Skip to main content
  1. All Posts/

bitcoin-bash-tools

Tools Shell

Bitcoin bash tools

Bitcoin-related functions in Bash.

Table of contents

  • Synopsis
  • Description


    Synopsis

    $ git clone https://github.com/grondilu/bitcoin-bash-tools.git
    $ . bitcoin-bash-tools/bitcoin.sh
    
    $ openssl rand 32 |wif
    
    $ mnemonic=($(create-mnemonic 128))
    $ echo "${mnemonic[@]}"
    
    $ mnemonic-to-seed "${mnemonic[@]}" > seed
    $ pegged-entropy {1..38} > seed
    
    $ xkey -s /N < seed
    $ ykey -s /N < seed
    $ zkey -s /N < seed
    
    $ bitcoinAddress "$(xkey -s /44h/0h/0h/0/0/N < seed |base58 -c)"
    $ bitcoinAddress "$(ykey -s /49h/0h/0h/0/0/N < seed |base58 -c)"
    $ bitcoinAddress "$(zkey -s /84h/0h/0h/0/0/N < seed |base58 -c)"
    
    
    $ bip85 wif
    $ bip85 mnemo
    $ bip85 xprv
    
    $ (cd bitcoin-bash-tools; prove;)
    


    Description

    This repository contains bitcoin-related bash functions, allowing bitcoin
    private keys generation and processing from and to various formats.
    To discourage the handling of keys in plain text, most of these functions
    mainly read and print keys in binary. The base58check version is only read
    or printed when reading from or writing to a terminal.

    Base-58 encoding

    base58 is a simple filter
    implementing Satoshi Nakamoto’s binary-to-text encoding.
    Its interface is inspired from coreutils’ base64.

    $ openssl rand 20 |base58
    2xkZS9xy8ViTSrJejTjgd2RpkZRn
    

    With the -c option, the checksum is added.

    $ echo foo |base58 -c
    J8kY46kF5y6
    

    With the -v option, the checksum is verified.

    $ echo foo |base58   |base58 -v || echo wrong checksum
    wrong checksum
    $ echo foo |base58 -c|base58 -v && echo good checksum
    good checksum
    

    Decoding is done with the -d option.

    $ base58 -d <<<J8kY46kF5y6
    foo
    M-MDjM-^E
    

    As seen above, when writing to a terminal, base58 will escape non-printable characters.
    Input can be coming from a file when giving the filename
    (or say a process substitution)
    as positional parameter :

    $ base58 <(echo foo)
    3csAed
    

    A large file will take a very long time to process though, as this encoding is absolutely not
    optimized to deal with large data.

    Bech32

    Bech32 is a string format used to encode
    segwit addresses, but by
    itself it is not a binary-to-text encoding, as it needs additional conventions
    for padding.
    Therefore, the bech32 function in this library does not read binary data, but
    merely creates a Bech32 string from a human readable part and a non checked data
    part :

    $ bech32 this-part-is-readable-by-a-human qpzry
    this-part-is-readable-by-a-human1qpzrylhvwcq
    

    The -m option creates a
    bech32m
    string :

    $ bech32 -m this-part-is-readable-by-a-human qpzry
    this-part-is-readable-by-a-human1qpzry2tuzaz
    

    The -v option can be used to verify the checksum :

    $ bech32 -v this-part-is-readable-by-a-human1qpzrylhvwcq && echo good checksum
    good checksum
    
    $ bech32 -m -v this-part-is-readable-by-a-human1qpzry2tuzaz && echo good checksum
    good checksum
    


    Wallet Import Format

    The function wif reads 32 bytes from stdin,
    interprets them as a secp256k1 exponent
    and displays the corresponding private key in Wallet Import
    Format
    .

    $ openssl rand 32 |wif
    L1zAdArjAUgbDKj8LYxs5NsFk5JB7dTKGLCNMNQXyzE4tWZBGqs9
    

    With the -u option, the uncompressed version is returned.
    With the -t option, the testnet
    version is returned.
    With the -d option, the reverse operation is performed : reading a
    key in WIF from stdin and printing 32 bytes to non-terminal standard output.
    When writing to a terminal, the output is in a format used by
    openssl ec.

    Extended keys

    Generation and derivation of eXtended keys, as described in
    BIP-0032 and its successors BIP-0044,
    BIP-0049 and BIP-0084, are supported by three filters, namely bip32, bip49 and bip84,
    along with three respective aliases xkey, ykey and zkey.
    The aliases exist for the sole reason that they are arguably easier to type.
    Unless the option -p, -s or -t is used, these functions read 78 bytes
    from stdin and interpret these as a serialized extended key. Then the
    extended key derived according to a derivation path provided as a positional
    parameter is computed and printed on stdout.
    A base58check-encoded key can be passed as input if it is pasted
    in the terminal, but to pass it through a pipe, it must first be decoded with
    base58 -d:

    $ myxprvkey=xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U
    $ base58 -d <<<"$myxprvkey" |xkey /0
    xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt
    

    To capture the base58check-encoded result, encoding must be performed explicitely with base58 -c.

    $ myXkey="$(base58 -d <<<"$myxprvkey"| xkey /0 |base58 -c)"
    

    When the -s option is used, stdin is used as a binary seed instead
    of an extended key. This option is thus required to generate a master key :

    $ openssl rand 64 |tee myseed |xkey -s
    xprv9s21ZrQHREDACTEDtahEqxcVoeTTAS5dMAqREDACTEDDZd7Av8eHm6cWFRLz5P5C6YporfPgTxC6rREDACTEDn5kJBuQY1v4ZVejoHFQxUg
    

    Any key in the key tree can be generated from a seed, though:

    $ cat myseed |xkey -s m/0h/0/0
    

    When the -t option is used, stdin is used as a binary seed and the generated
    key will be a testnet key.

    $ cat myseed |xkey -t
    tprv8ZgxMBicQKsPen8dPzk2REDACTEDiRWqeNcdvrrxLsJ7UZCB3wH5tQsUbCBEPDREDACTEDfTh3skpif3GFENREDACTEDgemFAhG914qE5EC
    

    N is the derivation operator used to get the so-called neutered key, a.k.a the public extended key.

    $ base58 -d <<<"$myxprvkey" |xkey /N
    xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB
    

    ykey and zkey differ from xkey mostly by their serialization format, as described in bip-0049 and bip-0084.

    $ openssl rand 64 > myseed
    $ ykey -s < myseed
    yprvABrGsX5C9jantX14t9AjGYHoPw5LV3wdRD9JH3UxsEkMsxv3BcdzSFnqNidrmQ82nnLCmu3w6PWMZjPTmLKSAdBFBnXhqoE3VgBQLN6xJzg
    $ zkey -s < myseed
    zprvAWgYBBk7JR8GjieqUJjUQTqxVwy22Z7ZMPTUXJf2tsHG5Wa83ez3TQFqWWNCTVfyEc3tk7PxY2KTytxCMvW4p7obDWvymgbk2AmoQq1qL8Q
    

    You can feed any file to these functions, and such file doesn’t have to be 64 bytes long.
    It should, however, contain at least that much entropy.
    If the derivation path begins with m or M, and unless the option -p, -s or
    -t is used, additional checks are performed to ensure that the input is a
    master private key or a master public key respectively.
    When reading a binary seed, under the hood the seed feeds the following openssl command :

    openssl dgst -sha512 -hmac "Bitcoin seed" -binary

    The output of this command is then split in two to produce a chain code and a private exponent,
    as described in bip-0032.

    Mnemonics

    It is possible to store the keys of a hierarchical deterministic wallet in biological
    memory using mnemonics methods. Bitcoin-bash-tools offers two methods for this purpose :
    the first one is an implementation of the dedicated BIP, and the other is a method based on
    long known mnemonics techniques.

    Bip-39

    A seed can be produced from a mnemonic, a.k.a a secret phrase, as described
    in BIP-0039.
    To create a mnemonic, a function create-mnemonic takes as argument an amount of entropy in bits
    either 128, 160, 192, 224 or 256. Default is 160.

    $ create-mnemonic 128
    invest hedgehog slogan unfold liar thunder cream leaf kiss combine minor document
    

    The function will attempt to read the locale
    settings to figure out which language to use. If it fails, or if the local language is not
    supported, it will use English.
    To override local language settings, set the LANG environment variable :

    $ LANG=zh_TW create-mnemonic
    凍濾槍斷覆捉斷山未飛沿始瓦曰撐
    

    As you can see, Chinese output does not use spaces.
    Alternatively, the function can take as argument some noise in hexadecimal (the
    corresponding number of bits must be a multiple of 32).

    $ create-mnemonic "$(openssl rand -hex 20)"
    poem season process confirm meadow hidden will direct seed void height shadow live visual sauce
    

    To create a seed from a mnemonic, there is a function mnemonic-to-seed.

    $...