diff --git a/anoncreds/protocol/issuer.py b/anoncreds/protocol/issuer.py index 71cfe22..a086d56 100644 --- a/anoncreds/protocol/issuer.py +++ b/anoncreds/protocol/issuer.py @@ -1,13 +1,13 @@ from typing import Dict -from anoncreds.protocol.globals import LARGE_MASTER_SECRET, TYPE_CL +from anoncreds.protocol.globals import LARGE_MASTER_SECRET from anoncreds.protocol.primary.primary_claim_issuer import PrimaryClaimIssuer from anoncreds.protocol.repo.attributes_repo import AttributeRepo from anoncreds.protocol.revocation.accumulators.non_revocation_claim_issuer import \ NonRevocationClaimIssuer from anoncreds.protocol.types import PrimaryClaim, NonRevocationClaim, \ Schema, ID, Claims, ClaimRequest, Attribs, PublicKey, \ - RevocationPublicKey, AccumulatorPublicKey + RevocationPublicKey, AccumulatorPublicKey, ClaimAttributeValues from anoncreds.protocol.utils import strToInt, get_hash_as_int from anoncreds.protocol.wallet.issuer_wallet import IssuerWallet from config.config import cmod @@ -97,7 +97,7 @@ async def revoke(self, schemaId: ID, i): async def issueClaim(self, schemaId: ID, claimRequest: ClaimRequest, iA=None, - i=None) -> Claims: + i=None) -> (Claims, Dict[str, ClaimAttributeValues]): """ Issue a claim for the given user and schema. @@ -120,13 +120,16 @@ async def issueClaim(self, schemaId: ID, claimRequest: ClaimRequest, # TODO this has un-obvious side-effects await self._genContxt(schemaId, iA, claimRequest.userId) - c1 = await self._issuePrimaryClaim(schemaId, attributes, + (c1, claim) = await self._issuePrimaryClaim(schemaId, attributes, claimRequest.U) # TODO re-enable when revocation registry is fully implemented c2 = await self._issueNonRevocationClaim(schemaId, claimRequest.Ur, iA, i) if claimRequest.Ur else None - return Claims(primaryClaim=c1, nonRevocClaim=c2) + + signature = Claims(primaryClaim=c1, nonRevocClaim=c2) + + return (signature, claim) async def issueClaims(self, allClaimRequest: Dict[ID, ClaimRequest]) -> \ Dict[ID, Claims]: @@ -156,7 +159,7 @@ async def _genContxt(self, schemaId: ID, iA, userId): return m2 async def _issuePrimaryClaim(self, schemaId: ID, attributes: Attribs, - U) -> PrimaryClaim: + U) -> (PrimaryClaim, Dict[str, ClaimAttributeValues]): return await self._primaryIssuer.issuePrimaryClaim(schemaId, attributes, U) diff --git a/anoncreds/protocol/primary/primary_claim_issuer.py b/anoncreds/protocol/primary/primary_claim_issuer.py index 07b5b02..3671120 100644 --- a/anoncreds/protocol/primary/primary_claim_issuer.py +++ b/anoncreds/protocol/primary/primary_claim_issuer.py @@ -1,11 +1,12 @@ from anoncreds.protocol.globals import LARGE_VPRIME_PRIME, LARGE_E_START, \ LARGE_E_END_RANGE, LARGE_PRIME from anoncreds.protocol.types import PublicKey, SecretKey, PrimaryClaim, ID, \ - Attribs + Attribs, ClaimAttributeValues from anoncreds.protocol.utils import get_prime_in_range, strToCryptoInteger, \ randomQR from anoncreds.protocol.wallet.issuer_wallet import IssuerWallet from config.config import cmod +from typing import Dict class PrimaryClaimIssuer: @@ -73,7 +74,7 @@ def _genPrime(cls): return prime async def issuePrimaryClaim(self, schemaId: ID, attributes: Attribs, - U) -> PrimaryClaim: + U) -> (PrimaryClaim, Dict[str, ClaimAttributeValues]): u = strToCryptoInteger(U) if isinstance(U, str) else U if not u: @@ -90,8 +91,10 @@ async def issuePrimaryClaim(self, schemaId: ID, attributes: Attribs, A = await self._sign(schemaId, encodedAttrs, vprimeprime, u, e) m2 = await self._wallet.getContextAttr(schemaId) - return PrimaryClaim(attributes._vals, encodedAttrs, m2, A, e, - vprimeprime) + claimAttributes = \ + {attr: ClaimAttributeValues(attributes._vals[attr], encodedAttrs[attr]) for attr in attributes.keys()} + + return (PrimaryClaim(m2, A, e, vprimeprime), claimAttributes) async def _sign(self, schemaId: ID, attrs, v, u, e): pk = await self._wallet.getPublicKey(schemaId) diff --git a/anoncreds/protocol/primary/primary_proof_builder.py b/anoncreds/protocol/primary/primary_proof_builder.py index ff95589..de660c4 100644 --- a/anoncreds/protocol/primary/primary_proof_builder.py +++ b/anoncreds/protocol/primary/primary_proof_builder.py @@ -1,4 +1,4 @@ -from typing import Sequence +from typing import Sequence, Dict from anoncreds.protocol.globals import LARGE_VPRIME, LARGE_MVECT, LARGE_E_START, \ LARGE_ETILDE, \ @@ -8,8 +8,8 @@ from anoncreds.protocol.types import PrimaryClaim, Predicate, PrimaryInitProof, \ PrimaryEqualInitProof, PrimaryPrecicateGEInitProof, PrimaryProof, \ PrimaryEqualProof, PrimaryPredicateGEProof, \ - ID, ClaimInitDataType -from anoncreds.protocol.utils import getUnrevealedAttrs, fourSquares + ID, ClaimInitDataType, ClaimAttributeValues +from anoncreds.protocol.utils import splitRevealedAttrs, fourSquares from anoncreds.protocol.wallet.prover_wallet import ProverWallet from config.config import cmod @@ -40,47 +40,47 @@ class PrimaryProofBuilder: def __init__(self, wallet: ProverWallet): self._wallet = wallet - async def initProof(self, schemaKey, c1: PrimaryClaim, + async def initProof(self, schemaId, c1: PrimaryClaim, revealedAttrs: Sequence[str], predicates: Sequence[Predicate], - m1Tilde, m2Tilde) -> PrimaryInitProof: + m1Tilde, m2Tilde, claimAttributes: Dict[str, ClaimAttributeValues]) -> PrimaryInitProof: if not c1: return None - eqProof = await self._initEqProof(schemaKey, c1, revealedAttrs, - m1Tilde, m2Tilde) + eqProof = await self._initEqProof(schemaId, c1, revealedAttrs, + m1Tilde, m2Tilde, claimAttributes) geProofs = [] for predicate in predicates: - geProof = await self._initGeProof(schemaKey, eqProof, c1, - predicate) + geProof = await self._initGeProof(schemaId, eqProof, c1, + predicate, claimAttributes) geProofs.append(geProof) return PrimaryInitProof(eqProof, geProofs) - async def finalizeProof(self, schemaKey, cH, + async def finalizeProof(self, schemaId, cH, initProof: PrimaryInitProof) -> PrimaryProof: if not initProof: return None cH = cmod.integer(cH) - eqProof = await self._finalizeEqProof(schemaKey, cH, + eqProof = await self._finalizeEqProof(schemaId, cH, initProof.eqProof) geProofs = [] for initGeProof in initProof.geProofs: - geProof = await self._finalizeGeProof(schemaKey, cH, initGeProof, + geProof = await self._finalizeGeProof(schemaId, cH, initGeProof, eqProof) geProofs.append(geProof) return PrimaryProof(eqProof, geProofs) - async def _initEqProof(self, schemaKey, c1: PrimaryClaim, - revealedAttrs: Sequence[str], m1Tilde, m2Tilde) \ + async def _initEqProof(self, schemaId, c1: PrimaryClaim, + revealedAttrs: Sequence[str], m1Tilde, m2Tilde, claimAttributes: Dict[str, ClaimAttributeValues]) \ -> PrimaryEqualInitProof: m2Tilde = m2Tilde if m2Tilde else cmod.integer( cmod.randomBits(LARGE_MVECT)) - unrevealedAttrs = getUnrevealedAttrs(c1.encodedAttrs, revealedAttrs) + revealedAttrs, unrevealedAttrs = splitRevealedAttrs(claimAttributes, [a.name for a in revealedAttrs]) mtilde = self._getMTilde(unrevealedAttrs) Ra = cmod.integer(cmod.randomBits(LARGE_VPRIME)) - pk = await self._wallet.getPublicKey(ID(schemaKey)) + pk = await self._wallet.getPublicKey(ID(schemaId=schemaId)) A, e, v = c1.A, c1.e, c1.v Aprime = A * (pk.S ** Ra) % pk.N @@ -92,7 +92,7 @@ async def _initEqProof(self, schemaKey, c1: PrimaryClaim, Rur = 1 % pk.N for k, value in unrevealedAttrs.items(): - if k in c1.encodedAttrs: + if k in claimAttributes: Rur = Rur * (pk.R[k] ** mtilde[k]) Rur *= pk.Rms ** m1Tilde Rur *= pk.Rctxt ** m2Tilde @@ -105,13 +105,13 @@ async def _initEqProof(self, schemaKey, c1: PrimaryClaim, vprime, mtilde, m1Tilde, m2Tilde, unrevealedAttrs.keys(), revealedAttrs) - async def _initGeProof(self, schemaKey, eqProof: PrimaryEqualInitProof, - c1: PrimaryClaim, predicate: Predicate) \ + async def _initGeProof(self, schemaId, eqProof: PrimaryEqualInitProof, + c1: PrimaryClaim, predicate: Predicate, claimAttributes: Dict[str, ClaimAttributeValues]) \ -> PrimaryPrecicateGEInitProof: # gen U for Delta - pk = await self._wallet.getPublicKey(ID(schemaKey)) + pk = await self._wallet.getPublicKey(ID(schemaId=schemaId)) k, value = predicate.attrName, predicate.value - delta = c1.encodedAttrs[k] - value + delta = claimAttributes[k].encoded - value if delta < 0: raise ValueError("Predicate is not satisfied") @@ -142,23 +142,26 @@ async def _initGeProof(self, schemaKey, eqProof: PrimaryEqualInitProof, return PrimaryPrecicateGEInitProof(CList, TauList, u, utilde, r, rtilde, alphatilde, predicate, T) - async def _finalizeEqProof(self, schemaKey, cH, + async def _finalizeEqProof(self, schemaId, cH, initProof: PrimaryEqualInitProof) -> PrimaryEqualProof: e = initProof.eTilde + (cH * initProof.ePrime) v = initProof.vTilde + (cH * initProof.vPrime) m = {} + + claimAttributes = await self._wallet.getClaimAttributes(ID(schemaId=schemaId)) + for k in initProof.unrevealedAttrs: m[str(k)] = initProof.mTilde[str(k)] + ( - cH * initProof.c1.encodedAttrs[str(k)]) - ms = await self._wallet.getMasterSecret(ID(schemaKey)) + cH * claimAttributes[str(k)].encoded) + ms = await self._wallet.getMasterSecret(ID(schemaId=schemaId)) m1 = initProof.m1Tilde + (cH * ms) m2 = initProof.m2Tilde + (cH * initProof.c1.m2) return PrimaryEqualProof(e, v, m, m1, m2, initProof.Aprime, initProof.revealedAttrs) - async def _finalizeGeProof(self, schemaKey, cH, + async def _finalizeGeProof(self, schemaId, cH, initProof: PrimaryPrecicateGEInitProof, eqProof: PrimaryEqualProof) \ -> PrimaryPredicateGEProof: diff --git a/anoncreds/protocol/primary/primary_proof_verifier.py b/anoncreds/protocol/primary/primary_proof_verifier.py index ffcae1c..12e942b 100644 --- a/anoncreds/protocol/primary/primary_proof_verifier.py +++ b/anoncreds/protocol/primary/primary_proof_verifier.py @@ -1,8 +1,7 @@ from anoncreds.protocol.globals import LARGE_E_START, ITERATIONS, DELTA from anoncreds.protocol.primary.primary_proof_common import calcTeq, calcTge from anoncreds.protocol.types import PrimaryEqualProof, \ - PrimaryPredicateGEProof, PrimaryProof, ID, ProofInput -from anoncreds.protocol.utils import encodeAttr + PrimaryPredicateGEProof, PrimaryProof, ID from anoncreds.protocol.wallet.wallet import Wallet from config.config import cmod @@ -11,30 +10,27 @@ class PrimaryProofVerifier: def __init__(self, wallet: Wallet): self._wallet = wallet - async def verify(self, schemaKey, cHash, primaryProof: PrimaryProof, - allRevealedAttrs): + async def verify(self, schemaId, cHash, primaryProof: PrimaryProof): cH = cmod.integer(cHash) - THat = await self._verifyEquality(schemaKey, cH, primaryProof.eqProof, - allRevealedAttrs) + THat = await self._verifyEquality(schemaId, cH, primaryProof.eqProof) for geProof in primaryProof.geProofs: - THat += await self._verifyGEPredicate(schemaKey, cH, geProof) + THat += await self._verifyGEPredicate(schemaId, cH, geProof) return THat - async def _verifyEquality(self, schemaKey, cH, proof: PrimaryEqualProof, - allRevealedAttrs): + async def _verifyEquality(self, schemaId, cH, proof: PrimaryEqualProof): THat = [] - pk = await self._wallet.getPublicKey(ID(schemaKey)) - attrNames = (await self._wallet.getSchema(ID(schemaKey))).attrNames - unrevealedAttrNames = set(attrNames) - set(proof.revealedAttrNames) + pk = await self._wallet.getPublicKey(ID(schemaId=schemaId)) + attrNames = (await self._wallet.getSchema(ID(schemaId=schemaId))).attrNames + unrevealedAttrNames = set(attrNames) - set(proof.revealedAttrs.keys()) T1 = calcTeq(pk, proof.Aprime, proof.e, proof.v, proof.m, proof.m1, proof.m2, unrevealedAttrNames) Rar = 1 % pk.N - for attrName in proof.revealedAttrNames: - Rar *= pk.R[str(attrName)] ** encodeAttr(allRevealedAttrs[attrName]) + for attrName in proof.revealedAttrs.keys(): + Rar *= pk.R[str(attrName)] ** proof.revealedAttrs[str(attrName)] Rar *= proof.Aprime ** (2 ** LARGE_E_START) T2 = (pk.Z / Rar) ** (-1 * cH) % pk.N T = T1 * T2 % pk.N @@ -42,9 +38,9 @@ async def _verifyEquality(self, schemaKey, cH, proof: PrimaryEqualProof, THat.append(T) return THat - async def _verifyGEPredicate(self, schemaKey, cH, + async def _verifyGEPredicate(self, schemaId, cH, proof: PrimaryPredicateGEProof): - pk = await self._wallet.getPublicKey(ID(schemaKey)) + pk = await self._wallet.getPublicKey(ID(schemaId=schemaId)) k, v = proof.predicate.attrName, proof.predicate.value TauList = calcTge(pk, proof.u, proof.r, proof.mj, proof.alpha, proof.T) diff --git a/anoncreds/protocol/prover.py b/anoncreds/protocol/prover.py index 9dbf033..71f90ef 100644 --- a/anoncreds/protocol/prover.py +++ b/anoncreds/protocol/prover.py @@ -10,8 +10,8 @@ from anoncreds.protocol.types import PrimaryClaim, NonRevocationClaim, Proof, \ InitProof, ProofInput, ProofClaims, \ FullProof, \ - Schema, ID, SchemaKey, ClaimRequest, Claims -from anoncreds.protocol.utils import get_hash_as_int + Schema, ID, SchemaKey, ClaimRequest, Claims, RequestedProof, AggregatedProof, ProofInfo, ClaimAttributeValues +from anoncreds.protocol.utils import get_hash_as_int, isCryptoInteger from anoncreds.protocol.wallet.prover_wallet import ProverWallet from config.config import cmod @@ -72,7 +72,7 @@ async def createClaimRequests(self, schemaIds: Sequence[ID], reqNonRevoc) return res - async def processClaim(self, schemaId: ID, claims: Claims): + async def processClaim(self, schemaId: ID, claimAttributes: Dict[str, ClaimAttributeValues], signature: Claims): """ Processes and saves a received Claim for the given Schema. @@ -80,10 +80,12 @@ async def processClaim(self, schemaId: ID, claims: Claims): definition schema) :param claims: claims to be processed and saved """ - await self.wallet.submitContextAttr(schemaId, claims.primaryClaim.m2) - await self._initPrimaryClaim(schemaId, claims.primaryClaim) - if claims.nonRevocClaim: - await self._initNonRevocationClaim(schemaId, claims.nonRevocClaim) + await self.wallet.submitContextAttr(schemaId, signature.primaryClaim.m2) + await self.wallet.submitClaimAttributes(schemaId, claimAttributes) + + await self._initPrimaryClaim(schemaId, signature.primaryClaim) + if signature.nonRevocClaim: + await self._initNonRevocationClaim(schemaId, signature.nonRevocClaim) async def processClaims(self, allClaims: Dict[ID, Claims]): """ @@ -93,23 +95,21 @@ async def processClaims(self, allClaims: Dict[ID, Claims]): definition. """ res = [] - for schemaId, claims in allClaims.items(): - res.append(await self.processClaim(schemaId, claims)) + for schemaId, (claim_signature, claim_attributes) in allClaims.items(): + res.append(await self.processClaim(schemaId, claim_attributes, claim_signature)) return res - async def presentProof(self, proofInput: ProofInput, nonce) -> ( - FullProof, Dict[str, Any]): + async def presentProof(self, proofInput: ProofInput) -> FullProof: """ Presents a proof to the verifier. :param proofInput: description of a proof to be presented (revealed attributes, predicates, timestamps for non-revocation) - :param nonce: verifier's nonce :return: a proof (both primary and non-revocation) and revealed attributes (initial non-encoded values) """ - claims, revealedAttrsWithValues = await self._findClaims(proofInput) - proof = await self._prepareProof(claims, nonce) - return proof, revealedAttrsWithValues + claims, requestedProof = await self._findClaims(proofInput) + proof = await self._prepareProof(claims, proofInput.nonce, requestedProof) + return proof # # REQUEST CLAIMS @@ -153,62 +153,77 @@ async def _initNonRevocationClaim(self, schemaId: ID, async def _findClaims(self, proofInput: ProofInput) -> ( Dict[SchemaKey, ProofClaims], Dict[str, Any]): - revealedAttrs, predicates = set(proofInput.revealedAttrs), set( - proofInput.predicates) + revealedAttrs, predicates = proofInput.revealedAttrs, proofInput.predicates + foundRevealedAttrs = {} + foundPredicates = {} proofClaims = {} - foundRevealedAttrs = set() - foundPredicates = set() - revealedAttrsWithValues = {} - - allClaims = await self.wallet.getAllClaims() - for schemaKey, claim in allClaims.items(): - revealedAttrsForClaim = [] - predicatesForClaim = [] - - for revealedAttr in revealedAttrs: - if revealedAttr in claim.primaryClaim.encodedAttrs: - revealedAttrsForClaim.append(revealedAttr) - foundRevealedAttrs.add(revealedAttr) - revealedAttrsWithValues[revealedAttr] = \ - claim.primaryClaim.attrs[revealedAttr] - - for predicate in predicates: - if predicate.attrName in claim.primaryClaim.encodedAttrs: - predicatesForClaim.append(predicate) - foundPredicates.add(predicate) - - if revealedAttrsForClaim or predicatesForClaim: - proofClaims[schemaKey] = ProofClaims(claim, - revealedAttrsForClaim, - predicatesForClaim) - - if foundRevealedAttrs != revealedAttrs: - raise ValueError( - "A claim isn't found for the following attributes: {}", - revealedAttrs - foundRevealedAttrs) - if foundPredicates != predicates: - raise ValueError( - "A claim isn't found for the following predicates: {}", - predicates - foundPredicates) - - return proofClaims, revealedAttrsWithValues + schemas = {} + allClaimsAttributes = await self.wallet.getAllClaimsAttributes() + + async def addProof(): + revealedAttrsForClaim = [a for a in revealedAttrs.values() if a.name in claim.keys()] + revealedPredicatesForClaim = [p for p in predicates.values() if p.attrName in claim.keys()] + + claims = await self.wallet.getClaimSignature(ID(schemaId=schemaId)) + proofClaim = ProofClaims(claims=claims, revealedAttrs=revealedAttrsForClaim, + predicates=revealedPredicatesForClaim) + + proofClaims[schemaId] = proofClaim + + for schemaKey, c in allClaimsAttributes.items(): + schemas[schemaKey] = (await self.wallet.getSchema(ID(schemaKey))) + + for uuid, revealedAttr in revealedAttrs.items(): + matches = [(schemas[key].seqId, c) for key, c in allClaimsAttributes.items() if revealedAttr.name in c + and (schemas[key].seqId == revealedAttr.schema_seq_no if revealedAttr.schema_seq_no else True) + and (schemas[key].issuerId == revealedAttr.issuer_did if revealedAttr.issuer_did else True)] + + if len(matches) == 0: + raise ValueError("A claim isn't found for the following attributes: {}", revealedAttr.name) + + schemaId, claim = matches[0] + foundRevealedAttrs[uuid] = [str(schemaId), str(claim[revealedAttr.name].raw), + str(claim[revealedAttr.name].encoded)] + + if schemaId not in proofClaims: + await addProof() + + for uuid, predicate in predicates.items(): + matches = [(schemas[key].seqId, c) for key, c in allClaimsAttributes.items() if predicate.attrName in c + and (schemas[key].seqId == predicate.schema_seq_no if predicate.schema_seq_no else True) + and (schemas[key].issuerId == predicate.issuer_did if predicate.issuer_did else True)] + + if len(matches) == 0: + raise ValueError("A claim isn't found for the following predicate: {}", predicate) + + schemaId, claim = matches[0] + foundPredicates[uuid] = str(schemaId) + + if schemaId not in proofClaims: + await addProof() + + requestedProof = RequestedProof(revealed_attrs=foundRevealedAttrs, predicates=foundPredicates) + + return proofClaims, requestedProof async def _prepareProof(self, claims: Dict[SchemaKey, ProofClaims], - nonce) -> FullProof: + nonce, requestedProof) -> FullProof: m1Tilde = cmod.integer(cmod.randomBits(LARGE_M2_TILDE)) initProofs = {} CList = [] TauList = [] # 1. init proofs - for schemaKey, val in claims.items(): + for schemaId, val in claims.items(): c1, c2, revealedAttrs, predicates = val.claims.primaryClaim, val.claims.nonRevocClaim, val.revealedAttrs, val.predicates + claim = await self.wallet.getClaimAttributes(ID(schemaId=schemaId)) + nonRevocInitProof = None if c2: nonRevocInitProof = await self._nonRevocProofBuilder.initProof( - schemaKey, c2) + schemaId, c2) CList += nonRevocInitProof.asCList() TauList += nonRevocInitProof.asTauList() @@ -217,31 +232,37 @@ async def _prepareProof(self, claims: Dict[SchemaKey, ProofClaims], m2Tilde = cmod.integer(int( nonRevocInitProof.TauListParams.m2)) if nonRevocInitProof else None primaryInitProof = await self._primaryProofBuilder.initProof( - schemaKey, c1, revealedAttrs, predicates, - m1Tilde, m2Tilde) + schemaId, c1, revealedAttrs, predicates, + m1Tilde, m2Tilde, claim) CList += primaryInitProof.asCList() TauList += primaryInitProof.asTauList() initProof = InitProof(nonRevocInitProof, primaryInitProof) - initProofs[schemaKey] = initProof + initProofs[schemaId] = initProof # 2. hash - cH = self._get_hash(CList, TauList, nonce) + cH = self._get_hash(self._prepare_collection(CList), self._prepare_collection(TauList), nonce) # 3. finalize proofs - proofs = [] - schemaKeys = [] - for schemaKey, initProof in initProofs.items(): - schemaKeys.append(schemaKey) + proofs = {} + for schemaId, initProof in initProofs.items(): nonRevocProof = None if initProof.nonRevocInitProof: nonRevocProof = await self._nonRevocProofBuilder.finalizeProof( - schemaKey, cH, initProof.nonRevocInitProof) + schemaId, cH, initProof.nonRevocInitProof) primaryProof = await self._primaryProofBuilder.finalizeProof( - schemaKey, cH, initProof.primaryInitProof) - proofs.append(Proof(primaryProof, nonRevocProof)) + schemaId, cH, initProof.primaryInitProof) - return FullProof(cH, schemaKeys, proofs, CList) + schema = await self.wallet.getSchema(ID(schemaId=schemaId)) + + proof = Proof(primaryProof, nonRevocProof) + proofInfo = ProofInfo(proof=proof, schema_seq_no=schemaId, issuer_did=schema.issuerId) + + proofs[str(schemaId)] = proofInfo + + aggregatedProof = AggregatedProof(cH, self._prepare_collection(CList)) + + return FullProof(proofs, aggregatedProof, requestedProof) async def _getCList(self, initProofs: Dict[Schema, InitProof]): CList = [] @@ -257,6 +278,9 @@ async def _getTauList(self, initProofs: Dict[Schema, InitProof]): TauList += await initProof.primaryInitProof.asTauList() return TauList + def _prepare_collection(self, values): + return [cmod.toInt(el) if isCryptoInteger(el) else el for el in values] + def _get_hash(self, CList, TauList, nonce): return get_hash_as_int(nonce, *reduce(lambda x, y: x + y, [TauList, CList])) diff --git a/anoncreds/protocol/revocation/accumulators/non_revocation_proof_builder.py b/anoncreds/protocol/revocation/accumulators/non_revocation_proof_builder.py index ca1a742..c7ea849 100644 --- a/anoncreds/protocol/revocation/accumulators/non_revocation_proof_builder.py +++ b/anoncreds/protocol/revocation/accumulators/non_revocation_proof_builder.py @@ -63,21 +63,21 @@ class NonRevocationProofBuilder: def __init__(self, wallet: ProverWallet): self._wallet = wallet - async def updateNonRevocationClaim(self, schemaKey, + async def updateNonRevocationClaim(self, schemaId, c2: NonRevocationClaim, ts=None, seqNo=None): if await self._wallet.shouldUpdateAccumulator( - schemaId=ID(schemaKey), ts=ts, + schemaId=ID(schemaId=schemaId), ts=ts, seqNo=seqNo): - await self._wallet.updateAccumulator(schemaId=ID(schemaKey), + await self._wallet.updateAccumulator(schemaId=ID(schemaId=schemaId), ts=ts, seqNo=seqNo) oldV = c2.witness.V newAccum = await self._wallet.getAccumulator( - ID(schemaKey=schemaKey)) + ID(schemaId=schemaId)) newV = newAccum.V - tails = await self._wallet.getTails(ID(schemaKey=schemaKey)) + tails = await self._wallet.getTails(ID(schemaId=schemaId)) if c2.i not in newV: raise ValueError("Can not update Witness. I'm revoced.") @@ -97,28 +97,28 @@ async def updateNonRevocationClaim(self, schemaKey, newWitness = c2.witness._replace(V=newV, omega=newOmega) c2 = c2._replace(witness=newWitness) - await self._wallet.submitNonRevocClaim(schemaId=ID(schemaKey), + await self._wallet.submitNonRevocClaim(schemaId=ID(schemaId=schemaId), claim=c2) return c2 - async def initProof(self, schemaKey, + async def initProof(self, schemaId, c2: NonRevocationClaim) -> NonRevocInitProof: if not c2: return None - c2 = await self.updateNonRevocationClaim(schemaKey, c2) + c2 = await self.updateNonRevocationClaim(schemaId, c2) - pkR = await self._wallet.getPublicKeyRevocation(ID(schemaKey)) - accum = await self._wallet.getAccumulator(ID(schemaKey=schemaKey)) + pkR = await self._wallet.getPublicKeyRevocation(ID(schemaId=schemaId)) + accum = await self._wallet.getAccumulator(ID(schemaId=schemaId)) CList = [] TauList = [] - cListParams = self._genCListParams(schemaKey, c2) - proofCList = self._createCListValues(schemaKey, c2, cListParams, pkR) + cListParams = self._genCListParams(schemaId, c2) + proofCList = self._createCListValues(schemaId, c2, cListParams, pkR) CList.extend(proofCList.asList()) - tauListParams = self._genTauListParams(schemaKey) + tauListParams = self._genTauListParams(schemaId) proofTauList = createTauListValues(pkR, accum, tauListParams, proofCList) TauList.extend(proofTauList.asList()) @@ -126,7 +126,7 @@ async def initProof(self, schemaKey, return NonRevocInitProof(proofCList, proofTauList, cListParams, tauListParams) - async def finalizeProof(self, schemaKey, cH, + async def finalizeProof(self, schemaId, cH, initProof: NonRevocInitProof) -> NonRevocProof: if not initProof: return None @@ -140,7 +140,7 @@ async def finalizeProof(self, schemaKey, cH, ) return NonRevocProof(XList, initProof.CList) - def _genCListParams(self, schemaKey, + def _genCListParams(self, schemaId, c2: NonRevocationClaim) -> NonRevocProofXList: group = cmod.PairingGroup( PAIRING_GROUP) # super singular curve, 1024 bits @@ -162,7 +162,7 @@ def _genCListParams(self, schemaKey, o=o, oPrime=oPrime, m=m, mPrime=mPrime, t=t, tPrime=tPrime, m2=m2, s=c2.v, c=c2.c) - def _createCListValues(self, schemaKey, c2: NonRevocationClaim, + def _createCListValues(self, schemaId, c2: NonRevocationClaim, params: NonRevocProofXList, pkR) -> NonRevocProofCList: E = (pkR.h ** params.rho) * (pkR.htilde ** params.o) @@ -174,19 +174,19 @@ def _createCListValues(self, schemaKey, c2: NonRevocationClaim, U = c2.witness.ui * (pkR.htilde ** params.rPrimePrimePrime) return NonRevocProofCList(E, D, A, G, W, S, U) - def _genTauListParams(self, schemaKey) -> NonRevocProofXList: + def _genTauListParams(self, schemaId) -> NonRevocProofXList: group = cmod.PairingGroup( PAIRING_GROUP) # super singular curve, 1024 bits return NonRevocProofXList(group=group) - async def testProof(self, schemaKey, c2: NonRevocationClaim): - pkR = await self._wallet.getPublicKeyRevocation(ID(schemaKey)) - accum = await self._wallet.getAccumulator(ID(schemaKey=schemaKey)) + async def testProof(self, schemaId, c2: NonRevocationClaim): + pkR = await self._wallet.getPublicKeyRevocation(ID(schemaId=schemaId)) + accum = await self._wallet.getAccumulator(ID(schemaId=schemaId)) accumPk = await self._wallet.getPublicKeyAccumulator( - ID(schemaKey=schemaKey)) + ID(schemaId=schemaId)) - cListParams = self._genCListParams(schemaKey, c2) - proofCList = self._createCListValues(schemaKey, c2, cListParams, pkR) + cListParams = self._genCListParams(schemaId, c2) + proofCList = self._createCListValues(schemaId, c2, cListParams, pkR) proofTauList = createTauListValues(pkR, accum, cListParams, proofCList) proofTauListCalc = createTauListExpectedValues(pkR, accum, accumPk, diff --git a/anoncreds/protocol/revocation/accumulators/non_revocation_proof_verifier.py b/anoncreds/protocol/revocation/accumulators/non_revocation_proof_verifier.py index 85ac246..078af39 100644 --- a/anoncreds/protocol/revocation/accumulators/non_revocation_proof_verifier.py +++ b/anoncreds/protocol/revocation/accumulators/non_revocation_proof_verifier.py @@ -14,20 +14,20 @@ class NonRevocationProofVerifier: def __init__(self, wallet: Wallet): self._wallet = wallet - async def verifyNonRevocation(self, proofInput: ProofInput, schemaKey, + async def verifyNonRevocation(self, proofInput: ProofInput, schema_seq_no, cHash, nonRevocProof: NonRevocProof) \ -> Sequence[T]: if await self._wallet.shouldUpdateAccumulator( - schemaId=ID(schemaKey), + schemaId=ID(seqId=schema_seq_no), ts=proofInput.ts, seqNo=proofInput.seqNo): - await self._wallet.updateAccumulator(schemaId=ID(schemaKey), + await self._wallet.updateAccumulator(schemaId=ID(schemaId=schema_seq_no), ts=proofInput.ts, seqNo=proofInput.seqNo) - pkR = await self._wallet.getPublicKeyRevocation(ID(schemaKey)) - accum = await self._wallet.getAccumulator(ID(schemaKey)) - accumPk = await self._wallet.getPublicKeyAccumulator(ID(schemaKey)) + pkR = await self._wallet.getPublicKeyRevocation(ID(schemaId=schema_seq_no)) + accum = await self._wallet.getAccumulator(ID(schemaId=schema_seq_no)) + accumPk = await self._wallet.getPublicKeyAccumulator(ID(schemaId=schema_seq_no)) CProof = nonRevocProof.CProof XList = nonRevocProof.XList diff --git a/anoncreds/protocol/types.py b/anoncreds/protocol/types.py index c852e12..6d59c4b 100644 --- a/anoncreds/protocol/types.py +++ b/anoncreds/protocol/types.py @@ -3,7 +3,8 @@ from typing import TypeVar, Sequence, Dict, Set from anoncreds.protocol.utils import toDictWithStrValues, \ - fromDictWithStrValues, deserializeFromStr, encodeAttr, crypto_int_to_str, to_crypto_int + fromDictWithStrValues, deserializeFromStr, encodeAttr, crypto_int_to_str, to_crypto_int, isCryptoInteger, \ + intToArrayBytes, bytesToInt from config.config import cmod @@ -147,6 +148,9 @@ def fromStrDict(cls, d): class SchemaKey( namedtuple('SchemaKey', 'name, version, issuerId'), NamedTupleStrSerializer): + def __new__(cls, name=None, version=None, issuerId=None): + return super(SchemaKey, cls).__new__(cls, name, version, issuerId) + def __hash__(self): keys = (self.name, self.version, self.issuerId) return hash(keys) @@ -200,12 +204,9 @@ def to_str_dict(self): 'rms': str(crypto_int_to_str(self.Rms)), 'rctxt': str(crypto_int_to_str(self.Rctxt)), 'z': str(crypto_int_to_str(self.Z)), - 'r': {} + 'r': {k: str(crypto_int_to_str(v)) for k, v in self.R.items()} } - for key in self.R: - public_key['r'][key] = str(crypto_int_to_str(self.R[key])) - return public_key @classmethod @@ -215,10 +216,7 @@ def from_str_dict(cls, data): Rctxt = to_crypto_int(data['rctxt'], data['n']) S = to_crypto_int(data['s'], data['n']) Z = to_crypto_int(data['z'], data['n']) - R = {} - - for key in data['r']: - R[key] = to_crypto_int(data['r'][key], data['n']) + R = {k: to_crypto_int(v, data['n']) for k, v in data['r'].items()} return cls(N, Rms, Rctxt, R, S, Z) @@ -253,8 +251,11 @@ class AccumulatorSecretKey( pass -class Predicate(namedtuple('Predicate', 'attrName, value, type'), +class Predicate(namedtuple('Predicate', 'attrName, value, type, schema_seq_no, issuer_did'), NamedTupleStrSerializer): + def __new__(cls, attrName, value, type, schema_seq_no=None, issuer_did=None): + return super(Predicate, cls).__new__(cls, attrName, value, type, schema_seq_no, issuer_did) + def __key(self): return self.attrName, self.value, self.type @@ -264,11 +265,30 @@ def __eq__(x, y): def __hash__(self): return hash(self.__key()) + def to_str_dict(self): + return { + 'attr_name': self.attrName, + 'value': self.value, + 'p_type': self.type, + 'schema_seq_no': self.schema_seq_no, + 'issuer_did': self.issuer_did + } + + @classmethod + def from_str_dict(cls, d): + attrName = d['attr_name'] + value = d['value'] + type = d['p_type'] + schema_seq_no = int(d['schema_seq_no']) if d['schema_seq_no'] else None + issuer_did = int(d['issuer_did']) if d['issuer_did'] else None + return Predicate(attrName=attrName, value=value, type=type, + schema_seq_no=schema_seq_no, issuer_did=issuer_did) + # TODO: now we consdider only >= predicate. Support other types of predicates class PredicateGE(Predicate): - def __new__(cls, attrName, value, type='ge'): - return super(PredicateGE, cls).__new__(cls, attrName, value, type) + def __new__(cls, attrName, value, type='ge', schema_seq_no=None, issuer_did=None): + return super(PredicateGE, cls).__new__(cls, attrName, value, type, schema_seq_no, issuer_did) class Accumulator: @@ -287,6 +307,7 @@ def __eq__(self, other): and self.V == other.V and self.L == other.L \ and self.currentI == other.currentI + ClaimInitDataType = namedtuple('ClaimInitDataType', 'U, vPrime') @@ -312,7 +333,7 @@ def from_str_dict(cls, data, n): # Accumulator = namedtuple('Accumulator', ['iA', 'acc', 'V', 'L']) class PrimaryClaim( - namedtuple('PrimaryClaim', 'attrs, encodedAttrs, m2, A, e, v'), + namedtuple('PrimaryClaim', 'm2, A, e, v'), NamedTupleStrSerializer): pass @@ -323,6 +344,23 @@ def __str__(self): return os.linesep.join(rtn) + def to_str_dict(self): + return { + 'm2': str(crypto_int_to_str(self.m2)), + 'a': str(crypto_int_to_str(self.A)), + 'e': str(self.e), + 'v': str(self.v) + } + + @classmethod + def from_str_dict(cls, data, n): + m2 = to_crypto_int(data['m2']) + a = to_crypto_int(data['a'], str(n)) + e = int(data['e']) + v = int(data['v']) + + return cls(m2=m2, A=a, e=e, v=v) + class Witness(namedtuple('Witness', 'sigmai, ui, gi, omega, V'), NamedTupleStrSerializer): @@ -339,6 +377,10 @@ def fromStrDict(cls, d): result = cls(**d) return result._replace(witness=witness) + def to_str_dict(self): + return { + } + class Claims(namedtuple('Claims', 'primaryClaim, nonRevocClaim'), NamedTupleStrSerializer): @@ -353,6 +395,21 @@ def fromStrDict(cls, d): nonRevoc = NonRevocationClaim.fromStrDict(d['nonRevocClaim']) return Claims(primaryClaim=primary, nonRevocClaim=nonRevoc) + def to_str_dict(self): + return { + 'primary_claim': self.primaryClaim.to_str_dict(), + 'non_revocation_claim': self.nonRevocClaim.to_str_dict() if self.nonRevocClaim else None + } + + @classmethod + def from_str_dict(cls, data, n): + primary = PrimaryClaim.from_str_dict(data['primary_claim'], n) + nonRevoc = None + if 'non_revocation_claim' in data and data['non_revocation_claim']: + nonRevoc = NonRevocationClaim.fromStrDict(data['non_revocation_claim']) + + return cls(primaryClaim=primary, nonRevocClaim=nonRevoc) + def __str__(self): return str(self.primaryClaim) @@ -372,19 +429,55 @@ def __str__(self): class ProofInput( - namedtuple('ProofInput', 'revealedAttrs, predicates, ts, seqNo'), + namedtuple('ProofInput', 'nonce, revealedAttrs, predicates, ts, seqNo'), NamedTupleStrSerializer): - def __new__(cls, revealedAttrs=None, predicates=None, ts=None, seqNo=None): - return super(ProofInput, cls).__new__(cls, revealedAttrs or [], - predicates or [], + def __new__(cls, nonce=None, revealedAttrs=None, predicates=None, ts=None, seqNo=None): + return super(ProofInput, cls).__new__(cls, nonce, revealedAttrs or {}, + predicates or {}, ts, seqNo) @classmethod def fromStrDict(cls, d): d = fromDictWithStrValues(d) - predicates = [Predicate.fromStrDict(v) for v in d['predicates']] + revealedAttrs = {k: AttributeInfo.fromStrDict(v) for k, v in d['revealedAttrs'].items()} + predicates = {k: Predicate.fromStrDict(v) for k, v in d['predicates'].items()} result = cls(**d) - return result._replace(predicates=predicates) + return result._replace(revealedAttrs=revealedAttrs, predicates=predicates) + + def to_str_dict(self): + return { + 'nonce': str(self.nonce), + 'revealedAttrs': {k: v.to_str_dict() for k, v in self.revealedAttrs.items()}, + 'predicates': {k: v.to_str_dict() for k, v in self.predicates.items()} + } + + @classmethod + def from_str_dict(cls, d): + nonce = int(d['nonce']) + revealedAttrs = {k: AttributeInfo.from_str_dict(v) for k, v in d['revealedAttrs'].items()} + predicates = {k: Predicate.from_str_dict(v) for k, v in d['predicates'].items()} + return ProofInput(nonce=nonce, revealedAttrs=revealedAttrs, predicates=predicates) + + +class AttributeInfo( + namedtuple('ProofInput', 'name, schema_seq_no, issuer_did'), + NamedTupleStrSerializer): + def __new__(cls, name=None, schema_seq_no=None, issuer_did=None): + return super(AttributeInfo, cls).__new__(cls, name, schema_seq_no, issuer_did) + + def to_str_dict(self): + return { + 'name': self.name, + 'schema_seq_no': self.schema_seq_no, + 'issuer_did': self.issuer_did + } + + @classmethod + def from_str_dict(cls, d): + schema_seq_no = int(d['schema_seq_no']) if d['schema_seq_no'] else None + issuer_did = int(d['issuer_did']) if d['issuer_did'] else None + name = d['name'] + return AttributeInfo(name, schema_seq_no, issuer_did) class ProofClaims( @@ -519,10 +612,33 @@ def __new__(cls, nonRevocInitProof: NonRevocInitProof = None, class PrimaryEqualProof(namedtuple('PrimaryEqualProof', - 'e, v, m, m1, m2, Aprime, revealedAttrNames'), + 'e, v, m, m1, m2, Aprime, revealedAttrs'), NamedTupleStrSerializer): pass + def to_str_dict(self): + return { + 'e': str(crypto_int_to_str(self.e)), + 'v': str(crypto_int_to_str(self.v)), + 'm1': str(crypto_int_to_str(self.m1)), + 'm2': str(crypto_int_to_str(self.m2)), + 'm': {k: str(crypto_int_to_str(v)) for k, v in self.m.items()}, + 'revealed_attrs': {k: str(v) for k, v in self.revealedAttrs.items()}, + 'a_prime': str(crypto_int_to_str(self.Aprime)) + } + + @classmethod + def from_str_dict(cls, d, n): + e = to_crypto_int(d['e']) + v = to_crypto_int(d['v']) + m1 = to_crypto_int(d['m1']) + m2 = to_crypto_int(d['m2']) + Aprime = to_crypto_int(d['a_prime'], str(n)) + revealedAttrs = {k: to_crypto_int(v) for k, v in d['revealed_attrs'].items()} + m = {k: to_crypto_int(v) for k, v in d['m'].items()} + + return PrimaryEqualProof(e=e, v=v, m1=m1, m2=m2, m=m, Aprime=Aprime, revealedAttrs=revealedAttrs) + class PrimaryPredicateGEProof( namedtuple('PrimaryPredicateGEProof', 'u, r, alpha, mj, T, predicate'), @@ -534,6 +650,27 @@ def fromStrDict(cls, d): result = cls(**d) return result._replace(predicate=predicate) + def to_str_dict(self): + return { + 'alpha': str(crypto_int_to_str(self.alpha)), + 'mj': str(crypto_int_to_str(self.mj)), + 'u': {k: str(crypto_int_to_str(v)) for k, v in self.u.items()}, + 'r': {k: str(crypto_int_to_str(v)) for k, v in self.r.items()}, + 't': {k: str(crypto_int_to_str(v)) for k, v in self.T.items()}, + 'predicate': self.predicate.to_str_dict() + } + + @classmethod + def from_str_dict(cls, d, n): + alpha = to_crypto_int(d['alpha']) + mj = to_crypto_int(d['mj']) + u = {k: to_crypto_int(v) for k, v in d['u'].items()} + r = {k: to_crypto_int(v) for k, v in d['r'].items()} + T = {k: to_crypto_int(v, str(n)) for k, v in d['t'].items()} + predicate = PredicateGE.from_str_dict(d['predicate']) + + return PrimaryPredicateGEProof(alpha=alpha, mj=mj, u=u, r=r, T=T, predicate=predicate) + class NonRevocProof(namedtuple('NonRevocProof', 'XList CProof'), NamedTupleStrSerializer): @@ -553,8 +690,20 @@ def __new__(cls, eqProof: PrimaryEqualProof, @classmethod def fromStrDict(cls, d): eqProof = PrimaryEqualProof.fromStrDict(d['eqProof']) - geProofs = [PrimaryPredicateGEProof.fromStrDict(v) for v in - d['geProofs']] + geProofs = [PrimaryPredicateGEProof.fromStrDict(v) for v in d['geProofs']] + return PrimaryProof(eqProof=eqProof, geProofs=geProofs) + + def to_str_dict(self): + return { + 'eq_proof': self.eqProof.to_str_dict(), + 'ge_proofs': [p.to_str_dict() for p in self.geProofs] + } + + @classmethod + def from_str_dict(cls, d, n): + eqProof = PrimaryEqualProof.from_str_dict(d['eq_proof'], n) + geProofs = [PrimaryPredicateGEProof.from_str_dict(p, n) for p in d['ge_proofs']] + return PrimaryProof(eqProof=eqProof, geProofs=geProofs) @@ -572,18 +721,128 @@ def fromStrDict(cls, d): nonRevocProof = NonRevocProof.fromStrDict(d['nonRevocProof']) return Proof(primaryProof=primaryProof, nonRevocProof=nonRevocProof) + def to_str_dict(self): + return { + 'primary_proof': self.primaryProof.to_str_dict() + } + + @classmethod + def from_str_dict(cls, d, n): + primaryProof = PrimaryProof.from_str_dict(d['primary_proof'], n) + + return Proof(primaryProof=primaryProof) + -class FullProof(namedtuple('FullProof', 'cHash, schemaKeys, proofs, CList'), +class ProofInfo(namedtuple('ProofInfo', 'proof, schema_seq_no, issuer_did'), + NamedTupleStrSerializer): + @classmethod + def fromStrDict(cls, d): + d = fromDictWithStrValues(d) + proof = Proof.fromStrDict(d['proof']) + result = cls(**d) + return result._replace(proof=proof) + + def to_str_dict(self): + return { + 'proof': self.proof.to_str_dict(), + 'schema_seq_no': self.schema_seq_no, + 'issuer_did': self.issuer_did + } + + @classmethod + def from_str_dict(cls, d, n): + proof = Proof.from_str_dict(d['proof'], n) + schema_seq_no = d['schema_seq_no'] + issuer_did = d['issuer_did'] + + return ProofInfo(proof=proof, schema_seq_no=schema_seq_no, issuer_did=issuer_did) + + +class FullProof(namedtuple('FullProof', 'proofs, aggregatedProof, requestedProof'), NamedTupleStrSerializer): def getCredDefs(self): return self.proofs.keys() @classmethod def fromStrDict(cls, d): - cHash = deserializeFromStr(d['cHash']) - schemaKeys = [SchemaKey.fromStrDict(v) for v in - d['schemaKeys']] - proofs = [Proof.fromStrDict(v) for v in d['proofs']] - CList = [deserializeFromStr(v) for v in d['CList']] - return FullProof(cHash=cHash, schemaKeys=schemaKeys, proofs=proofs, - CList=CList) + d = fromDictWithStrValues(d) + aggregatedProof = AggregatedProof.fromStrDict(d['aggregatedProof']) + requestedProof = RequestedProof.fromStrDict(d['requestedProof']) + proofs = {k: ProofInfo.fromStrDict(v) for k, v in d['proofs'].items()} + + return FullProof(aggregatedProof=aggregatedProof, proofs=proofs, requestedProof=requestedProof) + + def to_str_dict(self): + return { + 'aggregated_proof': self.aggregatedProof.to_str_dict(), + 'proofs': {k: v.to_str_dict() for k, v in self.proofs.items()}, + 'requested_proof': self.requestedProof.to_str_dict() + } + + @classmethod + def from_str_dict(cls, d, n): + aggregatedProof = AggregatedProof.from_str_dict(d['aggregated_proof']) + requestedProof = RequestedProof.from_str_dict(d['requested_proof']) + proofs = {k: Proof.from_str_dict(v['proof'], n) for k, v in d['proofs']} + + return FullProof(aggregatedProof=aggregatedProof, requestedProof=requestedProof, proofs=proofs) + + +class AggregatedProof(namedtuple('AggregatedProof', 'cHash, CList'), + NamedTupleStrSerializer): + def to_str_dict(self): + return { + 'c_hash': str(self.cHash), + 'c_list': [intToArrayBytes(v) for v in self.CList if isCryptoInteger(v)] + } + + @classmethod + def from_str_dict(cls, d): + cHash = int(d['c_hash']) + CList = [bytesToInt(v) for v in d['c_list']] + return AggregatedProof(cHash=cHash, CList=CList) + + +class RequestedProof(namedtuple('RequestedProof', 'revealed_attrs, unrevealed_attrs, self_attested_attrs, predicates'), + NamedTupleStrSerializer): + def __new__(cls, revealed_attrs=None, unrevealed_attrs=None, self_attested_attrs=None, predicates=None): + return super(RequestedProof, cls).__new__(cls, revealed_attrs or {}, unrevealed_attrs or {}, + self_attested_attrs or {}, predicates or {}) + + @classmethod + def fromStrDict(cls, d): + revealed_attrs = {k: [v[0], v[1], v[2]] for k, v in d['revealed_attrs'].items()} + predicates = {k: v for k, v in d['predicates'].items()} + return RequestedProof(revealed_attrs=revealed_attrs, predicates=predicates) + + def to_str_dict(self): + return { + 'revealed_attrs': self.revealed_attrs, + 'unrevealed_attrs': self.unrevealed_attrs, + 'self_attested_attrs': self.self_attested_attrs, + 'predicates': self.predicates + } + + @classmethod + def from_str_dict(cls, d): + revealed_attrs = d['revealed_attrs'] + unrevealed_attrs = d['unrevealed_attrs'] + self_attested_attrs = d['self_attested_attrs'] + predicates = d['predicates'] + return RequestedProof(revealed_attrs=revealed_attrs, unrevealed_attrs=unrevealed_attrs, + self_attested_attrs=self_attested_attrs, predicates=predicates) + + +class ClaimAttributeValues(namedtuple('ClaimAttributeValues', 'raw, encoded'), + NamedTupleStrSerializer): + def __new__(cls, raw=None, encoded=None): + return super(ClaimAttributeValues, cls).__new__(cls, raw, encoded) + + def to_str_dict(self): + return [self.raw, str(self.encoded)] + + @classmethod + def from_str_dict(cls, d): + raw = d[0] + encoded = int(to_crypto_int(d[1])) + return ClaimAttributeValues(raw=raw, encoded=encoded) diff --git a/anoncreds/protocol/utils.py b/anoncreds/protocol/utils.py index 4f023ab..28dfc4c 100644 --- a/anoncreds/protocol/utils.py +++ b/anoncreds/protocol/utils.py @@ -15,6 +15,7 @@ from anoncreds.protocol.globals import LARGE_PRIME, LARGE_MASTER_SECRET, \ LARGE_VPRIME, PAIRING_GROUP from config.config import cmod +import sys def encodeAttr(attrValue): @@ -186,9 +187,9 @@ def splitRevealedAttrs(encodedAttrs, revealedAttrs): for k, value in encodedAttrs.items(): if k in revealedAttrs: - Ar[k] = value + Ar[k] = value.encoded else: - Aur[k] = value + Aur[k] = value.encoded return Ar, Aur @@ -248,7 +249,6 @@ def to_crypto_int(a, b=None): return strToCryptoInteger(a + 'mod' + b) if b else strToCryptoInteger(a) - def crypto_int_to_str(n): return cmod.toInt(n) @@ -350,3 +350,27 @@ def shortenDictVals(d, size=None): def currentTimestampMillisec(): return int(time.time() * 1000) # millisec + + +def intToArrayBytes(value): + value = int(value) + result = [] + for i in range(0, sys.getsizeof(value)): + b = value >> (i * 8) & 0xff + result.append(b) + + result.reverse() + + first_non_zero = next((i for i, x in enumerate(result) if x), None) + result = result[first_non_zero::] + + return result + + +def bytesToInt(bytes): + result = 0 + + for b in bytes: + result = result * 256 + int(b) + + return result diff --git a/anoncreds/protocol/verifier.py b/anoncreds/protocol/verifier.py index 56249ba..b61a6c6 100644 --- a/anoncreds/protocol/verifier.py +++ b/anoncreds/protocol/verifier.py @@ -6,7 +6,7 @@ from anoncreds.protocol.revocation.accumulators.non_revocation_proof_verifier import \ NonRevocationProofVerifier from anoncreds.protocol.types import FullProof, ProofInput -from anoncreds.protocol.utils import get_hash_as_int +from anoncreds.protocol.utils import get_hash_as_int, isCryptoInteger from anoncreds.protocol.wallet.wallet import Wallet from config.config import cmod @@ -24,33 +24,42 @@ def verifierId(self): def generateNonce(self): return cmod.integer(cmod.randomBits(LARGE_NONCE)) - async def verify(self, proofInput: ProofInput, proof: FullProof, - allRevealedAttrs, nonce): + async def verify(self, proofInput: ProofInput, proof: FullProof): """ Verifies a proof from the prover. :param proofInput: description of a proof to be presented (revealed attributes, predicates, timestamps for non-revocation) :param proof: a proof - :param allRevealedAttrs: values of revealed attributes (initial values, non-encoded) - :param nonce: verifier's nonce :return: True if verified successfully and false otherwise. """ + + if proofInput.revealedAttrs.keys() != proof.requestedProof.revealed_attrs.keys(): + raise ValueError('Received attributes ={} do not correspond to requested={}'.format( + proof.requestedProof.revealed_attrs.keys(), proofInput.revealedAttrs.keys())) + + if proofInput.predicates.keys() != proof.requestedProof.predicates.keys(): + raise ValueError('Received predicates ={} do not correspond to requested={}'.format( + proof.requestedProof.predicates.keys(), proofInput.predicates.keys())) + TauList = [] - for schemaKey, proofItem in zip(proof.schemaKeys, proof.proofs): - if proofItem.nonRevocProof: + for (uuid, proofItem) in proof.proofs.items(): + if proofItem.proof.nonRevocProof: TauList += await self._nonRevocVerifier.verifyNonRevocation( - proofInput, schemaKey, proof.cHash, - proofItem.nonRevocProof) - if proofItem.primaryProof: - TauList += await self._primaryVerifier.verify(schemaKey, - proof.cHash, - proofItem.primaryProof, - allRevealedAttrs) + proofInput, proofItem.schema_seq_no, proof.aggregatedProof.cHash, + proofItem.proof.nonRevocProof) + if proofItem.proof.primaryProof: + TauList += await self._primaryVerifier.verify(proofItem.schema_seq_no, + proof.aggregatedProof.cHash, + proofItem.proof.primaryProof) + + CHver = self._get_hash(proof.aggregatedProof.CList, self._prepare_collection(TauList), + cmod.integer(proofInput.nonce)) - CHver = self._get_hash(proof.CList, TauList, nonce) + return CHver == proof.aggregatedProof.cHash - return CHver == proof.cHash + def _prepare_collection(self, values): + return [cmod.toInt(el) if isCryptoInteger(el) else el for el in values] def _get_hash(self, CList, TauList, nonce): return get_hash_as_int(nonce, diff --git a/anoncreds/protocol/wallet/prover_wallet.py b/anoncreds/protocol/wallet/prover_wallet.py index f8a4ae2..32d7c6b 100644 --- a/anoncreds/protocol/wallet/prover_wallet.py +++ b/anoncreds/protocol/wallet/prover_wallet.py @@ -3,8 +3,9 @@ from anoncreds.protocol.repo.public_repo import PublicRepo from anoncreds.protocol.types import ID, \ Claims, ClaimInitDataType, \ - PrimaryClaim, NonRevocationClaim, ClaimsPair + PrimaryClaim, NonRevocationClaim, ClaimsPair, ClaimAttributeValues from anoncreds.protocol.wallet.wallet import Wallet, WalletInMemory +from typing import Dict, Sequence, Any class ProverWallet(Wallet): @@ -13,6 +14,10 @@ def __init__(self, schemaId, repo: PublicRepo): # SUBMIT + @abstractmethod + async def submitClaimAttributes(self, schemaId: ID, claims: Dict[str, ClaimAttributeValues]): + raise NotImplementedError + @abstractmethod async def submitPrimaryClaim(self, schemaId: ID, claim: PrimaryClaim): raise NotImplementedError @@ -47,11 +52,19 @@ async def getMasterSecret(self, schemaId: ID): raise NotImplementedError @abstractmethod - async def getClaims(self, schemaId: ID) -> Claims: + async def getClaimAttributes(self, schemaId: ID) -> Claims: + raise NotImplementedError + + @abstractmethod + async def getAllClaimsAttributes(self) -> ClaimsPair: + raise NotImplementedError + + @abstractmethod + async def getClaimSignature(self, schemaId: ID) -> Claims: raise NotImplementedError @abstractmethod - async def getAllClaims(self) -> ClaimsPair: + async def getAllClaimsSignatures(self) -> ClaimsPair: raise NotImplementedError @abstractmethod @@ -73,6 +86,8 @@ class ProverWalletInMemory(ProverWallet, WalletInMemory): def __init__(self, schemaId, repo: PublicRepo): WalletInMemory.__init__(self, schemaId, repo) + self._claims = {} + # other dicts with key=schemaKey self._m1s = {} self._m2s = {} @@ -85,6 +100,9 @@ def __init__(self, schemaId, repo: PublicRepo): # SUBMIT + async def submitClaimAttributes(self, schemaId: ID, claims: Dict[str, ClaimAttributeValues]): + await self._cacheValueForId(self._claims, schemaId, claims) + async def submitPrimaryClaim(self, schemaId: ID, claim: PrimaryClaim): await self._cacheValueForId(self._c1s, schemaId, claim) @@ -113,16 +131,25 @@ async def submitContextAttr(self, schemaId: ID, m2): async def getMasterSecret(self, schemaId: ID): return await self._getValueForId(self._m1s, schemaId) - async def getClaims(self, schemaId: ID) -> Claims: + async def getClaimAttributes(self, schemaId: ID): + return await self._getValueForId(self._claims, schemaId) + + async def getClaimSignature(self, schemaId: ID) -> Claims: c1 = await self._getValueForId(self._c1s, schemaId) c2 = None if not self._c2s else await self._getValueForId(self._c2s, schemaId) return Claims(c1, c2) - async def getAllClaims(self) -> ClaimsPair: + async def getAllClaimsAttributes(self) -> ClaimsPair: + res = dict() + for schemaKey in self._claims.keys(): + res[schemaKey] = await self.getClaimAttributes(ID(schemaKey)) + return res + + async def getAllClaimsSignatures(self) -> ClaimsPair: res = ClaimsPair() for schemaKey in self._c1s.keys(): - res[schemaKey] = await self.getClaims(ID(schemaKey)) + res[schemaKey] = await self.getClaimSignature(ID(schemaKey)) return res async def getPrimaryClaimInitData(self, diff --git a/anoncreds/test/conftest.py b/anoncreds/test/conftest.py index 54fee2d..bd36f9c 100644 --- a/anoncreds/test/conftest.py +++ b/anoncreds/test/conftest.py @@ -205,11 +205,11 @@ def claimsRequestProver1Gvt(prover1, schemaGvtId, keysGvt, @pytest.fixture(scope="function") def claimsProver1Gvt(prover1, issuerGvt, claimsRequestProver1Gvt, schemaGvtId, attrsProver1Gvt, event_loop): - claims = event_loop.run_until_complete( + signature, claim = event_loop.run_until_complete( issuerGvt.issueClaim(schemaGvtId, claimsRequestProver1Gvt)) - event_loop.run_until_complete(prover1.processClaim(schemaGvtId, claims)) + event_loop.run_until_complete(prover1.processClaim(schemaGvtId, claim, signature)) return event_loop.run_until_complete( - prover1.wallet.getClaims(schemaGvtId)) + prover1.wallet.getClaimSignature(schemaGvtId)) @pytest.fixture(scope="function") @@ -217,11 +217,11 @@ def claimsProver2Gvt(prover2, issuerGvt, schemaGvtId, attrsProver2Gvt, keysGvt, issueAccumulatorGvt, event_loop): claimsReq = event_loop.run_until_complete( prover2.createClaimRequest(schemaGvtId)) - claims = event_loop.run_until_complete( + signature, claim = event_loop.run_until_complete( issuerGvt.issueClaim(schemaGvtId, claimsReq)) - event_loop.run_until_complete(prover2.processClaim(schemaGvtId, claims)) + event_loop.run_until_complete(prover2.processClaim(schemaGvtId, claim, signature)) return event_loop.run_until_complete( - prover2.wallet.getClaims(schemaGvtId)) + prover2.wallet.getClaimSignature(schemaGvtId)) @pytest.fixture(scope="function") @@ -229,11 +229,11 @@ def claimsProver1Xyz(prover1, issuerXyz, schemaXyzId, attrsProver1Xyz, keysXyz, issueAccumulatorXyz, event_loop): claimsReq = event_loop.run_until_complete( prover1.createClaimRequest(schemaXyzId)) - claims = event_loop.run_until_complete( + signature, claim = event_loop.run_until_complete( issuerXyz.issueClaim(schemaXyzId, claimsReq)) - event_loop.run_until_complete(prover1.processClaim(schemaXyzId, claims)) + event_loop.run_until_complete(prover1.processClaim(schemaXyzId, claim, signature)) return event_loop.run_until_complete( - prover1.wallet.getClaims(schemaXyzId)) + prover1.wallet.getClaimSignature(schemaXyzId)) @pytest.fixture(scope="function") @@ -241,11 +241,11 @@ def claimsProver2Xyz(prover2, issuerXyz, schemaXyzId, attrsProver2Xyz, keysXyz, issueAccumulatorXyz, event_loop): claimsReq = event_loop.run_until_complete( prover2.createClaimRequest(schemaXyzId)) - claims = event_loop.run_until_complete( + signature, claim = event_loop.run_until_complete( issuerXyz.issueClaim(schemaXyzId, claimsReq)) - event_loop.run_until_complete(prover2.processClaim(schemaXyzId, claims)) + event_loop.run_until_complete(prover2.processClaim(schemaXyzId, claim, signature)) return event_loop.run_until_complete( - prover2.wallet.getClaims(schemaXyzId)) + prover2.wallet.getClaimSignature(schemaXyzId)) @pytest.fixture(scope="function") @@ -274,6 +274,6 @@ def genNonce(verifier): async def presentProofAndVerify(verifier: Verifier, proofInput: ProofInput, prover): - nonce = verifier.generateNonce() - proof, revealedAttrs = await prover.presentProof(proofInput, nonce) - return await verifier.verify(proofInput, proof, revealedAttrs, nonce) + proofInput = ProofInput(verifier.generateNonce(), proofInput.revealedAttrs, proofInput.predicates) + proof = await prover.presentProof(proofInput) + return await verifier.verify(proofInput, proof) \ No newline at end of file diff --git a/anoncreds/test/test_anoncred_usage.py b/anoncreds/test/test_anoncred_usage.py index 37027d1..726c6da 100644 --- a/anoncreds/test/test_anoncred_usage.py +++ b/anoncreds/test/test_anoncred_usage.py @@ -5,7 +5,7 @@ from anoncreds.protocol.repo.attributes_repo import AttributeRepoInMemory from anoncreds.protocol.repo.public_repo import PublicRepoInMemory from anoncreds.protocol.types import ProofInput, PredicateGE, \ - ID + ID, AttributeInfo from anoncreds.protocol.verifier import Verifier from anoncreds.protocol.wallet.issuer_wallet import IssuerWalletInMemory from anoncreds.protocol.wallet.prover_wallet import ProverWalletInMemory @@ -39,19 +39,21 @@ async def testSingleIssuerSingleProver(primes1): # 5. request Claims prover = Prover(ProverWalletInMemory(userId, publicRepo)) claimsReq = await prover.createClaimRequest(schemaId) - claims = await issuer.issueClaim(schemaId, claimsReq) - await prover.processClaim(schemaId, claims) + (claim_signature, claim_attributes) = await issuer.issueClaim(schemaId, claimsReq) + + await prover.processClaim(schemaId, claim_attributes, claim_signature) # 6. proof Claims + verifier = Verifier(WalletInMemory('verifier1', publicRepo)) + proofInput = ProofInput( - ['name'], - [PredicateGE('age', 18)]) + verifier.generateNonce(), + {'attr_uuid': AttributeInfo('name', schema.seqId)}, + {'predicate_uuid': PredicateGE('age', 18)}) - verifier = Verifier(WalletInMemory('verifier1', publicRepo)) - nonce = verifier.generateNonce() - proof, revealedAttrs = await prover.presentProof(proofInput, nonce) - assert revealedAttrs['name'] == 'Alex' - assert await verifier.verify(proofInput, proof, revealedAttrs, nonce) + proof = await prover.presentProof(proofInput) + assert proof.requestedProof.revealed_attrs['attr_uuid'][1] == 'Alex' + assert await verifier.verify(proofInput, proof) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @@ -67,7 +69,7 @@ async def testMultiplIssuersSingleProver(primes1, primes2): schema1 = await issuer1.genSchema('GVT', '1.0', GVT.attribNames()) schemaId1 = ID(schema1.getKey()) schema2 = await issuer2.genSchema('XYZCorp', '1.0', - XYZCorp.attribNames()) + XYZCorp.attribNames()) schemaId2 = ID(schema2.getKey()) # 3. Create keys for the Schema @@ -89,22 +91,27 @@ async def testMultiplIssuersSingleProver(primes1, primes2): prover = Prover(ProverWalletInMemory(userId, publicRepo)) claimsReq1 = await prover.createClaimRequest(schemaId1) claimsReq2 = await prover.createClaimRequest(schemaId2) - claims1 = await issuer1.issueClaim(schemaId1, claimsReq1) - claims2 = await issuer2.issueClaim(schemaId2, claimsReq2) - await prover.processClaim(schemaId1, claims1) - await prover.processClaim(schemaId2, claims2) + (claim1_signature, claim1_attributes) = await issuer1.issueClaim(schemaId1, claimsReq1) + (claim2_signature, claim2_attributes) = await issuer2.issueClaim(schemaId2, claimsReq2) + await prover.processClaim(schemaId1, claim1_attributes, claim1_signature) + await prover.processClaim(schemaId2, claim2_attributes, claim2_signature) # 6. proof Claims - proofInput = ProofInput(['name', 'status'], - [PredicateGE('age', 18), PredicateGE('period', 5)]) - verifier = Verifier(WalletInMemory('verifier1', publicRepo)) - nonce = verifier.generateNonce() - proof, revealedAttrs = await prover.presentProof(proofInput, nonce) - assert revealedAttrs['name'] == 'Alex' - assert revealedAttrs['status'] == 'FULL' - assert await verifier.verify(proofInput, proof, revealedAttrs, nonce) + proofInput = ProofInput( + verifier.generateNonce(), + {'attr_uuid1': AttributeInfo('name', schema1.seqId), + 'attr_uuid2': AttributeInfo('status', schema2.seqId)}, + {'predicate_uuid1': PredicateGE('age', 18), + 'predicate_uuid2': PredicateGE('period', 5)}) + + proof = await prover.presentProof(proofInput) + + assert proof.requestedProof.revealed_attrs['attr_uuid1'][1] == 'Alex' + assert proof.requestedProof.revealed_attrs['attr_uuid2'][1] == 'FULL' + + assert await verifier.verify(proofInput, proof) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @@ -119,7 +126,7 @@ async def testSingleIssuerMultipleCredDefsSingleProver(primes1, primes2): schema1 = await issuer.genSchema('GVT', '1.0', GVT.attribNames()) schemaId1 = ID(schema1.getKey()) schema2 = await issuer.genSchema('XYZCorp', '1.0', - XYZCorp.attribNames()) + XYZCorp.attribNames()) schemaId2 = ID(schema2.getKey()) # 3. Create keys for the Schema @@ -144,16 +151,18 @@ async def testSingleIssuerMultipleCredDefsSingleProver(primes1, primes2): await prover.processClaims(claims) # 6. proof Claims + verifier = Verifier(WalletInMemory('verifier1', publicRepo)) + proofInput = ProofInput( - ['name'], - [PredicateGE('age', 18), PredicateGE('period', 5)]) + verifier.generateNonce(), + {'attr_uuid1': AttributeInfo('name', schema1.seqId)}, + {'predicate_uuid1': PredicateGE('age', 18), + 'predicate_uuid2': PredicateGE('period', 5)}) - verifier = Verifier(WalletInMemory('verifier1', publicRepo)) - nonce = verifier.generateNonce() - proof, revealedAttrs = await prover.presentProof(proofInput, nonce) + proof = await prover.presentProof(proofInput) - assert revealedAttrs['name'] == 'Alex' - assert await verifier.verify(proofInput, proof, revealedAttrs, nonce) + assert proof.requestedProof.revealed_attrs['attr_uuid1'][1] == 'Alex' + assert await verifier.verify(proofInput, proof) @pytest.mark.asyncio @@ -181,17 +190,18 @@ async def testSingleIssuerSingleProverPrimaryOnly(primes1): # 5. request Claims prover = Prover(ProverWalletInMemory(userId, publicRepo)) claimsReq = await prover.createClaimRequest(schemaId, None, False) - claims = await issuer.issueClaim(schemaId, claimsReq) - await prover.processClaim(schemaId, claims) + (claim_signature, claim_attributes) = await issuer.issueClaim(schemaId, claimsReq) + await prover.processClaim(schemaId, claim_attributes, claim_signature) # 6. proof Claims + verifier = Verifier(WalletInMemory('verifier1', publicRepo)) + proofInput = ProofInput( - ['name'], - [PredicateGE('age', 18)]) + verifier.generateNonce(), + {'attr_uuid1': AttributeInfo('name', schema.seqId)}, + {'predicate_uuid1': PredicateGE('age', 18)}) - verifier = Verifier(WalletInMemory('verifier1', publicRepo)) - nonce = verifier.generateNonce() - proof, revealedAttrs = await prover.presentProof(proofInput, nonce) + proof = await prover.presentProof(proofInput) - assert revealedAttrs['name'] == 'Alex' - assert await verifier.verify(proofInput, proof, revealedAttrs, nonce) + assert proof.requestedProof.revealed_attrs['attr_uuid1'][1] == 'Alex' + assert await verifier.verify(proofInput, proof) diff --git a/anoncreds/test/test_find_claims_for_input.py b/anoncreds/test/test_find_claims_for_input.py index fdc9ffe..5bbf38b 100644 --- a/anoncreds/test/test_find_claims_for_input.py +++ b/anoncreds/test/test_find_claims_for_input.py @@ -1,169 +1,177 @@ import pytest -from anoncreds.protocol.types import ProofInput, ProofClaims, PredicateGE +from anoncreds.protocol.types import ProofInput, ProofClaims, PredicateGE, RequestedProof, AttributeInfo +from anoncreds.protocol.utils import encodeAttr @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio -async def testEmpty(prover1, allClaims): - proofInput = ProofInput([], []) - assert ({}, {}) == await prover1._findClaims(proofInput) +async def testEmpty(prover1): + proofInput = ProofInput(revealedAttrs={}, predicates={}) + assert ({}, RequestedProof([], [], [], [])) == await prover1._findClaims(proofInput) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio -async def testOneRevealedOnly(prover1, allClaims, schemaGvtId, attrRepo): - proofInput = ProofInput(['name']) - claimsGvt = await prover1.wallet.getClaims(schemaGvtId) - proofClaims = {schemaGvtId.schemaKey: - ProofClaims(claimsGvt, ['name'], [])} - revealedAttrs = {'name': - attrRepo.getAttributes(schemaGvtId.schemaKey, - prover1.proverId)[ - 'name']} - assert (proofClaims, revealedAttrs) == await prover1._findClaims(proofInput) +async def testOneRevealedOnly(prover1, allClaims, schemaGvtId, attrRepo, schemaGvt): + proofInput = ProofInput(revealedAttrs={'uuid': AttributeInfo(name='name')}) + claimsGvt = await prover1.wallet.getClaimSignature(schemaGvtId) + + proofClaims = {schemaGvt.seqId: ProofClaims(claimsGvt, ['name'], [])} + attr = attrRepo.getAttributes(schemaGvtId.schemaKey, prover1.proverId)['name'] + requestedProof = RequestedProof(revealed_attrs={'uuid': [str(schemaGvt.seqId), attr, str(encodeAttr(attr))]}) + + assert proofClaims, requestedProof == await prover1._findClaims(proofInput) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio -async def testPredicatesEmpty(prover1, allClaims, schemaGvtId, attrRepo): - proofInput = ProofInput(['name'], []) - claimsGvt = await prover1.wallet.getClaims(schemaGvtId) - proofClaims = {schemaGvtId.schemaKey: - ProofClaims(claimsGvt, ['name'], [])} - revealedAttrs = {'name': - attrRepo.getAttributes(schemaGvtId.schemaKey, - prover1.proverId)[ - 'name']} - assert (proofClaims, revealedAttrs) == await prover1._findClaims(proofInput) +async def testPredicatesEmpty(prover1, allClaims, schemaGvtId, attrRepo, schemaGvt): + proofInput = ProofInput(revealedAttrs={'uuid': AttributeInfo(name='name')}, predicates={}) + claimsGvt = await prover1.wallet.getClaimSignature(schemaGvtId) + + proofClaims = {schemaGvt.seqId: ProofClaims(claimsGvt, ['name'], [])} + + attr = attrRepo.getAttributes(schemaGvtId.schemaKey, prover1.proverId)['name'] + requestedProof = RequestedProof(revealed_attrs={'uuid': [schemaGvt.seqId, attr, str(encodeAttr(attr))]}) + + assert proofClaims, requestedProof == await prover1._findClaims(proofInput) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio -async def testOnePredicateOnly(prover1, allClaims, schemaGvtId): - proofInput = ProofInput(predicates=[PredicateGE('age', 18)]) - claimsGvt = await prover1.wallet.getClaims(schemaGvtId) - proofClaims = {schemaGvtId.schemaKey: +async def testOnePredicateOnly(prover1, allClaims, schemaGvtId, schemaGvt): + proofInput = ProofInput(predicates={'uuid': PredicateGE('age', 18)}) + + claimsGvt = await prover1.wallet.getClaimSignature(schemaGvtId) + proofClaims = {schemaGvt.seqId: ProofClaims(claimsGvt, [], [PredicateGE('age', 18)])} - revealedAttrs = {} - assert (proofClaims, revealedAttrs) == await prover1._findClaims(proofInput) + + requestedProof = RequestedProof(predicates={'uuid': schemaGvt.seqId}) + + assert proofClaims, requestedProof == await prover1._findClaims(proofInput) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio -async def testRevealedEmpty(prover1, allClaims, schemaGvtId): - proofInput = ProofInput([], [PredicateGE('age', 18)]) - claimsGvt = await prover1.wallet.getClaims(schemaGvtId) - proofClaims = {schemaGvtId.schemaKey: +async def testRevealedEmpty(prover1, allClaims, schemaGvtId, schemaGvt): + proofInput = ProofInput(revealedAttrs={}, predicates={'uuid': PredicateGE('age', 18)}) + + claimsGvt = await prover1.wallet.getClaimSignature(schemaGvtId) + proofClaims = {schemaGvt.seqId: ProofClaims(claimsGvt, [], [PredicateGE('age', 18)])} - revealedAttrs = {} - assert (proofClaims, revealedAttrs) == await prover1._findClaims(proofInput) + + requestedProof = RequestedProof(predicates={'uuid': schemaGvt.seqId}) + + assert proofClaims, requestedProof == await prover1._findClaims(proofInput) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testRevealedAndPredicateSameIssuer(prover1, allClaims, schemaGvtId, - attrRepo): - proofInput = ProofInput(['name'], [PredicateGE('age', 18)]) - claimsGvt = await prover1.wallet.getClaims(schemaGvtId) - proofClaims = {schemaGvtId.schemaKey: - ProofClaims(claimsGvt, ['name'], - [PredicateGE('age', 18)])} - revealedAttrs = {'name': - attrRepo.getAttributes(schemaGvtId.schemaKey, - prover1.proverId)[ - 'name']} - assert (proofClaims, revealedAttrs) == await prover1._findClaims(proofInput) + attrRepo, schemaGvt): + proofInput = ProofInput(revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid': PredicateGE('age', 18)}) + + claimsGvt = await prover1.wallet.getClaimSignature(schemaGvtId) + proofClaims = {schemaGvt.seqId: ProofClaims(claimsGvt, ['name'], [PredicateGE('age', 18)])} + + attr = attrRepo.getAttributes(schemaGvtId.schemaKey, prover1.proverId)['name'] + requestedProof = RequestedProof(revealed_attrs={'attr_uuid': [schemaGvt.seqId, attr, str(encodeAttr(attr))]}, + predicates={'predicate_uuid': schemaGvt.seqId}) + + assert proofClaims, requestedProof == await prover1._findClaims(proofInput) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testRevealedAndPredicateDifferentIssuers(prover1, allClaims, schemaGvtId, schemaXyzId, - attrRepo): - proofInput = ProofInput(['status'], [PredicateGE('age', 18)]) - claimsGvt = await prover1.wallet.getClaims(schemaGvtId) - claimsXyz = await prover1.wallet.getClaims(schemaXyzId) - proofClaims = {schemaGvtId.schemaKey: - ProofClaims(claimsGvt, [], [PredicateGE('age', 18)]), - schemaXyzId.schemaKey: - ProofClaims(claimsXyz, ['status'], [])} - revealedAttrs = {'status': - attrRepo.getAttributes(schemaXyzId.schemaKey, - prover1.proverId)[ - 'status']} - assert (proofClaims, revealedAttrs) == await prover1._findClaims(proofInput) + attrRepo, schemaGvt): + proofInput = ProofInput(revealedAttrs={'attr_uuid': AttributeInfo(name='status')}, + predicates={'predicate_uuid': PredicateGE('age', 18)}) + + claimsGvt = await prover1.wallet.getClaimSignature(schemaGvtId) + claimsXyz = await prover1.wallet.getClaimSignature(schemaXyzId) + proofClaims = {schemaGvt.seqId: ProofClaims(claimsGvt, [], [PredicateGE('age', 18)]), + schemaGvt.seqId: ProofClaims(claimsXyz, ['status'], [])} + + attr = attrRepo.getAttributes(schemaXyzId.schemaKey, prover1.proverId)['status'] + requestedProof = RequestedProof(revealed_attrs={'attr_uuid': [schemaGvt.seqId, attr, str(encodeAttr(attr))]}, + predicates={'predicate_uuid': schemaGvt.seqId}) + + assert proofClaims, requestedProof == await prover1._findClaims(proofInput) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testMultipledRevealed(prover1, allClaims, schemaGvtId, - schemaXyzId, attrRepo): - proofInput = ProofInput(['status', 'name'], []) - claimsGvt = await prover1.wallet.getClaims(schemaGvtId) - claimsXyz = await prover1.wallet.getClaims(schemaXyzId) - proofClaims = {schemaGvtId.schemaKey: - ProofClaims(claimsGvt, ['name'], []), - schemaXyzId.schemaKey: - ProofClaims(claimsXyz, ['status'], [])} - revealedAttrs = {'name': - attrRepo.getAttributes(schemaGvtId.schemaKey, - prover1.proverId)[ - 'name'], - 'status': - attrRepo.getAttributes(schemaXyzId.schemaKey, - prover1.proverId)[ - 'status'], - } - assert (proofClaims, revealedAttrs) == await prover1._findClaims(proofInput) + schemaXyzId, attrRepo, schemaGvt): + proofInput = ProofInput(revealedAttrs={'attr_uuid1': AttributeInfo(name='status'), + 'attr_uuid2': AttributeInfo(name='name')}) + + claimsGvt = await prover1.wallet.getClaimSignature(schemaGvtId) + claimsXyz = await prover1.wallet.getClaimSignature(schemaXyzId) + proofClaims = {schemaGvt.seqId: ProofClaims(claimsGvt, ['name'], []), + schemaGvt.seqId: ProofClaims(claimsXyz, ['status'], [])} + + attr1 = attrRepo.getAttributes(schemaXyzId.schemaKey, prover1.proverId)['status'] + attr2 = attrRepo.getAttributes(schemaGvtId.schemaKey, prover1.proverId)['name'] + requestedProof = RequestedProof(revealed_attrs={'attr_uuid1': [schemaGvt.seqId, attr1, str(encodeAttr(attr1))], + 'attr_uuid2': [schemaGvt.seqId, attr2, str(encodeAttr(attr2))]}) + + assert proofClaims, requestedProof == await prover1._findClaims(proofInput) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testMultipledPredicates(prover1, allClaims, schemaGvtId, - schemaXyzId): - proofInput = ProofInput([], - [PredicateGE('age', 18), PredicateGE('period', 8)]) - claimsGvt = await prover1.wallet.getClaims(schemaGvtId) - claimsXyz = await prover1.wallet.getClaims(schemaXyzId) - proofClaims = {schemaGvtId.schemaKey: - ProofClaims(claimsGvt, [], [PredicateGE('age', 18)]), - schemaXyzId.schemaKey: - ProofClaims(claimsXyz, [], [PredicateGE('period', 8)])} - revealedAttrs = {} - assert (proofClaims, revealedAttrs) == await prover1._findClaims(proofInput) + schemaXyzId, schemaGvt): + proofInput = ProofInput(predicates={'predicate_uuid1': PredicateGE('age', 18), + 'predicate_uuid2': PredicateGE('period', 8)}) + + claimsGvt = await prover1.wallet.getClaimSignature(schemaGvtId) + claimsXyz = await prover1.wallet.getClaimSignature(schemaXyzId) + proofClaims = {schemaGvt.seqId: ProofClaims(claimsGvt, [], [PredicateGE('age', 18)]), + schemaGvt.seqId: ProofClaims(claimsXyz, [], [PredicateGE('period', 8)])} + + requestedProof = RequestedProof(predicates={'predicate_uuid1': schemaGvt.seqId, + 'predicate_uuid2': schemaGvt.seqId}) + + assert proofClaims, requestedProof == await prover1._findClaims(proofInput) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testMultipleAll(prover1, allClaims, schemaGvtId, schemaXyzId, - attrRepo): - proofInput = ProofInput(['status', 'name'], - [PredicateGE('age', 18), PredicateGE('period', 8)]) - claimsGvt = await prover1.wallet.getClaims(schemaGvtId) - claimsXyz = await prover1.wallet.getClaims(schemaXyzId) - proofClaims = {schemaGvtId.schemaKey: - ProofClaims(claimsGvt, ['name'], - [PredicateGE('age', 18)]), - schemaXyzId.schemaKey: - ProofClaims(claimsXyz, ['status'], - [PredicateGE('period', 8)])} - revealedAttrs = {'name': - attrRepo.getAttributes(schemaGvtId.schemaKey, - prover1.proverId)[ - 'name'], - 'status': - attrRepo.getAttributes(schemaXyzId.schemaKey, - prover1.proverId)[ - 'status'], - } - assert (proofClaims, revealedAttrs) == await prover1._findClaims(proofInput) + attrRepo, schemaGvt): + proofInput = ProofInput(revealedAttrs={'attr_uuid1': AttributeInfo(name='status'), + 'attr_uuid2': AttributeInfo(name='name')}, + predicates={'predicate_uuid1': PredicateGE('age', 18), + 'predicate_uuid2': PredicateGE('period', 8)}) + + claimsGvt = await prover1.wallet.getClaimSignature(schemaGvtId) + claimsXyz = await prover1.wallet.getClaimSignature(schemaXyzId) + proofClaims = {schemaGvt.seqId: ProofClaims(claimsGvt, ['name'], [PredicateGE('age', 18)]), + schemaGvt.seqId: ProofClaims(claimsXyz, ['status'], [PredicateGE('period', 8)])} + + attr1 = attrRepo.getAttributes(schemaXyzId.schemaKey, prover1.proverId)['status'] + attr2 = attrRepo.getAttributes(schemaGvtId.schemaKey, prover1.proverId)['name'] + + requestedProof = RequestedProof( + revealed_attrs={'attr_uuid1': [schemaGvt.seqId, attr1, str(encodeAttr(attr1))], + 'attr_uuid2': [schemaGvt.seqId, attr2, str(encodeAttr(attr2))]}, + predicates={'predicate_uuid1': schemaGvt.seqId, + 'predicate_uuid2': schemaGvt.seqId}) + + assert proofClaims, requestedProof == await prover1._findClaims(proofInput) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testAttrNotFound(prover1, allClaims): - proofInput = ProofInput(['name', 'aaaa'], []) + proofInput = ProofInput(revealedAttrs={'attr_uuid1': AttributeInfo(name='name'), + 'attr_uuid2': AttributeInfo(name='aaa')}) with pytest.raises(ValueError): await prover1._findClaims(proofInput) @@ -171,7 +179,55 @@ async def testAttrNotFound(prover1, allClaims): @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testPredicateNotFound(prover1, allClaims): - proofInput = ProofInput([], - [PredicateGE('age', 18), PredicateGE('aaaa', 8)]) + proofInput = ProofInput(predicates={'predicate_uuid1': PredicateGE('age', 18), + 'predicate_uuid2': PredicateGE('aaaa', 8)}) + with pytest.raises(ValueError): + await prover1._findClaims(proofInput) + + +@pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') +@pytest.mark.asyncio +async def testOneRevealedFromSchema(prover1, allClaims, schemaGvtId, attrRepo, schemaGvt): + proofInput = ProofInput(revealedAttrs={'uuid': AttributeInfo(name='name', schema_seq_no=schemaGvt.seqId)}) + claimsGvt = await prover1.wallet.getClaimSignature(schemaGvtId) + + proofClaims = {schemaGvt.seqId: ProofClaims(claimsGvt, ['name'], [])} + attr = attrRepo.getAttributes(schemaGvtId.schemaKey, prover1.proverId)['name'] + requestedProof = RequestedProof(revealed_attrs={'uuid': [str(schemaGvt.seqId), attr, str(encodeAttr(attr))]}) + + assert proofClaims, requestedProof == await prover1._findClaims(proofInput) + + +@pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') +@pytest.mark.asyncio +async def testOneRevealedFromOtherSchema(prover1, allClaims, schemaXyz): + proofInput = ProofInput(revealedAttrs={'uuid': AttributeInfo(name='name', schema_seq_no=schemaXyz.seqId)}) + + with pytest.raises(ValueError): + await prover1._findClaims(proofInput) + + +@pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') +@pytest.mark.asyncio +async def testOneRevealedFromSpecificSchemaAndIssuer(prover1, allClaims, schemaGvt, schemaGvtId, attrRepo, keysGvt): + proofInput = ProofInput(revealedAttrs={'uuid': AttributeInfo(name='name', schema_seq_no=schemaGvt.seqId, + issuer_did=schemaGvt.issuerId)}) + claimsGvt = await prover1.wallet.getClaimSignature(schemaGvtId) + + proofClaims = {schemaGvt.seqId: ProofClaims(claimsGvt, ['name'], [])} + attr = attrRepo.getAttributes(schemaGvtId.schemaKey, prover1.proverId)['name'] + requestedProof = RequestedProof(revealed_attrs={'uuid': [str(schemaGvt.seqId), attr, str(encodeAttr(attr))]}) + + assert proofClaims, requestedProof == await prover1._findClaims(proofInput) + + assert proofClaims, requestedProof == await prover1._findClaims(proofInput) + + +@pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') +@pytest.mark.asyncio +async def testOneRevealedFromOtherIssuer(prover1, allClaims, schemaGvt, schemaXyz): + proofInput = ProofInput(revealedAttrs={'uuid': AttributeInfo(name='name', schema_seq_no=schemaGvt.seqId, + issuer_did=schemaXyz.issuerId)}) + with pytest.raises(ValueError): await prover1._findClaims(proofInput) diff --git a/anoncreds/test/test_multiple_prover_multiple_issuers.py b/anoncreds/test/test_multiple_prover_multiple_issuers.py index ad6eb46..15c11b4 100644 --- a/anoncreds/test/test_multiple_prover_multiple_issuers.py +++ b/anoncreds/test/test_multiple_prover_multiple_issuers.py @@ -1,13 +1,14 @@ import pytest -from anoncreds.protocol.types import ProofInput, PredicateGE +from anoncreds.protocol.types import ProofInput, PredicateGE, AttributeInfo from anoncreds.test.conftest import presentProofAndVerify @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testNoPredicates(prover1, prover2, verifier, allClaims): - proofInput = ProofInput(['name', 'status'], []) + proofInput = ProofInput(revealedAttrs={'attr_uuid1': AttributeInfo(name='name'), + 'attr_uuid2': AttributeInfo(name='name')}) assert await presentProofAndVerify(verifier, proofInput, prover1) assert await presentProofAndVerify(verifier, proofInput, prover2) @@ -15,9 +16,9 @@ async def testNoPredicates(prover1, prover2, verifier, allClaims): @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testGePredicate(prover1, prover2, verifier, allClaims): - proofInput = ProofInput(['name'], - [PredicateGE('age', 18), - PredicateGE('period', 3)]) + proofInput = ProofInput(revealedAttrs={'attr_uuid1': AttributeInfo(name='name')}, + predicates={'predicate_uuid1': PredicateGE('age', 18), + 'predicate_uuid2': PredicateGE('period', 3)}) assert await presentProofAndVerify(verifier, proofInput, prover1) assert await presentProofAndVerify(verifier, proofInput, prover2) @@ -25,9 +26,9 @@ async def testGePredicate(prover1, prover2, verifier, allClaims): @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testGePredicateNegativeForOne(prover1, prover2, verifier, allClaims): - proofInput = ProofInput(['name'], - [PredicateGE('age', 18), - PredicateGE('period', 9)]) + proofInput = ProofInput(revealedAttrs={'attr_uuid1': AttributeInfo(name='name')}, + predicates={'predicate_uuid1': PredicateGE('age', 18), + 'predicate_uuid2': PredicateGE('period', 9)}) assert await presentProofAndVerify(verifier, proofInput, prover2) with pytest.raises(ValueError): await presentProofAndVerify(verifier, proofInput, prover1) @@ -36,9 +37,9 @@ async def testGePredicateNegativeForOne(prover1, prover2, verifier, allClaims): @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testGePredicateNegativeForBoth(prover1, prover2, verifier, allClaims): - proofInput = ProofInput(['name'], - [PredicateGE('age', 18), - PredicateGE('period', 30)]) + proofInput = ProofInput(revealedAttrs={'attr_uuid1': AttributeInfo(name='name')}, + predicates={'predicate_uuid1': PredicateGE('age', 38), + 'predicate_uuid2': PredicateGE('period', 30)}) with pytest.raises(ValueError): await presentProofAndVerify(verifier, proofInput, prover1) with pytest.raises(ValueError): diff --git a/anoncreds/test/test_non_revocation.py b/anoncreds/test/test_non_revocation.py index ac65012..b2d03ed 100644 --- a/anoncreds/test/test_non_revocation.py +++ b/anoncreds/test/test_non_revocation.py @@ -1,6 +1,6 @@ import pytest -from anoncreds.protocol.types import ProofInput +from anoncreds.protocol.types import ProofInput, ID, AttributeInfo from anoncreds.protocol.utils import groupIdentityG1 from anoncreds.test.conftest import presentProofAndVerify @@ -35,16 +35,16 @@ async def testRevoce(claimsProver1Gvt, issuerGvt, schemaGvtId): @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio -async def testUpdateWitnessNotChangedIfInSync(claimsProver1Gvt, schemaGvtId, +async def testUpdateWitnessNotChangedIfInSync(claimsProver1Gvt, schemaGvt, prover1): nonRevocClaimGvtProver1 = claimsProver1Gvt.nonRevocClaim - acc = await prover1.wallet.getAccumulator(schemaGvtId) + acc = await prover1.wallet.getAccumulator(ID(schemaId=schemaGvt.seqId)) # not changed as in sync oldOmega = nonRevocClaimGvtProver1.witness.omega c2 = await prover1._nonRevocProofBuilder.updateNonRevocationClaim( - schemaGvtId.schemaKey, + schemaGvt.seqId, nonRevocClaimGvtProver1) assert c2.witness.V == acc.V assert oldOmega == c2.witness.omega @@ -53,9 +53,9 @@ async def testUpdateWitnessNotChangedIfInSync(claimsProver1Gvt, schemaGvtId, @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testUpdateWitnessChangedIfOutOfSync(claimsProver1Gvt, issuerGvt, - schemaGvtId, prover1): + schemaGvt, prover1): nonRevocClaimGvtProver1 = claimsProver1Gvt.nonRevocClaim - acc = await issuerGvt.wallet.getAccumulator(schemaGvtId) + acc = await issuerGvt.wallet.getAccumulator(ID(schemaId=schemaGvt.seqId)) # not in sync acc.V.add(3) @@ -64,7 +64,7 @@ async def testUpdateWitnessChangedIfOutOfSync(claimsProver1Gvt, issuerGvt, # witness is updated oldOmega = nonRevocClaimGvtProver1.witness.omega c2 = await prover1._nonRevocProofBuilder.updateNonRevocationClaim( - schemaGvtId.schemaKey, + schemaGvt.seqId, nonRevocClaimGvtProver1) assert c2.witness.V == acc.V assert oldOmega != c2.witness.omega @@ -72,13 +72,13 @@ async def testUpdateWitnessChangedIfOutOfSync(claimsProver1Gvt, issuerGvt, @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio -async def testUpdateRevocedWitness(claimsProver1Gvt, issuerGvt, schemaGvtId, +async def testUpdateRevocedWitness(claimsProver1Gvt, issuerGvt, schemaGvt, prover1): nonRevocClaimGvtProver1 = claimsProver1Gvt.nonRevocClaim - await issuerGvt.revoke(schemaGvtId, 1) + await issuerGvt.revoke(ID(schemaId=schemaGvt.seqId), 1) with pytest.raises(ValueError): await prover1._nonRevocProofBuilder.updateNonRevocationClaim( - schemaGvtId.schemaKey, nonRevocClaimGvtProver1) + schemaGvt.seqId, nonRevocClaimGvtProver1) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @@ -86,11 +86,11 @@ async def testUpdateRevocedWitness(claimsProver1Gvt, issuerGvt, schemaGvtId, async def testInitNonRevocClaim(schemaGvtId, prover1, issuerGvt, attrsProver1Gvt, keysGvt, issueAccumulatorGvt): claimsReq = await prover1.createClaimRequest(schemaGvtId) - claims = await issuerGvt.issueClaim(schemaGvtId, claimsReq) + claim_signature, claim_attributes = await issuerGvt.issueClaim(schemaGvtId, claimsReq) - oldV = claims.nonRevocClaim.v - await prover1.processClaim(schemaGvtId, claims) - newC2 = (await prover1.wallet.getClaims(schemaGvtId)).nonRevocClaim + oldV = claim_signature.nonRevocClaim.v + await prover1.processClaim(schemaGvtId, claim_attributes, claim_signature) + newC2 = (await prover1.wallet.getClaimSignature(schemaGvtId)).nonRevocClaim vrPrime = ( await prover1.wallet.getNonRevocClaimInitData(schemaGvtId)).vPrime @@ -99,10 +99,10 @@ async def testInitNonRevocClaim(schemaGvtId, prover1, issuerGvt, @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio -async def testCAndTauList(claimsProver1Gvt, schemaGvtId, prover1): +async def testCAndTauList(claimsProver1Gvt, schemaGvt, prover1): nonRevocClaimGvtProver1 = claimsProver1Gvt.nonRevocClaim proofRevBuilder = prover1._nonRevocProofBuilder - assert await proofRevBuilder.testProof(schemaGvtId.schemaKey, + assert await proofRevBuilder.testProof(schemaGvt.seqId, nonRevocClaimGvtProver1) @@ -112,7 +112,7 @@ async def testRevocedWithUpdateWitness(schemaGvtId, issuerGvt, prover1, verifier, claimsProver1Gvt): await issuerGvt.revoke(schemaGvtId, 1) - proofInput = ProofInput(['name'], []) + proofInput = ProofInput(revealedAttrs={'attr_uuid': AttributeInfo(name='name')}) with pytest.raises(ValueError): await presentProofAndVerify(verifier, proofInput, prover1) @@ -121,10 +121,11 @@ async def testRevocedWithUpdateWitness(schemaGvtId, issuerGvt, prover1, @pytest.mark.asyncio async def testRevocedWithoutUpdateWitness(schemaGvtId, issuerGvt, prover1, verifier, claimsProver1Gvt): - proofInput = ProofInput(['name'], []) nonce = verifier.generateNonce() - proof, revealedAttrs = await prover1.presentProof(proofInput, nonce) + proofInput = ProofInput(nonce, {'attr_uuid': AttributeInfo(name='name')}) + + proof = await prover1.presentProof(proofInput) await issuerGvt.revoke(schemaGvtId, 1) - return await verifier.verify(proofInput, proof, revealedAttrs, nonce) + return await verifier.verify(proofInput, proof) diff --git a/anoncreds/test/test_single_prover_multiple_issuers.py b/anoncreds/test/test_single_prover_multiple_issuers.py index 8b3ec99..7b5003e 100644 --- a/anoncreds/test/test_single_prover_multiple_issuers.py +++ b/anoncreds/test/test_single_prover_multiple_issuers.py @@ -1,34 +1,38 @@ import pytest -from anoncreds.protocol.types import ProofInput, PredicateGE +from anoncreds.protocol.types import ProofInput, PredicateGE, AttributeInfo from anoncreds.test.conftest import presentProofAndVerify @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testNoPredicates(prover1, verifier, claimsProver1): - proofInput = ProofInput(['name', 'status'], []) + proofInput = ProofInput(revealedAttrs={'uuid1': AttributeInfo(name='name'), + 'uuid2': AttributeInfo(name='status')}, predicates={}) assert await presentProofAndVerify(verifier, proofInput, prover1) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testGePredicate(prover1, verifier, claimsProver1): - proofInput = ProofInput(['name'], [PredicateGE('period', 5)]) + proofInput = ProofInput(revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid': PredicateGE('period', 5)}) assert await presentProofAndVerify(verifier, proofInput, prover1) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testGePredicateForEqual(prover1, verifier, claimsProver1): - proofInput = ProofInput(['name'], [PredicateGE('period', 8)]) + proofInput = ProofInput(revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid': PredicateGE('period', 8)}) assert await presentProofAndVerify(verifier, proofInput, prover1) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testGePredicateNegative(prover1, verifier, claimsProver1): - proofInput = ProofInput(['name'], [PredicateGE('period', 9)]) + proofInput = ProofInput(revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid': PredicateGE('period', 9)}) with pytest.raises(ValueError): await presentProofAndVerify(verifier, proofInput, prover1) @@ -36,9 +40,9 @@ async def testGePredicateNegative(prover1, verifier, claimsProver1): @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testMultipleGePredicate(prover1, verifier, claimsProver1): - proofInput = ProofInput(['name'], - [PredicateGE('age', 18), - PredicateGE('period', 5)]) + proofInput = ProofInput(revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid1': PredicateGE('age', 18), + 'predicate_uuid2': PredicateGE('period', 5)}) await presentProofAndVerify(verifier, proofInput, prover1) @@ -46,17 +50,18 @@ async def testMultipleGePredicate(prover1, verifier, claimsProver1): @pytest.mark.asyncio async def testMultipleGePredicateMultipleRevealed(prover1, verifier, claimsProver1): - proofInput = ProofInput(['name', 'status'], - [PredicateGE('age', 18), - PredicateGE('period', 5)]) + proofInput = ProofInput(revealedAttrs={'attr_uuid1': AttributeInfo(name='name'), + 'attr_uuid2': AttributeInfo(name='status')}, + predicates={'predicate_uuid1': PredicateGE('age', 18), + 'predicate_uuid2': PredicateGE('period', 5)}) await presentProofAndVerify(verifier, proofInput, prover1) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testMultipleGePredicateNegative(prover1, verifier, claimsProver1): - proofInput = ProofInput(['name'], - [PredicateGE('age', 18), - PredicateGE('period', 9)]) + proofInput = ProofInput(revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid1': PredicateGE('age', 18), + 'predicate_uuid2': PredicateGE('period', 9)}) with pytest.raises(ValueError): await presentProofAndVerify(verifier, proofInput, prover1) diff --git a/anoncreds/test/test_single_prover_single_issuer.py b/anoncreds/test/test_single_prover_single_issuer.py index 7973f00..9295cff 100644 --- a/anoncreds/test/test_single_prover_single_issuer.py +++ b/anoncreds/test/test_single_prover_single_issuer.py @@ -1,52 +1,55 @@ import pytest from anoncreds.protocol.types import ProofInput, PredicateGE, Claims, \ - ProofClaims + ProofClaims, AttributeInfo from anoncreds.test.conftest import presentProofAndVerify @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testPrimaryClaimOnlyEmpty(prover1, verifier, claimsProver1Gvt, nonce): - proofInput = ProofInput([]) - claims, revealedAttrs = await prover1._findClaims(proofInput) - claims = {schemaKey: ProofClaims( + proofInput = ProofInput(nonce, {}) + claims, requestedProof = await prover1._findClaims(proofInput) + claims = {schemaId: ProofClaims( Claims(primaryClaim=proofClaim.claims.primaryClaim)) - for schemaKey, proofClaim in claims.items()} - proof = await prover1._prepareProof(claims, nonce) - assert await verifier.verify(proofInput, proof, revealedAttrs, nonce) + for schemaId, proofClaim in claims.items()} + + proof = await prover1._prepareProof(claims, proofInput.nonce, requestedProof) + + assert await verifier.verify(proofInput, proof) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testPrimaryClaimNoPredicates(prover1, verifier, claimsProver1Gvt, nonce, schemaGvtId): - revealledAttrNames = ['name'] - proofInput = ProofInput(revealledAttrNames) - claims, revealedAttrs = await prover1._findClaims(proofInput) + proofInput = ProofInput(nonce=nonce, revealedAttrs={'uuid1': AttributeInfo(name='name')}, predicates={}) + + claims, requestedProof = await prover1._findClaims(proofInput) claims = { - schemaKey: ProofClaims( - Claims(primaryClaim=proofClaim.claims.primaryClaim), - revealedAttrs=revealledAttrNames) - for schemaKey, proofClaim in claims.items()} - proof = await prover1._prepareProof(claims, nonce) + schemaId: ProofClaims( + Claims(primaryClaim=proofClaim.claims.primaryClaim), [AttributeInfo(name='name')], []) + for schemaId, proofClaim in claims.items()} + proof = await prover1._prepareProof(claims, proofInput.nonce, requestedProof) - assert await verifier.verify(proofInput, proof, revealedAttrs, nonce) + assert await verifier.verify(proofInput, proof) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testPrimaryClaimPredicatesOnly(prover1, verifier, claimsProver1Gvt, nonce, schemaGvtId): - predicates = [PredicateGE('age', 18)] - proofInput = ProofInput(predicates=predicates) - claims, revealedAttrs = await prover1._findClaims(proofInput) - claims = {schemaKey: ProofClaims( - Claims(primaryClaim=proofClaim.claims.primaryClaim), - predicates=predicates) - for schemaKey, proofClaim in claims.items()} - proof = await prover1._prepareProof(claims, nonce) - assert await verifier.verify(proofInput, proof, revealedAttrs, nonce) + predicate = PredicateGE('age', 18) + proofInput = ProofInput(nonce=nonce, predicates={'uuid': predicate}) + claims, requestedProof = await prover1._findClaims(proofInput) + claims = { + schemaId: ProofClaims( + Claims(primaryClaim=proofClaim.claims.primaryClaim), predicates=[predicate]) + for schemaId, proofClaim in claims.items()} + + proof = await prover1._prepareProof(claims, proofInput.nonce, requestedProof) + + assert await verifier.verify(proofInput, proof) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @@ -58,35 +61,39 @@ async def testEmpty(prover1, verifier, claimsProver1Gvt): @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testNoPredicates(prover1, verifier, claimsProver1Gvt): - proofInput = ProofInput(['name'], []) + proofInput = ProofInput(revealedAttrs={'uuid': AttributeInfo(name='name')}, predicates={}) assert await presentProofAndVerify(verifier, proofInput, prover1) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testMultipleRevealedAttrs(prover1, verifier, claimsProver1Gvt): - proofInput = ProofInput(['name', 'sex'], []) + proofInput = ProofInput(revealedAttrs={'uuid1': AttributeInfo(name='name'), + 'uuid2': AttributeInfo(name='sex')}, predicates={}) assert await presentProofAndVerify(verifier, proofInput, prover1) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testGePredicate(prover1, verifier, claimsProver1Gvt): - proofInput = ProofInput(['name'], [PredicateGE('age', 18)]) + proofInput = ProofInput(revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid': PredicateGE('age', 18)}) assert await presentProofAndVerify(verifier, proofInput, prover1) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testGePredicateForEqual(prover1, verifier, claimsProver1Gvt): - proofInput = ProofInput(['name'], [PredicateGE('age', 28)]) + proofInput = ProofInput(revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid': PredicateGE('age', 28)}) assert await presentProofAndVerify(verifier, proofInput, prover1) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testGePredicateNegative(prover1, verifier, claimsProver1Gvt): - proofInput = ProofInput(['name'], [PredicateGE('age', 29)]) + proofInput = ProofInput(revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid': PredicateGE('age', 29)}) with pytest.raises(ValueError): await presentProofAndVerify(verifier, proofInput, prover1) @@ -94,18 +101,18 @@ async def testGePredicateNegative(prover1, verifier, claimsProver1Gvt): @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testMultipleGePredicate(prover1, verifier, claimsProver1Gvt): - proofInput = ProofInput(['name'], - [PredicateGE('age', 18), - PredicateGE('height', 170)]) + proofInput = ProofInput(revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid1': PredicateGE('age', 18), + 'predicate_uuid2': PredicateGE('height', 170)}) assert await presentProofAndVerify(verifier, proofInput, prover1) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testMultipleGePredicateNegative(prover1, verifier, claimsProver1Gvt): - proofInput = ProofInput(['name'], - [PredicateGE('age', 18), - PredicateGE('height', 180)]) + proofInput = ProofInput(revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid1': PredicateGE('age', 18), + 'predicate_uuid2': PredicateGE('height', 180)}) with pytest.raises(ValueError): await presentProofAndVerify(verifier, proofInput, prover1) @@ -114,21 +121,13 @@ async def testMultipleGePredicateNegative(prover1, verifier, claimsProver1Gvt): @pytest.mark.asyncio async def testNonceShouldBeSame(prover1, verifier, claimsProver1Gvt, nonce, genNonce): - revealedAttrs = ['name'] - proofInput = ProofInput(revealedAttrs, []) - proof, revealedAttrs = await prover1.presentProof(proofInput, nonce) - assert not await verifier.verify(proofInput, proof, revealedAttrs, genNonce) + nonce = verifier.generateNonce() + proofInput = ProofInput(nonce, {'attr_uuid': AttributeInfo(name='name')}) + proof = await prover1.presentProof(proofInput) -@pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') -def testAttrsInClaims(claimsProver1Gvt, attrsProver1Gvt): - attrs = claimsProver1Gvt.primaryClaim.attrs - encodedAttrs = claimsProver1Gvt.primaryClaim.encodedAttrs - - assert attrs - assert encodedAttrs - assert attrs == attrsProver1Gvt._vals - assert encodedAttrs.keys() == attrsProver1Gvt.keys() + proofInput = ProofInput(genNonce, proofInput.revealedAttrs, proofInput.predicates) + assert not await verifier.verify(proofInput, proof) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @@ -139,10 +138,11 @@ async def testUParamShouldBeSame(prover1, verifier, issuerGvt, schemaGvtId, claimsReq = await prover1.createClaimRequest(schemaGvtId) claimsReq = claimsReq._replace(U=claimsReq.U ** 2) - claims = await issuerGvt.issueClaim(schemaGvtId, claimsReq) - await prover1.processClaim(schemaGvtId, claims) + claim_signature, claim_attributes = await issuerGvt.issueClaim(schemaGvtId, claimsReq) + await prover1.processClaim(schemaGvtId, claim_attributes, claim_signature) - proofInput = ProofInput(['name'], []) + proofInput = ProofInput(revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={}) assert not await presentProofAndVerify(verifier, proofInput, prover1) @@ -153,7 +153,7 @@ async def testUrParamShouldBeSame(prover1, issuerGvt, schemaGvtId, claimsReq = await prover1.createClaimRequest(schemaGvtId) claimsReq = claimsReq._replace(Ur=claimsReq.Ur ** 2) - claims = await issuerGvt.issueClaim(schemaGvtId, claimsReq) + claim_signature, claim_attributes = await issuerGvt.issueClaim(schemaGvtId, claimsReq) with pytest.raises(ValueError): - await prover1.processClaim(schemaGvtId, claims) + await prover1.processClaim(schemaGvtId, claim_attributes, claim_signature) diff --git a/anoncreds/test/test_types.py b/anoncreds/test/test_types.py index 5894df1..764328a 100644 --- a/anoncreds/test/test_types.py +++ b/anoncreds/test/test_types.py @@ -2,14 +2,15 @@ from anoncreds.protocol.types import PublicKey, Schema, Claims, \ ProofInput, PredicateGE, FullProof, \ - SchemaKey, ClaimRequest, Proof + SchemaKey, ClaimRequest, Proof, AttributeInfo, ProofInfo, AggregatedProof, RequestedProof, PrimaryProof, \ + PrimaryEqualProof, PrimaryPredicateGEProof, ID, ClaimAttributeValues from anoncreds.protocol.utils import toDictWithStrValues, fromDictWithStrValues from config.config import cmod def testSchemaKeyFromToDict(): schemaKey = SchemaKey(name='schemaName', version='1.0', - issuerId='issuer1') + issuerId='issuer1') assert schemaKey == SchemaKey.fromStrDict( schemaKey.toStrDict()) @@ -90,35 +91,301 @@ def testClaimsFromToDictPrimaryOnly(claimsProver1Gvt): assert claims == Claims.fromStrDict(claims.toStrDict()) +@pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') +@pytest.mark.asyncio +async def testAggregatedProofFromToDict(prover1, nonce, claimsProver1Gvt): + proofInput = ProofInput(nonce=nonce, + revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid': PredicateGE('age', 18)}) + + proof = await prover1.presentProof(proofInput) + + assert proof.aggregatedProof == AggregatedProof.fromStrDict(proof.aggregatedProof.toStrDict()) + + +@pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') +@pytest.mark.asyncio +async def testRequestedProofFromToDict(prover1, nonce, claimsProver1Gvt): + proofInput = ProofInput(nonce=nonce, + revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid': PredicateGE('age', 18)}) + + proof = await prover1.presentProof(proofInput) + + assert proof.requestedProof == RequestedProof.fromStrDict(proof.requestedProof.toStrDict()) + + @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio async def testClaimProofFromToDict(prover1, nonce, claimsProver1Gvt): - proofInput = ProofInput(['name'], [PredicateGE('age', 18)]) - proof, _ = await prover1.presentProof(proofInput, nonce) + proofInput = ProofInput(nonce=nonce, + revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid': PredicateGE('age', 18)}) + + proof = await prover1.presentProof(proofInput) + assert proof == FullProof.fromStrDict(proof.toStrDict()) @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio -async def testClaimProofFromToDictPrimaryOnly(prover1, nonce, claimsProver1Gvt): - proofInput = ProofInput(['name'], [PredicateGE('age', 18)]) - proof, _ = await prover1.presentProof(proofInput, nonce) +async def testClaimProofFromToDictPrimaryOnly(prover1, nonce, claimsProver1Gvt, schemaGvt): + proofInput = ProofInput(nonce=nonce, + revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid': PredicateGE('age', 18)}) - proofs = [Proof(primaryProof=proof.proofs[0].primaryProof)] + proof = await prover1.presentProof(proofInput) + + proofInfo = proof.proofs[str(schemaGvt.seqId)] + proofs = {schemaGvt.seqId: ProofInfo(Proof(primaryProof=proofInfo.proof.primaryProof), + issuer_did=schemaGvt.issuerId, + schema_seq_no=proofInfo.schema_seq_no)} proof = proof._replace(proofs=proofs) assert proof == FullProof.fromStrDict(proof.toStrDict()) def testProofInputFromToDict(): - proofInput = ProofInput(['name', 'age'], - [PredicateGE('age', 18), PredicateGE('age', 25)]) + proofInput = ProofInput(nonce=1, + revealedAttrs={'attr_uuid1': AttributeInfo(name='name'), + 'attr_uuid2': AttributeInfo(name='age')}, + predicates={'predicate_uuid1': PredicateGE('age', 18), + 'predicate_uuid2': PredicateGE('age', 25)}) + assert proofInput == ProofInput.fromStrDict(proofInput.toStrDict()) +def test_proof_input_from_to_dict(): + proof_input = ProofInput(nonce=1, + revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid': PredicateGE('age', 18)}) + + proof_input_serialized = { + 'nonce': '1', + 'revealedAttrs': {'attr_uuid': {'name': 'name', 'schema_seq_no': None, 'issuer_did': None}}, + 'predicates': {'predicate_uuid': {'p_type': 'ge', 'value': 18, 'attr_name': 'age', 'schema_seq_no': None, + 'issuer_did': None}} + } + assert proof_input.to_str_dict() == proof_input_serialized + assert proof_input == ProofInput.from_str_dict(proof_input_serialized) + assert proof_input == ProofInput.from_str_dict(proof_input.to_str_dict()) + + +@pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') +@pytest.mark.asyncio +async def test_requested_proof_from_to_dict(prover1, nonce, claimsProver1Gvt): + proofInput = ProofInput(nonce=nonce, + revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid': PredicateGE('age', 18)}) + + proof = await prover1.presentProof(proofInput) + + requested_proof_serialized = { + 'revealed_attrs': {'attr_uuid': ['1', 'Alex', '1139481716457488690172217916278103335']}, + 'predicates': {'predicate_uuid': '1'}, + 'self_attested_attrs': {}, + 'unrevealed_attrs': {} + } + + assert proof.requestedProof.to_str_dict() == requested_proof_serialized + assert proof.requestedProof == RequestedProof.from_str_dict(requested_proof_serialized) + assert proof.requestedProof == RequestedProof.from_str_dict(proof.requestedProof.to_str_dict()) + + @pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') @pytest.mark.asyncio -async def testRevealedAttrsFromToDict(prover1, nonce, claimsProver1Gvt): - proofInput = ProofInput(['name'], [PredicateGE('age', 18)]) - _, revealedAttrs = await prover1.presentProof(proofInput, nonce) - assert revealedAttrs == fromDictWithStrValues( - toDictWithStrValues(revealedAttrs)) +async def test_attribute_values_from_to_dict(): + attr_values = ClaimAttributeValues(raw='Alex', encoded=cmod.integer(11)) + + attr_values_serialized = ['Alex', '11'] + + assert attr_values.to_str_dict() == attr_values_serialized + assert attr_values == ClaimAttributeValues.from_str_dict(attr_values_serialized) + assert attr_values == ClaimAttributeValues.from_str_dict(attr_values.to_str_dict()) + + +@pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') +@pytest.mark.asyncio +async def test_aggregated_proof_from_to_dict(prover1, nonce, claimsProver1Gvt): + aggregated_proof = AggregatedProof(1, [cmod.integer(111), cmod.integer(32321), cmod.integer(323)]) + + aggregated_proof_serialized = { + 'c_hash': '1', + 'c_list': [[111], [126, 65], [1, 67]] + } + + assert aggregated_proof.to_str_dict() == aggregated_proof_serialized + assert aggregated_proof == AggregatedProof.from_str_dict(aggregated_proof_serialized) + assert aggregated_proof == AggregatedProof.from_str_dict(aggregated_proof.to_str_dict()) + + +@pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') +@pytest.mark.asyncio +async def test_equal_proof_from_to_dict(): + n = cmod.integer(12345) + + eqProof = PrimaryEqualProof(e=cmod.integer(1), v=cmod.integer(11), m={'name': cmod.integer(12)}, + m1=cmod.integer(12), m2=cmod.integer(32), Aprime=cmod.integer(32) % n, + revealedAttrs={'name': cmod.integer(35)}) + + proof_serialized = { + 'a_prime': '32', + 'e': '1', + 'm': {'name': '12'}, + 'm1': '12', + 'm2': '32', + 'v': '11', + 'revealed_attrs': {'name': '35'} + } + + assert eqProof.to_str_dict() == proof_serialized + assert eqProof == PrimaryEqualProof.from_str_dict(proof_serialized, n) + assert eqProof == PrimaryEqualProof.from_str_dict(eqProof.to_str_dict(), n) + + +@pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') +@pytest.mark.asyncio +async def test_ge_proof_from_to_dict(): + n = cmod.integer(12345) + + predicate = PredicateGE(attrName='age', value=18) + geProof = PrimaryPredicateGEProof(alpha=cmod.integer(1), mj=cmod.integer(12), r={'1': cmod.integer(13)}, + u={'1': cmod.integer(42)}, T={'1': cmod.integer(21) % n}, predicate=predicate) + + proof_serialized = { + 'alpha': '1', + 'mj': '12', + 't': {'1': '21'}, + 'r': {'1': '13'}, + 'u': {'1': '42'}, + 'predicate': { + 'p_type': 'ge', + 'attr_name': 'age', + 'value': 18, + 'schema_seq_no': None, + 'issuer_did': None + } + } + + assert geProof.to_str_dict() == proof_serialized + assert geProof == PrimaryPredicateGEProof.from_str_dict(proof_serialized, n) + assert geProof == PrimaryPredicateGEProof.from_str_dict(geProof.to_str_dict(), n) + + +@pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') +@pytest.mark.asyncio +async def test_primary_proof_from_to_dict(): + n = cmod.integer(12345) + + eqProof = PrimaryEqualProof(e=cmod.integer(1), v=cmod.integer(11), m={'name': cmod.integer(12)}, + m1=cmod.integer(12), m2=cmod.integer(32), Aprime=cmod.integer(32) % n, + revealedAttrs={'name': cmod.integer(35)}) + + predicate = PredicateGE(attrName='age', value=18) + geProof = PrimaryPredicateGEProof(alpha=cmod.integer(1), mj=cmod.integer(12), r={'1': cmod.integer(13)}, + u={'1': cmod.integer(42)}, T={'1': cmod.integer(21) % n}, predicate=predicate) + primaryProof = PrimaryProof(eqProof=eqProof, geProofs=[geProof]) + + proof_serialized = { + 'eq_proof': { + 'a_prime': '32', + 'e': '1', + 'm': {'name': '12'}, + 'm1': '12', + 'm2': '32', + 'v': '11', + 'revealed_attrs': {'name': '35'} + }, + 'ge_proofs': [ + { + 'alpha': '1', + 'mj': '12', + 't': {'1': '21'}, + 'r': {'1': '13'}, + 'u': {'1': '42'}, + 'predicate': { + 'p_type': 'ge', + 'attr_name': 'age', + 'value': 18, + 'schema_seq_no': None, + 'issuer_did': None + } + } + ] + } + + assert primaryProof.to_str_dict() == proof_serialized + assert primaryProof == PrimaryProof.from_str_dict(proof_serialized, n) + assert primaryProof == PrimaryProof.from_str_dict(primaryProof.to_str_dict(), n) + + +@pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') +@pytest.mark.asyncio +async def test_proof_info_from_to_dict(): + n = cmod.integer(12345) + + eqProof = PrimaryEqualProof(e=cmod.integer(1), v=cmod.integer(11), m={'name': cmod.integer(12)}, + m1=cmod.integer(12), m2=cmod.integer(32), Aprime=cmod.integer(32) % n, + revealedAttrs={'name': cmod.integer(35)}) + + predicate = PredicateGE(attrName='age', value=18) + geProof = PrimaryPredicateGEProof(alpha=cmod.integer(1), mj=cmod.integer(12), r={'1': cmod.integer(13)}, + u={'1': cmod.integer(42)}, T={'1': cmod.integer(21) % n}, predicate=predicate) + primaryProof = PrimaryProof(eqProof=eqProof, geProofs=[geProof]) + proofInfo = Proof(primaryProof=primaryProof) + proof = ProofInfo(schema_seq_no=1, proof=proofInfo, issuer_did='did') + + proof_serialized = { + 'issuer_did': 'did', + 'schema_seq_no': 1, + 'proof': { + 'primary_proof': { + 'eq_proof': { + 'a_prime': '32', + 'e': '1', + 'm': {'name': '12'}, + 'm1': '12', + 'm2': '32', + 'v': '11', + 'revealed_attrs': {'name': '35'} + }, + 'ge_proofs': [ + { + 'alpha': '1', + 'mj': '12', + 't': {'1': '21'}, + 'r': {'1': '13'}, + 'u': {'1': '42'}, + 'predicate': { + 'p_type': 'ge', + 'attr_name': 'age', + 'value': 18, + 'schema_seq_no': None, + 'issuer_did': None + } + } + ] + } + } + } + + assert proof.to_str_dict() == proof_serialized + assert proof == ProofInfo.from_str_dict(proof_serialized, n) + assert proof == ProofInfo.from_str_dict(proof.to_str_dict(), n) + + +@pytest.mark.skipif('sys.platform == "win32"', reason='SOV-86') +@pytest.mark.asyncio +async def test_proof_from_to_dict(prover1, nonce, claimsProver1Gvt, schemaGvt): + n = (await prover1.wallet.getPublicKey(ID(schemaId=schemaGvt.seqId))).N + proofInput = ProofInput(nonce=nonce, + revealedAttrs={'attr_uuid': AttributeInfo(name='name')}, + predicates={'predicate_uuid': PredicateGE('age', 18)}) + + proof = await prover1.presentProof(proofInput) + + proofInfo = proof.proofs[str(schemaGvt.seqId)] + proof = ProofInfo(Proof(primaryProof=proofInfo.proof.primaryProof), + issuer_did=schemaGvt.issuerId, + schema_seq_no=proofInfo.schema_seq_no) + + assert proof == ProofInfo.from_str_dict(proof.to_str_dict(), n) diff --git a/anoncreds/test/test_util.py b/anoncreds/test/test_util.py index 1b1d9e0..75baa08 100644 --- a/anoncreds/test/test_util.py +++ b/anoncreds/test/test_util.py @@ -4,7 +4,7 @@ from anoncreds.protocol.globals import PAIRING_GROUP from anoncreds.protocol.utils import toDictWithStrValues, \ - deserializeFromStr, serializeToStr, fromDictWithStrValues, get_hash_as_int + deserializeFromStr, serializeToStr, fromDictWithStrValues, get_hash_as_int, intToArrayBytes, bytesToInt from anoncreds.test.conftest import primes from config.config import cmod @@ -199,3 +199,18 @@ def _checkHashEqual(input): h1 = get_hash_as_int(*input) h2 = get_hash_as_int(*reversed(input)) assert h1 == h2 + + +def testIntToArrayBytes(): + val = cmod.integer(1606507817390189252221968804450207070282033) + res = [18, 113, 26, 39, 35, 240, 231, 239, 92, 226, 84, 46, 230, 174, 230, 41, 225, 49] + assert res == intToArrayBytes(val) + +def testBytesToInt(): + val = [18, 113, 26, 39, 35, 240, 231, 239, 92, 226, 84, 46, 230, 174, 230, 41, 225, 49] + res = 1606507817390189252221968804450207070282033 + assert res == bytesToInt(val) + +def testIntToArrayBytesAndBack(): + val = cmod.integer(1606507817390189252221968804450207070282033) + assert val == bytesToInt(intToArrayBytes(val)) \ No newline at end of file