Skip to content

Commit

Permalink
incorrect length of decrypted shares after pvss combination
Browse files Browse the repository at this point in the history
  • Loading branch information
piotr-roslaniec committed Jan 20, 2023
1 parent 1b260cc commit efa6150
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 45 deletions.
12 changes: 10 additions & 2 deletions ferveo/src/dkg/pv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,10 +305,12 @@ pub(crate) mod test_common {
///
/// The correctness of this function is tested in the module [`test_dealing`]
pub fn setup_dealt_dkg() -> PubliclyVerifiableDkg<EllipticCurve> {
let n = 4;
let rng = &mut ark_std::test_rng();
// gather everyone's transcripts
let mut transcripts = vec![];
for i in 0..4 {
for i in 0..n {
// All of the dkg instances have the same validators
let mut dkg = setup_dkg(i);
transcripts.push(dkg.share(rng).expect("Test failed"));
}
Expand All @@ -317,11 +319,17 @@ pub(crate) mod test_common {
// iterate over transcripts from lowest weight to highest
for (sender, pvss) in transcripts.into_iter().rev().enumerate() {
dkg.apply_message(
dkg.validators[3 - sender].validator.clone(),
dkg.validators[n - 1 - sender].validator.clone(),
pvss,
)
.expect("Setup failed");
}
// At this point, the dkg should contain n transcripts, each containing n shares
// TODO: Remove this check
assert_eq!(dkg.vss.len(), n);
for i in 0..n {
assert_eq!(dkg.vss[&(i as u32)].shares.len(), n);
}
dkg
}
}
Expand Down
125 changes: 95 additions & 30 deletions ferveo/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#![allow(unused_imports)]

pub mod dkg;
pub mod msg;
pub mod vss;

pub mod primitives;
use itertools::izip;

use itertools::{izip, zip_eq};
pub use primitives::*;

use ferveo_common::Rng;
Expand Down Expand Up @@ -32,15 +34,33 @@ use ark_ff::PrimeField;

use measure_time::print_time;

pub fn prepare_combine_simple<E: PairingEngine>(
shares_x: &[E::Fr],
) -> Vec<E::Fr> {
// Calculate lagrange coefficients using optimized formula, see https://en.wikipedia.org/wiki/Lagrange_polynomial#Optimal_algorithm
let mut lagrange_coeffs = vec![];
for x_j in shares_x {
let mut prod = E::Fr::one();
for x_m in shares_x {
if x_j != x_m {
// In this formula x_i = 0, hence numerator is x_m
prod *= (*x_m) / (*x_m - *x_j);
}
}
lagrange_coeffs.push(prod);
}
lagrange_coeffs
}

pub fn share_combine_simple<E: PairingEngine>(
shares: &[E::Fqk],
lagrange: &[E::Fr],
shares: &Vec<E::Fqk>,
lagrange_coeffs: &Vec<E::Fr>,
// prepared_key_shares: &[E::G2Affine],
) -> E::Fqk {
let mut product_of_shares = E::Fqk::one();

// Sum of C_i^{L_i}
for (c_i, alpha_i) in izip!(shares.iter(), lagrange.iter()) {
// Sum of C_i^{L_i}z
for (c_i, alpha_i) in zip_eq(shares.iter(), lagrange_coeffs.iter()) {
// Exponentiation by alpha_i
let ss = c_i.pow(alpha_i.into_repr());
product_of_shares *= ss;
Expand All @@ -58,6 +78,7 @@ mod test_dkg_full {
use ark_ff::UniformRand;
use ferveo_common::{TendermintValidator, ValidatorSet};
use group_threshold_cryptography as tpke;
use itertools::{zip_eq, Itertools};

type E = ark_bls12_381::Bls12_381;

Expand Down Expand Up @@ -106,32 +127,76 @@ mod test_dkg_full {

// TODO: Check ciphertext validity, https://nikkolasg.github.io/ferveo/tpke.html#to-validate-ciphertext-for-ind-cca2-security

// Each validator computes a decryption share
let decryption_shares = validator_keypairs.iter().map(|keypair| {
// let decryption_shares = aggregate
let decryption_shares = aggregate
.shares[0]
.iter()
.map(|share| {
// TODO: In simple decryption variant, we only have one share per validator
// assert_eq!(z_i.len(), 1);
let z_i = share.mul(keypair.decryption_key);

// Validator decryption of private key shares, https://nikkolasg.github.io/ferveo/pvss.html#validator-decryption-of-private-key-shares
let u = ciphertext.commitment;
let c_i = E::pairing(u, z_i);
c_i
})
.collect::<Vec<_>>();

// TODO: In simple decryption variant, we only have one share per validator
// assert_eq!(decryption_shares.len(), 1);
// decryption_shares[0]
decryption_shares
});

//

// let s = share_combine_simple::<E>(&aggregate.shares, &aggregate.coeffs);
// Each validator attempts to aggregate and decrypt the secret shares
// let decryption_shares = validator_keypairs
validator_keypairs
.iter()
.enumerate()
// Assuming that the ordering of the validator keypairs is the same as the ordering of the validators in the validator set
// TODO: Check this assumption
.for_each(|(validator_i, keypair)| {
let decrypted_shares: Vec<Vec<ark_bls12_381::G2Projective>> =
shares_for_validator(validator_i, &dkg)
.iter()
// Each "share" the validator has is actually a vector of shares
// This because of domain partitioning - the amount of shares is the same as the validator's "power"
.map(|share| {
// Decrypt the share by decrypting each of the G2 elements within ShareEncryptions<E>
share
.iter()
.map(|s| s.mul(keypair.decryption_key))
.collect()
})
.collect();

let combined_shares = decrypted_shares.iter().fold(
vec![
ark_bls12_381::G2Projective::zero();
decrypted_shares[0].len()
],
|acc, share| {
zip_eq(acc, share).map(|(a, b)| a + b).collect()
},
);

let decryption_shares = combined_shares
.iter()
.map(|z_i| {
// Validator decryption of private key shares, https://nikkolasg.github.io/ferveo/pvss.html#validator-decryption-of-private-key-shares
let u = ciphertext.commitment;
let c_i = E::pairing(u, *z_i);
c_i
})
.collect::<Vec<_>>();

let shares_x = &dkg.domain.elements().collect::<Vec<_>>();
let lagrange_coeffs = prepare_combine_simple::<E>(&shares_x);

let s =
share_combine_simple::<E>(&decryption_shares, &lagrange_coeffs);

let plaintext =
tpke::checked_decrypt_with_shared_secret(&ciphertext, aad, &s);
assert_eq!(plaintext, msg);
});

// TODO: Perform decryption here!

// For every validator, we're collecting all the decryption shares from all of the PVSS transcripts
// .flatten()
// .collect();

// let shares_x = &dkg.domain.elements().collect::<Vec<_>>();
// let lagrange_coeffs = prepare_combine_simple::<E>(&shares_x);
//
// let s =
// share_combine_simple::<E>(&decryption_shares, &lagrange_coeffs);
//
// let plaintext =
// tpke::checked_decrypt_with_shared_secret(&ciphertext, aad, &s);
// assert_eq!(plaintext, msg);

/*
TODO: This variant seems to be outdated/unused in simple threshold decryption variant
Expand Down
65 changes: 60 additions & 5 deletions ferveo/src/vss/pvss.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,23 @@ use ark_ec::PairingEngine;
use ark_ff::UniformRand;
use ark_serialize::*;
use ferveo_common::PublicKey;
use itertools::Itertools;
use itertools::{zip_eq, Itertools};
use subproductdomain::fast_multiexp;

/// These are the blinded evaluations of weight shares of a single random polynomial
pub type ShareEncryptions<E> = Vec<<E as PairingEngine>::G2Affine>;

/// Marker struct for unaggregated PVSS transcripts
#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)]
pub struct Unaggregated;

/// Marker struct for aggregated PVSS transcripts
#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)]
pub struct Aggregated;

/// Trait gate used to add extra methods to aggregated PVSS transcripts
pub trait Aggregate {}

/// Apply trait gate to Aggregated marker struct
impl Aggregate for Aggregated {}

Expand Down Expand Up @@ -72,7 +75,7 @@ impl<E: PairingEngine, T> PubliclyVerifiableSS<E, T> {
rng,
);
phi.coeffs[0] = *s; // setting the first coefficient to secret value
// Evaluations of the polynomial over the domain
// Evaluations of the polynomial over the domain
let evals = phi.evaluate_over_domain_by_ref(dkg.domain);
// commitment to coeffs, F_i
let coeffs = fast_multiexp(&phi.coeffs, dkg.pvss_params.g);
Expand All @@ -97,7 +100,7 @@ impl<E: PairingEngine, T> PubliclyVerifiableSS<E, T> {
// TODO: Cross check proof of knowledge check with the whitepaper; this check proves that there is a relationship between the secret and the pvss transcript
// Sigma is a proof of knowledge of the secret, sigma = h^s
let sigma = E::G2Affine::prime_subgroup_generator().mul(*s).into(); //todo hash to curve
// So at this point, we have a commitment to the polynomial, a number of shares, and a proof of knowledge
// So at this point, we have a commitment to the polynomial, a number of shares, and a proof of knowledge
let vss = Self {
coeffs,
shares,
Expand All @@ -117,8 +120,8 @@ impl<E: PairingEngine, T> PubliclyVerifiableSS<E, T> {
self.coeffs[0].into_projective(), // F_0 = g^s
E::G2Affine::prime_subgroup_generator(), // h
) == E::pairing(
E::G1Affine::prime_subgroup_generator(), // g
self.sigma // h^s
E::G1Affine::prime_subgroup_generator(), // g
self.sigma, // h^s
)
}

Expand Down Expand Up @@ -252,6 +255,57 @@ pub fn aggregate<E: PairingEngine>(
}
}

// pub fn aggregate_for_decryption<E: PairingEngine>(
// dkg: &PubliclyVerifiableDkg<E>,
// ) -> ShareEncryptions<E> {
// let aggregate = dkg
// .vss
// .iter()
// .map(|(_, pvss)| {
// assert_eq!(dkg.validators.len(), pvss.shares.len());
//
// let shares = pvss
// .shares
// .iter()
// .map(|a| batch_to_projective(a))
// .collect::<Vec<_>>();
//
// // Combine PVSS transcripts into a share aggregate
// let mut share_iter = shares.iter();
// let first_share = share_iter.next().unwrap();
// share_iter
// .fold(first_share, |acc, share| {
// &zip_eq(acc, share)
// .map(|(a, b)| *a + *b)
// .collect::<Vec<_>>()
// })
// .iter()
// .map(|a| a.into_affine())
// .collect::<ShareEncryptions<E>>()
// })
// .collect::<Vec<ShareEncryptions<E>>>();
//
// E::G2Projective::batch_normalization_into_affine(&aggregate)
// }

/// Returns ShareEncryptions<E> from DKG PVSS transcripts for a selected validator
pub fn shares_for_validator<E: PairingEngine>(
validator: usize,
dkg: &PubliclyVerifiableDkg<E>,
) -> Vec<ShareEncryptions<E>> {
// DKG contains multiple PVSS transcripts, one for each dealer
dkg.vss
.iter()
.map(|(_, pvss)| {
// Each PVSS transcript contains multiple shares, one for each validator
assert_eq!(dkg.validators.len(), pvss.shares.len());
pvss.shares[validator].clone()
})
// Each validator has a share from each PVSS transcript
// One share is represented by ShareEncryptions<E>, which is a vector of G2 points
.collect::<Vec<ShareEncryptions<E>>>()
}

#[cfg(test)]
mod test_pvss {
use super::*;
Expand All @@ -260,6 +314,7 @@ mod test_pvss {
use ark_bls12_381::Bls12_381 as EllipticCurve;
use ark_ff::UniformRand;
use ferveo_common::{TendermintValidator, ValidatorSet};

type Fr = <EllipticCurve as PairingEngine>::Fr;
type G1 = <EllipticCurve as PairingEngine>::G1Affine;
type G2 = <EllipticCurve as PairingEngine>::G2Affine;
Expand Down
8 changes: 2 additions & 6 deletions tpke-wasm/benches/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,7 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion};
pub fn bench_encrypt_combine(c: &mut Criterion) {
use tpke_wasm::*;

fn bench_encrypt(
num_shares: usize,
threshold: usize) -> impl Fn() {
fn bench_encrypt(num_shares: usize, threshold: usize) -> impl Fn() {
let message = "my-secret-message".as_bytes().to_vec();
let aad = "my-aad".as_bytes().to_vec();
let setup = Setup::new(threshold, num_shares);
Expand All @@ -16,9 +14,7 @@ pub fn bench_encrypt_combine(c: &mut Criterion) {
}
}

fn bench_combine(
num_shares: usize,
threshold: usize) -> impl Fn() {
fn bench_combine(num_shares: usize, threshold: usize) -> impl Fn() {
let message = "my-secret-message".as_bytes().to_vec();
let aad = "my-aad".as_bytes().to_vec();
let setup = Setup::new(threshold, num_shares);
Expand Down
2 changes: 1 addition & 1 deletion tpke-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ impl Setup {

let mut rng = rand::thread_rng();
let (public_key, private_key, contexts) =
tpke::setup_fast::<E>(threshold, shares_num, &mut rng);
tpke::setup_fast::<E>(threshold, shares_num, &mut rng);
let private_contexts = contexts
.clone()
.into_iter()
Expand Down
1 change: 0 additions & 1 deletion tpke/src/decryption.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use crate::*;

use ark_ec::ProjectiveCurve;


#[derive(Debug, Clone)]
pub struct DecryptionShareFast<E: PairingEngine> {
pub decrypter_index: usize,
Expand Down

0 comments on commit efa6150

Please sign in to comment.