#[allow(clippy::useless_attribute)]
#[allow(clippy::wildcard_imports)]
use std::prelude::v1::*;
use crate::{curve::Affine, jacobian::Jacobian, ScalarFieldElement};
use itertools::izip;
use zkp_primefield::{FieldElement, Inv, One, SquareInline};
use zkp_u256::{Binary, U256};
pub(crate) fn window_table(p: &Affine, naf: &mut [Jacobian]) {
naf[0] = Jacobian::from(p);
let p2 = naf[0].double();
for i in 1..naf.len() {
naf[i] = &naf[i - 1] + &p2;
}
}
pub fn window_table_affine(p: &Affine, naf: &mut [Affine]) {
naf[0] = p.clone();
let p2 = naf[0].double();
for i in 1..naf.len() {
naf[i] = &naf[i - 1] + &p2;
}
}
pub(crate) fn batch_convert(jacobians: &[Jacobian], affines: &mut [Affine]) {
debug_assert!(jacobians.len() == affines.len());
let mut vals = vec![FieldElement::one(); jacobians.len()];
let mut acc = FieldElement::one();
for (jac, val) in izip!(jacobians.iter(), vals.iter_mut()) {
*val = acc.clone();
acc *= &jac.z;
}
acc = acc.inv().unwrap();
for (jac, val, aff) in izip!(jacobians.iter(), vals.into_iter(), affines.iter_mut()).rev() {
let zi = &acc * val;
acc *= &jac.z;
let zi2 = zi.square();
let zi3 = zi * &zi2;
*aff = Affine::Point {
x: &jac.x * zi2,
y: &jac.y * zi3,
}
}
}
pub(crate) fn non_adjacent_form(scalar: &ScalarFieldElement, window: usize) -> [i16; 257] {
let mut scalar = scalar.to_uint();
let mask = (1_u64 << window) - 1;
let half = 1_i16 << (window - 1);
let mut snaf = [0_i16; 257];
let mut i: usize = 0;
loop {
match scalar.trailing_zeros() {
0 => {}
256 => break,
shift => {
scalar >>= shift;
i += shift;
}
}
#[allow(clippy::cast_possible_truncation)]
let mut n: i16 = (scalar.limb(0) & mask) as i16;
scalar >>= window;
if n >= half {
n -= 1_i16 << window;
scalar += U256::ONE;
}
snaf[i] = n;
i += window;
}
snaf
}
#[allow(clippy::cast_sign_loss)]
#[must_use]
#[allow(clippy::comparison_chain)]
pub fn mul(p: &Affine, scalar: &ScalarFieldElement) -> Jacobian {
let mut naf_table: [Jacobian; 8] = Default::default();
window_table(p, &mut naf_table);
let snaf_expansion = non_adjacent_form(scalar, 5);
let mut r = Jacobian::ZERO;
for i in (0..snaf_expansion.len()).rev() {
r.double_assign();
if snaf_expansion[i] > 0 {
r += &naf_table[(snaf_expansion[i] >> 1) as usize];
} else if snaf_expansion[i] < 0 {
r -= &naf_table[(-snaf_expansion[i] >> 1) as usize];
}
}
r
}
#[allow(clippy::cast_sign_loss)]
#[must_use]
#[allow(clippy::comparison_chain)]
pub fn double_mul(
point_a: &Affine,
scalar_a: &ScalarFieldElement,
point_b: &Affine,
scalar_b: &ScalarFieldElement,
) -> Jacobian {
let mut naf_table_a: [Jacobian; 8] = Default::default();
let mut naf_table_b: [Jacobian; 8] = Default::default();
window_table(point_a, &mut naf_table_a);
window_table(point_b, &mut naf_table_b);
let snaf_expansion_a = non_adjacent_form(scalar_a, 5);
let snaf_expansion_b = non_adjacent_form(scalar_b, 5);
let mut r = Jacobian::ZERO;
debug_assert_eq!(snaf_expansion_a.len(), snaf_expansion_b.len());
for i in (0..snaf_expansion_a.len()).rev() {
r.double_assign();
if snaf_expansion_a[i] > 0 {
r += &naf_table_a[(snaf_expansion_a[i] >> 1) as usize];
} else if snaf_expansion_b[i] < 0 {
r -= &naf_table_a[(-snaf_expansion_a[i] >> 1) as usize];
}
if snaf_expansion_b[i] > 0 {
r += &naf_table_b[(snaf_expansion_b[i] >> 1) as usize];
} else if snaf_expansion_b[i] < 0 {
r -= &naf_table_b[(-snaf_expansion_b[i] >> 1) as usize];
}
}
r
}
#[allow(clippy::cast_sign_loss)]
#[allow(clippy::comparison_chain)]
#[must_use]
pub fn base_mul(naf_table: &[Affine], scalar: &ScalarFieldElement) -> Jacobian {
let snaf_expansion = non_adjacent_form(scalar, 7);
let mut r = Jacobian::ZERO;
for i in (0..snaf_expansion.len()).rev() {
r.double_assign();
if snaf_expansion[i] > 0 {
r += &naf_table[(snaf_expansion[i] >> 1) as usize];
} else if snaf_expansion[i] < 0 {
r -= &naf_table[(-snaf_expansion[i] >> 1) as usize];
}
}
r
}
#[allow(clippy::cast_sign_loss)]
#[allow(clippy::shadow_unrelated)]
#[allow(clippy::comparison_chain)]
#[must_use]
pub fn double_base_mul(
naf_table_a: &[Affine],
scalar_a: &ScalarFieldElement,
point_b: &Affine,
scalar_b: &ScalarFieldElement,
) -> Jacobian {
let mut naf_table_b: [Jacobian; 8] = Default::default();
window_table(point_b, &mut naf_table_b);
let mut temp: [Affine; 8] = Default::default();
batch_convert(&naf_table_b, &mut temp);
let naf_table_b = temp;
let snaf_expansion_a = non_adjacent_form(scalar_a, 7);
let snaf_expansion_b = non_adjacent_form(scalar_b, 5);
let mut r = Jacobian::ZERO;
debug_assert_eq!(snaf_expansion_a.len(), snaf_expansion_b.len());
for i in (0..snaf_expansion_a.len()).rev() {
r.double_assign();
if snaf_expansion_a[i] > 0 {
r += &naf_table_a[(snaf_expansion_a[i] >> 1) as usize];
} else if snaf_expansion_a[i] < 0 {
r -= &naf_table_a[(-snaf_expansion_a[i] >> 1) as usize];
}
if snaf_expansion_b[i] > 0 {
r += &naf_table_b[(snaf_expansion_b[i] >> 1) as usize];
} else if snaf_expansion_b[i] < 0 {
r -= &naf_table_b[(-snaf_expansion_b[i] >> 1) as usize];
}
}
r
}
#[cfg(test)]
mod tests {
use super::*;
use zkp_macros_decl::{field_element, u256h};
use zkp_primefield::FieldElement;
#[test]
fn test_mul() {
let p = Affine::new(
field_element!("01ef15c18599971b7beced415a40f0c7deacfd9b0d1819e03d723d8bc943cfca"),
field_element!("005668060aa49730b7be4801df46ec62de53ecd11abe43a32873000c36e8dc1f"),
);
let c = ScalarFieldElement::from(u256h!(
"07374b7d69dc9825fc758b28913c8d2a27be5e7c32412f612b20c9c97afbe4dd"
));
let expected = Jacobian::from(Affine::new(
field_element!("00f24921907180cd42c9d2d4f9490a7bc19ac987242e80ac09a8ac2bcf0445de"),
field_element!("018a7a2ab4e795405f924de277b0e723d90eac55f2a470d8532113d735bdedd4"),
));
let result = mul(&p, &c);
assert_eq!(result, expected);
}
}