mirror of
https://github.com/selfxyz/self.git
synced 2026-04-05 03:00:53 -04:00
implement AttestationVerifier.ts
This commit is contained in:
92
sdk/src/AttestationVerifier.ts
Normal file
92
sdk/src/AttestationVerifier.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { groth16 } from 'snarkjs';
|
||||
import { n_dsc, k_dsc, ECDSA_K_LENGTH_FACTOR, k_dsc_ecdsa } from '../../common/src/constants/constants';
|
||||
import {
|
||||
areArraysEqual,
|
||||
getVkeyFromArtifacts,
|
||||
verifyDSCValidity,
|
||||
} from '../utils/utils';
|
||||
import forge from 'node-forge';
|
||||
import { splitToWords } from '../../common/src/utils/utils';
|
||||
import { parseDSC } from '../../common/src/utils/certificates/handleCertificate';
|
||||
import { OpenPassportAttestation, OpenPassportVerifierReport } from './index.web';
|
||||
import { parsePublicSignalsProve } from '../../common/src/utils/openPassportAttestation';
|
||||
|
||||
|
||||
export class AttestationVerifier {
|
||||
protected parsedPublicSignals: any;
|
||||
protected devMode: boolean;
|
||||
protected report: OpenPassportVerifierReport;
|
||||
|
||||
constructor(devMode: boolean = false) {
|
||||
this.devMode = devMode;
|
||||
}
|
||||
|
||||
async verify(attestation: OpenPassportAttestation): Promise<boolean> {
|
||||
const {
|
||||
proof: {
|
||||
value: { proof, publicSignals },
|
||||
},
|
||||
dsc: { value: dsc },
|
||||
dscProof: {
|
||||
value: { proof: dscProof, publicSignals: dscPublicSignals },
|
||||
},
|
||||
} = attestation;
|
||||
|
||||
const { signatureAlgorithm, hashFunction } = parseDSC(dsc); // inacurracy in the case of register circuit
|
||||
|
||||
const kScaled = signatureAlgorithm === 'ecdsa' ? ECDSA_K_LENGTH_FACTOR * k_dsc_ecdsa : k_dsc;
|
||||
const parsedPublicSignals = parsePublicSignalsProve(publicSignals, kScaled);
|
||||
|
||||
await this.verifyProof(proof, publicSignals, dsc, 'prove');
|
||||
switch (this.circuit) {
|
||||
case 'prove':
|
||||
if (this.circuitMode === 'prove_offchain') {
|
||||
await this.verifyProveArguments();
|
||||
await this.verifyDsc(dsc);
|
||||
} else if (this.circuitMode === 'register') {
|
||||
await this.verifyRegisterArguments();
|
||||
await this.verifyDscProof(dscProof, dscPublicSignals, dsc);
|
||||
}
|
||||
break;
|
||||
case 'disclose':
|
||||
await this.verifyDiscloseArguments();
|
||||
break;
|
||||
}
|
||||
return this.report.valid;
|
||||
}
|
||||
|
||||
protected async verifyProof(proof: string[], publicSignals: string[], dsc: string, circuit: string): Promise<void> {
|
||||
const vkey = this.getVerificationKey(dsc, circuit);
|
||||
const isVerified = await groth16.verify(vkey, publicSignals, proof as any);
|
||||
if (!isVerified) {
|
||||
// throw new Error('Proof verification failed');
|
||||
}
|
||||
}
|
||||
|
||||
protected getVerificationKey(dsc: string, circuit: string) {
|
||||
const { signatureAlgorithm, hashFunction } = parseDSC(dsc);
|
||||
return getVkeyFromArtifacts(circuit, signatureAlgorithm, hashFunction);
|
||||
}
|
||||
|
||||
protected async verifyDsc(dsc: string, pubKeyFromProof: string[]) {
|
||||
const dscCertificate = forge.pki.certificateFromPem(dsc);
|
||||
const isValidCertificate = verifyDSCValidity(dscCertificate, this.devMode);
|
||||
|
||||
if (!isValidCertificate) {
|
||||
// throw new Error('Invalid certificate chain');
|
||||
}
|
||||
|
||||
const dscModulus = BigInt((dscCertificate.publicKey as any).n);
|
||||
const dscModulusWords = splitToWords(dscModulus, n_dsc, k_dsc);
|
||||
const isModulusMatching = areArraysEqual(dscModulusWords, pubKeyFromProof);
|
||||
|
||||
if (!isModulusMatching) {
|
||||
// throw new Error('Public key modulus does not match');
|
||||
}
|
||||
}
|
||||
|
||||
private getParsedPublicSignals(publicSignals: string[], kScaled: number) {
|
||||
return parsePublicSignalsProve(publicSignals, kScaled);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
import { ArgumentsProveOffChain, ArgumentsRegisterOffChain, ArgumentsRegisterOnChain, Mode, OpenPassportAppPartial } from "../../common/src/utils/appType";
|
||||
import { ArgumentsProveOffChain, ArgumentsRegister, Mode, OpenPassportAppPartial } from "../../common/src/utils/appType";
|
||||
import { DEFAULT_RPC_URL, MODAL_SERVER_ADDRESS, WEBSOCKET_URL, countryNames } from "../../common/src/constants/constants";
|
||||
import { OpenPassportApp } from "../../common/src/utils/appType";
|
||||
import { UserIdType } from "../../common/src/utils/utils";
|
||||
import * as pako from 'pako';
|
||||
import msgpack from 'msgpack-lite';
|
||||
import { OpenPassportAttestation } from "./index.web";
|
||||
import { StringifyOptions } from "querystring";
|
||||
export class OpenPassportVerifier {
|
||||
import { AttestationVerifier } from './AttestationVerifier';
|
||||
export class OpenPassportVerifier extends AttestationVerifier {
|
||||
private mode: Mode;
|
||||
private scope: string;
|
||||
private minimumAge: { enabled: boolean; value: string } = { enabled: false, value: '18' };
|
||||
@@ -16,9 +16,9 @@ export class OpenPassportVerifier {
|
||||
private modalServerUrl: string = MODAL_SERVER_ADDRESS;
|
||||
private rpcUrl: string = DEFAULT_RPC_URL;
|
||||
private cscaMerkleTreeUrl: string = "";
|
||||
private devMode: boolean = false;
|
||||
|
||||
constructor(mode: Mode, scope: string) {
|
||||
constructor(mode: Mode, scope: string, devMode: boolean = false) {
|
||||
super(devMode);
|
||||
this.mode = mode;
|
||||
this.scope = scope;
|
||||
}
|
||||
@@ -78,7 +78,7 @@ export class OpenPassportVerifier {
|
||||
userIdType: userIdType,
|
||||
};
|
||||
|
||||
let openPassportArguments: ArgumentsProveOffChain | ArgumentsRegisterOnChain;
|
||||
let openPassportArguments: ArgumentsProveOffChain | ArgumentsRegister;
|
||||
switch (this.mode) {
|
||||
case "prove_offchain":
|
||||
const argsProveOffChain: ArgumentsProveOffChain = {
|
||||
@@ -92,10 +92,9 @@ export class OpenPassportVerifier {
|
||||
openPassportArguments = argsProveOffChain;
|
||||
break;
|
||||
case "register":
|
||||
const argsRegisterOnChain: ArgumentsRegisterOnChain = {
|
||||
const argsRegisterOnChain: ArgumentsRegister = {
|
||||
modalServerUrl: this.modalServerUrl,
|
||||
cscaMerkleTreeUrl: this.cscaMerkleTreeUrl,
|
||||
rpcUrl: this.rpcUrl,
|
||||
};
|
||||
openPassportArguments = argsRegisterOnChain;
|
||||
break;
|
||||
@@ -116,8 +115,5 @@ export class OpenPassportVerifier {
|
||||
}
|
||||
}
|
||||
|
||||
verify(attestation: OpenPassportAttestation): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ const handleWebSocketMessage =
|
||||
setProofStep: (step: number) => void,
|
||||
setProofVerified: (proofVerified: boolean) => void,
|
||||
openPassportVerifier: OpenPassportVerifier,
|
||||
onSuccess: (proof: OpenPassportAttestation, report: OpenPassportVerifierReport) => void
|
||||
onSuccess: (proof: OpenPassportAttestation) => void
|
||||
) =>
|
||||
async (data) => {
|
||||
console.log('received mobile status:', data.status);
|
||||
@@ -44,18 +44,18 @@ const handleWebSocketMessage =
|
||||
if (data.proof) {
|
||||
console.log(data.proof);
|
||||
try {
|
||||
const local_proofVerified: OpenPassportVerifierReport = await openPassportVerifier.verify(
|
||||
const local_proofVerified = await openPassportVerifier.verify(
|
||||
data.proof
|
||||
);
|
||||
setProofVerified(local_proofVerified.valid);
|
||||
setProofVerified(local_proofVerified);
|
||||
setProofStep(QRcodeSteps.PROOF_VERIFIED);
|
||||
setTimeout(() => {
|
||||
newSocket.emit('proof_verified', {
|
||||
sessionId,
|
||||
proofVerified: local_proofVerified.toString(),
|
||||
});
|
||||
if (local_proofVerified.valid) {
|
||||
onSuccess(data.proof, local_proofVerified);
|
||||
if (local_proofVerified) {
|
||||
onSuccess(data.proof);
|
||||
}
|
||||
}, 1500); // wait for animation to finish before sending the proof to mobile
|
||||
} catch (error) {
|
||||
|
||||
@@ -1,33 +1,23 @@
|
||||
'use client';
|
||||
|
||||
import { OpenPassportQRcode } from '../../../../../src/QRcode/OpenPassportQRcode';
|
||||
// import { OpenPassportQRcode } from '../../../../dist/bundle.web.js'
|
||||
import { TextField } from '@mui/material';
|
||||
import { useState } from 'react';
|
||||
import { COMMITMENT_TREE_TRACKER_URL } from '../../../../../../common/src/constants/constants';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
export default function Register() {
|
||||
const [appName, setAppName] = useState('🌐 OpenPassport');
|
||||
import { OpenPassportVerifier } from '../../../../../src/OpenPassportVerifier';
|
||||
export default function Prove() {
|
||||
const userId = uuidv4();
|
||||
return (
|
||||
<div className="h-screen w-full bg-white flex flex-col items-center justify-center gap-12">
|
||||
<div className="text-4xl text-black ">Register circuit</div>
|
||||
<OpenPassportQRcode
|
||||
appName={appName}
|
||||
scope="test"
|
||||
devMode={true}
|
||||
circuit="prove"
|
||||
circuitMode="register"
|
||||
merkleTreeUrl={COMMITMENT_TREE_TRACKER_URL}
|
||||
userId={userId}
|
||||
/>
|
||||
const scope = "scope"
|
||||
|
||||
<TextField
|
||||
id="outlined-basic"
|
||||
label="App Name"
|
||||
variant="outlined"
|
||||
value={appName}
|
||||
onChange={(e) => setAppName(e.target.value)}
|
||||
const openPassportVerifier = new OpenPassportVerifier('register', scope);
|
||||
return (
|
||||
<div className="h-screen w-full bg-white flex flex-col items-center justify-center gap-4">
|
||||
<OpenPassportQRcode
|
||||
appName="Mock App"
|
||||
userId={userId}
|
||||
userIdType={"uuid"}
|
||||
openPassportVerifier={openPassportVerifier}
|
||||
onSuccess={(attestation) => {
|
||||
// send the code to the backend server
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user