1
2
3
4
5 package edwards25519
6
7 import (
8 "bytes"
9 "encoding/hex"
10 "math/big"
11 mathrand "math/rand"
12 "reflect"
13 "testing"
14 "testing/quick"
15 )
16
17
18
19 func quickCheckConfig(slowScale int) *quick.Config {
20 cfg := new(quick.Config)
21 if !testing.Short() {
22 cfg.MaxCountScale = float64(slowScale)
23 }
24 return cfg
25 }
26
27 var scOneBytes = [32]byte{1}
28 var scOne, _ = new(Scalar).SetCanonicalBytes(scOneBytes[:])
29 var scMinusOne, _ = new(Scalar).SetCanonicalBytes(scalarMinusOneBytes[:])
30
31
32
33 func (Scalar) Generate(rand *mathrand.Rand, size int) reflect.Value {
34 var s [32]byte
35 diceRoll := rand.Intn(100)
36 switch {
37 case diceRoll == 0:
38 case diceRoll == 1:
39 s = scOneBytes
40 case diceRoll == 2:
41 s = scalarMinusOneBytes
42 case diceRoll < 5:
43
44 rand.Read(s[:16])
45 s[15] &= (1 << 5) - 1
46 case diceRoll < 10:
47
48 s[31] = 1 << 4
49 rand.Read(s[:16])
50 s[15] &= (1 << 4) - 1
51 default:
52
53
54
55 rand.Read(s[:])
56 s[31] &= (1 << 4) - 1
57 }
58
59 val := Scalar{}
60 fiatScalarFromBytes((*[4]uint64)(&val.s), &s)
61 fiatScalarToMontgomery(&val.s, (*fiatScalarNonMontgomeryDomainFieldElement)(&val.s))
62
63 return reflect.ValueOf(val)
64 }
65
66 func TestScalarGenerate(t *testing.T) {
67 f := func(sc Scalar) bool {
68 return isReduced(sc.Bytes())
69 }
70 if err := quick.Check(f, quickCheckConfig(1024)); err != nil {
71 t.Errorf("generated unreduced scalar: %v", err)
72 }
73 }
74
75 func TestScalarSetCanonicalBytes(t *testing.T) {
76 f1 := func(in [32]byte, sc Scalar) bool {
77
78 in[len(in)-1] &= (1 << 4) - 1
79 if _, err := sc.SetCanonicalBytes(in[:]); err != nil {
80 return false
81 }
82 repr := sc.Bytes()
83 return bytes.Equal(in[:], repr) && isReduced(repr)
84 }
85 if err := quick.Check(f1, quickCheckConfig(1024)); err != nil {
86 t.Errorf("failed bytes->scalar->bytes round-trip: %v", err)
87 }
88
89 f2 := func(sc1, sc2 Scalar) bool {
90 if _, err := sc2.SetCanonicalBytes(sc1.Bytes()); err != nil {
91 return false
92 }
93 return sc1 == sc2
94 }
95 if err := quick.Check(f2, quickCheckConfig(1024)); err != nil {
96 t.Errorf("failed scalar->bytes->scalar round-trip: %v", err)
97 }
98
99 b := scalarMinusOneBytes
100 b[31] += 1
101 s := scOne
102 if out, err := s.SetCanonicalBytes(b[:]); err == nil {
103 t.Errorf("SetCanonicalBytes worked on a non-canonical value")
104 } else if s != scOne {
105 t.Errorf("SetCanonicalBytes modified its receiver")
106 } else if out != nil {
107 t.Errorf("SetCanonicalBytes did not return nil with an error")
108 }
109 }
110
111 func TestScalarSetUniformBytes(t *testing.T) {
112 mod, _ := new(big.Int).SetString("27742317777372353535851937790883648493", 10)
113 mod.Add(mod, new(big.Int).Lsh(big.NewInt(1), 252))
114 f := func(in [64]byte, sc Scalar) bool {
115 sc.SetUniformBytes(in[:])
116 repr := sc.Bytes()
117 if !isReduced(repr) {
118 return false
119 }
120 scBig := bigIntFromLittleEndianBytes(repr[:])
121 inBig := bigIntFromLittleEndianBytes(in[:])
122 return inBig.Mod(inBig, mod).Cmp(scBig) == 0
123 }
124 if err := quick.Check(f, quickCheckConfig(1024)); err != nil {
125 t.Error(err)
126 }
127 }
128
129 func TestScalarSetBytesWithClamping(t *testing.T) {
130
131
132 random := "633d368491364dc9cd4c1bf891b1d59460face1644813240a313e61f2c88216e"
133 s, _ := new(Scalar).SetBytesWithClamping(decodeHex(random))
134 p := new(Point).ScalarBaseMult(s)
135 want := "1d87a9026fd0126a5736fe1628c95dd419172b5b618457e041c9c861b2494a94"
136 if got := hex.EncodeToString(p.Bytes()); got != want {
137 t.Errorf("random: got %q, want %q", got, want)
138 }
139
140 zero := "0000000000000000000000000000000000000000000000000000000000000000"
141 s, _ = new(Scalar).SetBytesWithClamping(decodeHex(zero))
142 p = new(Point).ScalarBaseMult(s)
143 want = "693e47972caf527c7883ad1b39822f026f47db2ab0e1919955b8993aa04411d1"
144 if got := hex.EncodeToString(p.Bytes()); got != want {
145 t.Errorf("zero: got %q, want %q", got, want)
146 }
147
148 one := "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
149 s, _ = new(Scalar).SetBytesWithClamping(decodeHex(one))
150 p = new(Point).ScalarBaseMult(s)
151 want = "12e9a68b73fd5aacdbcaf3e88c46fea6ebedb1aa84eed1842f07f8edab65e3a7"
152 if got := hex.EncodeToString(p.Bytes()); got != want {
153 t.Errorf("one: got %q, want %q", got, want)
154 }
155 }
156
157 func bigIntFromLittleEndianBytes(b []byte) *big.Int {
158 bb := make([]byte, len(b))
159 for i := range b {
160 bb[i] = b[len(b)-i-1]
161 }
162 return new(big.Int).SetBytes(bb)
163 }
164
165 func TestScalarMultiplyDistributesOverAdd(t *testing.T) {
166 multiplyDistributesOverAdd := func(x, y, z Scalar) bool {
167
168 var t1 Scalar
169 t1.Add(&x, &y)
170 t1.Multiply(&t1, &z)
171
172
173 var t2 Scalar
174 var t3 Scalar
175 t2.Multiply(&x, &z)
176 t3.Multiply(&y, &z)
177 t2.Add(&t2, &t3)
178
179 reprT1, reprT2 := t1.Bytes(), t2.Bytes()
180
181 return t1 == t2 && isReduced(reprT1) && isReduced(reprT2)
182 }
183
184 if err := quick.Check(multiplyDistributesOverAdd, quickCheckConfig(1024)); err != nil {
185 t.Error(err)
186 }
187 }
188
189 func TestScalarAddLikeSubNeg(t *testing.T) {
190 addLikeSubNeg := func(x, y Scalar) bool {
191
192 var t1 Scalar
193 t1.Subtract(&x, &y)
194
195
196 var t2 Scalar
197 t2.Negate(&y)
198 t2.Add(&t2, &x)
199
200 return t1 == t2 && isReduced(t1.Bytes())
201 }
202
203 if err := quick.Check(addLikeSubNeg, quickCheckConfig(1024)); err != nil {
204 t.Error(err)
205 }
206 }
207
208 func TestScalarNonAdjacentForm(t *testing.T) {
209 s, _ := (&Scalar{}).SetCanonicalBytes([]byte{
210 0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d,
211 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, 0x26, 0x4d,
212 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1,
213 0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09,
214 })
215
216 expectedNaf := [256]int8{
217 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,
218 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,
219 -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,
220 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,
221 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,
222 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,
223 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,
224 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,
225 }
226
227 sNaf := s.nonAdjacentForm(5)
228
229 for i := 0; i < 256; i++ {
230 if expectedNaf[i] != sNaf[i] {
231 t.Errorf("Wrong digit at position %d, got %d, expected %d", i, sNaf[i], expectedNaf[i])
232 }
233 }
234 }
235
236 type notZeroScalar Scalar
237
238 func (notZeroScalar) Generate(rand *mathrand.Rand, size int) reflect.Value {
239 var s Scalar
240 var isNonZero uint64
241 for isNonZero == 0 {
242 s = Scalar{}.Generate(rand, size).Interface().(Scalar)
243 fiatScalarNonzero(&isNonZero, (*[4]uint64)(&s.s))
244 }
245 return reflect.ValueOf(notZeroScalar(s))
246 }
247
248 func TestScalarEqual(t *testing.T) {
249 if scOne.Equal(scMinusOne) == 1 {
250 t.Errorf("scOne.Equal(&scMinusOne) is true")
251 }
252 if scMinusOne.Equal(scMinusOne) == 0 {
253 t.Errorf("scMinusOne.Equal(&scMinusOne) is false")
254 }
255 }
256
View as plain text