diff --git a/Cargo.toml b/Cargo.toml index 364bce9d..970299fb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,4 +58,8 @@ path = "src/bin_test_marlin.rs" [[bin]] name = "bin-test-groth16" -path = "src/bin_test_groth16.rs" \ No newline at end of file +path = "src/bin_test_groth16.rs" + +[[bin]] +name = "online" +path = "src/online.rs" \ No newline at end of file diff --git a/README.md b/README.md index cffbce82..fde041f5 100644 --- a/README.md +++ b/README.md @@ -28,11 +28,11 @@ cargo build run(by groth16): ``` -cargo run groth16 ./inputs/inputs.json +cargo run --bin main groth16 ./inputs/inputs.json ``` or run(by marlin): ``` -cargo run marlin ./inputs/inputs.json +cargo run --bin main marlin ./inputs/inputs.json ``` ## Tests diff --git a/arkworks/algebra/ec/src/group.rs b/arkworks/algebra/ec/src/group.rs index 1b1b3c8c..d506a605 100644 --- a/arkworks/algebra/ec/src/group.rs +++ b/arkworks/algebra/ec/src/group.rs @@ -1,4 +1,5 @@ use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; +use ark_std::PubUniformRand; use core::{ fmt::{Debug, Display}, hash::Hash, @@ -27,6 +28,7 @@ pub trait Group: + Hash + Neg + UniformRand + + PubUniformRand + Zero + Add + Sub diff --git a/arkworks/algebra/ec/src/lib.rs b/arkworks/algebra/ec/src/lib.rs index c0135101..9d860674 100644 --- a/arkworks/algebra/ec/src/lib.rs +++ b/arkworks/algebra/ec/src/lib.rs @@ -25,6 +25,7 @@ use ark_std::{ hash::Hash, ops::{Add, AddAssign, MulAssign, Neg, Sub, SubAssign}, vec::Vec, + PubUniformRand, }; use num_traits::Zero; use zeroize::Zeroize; @@ -138,6 +139,7 @@ pub trait ProjectiveCurve: + Debug + Display + UniformRand + + PubUniformRand + Zeroize + Zero + Neg diff --git a/arkworks/algebra/ec/src/models/short_weierstrass_jacobian.rs b/arkworks/algebra/ec/src/models/short_weierstrass_jacobian.rs index 2fae3137..7c23bdb4 100644 --- a/arkworks/algebra/ec/src/models/short_weierstrass_jacobian.rs +++ b/arkworks/algebra/ec/src/models/short_weierstrass_jacobian.rs @@ -13,7 +13,7 @@ use ark_std::{ use ark_ff::{ bytes::{FromBytes, ToBytes}, fields::{BitIteratorBE, Field, PrimeField, SquareRootField}, - ToConstraintField, UniformRand, + PubUniformRand, ToConstraintField, UniformRand, }; use crate::{models::SWModelParameters as Parameters, AffineCurve, ProjectiveCurve}; @@ -352,6 +352,8 @@ impl<'a, P: Parameters> core::iter::Sum<&'a Self> for GroupAffine

{ } } +impl PubUniformRand for GroupAffine

{} + mod group_impl { use super::*; use crate::group::Group; @@ -433,6 +435,8 @@ impl Distribution> for Standard { } } +impl PubUniformRand for GroupProjective

{} + impl ToBytes for GroupProjective

