use crate::zisklib::{eq, fcall_msb_pos_256};
use super::{
constants::{
FROBENIUS_GAMMA11, FROBENIUS_GAMMA12, FROBENIUS_GAMMA13, FROBENIUS_GAMMA14,
FROBENIUS_GAMMA15, FROBENIUS_GAMMA21, FROBENIUS_GAMMA22, FROBENIUS_GAMMA23,
FROBENIUS_GAMMA24, FROBENIUS_GAMMA25, FROBENIUS_GAMMA31, FROBENIUS_GAMMA32,
FROBENIUS_GAMMA33, FROBENIUS_GAMMA34, FROBENIUS_GAMMA35,
},
fp2::{conjugate_fp2_bn254, mul_fp2_bn254, scalar_mul_fp2_bn254},
fp6::{
add_fp6_bn254, dbl_fp6_bn254, inv_fp6_bn254, mul_fp6_bn254, neg_fp6_bn254,
sparse_mula_fp6_bn254, sparse_mulb_fp6_bn254, sparse_mulc_fp6_bn254, square_fp6_bn254,
sub_fp6_bn254,
},
};
#[inline]
pub fn mul_fp12_bn254(
a: &[u64; 48],
b: &[u64; 48],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 48] {
let a1 = &a[0..24].try_into().unwrap();
let a2 = &a[24..48].try_into().unwrap();
let b1 = &b[0..24].try_into().unwrap();
let b2 = &b[24..48].try_into().unwrap();
let a1b1 = mul_fp6_bn254(
a1,
b1,
#[cfg(feature = "hints")]
hints,
);
let a2b2 = mul_fp6_bn254(
a2,
b2,
#[cfg(feature = "hints")]
hints,
);
let a2b2v = sparse_mula_fp6_bn254(
&a2b2,
&[1, 0, 0, 0, 0, 0, 0, 0],
#[cfg(feature = "hints")]
hints,
);
let c1 = add_fp6_bn254(
&a1b1,
&a2b2v,
#[cfg(feature = "hints")]
hints,
);
let a1_plus_a2 = add_fp6_bn254(
a1,
a2,
#[cfg(feature = "hints")]
hints,
);
let b1_plus_b2 = add_fp6_bn254(
b1,
b2,
#[cfg(feature = "hints")]
hints,
);
let mut c2 = mul_fp6_bn254(
&a1_plus_a2,
&b1_plus_b2,
#[cfg(feature = "hints")]
hints,
);
c2 = sub_fp6_bn254(
&c2,
&a1b1,
#[cfg(feature = "hints")]
hints,
);
c2 = sub_fp6_bn254(
&c2,
&a2b2,
#[cfg(feature = "hints")]
hints,
);
let mut result = [0; 48];
result[0..24].copy_from_slice(&c1);
result[24..48].copy_from_slice(&c2);
result
}
#[inline]
pub fn sparse_mul_fp12_bn254(
a: &[u64; 48],
b: &[u64; 16],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 48] {
let a1 = &a[0..24].try_into().unwrap();
let a2 = &a[24..48].try_into().unwrap();
let mut c1 = sparse_mulc_fp6_bn254(
a2,
b,
#[cfg(feature = "hints")]
hints,
);
c1 = add_fp6_bn254(
&c1,
a1,
#[cfg(feature = "hints")]
hints,
);
let mut c2 = sparse_mulb_fp6_bn254(
a1,
b,
#[cfg(feature = "hints")]
hints,
);
c2 = add_fp6_bn254(
&c2,
a2,
#[cfg(feature = "hints")]
hints,
);
let mut result = [0; 48];
result[0..24].copy_from_slice(&c1);
result[24..48].copy_from_slice(&c2);
result
}
#[inline]
pub fn square_fp12_bn254(
a: &[u64; 48],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 48] {
let a1 = &a[0..24].try_into().unwrap();
let a2 = &a[24..48].try_into().unwrap();
let a1a2 = mul_fp6_bn254(
a1,
a2,
#[cfg(feature = "hints")]
hints,
);
let a2v = sparse_mula_fp6_bn254(
a2,
&[1, 0, 0, 0, 0, 0, 0, 0],
#[cfg(feature = "hints")]
hints,
);
let a1a2v = sparse_mula_fp6_bn254(
&a1a2,
&[1, 0, 0, 0, 0, 0, 0, 0],
#[cfg(feature = "hints")]
hints,
);
let a1_minus_a2 = sub_fp6_bn254(
a1,
a2,
#[cfg(feature = "hints")]
hints,
);
let a1_minus_a2v = sub_fp6_bn254(
a1,
&a2v,
#[cfg(feature = "hints")]
hints,
);
let mut c1 = mul_fp6_bn254(
&a1_minus_a2,
&a1_minus_a2v,
#[cfg(feature = "hints")]
hints,
);
c1 = add_fp6_bn254(
&c1,
&a1a2,
#[cfg(feature = "hints")]
hints,
);
c1 = add_fp6_bn254(
&c1,
&a1a2v,
#[cfg(feature = "hints")]
hints,
);
let c2 = dbl_fp6_bn254(
&a1a2,
#[cfg(feature = "hints")]
hints,
);
let mut result = [0; 48];
result[0..24].copy_from_slice(&c1);
result[24..48].copy_from_slice(&c2);
result
}
#[inline]
pub fn inv_fp12_bn254(a: &[u64; 48], #[cfg(feature = "hints")] hints: &mut Vec<u64>) -> [u64; 48] {
let a1 = &a[0..24].try_into().unwrap();
let a2 = &a[24..48].try_into().unwrap();
let a1_sq = square_fp6_bn254(
a1,
#[cfg(feature = "hints")]
hints,
);
let a2_sq = square_fp6_bn254(
a2,
#[cfg(feature = "hints")]
hints,
);
let a2_sqv = sparse_mula_fp6_bn254(
&a2_sq,
&[1, 0, 0, 0, 0, 0, 0, 0],
#[cfg(feature = "hints")]
hints,
);
let a1_sq_minus_a2_sqv = sub_fp6_bn254(
&a1_sq,
&a2_sqv,
#[cfg(feature = "hints")]
hints,
);
let inv = inv_fp6_bn254(
&a1_sq_minus_a2_sqv,
#[cfg(feature = "hints")]
hints,
);
let c1 = mul_fp6_bn254(
a1,
&inv,
#[cfg(feature = "hints")]
hints,
);
let c2 = neg_fp6_bn254(
&mul_fp6_bn254(
a2,
&inv,
#[cfg(feature = "hints")]
hints,
),
#[cfg(feature = "hints")]
hints,
);
let mut result = [0; 48];
result[0..24].copy_from_slice(&c1);
result[24..48].copy_from_slice(&c2);
result
}
#[inline]
pub fn conjugate_fp12_bn254(
a: &[u64; 48],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 48] {
let mut result = [0; 48];
result[0..24].copy_from_slice(&a[0..24]);
result[24..48].copy_from_slice(&neg_fp6_bn254(
&a[24..48].try_into().unwrap(),
#[cfg(feature = "hints")]
hints,
));
result
}
#[inline]
pub fn frobenius1_fp12_bn254(
a: &[u64; 48],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 48] {
let a11 = &a[0..8].try_into().unwrap();
let a12 = &a[8..16].try_into().unwrap();
let a13 = &a[16..24].try_into().unwrap();
let a21 = &a[24..32].try_into().unwrap();
let a22 = &a[32..40].try_into().unwrap();
let a23 = &a[40..48].try_into().unwrap();
let mut result = [0; 48];
result[0..8].copy_from_slice(&conjugate_fp2_bn254(
a11,
#[cfg(feature = "hints")]
hints,
));
let mut tmp = conjugate_fp2_bn254(
a12,
#[cfg(feature = "hints")]
hints,
);
result[8..16].copy_from_slice(&mul_fp2_bn254(
&tmp,
&FROBENIUS_GAMMA12,
#[cfg(feature = "hints")]
hints,
));
tmp = conjugate_fp2_bn254(
a13,
#[cfg(feature = "hints")]
hints,
);
result[16..24].copy_from_slice(&mul_fp2_bn254(
&tmp,
&FROBENIUS_GAMMA14,
#[cfg(feature = "hints")]
hints,
));
tmp = conjugate_fp2_bn254(
a21,
#[cfg(feature = "hints")]
hints,
);
result[24..32].copy_from_slice(&mul_fp2_bn254(
&tmp,
&FROBENIUS_GAMMA11,
#[cfg(feature = "hints")]
hints,
));
tmp = conjugate_fp2_bn254(
a22,
#[cfg(feature = "hints")]
hints,
);
result[32..40].copy_from_slice(&mul_fp2_bn254(
&tmp,
&FROBENIUS_GAMMA13,
#[cfg(feature = "hints")]
hints,
));
tmp = conjugate_fp2_bn254(
a23,
#[cfg(feature = "hints")]
hints,
);
result[40..48].copy_from_slice(&mul_fp2_bn254(
&tmp,
&FROBENIUS_GAMMA15,
#[cfg(feature = "hints")]
hints,
));
result
}
#[inline]
pub fn frobenius2_fp12_bn254(
a: &[u64; 48],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 48] {
let a11: &[u64; 8] = &a[0..8].try_into().unwrap();
let a12 = &a[8..16].try_into().unwrap();
let a13 = &a[16..24].try_into().unwrap();
let a21 = &a[24..32].try_into().unwrap();
let a22 = &a[32..40].try_into().unwrap();
let a23 = &a[40..48].try_into().unwrap();
let mut result = [0; 48];
result[0..8].copy_from_slice(a11);
result[8..16].copy_from_slice(&scalar_mul_fp2_bn254(
a12,
&FROBENIUS_GAMMA22,
#[cfg(feature = "hints")]
hints,
));
result[16..24].copy_from_slice(&scalar_mul_fp2_bn254(
a13,
&FROBENIUS_GAMMA24,
#[cfg(feature = "hints")]
hints,
));
result[24..32].copy_from_slice(&scalar_mul_fp2_bn254(
a21,
&FROBENIUS_GAMMA21,
#[cfg(feature = "hints")]
hints,
));
result[32..40].copy_from_slice(&scalar_mul_fp2_bn254(
a22,
&FROBENIUS_GAMMA23,
#[cfg(feature = "hints")]
hints,
));
result[40..48].copy_from_slice(&scalar_mul_fp2_bn254(
a23,
&FROBENIUS_GAMMA25,
#[cfg(feature = "hints")]
hints,
));
result
}
#[inline]
pub fn frobenius3_fp12_bn254(
a: &[u64; 48],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 48] {
let a11 = &a[0..8].try_into().unwrap();
let a12 = &a[8..16].try_into().unwrap();
let a13 = &a[16..24].try_into().unwrap();
let a21 = &a[24..32].try_into().unwrap();
let a22 = &a[32..40].try_into().unwrap();
let a23 = &a[40..48].try_into().unwrap();
let mut result = [0; 48];
result[0..8].copy_from_slice(&conjugate_fp2_bn254(
a11,
#[cfg(feature = "hints")]
hints,
));
let mut tmp = conjugate_fp2_bn254(
a12,
#[cfg(feature = "hints")]
hints,
);
result[8..16].copy_from_slice(&mul_fp2_bn254(
&tmp,
&FROBENIUS_GAMMA32,
#[cfg(feature = "hints")]
hints,
));
tmp = conjugate_fp2_bn254(
a13,
#[cfg(feature = "hints")]
hints,
);
result[16..24].copy_from_slice(&mul_fp2_bn254(
&tmp,
&FROBENIUS_GAMMA34,
#[cfg(feature = "hints")]
hints,
));
tmp = conjugate_fp2_bn254(
a21,
#[cfg(feature = "hints")]
hints,
);
result[24..32].copy_from_slice(&mul_fp2_bn254(
&tmp,
&FROBENIUS_GAMMA31,
#[cfg(feature = "hints")]
hints,
));
tmp = conjugate_fp2_bn254(
a22,
#[cfg(feature = "hints")]
hints,
);
result[32..40].copy_from_slice(&mul_fp2_bn254(
&tmp,
&FROBENIUS_GAMMA33,
#[cfg(feature = "hints")]
hints,
));
tmp = conjugate_fp2_bn254(
a23,
#[cfg(feature = "hints")]
hints,
);
result[40..48].copy_from_slice(&mul_fp2_bn254(
&tmp,
&FROBENIUS_GAMMA35,
#[cfg(feature = "hints")]
hints,
));
result
}
#[inline]
pub fn exp_fp12_bn254(
e: u64,
a: &[u64; 48],
#[cfg(feature = "hints")] hints: &mut Vec<u64>,
) -> [u64; 48] {
let mut one = [0; 48];
one[0] = 1;
if eq(a, &[0; 48]) {
return [0; 48];
} else if eq(a, &one) {
return one;
}
if e == 0 {
return one;
} else if e == 1 {
return *a;
}
let (_, max_bit) = fcall_msb_pos_256(
&[e, 0, 0, 0],
#[cfg(feature = "hints")]
hints,
);
assert!(max_bit < 64, "msb_pos hint out of range");
let e_bit = (e >> max_bit) & 1;
assert_eq!(e_bit, 1, "The most significant bit of the exponent must be 1");
let mut result = *a;
let mut e_rec = 1 << max_bit;
let _max_bit = max_bit as usize;
for i in (0.._max_bit).rev() {
result = square_fp12_bn254(
&result,
#[cfg(feature = "hints")]
hints,
);
if ((e >> i) & 1) == 1 {
result = mul_fp12_bn254(
&result,
a,
#[cfg(feature = "hints")]
hints,
);
e_rec |= 1 << i;
}
}
assert_eq!(e_rec, e, "Reconstructed e does not match input e");
result
}