Rebase, clippy, fmt
This commit is contained in:
Generated
+673
-1010
File diff suppressed because it is too large
Load Diff
+19
-2
@@ -111,7 +111,7 @@ members = [
|
||||
"tools/nymvisor",
|
||||
"tools/ts-rs-cli",
|
||||
"wasm/client",
|
||||
# "wasm/full-nym-wasm",
|
||||
# "wasm/full-nym-wasm",
|
||||
"wasm/mix-fetch",
|
||||
"wasm/node-tester",
|
||||
]
|
||||
@@ -128,7 +128,15 @@ default-members = [
|
||||
"explorer-api",
|
||||
]
|
||||
|
||||
exclude = ["explorer", "contracts", "nym-wallet", "nym-connect/mobile/src-tauri", "nym-connect/desktop", "nym-vpn/ui/src-tauri", "cpu-cycles"]
|
||||
exclude = [
|
||||
"explorer",
|
||||
"contracts",
|
||||
"nym-wallet",
|
||||
"nym-connect/mobile/src-tauri",
|
||||
"nym-connect/desktop",
|
||||
"nym-vpn/ui/src-tauri",
|
||||
"cpu-cycles",
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
authors = ["Nym Technologies SA"]
|
||||
@@ -207,6 +215,15 @@ wasm-bindgen-futures = "0.4.37"
|
||||
wasmtimer = "0.2.0"
|
||||
web-sys = "0.3.63"
|
||||
|
||||
bls12_381 = { path = "/Users/drazen/nym/bls12_381", default-features = false, features = [
|
||||
"alloc",
|
||||
"pairings",
|
||||
"experimental",
|
||||
"zeroize",
|
||||
] }
|
||||
ff = { version = "0.13", default-features = false }
|
||||
group = { version = "0.13", default-features = false }
|
||||
|
||||
# Profile settings for individual crates
|
||||
|
||||
[profile.release.package.nym-socks5-listener]
|
||||
|
||||
@@ -7,18 +7,20 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
chrono = "0.4.19"
|
||||
#bls12_381 = { version = "0.5", default-features = false, features = ["pairings", "alloc", "experimental"] }
|
||||
bls12_381 = { path = "/Users/simon/Documents/Nym/github/andrew_bls12_381", default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] }
|
||||
itertools = "0.10"
|
||||
digest = "0.9"
|
||||
rand = "0.8"
|
||||
thiserror = "1.0"
|
||||
sha2 = "0.9"
|
||||
bls12_381 = { workspace = true }
|
||||
bs58 = "0.4.0"
|
||||
serde = "1.0.189"
|
||||
chrono = "0.4.19"
|
||||
digest = "0.9"
|
||||
ff = { workspace = true }
|
||||
getset = "0.1.1"
|
||||
zeroize = "1.6.0"
|
||||
group = { workspace = true }
|
||||
itertools = "0.10"
|
||||
rand = "0.8"
|
||||
serde = "1.0.189"
|
||||
sha2 = "0.9"
|
||||
thiserror = "1.0"
|
||||
zeroize = { workspace = true }
|
||||
|
||||
|
||||
# internal
|
||||
nym-pemstore = { path = "../pemstore", version = "0.3.0" }
|
||||
@@ -26,14 +28,7 @@ nym-pemstore = { path = "../pemstore", version = "0.3.0" }
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.3", features = ["html_reports"] }
|
||||
|
||||
[dependencies.ff]
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
|
||||
[dependencies.group]
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
|
||||
[[bench]]
|
||||
name = "benchmarks"
|
||||
harness = false
|
||||
harness = false
|
||||
|
||||
@@ -264,7 +264,7 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
.unwrap();
|
||||
|
||||
// SPENDING PHASE
|
||||
let pay_info = PayInfo { info: [6u8; 32] };
|
||||
let pay_info = PayInfo { payinfo: [6u8; 32] };
|
||||
// CLIENT BENCHMARK: spend a single coin from the wallet
|
||||
// group.bench_function(
|
||||
// &format!(
|
||||
@@ -320,7 +320,7 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
let current_l = aggr_wallet.l.get();
|
||||
aggr_wallet.l.set(current_l - case.spend_vv);
|
||||
|
||||
let pay_info2 = PayInfo { info: [7u8; 32] };
|
||||
let pay_info2 = PayInfo { payinfo: [7u8; 32] };
|
||||
let (payment2, _) = aggr_wallet
|
||||
.spend(
|
||||
¶ms,
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use std::borrow::Borrow;
|
||||
|
||||
use bls12_381::Scalar;
|
||||
use digest::Digest;
|
||||
use digest::generic_array::typenum::Unsigned;
|
||||
use digest::Digest;
|
||||
use sha2::Sha256;
|
||||
|
||||
pub mod proof_spend;
|
||||
@@ -12,10 +12,10 @@ type ChallengeDigest = Sha256;
|
||||
|
||||
/// Generates a Scalar [or Fp] challenge by hashing a number of elliptic curve points.
|
||||
fn compute_challenge<D, I, B>(iter: I) -> Scalar
|
||||
where
|
||||
D: Digest,
|
||||
I: Iterator<Item=B>,
|
||||
B: AsRef<[u8]>,
|
||||
where
|
||||
D: Digest,
|
||||
I: Iterator<Item = B>,
|
||||
B: AsRef<[u8]>,
|
||||
{
|
||||
let mut h = D::new();
|
||||
for point_representation in iter {
|
||||
@@ -43,8 +43,8 @@ fn produce_response(witness_replacement: &Scalar, challenge: &Scalar, secret: &S
|
||||
|
||||
// note: it's caller's responsibility to ensure witnesses.len() = secrets.len()
|
||||
fn produce_responses<S>(witnesses: &[Scalar], challenge: &Scalar, secrets: &[S]) -> Vec<Scalar>
|
||||
where
|
||||
S: Borrow<Scalar>,
|
||||
where
|
||||
S: Borrow<Scalar>,
|
||||
{
|
||||
debug_assert_eq!(witnesses.len(), secrets.len());
|
||||
|
||||
|
||||
@@ -216,16 +216,21 @@ mod tests {
|
||||
.spend_verify(¶ms, &verification_key, &pay_info1)
|
||||
.unwrap());
|
||||
|
||||
|
||||
let pay_info2 = PayInfo::generate_payinfo(provider_keypair.public_key());
|
||||
let (payment2, _) = upd_wallet.spend(
|
||||
¶ms,
|
||||
&verification_key,
|
||||
&user_keypair.secret_key(),
|
||||
&pay_info2,
|
||||
false,
|
||||
spend_vv,
|
||||
).unwrap();
|
||||
let pay_info2 = PayInfo::generate_payinfo(
|
||||
provider_keypair.public_key().to_bytes()[..32]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
);
|
||||
let (payment2, _) = upd_wallet
|
||||
.spend(
|
||||
¶ms,
|
||||
&verification_key,
|
||||
&user_keypair.secret_key(),
|
||||
&pay_info2,
|
||||
false,
|
||||
spend_vv,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(payment2
|
||||
.spend_verify(¶ms, &verification_key, &pay_info2)
|
||||
@@ -433,15 +438,21 @@ mod tests {
|
||||
let current_l = aggr_wallet.l.get();
|
||||
aggr_wallet.l.set(current_l - 10);
|
||||
|
||||
let pay_info2 = PayInfo::generate_payinfo(provider_keypair.public_key());
|
||||
let (payment2, _) = aggr_wallet.spend(
|
||||
¶ms,
|
||||
&verification_key,
|
||||
&user_keypair.secret_key(),
|
||||
&pay_info2,
|
||||
false,
|
||||
spend_vv,
|
||||
).unwrap();
|
||||
let pay_info2 = PayInfo::generate_payinfo(
|
||||
provider_keypair.public_key().to_bytes()[..32]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
);
|
||||
let (payment2, _) = aggr_wallet
|
||||
.spend(
|
||||
¶ms,
|
||||
&verification_key,
|
||||
&user_keypair.secret_key(),
|
||||
&pay_info2,
|
||||
false,
|
||||
spend_vv,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let identify_result =
|
||||
identify(payment1, payment2, pay_info1.clone(), pay_info2.clone()).unwrap();
|
||||
|
||||
@@ -7,7 +7,7 @@ use getset::{CopyGetters, Getters};
|
||||
|
||||
use crate::error::{CompactEcashError, Result};
|
||||
use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness};
|
||||
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth, PublicKeyUser};
|
||||
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
|
||||
use crate::scheme::setup::{GroupParameters, Parameters};
|
||||
use crate::traits::Bytable;
|
||||
use crate::utils::{
|
||||
@@ -15,8 +15,8 @@ use crate::utils::{
|
||||
try_deserialize_g2_projective, try_deserialize_scalar, Signature, SignerIndex,
|
||||
};
|
||||
use crate::{Attribute, Base58};
|
||||
use chrono::{Utc, Timelike};
|
||||
use rand::{Rng, thread_rng};
|
||||
use chrono::Utc;
|
||||
use rand::{thread_rng, Rng};
|
||||
|
||||
pub mod aggregation;
|
||||
pub mod identify;
|
||||
|
||||
@@ -8,7 +8,9 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
#bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", branch = "gt-serialisation", default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] }
|
||||
bls12_381 = { path = "/Users/simon/Documents/Nym/github/andrew_bls12_381", default-features = false, features = ["alloc", "pairings", "experimental", "zeroize"] }
|
||||
bls12_381 = { workspace = true }
|
||||
ff = { workspace = true }
|
||||
group = { workspace = true }
|
||||
itertools = "0.10"
|
||||
digest = "0.9"
|
||||
rand = "0.8"
|
||||
@@ -19,14 +21,6 @@ bs58 = "0.4.0"
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.3", features = ["html_reports"] }
|
||||
|
||||
[dependencies.ff]
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
|
||||
[dependencies.group]
|
||||
version = "0.11"
|
||||
default-features = false
|
||||
|
||||
[[bench]]
|
||||
name = "benchmarks"
|
||||
harness = false
|
||||
harness = false
|
||||
|
||||
@@ -2,19 +2,23 @@ use std::collections::HashSet;
|
||||
use std::ops::Neg;
|
||||
use std::time::Duration;
|
||||
|
||||
use bls12_381::{G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, Gt, multi_miller_loop, Scalar};
|
||||
use criterion::{Criterion, criterion_group, criterion_main};
|
||||
use bls12_381::{
|
||||
multi_miller_loop, G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, Gt, Scalar,
|
||||
};
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use ff::Field;
|
||||
use group::{Curve, Group};
|
||||
use itertools::izip;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::thread_rng;
|
||||
|
||||
use nym_offline_divisible_ecash::{aggregate_verification_keys, aggregate_wallets,
|
||||
issue, issue_verify, PartialWallet,
|
||||
PayInfo, PublicKeyUser, SecretKeyUser, ttp_keygen_authorities, ttp_keygen_users, VerificationKeyAuth, withdrawal_request};
|
||||
use nym_offline_divisible_ecash::identification::{identify, IdentifyResult};
|
||||
use nym_offline_divisible_ecash::setup::{GroupParameters, Parameters};
|
||||
use nym_offline_divisible_ecash::{
|
||||
aggregate_verification_keys, aggregate_wallets, issue, issue_verify, ttp_keygen_authorities,
|
||||
ttp_keygen_users, withdrawal_request, PartialWallet, PayInfo, PublicKeyUser, SecretKeyUser,
|
||||
VerificationKeyAuth,
|
||||
};
|
||||
|
||||
#[allow(unused)]
|
||||
fn double_pairing(g11: &G1Affine, g21: &G2Affine, g12: &G1Affine, g22: &G2Affine) {
|
||||
@@ -118,9 +122,7 @@ fn bench_pairings(c: &mut Criterion) {
|
||||
b.iter(|| exponent_in_gt(gt, r))
|
||||
});
|
||||
|
||||
group.bench_function("single pairing", |b| {
|
||||
b.iter(|| single_pairing(&g11, &g21))
|
||||
});
|
||||
group.bench_function("single pairing", |b| b.iter(|| single_pairing(&g11, &g21)));
|
||||
|
||||
group.bench_function("double pairing", |b| {
|
||||
b.iter(|| double_pairing(&g11, &g21, &g12, &g22))
|
||||
@@ -166,7 +168,8 @@ fn bench_divisible_ecash(c: &mut Criterion) {
|
||||
|
||||
// KEY GENERATION FOR THE AUTHORITIES
|
||||
let threshold = (case.threshold_p * case.num_authorities as f32).round() as u64;
|
||||
let authorities_keypairs = ttp_keygen_authorities(¶ms, threshold, case.num_authorities).unwrap();
|
||||
let authorities_keypairs =
|
||||
ttp_keygen_authorities(¶ms, threshold, case.num_authorities).unwrap();
|
||||
let verification_keys_auth: Vec<VerificationKeyAuth> = authorities_keypairs
|
||||
.iter()
|
||||
.map(|keypair| keypair.verification_key())
|
||||
@@ -208,7 +211,7 @@ fn bench_divisible_ecash(c: &mut Criterion) {
|
||||
let mut rng = rand::thread_rng();
|
||||
let keypair = authorities_keypairs.choose(&mut rng).unwrap();
|
||||
group.bench_function(
|
||||
&format!("[Issuing Authority] issue_partial_wallet_with_L_{}", case.L, ),
|
||||
&format!("[Issuing Authority] issue_partial_wallet_with_L_{}", case.L,),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
issue(
|
||||
@@ -216,12 +219,12 @@ fn bench_divisible_ecash(c: &mut Criterion) {
|
||||
&withdrawal_req,
|
||||
pk_user.clone(),
|
||||
&keypair.secret_key(),
|
||||
).unwrap()
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
let mut wallet_blinded_signatures = Vec::new();
|
||||
for auth_keypair in authorities_keypairs {
|
||||
let blind_signature = issue(
|
||||
@@ -229,7 +232,8 @@ fn bench_divisible_ecash(c: &mut Criterion) {
|
||||
&withdrawal_req,
|
||||
pk_user.clone(),
|
||||
&auth_keypair.secret_key(),
|
||||
).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
wallet_blinded_signatures.push(blind_signature);
|
||||
}
|
||||
|
||||
@@ -237,7 +241,7 @@ fn bench_divisible_ecash(c: &mut Criterion) {
|
||||
let w = wallet_blinded_signatures.get(0).clone().unwrap();
|
||||
let vk = verification_keys_auth.get(0).clone().unwrap();
|
||||
group.bench_function(
|
||||
&format!("[Client] issue_verify_a_partial_wallet_with_L_{}", case.L, ),
|
||||
&format!("[Client] issue_verify_a_partial_wallet_with_L_{}", case.L,),
|
||||
|b| b.iter(|| issue_verify(&grp, vk, &sk_user, w, &req_info).unwrap()),
|
||||
);
|
||||
|
||||
@@ -245,12 +249,12 @@ fn bench_divisible_ecash(c: &mut Criterion) {
|
||||
wallet_blinded_signatures.iter(),
|
||||
verification_keys_auth.iter()
|
||||
)
|
||||
.map(|(w, vk)| issue_verify(&grp, &vk, &sk_user, &w, &req_info).unwrap())
|
||||
.collect();
|
||||
|
||||
.map(|(w, vk)| issue_verify(&grp, &vk, &sk_user, &w, &req_info).unwrap())
|
||||
.collect();
|
||||
|
||||
// AGGREGATE WALLET
|
||||
let mut wallet = aggregate_wallets(&grp, &verification_key, &sk_user, &partial_wallets).unwrap();
|
||||
let mut wallet =
|
||||
aggregate_wallets(&grp, &verification_key, &sk_user, &partial_wallets).unwrap();
|
||||
|
||||
// CLIENT BENCHMARK: aggregating all partial wallets
|
||||
group.bench_function(
|
||||
@@ -260,14 +264,22 @@ fn bench_divisible_ecash(c: &mut Criterion) {
|
||||
),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
aggregate_wallets(&grp, &verification_key, &sk_user, &partial_wallets)
|
||||
.unwrap()
|
||||
aggregate_wallets(&grp, &verification_key, &sk_user, &partial_wallets).unwrap()
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
let pay_info = PayInfo { info: [67u8; 32] };
|
||||
let (payment, wallet) = wallet.spend(¶ms, &verification_key, &sk_user, &pay_info, case.spend_vv, false).unwrap();
|
||||
let (payment, wallet) = wallet
|
||||
.spend(
|
||||
¶ms,
|
||||
&verification_key,
|
||||
&sk_user,
|
||||
&pay_info,
|
||||
case.spend_vv,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// CLIENT BENCHMARK: spend a single coin from the wallet
|
||||
group.bench_function(
|
||||
@@ -277,7 +289,15 @@ fn bench_divisible_ecash(c: &mut Criterion) {
|
||||
),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
wallet.spend(¶ms, &verification_key, &sk_user, &pay_info, case.spend_vv, true)
|
||||
wallet
|
||||
.spend(
|
||||
¶ms,
|
||||
&verification_key,
|
||||
&sk_user,
|
||||
&pay_info,
|
||||
case.spend_vv,
|
||||
true,
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
},
|
||||
@@ -291,7 +311,8 @@ fn bench_divisible_ecash(c: &mut Criterion) {
|
||||
),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
payment.spend_verify(¶ms, &verification_key, &pay_info)
|
||||
payment
|
||||
.spend_verify(¶ms, &verification_key, &pay_info)
|
||||
.unwrap()
|
||||
})
|
||||
},
|
||||
@@ -305,25 +326,50 @@ fn bench_divisible_ecash(c: &mut Criterion) {
|
||||
wallet.l.set(current_l - 1);
|
||||
|
||||
let pay_info2 = PayInfo { info: [52u8; 32] };
|
||||
let (payment2, wallet) = wallet.spend(¶ms, &verification_key, &sk_user, &pay_info2, 10, false).unwrap();
|
||||
let (payment2, wallet) = wallet
|
||||
.spend(¶ms, &verification_key, &sk_user, &pay_info2, 10, false)
|
||||
.unwrap();
|
||||
|
||||
// MERCHANT BENCHMARK: identify double spending
|
||||
group.bench_function(
|
||||
&format!(
|
||||
"[Merchant] identify_L_{}_threshold_{}_spend_vv_{}_pks_{}",
|
||||
case.L, case.threshold_p, case.spend_vv, pk_all_users.len()
|
||||
case.L,
|
||||
case.threshold_p,
|
||||
case.spend_vv,
|
||||
pk_all_users.len()
|
||||
),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
identify(¶ms, &verification_key, &pk_all_users, payment.clone(), payment2.clone(), pay_info, pay_info2).unwrap()
|
||||
identify(
|
||||
¶ms,
|
||||
&verification_key,
|
||||
&pk_all_users,
|
||||
payment.clone(),
|
||||
payment2.clone(),
|
||||
pay_info,
|
||||
pay_info2,
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
let identify_result = identify(¶ms, &verification_key, &pk_all_users, payment.clone(), payment2.clone(), pay_info, pay_info2).unwrap();
|
||||
assert_eq!(identify_result, IdentifyResult::DoubleSpendingPublicKeys(pk_user));
|
||||
let identify_result = identify(
|
||||
¶ms,
|
||||
&verification_key,
|
||||
&pk_all_users,
|
||||
payment.clone(),
|
||||
payment2.clone(),
|
||||
pay_info,
|
||||
pay_info2,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
identify_result,
|
||||
IdentifyResult::DoubleSpendingPublicKeys(pk_user)
|
||||
);
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_divisible_ecash);
|
||||
criterion_main!(benches);
|
||||
criterion_main!(benches);
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
/// Max value of wallet
|
||||
pub(crate) const L: u64 = 100;
|
||||
pub(crate) const L: u64 = 100;
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
use bls12_381::{G1Projective, G2Prepared, G2Projective, pairing, Scalar};
|
||||
use bls12_381::{pairing, G1Projective, G2Prepared, G2Projective, Scalar};
|
||||
|
||||
pub use scheme::aggregation::aggregate_verification_keys;
|
||||
pub use scheme::aggregation::aggregate_wallets;
|
||||
pub use scheme::identification;
|
||||
pub use scheme::keygen::{PublicKeyUser, SecretKeyUser, VerificationKeyAuth};
|
||||
pub use scheme::keygen::ttp_keygen_authorities;
|
||||
pub use scheme::keygen::ttp_keygen_users;
|
||||
pub use scheme::PartialWallet;
|
||||
pub use scheme::PayInfo;
|
||||
pub use scheme::keygen::{PublicKeyUser, SecretKeyUser, VerificationKeyAuth};
|
||||
pub use scheme::setup;
|
||||
pub use scheme::withdrawal::issue;
|
||||
pub use scheme::withdrawal::issue_verify;
|
||||
pub use scheme::withdrawal::withdrawal_request;
|
||||
pub use scheme::PartialWallet;
|
||||
pub use scheme::PayInfo;
|
||||
pub use traits::Base58;
|
||||
|
||||
use crate::error::DivisibleEcashError;
|
||||
use crate::traits::Bytable;
|
||||
|
||||
mod constants;
|
||||
mod error;
|
||||
mod proofs;
|
||||
mod scheme;
|
||||
@@ -24,6 +25,5 @@ mod scheme;
|
||||
mod tests;
|
||||
mod traits;
|
||||
mod utils;
|
||||
mod constants;
|
||||
|
||||
pub type Attribute = Scalar;
|
||||
|
||||
@@ -3,8 +3,8 @@ use std::convert::TryFrom;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use bls12_381::{G1Affine, G1Projective, Scalar};
|
||||
use digest::Digest;
|
||||
use digest::generic_array::typenum::Unsigned;
|
||||
use digest::Digest;
|
||||
use group::GroupEncoding;
|
||||
use sha2::Sha256;
|
||||
|
||||
@@ -13,17 +13,17 @@ use crate::scheme::keygen::PublicKeyUser;
|
||||
use crate::scheme::setup::GroupParameters;
|
||||
use crate::utils::try_deserialize_g1_projective;
|
||||
|
||||
pub mod proof_withdrawal;
|
||||
pub mod proof_spend;
|
||||
pub mod proof_withdrawal;
|
||||
|
||||
type ChallengeDigest = Sha256;
|
||||
|
||||
/// Generates a Scalar [or Fp] challenge by hashing a number of elliptic curve points.
|
||||
fn compute_challenge<D, I, B>(iter: I) -> Scalar
|
||||
where
|
||||
D: Digest,
|
||||
I: Iterator<Item=B>,
|
||||
B: AsRef<[u8]>,
|
||||
where
|
||||
D: Digest,
|
||||
I: Iterator<Item = B>,
|
||||
B: AsRef<[u8]>,
|
||||
{
|
||||
let mut h = D::new();
|
||||
for point_representation in iter {
|
||||
@@ -51,8 +51,8 @@ fn produce_response(witness_replacement: &Scalar, challenge: &Scalar, secret: &S
|
||||
|
||||
// note: it's caller's responsibility to ensure witnesses.len() = secrets.len()
|
||||
fn produce_responses<S>(witnesses: &[Scalar], challenge: &Scalar, secrets: &[S]) -> Vec<Scalar>
|
||||
where
|
||||
S: Borrow<Scalar>,
|
||||
where
|
||||
S: Borrow<Scalar>,
|
||||
{
|
||||
debug_assert_eq!(witnesses.len(), secrets.len());
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@ use std::ops::Neg;
|
||||
use bls12_381::{G1Projective, G2Projective, Gt, Scalar};
|
||||
use group::GroupEncoding;
|
||||
|
||||
use crate::proofs::{ChallengeDigest, compute_challenge, produce_response, produce_responses};
|
||||
use crate::scheme::{Phi, VarPhi, Wallet};
|
||||
use crate::error::{DivisibleEcashError, Result};
|
||||
use crate::proofs::{compute_challenge, produce_response, produce_responses, ChallengeDigest};
|
||||
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
|
||||
use crate::scheme::setup::Parameters;
|
||||
use crate::error::{DivisibleEcashError, Result};
|
||||
use crate::utils::{try_deserialize_scalar};
|
||||
use crate::scheme::{Phi, VarPhi, Wallet};
|
||||
use crate::utils::try_deserialize_scalar;
|
||||
|
||||
pub struct SpendInstance {
|
||||
pub kappa: G2Projective,
|
||||
@@ -136,7 +136,8 @@ impl SpendProof {
|
||||
instance: &SpendInstance,
|
||||
witness: &SpendWitness,
|
||||
verification_key: &VerificationKeyAuth,
|
||||
vv: u64) -> Self {
|
||||
vv: u64,
|
||||
) -> Self {
|
||||
let grp = params.get_grp();
|
||||
let params_u = params.get_params_u();
|
||||
let params_a = params.get_params_a();
|
||||
@@ -165,20 +166,31 @@ impl SpendProof {
|
||||
let zkcm_kappa = grp.gen2() * r_r
|
||||
+ verification_key.alpha
|
||||
+ r_attributes
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(attr, beta_i)| beta_i * attr)
|
||||
.sum::<G2Projective>();
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(attr, beta_i)| beta_i * attr)
|
||||
.sum::<G2Projective>();
|
||||
|
||||
let zkcm_phi0 = g1 * r_r1;
|
||||
let zkcm_phi1 = instance.varsig_prime1 * r_v + instance.psi_g1 * r_rho1 + params_u.get_ith_eta(vv as usize) * r_r1;
|
||||
let zkcm_phi1 = instance.varsig_prime1 * r_v
|
||||
+ instance.psi_g1 * r_rho1
|
||||
+ params_u.get_ith_eta(vv as usize) * r_r1;
|
||||
let zkcm_varphi0 = g1 * r_r2;
|
||||
let zkcm_varphi1 = (g1 * instance.rr) * r_sk_u + instance.theta_prime1 * r_v + instance.psi_g1 * r_rho2 + params_u.get_ith_eta(vv as usize) * r_r2;
|
||||
let zkcm_pg_eq1 = instance.pg_psi0_delta * r_r_varsig1 + instance.pg_psi0_gen2 * r_r_varsig2.neg();
|
||||
let zkcm_pg_eq2 = instance.pg_psi0_delta * r_r_theta1 + instance.pg_psi0_gen2 * r_r_theta2.neg();
|
||||
let zkcm_pg_eq3 = instance.pg_psi0_yy * r_r_rr + instance.pg_psi0_gen2 * r_r_ss + instance.pg_psi0_ww1 * r_r_varsig2 + instance.pg_psi0_ww2 * r_r_theta2;
|
||||
let zkcm_pg_eq4 = instance.pg_rr_psi1 * r_r_tt + instance.pg_psi0_tt * r_r_rr + instance.pg_psi0_psi1 * r_rho3.neg();
|
||||
|
||||
let zkcm_varphi1 = (g1 * instance.rr) * r_sk_u
|
||||
+ instance.theta_prime1 * r_v
|
||||
+ instance.psi_g1 * r_rho2
|
||||
+ params_u.get_ith_eta(vv as usize) * r_r2;
|
||||
let zkcm_pg_eq1 =
|
||||
instance.pg_psi0_delta * r_r_varsig1 + instance.pg_psi0_gen2 * r_r_varsig2.neg();
|
||||
let zkcm_pg_eq2 =
|
||||
instance.pg_psi0_delta * r_r_theta1 + instance.pg_psi0_gen2 * r_r_theta2.neg();
|
||||
let zkcm_pg_eq3 = instance.pg_psi0_yy * r_r_rr
|
||||
+ instance.pg_psi0_gen2 * r_r_ss
|
||||
+ instance.pg_psi0_ww1 * r_r_varsig2
|
||||
+ instance.pg_psi0_ww2 * r_r_theta2;
|
||||
let zkcm_pg_eq4 = instance.pg_rr_psi1 * r_r_tt
|
||||
+ instance.pg_psi0_tt * r_r_rr
|
||||
+ instance.pg_psi0_psi1 * r_rho3.neg();
|
||||
|
||||
let challenge = compute_challenge::<ChallengeDigest, _, _>(
|
||||
std::iter::once(g1.to_bytes().as_ref())
|
||||
@@ -191,7 +203,7 @@ impl SpendProof {
|
||||
.chain(std::iter::once(zkcm_pg_eq1.to_compressed().as_ref()))
|
||||
.chain(std::iter::once(zkcm_pg_eq2.to_compressed().as_ref()))
|
||||
.chain(std::iter::once(zkcm_pg_eq3.to_compressed().as_ref()))
|
||||
.chain(std::iter::once(zkcm_pg_eq4.to_compressed().as_ref()))
|
||||
.chain(std::iter::once(zkcm_pg_eq4.to_compressed().as_ref())),
|
||||
);
|
||||
|
||||
// compute response for each witness
|
||||
@@ -212,7 +224,6 @@ impl SpendProof {
|
||||
let response_r_rho2 = produce_response(&r_rho2, &challenge, &witness.rho2);
|
||||
let response_r_rho3 = produce_response(&r_rho3, &challenge, &witness.rho3);
|
||||
|
||||
|
||||
SpendProof {
|
||||
challenge,
|
||||
response_r,
|
||||
@@ -251,10 +262,10 @@ impl SpendProof {
|
||||
+ grp.gen2() * self.response_r
|
||||
+ verification_key.alpha * (Scalar::one() - self.challenge)
|
||||
+ [self.response_r_sk_u, self.response_r_v]
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(attr, beta_i)| beta_i * attr)
|
||||
.sum::<G2Projective>();
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(attr, beta_i)| beta_i * attr)
|
||||
.sum::<G2Projective>();
|
||||
|
||||
let zkcm_phi0 = g1 * self.response_r_r1 + instance.phi.0 * self.challenge;
|
||||
let zkcm_phi1 = instance.varsig_prime1 * self.response_r_v
|
||||
@@ -297,7 +308,7 @@ impl SpendProof {
|
||||
.chain(std::iter::once(zkcm_pg_eq1.to_compressed().as_ref()))
|
||||
.chain(std::iter::once(zkcm_pg_eq2.to_compressed().as_ref()))
|
||||
.chain(std::iter::once(zkcm_pg_eq3.to_compressed().as_ref()))
|
||||
.chain(std::iter::once(zkcm_pg_eq4.to_compressed().as_ref()))
|
||||
.chain(std::iter::once(zkcm_pg_eq4.to_compressed().as_ref())),
|
||||
);
|
||||
|
||||
challenge == self.challenge
|
||||
@@ -331,7 +342,9 @@ impl TryFrom<&[u8]> for SpendProof {
|
||||
let response_r_sk_u_bytes = bytes[FIELD_SIZE * 2..FIELD_SIZE * 3].try_into().unwrap();
|
||||
let response_r_sk_u = try_deserialize_scalar(
|
||||
&response_r_sk_u_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize response_r_sk_u".to_string()),
|
||||
DivisibleEcashError::Deserialization(
|
||||
"Failed to deserialize response_r_sk_u".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
let response_r_v_bytes = bytes[FIELD_SIZE * 3..FIELD_SIZE * 4].try_into().unwrap();
|
||||
@@ -361,25 +374,33 @@ impl TryFrom<&[u8]> for SpendProof {
|
||||
let response_r_varsig1_bytes = bytes[FIELD_SIZE * 7..FIELD_SIZE * 8].try_into().unwrap();
|
||||
let response_r_varsig1 = try_deserialize_scalar(
|
||||
response_r_varsig1_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize response_r_varsig1".to_string()),
|
||||
DivisibleEcashError::Deserialization(
|
||||
"Failed to deserialize response_r_varsig1".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
let response_r_theta1_bytes = bytes[FIELD_SIZE * 8..FIELD_SIZE * 9].try_into().unwrap();
|
||||
let response_r_theta1 = try_deserialize_scalar(
|
||||
&response_r_theta1_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize response_r_theta1".to_string()),
|
||||
DivisibleEcashError::Deserialization(
|
||||
"Failed to deserialize response_r_theta1".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
let response_r_varsig2_bytes = bytes[FIELD_SIZE * 9..FIELD_SIZE * 10].try_into().unwrap();
|
||||
let response_r_varsig2 = try_deserialize_scalar(
|
||||
&response_r_varsig2_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize response_r_varsig2".to_string()),
|
||||
DivisibleEcashError::Deserialization(
|
||||
"Failed to deserialize response_r_varsig2".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
let response_r_theta2_bytes = bytes[FIELD_SIZE * 10..FIELD_SIZE * 11].try_into().unwrap();
|
||||
let response_r_theta2 = try_deserialize_scalar(
|
||||
&response_r_theta2_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize response_r_theta2".to_string()),
|
||||
DivisibleEcashError::Deserialization(
|
||||
"Failed to deserialize response_r_theta2".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
let response_r_rr_bytes = bytes[FIELD_SIZE * 11..FIELD_SIZE * 12].try_into().unwrap();
|
||||
@@ -403,19 +424,25 @@ impl TryFrom<&[u8]> for SpendProof {
|
||||
let response_r_rho1_bytes = bytes[FIELD_SIZE * 14..FIELD_SIZE * 15].try_into().unwrap();
|
||||
let response_r_rho1 = try_deserialize_scalar(
|
||||
&response_r_rho1_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize response_r_rho1".to_string()),
|
||||
DivisibleEcashError::Deserialization(
|
||||
"Failed to deserialize response_r_rho1".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
let response_r_rho2_bytes = bytes[FIELD_SIZE * 15..FIELD_SIZE * 16].try_into().unwrap();
|
||||
let response_r_rho2 = try_deserialize_scalar(
|
||||
&response_r_rho2_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize response_r_rho2".to_string()),
|
||||
DivisibleEcashError::Deserialization(
|
||||
"Failed to deserialize response_r_rho2".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
let response_r_rho3_bytes = bytes[FIELD_SIZE * 16..FIELD_SIZE * 17].try_into().unwrap();
|
||||
let response_r_rho3 = try_deserialize_scalar(
|
||||
&response_r_rho3_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize response_r_rho3".to_string()),
|
||||
DivisibleEcashError::Deserialization(
|
||||
"Failed to deserialize response_r_rho3".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
Ok(SpendProof {
|
||||
@@ -444,15 +471,17 @@ impl TryFrom<&[u8]> for SpendProof {
|
||||
mod tests {
|
||||
use std::ops::Neg;
|
||||
|
||||
use bls12_381::{G2Projective, pairing};
|
||||
use bls12_381::{pairing, G2Projective};
|
||||
use group::Curve;
|
||||
use rand::thread_rng;
|
||||
|
||||
use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness};
|
||||
use crate::scheme::{PayInfo, Phi, VarPhi};
|
||||
use crate::scheme::aggregation::aggregate_verification_keys;
|
||||
use crate::scheme::keygen::{PublicKeyUser, SecretKeyUser, ttp_keygen_authorities, VerificationKeyAuth};
|
||||
use crate::scheme::keygen::{
|
||||
ttp_keygen_authorities, PublicKeyUser, SecretKeyUser, VerificationKeyAuth,
|
||||
};
|
||||
use crate::scheme::setup::{GroupParameters, Parameters};
|
||||
use crate::scheme::{PayInfo, Phi, VarPhi};
|
||||
use crate::utils::hash_to_scalar;
|
||||
|
||||
#[test]
|
||||
@@ -485,18 +514,26 @@ mod tests {
|
||||
let kappa = grp.gen2() * r
|
||||
+ verification_key.alpha
|
||||
+ attributes
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(priv_attr, beta_i)| beta_i * priv_attr)
|
||||
.sum::<G2Projective>();
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(priv_attr, beta_i)| beta_i * priv_attr)
|
||||
.sum::<G2Projective>();
|
||||
|
||||
let r1 = grp.random_scalar();
|
||||
let r2 = grp.random_scalar();
|
||||
let phi = Phi(grp.gen1() * r1, params_u.get_ith_sigma(l as usize) * v + params_u.get_ith_eta(vv as usize) * r1);
|
||||
let phi = Phi(
|
||||
grp.gen1() * r1,
|
||||
params_u.get_ith_sigma(l as usize) * v + params_u.get_ith_eta(vv as usize) * r1,
|
||||
);
|
||||
|
||||
let pay_info = PayInfo { info: [78u8; 32] };
|
||||
let rr = hash_to_scalar(pay_info.info);
|
||||
let varphi = VarPhi(grp.gen1() * r2, (grp.gen1() * rr) * sk + params_u.get_ith_theta(l as usize) * v + params_u.get_ith_eta(vv as usize) * r2);
|
||||
let varphi = VarPhi(
|
||||
grp.gen1() * r2,
|
||||
(grp.gen1() * rr) * sk
|
||||
+ params_u.get_ith_theta(l as usize) * v
|
||||
+ params_u.get_ith_eta(vv as usize) * r2,
|
||||
);
|
||||
|
||||
// random value used to compute blinded bases
|
||||
let r_varsig1 = grp.random_scalar();
|
||||
@@ -507,29 +544,37 @@ mod tests {
|
||||
let r_ss = grp.random_scalar();
|
||||
let r_tt = grp.random_scalar();
|
||||
|
||||
|
||||
// compute blinded bases
|
||||
let psi_g1 = params_u.get_psi_g1();
|
||||
let psi_g2 = params_u.get_psi_g2();
|
||||
let varsig_prime1 = params_u.get_ith_sigma(l as usize) + (psi_g1 * r_varsig1);
|
||||
let theta_prime1 = params_u.get_ith_theta(l as usize) + (psi_g1 * r_theta1);
|
||||
let varsig_prime2 = params_u.get_ith_sigma(l as usize + vv as usize - 1) + (psi_g1 * r_varsig2);
|
||||
let theta_prime2 = params_u.get_ith_theta(l as usize + vv as usize - 1) + (psi_g1 * r_theta2);
|
||||
let varsig_prime2 =
|
||||
params_u.get_ith_sigma(l as usize + vv as usize - 1) + (psi_g1 * r_varsig2);
|
||||
let theta_prime2 =
|
||||
params_u.get_ith_theta(l as usize + vv as usize - 1) + (psi_g1 * r_theta2);
|
||||
let rr_prime = params_u.get_ith_sps_sign(l as usize + vv as usize - 1).rr + (psi_g1 * r_rr);
|
||||
let ss_prime = params_u.get_ith_sps_sign(l as usize + vv as usize - 1).ss + (psi_g1 * r_ss);
|
||||
let tt_prime = params_u.get_ith_sps_sign(l as usize + vv as usize - 1).tt + (psi_g2 * r_tt);
|
||||
|
||||
|
||||
let rho1 = v.neg() * r_varsig1;
|
||||
let rho2 = v.neg() * r_theta1;
|
||||
let rho3 = r_rr * r_tt;
|
||||
|
||||
|
||||
let pg_varsigpr1_delta = pairing(&varsig_prime1.to_affine(), ¶ms_a.get_ith_delta((vv - 1) as usize).to_affine());
|
||||
let pg_psi0_delta = pairing(&psi_g1.to_affine(), ¶ms_a.get_ith_delta((vv - 1) as usize).to_affine());
|
||||
let pg_varsigpr1_delta = pairing(
|
||||
&varsig_prime1.to_affine(),
|
||||
¶ms_a.get_ith_delta((vv - 1) as usize).to_affine(),
|
||||
);
|
||||
let pg_psi0_delta = pairing(
|
||||
&psi_g1.to_affine(),
|
||||
¶ms_a.get_ith_delta((vv - 1) as usize).to_affine(),
|
||||
);
|
||||
let pg_varsigpr2_gen2 = pairing(&varsig_prime2.to_affine(), grp.gen2());
|
||||
let pg_psi0_gen2 = pairing(&psi_g1.to_affine(), grp.gen2());
|
||||
let pg_thetapr1_delta = pairing(&theta_prime1.to_affine(), ¶ms_a.get_ith_delta((vv - 1) as usize).to_affine());
|
||||
let pg_thetapr1_delta = pairing(
|
||||
&theta_prime1.to_affine(),
|
||||
¶ms_a.get_ith_delta((vv - 1) as usize).to_affine(),
|
||||
);
|
||||
let pg_thetapr2_gen2 = pairing(&theta_prime2.to_affine(), grp.gen2());
|
||||
let yy = params_u.get_sps_pk().get_yy();
|
||||
let pg_rrprime_yy = pairing(&rr_prime.to_affine(), &yy.to_affine());
|
||||
@@ -550,10 +595,10 @@ mod tests {
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
|
||||
let instance = SpendInstance {
|
||||
kappa,
|
||||
phi,
|
||||
@@ -606,8 +651,5 @@ mod tests {
|
||||
let zk_proof_bytes = zk_proof.to_bytes();
|
||||
let zk_proof2 = SpendProof::try_from(&zk_proof_bytes[..]).unwrap();
|
||||
assert_eq!(zk_proof, zk_proof2);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ use group::GroupEncoding;
|
||||
use itertools::izip;
|
||||
|
||||
use crate::error::{DivisibleEcashError, Result};
|
||||
use crate::proofs::{ChallengeDigest, compute_challenge, produce_response, produce_responses};
|
||||
use crate::proofs::{compute_challenge, produce_response, produce_responses, ChallengeDigest};
|
||||
use crate::scheme::keygen::PublicKeyUser;
|
||||
use crate::scheme::setup::{GroupParameters, Parameters};
|
||||
use crate::utils::try_deserialize_g1_projective;
|
||||
@@ -140,10 +140,10 @@ impl WithdrawalReqProof {
|
||||
// compute zkp commitments for each instance
|
||||
let zkcm_com = g1 * r_com_opening
|
||||
+ r_attributes
|
||||
.iter()
|
||||
.zip(params_u.get_gammas().iter())
|
||||
.map(|(rm_i, gamma_i)| gamma_i * rm_i)
|
||||
.sum::<G1Projective>();
|
||||
.iter()
|
||||
.zip(params_u.get_gammas().iter())
|
||||
.map(|(rm_i, gamma_i)| gamma_i * rm_i)
|
||||
.sum::<G1Projective>();
|
||||
|
||||
let zkcm_pedcom = r_pedcom_openings
|
||||
.iter()
|
||||
@@ -196,11 +196,7 @@ impl WithdrawalReqProof {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn verify(
|
||||
&self,
|
||||
params: &Parameters,
|
||||
instance: &WithdrawalReqInstance,
|
||||
) -> bool {
|
||||
pub(crate) fn verify(&self, params: &Parameters, instance: &WithdrawalReqInstance) -> bool {
|
||||
let grp = params.get_grp();
|
||||
let g1 = grp.gen1();
|
||||
let params_u = params.get_params_u();
|
||||
@@ -209,21 +205,21 @@ impl WithdrawalReqProof {
|
||||
let zkcm_com = instance.com * self.challenge
|
||||
+ g1 * self.response_opening
|
||||
+ self
|
||||
.response_attributes
|
||||
.iter()
|
||||
.zip(params_u.get_gammas().iter())
|
||||
.map(|(m_i, gamma_i)| gamma_i * m_i)
|
||||
.sum::<G1Projective>();
|
||||
.response_attributes
|
||||
.iter()
|
||||
.zip(params_u.get_gammas().iter())
|
||||
.map(|(m_i, gamma_i)| gamma_i * m_i)
|
||||
.sum::<G1Projective>();
|
||||
|
||||
let zkcm_pedcom = izip!(
|
||||
instance.pc_coms.iter(),
|
||||
self.response_openings.iter(),
|
||||
self.response_attributes.iter()
|
||||
)
|
||||
.map(|(cm_j, resp_o_j, resp_m_j)| {
|
||||
cm_j * self.challenge + g1 * resp_o_j + instance.h * resp_m_j
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
.map(|(cm_j, resp_o_j, resp_m_j)| {
|
||||
cm_j * self.challenge + g1 * resp_o_j + instance.h * resp_m_j
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let zk_commitment_user_sk =
|
||||
instance.pk_user.pk * self.challenge + g1 * self.response_attributes[0];
|
||||
@@ -292,7 +288,6 @@ mod tests {
|
||||
let grp = GroupParameters::new().unwrap();
|
||||
let params = Parameters::new(grp.clone());
|
||||
|
||||
|
||||
let sk = grp.random_scalar();
|
||||
let pk_user = PublicKeyUser {
|
||||
pk: grp.gen1() * sk,
|
||||
@@ -304,10 +299,10 @@ mod tests {
|
||||
let com_opening = grp.random_scalar();
|
||||
let com = grp.gen1() * com_opening
|
||||
+ attr
|
||||
.iter()
|
||||
.zip(params.get_params_u().get_gammas())
|
||||
.map(|(&m, gamma)| gamma * m)
|
||||
.sum::<G1Projective>();
|
||||
.iter()
|
||||
.zip(params.get_params_u().get_gammas())
|
||||
.map(|(&m, gamma)| gamma * m)
|
||||
.sum::<G1Projective>();
|
||||
let h = hash_g1(com.to_bytes());
|
||||
|
||||
let pc_openings = grp.n_random_scalars(attr.len());
|
||||
|
||||
@@ -2,19 +2,19 @@ use core::iter::Sum;
|
||||
use core::ops::Mul;
|
||||
use std::cell::Cell;
|
||||
|
||||
use bls12_381::{G2Prepared, G2Projective, pairing, Scalar};
|
||||
use bls12_381::{pairing, G2Prepared, G2Projective, 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::scheme::{PartialWallet, Wallet};
|
||||
use crate::utils::{
|
||||
check_bilinear_pairing, PartialSignature, perform_lagrangian_interpolation_at_origin,
|
||||
check_bilinear_pairing, perform_lagrangian_interpolation_at_origin, PartialSignature,
|
||||
Signature, SignatureShare, SignerIndex,
|
||||
};
|
||||
use crate::Attribute;
|
||||
|
||||
pub(crate) trait Aggregatable: Sized {
|
||||
fn aggregate(aggregatable: &[Self], indices: Option<&[SignerIndex]>) -> Result<Self>;
|
||||
@@ -26,10 +26,10 @@ pub(crate) trait Aggregatable: Sized {
|
||||
}
|
||||
|
||||
impl<T> Aggregatable for T
|
||||
where
|
||||
T: Sum,
|
||||
for<'a> T: Sum<&'a T>,
|
||||
for<'a> &'a T: Mul<Scalar, Output=T>,
|
||||
where
|
||||
T: Sum,
|
||||
for<'a> T: Sum<&'a T>,
|
||||
for<'a> &'a T: Mul<Scalar, Output = T>,
|
||||
{
|
||||
fn aggregate(aggregatable: &[T], indices: Option<&[u64]>) -> Result<T> {
|
||||
if aggregatable.is_empty() {
|
||||
@@ -164,4 +164,3 @@ pub fn aggregate_wallets(
|
||||
l: Cell::new(1),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ops::Neg;
|
||||
|
||||
use bls12_381::{Gt, pairing, Scalar};
|
||||
use bls12_381::{pairing, Gt, Scalar};
|
||||
use group::Curve;
|
||||
|
||||
use crate::error::{DivisibleEcashError, Result};
|
||||
use crate::scheme::{PayInfo, Payment};
|
||||
use crate::scheme::identification::IdentifyResult::DoubleSpendingPublicKeys;
|
||||
use crate::scheme::keygen::{PublicKeyUser, VerificationKeyAuth};
|
||||
use crate::scheme::setup::Parameters;
|
||||
use crate::scheme::{PayInfo, Payment};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum IdentifyResult {
|
||||
@@ -26,15 +26,23 @@ pub fn identify(
|
||||
payment1: Payment,
|
||||
payment2: Payment,
|
||||
pay_info1: PayInfo,
|
||||
pay_info2: PayInfo) -> Result<IdentifyResult> {
|
||||
pay_info2: 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 k in 0..payment1.vv {
|
||||
let sn = pairing(&payment1.phi.1.to_affine(), ¶ms_a.get_ith_delta(k as usize).to_affine())
|
||||
+ pairing(&payment1.phi.0.to_affine(), ¶ms_a.get_etas_ith_jth_elem(payment1.vv as usize, k as usize).to_affine());
|
||||
let sn = pairing(
|
||||
&payment1.phi.1.to_affine(),
|
||||
¶ms_a.get_ith_delta(k as usize).to_affine(),
|
||||
) + pairing(
|
||||
&payment1.phi.0.to_affine(),
|
||||
¶ms_a
|
||||
.get_etas_ith_jth_elem(payment1.vv as usize, k as usize)
|
||||
.to_affine(),
|
||||
);
|
||||
serial_numbers.insert(sn, k);
|
||||
}
|
||||
|
||||
@@ -43,8 +51,15 @@ pub fn identify(
|
||||
let mut k2 = 0;
|
||||
let mut duplicate_serial_numbers: Vec<(Gt, u64, u64)> = Default::default();
|
||||
for j in 0..payment2.vv {
|
||||
let sn = pairing(&payment2.phi.1.to_affine(), ¶ms_a.get_ith_delta(j as usize).to_affine())
|
||||
+ pairing(&payment2.phi.0.to_affine(), ¶ms_a.get_etas_ith_jth_elem(payment2.vv as usize, j as usize).to_affine());
|
||||
let sn = pairing(
|
||||
&payment2.phi.1.to_affine(),
|
||||
¶ms_a.get_ith_delta(j as usize).to_affine(),
|
||||
) + pairing(
|
||||
&payment2.phi.0.to_affine(),
|
||||
¶ms_a
|
||||
.get_etas_ith_jth_elem(payment2.vv as usize, j as usize)
|
||||
.to_affine(),
|
||||
);
|
||||
if !serial_numbers.contains_key(&sn) {
|
||||
serial_numbers.insert(sn, j);
|
||||
} else {
|
||||
@@ -61,13 +76,25 @@ pub fn identify(
|
||||
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_etas_ith_jth_elem(payment1.vv as usize, k1 as usize).to_affine());
|
||||
+ pairing(
|
||||
&payment1.varphi.0.to_affine(),
|
||||
¶ms_a
|
||||
.get_etas_ith_jth_elem(payment1.vv as usize, 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_etas_ith_jth_elem(payment2.vv as usize, k2 as usize).to_affine());
|
||||
|
||||
+ pairing(
|
||||
&payment2.varphi.0.to_affine(),
|
||||
¶ms_a
|
||||
.get_etas_ith_jth_elem(payment2.vv as usize, 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 + delta_k2 * payment2.rr.neg()).to_affine());
|
||||
let pg_pku_deltas = pairing(
|
||||
&pk_u.pk.to_affine(),
|
||||
&(delta_k1 * payment1.rr + delta_k2 * payment2.rr.neg()).to_affine(),
|
||||
);
|
||||
if tt1 - tt2 == pg_pku_deltas {
|
||||
return Ok(IdentifyResult::DoubleSpendingPublicKeys(pk_u.clone()));
|
||||
}
|
||||
@@ -86,12 +113,14 @@ mod tests {
|
||||
use group::Curve;
|
||||
use rand::thread_rng;
|
||||
|
||||
use crate::scheme::{PayInfo, Payment};
|
||||
use crate::scheme::aggregation::{aggregate_verification_keys, aggregate_wallets};
|
||||
use crate::scheme::identification::{identify, IdentifyResult};
|
||||
use crate::scheme::keygen::{PublicKeyUser, SecretKeyUser, ttp_keygen_authorities, VerificationKeyAuth};
|
||||
use crate::scheme::keygen::{
|
||||
ttp_keygen_authorities, PublicKeyUser, SecretKeyUser, VerificationKeyAuth,
|
||||
};
|
||||
use crate::scheme::setup::{GroupParameters, Parameters};
|
||||
use crate::scheme::withdrawal::{issue, issue_verify, withdrawal_request};
|
||||
use crate::scheme::{PayInfo, Payment};
|
||||
use crate::utils::hash_g1;
|
||||
|
||||
#[test]
|
||||
@@ -121,7 +150,6 @@ mod tests {
|
||||
let sk_user2 = SecretKeyUser { sk: sk2 };
|
||||
let pk_user2 = SecretKeyUser::public_key(&sk_user2, &grp);
|
||||
|
||||
|
||||
// WITHDRAWAL REQUEST FOR USER1
|
||||
let (withdrawal_req1, req_info1) = withdrawal_request(¶ms, &sk_user1).unwrap();
|
||||
|
||||
@@ -133,28 +161,52 @@ mod tests {
|
||||
&withdrawal_req1,
|
||||
pk_user1.clone(),
|
||||
&auth_keypair.secret_key(),
|
||||
).unwrap();
|
||||
let partial_wallet1 = issue_verify(&grp, &auth_keypair.verification_key(), &sk_user1, &blind_signature, &req_info1).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
let partial_wallet1 = issue_verify(
|
||||
&grp,
|
||||
&auth_keypair.verification_key(),
|
||||
&sk_user1,
|
||||
&blind_signature,
|
||||
&req_info1,
|
||||
)
|
||||
.unwrap();
|
||||
partial_wallets1.push(partial_wallet1);
|
||||
}
|
||||
|
||||
// AGGREGATE WALLET FOR USER1
|
||||
let mut wallet1 = aggregate_wallets(&grp, &verification_key, &sk_user1, &partial_wallets1).unwrap();
|
||||
let mut wallet1 =
|
||||
aggregate_wallets(&grp, &verification_key, &sk_user1, &partial_wallets1).unwrap();
|
||||
|
||||
let pay_info1 = PayInfo { info: [67u8; 32] };
|
||||
let (payment1, wallet1) = wallet1.spend(¶ms, &verification_key, &sk_user1, &pay_info1, 10, false).unwrap();
|
||||
let (payment1, wallet1) = wallet1
|
||||
.spend(¶ms, &verification_key, &sk_user1, &pay_info1, 10, false)
|
||||
.unwrap();
|
||||
|
||||
// SPEND VERIFICATION for USER1
|
||||
assert!(payment1.spend_verify(¶ms, &verification_key, &pay_info1).unwrap());
|
||||
assert!(payment1
|
||||
.spend_verify(¶ms, &verification_key, &pay_info1)
|
||||
.unwrap());
|
||||
|
||||
let payment2 = payment1.clone();
|
||||
// SPEND VERIFICATION for the duplicate payment
|
||||
assert!(payment1.spend_verify(¶ms, &verification_key, &pay_info1).unwrap());
|
||||
assert!(payment1
|
||||
.spend_verify(¶ms, &verification_key, &pay_info1)
|
||||
.unwrap());
|
||||
|
||||
let pay_info2 = pay_info1.clone();
|
||||
|
||||
let public_keys = HashSet::from([pk_user1, pk_user2]);
|
||||
let identify_result = identify(¶ms, &verification_key, &public_keys, payment1, payment2, pay_info1, pay_info2).unwrap();
|
||||
let identify_result = identify(
|
||||
¶ms,
|
||||
&verification_key,
|
||||
&public_keys,
|
||||
payment1,
|
||||
payment2,
|
||||
pay_info1,
|
||||
pay_info2,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(identify_result, IdentifyResult::DuplicatePayInfo(pay_info1));
|
||||
}
|
||||
|
||||
@@ -181,7 +233,6 @@ mod tests {
|
||||
let sk_user1 = SecretKeyUser { sk: sk1 };
|
||||
let pk_user1 = SecretKeyUser::public_key(&sk_user1, &grp);
|
||||
|
||||
|
||||
// GENERATE KEYS FOR OTHER USERS
|
||||
let mut pk_all_users = HashSet::new();
|
||||
for i in 0..50 {
|
||||
@@ -203,28 +254,52 @@ mod tests {
|
||||
&withdrawal_req1,
|
||||
pk_user1.clone(),
|
||||
&auth_keypair.secret_key(),
|
||||
).unwrap();
|
||||
let partial_wallet1 = issue_verify(&grp, &auth_keypair.verification_key(), &sk_user1, &blind_signature, &req_info1).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
let partial_wallet1 = issue_verify(
|
||||
&grp,
|
||||
&auth_keypair.verification_key(),
|
||||
&sk_user1,
|
||||
&blind_signature,
|
||||
&req_info1,
|
||||
)
|
||||
.unwrap();
|
||||
partial_wallets1.push(partial_wallet1);
|
||||
}
|
||||
|
||||
// AGGREGATE WALLET FOR USER1
|
||||
let mut wallet1 = aggregate_wallets(&grp, &verification_key, &sk_user1, &partial_wallets1).unwrap();
|
||||
let mut wallet1 =
|
||||
aggregate_wallets(&grp, &verification_key, &sk_user1, &partial_wallets1).unwrap();
|
||||
|
||||
let pay_info1 = PayInfo { info: [67u8; 32] };
|
||||
let (payment1, new_wallet1) = wallet1.spend(¶ms, &verification_key, &sk_user1, &pay_info1, 10, false).unwrap();
|
||||
let (payment1, new_wallet1) = wallet1
|
||||
.spend(¶ms, &verification_key, &sk_user1, &pay_info1, 10, false)
|
||||
.unwrap();
|
||||
|
||||
// let's reverse the spending counter in the wallet to create a double spending payment
|
||||
let current_l = wallet1.l.get();
|
||||
wallet1.l.set(current_l - 1);
|
||||
|
||||
let pay_info2 = PayInfo { info: [52u8; 32] };
|
||||
let (payment2, wallet1) = wallet1.spend(¶ms, &verification_key, &sk_user1, &pay_info2, 10, false).unwrap();
|
||||
let (payment2, wallet1) = wallet1
|
||||
.spend(¶ms, &verification_key, &sk_user1, &pay_info2, 10, false)
|
||||
.unwrap();
|
||||
|
||||
let identify_result = identify(
|
||||
¶ms,
|
||||
&verification_key,
|
||||
&pk_all_users,
|
||||
payment1,
|
||||
payment2,
|
||||
pay_info1,
|
||||
pay_info2,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let identify_result = identify(¶ms, &verification_key, &pk_all_users, payment1, payment2, pay_info1, pay_info2).unwrap();
|
||||
|
||||
assert_eq!(identify_result, IdentifyResult::DoubleSpendingPublicKeys(pk_user1));
|
||||
assert_eq!(
|
||||
identify_result,
|
||||
IdentifyResult::DoubleSpendingPublicKeys(pk_user1)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -271,31 +346,54 @@ mod tests {
|
||||
&withdrawal_req1,
|
||||
pk_user1.clone(),
|
||||
&auth_keypair.secret_key(),
|
||||
).unwrap();
|
||||
let partial_wallet1 = issue_verify(&grp, &auth_keypair.verification_key(), &sk_user1, &blind_signature, &req_info1).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
let partial_wallet1 = issue_verify(
|
||||
&grp,
|
||||
&auth_keypair.verification_key(),
|
||||
&sk_user1,
|
||||
&blind_signature,
|
||||
&req_info1,
|
||||
)
|
||||
.unwrap();
|
||||
partial_wallets1.push(partial_wallet1);
|
||||
}
|
||||
|
||||
// AGGREGATE WALLET FOR USER1
|
||||
let mut wallet1 = aggregate_wallets(&grp, &verification_key, &sk_user1, &partial_wallets1).unwrap();
|
||||
let mut wallet1 =
|
||||
aggregate_wallets(&grp, &verification_key, &sk_user1, &partial_wallets1).unwrap();
|
||||
|
||||
let pay_info1 = PayInfo { info: [67u8; 32] };
|
||||
let (payment1, new_wallet1) = wallet1.spend(¶ms, &verification_key, &sk_user1, &pay_info1, 10, false).unwrap();
|
||||
let (payment1, new_wallet1) = wallet1
|
||||
.spend(¶ms, &verification_key, &sk_user1, &pay_info1, 10, false)
|
||||
.unwrap();
|
||||
|
||||
// let's reverse the spending counter in the wallet to create a double spending payment
|
||||
let current_l = wallet1.l.get();
|
||||
wallet1.l.set(current_l - 7);
|
||||
|
||||
let pay_info2 = PayInfo { info: [52u8; 32] };
|
||||
let (payment2, wallet1) = wallet1.spend(¶ms, &verification_key, &sk_user1, &pay_info2, 10, false).unwrap();
|
||||
let (payment2, wallet1) = wallet1
|
||||
.spend(¶ms, &verification_key, &sk_user1, &pay_info2, 10, false)
|
||||
.unwrap();
|
||||
|
||||
let identify_result = identify(
|
||||
¶ms,
|
||||
&verification_key,
|
||||
&public_keys,
|
||||
payment1,
|
||||
payment2,
|
||||
pay_info1,
|
||||
pay_info2,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let identify_result = identify(¶ms, &verification_key, &public_keys, payment1, payment2, pay_info1, pay_info2).unwrap();
|
||||
|
||||
assert_eq!(identify_result, IdentifyResult::DoubleSpendingPublicKeys(pk_user1));
|
||||
assert_eq!(
|
||||
identify_result,
|
||||
IdentifyResult::DoubleSpendingPublicKeys(pk_user1)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn ok_if_two_different_payments() {
|
||||
let rng = thread_rng();
|
||||
@@ -335,19 +433,32 @@ mod tests {
|
||||
&withdrawal_req1,
|
||||
pk_user1.clone(),
|
||||
&auth_keypair.secret_key(),
|
||||
).unwrap();
|
||||
let partial_wallet1 = issue_verify(&grp, &auth_keypair.verification_key(), &sk_user1, &blind_signature, &req_info1).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
let partial_wallet1 = issue_verify(
|
||||
&grp,
|
||||
&auth_keypair.verification_key(),
|
||||
&sk_user1,
|
||||
&blind_signature,
|
||||
&req_info1,
|
||||
)
|
||||
.unwrap();
|
||||
partial_wallets1.push(partial_wallet1);
|
||||
}
|
||||
|
||||
// AGGREGATE WALLET FOR USER1
|
||||
let mut wallet1 = aggregate_wallets(&grp, &verification_key, &sk_user1, &partial_wallets1).unwrap();
|
||||
let mut wallet1 =
|
||||
aggregate_wallets(&grp, &verification_key, &sk_user1, &partial_wallets1).unwrap();
|
||||
|
||||
let pay_info1 = PayInfo { info: [67u8; 32] };
|
||||
let (payment1, wallet1) = wallet1.spend(¶ms, &verification_key, &sk_user1, &pay_info1, 10, false).unwrap();
|
||||
let (payment1, wallet1) = wallet1
|
||||
.spend(¶ms, &verification_key, &sk_user1, &pay_info1, 10, false)
|
||||
.unwrap();
|
||||
|
||||
// SPEND VERIFICATION for USER1
|
||||
assert!(payment1.spend_verify(¶ms, &verification_key, &pay_info1).unwrap());
|
||||
assert!(payment1
|
||||
.spend_verify(¶ms, &verification_key, &pay_info1)
|
||||
.unwrap());
|
||||
|
||||
// WITHDRAWAL REQUEST FOR USER2
|
||||
let (withdrawal_req2, req_info2) = withdrawal_request(¶ms, &sk_user2).unwrap();
|
||||
@@ -360,22 +471,44 @@ mod tests {
|
||||
&withdrawal_req2,
|
||||
pk_user2.clone(),
|
||||
&auth_keypair.secret_key(),
|
||||
).unwrap();
|
||||
let partial_wallet2 = issue_verify(&grp, &auth_keypair.verification_key(), &sk_user2, &blind_signature, &req_info2).unwrap();
|
||||
)
|
||||
.unwrap();
|
||||
let partial_wallet2 = issue_verify(
|
||||
&grp,
|
||||
&auth_keypair.verification_key(),
|
||||
&sk_user2,
|
||||
&blind_signature,
|
||||
&req_info2,
|
||||
)
|
||||
.unwrap();
|
||||
partial_wallets2.push(partial_wallet2);
|
||||
}
|
||||
|
||||
// AGGREGATE WALLET FOR USER2
|
||||
let mut wallet2 = aggregate_wallets(&grp, &verification_key, &sk_user2, &partial_wallets2).unwrap();
|
||||
let mut wallet2 =
|
||||
aggregate_wallets(&grp, &verification_key, &sk_user2, &partial_wallets2).unwrap();
|
||||
|
||||
let pay_info2 = PayInfo { info: [67u8; 32] };
|
||||
let (payment2, wallet2) = wallet2.spend(¶ms, &verification_key, &sk_user2, &pay_info2, 10, false).unwrap();
|
||||
let (payment2, wallet2) = wallet2
|
||||
.spend(¶ms, &verification_key, &sk_user2, &pay_info2, 10, false)
|
||||
.unwrap();
|
||||
|
||||
// SPEND VERIFICATION for USER2
|
||||
assert!(payment2.spend_verify(¶ms, &verification_key, &pay_info2).unwrap());
|
||||
assert!(payment2
|
||||
.spend_verify(¶ms, &verification_key, &pay_info2)
|
||||
.unwrap());
|
||||
|
||||
let public_keys = HashSet::from([pk_user1, pk_user2]);
|
||||
let identify_result = identify(¶ms, &verification_key, &public_keys, payment1, payment2, pay_info1, pay_info2).unwrap();
|
||||
let identify_result = identify(
|
||||
¶ms,
|
||||
&verification_key,
|
||||
&public_keys,
|
||||
payment1,
|
||||
payment2,
|
||||
pay_info1,
|
||||
pay_info2,
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(identify_result, IdentifyResult::NotADuplicatePayment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,10 @@ use group::Curve;
|
||||
use crate::error::{DivisibleEcashError, Result};
|
||||
use crate::scheme::aggregation::aggregate_verification_keys;
|
||||
use crate::scheme::setup::{GroupParameters, Parameters};
|
||||
use crate::utils::{Polynomial, SignerIndex, try_deserialize_g1_projective, try_deserialize_g2_projective, try_deserialize_scalar, try_deserialize_scalar_vec};
|
||||
use crate::utils::{
|
||||
try_deserialize_g1_projective, try_deserialize_g2_projective, try_deserialize_scalar,
|
||||
try_deserialize_scalar_vec, Polynomial, SignerIndex,
|
||||
};
|
||||
|
||||
#[derive(Eq, Debug, PartialEq, Clone)]
|
||||
pub struct SecretKeyAuth {
|
||||
@@ -236,13 +239,13 @@ impl<'a> Mul<Scalar> for &'a VerificationKeyAuth {
|
||||
}
|
||||
|
||||
impl<T> Sum<T> for VerificationKeyAuth
|
||||
where
|
||||
T: Borrow<VerificationKeyAuth>,
|
||||
where
|
||||
T: Borrow<VerificationKeyAuth>,
|
||||
{
|
||||
#[inline]
|
||||
fn sum<I>(iter: I) -> Self
|
||||
where
|
||||
I: Iterator<Item=T>,
|
||||
where
|
||||
I: Iterator<Item = T>,
|
||||
{
|
||||
let mut peekable = iter.peekable();
|
||||
let head_attributes = match peekable.peek() {
|
||||
@@ -319,7 +322,6 @@ pub struct KeyPairUser {
|
||||
public_key: PublicKeyUser,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
||||
pub struct KeyPairAuth {
|
||||
secret_key: SecretKeyAuth,
|
||||
@@ -366,11 +368,11 @@ impl KeyPairUser {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn ttp_keygen_authorities(
|
||||
params: &Parameters,
|
||||
threshold: u64,
|
||||
num_authorities: u64) -> Result<Vec<KeyPairAuth>> {
|
||||
num_authorities: u64,
|
||||
) -> Result<Vec<KeyPairAuth>> {
|
||||
if threshold == 0 {
|
||||
return Err(DivisibleEcashError::Setup(
|
||||
"Tried to generate threshold keys with a 0 threshold value".to_string(),
|
||||
@@ -422,11 +424,15 @@ pub fn ttp_keygen_authorities(
|
||||
|
||||
pub fn ttp_keygen_users(params: &Parameters) -> KeyPairUser {
|
||||
let grp = params.get_grp();
|
||||
let sk_user = SecretKeyUser { sk: grp.random_scalar() };
|
||||
let pk_user = PublicKeyUser { pk: grp.gen1() * sk_user.sk };
|
||||
let sk_user = SecretKeyUser {
|
||||
sk: grp.random_scalar(),
|
||||
};
|
||||
let pk_user = PublicKeyUser {
|
||||
pk: grp.gen1() * sk_user.sk,
|
||||
};
|
||||
|
||||
KeyPairUser {
|
||||
secret_key: sk_user,
|
||||
public_key: pk_user,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,23 +2,26 @@ use std::cell::Cell;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::ops::Neg;
|
||||
|
||||
use bls12_381::{G1Projective, G2Prepared, G2Projective, pairing, Scalar};
|
||||
use bls12_381::{pairing, G1Projective, G2Prepared, G2Projective, Scalar};
|
||||
use group::{Curve, GroupEncoding};
|
||||
|
||||
use crate::Attribute;
|
||||
use crate::constants::L;
|
||||
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, try_deserialize_g1_projective, try_deserialize_scalar, try_deserialize_g2_projective};
|
||||
use crate::utils::{
|
||||
check_bilinear_pairing, hash_to_scalar, try_deserialize_g1_projective,
|
||||
try_deserialize_g2_projective, try_deserialize_scalar, Signature, SignerIndex,
|
||||
};
|
||||
use crate::Attribute;
|
||||
|
||||
pub mod aggregation;
|
||||
pub mod identification;
|
||||
pub mod keygen;
|
||||
pub mod setup;
|
||||
pub mod structure_preserving_signature;
|
||||
pub mod withdrawal;
|
||||
pub mod identification;
|
||||
|
||||
pub fn compute_kappa(
|
||||
params: &GroupParameters,
|
||||
@@ -29,10 +32,10 @@ pub fn compute_kappa(
|
||||
params.gen2() * blinding_factor
|
||||
+ verification_key.alpha
|
||||
+ attributes
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(priv_attr, beta_i)| beta_i * priv_attr)
|
||||
.sum::<G2Projective>()
|
||||
.iter()
|
||||
.zip(verification_key.beta_g2.iter())
|
||||
.map(|(priv_attr, beta_i)| beta_i * priv_attr)
|
||||
.sum::<G2Projective>()
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug, Clone, Copy)]
|
||||
@@ -60,13 +63,17 @@ impl Phi {
|
||||
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()),
|
||||
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()),
|
||||
DivisibleEcashError::Deserialization(
|
||||
"Failed to deserialize element 1 of Phi".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
Ok(Phi(elem_0, elem_1))
|
||||
@@ -98,13 +105,17 @@ impl VarPhi {
|
||||
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()),
|
||||
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()),
|
||||
DivisibleEcashError::Deserialization(
|
||||
"Failed to deserialize element 1 of VarPhi".to_string(),
|
||||
),
|
||||
)?;
|
||||
|
||||
Ok(VarPhi(elem_0, elem_1))
|
||||
@@ -135,21 +146,49 @@ pub struct Payment {
|
||||
}
|
||||
|
||||
impl Payment {
|
||||
pub fn get_kappa(&self) -> G2Projective { self.kappa }
|
||||
pub fn get_sig(&self) -> Signature { self.sig }
|
||||
pub fn get_phi(&self) -> Phi { self.phi }
|
||||
pub fn get_varphi(&self) -> VarPhi { self.varphi }
|
||||
pub fn get_varsig_prime1(&self) -> G1Projective { self.varsig_prime1 }
|
||||
pub fn get_varsig_prime2(&self) -> G1Projective { self.varsig_prime2 }
|
||||
pub fn get_theta_prime1(&self) -> G1Projective { self.theta_prime1 }
|
||||
pub fn get_theta_prime2(&self) -> G1Projective { self.theta_prime2 }
|
||||
pub fn get_rr_prime(&self) -> G1Projective { self.rr_prime }
|
||||
pub fn get_ss_prime(&self) -> G1Projective { self.ss_prime }
|
||||
pub fn get_tt_prime(&self) -> G2Projective { self.tt_prime }
|
||||
pub fn get_rr(&self) -> Scalar { self.rr }
|
||||
pub fn get_zk_proof(&self) -> SpendProof { self.zk_proof.clone() }
|
||||
pub fn get_vv(&self) -> u64 { self.vv }
|
||||
pub fn to_bytes(&self) -> Vec<u8>{
|
||||
pub fn get_kappa(&self) -> G2Projective {
|
||||
self.kappa
|
||||
}
|
||||
pub fn get_sig(&self) -> Signature {
|
||||
self.sig
|
||||
}
|
||||
pub fn get_phi(&self) -> Phi {
|
||||
self.phi
|
||||
}
|
||||
pub fn get_varphi(&self) -> VarPhi {
|
||||
self.varphi
|
||||
}
|
||||
pub fn get_varsig_prime1(&self) -> G1Projective {
|
||||
self.varsig_prime1
|
||||
}
|
||||
pub fn get_varsig_prime2(&self) -> G1Projective {
|
||||
self.varsig_prime2
|
||||
}
|
||||
pub fn get_theta_prime1(&self) -> G1Projective {
|
||||
self.theta_prime1
|
||||
}
|
||||
pub fn get_theta_prime2(&self) -> G1Projective {
|
||||
self.theta_prime2
|
||||
}
|
||||
pub fn get_rr_prime(&self) -> G1Projective {
|
||||
self.rr_prime
|
||||
}
|
||||
pub fn get_ss_prime(&self) -> G1Projective {
|
||||
self.ss_prime
|
||||
}
|
||||
pub fn get_tt_prime(&self) -> G2Projective {
|
||||
self.tt_prime
|
||||
}
|
||||
pub fn get_rr(&self) -> Scalar {
|
||||
self.rr
|
||||
}
|
||||
pub fn get_zk_proof(&self) -> SpendProof {
|
||||
self.zk_proof.clone()
|
||||
}
|
||||
pub fn get_vv(&self) -> u64 {
|
||||
self.vv
|
||||
}
|
||||
pub fn to_bytes(&self) -> Vec<u8> {
|
||||
let kappa_bytes = self.kappa.to_affine().to_compressed();
|
||||
let sig_bytes = self.sig.to_bytes();
|
||||
let phi_bytes = self.phi.to_bytes();
|
||||
@@ -189,96 +228,96 @@ impl TryFrom<&[u8]> for Payment {
|
||||
type Error = DivisibleEcashError;
|
||||
|
||||
fn try_from(bytes: &[u8]) -> Result<Self> {
|
||||
if bytes.len() < 760 {
|
||||
if bytes.len() < 760 {
|
||||
return Err(DivisibleEcashError::Deserialization(
|
||||
"Invalid byte array for Payment deserialization".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
let mut idx = 0;
|
||||
let kappa_bytes: [u8; 96] = bytes[idx..idx+96].try_into().unwrap();
|
||||
let kappa_bytes: [u8; 96] = bytes[idx..idx + 96].try_into().unwrap();
|
||||
let kappa = try_deserialize_g2_projective(
|
||||
&kappa_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize kappa".to_string()),
|
||||
)?;
|
||||
idx += 96;
|
||||
|
||||
let sig_bytes: [u8; 96] = bytes[idx..idx+96].try_into().unwrap();
|
||||
let sig_bytes: [u8; 96] = bytes[idx..idx + 96].try_into().unwrap();
|
||||
let sig = Signature::try_from(sig_bytes.as_slice())?;
|
||||
idx += 96;
|
||||
|
||||
let phi_bytes: [u8; 96] = bytes[idx..idx+96].try_into().unwrap();
|
||||
let phi_bytes: [u8; 96] = bytes[idx..idx + 96].try_into().unwrap();
|
||||
let phi = Phi::from_bytes(&phi_bytes).unwrap();
|
||||
idx += 96;
|
||||
|
||||
let varphi_bytes: [u8; 96] = bytes[idx..idx+96].try_into().unwrap();
|
||||
let varphi_bytes: [u8; 96] = bytes[idx..idx + 96].try_into().unwrap();
|
||||
let varphi = VarPhi::from_bytes(&varphi_bytes).unwrap();
|
||||
idx += 96;
|
||||
|
||||
let varsig_prime1_bytes: [u8; 48] = bytes[idx..idx+48].try_into().unwrap();
|
||||
let varsig_prime1_bytes: [u8; 48] = bytes[idx..idx + 48].try_into().unwrap();
|
||||
let varsig_prime1 = try_deserialize_g1_projective(
|
||||
&varsig_prime1_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize varsig_prime1".to_string()),
|
||||
)?;
|
||||
idx += 48;
|
||||
|
||||
let varsig_prime2_bytes: [u8; 48] = bytes[idx..idx+48].try_into().unwrap();
|
||||
let varsig_prime2_bytes: [u8; 48] = bytes[idx..idx + 48].try_into().unwrap();
|
||||
let varsig_prime2 = try_deserialize_g1_projective(
|
||||
&varsig_prime2_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize varsig_prime2".to_string()),
|
||||
)?;
|
||||
idx += 48;
|
||||
|
||||
let theta_prime1_bytes: [u8; 48] = bytes[idx..idx+48].try_into().unwrap();
|
||||
let theta_prime1_bytes: [u8; 48] = bytes[idx..idx + 48].try_into().unwrap();
|
||||
let theta_prime1 = try_deserialize_g1_projective(
|
||||
&theta_prime1_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize theta_prime1".to_string()),
|
||||
)?;
|
||||
idx += 48;
|
||||
|
||||
let theta_prime2_bytes: [u8; 48] = bytes[idx..idx+48].try_into().unwrap();
|
||||
let theta_prime2_bytes: [u8; 48] = bytes[idx..idx + 48].try_into().unwrap();
|
||||
let theta_prime2 = try_deserialize_g1_projective(
|
||||
&theta_prime2_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize theta_prime2".to_string()),
|
||||
)?;
|
||||
idx += 48;
|
||||
|
||||
let rr_prime_bytes: [u8; 48] = bytes[idx..idx+48].try_into().unwrap();
|
||||
let rr_prime_bytes: [u8; 48] = bytes[idx..idx + 48].try_into().unwrap();
|
||||
let rr_prime = try_deserialize_g1_projective(
|
||||
&rr_prime_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize rr_prime".to_string()),
|
||||
)?;
|
||||
idx += 48;
|
||||
|
||||
let ss_prime_bytes: [u8; 48] = bytes[idx..idx+48].try_into().unwrap();
|
||||
let ss_prime_bytes: [u8; 48] = bytes[idx..idx + 48].try_into().unwrap();
|
||||
let ss_prime = try_deserialize_g1_projective(
|
||||
&ss_prime_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize ss_prime".to_string()),
|
||||
)?;
|
||||
idx += 48;
|
||||
|
||||
let tt_prime_bytes: [u8; 96] = bytes[idx..idx+96].try_into().unwrap();
|
||||
let tt_prime_bytes: [u8; 96] = bytes[idx..idx + 96].try_into().unwrap();
|
||||
let tt_prime = try_deserialize_g2_projective(
|
||||
&tt_prime_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize tt_prime".to_string()),
|
||||
)?;
|
||||
idx += 96;
|
||||
|
||||
let rr_bytes: [u8; 32] = bytes[idx..idx+32].try_into().unwrap();
|
||||
let rr_bytes: [u8; 32] = bytes[idx..idx + 32].try_into().unwrap();
|
||||
let rr = try_deserialize_scalar(
|
||||
&rr_bytes,
|
||||
DivisibleEcashError::Deserialization("Failed to deserialize rr element".to_string()),
|
||||
)?;
|
||||
idx += 32;
|
||||
|
||||
let vv = u64::from_le_bytes(bytes[idx..idx+8].try_into().unwrap());
|
||||
let vv = u64::from_le_bytes(bytes[idx..idx + 8].try_into().unwrap());
|
||||
idx += 8;
|
||||
|
||||
// Deserialize the SpendProof struct
|
||||
let zk_proof_bytes = &bytes[idx..];
|
||||
let zk_proof = SpendProof::try_from(zk_proof_bytes)?;
|
||||
|
||||
Ok(Payment{
|
||||
Ok(Payment {
|
||||
kappa,
|
||||
sig,
|
||||
phi,
|
||||
@@ -334,7 +373,6 @@ impl Wallet {
|
||||
self.l.get()
|
||||
}
|
||||
|
||||
|
||||
pub fn spend(
|
||||
&self,
|
||||
params: &Parameters,
|
||||
@@ -358,21 +396,24 @@ impl Wallet {
|
||||
// construct kappa i.e., blinded attributes for show
|
||||
let attributes = vec![sk_user.sk, self.v()];
|
||||
// compute kappa
|
||||
let kappa = compute_kappa(
|
||||
&grp,
|
||||
&verification_key,
|
||||
&attributes,
|
||||
sign_blinding_factor,
|
||||
);
|
||||
let kappa = compute_kappa(&grp, &verification_key, &attributes, sign_blinding_factor);
|
||||
|
||||
let r1 = grp.random_scalar();
|
||||
let r2 = grp.random_scalar();
|
||||
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);
|
||||
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() 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();
|
||||
@@ -388,8 +429,10 @@ impl Wallet {
|
||||
let psi_g2 = params_u.get_psi_g2();
|
||||
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_theta(self.l() as usize + vv as usize - 1) + (psi_g1 * r_theta2);
|
||||
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_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);
|
||||
@@ -400,11 +443,20 @@ impl Wallet {
|
||||
let rho2 = self.v.neg() * r_theta1;
|
||||
let rho3 = r_rr * r_tt;
|
||||
|
||||
let pg_varsigpr1_delta = pairing(&varsig_prime1.to_affine(), ¶ms_a.get_ith_delta((vv - 1) as usize).to_affine());
|
||||
let pg_psi0_delta = pairing(&psi_g1.to_affine(), ¶ms_a.get_ith_delta((vv - 1) as usize).to_affine());
|
||||
let pg_varsigpr1_delta = pairing(
|
||||
&varsig_prime1.to_affine(),
|
||||
¶ms_a.get_ith_delta((vv - 1) as usize).to_affine(),
|
||||
);
|
||||
let pg_psi0_delta = pairing(
|
||||
&psi_g1.to_affine(),
|
||||
¶ms_a.get_ith_delta((vv - 1) as usize).to_affine(),
|
||||
);
|
||||
let pg_varsigpr2_gen2 = pairing(&varsig_prime2.to_affine(), grp.gen2());
|
||||
let pg_psi0_gen2 = pairing(&psi_g1.to_affine(), grp.gen2());
|
||||
let pg_thetapr1_delta = pairing(&theta_prime1.to_affine(), ¶ms_a.get_ith_delta((vv - 1) as usize).to_affine());
|
||||
let pg_thetapr1_delta = pairing(
|
||||
&theta_prime1.to_affine(),
|
||||
¶ms_a.get_ith_delta((vv - 1) as usize).to_affine(),
|
||||
);
|
||||
let pg_thetapr2_gen2 = pairing(&theta_prime2.to_affine(), grp.gen2());
|
||||
let yy = params_u.get_sps_pk().get_yy();
|
||||
let pg_rrprime_yy = pairing(&rr_prime.to_affine(), &yy.to_affine());
|
||||
@@ -425,7 +477,8 @@ impl Wallet {
|
||||
|
||||
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_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 {
|
||||
@@ -511,7 +564,8 @@ impl Payment {
|
||||
&self,
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKeyAuth,
|
||||
pay_info: &PayInfo) -> Result<bool> {
|
||||
pay_info: &PayInfo,
|
||||
) -> Result<bool> {
|
||||
if bool::from(self.sig.0.is_identity()) {
|
||||
return Err(DivisibleEcashError::Spend(
|
||||
"The element h of the signature equals the identity".to_string(),
|
||||
@@ -549,11 +603,20 @@ impl Payment {
|
||||
|
||||
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_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_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());
|
||||
@@ -574,7 +637,8 @@ impl Payment {
|
||||
|
||||
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_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 {
|
||||
@@ -603,7 +667,9 @@ impl Payment {
|
||||
pg_psi0_psi1,
|
||||
};
|
||||
|
||||
Ok(self.zk_proof.verify(¶ms, &instance, &verification_key, self.vv))
|
||||
Ok(self
|
||||
.zk_proof
|
||||
.verify(¶ms, &instance, &verification_key, self.vv))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -613,10 +679,10 @@ mod tests {
|
||||
|
||||
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::keygen::{ttp_keygen_authorities, PublicKeyUser, VerificationKeyAuth};
|
||||
use crate::scheme::setup::{GroupParameters, Parameters};
|
||||
use crate::scheme::{PayInfo, Phi, VarPhi, Wallet};
|
||||
use crate::utils::hash_g1;
|
||||
|
||||
#[test]
|
||||
@@ -629,7 +695,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn varphi_to_and_from_bytes() {
|
||||
let varphi = VarPhi(hash_g1("Element 0 of VarPhi"), hash_g1("Element 1 of VarPhi"));
|
||||
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);
|
||||
@@ -657,4 +726,4 @@ mod tests {
|
||||
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::{pairing, G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, Scalar};
|
||||
use ff::Field;
|
||||
use group::Curve;
|
||||
use rand::thread_rng;
|
||||
@@ -21,7 +21,6 @@ pub struct GroupParameters {
|
||||
_g2_prepared_miller: G2Prepared,
|
||||
}
|
||||
|
||||
|
||||
impl GroupParameters {
|
||||
pub fn new() -> Result<GroupParameters> {
|
||||
Ok(GroupParameters {
|
||||
@@ -64,11 +63,17 @@ pub struct Parameters {
|
||||
}
|
||||
|
||||
impl Parameters {
|
||||
pub(crate) fn get_grp(&self) -> &GroupParameters { &self.grp }
|
||||
pub(crate) fn get_grp(&self) -> &GroupParameters {
|
||||
&self.grp
|
||||
}
|
||||
|
||||
pub(crate) fn get_params_u(&self) -> &ParametersUser { &self.params_u }
|
||||
pub(crate) fn get_params_u(&self) -> &ParametersUser {
|
||||
&self.params_u
|
||||
}
|
||||
|
||||
pub(crate) fn get_params_a(&self) -> &ParametersAuthority { &self.params_a }
|
||||
pub(crate) fn get_params_a(&self) -> &ParametersAuthority {
|
||||
&self.params_a
|
||||
}
|
||||
|
||||
pub fn new(grp: GroupParameters) -> Parameters {
|
||||
let g1 = grp.gen1();
|
||||
@@ -116,10 +121,13 @@ impl Parameters {
|
||||
let sps_signatures: Vec<SPSSignature> = sigmas_u
|
||||
.iter()
|
||||
.zip(thetas_u.iter())
|
||||
.map(|(sigma, theta)| sps_keypair.sps_sk.sign(&grp, Some(&vec![*sigma, *theta]), None))
|
||||
.map(|(sigma, theta)| {
|
||||
sps_keypair
|
||||
.sps_sk
|
||||
.sign(&grp, Some(&vec![*sigma, *theta]), None)
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
// Compute signature for each pair sigma, theta
|
||||
let params_u = ParametersUser {
|
||||
gammas: vec![gamma1, gamma2],
|
||||
@@ -149,7 +157,9 @@ impl Parameters {
|
||||
}
|
||||
|
||||
impl Parameters {
|
||||
pub(crate) fn get_sigma(&self) -> &G1Projective { &self.tmp_sigma }
|
||||
pub(crate) fn get_sigma(&self) -> &G1Projective {
|
||||
&self.tmp_sigma
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -166,31 +176,57 @@ pub struct ParametersUser {
|
||||
}
|
||||
|
||||
impl ParametersUser {
|
||||
pub(crate) fn get_gammas(&self) -> &Vec<G1Projective> { &self.gammas }
|
||||
pub(crate) fn get_gammas(&self) -> &Vec<G1Projective> {
|
||||
&self.gammas
|
||||
}
|
||||
|
||||
pub(crate) fn get_psi_g1(&self) -> &G1Projective { &self.psi_g1 }
|
||||
pub(crate) fn get_psi_g1(&self) -> &G1Projective {
|
||||
&self.psi_g1
|
||||
}
|
||||
|
||||
pub(crate) fn get_psi_g2(&self) -> &G2Projective { &self.psi_g2 }
|
||||
pub(crate) fn get_psi_g2(&self) -> &G2Projective {
|
||||
&self.psi_g2
|
||||
}
|
||||
|
||||
pub(crate) fn get_eta(&self) -> &G1Projective { &self.eta }
|
||||
pub(crate) fn get_eta(&self) -> &G1Projective {
|
||||
&self.eta
|
||||
}
|
||||
|
||||
pub(crate) fn get_etas(&self) -> &[G1Projective] { &self.etas }
|
||||
pub(crate) fn get_etas(&self) -> &[G1Projective] {
|
||||
&self.etas
|
||||
}
|
||||
|
||||
pub(crate) fn get_ith_eta(&self, idx: usize) -> &G1Projective { self.etas.get(idx - 1).unwrap() }
|
||||
pub(crate) fn get_ith_eta(&self, idx: usize) -> &G1Projective {
|
||||
self.etas.get(idx - 1).unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn get_sigmas(&self) -> &[G1Projective] { &self.sigmas }
|
||||
pub(crate) fn get_sigmas(&self) -> &[G1Projective] {
|
||||
&self.sigmas
|
||||
}
|
||||
|
||||
pub(crate) fn get_ith_sigma(&self, idx: usize) -> &G1Projective { self.sigmas.get(idx - 1).unwrap() }
|
||||
pub(crate) fn get_ith_sigma(&self, idx: usize) -> &G1Projective {
|
||||
self.sigmas.get(idx - 1).unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn get_thetas(&self) -> &[G1Projective] { &self.thetas }
|
||||
pub(crate) fn get_thetas(&self) -> &[G1Projective] {
|
||||
&self.thetas
|
||||
}
|
||||
|
||||
pub(crate) fn get_ith_theta(&self, idx: usize) -> &G1Projective { self.thetas.get(idx - 1).unwrap() }
|
||||
pub(crate) fn get_ith_theta(&self, idx: usize) -> &G1Projective {
|
||||
self.thetas.get(idx - 1).unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn get_sps_signs(&self) -> &[SPSSignature] { &self.sps_signatures }
|
||||
pub(crate) fn get_sps_signs(&self) -> &[SPSSignature] {
|
||||
&self.sps_signatures
|
||||
}
|
||||
|
||||
pub(crate) fn get_ith_sps_sign(&self, idx: usize) -> &SPSSignature { &self.sps_signatures.get(idx - 1).unwrap() }
|
||||
pub(crate) fn get_ith_sps_sign(&self, idx: usize) -> &SPSSignature {
|
||||
&self.sps_signatures.get(idx - 1).unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn get_sps_pk(&self) -> &SPSVerificationKey { &self.sps_pk }
|
||||
pub(crate) fn get_sps_pk(&self) -> &SPSVerificationKey {
|
||||
&self.sps_pk
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -200,13 +236,23 @@ pub struct ParametersAuthority {
|
||||
}
|
||||
|
||||
impl ParametersAuthority {
|
||||
pub(crate) fn get_deltas(&self) -> &[G2Projective] { &self.deltas }
|
||||
pub(crate) fn get_deltas(&self) -> &[G2Projective] {
|
||||
&self.deltas
|
||||
}
|
||||
|
||||
pub(crate) fn get_ith_delta(&self, idx: usize) -> &G2Projective { self.deltas.get(idx).unwrap() }
|
||||
pub(crate) fn get_ith_delta(&self, idx: usize) -> &G2Projective {
|
||||
self.deltas.get(idx).unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn get_etas(&self) -> &Vec<Vec<G2Projective>> { &self.etas }
|
||||
pub(crate) fn get_etas(&self) -> &Vec<Vec<G2Projective>> {
|
||||
&self.etas
|
||||
}
|
||||
|
||||
pub(crate) fn get_eta_ith_row(&self, idx: usize) -> &[G2Projective] { self.etas.get(idx).unwrap() }
|
||||
pub(crate) fn get_eta_ith_row(&self, idx: usize) -> &[G2Projective] {
|
||||
self.etas.get(idx).unwrap()
|
||||
}
|
||||
|
||||
pub(crate) fn get_etas_ith_jth_elem(&self, row: usize, column: usize) -> &G2Projective { self.etas.get(row - 1).unwrap().get(column).unwrap() }
|
||||
pub(crate) fn get_etas_ith_jth_elem(&self, row: usize, column: usize) -> &G2Projective {
|
||||
self.etas.get(row - 1).unwrap().get(column).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::fmt::Debug;
|
||||
use std::ops::Neg;
|
||||
|
||||
use bls12_381::{G1Projective, G2Projective, Gt, pairing, Scalar};
|
||||
use bls12_381::{pairing, G1Projective, G2Projective, Gt, Scalar};
|
||||
use group::Curve;
|
||||
|
||||
use crate::scheme::setup::GroupParameters;
|
||||
@@ -32,7 +32,12 @@ impl SPSSecretKey {
|
||||
self.y
|
||||
}
|
||||
|
||||
pub fn sign(&self, grp: &GroupParameters, messages_a: Option<&[G1Projective]>, messages_b: Option<&[G2Projective]>) -> SPSSignature {
|
||||
pub fn sign(
|
||||
&self,
|
||||
grp: &GroupParameters,
|
||||
messages_a: Option<&[G1Projective]>,
|
||||
messages_b: Option<&[G2Projective]>,
|
||||
) -> SPSSignature {
|
||||
let r = grp.random_scalar();
|
||||
let rr = grp.gen1() * r;
|
||||
let ss: G1Projective = match messages_a {
|
||||
@@ -42,9 +47,12 @@ impl SPSSecretKey {
|
||||
.zip(self.ws.iter())
|
||||
.map(|(m_i, w_i)| m_i * w_i.neg())
|
||||
.collect();
|
||||
grp.gen1() * (self.z() - r * self.y()) + prod_s.iter().fold(G1Projective::identity(), |acc, elem| acc + elem)
|
||||
grp.gen1() * (self.z() - r * self.y())
|
||||
+ prod_s
|
||||
.iter()
|
||||
.fold(G1Projective::identity(), |acc, elem| acc + elem)
|
||||
}
|
||||
None => grp.gen1() * (self.z() - r * self.y())
|
||||
None => grp.gen1() * (self.z() - r * self.y()),
|
||||
};
|
||||
let tt = match messages_b {
|
||||
Some(msgs_b) => {
|
||||
@@ -53,26 +61,32 @@ impl SPSSecretKey {
|
||||
.zip(self.us.iter())
|
||||
.map(|(m_i, u_i)| m_i * u_i.neg())
|
||||
.collect();
|
||||
(grp.gen2() + prod_t.iter().fold(G2Projective::identity(), |acc, elem| acc + elem)) * r.invert().unwrap()
|
||||
(grp.gen2()
|
||||
+ prod_t
|
||||
.iter()
|
||||
.fold(G2Projective::identity(), |acc, elem| acc + elem))
|
||||
* r.invert().unwrap()
|
||||
}
|
||||
None => grp.gen2() * r.invert().unwrap()
|
||||
None => grp.gen2() * r.invert().unwrap(),
|
||||
};
|
||||
|
||||
SPSSignature
|
||||
{
|
||||
rr,
|
||||
ss,
|
||||
tt,
|
||||
}
|
||||
SPSSignature { rr, ss, tt }
|
||||
}
|
||||
}
|
||||
|
||||
impl SPSVerificationKey {
|
||||
pub fn verify(&self, grp: &GroupParameters, signature: SPSSignature, messages_a: &[G1Projective], messages_b: Option<&[G2Projective]>) -> bool {
|
||||
pub fn verify(
|
||||
&self,
|
||||
grp: &GroupParameters,
|
||||
signature: SPSSignature,
|
||||
messages_a: &[G1Projective],
|
||||
messages_b: Option<&[G2Projective]>,
|
||||
) -> bool {
|
||||
let pg_rr_yy = pairing(&signature.rr.to_affine(), &self.yy.to_affine());
|
||||
let pg_ss_g2 = pairing(&signature.ss.to_affine(), grp.gen2());
|
||||
let pg_g1_zz = pairing(grp.gen1(), &self.zz.to_affine());
|
||||
let pg_ma_ww: Vec<Gt> = messages_a.iter()
|
||||
let pg_ma_ww: Vec<Gt> = messages_a
|
||||
.iter()
|
||||
.zip(self.wws.iter())
|
||||
.map(|(ma, ww)| pairing(&ma.to_affine(), &ww.to_affine()))
|
||||
.collect();
|
||||
@@ -90,7 +104,9 @@ impl SPSVerificationKey {
|
||||
Some(msgs_b) => {
|
||||
let pg_rr_tt = pairing(&signature.rr.to_affine(), &signature.tt.to_affine());
|
||||
let pg_g1_g2 = pairing(grp.gen1(), grp.gen2());
|
||||
let pg_uu_mb: Vec<Gt> = self.uus.iter()
|
||||
let pg_uu_mb: Vec<Gt> = self
|
||||
.uus
|
||||
.iter()
|
||||
.zip(msgs_b.iter())
|
||||
.map(|(uu, mb)| pairing(&uu.to_affine(), &mb.to_affine()))
|
||||
.collect();
|
||||
@@ -110,7 +126,8 @@ impl SPSVerificationKey {
|
||||
None => {
|
||||
let pg_sign_rr_yy = pairing(&signature.rr.to_affine(), &self.yy.to_affine());
|
||||
let pg_sign_ss_gen2 = pairing(&signature.ss.to_affine(), &grp.gen2());
|
||||
let pg_ma_wws: Vec<Gt> = messages_a.iter()
|
||||
let pg_ma_wws: Vec<Gt> = messages_a
|
||||
.iter()
|
||||
.zip(self.wws.iter())
|
||||
.map(|(ma, ww)| pairing(&ma.to_affine(), &ww.to_affine()))
|
||||
.collect();
|
||||
@@ -128,7 +145,9 @@ impl SPSVerificationKey {
|
||||
assert_eq!(pg_sign_rr_yy + pg_sign_ss_gen2 + prod_pg_ma_wws, pg_gen1_zz);
|
||||
assert_eq!(pg_rr_tt, pg_gen1_gen2);
|
||||
|
||||
if pg_sign_rr_yy + pg_sign_ss_gen2 + prod_pg_ma_wws == pg_gen1_zz && pg_rr_tt == pg_gen1_gen2 {
|
||||
if pg_sign_rr_yy + pg_sign_ss_gen2 + prod_pg_ma_wws == pg_gen1_zz
|
||||
&& pg_rr_tt == pg_gen1_gen2
|
||||
{
|
||||
true
|
||||
} else {
|
||||
false
|
||||
@@ -139,11 +158,17 @@ impl SPSVerificationKey {
|
||||
return result;
|
||||
}
|
||||
|
||||
pub fn get_ith_ww(&self, idx: usize) -> &G2Projective { return self.wws.get(idx).unwrap(); }
|
||||
pub fn get_ith_ww(&self, idx: usize) -> &G2Projective {
|
||||
return self.wws.get(idx).unwrap();
|
||||
}
|
||||
|
||||
pub fn get_zz(&self) -> &G2Projective { return &self.zz; }
|
||||
pub fn get_zz(&self) -> &G2Projective {
|
||||
return &self.zz;
|
||||
}
|
||||
|
||||
pub fn get_yy(&self) -> &G2Projective { return &self.yy; }
|
||||
pub fn get_yy(&self) -> &G2Projective {
|
||||
return &self.yy;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SPSKeyPair {
|
||||
@@ -187,7 +212,6 @@ pub struct SPSSignature {
|
||||
pub tt: G2Projective,
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand::thread_rng;
|
||||
@@ -204,7 +228,9 @@ mod tests {
|
||||
let msgs_a = vec![hash_g1("messageA1"), hash_g1("messageA2")];
|
||||
let msgs_b = vec![hash_g2("messageB1"), hash_g2("messageB2")];
|
||||
let signature = sps_keypair.sps_sk.sign(&grp, Some(&msgs_a), Some(&msgs_b));
|
||||
assert!(sps_keypair.sps_vk.verify(&grp, signature, &msgs_a, Some(&msgs_b)));
|
||||
assert!(sps_keypair
|
||||
.sps_vk
|
||||
.verify(&grp, signature, &msgs_a, Some(&msgs_b)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -216,4 +242,4 @@ mod tests {
|
||||
let signature = sps_keypair.sps_sk.sign(&grp, Some(&msgs_a), None);
|
||||
assert!(sps_keypair.sps_vk.verify(&grp, signature, &msgs_a, None));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@ use bls12_381::{G1Projective, G2Prepared, G2Projective, Scalar};
|
||||
use group::{Curve, GroupEncoding};
|
||||
|
||||
use crate::error::{DivisibleEcashError, Result};
|
||||
use crate::proofs::proof_withdrawal::{WithdrawalReqInstance, WithdrawalReqProof, WithdrawalReqWitness};
|
||||
use crate::proofs::proof_withdrawal::{
|
||||
WithdrawalReqInstance, WithdrawalReqProof, WithdrawalReqWitness,
|
||||
};
|
||||
use crate::scheme::keygen::{PublicKeyUser, SecretKeyAuth, SecretKeyUser, VerificationKeyAuth};
|
||||
use crate::scheme::PartialWallet;
|
||||
use crate::scheme::setup::{GroupParameters, Parameters};
|
||||
use crate::utils::{BlindedSignature, check_bilinear_pairing, hash_g1, Signature};
|
||||
use crate::scheme::PartialWallet;
|
||||
use crate::utils::{check_bilinear_pairing, hash_g1, BlindedSignature, Signature};
|
||||
|
||||
pub struct WithdrawalRequest {
|
||||
com_hash: G1Projective,
|
||||
@@ -21,7 +23,10 @@ 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();
|
||||
@@ -30,10 +35,10 @@ pub fn withdrawal_request(params: &Parameters, sk_user: &SecretKeyUser) -> Resul
|
||||
let com_opening = grp.random_scalar();
|
||||
let commitment = g1 * com_opening
|
||||
+ attributes
|
||||
.iter()
|
||||
.zip(params_u.get_gammas())
|
||||
.map(|(&m, gamma)| gamma * m)
|
||||
.sum::<G1Projective>();
|
||||
.iter()
|
||||
.zip(params_u.get_gammas())
|
||||
.map(|(&m, gamma)| gamma * m)
|
||||
.sum::<G1Projective>();
|
||||
|
||||
// Value h in the paper
|
||||
let com_hash = hash_g1(commitment.to_bytes());
|
||||
@@ -45,7 +50,6 @@ pub fn withdrawal_request(params: &Parameters, sk_user: &SecretKeyUser) -> Resul
|
||||
.map(|(o_j, m_j)| g1 * o_j + com_hash * m_j)
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
|
||||
// construct a zk proof of knowledge proving possession of m1, m2, o, o1, o2
|
||||
let instance = WithdrawalReqInstance {
|
||||
com: commitment,
|
||||
@@ -78,7 +82,12 @@ pub fn withdrawal_request(params: &Parameters, sk_user: &SecretKeyUser) -> Resul
|
||||
Ok((req, req_info))
|
||||
}
|
||||
|
||||
pub fn issue(params: &Parameters, req: &WithdrawalRequest, pk_u: PublicKeyUser, sk_a: &SecretKeyAuth) -> Result<BlindedSignature> {
|
||||
pub 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(
|
||||
@@ -115,8 +124,8 @@ pub fn issue_verify(
|
||||
vk_auth: &VerificationKeyAuth,
|
||||
sk_user: &SecretKeyUser,
|
||||
blind_signature: &BlindedSignature,
|
||||
req_info: &RequestInfo) -> Result<PartialWallet> {
|
||||
|
||||
req_info: &RequestInfo,
|
||||
) -> Result<PartialWallet> {
|
||||
// Parse the blinded signature
|
||||
let h = blind_signature.0;
|
||||
let c = blind_signature.1;
|
||||
@@ -163,4 +172,4 @@ pub fn issue_verify(
|
||||
v: req_info.v,
|
||||
idx: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
use rand::thread_rng;
|
||||
|
||||
use crate::error::DivisibleEcashError;
|
||||
use crate::scheme::{PayInfo, Payment};
|
||||
use crate::scheme::aggregation::{aggregate_signatures, aggregate_verification_keys, aggregate_wallets};
|
||||
use crate::scheme::aggregation::{
|
||||
aggregate_signatures, aggregate_verification_keys, aggregate_wallets,
|
||||
};
|
||||
use crate::scheme::identification::identify;
|
||||
use crate::scheme::keygen::{PublicKeyUser, SecretKeyUser, ttp_keygen_authorities, VerificationKeyAuth};
|
||||
use crate::scheme::keygen::{
|
||||
ttp_keygen_authorities, PublicKeyUser, SecretKeyUser, VerificationKeyAuth,
|
||||
};
|
||||
use crate::scheme::setup::{GroupParameters, Parameters};
|
||||
use crate::scheme::withdrawal::{issue, issue_verify, withdrawal_request};
|
||||
use crate::scheme::{PayInfo, Payment};
|
||||
|
||||
#[test]
|
||||
// Test wa full end to end flow of withdrawal request, issuance,
|
||||
@@ -43,7 +47,13 @@ fn main() -> Result<(), DivisibleEcashError> {
|
||||
pk_user.clone(),
|
||||
&auth_keypair.secret_key(),
|
||||
)?;
|
||||
let partial_wallet = issue_verify(&grp, &auth_keypair.verification_key(), &sk_user, &blind_signature, &req_info)?;
|
||||
let partial_wallet = issue_verify(
|
||||
&grp,
|
||||
&auth_keypair.verification_key(),
|
||||
&sk_user,
|
||||
&blind_signature,
|
||||
&req_info,
|
||||
)?;
|
||||
partial_wallets.push(partial_wallet);
|
||||
}
|
||||
|
||||
@@ -51,10 +61,13 @@ fn main() -> Result<(), DivisibleEcashError> {
|
||||
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, false)?;
|
||||
let (payment, wallet) =
|
||||
wallet.spend(¶ms, &verification_key, &sk_user, &pay_info, 10, false)?;
|
||||
|
||||
// SPEND VERIFICATION
|
||||
assert!(payment.spend_verify(¶ms, &verification_key, &pay_info).unwrap());
|
||||
// SPEND VERIFICATION
|
||||
assert!(payment
|
||||
.spend_verify(¶ms, &verification_key, &pay_info)
|
||||
.unwrap());
|
||||
let payment_bytes = payment.to_bytes();
|
||||
let payment2 = Payment::try_from(&payment_bytes[..]).unwrap();
|
||||
assert_eq!(payment, payment2);
|
||||
|
||||
@@ -6,10 +6,10 @@ use core::ops::Mul;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::ops::Neg;
|
||||
|
||||
use bls12_381::{
|
||||
G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, multi_miller_loop, Scalar,
|
||||
};
|
||||
use bls12_381::hash_to_curve::{ExpandMsgXmd, HashToCurve, HashToField};
|
||||
use bls12_381::{
|
||||
multi_miller_loop, G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, Scalar,
|
||||
};
|
||||
use ff::Field;
|
||||
use group::{Curve, Group};
|
||||
|
||||
@@ -85,9 +85,9 @@ pub(crate) fn perform_lagrangian_interpolation_at_origin<T>(
|
||||
points: &[SignerIndex],
|
||||
values: &[T],
|
||||
) -> Result<T>
|
||||
where
|
||||
T: Sum,
|
||||
for<'a> &'a T: Mul<Scalar, Output=T>,
|
||||
where
|
||||
T: Sum,
|
||||
for<'a> &'a T: Mul<Scalar, Output = T>,
|
||||
{
|
||||
if points.is_empty() || values.is_empty() {
|
||||
return Err(DivisibleEcashError::Interpolation(
|
||||
|
||||
@@ -9,22 +9,15 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
bls12_381 = { version = "0.5", default-features = false, features = ["pairings", "alloc", "experimental"] }
|
||||
itertools = "0.10"
|
||||
digest = "0.9"
|
||||
rand = "0.8"
|
||||
thiserror = "1.0"
|
||||
sha2 = "0.9"
|
||||
bls12_381 = { workspace = true }
|
||||
bs58 = "0.4.0"
|
||||
digest = "0.9"
|
||||
ff = { workspace = true }
|
||||
group = { workspace = true }
|
||||
itertools = "0.10"
|
||||
rand = "0.8"
|
||||
sha2 = "0.9"
|
||||
thiserror = "1.0"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.3", features = ["html_reports"] }
|
||||
|
||||
[dependencies.ff]
|
||||
version = "0.10"
|
||||
default-features = false
|
||||
|
||||
[dependencies.group]
|
||||
version = "0.10"
|
||||
default-features = false
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
mod error;
|
||||
mod scheme;
|
||||
mod traits;
|
||||
mod utils;
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
|
||||
@@ -15,16 +15,10 @@ use rand::seq::SliceRandom;
|
||||
use std::ops::Neg;
|
||||
use std::time::Duration;
|
||||
|
||||
use bls12_381::{G1Affine, G1Projective, G2Affine, G2Prepared, multi_miller_loop, Scalar};
|
||||
use criterion::{Criterion, criterion_group, criterion_main};
|
||||
use ff::Field;
|
||||
use group::{Curve, Group};
|
||||
use rand::seq::SliceRandom;
|
||||
|
||||
use nymcoconut::{
|
||||
aggregate_signature_shares, aggregate_verification_keys, Attribute, blind_sign,
|
||||
BlindedSignature, elgamal_keygen, Parameters, prepare_blind_sign, prove_bandwidth_credential,
|
||||
setup, Signature, SignatureShare, ttp_keygen, VerificationKey, verify_credential,
|
||||
aggregate_signature_shares, aggregate_verification_keys, blind_sign, elgamal_keygen,
|
||||
prepare_blind_sign, prove_bandwidth_credential, setup, ttp_keygen, verify_credential,
|
||||
Attribute, BlindedSignature, Parameters, Signature, SignatureShare, VerificationKey,
|
||||
};
|
||||
|
||||
#[allow(unused)]
|
||||
@@ -151,7 +145,7 @@ fn unblind_and_aggregate(
|
||||
&attributes,
|
||||
&unblinded_signature_shares,
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
struct BenchCase {
|
||||
@@ -229,7 +223,7 @@ fn bench_coconut(c: &mut Criterion) {
|
||||
&blind_sign_request,
|
||||
&public_attributes,
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
})
|
||||
},
|
||||
);
|
||||
@@ -244,7 +238,7 @@ fn bench_coconut(c: &mut Criterion) {
|
||||
&blind_sign_request,
|
||||
&public_attributes,
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
blinded_signatures.push(blinded_signature)
|
||||
}
|
||||
|
||||
@@ -325,7 +319,7 @@ fn bench_coconut(c: &mut Criterion) {
|
||||
serial_number,
|
||||
binding_number,
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap();
|
||||
|
||||
// CLIENT BENCHMARK
|
||||
group.bench_function(
|
||||
@@ -344,7 +338,7 @@ fn bench_coconut(c: &mut Criterion) {
|
||||
serial_number,
|
||||
binding_number,
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap()
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
@@ -123,6 +123,7 @@ impl From<ConfigV1_1_31> for Config {
|
||||
nym_api_urls: value.gateway.nym_api_urls,
|
||||
nyxd_urls: value.gateway.nyxd_urls,
|
||||
cosmos_mnemonic: value.gateway.cosmos_mnemonic,
|
||||
offline_credential_verification: false,
|
||||
},
|
||||
wireguard: nym_node::config::Wireguard {
|
||||
enabled: value.wireguard.enabled,
|
||||
@@ -216,6 +217,7 @@ pub struct GatewayV1_1_31 {
|
||||
// #[deprecated(note = "move to storage")]
|
||||
// TODO: I don't think this should be stored directly in the config...
|
||||
pub cosmos_mnemonic: bip39::Mnemonic,
|
||||
pub offline_credential_verification: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq, Serialize)]
|
||||
|
||||
@@ -201,12 +201,6 @@ impl EcashVerifier {
|
||||
api_clients: Vec<CoconutApiClient>,
|
||||
credential: EcashCredential,
|
||||
) -> Result<(), RequestHandlingError> {
|
||||
let req = nym_api_requests::coconut::VerifyCredentialBody::new(
|
||||
credential.clone(),
|
||||
proposal_id,
|
||||
self.nyxd_client.address(),
|
||||
);
|
||||
|
||||
for client in api_clients {
|
||||
self.cred_sender
|
||||
.unbounded_send(PendingCredential {
|
||||
|
||||
@@ -467,14 +467,14 @@ impl<St> Gateway<St> {
|
||||
let ecash_verifier = {
|
||||
let nyxd_client = self.random_nyxd_client()?;
|
||||
let ecash_params = self.get_ecash_parameters().await?;
|
||||
EcashVerifier::new(
|
||||
Arc::new(EcashVerifier::new(
|
||||
nyxd_client,
|
||||
ecash_params,
|
||||
self.identity_keypair.public_key().to_bytes(),
|
||||
shutdown.subscribe().named("EcashVerifier"),
|
||||
self.storage.clone(),
|
||||
self.config.gateway.offline_credential_verification,
|
||||
)
|
||||
))
|
||||
};
|
||||
|
||||
let mix_forwarding_channel =
|
||||
@@ -504,7 +504,7 @@ impl<St> Gateway<St> {
|
||||
mix_forwarding_channel.clone(),
|
||||
active_clients_store.clone(),
|
||||
shutdown.subscribe().named("websocket::Listener"),
|
||||
Arc::new(coconut_verifier),
|
||||
Arc::clone(&ecash_verifier),
|
||||
);
|
||||
|
||||
let nr_request_filter = if self.config.network_requester.enabled {
|
||||
@@ -527,7 +527,7 @@ impl<St> Gateway<St> {
|
||||
if self.config.ip_packet_router.enabled {
|
||||
let embedded_ip_sp = self
|
||||
.start_ip_packet_router(
|
||||
mix_forwarding_channel,
|
||||
mix_forwarding_channel.clone(),
|
||||
shutdown.subscribe().named("ip_service_provider"),
|
||||
)
|
||||
.await?;
|
||||
@@ -548,7 +548,7 @@ impl<St> Gateway<St> {
|
||||
mix_forwarding_channel,
|
||||
active_clients_store,
|
||||
shutdown.subscribe().named("websocket::Listener"),
|
||||
Arc::new(ecash_verifier),
|
||||
Arc::clone(&ecash_verifier),
|
||||
);
|
||||
|
||||
// Once this is a bit more mature, make this a commandline flag instead of a compile time
|
||||
|
||||
@@ -6,11 +6,11 @@ use thiserror::Error;
|
||||
#[derive(Error, Debug)]
|
||||
pub(crate) enum StorageError {
|
||||
#[error("Database experienced an internal error: {0}")]
|
||||
InternalDatabaseError(#[from] sqlx::Error),
|
||||
InternalDatabase(#[from] sqlx::Error),
|
||||
|
||||
#[error("Failed to perform database migration: {0}")]
|
||||
MigrationError(#[from] sqlx::migrate::MigrateError),
|
||||
Migration(#[from] sqlx::migrate::MigrateError),
|
||||
|
||||
#[error("Somehow stored data is incorrect: {0}")]
|
||||
DataCorruptionError(String),
|
||||
DataCorruption(String),
|
||||
}
|
||||
|
||||
@@ -384,17 +384,16 @@ impl Storage for PersistentStorage {
|
||||
.into_iter()
|
||||
.map(|stored_pending| {
|
||||
let credential = EcashCredential::try_from_bs58(stored_pending.credential)
|
||||
.map_err(|err| StorageError::DataCorruptionError(err.to_string()))?;
|
||||
.map_err(|err| StorageError::DataCorruption(err.to_string()))?;
|
||||
Ok((
|
||||
stored_pending.id,
|
||||
PendingCredential {
|
||||
credential,
|
||||
address: AccountId::from_str(&stored_pending.address)
|
||||
.map_err(|err| StorageError::DataCorruptionError(err.to_string()))?,
|
||||
.map_err(|err| StorageError::DataCorruption(err.to_string()))?,
|
||||
client: NymApiClient::new(
|
||||
Url::from_str(&stored_pending.api_url).map_err(|err| {
|
||||
StorageError::DataCorruptionError(err.to_string())
|
||||
})?,
|
||||
Url::from_str(&stored_pending.api_url)
|
||||
.map_err(|err| StorageError::DataCorruption(err.to_string()))?,
|
||||
),
|
||||
},
|
||||
))
|
||||
|
||||
Reference in New Issue
Block a user