Skip to main content

Private Guest List Contract

This Compact contract implements a party with a private guest list. It offers demonstration of the following features:

  • Hiding information on the public ledger
  • Verifying hidden ledger information
  • Access control to circuits
  • Operations on a Set
  • Introduction to witness functions
pragma language_version 0.21;
import CompactStandardLibrary;

export enum PartyState {
NOT_READY,
READY
}

export ledger organizers: Set<ZswapCoinPublicKey>;// organizers are public
export ledger hashedPartyGoers: Set<Bytes<32>>;// participants are hashed until they arrive
export ledger checkedInParty: Set<Bytes<32>>;
export ledger partyState: PartyState;
export ledger maxListSize: Uint<8>;

witness localStartParty(): PartyState;

constructor(){
// the publicKey of the caller of this function
organizers.insert(ownPublicKey());
partyState = PartyState.NOT_READY;
maxListSize = 99;
}

export circuit addOrganizer(newOrganizer: ZswapCoinPublicKey): [] {
assert(organizers.member(ownPublicKey()), "You are not an organizer");
assert(!organizers.member(disclose(newOrganizer)), "You are already in the organizer list");
assert(partyState == PartyState.NOT_READY, "The party has already started");

organizers.insert(disclose(newOrganizer));
}

export circuit addParticipant(_participantPk: Bytes<32>, _organizerSk: Bytes<32>): [] {
// only organizers can add party goers
assert(organizers.member(ownPublicKey()), "You are not an organizer");
assert(partyState == PartyState.NOT_READY, "The party has already started");
assert(hashedPartyGoers.size() < maxListSize, "The list is full");

const participant = commitWithSk(_participantPk, _organizerSk);
assert(!hashedPartyGoers.member(disclose(participant)), "You are already in the list");
hashedPartyGoers.insert(disclose(participant));

if (hashedPartyGoers.size() == maxListSize) {
const localPartyState = localStartParty();
// don't trust, verify
assert(localPartyState == PartyState.READY, "Please start the party, the list is full");
partyState = PartyState.READY;
}
}

export circuit checkIn(participantPk: Bytes<32>, _organizerSk: Bytes<32>): [] {
assert(organizers.member(ownPublicKey()), "You are not an organizer");
assert(partyState == PartyState.READY, "The party has not started yet");
assert(checkedInParty.size() < hashedPartyGoers.size(), "All guests have already checked in");
assert(hashedPartyGoers.member(commitWithSk(participantPk, _organizerSk)), "You are not on the list");

checkedInParty.insert(disclose(participantPk));
}

export circuit chainStartParty(): [] {
assert(organizers.member(ownPublicKey()), "Only organizers can start the party");
assert(partyState == PartyState.NOT_READY, "The party has already started");

const localPartyState = disclose(localStartParty());
assert(localPartyState == PartyState.READY, "Please start the party locally");
partyState = localPartyState;
}

circuit commitWithSk(_participantPk: Bytes<32>, _sk: Bytes<32>): Bytes<32> {
return disclose(persistentHash<Vector<2, Bytes<32>>>([_participantPk, _sk]));
}