You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The official Rust implementation of the BSV blockchain SDK, providing a complete toolkit for building BSV applications. Feature-complete and production-ready, with ~100,000 lines of Rust, 2,578 tests, 2,044+ cross-SDK test vectors, and byte-for-byte compatibility with the TypeScript and Go SDKs — including binary wire protocol interoperability.
Wallet - BRC-42 key derivation, ProtoWallet, WalletClient with HTTP substrates
Communication & Security
Messages - BRC-77/78 signed and encrypted peer-to-peer messaging
Auth - BRC-31 mutual authentication with certificate-based identity (BRC-52/53)
TOTP - RFC 6238 Time-based One-Time Passwords for two-factor authentication
Overlay Network
Overlay - SHIP/SLAP overlay network client for transaction broadcasting and lookup
Storage - UHRP content-addressed file storage via overlay network
Registry - On-chain definition registry for baskets, protocols, and certificates
KVStore - Blockchain-backed key-value storage (local encrypted, global public)
Identity - Certificate-based identity resolution and contact management
Compatibility
Compat - BIP-32 HD keys, BIP-39 mnemonics, Bitcoin Signed Messages, ECIES encryption
Installation
Add to your Cargo.toml:
[dependencies]
bsv-rs = "0.3"
Or with specific features:
[dependencies]
# All modulesbsv-rs = { version = "0.2", features = ["full"] }
# With HTTP client (for ARC broadcaster, WhatsOnChain, WalletClient, storage)bsv-rs = { version = "0.2", features = ["full", "http"] }
# Just primitives and script (default)bsv-rs = "0.3"# Common combinationsbsv-rs = { version = "0.2", features = ["wallet"] } # Keys, transactions, signingbsv-rs = { version = "0.2", features = ["auth", "http"] } # Authentication with HTTP transportbsv-rs = { version = "0.2", features = ["overlay", "http"] } # Overlay network operationsbsv-rs = { version = "0.2", features = ["compat"] } # BIP-32/39, BSM, ECIESbsv-rs = { version = "0.2", features = ["websocket"] } # Auth with WebSocket transport
Quick Start
Key Generation and Signing
use bsv_rs::{PrivateKey,PublicKey, sha256};// Generate a key pairlet private_key = PrivateKey::random();let public_key = private_key.public_key();// Get the addresslet address = public_key.to_address();println!("Address: {}", address);// Sign a messagelet msg_hash = sha256(b"Hello, BSV!");let signature = private_key.sign(&msg_hash).unwrap();// Verifyassert!(public_key.verify(&msg_hash,&signature));
Working with Scripts
use bsv_rs::script::{Script,LockingScript, op};use bsv_rs::script::templates::P2PKH;// Create a P2PKH locking script from an addresslet locking = P2PKH::lock_from_address("1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2").unwrap();// Or build a script programmaticallyletmut script = Script::new();
script
.write_opcode(op::OP_DUP).write_opcode(op::OP_HASH160).write_bin(&pubkey_hash).write_opcode(op::OP_EQUALVERIFY).write_opcode(op::OP_CHECKSIG);// Parse from hex or ASMlet script = Script::from_hex("76a914...88ac").unwrap();let script = Script::from_asm("OP_DUP OP_HASH160 <20-bytes> OP_EQUALVERIFY OP_CHECKSIG").unwrap();// Script type detectionif script.is_p2pkh(){let hash = script.extract_pubkey_hash();}
Building Transactions
use bsv_rs::transaction::{Transaction,TransactionInput,TransactionOutput,ChangeDistribution};use bsv_rs::script::LockingScript;// Create a new transactionletmut tx = Transaction::new();// Add an input (with full source transaction for signing)
tx.add_input(TransactionInput::with_source_transaction(source_tx,0)).unwrap();// Add outputs
tx.add_output(TransactionOutput::new(100_000,LockingScript::from_hex("76a914...88ac").unwrap(),)).unwrap();// Add a change output (amount computed during fee calculation)
tx.add_p2pkh_output("1MyChangeAddress...",None).unwrap();// Compute fees and sign
tx.fee(None,ChangeDistribution::Equal).await.unwrap();
tx.sign().await.unwrap();// Serializelet hex = tx.to_hex();let txid = tx.id();
BRC-42 Key Derivation
use bsv_rs::wallet::{KeyDeriver,Protocol,SecurityLevel,Counterparty};use bsv_rs::PrivateKey;// Create key derivers for Alice and Boblet alice = KeyDeriver::new(Some(PrivateKey::random()));let bob = KeyDeriver::new(Some(PrivateKey::random()));// Define a protocollet protocol = Protocol::new(SecurityLevel::App,"payment system");let key_id = "invoice-12345";// Bob derives a key for communication with Alicelet alice_counterparty = Counterparty::Other(alice.identity_key());let bob_private = bob.derive_private_key(&protocol, key_id,&alice_counterparty).unwrap();// Alice can derive the corresponding public keylet bob_counterparty = Counterparty::Other(bob.identity_key());let bob_public = alice.derive_public_key(&protocol, key_id,&bob_counterparty,false).unwrap();// They matchassert_eq!(bob_private.public_key().to_compressed(), bob_public.to_compressed());
ProtoWallet Operations
use bsv_rs::wallet::{ProtoWallet,Protocol,SecurityLevel,CreateSignatureArgs,EncryptArgs,Counterparty};use bsv_rs::PrivateKey;let alice = ProtoWallet::new(Some(PrivateKey::random()));let bob = ProtoWallet::new(Some(PrivateKey::random()));let protocol = Protocol::new(SecurityLevel::App,"secure messaging");// Sign datalet signed = alice.create_signature(CreateSignatureArgs{data:Some(b"Hello, BSV!".to_vec()),hash_to_directly_sign:None,protocol_id: protocol.clone(),key_id:"sig-1".to_string(),counterparty:None,}).unwrap();// Encrypt for Boblet encrypted = alice.encrypt(EncryptArgs{plaintext:b"Secret message".to_vec(),protocol_id: protocol.clone(),key_id:"msg-1".to_string(),counterparty:Some(Counterparty::Other(bob.identity_key())),}).unwrap();// Bob decryptslet decrypted = bob.decrypt(DecryptArgs{ciphertext: encrypted.ciphertext,protocol_id: protocol,key_id:"msg-1".to_string(),counterparty:Some(Counterparty::Other(alice.identity_key())),}).unwrap();
BRC-77/78 Messages (Signed & Encrypted)
use bsv_rs::primitives::PrivateKey;use bsv_rs::messages::{sign, verify, encrypt, decrypt};let sender = PrivateKey::random();let recipient = PrivateKey::random();// Sign for specific recipient (only they can verify)let signature = sign(b"Hello!",&sender,Some(&recipient.public_key())).unwrap();let valid = verify(b"Hello!",&signature,Some(&recipient)).unwrap();// Sign for anyone to verifylet signature = sign(b"Public announcement",&sender,None).unwrap();let valid = verify(b"Public announcement",&signature,None).unwrap();// Encrypt and decryptlet ciphertext = encrypt(b"Secret",&sender,&recipient.public_key()).unwrap();let plaintext = decrypt(&ciphertext,&recipient).unwrap();
BIP-32/39 HD Keys and Mnemonics
use bsv_rs::compat::bip32::{ExtendedKey,Network, generate_hd_key_from_mnemonic};use bsv_rs::compat::bip39::{Mnemonic,WordCount};// Generate a new mnemoniclet mnemonic = Mnemonic::new(WordCount::Words12).unwrap();println!("Mnemonic: {}", mnemonic.phrase());// Create HD key from mnemoniclet master = generate_hd_key_from_mnemonic(&mnemonic,"",Network::Mainnet).unwrap();// Derive using BIP-44 pathlet derived = master.derive_path("m/44'/0'/0'/0/0").unwrap();let address = derived.address(true).unwrap();// Parse existing extended keylet xprv = ExtendedKey::from_string("xprv9s21ZrQH143K...").unwrap();let xpub = xprv.neuter().unwrap();
TOTP Two-Factor Authentication
use bsv_rs::totp::{Totp,TotpOptions,TotpValidateOptions,Algorithm};// Shared secret (typically from base32-decoded QR code)let secret = b"12345678901234567890";// Generate a 6-digit codelet code = Totp::generate(secret,None);// Validate with 1-period skew (handles clock drift)assert!(Totp::validate(secret,&code,None));// Use SHA-256 with 8 digitslet options = TotpOptions{digits:8,algorithm:Algorithm::Sha256,
..Default::default()};let code = Totp::generate(secret,Some(options));
Overlay Network Lookup and Broadcast
use bsv_rs::overlay::{LookupResolver,LookupQuestion,TopicBroadcaster,TopicBroadcasterConfig};// Query a lookup servicelet resolver = LookupResolver::default();let question = LookupQuestion::new("ls_myservice", serde_json::json!({"key":"value"}));let answer = resolver.query(&question,Some(5000)).await?;// Broadcast to overlay topicslet broadcaster = TopicBroadcaster::new(vec!["tm_mytopic".to_string()],TopicBroadcasterConfig::default(),)?;let result = broadcaster.broadcast_tx(&tx).await;
UHRP File Storage
use bsv_rs::storage::{StorageDownloader, get_url_for_file, get_hash_from_url};// Generate UHRP URL from file contentlet url = get_url_for_file(b"Hello, World!").unwrap();// Download file from UHRP URL (requires http feature)let downloader = StorageDownloader::default();let result = downloader.download(&url).await?;println!("Downloaded {} bytes", result.data.len());// Parse hash from URLlet hash:[u8;32] = get_hash_from_url(&url).unwrap();
Key-Value Storage
use bsv_rs::kvstore::{LocalKVStore,KVStoreConfig};use bsv_rs::wallet::ProtoWallet;let wallet = ProtoWallet::new(Some(PrivateKey::random()));let config = KVStoreConfig::new().with_protocol_id("my-app");let store = LocalKVStore::new(wallet, config)?;// Set and get values (encrypted by default)
store.set("user:name","Alice",None).await?;let name = store.get("user:name","Unknown").await?;// List all keyslet keys = store.keys().await?;
Identity Resolution
use bsv_rs::identity::{IdentityClient,IdentityClientConfig,IdentityQuery};let client = IdentityClient::new(wallet,IdentityClientConfig::default());// Resolve identity by public keylet identity = client.resolve_by_identity_key("02abc123...",true).await?;// Discover certificates for an identitylet certs = client.discover_certificates("02abc123...").await?;// Query by attribute (email, phone, etc.)let results = client.resolve_by_attributes([("email".to_string(),"user@example.com".to_string())].into(),true).await?;
The binary wire protocol (WalletWireTransceiver/WalletWireProcessor) is fully interoperable with the Go SDK's wallet/serializer — messages serialized by one SDK can be deserialized by the other. This covers all 28 wallet interface methods, certificate formats, and complex nested types.
All implementations share test vectors to ensure cross-platform compatibility:
# Build with default features
cargo build
# Build with all features
cargo build --features full
# Run all tests
cargo test --features full
# Run all tests including HTTP mock tests
cargo test --features "full,http"# Run all tests including WebSocket transport
cargo test --features "full,websocket"# Run tests for specific module
cargo test --features wallet --test wallet_tests
cargo test --features wallet --test wire_method_roundtrip_tests
cargo test --features wallet --test wallet_wire_cross_sdk_tests
cargo test --features auth --test auth_peer_e2e_tests
cargo test --features "overlay,http" --test overlay_http_tests
cargo test --features "storage,http" --test storage_http_tests
cargo test --features kvstore --test kvstore_global_tests
cargo test --features "transaction,http" --test live_policy_http_tests
# Run benchmarks
cargo bench
# Run fuzz targets (requires cargo-fuzz)
cargo fuzz run fuzz_script_parser
cargo fuzz run fuzz_transaction_parser
cargo fuzz run fuzz_wire_protocol
cargo fuzz run fuzz_base58
# Lint
cargo clippy --all-targets --all-features
# Format
cargo fmt
# Generate documentation
cargo doc --open --features full