use {
crate::FieldElement,
ark_ff::{BigInt, BitIteratorLE, PrimeField},
itertools::Itertools,
serde::{Deserialize, Serialize},
};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct DigitalDecompositionWitnesses {
pub log_bases: Vec<usize>,
pub num_witnesses_to_decompose: usize,
pub witnesses_to_decompose: Vec<usize>,
pub first_witness_idx: usize,
pub num_witnesses: usize,
}
pub fn decompose_into_digits(value: FieldElement, log_bases: &[usize]) -> Vec<FieldElement> {
let num_digits = log_bases.len();
let mut digits = Vec::with_capacity(num_digits);
let mut value_bits = field_to_le_bits(value);
let ref_value_bits = &mut value_bits;
for &log_base in log_bases {
let digit_bits = ref_value_bits.take(log_base);
digits.push(le_bits_to_field(digit_bits))
}
let mut remaining_bits = value_bits;
assert!(
remaining_bits.all(|bit| !bit),
"Higher order bits are not zero"
);
digits
}
fn field_to_le_bits(value: FieldElement) -> BitIteratorLE<BigInt<4>> {
BitIteratorLE::new(value.into_bigint())
}
fn le_bits_to_field<I>(bits: I) -> FieldElement
where
I: Iterator<Item = bool>,
{
const LEN: usize = size_of::<<FieldElement as PrimeField>::BigInt>();
let mut le_bytes = [0; LEN];
for (i, chunk_in_bits) in bits.chunks(8).into_iter().take(LEN).enumerate() {
le_bytes[i] = chunk_in_bits
.into_iter()
.enumerate()
.fold(0u8, |acc, (i, bit)| acc | ((bit as u8) << i))
}
FieldElement::from_le_bytes_mod_order(&le_bytes)
}
#[cfg(test)]
#[test]
fn test_decompose_into_digits() {
let value = FieldElement::from(3 + 2u32 * 256 + 256 * 256);
let log_bases = vec![8, 8, 4];
let digits = decompose_into_digits(value, &log_bases);
assert_eq!(digits.len(), log_bases.len());
assert_eq!(digits[0], FieldElement::from(3u32));
assert_eq!(digits[1], FieldElement::from(2u32));
assert_eq!(digits[2], FieldElement::from(1u32));
}
#[cfg(test)]
#[test]
fn test_field_to_le_bits() {
let value = FieldElement::from(5u32);
let bits: Vec<bool> = field_to_le_bits(value).collect();
assert_eq!(bits.len(), 256);
assert!(bits[0]);
assert!(!bits[1]);
assert!(bits[2]);
assert!(!bits[254]);
assert!(!bits[255]);
}
#[cfg(test)]
#[test]
fn test_le_bits_to_field() {
let bits = vec![true, false, true, false, false];
let value = le_bits_to_field(bits.into_iter().take(64));
assert_eq!(value.into_bigint().0[0], 5);
}