Fix bug in the issuance verification
This commit is contained in:
@@ -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(¶ms, &instance, &witness);
|
||||
assert!(zk_proof.verify(¶ms, &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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,4 +20,4 @@ pub struct Wallet {
|
||||
sig: Signature,
|
||||
v: Scalar,
|
||||
idx: Option<SignerIndex>,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
})
|
||||
|
||||
@@ -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(¶ms, auth_keypair.secret_key(), user_keypair.public_key(), &req);
|
||||
let blind_signature = issue_wallet(
|
||||
¶ms,
|
||||
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(¶ms,
|
||||
// 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(¶ms, vk, &user_keypair.secret_key(), w, &req_info).unwrap())
|
||||
.collect();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user