ZK Passport smart contracts reference
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
Registration
andRegistration2
contracts, 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.
Registration
Interface
contract Registration 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 {
/* ... */
}
function revokeCertificate(bytes32 certificateKey_) external {
stateKeeper.removeCertificate(certificateKey_);
}
function register(
bytes32 certificatesRoot_,
uint256 identityKey_,
uint256 dgCommit_,
Passport memory passport_,
VerifierHelper.ProofPoints memory zkPoints_
) external {
/* ... */
}
function revoke(uint256 identityKey_, Passport memory passport_) external {
/* ... */
}
function reissueIdentity(
bytes32 certificatesRoot_,
uint256 identityKey_,
uint256 dgCommit_,
Passport memory passport_,
VerifierHelper.ProofPoints memory zkPoints_
) external {
/* ... */
}
function updateDependency(
MethodId methodId_,
bytes calldata data_,
bytes calldata proof_
) external {
/* ... */
}
}
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
;revoke(...)
— revokes the identity and its passport by the user's will, marks the passport (and identity) as revoked;reissueIdentity(...)
— issues previous passport <> identity bond by migrating to a new identity;updateDependency(...)
— adds or removes, depending on the method provided, a dispatcher via Rarimo TSS;
For the full implementation, see Registration.sol at the GitHub.
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 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 updateDependency(
MethodId methodId_,
bytes calldata data_,
bytes calldata proof_
) external virtual {
/* ... */
}
}
The main difference between Registration
and Registration2
contracts is that they use different ZK registration schemas.
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 (that was created using a different schema, compared toRegistration
), links the identity to its passport by callingStateKeeper
;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;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:
PUniversal2048Verifier
— used to create ZKPs that will be accepted byRegistration
;PUniversal4096Verifier
— used to create ZKPs that will be accepted byRegistration
;PUniversal2048Verifier2
— used to create ZKPs that will be accepted byRegistration2
;PUniversal4096Verifier2
— used to create ZKPs that will be accepted byRegistration2
;PInternalOptVerifier2
— internal verifier forRegistration2
;PInternalVerifier2
— internal verifier forRegistration2
;PMNEOptVerifier2
— internal verifier forRegistration2
;
verifyProof(...)
— verifies passport validity ZKP;
For the full implementation, see verifiers for Registration
and 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.
PRSASHA1Dispatcher
Interface
contract PRSASHA1Dispatcher is IPassportDispatcher, Initializable {
address public authenticator;
function authenticate(
bytes memory challenge_,
bytes memory passportSignature_,
bytes memory passportPublicKey_
) external view returns (bool) {
return
PRSASHA1Authenticator(authenticator).authenticate(
challenge_,
passportSignature_,
passportPublicKey_
);
}
}
authenticator
— address of the RSASHA1Authenticator contract for passports;authenticate(...)
— authenticates the RSASHA1 passport;
For the full implementation, see PRSASHA1Dispatcher.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.
PRSASHA1Authenticator
Interface
contract PRSASHA1Authenticator 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 PRSASHA1Authenticator.sol at the GitHub.