v

Зеркало из https://github.com/vlang/v
Форк
0
548 строк · 12.3 Кб
1
module edwards25519
2

3
// d is a constant in the curve equation.
4
const d_bytes = [u8(0xa3), 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75, 0xab, 0xd8, 0x41, 0x41, 0x4d,
5
	0x0a, 0x70, 0x00, 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c, 0x73, 0xfe, 0x6f, 0x2b, 0xee,
6
	0x6c, 0x03, 0x52]
7
const 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,
8
	0, 0, 0, 0, 0, 0, 0]
9
const gen_bytes = [u8(0x58), 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
10
	0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
11
	0x66, 0x66, 0x66, 0x66]
12
const d_const = d_const_generate() or { panic(err) }
13
const d2_const = d2_const_generate() or { panic(err) }
14
// id_point is the point at infinity.
15
const id_point = id_point_generate() or { panic(err) }
16
// generator point
17
const gen_point = generator() or { panic(err) }
18

19
fn d_const_generate() !Element {
20
	mut v := Element{}
21
	v.set_bytes(d_bytes)!
22
	return v
23
}
24

25
fn d2_const_generate() !Element {
26
	mut v := Element{}
27
	v.add(d_const, d_const)
28
	return v
29
}
30

31
// id_point_generate is the point at infinity.
32
fn id_point_generate() !Point {
33
	mut p := Point{}
34
	p.set_bytes(id_bytes)!
35
	return 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.
40
fn generator() !Point {
41
	mut p := Point{}
42
	p.set_bytes(gen_bytes)!
43
	return p
44
}
45

46
// Point types.
47
struct ProjectiveP1 {
48
mut:
49
	x Element
50
	y Element
51
	z Element
52
	t Element
53
}
54

55
struct ProjectiveP2 {
56
mut:
57
	x Element
58
	y Element
59
	z 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.
68
pub struct Point {
69
mut:
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.
72
	x Element
73
	y Element
74
	z Element
75
	t 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

81
fn check_initialized(points ...Point) {
82
	for _, p in points {
83
		if p.x == fe_zero && p.y == fe_zero {
84
			panic('edwards25519: use of uninitialized Point')
85
		}
86
	}
87
}
88

89
struct ProjectiveCached {
90
mut:
91
	ypx Element // y + x
92
	ymx Element // y - x
93
	z   Element
94
	t2d Element
95
}
96

97
struct AffineCached {
98
mut:
99
	ypx Element // y + x
100
	ymx Element // y - x
101
	t2d Element
102
}
103

104
fn (mut v ProjectiveP2) zero() ProjectiveP2 {
105
	v.x.zero()
106
	v.y.one()
107
	v.z.one()
108
	return 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.
118
pub 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.
127
	mut el0 := Element{}
128
	y := 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
135
	mut el1 := Element{}
136
	y2 := el1.square(y)
137
	mut el2 := Element{}
138
	u := el2.subtract(y2, fe_one)
139

140
	// v = dy² + 1
141
	mut el3 := Element{}
142
	mut vv := el3.multiply(y2, d_const)
143
	vv = vv.add(vv, fe_one)
144

145
	// x = +√(u/v)
146
	mut el4 := Element{}
147
	mut xx, was_square := el4.sqrt_ratio(u, vv)
148
	if was_square == 0 {
149
		return error('edwards25519: invalid point encoding')
150
	}
151

152
	// selected the negative square root if the sign bit is set.
153
	mut el5 := Element{}
154
	xx_neg := el5.negate(xx)
155
	xx.selected(xx_neg, xx, int(x[31] >> 7))
156

157
	v.x.set(xx)
158
	v.y.set(y)
159
	v.z.one()
160
	v.t.multiply(xx, y) // xy = T / z
161

162
	return v
163
}
164

165
// set sets v = u, and returns v.
166
pub fn (mut v Point) set(u Point) Point {
167
	v = u
168
	return v
169
}
170

171
// new_identity_point returns a new Point set to the identity.
172
pub fn new_identity_point() Point {
173
	mut p := Point{}
174
	return p.set(id_point)
175
}
176

177
// new_generator_point returns a new Point set to the canonical generator.
178
pub fn new_generator_point() Point {
179
	mut p := Point{}
180
	return p.set(gen_point)
181
}
182

183
fn (mut v ProjectiveCached) zero() ProjectiveCached {
184
	v.ypx.one()
185
	v.ymx.one()
186
	v.z.one()
187
	v.t2d.zero()
188
	return v
189
}
190

191
fn (mut v AffineCached) zero() AffineCached {
192
	v.ypx.one()
193
	v.ymx.one()
194
	v.t2d.zero()
195
	return 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.
202
pub 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.
205
	mut buf := [32]u8{}
206
	return v.bytes_generic(mut buf)
207
}
208

209
fn (mut v Point) bytes_generic(mut buf [32]u8) []u8 {
210
	check_initialized(v)
211

212
	mut zinv := Element{}
213
	mut x := Element{}
214
	mut y := Element{}
215
	zinv.invert(v.z) // zinv = 1 / z
216
	x.multiply(v.x, zinv) // x = x / z
217
	y.multiply(v.y, zinv) // y = y / z
218

219
	mut out := copy_field_element(mut buf, mut y)
220
	unsafe {
221
		// out[31] |= u8(x.is_negative() << 7) //original one
222
		out[31] |= u8(x.is_negative() * 128) // x << 7 == x * 2^7
223
	}
224
	return out
225
}
226

227
fn copy_field_element(mut buf [32]u8, mut v Element) []u8 {
228
	// this fail in test
229
	/*
230
	copy(mut buf[..], v.bytes())
231
	return buf[..]
232
	*/
233

234
	// this pass the test
235
	mut out := []u8{len: 32}
236
	for i := 0; i <= buf.len - 1; i++ {
237
		out[i] = v.bytes()[i]
238
	}
239

240
	return out
241
}
242

243
// Conversions.
244

245
fn (mut v ProjectiveP2) from_p1(p ProjectiveP1) ProjectiveP2 {
246
	v.x.multiply(p.x, p.t)
247
	v.y.multiply(p.y, p.z)
248
	v.z.multiply(p.z, p.t)
249
	return v
250
}
251

252
fn (mut v ProjectiveP2) from_p3(p Point) ProjectiveP2 {
253
	v.x.set(p.x)
254
	v.y.set(p.y)
255
	v.z.set(p.z)
256
	return v
257
}
258

259
fn (mut v Point) from_p1(p ProjectiveP1) Point {
260
	v.x.multiply(p.x, p.t)
261
	v.y.multiply(p.y, p.z)
262
	v.z.multiply(p.z, p.t)
263
	v.t.multiply(p.x, p.y)
264
	return v
265
}
266

267
fn (mut v Point) from_p2(p ProjectiveP2) Point {
268
	v.x.multiply(p.x, p.z)
269
	v.y.multiply(p.y, p.z)
270
	v.z.square(p.z)
271
	v.t.multiply(p.x, p.y)
272
	return v
273
}
274

275
fn (mut v ProjectiveCached) from_p3(p Point) ProjectiveCached {
276
	v.ypx.add(p.y, p.x)
277
	v.ymx.subtract(p.y, p.x)
278
	v.z.set(p.z)
279
	v.t2d.multiply(p.t, d2_const)
280
	return v
281
}
282

283
fn (mut v AffineCached) from_p3(p Point) AffineCached {
284
	v.ypx.add(p.y, p.x)
285
	v.ymx.subtract(p.y, p.x)
286
	v.t2d.multiply(p.t, d2_const)
287

288
	mut invz := Element{}
289
	invz.invert(p.z)
290
	v.ypx.multiply(v.ypx, invz)
291
	v.ymx.multiply(v.ymx, invz)
292
	v.t2d.multiply(v.t2d, invz)
293
	return v
294
}
295

296
// (Re)addition and subtraction.
297

298
// add sets v = p + q, and returns v.
299
pub fn (mut v Point) add(p Point, q Point) Point {
300
	check_initialized(p, q)
301
	mut pc := ProjectiveCached{}
302
	mut p1 := ProjectiveP1{}
303
	qcached := pc.from_p3(q)
304

305
	result := p1.add(p, qcached)
306
	return v.from_p1(result)
307
}
308

309
// subtract sets v = p - q, and returns v.
310
pub fn (mut v Point) subtract(p Point, q Point) Point {
311
	check_initialized(p, q)
312
	mut pc := ProjectiveCached{}
313
	mut p1 := ProjectiveP1{}
314
	qcached := pc.from_p3(q)
315
	result := p1.sub(p, qcached)
316
	return v.from_p1(result)
317
}
318

319
fn (mut v ProjectiveP1) add(p Point, q ProjectiveCached) ProjectiveP1 {
320
	// var ypx, ymx, pp, mm, tt2d, zz2 edwards25519.Element
321
	mut ypx := Element{}
322
	mut ymx := Element{}
323
	mut pp := Element{}
324
	mut mm := Element{}
325
	mut tt2d := Element{}
326
	mut zz2 := Element{}
327

328
	ypx.add(p.y, p.x)
329
	ymx.subtract(p.y, p.x)
330

331
	pp.multiply(ypx, q.ypx)
332
	mm.multiply(ymx, q.ymx)
333
	tt2d.multiply(p.t, q.t2d)
334
	zz2.multiply(p.z, q.z)
335

336
	zz2.add(zz2, zz2)
337

338
	v.x.subtract(pp, mm)
339
	v.y.add(pp, mm)
340
	v.z.add(zz2, tt2d)
341
	v.t.subtract(zz2, tt2d)
342
	return v
343
}
344

345
fn (mut v ProjectiveP1) sub(p Point, q ProjectiveCached) ProjectiveP1 {
346
	mut ypx := Element{}
347
	mut ymx := Element{}
348
	mut pp := Element{}
349
	mut mm := Element{}
350
	mut tt2d := Element{}
351
	mut zz2 := Element{}
352

353
	ypx.add(p.y, p.x)
354
	ymx.subtract(p.y, p.x)
355

356
	pp.multiply(ypx, q.ymx) // flipped sign
357
	mm.multiply(ymx, q.ypx) // flipped sign
358
	tt2d.multiply(p.t, q.t2d)
359
	zz2.multiply(p.z, q.z)
360

361
	zz2.add(zz2, zz2)
362

363
	v.x.subtract(pp, mm)
364
	v.y.add(pp, mm)
365
	v.z.subtract(zz2, tt2d) // flipped sign
366
	v.t.add(zz2, tt2d) // flipped sign
367
	return v
368
}
369

370
fn (mut v ProjectiveP1) add_affine(p Point, q AffineCached) ProjectiveP1 {
371
	mut ypx := Element{}
372
	mut ymx := Element{}
373
	mut pp := Element{}
374
	mut mm := Element{}
375
	mut tt2d := Element{}
376
	mut z2 := Element{}
377

378
	ypx.add(p.y, p.x)
379
	ymx.subtract(p.y, p.x)
380

381
	pp.multiply(ypx, q.ypx)
382
	mm.multiply(ymx, q.ymx)
383
	tt2d.multiply(p.t, q.t2d)
384

385
	z2.add(p.z, p.z)
386

387
	v.x.subtract(pp, mm)
388
	v.y.add(pp, mm)
389
	v.z.add(z2, tt2d)
390
	v.t.subtract(z2, tt2d)
391
	return v
392
}
393

394
fn (mut v ProjectiveP1) sub_affine(p Point, q AffineCached) ProjectiveP1 {
395
	mut ypx := Element{}
396
	mut ymx := Element{}
397
	mut pp := Element{}
398
	mut mm := Element{}
399
	mut tt2d := Element{}
400
	mut z2 := Element{}
401

402
	ypx.add(p.y, p.x)
403
	ymx.subtract(p.y, p.x)
404

405
	pp.multiply(ypx, q.ymx) // flipped sign
406
	mm.multiply(ymx, q.ypx) // flipped sign
407
	tt2d.multiply(p.t, q.t2d)
408

409
	z2.add(p.z, p.z)
410

411
	v.x.subtract(pp, mm)
412
	v.y.add(pp, mm)
413
	v.z.subtract(z2, tt2d) // flipped sign
414
	v.t.add(z2, tt2d) // flipped sign
415
	return v
416
}
417

418
// Doubling.
419

420
fn (mut v ProjectiveP1) double(p ProjectiveP2) ProjectiveP1 {
421
	// var xx, yy, zz2, xplusysq edwards25519.Element
422
	mut xx := Element{}
423
	mut yy := Element{}
424
	mut zz2 := Element{}
425
	mut xplusysq := Element{}
426

427
	xx.square(p.x)
428
	yy.square(p.y)
429
	zz2.square(p.z)
430
	zz2.add(zz2, zz2)
431
	xplusysq.add(p.x, p.y)
432
	xplusysq.square(xplusysq)
433

434
	v.y.add(yy, xx)
435
	v.z.subtract(yy, xx)
436

437
	v.x.subtract(xplusysq, v.y)
438
	v.t.subtract(zz2, v.z)
439
	return v
440
}
441

442
// Negation.
443

444
// negate sets v = -p, and returns v.
445
pub fn (mut v Point) negate(p Point) Point {
446
	check_initialized(p)
447
	v.x.negate(p.x)
448
	v.y.set(p.y)
449
	v.z.set(p.z)
450
	v.t.negate(p.t)
451
	return v
452
}
453

454
// equal returns 1 if v is equivalent to u, and 0 otherwise.
455
pub fn (mut v Point) equal(u Point) int {
456
	check_initialized(v, u)
457

458
	mut t1 := Element{}
459
	mut t2 := Element{}
460
	mut t3 := Element{}
461
	mut t4 := Element{}
462

463
	t1.multiply(v.x, u.z)
464
	t2.multiply(u.x, v.z)
465
	t3.multiply(v.y, u.z)
466
	t4.multiply(u.y, v.z)
467

468
	return 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.
474
fn (mut v ProjectiveCached) selected(a ProjectiveCached, b ProjectiveCached, cond int) ProjectiveCached {
475
	v.ypx.selected(a.ypx, b.ypx, cond)
476
	v.ymx.selected(a.ymx, b.ymx, cond)
477
	v.z.selected(a.z, b.z, cond)
478
	v.t2d.selected(a.t2d, b.t2d, cond)
479
	return v
480
}
481

482
// selected sets v to a if cond == 1 and to b if cond == 0.
483
fn (mut v AffineCached) selected(a AffineCached, b AffineCached, cond int) AffineCached {
484
	v.ypx.selected(a.ypx, b.ypx, cond)
485
	v.ymx.selected(a.ymx, b.ymx, cond)
486
	v.t2d.selected(a.t2d, b.t2d, cond)
487
	return v
488
}
489

490
// cond_neg negates v if cond == 1 and leaves it unchanged if cond == 0.
491
fn (mut v ProjectiveCached) cond_neg(cond int) ProjectiveCached {
492
	mut el := Element{}
493
	v.ypx.swap(mut v.ymx, cond)
494
	v.t2d.selected(el.negate(v.t2d), v.t2d, cond)
495
	return v
496
}
497

498
// cond_neg negates v if cond == 1 and leaves it unchanged if cond == 0.
499
fn (mut v AffineCached) cond_neg(cond int) AffineCached {
500
	mut el := Element{}
501
	v.ypx.swap(mut v.ymx, cond)
502
	v.t2d.selected(el.negate(v.t2d), v.t2d, cond)
503
	return v
504
}
505

506
fn check_on_curve(points ...Point) bool {
507
	for p in points {
508
		mut xx := Element{}
509
		mut yy := Element{}
510
		mut zz := Element{}
511
		mut zzzz := Element{}
512
		xx.square(p.x)
513
		yy.square(p.y)
514
		zz.square(p.z)
515
		zzzz.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²
520
		mut lhs := Element{}
521
		mut rhs := Element{}
522
		lhs.subtract(yy, xx)
523
		lhs.multiply(lhs, zz)
524
		rhs.multiply(d_const, xx)
525
		rhs.multiply(rhs, yy)
526
		rhs.add(rhs, zzzz)
527

528
		if lhs.equal(rhs) != 1 {
529
			return false
530
		}
531
		/*
532
		if lhs.equal(rhs) != 1 {
533
			lg.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
537
		lhs.multiply(p.x, p.y)
538
		rhs.multiply(p.z, p.t)
539
		/*
540
		if lhs.equal(rhs) != 1 {
541
			lg.error('point $i is not valid\nX = $p.x\nY = $p.y\nZ = $p.z')
542
		}*/
543
		if lhs.equal(rhs) != 1 {
544
			return false
545
		}
546
	}
547
	return true
548
}
549

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.