@zkproofport-app/sdk 0.5.0-beta.8 → 0.5.0-beta.9

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/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import { countryListError, checkProofIssuer, parseProofForOnChain, verifyProofOnChain, getPinnedVerifier, extractScopeFromPublicInputs, extractNullifierFromPublicInputs, extractDomainFromPublicInputs } from '@zkproofport-app/core';
2
- export { COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT, COINBASE_COUNTRY_PUBLIC_INPUT_COUNT, COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT, OIDC_ALLOWED_AUDIENCES, OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT, OIDC_NONCE_DOMAIN, OIDC_NOW_MAX_AGE_SECONDS, OIDC_NOW_MAX_FUTURE_SECONDS, OIDC_V1_PUBLIC_INPUT_COUNT, OIDC_V2_PUBLIC_INPUT_COUNT, PINNED_VARIANT_VERIFIERS, PINNED_VERIFIERS, checkOidcPolicy, deriveOidcNonceBinding, extractDomainFromPublicInputs, extractNullifierFromPublicInputs, extractScopeFromPublicInputs, getPinnedVariantVerifier, getPinnedVerifier, oidcAudienceHash } from '@zkproofport-app/core';
3
- import { isCircuitId, ALL_CIRCUIT_IDS, circuitActionBinding, resolveSignerVariant, getCircuitPackage, CIRCUIT_NEEDS_WALLET_SIGNATURE } from '@zkproofport-app/core/circuits';
4
- export { ALL_CIRCUIT_IDS, CIRCUIT_ACTION_BINDING, CIRCUIT_IDS, CIRCUIT_PACKAGES, CIRCUIT_SUPPORT_STATUS, CIRCUIT_VK_PATHS, EXPERIMENTAL_CIRCUIT_IDS, PLANNED_CIRCUIT_IDS, SIGNER_VARIANTS, SUPPORTED_CIRCUIT_IDS, circuitActionBinding, evmProofByteLength, getCircuitPackage, getCircuitSupportStatus, isCircuitId, isSignerVariant, isSupportedCircuitId, resolveSignerVariant, signerVariantsOf } from '@zkproofport-app/core/circuits';
2
+ export { COINBASE_ATTESTATION_PUBLIC_INPUT_LAYOUT, COINBASE_COUNTRY_PUBLIC_INPUT_COUNT, COINBASE_COUNTRY_PUBLIC_INPUT_LAYOUT, HUMAN_PASSPORT_SCORE_PUBLIC_INPUT_COUNT, HUMAN_PASSPORT_SCORE_PUBLIC_INPUT_LAYOUT, OIDC_ALLOWED_AUDIENCES, OIDC_DOMAIN_ATTESTATION_PUBLIC_INPUT_LAYOUT, OIDC_NONCE_DOMAIN, OIDC_NOW_MAX_AGE_SECONDS, OIDC_NOW_MAX_FUTURE_SECONDS, OIDC_V1_PUBLIC_INPUT_COUNT, OIDC_V2_PUBLIC_INPUT_COUNT, PINNED_VARIANT_VERIFIERS, PINNED_VERIFIERS, checkOidcPolicy, deriveOidcNonceBinding, extractDomainFromPublicInputs, extractNullifierFromPublicInputs, extractScopeFromPublicInputs, getPinnedVariantVerifier, getPinnedVerifier, oidcAudienceHash } from '@zkproofport-app/core';
3
+ import { isCircuitId, ALL_CIRCUIT_IDS, humanPassportScoreUnits, circuitActionBinding, resolveSignerVariant, getCircuitPackage, CIRCUIT_NEEDS_WALLET_SIGNATURE } from '@zkproofport-app/core/circuits';
4
+ export { ALL_CIRCUIT_IDS, CIRCUIT_ACTION_BINDING, CIRCUIT_IDS, CIRCUIT_PACKAGES, CIRCUIT_SUPPORT_STATUS, CIRCUIT_VK_PATHS, EXPERIMENTAL_CIRCUIT_IDS, HUMAN_PASSPORT_ISSUER, HUMAN_PASSPORT_ISSUER_ROOT, HUMAN_PASSPORT_SCORER_ID, HUMAN_PASSPORT_SCORE_SCHEMA, PLANNED_CIRCUIT_IDS, SIGNER_VARIANTS, SUPPORTED_CIRCUIT_IDS, circuitActionBinding, evmProofByteLength, getCircuitPackage, getCircuitSupportStatus, humanPassportScoreUnits, isCircuitId, isSignerVariant, isSupportedCircuitId, resolveSignerVariant, signerVariantsOf } from '@zkproofport-app/core/circuits';
5
5
  import { validateTypedAction } from '@zkproofport-app/core/typedAction';
