Add verification for the spend zkproof and first tests

This commit is contained in:
aniampio
2022-03-27 14:42:40 +01:00
committed by durch
parent 7fcd246089
commit d2a7d26e5a
4 changed files with 326 additions and 11 deletions
@@ -1,7 +1,13 @@
use bls12_381::{G1Projective, G2Projective, Scalar};
use std::convert::{TryFrom, TryInto};
use crate::scheme::keygen::SecretKeyUser;
use bls12_381::{G1Projective, G2Projective, Scalar};
use group::GroupEncoding;
use crate::error::{CompactEcashError, Result};
use crate::proofs::{ChallengeDigest, compute_challenge, produce_response, produce_responses};
use crate::scheme::keygen::{SecretKeyUser, VerificationKeyAuth};
use crate::scheme::setup::Parameters;
use crate::utils::{try_deserialize_g1_projective, try_deserialize_g2_projective};
#[derive(Debug)]
#[cfg_attr(test, derive(PartialEq))]
@@ -14,12 +20,80 @@ pub struct SpendInstance {
pub T: G1Projective,
}
impl TryFrom<&[u8]> for SpendInstance {
type Error = CompactEcashError;
fn try_from(bytes: &[u8]) -> Result<SpendInstance> {
if bytes.len() < 48 * 5 + 96 || (bytes.len()) % 48 != 0 {
return Err(CompactEcashError::DeserializationInvalidLength {
actual: bytes.len(),
modulus_target: bytes.len(),
target: 48 * 5 + 96,
modulus: 48,
object: "spend instance".to_string(),
});
}
let kappa_bytes = bytes[..96].try_into().unwrap();
let kappa = try_deserialize_g2_projective(
&kappa_bytes,
CompactEcashError::Deserialization("Failed to deserialize kappa".to_string()),
)?;
let A_bytes = bytes[96..144].try_into().unwrap();
let A = try_deserialize_g1_projective(
&A_bytes,
CompactEcashError::Deserialization("Failed to deserialize A".to_string()),
)?;
let C_bytes = bytes[144..192].try_into().unwrap();
let C = try_deserialize_g1_projective(
&C_bytes,
CompactEcashError::Deserialization("Failed to deserialize C".to_string()),
)?;
let D_bytes = bytes[192..240].try_into().unwrap();
let D = try_deserialize_g1_projective(
&D_bytes,
CompactEcashError::Deserialization("Failed to deserialize D".to_string()),
)?;
let S_bytes = bytes[240..288].try_into().unwrap();
let S = try_deserialize_g1_projective(
&S_bytes,
CompactEcashError::Deserialization("Failed to deserialize S".to_string()),
)?;
let T_bytes = bytes[288..336].try_into().unwrap();
let T = try_deserialize_g1_projective(
&T_bytes,
CompactEcashError::Deserialization("Failed to deserialize T".to_string()),
)?;
Ok(SpendInstance {
kappa,
A,
C,
D,
S,
T,
})
}
}
impl SpendInstance {
pub(crate) fn to_bytes(&self) -> Vec<u8> {
let mut bytes = Vec::with_capacity(96 + 5 * 48);
bytes.extend_from_slice(self.kappa.to_bytes().as_ref());
bytes.extend_from_slice(self.A.to_bytes().as_ref());
bytes.extend_from_slice(self.C.to_bytes().as_ref());
bytes.extend_from_slice(self.D.to_bytes().as_ref());
bytes.extend_from_slice(self.S.to_bytes().as_ref());
bytes.extend_from_slice(self.T.to_bytes().as_ref());
bytes
}
}
pub struct SpendWitness {
// includes skUser, v, t
pub attributes: Vec<Scalar>,
// signature randomizing element
pub r: Scalar,
pub l: u64,
pub l: Scalar,
pub o_a: Scalar,
pub o_c: Scalar,
pub o_d: Scalar,
@@ -30,11 +104,252 @@ pub struct SpendWitness {
}
pub struct SpendProof {}
pub struct SpendProof {
challenge: Scalar,
response_r: Scalar,
response_l: Scalar,
response_o_a: Scalar,
response_o_c: Scalar,
response_o_d: Scalar,
response_mu: Scalar,
response_lambda: Scalar,
response_o_mu: Scalar,
response_o_lambda: Scalar,
response_attributes: Vec<Scalar>,
}
impl SpendProof {
pub fn construct(params: &Parameters,
instance: &SpendInstance,
witness: &SpendWitness, ) {}
pub fn verify() {}
witness: &SpendWitness,
verification_key: &VerificationKeyAuth,
R: Scalar, ) -> Self {
// generate random values to replace each witness
let r_attributes = params.n_random_scalars(witness.attributes.len());
let r_r = params.random_scalar();
let r_l = params.random_scalar();
let r_o_a = params.random_scalar();
let r_o_c = params.random_scalar();
let r_o_d = params.random_scalar();
let r_mu = params.random_scalar();
let r_lambda = params.random_scalar();
let r_o_mu = params.random_scalar();
let r_o_lambda = params.random_scalar();
let g1 = params.gen1();
let gamma1 = params.gamma1().unwrap();
let beta2_bytes = verification_key
.beta_g2
.iter()
.map(|beta_i| beta_i.to_bytes())
.collect::<Vec<_>>();
// compute zkp commitment for each instance
let zkcm_kappa = params.gen2() * r_r
+ verification_key.alpha
+ r_attributes
.iter()
.zip(verification_key.beta_g2.iter())
.map(|(attr, beta_i)| beta_i * attr)
.sum::<G2Projective>();
let zkcm_A = g1 * r_o_a + gamma1 * r_l;
let zkcm_C = g1 * r_o_c + gamma1 * r_attributes[1];
let zkcm_D = g1 * r_o_d + gamma1 * r_attributes[2];
let zkcm_S = g1 * r_mu;
let zkcm_gamma11 = (instance.A + instance.C + gamma1) * r_mu + g1 * r_o_mu;
let zkcm_T = g1 * r_attributes[0] + (g1 * R) * r_lambda;
let zkcm_gamma12 = (instance.A + instance.D + gamma1) * r_lambda + g1 * r_o_lambda;
// TODO: Add also proof for l in [0, L-1]
// compute the challenge
let challenge = compute_challenge::<ChallengeDigest, _, _>(
std::iter::once(params.gen1().to_bytes().as_ref())
.chain(std::iter::once(gamma1.to_bytes().as_ref()))
.chain(std::iter::once(verification_key.alpha.to_bytes().as_ref()))
.chain(beta2_bytes.iter().map(|b| b.as_ref()))
.chain(std::iter::once(instance.to_bytes().as_ref()))
.chain(std::iter::once(zkcm_kappa.to_bytes().as_ref()))
// .chain(std::iter::once(zkcm_A.to_bytes().as_ref()))
// .chain(std::iter::once(zkcm_C.to_bytes().as_ref()))
// .chain(std::iter::once(zkcm_D.to_bytes().as_ref()))
// .chain(std::iter::once(zkcm_S.to_bytes().as_ref()))
// .chain(std::iter::once(zkcm_gamma11.to_bytes().as_ref()))
// .chain(std::iter::once(zkcm_T.to_bytes().as_ref()))
// .chain(std::iter::once(zkcm_gamma12.to_bytes().as_ref()))
);
// compute response for each witness
let response_r = produce_response(&r_r, &challenge, &witness.r);
let response_l = produce_response(&r_l, &challenge, &witness.l);
let response_o_a = produce_response(&r_o_a, &challenge, &witness.o_a);
let response_o_c = produce_response(&r_o_c, &challenge, &witness.o_c);
let response_o_d = produce_response(&r_o_d, &challenge, &witness.o_d);
let response_mu = produce_response(&r_mu, &challenge, &witness.mu);
let response_lambda = produce_response(&r_lambda, &challenge, &witness.lambda);
let response_o_mu = produce_response(&r_o_mu, &challenge, &witness.o_mu);
let response_o_lambda = produce_response(&r_o_lambda, &challenge, &witness.o_lambda);
let response_attributes = produce_responses(
&r_attributes,
&challenge,
&witness.attributes.iter().collect::<Vec<_>>(),
);
SpendProof {
challenge,
response_r,
response_l,
response_o_a,
response_o_c,
response_o_d,
response_mu,
response_lambda,
response_o_mu,
response_o_lambda,
response_attributes,
}
}
pub fn verify(&self,
params: &Parameters,
instance: &SpendInstance,
verification_key: &VerificationKeyAuth,
R: Scalar) -> bool {
let g1 = params.gen1();
let gamma1 = params.gamma1().unwrap();
let beta2_bytes = verification_key
.beta_g2
.iter()
.map(|beta_i| beta_i.to_bytes())
.collect::<Vec<_>>();
// re-compute each zkp commitment
let zkcm_kappa = instance.kappa * self.challenge
+ params.gen2() * self.response_r
+ verification_key.alpha * (Scalar::one() - self.challenge)
+ self.response_attributes
.iter()
.zip(verification_key.beta_g2.iter())
.map(|(attr, beta_i)| beta_i * attr)
.sum::<G2Projective>();
let zkcm_A = g1 * self.response_o_a + gamma1 * self.response_l + instance.A * self.challenge;
let zkcm_C = g1 * self.response_o_c + gamma1 * self.response_attributes[1] + instance.C * self.challenge;
let zkcm_D = g1 * self.response_o_d + gamma1 * self.response_attributes[2] + instance.D * self.challenge;
let zkcm_S = g1 * self.response_mu + instance.S * self.challenge;
let zkcm_gamma11 = (instance.A + instance.C + gamma1) * self.response_mu + g1 * self.response_o_mu + gamma1 * self.challenge;
let zkcm_T = g1 * self.response_attributes[0] + (g1 * R) * self.response_lambda + instance.T * self.challenge;
let zkcm_gamma12 = (instance.A + instance.D + gamma1) * self.response_lambda + g1 * self.response_o_lambda + gamma1 * self.challenge;
// re-compute the challenge
let challenge = compute_challenge::<ChallengeDigest, _, _>(
std::iter::once(params.gen1().to_bytes().as_ref())
.chain(std::iter::once(gamma1.to_bytes().as_ref()))
.chain(std::iter::once(verification_key.alpha.to_bytes().as_ref()))
.chain(beta2_bytes.iter().map(|b| b.as_ref()))
.chain(std::iter::once(instance.to_bytes().as_ref()))
.chain(std::iter::once(zkcm_kappa.to_bytes().as_ref()))
// .chain(std::iter::once(zkcm_A.to_bytes().as_ref()))
// .chain(std::iter::once(zkcm_C.to_bytes().as_ref()))
// .chain(std::iter::once(zkcm_D.to_bytes().as_ref()))
// .chain(std::iter::once(zkcm_S.to_bytes().as_ref()))
// .chain(std::iter::once(zkcm_gamma11.to_bytes().as_ref()))
// .chain(std::iter::once(zkcm_T.to_bytes().as_ref()))
// .chain(std::iter::once(zkcm_gamma12.to_bytes().as_ref()))
);
challenge == self.challenge
}
}
#[cfg(test)]
mod tests {
use bls12_381::{G2Projective, Scalar};
use rand::thread_rng;
use crate::proofs::proof_spend::{SpendInstance, SpendProof, SpendWitness};
use crate::scheme::aggregation::aggregate_verification_keys;
use crate::scheme::keygen::{PublicKeyUser, ttp_keygen, VerificationKeyAuth};
use crate::scheme::setup::Parameters;
use crate::scheme::spend::{PayInfo, pseudorandom_fgt, pseudorandom_fgv};
use crate::utils::hash_to_scalar;
#[test]
fn spend_proof_construct_and_verify() {
let rng = thread_rng();
let params = Parameters::new().unwrap();
let sk = params.random_scalar();
let pk_user = PublicKeyUser {
pk: params.gen1() * sk,
};
let authorities_keypairs = ttp_keygen(&params, 2, 3).unwrap();
let verification_keys_auth: Vec<VerificationKeyAuth> = authorities_keypairs
.iter()
.map(|keypair| keypair.verification_key())
.collect();
let verification_key = aggregate_verification_keys(&verification_keys_auth, Some(&[1, 2, 3])).unwrap();
let v = params.random_scalar();
let t = params.random_scalar();
let attributes = vec![sk, v, t];
let l = 5;
let r = params.random_scalar();
let kappa = params.gen2() * r
+ verification_key.alpha
+ attributes
.iter()
.zip(verification_key.beta_g2.iter())
.map(|(priv_attr, beta_i)| beta_i * priv_attr)
.sum::<G2Projective>();
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(l);
let C = params.gen1() * o_c + params.gamma1().unwrap() * v;
let D = params.gen1() * o_d + params.gamma1().unwrap() * t;
// compute hash of the payment info
let payInfo = PayInfo { info: [5u8; 32] };
let R = hash_to_scalar(payInfo.info);
// evaluate the pseudorandom functions
let S = pseudorandom_fgv(&params, v, l);
let T = params.gen1() * sk + pseudorandom_fgt(&params, t, l) * R;
// compute values mu, o_mu, lambda, o_lambda
let mu: Scalar = (v + Scalar::from(l) + Scalar::from(1)).neg();
let o_mu = ((o_a + o_c) * mu).neg();
let lambda = (t + Scalar::from(l) + Scalar::from(1)).neg();
let o_lambda = ((o_a + o_d) * lambda).neg();
let instance = SpendInstance {
kappa,
A: Default::default(),
C: Default::default(),
D: Default::default(),
S: Default::default(),
T: Default::default(),
};
let witness = SpendWitness {
attributes,
r,
l: Scalar::from(l),
o_a,
o_c,
o_d,
mu,
lambda,
o_mu,
o_lambda,
};
let zk_proof = SpendProof::construct(&params, &instance, &witness, &verification_key, R);
assert!(zk_proof.verify(&params, &instance, &verification_key, R))
}
}
@@ -34,7 +34,7 @@ impl TryFrom<&[u8]> for WithdrawalReqInstance {
modulus_target: bytes.len() - 8,
target: 48 * 4 + 8,
modulus: 48,
object: "secret key".to_string(),
object: "withdrawal request zkp instance".to_string(),
});
}
let com_bytes: [u8; 48] = bytes[..48].try_into().unwrap();
@@ -5,7 +5,7 @@ use std::convert::TryFrom;
use std::convert::TryInto;
use bls12_381::{G1Projective, G2Projective, Scalar};
use group::Curve;
use group::{Curve, GroupEncoding};
use crate::error::{CompactEcashError, Result};
use crate::scheme::aggregation::aggregate_verification_keys;
+3 -3
View File
@@ -11,7 +11,7 @@ use crate::scheme::Wallet;
use crate::utils::hash_to_scalar;
pub struct PayInfo {
info: [u8; 32],
pub(crate) info: [u8; 32],
}
pub fn pseudorandom_fgv(params: &Parameters, v: Scalar, l: u64) -> G1Projective {
@@ -87,7 +87,7 @@ pub fn spend(params: &Parameters, wallet: &Wallet, verification_key: &Verificati
let spendWitness = SpendWitness {
attributes,
r: sign_blinding_factor,
l: wallet.l(),
l: Scalar::from(wallet.l()),
o_a,
o_c,
o_d,
@@ -96,7 +96,7 @@ pub fn spend(params: &Parameters, wallet: &Wallet, verification_key: &Verificati
o_mu,
o_lambda,
};
let zkp = SpendProof::construct(&params, &spendInstance, &spendWitness);
let zkp = SpendProof::construct(&params, &spendInstance, &spendWitness, &verification_key, R);
// output pay and updated wallet