Skip to content

Commit

Permalink
Allow to transform multiple circuits at once
Browse files Browse the repository at this point in the history
  • Loading branch information
paberr committed Feb 5, 2024
1 parent e1beb66 commit 2386efe
Show file tree
Hide file tree
Showing 7 changed files with 166 additions and 73 deletions.
11 changes: 6 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion e2e/e2ephase1.sh
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ echo 1 | RUST_LOG=info cargo run --release --bin contribute --no-default-feature
echo 1 | RUST_LOG=info cargo run --release --bin contribute --no-default-features -- --unsafe-passphrase --exit-when-finished-contributing --keys-file $BASE_DIR/nimiq-verifier.keys --participation-mode verify --coordinator-url http://localhost:8080
echo 1 | RUST_LOG=info cargo run --release --bin control -- --unsafe-passphrase --keys-file $BASE_DIR/nimiq-verifier.keys --coordinator-url http://localhost:8080 apply-beacon --beacon-hash 0000000000000000000000000000000000000000000000000000000000000000 --expected-participant 2238a626c0cbd0c3357da185c438755a2426284abfb293c664f66ce237761a07
RUST_BACKTRACE=1 RUST_LOG=info cargo run --release --bin verify_transcript --no-default-features -- --beacon-hash 0000000000000000000000000000000000000000000000000000000000000000
RUST_LOG=info cargo run --release --bin intermediate_transform
RUST_LOG=info cargo run --release --bin intermediate_transform -- --setup-id 0 --circuit-filenames circuit_mnt4_753
RUST_LOG=info cargo run --release --bin intermediate_transform -- --setup-id 1 --circuit-filenames circuit_mnt6_753
mv circuit_mnt4_753_phase2_init setup0_phase2_init
mv circuit_mnt6_753_phase2_init setup1_phase2_init
1 change: 1 addition & 0 deletions e2e/e2ephase2.sh
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ echo 1 | RUST_LOG=info cargo run --release --bin contribute -- --unsafe-passphra
echo 1 | RUST_LOG=info cargo run --release --bin contribute -- --unsafe-passphrase --exit-when-finished-contributing --keys-file $BASE_DIR/nimiq-verifier.keys --participation-mode verify --coordinator-url http://localhost:8080
echo 1 | RUST_LOG=info cargo run --release --bin control -- -i new_challenge.query -I new_challenge.full --unsafe-passphrase --keys-file $BASE_DIR/nimiq-verifier.keys --circuit-filenames circuit_mnt4_753 --circuit-filenames circuit_mnt6_753 --coordinator-url http://localhost:8080 apply-beacon --beacon-hash 0000000000000000000000000000000000000000000000000000000000000000 --expected-participant 2238a626c0cbd0c3357da185c438755a2426284abfb293c664f66ce237761a07
RUST_LOG=info cargo run --release --bin verify_transcript -- --circuit-filenames circuit_mnt4_753 --circuit-filenames circuit_mnt6_753 --beacon-hash 0000000000000000000000000000000000000000000000000000000000000000 -i new_challenge.query -I new_challenge.full
RUST_LOG=info cargo run --release --bin get_keys
10 changes: 4 additions & 6 deletions src/bin/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,7 @@ pub struct ControlOpts {

pub struct Phase2Params {
pub chunk_size: usize,
pub phase1_powers: usize,
pub phase1_filename: String,
pub phase2_init_filename: String,
pub circuit_filename: String,
pub initial_query_filename: String,
pub initial_full_filename: String,
Expand All @@ -170,8 +169,8 @@ impl Phase2Opts {
for (i, setup) in ceremony.setups.iter().enumerate() {
setups.push(Phase2Params {
chunk_size: setup.parameters.chunk_size,
phase1_powers: setup.parameters.power,
phase1_filename: setup_filename!(PHASE2_INIT_FILENAME, setup.setup_id).to_string(),
phase2_init_filename: setup_filename!(PHASE2_INIT_FILENAME, setup.setup_id)
.to_string(),
circuit_filename: opts.circuit_filenames[i].to_string(),
initial_query_filename: setup_filename!(
opts.initial_query_filename
Expand Down Expand Up @@ -517,8 +516,7 @@ impl Control {
setup_filename!(NEW_CHALLENGE_HASH_FILENAME, setup.setup_id),
setup_filename!(NEW_CHALLENGE_LIST_FILENAME, setup.setup_id),
phase2_opts.setups[setup_index].chunk_size,
&phase2_opts.setups[setup_index].phase1_filename,
phase2_opts.setups[setup_index].phase1_powers,
&phase2_opts.setups[setup_index].phase2_init_filename,
&phase2_opts.setups[setup_index].circuit_filename,
);
phase2_cli::combine::<E>(
Expand Down
173 changes: 132 additions & 41 deletions src/bin/intermediate_transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,22 @@ use ark_mnt6_753::MNT6_753;
use ark_serialize::CanonicalDeserialize;
use gumdrop::Options;
use phase2::load_circuit::Matrices;
use setup_utils::{domain_size, CheckForCorrectness};
use snark_setup_operator::data_structs::Setup;
use snark_setup_operator::setup_filename;
use snark_setup_operator::transcript_data_structs::Transcript;
use snark_setup_operator::utils::{COMBINED_FILENAME, PHASE2_INIT_FILENAME};
use snark_setup_operator::utils::COMBINED_FILENAME;
use snark_setup_operator::{
error::VerifyTranscriptError,
utils::{create_full_parameters, remove_file_if_exists},
};
use std::collections::HashMap;
use std::ops::Neg;
use std::{fs::File, io::Read};
use std::{
fs::{copy, File},
io::Read,
};
use tracing::info;

/// If a circuit filename is given, the phase2 powers are estimated from the circuit itself.
/// Otherwise, the powers must be given by the additional argument.
Expand All @@ -27,16 +33,20 @@ pub struct IntermediateTransformOpts {
pub transcript_path: String,
#[options(help = "setup id", required)]
pub setup_id: usize,
#[options(help = "powers in phase2")]
pub phase2_powers: Option<usize>,
#[options(help = "circuit filename")]
pub circuit_filename: Option<String>,
#[options(help = "circuit size in phase2")]
pub phase2_size: Option<usize>,
#[options(help = "circuit filenames")]
pub circuit_filenames: Vec<String>,
#[options(help = "disable correctness checks for testing")]
pub disable_correctness_checks: bool,
}

pub struct IntermediateTransform {
pub transcript: Transcript,
pub setup_id: usize,
pub phase2_powers: usize,
pub phase2_sizes: Vec<usize>,
pub output_filenames: Vec<String>,
pub disable_correctness_checks: bool,
}

impl IntermediateTransform {
Expand All @@ -48,50 +58,62 @@ impl IntermediateTransform {
.expect("Should have read transcript file.");
let transcript: Transcript = serde_json::from_str::<Transcript>(&transcript)?;

let phase2_powers = if let Some(ref circuit_filename) = opts.circuit_filename {
let mut phase2_sizes = vec![];
let mut output_filenames = vec![];
if !opts.circuit_filenames.is_empty() {
let ceremony = transcript
.rounds
.iter()
.last()
.expect("Round not found in transcript");

let setup = &ceremony.setups[opts.setup_id];
match setup.parameters.curve_kind.as_str() {
"bw6" => Self::estimate_circuit_powers::<BW6_761>(circuit_filename),
"bls12_377" => Self::estimate_circuit_powers::<Bls12_377>(circuit_filename),
"mnt4_753" => Self::estimate_circuit_powers::<MNT4_753>(circuit_filename),
"mnt6_753" => Self::estimate_circuit_powers::<MNT6_753>(circuit_filename),
_ => {
return Err(VerifyTranscriptError::UnsupportedCurveKindError(
setup.parameters.curve_kind.clone(),
)
.into())
}
for circuit_filename in opts.circuit_filenames.iter() {
info!("Estimating powers for {}", circuit_filename);
let phase2_size = match setup.parameters.curve_kind.as_str() {
"bw6" => Self::estimate_phase2_size::<BW6_761>(&circuit_filename),
"bls12_377" => Self::estimate_phase2_size::<Bls12_377>(&circuit_filename),
"mnt4_753" => Self::estimate_phase2_size::<MNT4_753>(&circuit_filename),
"mnt6_753" => Self::estimate_phase2_size::<MNT6_753>(&circuit_filename),
_ => {
return Err(VerifyTranscriptError::UnsupportedCurveKindError(
setup.parameters.curve_kind.clone(),
)
.into())
}
};
info!("Circuit {} has {} powers", circuit_filename, phase2_size);
phase2_sizes.push(phase2_size);
output_filenames.push(format!("{}_phase2_init", circuit_filename));
}
} else {
opts.phase2_powers
.expect("Need to give either phase2_powers or circuit_filename")
};
phase2_sizes.push(
opts.phase2_size
.expect("Need to give either phase2_powers or circuit_filename"),
);
output_filenames.push(format!("setup{}_phase2_init", opts.setup_id));
}

Ok(Self {
transcript,
setup_id: opts.setup_id,
phase2_powers,
phase2_sizes,
output_filenames,
disable_correctness_checks: opts.disable_correctness_checks,
})
}

fn estimate_circuit_powers<P: Pairing>(circuit_filename: &str) -> usize {
fn estimate_phase2_size<P: Pairing>(circuit_filename: &str) -> usize {
let mut file = File::open(circuit_filename).unwrap();
let mut buffer = Vec::<u8>::new();
file.read_to_end(&mut buffer).unwrap();
let m = Matrices::<P>::deserialize_compressed(&*buffer).unwrap();

// num_constraints for the modified circuit includes the original num_instance_variables
std::cmp::max(
m.num_constraints,
m.num_witness_variables + m.num_instance_variables,
)
.next_power_of_two()
.trailing_zeros() as usize
}

fn run(&self) -> Result<()> {
Expand All @@ -103,32 +125,101 @@ impl IntermediateTransform {
.expect("Round not found in transcript");

let setup = &ceremony.setups[self.setup_id];
match setup.parameters.curve_kind.as_str() {
"bw6" => self.transform::<BW6_761>(setup),
"bls12_377" => self.transform::<Bls12_377>(setup),
"mnt4_753" => self.transform::<MNT4_753>(setup),
"mnt6_753" => self.transform::<MNT6_753>(setup),
_ => Err(VerifyTranscriptError::UnsupportedCurveKindError(
setup.parameters.curve_kind.clone(),
)
.into()),
}?;

let mut transformed = HashMap::new();
let mut first = true;
for (&phase2_size, output_filename) in
self.phase2_sizes.iter().zip(self.output_filenames.iter())
{
let domain = match setup.parameters.curve_kind.as_str() {
"bw6" => domain_size::<BW6_761>(phase2_size),
"bls12_377" => domain_size::<Bls12_377>(phase2_size),
"mnt4_753" => domain_size::<MNT4_753>(phase2_size),
"mnt6_753" => domain_size::<MNT6_753>(phase2_size),
_ => {
return Err(VerifyTranscriptError::UnsupportedCurveKindError(
setup.parameters.curve_kind.clone(),
)
.into())
}
};
info!(
"Creating intermediate transform with domain size {} for {}",
domain, output_filename
);
// If circuit with same domain size exists, copy transformation.
if let Some(existing_filename) = transformed.get(&domain) {
// Copy.
info!("Copying existing output.");
copy(existing_filename, output_filename).unwrap();
} else {
let disable_checks = self.disable_correctness_checks || !first;
match setup.parameters.curve_kind.as_str() {
"bw6" => self.transform::<BW6_761>(
setup,
phase2_size,
output_filename,
disable_checks,
),
"bls12_377" => self.transform::<Bls12_377>(
setup,
phase2_size,
output_filename,
disable_checks,
),
"mnt4_753" => self.transform::<MNT4_753>(
setup,
phase2_size,
output_filename,
disable_checks,
),
"mnt6_753" => self.transform::<MNT6_753>(
setup,
phase2_size,
output_filename,
disable_checks,
),
_ => Err(VerifyTranscriptError::UnsupportedCurveKindError(
setup.parameters.curve_kind.clone(),
)
.into()),
}?;
// As long as the phase2_size yields the same domain size, we ran reuse the result.
transformed.insert(domain, output_filename.to_string());
}
first = false;
}

Ok(())
}

fn transform<E: Pairing>(&self, setup: &Setup) -> Result<()>
fn transform<E: Pairing>(
&self,
setup: &Setup,
phase2_size: usize,
output_filename: &str,
disable_correctness_checks: bool,
) -> Result<()>
where
E::G1Affine: Neg<Output = E::G1Affine>,
{
info!(
"Setup {} has {} powers",
setup.setup_id, setup.parameters.power
);
let parameters = create_full_parameters::<E>(&setup.parameters)?;

remove_file_if_exists(setup_filename!(PHASE2_INIT_FILENAME, setup.setup_id))?;
phase1_cli::prepare_phase2(
setup_filename!(PHASE2_INIT_FILENAME, setup.setup_id),
remove_file_if_exists(output_filename)?;
phase2_cli::prepare_phase2(
output_filename,
setup_filename!(COMBINED_FILENAME, setup.setup_id),
self.phase2_powers,
phase2_size,
&parameters,
if disable_correctness_checks {
CheckForCorrectness::No
} else {
CheckForCorrectness::Full
},
)?;

Ok(())
Expand Down

0 comments on commit 2386efe

Please sign in to comment.