Open-source Noir reference implementations and EVM verifiers for privacy-preserving credential CIPs.
This repository contains executable circuit code, shared Noir libraries, generated verifier contracts, scripts, and deployment records. Normative statement semantics, trust assumptions, privacy boundaries, and conformance requirements are documented separately in the CIPs repository.
| CIP | Specification | Reference path | Implementation maturity |
|---|---|---|---|
| CIP-1 | Coinbase KYC Attestation | coinbase-attestation |
Reference |
| CIP-2 | Coinbase Country Predicate | coinbase-country-attestation |
Reference |
| CIP-3 | OIDC Domain Attestation | oidc-domain-attestation |
Reference |
| CIP-4 | GIWA Dojang Verified Address Proof | giwa-attestation |
PoC |
| CIP-5 | Korean Mobile ID Selective Disclosure Profile | mdl/kr-* |
Experimental |
coinbase-libs is a shared implementation library. coinbase-kyc is an older reference-only circuit. _archived-poc and zktls are outside the current credential CIP mapping.
Proves control of an address named by a signed Coinbase attestAccount(address) transaction while keeping the address, transaction, and signatures private. The circuit verifies user ownership, EIP-1559 transaction structure and signature, signer membership in a public Merkle root, target calldata, and a signal- and scope-bound nullifier.
Extends the Coinbase transaction profile with a private two-byte country code and a public inclusion or exclusion list of up to ten ISO 3166-1 alpha-2 values.
Verifies a Google Workspace or Microsoft 365 OIDC JWT with RSA-2048 and proves that its private email ends in a public domain. It exposes a provider identifier and an email-derived scope-bound nullifier.
Provider key authorization, JWT freshness, issuer, audience, and nonce policy are not enforced by the current circuit and must be handled by an integration profile.
GIWA Sepolia proof flow using a test MockGiwaAttester, mobile-compatible UltraHonk proof generation, and an EVM verifier. Production Dojang issuer and schema parameters remain unresolved.
Three circuits under mdl/ implement ownership/selective field commitment, year-based age threshold, and region-token predicates. They share keccak256(keccak256(ci) || scope) nullifiers.
The active circuits do not yet cryptographically authenticate claims against a canonical Mobile ID issuer trust anchor.
user_secret = keccak256(user_address || signal_hash)
nullifier = keccak256(user_secret || scope)
Duplicate-detection behavior depends on both signal_hash and scope remaining stable for the relevant action.
nullifier = keccak256(keccak256(email) || scope)
nullifier = keccak256(keccak256(ci) || scope)
Nullifier storage is application-specific. NullifierRegistry and ZKProofportNullifierRegistry are deprecated and are retained only as historical source references.
src/LedgerHouseStaking.sol holds real testnet
USDC deposits for the calling delegate. It offers no yield. The delegate can
withdraw its own balance without another proof; no administrator can withdraw it.
The token is Arc's six-decimal ERC-20 USDC interface at
0x3600000000000000000000000000000000000000, on chain 5042002.
It uses the Arc eligibility verifier at
0xCbC8E63fF92659E8B44cFF117D33005Bb669a018.
The staking contract is deployed at
0xD0F3eE648386B59B484157332E736388Fcc41F47,
in transaction
0x92f07f307b0b597b4786ca2f9c816297ad3db63694874842a213709f88ae4ba7.
The signed EIP-712 domain is Ledger House Staking, version 1, the current
chain ID and the staking contract's address. The struct is
CredentialDelegation(address delegate,string action,uint256 amount,uint256 expiresAt,string nonce);
action must be stake, and amount is in six-decimal token units. The
constructor pins the accepted Coinbase signer Merkle root. SCOPE is
keccak256("ledger-house").
stake(amount, proof, publicInputs, expiresAt, nonce) requires exactly 192
byte-valued fields: signal at 0, domain at 32, action at 64, signer root at 96,
scope at 128 and nullifier at 160. stakePacked accepts the same fields as
6144 concatenated bytes (192 ABI words, without an array header), for wallet
CLIs. Both entrypoints share validation and replay state. A nonempty nonce is
limited to 128 bytes; a nonempty proof is limited to 65536 bytes. Deadlines
must be strictly later than the current block timestamp. Reuse of a sender's
nonce or an action hash is refused, including after withdrawal. A fresh signed
action can reuse the credential's nullifier for a repeat demonstration.
balances(delegate) reads the position. withdraw(amount) sends only to
msg.sender. Staked(delegate, amount, actionHash) and
Withdrawn(delegate, amount) describe completed token movements. Failed proof
verification or token transfer rolls back balances and replay markers.
With pinned Foundry 1.4.3, run forge test --match-contract LedgerHouseStakingTest.
The deployment entrypoint is script/DeployLedgerHouseStaking.s.sol; it reads
PRIVATE_KEY and LEDGER_HOUSE_SIGNER_ROOT from the environment. Use Arc's
RPC and execute a dry run before adding --broadcast:
forge script script/DeployLedgerHouseStaking.s.sol:DeployLedgerHouseStaking \
--rpc-url https://rpc.testnet.arc.ioThe SDK buildSignerMerkleTree(0) root for the current four authorized signers
is 0xb60da9815c76261b61a1e91f199de5845fc171a6500e57c4240d2ac61d85e2bf.
Recompute it from the SDK when the signer list changes; do not accept a root
supplied by a proof. Foundry writes the deployment receipt under
broadcast/DeployLedgerHouseStaking.s.sol/5042002/run-latest.json.
The current generated artifacts were built with:
nargo 1.0.0-beta.8bb v1.0.0-nightly.20250723
./scripts/build.sh coinbase-attestation
./scripts/build.sh coinbase-country-attestation
./scripts/build.sh oidc-domain-attestation
./scripts/build.sh giwa-attestation
./scripts/build.sh mdl/kr-ownership
./scripts/build.sh mdl/kr-age
./scripts/build.sh mdl/kr-regionGenerated Solidity verifiers expose the common interface:
function verify(bytes calldata proof, bytes32[] calldata publicInputs)
external
view
returns (bool);See each pinned CIP for semantic public-input ordering and conformance requirements.
The tables below are synchronized with broadcast/**/run-latest.json at revision 28bbc303e04b732eb612d419b44dfd39d8a38a9a.
| Circuit | Verifier | Deployment record |
|---|---|---|
| Coinbase KYC | 0xcbc8e63ff92659e8b44cff117d33005bb669a018 |
DeployCoinbaseAttestation |
| Coinbase Country | 0x6646d970499bbed728636823a5a7e551e811b414 |
DeployCoinbaseCountryAttestation |
| OIDC Domain | 0x07121eb50b2ebe1675e7cb96c84b580a3ff6589e |
DeployOidcDomainAttestation |
| Circuit | Verifier | Deployment record |
|---|---|---|
| Coinbase KYC | 0x0036b61dbfab8f3cfeef77dd5d45f7efbfe2035c |
DeployCoinbaseAttestation |
| Coinbase Country | 0xdee363585926c3c28327efd1edd01cf4559738cf |
DeployCoinbaseCountryAttestation |
| OIDC Domain | 0x27afdea349f247cf698f97fdfab59e1bf8bd0550 |
DeployOidcDomainAttestation |
| Mobile ID ownership | 0x7602d09d24e6e16eff5ab981646872886376763e |
DeployMdlKrOwnership |
| Mobile ID age | 0xcff90ff8ceadc98f625300dc976ed85a3aa943ba |
DeployMdlKrAge |
| Mobile ID region | 0x435f0448f02f5df9659d460181116bcaf37e518e |
DeployMdlKrRegion |
| Circuit | Verifier | Deployment record |
|---|---|---|
| Coinbase KYC | 0xf7ded73e7a7fc8fb030c35c5a88d40abe6865382 |
DeployCoinbaseAttestation |
| Coinbase Country | 0xf3d5a09d2c85b28c52ef2905c1be3a852b609d0c |
DeployCoinbaseCountryAttestation |
| OIDC Domain | 0x9677ba46ad226ce8b3c4517d9c0143e4d458beae |
DeployOidcDomainAttestation |
| Circuit | Verifier | Deployment record |
|---|---|---|
| GIWA attestation PoC | 0xeb9eb5452790cfe549ff83ceb3dbe1c432231492 |
DeployGiwaAttestation |
Deployment scripts are under script/, with generated verifier sources under each circuit's target/ directory. The generic helper accepts configured network names:
./scripts/deploy_verifier.sh coinbase-attestation base-sepoliaEnvironment-specific keys, RPC URLs, and explorer credentials are required.
No external security audit or formal verification is documented for the current circuits. Review each CIP's trust assumptions and known limitations before relying on a reference implementation or deployment.
MIT, preserving the repository's existing license intent. Vendored dependencies retain their respective licenses.