From d893f1e467f205936e728330c18921e0a48917c3 Mon Sep 17 00:00:00 2001 From: Rob Knight Date: Sat, 14 Sep 2024 14:19:26 +0200 Subject: [PATCH] GPC verification via API --- apps/client-web/src/client/gpc.ts | 26 ++++++++++++++++---- examples/test-app/src/apis/GPC.tsx | 29 +++++++++++++++-------- examples/test-app/src/apis/PODSection.tsx | 5 +--- packages/app-connector/src/api_wrapper.ts | 21 +++++++--------- packages/app-connector/src/rpc_client.ts | 15 +++++------- packages/client-rpc/src/rpc_interfaces.ts | 7 +++--- packages/podspec/src/parse/pod.ts | 2 +- packages/podspec/src/schemas/pod.ts | 16 +++++-------- 8 files changed, 66 insertions(+), 55 deletions(-) diff --git a/apps/client-web/src/client/gpc.ts b/apps/client-web/src/client/gpc.ts index 50344dc..c1fc613 100644 --- a/apps/client-web/src/client/gpc.ts +++ b/apps/client-web/src/client/gpc.ts @@ -1,6 +1,12 @@ import { ConnectorAdvice } from "@parcnet/client-helpers"; import { ParcnetGPCRPC, ProveResult } from "@parcnet/client-rpc"; import { PodspecProofRequest, proofRequest } from "@parcnet/podspec"; +import { + GPCBoundConfig, + GPCProof, + GPCRevealedClaims, + gpcVerify +} from "@pcd/gpc"; import { Dispatch } from "react"; import { ClientAction } from "../state"; import { PODCollection } from "./pod_collection"; @@ -41,7 +47,6 @@ export class ParcnetGPCProcessor implements ParcnetGPCRPC { const advice = this.advice; return new Promise((resolve) => { - console.log("proving"); this.advice.showClient(); this.dispatch({ type: "set-proof-in-progress", @@ -57,9 +62,20 @@ export class ParcnetGPCProcessor implements ParcnetGPCRPC { }); } - // eslint-disable-next-line @typescript-eslint/no-explicit-any - public async verify(pcd: any): Promise { - console.log(pcd); - return true; + public async verify( + proof: GPCProof, + boundConfig: GPCBoundConfig, + revealedClaims: GPCRevealedClaims, + pr: PodspecProofRequest + ): Promise { + const config = proofRequest(pr).getProofRequest().proofConfig; + config.circuitIdentifier = boundConfig.circuitIdentifier; + + return gpcVerify( + proof, + config as GPCBoundConfig, + revealedClaims, + new URL("/artifacts", window.location.origin).toString() + ); } } diff --git a/examples/test-app/src/apis/GPC.tsx b/examples/test-app/src/apis/GPC.tsx index 4dc655e..75d1e2e 100644 --- a/examples/test-app/src/apis/GPC.tsx +++ b/examples/test-app/src/apis/GPC.tsx @@ -31,8 +31,8 @@ const request: PodspecProofRequest = { export function GPC(): ReactNode { const { z, connected } = useParcnetClient(); - const [proof, setProof] = useState(); - const [verified, _setVerified] = useState(); + const [proveResult, setProveResult] = useState(); + const [verified, setVerified] = useState(); return !connected ? null : (
@@ -75,16 +75,16 @@ const gpcProof = await z.gpc.prove(request); { try { - setProof(await z.gpc.prove(request)); + setProveResult(await z.gpc.prove(request)); } catch (e) { console.log(e); } }} label="Get GPC Proof" /> - {proof && ( + {proveResult && (
-              {JSONBig.stringify(proof, null, 2)}
+              {JSONBig.stringify(proveResult, null, 2)}
             
)}
@@ -93,18 +93,27 @@ const gpcProof = await z.gpc.prove(request); Verify a GPC proof like this: {` -const verified = await z.gpc.verify(proof); +const verified = await z.gpc.verify(proof, config, revealedClaims, request); `}

- {!proof && ( + {!proveResult && ( Generate a proof above, then we can verify it. )} - {proof && ( + {proveResult && ( { + onClick={async () => { try { - // setVerified(await z.gpc.verify(proof)); + if (proveResult.success) { + setVerified( + await z.gpc.verify( + proveResult.proof, + proveResult.boundConfig, + proveResult.revealedClaims, + request + ) + ); + } } catch (e) { console.log(e); } diff --git a/examples/test-app/src/apis/PODSection.tsx b/examples/test-app/src/apis/PODSection.tsx index 13eb301..4d14735 100644 --- a/examples/test-app/src/apis/PODSection.tsx +++ b/examples/test-app/src/apis/PODSection.tsx @@ -403,10 +403,7 @@ function DeletePOD({ z }: { z: ParcnetAPI }): ReactNode { function SubscribeToPODs({ z }: { z: ParcnetAPI }): ReactNode { const [pods, setPODs] = useState([]); - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const [subscription, setSubscription] = useState | null>( - null - ); + const [subscription, setSubscription] = useState(null); return (
diff --git a/packages/app-connector/src/api_wrapper.ts b/packages/app-connector/src/api_wrapper.ts index 6763069..c7a09a9 100644 --- a/packages/app-connector/src/api_wrapper.ts +++ b/packages/app-connector/src/api_wrapper.ts @@ -4,7 +4,7 @@ import { ProveResult } from "@parcnet/client-rpc"; import * as p from "@parcnet/podspec"; -import { GPCProof, GPCRevealedClaims } from "@pcd/gpc"; +import { GPCBoundConfig, GPCProof, GPCRevealedClaims } from "@pcd/gpc"; import { POD } from "@pcd/pod"; import { EventEmitter } from "eventemitter3"; import { PodspecProofRequest } from "../../podspec/src/index.js"; @@ -18,16 +18,12 @@ import { ParcnetRPCConnector } from "./rpc_client.js"; * It also allows the caller to run the query immediately, which is useful on * first creating the subscription, before any updates are available. */ -export class Subscription { +export class Subscription { #emitter: EventEmitter; - #query: p.PodSpec; + #query: p.PodSpec; #api: ParcnetPODWrapper; - constructor( - query: p.PodSpec, - emitter: EventEmitter, - api: ParcnetPODWrapper - ) { + constructor(query: p.PodSpec, emitter: EventEmitter, api: ParcnetPODWrapper) { this.#emitter = emitter; this.#query = query; this.#api = api; @@ -64,14 +60,12 @@ class ParcnetPODWrapper { }); } - async query(query: p.PodSpec): Promise { + async query(query: p.PodSpec): Promise { const pods = await this.#api.pod.query(query.schema); return pods.map((pod) => POD.deserialize(pod)); } - async subscribe( - query: p.PodSpec - ): Promise> { + async subscribe(query: p.PodSpec): Promise { const subscriptionId = await this.#api.pod.subscribe(query.schema); const emitter = new EventEmitter(); const subscription = new Subscription(query, emitter, this); @@ -107,10 +101,11 @@ class ParcnetGPCWrapper { async verify

>( proof: GPCProof, + config: GPCBoundConfig, revealedClaims: GPCRevealedClaims, proofRequest: PodspecProofRequest

): Promise { - return this.#api.gpc.verify(proof, revealedClaims, proofRequest); + return this.#api.gpc.verify(proof, config, revealedClaims, proofRequest); } } diff --git a/packages/app-connector/src/rpc_client.ts b/packages/app-connector/src/rpc_client.ts index 4bc624c..1f63372 100644 --- a/packages/app-connector/src/rpc_client.ts +++ b/packages/app-connector/src/rpc_client.ts @@ -13,8 +13,8 @@ import { RPCMessageType, SubscriptionUpdateResult } from "@parcnet/client-rpc"; -import { EntriesSchema, PodspecProofRequest } from "@parcnet/podspec"; -import { GPCProof, GPCRevealedClaims } from "@pcd/gpc"; +import { PodspecProofRequest } from "@parcnet/podspec"; +import { GPCBoundConfig, GPCProof, GPCRevealedClaims } from "@pcd/gpc"; import { EventEmitter } from "eventemitter3"; import { z, ZodFunction, ZodTuple, ZodTypeAny } from "zod"; import { DialogController } from "./adapters/iframe.js"; @@ -115,9 +115,7 @@ export class ParcnetRPCConnector implements ParcnetRPC, ParcnetEvents { this.#emitter = new EventEmitter(); this.pod = { - query: async ( - query: PODQuery - ): Promise => { + query: async (query: PODQuery): Promise => { return this.#typedInvoke( "pod.query", [query], @@ -138,9 +136,7 @@ export class ParcnetRPCConnector implements ParcnetRPC, ParcnetEvents { ParcnetRPCSchema.shape.pod.shape.delete ); }, - subscribe: async ( - query: PODQuery - ): Promise => { + subscribe: async (query: PODQuery): Promise => { return this.#typedInvoke( "pod.subscribe", [query], @@ -172,12 +168,13 @@ export class ParcnetRPCConnector implements ParcnetRPC, ParcnetEvents { }, verify: async ( proof: GPCProof, + boundConfig: GPCBoundConfig, revealedClaims: GPCRevealedClaims, proofRequest: PodspecProofRequest ): Promise => { return this.#typedInvoke( "gpc.verify", - [proof, revealedClaims, proofRequest], + [proof, boundConfig, revealedClaims, proofRequest], ParcnetRPCSchema.shape.gpc.shape.verify ); } diff --git a/packages/client-rpc/src/rpc_interfaces.ts b/packages/client-rpc/src/rpc_interfaces.ts index 33dd22c..be7579c 100644 --- a/packages/client-rpc/src/rpc_interfaces.ts +++ b/packages/client-rpc/src/rpc_interfaces.ts @@ -11,7 +11,7 @@ import { GPCBoundConfig, GPCProof, GPCRevealedClaims } from "@pcd/gpc"; * These interfaces are implemented in rpc_client.ts. */ -export type PODQuery = PODSchema; +export type PODQuery = PODSchema; export interface SubscriptionUpdateResult { subscriptionId: string; @@ -35,6 +35,7 @@ export interface ParcnetGPCRPC { canProve: (request: PodspecProofRequest) => Promise; verify: ( proof: GPCProof, + boundConfig: GPCBoundConfig, revealedClaims: GPCRevealedClaims, proofRequest: PodspecProofRequest ) => Promise; @@ -46,10 +47,10 @@ export interface ParcnetIdentityRPC { export interface ParcnetPODRPC { // Returns array of serialized PODs - query: (query: PODQuery) => Promise; + query: (query: PODQuery) => Promise; insert: (serializedPod: string) => Promise; delete: (signature: string) => Promise; - subscribe: (query: PODQuery) => Promise; + subscribe: (query: PODQuery) => Promise; unsubscribe: (subscriptionId: string) => Promise; } diff --git a/packages/podspec/src/parse/pod.ts b/packages/podspec/src/parse/pod.ts index 04dd958..c8d8c6a 100644 --- a/packages/podspec/src/parse/pod.ts +++ b/packages/podspec/src/parse/pod.ts @@ -41,7 +41,7 @@ export interface StrongPOD extends POD { * A PodSpec is a specification for a POD, including its schema and any * additional constraints. */ -export class PodSpec { +export class PodSpec { public readonly schema: PODSchema>; public entries(): EntriesSchemaLiteral { diff --git a/packages/podspec/src/schemas/pod.ts b/packages/podspec/src/schemas/pod.ts index 09fa6c6..658b895 100644 --- a/packages/podspec/src/schemas/pod.ts +++ b/packages/podspec/src/schemas/pod.ts @@ -1,21 +1,17 @@ import { PODValue } from "@pcd/pod"; import { EntriesSchema, EntriesSchemaLiteral } from "./entries.js"; -/** - * Schema for a tuple of entries. - */ -export type PODTupleSchema = { - entries: (keyof (E & { $signerPublicKey: never }) & string)[]; - isMemberOf?: PODValue[][]; - isNotMemberOf?: PODValue[][]; -}; - /** * Schema for validating a POD. */ export type PODSchema = { entries: EntriesSchemaLiteral; - tuples?: PODTupleSchema>[]; + tuples?: { + entries: (keyof (EntriesSchemaLiteral & { $signerPublicKey: never }) & + string)[]; + isMemberOf?: PODValue[][]; + isNotMemberOf?: PODValue[][]; + }[]; signerPublicKey?: { isMemberOf?: string[]; isNotMemberOf?: string[];