purify
C++ Purify implementation with native circuit and BPP support
Loading...
Searching...
No Matches
curve.c
Go to the documentation of this file.
1// Copyright (c) 2026 Judica, Inc.
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or https://opensource.org/license/mit/.
4
5#include "curve.h"
6
7#include <assert.h>
8#include <string.h>
9
10static const uint64_t kPurifyPrimeP[4] = {
11#if defined(PURIFY_CBMC_MODEL_SMALL_FIELD)
12 #include "verification/cbmc/model_small_field_constants.h"
13 PURIFY_CBMC_MODEL_FIELD_PRIME_INIT
14#else
15 UINT64_C(0xBFD25E8CD0364141),
16 UINT64_C(0xBAAEDCE6AF48A03B),
17 UINT64_C(0xFFFFFFFFFFFFFFFE),
18 UINT64_C(0xFFFFFFFFFFFFFFFF),
19#endif
20};
21
22static const uint64_t kPurifyOrderN1[4] = {
23#if defined(PURIFY_CBMC_MODEL_SMALL_FIELD)
24 PURIFY_CBMC_MODEL_CURVE_ORDER_N1_INIT
25#else
26 UINT64_C(0x8A5A2A2C58E547E9),
27 UINT64_C(0xA328F24405347212),
28 UINT64_C(0xFFFFFFFFFFFFFFFF),
29 UINT64_C(0xFFFFFFFFFFFFFFFF),
30#endif
31};
32
33static const uint64_t kPurifyOrderN2[4] = {
34#if defined(PURIFY_CBMC_MODEL_SMALL_FIELD)
35 PURIFY_CBMC_MODEL_CURVE_ORDER_N2_INIT
36#else
37 UINT64_C(0xF54A92ED47873A9B),
38 UINT64_C(0xD234C789595CCE64),
39 UINT64_C(0xFFFFFFFFFFFFFFFD),
40 UINT64_C(0xFFFFFFFFFFFFFFFF),
41#endif
42};
43
44static const uint64_t kPurifyHalfN1[4] = {
45#if defined(PURIFY_CBMC_MODEL_SMALL_FIELD)
46 PURIFY_CBMC_MODEL_CURVE_HALF_N1_INIT
47#else
48 UINT64_C(0x452D15162C72A3F4),
49 UINT64_C(0xD1947922029A3909),
50 UINT64_C(0xFFFFFFFFFFFFFFFF),
51 UINT64_C(0x7FFFFFFFFFFFFFFF),
52#endif
53};
54
55static const uint64_t kPurifyHalfN2[4] = {
56#if defined(PURIFY_CBMC_MODEL_SMALL_FIELD)
57 PURIFY_CBMC_MODEL_CURVE_HALF_N2_INIT
58#else
59 UINT64_C(0x7AA54976A3C39D4D),
60 UINT64_C(0xE91A63C4ACAE6732),
61 UINT64_C(0xFFFFFFFFFFFFFFFE),
62 UINT64_C(0x7FFFFFFFFFFFFFFF),
63#endif
64};
65
66static const uint64_t kPurifyFieldDi[4] = {
67#if defined(PURIFY_CBMC_MODEL_SMALL_FIELD)
68 PURIFY_CBMC_MODEL_FIELD_DI_INIT
69#else
70 UINT64_C(0x4CBA8C385348E6E7),
71 UINT64_C(0xE445F1F5DFB6A67E),
72 UINT64_C(0x6666666666666665),
73 UINT64_C(0x6666666666666666),
74#endif
75};
76
77static const char kPurifyHashToCurveTag[] = "Purify/HashToCurve";
78
79static void purify_curve_copy_u256(uint64_t out[4], const uint64_t value[4]) {
80 memcpy(out, value, 4u * sizeof(uint64_t));
81}
82
83static void purify_curve_u256_narrow_u512_unchecked(uint64_t out[4], const uint64_t value[8]) {
84 memcpy(out, value, 4u * sizeof(uint64_t));
85}
86
87static void purify_curve_u256_add_one_unchecked(uint64_t value[4]) {
88 uint64_t carry = 1u;
89 size_t i;
90
91 for (i = 0; i < 4u; ++i) {
92 uint64_t sum = value[i] + carry;
93 carry = (uint64_t)(sum < value[i]);
94 value[i] = sum;
95 }
96 assert(carry == 0u);
97}
98
99static void purify_curve_u64_to_be(unsigned char out[8], uint64_t value) {
100 size_t i;
101 for (i = 0; i < 8; ++i) {
102 out[7u - i] = (unsigned char)(value & 0xffu);
103 value >>= 8;
104 }
105}
106
107static void purify_curve_tag_hash(unsigned char out[32]) {
108 purify_sha256(out, (const unsigned char*)kPurifyHashToCurveTag, sizeof(kPurifyHashToCurveTag) - 1u);
109}
110
111static int purify_curve_hash_to_int_tagged_u320(uint64_t out[5],
112 const unsigned char* data,
113 size_t data_len,
114 const uint64_t range[5],
115 unsigned char info_byte) {
116 unsigned char tag_hash[32];
117 unsigned char derived[40];
118 unsigned char digest[32];
119 size_t bits = purify_u320_bit_length(range);
120 size_t bytes_needed = (bits + 7u) / 8u;
121 unsigned int attempt;
122
123 purify_curve_tag_hash(tag_hash);
124 for (attempt = 0; attempt < 256u; ++attempt) {
125 size_t derived_len = 0;
126 uint64_t block = 0;
127
128 while (derived_len < bytes_needed) {
129 unsigned char attempt_bytes[8];
130 unsigned char block_bytes[8];
131 const unsigned char* items[6];
132 size_t item_lens[6];
133 size_t copy_len;
134 int ok;
135
136 purify_curve_u64_to_be(attempt_bytes, (uint64_t)attempt);
137 purify_curve_u64_to_be(block_bytes, block);
138 items[0] = tag_hash;
139 item_lens[0] = sizeof(tag_hash);
140 items[1] = tag_hash;
141 item_lens[1] = sizeof(tag_hash);
142 items[2] = data;
143 item_lens[2] = data_len;
144 items[3] = &info_byte;
145 item_lens[3] = 1u;
146 items[4] = attempt_bytes;
147 item_lens[4] = sizeof(attempt_bytes);
148 items[5] = block_bytes;
149 item_lens[5] = sizeof(block_bytes);
150 ok = purify_sha256_many(digest, items, item_lens, 6u);
151 assert(ok != 0);
152 if (ok == 0) {
153 return 0;
154 }
155 copy_len = sizeof(digest);
156 if (copy_len > bytes_needed - derived_len) {
157 copy_len = bytes_needed - derived_len;
158 }
159 memcpy(derived + derived_len, digest, copy_len);
160 derived_len += copy_len;
161 ++block;
162 }
163
164 purify_u320_from_bytes_be(out, derived, bytes_needed);
165 purify_u320_mask_bits(out, bits);
166 if (purify_u320_compare(out, range) < 0) {
167 return 1;
168 }
169 }
170
171 return 0;
172}
173
174#if PURIFY_USE_LEGACY_FIELD_HASHES
175static int purify_curve_hash_to_int_hkdf_u320(uint64_t out[5],
176 const unsigned char* data,
177 size_t data_len,
178 const uint64_t range[5],
179 unsigned char info_byte) {
180 unsigned char derived[40];
181 unsigned char prk[32];
182 unsigned char t[32];
183 size_t bits = purify_u320_bit_length(range);
184 size_t bytes_needed = (bits + 7u) / 8u;
185 unsigned int salt_counter;
186
187 for (salt_counter = 0; salt_counter < 256u; ++salt_counter) {
188 unsigned char salt_byte = (unsigned char)salt_counter;
189 size_t offset = 0;
190 unsigned int block_index = 0;
191
192 memset(prk, 0, sizeof(prk));
193 memset(t, 0, sizeof(t));
194 purify_hmac_sha256(prk, &salt_byte, 1u, data, data_len);
195
196 while (offset < bytes_needed) {
197 const size_t prev_len = block_index == 0 ? 0u : sizeof(t);
198 const size_t input_len = prev_len + 2u;
199 unsigned char input[34];
200 size_t copy_len;
201
202 if (prev_len != 0u) {
203 memcpy(input, t, prev_len);
204 }
205 input[prev_len] = info_byte;
206 input[prev_len + 1u] = (unsigned char)(block_index + 1u);
207 purify_hmac_sha256(t, prk, sizeof(prk), input, input_len);
208 copy_len = sizeof(t);
209 if (copy_len > bytes_needed - offset) {
210 copy_len = bytes_needed - offset;
211 }
212 memcpy(derived + offset, t, copy_len);
213 offset += copy_len;
214 ++block_index;
215 }
216
217 purify_u320_from_bytes_be(out, derived, bytes_needed);
218 purify_u320_mask_bits(out, bits);
219 if (purify_u320_compare(out, range) < 0) {
220 return 1;
221 }
222 }
223
224 return 0;
225}
226#endif
227
235
239 if (point->infinity != 0 || purify_fe_is_zero(&point->z) != 0) {
241 }
242 if (purify_fe_is_one(&point->z) != 0) {
243 out.x = point->x;
244 out.y = point->y;
245 out.z = point->z;
246 return out;
247 }
248 {
249 purify_affine_point normalized;
250 purify_curve_affine(&normalized, curve, point);
251 out.x = normalized.x;
252 out.y = normalized.y;
253 purify_fe_set_u64(&out.z, 1);
254 }
255 return out;
256}
257
260 int flag) {
261 purify_fe_cmov(&dst->x, &src->x, flag);
262 purify_fe_cmov(&dst->y, &src->y, flag);
263 purify_fe_cmov(&dst->z, &src->z, flag);
264}
265
273
279 purify_fe b3;
280 purify_fe t0;
281 purify_fe t1;
282 purify_fe t2;
283 purify_fe t3;
284 purify_fe t4;
285 purify_fe t5;
286 purify_fe x3;
287 purify_fe y3;
288 purify_fe z3;
289
290 purify_fe_add(&b3, &curve->b, &curve->b);
291 purify_fe_add(&b3, &b3, &curve->b);
292 purify_fe_mul(&t0, &lhs->x, &rhs->x);
293 purify_fe_mul(&t1, &lhs->y, &rhs->y);
294 purify_fe_mul(&t2, &lhs->z, &rhs->z);
295 purify_fe_add(&t3, &lhs->x, &lhs->y);
296 purify_fe_add(&t4, &rhs->x, &rhs->y);
297 purify_fe_mul(&t3, &t3, &t4);
298 purify_fe_add(&t4, &t0, &t1);
299 purify_fe_sub(&t3, &t3, &t4);
300 purify_fe_add(&t4, &lhs->x, &lhs->z);
301 purify_fe_add(&t5, &rhs->x, &rhs->z);
302 purify_fe_mul(&t4, &t4, &t5);
303 purify_fe_add(&t5, &t0, &t2);
304 purify_fe_sub(&t4, &t4, &t5);
305 purify_fe_add(&t5, &lhs->y, &lhs->z);
306 purify_fe_add(&x3, &rhs->y, &rhs->z);
307 purify_fe_mul(&t5, &t5, &x3);
308 purify_fe_add(&x3, &t1, &t2);
309 purify_fe_sub(&t5, &t5, &x3);
310 purify_fe_mul(&z3, &curve->a, &t4);
311 purify_fe_mul(&x3, &b3, &t2);
312 purify_fe_add(&z3, &x3, &z3);
313 purify_fe_sub(&x3, &t1, &z3);
314 purify_fe_add(&z3, &t1, &z3);
315 purify_fe_mul(&y3, &x3, &z3);
316 purify_fe_add(&t1, &t0, &t0);
317 purify_fe_add(&t1, &t1, &t0);
318 purify_fe_mul(&t2, &curve->a, &t2);
319 purify_fe_mul(&t4, &b3, &t4);
320 purify_fe_add(&t1, &t1, &t2);
321 purify_fe_sub(&t2, &t0, &t2);
322 purify_fe_mul(&t2, &curve->a, &t2);
323 purify_fe_add(&t4, &t4, &t2);
324 purify_fe_mul(&t0, &t1, &t4);
325 purify_fe_add(&y3, &y3, &t0);
326 purify_fe_mul(&t0, &t5, &t4);
327 purify_fe_mul(&x3, &t3, &x3);
328 purify_fe_sub(&x3, &x3, &t0);
329 purify_fe_mul(&t0, &t3, &t1);
330 purify_fe_mul(&z3, &t5, &z3);
331 purify_fe_add(&z3, &z3, &t0);
332
333 out.x = x3;
334 out.y = y3;
335 out.z = z3;
336 return out;
337}
338
343 purify_fe b3;
344 purify_fe t0;
345 purify_fe t1;
346 purify_fe t2;
347 purify_fe t3;
348 purify_fe x3;
349 purify_fe y3;
350 purify_fe z3;
351
352 purify_fe_add(&b3, &curve->b, &curve->b);
353 purify_fe_add(&b3, &b3, &curve->b);
354 purify_fe_mul(&t0, &point->x, &point->x);
355 purify_fe_mul(&t1, &point->y, &point->y);
356 purify_fe_mul(&t2, &point->z, &point->z);
357 purify_fe_mul(&t3, &point->x, &point->y);
358 purify_fe_add(&t3, &t3, &t3);
359 purify_fe_mul(&z3, &point->x, &point->z);
360 purify_fe_add(&z3, &z3, &z3);
361 purify_fe_mul(&x3, &curve->a, &z3);
362 purify_fe_mul(&y3, &b3, &t2);
363 purify_fe_add(&y3, &x3, &y3);
364 purify_fe_sub(&x3, &t1, &y3);
365 purify_fe_add(&y3, &t1, &y3);
366 purify_fe_mul(&y3, &x3, &y3);
367 purify_fe_mul(&x3, &t3, &x3);
368 purify_fe_mul(&z3, &b3, &z3);
369 purify_fe_mul(&t2, &curve->a, &t2);
370 purify_fe_sub(&t3, &t0, &t2);
371 purify_fe_mul(&t3, &curve->a, &t3);
372 purify_fe_add(&t3, &t3, &z3);
373 purify_fe_add(&z3, &t0, &t0);
374 purify_fe_add(&t0, &z3, &t0);
375 purify_fe_add(&t0, &t0, &t2);
376 purify_fe_mul(&t0, &t0, &t3);
377 purify_fe_add(&y3, &y3, &t0);
378 purify_fe_mul(&t2, &point->y, &point->z);
379 purify_fe_add(&t2, &t2, &t2);
380 purify_fe_mul(&t0, &t2, &t3);
381 purify_fe_sub(&x3, &x3, &t0);
382 purify_fe_mul(&z3, &t2, &t1);
383 purify_fe_add(&z3, &z3, &z3);
384 purify_fe_add(&z3, &z3, &z3);
385
386 out.x = x3;
387 out.y = y3;
388 out.z = z3;
389 return out;
390}
391
392void purify_curve_prime_p(uint64_t out[4]) {
394}
395
396void purify_curve_order_n1(uint64_t out[4]) {
398}
399
400void purify_curve_order_n2(uint64_t out[4]) {
402}
403
404void purify_curve_half_n1(uint64_t out[4]) {
406}
407
408void purify_curve_half_n2(uint64_t out[4]) {
410}
411
415
419
420void purify_curve_two_p(uint64_t out[5]) {
422 purify_u320_try_mul_small(out, 2);
423}
424
426 purify_fe_set_u64(out, 118);
427}
428
430 purify_fe_set_u64(out, 339);
431}
432
434 purify_fe_set_u64(out, 5);
435}
436
438 int ok = purify_fe_set_u256(out, kPurifyFieldDi);
439 assert(ok != 0);
440 (void)ok;
441}
442
444 purify_fe_set_zero(&out->x);
445 purify_fe_set_u64(&out->y, 1);
446 purify_fe_set_zero(&out->z);
447 out->infinity = 1;
448}
449
451 purify_fe inv;
452 purify_fe inv2;
453 purify_fe inv3;
454 (void)curve;
455
456 if (point->infinity != 0 || purify_fe_is_zero(&point->z) != 0) {
457 purify_fe_set_zero(&out->x);
458 purify_fe_set_zero(&out->y);
459 out->infinity = 1;
460 return;
461 }
462
463 purify_fe_inverse_var(&inv, &point->z);
464 purify_fe_mul(&inv2, &inv, &inv);
465 purify_fe_mul(&inv3, &inv2, &inv);
466 purify_fe_mul(&out->x, &inv2, &point->x);
467 purify_fe_mul(&out->y, &inv3, &point->y);
468 out->infinity = 0;
469}
470
472 if (point->infinity != 0) {
473 *out = *point;
474 return;
475 }
476 out->x = point->x;
477 purify_fe_negate(&out->y, &point->y);
478 out->z = point->z;
479 out->infinity = 0;
480}
481
482int purify_curve_is_x_coord(const purify_curve* curve, const purify_fe* x) {
483 purify_fe x2;
484 purify_fe x3;
485 purify_fe ax;
486 purify_fe v;
487
488 purify_fe_mul(&x2, x, x);
489 purify_fe_mul(&x3, &x2, x);
490 purify_fe_mul(&ax, &curve->a, x);
491 purify_fe_add(&v, &x3, &ax);
492 purify_fe_add(&v, &v, &curve->b);
493 return purify_fe_legendre_symbol(&v) != -1;
494}
495
497 purify_fe x2;
498 purify_fe x3;
499 purify_fe ax;
500 purify_fe v;
501
502 purify_fe_mul(&x2, x, x);
503 purify_fe_mul(&x3, &x2, x);
504 purify_fe_mul(&ax, &curve->a, x);
505 purify_fe_add(&v, &x3, &ax);
506 purify_fe_add(&v, &v, &curve->b);
507 if (purify_fe_sqrt(&out->y, &v) == 0) {
508 return 0;
509 }
510
511 out->x = *x;
512 purify_fe_set_u64(&out->z, 1);
513 out->infinity = 0;
514 return 1;
515}
516
518 /* `purify_curve_mul()` doubles its accumulator in place, so preserve the input first. */
519 purify_jacobian_point input = *point;
520 purify_fe y1_2;
521 purify_fe y1_4;
522 purify_fe x1_2;
523 purify_fe s;
524 purify_fe m;
525 purify_fe tmp;
526
527 point = &input;
528
529 if (point->infinity != 0 || purify_fe_is_zero(&point->z) != 0) {
531 return;
532 }
533
534 purify_fe_mul(&y1_2, &point->y, &point->y);
535 purify_fe_mul(&y1_4, &y1_2, &y1_2);
536 purify_fe_mul(&x1_2, &point->x, &point->x);
537 purify_fe_set_u64(&tmp, 4);
538 purify_fe_mul(&s, &tmp, &point->x);
539 purify_fe_mul(&s, &s, &y1_2);
540 purify_fe_set_u64(&tmp, 3);
541 purify_fe_mul(&m, &tmp, &x1_2);
542 if (purify_fe_is_zero(&curve->a) == 0) {
543 purify_fe z1_2;
544 purify_fe z1_4;
545 purify_fe az;
546 purify_fe_mul(&z1_2, &point->z, &point->z);
547 purify_fe_mul(&z1_4, &z1_2, &z1_2);
548 purify_fe_mul(&az, &curve->a, &z1_4);
549 purify_fe_add(&m, &m, &az);
550 }
551 purify_fe_mul(&out->x, &m, &m);
552 purify_fe_set_u64(&tmp, 2);
553 purify_fe_mul(&tmp, &tmp, &s);
554 purify_fe_sub(&out->x, &out->x, &tmp);
555 purify_fe_sub(&out->y, &s, &out->x);
556 purify_fe_mul(&out->y, &m, &out->y);
557 purify_fe_set_u64(&tmp, 8);
558 purify_fe_mul(&tmp, &tmp, &y1_4);
559 purify_fe_sub(&out->y, &out->y, &tmp);
560 purify_fe_set_u64(&tmp, 2);
561 purify_fe_mul(&out->z, &tmp, &point->y);
562 purify_fe_mul(&out->z, &out->z, &point->z);
563 out->infinity = 0;
564}
565
567 const purify_jacobian_point* lhs, const purify_affine_point* rhs) {
568 purify_fe z1_2;
569 purify_fe z1_3;
570 purify_fe u2;
571 purify_fe s2;
572 purify_fe h;
573 purify_fe r;
574 purify_fe h_2;
575 purify_fe h_3;
576 purify_fe u1_h_2;
577 purify_fe tmp;
578 (void)curve;
579
580 if (lhs->infinity != 0 || purify_fe_is_zero(&lhs->z) != 0) {
581 out->x = rhs->x;
582 out->y = rhs->y;
583 purify_fe_set_u64(&out->z, 1);
584 out->infinity = rhs->infinity;
585 return;
586 }
587
588 purify_fe_mul(&z1_2, &lhs->z, &lhs->z);
589 purify_fe_mul(&z1_3, &z1_2, &lhs->z);
590 purify_fe_mul(&u2, &rhs->x, &z1_2);
591 purify_fe_mul(&s2, &rhs->y, &z1_3);
592 if (purify_fe_eq(&lhs->x, &u2) != 0) {
593 if (purify_fe_eq(&lhs->y, &s2) == 0) {
595 return;
596 }
597 purify_curve_double(out, curve, lhs);
598 return;
599 }
600
601 purify_fe_sub(&h, &u2, &lhs->x);
602 purify_fe_sub(&r, &s2, &lhs->y);
603 purify_fe_mul(&h_2, &h, &h);
604 purify_fe_mul(&h_3, &h_2, &h);
605 purify_fe_mul(&u1_h_2, &lhs->x, &h_2);
606 purify_fe_mul(&out->x, &r, &r);
607 purify_fe_sub(&out->x, &out->x, &h_3);
608 purify_fe_set_u64(&tmp, 2);
609 purify_fe_mul(&tmp, &tmp, &u1_h_2);
610 purify_fe_sub(&out->x, &out->x, &tmp);
611 purify_fe_sub(&out->y, &u1_h_2, &out->x);
612 purify_fe_mul(&out->y, &r, &out->y);
613 purify_fe_mul(&tmp, &lhs->y, &h_3);
614 purify_fe_sub(&out->y, &out->y, &tmp);
615 purify_fe_mul(&out->z, &h, &lhs->z);
616 out->infinity = 0;
617}
618
620 const purify_jacobian_point* lhs, const purify_jacobian_point* rhs) {
621 purify_fe z1_2;
622 purify_fe z1_3;
623 purify_fe z2_2;
624 purify_fe z2_3;
625 purify_fe u1;
626 purify_fe u2;
627 purify_fe s1;
628 purify_fe s2;
629 purify_fe h;
630 purify_fe r;
631 purify_fe h_2;
632 purify_fe h_3;
633 purify_fe u1_h_2;
634 purify_fe tmp;
635
636 if (lhs->infinity != 0 || purify_fe_is_zero(&lhs->z) != 0) {
637 *out = *rhs;
638 return;
639 }
640 if (rhs->infinity != 0 || purify_fe_is_zero(&rhs->z) != 0) {
641 *out = *lhs;
642 return;
643 }
644 if (purify_fe_is_one(&rhs->z) != 0) {
645 purify_affine_point rhs_affine;
646 rhs_affine.x = rhs->x;
647 rhs_affine.y = rhs->y;
648 rhs_affine.infinity = 0;
649 purify_curve_add_mixed(out, curve, lhs, &rhs_affine);
650 return;
651 }
652 if (purify_fe_is_one(&lhs->z) != 0) {
653 purify_affine_point lhs_affine;
654 lhs_affine.x = lhs->x;
655 lhs_affine.y = lhs->y;
656 lhs_affine.infinity = 0;
657 purify_curve_add_mixed(out, curve, rhs, &lhs_affine);
658 return;
659 }
660
661 purify_fe_mul(&z1_2, &lhs->z, &lhs->z);
662 purify_fe_mul(&z1_3, &z1_2, &lhs->z);
663 purify_fe_mul(&z2_2, &rhs->z, &rhs->z);
664 purify_fe_mul(&z2_3, &z2_2, &rhs->z);
665 purify_fe_mul(&u1, &lhs->x, &z2_2);
666 purify_fe_mul(&u2, &rhs->x, &z1_2);
667 purify_fe_mul(&s1, &lhs->y, &z2_3);
668 purify_fe_mul(&s2, &rhs->y, &z1_3);
669 if (purify_fe_eq(&u1, &u2) != 0) {
670 if (purify_fe_eq(&s1, &s2) == 0) {
672 return;
673 }
674 purify_curve_double(out, curve, lhs);
675 return;
676 }
677
678 purify_fe_sub(&h, &u2, &u1);
679 purify_fe_sub(&r, &s2, &s1);
680 purify_fe_mul(&h_2, &h, &h);
681 purify_fe_mul(&h_3, &h_2, &h);
682 purify_fe_mul(&u1_h_2, &u1, &h_2);
683 purify_fe_mul(&out->x, &r, &r);
684 purify_fe_sub(&out->x, &out->x, &h_3);
685 purify_fe_set_u64(&tmp, 2);
686 purify_fe_mul(&tmp, &tmp, &u1_h_2);
687 purify_fe_sub(&out->x, &out->x, &tmp);
688 purify_fe_sub(&out->y, &u1_h_2, &out->x);
689 purify_fe_mul(&out->y, &r, &out->y);
690 purify_fe_mul(&tmp, &s1, &h_3);
691 purify_fe_sub(&out->y, &out->y, &tmp);
692 purify_fe_mul(&out->z, &h, &lhs->z);
693 purify_fe_mul(&out->z, &out->z, &rhs->z);
694 out->infinity = 0;
695}
696
698 const purify_jacobian_point* point, const uint64_t scalar[4]) {
700 size_t bits = purify_u256_bit_length(scalar);
701 size_t i;
702
704 for (i = bits; i != 0; --i) {
705 size_t idx = i - 1u;
706 purify_curve_double(&result, curve, &result);
707 if (purify_u256_bit(scalar, idx) != 0) {
709 purify_curve_add(&sum, curve, &result, point);
710 result = sum;
711 }
712 }
713 *out = result;
714}
715
717 const purify_jacobian_point* point, const uint64_t scalar[4]) {
720 unsigned int prev_bit = 0;
721 size_t bits = purify_u256_bit_length(curve->n);
722 size_t i;
723
724 for (i = bits; i != 0; --i) {
725 size_t idx = i - 1u;
726 unsigned int bit = purify_u256_bit(scalar, idx) != 0 ? 1u : 0u;
727 purify_curve_complete_swap(&r0, &r1, (int)(bit ^ prev_bit));
728 {
731 r1 = sum;
732 r0 = doubled;
733 }
734 prev_bit = bit;
735 }
736 purify_curve_complete_swap(&r0, &r1, (int)prev_bit);
737 *out = r0;
738}
739
740#if defined(PURIFY_VALGRIND_TESTING) || defined(PURIFY_CBMC_TESTING)
741void purify_curve_mul_secret_ladder_only(purify_complete_projective_point* out, const purify_curve* curve,
742 const purify_jacobian_point* point, const uint64_t scalar[4]) {
744}
745
746void purify_curve_mul_secret_affine_unchecked(purify_affine_point* out, const purify_curve* curve,
747 const purify_jacobian_point* point, const uint64_t scalar[4]) {
749 purify_fe inv;
750
752 purify_fe_inverse(&inv, &r0.z);
753 purify_fe_mul(&out->x, &r0.x, &inv);
754 purify_fe_mul(&out->y, &r0.y, &inv);
755 out->infinity = 0;
756}
757#endif
758
760 const purify_jacobian_point* point, const uint64_t scalar[4]) {
762
764 if (purify_fe_is_zero(&r0.z) != 0) {
765 return 0;
766 }
767
768 {
769 purify_fe inv;
770 purify_fe_inverse(&inv, &r0.z);
771 purify_fe_mul(&out->x, &r0.x, &inv);
772 purify_fe_mul(&out->y, &r0.y, &inv);
773 out->infinity = 0;
774 }
775 return 1;
776}
777
779 const unsigned char* data, size_t data_len) {
780 uint64_t range[5];
781 int info_counter;
782
783 if (out == NULL || curve == NULL || (data_len != 0u && data == NULL)) {
784 return 0;
785 }
786
788 purify_curve_two_p(range);
789 for (info_counter = 0; info_counter < 256; ++info_counter) {
790 uint64_t value[5];
791 uint64_t x_candidate[5];
792 uint64_t x_words[4];
793 purify_fe x;
794 int ok;
795
796#if PURIFY_USE_LEGACY_FIELD_HASHES
797 ok = purify_curve_hash_to_int_hkdf_u320(value, data, data_len, range, (unsigned char)info_counter);
798#else
799 ok = purify_curve_hash_to_int_tagged_u320(value, data, data_len, range, (unsigned char)info_counter);
800#endif
801 if (ok == 0) {
802 continue;
803 }
804
805 purify_u320_shifted_right(x_candidate, value, 1u);
806 ok = purify_u256_try_narrow_u320(x_words, x_candidate);
807 assert(ok != 0);
808 if (ok == 0) {
809 return 0;
810 }
811 ok = purify_fe_set_u256(&x, x_words);
812 assert(ok != 0);
813 if (ok == 0) {
814 return 0;
815 }
816 if (purify_curve_is_x_coord(curve, &x) == 0) {
817 continue;
818 }
819 if (purify_curve_lift_x(out, curve, &x) == 0) {
820 continue;
821 }
822 if (purify_u320_bit(value, 0u) != 0) {
823 purify_curve_negate(out, out);
824 }
825 return 1;
826 }
827
828 return 0;
829}
830
831int purify_curve_is_valid_secret_key(const uint64_t value[8]) {
832 uint64_t upper_bound[8];
834 return purify_u512_compare(value, upper_bound) < 0;
835}
836
837int purify_curve_is_valid_public_key(const uint64_t value[8]) {
838 uint64_t upper_bound[8];
840 return purify_u512_compare(value, upper_bound) < 0;
841}
842
843static void purify_curve_unpack_secret_from_valid(uint64_t first[4], uint64_t second[4], const uint64_t value[8]) {
844 uint64_t denominator[8];
845 uint64_t quotient[8];
846 uint64_t remainder[8];
847 int ok;
848
850 ok = purify_u512_try_divmod_same_consttime(quotient, remainder, value, denominator);
851 assert(ok != 0);
852 if (ok == 0) {
853 purify_u256_set_zero(first);
854 purify_u256_set_zero(second);
855 return;
856 }
861}
862
863int purify_curve_unpack_secret(uint64_t first[4], uint64_t second[4], const uint64_t value[8]) {
864 if (purify_curve_is_valid_secret_key(value) == 0) {
865 return 0;
866 }
867
868 purify_curve_unpack_secret_from_valid(first, second, value);
869 return 1;
870}
871
872#if defined(PURIFY_VALGRIND_TESTING) || defined(PURIFY_CBMC_TESTING)
873void purify_curve_unpack_secret_unchecked(uint64_t first[4], uint64_t second[4], const uint64_t value[8]) {
874 purify_curve_unpack_secret_from_valid(first, second, value);
875}
876#endif
877
878int purify_curve_unpack_public(uint64_t first[4], uint64_t second[4], const uint64_t value[8]) {
879 uint64_t denominator[8];
880 uint64_t quotient[8];
881 uint64_t remainder[8];
882
883 if (purify_curve_is_valid_public_key(value) == 0) {
884 return 0;
885 }
886
888 if (purify_u512_try_divmod_same(quotient, remainder, value, denominator) == 0) {
889 return 0;
890 }
891 if (purify_u256_try_narrow_u512(first, remainder) == 0 || purify_u256_try_narrow_u512(second, quotient) == 0) {
892 return 0;
893 }
894 return 1;
895}
896
897void purify_curve_pack_public(uint64_t out[8], const uint64_t x1[4], const uint64_t x2[4]) {
898 uint64_t wide_x1[8];
900 purify_u512_widen_u256(wide_x1, x1);
901 purify_u512_try_add(out, wide_x1);
902}
903
904void purify_curve_combine(purify_fe* out, const purify_fe* x1, const purify_fe* x2) {
905 purify_fe field_a;
906 purify_fe field_b;
907 purify_fe field_di;
908 purify_fe two;
909 purify_fe u;
910 purify_fe v;
911 purify_fe uv;
912 purify_fe u_plus_v;
913 purify_fe denom;
914 purify_fe w;
915 purify_fe numer;
916 purify_fe tmp;
917
918 purify_curve_field_a(&field_a);
919 purify_curve_field_b(&field_b);
920 purify_curve_field_di(&field_di);
921 purify_fe_set_u64(&two, 2);
922
923 u = *x1;
924 purify_fe_mul(&v, x2, &field_di);
925 purify_fe_sub(&denom, &u, &v);
926 purify_fe_inverse(&w, &denom);
927 purify_fe_add(&u_plus_v, &u, &v);
928 purify_fe_mul(&uv, &u, &v);
929 purify_fe_add(&tmp, &field_a, &uv);
930 purify_fe_mul(&numer, &u_plus_v, &tmp);
931 purify_fe_mul(&tmp, &two, &field_b);
932 purify_fe_add(&numer, &numer, &tmp);
933 purify_fe_mul(&w, &w, &w);
934 purify_fe_mul(out, &numer, &w);
935}
936
937int purify_curve_key_to_bits(int* out_bits, size_t out_len, const uint64_t value[4], const uint64_t max_value[4]) {
938 uint64_t copy[4];
939 size_t bits;
940 size_t i;
941
942 if ((out_len != 0 && out_bits == NULL) || purify_u256_is_zero(value) != 0 || purify_u256_compare(value, max_value) > 0) {
943 return 0;
944 }
945
946 bits = purify_u256_bit_length(max_value);
947 if (out_len < bits) {
948 return 0;
949 }
950
951 purify_curve_copy_u256(copy, value);
952 purify_u256_try_sub(copy, (const uint64_t[4]){UINT64_C(1), UINT64_C(0), UINT64_C(0), UINT64_C(0)});
953 for (i = 0; i < bits; ++i) {
954 out_bits[i] = purify_u256_bit(copy, i) != 0 ? 1 : 0;
955 }
956 for (i = 3; i < bits; i += 3) {
957 int flip = 1 - out_bits[i];
958 out_bits[i - 1] ^= flip;
959 out_bits[i - 2] ^= flip;
960 out_bits[i] ^= 1;
961 }
962 return 1;
963}
static void purify_curve_complete_swap(purify_complete_projective_point *lhs, purify_complete_projective_point *rhs, int flag)
Definition curve.c:266
static const uint64_t kPurifyFieldDi[4]
Definition curve.c:66
void purify_curve_half_n1(uint64_t out[4])
Definition curve.c:404
int purify_curve_is_x_coord(const purify_curve *curve, const purify_fe *x)
Definition curve.c:482
void purify_curve_jacobian_infinity(purify_jacobian_point *out)
Definition curve.c:443
void purify_curve_pack_public(uint64_t out[8], const uint64_t x1[4], const uint64_t x2[4])
Definition curve.c:897
int purify_curve_is_valid_public_key(const uint64_t value[8])
Definition curve.c:837
static const char kPurifyHashToCurveTag[]
Definition curve.c:77
void purify_curve_order_n2(uint64_t out[4])
Definition curve.c:400
static purify_complete_projective_point purify_curve_complete_add(const purify_curve *curve, const purify_complete_projective_point *lhs, const purify_complete_projective_point *rhs)
Definition curve.c:275
static const uint64_t kPurifyOrderN1[4]
Definition curve.c:22
void purify_curve_packed_public_key_space_size(uint64_t out[8])
Definition curve.c:416
static void purify_curve_tag_hash(unsigned char out[32])
Definition curve.c:107
static void purify_curve_unpack_secret_from_valid(uint64_t first[4], uint64_t second[4], const uint64_t value[8])
Definition curve.c:843
static purify_complete_projective_point purify_curve_complete_double(const purify_curve *curve, const purify_complete_projective_point *point)
Definition curve.c:340
void purify_curve_order_n1(uint64_t out[4])
Definition curve.c:396
void purify_curve_packed_secret_key_space_size(uint64_t out[8])
Definition curve.c:412
int purify_curve_unpack_public(uint64_t first[4], uint64_t second[4], const uint64_t value[8])
Definition curve.c:878
void purify_curve_double(purify_jacobian_point *out, const purify_curve *curve, const purify_jacobian_point *point)
Definition curve.c:517
int purify_curve_key_to_bits(int *out_bits, size_t out_len, const uint64_t value[4], const uint64_t max_value[4])
Definition curve.c:937
static void purify_curve_complete_assign(purify_complete_projective_point *dst, const purify_complete_projective_point *src, int flag)
Definition curve.c:258
void purify_curve_field_a(purify_fe *out)
Definition curve.c:425
void purify_curve_two_p(uint64_t out[5])
Definition curve.c:420
void purify_curve_negate(purify_jacobian_point *out, const purify_jacobian_point *point)
Definition curve.c:471
void purify_curve_half_n2(uint64_t out[4])
Definition curve.c:408
int purify_curve_lift_x(purify_jacobian_point *out, const purify_curve *curve, const purify_fe *x)
Definition curve.c:496
int purify_curve_is_valid_secret_key(const uint64_t value[8])
Definition curve.c:831
void purify_curve_combine(purify_fe *out, const purify_fe *x1, const purify_fe *x2)
Definition curve.c:904
void purify_curve_field_di(purify_fe *out)
Definition curve.c:437
void purify_curve_field_d(purify_fe *out)
Definition curve.c:433
int purify_curve_hash_to_curve(purify_jacobian_point *out, const purify_curve *curve, const unsigned char *data, size_t data_len)
Definition curve.c:778
void purify_curve_field_b(purify_fe *out)
Definition curve.c:429
static const uint64_t kPurifyHalfN1[4]
Definition curve.c:44
int purify_curve_mul_secret_affine(purify_affine_point *out, const purify_curve *curve, const purify_jacobian_point *point, const uint64_t scalar[4])
Definition curve.c:759
void purify_curve_mul(purify_jacobian_point *out, const purify_curve *curve, const purify_jacobian_point *point, const uint64_t scalar[4])
Definition curve.c:697
static const uint64_t kPurifyOrderN2[4]
Definition curve.c:33
void purify_curve_add(purify_jacobian_point *out, const purify_curve *curve, const purify_jacobian_point *lhs, const purify_jacobian_point *rhs)
Definition curve.c:619
static void purify_curve_mul_secret_ladder_core(purify_complete_projective_point *out, const purify_curve *curve, const purify_jacobian_point *point, const uint64_t scalar[4])
Definition curve.c:716
static purify_complete_projective_point purify_curve_complete_identity(void)
Definition curve.c:228
static const uint64_t kPurifyHalfN2[4]
Definition curve.c:55
static purify_complete_projective_point purify_curve_secret_input_point(const purify_curve *curve, const purify_jacobian_point *point)
Definition curve.c:237
static void purify_curve_u256_narrow_u512_unchecked(uint64_t out[4], const uint64_t value[8])
Definition curve.c:83
void purify_curve_add_mixed(purify_jacobian_point *out, const purify_curve *curve, const purify_jacobian_point *lhs, const purify_affine_point *rhs)
Definition curve.c:566
void purify_curve_affine(purify_affine_point *out, const purify_curve *curve, const purify_jacobian_point *point)
Definition curve.c:450
static void purify_curve_u256_add_one_unchecked(uint64_t value[4])
Definition curve.c:87
void purify_curve_prime_p(uint64_t out[4])
Definition curve.c:392
static const uint64_t kPurifyPrimeP[4]
Definition curve.c:10
int purify_curve_unpack_secret(uint64_t first[4], uint64_t second[4], const uint64_t value[8])
Definition curve.c:863
static int purify_curve_hash_to_int_tagged_u320(uint64_t out[5], const unsigned char *data, size_t data_len, const uint64_t range[5], unsigned char info_byte)
Definition curve.c:111
static void purify_curve_u64_to_be(unsigned char out[8], uint64_t value)
Definition curve.c:99
static void purify_curve_copy_u256(uint64_t out[4], const uint64_t value[4])
Definition curve.c:79
int purify_fe_legendre_symbol(const purify_fe *value)
Definition field.c:154
void purify_fe_set_zero(purify_fe *out)
Definition field.c:25
int purify_fe_set_u256(purify_fe *out, const uint64_t value[4])
Definition field.c:49
void purify_fe_inverse(purify_fe *out, const purify_fe *value)
Definition field.c:90
int purify_fe_sqrt(purify_fe *out, const purify_fe *value)
Definition field.c:161
int purify_fe_is_zero(const purify_fe *value)
Definition field.c:65
int purify_fe_is_one(const purify_fe *value)
Definition field.c:69
void purify_fe_inverse_var(purify_fe *out, const purify_fe *value)
Definition field.c:95
void purify_fe_mul(purify_fe *out, const purify_fe *lhs, const purify_fe *rhs)
Definition field.c:112
void purify_fe_add(purify_fe *out, const purify_fe *lhs, const purify_fe *rhs)
Definition field.c:100
void purify_fe_sub(purify_fe *out, const purify_fe *lhs, const purify_fe *rhs)
Definition field.c:106
void purify_fe_cmov(purify_fe *dst, const purify_fe *src, int flag)
Definition field.c:86
int purify_fe_eq(const purify_fe *lhs, const purify_fe *rhs)
Definition field.c:77
void purify_fe_set_u64(purify_fe *out, uint64_t value)
Definition field.c:29
void purify_fe_negate(purify_fe *out, const purify_fe *value)
Definition field.c:81
Scalar32 scalar
Definition bppp.cpp:119
int purify_sha256_many(unsigned char output32[32], const unsigned char *const *items, const size_t *item_lens, size_t items_count)
Computes SHA-256 over a set of byte strings.
void purify_sha256(unsigned char output32[32], const unsigned char *data, size_t data_len)
Computes SHA-256 over a byte string.
void purify_hmac_sha256(unsigned char output32[32], const unsigned char *key, size_t key_len, const unsigned char *data, size_t data_len)
Computes HMAC-SHA256 over a byte string.
purify_fe y
Definition curve.h:25
purify_fe x
Definition curve.h:24
purify_fe b
Definition curve.h:37
purify_fe a
Definition curve.h:36
uint64_t n[4]
Definition curve.h:38
int purify_u256_try_narrow_u512(uint64_t out[4], const uint64_t value[8])
Definition uint.c:183
void purify_u512_widen_u256(uint64_t out[8], const uint64_t value[4])
Definition uint.c:170
void purify_u320_widen_u256(uint64_t out[5], const uint64_t value[4])
Definition uint.c:165
void purify_u512_multiply_u256(uint64_t out[8], const uint64_t lhs[4], const uint64_t rhs[4])
Definition uint.c:263
int purify_u512_try_divmod_same(uint64_t quotient[8], uint64_t remainder[8], const uint64_t numerator[8], const uint64_t denominator[8])
Definition uint.c:194
int purify_u256_try_narrow_u320(uint64_t out[4], const uint64_t value[5])
Definition uint.c:175
int purify_u512_try_divmod_same_consttime(uint64_t quotient[8], uint64_t remainder[8], const uint64_t numerator[8], const uint64_t denominator[8])
Definition uint.c:235
int PURIFY_UINT_FN() bit(const uint64_t value[PURIFY_UINT_WORDS], size_t index)
Definition uint_impl.h:125