Skip to content

Commit

Permalink
Subgroup based Handshake Distinguisher (#2)
Browse files Browse the repository at this point in the history
fix for subgroup based computational distinguisher and updates / simplifications to the elligator2 interface as a result
  • Loading branch information
jmwample authored Jun 26, 2024
1 parent 2226611 commit 8d96835
Show file tree
Hide file tree
Showing 13 changed files with 1,799 additions and 1,318 deletions.
2 changes: 1 addition & 1 deletion curve25519-dalek/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ rustdoc-args = [
"--html-in-header", "docs/assets/rustdoc-include-katex-header.html",
"--cfg", "docsrs",
]
features = ["serde", "rand_core", "elligator2", "digest", "legacy_compatibility", "group-bits"]
features = ["serde", "rand_core", "digest", "legacy_compatibility", "group-bits"]

[dev-dependencies]
sha2 = { version = "0.10", default-features = false }
Expand Down
20 changes: 20 additions & 0 deletions curve25519-dalek/src/backend/serial/fiat_u32/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -268,4 +268,24 @@ impl FieldElement2625 {
fiat_25519_carry(&mut output.0, &output_loose);
output
}

/// Returns 1 if self is greater than the other and 0 otherwise
// implementation based on C libgmp -> mpn_sub_n
pub(crate) fn gt(&self, other: &Self) -> Choice {
let mut _ul = 0_u32;
let mut _vl = 0_u32;
let mut _rl = 0_u32;

let mut cy = 0_u32;
for i in 0..10 {
_ul = self.0[i];
_vl = other.0[i];

let (_sl, _cy1) = _ul.overflowing_sub(_vl);
let (_rl, _cy2) = _sl.overflowing_sub(cy);
cy = _cy1 as u32 | _cy2 as u32;
}

Choice::from((cy != 0_u32) as u8)
}
}
20 changes: 20 additions & 0 deletions curve25519-dalek/src/backend/serial/fiat_u64/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,4 +259,24 @@ impl FieldElement51 {
fiat_25519_carry(&mut output.0, &output_loose);
output
}

/// Returns 1 if self is greater than the other and 0 otherwise
// implementation based on C libgmp -> mpn_sub_n
pub(crate) fn gt(&self, other: &Self) -> Choice {
let mut _ul = 0_u64;
let mut _vl = 0_u64;
let mut _rl = 0_u64;

let mut cy = 0_u64;
for i in 0..5 {
_ul = self.0[i];
_vl = other.0[i];

let (_sl, _cy1) = _ul.overflowing_sub(_vl);
let (_rl, _cy2) = _sl.overflowing_sub(cy);
cy = _cy1 as u64 | _cy2 as u64;
}

Choice::from((cy != 0_u64) as u8)
}
}
48 changes: 6 additions & 42 deletions curve25519-dalek/src/edwards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,6 @@ use core::ops::{Mul, MulAssign};

use cfg_if::cfg_if;

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

Expand Down Expand Up @@ -590,6 +588,8 @@ impl EdwardsPoint {
where
D: Digest<OutputSize = U64> + Default,
{
use crate::elligator2::Legacy;

let mut hash = D::new();
hash.update(bytes);
let h = hash.finalize();
Expand All @@ -598,52 +598,16 @@ impl EdwardsPoint {

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

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

E1_opt
.expect("Montgomery conversion to Edwards point in Elligator failed")
.mul_by_cofactor()
}

#[cfg(feature = "elligator2")]
/// Perform the Elligator2 mapping to an [`EdwardsPoint`].
///
/// Calculates a point on elliptic curve E (Curve25519) from an element of
/// the finite field F over which E is defined. See section 6.7.1 of the
/// RFC.
///
/// The input u and output P are elements of the field F. Note that
/// the output P is a point on the edwards curve and as such it's byte
/// representation is distinguishable from uniform random.
///
/// Input:
/// * u -> an element of field F.
///
/// Output:
/// * P - a point on the Edwards elliptic curve.
///
/// See <https://datatracker.ietf.org/doc/rfc9380/>
pub fn map_to_point(r: &[u8; 32]) -> EdwardsPoint {
let mut clamped = *r;
clamped[31] &= MASK_UNSET_BYTE;
let r_0 = FieldElement::from_bytes(&clamped);
let (x, y) = map_fe_to_edwards(&r_0);
Self::from_xy(&x, &y)
}

#[cfg(feature = "elligator2")]
fn from_xy(x: &FieldElement, y: &FieldElement) -> EdwardsPoint {
let z = FieldElement::ONE;
let t = x * y;

EdwardsPoint {
X: *x,
Y: *y,
Z: z,
T: t,
}
}
}

// ------------------------------------------------------------------------
Expand Down
Loading

0 comments on commit 8d96835

Please sign in to comment.