@zkproofport-app/sdk 0.5.0-beta.4 → 0.5.0-beta.5
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 +23 -15
- package/dist/constants.d.ts +1 -1
- package/dist/index.esm.js +9 -8
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +9 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +9 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -177,6 +177,7 @@ Proves that a user has completed Coinbase KYC identity verification without reve
|
|
|
177
177
|
| `scope` | `string` | Yes | Application-specific identifier (e.g., your domain). Ensures proof uniqueness per app. |
|
|
178
178
|
| `userAddress` | `string` | No | Address to prove the attestation for. Omit it and the mobile app asks the user to connect a wallet. |
|
|
179
179
|
| `rawTransaction` | `string` | No | Pre-fetched attestation transaction data. Omit it and the app fetches the attestation itself. |
|
|
180
|
+
| `action` | `TypedAction` | No | One EIP-712 action for the wallet to sign and the proof to carry. Without one the wallet signs the request's signal hash. See [Which circuits take an action](#which-circuits-take-an-action). |
|
|
180
181
|
|
|
181
182
|
```typescript
|
|
182
183
|
const relay = await sdk.createRelayRequest('coinbase_attestation', {
|
|
@@ -184,6 +185,9 @@ const relay = await sdk.createRelayRequest('coinbase_attestation', {
|
|
|
184
185
|
});
|
|
185
186
|
```
|
|
186
187
|
|
|
188
|
+
Its nullifier is `keccak(keccak(wallet ++ keccak("coinbase_attestation")) ++ scope)`:
|
|
189
|
+
one wallet in one scope has exactly one nullifier.
|
|
190
|
+
|
|
187
191
|
### `coinbase_country_attestation`
|
|
188
192
|
|
|
189
193
|
Proves a user's country based on Coinbase verification, supporting inclusion and exclusion checks, without revealing the actual country. Requires a wallet signer.
|
|
@@ -263,7 +267,7 @@ const { deepLink } = await sdk.createRelayRequest(
|
|
|
263
267
|
**An action is optional here.** Send one
|
|
264
268
|
and the wallet signs EIP-712 typed data, so the person reads named fields and
|
|
265
269
|
the proof carries what they approved. Send none and the wallet signs the
|
|
266
|
-
request's signal hash
|
|
270
|
+
request's signal hash. Coinbase KYC branches the same way. The circuit itself
|
|
267
271
|
branches, and it refuses a request that tries to be both: with an action the
|
|
268
272
|
signal hash must be empty, without one the EIP-712 pair must be.
|
|
269
273
|
|
|
@@ -284,8 +288,8 @@ await sdk.createRelayRequest(
|
|
|
284
288
|
```
|
|
285
289
|
|
|
286
290
|
Its public inputs are `signal_hash`, `domain_separator`, `action_hash`,
|
|
287
|
-
`signer_list_merkle_root`, `scope`, `nullifier
|
|
288
|
-
|
|
291
|
+
`signer_list_merkle_root`, `scope`, `nullifier`: Coinbase KYC's order without
|
|
292
|
+
its final `attested_at`.
|
|
289
293
|
|
|
290
294
|
One more difference worth knowing if you count people: its nullifier is
|
|
291
295
|
`keccak(keccak(wallet ++ keccak("giwa_attestation")) ++ scope)`. The wallet and
|
|
@@ -329,14 +333,15 @@ circuit names are special:
|
|
|
329
333
|
|
|
330
334
|
| What the circuit does with an action | Circuits |
|
|
331
335
|
|---|---|
|
|
332
|
-
| Signs it when present, signs the signal hash when not | `giwa_attestation`, `dojang_playground` |
|
|
333
|
-
| Has no action inputs — sending one is refused, not ignored | Coinbase
|
|
336
|
+
| Signs it when present, signs the signal hash when not | `coinbase_attestation`, `giwa_attestation`, `dojang_playground` |
|
|
337
|
+
| Has no action inputs — sending one is refused, not ignored | Coinbase country, OIDC domain |
|
|
334
338
|
|
|
335
339
|
```typescript
|
|
336
340
|
import { circuitActionBinding } from '@zkproofport-app/sdk';
|
|
337
341
|
|
|
338
342
|
circuitActionBinding('giwa_attestation'); // 'optional'
|
|
339
|
-
circuitActionBinding('coinbase_attestation'); // '
|
|
343
|
+
circuitActionBinding('coinbase_attestation'); // 'optional'
|
|
344
|
+
circuitActionBinding('coinbase_country_attestation'); // 'none'
|
|
340
345
|
```
|
|
341
346
|
|
|
342
347
|
Sending an action to a circuit that cannot prove one is an error rather than a
|
|
@@ -615,7 +620,7 @@ When you are done, `sdk.disconnect()` closes any open socket.
|
|
|
615
620
|
status: 'completed',
|
|
616
621
|
circuit: 'coinbase_attestation',
|
|
617
622
|
proof: '0x1f8b0a…', // proof bytes, opaque
|
|
618
|
-
publicInputs: ['0x00…2f', '0x00…a1', …], // ordered —
|
|
623
|
+
publicInputs: ['0x00…2f', '0x00…a1', …], // ordered — 193 entries for this circuit
|
|
619
624
|
verifierAddress: '0x…', // the verifier the app reports (checked, not trusted)
|
|
620
625
|
chainId: …, // the network the app reports (checked, not trusted)
|
|
621
626
|
deepLink: 'zkproofport://proof-request?data=…',
|
|
@@ -729,7 +734,7 @@ For OIDC domain proofs the SDK first checks what the proof says about the sign-i
|
|
|
729
734
|
|
|
730
735
|
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.
|
|
731
736
|
|
|
732
|
-
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.
|
|
737
|
+
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 }`. A Coinbase KYC proof also names the time its attestation was confirmed unrevoked; it must be within the last 15 minutes (and not more than 5 minutes ahead of your clock), so verify a Coinbase KYC proof when you receive it rather than re-verifying a stored one later. This too runs in every verify method.
|
|
733
738
|
|
|
734
739
|
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 1 hour after they were last listed.
|
|
735
740
|
|
|
@@ -885,7 +890,7 @@ const domain = extractDomainFromPublicInputs(publicInputs, 'oidc_domain_attestat
|
|
|
885
890
|
// domain: 'example.com', or null if the circuit doesn't match or inputs are insufficient
|
|
886
891
|
```
|
|
887
892
|
|
|
888
|
-
|
|
893
|
+
The circuit argument is required: the layout differs per circuit, and an omitted or unknown circuit id throws an error naming the known ones.
|
|
889
894
|
|
|
890
895
|
## Complete Example
|
|
891
896
|
|
|
@@ -1055,7 +1060,7 @@ import {
|
|
|
1055
1060
|
Two rules hold for every table below:
|
|
1056
1061
|
|
|
1057
1062
|
- **Every number is an index into `publicInputs`, and `_END` is inclusive.** Slice with `slice(START, END + 1)`.
|
|
1058
|
-
- **One entry is one field element, not one 32-byte value.** A `bytes32` such as a scope or a nullifier is spread over 32 consecutive entries, each holding a single byte in its low byte: `publicInputs[
|
|
1063
|
+
- **One entry is one field element, not one 32-byte value.** A `bytes32` such as a scope or a nullifier is spread over 32 consecutive entries, each holding a single byte in its low byte: `publicInputs[128] === '0x00…2f'` is the byte `0x2f`. Rebuild it by concatenating those 32 low bytes. The one exception is the OIDC RSA modulus, whose 18 entries each hold a 128-bit limb.
|
|
1059
1064
|
|
|
1060
1065
|
```typescript
|
|
1061
1066
|
const L = COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT;
|
|
@@ -1067,14 +1072,17 @@ const toBytes32 = (fields: string[]): string =>
|
|
|
1067
1072
|
const signalHash = toBytes32(publicInputs.slice(L.SIGNAL_HASH_START, L.SIGNAL_HASH_END + 1));
|
|
1068
1073
|
```
|
|
1069
1074
|
|
|
1070
|
-
### `coinbase_attestation` —
|
|
1075
|
+
### `coinbase_attestation` — 193 entries
|
|
1071
1076
|
|
|
1072
1077
|
| Index | Constants | Circuit field | What it is |
|
|
1073
1078
|
|-------|-----------|---------------|------------|
|
|
1074
|
-
| 0–31 | `SIGNAL_HASH_START` / `_END` | `signal_hash` | `bytes32` anti-replay challenge for the request |
|
|
1075
|
-
| 32–63 | `
|
|
1076
|
-
| 64–95 | `
|
|
1077
|
-
| 96–127 | `
|
|
1079
|
+
| 0–31 | `SIGNAL_HASH_START` / `_END` | `signal_hash` | `bytes32` anti-replay challenge for the request; zero when the wallet signed an EIP-712 action |
|
|
1080
|
+
| 32–63 | `DOMAIN_SEPARATOR_START` / `_END` | `domain_separator` | EIP-712 domain separator of the signed action; zero without one |
|
|
1081
|
+
| 64–95 | `ACTION_HASH_START` / `_END` | `action_hash` | EIP-712 struct hash of the signed action; zero without one |
|
|
1082
|
+
| 96–127 | `MERKLE_ROOT_START` / `_END` | `signer_list_merkle_root` | `bytes32` root of the Coinbase attestation-signer list the proof was checked against |
|
|
1083
|
+
| 128–159 | `SCOPE_START` / `_END` | `scope` | `bytes32` — `keccak256` of your scope string. Compare it (Step 8) |
|
|
1084
|
+
| 160–191 | `NULLIFIER_START` / `_END` | `nullifier` | `bytes32`, unique per wallet and scope |
|
|
1085
|
+
| 192 | `ATTESTED_AT` | `attested_at` | Unix seconds at which the attestation was confirmed unrevoked; checked against your clock by every verify method |
|
|
1078
1086
|
|
|
1079
1087
|
### `coinbase_country_attestation` — 150 entries
|
|
1080
1088
|
|
package/dist/constants.d.ts
CHANGED
|
@@ -83,7 +83,7 @@ export declare const DEEP_LINK_HOSTS: {
|
|
|
83
83
|
* ```typescript
|
|
84
84
|
* const metadata = CIRCUIT_METADATA['coinbase_attestation'];
|
|
85
85
|
* console.log(metadata.name); // "Coinbase KYC"
|
|
86
|
-
* console.log(metadata.publicInputsCount); //
|
|
86
|
+
* console.log(metadata.publicInputsCount); // 193
|
|
87
87
|
* ```
|
|
88
88
|
*/
|
|
89
89
|
export declare const CIRCUIT_METADATA: Record<CircuitType, {
|
package/dist/index.esm.js
CHANGED
|
@@ -90,19 +90,20 @@ const DEEP_LINK_HOSTS = {
|
|
|
90
90
|
* ```typescript
|
|
91
91
|
* const metadata = CIRCUIT_METADATA['coinbase_attestation'];
|
|
92
92
|
* console.log(metadata.name); // "Coinbase KYC"
|
|
93
|
-
* console.log(metadata.publicInputsCount); //
|
|
93
|
+
* console.log(metadata.publicInputsCount); // 193
|
|
94
94
|
* ```
|
|
95
95
|
*/
|
|
96
96
|
const CIRCUIT_METADATA = {
|
|
97
97
|
coinbase_attestation: {
|
|
98
98
|
name: 'Coinbase KYC',
|
|
99
|
-
description: 'Prove Coinbase identity verification',
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
|
|
105
|
-
|
|
99
|
+
description: 'Prove Coinbase identity verification, optionally authorizing one EIP-712 action',
|
|
100
|
+
// Coinbase KYC v2 (coinbase-attestation-v2/src/main.nr): GIWA's six
|
|
101
|
+
// `pub [u8; 32]` in its order, then `attested_at: pub u64` = 193 fields.
|
|
102
|
+
// signal_hash 0-31, domain_separator 32-63, action_hash 64-95,
|
|
103
|
+
// signer_list_merkle_root 96-127, scope 128-159, nullifier 160-191,
|
|
104
|
+
// attested_at 192. v1's 128 fields are refused on every verify path.
|
|
105
|
+
publicInputsCount: 193,
|
|
106
|
+
publicInputNames: ['signal_hash', 'domain_separator', 'action_hash', 'signer_list_merkle_root', 'scope', 'nullifier', 'attested_at'],
|
|
106
107
|
},
|
|
107
108
|
coinbase_country_attestation: {
|
|
108
109
|
name: 'Coinbase Country',
|