diff --git a/dcrec/secp256k1/field.go b/dcrec/secp256k1/field.go index e8563891..9c72a4ce 100644 --- a/dcrec/secp256k1/field.go +++ b/dcrec/secp256k1/field.go @@ -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. // diff --git a/dcrec/secp256k1/field_test.go b/dcrec/secp256k1/field_test.go index fa77d5ce..cdb7d271 100644 --- a/dcrec/secp256k1/field_test.go +++ b/dcrec/secp256k1/field_test.go @@ -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 + } } } diff --git a/dcrec/secp256k1/signature.go b/dcrec/secp256k1/signature.go index 1217ac98..ac1754ee 100644 --- a/dcrec/secp256k1/signature.go +++ b/dcrec/secp256k1/signature.go @@ -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. //