1use ark_ff::PrimeField;
2use ark_ff::Zero;
3use ark_std::io::Write;
4use num_bigint::BigUint;
5use serde::{Deserialize, Serialize};
6use std::borrow::Cow;
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 self.to_be_bytes().serialize(serializer)
123 }
124}
125
126impl<'de, T: PrimeField> Deserialize<'de> for FieldElement<T> {
127 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
128 where
129 D: serde::Deserializer<'de>,
130 {
131 let s: Cow<'de, [u8]> = Deserialize::deserialize(deserializer)?;
132 Ok(Self::from_be_bytes_reduce(&s))
133 }
134}
135
136impl<F: PrimeField> From<u128> for FieldElement<F> {
137 fn from(a: u128) -> FieldElement<F> {
138 FieldElement(F::from(a))
139 }
140}
141
142impl<F: PrimeField> From<usize> for FieldElement<F> {
143 fn from(a: usize) -> FieldElement<F> {
144 FieldElement::from(a as u64)
145 }
146}
147
148impl<F: PrimeField> From<u64> for FieldElement<F> {
149 fn from(a: u64) -> FieldElement<F> {
150 FieldElement(F::from(a))
151 }
152}
153
154impl<F: PrimeField> From<u32> for FieldElement<F> {
155 fn from(a: u32) -> FieldElement<F> {
156 FieldElement(F::from(a))
157 }
158}
159
160impl<F: PrimeField> From<u16> for FieldElement<F> {
161 fn from(a: u16) -> FieldElement<F> {
162 FieldElement(F::from(a))
163 }
164}
165
166impl<F: PrimeField> From<u8> for FieldElement<F> {
167 fn from(a: u8) -> FieldElement<F> {
168 FieldElement(F::from(a))
169 }
170}
171
172impl<F: PrimeField> From<bool> for FieldElement<F> {
173 fn from(boolean: bool) -> FieldElement<F> {
174 if boolean { FieldElement::one() } else { FieldElement::zero() }
175 }
176}
177
178impl<F: PrimeField> TryFrom<FieldElement<F>> for u128 {
179 type Error = ();
180
181 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
182 match value.try_into_u128() {
183 Some(value) => Ok(value),
184 None => Err(()),
185 }
186 }
187}
188
189impl<F: PrimeField> TryFrom<FieldElement<F>> for i128 {
190 type Error = ();
191
192 fn try_from(value: FieldElement<F>) -> Result<Self, Self::Error> {
193 match value.try_into_i128() {
194 Some(value) => Ok(value),
195 None => Err(()),
196 }
197 }
198}
199
200impl<F: PrimeField> From<FieldElement<F>> for bool {
201 fn from(field: FieldElement<F>) -> bool {
202 !field.is_zero()
203 }
204}
205
206impl<F: PrimeField> FieldElement<F> {
207 pub fn from_repr(field: F) -> Self {
211 Self(field)
212 }
213
214 pub fn into_repr(self) -> F {
218 self.0
219 }
220
221 pub fn fits_in_u128(&self) -> bool {
226 self.num_bits() <= 128
227 }
228
229 pub fn fits_in_i128(&self) -> bool {
236 let num_bits = u32::min(self.neg().num_bits(), self.num_bits());
237 num_bits <= 127 && self != &FieldElement::from(I128_SIGN_BOUNDARY)
238 }
239
240 pub fn try_from_str(input: &str) -> Option<FieldElement<F>> {
245 if input.contains('x') {
246 return FieldElement::from_hex(input);
247 }
248
249 let fr = F::from_str(input).ok()?;
250 Some(FieldElement(fr))
251 }
252
253 pub fn to_string_as_signed_integer(self, bit_size: u32) -> String {
261 assert!(bit_size <= 128);
262 if self.num_bits() > bit_size {
263 return self.to_string();
264 }
265
266 let max = if bit_size == 128 { i128::MAX as u128 } else { (1 << (bit_size - 1)) - 1 };
268 if self.to_u128() > max {
269 let f = FieldElement::from(2u32).pow(&bit_size.into()) - self;
270 format!("-{f}")
271 } else {
272 self.to_string()
273 }
274 }
275}
276
277impl<F: PrimeField> AcirField for FieldElement<F> {
278 fn one() -> FieldElement<F> {
279 FieldElement(F::one())
280 }
281 fn zero() -> FieldElement<F> {
282 FieldElement(F::zero())
283 }
284
285 fn is_zero(&self) -> bool {
286 self == &Self::zero()
287 }
288 fn is_one(&self) -> bool {
289 self == &Self::one()
290 }
291
292 fn pow(&self, exponent: &Self) -> Self {
293 FieldElement(self.0.pow(exponent.0.into_bigint()))
294 }
295
296 fn max_num_bits() -> u32 {
302 F::MODULUS_BIT_SIZE
303 }
304
305 fn max_num_bytes() -> u32 {
310 let num_bytes = Self::max_num_bits() / 8;
311 if Self::max_num_bits() % 8 == 0 { num_bytes } else { num_bytes + 1 }
312 }
313
314 fn modulus() -> BigUint {
315 F::MODULUS.into()
316 }
317
318 fn num_bits(&self) -> u32 {
320 let mut bit_counter = BitCounter::default();
321 self.0.serialize_uncompressed(&mut bit_counter).unwrap();
322 bit_counter.bits()
323 }
324
325 fn to_u128(self) -> u128 {
326 if !self.fits_in_u128() {
327 panic!("field element too large for u128");
328 }
329 let as_bigint = self.0.into_bigint();
330 let limbs = as_bigint.as_ref();
331
332 let mut result = u128::from(limbs[0]);
333 if limbs.len() > 1 {
334 let high_limb = u128::from(limbs[1]);
335 result += high_limb << 64;
336 }
337
338 result
339 }
340
341 fn try_into_u128(self) -> Option<u128> {
342 self.fits_in_u128().then(|| self.to_u128())
343 }
344
345 fn to_i128(self) -> i128 {
346 if !self.fits_in_i128() {
347 panic!("field element too large for i128");
348 }
349 if self.neg().num_bits() < self.num_bits() {
353 let bytes = self.neg().to_be_bytes();
354 i128::from_be_bytes(bytes[16..32].try_into().unwrap()).neg()
355 } else {
356 let bytes = self.to_be_bytes();
357 i128::from_be_bytes(bytes[16..32].try_into().unwrap())
358 }
359 }
360
361 fn try_into_i128(self) -> Option<i128> {
362 self.fits_in_i128().then(|| self.to_i128())
363 }
364
365 fn try_to_u64(&self) -> Option<u64> {
366 (self.num_bits() <= 64).then(|| self.to_u128() as u64)
367 }
368
369 fn try_to_u32(&self) -> Option<u32> {
370 (self.num_bits() <= 32).then(|| self.to_u128() as u32)
371 }
372
373 fn inverse(&self) -> FieldElement<F> {
376 let inv = self.0.inverse().unwrap_or_else(F::zero);
377 FieldElement(inv)
378 }
379
380 fn to_hex(self) -> String {
381 let bytes = self.to_be_bytes();
382 hex::encode(bytes)
383 }
384
385 fn to_short_hex(self) -> String {
386 if self.is_zero() {
387 return "0x00".to_owned();
388 }
389
390 let bytes = self.to_be_bytes();
392
393 let first_nonzero = bytes.iter().position(|&b| b != 0).unwrap_or(bytes.len());
395 let trimmed = &bytes[first_nonzero..];
396
397 let mut result = String::with_capacity(2 + trimmed.len() * 2);
400 result.push_str("0x");
401
402 use std::fmt::Write;
404 write!(&mut result, "{:x}", trimmed[0]).unwrap();
405
406 if !result.len().is_multiple_of(2) {
408 result.insert(2, '0');
410 }
411
412 for byte in &trimmed[1..] {
414 write!(&mut result, "{byte:02x}").unwrap();
415 }
416
417 result
418 }
419
420 fn from_hex(hex_str: &str) -> Option<FieldElement<F>> {
421 let value = hex_str.strip_prefix("0x").unwrap_or(hex_str);
422
423 let hex_as_bytes = if value.len().is_multiple_of(2) {
425 hex::decode(value).ok()?
426 } else {
427 let mut padded = String::with_capacity(value.len() + 1);
429 padded.push('0');
430 padded.push_str(value);
431 hex::decode(padded).ok()?
432 };
433
434 Some(FieldElement::from_be_bytes_reduce(&hex_as_bytes))
435 }
436
437 fn to_be_bytes(self) -> Vec<u8> {
438 let mut bytes = self.to_le_bytes();
439 bytes.reverse();
440 bytes
441 }
442
443 fn to_le_bytes(self) -> Vec<u8> {
445 let mut bytes = Vec::new();
446 self.0.serialize_uncompressed(&mut bytes).unwrap();
447 bytes
448 }
449
450 fn from_be_bytes_reduce(bytes: &[u8]) -> FieldElement<F> {
453 FieldElement(F::from_be_bytes_mod_order(bytes))
454 }
455
456 fn from_le_bytes_reduce(bytes: &[u8]) -> FieldElement<F> {
459 FieldElement(F::from_le_bytes_mod_order(bytes))
460 }
461
462 fn fetch_nearest_bytes(&self, num_bits: usize) -> Vec<u8> {
465 fn nearest_bytes(num_bits: usize) -> usize {
466 num_bits.div_ceil(8) * 8
467 }
468
469 let num_bytes = nearest_bytes(num_bits);
470 let num_elements = num_bytes / 8;
471
472 let bytes = self.to_le_bytes();
473
474 bytes[0..num_elements].to_vec()
475 }
476}
477
478impl<F: PrimeField> Neg for FieldElement<F> {
479 type Output = FieldElement<F>;
480
481 fn neg(self) -> Self::Output {
482 FieldElement(-self.0)
483 }
484}
485
486impl<F: PrimeField> Mul for FieldElement<F> {
487 type Output = FieldElement<F>;
488 fn mul(mut self, rhs: FieldElement<F>) -> Self::Output {
489 self.0.mul_assign(&rhs.0);
490 FieldElement(self.0)
491 }
492}
493impl<F: PrimeField> Div for FieldElement<F> {
494 type Output = FieldElement<F>;
495 #[allow(clippy::suspicious_arithmetic_impl)]
496 fn div(self, rhs: FieldElement<F>) -> Self::Output {
497 self * rhs.inverse()
498 }
499}
500impl<F: PrimeField> Add for FieldElement<F> {
501 type Output = FieldElement<F>;
502 fn add(mut self, rhs: FieldElement<F>) -> Self::Output {
503 self.add_assign(rhs);
504 FieldElement(self.0)
505 }
506}
507impl<F: PrimeField> AddAssign for FieldElement<F> {
508 fn add_assign(&mut self, rhs: FieldElement<F>) {
509 self.0.add_assign(&rhs.0);
510 }
511}
512
513impl<F: PrimeField> Sub for FieldElement<F> {
514 type Output = FieldElement<F>;
515 fn sub(mut self, rhs: FieldElement<F>) -> Self::Output {
516 self.sub_assign(rhs);
517 FieldElement(self.0)
518 }
519}
520impl<F: PrimeField> SubAssign for FieldElement<F> {
521 fn sub_assign(&mut self, rhs: FieldElement<F>) {
522 self.0.sub_assign(&rhs.0);
523 }
524}
525
526#[derive(Default, Debug)]
527struct BitCounter {
528 count: usize,
530 total: usize,
532 head_byte: u8,
534}
535
536impl BitCounter {
537 fn bits(&self) -> u32 {
538 if self.count == 0 {
541 return 0;
542 }
543
544 let num_bits_for_head_byte = self.head_byte.ilog2();
545
546 let tail_length = (self.count - 1) as u32;
551 8 * tail_length + num_bits_for_head_byte + 1
552 }
553}
554
555impl Write for BitCounter {
556 fn write(&mut self, buf: &[u8]) -> ark_std::io::Result<usize> {
557 for byte in buf {
558 self.total += 1;
559 if *byte != 0 {
560 self.count = self.total;
561 self.head_byte = *byte;
562 }
563 }
564 Ok(buf.len())
565 }
566
567 fn flush(&mut self) -> ark_std::io::Result<()> {
568 Ok(())
569 }
570}
571
572#[cfg(test)]
573mod tests {
574 use super::{AcirField, FieldElement};
575 use proptest::prelude::*;
576 use std::ops::Neg;
577
578 #[test]
579 fn requires_zero_bit_to_hold_zero() {
580 let field = FieldElement::<ark_bn254::Fr>::zero();
581 assert_eq!(field.num_bits(), 0);
582 }
583
584 #[test]
585 fn requires_one_bit_to_hold_one() {
586 let field = FieldElement::<ark_bn254::Fr>::one();
587 assert_eq!(field.num_bits(), 1);
588 }
589
590 proptest! {
591 #[test]
592 fn num_bits_agrees_with_ilog2(num in 1u128..) {
593 let field = FieldElement::<ark_bn254::Fr>::from(num);
594 prop_assert_eq!(field.num_bits(), num.ilog2() + 1);
595 }
596 }
597
598 #[test]
599 fn test_fits_in_u128() {
600 let field = FieldElement::<ark_bn254::Fr>::from(u128::MAX);
601 assert_eq!(field.num_bits(), 128);
602 assert!(field.fits_in_u128());
603 let big_field = field + FieldElement::one();
604 assert_eq!(big_field.num_bits(), 129);
605 assert!(!big_field.fits_in_u128());
606 }
607
608 #[test]
609 fn test_to_u128_basic() {
610 type F = FieldElement<ark_bn254::Fr>;
611
612 assert_eq!(F::zero().to_u128(), 0);
614
615 assert_eq!(F::from(1_u128).to_u128(), 1);
617 assert_eq!(F::from(42_u128).to_u128(), 42);
618 assert_eq!(F::from(1000_u128).to_u128(), 1000);
619
620 assert_eq!(F::from(u128::MAX).to_u128(), u128::MAX);
622
623 assert_eq!(F::from(1_u128 << 127).to_u128(), 1_u128 << 127);
625 assert_eq!(F::from((1_u128 << 127) - 1).to_u128(), (1_u128 << 127) - 1);
626 }
627
628 #[test]
629 #[should_panic(expected = "field element too large for u128")]
630 fn test_to_u128_panics_on_overflow() {
631 type F = FieldElement<ark_bn254::Fr>;
632
633 let too_large = F::from(u128::MAX) + F::one();
635 too_large.to_u128(); }
637
638 #[test]
639 fn test_try_into_u128() {
640 type F = FieldElement<ark_bn254::Fr>;
641
642 assert_eq!(F::zero().try_into_u128(), Some(0));
644 assert_eq!(F::from(42_u128).try_into_u128(), Some(42));
645 assert_eq!(F::from(u128::MAX).try_into_u128(), Some(u128::MAX));
646
647 let too_large = F::from(u128::MAX) + F::one();
649 assert_eq!(too_large.try_into_u128(), None);
650 }
651
652 #[test]
653 fn test_fits_in_i128() {
654 type F = FieldElement<ark_bn254::Fr>;
655
656 assert!(F::zero().fits_in_i128());
658 assert!(F::from(1_i128).fits_in_i128());
659 assert!(F::from(42_i128).fits_in_i128());
660 assert!(F::from(i128::MAX).fits_in_i128());
661
662 assert!(F::from(-1_i128).fits_in_i128());
664 assert!(F::from(-42_i128).fits_in_i128());
665 assert!(F::from(i128::MIN + 1).fits_in_i128());
666
667 assert!(F::from((1_u128 << 127) - 1).fits_in_i128());
669
670 assert!(!F::from(1_u128 << 127).fits_in_i128());
674 assert!(!F::from(i128::MIN).fits_in_i128());
675
676 let too_large = F::from(u128::MAX);
678 assert!(!too_large.fits_in_i128());
679 }
680
681 #[test]
682 fn test_to_i128_positive() {
683 type F = FieldElement<ark_bn254::Fr>;
684
685 assert_eq!(F::zero().to_i128(), 0);
687 assert_eq!(F::from(1_i128).to_i128(), 1);
688 assert_eq!(F::from(42_i128).to_i128(), 42);
689 assert_eq!(F::from(1000_i128).to_i128(), 1000);
690 assert_eq!(F::from(i128::MAX).to_i128(), i128::MAX);
691 }
692
693 #[test]
694 fn test_to_i128_negative() {
695 type F = FieldElement<ark_bn254::Fr>;
696
697 assert_eq!(F::from(-1_i128).to_i128(), -1);
699 assert_eq!(F::from(-42_i128).to_i128(), -42);
700 assert_eq!(F::from(-1000_i128).to_i128(), -1000);
701
702 assert_eq!(F::from(-i128::MAX).to_i128(), -i128::MAX);
704 assert_eq!(F::from(i128::MIN + 1).to_i128(), i128::MIN + 1);
705
706 }
708
709 #[test]
710 fn test_to_i128_roundtrip() {
711 type F = FieldElement<ark_bn254::Fr>;
712
713 let test_values =
716 vec![0_i128, 1, -1, 42, -42, i128::MAX, i128::MAX - 1, i128::MIN + 1, -i128::MAX];
717
718 for value in test_values {
719 let field = F::from(value);
720 assert!(field.fits_in_i128(), "Value {value} should fit in i128");
721 assert_eq!(field.to_i128(), value, "Roundtrip failed for {value}");
722 }
723 }
724
725 #[test]
726 #[should_panic(expected = "field element too large for i128")]
727 fn test_to_i128_panics_on_positive_overflow() {
728 type F = FieldElement<ark_bn254::Fr>;
729
730 let too_large = F::from(1_u128 << 127);
732 too_large.to_i128(); }
734
735 #[test]
736 #[should_panic(expected = "field element too large for i128")]
737 fn test_to_i128_panics_on_large_value() {
738 type F = FieldElement<ark_bn254::Fr>;
739
740 let too_large = F::from(u128::MAX);
742 too_large.to_i128(); }
744
745 #[test]
746 fn test_try_into_i128() {
747 type F = FieldElement<ark_bn254::Fr>;
748
749 assert_eq!(F::zero().try_into_i128(), Some(0));
751 assert_eq!(F::from(42_i128).try_into_i128(), Some(42));
752 assert_eq!(F::from(i128::MAX).try_into_i128(), Some(i128::MAX));
753 assert_eq!(F::from(-i128::MAX).try_into_i128(), Some(-i128::MAX));
754
755 assert_eq!(F::from(-1_i128).try_into_i128(), Some(-1));
757 assert_eq!(F::from(-42_i128).try_into_i128(), Some(-42));
758 assert_eq!(F::from(i128::MIN + 1).try_into_i128(), Some(i128::MIN + 1));
759 assert_eq!(F::from(i128::MAX - 1).try_into_i128(), Some(i128::MAX - 1));
760 assert_eq!(F::from(1_i128 << 126).try_into_i128(), Some(1_i128 << 126));
761 assert_eq!(F::from(-((1_i128 << 126) - 1)).try_into_i128(), Some(-((1_i128 << 126) - 1)));
762 assert_eq!(F::from(1_u128 << 127).try_into_i128(), None);
764 assert_eq!(F::from(u128::MAX).try_into_i128(), None);
765 assert_eq!(F::from(i128::MIN).try_into_i128(), None);
767 assert_eq!(F::from((1_u128 << 127) + 1).try_into_i128(), None);
769 assert_eq!(F::from((1_u128 << 127) + 1000).try_into_i128(), None);
770 assert_eq!(F::from(1_u128 << 127).neg().try_into_i128(), None);
771 assert_eq!(F::from((1_u128 << 127) + 1).neg().try_into_i128(), None);
772 assert_eq!(F::from((1_u128 << 127) + 100).try_into_i128(), None);
773 assert_eq!(F::from((1_u128 << 127) + 100).neg().try_into_i128(), None);
774 }
775
776 #[test]
777 fn serialize_fixed_test_vectors() {
778 let hex_strings = vec![
780 "0000000000000000000000000000000000000000000000000000000000000000",
781 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000",
782 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff",
783 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffffe",
784 ];
785
786 for (i, string) in hex_strings.into_iter().enumerate() {
787 let minus_i_field_element = -FieldElement::<ark_bn254::Fr>::from(i as i128);
788 assert_eq!(minus_i_field_element.to_hex(), string);
789 }
790 }
791
792 #[test]
793 fn max_num_bits_smoke() {
794 let max_num_bits_bn254 = FieldElement::<ark_bn254::Fr>::max_num_bits();
795 assert_eq!(max_num_bits_bn254, 254);
796 }
797
798 proptest! {
799 #[test]
800 fn test_endianness_prop(value in any::<u64>()) {
801 let field = FieldElement::<ark_bn254::Fr>::from(value);
802 let le_bytes = field.to_le_bytes();
804 let be_bytes = field.to_be_bytes();
805
806 let mut reversed_le = le_bytes.clone();
807 reversed_le.reverse();
808 prop_assert_eq!(&be_bytes, &reversed_le, "BE bytes should be reverse of LE bytes");
809
810 let from_le = FieldElement::from_le_bytes_reduce(&le_bytes);
812 let from_be = FieldElement::from_be_bytes_reduce(&be_bytes);
813 prop_assert_eq!(from_le, from_be, "Deserialization should be consistent between LE and BE");
814 prop_assert_eq!(from_le, field, "Deserialized value should match original");
815 }
816 }
817
818 #[test]
819 fn test_endianness() {
820 let field = FieldElement::<ark_bn254::Fr>::from(0x1234_5678_u32);
821 let le_bytes = field.to_le_bytes();
822 let be_bytes = field.to_be_bytes();
823
824 let mut reversed_le = le_bytes.clone();
826 reversed_le.reverse();
827 assert_eq!(&be_bytes, &reversed_le);
828
829 let from_le = FieldElement::from_le_bytes_reduce(&le_bytes);
831 let from_be = FieldElement::from_be_bytes_reduce(&be_bytes);
832 assert_eq!(from_le, from_be);
833 assert_eq!(from_le, field);
834
835 let large_field = FieldElement::<ark_bn254::Fr>::from(0x0123_4567_89AB_CDEF_u64); let large_le = large_field.to_le_bytes();
838 let reconstructed = FieldElement::from_le_bytes_reduce(&large_le);
839 assert_eq!(reconstructed, large_field);
840 }
841
842 proptest! {
843 #[test]
846 #[should_panic(expected = "serialized field element is not equal to input")]
847 fn recovers_original_hex_string(hex in "[0-9a-f]{64}") {
848 let fe: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&hex).expect("should accept any 32 byte hex string");
849 let output_hex = fe.to_hex();
850
851 prop_assert_eq!(hex, output_hex, "serialized field element is not equal to input");
852 }
853
854 #[test]
855 fn accepts_odd_length_hex_strings(hex in "(?:0x)[0-9a-fA-F]+") {
856 let insert_index = if hex.starts_with("0x") { 2 } else { 0 };
859 let mut opposite_parity_string = hex.clone();
860 opposite_parity_string.insert(insert_index, '0');
861
862 let fe_1: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&hex).unwrap();
863 let fe_2: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&opposite_parity_string).unwrap();
864
865 prop_assert_eq!(fe_1, fe_2, "equivalent hex strings with opposite parity deserialized to different values");
866 }
867 }
868
869 #[test]
870 fn test_to_hex() {
871 type F = FieldElement<ark_bn254::Fr>;
872 assert_eq!(
873 F::zero().to_hex(),
874 "0000000000000000000000000000000000000000000000000000000000000000"
875 );
876 assert_eq!(
877 F::one().to_hex(),
878 "0000000000000000000000000000000000000000000000000000000000000001"
879 );
880 assert_eq!(
881 F::from(0x123_u128).to_hex(),
882 "0000000000000000000000000000000000000000000000000000000000000123"
883 );
884 assert_eq!(
885 F::from(0x1234_u128).to_hex(),
886 "0000000000000000000000000000000000000000000000000000000000001234"
887 );
888 }
889
890 #[test]
891 fn test_to_short_hex() {
892 type F = FieldElement<ark_bn254::Fr>;
893 assert_eq!(F::zero().to_short_hex(), "0x00");
894 assert_eq!(F::one().to_short_hex(), "0x01");
895 assert_eq!(F::from(0x123_u128).to_short_hex(), "0x0123");
896 assert_eq!(F::from(0x1234_u128).to_short_hex(), "0x1234");
897 }
898
899 #[test]
900 fn to_string_as_signed_integer() {
901 type F = FieldElement<ark_bn254::Fr>;
902 assert_eq!(F::zero().to_string_as_signed_integer(8), "0");
903 assert_eq!(F::one().to_string_as_signed_integer(8), "1");
904 assert_eq!(F::from(127_u128).to_string_as_signed_integer(8), "127");
905 assert_eq!(F::from(128_u128).to_string_as_signed_integer(8), "-128");
906 assert_eq!(F::from(129_u128).to_string_as_signed_integer(8), "-127");
907 assert_eq!(F::from(255_u128).to_string_as_signed_integer(8), "-1");
908 assert_eq!(F::from(32767_u128).to_string_as_signed_integer(16), "32767");
909 assert_eq!(F::from(32768_u128).to_string_as_signed_integer(16), "-32768");
910 assert_eq!(F::from(65535_u128).to_string_as_signed_integer(16), "-1");
911 }
912}