use ark_bls12_381::{
Bls12_381, Fq as bls12_381_fq, Fq2 as bls12_381_Fq2, Fr as bls12_381_Fr,
G1Affine as bls12_381_G1Affine, G2Affine as bls12_381_G2Affine,
};
use ark_bn254::{
Bn254, Fq as bn254_Fq, Fq2 as bn254_Fq2, Fr as bn254_Fr, G1Affine as bn254_G1Affine,
G2Affine as bn254_G2Affine,
};
use ark_ec::AffineRepr;
use ark_ff::{BigInteger, PrimeField};
use ark_serialize::CanonicalDeserialize;
use num::BigUint;
use num_traits::Zero;
use serde::{Deserialize, Serialize};
pub const PROTOCOL_GROTH16: &str = "groth16";
pub const CURVE_BN254: &str = "bn128";
pub const CURVE_BLS12_381: &str = "bls12381";
pub struct Inputs(pub Vec<BigUint>);
impl From<&[bn254_Fr]> for Inputs {
fn from(src: &[bn254_Fr]) -> Self {
let els = src.iter().map(|point| point_to_biguint(*point)).collect();
Self(els)
}
}
impl From<&[bls12_381_Fr]> for Inputs {
fn from(src: &[bls12_381_Fr]) -> Self {
let els = src.iter().map(|point| point_to_biguint(*point)).collect();
Self(els)
}
}
impl From<Inputs> for Vec<bn254_Fr> {
fn from(inputs: Inputs) -> Self {
inputs
.0
.iter()
.map(|biguint| biguint_to_point(biguint.clone()))
.collect()
}
}
impl From<Inputs> for Vec<bls12_381_Fr> {
fn from(inputs: Inputs) -> Self {
inputs
.0
.iter()
.map(|biguint| biguint_to_point(biguint.clone()))
.collect()
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct G1 {
pub x: BigUint,
pub y: BigUint,
pub z: BigUint,
}
type G1Tup = (BigUint, BigUint, BigUint);
impl G1 {
pub fn as_tuple(&self) -> (BigUint, BigUint, BigUint) {
(self.x.clone(), self.y.clone(), self.z.clone())
}
pub fn to_bn254(self) -> bn254_G1Affine {
let x: bn254_Fq = biguint_to_point(self.x);
let y: bn254_Fq = biguint_to_point(self.y);
if x.is_zero() && y.is_zero() {
bn254_G1Affine::identity()
} else {
bn254_G1Affine::new(x, y)
}
}
pub fn from_bn254(p: &bn254_G1Affine) -> Self {
let p_z = p.into_group();
Self {
x: point_to_biguint(p.x),
y: point_to_biguint(p.y),
z: point_to_biguint(p_z.z),
}
}
pub fn to_bls12_381(self) -> bls12_381_G1Affine {
let x: bls12_381_fq = biguint_to_point(self.x);
let y: bls12_381_fq = biguint_to_point(self.y);
if x.is_zero() && y.is_zero() {
bls12_381_G1Affine::identity()
} else {
bls12_381_G1Affine::new(x, y)
}
}
pub fn from_bls12_381(p: &bls12_381_G1Affine) -> Self {
let p_z = p.into_group();
Self {
x: point_to_biguint(p.x),
y: point_to_biguint(p.y),
z: point_to_biguint(p_z.z),
}
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct G2 {
pub x: [BigUint; 2],
pub y: [BigUint; 2],
pub z: [BigUint; 2],
}
type G2Tup = ([BigUint; 2], [BigUint; 2], [BigUint; 2]);
impl G2 {
pub fn as_tuple(&self) -> G2Tup {
(
[self.x[1].clone(), self.x[0].clone()],
[self.y[1].clone(), self.y[0].clone()],
[self.z[1].clone(), self.z[0].clone()],
)
}
pub fn to_bn254(self) -> bn254_G2Affine {
let c0 = biguint_to_point(self.x[0].clone());
let c1 = biguint_to_point(self.x[1].clone());
let x = bn254_Fq2::new(c0, c1);
let c0 = biguint_to_point(self.y[0].clone());
let c1 = biguint_to_point(self.y[1].clone());
let y = bn254_Fq2::new(c0, c1);
if x.is_zero() && y.is_zero() {
bn254_G2Affine::identity()
} else {
bn254_G2Affine::new(x, y)
}
}
pub fn from_bn254(p: &bn254_G2Affine) -> Self {
let p_z = p.into_group();
Self {
x: [point_to_biguint(p.x.c0), point_to_biguint(p.x.c1)],
y: [point_to_biguint(p.y.c0), point_to_biguint(p.y.c1)],
z: [point_to_biguint(p_z.z.c0), point_to_biguint(p_z.z.c1)],
}
}
pub fn to_bls12_381(self) -> bls12_381_G2Affine {
let c0 = biguint_to_point(self.x[0].clone());
let c1 = biguint_to_point(self.x[1].clone());
let x = bls12_381_Fq2::new(c0, c1);
let c0 = biguint_to_point(self.y[0].clone());
let c1 = biguint_to_point(self.y[1].clone());
let y = bls12_381_Fq2::new(c0, c1);
if x.is_zero() && y.is_zero() {
bls12_381_G2Affine::identity()
} else {
bls12_381_G2Affine::new(x, y)
}
}
pub fn from_bls12_381(p: &bls12_381_G2Affine) -> Self {
let p_z = p.into_group();
Self {
x: [point_to_biguint(p.x.c0), point_to_biguint(p.x.c1)],
y: [point_to_biguint(p.y.c0), point_to_biguint(p.y.c1)],
z: [point_to_biguint(p_z.z.c0), point_to_biguint(p_z.z.c1)],
}
}
}
#[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct Proof {
pub a: G1,
pub b: G2,
pub c: G1,
pub protocol: String,
pub curve: String,
}
impl Proof {
pub fn as_tuple(&self) -> (G1Tup, G2Tup, G1Tup) {
(self.a.as_tuple(), self.b.as_tuple(), self.c.as_tuple())
}
}
impl From<ark_groth16::Proof<Bn254>> for Proof {
fn from(proof: ark_groth16::Proof<Bn254>) -> Self {
Self {
a: G1::from_bn254(&proof.a),
b: G2::from_bn254(&proof.b),
c: G1::from_bn254(&proof.c),
protocol: PROTOCOL_GROTH16.to_string(),
curve: CURVE_BN254.to_string(),
}
}
}
impl From<ark_groth16::Proof<Bls12_381>> for Proof {
fn from(proof: ark_groth16::Proof<Bls12_381>) -> Self {
Self {
a: G1::from_bls12_381(&proof.a),
b: G2::from_bls12_381(&proof.b),
c: G1::from_bls12_381(&proof.c),
protocol: PROTOCOL_GROTH16.to_string(),
curve: CURVE_BLS12_381.to_string(),
}
}
}
impl From<Proof> for ark_groth16::Proof<Bn254> {
fn from(src: Proof) -> Self {
ark_groth16::Proof {
a: src.a.to_bn254(),
b: src.b.to_bn254(),
c: src.c.to_bn254(),
}
}
}
impl From<Proof> for ark_groth16::Proof<Bls12_381> {
fn from(src: Proof) -> Self {
ark_groth16::Proof {
a: src.a.to_bls12_381(),
b: src.b.to_bls12_381(),
c: src.c.to_bls12_381(),
}
}
}
fn biguint_to_point<F: PrimeField>(point: BigUint) -> F {
let buf_size: usize = F::MODULUS_BIT_SIZE.div_ceil(8).try_into().unwrap(); let mut buf = point.to_bytes_le();
buf.resize(buf_size, 0u8);
let bigint = F::BigInt::deserialize_uncompressed(&buf[..]).expect("always works");
F::from_bigint(bigint).expect("always works")
}
fn point_to_biguint<F: PrimeField>(point: F) -> BigUint {
let point = point.into_bigint();
let point_bytes = point.to_bytes_be();
BigUint::from_bytes_be(&point_bytes[..])
}
#[cfg(test)]
mod tests {
use crate::prover::circom::{biguint_to_point, point_to_biguint, Inputs, Proof, G1, G2};
use num::BigUint;
mod bn254 {
use super::*;
use ark_bn254::{Bn254, Fq, Fr, G1Affine, G2Affine};
use ark_std::UniformRand;
fn fq() -> Fq {
Fq::from(2)
}
fn fr() -> Fr {
Fr::from(2)
}
fn g1() -> G1Affine {
let rng = &mut ark_std::test_rng();
G1Affine::rand(rng)
}
fn g2() -> G2Affine {
let rng = &mut ark_std::test_rng();
G2Affine::rand(rng)
}
#[test]
fn convert_fq() {
let el = fq();
let el2 = point_to_biguint(el);
let el3: Fq = biguint_to_point(el2.clone());
let el4 = point_to_biguint(el3);
assert_eq!(el, el3);
assert_eq!(el2, el4);
}
#[test]
fn convert_fr() {
let el = fr();
let el2 = point_to_biguint(el);
let el3: Fr = biguint_to_point(el2.clone());
let el4 = point_to_biguint(el3);
assert_eq!(el, el3);
assert_eq!(el2, el4);
}
#[test]
fn convert_g1() {
let el = g1();
let el2 = G1::from_bn254(&el);
let el3: G1Affine = el2.clone().to_bn254();
let el4 = G1::from_bn254(&el3);
assert_eq!(el, el3);
assert_eq!(el2, el4);
}
#[test]
fn convert_g2() {
let el = g2();
let el2 = G2::from_bn254(&el);
let el3: G2Affine = el2.clone().to_bn254();
let el4 = G2::from_bn254(&el3);
assert_eq!(el, el3);
assert_eq!(el2, el4);
}
#[test]
fn convert_proof() {
let p = ark_groth16::Proof::<Bn254> {
a: g1(),
b: g2(),
c: g1(),
};
let p2 = Proof::from(p.clone());
let p3 = ark_groth16::Proof::from(p2);
assert_eq!(p, p3);
}
#[test]
fn convert_fr_inputs_to_biguint() {
let bn254_1 = Fr::from(1u32);
let bn254_2 = Fr::from(2u32);
let bn254_3 = Fr::from(3u32);
let bn254_slice: &[Fr] = &[bn254_1, bn254_2, bn254_3];
let result: Inputs = bn254_slice.into();
assert_eq!(result.0.len(), 3);
assert_eq!(result.0[0], BigUint::from(1u32));
assert_eq!(result.0[1], BigUint::from(2u32));
assert_eq!(result.0[2], BigUint::from(3u32));
}
#[test]
fn convert_biguint_to_fr_inputs() {
let biguint1 = BigUint::from(1u32);
let biguint2 = BigUint::from(2u32);
let biguint3 = BigUint::from(3u32);
let inputs = Inputs(vec![biguint1, biguint2, biguint3]);
let result: Vec<Fr> = inputs.into();
assert_eq!(result.len(), 3);
assert_eq!(result[0], Fr::from(BigUint::from(1u32)));
assert_eq!(result[1], Fr::from(BigUint::from(2u32)));
assert_eq!(result[2], Fr::from(BigUint::from(3u32)));
}
}
mod bls12_381 {
use super::*;
use ark_bls12_381::{Bls12_381, Fq, Fr, G1Affine, G2Affine};
use ark_std::UniformRand;
fn fq() -> Fq {
Fq::from(2)
}
fn fr() -> Fr {
Fr::from(2)
}
fn g1() -> G1Affine {
let rng = &mut ark_std::test_rng();
G1Affine::rand(rng)
}
fn g2() -> G2Affine {
let rng = &mut ark_std::test_rng();
G2Affine::rand(rng)
}
#[test]
fn convert_fq() {
let el = fq();
let el2 = point_to_biguint(el);
let el3: Fq = biguint_to_point(el2.clone());
let el4 = point_to_biguint(el3);
assert_eq!(el, el3);
assert_eq!(el2, el4);
}
#[test]
fn convert_fr() {
let el = fr();
let el2 = point_to_biguint(el);
let el3: Fr = biguint_to_point(el2.clone());
let el4 = point_to_biguint(el3);
assert_eq!(el, el3);
assert_eq!(el2, el4);
}
#[test]
fn convert_g1() {
let el = g1();
let el2 = G1::from_bls12_381(&el);
let el3: G1Affine = el2.clone().to_bls12_381();
let el4 = G1::from_bls12_381(&el3);
assert_eq!(el, el3);
assert_eq!(el2, el4);
}
#[test]
fn convert_g2() {
let el = g2();
let el2 = G2::from_bls12_381(&el);
let el3: G2Affine = el2.clone().to_bls12_381();
let el4 = G2::from_bls12_381(&el3);
assert_eq!(el, el3);
assert_eq!(el2, el4);
}
#[test]
fn convert_proof() {
let p = ark_groth16::Proof::<Bls12_381> {
a: g1(),
b: g2(),
c: g1(),
};
let p2 = Proof::from(p.clone());
let p3 = ark_groth16::Proof::from(p2);
assert_eq!(p, p3);
}
#[test]
fn convert_fr_inputs_to_biguint() {
let bn254_1 = Fr::from(1u32);
let bn254_2 = Fr::from(2u32);
let bn254_3 = Fr::from(3u32);
let bn254_slice: &[Fr] = &[bn254_1, bn254_2, bn254_3];
let result: Inputs = bn254_slice.into();
assert_eq!(result.0.len(), 3);
assert_eq!(result.0[0], BigUint::from(1u32));
assert_eq!(result.0[1], BigUint::from(2u32));
assert_eq!(result.0[2], BigUint::from(3u32));
}
#[test]
fn convert_biguint_to_fr_inputs() {
let biguint1 = BigUint::from(1u32);
let biguint2 = BigUint::from(2u32);
let biguint3 = BigUint::from(3u32);
let inputs = Inputs(vec![biguint1, biguint2, biguint3]);
let result: Vec<Fr> = inputs.into();
assert_eq!(result.len(), 3);
assert_eq!(result[0], Fr::from(BigUint::from(1u32)));
assert_eq!(result[1], Fr::from(BigUint::from(2u32)));
assert_eq!(result[2], Fr::from(BigUint::from(3u32)));
}
}
}