1use super::FieldElement;
2use crate::{AffinePoint, NistP521, ProjectivePoint, Scalar, Uint};
3use elliptic_curve::{
4 FieldBytesEncoding,
5 array::Array,
6 consts::{U32, U98},
7 ops::Reduce,
8 subtle::Choice,
9};
10use hash2curve::MapToCurve;
11use primeorder::osswu::{AffineOsswuMap, OsswuMap, OsswuMapParams, Sgn0};
12
13#[cfg(feature = "group-digest")]
14impl hash2curve::GroupDigest for NistP521 {
15 const HASH_TO_CURVE_ID: &[u8] = b"P521_XMD:SHA-512_SSWU_RO_";
16 const ENCODE_TO_CURVE_ID: &[u8] = b"P521_XMD:SHA-512_SSWU_NU_";
17
18 type ExpandMsg = hash2curve::ExpandMsgXmd<sha2::Sha512>;
19}
20
21impl Reduce<Array<u8, U98>> for FieldElement {
22 fn reduce(value: &Array<u8, U98>) -> Self {
23 const F_2_392: FieldElement = FieldElement::from_hex(
24 "000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
25 );
26
27 let mut d0 = Array::default();
28 d0[17..].copy_from_slice(&value[0..49]);
29 let u0 = <Uint as FieldBytesEncoding<NistP521>>::decode_field_bytes(&d0);
30 let d0 = FieldElement::from_uint_unchecked(u0);
31
32 let mut d1 = Array::default();
33 d1[17..].copy_from_slice(&value[49..]);
34 let u1 = <Uint as FieldBytesEncoding<NistP521>>::decode_field_bytes(&d1);
35 let d1 = FieldElement::from_uint_unchecked(u1);
36
37 d0 * F_2_392 + d1
38 }
39}
40
41impl Sgn0 for FieldElement {
42 fn sgn0(&self) -> Choice {
43 self.is_odd()
44 }
45}
46
47impl OsswuMap for FieldElement {
48 const PARAMS: OsswuMapParams<Self> = OsswuMapParams {
49 c1: &[
50 0xffff_ffff_ffff_ffff,
51 0xffff_ffff_ffff_ffff,
52 0xffff_ffff_ffff_ffff,
53 0xffff_ffff_ffff_ffff,
54 0xffff_ffff_ffff_ffff,
55 0xffff_ffff_ffff_ffff,
56 0xffff_ffff_ffff_ffff,
57 0xffff_ffff_ffff_ffff,
58 0x0000_0000_0000_007f,
59 ],
60 c2: FieldElement::from_u64(2),
61 map_a: FieldElement::from_u64(3).neg(),
62 map_b: FieldElement::from_hex(
63 "0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00",
64 ),
65 z: FieldElement::from_u64(4).neg(),
66 };
67}
68
69impl MapToCurve for NistP521 {
70 type SecurityLevel = U32;
71 type FieldElement = FieldElement;
72 type Length = U98;
73
74 fn map_to_curve(element: FieldElement) -> ProjectivePoint {
75 AffinePoint::osswu(&element).into()
76 }
77}
78
79impl Reduce<Array<u8, U98>> for Scalar {
80 fn reduce(value: &Array<u8, U98>) -> Self {
81 #[cfg(target_pointer_width = "32")]
83 const F_2_392: Scalar = Scalar::from_hex_unchecked(
84 "0000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
85 );
86 #[cfg(target_pointer_width = "64")]
87 const F_2_392: Scalar = Scalar::from_hex_unchecked(
88 "000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
89 );
90
91 let mut d0 = Array::default();
92 d0[17..].copy_from_slice(&value[0..49]);
93 let u0 = <Uint as FieldBytesEncoding<NistP521>>::decode_field_bytes(&d0);
94 let d0 = Scalar::reduce(&u0);
95
96 let mut d1 = Array::default();
97 d1[17..].copy_from_slice(&value[49..]);
98 let u1 = <Uint as FieldBytesEncoding<NistP521>>::decode_field_bytes(&d1);
99 let d1 = Scalar::reduce(&u1);
100
101 d0 * F_2_392 + d1
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use crate::{
108 NistP521, Scalar, Uint,
109 arithmetic::field::{FieldElement, MODULUS},
110 };
111 use elliptic_curve::{
112 Curve,
113 array::Array,
114 bigint::{ArrayEncoding, CheckedSub, NonZero, U896},
115 consts::U98,
116 group::cofactor::CofactorGroup,
117 ops::Reduce,
118 sec1::{self, ToEncodedPoint},
119 };
120 use hash2curve::{self, ExpandMsgXmd, MapToCurve};
121 use hex_literal::hex;
122 use primeorder::osswu::OsswuMap;
123 use proptest::{num, prelude::ProptestConfig, proptest};
124 use sha2::Sha512;
125
126 #[cfg(target_pointer_width = "32")]
127 use crate::arithmetic::util;
128
129 #[test]
130 fn params() {
131 let params = <FieldElement as OsswuMap>::PARAMS;
132
133 let c1_expected = MODULUS.checked_sub(&Uint::from_u8(3)).unwrap()
134 / NonZero::new(Uint::from_u8(4)).unwrap();
135
136 #[cfg(target_pointer_width = "32")]
137 let c1_words = util::u32x17_to_u64x9(&c1_expected.as_words());
138 #[cfg(target_pointer_width = "64")]
139 let c1_words = c1_expected.to_words();
140
141 assert_eq!(c1_words, params.c1,);
142
143 let c2 = FieldElement::from_u64(4).sqrt().unwrap();
144 assert_eq!(params.c2, c2);
145 }
146
147 #[test]
148 fn hash_to_curve() {
149 struct TestVector {
150 msg: &'static [u8],
151 p_x: [u8; 66],
152 p_y: [u8; 66],
153 u_0: [u8; 66],
154 u_1: [u8; 66],
155 q0_x: [u8; 66],
156 q0_y: [u8; 66],
157 q1_x: [u8; 66],
158 q1_y: [u8; 66],
159 }
160
161 const DST: &[u8] = b"QUUX-V01-CS02-with-P521_XMD:SHA-512_SSWU_RO_";
162
163 const TEST_VECTORS: &[TestVector] = &[
164 TestVector {
165 msg: b"",
166 p_x: hex!("00fd767cebb2452030358d0e9cf907f525f50920c8f607889a6a35680727f64f4d66b161fafeb2654bea0d35086bec0a10b30b14adef3556ed9f7f1bc23cecc9c088"),
167 p_y: hex!("0169ba78d8d851e930680322596e39c78f4fe31b97e57629ef6460ddd68f8763fd7bd767a4e94a80d3d21a3c2ee98347e024fc73ee1c27166dc3fe5eeef782be411d"),
168 u_0: hex!("01e5f09974e5724f25286763f00ce76238c7a6e03dc396600350ee2c4135fb17dc555be99a4a4bae0fd303d4f66d984ed7b6a3ba386093752a855d26d559d69e7e9e"),
169 u_1: hex!("00ae593b42ca2ef93ac488e9e09a5fe5a2f6fb330d18913734ff602f2a761fcaaf5f596e790bcc572c9140ec03f6cccc38f767f1c1975a0b4d70b392d95a0c7278aa"),
170 q0_x: hex!("00b70ae99b6339fffac19cb9bfde2098b84f75e50ac1e80d6acb954e4534af5f0e9c4a5b8a9c10317b8e6421574bae2b133b4f2b8c6ce4b3063da1d91d34fa2b3a3c"),
171 q0_y: hex!("007f368d98a4ddbf381fb354de40e44b19e43bb11a1278759f4ea7b485e1b6db33e750507c071250e3e443c1aaed61f2c28541bb54b1b456843eda1eb15ec2a9b36e"),
172 q1_x: hex!("01143d0e9cddcdacd6a9aafe1bcf8d218c0afc45d4451239e821f5d2a56df92be942660b532b2aa59a9c635ae6b30e803c45a6ac871432452e685d661cd41cf67214"),
173 q1_y: hex!("00ff75515df265e996d702a5380defffab1a6d2bc232234c7bcffa433cd8aa791fbc8dcf667f08818bffa739ae25773b32073213cae9a0f2a917a0b1301a242dda0c"),
174 },
175 TestVector {
176 msg: b"abc",
177 p_x: hex!("002f89a1677b28054b50d15e1f81ed6669b5a2158211118ebdef8a6efc77f8ccaa528f698214e4340155abc1fa08f8f613ef14a043717503d57e267d57155cf784a4"),
178 p_y: hex!("010e0be5dc8e753da8ce51091908b72396d3deed14ae166f66d8ebf0a4e7059ead169ea4bead0232e9b700dd380b316e9361cfdba55a08c73545563a80966ecbb86d"),
179 u_0: hex!("003d00c37e95f19f358adeeaa47288ec39998039c3256e13c2a4c00a7cb61a34c8969472960150a27276f2390eb5e53e47ab193351c2d2d9f164a85c6a5696d94fe8"),
180 u_1: hex!("01f3cbd3df3893a45a2f1fecdac4d525eb16f345b03e2820d69bc580f5cbe9cb89196fdf720ef933c4c0361fcfe29940fd0db0a5da6bafb0bee8876b589c41365f15"),
181 q0_x: hex!("01b254e1c99c835836f0aceebba7d77750c48366ecb07fb658e4f5b76e229ae6ca5d271bb0006ffcc42324e15a6d3daae587f9049de2dbb0494378ffb60279406f56"),
182 q0_y: hex!("01845f4af72fc2b1a5a2fe966f6a97298614288b456cfc385a425b686048b25c952fbb5674057e1eb055d04568c0679a8e2dda3158dc16ac598dbb1d006f5ad915b0"),
183 q1_x: hex!("007f08e813c620e527c961b717ffc74aac7afccb9158cebc347d5715d5c2214f952c97e194f11d114d80d3481ed766ac0a3dba3eb73f6ff9ccb9304ad10bbd7b4a36"),
184 q1_y: hex!("0022468f92041f9970a7cc025d71d5b647f822784d29ca7b3bc3b0829d6bb8581e745f8d0cc9dc6279d0450e779ac2275c4c3608064ad6779108a7828ebd9954caeb"),
185 },
186 TestVector {
187 msg: b"abcdef0123456789",
188 p_x: hex!("006e200e276a4a81760099677814d7f8794a4a5f3658442de63c18d2244dcc957c645e94cb0754f95fcf103b2aeaf94411847c24187b89fb7462ad3679066337cbc4"),
189 p_y: hex!("001dd8dfa9775b60b1614f6f169089d8140d4b3e4012949b52f98db2deff3e1d97bf73a1fa4d437d1dcdf39b6360cc518d8ebcc0f899018206fded7617b654f6b168"),
190 u_0: hex!("00183ee1a9bbdc37181b09ec336bcaa34095f91ef14b66b1485c166720523dfb81d5c470d44afcb52a87b704dbc5c9bc9d0ef524dec29884a4795f55c1359945baf3"),
191 u_1: hex!("00504064fd137f06c81a7cf0f84aa7e92b6b3d56c2368f0a08f44776aa8930480da1582d01d7f52df31dca35ee0a7876500ece3d8fe0293cd285f790c9881c998d5e"),
192 q0_x: hex!("0021482e8622aac14da60e656043f79a6a110cbae5012268a62dd6a152c41594549f373910ebed170ade892dd5a19f5d687fae7095a461d583f8c4295f7aaf8cd7da"),
193 q0_y: hex!("0177e2d8c6356b7de06e0b5712d8387d529b848748e54a8bc0ef5f1475aa569f8f492fa85c3ad1c5edc51faf7911f11359bfa2a12d2ef0bd73df9cb5abd1b101c8b1"),
194 q1_x: hex!("00abeafb16fdbb5eb95095678d5a65c1f293291dfd20a3751dbe05d0a9bfe2d2eef19449fe59ec32cdd4a4adc3411177c0f2dffd0159438706159a1bbd0567d9b3d0"),
195 q1_y: hex!("007cc657f847db9db651d91c801741060d63dab4056d0a1d3524e2eb0e819954d8f677aa353bd056244a88f00017e00c3ce8beeedb4382d83d74418bd48930c6c182"),
196 },
197 TestVector {
198 msg: b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq",
199 p_x: hex!("01b264a630bd6555be537b000b99a06761a9325c53322b65bdc41bf196711f9708d58d34b3b90faf12640c27b91c70a507998e55940648caa8e71098bf2bc8d24664"),
200 p_y: hex!("01ea9f445bee198b3ee4c812dcf7b0f91e0881f0251aab272a12201fd89b1a95733fd2a699c162b639e9acdcc54fdc2f6536129b6beb0432be01aa8da02df5e59aaa"),
201 u_0: hex!("0159871e222689aad7694dc4c3480a49807b1eedd9c8cb4ae1b219d5ba51655ea5b38e2e4f56b36bf3e3da44a7b139849d28f598c816fe1bc7ed15893b22f63363c3"),
202 u_1: hex!("004ef0cffd475152f3858c0a8ccbdf7902d8261da92744e98df9b7fadb0a5502f29c5086e76e2cf498f47321434a40b1504911552ce44ad7356a04e08729ad9411f5"),
203 q0_x: hex!("0005eac7b0b81e38727efcab1e375f6779aea949c3e409b53a1d37aa2acbac87a7e6ad24aafbf3c52f82f7f0e21b872e88c55e17b7fa21ce08a94ea2121c42c2eb73"),
204 q0_y: hex!("00a173b6a53a7420dbd61d4a21a7c0a52de7a5c6ce05f31403bef747d16cc8604a039a73bdd6e114340e55dacd6bea8e217ffbadfb8c292afa3e1b2afc839a6ce7bb"),
205 q1_x: hex!("01881e3c193a69e4d88d8180a6879b74782a0bc7e529233e9f84bf7f17d2f319c36920ffba26f9e57a1e045cc7822c834c239593b6e142a694aa00c757b0db79e5e8"),
206 q1_y: hex!("01558b16d396d866e476e001f2dd0758927655450b84e12f154032c7c2a6db837942cd9f44b814f79b4d729996ced61eec61d85c675139cbffe3fbf071d2c21cfecb"),
207 },
208 TestVector {
209 msg: b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
210 p_x: hex!("00c12bc3e28db07b6b4d2a2b1167ab9e26fc2fa85c7b0498a17b0347edf52392856d7e28b8fa7a2dd004611159505835b687ecf1a764857e27e9745848c436ef3925"),
211 p_y: hex!("01cd287df9a50c22a9231beb452346720bb163344a41c5f5a24e8335b6ccc595fd436aea89737b1281aecb411eb835f0b939073fdd1dd4d5a2492e91ef4a3c55bcbd"),
212 u_0: hex!("0033d06d17bc3b9a3efc081a05d65805a14a3050a0dd4dfb4884618eb5c73980a59c5a246b18f58ad022dd3630faa22889fbb8ba1593466515e6ab4aeb7381c26334"),
213 u_1: hex!("0092290ab99c3fea1a5b8fb2ca49f859994a04faee3301cefab312d34227f6a2d0c3322cf76861c6a3683bdaa2dd2a6daa5d6906c663e065338b2344d20e313f1114"),
214 q0_x: hex!("00041f6eb92af8777260718e4c22328a7d74203350c6c8f5794d99d5789766698f459b83d5068276716f01429934e40af3d1111a22780b1e07e72238d2207e5386be"),
215 q0_y: hex!("001c712f0182813942b87cab8e72337db017126f52ed797dd234584ac9ae7e80dfe7abea11db02cf1855312eae1447dbaecc9d7e8c880a5e76a39f6258074e1bc2e0"),
216 q1_x: hex!("0125c0b69bcf55eab49280b14f707883405028e05c927cd7625d4e04115bd0e0e6323b12f5d43d0d6d2eff16dbcf244542f84ec058911260dc3bb6512ab5db285fbd"),
217 q1_y: hex!("008bddfb803b3f4c761458eb5f8a0aee3e1f7f68e9d7424405fa69172919899317fb6ac1d6903a432d967d14e0f80af63e7035aaae0c123e56862ce969456f99f102"),
218 },
219 ];
220
221 for test_vector in TEST_VECTORS {
222 let u = hash2curve::hash_to_field::<
224 2,
225 ExpandMsgXmd<Sha512>,
226 <NistP521 as MapToCurve>::SecurityLevel,
227 FieldElement,
228 <NistP521 as MapToCurve>::Length,
229 >(&[test_vector.msg], &[DST])
230 .unwrap();
231
232 macro_rules! assert_point_eq {
235 ($actual:expr, $expected_x:expr, $expected_y:expr) => {
236 let point = $actual.to_affine().to_encoded_point(false);
237 let (actual_x, actual_y) = match point.coordinates() {
238 sec1::Coordinates::Uncompressed { x, y } => (x, y),
239 _ => unreachable!(),
240 };
241
242 assert_eq!(&$expected_x, actual_x.as_slice());
243 assert_eq!(&$expected_y, actual_y.as_slice());
244 };
245 }
246
247 assert_eq!(u[0].to_bytes().as_slice(), test_vector.u_0);
248 assert_eq!(u[1].to_bytes().as_slice(), test_vector.u_1);
249
250 let q0 = NistP521::map_to_curve(u[0]);
251 assert_point_eq!(q0, test_vector.q0_x, test_vector.q0_y);
252
253 let q1 = NistP521::map_to_curve(u[1]);
254 assert_point_eq!(q1, test_vector.q1_x, test_vector.q1_y);
255
256 let p = (q0 + q1).clear_cofactor();
257 assert_point_eq!(p, test_vector.p_x, test_vector.p_y);
258
259 let pt = hash2curve::hash_from_bytes::<NistP521, ExpandMsgXmd<Sha512>>(
261 &[test_vector.msg],
262 &[DST],
263 )
264 .unwrap();
265 assert_point_eq!(pt, test_vector.p_x, test_vector.p_y);
266 }
267 }
268
269 #[test]
271 fn hash_to_scalar_voprf() {
272 struct TestVector {
273 dst: &'static [u8],
274 key_info: &'static [u8],
275 seed: &'static [u8],
276 sk_sm: &'static [u8],
277 }
278
279 const TEST_VECTORS: &[TestVector] = &[
280 TestVector {
281 dst: b"DeriveKeyPairOPRFV1-\x00-P521-SHA512",
282 key_info: &hex!("74657374206b6579"),
283 seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"),
284 sk_sm: &hex!(
285 "0153441b8faedb0340439036d6aed06d1217b34c42f17f8db4c5cc610a4a955d698a688831b16d0dc7713a1aa3611ec60703bffc7dc9c84e3ed673b3dbe1d5fccea6"
286 ),
287 },
288 TestVector {
289 dst: b"DeriveKeyPairOPRFV1-\x01-P521-SHA512",
290 key_info: b"test key",
291 seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"),
292 sk_sm: &hex!(
293 "015c7fc1b4a0b1390925bae915bd9f3d72009d44d9241b962428aad5d13f22803311e7102632a39addc61ea440810222715c9d2f61f03ea424ec9ab1fe5e31cf9238"
294 ),
295 },
296 TestVector {
297 dst: b"DeriveKeyPairOPRFV1-\x02-P521-SHA512",
298 key_info: b"test key",
299 seed: &hex!("a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3"),
300 sk_sm: &hex!(
301 "014893130030ce69cf714f536498a02ff6b396888f9bb507985c32928c4427d6d39de10ef509aca4240e8569e3a88debc0d392e3361bcd934cb9bdd59e339dff7b27"
302 ),
303 },
304 ];
305
306 'outer: for test_vector in TEST_VECTORS {
307 let key_info_len = u16::try_from(test_vector.key_info.len())
308 .unwrap()
309 .to_be_bytes();
310
311 for counter in 0_u8..=u8::MAX {
312 let scalar = hash2curve::hash_to_scalar::<NistP521, ExpandMsgXmd<Sha512>, U98>(
313 &[
314 test_vector.seed,
315 &key_info_len,
316 test_vector.key_info,
317 &counter.to_be_bytes(),
318 ],
319 &[test_vector.dst],
320 )
321 .unwrap();
322
323 if !bool::from(scalar.is_zero()) {
324 assert_eq!(scalar.to_bytes().as_slice(), test_vector.sk_sm);
325 continue 'outer;
326 }
327 }
328
329 panic!("deriving key failed");
330 }
331 }
332
333 #[test]
334 fn from_okm_fuzz() {
335 let mut wide_order = Array::default();
336
337 #[cfg(target_pointer_width = "32")]
338 wide_order[44..].copy_from_slice(NistP521::ORDER.to_be_byte_array().as_slice());
339 #[cfg(target_pointer_width = "64")]
340 wide_order[40..].copy_from_slice(NistP521::ORDER.to_be_byte_array().as_slice());
341
342 let wide_order = NonZero::<U896>::from_be_byte_array(wide_order).unwrap();
344
345 let simple_from_okm = move |data: Array<u8, U98>| -> Scalar {
346 let mut wide_data = Array::default();
347 wide_data[14..].copy_from_slice(data.as_slice());
348
349 let wide_data = U896::from_be_byte_array(wide_data);
350
351 let scalar = wide_data % wide_order;
352
353 #[cfg(target_pointer_width = "32")]
354 let reduced_scalar = Uint::from_be_slice(&scalar.to_be_byte_array()[44..]);
355 #[cfg(target_pointer_width = "64")]
356 let reduced_scalar = Uint::from_be_slice(&scalar.to_be_byte_array()[40..]);
357
358 Scalar::reduce(&reduced_scalar)
359 };
360
361 proptest!(
362 ProptestConfig::with_cases(1000),
363 |(
364 b0 in num::u64::ANY,
365 b1 in num::u64::ANY,
366 b2 in num::u64::ANY,
367 b3 in num::u64::ANY,
368 b4 in num::u64::ANY,
369 b5 in num::u64::ANY,
370 b6 in num::u64::ANY,
371 b7 in num::u64::ANY,
372 b8 in num::u64::ANY,
373 b9 in num::u64::ANY,
374 b10 in num::u64::ANY,
375 b11 in num::u64::ANY,
376 b12 in num::u16::ANY,
377 )| {
378 let mut data = Array::default();
379 data[..8].copy_from_slice(&b0.to_be_bytes());
380 data[8..16].copy_from_slice(&b1.to_be_bytes());
381 data[16..24].copy_from_slice(&b2.to_be_bytes());
382 data[24..32].copy_from_slice(&b3.to_be_bytes());
383 data[32..40].copy_from_slice(&b4.to_be_bytes());
384 data[40..48].copy_from_slice(&b5.to_be_bytes());
385 data[48..56].copy_from_slice(&b6.to_be_bytes());
386 data[56..64].copy_from_slice(&b7.to_be_bytes());
387 data[64..72].copy_from_slice(&b8.to_be_bytes());
388 data[72..80].copy_from_slice(&b9.to_be_bytes());
389 data[80..88].copy_from_slice(&b10.to_be_bytes());
390 data[88..96].copy_from_slice(&b11.to_be_bytes());
391 data[96..].copy_from_slice(&b12.to_be_bytes());
392
393 let from_okm = Scalar::reduce(&data);
394 let simple_from_okm = simple_from_okm(data);
395 assert_eq!(from_okm, simple_from_okm);
396 }
397 );
398 }
399}