ZK Passport smart contracts reference
We're in process of migrating from legacy Circom circuits to Noir Ultra Plonk for passport verification during registration. Until the migration is complete, both are supported resulting in existence of ...Noir
methods
A set of contracts facilitating self-issued anonymous identities based on the ZK Passport tech.
Currently, there are seven contract sections:
- State
— main
StateKeeper
contract and a set of utility contracts.StateKeeper
acts as a singleton state instance with which registration contracts interact.StateKeeper
does the following:- Stores the Sparse Merkle Tree with registered identities;
- Stores the Sparse Merkle Tree with registered certificates of ICAO members;
- Stores and manages some passport and identity information;
- Manages the "Passport <> Identity" bonds.
- Registration
— primary section with
Registration2
contract, that:- Allow users registration (with binding of their identity to the passport);
- Allow revocation of passport-identity binding;
- Allow re-issuance of previously revoked identity;
- Allow registration and revocation of ICAO member's certificates (calls
StateKeeper
); - Call one of the verifier contracts, based on the provided passport type, to verify ZKP;
- Manage different dispatchers.
- Verifiers — auto-generated contracts, the main purpose of which is to verify the ZKP.
- Dispatchers
— acts as a bridge between registration contracts and:
- authenticators corresponding to different passport types, if it is a passport dispatcher;
- signers, if it is a certificate dispatcher.
- Signers — responsible for verifying the signature of the ICAO member's certificate. It also stores information required for signature verification (e.g. RSA exponent).
- Authenticators — perform the passport Active Authentication (AA).
- Utilities — some utility contracts, such as X509, SHA1, RSA implementations in solidity language and other.
Deployments
Name | Address |
---|---|
StateKeeper | 0x61aa5b68D811884dA4FEC2De4a7AA0464df166E1 |
RegistrationSMT | 0x479F84502Db545FA8d2275372E0582425204A879 |
CertificatesSMT | 0xA8b350d699632569D5351B20ffC1b31202AcEDD8 |
Registration2 | 0x11BB4B14AA6e4b836580F3DBBa741dD89423B971 |
Registration2
Interface
contract Registration2 is Initializable, TSSUpgradeable {
StateKeeper public stateKeeper;
mapping(bytes32 => address) public certificateDispatchers;
mapping(bytes32 => address) public passportDispatchers;
mapping(bytes32 => address) public passportVerifiers;
function registerCertificate(
Certificate memory certificate_,
ICAOMember memory icaoMember_,
bytes32[] memory icaoMerkleProof_
) external virtual {
/* ... */
}
function revokeCertificate(bytes32 certificateKey_) external virtual {
stateKeeper.removeCertificate(certificateKey_);
}
function register(
bytes32 certificatesRoot_,
uint256 identityKey_,
uint256 dgCommit_,
Passport memory passport_,
VerifierHelper.ProofPoints memory zkPoints_
) external virtual {
/* ... */
}
function registerViaNoir(
bytes32 certificatesRoot_,
uint256 identityKey_,
uint256 dgCommit_,
Passport memory passport_,
bytes memory zkPoints_
) external virtual {
/* ... */
}
function revoke(uint256 identityKey_, Passport memory passport_) external virtual {
/* ... */
}
function reissueIdentity(
bytes32 certificatesRoot_,
uint256 identityKey_,
uint256 dgCommit_,
Passport memory passport_,
VerifierHelper.ProofPoints memory zkPoints_
) external virtual {
/* ... */
}
function reissueIdentityViaNoir(
bytes32 certificatesRoot_,
uint256 identityKey_,
uint256 dgCommit_,
Passport memory passport_,
bytes memory zkPoints_
) external virtual {
/* ... */
}
function updateDependency(
MethodId methodId_,
bytes calldata data_,
bytes calldata proof_
) external virtual {
/* ... */
}
}
stateKeeper
— instance ofStateKeeper
contract that saves all data about registrations, certificates, etc.;certificateDispatchers
— mapping from ICAO member's certificate to its dispatcher;passportDispatchers
— mapping from passport type to its dispatcher contract;passportVerifiers
— mapping from passport type to its verifier contract;registerCertificate(...)
— registers an ICAO member's X509 certificate in the certificates SMT (callsStateKeeper
contract);revokeCertificate(...)
— revokes an expired ICAO member's X509 certificate (callsStateKeeper
contract);register(...)
— registers the user (identity) by its passport, technically — issues the identity, calls the dispatcher to verify ZKP, links the identity to its passport by callingStateKeeper
;registerViaNoir(...)
- the same asregister(...)
but uses Noir proof instead of Circom;revoke(...)
— revokes the identity and its passport by the user's will, marks the passport (and identity) as revoked;reissueIdentity(...)
— re-issues previous passport <> identity bond by migration to a new identity;reissueIdentityViaNoir(...)
— the same asreissueIdentity(...)
but uses Noir proof instead of Circom;updateDependency(...)
— adds or removes, depending on the method provided, a dispatcher via Rarimo TSS;
For the full implementation, see Registration2.sol at the GitHub.
Verifiers
Interface
contract ExampleVerifier {
/* some constants */
function verifyProof(
uint[2] calldata _pA,
uint[2][2] calldata _pB,
uint[2] calldata _pC,
uint[4] calldata _pubSignals
) public view returns (bool) {
/* ... */
}
}
All verifiers are generated contracts that share the same interface. However, each verifier is designed to accept proofs generated by specific ZK schemas. Below is a list of the current verifiers:
Circom verifiers
— the list of acceptable byRegistration2
smart contracts to verify biometric passport;Noir verifiers
— the list of acceptable byRegistration2
smart contracts to verify biometric passport;PInternalOptVerifier2
— Georgian ID card verifier forRegistration2
;PInternalVerifier2
— Georgian ID card verifier forRegistration2
;PMNEOptVerifier2
— Montenegro ID card verifier forRegistration2
;
verifyProof(...)
— verifies passport validity ZKP;
For the full implementation, see verifiers for Registration2
at the GitHub.
PECDSASHA1Dispatcher
Interface
contract PECDSASHA1Dispatcher is IPassportDispatcher, Initializable {
address public authenticator;
function authenticate(
bytes memory challenge_,
bytes memory passportSignature_,
bytes memory passportPublicKey_
) external view returns (bool) {
/* ... */
}
}
authenticator
— address of the ECDSASHA1Authenticator contract for passports;authenticate(...)
— authenticates the ECDSASHA1 passport;
For the full implementation, see PECDSASHA1Dispatcher.sol at the GitHub.
PNOAADispatcher
Interface
contract PNOAADispatcher is IPassportDispatcher, Initializable {
function authenticate(
bytes memory,
bytes memory passportSignature_,
bytes memory passportPublicKey_
) external pure returns (bool) {
return passportSignature_.length == 0 && passportPublicKey_.length == 0;
}
}
This is a special dispatcher for passports without Active Authentication.
authenticate(...)
— authenticates the passport without AA. Just return true;
For the full implementation, see PNOAADispatcher.sol at the GitHub.
PRSASHADispatcher
Interface
contract PRSASHADispatcher is IPassportDispatcher, Initializable {
address public authenticator;
function authenticate(
bytes memory challenge_,
bytes memory passportSignature_,
bytes memory passportPublicKey_
) external view returns (bool) {
return
PRSASHAAuthenticator(authenticator).authenticate(
challenge_,
passportSignature_,
passportPublicKey_
);
}
}
authenticator
— address of the RSASHAAuthenticator contract for passports;authenticate(...)
— authenticates the RSASHA passport;
For the full implementation, see PRSASHADispatcher.sol at the GitHub.
CRSADispatcher
Interface
contract CRSADispatcher is ICertificateDispatcher, Initializable {
address public signer;
function verifyICAOSignature(
bytes memory x509SignedAttributes_,
bytes memory icaoMemberSignature_,
bytes memory icaoMemberKey_
) external view override returns (bool) {
return
ICertificateRSASigner(signer).verifyICAOSignature(
x509SignedAttributes_,
icaoMemberSignature_,
icaoMemberKey_
);
}
}
As for passports, there are authenticators for certificates, and it's one of them.
signer
— address of the CRSASigner or CRSAPSSSigner contract for certificates;verifyICAOSignature(...)
— verifies RSA signature of ICAO member's certificate;
For the full implementation, see CRSADispatcher.sol at the GitHub.
CRSAPSSSigner
Interface
contract CRSAPSSSigner is ICertificateRSASigner, Initializable {
uint256 public exponent;
bool public isSha2;
function verifyICAOSignature(
bytes memory x509SignedAttributes_,
bytes memory icaoMemberSignature_,
bytes memory icaoMemberKey_
) external view override returns (bool) {
return
RSAPSS.verify(
x509SignedAttributes_,
icaoMemberSignature_,
abi.encodePacked(exponent),
icaoMemberKey_,
isSha2
);
}
exponent
— RSAPSS exponent;isSha2
— hash function switcher, true - sha2, false - sha512;verifyICAOSignature(...)
— verifies ICAO member RSAPSS signature of the X509 certificate SA;
For the full implementation, see CRSAPSSSigner.sol at the GitHub.
CRSASigner
Interface
contract CRSASigner is ICertificateRSASigner, Initializable {
uint256 public exponent; // RSA exponent
bool public isSha1; // hash function switcher, true - sha1, false - sha2
function verifyICAOSignature(
bytes memory x509SignedAttributes_,
bytes memory icaoMemberSignature_,
bytes memory icaoMemberKey_
) external view override returns (bool) {
/* ... */
}
}
exponent
— RSA exponent;isSha2
— hash function switcher, true - sha2, false - sha512;verifyICAOSignature(...)
— verifies ICAO member RSA signature of the X509 certificate SA.;
For the full implementation, see CRSASigner.sol at the GitHub.
PECDSASHA1Authenticator
Interface
contract PECDSASHA1Authenticator {
/* brainpool256r1 parameters */
function authenticate(
bytes memory challenge,
uint256 r,
uint256 s,
uint256 x,
uint256 y
) external pure returns (bool) {
/* ... */
}
}
authenticate(...)
— checks active authentication of a passport (ECDSA signature);
For the full implementation, see PECDSASHA1Authenticator.sol at the GitHub.
PRSASHAAuthenticator
Interface
contract PRSASHAAuthenticator is Initializable {
uint256 public exponent; // RSA exponent
function authenticate(
bytes memory challenge_,
bytes memory s_,
bytes memory n_
) external view returns (bool) {
/* ... */
}
}
exponent
— RSA exponent;authenticate(...)
— checks active authentication of a passport (RSA signature);
For the full implementation, see PRSASHAAuthenticator.sol at the GitHub.
TD3QueryProofVerifier
Interface
contract TD3QueryProofVerifier {
function verifyProof(
uint256[2] calldata _pA,
uint256[2][2] calldata _pB,
uint256[2] calldata _pC,
uint256[] calldata _pubSignals
) external view returns (bool) {
/* ... */
}
}
- Verifies TD3-query zero-knowledge proofs produced by the Query circuit (e.g., age, uniqueness, country masks) without revealing raw passport data.
- Accepts Groth16 proof points and the public signals array (23 items for Query circuit) and returns
true
if valid. - Intended for SDK-level integrations where on-chain verification of query proofs is needed.
For the full implementation, see TD3QueryProofVerifier.sol at the GitHub.
PublicSignalsBuilder
Interface
library PublicSignalsBuilder {
uint256 public constant PROOF_SIGNALS_COUNT = 23;
function newPublicSignalsBuilder(
uint256 selector_,
uint256 nullifier_
) internal pure returns (uint256 dataPointer_);
function withName(uint256 dataPointer_, uint256 name_) internal pure;
function withNameResidual(uint256 dataPointer_, uint256 nameResidual_) internal pure;
function withNationality(uint256 dataPointer_, uint256 nationality_) internal pure;
function withCitizenship(uint256 dataPointer_, uint256 citizenship_) internal pure;
function withSex(uint256 dataPointer_, uint256 sex_) internal pure;
function withEventIdAndData(uint256 dataPointer_, uint256 eventId_, uint256 eventData_) internal pure;
function withIdStateRoot(uint256 dataPointer_, bytes32 idStateRoot_) internal view;
function withSelector(uint256 dataPointer_, uint256 selector_) internal pure;
function withCurrentDate(uint256 dataPointer_, uint256 currentDate_, uint256 timeBound_) internal view;
function withTimestampLowerboundAndUpperbound(uint256 dataPointer_, uint256 lb_, uint256 ub_) internal pure;
function withIdentityCounterLowerbound(uint256 dataPointer_, uint256 lb_, uint256 ub_) internal pure;
function withBirthDateLowerboundAndUpperbound(uint256 dataPointer_, uint256 lb_, uint256 ub_) internal pure;
function withExpirationDateLowerboundAndUpperbound(uint256 dataPointer_, uint256 lb_, uint256 ub_) internal pure;
function withCitizenshipMask(uint256 dataPointer_, uint256 citizenshipMask_) internal pure;
function buildAsUintArray(uint256 dataPointer_) internal pure returns (uint256[] memory);
function buildAsBytesArray(uint256 dataPointer_) internal pure returns (bytes32[] memory);
}
- Helper library to construct the Query circuit public signals in the exact index layout expected by verifiers (see Query circuit public signals spec).
- Validates constraints via
AQueryProofExecutor
storage;withIdStateRoot(...)
checksIPoseidonSMT(registrationSMT).isRootValid(...)
before writing the root at index 11. - Date handling:
withCurrentDate(...)
parsesyyMMdd
to a timestamp and enforces a ±timeBound window usingDate2Time
utilities. - Produces either
uint256[]
orbytes32[]
views of the same in-memory array for downstream verifier calls.
For the full implementation, see PublicSignalsBuilder.sol at the GitHub.
RegistrationSMTReplicator
Interface
contract RegistrationSMTReplicator is IPoseidonSMT {
uint256 public constant ROOT_VALIDITY = 1 hours;
string public constant REGISTRATION_ROOT_PREFIX = "Rarimo root";
address public sourceSMT;
bytes32 public latestRoot;
uint256 public latestTimestamp;
event RootTransitioned(bytes32 newRoot, uint256 transitionTimestamp);
function __RegistrationSMTReplicator_init(
address[] memory oracles_,
address sourceSMT_
) external;
function addOracles(address[] memory oracles_) external;
function removeOracles(address[] memory oracles_) external;
function setSourceSMT(address newSourceSMT_) external;
function transitionRoot(bytes32 newRoot_, uint256 transitionTimestamp_) external;
function transitionRootWithSignature(
bytes32 newRoot_,
uint256 transitionTimestamp_,
bytes memory signature_
) external;
function isRootValid(bytes32 root_) external view returns (bool);
function isRootLatest(bytes32 root_) public view returns (bool);
function isOracle(address oracle_) public view returns (bool);
function getOracles() external view returns (address[] memory);
}
- Deployed on target chains to replicate the Registration SMT root when the canonical
StateKeeper
is not directly available. - Root updates can be pushed by:
- Authorized oracles via
transitionRoot(...)
. - Anyone with an oracle-signed message via
transitionRootWithSignature(...)
usingkeccak256(abi.encodePacked(REGISTRATION_ROOT_PREFIX, sourceSMT, address(this), newRoot, timestamp))
recovered with ECDSA.
- Authorized oracles via
isRootValid(root)
returns true if the root is the latest or if it was observed withinROOT_VALIDITY
(1 hour), enabling lightweight freshness checks by verifiers depending onIPoseidonSMT
.- Owners manage the oracle set and can update
sourceSMT
; contract follows UUPS upgradeability and multi-owner controls.
For the full implementation, see RegistrationSMTReplicator.sol at the GitHub.