Skip to content

Commit

Permalink
feat: prepare functions for compressed rep3 sharing
Browse files Browse the repository at this point in the history
  • Loading branch information
rw0x0 authored and 0xThemis committed Oct 15, 2024
1 parent f6ad386 commit 55bef10
Show file tree
Hide file tree
Showing 7 changed files with 601 additions and 10 deletions.
182 changes: 179 additions & 3 deletions co-circom/co-circom-snarks/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,46 @@ use ark_ff::PrimeField;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use circom_types::Witness;
use mpc_core::protocols::{
rep3::{self, Rep3PrimeFieldShare},
rep3::{self, Rep3PrimeFieldShare, Rep3ShareVecType},
shamir::{self, ShamirPrimeFieldShare},
};
use rand::{CryptoRng, Rng};
use rand::{distributions::Standard, prelude::Distribution, CryptoRng, Rng, SeedableRng};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;

mod serde_compat;

/// This type represents the serialized version of a Rep3 witness. Its share can be either additive or replicated, and in both cases also compressed.
#[derive(Debug, Serialize, Deserialize)]
#[serde(bound = "")]
pub struct SerializeableSharedRep3Witness<F: PrimeField, U: Rng + SeedableRng + CryptoRng>
where
U::Seed: Serialize + for<'a> Deserialize<'a> + Clone + std::fmt::Debug,
{
/// The public inputs (which are the outputs of the circom circuit).
/// This also includes the constant 1 at position 0.
#[serde(
serialize_with = "crate::serde_compat::ark_se",
deserialize_with = "crate::serde_compat::ark_de"
)]
pub public_inputs: Vec<F>,
/// The secret-shared witness elements.
pub witness: Rep3ShareVecType<F, U>,
}

impl<F: PrimeField, U: Rng + SeedableRng + CryptoRng> SerializeableSharedRep3Witness<F, U>
where
U::Seed: Serialize + for<'a> Deserialize<'a> + Clone + std::fmt::Debug,
{
/// Transforms a shared witness into a serializable version.
pub fn from_shared_witness(inp: SharedWitness<F, Rep3PrimeFieldShare<F>>) -> Self {
Self {
public_inputs: inp.public_inputs,
witness: Rep3ShareVecType::Replicated(inp.witness),
}
}
}

//TODO THE SECRETSHARED TRAIT IS REALLY BAD. WE DO WANT SOMETHING ELSE!
/// A shared witness in the circom ecosystem.
#[derive(Debug, Serialize, Deserialize)]
Expand All @@ -37,6 +68,115 @@ where
pub witness: Vec<S>,
}

/// This type represents the serialized version of a Rep3 witness. Its share can be either additive or replicated, and in both cases also compressed.
#[derive(Debug, Serialize, Deserialize)]
#[serde(bound = "")]
pub struct SerializeableSharedRep3Input<F: PrimeField, U: Rng + SeedableRng + CryptoRng>
where
U::Seed: Serialize + for<'a> Deserialize<'a> + Clone + std::fmt::Debug,
{
#[serde(
serialize_with = "crate::serde_compat::ark_se",
deserialize_with = "crate::serde_compat::ark_de"
)]
/// A map from variable names to the public field elements.
/// This is a BTreeMap because it implements Canonical(De)Serialize.
pub public_inputs: BTreeMap<String, Vec<F>>,
/// A map from variable names to the share of the field element.
/// This is a BTreeMap because it implements Canonical(De)Serialize.
pub shared_inputs: BTreeMap<String, Rep3ShareVecType<F, U>>,
}

impl<F: PrimeField, U: Rng + SeedableRng + CryptoRng> Default for SerializeableSharedRep3Input<F, U>
where
U::Seed: Serialize + for<'a> Deserialize<'a> + Clone + std::fmt::Debug,
{
fn default() -> Self {
Self {
public_inputs: BTreeMap::new(),
shared_inputs: BTreeMap::new(),
}
}
}

