{"id":47444082,"url":"https://github.com/PeaceFounder/ShuffleProofs.jl","last_synced_at":"2026-04-06T13:00:56.318Z","repository":{"id":50932682,"uuid":"453004521","full_name":"PeaceFounder/ShuffleProofs.jl","owner":"PeaceFounder","description":"Verificatum compatible verifier and prover for NIZK proofs of shuffle","archived":false,"fork":false,"pushed_at":"2025-02-14T01:11:42.000Z","size":561,"stargazers_count":10,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-31T19:55:14.754Z","etag":null,"topics":["cryptography","elgamal","nizk","verificatum","zero-knowledge-proofs"],"latest_commit_sha":null,"homepage":"","language":"Julia","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PeaceFounder.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-01-28T09:12:54.000Z","updated_at":"2026-03-15T16:11:23.000Z","dependencies_parsed_at":"2024-03-25T18:36:42.013Z","dependency_job_id":null,"html_url":"https://github.com/PeaceFounder/ShuffleProofs.jl","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/PeaceFounder/ShuffleProofs.jl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeaceFounder%2FShuffleProofs.jl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeaceFounder%2FShuffleProofs.jl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeaceFounder%2FShuffleProofs.jl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeaceFounder%2FShuffleProofs.jl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PeaceFounder","download_url":"https://codeload.github.com/PeaceFounder/ShuffleProofs.jl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PeaceFounder%2FShuffleProofs.jl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31473271,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-06T08:36:52.050Z","status":"ssl_error","status_checked_at":"2026-04-06T08:36:51.267Z","response_time":112,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cryptography","elgamal","nizk","verificatum","zero-knowledge-proofs"],"created_at":"2026-03-23T06:00:59.902Z","updated_at":"2026-04-06T13:00:56.312Z","avatar_url":"https://github.com/PeaceFounder.png","language":"Julia","readme":"# ShuffleProofs.jl\n\n[![codecov](https://codecov.io/gh/PeaceFounder/ShuffleProofs.jl/graph/badge.svg?token=4VCLLS1YEF)](https://codecov.io/gh/PeaceFounder/ShuffleProofs.jl)\n\nShuffleProofs.jl is a high-performance Julia package implementing zero-knowledge proofs of shuffle, primarily designed for E2E verifiable e-voting systems and privacy-preserving applications. The package implements the Wikström proof of shuffle protocol with Verificatum compatibility, matching the protocol deployed in national-scale electronic voting systems across Estonia, Norway, and Switzerland.\n\n## Why ShuffleProofs.jl?\n\nTraditional cryptographic tools often focus solely on confidentiality and security. However, modern systems like electronic voting require privacy to unlink voters from their votes and verifiability, proving that every vote tallied had come from at most one eligible voter.  ShuffleProofs.jl addresses part of this complex challenge through ElGamal reencryption shuffle.\n\n- **Standards-Compliant**: Compatible with the battle-tested Verificatum verifier specification\n- **Flexible Design**: Supports various cryptographic groups and custom verification strategies\n- **Developer-Friendly**: Clean, type-safe implementation with comprehensive testing that closely matches [Haenni et al.](https://link.springer.com/chapter/10.1007/978-3-319-70278-0_23#citeas) pseudocode\n- **Enabling Ecosystem**: Easily reuse [CryptoPRG](https://github.com/PeaceFounder/CryptoPRG.jl), [CryptoGroups](https://github.com/PeaceFounder/CryptoGroups.jl), [OpenSSLGroups](https://github.com/PeaceFounder/OpenSSLGroups.jl) and [SigmaProofs](https://github.com/PeaceFounder/SigmaProofs.jl) for other supporting zero-knowledge proofs and transition seamlessly from prototyping to production environments\n- **High Performance**: Competitive with Verificatum on single-core benchmarks\n\n\u003ctable\u003e\n\u003ctr\u003e\n\u003ctd\u003e\u003cimg src=\"test/benchmarks/results/P-256_N=100000.svg\" alt=\"P-256 Performance\"\u003e\u003c/td\u003e\n\u003ctd\u003e\u003cimg src=\"test/benchmarks/results/modp_2048_N=10000.svg\" alt=\"ModP Performance\"\u003e\u003c/td\u003e\n\u003c/tr\u003e\n\u003c/table\u003e\n\n*Note: Light blue sections show the time taken for a proposition, proof deserialisation, and group membership validation in ShuffleProofs. The benchmarks for the P-256 group have been made using the implementation from OpenSSLGroups. Both quadratic residue prime group with 2048-bit prime modulus and NIST standard curve P-256 group offer 128-bit security for discrete logarithm problems. Performance tests made with Ubuntu 24.04 on M1 Pro. The benchmark figures have been made with code in `test/benchmarks/benchmark.jl`*\n\n## Installation\n\n```julia\nusing Pkg\nPkg.add(\"ShuffleProofs\")\n```\n\nThe package is registered in Julia's general registry and can be installed with the standard package manager on Julia-supported platforms: Linux, MacOS, Windows, FreeBSD and others. All dependencies are automatically handled during installation; no binary artefacts are compiled locally. Hence, the package shall work robustly for all future environments with few updates.\n\n## Core Features\n\n### Cryptographic Capabilities\n- Zero-knowledge proof generation and verification for ElGamal reencryption shuffles\n- Support for verifiable braiding proofs for public key anonymization\n- Extended ciphertext width support\n\n### Group Support\n- Native elliptic curves (P-192, P-256, secp256k1)\n- High-performance OpenSSL curve integration via [OpenSSLGroups.jl](https://github.com/PeaceFounder/OpenSSLGroups.jl)\n- Modular prime groups with flexible parameter selection\n- Extensible interface for custom group implementations and hardware optimisations\n\n### Verificatum Compatibility\n- Full compatibility with Verificatum's proof of shuffle verifier specification\n- Support for loading and verifying Verificatum-generated proofs\n- Flexible verifier interface for custom implementations\n- Reorganised, flat directory structure for proof serialisations while complying with file specifications\n\n## Quick Start: E-Voting Example\n\nHere's how to implement a basic e-voting system with anonymous vote collection and verifiable counting:\n\n```julia\nusing CryptoGroups\nusing SigmaProofs.ElGamal: Enc, ElGamalRow\nusing SigmaProofs.DecryptionProofs: decrypt\nusing SigmaProofs.Verificatum: ProtocolSpec\nusing ShuffleProofs: shuffle, verify\n\n# Setup\ng = @ECGroup{P_192}()\nverifier = ProtocolSpec(; g)\nsk = 123  # Secret key (in practice, distributed in threshold ceremony)\npk = g^sk\noptions = [g, g^2, g^3]  # Voting options\n\n# 1. Collect encrypted votes\nbbord = let\n    enc = Enc(pk, g)\n    ciphertexts_in = [enc(options[rand(1:3)], rand(1:10)) |\u003e ElGamalRow for i in 1:10]\n    (; ciphertexts_in)\nend\n\n# 2. Shuffle votes anonymously with proof\nbbord = let\n    simulator = shuffle(bbord.ciphertexts_in, g, pk, verifier)\n    (; bbord..., \n       ciphertexts_out = simulator.proposition.𝐞′,\n       shuffle_proof = simulator.proof)\nend\n\n# 3. Decrypt with proof\nbbord = let\n    simulator = decrypt(g, bbord.ciphertexts_out, sk, verifier)\n    (; bbord...,\n       votes = simulator.proposition.plaintexts,\n       dec_proof = simulator.proof)\nend\n```\n\nThis example demonstrates a complete electronic voting workflow: vote submission, shuffling, and decryption. The process ensures that while votes remain anonymous, the entire process is verifiable. Each step produces cryptographic proofs that can be independently verified, ensuring that no votes have been added, removed, or modified during the process.\n\nThe bulletin board (`bbord`) acts as a public ledger where all operations are recorded along with their proofs. This transparency allows anyone to verify the integrity of the election while maintaining voter privacy through the shuffle mechanism. \n\nFor ShuffleProofs, the important lines are:\n```julia\nsimulator = shuffle(bbord.ciphertexts_in, enc, verifier)\n```\nwhich creates a simulator containing proposition, proof and verifier as its fields, which can be verified with the:\n```julia\nverify(proposition, proof, verifier)\n```\nThis allows any party to independently verify that a shuffle was performed correctly without learning anything about the actual permutation used. To assure integrity, one then only needs to verify the verifier specification parameters accessible with the `simulator.verifier`, whereas `simulator.proposition` contains all data in one place to chain multiple shuffles together in a larger part of the protocol.\n\n\n## Braiding Example\n\nBraiding allows for anonymous group signatures. Here's how to use it:\n\n```julia\nusing CryptoGroups\nusing ShuffleProofs\nusing SigmaProofs.Verificatum: ProtocolSpec\n\n# Setup\ng = @ECGroup{P_256}()\n\n# Create member keys\ny = [4, 2, 3]\nY = g .^ y\n\n# Perform braiding\nverifier = ProtocolSpec(;g)\nsimulator = braid(Y, g, verifier)\n\n# Verify braiding\n@assert verify(simulator)\n\n# Get outputs\nh = ShuffleProofs.output_generator(simulator.proposition)\nY′ = ShuffleProofs.output_members(simulator.proposition)\n\n# Verify membership preservation\n@assert sort(h .^ y) == sort(Y′)\n```\n\nBraiding is an advanced feature that creates knot-like structures where inputs are related to outputs through privately known exponents. This is particularly useful in scenarios where group members need to prove their membership without revealing their identity, such as whistleblower protection systems or voting systems where votes are signed pseudonymously.\n\n## Working with Verificatum\n\nTo verify proofs generated by Verificatum:\n\n```julia\nsimulator = load_verificatum_simulator(DEMO_DIR)\nverify(simulator)\n```\n\nVerificatum compatibility is a key feature of ShuffleProofs.jl, allowing it to interoperate with one of the most widely deployed mix-net systems. This means proofs generated by Verificatum can be verified using this package and vice versa (in principle, if serialisation were to follow the directory structure of Verificatum specification). The implementation follows Verificatum's rigorous specification, ensuring complete compatibility.\n\n## Custom Verifiers\n\nThe package supports custom verifier implementations:\n\n```julia\nstruct HonestVerifier{T} \u003c: Verifier\n    challenge::PoSChallenge\nend\n\ngenerator_basis(verifier::HonestVerifier, G, n) = verifier.challenge.𝐡\nchallenge_perm(verifier::HonestVerifier, proposition, 𝐜) = verifier.challenge.𝐮\nchallenge_reenc(verifier::HonestVerifier, proposition, 𝐜, 𝐜̂, t) = verifier.challenge.c\n```\n\nThe verifier architecture is designed to be extensible, allowing users to implement custom verification strategies. This is particularly useful for specialised applications or research purposes where the standard verification process needs to be modified. \n\n## Performance\n### Performance Analysis\n\n- **Elliptic Curves**: ShuffleProofs matches Verificatum's single-core performance when using OpenSSL integration\n- **Modular Prime Groups**: \n  - A group membership validation via [hand-crafted Jacobi symbol calculations](https://github.com/PeaceFounder/CryptoGroups.jl/blob/0f6b4e223225634ec1506e6999f8922c079f62c7/src/Utils.jl#L24) takes a significant amount of verification time in ShuffleProofs \n  - Verificatum likely uses optimised Montgomery arithmetic (not yet implemented in ShuffleProofs) and simultaneous exponentiation also for membership validation\n- **Parallelism** Verificatum takes advantage of multiple cores in the system, as shown in performance benchmarks.\n\nIn addition, Verificatum is much more optimal in memory usage, offloading intermediate calculations to the disk, whereas ShuffleProofs keeps them all in memory, hence the large memory footprint. It would be interesting to explore in the future whether performance can be preserved with a generic disk-supported vector type streamed from a disk. \n\n### Performance Profiling\n\n![Verifier Profile](test/benchmarks/results/VerifierProfile.png)\n\nPerformance profiling reveals three major computational bottlenecks in the code: generator basis computation via `generator_basis` consumes 40% of execution time (left), verification of proof through group operations takes another 40% (right), and challenge generation via `challenge_perm` and `challenge_reenc` accounts for the remaining 20% (middle). While the generator basis computation and proof verification stages can be readily parallelised using either multithreading or multiprocessing, the challenge generation stage presents parallelisation roadblocks. Within this challenge generation phase, approximately 1/3rd of processing time is spent computing hashes from byte vectors using Nettle (highlighted in the profile view with yellow pencil fill). Hence, the specification would need to introduce block-wise hashing to parallelise this part. Nevertheless, 10x speedup is feasible with current specifications, as Verificatum demonstrates.\n\n### Performance Tips\n\n1. **Elliptic Curves** significantly outperform modular prime groups at equivalent security levels and require less memory\n2. **OpenSSL** provides a 25x speedup for elliptic curve operations over CryptoGroups basic implementation. OpenSSL can be used with the OpenSSLGroups package as follows:\n```julia\nusing OpenSSLGroups\ng = @ECGroup{OpenSSLGroups.Prime256v1}()\nverifier = ProtocolSpec(; g)\n\n# Rest of your code remains the same but runs much faster!\n```\n3. **Memory Usage:** ensure your machine has sufficient RAM to avoid disk swapping - for example, processing 1,000,000 ciphertexts requires approximately 16GB of RAM\n\n\n## References\n\n- Wikstrom, \"How To Implement A Stand-Alone Verifier for the Verificatum Mix-Net\"\n- Wikström, \"User Manual for the Verificatum Mix-Net\"\n- Wikström, \"A Sender Verifiable Mix-Net and a New Proof of a Shuffle\"\n- Haenni et al., \"Pseudo-Code Algorithms for Verifiable Re-Encryption Mix-Nets\"\n- [verificatum.org](https://verificatum.org)\n\nThese references provide the theoretical foundation and implementation details for the protocols used in this package. They are essential reading for understanding the security properties and mathematical underpinnings of the shuffle proofs.\n","funding_links":[],"categories":["Cryptography"],"sub_categories":["Zero-Knowledge Proofs"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPeaceFounder%2FShuffleProofs.jl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FPeaceFounder%2FShuffleProofs.jl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FPeaceFounder%2FShuffleProofs.jl/lists"}