secp256k1: Split nonce code into separate files.

This moves the code for generating an RFC6979 nonce and the related
tests into separate files named nonce.go and nonce_test.go,
respectively.  The nonce is not specific to ecdsa and therefore it is
being split out so it remains accessible to multiple signing algorithms.
This commit is contained in:
Dave Collins 2020-03-23 19:48:48 -05:00
parent a183a4a9ba
commit dcadf8fb9c
No known key found for this signature in database
GPG Key ID: B8904D9D9C93D1F2
4 changed files with 468 additions and 453 deletions

263
dcrec/secp256k1/nonce.go Normal file
View File

@ -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()
}
}

View File

@ -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
}
}
}

View File

@ -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()
}
}

View File

@ -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) {