impl<F: PrimeField, U: Rng + SeedableRng + CryptoRng> SerializeableSharedRep3Input<F, U>
where
U::Seed: Serialize + for<'a> Deserialize<'a> + Clone + std::fmt::Debug,
Standard: Distribution<U::Seed>,
{
/// Shares a given input into a [Rep3ShareVecType] type.
pub fn share_rep3<R: Rng + CryptoRng>(
input: &[F],
rng: &mut R,
seeded: bool,
additive: bool,
) -> [Rep3ShareVecType<F, U>; 3] {
let (share1, share2, share3) = match (seeded, additive) {
(true, true) => {
let [share1, share2, share3] =
rep3::share_field_elements_additive_seeded::<_, _, U>(input, rng);
let share1 = Rep3ShareVecType::SeededAdditive(share1);
let share2 = Rep3ShareVecType::SeededAdditive(share2);
let share3 = Rep3ShareVecType::SeededAdditive(share3);
(share1, share2, share3)
}
(true, false) => {
let [share1, share2, share3] =
rep3::share_field_elements_seeded::<_, _, U>(input, rng);
let share1 = Rep3ShareVecType::SeededReplicated(share1);
let share2 = Rep3ShareVecType::SeededReplicated(share2);
let share3 = Rep3ShareVecType::SeededReplicated(share3);
(share1, share2, share3)
}
(false, true) => {
let [share1, share2, share3] = rep3::share_field_elements_additive(input, rng);
let share1 = Rep3ShareVecType::Additive(share1);
let share2 = Rep3ShareVecType::Additive(share2);
let share3 = Rep3ShareVecType::Additive(share3);
(share1, share2, share3)
}
(false, false) => {
let [share1, share2, share3] = rep3::share_field_elements(input, rng);
let share1 = Rep3ShareVecType::Replicated(share1);
let share2 = Rep3ShareVecType::Replicated(share2);
let share3 = Rep3ShareVecType::Replicated(share3);
(share1, share2, share3)
}
};
[share1, share2, share3]
}

/// Merges two [SerializeableSharedRep3Input]s into one, performing basic sanity checks.
pub fn merge(self, other: Self) -> eyre::Result<Self> {
let mut shared_inputs = self.shared_inputs;
let public_inputs = self.public_inputs;
for (key, value) in other.shared_inputs {
if shared_inputs.contains_key(&key) {
eyre::bail!("Input with name {} present in multiple input shares", key);
}
if public_inputs.contains_key(&key) || other.public_inputs.contains_key(&key) {
eyre::bail!(
"Input name is once in shared inputs and once in public inputs: \"{key}\""
);
}
shared_inputs.insert(key, value);
}
for (key, value) in other.public_inputs {
if !public_inputs.contains_key(&key) {
eyre::bail!("Public input \"{key}\" must be present in all files");
}
if public_inputs.get(&key).expect("is there we checked") != &value {
eyre::bail!("Public input \"{key}\" must be same in all files");
}
}

Ok(Self {
shared_inputs,
public_inputs,
})
}
}

/// A shared input for a collaborative circom witness extension.
#[derive(Debug, Serialize, Deserialize)]
pub struct SharedInput<F: PrimeField, S>
Expand Down Expand Up @@ -142,8 +282,44 @@ where
}
}

