Skip to content

Commit 1f3d515

Browse files
committed
btcec/schnorr: zero out signature parsing allocations
Make ParseSignature short and simple, becoming eligible to inlining which avoids allocations.
1 parent 118e825 commit 1f3d515

1 file changed

Lines changed: 27 additions & 14 deletions

File tree

btcec/schnorr/signature.go

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -62,39 +62,52 @@ func (sig Signature) Serialize() []byte {
6262
return b[:]
6363
}
6464

65-
// ParseSignature parses a signature according to the BIP-340 specification and
66-
// enforces the following additional restrictions specific to secp256k1:
67-
//
68-
// - The r component must be in the valid range for secp256k1 field elements
69-
// - The s component must be in the valid range for secp256k1 scalars
70-
func ParseSignature(sig []byte) (*Signature, error) {
65+
// parseSignature exists to make ParseSignature eligible to inlining and
66+
// therefore avoid allocations.
67+
func parseSignature(sig *Signature, sigb []byte) error {
7168
// The signature must be the correct length.
72-
sigLen := len(sig)
69+
sigLen := len(sigb)
7370
if sigLen < SignatureSize {
7471
str := fmt.Sprintf("malformed signature: too short: %d < %d", sigLen,
7572
SignatureSize)
76-
return nil, signatureError(ecdsa_schnorr.ErrSigTooShort, str)
73+
return signatureError(ecdsa_schnorr.ErrSigTooShort, str)
7774
}
7875
if sigLen > SignatureSize {
7976
str := fmt.Sprintf("malformed signature: too long: %d > %d", sigLen,
8077
SignatureSize)
81-
return nil, signatureError(ecdsa_schnorr.ErrSigTooLong, str)
78+
return signatureError(ecdsa_schnorr.ErrSigTooLong, str)
8279
}
8380

8481
// The signature is validly encoded at this point, however, enforce
8582
// additional restrictions to ensure r is in the range [0, p-1], and s is in
8683
// the range [0, n-1] since valid Schnorr signatures are required to be in
8784
// that range per spec.
8885
var r btcec.FieldVal
89-
if overflow := r.SetByteSlice(sig[0:32]); overflow {
86+
if overflow := r.SetByteSlice(sigb[0:32]); overflow {
9087
str := "invalid signature: r >= field prime"
91-
return nil, signatureError(ecdsa_schnorr.ErrSigRTooBig, str)
88+
return signatureError(ecdsa_schnorr.ErrSigRTooBig, str)
9289
}
9390
var s btcec.ModNScalar
94-
s.SetByteSlice(sig[32:64])
91+
s.SetByteSlice(sigb[32:64])
92+
93+
// Return the normalized signature.
94+
sig.r = r
95+
sig.s = s
96+
sig.r.Normalize()
97+
return nil
98+
}
9599

96-
// Return the signature.
97-
return NewSignature(&r, &s), nil
100+
// ParseSignature parses a signature according to the BIP-340 specification and
101+
// enforces the following additional restrictions specific to secp256k1:
102+
//
103+
// - The r component must be in the valid range for secp256k1 field elements
104+
// - The s component must be in the valid range for secp256k1 scalars
105+
func ParseSignature(sig []byte) (*Signature, error) {
106+
s := new(Signature)
107+
if err := parseSignature(s, sig); err != nil {
108+
return nil, err
109+
}
110+
return s, nil
98111
}
99112

100113
// IsEqual compares this Signature instance to the one passed, returning true

0 commit comments

Comments
 (0)