v

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

3
// extended_coordinates returns v in extended coordinates (X:Y:Z:T) where
4
// x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522.
5
fn (mut v Point) extended_coordinates() (Element, Element, Element, Element) {
6
	// This function is outlined to make the allocations inline in the caller
7
	// rather than happen on the heap. Don't change the style without making
8
	// sure it doesn't increase the inliner cost.
9
	mut e := []Element{len: 4}
10
	x, y, z, t := v.extended_coordinates_generic(mut e)
11
	return x, y, z, t
12
}
13

14
fn (mut v Point) extended_coordinates_generic(mut e []Element) (Element, Element, Element, Element) {
15
	check_initialized(v)
16
	x := e[0].set(v.x)
17
	y := e[1].set(v.y)
18
	z := e[2].set(v.z)
19
	t := e[3].set(v.t)
20
	return x, y, z, t
21
}
22

23
// Given k > 0, set s = s**(2*i).
24
fn (mut s Scalar) pow2k(k int) {
25
	for i := 0; i < k; i++ {
26
		s.multiply(s, s)
27
	}
28
}
29

30
// set_extended_coordinates sets v = (X:Y:Z:T) in extended coordinates where
31
// x = X/Z, y = Y/Z, and xy = T/Z as in https://eprint.iacr.org/2008/522.
32
//
33
// If the coordinates are invalid or don't represent a valid point on the curve,
34
// set_extended_coordinates returns an error and the receiver is
35
// unchanged. Otherwise, set_extended_coordinates returns v.
36
fn (mut v Point) set_extended_coordinates(x Element, y Element, z Element, t Element) !Point {
37
	if !is_on_curve(x, y, z, t) {
38
		return error('edwards25519: invalid point coordinates')
39
	}
40
	v.x.set(x)
41
	v.y.set(y)
42
	v.z.set(z)
43
	v.t.set(t)
44
	return v
45
}
46

47
fn is_on_curve(x Element, y Element, z Element, t Element) bool {
48
	mut lhs := Element{}
49
	mut rhs := Element{}
50

51
	mut xx := Element{}
52
	xx.square(x)
53

54
	mut yy := Element{}
55
	yy.square(y)
56

57
	mut zz := Element{}
58
	zz.square(z)
59
	// zz := new(Element).Square(Z)
60

61
	mut tt := Element{}
62
	tt.square(t)
63
	// tt := new(Element).Square(T)
64
	// -x² + y² = 1 + dx²y²
65
	// -(X/Z)² + (Y/Z)² = 1 + d(T/Z)²
66
	// -X² + Y² = Z² + dT²
67
	lhs.subtract(yy, xx)
68
	mut d := d_const
69
	rhs.multiply(d, tt)
70
	rhs.add(rhs, zz)
71
	if lhs.equal(rhs) != 1 {
72
		return false
73
	}
74
	// xy = T/Z
75
	// XY/Z² = T/Z
76
	// XY = TZ
77
	lhs.multiply(x, y)
78
	rhs.multiply(t, z)
79
	return lhs.equal(rhs) == 1
80
}
81

82
// bytes_montgomery converts v to a point on the birationally-equivalent
83
// Curve25519 Montgomery curve, and returns its canonical 32 bytes encoding
84
// according to RFC 7748.
85
//
86
// Note that bytes_montgomery only encodes the u-coordinate, so v and -v encode
87
// to the same value. If v is the identity point, bytes_montgomery returns 32
88
// zero bytes, analogously to the X25519 function.
89
pub fn (mut v Point) bytes_montgomery() []u8 {
90
	// This function is outlined to make the allocations inline in the caller
91
	// rather than happen on the heap.
92
	mut buf := [32]u8{}
93
	return v.bytes_montgomery_generic(mut buf)
94
}
95

96
fn (mut v Point) bytes_montgomery_generic(mut buf [32]u8) []u8 {
97
	check_initialized(v)
98

99
	// RFC 7748, Section 4.1 provides the bilinear map to calculate the
100
	// Montgomery u-coordinate
101
	//
102
	//              u = (1 + y) / (1 - y)
103
	//
104
	// where y = Y / Z.
105

106
	mut y := Element{}
107
	mut recip := Element{}
108
	mut u := Element{}
109

110
	y.multiply(v.y, y.invert(v.z)) // y = Y / Z
111
	recip.invert(recip.subtract(fe_one, y)) // r = 1/(1 - y)
112
	u.multiply(u.add(fe_one, y), recip) // u = (1 + y)*r
113

114
	return copy_field_element(mut buf, mut u)
115
}
116

117
// mult_by_cofactor sets v = 8 * p, and returns v.
118
pub fn (mut v Point) mult_by_cofactor(p Point) Point {
119
	check_initialized(p)
120
	mut result := ProjectiveP1{}
121
	mut pp := ProjectiveP2{}
122
	pp.from_p3(p)
123
	result.double(pp)
124
	pp.from_p1(result)
125
	result.double(pp)
126
	pp.from_p1(result)
127
	result.double(pp)
128
	return v.from_p1(result)
129
}
130

