Skip to content

Commit

Permalink
Implement elligator2 tranform from point to representative, compatible
Browse files Browse the repository at this point in the history
with agl/ed25519/extra25519 and the kleshni C implementation.
  • Loading branch information
jmwample committed Jan 5, 2024
1 parent 0b45e00 commit b4ad93f
Show file tree
Hide file tree
Showing 13 changed files with 805 additions and 42 deletions.
5 changes: 4 additions & 1 deletion curve25519-dalek/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@ rustdoc-args = [
"--html-in-header", "docs/assets/rustdoc-include-katex-header.html",
"--cfg", "docsrs",
]
features = ["serde", "rand_core", "digest", "legacy_compatibility", "group-bits"]
features = ["serde", "rand_core", "elligator2", "digest", "legacy_compatibility", "group-bits"]

[dev-dependencies]
sha2 = { version = "0.10", default-features = false }
bincode = "1"
criterion = { version = "0.5", features = ["html_reports"] }
hex = "0.4.2"
json = "0.12.4"
rand = "0.8"
rand_core = { version = "0.6", default-features = false, features = ["getrandom"] }

Expand Down Expand Up @@ -69,6 +70,8 @@ precomputed-tables = []
legacy_compatibility = []
group = ["dep:group", "rand_core"]
group-bits = ["group", "ff/bits"]
elligator2 = []
digest = ["dep:digest", "elligator2"]

[target.'cfg(all(not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial"), target_arch = "x86_64"))'.dependencies]
curve25519-dalek-derive = { version = "0.1", path = "../curve25519-dalek-derive" }
1 change: 1 addition & 0 deletions curve25519-dalek/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ curve25519-dalek = ">= 4.0, < 4.2"
| `serde` | | Enables `serde` serialization/deserialization for all the point and scalar types. |
| `legacy_compatibility`| | Enables `Scalar::from_bits`, which allows the user to build unreduced scalars whose arithmetic is broken. Do not use this unless you know what you're doing. |
| `group` | | Enables external `group` and `ff` crate traits |
| `elligator2` | | Enables elligator2 functionality for supported types. This allows curve points to be encoded to uniform random representatives, and 32 byte values to be mapped (back) to curve points. |

To disable the default features when using `curve25519-dalek` as a dependency,
add `default-features = false` to the dependency in your `Cargo.toml`. To
Expand Down
2 changes: 2 additions & 0 deletions curve25519-dalek/src/backend/serial/u32/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,14 @@ pub(crate) const SQRT_M1: FieldElement2625 = FieldElement2625::from_limbs([
pub(crate) const APLUS2_OVER_FOUR: FieldElement2625 =
FieldElement2625::from_limbs([121666, 0, 0, 0, 0, 0, 0, 0, 0, 0]);

#[cfg(feature = "elligator2")]
/// `MONTGOMERY_A` is equal to 486662, which is a constant of the curve equation
/// for Curve25519 in its Montgomery form. (This is used internally within the
/// Elligator map.)
pub(crate) const MONTGOMERY_A: FieldElement2625 =
FieldElement2625::from_limbs([486662, 0, 0, 0, 0, 0, 0, 0, 0, 0]);

#[cfg(feature = "elligator2")]
/// `MONTGOMERY_A_NEG` is equal to -486662. (This is used internally within the
/// Elligator map.)
pub(crate) const MONTGOMERY_A_NEG: FieldElement2625 = FieldElement2625::from_limbs([
Expand Down
20 changes: 20 additions & 0 deletions curve25519-dalek/src/backend/serial/u32/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -601,4 +601,24 @@ impl FieldElement2625 {
}
FieldElement2625::reduce(coeffs)
}

/// 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 u64 | _cy2 as u64;
}

Choice::from((cy != 0_u32) as u8)
}
}
2 changes: 2 additions & 0 deletions curve25519-dalek/src/backend/serial/u64/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,13 @@ pub(crate) const SQRT_M1: FieldElement51 = FieldElement51::from_limbs([
pub(crate) const APLUS2_OVER_FOUR: FieldElement51 =
FieldElement51::from_limbs([121666, 0, 0, 0, 0]);

#[cfg(feature = "elligator2")]
/// `MONTGOMERY_A` is equal to 486662, which is a constant of the curve equation
/// for Curve25519 in its Montgomery form. (This is used internally within the
/// Elligator map.)
pub(crate) const MONTGOMERY_A: FieldElement51 = FieldElement51::from_limbs([486662, 0, 0, 0, 0]);

#[cfg(feature = "elligator2")]
/// `MONTGOMERY_A_NEG` is equal to -486662. (This is used internally within the
/// Elligator map.)
pub(crate) const MONTGOMERY_A_NEG: FieldElement51 = FieldElement51::from_limbs([
Expand Down
20 changes: 20 additions & 0 deletions curve25519-dalek/src/backend/serial/u64/field.rs
Original file line number Diff line number Diff line change
Expand Up @@ -572,4 +572,24 @@ impl FieldElement51 {

square
}

/// 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)
}
}
7 changes: 4 additions & 3 deletions curve25519-dalek/src/edwards.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ use cfg_if::cfg_if;

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


#[cfg(feature = "group")]
use {
Expand Down Expand Up @@ -595,9 +598,7 @@ impl EdwardsPoint {

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

let fe = FieldElement::from_bytes(&res);

let M1 = crate::montgomery::elligator_encode(&fe);
let M1 = map_to_point(&res);
let E1_opt = M1.to_edwards(sign_bit);

E1_opt
Expand Down
Loading

0 comments on commit b4ad93f

Please sign in to comment.