diff --git a/btcec/v2/schnorr/signature.go b/btcec/v2/schnorr/signature.go index a110e1b6..523214ac 100644 --- a/btcec/v2/schnorr/signature.go +++ b/btcec/v2/schnorr/signature.go @@ -21,14 +21,6 @@ const ( scalarSize = 32 ) -var ( - tagHashAux = []byte("BIP0340/aux") - - tagHashNonce = []byte("BIP0340/nonce") - - tagHashChallenge = []byte("BIP0340/challenge") -) - var ( // rfc6979ExtraDataV0 is the extra data to feed to RFC6979 when // generating the deterministic nonce for the BIP-340 scheme. This @@ -185,7 +177,7 @@ func schnorrVerify(sig *Signature, hash []byte, pub *btcec.PublicKey) error { pBytes := pubKey.SerializeCompressed() commitment := chainhash.TaggedHash( - tagHashChallenge, rBytes[:], pBytes[1:], hash, + chainhash.TagBIP0340Challenge, rBytes[:], pBytes[1:], hash, ) var e btcec.ModNScalar @@ -326,7 +318,7 @@ func schnorrSign(privKey, nonce *btcec.ModNScalar, pubKey *btcec.PublicKey, hash pBytes := pubKey.SerializeCompressed() commitment := chainhash.TaggedHash( - tagHashChallenge, rBytes[:], pBytes[1:], hash, + chainhash.TagBIP0340Challenge, rBytes[:], pBytes[1:], hash, ) var e btcec.ModNScalar @@ -493,7 +485,9 @@ func Sign(privKey *btcec.PrivateKey, hash []byte, // // t = bytes(d) xor tagged_hash("BIP0340/aux", a) privBytes := privKeyScalar.Bytes() - t := chainhash.TaggedHash(tagHashAux, (*opts.authNonce)[:]) + t := chainhash.TaggedHash( + chainhash.TagBIP0340Aux, (*opts.authNonce)[:], + ) for i := 0; i < len(t); i++ { t[i] ^= privBytes[i] } @@ -505,7 +499,7 @@ func Sign(privKey *btcec.PrivateKey, hash []byte, // We snip off the first byte of the serialized pubkey, as we // only need the x coordinate and not the market byte. rand := chainhash.TaggedHash( - tagHashNonce, t[:], pubKeyBytes[1:], hash, + chainhash.TagBIP0340Nonce, t[:], pubKeyBytes[1:], hash, ) // Step 8. diff --git a/chaincfg/chainhash/hash.go b/chaincfg/chainhash/hash.go index a71e6894..39401fd8 100644 --- a/chaincfg/chainhash/hash.go +++ b/chaincfg/chainhash/hash.go @@ -17,6 +17,25 @@ const HashSize = 32 // MaxHashStringSize is the maximum length of a Hash hash string. const MaxHashStringSize = HashSize * 2 +var ( + // TagBIP0340Challenge is the BIP-0340 tag for challenges. + TagBIP0340Challenge = []byte("BIP0340/challenge") + + // TagBIP0340Aux is the BIP-0340 tag for aux data. + TagBIP0340Aux = []byte("BIP0340/aux") + + // TagBIP0340Nonce is the BIP-0340 tag for nonces. + TagBIP0340Nonce = []byte("BIP0340/nonce") + + // precomputedTags is a map containing the SHA-256 hash of the BIP-0340 + // tags. + precomputedTags = map[string]Hash{ + string(TagBIP0340Challenge): sha256.Sum256(TagBIP0340Challenge), + string(TagBIP0340Aux): sha256.Sum256(TagBIP0340Aux), + string(TagBIP0340Nonce): sha256.Sum256(TagBIP0340Nonce), + } +) + // ErrHashStrSize describes an error that indicates the caller specified a hash // string that has too many characters. var ErrHashStrSize = fmt.Errorf("max hash string length is %v bytes", MaxHashStringSize) @@ -82,12 +101,13 @@ func NewHash(newHash []byte) (*Hash, error) { } // TaggedHash implements the tagged hash scheme described in BIP-340. We use -// sha-256 to bind a message hash to a speicifc context using a tag: +// sha-256 to bind a message hash to a specific context using a tag: // sha256(sha256(tag) || sha257(tag) || msg). -// -// TODO(roasbeef): add fast paths for common known tags func TaggedHash(tag []byte, msgs ...[]byte) *Hash { - shaTag := sha256.Sum256(tag) + shaTag, ok := precomputedTags[string(tag)] + if !ok { + shaTag = sha256.Sum256(tag) + } // h = sha256(sha256(tag) || sha256(tag) || msg h := sha256.New()