{ #[inline] fn write(&self, mut writer: W) -> IoResult<()> { diff --git a/arkworks/algebra/ec/src/models/twisted_edwards_extended.rs b/arkworks/algebra/ec/src/models/twisted_edwards_extended.rs index 6290e3a1..f9eb32fc 100644 --- a/arkworks/algebra/ec/src/models/twisted_edwards_extended.rs +++ b/arkworks/algebra/ec/src/models/twisted_edwards_extended.rs @@ -23,7 +23,7 @@ use zeroize::Zeroize; use ark_ff::{ bytes::{FromBytes, ToBytes}, fields::{BitIteratorBE, Field, PrimeField, SquareRootField}, - ToConstraintField, UniformRand, + PubUniformRand, ToConstraintField, UniformRand, }; #[cfg(feature = "parallel")] @@ -269,6 +269,8 @@ impl Distribution> for Standard { } } +impl PubUniformRand for GroupAffine

{} + mod group_impl { use super::*; use crate::group::Group; @@ -365,6 +367,20 @@ impl Distribution> for Standard { } } +impl PubUniformRand for GroupProjective

{ + #[inline] + fn pub_rand(rng: &mut R) -> GroupProjective

{ + loop { + let x = P::BaseField::pub_rand(rng); + let greatest = rng.gen(); + + if let Some(p) = GroupAffine::get_point_from_x(x, greatest) { + return p.scale_by_cofactor(); + } + } + } +} + impl ToBytes for GroupProjective

{ #[inline] fn write(&self, mut writer: W) -> IoResult<()> { diff --git a/arkworks/crypto-primitives/Cargo.toml b/arkworks/crypto-primitives/Cargo.toml index c33ca328..515b6e30 100644 --- a/arkworks/crypto-primitives/Cargo.toml +++ b/arkworks/crypto-primitives/Cargo.toml @@ -33,6 +33,8 @@ rayon = { version = "1.0", optional = true } derivative = { version = "2.0", features = ["use_core"] } tracing = { version = "0.1", default-features = false, features = [ "attributes" ], optional = true } +mpc-trait = { path = "../../mpc-trait" } + [features] default = ["std"] std = [ "ark-ff/std", "ark-ec/std", "ark-std/std", "ark-relations/std" ] diff --git a/arkworks/crypto-primitives/src/commitment/pedersen/mod.rs b/arkworks/crypto-primitives/src/commitment/pedersen/mod.rs index 2a7c9657..f668f5d3 100644 --- a/arkworks/crypto-primitives/src/commitment/pedersen/mod.rs +++ b/arkworks/crypto-primitives/src/commitment/pedersen/mod.rs @@ -4,7 +4,8 @@ use ark_ff::{bytes::ToBytes, BitIteratorLE, Field, FpParameters, PrimeField, ToC use ark_std::io::{Result as IoResult, Write}; use ark_std::marker::PhantomData; use ark_std::rand::Rng; -use ark_std::UniformRand; +use ark_std::{PubUniformRand, UniformRand}; +use mpc_trait::MpcWire; use super::CommitmentScheme; @@ -36,6 +37,15 @@ impl UniformRand for Randomness { } } +impl MpcWire for Randomness {} + +impl PubUniformRand for Randomness { + #[inline] + fn pub_rand(rng: &mut R) -> Self { + Randomness(PubUniformRand::pub_rand(rng)) + } +} + impl ToBytes for Randomness { fn write(&self, writer: W) -> IoResult<()> { self.0.write(writer) diff --git a/arkworks/crypto-primitives/src/crh/pedersen/mod.rs b/arkworks/crypto-primitives/src/crh/pedersen/mod.rs index a5bb201d..64b81563 100644 --- a/arkworks/crypto-primitives/src/crh/pedersen/mod.rs +++ b/arkworks/crypto-primitives/src/crh/pedersen/mod.rs @@ -41,7 +41,7 @@ impl CRH { pub fn generator_powers(num_powers: usize, rng: &mut R) -> Vec { let mut cur_gen_powers = Vec::with_capacity(num_powers); - let mut base = C::rand(rng); + let mut base = C::pub_rand(rng); for _ in 0..num_powers { cur_gen_powers.push(base); base.double_in_place(); diff --git a/arkworks/marlin/src/ahp/mod.rs b/arkworks/marlin/src/ahp/mod.rs index 59eedafc..9f5a5646 100644 --- a/arkworks/marlin/src/ahp/mod.rs +++ b/arkworks/marlin/src/ahp/mod.rs @@ -178,7 +178,12 @@ impl AHPForR1CS { (-beta * g_1_at_beta, LCTerm::One), ], ); - debug_assert!(evals.get_lc_eval(&outer_sumcheck, beta)?.is_zero()); + #[cfg(debug_assertions)] + { + let mut e = evals.get_lc_eval(&outer_sumcheck, beta)?; + e.publicize(); + debug_assert!(e.is_zero(), "Evaluation of lc is\n{}\n, not zero", e); + } linear_combinations.push(z_b); linear_combinations.push(g_1); @@ -244,7 +249,11 @@ impl AHPForR1CS { a.label = "inner_sumcheck".into(); let inner_sumcheck = a; - debug_assert!(evals.get_lc_eval(&inner_sumcheck, gamma)?.is_zero()); + debug_assert!({ + let mut e = evals.get_lc_eval(&inner_sumcheck, gamma)?; + e.publicize(); + e.is_zero() + }); linear_combinations.push(g_2); linear_combinations.push(a_denom); diff --git a/inputs/inputs.json b/inputs/inputs.json index 8e3ebb3a..99f23d73 100644 --- a/inputs/inputs.json +++ b/inputs/inputs.json @@ -1,3 +1,5 @@ { - "x": 4 + "x": 4, + "y": 5, + "z": 6 } \ No newline at end of file diff --git a/mpc-algebra/Cargo.toml b/mpc-algebra/Cargo.toml index daddf797..440b9ef4 100644 --- a/mpc-algebra/Cargo.toml +++ b/mpc-algebra/Cargo.toml @@ -11,8 +11,11 @@ ark-ff = { path = "../arkworks/algebra/ff", version = "0.3.0" } ark-poly = { path = "../arkworks/algebra/poly", version = "0.3.0" } ark-serialize = { path = "../arkworks/algebra/serialize", version = "0.3.0" } ark-std = { path = "../arkworks/std", version = "0.3.0", features = ["std", "print-trace"] } +ark-r1cs-std = { path = "../arkworks/r1cs-std", version = "0.3.0", default-features = false, optional = true } +ark-crypto-primitives = { path = "../arkworks/crypto-primitives", version = "0.3.0" } ark-bls12-377 = { path = "../arkworks/curves/bls12_377", version = "0.3.0" } +ark-ed-on-bls12-377 = { path = "../arkworks/curves/ed_on_bls12_377", version = "0.3.0" } rand = "0.8.5" num-bigint = { version = "0.4.3", features = ["rand"] } @@ -24,4 +27,7 @@ mpc-net = { path = "../mpc-net" } mpc-trait = { path = "../mpc-trait" } structopt = "0.3" -env_logger = "0.8" \ No newline at end of file +env_logger = "0.8" + +[features] +default = ["ark-r1cs-std"] \ No newline at end of file diff --git a/mpc-algebra/src/share.rs b/mpc-algebra/src/share.rs index a502c97e..b3534456 100644 --- a/mpc-algebra/src/share.rs +++ b/mpc-algebra/src/share.rs @@ -4,6 +4,8 @@ pub mod field; pub use field::*; pub mod group; pub use group::*; +pub mod msm; +pub use msm::*; pub mod pairing; pub use pairing::*; diff --git a/mpc-algebra/src/share/additive.rs b/mpc-algebra/src/share/additive.rs index 41e899c4..ec9ce7c4 100644 --- a/mpc-algebra/src/share/additive.rs +++ b/mpc-algebra/src/share/additive.rs @@ -15,7 +15,7 @@ use ark_std::UniformRand; use derivative::Derivative; use crate::reveal::Reveal; -use crate::{DenseOrSparsePolynomial, DensePolynomial, SparsePolynomial}; +use crate::{DenseOrSparsePolynomial, DensePolynomial, Msm, SparsePolynomial}; use crate::channel::MpcSerNet; use mpc_net::{MpcMultiNet as Net, MpcNet}; @@ -84,8 +84,10 @@ impl Reveal for AdditiveFieldShare { Self { val: b } } - fn from_public(_b: Self::Base) -> Self { - todo!() + fn from_public(f: Self::Base) -> Self { + Self { + val: if Net::am_king() { f } else { F::zero() }, + } } fn unwrap_as_public(self) -> Self::Base { @@ -94,6 +96,13 @@ impl Reveal for AdditiveFieldShare { } impl FieldShare for AdditiveFieldShare { + fn batch_open(selfs: impl IntoIterator) -> Vec { + let self_vec: Vec = selfs.into_iter().map(|s| s.val).collect(); + let all_vals = Net::broadcast(&self_vec); + (0..self_vec.len()) + .map(|i| all_vals.iter().map(|v| &v[i]).sum()) + .collect() + } fn add(&mut self, other: &Self) -> &mut Self { self.val += &other.val; self @@ -140,8 +149,8 @@ macro_rules! impl_field_basics { } } impl ToBytes for $share { - fn write(&self, _writer: W) -> io::Result<()> { - todo!() + fn write(&self, writer: W) -> io::Result<()> { + self.val.write(writer) } } impl FromBytes for $share { @@ -219,11 +228,12 @@ impl ExtFieldShare for MulExtFieldShare { Ord(bound = "T: Ord"), Hash(bound = "T: Hash") )] -pub struct AdditiveGroupShare { +pub struct AdditiveGroupShare { pub val: T, + _phants: PhantomData, } -impl Reveal for AdditiveGroupShare { +impl Reveal for AdditiveGroupShare { type Base = G; fn reveal(self) -> Self::Base { @@ -231,12 +241,16 @@ impl Reveal for AdditiveGroupShare { } fn from_add_shared(b: G) -> Self { - Self { val: b } + Self { + val: b, + _phants: PhantomData, + } } fn from_public(b: G) -> Self { Self { val: if Net::am_king() { b } else { G::zero() }, + _phants: PhantomData, } } @@ -247,22 +261,22 @@ impl Reveal for AdditiveGroupShare { macro_rules! impl_group_basics { ($share:ident, $bound:ident) => { - impl Debug for $share { + impl Debug for $share { fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { todo!() } } - impl ToBytes for $share { + impl ToBytes for $share { fn write(&self, _writer: W) -> io::Result<()> { todo!() } } - impl FromBytes for $share { + impl FromBytes for $share { fn read(_reader: R) -> io::Result { todo!() } } - impl CanonicalSerialize for $share { + impl CanonicalSerialize for $share { fn serialize(&self, _writer: W) -> Result<(), SerializationError> { todo!() } @@ -271,7 +285,7 @@ macro_rules! impl_group_basics { todo!() } } - impl CanonicalSerializeWithFlags for $share { + impl CanonicalSerializeWithFlags for $share { fn serialize_with_flags( &self, _writer: W, @@ -284,19 +298,19 @@ macro_rules! impl_group_basics { todo!() } } - impl CanonicalDeserialize for $share { + impl CanonicalDeserialize for $share { fn deserialize(_reader: R) -> Result { todo!() } } - impl CanonicalDeserializeWithFlags for $share { + impl CanonicalDeserializeWithFlags for $share { fn deserialize_with_flags( _reader: R, ) -> Result<(Self, Fl), SerializationError> { todo!() } } - impl UniformRand for $share { + impl UniformRand for $share { fn rand(_rng: &mut R) -> Self { todo!() } @@ -306,7 +320,7 @@ macro_rules! impl_group_basics { impl_group_basics!(AdditiveGroupShare, Group); -impl GroupShare for AdditiveGroupShare { +impl> GroupShare for AdditiveGroupShare { type FieldShare = AdditiveFieldShare; fn add(&mut self, other: &Self) -> &mut Self { @@ -316,7 +330,10 @@ impl GroupShare for AdditiveGroupShare { fn scale_pub_group(mut base: G, scalar: &Self::FieldShare) -> Self { base *= scalar.val; - Self { val: base } + Self { + val: base, + _phants: PhantomData::default(), + } } fn shift(&mut self, other: &G) -> &mut Self { @@ -325,6 +342,11 @@ impl GroupShare for AdditiveGroupShare { } self } + + fn multi_scale_pub_group(bases: &[G], scalars: &[Self::FieldShare]) -> Self { + let scalars: Vec = scalars.into_iter().map(|s| s.val.clone()).collect(); + Self::from_add_shared(M::msm(bases, &scalars)) + } } macro_rules! groups_share { @@ -333,8 +355,9 @@ macro_rules! groups_share { impl AffProjShare for $struct_name { type FrShare = AdditiveFieldShare; - type AffineShare = AdditiveGroupShare; - type ProjectiveShare = AdditiveGroupShare; + type AffineShare = AdditiveGroupShare>; + type ProjectiveShare = + AdditiveGroupShare>; fn sh_aff_to_proj(g: Self::AffineShare) -> Self::ProjectiveShare { g.map_homo(|s| s.into()) @@ -383,10 +406,12 @@ impl PairingShare for AdditivePairingShare { type FqeShare = AdditiveExtFieldShare; // Not a typo. We want a multiplicative subgroup. type FqkShare = MulExtFieldShare; - type G1AffineShare = AdditiveGroupShare; - type G2AffineShare = AdditiveGroupShare; - type G1ProjectiveShare = AdditiveGroupShare; - type G2ProjectiveShare = AdditiveGroupShare; + type G1AffineShare = AdditiveGroupShare>; + type G2AffineShare = AdditiveGroupShare>; + type G1ProjectiveShare = + AdditiveGroupShare>; + type G2ProjectiveShare = + AdditiveGroupShare>; type G1 = AdditiveG1Share; type G2 = AdditiveG2Share; diff --git a/mpc-algebra/src/share/msm.rs b/mpc-algebra/src/share/msm.rs new file mode 100644 index 00000000..48b24897 --- /dev/null +++ b/mpc-algebra/src/share/msm.rs @@ -0,0 +1,48 @@ +use ark_ec::{group::Group, AffineCurve, ProjectiveCurve}; +use derivative::Derivative; +use std::marker::PhantomData; + +/// Multi-scalar multiplications +pub trait Msm: Send + Sync + 'static { + fn msm(bases: &[G], scalars: &[S]) -> G; + fn pre_reveal_check() {} +} + +#[derive(Debug, Derivative, Clone, Copy)] +#[derivative(Default(bound = ""))] +pub struct NaiveMsm(pub PhantomData); + +impl Msm for NaiveMsm { + fn msm(bases: &[G], scalars: &[G::ScalarField]) -> G { + bases + .iter() + .zip(scalars.iter()) + .map(|(b, s)| { + let mut b = b.clone(); + b *= *s; + b + }) + .fold(G::zero(), |a, b| a + b) + } +} + +#[derive(Debug, Derivative, Clone, Copy)] +#[derivative(Default(bound = ""))] +pub struct AffineMsm(pub PhantomData); + +impl Msm for AffineMsm { + fn msm(bases: &[G], scalars: &[G::ScalarField]) -> G { + G::multi_scalar_mul(bases, scalars).into() + } +} + +#[derive(Debug, Derivative, Clone, Copy)] +#[derivative(Default(bound = ""))] +pub struct ProjectiveMsm(pub PhantomData); + +impl Msm for ProjectiveMsm { + fn msm(bases: &[G], scalars: &[G::ScalarField]) -> G { + let bases: Vec = bases.iter().map(|s| s.clone().into()).collect(); + ::multi_scalar_mul(&bases, scalars) + } +} diff --git a/mpc-algebra/src/wire.rs b/mpc-algebra/src/wire.rs index b676d9e6..0b08b635 100644 --- a/mpc-algebra/src/wire.rs +++ b/mpc-algebra/src/wire.rs @@ -4,4 +4,6 @@ pub mod group; pub use group::*; pub mod pairing; pub use pairing::*; +pub mod edwards; +pub use edwards::*; pub mod macros; diff --git a/mpc-algebra/src/wire/edwards.rs b/mpc-algebra/src/wire/edwards.rs new file mode 100644 index 00000000..16a97df4 --- /dev/null +++ b/mpc-algebra/src/wire/edwards.rs @@ -0,0 +1,258 @@ +use ark_ec::{ + twisted_edwards_extended::{GroupAffine, GroupProjective}, + ModelParameters, MontgomeryModelParameters, TEModelParameters, +}; +use ark_ed_on_bls12_377::{EdwardsParameters, EdwardsProjective}; +use ark_ff::{field_new, BigInteger256}; + +use ark_r1cs_std::{fields::fp::FpVar, groups::curves::twisted_edwards::AffineVar}; + +use crate::{AdditiveFieldShare, MpcField, Reveal}; + +use crate::channel::MpcSerNet; +use mpc_net::MpcMultiNet as Net; +// Scalar for ed +type Fr = MpcField>; + +impl From for BigInteger256 { + fn from(f: Fr) -> Self { + todo!() + } +} +// Base for ed +type Fq = MpcField>; + +pub type MpcEdwardsProjective = GroupProjective; + +#[derive(Clone, Default, PartialEq, Eq)] +pub struct MpcEdwardsParameters; + +impl ModelParameters for MpcEdwardsParameters { + type BaseField = Fq; + type ScalarField = Fr; +} + +impl TEModelParameters for MpcEdwardsParameters { + /// COEFF_A = -1 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, "-1"); + + /// COEFF_D = 3021 + #[rustfmt::skip] + const COEFF_D: Fq = field_new!(Fq, "3021"); + + /// COFACTOR = 4 + const COFACTOR: &'static [u64] = &[4]; + + /// COFACTOR_INV = + /// 527778859339273151515551558673846658209717731602102048798421311598680340096 + #[rustfmt::skip] + const COFACTOR_INV: Fr = field_new!(Fr, "527778859339273151515551558673846658209717731602102048798421311598680340096"); + + /// Generated randomly + const AFFINE_GENERATOR_COEFFS: (Self::BaseField, Self::BaseField) = (GENERATOR_X, GENERATOR_Y); + + type MontgomeryModelParameters = MpcEdwardsParameters; + + /// Multiplication by `a` is just negation. + /// Is `a` 1 or -1? + #[inline(always)] + fn mul_by_a(elem: &Self::BaseField) -> Self::BaseField { + -*elem + } +} + +impl MontgomeryModelParameters for MpcEdwardsParameters { + /// COEFF_A = 0x8D26E3FADA9010A26949031ECE3971B93952AD84D4753DDEDB748DA37E8F552 + /// = 3990301581132929505568273333084066329187552697088022219156688740916631500114 + #[rustfmt::skip] + const COEFF_A: Fq = field_new!(Fq, "3990301581132929505568273333084066329187552697088022219156688740916631500114"); + /// COEFF_B = 0x9D8F71EEC83A44C3A1FBCEC6F5418E5C6154C2682B8AC231C5A3725C8170AAD + /// = 4454160168295440918680551605697480202188346638066041608778544715000777738925 + #[rustfmt::skip] + const COEFF_B: Fq = field_new!(Fq, "4454160168295440918680551605697480202188346638066041608778544715000777738925"); + + type TEModelParameters = MpcEdwardsParameters; +} + +/// GENERATOR_X = +/// 4497879464030519973909970603271755437257548612157028181994697785683032656389, +#[rustfmt::skip] +const GENERATOR_X: Fq = field_new!(Fq, "4497879464030519973909970603271755437257548612157028181994697785683032656389"); + +/// GENERATOR_Y = +/// 4357141146396347889246900916607623952598927460421559113092863576544024487809 +#[rustfmt::skip] +const GENERATOR_Y: Fq = field_new!(Fq, "4357141146396347889246900916607623952598927460421559113092863576544024487809"); + +impl Fr { + /// Interpret a string of decimal numbers as a prime field element. + /// Does not accept unnecessary leading zeroes or a blank string. + /// For *internal* use only; please use the `field_new` macro instead + /// of this method + #[doc(hidden)] + pub const fn const_from_str( + limbs: &[u64], + is_positive: bool, + r2: BigInteger256, + modulus: BigInteger256, + inv: u64, + ) -> Self { + let val = ark_ed_on_bls12_377::Fr::const_from_str(limbs, is_positive, r2, modulus, inv); + Self::Public(val) + } +} + +impl Fq { + /// Interpret a string of decimal numbers as a prime field element. + /// Does not accept unnecessary leading zeroes or a blank string. + /// For *internal* use only; please use the `field_new` macro instead + /// of this method + #[doc(hidden)] + pub const fn const_from_str( + limbs: &[u64], + is_positive: bool, + r2: BigInteger256, + modulus: BigInteger256, + inv: u64, + ) -> Self { + let val = ark_bls12_377::Fr::const_from_str(limbs, is_positive, r2, modulus, inv); + Self::Public(val) + } +} + +pub type FqVar = FpVar; +pub type MpcEdwardsVar = AffineVar; + +pub trait ToLocal { + type Local; + + // lift objects to local + fn to_local(&self) -> Self::Local; +} + +pub trait ToMPC { + type MPC; + + // lift objects to MPC + fn to_mpc(&self) -> Self::MPC; +} + +impl ToLocal for GroupProjective { + type Local = GroupProjective; + fn to_local(&self) -> GroupProjective { + let x = self.x.unwrap_as_public(); + let y = self.y.unwrap_as_public(); + let t = self.t.unwrap_as_public(); + let z = self.z.unwrap_as_public(); + GroupProjective::new(x, y, t, z) + } +} +use ark_crypto_primitives::commitment::pedersen::{Parameters, Randomness}; + +impl ToLocal for Parameters { + type Local = Parameters; + + fn to_local(&self) -> Self::Local { + let randomness_generator = self + .randomness_generator + .iter() + .map(|x| x.to_local()) + .collect::>(); + let generators = self + .generators + .iter() + .map(|vec_g| vec_g.iter().map(|g| g.to_local()).collect::>()) + .collect::>(); + + Self::Local { + randomness_generator, + generators, + } + } +} + +impl Reveal for MpcEdwardsProjective { + type Base = EdwardsProjective; + + fn reveal(self) -> Self::Base { + let GroupProjective { x, y, t, z, .. } = self; + Self::Base::new(x.reveal(), y.reveal(), t.reveal(), z.reveal()) + } + + fn from_add_shared(_b: Self::Base) -> Self { + unimplemented!() + } + + fn from_public(_b: Self::Base) -> Self { + unimplemented!() + } +} + +impl Reveal for Randomness { + type Base = Randomness; + + fn reveal(self) -> Self::Base { + let Randomness(r) = self; + Randomness(r.reveal()) + } + + fn from_add_shared(_b: Self::Base) -> Self { + unimplemented!() + } + + fn from_public(_b: Self::Base) -> Self { + unimplemented!() + } +} + +impl ToMPC for GroupProjective { + type MPC = GroupProjective; + fn to_mpc(&self) -> Self::MPC { + let x = ::BaseField::from_public(self.x); + let y = ::BaseField::from_public(self.y); + let t = ::BaseField::from_public(self.t); + let z = ::BaseField::from_public(self.z); + GroupProjective::new(x, y, t, z) + } +} + +impl ToMPC for Parameters { + type MPC = Parameters; + + fn to_mpc(&self) -> Self::MPC { + let randomness_generator = self + .randomness_generator + .iter() + .map(|x| x.to_mpc()) + .collect::>(); + let generators = self + .generators + .iter() + .map(|vec_g| vec_g.iter().map(|g| g.to_mpc()).collect::>()) + .collect::>(); + + Self::MPC { + randomness_generator, + generators, + } + } +} + +impl Reveal for GroupAffine { + type Base = GroupAffine; + + fn reveal(self) -> Self::Base { + Net::broadcast(&self) + .into_iter() + .fold(Self::Base::default(), |acc, x| acc + x) + } + + fn from_add_shared(b: Self::Base) -> Self { + b + } + + fn from_public(_b: Self::Base) -> Self { + unimplemented!() + } +} diff --git a/mpc-algebra/src/wire/field.rs b/mpc-algebra/src/wire/field.rs index 85d0bda9..d1c978a0 100644 --- a/mpc-algebra/src/wire/field.rs +++ b/mpc-algebra/src/wire/field.rs @@ -21,7 +21,7 @@ use ark_serialize::{ // use crate::channel::MpcSerNet; use crate::share::field::FieldShare; -use crate::{BeaverSource, Reveal}; +use crate::{AdditiveFieldShare, BeaverSource, Reveal}; use mpc_net::{MpcMultiNet as Net, MpcNet}; #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -66,14 +66,22 @@ impl> MpcField { pub fn all_public_or_shared(v: impl IntoIterator) -> Result, Vec> { let mut out_a = Vec::new(); let mut out_b = Vec::new(); + let mut force_shared = Vec::new(); for s in v { match s { - Self::Public(x) => out_a.push(x), - Self::Shared(x) => out_b.push(x), + Self::Public(x) => { + out_a.push(x); + force_shared.push(S::from_public(x)); + } + Self::Shared(x) => { + out_b.push(x); + force_shared.push(x) + } } } if !out_a.is_empty() & !out_b.is_empty() { - panic!("Heterogeous") + // panic!("Heterogeous") + Err(force_shared) } else if !out_a.is_empty() { Ok(out_a) } else { @@ -137,7 +145,7 @@ impl> ToBytes for MpcField { fn write(&self, writer: W) -> io::Result<()> { match self { Self::Public(v) => v.write(writer), - Self::Shared(_) => unimplemented!("write share: {}", self), + Self::Shared(v) => v.write(writer), } } } @@ -167,10 +175,13 @@ impl> CanonicalSerialize for MpcField { impl> CanonicalSerializeWithFlags for MpcField { fn serialize_with_flags( &self, - _writer: W, - _flags: Fl, + writer: W, + flags: Fl, ) -> Result<(), ark_serialize::SerializationError> { - todo!() + match self { + Self::Public(v) => v.serialize_with_flags(writer, flags), + Self::Shared(_) => unimplemented!("serialize_with_flag share: {}", self), + } } fn serialized_size_with_flags(&self) -> usize { @@ -568,6 +579,10 @@ impl> MpcWire for MpcField { impl> Field for MpcField { type BasePrimeField = Self; + fn characteristic() -> &'static [u64] { + F::characteristic() + } + fn extension_degree() -> u64 { todo!() } @@ -577,11 +592,12 @@ impl> Field for MpcField { } fn double(&self) -> Self { - todo!() + Self::Public(F::from(2u8)) * self } fn double_in_place(&mut self) -> &mut Self { - todo!() + *self *= Self::Public(F::from(2u8)); + self } fn from_random_bytes_with_flags(_bytes: &[u8]) -> Option<(Self, Fl)> { @@ -589,7 +605,7 @@ impl> Field for MpcField { } fn square(&self) -> Self { - todo!() + self.clone() * self } fn square_in_place(&mut self) -> &mut Self { @@ -778,13 +794,34 @@ impl> PrimeField for MpcField { } } -impl> SquareRootField for MpcField { +impl> SquareRootField for MpcField { fn legendre(&self) -> ark_ff::LegendreSymbol { todo!() } fn sqrt(&self) -> Option { - todo!() + // todo!() + // TODO implement correctly. + + let is_shared = self.is_shared(); + let val = self.unwrap_as_public(); + + match val.sqrt() { + Some(sqrt) => { + if is_shared { + Some(Self::from_add_shared(sqrt)) + } else { + Some(Self::from_public(sqrt)) + } + } + None => None, + } + + // if is_shared { + // Some(Self::from_add_shared(sqrt.unwrap())) + // } else { + // Some(Self::from_public(sqrt.unwrap())) + // } } fn sqrt_in_place(&mut self) -> Option<&mut Self> { diff --git a/mpc-algebra/src/wire/group.rs b/mpc-algebra/src/wire/group.rs index 8689edf7..fd6cceff 100644 --- a/mpc-algebra/src/wire/group.rs +++ b/mpc-algebra/src/wire/group.rs @@ -134,8 +134,8 @@ impl> UniformRand for MpcGroup { } impl> PubUniformRand for MpcGroup { - fn pub_rand(_rng: &mut R) -> Self { - todo!() + fn pub_rand(rng: &mut R) -> Self { + Self::Public(::pub_rand(rng)) } } diff --git a/mpc-algebra/src/wire/pairing.rs b/mpc-algebra/src/wire/pairing.rs index d2055f04..ce3e5314 100644 --- a/mpc-algebra/src/wire/pairing.rs +++ b/mpc-algebra/src/wire/pairing.rs @@ -713,8 +713,8 @@ macro_rules! impl_aff_proj { fn multi_scalar_mul(bases: &[Self], scalars: &[Self::ScalarField]) -> Self::Projective { let b = { assert!(bases.iter().all(|b| !b.is_shared())); - let scalars_shared = scalars.first().map(|s| s.is_shared()).unwrap_or(true); - assert!(scalars.iter().all(|b| scalars_shared == b.is_shared())); + // let scalars_shared = scalars.first().map(|s| s.is_shared()).unwrap_or(true); + // assert!(scalars.iter().all(|b| scalars_shared == b.is_shared())); let bases = MpcGroup::all_public_or_shared(bases.into_iter().map(|i| i.val.clone())) .unwrap(); diff --git a/run_online.zsh b/run_online.zsh new file mode 100755 index 00000000..807e1524 --- /dev/null +++ b/run_online.zsh @@ -0,0 +1,30 @@ +set -ex +trap "exit" INT TERM +trap "kill 0" EXIT + +cargo build --bin online +BIN=./target/debug/online + + +PROCS=() + +for i in $(seq 0 2) +do +if [ $i == 0 ] +then + RUST_BACKTRACE=1 $BIN marlin ./inputs/inputs.json $i ./data/address & + pid=$! + PROCS[$i]=$pid +else + $BIN marlin ./inputs/inputs.json $i ./data/address > /dev/null & + pid=$! + PROCS[$i]=$pid +fi +done + +for pid in ${PROCS[@]} +do +wait $pid +done + +echo done \ No newline at end of file diff --git a/src/bin_test_groth16.rs b/src/bin_test_groth16.rs index 4163ccb5..5aafaf67 100644 --- a/src/bin_test_groth16.rs +++ b/src/bin_test_groth16.rs @@ -2,7 +2,7 @@ use mpc_net::{MpcMultiNet as Net, MpcNet}; use std::path::PathBuf; use structopt::StructOpt; -mod circuit; +mod circuits; mod groth16; #[derive(Debug, StructOpt)] diff --git a/src/bin_test_marlin.rs b/src/bin_test_marlin.rs index 3de9a005..35ad2e18 100644 --- a/src/bin_test_marlin.rs +++ b/src/bin_test_marlin.rs @@ -2,7 +2,7 @@ use mpc_net::{MpcMultiNet as Net, MpcNet}; use std::path::PathBuf; use structopt::StructOpt; -mod circuit; +mod circuits; mod marlin; #[derive(Debug, StructOpt)] @@ -19,5 +19,6 @@ struct Opt { fn main() { let opt = Opt::from_args(); Net::init_from_file(opt.input.to_str().unwrap(), opt.id); - marlin::mpc_test_prove_and_verify(1); + // marlin::mpc_test_prove_and_verify_pedersen(1); + marlin::mpc_test_each_commit(1); } diff --git a/src/circuit.rs b/src/circuit.rs deleted file mode 100644 index a1c7ab36..00000000 --- a/src/circuit.rs +++ /dev/null @@ -1,38 +0,0 @@ -use ark_ff::Field; -use ark_relations::{ - lc, - r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}, -}; - -// circuit -#[derive(Clone)] -pub struct MyCircuit { - pub a: Option, - pub b: Option, -} - -impl ConstraintSynthesizer for MyCircuit { - fn generate_constraints( - self, - cs: ConstraintSystemRef, - ) -> Result<(), SynthesisError> { - let a = cs.new_witness_variable(|| self.a.ok_or(SynthesisError::AssignmentMissing))?; - let b = cs.new_witness_variable(|| self.b.ok_or(SynthesisError::AssignmentMissing))?; - let c = cs.new_input_variable(|| { - let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?; - let b = self.b.ok_or(SynthesisError::AssignmentMissing)?; - - a.mul_assign(&b); - Ok(a) - })?; - - cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; - cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; - cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; - cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; - cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; - cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; - - Ok(()) - } -} diff --git a/src/circuits.rs b/src/circuits.rs new file mode 100644 index 00000000..bca271f1 --- /dev/null +++ b/src/circuits.rs @@ -0,0 +1,4 @@ +pub mod circuit; +pub mod input_circuit; +pub mod pedersen; +pub use pedersen::*; diff --git a/src/circuits/circuit.rs b/src/circuits/circuit.rs new file mode 100644 index 00000000..031b4f2a --- /dev/null +++ b/src/circuits/circuit.rs @@ -0,0 +1,108 @@ +use ark_ff::PrimeField; +use ark_relations::{ + lc, + r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}, +}; + +use super::{LocalOrMPC, PedersenComCircuit}; + +#[derive(Clone)] +pub struct MyCircuit> { + pub a: Option, + pub b: Option, + + pub params: Option, + pub vec_x: Option>, + pub randomness: Option>, + + pub vec_h_x: Option>, +} + +impl> MyCircuit { + fn verify_commitments(&self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> { + for i in 0..self.vec_x.as_ref().unwrap().len() { + let x = self.vec_x.clone().unwrap()[i]; + let h_x = &self.vec_h_x.clone().unwrap()[i]; + let randomness = &self.randomness.clone().unwrap()[i]; + + let x_com_circuit = PedersenComCircuit { + param: self.params.clone(), + input: Some(x), + open: Some(randomness.clone()), + commit: Some(h_x.clone()), + }; + + x_com_circuit.generate_constraints(cs.clone())?; + } + + Ok(()) + } +} + +impl> ConstraintSynthesizer + for MyCircuit +{ + fn generate_constraints( + self, + cs: ConstraintSystemRef, + ) -> Result<(), SynthesisError> { + let a = cs.new_witness_variable(|| self.a.ok_or(SynthesisError::AssignmentMissing))?; + let b = cs.new_witness_variable(|| self.b.ok_or(SynthesisError::AssignmentMissing))?; + let c = cs.new_input_variable(|| { + let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?; + let b = self.b.ok_or(SynthesisError::AssignmentMissing)?; + + a.mul_assign(&b); + Ok(a) + })?; + + cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; + cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; + cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; + cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; + cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; + cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; + + self.verify_commitments(cs.clone())?; + + println!("total number of constraints: {}", cs.num_constraints()); + + Ok(()) + } +} + +#[derive(Clone)] +pub struct MySimpleCircuit> { + pub a: Option, + pub b: Option, +} + +impl> ConstraintSynthesizer + for MySimpleCircuit +{ + fn generate_constraints( + self, + cs: ConstraintSystemRef, + ) -> Result<(), SynthesisError> { + let a = cs.new_witness_variable(|| self.a.ok_or(SynthesisError::AssignmentMissing))?; + let b = cs.new_witness_variable(|| self.b.ok_or(SynthesisError::AssignmentMissing))?; + let c = cs.new_input_variable(|| { + let mut a = self.a.ok_or(SynthesisError::AssignmentMissing)?; + let b = self.b.ok_or(SynthesisError::AssignmentMissing)?; + + a.mul_assign(&b); + Ok(a) + })?; + + cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; + cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; + cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; + cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; + cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; + cs.enforce_constraint(lc!() + a, lc!() + b, lc!() + c)?; + + println!("total number of constraints: {}", cs.num_constraints()); + + Ok(()) + } +} diff --git a/src/input_circuit.rs b/src/circuits/input_circuit.rs similarity index 57% rename from src/input_circuit.rs rename to src/circuits/input_circuit.rs index 91f5a26f..6574ba16 100644 --- a/src/input_circuit.rs +++ b/src/circuits/input_circuit.rs @@ -1,119 +1,14 @@ -use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; - -use ark_r1cs_std::groups::curves::twisted_edwards::AffineVar; -use ark_r1cs_std::{fields::fp::FpVar, prelude::*}; - use ark_bls12_377::Fr; +use ark_r1cs_std::{fields::fp::FpVar, prelude::*}; +use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; use std::cmp::Ordering; -use ark_crypto_primitives::{ - commitment::{ - pedersen::{constraints::CommGadget, Commitment, Randomness}, - CommitmentGadget, - }, - crh::pedersen, - CommitmentScheme, -}; - -use ark_ed_on_bls12_377::{constraints::EdwardsVar, EdwardsParameters}; +use super::{LocalOrMPC, PedersenComCircuit}; -pub type JubJub = ark_ed_on_bls12_377::EdwardsProjective; - -pub const PERDERSON_WINDOW_SIZE: usize = 100; -pub const PERDERSON_WINDOW_NUM: usize = 256; - -#[derive(Clone)] -pub struct Window; -impl pedersen::Window for Window { - const WINDOW_SIZE: usize = PERDERSON_WINDOW_SIZE; - const NUM_WINDOWS: usize = PERDERSON_WINDOW_NUM; -} - -pub type PedersenComScheme = Commitment; -pub type PedersenCommitment = ::Output; -pub type PedersenParam = ::Parameters; -pub type PedersenRandomness = Randomness; - -pub type PedersenComSchemeVar = CommGadget; -pub type PedersenParamVar = - >::ParametersVar; -pub type PedersenRandomnessVar = - >::RandomnessVar; -pub type PedersenCommitmentVar = AffineVar>; - -#[derive(Clone)] -pub struct PedersenComCircuit { - pub param: PedersenParam, - pub input: Fr, - pub open: PedersenRandomness, - pub commit: PedersenCommitment, -} - -impl ConstraintSynthesizer for PedersenComCircuit { - fn generate_constraints(self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> { - #[cfg(debug_assertions)] - println!("is setup mode?: {}", cs.is_in_setup_mode()); - let _cs_no = cs.num_constraints(); - - // step 1. Allocate Parameters for perdersen commitment - let param_var = - PedersenParamVar::new_input(ark_relations::ns!(cs, "gadget_parameters"), || { - Ok(&self.param) - }) - .unwrap(); - let _cs_no = cs.num_constraints() - _cs_no; - #[cfg(debug_assertions)] - println!("cs for parameters: {}", _cs_no); - let _cs_no = cs.num_constraints(); - - // step 2. Allocate inputs - let input_var = FpVar::new_witness(cs.clone(), || Ok(self.input))?; - let input_var_byte = input_var.to_bytes()?; - - let _cs_no = cs.num_constraints() - _cs_no; - #[cfg(debug_assertions)] - println!("cs for account: {}", _cs_no); - let _cs_no = cs.num_constraints(); - - // step 3. Allocate the opening - let open_var = - PedersenRandomnessVar::new_witness(ark_relations::ns!(cs, "gadget_randomness"), || { - Ok(&self.open) - }) - .unwrap(); - - let _cs_no = cs.num_constraints() - _cs_no; - #[cfg(debug_assertions)] - println!("cs for opening: {}", _cs_no); - let _cs_no = cs.num_constraints(); - - // step 4. Allocate the output - let result_var = - PedersenComSchemeVar::commit(¶m_var, &input_var_byte, &open_var).unwrap(); - - let _cs_no = cs.num_constraints() - _cs_no; - #[cfg(debug_assertions)] - println!("cs for commitment: {}", _cs_no); - let _cs_no = cs.num_constraints(); - - // circuit to compare the commited value with supplied value - let commitment_var2 = - PedersenCommitmentVar::new_input(ark_relations::ns!(cs, "gadget_commitment"), || { - Ok(self.commit) - }) - .unwrap(); - result_var.enforce_equal(&commitment_var2).unwrap(); - - let _cs_no = cs.num_constraints() - _cs_no; - #[cfg(debug_assertions)] - println!("cs for comparison: {}", _cs_no); - - #[cfg(debug_assertions)] - println!("total cs for Commitment: {}", cs.num_constraints()); - Ok(()) - } -} +type PedersenCommitment = >::PedersenCommitment; +type PedersenParam = >::PedersenParam; +type PedersenRandomness = >::PedersenRandomness; #[derive(Clone)] pub struct MySecretInputCircuit { @@ -168,10 +63,10 @@ impl MySecretInputCircuit { fn verify_commitment(&self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> { let x_com_circuit = PedersenComCircuit { - param: self.params.clone().unwrap(), - input: self.x.unwrap(), - open: self.randomness.clone().unwrap(), - commit: self.h_x.unwrap(), + param: self.params.clone(), + input: self.x, + open: self.randomness.clone(), + commit: self.h_x, }; x_com_circuit.generate_constraints(cs.clone())?; @@ -193,16 +88,18 @@ impl ConstraintSynthesizer for MySecretInputCircuit { #[cfg(test)] mod tests { use ark_bls12_377::Bls12_377; + use ark_crypto_primitives::CommitmentScheme; use ark_ff::{BigInteger, PrimeField}; use ark_groth16::Groth16; - use ark_snark::SNARK; - use ark_std::UniformRand; - use ark_marlin::*; use ark_poly::univariate::DensePolynomial; use ark_poly_commit::marlin_pc::MarlinKZG10; + use ark_snark::SNARK; + use ark_std::UniformRand; use blake2::Blake2s; + type PedersenComScheme = >::PedersenComScheme; + use super::*; #[test] @@ -262,7 +159,7 @@ mod tests { fn test_marlin() { let mut rng = rand::thread_rng(); - let universal_srs = MarlinLocal::universal_setup(50000, 250, 300, &mut rng).unwrap(); + let universal_srs = MarlinLocal::universal_setup(10000, 50, 100, &mut rng).unwrap(); // generate the setup parameters let x = Fr::from(4); diff --git a/src/circuits/pedersen.rs b/src/circuits/pedersen.rs new file mode 100644 index 00000000..2c590809 --- /dev/null +++ b/src/circuits/pedersen.rs @@ -0,0 +1,265 @@ +use ark_bls12_377::Fr; +use ark_ec::ProjectiveCurve; +use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; + +use ark_ff::PrimeField; +use ark_r1cs_std::groups::curves::twisted_edwards::AffineVar; +use ark_r1cs_std::{fields::fp::FpVar, prelude::*}; + +use ark_crypto_primitives::{ + commitment::{ + pedersen::{constraints::CommGadget, Commitment, Randomness}, + CommitmentGadget, + }, + crh::pedersen, + CommitmentScheme, +}; + +use ark_ed_on_bls12_377::{constraints::EdwardsVar, EdwardsParameters}; +use mpc_algebra::{ + AdditiveFieldShare, MpcEdwardsParameters, MpcEdwardsProjective, MpcEdwardsVar, MpcField, +}; + +use ark_ff::bytes::ToBytes; +use ark_std::{fmt::Debug, hash::Hash}; + +type MFr = MpcField>; + +pub trait LocalOrMPC { + type JubJub: ProjectiveCurve; + type PedersenComScheme: CommitmentScheme< + Output = Self::PedersenCommitment, + Parameters = Self::PedersenParam, + Randomness = Self::PedersenRandomness, + >; + type PedersenCommitment: ToBytes + Clone + Default + Eq + Hash + Debug; + type PedersenParam: Clone; + type PedersenRandomness: Clone + PartialEq + Debug + Eq + Default; + + type PedersenComSchemeVar: CommitmentGadget< + Self::PedersenComScheme, + ConstraintF, + OutputVar = Self::PedersenCommitmentVar, + ParametersVar = Self::PedersenParamVar, + RandomnessVar = Self::PedersenRandomnessVar, + >; + type PedersenParamVar: AllocVar + Clone; + type PedersenRandomnessVar: AllocVar<::Randomness, ConstraintF> + + Clone; + type PedersenCommitmentVar: EqGadget + + ToBytesGadget + + AllocVar<::Output, ConstraintF> + + R1CSVar + + Clone + + Sized + + Debug; +} + +impl LocalOrMPC for Fr { + type JubJub = ark_ed_on_bls12_377::EdwardsProjective; + + type PedersenComScheme = Commitment; + type PedersenCommitment = ::Output; + type PedersenParam = ::Parameters; + type PedersenRandomness = Randomness; + + type PedersenComSchemeVar = CommGadget; + type PedersenParamVar = >::ParametersVar; + type PedersenRandomnessVar = >::RandomnessVar; + type PedersenCommitmentVar = AffineVar>; +} + +impl LocalOrMPC for MFr { + type JubJub = MpcEdwardsProjective; + + type PedersenComScheme = Commitment; + type PedersenCommitment = ::Output; + type PedersenParam = ::Parameters; + type PedersenRandomness = Randomness; + + type PedersenComSchemeVar = CommGadget; + type PedersenParamVar = >::ParametersVar; + type PedersenRandomnessVar = >::RandomnessVar; + type PedersenCommitmentVar = AffineVar>; +} + +pub const PERDERSON_WINDOW_SIZE: usize = 256; +pub const PERDERSON_WINDOW_NUM: usize = 1; + +#[derive(Clone)] +pub struct Window; +impl pedersen::Window for Window { + const WINDOW_SIZE: usize = PERDERSON_WINDOW_SIZE; + const NUM_WINDOWS: usize = PERDERSON_WINDOW_NUM; +} + +#[derive(Clone)] +pub struct PedersenComCircuit> { + pub param: Option, + pub input: Option, + pub open: Option, + pub commit: Option, +} + +impl> ConstraintSynthesizer for PedersenComCircuit { + fn generate_constraints(self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> { + #[cfg(debug_assertions)] + println!("is setup mode?: {}", cs.is_in_setup_mode()); + let _cs_no = cs.num_constraints(); + + // step 1. Allocate Parameters for perdersen commitment + let param_var = + F::PedersenParamVar::new_input(ark_relations::ns!(cs, "gadget_parameters"), || { + self.param.ok_or(SynthesisError::AssignmentMissing) + })?; + let _cs_no = cs.num_constraints() - _cs_no; + #[cfg(debug_assertions)] + println!("cs for parameters: {}", _cs_no); + let _cs_no = cs.num_constraints(); + + // step 2. Allocate inputs + let input_var = FpVar::new_witness(cs.clone(), || { + self.input.ok_or(SynthesisError::AssignmentMissing) + })?; + let input_var_byte = input_var.to_bytes()?; + + let _cs_no = cs.num_constraints() - _cs_no; + #[cfg(debug_assertions)] + println!("cs for account: {}", _cs_no); + let _cs_no = cs.num_constraints(); + + // step 3. Allocate the opening + let open_var = F::PedersenRandomnessVar::new_witness( + ark_relations::ns!(cs, "gadget_randomness"), + || self.open.ok_or(SynthesisError::AssignmentMissing), + )?; + + let _cs_no = cs.num_constraints() - _cs_no; + #[cfg(debug_assertions)] + println!("cs for opening: {}", _cs_no); + let _cs_no = cs.num_constraints(); + + // step 4. Allocate the output + let result_var = F::PedersenComSchemeVar::commit(¶m_var, &input_var_byte, &open_var)?; + + let _cs_no = cs.num_constraints() - _cs_no; + #[cfg(debug_assertions)] + println!("cs for commitment: {}", _cs_no); + let _cs_no = cs.num_constraints(); + + // circuit to compare the commited value with supplied value + let commitment_var2 = F::PedersenCommitmentVar::new_input( + ark_relations::ns!(cs, "gadget_commitment"), + || self.commit.ok_or(SynthesisError::AssignmentMissing), + )?; + result_var.enforce_equal(&commitment_var2)?; + + let _cs_no = cs.num_constraints() - _cs_no; + #[cfg(debug_assertions)] + println!("cs for comparison: {}", _cs_no); + + #[cfg(debug_assertions)] + println!("total cs for Commitment: {}", cs.num_constraints()); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + use ark_ff::BigInteger; + use ark_std::{test_rng, UniformRand}; + + type MFr = mpc_algebra::MpcField>; + + #[test] + fn additivity_test_local() { + let rng = &mut test_rng(); + + let a = Fr::from(3); + + let params = >::PedersenComScheme::setup(rng).unwrap(); + + let randomness_a = >::PedersenRandomness::rand(rng); + + let a_bytes = a.into_repr().to_bytes_le(); + + let h_a = + >::PedersenComScheme::commit(¶ms, &a_bytes, &randomness_a) + .unwrap(); + + let b = Fr::from(4); + + let randomness_b = >::PedersenRandomness::rand(rng); + + let b_bytes = b.into_repr().to_bytes_le(); + + let h_b = + >::PedersenComScheme::commit(¶ms, &b_bytes, &randomness_b) + .unwrap(); + + // Note: Do not exceed the modulus. break additivity + let sum = a + b; + + let randomness = Randomness(randomness_a.0 + randomness_b.0); + + let bytes = sum.into_repr().to_bytes_le(); + + let h_sum = >::PedersenComScheme::commit(¶ms, &bytes, &randomness) + .unwrap(); + + assert_eq!(h_a + h_b, h_sum) + } + + #[test] + fn additivity_test_mpc() { + let rng = &mut test_rng(); + + let a = MFr::Public(Fr::from(3)); + + let params = >::PedersenComScheme::setup(rng).unwrap(); + + let randomness_a = >::PedersenRandomness::rand(rng); + + let a_bytes = a.into_repr().to_bytes_le(); + + let h_a = + >::PedersenComScheme::commit(¶ms, &a_bytes, &randomness_a) + .unwrap(); + + let b = MFr::Public(Fr::from(4)); + + let randomness_b = >::PedersenRandomness::rand(rng); + + let b_bytes = b.into_repr().to_bytes_le(); + + let h_b = + >::PedersenComScheme::commit(¶ms, &b_bytes, &randomness_b) + .unwrap(); + + let sum = a + b; + + let randomness = Randomness(randomness_a.0 + randomness_b.0); + + let bytes = sum.into_repr().to_bytes_le(); + + let h_sum = + >::PedersenComScheme::commit(¶ms, &bytes, &randomness) + .unwrap(); + + assert_eq!(h_a + h_b, h_sum) + } +} diff --git a/src/groth16.rs b/src/groth16.rs index ef839619..2f386d66 100644 --- a/src/groth16.rs +++ b/src/groth16.rs @@ -5,7 +5,7 @@ mod tests { use ark_snark::SNARK; use ark_std::UniformRand; - use super::super::circuit::MyCircuit; + use super::super::circuits::circuit::MySimpleCircuit; #[test] fn test_single() { @@ -17,7 +17,7 @@ mod tests { let mut c = a; c *= b; - let circuit = MyCircuit:: { + let circuit = MySimpleCircuit:: { a: Some(a), b: Some(b), }; diff --git a/src/main.rs b/src/main.rs index 436f46ba..d455dfea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,8 @@ #![allow(dead_code)] mod algebra; -mod circuit; +mod circuits; mod groth16; -mod input_circuit; mod marlin; mod preprocessing; mod serialize; @@ -27,6 +26,7 @@ use std::io::Write as Otherwrite; use structopt::StructOpt; +use crate::circuits::*; use crate::serialize::write_to_file; #[derive(Debug, StructOpt)] @@ -142,10 +142,11 @@ fn main() -> Result<(), Box> { let upper_bound = Fr::from(7); // // Pedersen commitment - let params = input_circuit::PedersenComScheme::setup(&mut rng).unwrap(); - let randomness = input_circuit::PedersenRandomness::rand(&mut rng); + let params = >::PedersenComScheme::setup(&mut rng).unwrap(); + let randomness = >::PedersenRandomness::rand(&mut rng); let x_bytes = x.into_repr().to_bytes_le(); - let h_x = input_circuit::PedersenComScheme::commit(¶ms, &x_bytes, &randomness).unwrap(); + let h_x = + >::PedersenComScheme::commit(¶ms, &x_bytes, &randomness).unwrap(); let circuit = input_circuit::MySecretInputCircuit::new( x, @@ -173,7 +174,7 @@ fn main() -> Result<(), Box> { } ZkSnark::Marlin => { let universal_srs = - MarlinLocal::universal_setup(50000, 250, 300, &mut rng).expect("Failed to setup"); + MarlinLocal::universal_setup(10000, 50, 100, &mut rng).expect("Failed to setup"); let (index_pk, index_vk) = MarlinLocal::index(&universal_srs, circuit.clone()).unwrap(); println!("Called index"); @@ -215,7 +216,7 @@ fn main() -> Result<(), Box> { let reader: &[u8] = &hex::decode(remove_prefix_string).unwrap(); - let deserialized_h_x: input_circuit::PedersenCommitment = + let deserialized_h_x: >::PedersenCommitment = ark_ec::models::twisted_edwards_extended::GroupAffine::deserialize(reader).unwrap(); assert_eq!(h_x, deserialized_h_x); diff --git a/src/marlin.rs b/src/marlin.rs index 10b827c2..3eafa6bd 100644 --- a/src/marlin.rs +++ b/src/marlin.rs @@ -1,11 +1,15 @@ +use ark_crypto_primitives::CommitmentScheme; +use ark_ff::{BigInteger, PrimeField}; use ark_marlin::{ahp::prover::*, *}; use ark_poly::univariate::DensePolynomial; use ark_poly_commit::marlin_pc::MarlinKZG10; -use ark_std::{end_timer, start_timer, test_rng}; +use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; +use ark_std::{end_timer, start_timer, test_rng, PubUniformRand, UniformRand}; use blake2::Blake2s; use mpc_algebra::*; +use mpc_net::{MpcMultiNet, MpcNet}; -use crate::circuit::MyCircuit; +use crate::circuits::{circuit::MyCircuit, LocalOrMPC, PedersenComCircuit}; pub type MpcField = wire::field::MpcField>; // pub type MpcGroup = group::MpcGroup>>; @@ -87,31 +91,107 @@ pub fn pf_publicize( type Fr = ark_bls12_377::Fr; type E = ark_bls12_377::Bls12_377; type ME = MpcPairingEngine; -type MFr = MpcField; +pub type MFr = MpcField; type MpcMarlinKZG10 = MarlinKZG10>; type LocalMarlinKZG10 = MarlinKZG10>; -type LocalMarlin = Marlin; -type MpcMarlin = Marlin; +pub type LocalMarlin = Marlin; +pub type MpcMarlin = Marlin; pub fn mpc_test_prove_and_verify(n_iters: usize) { + let n = 2; + let rng = &mut test_rng(); - let srs = LocalMarlin::universal_setup(100, 50, 100, rng).unwrap(); - println!("srs: {srs:?}"); - let empty_circuit: MyCircuit = MyCircuit { a: None, b: None }; + let srs = LocalMarlin::universal_setup(10000, 50, 100, rng).unwrap(); + + let params = >::PedersenComScheme::setup(rng).unwrap(); + + let vec_x = (0..n).map(|_| Fr::from(0)).collect::>(); + + let vec_x_bytes = vec_x + .iter() + .map(|x| x.into_repr().to_bytes_le()) + .collect::>(); + + let randomness = (0..n) + .map(|_| >::PedersenRandomness::rand(rng)) + .collect::>(); + + let h_x_vec = (0..n) + .map(|i| { + >::PedersenComScheme::commit( + ¶ms, + &vec_x_bytes[i], + &randomness[i], + ) + .unwrap() + }) + .collect::>(); + + let empty_circuit: MyCircuit = MyCircuit { + a: None, + b: None, + params: Some(params.clone()), + vec_x: Some(vec_x.clone()), + randomness: Some(randomness.clone()), + vec_h_x: Some(h_x_vec.clone()), + }; let (index_pk, index_vk) = LocalMarlin::index(&srs, empty_circuit).unwrap(); let mpc_index_pk = IndexProverKey::from_public(index_pk); for _ in 0..n_iters { let a = MpcField::::from(2u8); let b = MpcField::::from(2u8); + + // Pedersen commitment + //// commom parameter + let mpc_params = params.to_mpc(); + + //// input + let x = (0..n).map(|_| MFr::pub_rand(rng)).collect::>(); + let x_bytes = x + .iter() + .map(|x| x.into_repr().to_bytes_le()) + .collect::>(); + + //// randomness + let randomness = (0..n) + .map(|_| >::PedersenRandomness::pub_rand(rng)) + .collect::>(); + + //// commitment + let h_x = x_bytes + .iter() + .zip(randomness.iter()) + .map(|(x_bytes, randomness)| { + >::PedersenComScheme::commit( + &mpc_params, + &x_bytes, + &randomness, + ) + .unwrap() + }) + .collect::>(); + let circ = MyCircuit { a: Some(a), b: Some(b), + params: Some(mpc_params.clone()), + vec_x: Some(x.clone()), + randomness: Some(randomness.clone()), + vec_h_x: Some(h_x.clone()), }; let mut c = a; c *= &b; - let inputs = vec![c.reveal()]; + let mut inputs = vec![c.reveal()]; + + for commitment in h_x { + inputs.push(commitment.x.reveal()); + inputs.push(commitment.y.reveal()); + } + + // then, inputs is like [c, h_x_1.x, h_x_1.y, h_x_2.x, h_x_2.y, ...] + println!("{a}\n{b}\n{c}"); let mpc_proof = MpcMarlin::prove(&mpc_index_pk, circ, rng).unwrap(); let proof = pf_publicize(mpc_proof); @@ -122,3 +202,148 @@ pub fn mpc_test_prove_and_verify(n_iters: usize) { assert!(!is_valid); } } + +pub fn mpc_test_prove_and_verify_pedersen(n_iters: usize) { + // setup + let rng = &mut test_rng(); + + let srs = LocalMarlin::universal_setup(5000, 50, 100, rng).unwrap(); + + // Pedersen commitment + //// commom parameter + let params = >::PedersenComScheme::setup(rng).unwrap(); + + //// input + let x = Fr::from(4); + let x_bytes = x.into_repr().to_bytes_le(); + + //// randomness + let randomness = >::PedersenRandomness::pub_rand(rng); + + //// commitment + let h_x_local = + >::PedersenComScheme::commit(¶ms, &x_bytes, &randomness).unwrap(); + + let empty_circuit = PedersenComCircuit { + param: Some(params.clone()), + input: Some(x), + open: Some(randomness.clone()), + commit: Some(h_x_local), + }; + + let (index_pk, index_vk) = LocalMarlin::index(&srs, empty_circuit).unwrap(); + let mpc_index_pk = IndexProverKey::from_public(index_pk); + + for _ in 0..n_iters { + // Pedersen commitment + //// commom parameter + let mpc_params = params.to_mpc(); + + //// input + let x = MFr::pub_rand(rng); + let x_bytes = x.into_repr().to_bytes_le(); + + //// randomness + let randomness = >::PedersenRandomness::pub_rand(rng); + + //// commitment + let h_x = + >::PedersenComScheme::commit(&mpc_params, &x_bytes, &randomness) + .unwrap(); + + let circuit = PedersenComCircuit { + param: Some(mpc_params.clone()), + input: Some(x), + open: Some(randomness.clone()), + commit: Some(h_x), + }; + + let inputs = vec![h_x.x.reveal(), h_x.y.reveal()]; + let invalid_inputs = vec![h_x.y.reveal(), h_x.x.reveal()]; + + // prove + let mpc_proof = MpcMarlin::prove(&mpc_index_pk, circuit, rng).unwrap(); + let proof = pf_publicize(mpc_proof); + + // verify + let is_valid = LocalMarlin::verify(&index_vk, &inputs, &proof, rng).unwrap(); + assert!(is_valid); + let is_valid = LocalMarlin::verify(&index_vk, &invalid_inputs, &proof, rng).unwrap(); + assert!(!is_valid); + } +} + +pub fn mpc_test_each_commit(n_iters: usize) { + // setup + let rng = &mut test_rng(); + + let srs = LocalMarlin::universal_setup(5000, 50, 100, rng).unwrap(); + + // Pedersen commitment + //// commom parameter + let params = >::PedersenComScheme::setup(rng).unwrap(); + + //// input(parent) + let mut share_x = [Fr::from(3), Fr::from(8), Fr::from(20)]; + let x: Fr = share_x.iter().sum(); + let x_bytes = x.into_repr().to_bytes_le(); + + //// randomness(parent) + let randomness = >::PedersenRandomness::default(); + + //// commitment(parent) + let h_x_local = + >::PedersenComScheme::commit(¶ms, &x_bytes, &randomness).unwrap(); + + let empty_circuit = PedersenComCircuit { + param: Some(params.clone()), + input: Some(x), + open: Some(randomness.clone()), + commit: Some(h_x_local), + }; + + let (index_pk, index_vk) = LocalMarlin::index(&srs, empty_circuit).unwrap(); + + for _ in 0..n_iters { + // Pedersen commitment + //// input(child) + let n = MpcMultiNet::party_id(); + let commitment = { + // println!("party id is: {}", n); + + let x = share_x[n]; + let x_bytes = x.into_repr().to_bytes_le(); + + //// randomness + let randomness = >::PedersenRandomness::default(); + + //// commitment + let h_x = + >::PedersenComScheme::commit(¶ms, &x_bytes, &randomness) + .unwrap(); + + let circuit = PedersenComCircuit { + param: Some(params.clone()), + input: Some(x), + open: Some(randomness.clone()), + commit: Some(h_x), + }; + + let inputs = vec![h_x.x, h_x.y]; + let invalid_inputs = vec![h_x.y, h_x.x]; + + // prove + let proof = LocalMarlin::prove(&index_pk, circuit, rng).unwrap(); + + // verify + let is_valid = LocalMarlin::verify(&index_vk, &inputs, &proof, rng).unwrap(); + assert!(is_valid); + let is_valid = LocalMarlin::verify(&index_vk, &invalid_inputs, &proof, rng).unwrap(); + assert!(!is_valid); + + h_x + }; + + assert_eq!(h_x_local, commitment.reveal()); + } +} diff --git a/src/online.rs b/src/online.rs new file mode 100644 index 00000000..1a49e4c5 --- /dev/null +++ b/src/online.rs @@ -0,0 +1,237 @@ +use ark_bls12_377::Fr; +use ark_crypto_primitives::CommitmentScheme; +use ark_ff::{BigInteger, PrimeField}; +use ark_marlin::IndexProverKey; +use ark_serialize::Read; +use ark_std::test_rng; + +use mpc_algebra::Reveal; +use mpc_net::{MpcMultiNet as Net, MpcNet}; + +use serde::Deserialize; +use std::{fs::File, path::PathBuf, vec}; +use structopt::StructOpt; + +mod circuits; +use circuits::{circuit::MySimpleCircuit, LocalOrMPC, PedersenComCircuit}; +mod marlin; +use marlin::*; + +#[derive(Debug, StructOpt)] +#[structopt(name = "example", about = "An example of StructOpt usage.")] +struct Opt { + zksnark: String, + + // Input value file + input_file_path: String, + + // Id + id: usize, + + // Input address file + #[structopt(parse(from_os_str))] + input: PathBuf, +} + +#[derive(Debug, Deserialize)] +struct ArgInput { + x: u128, + y: u128, + z: u128, +} + +enum ZkSnark { + Groth16, + Marlin, +} + +fn which_zksnark(zksnark: &str) -> Result { + match zksnark { + "groth16" => Ok(ZkSnark::Groth16), + "marlin" => Ok(ZkSnark::Marlin), + _ => Err(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + "Only groth16 or marlin are supported", + )), + } +} + +fn main() -> Result<(), Box> { + let opt = Opt::from_args(); + + let zksnark: ZkSnark = match which_zksnark(&opt.zksnark) { + Ok(zk) => { + println!("selected zksnarks is OK"); + zk + } + Err(err) => { + eprintln!("Error: {err}"); + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::InvalidInput, + err, + ))); + } + }; + + // init + Net::init_from_file(opt.input.to_str().unwrap(), opt.id); + + let mut file = File::open(opt.input_file_path).expect("Failed to open file"); + let mut contents = String::new(); + file.read_to_string(&mut contents) + .expect("Failed to read file"); + + let data: ArgInput = serde_json::from_str(&contents).unwrap(); + println!("{:?}", data); + + let rng = &mut test_rng(); + + // online calculation + + // TODO: Separate the following part in preprocessing. + let shared_input = match Net::party_id() { + 0 => { + vec![ + MFr::from_add_shared(Fr::from(data.x)), + MFr::from_add_shared(Fr::from(0)), + MFr::from_add_shared(Fr::from(0)), + ] + } + 1 => { + vec![ + MFr::from_add_shared(Fr::from(0)), + MFr::from_add_shared(Fr::from(data.y)), + MFr::from_add_shared(Fr::from(0)), + ] + } + 2 => { + vec![ + MFr::from_add_shared(Fr::from(0)), + MFr::from_add_shared(Fr::from(0)), + MFr::from_add_shared(Fr::from(data.z)), + ] + } + _ => panic!("invalid party id"), + }; + + match zksnark { + ZkSnark::Groth16 => {} + ZkSnark::Marlin => { + let srs = LocalMarlin::universal_setup(10000, 50, 100, rng).expect("Failed to setup"); + + // commitmnet phase + // Pedersen commitment + //// commom parameter + let params = >::PedersenComScheme::setup(rng).unwrap(); + + // TODO: Load local_commitment from file + + let mut vec_inputs = Vec::new(); + let mut vec_randomness = Vec::new(); + let mut vec_h_x_local = Vec::new(); + + for x in shared_input.clone() { + //// input(parent) + let x_parent: Fr = x.clone().reveal(); + vec_inputs.push(x_parent.clone()); + let x_bytes = x_parent.into_repr().to_bytes_le(); + + //// randomness(parent) + let randomness = >::PedersenRandomness::default(); + + vec_randomness.push(randomness.clone()); + + //// commitment(parent) + let h_x_local = >::PedersenComScheme::commit( + ¶ms, + &x_bytes, + &randomness, + ) + .unwrap(); + + vec_h_x_local.push(h_x_local); + } + + let empty_circuit = PedersenComCircuit { + param: Some(params.clone()), + input: Some(vec_inputs[0]), + open: Some(vec_randomness[0].clone()), + commit: Some(vec_h_x_local[0]), + }; + + let (index_pk, index_vk) = LocalMarlin::index(&srs, empty_circuit).unwrap(); + + // Pedersen commitment + let commitment = shared_input + .iter() + .map(|x| { + //// input(child) + let x = x.unwrap_as_public(); + let x_bytes = x.into_repr().to_bytes_le(); + + //// randomness + let randomness = >::PedersenRandomness::default(); + + //// commitment + let h_x = >::PedersenComScheme::commit( + ¶ms, + &x_bytes, + &randomness, + ) + .unwrap(); + + let circuit = PedersenComCircuit { + param: Some(params.clone()), + input: Some(x), + open: Some(randomness.clone()), + commit: Some(h_x), + }; + + let inputs = vec![h_x.x, h_x.y]; + let invalid_inputs = vec![h_x.y, h_x.x]; + + // prove + let proof = LocalMarlin::prove(&index_pk, circuit, rng).unwrap(); + + // verify + let is_valid = LocalMarlin::verify(&index_vk, &inputs, &proof, rng).unwrap(); + assert!(is_valid); + let is_valid = + LocalMarlin::verify(&index_vk, &invalid_inputs, &proof, rng).unwrap(); + assert!(!is_valid); + + h_x + }) + .collect::>(); + + vec_h_x_local + .iter() + .zip(commitment.iter()) + .for_each(|(&x, y)| { + assert_eq!(x, y.reveal()); + }); + + // calculation phase + let empty_circuit: MySimpleCircuit = MySimpleCircuit { a: None, b: None }; + + let (index_pk, index_vk) = LocalMarlin::index(&srs, empty_circuit.clone()).unwrap(); + let mpc_index_pk = IndexProverKey::from_public(index_pk); + println!("Called index"); + + let circuit = MySimpleCircuit { + a: Some(shared_input[0].clone()), + b: Some(shared_input[1].clone()), + }; + let c = shared_input[0].clone() * shared_input[1].clone(); + + // calculate the proof by passing witness variable value + let mpc_proof = MpcMarlin::prove(&mpc_index_pk, circuit.clone(), rng).unwrap(); + let proof = pf_publicize(mpc_proof); + println!("Called prover"); + + assert!(LocalMarlin::verify(&index_vk, &[c.reveal()], &proof, rng).unwrap()); + } + } + + Ok(()) +}