Botan 3.13.0
Crypto and TLS for C&
pcurves_generic.cpp
Go to the documentation of this file.
1/*
2* (C) 2025 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#include <botan/internal/pcurves_generic.h>
8
9#include <botan/bigint.h>
10#include <botan/exceptn.h>
11#include <botan/rng.h>
12#include <botan/internal/barrett.h>
13#include <botan/internal/buffer_stuffer.h>
14#include <botan/internal/ct_utils.h>
15#include <botan/internal/loadstor.h>
16#include <botan/internal/mp_core.h>
17#include <botan/internal/pcurves_algos.h>
18#include <botan/internal/pcurves_instance.h>
19#include <botan/internal/pcurves_mul.h>
20#include <botan/internal/primality.h>
21#include <algorithm>
22
23namespace Botan::PCurve {
24
25namespace {
26
27template <size_t N>
28constexpr std::optional<std::array<word, N>> bytes_to_words(std::span<const uint8_t> bytes) {
29 if(bytes.size() > WordInfo<word>::bytes * N) {
30 return std::nullopt;
31 }
32
33 std::array<word, N> r{};
34
35 const size_t full_words = bytes.size() / WordInfo<word>::bytes;
36 const size_t extra_bytes = bytes.size() % WordInfo<word>::bytes;
37
38 for(size_t i = 0; i != full_words; ++i) {
39 r[i] = load_be<word>(bytes.data(), full_words - 1 - i);
40 }
41
42 if(extra_bytes > 0) {
43 const size_t shift = extra_bytes * 8;
44 bigint_shl1(r.data(), r.size(), r.size(), shift);
45
46 for(size_t i = 0; i != extra_bytes; ++i) {
47 const word b0 = bytes[WordInfo<word>::bytes * full_words + i];
48 r[0] |= (b0 << (8 * (extra_bytes - 1 - i)));
49 }
50 }
51
52 return r;
53}
54
55template <typename T>
56T impl_pow_vartime(const T& elem, const T& one, size_t bits, std::span<const word> exp) {
57 constexpr size_t WindowBits = 4;
58 constexpr size_t WindowElements = (1 << WindowBits) - 1;
59
60 const size_t Windows = (bits + WindowBits - 1) / WindowBits;
61
62 std::vector<T> tbl;
63 tbl.reserve(WindowElements);
64
65 tbl.push_back(elem);
66
67 for(size_t i = 1; i != WindowElements; ++i) {
68 if(i % 2 == 1) {
69 tbl.push_back(tbl[i / 2].square());
70 } else {
71 tbl.push_back(tbl[i - 1] * tbl[0]);
72 }
73 }
74
75 auto r = one;
76
77 const size_t w0 = read_window_bits<WindowBits>(exp, (Windows - 1) * WindowBits);
78
79 if(w0 > 0) {
80 r = tbl[w0 - 1];
81 }
82
83 for(size_t i = 1; i != Windows; ++i) {
84 for(size_t j = 0; j != WindowBits; ++j) {
85 r = r.square();
86 }
87 const size_t w = read_window_bits<WindowBits>(exp, (Windows - i - 1) * WindowBits);
88
89 if(w > 0) {
90 r *= tbl[w - 1];
91 }
92 }
93
94 return r;
95}
96
97} // namespace
98
99class GenericCurveParams final {
100 public:
101 typedef PrimeOrderCurve::StorageUnit StorageUnit;
102 static constexpr size_t N = PrimeOrderCurve::StorageWords;
103
104 GenericCurveParams(const BigInt& p,
105 const BigInt& a,
106 const BigInt& b,
107 const BigInt& base_x,
108 const BigInt& base_y,
109 const BigInt& order) :
110 m_words(p.sig_words()),
111 m_order_bits(order.bits()),
112 m_order_bytes(order.bytes()),
113 m_field_bits(p.bits()),
114 m_field_bytes(p.bytes()),
115 m_monty_order(order),
116 m_monty_field(p),
117 m_field(bn_to_fixed(p)),
118 m_field_minus_2(bn_to_fixed_rev(p - 2)),
119 m_field_monty_r1(bn_to_fixed(m_monty_field.R1())),
120 m_field_monty_r2(bn_to_fixed(m_monty_field.R2())),
121 m_field_p_plus_1_over_4(bn_to_fixed_rev((p + 1) / 4)),
122 m_field_inv_2(bn_to_fixed((p / 2) + 1)),
123 m_field_p_dash(m_monty_field.p_dash()),
124
125 m_order(bn_to_fixed(order)),
126 m_order_minus_2(bn_to_fixed_rev(order - 2)),
127 m_order_monty_r1(bn_to_fixed(m_monty_order.R1())),
128 m_order_monty_r2(bn_to_fixed(m_monty_order.R2())),
129 m_order_monty_r3(bn_to_fixed(m_monty_order.R3())),
130 m_order_inv_2(bn_to_fixed((order / 2) + 1)),
131 m_order_p_dash(m_monty_order.p_dash()),
132
133 m_a_is_minus_3(a + 3 == p),
134 m_a_is_zero(a.is_zero()),
135 m_order_is_lt_field(order < p) {
137 m_monty_curve_a = bn_to_fixed(m_monty_field.mul(a, m_monty_field.R2(), ws));
138 m_monty_curve_b = bn_to_fixed(m_monty_field.mul(b, m_monty_field.R2(), ws));
139
140 m_base_x = bn_to_fixed(m_monty_field.mul(base_x, m_monty_field.R2(), ws));
141 m_base_y = bn_to_fixed(m_monty_field.mul(base_y, m_monty_field.R2(), ws));
142 }
143
144 size_t words() const { return m_words; }
145
146 size_t order_bits() const { return m_order_bits; }
147
148 size_t order_bytes() const { return m_order_bytes; }
149
150 size_t field_bits() const { return m_field_bits; }
151
152 size_t field_bytes() const { return m_field_bytes; }
153
154 const Montgomery_Params& monty_order() const { return m_monty_order; }
155
156 const Montgomery_Params& monty_field() const { return m_monty_field; }
157
158 const StorageUnit& field() const { return m_field; }
159
160 const StorageUnit& field_minus_2() const { return m_field_minus_2; }
161
162 const StorageUnit& field_monty_r1() const { return m_field_monty_r1; }
163
164 const StorageUnit& field_monty_r2() const { return m_field_monty_r2; }
165
166 const StorageUnit& field_p_plus_1_over_4() const { return m_field_p_plus_1_over_4; }
167
168 const StorageUnit& field_inv_2() const { return m_field_inv_2; }
169
170 word field_p_dash() const { return m_field_p_dash; }
171
172 const StorageUnit& order() const { return m_order; }
173
174 const StorageUnit& order_minus_2() const { return m_order_minus_2; }
175
176 const StorageUnit& order_monty_r1() const { return m_order_monty_r1; }
177
178 const StorageUnit& order_monty_r2() const { return m_order_monty_r2; }
179
180 const StorageUnit& order_monty_r3() const { return m_order_monty_r3; }
181
182 const StorageUnit& order_inv_2() const { return m_order_inv_2; }
183
184 word order_p_dash() const { return m_order_p_dash; }
185
186 const StorageUnit& monty_curve_a() const { return m_monty_curve_a; }
187
188 const StorageUnit& monty_curve_b() const { return m_monty_curve_b; }
189
190 const StorageUnit& base_x() const { return m_base_x; }
191
192 const StorageUnit& base_y() const { return m_base_y; }
193
194 bool a_is_minus_3() const { return m_a_is_minus_3; }
195
196 bool a_is_zero() const { return m_a_is_zero; }
197
198 bool order_is_less_than_field() const { return m_order_is_lt_field; }
199
200 void mul(std::array<word, 2 * N>& z, const std::array<word, N>& x, const std::array<word, N>& y) const {
201 clear_mem(z);
202
203 if(m_words == 4) {
204 bigint_comba_mul4(z.data(), x.data(), y.data());
205 } else if(m_words == 6) {
206 bigint_comba_mul6(z.data(), x.data(), y.data());
207 } else if(m_words == 8) {
208 bigint_comba_mul8(z.data(), x.data(), y.data());
209 } else if(m_words == 9) {
210 bigint_comba_mul9(z.data(), x.data(), y.data());
211 } else {
212 bigint_mul(z.data(), z.size(), x.data(), m_words, m_words, y.data(), m_words, m_words, nullptr, 0);
213 }
214 }
215
216 void sqr(std::array<word, 2 * N>& z, const std::array<word, N>& x) const {
217 clear_mem(z);
218
219 if(m_words == 4) {
220 bigint_comba_sqr4(z.data(), x.data());
221 } else if(m_words == 6) {
222 bigint_comba_sqr6(z.data(), x.data());
223 } else if(m_words == 8) {
224 bigint_comba_sqr8(z.data(), x.data());
225 } else if(m_words == 9) {
226 bigint_comba_sqr9(z.data(), x.data());
227 } else {
228 bigint_sqr(z.data(), z.size(), x.data(), m_words, m_words, nullptr, 0);
229 }
230 }
231
232 private:
233 static std::array<word, PrimeOrderCurve::StorageWords> bn_to_fixed(const BigInt& n) {
234 const size_t n_words = n.sig_words();
236
237 std::array<word, PrimeOrderCurve::StorageWords> r{};
238 copy_mem(std::span{r}.first(n_words), n._as_span().first(n_words));
239 return r;
240 }
241
242 static std::array<word, PrimeOrderCurve::StorageWords> bn_to_fixed_rev(const BigInt& n) {
243 auto v = bn_to_fixed(n);
244 std::reverse(v.begin(), v.end());
245 return v;
246 }
247
248 private:
249 size_t m_words;
250 size_t m_order_bits;
251 size_t m_order_bytes;
252 size_t m_field_bits;
253 size_t m_field_bytes;
254
255 Montgomery_Params m_monty_order;
256 Montgomery_Params m_monty_field;
257
258 StorageUnit m_field;
259 StorageUnit m_field_minus_2;
260 StorageUnit m_field_monty_r1;
261 StorageUnit m_field_monty_r2;
262 StorageUnit m_field_p_plus_1_over_4;
263 StorageUnit m_field_inv_2;
264 word m_field_p_dash;
265
266 StorageUnit m_order;
267 StorageUnit m_order_minus_2;
268 StorageUnit m_order_monty_r1;
269 StorageUnit m_order_monty_r2;
270 StorageUnit m_order_monty_r3;
271 StorageUnit m_order_inv_2;
272 word m_order_p_dash;
273
274 StorageUnit m_monty_curve_a{};
275 StorageUnit m_monty_curve_b{};
276
277 StorageUnit m_base_x{};
278 StorageUnit m_base_y{};
279
280 bool m_a_is_minus_3;
281 bool m_a_is_zero;
282 bool m_order_is_lt_field;
283};
284
285class GenericScalar final {
286 public:
287 typedef word W;
288 typedef PrimeOrderCurve::StorageUnit StorageUnit;
289 static constexpr size_t N = PrimeOrderCurve::StorageWords;
290
291 static std::optional<GenericScalar> from_wide_bytes(const GenericPrimeOrderCurve* curve,
292 std::span<const uint8_t> bytes) {
293 const size_t mlen = curve->_params().order_bytes();
294
295 if(bytes.size() > 2 * mlen) {
296 return {};
297 }
298
299 std::array<uint8_t, 2 * sizeof(word) * N> padded_bytes{};
300 copy_mem(std::span{padded_bytes}.last(bytes.size()), bytes);
301
302 auto words = bytes_to_words<2 * N>(std::span{padded_bytes});
303 if(words) {
304 auto in_rep = wide_to_rep(curve, words.value());
305 return GenericScalar(curve, in_rep);
306 } else {
307 return {};
308 }
309 }
310
311 static std::optional<GenericScalar> deserialize(const GenericPrimeOrderCurve* curve,
312 std::span<const uint8_t> bytes) {
313 const size_t len = curve->_params().order_bytes();
314
315 if(bytes.size() != len) {
316 return {};
317 }
318
319 const auto words = bytes_to_words<N>(bytes);
320
321 if(words) {
322 if(!bigint_ct_is_lt(words->data(), N, curve->_params().order().data(), N).as_bool()) {
323 return {};
324 }
325
326 // Safe because we checked above that words is an integer < P
327 return GenericScalar(curve, to_rep(curve, *words));
328 } else {
329 return {};
330 }
331 }
332
333 static GenericScalar zero(const GenericPrimeOrderCurve* curve) {
334 const StorageUnit zeros{};
335 return GenericScalar(curve, zeros);
336 }
337
338 static GenericScalar one(const GenericPrimeOrderCurve* curve) {
339 return GenericScalar(curve, curve->_params().order_monty_r1());
340 }
341
342 static GenericScalar random(const GenericPrimeOrderCurve* curve, RandomNumberGenerator& rng) {
343 constexpr size_t MAX_ATTEMPTS = 1000;
344
345 const size_t bits = curve->_params().order_bits();
346
347 std::vector<uint8_t> buf(curve->_params().order_bytes());
348
349 for(size_t i = 0; i != MAX_ATTEMPTS; ++i) {
350 rng.randomize(buf);
351
352 // Zero off high bits that if set would certainly cause us
353 // to be out of range
354 if(bits % 8 != 0) {
355 const uint8_t mask = 0xFF >> (8 - (bits % 8));
356 buf[0] &= mask;
357 }
358
359 if(auto s = GenericScalar::deserialize(curve, buf)) {
360 if(s.value().is_nonzero().as_bool()) {
361 return s.value();
362 }
363 }
364 }
365
366 throw Internal_Error("Failed to generate random Scalar within bounded number of attempts");
367 }
368
369 friend GenericScalar operator+(const GenericScalar& a, const GenericScalar& b) {
370 const auto* curve = check_curve(a, b);
371 const size_t words = curve->_params().words();
372
373 StorageUnit t{};
374 const W carry = bigint_add3(t.data(), a.data(), words, b.data(), words);
375
376 StorageUnit r{};
377 bigint_monty_maybe_sub(words, r.data(), carry, t.data(), curve->_params().order().data());
378 return GenericScalar(curve, r);
379 }
380
381 friend GenericScalar operator-(const GenericScalar& a, const GenericScalar& b) { return a + b.negate(); }
382
383 friend GenericScalar operator*(const GenericScalar& a, const GenericScalar& b) {
384 const auto* curve = check_curve(a, b);
385
386 std::array<W, 2 * N> z; // NOLINT(*-member-init)
387 curve->_params().mul(z, a.value(), b.value());
388 return GenericScalar(curve, redc(curve, z));
389 }
390
391 GenericScalar& operator*=(const GenericScalar& other) {
392 const auto* curve = check_curve(*this, other);
393
394 std::array<W, 2 * N> z; // NOLINT(*-member-init)
395 curve->_params().mul(z, value(), other.value());
396 m_val = redc(curve, z);
397 return (*this);
398 }
399
400 GenericScalar square() const {
401 const auto* curve = this->m_curve;
402
403 std::array<W, 2 * N> z; // NOLINT(*-member-init)
404 curve->_params().sqr(z, value());
405 return GenericScalar(curve, redc(curve, z));
406 }
407
408 GenericScalar pow_vartime(const StorageUnit& exp) const {
409 auto one = GenericScalar::one(curve());
410 auto bits = curve()->_params().order_bits();
411 auto words = curve()->_params().words();
412 return impl_pow_vartime(*this, one, bits, std::span{exp}.last(words));
413 }
414
415 GenericScalar negate() const {
416 auto x_is_zero = CT::all_zeros(this->data(), N);
417
418 StorageUnit r;
419 bigint_sub3(r.data(), m_curve->_params().order().data(), N, this->data(), N);
420 x_is_zero.if_set_zero_out(r.data(), N);
421 return GenericScalar(m_curve, r);
422 }
423
424 GenericScalar invert() const { return pow_vartime(m_curve->_params().order_minus_2()); }
425
426 /**
427 * Helper for variable time BEEA
428 *
429 * Note this function assumes that its arguments are in the standard
430 * domain, not the Montgomery domain. invert_vartime converts its argument
431 * out of Montgomery, and then back to Montgomery when returning the result.
432 */
433 static void _invert_vartime_div2_helper(GenericScalar& a, GenericScalar& x) {
434 const auto& inv_2 = a.curve()->_params().order_inv_2();
435
436 // Conditional ok: this function is variable time
437 while((a.m_val[0] & 1) != 1) {
438 shift_right<1>(a.m_val);
439
440 const W borrow = shift_right<1>(x.m_val);
441
442 // Conditional ok: this function is variable time
443 if(borrow > 0) {
444 bigint_add2(x.m_val.data(), N, inv_2.data(), N);
445 }
446 }
447 }
448
449 /*
450 * See the comments on invert_vartime in pcurves_impl.h for background
451 */
452 GenericScalar invert_vartime() const {
453 if(this->is_zero().as_bool()) {
454 return (*this);
455 }
456
457 auto x = GenericScalar(m_curve, std::array<W, N>{1});
458 auto b = GenericScalar(m_curve, from_rep(m_curve, m_val));
459
460 // First loop iteration
461 GenericScalar::_invert_vartime_div2_helper(b, x);
462
463 auto a = b.negate();
464 // y += x but y is zero at the outset
465 auto y = x;
466
467 // First half of second loop iteration
468 GenericScalar::_invert_vartime_div2_helper(a, y);
469
470 for(;;) {
471 // Conditional ok: this function is variable time
472 if(a.m_val == b.m_val) {
473 // At this point it should be that a == b == 1
474 auto r = y.negate();
475
476 // Convert back to Montgomery
477 return GenericScalar(curve(), to_rep(curve(), r.m_val));
478 }
479
480 auto nx = x + y;
481
482 /*
483 * Otherwise either b > a or a > b
484 *
485 * If b > a we want to set b to b - a
486 * Otherwise we want to set a to a - b
487 *
488 * Compute r = b - a and check if it underflowed
489 * If it did not then we are in the b > a path
490 */
491 std::array<W, N> r{};
492 const word carry = bigint_sub3(r.data(), b.data(), N, a.data(), N);
493
494 // Conditional ok: this function is variable time
495 if(carry == 0) {
496 // b > a
497 b.m_val = r;
498 x = nx;
499 GenericScalar::_invert_vartime_div2_helper(b, x);
500 } else {
501 // We know this can't underflow because a > b
502 bigint_sub3(r.data(), a.data(), N, b.data(), N);
503 a.m_val = r;
504 y = nx;
505 GenericScalar::_invert_vartime_div2_helper(a, y);
506 }
507 }
508 }
509
510 template <concepts::resizable_byte_buffer T>
511 T serialize() const {
512 T bytes(m_curve->_params().order_bytes());
513 this->serialize_to(bytes);
514 return bytes;
515 }
516
517 void serialize_to(std::span<uint8_t> bytes) const {
518 auto v = from_rep(m_curve, m_val);
519 std::reverse(v.begin(), v.end());
520
521 const size_t flen = m_curve->_params().order_bytes();
522 BOTAN_ARG_CHECK(bytes.size() == flen, "Expected output span provided");
523
524 // Remove leading zero bytes
525 const auto padded_bytes = store_be(v);
526 const size_t extra = N * WordInfo<W>::bytes - flen;
527 copy_mem(bytes, std::span{padded_bytes}.subspan(extra, flen));
528 }
529
530 CT::Choice is_zero() const { return CT::all_zeros(m_val.data(), m_curve->_params().words()).as_choice(); }
531
532 CT::Choice is_nonzero() const { return !is_zero(); }
533
534 CT::Choice operator==(const GenericScalar& other) const {
535 if(this->m_curve != other.m_curve) {
536 return CT::Choice::no();
537 }
538
539 return CT::is_equal(m_val.data(), other.m_val.data(), m_curve->_params().words()).as_choice();
540 }
541
542 /**
543 * Convert the integer to standard representation and return the sequence of words
544 */
545 StorageUnit to_words() const { return from_rep(m_curve, m_val); }
546
547 const StorageUnit& stash_value() const { return m_val; }
548
549 const GenericPrimeOrderCurve* curve() const { return m_curve; }
550
551 GenericScalar(const GenericPrimeOrderCurve* curve, StorageUnit val) : m_curve(curve), m_val(val) {}
552
553 private:
554 const StorageUnit& value() const { return m_val; }
555
556 const W* data() const { return m_val.data(); }
557
558 static const GenericPrimeOrderCurve* check_curve(const GenericScalar& a, const GenericScalar& b) {
559 BOTAN_STATE_CHECK(a.m_curve == b.m_curve);
560 return a.m_curve;
561 }
562
563 static StorageUnit redc(const GenericPrimeOrderCurve* curve, std::array<W, 2 * N> z) {
564 const auto& mod = curve->_params().order();
565 const size_t words = curve->_params().words();
566 StorageUnit r{};
567 StorageUnit ws{};
569 r.data(), z.data(), mod.data(), words, curve->_params().order_p_dash(), ws.data(), ws.size());
570 return r;
571 }
572
573 static StorageUnit from_rep(const GenericPrimeOrderCurve* curve, StorageUnit z) {
574 std::array<W, 2 * N> ze{};
575 copy_mem(std::span{ze}.template first<N>(), z);
576 return redc(curve, ze);
577 }
578
579 static StorageUnit to_rep(const GenericPrimeOrderCurve* curve, StorageUnit x) {
580 std::array<W, 2 * N> z; // NOLINT(*-member-init)
581 curve->_params().mul(z, x, curve->_params().order_monty_r2());
582 return redc(curve, z);
583 }
584
585 static StorageUnit wide_to_rep(const GenericPrimeOrderCurve* curve, std::array<W, 2 * N> x) {
586 auto redc_x = redc(curve, x);
587 std::array<W, 2 * N> z; // NOLINT(*-member-init)
588 curve->_params().mul(z, redc_x, curve->_params().order_monty_r3());
589 return redc(curve, z);
590 }
591
592 const GenericPrimeOrderCurve* m_curve;
593 StorageUnit m_val;
594};
595
596namespace {
597
598class GenericField final {
599 public:
600 typedef word W;
601 typedef PrimeOrderCurve::StorageUnit StorageUnit;
602 static constexpr size_t N = PrimeOrderCurve::StorageWords;
603
604 static std::optional<GenericField> deserialize(const GenericPrimeOrderCurve* curve,
605 std::span<const uint8_t> bytes) {
606 const size_t len = curve->_params().field_bytes();
607
608 if(bytes.size() != len) {
609 return {};
610 }
611
612 const auto words = bytes_to_words<N>(bytes);
613
614 if(words) {
615 if(!bigint_ct_is_lt(words->data(), N, curve->_params().field().data(), N).as_bool()) {
616 return {};
617 }
618
619 // Safe because we checked above that words is an integer < P
620 return GenericField::from_words(curve, *words);
621 } else {
622 return {};
623 }
624 }
625
626 static GenericField from_words(const GenericPrimeOrderCurve* curve, const std::array<word, N>& words) {
627 return GenericField(curve, to_rep(curve, words));
628 }
629
630 static GenericField zero(const GenericPrimeOrderCurve* curve) {
631 const StorageUnit zeros{};
632 return GenericField(curve, zeros);
633 }
634
635 static GenericField one(const GenericPrimeOrderCurve* curve) {
636 return GenericField(curve, curve->_params().field_monty_r1());
637 }
638
639 static GenericField curve_a(const GenericPrimeOrderCurve* curve) {
640 return GenericField(curve, curve->_params().monty_curve_a());
641 }
642
643 static GenericField curve_b(const GenericPrimeOrderCurve* curve) {
644 return GenericField(curve, curve->_params().monty_curve_b());
645 }
646
647 static GenericField random(const GenericPrimeOrderCurve* curve, RandomNumberGenerator& rng) {
648 constexpr size_t MAX_ATTEMPTS = 1000;
649
650 const size_t bits = curve->_params().field_bits();
651
652 std::vector<uint8_t> buf(curve->_params().field_bytes());
653
654 for(size_t i = 0; i != MAX_ATTEMPTS; ++i) {
655 rng.randomize(buf);
656
657 // Zero off high bits that if set would certainly cause us
658 // to be out of range
659 if(bits % 8 != 0) {
660 const uint8_t mask = 0xFF >> (8 - (bits % 8));
661 buf[0] &= mask;
662 }
663
664 if(auto s = GenericField::deserialize(curve, buf)) {
665 if(s.value().is_nonzero().as_bool()) {
666 return s.value();
667 }
668 }
669 }
670
671 throw Internal_Error("Failed to generate random Scalar within bounded number of attempts");
672 }
673
674 /**
675 * Return the value of this divided by 2
676 */
677 GenericField div2() const {
678 StorageUnit t = value();
679 const W borrow = shift_right<1>(t);
680
681 // If value was odd, add (P/2)+1
682 bigint_cnd_add(borrow, t.data(), m_curve->_params().field_inv_2().data(), N);
683
684 return GenericField(m_curve, t);
685 }
686
687 /// Return (*this) multiplied by 2
688 GenericField mul2() const {
689 StorageUnit t = value();
690 const W carry = shift_left<1>(t);
691
692 StorageUnit r;
693 bigint_monty_maybe_sub<N>(r.data(), carry, t.data(), m_curve->_params().field().data());
694 return GenericField(m_curve, r);
695 }
696
697 /// Return (*this) multiplied by 3
698 GenericField mul3() const { return mul2() + (*this); }
699
700 /// Return (*this) multiplied by 4
701 GenericField mul4() const { return mul2().mul2(); }
702
703 /// Return (*this) multiplied by 8
704 GenericField mul8() const { return mul2().mul2().mul2(); }
705
706 friend GenericField operator+(const GenericField& a, const GenericField& b) {
707 const auto* curve = check_curve(a, b);
708 const size_t words = curve->_params().words();
709
710 StorageUnit t{};
711 const W carry = bigint_add3(t.data(), a.data(), words, b.data(), words);
712
713 StorageUnit r{};
714 bigint_monty_maybe_sub(words, r.data(), carry, t.data(), curve->_params().field().data());
715 return GenericField(curve, r);
716 }
717
718 friend GenericField operator-(const GenericField& a, const GenericField& b) { return a + b.negate(); }
719
720 friend GenericField operator*(const GenericField& a, const GenericField& b) {
721 const auto* curve = check_curve(a, b);
722
723 std::array<W, 2 * N> z; // NOLINT(*-member-init)
724 curve->_params().mul(z, a.value(), b.value());
725 return GenericField(curve, redc(curve, z));
726 }
727
728 GenericField& operator*=(const GenericField& other) {
729 const auto* curve = check_curve(*this, other);
730
731 std::array<W, 2 * N> z; // NOLINT(*-member-init)
732 curve->_params().mul(z, value(), other.value());
733 m_val = redc(curve, z);
734 return (*this);
735 }
736
737 GenericField square() const {
738 std::array<W, 2 * N> z; // NOLINT(*-member-init)
739 m_curve->_params().sqr(z, value());
740 return GenericField(m_curve, redc(m_curve, z));
741 }
742
743 GenericField pow_vartime(const StorageUnit& exp) const {
744 auto one = GenericField::one(curve());
745 auto bits = curve()->_params().field_bits();
746 auto words = curve()->_params().words();
747 return impl_pow_vartime(*this, one, bits, std::span{exp}.last(words));
748 }
749
750 GenericField negate() const {
751 auto x_is_zero = CT::all_zeros(this->data(), N);
752
753 StorageUnit r;
754 bigint_sub3(r.data(), m_curve->_params().field().data(), N, this->data(), N);
755 x_is_zero.if_set_zero_out(r.data(), N);
756 return GenericField(m_curve, r);
757 }
758
759 GenericField invert() const { return pow_vartime(m_curve->_params().field_minus_2()); }
760
761 GenericField invert_vartime() const {
762 // TODO take advantage of variable time here using eg BEEA
763 // see IntMod::invert_vartime in pcurves_impl.h
764 return invert();
765 }
766
767 template <concepts::resizable_byte_buffer T>
768 T serialize() const {
769 T bytes(m_curve->_params().field_bytes());
770 serialize_to(bytes);
771 return bytes;
772 }
773
774 void serialize_to(std::span<uint8_t> bytes) const {
775 auto v = from_rep(m_curve, m_val);
776 std::reverse(v.begin(), v.end());
777
778 const size_t flen = m_curve->_params().field_bytes();
779 BOTAN_ARG_CHECK(bytes.size() == flen, "Expected output span provided");
780
781 // Remove leading zero bytes
782 const auto padded_bytes = store_be(v);
783 const size_t extra = N * WordInfo<W>::bytes - flen;
784 copy_mem(bytes, std::span{padded_bytes}.subspan(extra, flen));
785 }
786
787 CT::Choice is_zero() const { return CT::all_zeros(m_val.data(), m_curve->_params().words()).as_choice(); }
788
789 CT::Choice is_nonzero() const { return !is_zero(); }
790
791 CT::Choice operator==(const GenericField& other) const {
792 if(this->m_curve != other.m_curve) {
793 return CT::Choice::no();
794 }
795
796 return CT::is_equal(m_val.data(), other.m_val.data(), m_curve->_params().words()).as_choice();
797 }
798
799 const StorageUnit& stash_value() const { return m_val; }
800
801 const GenericPrimeOrderCurve* curve() const { return m_curve; }
802
803 CT::Choice is_even() const {
804 auto v = from_rep(m_curve, m_val);
805 return !CT::Choice::from_int(v[0] & 0x01);
806 }
807
808 /**
809 * Convert the integer to standard representation and return the sequence of words
810 */
811 StorageUnit to_words() const { return from_rep(m_curve, m_val); }
812
813 void _const_time_poison() const { CT::poison(m_val); }
814
815 void _const_time_unpoison() const { CT::unpoison(m_val); }
816
817 static void conditional_swap(CT::Choice cond, GenericField& x, GenericField& y) {
818 const W mask = cond.into_bitmask<W>();
819
820 for(size_t i = 0; i != N; ++i) {
821 auto nx = choose(mask, y.m_val[i], x.m_val[i]);
822 auto ny = choose(mask, x.m_val[i], y.m_val[i]);
823 x.m_val[i] = nx;
824 y.m_val[i] = ny;
825 }
826 }
827
828 void conditional_assign(CT::Choice cond, const GenericField& nx) {
829 const W mask = cond.into_bitmask<W>();
830
831 for(size_t i = 0; i != N; ++i) {
832 m_val[i] = choose(mask, nx.m_val[i], m_val[i]);
833 }
834 }
835
836 /**
837 * Conditional assignment
838 *
839 * If `cond` is true, sets `x` to `nx` and `y` to `ny`
840 */
841 static void conditional_assign(
842 GenericField& x, GenericField& y, CT::Choice cond, const GenericField& nx, const GenericField& ny) {
843 const W mask = cond.into_bitmask<W>();
844
845 for(size_t i = 0; i != N; ++i) {
846 x.m_val[i] = choose(mask, nx.m_val[i], x.m_val[i]);
847 y.m_val[i] = choose(mask, ny.m_val[i], y.m_val[i]);
848 }
849 }
850
851 /**
852 * Conditional assignment
853 *
854 * If `cond` is true, sets `x` to `nx`, `y` to `ny`, and `z` to `nz`
855 */
856 static void conditional_assign(GenericField& x,
857 GenericField& y,
858 GenericField& z,
859 CT::Choice cond,
860 const GenericField& nx,
861 const GenericField& ny,
862 const GenericField& nz) {
863 const W mask = cond.into_bitmask<W>();
864
865 for(size_t i = 0; i != N; ++i) {
866 x.m_val[i] = choose(mask, nx.m_val[i], x.m_val[i]);
867 y.m_val[i] = choose(mask, ny.m_val[i], y.m_val[i]);
868 z.m_val[i] = choose(mask, nz.m_val[i], z.m_val[i]);
869 }
870 }
871
872 std::pair<GenericField, CT::Choice> sqrt() const {
873 BOTAN_STATE_CHECK(m_curve->_params().field()[0] % 4 == 3);
874
875 auto z = pow_vartime(m_curve->_params().field_p_plus_1_over_4());
876 const CT::Choice correct = (z.square() == *this);
877 // Zero out the return value if it would otherwise be incorrect
878 z.conditional_assign(!correct, zero(m_curve));
879 return {z, correct};
880 }
881
882 GenericField(const GenericPrimeOrderCurve* curve, StorageUnit val) : m_curve(curve), m_val(val) {}
883
884 private:
885 const StorageUnit& value() const { return m_val; }
886
887 const W* data() const { return m_val.data(); }
888
889 static const GenericPrimeOrderCurve* check_curve(const GenericField& a, const GenericField& b) {
890 BOTAN_STATE_CHECK(a.m_curve == b.m_curve);
891 return a.m_curve;
892 }
893
894 static StorageUnit redc(const GenericPrimeOrderCurve* curve, std::array<W, 2 * N> z) {
895 const auto& mod = curve->_params().field();
896 const size_t words = curve->_params().words();
897 StorageUnit r{};
898 StorageUnit ws{};
900 r.data(), z.data(), mod.data(), words, curve->_params().field_p_dash(), ws.data(), ws.size());
901 return r;
902 }
903
904 static StorageUnit from_rep(const GenericPrimeOrderCurve* curve, StorageUnit z) {
905 std::array<W, 2 * N> ze{};
906 copy_mem(std::span{ze}.template first<N>(), z);
907 return redc(curve, ze);
908 }
909
910 static StorageUnit to_rep(const GenericPrimeOrderCurve* curve, StorageUnit x) {
911 std::array<W, 2 * N> z{};
912 curve->_params().mul(z, x, curve->_params().field_monty_r2());
913 return redc(curve, z);
914 }
915
916 const GenericPrimeOrderCurve* m_curve;
917 StorageUnit m_val;
918};
919
920} // namespace
921
922/**
923* Affine Curve Point
924*
925* This contains a pair of integers (x,y) which satisfy the curve equation
926*/
927class GenericAffinePoint final {
928 public:
929 GenericAffinePoint(const GenericField& x, const GenericField& y) : m_x(x), m_y(y) {}
930
931 explicit GenericAffinePoint(const GenericPrimeOrderCurve* curve) :
932 m_x(GenericField::zero(curve)), m_y(GenericField::zero(curve)) {}
933
934 static GenericAffinePoint identity(const GenericPrimeOrderCurve* curve) {
935 return GenericAffinePoint(GenericField::zero(curve), GenericField::zero(curve));
936 }
937
938 static GenericAffinePoint identity(const GenericAffinePoint& pt) { return identity(pt.curve()); }
939
940 CT::Choice is_identity() const { return x().is_zero() && y().is_zero(); }
941
942 GenericAffinePoint negate() const { return GenericAffinePoint(x(), y().negate()); }
943
944 /**
945 * Serialize the point in uncompressed format
946 */
947 void serialize_to(std::span<uint8_t> bytes) const {
948 const size_t fe_bytes = curve()->_params().field_bytes();
949 BOTAN_ARG_CHECK(bytes.size() == 1 + 2 * fe_bytes, "Buffer size incorrect");
950 BOTAN_STATE_CHECK(this->is_identity().as_bool() == false);
951 BufferStuffer pack(bytes);
952 pack.append(0x04);
953 x().serialize_to(pack.next(fe_bytes));
954 y().serialize_to(pack.next(fe_bytes));
955 BOTAN_DEBUG_ASSERT(pack.full());
956 }
957
958 /**
959 * If idx is zero then return the identity element. Otherwise return pts[idx - 1]
960 *
961 * Returns the identity element also if idx is out of range
962 */
963 static auto ct_select(std::span<const GenericAffinePoint> pts, size_t idx) {
964 BOTAN_ARG_CHECK(!pts.empty(), "Cannot select from an empty set");
965 auto result = GenericAffinePoint::identity(pts[0].curve());
966
967 // Intentionally wrapping; set to maximum size_t if idx == 0
968 const size_t idx1 = static_cast<size_t>(idx - 1);
969 for(size_t i = 0; i != pts.size(); ++i) {
970 const auto found = CT::Mask<size_t>::is_equal(idx1, i).as_choice();
971 result.conditional_assign(found, pts[i]);
972 }
973
974 return result;
975 }
976
977 /**
978 * Return (x^3 + A*x + B) mod p
979 */
980 static GenericField x3_ax_b(const GenericField& x) {
981 return (x.square() + GenericField::curve_a(x.curve())) * x + GenericField::curve_b(x.curve());
982 }
983
984 /**
985 * Point deserialization (SEC1 uncompressed format only)
986 */
987 static std::optional<GenericAffinePoint> deserialize_uncompressed(const GenericPrimeOrderCurve* curve,
988 std::span<const uint8_t> bytes) {
989 const size_t fe_bytes = curve->_params().field_bytes();
990
991 if(bytes.size() == 1 + 2 * fe_bytes && bytes[0] == 0x04) {
992 auto x = GenericField::deserialize(curve, bytes.subspan(1, fe_bytes));
993 auto y = GenericField::deserialize(curve, bytes.subspan(1 + fe_bytes, fe_bytes));
994
995 if(x && y) {
996 const auto lhs = (*y).square();
997 const auto rhs = GenericAffinePoint::x3_ax_b(*x);
998 if((lhs == rhs).as_bool()) {
999 return GenericAffinePoint(*x, *y);
1000 }
1001 }
1002 }
1003
1004 return {};
1005 }
1006
1007 /**
1008 * Point deserialization (SEC1 compressed format only)
1009 */
1010 static std::optional<GenericAffinePoint> deserialize_compressed(const GenericPrimeOrderCurve* curve,
1011 std::span<const uint8_t> bytes) {
1012 const size_t fe_bytes = curve->_params().field_bytes();
1013
1014 if(bytes.size() == 1 + fe_bytes && (bytes[0] == 0x02 || bytes[0] == 0x03)) {
1015 const CT::Choice y_is_even = CT::Mask<uint8_t>::is_equal(bytes[0], 0x02).as_choice();
1016
1017 if(auto x = GenericField::deserialize(curve, bytes.subspan(1, fe_bytes))) {
1018 auto [y, is_square] = x3_ax_b(*x).sqrt();
1019
1020 if(is_square.as_bool()) {
1021 const auto flip_y = y_is_even != y.is_even();
1022 y.conditional_assign(flip_y, y.negate());
1023 return GenericAffinePoint(*x, y);
1024 }
1025 }
1026 }
1027
1028 return {};
1029 }
1030
1031 /**
1032 * Return the affine x coordinate
1033 */
1034 const GenericField& x() const { return m_x; }
1035
1036 /**
1037 * Return the affine y coordinate
1038 */
1039 const GenericField& y() const { return m_y; }
1040
1041 /**
1042 * Conditional assignment of an affine point
1043 */
1044 void conditional_assign(CT::Choice cond, const GenericAffinePoint& pt) {
1045 GenericField::conditional_assign(m_x, m_y, cond, pt.x(), pt.y());
1046 }
1047
1048 const GenericPrimeOrderCurve* curve() const { return m_x.curve(); }
1049
1050 void _const_time_poison() const { CT::poison_all(m_x, m_y); }
1051
1052 void _const_time_unpoison() const { CT::unpoison_all(m_x, m_y); }
1053
1054 private:
1055 GenericField m_x;
1056 GenericField m_y;
1057};
1058
1059class GenericProjectivePoint final {
1060 public:
1061 typedef GenericProjectivePoint Self;
1062
1063 using FieldElement = GenericField;
1064
1065 /**
1066 * Convert a point from affine to projective form
1067 */
1068 static Self from_affine(const GenericAffinePoint& pt) {
1069 auto x = pt.x();
1070 auto y = pt.y();
1071 auto z = GenericField::one(x.curve());
1072
1073 // If pt is identity (0,0) swap y/z to convert (0,0,1) into (0,1,0)
1074 GenericField::conditional_swap(pt.is_identity(), y, z);
1075 return GenericProjectivePoint(x, y, z);
1076 }
1077
1078 /**
1079 * Return the identity element
1080 */
1081 static Self identity(const GenericPrimeOrderCurve* curve) {
1082 return Self(GenericField::zero(curve), GenericField::one(curve), GenericField::zero(curve));
1083 }
1084
1085 /**
1086 * Default constructor: the identity element
1087 */
1088 explicit GenericProjectivePoint(const GenericPrimeOrderCurve* curve) :
1089 m_x(GenericField::zero(curve)), m_y(GenericField::one(curve)), m_z(GenericField::zero(curve)) {}
1090
1091 /**
1092 * Affine constructor: take x/y coordinates
1093 */
1094 GenericProjectivePoint(const GenericField& x, const GenericField& y) :
1095 m_x(x), m_y(y), m_z(GenericField::one(m_x.curve())) {}
1096
1097 /**
1098 * Projective constructor: take x/y/z coordinates
1099 */
1100 GenericProjectivePoint(const GenericField& x, const GenericField& y, const GenericField& z) :
1101 m_x(x), m_y(y), m_z(z) {}
1102
1103 friend Self operator+(const Self& a, const Self& b) { return Self::add(a, b); }
1104
1105 friend Self operator+(const Self& a, const GenericAffinePoint& b) { return Self::add_mixed(a, b); }
1106
1107 friend Self operator+(const GenericAffinePoint& a, const Self& b) { return Self::add_mixed(b, a); }
1108
1109 Self& operator+=(const Self& other) {
1110 (*this) = (*this) + other;
1111 return (*this);
1112 }
1113
1114 Self& operator+=(const GenericAffinePoint& other) {
1115 (*this) = (*this) + other;
1116 return (*this);
1117 }
1118
1119 CT::Choice is_identity() const { return z().is_zero(); }
1120
1121 void conditional_assign(CT::Choice cond, const Self& pt) {
1122 GenericField::conditional_assign(m_x, m_y, m_z, cond, pt.x(), pt.y(), pt.z());
1123 }
1124
1125 /**
1126 * Mixed (projective + affine) point addition
1127 */
1128 static Self add_mixed(const Self& a, const GenericAffinePoint& b) {
1129 return point_add_mixed<Self, GenericAffinePoint, GenericField>(a, b, GenericField::one(a.curve()));
1130 }
1131
1132 static Self add_or_sub(const Self& a, const GenericAffinePoint& b, CT::Choice sub) {
1133 return point_add_or_sub_mixed<Self, GenericAffinePoint, GenericField>(a, b, sub, GenericField::one(a.curve()));
1134 }
1135
1136 /**
1137 * Projective point addition
1138 */
1139 static Self add(const Self& a, const Self& b) { return point_add<Self, GenericField>(a, b); }
1140
1141 /**
1142 * Iterated point doubling
1143 */
1144 Self dbl_n(size_t n) const {
1145 if(curve()->_params().a_is_minus_3()) {
1146 return dbl_n_a_minus_3(*this, n);
1147 } else if(curve()->_params().a_is_zero()) {
1148 return dbl_n_a_zero(*this, n);
1149 } else {
1150 const auto A = GenericField::curve_a(curve());
1151 return dbl_n_generic(*this, A, n);
1152 }
1153 }
1154
1155 /**
1156 * Point doubling
1157 */
1158 Self dbl() const {
1159 if(curve()->_params().a_is_minus_3()) {
1160 return dbl_a_minus_3(*this);
1161 } else if(curve()->_params().a_is_zero()) {
1162 return dbl_a_zero(*this);
1163 } else {
1164 const auto A = GenericField::curve_a(curve());
1165 return dbl_generic(*this, A);
1166 }
1167 }
1168
1169 /**
1170 * Point negation
1171 */
1172 Self negate() const { return Self(x(), y().negate(), z()); }
1173
1174 /**
1175 * Randomize the point representation
1176 *
1177 * Projective coordinates are redundant; if (x,y,z) is a projective
1178 * point then so is (x*r^2,y*r^3,z*r) for any non-zero r.
1179 */
1180 void randomize_rep(RandomNumberGenerator& rng) {
1181 // In certain contexts we may be called with a Null_RNG; in that case the
1182 // caller is accepting that randomization will not occur
1183
1184 if(rng.is_seeded()) {
1185 auto r = GenericField::random(curve(), rng);
1186
1187 auto r2 = r.square();
1188 auto r3 = r2 * r;
1189
1190 m_x *= r2;
1191 m_y *= r3;
1192 m_z *= r;
1193 }
1194 }
1195
1196 /**
1197 * Return the projective x coordinate
1198 */
1199 const GenericField& x() const { return m_x; }
1200
1201 /**
1202 * Return the projective y coordinate
1203 */
1204 const GenericField& y() const { return m_y; }
1205
1206 /**
1207 * Return the projective z coordinate
1208 */
1209 const GenericField& z() const { return m_z; }
1210
1211 const GenericPrimeOrderCurve* curve() const { return m_x.curve(); }
1212
1213 void _const_time_poison() const { CT::poison_all(m_x, m_y, m_z); }
1214
1215 void _const_time_unpoison() const { CT::unpoison_all(m_x, m_y, m_z); }
1216
1217 private:
1218 GenericField m_x;
1219 GenericField m_y;
1220 GenericField m_z;
1221};
1222
1223namespace {
1224
1225class GenericCurve final {
1226 public:
1227 typedef GenericField FieldElement;
1228 typedef GenericScalar Scalar;
1229 typedef GenericAffinePoint AffinePoint;
1230 typedef GenericProjectivePoint ProjectivePoint;
1231
1232 typedef word WordType;
1233};
1234
1235class GenericBlindedScalarBits final {
1236 public:
1237 GenericBlindedScalarBits(const GenericScalar& scalar, RandomNumberGenerator& rng, size_t wb) {
1238 BOTAN_ASSERT_NOMSG(wb == 1 || wb == 2 || wb == 3 || wb == 4 || wb == 5 || wb == 6 || wb == 7);
1239
1240 const auto& params = scalar.curve()->_params();
1241
1242 const size_t order_bits = params.order_bits();
1243 m_window_bits = wb;
1244
1245 const size_t blinder_bits = scalar_blinding_bits(order_bits);
1246
1247 if(blinder_bits > 0 && rng.is_seeded()) {
1248 const size_t mask_words = (blinder_bits + WordInfo<word>::bits - 1) / WordInfo<word>::bits;
1249 const size_t mask_bytes = mask_words * WordInfo<word>::bytes;
1250
1251 const size_t words = params.words();
1252
1253 secure_vector<uint8_t> maskb(mask_bytes);
1254 rng.randomize(maskb);
1255
1256 std::array<word, PrimeOrderCurve::StorageWords> mask{};
1257 load_le(mask.data(), maskb.data(), mask_words);
1258
1259 // Mask to exactly blinder_bits and set MSB and LSB
1260 const size_t excess = mask_words * WordInfo<word>::bits - blinder_bits;
1261 if(excess > 0) {
1262 mask[mask_words - 1] &= (static_cast<word>(1) << (WordInfo<word>::bits - excess)) - 1;
1263 }
1264 const size_t msb_pos = (blinder_bits - 1) % WordInfo<word>::bits;
1265 mask[(blinder_bits - 1) / WordInfo<word>::bits] |= static_cast<word>(1) << msb_pos;
1266 mask[0] |= 1;
1267
1268 std::array<word, 2 * PrimeOrderCurve::StorageWords> mask_n{};
1269
1270 const auto sw = scalar.to_words();
1271
1272 // Compute masked scalar s + k*n
1273 params.mul(mask_n, mask, params.order());
1274 bigint_add2(mask_n.data(), 2 * words, sw.data(), words);
1275
1276 std::reverse(mask_n.begin(), mask_n.end());
1277 m_bytes = store_be<std::vector<uint8_t>>(mask_n);
1278 m_bits = order_bits + blinder_bits;
1279 } else {
1280 // No RNG available, skip blinding
1281 m_bytes = scalar.serialize<std::vector<uint8_t>>();
1282 m_bits = order_bits;
1283 }
1284
1285 m_windows = (m_bits + wb - 1) / wb;
1286 }
1287
1288 size_t windows() const { return m_windows; }
1289
1290 size_t bits() const { return m_bits; }
1291
1292 size_t get_window(size_t offset) const {
1293 if(m_window_bits == 1) {
1294 return read_window_bits<1>(std::span{m_bytes}, offset);
1295 } else if(m_window_bits == 2) {
1296 return read_window_bits<2>(std::span{m_bytes}, offset);
1297 } else if(m_window_bits == 3) {
1298 return read_window_bits<3>(std::span{m_bytes}, offset);
1299 } else if(m_window_bits == 4) {
1300 return read_window_bits<4>(std::span{m_bytes}, offset);
1301 } else if(m_window_bits == 5) {
1302 return read_window_bits<5>(std::span{m_bytes}, offset);
1303 } else if(m_window_bits == 6) {
1304 return read_window_bits<6>(std::span{m_bytes}, offset);
1305 } else if(m_window_bits == 7) {
1306 return read_window_bits<7>(std::span{m_bytes}, offset);
1307 } else {
1309 }
1310 }
1311
1312 private:
1313 std::vector<uint8_t> m_bytes;
1314 size_t m_bits;
1315 size_t m_windows;
1316 size_t m_window_bits;
1317};
1318
1319class GenericWindowedMul final {
1320 public:
1321 static constexpr size_t WindowBits = VarPointWindowBits;
1322 static constexpr size_t TableSize = (1 << WindowBits) - 1;
1323
1324 explicit GenericWindowedMul(const GenericAffinePoint& pt) :
1325 m_table(varpoint_setup<GenericCurve, TableSize>(pt)) {}
1326
1327 GenericProjectivePoint mul(const GenericScalar& s, RandomNumberGenerator& rng) {
1328 const GenericBlindedScalarBits bits(s, rng, WindowBits);
1329
1330 return varpoint_exec<GenericCurve, WindowBits>(m_table, bits, rng);
1331 }
1332
1333 private:
1334 AffinePointTable<GenericCurve> m_table;
1335};
1336
1337} // namespace
1338
1339class GenericBaseMulTable final {
1340 public:
1341 static constexpr size_t WindowBits = BasePointWindowBits;
1342
1343 // +1 for Booth carry from the top window
1344 explicit GenericBaseMulTable(const GenericAffinePoint& pt) :
1345 m_table(basemul_booth_setup<GenericCurve, WindowBits>(pt, blinded_scalar_bits(*pt.curve()) + 1)) {}
1346
1347 GenericProjectivePoint mul(const GenericScalar& s, RandomNumberGenerator& rng) {
1348 // W+1 bit windows for Booth recoding overlap
1349 const GenericBlindedScalarBits scalar(s, rng, WindowBits + 1);
1350 return basemul_booth_exec<GenericCurve, WindowBits>(m_table, scalar, rng);
1351 }
1352
1353 private:
1354 static size_t blinded_scalar_bits(const GenericPrimeOrderCurve& curve) {
1355 const size_t order_bits = curve.order_bits();
1356 return order_bits + scalar_blinding_bits(order_bits);
1357 }
1358
1359 std::vector<GenericAffinePoint> m_table;
1360};
1361
1362namespace {
1363
1364class GenericWindowedMul2 final {
1365 public:
1366 static constexpr size_t WindowBits = Mul2PrecompWindowBits;
1367
1368 GenericWindowedMul2(const GenericWindowedMul2& other) = delete;
1369 GenericWindowedMul2(GenericWindowedMul2&& other) = delete;
1370 GenericWindowedMul2& operator=(const GenericWindowedMul2& other) = delete;
1371 GenericWindowedMul2& operator=(GenericWindowedMul2&& other) = delete;
1372
1373 ~GenericWindowedMul2() = default;
1374
1375 GenericWindowedMul2(const GenericAffinePoint& p, const GenericAffinePoint& q) :
1376 m_table(mul2_setup<GenericCurve, WindowBits>(p, q)) {}
1377
1378 GenericProjectivePoint mul2(const GenericScalar& x, const GenericScalar& y, RandomNumberGenerator& rng) const {
1379 const GenericBlindedScalarBits x_bits(x, rng, WindowBits);
1380 const GenericBlindedScalarBits y_bits(y, rng, WindowBits);
1381 return mul2_exec<GenericCurve, WindowBits>(m_table, x_bits, y_bits, rng);
1382 }
1383
1384 private:
1385 AffinePointTable<GenericCurve> m_table;
1386};
1387
1388class GenericVartimeWindowedMul2 final : public PrimeOrderCurve::PrecomputedMul2Table {
1389 public:
1390 static constexpr size_t WindowBits = Mul2PrecompWindowBits;
1391
1392 GenericVartimeWindowedMul2(const GenericVartimeWindowedMul2& other) = delete;
1393 GenericVartimeWindowedMul2(GenericVartimeWindowedMul2&& other) = delete;
1394 GenericVartimeWindowedMul2& operator=(const GenericVartimeWindowedMul2& other) = delete;
1395 GenericVartimeWindowedMul2& operator=(GenericVartimeWindowedMul2&& other) = delete;
1396
1397 ~GenericVartimeWindowedMul2() override = default;
1398
1399 GenericVartimeWindowedMul2(const GenericAffinePoint& p, const GenericAffinePoint& q) :
1400 m_table(to_affine_batch<GenericCurve, true>(mul2_setup<GenericCurve, WindowBits>(p, q))) {}
1401
1402 GenericProjectivePoint mul2_vartime(const GenericScalar& x, const GenericScalar& y) const {
1403 const auto x_bits = x.serialize<std::vector<uint8_t>>();
1404 const auto y_bits = y.serialize<std::vector<uint8_t>>();
1405
1406 const auto& curve = m_table[0].curve();
1407 auto accum = GenericProjectivePoint(curve);
1408
1409 const size_t order_bits = curve->order_bits();
1410
1411 const size_t windows = (order_bits + WindowBits - 1) / WindowBits;
1412
1413 for(size_t i = 0; i != windows; ++i) {
1414 auto x_i = read_window_bits<WindowBits>(std::span{x_bits}, (windows - i - 1) * WindowBits);
1415 auto y_i = read_window_bits<WindowBits>(std::span{y_bits}, (windows - i - 1) * WindowBits);
1416
1417 if(i > 0) {
1418 accum = accum.dbl_n(WindowBits);
1419 }
1420
1421 const size_t idx = (y_i << WindowBits) + x_i;
1422
1423 if(idx > 0) {
1424 accum += m_table[idx - 1];
1425 }
1426 }
1427
1428 return accum;
1429 }
1430
1431 private:
1432 std::vector<GenericAffinePoint> m_table;
1433};
1434
1435} // namespace
1436
1438 const BigInt& p, const BigInt& a, const BigInt& b, const BigInt& base_x, const BigInt& base_y, const BigInt& order) :
1439 m_params(std::make_unique<GenericCurveParams>(p, a, b, base_x, base_y, order)) {}
1440
1442 BOTAN_STATE_CHECK(m_basemul == nullptr);
1443 m_basemul = std::make_unique<GenericBaseMulTable>(from_stash(generator()));
1444}
1445
1447 return _params().order_bits();
1448}
1449
1451 return _params().order_bytes();
1452}
1453
1455 return _params().field_bytes();
1456}
1457
1459 RandomNumberGenerator& rng) const {
1460 BOTAN_STATE_CHECK(m_basemul != nullptr);
1461 return stash(m_basemul->mul(from_stash(scalar), rng));
1462}
1463
1465 RandomNumberGenerator& rng) const {
1466 BOTAN_STATE_CHECK(m_basemul != nullptr);
1467 auto pt_s = m_basemul->mul(from_stash(scalar), rng);
1468 BOTAN_STATE_CHECK(!pt_s.is_identity().as_bool());
1469 const auto x_bytes = to_affine_x<GenericCurve>(pt_s).serialize<secure_vector<uint8_t>>();
1470 if(auto s = GenericScalar::from_wide_bytes(this, x_bytes)) {
1471 return stash(*s);
1472 } else {
1473 throw Internal_Error("Failed to convert x coordinate to integer modulo scalar");
1474 }
1475}
1476
1478 const Scalar& scalar,
1479 RandomNumberGenerator& rng) const {
1480 GenericWindowedMul pt_table(from_stash(pt));
1481 return stash(pt_table.mul(from_stash(scalar), rng));
1482}
1483
1485 const Scalar& scalar,
1486 RandomNumberGenerator& rng) const {
1487 GenericWindowedMul pt_table(from_stash(pt));
1488 auto pt_s = pt_table.mul(from_stash(scalar), rng);
1489 BOTAN_STATE_CHECK(!pt_s.is_identity().as_bool());
1490 return to_affine_x<GenericCurve>(pt_s).serialize<secure_vector<uint8_t>>();
1491}
1492
1493std::unique_ptr<const PrimeOrderCurve::PrecomputedMul2Table> GenericPrimeOrderCurve::mul2_setup_g(
1494 const AffinePoint& q) const {
1495 return std::make_unique<GenericVartimeWindowedMul2>(from_stash(generator()), from_stash(q));
1496}
1497
1498std::optional<PrimeOrderCurve::ProjectivePoint> GenericPrimeOrderCurve::mul2_vartime(const PrecomputedMul2Table& tableb,
1499 const Scalar& s1,
1500 const Scalar& s2) const {
1501 const auto& tbl = dynamic_cast<const GenericVartimeWindowedMul2&>(tableb);
1502 auto pt = tbl.mul2_vartime(from_stash(s1), from_stash(s2));
1503 if(pt.is_identity().as_bool()) {
1504 return {};
1505 } else {
1506 return stash(pt);
1507 }
1508}
1509
1510std::optional<PrimeOrderCurve::ProjectivePoint> GenericPrimeOrderCurve::mul_px_qy(
1511 const AffinePoint& p, const Scalar& x, const AffinePoint& q, const Scalar& y, RandomNumberGenerator& rng) const {
1512 const GenericWindowedMul2 table(from_stash(p), from_stash(q));
1513 auto pt = table.mul2(from_stash(x), from_stash(y), rng);
1514 if(pt.is_identity().as_bool()) {
1515 return {};
1516 } else {
1517 return stash(pt);
1518 }
1519}
1520
1522 const Scalar& v,
1523 const Scalar& s1,
1524 const Scalar& s2) const {
1525 const auto& tbl = dynamic_cast<const GenericVartimeWindowedMul2&>(tableb);
1526 auto pt = tbl.mul2_vartime(from_stash(s1), from_stash(s2));
1527
1528 if(!pt.is_identity().as_bool()) {
1529 const auto z2 = pt.z().square();
1530
1531 const auto v_bytes = from_stash(v).serialize<std::vector<uint8_t>>();
1532
1533 if(auto fe_v = GenericField::deserialize(this, v_bytes)) {
1534 if((*fe_v * z2 == pt.x()).as_bool()) {
1535 return true;
1536 }
1537
1538 if(_params().order_is_less_than_field()) {
1539 const auto n = GenericField::from_words(this, _params().order());
1540 const auto neg_n = n.negate().to_words();
1541
1542 const auto vw = fe_v->to_words();
1543 if(bigint_ct_is_lt(vw.data(), vw.size(), neg_n.data(), neg_n.size()).as_bool()) {
1544 return (((*fe_v + n) * z2) == pt.x()).as_bool();
1545 }
1546 }
1547 }
1548 }
1549
1550 return false;
1551}
1552
1554 return PrimeOrderCurve::AffinePoint::_create(shared_from_this(), _params().base_x(), _params().base_y());
1555}
1556
1558 return stash(GenericAffinePoint::identity(this));
1559}
1560
1562 auto affine = to_affine<GenericCurve>(from_stash(pt));
1563
1564 const auto y2 = affine.y().square();
1565 const auto x3_ax_b = GenericCurve::AffinePoint::x3_ax_b(affine.x());
1566 const auto valid_point = affine.is_identity() || (y2 == x3_ax_b);
1567
1568 BOTAN_ASSERT(valid_point.as_bool(), "Computed point is on the curve");
1569
1570 return stash(affine);
1571}
1572
1574 return stash(GenericProjectivePoint::from_affine(from_stash(a)) + from_stash(b));
1575}
1576
1578 return stash(from_stash(pt).negate());
1579}
1580
1582 return from_stash(pt).is_identity().as_bool();
1583}
1584
1585void GenericPrimeOrderCurve::serialize_point(std::span<uint8_t> bytes, const AffinePoint& pt) const {
1586 from_stash(pt).serialize_to(bytes);
1587}
1588
1589void GenericPrimeOrderCurve::serialize_scalar(std::span<uint8_t> bytes, const Scalar& scalar) const {
1590 BOTAN_ARG_CHECK(bytes.size() == _params().order_bytes(), "Invalid length to serialize_scalar");
1591 from_stash(scalar).serialize_to(bytes);
1592}
1593
1594std::optional<PrimeOrderCurve::Scalar> GenericPrimeOrderCurve::deserialize_scalar(
1595 std::span<const uint8_t> bytes) const {
1596 if(auto s = GenericScalar::deserialize(this, bytes)) {
1597 if(s->is_nonzero().as_bool()) {
1598 return stash(s.value());
1599 }
1600 }
1601
1602 return {};
1603}
1604
1605std::optional<PrimeOrderCurve::Scalar> GenericPrimeOrderCurve::scalar_from_wide_bytes(
1606 std::span<const uint8_t> bytes) const {
1607 if(auto s = GenericScalar::from_wide_bytes(this, bytes)) {
1608 return stash(s.value());
1609 } else {
1610 return {};
1611 }
1612}
1613
1614std::optional<PrimeOrderCurve::AffinePoint> GenericPrimeOrderCurve::deserialize_point_uncompressed(
1615 std::span<const uint8_t> bytes) const {
1616 if(auto pt = GenericAffinePoint::deserialize_uncompressed(this, bytes)) {
1617 return stash(pt.value());
1618 } else {
1619 return {};
1620 }
1621}
1622
1623std::optional<PrimeOrderCurve::AffinePoint> GenericPrimeOrderCurve::deserialize_point_compressed(
1624 std::span<const uint8_t> bytes) const {
1625 if(auto pt = GenericAffinePoint::deserialize_compressed(this, bytes)) {
1626 return stash(pt.value());
1627 } else {
1628 return {};
1629 }
1630}
1631
1633 return stash(from_stash(a) + from_stash(b));
1634}
1635
1637 return stash(from_stash(a) - from_stash(b));
1638}
1639
1641 return stash(from_stash(a) * from_stash(b));
1642}
1643
1645 return stash(from_stash(s).square());
1646}
1647
1649 return stash(from_stash(s).invert());
1650}
1651
1653 return stash(from_stash(s).invert_vartime());
1654}
1655
1657 return stash(from_stash(s).negate());
1658}
1659
1661 return from_stash(s).is_zero().as_bool();
1662}
1663
1665 return (from_stash(a) == from_stash(b)).as_bool();
1666}
1667
1669 return stash(GenericScalar::one(this));
1670}
1671
1673 return stash(GenericScalar::random(this, rng));
1674}
1675
1676PrimeOrderCurve::Scalar GenericPrimeOrderCurve::stash(const GenericScalar& s) const {
1677 return Scalar::_create(shared_from_this(), s.stash_value());
1678}
1679
1680GenericScalar GenericPrimeOrderCurve::from_stash(const PrimeOrderCurve::Scalar& s) const {
1681 BOTAN_ARG_CHECK(s._curve().get() == this, "Curve mismatch");
1682 return GenericScalar(this, s._value());
1683}
1684
1685PrimeOrderCurve::AffinePoint GenericPrimeOrderCurve::stash(const GenericAffinePoint& pt) const {
1686 auto x_w = pt.x().stash_value();
1687 auto y_w = pt.y().stash_value();
1688 return AffinePoint::_create(shared_from_this(), x_w, y_w);
1689}
1690
1691GenericAffinePoint GenericPrimeOrderCurve::from_stash(const PrimeOrderCurve::AffinePoint& pt) const {
1692 BOTAN_ARG_CHECK(pt._curve().get() == this, "Curve mismatch");
1693 auto x = GenericField(this, pt._x());
1694 auto y = GenericField(this, pt._y());
1695 return GenericAffinePoint(x, y);
1696}
1697
1698PrimeOrderCurve::ProjectivePoint GenericPrimeOrderCurve::stash(const GenericProjectivePoint& pt) const {
1699 auto x_w = pt.x().stash_value();
1700 auto y_w = pt.y().stash_value();
1701 auto z_w = pt.z().stash_value();
1702 return ProjectivePoint::_create(shared_from_this(), x_w, y_w, z_w);
1703}
1704
1705GenericProjectivePoint GenericPrimeOrderCurve::from_stash(const PrimeOrderCurve::ProjectivePoint& pt) const {
1706 BOTAN_ARG_CHECK(pt._curve().get() == this, "Curve mismatch");
1707 auto x = GenericField(this, pt._x());
1708 auto y = GenericField(this, pt._y());
1709 auto z = GenericField(this, pt._z());
1710 return GenericProjectivePoint(x, y, z);
1711}
1712
1714 return false;
1715}
1716
1718 std::function<void(std::span<uint8_t>)> expand_message) const {
1719 BOTAN_UNUSED(expand_message);
1720 throw Not_Implemented("Hash to curve is not implemented for this curve");
1721}
1722
1724 std::function<void(std::span<uint8_t>)> expand_message) const {
1725 BOTAN_UNUSED(expand_message);
1726 throw Not_Implemented("Hash to curve is not implemented for this curve");
1727}
1728
1729std::shared_ptr<const PrimeOrderCurve> PCurveInstance::from_params(
1730 const BigInt& p, const BigInt& a, const BigInt& b, const BigInt& base_x, const BigInt& base_y, const BigInt& order) {
1731 // We don't check that p and order are prime here on the assumption this has
1732 // been checked already by EC_Group
1733
1734 BOTAN_ARG_CHECK(a >= 0 && a < p, "a is invalid");
1735 BOTAN_ARG_CHECK(b > 0 && b < p, "b is invalid");
1736 BOTAN_ARG_CHECK(base_x >= 0 && base_x < p, "base_x is invalid");
1737 BOTAN_ARG_CHECK(base_y >= 0 && base_y < p, "base_y is invalid");
1738
1739 const size_t p_bits = p.bits();
1740
1741 // Same size restrictions as EC_Group however here we do not require
1742 // exactly the primes for the 521 or 239 bit exceptions; this code
1743 // should work fine with any such prime and we are relying on the higher
1744 // levels to prevent creating such a group in the first place
1745 //
1746 // TODO(Botan4) increase the 128 here to 192 when the corresponding EC_Group constructor is changed
1747 //
1748 if(p_bits != 521 && p_bits != 239 && (p_bits < 128 || p_bits > 512 || p_bits % 32 != 0)) {
1749 return {};
1750 }
1751
1752 // We don't want to deal with Shanks-Tonelli in the generic case
1753 if(p % 4 != 3) {
1754 return {};
1755 }
1756
1757 // The bit length of the field and order being the same simplifies things
1758 if(p_bits != order.bits()) {
1759 return {};
1760 }
1761
1762 // Check that the (x,y) generator point is on the curve
1764 const BigInt y2 = mod_p.square(base_y);
1765 const BigInt x3_ax_b = mod_p.reduce(mod_p.cube(base_x) + mod_p.multiply(a, base_x) + b);
1766 if(y2 != x3_ax_b) {
1767 return {};
1768 }
1769
1770 auto gpoc = std::make_shared<GenericPrimeOrderCurve>(p, a, b, base_x, base_y, order);
1771 /*
1772 The implementation of this needs to call shared_from_this which is not usable
1773 until after the constructor has completed, so we have to do a two-stage
1774 construction process. This is certainly not so clean but it is contained to
1775 this single file so seems tolerable.
1776
1777 Alternately we could lazily compute the base mul table but this brings in
1778 locking issues which seem a worse alternative overall.
1779 */
1780 gpoc->_precompute_base_mul();
1781 return gpoc;
1782}
1783
1784} // namespace Botan::PCurve
#define BOTAN_UNUSED
Definition assert.h:144
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_DEBUG_ASSERT(expr)
Definition assert.h:129
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:62
#define BOTAN_ASSERT_UNREACHABLE()
Definition assert.h:166
static Barrett_Reduction for_public_modulus(const BigInt &m)
Definition barrett.cpp:33
size_t bits() const
Definition bigint.cpp:307
static constexpr Choice from_int(T v)
Definition ct_utils.h:268
static constexpr Choice no()
Definition ct_utils.h:307
static constexpr Mask< T > is_equal(T x, T y)
Definition ct_utils.h:442
Scalar random_scalar(RandomNumberGenerator &rng) const override
AffinePoint point_negate(const AffinePoint &pt) const override
bool mul2_vartime_x_mod_order_eq(const PrecomputedMul2Table &tableb, const Scalar &v, const Scalar &s1, const Scalar &s2) const override
ProjectivePoint mul_by_g(const Scalar &scalar, RandomNumberGenerator &rng) const override
std::optional< ProjectivePoint > mul_px_qy(const AffinePoint &p, const Scalar &x, const AffinePoint &q, const Scalar &y, RandomNumberGenerator &rng) const override
ProjectivePoint hash_to_curve_ro(std::function< void(std::span< uint8_t >)> expand_message) const override
void serialize_scalar(std::span< uint8_t > bytes, const Scalar &scalar) const override
Scalar scalar_square(const Scalar &s) const override
Scalar squaring.
std::optional< Scalar > deserialize_scalar(std::span< const uint8_t > bytes) const override
std::optional< Scalar > scalar_from_wide_bytes(std::span< const uint8_t > bytes) const override
std::unique_ptr< const PrecomputedMul2Table > mul2_setup_g(const AffinePoint &q) const override
Setup a table for 2-ary multiplication where the first point is the generator.
GenericPrimeOrderCurve(const BigInt &p, const BigInt &a, const BigInt &b, const BigInt &base_x, const BigInt &base_y, const BigInt &order)
AffinePoint generator() const override
Return the standard generator.
const GenericCurveParams & _params() const
AffinePoint hash_to_curve_nu(std::function< void(std::span< uint8_t >)> expand_message) const override
ProjectivePoint point_add(const AffinePoint &a, const AffinePoint &b) const override
Scalar scalar_mul(const Scalar &a, const Scalar &b) const override
Scalar multiplication.
Scalar scalar_invert(const Scalar &s) const override
Scalar inversion.
std::optional< ProjectivePoint > mul2_vartime(const PrecomputedMul2Table &tableb, const Scalar &x, const Scalar &y) const override
std::optional< AffinePoint > deserialize_point_compressed(std::span< const uint8_t > bytes) const override
void serialize_point(std::span< uint8_t > bytes, const AffinePoint &pt) const override
bool scalar_is_zero(const Scalar &s) const override
Test if scalar is zero.
Scalar scalar_negate(const Scalar &s) const override
Scalar negation.
secure_vector< uint8_t > mul_x_only(const AffinePoint &pt, const Scalar &scalar, RandomNumberGenerator &rng) const override
AffinePoint point_identity() const override
Return the identity element (aka the point at infinity).
ProjectivePoint mul(const AffinePoint &pt, const Scalar &scalar, RandomNumberGenerator &rng) const override
Scalar base_point_mul_x_mod_order(const Scalar &scalar, RandomNumberGenerator &rng) const override
Scalar scalar_invert_vartime(const Scalar &s) const override
Scalar inversion (variable time).
bool affine_point_is_identity(const AffinePoint &pt) const override
size_t scalar_bytes() const override
Return the byte length of the scalar element.
Scalar scalar_sub(const Scalar &a, const Scalar &b) const override
Scalar subtraction.
AffinePoint point_to_affine(const ProjectivePoint &pt) const override
bool scalar_equal(const Scalar &a, const Scalar &b) const override
Test if two scalars are equal.
std::optional< AffinePoint > deserialize_point_uncompressed(std::span< const uint8_t > bytes) const override
Scalar scalar_add(const Scalar &a, const Scalar &b) const override
Scalar addition.
size_t order_bits() const override
Return the bit length of the group order.
static AffinePoint _create(CurvePtr curve, StorageUnit x, StorageUnit y)
Definition pcurves.h:112
static constexpr size_t StorageWords
Number of words used to store MaximumByteLength.
Definition pcurves.h:42
std::array< word, StorageWords > StorageUnit
Definition pcurves.h:59
constexpr void pack(const Polynomial< PolyTrait, D > &p, BufferStuffer &stuffer, MapFnT map)
constexpr void conditional_swap(bool cnd, T &x, T &y)
Definition ct_utils.h:768
constexpr void poison_all(const Ts &... ts)
Definition ct_utils.h:201
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:798
constexpr void unpoison_all(const Ts &... ts)
Definition ct_utils.h:207
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:67
constexpr CT::Mask< T > all_zeros(const T elem[], size_t len)
Definition ct_utils.h:785
constexpr void poison(const T *p, size_t n)
Definition ct_utils.h:56
C::ProjectivePoint varpoint_exec(const AffinePointTable< C > &table, const BlindedScalar &scalar, RandomNumberGenerator &rng)
constexpr auto bigint_add2(W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:94
constexpr auto bigint_add3(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:120
auto to_affine_x(const typename C::ProjectivePoint &pt)
constexpr auto bytes_to_words(std::span< const uint8_t, L > bytes)
constexpr W shift_left(std::array< W, N > &x)
Definition mp_core.h:725
constexpr ProjectivePoint dbl_n_generic(const ProjectivePoint &pt, const FieldElement &A, size_t n)
BigInt operator*(const BigInt &x, const BigInt &y)
Definition big_ops3.cpp:57
constexpr size_t read_window_bits(std::span< const W, N > words, size_t offset)
Definition mp_core.h:1071
void bigint_comba_sqr4(word z[8], const word x[4])
Definition mp_comba.cpp:17
void bigint_comba_sqr6(word z[12], const word x[6])
Definition mp_comba.cpp:75
constexpr ProjectivePoint dbl_a_minus_3(const ProjectivePoint &pt)
constexpr size_t scalar_blinding_bits(size_t scalar_bits)
Definition pcurves_mul.h:41
void bigint_comba_mul4(word z[8], const word x[4], const word y[4])
Definition mp_comba.cpp:43
BigInt square(const BigInt &x)
Definition numthry.cpp:184
void bigint_sqr(word z[], size_t z_size, const word x[], size_t x_size, size_t x_sw, word workspace[], size_t ws_size)
Definition mp_karat.cpp:327
OctetString operator+(const OctetString &k1, const OctetString &k2)
Definition symkey.cpp:99
C::ProjectivePoint mul2_exec(const AffinePointTable< C > &table, const BlindedScalar &x, const BlindedScalar &y, RandomNumberGenerator &rng)
constexpr auto bigint_sub3(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:192
void bigint_mul(word z[], size_t z_size, const word x[], size_t x_size, size_t x_sw, const word y[], size_t y_size, size_t y_sw, word workspace[], size_t ws_size)
Definition mp_karat.cpp:283
void bigint_comba_mul6(word z[12], const word x[6], const word y[6])
Definition mp_comba.cpp:116
constexpr ProjectivePoint dbl_n_a_zero(const ProjectivePoint &pt, size_t n)
auto to_affine_batch(std::span< const typename C::ProjectivePoint > projective)
constexpr ProjectivePoint dbl_a_zero(const ProjectivePoint &pt)
C::ProjectivePoint basemul_booth_exec(std::span< const typename C::AffinePoint > table, const BlindedScalar &scalar, RandomNumberGenerator &rng)
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144
BigInt operator-(const BigInt &x, const BigInt &y)
Definition bigint.h:1219
std::vector< typename C::ProjectivePoint > mul2_setup(const typename C::AffinePoint &p, const typename C::AffinePoint &q)
constexpr void bigint_shl1(W x[], size_t x_size, size_t x_words, size_t shift)
Definition mp_core.h:309
constexpr auto to_affine(const typename C::ProjectivePoint &pt)
void R2(uint32_t A, uint32_t &B, uint32_t C, uint32_t &D, uint32_t E, uint32_t &F, uint32_t G, uint32_t &H, uint32_t TJ, uint32_t Wi, uint32_t Wj)
Definition sm3_fn.h:43
constexpr ProjectivePoint point_add_mixed(const ProjectivePoint &a, const AffinePoint &b, const FieldElement &one)
void bigint_monty_redc(word r[], const word z[], const word p[], size_t p_size, word p_dash, word ws[], size_t ws_size)
Definition mp_core.h:923
std::vector< typename C::AffinePoint > basemul_booth_setup(const typename C::AffinePoint &p, size_t max_scalar_bits)
constexpr W bigint_cnd_add(W cnd, W x[], const W y[], size_t size)
Definition mp_core.h:45
constexpr ProjectivePoint point_add_or_sub_mixed(const ProjectivePoint &a, const AffinePoint &b, CT::Choice sub, const FieldElement &one)
constexpr void bigint_monty_maybe_sub(size_t N, W z[], W x0, const W x[], const W p[])
Definition mp_core.h:225
void bigint_comba_mul9(word z[18], const word x[9], const word y[9])
Definition mp_comba.cpp:512
void R1(uint32_t A, uint32_t &B, uint32_t C, uint32_t &D, uint32_t E, uint32_t &F, uint32_t G, uint32_t &H, uint32_t TJ, uint32_t Wi, uint32_t Wj)
Definition sm3_fn.h:21
void carry(int64_t &h0, int64_t &h1)
BOTAN_FORCE_INLINE constexpr T choose(T mask, T a, T b)
Definition bit_ops.h:216
constexpr ProjectivePoint dbl_n_a_minus_3(const ProjectivePoint &pt, size_t n)
AffinePointTable< C > varpoint_setup(const typename C::AffinePoint &p)
constexpr auto load_le(ParamTs &&... params)
Definition loadstor.h:495
constexpr auto bigint_ct_is_lt(const W x[], size_t x_size, const W y[], size_t y_size, bool lt_or_equal=false) -> CT::Mask< W >
Definition mp_core.h:486
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128
void bigint_comba_sqr8(word z[16], const word x[8])
Definition mp_comba.cpp:293
void bigint_comba_sqr9(word z[18], const word x[9])
Definition mp_comba.cpp:441
constexpr ProjectivePoint dbl_generic(const ProjectivePoint &pt, const FieldElement &A)
bool operator==(const AlgorithmIdentifier &x, const AlgorithmIdentifier &y)
Definition alg_id.cpp:54
constexpr ProjectivePoint point_add(const ProjectivePoint &a, const ProjectivePoint &b)
constexpr auto operator*=(Strong< T1, Tags... > &a, T2 b)
std::conditional_t< HasNative64BitRegisters, std::uint64_t, uint32_t > word
The native machine word, used as the limb type for multiprecision integers.
Definition types.h:131
void bigint_comba_mul8(word z[16], const word x[8], const word y[8])
Definition mp_comba.cpp:353
constexpr auto store_be(ParamTs &&... params)
Definition loadstor.h:745
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:118
constexpr auto load_be(ParamTs &&... params)
Definition loadstor.h:504
constexpr W shift_right(std::array< W, N > &x)
Definition mp_core.h:741