/src/blst_normal/src/e1.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 vec384 B_E1 = { /* (4 << 384) % P */ |
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 | | }; |
19 | | |
20 | | const POINTonE1 BLS12_381_G1 = { /* generator point [in Montgomery] */ |
21 | | /* (0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905 |
22 | | * a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb << 384) % P */ |
23 | | { TO_LIMB_T(0x5cb38790fd530c16), TO_LIMB_T(0x7817fc679976fff5), |
24 | | TO_LIMB_T(0x154f95c7143ba1c1), TO_LIMB_T(0xf0ae6acdf3d0e747), |
25 | | TO_LIMB_T(0xedce6ecc21dbf440), TO_LIMB_T(0x120177419e0bfb75) }, |
26 | | /* (0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af6 |
27 | | * 00db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1 << 384) % P */ |
28 | | { TO_LIMB_T(0xbaac93d50ce72271), TO_LIMB_T(0x8c22631a7918fd8e), |
29 | | TO_LIMB_T(0xdd595f13570725ce), TO_LIMB_T(0x51ac582950405194), |
30 | | TO_LIMB_T(0x0e1c8c3fad0059c0), TO_LIMB_T(0x0bbc3efc5008a26a) }, |
31 | | { ONE_MONT_P } |
32 | | }; |
33 | | |
34 | | const POINTonE1 BLS12_381_NEG_G1 = { /* negative generator [in Montgomery] */ |
35 | | /* (0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905 |
36 | | * a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb << 384) % P */ |
37 | | { TO_LIMB_T(0x5cb38790fd530c16), TO_LIMB_T(0x7817fc679976fff5), |
38 | | TO_LIMB_T(0x154f95c7143ba1c1), TO_LIMB_T(0xf0ae6acdf3d0e747), |
39 | | TO_LIMB_T(0xedce6ecc21dbf440), TO_LIMB_T(0x120177419e0bfb75) }, |
40 | | /* (0x114d1d6855d545a8aa7d76c8cf2e21f267816aef1db507c9 |
41 | | * 6655b9d5caac42364e6f38ba0ecb751bad54dcd6b939c2ca << 384) % P */ |
42 | | { TO_LIMB_T(0xff526c2af318883a), TO_LIMB_T(0x92899ce4383b0270), |
43 | | TO_LIMB_T(0x89d7738d9fa9d055), TO_LIMB_T(0x12caf35ba344c12a), |
44 | | TO_LIMB_T(0x3cff1b76964b5317), TO_LIMB_T(0x0e44d2ede9774430) }, |
45 | | { ONE_MONT_P } |
46 | | }; |
47 | | |
48 | | static inline void mul_by_b_onE1(vec384 out, const vec384 in) |
49 | 7.23k | { lshift_fp(out, in, 2); } |
50 | | |
51 | | static inline void mul_by_4b_onE1(vec384 out, const vec384 in) |
52 | 0 | { lshift_fp(out, in, 4); } |
53 | | |
54 | | static void POINTonE1_cneg(POINTonE1 *p, bool_t cbit) |
55 | 311k | { cneg_fp(p->Y, p->Y, cbit); } |
56 | | |
57 | | void blst_p1_cneg(POINTonE1 *a, int cbit) |
58 | 2.79k | { POINTonE1_cneg(a, is_zero(cbit) ^ 1); } |
59 | | |
60 | | static void POINTonE1_from_Jacobian(POINTonE1 *out, const POINTonE1 *in) |
61 | 4.10k | { |
62 | 4.10k | vec384 Z, ZZ; |
63 | 4.10k | limb_t inf = vec_is_zero(in->Z, sizeof(in->Z)); |
64 | | |
65 | 4.10k | reciprocal_fp(Z, in->Z); /* 1/Z */ |
66 | | |
67 | 4.10k | sqr_fp(ZZ, Z); |
68 | 4.10k | mul_fp(out->X, in->X, ZZ); /* X = X/Z^2 */ |
69 | | |
70 | 4.10k | mul_fp(ZZ, ZZ, Z); |
71 | 4.10k | mul_fp(out->Y, in->Y, ZZ); /* Y = Y/Z^3 */ |
72 | | |
73 | 4.10k | vec_select(out->Z, in->Z, BLS12_381_G1.Z, |
74 | 4.10k | sizeof(BLS12_381_G1.Z), inf); /* Z = inf ? 0 : 1 */ |
75 | 4.10k | } |
76 | | |
77 | | void blst_p1_from_jacobian(POINTonE1 *out, const POINTonE1 *a) |
78 | 0 | { POINTonE1_from_Jacobian(out, a); } |
79 | | |
80 | | static void POINTonE1_to_affine(POINTonE1_affine *out, const POINTonE1 *in) |
81 | 9.87k | { |
82 | 9.87k | POINTonE1 p; |
83 | | |
84 | 9.87k | if (!vec_is_equal(in->Z, BLS12_381_Rx.p, sizeof(in->Z))) { |
85 | 4.10k | POINTonE1_from_Jacobian(&p, in); |
86 | 4.10k | in = &p; |
87 | 4.10k | } |
88 | 9.87k | vec_copy(out, in, sizeof(*out)); |
89 | 9.87k | } |
90 | | |
91 | | void blst_p1_to_affine(POINTonE1_affine *out, const POINTonE1 *a) |
92 | 9.87k | { POINTonE1_to_affine(out, a); } |
93 | | |
94 | | void blst_p1_from_affine(POINTonE1 *out, const POINTonE1_affine *a) |
95 | 2.47k | { |
96 | 2.47k | vec_copy(out, a, sizeof(*a)); |
97 | 2.47k | vec_select(out->Z, a->X, BLS12_381_Rx.p, sizeof(out->Z), |
98 | 2.47k | vec_is_zero(a, sizeof(*a))); |
99 | 2.47k | } |
100 | | |
101 | | static bool_t POINTonE1_affine_on_curve(const POINTonE1_affine *p) |
102 | 19.0k | { |
103 | 19.0k | vec384 XXX, YY; |
104 | | |
105 | 19.0k | sqr_fp(XXX, p->X); |
106 | 19.0k | mul_fp(XXX, XXX, p->X); /* X^3 */ |
107 | 19.0k | add_fp(XXX, XXX, B_E1); /* X^3 + B */ |
108 | | |
109 | 19.0k | sqr_fp(YY, p->Y); /* Y^2 */ |
110 | | |
111 | 19.0k | return vec_is_equal(XXX, YY, sizeof(XXX)); |
112 | 19.0k | } |
113 | | |
114 | | int blst_p1_affine_on_curve(const POINTonE1_affine *p) |
115 | 18.9k | { return (int)(POINTonE1_affine_on_curve(p) | vec_is_zero(p, sizeof(*p))); } |
116 | | |
117 | | static bool_t POINTonE1_on_curve(const POINTonE1 *p) |
118 | 7.23k | { |
119 | 7.23k | vec384 XXX, YY, BZ6; |
120 | 7.23k | limb_t inf = vec_is_zero(p->Z, sizeof(p->Z)); |
121 | | |
122 | 7.23k | sqr_fp(BZ6, p->Z); |
123 | 7.23k | mul_fp(BZ6, BZ6, p->Z); |
124 | 7.23k | sqr_fp(BZ6, BZ6); /* Z^6 */ |
125 | 7.23k | mul_by_b_onE1(BZ6, BZ6); /* B*Z^6 */ |
126 | | |
127 | 7.23k | sqr_fp(XXX, p->X); |
128 | 7.23k | mul_fp(XXX, XXX, p->X); /* X^3 */ |
129 | 7.23k | add_fp(XXX, XXX, BZ6); /* X^3 + B*Z^6 */ |
130 | | |
131 | 7.23k | sqr_fp(YY, p->Y); /* Y^2 */ |
132 | | |
133 | 7.23k | return vec_is_equal(XXX, YY, sizeof(XXX)) | inf; |
134 | 7.23k | } |
135 | | |
136 | | int blst_p1_on_curve(const POINTonE1 *p) |
137 | 7.23k | { return (int)POINTonE1_on_curve(p); } |
138 | | |
139 | | static limb_t POINTonE1_affine_Serialize_BE(unsigned char out[96], |
140 | | const POINTonE1_affine *in) |
141 | 92 | { |
142 | 92 | vec384 temp; |
143 | | |
144 | 92 | from_fp(temp, in->X); |
145 | 92 | be_bytes_from_limbs(out, temp, sizeof(temp)); |
146 | | |
147 | 92 | from_fp(temp, in->Y); |
148 | 92 | be_bytes_from_limbs(out + 48, temp, sizeof(temp)); |
149 | | |
150 | 92 | return sgn0_pty_mod_384(temp, BLS12_381_P); |
151 | 92 | } |
152 | | |
153 | | void blst_p1_affine_serialize(unsigned char out[96], |
154 | | const POINTonE1_affine *in) |
155 | 40 | { |
156 | 40 | if (vec_is_zero(in->X, 2*sizeof(in->X))) { |
157 | 0 | bytes_zero(out, 96); |
158 | 0 | out[0] = 0x40; /* infinity bit */ |
159 | 40 | } else { |
160 | 40 | (void)POINTonE1_affine_Serialize_BE(out, in); |
161 | 40 | } |
162 | 40 | } |
163 | | |
164 | | static limb_t POINTonE1_Serialize_BE(unsigned char out[96], |
165 | | const POINTonE1 *in) |
166 | 52 | { |
167 | 52 | POINTonE1 p; |
168 | | |
169 | 52 | if (!vec_is_equal(in->Z, BLS12_381_Rx.p, sizeof(in->Z))) { |
170 | 0 | POINTonE1_from_Jacobian(&p, in); |
171 | 0 | in = &p; |
172 | 0 | } |
173 | | |
174 | 52 | return POINTonE1_affine_Serialize_BE(out, (const POINTonE1_affine *)in); |
175 | 52 | } |
176 | | |
177 | | static void POINTonE1_Serialize(unsigned char out[96], const POINTonE1 *in) |
178 | 2.47k | { |
179 | 2.47k | if (vec_is_zero(in->Z, sizeof(in->Z))) { |
180 | 2.42k | bytes_zero(out, 96); |
181 | 2.42k | out[0] = 0x40; /* infinity bit */ |
182 | 2.42k | } else { |
183 | 52 | (void)POINTonE1_Serialize_BE(out, in); |
184 | 52 | } |
185 | 2.47k | } |
186 | | |
187 | | void blst_p1_serialize(unsigned char out[96], const POINTonE1 *in) |
188 | 2.47k | { POINTonE1_Serialize(out, in); } |
189 | | |
190 | | static limb_t POINTonE1_affine_Compress_BE(unsigned char out[48], |
191 | | const POINTonE1_affine *in) |
192 | 40 | { |
193 | 40 | vec384 temp; |
194 | | |
195 | 40 | from_fp(temp, in->X); |
196 | 40 | be_bytes_from_limbs(out, temp, sizeof(temp)); |
197 | | |
198 | 40 | return sgn0_pty_mont_384(in->Y, BLS12_381_P, p0); |
199 | 40 | } |
200 | | |
201 | | void blst_p1_affine_compress(unsigned char out[48], const POINTonE1_affine *in) |
202 | 135 | { |
203 | 135 | if (vec_is_zero(in->X, 2*sizeof(in->X))) { |
204 | 95 | bytes_zero(out, 48); |
205 | 95 | out[0] = 0xc0; /* compressed and infinity bits */ |
206 | 95 | } else { |
207 | 40 | limb_t sign = POINTonE1_affine_Compress_BE(out, in); |
208 | 40 | out[0] |= (unsigned char)(0x80 | ((sign & 2) << 4)); |
209 | 40 | } |
210 | 135 | } |
211 | | |
212 | | static limb_t POINTonE1_Compress_BE(unsigned char out[48], |
213 | | const POINTonE1 *in) |
214 | 0 | { |
215 | 0 | POINTonE1 p; |
216 | |
|
217 | 0 | if (!vec_is_equal(in->Z, BLS12_381_Rx.p, sizeof(in->Z))) { |
218 | 0 | POINTonE1_from_Jacobian(&p, in); |
219 | 0 | in = &p; |
220 | 0 | } |
221 | |
|
222 | 0 | return POINTonE1_affine_Compress_BE(out, (const POINTonE1_affine *)in); |
223 | 0 | } |
224 | | |
225 | | void blst_p1_compress(unsigned char out[48], const POINTonE1 *in) |
226 | 0 | { |
227 | 0 | if (vec_is_zero(in->Z, sizeof(in->Z))) { |
228 | 0 | bytes_zero(out, 48); |
229 | 0 | out[0] = 0xc0; /* compressed and infinity bits */ |
230 | 0 | } else { |
231 | 0 | limb_t sign = POINTonE1_Compress_BE(out, in); |
232 | 0 | out[0] |= (unsigned char)(0x80 | ((sign & 2) << 4)); |
233 | 0 | } |
234 | 0 | } |
235 | | |
236 | | static limb_t POINTonE1_Uncompress_BE(POINTonE1_affine *out, |
237 | | const unsigned char in[48]) |
238 | 216 | { |
239 | 216 | POINTonE1_affine ret; |
240 | 216 | vec384 temp; |
241 | | |
242 | 216 | limbs_from_be_bytes(ret.X, in, sizeof(ret.X)); |
243 | | /* clear top 3 bits in case caller was conveying some information there */ |
244 | 216 | ret.X[sizeof(ret.X)/sizeof(limb_t)-1] &= ((limb_t)0-1) >> 3; |
245 | 216 | add_fp(temp, ret.X, ZERO_384); /* less than modulus? */ |
246 | 216 | if (!vec_is_equal(temp, ret.X, sizeof(temp))) |
247 | 21 | return (limb_t)0 - BLST_BAD_ENCODING; |
248 | 195 | mul_fp(ret.X, ret.X, BLS12_381_RR); |
249 | | |
250 | 195 | sqr_fp(ret.Y, ret.X); |
251 | 195 | mul_fp(ret.Y, ret.Y, ret.X); |
252 | 195 | add_fp(ret.Y, ret.Y, B_E1); /* X^3 + B */ |
253 | 195 | if (!sqrt_fp(ret.Y, ret.Y)) |
254 | 20 | return (limb_t)0 - BLST_POINT_NOT_ON_CURVE; |
255 | | |
256 | 175 | vec_copy(out, &ret, sizeof(ret)); |
257 | | |
258 | 175 | return sgn0_pty_mont_384(out->Y, BLS12_381_P, p0); |
259 | 195 | } |
260 | | |
261 | | static BLST_ERROR POINTonE1_Uncompress_Z(POINTonE1_affine *out, |
262 | | const unsigned char in[48]) |
263 | 481 | { |
264 | 481 | unsigned char in0 = in[0]; |
265 | 481 | limb_t sgn0_pty; |
266 | | |
267 | 481 | if ((in0 & 0x80) == 0) /* compressed bit */ |
268 | 213 | return BLST_BAD_ENCODING; |
269 | | |
270 | 268 | if (in0 & 0x40) { /* infinity bit */ |
271 | 52 | if (byte_is_zero(in0 & 0x3f) & bytes_are_zero(in+1, 47)) { |
272 | 20 | vec_zero(out, sizeof(*out)); |
273 | 20 | return BLST_SUCCESS; |
274 | 32 | } else { |
275 | 32 | return BLST_BAD_ENCODING; |
276 | 32 | } |
277 | 52 | } |
278 | | |
279 | 216 | sgn0_pty = POINTonE1_Uncompress_BE(out, in); |
280 | | |
281 | 216 | if (sgn0_pty > 3) |
282 | 41 | return (BLST_ERROR)(0 - sgn0_pty); /* POINT_NOT_ON_CURVE */ |
283 | | |
284 | 175 | sgn0_pty >>= 1; /* skip over parity bit */ |
285 | 175 | sgn0_pty ^= (in0 & 0x20) >> 5; |
286 | 175 | cneg_fp(out->Y, out->Y, sgn0_pty); |
287 | | |
288 | | /* (0,±2) is not in group, but application might want to ignore? */ |
289 | 175 | return vec_is_zero(out->X, sizeof(out->X)) ? BLST_POINT_NOT_IN_GROUP |
290 | 175 | : BLST_SUCCESS; |
291 | 216 | } |
292 | | |
293 | | BLST_ERROR blst_p1_uncompress(POINTonE1_affine *out, const unsigned char in[48]) |
294 | 364 | { return POINTonE1_Uncompress_Z(out, in); } |
295 | | |
296 | | static BLST_ERROR POINTonE1_Deserialize_BE(POINTonE1_affine *out, |
297 | | const unsigned char in[96]) |
298 | 172 | { |
299 | 172 | POINTonE1_affine ret; |
300 | 172 | vec384 temp; |
301 | | |
302 | 172 | limbs_from_be_bytes(ret.X, in, sizeof(ret.X)); |
303 | 172 | limbs_from_be_bytes(ret.Y, in + 48, sizeof(ret.Y)); |
304 | | |
305 | | /* clear top 3 bits in case caller was conveying some information there */ |
306 | 172 | ret.X[sizeof(ret.X)/sizeof(limb_t)-1] &= ((limb_t)0-1) >> 3; |
307 | 172 | add_fp(temp, ret.X, ZERO_384); /* less than modulus? */ |
308 | 172 | if (!vec_is_equal(temp, ret.X, sizeof(temp))) |
309 | 20 | return BLST_BAD_ENCODING; |
310 | | |
311 | 152 | add_fp(temp, ret.Y, ZERO_384); /* less than modulus? */ |
312 | 152 | if (!vec_is_equal(temp, ret.Y, sizeof(temp))) |
313 | 20 | return BLST_BAD_ENCODING; |
314 | | |
315 | 132 | mul_fp(ret.X, ret.X, BLS12_381_RR); |
316 | 132 | mul_fp(ret.Y, ret.Y, BLS12_381_RR); |
317 | | |
318 | 132 | if (!POINTonE1_affine_on_curve(&ret)) |
319 | 90 | return BLST_POINT_NOT_ON_CURVE; |
320 | | |
321 | 42 | vec_copy(out, &ret, sizeof(ret)); |
322 | | |
323 | | /* (0,±2) is not in group, but application might want to ignore? */ |
324 | 42 | return vec_is_zero(out->X, sizeof(out->X)) ? BLST_POINT_NOT_IN_GROUP |
325 | 42 | : BLST_SUCCESS; |
326 | 132 | } |
327 | | |
328 | | static BLST_ERROR POINTonE1_Deserialize_Z(POINTonE1_affine *out, |
329 | | const unsigned char in[96]) |
330 | 2.74k | { |
331 | 2.74k | unsigned char in0 = in[0]; |
332 | | |
333 | 2.74k | if ((in0 & 0xe0) == 0) |
334 | 172 | return POINTonE1_Deserialize_BE(out, in); |
335 | | |
336 | 2.57k | if (in0 & 0x80) /* compressed bit */ |
337 | 117 | return POINTonE1_Uncompress_Z(out, in); |
338 | | |
339 | 2.45k | if (in0 & 0x40) { /* infinity bit */ |
340 | 2.44k | if (byte_is_zero(in0 & 0x3f) & bytes_are_zero(in+1, 95)) { |
341 | 2.42k | vec_zero(out, sizeof(*out)); |
342 | 2.42k | return BLST_SUCCESS; |
343 | 2.42k | } |
344 | 2.44k | } |
345 | | |
346 | 35 | return BLST_BAD_ENCODING; |
347 | 2.45k | } |
348 | | |
349 | | BLST_ERROR blst_p1_deserialize(POINTonE1_affine *out, |
350 | | const unsigned char in[96]) |
351 | 272 | { return POINTonE1_Deserialize_Z(out, in); } |
352 | | |
353 | | #include "ec_ops.h" |
354 | | POINT_DADD_IMPL(POINTonE1, 384, fp) |
355 | | POINT_DADD_AFFINE_IMPL_A0(POINTonE1, 384, fp, BLS12_381_Rx.p) |
356 | | POINT_ADD_IMPL(POINTonE1, 384, fp) |
357 | | POINT_ADD_AFFINE_IMPL(POINTonE1, 384, fp, BLS12_381_Rx.p) |
358 | | POINT_DOUBLE_IMPL_A0(POINTonE1, 384, fp) |
359 | | POINT_IS_EQUAL_IMPL(POINTonE1, 384, fp) |
360 | | |
361 | | void blst_p1_add(POINTonE1 *out, const POINTonE1 *a, const POINTonE1 *b) |
362 | 344 | { POINTonE1_add(out, a, b); } |
363 | | |
364 | | void blst_p1_add_or_double(POINTonE1 *out, const POINTonE1 *a, |
365 | | const POINTonE1 *b) |
366 | 134 | { POINTonE1_dadd(out, a, b, NULL); } |
367 | | |
368 | | void blst_p1_add_affine(POINTonE1 *out, const POINTonE1 *a, |
369 | | const POINTonE1_affine *b) |
370 | 2.86k | { POINTonE1_add_affine(out, a, b); } |
371 | | |
372 | | void blst_p1_add_or_double_affine(POINTonE1 *out, const POINTonE1 *a, |
373 | | const POINTonE1_affine *b) |
374 | 203 | { POINTonE1_dadd_affine(out, a, b); } |
375 | | |
376 | | void blst_p1_double(POINTonE1 *out, const POINTonE1 *a) |
377 | 114 | { POINTonE1_double(out, a); } |
378 | | |
379 | | int blst_p1_is_equal(const POINTonE1 *a, const POINTonE1 *b) |
380 | 4.05k | { return (int)POINTonE1_is_equal(a, b); } |
381 | | |
382 | | #include "ec_mult.h" |
383 | | POINT_MULT_SCALAR_WX_IMPL(POINTonE1, 4) |
384 | | POINT_MULT_SCALAR_WX_IMPL(POINTonE1, 5) |
385 | | |
386 | | #ifdef __BLST_PRIVATE_TESTMODE__ |
387 | | POINT_AFFINE_MULT_SCALAR_IMPL(POINTonE1) |
388 | | |
389 | | DECLARE_PRIVATE_POINTXZ(POINTonE1, 384) |
390 | | POINT_LADDER_PRE_IMPL(POINTonE1, 384, fp) |
391 | | POINT_LADDER_STEP_IMPL_A0(POINTonE1, 384, fp, onE1) |
392 | | POINT_LADDER_POST_IMPL_A0(POINTonE1, 384, fp, onE1) |
393 | | POINT_MULT_SCALAR_LADDER_IMPL(POINTonE1) |
394 | | #endif |
395 | | |
396 | | static const vec384 beta = { /* such that beta^3 - 1 = 0 */ |
397 | | /* -1/2 * (1 + sqrt(-3)) = ((P-2)^(P-2)) * (1 + (P-3)^((P+1)/4)) */ |
398 | | /* (0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4 |
399 | | 897d29650fb85f9b409427eb4f49fffd8bfd00000000aaac << 384) % P */ |
400 | | TO_LIMB_T(0xcd03c9e48671f071), TO_LIMB_T(0x5dab22461fcda5d2), |
401 | | TO_LIMB_T(0x587042afd3851b95), TO_LIMB_T(0x8eb60ebe01bacb9e), |
402 | | TO_LIMB_T(0x03f97d6e83d050d2), TO_LIMB_T(0x18f0206554638741) |
403 | | }; |
404 | | |
405 | | static void sigma(POINTonE1 *out, const POINTonE1 *in) |
406 | 36.7k | { |
407 | 36.7k | vec_copy(out->X, in->X, 2*sizeof(out->X)); |
408 | 36.7k | mul_fp(out->Z, in->Z, beta); |
409 | 36.7k | } |
410 | | |
411 | | /* Gallant-Lambert-Vanstone, ~45% faster than POINTonE1_mult_w5 */ |
412 | | static void POINTonE1_mult_glv(POINTonE1 *out, const POINTonE1 *in, |
413 | | const pow256 SK) |
414 | 4.33k | { |
415 | 4.33k | union { vec256 l; pow256 s; } val; |
416 | | |
417 | | /* SK/z^2 [in constant time] */ |
418 | | |
419 | 4.33k | limbs_from_le_bytes(val.l, SK, 32); |
420 | 4.33k | div_by_zz(val.l); |
421 | 4.33k | le_bytes_from_limbs(val.s, val.l, 32); |
422 | | |
423 | 4.33k | { |
424 | 4.33k | const byte *scalars[2] = { val.s+16, val.s }; |
425 | 4.33k | POINTonE1 table[2][1<<(5-1)]; /* 4.5KB */ |
426 | 4.33k | size_t i; |
427 | | |
428 | 4.33k | POINTonE1_precompute_w5(table[0], in); |
429 | 73.6k | for (i = 0; i < 1<<(5-1); i++) { |
430 | 69.3k | mul_fp(table[1][i].X, table[0][i].X, beta); |
431 | 69.3k | cneg_fp(table[1][i].Y, table[0][i].Y, 1); |
432 | 69.3k | vec_copy(table[1][i].Z, table[0][i].Z, sizeof(table[1][i].Z)); |
433 | 69.3k | } |
434 | | |
435 | 4.33k | POINTonE1s_mult_w5(out, NULL, 2, scalars, 128, table); |
436 | 4.33k | POINTonE1_cneg(out, 1); |
437 | 4.33k | mul_fp(out->Z, out->Z, beta); |
438 | 4.33k | mul_fp(out->Z, out->Z, beta); |
439 | 4.33k | } |
440 | | |
441 | 4.33k | vec_zero(val.l, sizeof(val)); /* scrub the copy of SK */ |
442 | 4.33k | } |
443 | | |
444 | | static void POINTonE1_sign(POINTonE1 *out, const POINTonE1 *in, const pow256 SK) |
445 | 4.01k | { |
446 | 4.01k | vec384 Z, ZZ; |
447 | 4.01k | limb_t inf; |
448 | | |
449 | 4.01k | POINTonE1_mult_glv(out, in, SK); |
450 | | |
451 | | /* convert to affine to remove possible bias in out->Z */ |
452 | 4.01k | inf = vec_is_zero(out->Z, sizeof(out->Z)); |
453 | | #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
454 | | flt_reciprocal_fp(Z, out->Z); /* 1/Z */ |
455 | | #else |
456 | 4.01k | reciprocal_fp(Z, out->Z); /* 1/Z */ |
457 | 4.01k | #endif |
458 | | |
459 | 4.01k | sqr_fp(ZZ, Z); |
460 | 4.01k | mul_fp(out->X, out->X, ZZ); /* X = X/Z^2 */ |
461 | | |
462 | 4.01k | mul_fp(ZZ, ZZ, Z); |
463 | 4.01k | mul_fp(out->Y, out->Y, ZZ); /* Y = Y/Z^3 */ |
464 | | |
465 | 4.01k | vec_select(out->Z, out->Z, BLS12_381_G1.Z, sizeof(BLS12_381_G1.Z), |
466 | 4.01k | inf); /* Z = inf ? 0 : 1 */ |
467 | 4.01k | } |
468 | | |
469 | | void blst_sk_to_pk_in_g1(POINTonE1 *out, const pow256 SK) |
470 | 4.01k | { POINTonE1_sign(out, &BLS12_381_G1, SK); } |
471 | | |
472 | | void blst_sign_pk_in_g2(POINTonE1 *out, const POINTonE1 *msg, const pow256 SK) |
473 | 0 | { POINTonE1_sign(out, msg, SK); } |
474 | | |
475 | | void blst_sk_to_pk2_in_g1(unsigned char out[96], POINTonE1_affine *PK, |
476 | | const pow256 SK) |
477 | 0 | { |
478 | 0 | POINTonE1 P[1]; |
479 | |
|
480 | 0 | POINTonE1_sign(P, &BLS12_381_G1, SK); |
481 | 0 | if (PK != NULL) |
482 | 0 | vec_copy(PK, P, sizeof(*PK)); |
483 | 0 | if (out != NULL) { |
484 | 0 | limb_t sgn0_pty = POINTonE1_Serialize_BE(out, P); |
485 | 0 | out[0] |= (sgn0_pty & 2) << 4; /* pre-decorate */ |
486 | 0 | out[0] |= vec_is_zero(P->Z, sizeof(P->Z)) << 6; |
487 | 0 | } |
488 | 0 | } |
489 | | |
490 | | void blst_sign_pk2_in_g2(unsigned char out[96], POINTonE1_affine *sig, |
491 | | const POINTonE1 *hash, const pow256 SK) |
492 | 0 | { |
493 | 0 | POINTonE1 P[1]; |
494 | |
|
495 | 0 | POINTonE1_sign(P, hash, SK); |
496 | 0 | if (sig != NULL) |
497 | 0 | vec_copy(sig, P, sizeof(*sig)); |
498 | 0 | if (out != NULL) { |
499 | 0 | limb_t sgn0_pty = POINTonE1_Serialize_BE(out, P); |
500 | 0 | out[0] |= (sgn0_pty & 2) << 4; /* pre-decorate */ |
501 | 0 | out[0] |= vec_is_zero(P->Z, sizeof(P->Z)) << 6; |
502 | 0 | } |
503 | 0 | } |
504 | | |
505 | | void blst_p1_mult(POINTonE1 *out, const POINTonE1 *a, |
506 | | const byte *scalar, size_t nbits) |
507 | 2.45k | { |
508 | 2.45k | if (nbits < 176) { |
509 | 1.63k | if (nbits) |
510 | 823 | POINTonE1_mult_w4(out, a, scalar, nbits); |
511 | 814 | else |
512 | 814 | vec_zero(out, sizeof(*out)); |
513 | 1.63k | } else if (nbits <= 256) { |
514 | 383 | union { vec256 l; pow256 s; } val; |
515 | 383 | size_t i, j, top, mask = (size_t)0 - 1; |
516 | | |
517 | | /* this is not about constant-time-ness, but branch optimization */ |
518 | 12.6k | for (top = (nbits + 7)/8, i=0, j=0; i<sizeof(val.s);) { |
519 | 12.2k | val.s[i++] = scalar[j] & mask; |
520 | 12.2k | mask = 0 - ((i - top) >> (8*sizeof(top)-1)); |
521 | 12.2k | j += 1 & mask; |
522 | 12.2k | } |
523 | | |
524 | 383 | if (check_mod_256(val.s, BLS12_381_r)) /* z^4 is the formal limit */ |
525 | 320 | POINTonE1_mult_glv(out, a, val.s); |
526 | 63 | else /* should never be the case, added for formal completeness */ |
527 | 63 | POINTonE1_mult_w5(out, a, scalar, nbits); |
528 | | |
529 | 383 | vec_zero(val.l, sizeof(val)); |
530 | 437 | } else { /* should never be the case, added for formal completeness */ |
531 | 437 | POINTonE1_mult_w5(out, a, scalar, nbits); |
532 | 437 | } |
533 | 2.45k | } |
534 | | |
535 | | void blst_p1_unchecked_mult(POINTonE1 *out, const POINTonE1 *a, |
536 | | const byte *scalar, size_t nbits) |
537 | 0 | { |
538 | 0 | if (nbits) |
539 | 0 | POINTonE1_mult_w4(out, a, scalar, nbits); |
540 | 0 | else |
541 | 0 | vec_zero(out, sizeof(*out)); |
542 | 0 | } |
543 | | |
544 | | int blst_p1_affine_is_equal(const POINTonE1_affine *a, |
545 | | const POINTonE1_affine *b) |
546 | 79 | { return (int)vec_is_equal(a, b, sizeof(*a)); } |
547 | | |
548 | | int blst_p1_is_inf(const POINTonE1 *p) |
549 | 2.86k | { return (int)vec_is_zero(p->Z, sizeof(p->Z)); } |
550 | | |
551 | | const POINTonE1 *blst_p1_generator(void) |
552 | 0 | { return &BLS12_381_G1; } |
553 | | |
554 | | int blst_p1_affine_is_inf(const POINTonE1_affine *p) |
555 | 5.63k | { return (int)vec_is_zero(p, sizeof(*p)); } |
556 | | |
557 | | const POINTonE1_affine *blst_p1_affine_generator(void) |
558 | 0 | { return (const POINTonE1_affine *)&BLS12_381_G1; } |
559 | | |
560 | | size_t blst_p1_sizeof(void) |
561 | 0 | { return sizeof(POINTonE1); } |
562 | | |
563 | | size_t blst_p1_affine_sizeof(void) |
564 | 0 | { return sizeof(POINTonE1_affine); } |