diff --git a/plonky2/src/gadgets/glv.rs b/plonky2/src/gadgets/glv.rs new file mode 100644 index 00000000..c5790640 --- /dev/null +++ b/plonky2/src/gadgets/glv.rs @@ -0,0 +1,89 @@ +use std::marker::PhantomData; + +use plonky2_field::extension_field::Extendable; +use plonky2_field::secp256k1_base::Secp256K1Base; +use plonky2_field::secp256k1_scalar::Secp256K1Scalar; + +use crate::curve::glv::{decompose_secp256k1_scalar, BETA}; +use crate::curve::secp256k1::Secp256K1; +use crate::gadgets::curve::AffinePointTarget; +use crate::gadgets::nonnative::NonNativeTarget; +use crate::hash::hash_types::RichField; +use crate::iop::generator::{GeneratedValues, SimpleGenerator}; +use crate::iop::target::Target; +use crate::iop::witness::{PartitionWitness, Witness}; +use crate::plonk::circuit_builder::CircuitBuilder; + +impl, const D: usize> CircuitBuilder { + pub fn secp256k1_glv_beta(&mut self) -> NonNativeTarget { + self.constant_nonnative(BETA) + } + + pub fn decompose_secp256k1_scalar( + &mut self, + k: &NonNativeTarget, + ) -> ( + NonNativeTarget, + NonNativeTarget, + ) { + let k1 = self.add_virtual_nonnative_target::(); + let k2 = self.add_virtual_nonnative_target::(); + + self.add_simple_generator(GLVDecompositionGenerator:: { + k: k.clone(), + k1: k1.clone(), + k2: k2.clone(), + _phantom: PhantomData, + }); + + (k1, k2) + } + + pub fn glv_mul( + &mut self, + k: &NonNativeTarget, + p: &AffinePointTarget, + ) -> AffinePointTarget { + let (k1, k2) = self.decompose_secp256k1_scalar(k); + + let beta = self.secp256k1_glv_beta(); + let beta_px = self.mul_nonnative(&beta, &p.x); + let sp = AffinePointTarget:: { + x: beta_px, + y: p.y.clone(), + }; + + // TODO: replace with MSM + let part1 = self.curve_scalar_mul(&p, &k1); + let part2 = self.curve_scalar_mul(&sp, &k2); + + self.curve_add(&part1, &part2) + } +} + +#[derive(Debug)] +struct GLVDecompositionGenerator, const D: usize> { + k: NonNativeTarget, + k1: NonNativeTarget, + k2: NonNativeTarget, + _phantom: PhantomData, +} + +impl, const D: usize> SimpleGenerator + for GLVDecompositionGenerator +{ + fn dependencies(&self) -> Vec { + self.k.value.limbs.iter().map(|l| l.0).collect() + } + + fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { + let k = witness.get_nonnative_target(self.k.clone()); + let (k1, k2) = decompose_secp256k1_scalar(k); + + out_buffer.set_nonnative_target(self.k1.clone(), k1); + out_buffer.set_nonnative_target(self.k2.clone(), k2); + } +} + +#[cfg(test)] +mod tests {} diff --git a/plonky2/src/gadgets/mod.rs b/plonky2/src/gadgets/mod.rs index ec4d1263..c3dd4a54 100644 --- a/plonky2/src/gadgets/mod.rs +++ b/plonky2/src/gadgets/mod.rs @@ -4,6 +4,7 @@ pub mod arithmetic_u32; pub mod biguint; pub mod curve; pub mod ecdsa; +pub mod glv; pub mod hash; pub mod interpolation; pub mod multiple_comparison;