Skip to content
This repository has been archived by the owner on Nov 23, 2023. It is now read-only.

Commit

Permalink
feat(lib): threshold circuit integration (#361)
Browse files Browse the repository at this point in the history
  • Loading branch information
brech1 authored Oct 5, 2023
1 parent aefc9de commit 6baedea
Show file tree
Hide file tree
Showing 12 changed files with 743 additions and 255 deletions.
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

# Assets
/eigentrust-cli/assets/attestation_station.rs
/eigentrust-cli/assets/et-proving-key.bin
/eigentrust-cli/assets/et-public-inputs.bin
/eigentrust-cli/assets/et-proof.bin
/eigentrust-cli/assets/*-proving-key.bin
/eigentrust-cli/assets/*-public-inputs.bin
/eigentrust-cli/assets/*-proof.bin
/eigentrust-cli/assets/kzg-params-*.bin
158 changes: 125 additions & 33 deletions eigentrust-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
use clap::{Args, Parser, Subcommand};
use eigentrust::{
attestation::{AttestationRaw, SignedAttestationRaw},
circuit::ET_PARAMS_K,
circuit::{Circuit, ET_PARAMS_K, TH_PARAMS_K},
error::EigenError,
eth::deploy_as,
storage::{
Expand Down Expand Up @@ -53,6 +53,12 @@ pub enum Mode {
LocalScores,
/// Retrieves and saves all attestations and calculates the global scores.
Scores,
/// Generates a Threshold circuit proof for the selected participant.
ThProof(ThProofData),
/// Generates Threshold circuit proving key
ThProvingKey,
/// Verifies the stored Threshold circuit proof.
ThVerify,
/// Displays the current configuration.
Show,
/// Updates the configuration. Requires 'UpdateData'.
Expand Down Expand Up @@ -113,14 +119,22 @@ pub struct UpdateData {
node_url: Option<String>,
}

/// KZGParams subcommand inputs
/// KZGParams subcommand input.
#[derive(Args, Debug)]
pub struct KZGParamsData {
/// Polynomial degree.
#[clap(long = "k")]
k: Option<String>,
}

/// ThresholdProof subcommand input.
#[derive(Args, Debug)]
pub struct ThProofData {
/// Peer.
#[clap(long = "peer")]
peer: Option<String>,
}

/// Bandada API action.
pub enum Action {
Add,
Expand Down Expand Up @@ -298,34 +312,28 @@ pub async fn handle_deploy(config: ClientConfig) -> Result<(), EigenError> {
Ok(())
}

/// Handles proving key generation.
/// Handles eigentrust circuit proving key generation.
pub fn handle_et_pk() -> Result<(), EigenError> {
let et_kzg_params = EigenFile::KzgParams(ET_PARAMS_K).load()?;
let proving_key = Client::generate_et_pk(et_kzg_params)?;

EigenFile::ProvingKey.save(proving_key)
EigenFile::ProvingKey(Circuit::EigenTrust).save(proving_key)
}

/// Handles the eigentrust proof generation command.
pub async fn handle_et_proof(config: ClientConfig) -> Result<(), EigenError> {
let mnemonic = load_mnemonic();
let client = Client::new(config, mnemonic);
let attestations = load_or_fetch_attestations(client.get_config().clone()).await?;

let att_fp = get_file_path("attestations", FileType::Csv)?;

handle_attestations(client.get_config().clone()).await?;
let att_storage = CSVFileStorage::<AttestationRecord>::new(att_fp);
let attestations: Result<Vec<SignedAttestationRaw>, EigenError> =
att_storage.load()?.into_iter().map(|record| record.try_into()).collect();

let proving_key = EigenFile::ProvingKey.load()?;
let proving_key = EigenFile::ProvingKey(Circuit::EigenTrust).load()?;
let kzg_params = EigenFile::KzgParams(ET_PARAMS_K).load()?;

// Generate proof
let report = client.calculate_scores(attestations?, kzg_params, proving_key).await?;
let report = client.generate_et_proof(attestations, kzg_params, proving_key)?;

EigenFile::EtProof.save(report.proof)?;
EigenFile::ETPublicInputs.save(report.pub_inputs.to_bytes())?;
EigenFile::Proof(Circuit::EigenTrust).save(report.proof)?;
EigenFile::PublicInputs(Circuit::EigenTrust).save(report.pub_inputs.to_bytes())?;

Ok(())
}
Expand All @@ -337,12 +345,12 @@ pub async fn handle_et_verify(config: ClientConfig) -> Result<(), EigenError> {

// Load data
let kzg_params = EigenFile::KzgParams(ET_PARAMS_K).load()?;
let public_inputs = EigenFile::ETPublicInputs.load()?;
let proving_key = EigenFile::ProvingKey.load()?;
let proof = EigenFile::EtProof.load()?;
let public_inputs = EigenFile::PublicInputs(Circuit::EigenTrust).load()?;
let proving_key = EigenFile::ProvingKey(Circuit::EigenTrust).load()?;
let proof = EigenFile::Proof(Circuit::EigenTrust).load()?;

// Verify proof
client.verify(kzg_params, public_inputs, proving_key, proof).await?;
client.verify(kzg_params, public_inputs, proving_key, proof)?;

info!("EigenTrust proof has been verified.");
Ok(())
Expand All @@ -369,7 +377,6 @@ pub async fn handle_scores(
) -> Result<(), EigenError> {
let mnemonic = load_mnemonic();
let client = Client::new(config, mnemonic);

let att_fp = get_file_path("attestations", FileType::Csv)?;

// Get or Fetch attestations
Expand Down Expand Up @@ -402,23 +409,13 @@ pub async fn handle_scores(
},
};

let proving_key = EigenFile::ProvingKey.load()?;
let kzg_params = EigenFile::KzgParams(ET_PARAMS_K).load()?;

// Calculate scores
let score_records: Vec<ScoreRecord> = client
.calculate_scores(attestations, kzg_params, proving_key)
.await?
.scores
.into_iter()
.map(ScoreRecord::from_score)
.collect();

let scores_fp = get_file_path("scores", FileType::Csv)?;
let score_records: Vec<ScoreRecord> =
client.calculate_scores(attestations)?.into_iter().map(ScoreRecord::from_score).collect();

// Save scores
let scores_fp = get_file_path("scores", FileType::Csv)?;
let mut records_storage = CSVFileStorage::<ScoreRecord>::new(scores_fp);

records_storage.save(score_records)?;

info!(
Expand All @@ -429,6 +426,75 @@ pub async fn handle_scores(
Ok(())
}

/// Handles threshold circuit proving key generation.
pub async fn handle_th_pk(config: ClientConfig) -> Result<(), EigenError> {
let mnemonic = load_mnemonic();
let client = Client::new(config, mnemonic);
let attestations = load_or_fetch_attestations(client.get_config().clone()).await?;

// Load KZG params
let et_kzg_params = EigenFile::KzgParams(ET_PARAMS_K).load()?;
let th_kzg_params = EigenFile::KzgParams(TH_PARAMS_K).load()?;

let proving_key = client.generate_th_pk(attestations, et_kzg_params, th_kzg_params)?;

EigenFile::ProvingKey(Circuit::Threshold).save(proving_key)
}

/// Handles threshold circuit proof generation.
pub async fn handle_th_proof(config: ClientConfig, data: ThProofData) -> Result<(), EigenError> {
let mnemonic = load_mnemonic();
let client = Client::new(config.clone(), mnemonic);
let attestations = load_or_fetch_attestations(client.get_config().clone()).await?;

// Load KZG params and proving key
let et_kzg_params = EigenFile::KzgParams(ET_PARAMS_K).load()?;
let th_kzg_params = EigenFile::KzgParams(TH_PARAMS_K).load()?;
let proving_key = EigenFile::ProvingKey(Circuit::Threshold).load()?;

// Parse peer id
let peer_id = match data.peer {
Some(peer) => peer.parse::<u32>().map_err(|e| EigenError::ParsingError(e.to_string()))?,
None => {
return Err(EigenError::ValidationError(
"Missing parameter 'peer': participant address.".to_string(),
))
},
};

let report = client.generate_th_proof(
attestations,
et_kzg_params,
th_kzg_params,
proving_key,
config.band_th.parse().unwrap(),
peer_id,
)?;

EigenFile::Proof(Circuit::Threshold).save(report.proof)?;
EigenFile::PublicInputs(Circuit::Threshold).save(report.pub_inputs.to_bytes())?;

Ok(())
}

/// Handles the eigentrust proof verification command.
pub async fn handle_th_verify(config: ClientConfig) -> Result<(), EigenError> {
let mnemonic = load_mnemonic();
let client = Client::new(config, mnemonic);

// Load data
let kzg_params = EigenFile::KzgParams(TH_PARAMS_K).load()?;
let public_inputs = EigenFile::PublicInputs(Circuit::Threshold).load()?;
let proving_key = EigenFile::ProvingKey(Circuit::Threshold).load()?;
let proof = EigenFile::Proof(Circuit::Threshold).load()?;

// Verify proof
client.verify(kzg_params, public_inputs, proving_key, proof)?;

info!("Threshold proof has been verified.");
Ok(())
}

/// Handles the CLI project configuration update.
pub fn handle_update(config: &mut ClientConfig, data: UpdateData) -> Result<(), EigenError> {
if let Some(as_address) = data.as_address {
Expand Down Expand Up @@ -474,6 +540,32 @@ pub fn handle_update(config: &mut ClientConfig, data: UpdateData) -> Result<(),
json_storage.save(config.clone())
}

/// Tries to load attestations from local storage. If no attestations are found,
/// it fetches them from the AS contract.
pub async fn load_or_fetch_attestations(
config: ClientConfig,
) -> Result<Vec<SignedAttestationRaw>, EigenError> {
let att_file_path = get_file_path("attestations", FileType::Csv)?;
let att_storage = CSVFileStorage::<AttestationRecord>::new(att_file_path.clone());

match att_storage.load() {
Ok(local_records) => {
if !local_records.is_empty() {
return local_records.into_iter().map(|record| record.try_into()).collect();
}
debug!("No local attestations found. Fetching from AS contract.");
},
Err(_) => {
debug!("Error loading local attestations. Fetching from AS contract.");
},
}

let client = Client::new(config, load_mnemonic());
handle_attestations(client.get_config().clone()).await?;

att_storage.load()?.into_iter().map(|record| record.try_into()).collect()
}

#[cfg(test)]
mod tests {
use crate::cli::{AttestData, Cli};
Expand Down
25 changes: 13 additions & 12 deletions eigentrust-cli/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
use dotenv::{dotenv, var};
use eigentrust::{
circuit::Circuit,
error::EigenError,
storage::{BinFileStorage, JSONFileStorage, Storage},
ClientConfig,
Expand All @@ -15,12 +16,12 @@ use std::{env::current_dir, path::PathBuf};
const DEFAULT_MNEMONIC: &str = "test test test test test test test test test test test junk";
/// Library configuration file name.
pub const CONFIG_FILE: &str = "config";
/// EigenTrust generated proof file name.
pub const ET_PROOF_FILE: &str = "et-proof";
/// EigenTrust proving key file name.
pub const ET_PROVING_KEY_FILE: &str = "et-proving-key";
/// EigenTrust proof public inputs file name.
pub const ET_PUB_INP_FILE: &str = "et-public-inputs";
/// Proof file name.
pub const PROOF_FILE: &str = "proof";
/// Proving key file name.
pub const PROVING_KEY_FILE: &str = "proving-key";
/// Public inputs file name.
pub const PUB_INP_FILE: &str = "public-inputs";
/// KZG parameters file name.
pub const PARAMS_FILE: &str = "kzg-params";

Expand Down Expand Up @@ -48,9 +49,9 @@ impl FileType {
// Enum for different EigenTrust binary files
pub enum EigenFile {
KzgParams(u32),
ProvingKey,
EtProof,
ETPublicInputs,
ProvingKey(Circuit),
Proof(Circuit),
PublicInputs(Circuit),
}

impl EigenFile {
Expand All @@ -75,9 +76,9 @@ impl EigenFile {
fn filename(&self) -> String {
match self {
EigenFile::KzgParams(pol_degree) => format!("{}-{}", PARAMS_FILE, pol_degree),
EigenFile::ProvingKey => ET_PROVING_KEY_FILE.to_string(),
EigenFile::EtProof => ET_PROOF_FILE.to_string(),
EigenFile::ETPublicInputs => ET_PUB_INP_FILE.to_string(),
EigenFile::ProvingKey(circuit) => format!("{}-{}", circuit.as_str(), PROVING_KEY_FILE),
EigenFile::Proof(circuit) => format!("{}-{}", circuit.as_str(), PROOF_FILE),
EigenFile::PublicInputs(circuit) => format!("{}-{}", circuit.as_str(), PUB_INP_FILE),
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions eigentrust-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ async fn main() -> Result<(), EigenError> {
Mode::LocalScores => handle_scores(config, AttestationsOrigin::Local).await?,
Mode::Scores => handle_scores(config, AttestationsOrigin::Fetch).await?,
Mode::Show => info!("Client config:\n{:#?}", config),
Mode::ThProof(data) => handle_th_proof(config, data).await?,
Mode::ThProvingKey => handle_th_pk(config).await?,
Mode::ThVerify => handle_th_verify(config).await?,
Mode::Update(update_data) => handle_update(&mut config, update_data)?,
};

Expand Down
2 changes: 1 addition & 1 deletion eigentrust-zk/src/circuits/dynamic_sets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ where
unassigned_msg_hashes.push(msg_hashes_row);
unassigned_s_invs.push(s_inv_row);

let pk = pks[i].clone().unwrap();
let pk = pks[i].clone().unwrap_or(PublicKey::default());
let unassigned_pk = UnassignedPublicKey::new(pk);
unassigned_pks.push(unassigned_pk);
}
Expand Down
12 changes: 12 additions & 0 deletions eigentrust-zk/src/circuits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::{
sponge::StatefulSpongeChipset,
FullRoundChip, PartialRoundChip, PoseidonChipset,
},
verifier::aggregator::native::NativeAggregator,
};
use halo2::halo2curves::{
bn256::{Bn256, Fr as Scalar},
Expand Down Expand Up @@ -54,6 +55,8 @@ pub const NUM_DECIMAL_LIMBS: usize = 2;
pub const POWER_OF_TEN: usize = 72;
/// Default polynomial degree for KZG parameters for EigenTrust circuit.
pub const ET_PARAMS_K: u32 = 20;
/// Default polynomial degree for KZG parameters for Threshold circuit.
pub const TH_PARAMS_K: u32 = 21;

/// Rational score
pub type RationalScore = BigRational;
Expand Down Expand Up @@ -94,6 +97,15 @@ pub type Opinion4 = Opinion<
PoseidonNativeHasher,
PoseidonNativeSponge,
>;
/// Native Aggregator for set with 4 participants
pub type NativeAggregator4 = NativeAggregator<
Bn256,
NUM_NEIGHBOURS,
NUM_BITS,
Bn256_4_68,
PoseidonNativeSponge,
Bn254Params,
>;

/// Native EigenTrust set with 4 participants
pub type NativeEigenTrust4 = NativeEigenTrustSet<
Expand Down
Loading

0 comments on commit 6baedea

Please sign in to comment.