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}