arkeddsa/src/constraints.rs
src/constraints.rsRaw
1/// This file implements the EdDSA verification in-circuit.
2use ark_crypto_primitives::sponge::{
3 constraints::CryptographicSpongeVar,
4 poseidon::{constraints::PoseidonSpongeVar, PoseidonConfig},
5};
6use ark_ec::CurveGroup;
7use ark_ff::Field;
8use ark_r1cs_std::{
9 boolean::Boolean,
10 convert::{ToBitsGadget, ToConstraintFieldGadget},
11 fields::emulated_fp::EmulatedFpVar,
12 fields::fp::FpVar,
13 groups::CurveVar,
14};
15use ark_relations::r1cs::ConstraintSystemRef;
16
17/// CF stands for ConstraintField
18pub type CF<C> = <<C as CurveGroup>::BaseField as Field>::BasePrimeField;
19
20/// gadget to compute the EdDSA verification in-circuit
21pub fn verify<C, GC>(
22 cs: ConstraintSystemRef<CF<C>>,
23 poseidon_config: PoseidonConfig<CF<C>>,
24 pk: GC,
25 // sig: (GC, NonNativeFieldVar<C::ScalarField, CF<C>>),
26 sig: (GC, Vec<Boolean<CF<C>>>),
27 msg: FpVar<CF<C>>,
28) -> ark_relations::r1cs::Result<Boolean<CF<C>>>
29where
30 C: CurveGroup,
31 GC: CurveVar<C, CF<C>> + ToConstraintFieldGadget<CF<C>>,
32{
33 // let (r, s): (GC, NonNativeFieldVar<C::ScalarField, CF<C>>) = sig;
34 let (r, s): (GC, Vec<Boolean<CF<C>>>) = sig;
35
36 let r_xy = r.to_constraint_field()?;
37 let pk_xy = pk.to_constraint_field()?;
38
39 let mut poseidon = PoseidonSpongeVar::new(cs.clone(), &poseidon_config);
40 poseidon.absorb(&r_xy)?;
41 poseidon.absorb(&pk_xy)?;
42 poseidon.absorb(&msg)?;
43 let k = poseidon.squeeze_field_elements(1)?;
44 let k = k
45 .first()
46 .ok_or(ark_relations::r1cs::SynthesisError::Unsatisfiable)?;
47
48 let kx_b = pk.scalar_mul_le(k.to_bits_le()?.iter())?;
49
50 let g = GC::new_constant(cs.clone(), C::generator())?;
51 // let s_b = g.scalar_mul_le(s.to_bits_le()?.iter())?;
52 let s_b = g.scalar_mul_le(s.iter())?;
53 let r_rec: GC = s_b - kx_b;
54 Ok(r_rec.is_eq(&r)?)
55}
56
57#[cfg(test)]
58mod tests {
59 use ark_ff::{BigInteger, PrimeField};
60 use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget, fields::emulated_fp::EmulatedFpVar};
61 use ark_relations::r1cs::ConstraintSystem;
62 use rand_core::OsRng;
63
64 use super::*;
65 use crate::ed_on_bn254_twist::{
66 constraints::EdwardsVar as GVar, BaseField as Fq, EdwardsConfig, EdwardsProjective as G,
67 ScalarField as Fr,
68 };
69 use crate::{poseidon_config, SigningKey};
70
71 #[test]
72 fn gadget_verify() {
73 let poseidon_config = poseidon_config::<Fq>(4, 8, 60);
74 let sk = SigningKey::<G>::generate::<blake2::Blake2b512>(&mut OsRng).unwrap();
75 let msg_raw = b"xxx yyy <<< zzz >>> bunny";
76 let msg = Fq::from_le_bytes_mod_order(msg_raw);
77 let sig = sk
78 .sign::<blake2::Blake2b512>(&poseidon_config, &msg)
79 .unwrap();
80 let pk = sk.public_key();
81 pk.verify(&poseidon_config, &msg, &sig).unwrap();
82
83 let cs = ConstraintSystem::<Fq>::new_ref();
84 let pk_var: GVar = GVar::new_witness(cs.clone(), || Ok(*pk.as_ref())).unwrap();
85 let r_var: GVar = GVar::new_witness(cs.clone(), || Ok(*sig.r())).unwrap();
86 let s_var =
87 Vec::<Boolean<Fq>>::new_witness(cs.clone(), || Ok(sig.s().into_bigint().to_bits_le()))
88 .unwrap();
89 let msg_var = FpVar::<Fq>::new_witness(cs.clone(), || Ok(msg)).unwrap();
90
91 let res = verify::<G, GVar>(cs.clone(), poseidon_config, pk_var, (r_var, s_var), msg_var)
92 .unwrap();
93 res.enforce_equal(&Boolean::<Fq>::TRUE).unwrap();
94
95 dbg!(cs.num_constraints());
96 assert!(cs.is_satisfied().unwrap());
97 }
98}