@zkproofport-app/sdk 0.5.0-beta.4 → 0.5.0-beta.6
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 +59 -28
- package/dist/ProofportSDK.d.ts +24 -1
- package/dist/constants.d.ts +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.esm.js +109 -23
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +111 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +109 -23
- package/dist/index.mjs.map +1 -1
- package/dist/offChainVerifier.d.ts +8 -1
- package/dist/types.d.ts +7 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -92,27 +92,32 @@ const DEEP_LINK_HOSTS = {
|
|
|
92
92
|
* ```typescript
|
|
93
93
|
* const metadata = CIRCUIT_METADATA['coinbase_attestation'];
|
|
94
94
|
* console.log(metadata.name); // "Coinbase KYC"
|
|
95
|
-
* console.log(metadata.publicInputsCount); //
|
|
95
|
+
* console.log(metadata.publicInputsCount); // 193
|
|
96
96
|
* ```
|
|
97
97
|
*/
|
|
98
98
|
const CIRCUIT_METADATA = {
|
|
99
99
|
coinbase_attestation: {
|
|
100
100
|
name: 'Coinbase KYC',
|
|
101
|
-
description: 'Prove Coinbase identity verification',
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
|
|
107
|
-
|
|
101
|
+
description: 'Prove Coinbase identity verification, optionally authorizing one EIP-712 action',
|
|
102
|
+
// Coinbase KYC v2 (coinbase-attestation-v2/src/main.nr): GIWA's six
|
|
103
|
+
// `pub [u8; 32]` in its order, then `attested_at: pub u64` = 193 fields.
|
|
104
|
+
// signal_hash 0-31, domain_separator 32-63, action_hash 64-95,
|
|
105
|
+
// signer_list_merkle_root 96-127, scope 128-159, nullifier 160-191,
|
|
106
|
+
// attested_at 192. v1's 128 fields are refused on every verify path.
|
|
107
|
+
publicInputsCount: 193,
|
|
108
|
+
publicInputNames: ['signal_hash', 'domain_separator', 'action_hash', 'signer_list_merkle_root', 'scope', 'nullifier', 'attested_at'],
|
|
108
109
|
},
|
|
109
110
|
coinbase_country_attestation: {
|
|
110
111
|
name: 'Coinbase Country',
|
|
111
|
-
description: 'Prove Coinbase country verification',
|
|
112
|
-
//
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
|
|
112
|
+
description: 'Prove Coinbase country verification, optionally authorizing one EIP-712 action',
|
|
113
|
+
// Coinbase Country v2 (coinbase-country-attestation-v2/src/main.nr):
|
|
114
|
+
// signal_hash 0-31, domain_separator 32-63, action_hash 64-95,
|
|
115
|
+
// signer_list_merkle_root 96-127, country_list 128-147 (10 x 2 bytes),
|
|
116
|
+
// country_list_length 148, is_included 149, scope 150-181,
|
|
117
|
+
// nullifier 182-213, attested_at 214 = 215 fields. v1's 150 fields are
|
|
118
|
+
// refused on every verify path.
|
|
119
|
+
publicInputsCount: 215,
|
|
120
|
+
publicInputNames: ['signal_hash', 'domain_separator', 'action_hash', 'signer_list_merkle_root', 'country_list', 'country_list_length', 'is_included', 'scope', 'nullifier', 'attested_at'],
|
|
116
121
|
},
|
|
117
122
|
oidc_domain_attestation: {
|
|
118
123
|
name: 'OIDC Domain',
|
|
@@ -641,11 +646,9 @@ function validateProofRequest(request) {
|
|
|
641
646
|
if (inputs.userAddress && !/^0x[a-fA-F0-9]{40}$/.test(inputs.userAddress)) {
|
|
642
647
|
return { valid: false, error: 'Invalid userAddress format' };
|
|
643
648
|
}
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
if (!inputs.countryList.every(c => typeof c === 'string')) {
|
|
648
|
-
return { valid: false, error: 'countryList must contain only strings' };
|
|
649
|
+
const listError = core.countryListError(inputs.countryList);
|
|
650
|
+
if (listError) {
|
|
651
|
+
return { valid: false, error: listError };
|
|
649
652
|
}
|
|
650
653
|
if (typeof inputs.isIncluded !== 'boolean') {
|
|
651
654
|
return { valid: false, error: 'isIncluded is required and must be a boolean' };
|
|
@@ -1072,7 +1075,7 @@ async function verifyProofOffChain(circuit, proof, publicInputs, options = {}) {
|
|
|
1072
1075
|
// their trust anchor as a public input the prover chooses. For OIDC that is
|
|
1073
1076
|
// the RSA key -- see core's oidcProviderKeys. Checked here so a dApp that
|
|
1074
1077
|
// verifies off-chain gets the same answer as one that verifies on-chain.
|
|
1075
|
-
const issuer = await core.checkProofIssuer(circuit, publicInputs, { request: options.request });
|
|
1078
|
+
const issuer = await core.checkProofIssuer(circuit, publicInputs, { request: options.request, countryCondition: options.countryCondition });
|
|
1076
1079
|
if (!issuer.ok) {
|
|
1077
1080
|
return { valid: false, error: issuer.error };
|
|
1078
1081
|
}
|
|
@@ -1232,6 +1235,12 @@ class ProofportSDK {
|
|
|
1232
1235
|
* {@link ProofportSDK.MAX_REMEMBERED_RELAY_REQUESTS}.
|
|
1233
1236
|
*/
|
|
1234
1237
|
this.relayRequests = new Map();
|
|
1238
|
+
/**
|
|
1239
|
+
* requestId -> the country list and direction of the Coinbase Country relay
|
|
1240
|
+
* requests this instance created, so verifyResponse* can hold the proof to
|
|
1241
|
+
* them. Bounded like {@link relayRequests}.
|
|
1242
|
+
*/
|
|
1243
|
+
this.countryRequests = new Map();
|
|
1235
1244
|
this.signer = null;
|
|
1236
1245
|
this.socket = null;
|
|
1237
1246
|
/**
|
|
@@ -1363,6 +1372,15 @@ class ProofportSDK {
|
|
|
1363
1372
|
if (typeof inputs.isIncluded !== 'boolean') {
|
|
1364
1373
|
throw new Error('isIncluded is required for coinbase_country_attestation circuit');
|
|
1365
1374
|
}
|
|
1375
|
+
const listError = core.countryListError(inputs.countryList);
|
|
1376
|
+
if (listError)
|
|
1377
|
+
throw new Error(`${listError} (circuit: coinbase_country_attestation)`);
|
|
1378
|
+
// Coinbase Country v2 binds an action or none, like Coinbase KYC v2.
|
|
1379
|
+
if (inputs.action !== undefined) {
|
|
1380
|
+
const actionError = typedAction.validateTypedAction(inputs.action);
|
|
1381
|
+
if (actionError)
|
|
1382
|
+
throw new Error(`${actionError} (circuit: coinbase_country_attestation)`);
|
|
1383
|
+
}
|
|
1366
1384
|
const request = {
|
|
1367
1385
|
requestId: generateRequestId(),
|
|
1368
1386
|
circuit: 'coinbase_country_attestation',
|
|
@@ -1763,6 +1781,7 @@ class ProofportSDK {
|
|
|
1763
1781
|
return core.verifyProofOnChain(circuit, parsedProof, providerOrSigner, this.verifierTarget(circuit), undefined, {
|
|
1764
1782
|
request: options.request,
|
|
1765
1783
|
signerVariant: options.signerVariant,
|
|
1784
|
+
countryCondition: options.countryCondition,
|
|
1766
1785
|
});
|
|
1767
1786
|
}
|
|
1768
1787
|
/**
|
|
@@ -1803,6 +1822,43 @@ class ProofportSDK {
|
|
|
1803
1822
|
this.relayRequests.delete(oldest);
|
|
1804
1823
|
}
|
|
1805
1824
|
}
|
|
1825
|
+
/**
|
|
1826
|
+
* The country list and direction a `coinbase_country_attestation` response
|
|
1827
|
+
* must have been proved against: the one the caller passed, else the relay
|
|
1828
|
+
* request this instance created under the response's requestId, else the
|
|
1829
|
+
* deep-link request still pending under it. `{ error }` when there is none:
|
|
1830
|
+
* the proof's list is the prover's choice, so a response this SDK cannot
|
|
1831
|
+
* place is refused rather than accepted for whatever list it carries.
|
|
1832
|
+
*/
|
|
1833
|
+
countryConditionFor(response, explicit) {
|
|
1834
|
+
if (explicit !== undefined)
|
|
1835
|
+
return { condition: explicit };
|
|
1836
|
+
const remembered = this.countryRequests.get(response.requestId);
|
|
1837
|
+
if (remembered)
|
|
1838
|
+
return { condition: remembered };
|
|
1839
|
+
const pending = this.pendingRequests.get(response.requestId);
|
|
1840
|
+
const inputs = pending?.circuit === 'coinbase_country_attestation' ? pending.inputs : undefined;
|
|
1841
|
+
if (inputs && Array.isArray(inputs.countryList) && typeof inputs.isIncluded === 'boolean') {
|
|
1842
|
+
return { condition: { countryList: [...inputs.countryList], isIncluded: inputs.isIncluded } };
|
|
1843
|
+
}
|
|
1844
|
+
return {
|
|
1845
|
+
error: `No Coinbase Country request ${JSON.stringify(response.requestId)} was created by this SDK instance, so the ` +
|
|
1846
|
+
"proof's country list cannot be checked against what was asked. Pass { countryCondition: { countryList, " +
|
|
1847
|
+
'isIncluded } } -- the list and direction of the request you created.',
|
|
1848
|
+
};
|
|
1849
|
+
}
|
|
1850
|
+
/** @internal Remember a Coinbase Country relay request's list and direction for verifyResponse*. */
|
|
1851
|
+
rememberCountryRequest(requestId, inputs) {
|
|
1852
|
+
const i = inputs;
|
|
1853
|
+
if (typeof requestId !== 'string' || !i || !Array.isArray(i.countryList) || typeof i.isIncluded !== 'boolean')
|
|
1854
|
+
return;
|
|
1855
|
+
this.countryRequests.delete(requestId);
|
|
1856
|
+
this.countryRequests.set(requestId, { countryList: [...i.countryList], isIncluded: i.isIncluded });
|
|
1857
|
+
while (this.countryRequests.size > ProofportSDK.MAX_REMEMBERED_RELAY_REQUESTS) {
|
|
1858
|
+
const oldest = this.countryRequests.keys().next().value;
|
|
1859
|
+
this.countryRequests.delete(oldest);
|
|
1860
|
+
}
|
|
1861
|
+
}
|
|
1806
1862
|
/**
|
|
1807
1863
|
* The verifier for a circuit: the one the dApp configured, otherwise the
|
|
1808
1864
|
* pinned deployment on the chain this SDK's environment verifies that
|
|
@@ -1831,6 +1887,10 @@ class ProofportSDK {
|
|
|
1831
1887
|
* @param options.request - For `oidc_domain_attestation`: the `{ scope, requestId }`
|
|
1832
1888
|
* the response answers. Not needed for a relay request this SDK instance
|
|
1833
1889
|
* created; an OIDC response this instance cannot place is refused without it.
|
|
1890
|
+
* @param options.countryCondition - For `coinbase_country_attestation`: the
|
|
1891
|
+
* `{ countryList, isIncluded }` the request asked for. Not needed for a
|
|
1892
|
+
* request this SDK instance created (relay or deep link); a Country response
|
|
1893
|
+
* this instance cannot place is refused without it.
|
|
1834
1894
|
*
|
|
1835
1895
|
* @returns Promise resolving to verification result with valid boolean and optional error message
|
|
1836
1896
|
*
|
|
@@ -1868,6 +1928,13 @@ class ProofportSDK {
|
|
|
1868
1928
|
return { valid: false, error: found.error };
|
|
1869
1929
|
request = found.request;
|
|
1870
1930
|
}
|
|
1931
|
+
let countryCondition;
|
|
1932
|
+
if (response.circuit === 'coinbase_country_attestation') {
|
|
1933
|
+
const found = this.countryConditionFor(response, options.countryCondition);
|
|
1934
|
+
if ('error' in found)
|
|
1935
|
+
return { valid: false, error: found.error };
|
|
1936
|
+
countryCondition = found.condition;
|
|
1937
|
+
}
|
|
1871
1938
|
const parsedProof = core.parseProofForOnChain(response.proof, response.publicInputs, response.publicInputs.length);
|
|
1872
1939
|
// The response's verifierAddress and chainId are a claim to check, never
|
|
1873
1940
|
// the contract to call: whoever wrote the response would otherwise pick
|
|
@@ -1876,7 +1943,7 @@ class ProofportSDK {
|
|
|
1876
1943
|
return core.verifyProofOnChain(response.circuit, parsedProof, providerOrSigner, this.verifierTarget(response.circuit), {
|
|
1877
1944
|
verifierAddress: response.verifierAddress,
|
|
1878
1945
|
chainId: response.chainId,
|
|
1879
|
-
}, { request, signerVariant: response.signerVariant });
|
|
1946
|
+
}, { request, signerVariant: response.signerVariant, countryCondition });
|
|
1880
1947
|
}
|
|
1881
1948
|
/**
|
|
1882
1949
|
* Verifies a proof response off-chain, against the circuit's verification key.
|
|
@@ -1913,7 +1980,14 @@ class ProofportSDK {
|
|
|
1913
1980
|
return { valid: false, error: found.error };
|
|
1914
1981
|
request = found.request;
|
|
1915
1982
|
}
|
|
1916
|
-
|
|
1983
|
+
let countryCondition;
|
|
1984
|
+
if (response.circuit === 'coinbase_country_attestation') {
|
|
1985
|
+
const found = this.countryConditionFor(response, options?.countryCondition);
|
|
1986
|
+
if ('error' in found)
|
|
1987
|
+
return { valid: false, error: found.error };
|
|
1988
|
+
countryCondition = found.condition;
|
|
1989
|
+
}
|
|
1990
|
+
return verifyProofOffChain(response.circuit, response.proof, response.publicInputs, { ...options, request, countryCondition, signerVariant: response.signerVariant });
|
|
1917
1991
|
}
|
|
1918
1992
|
// ============ Utility Methods ============
|
|
1919
1993
|
/**
|
|
@@ -2291,6 +2365,16 @@ class ProofportSDK {
|
|
|
2291
2365
|
}
|
|
2292
2366
|
}
|
|
2293
2367
|
}
|
|
2368
|
+
// A Coinbase Country list the circuit would refuse is refused here, before a
|
|
2369
|
+
// challenge is burned, as createProofRequest does.
|
|
2370
|
+
if (circuit === 'coinbase_country_attestation') {
|
|
2371
|
+
const c = inputs;
|
|
2372
|
+
const listError = core.countryListError(c.countryList);
|
|
2373
|
+
if (listError)
|
|
2374
|
+
throw new Error(`${listError} (circuit: ${circuit})`);
|
|
2375
|
+
if (typeof c.isIncluded !== 'boolean')
|
|
2376
|
+
throw new Error('isIncluded is required for coinbase_country_attestation circuit');
|
|
2377
|
+
}
|
|
2294
2378
|
// Return target: validated before we burn a challenge, so a typo surfaces
|
|
2295
2379
|
// as a local error instead of a relay 400 on the second round trip.
|
|
2296
2380
|
if (options.returnScheme !== undefined) {
|
|
@@ -2346,6 +2430,8 @@ class ProofportSDK {
|
|
|
2346
2430
|
}
|
|
2347
2431
|
const created = await response.json();
|
|
2348
2432
|
this.rememberRelayRequest(created.requestId, scope);
|
|
2433
|
+
if (circuit === 'coinbase_country_attestation')
|
|
2434
|
+
this.rememberCountryRequest(created.requestId, inputs);
|
|
2349
2435
|
return created;
|
|
2350
2436
|
}
|
|
2351
2437
|
/**
|
|
@@ -2648,6 +2734,10 @@ Object.defineProperty(exports, "COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT", {
|
|
|
2648
2734
|
enumerable: true,
|
|
2649
2735
|
get: function () { return core.COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT; }
|
|
2650
2736
|
});
|
|
2737
|
+
Object.defineProperty(exports, "COINBASE_COUNTRY_PUBLIC_INPUT_COUNT", {
|
|
2738
|
+
enumerable: true,
|
|
2739
|
+
get: function () { return core.COINBASE_COUNTRY_PUBLIC_INPUT_COUNT; }
|
|
2740
|
+
});
|
|
2651
2741
|
Object.defineProperty(exports, "COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT", {
|
|
2652
2742
|
enumerable: true,
|
|
2653
2743
|
get: function () { return core.COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT; }
|