可用于在 Go 项目中构建、签名、验证 Bitcoin SV 交易,处理密钥、地址、脚本和区块等。项目从 JavaScript 版 BSV 库移植,提供与官方 bitcoind 测试向量和 JS 库交叉验证的完整测试套件,涵盖加密、编码、HD 钱包、脚本解释器等核心功能。【此简介由AI生成】
bitcoin-go
A pure and powerful Go implementation of the Bitcoin SV (BSV) library,
ported from the JavaScript library @scrypt-inc/bsv.
The port aims for behavioral equivalence with the JS library: every module was translated faithfully from the original source, and the test suite is driven by the same official bitcoind test vectors plus cross-implementation round-trips against the JS library.
Getting started
# clone and build
git clone git@gitcode.com:Youyi-Labs/bitcoin-go.git
cd bitcoin-go
go build ./...
# run the full test suite (2650+ tests)
go test ./...
# run the example program
go run ./examples
Add it to your module:
go get gitcode.com/Youyi-Labs/bitcoin-go
import bsv "gitcode.com/Youyi-Labs/bitcoin-go"
License
MIT. This is a Go port of the JavaScript library
@scrypt-inc/bsv; the original copyright
notices are preserved in the LICENSE file.
Features
| Area | Modules |
|---|---|
| Crypto | secp256k1 ECDSA (RFC 6979 deterministic k, low-S, pubkey recovery), SHA-1/SHA-256/SHA-512, double-SHA256, RIPEMD-160, HASH160, HMAC, AES-CBC |
| Encoding | Base58, Base58Check, CompactSize varints, buffer reader/writer |
| Keys | PrivateKey (WIF), PublicKey (SEC1 DER), Address (P2PKH/P2SH), HD keys (BIP32) |
| Script | Full BSV script interpreter with P2SH, CLTV/CSV, and the Magnetic/Monolith opcodes (OP_CAT, OP_SPLIT, OP_MUL, …) |
| Transactions | Build, serialize, sign (SIGHASH_ALL/NONE/SINGLE + FORKID), BIP69 sorting, sighash with HashCache |
| Block | Block, BlockHeader, MerkleBlock (BIP37) |
| Extra | Bitcoin signed Message (BIP137), Mnemonic (BIP39, 6 wordlists), ECIES (Bitcore + Electrum BIE1) |
Usage
A complete, runnable version of every example below lives in
examples/main.go; the script-interpreter walkthrough lives inexamples/interpreter/main.go.
cd bitcoin-go
go run ./examples # keys, wallets, scripts, transactions, ...
go run ./examples/interpreter # the script interpreter (VerifyScript)
1. Keys and addresses
import bsv "gitcode.com/Youyi-Labs/bitcoin-go"
// parse a WIF private key
priv, err := bsv.PrivateKeyFromWIF("cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY")
if err != nil { /* handle */ }
// derive the public key and an address (testnet / livenet)
pub := priv.ToPublicKey()
addr, _ := priv.ToAddress(bsv.Testnet) // mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1
fmt.Println(pub.ToString(), addr.ToString())
// parse an address back and check its type
parsed, _ := bsv.AddressFromString("mszYqVnqKoQx4jcTdJXxwKAissE3Jbrrc1", nil, "")
parsed.IsPayToPublicKeyHash() // true
// generate random keys
randomPriv, _ := bsv.PrivateKeyFromRandom("testnet")
2. HD wallet keys (BIP32)
// master key from a seed
seed, _ := hex.DecodeString("000102030405060708090a0b0c0d0e0f")
master, _ := bsv.HDPrivateKeyFromSeed(seed, nil)
fmt.Println(master.Xprivkey) // xprv9s21ZrQH143K3QTDL4...
fmt.Println(master.Xpubkey()) // xpub661MyMwAqRbcFtXgS5...
// derive children (hardened with ')
child, _ := master.DeriveChild("m/0'/1/2'", false)
// derive from the public key only (non-hardened)
xpub, _ := bsv.NewHDPublicKey(master.Xpubkey())
grandchild, _ := xpub.DeriveChild("m/0/1", false)
3. Mnemonic (BIP39)
// generate a random 12-word phrase
m, _ := bsv.MnemonicFromRandom(nil)
fmt.Println(m.ToString())
// restore from a known phrase and derive the BIP32 seed + HD key
fixed, _ := bsv.MnemonicFromString(
"abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about", nil)
seed := fixed.ToSeed("TREZOR") // 64-byte BIP39 seed
hd, _ := fixed.ToHDPrivateKey("", nil) // *bsv.HDPrivateKey
4. Scripts
// build a P2PKH output script from an address
p2pkh, _ := bsv.BuildPublicKeyHashOut(addr)
fmt.Println(p2pkh.ToASM()) // OP_DUP OP_HASH160 <hash> OP_EQUALVERIFY OP_CHECKSIG
// OP_RETURN data outputs (plain and safe OP_FALSE OP_RETURN style)
dataOut, _ := bsv.BuildDataOut("hello bsv", "")
safeOut, _ := bsv.BuildSafeDataOut([]byte{1, 2, 3}, "")
// parse a serialized script and classify it
s, _ := bsv.ScriptFromHex("76a914f4c03610e60ad15100929cc23da2f3a799af172588ac")
s.IsPublicKeyHashOut() // true
scriptAddr, _ := s.ToAddress(bsv.Livenet) // address the script pays to
// 2-of-2 multisig output
multisig, _ := bsv.BuildMultisigOut([]*bsv.PublicKey{k1, k2}, 2, false)
5. Transactions
// the UTXO to spend (a P2PKH output we control)
scriptPubkey, _ := bsv.BuildPublicKeyHashOut(fromAddr)
utxo := map[string]interface{}{
"txId": "a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458",
"outputIndex": 0,
"script": scriptPubkey,
"satoshis": 100000,
}
tx, _ := bsv.NewTransaction(nil)
tx.From(utxo, nil, 0) // add input
tx.To("mrU9pEmAx26HcbKVrABvgL7AwA5fjNFoDc", 40000) // add outputs
tx.To("n28S35tqEMbt6vNad7A5K3mZ7vdn8dZ86X", 30000)
tx.Sign(priv, 0) // SIGHASH_ALL|FORKID by default
fmt.Println(tx.IsFullySigned()) // true
fmt.Println(tx.GetID()) // txid
fmt.Println(tx.ToHex()) // broadcast-ready serialization
// verify the input script with the full interpreter
verified, errstr := bsv.VerifyScript(tx.Inputs[0].GetScript(), scriptPubkey, tx, 0,
bsv.SCRIPT_VERIFY_P2SH|bsv.SCRIPT_VERIFY_STRICTENC|bsv.SCRIPT_ENABLE_SIGHASH_FORKID,
bsv.NewBNFromNumber(100000), nil)
// deserialize back, apply BIP69 ordering, append OP_RETURN data
copy, _ := bsv.TransactionFromString(tx.ToHex())
tx.Sort()
tx.AddData("genesis is coming")
6. Signed messages (BIP137)
msg, _ := bsv.NewMessage("hello, world")
sig, _ := msg.Sign(priv) // base64 compact signature
ok, _ := msg.Verify(addr.ToString(), sig) // true
7. ECIES encryption
// Alice encrypts to Bob's public key
enc := bsv.NewECIES(nil)
enc.SetPrivateKey(alicePriv)
enc.SetPublicKey(bobPriv.ToPublicKey())
ciphertext, _ := enc.Encrypt("top secret", nil)
// Bob decrypts with his private key
dec := bsv.NewECIES(nil)
dec.SetPrivateKey(bobPriv)
plaintext, _ := dec.Decrypt(ciphertext)
8. Blocks and MerkleBlocks (BIP37)
// parse a block header from its 80-byte hex form
header, _ := bsv.BlockHeaderFromString(headerHex)
fmt.Println(header.Hash()) // 000000000019d6689c08... (genesis)
// build a MerkleBlock from its JSON object form (as sent by BIP37 peers)
mb, _ := bsv.NewMerkleBlock(mbJSONObject)
mb.ValidMerkleTree() // true
filtered, _ := mb.FilteredTxsHash() // txids matching the bloom filter
// parse a full raw block (magic + size prefix, as stored in blk*.dat)
block, _ := bsv.BlockFromRawBlock(rawBlockData)
block.Header.Hash()
len(block.Transactions)
9. Encoding helpers
bsv.Base58Encode([]byte("hello world")) // StV1DL6CwTryKyV
bsv.Base58CheckEncode(dataWithChecksum) // bitcoin base58check
bsv.NewVarintFromNumber(300).Buf // CompactSize encoding
10. Script interpreter (VerifyScript)
The full BSV script interpreter is exposed through VerifyScript: it runs
scriptSig + scriptPubKey on an interpreter stack and reports whether the
spend is valid. Two usage modes:
// (a) standalone evaluation: pass a nil transaction for scripts that do not
// sign (no OP_CHECKSIG family) - Magnetic/Monolith opcodes work too
script, _ := bsv.ScriptFromHex("5152935387") // OP_1 OP_2 OP_ADD OP_3 OP_EQUAL
ok, errstr := bsv.VerifyScript(nil, script, nil, 0,
bsv.SCRIPT_ENABLE_MAGNETIC_OPCODES|bsv.SCRIPT_ENABLE_MONOLITH_OPCODES, nil, nil)
// ok == true, errstr == ""
// (b) full spend verification: the interpreter validates a real P2PKH spend
ok, errstr = bsv.VerifyScript(tx.Inputs[0].GetScript(), scriptPubkey, tx, 0,
bsv.DEFAULT_FLAGS, bsv.NewBNFromNumber(100000), nil)
A complete, runnable walkthrough - arithmetic, a failing script,
OP_CAT,OP_FALSE OP_RETURN, and a correct/wrong-key P2PKH spend - lives inexamples/interpreter/main.go:
go run ./examples/interpreter
Testing
The test suite is self-contained: all official bitcoind test vectors are
vendored into the repository under testdata/, so the project
builds and tests anywhere without the original JS sources. Every vector runs
as an individual go test sub-test:
$ go test -v ./... # 2650+ tests
The vendored data (testdata/) was copied from the original JS project's
test/data/ and test/mnemonic/data/ directories:
testdata/
├── base58_keys_valid.json # bitcoind base58check address/key vectors
├── base58_keys_invalid.json
├── script_tests.json # script interpreter evaluation vectors
├── tx_valid.json # full-transaction validity vectors
├── tx_invalid.json
├── tx_creation.json # end-to-end build/sign/change/serialize vectors
├── sighash.json # forkid sighash vectors
├── ecdsa.json # RFC 6979 ECDSA signature vectors
├── bip69.json # BIP69 input/output ordering vectors
├── fixtures.json # BIP39 mnemonic vectors
├── merkleblocks.json # BIP37 merkleblock filter vectors
├── blk86756-testnet.dat # real testnet block (wire format)
└── blk86756-testnet.json # expected block contents
Coverage highlights:
- script_tests.json — 1324 interpreter vectors (all pass, 5 witness-format vectors skipped)
- tx_valid.json / tx_invalid.json — 50 valid + 40 invalid full-transaction vectors
- tx_creation.json — 6 end-to-end build/sign/change/serialize vectors (byte-exact)
- sighash.json — 1000 forkid sighash vectors
- ecdsa.json — RFC 6979 signature vectors (byte-exact r/s)
- base58_keys_valid/invalid.json — 100 address/key vectors
- BIP39 fixtures — 25 entropy→mnemonic→seed vectors
- BIP32 — derivation vectors with byte-exact xprv/xpub
- BIP69 — input/output sorting vectors
- MerkleBlock (BIP37) — official filter vectors
- Real block — 22-transaction testnet block parsed and verified
- Behavior tests — Script API, keys, addresses, transactions, locktimes
- Cross-library — ECIES ciphertext and Message signatures byte-identical to the JS library
Dependencies
github.com/decred/dcrd/dcrec/secp256k1/v4— secp256k1 curve mathgolang.org/x/crypto— RIPEMD-160, PBKDF2golang.org/x/text— Unicode normalization (BIP39)
Everything else uses the Go standard library.