Bulk Semaphore: Scalable, Customizable Private Transactions
Private governance, sealed bid auctions, anonymous surveys, and any system requiring anonymous messaging and signaling
In our previous discussion, we introduced Bulk Semaphore as a protocol for bulk anonymous membership and signaling and demonstrated how Blockframe uses it to implement infinitely scalable sealed-bid auctions on Ethereum and EVM chains.
Today, we are releasing Bulk Semaphore as an open-source protocol. Along with this release, we are providing developers with the necessary tools and instructions to adapt the protocol to various applications.
Private Governance
As an added guide, we are presenting how Bulk Semaphore can be adapted for private voting:
Modify the contracts inside the
private-voting
folder of the Bulk Semaphore GitHub repository to your likingThis involves deciding on whether the governance system is on-chain or off-chain.
Deploy the contracts
Deploy the zkSNARK server
Interact with the contracts and zkSNARK server from your frontend.
The zkSNARK server comes pre-packaged with the required HTTP endpoints for verification.
View a live demo of Blockframeโs private governance protocol here: https://blockframe.io/governance-demo
Comparison to Iskoratia
Isokratia is a recursive SNARKs protocol enabling trust-minimized governance for off-chain voting platforms.
While both Iskoratia and Blockframe's Bulk Semaphore utilize recursive zkSNARKs to achieve scalability, Bulk Semaphore stands out by being nearly 2x more gas efficient, offering a significant advantage in terms of transaction costs for users. Additionally Bulk Semaphore is generic and composable, i.e., it can be used for off-chain voting platforms, on-chain voting platforms and even completely different use-cases requiring private transactions.
Custom Use Cases
The Bulk Semaphore GitHub also contains a folder named `generic` containing a Semaphore implementation with general purpose public inputs:
group_id: uint256 group identifier i.e. auction_id
value: an arbitrary uint256 signal i.e. bid_value
secret: a random uint256 secret
identity_nullifier: the userโs uint256 identifier
identity_trapdoor: random uint256 user identifier secret
If the developer requires more customization, we offer a custom configuration guide where we walk the developer step by step through how to add any number of parameters to the zkSNARK commitment and deploy a custom zkSNARK system.
System Design
Smart Contract Interface
function createGroup(uint256 groupId, address admin)
function reveal(uint256 commitment, uint256 groupId, uint256 value)
function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[68] calldata _pubSignals)
Developers are given full control over commitment submission. While we offer an example using a create2 factory, a direct on-chain function is also readily available for alternative approaches:
function submitCommitment(uint256 commitment, uint256 value)
Composable Privacy
When revealing commitments on-chain to be included in the root proof, the minimum requirement is that just a commitment hash is revealed. Developers can choose to disclose the contents of this commitment hash, thereby adjusting the level of privacy of the zkSNARK system. For example, in Blockframeโs sealed bid auction design, bidders must reveal all the contents of their commitment hash when they reveal their bid such as auctionId, bidAmount, bidCurrency, etcโฆ However, some applications may want to maintain complete privacy even post-facto of the underlying process i.e. auction, in which case the reveal function can and should only accept a commitment.
Extendability
Bulk Semaphore is completely feature-agnostic and can be integrated into any system involving private membership, messaging or signaling such as:
Anonymous on-chain and off-chain governance
Anonymous surveys
Trade auctions
Sealed bid auctions
Verifying any off-chain computations in decentralized fashion
FAQ
What is a zkSNARK? Is it a server? Is it an oracle?
A zkSNARK is a cryptographic proof system that allows one party to prove to another that a statement is true, without revealing any specific information about the statement itself. This enables private transactions and private information storage on public blockchains like Ethereum. In our implementation, the zkSNARK system is hosted on a Rust server. It is not an oracle.
Who can run the zkSNARK?
The zkSNARK is run on a dedicated Rust server. Anyone can run their own zkSNARK system. The server features HTTP endpoints that make commitment generation and proof verification simple. Once the server is running, the frontend can just call these HTTP endpoints directly.
What is the difference between Semaphore and Bulk Semaphore?
Semaphore is an anonymous messaging and signaling protocol with single-proof verification. Each commitment in Semaphore requires a separate on-chain proof verification, costing about 60k gas. Bulk Semaphore builds upon Semaphore but introduces bulk verification, allowing for the collective verification of an unlimited number of proofs at a cost of around 200k gas. This makes Bulk Semaphore more scalable and efficient for large-scale systems.
Who can generate the proofs?
The proofs are generated by the zkSNARK server.
In the private voting example, the proof is the parameter that is required to execute a governance proposal.
Who can verify the proofs?
Anyone can verify the proof as long as they have access to it. The proof is emitted by the zkSNARK server.
How is it possible for anyone to verify a proof? Could a user misuse the proof in a transaction once it is revealed to them?
To prevent this, the prover emits hash(proof || group_id || Semaphore Merkle root), which must be submitted to the smart contract prior to on-chain proof verification.
How do we ensure the process was conducted truthfully? Can the zkSNARK server host omit commitments?
The integrity of the vote is maintained as the Semaphore Merkle tree root is posted on-chain when the proof is verified. This allows anyone to verify which commitments were included in the vote, ensuring transparency and preventing vote omission. The system can be automatically disabled if any skew is detected.
How can I generate a proof-of-censorship and proof-of-authenticity after the process is completed?
When a proof is verified, the Semaphore Merkle tree root associated with the proof is posted. This allows anyone to verify which commitments were included in the proof verification process conducted by the administrator, ensuring transparency and authenticity.
User Experience Optimizations
Using account abstraction, reveal transactions can be pre-signed by users omitting the requirement for the user to come back to reveal their commitment.
Using a create2 factory for the commitment allows for transactions to be submitted with complete privacy.
GitHub
https://github.com/blockframeapp/bulk-semaphore
[To be made public in the 3rd week of September]