@iden3/js-iden3-auth
Version:
iden3-auth implementation in JavaScript
75 lines (74 loc) • 3.42 kB
JavaScript
import { Path } from '@iden3/js-jsonld-merklization';
import { LinkedMultiQueryPubSignals, byteEncoder, cacheLoader, parseQueriesMetadata, calculateQueryHashV3, calculateCoreSchemaHash, LinkedMultiQueryInputs, Operators, fieldValueFromVerifiablePresentation } from '@0xpolygonid/js-sdk';
/**
* Verifies the linked multi-query circuit.
* @beta
*/
export class LinkedMultiQueryVerifier {
constructor(pubSignals) {
this.pubSignals = new LinkedMultiQueryPubSignals();
this.bigIntCompare = (a, b) => {
if (a < b)
return -1;
if (a > b)
return 1;
return 0;
};
this.pubSignals = this.pubSignals.pubSignalsUnmarshal(byteEncoder.encode(JSON.stringify(pubSignals)));
}
verifyIdOwnership() {
return Promise.resolve();
}
async verifyQuery(query, schemaLoader, verifiablePresentation) {
let schema;
const ldOpts = { documentLoader: schemaLoader ?? cacheLoader() };
try {
schema = (await ldOpts.documentLoader(query.context)).document;
}
catch (e) {
throw new Error(`can't load schema for request query`);
}
const ldContextJSON = JSON.stringify(schema);
const credentialSubject = query.credentialSubject;
const schemaId = await Path.getTypeIDFromContext(ldContextJSON, query.type, ldOpts);
const schemaHash = calculateCoreSchemaHash(byteEncoder.encode(schemaId));
const queriesMetadata = await parseQueriesMetadata(query.type, ldContextJSON, credentialSubject, ldOpts);
const request = [];
const merklized = queriesMetadata[0]?.merklizedSchema ? 1 : 0;
for (let i = 0; i < LinkedMultiQueryInputs.queryCount; i++) {
const queryMeta = queriesMetadata[i];
const values = queryMeta?.values ?? [];
const valArrSize = values.length;
const queryHash = calculateQueryHashV3(values, schemaHash, queryMeta?.slotIndex ?? 0, queryMeta?.operator ?? 0, queryMeta?.claimPathKey.toString() ?? 0, valArrSize, merklized, 0, 0, 0);
request.push({ queryHash, queryMeta });
}
const queryHashCompare = (a, b) => {
if (a.queryHash < b.queryHash)
return -1;
if (a.queryHash > b.queryHash)
return 1;
return 0;
};
const pubSignalsMeta = this.pubSignals.circuitQueryHash.map((queryHash, index) => ({
queryHash,
operatorOutput: this.pubSignals.operatorOutput[index]
}));
pubSignalsMeta.sort(queryHashCompare);
request.sort(queryHashCompare);
for (let i = 0; i < LinkedMultiQueryInputs.queryCount; i++) {
if (request[i].queryHash != pubSignalsMeta[i].queryHash) {
throw new Error('query hashes do not match');
}
if (request[i].queryMeta?.operator === Operators.SD) {
const disclosedValue = await fieldValueFromVerifiablePresentation(request[i].queryMeta.fieldName, verifiablePresentation, schemaLoader);
if (disclosedValue != pubSignalsMeta[i].operatorOutput) {
throw new Error('disclosed value is not in the proof outputs');
}
}
}
return this.pubSignals;
}
async verifyStates() {
return Promise.resolve();
}
}