UNPKG

@ew-did-registry/claims

Version:

The package exposes functionality needed to create, inspect, approve, and verify Private and Public claims

118 lines (113 loc) 3.85 kB
import { bn, hash, ecc, bitArray } from 'sjcl'; import { DelegateTypes, IDIDDocument, } from '@ew-did-registry/did-resolver-interface'; import crypto from 'crypto'; import { Claims } from '../claims'; import { IClaimsVerifier } from '../interface'; import { IProofClaim, IPublicClaim } from '../models'; export class ClaimsVerifier extends Claims implements IClaimsVerifier { /** * Verifies integrity of the claim, the claim is issued by the user * delegate and the authenticity of the issuer's signature * * @example * ```typescript * import { ClaimsVerifier } from '@ew-did-registry/claims'; * import { Keys } from '@ew-did-registry/keys'; * * const keys = new Keys(); * const claims = new ClaimsVerifier(verifier); * const verified = claims.verifyPublicProof(issuedToken); * ``` * @param { string } token containing proof data * @returns { Promise<void> } whether the proof was succesfull * @throws if the proof failed */ async verifyPublicProof( claimUrl: string, { holderDoc, issuerDoc, }: { holderDoc?: IDIDDocument; issuerDoc?: IDIDDocument; } = {} ): Promise<IPublicClaim> { return this.verify(claimUrl, { holderDoc, issuerDoc, }) as Promise<IPublicClaim>; } /** * Checks issuer signature on issued token and user signature on proof token * and verifies that proof and private data mathches to each other * * @example * ```typescript * import { ClaimsVerifier } from '@ew-did-registry/claims'; * import { Keys } from '@ew-did-registry/keys'; * * const keys = new Keys(); * const claims = new ClaimsVerifier(verifier); * const verified = claims.verifyPrivateProof(proofToken); * ``` * @param { string } proofToken contains proof data * @param { string } privateToken contains private data * @returns { Promise<void> } whether the proof was succesfull * @throws if the proof failed */ async verifyPrivateProof(proofToken: string): Promise<void> { const { claimUrl } = this.jwt.decode(proofToken) as IProofClaim; const privateClaim = await this.verify(claimUrl); const curve: sjcl.SjclEllipticalCurve = ecc.curves.k256; const g = curve.G; const proofClaim: IProofClaim = this.jwt.decode(proofToken) as IProofClaim; if ( !this.document.isValidDelegate( DelegateTypes.verification, privateClaim.signer, privateClaim.did ) ) { throw new Error("Issuer isn't a user delegate"); } const { proofData } = proofClaim; // eslint-disable-next-line no-restricted-syntax Object.entries(privateClaim.claimData).forEach(([key, value]) => { const field = proofData[key]; if (field.encrypted) { const PK = curve.fromBits(value as []); // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore let { h, s } = field.value; h = curve.fromBits(h); s = bn.fromBits(s); const c = bn.fromBits( hash.sha256.hash(g.x.toBits().concat(h.toBits()).concat(PK.toBits())) ); const left = g.mult(s); const right = PK.mult(c).toJac().add(h).toAffine(); if (!bitArray.equal(left.toBits(), right.toBits())) { throw new Error( "User didn't prove the knowledge of the private data" ); } } else { const fieldHash = crypto .createHash('sha256') .update(field.value as string) .digest('hex'); // eslint-disable-next-line new-cap const PK = g.mult(new bn(fieldHash)); const bitsPK = PK.toBits(); if (!bitArray.equal(value as [], bitsPK)) { throw new Error( 'Disclosed field does not correspond to stored field' ); } } }); } }