/ console / types / integers / src / from_field.rs
from_field.rs
  1  // Copyright (c) 2025-2026 ACDC Network
  2  // This file is part of the alphavm library.
  3  //
  4  // Alpha Chain | Delta Chain Protocol
  5  // International Monetary Graphite.
  6  //
  7  // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com).
  8  // They built world-class ZK infrastructure. We installed the EASY button.
  9  // Their cryptography: elegant. Our modifications: bureaucracy-compatible.
 10  // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours.
 11  //
 12  // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0
 13  // All modifications and new work: CC0 1.0 Universal Public Domain Dedication.
 14  // No rights reserved. No permission required. No warranty. No refunds.
 15  //
 16  // https://creativecommons.org/publicdomain/zero/1.0/
 17  // SPDX-License-Identifier: CC0-1.0
 18  
 19  use super::*;
 20  
 21  impl<E: Environment, I: IntegerType> FromField for Integer<E, I> {
 22      type Field = Field<E>;
 23  
 24      /// Casts an integer from a base field.
 25      ///
 26      /// This method guarantees the following:
 27      ///   1. If the field element is larger than the integer domain, then the operation will fail.
 28      ///   2. If the field element is smaller than the integer domain, then the operation will succeed.
 29      fn from_field(field: &Self::Field) -> Result<Self> {
 30          // Note: We are reconstituting the integer from the base field.
 31          // This is safe as the number of bits in the integer is less than the base field modulus,
 32          // and thus will always fit within a single base field element.
 33          debug_assert!(I::BITS < Field::<E>::size_in_bits() as u64);
 34  
 35          // Convert the field element into bits.
 36          let bits_le = field.to_bits_le();
 37  
 38          // Extract the integer bits from the field element, **without** a carry bit.
 39          let (bits_le, zero_bits) = bits_le.split_at(Self::size_in_bits());
 40  
 41          // Ensure the unused upper bits are all zero.
 42          ensure!(zero_bits.iter().all(|&bit| !bit), "Failed to convert field to integer: upper bits are not zero");
 43  
 44          // Return the integer.
 45          Self::from_bits_le(bits_le)
 46      }
 47  }
 48  
 49  #[cfg(test)]
 50  mod tests {
 51      use super::*;
 52      use alphavm_console_network_environment::Console;
 53  
 54      type CurrentEnvironment = Console;
 55  
 56      const ITERATIONS: u64 = 10_000;
 57  
 58      fn check_from_field<I: IntegerType>() -> Result<()> {
 59          let mut rng = TestRng::default();
 60  
 61          for _ in 0..ITERATIONS {
 62              // Sample a random integer.
 63              let expected = Integer::<CurrentEnvironment, I>::rand(&mut rng);
 64  
 65              // Perform the operation.
 66              let candidate = Integer::from_field(&expected.to_field()?)?;
 67              assert_eq!(expected, candidate);
 68  
 69              // Sample a random field.
 70              let expected = Field::<CurrentEnvironment>::rand(&mut rng);
 71              // Determine the integer domain.
 72              let integer_max = match I::type_name() {
 73                  "u8" | "i8" => Field::<CurrentEnvironment>::from_u8(u8::MAX),
 74                  "u16" | "i16" => Field::<CurrentEnvironment>::from_u16(u16::MAX),
 75                  "u32" | "i32" => Field::<CurrentEnvironment>::from_u32(u32::MAX),
 76                  "u64" | "i64" => Field::<CurrentEnvironment>::from_u64(u64::MAX),
 77                  "u128" | "i128" => Field::<CurrentEnvironment>::from_u128(u128::MAX),
 78                  _ => panic!("Unsupported integer type."),
 79              };
 80              // Filter for field elements that exceed the integer domain.
 81              if expected > integer_max {
 82                  // Perform the operation.
 83                  assert!(Integer::<_, I>::from_field(&expected).is_err());
 84              } else {
 85                  // Perform the operation.
 86                  assert!(Integer::<_, I>::from_field(&expected).is_ok());
 87              }
 88          }
 89          Ok(())
 90      }
 91  
 92      #[test]
 93      fn test_u8_from_field() -> Result<()> {
 94          type I = u8;
 95          check_from_field::<I>()
 96      }
 97  
 98      #[test]
 99      fn test_i8_from_field() -> Result<()> {
100          type I = i8;
101          check_from_field::<I>()
102      }
103  
104      #[test]
105      fn test_u16_from_field() -> Result<()> {
106          type I = u16;
107          check_from_field::<I>()
108      }
109  
110      #[test]
111      fn test_i16_from_field() -> Result<()> {
112          type I = i16;
113          check_from_field::<I>()
114      }
115  
116      #[test]
117      fn test_u32_from_field() -> Result<()> {
118          type I = u32;
119          check_from_field::<I>()
120      }
121  
122      #[test]
123      fn test_i32_from_field() -> Result<()> {
124          type I = i32;
125          check_from_field::<I>()
126      }
127  
128      #[test]
129      fn test_u64_from_field() -> Result<()> {
130          type I = u64;
131          check_from_field::<I>()
132      }
133  
134      #[test]
135      fn test_i64_from_field() -> Result<()> {
136          type I = i64;
137          check_from_field::<I>()
138      }
139  
140      #[test]
141      fn test_u128_from_field() -> Result<()> {
142          type I = u128;
143          check_from_field::<I>()
144      }
145  
146      #[test]
147      fn test_i128_from_field() -> Result<()> {
148          type I = i128;
149          check_from_field::<I>()
150      }
151  }