1use ark_ff::PrimeField;
2use ark_ff::Zero;
3use msgpack_tagged::MsgpackTagged;
4use num_bigint::BigUint;
5use serde::{Deserialize, Serialize};
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 serializer.serialize_bytes(&self.to_be_bytes())
144 }
145}
146
147impl<'de, T: PrimeField> Deserialize<'de> for FieldElement<T> {
148 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
149 where
150 D: serde::Deserializer<'de>,
151 {
152 let bytes = serde_bytes::ByteBuf::deserialize(deserializer)?;
163 Ok(Self::from_be_bytes_reduce(&bytes))
164 }
165}
166
167impl<F: PrimeField> From<u128> for FieldElement<F> {
168 fn from(a: u128) -> FieldElement<F> {
169 FieldElement(F::from(a))
170 }
171}
172
173impl<F: PrimeField> From<usize> for FieldElement<F> {
174 fn from(a: usize) -> FieldElement<F> {
175 FieldElement::from(a as u64)
176 }
177}
178
179impl<F: PrimeField> From<u64> for FieldElement<F> {
180 fn from(a: u64) -> FieldElement<F> {
181 FieldElement(F::from(a))
182 }
183}
184
185impl<F: PrimeField> From<u32> for FieldElement<F> {
186 fn from(a: u32) -> FieldElement<F> {
187 FieldElement(F::from(a))
188 }
189}
190
191impl<F: PrimeField> From<u16> for FieldElement<F> {
192 fn from(a: u16) -> FieldElement<F> {
193 FieldElement(F::from(a))
194 }
195}
196
197impl<F: PrimeField> From<u8> for FieldElement<F> {
198 fn from(a: u8) -> FieldElement<F> {
199 FieldElement(F::from(a))
200 }
201}
202
203impl<F: PrimeField> From<bool> for FieldElement<F> {
204 fn from(boolean: bool) -> FieldElement<F> {
205 if boolean { FieldElement::one() } else { FieldElement::zero() }
206 }
207}
208
209impl<F: PrimeField> TryFrom<FieldElement<F>> for u128 {
210 type Error = ();
211
212 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
213 value.try_into_u128().ok_or(())
214 }
215}
216
217impl<F: PrimeField> TryFrom<FieldElement<F>> for u64 {
218 type Error = ();
219
220 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
221 value.try_to_u64().ok_or(())
222 }
223}
224
225impl<F: PrimeField> TryFrom<FieldElement<F>> for u32 {
226 type Error = ();
227
228 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
229 value.try_to_u32().ok_or(())
230 }
231}
232
233impl<F: PrimeField> TryFrom<FieldElement<F>> for u16 {
234 type Error = ();
235
236 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
237 value.try_to_u32().and_then(|x| x.try_into().ok()).ok_or(())
238 }
239}
240
241impl<F: PrimeField> TryFrom<FieldElement<F>> for u8 {
242 type Error = ();
243
244 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
245 value.try_to_u32().and_then(|x| x.try_into().ok()).ok_or(())
246 }
247}
248
249impl<F: PrimeField> TryFrom<FieldElement<F>> for i128 {
250 type Error = ();
251
252 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
253 value.try_into_i128().ok_or(())
254 }
255}
256
257impl<F: PrimeField> TryFrom<FieldElement<F>> for i64 {
258 type Error = ();
259
260 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
261 value.try_into_i128().and_then(|x| x.try_into().ok()).ok_or(())
262 }
263}
264
265impl<F: PrimeField> TryFrom<FieldElement<F>> for i32 {
266 type Error = ();
267
268 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
269 value.try_into_i128().and_then(|x| x.try_into().ok()).ok_or(())
270 }
271}
272
273impl<F: PrimeField> TryFrom<FieldElement<F>> for i16 {
274 type Error = ();
275
276 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
277 value.try_into_i128().and_then(|x| x.try_into().ok()).ok_or(())
278 }
279}
280
281impl<F: PrimeField> TryFrom<FieldElement<F>> for i8 {
282 type Error = ();
283
284 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
285 value.try_into_i128().and_then(|x| x.try_into().ok()).ok_or(())
286 }
287}
288
289impl<F: PrimeField> From<FieldElement<F>> for bool {
290 fn from(field: FieldElement<F>) -> bool {
291 !field.is_zero()
292 }
293}
294
295impl<F: PrimeField> FieldElement<F> {
296 pub fn from_repr(field: F) -> Self {
300 Self(field)
301 }
302
303 pub fn into_repr(self) -> F {
307 self.0
308 }
309
310 pub fn fits_in_u128(&self) -> bool {
315 self.num_bits() <= 128
316 }
317
318 pub fn fits_in_i128(&self) -> bool {
326 let neg = self.neg();
327 self.num_bits() <= 127
328 || neg.num_bits() <= 127
329 || self.neg() == FieldElement::from(I128_SIGN_BOUNDARY)
330 }
331
332 pub fn try_from_str(input: &str) -> Option<FieldElement<F>> {
337 if input.contains('x') {
338 return FieldElement::from_hex(input);
339 }
340
341 let fr = F::from_str(input).ok()?;
342 Some(FieldElement(fr))
343 }
344
345 pub fn to_string_as_signed_integer(self, bit_size: u32) -> String {
353 assert!(bit_size <= 128);
354 if self.num_bits() > bit_size {
355 return self.to_string();
356 }
357
358 let max = if bit_size == 128 { i128::MAX as u128 } else { (1 << (bit_size - 1)) - 1 };
360 if self.to_u128() > max {
361 let f = FieldElement::from(2u32).pow(&bit_size.into()) - self;
362 format!("-{f}")
363 } else {
364 self.to_string()
365 }
366 }
367}
368
369impl<F: PrimeField> AcirField for FieldElement<F> {
370 fn one() -> FieldElement<F> {
371 FieldElement(F::one())
372 }
373 fn zero() -> FieldElement<F> {
374 FieldElement(F::zero())
375 }
376
377 fn is_zero(&self) -> bool {
378 self == &Self::zero()
379 }
380 fn is_one(&self) -> bool {
381 self == &Self::one()
382 }
383
384 fn pow(&self, exponent: &Self) -> Self {
385 FieldElement(self.0.pow(exponent.0.into_bigint()))
386 }
387
388 fn max_num_bits() -> u32 {
394 F::MODULUS_BIT_SIZE
395 }
396
397 fn max_num_bytes() -> u32 {
402 let num_bytes = Self::max_num_bits() / 8;
403 if Self::max_num_bits() % 8 == 0 { num_bytes } else { num_bytes + 1 }
404 }
405
406 fn modulus() -> BigUint {
407 F::MODULUS.into()
408 }
409
410 fn num_bits(&self) -> u32 {
412 let bigint = self.0.into_bigint();
413 let limbs = bigint.as_ref();
414 for (i, &limb) in limbs.iter().enumerate().rev() {
415 if limb != 0 {
416 return (i as u32) * 64 + (64 - limb.leading_zeros());
417 }
418 }
419 0
420 }
421
422 fn to_u128(self) -> u128 {
423 if !self.fits_in_u128() {
424 panic!("field element too large for u128");
425 }
426 let as_bigint = self.0.into_bigint();
427 let limbs = as_bigint.as_ref();
428
429 let mut result = u128::from(limbs[0]);
430 if limbs.len() > 1 {
431 let high_limb = u128::from(limbs[1]);
432 result += high_limb << 64;
433 }
434
435 result
436 }
437
438 fn try_into_u128(self) -> Option<u128> {
439 self.fits_in_u128().then(|| self.to_u128())
440 }
441
442 fn to_i128(self) -> i128 {
443 if !self.fits_in_i128() {
444 panic!("field element too large for i128");
445 }
446 if self.neg().num_bits() < self.num_bits() {
450 let bytes = self.neg().to_be_bytes();
451 i128::from_be_bytes(bytes[16..32].try_into().unwrap()).wrapping_neg()
455 } else {
456 let bytes = self.to_be_bytes();
457 i128::from_be_bytes(bytes[16..32].try_into().unwrap())
458 }
459 }
460
461 fn try_into_i128(self) -> Option<i128> {
462 self.fits_in_i128().then(|| self.to_i128())
463 }
464
465 fn try_to_u64(&self) -> Option<u64> {
466 (self.num_bits() <= 64).then(|| self.to_u128() as u64)
467 }
468
469 fn try_to_u32(&self) -> Option<u32> {
470 (self.num_bits() <= 32).then(|| self.to_u128() as u32)
471 }
472
473 fn inverse(&self) -> FieldElement<F> {
476 let inv = self.0.inverse().unwrap_or_else(F::zero);
477 FieldElement(inv)
478 }
479
480 fn to_hex(self) -> String {
481 let bytes = self.to_be_bytes();
482 hex::encode(bytes)
483 }
484
485 fn to_short_hex(self) -> String {
486 if self.is_zero() {
487 return "0x00".to_owned();
488 }
489
490 let bytes = self.to_be_bytes();
492
493 let first_nonzero = bytes.iter().position(|&b| b != 0).unwrap_or(bytes.len());
495 let trimmed = &bytes[first_nonzero..];
496
497 let mut result = String::with_capacity(2 + trimmed.len() * 2);
500 result.push_str("0x");
501
502 use std::fmt::Write;
504 write!(&mut result, "{:x}", trimmed[0]).unwrap();
505
506 if !result.len().is_multiple_of(2) {
508 result.insert(2, '0');
510 }
511
512 for byte in &trimmed[1..] {
514 write!(&mut result, "{byte:02x}").unwrap();
515 }
516
517 result
518 }
519
520 fn from_hex(hex_str: &str) -> Option<FieldElement<F>> {
521 let value = hex_str.strip_prefix("0x").unwrap_or(hex_str);
522
523 let hex_as_bytes = if value.len().is_multiple_of(2) {
525 hex::decode(value).ok()?
526 } else {
527 let mut padded = String::with_capacity(value.len() + 1);
529 padded.push('0');
530 padded.push_str(value);
531 hex::decode(padded).ok()?
532 };
533
534 Some(FieldElement::from_be_bytes_reduce(&hex_as_bytes))
535 }
536
537 fn to_be_bytes(self) -> Vec<u8> {
538 let mut bytes = self.to_le_bytes();
539 bytes.reverse();
540 bytes
541 }
542
543 fn to_le_bytes(self) -> Vec<u8> {
545 let mut bytes = Vec::new();
546 self.0.serialize_uncompressed(&mut bytes).unwrap();
547 bytes
548 }
549
550 fn from_be_bytes_reduce(bytes: &[u8]) -> FieldElement<F> {
553 FieldElement(F::from_be_bytes_mod_order(bytes))
554 }
555
556 fn from_le_bytes_reduce(bytes: &[u8]) -> FieldElement<F> {
559 FieldElement(F::from_le_bytes_mod_order(bytes))
560 }
561
562 fn fetch_nearest_bytes(&self, num_bits: usize) -> Vec<u8> {
565 fn nearest_bytes(num_bits: usize) -> usize {
566 num_bits.div_ceil(8) * 8
567 }
568
569 let num_bytes = nearest_bytes(num_bits);
570 let num_elements = num_bytes / 8;
571
572 let bytes = self.to_le_bytes();
573
574 bytes[0..num_elements].to_vec()
575 }
576}
577
578impl<F: PrimeField> Neg for FieldElement<F> {
579 type Output = FieldElement<F>;
580
581 fn neg(self) -> Self::Output {
582 FieldElement(-self.0)
583 }
584}
585
586impl<F: PrimeField> Mul for FieldElement<F> {
587 type Output = FieldElement<F>;
588 fn mul(mut self, rhs: FieldElement<F>) -> Self::Output {
589 self.0.mul_assign(&rhs.0);
590 FieldElement(self.0)
591 }
592}
593impl<F: PrimeField> Div for FieldElement<F> {
594 type Output = FieldElement<F>;
595 #[allow(clippy::suspicious_arithmetic_impl)]
596 fn div(self, rhs: FieldElement<F>) -> Self::Output {
597 self * rhs.inverse()
598 }
599}
600impl<F: PrimeField> Add for FieldElement<F> {
601 type Output = FieldElement<F>;
602 fn add(mut self, rhs: FieldElement<F>) -> Self::Output {
603 self.add_assign(rhs);
604 FieldElement(self.0)
605 }
606}
607impl<F: PrimeField> AddAssign for FieldElement<F> {
608 fn add_assign(&mut self, rhs: FieldElement<F>) {
609 self.0.add_assign(&rhs.0);
610 }
611}
612
613impl<F: PrimeField> Sub for FieldElement<F> {
614 type Output = FieldElement<F>;
615 fn sub(mut self, rhs: FieldElement<F>) -> Self::Output {
616 self.sub_assign(rhs);
617 FieldElement(self.0)
618 }
619}
620impl<F: PrimeField> SubAssign for FieldElement<F> {
621 fn sub_assign(&mut self, rhs: FieldElement<F>) {
622 self.0.sub_assign(&rhs.0);
623 }
624}
625
626impl<F: PrimeField> MsgpackTagged for FieldElement<F> {
627 const TAGGED: msgpack_tagged::Tagged = msgpack_tagged::Tagged::empty_product();
628
629 fn register_into(_reg: &mut msgpack_tagged::TagRegistry) {}
633}
634
635#[cfg(test)]
636mod tests {
637 use super::{AcirField, FieldElement};
638 use proptest::prelude::*;
639 use std::ops::Neg;
640
641 #[test]
642 fn requires_zero_bit_to_hold_zero() {
643 let field = FieldElement::<ark_bn254::Fr>::zero();
644 assert_eq!(field.num_bits(), 0);
645 }
646
647 #[test]
648 fn requires_one_bit_to_hold_one() {
649 let field = FieldElement::<ark_bn254::Fr>::one();
650 assert_eq!(field.num_bits(), 1);
651 }
652
653 proptest! {
654 #[test]
655 fn num_bits_agrees_with_ilog2(num in 1u128..) {
656 let field = FieldElement::<ark_bn254::Fr>::from(num);
657 prop_assert_eq!(field.num_bits(), num.ilog2() + 1);
658 }
659 }
660
661 #[test]
662 fn test_fits_in_u128() {
663 let field = FieldElement::<ark_bn254::Fr>::from(u128::MAX);
664 assert_eq!(field.num_bits(), 128);
665 assert!(field.fits_in_u128());
666 let big_field = field + FieldElement::one();
667 assert_eq!(big_field.num_bits(), 129);
668 assert!(!big_field.fits_in_u128());
669 }
670
671 #[test]
672 fn test_to_u128_basic() {
673 type F = FieldElement<ark_bn254::Fr>;
674
675 assert_eq!(F::zero().to_u128(), 0);
677
678 assert_eq!(F::from(1_u128).to_u128(), 1);
680 assert_eq!(F::from(42_u128).to_u128(), 42);
681 assert_eq!(F::from(1000_u128).to_u128(), 1000);
682
683 assert_eq!(F::from(u128::MAX).to_u128(), u128::MAX);
685
686 assert_eq!(F::from(1_u128 << 127).to_u128(), 1_u128 << 127);
688 assert_eq!(F::from((1_u128 << 127) - 1).to_u128(), (1_u128 << 127) - 1);
689 }
690
691 #[test]
692 #[should_panic(expected = "field element too large for u128")]
693 fn test_to_u128_panics_on_overflow() {
694 type F = FieldElement<ark_bn254::Fr>;
695
696 let too_large = F::from(u128::MAX) + F::one();
698 too_large.to_u128(); }
700
701 #[test]
702 fn test_try_into_u128() {
703 type F = FieldElement<ark_bn254::Fr>;
704
705 assert_eq!(F::zero().try_into_u128(), Some(0));
707 assert_eq!(F::from(42_u128).try_into_u128(), Some(42));
708 assert_eq!(F::from(u128::MAX).try_into_u128(), Some(u128::MAX));
709
710 let too_large = F::from(u128::MAX) + F::one();
712 assert_eq!(too_large.try_into_u128(), None);
713 }
714
715 #[test]
716 fn test_fits_in_i128() {
717 type F = FieldElement<ark_bn254::Fr>;
718
719 assert!(F::zero().fits_in_i128());
721 assert!(F::from(1_i128).fits_in_i128());
722 assert!(F::from(42_i128).fits_in_i128());
723 assert!(F::from(i128::MAX).fits_in_i128());
724
725 assert!(F::from(-1_i128).fits_in_i128());
727 assert!(F::from(-42_i128).fits_in_i128());
728 assert!(F::from(i128::MIN + 1).fits_in_i128());
729 assert!(F::from(i128::MIN).fits_in_i128());
730
731 assert!(F::from((1_u128 << 127) - 1).fits_in_i128());
733
734 assert!(!F::from(1_u128 << 127).fits_in_i128());
737
738 let too_large = F::from(u128::MAX);
740 assert!(!too_large.fits_in_i128());
741 }
742
743 #[test]
744 fn test_to_i128_positive() {
745 type F = FieldElement<ark_bn254::Fr>;
746
747 assert_eq!(F::zero().to_i128(), 0);
749 assert_eq!(F::from(1_i128).to_i128(), 1);
750 assert_eq!(F::from(42_i128).to_i128(), 42);
751 assert_eq!(F::from(1000_i128).to_i128(), 1000);
752 assert_eq!(F::from(i128::MAX).to_i128(), i128::MAX);
753 }
754
755 #[test]
756 fn test_to_i128_negative() {
757 type F = FieldElement<ark_bn254::Fr>;
758
759 assert_eq!(F::from(-1_i128).to_i128(), -1);
761 assert_eq!(F::from(-42_i128).to_i128(), -42);
762 assert_eq!(F::from(-1000_i128).to_i128(), -1000);
763
764 assert_eq!(F::from(-i128::MAX).to_i128(), -i128::MAX);
766 assert_eq!(F::from(i128::MIN + 1).to_i128(), i128::MIN + 1);
767 assert_eq!(F::from(i128::MIN).to_i128(), i128::MIN);
768 }
769
770 #[test]
771 fn test_to_i128_roundtrip() {
772 type F = FieldElement<ark_bn254::Fr>;
773
774 let test_values = vec![
776 0_i128,
777 1,
778 -1,
779 42,
780 -42,
781 i128::MAX,
782 i128::MAX - 1,
783 i128::MIN,
784 i128::MIN + 1,
785 -i128::MAX,
786 ];
787
788 for value in test_values {
789 let field = F::from(value);
790 assert!(field.fits_in_i128(), "Value {value} should fit in i128");
791 assert_eq!(field.to_i128(), value, "Roundtrip failed for {value}");
792 }
793 }
794
795 #[test]
796 #[should_panic(expected = "field element too large for i128")]
797 fn test_to_i128_panics_on_positive_overflow() {
798 type F = FieldElement<ark_bn254::Fr>;
799
800 let too_large = F::from(1_u128 << 127);
802 too_large.to_i128(); }
804
805 #[test]
806 #[should_panic(expected = "field element too large for i128")]
807 fn test_to_i128_panics_on_large_value() {
808 type F = FieldElement<ark_bn254::Fr>;
809
810 let too_large = F::from(u128::MAX);
812 too_large.to_i128(); }
814
815 #[test]
816 fn test_try_into_i128() {
817 type F = FieldElement<ark_bn254::Fr>;
818 assert_eq!(F::zero().try_into_i128(), Some(0));
820 assert_eq!(F::from(42_i128).try_into_i128(), Some(42));
821 assert_eq!(F::from(i128::MAX).try_into_i128(), Some(i128::MAX));
822 assert_eq!(F::from(-i128::MAX).try_into_i128(), Some(-i128::MAX));
823
824 assert_eq!(F::from(-1_i128).try_into_i128(), Some(-1));
826 assert_eq!(F::from(-42_i128).try_into_i128(), Some(-42));
827 assert_eq!(F::from(i128::MIN + 1).try_into_i128(), Some(i128::MIN + 1));
828 assert_eq!(F::from(i128::MAX - 1).try_into_i128(), Some(i128::MAX - 1));
829 assert_eq!(F::from(1_i128 << 126).try_into_i128(), Some(1_i128 << 126));
830 assert_eq!(F::from(-((1_i128 << 126) - 1)).try_into_i128(), Some(-((1_i128 << 126) - 1)));
831 assert_eq!(F::from(i128::MIN).try_into_i128(), Some(i128::MIN));
834 assert_eq!(F::from(1_u128 << 127).neg().try_into_i128(), Some(i128::MIN));
835 assert_eq!(F::from(1_u128 << 127).try_into_i128(), None);
837 assert_eq!(F::from(u128::MAX).try_into_i128(), None);
838 assert_eq!(F::from((1_u128 << 127) + 1).try_into_i128(), None);
840 assert_eq!(F::from((1_u128 << 127) + 1000).try_into_i128(), None);
841 assert_eq!(F::from((1_u128 << 127) + 1).neg().try_into_i128(), None);
842 assert_eq!(F::from((1_u128 << 127) + 100).try_into_i128(), None);
843 assert_eq!(F::from((1_u128 << 127) + 100).neg().try_into_i128(), None);
844 }
845
846 #[test]
847 fn serialize_fixed_test_vectors() {
848 let hex_strings = vec![
850 "0000000000000000000000000000000000000000000000000000000000000000",
851 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000",
852 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff",
853 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffffe",
854 ];
855
856 for (i, string) in hex_strings.into_iter().enumerate() {
857 let minus_i_field_element = -FieldElement::<ark_bn254::Fr>::from(i as i128);
858 assert_eq!(minus_i_field_element.to_hex(), string);
859 }
860 }
861
862 #[test]
863 fn max_num_bits_smoke() {
864 let max_num_bits_bn254 = FieldElement::<ark_bn254::Fr>::max_num_bits();
865 assert_eq!(max_num_bits_bn254, 254);
866 }
867
868 proptest! {
869 #[test]
870 fn test_endianness_prop(value in any::<u64>()) {
871 let field = FieldElement::<ark_bn254::Fr>::from(value);
872 let le_bytes = field.to_le_bytes();
874 let be_bytes = field.to_be_bytes();
875
876 let mut reversed_le = le_bytes.clone();
877 reversed_le.reverse();
878 prop_assert_eq!(&be_bytes, &reversed_le, "BE bytes should be reverse of LE bytes");
879
880 let from_le = FieldElement::from_le_bytes_reduce(&le_bytes);
882 let from_be = FieldElement::from_be_bytes_reduce(&be_bytes);
883 prop_assert_eq!(from_le, from_be, "Deserialization should be consistent between LE and BE");
884 prop_assert_eq!(from_le, field, "Deserialized value should match original");
885 }
886 }
887
888 #[test]
889 fn test_endianness() {
890 let field = FieldElement::<ark_bn254::Fr>::from(0x1234_5678_u32);
891 let le_bytes = field.to_le_bytes();
892 let be_bytes = field.to_be_bytes();
893
894 let mut reversed_le = le_bytes.clone();
896 reversed_le.reverse();
897 assert_eq!(&be_bytes, &reversed_le);
898
899 let from_le = FieldElement::from_le_bytes_reduce(&le_bytes);
901 let from_be = FieldElement::from_be_bytes_reduce(&be_bytes);
902 assert_eq!(from_le, from_be);
903 assert_eq!(from_le, field);
904
905 let large_field = FieldElement::<ark_bn254::Fr>::from(0x0123_4567_89AB_CDEF_u64); let large_le = large_field.to_le_bytes();
908 let reconstructed = FieldElement::from_le_bytes_reduce(&large_le);
909 assert_eq!(reconstructed, large_field);
910 }
911
912 proptest! {
913 #[test]
916 #[should_panic(expected = "serialized field element is not equal to input")]
917 fn recovers_original_hex_string(hex in "[0-9a-f]{64}") {
918 let fe: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&hex).expect("should accept any 32 byte hex string");
919 let output_hex = fe.to_hex();
920
921 prop_assert_eq!(hex, output_hex, "serialized field element is not equal to input");
922 }
923
924 #[test]
925 fn accepts_odd_length_hex_strings(hex in "(?:0x)[0-9a-fA-F]+") {
926 let insert_index = if hex.starts_with("0x") { 2 } else { 0 };
929 let mut opposite_parity_string = hex.clone();
930 opposite_parity_string.insert(insert_index, '0');
931
932 let fe_1: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&hex).unwrap();
933 let fe_2: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&opposite_parity_string).unwrap();
934
935 prop_assert_eq!(fe_1, fe_2, "equivalent hex strings with opposite parity deserialized to different values");
936 }
937 }
938
939 #[test]
940 fn test_to_hex() {
941 type F = FieldElement<ark_bn254::Fr>;
942 assert_eq!(
943 F::zero().to_hex(),
944 "0000000000000000000000000000000000000000000000000000000000000000"
945 );
946 assert_eq!(
947 F::one().to_hex(),
948 "0000000000000000000000000000000000000000000000000000000000000001"
949 );
950 assert_eq!(
951 F::from(0x123_u128).to_hex(),
952 "0000000000000000000000000000000000000000000000000000000000000123"
953 );
954 assert_eq!(
955 F::from(0x1234_u128).to_hex(),
956 "0000000000000000000000000000000000000000000000000000000000001234"
957 );
958 }
959
960 #[test]
961 fn test_to_short_hex() {
962 type F = FieldElement<ark_bn254::Fr>;
963 assert_eq!(F::zero().to_short_hex(), "0x00");
964 assert_eq!(F::one().to_short_hex(), "0x01");
965 assert_eq!(F::from(0x123_u128).to_short_hex(), "0x0123");
966 assert_eq!(F::from(0x1234_u128).to_short_hex(), "0x1234");
967 }
968
969 #[test]
970 fn to_string_as_signed_integer() {
971 type F = FieldElement<ark_bn254::Fr>;
972 assert_eq!(F::zero().to_string_as_signed_integer(8), "0");
973 assert_eq!(F::one().to_string_as_signed_integer(8), "1");
974 assert_eq!(F::from(127_u128).to_string_as_signed_integer(8), "127");
975 assert_eq!(F::from(128_u128).to_string_as_signed_integer(8), "-128");
976 assert_eq!(F::from(129_u128).to_string_as_signed_integer(8), "-127");
977 assert_eq!(F::from(255_u128).to_string_as_signed_integer(8), "-1");
978 assert_eq!(F::from(32767_u128).to_string_as_signed_integer(16), "32767");
979 assert_eq!(F::from(32768_u128).to_string_as_signed_integer(16), "-32768");
980 assert_eq!(F::from(65535_u128).to_string_as_signed_integer(16), "-1");
981 }
982}