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}