This repositry is zk-mpc.
The following is the main directory structure.
/circuits
- This module contains various circuits.
circuit.rs
- This file defines the circuit for MPC.
input_circuit.rs
- This file defines the input circuit for prove the correctness of secret inputs sharing.
/she
- This file defines the Somewhat Hmomorphic Encryption protocol. Concrete implementation is based on these papers.
input.rs
- This file defines the input struct used in the corresponding circuit.
bin_werewolf.rs
- This is the binary file for werewolf game.
main.rs
- This file is the main binary file. Mainly, used for preprocessing phase.
online.rs
- This file is the second binary file. Mainly, used for online phase.
preprocessing.rs
- This file defines the preprocessing module.
- MPC protocol requires preprocessing.
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
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
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