# income-over-kgs-v1

observedMonthlyIncome >= minIncome, both in minor units (amount x 100) of KGS; the income is the average monthly inflow observed on a connected account, committed under this circuit id only when the attestation's currency is KGS. Proven without revealing the attribute, against a commitment
`Poseidon(value, salt)` the issuer recorded in SuperWalletTrustRegistry under this circuit's id,
and bound to the verifier's nonce.

**This circuit has no files of its own.** It is [income-over-v1](../income-over-v1/) - the same threshold
circuit, proving key, verification key and verifier contract - registered under another name. The
key ceremony, the transcript and every file are in [../income-over-v1/](../income-over-v1/).

| | |
|---|---|
| circuitId | `0x0976fff0c0ec198d9a095ae74d8f79c3cbbcccb8117c677911d6d4f362f2e0e7` = keccak256("income-over-kgs-v1") |
| Key and verifier of | `income-over-v1` (circuitId `0x2f302f5e16d464bd252d5951bafcbed0cbc398cfe6c4ad46d04469a1eead4323`) |
| vkHash | `0x543b70decfe8abad980bb3167a556aedb741c9d36946993c55dca2014a22a5ac` (identical to income-over-v1's) |
| Verifier contract (Xphere 20250217) | see ../income-over-v1/ (income-over-v1's; runtime keccak256 `0xf860b9e8a04ef653d48ba078db430621643b027839361eef754fb6c1aca59103`) |
| ceremonyContributions | 1 (income-over-v1's ceremony) |
| Committed attribute | `observedMonthlyIncome`: the average monthly inflow observed on a connected bank account (evidence L3), in minor units of KGS = amount x 100, issued only when the `bank_cashflow` requirement is met and the bank reports the currency as KGS |
| Public signals | `commitment`, `threshold`, `nonce` |
| Request (`<sw-verify request>`) | `income>=60000:KGS` -> predicate `{ "circuit": "income-over-kgs-v1", "params": { "minIncome": 60000, "currency": "KGS" } }` |
| Registry | **Not registered as of 2026-09-27**: until `register-circuit income-over-kgs-v1 <income-over-v1 verifier address> 0x543b70decfe8abad980bb3167a556aedb741c9d36946993c55dca2014a22a5ac 1 https://trendy.storydot.kr/sdk/zk/income-over-kgs-v1/` is sent, verifiers refuse this predicate |

## Why a separate name is safe

A proof for `income-over-kgs-v1` and one for any other income circuit (income-over-krw-v1, income-over-lak-v1, income-over-vnd-v1, income-over-thb-v1, income-over-usd-v1) are
checked by the same contract with the same key, and the currency is neither a public input nor
inside the commitment `Poseidon(amount, salt)`. What binds the currency is the circuit id: the
issuer commits an income under `income-over-kgs-v1` only when the attestation's income currency is
KGS. A holder whose income is in another currency (say KRW) has a commitment under that
currency's id only; relabelling the proof as `income-over-kgs-v1` meets
`commitment(credentialId, keccak256("income-over-kgs-v1")) = 0` and is refused (`no_commitment`). A
`currency` written next to the proof in a response is not proven and decides nothing.
`income-over-v1` itself is never registered and nothing is committed under it.

## What a verifier checks

1. The registry maps keccak256("income-over-kgs-v1") to a verifier whose vkHash is the one above; the proof passes
   `verifyProof` there.
2. `publicSignals[0]` equals `commitment(credentialId, keccak256("income-over-kgs-v1"))`, the credential is
   anchored and not revoked, and its issuer is active.
3. The last public signal equals the nonce the verifier issued.
4. `threshold` >= minIncome x 100 (minor units) and < 2^48. The currency is not a public input and not in the commitment: it is bound by the circuit id. The issuer commits an income under `income-over-kgs-v1` only when the attestation's currency is KGS, so `commitment(credentialId, keccak256("income-over-kgs-v1"))` exists only for a KGS income. A holder whose income is in another currency has no commitment here and is refused (`no_commitment`). A `currency` written next to the proof in the response is not proven and does not decide anything.
