zPass invalidate program
// The 'zpass_invalidate' program.
program zpass_invalidate.aleo {
// Example admin address that has authority to add or remove issuer
const ADMIN: address = aleo1rhgdu77hgyqd3xjj8ucu3jj9r2krwz6mnzyd80gncr5fxcwlh5rsvzp9px;
// The ZPass record
record ZPass {
owner: address,
issuer: address,
dob: u32,
nationality: field,
expiry: u32,
salt: scalar
}
// The private credentials struct
struct PrivateCredentials {
subject: address,
dob: u32,
nationality: field,
expiry: u32
}
// The public credentials struct
// This is the public information that is shared publicly onchain
struct PublicCredentials {
issuer: address,
salt: scalar
}
// The full credentials struct to be hashed and verified against the signature
struct FullCredentials {
issuer: address,
subject: address,
dob: u32,
nationality: field,
expiry: u32,
salt: scalar
}
// Stores approved issuers
mapping is_issuer: address => bool;
// The mapping of issued commitments
mapping issued: group => bool;
// The mapping of invalidated commitments
mapping invalidated: group => bool;
// The count of issued ZPasses
// Using key of 0field as global key
mapping issuance_count: field => u128;
async transition add_issuer(
public issuer: address
) -> Future {
assert_eq(self.caller, ADMIN);
return add_issuer_finalize(issuer);
}
async function add_issuer_finalize(
issuer: address
) {
is_issuer.set(issuer, true);
}
async transition remove_issuer(
public issuer: address
) -> Future {
assert_eq(self.caller, ADMIN);
return remove_issuer_finalize(issuer);
}
async function remove_issuer_finalize(
issuer: address
) {
is_issuer.set(issuer, false);
}
async transition issue(
private sig: signature,
private pri: PrivateCredentials,
public pub: PublicCredentials,
) -> (ZPass, Future) {
// Construct the full credentials struct to be hashed and verified against the signature
let credentials: FullCredentials = FullCredentials {
issuer: pub.issuer,
subject: self.signer, // The signer must be the subject of the ZPass
dob: pri.dob,
nationality: pri.nationality,
expiry: pri.expiry,
salt: pub.salt,
};
// Verify signature
assert_eq(signature::verify(sig, pub.issuer, Poseidon2::hash_to_field(credentials)), true);
// Compute commitment to prevent double issuance
let commit: group = BHP256::commit_to_group(self.signer, pub.salt);
// Return the ZPass record and pass the commitment to store in the mapping
return (ZPass {
owner: self.signer,
issuer: pub.issuer,
dob: pri.dob,
nationality: pri.nationality,
expiry: pri.expiry,
salt: pub.salt
}, issue_finalize(pub.issuer, commit));
}
async function issue_finalize(
public issuer: address,
public commit: group
) {
// Ensure the issuer is approved
assert_eq(is_issuer.get(issuer), true);
// Ensure the commitment is not already issued
assert_eq(issued.get_or_use(commit, false), false);
// Store the commitment in the mapping
issued.set(commit, true);
// Increment the issuance count
issuance_count.set(0field, issuance_count.get_or_use(0field, 0u128) + 1u128);
}
// Must know the details of the ZPass to invalidate it
// subject in FullCredentials is owner of the ZPass to invalidate
async transition invalidate(
credentials: FullCredentials
) -> Future {
let commit: group = BHP256::commit_to_group(credentials, credentials.salt);
return invalidate_finalize(commit);
}
// Helper function to check validity of ZPass
async function invalidate_finalize(
public commit: group
) {
// Store the commitment in the mapping
invalidated.set(commit, true);
}
async transition is_invalid(
credentials: FullCredentials
) -> Future {
let commit: group = BHP256::commit_to_group(credentials, credentials.salt);
return is_invalid_finalize(commit);
}
async function is_invalid_finalize(
public commit: group
) {
assert_eq(invalidated.get_or_use(commit, false), false);
}
}
This program enhances the zPass issuance program by introducing a new mapping called invalidated
. This mapping is used to store the commitments of zPass records that have been invalidated. Invalidation may occur in cases where the rightful owner no longer has exclusive access to their zPass, such as when an account is compromised. In such scenarios, the user can choose to reissue a new zPass associated with a different account.
To ensure the validity of a zPass, an is_invalid
transition is added. This transition allows importing programs to verify whether a zPass has been invalidated by passing all the private information from the zPass. This process guarantees the integrity of the zPass and ensures that only the rightful owner can utilize it, maintaining its exclusivity and security.
Last updated