ziffle
Mental poker shuffle protocol using zero-knowledge proofs.
ziffle implements a mental poker protocol where multiple players can
collaboratively shuffle a deck of cards without any player learning the order,
and then selectively reveal individual cards.
The protocol uses Bayer-Groth 2012 shuffle proofs to ensure that each shuffle is performed correctly without revealing the permutation.
ziffle is a #[no_std] crate.
⚠️ Security Warning
This code has not been independently audited. It is experimental software provided as-is without any warranties. While the implementation follows the Bayer-Groth 2012 specification, it may contain bugs or vulnerabilities.
DO NOT use this library to play for non-trivial amounts of money or in any high-stakes scenario. Use at your own risk.
Main Entry Point
The Shuffle struct is the primary interface for using this library. Create an
instance with Shuffle::<N>::default() where N is the number of cards in your deck.
Example: Three-Player Poker Game
use ;
// Create a standard 52-card deck
let shuffle = default;
let mut rng = test_rng; // DO NOT USE IN PRODUCTION
let ctx = b"poker_game_session_123";
// Three players generate their keys and prove ownership
let = shuffle.keygen;
let = shuffle.keygen;
let = shuffle.keygen;
// Each player verifies others' key ownership proofs
let alice_vpk = alice_proof.verify.unwrap;
let bob_vpk = bob_proof.verify.unwrap;
let carol_vpk = carol_proof.verify.unwrap;
// Create aggregate public key from all verified keys
let apk = new;
// Alice performs the initial shuffle
let = shuffle.shuffle_initial_deck;
let alice_vdeck = shuffle
.verify_initial_shuffle
.expect;
// Bob shuffles Alice's deck
let = shuffle.shuffle_deck;
let bob_vdeck = shuffle
.verify_shuffle
.expect;
// Carol shuffles Bob's deck
let = shuffle.shuffle_deck;
let final_vdeck = shuffle
.verify_shuffle
.expect;
// Now the deck is fully shuffled and encrypted. Let's reveal the first card.
let first_card = final_vdeck.get.unwrap;
// Each player creates a reveal token for the first card
let =
first_card.reveal_token;
let =
first_card.reveal_token;
let =
first_card.reveal_token;
// All players verify each other's reveal tokens
let alice_vtoken = alice_token_proof
.verify
.expect;
let bob_vtoken = bob_token_proof
.verify
.expect;
let carol_vtoken = carol_token_proof
.verify
.expect;
// Aggregate the verified tokens to decrypt the card
let aggregate_token = new;
// Reveal the card's index in the original deck (0-51)
let card_index = shuffle
.reveal_card
.expect;
println!;
assert!;
Serialized Sizes
The following table shows the serialized sizes of types that need to be transmitted over the network in a typical mental poker protocol. All sizes use compressed canonical serialization from arkworks.
| Type | Size | Notes |
|---|---|---|
PublicKey |
33 bytes | One per player at setup |
OwnershipProof |
65 bytes | One per player at setup |
MaskedDeck<52> |
3,432 bytes | 66 bytes per card (33 × 2) |
ShuffleProof<52> |
5,547 bytes | One per shuffle operation |
RevealToken |
33 bytes | One per player per revealed card |
RevealTokenProof |
98 bytes | One per player per revealed card |
License
Licensed under either of
- Apache License, Version 2.0, (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or https://opensource.org/licenses/MIT)
at your option.
Contribution
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.