import (
"crypto/internal/fips140deps/byteorder"
"errors"
+ "math/bits"
)
// A Scalar is an integer modulo
return false
}
- for i := len(s) - 1; i >= 0; i-- {
- switch {
- case s[i] > scalarMinusOneBytes[i]:
- return false
- case s[i] < scalarMinusOneBytes[i]:
- return true
- }
- }
- return true
+ s0 := byteorder.LEUint64(s[:8])
+ s1 := byteorder.LEUint64(s[8:16])
+ s2 := byteorder.LEUint64(s[16:24])
+ s3 := byteorder.LEUint64(s[24:])
+
+ l0 := byteorder.LEUint64(scalarMinusOneBytes[:8])
+ l1 := byteorder.LEUint64(scalarMinusOneBytes[8:16])
+ l2 := byteorder.LEUint64(scalarMinusOneBytes[16:24])
+ l3 := byteorder.LEUint64(scalarMinusOneBytes[24:])
+
+ // Do a constant time subtraction chain scalarMinusOneBytes - s. If there is
+ // a borrow at the end, then s > scalarMinusOneBytes.
+ _, b := bits.Sub64(l0, s0, 0)
+ _, b = bits.Sub64(l1, s1, b)
+ _, b = bits.Sub64(l2, s2, b)
+ _, b = bits.Sub64(l3, s3, b)
+ return b == 0
}
// SetBytesWithClamping applies the buffer pruning described in RFC 8032,
var scOneBytes = [32]byte{1}
var scOne, _ = new(Scalar).SetCanonicalBytes(scOneBytes[:])
-var scMinusOne, _ = new(Scalar).SetCanonicalBytes(scalarMinusOneBytes[:])
+var scMinusOne = new(Scalar).Subtract(new(Scalar), scOne)
// Generate returns a valid (reduced modulo l) Scalar with a distribution
// weighted towards high, low, and edge values.
case diceRoll == 1:
s = scOneBytes
case diceRoll == 2:
- s = scalarMinusOneBytes
+ s = [32]byte(scMinusOne.Bytes())
case diceRoll < 5:
// Generate a low scalar in [0, 2^125).
rand.Read(s[:16])
t.Errorf("failed scalar->bytes->scalar round-trip: %v", err)
}
- b := scalarMinusOneBytes
- b[31] += 1
- s := scOne
- if out, err := s.SetCanonicalBytes(b[:]); err == nil {
- t.Errorf("SetCanonicalBytes worked on a non-canonical value")
- } else if s != scOne {
- t.Errorf("SetCanonicalBytes modified its receiver")
- } else if out != nil {
- t.Errorf("SetCanonicalBytes did not return nil with an error")
+ expectReject := func(b []byte) {
+ t.Helper()
+ s := scOne
+ if out, err := s.SetCanonicalBytes(b[:]); err == nil {
+ t.Errorf("SetCanonicalBytes worked on a non-canonical value")
+ } else if s != scOne {
+ t.Errorf("SetCanonicalBytes modified its receiver")
+ } else if out != nil {
+ t.Errorf("SetCanonicalBytes did not return nil with an error")
+ }
}
+
+ b := scMinusOne.Bytes()
+ b[0] += 1
+ expectReject(b)
+
+ b = scMinusOne.Bytes()
+ b[31] += 1
+ expectReject(b)
+
+ b = scMinusOne.Bytes()
+ b[31] |= 0b1000_0000
+ expectReject(b)
}
func TestScalarSetUniformBytes(t *testing.T) {