Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
piotr-roslaniec committed Jan 20, 2023
1 parent 17cdb5b commit 8cb52d8
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 6 deletions.
2 changes: 1 addition & 1 deletion ferveo/src/dkg/pv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ pub(crate) mod test_common {
ValidatorSet::new(
(0..4)
.map(|i| TendermintValidator {
power: i,
power: i, // TODO: Should set to 1 in order to force partitioning to give one share to each validator. Replace with 1 by reworking how partitioning works.
address: format!("validator_{}", i),
public_key: keypairs[i as usize].public(),
})
Expand Down
121 changes: 121 additions & 0 deletions ferveo/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod msg;
pub mod vss;

pub mod primitives;
use itertools::izip;
pub use primitives::*;

use ferveo_common::Rng;
Expand All @@ -30,3 +31,123 @@ use ark_ec::PairingEngine;
use ark_ff::PrimeField;

use measure_time::print_time;

pub fn share_combine_simple<E: PairingEngine>(
shares: &[E::Fqk],
lagrange: &[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()) {
// Exponentiation by alpha_i
let ss = c_i.pow(alpha_i.into_repr());
product_of_shares *= ss;
}

product_of_shares
}

#[cfg(test)]
mod test_dkg_full {
use super::*;

use crate::dkg::pv::test_common::*;
use ark_bls12_381::Bls12_381 as EllipticCurve;
use ark_ff::UniformRand;
use ferveo_common::{TendermintValidator, ValidatorSet};
use group_threshold_cryptography as tpke;

type E = ark_bls12_381::Bls12_381;

/// Test happy flow for a full DKG with simple threshold decryption variant
#[test]
fn test_dkg_simple_decryption_variant() {
//
// The following is copied from other tests
//

let rng = &mut ark_std::test_rng();
let dkg = setup_dealt_dkg();
let aggregate = aggregate(&dkg);
// check that a polynomial of the correct degree was created
assert_eq!(aggregate.coeffs.len(), 5);
// check that the correct number of shares were created
assert_eq!(aggregate.shares.len(), 4);
// check that the optimistic verify returns true
assert!(aggregate.verify_optimistic());
// check that the full verify returns true
assert!(aggregate.verify_full(&dkg, rng));
// check that the verification of aggregation passes
assert_eq!(
aggregate
.verify_aggregation(&dkg, rng)
.expect("Test failed"),
6
);

//
// Now, we start the actual test
//

// At this point, we have a DKG that has been dealt and aggregated
// We now want to test the decryption of a message

// First, we encrypt a message using a DKG public key

let msg: &[u8] = "abc".as_bytes();
let aad: &[u8] = "my-aad".as_bytes();
let public_key = dkg.final_key();
let ciphertext = tpke::encrypt::<_, E>(msg, aad, &public_key, rng);

// TODO: Update test utils so that we can easily get a validator keypair for each validator
let validator_keypairs = gen_keypairs();

// 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);

/*
TODO: This variant seems to be outdated/unused in simple threshold decryption variant
// Following section 4.4.8 of the paper, we need to compute the following:
let decryption_shares = validator_keypairs.iter().map(|validator| {
// TODO: Check the validity of (U, W)
// Compute the decryption share D_{i,j} = [dk_j^{-1}]*U_i
// We only have one U in this case
let u = ciphertext.commitment;
let dk_j = validator.decryption_key;
let dk_j_inv = dk_j.inverse().unwrap();
let d_ij = u.mul(dk_j_inv);
d_ij
});
*/
}
}
34 changes: 29 additions & 5 deletions ferveo/src/vss/pvss.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub struct PubliclyVerifiableParams<E: PairingEngine> {
/// 2/3 the total), this will be aggregated into a final key
#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)]
pub struct PubliclyVerifiableSS<E: PairingEngine, T = Unaggregated> {
/// Feldman commitment to the VSS polynomial, F = g^{\phi}
/// Used in Feldman commitment to the VSS polynomial, F = g^{\phi}
pub coeffs: Vec<E::G1Affine>,

/// The shares to be dealt to each validator
Expand All @@ -66,11 +66,13 @@ impl<E: PairingEngine, T> PubliclyVerifiableSS<E, T> {
dkg: &PubliclyVerifiableDkg<E>,
rng: &mut R,
) -> Result<Self> {
// Our random polynomial, \phi(x) = s + \sum_{i=1}^{t-1} a_i x^i
let mut phi = DensePolynomial::<E::Fr>::rand(
(dkg.params.total_weight - dkg.params.security_threshold) as usize,
rng,
);
phi.coeffs[0] = *s;
phi.coeffs[0] = *s; // setting the first coefficient to secret value
// 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 @@ -92,7 +94,10 @@ impl<E: PairingEngine, T> PubliclyVerifiableSS<E, T> {
));
}
//phi.zeroize(); // TODO zeroize?
// 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
let vss = Self {
coeffs,
shares,
Expand All @@ -106,10 +111,15 @@ impl<E: PairingEngine, T> PubliclyVerifiableSS<E, T> {
/// i.e. we optimistically do not check the commitment. This is deferred
/// until the aggregation step
pub fn verify_optimistic(&self) -> bool {
// We're only checking the proof of knowledge here, sigma ?= h^s
// "Does the first coefficient of the secret polynomial match the proof of knowledge?"
E::pairing(
self.coeffs[0].into_projective(),
E::G2Affine::prime_subgroup_generator(),
) == E::pairing(E::G1Affine::prime_subgroup_generator(), self.sigma)
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
)
}

/// Part of checking the validity of an aggregated PVSS transcript
Expand All @@ -127,8 +137,11 @@ impl<E: PairingEngine, T> PubliclyVerifiableSS<E, T> {
print_time!("commitment fft");
dkg.domain.fft_in_place(&mut commitment);

// Each validator checks that their share is correct
dkg.validators.iter().zip(self.shares.iter()).all(
|(validator, shares)| {
// ek is the public key of the validator
// TODO: Is that the ek = [dk]H key?
let ek = validator
.validator
.public_key
Expand All @@ -138,14 +151,19 @@ impl<E: PairingEngine, T> PubliclyVerifiableSS<E, T> {
let mut powers_of_alpha = alpha;
let mut y = E::G2Projective::zero();
let mut a = E::G1Projective::zero();
// Validator checks checks aggregated shares against commitment
for (y_i, a_i) in shares.iter().zip_eq(
commitment[validator.share_start..validator.share_end]
.iter(),
) {
// We iterate over shares (y_i) and commitment (a_i)
// TODO: Check #3 is missing
// See #3 in 4.2.3 section of https://eprint.iacr.org/2022/898.pdf
y += y_i.mul(powers_of_alpha.into_repr());
a += a_i.mul(powers_of_alpha.into_repr());
powers_of_alpha *= alpha;
}
// See #4 in 4.2.3 section of https://eprint.iacr.org/2022/898.pdf
// Y = \sum_i y_i \alpha^i
// A = \sum_i a_i \alpha^i
// e(G,Y) = e(A, ek)
Expand All @@ -168,6 +186,8 @@ impl<E: PairingEngine, T: Aggregate> PubliclyVerifiableSS<E, T> {
) -> Result<u32> {
print_time!("PVSS verify_aggregation");
self.verify_full(dkg, rng);
// Now, we verify that the aggregated PVSS transcript is a valid aggregation
// If it is, we return the total weights of the PVSS transcripts
let mut y = E::G1Projective::zero();
let mut weight = 0u32;
for (dealer, pvss) in dkg.vss.iter() {
Expand Down Expand Up @@ -200,6 +220,10 @@ pub fn aggregate<E: PairingEngine>(
.iter()
.map(|a| batch_to_projective(a))
.collect::<Vec<_>>();

// So now we're iterating over the PVSS instances, and adding their coefficients and shares, and their sigma
// sigma is the sum of all the sigma_i, which is the proof of knowledge of the secret polynomial
// Aggregating is just adding the corresponding values in pvss instances, so pvss = pvss + pvss_j
for (_, next) in pvss_iter {
sigma = sigma.add(next.sigma);
coeffs
Expand Down

0 comments on commit 8cb52d8

Please sign in to comment.