use crate::base::{encode::U256, scalar::MontScalar};
use ark_ff::MontConfig;
pub trait ZigZag<T> {
fn zigzag(&self) -> T;
}
impl<T: MontConfig<4>> ZigZag<U256> for MontScalar<T> {
fn zigzag(&self) -> U256 {
let mut x: U256 = self.into();
let mut y: U256 = (&-self).into();
if x.high > y.high || (x.high == y.high && x.low > y.low) {
y.high = (y.high << 1) | (y.low >> 127);
y.low <<= 1;
let (low_val, carry_low) = y.low.overflowing_sub(1_u128);
y.low = low_val;
y.high -= u128::from(carry_low);
y
} else {
x.high = (x.high << 1) | (x.low >> 127);
x.low <<= 1;
x
}
}
}
impl<T: MontConfig<4>> ZigZag<MontScalar<T>> for U256 {
fn zigzag(&self) -> MontScalar<T> {
let mut zig_val = U256 {
low: (self.low >> 1) | ((self.high & 1) << 127),
high: self.high >> 1,
};
if self.low & 1 == 1 {
let (low_val, carry_low) = zig_val.low.overflowing_add(1_u128);
zig_val.low = low_val;
zig_val.high += u128::from(carry_low);
let scal: MontScalar<T> = (&zig_val).into();
-scal
} else {
let scal: MontScalar<T> = (&zig_val).into();
scal
}
}
}