1use ark_ff::BigInteger;
2use ark_ff::PrimeField;
3use ark_ff::Zero;
4use msgpack_tagged::MsgpackTagged;
5use num_bigint::BigUint;
6use serde::{Deserialize, Serialize};
7use std::ops::{Add, AddAssign, Div, Mul, Neg, Sub, SubAssign};
8
9use crate::AcirField;
10
11const I128_SIGN_BOUNDARY: u128 = 1_u128 << 127;
15
16#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
18pub struct FieldElement<F: PrimeField>(F);
19
20impl<F: PrimeField> std::fmt::Display for FieldElement<F> {
21 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
22 let number = BigUint::from_bytes_be(&self.to_be_bytes());
25 if number == BigUint::zero() {
26 return write!(f, "0");
27 }
28 let minus_number = BigUint::from_bytes_be(&(self.neg()).to_be_bytes());
31 let (smaller_repr, is_negative) =
32 if minus_number.to_string().len() < number.to_string().len() {
33 (minus_number, true)
34 } else {
35 (number, false)
36 };
37 if is_negative {
38 write!(f, "-")?;
39 }
40
41 write!(f, "{smaller_repr}")
42 }
43}
44
45impl<F: PrimeField> std::fmt::Debug for FieldElement<F> {
46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 std::fmt::Display::fmt(self, f)
48 }
49}
50
51impl<F: PrimeField> From<i128> for FieldElement<F> {
52 fn from(a: i128) -> FieldElement<F> {
53 if a >= 0 {
55 FieldElement(F::from(a as u128))
57 } else {
58 let abs_value = a.wrapping_neg() as u128;
60 FieldElement(-F::from(abs_value))
61 }
62 }
63}
64
65impl<F: PrimeField> From<i64> for FieldElement<F> {
66 fn from(a: i64) -> Self {
67 if a >= 0 {
69 FieldElement(F::from(a as u64))
70 } else {
71 let abs_value = a.wrapping_neg() as u64;
73 FieldElement(-F::from(abs_value))
74 }
75 }
76}
77
78impl<F: PrimeField> From<i32> for FieldElement<F> {
79 fn from(a: i32) -> Self {
80 if a >= 0 {
82 FieldElement(F::from(a as u32))
83 } else {
84 let abs_value = a.wrapping_neg() as u32;
86 FieldElement(-F::from(abs_value))
87 }
88 }
89}
90
91impl<F: PrimeField> From<i16> for FieldElement<F> {
92 fn from(a: i16) -> Self {
93 if a >= 0 {
95 FieldElement(F::from(a as u16))
96 } else {
97 let abs_value = a.wrapping_neg() as u16;
99 FieldElement(-F::from(abs_value))
100 }
101 }
102}
103
104impl<F: PrimeField> From<i8> for FieldElement<F> {
105 fn from(a: i8) -> Self {
106 if a >= 0 {
108 FieldElement(F::from(a as u8))
109 } else {
110 let abs_value = a.wrapping_neg() as u8;
112 FieldElement(-F::from(abs_value))
113 }
114 }
115}
116
117impl<T: PrimeField> Serialize for FieldElement<T> {
118 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
119 where
120 S: serde::Serializer,
121 {
122 serializer.serialize_bytes(&self.to_be_bytes())
145 }
146}
147
148impl<'de, T: PrimeField> Deserialize<'de> for FieldElement<T> {
149 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
150 where
151 D: serde::Deserializer<'de>,
152 {
153 let bytes = serde_bytes::ByteBuf::deserialize(deserializer)?;
164 Ok(Self::from_be_bytes_reduce(&bytes))
165 }
166}
167
168impl<F: PrimeField> From<u128> for FieldElement<F> {
169 fn from(a: u128) -> FieldElement<F> {
170 FieldElement(F::from(a))
171 }
172}
173
174impl<F: PrimeField> From<usize> for FieldElement<F> {
175 fn from(a: usize) -> FieldElement<F> {
176 FieldElement::from(a as u64)
177 }
178}
179
180impl<F: PrimeField> From<u64> for FieldElement<F> {
181 fn from(a: u64) -> FieldElement<F> {
182 FieldElement(F::from(a))
183 }
184}
185
186impl<F: PrimeField> From<u32> for FieldElement<F> {
187 fn from(a: u32) -> FieldElement<F> {
188 FieldElement(F::from(a))
189 }
190}
191
192impl<F: PrimeField> From<u16> for FieldElement<F> {
193 fn from(a: u16) -> FieldElement<F> {
194 FieldElement(F::from(a))
195 }
196}
197
198impl<F: PrimeField> From<u8> for FieldElement<F> {
199 fn from(a: u8) -> FieldElement<F> {
200 FieldElement(F::from(a))
201 }
202}
203
204impl<F: PrimeField> From<bool> for FieldElement<F> {
205 fn from(boolean: bool) -> FieldElement<F> {
206 if boolean { FieldElement::one() } else { FieldElement::zero() }
207 }
208}
209
210impl<F: PrimeField> TryFrom<FieldElement<F>> for u128 {
211 type Error = ();
212
213 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
214 value.try_into_u128().ok_or(())
215 }
216}
217
218impl<F: PrimeField> TryFrom<FieldElement<F>> for u64 {
219 type Error = ();
220
221 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
222 value.try_to_u64().ok_or(())
223 }
224}
225
226impl<F: PrimeField> TryFrom<FieldElement<F>> for u32 {
227 type Error = ();
228
229 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
230 value.try_to_u32().ok_or(())
231 }
232}
233
234impl<F: PrimeField> TryFrom<FieldElement<F>> for u16 {
235 type Error = ();
236
237 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
238 value.try_to_u32().and_then(|x| x.try_into().ok()).ok_or(())
239 }
240}
241
242impl<F: PrimeField> TryFrom<FieldElement<F>> for u8 {
243 type Error = ();
244
245 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
246 value.try_to_u32().and_then(|x| x.try_into().ok()).ok_or(())
247 }
248}
249
250impl<F: PrimeField> TryFrom<FieldElement<F>> for i128 {
251 type Error = ();
252
253 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
254 value.try_into_i128().ok_or(())
255 }
256}
257
258impl<F: PrimeField> TryFrom<FieldElement<F>> for i64 {
259 type Error = ();
260
261 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
262 value.try_into_i128().and_then(|x| x.try_into().ok()).ok_or(())
263 }
264}
265
266impl<F: PrimeField> TryFrom<FieldElement<F>> for i32 {
267 type Error = ();
268
269 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
270 value.try_into_i128().and_then(|x| x.try_into().ok()).ok_or(())
271 }
272}
273
274impl<F: PrimeField> TryFrom<FieldElement<F>> for i16 {
275 type Error = ();
276
277 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
278 value.try_into_i128().and_then(|x| x.try_into().ok()).ok_or(())
279 }
280}
281
282impl<F: PrimeField> TryFrom<FieldElement<F>> for i8 {
283 type Error = ();
284
285 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
286 value.try_into_i128().and_then(|x| x.try_into().ok()).ok_or(())
287 }
288}
289
290impl<F: PrimeField> From<FieldElement<F>> for bool {
291 fn from(field: FieldElement<F>) -> bool {
292 !field.is_zero()
293 }
294}
295
296impl<F: PrimeField> FieldElement<F> {
297 pub fn from_repr(field: F) -> Self {
301 Self(field)
302 }
303
304 pub fn into_repr(self) -> F {
308 self.0
309 }
310
311 pub fn fits_in_u128(&self) -> bool {
316 self.num_bits() <= 128
317 }
318
319 pub fn fits_in_i128(&self) -> bool {
327 let neg = self.neg();
328 self.num_bits() <= 127
329 || neg.num_bits() <= 127
330 || self.neg() == FieldElement::from(I128_SIGN_BOUNDARY)
331 }
332
333 pub fn try_from_str(input: &str) -> Option<FieldElement<F>> {
338 if input.contains('x') {
339 return FieldElement::from_hex(input);
340 }
341
342 let fr = F::from_str(input).ok()?;
343 Some(FieldElement(fr))
344 }
345
346 pub fn to_string_as_signed_integer(self, bit_size: u32) -> String {
354 assert!(bit_size <= 128);
355 if self.num_bits() > bit_size {
356 return self.to_string();
357 }
358
359 let max = if bit_size == 128 { i128::MAX as u128 } else { (1 << (bit_size - 1)) - 1 };
361 if self.to_u128() > max {
362 let f = FieldElement::from(2u32).pow(&bit_size.into()) - self;
363 format!("-{f}")
364 } else {
365 self.to_string()
366 }
367 }
368}
369
370impl<F: PrimeField> AcirField for FieldElement<F> {
371 fn one() -> FieldElement<F> {
372 FieldElement(F::one())
373 }
374 fn zero() -> FieldElement<F> {
375 FieldElement(F::zero())
376 }
377
378 fn is_zero(&self) -> bool {
379 self == &Self::zero()
380 }
381 fn is_one(&self) -> bool {
382 self == &Self::one()
383 }
384
385 fn pow(&self, exponent: &Self) -> Self {
386 FieldElement(self.0.pow(exponent.0.into_bigint()))
387 }
388
389 fn max_num_bits() -> u32 {
395 F::MODULUS_BIT_SIZE
396 }
397
398 fn max_num_bytes() -> u32 {
403 let num_bytes = Self::max_num_bits() / 8;
404 if Self::max_num_bits() % 8 == 0 { num_bytes } else { num_bytes + 1 }
405 }
406
407 fn modulus() -> BigUint {
408 BigUint::from_bytes_le(&F::MODULUS.to_bytes_le())
411 }
412
413 fn num_bits(&self) -> u32 {
415 let bigint = self.0.into_bigint();
416 let limbs = bigint.as_ref();
417 for (i, &limb) in limbs.iter().enumerate().rev() {
418 if limb != 0 {
419 return (i as u32) * 64 + (64 - limb.leading_zeros());
420 }
421 }
422 0
423 }
424
425 fn to_u128(self) -> u128 {
426 if !self.fits_in_u128() {
427 panic!("field element too large for u128");
428 }
429 let as_bigint = self.0.into_bigint();
430 let limbs = as_bigint.as_ref();
431
432 let mut result = u128::from(limbs[0]);
433 if limbs.len() > 1 {
434 let high_limb = u128::from(limbs[1]);
435 result += high_limb << 64;
436 }
437
438 result
439 }
440
441 fn try_into_u128(self) -> Option<u128> {
442 self.fits_in_u128().then(|| self.to_u128())
443 }
444
445 fn to_i128(self) -> i128 {
446 if !self.fits_in_i128() {
447 panic!("field element too large for i128");
448 }
449 if self.neg().num_bits() < self.num_bits() {
453 let bytes = self.neg().to_be_bytes();
454 i128::from_be_bytes(bytes[16..32].try_into().unwrap()).wrapping_neg()
458 } else {
459 let bytes = self.to_be_bytes();
460 i128::from_be_bytes(bytes[16..32].try_into().unwrap())
461 }
462 }
463
464 fn try_into_i128(self) -> Option<i128> {
465 self.fits_in_i128().then(|| self.to_i128())
466 }
467
468 fn try_to_u64(&self) -> Option<u64> {
469 (self.num_bits() <= 64).then(|| self.to_u128() as u64)
470 }
471
472 fn try_to_u32(&self) -> Option<u32> {
473 (self.num_bits() <= 32).then(|| self.to_u128() as u32)
474 }
475
476 fn inverse(&self) -> FieldElement<F> {
479 let inv = self.0.inverse().unwrap_or_else(F::zero);
480 FieldElement(inv)
481 }
482
483 fn to_hex(self) -> String {
484 let bytes = self.to_be_bytes();
485 hex::encode(bytes)
486 }
487
488 fn to_short_hex(self) -> String {
489 if self.is_zero() {
490 return "0x00".to_owned();
491 }
492
493 let bytes = self.to_be_bytes();
495
496 let first_nonzero = bytes.iter().position(|&b| b != 0).unwrap_or(bytes.len());
498 let trimmed = &bytes[first_nonzero..];
499
500 let mut result = String::with_capacity(2 + trimmed.len() * 2);
503 result.push_str("0x");
504
505 use std::fmt::Write;
507 write!(&mut result, "{:x}", trimmed[0]).unwrap();
508
509 if !result.len().is_multiple_of(2) {
511 result.insert(2, '0');
513 }
514
515 for byte in &trimmed[1..] {
517 write!(&mut result, "{byte:02x}").unwrap();
518 }
519
520 result
521 }
522
523 fn from_hex(hex_str: &str) -> Option<FieldElement<F>> {
524 let value = hex_str.strip_prefix("0x").unwrap_or(hex_str);
525
526 let hex_as_bytes = if value.len().is_multiple_of(2) {
528 hex::decode(value).ok()?
529 } else {
530 let mut padded = String::with_capacity(value.len() + 1);
532 padded.push('0');
533 padded.push_str(value);
534 hex::decode(padded).ok()?
535 };
536
537 Some(FieldElement::from_be_bytes_reduce(&hex_as_bytes))
538 }
539
540 fn to_be_bytes(self) -> Vec<u8> {
541 let mut bytes = self.to_le_bytes();
542 bytes.reverse();
543 bytes
544 }
545
546 fn to_le_bytes(self) -> Vec<u8> {
548 let mut bytes = Vec::new();
549 self.0.serialize_uncompressed(&mut bytes).unwrap();
550 bytes
551 }
552
553 fn from_be_bytes_reduce(bytes: &[u8]) -> FieldElement<F> {
556 FieldElement(F::from_be_bytes_mod_order(bytes))
557 }
558
559 fn from_le_bytes_reduce(bytes: &[u8]) -> FieldElement<F> {
562 FieldElement(F::from_le_bytes_mod_order(bytes))
563 }
564
565 fn fetch_nearest_bytes(&self, num_bits: usize) -> Vec<u8> {
568 fn nearest_bytes(num_bits: usize) -> usize {
569 num_bits.div_ceil(8) * 8
570 }
571
572 let num_bytes = nearest_bytes(num_bits);
573 let num_elements = num_bytes / 8;
574
575 let bytes = self.to_le_bytes();
576
577 bytes[0..num_elements].to_vec()
578 }
579}
580
581impl<F: PrimeField> Neg for FieldElement<F> {
582 type Output = FieldElement<F>;
583
584 fn neg(self) -> Self::Output {
585 FieldElement(-self.0)
586 }
587}
588
589impl<F: PrimeField> Mul for FieldElement<F> {
590 type Output = FieldElement<F>;
591 fn mul(mut self, rhs: FieldElement<F>) -> Self::Output {
592 self.0.mul_assign(&rhs.0);
593 FieldElement(self.0)
594 }
595}
596impl<F: PrimeField> Div for FieldElement<F> {
597 type Output = FieldElement<F>;
598 #[allow(clippy::suspicious_arithmetic_impl)]
599 fn div(self, rhs: FieldElement<F>) -> Self::Output {
600 self * rhs.inverse()
601 }
602}
603impl<F: PrimeField> Add for FieldElement<F> {
604 type Output = FieldElement<F>;
605 fn add(mut self, rhs: FieldElement<F>) -> Self::Output {
606 self.add_assign(rhs);
607 FieldElement(self.0)
608 }
609}
610impl<F: PrimeField> AddAssign for FieldElement<F> {
611 fn add_assign(&mut self, rhs: FieldElement<F>) {
612 self.0.add_assign(&rhs.0);
613 }
614}
615
616impl<F: PrimeField> Sub for FieldElement<F> {
617 type Output = FieldElement<F>;
618 fn sub(mut self, rhs: FieldElement<F>) -> Self::Output {
619 self.sub_assign(rhs);
620 FieldElement(self.0)
621 }
622}
623impl<F: PrimeField> SubAssign for FieldElement<F> {
624 fn sub_assign(&mut self, rhs: FieldElement<F>) {
625 self.0.sub_assign(&rhs.0);
626 }
627}
628
629impl<F: PrimeField> MsgpackTagged for FieldElement<F> {
630 const TAGGED: msgpack_tagged::Tagged = msgpack_tagged::Tagged::empty_product();
631
632 fn register_into(_reg: &mut msgpack_tagged::TagRegistry) {}
636}
637
638#[cfg(test)]
639mod tests {
640 use super::{AcirField, FieldElement};
641 use proptest::prelude::*;
642 use std::ops::Neg;
643
644 #[test]
645 fn requires_zero_bit_to_hold_zero() {
646 let field = FieldElement::<ark_bn254::Fr>::zero();
647 assert_eq!(field.num_bits(), 0);
648 }
649
650 #[test]
651 fn requires_one_bit_to_hold_one() {
652 let field = FieldElement::<ark_bn254::Fr>::one();
653 assert_eq!(field.num_bits(), 1);
654 }
655
656 proptest! {
657 #[test]
658 fn num_bits_agrees_with_ilog2(num in 1u128..) {
659 let field = FieldElement::<ark_bn254::Fr>::from(num);
660 prop_assert_eq!(field.num_bits(), num.ilog2() + 1);
661 }
662 }
663
664 #[test]
665 fn test_fits_in_u128() {
666 let field = FieldElement::<ark_bn254::Fr>::from(u128::MAX);
667 assert_eq!(field.num_bits(), 128);
668 assert!(field.fits_in_u128());
669 let big_field = field + FieldElement::one();
670 assert_eq!(big_field.num_bits(), 129);
671 assert!(!big_field.fits_in_u128());
672 }
673
674 #[test]
675 fn test_to_u128_basic() {
676 type F = FieldElement<ark_bn254::Fr>;
677
678 assert_eq!(F::zero().to_u128(), 0);
680
681 assert_eq!(F::from(1_u128).to_u128(), 1);
683 assert_eq!(F::from(42_u128).to_u128(), 42);
684 assert_eq!(F::from(1000_u128).to_u128(), 1000);
685
686 assert_eq!(F::from(u128::MAX).to_u128(), u128::MAX);
688
689 assert_eq!(F::from(1_u128 << 127).to_u128(), 1_u128 << 127);
691 assert_eq!(F::from((1_u128 << 127) - 1).to_u128(), (1_u128 << 127) - 1);
692 }
693
694 #[test]
695 #[should_panic(expected = "field element too large for u128")]
696 fn test_to_u128_panics_on_overflow() {
697 type F = FieldElement<ark_bn254::Fr>;
698
699 let too_large = F::from(u128::MAX) + F::one();
701 too_large.to_u128(); }
703
704 #[test]
705 fn test_try_into_u128() {
706 type F = FieldElement<ark_bn254::Fr>;
707
708 assert_eq!(F::zero().try_into_u128(), Some(0));
710 assert_eq!(F::from(42_u128).try_into_u128(), Some(42));
711 assert_eq!(F::from(u128::MAX).try_into_u128(), Some(u128::MAX));
712
713 let too_large = F::from(u128::MAX) + F::one();
715 assert_eq!(too_large.try_into_u128(), None);
716 }
717
718 #[test]
719 fn test_fits_in_i128() {
720 type F = FieldElement<ark_bn254::Fr>;
721
722 assert!(F::zero().fits_in_i128());
724 assert!(F::from(1_i128).fits_in_i128());
725 assert!(F::from(42_i128).fits_in_i128());
726 assert!(F::from(i128::MAX).fits_in_i128());
727
728 assert!(F::from(-1_i128).fits_in_i128());
730 assert!(F::from(-42_i128).fits_in_i128());
731 assert!(F::from(i128::MIN + 1).fits_in_i128());
732 assert!(F::from(i128::MIN).fits_in_i128());
733
734 assert!(F::from((1_u128 << 127) - 1).fits_in_i128());
736
737 assert!(!F::from(1_u128 << 127).fits_in_i128());
740
741 let too_large = F::from(u128::MAX);
743 assert!(!too_large.fits_in_i128());
744 }
745
746 #[test]
747 fn test_to_i128_positive() {
748 type F = FieldElement<ark_bn254::Fr>;
749
750 assert_eq!(F::zero().to_i128(), 0);
752 assert_eq!(F::from(1_i128).to_i128(), 1);
753 assert_eq!(F::from(42_i128).to_i128(), 42);
754 assert_eq!(F::from(1000_i128).to_i128(), 1000);
755 assert_eq!(F::from(i128::MAX).to_i128(), i128::MAX);
756 }
757
758 #[test]
759 fn test_to_i128_negative() {
760 type F = FieldElement<ark_bn254::Fr>;
761
762 assert_eq!(F::from(-1_i128).to_i128(), -1);
764 assert_eq!(F::from(-42_i128).to_i128(), -42);
765 assert_eq!(F::from(-1000_i128).to_i128(), -1000);
766
767 assert_eq!(F::from(-i128::MAX).to_i128(), -i128::MAX);
769 assert_eq!(F::from(i128::MIN + 1).to_i128(), i128::MIN + 1);
770 assert_eq!(F::from(i128::MIN).to_i128(), i128::MIN);
771 }
772
773 #[test]
774 fn test_to_i128_roundtrip() {
775 type F = FieldElement<ark_bn254::Fr>;
776
777 let test_values = vec![
779 0_i128,
780 1,
781 -1,
782 42,
783 -42,
784 i128::MAX,
785 i128::MAX - 1,
786 i128::MIN,
787 i128::MIN + 1,
788 -i128::MAX,
789 ];
790
791 for value in test_values {
792 let field = F::from(value);
793 assert!(field.fits_in_i128(), "Value {value} should fit in i128");
794 assert_eq!(field.to_i128(), value, "Roundtrip failed for {value}");
795 }
796 }
797
798 #[test]
799 #[should_panic(expected = "field element too large for i128")]
800 fn test_to_i128_panics_on_positive_overflow() {
801 type F = FieldElement<ark_bn254::Fr>;
802
803 let too_large = F::from(1_u128 << 127);
805 too_large.to_i128(); }
807
808 #[test]
809 #[should_panic(expected = "field element too large for i128")]
810 fn test_to_i128_panics_on_large_value() {
811 type F = FieldElement<ark_bn254::Fr>;
812
813 let too_large = F::from(u128::MAX);
815 too_large.to_i128(); }
817
818 #[test]
819 fn test_try_into_i128() {
820 type F = FieldElement<ark_bn254::Fr>;
821 assert_eq!(F::zero().try_into_i128(), Some(0));
823 assert_eq!(F::from(42_i128).try_into_i128(), Some(42));
824 assert_eq!(F::from(i128::MAX).try_into_i128(), Some(i128::MAX));
825 assert_eq!(F::from(-i128::MAX).try_into_i128(), Some(-i128::MAX));
826
827 assert_eq!(F::from(-1_i128).try_into_i128(), Some(-1));
829 assert_eq!(F::from(-42_i128).try_into_i128(), Some(-42));
830 assert_eq!(F::from(i128::MIN + 1).try_into_i128(), Some(i128::MIN + 1));
831 assert_eq!(F::from(i128::MAX - 1).try_into_i128(), Some(i128::MAX - 1));
832 assert_eq!(F::from(1_i128 << 126).try_into_i128(), Some(1_i128 << 126));
833 assert_eq!(F::from(-((1_i128 << 126) - 1)).try_into_i128(), Some(-((1_i128 << 126) - 1)));
834 assert_eq!(F::from(i128::MIN).try_into_i128(), Some(i128::MIN));
837 assert_eq!(F::from(1_u128 << 127).neg().try_into_i128(), Some(i128::MIN));
838 assert_eq!(F::from(1_u128 << 127).try_into_i128(), None);
840 assert_eq!(F::from(u128::MAX).try_into_i128(), None);
841 assert_eq!(F::from((1_u128 << 127) + 1).try_into_i128(), None);
843 assert_eq!(F::from((1_u128 << 127) + 1000).try_into_i128(), None);
844 assert_eq!(F::from((1_u128 << 127) + 1).neg().try_into_i128(), None);
845 assert_eq!(F::from((1_u128 << 127) + 100).try_into_i128(), None);
846 assert_eq!(F::from((1_u128 << 127) + 100).neg().try_into_i128(), None);
847 }
848
849 #[test]
850 fn serialize_fixed_test_vectors() {
851 let hex_strings = vec![
853 "0000000000000000000000000000000000000000000000000000000000000000",
854 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000",
855 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff",
856 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffffe",
857 ];
858
859 for (i, string) in hex_strings.into_iter().enumerate() {
860 let minus_i_field_element = -FieldElement::<ark_bn254::Fr>::from(i as i128);
861 assert_eq!(minus_i_field_element.to_hex(), string);
862 }
863 }
864
865 #[test]
866 fn max_num_bits_smoke() {
867 let max_num_bits_bn254 = FieldElement::<ark_bn254::Fr>::max_num_bits();
868 assert_eq!(max_num_bits_bn254, 254);
869 }
870
871 proptest! {
872 #[test]
873 fn test_endianness_prop(value in any::<u64>()) {
874 let field = FieldElement::<ark_bn254::Fr>::from(value);
875 let le_bytes = field.to_le_bytes();
877 let be_bytes = field.to_be_bytes();
878
879 let mut reversed_le = le_bytes.clone();
880 reversed_le.reverse();
881 prop_assert_eq!(&be_bytes, &reversed_le, "BE bytes should be reverse of LE bytes");
882
883 let from_le = FieldElement::from_le_bytes_reduce(&le_bytes);
885 let from_be = FieldElement::from_be_bytes_reduce(&be_bytes);
886 prop_assert_eq!(from_le, from_be, "Deserialization should be consistent between LE and BE");
887 prop_assert_eq!(from_le, field, "Deserialized value should match original");
888 }
889 }
890
891 #[test]
892 fn test_endianness() {
893 let field = FieldElement::<ark_bn254::Fr>::from(0x1234_5678_u32);
894 let le_bytes = field.to_le_bytes();
895 let be_bytes = field.to_be_bytes();
896
897 let mut reversed_le = le_bytes.clone();
899 reversed_le.reverse();
900 assert_eq!(&be_bytes, &reversed_le);
901
902 let from_le = FieldElement::from_le_bytes_reduce(&le_bytes);
904 let from_be = FieldElement::from_be_bytes_reduce(&be_bytes);
905 assert_eq!(from_le, from_be);
906 assert_eq!(from_le, field);
907
908 let large_field = FieldElement::<ark_bn254::Fr>::from(0x0123_4567_89AB_CDEF_u64); let large_le = large_field.to_le_bytes();
911 let reconstructed = FieldElement::from_le_bytes_reduce(&large_le);
912 assert_eq!(reconstructed, large_field);
913 }
914
915 proptest! {
916 #[test]
919 #[should_panic(expected = "serialized field element is not equal to input")]
920 fn recovers_original_hex_string(hex in "[0-9a-f]{64}") {
921 let fe: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&hex).expect("should accept any 32 byte hex string");
922 let output_hex = fe.to_hex();
923
924 prop_assert_eq!(hex, output_hex, "serialized field element is not equal to input");
925 }
926
927 #[test]
928 fn accepts_odd_length_hex_strings(hex in "(?:0x)[0-9a-fA-F]+") {
929 let insert_index = if hex.starts_with("0x") { 2 } else { 0 };
932 let mut opposite_parity_string = hex.clone();
933 opposite_parity_string.insert(insert_index, '0');
934
935 let fe_1: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&hex).unwrap();
936 let fe_2: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&opposite_parity_string).unwrap();
937
938 prop_assert_eq!(fe_1, fe_2, "equivalent hex strings with opposite parity deserialized to different values");
939 }
940 }
941
942 #[test]
943 fn test_to_hex() {
944 type F = FieldElement<ark_bn254::Fr>;
945 assert_eq!(
946 F::zero().to_hex(),
947 "0000000000000000000000000000000000000000000000000000000000000000"
948 );
949 assert_eq!(
950 F::one().to_hex(),
951 "0000000000000000000000000000000000000000000000000000000000000001"
952 );
953 assert_eq!(
954 F::from(0x123_u128).to_hex(),
955 "0000000000000000000000000000000000000000000000000000000000000123"
956 );
957 assert_eq!(
958 F::from(0x1234_u128).to_hex(),
959 "0000000000000000000000000000000000000000000000000000000000001234"
960 );
961 }
962
963 #[test]
964 fn test_to_short_hex() {
965 type F = FieldElement<ark_bn254::Fr>;
966 assert_eq!(F::zero().to_short_hex(), "0x00");
967 assert_eq!(F::one().to_short_hex(), "0x01");
968 assert_eq!(F::from(0x123_u128).to_short_hex(), "0x0123");
969 assert_eq!(F::from(0x1234_u128).to_short_hex(), "0x1234");
970 }
971
972 #[test]
973 fn to_string_as_signed_integer() {
974 type F = FieldElement<ark_bn254::Fr>;
975 assert_eq!(F::zero().to_string_as_signed_integer(8), "0");
976 assert_eq!(F::one().to_string_as_signed_integer(8), "1");
977 assert_eq!(F::from(127_u128).to_string_as_signed_integer(8), "127");
978 assert_eq!(F::from(128_u128).to_string_as_signed_integer(8), "-128");
979 assert_eq!(F::from(129_u128).to_string_as_signed_integer(8), "-127");
980 assert_eq!(F::from(255_u128).to_string_as_signed_integer(8), "-1");
981 assert_eq!(F::from(32767_u128).to_string_as_signed_integer(16), "32767");
982 assert_eq!(F::from(32768_u128).to_string_as_signed_integer(16), "-32768");
983 assert_eq!(F::from(65535_u128).to_string_as_signed_integer(16), "-1");
984 }
985}