This repositry is zk-mpc.
The following is the main directory structure.
.
|-- Cargo.lock
|-- Cargo.toml
|-- README.md
|-- arkworks # Arkworks libraries
|-- benches # Benchmarking
|-- data
| `-- address
|-- docs # subDocuments
| `-- benchmark.md # Benchmarking results
|-- examples # Binary files are here.
| |-- bin_test_groth16.rs
| |-- bin_test_marlin.rs
| |-- bin_werewolf.rs # Werewolf game binary file.
| `-- online.rs # Online phase (in MPC) binary file.
|-- images # Image assets
|-- inputs
| |-- inputs-template.json
| `-- inputs.json
|-- mpc-algebra # Sub crate: MPC algebra. MpcField, MpcVar, etc.
| |-- Cargo.lock
| |-- Cargo.toml
| |-- README.md
| |-- data
| |-- examples
| |-- src
| `-- test.zsh
|-- mpc-net # Sub crate: MPC network. MpcNet, MpcNetServer, etc.
| |-- Cargo.lock
| |-- Cargo.toml
| |-- data
| |-- examples
| `-- src
|-- mpc-trait
| |-- Cargo.toml
| `-- src
|-- run_groth16.zsh # Script for Run groth16
|-- run_marlin.zsh # Script for Run marlin
|-- run_online.zsh # Script for Run online phase
|-- run_werewolf.zsh # Script for Run werewolf game
`-- src
|-- algebra.rs
|-- circuits # Circuits modules. Various circuits are defined here.
|-- circuits.rs
|-- groth16.rs # Groth16(zk-SNARKs) module
|-- input.rs # Input structs are defined in circuits.
|-- lib.rs
|-- main.rs # Main binary file used for preprocessing phase.
|-- marlin.rs # Marlin(zk-SNARKs) module
|-- preprocessing.rs # Preprocessing module, which is required for MPC.
|-- serialize.rs
|-- she # Somewhat Homomorphic Encryption sub module.
`-- she.rs # Somewhat Homomorphic Encryption
Clone this repositry:
git clone https://github.com/Yoii-Inc/zk-mpc.git
and build:
cargo build
setup input file
cp ./inputs/inputs-template.json ./inputs/inputs.json
setup output folder
mkdir ./outputs
mkdir ./outputs/0
mkdir ./outputs/1
mkdir ./outputs/2
run(by groth16):
cargo run --bin main groth16 ./inputs/inputs.json
or run(by marlin):
cargo run --bin main marlin ./inputs/inputs.json
run online phase
./run_online.zsh
The tests performed by the following DOES NOT include MPC. Therefore, testing of the MPC itself is performed by executing preprocessing and online as described above.
cargo test --bin main
./run_marlin.zsh
or
./mpc-algebra/test.zsh
To specify secret inputs, follow these steps:
-
In the
inputs/inputs.json
file, define the desired inputs using a JSON format. For example:{ "arg1": 10, "arg2": -2, "arg3": "value3" }
You can modify the number and types of arguments based on your requirements.
-
In the main.rs file of your project, use the ArgInput struct to receive the specified arguments. Make sure to update the struct definition to match the number and types of arguments you specified in the inputs.json file. For example:
struct ArgInput { arg1: u128, arg2: i32, arg3: String, }
Modify the ArgInput struct as needed to accommodate the changes in the number and types of arguments.
By following these steps, you can specify secret inputs in the inputs.json file and receive them in your Rust program using the ArgInput struct.
Constraints are specified in input_circuit.rs
. For example:
pub struct MySecretInputCircuit<F: PrimeField + LocalOrMPC<F>> {
// private witness to the circuit
x: Option<F>,
input_bit: Option<Vec<F>>,
open_bit: Option<Vec<F>>,
params: Option<F::PedersenParam>,
// public instance to the circuit
h_x: Option<F::PedersenCommitment>,
lower_bound: Option<F>,
upper_bound: Option<F>,
}
This sturuct represents a circuit, and it requires to define the necessary witness and public instances.
In addition, the constraints in the circuit are defined as follows.
impl<F: PrimeField + LocalOrMPC<F>> ConstraintSynthesizer<F> for MySecretInputCircuit<F> {
fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
self.verify_constraints(cs.clone())?;
self.verify_commitment(cs.clone())?;
Ok(())
}
}
In addition to usual constraints, we also defines one here to calculate commitments.
Here we show the example of the former constraints:
impl<F: PrimeField + LocalOrMPC<F>> MySecretInputCircuit<F> {
fn verify_constraints(&self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
let x = FpVar::new_witness(cs.clone(), || {
self.x.ok_or(SynthesisError::AssignmentMissing)
})?;
let lower_bound = FpVar::new_input(cs.clone(), || {
self.lower_bound.ok_or(SynthesisError::AssignmentMissing)
})?;
let upper_bound = FpVar::new_input(cs.clone(), || {
self.upper_bound.ok_or(SynthesisError::AssignmentMissing)
})?;
x.enforce_cmp(&lower_bound, Ordering::Greater, true)?;
x.enforce_cmp(&upper_bound, Ordering::Less, false)?;
Ok(())
}
}
See this to learn more about how to specify constraints.
online mpc calculations are specified in circuits/circuit.rs
. Defaultly, MySimpleCircuit is used. Constraints is specified in same way as input_circuit.rs
.
Initialize werewolf game. The following command initializes the game with 3 players. Game files are generated in werewolf/
directory.
./run_werewolf.zsh init 3
Run the game. The following command runs the game in the night phase.
The command is written in Default zsh file, that player allocated fortune teller
get whether next player is werewolf or not and outputs the result to e.g. werewolf/0/divination_result.json
.
./run_werewolf.zsh night
When playing with n players, in the i-th (0-indexed) terminal, enter the following command:
cargo run --example werewolf-cli --release i ./data/n
For example, for a 4-players game, in the first terminal, you would enter:
cargo run --example werewolf-cli --release 0 ./data/4
In she
module, we implement somewhat homomorphic encryption. Concrete implementation is based on these papers.
- Fully Homomorphic Encryption from Ring-LWE and Security for Key Dependent Messages.
- Fully Homomorphic SIMD Operations .
- Multiparty Computation from Somewhat Homomorphic Encryption.
The additive secret sharing method is used in SPDZ, and the secret information
With respect to the input values of SPDZ, a participant's share of secret information
- Each participant has a share
$r_i$ of a random number$r$ . The value of$r$ is unknown to anyone at this point. - The participant who wants to create a share of secret information
$x$ recovers the value of$r$ and broadcasts$\varepsilon=x-r$ . - Each participant
$P_i$ determines its share$x_i$ of$x$ as$x_1=r_1+\varepsilon, x_i=r_i(i\neq 1)$ . In this case,$x=\sum x_i$ holds.
The share
Therefore, for each conditional secret input
- Secret input
-
$x$ : secret information -
$randomenesss$ : randomness for commitment.
-
- Public input
-
$h_x$ : commitment of secret value$x$ .
-
For these, the participant who has secret inputs creates a proof so that the following relation is satisfied.
where the 1st equation is the condition that
Requirement for
Result of benchmarking is shown in benchmark.md.