use bn::BigNumber;
use cl::*;
use cl::constants::{LARGE_E_START, ITERATION, LARGE_NONCE};
use cl::helpers::*;
use errors::IndyCryptoError;
use std::collections::{HashMap, HashSet};
use std::iter::FromIterator;
pub struct Verifier {}
impl Verifier {
pub fn new_sub_proof_request_builder() -> Result<SubProofRequestBuilder, IndyCryptoError> {
let res = SubProofRequestBuilder::new()?;
Ok(res)
}
pub fn new_nonce() -> Result<Nonce, IndyCryptoError> {
Ok(bn_rand(LARGE_NONCE)?)
}
pub fn new_proof_verifier() -> Result<ProofVerifier, IndyCryptoError> {
Ok(ProofVerifier {
claims: HashMap::new(),
})
}
}
#[derive(Debug)]
pub struct ProofVerifier {
claims: HashMap<String, VerifyClaim>,
}
impl ProofVerifier {
pub fn add_sub_proof_request(&mut self,
key_id: &str,
sub_proof_request: &SubProofRequest,
claim_schema: &ClaimSchema,
issuer_pub_key: &IssuerPublicKey,
rev_reg_pub: Option<&RevocationRegistryPublic>) -> Result<(), IndyCryptoError> {
ProofVerifier::_check_add_sub_proof_request_params_consistency(sub_proof_request, claim_schema)?;
self.claims.insert(key_id.to_string(), VerifyClaim {
pub_key: issuer_pub_key.clone()?,
r_reg: rev_reg_pub.map(Clone::clone),
sub_proof_request: sub_proof_request.clone(),
claim_schema: claim_schema.clone(),
});
Ok(())
}
fn _check_add_sub_proof_request_params_consistency(sub_proof_request: &SubProofRequest, claim_schema: &ClaimSchema) -> Result<(), IndyCryptoError> {
trace!("ProofVerifier::_check_add_sub_proof_request_params_consistency: >>> sub_proof_request: {:?}, claim_schema: {:?}", sub_proof_request, claim_schema);
if sub_proof_request.revealed_attrs.difference(&claim_schema.attrs).count() != 0 {
return Err(IndyCryptoError::InvalidStructure(format!("Claim doesn't contain requested attribute")));
}
let predicates_attrs =
sub_proof_request.predicates.iter()
.map(|predicate| predicate.attr_name.clone())
.collect::<HashSet<String>>();
if predicates_attrs.difference(&claim_schema.attrs).count() != 0 {
return Err(IndyCryptoError::InvalidStructure(format!("Claim doesn't contain attribute requested in predicate")));
}
trace!("ProofVerifier::_check_add_sub_proof_request_params_consistency: <<<");
Ok(())
}
pub fn verify(self,
proof: &Proof,
nonce: &Nonce) -> Result<bool, IndyCryptoError> {
trace!("ProofVerifier::verify: >>> proof: {:?}, nonce: {:?}", proof, nonce);
ProofVerifier::_check_verify_params_consistency(&self.claims, proof)?;
let mut tau_list: Vec<Vec<u8>> = Vec::new();
for (issuer_key_id, proof_item) in &proof.proofs {
let claim = self.claims.get(issuer_key_id)
.ok_or(IndyCryptoError::AnoncredsProofRejected(format!("Schema is not found")))?;
if let (Some(non_revocation_proof), Some(pkr), Some(revoc_reg)) = (proof_item.non_revoc_proof.as_ref(),
claim.pub_key.r_key.as_ref(),
claim.r_reg.as_ref()) {
tau_list.extend_from_slice(
&ProofVerifier::_verify_non_revocation_proof(
&pkr,
&revoc_reg.acc,
&revoc_reg.key,
&proof.aggregated_proof.c_hash,
&non_revocation_proof)?.as_slice()?
);
};
tau_list.append_vec(
&ProofVerifier::_verify_primary_proof(&claim.pub_key.p_key,
&proof.aggregated_proof.c_hash,
&proof_item.primary_proof,
&claim.claim_schema,
&claim.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(&mut 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_verify_params_consistency(claims: &HashMap<String, VerifyClaim>, proof: &Proof) -> Result<(), IndyCryptoError> {
trace!("ProofVerifier::_check_verify_params_consistency: >>> claims: {:?}, proof: {:?}", claims, proof);
for (key_id, claim) in claims {
let proof_for_claim = proof.proofs.get(key_id.as_str()).
ok_or(IndyCryptoError::AnoncredsProofRejected(format!("Proof not found")))?;
let proof_revealed_attrs = HashSet::from_iter(proof_for_claim.primary_proof.eq_proof.revealed_attrs.keys().cloned());
if proof_revealed_attrs != claim.sub_proof_request.revealed_attrs {
return Err(IndyCryptoError::AnoncredsProofRejected(format!("Proof revealed attributes not correspond to requested attributes")));
}
let proof_predicates =
proof_for_claim.primary_proof.ge_proofs.iter()
.map(|ge_proof| ge_proof.predicate.clone())
.collect::<HashSet<Predicate>>();
if proof_predicates != claim.sub_proof_request.predicates {
return Err(IndyCryptoError::AnoncredsProofRejected(format!("Proof predicates not correspond to requested predicates")));
}
}
trace!("ProofVerifier::_check_verify_params_consistency: <<<");
Ok(())
}
fn _verify_primary_proof(issuer_pub_key: &IssuerPrimaryPublicKey, c_hash: &BigNumber,
primary_proof: &PrimaryProof, claim_schema: &ClaimSchema, sub_proof_request: &SubProofRequest) -> Result<Vec<BigNumber>, IndyCryptoError> {
trace!("ProofVerifier::_verify_primary_proof: >>> issuer_pub_key: {:?}, c_hash: {:?}, primary_proof: {:?}, sub_proof_request: {:?}",
issuer_pub_key, c_hash, primary_proof, sub_proof_request);
let mut t_hat: Vec<BigNumber> = ProofVerifier::_verify_equality(issuer_pub_key, &primary_proof.eq_proof, c_hash, claim_schema, sub_proof_request)?;
for ge_proof in primary_proof.ge_proofs.iter() {
t_hat.append(&mut ProofVerifier::_verify_ge_predicate(issuer_pub_key, ge_proof, c_hash)?)
}
trace!("ProofVerifier::_verify_primary_proof: <<< t_hat: {:?}", t_hat);
Ok(t_hat)
}
fn _verify_equality(issuer_pub_key: &IssuerPrimaryPublicKey, proof: &PrimaryEqualProof, c_hash: &BigNumber,
claim_schema: &ClaimSchema, sub_proof_request: &SubProofRequest) -> Result<Vec<BigNumber>, IndyCryptoError> {
trace!("ProofVerifier::_verify_equality: >>> issuer_pub_key: {:?}, proof: {:?}, c_hash: {:?}, claim_schema: {:?}, sub_proof_request: {:?}",
issuer_pub_key, proof, c_hash, claim_schema, sub_proof_request);
let unrevealed_attrs: HashSet<String> =
claim_schema.attrs
.difference(&sub_proof_request.revealed_attrs)
.map(|attr| attr.clone())
.collect::<HashSet<String>>();
let t1: BigNumber = calc_teq(&issuer_pub_key, &proof.a_prime, &proof.e, &proof.v, &proof.m,
&proof.m1, &proof.m2, &unrevealed_attrs)?;
let mut ctx = BigNumber::new_context()?;
let mut rar = BigNumber::from_dec("1")?;
for (attr, encoded_value) in &proof.revealed_attrs {
let cur_r = issuer_pub_key.r.get(attr)
.ok_or(IndyCryptoError::AnoncredsProofRejected(format!("Value by key '{}' not found in pk.r", attr)))?;
rar = cur_r
.mod_exp(encoded_value, &issuer_pub_key.n, Some(&mut ctx))?
.mul(&rar, Some(&mut ctx))?;
}
let tmp: BigNumber =
BigNumber::from_dec("2")?
.exp(
&BigNumber::from_dec(&LARGE_E_START.to_string())?,
Some(&mut ctx)
)?;
rar = proof.a_prime
.mod_exp(&tmp, &issuer_pub_key.n, Some(&mut ctx))?
.mul(&rar, Some(&mut ctx))?;
let t2: BigNumber = issuer_pub_key.z
.mod_div(&rar, &issuer_pub_key.n)?
.mod_exp(&c_hash, &issuer_pub_key.n, Some(&mut ctx))?
.inverse(&issuer_pub_key.n, Some(&mut ctx))?;
let t: BigNumber = t1
.mul(&t2, Some(&mut ctx))?
.modulus(&issuer_pub_key.n, Some(&mut ctx))?;
trace!("ProofVerifier::_verify_equality: <<< t: {:?}", t);
Ok(vec![t])
}
fn _verify_ge_predicate(issuer_pub_key: &IssuerPrimaryPublicKey, proof: &PrimaryPredicateGEProof, c_hash: &BigNumber) -> Result<Vec<BigNumber>, IndyCryptoError> {
trace!("ProofVerifier::_verify_ge_predicate: >>> issuer_pub_key: {:?}, proof: {:?}, c_hash: {:?}", issuer_pub_key, proof, c_hash);
let mut ctx = BigNumber::new_context()?;
let mut tau_list = calc_tge(&issuer_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(IndyCryptoError::AnoncredsProofRejected(format!("Value by key '{}' not found in proof.t", i)))?;
tau_list[i] = cur_t
.mod_exp(&c_hash, &issuer_pub_key.n, Some(&mut ctx))?
.inverse(&issuer_pub_key.n, Some(&mut ctx))?
.mul(&tau_list[i], Some(&mut ctx))?
.modulus(&issuer_pub_key.n, Some(&mut ctx))?;
}
let delta = proof.t.get("DELTA")
.ok_or(IndyCryptoError::AnoncredsProofRejected(format!("Value by key '{}' not found in proof.t", "DELTA")))?;
tau_list[ITERATION] = issuer_pub_key.z
.mod_exp(
&BigNumber::from_dec(&proof.predicate.value.to_string())?,
&issuer_pub_key.n, Some(&mut ctx))?
.mul(&delta, Some(&mut ctx))?
.mod_exp(&c_hash, &issuer_pub_key.n, Some(&mut ctx))?
.inverse(&issuer_pub_key.n, Some(&mut ctx))?
.mul(&tau_list[ITERATION], Some(&mut ctx))?
.modulus(&issuer_pub_key.n, Some(&mut ctx))?;
tau_list[ITERATION + 1] = delta
.mod_exp(&c_hash, &issuer_pub_key.n, Some(&mut ctx))?
.inverse(&issuer_pub_key.n, Some(&mut ctx))?
.mul(&tau_list[ITERATION + 1], Some(&mut ctx))?
.modulus(&issuer_pub_key.n, Some(&mut ctx))?;
trace!("ProofVerifier::_verify_ge_predicate: <<< tau_list: {:?},", tau_list);
Ok(tau_list)
}
pub fn _verify_non_revocation_proof(issuer_r_pub_key: &IssuerRevocationPublicKey,
accum: &RevocationAccumulator,
accum_pk: &RevocationAccumulatorPublicKey,
c_hash: &BigNumber, proof: &NonRevocProof)
-> Result<NonRevocProofTauList, IndyCryptoError> {
trace!("ProofVerifier::_verify_non_revocation_proof: >>> issuer_r_pub_key: {:?}, accum: {:?}, accum_pk: {:?}, c_hash: {:?}",
issuer_r_pub_key, accum, accum_pk, c_hash);
let ch_num_z = bignum_to_group_element(&c_hash)?;
let t_hat_expected_values = create_tau_list_expected_values(issuer_r_pub_key, accum, accum_pk, &proof.c_list)?;
let t_hat_calc_values = create_tau_list_values(&issuer_r_pub_key, &accum, &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_equlity_works() {
MockHelper::inject();
let proof = prover::mocks::eq_proof();
let pk = issuer::mocks::issuer_primary_public_key();
let c_h = prover::mocks::aggregated_proof().c_hash;
let claim_schema = issuer::mocks::claim_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,
&claim_schema,
&sub_proof_request).unwrap();
assert_eq!("7482119769466399985453964851245160858083213139582181384392546015391266465526851030277921408409258064077698298124641650660813004229404233357607661770\
7349015173216066298469796629848379475742662270634373967221781036145898302079498084911189254205359080720863996359684543833466536415829603044441714644215231961048\
8185863374642452252262537639796626459270165235687616182451932827771166420110852842258328296215336523679907850550512281026511049364855879504226754090322982687515\
11838487572303641236062952085251651696655442524160504107798338763119112728565616246769765635577446028951291604888490982944375208275466186869182747994", 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::issuer_primary_public_key();
let res = ProofVerifier::_verify_ge_predicate(&pk, &proof, &c_h);
assert!(res.is_ok());
let res_data = res.unwrap();
assert_eq!("376910366785000888640907068892773445290856982028553183426096623244555347257778101747799882436148347403830024840429617795354387295127009257238001847697728551\
176536093973115809374401318141110098900739722767845936624708107236876761676800627172399726564255634308382367493256717024633900449205720018609556512423317410372608366135\
066533236820567062263706984223659166559990463804265095415860347492428279789699722395246760391390256022639741018088870083311929296796590769109958556654779529301996928547\
78469439162325030246066895851569630345729938981633504514117558420480144828304421708923356898912192737390539479512879411139535", res_data[0].to_dec().unwrap());
assert_eq!("376910366785000888640907068892773445290856982028553183426096623244555347257778101747799882436148347403830024840429617795354387295127009257238001847697728551\
176536093973115809374401318141110098900739722767845936624708107236876761676800627172399726564255634308382367493256717024633900449205720018609556512423317410372608366135\
066533236820567062263706984223659166559990463804265095415860347492428279789699722395246760391390256022639741018088870083311929296796590769109958556654779529301996928547\
78469439162325030246066895851569630345729938981633504514117558420480144828304421708923356898912192737390539479512879411139535", res_data[4].to_dec().unwrap());
assert_eq!("4706530486660795807594696126453392843593312253601667969008027865938669831613255990876876168574341472858634191430502533997053787371484591516484310077682156120\
0343390749927996265246866447155790487554483555192805709960222015718787293872197230832464704800887153568636866026153126587657548580608446574507279965440247754859129693686\
1864273991033137371106324132550175224820164581900030456410773386740196083471393997554706544523739752281900419801521207994038554809091738654313973079882387597672518908535\
80982844825639097363091181044515877489450972963624109587697097258041963985607958610791800500711857115582406526050626576194", res_data[5].to_dec().unwrap());
}
}