# nationality-not-in-v1

the ISO 3166-1 numeric nationality is not in the list whose sorted-leaf Merkle root is public. Proven without revealing the attribute, against a
commitment `Poseidon(value, salt)` the issuer recorded in SuperWalletTrustRegistry
(`commitment(credentialId, circuitId)`), and bound to the verifier's nonce.

| | |
|---|---|
| circuitId | `0x64edefdd24bd1e1b951b0594a182ba03035df2127c9f409ef6b261c47445f188` = keccak256("nationality-not-in-v1") |
| vkHash | `0xb14820277056692f2b77378ee54363e41795f69eb5793c7cbfdb6ea4d65242d7` |
| ceremonyContributions | 1 (one Super Wallet contribution plus a public Xphere beacon; see TRANSCRIPT.md) |
| Committed attribute | `nationality`: ISO 3166-1 numeric code |
| Public signals | `commitment`, `root`, `nonce` (snarkjs order; the commitment first, the nonce last) |
| Verifier call | `verifyProof(uint256[2],uint256[2][2],uint256[2],uint256[3])` |
| Request (`<sw-verify request>`) | `nationality-not-in:408,364` -> predicate `{ "circuit": "nationality-not-in-v1", "params": { "codes": [408, 364] } }` |
| Registry | `0x852688D815410e3FEa015FD3a07028BF6b981d80` on Xphere (chain id 20250217). **Not registered as of 2026-09-27**: until `register-circuit` is sent, `circuit(0x64edefdd...)` returns the zero address and verifiers refuse this predicate |
| uri | https://trendy.storydot.kr/sdk/zk/nationality-not-in-v1/ |

## What a verifier checks

1. The circuit is registered and its vkHash is the one above; the proof passes `verifyProof` on
   the registered verifier contract (a view `eth_call`).
2. `publicSignals[0]` equals `commitment(credentialId, circuitId)` on the registry, the credential
   is anchored and not revoked, and its issuer is active.
3. The last public signal equals the nonce the verifier issued for this request (a proof made for
   another request fails the pairing check, and is refused before that).
4. The statement inputs are what was asked: `root` equals the sorted-leaf root the verifier rebuilds from its own list (leaves Poseidon of 0, the sorted codes, 65535, padding 65535; depth 8). The list is the verifier's; Super Wallet does not supply one.

`@superwallet/verifier-sdk` `verify(response, { zkRequest })` and `<sw-verify request="nationality-not-in:408,364">`
do all four.

## Files

| File | What it is |
|---|---|
| `nationality-not-in-v1.circom`, `templates/`, `lib/` | The circuit (circom 2.1.9; circomlib 2.0.5 for Poseidon, bitify and comparators) |
| `nationality-not-in-v1.r1cs` | The constraint system (4,635 constraints); needed to check the ceremony |
| `nationality-not-in-v1.wasm` | Witness calculator, for proving |
| `nationality-not-in-v1.zkey` | The final proving key; contains the whole contribution chain |
| `verification_key.json` | The Groth16 verification key |
| `Verifier.sol`, `solc-input.json` | The snarkjs Solidity verifier and the exact compiler input (solc 0.8.24, optimizer 200 runs, evmVersion paris) |
| `circuit.json` | Machine-readable manifest and ceremony record |
| `TRANSCRIPT.md` | The ceremony, step by step, with every hash |

## Reproduce

```sh
npm install circomlib@2.0.5 circom2@0.2.23
npx circom2 nationality-not-in-v1.circom --r1cs --wasm --O2 -l . -l node_modules
sha256sum nationality-not-in-v1.r1cs      # 1fd150a8532dcc65139a4c1daadd148046129d9e14076c61e7dac329784c143f

npx --yes solc@0.8.24 --standard-json < solc-input.json > solc-output.json
# keccak256(runtime bytecode of contracts/nationality-not-in-v1.Verifier.sol:Groth16Verifier) = 0xd5c4a13d1347ce8f953b207c6b07906da5babaf85900b0fd7b3b85a13615eccb
# (../tier-threshold-v1/check-bytecode.cjs compares it with the deployed contract)
```

vkHash: RFC 8785 canonical JSON of `verification_key.json` (keys sorted, no whitespace), then
keccak256: `node scripts/governance.cjs vk-hash verification_key.json` in chain/trust-registry, or
`vkHash()` in @superwallet/zk-kit.
