{"id":15012374,"url":"https://github.com/microsoft/spartan","last_synced_at":"2025-05-14T06:11:18.752Z","repository":{"id":37417034,"uuid":"228483989","full_name":"microsoft/Spartan","owner":"microsoft","description":"Spartan: High-speed zkSNARKs without trusted setup","archived":false,"fork":false,"pushed_at":"2025-01-29T21:27:11.000Z","size":148,"stargazers_count":760,"open_issues_count":4,"forks_count":135,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-05-07T23:47:50.339Z","etag":null,"topics":["cryptography-library","nizk","rust-library","verifiable-computing","zero-knowledge-proofs","zksnarks"],"latest_commit_sha":null,"homepage":"","language":"Rust","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/microsoft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-16T22:03:06.000Z","updated_at":"2025-05-07T08:15:57.000Z","dependencies_parsed_at":"2024-01-13T23:18:10.101Z","dependency_job_id":"c53531be-59df-47af-817d-04567671e330","html_url":"https://github.com/microsoft/Spartan","commit_stats":{"total_commits":52,"total_committers":15,"mean_commits":3.466666666666667,"dds":0.3653846153846154,"last_synced_commit":"2b791bd7d572433b245eba7d5e5aeba3301ec8f5"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microsoft%2FSpartan","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microsoft%2FSpartan/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microsoft%2FSpartan/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/microsoft%2FSpartan/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/microsoft","download_url":"https://codeload.github.com/microsoft/Spartan/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254083357,"owners_count":22011864,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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-library","nizk","rust-library","verifiable-computing","zero-knowledge-proofs","zksnarks"],"created_at":"2024-09-24T19:42:32.930Z","updated_at":"2025-05-14T06:11:18.668Z","avatar_url":"https://github.com/microsoft.png","language":"Rust","readme":"# Spartan: High-speed zkSNARKs without trusted setup\n\n![Rust](https://github.com/microsoft/Spartan/actions/workflows/rust.yml/badge.svg)\n[![](https://img.shields.io/crates/v/spartan.svg)](\u003c(https://crates.io/crates/spartan)\u003e)\n\nSpartan is a high-speed zero-knowledge proof system, a cryptographic primitive that enables a prover to prove a mathematical statement to a verifier without revealing anything besides the validity of the statement. This repository provides `libspartan,` a Rust library that implements a zero-knowledge succinct non-interactive argument of knowledge (zkSNARK), which is a type of zero-knowledge proof system with short proofs and fast verification times. The details of the Spartan proof system are described in our [paper](https://eprint.iacr.org/2019/550) published at [CRYPTO 2020](https://crypto.iacr.org/2020/). The security of the Spartan variant implemented in this library is based on the discrete logarithm problem in the random oracle model.\n\nA simple example application is proving the knowledge of a secret s such that H(s) == d for a public d, where H is a cryptographic hash function (e.g., SHA-256, Keccak). A more complex application is a database-backed cloud service that produces proofs of correct state machine transitions for auditability. See this [paper](https://eprint.iacr.org/2020/758.pdf) for an overview and this [paper](https://eprint.iacr.org/2018/907.pdf) for details.\n\nNote that this library has _not_ received a security review or audit.\n\n## Highlights\n\nWe now highlight Spartan's distinctive features.\n\n- **No \"toxic\" waste:** Spartan is a _transparent_ zkSNARK and does not require a trusted setup. So, it does not involve any trapdoors that must be kept secret or require a multi-party ceremony to produce public parameters.\n\n- **General-purpose:** Spartan produces proofs for arbitrary NP statements. `libspartan` supports NP statements expressed as rank-1 constraint satisfiability (R1CS) instances, a popular language for which there exists efficient transformations and compiler toolchains from high-level programs of interest.\n\n- **Sub-linear verification costs:** Spartan is the first transparent proof system with sub-linear verification costs for arbitrary NP statements (e.g., R1CS).\n\n- **Standardized security:** Spartan's security relies on the hardness of computing discrete logarithms (a standard cryptographic assumption) in the random oracle model. `libspartan` uses `ristretto255`, a prime-order group abstraction atop `curve25519` (a high-speed elliptic curve). We use [`curve25519-dalek`](https://docs.rs/curve25519-dalek) for arithmetic over `ristretto255`.\n\n- **State-of-the-art performance:**\n  Among transparent SNARKs, Spartan offers the fastest prover with speedups of 36–152× depending on the baseline, produces proofs that are shorter by 1.2–416×, and incurs the lowest verification times with speedups of 3.6–1326×. The only exception is proof sizes under Bulletproofs, but Bulletproofs incurs slower verification both asymptotically and concretely. When compared to the state-of-the-art zkSNARK with trusted setup, Spartan’s prover is 2× faster for arbitrary R1CS instances and 16× faster for data-parallel workloads.\n\n### Implementation details\n\n`libspartan` uses [`merlin`](https://docs.rs/merlin/) to automate the Fiat-Shamir transform. We also introduce a new type called `RandomTape` that extends a `Transcript` in `merlin` to allow the prover's internal methods to produce private randomness using its private transcript without having to create `OsRng` objects throughout the code. An object of type `RandomTape` is initialized with a new random seed from `OsRng` for each proof produced by the library.\n\n## Examples\n\nTo import `libspartan` into your Rust project, add the following dependency to `Cargo.toml`:\n\n```text\nspartan = \"0.8.0\"\n```\n\nThe following example shows how to use `libspartan` to create and verify a SNARK proof.\nSome of our public APIs' style is inspired by the underlying crates we use.\n\n```rust\nextern crate libspartan;\nextern crate merlin;\nuse libspartan::{Instance, SNARKGens, SNARK};\nuse merlin::Transcript;\nfn main() {\n    // specify the size of an R1CS instance\n    let num_vars = 1024;\n    let num_cons = 1024;\n    let num_inputs = 10;\n    let num_non_zero_entries = 1024;\n\n    // produce public parameters\n    let gens = SNARKGens::new(num_cons, num_vars, num_inputs, num_non_zero_entries);\n\n    // ask the library to produce a synthentic R1CS instance\n    let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);\n\n    // create a commitment to the R1CS instance\n    let (comm, decomm) = SNARK::encode(\u0026inst, \u0026gens);\n\n    // produce a proof of satisfiability\n    let mut prover_transcript = Transcript::new(b\"snark_example\");\n    let proof = SNARK::prove(\u0026inst, \u0026comm, \u0026decomm, vars, \u0026inputs, \u0026gens, \u0026mut prover_transcript);\n\n    // verify the proof of satisfiability\n    let mut verifier_transcript = Transcript::new(b\"snark_example\");\n    assert!(proof\n      .verify(\u0026comm, \u0026inputs, \u0026mut verifier_transcript, \u0026gens)\n      .is_ok());\n    println!(\"proof verification successful!\");\n}\n```\n\nHere is another example to use the NIZK variant of the Spartan proof system:\n\n```rust\nextern crate libspartan;\nextern crate merlin;\nuse libspartan::{Instance, NIZKGens, NIZK};\nuse merlin::Transcript;\nfn main() {\n    // specify the size of an R1CS instance\n    let num_vars = 1024;\n    let num_cons = 1024;\n    let num_inputs = 10;\n\n    // produce public parameters\n    let gens = NIZKGens::new(num_cons, num_vars, num_inputs);\n\n    // ask the library to produce a synthentic R1CS instance\n    let (inst, vars, inputs) = Instance::produce_synthetic_r1cs(num_cons, num_vars, num_inputs);\n\n    // produce a proof of satisfiability\n    let mut prover_transcript = Transcript::new(b\"nizk_example\");\n    let proof = NIZK::prove(\u0026inst, vars, \u0026inputs, \u0026gens, \u0026mut prover_transcript);\n\n    // verify the proof of satisfiability\n    let mut verifier_transcript = Transcript::new(b\"nizk_example\");\n    assert!(proof\n      .verify(\u0026inst, \u0026inputs, \u0026mut verifier_transcript, \u0026gens)\n      .is_ok());\n    println!(\"proof verification successful!\");\n}\n```\n\nFinally, we provide an example that specifies a custom R1CS instance instead of using a synthetic instance\n\n```rust\n#![allow(non_snake_case)]\nextern crate curve25519_dalek;\nextern crate libspartan;\nextern crate merlin;\nuse curve25519_dalek::scalar::Scalar;\nuse libspartan::{InputsAssignment, Instance, SNARKGens, VarsAssignment, SNARK};\nuse merlin::Transcript;\nuse rand::rngs::OsRng;\n\nfn main() {\n  // produce a tiny instance\n  let (\n    num_cons,\n    num_vars,\n    num_inputs,\n    num_non_zero_entries,\n    inst,\n    assignment_vars,\n    assignment_inputs,\n  ) = produce_tiny_r1cs();\n\n  // produce public parameters\n  let gens = SNARKGens::new(num_cons, num_vars, num_inputs, num_non_zero_entries);\n\n  // create a commitment to the R1CS instance\n  let (comm, decomm) = SNARK::encode(\u0026inst, \u0026gens);\n\n  // produce a proof of satisfiability\n  let mut prover_transcript = Transcript::new(b\"snark_example\");\n  let proof = SNARK::prove(\n    \u0026inst,\n    \u0026comm,\n    \u0026decomm,\n    assignment_vars,\n    \u0026assignment_inputs,\n    \u0026gens,\n    \u0026mut prover_transcript,\n  );\n\n  // verify the proof of satisfiability\n  let mut verifier_transcript = Transcript::new(b\"snark_example\");\n  assert!(proof\n    .verify(\u0026comm, \u0026assignment_inputs, \u0026mut verifier_transcript, \u0026gens)\n    .is_ok());\n  println!(\"proof verification successful!\");\n}\n\nfn produce_tiny_r1cs() -\u003e (\n usize,\n usize,\n usize,\n usize,\n Instance,\n VarsAssignment,\n InputsAssignment,\n) {\n  // We will use the following example, but one could construct any R1CS instance.\n  // Our R1CS instance is three constraints over five variables and two public inputs\n  // (Z0 + Z1) * I0 - Z2 = 0\n  // (Z0 + I1) * Z2 - Z3 = 0\n  // Z4 * 1 - 0 = 0\n\n  // parameters of the R1CS instance rounded to the nearest power of two\n  let num_cons = 4;\n  let num_vars = 5;\n  let num_inputs = 2;\n  let num_non_zero_entries = 5;\n\n  // We will encode the above constraints into three matrices, where\n  // the coefficients in the matrix are in the little-endian byte order\n  let mut A: Vec\u003c(usize, usize, [u8; 32])\u003e = Vec::new();\n  let mut B: Vec\u003c(usize, usize, [u8; 32])\u003e = Vec::new();\n  let mut C: Vec\u003c(usize, usize, [u8; 32])\u003e = Vec::new();\n\n  // The constraint system is defined over a finite field, which in our case is\n  // the scalar field of ristreeto255/curve25519 i.e., p =  2^{252}+27742317777372353535851937790883648493\n  // To construct these matrices, we will use `curve25519-dalek` but one can use any other method.\n\n  // a variable that holds a byte representation of 1\n  let one = Scalar::ONE.to_bytes();\n\n  // R1CS is a set of three sparse matrices A B C, where is a row for every\n  // constraint and a column for every entry in z = (vars, 1, inputs)\n  // An R1CS instance is satisfiable iff:\n  // Az \\circ Bz = Cz, where z = (vars, 1, inputs)\n\n  // constraint 0 entries in (A,B,C)\n  // constraint 0 is (Z0 + Z1) * I0 - Z2 = 0.\n  // We set 1 in matrix A for columns that correspond to Z0 and Z1\n  // We set 1 in matrix B for column that corresponds to I0\n  // We set 1 in matrix C for column that corresponds to Z2\n  A.push((0, 0, one));\n  A.push((0, 1, one));\n  B.push((0, num_vars + 1, one));\n  C.push((0, 2, one));\n\n  // constraint 1 entries in (A,B,C)\n  A.push((1, 0, one));\n  A.push((1, num_vars + 2, one));\n  B.push((1, 2, one));\n  C.push((1, 3, one));\n\n  // constraint 3 entries in (A,B,C)\n  A.push((2, 4, one));\n  B.push((2, num_vars, one));\n\n  let inst = Instance::new(num_cons, num_vars, num_inputs, \u0026A, \u0026B, \u0026C).unwrap();\n\n  // compute a satisfying assignment\n  let mut csprng: OsRng = OsRng;\n  let i0 = Scalar::random(\u0026mut csprng);\n  let i1 = Scalar::random(\u0026mut csprng);\n  let z0 = Scalar::random(\u0026mut csprng);\n  let z1 = Scalar::random(\u0026mut csprng);\n  let z2 = (z0 + z1) * i0; // constraint 0\n  let z3 = (z0 + i1) * z2; // constraint 1\n  let z4 = Scalar::ZERO; //constraint 2\n\n  // create a VarsAssignment\n  let mut vars = vec![Scalar::ZERO.to_bytes(); num_vars];\n  vars[0] = z0.to_bytes();\n  vars[1] = z1.to_bytes();\n  vars[2] = z2.to_bytes();\n  vars[3] = z3.to_bytes();\n  vars[4] = z4.to_bytes();\n  let assignment_vars = VarsAssignment::new(\u0026vars).unwrap();\n\n  // create an InputsAssignment\n  let mut inputs = vec![Scalar::ZERO.to_bytes(); num_inputs];\n  inputs[0] = i0.to_bytes();\n  inputs[1] = i1.to_bytes();\n  let assignment_inputs = InputsAssignment::new(\u0026inputs).unwrap();\n\n  // check if the instance we created is satisfiable\n  let res = inst.is_sat(\u0026assignment_vars, \u0026assignment_inputs);\n  assert_eq!(res.unwrap(), true);\n\n  (\n    num_cons,\n    num_vars,\n    num_inputs,\n    num_non_zero_entries,\n    inst,\n    assignment_vars,\n    assignment_inputs,\n  )\n }\n```\n\nFor more examples, see [`examples/`](examples) directory in this repo.\n\n## Building `libspartan`\n\nInstall [`rustup`](https://rustup.rs/)\n\nSwitch to nightly Rust using `rustup`:\n\n```text\nrustup default nightly\n```\n\nClone the repository:\n\n```text\ngit clone https://github.com/Microsoft/Spartan\ncd Spartan\n```\n\nTo build docs for public APIs of `libspartan`:\n\n```text\ncargo doc\n```\n\nTo run tests:\n\n```text\nRUSTFLAGS=\"-C target_cpu=native\" cargo test\n```\n\nTo build `libspartan`:\n\n```text\nRUSTFLAGS=\"-C target_cpu=native\" cargo build --release\n```\n\n\u003e NOTE: We enable SIMD instructions in `curve25519-dalek` by default, so if it fails to build remove the \"simd_backend\" feature argument in `Cargo.toml`.\n\n### Supported features\n\n- `std`: enables std features (enabled by default)\n- `simd_backend`: enables `curve25519-dalek`'s simd feature (enabled by default)\n- `profile`: enables fine-grained profiling information (see below for its use)\n\n### WASM Support\n\n`libspartan` depends upon `rand::OsRng` (internally uses `getrandom` crate), it has out of box support for `wasm32-wasi`.\n\nFor the target `wasm32-unknown-unknown` disable default features for spartan\nand add direct dependency on `getrandom` with `wasm-bindgen` feature enabled.\n\n```toml\n[dependencies]\nspartan = { version = \"0.7\", default-features = false }\n# since spartan uses getrandom(rand's OsRng), we need to enable 'wasm-bindgen'\n# feature to make it feed rand seed from js/nodejs env\n# https://docs.rs/getrandom/0.1.16/getrandom/index.html#support-for-webassembly-and-asmjs\ngetrandom = { version = \"0.1\", features = [\"wasm-bindgen\"] }\n```\n\n## Performance\n\n### End-to-end benchmarks\n\n`libspartan` includes two benches: `benches/nizk.rs` and `benches/snark.rs`. If you report the performance of Spartan in a research paper, we recommend using these benches for higher accuracy instead of fine-grained profiling (listed below).\n\nTo run end-to-end benchmarks:\n\n```text\nRUSTFLAGS=\"-C target_cpu=native\" cargo bench\n```\n\n### Fine-grained profiling\n\nBuild `libspartan` with `profile` feature enabled. It creates two profilers: `./target/release/snark` and `./target/release/nizk`.\n\nThese profilers report performance as depicted below (for varying R1CS instance sizes). The reported\nperformance is from running the profilers on a Microsoft Surface Laptop 3 on a single CPU core of Intel Core i7-1065G7 running Ubuntu 20.04 (atop WSL2 on Windows 10).\nSee Section 9 in our [paper](https://eprint.iacr.org/2019/550) to see how this compares with other zkSNARKs in the literature.\n\n```text\n$ ./target/release/snark\nProfiler:: SNARK\n  * number_of_constraints 1048576\n  * number_of_variables 1048576\n  * number_of_inputs 10\n  * number_non-zero_entries_A 1048576\n  * number_non-zero_entries_B 1048576\n  * number_non-zero_entries_C 1048576\n  * SNARK::encode\n  * SNARK::encode 14.2644201s\n  * SNARK::prove\n    * R1CSProof::prove\n      * polycommit\n      * polycommit 2.7175848s\n      * prove_sc_phase_one\n      * prove_sc_phase_one 683.7481ms\n      * prove_sc_phase_two\n      * prove_sc_phase_two 846.1056ms\n      * polyeval\n      * polyeval 193.4216ms\n    * R1CSProof::prove 4.4416193s\n    * len_r1cs_sat_proof 47024\n    * eval_sparse_polys\n    * eval_sparse_polys 377.357ms\n    * R1CSEvalProof::prove\n      * commit_nondet_witness\n      * commit_nondet_witness 14.4507331s\n      * build_layered_network\n      * build_layered_network 3.4360521s\n      * evalproof_layered_network\n        * len_product_layer_proof 64712\n      * evalproof_layered_network 15.5708066s\n    * R1CSEvalProof::prove 34.2930559s\n    * len_r1cs_eval_proof 133720\n  * SNARK::prove 39.1297568s\n  * SNARK::proof_compressed_len 141768\n  * SNARK::verify\n    * verify_sat_proof\n    * verify_sat_proof 20.0828ms\n    * verify_eval_proof\n      * verify_polyeval_proof\n        * verify_prod_proof\n        * verify_prod_proof 1.1847ms\n        * verify_hash_proof\n        * verify_hash_proof 81.06ms\n      * verify_polyeval_proof 82.3583ms\n    * verify_eval_proof 82.8937ms\n  * SNARK::verify 103.0536ms\n```\n\n```text\n$ ./target/release/nizk\nProfiler:: NIZK\n  * number_of_constraints 1048576\n  * number_of_variables 1048576\n  * number_of_inputs 10\n  * number_non-zero_entries_A 1048576\n  * number_non-zero_entries_B 1048576\n  * number_non-zero_entries_C 1048576\n  * NIZK::prove\n    * R1CSProof::prove\n      * polycommit\n      * polycommit 2.7220635s\n      * prove_sc_phase_one\n      * prove_sc_phase_one 722.5487ms\n      * prove_sc_phase_two\n      * prove_sc_phase_two 862.6796ms\n      * polyeval\n      * polyeval 190.2233ms\n    * R1CSProof::prove 4.4982305s\n    * len_r1cs_sat_proof 47024\n  * NIZK::prove 4.5139888s\n  * NIZK::proof_compressed_len 48134\n  * NIZK::verify\n    * eval_sparse_polys\n    * eval_sparse_polys 395.0847ms\n    * verify_sat_proof\n    * verify_sat_proof 19.286ms\n  * NIZK::verify 414.5102ms\n```\n\n## LICENSE\n\nSee [LICENSE](./LICENSE)\n\n## Contributing\n\nSee [CONTRIBUTING](./CONTRIBUTING.md)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicrosoft%2Fspartan","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmicrosoft%2Fspartan","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmicrosoft%2Fspartan/lists"}