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