signatures

https://bitcoin.stackexchange.com/a/12556

There are two different encodings used. DER and compact

Everything in the Bitcoin protocol, including transaction signatures and alert signatures, uses DER encoding. This results in 71 bytes signatures (on average), as there are several header bytes, and the R and S valued are variable length.

For message signatures, a custom encoding is used which is more compact (and more recent) and supports public key recovery (given a message and a signature, find which public key would have created it). The code you're referring to in the question is for creating such signatures.

A correct DER-encoded signature has the following form:

  • 0x30: a header byte indicating a compound structure. A 1-byte length descriptor for all what follows.
  • 0x02: a header byte indicating an integer. A 1-byte length descriptor for the R value The R coordinate, as a big-endian integer.
  • 0x02: a header byte indicating an integer. A 1-byte length descriptor for the S value. The S coordinate, as a big-endian integer.

Where initial 0x00 bytes for R and S are not allowed, except when their first byte would otherwise be above 0x7F (in which case a single 0x00 in front is required). Also note that inside transaction signatures, an extra hashtype byte follows the actual signature data.

RI

C/C++

  • https://github.com/bitcoin-core/secp256k1
  • by Peter Wuille
  • 又名 libsecp256k1

How bitcoin using secp256k1

  • https://github.com/bitcoin/bitcoin/blob/v0.15.1/src/wallet/rpcwallet.cpp#L163-L171
    • https://github.com/bitcoin/bitcoin/blob/v0.15.1/src/wallet/wallet.cpp#L3437 (pubkey from pool)
      • https://github.com/bitcoin/bitcoin/blob/v0.15.1/src/wallet/wallet.cpp#L125-L158 (how pubkey gen)
        • https://github.com/bitcoin/bitcoin/blob/v0.15.1/src/key.cpp#L152 (use secp256k1 to create pubkey)
    • https://github.com/bitcoin/bitcoin/blob/v0.15.1/src/pubkey.h#L144 (hash160)
    • https://github.com/bitcoin/bitcoin/blob/v0.15.1/src/base58.cpp#L197 ( CBitcoinAddress(keyID).ToString() -> base58check)
$ src/bitcoin-cli getnewaddress
1Fop9P6BvWX5PdYcnABur6vXYbRVK2zjXp
$ src/bitcoin-cli dumpprivkey 1Fop9P6BvWX5PdYcnABur6vXYbRVK2zjXp
L3o684tsf6E4ZKwHXWwLd3pzjRksG7e9eeknqQP8XBytjTv8utje
$ echo L3o684tsf6E4ZKwHXWwLd3pzjRksG7e9eeknqQP8XBytjTv8utje|bx wif-to-public|bx ec-to-address
1Fop9P6BvWX5PdYcnABur6vXYbRVK2zjXp

How ex using secp256k1

  • https://github.com/libbitcoin/secp256k1 (is fork of bitcoin-core/secp256k1)
    • https://github.com/libbitcoin/libbitcoin/blob/v3.3.0/src/math/elliptic_curve.cpp
    • https://github.com/libbitcoin/libbitcoin/blob/v3.3.0/src/math/elliptic_curve.cpp#L85
    • https://github.com/libbitcoin/libbitcoin/blob/v3.3.0/src/wallet/ec_private.cpp#L201
    • https://github.com/libbitcoin/libbitcoin-explorer/blob/v3.3.0/src/commands/ec-new.cpp#L53
$ echo 000000000000000000000000000000000000000000000000 |bx ec-new
f00ccc9dae46346963a579b2ffb3deb67a1cb0da158aef9c7b839ac05640d190
$ echo 000000000000000000000000000000000000000000000000 |bx ec-new |bx ec-to-public
03dc8335336fe1ea6936f2c13c5ac06b5ab585e5c72434f8bc74829349c9d14054
$ echo 000000000000000000000000000000000000000000000000 |bx ec-new |bx ec-to-public |bx ec-to-address
12KWaMA14HonuGKvEruKwe7rAFPbUzpwVM

$ echo 000000000000000000000000000000000000000000000000 |bx ec-new |bx ec-to-wif
L5GLUwKZA1VLu1u85n4ZqViWcDFrvh7nDzENesWwsk1Ed4wCHBXe
$ echo 000000000000000000000000000000000000000000000000 |bx ec-new |bx ec-to-wif |bx wif-to-ec
f00ccc9dae46346963a579b2ffb3deb67a1cb0da158aef9c7b839ac05640d190
$ echo 000000000000000000000000000000000000000000000000 |bx ec-new |bx ec-to-wif |bx wif-to-ec|bx ec-to-public
03dc8335336fe1ea6936f2c13c5ac06b5ab585e5c72434f8bc74829349c9d14054
$ echo 000000000000000000000000000000000000000000000000 |bx ec-new |bx ec-to-wif |bx wif-to-ec|bx ec-to-public|bx ec-to-address
12KWaMA14HonuGKvEruKwe7rAFPbUzpwVM

