Move spend and spec vfy as functions associated with wallet and payment
This commit is contained in:
@@ -271,10 +271,11 @@ mod tests {
|
||||
use rand::thread_rng;
|
||||
|
||||
use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness};
|
||||
use crate::scheme::{pseudorandom_fgt, pseudorandom_fgv};
|
||||
use crate::scheme::aggregation::aggregate_verification_keys;
|
||||
use crate::scheme::keygen::{PublicKeyUser, ttp_keygen, VerificationKeyAuth};
|
||||
use crate::scheme::PayInfo;
|
||||
use crate::scheme::setup::Parameters;
|
||||
use crate::scheme::spend::{PayInfo, pseudorandom_fgt, pseudorandom_fgv};
|
||||
use crate::utils::hash_to_scalar;
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::scheme::{PayInfo, Payment};
|
||||
use crate::scheme::keygen::PublicKeyUser;
|
||||
use crate::scheme::setup::Parameters;
|
||||
use crate::scheme::spend::{PayInfo, Payment};
|
||||
|
||||
pub fn identify(params: &Parameters, pay1: Payment, pay2: Payment, payInfo1: PayInfo, payInfo2: PayInfo) -> Result<PublicKeyUser> {
|
||||
// TODO: We had to include checks for S1, S2 and payinfo1 and payinfo2
|
||||
let pkUser = (pay2.T * pay1.R - pay1.T * pay2.R) * (pay1.R - pay2.R).invert().unwrap();
|
||||
Ok(PublicKeyUser { pk: pkUser })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,16 @@ use std::cell::Cell;
|
||||
use std::convert::TryFrom;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use bls12_381::{G1Projective, Scalar};
|
||||
use bls12_381::{G1Projective, G2Prepared, G2Projective, Scalar};
|
||||
use group::Curve;
|
||||
|
||||
use crate::Attribute;
|
||||
use crate::error::{CompactEcashError, Result};
|
||||
use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness};
|
||||
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
|
||||
use crate::scheme::setup::Parameters;
|
||||
use crate::traits::Bytable;
|
||||
use crate::utils::try_deserialize_g1_projective;
|
||||
use crate::utils::{check_bilinear_pairing, hash_to_scalar, try_deserialize_g1_projective};
|
||||
|
||||
pub mod aggregation;
|
||||
pub mod keygen;
|
||||
@@ -146,7 +149,174 @@ impl Wallet {
|
||||
pub fn v(&self) -> Scalar { self.v }
|
||||
pub fn t(&self) -> Scalar { self.t }
|
||||
pub fn l(&self) -> u64 { self.l.get() }
|
||||
|
||||
fn up(&self) {
|
||||
self.l.set(self.l.get() + 1);
|
||||
}
|
||||
|
||||
pub fn spend(&self, params: &Parameters, verification_key: &VerificationKeyAuth, skUser: &SecretKeyUser, payInfo: &PayInfo) -> Result<(Payment, &Self)> {
|
||||
if self.l() > params.L() {
|
||||
return Err(CompactEcashError::Spend(
|
||||
"The counter l is higher than max L".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
// randomize signature in the wallet
|
||||
let (signature_prime, sign_blinding_factor) = self.signature().randomise(params);
|
||||
// construct kappa i.e., blinded attributes for show
|
||||
let attributes = vec![skUser.sk, self.v(), self.t()];
|
||||
let kappa = compute_kappa(¶ms, &verification_key, &attributes, sign_blinding_factor);
|
||||
|
||||
// pick random openings o_a, o_c, o_d
|
||||
let o_a = params.random_scalar();
|
||||
let o_c = params.random_scalar();
|
||||
let o_d = params.random_scalar();
|
||||
|
||||
// compute commitments A, C, D
|
||||
let A = params.gen1() * o_a + params.gamma1().unwrap() * Scalar::from(self.l());
|
||||
let C = params.gen1() * o_c + params.gamma1().unwrap() * self.v();
|
||||
let D = params.gen1() * o_d + params.gamma1().unwrap() * self.t();
|
||||
|
||||
// compute hash of the payment info
|
||||
let R = hash_to_scalar(payInfo.info);
|
||||
|
||||
// evaluate the pseudorandom functions
|
||||
let S = pseudorandom_fgv(¶ms, self.v(), self.l());
|
||||
let T = params.gen1() * skUser.sk + pseudorandom_fgt(¶ms, self.t(), self.l()) * R;
|
||||
|
||||
// compute values mu, o_mu, lambda, o_lambda
|
||||
let mu: Scalar = (self.v() + Scalar::from(self.l()) + Scalar::from(1)).invert().unwrap();
|
||||
let o_mu = ((o_a + o_c) * mu).neg();
|
||||
let lambda = (self.t() + Scalar::from(self.l()) + Scalar::from(1)).invert().unwrap();
|
||||
let o_lambda = ((o_a + o_d) * lambda).neg();
|
||||
|
||||
// construct the zkp proof
|
||||
let spendInstance = SpendInstance {
|
||||
kappa,
|
||||
A,
|
||||
C,
|
||||
D,
|
||||
S,
|
||||
T,
|
||||
};
|
||||
let spendWitness = SpendWitness {
|
||||
attributes,
|
||||
r: sign_blinding_factor,
|
||||
l: Scalar::from(self.l()),
|
||||
o_a,
|
||||
o_c,
|
||||
o_d,
|
||||
mu,
|
||||
lambda,
|
||||
o_mu,
|
||||
o_lambda,
|
||||
};
|
||||
let zk_proof = SpendProof::construct(¶ms, &spendInstance, &spendWitness, &verification_key, R);
|
||||
|
||||
// output pay and updated wallet
|
||||
let pay = Payment {
|
||||
kappa,
|
||||
sig: signature_prime,
|
||||
S,
|
||||
T,
|
||||
A,
|
||||
C,
|
||||
D,
|
||||
R,
|
||||
zk_proof,
|
||||
};
|
||||
|
||||
self.up();
|
||||
|
||||
Ok((pay, self))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pseudorandom_fgv(params: &Parameters, v: Scalar, l: u64) -> G1Projective {
|
||||
let pow = (v + Scalar::from(l) + Scalar::from(1)).neg();
|
||||
params.gen1() * pow
|
||||
}
|
||||
|
||||
pub fn pseudorandom_fgt(params: &Parameters, t: Scalar, l: u64) -> G1Projective {
|
||||
let pow = (t + Scalar::from(l) + Scalar::from(1)).neg();
|
||||
params.gen1() * pow
|
||||
}
|
||||
|
||||
pub fn compute_kappa(
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKeyAuth,
|
||||
attributes: &[Attribute],
|
||||
blinding_factor: Scalar,
|
||||
) -> G2Projective {
|
||||
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>()
|
||||
}
|
||||
|
||||
pub struct PayInfo {
|
||||
pub(crate) info: [u8; 32],
|
||||
}
|
||||
|
||||
pub struct Payment {
|
||||
pub kappa: G2Projective,
|
||||
pub sig: Signature,
|
||||
pub S: G1Projective,
|
||||
pub T: G1Projective,
|
||||
pub A: G1Projective,
|
||||
pub C: G1Projective,
|
||||
pub D: G1Projective,
|
||||
pub R: Scalar,
|
||||
pub zk_proof: SpendProof,
|
||||
}
|
||||
|
||||
impl Payment {
|
||||
pub fn spend_verify(&self, params: &Parameters, verification_key: &VerificationKeyAuth, payinfo: &PayInfo) -> Result<bool> {
|
||||
if bool::from(self.sig.0.is_identity()) {
|
||||
return Err(CompactEcashError::Spend(
|
||||
"The element h of the signature equals the identity".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if !check_bilinear_pairing(
|
||||
&self.sig.0.to_affine(),
|
||||
&G2Prepared::from(self.kappa.to_affine()),
|
||||
&self.sig.1.to_affine(),
|
||||
params.prepared_miller_g2(),
|
||||
) {
|
||||
return Err(CompactEcashError::Spend(
|
||||
"The bilinear check for kappa failed".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
// verify integrity of R
|
||||
if !(self.R == hash_to_scalar(payinfo.info)) {
|
||||
return Err(CompactEcashError::Spend(
|
||||
"Integrity of R does not hold".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
//TODO: verify whether payinfo contains merchent's identifier
|
||||
|
||||
// verify the zk proof
|
||||
let instance = SpendInstance {
|
||||
kappa: self.kappa,
|
||||
A: self.A,
|
||||
C: self.C,
|
||||
D: self.D,
|
||||
S: self.S,
|
||||
T: self.T,
|
||||
};
|
||||
|
||||
if !self.zk_proof.verify(¶ms, &instance, &verification_key, self.R) {
|
||||
return Err(CompactEcashError::Spend(
|
||||
"ZkProof verification failed".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
@@ -1,181 +0,0 @@
|
||||
use std::cell::Cell;
|
||||
use std::convert::TryInto;
|
||||
|
||||
use bls12_381::{G1Projective, G2Prepared, G2Projective, Scalar};
|
||||
use group::Curve;
|
||||
|
||||
use crate::Attribute;
|
||||
use crate::error::{CompactEcashError, Result};
|
||||
use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness};
|
||||
use crate::scheme::{Signature, Wallet};
|
||||
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
|
||||
use crate::scheme::setup::Parameters;
|
||||
use crate::utils::{check_bilinear_pairing, hash_to_scalar};
|
||||
|
||||
pub struct PayInfo {
|
||||
pub(crate) info: [u8; 32],
|
||||
}
|
||||
|
||||
pub struct Payment {
|
||||
pub kappa: G2Projective,
|
||||
pub sig: Signature,
|
||||
pub S: G1Projective,
|
||||
pub T: G1Projective,
|
||||
pub A: G1Projective,
|
||||
pub C: G1Projective,
|
||||
pub D: G1Projective,
|
||||
pub R: Scalar,
|
||||
pub zk_proof: SpendProof,
|
||||
}
|
||||
|
||||
pub fn pseudorandom_fgv(params: &Parameters, v: Scalar, l: u64) -> G1Projective {
|
||||
let pow = (v + Scalar::from(l) + Scalar::from(1)).neg();
|
||||
params.gen1() * pow
|
||||
}
|
||||
|
||||
pub fn pseudorandom_fgt(params: &Parameters, t: Scalar, l: u64) -> G1Projective {
|
||||
let pow = (t + Scalar::from(l) + Scalar::from(1)).neg();
|
||||
params.gen1() * pow
|
||||
}
|
||||
|
||||
pub fn compute_kappa(
|
||||
params: &Parameters,
|
||||
verification_key: &VerificationKeyAuth,
|
||||
attributes: &[Attribute],
|
||||
blinding_factor: Scalar,
|
||||
) -> G2Projective {
|
||||
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>()
|
||||
}
|
||||
|
||||
pub fn spend(params: &Parameters, wallet: &Wallet, verification_key: &VerificationKeyAuth, skUser: &SecretKeyUser, payInfo: &PayInfo) -> Result<(Payment, Wallet)> {
|
||||
if wallet.l() > params.L() {
|
||||
return Err(CompactEcashError::Spend(
|
||||
"The counter l is higher than max L".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
// randomize signature in the wallet
|
||||
let (signature_prime, sign_blinding_factor) = wallet.signature().randomise(params);
|
||||
// construct kappa i.e., blinded attributes for show
|
||||
let attributes = vec![skUser.sk, wallet.v(), wallet.t()];
|
||||
let kappa = compute_kappa(¶ms, &verification_key, &attributes, sign_blinding_factor);
|
||||
|
||||
// pick random openings o_a, o_c, o_d
|
||||
let o_a = params.random_scalar();
|
||||
let o_c = params.random_scalar();
|
||||
let o_d = params.random_scalar();
|
||||
|
||||
// compute commitments A, C, D
|
||||
let A = params.gen1() * o_a + params.gamma1().unwrap() * Scalar::from(wallet.l());
|
||||
let C = params.gen1() * o_c + params.gamma1().unwrap() * wallet.v();
|
||||
let D = params.gen1() * o_d + params.gamma1().unwrap() * wallet.t();
|
||||
|
||||
// compute hash of the payment info
|
||||
let R = hash_to_scalar(payInfo.info);
|
||||
|
||||
// evaluate the pseudorandom functions
|
||||
let S = pseudorandom_fgv(¶ms, wallet.v(), wallet.l());
|
||||
let T = params.gen1() * skUser.sk + pseudorandom_fgt(¶ms, wallet.t(), wallet.l()) * R;
|
||||
|
||||
// compute values mu, o_mu, lambda, o_lambda
|
||||
let mu: Scalar = (wallet.v() + Scalar::from(wallet.l()) + Scalar::from(1)).neg();
|
||||
let o_mu = ((o_a + o_c) * mu).neg();
|
||||
let lambda = (wallet.t() + Scalar::from(wallet.l()) + Scalar::from(1)).neg();
|
||||
let o_lambda = ((o_a + o_d) * lambda).neg();
|
||||
|
||||
// construct the zkp proof
|
||||
let spendInstance = SpendInstance {
|
||||
kappa,
|
||||
A,
|
||||
C,
|
||||
D,
|
||||
S,
|
||||
T,
|
||||
};
|
||||
let spendWitness = SpendWitness {
|
||||
attributes,
|
||||
r: sign_blinding_factor,
|
||||
l: Scalar::from(wallet.l()),
|
||||
o_a,
|
||||
o_c,
|
||||
o_d,
|
||||
mu,
|
||||
lambda,
|
||||
o_mu,
|
||||
o_lambda,
|
||||
};
|
||||
let zk_proof = SpendProof::construct(¶ms, &spendInstance, &spendWitness, &verification_key, R);
|
||||
|
||||
// output pay and updated wallet
|
||||
let pay = Payment {
|
||||
kappa,
|
||||
sig: signature_prime,
|
||||
S,
|
||||
T,
|
||||
A,
|
||||
C,
|
||||
D,
|
||||
R,
|
||||
zk_proof,
|
||||
};
|
||||
let wallet_upd = Wallet {
|
||||
sig: wallet.sig,
|
||||
v: wallet.v,
|
||||
t: wallet.t,
|
||||
l: Cell::new(wallet.l.get() + 1),
|
||||
};
|
||||
|
||||
Ok((pay, wallet_upd))
|
||||
}
|
||||
|
||||
pub fn spend_verify(params: &Parameters, verification_key: &VerificationKeyAuth, pay: &Payment, payinfo: &PayInfo) -> Result<bool> {
|
||||
if bool::from(pay.sig.0.is_identity()) {
|
||||
return Err(CompactEcashError::Spend(
|
||||
"The element h of the signature equals the identity".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
if !check_bilinear_pairing(
|
||||
&pay.sig.0.to_affine(),
|
||||
&G2Prepared::from(pay.kappa.to_affine()),
|
||||
&pay.sig.1.to_affine(),
|
||||
params.prepared_miller_g2(),
|
||||
) {
|
||||
return Err(CompactEcashError::Spend(
|
||||
"The bilinear check for kappa failed".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
// verify integrity of R
|
||||
if !(pay.R == hash_to_scalar(payinfo.info)) {
|
||||
return Err(CompactEcashError::Spend(
|
||||
"Integrity of R does not hold".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
//TODO: verify whether payinfo contains merchent's identifier
|
||||
|
||||
// verify the zk proof
|
||||
let instance = SpendInstance {
|
||||
kappa: pay.kappa,
|
||||
A: pay.A,
|
||||
C: pay.C,
|
||||
D: pay.D,
|
||||
S: pay.S,
|
||||
T: pay.T,
|
||||
};
|
||||
|
||||
if !pay.zk_proof.verify(¶ms, &instance, &verification_key, pay.R) {
|
||||
return Err(CompactEcashError::Spend(
|
||||
"ZkProof verification failed".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ use crate::scheme::aggregation::{aggregate_signature_shares, aggregate_verificat
|
||||
use crate::scheme::keygen::{
|
||||
generate_keypair_user, PublicKeyUser, SecretKeyUser, ttp_keygen, VerificationKeyAuth,
|
||||
};
|
||||
use crate::scheme::PayInfo;
|
||||
use crate::scheme::setup::Parameters;
|
||||
use crate::scheme::spend::{PayInfo, spend, spend_verify};
|
||||
use crate::scheme::withdrawal::{issue_verify, issue_wallet, withdrawal_request};
|
||||
|
||||
#[test]
|
||||
@@ -51,9 +51,9 @@ fn main() -> Result<(), CompactEcashError> {
|
||||
info: [6u8; 32],
|
||||
};
|
||||
|
||||
let (payment, upd_wallet) = spend(¶ms, &aggr_wallet, &verification_key, &user_keypair.secret_key(), &payInfo)?;
|
||||
let (payment, upd_wallet) = aggr_wallet.spend(¶ms, &verification_key, &user_keypair.secret_key(), &payInfo)?;
|
||||
|
||||
assert!(spend_verify(¶ms, &verification_key, &payment, &payInfo).unwrap());
|
||||
assert!(payment.spend_verify(¶ms, &verification_key, &payInfo).unwrap());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user