Skip to content

Commit b4ad93f

Browse files
committed
Implement elligator2 tranform from point to representative, compatible
with agl/ed25519/extra25519 and the kleshni C implementation.
1 parent 0b45e00 commit b4ad93f

File tree

13 files changed

+805
-42
lines changed

13 files changed

+805
-42
lines changed

curve25519-dalek/Cargo.toml

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

3232
[dev-dependencies]
3333
sha2 = { version = "0.10", default-features = false }
3434
bincode = "1"
3535
criterion = { version = "0.5", features = ["html_reports"] }
3636
hex = "0.4.2"
37+
json = "0.12.4"
3738
rand = "0.8"
3839
rand_core = { version = "0.6", default-features = false, features = ["getrandom"] }
3940

@@ -69,6 +70,8 @@ precomputed-tables = []
6970
legacy_compatibility = []
7071
group = ["dep:group", "rand_core"]
7172
group-bits = ["group", "ff/bits"]
73+
elligator2 = []
74+
digest = ["dep:digest", "elligator2"]
7275

7376
[target.'cfg(all(not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial"), target_arch = "x86_64"))'.dependencies]
7477
curve25519-dalek-derive = { version = "0.1", path = "../curve25519-dalek-derive" }

curve25519-dalek/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ curve25519-dalek = ">= 4.0, < 4.2"
5656
| `serde` | | Enables `serde` serialization/deserialization for all the point and scalar types. |
5757
| `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. |
5858
| `group` | | Enables external `group` and `ff` crate traits |
59+
| `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. |
5960

6061
To disable the default features when using `curve25519-dalek` as a dependency,
6162
add `default-features = false` to the dependency in your `Cargo.toml`. To

curve25519-dalek/src/backend/serial/u32/constants.rs

+2
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,14 @@ pub(crate) const SQRT_M1: FieldElement2625 = FieldElement2625::from_limbs([
7171
pub(crate) const APLUS2_OVER_FOUR: FieldElement2625 =
7272
FieldElement2625::from_limbs([121666, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
7373

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

81+
#[cfg(feature = "elligator2")]
8082
/// `MONTGOMERY_A_NEG` is equal to -486662. (This is used internally within the
8183
/// Elligator map.)
8284
pub(crate) const MONTGOMERY_A_NEG: FieldElement2625 = FieldElement2625::from_limbs([

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

+20
Original file line numberDiff line numberDiff line change
@@ -601,4 +601,24 @@ impl FieldElement2625 {
601601
}
602602
FieldElement2625::reduce(coeffs)
603603
}
604+
605+
/// Returns 1 if self is greater than the other and 0 otherwise
606+
// implementation based on C libgmp -> mpn_sub_n
607+
pub(crate) fn gt(&self, other: &Self) -> Choice {
608+
let mut _ul = 0_u32;
609+
let mut _vl = 0_u32;
610+
let mut _rl = 0_u32;
611+
612+
let mut cy = 0_u32;
613+
for i in 0..10 {
614+
_ul = self.0[i];
615+
_vl = other.0[i];
616+
617+
let (_sl, _cy1) = _ul.overflowing_sub(_vl);
618+
let (_rl, _cy2) = _sl.overflowing_sub(cy);
619+
cy = _cy1 as u64 | _cy2 as u64;
620+
}
621+
622+
Choice::from((cy != 0_u32) as u8)
623+
}
604624
}

curve25519-dalek/src/backend/serial/u64/constants.rs

+2
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,13 @@ pub(crate) const SQRT_M1: FieldElement51 = FieldElement51::from_limbs([
9898
pub(crate) const APLUS2_OVER_FOUR: FieldElement51 =
9999
FieldElement51::from_limbs([121666, 0, 0, 0, 0]);
100100

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

107+
#[cfg(feature = "elligator2")]
106108
/// `MONTGOMERY_A_NEG` is equal to -486662. (This is used internally within the
107109
/// Elligator map.)
108110
pub(crate) const MONTGOMERY_A_NEG: FieldElement51 = FieldElement51::from_limbs([

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

+20
Original file line numberDiff line numberDiff line change
@@ -572,4 +572,24 @@ impl FieldElement51 {
572572

573573
square
574574
}
575+
576+
/// Returns 1 if self is greater than the other and 0 otherwise
577+
// implementation based on C libgmp -> mpn_sub_n
578+
pub(crate) fn gt(&self, other: &Self) -> Choice {
579+
let mut _ul = 0_u64;
580+
let mut _vl = 0_u64;
581+
let mut _rl = 0_u64;
582+
583+
let mut cy = 0_u64;
584+
for i in 0..5 {
585+
_ul = self.0[i];
586+
_vl = other.0[i];
587+
588+
let (_sl, _cy1) = _ul.overflowing_sub(_vl);
589+
let (_rl, _cy2) = _sl.overflowing_sub(cy);
590+
cy = _cy1 as u64 | _cy2 as u64;
591+
}
592+
593+
Choice::from((cy != 0_u64) as u8)
594+
}
575595
}

curve25519-dalek/src/edwards.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ use cfg_if::cfg_if;
106106

107107
#[cfg(feature = "digest")]
108108
use digest::{generic_array::typenum::U64, Digest};
109+
#[cfg(feature = "digest")]
110+
use crate::elligator2::map_to_point;
111+
109112

110113
#[cfg(feature = "group")]
111114
use {
@@ -595,9 +598,7 @@ impl EdwardsPoint {
595598

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

598-
let fe = FieldElement::from_bytes(&res);
599-
600-
let M1 = crate::montgomery::elligator_encode(&fe);
601+
let M1 = map_to_point(&res);
601602
let E1_opt = M1.to_edwards(sign_bit);
602603

603604
E1_opt

0 commit comments

Comments
 (0)