Coverage Report

Created: 2023-12-08 07:00

/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);   }