• Stars
    star
    180
  • Rank 213,097 (Top 5 %)
  • Language
    Rust
  • License
    Apache License 2.0
  • Created over 6 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

*archived* Library for a Bitcoin Wallet

Safety Dance

Bitcoin Wallet Library in Rust

Archiving

This library is being archived:

  • No one is currently working on this library.
  • If you are writing a Bitcoin wallet BDK may serve your needs.

Thanks!

This is a library to build Bitcoin wallets with Rust. It uses BIP32 key derivation, BIP39 mnemonics and BIP44, BIP48, BIP84 key hierarchy which makes it compatible to TREZOR, Ledger and many other wallets.

This library supports SLIP-0039 Shamir's Shared Secret Scheme as available in TREZOR Model T

It supports legacy P2PKH, transitional P2SHWPKH and native segwit P2WPKH for single key signatures and native P2WSH for arbitrary sripts.

Basic Accounts Use

MasterAccount holds an encrypted seed that implies the BIP32 root key. Add any number of Account to it to derive hiararchies following BIP44. An Account will have addresses of a uniform type.

const PASSPHRASE: &str = "correct horse battery staple";

// create a new random master account. This holds the root BIP32 key
// PASSPHRASE is used to encrypt the seed in memory and in storage
let mut master = MasterAccount::new(MasterKeyEntropy::Sufficient, Network::Bitcoin, PASSPHRASE).unwrap();

// or re-create a master from a known mnemonic
let words = "announce damage viable ticket engage curious yellow ten clock finish burden orient faculty rigid smile host offer affair suffer slogan mercy another switch park";
let mnemonic = Mnemonic::from_str(words).unwrap();
// PASSPHRASE is used to encrypt the seed in memory and in storage
// last argument is option password for plausible deniability
let mut master = MasterAccount::from_mnemonic(&mnemonic, 0, Network::Bitcoin, PASSPHRASE, None).unwrap();

// The master accounts only store public keys
// Private keys are created on-demand from encrypted seed with an Unlocker and forgotten as soon as possible

// create an unlocker that is able to decrypt the encrypted mnemonic and then calculate private keys
let mut unlocker = Unlocker::new_for_master(&master, PASSPHRASE).unwrap();

// The unlocker is needed to create accounts within the master account as 
// key derivation follows BIP 44, which requires private key derivation

// create a P2PKH (pay-to-public-key-hash) (legacy) account. 
// account number 0, sub-account 0 (which usually means receiver) BIP32 look-ahead 10
let account = Account::new(&mut unlocker, AccountAddressType::P2PKH, 0, 0, 10).unwrap();
master.add_account(account);

// create a P2SHWPKH (pay-to-script-hash-witness-public-key-hash) (transitional single key segwit) account.
// account number 0, sub-account 1 (which usually means change) BIP32 look-ahead 10
let account = Account::new(&mut unlocker, AccountAddressType::P2SHWPKH, 0, 1, 10).unwrap();
master.add_account(account);

// create a P2WPKH (pay-to-witness-public-key-hash) (native single key segwit) account.
// account number 1, sub-account 0 (which usually means receiver) BIP32 look-ahead 10
let account = Account::new(&mut unlocker, AccountAddressType::P2WPKH, 1, 0, 10).unwrap();
master.add_account(account);
// account number 1, sub-account 1 (which usually means change) BIP32 look-ahead 10
let account = Account::new(&mut unlocker, AccountAddressType::P2WPKH, 1, 1, 10).unwrap();
master.add_account(account);

// get next legacy receiver address
let source = master.get_mut((0,0)).unwrap().next_key().unwrap().address.clone();
// pay to some native segwit address
let target = master.get_mut((1,0)).unwrap().next_key().unwrap().address.clone();
// change to some transitional address
let change = master.get_mut((0,1)).unwrap().next_key().unwrap().address.clone();

// a dummy transaction to send to source
let input_transaction = Transaction {
            input: vec![
                TxIn {
                    previous_output: OutPoint { txid: sha256d::Hash::default(), vout: 0 },
                    sequence: RBF,
                    witness: Vec::new(),
                    script_sig: Script::new(),
                }
            ],
            output: vec![
                TxOut {
                    script_pubkey: source.script_pubkey(),
                    value: 5000000000,
                }
            ],
            lock_time: 0,
            version: 2,
        };

let txid = input_transaction.txid();

const RBF: u32 = 0xffffffff - 2;

// a dummy transaction that spends source
let mut spending_transaction = Transaction {
            input: vec![
                TxIn {
                    previous_output: OutPoint { txid, vout: 0 },
                    sequence: RBF,
                    witness: Vec::new(),
                    script_sig: Script::new(),
                }
            ],
            output: vec![
                TxOut {
                    script_pubkey: target.script_pubkey(),
                    value: 4000000000,
                },
                TxOut {
                    script_pubkey: change.script_pubkey(),
                    value: 999999000,
                }
            ],
            lock_time: 0,
            version: 2,
        };

// helper to find previous outputs
let mut spent = HashMap::new();
spent.insert(txid, input_transaction.clone());

