use bn::BigNumber;
use cl::*;
use cl::constants::{LARGE_E_START_VALUE, ITERATION};
use cl::helpers::*;
use errors::prelude::*;
use std::collections::BTreeSet;
use std::iter::FromIterator;
use utils::get_hash_as_int;
pub struct Verifier {}
impl Verifier {
pub fn new_sub_proof_request_builder() -> IndyCryptoResult<SubProofRequestBuilder> {
let res = SubProofRequestBuilder::new()?;
Ok(res)
}
pub fn new_proof_verifier() -> IndyCryptoResult<ProofVerifier> {
Ok(ProofVerifier {
credentials: Vec::new(),
})
}
}
#[derive(Debug)]
pub struct ProofVerifier {
credentials: Vec<VerifiableCredential>,
}
impl ProofVerifier {
pub fn add_sub_proof_request(&mut self,
sub_proof_request: &SubProofRequest,
credential_schema: &CredentialSchema,
non_credential_schema: &NonCredentialSchema,
credential_pub_key: &CredentialPublicKey,
rev_key_pub: Option<&RevocationKeyPublic>,
rev_reg: Option<&RevocationRegistry>) -> IndyCryptoResult<()> {
ProofVerifier::_check_add_sub_proof_request_params_consistency(sub_proof_request, credential_schema)?;
self.credentials.push(VerifiableCredential {
pub_key: credential_pub_key.clone()?,
sub_proof_request: sub_proof_request.clone(),
credential_schema: credential_schema.clone(),
non_credential_schema: non_credential_schema.clone(),
rev_key_pub: rev_key_pub.map(Clone::clone),
rev_reg: rev_reg.map(Clone::clone)
});
Ok(())
}
pub fn verify(&self,
proof: &Proof,
nonce: &Nonce) -> IndyCryptoResult<bool> {
trace!("ProofVerifier::verify: >>> proof: {:?}, nonce: {:?}", proof, nonce);
ProofVerifier::_check_verify_params_consistency(&self.credentials, proof)?;
let mut tau_list: Vec<Vec<u8>> = Vec::new();
assert_eq!(proof.proofs.len(), self.credentials.len());
for idx in 0..proof.proofs.len() {
let proof_item = &proof.proofs[idx];
let credential = &self.credentials[idx];
if let (Some(non_revocation_proof), Some(cred_rev_pub_key), Some(rev_reg), Some(rev_key_pub)) = (proof_item.non_revoc_proof.as_ref(),
credential.pub_key.r_key.as_ref(),
credential.rev_reg.as_ref(),
credential.rev_key_pub.as_ref()) {
tau_list.extend_from_slice(
&ProofVerifier::_verify_non_revocation_proof(&cred_rev_pub_key,
&rev_reg,
&rev_key_pub,
&proof.aggregated_proof.c_hash,
&non_revocation_proof)?.as_slice()?
);
};
tau_list.append_vec(
&ProofVerifier::_verify_primary_proof(&credential.pub_key.p_key,
&proof.aggregated_proof.c_hash,
&proof_item.primary_proof,
&credential.credential_schema,
&credential.non_credential_schema,
&credential.sub_proof_request)?
)?;
}
let mut values: Vec<Vec<u8>> = Vec::new();
values.extend_from_slice(&tau_list);
values.extend_from_slice(&proof.aggregated_proof.c_list);
values.push(nonce.to_bytes()?);
let c_hver = get_hash_as_int(&values)?;
info!(target: "anoncreds_service", "Verifier verify proof -> done");
let valid = c_hver == proof.aggregated_proof.c_hash;
trace!("ProofVerifier::verify: <<< valid: {:?}", valid);
Ok(valid)
}
fn _check_add_sub_proof_request_params_consistency(sub_proof_request: &SubProofRequest,
cred_schema: &CredentialSchema) -> IndyCryptoResult<()> {
trace!("ProofVerifier::_check_add_sub_proof_request_params_consistency: >>> sub_proof_request: {:?}, cred_schema: {:?}", sub_proof_request, cred_schema);
if sub_proof_request.revealed_attrs.difference(&cred_schema.attrs).count() != 0 {
return Err(err_msg(IndyCryptoErrorKind::InvalidStructure, "Credential doesn't contain requested attribute"));
}
let predicates_attrs =
sub_proof_request.predicates.iter()
.map(|predicate| predicate.attr_name.clone())
.collect::<BTreeSet<String>>();
if predicates_attrs.difference(&cred_schema.attrs).count() != 0 {
return Err(err_msg(IndyCryptoErrorKind::InvalidStructure, "Credential doesn't contain attribute requested in predicate"));
}
trace!("ProofVerifier::_check_add_sub_proof_request_params_consistency: <<<");
Ok(())
}
fn _check_verify_params_consistency(credentials: &Vec<VerifiableCredential>,
proof: &Proof) -> IndyCryptoResult<()> {
trace!("ProofVerifier::_check_verify_params_consistency: >>> credentials: {:?}, proof: {:?}", credentials, proof);
assert_eq!(proof.proofs.len(), credentials.len());
for idx in 0..proof.proofs.len() {
let proof_for_credential = &proof.proofs[idx];
let credential = &credentials[idx];
let proof_revealed_attrs = BTreeSet::from_iter(proof_for_credential.primary_proof.eq_proof.revealed_attrs.keys().cloned());
if proof_revealed_attrs != credential.sub_proof_request.revealed_attrs {
return Err(err_msg(IndyCryptoErrorKind::ProofRejected, "Proof revealed attributes not correspond to requested attributes"));
}
let proof_predicates =
proof_for_credential.primary_proof.ge_proofs.iter()
.map(|ge_proof| ge_proof.predicate.clone())
.collect::<BTreeSet<Predicate>>();
if proof_predicates != credential.sub_proof_request.predicates {
return Err(err_msg(IndyCryptoErrorKind::ProofRejected, "Proof predicates not correspond to requested predicates"));
}
}
trace!("ProofVerifier::_check_verify_params_consistency: <<<");
Ok(())
}
fn _verify_primary_proof(p_pub_key: &CredentialPrimaryPublicKey,
c_hash: &BigNumber,
primary_proof: &PrimaryProof,
cred_schema: &CredentialSchema,
non_cred_schema: &NonCredentialSchema,
sub_proof_request: &SubProofRequest) -> IndyCryptoResult<Vec<BigNumber>> {
trace!("ProofVerifier::_verify_primary_proof: >>> p_pub_key: {:?}, c_hash: {:?}, primary_proof: {:?}, cred_schema: {:?}, sub_proof_request: {:?}",
p_pub_key, c_hash, primary_proof, cred_schema, sub_proof_request);
let mut t_hat: Vec<BigNumber> = ProofVerifier::_verify_equality(p_pub_key,
&primary_proof.eq_proof,
c_hash,
cred_schema,
non_cred_schema,
sub_proof_request)?;
for ge_proof in primary_proof.ge_proofs.iter() {
t_hat.append(&mut ProofVerifier::_verify_ge_predicate(p_pub_key, ge_proof, c_hash)?)
}
trace!("ProofVerifier::_verify_primary_proof: <<< t_hat: {:?}", t_hat);
Ok(t_hat)
}
fn _verify_equality(p_pub_key: &CredentialPrimaryPublicKey,
proof: &PrimaryEqualProof,
c_hash: &BigNumber,
cred_schema: &CredentialSchema,
non_cred_schema: &NonCredentialSchema,
sub_proof_request: &SubProofRequest) -> IndyCryptoResult<Vec<BigNumber>> {
trace!("ProofVerifier::_verify_equality: >>> p_pub_key: {:?}, proof: {:?}, c_hash: {:?}, cred_schema: {:?}, sub_proof_request: {:?}",
p_pub_key, proof, c_hash, cred_schema, sub_proof_request);
let unrevealed_attrs = cred_schema
.attrs
.union(&non_cred_schema.attrs)
.cloned()
.collect::<BTreeSet<String>>()
.difference(&sub_proof_request.revealed_attrs)
.cloned()
.collect::<HashSet<String>>();
let t1: BigNumber = calc_teq(&p_pub_key, &proof.a_prime, &proof.e, &proof.v, &proof.m, &proof.m2, &unrevealed_attrs)?;
let mut ctx = BigNumber::new_context()?;
let mut rar = proof.a_prime.mod_exp(&LARGE_E_START_VALUE, &p_pub_key.n, Some(&mut ctx))?;
for (attr, encoded_value) in &proof.revealed_attrs {
let cur_r = p_pub_key.r.get(attr)
.ok_or(err_msg(IndyCryptoErrorKind::ProofRejected, format!("Value by key '{}' not found in pk.r", attr)))?;
rar = cur_r
.mod_exp(encoded_value, &p_pub_key.n, Some(&mut ctx))?
.mod_mul(&rar, &p_pub_key.n, Some(&mut ctx))?;
}
let t2: BigNumber = p_pub_key.z
.mod_div(&rar, &p_pub_key.n, Some(&mut ctx))?
.inverse(&p_pub_key.n, Some(&mut ctx))?
.mod_exp(&c_hash, &p_pub_key.n, Some(&mut ctx))?;
let t: BigNumber = t1.mod_mul(&t2, &p_pub_key.n, Some(&mut ctx))?;
trace!("ProofVerifier::_verify_equality: <<< t: {:?}", t);
Ok(vec![t])
}
fn _verify_ge_predicate(p_pub_key: &CredentialPrimaryPublicKey,
proof: &PrimaryPredicateGEProof,
c_hash: &BigNumber) -> IndyCryptoResult<Vec<BigNumber>> {
trace!("ProofVerifier::_verify_ge_predicate: >>> p_pub_key: {:?}, proof: {:?}, c_hash: {:?}", p_pub_key, proof, c_hash);
let mut ctx = BigNumber::new_context()?;
let mut tau_list = calc_tge(&p_pub_key, &proof.u, &proof.r, &proof.mj,
&proof.alpha, &proof.t)?;
for i in 0..ITERATION {
let cur_t = proof.t.get(&i.to_string())
.ok_or(err_msg(IndyCryptoErrorKind::ProofRejected, format!("Value by key '{}' not found in proof.t", i)))?;
tau_list[i] = cur_t
.mod_exp(&c_hash, &p_pub_key.n, Some(&mut ctx))?
.inverse(&p_pub_key.n, Some(&mut ctx))?
.mod_mul(&tau_list[i], &p_pub_key.n, Some(&mut ctx))?;
}
let delta = proof.t.get("DELTA")
.ok_or(err_msg(IndyCryptoErrorKind::ProofRejected, format!("Value by key '{}' not found in proof.t", "DELTA")))?;
tau_list[ITERATION] = p_pub_key.z
.mod_exp(&BigNumber::from_dec(&proof.predicate.value.to_string())?,
&p_pub_key.n, Some(&mut ctx))?
.mul(&delta, Some(&mut ctx))?
.mod_exp(&c_hash, &p_pub_key.n, Some(&mut ctx))?
.inverse(&p_pub_key.n, Some(&mut ctx))?
.mod_mul(&tau_list[ITERATION], &p_pub_key.n, Some(&mut ctx))?;
tau_list[ITERATION + 1] = delta
.mod_exp(&c_hash, &p_pub_key.n, Some(&mut ctx))?
.inverse(&p_pub_key.n, Some(&mut ctx))?
.mod_mul(&tau_list[ITERATION + 1], &p_pub_key.n, Some(&mut ctx))?;
trace!("ProofVerifier::_verify_ge_predicate: <<< tau_list: {:?},", tau_list);
Ok(tau_list)
}
fn _verify_non_revocation_proof(r_pub_key: &CredentialRevocationPublicKey,
rev_reg: &RevocationRegistry,
rev_key_pub: &RevocationKeyPublic,
c_hash: &BigNumber, proof: &NonRevocProof) -> IndyCryptoResult<NonRevocProofTauList> {
trace!("ProofVerifier::_verify_non_revocation_proof: >>> r_pub_key: {:?}, rev_reg: {:?}, rev_key_pub: {:?}, c_hash: {:?}",
r_pub_key, rev_reg, rev_key_pub, c_hash);
let ch_num_z = bignum_to_group_element(&c_hash)?;
let t_hat_expected_values = create_tau_list_expected_values(r_pub_key, rev_reg, rev_key_pub, &proof.c_list)?;
let t_hat_calc_values = create_tau_list_values(&r_pub_key, rev_reg, &proof.x_list, &proof.c_list)?;
let non_revoc_proof_tau_list = Ok(NonRevocProofTauList {
t1: t_hat_expected_values.t1.mul(&ch_num_z)?.add(&t_hat_calc_values.t1)?,
t2: t_hat_expected_values.t2.mul(&ch_num_z)?.add(&t_hat_calc_values.t2)?,
t3: t_hat_expected_values.t3.pow(&ch_num_z)?.mul(&t_hat_calc_values.t3)?,
t4: t_hat_expected_values.t4.pow(&ch_num_z)?.mul(&t_hat_calc_values.t4)?,
t5: t_hat_expected_values.t5.mul(&ch_num_z)?.add(&t_hat_calc_values.t5)?,
t6: t_hat_expected_values.t6.mul(&ch_num_z)?.add(&t_hat_calc_values.t6)?,
t7: t_hat_expected_values.t7.pow(&ch_num_z)?.mul(&t_hat_calc_values.t7)?,
t8: t_hat_expected_values.t8.pow(&ch_num_z)?.mul(&t_hat_calc_values.t8)?
});
trace!("ProofVerifier::_verify_non_revocation_proof: <<< non_revoc_proof_tau_list: {:?}", non_revoc_proof_tau_list);
non_revoc_proof_tau_list
}
}
#[cfg(test)]
mod tests {
use super::*;
use cl::prover;
use cl::issuer;
use cl::helpers::MockHelper;
use cl::prover::mocks::*;
#[test]
fn sub_proof_request_builder_works() {
let mut sub_proof_request_builder = Verifier::new_sub_proof_request_builder().unwrap();
sub_proof_request_builder.add_revealed_attr("name").unwrap();
sub_proof_request_builder.add_predicate("age", "GE", 18).unwrap();
let sub_proof_request = sub_proof_request_builder.finalize().unwrap();
assert!(sub_proof_request.revealed_attrs.contains("name"));
assert!(sub_proof_request.predicates.contains(&predicate()));
}
#[test]
fn verify_equality_works() {
MockHelper::inject();
let proof = prover::mocks::eq_proof();
let pk = issuer::mocks::credential_primary_public_key();
let c_h = prover::mocks::aggregated_proof().c_hash;
let credential_schema = issuer::mocks::credential_schema();
let non_credential_schema = issuer::mocks::non_credential_schema();
let mut sub_proof_request_builder = SubProofRequestBuilder::new().unwrap();
sub_proof_request_builder.add_revealed_attr("name").unwrap();
let sub_proof_request = sub_proof_request_builder.finalize().unwrap();
let res: Vec<BigNumber> = ProofVerifier::_verify_equality(&pk,
&proof,
&c_h,
&credential_schema,
&non_credential_schema,
&sub_proof_request).unwrap();
assert_eq!("10403187904873314760355557832761590691431383521745031865309573910963034393207684\
41047372720051528347747837647360259125725910627967862485202935551931564829193622679374932738\
38474536597850351434049013891806846939373481702013509894344027659392557687896251802916259781\
84555673228742169810564578048461551461925810052930346018787363753466820600660809185539201223\
71561407375323615559370420617674817058682033406887804922024342182995444044012636448897449995\
96623718830501291018016504024850859488898905605533676936340030965601041522317339491952524844\
02507347769428679283112853202405399796966635008669186194259851326316679551259", res[0].to_dec().unwrap());
}
#[test]
fn _verify_ge_predicate_works() {
MockHelper::inject();
let proof = prover::mocks::ge_proof();
let c_h = prover::mocks::aggregated_proof().c_hash;
let pk = issuer::mocks::credential_primary_public_key();
let res = ProofVerifier::_verify_ge_predicate(&pk, &proof, &c_h);
assert!(res.is_ok());
let res_data = res.unwrap();
assert_eq!("84541983257221862363846490076513159323178083291858042421207690118109227097470776\
29156584847233795772635909150135300090254032895037949890518860393886507672431721432085454991\
53093207263594616249619617338381693555232209880961750666056680810026822527599168269456730020\
01231825064670095844788135102734720995698848664953286323041296412437988472201525915887801570\
70103470323302606738147041031249783093273756323937754190996658020897337906239502331775611703\
28042970307095658890209337238786401127759306357959942690001365403300148843097814151882478353\
39418932462384016593481929101948092657508460688911105398322543841514412679282", res_data[0].to_dec().unwrap());
assert_eq!("84541983257221862363846490076513159323178083291858042421207690118109227097470776\
29156584847233795772635909150135300090254032895037949890518860393886507672431721432085454991\
53093207263594616249619617338381693555232209880961750666056680810026822527599168269456730020\
01231825064670095844788135102734720995698848664953286323041296412437988472201525915887801570\
70103470323302606738147041031249783093273756323937754190996658020897337906239502331775611703\
28042970307095658890209337238786401127759306357959942690001365403300148843097814151882478353\
39418932462384016593481929101948092657508460688911105398322543841514412679282", res_data[4].to_dec().unwrap());
assert_eq!("71576740094469616050175125038612941221466947853166771156257978699698137573095744\
20081189100581220746619329202518959516574932458476055705176224361367551303754232635252988973\
23789904575729089031680343784068658206913548928748946934732765157510452464211110112604384315\
16865750528792129415255282372242857723274819466930397323134722222564785435619193280367926994\
59191029832881324878202293930994818463297709055310139101500199217390179488337854210925404890\
00403016403129020563799240705009712476150627783447048219852434435047969447195784507059403459\
40533745092900800249667587825786217899894277583562804465078452786585349967293", res_data[5].to_dec().unwrap());
}
}