use crate::PreparedEmbedding;
use crate::bits::{bytes_for, check_holds};
use crate::field::{BinaryField, FieldBuffer, PrimeCharacteristic, PrimeField};
use crate::kernel::gf1::{self, LaneTest};
#[inline]
fn check_lanes<T: FieldBuffer>(name: &str, operand: &str, len: usize, bits: usize) {
let Some(expected) = bits.checked_mul(T::BYTES) else {
panic!("{name}: {operand} is {len} bytes but count {bits} overflows `usize`");
};
assert_eq!(
len, expected,
"{name}: {operand} is {len} bytes but {bits} elements need {expected}"
);
}
#[inline]
fn check_packed_out(name: &str, operand: &str, len: usize, bits: usize) {
let expected = bytes_for(bits);
assert_eq!(
len, expected,
"{name}: {operand} is {len} bytes but {bits} bits need {expected}"
);
}
#[inline]
fn bit_words<S, T>(map: &PreparedEmbedding<S, T>) -> (u64, u64)
where
S: PrimeField<Characteristic = PrimeCharacteristic<2>>,
T: BinaryField + FieldBuffer<Characteristic = S::Characteristic>,
{
map.bit_map_words()
.expect("bit_map_words: GF(2)-sourced maps carry precomputed bit words")
}
#[inline]
pub fn embed_into_with<S, T>(dst: &mut [u8], map: &PreparedEmbedding<S, T>, src: &[u8], bits: usize)
where
S: PrimeField<Characteristic = PrimeCharacteristic<2>>,
T: BinaryField + FieldBuffer<Characteristic = S::Characteristic>,
{
check_holds("embed_into_with", "src", src.len(), bits);
check_lanes::<T>("embed_into_with", "dst", dst.len(), bits);
let (one_w, _) = bit_words(map);
gf1::expand(dst, one_w, src, bits, T::BYTES);
}
#[inline]
pub fn trace_into_with<S, T>(dst: &mut [u8], map: &PreparedEmbedding<S, T>, src: &[u8], bits: usize)
where
S: PrimeField<Characteristic = PrimeCharacteristic<2>>,
T: BinaryField + FieldBuffer<Characteristic = S::Characteristic>,
{
check_lanes::<T>("trace_into_with", "src", src.len(), bits);
check_packed_out("trace_into_with", "dst", dst.len(), bits);
let (_, tau) = bit_words(map);
gf1::compress(dst, src, bits, T::BYTES, &LaneTest::Parity(tau));
}
#[inline]
pub fn norm_into_with<S, T>(dst: &mut [u8], map: &PreparedEmbedding<S, T>, src: &[u8], bits: usize)
where
S: PrimeField<Characteristic = PrimeCharacteristic<2>>,
T: BinaryField + FieldBuffer<Characteristic = S::Characteristic>,
{
check_lanes::<T>("norm_into_with", "src", src.len(), bits);
check_packed_out("norm_into_with", "dst", dst.len(), bits);
let _ = bit_words(map);
gf1::compress(dst, src, bits, T::BYTES, &LaneTest::NonZero);
}
#[inline]
pub fn restrict_into_with<S, T>(
dst: &mut [u8],
valid: &mut [u8],
map: &PreparedEmbedding<S, T>,
src: &[u8],
bits: usize,
) where
S: PrimeField<Characteristic = PrimeCharacteristic<2>>,
T: BinaryField + FieldBuffer<Characteristic = S::Characteristic>,
{
check_lanes::<T>("restrict_into_with", "src", src.len(), bits);
check_packed_out("restrict_into_with", "dst", dst.len(), bits);
check_packed_out("restrict_into_with", "valid", valid.len(), bits);
let (one_w, _) = bit_words(map);
gf1::restrict(dst, valid, one_w, src, bits, T::BYTES);
}
#[inline]
pub fn contains_into_with<S, T>(
valid: &mut [u8],
map: &PreparedEmbedding<S, T>,
src: &[u8],
bits: usize,
) where
S: PrimeField<Characteristic = PrimeCharacteristic<2>>,
T: BinaryField + FieldBuffer<Characteristic = S::Characteristic>,
{
check_lanes::<T>("contains_into_with", "src", src.len(), bits);
check_packed_out("contains_into_with", "valid", valid.len(), bits);
let (one_w, _) = bit_words(map);
gf1::compress(valid, src, bits, T::BYTES, &LaneTest::ZeroOrOne(one_w));
}