Skip to content

Commit 16f4b17

Browse files
committed
Compute Ed448 scalar multiplication in untwisted form
1 parent 46a6de6 commit 16f4b17

File tree

4 files changed

+123
-42
lines changed

4 files changed

+123
-42
lines changed

ed448-goldilocks/src/edwards.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
/// If this is a problem, one can use a different isogeny strategy (Decaf)
1212
pub(crate) mod affine;
1313
pub(crate) mod extended;
14+
mod mul;
1415
mod scalar;
1516
pub use affine::AffinePoint;
1617
pub use extended::{CompressedEdwardsY, EdwardsPoint};
18+
use mul::scalar_mul;
1719
pub use scalar::{EdwardsScalar, EdwardsScalarBytes, WideEdwardsScalarBytes};

ed448-goldilocks/src/edwards/extended.rs

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use core::fmt::{Display, Formatter, LowerHex, Result as FmtResult, UpperHex};
33
use core::iter::Sum;
44
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
55

6-
use crate::curve::scalar_mul::variable_base;
6+
use super::scalar_mul;
77
use crate::curve::twedwards::extensible::ExtensiblePoint as TwistedExtensiblePoint;
88
use crate::field::FieldElement;
99
use crate::*;
@@ -543,40 +543,7 @@ impl EdwardsPoint {
543543

544544
/// Generic scalar multiplication to compute s*P
545545
pub fn scalar_mul(&self, scalar: &EdwardsScalar) -> Self {
546-
// Compute floor(s/4)
547-
let mut scalar_div_four = *scalar;
548-
scalar_div_four.div_by_four();
549-
550-
// Use isogeny and dual isogeny to compute phi^-1((s/4) * phi(P))
551-
let partial_result =
552-
variable_base(&self.to_twisted().to_extended(), &scalar_div_four).to_untwisted();
553-
// Add partial result to (scalar mod 4) * P
554-
partial_result.add(&self.scalar_mod_four(scalar))
555-
}
556-
557-
/// Returns (scalar mod 4) * P in constant time
558-
pub(crate) fn scalar_mod_four(&self, scalar: &EdwardsScalar) -> Self {
559-
// Compute compute (scalar mod 4)
560-
let s_mod_four = scalar[0] & 3;
561-
562-
// Compute all possible values of (scalar mod 4) * P
563-
let zero_p = EdwardsPoint::IDENTITY;
564-
let one_p = self;
565-
let two_p = one_p.double();
566-
let three_p = two_p.add(self);
567-
568-
// Under the reasonable assumption that `==` is constant time
569-
// Then the whole function is constant time.
570-
// This should be cheaper than calling double_and_add or a scalar mul operation
571-
// as the number of possibilities are so small.
572-
// XXX: This claim has not been tested (although it sounds intuitive to me)
573-
let mut result = EdwardsPoint::IDENTITY;
574-
result.conditional_assign(&zero_p, Choice::from((s_mod_four == 0) as u8));
575-
result.conditional_assign(one_p, Choice::from((s_mod_four == 1) as u8));
576-
result.conditional_assign(&two_p, Choice::from((s_mod_four == 2) as u8));
577-
result.conditional_assign(&three_p, Choice::from((s_mod_four == 3) as u8));
578-
579-
result
546+
scalar_mul(self, scalar)
580547
}
581548

582549
/// Standard compression; store Y and sign of X

ed448-goldilocks/src/edwards/mul.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
use super::{EdwardsPoint, EdwardsScalar};
2+
use crate::field::FieldElement;
3+
use subtle::{Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq};
4+
5+
pub(super) fn scalar_mul(point: &EdwardsPoint, scalar: &EdwardsScalar) -> EdwardsPoint {
6+
let mut result = ExtensiblePoint::IDENTITY;
7+
8+
// Recode Scalar
9+
let scalar = scalar.to_radix_16();
10+
11+
let lookup = LookupTable::from(point);
12+
13+
for i in (0..113).rev() {
14+
result = result.double();
15+
result = result.double();
16+
result = result.double();
17+
result = result.double();
18+
19+
// The mask is the top bit, will be 1 for negative numbers, 0 for positive numbers
20+
let mask = scalar[i] >> 7;
21+
let sign = mask & 0x1;
22+
// Use the mask to get the absolute value of scalar
23+
let abs_value = ((scalar[i] + mask) ^ mask) as u32;
24+
25+
let mut neg_P = lookup.select(abs_value);
26+
neg_P.conditional_negate(Choice::from((sign) as u8));
27+
28+
result = (EdwardsPoint::from(result) + neg_P).into();
29+
}
30+
31+
result.into()
32+
}
33+
34+
struct ExtensiblePoint {
35+
X: FieldElement,
36+
Y: FieldElement,
37+
Z: FieldElement,
38+
T1: FieldElement,
39+
T2: FieldElement,
40+
}
41+
42+
impl ExtensiblePoint {
43+
const IDENTITY: ExtensiblePoint = ExtensiblePoint {
44+
X: FieldElement::ZERO,
45+
Y: FieldElement::ONE,
46+
Z: FieldElement::ONE,
47+
T1: FieldElement::ZERO,
48+
T2: FieldElement::ONE,
49+
};
50+
51+
fn double(&self) -> Self {
52+
let A = self.X.square();
53+
let B = self.Y.square();
54+
let C = self.Z.square().double();
55+
let D = A;
56+
let E = (self.X + self.Y).square() - A - B;
57+
let G = D + B;
58+
let F = G - C;
59+
let H = D - B;
60+
Self {
61+
X: E * F,
62+
Y: G * H,
63+
Z: F * G,
64+
T1: E,
65+
T2: H,
66+
}
67+
}
68+
}
69+
70+
impl From<ExtensiblePoint> for EdwardsPoint {
71+
fn from(value: ExtensiblePoint) -> Self {
72+
Self {
73+
X: value.X,
74+
Y: value.Y,
75+
Z: value.Z,
76+
T: value.T1 * value.T2,
77+
}
78+
}
79+
}
80+
81+
impl From<EdwardsPoint> for ExtensiblePoint {
82+
fn from(value: EdwardsPoint) -> Self {
83+
Self {
84+
X: value.X,
85+
Y: value.Y,
86+
Z: value.Z,
87+
T1: value.T,
88+
T2: FieldElement::ONE,
89+
}
90+
}
91+
}
92+
93+
pub struct LookupTable([EdwardsPoint; 8]);
94+
95+
/// Precomputes odd multiples of the point passed in
96+
impl From<&EdwardsPoint> for LookupTable {
97+
fn from(P: &EdwardsPoint) -> LookupTable {
98+
let mut table = [*P; 8];
99+
100+
for i in 1..8 {
101+
table[i] = P + table[i - 1];
102+
}
103+
104+
LookupTable(table)
105+
}
106+
}
107+
108+
impl LookupTable {
109+
/// Selects a projective niels point from a lookup table in constant time
110+
pub fn select(&self, index: u32) -> EdwardsPoint {
111+
let mut result = EdwardsPoint::IDENTITY;
112+
113+
for i in 1..9 {
114+
let swap = index.ct_eq(&(i as u32));
115+
result.conditional_assign(&self.0[i - 1], swap);
116+
}
117+
result
118+
}
119+
}

ed448-goldilocks/src/field/scalar.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -666,13 +666,6 @@ impl<C: CurveWithScalar> Scalar<C> {
666666
self.scalar.is_zero()
667667
}
668668

669-
/// Divides a scalar by four without reducing mod p
670-
/// This is used in the 2-isogeny when mapping points from Ed448-Goldilocks
671-
/// to Twisted-Goldilocks
672-
pub(crate) fn div_by_four(&mut self) {
673-
self.scalar >>= 2;
674-
}
675-
676669
// This method was modified from Curve25519-Dalek codebase. [scalar.rs]
677670
// We start with 14 u32s and convert them to 56 u8s.
678671
// 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)

0 commit comments

Comments
 (0)