Add spend and spend verification functions; fix breaking test for proof of withdrawal

This commit is contained in:
aniampio
2022-05-10 13:21:53 +01:00
parent 9c22c082c0
commit 68485f8998
7 changed files with 169 additions and 62 deletions
@@ -14,6 +14,7 @@ use crate::scheme::setup::GroupParameters;
use crate::utils::try_deserialize_g1_projective;
pub mod proof_withdrawal;
pub mod proof_spend;
type ChallengeDigest = Sha256;
@@ -1,4 +1,32 @@
pub struct SpendInstance {}
use bls12_381::{G1Projective, G2Projective, Scalar};
use crate::scheme::{Phi, VarPhi};
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
use crate::scheme::setup::Parameters;
pub struct SpendInstance {
pub kappa: G2Projective,
pub phi: Phi,
pub var_phi: VarPhi,
pub rr: G1Projective,
pub ss: G1Projective,
pub tt: G1Projective,
}
pub struct SpendWitness {
sk_u: SecretKeyUser,
v: Scalar,
r: Scalar,
r1: Scalar,
r2: Scalar,
}
#[derive(Debug, Clone)]
pub struct SpendProof {}
impl SpendProof {
pub fn construct() {}
}
pub struct SpendWitness {}
@@ -130,7 +130,7 @@ impl WithdrawalReqProof {
) -> Self {
let grp = params.get_grp();
let g1 = grp.gen1();
let paramsU = params.get_paramsUser();
let params_u = params.get_params_u();
// generate random values to replace the witnesses
let r_com_opening = grp.random_scalar();
@@ -141,7 +141,7 @@ impl WithdrawalReqProof {
let zkcm_com = g1 * r_com_opening
+ r_attributes
.iter()
.zip(paramsU.get_gammas().iter())
.zip(params_u.get_gammas().iter())
.map(|(rm_i, gamma_i)| gamma_i * rm_i)
.sum::<G1Projective>();
@@ -154,7 +154,7 @@ impl WithdrawalReqProof {
let zkcm_user_sk = g1 * r_attributes[0];
// covert to bytes
let gammas_bytes = paramsU
let gammas_bytes = params_u
.get_gammas()
.iter()
.map(|gamma| gamma.to_bytes())
@@ -203,7 +203,7 @@ impl WithdrawalReqProof {
) -> bool {
let grp = params.get_grp();
let g1 = grp.gen1();
let paramsU = params.get_paramsUser();
let paramsU = params.get_params_u();
// recompute zk commitments for each instance
let zkcm_com = instance.com * self.challenge
@@ -305,7 +305,7 @@ mod tests {
let com = grp.gen1() * com_opening
+ attr
.iter()
.zip(params.get_paramsUser().get_gammas())
.zip(params.get_params_u().get_gammas())
.map(|(&m, gamma)| gamma * m)
.sum::<G1Projective>();
let h = hash_g1(com.to_bytes());
@@ -1,13 +1,15 @@
use std::cell::Cell;
use bls12_381::{G2Projective, Scalar};
use bls12_381::{G1Projective, G2Prepared, G2Projective, Scalar};
use group::Curve;
use crate::Attribute;
use crate::constants::L;
use crate::error::{DivisibleEcashError, Result};
use crate::proofs::proof_spend::SpendProof;
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
use crate::scheme::setup::{GroupParameters, Parameters};
use crate::utils::{hash_to_scalar, Signature, SignerIndex};
use crate::utils::{check_bilinear_pairing, hash_to_scalar, Signature, SignerIndex};
pub mod aggregation;
pub mod identify;
@@ -31,12 +33,27 @@ pub fn compute_kappa(
.sum::<G2Projective>()
}
#[derive(Debug, Clone)]
pub struct Phi(pub(crate) G1Projective, pub(crate) G1Projective);
#[derive(Debug, Clone)]
pub struct VarPhi(pub(crate) G1Projective, pub(crate) G1Projective);
pub struct PayInfo {
pub info: [u8; 32],
}
#[derive(Debug, Clone)]
pub struct Payment {}
pub struct Payment {
kappa: G2Projective,
sig: Signature,
phi: Phi,
varphi: VarPhi,
rr: Scalar,
zkproof: SpendProof,
vv: u64,
}
pub struct PartialWallet {
sig: Signature,
@@ -77,16 +94,16 @@ impl Wallet {
verification_key: &VerificationKeyAuth,
sk_user: &SecretKeyUser,
pay_info: &PayInfo,
V: u64,
vv: u64,
) -> Result<(Payment, &Self)> {
if self.l() + V > L {
if self.l() + vv >= L {
return Err(DivisibleEcashError::Spend(
"The counter l is higher than max L".to_string(),
));
}
let grp = params.get_grp();
let paramsU = params.get_paramsUser();
let params_u = params.get_params_u();
// randomize signature in the wallet
let (signature_prime, sign_blinding_factor) = self.signature().randomise(grp);
// construct kappa i.e., blinded attributes for show
@@ -101,19 +118,71 @@ impl Wallet {
let r1 = grp.random_scalar();
let r2 = grp.random_scalar();
let phi1 = grp.gen1() * r1;
let phi2 = paramsU.get_ith_sigma(self.l.get() as usize) * self.v + paramsU.get_ith_eta(V as usize) * r1;
let phi = Phi(grp.gen1() * r1, params_u.get_ith_sigma(self.l.get() as usize) * self.v + params_u.get_ith_eta(vv as usize) * r1);
// compute hash of the payment info
let rr = hash_to_scalar(pay_info.info);
let rho1 = grp.gen1() * r2;
let rho2 = (grp.gen1() * rr) * sk_user.sk + paramsU.get_ith_theta(self.l.get() as usize) * self.v + paramsU.get_ith_eta(V as usize) * r2;
let varphi = VarPhi(grp.gen1() * r2, (grp.gen1() * rr) * sk_user.sk + params_u.get_ith_theta(self.l.get() as usize) * self.v + params_u.get_ith_eta(vv as usize) * r2);
// compute the zk proof
let zkproof = SpendProof {};
// output pay and updated wallet
let pay = Payment {};
let pay = Payment {
kappa,
sig: signature_prime,
phi,
varphi,
rr,
zkproof,
vv,
};
self.l.set(self.l.get() + vv);
Ok((pay, self))
}
}
impl Payment {
pub fn spend_verify(
&self,
params: &Parameters,
verification_key: &VerificationKeyAuth,
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(),
));
}
let grp = params.get_grp();
if !check_bilinear_pairing(
&self.sig.0.to_affine(),
&G2Prepared::from(self.kappa.to_affine()),
&self.sig.1.to_affine(),
grp.prepared_miller_g2(),
) {
return Err(DivisibleEcashError::Spend(
"The bilinear check for kappa failed".to_string(),
));
}
if bool::from(self.sig.0.is_identity()) {
return Err(DivisibleEcashError::Spend(
"The element h of the signature on l equals the identity".to_string(),
));
}
// verify integrity of R
if !(self.rr == hash_to_scalar(pay_info.info)) {
return Err(DivisibleEcashError::Spend(
"Integrity of R does not hold".to_string(),
));
}
//TODO: verify whether payinfo contains merchent's identifier
// TODO: Add zk proof verification
Ok(true)
}
}
@@ -52,20 +52,22 @@ impl GroupParameters {
#[derive(Debug, Clone)]
pub struct Parameters {
grp: GroupParameters,
paramsUser: ParametersUser,
paramsAuth: ParametersAuthority,
params_u: ParametersUser,
params_a: ParametersAuthority,
}
impl Parameters {
pub(crate) fn get_grp(&self) -> &GroupParameters { &self.grp }
pub(crate) fn get_paramsUser(&self) -> &ParametersUser { &self.paramsUser }
pub(crate) fn get_params_u(&self) -> &ParametersUser { &self.params_u }
pub(crate) fn get_paramsAuth(&self) -> &ParametersAuthority { &self.paramsAuth }
pub(crate) fn get_params_a(&self) -> &ParametersAuthority { &self.params_a }
pub fn new(grp: GroupParameters) -> Parameters {
let g1 = grp.gen1();
let g2 = grp.gen2();
let psi1 = hash_g1("psi1");
let psi2 = hash_g1("psi2");
let gamma1 = hash_g1("gamma1");
let gamma2 = hash_g1("gamma2");
let eta = hash_g1("eta");
@@ -79,55 +81,59 @@ impl Parameters {
let sigma = g1 * z;
let theta = eta * z;
let sigmasUser: Vec<G1Projective> = (1..=L)
let sigmas_u: Vec<G1Projective> = (1..=L)
.map(|i| sigma * (y * Scalar::from(i)))
.collect();
let thetasUser: Vec<G1Projective> = (1..=L)
let thetas_u: Vec<G1Projective> = (1..=L)
.map(|i| theta * (y * Scalar::from(i)))
.collect();
let deltasAuth: Vec<G2Projective> = (0..=L - 1)
let deltas_a: Vec<G2Projective> = (0..=L - 1)
.map(|i| g2 * (y * Scalar::from(i)))
.collect();
let etasUser: Vec<G1Projective> = vec_a.iter().map(|x| g1 * x).collect();
let etas_u: Vec<G1Projective> = vec_a.iter().map(|x| g1 * x).collect();
let mut etasAuth: Vec<G2Projective> = Default::default();
for l in 1..=L + 1 {
let mut etas_a: Vec<G2Projective> = Default::default();
for l in 1..=L {
println!("l = {:?}", l);
for k in 0..=l - 1 {
etasAuth.push(g2 * (vec_a[l as usize].neg() * (y * Scalar::from(k))));
println!("k = {:?}", k);
etas_a.push(g2 * (vec_a[l as usize - 1].neg() * (y * Scalar::from(k))));
}
}
let sps_keypair = SPSKeyPair::new(grp.clone(), 2, 0);
let messagesA = vec![sigma, theta];
let messages_a = vec![sigma, theta];
let sps_signatures: Vec<SPSSignature> = sigmasUser
let sps_signatures: Vec<SPSSignature> = sigmas_u
.iter()
.zip(thetasUser.iter())
.map(|(sigma, theta)| sps_keypair.sps_sk.sign(grp.clone(), Some(&messagesA), None))
.zip(thetas_u.iter())
.map(|(sigma, theta)| sps_keypair.sps_sk.sign(grp.clone(), Some(&messages_a), None))
.collect();
// Compute signature for each pair sigma, theta
let paramsUser = ParametersUser {
let params_u = ParametersUser {
gammas: vec![gamma1, gamma2],
psi: vec![psi1, psi2],
eta,
omega,
etas: etasUser,
sigmas: sigmasUser,
thetas: thetasUser,
etas: etas_u,
sigmas: sigmas_u,
thetas: thetas_u,
sps_signatures,
sps_pk: sps_keypair.sps_vk,
};
let paramsAuth = ParametersAuthority {
deltas: deltasAuth,
etas: etasAuth,
let params_a = ParametersAuthority {
deltas: deltas_a,
etas: etas_a,
};
return Parameters {
grp,
paramsUser,
paramsAuth,
params_u,
params_a,
};
}
}
@@ -135,6 +141,7 @@ impl Parameters {
#[derive(Debug, Clone)]
pub struct ParametersUser {
gammas: Vec<G1Projective>,
psi: Vec<G1Projective>,
eta: G1Projective,
omega: G1Projective,
etas: Vec<G1Projective>,
@@ -147,6 +154,8 @@ pub struct ParametersUser {
impl ParametersUser {
pub(crate) fn get_gammas(&self) -> &Vec<G1Projective> { &self.gammas }
pub(crate) fn get_psi(&self) -> &Vec<G1Projective> { &self.psi }
pub(crate) fn get_eta(&self) -> &G1Projective { &self.eta }
pub(crate) fn get_omega(&self) -> &G1Projective { &self.omega }
@@ -9,7 +9,7 @@ use crate::scheme::setup::GroupParameters;
#[derive(Debug, Clone)]
pub struct SPSVerificationKey {
pub grparams: GroupParameters,
pub grp: GroupParameters,
pub uus: Vec<G1Projective>,
pub wws: Vec<G2Projective>,
pub yy: G2Projective,
@@ -17,7 +17,7 @@ pub struct SPSVerificationKey {
}
pub struct SPSSecretKey {
spsVK: SPSVerificationKey,
sps_vk: SPSVerificationKey,
us: Vec<Scalar>,
ws: Vec<Scalar>,
y: Scalar,
@@ -33,30 +33,30 @@ impl SPSSecretKey {
self.y
}
pub fn sign(&self, grparams: GroupParameters, messagesA: Option<&[G1Projective]>, messagesB: Option<&[G2Projective]>) -> SPSSignature {
let r = grparams.random_scalar();
let rr = grparams.gen1() * r;
let ss: G1Projective = match messagesA {
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 {
Some(msgsA) => {
let prodS: Vec<G1Projective> = msgsA
.iter()
.zip(self.ws.iter())
.map(|(m_i, w_i)| m_i * w_i.neg())
.collect();
grparams.gen1() * (self.z() - r * self.y()) + prodS.iter().fold(G1Projective::identity(), |acc, elem| acc + elem)
grp.gen1() * (self.z() - r * self.y()) + prodS.iter().fold(G1Projective::identity(), |acc, elem| acc + elem)
}
None => grparams.gen1() * (self.z() - r * self.y())
None => grp.gen1() * (self.z() - r * self.y())
};
let tt = match messagesB {
let tt = match messages_b {
Some(msgsB) => {
let prodT: Vec<G2Projective> = msgsB
.iter()
.zip(self.us.iter())
.map(|(m_i, u_i)| m_i * u_i.neg())
.collect();
(grparams.gen2() + prodT.iter().fold(G2Projective::identity(), |acc, elem| acc + elem)) * r.invert().unwrap()
(grp.gen2() + prodT.iter().fold(G2Projective::identity(), |acc, elem| acc + elem)) * r.invert().unwrap()
}
None => grparams.gen2() * r.invert().unwrap()
None => grp.gen2() * r.invert().unwrap()
};
SPSSignature
@@ -91,14 +91,14 @@ impl SPSKeyPair {
let zz = grparams.gen2() * z;
let sps_vk = SPSVerificationKey {
grparams: grparams.clone(),
grp: grparams.clone(),
uus,
wws,
yy,
zz,
};
let sps_sk = SPSSecretKey {
spsVK: sps_vk.clone(),
sps_vk: sps_vk.clone(),
us,
ws,
y,
@@ -24,14 +24,14 @@ pub struct RequestInfo {
pub fn withdrawal_request(params: Parameters, sk_user: SecretKeyUser) -> Result<(WithdrawalRequest, RequestInfo)> {
let grp = params.get_grp();
let g1 = grp.gen1();
let paramsU = params.get_paramsUser();
let params_u = params.get_params_u();
let v = grp.random_scalar();
let attributes = vec![sk_user.sk, v];
let com_opening = grp.random_scalar();
let commitment = g1 * com_opening
+ attributes
.iter()
.zip(paramsU.get_gammas())
.zip(params_u.get_gammas())
.map(|(&m, gamma)| gamma * m)
.sum::<G1Projective>();
@@ -78,7 +78,7 @@ pub fn withdrawal_request(params: Parameters, sk_user: SecretKeyUser) -> Result<
Ok((req, req_info))
}
pub(crate) fn issue(params: &Parameters, req: WithdrawalRequest, pkU: PublicKeyUser, skA: SecretKeyAuth) -> Result<BlindedSignature> {
pub(crate) fn issue(params: &Parameters, req: WithdrawalRequest, pk_u: PublicKeyUser, sk_a: SecretKeyAuth) -> Result<BlindedSignature> {
let h = hash_g1(req.com.to_bytes());
if !(h == req.com_hash) {
return Err(DivisibleEcashError::WithdrawalRequestVerification(
@@ -91,7 +91,7 @@ pub(crate) fn issue(params: &Parameters, req: WithdrawalRequest, pkU: PublicKeyU
com: req.com,
h: req.com_hash,
pc_coms: req.pc_coms.clone(),
pk_user: pkU,
pk_user: pk_u,
};
if !req.zk_proof.verify(&params, &instance) {
return Err(DivisibleEcashError::WithdrawalRequestVerification(
@@ -102,9 +102,9 @@ pub(crate) fn issue(params: &Parameters, req: WithdrawalRequest, pkU: PublicKeyU
let sig = req
.pc_coms
.iter()
.zip(skA.ys.iter())
.zip(sk_a.ys.iter())
.map(|(pc, yi)| pc * yi)
.chain(std::iter::once(h * skA.x))
.chain(std::iter::once(h * sk_a.x))
.sum();
Ok(BlindedSignature(h, sig))