diff --git a/src/blob.rs b/src/blob.rs index 8d526d6..adcfc6b 100644 --- a/src/blob.rs +++ b/src/blob.rs @@ -36,7 +36,8 @@ impl Blob { } pub(crate) fn commitment(&self, setup: &Setup) -> Commitment { - let lincomb = P1::lincomb(setup.g1_lagrange_brp.as_slice(), self.elements.as_slice()); + let lincomb = + P1::lincomb_pippenger(setup.g1_lagrange_brp.as_slice(), self.elements.as_slice()); Commitment::from(lincomb) } diff --git a/src/bls.rs b/src/bls.rs index c3e1330..680a70e 100644 --- a/src/bls.rs +++ b/src/bls.rs @@ -1,3 +1,4 @@ +use core::slice; use std::{ cmp, mem::MaybeUninit, @@ -8,12 +9,12 @@ use blst::{ blst_bendian_from_scalar, blst_final_exp, blst_fp, blst_fp12, blst_fp12_is_one, blst_fp12_mul, blst_fr, blst_fr_add, blst_fr_cneg, blst_fr_eucl_inverse, blst_fr_from_scalar, blst_fr_from_uint64, blst_fr_lshift, blst_fr_mul, blst_fr_rshift, blst_fr_sub, - blst_miller_loop, blst_p1, blst_p1_add, blst_p1_affine, blst_p1_affine_in_g1, blst_p1_cneg, - blst_p1_compress, blst_p1_deserialize, blst_p1_from_affine, blst_p1_mult, blst_p1_to_affine, - blst_p2, blst_p2_add, blst_p2_affine, blst_p2_affine_in_g2, blst_p2_deserialize, - blst_p2_from_affine, blst_p2_mult, blst_p2_to_affine, blst_scalar, blst_scalar_fr_check, - blst_scalar_from_bendian, blst_scalar_from_fr, blst_sha256, blst_uint64_from_fr, BLS12_381_G2, - BLS12_381_NEG_G1, BLS12_381_NEG_G2, BLST_ERROR, + blst_lendian_from_scalar, blst_miller_loop, blst_p1, blst_p1_add, blst_p1_affine, + blst_p1_affine_in_g1, blst_p1_cneg, blst_p1_compress, blst_p1_deserialize, blst_p1_from_affine, + blst_p1_mult, blst_p1_to_affine, blst_p2, blst_p2_add, blst_p2_affine, blst_p2_affine_in_g2, + blst_p2_deserialize, blst_p2_from_affine, blst_p2_mult, blst_p2_to_affine, blst_scalar, + blst_scalar_fr_check, blst_scalar_from_bendian, blst_scalar_from_fr, blst_sha256, + blst_uint64_from_fr, p1_affines, BLS12_381_G2, BLS12_381_NEG_G1, BLS12_381_NEG_G2, BLST_ERROR, }; #[derive(Clone, Copy, Debug)] @@ -120,6 +121,16 @@ impl Fr { bytes } + pub fn to_le_bytes(self) -> [u8; Self::BYTES] { + let mut bytes = [0; Self::BYTES]; + let mut scalar = MaybeUninit::::uninit(); + unsafe { + blst_scalar_from_fr(scalar.as_mut_ptr(), &self.element); + blst_lendian_from_scalar(bytes.as_mut_ptr(), scalar.as_ptr()); + } + bytes + } + pub fn as_u64(&self) -> u64 { let mut out = [0, 0, 0, 0]; unsafe { @@ -322,6 +333,7 @@ impl Shr for Fr { } #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] +#[repr(transparent)] pub struct P1 { element: blst_p1, } @@ -374,17 +386,36 @@ impl P1 { out } - // TODO: optimize w/ pippenger pub fn lincomb(points: impl AsRef<[Self]>, scalars: impl AsRef<[Fr]>) -> Self { let n = cmp::min(points.as_ref().len(), scalars.as_ref().len()); let mut lincomb = Self::INF; for i in 0..n { lincomb = lincomb + (points.as_ref()[i] * scalars.as_ref()[i]); } - lincomb } + pub fn lincomb_pippenger(points: impl AsRef<[Self]>, scalars: impl AsRef<[Fr]>) -> Self { + let n = cmp::min(points.as_ref().len(), scalars.as_ref().len()); + + let points = unsafe { + // NOTE: we can perform the cast from `*const P1` to `*const blst_p1` given + // `repr(transparent)` for `P1` + slice::from_raw_parts(points.as_ref().as_ptr() as *const blst_p1, n) + }; + let points = p1_affines::from(points); + + let scalar_iter = scalars.as_ref().iter().take(n); + let mut scalars = Vec::with_capacity(n * Fr::BYTES); + for scalar in scalar_iter.map(|scalar| scalar.to_le_bytes()) { + scalars.extend_from_slice(scalar.as_slice()); + } + + let lincomb = points.mult(&scalars, 255); + + Self { element: lincomb } + } + // TODO: make available as `const` pub fn neg_generator() -> Self { let mut out = MaybeUninit::::uninit(); diff --git a/src/kzg/poly.rs b/src/kzg/poly.rs index d076016..80cbaf6 100644 --- a/src/kzg/poly.rs +++ b/src/kzg/poly.rs @@ -65,7 +65,7 @@ impl<'a, const N: usize> Polynomial<'a, N> { quotient_poly.push(quotient); } - let lincomb = P1::lincomb(setup.g1_lagrange_brp.as_slice(), quotient_poly); + let lincomb = P1::lincomb_pippenger(setup.g1_lagrange_brp.as_slice(), quotient_poly); (eval, lincomb) }