6
6
  export { parseTypedAction, validateTypedAction } from '@zkproofport-app/core/typedAction';
7
7
 
@@ -41,6 +41,7 @@ const VERIFICATION_CHAINS = {
41
41
  oidc_domain_attestation: 8453,
42
42
  giwa_attestation: 91342,
43
43
  dojang_playground: 91342,
44
+ human_passport_score: 8453,
44
45
  },
45
46
  staging: {
46
47
  coinbase_attestation: 84532,
@@ -48,6 +49,7 @@ const VERIFICATION_CHAINS = {
48
49
  oidc_domain_attestation: 84532,
49
50
  giwa_attestation: 91342,
50
51
  dojang_playground: 91342,
52
+ human_passport_score: 84532,
51
53
  },
52
54
  local: {
53
55
  coinbase_attestation: 84532,
@@ -55,6 +57,7 @@ const VERIFICATION_CHAINS = {
55
57
  oidc_domain_attestation: 84532,
56
58
  giwa_attestation: 91342,
57
59
  dojang_playground: 91342,
60
+ human_passport_score: 84532,
58
61
  },
59
62
  };
60
63
  /**
@@ -156,6 +159,14 @@ const CIRCUIT_METADATA = {
156
159
  publicInputsCount: 160,
157
160
  publicInputNames: ['signal_hash', 'domain_separator', 'action_hash', 'scope', 'nullifier'],
158
161
  },
162
+ // human-passport-score/src/main.nr: GIWA's six `pub [u8; 32]`, then
163
+ // min_score (u32, score x 10^4), scorer_id and now (u64) = 195 fields.
164
+ human_passport_score: {
165
+ name: 'Human Passport',
166
+ description: 'Prove a Human Passport score at or above a threshold, optionally authorizing one EIP-712 action',
167
+ publicInputsCount: 195,
168
+ publicInputNames: ['signal_hash', 'domain_separator', 'action_hash', 'signer_list_merkle_root', 'scope', 'nullifier', 'min_score', 'scorer_id', 'now'],
169
+ },
159
170
  };
160
171
  /**
161
172
  * Default proof request expiration time in milliseconds.
@@ -652,6 +663,21 @@ function validateProofRequest(request) {
652
663
  return { valid: false, error: 'isIncluded is required and must be a boolean' };
653
664
  }
654
665
  }
666
+ else if (request.circuit === 'human_passport_score') {
667
+ const inputs = request.inputs;
668
+ if (inputs.userAddress && !/^0x[a-fA-F0-9]{40}$/.test(inputs.userAddress)) {
669
+ return { valid: false, error: 'Invalid userAddress format' };
670
+ }
671
+ if (!inputs.scope || typeof inputs.scope !== 'string' || inputs.scope.trim() === '') {
672
+ return { valid: false, error: 'scope is required and must be a non-empty string' };
673
+ }
674
+ try {
675
+ humanPassportScoreUnits(inputs.minScore);
676
+ }
677
+ catch (error) {
678
+ return { valid: false, error: error instanceof Error ? error.message : String(error) };
679
+ }
680
+ }
655
681
  else if (request.circuit === 'oidc_domain_attestation') {
656
682
  const inputs = request.inputs;
657
683
  if (!inputs.domain || typeof inputs.domain !== 'string' || inputs.domain.trim() === '') {
@@ -3940,7 +3966,7 @@ async function verifyProofOffChain(circuit, proof, publicInputs, options = {}) {
3940
3966
  // their trust anchor as a public input the prover chooses. For OIDC that is
3941
3967
  // the RSA key -- see core's oidcProviderKeys. Checked here so a dApp that
3942
3968
  // verifies off-chain gets the same answer as one that verifies on-chain.
3943
- const issuer = await checkProofIssuer(circuit, publicInputs, { request: options.request, countryCondition: options.countryCondition });
3969
+ const issuer = await checkProofIssuer(circuit, publicInputs, { request: options.request, countryCondition: options.countryCondition, minScore: options.minScore });
3944
3970
  if (!issuer.ok) {
3945
3971
  return { valid: false, error: issuer.error };
3946
3972
  }
@@ -4106,6 +4132,12 @@ class ProofportSDK {
4106
4132
  * them. Bounded like {@link relayRequests}.
4107
4133
  */
4108
4134
  this.countryRequests = new Map();
4135
+ /**
4136
+ * requestId -> the score threshold of the Human Passport relay requests this
4137
+ * instance created, so verifyResponse* can hold the proof's min_score to it.
4138
+ * Bounded like {@link relayRequests}.
4139
+ */
4140
+ this.passportRequests = new Map();
4109
4141
  this.signer = null;
4110
4142
  this.socket = null;
4111
4143
  /**
@@ -4298,6 +4330,16 @@ class ProofportSDK {
4298
4330
  switch (builder) {
4299
4331
  case 'country':
4300
4332
  return this.createCoinbaseCountryRequest(inputs, options);
4333
+ case 'passport': {
4334
+ const minScore = inputs.minScore;
4335
+ try {
4336
+ humanPassportScoreUnits(minScore);
4337
+ }
4338
+ catch (error) {
4339
+ throw new Error(`${error instanceof Error ? error.message : String(error)} (circuit: ${circuit})`);
4340
+ }
4341
+ return this.createScopedRequest(circuit, inputs, options);
4342
+ }
4301
4343
  case 'scoped':
4302
4344
  return this.createScopedRequest(circuit, inputs, options);
4303
4345
  }
@@ -4647,6 +4689,7 @@ class ProofportSDK {
4647
4689
  request: options.request,
4648
4690
  signerVariant: options.signerVariant,
4649
4691
  countryCondition: options.countryCondition,
4692
+ minScore: options.minScore,
4650
4693
  });
4651
4694
  }
4652
4695
  /**
@@ -4712,6 +4755,42 @@ class ProofportSDK {
4712
4755
  'isIncluded } } -- the list and direction of the request you created.',
4713
4756
  };
4714
4757
  }
4758
+ /**
4759
+ * The score threshold a `human_passport_score` response must carry: the one
4760
+ * the caller passed, else the relay request this instance created under the
4761
+ * response's requestId, else the deep-link request still pending under it.
4762
+ * `{ error }` when there is none: the proof's threshold is the prover's
4763
+ * choice, so a response this SDK cannot place is refused rather than
4764
+ * accepted for whatever threshold it carries.
4765
+ */
4766
+ passportMinScoreFor(response, explicit) {
4767
+ if (explicit !== undefined)
4768
+ return { minScore: explicit };
4769
+ const remembered = this.passportRequests.get(response.requestId);
4770
+ if (remembered !== undefined)
4771
+ return { minScore: remembered };
4772
+ const pending = this.pendingRequests.get(response.requestId);
4773
+ const inputs = pending?.circuit === 'human_passport_score' ? pending.inputs : undefined;
4774
+ if (inputs && typeof inputs.minScore === 'number')
4775
+ return { minScore: inputs.minScore };
4776
+ return {
4777
+ error: `No Human Passport request ${JSON.stringify(response.requestId)} was created by this SDK instance, so the ` +
4778
+ "proof's score threshold cannot be checked against what was asked. Pass { minScore } -- the threshold of " +
4779
+ 'the request you created.',
4780
+ };
4781
+ }
4782
+ /** @internal Remember a Human Passport relay request's threshold for verifyResponse*. */
4783
+ rememberPassportRequest(requestId, inputs) {
4784
+ const minScore = inputs?.minScore;
4785
+ if (typeof requestId !== 'string' || typeof minScore !== 'number')
4786
+ return;
4787
+ this.passportRequests.delete(requestId);
4788
+ this.passportRequests.set(requestId, minScore);
4789
+ while (this.passportRequests.size > ProofportSDK.MAX_REMEMBERED_RELAY_REQUESTS) {
4790
+ const oldest = this.passportRequests.keys().next().value;
4791
+ this.passportRequests.delete(oldest);
4792
+ }
4793
+ }
4715
4794
  /** @internal Remember a Coinbase Country relay request's list and direction for verifyResponse*. */
4716
4795
  rememberCountryRequest(requestId, inputs) {
4717
4796
  const i = inputs;
@@ -4800,6 +4879,13 @@ class ProofportSDK {
4800
4879
  return { valid: false, error: found.error };
4801
4880
  countryCondition = found.condition;
4802
4881
  }
4882
+ let minScore;
4883
+ if (response.circuit === 'human_passport_score') {
4884
+ const found = this.passportMinScoreFor(response, options.minScore);
4885
+ if ('error' in found)
4886
+ return { valid: false, error: found.error };
4887
+ minScore = found.minScore;
4888
+ }
4803
4889
  const parsedProof = parseProofForOnChain(response.proof, response.publicInputs, response.publicInputs.length);
4804
4890
  // The response's verifierAddress and chainId are a claim to check, never
4805
4891
  // the contract to call: whoever wrote the response would otherwise pick
@@ -4808,7 +4894,7 @@ class ProofportSDK {
4808
4894
  return verifyProofOnChain(response.circuit, parsedProof, providerOrSigner, this.verifierTarget(response.circuit), {
4809
4895
  verifierAddress: response.verifierAddress,
4810
4896
  chainId: response.chainId,
4811
- }, { request, signerVariant: response.signerVariant, countryCondition });
4897
+ }, { request, signerVariant: response.signerVariant, countryCondition, minScore });
4812
4898
  }
