secp256k1: Expose IsOddBit on field val type.

This exposes a new function on the FieldVal type named IsOddBit which
operates similarly to IsOdd except it returns a 0 or 1.

This is being provided 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.

Since the type is now exported for external use, consumers would
otherwise have no way to perform the conversion.
This commit is contained in:
Dave Collins 2020-03-23 14:11:34 -05:00
parent be680db523
commit 05cc323f2a
No known key found for this signature in database
GPG Key ID: B8904D9D9C93D1F2
3 changed files with 27 additions and 4 deletions

View File

@ -500,6 +500,21 @@ func (f *FieldVal) IsOne() bool {
return bits == 0
}
// IsOddBit returns 1 when the field value is an odd number 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. See IsOdd for the version that returns a
// bool.
//
// Preconditions:
// - The field value MUST be normalized
func (f *FieldVal) IsOddBit() uint32 {
// Only odd numbers have the bottom bit set.
return f.n[0] & 1
}
// IsOdd returns whether or not the field value is an odd number in constant
// time.
//

View File

@ -490,8 +490,8 @@ func TestFieldNormalize(t *testing.T) {
}
}
// TestFieldIsOdd ensures that checking if a field value IsOdd works as
// expected.
// TestFieldIsOdd ensures that checking if a field value is odd via IsOdd and
// IsOddBit works as expected.
func TestFieldIsOdd(t *testing.T) {
tests := []struct {
name string // test description
@ -528,12 +528,20 @@ func TestFieldIsOdd(t *testing.T) {
}}
for _, test := range tests {
result := new(FieldVal).SetHex(test.in).IsOdd()
f := new(FieldVal).SetHex(test.in)
result := f.IsOdd()
if result != test.expected {
t.Errorf("%s: wrong result -- got: %v, want: %v", test.name,
result, test.expected)
continue
}
result2 := f.IsOddBit() == 1
if result2 != test.expected {
t.Errorf("%s: wrong result -- got: %v, want: %v", test.name,
result2, test.expected)
continue
}
}
}

View File

@ -881,7 +881,7 @@ func signRFC6979(privateKey *PrivateKey, hash []byte) (*Signature, byte) {
// points since that would require breaking the ECDLP, but, in practice
// this strongly implies with extremely high probability that there are
// only a few actual points for which this case is true.
pubKeyRecoveryCode := byte(overflow<<1) | byte(kG.y.n[0]&0x01)
pubKeyRecoveryCode := byte(overflow<<1) | byte(kG.y.IsOddBit())
// Step 4.
//