use super::*;
use smallvec::{SmallVec, smallvec};
const MAX_FIELD_SIZE_IN_BITS: usize = 384;
impl<E: Environment> FromBits for Field<E> {
fn from_bits_le(bits_le: &[bool]) -> Result<Self> {
let size_in_data_bits = Field::<E>::size_in_data_bits();
let size_in_bits = Field::<E>::size_in_bits();
let num_bits = bits_le.len();
if num_bits > size_in_bits {
let should_be_zero = bits_le[size_in_bits..].iter().fold(false, |acc, bit| acc | bit);
ensure!(!should_be_zero, "The excess bits are not zero.");
}
if num_bits > size_in_data_bits {
let field = E::BigInteger::from_bits_le(&bits_le[..size_in_bits])?;
ensure!(field < E::Field::modulus(), "The field is greater than or equal to the modulus.");
Ok(Field { field: E::Field::from_bigint(field).ok_or_else(|| anyhow!("Invalid field from bits"))? })
} else {
let mut sanitized_bits: SmallVec<[bool; MAX_FIELD_SIZE_IN_BITS]> = smallvec![false; size_in_bits];
sanitized_bits[..num_bits].copy_from_slice(bits_le);
let field = E::Field::from_bigint(E::BigInteger::from_bits_le(&sanitized_bits)?)
.ok_or_else(|| anyhow!("Invalid field from bits"))?;
Ok(Field { field })
}
}
fn from_bits_be(bits_be: &[bool]) -> Result<Self> {
let mut bits_le = bits_be.to_vec();
bits_le.reverse();
Self::from_bits_le(&bits_le)
}
}
#[cfg(test)]
mod tests {
use super::*;
use snarkvm_console_network_environment::Console;
type CurrentEnvironment = Console;
const ITERATIONS: usize = 100;
fn check_from_bits_le() -> Result<()> {
let mut rng = TestRng::default();
for i in 0..ITERATIONS {
let expected: Field<CurrentEnvironment> = Uniform::rand(&mut rng);
let given_bits = expected.to_bits_le();
assert_eq!(Field::<CurrentEnvironment>::size_in_bits(), given_bits.len());
let candidate = Field::<CurrentEnvironment>::from_bits_le(&given_bits)?;
assert_eq!(expected, candidate);
let candidate = [given_bits, vec![false; i]].concat();
let candidate = Field::<CurrentEnvironment>::from_bits_le(&candidate)?;
assert_eq!(expected, candidate);
assert_eq!(Field::<CurrentEnvironment>::size_in_bits(), candidate.to_bits_le().len());
}
Ok(())
}
fn check_from_bits_be() -> Result<()> {
let mut rng = TestRng::default();
for i in 0..ITERATIONS {
let expected: Field<CurrentEnvironment> = Uniform::rand(&mut rng);
let given_bits = expected.to_bits_be();
assert_eq!(Field::<CurrentEnvironment>::size_in_bits(), given_bits.len());
let candidate = Field::<CurrentEnvironment>::from_bits_be(&given_bits)?;
assert_eq!(expected, candidate);
let candidate = [vec![false; i], given_bits].concat();
let candidate = Field::<CurrentEnvironment>::from_bits_be(&candidate)?;
assert_eq!(expected, candidate);
assert_eq!(Field::<CurrentEnvironment>::size_in_bits(), candidate.to_bits_be().len());
}
Ok(())
}
#[test]
fn test_from_bits_le() -> Result<()> {
check_from_bits_le()
}
#[test]
fn test_from_bits_be() -> Result<()> {
check_from_bits_be()
}
#[test]
fn test_size_in_bits_is_within_max() {
let size_in_bits = Field::<CurrentEnvironment>::size_in_bits();
assert!(
size_in_bits <= MAX_FIELD_SIZE_IN_BITS,
"MAX_FIELD_SIZE_IN_BITS ({MAX_FIELD_SIZE_IN_BITS}) must be at least the field size ({size_in_bits})"
);
}
}