4813
4899
  /**
4814
4900
  * Verifies a proof response off-chain, against the circuit's verification key.
@@ -4852,7 +4938,14 @@ class ProofportSDK {
4852
4938
  return { valid: false, error: found.error };
4853
4939
  countryCondition = found.condition;
4854
4940
  }
4855
- return verifyProofOffChain(response.circuit, response.proof, response.publicInputs, { ...options, request, countryCondition, signerVariant: response.signerVariant });
4941
+ let minScore;
4942
+ if (response.circuit === 'human_passport_score') {
4943
+ const found = this.passportMinScoreFor(response, options?.minScore);
4944
+ if ('error' in found)
4945
+ return { valid: false, error: found.error };
4946
+ minScore = found.minScore;
4947
+ }
4948
+ return verifyProofOffChain(response.circuit, response.proof, response.publicInputs, { ...options, request, countryCondition, minScore, signerVariant: response.signerVariant });
4856
4949
  }
4857
4950
  // ============ Utility Methods ============
4858
4951
  /**
@@ -5230,6 +5323,15 @@ class ProofportSDK {
5230
5323
  }
5231
5324
  }
5232
5325
  }
5326
+ // A Human Passport threshold the circuit cannot carry is refused here too.
5327
+ if (circuit === 'human_passport_score') {
5328
+ try {
5329
+ humanPassportScoreUnits(inputs.minScore);
5330
+ }
5331
+ catch (error) {
5332
+ throw new Error(`${error instanceof Error ? error.message : String(error)} (circuit: ${circuit})`);
5333
+ }
5334
+ }
5233
5335
  // A Coinbase Country list the circuit would refuse is refused here, before a
5234
5336
  // challenge is burned, as createProofRequest does.
5235
5337
  if (circuit === 'coinbase_country_attestation') {
@@ -5297,6 +5399,8 @@ class ProofportSDK {
5297
5399
  this.rememberRelayRequest(created.requestId, scope);
5298
5400
  if (circuit === 'coinbase_country_attestation')
5299
5401
  this.rememberCountryRequest(created.requestId, inputs);
5402
+ if (circuit === 'human_passport_score')
5403
+ this.rememberPassportRequest(created.requestId, inputs);
5300
5404
  return created;
5301
5405
  }
5302
5406
  /**
@@ -5593,6 +5697,8 @@ ProofportSDK.REQUEST_BUILDERS = {
5593
5697
  oidc_domain_attestation: 'scoped',
5594
5698
  giwa_attestation: 'scoped',
5595
5699
  dojang_playground: 'scoped',
5700
+ // Scoped, plus the score threshold the proof must carry.
5701
+ human_passport_score: 'passport',
5596
5702
  };
5597
5703
 
5598
5704
  export { DEFAULT_RELAY_WAIT_MS, ProofportSDK, RELAY_TERMINAL_STATUSES, ProofportSDK as default, isTerminalRelayStatus, verifyProofOffChain };