func SignMessage(privKey string, message string, compress bool) string { prefixBytes := []byte("Bitcoin Signed Message:\n") messageBytes := []byte(message) bytes := []byte{} bytes = append(bytes, byte(len(prefixBytes))) bytes = append(bytes, prefixBytes...) bytes = append(bytes, byte(len(messageBytes))) bytes = append(bytes, messageBytes...) privKeyBytes := HexDecode(privKey) x, y := btcec.S256().ScalarBaseMult(privKeyBytes) ecdsaPubKey := ecdsa.PublicKey{ Curve: btcec.S256(), X: x, Y: y, } ecdsaPrivKey := &ecdsa.PrivateKey{ PublicKey: ecdsaPubKey, D: new(big.Int).SetBytes(privKeyBytes), } sigbytes, err := btcec.SignCompact(btcec.S256(), ecdsaPrivKey, btcwire.DoubleSha256(bytes), compress) if err != nil { panic(err) } return base64.StdEncoding.EncodeToString(sigbytes) }
// String returns the extended key as a human-readable base58-encoded string. func (k *ExtendedKey) String() string { if len(k.key) == 0 { return "zeroed extended key" } var childNumBytes [4]byte depthByte := byte(k.depth % 256) binary.BigEndian.PutUint32(childNumBytes[:], k.childNum) // The serialized format is: // version (4) || depth (1) || parent fingerprint (4)) || // child num (4) || chain code (32) || key data (33) || checksum (4) serializedBytes := make([]byte, 0, serializedKeyLen+4) serializedBytes = append(serializedBytes, k.version...) serializedBytes = append(serializedBytes, depthByte) serializedBytes = append(serializedBytes, k.parentFP...) serializedBytes = append(serializedBytes, childNumBytes[:]...) serializedBytes = append(serializedBytes, k.chainCode...) if k.isPrivate { serializedBytes = append(serializedBytes, 0x00) serializedBytes = append(serializedBytes, k.key...) } else { serializedBytes = append(serializedBytes, k.pubKeyBytes()...) } checkSum := btcwire.DoubleSha256(serializedBytes)[:4] serializedBytes = append(serializedBytes, checkSum...) return btcutil.Base58Encode(serializedBytes) }
// This example demonstrates signing a message with a secp256k1 private key that // is first parsed form raw bytes and serializing the generated signature. func Example_signMessage() { // Decode a hex-encoded private key. pkBytes, err := hex.DecodeString("22a47fa09a223f2aa079edf85a7c2d4f87" + "20ee63e502ee2869afab7de234b80c") if err != nil { fmt.Println(err) return } privKey, pubKey := btcec.PrivKeyFromBytes(btcec.S256(), pkBytes) // Sign a message using the private key. message := "test message" messageHash := btcwire.DoubleSha256([]byte(message)) signature, err := privKey.Sign(messageHash) if err != nil { fmt.Println(err) return } // Serialize and display the signature. // // NOTE: This is commented out for the example since the signature // produced uses random numbers and therefore will always be different. //fmt.Printf("Serialized Signature: %x\n", signature.Serialize()) // Verify the signature for the message using the public key. verified := signature.Verify(messageHash, pubKey) fmt.Printf("Signature Verified? %v\n", verified) // Output: // Signature Verified? true }
// DecodeAddress decodes a human-readable payment address string // returning the 20-byte decoded address, along with the Bitcoin // network for the address. // // DEPRECATED - Use DecodeAddr to decode a string encoded address to // the Address interface. func DecodeAddress(addr string) (addrHash []byte, net btcwire.BitcoinNet, err error) { decoded := Base58Decode(addr) // Length of decoded address must be 20 bytes + 1 byte for a network // identifier byte + 4 bytes of checksum. if len(decoded) != ripemd160.Size+5 { return nil, 0x00, ErrMalformedAddress } switch decoded[0] { case MainNetAddr: net = btcwire.MainNet case TestNetAddr: net = btcwire.TestNet3 default: return nil, 0, ErrUnknownNet } // Checksum is first four bytes of double SHA256 of the network byte // and addrHash. Verify this matches the final 4 bytes of the decoded // address. tosum := decoded[:ripemd160.Size+1] cksum := btcwire.DoubleSha256(tosum)[:4] if !bytes.Equal(cksum, decoded[len(decoded)-4:]) { return nil, net, ErrMalformedAddress } addrHash = make([]byte, ripemd160.Size, ripemd160.Size) copy(addrHash, decoded[1:ripemd160.Size+1]) return addrHash, net, nil }
// encodeAddress returns a human-readable payment address given a ripemd160 hash // and netID which encodes the bitcoin network and address type. It is used // in both pay-to-pubkey-hash (P2PKH) and pay-to-script-hash (P2SH) address // encoding. func encodeAddress(hash160 []byte, netID byte) string { // Format is 1 byte for a network and address class (i.e. P2PKH vs // P2SH), 20 bytes for a RIPEMD160 hash, and 4 bytes of checksum. b := make([]byte, 0, 1+ripemd160.Size+4) b = append(b, netID) b = append(b, hash160...) cksum := btcwire.DoubleSha256(b)[:4] b = append(b, cksum...) return Base58Encode(b) }
func (a *AddrManager) getTriedBucket(netAddr *btcwire.NetAddress) int { // bitcoind hashes this as: // doublesha256(key + group + truncate_to_64bits(doublesha256(key)) % buckets_per_group) % num_buckets data1 := []byte{} data1 = append(data1, a.key[:]...) data1 = append(data1, []byte(NetAddressKey(netAddr))...) hash1 := btcwire.DoubleSha256(data1) hash64 := binary.LittleEndian.Uint64(hash1) hash64 %= triedBucketsPerGroup hashbuf := new(bytes.Buffer) binary.Write(hashbuf, binary.LittleEndian, hash64) data2 := []byte{} data2 = append(data2, a.key[:]...) data2 = append(data2, GroupKey(netAddr)...) data2 = append(data2, hashbuf.Bytes()...) hash2 := btcwire.DoubleSha256(data2) return int(binary.LittleEndian.Uint64(hash2) % triedBucketCount) }
// hashMerkleBranches takes two hashes, treated as the left and right tree // nodes, and returns the hash of their concatenation. This is a helper // function used to during generatation of a merkle tree. func hashMerkleBranches(left *btcwire.ShaHash, right *btcwire.ShaHash) *btcwire.ShaHash { // Concatenate the left and right nodes. var sha [btcwire.HashSize * 2]byte copy(sha[:btcwire.HashSize], left.Bytes()) copy(sha[btcwire.HashSize:], right.Bytes()) // Create a new sha hash from the double sha 256. Ignore the error // here since SetBytes can't fail here due to the fact DoubleSha256 // always returns a []byte of the right size regardless of input. newSha, _ := btcwire.NewShaHash(btcwire.DoubleSha256(sha[:])) return newSha }
func (a *AddrManager) getNewBucket(netAddr, srcAddr *btcwire.NetAddress) int { // bitcoind: // doublesha256(key + sourcegroup + int64(doublesha256(key + group + sourcegroup))%bucket_per_source_group) % num_new_buckes data1 := []byte{} data1 = append(data1, a.key[:]...) data1 = append(data1, []byte(GroupKey(netAddr))...) data1 = append(data1, []byte(GroupKey(srcAddr))...) hash1 := btcwire.DoubleSha256(data1) hash64 := binary.LittleEndian.Uint64(hash1) hash64 %= newBucketsPerGroup hashbuf := new(bytes.Buffer) binary.Write(hashbuf, binary.LittleEndian, hash64) data2 := []byte{} data2 = append(data2, a.key[:]...) data2 = append(data2, GroupKey(srcAddr)...) data2 = append(data2, hashbuf.Bytes()...) hash2 := btcwire.DoubleSha256(data2) return int(binary.LittleEndian.Uint64(hash2) % newBucketCount) }
func encodeHashWithNetId(netID byte, addrHash []byte) (encoded string, err error) { tosum := append([]byte{netID}, addrHash...) cksum := btcwire.DoubleSha256(tosum) // Address before base58 encoding is 1 byte for netID, 20 bytes for // hash, plus 4 bytes of checksum. a := make([]byte, 25, 25) a[0] = netID copy(a[1:], addrHash) copy(a[21:], cksum[:4]) return Base58Encode(a), nil }
// NewKeyFromString returns a new extended key instance from a base58-encoded // extended key. func NewKeyFromString(key string) (*ExtendedKey, error) { // The base58-decoded extended key must consist of a serialized payload // plus an additional 4 bytes for the checksum. decoded := btcutil.Base58Decode(key) if len(decoded) != serializedKeyLen+4 { return nil, ErrInvalidKeyLen } // The serialized format is: // version (4) || depth (1) || parent fingerprint (4)) || // child num (4) || chain code (32) || key data (33) || checksum (4) // Split the payload and checksum up and ensure the checksum matches. payload := decoded[:len(decoded)-4] checkSum := decoded[len(decoded)-4:] expectedCheckSum := btcwire.DoubleSha256(payload)[:4] if !bytes.Equal(checkSum, expectedCheckSum) { return nil, ErrBadChecksum } // Deserialize each of the payload fields. version := payload[:4] depth := uint16(payload[4:5][0]) parentFP := payload[5:9] childNum := binary.BigEndian.Uint32(payload[9:13]) chainCode := payload[13:45] keyData := payload[45:78] // The key data is a private key if it starts with 0x00. Serialized // compressed pubkeys either start with 0x02 or 0x03. isPrivate := keyData[0] == 0x00 if isPrivate { // Ensure the private key is valid. It must be within the range // of the order of the secp256k1 curve and not be 0. keyData = keyData[1:] keyNum := new(big.Int).SetBytes(keyData) if keyNum.Cmp(btcec.S256().N) >= 0 || keyNum.Sign() == 0 { return nil, ErrUnusableSeed } } else { // Ensure the public key parses correctly and is actually on the // secp256k1 curve. _, err := btcec.ParsePubKey(keyData, btcec.S256()) if err != nil { return nil, err } } return newExtendedKey(version, keyData, chainCode, parentFP, depth, childNum, isPrivate), nil }
// DecodeAddr decodes the string encoding of an address and returns // the Address if addr is a valid encoding for a known address type. // // This is named DecodeAddr and not DecodeAddress due to DecodeAddress // already being defined for an old api. When the old api is eventually // removed, a proper DecodeAddress function will be added, and DecodeAddr // will become deprecated. func DecodeAddr(addr string) (Address, error) { decoded := Base58Decode(addr) // Switch on decoded length to determine the type. switch len(decoded) { case 1 + ripemd160.Size + 4: // P2PKH or P2SH // Parse the network and hash type (pubkey hash vs script // hash) from the first byte. net := btcwire.MainNet isscript := false switch decoded[0] { case MainNetAddr: // Use defaults. case TestNetAddr: net = btcwire.TestNet3 case MainNetScriptHash: isscript = true case TestNetScriptHash: isscript = true net = btcwire.TestNet3 default: return nil, ErrUnknownIdentifier } // Verify hash checksum. Checksum is calculated as the first // four bytes of double SHA256 of the network byte and hash. tosum := decoded[:ripemd160.Size+1] cksum := btcwire.DoubleSha256(tosum)[:4] if !bytes.Equal(cksum, decoded[len(decoded)-4:]) { return nil, ErrChecksumMismatch } // Return concrete type. if isscript { return NewAddressScriptHashFromHash( decoded[1:ripemd160.Size+1], net) } return NewAddressPubKeyHash(decoded[1:ripemd160.Size+1], net) default: return nil, errors.New("decoded address is of unknown size") } }
// encodeAddress returns a human-readable payment address given a ripemd160 hash // and netid which encodes the bitcoin network and address type. It is used // in both pay-to-pubkey-hash (P2PKH) and pay-to-script-hash (P2SH) address // encoding. func encodeAddress(hash160 []byte, netID byte) string { tosum := make([]byte, ripemd160.Size+1) tosum[0] = netID copy(tosum[1:], hash160) cksum := btcwire.DoubleSha256(tosum) // Address before base58 encoding is 1 byte for netID, ripemd160 hash // size, plus 4 bytes of checksum (total 25). b := make([]byte, ripemd160.Size+5, ripemd160.Size+5) b[0] = netID copy(b[1:], hash160) copy(b[ripemd160.Size+1:], cksum[:4]) return Base58Encode(b) }
// DecodePrivateKey takes a Wallet Import Format (WIF) string and // decodes into a 32-byte private key. func DecodePrivateKey(wif string) ([]byte, btcwire.BitcoinNet, bool, error) { decoded := Base58Decode(wif) decodedLen := len(decoded) compressed := false // Length of decoded privkey must be 32 bytes + an optional 1 byte (0x01) // if compressed, plus 1 byte for netID + 4 bytes of checksum if decodedLen == 32+6 { compressed = true if decoded[33] != 0x01 { return nil, 0, compressed, ErrMalformedPrivateKey } } else if decodedLen != 32+5 { return nil, 0, compressed, ErrMalformedPrivateKey } var net btcwire.BitcoinNet switch decoded[0] { case MainNetKey: net = btcwire.MainNet case TestNetKey: net = btcwire.TestNet3 default: return nil, 0, compressed, ErrUnknownNet } // Checksum is first four bytes of double SHA256 of the identifier byte // and privKey. Verify this matches the final 4 bytes of the decoded // private key. var tosum []byte if compressed { tosum = decoded[:32+1+1] } else { tosum = decoded[:32+1] } cksum := btcwire.DoubleSha256(tosum)[:4] if !bytes.Equal(cksum, decoded[decodedLen-4:]) { return nil, 0, compressed, ErrMalformedPrivateKey } privKey := make([]byte, 32, 32) copy(privKey[:], decoded[1:32+1]) return privKey, net, compressed, nil }
// DecodeAddress decodes the string encoding of an address and returns // the Address if addr is a valid encoding for a known address type. // // The bitcoin network the address is associated with is extracted if possible. // When the address does not encode the network, such as in the case of a raw // public key, the address will be associated with the passed defaultNet. func DecodeAddress(addr string, defaultNet *btcnet.Params) (Address, error) { // Serialized public keys are either 65 bytes (130 hex chars) if // uncompressed/hybrid or 33 bytes (66 hex chars) if compressed. if len(addr) == 130 || len(addr) == 66 { serializedPubKey, err := hex.DecodeString(addr) if err != nil { return nil, err } return NewAddressPubKey(serializedPubKey, defaultNet) } // Switch on decoded length to determine the type. decoded := Base58Decode(addr) switch len(decoded) { case 1 + ripemd160.Size + 4: // P2PKH or P2SH // Verify hash checksum. Checksum is calculated as the first // four bytes of double SHA256 of the network byte and hash. tosum := decoded[:ripemd160.Size+1] cksum := btcwire.DoubleSha256(tosum)[:4] if !bytes.Equal(cksum, decoded[len(decoded)-4:]) { return nil, ErrChecksumMismatch } netID := decoded[0] isP2PKH := btcnet.IsPubKeyHashAddrID(netID) isP2SH := btcnet.IsScriptHashAddrID(netID) switch hash160 := decoded[1 : ripemd160.Size+1]; { case isP2PKH && isP2SH: return nil, ErrAddressCollision case isP2PKH: return newAddressPubKeyHash(hash160, netID) case isP2SH: return newAddressScriptHashFromHash(hash160, netID) default: return nil, ErrUnknownAddressType } default: return nil, errors.New("decoded address is of unknown size") } }
// String creates the Wallet Import Format string encoding of a WIF structure. // See DecodeWIF for a detailed breakdown of the format and requirements of // a valid WIF string. func (w *WIF) String() string { // Precalculate size. Maximum number of bytes before base58 encoding // is one byte for the network, 32 bytes of private key, possibly one // extra byte if the pubkey is to be compressed, and finally four // bytes of checksum. encodeLen := 1 + btcec.PrivKeyBytesLen + 4 if w.CompressPubKey { encodeLen++ } a := make([]byte, 0, encodeLen) a = append(a, w.netID) // Pad and append bytes manually, instead of using Serialize, to // avoid another call to make. a = paddedAppend(btcec.PrivKeyBytesLen, a, w.PrivKey.D.Bytes()) if w.CompressPubKey { a = append(a, compressMagic) } cksum := btcwire.DoubleSha256(a)[:4] a = append(a, cksum...) return Base58Encode(a) }
// EncodePrivateKey takes a 32-byte private key and encodes it into the // Wallet Import Format (WIF). func EncodePrivateKey(privKey []byte, net btcwire.BitcoinNet, compressed bool) (string, error) { if len(privKey) != 32 { return "", ErrMalformedPrivateKey } var netID byte switch net { case btcwire.MainNet: netID = MainNetKey case btcwire.TestNet3: netID = TestNetKey default: return "", ErrUnknownNet } tosum := append([]byte{netID}, privKey...) if compressed { tosum = append(tosum, 0x01) } cksum := btcwire.DoubleSha256(tosum) // Private key before base58 encoding is 1 byte for netID, 32 bytes for // privKey, plus an optional byte (0x01) if copressed, plus 4 bytes of checksum. encodeLen := 37 if compressed { encodeLen += 1 } a := make([]byte, encodeLen, encodeLen) a[0] = netID copy(a[1:], privKey) if compressed { copy(a[32+1:], []byte{0x01}) copy(a[32+1+1:], cksum[:4]) } else { copy(a[32+1:], cksum[:4]) } return Base58Encode(a), nil }
// DecodeWIF creates a new WIF structure by decoding the string encoding of // the import format. // // The WIF string must be a base58-encoded string of the following byte // sequence: // // * 1 byte to identify the network, must be 0x80 for mainnet or 0xef for // either testnet3 or the regression test network // * 32 bytes of a binary-encoded, big-endian, zero-padded private key // * Optional 1 byte (equal to 0x01) if the address being imported or exported // was created by taking the RIPEMD160 after SHA256 hash of a serialized // compressed (33-byte) public key // * 4 bytes of checksum, must equal the first four bytes of the double SHA256 // of every byte before the checksum in this sequence // // If the base58-decoded byte sequence does not match this, DecodeWIF will // return a non-nil error. ErrMalformedPrivateKey is returned when the WIF // is of an impossible length or the expected compressed pubkey magic number // does not equal the expected value of 0x01. ErrChecksumMismatch is returned // if the expected WIF checksum does not match the calculated checksum. func DecodeWIF(wif string) (*WIF, error) { decoded := Base58Decode(wif) decodedLen := len(decoded) var compress bool // Length of base58 decoded WIF must be 32 bytes + an optional 1 byte // (0x01) if compressed, plus 1 byte for netID + 4 bytes of checksum. switch decodedLen { case 1 + btcec.PrivKeyBytesLen + 1 + 4: if decoded[33] != compressMagic { return nil, ErrMalformedPrivateKey } compress = true case 1 + btcec.PrivKeyBytesLen + 4: compress = false default: return nil, ErrMalformedPrivateKey } // Checksum is first four bytes of double SHA256 of the identifier byte // and privKey. Verify this matches the final 4 bytes of the decoded // private key. var tosum []byte if compress { tosum = decoded[:1+btcec.PrivKeyBytesLen+1] } else { tosum = decoded[:1+btcec.PrivKeyBytesLen] } cksum := btcwire.DoubleSha256(tosum)[:4] if !bytes.Equal(cksum, decoded[decodedLen-4:]) { return nil, ErrChecksumMismatch } netID := decoded[0] privKeyBytes := decoded[1 : 1+btcec.PrivKeyBytesLen] privKey, _ := btcec.PrivKeyFromBytes(btcec.S256(), privKeyBytes) return &WIF{privKey, compress, netID}, nil }
// This example demonstrates verifying a secp256k1 signature against a public // key that is first parsed from raw bytes. The signature is also parsed from // raw bytes. func Example_verifySignature() { // Decode hex-encoded serialized public key. pubKeyBytes, err := hex.DecodeString("02a673638cb9587cb68ea08dbef685c" + "6f2d2a751a8b3c6f2a7e9a4999e6e4bfaf5") if err != nil { fmt.Println(err) return } pubKey, err := btcec.ParsePubKey(pubKeyBytes, btcec.S256()) if err != nil { fmt.Println(err) return } // Decode hex-encoded serialized signature. sigBytes, err := hex.DecodeString("30450220090ebfb3690a0ff115bb1b38b" + "8b323a667b7653454f1bccb06d4bbdca42c2079022100ec95778b51e707" + "1cb1205f8bde9af6592fc978b0452dafe599481c46d6b2e479") if err != nil { fmt.Println(err) return } signature, err := btcec.ParseSignature(sigBytes, btcec.S256()) if err != nil { fmt.Println(err) return } // Verify the signature for the message using the public key. message := "test message" messageHash := btcwire.DoubleSha256([]byte(message)) verified := signature.Verify(messageHash, pubKey) fmt.Println("Signature Verified?", verified) // Output: // Signature Verified? true }
// calcScriptHash will, given the a script and hashtype for the current // scriptmachine, calculate the doubleSha256 hash of the transaction and // script to be used for signature signing and verification. func calcScriptHash(script []parsedOpcode, hashType byte, tx *btcwire.MsgTx, idx int) []byte { // remove all instances of OP_CODESEPARATOR still left in the script script = removeOpcode(script, OP_CODESEPARATOR) // Make a deep copy of the transaction, zeroing out the script // for all inputs that are not currently being processed. txCopy := tx.Copy() for i := range txCopy.TxIn { var txIn btcwire.TxIn txIn = *txCopy.TxIn[i] txCopy.TxIn[i] = &txIn if i == idx { // unparseScript cannot fail here, because removeOpcode // above only returns a valid script. sigscript, _ := unparseScript(script) txCopy.TxIn[idx].SignatureScript = sigscript } else { txCopy.TxIn[i].SignatureScript = []byte{} } } // Default behaviour has all outputs set up. for i := range txCopy.TxOut { var txOut btcwire.TxOut txOut = *txCopy.TxOut[i] txCopy.TxOut[i] = &txOut } switch hashType & 31 { case SigHashNone: txCopy.TxOut = txCopy.TxOut[0:0] // empty slice for i := range txCopy.TxIn { if i != idx { txCopy.TxIn[i].Sequence = 0 } } case SigHashSingle: if idx >= len(txCopy.TxOut) { // This was created by a buggy implementation. // In this case we do the same as bitcoind and bitcoinj // and return 1 (as a uint256 little endian) as an // error. Unfortunately this was not checked anywhere // and thus is treated as the actual // hash. hash := make([]byte, 32) hash[0] = 0x01 return hash } // Resize output array to up to and including requested index. txCopy.TxOut = txCopy.TxOut[:idx+1] // all but current output get zeroed out for i := 0; i < idx; i++ { txCopy.TxOut[i].Value = -1 txCopy.TxOut[i].PkScript = []byte{} } // Sequence on all other inputs is 0, too. for i := range txCopy.TxIn { if i != idx { txCopy.TxIn[i].Sequence = 0 } } default: // XXX bitcoind treats undefined hashtypes like normal // SigHashAll for purposes of hash generation. fallthrough case SigHashOld: fallthrough case SigHashAll: // nothing special here } if hashType&SigHashAnyOneCanPay != 0 { txCopy.TxIn = txCopy.TxIn[idx : idx+1] idx = 0 } var wbuf bytes.Buffer txCopy.Serialize(&wbuf) // Append LE 4 bytes hash type binary.Write(&wbuf, binary.LittleEndian, uint32(hashType)) return btcwire.DoubleSha256(wbuf.Bytes()) }
func dsha256(data []byte) []byte { return btcwire.DoubleSha256(data) }