arnaucube
arnaucube/circom-compatPublic Self-hosted repository
circom-compat/src/ethereum.rs
src/ethereum.rsRaw
  1//! Helpers for converting Arkworks types to U256-tuples as expected by the
  2//! Solidity Groth16 Verifier smart contracts
  3use ark_ff::{BigInteger, FromBytes, PrimeField};
  4use ethers_core::types::U256;
  5use num_traits::Zero;
  6
  7use ark_bn254::{Bn254, Fq, Fq2, Fr, G1Affine, G2Affine};
  8
  9pub struct Inputs(pub Vec<U256>);
 10
 11impl From<&[Fr]> for Inputs {
 12    fn from(src: &[Fr]) -> Self {
 13        let els = src.iter().map(|point| point_to_u256(*point)).collect();
 14
 15        Self(els)
 16    }
 17}
 18
 19#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 20pub struct G1 {
 21    pub x: U256,
 22    pub y: U256,
 23}
 24
 25impl From<G1> for G1Affine {
 26    fn from(src: G1) -> G1Affine {
 27        let x: Fq = u256_to_point(src.x);
 28        let y: Fq = u256_to_point(src.y);
 29        let inf = x.is_zero() && y.is_zero();
 30        G1Affine::new(x, y, inf)
 31    }
 32}
 33
 34type G1Tup = (U256, U256);
 35
 36impl G1 {
 37    pub fn as_tuple(&self) -> (U256, U256) {
 38        (self.x, self.y)
 39    }
 40}
 41
 42impl From<&G1Affine> for G1 {
 43    fn from(p: &G1Affine) -> Self {
 44        Self {
 45            x: point_to_u256(p.x),
 46            y: point_to_u256(p.y),
 47        }
 48    }
 49}
 50
 51#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 52pub struct G2 {
 53    pub x: [U256; 2],
 54    pub y: [U256; 2],
 55}
 56
 57impl From<G2> for G2Affine {
 58    fn from(src: G2) -> G2Affine {
 59        let c0 = u256_to_point(src.x[0]);
 60        let c1 = u256_to_point(src.x[1]);
 61        let x = Fq2::new(c0, c1);
 62
 63        let c0 = u256_to_point(src.y[0]);
 64        let c1 = u256_to_point(src.y[1]);
 65        let y = Fq2::new(c0, c1);
 66
 67        let inf = x.is_zero() && y.is_zero();
 68        G2Affine::new(x, y, inf)
 69    }
 70}
 71
 72type G2Tup = ([U256; 2], [U256; 2]);
 73
 74impl G2 {
 75    // NB: Serialize the c1 limb first.
 76    pub fn as_tuple(&self) -> G2Tup {
 77        ([self.x[1], self.x[0]], [self.y[1], self.y[0]])
 78    }
 79}
 80
 81impl From<&G2Affine> for G2 {
 82    fn from(p: &G2Affine) -> Self {
 83        Self {
 84            x: [point_to_u256(p.x.c0), point_to_u256(p.x.c1)],
 85            y: [point_to_u256(p.y.c0), point_to_u256(p.y.c1)],
 86        }
 87    }
 88}
 89
 90#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
 91pub struct Proof {
 92    pub a: G1,
 93    pub b: G2,
 94    pub c: G1,
 95}
 96
 97impl Proof {
 98    pub fn as_tuple(&self) -> (G1Tup, G2Tup, G1Tup) {
 99        (self.a.as_tuple(), self.b.as_tuple(), self.c.as_tuple())
100    }
101}
102
103impl From<ark_groth16::Proof<Bn254>> for Proof {
104    fn from(proof: ark_groth16::Proof<Bn254>) -> Self {
105        Self {
106            a: G1::from(&proof.a),
107            b: G2::from(&proof.b),
108            c: G1::from(&proof.c),
109        }
110    }
111}
112
113impl From<Proof> for ark_groth16::Proof<Bn254> {
114    fn from(src: Proof) -> ark_groth16::Proof<Bn254> {
115        ark_groth16::Proof {
116            a: src.a.into(),
117            b: src.b.into(),
118            c: src.c.into(),
119        }
120    }
121}
122
123#[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord)]
124pub struct VerifyingKey {
125    pub alpha1: G1,
126    pub beta2: G2,
127    pub gamma2: G2,
128    pub delta2: G2,
129    pub ic: Vec<G1>,
130}
131
132impl VerifyingKey {
133    pub fn as_tuple(&self) -> (G1Tup, G2Tup, G2Tup, G2Tup, Vec<G1Tup>) {
134        (
135            self.alpha1.as_tuple(),
136            self.beta2.as_tuple(),
137            self.gamma2.as_tuple(),
138            self.delta2.as_tuple(),
139            self.ic.iter().map(|i| i.as_tuple()).collect(),
140        )
141    }
142}
143
144impl From<ark_groth16::VerifyingKey<Bn254>> for VerifyingKey {
145    fn from(vk: ark_groth16::VerifyingKey<Bn254>) -> Self {
146        Self {
147            alpha1: G1::from(&vk.alpha_g1),
148            beta2: G2::from(&vk.beta_g2),
149            gamma2: G2::from(&vk.gamma_g2),
150            delta2: G2::from(&vk.delta_g2),
151            ic: vk.gamma_abc_g1.iter().map(G1::from).collect(),
152        }
153    }
154}
155
156impl From<VerifyingKey> for ark_groth16::VerifyingKey<Bn254> {
157    fn from(src: VerifyingKey) -> ark_groth16::VerifyingKey<Bn254> {
158        ark_groth16::VerifyingKey {
159            alpha_g1: src.alpha1.into(),
160            beta_g2: src.beta2.into(),
161            gamma_g2: src.gamma2.into(),
162            delta_g2: src.delta2.into(),
163            gamma_abc_g1: src.ic.into_iter().map(Into::into).collect(),
164        }
165    }
166}
167
168// Helper for converting a PrimeField to its U256 representation for Ethereum compatibility
169fn u256_to_point<F: PrimeField>(point: U256) -> F {
170    let mut buf = [0; 32];
171    point.to_little_endian(&mut buf);
172    let bigint = F::BigInt::read(&buf[..]).expect("always works");
173    F::from_repr(bigint).expect("alwasy works")
174}
175
176// Helper for converting a PrimeField to its U256 representation for Ethereum compatibility
177// (U256 reads data as big endian)
178fn point_to_u256<F: PrimeField>(point: F) -> U256 {
179    let point = point.into_repr();
180    let point_bytes = point.to_bytes_be();
181    U256::from(&point_bytes[..])
182}
183
184#[cfg(test)]
185mod tests {
186    use super::*;
187    use ark_bn254::Fq;
188
189    fn fq() -> Fq {
190        Fq::from(2)
191    }
192
193    fn fq2() -> Fq2 {
194        Fq2::from(2)
195    }
196
197    fn fr() -> Fr {
198        Fr::from(2)
199    }
200
201    fn g1() -> G1Affine {
202        G1Affine::new(fq(), fq(), false)
203    }
204
205    fn g2() -> G2Affine {
206        G2Affine::new(fq2(), fq2(), false)
207    }
208
209    #[test]
210    fn convert_fq() {
211        let el = fq();
212        let el2 = point_to_u256(el);
213        let el3: Fq = u256_to_point(el2);
214        let el4 = point_to_u256(el3);
215        assert_eq!(el, el3);
216        assert_eq!(el2, el4);
217    }
218
219    #[test]
220    fn convert_fr() {
221        let el = fr();
222        let el2 = point_to_u256(el);
223        let el3: Fr = u256_to_point(el2);
224        let el4 = point_to_u256(el3);
225        assert_eq!(el, el3);
226        assert_eq!(el2, el4);
227    }
228
229    #[test]
230    fn convert_g1() {
231        let el = g1();
232        let el2 = G1::from(&el);
233        let el3: G1Affine = el2.into();
234        let el4 = G1::from(&el3);
235        assert_eq!(el, el3);
236        assert_eq!(el2, el4);
237    }
238
239    #[test]
240    fn convert_g2() {
241        let el = g2();
242        let el2 = G2::from(&el);
243        let el3: G2Affine = el2.into();
244        let el4 = G2::from(&el3);
245        assert_eq!(el, el3);
246        assert_eq!(el2, el4);
247    }
248
249    #[test]
250    fn convert_vk() {
251        let vk = ark_groth16::VerifyingKey::<Bn254> {
252            alpha_g1: g1(),
253            beta_g2: g2(),
254            gamma_g2: g2(),
255            delta_g2: g2(),
256            gamma_abc_g1: vec![g1(), g1(), g1()],
257        };
258        let vk_ethers = VerifyingKey::from(vk.clone());
259        let ark_vk: ark_groth16::VerifyingKey<Bn254> = vk_ethers.into();
260        assert_eq!(ark_vk, vk);
261    }
262
263    #[test]
264    fn convert_proof() {
265        let p = ark_groth16::Proof::<Bn254> {
266            a: g1(),
267            b: g2(),
268            c: g1(),
269        };
270        let p2 = Proof::from(p.clone());
271        let p3 = ark_groth16::Proof::from(p2);
272        assert_eq!(p, p3);
273    }
274}