diff --git a/dcrec/secp256k1/nonce.go b/dcrec/secp256k1/nonce.go new file mode 100644 index 00000000..81b205d9 --- /dev/null +++ b/dcrec/secp256k1/nonce.go @@ -0,0 +1,263 @@ +// Copyright (c) 2013-2014 The btcsuite developers +// Copyright (c) 2015-2020 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + "bytes" + "crypto/sha256" + "hash" +) + +// References: +// [GECC]: Guide to Elliptic Curve Cryptography (Hankerson, Menezes, Vanstone) +// +// [ISO/IEC 8825-1]: Information technology — ASN.1 encoding rules: +// Specification of Basic Encoding Rules (BER), Canonical Encoding Rules +// (CER) and Distinguished Encoding Rules (DER) +// +// [SEC1]: Elliptic Curve Cryptography (May 31, 2009, Version 2.0) +// https://www.secg.org/sec1-v2.pdf + +var ( + // singleZero is used during RFC6979 nonce generation. It is provided + // here to avoid the need to create it multiple times. + singleZero = []byte{0x00} + + // zeroInitializer is used during RFC6979 nonce generation. It is provided + // here to avoid the need to create it multiple times. + zeroInitializer = bytes.Repeat([]byte{0x00}, sha256.BlockSize) + + // singleOne is used during RFC6979 nonce generation. It is provided + // here to avoid the need to create it multiple times. + singleOne = []byte{0x01} + + // oneInitializer is used during RFC6979 nonce generation. It is provided + // here to avoid the need to create it multiple times. + oneInitializer = bytes.Repeat([]byte{0x01}, sha256.Size) +) + +// hmacsha256 implements a resettable version of HMAC-SHA256. +type hmacsha256 struct { + inner, outer hash.Hash + ipad, opad [sha256.BlockSize]byte +} + +// Write adds data to the running hash. +func (h *hmacsha256) Write(p []byte) { + h.inner.Write(p) +} + +// initKey initializes the HMAC-SHA256 instance to the provided key. +func (h *hmacsha256) initKey(key []byte) { + // Hash the key if it is too large. + if len(key) > sha256.BlockSize { + h.outer.Write(key) + key = h.outer.Sum(nil) + } + copy(h.ipad[:], key) + copy(h.opad[:], key) + for i := range h.ipad { + h.ipad[i] ^= 0x36 + } + for i := range h.opad { + h.opad[i] ^= 0x5c + } + h.inner.Write(h.ipad[:]) +} + +// ResetKey resets the HMAC-SHA256 to its initial state and then initializes it +// with the provided key. It is equivalent to creating a new instance with the +// provided key without allocating more memory. +func (h *hmacsha256) ResetKey(key []byte) { + h.inner.Reset() + h.outer.Reset() + copy(h.ipad[:], zeroInitializer) + copy(h.opad[:], zeroInitializer) + h.initKey(key) +} + +// Resets the HMAC-SHA256 to its initial state using the current key. +func (h *hmacsha256) Reset() { + h.inner.Reset() + h.inner.Write(h.ipad[:]) +} + +// Sum returns the hash of the written data. +func (h *hmacsha256) Sum() []byte { + h.outer.Reset() + h.outer.Write(h.opad[:]) + h.outer.Write(h.inner.Sum(nil)) + return h.outer.Sum(nil) +} + +// newHMACSHA256 returns a new HMAC-SHA256 hasher using the provided key. +func newHMACSHA256(key []byte) *hmacsha256 { + h := new(hmacsha256) + h.inner = sha256.New() + h.outer = sha256.New() + h.initKey(key) + return h +} + +// NonceRFC6979 generates a nonce deterministically according to RFC 6979 using +// HMAC-SHA256 for the hashing function. It takes a 32-byte hash as an input +// and returns a 32-byte nonce to be used for deterministic signing. The extra +// and version arguments are optional, but allow additional data to be added to +// the input of the HMAC. When provided, the extra data must be 32-bytes and +// version must be 16 bytes or they will be ignored. +// +// Finally, the extraIterations parameter provides a method to produce a stream +// of deterministic nonces to ensure the signing code is able to produce a nonce +// that results in a valid signature in the extremely unlikely event the +// original nonce produced results in an invalid signature (e.g. R == 0). +// Signing code should start with 0 and increment it if necessary. +func NonceRFC6979(privKey []byte, hash []byte, extra []byte, version []byte, extraIterations uint32) *ModNScalar { + // Input to HMAC is the 32-byte private key and the 32-byte hash. In + // addition, it may include the optional 32-byte extra data and 16-byte + // version. Create a fixed-size array to avoid extra allocs and slice it + // properly. + const ( + privKeyLen = 32 + hashLen = 32 + extraLen = 32 + versionLen = 16 + ) + var keyBuf [privKeyLen + hashLen + extraLen + versionLen]byte + + // Truncate rightmost bytes of private key and hash if they are too long and + // leave left padding of zeros when they're too short. + if len(privKey) > privKeyLen { + privKey = privKey[:privKeyLen] + } + if len(hash) > hashLen { + hash = hash[:hashLen] + } + offset := privKeyLen - len(privKey) // Zero left padding if needed. + offset += copy(keyBuf[offset:], privKey) + offset += hashLen - len(hash) // Zero left padding if needed. + offset += copy(keyBuf[offset:], hash) + if len(extra) == extraLen { + offset += copy(keyBuf[offset:], extra) + if len(version) == versionLen { + offset += copy(keyBuf[offset:], version) + } + } else if len(version) == versionLen { + // When the version was specified, but not the extra data, leave the + // extra data portion all zero. + offset += privKeyLen + offset += copy(keyBuf[offset:], version) + } + key := keyBuf[:offset] + + // Step B. + // + // V = 0x01 0x01 0x01 ... 0x01 such that the length of V, in bits, is + // equal to 8*ceil(hashLen/8). + // + // Note that since the hash length is a multiple of 8 for the chosen hash + // function in this optimized implementation, the result is just the hash + // length, so avoid the extra calculations. Also, since it isn't modified, + // start with a global value. + v := oneInitializer + + // Step C (Go zeroes all allocated memory). + // + // K = 0x00 0x00 0x00 ... 0x00 such that the length of K, in bits, is + // equal to 8*ceil(hashLen/8). + // + // As above, since the hash length is a multiple of 8 for the chosen hash + // function in this optimized implementation, the result is just the hash + // length, so avoid the extra calculations. + k := zeroInitializer[:hashLen] + + // Step D. + // + // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1)) + // + // Note that key is the "int2octets(x) || bits2octets(h1)" portion along + // with potential additional data as described by section 3.6 of the RFC. + hasher := newHMACSHA256(k) + hasher.Write(oneInitializer) + hasher.Write(singleZero[:]) + hasher.Write(key) + k = hasher.Sum() + + // Step E. + // + // V = HMAC_K(V) + hasher.ResetKey(k) + hasher.Write(v) + v = hasher.Sum() + + // Step F. + // + // K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1)) + // + // Note that key is the "int2octets(x) || bits2octets(h1)" portion along + // with potential additional data as described by section 3.6 of the RFC. + hasher.Reset() + hasher.Write(v) + hasher.Write(singleOne[:]) + hasher.Write(key[:]) + k = hasher.Sum() + + // Step G. + // + // V = HMAC_K(V) + hasher.ResetKey(k) + hasher.Write(v) + v = hasher.Sum() + + // Step H. + // + // Repeat until the value is nonzero and less than the curve order. + var generated uint32 + for { + // Step H1 and H2. + // + // Set T to the empty sequence. The length of T (in bits) is denoted + // tlen; thus, at that point, tlen = 0. + // + // While tlen < qlen, do the following: + // V = HMAC_K(V) + // T = T || V + // + // Note that because the hash function output is the same length as the + // private key in this optimized implementation, there is no need to + // loop or create an intermediate T. + hasher.Reset() + hasher.Write(v) + v = hasher.Sum() + + // Step H3. + // + // k = bits2int(T) + // If k is within the range [1,q-1], return it. + // + // Otherwise, compute: + // K = HMAC_K(V || 0x00) + // V = HMAC_K(V) + var secret ModNScalar + overflow := secret.SetByteSlice(v) + if !overflow && !secret.IsZero() { + generated++ + if generated > extraIterations { + return &secret + } + } + + // K = HMAC_K(V || 0x00) + hasher.Reset() + hasher.Write(v) + hasher.Write(singleZero[:]) + k = hasher.Sum() + + // V = HMAC_K(V) + hasher.ResetKey(k) + hasher.Write(v) + v = hasher.Sum() + } +} diff --git a/dcrec/secp256k1/nonce_test.go b/dcrec/secp256k1/nonce_test.go new file mode 100644 index 00000000..93b695ef --- /dev/null +++ b/dcrec/secp256k1/nonce_test.go @@ -0,0 +1,205 @@ +// Copyright (c) 2013-2016 The btcsuite developers +// Copyright (c) 2015-2020 The Decred developers +// Use of this source code is governed by an ISC +// license that can be found in the LICENSE file. + +package secp256k1 + +import ( + "bytes" + "crypto/sha256" + "testing" +) + +// TestNonceRFC6979 ensures that the deterministic nonces generated by +// NonceRFC6979 produces the expected nonces, including things such as when +// providing extra data and version information, short hashes, and multiple +// iterations. +func TestNonceRFC6979(t *testing.T) { + tests := []struct { + name string + key string + hash string + extraData string + version string + iterations uint32 + expected string + }{{ + name: "key 32 bytes, hash 32 bytes, no extra data, no version", + key: "0011111111111111111111111111111111111111111111111111111111111111", + hash: "0000000000000000000000000000000000000000000000000000000000000001", + iterations: 0, + expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", + }, { + // Should be same as key with 32 bytes due to zero padding. + name: "key <32 bytes, hash 32 bytes, no extra data, no version", + key: "11111111111111111111111111111111111111111111111111111111111111", + hash: "0000000000000000000000000000000000000000000000000000000000000001", + iterations: 0, + expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", + }, { + // Should be same as key with 32 bytes due to truncation. + name: "key >32 bytes, hash 32 bytes, no extra data, no version", + key: "001111111111111111111111111111111111111111111111111111111111111111", + hash: "0000000000000000000000000000000000000000000000000000000000000001", + iterations: 0, + expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", + }, { + name: "hash <32 bytes (padded), no extra data, no version", + key: "0011111111111111111111111111111111111111111111111111111111111111", + hash: "00000000000000000000000000000000000000000000000000000000000001", + iterations: 0, + expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", + }, { + name: "hash >32 bytes (truncated), no extra data, no version", + key: "0011111111111111111111111111111111111111111111111111111111111111", + hash: "000000000000000000000000000000000000000000000000000000000000000100", + iterations: 0, + expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", + }, { + name: "hash 32 bytes, extra data <32 bytes (ignored), no version", + key: "0011111111111111111111111111111111111111111111111111111111111111", + hash: "0000000000000000000000000000000000000000000000000000000000000001", + extraData: "00000000000000000000000000000000000000000000000000000000000002", + iterations: 0, + expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", + }, { + name: "hash 32 bytes, extra data >32 bytes (ignored), no version", + key: "0011111111111111111111111111111111111111111111111111111111111111", + hash: "0000000000000000000000000000000000000000000000000000000000000001", + extraData: "000000000000000000000000000000000000000000000000000000000000000002", + iterations: 0, + expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", + }, { + name: "hash 32 bytes, no extra data, version <16 bytes (ignored)", + key: "0011111111111111111111111111111111111111111111111111111111111111", + hash: "0000000000000000000000000000000000000000000000000000000000000001", + version: "000000000000000000000000000003", + iterations: 0, + expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", + }, { + name: "hash 32 bytes, no extra data, version >16 bytes (ignored)", + key: "001111111111111111111111111111111111111111111111111111111111111122", + hash: "0000000000000000000000000000000000000000000000000000000000000001", + version: "0000000000000000000000000000000003", + iterations: 0, + expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", + }, { + name: "hash 32 bytes, extra data 32 bytes, no version", + key: "0011111111111111111111111111111111111111111111111111111111111111", + hash: "0000000000000000000000000000000000000000000000000000000000000001", + extraData: "0000000000000000000000000000000000000000000000000000000000000002", + iterations: 0, + expected: "67893461ade51cde61824b20bc293b585d058e6b9f40fb68453d5143f15116ae", + }, { + name: "hash 32 bytes, no extra data, version 16 bytes", + key: "0011111111111111111111111111111111111111111111111111111111111111", + hash: "0000000000000000000000000000000000000000000000000000000000000001", + version: "00000000000000000000000000000003", + iterations: 0, + expected: "7b27d6ceff87e1ded1860ca4e271a530e48514b9d3996db0af2bb8bda189007d", + }, { + // Should be same as no extra data + version specified due to padding. + name: "hash 32 bytes, extra data 32 bytes all zero, version 16 bytes", + key: "0011111111111111111111111111111111111111111111111111111111111111", + hash: "0000000000000000000000000000000000000000000000000000000000000001", + extraData: "0000000000000000000000000000000000000000000000000000000000000000", + version: "00000000000000000000000000000003", + iterations: 0, + expected: "7b27d6ceff87e1ded1860ca4e271a530e48514b9d3996db0af2bb8bda189007d", + }, { + name: "hash 32 bytes, extra data 32 bytes, version 16 bytes", + key: "0011111111111111111111111111111111111111111111111111111111111111", + hash: "0000000000000000000000000000000000000000000000000000000000000001", + extraData: "0000000000000000000000000000000000000000000000000000000000000002", + version: "00000000000000000000000000000003", + iterations: 0, + expected: "9b5657643dfd4b77d99dfa505ed8a17e1b9616354fc890669b4aabece2170686", + }, { + name: "hash 32 bytes, no extra data, no version, extra iteration", + key: "0011111111111111111111111111111111111111111111111111111111111111", + hash: "0000000000000000000000000000000000000000000000000000000000000001", + iterations: 1, + expected: "66fca3fe494a6216e4a3f15cfbc1d969c60d9cdefda1a1c193edabd34aa8cd5e", + }, { + name: "hash 32 bytes, no extra data, no version, 2 extra iterations", + key: "0011111111111111111111111111111111111111111111111111111111111111", + hash: "0000000000000000000000000000000000000000000000000000000000000001", + iterations: 2, + expected: "70da248c92b5d28a52eafca1848b1a37d4cb36526c02553c9c48bb0b895fc77d", + }} + + for _, test := range tests { + privKey := hexToBytes(test.key) + hash := hexToBytes(test.hash) + extraData := hexToBytes(test.extraData) + version := hexToBytes(test.version) + wantNonce := hexToBytes(test.expected) + + // Ensure deterministically generated nonce is the expected value. + gotNonce := NonceRFC6979(privKey, hash[:], extraData, version, + test.iterations) + gotNonceBytes := gotNonce.Bytes() + if !bytes.Equal(gotNonceBytes[:], wantNonce) { + t.Errorf("%s: unexpected nonce -- got %x, want %x", test.name, + gotNonceBytes, wantNonce) + continue + } + } +} + +// TestRFC6979Compat ensures that the deterministic nonces generated by +// NonceRFC6979 produces the expected nonces for known values from other +// implementations. +func TestRFC6979Compat(t *testing.T) { + // Test vectors matching Trezor and CoreBitcoin implementations. + // - https://github.com/trezor/trezor-crypto/blob/9fea8f8ab377dc514e40c6fd1f7c89a74c1d8dc6/tests.c#L432-L453 + // - https://github.com/oleganza/CoreBitcoin/blob/e93dd71207861b5bf044415db5fa72405e7d8fbc/CoreBitcoin/BTCKey%2BTests.m#L23-L49 + tests := []struct { + key string + msg string + nonce string + }{{ + "cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", + "sample", + "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3", + }, { + // This signature hits the case when S is higher than halforder. + // If S is not canonicalized (lowered by halforder), this test will fail. + "0000000000000000000000000000000000000000000000000000000000000001", + "Satoshi Nakamoto", + "8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15", + }, { + "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", + "Satoshi Nakamoto", + "33a19b60e25fb6f4435af53a3d42d493644827367e6453928554f43e49aa6f90", + }, { + "f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181", + "Alan Turing", + "525a82b70e67874398067543fd84c83d30c175fdc45fdeee082fe13b1d7cfdf1", + }, { + "0000000000000000000000000000000000000000000000000000000000000001", + "All those moments will be lost in time, like tears in rain. Time to die...", + "38aa22d72376b4dbc472e06c3ba403ee0a394da63fc58d88686c611aba98d6b3", + }, { + "e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2", + "There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them!", + "1f4b84c23a86a221d233f2521be018d9318639d5b8bbd6374a8a59232d16ad3d", + }} + + for i, test := range tests { + privKey := hexToBytes(test.key) + hash := sha256.Sum256([]byte(test.msg)) + + // Ensure deterministically generated nonce is the expected value. + gotNonce := NonceRFC6979(privKey, hash[:], nil, nil, 0) + wantNonce := hexToBytes(test.nonce) + gotNonceBytes := gotNonce.Bytes() + if !bytes.Equal(gotNonceBytes[:], wantNonce) { + t.Errorf("NonceRFC6979 #%d (%s): Nonce is incorrect: "+ + "%x (expected %x)", i, test.msg, gotNonce, + wantNonce) + continue + } + } +} diff --git a/dcrec/secp256k1/signature.go b/dcrec/secp256k1/signature.go index 9a7b4465..4eefc1bf 100644 --- a/dcrec/secp256k1/signature.go +++ b/dcrec/secp256k1/signature.go @@ -6,11 +6,8 @@ package secp256k1 import ( - "bytes" - "crypto/sha256" "errors" "fmt" - "hash" ) // References: @@ -30,22 +27,6 @@ type Signature struct { } var ( - // singleZero is used during RFC6979 nonce generation. It is provided - // here to avoid the need to create it multiple times. - singleZero = []byte{0x00} - - // zeroInitializer is used during RFC6979 nonce generation. It is provided - // here to avoid the need to create it multiple times. - zeroInitializer = bytes.Repeat([]byte{0x00}, sha256.BlockSize) - - // singleOne is used during RFC6979 nonce generation. It is provided - // here to avoid the need to create it multiple times. - singleOne = []byte{0x01} - - // oneInitializer is used during RFC6979 nonce generation. It is provided - // here to avoid the need to create it multiple times. - oneInitializer = bytes.Repeat([]byte{0x01}, sha256.Size) - // orderAsFieldVal is the order of the secp256k1 curve group stored as a // field value. It is provided here to avoid the need to create it multiple // times. @@ -918,226 +899,3 @@ func signRFC6979(privateKey *PrivateKey, hash []byte) (*Signature, byte) { return NewSignature(&r, s), pubKeyRecoveryCode } } - -// hmacsha256 implements a resettable version of HMAC-SHA256. -type hmacsha256 struct { - inner, outer hash.Hash - ipad, opad [sha256.BlockSize]byte -} - -// Write adds data to the running hash. -func (h *hmacsha256) Write(p []byte) { - h.inner.Write(p) -} - -// initKey initializes the HMAC-SHA256 instance to the provided key. -func (h *hmacsha256) initKey(key []byte) { - // Hash the key if it is too large. - if len(key) > sha256.BlockSize { - h.outer.Write(key) - key = h.outer.Sum(nil) - } - copy(h.ipad[:], key) - copy(h.opad[:], key) - for i := range h.ipad { - h.ipad[i] ^= 0x36 - } - for i := range h.opad { - h.opad[i] ^= 0x5c - } - h.inner.Write(h.ipad[:]) -} - -// ResetKey resets the HMAC-SHA256 to its initial state and then initializes it -// with the provided key. It is equivalent to creating a new instance with the -// provided key without allocating more memory. -func (h *hmacsha256) ResetKey(key []byte) { - h.inner.Reset() - h.outer.Reset() - copy(h.ipad[:], zeroInitializer) - copy(h.opad[:], zeroInitializer) - h.initKey(key) -} - -// Resets the HMAC-SHA256 to its initial state using the current key. -func (h *hmacsha256) Reset() { - h.inner.Reset() - h.inner.Write(h.ipad[:]) -} - -// Sum returns the hash of the written data. -func (h *hmacsha256) Sum() []byte { - h.outer.Reset() - h.outer.Write(h.opad[:]) - h.outer.Write(h.inner.Sum(nil)) - return h.outer.Sum(nil) -} - -// newHMACSHA256 returns a new HMAC-SHA256 hasher using the provided key. -func newHMACSHA256(key []byte) *hmacsha256 { - h := new(hmacsha256) - h.inner = sha256.New() - h.outer = sha256.New() - h.initKey(key) - return h -} - -// NonceRFC6979 generates a nonce deterministically according to RFC 6979 using -// HMAC-SHA256 for the hashing function. It takes a 32-byte hash as an input -// and returns a 32-byte nonce to be used for deterministic signing. The extra -// and version arguments are optional, but allow additional data to be added to -// the input of the HMAC. When provided, the extra data must be 32-bytes and -// version must be 16 bytes or they will be ignored. -// -// Finally, the extraIterations parameter provides a method to produce a stream -// of deterministic nonces to ensure the signing code is able to produce a nonce -// that results in a valid signature in the extremely unlikely event the -// original nonce produced results in an invalid signature (e.g. R == 0). -// Signing code should start with 0 and increment it if necessary. -func NonceRFC6979(privKey []byte, hash []byte, extra []byte, version []byte, extraIterations uint32) *ModNScalar { - // Input to HMAC is the 32-byte private key and the 32-byte hash. In - // addition, it may include the optional 32-byte extra data and 16-byte - // version. Create a fixed-size array to avoid extra allocs and slice it - // properly. - const ( - privKeyLen = 32 - hashLen = 32 - extraLen = 32 - versionLen = 16 - ) - var keyBuf [privKeyLen + hashLen + extraLen + versionLen]byte - - // Truncate rightmost bytes of private key and hash if they are too long and - // leave left padding of zeros when they're too short. - if len(privKey) > privKeyLen { - privKey = privKey[:privKeyLen] - } - if len(hash) > hashLen { - hash = hash[:hashLen] - } - offset := privKeyLen - len(privKey) // Zero left padding if needed. - offset += copy(keyBuf[offset:], privKey) - offset += hashLen - len(hash) // Zero left padding if needed. - offset += copy(keyBuf[offset:], hash) - if len(extra) == extraLen { - offset += copy(keyBuf[offset:], extra) - if len(version) == versionLen { - offset += copy(keyBuf[offset:], version) - } - } else if len(version) == versionLen { - // When the version was specified, but not the extra data, leave the - // extra data portion all zero. - offset += privKeyLen - offset += copy(keyBuf[offset:], version) - } - key := keyBuf[:offset] - - // Step B. - // - // V = 0x01 0x01 0x01 ... 0x01 such that the length of V, in bits, is - // equal to 8*ceil(hashLen/8). - // - // Note that since the hash length is a multiple of 8 for the chosen hash - // function in this optimized implementation, the result is just the hash - // length, so avoid the extra calculations. Also, since it isn't modified, - // start with a global value. - v := oneInitializer - - // Step C (Go zeroes all allocated memory). - // - // K = 0x00 0x00 0x00 ... 0x00 such that the length of K, in bits, is - // equal to 8*ceil(hashLen/8). - // - // As above, since the hash length is a multiple of 8 for the chosen hash - // function in this optimized implementation, the result is just the hash - // length, so avoid the extra calculations. - k := zeroInitializer[:hashLen] - - // Step D. - // - // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1)) - // - // Note that key is the "int2octets(x) || bits2octets(h1)" portion along - // with potential additional data as described by section 3.6 of the RFC. - hasher := newHMACSHA256(k) - hasher.Write(oneInitializer) - hasher.Write(singleZero[:]) - hasher.Write(key) - k = hasher.Sum() - - // Step E. - // - // V = HMAC_K(V) - hasher.ResetKey(k) - hasher.Write(v) - v = hasher.Sum() - - // Step F. - // - // K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1)) - // - // Note that key is the "int2octets(x) || bits2octets(h1)" portion along - // with potential additional data as described by section 3.6 of the RFC. - hasher.Reset() - hasher.Write(v) - hasher.Write(singleOne[:]) - hasher.Write(key[:]) - k = hasher.Sum() - - // Step G. - // - // V = HMAC_K(V) - hasher.ResetKey(k) - hasher.Write(v) - v = hasher.Sum() - - // Step H. - // - // Repeat until the value is nonzero and less than the curve order. - var generated uint32 - for { - // Step H1 and H2. - // - // Set T to the empty sequence. The length of T (in bits) is denoted - // tlen; thus, at that point, tlen = 0. - // - // While tlen < qlen, do the following: - // V = HMAC_K(V) - // T = T || V - // - // Note that because the hash function output is the same length as the - // private key in this optimized implementation, there is no need to - // loop or create an intermediate T. - hasher.Reset() - hasher.Write(v) - v = hasher.Sum() - - // Step H3. - // - // k = bits2int(T) - // If k is within the range [1,q-1], return it. - // - // Otherwise, compute: - // K = HMAC_K(V || 0x00) - // V = HMAC_K(V) - var secret ModNScalar - overflow := secret.SetByteSlice(v) - if !overflow && !secret.IsZero() { - generated++ - if generated > extraIterations { - return &secret - } - } - - // K = HMAC_K(V || 0x00) - hasher.Reset() - hasher.Write(v) - hasher.Write(singleZero[:]) - k = hasher.Sum() - - // V = HMAC_K(V) - hasher.ResetKey(k) - hasher.Write(v) - v = hasher.Sum() - } -} diff --git a/dcrec/secp256k1/signature_test.go b/dcrec/secp256k1/signature_test.go index e9911e6a..02becac8 100644 --- a/dcrec/secp256k1/signature_test.go +++ b/dcrec/secp256k1/signature_test.go @@ -8,7 +8,6 @@ package secp256k1 import ( "bytes" "crypto/rand" - "crypto/sha256" "encoding/hex" "errors" "fmt" @@ -343,216 +342,6 @@ func TestSignCompact(t *testing.T) { } } -// TestNonceRFC6979 ensures that the deterministic nonces generated by -// NonceRFC6979 produces the expected nonces, including things such as when -// providing extra data and version information, short hashes, and multiple -// iterations. -func TestNonceRFC6979(t *testing.T) { - tests := []struct { - name string - key string - hash string - extraData string - version string - iterations uint32 - expected string - }{{ - name: "key 32 bytes, hash 32 bytes, no extra data, no version", - key: "0011111111111111111111111111111111111111111111111111111111111111", - hash: "0000000000000000000000000000000000000000000000000000000000000001", - iterations: 0, - expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", - }, { - // Should be same as key with 32 bytes due to zero padding. - name: "key <32 bytes, hash 32 bytes, no extra data, no version", - key: "11111111111111111111111111111111111111111111111111111111111111", - hash: "0000000000000000000000000000000000000000000000000000000000000001", - iterations: 0, - expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", - }, { - // Should be same as key with 32 bytes due to truncation. - name: "key >32 bytes, hash 32 bytes, no extra data, no version", - key: "001111111111111111111111111111111111111111111111111111111111111111", - hash: "0000000000000000000000000000000000000000000000000000000000000001", - iterations: 0, - expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", - }, { - name: "hash <32 bytes (padded), no extra data, no version", - key: "0011111111111111111111111111111111111111111111111111111111111111", - hash: "00000000000000000000000000000000000000000000000000000000000001", - iterations: 0, - expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", - }, { - name: "hash >32 bytes (truncated), no extra data, no version", - key: "0011111111111111111111111111111111111111111111111111111111111111", - hash: "000000000000000000000000000000000000000000000000000000000000000100", - iterations: 0, - expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", - }, { - name: "hash 32 bytes, extra data <32 bytes (ignored), no version", - key: "0011111111111111111111111111111111111111111111111111111111111111", - hash: "0000000000000000000000000000000000000000000000000000000000000001", - extraData: "00000000000000000000000000000000000000000000000000000000000002", - iterations: 0, - expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", - }, { - name: "hash 32 bytes, extra data >32 bytes (ignored), no version", - key: "0011111111111111111111111111111111111111111111111111111111111111", - hash: "0000000000000000000000000000000000000000000000000000000000000001", - extraData: "000000000000000000000000000000000000000000000000000000000000000002", - iterations: 0, - expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", - }, { - name: "hash 32 bytes, no extra data, version <16 bytes (ignored)", - key: "0011111111111111111111111111111111111111111111111111111111111111", - hash: "0000000000000000000000000000000000000000000000000000000000000001", - version: "000000000000000000000000000003", - iterations: 0, - expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", - }, { - name: "hash 32 bytes, no extra data, version >16 bytes (ignored)", - key: "001111111111111111111111111111111111111111111111111111111111111122", - hash: "0000000000000000000000000000000000000000000000000000000000000001", - version: "0000000000000000000000000000000003", - iterations: 0, - expected: "154e92760f77ad9af6b547edd6f14ad0fae023eb2221bc8be2911675d8a686a3", - }, { - name: "hash 32 bytes, extra data 32 bytes, no version", - key: "0011111111111111111111111111111111111111111111111111111111111111", - hash: "0000000000000000000000000000000000000000000000000000000000000001", - extraData: "0000000000000000000000000000000000000000000000000000000000000002", - iterations: 0, - expected: "67893461ade51cde61824b20bc293b585d058e6b9f40fb68453d5143f15116ae", - }, { - name: "hash 32 bytes, no extra data, version 16 bytes", - key: "0011111111111111111111111111111111111111111111111111111111111111", - hash: "0000000000000000000000000000000000000000000000000000000000000001", - version: "00000000000000000000000000000003", - iterations: 0, - expected: "7b27d6ceff87e1ded1860ca4e271a530e48514b9d3996db0af2bb8bda189007d", - }, { - // Should be same as no extra data + version specified due to padding. - name: "hash 32 bytes, extra data 32 bytes all zero, version 16 bytes", - key: "0011111111111111111111111111111111111111111111111111111111111111", - hash: "0000000000000000000000000000000000000000000000000000000000000001", - extraData: "0000000000000000000000000000000000000000000000000000000000000000", - version: "00000000000000000000000000000003", - iterations: 0, - expected: "7b27d6ceff87e1ded1860ca4e271a530e48514b9d3996db0af2bb8bda189007d", - }, { - name: "hash 32 bytes, extra data 32 bytes, version 16 bytes", - key: "0011111111111111111111111111111111111111111111111111111111111111", - hash: "0000000000000000000000000000000000000000000000000000000000000001", - extraData: "0000000000000000000000000000000000000000000000000000000000000002", - version: "00000000000000000000000000000003", - iterations: 0, - expected: "9b5657643dfd4b77d99dfa505ed8a17e1b9616354fc890669b4aabece2170686", - }, { - name: "hash 32 bytes, no extra data, no version, extra iteration", - key: "0011111111111111111111111111111111111111111111111111111111111111", - hash: "0000000000000000000000000000000000000000000000000000000000000001", - iterations: 1, - expected: "66fca3fe494a6216e4a3f15cfbc1d969c60d9cdefda1a1c193edabd34aa8cd5e", - }, { - name: "hash 32 bytes, no extra data, no version, 2 extra iterations", - key: "0011111111111111111111111111111111111111111111111111111111111111", - hash: "0000000000000000000000000000000000000000000000000000000000000001", - iterations: 2, - expected: "70da248c92b5d28a52eafca1848b1a37d4cb36526c02553c9c48bb0b895fc77d", - }} - - for _, test := range tests { - privKey := hexToBytes(test.key) - hash := hexToBytes(test.hash) - extraData := hexToBytes(test.extraData) - version := hexToBytes(test.version) - wantNonce := hexToBytes(test.expected) - - // Ensure deterministically generated nonce is the expected value. - gotNonce := NonceRFC6979(privKey, hash[:], extraData, version, - test.iterations) - gotNonceBytes := gotNonce.Bytes() - if !bytes.Equal(gotNonceBytes[:], wantNonce) { - t.Errorf("%s: unexpected nonce -- got %x, want %x", test.name, - gotNonceBytes, wantNonce) - continue - } - } -} - -// TestRFC6979Compat ensures that the deterministic nonces generated by -// NonceRFC6979 produces the expected nonces and resulting signatures for known -// values from other implementations. -func TestRFC6979Compat(t *testing.T) { - // Test vectors matching Trezor and CoreBitcoin implementations. - // - https://github.com/trezor/trezor-crypto/blob/9fea8f8ab377dc514e40c6fd1f7c89a74c1d8dc6/tests.c#L432-L453 - // - https://github.com/oleganza/CoreBitcoin/blob/e93dd71207861b5bf044415db5fa72405e7d8fbc/CoreBitcoin/BTCKey%2BTests.m#L23-L49 - tests := []struct { - key string - msg string - nonce string - signature string - }{{ - "cca9fbcc1b41e5a95d369eaa6ddcff73b61a4efaa279cfc6567e8daa39cbaf50", - "sample", - "2df40ca70e639d89528a6b670d9d48d9165fdc0febc0974056bdce192b8e16a3", - "3045022100af340daf02cc15c8d5d08d7735dfe6b98a474ed373bdb5fbecf7571be52b384202205009fb27f37034a9b24b707b7c6b79ca23ddef9e25f7282e8a797efe53a8f124", - }, { - // This signature hits the case when S is higher than halforder. - // If S is not canonicalized (lowered by halforder), this test will fail. - "0000000000000000000000000000000000000000000000000000000000000001", - "Satoshi Nakamoto", - "8f8a276c19f4149656b280621e358cce24f5f52542772691ee69063b74f15d15", - "3045022100934b1ea10a4b3c1757e2b0c017d0b6143ce3c9a7e6a4a49860d7a6ab210ee3d802202442ce9d2b916064108014783e923ec36b49743e2ffa1c4496f01a512aafd9e5", - }, { - "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140", - "Satoshi Nakamoto", - "33a19b60e25fb6f4435af53a3d42d493644827367e6453928554f43e49aa6f90", - "3045022100fd567d121db66e382991534ada77a6bd3106f0a1098c231e47993447cd6af2d002206b39cd0eb1bc8603e159ef5c20a5c8ad685a45b06ce9bebed3f153d10d93bed5", - }, { - "f8b8af8ce3c7cca5e300d33939540c10d45ce001b8f252bfbc57ba0342904181", - "Alan Turing", - "525a82b70e67874398067543fd84c83d30c175fdc45fdeee082fe13b1d7cfdf1", - "304402207063ae83e7f62bbb171798131b4a0564b956930092b33b07b395615d9ec7e15c022058dfcc1e00a35e1572f366ffe34ba0fc47db1e7189759b9fb233c5b05ab388ea", - }, { - "0000000000000000000000000000000000000000000000000000000000000001", - "All those moments will be lost in time, like tears in rain. Time to die...", - "38aa22d72376b4dbc472e06c3ba403ee0a394da63fc58d88686c611aba98d6b3", - "30450221008600dbd41e348fe5c9465ab92d23e3db8b98b873beecd930736488696438cb6b0220547fe64427496db33bf66019dacbf0039c04199abb0122918601db38a72cfc21", - }, { - "e91671c46231f833a6406ccbea0e3e392c76c167bac1cb013f6f1013980455c2", - "There is a computer disease that anybody who works with computers knows about. It's a very serious disease and it interferes completely with the work. The trouble with computers is that you 'play' with them!", - "1f4b84c23a86a221d233f2521be018d9318639d5b8bbd6374a8a59232d16ad3d", - "3045022100b552edd27580141f3b2a5463048cb7cd3e047b97c9f98076c32dbdf85a68718b0220279fa72dd19bfae05577e06c7c0c1900c371fcd5893f7e1d56a37d30174671f6", - }} - - for i, test := range tests { - privKey := hexToBytes(test.key) - hash := sha256.Sum256([]byte(test.msg)) - - // Ensure deterministically generated nonce is the expected value. - gotNonce := NonceRFC6979(privKey, hash[:], nil, nil, 0) - wantNonce := hexToBytes(test.nonce) - gotNonceBytes := gotNonce.Bytes() - if !bytes.Equal(gotNonceBytes[:], wantNonce) { - t.Errorf("NonceRFC6979 #%d (%s): Nonce is incorrect: "+ - "%x (expected %x)", i, test.msg, gotNonce, - wantNonce) - continue - } - - // Ensure deterministically generated signature is the expected value. - gotSig := PrivKeyFromBytes(privKey).Sign(hash[:]) - gotSigBytes := gotSig.Serialize() - wantSigBytes := hexToBytes(test.signature) - if !bytes.Equal(gotSigBytes, wantSigBytes) { - t.Errorf("Sign #%d (%s): mismatched signature: %x (expected %x)", i, - test.msg, gotSigBytes, wantSigBytes) - continue - } - } -} - // TestSignatureIsEqual ensures that equality testing between to signatures // works as expected. func TestSignatureIsEqual(t *testing.T) {