impl<F: PrimeField> SharedWitness<F, Rep3PrimeFieldShare<F>> {
impl<F: PrimeField, U: Rng + SeedableRng + CryptoRng> SerializeableSharedRep3Witness<F, U>
where
U::Seed: Serialize + for<'a> Deserialize<'a> + Clone + std::fmt::Debug,

Standard: Distribution<U::Seed>,
{
/// Shares a given witness and public input vector using the Rep3 protocol.
pub fn share_rep3<R: Rng + CryptoRng>(
witness: Witness<F>,
num_pub_inputs: usize,
rng: &mut R,
seeded: bool,
additive: bool,
) -> [Self; 3] {
let public_inputs = &witness.values[..num_pub_inputs];
let witness = &witness.values[num_pub_inputs..];

let [share1, share2, share3] =
SerializeableSharedRep3Input::share_rep3(witness, rng, seeded, additive);

let witness1 = Self {
public_inputs: public_inputs.to_vec(),
witness: share1,
};
let witness2 = Self {
public_inputs: public_inputs.to_vec(),
witness: share2,
};
let witness3 = Self {
public_inputs: public_inputs.to_vec(),
witness: share3,
};
[witness1, witness2, witness3]
}
}

impl<F: PrimeField> SharedWitness<F, Rep3PrimeFieldShare<F>> {
/// Shares a given witness and public input vector using the rep3 protocol.
pub fn share_rep3<R: Rng + CryptoRng>(
witness: Witness<F>,
num_pub_inputs: usize,
Expand Down
11 changes: 8 additions & 3 deletions co-circom/co-groth16/src/groth16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -477,9 +477,8 @@ where
P::BaseField: CircomArkworksPrimeFieldBridge,
P::ScalarField: CircomArkworksPrimeFieldBridge,
{
/// Create a new [Rep3CoGroth16] protocol with a given network configuration.
pub fn with_network_config(config: NetworkConfig) -> Result<Self> {
let mpc_net = Rep3MpcNet::new(config)?;
/// Create a new [Rep3CoGroth16] protocol with a given network.
pub fn with_network(mpc_net: Rep3MpcNet) -> Result<Self> {
let mut io_context0 = IoContext::init(mpc_net)?;
let io_context1 = io_context0.fork()?;
let driver = Rep3Groth16Driver::new(io_context0, io_context1);
Expand All @@ -488,6 +487,12 @@ where
phantom_data: PhantomData,
})
}

/// Create a new [Rep3CoGroth16] protocol with a given network configuration.
pub fn with_network_config(config: NetworkConfig) -> Result<Self> {
let mpc_net = Rep3MpcNet::new(config)?;
Self::with_network(mpc_net)
}
}

impl<P: Pairing> ShamirCoGroth16<P, ShamirMpcNet>
Expand Down
11 changes: 8 additions & 3 deletions co-circom/co-plonk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,8 @@ mod plonk_utils {
}

impl<P: Pairing> Rep3CoPlonk<P> {
/// Create a new [Rep3CoPlonk] protocol with a given network configuration.
pub fn with_network_config(config: NetworkConfig) -> eyre::Result<Self> {
let mpc_net = Rep3MpcNet::new(config)?;
/// Create a new [Rep3CoPlonk] protocol with a given network.
pub fn with_network(mpc_net: Rep3MpcNet) -> eyre::Result<Self> {
let mut io_context0 = IoContext::init(mpc_net)?;
let io_context1 = io_context0.fork()?;
let driver = Rep3PlonkDriver::new(io_context0, io_context1);
Expand All @@ -232,6 +231,12 @@ impl<P: Pairing> Rep3CoPlonk<P> {
phantom_data: PhantomData,
})
}

/// Create a new [Rep3CoPlonk] protocol with a given network configuration.
pub fn with_network_config(config: NetworkConfig) -> eyre::Result<Self> {
let mpc_net = Rep3MpcNet::new(config)?;
Self::with_network(mpc_net)
}
}

impl<P: Pairing> ShamirCoPlonk<P> {
Expand Down
1 change: 1 addition & 0 deletions mpc-core/src/protocols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
pub mod bridges;
pub mod rep3;
pub(crate) mod serde_compat;
pub mod shamir;
31 changes: 31 additions & 0 deletions mpc-core/src/protocols/bridges/rep3_to_shamir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,37 @@ impl<F: PrimeField, N: ShamirNetwork> ShamirProtocol<F, N> {
self.degree_reduce_vec(muls)
}

/// Translate a 3-party additive prime field share into a 3-party Shamir prime field share, where the underlying sharing polynomial is of degree 1 (i.e., the threshold t = 1).
pub fn translate_primefield_addshare(
&mut self,
input: F,
) -> std::io::Result<ShamirPrimeFieldShare<F>> {
// Essentially, a mul function
let my_lagrange_coeff = self.open_lagrange_2t[0]
.inverse()
.expect("lagrange coeff must be invertible");
let mul = input * my_lagrange_coeff;
self.degree_reduce(mul)
}

/// Translate a 3-party additive prime field share vector into a 3-party Shamir prime field share vector, where the underlying sharing polynomial is of degree 1 (i.e., the threshold t = 1).
pub fn translate_primefield_addshare_vec(
&mut self,
input: Vec<F>,
) -> std::io::Result<Vec<ShamirPrimeFieldShare<F>>> {
// Essentially, a mul_vec function
let my_lagrange_coeff = self.open_lagrange_2t[0]
.inverse()
.expect("lagrange coeff must be invertible");
// TODO maybe we do not collect here? we can just provide the iter
// to the next function?
let muls = input
.into_iter()
.map(|share| share * my_lagrange_coeff)
.collect::<Vec<_>>();
self.degree_reduce_vec(muls)
}

/// Translate a Rep3 point share into a 3-party Shamir point share, where the underlying sharing polynomial is of degree 1 (i.e., the threshold t = 1).
pub fn translate_point_repshare<C>(
&mut self,
Expand Down
Loading

0 comments on commit 55bef10

Please sign in to comment.