Skip to content

Commit e0ef773

Browse files
committed
removed legacy impl everything is working except signal testcases [skip ci]
1 parent 10f829a commit e0ef773

File tree

5 files changed

+40
-336
lines changed

5 files changed

+40
-336
lines changed

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

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -597,24 +597,4 @@ impl FieldElement51 {
597597

598598
Choice::from(c_gt as u8)
599599
}
600-
601-
/// Returns 1 if self is greater than the other and 0 otherwise
602-
// strategy: check if b-a overflows. if it does not overflow, then a was larger
603-
pub(crate) fn mpn_sub_n(&self, other: &Self) -> Choice {
604-
let mut _ul = 0_u64;
605-
let mut _vl = 0_u64;
606-
let mut _rl = 0_u64;
607-
608-
let mut cy = 0_u64;
609-
for i in 0..5 {
610-
_ul = self.0[i];
611-
_vl = other.0[i];
612-
613-
let (_sl, _cy1) = _ul.overflowing_sub(_vl);
614-
let (_rl, _cy2) = _sl.overflowing_sub(cy);
615-
cy = _cy1 as u64 | _cy2 as u64;
616-
}
617-
618-
Choice::from((cy != 0_u64) as u8)
619-
}
620600
}

curve25519-dalek/src/edwards.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,7 @@ impl EdwardsPoint {
588588
where
589589
D: Digest<OutputSize = U64> + Default,
590590
{
591-
use crate::elligator2::Legacy;
591+
use crate::elligator2::RFC9380;
592592

593593
let mut hash = D::new();
594594
hash.update(bytes);
@@ -601,7 +601,7 @@ impl EdwardsPoint {
601601
// rfc9380 should always result in a valid point since no field elements
602602
// are invalid. so unwrap should be safe.
603603
#[allow(clippy::unwrap_used)]
604-
let fe1 = MontgomeryPoint::from_representative::<Legacy>(&res).unwrap();
604+
let fe1 = MontgomeryPoint::from_representative::<RFC9380>(&res).unwrap();
605605
let E1_opt = fe1.to_edwards(sign_bit);
606606

607607
E1_opt

curve25519-dalek/src/elligator2.rs

Lines changed: 25 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,38 @@
3434
//! [`EdwardsPoint`] objects themselves.
3535
//!
3636
//! ```rust
37+
//! # use hex::FromHex;
3738
//! use rand::RngCore;
3839
//! use curve25519_dalek::{MontgomeryPoint, EdwardsPoint, elligator2::{RFC9380, Randomized, MapToPointVariant}};
3940
//!
4041
//! // Montgomery Points can be mapped to and from elligator representatives
4142
//! // using any algorithm variant.
4243
//! let tweak = rand::thread_rng().next_u32() as u8;
43-
//! let mont_point = MontgomeryPoint::default(); // example point known to be representable
44+
//! let mont_point = MontgomeryPoint::default(); // example private key point known to be representable
4445
//! let r = mont_point.to_representative::<RFC9380>(tweak).unwrap();
46+
//! let pubkey = RFC9380::mul_base_clamped(mont_point.to_bytes()).to_montgomery();
4547
//!
46-
//! _ = MontgomeryPoint::from_representative::<RFC9380>(&r).unwrap();
48+
//! let derived_pubkey = MontgomeryPoint::from_representative::<RFC9380>(&r).unwrap();
49+
//! assert_eq!(pubkey, derived_pubkey);
4750
//!
48-
//! // Edwards Points can be transformed as well.
51+
//! // Points in byte format can be transformed
52+
//!
53+
//! // (example known representable point)
54+
//! let mut point = <[u8;32]>::from_hex("00deadbeef00deadbeef00deadbeef00deadbeef00deadbeef00deadbeef0124").unwrap();
55+
//! let tweak = rand::thread_rng().next_u32() as u8;
56+
//! let r = RFC9380::to_representative(&point, tweak).unwrap();
57+
//! let pubkey = RFC9380::mul_base_clamped(point).to_montgomery();
58+
//!
59+
//! let derived_pubkey = MontgomeryPoint::from_representative::<RFC9380>(&r).unwrap();
60+
//! assert_eq!(pubkey, derived_pubkey);
61+
//!
62+
//! // Edwards Points can be transformed as well. This example uses the Randomized variant.
4963
//! let edw_point = EdwardsPoint::default(); // example point known to be representable
5064
//! let r = edw_point.to_representative::<Randomized>(tweak).unwrap();
65+
//! let pubkey = Randomized::mul_base_clamped(edw_point.to_montgomery().to_bytes());
5166
//!
52-
//! _ = EdwardsPoint::from_representative::<Randomized>(&r).unwrap();
67+
//! let derived_pubkey = EdwardsPoint::from_representative::<Randomized>(&r).unwrap();
68+
//! assert_eq!(pubkey, derived_pubkey);
5369
//! ```
5470
//!
5571
//! ### Generating Representable Points.
@@ -131,8 +147,7 @@ use crate::EdwardsPoint;
131147

132148
use cfg_if::cfg_if;
133149
use subtle::{
134-
Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater,
135-
CtOption,
150+
Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq, CtOption,
136151
};
137152

138153
/// bitmask for a single byte when clearing the high order two bits of a representative
@@ -141,10 +156,6 @@ pub(crate) const MASK_UNSET_BYTE: u8 = 0x3f;
141156
pub(crate) const MASK_SET_BYTE: u8 = 0xc0;
142157

143158
/// (p - 1) / 2 = 2^254 - 10
144-
pub(crate) const DIVIDE_MINUS_P_1_2_BYTES: [u8; 32] = [
145-
0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
146-
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
147-
];
148159
149160
/// Common interface for the different ways to compute the elligator2 forward
150161
/// and reverse transformations.
@@ -230,67 +241,6 @@ impl MapToPointVariant for Randomized {
230241
}
231242
}
232243

233-
#[cfg(feature = "digest")]
234-
/// In general this mode should **NEVER** be used unless there is a very specific
235-
/// reason to do so as it has multiple serious known flaws.
236-
///
237-
/// Converts between a point on elliptic curve E (Curve25519) and an element of
238-
/// the finite field F over which E is defined. Supports older implementations
239-
/// with a common implementation bug (Signal, Kleshni-C).
240-
///
241-
/// In contrast to the [`RFC9380`] variant, `Legacy` does NOT assume that input values are always
242-
/// going to be the least-square-root representation of the field element.
243-
/// This is divergent from the specifications for both elligator2 and RFC 9380,
244-
/// however, some older implementations miss this detail. This allows us to be
245-
/// compatible with those alternate implementations if necessary, since the
246-
/// resulting point will be different for inputs with either of the
247-
/// high-order two bits set. The kleshni C and Signal implementations are examples
248-
/// of libraries that don't always use the least square root.
249-
///
250-
// We return the LSR for to_representative values. This is here purely for testing
251-
// compatability and ensuring that we understand the subtle differences that can
252-
// influence proper implementation.
253-
pub struct Legacy;
254-
255-
#[cfg(feature = "digest")]
256-
impl MapToPointVariant for Legacy {
257-
fn from_representative(representative: &[u8; 32]) -> CtOption<EdwardsPoint> {
258-
let representative = FieldElement::from_bytes(representative);
259-
let (x, y) = map_fe_to_edwards(&representative);
260-
let point = EdwardsPoint {
261-
X: x,
262-
Y: y,
263-
Z: FieldElement::ONE,
264-
T: &x * &y,
265-
};
266-
CtOption::new(point, Choice::from(1))
267-
}
268-
269-
// There is a bug in the kleshni implementation where it
270-
// takes a sortcut when computng greater than for field elemements.
271-
// For the purpose of making tests pass matching the bugged implementation
272-
// I am adding the bug here intentionally. Legacy is not exposed and
273-
// should not be exposed as it is obviously flawed in multiple ways.
274-
//
275-
// What we want is:
276-
// If root - (p - 1) / 2 < 0, root := -root
277-
// This is not equivalent to:
278-
// if root > (p - 1)/2 root := -root
279-
//
280-
fn to_representative(point: &[u8; 32], _tweak: u8) -> CtOption<[u8; 32]> {
281-
let pubkey = EdwardsPoint::mul_base_clamped(*point);
282-
let v_in_sqrt = v_in_sqrt_pubkey_edwards(&pubkey);
283-
284-
point_to_representative(&MontgomeryPoint(*point), v_in_sqrt.into())
285-
286-
// let divide_minus_p_1_2 = FieldElement::from_bytes(&DIVIDE_MINUS_P_1_2_BYTES);
287-
// let did_negate = divide_minus_p_1_2.ct_gt(&b);
288-
// let should_negate = Self::gt(&b, &divide_minus_p_1_2);
289-
// FieldElement::conditional_negate(&mut b, did_negate ^ should_negate);
290-
// CtOption::new(b.as_bytes(), c)
291-
}
292-
}
293-
294244
// ===========================================================================
295245
// Montgomery and Edwards Interfaces
296246
// ===========================================================================
@@ -577,8 +527,6 @@ pub(crate) fn point_to_representative(
577527
point: &MontgomeryPoint,
578528
v_in_sqrt: bool,
579529
) -> CtOption<[u8; 32]> {
580-
let divide_minus_p_1_2 = FieldElement::from_bytes(&DIVIDE_MINUS_P_1_2_BYTES);
581-
582530
// a := point
583531
let a = &FieldElement::from_bytes(&point.0);
584532
let a_neg = -a;
@@ -602,7 +550,8 @@ pub(crate) fn point_to_representative(
602550

603551
// If root > (p - 1) / 2, root := -root
604552
// let negate = divide_minus_p_1_2.ct_gt(&b);
605-
let negate = divide_minus_p_1_2.mpn_sub_n(&b);
553+
// let negate = divide_minus_p_1_2.mpn_sub_n(&b);
554+
let negate = b.is_negative();
606555
FieldElement::conditional_negate(&mut b, negate);
607556

608557
CtOption::new(b.as_bytes(), is_encodable)
@@ -678,8 +627,6 @@ pub(crate) fn v_in_sqrt(key_input: &[u8; 32]) -> Choice {
678627
/// Determines if `V <= (p - 1)/2` for an EdwardsPoint (e.g an x25519 public key)
679628
/// and returns a [`Choice`] indicating the result.
680629
pub(crate) fn v_in_sqrt_pubkey_edwards(pubkey: &EdwardsPoint) -> Choice {
681-
let divide_minus_p_1_2 = FieldElement::from_bytes(&DIVIDE_MINUS_P_1_2_BYTES);
682-
683630
// sqrtMinusAPlus2 is sqrt(-(486662+2))
684631
let (_, sqrt_minus_a_plus_2) = FieldElement::sqrt_ratio_i(
685632
&(&MONTGOMERY_A_NEG - &(&FieldElement::ONE + &FieldElement::ONE)),
@@ -697,8 +644,8 @@ pub(crate) fn v_in_sqrt_pubkey_edwards(pubkey: &EdwardsPoint) -> Choice {
697644

698645
// is v <= (q-1)/2 ?
699646
// divide_minus_p_1_2.ct_gt(&v)
700-
// v.is_negative()
701-
divide_minus_p_1_2.mpn_sub_n(&v)
647+
// divide_minus_p_1_2.mpn_sub_n(&v)
648+
!v.is_negative()
702649
}
703650

704651
// ============================================================================
@@ -800,8 +747,3 @@ mod randomness;
800747
#[cfg(test)]
801748
#[cfg(feature = "elligator2")]
802749
mod subgroup;
803-
804-
#[cfg(test)]
805-
#[cfg(feature = "elligator2")]
806-
#[cfg(feature = "digest")]
807-
mod legacy;

curve25519-dalek/src/elligator2/compatibility.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,23 @@
11
use super::*;
2-
32
use hex::FromHex;
43

54
////////////////////////////////////////////////////////////
65
// Ntor tests //
76
////////////////////////////////////////////////////////////
87

8+
9+
#[test]
10+
#[cfg(feature = "elligator2")]
11+
fn ident_is_representable() {
12+
let m = MontgomeryPoint::default();
13+
let repres = m.to_representative::<RFC9380>(0u8).expect("should succeed, I think");
14+
let pubkey = RFC9380::mul_base_clamped(m.to_bytes()).to_montgomery();
15+
16+
// let orig = MontgomeryPoint::from_representative::<RFC9380>(&out).expect("should prob also work");
17+
let orig = MontgomeryPoint::map_to_point(&repres);
18+
assert_eq!(&pubkey, &orig);
19+
}
20+
921
#[test]
1022
#[cfg(feature = "elligator2")]
1123
fn pubkey_from_repres() {

0 commit comments

Comments
 (0)