1
2
3
4
5 package edwards25519
6
7 import (
8 "crypto/ed25519/internal/edwards25519/field"
9 "encoding/hex"
10 "os"
11 "reflect"
12 "strings"
13 "testing"
14 )
15
16 var B = NewGeneratorPoint()
17 var I = NewIdentityPoint()
18
19 func checkOnCurve(t *testing.T, points ...*Point) {
20 t.Helper()
21 for i, p := range points {
22 var XX, YY, ZZ, ZZZZ field.Element
23 XX.Square(&p.x)
24 YY.Square(&p.y)
25 ZZ.Square(&p.z)
26 ZZZZ.Square(&ZZ)
27
28
29
30
31 var lhs, rhs field.Element
32 lhs.Subtract(&YY, &XX).Multiply(&lhs, &ZZ)
33 rhs.Multiply(d, &XX).Multiply(&rhs, &YY).Add(&rhs, &ZZZZ)
34 if lhs.Equal(&rhs) != 1 {
35 t.Errorf("X, Y, and Z do not specify a point on the curve\nX = %v\nY = %v\nZ = %v", p.x, p.y, p.z)
36 }
37
38 lhs.Multiply(&p.x, &p.y)
39 rhs.Multiply(&p.z, &p.t)
40 if lhs.Equal(&rhs) != 1 {
41 t.Errorf("point %d is not valid\nX = %v\nY = %v\nZ = %v", i, p.x, p.y, p.z)
42 }
43 }
44 }
45
46 func TestGenerator(t *testing.T) {
47
48
49 x := "1ad5258f602d56c9b2a7259560c72c695cdcd6fd31e2a4c0fe536ecdd3366921"
50 y := "5866666666666666666666666666666666666666666666666666666666666666"
51 if got := hex.EncodeToString(B.x.Bytes()); got != x {
52 t.Errorf("wrong B.x: got %s, expected %s", got, x)
53 }
54 if got := hex.EncodeToString(B.y.Bytes()); got != y {
55 t.Errorf("wrong B.y: got %s, expected %s", got, y)
56 }
57 if B.z.Equal(feOne) != 1 {
58 t.Errorf("wrong B.z: got %v, expected 1", B.z)
59 }
60
61 checkOnCurve(t, B)
62 }
63
64 func TestAddSubNegOnBasePoint(t *testing.T) {
65 checkLhs, checkRhs := &Point{}, &Point{}
66
67 checkLhs.Add(B, B)
68 tmpP2 := new(projP2).FromP3(B)
69 tmpP1xP1 := new(projP1xP1).Double(tmpP2)
70 checkRhs.fromP1xP1(tmpP1xP1)
71 if checkLhs.Equal(checkRhs) != 1 {
72 t.Error("B + B != [2]B")
73 }
74 checkOnCurve(t, checkLhs, checkRhs)
75
76 checkLhs.Subtract(B, B)
77 Bneg := new(Point).Negate(B)
78 checkRhs.Add(B, Bneg)
79 if checkLhs.Equal(checkRhs) != 1 {
80 t.Error("B - B != B + (-B)")
81 }
82 if I.Equal(checkLhs) != 1 {
83 t.Error("B - B != 0")
84 }
85 if I.Equal(checkRhs) != 1 {
86 t.Error("B + (-B) != 0")
87 }
88 checkOnCurve(t, checkLhs, checkRhs, Bneg)
89 }
90
91 func TestComparable(t *testing.T) {
92 if reflect.TypeOf(Point{}).Comparable() {
93 t.Error("Point is unexpectedly comparable")
94 }
95 }
96
97 func TestInvalidEncodings(t *testing.T) {
98
99 invalid := "efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f"
100 p := NewGeneratorPoint()
101 if out, err := p.SetBytes(decodeHex(invalid)); err == nil {
102 t.Error("expected error for invalid point")
103 } else if out != nil {
104 t.Error("SetBytes did not return nil on an invalid encoding")
105 } else if p.Equal(B) != 1 {
106 t.Error("the Point was modified while decoding an invalid encoding")
107 }
108 checkOnCurve(t, p)
109 }
110
111 func TestNonCanonicalPoints(t *testing.T) {
112 type test struct {
113 name string
114 encoding, canonical string
115 }
116 tests := []test{
117
118
119 {
120 "y=1,sign-",
121 "0100000000000000000000000000000000000000000000000000000000000080",
122 "0100000000000000000000000000000000000000000000000000000000000000",
123 },
124 {
125 "y=p+1,sign-",
126 "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
127 "0100000000000000000000000000000000000000000000000000000000000000",
128 },
129 {
130 "y=p-1,sign-",
131 "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
132 "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
133 },
134
135
136 {
137 "y=p,sign+",
138 "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
139 "0000000000000000000000000000000000000000000000000000000000000000",
140 },
141 {
142 "y=p,sign-",
143 "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
144 "0000000000000000000000000000000000000000000000000000000000000080",
145 },
146 {
147 "y=p+1,sign+",
148 "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
149 "0100000000000000000000000000000000000000000000000000000000000000",
150 },
151
152
153 {
154 "y=p+3,sign+",
155 "f0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
156 "0300000000000000000000000000000000000000000000000000000000000000",
157 },
158 {
159 "y=p+3,sign-",
160 "f0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
161 "0300000000000000000000000000000000000000000000000000000000000080",
162 },
163 {
164 "y=p+4,sign+",
165 "f1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
166 "0400000000000000000000000000000000000000000000000000000000000000",
167 },
168 {
169 "y=p+4,sign-",
170 "f1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
171 "0400000000000000000000000000000000000000000000000000000000000080",
172 },
173 {
174 "y=p+5,sign+",
175 "f2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
176 "0500000000000000000000000000000000000000000000000000000000000000",
177 },
178 {
179 "y=p+5,sign-",
180 "f2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
181 "0500000000000000000000000000000000000000000000000000000000000080",
182 },
183 {
184 "y=p+6,sign+",
185 "f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
186 "0600000000000000000000000000000000000000000000000000000000000000",
187 },
188 {
189 "y=p+6,sign-",
190 "f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
191 "0600000000000000000000000000000000000000000000000000000000000080",
192 },
193
194
195 {
196 "y=p+9,sign+",
197 "f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
198 "0900000000000000000000000000000000000000000000000000000000000000",
199 },
200 {
201 "y=p+9,sign-",
202 "f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
203 "0900000000000000000000000000000000000000000000000000000000000080",
204 },
205 {
206 "y=p+10,sign+",
207 "f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
208 "0a00000000000000000000000000000000000000000000000000000000000000",
209 },
210 {
211 "y=p+10,sign-",
212 "f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
213 "0a00000000000000000000000000000000000000000000000000000000000080",
214 },
215
216
217
218 {
219 "y=p+14,sign+",
220 "fbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
221 "0e00000000000000000000000000000000000000000000000000000000000000",
222 },
223 {
224 "y=p+14,sign-",
225 "fbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
226 "0e00000000000000000000000000000000000000000000000000000000000080",
227 },
228 {
229 "y=p+15,sign+",
230 "fcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
231 "0f00000000000000000000000000000000000000000000000000000000000000",
232 },
233 {
234 "y=p+15,sign-",
235 "fcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
236 "0f00000000000000000000000000000000000000000000000000000000000080",
237 },
238 {
239 "y=p+16,sign+",
240 "fdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
241 "1000000000000000000000000000000000000000000000000000000000000000",
242 },
243 {
244 "y=p+16,sign-",
245 "fdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
246 "1000000000000000000000000000000000000000000000000000000000000080",
247 },
248
249 {
250 "y=p+18,sign+",
251 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
252 "1200000000000000000000000000000000000000000000000000000000000000",
253 },
254 {
255 "y=p+18,sign-",
256 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
257 "1200000000000000000000000000000000000000000000000000000000000080",
258 },
259 }
260 for _, tt := range tests {
261 t.Run(tt.name, func(t *testing.T) {
262 p1, err := new(Point).SetBytes(decodeHex(tt.encoding))
263 if err != nil {
264 t.Fatalf("error decoding non-canonical point: %v", err)
265 }
266 p2, err := new(Point).SetBytes(decodeHex(tt.canonical))
267 if err != nil {
268 t.Fatalf("error decoding canonical point: %v", err)
269 }
270 if p1.Equal(p2) != 1 {
271 t.Errorf("equivalent points are not equal: %v, %v", p1, p2)
272 }
273 if encoding := hex.EncodeToString(p1.Bytes()); encoding != tt.canonical {
274 t.Errorf("re-encoding does not match canonical; got %q, expected %q", encoding, tt.canonical)
275 }
276 checkOnCurve(t, p1, p2)
277 })
278 }
279 }
280
281 var testAllocationsSink byte
282
283 func TestAllocations(t *testing.T) {
284 if strings.HasSuffix(os.Getenv("GO_BUILDER_NAME"), "-noopt") {
285 t.Skip("skipping allocations test without relevant optimizations")
286 }
287 if allocs := testing.AllocsPerRun(100, func() {
288 p := NewIdentityPoint()
289 p.Add(p, NewGeneratorPoint())
290 s := NewScalar()
291 testAllocationsSink ^= s.Bytes()[0]
292 testAllocationsSink ^= p.Bytes()[0]
293 }); allocs > 0 {
294 t.Errorf("expected zero allocations, got %0.1v", allocs)
295 }
296 }
297
298 func decodeHex(s string) []byte {
299 b, err := hex.DecodeString(s)
300 if err != nil {
301 panic(err)
302 }
303 return b
304 }
305
View as plain text