131
// invert sets s to the inverse of a nonzero scalar v, and returns s.
132
//
133
// If t is zero, invert returns zero.
134
pub fn (mut s Scalar) invert(t Scalar) Scalar {
135
	// Uses a hardcoded sliding window of width 4.
136
	mut table := [8]Scalar{}
137
	mut tt := Scalar{}
138
	tt.multiply(t, t)
139
	table[0] = t
140
	for i := 0; i < 7; i++ {
141
		table[i + 1].multiply(table[i], tt)
142
	}
143
	// Now table = [t**1, t**3, t**7, t**11, t**13, t**15]
144
	// so t**k = t[k/2] for odd k
145

146
	// To compute the sliding window digits, use the following Sage script:
147

148
	// sage: import itertools
149
	// sage: def sliding_window(w,k):
150
	// ....:     digits = []
151
	// ....:     while k > 0:
152
	// ....:         if k % 2 == 1:
153
	// ....:             kmod = k % (2**w)
154
	// ....:             digits.append(kmod)
155
	// ....:             k = k - kmod
156
	// ....:         else:
157
	// ....:             digits.append(0)
158
	// ....:         k = k // 2
159
	// ....:     return digits
160

161
	// Now we can compute s roughly as follows:
162

163
	// sage: s = 1
164
	// sage: for coeff in reversed(sliding_window(4,l-2)):
165
	// ....:     s = s*s
166
	// ....:     if coeff > 0 :
167
	// ....:         s = s*t**coeff
168

169
	// This works on one bit at a time, with many runs of zeros.
170
	// The digits can be collapsed into [(count, coeff)] as follows:
171

172
	// sage: [(len(list(group)),d) for d,group in itertools.groupby(sliding_window(4,l-2))]
173

174
	// Entries of the form (k, 0) turn into pow2k(k)
175
	// Entries of the form (1, coeff) turn into a squaring and then a table lookup.
176
	// We can fold the squaring into the previous pow2k(k) as pow2k(k+1).
177

178
	s = table[1 / 2]
179
	s.pow2k(127 + 1)
180
	s.multiply(s, table[1 / 2])
181
	s.pow2k(4 + 1)
182
	s.multiply(s, table[9 / 2])
183
	s.pow2k(3 + 1)
184
	s.multiply(s, table[11 / 2])
185
	s.pow2k(3 + 1)
186
	s.multiply(s, table[13 / 2])
187
	s.pow2k(3 + 1)
188
	s.multiply(s, table[15 / 2])
189
	s.pow2k(4 + 1)
190
	s.multiply(s, table[7 / 2])
191
	s.pow2k(4 + 1)
192
	s.multiply(s, table[15 / 2])
193
	s.pow2k(3 + 1)
194
	s.multiply(s, table[5 / 2])
195
	s.pow2k(3 + 1)
196
	s.multiply(s, table[1 / 2])
197
	s.pow2k(4 + 1)
198
	s.multiply(s, table[15 / 2])
199
	s.pow2k(4 + 1)
200
	s.multiply(s, table[15 / 2])
201
	s.pow2k(4 + 1)
202
	s.multiply(s, table[7 / 2])
203
	s.pow2k(3 + 1)
204
	s.multiply(s, table[3 / 2])
205
	s.pow2k(4 + 1)
206
	s.multiply(s, table[11 / 2])
207
	s.pow2k(5 + 1)
208
	s.multiply(s, table[11 / 2])
209
	s.pow2k(9 + 1)
210
	s.multiply(s, table[9 / 2])
211
	s.pow2k(3 + 1)
212
	s.multiply(s, table[3 / 2])
213
	s.pow2k(4 + 1)
214
	s.multiply(s, table[3 / 2])
215
	s.pow2k(4 + 1)
216
	s.multiply(s, table[3 / 2])
217
	s.pow2k(4 + 1)
218
	s.multiply(s, table[9 / 2])
219
	s.pow2k(3 + 1)
220
	s.multiply(s, table[7 / 2])
221
	s.pow2k(3 + 1)
222
	s.multiply(s, table[3 / 2])
223
	s.pow2k(3 + 1)
224
	s.multiply(s, table[13 / 2])
225
	s.pow2k(3 + 1)
226
	s.multiply(s, table[7 / 2])
227
	s.pow2k(4 + 1)
228
	s.multiply(s, table[9 / 2])
229
	s.pow2k(3 + 1)
230
	s.multiply(s, table[15 / 2])
231
	s.pow2k(4 + 1)
232
	s.multiply(s, table[11 / 2])
233

234
	return s
235
}
236

