arnaucube
arnaucube/schnorrPublic Self-hosted repository
schnorr/src/schnorr_prover.rs
src/schnorr_prover.rsRaw
  1use anyhow::Result;
  2use plonky2::iop::generator::{GeneratedValues, SimpleGenerator};
  3use plonky2::iop::target::{BoolTarget, Target};
  4use plonky2::iop::witness::{PartialWitness, PartitionWitness, Witness, WitnessWrite};
  5use plonky2::field::extension::{Extendable, FieldExtension};
  6use plonky2::field::types::{Field, PrimeField64};
  7use plonky2::field::goldilocks_field::GoldilocksField;
  8use plonky2::hash::hash_types::RichField;
  9use plonky2::hash::poseidon::PoseidonHash;
 10use plonky2::plonk::circuit_builder::CircuitBuilder;
 11use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitData, VerifierOnlyCircuitData};
 12use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
 13use plonky2::plonk::proof::ProofWithPublicInputs;
 14use plonky2::util::serialization::{Buffer, IoResult, Read, Write};
 15
 16type GoldF = GoldilocksField;
 17
 18pub struct MessageTarget {
 19    msg: Vec<Target>,
 20}
 21
 22impl MessageTarget {
 23    fn new_with_size(builder: &mut CircuitBuilder<GoldF, 2>, n: usize) -> Self {
 24        Self {
 25            msg: builder.add_virtual_targets(n),
 26        }
 27    }
 28}
 29
 30pub struct SchnorrSignatureTarget {
 31    s: Target,
 32    e: Target,
 33}
 34
 35impl SchnorrSignatureTarget {
 36    fn new_virtual(builder: &mut CircuitBuilder<GoldF, 2>) -> Self {
 37        let s = builder.add_virtual_target();
 38        let e = builder.add_virtual_target();
 39        Self{ s, e }
 40    }
 41}
 42
 43pub struct SchnorrPublicKeyTarget {
 44    pk: Target,
 45}
 46
 47#[derive(Debug, Default)]
 48pub struct Mod65537Generator {
 49    a: Target,
 50    q: Target,
 51    r: Target,
 52}
 53
 54impl SimpleGenerator<GoldF, 2> for Mod65537Generator {
 55    fn id(&self) -> String {
 56        "Mod65537Generator".to_string()
 57    }
 58    fn dependencies(&self) -> Vec<Target> {
 59        vec![self.a]
 60    }
 61
 62    fn run_once(
 63        &self,
 64        witness: &PartitionWitness<GoldF>,
 65        out_buffer: &mut GeneratedValues<GoldF>,
 66    ) -> Result<()> {
 67        let a = witness.get_target(self.a);
 68        let a64 = a.to_canonical_u64();
 69        let q64 = a64 / 65537;
 70        let r64 = a64 % 65537;
 71
 72        out_buffer.set_target(self.q, GoldF::from_canonical_u64(q64));
 73        out_buffer.set_target(self.r, GoldF::from_canonical_u64(r64));
 74
 75        Ok(())
 76    }
 77
 78    fn serialize(&self, dst: &mut Vec<u8>, common_data: &CommonCircuitData<GoldF, 2>) -> IoResult<()> {
 79        println!("SERIALIZATION!  What is this good for?");
 80        dst.write_target(self.a)?;
 81        dst.write_target(self.q)?;
 82        dst.write_target(self.r)?;
 83        Ok(())
 84    }
 85
 86    fn deserialize(src: &mut Buffer, common_data: &CommonCircuitData<GoldF, 2>) -> IoResult<Self>
 87    where
 88        Self: Sized 
 89    {
 90            println!("DESERIALIZATION!  What is this good for?");
 91            let a = src.read_target()?;
 92            let q = src.read_target()?;
 93            let r = src.read_target()?;
 94            OK(Self { a, q, r })
 95    }
 96}
 97
 98pub struct SchnorrBuilder {
 99
100}
101
102impl SchnorrBuilder {
103    // Reduce a modulo the constant 65537
104    // where a is the canonical representative for an element of the field
105    // (meaning: 0 \leq a < p)
106
107    // To verify this, write
108    // a = 65537 * q + r, and do range checks to check that:
109    // 0 <= q <= floor(p / 65537)
110    // 0 <= r < 65537
111    // (these first two checks guarantee that a lies in the range [0, p + 65536])
112    // if q = floor(p / 65537) then r = 0
113    // (note that p % 65537 == 1 so this is the only possibility)
114    fn mod_65537 <
115        C: GenericConfig<2, F = GoldF>,
116    > (
117        builder: &mut CircuitBuilder::<GoldF, 2>,
118        a: &Target,
119    ) -> Target {
120        let q = builder.add_virtual_target();
121        let r = builder.add_virtual_target();
122
123        // the Mod65537Generator will assign values to q and r later
124        builder.add_simple_generator( Mod65537Generator { a, q, r } );
125
126        // impose four constraints
127        // 1. a = 65537 * q + r
128        let t65537 = builder.constant(GoldF::from_canonical_u64(65537));
129        let a_copy = builder.mul_add(t65537, q, r);
130        builder.connect(*a, a_copy);
131
132        // 2. 0 <= q <= floor(p / 65537)
133        // max_q is 281470681743360 = floor(p / 65537) = (p-1) / 65537 = 2^48 - 2^32
134        let max_q = builder.constant(GoldF::from_canonical_u64(281470681743360));
135        builder.range_check(q, 48);
136        builder.range_check(builder.sub(max_q, q), 48);
137
138        // 3. 0 <= r < 65537
139        let max_r = builder.constant(GoldF::from_canonical_u64(65537));
140        builder.range_check(r, 17);
141        builder.range_check(builder.sub(max_r, r), 17);
142
143        // 4. if q = floor(p / 65537) then r = 0
144        let q_equals_max = builder.is_equal(q, max_q);
145        builder.connect(builder.mul(q_equals_max.target, r), builder.zero());
146
147        r
148    }
149
150    fn constrain_sig <
151        C: GenericConfig<2, F = GoldF>,
152    > (
153        &self,
154        builder: &mut CircuitBuilder::<GoldF, 2>,
155        sig: &SchnorrSignatureTarget,
156        msg: &MessageTarget,
157        pk: &SchnorrPublicKeyTarget,
158    ) -> () {
159        let PRIME_GROUP_GEN: Target = builder.constant(GoldF::from_canonical_u64(6612579038192137166));
160        let PRIME_GROUP_ORDER: Target = builder.constant(GoldF::from_canonical_u64(65537));
161        const num_bits_exp: usize = 32;
162
163        /*
164        let r: GoldF = Self::pow(self.PRIME_GROUP_GEN, sig.s)
165            * Self::pow(pk.pk, sig.e);
166        let e_v: u64 = self.hash_insecure(&r, msg);
167        e_v == sig.e   */
168
169        let gs: Target = builder.exp(PRIME_GROUP_GEN, sig.s, num_bits_exp);
170        let pe: Target = builder.exp(pk.pk, sig.e, num_bits_exp);
171        let r: Target = builder.mul(gs, pe);
172
173        // compute hash
174        // note that it's safe to clone Targets since they just contain indices
175        let hash_input: Vec<Target> = std::iter::once(r)
176            .chain(msg.msg.iter().cloned()) 
177            .collect();
178        let e: Target = builder.hash_n_to_hash_no_pad::<PoseidonHash>(
179            hash_input,
180        ).elements[0] // whoops have to take mod group order;
181
182        // enforce equality
183        builder.connect(e, sig.e);
184    }
185}
186
187#[cfg(test)]
188mod tests{
189    use crate::schnorr::{SchnorrPublicKey, SchnorrSecretKey, SchnorrSigner, SchnorrSignature};
190    use crate::schnorr_prover::SchnorrBuilder;
191    use plonky2::plonk::circuit_builder::CircuitBuilder;
192    use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, CommonCircuitData, VerifierCircuitData, VerifierOnlyCircuitData};
193    use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
194    use plonky2::field::goldilocks_field::GoldilocksField;
195    use rand;
196
197    #[test]
198    fn test_schnorr() -> () {
199        const D: usize = 2;
200        type C = PoseidonGoldilocksConfig;
201        type F = <C as GenericConfig<D>>::F;
202
203        let mut rng: rand::rngs::ThreadRng = rand::thread_rng();
204
205        let config = CircuitConfig::standard_recursion_config();
206        let mut builder = CircuitBuilder::<F, D>::new(config);
207
208        builder.add_virtual_fri_proof(num_leaves_per_oracle, params)
209
210        let sb: SchnorrBuilder = SchnorrBuilder{};
211
212        // create keypair, message, signature
213        let sk: SchnorrSecretKey = SchnorrSecretKey{ sk: 133 };
214        let ss = SchnorrSigner::new();
215        let pk: SchnorrPublicKey = ss.keygen(&sk);
216        let msg: Vec<GoldilocksField> = ss.u64_into_goldilocks_vec(
217            vec![1500, 1600, 0, 0, 0]
218        );
219        let msg_size: usize = msg.len();
220        let sig: SchnorrSignature = ss.sign(&msg, &sk, &mut rng);
221
222        let sig_target = builder.constant(sig);
223        // instead of verifying we're going to prove the verification
224        sb.constrain_sig(
225            &mut builder,
226            &sig,
227            &msg,
228            &pk
229        );
230    }
231}