diff --git a/dcrec/secp256k1/modnscalar.go b/dcrec/secp256k1/modnscalar.go index a6ee4462..b4f7b5bb 100644 --- a/dcrec/secp256k1/modnscalar.go +++ b/dcrec/secp256k1/modnscalar.go @@ -298,9 +298,13 @@ func (s *ModNScalar) reduce256(overflows uint32) { // SetBytes interprets the provided array as a 256-bit big-endian unsigned // integer, reduces it modulo the group order, sets the scalar to the result, -// and returns whether or not it was reduced (aka it overflowed) in constant -// time. -func (s *ModNScalar) SetBytes(b *[32]byte) bool { +// and returns either 1 if it was reduced (aka it overflowed) or 0 otherwise in +// constant time. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. +func (s *ModNScalar) SetBytes(b *[32]byte) uint32 { // Pack the 256 total bits across the 8 uint32 words. This could be done // with a for loop, but benchmarks show this unrolled version is about 2 // times faster than the variant that uses a loop. @@ -317,7 +321,7 @@ func (s *ModNScalar) SetBytes(b *[32]byte) bool { // not it was reduced. needsReduce := s.overflows() s.reduce256(needsReduce) - return needsReduce != 0 + return needsReduce } // zeroArray32 zeroes the provided 32-byte buffer. @@ -343,7 +347,7 @@ func (s *ModNScalar) SetByteSlice(b []byte) bool { copy(b32[32-len(b):], b) result := s.SetBytes(&b32) zeroArray32(&b32) - return result + return result != 0 } // PutBytes unpacks the scalar to a 32-byte big-endian value using the passed diff --git a/dcrec/secp256k1/modnscalar_test.go b/dcrec/secp256k1/modnscalar_test.go index 92f2163a..3bd705db 100644 --- a/dcrec/secp256k1/modnscalar_test.go +++ b/dcrec/secp256k1/modnscalar_test.go @@ -243,7 +243,7 @@ func TestModNScalarSetBytes(t *testing.T) { truncatedInBytes = truncatedInBytes[:32] } copy(b32[32-len(truncatedInBytes):], truncatedInBytes) - overflow = s2.SetBytes(&b32) + overflow = s2.SetBytes(&b32) != 0 if !reflect.DeepEqual(s2.n, test.expected) { t.Errorf("%s: unexpected result\ngot: %x\nwant: %x", test.name, s2.n, test.expected) diff --git a/dcrec/secp256k1/signature.go b/dcrec/secp256k1/signature.go index a9644f43..63483961 100644 --- a/dcrec/secp256k1/signature.go +++ b/dcrec/secp256k1/signature.go @@ -137,14 +137,20 @@ func (sig *Signature) Serialize() []byte { return b } -// fieldToModNScalar converts a field value to scalar modulo the curve order. -func fieldToModNScalar(v *fieldVal) ModNScalar { +// fieldToModNScalar converts a field value to scalar modulo the group order and +// returns the scalar along with either 1 if it was reduced (aka it overflowed) +// or 0 otherwise. +// +// Note that a bool is not used here because it is not possible in Go to convert +// from a bool to numeric value in constant time and many constant-time +// operations require a numeric value. +func fieldToModNScalar(v *fieldVal) (ModNScalar, uint32) { var buf [32]byte v.PutBytes(&buf) var s ModNScalar - s.SetBytes(&buf) + overflow := s.SetBytes(&buf) zeroArray32(&buf) - return s + return s, overflow } // Verify returns whether or not the signature is valid for the provided hash @@ -223,7 +229,7 @@ func (sig *Signature) Verify(hash []byte, pubKey *PublicKey) bool { // Note that the point must be in affine coordinates since R is in affine // coordinates. X.ToAffine() - x := fieldToModNScalar(&X.x) + x, _ := fieldToModNScalar(&X.x) // Step 8. // @@ -604,7 +610,7 @@ func signRFC6979(privateKey *PrivateKey, hash []byte) *Signature { // // r = kG.x mod N // Repeat from step 1 if r = 0 - r := fieldToModNScalar(&kG.x) + r, _ := fieldToModNScalar(&kG.x) if r.IsZero() { continue }