arnaucube
arnaucube/plonky2-recursion-experimentPublic Self-hosted repository
plonky2-recursion-experiment/src/sig_gadget.rs
src/sig_gadget.rsRaw
  1use anyhow::Result;
  2use plonky2::iop::target::{BoolTarget, Target};
  3use plonky2::iop::witness::{PartialWitness, WitnessWrite};
  4use plonky2::plonk::circuit_builder::CircuitBuilder;
  5
  6use sch::schnorr::*;
  7use sch::schnorr_prover::*;
  8
  9use super::{C, D, F};
 10
 11/// if s==0: returns x
 12/// if s==1: returns y
 13/// Warning: this method assumes all input values are ensured to be \in {0,1}
 14fn selector_gate(builder: &mut CircuitBuilder<F, D>, x: Target, y: Target, s: Target) -> Target {
 15    // z = x + s(y-x)
 16    let y_x = builder.sub(y, x);
 17    // z = x+s(y-x) <==> mul_add(s, yx, x)=s*(y-x)+x
 18    builder.mul_add(s, y_x, x)
 19}
 20
 21/// ensures b \in {0,1}
 22fn binary_check(builder: &mut CircuitBuilder<F, D>, b: Target) {
 23    let zero = builder.zero();
 24    let one = builder.one();
 25    // b * (b-1) == 0
 26    let b_1 = builder.sub(b, one);
 27    let r = builder.mul(b, b_1);
 28    builder.connect(r, zero);
 29}
 30
 31pub struct PODInput {
 32    pub pk: SchnorrPublicKey,
 33    pub sig: SchnorrSignature,
 34}
 35
 36/// The logic of this gadget verifies the given signature if `selector==0`.
 37/// We reuse this gadget for all the the signature verifications in the node of the recursion tree.
 38///
 39/// Contains the methods to `add_targets` (ie. create the targets, the logic of the circuit), and
 40/// `set_targets` (ie. set the specific values to be used for the previously created targets).
 41pub struct PODGadgetTargets {
 42    pub selector_targ: Target,
 43    pub selector_booltarg: BoolTarget,
 44
 45    pub pk_targ: SchnorrPublicKeyTarget,
 46    pub sig_targ: SchnorrSignatureTarget,
 47}
 48
 49impl PODGadgetTargets {
 50    pub fn add_targets(
 51        mut builder: &mut CircuitBuilder<F, D>,
 52        msg_targ: &MessageTarget,
 53    ) -> Result<Self> {
 54        let selector_targ = builder.add_virtual_target();
 55        // ensure that selector_booltarg is \in {0,1}
 56        binary_check(builder, selector_targ);
 57        let selector_booltarg = BoolTarget::new_unsafe(selector_targ);
 58
 59        // signature verification:
 60        let sb: SchnorrBuilder = SchnorrBuilder {};
 61        let pk_targ = SchnorrPublicKeyTarget::new_virtual(&mut builder);
 62        let sig_targ = SchnorrSignatureTarget::new_virtual(&mut builder);
 63        let sig_verif_targ = sb.verify_sig::<C>(&mut builder, &sig_targ, &msg_targ, &pk_targ);
 64
 65        // - if selector=0
 66        //     verify_sig==1 && proof_enabled=0
 67        // - if selector=1
 68        //     verify_sig==NaN && proof_enabled=1   (don't check the sig)
 69        //
 70        // if selector=0: check that sig_verif==1
 71        // if selector=1: check that one==1
 72        let one = builder.one();
 73        let expected = selector_gate(
 74            builder,
 75            sig_verif_targ.target,
 76            one,
 77            selector_booltarg.target,
 78        );
 79        let one_2 = builder.one();
 80        builder.connect(expected, one_2);
 81
 82        Ok(Self {
 83            selector_targ,
 84            selector_booltarg,
 85            pk_targ,
 86            sig_targ,
 87        })
 88    }
 89    pub fn set_targets(
 90        &mut self,
 91        pw: &mut PartialWitness<F>,
 92        // if `selector` set to 0 will verify the given signature, if set to 1 won't (and the
 93        // recursion layer will verify the respective plonky2 proof)
 94        selector: F,
 95        pod: &PODInput,
 96    ) -> Result<()> {
 97        pw.set_target(self.selector_targ, selector)?;
 98
 99        // set signature related values:
100        self.pk_targ.set_witness(pw, &pod.pk).unwrap();
101        self.sig_targ.set_witness(pw, &pod.sig).unwrap();
102
103        Ok(())
104    }
105}