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
31/// The logic of this gadget verifies the given signature if `selector==0`.
32/// We reuse this gadget for all the the signature verifications in the node of the recursion tree.
33///
34/// Contains the methods to `build` (ie. create the targets, the logic of the circuit), and
35/// `fill_targets` (ie. set the specific values to be used for the previously created targets).
36pub struct SignatureGadgetTargets {
37    pub selector_targ: Target,
38    pub selector_booltarg: BoolTarget,
39
40    pub pk_targ: SchnorrPublicKeyTarget,
41    pub sig_targ: SchnorrSignatureTarget,
42}
43impl SignatureGadgetTargets {
44    pub fn build(
45        mut builder: &mut CircuitBuilder<F, D>,
46        msg_targ: &MessageTarget,
47    ) -> Result<SignatureGadgetTargets> {
48        let selector_targ = builder.add_virtual_target();
49        // ensure that selector_booltarg is \in {0,1}
50        binary_check(builder, selector_targ);
51        let selector_booltarg = BoolTarget::new_unsafe(selector_targ);
52
53        // signature verification:
54        let sb: SchnorrBuilder = SchnorrBuilder {};
55        let pk_targ = SchnorrPublicKeyTarget::new_virtual(&mut builder);
56        let sig_targ = SchnorrSignatureTarget::new_virtual(&mut builder);
57        let sig_verif_targ = sb.verify_sig::<C>(&mut builder, &sig_targ, &msg_targ, &pk_targ);
58
59        // - if selector=0
60        //     verify_sig==1 && proof_enabled=0
61        // - if selector=1
62        //     verify_sig==NaN && proof_enabled=1   (don't check the sig)
63        //
64        // if selector=0: check that sig_verif==1
65        // if selector=1: check that one==1
66        let one = builder.one();
67        let expected = selector_gate(
68            builder,
69            sig_verif_targ.target,
70            one,
71            selector_booltarg.target,
72        );
73        let one_2 = builder.one();
74        builder.connect(expected, one_2);
75
76        Ok(Self {
77            selector_targ,
78            selector_booltarg,
79            pk_targ,
80            sig_targ,
81        })
82    }
83    pub fn fill_targets(
84        &mut self,
85        pw: &mut PartialWitness<F>,
86        selector: F, // 1=proof, 0=sig
87        pk: &SchnorrPublicKey,
88        sig: &SchnorrSignature,
89    ) -> Result<()> {
90        pw.set_target(self.selector_targ, selector)?;
91
92        // set signature related values:
93        self.pk_targ.set_witness(pw, &pk).unwrap();
94        self.sig_targ.set_witness(pw, &sig).unwrap();
95
96        Ok(())
97    }
98}