BSV foundation library for Zig.
- Status
- Getting Started
- Module Layout
- Documentation
- Standards Coverage
- Script Verification APIs
- Interpreter Coverage
- Benchmarks
Crypto, keys, script, transactions, SPV, BEEF, and broadcast. 27 BRC standards covered.
Details
Implemented:
primitives: hex, varint, base58, base58check, network/version-byte helpers, chainhash (display-order hash type), EC curve wrapper with ECDH and Type-42 key derivation, ECDSA signatures with low-S normalization, Schnorr proofs, AES-CBC, AES-GCM, symmetric key encryption, Shamir secret sharing (key shares, backup format), HMAC-DRBG, BIP32 HD keys (xpriv/xpub, child derivation), BIP39 mnemonics (English wordlist, PBKDF2 seed), BRC-43 invoice stringscrypto: sha256, sha512, hash256, ripemd160, hash160, hmacSha256, hmacSha512, secp256k1 private/public keys, secp256k1 point API, DER signatures, compact signatures with recovery, ECIES (Electrum + Bitcore), tx-signature helperscompat: P2PKH address, WIF encode/decode, Bitcoin Signed Message (sign/verify/recover), ECIEStransaction: parse/serialize (standard + extended format), txid, sighash/preimage, P2PKH spend helpers, BEEF V1/V2/Atomic, transaction builder (addInput/addOutput/payToAddress/sign), fee calculation with pluggable models, change distributionscript: ScriptNum, parser/chunks, full modern BSV opcode surface plus legacy/reference semantics, execution engine, transaction-aware CHECKSIG/CHECKMULTISIG, configurable policy enforcement, ASM encode/decode, script builder (appendPushData/appendOpcodes), type detection (isP2PKH/isP2PK/isData/isMultiSigOut), templates (P2PKH, OP_RETURN, PushDrop, R-puzzle, OP_TRUE, Push TX), script clone/ownershipspv: MerklePath parse/serialize/computeRoot/combine/verify, MerkleTreeParent, ancestor traversal, BEEF verification, pluggable chain tracker interfacemessage: BRC-77 signed messages (sign/verify) and BRC-78 encrypted messages (encrypt/decrypt)broadcast: WhatsOnChain, TAAL, and Arc HTTP broadcast clients
Script interpreter test corpus:
- 1,499 test vectors from the BSV script corpus
- 1,435 executable rows passing
- 64 rows tracked as meta/non-executable
Requirements: Zig 0.15.2
Fetch the dependency:
zig fetch --save git+https://github.com/b-open-io/bsvz.gitThen expose the module in your build.zig:
const bsvz = b.dependency("bsvz", .{ .target = target, .optimize = optimize });
exe.root_module.addImport("bsvz", bsvz.module("bsvz"));| Module | Description |
|---|---|
bsvz.primitives |
Hex, varint, base58, base58check, version-byte helpers |
bsvz.primitives.chainhash |
Display-order (reverse hex) hash type, single/double hash helpers |
bsvz.primitives.ec |
EC curve wrapper, PrivateKey, PublicKey, key generation, ECDH, Type-42 derivation |
bsvz.primitives.ecdsa |
ECDSA signature type with DER encoding and low-S normalization |
bsvz.primitives.schnorr |
Schnorr DLEQ proof generation and verification |
bsvz.primitives.keyshares |
Shamir secret sharing: polynomial, key shares, backup format |
bsvz.primitives.aescbc |
AES-CBC encrypt/decrypt with PKCS7 padding (128/256-bit keys) |
bsvz.primitives.aesgcm |
AES-GCM encrypt/decrypt with authentication tags (128/256-bit keys) |
bsvz.primitives.symmetric |
Symmetric key wrapper with encrypt/decrypt |
bsvz.primitives.drbg |
HMAC-DRBG deterministic random bit generator |
bsvz.primitives.bip32 |
HD key derivation: ExtendedKey, xpriv/xpub, child paths, mainnet/testnet, masterFromMnemonic |
bsvz.primitives.bip39 |
Mnemonic generation, English wordlist, entropy, PBKDF2 seed derivation |
bsvz.primitives.brc43 |
BRC-43 protocol ID normalization and <level>-<protocol>-<key> invoice strings |
bsvz.crypto |
SHA256, SHA512, RIPEMD160, HASH160, HASH256, HMAC-SHA256, HMAC-SHA512, secp256k1 keys and point API, DER and compact signatures, ECIES |
bsvz.script |
Script parser, opcode set, execution engine, policy flags, ASM encode/decode, script builder, type detection |
bsvz.transaction |
Parse, serialize (standard + extended format), sighash, P2PKH spend helpers |
bsvz.transaction.builder |
Transaction builder: addInput, addOutput, payToAddress, sign, applyFee |
bsvz.transaction.beef |
BEEF V1/V2/Atomic parse, serialize, and transaction extraction |
bsvz.transaction.fees |
Fee calculation, change distribution, total input/output satoshis |
bsvz.transaction.fee_model |
Pluggable fee models (satoshis-per-kilobyte) |
bsvz.message |
BRC-77 portable signed messages (signed); BRC-78 portable encrypted messages (encrypted) |
bsvz.compat |
P2PKH address, WIF encode/decode, Bitcoin Signed Message, ECIES |
bsvz.spv |
MerklePath, MerkleTreeParent, BlockHeader, SPV and BEEF verification |
bsvz.broadcast |
WhatsOnChain, TAAL, Arc HTTP broadcast clients |
- Overview
- Examples and Usage Guides
- Concepts — ownership, allocators, lifecycle
- Low-Level Notes — module internals, implementation details
27 BRC standards covered — full spec index at bsv.brc.dev
| Standard | Title | Module |
|---|---|---|
| BRC‑2 | Data Encryption and Decryption | primitives.aescbc, primitives.aesgcm, primitives.symmetric |
| BRC‑3 | Digital Signature Creation and Verification | primitives.ec, primitives.ecdsa, crypto.secp256k1 |
| BRC‑8 | Everett-style Transaction Envelopes | transaction |
| BRC‑9 | Simplified Payment Verification | spv.verify, spv.verifyBeef |
| BRC‑12 | Raw Transaction Format | transaction |
| BRC‑14 | Script Binary, Hex, and ASM Formats | script, script.asm |
| BRC‑16 | Pay to Public Key Hash | script.templates.p2pkh, compat.address |
| BRC‑17 | Pay to R Puzzle Hash | script.templates.r_puzzle |
| BRC‑18 | Pay to False Return | script.templates.op_return |
| BRC‑19 | Pay to True Return | script.templates.op_true |
| BRC‑30 | Transaction Extended Format (EF) | transaction |
| BRC‑32 | BIP32 Key Derivation | primitives.bip32 |
| BRC‑36 | Format for Bitcoin Outpoints | transaction.OutPoint |
| BRC‑42 | BSV Key Derivation Scheme (Type‑42) | primitives.ec (deriveChild, deriveSharedSecret) |
| BRC‑43 | Security Levels, Protocol IDs, Key IDs | primitives.brc43, primitives.ec (deriveChild) |
| BRC‑47 | Bare Multi-Signature | script |
| BRC‑48 | Pay to Push Drop | script.templates.pushdrop |
| BRC‑61 | Compound Merkle Path Format | spv.MerklePath |
| BRC‑62 | BEEF Transactions | transaction.beef |
| BRC‑67 | Simplified Payment Verification | spv |
| BRC‑74 | BSV Unified Merkle Path (BUMP) | spv.MerklePath |
| BRC‑75 | Mnemonic for Master Private Key | primitives.bip39 |
| BRC‑77 | Message Signature Creation and Verification | message.signed (portable wire); legacy BSM: compat.bsm, crypto.compact |
| BRC‑78 | Portable Encrypted Messages | message.encrypted (BRC-78 wire); Electrum/Bitcore ECIES: crypto.ecies, compat.ecies |
| BRC‑94 | Schnorr Shared Secret Revelation | primitives.schnorr |
| BRC‑95 | Atomic BEEF Transactions | transaction.beef |
| BRC‑96 | BEEF V2 Txid Only Extension | transaction.beef |
The verification surface covers plain script pairs, full prevout spends, detailed results, and step traces.
API reference and examples
| Function | Description |
|---|---|
bsvz.script.thread.verifyScripts(...) |
Verify a plain unlocking/locking script pair |
bsvz.script.thread.ScriptThread.verifyPair(...) |
Same, on a reusable thread |
bsvz.script.thread.verifyExecutableScripts(...) |
Verify an executable/full-locking-script pair |
bsvz.script.thread.verifyPrevoutSpend(...) |
Verify a spend against a previous output |
bsvz.script.thread.verifyPrevoutSpendDetailed(...) |
Same, with structured result |
bsvz.script.thread.verifyPrevoutSpendTraced(...) |
Same, with step trace |
bsvz.script.interpreter.verify(...) |
Small wrapper for simple verification |
bsvz.script.interpreter.verifyPrevout(...) |
Small wrapper for prevout verification |
bsvz.script.interpreter.verifyDetailed(...) |
Detailed result variant |
bsvz.script.interpreter.verifyTraced(...) |
Traced variant |
Return shapes:
true/false: script evaluated cleanly, result is the final truthinesserror.*: policy, parsing, encoding, or transaction-context failure;result.terminalgives.success,.false_result, or.script_error
Detailed result fields: result.phase, result.script_error
Trace step fields: phase, opcode offset, opcode byte, pre-step stack/altstack/condition-stack snapshots, ops_executed, last_code_separator
Both VerificationResult and traced results have writeDebug(...) helpers.
var thread = bsvz.script.thread.ScriptThread.init(.{ .allocator = allocator });
defer thread.deinit();
const ok = try thread.verifyPair(
bsvz.script.Script.init(unlocking_bytes),
bsvz.script.Script.init(locking_bytes),
);const previous_output = previous_tx.outputs[previous_output_index];
var result = bsvz.script.interpreter.verifyPrevoutDetailed(.{
.allocator = allocator,
.tx = &spend_tx,
.input_index = spend_input_index,
.previous_output = previous_output,
.unlocking_script = spend_tx.inputs[spend_input_index].unlocking_script,
});
defer result.deinit(allocator);
if (result.terminal == .script_error) return result.script_error.?;
const ok = result.success;var traced = bsvz.script.thread.verifyScriptsTraced(.{
.allocator = allocator,
}, bsvz.script.Script.init(&[_]u8{}), bsvz.script.Script.init(&[_]u8{
@intFromEnum(bsvz.script.opcode.Opcode.OP_1),
@intFromEnum(bsvz.script.opcode.Opcode.OP_FROMALTSTACK),
}));
defer traced.deinit(allocator);
try traced.writeDebug(std.io.getStdOut().writer());const output = bsvz.transaction.Output{
.satoshis = 42,
.locking_script = bsvz.script.Script.init(&[_]u8{0x6a}),
};
var raw = try allocator.alloc(u8, output.serializedLen());
defer allocator.free(raw);
_ = output.writeInto(raw);
const parsed = try bsvz.transaction.Output.parse(raw);
const hash_all = try bsvz.transaction.Output.hashAll(allocator, &[_]bsvz.transaction.Output{output});- Plain script trace: ./examples/script_trace_demo.zig
- Prevout spend trace: ./examples/prevout_trace_demo.zig
- Hash demo: ./examples/hash_demo.zig
- GorillaPool ARC broadcast: ./examples/gorillapool_arc_demo.zig
bsvz.crypto.Point: fromCompressedSec1, fromRaw64, toCompressedSec1, toRaw64, xBytes32, yBytes32, add, mul, negate
Coverage map
| Area | Notes |
|---|---|
| Script bytes, chunks, parser, serializer | direct pushes, PUSHDATA1/2/4, chunk roundtrip, malformed pushdata rejection |
| Script thread / seam orchestration | separates seam behavior from the opcode loop; owns the "full previous locking script for sighash, executable prefix for execution" split |
| Push-only and script inspection helpers | isPushOnly, hasCodeSeparator, top-level OP_RETURN tail handling |
| Execution core | stack, altstack, condition stack, truthiness, op counting, stack limits |
| Control flow | IF, NOTIF, ELSE, ENDIF, VERIFY, legacy vs post-Genesis multi-ELSE, post-Genesis OP_RETURN, CODESEPARATOR |
| Stack ops | DUP, DROP, SWAP, ROT, ROLL, PICK, 2DUP, 2DROP, 2OVER, 2ROT, 2SWAP, 3DUP, IFDUP, TOALTSTACK, FROMALTSTACK, TUCK |
| Byte/splice ops | CAT, SPLIT, NUM2BIN, BIN2NUM, SIZE |
| Bitwise ops | INVERT, AND, OR, XOR, LSHIFT, RSHIFT |
| Numeric and boolean ops | ADD, SUB, MUL, DIV, MOD, comparisons, min/max, within, boolean logic |
| Hash ops | RIPEMD160, SHA1, SHA256, HASH160, HASH256 |
ScriptNum |
small-or-big numeric core using Zig stdlib bigint for promoted values |
CHECKSIG |
transaction-aware, legacy and ForkID paths, CODESEPARATOR handling, scriptCode normalization |
CHECKMULTISIG |
transaction-aware, post-Genesis behavior, early-exit, NULLDUMMY/NULLFAIL/ForkID policy |
| Policy flags | strict_encoding, der_signatures, low_s, strict_pubkey_encoding, null_dummy, null_fail, sig_push_only, clean_stack, minimal_data, minimal_if, discourage_upgradable_nops, verify_check_locktime, verify_check_sequence |
| CLTV / CSV / upgradable NOPs | tx-aware legacy/reference verify semantics behind explicit flags; post-Genesis BSV profile treats them as NOP-family ops unless policy discourages them |
| Numeric minimal-encoding parity | minimal push and minimal numeric decoding enforced where Go applies MINIMALDATA |
CODESEPARATOR parity |
legacy and ForkID scriptCode behavior, chained separator tests, parser/scanner coverage |
| BSV script test vectors | all 1,499 Go corpus rows are accounted for across exact, filtered, reference, and specialized suites; all 1,435 executable rows pass; 64 meta/non-executable rows are audited |
Scope:
- Modern post-Genesis BSV script execution by default, plus legacy-reference semantics and opt-in legacy P2SH for compatibility and corpus parity
Harnesses and results (Apple M3 Max)
Harnesses:
# bsvz interpreter
zig build bench
# Go SDK comparison
cd benchmarks/go_sdk && GOCACHE=/tmp/go-build-bsvz go test -run '^$' -bench . -benchmem
# Live corpus pipeline (requires sibling bsvz-autotrainer repo)
cd ../bsvz-autotrainer && bun bench:pipeSource: ./benchmarks/script_engine.zig, ./benchmarks/go_sdk/script_engine_bench_test.go
Benchmarks use prebuilt fixtures. Key generation and per-iteration signing are excluded from the hot loop.
Script engine (Apple M3 Max):
| Workload | bsvz |
go-sdk |
|---|---|---|
| arithmetic verify | ~0.11 us/op | ~3.7 us/op |
| branching verify | ~0.10 us/op | ~4.6 us/op |
| SHA256 verify | ~0.11 us/op | ~3.9 us/op |
| HASH160 verify | ~0.28 us/op | ~4.0 us/op |
| stack ops verify | ~0.30 us/op | ~12.7 us/op |
| P2PKH verify (Go reference tx) | ~476.1 us/op | ~227.4 us/op |
bsvz diagnostics:
| Workload | bsvz |
|---|---|
| P2PKH sighash only | ~0.35 us/op |
| P2PKH secp verify only | ~433.8 us/op |
| P2PKH verify (synthetic fixture) | ~456.5 us/op |
Live corpus pipeline (JungleBus-style, via bsvz-autotrainer):
| Workload | bsvz |
go-sdk |
|---|---|---|
| wall clock | ~1720 ms | ~1851 ms |
| tx throughput | ~1907 tx/s | ~1772 tx/s |
| parse+spend throughput | ~13121 ops/s | ~12194 ops/s |
Phase split:
| Phase | bsvz |
go-sdk |
|---|---|---|
| JSON DOM | ~492 ms | ~517 ms |
| tx hex decode | ~38 ms | ~59 ms |
| spend verify | ~1146 ms | ~1224 ms |
The remaining cost sits in secp verification. bsvz now uses Zig stdlib prehashed verification directly rather than a custom secp256k1 fast path.
These numbers are a local baseline on one machine; your results will vary with allocator configuration, CPU microarchitecture, and corpus mix.
| Language | Repository |
|---|---|
| TypeScript | bsv-blockchain/ts-sdk |
| Go | bsv-blockchain/go-sdk |
| Python | bsv-blockchain/py-sdk |
| Rust | b1narydt/bsv-rust-sdk |
