bls12-381 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/main.yml +18 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +77 -0
- data/Rakefile +8 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/bls12-381.gemspec +37 -0
- data/lib/bls.rb +100 -0
- data/lib/bls/curve.rb +36 -0
- data/lib/bls/field.rb +692 -0
- data/lib/bls/math.rb +144 -0
- data/lib/bls/pairing.rb +20 -0
- data/lib/bls/point.rb +509 -0
- data/lib/bls/version.rb +5 -0
- metadata +93 -0
data/lib/bls/field.rb
ADDED
@@ -0,0 +1,692 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module BLS
|
4
|
+
|
5
|
+
# Finite field
|
6
|
+
module Field
|
7
|
+
|
8
|
+
def zero?
|
9
|
+
value.zero?
|
10
|
+
end
|
11
|
+
|
12
|
+
def negate
|
13
|
+
self.class.new(-value)
|
14
|
+
end
|
15
|
+
|
16
|
+
def ==(other)
|
17
|
+
value == other.value
|
18
|
+
end
|
19
|
+
|
20
|
+
def invert
|
21
|
+
x0 = 1
|
22
|
+
x1 = 0
|
23
|
+
y0 = 0
|
24
|
+
y1 = 1
|
25
|
+
a = self.class.const_get(:ORDER)
|
26
|
+
b = value
|
27
|
+
until a.zero?
|
28
|
+
q, b, a = [b / a, a, b % a]
|
29
|
+
x0, x1 = [x1, x0 - q * x1]
|
30
|
+
y0, y1 = [y1, y0 - q * y1]
|
31
|
+
end
|
32
|
+
self.class.new(x0)
|
33
|
+
end
|
34
|
+
|
35
|
+
def add(other)
|
36
|
+
self.class.new(value + other.value)
|
37
|
+
end
|
38
|
+
alias + add
|
39
|
+
|
40
|
+
def square
|
41
|
+
self.class.new(value**2)
|
42
|
+
end
|
43
|
+
|
44
|
+
def pow(n)
|
45
|
+
v = value.pow(n, self.class.const_get(:ORDER))
|
46
|
+
self.class.new(v)
|
47
|
+
end
|
48
|
+
alias ** pow
|
49
|
+
|
50
|
+
def subtract(other)
|
51
|
+
self.class.new(value - other.value)
|
52
|
+
end
|
53
|
+
alias - subtract
|
54
|
+
|
55
|
+
def multiply(other)
|
56
|
+
v = other.is_a?(Field) ? other.value : other
|
57
|
+
self.class.new(value * v)
|
58
|
+
end
|
59
|
+
alias * multiply
|
60
|
+
|
61
|
+
def div(other)
|
62
|
+
v = other.is_a?(Field) ? other.invert : self.class.new(other).invert
|
63
|
+
multiply(v)
|
64
|
+
end
|
65
|
+
alias / div
|
66
|
+
end
|
67
|
+
|
68
|
+
# Finite field over q.
|
69
|
+
class Fq
|
70
|
+
include Field
|
71
|
+
|
72
|
+
ORDER = BLS::Curve::P
|
73
|
+
MAX_BITS = Curve::P.bit_length
|
74
|
+
|
75
|
+
attr_reader :value
|
76
|
+
|
77
|
+
def initialize(value)
|
78
|
+
raise ArgumentError, 'Invalid value.' unless value.is_a?(Integer)
|
79
|
+
|
80
|
+
@value = BLS.mod(value, ORDER)
|
81
|
+
end
|
82
|
+
|
83
|
+
ZERO = Fq.new(0)
|
84
|
+
ONE = Fq.new(1)
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
# Finite field over r.
|
89
|
+
class Fr
|
90
|
+
include Field
|
91
|
+
|
92
|
+
ORDER = BLS::Curve::R
|
93
|
+
|
94
|
+
attr_reader :value
|
95
|
+
|
96
|
+
def initialize(value)
|
97
|
+
raise ArgumentError, 'Invalid value.' unless value.is_a?(Integer)
|
98
|
+
|
99
|
+
@value = BLS.mod(value, ORDER)
|
100
|
+
end
|
101
|
+
|
102
|
+
ZERO = Fr.new(0)
|
103
|
+
ONE = Fr.new(1)
|
104
|
+
|
105
|
+
def legendre
|
106
|
+
pow((order - 1) / 2)
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
# Module for a field over polynomial.
|
112
|
+
# TT - ThisType, CT - ChildType, TTT - Tuple Type
|
113
|
+
module FQP
|
114
|
+
|
115
|
+
def ==(other)
|
116
|
+
coeffs == other.coeffs
|
117
|
+
end
|
118
|
+
|
119
|
+
def zero?
|
120
|
+
coeffs.find { |c| !c.zero? }.nil?
|
121
|
+
end
|
122
|
+
|
123
|
+
def add(other)
|
124
|
+
self.class.new(coeffs.map.with_index { |v, i| v + other.coeffs[i] })
|
125
|
+
end
|
126
|
+
alias + add
|
127
|
+
|
128
|
+
def subtract(other)
|
129
|
+
self.class.new(coeffs.map.with_index { |v, i| v - other.coeffs[i] })
|
130
|
+
end
|
131
|
+
alias - subtract
|
132
|
+
|
133
|
+
def div(other)
|
134
|
+
inv = other.is_a?(Integer) ? Fq.new(other).invert.value : other.invert
|
135
|
+
multiply(inv)
|
136
|
+
end
|
137
|
+
alias / div
|
138
|
+
|
139
|
+
def negate
|
140
|
+
self.class.new(coeffs.map(&:negate))
|
141
|
+
end
|
142
|
+
|
143
|
+
def pow(n)
|
144
|
+
one = self.class.const_get(:ONE)
|
145
|
+
return one if n.zero?
|
146
|
+
return self if n == 1
|
147
|
+
|
148
|
+
p = one
|
149
|
+
d = self
|
150
|
+
while n.positive?
|
151
|
+
p *= d unless (n & 1).zero?
|
152
|
+
n >>= 1
|
153
|
+
d = d.square
|
154
|
+
end
|
155
|
+
p
|
156
|
+
end
|
157
|
+
alias ** pow
|
158
|
+
|
159
|
+
def conjugate
|
160
|
+
self.class.new([coeffs[0], coeffs[1].negate])
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
# Finite extension field over irreducible polynomial.
|
165
|
+
# Fq(u) / (u^2 - β) where β = -1
|
166
|
+
class Fq2
|
167
|
+
include FQP
|
168
|
+
|
169
|
+
# For Fq2 roots of unity.
|
170
|
+
RV1 = 0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09
|
171
|
+
EV1 = 0x699be3b8c6870965e5bf892ad5d2cc7b0e85a117402dfd83b7f4a947e02d978498255a2aaec0ac627b5afbdf1bf1c90
|
172
|
+
EV2 = 0x8157cd83046453f5dd0972b6e3949e4288020b5b8a9cc99ca07e27089a2ce2436d965026adad3ef7baba37f2183e9b5
|
173
|
+
EV3 = 0xab1c2ffdd6c253ca155231eb3e71ba044fd562f6f72bc5bad5ec46a0b7a3b0247cf08ce6c6317f40edbc653a72dee17
|
174
|
+
EV4 = 0xaa404866706722864480885d68ad0ccac1967c7544b447873cc37e0181271e006df72162a3d3e0287bf597fbf7f8fc1
|
175
|
+
|
176
|
+
ORDER = BLS::Curve::P2
|
177
|
+
MAX_BITS = Curve::P2.bit_length
|
178
|
+
COFACTOR = BLS::Curve::H2
|
179
|
+
|
180
|
+
attr_reader :coeffs
|
181
|
+
|
182
|
+
def initialize(coeffs)
|
183
|
+
raise ArgumentError, 'Expected array with 2 elements' unless coeffs.size == 2
|
184
|
+
|
185
|
+
@coeffs = coeffs.map { |c| c.is_a?(Integer) ? Fq.new(c) : c }
|
186
|
+
end
|
187
|
+
|
188
|
+
ROOT = Fq.new(-1)
|
189
|
+
ZERO = Fq2.new([0, 0])
|
190
|
+
ONE = Fq2.new([1, 0])
|
191
|
+
|
192
|
+
# Eighth roots of unity, used for computing square roots in Fq2.
|
193
|
+
ROOTS_OF_UNITY = [
|
194
|
+
Fq2.new([1, 0]),
|
195
|
+
Fq2.new([RV1, -RV1]),
|
196
|
+
Fq2.new([0, 1]),
|
197
|
+
Fq2.new([RV1, RV1]),
|
198
|
+
Fq2.new([-1, 0]),
|
199
|
+
Fq2.new([-RV1, RV1]),
|
200
|
+
Fq2.new([0, -1]),
|
201
|
+
Fq2.new([-RV1, -RV1])
|
202
|
+
].freeze
|
203
|
+
|
204
|
+
# eta values, used for computing sqrt(g(X1(t)))
|
205
|
+
ETAS = [
|
206
|
+
Fq2.new([EV1, EV2]),
|
207
|
+
Fq2.new([-EV2, EV1]),
|
208
|
+
Fq2.new([EV3, EV4]),
|
209
|
+
Fq2.new([-EV4, EV3])
|
210
|
+
].freeze
|
211
|
+
|
212
|
+
FROBENIUS_COEFFICIENTS = [
|
213
|
+
Fq.new(0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001),
|
214
|
+
Fq.new(0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa)
|
215
|
+
].freeze
|
216
|
+
|
217
|
+
def values
|
218
|
+
coeffs.map(&:value)
|
219
|
+
end
|
220
|
+
|
221
|
+
def square
|
222
|
+
c0 = coeffs[0]
|
223
|
+
c1 = coeffs[1]
|
224
|
+
a = c0 + c1
|
225
|
+
b = c0 - c1
|
226
|
+
c = c0 + c0
|
227
|
+
Fq2.new([a * b, c * c1])
|
228
|
+
end
|
229
|
+
|
230
|
+
def multiply(other)
|
231
|
+
return Fq2.new(coeffs.map { |c| c * other }) if other.is_a?(Integer)
|
232
|
+
|
233
|
+
c0, c1 = coeffs
|
234
|
+
r0, r1 = other.coeffs
|
235
|
+
t1 = c0 * r0
|
236
|
+
t2 = c1 * r1
|
237
|
+
Fq2.new([t1 - t2, ((c0 + c1) * (r0 + r1)) - (t1 + t2)])
|
238
|
+
end
|
239
|
+
alias * multiply
|
240
|
+
|
241
|
+
def invert
|
242
|
+
a, b = values
|
243
|
+
factor = Fq.new(a * a + b * b).invert
|
244
|
+
Fq2.new([factor * a, factor * -b])
|
245
|
+
end
|
246
|
+
|
247
|
+
# Raises to q**i -th power
|
248
|
+
def frobenius_map(power)
|
249
|
+
Fq2.new([coeffs[0], coeffs[1] * Fq2::FROBENIUS_COEFFICIENTS[power % 2]])
|
250
|
+
end
|
251
|
+
|
252
|
+
def mul_by_non_residue
|
253
|
+
c0, c1 = coeffs
|
254
|
+
Fq2.new([c0 - c1, c0 + c1])
|
255
|
+
end
|
256
|
+
|
257
|
+
def multiply_by_b
|
258
|
+
c0, c1 = coeffs
|
259
|
+
t0 = c0 * 4
|
260
|
+
t1 = c1 * 4
|
261
|
+
Fq2.new([t0 - t1, t0 + t1])
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
# Finite extension field over irreducible polynomial.
|
266
|
+
# Fq2(v) / (v^3 - ξ) where ξ = u + 1
|
267
|
+
class Fq6
|
268
|
+
include FQP
|
269
|
+
|
270
|
+
attr_reader :coeffs
|
271
|
+
|
272
|
+
def initialize(coeffs)
|
273
|
+
raise ArgumentError, 'Expected array with 3 elements' unless coeffs.size == 3
|
274
|
+
|
275
|
+
@coeffs = coeffs
|
276
|
+
end
|
277
|
+
|
278
|
+
def self.from_tuple(t)
|
279
|
+
Fq6.new([Fq2.new(t[0...2]), Fq2.new(t[2...4]), Fq2.new(t[4...6])])
|
280
|
+
end
|
281
|
+
|
282
|
+
ZERO = Fq6.new([Fq2::ZERO, Fq2::ZERO, Fq2::ZERO])
|
283
|
+
ONE = Fq6.new([Fq2::ONE, Fq2::ZERO, Fq2::ZERO])
|
284
|
+
|
285
|
+
FROBENIUS_COEFFICIENTS_1 = [
|
286
|
+
Fq2.new([
|
287
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,
|
288
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
289
|
+
]),
|
290
|
+
Fq2.new([
|
291
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,
|
292
|
+
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac
|
293
|
+
]),
|
294
|
+
Fq2.new([
|
295
|
+
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe,
|
296
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,
|
297
|
+
]),
|
298
|
+
Fq2.new([
|
299
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,
|
300
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
|
301
|
+
]),
|
302
|
+
Fq2.new([
|
303
|
+
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac,
|
304
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
305
|
+
]),
|
306
|
+
Fq2.new([
|
307
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,
|
308
|
+
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe
|
309
|
+
])
|
310
|
+
].freeze
|
311
|
+
|
312
|
+
FROBENIUS_COEFFICIENTS_2 = [
|
313
|
+
Fq2.new([
|
314
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,
|
315
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
316
|
+
]),
|
317
|
+
Fq2.new([
|
318
|
+
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad,
|
319
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
320
|
+
]),
|
321
|
+
Fq2.new([
|
322
|
+
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac,
|
323
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
324
|
+
]),
|
325
|
+
Fq2.new([
|
326
|
+
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa,
|
327
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
328
|
+
]),
|
329
|
+
Fq2.new([
|
330
|
+
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe,
|
331
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
332
|
+
]),
|
333
|
+
Fq2.new([
|
334
|
+
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff,
|
335
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
336
|
+
])
|
337
|
+
].freeze
|
338
|
+
|
339
|
+
# Multiply by quadratic non-residue v.
|
340
|
+
def mul_by_non_residue
|
341
|
+
Fq6.new([coeffs[2].mul_by_non_residue, coeffs[0], coeffs[1]])
|
342
|
+
end
|
343
|
+
|
344
|
+
def multiply(other)
|
345
|
+
return Fq6.new([coeffs[0] * other, coeffs[1] * other, coeffs[2] * other]) if other.is_a?(Integer)
|
346
|
+
|
347
|
+
c0, c1, c2 = coeffs
|
348
|
+
r0, r1, r2 = other.coeffs
|
349
|
+
t0 = c0 * r0
|
350
|
+
t1 = c1 * r1
|
351
|
+
t2 = c2 * r2
|
352
|
+
|
353
|
+
Fq6.new([
|
354
|
+
t0 + ((c1 + c2) * (r1 + r2) - (t1 + t2)).mul_by_non_residue,
|
355
|
+
(c0 + c1) * (r0 + r1) - (t0 + t1) + t2.mul_by_non_residue,
|
356
|
+
t1 + ((c0 + c2) * (r0 + r2) - (t0 + t2))
|
357
|
+
])
|
358
|
+
end
|
359
|
+
alias * multiply
|
360
|
+
|
361
|
+
# Sparse multiplication.
|
362
|
+
def multiply_by_1(b1)
|
363
|
+
Fq6.new([coeffs[2].multiply(b1).mul_by_non_residue, coeffs[0] * b1, coeffs[1] * b1])
|
364
|
+
end
|
365
|
+
|
366
|
+
# Sparse multiplication.
|
367
|
+
def multiply_by_01(b0, b1)
|
368
|
+
c0, c1, c2 = coeffs
|
369
|
+
t0 = c0 * b0
|
370
|
+
t1 = c1 * b1
|
371
|
+
Fq6.new([((c1 + c2) * b1 - t1).mul_by_non_residue + t0, (b0 + b1) * (c0 + c1) - t0 - t1, (c0 + c2) * b0 - t0 + t1])
|
372
|
+
end
|
373
|
+
|
374
|
+
def multiply_by_fq2(other)
|
375
|
+
Fq6.new(coeffs.map { |c| c * other })
|
376
|
+
end
|
377
|
+
|
378
|
+
def square
|
379
|
+
c0, c1, c2 = coeffs
|
380
|
+
t0 = c0.square
|
381
|
+
t1 = c0 * c1 * 2
|
382
|
+
t3 = c1 * c2 * 2
|
383
|
+
t4 = c2.square
|
384
|
+
Fq6.new([t3.mul_by_non_residue + t0, t4.mul_by_non_residue + t1, t1 + (c0 - c1 + c2).square + t3 - t0 - t4])
|
385
|
+
end
|
386
|
+
|
387
|
+
def invert
|
388
|
+
c0, c1, c2 = coeffs
|
389
|
+
t0 = c0.square - (c2 * c1).mul_by_non_residue
|
390
|
+
t1 = c2.square.mul_by_non_residue - (c0 * c1)
|
391
|
+
t2 = c1.square - c0 * c2
|
392
|
+
t4 = ((c2 * t1 + c1 * t2).mul_by_non_residue + c0 * t0).invert
|
393
|
+
Fq6.new([t4 * t0, t4 * t1, t4 * t2])
|
394
|
+
end
|
395
|
+
|
396
|
+
def frobenius_map(power)
|
397
|
+
Fq6.new([
|
398
|
+
coeffs[0].frobenius_map(power),
|
399
|
+
coeffs[1].frobenius_map(power) * Fq6::FROBENIUS_COEFFICIENTS_1[power % 6],
|
400
|
+
coeffs[2].frobenius_map(power) * Fq6::FROBENIUS_COEFFICIENTS_2[power % 6]
|
401
|
+
])
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
# Finite extension field over irreducible polynomial.
|
406
|
+
# Fq6(w) / (w2 - γ) where γ = v
|
407
|
+
class Fq12
|
408
|
+
include FQP
|
409
|
+
|
410
|
+
attr_reader :coeffs
|
411
|
+
|
412
|
+
def initialize(coeffs)
|
413
|
+
raise ArgumentError, 'Expected array with 2 elements' unless coeffs.size == 2
|
414
|
+
|
415
|
+
@coeffs = coeffs
|
416
|
+
end
|
417
|
+
|
418
|
+
def self.from_tuple(t)
|
419
|
+
Fq12.new([Fq6.from_tuple(t[0...6]), Fq6.from_tuple(t[6...12])])
|
420
|
+
end
|
421
|
+
|
422
|
+
ZERO = Fq12.new([Fq6::ZERO, Fq6::ZERO])
|
423
|
+
ONE = Fq12.new([Fq6::ONE, Fq6::ZERO])
|
424
|
+
|
425
|
+
FROBENIUS_COEFFICIENTS = [
|
426
|
+
Fq2.new([
|
427
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001,
|
428
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
429
|
+
]),
|
430
|
+
Fq2.new([
|
431
|
+
0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8,
|
432
|
+
0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3
|
433
|
+
]),
|
434
|
+
Fq2.new([
|
435
|
+
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffeffff,
|
436
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
437
|
+
]),
|
438
|
+
Fq2.new([
|
439
|
+
0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2,
|
440
|
+
0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09
|
441
|
+
]),
|
442
|
+
Fq2.new([
|
443
|
+
0x00000000000000005f19672fdf76ce51ba69c6076a0f77eaddb3a93be6f89688de17d813620a00022e01fffffffefffe,
|
444
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
445
|
+
]),
|
446
|
+
Fq2.new([
|
447
|
+
0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995,
|
448
|
+
0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116
|
449
|
+
]),
|
450
|
+
Fq2.new([
|
451
|
+
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaaaa,
|
452
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
453
|
+
]),
|
454
|
+
Fq2.new([
|
455
|
+
0x00fc3e2b36c4e03288e9e902231f9fb854a14787b6c7b36fec0c8ec971f63c5f282d5ac14d6c7ec22cf78a126ddc4af3,
|
456
|
+
0x1904d3bf02bb0667c231beb4202c0d1f0fd603fd3cbd5f4f7b2443d784bab9c4f67ea53d63e7813d8d0775ed92235fb8
|
457
|
+
]),
|
458
|
+
Fq2.new([
|
459
|
+
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac,
|
460
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
461
|
+
]),
|
462
|
+
Fq2.new([
|
463
|
+
0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09,
|
464
|
+
0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2
|
465
|
+
]),
|
466
|
+
Fq2.new([
|
467
|
+
0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad,
|
468
|
+
0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
469
|
+
]),
|
470
|
+
Fq2.new([
|
471
|
+
0x05b2cfd9013a5fd8df47fa6b48b1e045f39816240c0b8fee8beadf4d8e9c0566c63a3e6e257f87329b18fae980078116,
|
472
|
+
0x144e4211384586c16bd3ad4afa99cc9170df3560e77982d0db45f3536814f0bd5871c1908bd478cd1ee605167ff82995
|
473
|
+
])
|
474
|
+
].freeze
|
475
|
+
|
476
|
+
def multiply(other)
|
477
|
+
return Fq12.new([coeffs[0] * other, coeffs[1] * other]) if other.is_a?(Integer)
|
478
|
+
|
479
|
+
c0, c1 = coeffs
|
480
|
+
r0, r1 = other.coeffs
|
481
|
+
t1 = c0 * r0
|
482
|
+
t2 = c1 * r1
|
483
|
+
Fq12.new([t1 + t2.mul_by_non_residue, (c0 + c1) * (r0 + r1) - (t1 + t2)])
|
484
|
+
end
|
485
|
+
alias * multiply
|
486
|
+
|
487
|
+
def multiply_by_014(o0, o1, o4)
|
488
|
+
c0, c1 = coeffs
|
489
|
+
t0 = c0.multiply_by_01(o0, o1)
|
490
|
+
t1 = c1.multiply_by_1(o4)
|
491
|
+
Fq12.new([t1.mul_by_non_residue + t0, (c1 + c0).multiply_by_01(o0, o1 + o4) - t0 - t1])
|
492
|
+
end
|
493
|
+
|
494
|
+
def multiply_by_fq2(other)
|
495
|
+
Fq12.new(coeffs.map{ |c| c.multiply_by_fq2(other) })
|
496
|
+
end
|
497
|
+
|
498
|
+
def square
|
499
|
+
c0, c1 = coeffs
|
500
|
+
ab = c0 * c1
|
501
|
+
Fq12.new([(c1.mul_by_non_residue + c0) * (c0 + c1) - ab - ab.mul_by_non_residue, ab + ab])
|
502
|
+
end
|
503
|
+
|
504
|
+
def invert
|
505
|
+
c0, c1 = coeffs
|
506
|
+
t = (c0.square - c1.square.mul_by_non_residue).invert
|
507
|
+
Fq12.new([c0 * t, (c1 * t).negate])
|
508
|
+
end
|
509
|
+
|
510
|
+
def frobenius_map(power)
|
511
|
+
c0, c1 = coeffs
|
512
|
+
r0 = c0.frobenius_map(power)
|
513
|
+
c1_0, c1_1, c1_2 = c1.frobenius_map(power).coeffs
|
514
|
+
Fq12.new([
|
515
|
+
r0,
|
516
|
+
Fq6.new([
|
517
|
+
c1_0 * Fq12::FROBENIUS_COEFFICIENTS[power % 12],
|
518
|
+
c1_1 * Fq12::FROBENIUS_COEFFICIENTS[power % 12],
|
519
|
+
c1_2 * Fq12::FROBENIUS_COEFFICIENTS[power % 12]])])
|
520
|
+
end
|
521
|
+
|
522
|
+
def final_exponentiate
|
523
|
+
t0 = frobenius_map(6) / self
|
524
|
+
t1 = t0.frobenius_map(2) * t0
|
525
|
+
t2 = t1.cyclotomic_exp(Curve::X).conjugate
|
526
|
+
t3 = t1.cyclotomic_square.conjugate * t2
|
527
|
+
t4 = t3.cyclotomic_exp(Curve::X).conjugate
|
528
|
+
t5 = t4.cyclotomic_exp(Curve::X).conjugate
|
529
|
+
t6 = t5.cyclotomic_exp(Curve::X).conjugate * t2.cyclotomic_square
|
530
|
+
(t2 * t5).frobenius_map(2) * (t4 * t1).frobenius_map(3) *
|
531
|
+
(t6 * t1.conjugate).frobenius_map(1) * t6.cyclotomic_exp(Curve::X).conjugate * t3.conjugate * t1
|
532
|
+
end
|
533
|
+
|
534
|
+
def cyclotomic_square
|
535
|
+
c0, c1 = coeffs
|
536
|
+
c0c0, c0c1, c0c2 = c0.coeffs
|
537
|
+
c1c0, c1c1, c1c2 = c1.coeffs
|
538
|
+
t3, t4 = fq4_square(c0c0, c1c1)
|
539
|
+
t5, t6 = fq4_square(c1c0, c0c2)
|
540
|
+
t7, t8 = fq4_square(c0c1, c1c2)
|
541
|
+
t9 = t8.mul_by_non_residue
|
542
|
+
Fq12.new([
|
543
|
+
Fq6.new([(t3 - c0c0) * 2 + t3, (t5 - c0c1) * 2 + t5, (t7 - c0c2) * 2 + t7]),
|
544
|
+
Fq6.new([(t9 + c1c0) * 2 + t9, (t4 + c1c1) * 2 + t4, (t6 + c1c2) * 2 + t6])])
|
545
|
+
end
|
546
|
+
|
547
|
+
def cyclotomic_exp(n)
|
548
|
+
z = Fq12::ONE
|
549
|
+
i = BLS_X_LEN - 1
|
550
|
+
while i >= 0
|
551
|
+
z = z.cyclotomic_square
|
552
|
+
z *= self unless BLS.bit_get(n, i).zero?
|
553
|
+
i -= 1
|
554
|
+
end
|
555
|
+
z
|
556
|
+
end
|
557
|
+
|
558
|
+
private
|
559
|
+
|
560
|
+
# @param [Fq2] a
|
561
|
+
# @param [Fq2] b
|
562
|
+
# @return [Array]
|
563
|
+
def fq4_square(a, b)
|
564
|
+
a2 = a.square
|
565
|
+
b2 = b.square
|
566
|
+
[b2.mul_by_non_residue + a2, (a + b).square - a2 - b2]
|
567
|
+
end
|
568
|
+
|
569
|
+
end
|
570
|
+
|
571
|
+
UT_ROOT = BLS::Fq6.new([BLS::Fq2::ZERO, BLS::Fq2::ONE, BLS::Fq2::ZERO])
|
572
|
+
WSQ = BLS::Fq12.new([UT_ROOT, BLS::Fq6::ZERO])
|
573
|
+
WSQ_INV = WSQ.invert
|
574
|
+
WCU = BLS::Fq12.new([BLS::Fq6::ZERO, UT_ROOT])
|
575
|
+
WCU_INV = WCU.invert
|
576
|
+
# 1 / F2(2)^((p - 1) / 3) in GF(p^2)
|
577
|
+
PSI2_C1 = 0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac
|
578
|
+
BLS_X_LEN = Curve::X.bit_length
|
579
|
+
|
580
|
+
P_MINUS_9_DIV_16 = (Curve::P**2 - 9) / 16
|
581
|
+
|
582
|
+
XNUM = [
|
583
|
+
Fq2.new([
|
584
|
+
0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6,
|
585
|
+
0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97d6]),
|
586
|
+
Fq2.new([
|
587
|
+
0x0,
|
588
|
+
0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71a]),
|
589
|
+
Fq2.new([
|
590
|
+
0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71e,
|
591
|
+
0x8ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38d]),
|
592
|
+
Fq2.new([
|
593
|
+
0x171d6541fa38ccfaed6dea691f5fb614cb14b4e7f4e810aa22d6108f142b85757098e38d0f671c7188e2aaaaaaaa5ed1,
|
594
|
+
0x0])
|
595
|
+
].freeze
|
596
|
+
XDEN = [
|
597
|
+
Fq2.new([
|
598
|
+
0x0,
|
599
|
+
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa63]),
|
600
|
+
Fq2.new([
|
601
|
+
0xc,
|
602
|
+
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa9f]),
|
603
|
+
Fq2::ONE,
|
604
|
+
Fq2::ZERO
|
605
|
+
].freeze
|
606
|
+
YNUM = [
|
607
|
+
Fq2.new([
|
608
|
+
0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706,
|
609
|
+
0x1530477c7ab4113b59a4c18b076d11930f7da5d4a07f649bf54439d87d27e500fc8c25ebf8c92f6812cfc71c71c6d706]),
|
610
|
+
Fq2.new([
|
611
|
+
0x0,
|
612
|
+
0x5c759507e8e333ebb5b7a9a47d7ed8532c52d39fd3a042a88b58423c50ae15d5c2638e343d9c71c6238aaaaaaaa97be]),
|
613
|
+
Fq2.new([
|
614
|
+
0x11560bf17baa99bc32126fced787c88f984f87adf7ae0c7f9a208c6b4f20a4181472aaa9cb8d555526a9ffffffffc71c,
|
615
|
+
0x8ab05f8bdd54cde190937e76bc3e447cc27c3d6fbd7063fcd104635a790520c0a395554e5c6aaaa9354ffffffffe38f]),
|
616
|
+
Fq2.new([
|
617
|
+
0x124c9ad43b6cf79bfbf7043de3811ad0761b0f37a1e26286b0e977c69aa274524e79097a56dc4bd9e1b371c71c718b10,
|
618
|
+
0x0])
|
619
|
+
].freeze
|
620
|
+
YDEN = [
|
621
|
+
Fq2.new([
|
622
|
+
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb,
|
623
|
+
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa8fb]),
|
624
|
+
Fq2.new([
|
625
|
+
0x0,
|
626
|
+
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffa9d3]),
|
627
|
+
Fq2.new([
|
628
|
+
0x12,
|
629
|
+
0x1a0111ea397fe69a4b1ba7b6434bacd764774b84f38512bf6730d2a0f6b0f6241eabfffeb153ffffb9feffffffffaa99]),
|
630
|
+
Fq2.new([0x1, 0x0])
|
631
|
+
].freeze
|
632
|
+
|
633
|
+
ISOGENY_COEFFICIENTS = [XNUM, XDEN, YNUM, YDEN]
|
634
|
+
|
635
|
+
module_function
|
636
|
+
|
637
|
+
def psi(x, y)
|
638
|
+
x2 = WSQ_INV.multiply_by_fq2(x).frobenius_map(1).multiply(WSQ).coeffs[0].coeffs[0]
|
639
|
+
y2 = WCU_INV.multiply_by_fq2(y).frobenius_map(1).multiply(WCU).coeffs[0].coeffs[0]
|
640
|
+
[x2, y2]
|
641
|
+
end
|
642
|
+
|
643
|
+
def psi2(x, y)
|
644
|
+
[x * PSI2_C1, y.negate]
|
645
|
+
end
|
646
|
+
|
647
|
+
def miller_loop(ell, g1)
|
648
|
+
f12 = Fq12::ONE
|
649
|
+
p_x, p_y = g1
|
650
|
+
i = BLS_X_LEN - 2
|
651
|
+
j = 0
|
652
|
+
while i >= 0
|
653
|
+
f12 = f12.multiply_by_014(ell[j][0], ell[j][1] * p_x.value, ell[j][2] * p_y.value)
|
654
|
+
unless bit_get(Curve::X, i).zero?
|
655
|
+
j += 1
|
656
|
+
f12 = f12.multiply_by_014(ell[j][0], ell[j][1] * p_x.value, ell[j][2] * p_y.value)
|
657
|
+
end
|
658
|
+
f12 = f12.square unless i.zero?
|
659
|
+
i -= 1
|
660
|
+
j += 1
|
661
|
+
end
|
662
|
+
f12.conjugate
|
663
|
+
end
|
664
|
+
|
665
|
+
|
666
|
+
|
667
|
+
def sgn0(x)
|
668
|
+
x0, x1 = x.values
|
669
|
+
sign_0 = x0 % 2
|
670
|
+
zero_0 = x0 === 0
|
671
|
+
sign_1 = x1 % 2
|
672
|
+
sign_0 || (zero_0 && sign_1)
|
673
|
+
end
|
674
|
+
|
675
|
+
def sqrt_div_fq2(u, v)
|
676
|
+
uv7 = u * v**7
|
677
|
+
uv15 = uv7 * v**8
|
678
|
+
gamma = uv15**P_MINUS_9_DIV_16 * uv7
|
679
|
+
success = false
|
680
|
+
result = gamma
|
681
|
+
positive_roots_of_unity = Fq2::ROOTS_OF_UNITY[0...4]
|
682
|
+
positive_roots_of_unity.each do |root|
|
683
|
+
candidate = root * gamma
|
684
|
+
if (candidate**2 * v - u).zero? && !success
|
685
|
+
success = true
|
686
|
+
result = candidate
|
687
|
+
end
|
688
|
+
end
|
689
|
+
[success, result]
|
690
|
+
end
|
691
|
+
|
692
|
+
end
|