#[cfg(zisk_guest)]
use crate::alloc_extern::vec;
#[cfg(zisk_guest)]
use crate::alloc_extern::vec::Vec;
use crate::syscalls::{
syscall_add256, syscall_arith256, SyscallAdd256Params, SyscallArith256Params,
};
use super::{rem_long, LongScratch, U256};
pub fn square_long(
a: &[U256],
out: &mut [U256],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> usize {
let len_a = a.len();
#[cfg(debug_assertions)]
{
assert_ne!(len_a, 0, "Input 'a' must have at least one limb");
if len_a > 1 {
assert!(!a[len_a - 1].is_zero(), "Input 'a' must not have leading zeros");
}
}
for (i, ai) in a.iter().enumerate() {
let k = 2 * i;
let mut ai_ai = SyscallArith256Params {
a: ai.as_limbs(),
b: ai.as_limbs(),
c: U256::ZERO.as_limbs(),
dl: out[k].as_limbs_mut(),
dh: &mut [0, 0, 0, 0],
};
syscall_arith256(
&mut ai_ai,
#[cfg(feature = "hints")]
hints,
);
out[k + 1] = U256::from_u64s(ai_ai.dh);
}
for i in 0..len_a {
for j in (i + 1)..len_a {
let mut ai_aj = SyscallArith256Params {
a: a[i].as_limbs(),
b: a[j].as_limbs(),
c: U256::ZERO.as_limbs(),
dl: &mut [0, 0, 0, 0],
dh: &mut [0, 0, 0, 0],
};
syscall_arith256(
&mut ai_aj,
#[cfg(feature = "hints")]
hints,
);
let mut low_chunk: [u64; 4] = [0, 0, 0, 0];
let mut dbl_low =
SyscallAdd256Params { a: ai_aj.dl, b: ai_aj.dl, cin: 0, c: &mut low_chunk };
let carry = syscall_add256(
&mut dbl_low,
#[cfg(feature = "hints")]
hints,
);
let mut mid_chunk: [u64; 4] = [0, 0, 0, 0];
let mut dbl_high =
SyscallAdd256Params { a: ai_aj.dh, b: ai_aj.dh, cin: carry, c: &mut mid_chunk };
let high_chunk = syscall_add256(
&mut dbl_high,
#[cfg(feature = "hints")]
hints,
);
let k = i + j;
let mut add = SyscallAdd256Params {
a: out[k].as_limbs(),
b: &low_chunk,
cin: 0,
c: &mut [0, 0, 0, 0],
};
let mut carry = syscall_add256(
&mut add,
#[cfg(feature = "hints")]
hints,
);
out[k] = U256::from_u64s(add.c);
let mut add = SyscallAdd256Params {
a: out[k + 1].as_limbs(),
b: &mid_chunk,
cin: carry,
c: &mut [0, 0, 0, 0],
};
carry = syscall_add256(
&mut add,
#[cfg(feature = "hints")]
hints,
);
out[k + 1] = U256::from_u64s(add.c);
let mut add = SyscallAdd256Params {
a: out[k + 2].as_limbs(),
b: &[high_chunk, 0, 0, 0],
cin: carry,
c: &mut [0, 0, 0, 0],
};
carry = syscall_add256(
&mut add,
#[cfg(feature = "hints")]
hints,
);
out[k + 2] = U256::from_u64s(add.c);
let mut idx = k + 3;
while carry != 0 {
let mut add = SyscallAdd256Params {
a: out[idx].as_limbs(),
b: U256::ZERO.as_limbs(),
cin: carry,
c: &mut [0, 0, 0, 0],
};
carry = syscall_add256(
&mut add,
#[cfg(feature = "hints")]
hints,
);
out[idx] = U256::from_u64s(add.c);
idx += 1;
}
}
}
if out[2 * len_a - 1].is_zero() {
2 * len_a - 1
} else {
2 * len_a
}
}
pub fn square_and_reduce_long(
a: &[U256],
modulus: &[U256],
scratch: &mut LongScratch,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> Vec<U256> {
#[cfg(debug_assertions)]
{
let len_m = modulus.len();
assert_ne!(len_m, 0, "Input 'modulus' must have at least one limb");
assert!(!modulus[len_m - 1].is_zero(), "Input 'modulus' must not have leading zeros");
}
let sq_len = square_long(
a,
&mut scratch.mul,
#[cfg(feature = "hints")]
hints,
);
rem_long(
&scratch.mul[..sq_len],
modulus,
&mut scratch.rem,
#[cfg(feature = "hints")]
hints,
)
}