// sign the spend
master.sign(&mut spending_transaction, SigHashType::All,
                       &(|_| Some(input_transaction.output[0].clone())), 
            &mut unlocker).expect("can not sign");

// verify the spend with the bitcoinconsensus library
spending_transaction.verify(|point|
            spent.get(&point.txid).and_then(|t| t.output.get(point.vout as usize).cloned())
        ).expect("Bitcoin Core would not like this")

Advanced Accounts Use

const CSV:u16 = 10; // 10 blocks relative lock

// create a P2WSH (pay-to-witness-script-hash) (native segwit for arbitrary scripts) account
let account = Account::new(&mut unlocker, AccountAddressType::P2WSH(4711), 2, 0, 0).unwrap();
master.add_account(account);
{
    let account = master.get_mut((2, 0)).unwrap();
    let scripter = |pk: &PublicKey, csv: Option<u16>| Builder::new()
        .push_int(csv.unwrap() as i64)
        .push_opcode(all::OP_CSV)
        .push_opcode(all::OP_DROP)
        .push_slice(pk.to_bytes().as_slice())
        .push_opcode(all::OP_CHECKSIG)
        .into_script();
    account.add_script_key(scripter, Some(&[0x01; 32]), Some(CSV)).unwrap();
}

Coins use

// create a coin store
let mut coins = Coins::new();

// put all coins from block into coin store that are ours (means master can sign for them)
coins.process(&mut master, &block);

// calculate balances
let confirmed = coins.confirmed_balance();
let unconfirmed = coins.unconfirmed_balance();
// means not OP_CSV time locked
let available = coins.available_balance();

// undo the highest block as it was removed through re-org
coins.unwind_tip(block_hash);

// choose inputs to spend
let inputs = choose_inputs (minimum_amount_needed, current_block_height, |h| height_of_block(h));

Shamir's Secret Shares

// create an new random account        
let master = MasterAccount::new(MasterKeyEntropy::Low, Network::Bitcoin, PASSPHRASE).unwrap();

// extract seed
let seed = master.seed(Network::Bitcoin, PASSPHRASE).unwrap();

// cut seed into 5 shares such that any 3 of them is sufficient to re-construct
let shares = ShamirSecretSharing::generate(1, &[(3,5)], &seed, None, 1).unwrap();

// re-construct seed from the first 3
let reconstructed_seed = ShamirSecretSharing::combine(&shares[..3], None).unwrap();

// re-construct master from seed
let reconstructed_master = MasterAccount::from_seed(&reconstructed_seed, 0, Network::Bitcoin, PASSPHRASE).unwrap();

// prove that everything went fine
assert_eq!(master.master_public(), reconstructed_master.master_public());
assert_eq!(master.encrypted(), reconstructed_master.encrypted());

More Repositories

1

rust-bitcoin

Rust Bitcoin library
Rust
2,063
star
2

rust-miniscript

Support for Miniscript and Output Descriptors for rust-bitcoin
Rust
342
star
3

rust-secp256k1

Rust language bindings for Bitcoin secp256k1 library.
C
337
star
4

rust-bitcoincore-rpc

Rust RPC client library for the Bitcoin Core JSON-RPC API.
Rust
293
star
5

murmel

Bitcoin SPV client in Rust.
Rust
102
star
6

rust-bech32

Bech32 format encoding and decoding
Rust
94
star
7

rust-bip39

A Rust library for working with Bitcoin BIP-39 mnemonics
Rust
88
star
8

bitcoin_hashes

Simple library which implements a few hashes and does nothing else
Rust
66
star
9

hammersbald

Hammersbald is a fast embedded blockchain database
Rust
52
star
10

rust-bitcoinconsensus

Bitcoin's libbitcoinconsenus.a with Rust binding. Built from Bitcoin sources with cargo.
C++
46
star
11

bitcoind

Utility to launch a regtest bitcoind process in a rust test
Rust
34
star
12

rust-bip47

BIP47 implementation in Rust
Rust
26
star
13

rust-lightning-invoice

lightning BOLT 11 invoice implementation
Rust
20
star
14

rust-bech32-bitcoin

Encoding and decoding Segregated Witness addresses in Bech32 format
Rust
16
star
15

bip324

encrypted messages over the Bitcoin P2P Protocol
Rust
15
star
16

bip322

Implements BIP322 generic message signing and verification
Rust
14
star
17

constants

Constants used across Bitcoin libraries
Rust
8
star
18

hex-conservative

Hex crate with a conservative MSRV and dependency policy
Rust
7
star
19

rust-bitcoin-chain

In-Memory Bitcoin blockchain
Rust
5
star
20

www.rust-bitcoin.org

Web site source code
Shell
5
star
21

rust-bitcoin.github.io

SCSS
5
star
22

rust-bitcoind-json-rpc

Support for Bitcoin Core's JSON-RPC API
Rust
5
star
23

rust-bitcoin-maintainer-tools

Scripts, test vectors, and other things used by or across multiple repositories in the rust-bitcoin ecosystem.
Rust
5
star
24

workshop

Conference workshop material
HTML
2
star
25

rust-psbt-v0

Partially Signed Bitcoin Transaction Format - BIP-174
Rust
1
star