v
Зеркало из https://github.com/vlang/v
1module edwards25519
2
3// d is a constant in the curve equation.
4const d_bytes = [u8(0xa3), 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75, 0xab, 0xd8, 0x41, 0x41, 0x4d,
50x0a, 0x70, 0x00, 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c, 0x73, 0xfe, 0x6f, 0x2b, 0xee,
60x6c, 0x03, 0x52]
7const id_bytes = [u8(1), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
80, 0, 0, 0, 0, 0, 0]
9const gen_bytes = [u8(0x58), 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
100x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
110x66, 0x66, 0x66, 0x66]
12const d_const = d_const_generate() or { panic(err) }
13const d2_const = d2_const_generate() or { panic(err) }
14// id_point is the point at infinity.
15const id_point = id_point_generate() or { panic(err) }
16// generator point
17const gen_point = generator() or { panic(err) }
18
19fn d_const_generate() !Element {
20mut v := Element{}
21v.set_bytes(d_bytes)!
22return v
23}
24
25fn d2_const_generate() !Element {
26mut v := Element{}
27v.add(d_const, d_const)
28return v
29}
30
31// id_point_generate is the point at infinity.
32fn id_point_generate() !Point {
33mut p := Point{}
34p.set_bytes(id_bytes)!
35return p
36}
37
38// generator is the canonical curve basepoint. See TestGenerator for the
39// correspondence of this encoding with the values in RFC 8032.
40fn generator() !Point {
41mut p := Point{}
42p.set_bytes(gen_bytes)!
43return p
44}
45
46// Point types.
47struct ProjectiveP1 {
48mut:
49x Element
50y Element
51z Element
52t Element
53}
54
55struct ProjectiveP2 {
56mut:
57x Element
58y Element
59z Element
60}
61
62// Point represents a point on the edwards25519 curve.
63//
64// This type works similarly to math/big.Int, and all arguments and receivers
65// are allowed to alias.
66//
67// The zero value is NOT valid, and it may be used only as a receiver.
68pub struct Point {
69mut:
70// The point is internally represented in extended coordinates (x, y, z, T)
71// where x = x/z, y = y/z, and xy = T/z per https://eprint.iacr.org/2008/522.
72x Element
73y Element
74z Element
75t Element
76// Make the type not comparable (i.e. used with == or as a map key), as
77// equivalent points can be represented by different values.
78// _ incomparable
79}
80
81fn check_initialized(points ...Point) {
82for _, p in points {
83if p.x == fe_zero && p.y == fe_zero {
84panic('edwards25519: use of uninitialized Point')
85}
86}
87}
88
89struct ProjectiveCached {
90mut:
91ypx Element // y + x
92ymx Element // y - x
93z Element
94t2d Element
95}
96
97struct AffineCached {
98mut:
99ypx Element // y + x
100ymx Element // y - x
101t2d Element
102}
103
104fn (mut v ProjectiveP2) zero() ProjectiveP2 {
105v.x.zero()
106v.y.one()
107v.z.one()
108return v
109}
110
111// set_bytes sets v = x, where x is a 32-byte encoding of v. If x does not
112// represent a valid point on the curve, set_bytes returns an error and
113// the receiver is unchanged. Otherwise, set_bytes returns v.
114//
115// Note that set_bytes accepts all non-canonical encodings of valid points.
116// That is, it follows decoding rules that match most implementations in
117// the ecosystem rather than RFC 8032.
118pub fn (mut v Point) set_bytes(x []u8) !Point {
119// Specifically, the non-canonical encodings that are accepted are
120// 1) the ones where the edwards25519 element is not reduced (see the
121// (*edwards25519.Element).set_bytes docs) and
122// 2) the ones where the x-coordinate is zero and the sign bit is set.
123//
124// This is consistent with crypto/ed25519/internal/edwards25519. Read more
125// at https://hdevalence.ca/blog/2020-10-04-its-25519am, specifically the
126// "Canonical A, R" section.
127mut el0 := Element{}
128y := el0.set_bytes(x) or { return error('edwards25519: invalid point encoding length') }
129
130// -x² + y² = 1 + dx²y²
131// x² + dx²y² = x²(dy² + 1) = y² - 1
132// x² = (y² - 1) / (dy² + 1)
133
134// u = y² - 1
135mut el1 := Element{}
136y2 := el1.square(y)
137mut el2 := Element{}
138u := el2.subtract(y2, fe_one)
139
140// v = dy² + 1
141mut el3 := Element{}
142mut vv := el3.multiply(y2, d_const)
143vv = vv.add(vv, fe_one)
144
145// x = +√(u/v)
146mut el4 := Element{}
147mut xx, was_square := el4.sqrt_ratio(u, vv)
148if was_square == 0 {
149return error('edwards25519: invalid point encoding')
150}
151
152// selected the negative square root if the sign bit is set.
153mut el5 := Element{}
154xx_neg := el5.negate(xx)
155xx.selected(xx_neg, xx, int(x[31] >> 7))
156
157v.x.set(xx)
158v.y.set(y)
159v.z.one()
160v.t.multiply(xx, y) // xy = T / z
161
162return v
163}
164
165// set sets v = u, and returns v.
166pub fn (mut v Point) set(u Point) Point {
167v = u
168return v
169}
170
171// new_identity_point returns a new Point set to the identity.
172pub fn new_identity_point() Point {
173mut p := Point{}
174return p.set(id_point)
175}
176
177// new_generator_point returns a new Point set to the canonical generator.
178pub fn new_generator_point() Point {
179mut p := Point{}
180return p.set(gen_point)
181}
182
183fn (mut v ProjectiveCached) zero() ProjectiveCached {
184v.ypx.one()
185v.ymx.one()
186v.z.one()
187v.t2d.zero()
188return v
189}
190
191fn (mut v AffineCached) zero() AffineCached {
192v.ypx.one()
193v.ymx.one()
194v.t2d.zero()
195return v
196}
197
198// Encoding.
199
200// bytes returns the canonical 32-byte encoding of v, according to RFC 8032,
201// Section 5.1.2.
202pub fn (mut v Point) bytes() []u8 {
203// This function is outlined to make the allocations inline in the caller
204// rather than happen on the heap.
205mut buf := [32]u8{}
206return v.bytes_generic(mut buf)
207}
208
209fn (mut v Point) bytes_generic(mut buf [32]u8) []u8 {
210check_initialized(v)
211
212mut zinv := Element{}
213mut x := Element{}
214mut y := Element{}
215zinv.invert(v.z) // zinv = 1 / z
216x.multiply(v.x, zinv) // x = x / z
217y.multiply(v.y, zinv) // y = y / z
218
219mut out := copy_field_element(mut buf, mut y)
220unsafe {
221// out[31] |= u8(x.is_negative() << 7) //original one
222out[31] |= u8(x.is_negative() * 128) // x << 7 == x * 2^7
223}
224return out
225}
226
227fn copy_field_element(mut buf [32]u8, mut v Element) []u8 {
228// this fail in test
229/*
230copy(mut buf[..], v.bytes())
231return buf[..]
232*/
233
234// this pass the test
235mut out := []u8{len: 32}
236for i := 0; i <= buf.len - 1; i++ {
237out[i] = v.bytes()[i]
238}
239
240return out
241}
242
243// Conversions.
244
245fn (mut v ProjectiveP2) from_p1(p ProjectiveP1) ProjectiveP2 {
246v.x.multiply(p.x, p.t)
247v.y.multiply(p.y, p.z)
248v.z.multiply(p.z, p.t)
249return v
250}
251
252fn (mut v ProjectiveP2) from_p3(p Point) ProjectiveP2 {
253v.x.set(p.x)
254v.y.set(p.y)
255v.z.set(p.z)
256return v
257}
258
259fn (mut v Point) from_p1(p ProjectiveP1) Point {
260v.x.multiply(p.x, p.t)
261v.y.multiply(p.y, p.z)
262v.z.multiply(p.z, p.t)
263v.t.multiply(p.x, p.y)
264return v
265}
266
267fn (mut v Point) from_p2(p ProjectiveP2) Point {
268v.x.multiply(p.x, p.z)
269v.y.multiply(p.y, p.z)
270v.z.square(p.z)
271v.t.multiply(p.x, p.y)
272return v
273}
274
275fn (mut v ProjectiveCached) from_p3(p Point) ProjectiveCached {
276v.ypx.add(p.y, p.x)
277v.ymx.subtract(p.y, p.x)
278v.z.set(p.z)
279v.t2d.multiply(p.t, d2_const)
280return v
281}
282
283fn (mut v AffineCached) from_p3(p Point) AffineCached {
284v.ypx.add(p.y, p.x)
285v.ymx.subtract(p.y, p.x)
286v.t2d.multiply(p.t, d2_const)
287
288mut invz := Element{}
289invz.invert(p.z)
290v.ypx.multiply(v.ypx, invz)
291v.ymx.multiply(v.ymx, invz)
292v.t2d.multiply(v.t2d, invz)
293return v
294}
295
296// (Re)addition and subtraction.
297
298// add sets v = p + q, and returns v.
299pub fn (mut v Point) add(p Point, q Point) Point {
300check_initialized(p, q)
301mut pc := ProjectiveCached{}
302mut p1 := ProjectiveP1{}
303qcached := pc.from_p3(q)
304
305result := p1.add(p, qcached)
306return v.from_p1(result)
307}
308
309// subtract sets v = p - q, and returns v.
310pub fn (mut v Point) subtract(p Point, q Point) Point {
311check_initialized(p, q)
312mut pc := ProjectiveCached{}
313mut p1 := ProjectiveP1{}
314qcached := pc.from_p3(q)
315result := p1.sub(p, qcached)
316return v.from_p1(result)
317}
318
319fn (mut v ProjectiveP1) add(p Point, q ProjectiveCached) ProjectiveP1 {
320// var ypx, ymx, pp, mm, tt2d, zz2 edwards25519.Element
321mut ypx := Element{}
322mut ymx := Element{}
323mut pp := Element{}
324mut mm := Element{}
325mut tt2d := Element{}
326mut zz2 := Element{}
327
328ypx.add(p.y, p.x)
329ymx.subtract(p.y, p.x)
330
331pp.multiply(ypx, q.ypx)
332mm.multiply(ymx, q.ymx)
333tt2d.multiply(p.t, q.t2d)
334zz2.multiply(p.z, q.z)
335
336zz2.add(zz2, zz2)
337
338v.x.subtract(pp, mm)
339v.y.add(pp, mm)
340v.z.add(zz2, tt2d)
341v.t.subtract(zz2, tt2d)
342return v
343}
344
345fn (mut v ProjectiveP1) sub(p Point, q ProjectiveCached) ProjectiveP1 {
346mut ypx := Element{}
347mut ymx := Element{}
348mut pp := Element{}
349mut mm := Element{}
350mut tt2d := Element{}
351mut zz2 := Element{}
352
353ypx.add(p.y, p.x)
354ymx.subtract(p.y, p.x)
355
356pp.multiply(ypx, q.ymx) // flipped sign
357mm.multiply(ymx, q.ypx) // flipped sign
358tt2d.multiply(p.t, q.t2d)
359zz2.multiply(p.z, q.z)
360
361zz2.add(zz2, zz2)
362
363v.x.subtract(pp, mm)
364v.y.add(pp, mm)
365v.z.subtract(zz2, tt2d) // flipped sign
366v.t.add(zz2, tt2d) // flipped sign
367return v
368}
369
370fn (mut v ProjectiveP1) add_affine(p Point, q AffineCached) ProjectiveP1 {
371mut ypx := Element{}
372mut ymx := Element{}
373mut pp := Element{}
374mut mm := Element{}
375mut tt2d := Element{}
376mut z2 := Element{}
377
378ypx.add(p.y, p.x)
379ymx.subtract(p.y, p.x)
380
381pp.multiply(ypx, q.ypx)
382mm.multiply(ymx, q.ymx)
383tt2d.multiply(p.t, q.t2d)
384
385z2.add(p.z, p.z)
386
387v.x.subtract(pp, mm)
388v.y.add(pp, mm)
389v.z.add(z2, tt2d)
390v.t.subtract(z2, tt2d)
391return v
392}
393
394fn (mut v ProjectiveP1) sub_affine(p Point, q AffineCached) ProjectiveP1 {
395mut ypx := Element{}
396mut ymx := Element{}
397mut pp := Element{}
398mut mm := Element{}
399mut tt2d := Element{}
400mut z2 := Element{}
401
402ypx.add(p.y, p.x)
403ymx.subtract(p.y, p.x)
404
405pp.multiply(ypx, q.ymx) // flipped sign
406mm.multiply(ymx, q.ypx) // flipped sign
407tt2d.multiply(p.t, q.t2d)
408
409z2.add(p.z, p.z)
410
411v.x.subtract(pp, mm)
412v.y.add(pp, mm)
413v.z.subtract(z2, tt2d) // flipped sign
414v.t.add(z2, tt2d) // flipped sign
415return v
416}
417
418// Doubling.
419
420fn (mut v ProjectiveP1) double(p ProjectiveP2) ProjectiveP1 {
421// var xx, yy, zz2, xplusysq edwards25519.Element
422mut xx := Element{}
423mut yy := Element{}
424mut zz2 := Element{}
425mut xplusysq := Element{}
426
427xx.square(p.x)
428yy.square(p.y)
429zz2.square(p.z)
430zz2.add(zz2, zz2)
431xplusysq.add(p.x, p.y)
432xplusysq.square(xplusysq)
433
434v.y.add(yy, xx)
435v.z.subtract(yy, xx)
436
437v.x.subtract(xplusysq, v.y)
438v.t.subtract(zz2, v.z)
439return v
440}
441
442// Negation.
443
444// negate sets v = -p, and returns v.
445pub fn (mut v Point) negate(p Point) Point {
446check_initialized(p)
447v.x.negate(p.x)
448v.y.set(p.y)
449v.z.set(p.z)
450v.t.negate(p.t)
451return v
452}
453
454// equal returns 1 if v is equivalent to u, and 0 otherwise.
455pub fn (mut v Point) equal(u Point) int {
456check_initialized(v, u)
457
458mut t1 := Element{}
459mut t2 := Element{}
460mut t3 := Element{}
461mut t4 := Element{}
462
463t1.multiply(v.x, u.z)
464t2.multiply(u.x, v.z)
465t3.multiply(v.y, u.z)
466t4.multiply(u.y, v.z)
467
468return t1.equal(t2) & t3.equal(t4)
469}
470
471// Constant-time operations
472
473// selected sets v to a if cond == 1 and to b if cond == 0.
474fn (mut v ProjectiveCached) selected(a ProjectiveCached, b ProjectiveCached, cond int) ProjectiveCached {
475v.ypx.selected(a.ypx, b.ypx, cond)
476v.ymx.selected(a.ymx, b.ymx, cond)
477v.z.selected(a.z, b.z, cond)
478v.t2d.selected(a.t2d, b.t2d, cond)
479return v
480}
481
482// selected sets v to a if cond == 1 and to b if cond == 0.
483fn (mut v AffineCached) selected(a AffineCached, b AffineCached, cond int) AffineCached {
484v.ypx.selected(a.ypx, b.ypx, cond)
485v.ymx.selected(a.ymx, b.ymx, cond)
486v.t2d.selected(a.t2d, b.t2d, cond)
487return v
488}
489
490// cond_neg negates v if cond == 1 and leaves it unchanged if cond == 0.
491fn (mut v ProjectiveCached) cond_neg(cond int) ProjectiveCached {
492mut el := Element{}
493v.ypx.swap(mut v.ymx, cond)
494v.t2d.selected(el.negate(v.t2d), v.t2d, cond)
495return v
496}
497
498// cond_neg negates v if cond == 1 and leaves it unchanged if cond == 0.
499fn (mut v AffineCached) cond_neg(cond int) AffineCached {
500mut el := Element{}
501v.ypx.swap(mut v.ymx, cond)
502v.t2d.selected(el.negate(v.t2d), v.t2d, cond)
503return v
504}
505
506fn check_on_curve(points ...Point) bool {
507for p in points {
508mut xx := Element{}
509mut yy := Element{}
510mut zz := Element{}
511mut zzzz := Element{}
512xx.square(p.x)
513yy.square(p.y)
514zz.square(p.z)
515zzzz.square(zz)
516// -x² + y² = 1 + dx²y²
517// -(X/Z)² + (Y/Z)² = 1 + d(X/Z)²(Y/Z)²
518// (-X² + Y²)/Z² = 1 + (dX²Y²)/Z⁴
519// (-X² + Y²)*Z² = Z⁴ + dX²Y²
520mut lhs := Element{}
521mut rhs := Element{}
522lhs.subtract(yy, xx)
523lhs.multiply(lhs, zz)
524rhs.multiply(d_const, xx)
525rhs.multiply(rhs, yy)
526rhs.add(rhs, zzzz)
527
528if lhs.equal(rhs) != 1 {
529return false
530}
531/*
532if lhs.equal(rhs) != 1 {
533lg.error('X, Y, and Z do not specify a point on the curve\nX = $p.x \nY = $p.y\nZ = $p.z')
534}*/
535
536// xy = T/Z
537lhs.multiply(p.x, p.y)
538rhs.multiply(p.z, p.t)
539/*
540if lhs.equal(rhs) != 1 {
541lg.error('point $i is not valid\nX = $p.x\nY = $p.y\nZ = $p.z')
542}*/
543if lhs.equal(rhs) != 1 {
544return false
545}
546}
547return true
548}
549