Skip to content

Commit 6a9d8f0

Browse files
authored
ed448-goldilocks: fix Decaf448 map2curve and add test vectors (#1283)
1 parent d338e11 commit 6a9d8f0

File tree

2 files changed

+113
-48
lines changed

2 files changed

+113
-48
lines changed

ed448-goldilocks/src/decaf.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,78 @@ mod scalar;
99
pub use affine::AffinePoint;
1010
pub use points::{CompressedDecaf, DecafPoint};
1111
pub use scalar::{DecafScalar, DecafScalarBytes, WideDecafScalarBytes};
12+
13+
// https://www.rfc-editor.org/rfc/rfc9496#name-group-elements-from-uniform-
14+
#[test]
15+
fn hash_to_curve() {
16+
use hex_literal::hex;
17+
18+
const TEST_VECTORS: [TestVector; 7] = [
19+
TestVector {
20+
input: hex!(
21+
"cbb8c991fd2f0b7e1913462d6463e4fd2ce4ccdd28274dc2ca1f4165d5ee6cdccea57be3416e166fd06718a31af45a2f8e987e301be59ae6673e963001dbbda80df47014a21a26d6c7eb4ebe0312aa6fffb8d1b26bc62ca40ed51f8057a635a02c2b8c83f48fa6a2d70f58a1185902c0"
22+
),
23+
output: hex!(
24+
"0c709c9607dbb01c94513358745b7c23953d03b33e39c7234e268d1d6e24f34014ccbc2216b965dd231d5327e591dc3c0e8844ccfd568848"
25+
),
26+
},
27+
TestVector {
28+
input: hex!(
29+
"b6d8da654b13c3101d6634a231569e6b85961c3f4b460a08ac4a5857069576b64428676584baa45b97701be6d0b0ba18ac28d443403b45699ea0fbd1164f5893d39ad8f29e48e399aec5902508ea95e33bc1e9e4620489d684eb5c26bc1ad1e09aba61fabc2cdfee0b6b6862ffc8e55a"
30+
),
31+
output: hex!(
32+
"76ab794e28ff1224c727fa1016bf7f1d329260b7218a39aea2fdb17d8bd9119017b093d641cedf74328c327184dc6f2a64bd90eddccfcdab"
33+
),
34+
},
35+
TestVector {
36+
input: hex!(
37+
"36a69976c3e5d74e4904776993cbac27d10f25f5626dd45c51d15dcf7b3e6a5446a6649ec912a56895d6baa9dc395ce9e34b868d9fb2c1fc72eb6495702ea4f446c9b7a188a4e0826b1506b0747a6709f37988ff1aeb5e3788d5076ccbb01a4bc6623c92ff147a1e21b29cc3fdd0e0f4"
38+
),
39+
output: hex!(
40+
"c8d7ac384143500e50890a1c25d643343accce584caf2544f9249b2bf4a6921082be0e7f3669bb5ec24535e6c45621e1f6dec676edd8b664"
41+
),
42+
},
43+
TestVector {
44+
input: hex!(
45+
"d5938acbba432ecd5617c555a6a777734494f176259bff9dab844c81aadcf8f7abd1a9001d89c7008c1957272c1786a4293bb0ee7cb37cf3988e2513b14e1b75249a5343643d3c5e5545a0c1a2a4d3c685927c38bc5e5879d68745464e2589e000b31301f1dfb7471a4f1300d6fd0f99"
46+
),
47+
output: hex!(
48+
"62beffc6b8ee11ccd79dbaac8f0252c750eb052b192f41eeecb12f2979713b563caf7d22588eca5e80995241ef963e7ad7cb7962f343a973"
49+
),
50+
},
51+
TestVector {
52+
input: hex!(
53+
"4dec58199a35f531a5f0a9f71a53376d7b4bdd6bbd2904234a8ea65bbacbce2a542291378157a8f4be7b6a092672a34d85e473b26ccfbd4cdc6739783dc3f4f6ee3537b7aed81df898c7ea0ae89a15b5559596c2a5eeacf8b2b362f3db2940e3798b63203cae77c4683ebaed71533e51"
54+
),
55+
output: hex!(
56+
"f4ccb31d263731ab88bed634304956d2603174c66da38742053fa37dd902346c3862155d68db63be87439e3d68758ad7268e239d39c4fd3b"
57+
),
58+
},
59+
TestVector {
60+
input: hex!(
61+
"df2aa1536abb4acab26efa538ce07fd7bca921b13e17bc5ebcba7d1b6b733deda1d04c220f6b5ab35c61b6bcb15808251cab909a01465b8ae3fc770850c66246d5a9eae9e2877e0826e2b8dc1bc08009590bc6778a84e919fbd28e02a0f9c49b48dc689eb5d5d922dc01469968ee81b5"
62+
),
63+
output: hex!(
64+
"7e79b00e8e0a76a67c0040f62713b8b8c6d6f05e9c6d02592e8a22ea896f5deacc7c7df5ed42beae6fedb9000285b482aa504e279fd49c32"
65+
),
66+
},
67+
TestVector {
68+
input: hex!(
69+
"e9fb440282e07145f1f7f5ecf3c273212cd3d26b836b41b02f108431488e5e84bd15f2418b3d92a3380dd66a374645c2a995976a015632d36a6c2189f202fc766e1c82f50ad9189be190a1f0e8f9b9e69c9c18cc98fdd885608f68bf0fdedd7b894081a63f70016a8abf04953affbefa"
70+
),
71+
output: hex!(
72+
"20b171cb16be977f15e013b9752cf86c54c631c4fc8cbf7c03c4d3ac9b8e8640e7b0e9300b987fe0ab5044669314f6ed1650ae037db853f1"
73+
),
74+
},
75+
];
76+
77+
struct TestVector {
78+
input: [u8; 112],
79+
output: [u8; 56],
80+
}
81+
82+
for TestVector { input, output } in TEST_VECTORS {
83+
let point = DecafPoint::from_uniform_bytes(&input);
84+
assert_eq!(point.compress().as_bytes(), output);
85+
}
86+
}

ed448-goldilocks/src/field/element.rs

Lines changed: 38 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -338,27 +338,6 @@ impl FieldElement {
338338
(inv_sqrt_x * u, zero_u | is_res)
339339
}
340340

341-
/// Computes the square root ratio of two elements
342-
///
343-
/// The difference between this and `sqrt_ratio` is that
344-
/// if the input is non-square, the function returns a result with
345-
/// a defined relationship to the inputs.
346-
pub(crate) fn sqrt_ratio_i(u: &FieldElement, v: &FieldElement) -> (FieldElement, Choice) {
347-
const P_MINUS_THREE_DIV_4: U448 = U448::from_be_hex(
348-
"3fffffffffffffffffffffffffffffffffffffffffffffffffffffffbfffffffffffffffffffffffffffffffffffffffffffffffffffffff",
349-
);
350-
let u = u.0;
351-
let v = v.0;
352-
353-
let r = u * (u * v).pow(&P_MINUS_THREE_DIV_4);
354-
let check = v * r.square();
355-
let was_square = check.ct_eq(&u);
356-
357-
let mut r = FieldElement(r);
358-
r.conditional_negate(r.is_negative());
359-
(r, was_square)
360-
}
361-
362341
pub(crate) fn map_to_curve_elligator2(&self) -> AffinePoint {
363342
let mut t1 = self.square(); // 1. t1 = u^2
364343
t1 *= Self::Z; // 2. t1 = Z * t1 // Z * u^2
@@ -382,38 +361,49 @@ impl FieldElement {
382361
AffinePoint { x, y }
383362
}
384363

364+
// See https://www.shiftleft.org/papers/decaf/decaf.pdf#section.A.3.
365+
// Implementation copied from <https://sourceforge.net/p/ed448goldilocks/code/ci/e5cc6240690d3ffdfcbdb1e4e851954b789cd5d9/tree/src/per_curve/elligator.tmpl.c#l28>.
385366
pub(crate) fn map_to_curve_decaf448(&self) -> TwistedExtendedPoint {
386367
const ONE_MINUS_TWO_D: FieldElement =
387368
FieldElement(ConstMontyType::new(&U448::from_u64(78163)));
388369

389370
let r = -self.square();
390-
let u0 = Self::EDWARDS_D * (r - Self::ONE);
391-
let u1 = (u0 + Self::ONE) * (u0 - r);
392-
393-
let rhs = (r + Self::ONE) * u1;
394-
let (v, was_square) = Self::sqrt_ratio_i(&ONE_MINUS_TWO_D, &rhs);
395-
396-
let mut v_prime = self * v;
397-
v_prime.conditional_assign(&v, was_square);
398-
let mut sgn = Self::MINUS_ONE;
399-
sgn.conditional_negate(was_square);
400-
401-
let s = v_prime * (r + Self::ONE);
402-
let s2 = s.square();
403-
let s_abs = Self::conditional_select(&s, &s.neg(), s.is_negative());
404-
405-
let w0 = s_abs + s_abs;
406-
let w1 = s2 + Self::ONE;
407-
let w2 = s2 - Self::ONE;
408-
let w3 = v_prime * s * (r - Self::ONE) * ONE_MINUS_TWO_D + sgn;
409-
410-
EdwardsPoint {
411-
X: w0 * w3,
412-
Y: w2 * w1,
413-
Z: w1 * w3,
414-
T: w0 * w2,
415-
}
416-
.to_twisted()
371+
372+
let a = r - Self::ONE;
373+
let b = a * Self::EDWARDS_D;
374+
let a = b + Self::ONE;
375+
let b = b - r;
376+
let c = a * b;
377+
378+
let a = r + Self::ONE;
379+
let n = a * ONE_MINUS_TWO_D;
380+
381+
let a = c * n;
382+
let (b, square) = a.inverse_square_root();
383+
let c = Self::conditional_select(self, &Self::ONE, square);
384+
let e = b * c;
385+
386+
let mut a = n * e;
387+
a.conditional_negate(!Choice::from(a.0.retrieve().bit(0)) ^ square);
388+
389+
let c = e * ONE_MINUS_TWO_D;
390+
let b = c.square();
391+
let e = r - Self::ONE;
392+
let c = b * e;
393+
let mut b = c * n;
394+
b.conditional_negate(square);
395+
let b = b - Self::ONE;
396+
397+
let c = a.square();
398+
let a = a + a;
399+
let e = c + Self::ONE;
400+
let T = a * e;
401+
let X = a * b;
402+
let a = Self::ONE - c;
403+
let Y = e * a;
404+
let Z = a * b;
405+
406+
TwistedExtendedPoint { X, Y, Z, T }
417407
}
418408
}
419409

0 commit comments

Comments
 (0)