scalar_test.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. // Copyright (c) 2019 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package edwards25519
  5. import (
  6. "bytes"
  7. "encoding/hex"
  8. "math/big"
  9. mathrand "math/rand"
  10. "reflect"
  11. "testing"
  12. "testing/quick"
  13. )
  14. // Generate returns a valid (reduced modulo l) Scalar with a distribution
  15. // weighted towards high, low, and edge values.
  16. func (Scalar) Generate(rand *mathrand.Rand, size int) reflect.Value {
  17. s := scZero
  18. diceRoll := rand.Intn(100)
  19. switch {
  20. case diceRoll == 0:
  21. case diceRoll == 1:
  22. s = scOne
  23. case diceRoll == 2:
  24. s = scMinusOne
  25. case diceRoll < 5:
  26. // Generate a low scalar in [0, 2^125).
  27. rand.Read(s.s[:16])
  28. s.s[15] &= (1 << 5) - 1
  29. case diceRoll < 10:
  30. // Generate a high scalar in [2^252, 2^252 + 2^124).
  31. s.s[31] = 1 << 4
  32. rand.Read(s.s[:16])
  33. s.s[15] &= (1 << 4) - 1
  34. default:
  35. // Generate a valid scalar in [0, l) by returning [0, 2^252) which has a
  36. // negligibly different distribution (the former has a 2^-127.6 chance
  37. // of being out of the latter range).
  38. rand.Read(s.s[:])
  39. s.s[31] &= (1 << 4) - 1
  40. }
  41. return reflect.ValueOf(s)
  42. }
  43. // quickCheckConfig1024 will make each quickcheck test run (1024 * -quickchecks)
  44. // times. The default value of -quickchecks is 100.
  45. var quickCheckConfig1024 = &quick.Config{MaxCountScale: 1 << 10}
  46. func TestScalarGenerate(t *testing.T) {
  47. f := func(sc Scalar) bool {
  48. return isReduced(&sc)
  49. }
  50. if err := quick.Check(f, quickCheckConfig1024); err != nil {
  51. t.Errorf("generated unreduced scalar: %v", err)
  52. }
  53. }
  54. func TestScalarSetCanonicalBytes(t *testing.T) {
  55. f1 := func(in [32]byte, sc Scalar) bool {
  56. // Mask out top 4 bits to guarantee value falls in [0, l).
  57. in[len(in)-1] &= (1 << 4) - 1
  58. if _, err := sc.SetCanonicalBytes(in[:]); err != nil {
  59. return false
  60. }
  61. return bytes.Equal(in[:], sc.Bytes()) && isReduced(&sc)
  62. }
  63. if err := quick.Check(f1, quickCheckConfig1024); err != nil {
  64. t.Errorf("failed bytes->scalar->bytes round-trip: %v", err)
  65. }
  66. f2 := func(sc1, sc2 Scalar) bool {
  67. if _, err := sc2.SetCanonicalBytes(sc1.Bytes()); err != nil {
  68. return false
  69. }
  70. return sc1 == sc2
  71. }
  72. if err := quick.Check(f2, quickCheckConfig1024); err != nil {
  73. t.Errorf("failed scalar->bytes->scalar round-trip: %v", err)
  74. }
  75. b := scMinusOne.s
  76. b[31] += 1
  77. s := scOne
  78. if out, err := s.SetCanonicalBytes(b[:]); err == nil {
  79. t.Errorf("SetCanonicalBytes worked on a non-canonical value")
  80. } else if s != scOne {
  81. t.Errorf("SetCanonicalBytes modified its receiver")
  82. } else if out != nil {
  83. t.Errorf("SetCanonicalBytes did not return nil with an error")
  84. }
  85. }
  86. func TestScalarSetUniformBytes(t *testing.T) {
  87. mod, _ := new(big.Int).SetString("27742317777372353535851937790883648493", 10)
  88. mod.Add(mod, new(big.Int).Lsh(big.NewInt(1), 252))
  89. f := func(in [64]byte, sc Scalar) bool {
  90. sc.SetUniformBytes(in[:])
  91. if !isReduced(&sc) {
  92. return false
  93. }
  94. scBig := bigIntFromLittleEndianBytes(sc.s[:])
  95. inBig := bigIntFromLittleEndianBytes(in[:])
  96. return inBig.Mod(inBig, mod).Cmp(scBig) == 0
  97. }
  98. if err := quick.Check(f, quickCheckConfig1024); err != nil {
  99. t.Error(err)
  100. }
  101. }
  102. func TestScalarSetBytesWithClamping(t *testing.T) {
  103. // Generated with libsodium.js 1.0.18 crypto_scalarmult_ed25519_base.
  104. random := "633d368491364dc9cd4c1bf891b1d59460face1644813240a313e61f2c88216e"
  105. s := new(Scalar).SetBytesWithClamping(decodeHex(random))
  106. p := new(Point).ScalarBaseMult(s)
  107. want := "1d87a9026fd0126a5736fe1628c95dd419172b5b618457e041c9c861b2494a94"
  108. if got := hex.EncodeToString(p.Bytes()); got != want {
  109. t.Errorf("random: got %q, want %q", got, want)
  110. }
  111. zero := "0000000000000000000000000000000000000000000000000000000000000000"
  112. s = new(Scalar).SetBytesWithClamping(decodeHex(zero))
  113. p = new(Point).ScalarBaseMult(s)
  114. want = "693e47972caf527c7883ad1b39822f026f47db2ab0e1919955b8993aa04411d1"
  115. if got := hex.EncodeToString(p.Bytes()); got != want {
  116. t.Errorf("zero: got %q, want %q", got, want)
  117. }
  118. one := "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
  119. s = new(Scalar).SetBytesWithClamping(decodeHex(one))
  120. p = new(Point).ScalarBaseMult(s)
  121. want = "12e9a68b73fd5aacdbcaf3e88c46fea6ebedb1aa84eed1842f07f8edab65e3a7"
  122. if got := hex.EncodeToString(p.Bytes()); got != want {
  123. t.Errorf("one: got %q, want %q", got, want)
  124. }
  125. }
  126. func bigIntFromLittleEndianBytes(b []byte) *big.Int {
  127. bb := make([]byte, len(b))
  128. for i := range b {
  129. bb[i] = b[len(b)-i-1]
  130. }
  131. return new(big.Int).SetBytes(bb)
  132. }
  133. func TestScalarMultiplyDistributesOverAdd(t *testing.T) {
  134. multiplyDistributesOverAdd := func(x, y, z Scalar) bool {
  135. // Compute t1 = (x+y)*z
  136. var t1 Scalar
  137. t1.Add(&x, &y)
  138. t1.Multiply(&t1, &z)
  139. // Compute t2 = x*z + y*z
  140. var t2 Scalar
  141. var t3 Scalar
  142. t2.Multiply(&x, &z)
  143. t3.Multiply(&y, &z)
  144. t2.Add(&t2, &t3)
  145. return t1 == t2 && isReduced(&t1) && isReduced(&t3)
  146. }
  147. if err := quick.Check(multiplyDistributesOverAdd, quickCheckConfig1024); err != nil {
  148. t.Error(err)
  149. }
  150. }
  151. func TestScalarAddLikeSubNeg(t *testing.T) {
  152. addLikeSubNeg := func(x, y Scalar) bool {
  153. // Compute t1 = x - y
  154. var t1 Scalar
  155. t1.Subtract(&x, &y)
  156. // Compute t2 = -y + x
  157. var t2 Scalar
  158. t2.Negate(&y)
  159. t2.Add(&t2, &x)
  160. return t1 == t2 && isReduced(&t1)
  161. }
  162. if err := quick.Check(addLikeSubNeg, quickCheckConfig1024); err != nil {
  163. t.Error(err)
  164. }
  165. }
  166. func TestScalarNonAdjacentForm(t *testing.T) {
  167. s := Scalar{[32]byte{
  168. 0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d,
  169. 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, 0x26, 0x4d,
  170. 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1,
  171. 0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09,
  172. }}
  173. expectedNaf := [256]int8{
  174. 0, 13, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, -9, 0, 0, 0, 0, -11, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1,
  175. 0, 0, 0, 0, 9, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 11, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0,
  176. -9, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 9, 0,
  177. 0, 0, 0, -15, 0, 0, 0, 0, -7, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, -3, 0,
  178. 0, 0, 0, -11, 0, 0, 0, 0, -7, 0, 0, 0, 0, -13, 0, 0, 0, 0, 11, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 1, 0, 0,
  179. 0, 0, 0, -15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 13, 0, 0, 0,
  180. 0, 0, 0, 11, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 7,
  181. 0, 0, 0, 0, 0, -15, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 15, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
  182. }
  183. sNaf := s.nonAdjacentForm(5)
  184. for i := 0; i < 256; i++ {
  185. if expectedNaf[i] != sNaf[i] {
  186. t.Errorf("Wrong digit at position %d, got %d, expected %d", i, sNaf[i], expectedNaf[i])
  187. }
  188. }
  189. }
  190. type notZeroScalar Scalar
  191. func (notZeroScalar) Generate(rand *mathrand.Rand, size int) reflect.Value {
  192. var s Scalar
  193. for s == scZero {
  194. s = Scalar{}.Generate(rand, size).Interface().(Scalar)
  195. }
  196. return reflect.ValueOf(notZeroScalar(s))
  197. }
  198. func TestScalarEqual(t *testing.T) {
  199. if scOne.Equal(&scMinusOne) == 1 {
  200. t.Errorf("scOne.Equal(&scMinusOne) is true")
  201. }
  202. if scMinusOne.Equal(&scMinusOne) == 0 {
  203. t.Errorf("scMinusOne.Equal(&scMinusOne) is false")
  204. }
  205. }