@zkproofport-app/sdk 0.5.0-beta.0 → 0.5.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -15
- package/dist/ProofportSDK.d.ts +29 -8
- package/dist/constants.d.ts +43 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.esm.js +177 -39
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +183 -37
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +177 -39
- package/dist/index.mjs.map +1 -1
- package/dist/offChainVerifier.d.ts +4 -0
- package/dist/types.d.ts +8 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -81,7 +81,7 @@ const qrDataUrl = await sdk.generateQRCode(relay.deepLink);
|
|
|
81
81
|
const result = await sdk.waitForProof(relay.requestId);
|
|
82
82
|
|
|
83
83
|
if (result.status === 'completed') {
|
|
84
|
-
// 6. Verify on-chain — the
|
|
84
|
+
// 6. Verify on-chain — against the SDK's own verifier for this circuit
|
|
85
85
|
const response: ProofResponse = {
|
|
86
86
|
requestId: result.requestId,
|
|
87
87
|
circuit: result.circuit as CircuitType,
|
|
@@ -296,9 +296,8 @@ One more difference worth knowing if you count people: its nullifier is
|
|
|
296
296
|
a constant compiled into the circuit, so one wallet in one scope has exactly
|
|
297
297
|
one nullifier and there is no input a prover can vary.
|
|
298
298
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
deployment is planned; until it exists, do not ship on this.
|
|
299
|
+
The verifier is deployed on GIWA Sepolia (chain `91342`). The mobile app shows
|
|
300
|
+
this circuit in its Laboratory, which the user turns on in More.
|
|
302
301
|
|
|
303
302
|
### `dojang_playground`
|
|
304
303
|
|
|
@@ -350,7 +349,7 @@ something the circuit never saw.
|
|
|
350
349
|
|
|
351
350
|
## Planned Circuits
|
|
352
351
|
|
|
353
|
-
|
|
352
|
+
ZKProofport is registered with the Ministry of the Interior and Safety as a Korea Mobile ID integration service (모바일 신분증 연계서비스). The three circuits below are in beta: `CIRCUIT_SUPPORT_STATUS` reports each of them as `planned`, and their input shape and public-input layout can change without a major version bump.
|
|
354
353
|
|
|
355
354
|
### `mdl_kr_ownership`
|
|
356
355
|
|
|
@@ -677,8 +676,8 @@ When you are done, `sdk.disconnect()` closes any open socket.
|
|
|
677
676
|
circuit: 'coinbase_attestation',
|
|
678
677
|
proof: '0x1f8b0a…', // proof bytes, opaque
|
|
679
678
|
publicInputs: ['0x00…2f', '0x00…a1', …], // ordered — 128 entries for this circuit
|
|
680
|
-
verifierAddress: '0x…', //
|
|
681
|
-
chainId: …, // network
|
|
679
|
+
verifierAddress: '0x…', // the verifier the app reports (checked, not trusted)
|
|
680
|
+
chainId: …, // the network the app reports (checked, not trusted)
|
|
682
681
|
deepLink: 'zkproofport://proof-request?data=…',
|
|
683
682
|
createdAt: '2026-02-07T09:14:02.101Z',
|
|
684
683
|
updatedAt: '2026-02-07T09:14:48.902Z',
|
|
@@ -692,8 +691,8 @@ When you are done, `sdk.disconnect()` closes any open socket.
|
|
|
692
691
|
| `circuit` | `string` | terminal results | Which circuit produced the proof, as reported by the mobile app. You need it to read `publicInputs`, because the layout is per circuit. Undefined while the request is still pending. |
|
|
693
692
|
| `proof` | `string` | `'completed'` | The proof bytes as a `0x` hex string. Opaque: the only thing to do with it is hand it to a verifier. |
|
|
694
693
|
| `publicInputs` | `string[]` | `'completed'` | The circuit's public inputs **in circuit order**. This is the part that carries meaning — what each index holds is in [Public Input Layout Constants](#public-input-layout-constants). |
|
|
695
|
-
| `verifierAddress` | `string` | `'completed'` |
|
|
696
|
-
| `chainId` | `number` | `'completed'` | The
|
|
694
|
+
| `verifierAddress` | `string` | `'completed'` | The verifier contract the mobile app reports. Forward it: the SDK compares it with the verifier it ships with and refuses the proof if they differ. It never verifies against this address. |
|
|
695
|
+
| `chainId` | `number` | `'completed'` | The network the mobile app reports. Same rule: compared, never trusted. |
|
|
697
696
|
| `error` | `string` | `'error'`, `'failed'`, `'expired'` | Human-readable reason from the mobile app or the relay. |
|
|
698
697
|
| `errorCode` | `string` | some `'error'` results | The app's error code, `E` + four digits (e.g. `'E2007'`). Absent when the app did not send one. |
|
|
699
698
|
| `deepLink` | `string` | polling path only | The deep link the request was created with. |
|
|
@@ -771,8 +770,8 @@ The relay answers `'expired'` before the SDK's default `timeoutMs` (300 000 ms)
|
|
|
771
770
|
| `status` | `'pending' \| 'completed' \| 'error' \| 'cancelled'` | Yes | `'completed'`. Anything else and verification returns `{ valid: false, error: 'Invalid or incomplete response' }` without touching the chain. Note the relay says `'failed'` where this type says `'error'` |
|
|
772
771
|
| `proof` | `string` | When completed | `result.proof` |
|
|
773
772
|
| `publicInputs` | `string[]` | When completed | `result.publicInputs` |
|
|
774
|
-
| `verifierAddress` | `string` |
|
|
775
|
-
| `chainId` | `number` |
|
|
773
|
+
| `verifierAddress` | `string` | No | `result.verifierAddress`. Optional. When present it must match the SDK's own verifier for the circuit, or verification is refused |
|
|
774
|
+
| `chainId` | `number` | No | `result.chainId`. Optional. When present it must match the network the SDK verifies the circuit on, or verification is refused |
|
|
776
775
|
| `numPublicInputs` | `number` | No | Never delivered by the relay, and never read during verification — `publicInputs.length` is used instead. Omit it |
|
|
777
776
|
| `timestamp` | `number` | No | Not delivered by the relay. Omit it |
|
|
778
777
|
| `error` | `string` | On failure | `result.error`. Carried for your own logging; verification ignores it |
|
|
@@ -783,7 +782,15 @@ There is no `nullifier` field here either.
|
|
|
783
782
|
|
|
784
783
|
Verify the proof cryptographically by calling the deployed Solidity verifier contract.
|
|
785
784
|
|
|
786
|
-
|
|
785
|
+
`verifyResponseOnChain` checks the proof against the verifier contract the SDK ships with for that circuit. Which contract judges a proof is never taken from the proof's own response: the SDK carries the deployed verifiers, generated from the circuits' deployment records, and a response whose `verifierAddress` or `chainId` differs from them is refused rather than checked elsewhere. If you configure your own verifier in the SDK's `verifiers` option, that one is used instead.
|
|
786
|
+
|
|
787
|
+
For OIDC domain proofs the SDK also checks that the proof was made with a signing key Google or Microsoft actually publishes. That key is part of the proof's public inputs, so a proof made with a self-generated key would otherwise pass the contract. The SDK fetches the provider's published keys, caches them as the provider's own cache headers allow, and returns `{ valid: false, error }` when the key is not among them or the keys cannot be fetched. Every verify method does this; there is nothing to call separately.
|
|
788
|
+
|
|
789
|
+
For Coinbase KYC, Coinbase country and GIWA proofs the SDK checks that the attestation's signer belongs to the published signer set: the proof carries the root of the signer list it was made against, and a proof made against any other list is refused with `{ valid: false, error }`. This too runs in every verify method.
|
|
790
|
+
|
|
791
|
+
The one limit: a proof made with a key the provider has already withdrawn, which this process never saw while it was published, cannot be checked and is refused. Keys seen while published stay acceptable for 24 hours after they disappear.
|
|
792
|
+
|
|
793
|
+
|
|
787
794
|
|
|
788
795
|
```typescript
|
|
789
796
|
import type { CircuitType, ProofResponse } from '@zkproofport-app/sdk';
|
|
@@ -815,11 +822,11 @@ The SDK connects to the right network on its own. Pass your own ethers `Provider
|
|
|
815
822
|
const verification = await sdk.verifyResponseOnChain(response, myProvider);
|
|
816
823
|
```
|
|
817
824
|
|
|
818
|
-
`verifyResponseOnChain` reports failures instead of throwing them. An incomplete response (`status` other than `'completed'`, or a missing `proof` / `publicInputs`) returns `{ valid: false, error: 'Invalid or incomplete response' }` without making a network call; a
|
|
825
|
+
`verifyResponseOnChain` reports failures instead of throwing them. An incomplete response (`status` other than `'completed'`, or a missing `proof` / `publicInputs`) returns `{ valid: false, error: 'Invalid or incomplete response' }` without making a network call; an unknown circuit, a response naming a different verifier, an OIDC signing key the provider does not publish and a reverting contract call each return `{ valid: false, error }` saying which.
|
|
819
826
|
|
|
820
827
|
`valid: true` means the verifier contract accepted the proof: it is a real proof for that circuit, and its public inputs are the ones it was proved against. It does **not** yet mean the proof answers *your* question — that it was bound to your scope, or that the domain or country in it is the one you asked for. Those live in the public inputs, and reading them is Step 8. `valid: false` is a rejected proof, not an outage: do not retry it, refuse the user.
|
|
821
828
|
|
|
822
|
-
>
|
|
829
|
+
> **`verifyOnChain` and `verifyResponseOffChain`.** `sdk.verifyOnChain(circuit, proof, publicInputs, providerOrSigner?)` takes the same proof in raw pieces and checks it against the same built-in verifier, with the same OIDC key check. `sdk.verifyResponseOffChain(response)` checks the proof against the circuit's verification key with no chain involved, and runs the same OIDC key check. Prefer `verifyResponseOnChain` when the answer has to be the one a contract gives.
|
|
823
830
|
|
|
824
831
|
### Step 8: Extract Scope, Nullifier, and Domain
|
|
825
832
|
|
|
@@ -1025,7 +1032,7 @@ async function verifyUser() {
|
|
|
1025
1032
|
|
|
1026
1033
|
## Configuration
|
|
1027
1034
|
|
|
1028
|
-
`ProofportSDK.create()` returns a fully configured SDK instance. No manual configuration is needed: the relay endpoint
|
|
1035
|
+
`ProofportSDK.create()` returns a fully configured SDK instance. No manual configuration is needed: the relay endpoint and the verifier contracts proofs are checked against are built in. The verifier a proof response names is compared with them, never used in their place.
|
|
1029
1036
|
|
|
1030
1037
|
## Types Reference
|
|
1031
1038
|
|
package/dist/ProofportSDK.d.ts
CHANGED
|
@@ -44,6 +44,12 @@ export declare class ProofportSDK {
|
|
|
44
44
|
private signer;
|
|
45
45
|
private relayUrl;
|
|
46
46
|
private socket;
|
|
47
|
+
/**
|
|
48
|
+
* Set by {@link ProofportSDK.create} from its environment preset. It decides
|
|
49
|
+
* which chain a proof is verified on when the dApp configured no verifier
|
|
50
|
+
* for the circuit; a custom-config SDK has none and must configure one.
|
|
51
|
+
*/
|
|
52
|
+
private environment;
|
|
47
53
|
/**
|
|
48
54
|
* Creates a new ProofportSDK instance.
|
|
49
55
|
*
|
|
@@ -73,13 +79,11 @@ export declare class ProofportSDK {
|
|
|
73
79
|
constructor(config?: ProofportConfig);
|
|
74
80
|
/**
|
|
75
81
|
* @internal
|
|
76
|
-
* Creates a
|
|
82
|
+
* Creates a proof request for a circuit whose dapp-side input is a scope
|
|
83
|
+
* (Coinbase KYC, OIDC domain, GIWA, Dojang), keeping that circuit's id.
|
|
77
84
|
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
* while maintaining privacy through zero-knowledge proofs.
|
|
81
|
-
*
|
|
82
|
-
* @param inputs - Circuit inputs for Coinbase KYC
|
|
85
|
+
* @param circuit - The circuit requested; it is the request's circuit
|
|
86
|
+
* @param inputs - Circuit inputs; `scope` is required (and `domain` for OIDC)
|
|
83
87
|
* @param inputs.scope - Application-specific scope (e.g., domain name)
|
|
84
88
|
* @param options - Request configuration options
|
|
85
89
|
|
|
@@ -94,7 +98,7 @@ export declare class ProofportSDK {
|
|
|
94
98
|
*
|
|
95
99
|
* @example
|
|
96
100
|
* ```typescript
|
|
97
|
-
* const request = sdk.
|
|
101
|
+
* const request = sdk.createScopedRequest('coinbase_attestation', {
|
|
98
102
|
* scope: 'myapp.com'
|
|
99
103
|
* }, {
|
|
100
104
|
* dappName: 'My DApp',
|
|
@@ -104,7 +108,7 @@ export declare class ProofportSDK {
|
|
|
104
108
|
* const deepLink = sdk.getDeepLinkUrl(request);
|
|
105
109
|
* ```
|
|
106
110
|
*/
|
|
107
|
-
private
|
|
111
|
+
private createScopedRequest;
|
|
108
112
|
/**
|
|
109
113
|
* @internal
|
|
110
114
|
* Creates a Coinbase Country attestation proof request.
|
|
@@ -169,6 +173,12 @@ export declare class ProofportSDK {
|
|
|
169
173
|
* ```
|
|
170
174
|
*/
|
|
171
175
|
private createProofRequest;
|
|
176
|
+
/**
|
|
177
|
+
* How each circuit's request is built and checked. Keyed by circuit id and
|
|
178
|
+
* exhaustive over it, so a new circuit is a compile error here instead of
|
|
179
|
+
* falling through to another circuit's builder.
|
|
180
|
+
*/
|
|
181
|
+
private static readonly REQUEST_BUILDERS;
|
|
172
182
|
/**
|
|
173
183
|
* @internal
|
|
174
184
|
* Creates a Korea Mobile ID (mDL) proof request for any of the three
|
|
@@ -491,6 +501,13 @@ export declare class ProofportSDK {
|
|
|
491
501
|
valid: boolean;
|
|
492
502
|
error?: string;
|
|
493
503
|
}>;
|
|
504
|
+
/**
|
|
505
|
+
* The verifier for a circuit: the one the dApp configured, otherwise the
|
|
506
|
+
* pinned deployment on the chain this SDK's environment verifies that
|
|
507
|
+
* circuit on. `undefined` when neither exists, which core reports as an
|
|
508
|
+
* error. Never anything a proof response said.
|
|
509
|
+
*/
|
|
510
|
+
private verifierTarget;
|
|
494
511
|
/**
|
|
495
512
|
* Verifies a proof response on-chain using the deployed verifier contract.
|
|
496
513
|
*
|
|
@@ -575,6 +592,8 @@ export declare class ProofportSDK {
|
|
|
575
592
|
* ```
|
|
576
593
|
*/
|
|
577
594
|
getVerifierAddress(circuit: CircuitType): string;
|
|
595
|
+
/** The configured or pinned verifier, or an error saying why there is none. */
|
|
596
|
+
private requireVerifier;
|
|
578
597
|
/**
|
|
579
598
|
* Gets the blockchain chain ID where the verifier contract is deployed.
|
|
580
599
|
*
|
|
@@ -731,6 +750,8 @@ export declare class ProofportSDK {
|
|
|
731
750
|
* ```
|
|
732
751
|
*/
|
|
733
752
|
static create(envOrConfig?: SDKEnvironment | ProofportConfig): ProofportSDK;
|
|
753
|
+
/** @internal An SDK on an environment preset's relay, verifying on that environment's chains. */
|
|
754
|
+
private static forEnvironment;
|
|
734
755
|
/**
|
|
735
756
|
* Detects if the code is running on a mobile device.
|
|
736
757
|
*
|
package/dist/constants.d.ts
CHANGED
|
@@ -13,6 +13,49 @@ import type { CircuitType, SDKEnvironment } from './types';
|
|
|
13
13
|
* ```
|
|
14
14
|
*/
|
|
15
15
|
export declare const RELAY_URLS: Record<SDKEnvironment, string>;
|
|
16
|
+
/**
|
|
17
|
+
* The chain each circuit is verified on, per environment. Complete: a circuit
|
|
18
|
+
* added to the SDK is a compile error here until somebody names its chain.
|
|
19
|
+
*
|
|
20
|
+
* Mirrors the mobile app's `CIRCUIT_NETWORKS` (proofport-app
|
|
21
|
+
* src/config/contracts.ts), because a proof is checked where the app said its
|
|
22
|
+
* verifier is: Base for the Coinbase and OIDC circuits, GIWA Sepolia for GIWA
|
|
23
|
+
* and Dojang (testnet-only), Base Sepolia for Korea Mobile ID (testnet-only).
|
|
24
|
+
* The ADDRESS on that chain always comes from core's pinned table, never from
|
|
25
|
+
* a proof response.
|
|
26
|
+
*/
|
|
27
|
+
export declare const VERIFICATION_CHAINS: {
|
|
28
|
+
readonly production: {
|
|
29
|
+
readonly coinbase_attestation: 8453;
|
|
30
|
+
readonly coinbase_country_attestation: 8453;
|
|
31
|
+
readonly oidc_domain_attestation: 8453;
|
|
32
|
+
readonly giwa_attestation: 91342;
|
|
33
|
+
readonly dojang_playground: 91342;
|
|
34
|
+
readonly mdl_kr_ownership: 84532;
|
|
35
|
+
readonly mdl_kr_age: 84532;
|
|
36
|
+
readonly mdl_kr_region: 84532;
|
|
37
|
+
};
|
|
38
|
+
readonly staging: {
|
|
39
|
+
readonly coinbase_attestation: 84532;
|
|
40
|
+
readonly coinbase_country_attestation: 84532;
|
|
41
|
+
readonly oidc_domain_attestation: 84532;
|
|
42
|
+
readonly giwa_attestation: 91342;
|
|
43
|
+
readonly dojang_playground: 91342;
|
|
44
|
+
readonly mdl_kr_ownership: 84532;
|
|
45
|
+
readonly mdl_kr_age: 84532;
|
|
46
|
+
readonly mdl_kr_region: 84532;
|
|
47
|
+
};
|
|
48
|
+
readonly local: {
|
|
49
|
+
readonly coinbase_attestation: 84532;
|
|
50
|
+
readonly coinbase_country_attestation: 84532;
|
|
51
|
+
readonly oidc_domain_attestation: 84532;
|
|
52
|
+
readonly giwa_attestation: 91342;
|
|
53
|
+
readonly dojang_playground: 91342;
|
|
54
|
+
readonly mdl_kr_ownership: 84532;
|
|
55
|
+
readonly mdl_kr_age: 84532;
|
|
56
|
+
readonly mdl_kr_region: 84532;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
16
59
|
/**
|
|
17
60
|
* Default deep link URL scheme for ZKProofport mobile app.
|
|
18
61
|
* Used to construct deep link URLs that open the mobile app.
|
package/dist/index.d.ts
CHANGED
|
@@ -30,6 +30,8 @@ export { extractScopeFromPublicInputs, extractNullifierFromPublicInputs, extract
|
|
|
30
30
|
export { CIRCUIT_IDS, CIRCUIT_SUPPORT_STATUS, ALL_CIRCUIT_IDS, SUPPORTED_CIRCUIT_IDS, EXPERIMENTAL_CIRCUIT_IDS, PLANNED_CIRCUIT_IDS, isCircuitId, isSupportedCircuitId, getCircuitSupportStatus, CIRCUIT_VK_PATHS, } from './circuits';
|
|
31
31
|
export { verifyProofOffChain } from './offChainVerifier';
|
|
32
32
|
export type { OffChainVerifyResult, OffChainVerifyOptions, } from './offChainVerifier';
|
|
33
|
+
export { PINNED_VERIFIERS, getPinnedVerifier } from './verifier';
|
|
34
|
+
export type { PinnedVerifier } from './verifier';
|
|
33
35
|
export { COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT, COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT, OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT, MDL_KR_PUBLIC_INPUT_LAYOUT, } from './constants';
|
|
34
36
|
export type { CircuitId, CircuitSupportStatus } from './circuits';
|
|
35
37
|
export { CIRCUIT_ACTION_BINDING, circuitActionBinding, } from './circuits';
|
package/dist/index.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { parseProofForOnChain, verifyProofOnChain,
|
|
2
|
-
export { COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT, COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT, MDL_KR_PUBLIC_INPUT_LAYOUT, OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT, extractDomainFromPublicInputs, extractNullifierFromPublicInputs, extractScopeFromPublicInputs } from '@zkproofport-app/core';
|
|
1
|
+
import { checkProofIssuer, parseProofForOnChain, verifyProofOnChain, getPinnedVerifier, extractScopeFromPublicInputs, extractNullifierFromPublicInputs, extractDomainFromPublicInputs } from '@zkproofport-app/core';
|
|
2
|
+
export { COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT, COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT, MDL_KR_PUBLIC_INPUT_LAYOUT, OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT, PINNED_VERIFIERS, extractDomainFromPublicInputs, extractNullifierFromPublicInputs, extractScopeFromPublicInputs, getPinnedVerifier } from '@zkproofport-app/core';
|
|
3
3
|
import { isCircuitId, ALL_CIRCUIT_IDS, circuitActionBinding, CIRCUIT_VK_PATHS, CIRCUIT_NEEDS_WALLET_SIGNATURE } from '@zkproofport-app/core/circuits';
|
|
4
4
|
export { ALL_CIRCUIT_IDS, CIRCUIT_ACTION_BINDING, CIRCUIT_IDS, CIRCUIT_SUPPORT_STATUS, CIRCUIT_VK_PATHS, EXPERIMENTAL_CIRCUIT_IDS, PLANNED_CIRCUIT_IDS, SUPPORTED_CIRCUIT_IDS, circuitActionBinding, getCircuitSupportStatus, isCircuitId, isSupportedCircuitId } from '@zkproofport-app/core/circuits';
|
|
5
5
|
import { validateTypedAction } from '@zkproofport-app/core/typedAction';
|
|
@@ -23,6 +23,49 @@ const RELAY_URLS = {
|
|
|
23
23
|
staging: 'https://stg-relay.zkproofport.app',
|
|
24
24
|
local: 'http://localhost:4001',
|
|
25
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* The chain each circuit is verified on, per environment. Complete: a circuit
|
|
28
|
+
* added to the SDK is a compile error here until somebody names its chain.
|
|
29
|
+
*
|
|
30
|
+
* Mirrors the mobile app's `CIRCUIT_NETWORKS` (proofport-app
|
|
31
|
+
* src/config/contracts.ts), because a proof is checked where the app said its
|
|
32
|
+
* verifier is: Base for the Coinbase and OIDC circuits, GIWA Sepolia for GIWA
|
|
33
|
+
* and Dojang (testnet-only), Base Sepolia for Korea Mobile ID (testnet-only).
|
|
34
|
+
* The ADDRESS on that chain always comes from core's pinned table, never from
|
|
35
|
+
* a proof response.
|
|
36
|
+
*/
|
|
37
|
+
const VERIFICATION_CHAINS = {
|
|
38
|
+
production: {
|
|
39
|
+
coinbase_attestation: 8453,
|
|
40
|
+
coinbase_country_attestation: 8453,
|
|
41
|
+
oidc_domain_attestation: 8453,
|
|
42
|
+
giwa_attestation: 91342,
|
|
43
|
+
dojang_playground: 91342,
|
|
44
|
+
mdl_kr_ownership: 84532,
|
|
45
|
+
mdl_kr_age: 84532,
|
|
46
|
+
mdl_kr_region: 84532,
|
|
47
|
+
},
|
|
48
|
+
staging: {
|
|
49
|
+
coinbase_attestation: 84532,
|
|
50
|
+
coinbase_country_attestation: 84532,
|
|
51
|
+
oidc_domain_attestation: 84532,
|
|
52
|
+
giwa_attestation: 91342,
|
|
53
|
+
dojang_playground: 91342,
|
|
54
|
+
mdl_kr_ownership: 84532,
|
|
55
|
+
mdl_kr_age: 84532,
|
|
56
|
+
mdl_kr_region: 84532,
|
|
57
|
+
},
|
|
58
|
+
local: {
|
|
59
|
+
coinbase_attestation: 84532,
|
|
60
|
+
coinbase_country_attestation: 84532,
|
|
61
|
+
oidc_domain_attestation: 84532,
|
|
62
|
+
giwa_attestation: 91342,
|
|
63
|
+
dojang_playground: 91342,
|
|
64
|
+
mdl_kr_ownership: 84532,
|
|
65
|
+
mdl_kr_age: 84532,
|
|
66
|
+
mdl_kr_region: 84532,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
26
69
|
/**
|
|
27
70
|
* Default deep link URL scheme for ZKProofport mobile app.
|
|
28
71
|
* Used to construct deep link URLs that open the mobile app.
|
|
@@ -3963,6 +4006,10 @@ async function fetchVerificationKey(circuit, timeoutMs) {
|
|
|
3963
4006
|
* Needs no setup from the caller: the verifier ships with this SDK and is
|
|
3964
4007
|
* loaded on first use.
|
|
3965
4008
|
*
|
|
4009
|
+
* For `oidc_domain_attestation` it first checks the proof's RSA key against the
|
|
4010
|
+
* provider's published JWKS (core's `checkOidcProviderKey`); a key the provider
|
|
4011
|
+
* does not publish, or a JWKS that cannot be fetched, is `{ valid: false }`.
|
|
4012
|
+
*
|
|
3966
4013
|
* @param circuit - Canonical circuit identifier
|
|
3967
4014
|
* @param proof - Proof bytes as hex, WITHOUT public inputs (as the relay sends it)
|
|
3968
4015
|
* @param publicInputs - Public inputs as hex strings, in circuit order
|
|
@@ -3981,6 +4028,18 @@ async function fetchVerificationKey(circuit, timeoutMs) {
|
|
|
3981
4028
|
*/
|
|
3982
4029
|
async function verifyProofOffChain(circuit, proof, publicInputs, options = {}) {
|
|
3983
4030
|
const timeoutMs = options.timeoutMs ?? 30000;
|
|
4031
|
+
if (!isCircuitId(circuit)) {
|
|
4032
|
+
return { valid: false, error: `Unknown circuit '${circuit}'. Known: ${ALL_CIRCUIT_IDS.join(', ')}.` };
|
|
4033
|
+
}
|
|
4034
|
+
// Before Barretenberg, and for the same reason as on-chain: a proof can be
|
|
4035
|
+
// mathematically valid and still mean nothing, because some circuits take
|
|
4036
|
+
// their trust anchor as a public input the prover chooses. For OIDC that is
|
|
4037
|
+
// the RSA key -- see core's oidcProviderKeys. Checked here so a dApp that
|
|
4038
|
+
// verifies off-chain gets the same answer as one that verifies on-chain.
|
|
4039
|
+
const issuer = await checkProofIssuer(circuit, publicInputs);
|
|
4040
|
+
if (!issuer.ok) {
|
|
4041
|
+
return { valid: false, error: issuer.error };
|
|
4042
|
+
}
|
|
3984
4043
|
// A REQUIRED dependency, loaded lazily.
|
|
3985
4044
|
//
|
|
3986
4045
|
// It was briefly an optional peer dependency, on the reasoning that the WASM
|
|
@@ -4121,22 +4180,32 @@ class ProofportSDK {
|
|
|
4121
4180
|
this.pendingRequests = new Map();
|
|
4122
4181
|
this.signer = null;
|
|
4123
4182
|
this.socket = null;
|
|
4183
|
+
/**
|
|
4184
|
+
* Set by {@link ProofportSDK.create} from its environment preset. It decides
|
|
4185
|
+
* which chain a proof is verified on when the dApp configured no verifier
|
|
4186
|
+
* for the circuit; a custom-config SDK has none and must configure one.
|
|
4187
|
+
*/
|
|
4188
|
+
this.environment = null;
|
|
4124
4189
|
this.config = {
|
|
4125
4190
|
scheme: config.scheme || DEFAULT_SCHEME,
|
|
4126
4191
|
verifiers: config.verifiers || {},
|
|
4127
4192
|
};
|
|
4128
4193
|
this.relayUrl = config.relayUrl || '';
|
|
4194
|
+
if (config.environment !== undefined) {
|
|
4195
|
+
if (!Object.prototype.hasOwnProperty.call(VERIFICATION_CHAINS, config.environment)) {
|
|
4196
|
+
throw new Error(`Unknown environment '${config.environment}'. Known: ${Object.keys(VERIFICATION_CHAINS).join(', ')}.`);
|
|
4197
|
+
}
|
|
4198
|
+
this.environment = config.environment;
|
|
4199
|
+
}
|
|
4129
4200
|
}
|
|
4130
4201
|
// ============ Request Creation ============
|
|
4131
4202
|
/**
|
|
4132
4203
|
* @internal
|
|
4133
|
-
* Creates a
|
|
4134
|
-
*
|
|
4135
|
-
* Generates a proof request for verifying Coinbase KYC status without revealing
|
|
4136
|
-
* the actual attestation data. The proof confirms the user has passed Coinbase KYC
|
|
4137
|
-
* while maintaining privacy through zero-knowledge proofs.
|
|
4204
|
+
* Creates a proof request for a circuit whose dapp-side input is a scope
|
|
4205
|
+
* (Coinbase KYC, OIDC domain, GIWA, Dojang), keeping that circuit's id.
|
|
4138
4206
|
*
|
|
4139
|
-
* @param
|
|
4207
|
+
* @param circuit - The circuit requested; it is the request's circuit
|
|
4208
|
+
* @param inputs - Circuit inputs; `scope` is required (and `domain` for OIDC)
|
|
4140
4209
|
* @param inputs.scope - Application-specific scope (e.g., domain name)
|
|
4141
4210
|
* @param options - Request configuration options
|
|
4142
4211
|
|
|
@@ -4151,7 +4220,7 @@ class ProofportSDK {
|
|
|
4151
4220
|
*
|
|
4152
4221
|
* @example
|
|
4153
4222
|
* ```typescript
|
|
4154
|
-
* const request = sdk.
|
|
4223
|
+
* const request = sdk.createScopedRequest('coinbase_attestation', {
|
|
4155
4224
|
* scope: 'myapp.com'
|
|
4156
4225
|
* }, {
|
|
4157
4226
|
* dappName: 'My DApp',
|
|
@@ -4161,13 +4230,34 @@ class ProofportSDK {
|
|
|
4161
4230
|
* const deepLink = sdk.getDeepLinkUrl(request);
|
|
4162
4231
|
* ```
|
|
4163
4232
|
*/
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4233
|
+
createScopedRequest(circuit, inputs, options = {}) {
|
|
4234
|
+
const scope = inputs.scope;
|
|
4235
|
+
if (typeof scope !== 'string' || scope.trim() === '') {
|
|
4236
|
+
throw new Error(`scope is required for ${circuit} circuit`);
|
|
4237
|
+
}
|
|
4238
|
+
if (circuit === 'oidc_domain_attestation') {
|
|
4239
|
+
const domain = inputs.domain;
|
|
4240
|
+
if (typeof domain !== 'string' || domain.trim() === '') {
|
|
4241
|
+
throw new Error('domain is required for oidc_domain_attestation circuit');
|
|
4242
|
+
}
|
|
4243
|
+
}
|
|
4244
|
+
const action = inputs.action;
|
|
4245
|
+
const binding = circuitActionBinding(circuit);
|
|
4246
|
+
if (binding === 'none' && action !== undefined) {
|
|
4247
|
+
throw new Error(`${circuit} has no action inputs, so an action sent with it would not be proved.`);
|
|
4248
|
+
}
|
|
4249
|
+
if (binding === 'required' || (binding === 'optional' && action !== undefined)) {
|
|
4250
|
+
const actionError = validateTypedAction(action);
|
|
4251
|
+
if (actionError)
|
|
4252
|
+
throw new Error(`${actionError} (circuit: ${circuit})`);
|
|
4167
4253
|
}
|
|
4168
4254
|
const request = {
|
|
4169
4255
|
requestId: generateRequestId(),
|
|
4170
|
-
circuit
|
|
4256
|
+
// The circuit asked for, always. This used to be the literal
|
|
4257
|
+
// 'coinbase_attestation', and every circuit that was not country or mDL
|
|
4258
|
+
// was routed here -- a GIWA, Dojang or OIDC request silently became a
|
|
4259
|
+
// Coinbase KYC request.
|
|
4260
|
+
circuit,
|
|
4171
4261
|
inputs,
|
|
4172
4262
|
message: options.message,
|
|
4173
4263
|
dappName: options.dappName,
|
|
@@ -4264,16 +4354,17 @@ class ProofportSDK {
|
|
|
4264
4354
|
* ```
|
|
4265
4355
|
*/
|
|
4266
4356
|
createProofRequest(circuit, inputs, options = {}) {
|
|
4267
|
-
if (circuit
|
|
4268
|
-
|
|
4269
|
-
}
|
|
4270
|
-
else if (circuit === 'mdl_kr_ownership' ||
|
|
4271
|
-
circuit === 'mdl_kr_age' ||
|
|
4272
|
-
circuit === 'mdl_kr_region') {
|
|
4273
|
-
return this.createMdlKrRequest(circuit, inputs, options);
|
|
4357
|
+
if (!isCircuitId(circuit)) {
|
|
4358
|
+
throw new Error(`Unknown circuit '${circuit}'. Known: ${ALL_CIRCUIT_IDS.join(', ')}.`);
|
|
4274
4359
|
}
|
|
4275
|
-
|
|
4276
|
-
|
|
4360
|
+
const builder = ProofportSDK.REQUEST_BUILDERS[circuit];
|
|
4361
|
+
switch (builder) {
|
|
4362
|
+
case 'country':
|
|
4363
|
+
return this.createCoinbaseCountryRequest(inputs, options);
|
|
4364
|
+
case 'mdl':
|
|
4365
|
+
return this.createMdlKrRequest(circuit, inputs, options);
|
|
4366
|
+
case 'scoped':
|
|
4367
|
+
return this.createScopedRequest(circuit, inputs, options);
|
|
4277
4368
|
}
|
|
4278
4369
|
}
|
|
4279
4370
|
/**
|
|
@@ -4650,8 +4741,24 @@ class ProofportSDK {
|
|
|
4650
4741
|
*/
|
|
4651
4742
|
async verifyOnChain(circuit, proof, publicInputs, providerOrSigner) {
|
|
4652
4743
|
const parsedProof = parseProofForOnChain(proof, publicInputs, publicInputs.length);
|
|
4653
|
-
|
|
4654
|
-
|
|
4744
|
+
return verifyProofOnChain(circuit, parsedProof, providerOrSigner, this.verifierTarget(circuit));
|
|
4745
|
+
}
|
|
4746
|
+
/**
|
|
4747
|
+
* The verifier for a circuit: the one the dApp configured, otherwise the
|
|
4748
|
+
* pinned deployment on the chain this SDK's environment verifies that
|
|
4749
|
+
* circuit on. `undefined` when neither exists, which core reports as an
|
|
4750
|
+
* error. Never anything a proof response said.
|
|
4751
|
+
*/
|
|
4752
|
+
verifierTarget(circuit) {
|
|
4753
|
+
const configured = this.config.verifiers[circuit];
|
|
4754
|
+
if (configured)
|
|
4755
|
+
return configured;
|
|
4756
|
+
if (this.environment === null)
|
|
4757
|
+
return undefined;
|
|
4758
|
+
const chains = VERIFICATION_CHAINS[this.environment];
|
|
4759
|
+
if (!Object.prototype.hasOwnProperty.call(chains, circuit))
|
|
4760
|
+
return undefined;
|
|
4761
|
+
return { chainId: chains[circuit] };
|
|
4655
4762
|
}
|
|
4656
4763
|
/**
|
|
4657
4764
|
* Verifies a proof response on-chain using the deployed verifier contract.
|
|
@@ -4692,12 +4799,14 @@ class ProofportSDK {
|
|
|
4692
4799
|
return { valid: false, error: 'Invalid or incomplete response' };
|
|
4693
4800
|
}
|
|
4694
4801
|
const parsedProof = parseProofForOnChain(response.proof, response.publicInputs, response.publicInputs.length);
|
|
4695
|
-
|
|
4696
|
-
|
|
4802
|
+
// The response's verifierAddress and chainId are a claim to check, never
|
|
4803
|
+
// the contract to call: whoever wrote the response would otherwise pick
|
|
4804
|
+
// the judge. A claim that differs from the pinned or configured verifier
|
|
4805
|
+
// is refused.
|
|
4806
|
+
return verifyProofOnChain(response.circuit, parsedProof, providerOrSigner, this.verifierTarget(response.circuit), {
|
|
4697
4807
|
verifierAddress: response.verifierAddress,
|
|
4698
4808
|
chainId: response.chainId,
|
|
4699
|
-
};
|
|
4700
|
-
return verifyProofOnChain(response.circuit, parsedProof, providerOrSigner, customVerifier, responseVerifier);
|
|
4809
|
+
});
|
|
4701
4810
|
}
|
|
4702
4811
|
/**
|
|
4703
4812
|
* Verifies a proof response off-chain, against the circuit's verification key.
|
|
@@ -4748,8 +4857,17 @@ class ProofportSDK {
|
|
|
4748
4857
|
* ```
|
|
4749
4858
|
*/
|
|
4750
4859
|
getVerifierAddress(circuit) {
|
|
4751
|
-
|
|
4752
|
-
|
|
4860
|
+
return this.requireVerifier(circuit).address;
|
|
4861
|
+
}
|
|
4862
|
+
/** The configured or pinned verifier, or an error saying why there is none. */
|
|
4863
|
+
requireVerifier(circuit) {
|
|
4864
|
+
const target = this.verifierTarget(circuit);
|
|
4865
|
+
if (!target) {
|
|
4866
|
+
throw new Error(`No verifier configured for circuit '${circuit}'. Configure one in the SDK's verifiers option, or create the SDK with ProofportSDK.create() to use the pinned deployment.`);
|
|
4867
|
+
}
|
|
4868
|
+
if ('address' in target)
|
|
4869
|
+
return { address: target.address, chainId: target.chainId };
|
|
4870
|
+
return { address: getPinnedVerifier(circuit, target.chainId).address, chainId: target.chainId };
|
|
4753
4871
|
}
|
|
4754
4872
|
/**
|
|
4755
4873
|
* Gets the blockchain chain ID where the verifier contract is deployed.
|
|
@@ -4769,8 +4887,7 @@ class ProofportSDK {
|
|
|
4769
4887
|
* ```
|
|
4770
4888
|
*/
|
|
4771
4889
|
getVerifierChainId(circuit) {
|
|
4772
|
-
|
|
4773
|
-
return getVerifierChainId(circuit, customVerifier);
|
|
4890
|
+
return this.requireVerifier(circuit).chainId;
|
|
4774
4891
|
}
|
|
4775
4892
|
/**
|
|
4776
4893
|
* Gets metadata for a specific circuit type.
|
|
@@ -4917,17 +5034,20 @@ class ProofportSDK {
|
|
|
4917
5034
|
*/
|
|
4918
5035
|
static create(envOrConfig) {
|
|
4919
5036
|
if (typeof envOrConfig === 'undefined') {
|
|
4920
|
-
return
|
|
5037
|
+
return ProofportSDK.forEnvironment('production');
|
|
4921
5038
|
}
|
|
4922
5039
|
if (typeof envOrConfig === 'string') {
|
|
4923
|
-
|
|
4924
|
-
if (!relayUrl) {
|
|
4925
|
-
throw new Error(`Unknown environment: ${envOrConfig}. Use 'production', 'staging', or 'local'.`);
|
|
4926
|
-
}
|
|
4927
|
-
return new ProofportSDK({ relayUrl });
|
|
5040
|
+
return ProofportSDK.forEnvironment(envOrConfig);
|
|
4928
5041
|
}
|
|
4929
5042
|
return new ProofportSDK(envOrConfig);
|
|
4930
5043
|
}
|
|
5044
|
+
/** @internal An SDK on an environment preset's relay, verifying on that environment's chains. */
|
|
5045
|
+
static forEnvironment(env) {
|
|
5046
|
+
if (!Object.prototype.hasOwnProperty.call(RELAY_URLS, env)) {
|
|
5047
|
+
throw new Error(`Unknown environment: ${env}. Use 'production', 'staging', or 'local'.`);
|
|
5048
|
+
}
|
|
5049
|
+
return new ProofportSDK({ relayUrl: RELAY_URLS[env], environment: env });
|
|
5050
|
+
}
|
|
4931
5051
|
/**
|
|
4932
5052
|
* Detects if the code is running on a mobile device.
|
|
4933
5053
|
*
|
|
@@ -5061,7 +5181,10 @@ class ProofportSDK {
|
|
|
5061
5181
|
// calling createRelayRequest() for it with no signer got no local error and
|
|
5062
5182
|
// a relay 401 two round trips later.
|
|
5063
5183
|
static needsWalletSignature(circuit) {
|
|
5064
|
-
|
|
5184
|
+
if (!isCircuitId(circuit)) {
|
|
5185
|
+
throw new Error(`Unknown circuit '${circuit}'. Expected: ${ALL_CIRCUIT_IDS.join(', ')}`);
|
|
5186
|
+
}
|
|
5187
|
+
return CIRCUIT_NEEDS_WALLET_SIGNATURE[circuit];
|
|
5065
5188
|
}
|
|
5066
5189
|
async createRelayRequest(circuit, inputs, options = {}) {
|
|
5067
5190
|
if (!this.relayUrl) {
|
|
@@ -5435,6 +5558,21 @@ class ProofportSDK {
|
|
|
5435
5558
|
return extractDomainFromPublicInputs(publicInputs, circuit);
|
|
5436
5559
|
}
|
|
5437
5560
|
}
|
|
5561
|
+
/**
|
|
5562
|
+
* How each circuit's request is built and checked. Keyed by circuit id and
|
|
5563
|
+
* exhaustive over it, so a new circuit is a compile error here instead of
|
|
5564
|
+
* falling through to another circuit's builder.
|
|
5565
|
+
*/
|
|
5566
|
+
ProofportSDK.REQUEST_BUILDERS = {
|
|
5567
|
+
coinbase_attestation: 'scoped',
|
|
5568
|
+
coinbase_country_attestation: 'country',
|
|
5569
|
+
oidc_domain_attestation: 'scoped',
|
|
5570
|
+
giwa_attestation: 'scoped',
|
|
5571
|
+
dojang_playground: 'scoped',
|
|
5572
|
+
mdl_kr_ownership: 'mdl',
|
|
5573
|
+
mdl_kr_age: 'mdl',
|
|
5574
|
+
mdl_kr_region: 'mdl',
|
|
5575
|
+
};
|
|
5438
5576
|
|
|
5439
5577
|
export { ProofportSDK, RELAY_TERMINAL_STATUSES, ProofportSDK as default, isTerminalRelayStatus, verifyProofOffChain };
|
|
5440
5578
|
//# sourceMappingURL=index.esm.js.map
|