Skip to content

Commit 0e83966

Browse files
authored
ed448-goldilocks: account for oddness in Scalar divisions (#1369)
- Re-use `Scalar::halve()` to compute `div_by_four()` - Rename `Scalar::halve()` to `Scalar::div_by_2()`
1 parent 95bf28e commit 0e83966

File tree

4 files changed

+15
-46
lines changed

4 files changed

+15
-46
lines changed

ed448-goldilocks/src/decaf/scalar.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,9 +153,9 @@ mod test {
153153
let eight = DecafScalar::from(8u8);
154154
let four = DecafScalar::from(4u8);
155155
let two = DecafScalar::from(2u8);
156-
assert_eq!(eight.halve(), four);
157-
assert_eq!(four.halve(), two);
158-
assert_eq!(two.halve(), DecafScalar::ONE);
156+
assert_eq!(eight.div_by_2(), four);
157+
assert_eq!(four.div_by_2(), two);
158+
assert_eq!(two.div_by_2(), DecafScalar::ONE);
159159
}
160160

161161
#[test]

ed448-goldilocks/src/edwards/extended.rs

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -334,38 +334,10 @@ impl EdwardsPoint {
334334
/// Generic scalar multiplication to compute s*P
335335
pub fn scalar_mul(&self, scalar: &EdwardsScalar) -> Self {
336336
// Compute floor(s/4)
337-
let mut scalar_div_four = *scalar;
338-
scalar_div_four.div_by_four();
337+
let scalar_div_four = scalar.div_by_2().div_by_2();
339338

340339
// Use isogeny and dual isogeny to compute phi^-1((s/4) * phi(P))
341-
let partial_result = variable_base(&self.to_twisted(), &scalar_div_four).to_untwisted();
342-
// Add partial result to (scalar mod 4) * P
343-
partial_result.add(&self.scalar_mod_four(scalar))
344-
}
345-
346-
/// Returns (scalar mod 4) * P in constant time
347-
pub(crate) fn scalar_mod_four(&self, scalar: &EdwardsScalar) -> Self {
348-
// Compute compute (scalar mod 4)
349-
let s_mod_four = scalar[0] & 3;
350-
351-
// Compute all possible values of (scalar mod 4) * P
352-
let zero_p = EdwardsPoint::IDENTITY;
353-
let one_p = self;
354-
let two_p = one_p.double();
355-
let three_p = two_p.add(self);
356-
357-
// Under the reasonable assumption that `==` is constant time
358-
// Then the whole function is constant time.
359-
// This should be cheaper than calling double_and_add or a scalar mul operation
360-
// as the number of possibilities are so small.
361-
// XXX: This claim has not been tested (although it sounds intuitive to me)
362-
let mut result = EdwardsPoint::IDENTITY;
363-
result.conditional_assign(&zero_p, Choice::from((s_mod_four == 0) as u8));
364-
result.conditional_assign(one_p, Choice::from((s_mod_four == 1) as u8));
365-
result.conditional_assign(&two_p, Choice::from((s_mod_four == 2) as u8));
366-
result.conditional_assign(&three_p, Choice::from((s_mod_four == 3) as u8));
367-
368-
result
340+
variable_base(&self.to_twisted(), &scalar_div_four).to_untwisted()
369341
}
370342

371343
/// Add two points

ed448-goldilocks/src/edwards/scalar.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,9 @@ mod test {
169169
let eight = EdwardsScalar::from(8u8);
170170
let four = EdwardsScalar::from(4u8);
171171
let two = EdwardsScalar::from(2u8);
172-
assert_eq!(eight.halve(), four);
173-
assert_eq!(four.halve(), two);
174-
assert_eq!(two.halve(), EdwardsScalar::ONE);
172+
assert_eq!(eight.div_by_2(), four);
173+
assert_eq!(four.div_by_2(), two);
174+
assert_eq!(two.div_by_2(), EdwardsScalar::ONE);
175175
}
176176

177177
#[test]

ed448-goldilocks/src/field/scalar.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use elliptic_curve::{
1313
Array, ArraySize,
1414
typenum::{Prod, Unsigned},
1515
},
16-
bigint::{Limb, NonZero, U448, U896, Word, Zero},
16+
bigint::{Integer, Limb, NonZero, U448, U896, Word, Zero},
1717
consts::U2,
1818
ff::{Field, helpers},
1919
ops::{Invert, Reduce, ReduceNonZero},
@@ -658,13 +658,6 @@ impl<C: CurveWithScalar> Scalar<C> {
658658
self.scalar.is_zero()
659659
}
660660

661-
/// Divides a scalar by four without reducing mod p
662-
/// This is used in the 2-isogeny when mapping points from Ed448-Goldilocks
663-
/// to Twisted-Goldilocks
664-
pub(crate) fn div_by_four(&mut self) {
665-
self.scalar >>= 2;
666-
}
667-
668661
// This method was modified from Curve25519-Dalek codebase. [scalar.rs]
669662
// We start with 14 u32s and convert them to 56 u8s.
670663
// We then use the code copied from Dalek to convert the 56 u8s to radix-16 and re-center the coefficients to be between [-16,16)
@@ -778,8 +771,12 @@ impl<C: CurveWithScalar> Scalar<C> {
778771
}
779772

780773
/// Halves a Scalar modulo the prime
781-
pub const fn halve(&self) -> Self {
782-
Self::new(self.scalar.shr_vartime(1))
774+
pub fn div_by_2(&self) -> Self {
775+
let is_odd = self.scalar.is_odd();
776+
let if_odd = self.scalar + *ORDER;
777+
let scalar = U448::conditional_select(&self.scalar, &if_odd, is_odd);
778+
779+
Self::new(scalar >> 1)
783780
}
784781

785782
/// Attempt to construct a `Scalar` from a canonical byte representation.

0 commit comments

Comments
 (0)