arnaucube
arnaucube/sigmabus-pocPublic Self-hosted repository
sigmabus-poc/src/sigmabus.rs
src/sigmabus.rsRaw
  1use ark_crypto_primitives::{
  2    crh::{poseidon::CRH, CRHScheme},
  3    snark::SNARK,
  4    sponge::{poseidon::PoseidonConfig, Absorb},
  5};
  6use ark_ec::{pairing::Pairing, CurveGroup, Group};
  7use ark_groth16::{Groth16, Proof as Groth16Proof};
  8use ark_std::{
  9    rand::{CryptoRng, Rng},
 10    UniformRand, Zero,
 11};
 12use std::marker::PhantomData;
 13use std::ops::Mul;
 14
 15use crate::circuits::GenZKCircuit;
 16use crate::transcript::PoseidonTranscript;
 17use crate::Error;
 18
 19/// Proof represents the Sigmabus proof
 20pub struct Proof<E: Pairing> {
 21    cm: E::ScalarField,
 22    sigma_proof: SigmaProof<E::G1>,
 23    zkproof: Groth16Proof<E>,
 24}
 25
 26/// SigmaProof represents the Sigma protocol proof (not Sigmabus proof)
 27pub struct SigmaProof<C: CurveGroup> {
 28    pub s: C::ScalarField,
 29    pub R: C,
 30    pub r_h: C::ScalarField,
 31}
 32
 33pub struct Params<E: Pairing> {
 34    _e: PhantomData<E>,
 35    poseidon_config: PoseidonConfig<E::ScalarField>,
 36    pk: <Groth16<E> as SNARK<E::ScalarField>>::ProvingKey,
 37    vk: <Groth16<E> as SNARK<E::ScalarField>>::VerifyingKey,
 38}
 39
 40/// Sigmabus implements [Sigmabus](https://eprint.iacr.org/2023/1406) prover & verifier for proving
 41/// X=x*G as described in section 3 of the paper, using Groth16's zkSNARK scheme.
 42pub struct Sigmabus<E: Pairing> {
 43    _e: PhantomData<E>,
 44}
 45
 46impl<E: Pairing> Sigmabus<E>
 47where
 48    E::ScalarField: Absorb,
 49{
 50    pub fn setup<R: Rng + CryptoRng>(
 51        rng: &mut R,
 52        poseidon_config: &PoseidonConfig<E::ScalarField>,
 53    ) -> Params<E> {
 54        let circuit = GenZKCircuit::<E::G1> {
 55            _c: PhantomData,
 56            poseidon_config: poseidon_config.clone(),
 57            // public
 58            cm: E::ScalarField::zero(),
 59            s: E::ScalarField::zero(),
 60            r_h: E::ScalarField::zero(),
 61            c: E::ScalarField::zero(),
 62            // private
 63            x: E::ScalarField::zero(),
 64            r: E::ScalarField::zero(),
 65            o_h: E::ScalarField::zero(),
 66        };
 67
 68        // generate the snark proof
 69        let (pk, vk) = Groth16::<E>::circuit_specific_setup(circuit.clone(), rng).unwrap();
 70        Params::<E> {
 71            _e: PhantomData,
 72            poseidon_config: poseidon_config.clone(),
 73            pk,
 74            vk,
 75        }
 76    }
 77
 78    pub fn prove<R: Rng + CryptoRng>(
 79        rng: &mut R,
 80        params: &Params<E>,
 81        transcript: &mut PoseidonTranscript<E::G1>,
 82        x: E::ScalarField,
 83    ) -> Result<Proof<E>, Error> {
 84        // cm
 85        let cm: E::ScalarField =
 86            CRH::<E::ScalarField>::evaluate(&params.poseidon_config, [x]).unwrap();
 87        transcript.absorb(&cm);
 88
 89        let r = E::ScalarField::rand(rng);
 90        let o_h = E::ScalarField::rand(rng);
 91
 92        let R = E::G1::generator().mul(r);
 93
 94        let r_h: E::ScalarField =
 95            CRH::<E::ScalarField>::evaluate(&params.poseidon_config, [r, o_h]).unwrap();
 96
 97        transcript.absorb_point(&R);
 98        transcript.absorb(&r_h);
 99
100        let c = transcript.get_challenge();
101
102        let s = r + c * x;
103
104        let circuit = GenZKCircuit::<E::G1> {
105            _c: PhantomData,
106            poseidon_config: params.poseidon_config.clone(),
107            // public
108            cm,
109            s,
110            r_h,
111            c,
112            // private
113            x,
114            r,
115            o_h,
116        };
117
118        // generate the snark proof
119        let zkproof = Groth16::<E>::prove(&params.pk, circuit.clone(), rng).unwrap();
120
121        Ok(Proof {
122            cm,
123            sigma_proof: SigmaProof { s, R, r_h },
124            zkproof,
125        })
126    }
127
128    pub fn verify(
129        params: &Params<E>,
130        transcript: &mut PoseidonTranscript<E::G1>,
131        proof: Proof<E>,
132        X: E::G1,
133    ) -> Result<(), Error> {
134        let lhs = E::G1::generator().mul(proof.sigma_proof.s);
135
136        transcript.absorb(&proof.cm);
137        transcript.absorb_point(&proof.sigma_proof.R);
138        transcript.absorb(&proof.sigma_proof.r_h);
139        let c = transcript.get_challenge();
140
141        let rhs = proof.sigma_proof.R + X.mul(c);
142
143        if lhs != rhs {
144            return Err(Error::SigmaFail);
145        }
146
147        // verify zkSNARK proof
148        let public_input = [proof.cm, proof.sigma_proof.s, proof.sigma_proof.r_h, c];
149
150        let valid_proof = Groth16::<E>::verify(&params.vk, &public_input, &proof.zkproof).unwrap();
151        if !valid_proof {
152            return Err(Error::GenZKFail);
153        }
154
155        Ok(())
156    }
157}
158
159#[cfg(test)]
160mod tests {
161    use super::*;
162    use ark_bn254::{Bn254, Fr, G1Projective};
163    use ark_std::rand::{RngCore, SeedableRng};
164    use ark_std::test_rng;
165
166    use crate::transcript::tests::poseidon_test_config;
167
168    #[test]
169    fn test_sigmabus_prove_verify() {
170        let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64());
171        let poseidon_config = poseidon_test_config::<Fr>();
172
173        // generate the trusted setup
174        let params = Sigmabus::<Bn254>::setup(&mut rng, &poseidon_config);
175
176        // compute X = x * G
177        let x = Fr::rand(&mut rng);
178        let X = G1Projective::generator().mul(x);
179
180        let mut transcript_p = PoseidonTranscript::<G1Projective>::new(&poseidon_config);
181
182        // generate Sigmabus proof for X==x*G
183        let proof = Sigmabus::<Bn254>::prove(&mut rng, &params, &mut transcript_p, x).unwrap();
184
185        // verify Sigmabus proof for X==x*G
186        let mut transcript_v = PoseidonTranscript::<G1Projective>::new(&poseidon_config);
187        Sigmabus::<Bn254>::verify(&params, &mut transcript_v, proof, X).unwrap();
188    }
189}