use crate::zisklib::lib::{
constants::{MAX_256 as MAX, ONE_256 as ONE, ZERO_256 as ZERO},
utils::{is_one, is_zero},
};
use crate::zisklib::{fcall_bin_decomp, fcall_msb_pos_256, is_power_of_two};
use super::mul::{overflowing_mul256, overflowing_square256, wrapping_mul256, wrapping_square256};
pub fn checked_pow256(
base: &[u64; 4],
exp: &[u64; 4],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> Option<[u64; 4]> {
match overflowing_pow256(
base,
exp,
#[cfg(feature = "hints")]
hints,
) {
(res, false) => Some(res),
(_, true) => None,
}
}
pub fn overflowing_pow256(
base: &[u64; 4],
exp: &[u64; 4],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> ([u64; 4], bool) {
if is_zero(exp) {
return (ONE, false);
} else if is_one(exp) {
return (*base, false);
}
if is_zero(base) {
return (ZERO, false);
} else if is_one(base) {
return (ONE, false);
}
if is_power_of_two(exp) {
let (limb, bit) = fcall_msb_pos_256(
exp,
#[cfg(feature = "hints")]
hints,
);
assert!(limb < 4 && bit < 64, "msb_pos hint out of range");
let mut check_exp = [0u64; 4];
check_exp[limb as usize] = 1u64 << (bit as usize);
assert_eq!(check_exp[limb as usize], exp[limb as usize], "Exponent limb mismatch");
let mut overflow = false;
let mut result = *base;
for _ in 0..(64 * limb + bit) {
let (res, sq_overflow) = overflowing_square256(
&result,
#[cfg(feature = "hints")]
hints,
);
result = res;
overflow |= sq_overflow;
}
return (result, overflow);
}
let (len, bits) = fcall_bin_decomp(
exp,
#[cfg(feature = "hints")]
hints,
);
assert!(len > 0 && bits[0] == 1, "Exponent must be non-zero");
assert!(len <= 256, "Exponent bit length out of range");
assert!(bits.len() == len, "Bit decomposition length mismatch");
let mut overflow = false;
let mut result = *base;
let mut rec_exp = [0u64; 4];
let bit_pos = len - 1;
rec_exp[bit_pos / 64] = 1u64 << (bit_pos % 64);
for (bit_idx, &bit) in bits.iter().enumerate().skip(1) {
let (res, sq_overflow) = overflowing_square256(
&result,
#[cfg(feature = "hints")]
hints,
);
result = res;
overflow |= sq_overflow;
if bit == 1 {
let (res, mul_overflow) = overflowing_mul256(
&result,
base,
#[cfg(feature = "hints")]
hints,
);
result = res;
overflow |= mul_overflow;
let bit_pos = len - 1 - bit_idx;
rec_exp[bit_pos / 64] |= 1u64 << (bit_pos % 64);
}
}
assert_eq!(rec_exp, *exp, "Exponent decomposition mismatch");
(result, overflow)
}
pub fn wrapping_pow256(
base: &[u64; 4],
exp: &[u64; 4],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 4] {
if is_zero(exp) {
return ONE;
} else if is_one(exp) {
return *base;
}
if is_zero(base) {
return ZERO;
} else if is_one(base) {
return ONE;
}
if is_power_of_two(exp) {
let (limb, bit) = fcall_msb_pos_256(
exp,
#[cfg(feature = "hints")]
hints,
);
assert!(limb < 4 && bit < 64, "msb_pos hint out of range");
let mut check_exp = [0u64; 4];
check_exp[limb as usize] = 1u64 << (bit as usize);
assert_eq!(check_exp[limb as usize], exp[limb as usize], "Exponent limb mismatch");
let mut result = *base;
for _ in 0..(64 * limb + bit) {
result = wrapping_square256(
&result,
#[cfg(feature = "hints")]
hints,
);
}
return result;
}
let (len, bits) = fcall_bin_decomp(
exp,
#[cfg(feature = "hints")]
hints,
);
assert!(len > 0 && bits[0] == 1, "Exponent must be non-zero");
assert!(len <= 256, "Exponent bit length out of range");
assert!(bits.len() == len, "Bit decomposition length mismatch");
let mut result = *base;
let mut rec_exp = [0u64; 4];
let bit_pos = len - 1;
rec_exp[bit_pos / 64] = 1u64 << (bit_pos % 64);
for (bit_idx, &bit) in bits.iter().enumerate().skip(1) {
result = wrapping_square256(
&result,
#[cfg(feature = "hints")]
hints,
);
if bit == 1 {
result = wrapping_mul256(
&result,
base,
#[cfg(feature = "hints")]
hints,
);
let bit_pos = len - 1 - bit_idx;
rec_exp[bit_pos / 64] |= 1u64 << (bit_pos % 64);
}
}
assert_eq!(rec_exp, *exp, "Exponent decomposition mismatch");
result
}
pub fn saturating_pow256(
base: &[u64; 4],
exp: &[u64; 4],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 4] {
match overflowing_pow256(
base,
exp,
#[cfg(feature = "hints")]
hints,
) {
(res, false) => res,
(_, true) => MAX,
}
}
#[cfg_attr(not(feature = "hints"), no_mangle)]
#[cfg_attr(feature = "hints", export_name = "hints_checked_pow256_c")]
pub unsafe extern "C" fn checked_pow256_c(
base_ptr: *const u64,
exp_ptr: *const u64,
result_ptr: *mut u64,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> u8 {
let base = &*(base_ptr as *const [u64; 4]);
let exp = &*(exp_ptr as *const [u64; 4]);
match checked_pow256(
base,
exp,
#[cfg(feature = "hints")]
hints,
) {
Some(res) => {
let result = &mut *(result_ptr as *mut [u64; 4]);
*result = res;
1
}
None => 0,
}
}
#[cfg_attr(not(feature = "hints"), no_mangle)]
#[cfg_attr(feature = "hints", export_name = "hints_overflowing_pow256_c")]
pub unsafe extern "C" fn overflowing_pow256_c(
base_ptr: *const u64,
exp_ptr: *const u64,
result_ptr: *mut u64,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> u8 {
let base = &*(base_ptr as *const [u64; 4]);
let exp = &*(exp_ptr as *const [u64; 4]);
let (res, overflow) = overflowing_pow256(
base,
exp,
#[cfg(feature = "hints")]
hints,
);
let result = &mut *(result_ptr as *mut [u64; 4]);
*result = res;
overflow as u8
}
#[cfg_attr(not(feature = "hints"), no_mangle)]
#[cfg_attr(feature = "hints", export_name = "hints_wrapping_pow256_c")]
pub unsafe extern "C" fn wrapping_pow256_c(
base_ptr: *const u64,
exp_ptr: *const u64,
result_ptr: *mut u64,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) {
let base = &*(base_ptr as *const [u64; 4]);
let exp = &*(exp_ptr as *const [u64; 4]);
let result = &mut *(result_ptr as *mut [u64; 4]);
*result = wrapping_pow256(
base,
exp,
#[cfg(feature = "hints")]
hints,
);
}
#[cfg_attr(not(feature = "hints"), no_mangle)]
#[cfg_attr(feature = "hints", export_name = "hints_saturating_pow256_c")]
pub unsafe extern "C" fn saturating_pow256_c(
base_ptr: *const u64,
exp_ptr: *const u64,
result_ptr: *mut u64,
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) {
let base = &*(base_ptr as *const [u64; 4]);
let exp = &*(exp_ptr as *const [u64; 4]);
let result = &mut *(result_ptr as *mut [u64; 4]);
*result = saturating_pow256(
base,
exp,
#[cfg(feature = "hints")]
hints,
);
}