Add aggregation and e2e test

This commit is contained in:
aniampio
2022-06-23 14:49:01 +01:00
committed by durch
parent 40af8ebf47
commit db69158b4b
11 changed files with 418 additions and 65 deletions
Generated
-1
View File
@@ -1006,7 +1006,6 @@ dependencies = [
[[package]]
name = "bls12_381"
version = "0.6.0"
source = "git+https://github.com/jstuczyn/bls12_381?branch=gt-serialisation#10fb6f700bfda17c8475af3bfd31e3fec15f2278"
dependencies = [
"digest 0.9.0",
<<<<<<< HEAD
@@ -7,7 +7,8 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch = "gt-serialisation", default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] }
#bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch = "gt-serialisation", default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] }
bls12_381 = { path = "/Users/ania/Documents/Git/andrew_bls12_381", default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] }
itertools = "0.10"
digest = "0.9"
rand = "0.8"
@@ -25,6 +25,9 @@ pub enum DivisibleEcashError {
#[error("Spend Verification related error: {0}")]
Spend(String),
#[error("Identify Verification related error: {0}")]
Identify(String),
#[error("Tried to deserialize {object} with bytes of invalid length. Expected {actual} < {} or {modulus_target} % {modulus} == 0")]
DeserializationInvalidLength {
actual: usize,
@@ -15,8 +15,8 @@ pub struct SpendInstance {
pub varphi: VarPhi,
pub rr: Scalar,
pub rr_prime: G1Projective,
pub ss: G1Projective,
pub tt: G2Projective,
pub ss_prime: G1Projective,
pub tt_prime: G2Projective,
pub varsig_prime1: G1Projective,
pub theta_prime1: G1Projective,
pub pg_eq1: Gt,
@@ -43,8 +43,8 @@ impl SpendInstance {
bytes.extend_from_slice(self.varphi.to_bytes().as_ref());
bytes.extend_from_slice(self.rr.to_bytes().as_ref());
bytes.extend_from_slice(self.rr_prime.to_bytes().as_ref());
bytes.extend_from_slice(self.ss.to_bytes().as_ref());
bytes.extend_from_slice(self.tt.to_bytes().as_ref());
bytes.extend_from_slice(self.ss_prime.to_bytes().as_ref());
bytes.extend_from_slice(self.tt_prime.to_bytes().as_ref());
bytes.extend_from_slice(self.varsig_prime1.to_bytes().as_ref());
bytes.extend_from_slice(self.theta_prime1.to_bytes().as_ref());
bytes.extend_from_slice(self.pg_eq1.to_compressed().as_ref());
@@ -283,7 +283,7 @@ impl SpendProof {
mod tests {
use std::ops::Neg;
use bls12_381::{G2Projective, Gt, pairing};
use bls12_381::{G2Projective, pairing};
use group::Curve;
use rand::thread_rng;
@@ -392,41 +392,6 @@ mod tests {
let pg_eq3 = pg_rrprime_yy + pg_ssprime_gen2 + pg_varsigpr2_ww1 + pg_thetapr2_ww2 - pg_gen1_zz;
let pg_eq4 = pg_rr_tt - pg_gen1_gen2;
// assert eq 15
// let L1 = pg_rrprime_yy - pg_psi0_yy * r_rr + pg_ssprime_gen2 - pg_psi0_gen2 * r_ss + pg_varsigpr2_ww1 - pg_psi0_ww1 * r_varsig2 + pg_thetapr2_ww2 - pg_psi0_ww2 * r_theta2 - pg_gen1_zz;
// assert_eq!(L1, Gt::identity());
// // assert equation 8
// assert_eq!(
// pairing(&params_u.get_ith_sps_sign(l as usize + vv as usize - 1).rr.to_affine(), &yy.to_affine())
// + pairing(&params_u.get_ith_sps_sign(l as usize + vv as usize - 1).ss.to_affine(), grp.gen2())
// + pairing(&params_u.get_ith_sigma(l as usize + vv as usize - 1).to_affine(), &params_u.get_sps_pk().get_ith_ww(0).to_affine())
// + pairing(&params_u.get_ith_theta(l as usize + vv as usize - 1).to_affine(), &params_u.get_sps_pk().get_ith_ww(1).to_affine())
// - pairing(grp.gen1(), &params_u.get_sps_pk().get_zz().to_affine()),
// Gt::identity()
// );
// let's do step by step checks:
// 1
// assert_eq!(pairing(&params_u.get_ith_sps_sign(l as usize + vv as usize - 1).rr.to_affine(), &yy.to_affine()),
// pg_rrprime_yy - pg_psi0_yy * r_rr
// );
// 2
// assert_eq!(pairing(&params_u.get_ith_sps_sign(l as usize + vv as usize - 1).ss.to_affine(), grp.gen2()),
// pg_ssprime_gen2 - pg_psi0_gen2 * r_ss
// );
// 3
// assert_eq!(pairing(&params_u.get_ith_sigma(l as usize + vv as usize - 1).to_affine(), &params_u.get_sps_pk().get_ith_ww(0).to_affine()),
// pg_varsigpr2_ww1 - pg_psi0_ww1 * r_varsig2
// );
// 4
// assert_eq!(pairing(&params_u.get_ith_theta(l as usize + vv as usize - 1).to_affine(), &params_u.get_sps_pk().get_ith_ww(1).to_affine()),
// pg_thetapr2_ww2 - pg_psi0_ww2 * r_theta2
// );
// 5
// assert_eq!(pairing(grp.gen1(), &params_u.get_sps_pk().get_zz().to_affine()),
// pg_gen1_zz);
let instance = SpendInstance {
kappa,
@@ -434,8 +399,8 @@ mod tests {
varphi,
rr,
rr_prime,
ss: ss_prime,
tt: tt_prime,
ss_prime: ss_prime,
tt_prime: tt_prime,
varsig_prime1,
theta_prime1,
pg_eq1,
@@ -2,12 +2,13 @@ use core::iter::Sum;
use core::ops::Mul;
use std::cell::Cell;
use bls12_381::{G2Prepared, G2Projective, Scalar};
use bls12_381::{G2Prepared, G2Projective, pairing, Scalar};
use group::Curve;
use itertools::Itertools;
use crate::Attribute;
use crate::error::{DivisibleEcashError, Result};
use crate::scheme::{PartialWallet, Wallet};
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
use crate::scheme::setup::GroupParameters;
use crate::utils::{
@@ -140,4 +141,27 @@ pub fn aggregate_signatures(
Ok(signature)
}
pub fn aggregate_wallets(
grp: &GroupParameters,
verification_key: &VerificationKeyAuth,
sk_user: &SecretKeyUser,
wallets: &[PartialWallet],
) -> Result<Wallet> {
let signature_shares: Vec<SignatureShare> = wallets
.iter()
.enumerate()
.map(|(idx, wallet)| SignatureShare::new(*wallet.signature(), (idx + 1) as u64))
.collect();
let v = wallets.get(0).unwrap().v;
let attributes = vec![sk_user.sk, v];
let aggregated_signature =
aggregate_signature_shares(&grp, &verification_key, &attributes, &signature_shares)?;
Ok(Wallet {
sig: aggregated_signature,
v,
l: Cell::new(1),
})
}
@@ -0,0 +1,113 @@
use std::collections::HashMap;
use std::ops::Neg;
use bls12_381::{Gt, pairing};
use group::Curve;
use crate::error::{DivisibleEcashError, Result};
use crate::scheme::{PayInfo, Payment};
use crate::scheme::identification::IdentifyResult::DoubleSpendingPublicKeys;
use crate::scheme::keygen::PublicKeyUser;
use crate::scheme::setup::Parameters;
pub enum IdentifyResult {
NoCommonSerialNumbers,
DuplicatePayInfo(PayInfo),
DoubleSpendingPublicKeys(Vec<PublicKeyUser>),
Whatever,
}
// how do we get the list of all pkU ?
pub fn identify(
params: &Parameters,
public_keys_u: &[PublicKeyUser],
payment1: Payment,
payment2: Payment,
payinfo1: PayInfo,
payinfo2: PayInfo) -> Result<IdentifyResult> {
let params_a = params.get_params_a();
// compute the serial numbers for k1 in [0, V1-1]
let mut serial_numbers = HashMap::new();
for k1 in 0..payment1.vv {
let sn = pairing(&payment1.phi.0.to_affine(), &params_a.get_ith_delta(k1 as usize).to_affine())
+ pairing(&payment1.phi.1.to_affine(), &params_a.get_ith_eta(k1 as usize).to_affine());
serial_numbers.insert(sn, k1);
}
// compute the serial numbers fo k2 in [0, V2-1]
let mut duplicate_serial_numbers: Vec<(Gt, u64, u64)> = Default::default();
for k2 in 0..payment2.vv {
let sn = pairing(&payment2.phi.0.to_affine(), &params_a.get_ith_delta(k2 as usize).to_affine())
+ pairing(&payment2.phi.1.to_affine(), &params_a.get_ith_eta(k2 as usize).to_affine());
if !serial_numbers.contains_key(&sn) {
serial_numbers.insert(sn, k2);
} else {
let k1 = *serial_numbers.get(&sn).unwrap() as u64;
duplicate_serial_numbers.push((sn, k1, k2));
}
}
if duplicate_serial_numbers.is_empty() {
Ok(IdentifyResult::NoCommonSerialNumbers)
} else {
if payinfo1.info == payinfo2.info {
Ok(IdentifyResult::DuplicatePayInfo(payinfo1))
} else {
let mut identified_pk_u: Vec<PublicKeyUser> = Default::default();
for elem in duplicate_serial_numbers.iter() {
let k1 = elem.1;
let k2 = elem.2;
let delta_k1 = params_a.get_ith_delta(k1 as usize);
let delta_k2 = params_a.get_ith_delta(k2 as usize);
let tt1 = pairing(&payment1.varphi.1.to_affine(), &delta_k1.to_affine())
+ pairing(&payment1.varphi.0.to_affine(), &params_a.get_ith_eta(k1 as usize).to_affine());
let tt2 = pairing(&payment2.varphi.1.to_affine(), &delta_k2.to_affine())
+ pairing(&payment2.varphi.0.to_affine(), &params_a.get_ith_eta(k2 as usize).to_affine());
for pk_u in public_keys_u.iter() {
let pg_pku_deltas = pairing(&pk_u.pk.to_affine(), &(delta_k1 * payment1.rr.neg() + delta_k2 * payment2.rr.neg()).to_affine());
if tt1 + tt2.neg() == pg_pku_deltas {
identified_pk_u.push(pk_u.clone());
}
}
}
if !identified_pk_u.is_empty() {
Ok(DoubleSpendingPublicKeys(identified_pk_u.clone()))
} else {
return Err(DivisibleEcashError::Identify(
"A duplicate serial number was detected, the payinfo1 and payinfo2 are different, but we failed to identify the double-spending public key".to_string(),
));
}
}
}
}
#[cfg(test)]
mod tests {
use rand::thread_rng;
use crate::scheme::keygen::PublicKeyUser;
use crate::scheme::setup::{GroupParameters, Parameters};
use crate::utils::hash_g1;
#[test]
fn no_matching_serial_numbers() {}
#[test]
fn matching_payinfo() {}
#[test]
fn identified_duplicate_serial_number_and_non_matching_payinfo() {
let rng = thread_rng();
let grp = GroupParameters::new().unwrap();
let params = Parameters::new(grp.clone());
let params_u = params.get_params_u();
let params_a = params.get_params_a();
let pk_u1 = PublicKeyUser { pk: hash_g1("PublicKey1") };
let pk_u2 = PublicKeyUser { pk: hash_g1("PublicKey1") };
let pk_u3 = PublicKeyUser { pk: hash_g1("PublicKey1") };
}
}
@@ -1,4 +1,5 @@
use std::cell::Cell;
use std::convert::{TryFrom, TryInto};
use std::ops::Neg;
use bls12_381::{G1Projective, G2Prepared, G2Projective, pairing, Scalar};
@@ -10,7 +11,7 @@ use crate::error::{DivisibleEcashError, Result};
use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness};
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
use crate::scheme::setup::{GroupParameters, Parameters};
use crate::utils::{check_bilinear_pairing, hash_to_scalar, Signature, SignerIndex};
use crate::utils::{check_bilinear_pairing, hash_to_scalar, Signature, SignerIndex, try_deserialize_g1_projective};
pub mod aggregation;
pub mod identify;
@@ -18,6 +19,7 @@ pub mod keygen;
pub mod setup;
pub mod structure_preserving_signature;
pub mod withdrawal;
pub mod identification;
pub fn compute_kappa(
params: &GroupParameters,
@@ -34,7 +36,7 @@ pub fn compute_kappa(
.sum::<G2Projective>()
}
#[derive(Debug, Clone, Copy)]
#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub struct Phi(pub(crate) G1Projective, pub(crate) G1Projective);
impl Phi {
@@ -44,9 +46,35 @@ impl Phi {
bytes.extend_from_slice(self.1.to_bytes().as_ref());
bytes
}
pub(crate) fn from_bytes(bytes: &[u8]) -> Result<Self> {
if bytes.len() < 48 * 2 || (bytes.len()) % 48 != 0 {
return Err(DivisibleEcashError::DeserializationInvalidLength {
actual: bytes.len(),
modulus_target: bytes.len(),
target: 48 * 2,
modulus: 48,
object: "phi".to_string(),
});
}
let elem_0_bytes = bytes[0..48].try_into().unwrap();
let elem_0 = try_deserialize_g1_projective(
elem_0_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize element 0 of Phi".to_string()),
)?;
let elem_1_bytes = bytes[48..96].try_into().unwrap();
let elem_1 = try_deserialize_g1_projective(
elem_1_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize element 1 of Phi".to_string()),
)?;
Ok(Phi(elem_0, elem_1))
}
}
#[derive(Debug, Clone, Copy)]
#[derive(Eq, PartialEq, Debug, Clone, Copy)]
pub struct VarPhi(pub(crate) G1Projective, pub(crate) G1Projective);
impl VarPhi {
@@ -56,6 +84,32 @@ impl VarPhi {
bytes.extend_from_slice(self.1.to_bytes().as_ref());
bytes
}
pub(crate) fn from_bytes(bytes: &[u8]) -> Result<Self> {
if bytes.len() < 48 * 2 || (bytes.len()) % 48 != 0 {
return Err(DivisibleEcashError::DeserializationInvalidLength {
actual: bytes.len(),
modulus_target: bytes.len(),
target: 48 * 2,
modulus: 48,
object: "varphi".to_string(),
});
}
let elem_0_bytes = bytes[0..48].try_into().unwrap();
let elem_0 = try_deserialize_g1_projective(
elem_0_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize element 0 of VarPhi".to_string()),
)?;
let elem_1_bytes = bytes[48..96].try_into().unwrap();
let elem_1 = try_deserialize_g1_projective(
elem_1_bytes,
DivisibleEcashError::Deserialization("Failed to deserialize element 1 of VarPhi".to_string()),
)?;
Ok(VarPhi(elem_0, elem_1))
}
}
pub struct PayInfo {
@@ -68,6 +122,13 @@ pub struct Payment {
sig: Signature,
phi: Phi,
varphi: VarPhi,
varsig_prime1: G1Projective,
varsig_prime2: G1Projective,
theta_prime1: G1Projective,
theta_prime2: G1Projective,
rr_prime: G1Projective,
ss_prime: G1Projective,
tt_prime: G2Projective,
rr: Scalar,
zk_proof: SpendProof,
vv: u64,
@@ -79,6 +140,18 @@ pub struct PartialWallet {
idx: Option<SignerIndex>,
}
impl PartialWallet {
pub fn signature(&self) -> &Signature {
&self.sig
}
pub fn v(&self) -> Scalar {
self.v
}
pub fn index(&self) -> Option<SignerIndex> {
self.idx
}
}
pub struct Wallet {
sig: Signature,
v: Scalar,
@@ -137,11 +210,12 @@ impl Wallet {
let r1 = grp.random_scalar();
let r2 = grp.random_scalar();
let phi = Phi(grp.gen1() * r1, params_u.get_ith_sigma(self.l.get() as usize) * self.v + params_u.get_ith_eta(vv as usize) * r1);
let phi = Phi(grp.gen1() * r1, params_u.get_ith_sigma(self.l() as usize) * self.v + params_u.get_ith_eta(vv as usize) * r1);
// compute hash of the payment info
let rr = hash_to_scalar(pay_info.info);
let varphi = VarPhi(grp.gen1() * r2, (grp.gen1() * rr) * sk_user.sk + params_u.get_ith_theta(self.l.get() as usize) * self.v + params_u.get_ith_eta(vv as usize) * r2);
let varphi = VarPhi(grp.gen1() * r2, (grp.gen1() * rr) * sk_user.sk + params_u.get_ith_theta(self.l() as usize) * self.v + params_u.get_ith_eta(vv as usize) * r2);
// random value used to compute blinded bases
let r_varsig1 = grp.random_scalar();
@@ -158,10 +232,12 @@ impl Wallet {
let varsig_prime1 = params_u.get_ith_sigma(self.l() as usize) + (psi_g1 * r_varsig1);
let theta_prime1 = params_u.get_ith_theta(self.l() as usize) + (psi_g1 * r_theta1);
let varsig_prime2 = params_u.get_ith_sigma(self.l() as usize + vv as usize - 1) + (psi_g1 * r_varsig2);
let theta_prime2 = params_u.get_ith_sigma(self.l() as usize + vv as usize - 1) + (psi_g1 * r_theta2);
let rr_prime = params_u.get_ith_sps_sign(self.l() as usize + vv as usize - 1).rr + (psi_g1 * r_rr);
let ss_prime = params_u.get_ith_sps_sign(self.l() as usize + vv as usize - 1).ss + (psi_g1 * r_ss);
let tt_prime = params_u.get_ith_sps_sign(self.l() as usize + vv as usize - 1).tt + (psi_g2 * r_tt);
let theta_prime2 = params_u.get_ith_theta(self.l() as usize + vv as usize - 1) + (psi_g1 * r_theta2);
let tau_l_vv = params_u.get_ith_sps_sign(self.l() as usize + vv as usize - 1);
let rr_prime = tau_l_vv.rr + (psi_g1 * r_rr);
let ss_prime = tau_l_vv.ss + (psi_g1 * r_ss);
let tt_prime = tau_l_vv.tt + (psi_g2 * r_tt);
let rho1 = self.v.neg() * r_varsig1;
let rho2 = self.v.neg() * r_theta1;
@@ -181,7 +257,7 @@ impl Wallet {
let ww2 = params_u.get_sps_pk().get_ith_ww(1);
let pg_varsigpr2_ww1 = pairing(&varsig_prime2.to_affine(), &ww1.to_affine());
let pg_psi0_ww1 = pairing(&psi_g1.to_affine(), &ww1.to_affine());
let pg_thetapr2_ww2 = pairing(&theta_prime1.to_affine(), &ww2.to_affine());
let pg_thetapr2_ww2 = pairing(&theta_prime2.to_affine(), &ww2.to_affine());
let pg_psi0_ww2 = pairing(&psi_g1.to_affine(), &ww2.to_affine());
let pg_gen1_zz = pairing(grp.gen1(), &params_u.get_sps_pk().get_zz().to_affine());
let pg_rr_tt = pairing(&rr_prime.to_affine(), &tt_prime.to_affine());
@@ -201,8 +277,8 @@ impl Wallet {
varphi,
rr,
rr_prime,
ss: ss_prime,
tt: tt_prime,
ss_prime,
tt_prime,
varsig_prime1,
theta_prime1,
pg_eq1,
@@ -248,12 +324,19 @@ impl Wallet {
sig: signature_prime,
phi,
varphi,
varsig_prime1,
varsig_prime2,
theta_prime1,
theta_prime2,
rr_prime,
ss_prime,
tt_prime,
rr,
zk_proof,
vv,
};
self.l.set(self.l.get() + vv);
self.l.set(self.l() + vv);
Ok((pay, self))
}
}
@@ -270,6 +353,8 @@ impl Payment {
));
}
let grp = params.get_grp();
let params_a = params.get_params_a();
let params_u = params.get_params_u();
if !check_bilinear_pairing(
&self.sig.0.to_affine(),
@@ -297,8 +382,114 @@ impl Payment {
//TODO: verify whether payinfo contains merchent's identifier
// TODO: Add zk proof verification
let psi_g1 = params_u.get_psi_g1();
let psi_g2 = params_u.get_psi_g2();
let pg_varsigpr1_delta = pairing(&self.varsig_prime1.to_affine(), &params_a.get_ith_delta((self.vv - 1) as usize).to_affine());
let pg_psi0_delta = pairing(&psi_g1.to_affine(), &params_a.get_ith_delta((self.vv - 1) as usize).to_affine());
let pg_varsigpr2_gen2 = pairing(&self.varsig_prime2.to_affine(), grp.gen2());
let pg_psi0_gen2 = pairing(&psi_g1.to_affine(), grp.gen2());
let pg_thetapr1_delta = pairing(&self.theta_prime1.to_affine(), &params_a.get_ith_delta((self.vv - 1) as usize).to_affine());
let pg_thetapr2_gen2 = pairing(&self.theta_prime2.to_affine(), grp.gen2());
let yy = params_u.get_sps_pk().get_yy();
let pg_rrprime_yy = pairing(&self.rr_prime.to_affine(), &yy.to_affine());
let pg_psi0_yy = pairing(&psi_g1.to_affine(), &yy.to_affine());
let pg_ssprime_gen2 = pairing(&self.ss_prime.to_affine(), grp.gen2());
let ww1 = params_u.get_sps_pk().get_ith_ww(0);
let ww2 = params_u.get_sps_pk().get_ith_ww(1);
let pg_varsigpr2_ww1 = pairing(&self.varsig_prime2.to_affine(), &ww1.to_affine());
let pg_psi0_ww1 = pairing(&psi_g1.to_affine(), &ww1.to_affine());
let pg_thetapr2_ww2 = pairing(&self.theta_prime2.to_affine(), &ww2.to_affine());
let pg_psi0_ww2 = pairing(&psi_g1.to_affine(), &ww2.to_affine());
let pg_gen1_zz = pairing(grp.gen1(), &params_u.get_sps_pk().get_zz().to_affine());
let pg_rr_tt = pairing(&self.rr_prime.to_affine(), &self.tt_prime.to_affine());
let pg_rr_psi1 = pairing(&self.rr_prime.to_affine(), &psi_g2.to_affine());
let pg_psi0_tt = pairing(&psi_g1.to_affine(), &self.tt_prime.to_affine());
let pg_psi0_psi1 = pairing(&psi_g1.to_affine(), &psi_g2.to_affine());
let pg_gen1_gen2 = pairing(grp.gen1(), grp.gen2());
Ok(true)
let pg_eq1 = pg_varsigpr1_delta - pg_varsigpr2_gen2;
let pg_eq2 = pg_thetapr1_delta - pg_thetapr2_gen2;
let pg_eq3 = pg_rrprime_yy + pg_ssprime_gen2 + pg_varsigpr2_ww1 + pg_thetapr2_ww2 + pg_gen1_zz.neg();
let pg_eq4 = pg_rr_tt - pg_gen1_gen2;
let instance = SpendInstance {
kappa: self.kappa,
phi: self.phi,
varphi: self.varphi,
rr: self.rr,
rr_prime: self.rr_prime,
ss_prime: self.ss_prime,
tt_prime: self.tt_prime,
varsig_prime1: self.varsig_prime1,
theta_prime1: self.theta_prime1,
pg_eq1,
pg_eq2,
pg_eq3,
pg_eq4,
psi_g1: *psi_g1,
psi_g2: *psi_g2,
pg_psi0_delta,
pg_psi0_gen2,
pg_psi0_yy,
pg_psi0_ww1,
pg_psi0_ww2,
pg_rr_psi1,
pg_psi0_tt,
pg_psi0_psi1,
};
Ok(self.zk_proof.verify(&params, &instance, &verification_key, self.vv))
}
}
#[cfg(test)]
mod tests {
use std::convert::TryFrom;
use rand::thread_rng;
use crate::scheme::{PayInfo, Phi, VarPhi, Wallet};
use crate::scheme::aggregation::aggregate_verification_keys;
use crate::scheme::keygen::{PublicKeyUser, ttp_keygen_authorities, VerificationKeyAuth};
use crate::scheme::setup::{GroupParameters, Parameters};
use crate::utils::hash_g1;
#[test]
fn phi_to_and_from_bytes() {
let phi = Phi(hash_g1("Element 0 of Phi"), hash_g1("Element 1 of Phi"));
let phi_bytes = phi.to_bytes();
let phi_from_bytes = Phi::from_bytes(&phi_bytes).unwrap();
assert_eq!(phi, phi_from_bytes);
}
#[test]
fn varphi_to_and_from_bytes() {
let varphi = VarPhi(hash_g1("Element 0 of VarPhi"), hash_g1("Element 1 of VarPhi"));
let varphi_bytes = varphi.to_bytes();
let varphi_from_bytes = VarPhi::from_bytes(&varphi_bytes).unwrap();
assert_eq!(varphi, varphi_from_bytes);
}
#[test]
fn spend_verification_is_correct() {
let rng = thread_rng();
let grp = GroupParameters::new().unwrap();
let params = Parameters::new(grp.clone());
let params_u = params.get_params_u();
let params_a = params.get_params_a();
let sk = grp.random_scalar();
let pk_user = PublicKeyUser {
pk: grp.gen1() * sk,
};
let authorities_keypairs = ttp_keygen_authorities(&params, 2, 3).unwrap();
let verification_keys_auth: Vec<VerificationKeyAuth> = authorities_keypairs
.iter()
.map(|keypair| keypair.verification_key())
.collect();
let verification_key =
aggregate_verification_keys(&verification_keys_auth, Some(&[1, 2, 3])).unwrap();
}
}
@@ -1,7 +1,7 @@
use std::convert::TryFrom;
use std::net::ToSocketAddrs;
use bls12_381::{G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, pairing, Scalar};
use bls12_381::{G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, Scalar};
use ff::Field;
use group::Curve;
use rand::thread_rng;
@@ -1,11 +1,9 @@
use std::convert::TryFrom;
use std::fmt::Debug;
use std::ops::Neg;
use bls12_381::{G1Projective, G2Projective, Gt, pairing, Scalar};
use group::Curve;
use crate::Attribute;
use crate::scheme::setup::GroupParameters;
#[derive(Debug, Clone)]
@@ -21,7 +21,7 @@ pub struct RequestInfo {
v: Scalar,
}
pub fn withdrawal_request(params: Parameters, sk_user: SecretKeyUser) -> Result<(WithdrawalRequest, RequestInfo)> {
pub fn withdrawal_request(params: &Parameters, sk_user: &SecretKeyUser) -> Result<(WithdrawalRequest, RequestInfo)> {
let grp = params.get_grp();
let g1 = grp.gen1();
let params_u = params.get_params_u();
@@ -78,7 +78,7 @@ pub fn withdrawal_request(params: Parameters, sk_user: SecretKeyUser) -> Result<
Ok((req, req_info))
}
pub(crate) fn issue(params: &Parameters, req: WithdrawalRequest, pk_u: PublicKeyUser, sk_a: SecretKeyAuth) -> Result<BlindedSignature> {
pub(crate) fn issue(params: &Parameters, req: &WithdrawalRequest, pk_u: PublicKeyUser, sk_a: &SecretKeyAuth) -> Result<BlindedSignature> {
let h = hash_g1(req.com.to_bytes());
if !(h == req.com_hash) {
return Err(DivisibleEcashError::WithdrawalRequestVerification(
@@ -1 +1,60 @@
use rand::thread_rng;
use crate::error::DivisibleEcashError;
use crate::scheme::aggregation::{aggregate_signatures, aggregate_verification_keys, aggregate_wallets};
use crate::scheme::keygen::{PublicKeyUser, SecretKeyUser, ttp_keygen_authorities, VerificationKeyAuth};
use crate::scheme::PayInfo;
use crate::scheme::setup::{GroupParameters, Parameters};
use crate::scheme::withdrawal::{issue, issue_verify, withdrawal_request};
#[test]
fn main() -> Result<(), DivisibleEcashError> {
// SETUP PHASE
let rng = thread_rng();
let grp = GroupParameters::new().unwrap();
let params = Parameters::new(grp.clone());
let params_u = params.get_params_u();
let params_a = params.get_params_a();
// KEY GENERATION FOR THE AUTHORITIES
let authorities_keypairs = ttp_keygen_authorities(&params, 2, 3).unwrap();
let verification_keys_auth: Vec<VerificationKeyAuth> = authorities_keypairs
.iter()
.map(|keypair| keypair.verification_key())
.collect();
let verification_key =
aggregate_verification_keys(&verification_keys_auth, Some(&[1, 2, 3])).unwrap();
// KEY GENERATION FOR THE USER
let sk = grp.random_scalar();
let sk_user = SecretKeyUser { sk };
let pk_user = SecretKeyUser::public_key(&sk_user, &grp);
// WITHDRAWAL REQUEST
let (withdrawal_req, req_info) = withdrawal_request(&params, &sk_user)?;
// ISSUE PARTIAL WALLETS
let mut partial_wallets = Vec::new();
for auth_keypair in authorities_keypairs {
let blind_signature = issue(
&params,
&withdrawal_req,
pk_user.clone(),
&auth_keypair.secret_key(),
)?;
let partial_wallet = issue_verify(&grp, &auth_keypair.verification_key(), &sk_user, &blind_signature, &req_info)?;
partial_wallets.push(partial_wallet);
}
// AGGREGATE WALLET
let mut wallet = aggregate_wallets(&grp, &verification_key, &sk_user, &partial_wallets)?;
let pay_info = PayInfo { info: [67u8; 32] };
let (payment, wallet) = wallet.spend(&params, &verification_key, &sk_user, &pay_info, 10)?;
// SPEND VERIFICATION
payment.spend_verify(&params, &verification_key, &pay_info);
Ok(())
}