Skip to content

Commit 750c4ce

Browse files
authored
Merge pull request #4953 from randombit/jack/generic-scalar-inverse-vartime
Add variable time scalar inversion to pcurves_generic
2 parents 2c5ea09 + 44502bc commit 750c4ce

1 file changed

Lines changed: 93 additions & 6 deletions

File tree

src/lib/math/pcurves/pcurves_generic/pcurves_generic.cpp

Lines changed: 93 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -117,14 +117,15 @@ class GenericCurveParams final {
117117
m_field_monty_r1(bn_to_fixed(m_monty_field.R1())),
118118
m_field_monty_r2(bn_to_fixed(m_monty_field.R2())),
119119
m_field_p_plus_1_over_4(bn_to_fixed_rev((p + 1) / 4)),
120-
m_field_p_over_2_plus_1(bn_to_fixed((p / 2) + 1)),
120+
m_field_inv_2(bn_to_fixed((p / 2) + 1)),
121121
m_field_p_dash(m_monty_field.p_dash()),
122122

123123
m_order(bn_to_fixed(order)),
124124
m_order_minus_2(bn_to_fixed_rev(order - 2)),
125125
m_order_monty_r1(bn_to_fixed(m_monty_order.R1())),
126126
m_order_monty_r2(bn_to_fixed(m_monty_order.R2())),
127127
m_order_monty_r3(bn_to_fixed(m_monty_order.R3())),
128+
m_order_inv_2(bn_to_fixed((order / 2) + 1)),
128129
m_order_p_dash(m_monty_order.p_dash()),
129130

130131
m_a_is_minus_3(a + 3 == p),
@@ -162,7 +163,7 @@ class GenericCurveParams final {
162163

163164
const StorageUnit& field_p_plus_1_over_4() const { return m_field_p_plus_1_over_4; }
164165

165-
const StorageUnit& field_p_over_2_plus_1() const { return m_field_p_over_2_plus_1; }
166+
const StorageUnit& field_inv_2() const { return m_field_inv_2; }
166167

167168
word field_p_dash() const { return m_field_p_dash; }
168169

@@ -176,6 +177,8 @@ class GenericCurveParams final {
176177

177178
const StorageUnit& order_monty_r3() const { return m_order_monty_r3; }
178179

180+
const StorageUnit& order_inv_2() const { return m_order_inv_2; }
181+
179182
word order_p_dash() const { return m_order_p_dash; }
180183

181184
const StorageUnit& monty_curve_a() const { return m_monty_curve_a; }
@@ -255,14 +258,15 @@ class GenericCurveParams final {
255258
StorageUnit m_field_monty_r1;
256259
StorageUnit m_field_monty_r2;
257260
StorageUnit m_field_p_plus_1_over_4;
258-
StorageUnit m_field_p_over_2_plus_1;
261+
StorageUnit m_field_inv_2;
259262
word m_field_p_dash;
260263

261264
StorageUnit m_order;
262265
StorageUnit m_order_minus_2;
263266
StorageUnit m_order_monty_r1;
264267
StorageUnit m_order_monty_r2;
265268
StorageUnit m_order_monty_r3;
269+
StorageUnit m_order_inv_2;
266270
word m_order_p_dash;
267271

268272
StorageUnit m_monty_curve_a;
@@ -417,6 +421,90 @@ class GenericScalar final {
417421

418422
GenericScalar invert() const { return pow_vartime(m_curve->_params().order_minus_2()); }
419423

424+
/**
425+
* Helper for variable time BEEA
426+
*
427+
* Note this function assumes that its arguments are in the standard
428+
* domain, not the Montgomery domain. invert_vartime converts its argument
429+
* out of Montgomery, and then back to Montgomery when returning the result.
430+
*/
431+
static void _invert_vartime_div2_helper(GenericScalar& a, GenericScalar& x) {
432+
const auto& inv_2 = a.curve()->_params().order_inv_2();
433+
434+
// Conditional ok: this function is variable time
435+
while((a.m_val[0] & 1) != 1) {
436+
shift_right<1>(a.m_val);
437+
438+
W borrow = shift_right<1>(x.m_val);
439+
440+
// Conditional ok: this function is variable time
441+
if(borrow) {
442+
bigint_add2_nc(x.m_val.data(), N, inv_2.data(), N);
443+
}
444+
}
445+
}
446+
447+
/*
448+
* See the comments on invert_vartime in pcurves_impl.h for background
449+
*/
450+
GenericScalar invert_vartime() const {
451+
if(this->is_zero().as_bool()) {
452+
return (*this);
453+
}
454+
455+
auto x = GenericScalar(m_curve, std::array<W, N>{1});
456+
auto b = GenericScalar(m_curve, from_rep(m_curve, m_val));
457+
458+
// First loop iteration
459+
GenericScalar::_invert_vartime_div2_helper(b, x);
460+
461+
auto a = b.negate();
462+
// y += x but y is zero at the outset
463+
auto y = x;
464+
465+
// First half of second loop iteration
466+
GenericScalar::_invert_vartime_div2_helper(a, y);
467+
468+
for(;;) {
469+
// Conditional ok: this function is variable time
470+
if(a.m_val == b.m_val) {
471+
// At this point it should be that a == b == 1
472+
auto r = y.negate();
473+
474+
// Convert back to Montgomery
475+
return GenericScalar(curve(), to_rep(curve(), r.m_val));
476+
}
477+
478+
auto nx = x + y;
479+
480+
/*
481+
* Otherwise either b > a or a > b
482+
*
483+
* If b > a we want to set b to b - a
484+
* Otherwise we want to set a to a - b
485+
*
486+
* Compute r = b - a and check if it underflowed
487+
* If it did not then we are in the b > a path
488+
*/
489+
std::array<W, N> r;
490+
word carry = bigint_sub3(r.data(), b.data(), N, a.data(), N);
491+
492+
// Conditional ok: this function is variable time
493+
if(carry == 0) {
494+
// b > a
495+
b.m_val = r;
496+
x = nx;
497+
GenericScalar::_invert_vartime_div2_helper(b, x);
498+
} else {
499+
// We know this can't underflow because a > b
500+
bigint_sub3(r.data(), a.data(), N, b.data(), N);
501+
a.m_val = r;
502+
y = nx;
503+
GenericScalar::_invert_vartime_div2_helper(a, y);
504+
}
505+
}
506+
}
507+
420508
template <concepts::resizable_byte_buffer T>
421509
T serialize() const {
422510
T bytes(m_curve->_params().order_bytes());
@@ -587,7 +675,7 @@ class GenericField final {
587675
W borrow = shift_right<1>(t);
588676

589677
// If value was odd, add (P/2)+1
590-
bigint_cnd_add(borrow, t.data(), N, m_curve->_params().field_p_over_2_plus_1().data(), N);
678+
bigint_cnd_add(borrow, t.data(), N, m_curve->_params().field_inv_2().data(), N);
591679

592680
return GenericField(m_curve, t);
593681
}
@@ -1500,8 +1588,7 @@ PrimeOrderCurve::Scalar GenericPrimeOrderCurve::scalar_invert(const Scalar& s) c
15001588
}
15011589

15021590
PrimeOrderCurve::Scalar GenericPrimeOrderCurve::scalar_invert_vartime(const Scalar& s) const {
1503-
// TODO support BEEA for this
1504-
return stash(from_stash(s).invert());
1591+
return stash(from_stash(s).invert_vartime());
15051592
}
15061593

15071594
PrimeOrderCurve::Scalar GenericPrimeOrderCurve::scalar_negate(const Scalar& s) const {

0 commit comments

Comments
 (0)