@zkproofport-app/sdk 0.2.1 → 0.2.3
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 +87 -25
- package/dist/ProofportSDK.d.ts +23 -0
- package/dist/constants.d.ts +32 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.esm.js +220 -40
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +224 -39
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +220 -40
- package/dist/index.mjs.map +1 -1
- package/dist/types.d.ts +18 -2
- package/dist/verifier.d.ts +19 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -72,6 +72,12 @@ const CIRCUIT_METADATA = {
|
|
|
72
72
|
publicInputsCount: 14,
|
|
73
73
|
publicInputNames: ['signal_hash', 'signer_list_merkle_root', 'country_list', 'country_list_length', 'is_included'],
|
|
74
74
|
},
|
|
75
|
+
oidc_domain_attestation: {
|
|
76
|
+
name: 'OIDC Domain',
|
|
77
|
+
description: 'Prove email domain affiliation via OIDC JWT',
|
|
78
|
+
publicInputsCount: 420,
|
|
79
|
+
publicInputNames: ['pubkey_modulus_limbs', 'domain', 'scope', 'nullifier'],
|
|
80
|
+
},
|
|
75
81
|
};
|
|
76
82
|
/**
|
|
77
83
|
* Standard verifier contract ABI shared across all Barretenberg-generated verifiers.
|
|
@@ -140,6 +146,97 @@ const DEFAULT_REQUEST_EXPIRY_MS = 10 * 60 * 1000;
|
|
|
140
146
|
* ```
|
|
141
147
|
*/
|
|
142
148
|
const MAX_QR_DATA_SIZE = 2953; // Version 40 with L error correction
|
|
149
|
+
/**
|
|
150
|
+
* Coinbase Attestation circuit public input layout (byte offsets).
|
|
151
|
+
* Defines the byte positions of each field in the flattened public inputs array.
|
|
152
|
+
*
|
|
153
|
+
* Public inputs are packed as bytes32 values:
|
|
154
|
+
* - signal_hash: bytes 0-31
|
|
155
|
+
* - merkle_root: bytes 32-63
|
|
156
|
+
* - scope: bytes 64-95
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* ```typescript
|
|
160
|
+
* const publicInputs = response.publicInputs;
|
|
161
|
+
* const signalHash = publicInputs.slice(
|
|
162
|
+
* COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT.SIGNAL_HASH_START,
|
|
163
|
+
* COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT.SIGNAL_HASH_END + 1
|
|
164
|
+
* );
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
const COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT = {
|
|
168
|
+
SIGNAL_HASH_START: 0,
|
|
169
|
+
SIGNAL_HASH_END: 31,
|
|
170
|
+
MERKLE_ROOT_START: 32,
|
|
171
|
+
MERKLE_ROOT_END: 63,
|
|
172
|
+
SCOPE_START: 64,
|
|
173
|
+
SCOPE_END: 95,
|
|
174
|
+
NULLIFIER_START: 96,
|
|
175
|
+
NULLIFIER_END: 127,
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Coinbase Country Attestation circuit public input layout (byte offsets).
|
|
179
|
+
* Defines the byte positions of each field in the flattened public inputs array.
|
|
180
|
+
*
|
|
181
|
+
* Public inputs are packed as bytes32 values:
|
|
182
|
+
* - signal_hash: bytes 0-31
|
|
183
|
+
* - merkle_root: bytes 32-63
|
|
184
|
+
* - country_list: bytes 64-83 (20 bytes for 10 countries)
|
|
185
|
+
* - country_list_length: byte 84
|
|
186
|
+
* - is_included: byte 85
|
|
187
|
+
* - scope: bytes 86-117
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```typescript
|
|
191
|
+
* const publicInputs = response.publicInputs;
|
|
192
|
+
* const countryList = publicInputs.slice(
|
|
193
|
+
* COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT.COUNTRY_LIST_START,
|
|
194
|
+
* COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT.COUNTRY_LIST_END + 1
|
|
195
|
+
* );
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
const COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT = {
|
|
199
|
+
SIGNAL_HASH_START: 0,
|
|
200
|
+
SIGNAL_HASH_END: 31,
|
|
201
|
+
MERKLE_ROOT_START: 32,
|
|
202
|
+
MERKLE_ROOT_END: 63,
|
|
203
|
+
COUNTRY_LIST_START: 64,
|
|
204
|
+
COUNTRY_LIST_END: 83,
|
|
205
|
+
COUNTRY_LIST_LENGTH: 84,
|
|
206
|
+
IS_INCLUDED: 85,
|
|
207
|
+
SCOPE_START: 86,
|
|
208
|
+
SCOPE_END: 117,
|
|
209
|
+
NULLIFIER_START: 118,
|
|
210
|
+
NULLIFIER_END: 149,
|
|
211
|
+
};
|
|
212
|
+
/**
|
|
213
|
+
* OIDC Domain Attestation circuit public input layout (byte offsets).
|
|
214
|
+
* Defines the byte positions of each field in the flattened public inputs array.
|
|
215
|
+
*
|
|
216
|
+
* Public inputs are packed as individual field elements (one byte per element):
|
|
217
|
+
* - pubkey_modulus_limbs: 18 x u128 = 18 x 16 bytes = 288 bytes → fields 0–287
|
|
218
|
+
* - domain (BoundedVec<u8, 64>): 4-byte length (u32) + 64-byte storage = 68 fields → fields 288–355
|
|
219
|
+
* - scope: 32 bytes → fields 356–387
|
|
220
|
+
* - nullifier: 32 bytes → fields 388–419
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```typescript
|
|
224
|
+
* const scope = publicInputs.slice(
|
|
225
|
+
* OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT.SCOPE_START,
|
|
226
|
+
* OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT.SCOPE_END + 1
|
|
227
|
+
* );
|
|
228
|
+
* ```
|
|
229
|
+
*/
|
|
230
|
+
const OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT = {
|
|
231
|
+
PUBKEY_MODULUS_START: 0,
|
|
232
|
+
PUBKEY_MODULUS_END: 287,
|
|
233
|
+
DOMAIN_START: 288,
|
|
234
|
+
DOMAIN_END: 355,
|
|
235
|
+
SCOPE_START: 356,
|
|
236
|
+
SCOPE_END: 387,
|
|
237
|
+
NULLIFIER_START: 388,
|
|
238
|
+
NULLIFIER_END: 419,
|
|
239
|
+
};
|
|
143
240
|
|
|
144
241
|
/**
|
|
145
242
|
* Deep Link utilities for ZKProofport SDK
|
|
@@ -392,7 +489,7 @@ function validateProofRequest(request) {
|
|
|
392
489
|
if (!request.circuit) {
|
|
393
490
|
return { valid: false, error: 'Missing circuit type' };
|
|
394
491
|
}
|
|
395
|
-
if (!['coinbase_attestation', 'coinbase_country_attestation'].includes(request.circuit)) {
|
|
492
|
+
if (!['coinbase_attestation', 'coinbase_country_attestation', 'oidc_domain_attestation'].includes(request.circuit)) {
|
|
396
493
|
return { valid: false, error: `Invalid circuit type: ${request.circuit}` };
|
|
397
494
|
}
|
|
398
495
|
if (!request.callbackUrl) {
|
|
@@ -422,6 +519,15 @@ function validateProofRequest(request) {
|
|
|
422
519
|
return { valid: false, error: 'isIncluded is required and must be a boolean' };
|
|
423
520
|
}
|
|
424
521
|
}
|
|
522
|
+
else if (request.circuit === 'oidc_domain_attestation') {
|
|
523
|
+
const inputs = request.inputs;
|
|
524
|
+
if (!inputs.domain || typeof inputs.domain !== 'string' || inputs.domain.trim() === '') {
|
|
525
|
+
return { valid: false, error: 'domain is required and must be a non-empty string' };
|
|
526
|
+
}
|
|
527
|
+
if (!inputs.scope || typeof inputs.scope !== 'string' || inputs.scope.trim() === '') {
|
|
528
|
+
return { valid: false, error: 'scope is required and must be a non-empty string' };
|
|
529
|
+
}
|
|
530
|
+
}
|
|
425
531
|
// Check expiry
|
|
426
532
|
if (request.expiresAt && Date.now() > request.expiresAt) {
|
|
427
533
|
return { valid: false, error: 'Request has expired' };
|
|
@@ -856,6 +962,10 @@ function extractScopeFromPublicInputs(publicInputsHex, circuit) {
|
|
|
856
962
|
start = 86;
|
|
857
963
|
end = 117;
|
|
858
964
|
}
|
|
965
|
+
else if (circuit === 'oidc_domain_attestation') {
|
|
966
|
+
start = 356;
|
|
967
|
+
end = 387;
|
|
968
|
+
}
|
|
859
969
|
else {
|
|
860
970
|
start = 64;
|
|
861
971
|
end = 95;
|
|
@@ -865,6 +975,43 @@ function extractScopeFromPublicInputs(publicInputsHex, circuit) {
|
|
|
865
975
|
const scopeFields = publicInputsHex.slice(start, end + 1);
|
|
866
976
|
return reconstructBytes32FromFields(scopeFields);
|
|
867
977
|
}
|
|
978
|
+
/**
|
|
979
|
+
* Extracts the nullifier (bytes32) from public inputs based on circuit type.
|
|
980
|
+
*
|
|
981
|
+
* The nullifier is a unique, deterministic hash derived from the user's attestation
|
|
982
|
+
* and scope. It serves as a privacy-preserving user identifier — the same user
|
|
983
|
+
* with the same scope always produces the same nullifier, enabling duplicate
|
|
984
|
+
* detection without revealing the wallet address.
|
|
985
|
+
*
|
|
986
|
+
* @param publicInputsHex - Array of hex-encoded field elements
|
|
987
|
+
* @param circuit - Circuit type (defaults to coinbase_attestation)
|
|
988
|
+
* @returns Nullifier as hex string (bytes32), or null if publicInputs too short
|
|
989
|
+
*
|
|
990
|
+
* @example
|
|
991
|
+
* ```typescript
|
|
992
|
+
* const nullifier = extractNullifierFromPublicInputs(publicInputs, 'coinbase_attestation');
|
|
993
|
+
* console.log(nullifier); // '0xabc123...'
|
|
994
|
+
* ```
|
|
995
|
+
*/
|
|
996
|
+
function extractNullifierFromPublicInputs(publicInputsHex, circuit) {
|
|
997
|
+
let start, end;
|
|
998
|
+
if (circuit === 'coinbase_country_attestation') {
|
|
999
|
+
start = 118;
|
|
1000
|
+
end = 149;
|
|
1001
|
+
}
|
|
1002
|
+
else if (circuit === 'oidc_domain_attestation') {
|
|
1003
|
+
start = 388;
|
|
1004
|
+
end = 419;
|
|
1005
|
+
}
|
|
1006
|
+
else {
|
|
1007
|
+
start = 96;
|
|
1008
|
+
end = 127;
|
|
1009
|
+
}
|
|
1010
|
+
if (publicInputsHex.length <= end)
|
|
1011
|
+
return null;
|
|
1012
|
+
const nullifierFields = publicInputsHex.slice(start, end + 1);
|
|
1013
|
+
return reconstructBytes32FromFields(nullifierFields);
|
|
1014
|
+
}
|
|
868
1015
|
/** @internal Reconstruct a bytes32 value from 32 individual field elements */
|
|
869
1016
|
function reconstructBytes32FromFields(fields) {
|
|
870
1017
|
if (fields.length !== 32) {
|
|
@@ -1747,53 +1894,26 @@ class ProofportSDK {
|
|
|
1747
1894
|
}
|
|
1748
1895
|
return await response.json();
|
|
1749
1896
|
}
|
|
1750
|
-
/**
|
|
1751
|
-
* Creates a proof request through the relay server.
|
|
1752
|
-
*
|
|
1753
|
-
* This is the recommended way to create proof requests. The relay server:
|
|
1754
|
-
* - Issues a server-side requestId (validated by the mobile app)
|
|
1755
|
-
* - Tracks request status in Redis
|
|
1756
|
-
* - Builds the deep link with relay callback URL
|
|
1757
|
-
* - Stores inputs hash for deep link integrity verification
|
|
1758
|
-
*
|
|
1759
|
-
* @param circuit - Circuit type identifier
|
|
1760
|
-
* @param inputs - Circuit-specific inputs
|
|
1761
|
-
* @param options - Request options (message, dappName, dappIcon, nonce)
|
|
1762
|
-
* @returns Promise resolving to RelayProofRequest with requestId, deepLink, pollUrl
|
|
1763
|
-
* @throws Error if signer not set or relay request fails
|
|
1764
|
-
*
|
|
1765
|
-
* @example
|
|
1766
|
-
* ```typescript
|
|
1767
|
-
* const sdk = ProofportSDK.create();
|
|
1768
|
-
* sdk.setSigner(signer);
|
|
1769
|
-
*
|
|
1770
|
-
* const relay = await sdk.createRelayRequest('coinbase_attestation', {
|
|
1771
|
-
* scope: 'myapp.com'
|
|
1772
|
-
* }, { dappName: 'My DApp' });
|
|
1773
|
-
*
|
|
1774
|
-
* // Generate QR code from relay deep link
|
|
1775
|
-
* const qr = await sdk.generateQRCode(relay.deepLink);
|
|
1776
|
-
*
|
|
1777
|
-
* // Wait for proof (WebSocket primary, polling fallback)
|
|
1778
|
-
* const result = await sdk.waitForProof(relay.requestId);
|
|
1779
|
-
* ```
|
|
1780
|
-
*/
|
|
1781
1897
|
async createRelayRequest(circuit, inputs, options = {}) {
|
|
1782
|
-
if (!this.signer) {
|
|
1783
|
-
throw new Error('Signer not set. Call setSigner() first.');
|
|
1784
|
-
}
|
|
1785
1898
|
if (!this.relayUrl) {
|
|
1786
1899
|
throw new Error('relayUrl is required. Set it in ProofportSDK config.');
|
|
1787
1900
|
}
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1901
|
+
const needsSignature = ProofportSDK.WALLET_SIGNATURE_CIRCUITS.includes(circuit);
|
|
1902
|
+
if (needsSignature && !this.signer) {
|
|
1903
|
+
throw new Error('Signer not set. Call setSigner() first. Wallet signature is required for this circuit.');
|
|
1904
|
+
}
|
|
1905
|
+
// Get challenge + requestId from relay
|
|
1906
|
+
const { requestId, challenge } = await this.getChallenge();
|
|
1791
1907
|
const body = {
|
|
1908
|
+
requestId,
|
|
1792
1909
|
circuitId: circuit,
|
|
1793
1910
|
inputs,
|
|
1794
1911
|
challenge,
|
|
1795
|
-
signature,
|
|
1796
1912
|
};
|
|
1913
|
+
// Sign challenge for circuits that require wallet signature
|
|
1914
|
+
if (needsSignature && this.signer) {
|
|
1915
|
+
body.signature = await this.signer.signMessage(challenge);
|
|
1916
|
+
}
|
|
1797
1917
|
if (options.message)
|
|
1798
1918
|
body.message = options.message;
|
|
1799
1919
|
if (options.dappName)
|
|
@@ -2045,8 +2165,73 @@ class ProofportSDK {
|
|
|
2045
2165
|
extractScope(publicInputs, circuit) {
|
|
2046
2166
|
return extractScopeFromPublicInputs(publicInputs, circuit);
|
|
2047
2167
|
}
|
|
2168
|
+
/**
|
|
2169
|
+
* Extracts the nullifier (bytes32) from proof public inputs.
|
|
2170
|
+
*
|
|
2171
|
+
* The nullifier is a unique, deterministic hash derived from the user's attestation
|
|
2172
|
+
* and scope. It serves as a privacy-preserving user identifier — the same user
|
|
2173
|
+
* with the same scope always produces the same nullifier, enabling duplicate
|
|
2174
|
+
* detection without revealing the wallet address.
|
|
2175
|
+
*
|
|
2176
|
+
* @param publicInputs - Array of hex-encoded field elements from proof result
|
|
2177
|
+
* @param circuit - Circuit type that produced the public inputs
|
|
2178
|
+
* @returns Nullifier as hex string (bytes32), or null if publicInputs too short
|
|
2179
|
+
*
|
|
2180
|
+
* @example
|
|
2181
|
+
* ```typescript
|
|
2182
|
+
* const result = await sdk.waitForProof(relay.requestId);
|
|
2183
|
+
* if (result.status === 'completed') {
|
|
2184
|
+
* const nullifier = sdk.extractNullifier(result.publicInputs, result.circuit);
|
|
2185
|
+
* console.log('Nullifier:', nullifier); // '0xabc123...'
|
|
2186
|
+
* }
|
|
2187
|
+
* ```
|
|
2188
|
+
*/
|
|
2189
|
+
extractNullifier(publicInputs, circuit) {
|
|
2190
|
+
return extractNullifierFromPublicInputs(publicInputs, circuit);
|
|
2191
|
+
}
|
|
2048
2192
|
}
|
|
2193
|
+
/**
|
|
2194
|
+
* Creates a proof request through the relay server.
|
|
2195
|
+
*
|
|
2196
|
+
* This is the recommended way to create proof requests. The relay server:
|
|
2197
|
+
* - Issues a server-side requestId (validated by the mobile app)
|
|
2198
|
+
* - Tracks request status in Redis
|
|
2199
|
+
* - Builds the deep link with relay callback URL
|
|
2200
|
+
* - Stores inputs hash for deep link integrity verification
|
|
2201
|
+
*
|
|
2202
|
+
* @param circuit - Circuit type identifier
|
|
2203
|
+
* @param inputs - Circuit-specific inputs
|
|
2204
|
+
* @param options - Request options (message, dappName, dappIcon, nonce)
|
|
2205
|
+
* @returns Promise resolving to RelayProofRequest with requestId, deepLink, pollUrl
|
|
2206
|
+
* @throws Error if signer not set or relay request fails
|
|
2207
|
+
*
|
|
2208
|
+
* @example
|
|
2209
|
+
* ```typescript
|
|
2210
|
+
* const sdk = ProofportSDK.create();
|
|
2211
|
+
* sdk.setSigner(signer);
|
|
2212
|
+
*
|
|
2213
|
+
* const relay = await sdk.createRelayRequest('coinbase_attestation', {
|
|
2214
|
+
* scope: 'myapp.com'
|
|
2215
|
+
* }, { dappName: 'My DApp' });
|
|
2216
|
+
*
|
|
2217
|
+
* // Generate QR code from relay deep link
|
|
2218
|
+
* const qr = await sdk.generateQRCode(relay.deepLink);
|
|
2219
|
+
*
|
|
2220
|
+
* // Wait for proof (WebSocket primary, polling fallback)
|
|
2221
|
+
* const result = await sdk.waitForProof(relay.requestId);
|
|
2222
|
+
* ```
|
|
2223
|
+
*/
|
|
2224
|
+
// Circuits that require wallet signature (used as circuit input)
|
|
2225
|
+
ProofportSDK.WALLET_SIGNATURE_CIRCUITS = [
|
|
2226
|
+
'coinbase_attestation',
|
|
2227
|
+
'coinbase_country_attestation',
|
|
2228
|
+
];
|
|
2049
2229
|
|
|
2230
|
+
exports.COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT = COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT;
|
|
2231
|
+
exports.COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT = COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT;
|
|
2232
|
+
exports.OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT = OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT;
|
|
2050
2233
|
exports.ProofportSDK = ProofportSDK;
|
|
2051
2234
|
exports.default = ProofportSDK;
|
|
2235
|
+
exports.extractNullifierFromPublicInputs = extractNullifierFromPublicInputs;
|
|
2236
|
+
exports.extractScopeFromPublicInputs = extractScopeFromPublicInputs;
|
|
2052
2237
|
//# sourceMappingURL=index.js.map
|