237
// multi_scalar_mult sets v = sum(scalars[i] * points[i]), and returns v.
238
//
239
// Execution time depends only on the lengths of the two slices, which must match.
240
pub fn (mut v Point) multi_scalar_mult(scalars []Scalar, points []Point) Point {
241
	if scalars.len != points.len {
242
		panic('edwards25519: called multi_scalar_mult with different size inputs')
243
	}
244
	check_initialized(...points)
245

246
	mut sc := scalars.clone()
247
	// Proceed as in the single-base case, but share doublings
248
	// between each point in the multiscalar equation.
249

250
	// Build lookup tables for each point
251
	mut tables := []ProjLookupTable{len: points.len}
252
	for i, _ in tables {
253
		tables[i].from_p3(points[i])
254
	}
255
	// Compute signed radix-16 digits for each scalar
256
	// digits := make([][64]int8, len(scalars))
257
	mut digits := [][]i8{len: sc.len, init: []i8{len: 64, cap: 64}}
258

259
	for j, _ in digits {
260
		digits[j] = sc[j].signed_radix16()
261
	}
262

263
	// Unwrap first loop iteration to save computing 16*identity
264
	mut multiple := ProjectiveCached{}
265
	mut tmp1 := ProjectiveP1{}
266
	mut tmp2 := ProjectiveP2{}
267
	// Lookup-and-add the appropriate multiple of each input point
268
	for k, _ in tables {
269
		tables[k].select_into(mut multiple, digits[k][63])
270
		tmp1.add(v, multiple) // tmp1 = v + x_(j,63)*Q in P1xP1 coords
271
		v.from_p1(tmp1) // update v
272
	}
273
	tmp2.from_p3(v) // set up tmp2 = v in P2 coords for next iteration
274
	for r := 62; r >= 0; r-- {
275
		tmp1.double(tmp2) // tmp1 =  2*(prev) in P1xP1 coords
276
		tmp2.from_p1(tmp1) // tmp2 =  2*(prev) in P2 coords
277
		tmp1.double(tmp2) // tmp1 =  4*(prev) in P1xP1 coords
278
		tmp2.from_p1(tmp1) // tmp2 =  4*(prev) in P2 coords
279
		tmp1.double(tmp2) // tmp1 =  8*(prev) in P1xP1 coords
280
		tmp2.from_p1(tmp1) // tmp2 =  8*(prev) in P2 coords
281
		tmp1.double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords
282
		v.from_p1(tmp1) //    v = 16*(prev) in P3 coords
283
		// Lookup-and-add the appropriate multiple of each input point
284
		for s, _ in tables {
285
			tables[s].select_into(mut multiple, digits[s][r])
286
			tmp1.add(v, multiple) // tmp1 = v + x_(j,i)*Q in P1xP1 coords
287
			v.from_p1(tmp1) // update v
288
		}
289
		tmp2.from_p3(v) // set up tmp2 = v in P2 coords for next iteration
290
	}
291
	return v
292
}
293

294
// vartime_multiscalar_mult sets v = sum(scalars[i] * points[i]), and returns v.
295
//
296
// Execution time depends on the inputs.
297
pub fn (mut v Point) vartime_multiscalar_mult(scalars []Scalar, points []Point) Point {
298
	if scalars.len != points.len {
299
		panic('edwards25519: called VarTimeMultiScalarMult with different size inputs')
300
	}
301
	check_initialized(...points)
302

303
	// Generalize double-base NAF computation to arbitrary sizes.
304
	// Here all the points are dynamic, so we only use the smaller
305
	// tables.
306

307
	// Build lookup tables for each point
308
	mut tables := []NafLookupTable5{len: points.len}
309
	for i, _ in tables {
310
		tables[i].from_p3(points[i])
311
	}
312
	mut sc := scalars.clone()
313
	// Compute a NAF for each scalar
314
	// mut nafs := make([][256]int8, len(scalars))
315
	mut nafs := [][]i8{len: sc.len, init: []i8{len: 256, cap: 256}}
316
	for j, _ in nafs {
317
		nafs[j] = sc[j].non_adjacent_form(5)
318
	}
319

320
	mut multiple := ProjectiveCached{}
321
	mut tmp1 := ProjectiveP1{}
322
	mut tmp2 := ProjectiveP2{}
323
	tmp2.zero()
324

325
	// Move from high to low bits, doubling the accumulator
326
	// at each iteration and checking whether there is a nonzero
327
	// coefficient to look up a multiple of.
328
	//
329
	// Skip trying to find the first nonzero coefficient, because
330
	// searching might be more work than a few extra doublings.
331
	// k == i, l == j
332
	for k := 255; k >= 0; k-- {
333
		tmp1.double(tmp2)
334

335
		for l, _ in nafs {
336
			if nafs[l][k] > 0 {
337
				v.from_p1(tmp1)
338
				tables[l].select_into(mut multiple, nafs[l][k])
339
				tmp1.add(v, multiple)
340
			} else if nafs[l][k] < 0 {
341
				v.from_p1(tmp1)
342
				tables[l].select_into(mut multiple, -nafs[l][k])
343
				tmp1.sub(v, multiple)
344
			}
345
		}
346

347
		tmp2.from_p1(tmp1)
348
	}
349

350
	v.from_p2(tmp2)
351
	return v
352
}
353

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

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

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

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