From 36457dacc7fbb2b83751331474f3041c1c6297c1 Mon Sep 17 00:00:00 2001 From: Dimasik Kolezhniuk Date: Tue, 27 Jun 2023 09:59:34 +0200 Subject: [PATCH] Use latest JSON-LD merklizer --- package-lock.json | 8 +- package.json | 2 +- src/circuits/common.ts | 1 - src/circuits/models.ts | 2 +- src/credentials/status/on-chain-revocation.ts | 18 +- src/iden3comm/handlers/auth.ts | 2 +- src/identity/identity-wallet.ts | 48 +- src/index.ts | 2 + src/loaders/index.ts | 1 - src/loaders/schema.ts | 122 ----- src/proof/proof-service.ts | 65 ++- src/schema-processor/json/parser.ts | 7 +- src/verifiable/credential.ts | 6 +- .../atomic-query-mtp-v2-on-chain.test.ts | 46 +- .../atomic-query-sig-v2-on-chain.test.ts | 34 +- tests/circuits/utils.ts | 2 +- tests/proofs/mtp-onchain.test.ts | 468 +++++++++--------- tests/proofs/sig-onchain.test.ts | 394 +++++++-------- 18 files changed, 594 insertions(+), 634 deletions(-) delete mode 100644 src/loaders/schema.ts diff --git a/package-lock.json b/package-lock.json index b433f437..64879038 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@iden3/js-crypto": "1.0.0-beta.1", "@iden3/js-iden3-core": "1.0.0-beta.2", - "@iden3/js-jsonld-merklization": "1.0.0-beta.8", + "@iden3/js-jsonld-merklization": "1.0.0-beta.13", "@iden3/js-jwz": "1.0.0-beta.2", "@iden3/js-merkletree": "1.0.0-beta.4", "@lumeweb/js-sha3-browser": "^0.8.1", @@ -1424,9 +1424,9 @@ } }, "node_modules/@iden3/js-jsonld-merklization": { - "version": "1.0.0-beta.8", - "resolved": "https://registry.npmjs.org/@iden3/js-jsonld-merklization/-/js-jsonld-merklization-1.0.0-beta.8.tgz", - "integrity": "sha512-PK/WUosJ8hy3xFFVS9bX+EUwgQF36Jh+0sZcHTfM5Szak7BkCDokxd8G5Wp2HertQyiZ0AIk0iL4MiieS/sQOg==", + "version": "1.0.0-beta.13", + "resolved": "https://registry.npmjs.org/@iden3/js-jsonld-merklization/-/js-jsonld-merklization-1.0.0-beta.13.tgz", + "integrity": "sha512-V26tksTEmNWRsfeP1prKaokdGPaNOZ78O1cwhDb2DyrhnO3H3/e94O+rKkHshLdOnSivRvPA2YYkyzIl/Nqqxw==", "dependencies": { "@iden3/js-crypto": "1.0.0-beta.1", "@iden3/js-merkletree": "1.0.0-beta.2", diff --git a/package.json b/package.json index 5d58c079..5f66e11d 100644 --- a/package.json +++ b/package.json @@ -67,7 +67,7 @@ "dependencies": { "@iden3/js-crypto": "1.0.0-beta.1", "@iden3/js-iden3-core": "1.0.0-beta.2", - "@iden3/js-jsonld-merklization": "1.0.0-beta.8", + "@iden3/js-jsonld-merklization": "1.0.0-beta.13", "@iden3/js-jwz": "1.0.0-beta.2", "@iden3/js-merkletree": "1.0.0-beta.4", "@lumeweb/js-sha3-browser": "^0.8.1", diff --git a/src/circuits/common.ts b/src/circuits/common.ts index 1caee29b..a045960c 100644 --- a/src/circuits/common.ts +++ b/src/circuits/common.ts @@ -68,7 +68,6 @@ export class BaseConfig { getMTLevelOnChain(): number { return this.mtLevelOnChain ? this.mtLevelOnChain : defaultMTLevelsOnChain; } - } /** diff --git a/src/circuits/models.ts b/src/circuits/models.ts index b6c1b6ad..be50d5fd 100644 --- a/src/circuits/models.ts +++ b/src/circuits/models.ts @@ -70,7 +70,7 @@ export enum CircuitId { // AtomicQuerySig is a type for credentialAttrQuerySig.circom AtomicQuerySigV2 = 'credentialAtomicQuerySigV2', // AtomicQuerySigOnChain is a type for credentialAtomicQuerySigOnChain.circom - AtomicQuerySigV2OnChain = 'credentialAtomicQuerySigV2OnChain', + AtomicQuerySigV2OnChain = 'credentialAtomicQuerySigV2OnChain' } /** diff --git a/src/credentials/status/on-chain-revocation.ts b/src/credentials/status/on-chain-revocation.ts index e8fd311c..ef9ad907 100644 --- a/src/credentials/status/on-chain-revocation.ts +++ b/src/credentials/status/on-chain-revocation.ts @@ -21,9 +21,12 @@ export class OnChainResolver implements CredentialStatusResolver { */ constructor(private readonly _configs: EthConnectionConfig[]) {} - async resolve(credentialStatus: CredentialStatus, opts: { - issuer: DID; - }): Promise { + async resolve( + credentialStatus: CredentialStatus, + opts: { + issuer: DID; + } + ): Promise { return this.getRevocationOnChain(credentialStatus, opts.issuer); } @@ -34,10 +37,11 @@ export class OnChainResolver implements CredentialStatusResolver { * @param {DID} issuerDid - issuer did * @returns Promise */ - async getRevocationOnChain(credentialStatus: CredentialStatus, issuer: DID): Promise { - const { contractAddress, chainId, revocationNonce } = this.parseOnChainId( - credentialStatus.id - ); + async getRevocationOnChain( + credentialStatus: CredentialStatus, + issuer: DID + ): Promise { + const { contractAddress, chainId, revocationNonce } = this.parseOnChainId(credentialStatus.id); if (revocationNonce !== credentialStatus.revocationNonce) { throw new Error('revocationNonce does not match'); } diff --git a/src/iden3comm/handlers/auth.ts b/src/iden3comm/handlers/auth.ts index e0756662..01dfd6fa 100644 --- a/src/iden3comm/handlers/auth.ts +++ b/src/iden3comm/handlers/auth.ts @@ -250,7 +250,7 @@ export class AuthHandler implements IAuthHandler { { authProfileNonce: authProfileNonce, credentialSubjectProfileNonce: r.credentialSubjectProfileNonce, - skipRevocation: false, + skipRevocation: false } ); diff --git a/src/identity/identity-wallet.ts b/src/identity/identity-wallet.ts index 5f55d648..5b996273 100644 --- a/src/identity/identity-wallet.ts +++ b/src/identity/identity-wallet.ts @@ -21,7 +21,6 @@ import { JSONSchema, Parser, CoreClaimOptions } from '../schema-processor'; import { IDataStorage } from '../storage/interfaces/data-storage'; import { MerkleTreeType } from '../storage/entities/mt'; import { getRandomBytes, keyPath } from '../kms/provider-helpers'; -import { UniversalSchemaLoader } from '../loaders'; import { VerifiableConstants, BJJSignatureProof2021, @@ -37,7 +36,12 @@ import { import { CredentialRequest, ICredentialWallet } from '../credentials'; import { pushHashesToRHS, TreesModel } from '../credentials/rhs'; import { TreeState } from '../circuits'; -import { byteDecoder } from '../utils'; +import { byteEncoder } from '../utils'; +import { + Options as MerklizerOptions, + Path, + getDocumentLoader +} from '@iden3/js-jsonld-merklization'; /** * DID creation options @@ -539,13 +543,26 @@ export class IdentityWallet implements IIdentityWallet { } /** {@inheritDoc IIdentityWallet.issueCredential} */ - async issueCredential(issuerDID: DID, req: CredentialRequest): Promise { + async issueCredential( + issuerDID: DID, + req: CredentialRequest, + opts?: MerklizerOptions + ): Promise { req.revocationOpts.id = req.revocationOpts.id.replace(/\/$/, ''); - const schema = await new UniversalSchemaLoader('ipfs.io').load(req.credentialSchema); - - const jsonSchema: JSONSchema = JSON.parse(byteDecoder.decode(schema)); + let schema: object; + const loader = + opts?.documentLoader ?? + getDocumentLoader({ + ipfsNodeURL: 'ipfs.io' + }); + try { + schema = (await loader(req.credentialSchema)).document; + } catch (e) { + throw new Error(`can't load credential schema ${req.credentialSchema}`); + } + const jsonSchema = schema as JSONSchema; let credential: W3CCredential = new W3CCredential(); req.revocationOpts.nonce = @@ -571,10 +588,25 @@ export class IdentityWallet implements IIdentityWallet { version: 0 }; + let jsonLDCtx: object; + try { + jsonLDCtx = (await loader(jsonSchema.$metadata.uris.jsonLdContext)).document; + } catch (e) { + throw new Error(`can't load json-ld schema ${jsonSchema.$metadata.uris.jsonLdContext}`); + } + + const schemaBytes = byteEncoder.encode(JSON.stringify(jsonSchema)); + + const credentialType = await Path.getTypeIDFromContext( + JSON.stringify(jsonLDCtx), + req.type, + opts + ); + const coreClaim = await new Parser().parseClaim( credential, - `${jsonSchema.$metadata.uris['jsonLdContext']}#${req.type}`, - schema, + credentialType, + schemaBytes, coreClaimOpts ); diff --git a/src/index.ts b/src/index.ts index 314c6e33..0d89107b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -11,4 +11,6 @@ export * from './loaders'; export * from './iden3comm/handlers'; export * from './utils'; import * as core from '@iden3/js-iden3-core'; +import * as jsonLDMerklizer from '@iden3/js-jsonld-merklization'; export { core }; +export { jsonLDMerklizer }; diff --git a/src/loaders/index.ts b/src/loaders/index.ts index 3d5b8ff7..0a33c489 100644 --- a/src/loaders/index.ts +++ b/src/loaders/index.ts @@ -1,2 +1 @@ export * from './key'; -export * from './schema'; diff --git a/src/loaders/schema.ts b/src/loaders/schema.ts deleted file mode 100644 index 8f90b604..00000000 --- a/src/loaders/schema.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { create, IPFSHTTPClient } from 'ipfs-http-client'; - -/** - * Loader interface to load schema - * - * @export - * @beta - * @interface ISchemaLoader - */ -export interface ISchemaLoader { - /** - * loads schema by its url - * - * @param {string} url - * @returns `Promise` - */ - load(url: string): Promise; -} - -/** - * loads schemas from ipfs and http sources - * - * @export - * @beta - * @class UniversalSchemaLoader - * @implements implements ISchemaLoader interface - */ -export class UniversalSchemaLoader implements ISchemaLoader { - constructor(private ipfsUrl: string) {} - - /** - * loads schema by URL - * - * @param {string} url - schema URL - * @returns `Promise` - */ - public async load(url: string): Promise { - const l = getLoader(url, this.ipfsUrl); - const schemaRes = await l.load(url); - return schemaRes; - } -} - -/** - * loads schemas from http source - * - * @export - * @beta - * @class HttpSchemaLoader - * @implements implements ISchemaLoader interface - */ -export class HttpSchemaLoader implements ISchemaLoader { - /** - * - * - * @param {string} url - schema URL - * @returns `Promise` - */ - public async load(url: string): Promise { - const resp = await fetch(url); - return new Uint8Array(await resp.arrayBuffer()); - } -} -/** - * loads schemas from ipfs source - * - * @export - * @beta - * @class IpfsSchemaLoader - * @implements implements ISchemaLoader interface - */ -export class IpfsSchemaLoader implements ISchemaLoader { - private readonly client: IPFSHTTPClient; - /** - * Creates an instance of IpfsSchemaLoader. - * @param {string} url - host of the ipfs node - */ - constructor(private readonly url: string) { - this.client = create({ url: this.url }); - } - /** - * loads schema from ipfs by its identifier - * - * @param {string} url - schema IPFS identifier - * @returns `Promise` - */ - public async load(url: string): Promise { - const uri = new URL(url); - - const schemaRes = this.client.cat(uri.host); - - let schemaBytes: Uint8Array = Uint8Array.from([]); - for await (const num of schemaRes) { - schemaBytes = Uint8Array.from(num); - } - - return schemaBytes; - } -} - -/** - * returns loader for schemas based on the URL protocol - * - * @export - * @param {string} url - schema url - * @param {string} [ipfsConfigUrl] - ipfs node host url - * @returns ISchemaLoader - */ -export function getLoader(url: string, ipfsConfigUrl?: string): ISchemaLoader { - const uri = new URL(url); - - switch (uri.protocol) { - case 'http:': - case 'https:': - return new HttpSchemaLoader(); - case 'ipfs:': - return new IpfsSchemaLoader(ipfsConfigUrl); - - default: - throw new Error(`loader for ${uri.protocol} is not supported`); - } -} diff --git a/src/proof/proof-service.ts b/src/proof/proof-service.ts index 8afa1469..df8eddd9 100644 --- a/src/proof/proof-service.ts +++ b/src/proof/proof-service.ts @@ -39,14 +39,17 @@ import { import { toClaimNonRevStatus, toGISTProof } from './common'; import { NativeProver } from './prover'; -import { Path } from '@iden3/js-jsonld-merklization'; +import { + Options as MerklizerOptions, + Path, + getDocumentLoader +} from '@iden3/js-jsonld-merklization'; import { ZKProof } from '@iden3/js-jwz'; import { Signer } from 'ethers'; import { ZeroKnowledgeProofRequest, ZeroKnowledgeProofResponse } from '../iden3comm'; -import { UniversalSchemaLoader } from '../loaders'; import { Parser } from '../schema-processor'; import { ICircuitStorage, IStateStorage } from '../storage'; -import { byteDecoder } from '../utils'; +import { byteEncoder } from '../utils/encoding'; interface PreparedAuthBJJCredential { authCredential: W3CCredential; @@ -165,7 +168,7 @@ export class ProofService implements IProofService { constructor( private readonly _identityWallet: IIdentityWallet, private readonly _credentialWallet: ICredentialWallet, - private readonly _circuitStorage: ICircuitStorage, + _circuitStorage: ICircuitStorage, private readonly _stateStorage: IStateStorage ) { this._prover = new NativeProver(_circuitStorage); @@ -313,7 +316,7 @@ export class ProofService implements IProofService { opts: ProofGenerationOptions ): Promise<{ inputs: Uint8Array; vp?: object }> { let generateInputFn; - switch(proofReq.circuitId) { + switch (proofReq.circuitId) { case CircuitId.AtomicQueryMTPV2: generateInputFn = this.generateMTPV2Inputs.bind(this); break; @@ -329,9 +332,8 @@ export class ProofService implements IProofService { default: throw new Error(`circuit with id ${proofReq.circuitId} is not supported by issuer`); } - + return generateInputFn(preparedCredential, identifier, proofReq, opts); - } private async generateMTPV2Inputs( @@ -339,7 +341,7 @@ export class ProofService implements IProofService { identifier: DID, proofReq: ZeroKnowledgeProofRequest, opts: ProofGenerationOptions - ): Promise<{ inputs: Uint8Array; vp?: object }>{ + ): Promise<{ inputs: Uint8Array; vp?: object }> { const circuitClaimData = await this.newCircuitClaimData( preparedCredential.credential, preparedCredential.credentialCoreClaim @@ -603,38 +605,47 @@ export class ProofService implements IProofService { return circuitClaim; } + private async toCircuitsQuery( query: ProofQuery, credential: W3CCredential, - coreClaim: Claim + coreClaim: Claim, + opts?: MerklizerOptions ): Promise<{ query: Query; vp?: object }> { const mtPosition = coreClaim.getMerklizedPosition(); return mtPosition === MerklizedRootPosition.None - ? this.prepareNonMerklizedQuery(query, credential) - : this.prepareMerklizedQuery(query, credential, mtPosition); + ? this.prepareNonMerklizedQuery(query, credential, opts) + : this.prepareMerklizedQuery(query, credential, mtPosition, opts); } + private async prepareMerklizedQuery( query: ProofQuery, credential: W3CCredential, - merklizedPosition: MerklizedRootPosition + merklizedPosition: MerklizedRootPosition, + opts?: MerklizerOptions ): Promise<{ query: Query; vp?: object }> { const parsedQuery = await this.parseRequest(query.credentialSubject); - const loader = new UniversalSchemaLoader('ipfs.io'); - const schema = await loader.load(credential['@context'][2]); + const loader = opts?.documentLoader ?? getDocumentLoader(); + let schema: object; + try { + schema = (await loader(credential['@context'][2])).document; + } catch (e) { + throw new Error(`can't load credential schema ${credential['@context'][2]}`); + } let path: Path = new Path(); if (parsedQuery.query.operator !== QueryOperators.$noop) { path = await Path.getContextPathKey( - byteDecoder.decode(schema), + JSON.stringify(schema), credential.type[1], parsedQuery.fieldName ); } path.prepend(['https://www.w3.org/2018/credentials#credentialSubject']); - const mk = await credential.merklize(); + const mk = await credential.merklize(opts); const { proof, value: mtValue } = await mk.proof(path); const pathKey = await path.mtEntry(); @@ -669,17 +680,31 @@ export class ProofService implements IProofService { private async prepareNonMerklizedQuery( query: ProofQuery, - credential: W3CCredential + credential: W3CCredential, + opts?: MerklizerOptions ): Promise<{ query: Query; vp?: object }> { - const loader = new UniversalSchemaLoader('ipfs.io'); - const schema = await loader.load(credential.credentialSchema.id); + const loader = + opts?.documentLoader ?? + getDocumentLoader({ + ipfsNodeURL: 'ipfs.io' + }); + + let schema: object; + try { + schema = (await loader(credential.credentialSchema.id)).document; + } catch (e) { + throw new Error(`can't load credential schema ${credential['@context'][2]}`); + } if (query.credentialSubject && Object.keys(query.credentialSubject).length > 1) { throw new Error('multiple requests are not supported'); } const parsedQuery = await this.parseRequest(query.credentialSubject); - parsedQuery.query.slotIndex = new Parser().getFieldSlotIndex(parsedQuery.fieldName, schema); + parsedQuery.query.slotIndex = new Parser().getFieldSlotIndex( + parsedQuery.fieldName, + byteEncoder.encode(JSON.stringify(schema)) + ); if (parsedQuery.isSelectiveDisclosure) { const { vp, mzValue } = await verifiablePresentationFromCred( diff --git a/src/schema-processor/json/parser.ts b/src/schema-processor/json/parser.ts index cf2706c9..ad9886a8 100644 --- a/src/schema-processor/json/parser.ts +++ b/src/schema-processor/json/parser.ts @@ -3,6 +3,7 @@ import { LDParser } from '../jsonld'; import { Claim as CoreClaim, ClaimOptions, DID } from '@iden3/js-iden3-core'; import { createSchemaHash, fillSlot } from '../utils'; import { byteDecoder, byteEncoder } from '../../utils'; +import { Options as MerklizerOptions } from '@iden3/js-jsonld-merklization'; /** * Parsed slots of core.Claim @@ -93,7 +94,7 @@ export class Parser { credential: W3CCredential, credentialType: string, jsonSchemaBytes: Uint8Array, - opts?: CoreClaimOptions + opts?: MerklizerOptions & CoreClaimOptions ): Promise { if (!opts) { opts = { @@ -142,12 +143,12 @@ export class Parser { switch (opts.merklizedRootPosition) { case MerklizedRootPosition.Index: { - const mk = await credential.merklize(); + const mk = await credential.merklize(opts); claim.setIndexMerklizedRoot((await mk.root()).bigInt()); break; } case MerklizedRootPosition.Value: { - const mk = await credential.merklize(); + const mk = await credential.merklize(opts); claim.setValueMerklizedRoot((await mk.root()).bigInt()); break; } diff --git a/src/verifiable/credential.ts b/src/verifiable/credential.ts index 17801779..6271ad9e 100644 --- a/src/verifiable/credential.ts +++ b/src/verifiable/credential.ts @@ -2,7 +2,7 @@ import { BJJSignatureProof2021, Iden3SparseMerkleTreeProof, CredentialStatus } f import { Claim } from '@iden3/js-iden3-core'; import { ProofType } from './constants'; import { Proof } from '@iden3/js-merkletree'; -import { Merklizer } from '@iden3/js-jsonld-merklization'; +import { Merklizer, Options } from '@iden3/js-jsonld-merklization'; /** * W3C Verifiable credential @@ -29,10 +29,10 @@ export class W3CCredential { * * @returns `Promise` */ - async merklize(): Promise { + async merklize(opts?: Options): Promise { const credential = { ...this }; delete credential.proof; - return await Merklizer.merklizeJSONLD(JSON.stringify(credential)); + return await Merklizer.merklizeJSONLD(JSON.stringify(credential), opts); } /** diff --git a/tests/circuits/atomic-query-mtp-v2-on-chain.test.ts b/tests/circuits/atomic-query-mtp-v2-on-chain.test.ts index 4d2a281a..77f4b838 100644 --- a/tests/circuits/atomic-query-mtp-v2-on-chain.test.ts +++ b/tests/circuits/atomic-query-mtp-v2-on-chain.test.ts @@ -28,14 +28,14 @@ describe('atomic-query-mtp-v2-on-chain', () => { const user = await IdentityTest.newIdentity(userPK); const issuer = await IdentityTest.newIdentity(issuerPK); - // generate global tree - const gTree = globalTree(); - await gTree.add(issuer.id.bigInt(), (await issuer.state()).bigInt()); + // generate global tree + const gTree = globalTree(); + await gTree.add(issuer.id.bigInt(), (await issuer.state()).bigInt()); - // prepare inputs - const globalProof = await gTree.generateProof(user.id.bigInt()); - const authClaimIncMTP = await user.claimMTPRaw(user.authClaim); - const authClaimNonRevMTP = await user.claimRevMTPRaw(user.authClaim); + // prepare inputs + const globalProof = await gTree.generateProof(user.id.bigInt()); + const authClaimIncMTP = await user.claimMTPRaw(user.authClaim); + const authClaimNonRevMTP = await user.claimRevMTPRaw(user.authClaim); const challenge = BigInt(10); const signature = user.signBJJ(challenge); @@ -92,14 +92,14 @@ describe('atomic-query-mtp-v2-on-chain', () => { inputs.authClaimIncMtp = authClaimIncMTP.proof; inputs.authClaimNonRevMtp = authClaimNonRevMTP.proof; inputs.treeState = { - state: await user.state(), - claimsRoot: await user.clt.root(), - revocationRoot: await user.ret.root(), - rootOfRoots: await user.rot.root() + state: await user.state(), + claimsRoot: await user.clt.root(), + revocationRoot: await user.ret.root(), + rootOfRoots: await user.rot.root() }; inputs.gistProof = { - root: await gTree.root(), - proof: globalProof.proof + root: await gTree.root(), + proof: globalProof.proof }; inputs.signature = signature; inputs.challenge = challenge; @@ -136,12 +136,14 @@ describe('atomic-query-mtp-v2-on-chain', () => { const schema = coreSchemaFromStr('180410020913331409885634153623124536270'); const slotIndex = 2; const operator = 1; - const quaryHash = poseidon.hash([schema.bigInt(), - BigInt(slotIndex), - BigInt(operator), - BigInt(0), - BigInt(1), - valueHash]); + const quaryHash = poseidon.hash([ + schema.bigInt(), + BigInt(slotIndex), + BigInt(operator), + BigInt(0), + BigInt(1), + valueHash + ]); const exp = new AtomicQueryMTPV2OnChainPubSignals(); exp.requestID = BigInt(23); @@ -161,8 +163,10 @@ describe('atomic-query-mtp-v2-on-chain', () => { exp.timestamp = timestamp; exp.merklized = 0; exp.isRevocationChecked = 1; - exp.challenge = BigInt(10), - exp.gistRoot = newHashFromString("11098939821764568131087645431296528907277253709936443029379587475821759259406"); + (exp.challenge = BigInt(10)), + (exp.gistRoot = newHashFromString( + '11098939821764568131087645431296528907277253709936443029379587475821759259406' + )); expect(exp).to.deep.equal(out); }); }); diff --git a/tests/circuits/atomic-query-sig-v2-on-chain.test.ts b/tests/circuits/atomic-query-sig-v2-on-chain.test.ts index a6229270..c14676fb 100644 --- a/tests/circuits/atomic-query-sig-v2-on-chain.test.ts +++ b/tests/circuits/atomic-query-sig-v2-on-chain.test.ts @@ -15,7 +15,7 @@ import { timestamp, prepareIntArray, globalTree, - coreSchemaFromStr, + coreSchemaFromStr } from './utils'; import expectedJson from './data/sig-v2-on-chain-inputs.json'; @@ -106,14 +106,14 @@ describe('atomic-query-sig-v2-on-chain', () => { inputs.authClaimIncMtp = authClaimIncMTP.proof; inputs.authClaimNonRevMtp = authClaimNonRevMTP.proof; inputs.treeState = { - state: await user.state(), - claimsRoot: await user.clt.root(), - revocationRoot: await user.ret.root(), - rootOfRoots: await user.rot.root() + state: await user.state(), + claimsRoot: await user.clt.root(), + revocationRoot: await user.ret.root(), + rootOfRoots: await user.rot.root() }; inputs.gistProof = { - root: await gTree.root(), - proof: globalProof.proof + root: await gTree.root(), + proof: globalProof.proof }; inputs.signature = signature; inputs.challenge = challenge; @@ -150,12 +150,14 @@ describe('atomic-query-sig-v2-on-chain', () => { const schema = coreSchemaFromStr('180410020913331409885634153623124536270'); const slotIndex = 2; const operator = 1; - const quaryHash = poseidon.hash([schema.bigInt(), - BigInt(slotIndex), - BigInt(operator), - BigInt(0), - BigInt(1), - valueHash]); + const quaryHash = poseidon.hash([ + schema.bigInt(), + BigInt(slotIndex), + BigInt(operator), + BigInt(0), + BigInt(1), + valueHash + ]); const exp = new AtomicQuerySigV2OnChainPubSignals(); exp.requestID = BigInt(23); @@ -175,8 +177,10 @@ describe('atomic-query-sig-v2-on-chain', () => { exp.timestamp = timestamp; exp.merklized = 0; exp.isRevocationChecked = 1; - exp.challenge = BigInt(10), - exp.gistRoot = newHashFromString("11098939821764568131087645431296528907277253709936443029379587475821759259406"); + (exp.challenge = BigInt(10)), + (exp.gistRoot = newHashFromString( + '11098939821764568131087645431296528907277253709936443029379587475821759259406' + )); expect(exp).to.deep.equal(out); }); }); diff --git a/tests/circuits/utils.ts b/tests/circuits/utils.ts index 53731338..786fbd1d 100644 --- a/tests/circuits/utils.ts +++ b/tests/circuits/utils.ts @@ -361,4 +361,4 @@ export const globalTree = () => new Merkletree(new InMemoryDB(str2Bytes('')), tr export const coreSchemaFromStr = (schemaIntString: string) => { const schemaInt = BigInt(schemaIntString); return SchemaHash.newSchemaHashFromInt(schemaInt); -} +}; diff --git a/tests/proofs/mtp-onchain.test.ts b/tests/proofs/mtp-onchain.test.ts index 2b5ca960..78daeef9 100644 --- a/tests/proofs/mtp-onchain.test.ts +++ b/tests/proofs/mtp-onchain.test.ts @@ -1,119 +1,126 @@ import { - CircuitStorage, - CredentialStorage, - Identity, - IdentityStorage, - IdentityWallet, - Profile, - byteEncoder - } from '../../src'; - import { BjjProvider, KMS, KmsKeyType } from '../../src/kms'; - import { InMemoryPrivateKeyStore } from '../../src/kms/store'; - import { IDataStorage, IStateStorage } from '../../src/storage/interfaces'; - import { InMemoryDataSource, InMemoryMerkleTreeStorage } from '../../src/storage/memory'; - import { CredentialRequest, CredentialStatusResolverRegistry, CredentialWallet, RHSResolver } from '../../src/credentials'; - import { ProofService } from '../../src/proof'; - import { CircuitId } from '../../src/circuits'; - import { FSKeyLoader } from '../../src/loaders'; - import { ethers } from 'ethers'; - import { EthStateStorage } from '../../src/storage/blockchain/state'; - import { RootInfo, StateProof } from '../../src/storage/entities/state'; - import path from 'path'; - import { CredentialStatusType, W3CCredential } from '../../src/verifiable'; - import { ZeroKnowledgeProofRequest } from '../../src/iden3comm'; - import { CircuitData } from '../../src/storage/entities/circuitData'; - import { Blockchain, DidMethod, NetworkId } from '@iden3/js-iden3-core'; - import { expect } from 'chai'; - import { checkVerifiablePresentation } from './common'; - - describe('mtp onchain proofs', () => { - let idWallet: IdentityWallet; - let credWallet: CredentialWallet; - - let dataStorage: IDataStorage; - let proofService: ProofService; - - const rhsUrl = process.env.RHS_URL as string; - const walletKey = process.env.WALLET_KEY as string; - - const mockStateStorage: IStateStorage = { - getLatestStateById: async () => { - return { - id: 25191641634853875207018381290409317860151551336133597267061715643603096065n, - state: 15316103435703269893947162180693935798669021972402205481551466808302934202991n, - replacedByState: 0n, - createdAtTimestamp: 1672245326n, - replacedAtTimestamp: 0n, - createdAtBlock: 30258020n, - replacedAtBlock: 0n - }; - }, - publishState: async () => { - return '0xc837f95c984892dbcc3ac41812ecb145fedc26d7003202c50e1b87e226a9b33c'; - }, - getGISTProof: (): Promise => { - return Promise.resolve({ - root: 0n, - existence: false, - siblings: [], - index: 0n, - value: 0n, - auxExistence: false, - auxIndex: 0n, - auxValue: 0n - }); - }, - getGISTRootInfo: (): Promise => { - return Promise.resolve({ - root: 0n, - replacedByRoot: 0n, - createdAtTimestamp: 0n, - replacedAtTimestamp: 0n, - createdAtBlock: 0n, - replacedAtBlock: 0n - }); - } - }; - beforeEach(async () => { - const memoryKeyStore = new InMemoryPrivateKeyStore(); - const bjjProvider = new BjjProvider(KmsKeyType.BabyJubJub, memoryKeyStore); - const kms = new KMS(); - kms.registerKeyProvider(KmsKeyType.BabyJubJub, bjjProvider); - - dataStorage = { - credential: new CredentialStorage(new InMemoryDataSource()), - identity: new IdentityStorage( - new InMemoryDataSource(), - new InMemoryDataSource() - ), - mt: new InMemoryMerkleTreeStorage(40), - states: mockStateStorage + CircuitStorage, + CredentialStorage, + Identity, + IdentityStorage, + IdentityWallet, + Profile, + byteEncoder +} from '../../src'; +import { BjjProvider, KMS, KmsKeyType } from '../../src/kms'; +import { InMemoryPrivateKeyStore } from '../../src/kms/store'; +import { IDataStorage, IStateStorage } from '../../src/storage/interfaces'; +import { InMemoryDataSource, InMemoryMerkleTreeStorage } from '../../src/storage/memory'; +import { + CredentialRequest, + CredentialStatusResolverRegistry, + CredentialWallet, + RHSResolver +} from '../../src/credentials'; +import { ProofService } from '../../src/proof'; +import { CircuitId } from '../../src/circuits'; +import { FSKeyLoader } from '../../src/loaders'; +import { ethers } from 'ethers'; +import { EthStateStorage } from '../../src/storage/blockchain/state'; +import { RootInfo, StateProof } from '../../src/storage/entities/state'; +import path from 'path'; +import { CredentialStatusType, W3CCredential } from '../../src/verifiable'; +import { ZeroKnowledgeProofRequest } from '../../src/iden3comm'; +import { CircuitData } from '../../src/storage/entities/circuitData'; +import { Blockchain, DidMethod, NetworkId } from '@iden3/js-iden3-core'; +import { expect } from 'chai'; +import { checkVerifiablePresentation } from './common'; + +describe('mtp onchain proofs', () => { + let idWallet: IdentityWallet; + let credWallet: CredentialWallet; + + let dataStorage: IDataStorage; + let proofService: ProofService; + + const rhsUrl = process.env.RHS_URL as string; + const walletKey = process.env.WALLET_KEY as string; + + const mockStateStorage: IStateStorage = { + getLatestStateById: async () => { + return { + id: 25191641634853875207018381290409317860151551336133597267061715643603096065n, + state: 15316103435703269893947162180693935798669021972402205481551466808302934202991n, + replacedByState: 0n, + createdAtTimestamp: 1672245326n, + replacedAtTimestamp: 0n, + createdAtBlock: 30258020n, + replacedAtBlock: 0n }; - - const circuitStorage = new CircuitStorage(new InMemoryDataSource()); - - // todo: change this loader - const loader = new FSKeyLoader(path.join(__dirname, './testdata')); - - await circuitStorage.saveCircuitData(CircuitId.AtomicQueryMTPV2OnChain, { - circuitId: CircuitId.AtomicQueryMTPV2OnChain, - wasm: await loader.load(`${CircuitId.AtomicQueryMTPV2OnChain.toString()}/circuit.wasm`), - provingKey: await loader.load(`${CircuitId.AtomicQueryMTPV2OnChain.toString()}/circuit_final.zkey`), - verificationKey: await loader.load( - `${CircuitId.AtomicQueryMTPV2OnChain.toString()}/verification_key.json` - ) + }, + publishState: async () => { + return '0xc837f95c984892dbcc3ac41812ecb145fedc26d7003202c50e1b87e226a9b33c'; + }, + getGISTProof: (): Promise => { + return Promise.resolve({ + root: 0n, + existence: false, + siblings: [], + index: 0n, + value: 0n, + auxExistence: false, + auxIndex: 0n, + auxValue: 0n }); - - await circuitStorage.saveCircuitData(CircuitId.StateTransition, { - circuitId: CircuitId.StateTransition, - wasm: await loader.load(`${CircuitId.StateTransition.toString()}/circuit.wasm`), - provingKey: await loader.load(`${CircuitId.StateTransition.toString()}/circuit_final.zkey`), - verificationKey: await loader.load( - `${CircuitId.AtomicQueryMTPV2OnChain.toString()}/verification_key.json` - ) + }, + getGISTRootInfo: (): Promise => { + return Promise.resolve({ + root: 0n, + replacedByRoot: 0n, + createdAtTimestamp: 0n, + replacedAtTimestamp: 0n, + createdAtBlock: 0n, + replacedAtBlock: 0n }); - - /* + } + }; + beforeEach(async () => { + const memoryKeyStore = new InMemoryPrivateKeyStore(); + const bjjProvider = new BjjProvider(KmsKeyType.BabyJubJub, memoryKeyStore); + const kms = new KMS(); + kms.registerKeyProvider(KmsKeyType.BabyJubJub, bjjProvider); + + dataStorage = { + credential: new CredentialStorage(new InMemoryDataSource()), + identity: new IdentityStorage( + new InMemoryDataSource(), + new InMemoryDataSource() + ), + mt: new InMemoryMerkleTreeStorage(40), + states: mockStateStorage + }; + + const circuitStorage = new CircuitStorage(new InMemoryDataSource()); + + // todo: change this loader + const loader = new FSKeyLoader(path.join(__dirname, './testdata')); + + await circuitStorage.saveCircuitData(CircuitId.AtomicQueryMTPV2OnChain, { + circuitId: CircuitId.AtomicQueryMTPV2OnChain, + wasm: await loader.load(`${CircuitId.AtomicQueryMTPV2OnChain.toString()}/circuit.wasm`), + provingKey: await loader.load( + `${CircuitId.AtomicQueryMTPV2OnChain.toString()}/circuit_final.zkey` + ), + verificationKey: await loader.load( + `${CircuitId.AtomicQueryMTPV2OnChain.toString()}/verification_key.json` + ) + }); + + await circuitStorage.saveCircuitData(CircuitId.StateTransition, { + circuitId: CircuitId.StateTransition, + wasm: await loader.load(`${CircuitId.StateTransition.toString()}/circuit.wasm`), + provingKey: await loader.load(`${CircuitId.StateTransition.toString()}/circuit_final.zkey`), + verificationKey: await loader.load( + `${CircuitId.AtomicQueryMTPV2OnChain.toString()}/verification_key.json` + ) + }); + + /* To use ethereum storage const conf = defaultEthConnectionConfig; @@ -123,127 +130,126 @@ import { dataStorage.states = ethStorage; */ - const resolvers = new CredentialStatusResolverRegistry(); - resolvers.register( - CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, - new RHSResolver(dataStorage.states) - ); - credWallet = new CredentialWallet(dataStorage,resolvers); - idWallet = new IdentityWallet(kms, dataStorage, credWallet); - - proofService = new ProofService(idWallet, credWallet, circuitStorage, mockStateStorage); + const resolvers = new CredentialStatusResolverRegistry(); + resolvers.register( + CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, + new RHSResolver(dataStorage.states) + ); + credWallet = new CredentialWallet(dataStorage, resolvers); + idWallet = new IdentityWallet(kms, dataStorage, credWallet); + + proofService = new ProofService(idWallet, credWallet, circuitStorage, mockStateStorage); + }); + + it('mtpv2onchain-merklized', async () => { + const seedPhraseIssuer: Uint8Array = byteEncoder.encode('seedseedseedseedseedseedseedsnew'); + const seedPhrase: Uint8Array = byteEncoder.encode('seedseedseedseedseedseedseeduser'); + + const { did: userDID, credential } = await idWallet.createIdentity({ + method: DidMethod.Iden3, + blockchain: Blockchain.Polygon, + networkId: NetworkId.Mumbai, + seed: seedPhrase, + revocationOpts: { + type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, + id: rhsUrl + } }); - - it('mtpv2onchain-merklized', async () => { - const seedPhraseIssuer: Uint8Array = byteEncoder.encode('seedseedseedseedseedseedseedsnew'); - const seedPhrase: Uint8Array = byteEncoder.encode('seedseedseedseedseedseedseeduser'); - - const { did: userDID, credential } = await idWallet.createIdentity({ - method: DidMethod.Iden3, - blockchain: Blockchain.Polygon, - networkId: NetworkId.Mumbai, - seed: seedPhrase, - revocationOpts: { - type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, - id: rhsUrl - } - }); - - const { did: issuerDID, credential: issuerAuthCredential } = await idWallet.createIdentity({ - method: DidMethod.Iden3, - blockchain: Blockchain.Polygon, - networkId: NetworkId.Mumbai, - seed: seedPhraseIssuer, - revocationOpts: { - type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, - id: rhsUrl - } - }); - await credWallet.save(issuerAuthCredential); - - const claimReq: CredentialRequest = { - credentialSchema: - 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/KYCAgeCredential-v3.json', - type: 'KYCAgeCredential', + + const { did: issuerDID, credential: issuerAuthCredential } = await idWallet.createIdentity({ + method: DidMethod.Iden3, + blockchain: Blockchain.Polygon, + networkId: NetworkId.Mumbai, + seed: seedPhraseIssuer, + revocationOpts: { + type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, + id: rhsUrl + } + }); + await credWallet.save(issuerAuthCredential); + + const claimReq: CredentialRequest = { + credentialSchema: + 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/KYCAgeCredential-v3.json', + type: 'KYCAgeCredential', + credentialSubject: { + id: userDID.toString(), + birthday: 19960424, + documentType: 99 + }, + expiration: 1693526400, + revocationOpts: { + type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, + nonce: 1000, + id: rhsUrl + } + }; + + const issuerCred = await idWallet.issueCredential(issuerDID, claimReq); + + await credWallet.save(issuerCred); + + const res = await idWallet.addCredentialsToMerkleTree([issuerCred], issuerDID); + + // publish to rhs + + await idWallet.publishStateToRHS(issuerDID, rhsUrl); + + // you must store stat info (e.g. state and it's roots) + + const ethSigner = new ethers.Wallet( + walletKey, + (dataStorage.states as EthStateStorage).provider + ); + + const txId = await proofService.transitState( + issuerDID, + res.oldTreeState, + true, + dataStorage.states, + ethSigner + ); + + const credsWithIden3MTPProof = await idWallet.generateIden3SparseMerkleTreeProof( + issuerDID, + res.credentials, + txId + ); + + await credWallet.saveAll(credsWithIden3MTPProof); + + const proofReq: ZeroKnowledgeProofRequest = { + id: 1, + circuitId: CircuitId.AtomicQueryMTPV2OnChain, + optional: false, + query: { + allowedIssuers: ['*'], + type: claimReq.type, + context: + 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld', credentialSubject: { - id: userDID.toString(), - birthday: 19960424, - documentType: 99 - }, - expiration: 1693526400, - revocationOpts: { - type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, - nonce: 1000, - id: rhsUrl - } - }; - - const issuerCred = await idWallet.issueCredential(issuerDID, claimReq); - - await credWallet.save(issuerCred); - - const res = await idWallet.addCredentialsToMerkleTree([issuerCred], issuerDID); - - // publish to rhs - - await idWallet.publishStateToRHS(issuerDID, rhsUrl); - - // you must store stat info (e.g. state and it's roots) - - const ethSigner = new ethers.Wallet( - walletKey, - (dataStorage.states as EthStateStorage).provider - ); - - const txId = await proofService.transitState( - issuerDID, - res.oldTreeState, - true, - dataStorage.states, - ethSigner - ); - - const credsWithIden3MTPProof = await idWallet.generateIden3SparseMerkleTreeProof( - issuerDID, - res.credentials, - txId - ); - - await credWallet.saveAll(credsWithIden3MTPProof); - - const proofReq: ZeroKnowledgeProofRequest = { - id: 1, - circuitId: CircuitId.AtomicQueryMTPV2OnChain, - optional: false, - query: { - allowedIssuers: ['*'], - type: claimReq.type, - context: - 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld', - credentialSubject: { - documentType: { - $eq: 99 - } + documentType: { + $eq: 99 } } - }; - - const creds = await credWallet.findByQuery(proofReq.query); - expect(creds.length).to.not.equal(0); - - const credsForMyUserDID = await credWallet.filterByCredentialSubject(creds, userDID); - expect(creds.length).to.equal(1); - - const { proof, vp } = await proofService.generateProof(proofReq, userDID, credsForMyUserDID[0]); - console.log(proof); - expect(vp).to.be.undefined; - await checkVerifiablePresentation( - claimReq.type, - userDID, - credsForMyUserDID[0], - proofService, - CircuitId.AtomicQueryMTPV2OnChain - ); - }); + } + }; + + const creds = await credWallet.findByQuery(proofReq.query); + expect(creds.length).to.not.equal(0); + + const credsForMyUserDID = await credWallet.filterByCredentialSubject(creds, userDID); + expect(creds.length).to.equal(1); + + const { proof, vp } = await proofService.generateProof(proofReq, userDID, credsForMyUserDID[0]); + console.log(proof); + expect(vp).to.be.undefined; + await checkVerifiablePresentation( + claimReq.type, + userDID, + credsForMyUserDID[0], + proofService, + CircuitId.AtomicQueryMTPV2OnChain + ); }); - \ No newline at end of file +}); diff --git a/tests/proofs/sig-onchain.test.ts b/tests/proofs/sig-onchain.test.ts index b822da98..f3e26304 100644 --- a/tests/proofs/sig-onchain.test.ts +++ b/tests/proofs/sig-onchain.test.ts @@ -1,202 +1,208 @@ import { - CircuitStorage, - CredentialStorage, - Identity, - IdentityStorage, - IdentityWallet, - Profile - } from '../../src'; - import { BjjProvider, KMS, KmsKeyType } from '../../src/kms'; - import { InMemoryPrivateKeyStore } from '../../src/kms/store'; - import { IDataStorage, IStateStorage } from '../../src/storage/interfaces'; - import { InMemoryDataSource, InMemoryMerkleTreeStorage } from '../../src/storage/memory'; - import { CredentialRequest, CredentialStatusResolverRegistry, CredentialWallet, RHSResolver } from '../../src/credentials'; - import { ProofService } from '../../src/proof'; - import { CircuitId } from '../../src/circuits'; - import { FSKeyLoader } from '../../src/loaders'; - import { CredentialStatusType, VerifiableConstants, W3CCredential } from '../../src/verifiable'; - import { RootInfo, StateProof } from '../../src/storage/entities/state'; - import path from 'path'; - import { byteEncoder } from '../../src'; - import { ZeroKnowledgeProofRequest } from '../../src/iden3comm'; - import { CircuitData } from '../../src/storage/entities/circuitData'; - import { Blockchain, DidMethod, NetworkId } from '@iden3/js-iden3-core'; - import { expect } from 'chai'; - import { checkVerifiablePresentation } from './common'; - - describe('sig onchain proofs', () => { - let idWallet: IdentityWallet; - let credWallet: CredentialWallet; - - let dataStorage: IDataStorage; - let proofService: ProofService; - const rhsUrl = process.env.RHS_URL as string; - - const mockStateStorage: IStateStorage = { - getLatestStateById: async () => { - throw new Error(VerifiableConstants.ERRORS.IDENTITY_DOES_NOT_EXIST); - }, - publishState: async () => { - return '0xc837f95c984892dbcc3ac41812ecb145fedc26d7003202c50e1b87e226a9b33c'; - }, - getGISTProof: (): Promise => { - return Promise.resolve({ - root: 0n, - existence: false, - siblings: [], - index: 0n, - value: 0n, - auxExistence: false, - auxIndex: 0n, - auxValue: 0n - }); - }, - getGISTRootInfo: (): Promise => { - return Promise.resolve({ - root: 0n, - replacedByRoot: 0n, - createdAtTimestamp: 0n, - replacedAtTimestamp: 0n, - createdAtBlock: 0n, - replacedAtBlock: 0n - }); - } - }; - - beforeEach(async () => { - const memoryKeyStore = new InMemoryPrivateKeyStore(); - const bjjProvider = new BjjProvider(KmsKeyType.BabyJubJub, memoryKeyStore); - const kms = new KMS(); - kms.registerKeyProvider(KmsKeyType.BabyJubJub, bjjProvider); - - dataStorage = { - credential: new CredentialStorage(new InMemoryDataSource()), - identity: new IdentityStorage( - new InMemoryDataSource(), - new InMemoryDataSource() - ), - mt: new InMemoryMerkleTreeStorage(40), - states: mockStateStorage - }; - - const circuitStorage = new CircuitStorage(new InMemoryDataSource()); - - const loader = new FSKeyLoader(path.join(__dirname, './testdata')); - - await circuitStorage.saveCircuitData(CircuitId.AuthV2, { - circuitId: CircuitId.AuthV2, - wasm: await loader.load(`${CircuitId.AuthV2.toString()}/circuit.wasm`), - provingKey: await loader.load(`${CircuitId.AuthV2.toString()}/circuit_final.zkey`), - verificationKey: await loader.load(`${CircuitId.AuthV2.toString()}/verification_key.json`) - }); - - await circuitStorage.saveCircuitData(CircuitId.AtomicQuerySigV2OnChain, { - circuitId: CircuitId.AtomicQuerySigV2OnChain, - wasm: await loader.load(`${CircuitId.AtomicQuerySigV2OnChain.toString()}/circuit.wasm`), - provingKey: await loader.load(`${CircuitId.AtomicQuerySigV2OnChain.toString()}/circuit_final.zkey`), - verificationKey: await loader.load( - `${CircuitId.AtomicQuerySigV2OnChain.toString()}/verification_key.json` - ) + CircuitStorage, + CredentialStorage, + Identity, + IdentityStorage, + IdentityWallet, + Profile +} from '../../src'; +import { BjjProvider, KMS, KmsKeyType } from '../../src/kms'; +import { InMemoryPrivateKeyStore } from '../../src/kms/store'; +import { IDataStorage, IStateStorage } from '../../src/storage/interfaces'; +import { InMemoryDataSource, InMemoryMerkleTreeStorage } from '../../src/storage/memory'; +import { + CredentialRequest, + CredentialStatusResolverRegistry, + CredentialWallet, + RHSResolver +} from '../../src/credentials'; +import { ProofService } from '../../src/proof'; +import { CircuitId } from '../../src/circuits'; +import { FSKeyLoader } from '../../src/loaders'; +import { CredentialStatusType, VerifiableConstants, W3CCredential } from '../../src/verifiable'; +import { RootInfo, StateProof } from '../../src/storage/entities/state'; +import path from 'path'; +import { byteEncoder } from '../../src'; +import { ZeroKnowledgeProofRequest } from '../../src/iden3comm'; +import { CircuitData } from '../../src/storage/entities/circuitData'; +import { Blockchain, DidMethod, NetworkId } from '@iden3/js-iden3-core'; +import { expect } from 'chai'; +import { checkVerifiablePresentation } from './common'; + +describe('sig onchain proofs', () => { + let idWallet: IdentityWallet; + let credWallet: CredentialWallet; + + let dataStorage: IDataStorage; + let proofService: ProofService; + const rhsUrl = process.env.RHS_URL as string; + + const mockStateStorage: IStateStorage = { + getLatestStateById: async () => { + throw new Error(VerifiableConstants.ERRORS.IDENTITY_DOES_NOT_EXIST); + }, + publishState: async () => { + return '0xc837f95c984892dbcc3ac41812ecb145fedc26d7003202c50e1b87e226a9b33c'; + }, + getGISTProof: (): Promise => { + return Promise.resolve({ + root: 0n, + existence: false, + siblings: [], + index: 0n, + value: 0n, + auxExistence: false, + auxIndex: 0n, + auxValue: 0n }); - - await circuitStorage.saveCircuitData(CircuitId.StateTransition, { - circuitId: CircuitId.StateTransition, - wasm: await loader.load(`${CircuitId.StateTransition.toString()}/circuit.wasm`), - provingKey: await loader.load(`${CircuitId.StateTransition.toString()}/circuit_final.zkey`), - verificationKey: await loader.load( - `${CircuitId.AtomicQueryMTPV2.toString()}/verification_key.json` - ) + }, + getGISTRootInfo: (): Promise => { + return Promise.resolve({ + root: 0n, + replacedByRoot: 0n, + createdAtTimestamp: 0n, + replacedAtTimestamp: 0n, + createdAtBlock: 0n, + replacedAtBlock: 0n }); - const resolvers = new CredentialStatusResolverRegistry(); - resolvers.register( - CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, - new RHSResolver(dataStorage.states) - ); - credWallet = new CredentialWallet(dataStorage,resolvers); - idWallet = new IdentityWallet(kms, dataStorage, credWallet); - - proofService = new ProofService(idWallet, credWallet, circuitStorage, mockStateStorage); + } + }; + + beforeEach(async () => { + const memoryKeyStore = new InMemoryPrivateKeyStore(); + const bjjProvider = new BjjProvider(KmsKeyType.BabyJubJub, memoryKeyStore); + const kms = new KMS(); + kms.registerKeyProvider(KmsKeyType.BabyJubJub, bjjProvider); + + dataStorage = { + credential: new CredentialStorage(new InMemoryDataSource()), + identity: new IdentityStorage( + new InMemoryDataSource(), + new InMemoryDataSource() + ), + mt: new InMemoryMerkleTreeStorage(40), + states: mockStateStorage + }; + + const circuitStorage = new CircuitStorage(new InMemoryDataSource()); + + const loader = new FSKeyLoader(path.join(__dirname, './testdata')); + + await circuitStorage.saveCircuitData(CircuitId.AuthV2, { + circuitId: CircuitId.AuthV2, + wasm: await loader.load(`${CircuitId.AuthV2.toString()}/circuit.wasm`), + provingKey: await loader.load(`${CircuitId.AuthV2.toString()}/circuit_final.zkey`), + verificationKey: await loader.load(`${CircuitId.AuthV2.toString()}/verification_key.json`) }); - - it('sigv2-onchain-merklized', async () => { - const seedPhraseIssuer: Uint8Array = byteEncoder.encode('seedseedseedseedseedseedseedseed'); - const seedPhrase: Uint8Array = byteEncoder.encode('seedseedseedseedseedseedseeduser'); - - const { did: userDID } = await idWallet.createIdentity({ - method: DidMethod.Iden3, - blockchain: Blockchain.Polygon, - networkId: NetworkId.Mumbai, - seed: seedPhrase, - revocationOpts: { - type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, - id: rhsUrl - } - }); - - const { did: issuerDID } = await idWallet.createIdentity({ - method: DidMethod.Iden3, - blockchain: Blockchain.Polygon, - networkId: NetworkId.Mumbai, - seed: seedPhraseIssuer, - revocationOpts: { - type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, - id: rhsUrl - } - }); - const claimReq: CredentialRequest = { - credentialSchema: - 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/KYCAgeCredential-v3.json', - type: 'KYCAgeCredential', + + await circuitStorage.saveCircuitData(CircuitId.AtomicQuerySigV2OnChain, { + circuitId: CircuitId.AtomicQuerySigV2OnChain, + wasm: await loader.load(`${CircuitId.AtomicQuerySigV2OnChain.toString()}/circuit.wasm`), + provingKey: await loader.load( + `${CircuitId.AtomicQuerySigV2OnChain.toString()}/circuit_final.zkey` + ), + verificationKey: await loader.load( + `${CircuitId.AtomicQuerySigV2OnChain.toString()}/verification_key.json` + ) + }); + + await circuitStorage.saveCircuitData(CircuitId.StateTransition, { + circuitId: CircuitId.StateTransition, + wasm: await loader.load(`${CircuitId.StateTransition.toString()}/circuit.wasm`), + provingKey: await loader.load(`${CircuitId.StateTransition.toString()}/circuit_final.zkey`), + verificationKey: await loader.load( + `${CircuitId.AtomicQueryMTPV2.toString()}/verification_key.json` + ) + }); + const resolvers = new CredentialStatusResolverRegistry(); + resolvers.register( + CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, + new RHSResolver(dataStorage.states) + ); + credWallet = new CredentialWallet(dataStorage, resolvers); + idWallet = new IdentityWallet(kms, dataStorage, credWallet); + + proofService = new ProofService(idWallet, credWallet, circuitStorage, mockStateStorage); + }); + + it('sigv2-onchain-merklized', async () => { + const seedPhraseIssuer: Uint8Array = byteEncoder.encode('seedseedseedseedseedseedseedseed'); + const seedPhrase: Uint8Array = byteEncoder.encode('seedseedseedseedseedseedseeduser'); + + const { did: userDID } = await idWallet.createIdentity({ + method: DidMethod.Iden3, + blockchain: Blockchain.Polygon, + networkId: NetworkId.Mumbai, + seed: seedPhrase, + revocationOpts: { + type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, + id: rhsUrl + } + }); + + const { did: issuerDID } = await idWallet.createIdentity({ + method: DidMethod.Iden3, + blockchain: Blockchain.Polygon, + networkId: NetworkId.Mumbai, + seed: seedPhraseIssuer, + revocationOpts: { + type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, + id: rhsUrl + } + }); + const claimReq: CredentialRequest = { + credentialSchema: + 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json/KYCAgeCredential-v3.json', + type: 'KYCAgeCredential', + credentialSubject: { + id: userDID.toString(), + birthday: 19960424, + documentType: 99 + }, + expiration: 1693526400, + revocationOpts: { + type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, + id: rhsUrl + } + }; + const issuerCred = await idWallet.issueCredential(issuerDID, claimReq); + + await credWallet.save(issuerCred); + + const proofReq: ZeroKnowledgeProofRequest = { + id: 1, + circuitId: CircuitId.AtomicQuerySigV2OnChain, + optional: false, + query: { + allowedIssuers: ['*'], + type: claimReq.type, + context: + 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld', credentialSubject: { - id: userDID.toString(), - birthday: 19960424, - documentType: 99 - }, - expiration: 1693526400, - revocationOpts: { - type: CredentialStatusType.Iden3ReverseSparseMerkleTreeProof, - id: rhsUrl - } - }; - const issuerCred = await idWallet.issueCredential(issuerDID, claimReq); - - await credWallet.save(issuerCred); - - const proofReq: ZeroKnowledgeProofRequest = { - id: 1, - circuitId: CircuitId.AtomicQuerySigV2OnChain, - optional: false, - query: { - allowedIssuers: ['*'], - type: claimReq.type, - context: - 'https://raw.githubusercontent.com/iden3/claim-schema-vocab/main/schemas/json-ld/kyc-v3.json-ld', - credentialSubject: { - documentType: { - $eq: 99 - } + documentType: { + $eq: 99 } } - }; - - const creds = await credWallet.findByQuery(proofReq.query); - expect(creds.length).to.not.equal(0); - - const credsForMyUserDID = await credWallet.filterByCredentialSubject(creds, userDID); - expect(creds.length).to.equal(1); - - const { proof, vp } = await proofService.generateProof(proofReq, userDID, credsForMyUserDID[0]); - console.log(proof); - - expect(vp).to.be.undefined; - - await checkVerifiablePresentation( - claimReq.type, - userDID, - credsForMyUserDID[0], - proofService, - CircuitId.AtomicQuerySigV2OnChain - ); - }); + } + }; + + const creds = await credWallet.findByQuery(proofReq.query); + expect(creds.length).to.not.equal(0); + + const credsForMyUserDID = await credWallet.filterByCredentialSubject(creds, userDID); + expect(creds.length).to.equal(1); + + const { proof, vp } = await proofService.generateProof(proofReq, userDID, credsForMyUserDID[0]); + console.log(proof); + + expect(vp).to.be.undefined; + + await checkVerifiablePresentation( + claimReq.type, + userDID, + credsForMyUserDID[0], + proofService, + CircuitId.AtomicQuerySigV2OnChain + ); }); - \ No newline at end of file +});