secp256k1: Return num instead of bool for overflow.

This modifies the SetBytes method on the ModNScalar type to return the
overflow condition as a uint32 instead of a bool in order to better
facilite constant time code in upcoming changes and updates the callers
as needed.

It also updates the internal fieldToModNScalar convenience function to
return the flag as well.
This commit is contained in:
Dave Collins 2020-02-19 05:02:46 -06:00
parent b21feec2cd
commit 3db614b5a4
No known key found for this signature in database
GPG Key ID: B8904D9D9C93D1F2
3 changed files with 22 additions and 12 deletions

View File

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

View File

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

View File

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