Move spend and spec vfy as functions associated with wallet and payment

This commit is contained in:
aniampio
2022-03-28 17:36:40 +01:00
parent bfa7754ea6
commit ef0867a7e7
5 changed files with 179 additions and 189 deletions
@@ -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 })
}
}
+172 -2
View File
@@ -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(&params, &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(&params, self.v(), self.l());
let T = params.gen1() * skUser.sk + pseudorandom_fgt(&params, 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(&params, &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(&params, &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(&params, &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(&params, wallet.v(), wallet.l());
let T = params.gen1() * skUser.sk + pseudorandom_fgt(&params, 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(&params, &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(&params, &instance, &verification_key, pay.R) {
return Err(CompactEcashError::Spend(
"ZkProof verification failed".to_string(),
));
}
Ok(true)
}
+3 -3
View File
@@ -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(&params, &aggr_wallet, &verification_key, &user_keypair.secret_key(), &payInfo)?;
let (payment, upd_wallet) = aggr_wallet.spend(&params, &verification_key, &user_keypair.secret_key(), &payInfo)?;
assert!(spend_verify(&params, &verification_key, &payment, &payInfo).unwrap());
assert!(payment.spend_verify(&params, &verification_key, &payInfo).unwrap());
Ok(())
}