1use ark_ff::PrimeField;
2use ark_ff::Zero;
3use num_bigint::BigUint;
4use serde::{Deserialize, Serialize};
5use std::borrow::Cow;
6use std::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
7
8use crate::AcirField;
9
10const I128_SIGN_BOUNDARY: u128 = 1_u128 << 127;
14
15#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct FieldElement<F: PrimeField>(F);
18
19impl<F: PrimeField> std::fmt::Display for FieldElement<F> {
20 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
21 let number = BigUint::from_bytes_be(&self.to_be_bytes());
24 if number == BigUint::zero() {
25 return write!(f, "0");
26 }
27 let minus_number = BigUint::from_bytes_be(&(self.neg()).to_be_bytes());
30 let (smaller_repr, is_negative) =
31 if minus_number.to_string().len() < number.to_string().len() {
32 (minus_number, true)
33 } else {
34 (number, false)
35 };
36 if is_negative {
37 write!(f, "-")?;
38 }
39
40 write!(f, "{smaller_repr}")
41 }
42}
43
44impl<F: PrimeField> std::fmt::Debug for FieldElement<F> {
45 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46 std::fmt::Display::fmt(self, f)
47 }
48}
49
50impl<F: PrimeField> From<i128> for FieldElement<F> {
51 fn from(a: i128) -> FieldElement<F> {
52 if a >= 0 {
54 FieldElement(F::from(a as u128))
56 } else {
57 let abs_value = a.wrapping_neg() as u128;
59 FieldElement(-F::from(abs_value))
60 }
61 }
62}
63
64impl<F: PrimeField> From<i64> for FieldElement<F> {
65 fn from(a: i64) -> Self {
66 if a >= 0 {
68 FieldElement(F::from(a as u64))
69 } else {
70 let abs_value = a.wrapping_neg() as u64;
72 FieldElement(-F::from(abs_value))
73 }
74 }
75}
76
77impl<F: PrimeField> From<i32> for FieldElement<F> {
78 fn from(a: i32) -> Self {
79 if a >= 0 {
81 FieldElement(F::from(a as u32))
82 } else {
83 let abs_value = a.wrapping_neg() as u32;
85 FieldElement(-F::from(abs_value))
86 }
87 }
88}
89
90impl<F: PrimeField> From<i16> for FieldElement<F> {
91 fn from(a: i16) -> Self {
92 if a >= 0 {
94 FieldElement(F::from(a as u16))
95 } else {
96 let abs_value = a.wrapping_neg() as u16;
98 FieldElement(-F::from(abs_value))
99 }
100 }
101}
102
103impl<F: PrimeField> From<i8> for FieldElement<F> {
104 fn from(a: i8) -> Self {
105 if a >= 0 {
107 FieldElement(F::from(a as u8))
108 } else {
109 let abs_value = a.wrapping_neg() as u8;
111 FieldElement(-F::from(abs_value))
112 }
113 }
114}
115
116impl<T: PrimeField> Serialize for FieldElement<T> {
117 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
118 where
119 S: serde::Serializer,
120 {
121 self.to_be_bytes().serialize(serializer)
122 }
123}
124
125impl<'de, T: PrimeField> Deserialize<'de> for FieldElement<T> {
126 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
127 where
128 D: serde::Deserializer<'de>,
129 {
130 let s: Cow<'de, [u8]> = Deserialize::deserialize(deserializer)?;
131 Ok(Self::from_be_bytes_reduce(&s))
132 }
133}
134
135impl<F: PrimeField> From<u128> for FieldElement<F> {
136 fn from(a: u128) -> FieldElement<F> {
137 FieldElement(F::from(a))
138 }
139}
140
141impl<F: PrimeField> From<usize> for FieldElement<F> {
142 fn from(a: usize) -> FieldElement<F> {
143 FieldElement::from(a as u64)
144 }
145}
146
147impl<F: PrimeField> From<u64> for FieldElement<F> {
148 fn from(a: u64) -> FieldElement<F> {
149 FieldElement(F::from(a))
150 }
151}
152
153impl<F: PrimeField> From<u32> for FieldElement<F> {
154 fn from(a: u32) -> FieldElement<F> {
155 FieldElement(F::from(a))
156 }
157}
158
159impl<F: PrimeField> From<u16> for FieldElement<F> {
160 fn from(a: u16) -> FieldElement<F> {
161 FieldElement(F::from(a))
162 }
163}
164
165impl<F: PrimeField> From<u8> for FieldElement<F> {
166 fn from(a: u8) -> FieldElement<F> {
167 FieldElement(F::from(a))
168 }
169}
170
171impl<F: PrimeField> From<bool> for FieldElement<F> {
172 fn from(boolean: bool) -> FieldElement<F> {
173 if boolean { FieldElement::one() } else { FieldElement::zero() }
174 }
175}
176
177impl<F: PrimeField> TryFrom<FieldElement<F>> for u128 {
178 type Error = ();
179
180 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
181 value.try_into_u128().ok_or(())
182 }
183}
184
185impl<F: PrimeField> TryFrom<FieldElement<F>> for u64 {
186 type Error = ();
187
188 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
189 value.try_to_u64().ok_or(())
190 }
191}
192
193impl<F: PrimeField> TryFrom<FieldElement<F>> for u32 {
194 type Error = ();
195
196 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
197 value.try_to_u32().ok_or(())
198 }
199}
200
201impl<F: PrimeField> TryFrom<FieldElement<F>> for u16 {
202 type Error = ();
203
204 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
205 value.try_to_u32().and_then(|x| x.try_into().ok()).ok_or(())
206 }
207}
208
209impl<F: PrimeField> TryFrom<FieldElement<F>> for u8 {
210 type Error = ();
211
212 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
213 value.try_to_u32().and_then(|x| x.try_into().ok()).ok_or(())
214 }
215}
216
217impl<F: PrimeField> TryFrom<FieldElement<F>> for i128 {
218 type Error = ();
219
220 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
221 value.try_into_i128().ok_or(())
222 }
223}
224
225impl<F: PrimeField> TryFrom<FieldElement<F>> for i64 {
226 type Error = ();
227
228 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
229 value.try_into_i128().and_then(|x| x.try_into().ok()).ok_or(())
230 }
231}
232
233impl<F: PrimeField> TryFrom<FieldElement<F>> for i32 {
234 type Error = ();
235
236 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
237 value.try_into_i128().and_then(|x| x.try_into().ok()).ok_or(())
238 }
239}
240
241impl<F: PrimeField> TryFrom<FieldElement<F>> for i16 {
242 type Error = ();
243
244 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
245 value.try_into_i128().and_then(|x| x.try_into().ok()).ok_or(())
246 }
247}
248
249impl<F: PrimeField> TryFrom<FieldElement<F>> for i8 {
250 type Error = ();
251
252 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
253 value.try_into_i128().and_then(|x| x.try_into().ok()).ok_or(())
254 }
255}
256
257impl<F: PrimeField> From<FieldElement<F>> for bool {
258 fn from(field: FieldElement<F>) -> bool {
259 !field.is_zero()
260 }
261}
262
263impl<F: PrimeField> FieldElement<F> {
264 pub fn from_repr(field: F) -> Self {
268 Self(field)
269 }
270
271 pub fn into_repr(self) -> F {
275 self.0
276 }
277
278 pub fn fits_in_u128(&self) -> bool {
283 self.num_bits() <= 128
284 }
285
286 pub fn fits_in_i128(&self) -> bool {
293 let num_bits = u32::min(self.neg().num_bits(), self.num_bits());
294 num_bits <= 127 && self != &FieldElement::from(I128_SIGN_BOUNDARY)
295 }
296
297 pub fn try_from_str(input: &str) -> Option<FieldElement<F>> {
302 if input.contains('x') {
303 return FieldElement::from_hex(input);
304 }
305
306 let fr = F::from_str(input).ok()?;
307 Some(FieldElement(fr))
308 }
309
310 pub fn to_string_as_signed_integer(self, bit_size: u32) -> String {
318 assert!(bit_size <= 128);
319 if self.num_bits() > bit_size {
320 return self.to_string();
321 }
322
323 let max = if bit_size == 128 { i128::MAX as u128 } else { (1 << (bit_size - 1)) - 1 };
325 if self.to_u128() > max {
326 let f = FieldElement::from(2u32).pow(&bit_size.into()) - self;
327 format!("-{f}")
328 } else {
329 self.to_string()
330 }
331 }
332}
333
334impl<F: PrimeField> AcirField for FieldElement<F> {
335 fn one() -> FieldElement<F> {
336 FieldElement(F::one())
337 }
338 fn zero() -> FieldElement<F> {
339 FieldElement(F::zero())
340 }
341
342 fn is_zero(&self) -> bool {
343 self == &Self::zero()
344 }
345 fn is_one(&self) -> bool {
346 self == &Self::one()
347 }
348
349 fn pow(&self, exponent: &Self) -> Self {
350 FieldElement(self.0.pow(exponent.0.into_bigint()))
351 }
352
353 fn max_num_bits() -> u32 {
359 F::MODULUS_BIT_SIZE
360 }
361
362 fn max_num_bytes() -> u32 {
367 let num_bytes = Self::max_num_bits() / 8;
368 if Self::max_num_bits() % 8 == 0 { num_bytes } else { num_bytes + 1 }
369 }
370
371 fn modulus() -> BigUint {
372 F::MODULUS.into()
373 }
374
375 fn num_bits(&self) -> u32 {
377 let bigint = self.0.into_bigint();
378 let limbs = bigint.as_ref();
379 for (i, &limb) in limbs.iter().enumerate().rev() {
380 if limb != 0 {
381 return (i as u32) * 64 + (64 - limb.leading_zeros());
382 }
383 }
384 0
385 }
386
387 fn to_u128(self) -> u128 {
388 if !self.fits_in_u128() {
389 panic!("field element too large for u128");
390 }
391 let as_bigint = self.0.into_bigint();
392 let limbs = as_bigint.as_ref();
393
394 let mut result = u128::from(limbs[0]);
395 if limbs.len() > 1 {
396 let high_limb = u128::from(limbs[1]);
397 result += high_limb << 64;
398 }
399
400 result
401 }
402
403 fn try_into_u128(self) -> Option<u128> {
404 self.fits_in_u128().then(|| self.to_u128())
405 }
406
407 fn to_i128(self) -> i128 {
408 if !self.fits_in_i128() {
409 panic!("field element too large for i128");
410 }
411 if self.neg().num_bits() < self.num_bits() {
415 let bytes = self.neg().to_be_bytes();
416 i128::from_be_bytes(bytes[16..32].try_into().unwrap()).neg()
417 } else {
418 let bytes = self.to_be_bytes();
419 i128::from_be_bytes(bytes[16..32].try_into().unwrap())
420 }
421 }
422
423 fn try_into_i128(self) -> Option<i128> {
424 self.fits_in_i128().then(|| self.to_i128())
425 }
426
427 fn try_to_u64(&self) -> Option<u64> {
428 (self.num_bits() <= 64).then(|| self.to_u128() as u64)
429 }
430
431 fn try_to_u32(&self) -> Option<u32> {
432 (self.num_bits() <= 32).then(|| self.to_u128() as u32)
433 }
434
435 fn inverse(&self) -> FieldElement<F> {
438 let inv = self.0.inverse().unwrap_or_else(F::zero);
439 FieldElement(inv)
440 }
441
442 fn to_hex(self) -> String {
443 let bytes = self.to_be_bytes();
444 hex::encode(bytes)
445 }
446
447 fn to_short_hex(self) -> String {
448 if self.is_zero() {
449 return "0x00".to_owned();
450 }
451
452 let bytes = self.to_be_bytes();
454
455 let first_nonzero = bytes.iter().position(|&b| b != 0).unwrap_or(bytes.len());
457 let trimmed = &bytes[first_nonzero..];
458
459 let mut result = String::with_capacity(2 + trimmed.len() * 2);
462 result.push_str("0x");
463
464 use std::fmt::Write;
466 write!(&mut result, "{:x}", trimmed[0]).unwrap();
467
468 if !result.len().is_multiple_of(2) {
470 result.insert(2, '0');
472 }
473
474 for byte in &trimmed[1..] {
476 write!(&mut result, "{byte:02x}").unwrap();
477 }
478
479 result
480 }
481
482 fn from_hex(hex_str: &str) -> Option<FieldElement<F>> {
483 let value = hex_str.strip_prefix("0x").unwrap_or(hex_str);
484
485 let hex_as_bytes = if value.len().is_multiple_of(2) {
487 hex::decode(value).ok()?
488 } else {
489 let mut padded = String::with_capacity(value.len() + 1);
491 padded.push('0');
492 padded.push_str(value);
493 hex::decode(padded).ok()?
494 };
495
496 Some(FieldElement::from_be_bytes_reduce(&hex_as_bytes))
497 }
498
499 fn to_be_bytes(self) -> Vec<u8> {
500 let mut bytes = self.to_le_bytes();
501 bytes.reverse();
502 bytes
503 }
504
505 fn to_le_bytes(self) -> Vec<u8> {
507 let mut bytes = Vec::new();
508 self.0.serialize_uncompressed(&mut bytes).unwrap();
509 bytes
510 }
511
512 fn from_be_bytes_reduce(bytes: &[u8]) -> FieldElement<F> {
515 FieldElement(F::from_be_bytes_mod_order(bytes))
516 }
517
518 fn from_le_bytes_reduce(bytes: &[u8]) -> FieldElement<F> {
521 FieldElement(F::from_le_bytes_mod_order(bytes))
522 }
523
524 fn fetch_nearest_bytes(&self, num_bits: usize) -> Vec<u8> {
527 fn nearest_bytes(num_bits: usize) -> usize {
528 num_bits.div_ceil(8) * 8
529 }
530
531 let num_bytes = nearest_bytes(num_bits);
532 let num_elements = num_bytes / 8;
533
534 let bytes = self.to_le_bytes();
535
536 bytes[0..num_elements].to_vec()
537 }
538}
539
540impl<F: PrimeField> Neg for FieldElement<F> {
541 type Output = FieldElement<F>;
542
543 fn neg(self) -> Self::Output {
544 FieldElement(-self.0)
545 }
546}
547
548impl<F: PrimeField> Mul for FieldElement<F> {
549 type Output = FieldElement<F>;
550 fn mul(mut self, rhs: FieldElement<F>) -> Self::Output {
551 self.0.mul_assign(&rhs.0);
552 FieldElement(self.0)
553 }
554}
555impl<F: PrimeField> Div for FieldElement<F> {
556 type Output = FieldElement<F>;
557 #[allow(clippy::suspicious_arithmetic_impl)]
558 fn div(self, rhs: FieldElement<F>) -> Self::Output {
559 self * rhs.inverse()
560 }
561}
562impl<F: PrimeField> Add for FieldElement<F> {
563 type Output = FieldElement<F>;
564 fn add(mut self, rhs: FieldElement<F>) -> Self::Output {
565 self.add_assign(rhs);
566 FieldElement(self.0)
567 }
568}
569impl<F: PrimeField> AddAssign for FieldElement<F> {
570 fn add_assign(&mut self, rhs: FieldElement<F>) {
571 self.0.add_assign(&rhs.0);
572 }
573}
574
575impl<F: PrimeField> Sub for FieldElement<F> {
576 type Output = FieldElement<F>;
577 fn sub(mut self, rhs: FieldElement<F>) -> Self::Output {
578 self.sub_assign(rhs);
579 FieldElement(self.0)
580 }
581}
582impl<F: PrimeField> SubAssign for FieldElement<F> {
583 fn sub_assign(&mut self, rhs: FieldElement<F>) {
584 self.0.sub_assign(&rhs.0);
585 }
586}
587
588#[cfg(test)]
589mod tests {
590 use super::{AcirField, FieldElement};
591 use proptest::prelude::*;
592 use std::ops::Neg;
593
594 #[test]
595 fn requires_zero_bit_to_hold_zero() {
596 let field = FieldElement::<ark_bn254::Fr>::zero();
597 assert_eq!(field.num_bits(), 0);
598 }
599
600 #[test]
601 fn requires_one_bit_to_hold_one() {
602 let field = FieldElement::<ark_bn254::Fr>::one();
603 assert_eq!(field.num_bits(), 1);
604 }
605
606 proptest! {
607 #[test]
608 fn num_bits_agrees_with_ilog2(num in 1u128..) {
609 let field = FieldElement::<ark_bn254::Fr>::from(num);
610 prop_assert_eq!(field.num_bits(), num.ilog2() + 1);
611 }
612 }
613
614 #[test]
615 fn test_fits_in_u128() {
616 let field = FieldElement::<ark_bn254::Fr>::from(u128::MAX);
617 assert_eq!(field.num_bits(), 128);
618 assert!(field.fits_in_u128());
619 let big_field = field + FieldElement::one();
620 assert_eq!(big_field.num_bits(), 129);
621 assert!(!big_field.fits_in_u128());
622 }
623
624 #[test]
625 fn test_to_u128_basic() {
626 type F = FieldElement<ark_bn254::Fr>;
627
628 assert_eq!(F::zero().to_u128(), 0);
630
631 assert_eq!(F::from(1_u128).to_u128(), 1);
633 assert_eq!(F::from(42_u128).to_u128(), 42);
634 assert_eq!(F::from(1000_u128).to_u128(), 1000);
635
636 assert_eq!(F::from(u128::MAX).to_u128(), u128::MAX);
638
639 assert_eq!(F::from(1_u128 << 127).to_u128(), 1_u128 << 127);
641 assert_eq!(F::from((1_u128 << 127) - 1).to_u128(), (1_u128 << 127) - 1);
642 }
643
644 #[test]
645 #[should_panic(expected = "field element too large for u128")]
646 fn test_to_u128_panics_on_overflow() {
647 type F = FieldElement<ark_bn254::Fr>;
648
649 let too_large = F::from(u128::MAX) + F::one();
651 too_large.to_u128(); }
653
654 #[test]
655 fn test_try_into_u128() {
656 type F = FieldElement<ark_bn254::Fr>;
657
658 assert_eq!(F::zero().try_into_u128(), Some(0));
660 assert_eq!(F::from(42_u128).try_into_u128(), Some(42));
661 assert_eq!(F::from(u128::MAX).try_into_u128(), Some(u128::MAX));
662
663 let too_large = F::from(u128::MAX) + F::one();
665 assert_eq!(too_large.try_into_u128(), None);
666 }
667
668 #[test]
669 fn test_fits_in_i128() {
670 type F = FieldElement<ark_bn254::Fr>;
671
672 assert!(F::zero().fits_in_i128());
674 assert!(F::from(1_i128).fits_in_i128());
675 assert!(F::from(42_i128).fits_in_i128());
676 assert!(F::from(i128::MAX).fits_in_i128());
677
678 assert!(F::from(-1_i128).fits_in_i128());
680 assert!(F::from(-42_i128).fits_in_i128());
681 assert!(F::from(i128::MIN + 1).fits_in_i128());
682
683 assert!(F::from((1_u128 << 127) - 1).fits_in_i128());
685
686 assert!(!F::from(1_u128 << 127).fits_in_i128());
690 assert!(!F::from(i128::MIN).fits_in_i128());
691
692 let too_large = F::from(u128::MAX);
694 assert!(!too_large.fits_in_i128());
695 }
696
697 #[test]
698 fn test_to_i128_positive() {
699 type F = FieldElement<ark_bn254::Fr>;
700
701 assert_eq!(F::zero().to_i128(), 0);
703 assert_eq!(F::from(1_i128).to_i128(), 1);
704 assert_eq!(F::from(42_i128).to_i128(), 42);
705 assert_eq!(F::from(1000_i128).to_i128(), 1000);
706 assert_eq!(F::from(i128::MAX).to_i128(), i128::MAX);
707 }
708
709 #[test]
710 fn test_to_i128_negative() {
711 type F = FieldElement<ark_bn254::Fr>;
712
713 assert_eq!(F::from(-1_i128).to_i128(), -1);
715 assert_eq!(F::from(-42_i128).to_i128(), -42);
716 assert_eq!(F::from(-1000_i128).to_i128(), -1000);
717
718 assert_eq!(F::from(-i128::MAX).to_i128(), -i128::MAX);
720 assert_eq!(F::from(i128::MIN + 1).to_i128(), i128::MIN + 1);
721
722 }
724
725 #[test]
726 fn test_to_i128_roundtrip() {
727 type F = FieldElement<ark_bn254::Fr>;
728
729 let test_values =
732 vec![0_i128, 1, -1, 42, -42, i128::MAX, i128::MAX - 1, i128::MIN + 1, -i128::MAX];
733
734 for value in test_values {
735 let field = F::from(value);
736 assert!(field.fits_in_i128(), "Value {value} should fit in i128");
737 assert_eq!(field.to_i128(), value, "Roundtrip failed for {value}");
738 }
739 }
740
741 #[test]
742 #[should_panic(expected = "field element too large for i128")]
743 fn test_to_i128_panics_on_positive_overflow() {
744 type F = FieldElement<ark_bn254::Fr>;
745
746 let too_large = F::from(1_u128 << 127);
748 too_large.to_i128(); }
750
751 #[test]
752 #[should_panic(expected = "field element too large for i128")]
753 fn test_to_i128_panics_on_large_value() {
754 type F = FieldElement<ark_bn254::Fr>;
755
756 let too_large = F::from(u128::MAX);
758 too_large.to_i128(); }
760
761 #[test]
762 fn test_try_into_i128() {
763 type F = FieldElement<ark_bn254::Fr>;
764
765 assert_eq!(F::zero().try_into_i128(), Some(0));
767 assert_eq!(F::from(42_i128).try_into_i128(), Some(42));
768 assert_eq!(F::from(i128::MAX).try_into_i128(), Some(i128::MAX));
769 assert_eq!(F::from(-i128::MAX).try_into_i128(), Some(-i128::MAX));
770
771 assert_eq!(F::from(-1_i128).try_into_i128(), Some(-1));
773 assert_eq!(F::from(-42_i128).try_into_i128(), Some(-42));
774 assert_eq!(F::from(i128::MIN + 1).try_into_i128(), Some(i128::MIN + 1));
775 assert_eq!(F::from(i128::MAX - 1).try_into_i128(), Some(i128::MAX - 1));
776 assert_eq!(F::from(1_i128 << 126).try_into_i128(), Some(1_i128 << 126));
777 assert_eq!(F::from(-((1_i128 << 126) - 1)).try_into_i128(), Some(-((1_i128 << 126) - 1)));
778 assert_eq!(F::from(1_u128 << 127).try_into_i128(), None);
780 assert_eq!(F::from(u128::MAX).try_into_i128(), None);
781 assert_eq!(F::from(i128::MIN).try_into_i128(), None);
783 assert_eq!(F::from((1_u128 << 127) + 1).try_into_i128(), None);
785 assert_eq!(F::from((1_u128 << 127) + 1000).try_into_i128(), None);
786 assert_eq!(F::from(1_u128 << 127).neg().try_into_i128(), None);
787 assert_eq!(F::from((1_u128 << 127) + 1).neg().try_into_i128(), None);
788 assert_eq!(F::from((1_u128 << 127) + 100).try_into_i128(), None);
789 assert_eq!(F::from((1_u128 << 127) + 100).neg().try_into_i128(), None);
790 }
791
792 #[test]
793 fn serialize_fixed_test_vectors() {
794 let hex_strings = vec![
796 "0000000000000000000000000000000000000000000000000000000000000000",
797 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000",
798 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff",
799 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffffe",
800 ];
801
802 for (i, string) in hex_strings.into_iter().enumerate() {
803 let minus_i_field_element = -FieldElement::<ark_bn254::Fr>::from(i as i128);
804 assert_eq!(minus_i_field_element.to_hex(), string);
805 }
806 }
807
808 #[test]
809 fn max_num_bits_smoke() {
810 let max_num_bits_bn254 = FieldElement::<ark_bn254::Fr>::max_num_bits();
811 assert_eq!(max_num_bits_bn254, 254);
812 }
813
814 proptest! {
815 #[test]
816 fn test_endianness_prop(value in any::<u64>()) {
817 let field = FieldElement::<ark_bn254::Fr>::from(value);
818 let le_bytes = field.to_le_bytes();
820 let be_bytes = field.to_be_bytes();
821
822 let mut reversed_le = le_bytes.clone();
823 reversed_le.reverse();
824 prop_assert_eq!(&be_bytes, &reversed_le, "BE bytes should be reverse of LE bytes");
825
826 let from_le = FieldElement::from_le_bytes_reduce(&le_bytes);
828 let from_be = FieldElement::from_be_bytes_reduce(&be_bytes);
829 prop_assert_eq!(from_le, from_be, "Deserialization should be consistent between LE and BE");
830 prop_assert_eq!(from_le, field, "Deserialized value should match original");
831 }
832 }
833
834 #[test]
835 fn test_endianness() {
836 let field = FieldElement::<ark_bn254::Fr>::from(0x1234_5678_u32);
837 let le_bytes = field.to_le_bytes();
838 let be_bytes = field.to_be_bytes();
839
840 let mut reversed_le = le_bytes.clone();
842 reversed_le.reverse();
843 assert_eq!(&be_bytes, &reversed_le);
844
845 let from_le = FieldElement::from_le_bytes_reduce(&le_bytes);
847 let from_be = FieldElement::from_be_bytes_reduce(&be_bytes);
848 assert_eq!(from_le, from_be);
849 assert_eq!(from_le, field);
850
851 let large_field = FieldElement::<ark_bn254::Fr>::from(0x0123_4567_89AB_CDEF_u64); let large_le = large_field.to_le_bytes();
854 let reconstructed = FieldElement::from_le_bytes_reduce(&large_le);
855 assert_eq!(reconstructed, large_field);
856 }
857
858 proptest! {
859 #[test]
862 #[should_panic(expected = "serialized field element is not equal to input")]
863 fn recovers_original_hex_string(hex in "[0-9a-f]{64}") {
864 let fe: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&hex).expect("should accept any 32 byte hex string");
865 let output_hex = fe.to_hex();
866
867 prop_assert_eq!(hex, output_hex, "serialized field element is not equal to input");
868 }
869
870 #[test]
871 fn accepts_odd_length_hex_strings(hex in "(?:0x)[0-9a-fA-F]+") {
872 let insert_index = if hex.starts_with("0x") { 2 } else { 0 };
875 let mut opposite_parity_string = hex.clone();
876 opposite_parity_string.insert(insert_index, '0');
877
878 let fe_1: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&hex).unwrap();
879 let fe_2: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&opposite_parity_string).unwrap();
880
881 prop_assert_eq!(fe_1, fe_2, "equivalent hex strings with opposite parity deserialized to different values");
882 }
883 }
884
885 #[test]
886 fn test_to_hex() {
887 type F = FieldElement<ark_bn254::Fr>;
888 assert_eq!(
889 F::zero().to_hex(),
890 "0000000000000000000000000000000000000000000000000000000000000000"
891 );
892 assert_eq!(
893 F::one().to_hex(),
894 "0000000000000000000000000000000000000000000000000000000000000001"
895 );
896 assert_eq!(
897 F::from(0x123_u128).to_hex(),
898 "0000000000000000000000000000000000000000000000000000000000000123"
899 );
900 assert_eq!(
901 F::from(0x1234_u128).to_hex(),
902 "0000000000000000000000000000000000000000000000000000000000001234"
903 );
904 }
905
906 #[test]
907 fn test_to_short_hex() {
908 type F = FieldElement<ark_bn254::Fr>;
909 assert_eq!(F::zero().to_short_hex(), "0x00");
910 assert_eq!(F::one().to_short_hex(), "0x01");
911 assert_eq!(F::from(0x123_u128).to_short_hex(), "0x0123");
912 assert_eq!(F::from(0x1234_u128).to_short_hex(), "0x1234");
913 }
914
915 #[test]
916 fn to_string_as_signed_integer() {
917 type F = FieldElement<ark_bn254::Fr>;
918 assert_eq!(F::zero().to_string_as_signed_integer(8), "0");
919 assert_eq!(F::one().to_string_as_signed_integer(8), "1");
920 assert_eq!(F::from(127_u128).to_string_as_signed_integer(8), "127");
921 assert_eq!(F::from(128_u128).to_string_as_signed_integer(8), "-128");
922 assert_eq!(F::from(129_u128).to_string_as_signed_integer(8), "-127");
923 assert_eq!(F::from(255_u128).to_string_as_signed_integer(8), "-1");
924 assert_eq!(F::from(32767_u128).to_string_as_signed_integer(16), "32767");
925 assert_eq!(F::from(32768_u128).to_string_as_signed_integer(16), "-32768");
926 assert_eq!(F::from(65535_u128).to_string_as_signed_integer(16), "-1");
927 }
928}