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<T: PrimeField> Serialize for FieldElement<T> {
66 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
67 where
68 S: serde::Serializer,
69 {
70 self.to_be_bytes().serialize(serializer)
71 }
72}
73
74impl<'de, T: PrimeField> Deserialize<'de> for FieldElement<T> {
75 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
76 where
77 D: serde::Deserializer<'de>,
78 {
79 let s: Cow<'de, [u8]> = Deserialize::deserialize(deserializer)?;
80 Ok(Self::from_be_bytes_reduce(&s))
81 }
82}
83
84impl<F: PrimeField> From<u128> for FieldElement<F> {
85 fn from(a: u128) -> FieldElement<F> {
86 FieldElement(F::from(a))
87 }
88}
89
90impl<F: PrimeField> From<usize> for FieldElement<F> {
91 fn from(a: usize) -> FieldElement<F> {
92 FieldElement::from(a as u64)
93 }
94}
95
96impl<F: PrimeField> From<u64> for FieldElement<F> {
97 fn from(a: u64) -> FieldElement<F> {
98 FieldElement(F::from(a))
99 }
100}
101
102impl<F: PrimeField> From<u32> for FieldElement<F> {
103 fn from(a: u32) -> FieldElement<F> {
104 FieldElement(F::from(a))
105 }
106}
107
108impl<F: PrimeField> From<bool> for FieldElement<F> {
109 fn from(boolean: bool) -> FieldElement<F> {
110 if boolean { FieldElement::one() } else { FieldElement::zero() }
111 }
112}
113
114impl<F: PrimeField> FieldElement<F> {
115 pub fn from_repr(field: F) -> Self {
119 Self(field)
120 }
121
122 pub fn into_repr(self) -> F {
126 self.0
127 }
128
129 pub fn fits_in_u128(&self) -> bool {
134 self.num_bits() <= 128
135 }
136
137 pub fn fits_in_i128(&self) -> bool {
144 let num_bits = u32::min(self.neg().num_bits(), self.num_bits());
145 num_bits <= 127 && self != &FieldElement::from(I128_SIGN_BOUNDARY)
146 }
147
148 pub fn try_from_str(input: &str) -> Option<FieldElement<F>> {
153 if input.contains('x') {
154 return FieldElement::from_hex(input);
155 }
156
157 let fr = F::from_str(input).ok()?;
158 Some(FieldElement(fr))
159 }
160
161 pub fn to_string_as_signed_integer(self, bit_size: u32) -> String {
169 assert!(bit_size <= 128);
170 if self.num_bits() > bit_size {
171 return self.to_string();
172 }
173
174 let max = if bit_size == 128 { i128::MAX as u128 } else { (1 << (bit_size - 1)) - 1 };
176 if self.to_u128() > max {
177 let f = FieldElement::from(2u32).pow(&bit_size.into()) - self;
178 format!("-{f}")
179 } else {
180 self.to_string()
181 }
182 }
183}
184
185impl<F: PrimeField> AcirField for FieldElement<F> {
186 fn one() -> FieldElement<F> {
187 FieldElement(F::one())
188 }
189 fn zero() -> FieldElement<F> {
190 FieldElement(F::zero())
191 }
192
193 fn is_zero(&self) -> bool {
194 self == &Self::zero()
195 }
196 fn is_one(&self) -> bool {
197 self == &Self::one()
198 }
199
200 fn pow(&self, exponent: &Self) -> Self {
201 FieldElement(self.0.pow(exponent.0.into_bigint()))
202 }
203
204 fn max_num_bits() -> u32 {
210 F::MODULUS_BIT_SIZE
211 }
212
213 fn max_num_bytes() -> u32 {
218 let num_bytes = Self::max_num_bits() / 8;
219 if Self::max_num_bits() % 8 == 0 { num_bytes } else { num_bytes + 1 }
220 }
221
222 fn modulus() -> BigUint {
223 F::MODULUS.into()
224 }
225
226 fn num_bits(&self) -> u32 {
228 let mut bit_counter = BitCounter::default();
229 self.0.serialize_uncompressed(&mut bit_counter).unwrap();
230 bit_counter.bits()
231 }
232
233 fn to_u128(self) -> u128 {
234 if !self.fits_in_u128() {
235 panic!("field element too large for u128");
236 }
237 let as_bigint = self.0.into_bigint();
238 let limbs = as_bigint.as_ref();
239
240 let mut result = u128::from(limbs[0]);
241 if limbs.len() > 1 {
242 let high_limb = u128::from(limbs[1]);
243 result += high_limb << 64;
244 }
245
246 result
247 }
248
249 fn try_into_u128(self) -> Option<u128> {
250 self.fits_in_u128().then(|| self.to_u128())
251 }
252
253 fn to_i128(self) -> i128 {
254 if !self.fits_in_i128() {
255 panic!("field element too large for i128");
256 }
257 if self.neg().num_bits() < self.num_bits() {
261 let bytes = self.neg().to_be_bytes();
262 i128::from_be_bytes(bytes[16..32].try_into().unwrap()).neg()
263 } else {
264 let bytes = self.to_be_bytes();
265 i128::from_be_bytes(bytes[16..32].try_into().unwrap())
266 }
267 }
268
269 fn try_into_i128(self) -> Option<i128> {
270 self.fits_in_i128().then(|| self.to_i128())
271 }
272
273 fn try_to_u64(&self) -> Option<u64> {
274 (self.num_bits() <= 64).then(|| self.to_u128() as u64)
275 }
276
277 fn try_to_u32(&self) -> Option<u32> {
278 (self.num_bits() <= 32).then(|| self.to_u128() as u32)
279 }
280
281 fn inverse(&self) -> FieldElement<F> {
284 let inv = self.0.inverse().unwrap_or_else(F::zero);
285 FieldElement(inv)
286 }
287
288 fn to_hex(self) -> String {
289 let bytes = self.to_be_bytes();
290 hex::encode(bytes)
291 }
292
293 fn to_short_hex(self) -> String {
294 if self.is_zero() {
295 return "0x00".to_owned();
296 }
297
298 let bytes = self.to_be_bytes();
300
301 let first_nonzero = bytes.iter().position(|&b| b != 0).unwrap_or(bytes.len());
303 let trimmed = &bytes[first_nonzero..];
304
305 let mut result = String::with_capacity(2 + trimmed.len() * 2);
308 result.push_str("0x");
309
310 use std::fmt::Write;
312 write!(&mut result, "{:x}", trimmed[0]).unwrap();
313
314 if !result.len().is_multiple_of(2) {
316 result.insert(2, '0');
318 }
319
320 for byte in &trimmed[1..] {
322 write!(&mut result, "{byte:02x}").unwrap();
323 }
324
325 result
326 }
327
328 fn from_hex(hex_str: &str) -> Option<FieldElement<F>> {
329 let value = hex_str.strip_prefix("0x").unwrap_or(hex_str);
330
331 let hex_as_bytes = if value.len().is_multiple_of(2) {
333 hex::decode(value).ok()?
334 } else {
335 let mut padded = String::with_capacity(value.len() + 1);
337 padded.push('0');
338 padded.push_str(value);
339 hex::decode(padded).ok()?
340 };
341
342 Some(FieldElement::from_be_bytes_reduce(&hex_as_bytes))
343 }
344
345 fn to_be_bytes(self) -> Vec<u8> {
346 let mut bytes = self.to_le_bytes();
347 bytes.reverse();
348 bytes
349 }
350
351 fn to_le_bytes(self) -> Vec<u8> {
353 let mut bytes = Vec::new();
354 self.0.serialize_uncompressed(&mut bytes).unwrap();
355 bytes
356 }
357
358 fn from_be_bytes_reduce(bytes: &[u8]) -> FieldElement<F> {
361 FieldElement(F::from_be_bytes_mod_order(bytes))
362 }
363
364 fn from_le_bytes_reduce(bytes: &[u8]) -> FieldElement<F> {
367 FieldElement(F::from_le_bytes_mod_order(bytes))
368 }
369
370 fn fetch_nearest_bytes(&self, num_bits: usize) -> Vec<u8> {
373 fn nearest_bytes(num_bits: usize) -> usize {
374 num_bits.div_ceil(8) * 8
375 }
376
377 let num_bytes = nearest_bytes(num_bits);
378 let num_elements = num_bytes / 8;
379
380 let bytes = self.to_le_bytes();
381
382 bytes[0..num_elements].to_vec()
383 }
384}
385
386impl<F: PrimeField> Neg for FieldElement<F> {
387 type Output = FieldElement<F>;
388
389 fn neg(self) -> Self::Output {
390 FieldElement(-self.0)
391 }
392}
393
394impl<F: PrimeField> Mul for FieldElement<F> {
395 type Output = FieldElement<F>;
396 fn mul(mut self, rhs: FieldElement<F>) -> Self::Output {
397 self.0.mul_assign(&rhs.0);
398 FieldElement(self.0)
399 }
400}
401impl<F: PrimeField> Div for FieldElement<F> {
402 type Output = FieldElement<F>;
403 #[allow(clippy::suspicious_arithmetic_impl)]
404 fn div(self, rhs: FieldElement<F>) -> Self::Output {
405 self * rhs.inverse()
406 }
407}
408impl<F: PrimeField> Add for FieldElement<F> {
409 type Output = FieldElement<F>;
410 fn add(mut self, rhs: FieldElement<F>) -> Self::Output {
411 self.add_assign(rhs);
412 FieldElement(self.0)
413 }
414}
415impl<F: PrimeField> AddAssign for FieldElement<F> {
416 fn add_assign(&mut self, rhs: FieldElement<F>) {
417 self.0.add_assign(&rhs.0);
418 }
419}
420
421impl<F: PrimeField> Sub for FieldElement<F> {
422 type Output = FieldElement<F>;
423 fn sub(mut self, rhs: FieldElement<F>) -> Self::Output {
424 self.sub_assign(rhs);
425 FieldElement(self.0)
426 }
427}
428impl<F: PrimeField> SubAssign for FieldElement<F> {
429 fn sub_assign(&mut self, rhs: FieldElement<F>) {
430 self.0.sub_assign(&rhs.0);
431 }
432}
433
434#[derive(Default, Debug)]
435struct BitCounter {
436 count: usize,
438 total: usize,
440 head_byte: u8,
442}
443
444impl BitCounter {
445 fn bits(&self) -> u32 {
446 if self.count == 0 {
449 return 0;
450 }
451
452 let num_bits_for_head_byte = self.head_byte.ilog2();
453
454 let tail_length = (self.count - 1) as u32;
459 8 * tail_length + num_bits_for_head_byte + 1
460 }
461}
462
463impl Write for BitCounter {
464 fn write(&mut self, buf: &[u8]) -> ark_std::io::Result<usize> {
465 for byte in buf {
466 self.total += 1;
467 if *byte != 0 {
468 self.count = self.total;
469 self.head_byte = *byte;
470 }
471 }
472 Ok(buf.len())
473 }
474
475 fn flush(&mut self) -> ark_std::io::Result<()> {
476 Ok(())
477 }
478}
479
480#[cfg(test)]
481mod tests {
482 use super::{AcirField, FieldElement};
483 use proptest::prelude::*;
484 use std::ops::Neg;
485
486 #[test]
487 fn requires_zero_bit_to_hold_zero() {
488 let field = FieldElement::<ark_bn254::Fr>::zero();
489 assert_eq!(field.num_bits(), 0);
490 }
491
492 #[test]
493 fn requires_one_bit_to_hold_one() {
494 let field = FieldElement::<ark_bn254::Fr>::one();
495 assert_eq!(field.num_bits(), 1);
496 }
497
498 proptest! {
499 #[test]
500 fn num_bits_agrees_with_ilog2(num in 1u128..) {
501 let field = FieldElement::<ark_bn254::Fr>::from(num);
502 prop_assert_eq!(field.num_bits(), num.ilog2() + 1);
503 }
504 }
505
506 #[test]
507 fn test_fits_in_u128() {
508 let field = FieldElement::<ark_bn254::Fr>::from(u128::MAX);
509 assert_eq!(field.num_bits(), 128);
510 assert!(field.fits_in_u128());
511 let big_field = field + FieldElement::one();
512 assert_eq!(big_field.num_bits(), 129);
513 assert!(!big_field.fits_in_u128());
514 }
515
516 #[test]
517 fn test_to_u128_basic() {
518 type F = FieldElement<ark_bn254::Fr>;
519
520 assert_eq!(F::zero().to_u128(), 0);
522
523 assert_eq!(F::from(1_u128).to_u128(), 1);
525 assert_eq!(F::from(42_u128).to_u128(), 42);
526 assert_eq!(F::from(1000_u128).to_u128(), 1000);
527
528 assert_eq!(F::from(u128::MAX).to_u128(), u128::MAX);
530
531 assert_eq!(F::from(1_u128 << 127).to_u128(), 1_u128 << 127);
533 assert_eq!(F::from((1_u128 << 127) - 1).to_u128(), (1_u128 << 127) - 1);
534 }
535
536 #[test]
537 #[should_panic(expected = "field element too large for u128")]
538 fn test_to_u128_panics_on_overflow() {
539 type F = FieldElement<ark_bn254::Fr>;
540
541 let too_large = F::from(u128::MAX) + F::one();
543 too_large.to_u128(); }
545
546 #[test]
547 fn test_try_into_u128() {
548 type F = FieldElement<ark_bn254::Fr>;
549
550 assert_eq!(F::zero().try_into_u128(), Some(0));
552 assert_eq!(F::from(42_u128).try_into_u128(), Some(42));
553 assert_eq!(F::from(u128::MAX).try_into_u128(), Some(u128::MAX));
554
555 let too_large = F::from(u128::MAX) + F::one();
557 assert_eq!(too_large.try_into_u128(), None);
558 }
559
560 #[test]
561 fn test_fits_in_i128() {
562 type F = FieldElement<ark_bn254::Fr>;
563
564 assert!(F::zero().fits_in_i128());
566 assert!(F::from(1_i128).fits_in_i128());
567 assert!(F::from(42_i128).fits_in_i128());
568 assert!(F::from(i128::MAX).fits_in_i128());
569
570 assert!(F::from(-1_i128).fits_in_i128());
572 assert!(F::from(-42_i128).fits_in_i128());
573 assert!(F::from(i128::MIN + 1).fits_in_i128());
574
575 assert!(F::from((1_u128 << 127) - 1).fits_in_i128());
577
578 assert!(!F::from(1_u128 << 127).fits_in_i128());
582 assert!(!F::from(i128::MIN).fits_in_i128());
583
584 let too_large = F::from(u128::MAX);
586 assert!(!too_large.fits_in_i128());
587 }
588
589 #[test]
590 fn test_to_i128_positive() {
591 type F = FieldElement<ark_bn254::Fr>;
592
593 assert_eq!(F::zero().to_i128(), 0);
595 assert_eq!(F::from(1_i128).to_i128(), 1);
596 assert_eq!(F::from(42_i128).to_i128(), 42);
597 assert_eq!(F::from(1000_i128).to_i128(), 1000);
598 assert_eq!(F::from(i128::MAX).to_i128(), i128::MAX);
599 }
600
601 #[test]
602 fn test_to_i128_negative() {
603 type F = FieldElement<ark_bn254::Fr>;
604
605 assert_eq!(F::from(-1_i128).to_i128(), -1);
607 assert_eq!(F::from(-42_i128).to_i128(), -42);
608 assert_eq!(F::from(-1000_i128).to_i128(), -1000);
609
610 assert_eq!(F::from(-i128::MAX).to_i128(), -i128::MAX);
612 assert_eq!(F::from(i128::MIN + 1).to_i128(), i128::MIN + 1);
613
614 }
616
617 #[test]
618 fn test_to_i128_roundtrip() {
619 type F = FieldElement<ark_bn254::Fr>;
620
621 let test_values =
624 vec![0_i128, 1, -1, 42, -42, i128::MAX, i128::MAX - 1, i128::MIN + 1, -i128::MAX];
625
626 for value in test_values {
627 let field = F::from(value);
628 assert!(field.fits_in_i128(), "Value {value} should fit in i128");
629 assert_eq!(field.to_i128(), value, "Roundtrip failed for {value}");
630 }
631 }
632
633 #[test]
634 #[should_panic(expected = "field element too large for i128")]
635 fn test_to_i128_panics_on_positive_overflow() {
636 type F = FieldElement<ark_bn254::Fr>;
637
638 let too_large = F::from(1_u128 << 127);
640 too_large.to_i128(); }
642
643 #[test]
644 #[should_panic(expected = "field element too large for i128")]
645 fn test_to_i128_panics_on_large_value() {
646 type F = FieldElement<ark_bn254::Fr>;
647
648 let too_large = F::from(u128::MAX);
650 too_large.to_i128(); }
652
653 #[test]
654 fn test_try_into_i128() {
655 type F = FieldElement<ark_bn254::Fr>;
656
657 assert_eq!(F::zero().try_into_i128(), Some(0));
659 assert_eq!(F::from(42_i128).try_into_i128(), Some(42));
660 assert_eq!(F::from(i128::MAX).try_into_i128(), Some(i128::MAX));
661 assert_eq!(F::from(-i128::MAX).try_into_i128(), Some(-i128::MAX));
662
663 assert_eq!(F::from(-1_i128).try_into_i128(), Some(-1));
665 assert_eq!(F::from(-42_i128).try_into_i128(), Some(-42));
666 assert_eq!(F::from(i128::MIN + 1).try_into_i128(), Some(i128::MIN + 1));
667 assert_eq!(F::from(i128::MAX - 1).try_into_i128(), Some(i128::MAX - 1));
668 assert_eq!(F::from(1_i128 << 126).try_into_i128(), Some(1_i128 << 126));
669 assert_eq!(F::from(-((1_i128 << 126) - 1)).try_into_i128(), Some(-((1_i128 << 126) - 1)));
670 assert_eq!(F::from(1_u128 << 127).try_into_i128(), None);
672 assert_eq!(F::from(u128::MAX).try_into_i128(), None);
673 assert_eq!(F::from(i128::MIN).try_into_i128(), None);
675 assert_eq!(F::from((1_u128 << 127) + 1).try_into_i128(), None);
677 assert_eq!(F::from((1_u128 << 127) + 1000).try_into_i128(), None);
678 assert_eq!(F::from(1_u128 << 127).neg().try_into_i128(), None);
679 assert_eq!(F::from((1_u128 << 127) + 1).neg().try_into_i128(), None);
680 assert_eq!(F::from((1_u128 << 127) + 100).try_into_i128(), None);
681 assert_eq!(F::from((1_u128 << 127) + 100).neg().try_into_i128(), None);
682 }
683
684 #[test]
685 fn serialize_fixed_test_vectors() {
686 let hex_strings = vec![
688 "0000000000000000000000000000000000000000000000000000000000000000",
689 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000",
690 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593efffffff",
691 "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593effffffe",
692 ];
693
694 for (i, string) in hex_strings.into_iter().enumerate() {
695 let minus_i_field_element = -FieldElement::<ark_bn254::Fr>::from(i as i128);
696 assert_eq!(minus_i_field_element.to_hex(), string);
697 }
698 }
699
700 #[test]
701 fn max_num_bits_smoke() {
702 let max_num_bits_bn254 = FieldElement::<ark_bn254::Fr>::max_num_bits();
703 assert_eq!(max_num_bits_bn254, 254);
704 }
705
706 proptest! {
707 #[test]
708 fn test_endianness_prop(value in any::<u64>()) {
709 let field = FieldElement::<ark_bn254::Fr>::from(value);
710 let le_bytes = field.to_le_bytes();
712 let be_bytes = field.to_be_bytes();
713
714 let mut reversed_le = le_bytes.clone();
715 reversed_le.reverse();
716 prop_assert_eq!(&be_bytes, &reversed_le, "BE bytes should be reverse of LE bytes");
717
718 let from_le = FieldElement::from_le_bytes_reduce(&le_bytes);
720 let from_be = FieldElement::from_be_bytes_reduce(&be_bytes);
721 prop_assert_eq!(from_le, from_be, "Deserialization should be consistent between LE and BE");
722 prop_assert_eq!(from_le, field, "Deserialized value should match original");
723 }
724 }
725
726 #[test]
727 fn test_endianness() {
728 let field = FieldElement::<ark_bn254::Fr>::from(0x1234_5678_u32);
729 let le_bytes = field.to_le_bytes();
730 let be_bytes = field.to_be_bytes();
731
732 let mut reversed_le = le_bytes.clone();
734 reversed_le.reverse();
735 assert_eq!(&be_bytes, &reversed_le);
736
737 let from_le = FieldElement::from_le_bytes_reduce(&le_bytes);
739 let from_be = FieldElement::from_be_bytes_reduce(&be_bytes);
740 assert_eq!(from_le, from_be);
741 assert_eq!(from_le, field);
742
743 let large_field = FieldElement::<ark_bn254::Fr>::from(0x0123_4567_89AB_CDEF_u64); let large_le = large_field.to_le_bytes();
746 let reconstructed = FieldElement::from_le_bytes_reduce(&large_le);
747 assert_eq!(reconstructed, large_field);
748 }
749
750 proptest! {
751 #[test]
754 #[should_panic(expected = "serialized field element is not equal to input")]
755 fn recovers_original_hex_string(hex in "[0-9a-f]{64}") {
756 let fe: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&hex).expect("should accept any 32 byte hex string");
757 let output_hex = fe.to_hex();
758
759 prop_assert_eq!(hex, output_hex, "serialized field element is not equal to input");
760 }
761
762 #[test]
763 fn accepts_odd_length_hex_strings(hex in "(?:0x)[0-9a-fA-F]+") {
764 let insert_index = if hex.starts_with("0x") { 2 } else { 0 };
767 let mut opposite_parity_string = hex.to_string();
768 opposite_parity_string.insert(insert_index, '0');
769
770 let fe_1: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&hex).unwrap();
771 let fe_2: FieldElement::<ark_bn254::Fr> = FieldElement::from_hex(&opposite_parity_string).unwrap();
772
773 prop_assert_eq!(fe_1, fe_2, "equivalent hex strings with opposite parity deserialized to different values");
774 }
775 }
776
777 #[test]
778 fn test_to_hex() {
779 type F = FieldElement<ark_bn254::Fr>;
780 assert_eq!(
781 F::zero().to_hex(),
782 "0000000000000000000000000000000000000000000000000000000000000000"
783 );
784 assert_eq!(
785 F::one().to_hex(),
786 "0000000000000000000000000000000000000000000000000000000000000001"
787 );
788 assert_eq!(
789 F::from(0x123_u128).to_hex(),
790 "0000000000000000000000000000000000000000000000000000000000000123"
791 );
792 assert_eq!(
793 F::from(0x1234_u128).to_hex(),
794 "0000000000000000000000000000000000000000000000000000000000001234"
795 );
796 }
797
798 #[test]
799 fn test_to_short_hex() {
800 type F = FieldElement<ark_bn254::Fr>;
801 assert_eq!(F::zero().to_short_hex(), "0x00");
802 assert_eq!(F::one().to_short_hex(), "0x01");
803 assert_eq!(F::from(0x123_u128).to_short_hex(), "0x0123");
804 assert_eq!(F::from(0x1234_u128).to_short_hex(), "0x1234");
805 }
806
807 #[test]
808 fn to_string_as_signed_integer() {
809 type F = FieldElement<ark_bn254::Fr>;
810 assert_eq!(F::zero().to_string_as_signed_integer(8), "0");
811 assert_eq!(F::one().to_string_as_signed_integer(8), "1");
812 assert_eq!(F::from(127_u128).to_string_as_signed_integer(8), "127");
813 assert_eq!(F::from(128_u128).to_string_as_signed_integer(8), "-128");
814 assert_eq!(F::from(129_u128).to_string_as_signed_integer(8), "-127");
815 assert_eq!(F::from(255_u128).to_string_as_signed_integer(8), "-1");
816 assert_eq!(F::from(32767_u128).to_string_as_signed_integer(16), "32767");
817 assert_eq!(F::from(32768_u128).to_string_as_signed_integer(16), "-32768");
818 assert_eq!(F::from(65535_u128).to_string_as_signed_integer(16), "-1");
819 }
820}