Skip to content

Commit 15ad0b3

Browse files
committed
Subgroup based Handshake Distinguisher (#2)
fix for subgroup based computational distinguisher and updates / simplifications to the elligator2 interface as a result
1 parent 8cd2b28 commit 15ad0b3

File tree

13 files changed

+1799
-1318
lines changed

13 files changed

+1799
-1318
lines changed

curve25519-dalek/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ rustdoc-args = [
2727
"--html-in-header", "docs/assets/rustdoc-include-katex-header.html",
2828
"--cfg", "docsrs",
2929
]
30-
features = ["serde", "rand_core", "elligator2", "digest", "legacy_compatibility", "group-bits"]
30+
features = ["serde", "rand_core", "digest", "legacy_compatibility", "group-bits"]
3131

3232
[dev-dependencies]
3333
sha2 = { version = "0.10", default-features = false }

curve25519-dalek/src/backend/serial/fiat_u32/field.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,4 +268,24 @@ impl FieldElement2625 {
268268
fiat_25519_carry(&mut output.0, &output_loose);
269269
output
270270
}
271+
272+
/// Returns 1 if self is greater than the other and 0 otherwise
273+
// implementation based on C libgmp -> mpn_sub_n
274+
pub(crate) fn gt(&self, other: &Self) -> Choice {
275+
let mut _ul = 0_u32;
276+
let mut _vl = 0_u32;
277+
let mut _rl = 0_u32;
278+
279+
let mut cy = 0_u32;
280+
for i in 0..10 {
281+
_ul = self.0[i];
282+
_vl = other.0[i];
283+
284+
let (_sl, _cy1) = _ul.overflowing_sub(_vl);
285+
let (_rl, _cy2) = _sl.overflowing_sub(cy);
286+
cy = _cy1 as u32 | _cy2 as u32;
287+
}
288+
289+
Choice::from((cy != 0_u32) as u8)
290+
}
271291
}

curve25519-dalek/src/backend/serial/fiat_u64/field.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,4 +259,24 @@ impl FieldElement51 {
259259
fiat_25519_carry(&mut output.0, &output_loose);
260260
output
261261
}
262+
263+
/// Returns 1 if self is greater than the other and 0 otherwise
264+
// implementation based on C libgmp -> mpn_sub_n
265+
pub(crate) fn gt(&self, other: &Self) -> Choice {
266+
let mut _ul = 0_u64;
267+
let mut _vl = 0_u64;
268+
let mut _rl = 0_u64;
269+
270+
let mut cy = 0_u64;
271+
for i in 0..5 {
272+
_ul = self.0[i];
273+
_vl = other.0[i];
274+
275+
let (_sl, _cy1) = _ul.overflowing_sub(_vl);
276+
let (_rl, _cy2) = _sl.overflowing_sub(cy);
277+
cy = _cy1 as u64 | _cy2 as u64;
278+
}
279+
280+
Choice::from((cy != 0_u64) as u8)
281+
}
262282
}

curve25519-dalek/src/edwards.rs

Lines changed: 6 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,6 @@ use core::ops::{Mul, MulAssign};
103103

104104
use cfg_if::cfg_if;
105105

106-
#[cfg(feature = "elligator2")]
107-
use crate::elligator2::{map_fe_to_edwards, MASK_UNSET_BYTE};
108106
#[cfg(feature = "digest")]
109107
use digest::{generic_array::typenum::U64, Digest};
110108

@@ -590,6 +588,8 @@ impl EdwardsPoint {
590588
where
591589
D: Digest<OutputSize = U64> + Default,
592590
{
591+
use crate::elligator2::Legacy;
592+
593593
let mut hash = D::new();
594594
hash.update(bytes);
595595
let h = hash.finalize();
@@ -598,52 +598,16 @@ impl EdwardsPoint {
598598

599599
let sign_bit = (res[31] & 0x80) >> 7;
600600

601-
let fe1 = MontgomeryPoint::map_to_point_unbounded(&res);
601+
// rfc9380 should always result in a valid point since no field elements
602+
// are invalid. so unwrap should be safe.
603+
#[allow(clippy::unwrap_used)]
604+
let fe1 = MontgomeryPoint::from_representative::<Legacy>(&res).unwrap();
602605
let E1_opt = fe1.to_edwards(sign_bit);
603606

604607
E1_opt
605608
.expect("Montgomery conversion to Edwards point in Elligator failed")
606609
.mul_by_cofactor()
607610
}
608-
609-
#[cfg(feature = "elligator2")]
610-
/// Perform the Elligator2 mapping to an [`EdwardsPoint`].
611-
///
612-
/// Calculates a point on elliptic curve E (Curve25519) from an element of
613-
/// the finite field F over which E is defined. See section 6.7.1 of the
614-
/// RFC.
615-
///
616-
/// The input u and output P are elements of the field F. Note that
617-
/// the output P is a point on the edwards curve and as such it's byte
618-
/// representation is distinguishable from uniform random.
619-
///
620-
/// Input:
621-
/// * u -> an element of field F.
622-
///
623-
/// Output:
624-
/// * P - a point on the Edwards elliptic curve.
625-
///
626-
/// See <https://datatracker.ietf.org/doc/rfc9380/>
627-
pub fn map_to_point(r: &[u8; 32]) -> EdwardsPoint {
628-
let mut clamped = *r;
629-
clamped[31] &= MASK_UNSET_BYTE;
630-
let r_0 = FieldElement::from_bytes(&clamped);
631-
let (x, y) = map_fe_to_edwards(&r_0);
632-
Self::from_xy(&x, &y)
633-
}
634-
635-
#[cfg(feature = "elligator2")]
636-
fn from_xy(x: &FieldElement, y: &FieldElement) -> EdwardsPoint {
637-
let z = FieldElement::ONE;
638-
let t = x * y;
639-
640-
EdwardsPoint {
641-
X: *x,
642-
Y: *y,
643-
Z: z,
644-
T: t,
645-
}
646-
}
647611
}
648612

649613
// ------------------------------------------------------------------------

0 commit comments

Comments
 (0)