How picocoin works with secp256k1

  • picocoin is C light lib by Jeff Garzik ( Gavin Andresen的朋友,segwit2x的主要开发)
  • https://github.com/jgarzik/picocoin/blob/v0.5/lib/key.c#L57-L73

how rust-bitcoin works with libsecp256k1

  • https://github.com/apoelstra/rust-bitcoin/blob/master/src/util/address.rs#L55-L64
  • https://github.com/apoelstra/rust-secp256k1/blob/master/src/key.rs#L146-L160
  • https://github.com/apoelstra/rust-secp256k1 is a wrapper around libsecp256k1,

how bitcoinj works with libsecp256k1

  • Using JNI (which provided by libsecp256k1 officially)
    • https://github.com/bitcoin-core/secp256k1/tree/master/src/java/
  • https://github.com/bitcoinj/bitcoinj/blob/v0.14.5/core/src/main/java/org/bitcoin/NativeSecp256k1.java
  • Note: bitcoinj looks maintained by greenaddress

Python

  • https://github.com/vbuterin/pybitcointools By VB
>>> sha256('some big long brainwallet password')
'57c617d9b4e1f7af6ec97ca2ff57e94a28279a7eedd4d12a99fa11170e94f5a4'
>>> decoded_private_key = bitcoin.decode_privkey(sha256('some big long brainwallet password'), 'hex')
>>> public_key = bitcoin.fast_multiply(bitcoin.G, decoded_private_key)
>>> hex_encoded_public_key = bitcoin.encode_pubkey(public_key, 'hex')
>>> bitcoin.pubkey_to_address(public_key)
'1CQLd3bhw4EzaURHbKCwM5YZbUQfA4ReY6'
>>> (public_key_x, public_key_y) = public_key
>>> compressed_prefix = '02' if (public_key_y % 2) == 0 else '03'
>>> hex_compressed_public_key = compressed_prefix + bitcoin.encode(public_key_x, 16)
>>> bitcoin.pubkey_to_address(hex_compressed_public_key)
'1EHw4jytKnzMSX8szNrXJ9FQiahKYnuuji'
$ echo 57c617d9b4e1f7af6ec97ca2ff57e94a28279a7eedd4d12a99fa11170e94f5a4|bx ec-to-public|bx ec-to-address
1EHw4jytKnzMSX8szNrXJ9FQiahKYnuuji

Javascript

  • https://github.com/cryptocoinjs/secp256k1-node

Go

  • Package btcec implements elliptic curve cryptography needed for working with Bitcoin (secp256k1 only for now).
  • https://github.com/btcsuite/btcd/tree/master/btcec
    • https://github.com/btcsuite/btcd/blob/master/btcec/pubkey.go#L69-L122

How Ethereum works with secp256k1

  • Ethereum use the hybrid solution
    • 公钥生成使用标准go api (crypto/ecdsa)
      • https://github.com/ethereum/go-ethereum/blob/v1.7.2/accounts/keystore/key.go#L161-L167
    • 签名使用cgo来调用libsecp256k1的c代码 (性能考虑)
      • https://github.com/ethereum/go-ethereum/blob/v1.7.2/crypto/secp256k1/secp256.go#L68-L97
    • 同时集成了btcec包, 当使用non-cgo模式时候,则使用这种方式(https://github.com/ethereum/go-ethereum/pull/3680 non-cgo fallback implementation of secp256k1 operations. The fallback implementation is not used when cgo is available. )
      • https://github.com/ethereum/go-ethereum/blob/v1.7.2/crypto/signature_nocgo.go#L48-L72

C#

  • https://github.com/MetacoSA/NBitcoin/blob/v4.0.0.42/NBitcoin/Crypto/ECKey.cs#L98
  • https://github.com/MetacoSA/NBitcoin/blob/v4.0.0.42/NBitcoin/BouncyCastle/math/ec/custom/sec/SecP256K1Curve.cs

Object-C

  • https://github.com/oleganza/CoreBitcoin/blob/0.6.8.1/openssl/include/openssl/obj_mac.h#L384-L386
  • https://github.com/oleganza/CoreBitcoin/blob/0.6.8.1/CoreBitcoin/BTCKey.h
  • https://github.com/oleganza/CoreBitcoin/blob/0.6.8.1/CoreBitcoin/BTCKey.m
  • https://github.com/oleganza/CoreBitcoin/blob/0.6.8.1/CoreBitcoin/BTCCurvePoint.h
  • https://github.com/oleganza/CoreBitcoin/blob/0.6.8.1/CoreBitcoin/BTCCurvePoint.m

Reference

  • https://en.bitcoin.it/wiki/Secp256k1
  • https://bitcoin.stackexchange.com/a/21911
  • https://github.com/bitcoinbook/bitcoinbook/blob/develop/ch04.asciidoc
  • https://github.com/bitcoinbook/bitcoinbook/blob/develop/code/key-to-address-ecc-example.py