use crate::base::{
encode::{ZigZag, U256},
scalar::MontScalar,
};
use ark_ff::MontConfig;
use core::cmp::{max, Ordering};
pub fn write_scalar_varint<T: MontConfig<4>>(buf: &mut [u8], x: &MontScalar<T>) -> usize {
write_u256_varint(buf, x.zigzag())
}
#[expect(clippy::cast_possible_truncation)]
pub fn write_u256_varint(buf: &mut [u8], mut zig_x: U256) -> usize {
let mut pos = 0;
while zig_x.high != 0 || zig_x.low >= 0b1000_0000 {
buf[pos] = (zig_x.low as u8) | 0b1000_0000;
pos += 1;
zig_x.low = (zig_x.low >> 7) | ((zig_x.high & 0b0111_1111) << 121);
zig_x.high >>= 7;
}
buf[pos] = (zig_x.low & 0b0111_1111) as u8;
pos + 1
}
pub fn read_scalar_varint<T: MontConfig<4>>(buf: &[u8]) -> Option<(MontScalar<T>, usize)> {
read_u256_varint(buf).map(|(val, s)| (val.zigzag(), s))
}
pub fn read_u256_varint(buf: &[u8]) -> Option<(U256, usize)> {
let mut val = U256::from_words(0, 0);
let mut shift_amount: u32 = 0;
for next_byte in buf {
match shift_amount.cmp(&126_u32) {
Ordering::Less => val.low |= (u128::from(*next_byte & 0b0111_1111)) << shift_amount,
Ordering::Equal => {
val.low |= (u128::from(*next_byte & 0b0000_0011)) << shift_amount;
val.high |= (u128::from(*next_byte & 0b0111_1100)) >> 2;
}
Ordering::Greater => {
val.high |= (u128::from(*next_byte & 0b0111_1111)) << (shift_amount - 128);
}
}
shift_amount += 7;
if (*next_byte >> 7) == 0 {
return Some((val, (shift_amount / 7) as usize));
}
if shift_amount > 256 {
return None;
}
}
None
}
#[cfg(test)]
pub fn write_scalar_varints<T: MontConfig<4>>(buf: &mut [u8], scals: &[MontScalar<T>]) -> usize {
let mut total_bytes_written = 0;
for scal in scals {
let bytes_written = write_scalar_varint(&mut buf[total_bytes_written..], scal);
total_bytes_written += bytes_written;
}
total_bytes_written
}
#[cfg(test)]
pub fn read_scalar_varints<T: MontConfig<4>>(
scals_buf: &mut [MontScalar<T>],
input_buf: &[u8],
) -> Option<()> {
let mut buf = input_buf;
for scal_buf in scals_buf.iter_mut() {
let (scal, bytes_read) = read_scalar_varint(buf)?;
*scal_buf = scal;
buf = &buf[bytes_read..];
}
Some(())
}
pub fn scalar_varint_size<T: MontConfig<4>>(x: &MontScalar<T>) -> usize {
u256_varint_size(x.zigzag())
}
pub fn u256_varint_size(zig_x: U256) -> usize {
let zigzag_size = if zig_x.high == 0 {
128 - zig_x.low.leading_zeros()
} else {
256 - zig_x.high.leading_zeros()
};
max(1, (zigzag_size as usize).div_ceil(7))
}
#[cfg(test)]
pub fn scalar_varints_size<T: MontConfig<4>>(scals: &[MontScalar<T>]) -> usize {
let mut all_size: usize = 0;
for x in scals {
all_size += scalar_varint_size(x);
}
all_size
}