mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-04 23:03:08 +00:00
180 lines
6.2 KiB
Rust
180 lines
6.2 KiB
Rust
use std::marker::PhantomData;
|
|
|
|
use plonky2::hash::hash_types::RichField;
|
|
use plonky2::iop::generator::{GeneratedValues, SimpleGenerator};
|
|
use plonky2::iop::target::{BoolTarget, Target};
|
|
use plonky2::iop::witness::PartitionWitness;
|
|
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
|
use plonky2_field::extension::Extendable;
|
|
use plonky2_field::secp256k1_base::Secp256K1Base;
|
|
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
|
use plonky2_field::types::{Field, PrimeField};
|
|
|
|
use crate::curve::glv::{decompose_secp256k1_scalar, GLV_BETA, GLV_S};
|
|
use crate::curve::secp256k1::Secp256K1;
|
|
use crate::gadgets::biguint::{GeneratedValuesBigUint, WitnessBigUint};
|
|
use crate::gadgets::curve::{AffinePointTarget, CircuitBuilderCurve};
|
|
use crate::gadgets::curve_msm::curve_msm_circuit;
|
|
use crate::gadgets::nonnative::{CircuitBuilderNonNative, NonNativeTarget};
|
|
|
|
pub trait CircuitBuilderGlv<F: RichField + Extendable<D>, const D: usize> {
|
|
fn secp256k1_glv_beta(&mut self) -> NonNativeTarget<Secp256K1Base>;
|
|
|
|
fn decompose_secp256k1_scalar(
|
|
&mut self,
|
|
k: &NonNativeTarget<Secp256K1Scalar>,
|
|
) -> (
|
|
NonNativeTarget<Secp256K1Scalar>,
|
|
NonNativeTarget<Secp256K1Scalar>,
|
|
BoolTarget,
|
|
BoolTarget,
|
|
);
|
|
|
|
fn glv_mul(
|
|
&mut self,
|
|
p: &AffinePointTarget<Secp256K1>,
|
|
k: &NonNativeTarget<Secp256K1Scalar>,
|
|
) -> AffinePointTarget<Secp256K1>;
|
|
}
|
|
|
|
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilderGlv<F, D>
|
|
for CircuitBuilder<F, D>
|
|
{
|
|
fn secp256k1_glv_beta(&mut self) -> NonNativeTarget<Secp256K1Base> {
|
|
self.constant_nonnative(GLV_BETA)
|
|
}
|
|
|
|
fn decompose_secp256k1_scalar(
|
|
&mut self,
|
|
k: &NonNativeTarget<Secp256K1Scalar>,
|
|
) -> (
|
|
NonNativeTarget<Secp256K1Scalar>,
|
|
NonNativeTarget<Secp256K1Scalar>,
|
|
BoolTarget,
|
|
BoolTarget,
|
|
) {
|
|
let k1 = self.add_virtual_nonnative_target_sized::<Secp256K1Scalar>(4);
|
|
let k2 = self.add_virtual_nonnative_target_sized::<Secp256K1Scalar>(4);
|
|
let k1_neg = self.add_virtual_bool_target();
|
|
let k2_neg = self.add_virtual_bool_target();
|
|
|
|
self.add_simple_generator(GLVDecompositionGenerator::<F, D> {
|
|
k: k.clone(),
|
|
k1: k1.clone(),
|
|
k2: k2.clone(),
|
|
k1_neg,
|
|
k2_neg,
|
|
_phantom: PhantomData,
|
|
});
|
|
|
|
// Check that `k1_raw + GLV_S * k2_raw == k`.
|
|
let k1_raw = self.nonnative_conditional_neg(&k1, k1_neg);
|
|
let k2_raw = self.nonnative_conditional_neg(&k2, k2_neg);
|
|
let s = self.constant_nonnative(GLV_S);
|
|
let mut should_be_k = self.mul_nonnative(&s, &k2_raw);
|
|
should_be_k = self.add_nonnative(&should_be_k, &k1_raw);
|
|
self.connect_nonnative(&should_be_k, k);
|
|
|
|
(k1, k2, k1_neg, k2_neg)
|
|
}
|
|
|
|
fn glv_mul(
|
|
&mut self,
|
|
p: &AffinePointTarget<Secp256K1>,
|
|
k: &NonNativeTarget<Secp256K1Scalar>,
|
|
) -> AffinePointTarget<Secp256K1> {
|
|
let (k1, k2, k1_neg, k2_neg) = self.decompose_secp256k1_scalar(k);
|
|
|
|
let beta = self.secp256k1_glv_beta();
|
|
let beta_px = self.mul_nonnative(&beta, &p.x);
|
|
let sp = AffinePointTarget::<Secp256K1> {
|
|
x: beta_px,
|
|
y: p.y.clone(),
|
|
};
|
|
|
|
let p_neg = self.curve_conditional_neg(p, k1_neg);
|
|
let sp_neg = self.curve_conditional_neg(&sp, k2_neg);
|
|
curve_msm_circuit(self, &p_neg, &sp_neg, &k1, &k2)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct GLVDecompositionGenerator<F: RichField + Extendable<D>, const D: usize> {
|
|
k: NonNativeTarget<Secp256K1Scalar>,
|
|
k1: NonNativeTarget<Secp256K1Scalar>,
|
|
k2: NonNativeTarget<Secp256K1Scalar>,
|
|
k1_neg: BoolTarget,
|
|
k2_neg: BoolTarget,
|
|
_phantom: PhantomData<F>,
|
|
}
|
|
|
|
impl<F: RichField + Extendable<D>, const D: usize> SimpleGenerator<F>
|
|
for GLVDecompositionGenerator<F, D>
|
|
{
|
|
fn dependencies(&self) -> Vec<Target> {
|
|
self.k.value.limbs.iter().map(|l| l.0).collect()
|
|
}
|
|
|
|
fn run_once(&self, witness: &PartitionWitness<F>, out_buffer: &mut GeneratedValues<F>) {
|
|
let k = Secp256K1Scalar::from_noncanonical_biguint(
|
|
witness.get_biguint_target(self.k.value.clone()),
|
|
);
|
|
|
|
let (k1, k2, k1_neg, k2_neg) = decompose_secp256k1_scalar(k);
|
|
|
|
out_buffer.set_biguint_target(&self.k1.value, &k1.to_canonical_biguint());
|
|
out_buffer.set_biguint_target(&self.k2.value, &k2.to_canonical_biguint());
|
|
out_buffer.set_bool_target(self.k1_neg, k1_neg);
|
|
out_buffer.set_bool_target(self.k2_neg, k2_neg);
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use anyhow::Result;
|
|
use plonky2::iop::witness::PartialWitness;
|
|
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
|
use plonky2::plonk::circuit_data::CircuitConfig;
|
|
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
|
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
|
use plonky2_field::types::Field;
|
|
|
|
use crate::curve::curve_types::{Curve, CurveScalar};
|
|
use crate::curve::glv::glv_mul;
|
|
use crate::curve::secp256k1::Secp256K1;
|
|
use crate::gadgets::curve::CircuitBuilderCurve;
|
|
use crate::gadgets::glv::CircuitBuilderGlv;
|
|
use crate::gadgets::nonnative::CircuitBuilderNonNative;
|
|
|
|
#[test]
|
|
#[ignore]
|
|
fn test_glv_gadget() -> Result<()> {
|
|
const D: usize = 2;
|
|
type C = PoseidonGoldilocksConfig;
|
|
type F = <C as GenericConfig<D>>::F;
|
|
|
|
let config = CircuitConfig::standard_ecc_config();
|
|
|
|
let pw = PartialWitness::new();
|
|
let mut builder = CircuitBuilder::<F, D>::new(config);
|
|
|
|
let rando =
|
|
(CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE).to_affine();
|
|
let randot = builder.constant_affine_point(rando);
|
|
|
|
let scalar = Secp256K1Scalar::rand();
|
|
let scalar_target = builder.constant_nonnative(scalar);
|
|
|
|
let rando_glv_scalar = glv_mul(rando.to_projective(), scalar);
|
|
let expected = builder.constant_affine_point(rando_glv_scalar.to_affine());
|
|
let actual = builder.glv_mul(&randot, &scalar_target);
|
|
builder.connect_affine_point(&expected, &actual);
|
|
|
|
dbg!(builder.num_gates());
|
|
let data = builder.build::<C>();
|
|
let proof = data.prove(pw).unwrap();
|
|
|
|
data.verify(proof)
|
|
}
|
|
}
|