@@ -231,6 +231,9 @@ impl MapToPointVariant for Randomized {
231
231
}
232
232
233
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
+ ///
234
237
/// Converts between a point on elliptic curve E (Curve25519) and an element of
235
238
/// the finite field F over which E is defined. Supports older implementations
236
239
/// with a common implementation bug (Signal, Kleshni-C).
@@ -244,9 +247,6 @@ impl MapToPointVariant for Randomized {
244
247
/// high-order two bits set. The kleshni C and Signal implementations are examples
245
248
/// of libraries that don't always use the least square root.
246
249
///
247
- /// In general this mode should NOT be used unless there is a very specific
248
- /// reason to do so.
249
- ///
250
250
// We return the LSR for to_representative values. This is here purely for testing
251
251
// compatability and ensuring that we understand the subtle differences that can
252
252
// influence proper implementation.
@@ -266,10 +266,28 @@ impl MapToPointVariant for Legacy {
266
266
CtOption :: new ( point, Choice :: from ( 1 ) )
267
267
}
268
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
+ //
269
280
fn to_representative ( point : & [ u8 ; 32 ] , _tweak : u8 ) -> CtOption < [ u8 ; 32 ] > {
270
281
let pubkey = EdwardsPoint :: mul_base_clamped ( * point) ;
271
282
let v_in_sqrt = v_in_sqrt_pubkey_edwards ( & pubkey) ;
283
+
272
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, ÷_minus_p_1_2);
289
+ // FieldElement::conditional_negate(&mut b, did_negate ^ should_negate);
290
+ // CtOption::new(b.as_bytes(), c)
273
291
}
274
292
}
275
293
@@ -583,7 +601,8 @@ pub(crate) fn point_to_representative(
583
601
let mut b = FieldElement :: conditional_select ( & r1, & r0, Choice :: from ( v_in_sqrt as u8 ) ) ;
584
602
585
603
// 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) ;
587
606
FieldElement :: conditional_negate ( & mut b, negate) ;
588
607
589
608
CtOption :: new ( b. as_bytes ( ) , is_encodable)
@@ -677,7 +696,9 @@ pub(crate) fn v_in_sqrt_pubkey_edwards(pubkey: &EdwardsPoint) -> Choice {
677
696
let v = & ( & t0 * & inv1) * & ( & pubkey. Z * & sqrt_minus_a_plus_2) ;
678
697
679
698
// 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)
681
702
}
682
703
683
704
// ============================================================================
0 commit comments