use crate::nist::arith::Field;
use crate::p256::{Fn as Scalar, Fp};
use ic_core::ct::Choice;
macro_rules! probes {
($t:ty, $reduce:ident, $add:ident, $sub:ident, $mul:ident, $neg:ident, $cmov:ident, $eq:ident, $odd:ident) => {
#[inline(always)]
pub fn $reduce(a: &[u8; 32]) -> [u8; 32] {
<$t>::from_bytes_reduced(a).to_bytes()
}
#[inline(always)]
pub fn $add(a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
<$t>::from_bytes_reduced(a)
.add(&<$t>::from_bytes_reduced(b))
.to_bytes()
}
#[inline(always)]
pub fn $sub(a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
<$t>::from_bytes_reduced(a)
.sub(&<$t>::from_bytes_reduced(b))
.to_bytes()
}
#[inline(always)]
pub fn $mul(a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
<$t>::from_bytes_reduced(a)
.mul(&<$t>::from_bytes_reduced(b))
.to_bytes()
}
#[inline(always)]
pub fn $neg(a: &[u8; 32]) -> [u8; 32] {
<$t>::from_bytes_reduced(a).neg().to_bytes()
}
#[inline(always)]
pub fn $cmov(flag: u8, a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
let mut x = <$t>::from_bytes_reduced(a);
<$t as Field>::cmov(
&mut x,
&<$t>::from_bytes_reduced(b),
Choice::from_u8(flag & 1),
);
x.to_bytes()
}
#[inline(always)]
pub fn $eq(a: &[u8; 32], b: &[u8; 32]) -> u8 {
<$t>::from_bytes_reduced(a)
.ct_eq(&<$t>::from_bytes_reduced(b))
.unwrap_u8()
}
#[inline(always)]
pub fn $odd(a: &[u8; 32]) -> u8 {
<$t>::from_bytes_reduced(a).is_odd().unwrap_u8()
}
};
}
probes!(Fp, fp_reduce, fp_add, fp_sub, fp_mul, fp_neg, fp_cmov, fp_eq, fp_is_odd);
probes!(Scalar, fn_reduce, fn_add, fn_sub, fn_mul, fn_neg, fn_cmov, fn_eq, fn_is_odd);
#[cfg(not(ic_approved_only))]
#[inline(always)]
pub fn ed25519_reduce_wide(x: &[u8; 64]) -> [u8; 32] {
crate::scalar::reduce_wide(x)
}
#[cfg(not(ic_approved_only))]
#[inline(always)]
pub fn ed25519_mul_add(a: &[u8; 32], b: &[u8; 32], c: &[u8; 32]) -> [u8; 32] {
crate::scalar::mul_add(a, b, c)
}
#[cfg(all(
not(ic_approved_only),
target_arch = "x86_64",
not(any(ic_limb32, ic_ec_portable))
))]
#[allow(unsafe_code)]
pub mod x86 {
use crate::fe64::edwards;
pub use crate::fe64::edwards::{Ws, Ws2};
use crate::fe64::Fe64;
pub use crate::f51x4::probes as ifma;
#[inline(always)]
pub unsafe fn fe64_mul(a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
Fe64::from_bytes(a).mul(&Fe64::from_bytes(b)).to_bytes()
}
#[inline(always)]
pub unsafe fn fe64_square(a: &[u8; 32]) -> [u8; 32] {
Fe64::from_bytes(a).square().to_bytes()
}
#[inline(always)]
pub unsafe fn fe64_add(a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
Fe64::from_bytes(a).add(&Fe64::from_bytes(b)).to_bytes()
}
#[inline(always)]
pub unsafe fn fe64_sub(a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
Fe64::from_bytes(a).sub(&Fe64::from_bytes(b)).to_bytes()
}
#[inline(always)]
pub unsafe fn fe64_mul121666(a: &[u8; 32]) -> [u8; 32] {
Fe64::from_bytes(a).mul121666().to_bytes()
}
#[inline(always)]
pub unsafe fn fe64_invert(a: &[u8; 32]) -> [u8; 32] {
Fe64::from_bytes(a).invert().to_bytes()
}
#[inline(always)]
pub unsafe fn x25519_step(ws: &mut [u64; 76], swap: u64) {
crate::fe64::ladder_step(ws, swap & 1)
}
#[inline(always)]
pub unsafe fn x25519_double(ws: &mut [u64; 76]) {
crate::fe64::ladder_double(ws)
}
#[inline(always)]
pub fn ed25519_select(dst: &mut [u64; 16], table: &[[u64; 12]; 8], digit: i8) {
edwards::select(dst, table, digit)
}
#[inline(always)]
pub unsafe fn ed25519_madd_ext2(ws: &mut Ws2) {
edwards::madd_ext2(ws);
}
pub use crate::fe64::edwards::Ws2Scan;
pub use crate::fe64::edwards::probes as wide;
#[inline(always)]
pub fn ed25519_digits32(scalar: &[u8; 32]) -> [i8; 52] {
crate::ed25519::signed_digits32(scalar)
}
#[inline(always)]
pub unsafe fn ed25519_dbl_nadd(ws: &mut Ws) {
edwards::dbl(ws);
edwards::to_proj(ws);
edwards::dbl(ws);
edwards::to_ext(ws);
edwards::nadd(ws);
edwards::to_ext(ws);
}
}
#[cfg(target_arch = "x86_64")]
pub use crate::nist::p256_x86::{mul_adx as fp_mul_adx, square_adx as fp_square_adx};
#[cfg(target_arch = "x86_64")]
pub use crate::nist::p256_x86_point::{
add_adx as point_add_adx, add_affine_adx as point_add_affine_adx,
double_adx as point_double_adx, double_in_place_adx as point_double_in_place_adx,
};
#[cfg(target_arch = "x86_64")]
pub use crate::nist::mont_x86::mul_p384_n as p384_fn_mul_adx;
#[cfg(target_arch = "x86_64")]
pub use crate::nist::p384_x86_point::{
add_adx as p384_point_add_adx, add_affine_adx as p384_point_add_affine_adx,
double_adx as p384_point_double_adx, double_in_place_adx as p384_point_double_in_place_adx,
fmul_adx as p384_fp_mul_adx, fsqr_adx as p384_fp_sqr_adx,
};
#[cfg(all(target_arch = "x86_64", not(ic_limb32)))]
#[inline(always)]
pub fn p384_fp_invert(a: &[u64; 6]) -> [u64; 6] {
crate::nist::safegcd::invert_384::<crate::p384::FpModulus>(a)
}
#[cfg(target_arch = "x86_64")]
pub struct P384Comb(crate::nist::gentable::Comb<crate::p384::P384>);
#[cfg(target_arch = "x86_64")]
pub fn p384_comb_new(public_key: &[u8; 97]) -> Option<P384Comb> {
let q = crate::nist::point::AffinePoint::<crate::p384::P384>::from_sec1(public_key)?;
Some(P384Comb(crate::nist::gentable::Comb::new(
&crate::nist::point::Point::from_affine(&q),
)))
}
#[cfg(target_arch = "x86_64")]
#[inline(always)]
pub fn p384_comb_select(comb: &P384Comb, digit: i8, out: &mut [[u64; 6]; 2]) {
let (x, y) = comb.0.first_window().select(digit);
*out = [x.0, y.0];
}
#[cfg(target_arch = "x86_64")]
pub struct P256Window(crate::nist::gentable::Window<crate::p256::P256>);
#[cfg(target_arch = "x86_64")]
pub fn p256_window_new(public_key: &[u8; 65]) -> Option<P256Window> {
let q = crate::nist::point::AffinePoint::<crate::p256::P256>::from_sec1(public_key)?;
Some(P256Window(crate::nist::gentable::Window::new(
&crate::nist::point::Point::from_affine(&q),
)))
}
#[cfg(target_arch = "x86_64")]
pub struct P256Table(crate::nist::gentable::AffineWindow<crate::p256::P256, 32>);
#[cfg(target_arch = "x86_64")]
pub fn p256_table_new(public_key: &[u8; 65]) -> Option<P256Table> {
let q = crate::nist::point::AffinePoint::<crate::p256::P256>::from_sec1(public_key)?;
Some(P256Table(crate::nist::gentable::AffineWindow::new(
&crate::nist::point::Point::from_affine(&q),
)))
}
#[cfg(target_arch = "x86_64")]
#[allow(unsafe_code)]
mod adx_steps {
use super::{P256Table, P256Window, P384Comb};
#[cfg(target_arch = "x86_64")]
#[inline(always)]
pub unsafe fn p384_ladder_add(
comb: &P384Comb,
digit: i8,
buf: &mut [core::mem::MaybeUninit<u64>; crate::nist::p384_x86::LADDER],
) {
let (x, y) = comb.0.first_window().select(digit);
unsafe { crate::nist::p384_x86::ladder_add(buf, &x.0, &y.0, digit) }
}
#[cfg(target_arch = "x86_64")]
#[inline(always)]
pub unsafe fn p256_ladder_add(
window: &P256Window,
digit: i8,
buf: &mut [core::mem::MaybeUninit<u64>; crate::nist::p256_x86::LADDER],
) {
let entry = window.0.select(digit);
unsafe { crate::nist::p256_x86::ladder_add(buf, &entry) }
}
#[cfg(target_arch = "x86_64")]
#[inline(always)]
pub unsafe fn p256_table_add(
table: &P256Table,
digit: i8,
buf: &mut [core::mem::MaybeUninit<u64>; crate::nist::p256_x86::TABLE],
) {
let (x, y) = table.0.select(digit);
unsafe { crate::nist::p256_x86::table_add(buf, &x.0, &y.0, digit) }
}
}
#[cfg(target_arch = "x86_64")]
pub use adx_steps::{p256_ladder_add, p256_table_add, p384_ladder_add};
#[cfg(all(target_arch = "x86_64", not(ic_limb32)))]
#[inline(always)]
pub fn p256_fp_invert(a: &[u64; 4]) -> [u64; 4] {
crate::nist::safegcd::invert::<crate::p256::FpModulus>(a)
}
#[cfg(all(target_arch = "x86_64", not(ic_limb32)))]
#[inline(always)]
pub fn p256_fn_invert(a: &[u64; 4]) -> [u64; 4] {
crate::nist::safegcd::invert::<crate::p256::FnModulus>(a)
}
#[cfg(target_arch = "x86_64")]
pub use crate::nist::ifma::probes as nist_ifma;