1use core::fmt::{self, Debug, Display, Formatter, LowerHex, UpperHex};
2use core::iter::{Product, Sum};
3use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
4
5use super::{ConstMontyType, MODULUS};
6use crate::{
7 AffinePoint, Decaf448, DecafPoint, Ed448, EdwardsPoint,
8 curve::twedwards::extended::ExtendedPoint as TwistedExtendedPoint,
9};
10use elliptic_curve::{
11 Field,
12 array::Array,
13 bigint::{
14 NonZero, U448, U704, Zero,
15 consts::{U28, U56, U84, U88},
16 modular::ConstMontyParams,
17 },
18 ops::{BatchInvert, Reduce},
19 zeroize::DefaultIsZeroes,
20};
21use hash2curve::MapToCurve;
22use rand_core::TryRng;
23use subtle::{
24 Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq, ConstantTimeLess,
25 CtOption,
26};
27
28#[derive(Clone, Copy, Default)]
29pub struct FieldElement(pub(crate) ConstMontyType);
30
31impl Display for FieldElement {
32 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
33 write!(f, "{:x}", self.0.retrieve())
34 }
35}
36
37impl Debug for FieldElement {
38 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
39 write!(f, "FieldElement({:x})", self.0.retrieve())
40 }
41}
42
43impl LowerHex for FieldElement {
44 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
45 write!(f, "{:x}", self.0.retrieve())
46 }
47}
48
49impl UpperHex for FieldElement {
50 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
51 write!(f, "{:X}", self.0.retrieve())
52 }
53}
54
55impl BatchInvert for FieldElement {}
56
57impl ConstantTimeEq for FieldElement {
58 fn ct_eq(&self, other: &Self) -> Choice {
59 self.0.ct_eq(&other.0)
60 }
61}
62
63impl ConditionallySelectable for FieldElement {
64 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
65 Self(ConstMontyType::conditional_select(&a.0, &b.0, choice))
66 }
67}
68
69impl PartialEq for FieldElement {
70 fn eq(&self, other: &FieldElement) -> bool {
71 self.ct_eq(other).into()
72 }
73}
74impl Eq for FieldElement {}
75
76impl Reduce<Array<u8, U84>> for FieldElement {
77 fn reduce(value: &Array<u8, U84>) -> Self {
78 const SEMI_WIDE_MODULUS: NonZero<U704> = NonZero::<U704>::new_unwrap(U704::from_be_hex(
79 "0000000000000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
80 ));
81 let mut tmp = Array::<u8, U88>::default();
82 tmp[4..].copy_from_slice(&value[..]);
83
84 let mut num = U704::from_be_slice(&tmp[..]);
85 num %= SEMI_WIDE_MODULUS;
86
87 let bytes =
88 <[u8; 56]>::try_from(&num.to_le_bytes()[..56]).expect("slice is the wrong length");
89 FieldElement(ConstMontyType::new(&U448::from_le_slice(&bytes)))
90 }
91}
92
93impl Reduce<Array<u8, U56>> for FieldElement {
94 fn reduce(value: &Array<u8, U56>) -> Self {
95 FieldElement::from_bytes(&value.0)
96 }
97}
98
99impl DefaultIsZeroes for FieldElement {}
100
101impl Add<&FieldElement> for &FieldElement {
102 type Output = FieldElement;
103
104 fn add(self, other: &FieldElement) -> FieldElement {
105 FieldElement(self.0.add(&other.0))
106 }
107}
108
109define_add_variants!(
110 LHS = FieldElement,
111 RHS = FieldElement,
112 Output = FieldElement
113);
114
115impl AddAssign for FieldElement {
116 fn add_assign(&mut self, other: FieldElement) {
117 *self = *self + other;
118 }
119}
120
121impl AddAssign<&FieldElement> for FieldElement {
122 fn add_assign(&mut self, other: &FieldElement) {
123 *self = *self + *other;
124 }
125}
126
127impl Sub<&FieldElement> for &FieldElement {
128 type Output = FieldElement;
129
130 fn sub(self, other: &FieldElement) -> FieldElement {
131 FieldElement(self.0.sub(&other.0))
132 }
133}
134
135define_sub_variants!(
136 LHS = FieldElement,
137 RHS = FieldElement,
138 Output = FieldElement
139);
140
141impl SubAssign for FieldElement {
142 fn sub_assign(&mut self, other: FieldElement) {
143 *self = *self - other;
144 }
145}
146
147impl SubAssign<&FieldElement> for FieldElement {
148 fn sub_assign(&mut self, other: &FieldElement) {
149 *self = *self - *other;
150 }
151}
152
153impl Mul<&FieldElement> for &FieldElement {
154 type Output = FieldElement;
155
156 fn mul(self, other: &FieldElement) -> FieldElement {
157 FieldElement(self.0.mul(&other.0))
158 }
159}
160
161define_mul_variants!(
162 LHS = FieldElement,
163 RHS = FieldElement,
164 Output = FieldElement
165);
166
167impl MulAssign<&FieldElement> for FieldElement {
168 fn mul_assign(&mut self, other: &FieldElement) {
169 *self = *self * *other;
170 }
171}
172
173impl MulAssign for FieldElement {
174 fn mul_assign(&mut self, other: FieldElement) {
175 *self = *self * other;
176 }
177}
178
179impl Neg for &FieldElement {
180 type Output = FieldElement;
181
182 fn neg(self) -> FieldElement {
183 -*self
184 }
185}
186
187impl Neg for FieldElement {
188 type Output = FieldElement;
189
190 fn neg(self) -> FieldElement {
191 Self(self.0.neg())
192 }
193}
194
195impl MapToCurve for Ed448 {
196 type SecurityLevel = U28;
197 type FieldElement = FieldElement;
198 type Length = U84;
199
200 fn map_to_curve(element: FieldElement) -> EdwardsPoint {
201 element.map_to_curve_elligator2().isogeny().to_edwards()
202 }
203}
204
205impl MapToCurve for Decaf448 {
206 type SecurityLevel = U28;
207 type FieldElement = FieldElement;
208 type Length = U56;
209
210 fn map_to_curve(element: FieldElement) -> DecafPoint {
211 DecafPoint(element.map_to_curve_decaf448())
212 }
213}
214
215impl Sum for FieldElement {
216 fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
217 iter.reduce(Add::add).unwrap_or(Self::ZERO)
218 }
219}
220
221impl<'a> Sum<&'a FieldElement> for FieldElement {
222 fn sum<I: Iterator<Item = &'a FieldElement>>(iter: I) -> Self {
223 iter.copied().sum()
224 }
225}
226
227impl Product for FieldElement {
228 fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
229 iter.reduce(Mul::mul).unwrap_or(Self::ONE)
230 }
231}
232
233impl<'a> Product<&'a FieldElement> for FieldElement {
234 fn product<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
235 iter.copied().product()
236 }
237}
238
239impl Field for FieldElement {
240 const ZERO: Self = Self::ZERO;
241 const ONE: Self = Self::ONE;
242
243 fn try_random<R: TryRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
244 let mut bytes = [0; 56];
245
246 loop {
247 rng.try_fill_bytes(&mut bytes)?;
248 if let Some(fe) = Self::from_repr(&bytes).into() {
249 return Ok(fe);
250 }
251 }
252 }
253
254 fn square(&self) -> Self {
255 self.square()
256 }
257
258 fn double(&self) -> Self {
259 self.double()
260 }
261
262 fn invert(&self) -> CtOption<Self> {
263 CtOption::from(self.0.invert()).map(Self)
264 }
265
266 fn sqrt(&self) -> CtOption<Self> {
267 let sqrt = self.unchecked_sqrt();
268 CtOption::new(sqrt, sqrt.square().ct_eq(self))
269 }
270
271 fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
272 let (result, is_square) = Self::sqrt_ratio(num, div);
273 (is_square, result)
274 }
275}
276
277impl FieldElement {
278 pub const A_PLUS_TWO_OVER_FOUR: Self = Self(ConstMontyType::new(&U448::from_be_hex(
279 "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000098aa",
280 )));
281 pub const DECAF_FACTOR: Self = Self(ConstMontyType::new(&U448::from_be_hex(
282 "22d962fbeb24f7683bf68d722fa26aa0a1f1a7b8a5b8d54b64a2d780968c14ba839a66f4fd6eded260337bf6aa20ce529642ef0f45572736",
283 )));
284 pub const EDWARDS_D: Self = Self(ConstMontyType::new(&U448::from_be_hex(
285 "fffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffff6756",
286 )));
287 pub const J: Self = Self(ConstMontyType::new(&U448::from_u64(156326)));
288 pub const MINUS_ONE: Self = Self(ConstMontyType::new(&U448::from_be_hex(
289 "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
290 )));
291 pub const NEG_EDWARDS_D: Self = Self(ConstMontyType::new(&U448::from_be_hex(
292 "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000098a9",
293 )));
294 pub const NEG_FOUR_TIMES_TWISTED_D: Self = Self(ConstMontyType::new(&U448::from_be_hex(
295 "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000262a8",
296 )));
297 pub const ONE: Self = Self(ConstMontyType::new(&U448::ONE));
298 pub const TWO: Self = Self(ConstMontyType::new(&U448::from_u64(2)));
299 pub const TWISTED_D: Self = Self(ConstMontyType::new(&U448::from_be_hex(
300 "fffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffffffffffffffffffffffffffffffffffffff6755",
301 )));
302 pub const TWO_TIMES_TWISTED_D: Self = Self(ConstMontyType::new(&U448::from_be_hex(
303 "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffeceab",
304 )));
305 pub const Z: Self = Self(ConstMontyType::new(&U448::from_be_hex(
306 "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffffffffffffffe",
307 )));
308 pub const ZERO: Self = Self(ConstMontyType::new(&U448::ZERO));
309
310 pub fn is_negative(&self) -> Choice {
311 self.0.retrieve().is_odd().into()
312 }
313
314 pub fn is_zero(&self) -> Choice {
315 self.0.is_zero().into()
316 }
317
318 pub fn invert(&self) -> Self {
320 Self(self.0.invert().unwrap_or_default())
321 }
322
323 pub fn square(&self) -> Self {
324 Self(self.0.square())
325 }
326
327 fn square_n<const N: u32>(&self) -> FieldElement {
329 let mut result = *self;
330
331 for _ in 0..N {
332 result = result.square();
333 }
334
335 result
336 }
337
338 pub fn is_square(&self) -> Choice {
339 !Choice::from(self.0.jacobi_symbol().is_minus_one())
340 }
341
342 pub fn unchecked_sqrt(&self) -> FieldElement {
343 let z = *self;
346 let zp2 = z.square() * z;
347 let zp3 = zp2.square() * z;
348 let zp4 = zp3.square() * z;
349 let zp7 = zp4.square_n::<3>() * zp3;
350 let zp14 = zp7.square_n::<7>() * zp7;
351 let zp28 = zp14.square_n::<14>() * zp14;
352 let zp56 = zp28.square_n::<28>() * zp28;
353 let zp112 = zp56.square_n::<56>() * zp56;
354 let zp224 = zp112.square_n::<112>() * zp112;
355 zp224.square_n::<222>()
356 }
357
358 pub fn to_bytes(self) -> [u8; 56] {
359 let mut bytes = [0u8; 56];
360 bytes.copy_from_slice(&self.0.retrieve().to_le_bytes()[..56]);
361 bytes
362 }
363
364 pub fn to_bytes_extended(self) -> [u8; 57] {
365 let mut bytes = [0u8; 57];
366 bytes[..56].copy_from_slice(&self.to_bytes());
367 bytes
368 }
369
370 pub fn from_bytes(bytes: &[u8; 56]) -> Self {
371 Self(ConstMontyType::new(&U448::from_le_slice(bytes)))
372 }
373
374 pub fn from_bytes_extended(bytes: &[u8; 57]) -> Self {
375 Self(ConstMontyType::new(&U448::from_le_slice(&bytes[..56])))
376 }
377
378 pub fn from_repr(bytes: &[u8; 56]) -> CtOption<Self> {
379 let integer = U448::from_le_slice(bytes);
380 let is_some = integer.ct_lt(MODULUS::PARAMS.modulus());
381 CtOption::new(Self(ConstMontyType::new(&integer)), is_some)
382 }
383
384 pub fn double(&self) -> Self {
385 Self(self.0.double())
386 }
387
388 pub(crate) fn inverse_square_root(&self) -> (FieldElement, Choice) {
392 let (mut l0, mut l1, mut l2);
393
394 l1 = self.square();
395 l2 = l1 * self;
396 l1 = l2.square();
397 l2 = l1 * self;
398 l1 = l2.square_n::<3>();
399 l0 = l2 * l1;
400 l1 = l0.square_n::<3>();
401 l0 = l2 * l1;
402 l2 = l0.square_n::<9>();
403 l1 = l0 * l2;
404 l0 = l1.square();
405 l2 = l0 * self;
406 l0 = l2.square_n::<18>();
407 l2 = l1 * l0;
408 l0 = l2.square_n::<37>();
409 l1 = l2 * l0;
410 l0 = l1.square_n::<37>();
411 l1 = l2 * l0;
412 l0 = l1.square_n::<111>();
413 l2 = l1 * l0;
414 l0 = l2.square();
415 l1 = l0 * self;
416 l0 = l1.square_n::<223>();
417 l1 = l2 * l0;
418 l2 = l1.square();
419 l0 = l2 * self;
420
421 let is_residue = l0.ct_eq(&FieldElement::ONE);
422 (l1, is_residue)
423 }
424
425 pub(crate) fn sqrt_ratio(u: &FieldElement, v: &FieldElement) -> (FieldElement, Choice) {
427 let x = *u * v;
429 let (inv_sqrt_x, is_res) = x.inverse_square_root();
430 let zero_u = u.ct_eq(&FieldElement::ZERO);
434 (inv_sqrt_x * u, zero_u | is_res)
435 }
436
437 pub(crate) fn div_by_2(&self) -> FieldElement {
438 Self(self.0.div_by_2())
439 }
440
441 pub(crate) fn map_to_curve_elligator2(&self) -> AffinePoint {
442 let mut t1 = self.square(); t1 *= Self::Z; let e1 = t1.ct_eq(&Self::MINUS_ONE); t1.conditional_assign(&Self::ZERO, e1); let mut x1 = t1 + Self::ONE; x1 = x1.invert(); x1 *= -Self::J; let mut gx1 = x1 + Self::J; gx1 *= x1; gx1 += Self::ONE; gx1 *= x1; let x2 = -x1 - Self::J; let gx2 = t1 * gx1; let e2 = gx1.is_square(); let x = Self::conditional_select(&x2, &x1, e2); let y2 = Self::conditional_select(&gx2, &gx1, e2); let mut y = y2.unchecked_sqrt(); let e3 = y.is_negative(); y.conditional_negate(e2 ^ e3); AffinePoint { x, y }
462 }
463
464 pub(crate) fn map_to_curve_decaf448(&self) -> TwistedExtendedPoint {
467 const ONE_MINUS_TWO_D: FieldElement =
468 FieldElement(ConstMontyType::new(&U448::from_u64(78163)));
469
470 let r = -self.square();
471
472 let a = r - Self::ONE;
473 let b = a * Self::EDWARDS_D;
474 let a = b + Self::ONE;
475 let b = b - r;
476 let c = a * b;
477
478 let a = r + Self::ONE;
479 let n = a * ONE_MINUS_TWO_D;
480
481 let a = c * n;
482 let (b, square) = a.inverse_square_root();
483 let c = Self::conditional_select(self, &Self::ONE, square);
484 let e = b * c;
485
486 let mut a = n * e;
487 a.conditional_negate(!a.is_negative() ^ square);
488
489 let c = e * ONE_MINUS_TWO_D;
490 let b = c.square();
491 let e = r - Self::ONE;
492 let c = b * e;
493 let mut b = c * n;
494 b.conditional_negate(square);
495 let b = b - Self::ONE;
496
497 let c = a.square();
498 let a = a.double();
499 let e = c + Self::ONE;
500 let T = a * e;
501 let X = a * b;
502 let a = Self::ONE - c;
503 let Y = e * a;
504 let Z = a * b;
505
506 TwistedExtendedPoint { X, Y, Z, T }
507 }
508}
509
510#[cfg(test)]
511mod tests {
512 use super::*;
513 use elliptic_curve::consts::U32;
514 use hash2curve::{ExpandMsg, ExpandMsgXof, Expander};
515 use hex_literal::hex;
516 use shake::Shake256;
517
518 fn assert_from_okm(dst: &[u8], msgs: &[(&[u8], [u8; 56], [u8; 56])]) {
519 for (msg, expected_u0, expected_u1) in msgs {
520 let mut expander = <ExpandMsgXof<Shake256> as ExpandMsg<U32>>::expand_message(
521 &[*msg],
522 &[dst],
523 (84 * 2).try_into().unwrap(),
524 )
525 .unwrap();
526
527 let mut data = Array::<u8, U84>::default();
528 expander.fill_bytes(&mut data).unwrap();
529 let u0 = FieldElement::reduce(&data);
530
531 let mut e_u0 = *expected_u0;
532 e_u0.reverse();
533 let mut e_u1 = *expected_u1;
534 e_u1.reverse();
535
536 assert_eq!(u0.to_bytes(), e_u0);
537 expander.fill_bytes(&mut data).unwrap();
538 let u1 = FieldElement::reduce(&data);
539 assert_eq!(u1.to_bytes(), e_u1);
540 }
541 }
542
543 #[test]
544 fn from_okm_curve448() {
545 const DST: &[u8] = b"QUUX-V01-CS02-with-curve448_XOF:SHAKE256_ELL2_RO_";
546 const MSGS: &[(&[u8], [u8; 56], [u8; 56])] = &[
547 (b"", hex!("c704c7b3d3b36614cf3eedd0324fe6fe7d1402c50efd16cff89ff63f50938506280d3843478c08e24f7842f4e3ef45f6e3c4897f9d976148"), hex!("c25427dc97fff7a5ad0a78654e2c6c27b1c1127b5b53c7950cd1fd6edd2703646b25f341e73deedfebf022d1d3cecd02b93b4d585ead3ed7")),
548 (b"abc", hex!("2dd95593dfee26fe0d218d3d9a0a23d9e1a262fd1d0b602483d08415213e75e2db3c69b0a5bc89e71bcefc8c723d2b6a0cf263f02ad2aa70"), hex!("272e4c79a1290cc6d2bc4f4f9d31bf7fbe956ca303c04518f117d77c0e9d850796fc3e1e2bcb9c75e8eaaded5e150333cae9931868047c9d")),
549 (b"abcdef0123456789", hex!("6aab71a38391639f27e49eae8b1cb6b7172a1f478190ece293957e7cdb2391e7cc1c4261970d9c1bbf9c3915438f74fbd7eb5cd4d4d17ace"), hex!("c80b8380ca47a3bcbf76caa75cef0e09f3d270d5ee8f676cde11aedf41aaca6741bd81a86232bd336ccb42efad39f06542bc06a67b65909e")),
550 (b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", hex!("cb5c27e51f9c18ee8ffdb6be230f4eb4f2c2481963b2293484f08da2241c1ff59f80978e6defe9d70e34abba2fcbe12dc3a1eb2c5d3d2e4a"), hex!("c895e8afecec5466e126fa70fc4aa784b8009063afb10e3ee06a9b22318256aa8693b0c85b955cf2d6540b8ed71e729af1b8d5ca3b116cd7")),
551 (b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", hex!("8cba93a007bb2c801b1769e026b1fa1640b14a34cf3029db3c7fd6392745d6fec0f7870b5071d6da4402cedbbde28ae4e50ab30e1049a238"), hex!("4223746145069e4b8a981acc3404259d1a2c3ecfed5d864798a89d45f81a2c59e2d40eb1d5f0fe11478cbb2bb30246dd388cb932ad7bb330")),
552 ];
553
554 assert_from_okm(DST, MSGS);
556 }
557
558 #[test]
559 fn from_okm_edwards448() {
560 const DST: &[u8] = b"QUUX-V01-CS02-with-edwards448_XOF:SHAKE256_ELL2_RO_";
561 const MSGS: &[(&[u8], [u8; 56], [u8; 56])] = &[
562 (b"", hex!("0847c5ebf957d3370b1f98fde499fb3e659996d9fc9b5707176ade785ba72cd84b8a5597c12b1024be5f510fa5ba99642c4cec7f3f69d3e7"), hex!("f8cbd8a7ae8c8deed071f3ac4b93e7cfcb8f1eac1645d699fd6d3881cb295a5d3006d9449ed7cad412a77a1fe61e84a9e41d59ef384d6f9a")),
563 (b"abc", hex!("04d975cd938ab49be3e81703d6a57cca84ed80d2ff6d4756d3f22947fb5b70ab0231f0087cbfb4b7cae73b41b0c9396b356a4831d9a14322"), hex!("2547ca887ac3db7b5fad3a098aa476e90078afe1358af6c63d677d6edfd2100bc004e0f5db94dd2560fc5b308e223241d00488c9ca6b0ef2")),
564 (b"abcdef0123456789", hex!("10659ce25588db4e4be6f7c791a79eb21a7f24aaaca76a6ca3b83b80aaf95aa328fe7d569a1ac99f9cd216edf3915d72632f1a8b990e250c"), hex!("9243e5b6c480683fd533e81f4a778349a309ce00bd163a29eb9fa8dbc8f549242bef33e030db21cffacd408d2c4264b93e476c6a8590e7aa")),
565 (b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq", hex!("c80390020e578f009ead417029eff6cd0926110922db63ab98395e3bdfdd5d8a65b1a2b8d495dc8c5e59b7f3518731f7dfc0f93ace5dee4b"), hex!("1c4dc6653a445bbef2add81d8e90a6c8591a788deb91d0d3f1519a2e4a460313041b77c1b0817f2e80b388e5c3e49f37d787dc1f85e4324a")),
566 (b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", hex!("163c79ab0210a4b5e4f44fb19437ea965bf5431ab233ef16606f0b03c5f16a3feb7d46a5a675ce8f606e9c2bf74ee5336c54a1e54919f13f"), hex!("f99666bde4995c4088333d6c2734687e815f80a99c6da02c47df4b51f6c9d9ed466b4fecf7d9884990a8e0d0be6907fa437e0b1a27f49265")),
567 ];
568
569 assert_from_okm(DST, MSGS);
570 }
571
572 #[test]
573 fn get_constants() {
574 let m1 = -FieldElement::ONE;
575 assert_eq!(m1, FieldElement::MINUS_ONE);
576 }
577
578 #[test]
579 fn sqrt() {
580 for &n in &[1u8, 4, 9, 16, 25, 36, 49, 64] {
581 let mut bytes = [0u8; 56];
582 bytes[0] = n;
583
584 let fe = FieldElement::from_bytes(&bytes);
585 let sqrt = fe.sqrt().unwrap();
586 assert_eq!(sqrt.square(), fe);
587 }
588
589 let nine = FieldElement::from_bytes(&[
590 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
591 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
592 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
593 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
594 ]);
595 let three = FieldElement::from_bytes(&[
596 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
597 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
598 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
599 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
600 ]);
601 assert_eq!(three, nine.unchecked_sqrt());
602 }
603}