Add aggregation and e2e test
This commit is contained in:
Generated
-1
@@ -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(¶ms_u.get_ith_sps_sign(l as usize + vv as usize - 1).rr.to_affine(), &yy.to_affine())
|
||||
// + pairing(¶ms_u.get_ith_sps_sign(l as usize + vv as usize - 1).ss.to_affine(), grp.gen2())
|
||||
// + pairing(¶ms_u.get_ith_sigma(l as usize + vv as usize - 1).to_affine(), ¶ms_u.get_sps_pk().get_ith_ww(0).to_affine())
|
||||
// + pairing(¶ms_u.get_ith_theta(l as usize + vv as usize - 1).to_affine(), ¶ms_u.get_sps_pk().get_ith_ww(1).to_affine())
|
||||
// - pairing(grp.gen1(), ¶ms_u.get_sps_pk().get_zz().to_affine()),
|
||||
// Gt::identity()
|
||||
// );
|
||||
|
||||
// let's do step by step checks:
|
||||
// 1
|
||||
// assert_eq!(pairing(¶ms_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(¶ms_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(¶ms_u.get_ith_sigma(l as usize + vv as usize - 1).to_affine(), ¶ms_u.get_sps_pk().get_ith_ww(0).to_affine()),
|
||||
// pg_varsigpr2_ww1 - pg_psi0_ww1 * r_varsig2
|
||||
// );
|
||||
// 4
|
||||
// assert_eq!(pairing(¶ms_u.get_ith_theta(l as usize + vv as usize - 1).to_affine(), ¶ms_u.get_sps_pk().get_ith_ww(1).to_affine()),
|
||||
// pg_thetapr2_ww2 - pg_psi0_ww2 * r_theta2
|
||||
// );
|
||||
// 5
|
||||
// assert_eq!(pairing(grp.gen1(), ¶ms_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(), ¶ms_a.get_ith_delta(k1 as usize).to_affine())
|
||||
+ pairing(&payment1.phi.1.to_affine(), ¶ms_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(), ¶ms_a.get_ith_delta(k2 as usize).to_affine())
|
||||
+ pairing(&payment2.phi.1.to_affine(), ¶ms_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(), ¶ms_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(), ¶ms_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(), ¶ms_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(), ¶ms_a.get_ith_delta((self.vv - 1) as usize).to_affine());
|
||||
let pg_psi0_delta = pairing(&psi_g1.to_affine(), ¶ms_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(), ¶ms_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(), ¶ms_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(¶ms, &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(¶ms, 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(¶ms, 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(¶ms, &sk_user)?;
|
||||
|
||||
// ISSUE PARTIAL WALLETS
|
||||
let mut partial_wallets = Vec::new();
|
||||
for auth_keypair in authorities_keypairs {
|
||||
let blind_signature = issue(
|
||||
¶ms,
|
||||
&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(¶ms, &verification_key, &sk_user, &pay_info, 10)?;
|
||||
|
||||
// SPEND VERIFICATION
|
||||
payment.spend_verify(¶ms, &verification_key, &pay_info);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user