/src/blst_normal/src/e2.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright Supranational LLC |
3 | | * Licensed under the Apache License, Version 2.0, see LICENSE for details. |
4 | | * SPDX-License-Identifier: Apache-2.0 |
5 | | */ |
6 | | |
7 | | #include "point.h" |
8 | | #include "fields.h" |
9 | | #include "errors.h" |
10 | | |
11 | | /* |
12 | | * y^2 = x^3 + B |
13 | | */ |
14 | | static const vec384x B_E2 = { /* 4 + 4*i */ |
15 | | { TO_LIMB_T(0xaa270000000cfff3), TO_LIMB_T(0x53cc0032fc34000a), |
16 | | TO_LIMB_T(0x478fe97a6b0a807f), TO_LIMB_T(0xb1d37ebee6ba24d7), |
17 | | TO_LIMB_T(0x8ec9733bbf78ab2f), TO_LIMB_T(0x09d645513d83de7e) }, |
18 | | { TO_LIMB_T(0xaa270000000cfff3), TO_LIMB_T(0x53cc0032fc34000a), |
19 | | TO_LIMB_T(0x478fe97a6b0a807f), TO_LIMB_T(0xb1d37ebee6ba24d7), |
20 | | TO_LIMB_T(0x8ec9733bbf78ab2f), TO_LIMB_T(0x09d645513d83de7e) } |
21 | | }; |
22 | | |
23 | | const POINTonE2 BLS12_381_G2 = { /* generator point [in Montgomery] */ |
24 | | { /* (0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02 |
25 | | b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8 << 384) % P */ |
26 | | { TO_LIMB_T(0xf5f28fa202940a10), TO_LIMB_T(0xb3f5fb2687b4961a), |
27 | | TO_LIMB_T(0xa1a893b53e2ae580), TO_LIMB_T(0x9894999d1a3caee9), |
28 | | TO_LIMB_T(0x6f67b7631863366b), TO_LIMB_T(0x058191924350bcd7) }, |
29 | | /* (0x13e02b6052719f607dacd3a088274f65596bd0d09920b61a |
30 | | b5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e << 384) % P */ |
31 | | { TO_LIMB_T(0xa5a9c0759e23f606), TO_LIMB_T(0xaaa0c59dbccd60c3), |
32 | | TO_LIMB_T(0x3bb17e18e2867806), TO_LIMB_T(0x1b1ab6cc8541b367), |
33 | | TO_LIMB_T(0xc2b6ed0ef2158547), TO_LIMB_T(0x11922a097360edf3) } |
34 | | }, |
35 | | { /* (0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a7 |
36 | | 6d429a695160d12c923ac9cc3baca289e193548608b82801 << 384) % P */ |
37 | | { TO_LIMB_T(0x4c730af860494c4a), TO_LIMB_T(0x597cfa1f5e369c5a), |
38 | | TO_LIMB_T(0xe7e6856caa0a635a), TO_LIMB_T(0xbbefb5e96e0d495f), |
39 | | TO_LIMB_T(0x07d3a975f0ef25a2), TO_LIMB_T(0x0083fd8e7e80dae5) }, |
40 | | /* (0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af |
41 | | 267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be << 384) % P */ |
42 | | { TO_LIMB_T(0xadc0fc92df64b05d), TO_LIMB_T(0x18aa270a2b1461dc), |
43 | | TO_LIMB_T(0x86adac6a3be4eba0), TO_LIMB_T(0x79495c4ec93da33a), |
44 | | TO_LIMB_T(0xe7175850a43ccaed), TO_LIMB_T(0x0b2bc2a163de1bf2) }, |
45 | | }, |
46 | | { { ONE_MONT_P }, { 0 } } |
47 | | }; |
48 | | |
49 | | const POINTonE2 BLS12_381_NEG_G2 = { /* negative generator [in Montgomery] */ |
50 | | { /* (0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02 |
51 | | b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8 << 384) % P */ |
52 | | { TO_LIMB_T(0xf5f28fa202940a10), TO_LIMB_T(0xb3f5fb2687b4961a), |
53 | | TO_LIMB_T(0xa1a893b53e2ae580), TO_LIMB_T(0x9894999d1a3caee9), |
54 | | TO_LIMB_T(0x6f67b7631863366b), TO_LIMB_T(0x058191924350bcd7) }, |
55 | | /* (0x13e02b6052719f607dacd3a088274f65596bd0d09920b61a |
56 | | b5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e << 384) % P */ |
57 | | { TO_LIMB_T(0xa5a9c0759e23f606), TO_LIMB_T(0xaaa0c59dbccd60c3), |
58 | | TO_LIMB_T(0x3bb17e18e2867806), TO_LIMB_T(0x1b1ab6cc8541b367), |
59 | | TO_LIMB_T(0xc2b6ed0ef2158547), TO_LIMB_T(0x11922a097360edf3) } |
60 | | }, |
61 | | { /* (0x0d1b3cc2c7027888be51d9ef691d77bcb679afda66c73f17 |
62 | | f9ee3837a55024f78c71363275a75d75d86bab79f74782aa << 384) % P */ |
63 | | { TO_LIMB_T(0x6d8bf5079fb65e61), TO_LIMB_T(0xc52f05df531d63a5), |
64 | | TO_LIMB_T(0x7f4a4d344ca692c9), TO_LIMB_T(0xa887959b8577c95f), |
65 | | TO_LIMB_T(0x4347fe40525c8734), TO_LIMB_T(0x197d145bbaff0bb5) }, |
66 | | /* (0x13fa4d4a0ad8b1ce186ed5061789213d993923066dddaf10 |
67 | | 40bc3ff59f825c78df74f2d75467e25e0f55f8a00fa030ed << 384) % P */ |
68 | | { TO_LIMB_T(0x0c3e036d209afa4e), TO_LIMB_T(0x0601d8f4863f9e23), |
69 | | TO_LIMB_T(0xe0832636bacc0a84), TO_LIMB_T(0xeb2def362a476f84), |
70 | | TO_LIMB_T(0x64044f659f0ee1e9), TO_LIMB_T(0x0ed54f48d5a1caa7) } |
71 | | }, |
72 | | { { ONE_MONT_P }, { 0 } } |
73 | | }; |
74 | | |
75 | | static void mul_by_b_onE2(vec384x out, const vec384x in) |
76 | 2.64k | { |
77 | 2.64k | sub_fp(out[0], in[0], in[1]); |
78 | 2.64k | add_fp(out[1], in[0], in[1]); |
79 | 2.64k | lshift_fp(out[0], out[0], 2); |
80 | 2.64k | lshift_fp(out[1], out[1], 2); |
81 | 2.64k | } |
82 | | |
83 | | static void mul_by_4b_onE2(vec384x out, const vec384x in) |
84 | 0 | { |
85 | 0 | sub_fp(out[0], in[0], in[1]); |
86 | 0 | add_fp(out[1], in[0], in[1]); |
87 | 0 | lshift_fp(out[0], out[0], 4); |
88 | 0 | lshift_fp(out[1], out[1], 4); |
89 | 0 | } |
90 | | |
91 | | static void POINTonE2_cneg(POINTonE2 *p, bool_t cbit) |
92 | 198k | { cneg_fp2(p->Y, p->Y, cbit); } |
93 | | |
94 | | void blst_p2_cneg(POINTonE2 *a, int cbit) |
95 | 2.36k | { POINTonE2_cneg(a, is_zero(cbit) ^ 1); } |
96 | | |
97 | | static void POINTonE2_from_Jacobian(POINTonE2 *out, const POINTonE2 *in) |
98 | 4.76k | { |
99 | 4.76k | vec384x Z, ZZ; |
100 | 4.76k | limb_t inf = vec_is_zero(in->Z, sizeof(in->Z)); |
101 | | |
102 | 4.76k | reciprocal_fp2(Z, in->Z); /* 1/Z */ |
103 | | |
104 | 4.76k | sqr_fp2(ZZ, Z); |
105 | 4.76k | mul_fp2(out->X, in->X, ZZ); /* X = X/Z^2 */ |
106 | | |
107 | 4.76k | mul_fp2(ZZ, ZZ, Z); |
108 | 4.76k | mul_fp2(out->Y, in->Y, ZZ); /* Y = Y/Z^3 */ |
109 | | |
110 | 4.76k | vec_select(out->Z, in->Z, BLS12_381_G2.Z, |
111 | 4.76k | sizeof(BLS12_381_G2.Z), inf); /* Z = inf ? 0 : 1 */ |
112 | 4.76k | } |
113 | | |
114 | | void blst_p2_from_jacobian(POINTonE2 *out, const POINTonE2 *a) |
115 | 0 | { POINTonE2_from_Jacobian(out, a); } |
116 | | |
117 | | static void POINTonE2_to_affine(POINTonE2_affine *out, const POINTonE2 *in) |
118 | 7.67k | { |
119 | 7.67k | POINTonE2 p; |
120 | | |
121 | 7.67k | if (!vec_is_equal(in->Z, BLS12_381_Rx.p2, sizeof(in->Z))) { |
122 | 2.85k | POINTonE2_from_Jacobian(&p, in); |
123 | 2.85k | in = &p; |
124 | 2.85k | } |
125 | 7.67k | vec_copy(out, in, sizeof(*out)); |
126 | 7.67k | } |
127 | | |
128 | | void blst_p2_to_affine(POINTonE2_affine *out, const POINTonE2 *a) |
129 | 7.67k | { POINTonE2_to_affine(out, a); } |
130 | | |
131 | | void blst_p2_from_affine(POINTonE2 *out, const POINTonE2_affine *a) |
132 | 11.3k | { |
133 | 11.3k | vec_copy(out, a, sizeof(*a)); |
134 | 11.3k | vec_select(out->Z, a->X, BLS12_381_Rx.p2, sizeof(out->Z), |
135 | 11.3k | vec_is_zero(a, sizeof(*a))); |
136 | 11.3k | } |
137 | | |
138 | | static bool_t POINTonE2_affine_on_curve(const POINTonE2_affine *p) |
139 | 18.3k | { |
140 | 18.3k | vec384x XXX, YY; |
141 | | |
142 | 18.3k | sqr_fp2(XXX, p->X); |
143 | 18.3k | mul_fp2(XXX, XXX, p->X); /* X^3 */ |
144 | 18.3k | add_fp2(XXX, XXX, B_E2); /* X^3 + B */ |
145 | | |
146 | 18.3k | sqr_fp2(YY, p->Y); /* Y^2 */ |
147 | | |
148 | 18.3k | return vec_is_equal(XXX, YY, sizeof(XXX)); |
149 | 18.3k | } |
150 | | |
151 | | int blst_p2_affine_on_curve(const POINTonE2_affine *p) |
152 | 18.2k | { return (int)(POINTonE2_affine_on_curve(p) | vec_is_zero(p, sizeof(*p))); } |
153 | | |
154 | | static bool_t POINTonE2_on_curve(const POINTonE2 *p) |
155 | 2.64k | { |
156 | 2.64k | vec384x XXX, YY, BZ6; |
157 | 2.64k | limb_t inf = vec_is_zero(p->Z, sizeof(p->Z)); |
158 | | |
159 | 2.64k | sqr_fp2(BZ6, p->Z); |
160 | 2.64k | mul_fp2(BZ6, BZ6, p->Z); |
161 | 2.64k | sqr_fp2(XXX, BZ6); /* Z^6 */ |
162 | 2.64k | mul_by_b_onE2(BZ6, XXX); /* B*Z^6 */ |
163 | | |
164 | 2.64k | sqr_fp2(XXX, p->X); |
165 | 2.64k | mul_fp2(XXX, XXX, p->X); /* X^3 */ |
166 | 2.64k | add_fp2(XXX, XXX, BZ6); /* X^3 + B*Z^6 */ |
167 | | |
168 | 2.64k | sqr_fp2(YY, p->Y); /* Y^2 */ |
169 | | |
170 | 2.64k | return vec_is_equal(XXX, YY, sizeof(XXX)) | inf; |
171 | 2.64k | } |
172 | | |
173 | | int blst_p2_on_curve(const POINTonE2 *p) |
174 | 2.64k | { return (int)POINTonE2_on_curve(p); } |
175 | | |
176 | | static limb_t POINTonE2_affine_Serialize_BE(unsigned char out[192], |
177 | | const POINTonE2_affine *in) |
178 | 73 | { |
179 | 73 | vec384x temp; |
180 | | |
181 | 73 | from_fp(temp[1], in->X[1]); |
182 | 73 | be_bytes_from_limbs(out, temp[1], sizeof(temp[1])); |
183 | 73 | from_fp(temp[0], in->X[0]); |
184 | 73 | be_bytes_from_limbs(out + 48, temp[0], sizeof(temp[0])); |
185 | | |
186 | 73 | from_fp(temp[1], in->Y[1]); |
187 | 73 | be_bytes_from_limbs(out + 96, temp[1], sizeof(temp[1])); |
188 | 73 | from_fp(temp[0], in->Y[0]); |
189 | 73 | be_bytes_from_limbs(out + 144, temp[0], sizeof(temp[0])); |
190 | | |
191 | 73 | return sgn0_pty_mod_384x(temp, BLS12_381_P); |
192 | 73 | } |
193 | | |
194 | | void blst_p2_affine_serialize(unsigned char out[192], |
195 | | const POINTonE2_affine *in) |
196 | 42 | { |
197 | 42 | if (vec_is_zero(in->X, 2*sizeof(in->X))) { |
198 | 2 | bytes_zero(out, 192); |
199 | 2 | out[0] = 0x40; /* infinity bit */ |
200 | 40 | } else { |
201 | 40 | (void)POINTonE2_affine_Serialize_BE(out, in); |
202 | 40 | } |
203 | 42 | } |
204 | | |
205 | | static limb_t POINTonE2_Serialize_BE(unsigned char out[192], |
206 | | const POINTonE2 *in) |
207 | 33 | { |
208 | 33 | POINTonE2 p; |
209 | | |
210 | 33 | if (!vec_is_equal(in->Z, BLS12_381_Rx.p2, sizeof(in->Z))) { |
211 | 0 | POINTonE2_from_Jacobian(&p, in); |
212 | 0 | in = &p; |
213 | 0 | } |
214 | | |
215 | 33 | return POINTonE2_affine_Serialize_BE(out, (const POINTonE2_affine *)in); |
216 | 33 | } |
217 | | |
218 | | static void POINTonE2_Serialize(unsigned char out[192], const POINTonE2 *in) |
219 | 2.17k | { |
220 | 2.17k | if (vec_is_zero(in->Z, sizeof(in->Z))) { |
221 | 2.14k | bytes_zero(out, 192); |
222 | 2.14k | out[0] = 0x40; /* infinity bit */ |
223 | 2.14k | } else { |
224 | 33 | (void)POINTonE2_Serialize_BE(out, in); |
225 | 33 | } |
226 | 2.17k | } |
227 | | |
228 | | void blst_p2_serialize(unsigned char out[192], const POINTonE2 *in) |
229 | 2.17k | { POINTonE2_Serialize(out, in); } |
230 | | |
231 | | static limb_t POINTonE2_affine_Compress_BE(unsigned char out[96], |
232 | | const POINTonE2_affine *in) |
233 | 41 | { |
234 | 41 | vec384 temp; |
235 | | |
236 | 41 | from_fp(temp, in->X[1]); |
237 | 41 | be_bytes_from_limbs(out, temp, sizeof(temp)); |
238 | 41 | from_fp(temp, in->X[0]); |
239 | 41 | be_bytes_from_limbs(out + 48, temp, sizeof(temp)); |
240 | | |
241 | 41 | return sgn0_pty_mont_384x(in->Y, BLS12_381_P, p0); |
242 | 41 | } |
243 | | |
244 | | void blst_p2_affine_compress(unsigned char out[96], const POINTonE2_affine *in) |
245 | 162 | { |
246 | 162 | if (vec_is_zero(in->X, 2*sizeof(in->X))) { |
247 | 121 | bytes_zero(out, 96); |
248 | 121 | out[0] = 0xc0; /* compressed and infinity bits */ |
249 | 121 | } else { |
250 | 41 | limb_t sign = POINTonE2_affine_Compress_BE(out, in); |
251 | 41 | out[0] |= (unsigned char)(0x80 | ((sign & 2) << 4)); |
252 | 41 | } |
253 | 162 | } |
254 | | |
255 | | static limb_t POINTonE2_Compress_BE(unsigned char out[96], |
256 | | const POINTonE2 *in) |
257 | 0 | { |
258 | 0 | POINTonE2 p; |
259 | |
|
260 | 0 | if (!vec_is_equal(in->Z, BLS12_381_Rx.p, sizeof(in->Z))) { |
261 | 0 | POINTonE2_from_Jacobian(&p, in); |
262 | 0 | in = &p; |
263 | 0 | } |
264 | |
|
265 | 0 | return POINTonE2_affine_Compress_BE(out, (const POINTonE2_affine *)in); |
266 | 0 | } |
267 | | |
268 | | void blst_p2_compress(unsigned char out[96], const POINTonE2 *in) |
269 | 0 | { |
270 | 0 | if (vec_is_zero(in->Z, sizeof(in->Z))) { |
271 | 0 | bytes_zero(out, 96); |
272 | 0 | out[0] = 0xc0; /* compressed and infinity bits */ |
273 | 0 | } else { |
274 | 0 | limb_t sign = POINTonE2_Compress_BE(out, in); |
275 | 0 | out[0] |= (unsigned char)(0x80 | ((sign & 2) << 4)); |
276 | 0 | } |
277 | 0 | } |
278 | | |
279 | | static limb_t POINTonE2_Uncompress_BE(POINTonE2_affine *out, |
280 | | const unsigned char in[96]) |
281 | 175 | { |
282 | 175 | POINTonE2_affine ret; |
283 | 175 | vec384 temp; |
284 | | |
285 | 175 | limbs_from_be_bytes(ret.X[1], in, sizeof(ret.X[1])); |
286 | 175 | limbs_from_be_bytes(ret.X[0], in + 48, sizeof(ret.X[0])); |
287 | | |
288 | | /* clear top 3 bits in case caller was conveying some information there */ |
289 | 175 | ret.X[1][sizeof(ret.X[1])/sizeof(limb_t)-1] &= ((limb_t)0-1) >> 3; |
290 | 175 | add_fp(temp, ret.X[1], ZERO_384); /* less than modulus? */ |
291 | 175 | if (!vec_is_equal(temp, ret.X[1], sizeof(temp))) |
292 | 20 | return (limb_t)0 - BLST_BAD_ENCODING; |
293 | | |
294 | 155 | add_fp(temp, ret.X[0], ZERO_384); /* less than modulus? */ |
295 | 155 | if (!vec_is_equal(temp, ret.X[0], sizeof(temp))) |
296 | 20 | return (limb_t)0 - BLST_BAD_ENCODING; |
297 | | |
298 | 135 | mul_fp(ret.X[0], ret.X[0], BLS12_381_RR); |
299 | 135 | mul_fp(ret.X[1], ret.X[1], BLS12_381_RR); |
300 | | |
301 | 135 | sqr_fp2(ret.Y, ret.X); |
302 | 135 | mul_fp2(ret.Y, ret.Y, ret.X); |
303 | 135 | add_fp2(ret.Y, ret.Y, B_E2); /* X^3 + B */ |
304 | 135 | if (!sqrt_fp2(ret.Y, ret.Y)) |
305 | 23 | return (limb_t)0 - BLST_POINT_NOT_ON_CURVE; |
306 | | |
307 | 112 | vec_copy(out, &ret, sizeof(ret)); |
308 | | |
309 | 112 | return sgn0_pty_mont_384x(out->Y, BLS12_381_P, p0); |
310 | 135 | } |
311 | | |
312 | | static BLST_ERROR POINTonE2_Uncompress_Z(POINTonE2_affine *out, |
313 | | const unsigned char in[96]) |
314 | 348 | { |
315 | 348 | unsigned char in0 = in[0]; |
316 | 348 | limb_t sgn0_pty; |
317 | | |
318 | 348 | if ((in0 & 0x80) == 0) /* compressed bit */ |
319 | 131 | return BLST_BAD_ENCODING; |
320 | | |
321 | 217 | if (in0 & 0x40) { /* infinity bit */ |
322 | 42 | if (byte_is_zero(in0 & 0x3f) & bytes_are_zero(in+1, 95)) { |
323 | 21 | vec_zero(out, sizeof(*out)); |
324 | 21 | return BLST_SUCCESS; |
325 | 21 | } else { |
326 | 21 | return BLST_BAD_ENCODING; |
327 | 21 | } |
328 | 42 | } |
329 | | |
330 | 175 | sgn0_pty = POINTonE2_Uncompress_BE(out, in); |
331 | | |
332 | 175 | if (sgn0_pty > 3) |
333 | 63 | return (BLST_ERROR)(0 - sgn0_pty); /* POINT_NOT_ON_CURVE */ |
334 | | |
335 | 112 | sgn0_pty >>= 1; /* skip over parity bit */ |
336 | 112 | sgn0_pty ^= (in0 & 0x20) >> 5; |
337 | 112 | cneg_fp2(out->Y, out->Y, sgn0_pty); |
338 | | |
339 | 112 | return BLST_SUCCESS; |
340 | 175 | } |
341 | | |
342 | | BLST_ERROR blst_p2_uncompress(POINTonE2_affine *out, const unsigned char in[96]) |
343 | 289 | { return POINTonE2_Uncompress_Z(out, in); } |
344 | | |
345 | | static BLST_ERROR POINTonE2_Deserialize_BE(POINTonE2_affine *out, |
346 | | const unsigned char in[192]) |
347 | 155 | { |
348 | 155 | POINTonE2_affine ret; |
349 | 155 | vec384 temp; |
350 | | |
351 | 155 | limbs_from_be_bytes(ret.X[1], in, sizeof(ret.X[1])); |
352 | 155 | limbs_from_be_bytes(ret.X[0], in + 48, sizeof(ret.X[0])); |
353 | 155 | limbs_from_be_bytes(ret.Y[1], in + 96, sizeof(ret.Y[1])); |
354 | 155 | limbs_from_be_bytes(ret.Y[0], in + 144, sizeof(ret.Y[0])); |
355 | | |
356 | | /* clear top 3 bits in case caller was conveying some information there */ |
357 | 155 | ret.X[1][sizeof(ret.X[1])/sizeof(limb_t)-1] &= ((limb_t)0-1) >> 3; |
358 | 155 | add_fp(temp, ret.X[1], ZERO_384); /* less than modulus? */ |
359 | 155 | if (!vec_is_equal(temp, ret.X[1], sizeof(temp))) |
360 | 11 | return BLST_BAD_ENCODING; |
361 | | |
362 | 144 | add_fp(temp, ret.X[0], ZERO_384); /* less than modulus? */ |
363 | 144 | if (!vec_is_equal(temp, ret.X[0], sizeof(temp))) |
364 | 16 | return BLST_BAD_ENCODING; |
365 | | |
366 | 128 | add_fp(temp, ret.Y[1], ZERO_384); /* less than modulus? */ |
367 | 128 | if (!vec_is_equal(temp, ret.Y[1], sizeof(temp))) |
368 | 21 | return BLST_BAD_ENCODING; |
369 | | |
370 | 107 | add_fp(temp, ret.Y[0], ZERO_384); /* less than modulus? */ |
371 | 107 | if (!vec_is_equal(temp, ret.Y[0], sizeof(temp))) |
372 | 21 | return BLST_BAD_ENCODING; |
373 | | |
374 | 86 | mul_fp(ret.X[0], ret.X[0], BLS12_381_RR); |
375 | 86 | mul_fp(ret.X[1], ret.X[1], BLS12_381_RR); |
376 | 86 | mul_fp(ret.Y[0], ret.Y[0], BLS12_381_RR); |
377 | 86 | mul_fp(ret.Y[1], ret.Y[1], BLS12_381_RR); |
378 | | |
379 | 86 | if (!POINTonE2_affine_on_curve(&ret)) |
380 | 66 | return BLST_POINT_NOT_ON_CURVE; |
381 | | |
382 | 20 | vec_copy(out, &ret, sizeof(ret)); |
383 | | |
384 | 20 | return BLST_SUCCESS; |
385 | 86 | } |
386 | | |
387 | | static BLST_ERROR POINTonE2_Deserialize_Z(POINTonE2_affine *out, |
388 | | const unsigned char in[192]) |
389 | 2.40k | { |
390 | 2.40k | unsigned char in0 = in[0]; |
391 | | |
392 | 2.40k | if ((in0 & 0xe0) == 0) |
393 | 155 | return POINTonE2_Deserialize_BE(out, in); |
394 | | |
395 | 2.24k | if (in0 & 0x80) /* compressed bit */ |
396 | 59 | return POINTonE2_Uncompress_Z(out, in); |
397 | | |
398 | 2.18k | if (in0 & 0x40) { /* infinity bit */ |
399 | 2.16k | if (byte_is_zero(in0 & 0x3f) & bytes_are_zero(in+1, 191)) { |
400 | 2.14k | vec_zero(out, sizeof(*out)); |
401 | 2.14k | return BLST_SUCCESS; |
402 | 2.14k | } |
403 | 2.16k | } |
404 | | |
405 | 43 | return BLST_BAD_ENCODING; |
406 | 2.18k | } |
407 | | |
408 | | BLST_ERROR blst_p2_deserialize(POINTonE2_affine *out, |
409 | | const unsigned char in[192]) |
410 | 225 | { return POINTonE2_Deserialize_Z(out, in); } |
411 | | |
412 | | #include "ec_ops.h" |
413 | | POINT_DADD_IMPL(POINTonE2, 384x, fp2) |
414 | | POINT_DADD_AFFINE_IMPL_A0(POINTonE2, 384x, fp2, BLS12_381_Rx.p2) |
415 | | POINT_ADD_IMPL(POINTonE2, 384x, fp2) |
416 | | POINT_ADD_AFFINE_IMPL(POINTonE2, 384x, fp2, BLS12_381_Rx.p2) |
417 | | POINT_DOUBLE_IMPL_A0(POINTonE2, 384x, fp2) |
418 | | POINT_IS_EQUAL_IMPL(POINTonE2, 384x, fp2) |
419 | | |
420 | | void blst_p2_add(POINTonE2 *out, const POINTonE2 *a, const POINTonE2 *b) |
421 | 0 | { POINTonE2_add(out, a, b); } |
422 | | |
423 | | void blst_p2_add_or_double(POINTonE2 *out, const POINTonE2 *a, |
424 | | const POINTonE2 *b) |
425 | 0 | { POINTonE2_dadd(out, a, b, NULL); } |
426 | | |
427 | | void blst_p2_add_affine(POINTonE2 *out, const POINTonE2 *a, |
428 | | const POINTonE2_affine *b) |
429 | 0 | { POINTonE2_add_affine(out, a, b); } |
430 | | |
431 | | void blst_p2_add_or_double_affine(POINTonE2 *out, const POINTonE2 *a, |
432 | | const POINTonE2_affine *b) |
433 | 2.60k | { POINTonE2_dadd_affine(out, a, b); } |
434 | | |
435 | | void blst_p2_double(POINTonE2 *out, const POINTonE2 *a) |
436 | 63 | { POINTonE2_double(out, a); } |
437 | | |
438 | | int blst_p2_is_equal(const POINTonE2 *a, const POINTonE2 *b) |
439 | 2.74k | { return (int)POINTonE2_is_equal(a, b); } |
440 | | |
441 | | #include "ec_mult.h" |
442 | | POINT_MULT_SCALAR_WX_IMPL(POINTonE2, 4) |
443 | | POINT_MULT_SCALAR_WX_IMPL(POINTonE2, 5) |
444 | | |
445 | | #ifdef __BLST_PRIVATE_TESTMODE__ |
446 | | POINT_AFFINE_MULT_SCALAR_IMPL(POINTonE2) |
447 | | |
448 | | DECLARE_PRIVATE_POINTXZ(POINTonE2, 384x) |
449 | | POINT_LADDER_PRE_IMPL(POINTonE2, 384x, fp2) |
450 | | POINT_LADDER_STEP_IMPL_A0(POINTonE2, 384x, fp2, onE2) |
451 | | POINT_LADDER_POST_IMPL_A0(POINTonE2, 384x, fp2, onE2) |
452 | | POINT_MULT_SCALAR_LADDER_IMPL(POINTonE2) |
453 | | #endif |
454 | | |
455 | | static void psi(POINTonE2 *out, const POINTonE2 *in) |
456 | 106k | { |
457 | 106k | static const vec384x frobenius_x = { /* 1/(1 + i)^((P-1)/3) */ |
458 | 106k | { 0 }, |
459 | 106k | { /* (0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4 |
460 | | 897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad << 384) % P */ |
461 | 106k | TO_LIMB_T(0x890dc9e4867545c3), TO_LIMB_T(0x2af322533285a5d5), |
462 | 106k | TO_LIMB_T(0x50880866309b7e2c), TO_LIMB_T(0xa20d1b8c7e881024), |
463 | 106k | TO_LIMB_T(0x14e4f04fe2db9068), TO_LIMB_T(0x14e56d3f1564853a) } |
464 | 106k | }; |
465 | 106k | static const vec384x frobenius_y = { /* 1/(1 + i)^((P-1)/2) */ |
466 | 106k | { /* (0x135203e60180a68ee2e9c448d77a2cd91c3dedd930b1cf60 |
467 | | ef396489f61eb45e304466cf3e67fa0af1ee7b04121bdea2 << 384) % P */ |
468 | 106k | TO_LIMB_T(0x3e2f585da55c9ad1), TO_LIMB_T(0x4294213d86c18183), |
469 | 106k | TO_LIMB_T(0x382844c88b623732), TO_LIMB_T(0x92ad2afd19103e18), |
470 | 106k | TO_LIMB_T(0x1d794e4fac7cf0b9), TO_LIMB_T(0x0bd592fc7d825ec8) }, |
471 | 106k | { /* (0x06af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e |
472 | | 77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09 << 384) % P */ |
473 | 106k | TO_LIMB_T(0x7bcfa7a25aa30fda), TO_LIMB_T(0xdc17dec12a927e7c), |
474 | 106k | TO_LIMB_T(0x2f088dd86b4ebef1), TO_LIMB_T(0xd1ca2087da74d4a7), |
475 | 106k | TO_LIMB_T(0x2da2596696cebc1d), TO_LIMB_T(0x0e2b7eedbbfd87d2) }, |
476 | 106k | }; |
477 | | |
478 | 106k | vec_copy(out, in, sizeof(*out)); |
479 | 106k | cneg_fp(out->X[1], out->X[1], 1); mul_fp2(out->X, out->X, frobenius_x); |
480 | 106k | cneg_fp(out->Y[1], out->Y[1], 1); mul_fp2(out->Y, out->Y, frobenius_y); |
481 | 106k | cneg_fp(out->Z[1], out->Z[1], 1); |
482 | 106k | } |
483 | | |
484 | | /* Galbraith-Lin-Scott, ~67% faster than POINTonE2_mul_w5 */ |
485 | | static void POINTonE2_mult_gls(POINTonE2 *out, const POINTonE2 *in, |
486 | | const pow256 SK) |
487 | 1.74k | { |
488 | 1.74k | union { vec256 l; pow256 s; } val; |
489 | | |
490 | | /* break down SK to "digits" with |z| as radix [in constant time] */ |
491 | | |
492 | 1.74k | limbs_from_le_bytes(val.l, SK, 32); |
493 | 1.74k | div_by_zz(val.l); |
494 | 1.74k | div_by_z(val.l); |
495 | 1.74k | div_by_z(val.l + NLIMBS(256)/2); |
496 | 1.74k | le_bytes_from_limbs(val.s, val.l, 32); |
497 | | |
498 | 1.74k | { |
499 | 1.74k | const byte *scalars[2] = { val.s, NULL }; |
500 | 1.74k | POINTonE2 table[4][1<<(5-1)]; /* 18KB */ |
501 | 1.74k | size_t i; |
502 | | |
503 | 1.74k | POINTonE2_precompute_w5(table[0], in); |
504 | 29.6k | for (i = 0; i < 1<<(5-1); i++) { |
505 | 27.9k | psi(&table[1][i], &table[0][i]); |
506 | 27.9k | psi(&table[2][i], &table[1][i]); |
507 | 27.9k | psi(&table[3][i], &table[2][i]); |
508 | 27.9k | POINTonE2_cneg(&table[1][i], 1); /* account for z being negative */ |
509 | 27.9k | POINTonE2_cneg(&table[3][i], 1); |
510 | 27.9k | } |
511 | | |
512 | 1.74k | POINTonE2s_mult_w5(out, NULL, 4, scalars, 64, table); |
513 | 1.74k | } |
514 | | |
515 | 1.74k | vec_zero(val.l, sizeof(val)); /* scrub the copy of SK */ |
516 | 1.74k | } |
517 | | |
518 | | static void POINTonE2_sign(POINTonE2 *out, const POINTonE2 *in, const pow256 SK) |
519 | 1.68k | { |
520 | 1.68k | vec384x Z, ZZ; |
521 | 1.68k | limb_t inf; |
522 | | |
523 | 1.68k | POINTonE2_mult_gls(out, in, SK); |
524 | | |
525 | | /* convert to affine to remove possible bias in out->Z */ |
526 | 1.68k | inf = vec_is_zero(out->Z, sizeof(out->Z)); |
527 | | #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
528 | | flt_reciprocal_fp2(Z, out->Z); /* 1/Z */ |
529 | | #else |
530 | 1.68k | reciprocal_fp2(Z, out->Z); /* 1/Z */ |
531 | 1.68k | #endif |
532 | | |
533 | 1.68k | sqr_fp2(ZZ, Z); |
534 | 1.68k | mul_fp2(out->X, out->X, ZZ); /* X = X/Z^2 */ |
535 | | |
536 | 1.68k | mul_fp2(ZZ, ZZ, Z); |
537 | 1.68k | mul_fp2(out->Y, out->Y, ZZ); /* Y = Y/Z^3 */ |
538 | | |
539 | 1.68k | vec_select(out->Z, out->Z, BLS12_381_G2.Z, sizeof(BLS12_381_G2.Z), |
540 | 1.68k | inf); /* Z = inf ? 0 : 1 */ |
541 | 1.68k | } |
542 | | |
543 | | void blst_sk_to_pk_in_g2(POINTonE2 *out, const pow256 SK) |
544 | 481 | { POINTonE2_sign(out, &BLS12_381_G2, SK); } |
545 | | |
546 | | void blst_sign_pk_in_g1(POINTonE2 *out, const POINTonE2 *msg, const pow256 SK) |
547 | 1.20k | { POINTonE2_sign(out, msg, SK); } |
548 | | |
549 | | void blst_sk_to_pk2_in_g2(unsigned char out[192], POINTonE2_affine *PK, |
550 | | const pow256 SK) |
551 | 0 | { |
552 | 0 | POINTonE2 P[1]; |
553 | |
|
554 | 0 | POINTonE2_sign(P, &BLS12_381_G2, SK); |
555 | 0 | if (PK != NULL) |
556 | 0 | vec_copy(PK, P, sizeof(*PK)); |
557 | 0 | if (out != NULL) { |
558 | 0 | limb_t sgn0_pty = POINTonE2_Serialize_BE(out, P); |
559 | 0 | out[0] |= (sgn0_pty & 2) << 4; /* pre-decorate */ |
560 | 0 | out[0] |= vec_is_zero(P->Z, sizeof(P->Z)) << 6; |
561 | 0 | } |
562 | 0 | } |
563 | | |
564 | | void blst_sign_pk2_in_g1(unsigned char out[192], POINTonE2_affine *sig, |
565 | | const POINTonE2 *hash, const pow256 SK) |
566 | 0 | { |
567 | 0 | POINTonE2 P[1]; |
568 | |
|
569 | 0 | POINTonE2_sign(P, hash, SK); |
570 | 0 | if (sig != NULL) |
571 | 0 | vec_copy(sig, P, sizeof(*sig)); |
572 | 0 | if (out != NULL) { |
573 | 0 | limb_t sgn0_pty = POINTonE2_Serialize_BE(out, P); |
574 | 0 | out[0] |= (sgn0_pty & 2) << 4; /* pre-decorate */ |
575 | 0 | out[0] |= vec_is_zero(P->Z, sizeof(P->Z)) << 6; |
576 | 0 | } |
577 | 0 | } |
578 | | |
579 | | void blst_p2_mult(POINTonE2 *out, const POINTonE2 *a, |
580 | | const byte *scalar, size_t nbits) |
581 | 480 | { |
582 | 480 | if (nbits < 144) { |
583 | 231 | if (nbits) |
584 | 184 | POINTonE2_mult_w4(out, a, scalar, nbits); |
585 | 47 | else |
586 | 47 | vec_zero(out, sizeof(*out)); |
587 | 249 | } else if (nbits <= 256) { |
588 | 103 | union { vec256 l; pow256 s; } val; |
589 | 103 | size_t i, j, top, mask = (size_t)0 - 1; |
590 | | |
591 | | /* this is not about constant-time-ness, but branch optimization */ |
592 | 3.39k | for (top = (nbits + 7)/8, i=0, j=0; i<sizeof(val.s);) { |
593 | 3.29k | val.s[i++] = scalar[j] & mask; |
594 | 3.29k | mask = 0 - ((i - top) >> (8*sizeof(top)-1)); |
595 | 3.29k | j += 1 & mask; |
596 | 3.29k | } |
597 | | |
598 | 103 | if (check_mod_256(val.s, BLS12_381_r)) /* z^4 is the formal limit */ |
599 | 61 | POINTonE2_mult_gls(out, a, val.s); |
600 | 42 | else /* should never be the case, added for formal completeness */ |
601 | 42 | POINTonE2_mult_w5(out, a, scalar, nbits); |
602 | | |
603 | 103 | vec_zero(val.l, sizeof(val)); |
604 | 146 | } else { /* should never be the case, added for formal completeness */ |
605 | 146 | POINTonE2_mult_w5(out, a, scalar, nbits); |
606 | 146 | } |
607 | 480 | } |
608 | | |
609 | | void blst_p2_unchecked_mult(POINTonE2 *out, const POINTonE2 *a, |
610 | | const byte *scalar, size_t nbits) |
611 | 0 | { |
612 | 0 | if (nbits) |
613 | 0 | POINTonE2_mult_w4(out, a, scalar, nbits); |
614 | 0 | else |
615 | 0 | vec_zero(out, sizeof(*out)); |
616 | 0 | } |
617 | | |
618 | | int blst_p2_affine_is_equal(const POINTonE2_affine *a, |
619 | | const POINTonE2_affine *b) |
620 | 0 | { return (int)vec_is_equal(a, b, sizeof(*a)); } |
621 | | |
622 | | int blst_p2_is_inf(const POINTonE2 *p) |
623 | 0 | { return (int)vec_is_zero(p->Z, sizeof(p->Z)); } |
624 | | |
625 | | const POINTonE2 *blst_p2_generator(void) |
626 | 0 | { return &BLS12_381_G2; } |
627 | | |
628 | | int blst_p2_affine_is_inf(const POINTonE2_affine *p) |
629 | 0 | { return (int)vec_is_zero(p, sizeof(*p)); } |
630 | | |
631 | | const POINTonE2_affine *blst_p2_affine_generator(void) |
632 | 0 | { return (const POINTonE2_affine *)&BLS12_381_G2; } |
633 | | |
634 | | size_t blst_p2_sizeof(void) |
635 | 0 | { return sizeof(POINTonE2); } |
636 | | |
637 | | size_t blst_p2_affine_sizeof(void) |
638 | 0 | { return sizeof(POINTonE2_affine); } |