ed448_goldilocks/decaf/
scalar.rs1use crate::Decaf448;
2use crate::field::{CurveWithScalar, ORDER, Scalar, ScalarBytes, WideScalarBytes};
3
4use elliptic_curve::array::Array;
5use elliptic_curve::bigint::{Limb, NonZero, U448, U512};
6use elliptic_curve::consts::{U56, U64};
7use elliptic_curve::ops::Reduce;
8use elliptic_curve::scalar::FromUintUnchecked;
9use subtle::{Choice, ConstantTimeEq, CtOption};
10
11impl CurveWithScalar for Decaf448 {
12 type ReprSize = U56;
13
14 fn from_bytes_mod_order_wide(input: &WideScalarBytes<Self>) -> Scalar<Self> {
15 let value = (
16 U448::from_le_slice(&input[..56]),
17 U448::from_le_slice(&input[56..112]),
18 );
19 Scalar::new(U448::rem_wide_vartime(value, ORDER.as_nz_ref()))
20 }
21
22 fn from_canonical_bytes(bytes: &ScalarBytes<Self>) -> subtle::CtOption<Scalar<Self>> {
23 let is_valid = (bytes[55] >> 6).ct_eq(&0);
25 let bytes: [u8; 56] = core::array::from_fn(|i| bytes[i]);
26 let candidate = Scalar::new(U448::from_le_slice(&bytes));
27
28 let (_, underflow) = candidate.scalar.borrowing_sub(&ORDER, Limb::ZERO);
30 let underflow = Choice::from((underflow.0 >> (Limb::BITS - 1)) as u8);
31 CtOption::new(candidate, underflow & is_valid)
32 }
33
34 fn to_repr(scalar: &Scalar<Self>) -> ScalarBytes<Self> {
35 scalar.to_bytes().into()
36 }
37}
38
39pub type DecafScalar = Scalar<Decaf448>;
41
42impl DecafScalar {
43 pub fn from_bytes_mod_order_wide(input: &WideDecafScalarBytes) -> DecafScalar {
46 Decaf448::from_bytes_mod_order_wide(input)
47 }
48}
49
50elliptic_curve::scalar_impls!(Decaf448, DecafScalar);
51
52pub type DecafScalarBytes = ScalarBytes<Decaf448>;
54pub type WideDecafScalarBytes = WideScalarBytes<Decaf448>;
56
57impl Reduce<Array<u8, U64>> for DecafScalar {
58 fn reduce(value: &Array<u8, U64>) -> Self {
59 const SEMI_WIDE_MODULUS: NonZero<U512> = NonZero::<U512>::new_unwrap(U512::from_be_hex(
60 "00000000000000003fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3",
61 ));
62
63 let mut num = U512::from_le_slice(value);
64 num %= SEMI_WIDE_MODULUS;
65 let mut words = [0; U448::LIMBS];
66 words.copy_from_slice(&num.to_words()[..U448::LIMBS]);
67 Scalar::new(U448::from_words(words))
68 }
69}
70
71#[cfg(test)]
72mod test {
73 use super::*;
74 use elliptic_curve::PrimeField;
75 use elliptic_curve::array::Array;
76 use hash2curve::ExpandMsgXof;
77 use hex_literal::hex;
78 use proptest::property_test;
79 use shake::Shake256;
80
81 #[test]
82 fn test_basic_add() {
83 let five = DecafScalar::from(5u8);
84 let six = DecafScalar::from(6u8);
85
86 assert_eq!(five + six, DecafScalar::from(11u8))
87 }
88
89 #[test]
90 fn test_basic_sub() {
91 let ten = DecafScalar::from(10u8);
92 let five = DecafScalar::from(5u8);
93 assert_eq!(ten - five, DecafScalar::from(5u8))
94 }
95
96 #[test]
97 fn test_basic_mul() {
98 let ten = DecafScalar::from(10u8);
99 let five = DecafScalar::from(5u8);
100
101 assert_eq!(ten * five, DecafScalar::from(50u8))
102 }
103
104 #[test]
105 fn test_mul() {
106 let a = DecafScalar::new(U448::from_be_hex(
107 "1e63e8073b089f0747cf8cac2c3dc2732aae8688a8fa552ba8cb0ae8c0be082e74d657641d9ac30a087b8fb97f8ed27dc96a3c35ffb823a3",
108 ));
109
110 let b = DecafScalar::new(U448::from_be_hex(
111 "16c5450acae1cb680a92de2d8e59b30824e8d4991adaa0e7bc343bcbd099595b188c6b1a1e30b38b17aa6d9be416b899686eb329d8bedc42",
112 ));
113
114 let exp = DecafScalar::new(U448::from_be_hex(
115 "31e055c14ca389edfccd61b3203d424bb9036ff6f2d89c1e07bcd93174e9335f36a1492008a3a0e46abd26f5994c9c2b1f5b3197a18d010a",
116 ));
117
118 assert_eq!(a * b, exp)
119 }
120 #[test]
121 fn test_basic_square() {
122 let a = DecafScalar::new(U448::from_be_hex(
123 "3162081604b3273b930392e5d2391f9d21cc3078f22c69514bb395e08dccc4866f08f3311370f8b83fa50692f640922b7e56a34bcf5fac3d",
124 ));
125 let expected_a_squared = DecafScalar::new(U448::from_be_hex(
126 "1c1e32fc66b21c9c42d6e8e20487193cf6d49916421b290098f30de3713006cfe8ee9d21eeef7427f82a1fe036630c74b9acc2c2ede40f04",
127 ));
128
129 assert_eq!(a.square(), expected_a_squared)
130 }
131
132 #[test]
133 fn test_sanity_check_index_mut() {
134 let mut x = DecafScalar::ONE;
135 x[0] = 2;
136 assert_eq!(x, DecafScalar::from(2u8))
137 }
138 #[test]
139 fn test_basic_halving() {
140 let eight = DecafScalar::from(8u8);
141 let four = DecafScalar::from(4u8);
142 let two = DecafScalar::from(2u8);
143 assert_eq!(eight.div_by_2(), four);
144 assert_eq!(four.div_by_2(), two);
145 assert_eq!(two.div_by_2(), DecafScalar::ONE);
146 }
147
148 #[test]
149 fn test_equals() {
150 let a = DecafScalar::from(5u8);
151 let b = DecafScalar::from(5u8);
152 let c = DecafScalar::from(10u8);
153 assert_eq!(a, b);
154 assert_ne!(a, c);
155 }
156
157 #[test]
158 fn test_basic_inversion() {
159 for i in 1..=100u8 {
161 let x = DecafScalar::from(i);
162 let x_inv = x.invert();
163 assert_eq!(x_inv * x, DecafScalar::ONE)
164 }
165
166 let zero = DecafScalar::ZERO;
168 let expected_zero = zero.invert();
169 assert_eq!(expected_zero, zero)
170 }
171 #[test]
172 fn test_serialise() {
173 let scalar = DecafScalar::new(U448::from_be_hex(
174 "0d79f6e375d3395ed9a6c4c3c49a1433fd7c58aa38363f74e9ab2c22a22347d79988f8e01e8a309f862a9f1052fcd042b9b1ed7115598f62",
175 ));
176 let got = DecafScalar::from_canonical_bytes(&scalar.into()).unwrap();
177 assert_eq!(scalar, got)
178 }
179 #[test]
180 fn test_from_canonical_bytes() {
181 let mut bytes = DecafScalarBytes::from(hex!(
183 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
184 ));
185 bytes.reverse();
186 let s = DecafScalar::from_canonical_bytes(&bytes);
187 assert!(<Choice as Into<bool>>::into(s.is_none()));
188
189 let mut bytes = DecafScalarBytes::from(hex!(
191 "3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3"
192 ));
193 bytes.reverse();
194 let s = DecafScalar::from_canonical_bytes(&bytes);
195 assert!(<Choice as Into<bool>>::into(s.is_none()));
196
197 let mut bytes = DecafScalarBytes::from(hex!(
199 "3fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f2"
200 ));
201 bytes.reverse();
202 let s = DecafScalar::from_canonical_bytes(&bytes);
203 match Option::<DecafScalar>::from(s) {
204 Some(s) => assert_eq!(s, DecafScalar::ZERO - DecafScalar::ONE),
205 None => panic!("should not return None"),
206 };
207 }
208
209 #[test]
210 fn test_from_bytes_mod_order_wide() {
211 let mut bytes = WideDecafScalarBytes::from(hex!(
213 "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f3"
214 ));
215 bytes.reverse();
216 let s = DecafScalar::from_bytes_mod_order_wide(&bytes);
217 assert_eq!(s, DecafScalar::ZERO);
218
219 let mut bytes = WideDecafScalarBytes::from(hex!(
221 "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f2"
222 ));
223 bytes.reverse();
224 let s = DecafScalar::from_bytes_mod_order_wide(&bytes);
225 assert_eq!(s, DecafScalar::ZERO - DecafScalar::ONE);
226
227 let mut bytes = WideDecafScalarBytes::from(hex!(
229 "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003fffffffffffffffffffffffffffffffffffffffffffffffffffffff7cca23e9c44edb49aed63690216cc2728dc58f552378c292ab5844f4"
230 ));
231 bytes.reverse();
232 let s = DecafScalar::from_bytes_mod_order_wide(&bytes);
233 assert_eq!(s, DecafScalar::ONE);
234
235 let bytes = WideDecafScalarBytes::from(hex!(
237 "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
238 ));
239 let s = DecafScalar::from_bytes_mod_order_wide(&bytes);
240 let mut bytes = DecafScalarBytes::from(hex!(
241 "3402a939f823b7292052bcb7e4d070af1a9cc14ba3c47c44ae17cf725ee4d8380d66de2388ea18597af32c4bc1b195d9e3539257049b9b5f"
242 ));
243 bytes.reverse();
244 let reduced = DecafScalar::from_canonical_bytes(&bytes).unwrap();
245 assert_eq!(s, reduced);
246 }
247
248 #[cfg(all(feature = "alloc", feature = "serde"))]
249 #[test]
250 fn serde() {
251 use elliptic_curve::PrimeField;
252
253 let res = serde_json::to_string(&DecafScalar::TWO_INV);
254 assert!(res.is_ok());
255 let sj = res.unwrap();
256
257 let res = serde_json::from_str::<DecafScalar>(&sj);
258 assert!(res.is_ok());
259 assert_eq!(res.unwrap(), DecafScalar::TWO_INV);
260
261 let res = serde_bare::to_vec(&DecafScalar::TWO_INV);
262 assert!(res.is_ok());
263 let sb = res.unwrap();
264 assert_eq!(sb.len(), 57);
265
266 let res = serde_bare::from_slice::<DecafScalar>(&sb);
267 assert!(res.is_ok());
268 assert_eq!(res.unwrap(), DecafScalar::TWO_INV);
269 }
270
271 #[test]
272 fn scalar_hash() {
273 let msg = b"hello world";
274 let dst = b"decaf448_XOF:SHAKE256_D448MAP_RO_";
275 let res =
276 hash2curve::hash_to_scalar::<Decaf448, ExpandMsgXof<Shake256>, U64>(&[msg], &[dst])
277 .unwrap();
278 let expected: [u8; 56] = hex_literal::hex!(
279 "55e7b59aa035db959409c6b69b817a18c8133d9ad06687665f5720672924da0a84eab7fee415ef13e7aaebdd227291ee8e156f32c507ad2e"
280 );
281 assert_eq!(res.to_repr(), Array::from(expected));
282 }
283
284 #[test]
286 fn hash_to_scalar_voprf() {
287 struct TestVector {
288 dst: &'static [u8],
289 sk_sm: &'static [u8],
290 }
291
292 const KEY_INFO: &[u8] = b"test key";
293 const SEED: &[u8] =
294 &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3");
295
296 const TEST_VECTORS: &[TestVector] = &[
297 TestVector {
298 dst: b"DeriveKeyPairOPRFV1-\x00-decaf448-SHAKE256",
299 sk_sm: &hex!(
300 "e8b1375371fd11ebeb224f832dcc16d371b4188951c438f751425699ed29ecc80c6c13e558ccd67634fd82eac94aa8d1f0d7fee990695d1e"
301 ),
302 },
303 TestVector {
304 dst: b"DeriveKeyPairOPRFV1-\x01-decaf448-SHAKE256",
305 sk_sm: &hex!(
306 "e3c01519a076a326a0eb566343e9b21c115fa18e6e85577ddbe890b33104fcc2835ddfb14a928dc3f5d79b936e17c76b99e0bf6a1680930e"
307 ),
308 },
309 TestVector {
310 dst: b"DeriveKeyPairOPRFV1-\x02-decaf448-SHAKE256",
311 sk_sm: &hex!(
312 "792a10dcbd3ba4a52a054f6f39186623208695301e7adb9634b74709ab22de402990eb143fd7c67ac66be75e0609705ecea800992aac8e19"
313 ),
314 },
315 ];
316
317 let key_info_len = u16::try_from(KEY_INFO.len()).unwrap().to_be_bytes();
318
319 'outer: for test_vector in TEST_VECTORS {
320 for counter in 0_u8..=u8::MAX {
321 let scalar = hash2curve::hash_to_scalar::<Decaf448, ExpandMsgXof<Shake256>, U64>(
322 &[SEED, &key_info_len, KEY_INFO, &counter.to_be_bytes()],
323 &[test_vector.dst],
324 )
325 .unwrap();
326
327 if !bool::from(scalar.is_zero()) {
328 assert_eq!(scalar.to_bytes().as_slice(), test_vector.sk_sm);
329 continue 'outer;
330 }
331 }
332
333 panic!("deriving key failed");
334 }
335 }
336
337 #[property_test]
338 fn from_canonical_bytes(bytes: [u8; 56]) {
339 DecafScalar::from_canonical_bytes(&bytes.into());
340 }
341}