Add spend and spend verification functions; fix breaking test for proof of withdrawal
This commit is contained in:
@@ -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(¶ms, &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))
|
||||
|
||||
Reference in New Issue
Block a user