@@ -231,6 +231,9 @@ impl MapToPointVariant for Randomized {
231231}
232232
233233#[ 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+ ///
234237/// Converts between a point on elliptic curve E (Curve25519) and an element of
235238/// the finite field F over which E is defined. Supports older implementations
236239/// with a common implementation bug (Signal, Kleshni-C).
@@ -244,9 +247,6 @@ impl MapToPointVariant for Randomized {
244247/// high-order two bits set. The kleshni C and Signal implementations are examples
245248/// of libraries that don't always use the least square root.
246249///
247- /// In general this mode should NOT be used unless there is a very specific
248- /// reason to do so.
249- ///
250250// We return the LSR for to_representative values. This is here purely for testing
251251// compatability and ensuring that we understand the subtle differences that can
252252// influence proper implementation.
@@ -266,10 +266,28 @@ impl MapToPointVariant for Legacy {
266266 CtOption :: new ( point, Choice :: from ( 1 ) )
267267 }
268268
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+ //
269280 fn to_representative ( point : & [ u8 ; 32 ] , _tweak : u8 ) -> CtOption < [ u8 ; 32 ] > {
270281 let pubkey = EdwardsPoint :: mul_base_clamped ( * point) ;
271282 let v_in_sqrt = v_in_sqrt_pubkey_edwards ( & pubkey) ;
283+
272284 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, ÷_minus_p_1_2);
289+ // FieldElement::conditional_negate(&mut b, did_negate ^ should_negate);
290+ // CtOption::new(b.as_bytes(), c)
273291 }
274292}
275293
@@ -583,7 +601,8 @@ pub(crate) fn point_to_representative(
583601 let mut b = FieldElement :: conditional_select ( & r1, & r0, Choice :: from ( v_in_sqrt as u8 ) ) ;
584602
585603 // If root > (p - 1) / 2, root := -root
586- let negate = divide_minus_p_1_2. ct_gt ( & b) ;
604+ // let negate = divide_minus_p_1_2.ct_gt(&b);
605+ let negate = divide_minus_p_1_2. mpn_sub_n ( & b) ;
587606 FieldElement :: conditional_negate ( & mut b, negate) ;
588607
589608 CtOption :: new ( b. as_bytes ( ) , is_encodable)
@@ -677,7 +696,9 @@ pub(crate) fn v_in_sqrt_pubkey_edwards(pubkey: &EdwardsPoint) -> Choice {
677696 let v = & ( & t0 * & inv1) * & ( & pubkey. Z * & sqrt_minus_a_plus_2) ;
678697
679698 // is v <= (q-1)/2 ?
680- divide_minus_p_1_2. ct_gt ( & v)
699+ // divide_minus_p_1_2.ct_gt(&v)
700+ // v.is_negative()
701+ divide_minus_p_1_2. mpn_sub_n ( & v)
681702}
682703
683704// ============================================================================
0 commit comments