@0xpolygonid/js-sdk
Version:
SDK to work with Polygon ID
416 lines (415 loc) • 23.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InputGenerator = exports.circuitValidator = void 0;
const js_iden3_core_1 = require("@iden3/js-iden3-core");
const verifiable_1 = require("../../verifiable");
const circuits_1 = require("../../circuits");
const common_1 = require("../common");
const credentials_1 = require("../../credentials");
const utils_1 = require("../../utils");
const allOperations = Object.values(circuits_1.QueryOperators);
const v2Operations = [
circuits_1.Operators.NOOP,
circuits_1.Operators.EQ,
circuits_1.Operators.LT,
circuits_1.Operators.GT,
circuits_1.Operators.IN,
circuits_1.Operators.NIN,
circuits_1.Operators.NE,
circuits_1.Operators.SD
];
const v2OnChainOperations = [
circuits_1.Operators.EQ,
circuits_1.Operators.LT,
circuits_1.Operators.GT,
circuits_1.Operators.IN,
circuits_1.Operators.NIN,
circuits_1.Operators.NE
];
exports.circuitValidator = {
[circuits_1.CircuitId.AtomicQueryMTPV2]: { maxQueriesCount: 1, supportedOperations: v2Operations },
[circuits_1.CircuitId.AtomicQueryMTPV2OnChain]: {
maxQueriesCount: 1,
supportedOperations: v2OnChainOperations
},
[circuits_1.CircuitId.AtomicQuerySigV2]: { maxQueriesCount: 1, supportedOperations: v2Operations },
[circuits_1.CircuitId.AtomicQuerySigV2OnChain]: {
maxQueriesCount: 1,
supportedOperations: v2OnChainOperations
},
[circuits_1.CircuitId.AtomicQueryV3]: { maxQueriesCount: 1, supportedOperations: allOperations },
[circuits_1.CircuitId.AtomicQueryV3OnChain]: { maxQueriesCount: 1, supportedOperations: allOperations },
[circuits_1.CircuitId.AuthV2]: { maxQueriesCount: 0, supportedOperations: [] },
[circuits_1.CircuitId.StateTransition]: { maxQueriesCount: 0, supportedOperations: [] },
[circuits_1.CircuitId.LinkedMultiQuery10]: { maxQueriesCount: 10, supportedOperations: allOperations }
};
class InputGenerator {
constructor(_identityWallet, _credentialWallet, _stateStorage) {
this._identityWallet = _identityWallet;
this._credentialWallet = _credentialWallet;
this._stateStorage = _stateStorage;
this.credentialAtomicQueryMTPV2PrepareInputs = async ({ preparedCredential, identifier, proofReq, params, circuitQueries }) => {
const circuitClaimData = await this.newCircuitClaimData(preparedCredential);
circuitClaimData.nonRevProof = (0, common_1.toClaimNonRevStatus)(preparedCredential.revStatus);
const circuitInputs = new circuits_1.AtomicQueryMTPV2Inputs();
circuitInputs.id = js_iden3_core_1.DID.idFromDID(identifier);
circuitInputs.requestID = BigInt(proofReq.id);
const query = circuitQueries[0];
query.operator = this.transformV2QueryOperator(query.operator);
circuitInputs.query = query;
circuitInputs.claim = {
issuerID: circuitClaimData.issuerId,
claim: circuitClaimData.claim,
incProof: { proof: circuitClaimData.proof, treeState: circuitClaimData.treeState },
nonRevProof: circuitClaimData.nonRevProof
};
circuitInputs.currentTimeStamp = (0, js_iden3_core_1.getUnixTimestamp)(new Date());
circuitInputs.claimSubjectProfileNonce = BigInt(params.credentialSubjectProfileNonce);
circuitInputs.profileNonce = BigInt(params.authProfileNonce);
circuitInputs.skipClaimRevocationCheck = params.skipRevocation;
this.checkOperatorSupport(proofReq.circuitId, query.operator);
return circuitInputs.inputsMarshal();
};
this.credentialAtomicQueryMTPV2OnChainPrepareInputs = async ({ preparedCredential, identifier, proofReq, params, circuitQueries }) => {
const circuitClaimData = await this.newCircuitClaimData(preparedCredential);
const authInfo = await this.prepareAuthBJJCredential(identifier);
const authClaimData = await this.newCircuitClaimData({
credential: authInfo.credential,
credentialCoreClaim: authInfo.coreClaim
});
circuitClaimData.nonRevProof = (0, common_1.toClaimNonRevStatus)(preparedCredential.revStatus);
const circuitInputs = new circuits_1.AtomicQueryMTPV2OnChainInputs();
const id = js_iden3_core_1.DID.idFromDID(identifier);
circuitInputs.id = js_iden3_core_1.DID.idFromDID(identifier);
circuitInputs.requestID = BigInt(proofReq.id);
const stateProof = await this._stateStorage.getGISTProof(id.bigInt());
const gistProof = (0, common_1.toGISTProof)(stateProof);
circuitInputs.gistProof = gistProof;
if (authClaimData?.treeState) {
circuitInputs.treeState = {
state: authClaimData?.treeState?.state,
claimsRoot: authClaimData?.treeState?.claimsRoot,
revocationRoot: authClaimData?.treeState?.revocationRoot,
rootOfRoots: authClaimData?.treeState?.rootOfRoots
};
}
circuitInputs.authClaim = authClaimData.claim;
circuitInputs.authClaimIncMtp = authClaimData.proof;
circuitInputs.authClaimNonRevMtp = authInfo.nonRevProof.proof;
if (!params.challenge) {
throw new Error('challenge must be provided for onchain circuits');
}
const signature = await this._identityWallet.signChallenge(params.challenge, authInfo.credential);
circuitInputs.signature = signature;
circuitInputs.challenge = params.challenge;
const query = circuitQueries[0];
circuitInputs.query = query;
circuitInputs.claim = {
issuerID: circuitClaimData.issuerId,
claim: circuitClaimData.claim,
incProof: { proof: circuitClaimData.proof, treeState: circuitClaimData.treeState },
nonRevProof: circuitClaimData.nonRevProof
};
circuitInputs.currentTimeStamp = (0, js_iden3_core_1.getUnixTimestamp)(new Date());
circuitInputs.claimSubjectProfileNonce = BigInt(params.credentialSubjectProfileNonce);
circuitInputs.profileNonce = BigInt(params.authProfileNonce);
circuitInputs.skipClaimRevocationCheck = params.skipRevocation;
this.checkOperatorSupport(proofReq.circuitId, query.operator);
return circuitInputs.inputsMarshal();
};
this.credentialAtomicQuerySigV2PrepareInputs = async ({ preparedCredential, identifier, proofReq, params, circuitQueries }) => {
const circuitClaimData = await this.newCircuitClaimData(preparedCredential);
circuitClaimData.nonRevProof = (0, common_1.toClaimNonRevStatus)(preparedCredential.revStatus);
const circuitInputs = new circuits_1.AtomicQuerySigV2Inputs();
circuitInputs.id = js_iden3_core_1.DID.idFromDID(identifier);
circuitInputs.claim = {
issuerID: circuitClaimData?.issuerId,
signatureProof: circuitClaimData.signatureProof,
claim: circuitClaimData.claim,
nonRevProof: circuitClaimData.nonRevProof
};
circuitInputs.requestID = BigInt(proofReq.id);
circuitInputs.claimSubjectProfileNonce = BigInt(params.credentialSubjectProfileNonce);
circuitInputs.profileNonce = BigInt(params.authProfileNonce);
circuitInputs.skipClaimRevocationCheck = params.skipRevocation;
const query = circuitQueries[0];
query.operator = this.transformV2QueryOperator(query.operator);
circuitInputs.query = query;
circuitInputs.currentTimeStamp = (0, js_iden3_core_1.getUnixTimestamp)(new Date());
this.checkOperatorSupport(proofReq.circuitId, query.operator);
return circuitInputs.inputsMarshal();
};
this.credentialAtomicQuerySigV2OnChainPrepareInputs = async ({ preparedCredential, identifier, proofReq, params, circuitQueries }) => {
const circuitClaimData = await this.newCircuitClaimData(preparedCredential);
const authInfo = await this.prepareAuthBJJCredential(identifier);
const authClaimData = await this.newCircuitClaimData({
credential: authInfo.credential,
credentialCoreClaim: authInfo.coreClaim
});
circuitClaimData.nonRevProof = (0, common_1.toClaimNonRevStatus)(preparedCredential.revStatus);
const circuitInputs = new circuits_1.AtomicQuerySigV2OnChainInputs();
const id = js_iden3_core_1.DID.idFromDID(identifier);
circuitInputs.id = id;
circuitInputs.claim = {
issuerID: circuitClaimData.issuerId,
signatureProof: circuitClaimData.signatureProof,
claim: circuitClaimData.claim,
nonRevProof: circuitClaimData.nonRevProof
};
circuitInputs.requestID = BigInt(proofReq.id);
circuitInputs.claimSubjectProfileNonce = BigInt(params.credentialSubjectProfileNonce);
circuitInputs.profileNonce = BigInt(params.authProfileNonce);
circuitInputs.skipClaimRevocationCheck = params.skipRevocation;
const query = circuitQueries[0];
circuitInputs.query = query;
circuitInputs.currentTimeStamp = (0, js_iden3_core_1.getUnixTimestamp)(new Date());
if (authClaimData.treeState) {
circuitInputs.treeState = {
state: authClaimData.treeState?.state,
claimsRoot: authClaimData.treeState?.claimsRoot,
revocationRoot: authClaimData.treeState?.revocationRoot,
rootOfRoots: authClaimData.treeState?.rootOfRoots
};
}
const stateProof = await this._stateStorage.getGISTProof(id.bigInt());
const gistProof = (0, common_1.toGISTProof)(stateProof);
circuitInputs.gistProof = gistProof;
circuitInputs.authClaim = authClaimData.claim;
circuitInputs.authClaimIncMtp = authClaimData.proof;
circuitInputs.authClaimNonRevMtp = authInfo.nonRevProof.proof;
if (!params.challenge) {
throw new Error('challenge must be provided for onchain circuits');
}
const signature = await this._identityWallet.signChallenge(params.challenge, authInfo.credential);
circuitInputs.signature = signature;
circuitInputs.challenge = params.challenge;
this.checkOperatorSupport(proofReq.circuitId, query.operator);
return circuitInputs.inputsMarshal();
};
this.credentialAtomicQueryV3PrepareInputs = async ({ preparedCredential, identifier, proofReq, params, circuitQueries }) => {
const circuitClaimData = await this.newCircuitClaimData(preparedCredential);
circuitClaimData.nonRevProof = (0, common_1.toClaimNonRevStatus)(preparedCredential.revStatus);
let proofType;
switch (proofReq.query.proofType) {
case verifiable_1.ProofType.BJJSignature:
proofType = verifiable_1.ProofType.BJJSignature;
break;
case verifiable_1.ProofType.Iden3SparseMerkleTreeProof:
proofType = verifiable_1.ProofType.Iden3SparseMerkleTreeProof;
break;
default:
if (circuitClaimData.proof) {
proofType = verifiable_1.ProofType.Iden3SparseMerkleTreeProof;
}
else if (circuitClaimData.signatureProof) {
proofType = verifiable_1.ProofType.BJJSignature;
}
else {
throw Error('claim has no MTP or signature proof');
}
break;
}
const circuitInputs = new circuits_1.AtomicQueryV3Inputs();
circuitInputs.id = js_iden3_core_1.DID.idFromDID(identifier);
circuitInputs.claim = {
issuerID: circuitClaimData?.issuerId,
signatureProof: circuitClaimData.signatureProof,
claim: circuitClaimData.claim,
nonRevProof: circuitClaimData.nonRevProof,
incProof: { proof: circuitClaimData.proof, treeState: circuitClaimData.treeState }
};
circuitInputs.requestID = BigInt(proofReq.id);
circuitInputs.claimSubjectProfileNonce = BigInt(params.credentialSubjectProfileNonce);
circuitInputs.profileNonce = BigInt(params.authProfileNonce);
circuitInputs.skipClaimRevocationCheck = params.skipRevocation;
const query = circuitQueries[0];
query.values = [circuits_1.Operators.SD, circuits_1.Operators.NOOP].includes(query.operator) ? [] : query.values;
query.valueProof = query.operator === circuits_1.Operators.NOOP ? new circuits_1.ValueProof() : query.valueProof;
circuitInputs.query = query;
circuitInputs.currentTimeStamp = (0, js_iden3_core_1.getUnixTimestamp)(new Date());
circuitInputs.proofType = proofType;
circuitInputs.linkNonce = params.linkNonce ?? BigInt(0);
circuitInputs.verifierID = params.verifierDid ? js_iden3_core_1.DID.idFromDID(params.verifierDid) : undefined;
circuitInputs.nullifierSessionID = proofReq.params?.nullifierSessionId
? BigInt(proofReq.params?.nullifierSessionId?.toString())
: BigInt(0);
this.checkOperatorSupport(proofReq.circuitId, query.operator);
return circuitInputs.inputsMarshal();
};
this.credentialAtomicQueryV3OnChainPrepareInputs = async ({ preparedCredential, identifier, proofReq, params, circuitQueries }) => {
const id = js_iden3_core_1.DID.idFromDID(identifier);
const circuitClaimData = await this.newCircuitClaimData(preparedCredential);
circuitClaimData.nonRevProof = (0, common_1.toClaimNonRevStatus)(preparedCredential.revStatus);
let proofType;
switch (proofReq.query.proofType) {
case verifiable_1.ProofType.BJJSignature:
proofType = verifiable_1.ProofType.BJJSignature;
break;
case verifiable_1.ProofType.Iden3SparseMerkleTreeProof:
proofType = verifiable_1.ProofType.Iden3SparseMerkleTreeProof;
break;
default:
if (circuitClaimData.proof) {
proofType = verifiable_1.ProofType.Iden3SparseMerkleTreeProof;
}
else if (circuitClaimData.signatureProof) {
proofType = verifiable_1.ProofType.BJJSignature;
}
else {
throw Error('claim has no MTP or signature proof');
}
break;
}
const circuitInputs = new circuits_1.AtomicQueryV3OnChainInputs();
circuitInputs.id = js_iden3_core_1.DID.idFromDID(identifier);
circuitInputs.claim = {
issuerID: circuitClaimData?.issuerId,
signatureProof: circuitClaimData.signatureProof,
claim: circuitClaimData.claim,
nonRevProof: circuitClaimData.nonRevProof,
incProof: { proof: circuitClaimData.proof, treeState: circuitClaimData.treeState }
};
circuitInputs.requestID = BigInt(proofReq.id);
circuitInputs.claimSubjectProfileNonce = BigInt(params.credentialSubjectProfileNonce);
circuitInputs.profileNonce = BigInt(params.authProfileNonce);
circuitInputs.skipClaimRevocationCheck = params.skipRevocation;
const query = circuitQueries[0];
query.values = [circuits_1.Operators.SD, circuits_1.Operators.NOOP].includes(query.operator) ? [] : query.values;
query.valueProof = query.operator === circuits_1.Operators.NOOP ? new circuits_1.ValueProof() : query.valueProof;
circuitInputs.query = query;
circuitInputs.currentTimeStamp = (0, js_iden3_core_1.getUnixTimestamp)(new Date());
circuitInputs.proofType = proofType;
circuitInputs.linkNonce = params.linkNonce ?? BigInt(0);
circuitInputs.verifierID = params.verifierDid ? js_iden3_core_1.DID.idFromDID(params.verifierDid) : undefined;
circuitInputs.nullifierSessionID = proofReq.params?.nullifierSessionId
? BigInt(proofReq.params?.nullifierSessionId?.toString())
: BigInt(0);
const isEthIdentity = (0, utils_1.isEthereumIdentity)(identifier);
circuitInputs.isBJJAuthEnabled = isEthIdentity ? 0 : 1;
circuitInputs.challenge = BigInt(params.challenge ?? 0);
const stateProof = await this._stateStorage.getGISTProof(id.bigInt());
const gistProof = (0, common_1.toGISTProof)(stateProof);
circuitInputs.gistProof = gistProof;
// auth inputs
if (circuitInputs.isBJJAuthEnabled === 1) {
const authPrepared = await this.prepareAuthBJJCredential(identifier);
const authClaimData = await this.newCircuitClaimData({
credential: authPrepared.credential,
credentialCoreClaim: authPrepared.coreClaim
});
const signature = await this._identityWallet.signChallenge(circuitInputs.challenge, authPrepared.credential);
circuitInputs.authClaim = authClaimData.claim;
circuitInputs.authClaimIncMtp = authClaimData.proof;
circuitInputs.authClaimNonRevMtp = authPrepared.nonRevProof.proof;
circuitInputs.treeState = authClaimData.treeState;
circuitInputs.signature = signature;
}
this.checkOperatorSupport(proofReq.circuitId, query.operator);
return circuitInputs.inputsMarshal();
};
this.linkedMultiQuery10PrepareInputs = async ({ preparedCredential, params, proofReq, circuitQueries }) => {
const circuitClaimData = await this.newCircuitClaimData(preparedCredential);
circuitClaimData.nonRevProof = (0, common_1.toClaimNonRevStatus)(preparedCredential.revStatus);
const circuitInputs = new circuits_1.LinkedMultiQueryInputs();
circuitInputs.linkNonce = params.linkNonce ?? BigInt(0);
circuitInputs.claim = circuitClaimData.claim;
circuitInputs.query = circuitQueries;
circuitQueries.forEach((query) => {
this.checkOperatorSupport(proofReq.circuitId, query.operator);
});
circuitQueries.forEach((query) => {
query.values = [circuits_1.Operators.SD, circuits_1.Operators.NOOP].includes(query.operator) ? [] : query.values;
query.valueProof = query.operator === circuits_1.Operators.NOOP ? new circuits_1.ValueProof() : query.valueProof;
});
return circuitInputs.inputsMarshal();
};
}
async generateInputs(ctx) {
const { circuitId } = ctx.proofReq;
const fnName = `${circuitId.split('-')[0]}PrepareInputs`;
const queriesLength = ctx.circuitQueries.length;
if (queriesLength > exports.circuitValidator[circuitId].maxQueriesCount) {
throw new Error(`circuit ${circuitId} supports only ${exports.circuitValidator[circuitId].maxQueriesCount} queries`);
}
const fn = this[fnName];
if (!fn) {
throw new Error(`inputs generator for ${circuitId} not found`);
}
return fn(ctx);
}
async newCircuitClaimData(preparedCredential) {
const smtProof = preparedCredential.credential.getIden3SparseMerkleTreeProof();
const circuitClaim = new circuits_1.CircuitClaim();
circuitClaim.claim = preparedCredential.credentialCoreClaim;
circuitClaim.issuerId = js_iden3_core_1.DID.idFromDID(js_iden3_core_1.DID.parse(preparedCredential.credential.issuer));
if (smtProof) {
circuitClaim.proof = smtProof.mtp;
circuitClaim.treeState = {
state: smtProof.issuerData.state.value,
claimsRoot: smtProof.issuerData.state.claimsTreeRoot,
revocationRoot: smtProof.issuerData.state.revocationTreeRoot,
rootOfRoots: smtProof.issuerData.state.rootOfRoots
};
}
const sigProof = preparedCredential.credential.getBJJSignature2021Proof();
if (sigProof) {
const issuerDID = sigProof.issuerData.id;
const userDID = (0, credentials_1.getUserDIDFromCredential)(issuerDID, preparedCredential.credential);
const { credentialStatus, mtp, authCoreClaim } = sigProof.issuerData;
if (!credentialStatus) {
throw new Error("can't check the validity of issuer auth claim: no credential status in proof");
}
if (!mtp) {
throw new Error('issuer auth credential must have a mtp proof');
}
if (!authCoreClaim) {
throw new Error('issuer auth credential must have a core claim proof');
}
const opts = {
issuerGenesisState: sigProof.issuerData.state,
issuerDID,
userDID
};
const rs = await this._credentialWallet.getRevocationStatus(credentialStatus, opts);
const issuerAuthNonRevProof = (0, common_1.toClaimNonRevStatus)(rs);
circuitClaim.signatureProof = {
signature: sigProof.signature,
issuerAuthIncProof: {
proof: sigProof.issuerData.mtp,
treeState: {
state: sigProof.issuerData.state.value,
claimsRoot: sigProof.issuerData.state.claimsTreeRoot,
revocationRoot: sigProof.issuerData.state.revocationTreeRoot,
rootOfRoots: sigProof.issuerData.state.rootOfRoots
}
},
issuerAuthClaim: sigProof.issuerData.authCoreClaim,
issuerAuthNonRevProof
};
}
return circuitClaim;
}
async prepareAuthBJJCredential(did, treeStateInfo) {
const { authCredential, incProof, nonRevProof } = await this._identityWallet.getActualAuthCredential(did, treeStateInfo);
const authCoreClaim = authCredential.getCoreClaimFromProof(verifiable_1.ProofType.Iden3SparseMerkleTreeProof);
if (!authCoreClaim) {
throw new Error('auth core claim is not defined for auth bjj credential');
}
return {
credential: authCredential,
incProof,
nonRevProof,
coreClaim: authCoreClaim
};
}
transformV2QueryOperator(operator) {
return operator === circuits_1.Operators.SD || operator === circuits_1.Operators.NOOP ? circuits_1.Operators.EQ : operator;
}
checkOperatorSupport(circuitId, operator) {
const supportedOperators = exports.circuitValidator[circuitId].supportedOperations;
if (!supportedOperators.includes(operator)) {
throw new Error(`operator ${(0, circuits_1.getOperatorNameByValue)(operator)} is not supported by ${circuitId}`);
}
}
}
exports.InputGenerator = InputGenerator;