Fix bug in the issuance verification

This commit is contained in:
aniampio
2022-03-23 16:43:59 +00:00
parent 0c1cdc4b63
commit 5b5bbc2a3d
7 changed files with 99 additions and 83 deletions
+45 -45
View File
@@ -3,8 +3,8 @@ use std::convert::TryFrom;
use std::convert::TryInto;
use bls12_381::{G1Affine, G1Projective, Scalar};
use digest::Digest;
use digest::generic_array::typenum::Unsigned;
use digest::Digest;
use group::GroupEncoding;
use itertools::izip;
use sha2::Sha256;
@@ -18,10 +18,10 @@ type ChallengeDigest = Sha256;
/// Generates a Scalar [or Fp] challenge by hashing a number of elliptic curve points.
fn compute_challenge<D, I, B>(iter: I) -> Scalar
where
D: Digest,
I: Iterator<Item=B>,
B: AsRef<[u8]>,
where
D: Digest,
I: Iterator<Item = B>,
B: AsRef<[u8]>,
{
let mut h = D::new();
for point_representation in iter {
@@ -49,8 +49,8 @@ fn produce_response(witness_replacement: &Scalar, challenge: &Scalar, secret: &S
// note: it's caller's responsibility to ensure witnesses.len() = secrets.len()
fn produce_responses<S>(witnesses: &[Scalar], challenge: &Scalar, secrets: &[S]) -> Vec<Scalar>
where
S: Borrow<Scalar>,
where
S: Borrow<Scalar>,
{
debug_assert_eq!(witnesses.len(), secrets.len());
@@ -91,16 +91,12 @@ impl TryFrom<&[u8]> for WithdrawalReqInstance {
let com_bytes: [u8; 48] = bytes[..48].try_into().unwrap();
let com = try_deserialize_g1_projective(
&com_bytes,
CompactEcashError::Deserialization(
"Failed to deserialize com".to_string(),
),
CompactEcashError::Deserialization("Failed to deserialize com".to_string()),
)?;
let h_bytes: [u8; 48] = bytes[48..96].try_into().unwrap();
let h = try_deserialize_g1_projective(
&h_bytes,
CompactEcashError::Deserialization(
"Failed to deserialize h".to_string(),
),
CompactEcashError::Deserialization("Failed to deserialize h".to_string()),
)?;
let pc_coms_len = u64::from_le_bytes(bytes[96..104].try_into().unwrap());
let actual_pc_coms_len = (bytes.len() - 152) / 48;
@@ -191,10 +187,10 @@ impl WithdrawalReqProof {
// compute zkp commitments for each instance
let zkcm_com = params.gen1() * r_com_opening
+ r_attributes
.iter()
.zip(params.gammas().iter())
.map(|(rm_i, gamma_i)| gamma_i * rm_i)
.sum::<G1Projective>();
.iter()
.zip(params.gammas().iter())
.map(|(rm_i, gamma_i)| gamma_i * rm_i)
.sum::<G1Projective>();
let zkcm_pedcom = r_pedcom_openings
.iter()
@@ -216,7 +212,6 @@ impl WithdrawalReqProof {
.map(|cm| cm.to_bytes())
.collect::<Vec<_>>();
println!("Zk commitments to com {:?}", zkcm_com.to_bytes());
// compute zkp challenge using g1, gammas, c, h, c1, c2, c3, zk commitments
let challenge = compute_challenge::<ChallengeDigest, _, _>(
std::iter::once(params.gen1().to_bytes().as_ref())
@@ -228,11 +223,7 @@ impl WithdrawalReqProof {
);
// compute response
let response_opening = produce_response(
&r_com_opening,
&challenge,
&witness.com_opening,
);
let response_opening = produce_response(&r_com_opening, &challenge, &witness.com_opening);
let response_openings = produce_responses(
&r_pedcom_openings,
&challenge,
@@ -257,20 +248,24 @@ impl WithdrawalReqProof {
let zkcm_com = instance.com * self.challenge
+ params.gen1() * self.response_opening
+ self
.response_attributes
.iter()
.zip(params.gammas().iter())
.map(|(m_i, gamma_i)| gamma_i * m_i)
.sum::<G1Projective>();
.response_attributes
.iter()
.zip(params.gammas().iter())
.map(|(m_i, gamma_i)| gamma_i * m_i)
.sum::<G1Projective>();
let zkcm_pedcom = izip!(
instance.pc_coms.iter(),
self.response_openings.iter(),
self.response_attributes.iter())
.map(|(cm_j, resp_o_j, resp_m_j)| cm_j * self.challenge + params.gen1() * resp_o_j + instance.h * resp_m_j)
.collect::<Vec<_>>();
self.response_attributes.iter()
)
.map(|(cm_j, resp_o_j, resp_m_j)| {
cm_j * self.challenge + params.gen1() * resp_o_j + instance.h * resp_m_j
})
.collect::<Vec<_>>();
let zk_commitment_user_sk = instance.pk_user.pk * self.challenge + params.gen1() * self.response_attributes[0];
let zk_commitment_user_sk =
instance.pk_user.pk * self.challenge + params.gen1() * self.response_attributes[0];
// covert to bytes
let gammas_bytes = params
@@ -284,8 +279,6 @@ impl WithdrawalReqProof {
.map(|cm| cm.to_bytes())
.collect::<Vec<_>>();
println!("Zk commitments to com Vfy {:?}", zkcm_com.to_bytes());
// recompute zkp challenge
let challenge = compute_challenge::<ChallengeDigest, _, _>(
std::iter::once(params.gen1().to_bytes().as_ref())
@@ -296,8 +289,6 @@ impl WithdrawalReqProof {
.chain(std::iter::once(zk_commitment_user_sk.to_bytes().as_ref())),
);
println!("Original challenge: {:?}", self.challenge);
println!("Recomputed challenge: {:?}", challenge);
challenge == self.challenge
}
}
@@ -318,8 +309,14 @@ mod tests {
let instance = WithdrawalReqInstance {
com: G1Projective::random(&mut rng),
h: G1Projective::random(&mut rng),
pc_coms: vec![G1Projective::random(&mut rng), G1Projective::random(&mut rng), G1Projective::random(&mut rng)],
pk_user: PublicKeyUser { pk: params.gen1() * params.random_scalar() },
pc_coms: vec![
G1Projective::random(&mut rng),
G1Projective::random(&mut rng),
G1Projective::random(&mut rng),
],
pk_user: PublicKeyUser {
pk: params.gen1() * params.random_scalar(),
},
};
let instance_bytes = instance.to_bytes();
@@ -332,17 +329,20 @@ mod tests {
let mut rng = thread_rng();
let params = Parameters::new().unwrap();
let sk = params.random_scalar();
let pk_user = PublicKeyUser { pk: params.gen1() * sk };
let pk_user = PublicKeyUser {
pk: params.gen1() * sk,
};
let v = params.random_scalar();
let t = params.random_scalar();
let attr = vec![sk, v, t];
let com_opening = params.random_scalar();
let com = params.gen1() * com_opening + attr
.iter()
.zip(params.gammas())
.map(|(&m, gamma)| gamma * m)
.sum::<G1Projective>();
let com = params.gen1() * com_opening
+ attr
.iter()
.zip(params.gammas())
.map(|(&m, gamma)| gamma * m)
.sum::<G1Projective>();
let h = hash_g1(com.to_bytes());
let pc_openings = params.n_random_scalars(attr.len());
@@ -367,4 +367,4 @@ mod tests {
let zk_proof = WithdrawalReqProof::construct(&params, &instance, &witness);
assert!(zk_proof.verify(&params, &instance))
}
}
}
@@ -6,11 +6,11 @@ use bls12_381::{G1Projective, G2Projective, Scalar};
use crate::error::{CompactEcashError, Result};
use crate::scheme::setup::Parameters;
use crate::scheme::SignerIndex;
use crate::utils::Polynomial;
use crate::utils::{
try_deserialize_g1_projective, try_deserialize_g2_projective, try_deserialize_scalar,
try_deserialize_scalar_vec,
};
use crate::utils::Polynomial;
#[derive(Debug, PartialEq, Clone)]
pub struct SecretKeyAuth {
@@ -203,7 +203,9 @@ impl KeyPairAuth {
self.secret_key.clone()
}
pub fn verification_key(&self) -> VerificationKeyAuth { self.verification_key.clone() }
pub fn verification_key(&self) -> VerificationKeyAuth {
self.verification_key.clone()
}
}
pub struct KeyPairUser {
@@ -291,4 +293,4 @@ pub fn ttp_keygen(
.collect();
Ok(keypairs)
}
}
+1 -1
View File
@@ -20,4 +20,4 @@ pub struct Wallet {
sig: Signature,
v: Scalar,
idx: Option<SignerIndex>,
}
}
+1 -2
View File
@@ -1,4 +1,4 @@
use bls12_381::{G1Affine, G2Affine, G2Prepared, Scalar};
use bls12_381::{G1Affine, G1Projective, G2Affine, G2Prepared, Scalar};
use ff::Field;
use group::{Curve, GroupEncoding};
use rand::thread_rng;
@@ -47,7 +47,6 @@ impl Parameters {
pub(crate) fn gammas(&self) -> &Vec<G1Affine> {
&self.gammas
}
pub fn random_scalar(&self) -> Scalar {
// lazily-initialized thread-local random number generator, seeded by the system
@@ -24,7 +24,6 @@ pub struct RequestInfo {
t: Scalar,
}
pub fn withdrawal_request(
params: &Parameters,
sk_user: &SecretKeyUser,
@@ -35,7 +34,8 @@ pub fn withdrawal_request(
let attributes = vec![sk_user.sk, v, t];
let gammas = params.gammas();
let com_opening = params.random_scalar();
let com = params.gen1() * com_opening + attributes
let com = params.gen1() * com_opening
+ attributes
.iter()
.zip(gammas)
.map(|(&m, gamma)| gamma * m)
@@ -58,7 +58,9 @@ pub fn withdrawal_request(
com,
h: com_hash,
pc_coms: pc_coms.clone(),
pk_user: PublicKeyUser { pk: params.gen1() * sk_user.sk },
pk_user: PublicKeyUser {
pk: params.gen1() * sk_user.sk,
},
};
let witness = WithdrawalReqWitness {
@@ -124,20 +126,25 @@ pub fn issue_wallet(
Ok(BlindedSignature(h, sig))
}
pub fn issue_verify(params: &Parameters, vk_auth: &VerificationKeyAuth, sk_user: &SecretKeyUser, blind_signature: &BlindedSignature, req_info: &RequestInfo) -> Result<Wallet> {
pub fn issue_verify(
params: &Parameters,
vk_auth: &VerificationKeyAuth,
sk_user: &SecretKeyUser,
blind_signature: &BlindedSignature,
req_info: &RequestInfo,
) -> Result<Wallet> {
// Parse the blinded signature
let h = blind_signature.0;
let c = blind_signature.1;
// Verify the integrity of the reponse from the authority
// Verify the integrity of the response from the authority
if !(req_info.com_hash == h) {
return Err(CompactEcashError::IssuanceVfy(
"Failed to verify the proof of knowledge".to_string(),
"Integrity verification failed".to_string(),
));
}
// Unblind the blinded signature
// Unblind the blinded signature on the partial wallet
let blinding_removers = vk_auth
.beta_g1
.iter()
@@ -148,7 +155,7 @@ pub fn issue_verify(params: &Parameters, vk_auth: &VerificationKeyAuth, sk_user:
let unblinded_c = c - blinding_removers;
// Verify the signature correctness on the wallet share
let attr = vec![sk_user.sk, req_info.v];
let attr = vec![sk_user.sk, req_info.v, req_info.t];
let signed_attributes = attr
.iter()
@@ -167,10 +174,8 @@ pub fn issue_verify(params: &Parameters, vk_auth: &VerificationKeyAuth, sk_user:
));
}
Ok(Wallet {
sig: Signature(h,
unblinded_c),
sig: Signature(h, unblinded_c),
v: req_info.v,
idx: None,
})
+16 -14
View File
@@ -1,10 +1,12 @@
use itertools::izip;
use crate::error::CompactEcashError;
use crate::scheme::keygen::{generate_keypair_user, PublicKeyUser, SecretKeyUser, ttp_keygen, VerificationKeyAuth};
use crate::scheme::keygen::{
generate_keypair_user, ttp_keygen, PublicKeyUser, SecretKeyUser, VerificationKeyAuth,
};
use crate::scheme::setup::Parameters;
use crate::scheme::Wallet;
use crate::scheme::withdrawal::{issue_verify, issue_wallet, withdrawal_request};
use crate::scheme::Wallet;
use crate::VerificationKey;
#[test]
@@ -22,21 +24,21 @@ fn main() -> Result<(), CompactEcashError> {
let mut wallet_blinded_signatures = Vec::new();
for auth_keypair in authorities_keypairs {
let blind_signature = issue_wallet(&params, auth_keypair.secret_key(), user_keypair.public_key(), &req);
let blind_signature = issue_wallet(
&params,
auth_keypair.secret_key(),
user_keypair.public_key(),
&req,
);
wallet_blinded_signatures.push(blind_signature.unwrap());
}
// let unblinded_wallet_shares: Vec<Wallet> =
// izip!(wallet_blinded_signatures.iter(), verification_keys_auth.iter())
// .map(|(w, vk)| {
// issue_verify(&params,
// vk,
// &user_keypair.secret_key(),
// w,
// &req_info)
// .unwrap()
// })
// .collect();
let unblinded_wallet_shares: Vec<Wallet> = izip!(
wallet_blinded_signatures.iter(),
verification_keys_auth.iter()
)
.map(|(w, vk)| issue_verify(&params, vk, &user_keypair.secret_key(), w, &req_info).unwrap())
.collect();
Ok(())
}
+14 -6
View File
@@ -6,8 +6,10 @@ use core::ops::Mul;
use std::convert::TryInto;
use std::ops::Neg;
use bls12_381::{G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, multi_miller_loop, Scalar};
use bls12_381::hash_to_curve::{ExpandMsgXmd, HashToCurve, HashToField};
use bls12_381::{
multi_miller_loop, G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, Scalar,
};
use ff::Field;
use group::Group;
@@ -83,9 +85,9 @@ pub(crate) fn perform_lagrangian_interpolation_at_origin<T>(
points: &[SignerIndex],
values: &[T],
) -> Result<T>
where
T: Sum,
for<'a> &'a T: Mul<Scalar, Output=T>,
where
T: Sum,
for<'a> &'a T: Mul<Scalar, Output = T>,
{
if points.is_empty() || values.is_empty() {
return Err(CompactEcashError::Interpolation(
@@ -165,13 +167,19 @@ pub fn try_deserialize_scalar(bytes: &[u8; 32], err: CompactEcashError) -> Resul
Into::<Option<Scalar>>::into(Scalar::from_bytes(bytes)).ok_or(err)
}
pub fn try_deserialize_g1_projective(bytes: &[u8; 48], err: CompactEcashError) -> Result<G1Projective> {
pub fn try_deserialize_g1_projective(
bytes: &[u8; 48],
err: CompactEcashError,
) -> Result<G1Projective> {
Into::<Option<G1Affine>>::into(G1Affine::from_compressed(bytes))
.ok_or(err)
.map(G1Projective::from)
}
pub fn try_deserialize_g2_projective(bytes: &[u8; 96], err: CompactEcashError) -> Result<G2Projective> {
pub fn try_deserialize_g2_projective(
bytes: &[u8; 96],
err: CompactEcashError,
) -> Result<G2Projective> {
Into::<Option<G2Affine>>::into(G2Affine::from_compressed(bytes))
.ok_or(err)
.map(G2Projective::from)