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 {
294 let neg = self.neg();
295 self.num_bits() <= 127
296 || neg.num_bits() <= 127
297 || self.neg() == FieldElement::from(I128_SIGN_BOUNDARY)
298 }
299
300 pub fn try_from_str(input: &str) -> Option<FieldElement<F>> {
305 if input.contains('x') {
306 return FieldElement::from_hex(input);
307 }
308
309 let fr = F::from_str(input).ok()?;
310 Some(FieldElement(fr))
311 }
312
313 pub fn to_string_as_signed_integer(self, bit_size: u32) -> String {
321 assert!(bit_size <= 128);
322 if self.num_bits() > bit_size {
323 return self.to_string();
324 }
325
326 let max = if bit_size == 128 { i128::MAX as u128 } else { (1 << (bit_size - 1)) - 1 };
328 if self.to_u128() > max {
329 let f = FieldElement::from(2u32).pow(&bit_size.into()) - self;
330 format!("-{f}")
331 } else {
332 self.to_string()
333 }
334 }
335}
336
337impl<F: PrimeField> AcirField for FieldElement<F> {
338 fn one() -> FieldElement<F> {
339 FieldElement(F::one())
340 }
341 fn zero() -> FieldElement<F> {
342 FieldElement(F::zero())
343 }
344
345 fn is_zero(&self) -> bool {
346 self == &Self::zero()
347 }
348 fn is_one(&self) -> bool {
349 self == &Self::one()
350 }
351
352 fn pow(&self, exponent: &Self) -> Self {
353 FieldElement(self.0.pow(exponent.0.into_bigint()))
354 }
355
356 fn max_num_bits() -> u32 {
362 F::MODULUS_BIT_SIZE
363 }
364
365 fn max_num_bytes() -> u32 {
370 let num_bytes = Self::max_num_bits() / 8;
371 if Self::max_num_bits() % 8 == 0 { num_bytes } else { num_bytes + 1 }
372 }
373
374 fn modulus() -> BigUint {
375 F::MODULUS.into()
376 }
377
378 fn num_bits(&self) -> u32 {
380 let bigint = self.0.into_bigint();
381 let limbs = bigint.as_ref();
382 for (i, &limb) in limbs.iter().enumerate().rev() {
383 if limb != 0 {
384 return (i as u32) * 64 + (64 - limb.leading_zeros());
385 }
386 }
387 0
388 }
389
390 fn to_u128(self) -> u128 {
391 if !self.fits_in_u128() {
392 panic!("field element too large for u128");
393 }
394 let as_bigint = self.0.into_bigint();
395 let limbs = as_bigint.as_ref();
396
397 let mut result = u128::from(limbs[0]);
398 if limbs.len() > 1 {
399 let high_limb = u128::from(limbs[1]);
400 result += high_limb << 64;
401 }
402
403 result
404 }
405
406 fn try_into_u128(self) -> Option<u128> {
407 self.fits_in_u128().then(|| self.to_u128())
408 }
409
410 fn to_i128(self) -> i128 {
411 if !self.fits_in_i128() {
412 panic!("field element too large for i128");
413 }
414 if self.neg().num_bits() < self.num_bits() {
418 let bytes = self.neg().to_be_bytes();
419 i128::from_be_bytes(bytes[16..32].try_into().unwrap()).wrapping_neg()
423 } else {
424 let bytes = self.to_be_bytes();
425 i128::from_be_bytes(bytes[16..32].try_into().unwrap())
426 }
427 }
428
429 fn try_into_i128(self) -> Option<i128> {
430 self.fits_in_i128().then(|| self.to_i128())
431 }
432
433 fn try_to_u64(&self) -> Option<u64> {
434 (self.num_bits() <= 64).then(|| self.to_u128() as u64)
435 }
436
437 fn try_to_u32(&self) -> Option<u32> {
438 (self.num_bits() <= 32).then(|| self.to_u128() as u32)
439 }
440
441 fn inverse(&self) -> FieldElement<F> {
444 let inv = self.0.inverse().unwrap_or_else(F::zero);
445 FieldElement(inv)
446 }
447
448 fn to_hex(self) -> String {
449 let bytes = self.to_be_bytes();
450 hex::encode(bytes)
451 }
452
453 fn to_short_hex(self) -> String {
454 if self.is_zero() {
455 return "0x00".to_owned();
456 }
457
458 let bytes = self.to_be_bytes();
460
461 let first_nonzero = bytes.iter().position(|&b| b != 0).unwrap_or(bytes.len());
463 let trimmed = &bytes[first_nonzero..];
464
465 let mut result = String::with_capacity(2 + trimmed.len() * 2);
468 result.push_str("0x");
469
470 use std::fmt::Write;
472 write!(&mut result, "{:x}", trimmed[0]).unwrap();
473
474 if !result.len().is_multiple_of(2) {
476 result.insert(2, '0');
478 }
479
480 for byte in &trimmed[1..] {
482 write!(&mut result, "{byte:02x}").unwrap();
483 }
484
485 result
486 }
487
488 fn from_hex(hex_str: &str) -> Option<FieldElement<F>> {
489 let value = hex_str.strip_prefix("0x").unwrap_or(hex_str);
490
491 let hex_as_bytes = if value.len().is_multiple_of(2) {
493 hex::decode(value).ok()?
494 } else {
495 let mut padded = String::with_capacity(value.len() + 1);
497 padded.push('0');
498 padded.push_str(value);
499 hex::decode(padded).ok()?
500 };
501
502 Some(FieldElement::from_be_bytes_reduce(&hex_as_bytes))
503 }
504
505 fn to_be_bytes(self) -> Vec<u8> {
506 let mut bytes = self.to_le_bytes();
507 bytes.reverse();
508 bytes
509 }
510
511 fn to_le_bytes(self) -> Vec<u8> {
513 let mut bytes = Vec::new();
514 self.0.serialize_uncompressed(&mut bytes).unwrap();
515 bytes
516 }
517
518 fn from_be_bytes_reduce(bytes: &[u8]) -> FieldElement<F> {
521 FieldElement(F::from_be_bytes_mod_order(bytes))
522 }
523
524 fn from_le_bytes_reduce(bytes: &[u8]) -> FieldElement<F> {
527 FieldElement(F::from_le_bytes_mod_order(bytes))
528 }
529
530 fn fetch_nearest_bytes(&self, num_bits: usize) -> Vec<u8> {
533 fn nearest_bytes(num_bits: usize) -> usize {
534 num_bits.div_ceil(8) * 8
535 }
536
537 let num_bytes = nearest_bytes(num_bits);
538 let num_elements = num_bytes / 8;
539
540 let bytes = self.to_le_bytes();
541
542 bytes[0..num_elements].to_vec()
543 }
544}
545
546impl<F: PrimeField> Neg for FieldElement<F> {
547 type Output = FieldElement<F>;
548
549 fn neg(self) -> Self::Output {
550 FieldElement(-self.0)
551 }
552}
553
554impl<F: PrimeField> Mul for FieldElement<F> {
555 type Output = FieldElement<F>;
556 fn mul(mut self, rhs: FieldElement<F>) -> Self::Output {
557 self.0.mul_assign(&rhs.0);
558 FieldElement(self.0)
559 }
560}
561impl<F: PrimeField> Div for FieldElement<F> {
562 type Output = FieldElement<F>;
563 #[allow(clippy::suspicious_arithmetic_impl)]
564 fn div(self, rhs: FieldElement<F>) -> Self::Output {
565 self * rhs.inverse()
566 }
567}
568impl<F: PrimeField> Add for FieldElement<F> {
569 type Output = FieldElement<F>;
570 fn add(mut self, rhs: FieldElement<F>) -> Self::Output {
571 self.add_assign(rhs);
572 FieldElement(self.0)
573 }
574}
575impl<F: PrimeField> AddAssign for FieldElement<F> {
576 fn add_assign(&mut self, rhs: FieldElement<F>) {
577 self.0.add_assign(&rhs.0);
578 }
579}
580
581impl<F: PrimeField> Sub for FieldElement<F> {
582 type Output = FieldElement<F>;
583 fn sub(mut self, rhs: FieldElement<F>) -> Self::Output {
584 self.sub_assign(rhs);
585 FieldElement(self.0)
586 }
587}
588impl<F: PrimeField> SubAssign for FieldElement<F> {
589 fn sub_assign(&mut self, rhs: FieldElement<F>) {
590 self.0.sub_assign(&rhs.0);
591 }
592}
593
594#[cfg(test)]
595mod tests {
596 use super::{AcirField, FieldElement};
597 use proptest::prelude::*;
598 use std::ops::Neg;
599
600 #[test]
601 fn requires_zero_bit_to_hold_zero() {
602 let field = FieldElement::<ark_bn254::Fr>::zero();
603 assert_eq!(field.num_bits(), 0);
604 }
605
606 #[test]
607 fn requires_one_bit_to_hold_one() {
608 let field = FieldElement::<ark_bn254::Fr>::one();
609 assert_eq!(field.num_bits(), 1);
610 }
611
612 proptest! {
613 #[test]
614 fn num_bits_agrees_with_ilog2(num in 1u128..) {
615 let field = FieldElement::<ark_bn254::Fr>::from(num);
616 prop_assert_eq!(field.num_bits(), num.ilog2() + 1);
617 }
618 }
619
620 #[test]
621 fn test_fits_in_u128() {
622 let field = FieldElement::<ark_bn254::Fr>::from(u128::MAX);
623 assert_eq!(field.num_bits(), 128);
624 assert!(field.fits_in_u128());
625 let big_field = field + FieldElement::one();
626 assert_eq!(big_field.num_bits(), 129);
627 assert!(!big_field.fits_in_u128());
628 }
629
630 #[test]
631 fn test_to_u128_basic() {
632 type F = FieldElement<ark_bn254::Fr>;
633
634 assert_eq!(F::zero().to_u128(), 0);
636
637 assert_eq!(F::from(1_u128).to_u128(), 1);
639 assert_eq!(F::from(42_u128).to_u128(), 42);
640 assert_eq!(F::from(1000_u128).to_u128(), 1000);
641
642 assert_eq!(F::from(u128::MAX).to_u128(), u128::MAX);
644
645 assert_eq!(F::from(1_u128 << 127).to_u128(), 1_u128 << 127);
647 assert_eq!(F::from((1_u128 << 127) - 1).to_u128(), (1_u128 << 127) - 1);
648 }
649
650 #[test]
651 #[should_panic(expected = "field element too large for u128")]
652 fn test_to_u128_panics_on_overflow() {
653 type F = FieldElement<ark_bn254::Fr>;
654
655 let too_large = F::from(u128::MAX) + F::one();
657 too_large.to_u128(); }
659
660 #[test]
661 fn test_try_into_u128() {
662 type F = FieldElement<ark_bn254::Fr>;
663
664 assert_eq!(F::zero().try_into_u128(), Some(0));
666 assert_eq!(F::from(42_u128).try_into_u128(), Some(42));
667 assert_eq!(F::from(u128::MAX).try_into_u128(), Some(u128::MAX));
668
669 let too_large = F::from(u128::MAX) + F::one();
671 assert_eq!(too_large.try_into_u128(), None);
672 }
673
674 #[test]
675 fn test_fits_in_i128() {
676 type F = FieldElement<ark_bn254::Fr>;
677
678 assert!(F::zero().fits_in_i128());
680 assert!(F::from(1_i128).fits_in_i128());
681 assert!(F::from(42_i128).fits_in_i128());
682 assert!(F::from(i128::MAX).fits_in_i128());
683
684 assert!(F::from(-1_i128).fits_in_i128());
686 assert!(F::from(-42_i128).fits_in_i128());
687 assert!(F::from(i128::MIN + 1).fits_in_i128());
688 assert!(F::from(i128::MIN).fits_in_i128());
689
690 assert!(F::from((1_u128 << 127) - 1).fits_in_i128());
692
693 assert!(!F::from(1_u128 << 127).fits_in_i128());
696
697 let too_large = F::from(u128::MAX);
699 assert!(!too_large.fits_in_i128());
700 }
701
702 #[test]
703 fn test_to_i128_positive() {
704 type F = FieldElement<ark_bn254::Fr>;
705
706 assert_eq!(F::zero().to_i128(), 0);
708 assert_eq!(F::from(1_i128).to_i128(), 1);
709 assert_eq!(F::from(42_i128).to_i128(), 42);
710 assert_eq!(F::from(1000_i128).to_i128(), 1000);
711 assert_eq!(F::from(i128::MAX).to_i128(), i128::MAX);
712 }
713
714 #[test]
715 fn test_to_i128_negative() {
716 type F = FieldElement<ark_bn254::Fr>;
717
718 assert_eq!(F::from(-1_i128).to_i128(), -1);
720 assert_eq!(F::from(-42_i128).to_i128(), -42);
721 assert_eq!(F::from(-1000_i128).to_i128(), -1000);
722
723 assert_eq!(F::from(-i128::MAX).to_i128(), -i128::MAX);
725 assert_eq!(F::from(i128::MIN + 1).to_i128(), i128::MIN + 1);
726 assert_eq!(F::from(i128::MIN).to_i128(), i128::MIN);
727 }
728
729 #[test]
730 fn test_to_i128_roundtrip() {
731 type F = FieldElement<ark_bn254::Fr>;
732
733 let test_values = vec![
735 0_i128,
736 1,
737 -1,
738 42,
739 -42,
740 i128::MAX,
741 i128::MAX - 1,
742 i128::MIN,
743 i128::MIN + 1,
744 -i128::MAX,
745 ];
746
747 for value in test_values {
748 let field = F::from(value);
749 assert!(field.fits_in_i128(), "Value {value} should fit in i128");
750 assert_eq!(field.to_i128(), value, "Roundtrip failed for {value}");
751 }
752 }
753
754 #[test]
755 #[should_panic(expected = "field element too large for i128")]
756 fn test_to_i128_panics_on_positive_overflow() {
757 type F = FieldElement<ark_bn254::Fr>;
758
759 let too_large = F::from(1_u128 << 127);
761 too_large.to_i128(); }
763
764 #[test]
765 #[should_panic(expected = "field element too large for i128")]
766 fn test_to_i128_panics_on_large_value() {
767 type F = FieldElement<ark_bn254::Fr>;
768
769 let too_large = F::from(u128::MAX);
771 too_large.to_i128(); }
773
774 #[test]
775 fn test_try_into_i128() {
776 type F = FieldElement<ark_bn254::Fr>;
777 assert_eq!(F::zero().try_into_i128(), Some(0));
779 assert_eq!(F::from(42_i128).try_into_i128(), Some(42));
780 assert_eq!(F::from(i128::MAX).try_into_i128(), Some(i128::MAX));
781 assert_eq!(F::from(-i128::MAX).try_into_i128(), Some(-i128::MAX));
782
783 assert_eq!(F::from(-1_i128).try_into_i128(), Some(-1));
785 assert_eq!(F::from(-42_i128).try_into_i128(), Some(-42));
786 assert_eq!(F::from(i128::MIN + 1).try_into_i128(), Some(i128::MIN + 1));
787 assert_eq!(F::from(i128::MAX - 1).try_into_i128(), Some(i128::MAX - 1));
788 assert_eq!(F::from(1_i128 << 126).try_into_i128(), Some(1_i128 << 126));
789 assert_eq!(F::from(-((1_i128 << 126) - 1)).try_into_i128(), Some(-((1_i128 << 126) - 1)));
790 assert_eq!(F::from(i128::MIN).try_into_i128(), Some(i128::MIN));
793 assert_eq!(F::from(1_u128 << 127).neg().try_into_i128(), Some(i128::MIN));
794 assert_eq!(F::from(1_u128 << 127).try_into_i128(), None);
796 assert_eq!(F::from(u128::MAX).try_into_i128(), None);
797 assert_eq!(F::from((1_u128 << 127) + 1).try_into_i128(), None);
799 assert_eq!(F::from((1_u128 << 127) + 1000).try_into_i128(), None);
800 assert_eq!(F::from((1_u128 << 127) + 1).neg().try_into_i128(), None);
801 assert_eq!(F::from((1_u128 << 127) + 100).try_into_i128(), None);
802 assert_eq!(F::from((1_u128 << 127) + 100).neg().try_into_i128(), None);
803 }
804
805 #[test]
806 fn serialize_fixed_test_vectors() {
807 let hex_strings = vec![
809 "0000000000000000000000000000000000000000000000000000000000000000",
810 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000",
811 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff",
812 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffffe",
813 ];
814
815 for (i, string) in hex_strings.into_iter().enumerate() {
816 let minus_i_field_element = -FieldElement::<ark_bn254::Fr>::from(i as i128);
817 assert_eq!(minus_i_field_element.to_hex(), string);
818 }
819 }
820
821 #[test]
822 fn max_num_bits_smoke() {
823 let max_num_bits_bn254 = FieldElement::<ark_bn254::Fr>::max_num_bits();
824 assert_eq!(max_num_bits_bn254, 254);
825 }
826
827 proptest! {
828 #[test]
829 fn test_endianness_prop(value in any::<u64>()) {
830 let field = FieldElement::<ark_bn254::Fr>::from(value);
831 let le_bytes = field.to_le_bytes();
833 let be_bytes = field.to_be_bytes();
834
835 let mut reversed_le = le_bytes.clone();
836 reversed_le.reverse();
837 prop_assert_eq!(&be_bytes, &reversed_le, "BE bytes should be reverse of LE bytes");
838
839 let from_le = FieldElement::from_le_bytes_reduce(&le_bytes);
841 let from_be = FieldElement::from_be_bytes_reduce(&be_bytes);
842 prop_assert_eq!(from_le, from_be, "Deserialization should be consistent between LE and BE");
843 prop_assert_eq!(from_le, field, "Deserialized value should match original");
844 }
845 }
846
847 #[test]
848 fn test_endianness() {
849 let field = FieldElement::<ark_bn254::Fr>::from(0x1234_5678_u32);
850 let le_bytes = field.to_le_bytes();
851 let be_bytes = field.to_be_bytes();
852
853 let mut reversed_le = le_bytes.clone();
855 reversed_le.reverse();
856 assert_eq!(&be_bytes, &reversed_le);
857
858 let from_le = FieldElement::from_le_bytes_reduce(&le_bytes);
860 let from_be = FieldElement::from_be_bytes_reduce(&be_bytes);
861 assert_eq!(from_le, from_be);
862 assert_eq!(from_le, field);
863
864 let large_field = FieldElement::<ark_bn254::Fr>::from(0x0123_4567_89AB_CDEF_u64); let large_le = large_field.to_le_bytes();
867 let reconstructed = FieldElement::from_le_bytes_reduce(&large_le);
868 assert_eq!(reconstructed, large_field);
869 }
870
871 proptest! {
872 #[test]
875 #[should_panic(expected = "serialized field element is not equal to input")]
876 fn recovers_original_hex_string(hex in "[0-9a-f]{64}") {
877 let fe: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&hex).expect("should accept any 32 byte hex string");
878 let output_hex = fe.to_hex();
879
880 prop_assert_eq!(hex, output_hex, "serialized field element is not equal to input");
881 }
882
883 #[test]
884 fn accepts_odd_length_hex_strings(hex in "(?:0x)[0-9a-fA-F]+") {
885 let insert_index = if hex.starts_with("0x") { 2 } else { 0 };
888 let mut opposite_parity_string = hex.clone();
889 opposite_parity_string.insert(insert_index, '0');
890
891 let fe_1: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&hex).unwrap();
892 let fe_2: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&opposite_parity_string).unwrap();
893
894 prop_assert_eq!(fe_1, fe_2, "equivalent hex strings with opposite parity deserialized to different values");
895 }
896 }
897
898 #[test]
899 fn test_to_hex() {
900 type F = FieldElement<ark_bn254::Fr>;
901 assert_eq!(
902 F::zero().to_hex(),
903 "0000000000000000000000000000000000000000000000000000000000000000"
904 );
905 assert_eq!(
906 F::one().to_hex(),
907 "0000000000000000000000000000000000000000000000000000000000000001"
908 );
909 assert_eq!(
910 F::from(0x123_u128).to_hex(),
911 "0000000000000000000000000000000000000000000000000000000000000123"
912 );
913 assert_eq!(
914 F::from(0x1234_u128).to_hex(),
915 "0000000000000000000000000000000000000000000000000000000000001234"
916 );
917 }
918
919 #[test]
920 fn test_to_short_hex() {
921 type F = FieldElement<ark_bn254::Fr>;
922 assert_eq!(F::zero().to_short_hex(), "0x00");
923 assert_eq!(F::one().to_short_hex(), "0x01");
924 assert_eq!(F::from(0x123_u128).to_short_hex(), "0x0123");
925 assert_eq!(F::from(0x1234_u128).to_short_hex(), "0x1234");
926 }
927
928 #[test]
929 fn to_string_as_signed_integer() {
930 type F = FieldElement<ark_bn254::Fr>;
931 assert_eq!(F::zero().to_string_as_signed_integer(8), "0");
932 assert_eq!(F::one().to_string_as_signed_integer(8), "1");
933 assert_eq!(F::from(127_u128).to_string_as_signed_integer(8), "127");
934 assert_eq!(F::from(128_u128).to_string_as_signed_integer(8), "-128");
935 assert_eq!(F::from(129_u128).to_string_as_signed_integer(8), "-127");
936 assert_eq!(F::from(255_u128).to_string_as_signed_integer(8), "-1");
937 assert_eq!(F::from(32767_u128).to_string_as_signed_integer(16), "32767");
938 assert_eq!(F::from(32768_u128).to_string_as_signed_integer(16), "-32768");
939 assert_eq!(F::from(65535_u128).to_string_as_signed_integer(16), "-1");
940 }
941}