├── .gitignore ├── circuits ├── src │ ├── binary.rs │ ├── lib.rs │ ├── adapters │ │ ├── mod.rs │ │ └── r1cs.rs │ ├── interfaces.rs │ └── primitives.rs ├── Cargo.toml └── README.md ├── schnorr ├── .gitignore ├── Cargo.toml └── src │ ├── lib.rs │ └── core.rs ├── circom-groth16 ├── README.md ├── circuit.sym ├── circuit.r1cs ├── assets │ └── circuit.circom ├── Cargo.toml └── src │ └── main.rs ├── playground ├── src │ └── main.rs └── Cargo.toml ├── polynomial ├── src │ ├── composed │ │ ├── mod.rs │ │ ├── interfaces.rs │ │ └── multilinear.rs │ ├── lib.rs │ ├── multivariate.rs │ ├── interface.rs │ └── utils.rs ├── Cargo.toml ├── README.md └── Cargo.lock ├── succinct-gkr ├── src │ └── main.rs └── Cargo.toml ├── gkr ├── src │ ├── lib.rs │ ├── interfaces.rs │ ├── primitives.rs │ ├── utils.rs │ └── protocol.rs ├── Cargo.toml ├── README.md └── benches │ └── gkr_protocol_benchmark.rs ├── groth16 ├── src │ ├── tests │ │ ├── mod.rs │ │ └── protocol.rs │ ├── lib.rs │ ├── interfaces.rs │ ├── preprocessing.rs │ ├── trusted_setup.rs │ ├── protocol.rs │ ├── primitives.rs │ └── utils.rs ├── Cargo.toml └── README.md ├── assets └── sum check protocol.png ├── sha256-hash-function ├── src │ ├── lib.rs │ ├── operations.rs │ ├── constants.rs │ ├── interface.rs │ └── functions.rs ├── Cargo.toml └── README.md ├── sum_check ├── src │ ├── lib.rs │ ├── data_structure.rs │ ├── composed │ │ ├── utils.rs │ │ ├── mod.rs │ │ ├── verifier.rs │ │ └── prover.rs │ ├── interface.rs │ ├── verifier.rs │ └── prover.rs ├── Cargo.toml ├── README.md └── benches │ └── sum_check_benchmark.rs ├── fiat_shamir ├── Cargo.toml ├── src │ ├── interface.rs │ └── lib.rs └── README.md ├── polynomial-commitment-schemes └── kzg-rust │ ├── src │ ├── lib.rs │ ├── primitives.rs │ ├── multilinear.rs │ ├── interface.rs │ ├── univariate.rs │ └── utils.rs │ └── Cargo.toml ├── bls-multi-sign-threshold-wallet ├── Cargo.toml └── src │ └── main.rs ├── Cargo.toml └── .gitmodules /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | -------------------------------------------------------------------------------- /circuits/src/binary.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /schnorr/.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /circom-groth16/README.md: -------------------------------------------------------------------------------- 1 | ### This is really a work in progress!! -------------------------------------------------------------------------------- /circom-groth16/circuit.sym: -------------------------------------------------------------------------------- 1 | 1,1,0,main.c 2 | 2,2,0,main.a 3 | 3,3,0,main.b 4 | -------------------------------------------------------------------------------- /playground/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /polynomial/src/composed/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod interfaces; 2 | pub mod multilinear; 3 | -------------------------------------------------------------------------------- /succinct-gkr/src/main.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("Hello, world!"); 3 | } 4 | -------------------------------------------------------------------------------- /gkr/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod interfaces; 2 | pub mod primitives; 3 | pub mod protocol; 4 | pub mod utils; 5 | -------------------------------------------------------------------------------- /groth16/src/tests/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod preprocessing; 3 | #[cfg(test)] 4 | mod protocol; 5 | -------------------------------------------------------------------------------- /circom-groth16/circuit.r1cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Daniolet/Cryptography-N-ZK/HEAD/circom-groth16/circuit.r1cs -------------------------------------------------------------------------------- /assets/sum check protocol.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Daniolet/Cryptography-N-ZK/HEAD/assets/sum check protocol.png -------------------------------------------------------------------------------- /sha256-hash-function/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod constants; 2 | pub mod functions; 3 | pub mod interface; 4 | pub mod operations; 5 | -------------------------------------------------------------------------------- /sum_check/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod composed; 2 | pub mod data_structure; 3 | pub mod interface; 4 | pub mod prover; 5 | pub mod verifier; 6 | -------------------------------------------------------------------------------- /sha256-hash-function/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sha256-hash-function" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /circuits/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod adapters; 2 | pub mod arithmetic; 3 | pub mod binary; 4 | pub mod interfaces; 5 | pub mod primitives; 6 | pub mod utils; 7 | -------------------------------------------------------------------------------- /fiat_shamir/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "fiat_shamir" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | sha3 = "0.10.8" 8 | ark-ff = "0.4.2" -------------------------------------------------------------------------------- /polynomial-commitment-schemes/kzg-rust/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod interface; 2 | pub mod multilinear; 3 | pub mod primitives; 4 | pub mod univariate; 5 | pub mod utils; 6 | -------------------------------------------------------------------------------- /groth16/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod interfaces; 2 | pub mod preprocessing; 3 | pub mod primitives; 4 | pub mod protocol; 5 | pub mod tests; 6 | pub mod trusted_setup; 7 | pub mod utils; 8 | -------------------------------------------------------------------------------- /circuits/src/adapters/mod.rs: -------------------------------------------------------------------------------- 1 | //! This module provides interfaces and implementaions for transpiling a circuit into other 2 | //! intermidiate arithmetic representations. E.g. R1CS, AIR, and so on. 3 | 4 | pub mod r1cs; 5 | -------------------------------------------------------------------------------- /schnorr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "schnorr" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | lambdaworks-math = "0.5.0" 8 | rand = "0.8.5" 9 | sha256 = "1.5.0" 10 | anyhow = "1.0.83" 11 | -------------------------------------------------------------------------------- /bls-multi-sign-threshold-wallet/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "bls-multi-sign-threshold-wallet" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | polynomial = {path = "../polynomial"} 8 | rand = "0.8.5" 9 | -------------------------------------------------------------------------------- /succinct-gkr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "succinct-gkr" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | -------------------------------------------------------------------------------- /polynomial/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub use ark_ff; 2 | pub use ark_poly; 3 | pub use ark_test_curves; 4 | pub mod composed; 5 | pub mod interface; 6 | pub mod multilinear; 7 | pub mod multivariate; 8 | pub mod univariant; 9 | pub mod utils; 10 | -------------------------------------------------------------------------------- /circuits/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "circuits" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | ark-ff = "0.4.2" 8 | ark-test-curves = {version = "0.4.2", features = ["bls12_381_scalar_field", "bls12_381_curve", "ed_on_bls12_381"]} 9 | polynomial = {path = "../polynomial"} 10 | -------------------------------------------------------------------------------- /polynomial/src/composed/interfaces.rs: -------------------------------------------------------------------------------- 1 | use ark_ff::PrimeField; 2 | 3 | pub trait ComposedMultilinearInterface { 4 | /// Returns the element wise product of the polymonials 5 | fn elementwise_product(&self) -> Vec; 6 | /// Returns the possible maximum degree of the composed polynomial 7 | fn max_degree(&self) -> usize; 8 | } 9 | -------------------------------------------------------------------------------- /polynomial/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "polynomial" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | ark-poly = "0.4.2" 8 | ark-ff = "0.4.2" 9 | ark-test-curves = {version = "0.4.2", features = ["bls12_381_scalar_field", "bls12_381_curve", "ed_on_bls12_381"]} 10 | ark-serialize = "0.4.2" 11 | digest = "0.10.7" 12 | ark-std.workspace = true -------------------------------------------------------------------------------- /circom-groth16/assets/circuit.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | /*This circuit template checks that c is the multiplication of a and b.*/ 4 | 5 | template Multiplier2 () { 6 | 7 | // Declaration of signals. 8 | signal input a; 9 | signal input b; 10 | signal output c; 11 | 12 | // Constraints. 13 | c <== a * b; 14 | } 15 | 16 | component main = Multiplier2(); -------------------------------------------------------------------------------- /sha256-hash-function/src/operations.rs: -------------------------------------------------------------------------------- 1 | /// This function is used to perform the XOR operation 2 | pub fn xor(a: u32, b: u32) -> u32 { 3 | a ^ b 4 | } 5 | 6 | /// This is for doing a bit shift right 7 | pub fn right_shift(x: u32, round: u32) -> u32 { 8 | x >> round 9 | } 10 | 11 | /// This is for doing a rotate right 12 | pub fn rotate_right(x: u32, n: u32) -> u32 { 13 | x.rotate_right(n) 14 | } 15 | -------------------------------------------------------------------------------- /polynomial-commitment-schemes/kzg-rust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "kzg-rust" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | ark-ff = "0.4.2" 8 | ark-ec = "0.4.2" 9 | ark-bls12-381 = "0.4.0" 10 | ark-test-curves = {version = "0.4.2", features = ["bls12_381_scalar_field", "bls12_381_curve", "ed_on_bls12_381"]} 11 | polynomial.workspace = true 12 | circuits.workspace = true 13 | rand = "0.8.4" -------------------------------------------------------------------------------- /groth16/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "groth16" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | ark-ff = "0.4.2" 8 | ark-ec = "0.4.2" 9 | ark-bls12-381 = "0.4.0" 10 | ark-test-curves = {version = "0.4.2", features = ["bls12_381_scalar_field", "bls12_381_curve", "ed_on_bls12_381", "secp256k1"]} 11 | polynomial = {path = "../polynomial"} 12 | circuits = {path = "../circuits"} 13 | rand = "0.8.4" 14 | hex-literal = "0.4.1" -------------------------------------------------------------------------------- /circom-groth16/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "circom-groth16" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | groth16 = {path = "../groth16"} 8 | ark-circom = { git = "https://github.com/developeruche/circom-compat.git"} 9 | ark-ff = { version = "0.4.2", default-features = false, features = ["parallel", "asm"] } 10 | ark-std = { version = "=0.4.0", default-features = false, features = ["parallel"] } 11 | ark-bn254 = { version = "=0.4.0" } -------------------------------------------------------------------------------- /sum_check/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sum_check" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | ark-ff = "0.4.2" 8 | ark-test-curves = {version = "0.4.2", features = ["bls12_381_scalar_field", "bls12_381_curve", "ed_on_bls12_381"]} 9 | polynomial = {path = "../polynomial"} 10 | fiat_shamir = {path = "../fiat_shamir"} 11 | 12 | 13 | 14 | 15 | [dev-dependencies] 16 | criterion = "0.5.1" 17 | 18 | 19 | [[bench]] 20 | name = "sum_check_benchmark" 21 | harness = false 22 | 23 | -------------------------------------------------------------------------------- /gkr/src/interfaces.rs: -------------------------------------------------------------------------------- 1 | use crate::primitives::GKRProof; 2 | use ark_ff::PrimeField; 3 | use circuits::primitives::{Circuit, CircuitEvaluation}; 4 | 5 | /// This is the interface for the GKR protocol 6 | pub trait GKRProtocolInterface { 7 | /// This function is used to create GKR proofs 8 | fn prove(circuit: &Circuit, evals: &CircuitEvaluation) -> GKRProof; 9 | 10 | /// This function is used to verify GKR proofs 11 | fn verify(circuit: &Circuit, input: &[F], proof: &GKRProof) -> bool; 12 | } 13 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "polynomial", 4 | "bls-multi-sign-threshold-wallet", 5 | "fiat_shamir", 6 | "sum_check", 7 | "sha256-hash-function", 8 | "gkr", 9 | "circuits", 10 | "groth16", 11 | "polynomial-commitment-schemes/kzg-rust", 12 | "playground", 13 | "succinct-gkr", 14 | ] 15 | exclude = [ 16 | "circom-groth16" 17 | ] 18 | 19 | 20 | [workspace.dependencies] 21 | polynomial = { path = "polynomial" } 22 | circuits = { path = "circuits" } 23 | ark-std = "0.4.0" 24 | -------------------------------------------------------------------------------- /playground/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "playground" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | ark-secp256k1 = "0.4.0" 10 | ark-ff = "0.4.2" 11 | ark-ec = "0.4.2" 12 | ark-bls12-381 = "0.4.0" 13 | ark-test-curves = {version = "0.4.2", features = ["bls12_381_scalar_field", "bls12_381_curve", "ed_on_bls12_381", "secp256k1"]} 14 | polynomial = {path = "../polynomial"} 15 | circuits = {path = "../circuits"} 16 | rand = "0.8.4" -------------------------------------------------------------------------------- /gkr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "gkr" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | ark-ff = "0.4.2" 8 | ark-test-curves = {version = "0.4.2", features = ["bls12_381_scalar_field", "bls12_381_curve", "ed_on_bls12_381"]} 9 | polynomial = {path = "../polynomial"} 10 | fiat_shamir = {path = "../fiat_shamir"} 11 | sum_check = {path = "../sum_check"} 12 | circuits = {path = "../circuits"} 13 | 14 | 15 | 16 | [dev-dependencies] 17 | criterion = "0.5.1" 18 | 19 | 20 | [[bench]] 21 | name = "gkr_protocol_benchmark" 22 | harness = false 23 | -------------------------------------------------------------------------------- /polynomial-commitment-schemes/kzg-rust/src/primitives.rs: -------------------------------------------------------------------------------- 1 | use ark_ec::pairing::Pairing; 2 | 3 | #[derive(Clone, PartialEq, Eq, Hash, Default, Debug)] 4 | pub struct SRS { 5 | pub g1_power_of_taus: Vec, 6 | pub g2_power_of_tau: P::G2, 7 | } 8 | 9 | #[derive(Clone, PartialEq, Eq, Hash, Default, Debug)] 10 | pub struct MultiLinearSRS { 11 | pub g1_power_of_taus: Vec, // this is an expression of g1^tau^i over the boolean hypercube (every possible combination of each monomial) 12 | pub g2_power_of_taus: Vec, // this is a vector of g2^tau^i 13 | } 14 | -------------------------------------------------------------------------------- /gkr/README.md: -------------------------------------------------------------------------------- 1 | The GKR protocol is very fascinating, fairly not so complicated compared to other protocols but heavily generic and useful. The GKR protocol involves running one protocol (Sum check) inside this protocol (GKR). The GKR protocol, named after Shafi Goldwasser, Yael Tauman Kalai, and Guy N. Rothblum, is a zero-knowledge proof protocol that focuses on efficient delegation of computation. Specifically, it is designed to verify computations represented as layered arithmetic circuits with logarithmic depth in the number of inputs. The GKR protocol is known for its efficiency and ability to handle large-scale computations. 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ecdsa-rust"] 2 | path = ecdsa-rust 3 | url = https://github.com/developeruche/ecdsa-rust 4 | [submodule "kzg-airdrop-bn254"] 5 | path = kzg-airdrop-bn254 6 | url = https://github.com/developeruche/kzg-airdrop-bn254 7 | [submodule "light-tornodo-cash"] 8 | path = light-tornodo-cash 9 | url = https://github.com/developeruche/light-tornodo-cash 10 | [submodule "non-interactive-chaum-pedersen-lib"] 11 | path = non-interactive-chaum-pedersen-lib 12 | url = https://github.com/developeruche/non-interactive-chaum-pedersen-lib 13 | [submodule "vrf-rust-solidity"] 14 | path = vrf-rust-solidity 15 | url = https://github.com/developeruche/vrf-rust-solidity 16 | -------------------------------------------------------------------------------- /sum_check/src/data_structure.rs: -------------------------------------------------------------------------------- 1 | use ark_ff::PrimeField; 2 | use polynomial::interface::MultilinearPolynomialInterface; 3 | 4 | /// This struct is used to store the sum check proof 5 | #[derive(Clone, PartialEq, Eq, Hash, Default, Debug)] 6 | pub struct SumCheckProof> { 7 | /// This is the polynomial that is used to generate the sum check proof 8 | pub polynomial: P, 9 | /// This vector stores the round polynomials 10 | pub round_poly: Vec

, 11 | /// This vectors store the polynomial from the first round 12 | pub round_0_poly: P, 13 | /// This holds the sum of the polynomial evaluation over the boolean hypercube 14 | pub sum: F, 15 | } 16 | -------------------------------------------------------------------------------- /gkr/src/primitives.rs: -------------------------------------------------------------------------------- 1 | use ark_ff::PrimeField; 2 | use polynomial::multilinear::Multilinear; 3 | use sum_check::composed::ComposedSumCheckProof; 4 | 5 | #[derive(Clone, PartialEq, Eq, Hash, Default, Debug)] 6 | pub struct GKRProof { 7 | /// This is the list of sum check proofs gotten during this protocol 8 | pub sum_check_proofs: Vec>, 9 | /// This is a vector contain result of eval of w_i(b) 10 | pub w_i_b: Vec, 11 | /// This is a vector contain result of eval of w_i(c) 12 | pub w_i_c: Vec, 13 | /// This is a multilinear polynomial representing the output of the Circuit 14 | pub w_0_mle: Multilinear, 15 | } 16 | 17 | #[cfg(test)] 18 | mod tests { 19 | use super::*; 20 | use ark_test_curves::bls12_381::Fr; 21 | } 22 | -------------------------------------------------------------------------------- /circom-groth16/src/main.rs: -------------------------------------------------------------------------------- 1 | use ark_circom::{CircomBuilder, CircomConfig}; 2 | use ark_std::rand::thread_rng; 3 | use ark_bn254::Bn254; 4 | 5 | 6 | type Groth16Protocol = groth16::protocol::Groth16Protocol; 7 | 8 | fn main() { 9 | // Load the WASM and R1CS for witness and proof generation 10 | let cfg = CircomConfig::::new( 11 | "./assets/mycircuit.wasm", 12 | "./assets/mycircuit.r1cs", 13 | ).unwrap(); 14 | 15 | // Insert our public inputs as key value pairs 16 | let mut builder = CircomBuilder::new(cfg); 17 | builder.push_input("a", 3); 18 | builder.push_input("b", 11); 19 | 20 | // Create an empty instance for setting it up 21 | let circom = builder.setup(); 22 | 23 | // Run a trusted setup 24 | let mut rng = thread_rng(); 25 | } -------------------------------------------------------------------------------- /fiat_shamir/src/interface.rs: -------------------------------------------------------------------------------- 1 | use ark_ff::PrimeField; 2 | 3 | /// This is a generic interface for the fiat shamir transcript. 4 | pub trait TranscriptInterface { 5 | /// This is used to append a message to the transcript. 6 | fn append(&mut self, msg: Vec); 7 | /// This is used to get the challenge from the transcript. 8 | fn sample(&mut self) -> [u8; 32]; 9 | /// This is used to sample n challenges from the transcript. 10 | fn sample_n(&mut self, n: usize) -> Vec<[u8; 32]>; 11 | /// This is used to sample n challenges from the transcript as field elements. 12 | fn sample_n_as_field_elements(&mut self, n: usize) -> Vec; 13 | /// This is used to sample a challenge from the transcript as a field element. 14 | fn sample_as_field_element(&mut self) -> F; 15 | } 16 | -------------------------------------------------------------------------------- /fiat_shamir/README.md: -------------------------------------------------------------------------------- 1 | # Fiat Shamir Transcirpt 2 | The Fiat-Shamir transcript is a cryptographic technique used to transform an interactive proof system into a non-interactive one. This transformation enhances the efficiency and practicality of certain cryptographic protocols, including zero-knowledge proofs, by eliminating the need for interaction between the prover and the verifier. 3 | 4 | 5 | ### TranscriptInterface 6 | 7 | The Fiat Shamir transcript would have these two functions; 8 | 1. `append`: This is used by the prover to simulate the prover sending a message to the verifier. This function only appends `Bytes` as all these can be converted to and from `Bytes` 9 | 2. `sample`: This is used by the prover to simulate a random reply from the verifier, this is powered by a `Random Oracle Model` using a hash function as the source of `Pseudo` randomness. would be making use of the `sha3` crate for the source of random. -------------------------------------------------------------------------------- /sha256-hash-function/src/constants.rs: -------------------------------------------------------------------------------- 1 | pub const K: [u32; 64] = [ 2 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 3 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 4 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 5 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 6 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 7 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 8 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 9 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, 10 | ]; 11 | 12 | pub const H: [u32; 8] = [ 13 | 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, 14 | ]; 15 | -------------------------------------------------------------------------------- /circuits/src/interfaces.rs: -------------------------------------------------------------------------------- 1 | use crate::primitives::{CircuitEvaluation, ConstraintsWithLabelSize}; 2 | use ark_ff::PrimeField; 3 | use polynomial::multilinear::Multilinear; 4 | use std::ops::{Add, Mul}; 5 | 6 | /// This is the interface for the circuit 7 | pub trait CircuitInterface { 8 | /// This function evaluates the circuit 9 | fn evaluate(&self, input: &[F]) -> CircuitEvaluation 10 | where 11 | F: Add + Mul + Copy; 12 | } 13 | 14 | /// This is the interface for the GKR protocol circuit 15 | pub trait GKRProtocolCircuitInterface { 16 | /// This function returns the addition mle for a indicated layer 17 | fn get_add_n_mul_mle( 18 | &self, 19 | layer_index: usize, 20 | ) -> (Multilinear, Multilinear); 21 | } 22 | 23 | /// This is an interface for handling R1CS related operations 24 | pub trait ExtractConstraintsInterface { 25 | /// this function extracts constrant for the algebric circuit 26 | fn extract_constraints(&self) -> ConstraintsWithLabelSize; 27 | } 28 | -------------------------------------------------------------------------------- /sum_check/src/composed/utils.rs: -------------------------------------------------------------------------------- 1 | use ark_ff::PrimeField; 2 | use polynomial::{ 3 | composed::multilinear::ComposedMultilinear, interface::MultilinearPolynomialInterface, 4 | }; 5 | 6 | pub fn compute_multi_composed_bytes(poly: &[ComposedMultilinear]) -> Vec { 7 | let mut bytes = Vec::new(); 8 | 9 | for p in poly.iter() { 10 | let p_bytes = p.to_bytes(); 11 | bytes.extend_from_slice(&p_bytes); 12 | } 13 | 14 | bytes 15 | } 16 | 17 | pub fn perform_multi_partial_eval( 18 | poly: &[ComposedMultilinear], 19 | point: F, 20 | index: usize, 21 | ) -> Vec> { 22 | let mut new_poly = Vec::new(); 23 | 24 | for i in 0..poly.len() { 25 | new_poly.push(poly[i].partial_evaluation(point, index)); 26 | } 27 | 28 | new_poly 29 | } 30 | 31 | pub fn perform_multi_eval( 32 | poly: &[ComposedMultilinear], 33 | point: &Vec, 34 | ) -> Vec { 35 | let mut result = Vec::new(); 36 | 37 | for i in 0..poly.len() { 38 | result.push(poly[i].evaluate(point).unwrap()); 39 | } 40 | 41 | result 42 | } 43 | -------------------------------------------------------------------------------- /polynomial-commitment-schemes/kzg-rust/src/multilinear.rs: -------------------------------------------------------------------------------- 1 | use ark_ec::{pairing::Pairing, Group}; 2 | use ark_ff::PrimeField; 3 | use polynomial::{multilinear::Multilinear, utils::boolean_hypercube}; 4 | 5 | use crate::{ 6 | interface::KZGMultiLinearInterface, 7 | primitives::MultiLinearSRS, 8 | utils::{bh_to_g1_srs, g2_operation}, 9 | }; 10 | 11 | #[derive(Clone, PartialEq, Eq, Hash, Default, Debug)] 12 | pub struct MultilinearKZG; 13 | 14 | impl KZGMultiLinearInterface

for MultilinearKZG { 15 | fn generate_srs(taus: &[F]) -> MultiLinearSRS

{ 16 | let number_of_variables = taus.len(); 17 | let boolean_hypercube = boolean_hypercube::(number_of_variables); 18 | let g1_power_of_taus = bh_to_g1_srs::(&boolean_hypercube, taus); 19 | let g2_power_of_taus = g2_operation::(taus); 20 | 21 | MultiLinearSRS { 22 | g1_power_of_taus, 23 | g2_power_of_taus, 24 | } 25 | } 26 | 27 | fn commit(srs: &MultiLinearSRS

, poly: &Multilinear) -> P::G1 { 28 | poly.evaluations 29 | .iter() 30 | .zip(srs.g1_power_of_taus.iter()) 31 | .map(|(eval, p1)| p1.mul_bigint(eval.into_bigint())) 32 | .sum() 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /sha256-hash-function/src/interface.rs: -------------------------------------------------------------------------------- 1 | use std::iter::repeat; 2 | 3 | use crate::functions::{convert_to_u32, split_u64_to_u32}; 4 | 5 | pub struct Block { 6 | pub w: [u32; 64], 7 | } 8 | 9 | pub struct PreProcessor { 10 | pub blob: Vec, 11 | } 12 | 13 | pub trait PreProcessorInterface { 14 | /// This takes in the data to be hashed and arrange it as a preprocessed vector of 512bit 15 | fn compute_blocks(&mut self) -> Vec; 16 | } 17 | 18 | pub trait BlockInterface { 19 | /// This function uses the block info to create a message shedule 20 | fn message_shedule(&self) -> [u32; 64]; 21 | } 22 | 23 | impl PreProcessorInterface for PreProcessor { 24 | fn compute_blocks(&mut self) -> Vec { 25 | let mut blocks = Vec::new(); 26 | 27 | if self.blob.len() <= 112 { 28 | let len_initial = self.blob.len() as u64; 29 | let len_initial_2_u32 = split_u64_to_u32(len_initial); 30 | let padding_lenght = 112 - len_initial; 31 | self.blob.extend(repeat(0u8).take(padding_lenght as usize)); 32 | let mut blob_u32 = convert_to_u32(self.blob.clone()); 33 | blob_u32.extend(len_initial_2_u32); 34 | 35 | let block: Block = Block { 36 | w: blob_u32.try_into().unwrap(), 37 | }; 38 | 39 | blocks.push(block); 40 | } else { 41 | } 42 | 43 | blocks 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /fiat_shamir/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod interface; 2 | use interface::TranscriptInterface; 3 | use sha3::{Digest, Keccak256}; 4 | 5 | #[derive(Clone, Default, Debug)] 6 | pub struct FiatShamirTranscript { 7 | hasher: Keccak256, 8 | } 9 | 10 | impl FiatShamirTranscript { 11 | pub fn new(msg: Vec) -> Self { 12 | let mut response = Self { 13 | hasher: Keccak256::new(), 14 | }; 15 | response.append(msg); 16 | response 17 | } 18 | } 19 | 20 | impl TranscriptInterface for FiatShamirTranscript { 21 | fn append(&mut self, msg: Vec) { 22 | self.hasher.update(&msg); 23 | } 24 | 25 | fn sample(&mut self) -> [u8; 32] { 26 | let response = self.hasher.finalize_reset(); 27 | self.hasher.update(&response); 28 | response.into() 29 | } 30 | 31 | fn sample_n(&mut self, n: usize) -> Vec<[u8; 32]> { 32 | let mut response = Vec::new(); 33 | for _ in 0..n { 34 | response.push(self.sample()); 35 | } 36 | response 37 | } 38 | 39 | fn sample_n_as_field_elements(&mut self, n: usize) -> Vec { 40 | let mut response = Vec::new(); 41 | for _ in 0..n { 42 | response.push(F::from_be_bytes_mod_order(&self.sample())); 43 | } 44 | response 45 | } 46 | 47 | fn sample_as_field_element(&mut self) -> F { 48 | F::from_be_bytes_mod_order(&self.sample()) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /polynomial-commitment-schemes/kzg-rust/src/interface.rs: -------------------------------------------------------------------------------- 1 | use crate::primitives::{MultiLinearSRS, SRS}; 2 | use ark_ec::pairing::Pairing; 3 | use ark_ff::PrimeField; 4 | use polynomial::{multilinear::Multilinear, univariant::UnivariantPolynomial}; 5 | 6 | /// This trait is used by it implementing struct to create a new SRS, taking in the string representation of the SRS or the fs-path to the SRS file. 7 | pub trait FromStringToSRS { 8 | fn from_string_to_srs(&self, srs: String) -> SRS

; 9 | } 10 | 11 | pub trait KZGUnivariateInterface { 12 | /// This function is used to generate a new SRS. 13 | fn generate_srs(tau: &P::ScalarField, poly_degree: usize) -> SRS

; 14 | /// Commit to a polynomial would degree is less than the degree of the SRS 15 | fn commit(srs: &SRS

, poly: &UnivariantPolynomial) -> P::G1; 16 | /// Open a polynomial at a point 17 | fn open(srs: &SRS

, poly: &UnivariantPolynomial, point: &F) -> (F, P::G1); 18 | /// Verify polynomial evaluation 19 | fn verify( 20 | srs: &SRS

, 21 | commitment: &P::G1, 22 | point: &F, 23 | point_evaluation: &F, 24 | proof: &P::G1, 25 | ) -> bool; 26 | } 27 | 28 | pub trait KZGMultiLinearInterface { 29 | /// This function is used to generate a new SRS. 30 | fn generate_srs(taus: &[F]) -> MultiLinearSRS

; 31 | /// This function is used to commit to the poly using a provided SRS 32 | fn commit(srs: &MultiLinearSRS

, poly: &Multilinear) -> P::G1; 33 | } 34 | -------------------------------------------------------------------------------- /gkr/benches/gkr_protocol_benchmark.rs: -------------------------------------------------------------------------------- 1 | //! This file contains the benchmarking code for the gkr protocol. 2 | use ark_test_curves::bls12_381::Fr; 3 | use circuits::{interfaces::CircuitInterface, primitives::Circuit}; 4 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 5 | use gkr::{interfaces::GKRProtocolInterface, protocol::GKRProtocol}; 6 | 7 | fn gkr_protocol_benchmark(c: &mut Criterion) { 8 | let circuit = black_box(Circuit::random(8)); 9 | let input = black_box( 10 | (0u64..256) 11 | .into_iter() 12 | .map(|x| Fr::from(x)) 13 | .collect::>(), 14 | ); 15 | 16 | c.bench_function("GKR protocol with evaluation", |b| { 17 | b.iter(|| { 18 | let evaluation = circuit.evaluate(&input); 19 | let proof = GKRProtocol::prove(&circuit, &evaluation); 20 | assert!(GKRProtocol::verify(&circuit, &input, &proof)); 21 | }) 22 | }); 23 | } 24 | 25 | fn gkr_protocol_benchmark_without_eval(c: &mut Criterion) { 26 | let circuit = black_box(Circuit::random(8)); 27 | let input = black_box( 28 | (0u64..256) 29 | .into_iter() 30 | .map(|x| Fr::from(x)) 31 | .collect::>(), 32 | ); 33 | let evaluation = black_box(circuit.evaluate(&input)); 34 | 35 | c.bench_function("GKR protocol without evaluation", |b| { 36 | b.iter(|| { 37 | let proof = GKRProtocol::prove(&circuit, &evaluation); 38 | assert!(GKRProtocol::verify(&circuit, &input, &proof)); 39 | }) 40 | }); 41 | } 42 | 43 | criterion_group!( 44 | benches, 45 | gkr_protocol_benchmark, 46 | gkr_protocol_benchmark_without_eval 47 | ); 48 | 49 | criterion_main!(benches); 50 | -------------------------------------------------------------------------------- /sha256-hash-function/src/functions.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Shr; 2 | 3 | pub fn sigma_0(x: u32) -> u32 { 4 | x.rotate_right(7) ^ x.rotate_right(18) ^ x.shr(3) 5 | } 6 | 7 | pub fn sigma_1(x: u32) -> u32 { 8 | x.rotate_right(17) ^ x.rotate_right(19) ^ x.shr(10) 9 | } 10 | 11 | pub fn prime_sigma_0(x: u32) -> u32 { 12 | x.rotate_right(2) ^ x.rotate_right(13) ^ x.rotate_right(22) 13 | } 14 | 15 | pub fn prime_sigma_1(x: u32) -> u32 { 16 | x.rotate_right(6) ^ x.rotate_right(11) ^ x.rotate_right(25) 17 | } 18 | 19 | pub fn choice(x: u32, y: u32, z: u32) -> u32 { 20 | (x & y) ^ (!x & z) 21 | } 22 | 23 | pub fn maj(x: u32, y: u32, z: u32) -> u32 { 24 | (x & y) ^ (x & z) ^ (y & z) 25 | } 26 | 27 | pub fn compute_message_shedule_extension(wi_2: u32, wi_7: u32, wi_15: u32, wi_16: u32) -> u32 { 28 | sigma_1(wi_2) 29 | .wrapping_add(wi_7) 30 | .wrapping_add(sigma_1(wi_15)) 31 | .wrapping_add(wi_16) 32 | } 33 | 34 | pub fn convert_to_u32(padded_vec: Vec) -> Vec { 35 | if padded_vec.len() != 112 { 36 | panic!("Input vector must be of length 112"); 37 | } 38 | 39 | let mut u32_vec = Vec::new(); 40 | for i in (0..padded_vec.len()).step_by(4) { 41 | // Safe since the check ensures length is a multiple of 4 42 | let u32_element = unsafe { 43 | // Convert a slice of 4 bytes to u32 (assuming native endianness) 44 | *(padded_vec.as_ptr().add(i) as *const u32) 45 | }; 46 | u32_vec.push(u32_element); 47 | } 48 | u32_vec 49 | } 50 | 51 | pub fn split_u64_to_u32(value: u64) -> Vec { 52 | let upper_32 = (value >> 32) as u32; // Right shift by 32 to get upper bits and cast to u32 53 | let lower_32 = (value & 0xffffffff) as u32; // Bitwise AND with all ones to get lower bits and cast to u32 54 | vec![upper_32, lower_32] 55 | } 56 | -------------------------------------------------------------------------------- /schnorr/src/lib.rs: -------------------------------------------------------------------------------- 1 | use core::Signature; 2 | 3 | use sha256::digest; 4 | 5 | use lambdaworks_math::{ 6 | cyclic_group::IsGroup, 7 | elliptic_curve::{ 8 | short_weierstrass::curves::bls12_381::curve::BLS12381Curve, traits::IsEllipticCurve, 9 | }, 10 | traits::{AsBytes, ByteConversion}, 11 | unsigned_integer::element::U256, 12 | }; 13 | use rand::prelude::*; 14 | 15 | pub mod core; 16 | 17 | /// This function is used to sign a message over a generic elliptic curve and generic hash function. 18 | pub fn sign(private_key: U256, message: String) -> anyhow::Result { 19 | // Generate out very secured random scalar 20 | let mut randomness_engine = rand::thread_rng(); 21 | let raw_k = digest(randomness_engine.gen_range(0..100).to_string()); 22 | let k = U256::from_bytes_be(&raw_k.as_bytes()).expect("Failed to convert bytes to U256"); 23 | // r = G.pow(k) 24 | let r = BLS12381Curve::generator().operate_with_self(k); 25 | 26 | let mut e_preimage = r.as_bytes(); 27 | // (r || message) 28 | e_preimage.extend(message.as_bytes().to_vec()); 29 | // H (r || message) 30 | let e_raw = digest(e_preimage); 31 | let e = U256::from_bytes_be(&e_raw.as_bytes()).expect("Failed to convert bytes to U256"); 32 | 33 | // s = k - e * private_key 34 | let s = k - (e * private_key); 35 | 36 | Ok(Signature::new(s, e)) 37 | } 38 | 39 | pub fn add(left: usize, right: usize) -> usize { 40 | left + right 41 | } 42 | 43 | #[cfg(test)] 44 | mod tests { 45 | use crate::core::KeyPair; 46 | 47 | use super::*; 48 | 49 | #[test] 50 | fn it_works() { 51 | let key_pair = KeyPair::new(U256::from(123456789u128)); 52 | let message = "Hello, world!".to_string(); 53 | let signature = sign(key_pair.private_key, message.clone()).unwrap(); 54 | assert!(signature.verify(message, key_pair.public_key).unwrap()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /sum_check/src/composed/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod multicomposed; 2 | pub mod prover; 3 | pub mod utils; 4 | pub mod verifier; 5 | 6 | use ark_ff::{BigInteger, PrimeField}; 7 | use polynomial::{ 8 | interface::UnivariantPolynomialInterface, multilinear::Multilinear, 9 | univariant::UnivariantPolynomial, utils::compute_domain, 10 | }; 11 | 12 | /// This struct is used to store the sum check proof 13 | #[derive(Clone, PartialEq, Eq, Hash, Default, Debug)] 14 | pub struct ComposedSumCheckProof { 15 | /// This vector stores the round polynomials 16 | pub round_poly: Vec>, 17 | /// This holds the sum of the polynomial evaluation over the boolean hypercube 18 | pub sum: F, 19 | } 20 | 21 | #[derive(Clone, PartialEq, Eq, Hash, Default, Debug)] 22 | pub struct RoundPoly { 23 | /// This is a vector of points that would be interpolated against a domain of real numbers to obtain the round polynomial 24 | pub poly_vec: Vec, 25 | } 26 | 27 | impl RoundPoly { 28 | pub fn new(poly_vec: Vec) -> Self { 29 | Self { poly_vec } 30 | } 31 | 32 | pub fn interpolate(&self) -> UnivariantPolynomial { 33 | let domain = compute_domain(self.poly_vec.len(), 0); 34 | UnivariantPolynomial::interpolate(self.poly_vec.clone(), domain) 35 | } 36 | 37 | pub fn rep_in_eval(&self) -> Multilinear { 38 | Multilinear::new(self.poly_vec.clone(), 1) 39 | } 40 | } 41 | 42 | impl ComposedSumCheckProof { 43 | pub fn new(round_poly: Vec>, sum: F) -> Self { 44 | Self { round_poly, sum } 45 | } 46 | 47 | pub fn to_bytes(&self) -> Vec { 48 | let mut bytes = Vec::new(); 49 | for round_poly in self.round_poly.iter() { 50 | bytes.extend_from_slice(&round_poly.to_bytes()); 51 | } 52 | bytes.extend_from_slice(&self.sum.into_bigint().to_bytes_be()); 53 | bytes 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /sum_check/README.md: -------------------------------------------------------------------------------- 1 | # Sum check protocol 2 | -------------------- 3 | 4 | Sum-Check Protocol The Sum-Check Protocol is a fundamental technique in theoretical computer science, particularly in the field of interactive proof systems and complexity theory. It’s often used to prove properties about polynomials and is a key component in constructing various interactive proofs, including those for NP-complete problems. 5 | 6 | Suppose we are given a v-variate polynomial g defined over a finite field F. The purpose of the sum-check protocol is for the prover to provide the verifier with the sum of evaluations over the boolean hypercube. 7 | 8 | #### Example 9 | ![Sum Check Protocol Example](https://raw.githubusercontent.com/developeruche/cryptography-n-zk-research/main/assets/sum%20check%20protocol.png) 10 | 11 | 12 | ### Build Guide 13 | 14 | 1. Clone the repository 15 | 16 | ```bash 17 | git clone ** 18 | ``` 19 | 20 | 2. Build the project 21 | 22 | ```bash 23 | cargo build --release 24 | ``` 25 | 26 | 3. Run the project test 27 | 28 | ```bash 29 | cargo test 30 | ``` 31 | 32 | ### Usage (How to compute proofs and verify claims) 33 | 34 | ```rust 35 | 36 | let poly = Multilinear::new( 37 | vec![ 38 | Fr::from(1), 39 | Fr::from(3), 40 | Fr::from(5), 41 | Fr::from(7), 42 | Fr::from(2), 43 | Fr::from(4), 44 | Fr::from(6), 45 | Fr::from(8), 46 | Fr::from(3), 47 | Fr::from(5), 48 | Fr::from(7), 49 | Fr::from(9), 50 | Fr::from(4), 51 | Fr::from(6), 52 | Fr::from(8), 53 | Fr::from(10), 54 | ], 55 | 4, 56 | ); 57 | let mut prover = Prover::new(poly); 58 | prover.calculate_sum(); 59 | 60 | println!("Sum: {:?}", prover.sum); 61 | 62 | let proof = prover.sum_check_proof(); 63 | let mut verifer = Verifier::new(); 64 | 65 | assert!(verifer.verify(&proof)); 66 | 67 | ``` 68 | -------------------------------------------------------------------------------- /schnorr/src/core.rs: -------------------------------------------------------------------------------- 1 | pub use lambdaworks_math::{ 2 | cyclic_group::IsGroup, 3 | elliptic_curve::{ 4 | short_weierstrass::curves::bls12_381::curve::BLS12381Curve, traits::IsEllipticCurve, 5 | }, 6 | unsigned_integer::element::U256, 7 | }; 8 | use lambdaworks_math::{ 9 | elliptic_curve::short_weierstrass::point::ShortWeierstrassProjectivePoint, 10 | traits::{AsBytes, ByteConversion}, 11 | }; 12 | use sha256::digest; 13 | 14 | pub struct KeyPair { 15 | pub private_key: U256, 16 | pub public_key: ShortWeierstrassProjectivePoint, 17 | } 18 | 19 | pub struct Signature { 20 | pub s: U256, 21 | pub e: U256, 22 | } 23 | 24 | impl KeyPair { 25 | /// This function is used to generate a new key pair 26 | pub fn new(private_key: U256) -> Self { 27 | let generator = BLS12381Curve::generator(); 28 | let public_key = generator.operate_with_self(private_key); 29 | 30 | KeyPair { 31 | private_key, 32 | public_key, 33 | } 34 | } 35 | } 36 | 37 | impl Signature { 38 | pub fn new(s: U256, e: U256) -> Self { 39 | Signature { s, e } 40 | } 41 | 42 | /// This function is used for verifying a signature over a message 43 | pub fn verify( 44 | &self, 45 | message: String, 46 | public_key: ShortWeierstrassProjectivePoint, 47 | ) -> anyhow::Result { 48 | let generator = BLS12381Curve::generator(); 49 | let g_pow_s = generator.operate_with_self(self.s); 50 | let public_key_pow_e = public_key.operate_with_self(self.e); 51 | 52 | // g^s * public_key^e 53 | let r_v = g_pow_s.operate_with(&public_key_pow_e); 54 | 55 | let mut e_preimage = r_v.as_bytes(); 56 | e_preimage.extend(message.as_bytes().to_vec()); 57 | let e_raw = digest(e_preimage); 58 | let e = U256::from_bytes_be(&e_raw.as_bytes()).expect("Failed to convert bytes to U256"); 59 | 60 | Ok(e == self.e) 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /polynomial/src/multivariate.rs: -------------------------------------------------------------------------------- 1 | use ark_ff::{BigInteger, PrimeField}; 2 | use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; 3 | // use std::ops::{Add, AddAssign}; 4 | 5 | /// A multivariate polynomial. 6 | /// Building a generic structure that can accomodate both (univarate, multi-linear and multivarate) polynomials 7 | #[derive(Clone, PartialEq, Eq, Hash, Default, Debug, CanonicalSerialize, CanonicalDeserialize)] 8 | pub struct Multivariate { 9 | /// The coefficients of the polynomial. 10 | pub evaluations: Vec, 11 | /// This is the number of variables in the polynomial. 12 | pub num_vars: usize, 13 | /// This is the index of the operationals hypercube 14 | pub hc_index: usize, 15 | } 16 | 17 | impl Multivariate { 18 | /// This is the function for creating a new multivariate polynomial. 19 | pub fn new(evaluations: Vec, num_vars: usize, hc_index: usize) -> Self { 20 | // SANITY_CHECK: Ensure that the number of evaluations is equal to the number of variables raised to power of 2 21 | assert_eq!( 22 | evaluations.len(), 23 | hc_index.pow(num_vars as u32), 24 | "Number of evaluations must be equal to 2^num_vars" 25 | ); 26 | 27 | Self { 28 | evaluations, 29 | num_vars, 30 | hc_index, 31 | } 32 | } 33 | 34 | /// This function is used to check if the polynomial is zero 35 | pub fn is_zero(&self) -> bool { 36 | self.evaluations.iter().all(|x| x.is_zero()) 37 | } 38 | 39 | /// This function is used to return the bytes representation of the polynomial 40 | pub fn to_bytes(&self) -> Vec { 41 | let mut m_ploy_bytes = Vec::new(); 42 | 43 | for eval in &self.evaluations { 44 | let big_int = eval.into_bigint().to_bytes_be(); 45 | m_ploy_bytes.extend_from_slice(&big_int); 46 | } 47 | 48 | m_ploy_bytes 49 | } 50 | } 51 | 52 | // NOTE: This implemenation is not complete yet! 53 | -------------------------------------------------------------------------------- /sum_check/src/composed/verifier.rs: -------------------------------------------------------------------------------- 1 | use super::ComposedSumCheckProof; 2 | use crate::interface::ComposedVerifierInterface; 3 | use ark_ff::{BigInteger, PrimeField}; 4 | use fiat_shamir::interface::TranscriptInterface; 5 | use fiat_shamir::FiatShamirTranscript; 6 | use polynomial::composed::multilinear::ComposedMultilinear; 7 | use polynomial::interface::MultilinearPolynomialInterface; 8 | use polynomial::interface::PolynomialInterface; 9 | 10 | #[derive(Clone, Default, Debug)] 11 | pub struct ComposedVerifier; 12 | 13 | impl ComposedVerifierInterface for ComposedVerifier { 14 | fn verify(proof: &ComposedSumCheckProof, poly: &ComposedMultilinear) -> bool { 15 | let mut transcript = FiatShamirTranscript::default(); 16 | 17 | transcript.append(poly.to_bytes()); 18 | transcript.append(proof.sum.into_bigint().to_bytes_be()); 19 | 20 | let mut all_rands = Vec::new(); 21 | 22 | let mut mutating_sum = proof.sum; 23 | 24 | for r_poly in proof.round_poly.iter() { 25 | transcript.append(r_poly.to_bytes()); 26 | 27 | // stage one assertion (see if current mutating sum was influenced by the passed mutating sum) 28 | let untrusted_sum = r_poly.evaluate(&F::zero()) + r_poly.evaluate(&F::one()); 29 | 30 | if untrusted_sum != mutating_sum { 31 | println!( 32 | "untrusted_sum != proof.sum --> {} - {}", 33 | untrusted_sum, proof.sum 34 | ); 35 | return false; 36 | } 37 | 38 | let sample = F::from_be_bytes_mod_order(&transcript.sample()); 39 | mutating_sum = r_poly.evaluate(&sample); 40 | all_rands.push(sample); 41 | } 42 | 43 | // last round check 44 | let last_mutating_sum = poly.evaluate(&all_rands).unwrap(); 45 | 46 | if last_mutating_sum != mutating_sum { 47 | println!( 48 | "last_mutating_sum != mutating_sum --> {} - {}", 49 | last_mutating_sum, mutating_sum 50 | ); 51 | return false; 52 | } 53 | 54 | true 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /bls-multi-sign-threshold-wallet/src/main.rs: -------------------------------------------------------------------------------- 1 | use polynomial::{ 2 | ark_ff::PrimeField, 3 | ark_test_curves::bls12_381::Fr, 4 | interface::{PolynomialInterface, UnivariantPolynomialInterface}, 5 | univariant::UnivariantPolynomial, 6 | }; 7 | 8 | fn main() { 9 | //testing the shamir secret sharing 10 | let threshold = 3; 11 | let members = 5; 12 | 13 | let secret = Fr::from(1234567890u32); 14 | 15 | let (shares_x, shares_y) = shamir_secret_sharing(threshold, members, secret); 16 | 17 | let user_x = shares_x[1..].to_vec(); 18 | let user_y = shares_y[1..].to_vec(); 19 | 20 | println!("Recovering with {} - and - {}", user_x.len(), user_y.len()); 21 | 22 | let recovered_secret = recover_secret(user_x, user_y); 23 | 24 | println!("Recovered secret: {:?}", recovered_secret); 25 | 26 | assert!(secret == recovered_secret); 27 | } 28 | 29 | pub fn shamir_secret_sharing( 30 | threshold: usize, 31 | members: usize, 32 | secret: F, 33 | ) -> (Vec, Vec) { 34 | let mut rng = rand::thread_rng(); 35 | let mut domain = Vec::with_capacity(threshold + 1); 36 | let mut y_s = Vec::with_capacity(threshold + 1); 37 | 38 | for i in 0..threshold { 39 | domain.push(F::from(i as u32)); 40 | } 41 | 42 | for _ in 0..threshold { 43 | y_s.push(F::rand(&mut rng)); 44 | } 45 | 46 | y_s[0] = secret; 47 | 48 | let poly = UnivariantPolynomial::interpolate(y_s, domain); 49 | 50 | if poly.degree() != threshold - 1 { 51 | panic!("Polynomial degree is not correct"); 52 | } 53 | 54 | let mut shares_y = Vec::with_capacity(members); 55 | let mut shares_x = Vec::with_capacity(members); 56 | 57 | for i in 0..members { 58 | let x = F::from(i as u32); 59 | let y = poly.evaluate(&x); 60 | shares_x.push(x); 61 | shares_y.push(y); 62 | } 63 | 64 | (shares_x, shares_y) 65 | } 66 | 67 | pub fn recover_secret(shares_x: Vec, shares_y: Vec) -> F { 68 | let poly = UnivariantPolynomial::interpolate(shares_y.clone(), shares_x.clone()); 69 | let secret = poly.evaluate(&F::zero()); 70 | secret 71 | } 72 | -------------------------------------------------------------------------------- /groth16/src/interfaces.rs: -------------------------------------------------------------------------------- 1 | use crate::primitives::{ 2 | Proof, ProofRands, QAPPolys, QAPPolysCoefficients, ToxicWaste, TrustedSetupExcecution, QAP, 3 | }; 4 | use ark_ec::pairing::Pairing; 5 | use ark_ff::PrimeField; 6 | use circuits::primitives::Witness; 7 | 8 | pub trait R1CSProcessingInterface { 9 | /// This function take the columns from the R1CS matrix and returns the QAP polynomial coefficients 10 | fn to_qap_poly_coefficients(&self) -> QAPPolysCoefficients; 11 | } 12 | 13 | pub trait QAPPolysCoefficientsInterface { 14 | /// This fuction takes the QAP polynomial coefficients with the witness and returns the QAP polynomials 15 | fn to_qap_polynomials(&self, witness: Vec) -> QAP; 16 | } 17 | 18 | pub trait QAPInterface { 19 | /// This is function is used to check if the QAP is satisfied 20 | fn is_satisfied(&self) -> bool; 21 | } 22 | 23 | pub trait TrustedSetupInterface { 24 | /// This function is used to run the trusted setup 25 | /// parameters: 26 | /// circuit_details: The QAPPolys struct that contains the QAP polynomial coefficients.\ 27 | /// this is used for the circuit specific trusted setup 28 | /// This trusted setup would also be used to generate the proving and verification key. 29 | fn run_trusted_setup( 30 | toxic_waste: &ToxicWaste, 31 | qap_polys: &QAPPolys, 32 | number_of_constraints: usize, 33 | ) -> TrustedSetupExcecution

; 34 | } 35 | 36 | pub trait PreProcessorInterface { 37 | /// This function is used to preprocess the R1CS 38 | fn preprocess(&self) -> QAP; 39 | } 40 | 41 | pub trait ProtocolInterface { 42 | /// This function is used to generate a groth16 proof 43 | fn generate_proof( 44 | proof_rands: ProofRands, 45 | trusted_setup: &TrustedSetupExcecution

, 46 | qap: &QAP, 47 | witness: &Witness, 48 | ) -> Proof

; 49 | 50 | /// This function is used to verify a groth16 proof 51 | fn verify_proof( 52 | proof: &Proof

, 53 | trusrted_setup: &TrustedSetupExcecution

, 54 | public_input: &Vec, 55 | ) -> bool; 56 | } 57 | -------------------------------------------------------------------------------- /polynomial/README.md: -------------------------------------------------------------------------------- 1 | # Polynomials 2 | -------------------- 3 | 4 | Polynomials, those elegant expressions of coefficients and variables, hold within them the power to transcend mere mathematics and touch the realms of art, security, and computation. They are the silent composers of symphonies that secure our digital secrets, the architects of algorithms, and the timeless dancers in the space of numbers. 5 | 6 | In cryptography, polynomials become the guardians of our privacy. Imagine them as the secretive sentinels of the digital age, weaving intricate webs through finite fields and elliptic curves. They hide messages within their degrees and coefficients, creating ciphers that are as impenetrable as a knight’s armor. The beauty of polynomial-based cryptographic methods, like those in elliptic curve cryptography, lies in their blend of simplicity and complexity. A single polynomial equation, when viewed through the lens of number theory, can secure communications against the most relentless of adversaries. 7 | 8 | Mathematically, polynomials are the storytellers of calculus and algebra, narrating the tales of curves and surfaces. They are the chameleons of mathematics, capable of transforming into various forms—factored, expanded, or simplified. Each transformation reveals a different facet of their character, whether it’s the roots that solve equations or the coefficients that describe geometric shapes. The Fundamental Theorem of Algebra whispers the promise that every non-zero polynomial has at least one complex root, a promise that ensures completeness in the mathematical universe. 9 | 10 | To a programmer, polynomials are the unsung heroes of code. They are the engines driving graphics rendering, error detection, and machine learning algorithms. Picture a polynomial as a loyal steed, carrying a programmer through the treacherous terrain of computational complexity. In computer graphics, Bézier curves, those graceful polynomial curves, render the smooth lines and shapes that we see on our screens. Error-correcting codes like Reed-Solomon, built upon the foundation of polynomials, ensure the integrity of our data as it travels across the globe. 11 | 12 | Polynomials, thus, are not just mathematical constructs. They are the bridge between the abstract and the tangible, the simple and the profound. They dance in the cryptographic shadows, tell stories in the language of algebra, and work tirelessly in the digital realms crafted by programmers. In their coefficients and variables, they hold the essence of order and chaos, a delicate balance that makes the world of mathematics so infinitely fascinating. 13 | 14 | 15 | ## Polynomial 16 | 17 | This is the implementation of a polynomial in Rust. The Polynomial struct allows you to create a polynomial, evaluate it at a specific point, and add or multiply two polynomials together. 18 | 19 | The variations of polynomials built in here are; 20 | - Univariate Polynomial 21 | - Multivariate Polynomial 22 | - Multilinear Polynomial 23 | 24 | ... the last two could give a man 2^N complexity nightmare :). -------------------------------------------------------------------------------- /circuits/README.md: -------------------------------------------------------------------------------- 1 | # Circuits 2 | ----------------------- 3 | ## Description 4 | This is a library for creating and manipulating circuits. The library is designed to be modular and extensible. The library is designed to be used in the context of snarks, but can be used for any type of circuit. 5 | 6 | This circuits in this lib are; 7 | 8 | ### 1. Binary Circuit 9 | ### 2. Arithmetic Circuit 10 | 11 | 12 | ### Usage (Creating a Circuit) 13 | ```rust 14 | // sample circuit evaluation 15 | // 100(*) - layer 0 16 | // / \ 17 | // 5(+)_0 20(*)_1 - layer 1 18 | // / \ / \ 19 | // 2 3 4 5 20 | 21 | let layer_0 = CircuitLayer::new(vec![Gate::new(GateType::Mul, [0, 1])]); 22 | let layer_1 = CircuitLayer::new(vec![ 23 | Gate::new(GateType::Add, [0, 1]), 24 | Gate::new(GateType::Mul, [2, 3]), 25 | ]); 26 | let circuit = Circuit::new(vec![layer_0, layer_1]); 27 | let input = [ 28 | Fr::from(2u32), 29 | Fr::from(3u32), 30 | Fr::from(4u32), 31 | Fr::from(5u32), 32 | ]; 33 | let evaluation = circuit.evaluate(&input); 34 | let expected_output = vec![ 35 | vec![Fr::from(100u32)], 36 | vec![Fr::from(5u32), Fr::from(20u32)], 37 | vec![ 38 | Fr::from(2u32), 39 | Fr::from(3u32), 40 | Fr::from(4u32), 41 | Fr::from(5u32), 42 | ], 43 | ]; 44 | 45 | assert_eq!(evaluation.layers, expected_output); 46 | ``` 47 | 48 | 49 | ### Usage (For Groth16) 50 | ```rust 51 | // running groth16 on this circuit 52 | // 100(*) - layer 0 53 | // / \ 54 | // 41 103 - input layer 55 | let layer_0 = CircuitLayer::new(vec![Gate::new(GateType::Mul, [0, 1])]); 56 | 57 | let circuit = Circuit::new(vec![layer_0]); 58 | let constraints = circuit.extract_constraints(); 59 | 60 | let r1cs = constraints.to_r1cs_vec::(); 61 | let witness = Witness::new( 62 | vec![Fr::from(1u32)], 63 | vec![Fr::from(4223u32), Fr::from(41u32), Fr::from(103u32)], 64 | ); 65 | let r1cs_check = r1cs.check(witness.render()); 66 | assert!(r1cs_check, "this is the R1CS check"); 67 | 68 | let qap_poly_coefficients = r1cs.to_qap_poly_coefficients(); 69 | let qap_poly = qap_poly_coefficients.into_poly_rep(); 70 | 71 | let preprocessor = PreProcessor::new(r1cs, witness.clone()); 72 | let qap = preprocessor.preprocess(); 73 | 74 | let check = qap.qap_check(); 75 | assert_eq!(check, true); 76 | 77 | let toxic_waste = ToxicWaste::new( 78 | Fr::from(2u32), 79 | Fr::from(3u32), 80 | Fr::from(5u32), 81 | Fr::from(6u32), 82 | Fr::from(4u32), 83 | ); 84 | 85 | let trusted_setup = TrustedSetup::::run_trusted_setup( 86 | &toxic_waste, 87 | &qap_poly, 88 | qap.ax.degree(), 89 | ); 90 | 91 | let proof_rands = ProofRands::::new(Fr::from(3u32), Fr::from(5u32)); 92 | 93 | let groth16_proof = Groth16Protocol::::generate_proof( 94 | proof_rands, 95 | &trusted_setup, 96 | &qap, 97 | &witness, 98 | ); 99 | 100 | let is_valid = Groth16Protocol::::verify_proof( 101 | &groth16_proof, 102 | &trusted_setup, 103 | &witness.public_input, 104 | ); 105 | 106 | assert!(is_valid); 107 | ``` -------------------------------------------------------------------------------- /sum_check/benches/sum_check_benchmark.rs: -------------------------------------------------------------------------------- 1 | //! This file contains the benchmarking code for the sum_check function. 2 | //! 1. Normal sum check benchmarking 3 | //! 2. Running sum check on a composed polynomial 4 | //! 3. Running sum check on a multi-composed polynomial 5 | 6 | use ark_test_curves::bls12_381::Fr; 7 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 8 | use fiat_shamir::FiatShamirTranscript; 9 | use polynomial::{composed::multilinear::ComposedMultilinear, multilinear::Multilinear}; 10 | use sum_check::{ 11 | composed::{ 12 | multicomposed::{MultiComposedProver, MultiComposedVerifier}, 13 | prover::ComposedProver, 14 | verifier::ComposedVerifier, 15 | }, 16 | interface::{ 17 | ComposedProverInterface, ComposedVerifierInterface, MultiComposedProverInterface, 18 | MultiComposedVerifierInterface, ProverInterface, VerifierInterface, 19 | }, 20 | prover::Prover, 21 | verifier::Verifier, 22 | }; 23 | 24 | fn normal_sum_check_benchmark(c: &mut Criterion) { 25 | let poly = black_box(Multilinear::::random(12)); 26 | 27 | c.bench_function("Normal sum check", |b| { 28 | b.iter(|| { 29 | let mut transcript = FiatShamirTranscript::default(); 30 | let sum = Prover::calculate_sum(&poly); 31 | let proof = Prover::sum_check_proof(&poly, &mut transcript, &sum); 32 | assert!(Verifier::verify(&proof)); 33 | }) 34 | }); 35 | } 36 | 37 | fn composed_sum_check_benchmark(c: &mut Criterion) { 38 | let poly_1 = black_box(Multilinear::::random(12)); 39 | let poly_2 = black_box(Multilinear::::random(12)); 40 | let composed_poly = black_box(ComposedMultilinear::new(vec![poly_1, poly_2])); 41 | 42 | c.bench_function("Composed sum check", |b| { 43 | b.iter(|| { 44 | let mut transcript = FiatShamirTranscript::default(); 45 | let sum = ComposedProver::calculate_sum(&composed_poly); 46 | let (proof, _) = ComposedProver::sum_check_proof(&composed_poly, &mut transcript, &sum); 47 | assert!(ComposedVerifier::verify(&proof, &composed_poly)); 48 | }) 49 | }); 50 | } 51 | 52 | fn multi_composed_sum_check_benchmark(c: &mut Criterion) { 53 | let poly_1 = black_box(Multilinear::::random(12)); 54 | let poly_2 = black_box(Multilinear::::random(12)); 55 | let poly_3 = black_box(Multilinear::::random(12)); 56 | let poly_4 = black_box(Multilinear::::random(12)); 57 | 58 | let composed_poly_1 = black_box(ComposedMultilinear::new(vec![poly_1, poly_2])); 59 | let composed_poly_2 = black_box(ComposedMultilinear::new(vec![poly_3, poly_4])); 60 | 61 | let multi_composed_poly = vec![composed_poly_1, composed_poly_2]; 62 | 63 | c.bench_function("Multi-composed sum check", |b| { 64 | b.iter(|| { 65 | let sum = MultiComposedProver::calculate_sum(&multi_composed_poly); 66 | let (proof, _) = MultiComposedProver::sum_check_proof(&multi_composed_poly, &sum); 67 | assert!(MultiComposedVerifier::verify(&proof, &multi_composed_poly)); 68 | }) 69 | }); 70 | } 71 | 72 | criterion_group!( 73 | benches, 74 | multi_composed_sum_check_benchmark, 75 | composed_sum_check_benchmark, 76 | normal_sum_check_benchmark 77 | ); 78 | 79 | criterion_main!(benches); 80 | -------------------------------------------------------------------------------- /polynomial-commitment-schemes/kzg-rust/src/univariate.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | interface::KZGUnivariateInterface, 3 | primitives::SRS, 4 | utils::{ 5 | generate_powers_of_tau_g1, linear_combination_homomorphic_poly_eval_g1, 6 | linear_combination_homomorphic_poly_eval_g1_primefield, 7 | }, 8 | }; 9 | use ark_ec::{pairing::Pairing, Group}; 10 | use ark_ff::PrimeField; 11 | use polynomial::interface::PolynomialInterface; 12 | use polynomial::univariant::UnivariantPolynomial; 13 | 14 | #[derive(Clone, PartialEq, Eq, Hash, Default, Debug)] 15 | pub struct UnivariateKZG; 16 | 17 | impl KZGUnivariateInterface

for UnivariateKZG { 18 | fn generate_srs(tau: &P::ScalarField, poly_degree: usize) -> SRS

{ 19 | let g1_power_of_taus = generate_powers_of_tau_g1::

(tau, poly_degree); 20 | let g2_power_of_tau = P::G2::generator().mul_bigint(tau.into_bigint()); 21 | 22 | SRS { 23 | g1_power_of_taus, 24 | g2_power_of_tau, 25 | } 26 | } 27 | 28 | fn commit(srs: &SRS

, poly: &UnivariantPolynomial) -> P::G1 { 29 | linear_combination_homomorphic_poly_eval_g1::

(poly, &srs.g1_power_of_taus) 30 | } 31 | 32 | fn open(srs: &SRS

, poly: &UnivariantPolynomial, point: &F) -> (F, P::G1) { 33 | let point_evaluation = poly.evaluate(point); 34 | let divisor = UnivariantPolynomial::new(vec![-*point, F::one()]); 35 | let numerator = poly - point_evaluation; 36 | let quotient = numerator / divisor; 37 | 38 | let proof = linear_combination_homomorphic_poly_eval_g1_primefield::( 39 | "ient, 40 | &srs.g1_power_of_taus, 41 | ); 42 | 43 | (point_evaluation, proof) 44 | } 45 | 46 | fn verify( 47 | srs: &SRS

, 48 | commitment: &P::G1, 49 | point: &F, 50 | point_evaluation: &F, 51 | proof: &P::G1, 52 | ) -> bool { 53 | let g2_generator = P::G2::generator(); 54 | let g1_point_evalauation = 55 | srs.g1_power_of_taus[0].mul_bigint(point_evaluation.into_bigint()); 56 | let g2_point = g2_generator.mul_bigint(point.into_bigint()); 57 | 58 | let left_pairing = P::pairing(*commitment - g1_point_evalauation, g2_generator); 59 | let right_pairing = P::pairing(*proof, srs.g2_power_of_tau - g2_point); 60 | 61 | left_pairing == right_pairing 62 | } 63 | } 64 | 65 | #[cfg(test)] 66 | mod tests { 67 | use super::*; 68 | use ark_test_curves::bls12_381::{Bls12_381, Fr}; 69 | 70 | #[test] 71 | fn test_univariate_kzg() { 72 | let tau = Fr::from(10u64); 73 | let poly_degree = 4; 74 | let srs: SRS = UnivariateKZG::generate_srs(&tau, poly_degree); 75 | 76 | let poly = UnivariantPolynomial::new(vec![ 77 | Fr::from(1u64), 78 | Fr::from(2u64), 79 | Fr::from(3u64), 80 | Fr::from(4u64), 81 | Fr::from(5u64), 82 | ]); 83 | let commitment = UnivariateKZG::commit(&srs, &poly); 84 | let (point_evaluation, proof) = UnivariateKZG::open::(&srs, &poly, &Fr::from(2u64)); 85 | let is_valid = UnivariateKZG::verify::( 86 | &srs, 87 | &commitment, 88 | &Fr::from(2u64), 89 | &point_evaluation, 90 | &proof, 91 | ); 92 | 93 | assert!(is_valid); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /groth16/src/preprocessing.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | interfaces::{ 3 | PreProcessorInterface, QAPInterface, QAPPolysCoefficientsInterface, R1CSProcessingInterface, 4 | }, 5 | primitives::{QAPPolysCoefficients, QAP}, 6 | utils::generate_t_poly, 7 | }; 8 | use ark_ff::PrimeField; 9 | use circuits::primitives::{Witness, R1CS}; 10 | use polynomial::univariant::UnivariantPolynomial; 11 | 12 | pub struct PreProcessor { 13 | pub r1cs: R1CS, 14 | pub witness: Witness, 15 | } 16 | 17 | impl PreProcessor { 18 | pub fn new(r1cs: R1CS, witness: Witness) -> Self { 19 | Self { r1cs, witness } 20 | } 21 | } 22 | 23 | impl R1CSProcessingInterface for R1CS { 24 | fn to_qap_poly_coefficients(&self) -> QAPPolysCoefficients { 25 | // assert that all the r1cs components are of the same length 26 | // this checks if the number of constraints are equal 27 | assert!( 28 | self.a.len() == self.b.len() && self.a.len() == self.c.len(), 29 | "The R1CS components are not of the same length" 30 | ); 31 | 32 | let mut new_a = vec![]; 33 | let mut new_b = vec![]; 34 | let mut new_c = vec![]; 35 | 36 | let rows = self.a.len(); 37 | let columns = self.a[0].len(); 38 | 39 | for i in 0..columns { 40 | let mut a = vec![]; 41 | let mut b = vec![]; 42 | let mut c = vec![]; 43 | 44 | for j in 0..rows { 45 | a.push(self.a[j][i]); 46 | b.push(self.b[j][i]); 47 | c.push(self.c[j][i]); 48 | } 49 | 50 | new_a.push(a); 51 | new_b.push(b); 52 | new_c.push(c); 53 | } 54 | 55 | QAPPolysCoefficients { 56 | a: new_a, 57 | b: new_b, 58 | c: new_c, 59 | } 60 | } 61 | } 62 | 63 | impl QAPPolysCoefficientsInterface for QAPPolysCoefficients { 64 | fn to_qap_polynomials(&self, witness: Vec) -> QAP { 65 | let polys = self.into_poly_rep(); 66 | 67 | let cx = polys 68 | .c 69 | .iter() 70 | .zip(witness.iter()) 71 | .map(|(p, w)| p.clone() * w.clone()) 72 | .fold(UnivariantPolynomial::zero(), |acc, x| acc + x); 73 | let ax = polys 74 | .a 75 | .iter() 76 | .zip(witness.iter()) 77 | .map(|(p, w)| p.clone() * w.clone()) 78 | .fold(UnivariantPolynomial::zero(), |acc, x| acc + x); 79 | let bx = polys 80 | .b 81 | .iter() 82 | .zip(witness.iter()) 83 | .map(|(p, w)| p.clone() * w.clone()) 84 | .fold(UnivariantPolynomial::zero(), |acc, x| acc + x); 85 | 86 | let t = generate_t_poly::(witness.len()); 87 | let h = ((ax.clone() * bx.clone()) - cx.clone()) / t.clone(); 88 | 89 | QAP::new(cx, ax, bx, t, h) 90 | } 91 | } 92 | 93 | impl PreProcessorInterface for PreProcessor { 94 | fn preprocess(&self) -> QAP { 95 | let qap_poly_coefficients = self.r1cs.to_qap_poly_coefficients(); 96 | qap_poly_coefficients.to_qap_polynomials(self.witness.render()) 97 | } 98 | } 99 | 100 | impl QAPInterface for QAP { 101 | fn is_satisfied(&self) -> bool { 102 | self.qap_check() 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /sum_check/src/interface.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | composed::{multicomposed::IntermidateClaimCheck, ComposedSumCheckProof}, 3 | data_structure::SumCheckProof, 4 | }; 5 | use ark_ff::PrimeField; 6 | use fiat_shamir::FiatShamirTranscript; 7 | use polynomial::{ 8 | composed::multilinear::ComposedMultilinear, interface::MultilinearPolynomialInterface, 9 | multilinear::Multilinear, univariant::UnivariantPolynomial, 10 | }; 11 | 12 | /// This trait is used to define the prover interface 13 | pub trait ProverInterface { 14 | /// This function returns the sum of the multilinear polynomial evaluation over the boolean hypercube. 15 | fn calculate_sum(poly: &Multilinear) -> F; 16 | /// This function returns the round zero computed polynomial 17 | fn compute_round_zero_poly>( 18 | poly: &P, 19 | transcript: &mut FiatShamirTranscript, 20 | ) -> P; 21 | /// This function computes sum check proof 22 | fn sum_check_proof + Clone>( 23 | poly: &P, 24 | transcript: &mut FiatShamirTranscript, 25 | sum: &F, 26 | ) -> SumCheckProof; 27 | } 28 | 29 | /// The verifier interface is used to verify the sum check proof 30 | pub trait VerifierInterface { 31 | /// This function verifies the sum check proof 32 | fn verify + Clone>(proof: &SumCheckProof) -> bool; 33 | } 34 | 35 | /// This trait is used to define the composed prover interface 36 | pub trait ComposedProverInterface { 37 | /// This function returns the sum of the multilinear polynomial evaluation over the boolean hypercube. 38 | fn calculate_sum(poly: &ComposedMultilinear) -> F; 39 | /// This function returns the round zero computed polynomial 40 | fn compute_round_zero_poly( 41 | poly: &ComposedMultilinear, 42 | transcript: &mut FiatShamirTranscript, 43 | ) -> UnivariantPolynomial; 44 | /// This function computes sum check proof 45 | fn sum_check_proof( 46 | poly: &ComposedMultilinear, 47 | transcript: &mut FiatShamirTranscript, 48 | sum: &F, 49 | ) -> (ComposedSumCheckProof, Vec); 50 | } 51 | 52 | /// The verifier interface is used to verify the sum check proof 53 | pub trait ComposedVerifierInterface { 54 | /// This function verifies the sum check proof 55 | fn verify(proof: &ComposedSumCheckProof, poly: &ComposedMultilinear) -> bool; 56 | } 57 | 58 | /// This trait is used to define the multi-composed prover interface 59 | pub trait MultiComposedProverInterface { 60 | /// This function returns the sum of the multilinear polynomial evaluation over the boolean hypercube. 61 | fn calculate_sum(poly: &[ComposedMultilinear]) -> F; 62 | /// This function computes sum check proof 63 | fn sum_check_proof( 64 | poly: &[ComposedMultilinear], 65 | sum: &F, 66 | ) -> (ComposedSumCheckProof, Vec); 67 | /// This function computes sum check proof 68 | fn sum_check_proof_without_initial_polynomial( 69 | poly: &[ComposedMultilinear], 70 | sum: &F, 71 | ) -> (ComposedSumCheckProof, Vec); 72 | fn sum_check_proof_internal( 73 | poly_: &[ComposedMultilinear], 74 | transcript: &mut FiatShamirTranscript, 75 | sum: &F, 76 | ) -> (ComposedSumCheckProof, Vec); 77 | } 78 | 79 | /// The verifier interface is used to verify the sum check proof 80 | pub trait MultiComposedVerifierInterface { 81 | /// This function verifies the sum check proof 82 | fn verify(proof: &ComposedSumCheckProof, poly: &[ComposedMultilinear]) -> bool; 83 | fn verify_except_last_check(proof: &ComposedSumCheckProof) -> IntermidateClaimCheck; 84 | fn verify_internal( 85 | proof: &ComposedSumCheckProof, 86 | transcript: &mut FiatShamirTranscript, 87 | ) -> Result, &'static str>; 88 | } 89 | -------------------------------------------------------------------------------- /groth16/src/trusted_setup.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | interfaces::TrustedSetupInterface, 3 | primitives::{QAPPolys, ToxicWaste, TrustedSetup, TrustedSetupExcecution}, 4 | utils::{ 5 | generate_c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_private, 6 | generate_c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_public, generate_powers_of_tau_g1, 7 | generate_powers_of_tau_g2, generate_powers_of_tau_t_poly_delta_inverse_g1, generate_t_poly, 8 | }, 9 | }; 10 | use ark_ec::{pairing::Pairing, Group}; 11 | use ark_ff::{Field, PrimeField}; 12 | use polynomial::interface::PolynomialInterface; 13 | 14 | impl TrustedSetupInterface

for TrustedSetup

{ 15 | fn run_trusted_setup( 16 | toxic_waste: &ToxicWaste, 17 | qap_polys: &QAPPolys, 18 | number_of_constraints: usize, 19 | ) -> TrustedSetupExcecution

{ 20 | let t_poly = generate_t_poly::(number_of_constraints); 21 | 22 | let powers_of_tau_g1 = 23 | generate_powers_of_tau_g1::

(toxic_waste.tau, number_of_constraints + 1); 24 | let powers_of_tau_g2 = 25 | generate_powers_of_tau_g2::

(toxic_waste.tau, number_of_constraints + 1); 26 | let powers_of_tau_t_poly_delta_inverse_g1 = 27 | generate_powers_of_tau_t_poly_delta_inverse_g1::

( 28 | toxic_waste.tau, 29 | toxic_waste.delta.inverse().unwrap(), 30 | &t_poly, 31 | number_of_constraints + 2, 32 | ); 33 | let beta_g2 = P::G2::generator().mul_bigint(toxic_waste.beta.into_bigint()); 34 | let alpha_g1 = P::G1::generator().mul_bigint(toxic_waste.alpha.into_bigint()); 35 | let gamma_g2 = P::G2::generator().mul_bigint(toxic_waste.gamma.into_bigint()); 36 | let delta_g2 = P::G2::generator().mul_bigint(toxic_waste.delta.into_bigint()); 37 | let beta_g1 = P::G1::generator().mul_bigint(toxic_waste.beta.into_bigint()); 38 | let delta_g1 = P::G1::generator().mul_bigint(toxic_waste.delta.into_bigint()); 39 | 40 | // this is done here because the phases for the trusted set is reduced to one 41 | // this is Ideally done when needed by the prover using linear combination 42 | // c(tau) + beta*a(tau) + alpha*c(tau)) 43 | let c_tau: Vec = qap_polys 44 | .c 45 | .iter() 46 | .map(|c| c.evaluate(&toxic_waste.tau)) 47 | .collect(); 48 | let a_tau: Vec = qap_polys 49 | .a 50 | .iter() 51 | .map(|a| a.evaluate(&toxic_waste.tau) * toxic_waste.beta) 52 | .collect(); 53 | let b_tau: Vec = qap_polys 54 | .b 55 | .iter() 56 | .map(|b| b.evaluate(&toxic_waste.tau) * toxic_waste.alpha) 57 | .collect(); 58 | let c_tau_plus_beta_a_tau_plus_alpha_b_tau: Vec = c_tau 59 | .iter() 60 | .zip(a_tau.iter()) 61 | .zip(b_tau.iter()) 62 | .map(|((c, a), b)| *c + *a + b) 63 | .collect(); 64 | 65 | let c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_public = 66 | generate_c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_public::

( 67 | &c_tau_plus_beta_a_tau_plus_alpha_b_tau, 68 | &toxic_waste.gamma, 69 | ); 70 | let c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_private = 71 | generate_c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_private::

( 72 | &c_tau_plus_beta_a_tau_plus_alpha_b_tau, 73 | &toxic_waste.delta, 74 | ); 75 | 76 | TrustedSetupExcecution::

::new( 77 | powers_of_tau_g1, 78 | powers_of_tau_g2, 79 | beta_g2, 80 | alpha_g1, 81 | beta_g1, 82 | c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_public, 83 | c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_private, 84 | powers_of_tau_t_poly_delta_inverse_g1, 85 | gamma_g2, 86 | delta_g2, 87 | delta_g1, 88 | ) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /sum_check/src/verifier.rs: -------------------------------------------------------------------------------- 1 | use crate::{data_structure::SumCheckProof, interface::VerifierInterface}; 2 | use ark_ff::PrimeField; 3 | use fiat_shamir::{interface::TranscriptInterface, FiatShamirTranscript}; 4 | use polynomial::interface::MultilinearPolynomialInterface; 5 | 6 | #[derive(Clone, Default, Debug)] 7 | pub struct Verifier; 8 | 9 | impl VerifierInterface for Verifier { 10 | /// This function verifies the sum check proof 11 | fn verify>(proof: &SumCheckProof) -> bool { 12 | // steps 13 | // 1. eval poly_0 at 0 and 1 and check if the sum is equal to the sum in the proof [done] 14 | // 2. append poly_0 to the transcript 15 | // 3. eval poly_1 at rand_0 from transcript and check if the eval of poly_0 at 0 and 1 is equal to poly_1 at rand_0 16 | // 4. append poly_1 to the transcript 17 | // 5. repeat step 3 and 4 until the last round 18 | // 6. check if the eval of the last poly at rand(last) is equal to the eval of the main poly at all rands() 19 | 20 | let mut transcript = FiatShamirTranscript::default(); 21 | let mut all_rands = Vec::new(); 22 | 23 | // step 1 24 | let untrusted_sum = proof.round_0_poly.evaluate(&vec![F::one()]).unwrap() 25 | + proof.round_0_poly.evaluate(&vec![F::zero()]).unwrap(); 26 | 27 | if untrusted_sum != proof.sum { 28 | println!( 29 | "untrusted_sum != proof.sum --> {} - {}", 30 | untrusted_sum, proof.sum 31 | ); 32 | return false; 33 | } 34 | 35 | // step 2 36 | transcript.append(proof.round_0_poly.to_bytes()); 37 | 38 | // step 3 and 4 39 | let sample_1 = F::from_be_bytes_mod_order(&transcript.sample()); 40 | all_rands.push(sample_1); 41 | let eval_poly_0_at_rand = proof.round_0_poly.evaluate(&vec![sample_1]).unwrap(); 42 | let eval_poly_1_at_0_plus_1 = proof.round_poly[0].evaluate(&vec![F::one()]).unwrap() 43 | + proof.round_poly[0].evaluate(&vec![F::zero()]).unwrap(); 44 | 45 | if eval_poly_0_at_rand != eval_poly_1_at_0_plus_1 { 46 | println!( 47 | "eval_poly_0_at_rand != eval_poly_1_at_0_plus_1 --> {} - {}", 48 | eval_poly_0_at_rand, eval_poly_1_at_0_plus_1 49 | ); 50 | return false; 51 | } 52 | 53 | transcript.append(proof.round_poly[0].to_bytes()); 54 | 55 | // step 5 56 | for i in 1..proof.round_poly.len() { 57 | let sample_i = F::from_be_bytes_mod_order(&transcript.sample()); 58 | all_rands.push(sample_i); 59 | let eval_poly_i_at_rand = proof.round_poly[i - 1].evaluate(&vec![sample_i]).unwrap(); 60 | let eval_poly_i_plus_1_at_0_plus_1 = 61 | proof.round_poly[i].evaluate(&vec![F::one()]).unwrap() 62 | + proof.round_poly[i].evaluate(&vec![F::zero()]).unwrap(); 63 | 64 | if eval_poly_i_at_rand != eval_poly_i_plus_1_at_0_plus_1 { 65 | println!( 66 | "eval_poly_i_at_rand != eval_poly_i_plus_1_at_0_plus_1 --> {} - {}", 67 | eval_poly_i_at_rand, eval_poly_i_plus_1_at_0_plus_1 68 | ); 69 | return false; 70 | } 71 | 72 | transcript.append(proof.round_poly[i].to_bytes()); 73 | } 74 | 75 | // step 6 76 | let last_round_rand = F::from_be_bytes_mod_order(&transcript.sample()); 77 | all_rands.push(last_round_rand); 78 | let eval_last_poly_at_rand = proof.round_poly[proof.round_poly.len() - 1] 79 | .evaluate(&vec![all_rands[all_rands.len() - 1]]) 80 | .unwrap(); 81 | let eval_main_poly_at_all_rands = proof.polynomial.evaluate(&all_rands).unwrap(); 82 | 83 | if eval_last_poly_at_rand != eval_main_poly_at_all_rands { 84 | println!( 85 | "eval_last_poly_at_rand != eval_main_poly_at_all_rands --> {} - {}", 86 | eval_last_poly_at_rand, eval_main_poly_at_all_rands 87 | ); 88 | return false; 89 | } 90 | 91 | true 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /polynomial/src/interface.rs: -------------------------------------------------------------------------------- 1 | use ark_ff::PrimeField; 2 | 3 | /// Describes the common interface for univariate and multivariate polynomials 4 | /// This F generic parameter should be a field 5 | pub trait PolynomialInterface { 6 | /// The type of evaluation points for this polynomial. 7 | /// this could be a set of real numbers or roots of unity depending on the intrepolation logic 8 | type Point; 9 | 10 | /// Return the total degree of the polynomial 11 | fn degree(&self) -> usize; 12 | 13 | /// Evaluates `self` at the given `point` in `Self::Point`. 14 | fn evaluate(&self, point: &Self::Point) -> F; 15 | 16 | /// Checks if the polynomial is zero 17 | fn is_zero(&self) -> bool; 18 | } 19 | 20 | pub trait UnivariantPolynomialInterface: PolynomialInterface { 21 | /// This function returs an array of co-efficents of this polynomial 22 | fn coefficients(&self) -> &[F]; 23 | /// This function createsa new polynomial from a list of coefficients slice 24 | fn from_coefficients_slice(coeffs: &[F]) -> Self; 25 | /// This function creates a new polynomial from a list of coefficients vector 26 | fn from_coefficients_vec(coeffs: Vec) -> Self; 27 | /// This function is used to create a new univariate polynomial using an interpolation 28 | fn interpolate(point_ys: Vec, domain: Vec) -> Self; 29 | } 30 | 31 | pub trait MultilinearPolynomialInterface { 32 | /// This function returns the number of variables in the polynomial 33 | fn num_vars(&self) -> usize; 34 | /// This function creates a new polynomial from a list of evaluations 35 | fn partial_evaluation(&self, evaluation_point: F, variable_index: usize) -> Self; 36 | /// This function allows for multiple parial evaluations 37 | fn partial_evaluations(&self, evaluation_points: Vec, variable_indices: Vec) -> Self; 38 | /// This function is used to evaluate the polynomial at a given point 39 | fn evaluate(&self, point: &Vec) -> Option; 40 | /// Extend polynomials with new variables 41 | /// given f(x,y) = 2xy + 3y + 4x + 5 this function can extend it to f(x,y,z) = 2xy + 3y + 4x + 5 + 0z 42 | fn extend_with_new_variables(&self, num_of_new_variables: usize) -> Self; 43 | /// Addition for multilinear polynomials with 2 distinict variables 44 | /// given f(x,y) = 2xy + 3y + 4x + 5 and f(a,b) = 2ab + 3b + 4a + 5 45 | /// f(x,y) + f(a,b) = 2xy + 3y + 4x + 5 + 2ab + 3b + 4a + 5 46 | fn add_distinct(&self, rhs: &Self) -> Self; 47 | /// Multiplication for multilinear polynomials with 2 distinict variables 48 | /// given f(x,y) = 2xy + 3y + 4x + 5 and f(a,b) = 2ab + 3b + 4a + 5 49 | /// f(x,y) * f(a,b) = 4xyab + 6yab + 8xab + 10ab + 6y + 8x + 10 50 | fn mul_distinct(&self, rhs: &Self) -> Self; 51 | /// Interpolation for multilinear polynomials with 2 distinict variables 52 | fn interpolate(y_s: &[F]) -> Self; 53 | /// This function returns the additive identity of the polynomial 54 | fn zero(num_vars: usize) -> Self; 55 | /// This function is used to check if the polynomial is zero 56 | fn is_zero(&self) -> bool; 57 | /// This function performs `Add` but in contexct of the type 58 | fn internal_add(&self, rhs: &Self) -> Self; 59 | /// This function performs `AddAssign` but in contexct of the type 60 | fn internal_add_assign(&mut self, rhs: &Self); 61 | /// This function is used to return the bytes representation of the polynomial 62 | fn to_bytes(&self) -> Vec; 63 | } 64 | 65 | pub trait MultivariatePolynomialInterface { 66 | /// This function returns the number of variables in the polynomial 67 | fn num_vars(&self) -> usize; 68 | /// This function returns the operational hypercube index 69 | fn hc_index(&self) -> usize; 70 | /// This function is used to evaluate the polynomial at a given point 71 | fn evaluate(&self, point: &Vec) -> Option; 72 | /// This function creates a new polynomial from a list of evaluations 73 | fn partial_evaluation(&self, evaluation_point: F, variable_index: usize) -> Self; 74 | /// This function allows for multiple parial evaluations 75 | fn partial_evaluations(&self, evaluation_points: Vec, variable_indices: Vec) -> Self; 76 | } 77 | -------------------------------------------------------------------------------- /groth16/src/protocol.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | interfaces::ProtocolInterface, 3 | primitives::{Proof, ProofRands, TrustedSetupExcecution, QAP}, 4 | utils::{ 5 | internal_product_g1, linear_combination_homomorphic_poly_eval_g1, 6 | linear_combination_homomorphic_poly_eval_g2, PRIVATE_VARIABLES_INDEX, 7 | }, 8 | }; 9 | use ark_ec::{pairing::Pairing, Group}; 10 | use ark_ff::PrimeField; 11 | use circuits::primitives::Witness; 12 | 13 | /// This is the Groth16 protocol implementation (Struct binding to the ProtocolInterface) 14 | pub struct Groth16Protocol { 15 | // just binding this struct to this type... 16 | phantom: std::marker::PhantomData

, 17 | } 18 | 19 | impl ProtocolInterface

for Groth16Protocol

{ 20 | /// This function is used to generate a groth16 proof 21 | /// parameters: 22 | /// proof_rands: The random values used to generate the proof 23 | /// 24 | /// this proofing would be done in this manner; 25 | /// A is calculated, then B, then C 26 | /// proof = ([A]_1, [B]_2, [C]_1) 27 | fn generate_proof( 28 | proof_rands: ProofRands, 29 | trusted_setup: &TrustedSetupExcecution

, 30 | qap: &QAP, 31 | witness: &Witness, 32 | ) -> Proof

{ 33 | // generating A (g) 34 | let r_delta_g1 = trusted_setup 35 | .delta_g1 36 | .mul_bigint(proof_rands.r.into_bigint()); 37 | let qap_a_at_tau: P::G1 = linear_combination_homomorphic_poly_eval_g1::

( 38 | &qap.ax, 39 | &trusted_setup.powers_of_tau_g1, 40 | ); 41 | let a_g1 = r_delta_g1 + trusted_setup.alpha_g1 + qap_a_at_tau; 42 | 43 | // generating B (g2) 44 | let s_delta_g2 = trusted_setup 45 | .delta_g2 46 | .mul_bigint(proof_rands.s.into_bigint()); 47 | let qap_b_at_tau = linear_combination_homomorphic_poly_eval_g2::

( 48 | &qap.bx, 49 | &trusted_setup.powers_of_tau_g2, 50 | ); 51 | let b_g2 = s_delta_g2 + trusted_setup.beta_g2 + qap_b_at_tau; 52 | 53 | // generate B (g1) 54 | let s_delta_g1 = trusted_setup 55 | .delta_g1 56 | .mul_bigint(proof_rands.s.into_bigint()); 57 | let qap_b_at_tau = linear_combination_homomorphic_poly_eval_g1::

( 58 | &qap.bx, 59 | &trusted_setup.powers_of_tau_g1, 60 | ); 61 | let b_g1 = s_delta_g1 + trusted_setup.beta_g1 + qap_b_at_tau; 62 | 63 | let witness_vec = witness.render(); 64 | let _x_g1 = internal_product_g1::

( 65 | &trusted_setup.c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_public, 66 | &witness_vec[..PRIVATE_VARIABLES_INDEX].to_vec(), 67 | ); 68 | 69 | let c_prime_g1 = internal_product_g1::

( 70 | &trusted_setup.c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_private, 71 | &witness_vec[PRIVATE_VARIABLES_INDEX..].to_vec(), 72 | ); 73 | let ht_g1 = linear_combination_homomorphic_poly_eval_g1::

( 74 | &qap.h, 75 | &trusted_setup.powers_of_tau_t_poly_delta_inverse_g1, 76 | ); 77 | 78 | let s_a_g1 = a_g1.mul_bigint(proof_rands.s.into_bigint()); 79 | let r_b_g1 = b_g1.mul_bigint(proof_rands.r.into_bigint()); 80 | let r_mul_s_delta_g1 = trusted_setup 81 | .delta_g1 82 | .mul_bigint((proof_rands.r * proof_rands.s).into_bigint()); 83 | let c_g1 = c_prime_g1 + ht_g1 + s_a_g1 + r_b_g1 + (-r_mul_s_delta_g1); 84 | 85 | Proof { 86 | a: a_g1, 87 | b: b_g2, 88 | c: c_g1, 89 | } 90 | } 91 | 92 | /// This function is used to verify a groth16 proof 93 | fn verify_proof( 94 | proof: &Proof

, 95 | trusted_setup: &TrustedSetupExcecution

, 96 | public_input: &Vec, 97 | ) -> bool { 98 | let lhs = P::pairing(proof.a, proof.b); 99 | let rhs_1 = P::pairing(trusted_setup.alpha_g1, trusted_setup.beta_g2); 100 | let rhs_2 = P::pairing( 101 | internal_product_g1::

( 102 | &trusted_setup.c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_public, 103 | public_input, 104 | ), 105 | trusted_setup.gamma_g2, 106 | ); 107 | let rhs_3 = P::pairing(proof.c, trusted_setup.delta_g2); 108 | 109 | lhs == (rhs_1 + rhs_2 + rhs_3) 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /polynomial-commitment-schemes/kzg-rust/src/utils.rs: -------------------------------------------------------------------------------- 1 | use ark_ec::{pairing::Pairing, Group}; 2 | use ark_ff::PrimeField; 3 | use polynomial::univariant::UnivariantPolynomial; 4 | 5 | pub fn linear_combination_homomorphic_poly_eval_g1

( 6 | poly: &UnivariantPolynomial, 7 | powers_of_secret_gx: &[P::G1], 8 | ) -> P::G1 9 | where 10 | P: Pairing, 11 | { 12 | poly.coefficients 13 | .iter() 14 | .enumerate() 15 | .fold(P::G1::default(), |mut acc, (index, coeff)| { 16 | let res = powers_of_secret_gx[index].mul_bigint(coeff.into_bigint()); 17 | acc = acc + res; 18 | acc 19 | }) 20 | } 21 | 22 | /// This function generates the powers of tau for the circuit 23 | /// tau = 5; 24 | /// powers_of_tau_g1 = [g.5^0 g.5^1, g.5^2, g.5^3, g.5^4, g.5^5, g.5^6, g.5^7] 25 | pub fn generate_powers_of_tau_g1(tau: &P::ScalarField, n: usize) -> Vec { 26 | let n = n + 1; 27 | let mut powers_of_tau_g1 = Vec::with_capacity(n); 28 | let mut tau_power = *tau; 29 | let generator = P::G1::generator(); 30 | 31 | powers_of_tau_g1.push(generator); 32 | 33 | for _ in 1..n { 34 | powers_of_tau_g1.push(generator.mul_bigint(tau_power.into_bigint())); 35 | tau_power = tau_power * *tau; 36 | } 37 | 38 | powers_of_tau_g1 39 | } 40 | 41 | pub fn linear_combination_homomorphic_poly_eval_g1_primefield( 42 | poly: &UnivariantPolynomial, 43 | powers_of_secret_gx: &[P::G1], 44 | ) -> P::G1 45 | where 46 | P: Pairing, 47 | F: PrimeField, 48 | { 49 | poly.coefficients 50 | .iter() 51 | .enumerate() 52 | .fold(P::G1::default(), |mut acc, (index, coeff)| { 53 | let res = powers_of_secret_gx[index].mul_bigint(coeff.into_bigint()); 54 | acc = acc + res; 55 | acc 56 | }) 57 | } 58 | 59 | pub fn perform_zero_and_one_check(pattern: &[F], object: &[F]) -> F { 60 | let mut result = F::one(); 61 | 62 | for (i, hypercube_element) in pattern.iter().enumerate() { 63 | if hypercube_element.is_zero() { 64 | result *= F::one() - object[i]; 65 | } else { 66 | result *= object[i] 67 | } 68 | } 69 | 70 | result 71 | } 72 | 73 | pub fn bh_to_g1_srs(bh: &[Vec], object: &[F]) -> Vec { 74 | let mut srs = Vec::with_capacity(bh.len()); 75 | let generator = P::G1::generator(); 76 | 77 | for i in bh.iter() { 78 | let result = perform_zero_and_one_check(i, object); 79 | srs.push(generator.mul_bigint(result.into_bigint())); 80 | } 81 | 82 | srs 83 | } 84 | 85 | pub fn g2_operation(oprands: &[F]) -> Vec { 86 | let mut result = Vec::with_capacity(oprands.len()); 87 | let generator = P::G2::generator(); 88 | 89 | for i in oprands.iter() { 90 | result.push(generator.mul_bigint(i.into_bigint())) 91 | } 92 | 93 | result 94 | } 95 | 96 | #[cfg(test)] 97 | mod tests { 98 | use super::*; 99 | use ark_test_curves::bls12_381::Fr; 100 | 101 | fn generator_operation(oprands: &[F]) -> Vec { 102 | let mut result = Vec::with_capacity(oprands.len()); 103 | let generator = P::G1::generator(); 104 | 105 | for i in oprands.iter() { 106 | result.push(generator.mul_bigint(i.into_bigint())) 107 | } 108 | 109 | result 110 | } 111 | 112 | #[test] 113 | fn test_perform_zero_and_one_check() { 114 | let object = vec![Fr::from(2u8), Fr::from(4u8)]; 115 | 116 | let pattern_1 = vec![Fr::from(0u8), Fr::from(0u8)]; 117 | let pattern_2 = vec![Fr::from(0u8), Fr::from(1u8)]; 118 | let pattern_3 = vec![Fr::from(1u8), Fr::from(0u8)]; 119 | let pattern_4 = vec![Fr::from(1u8), Fr::from(1u8)]; 120 | 121 | let result_1 = perform_zero_and_one_check(&pattern_1, &object); 122 | let result_2 = perform_zero_and_one_check(&pattern_2, &object); 123 | let result_3 = perform_zero_and_one_check(&pattern_3, &object); 124 | let result_4 = perform_zero_and_one_check(&pattern_4, &object); 125 | 126 | assert_eq!(result_1, Fr::from(3u8)); 127 | assert_eq!(result_2, Fr::from(-4)); 128 | assert_eq!(result_3, Fr::from(-6)); 129 | assert_eq!(result_4, Fr::from(8u8)); 130 | } 131 | 132 | #[test] 133 | fn test_bh_to_g1_srs() { 134 | let object = vec![Fr::from(2u8), Fr::from(4u8)]; 135 | let bh = vec![ 136 | vec![Fr::from(0u8), Fr::from(0u8)], 137 | vec![Fr::from(0u8), Fr::from(1u8)], 138 | vec![Fr::from(1u8), Fr::from(0u8)], 139 | vec![Fr::from(1u8), Fr::from(1u8)], 140 | ]; 141 | 142 | let srs = bh_to_g1_srs::(&bh, &object); 143 | 144 | assert_eq!(srs.len(), 4); 145 | assert_eq!( 146 | srs, 147 | generator_operation::(&[ 148 | Fr::from(3u8), 149 | Fr::from(-4), 150 | Fr::from(-6), 151 | Fr::from(8u8) 152 | ]) 153 | ); 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /gkr/src/utils.rs: -------------------------------------------------------------------------------- 1 | use ark_ff::PrimeField; 2 | use fiat_shamir::{interface::TranscriptInterface, FiatShamirTranscript}; 3 | use polynomial::{ 4 | composed::multilinear::ComposedMultilinear, 5 | interface::{MultilinearPolynomialInterface, PolynomialInterface}, 6 | multilinear::Multilinear, 7 | univariant::UnivariantPolynomial, 8 | }; 9 | use sum_check::{ 10 | composed::{ 11 | multicomposed::{MultiComposedProver, MultiComposedVerifier}, 12 | ComposedSumCheckProof, 13 | }, 14 | interface::{MultiComposedProverInterface, MultiComposedVerifierInterface}, 15 | }; 16 | 17 | pub fn gen_w_mle(evals: &[Vec], layer_index: usize) -> Multilinear { 18 | // see if the layer index is out of bounds 19 | if layer_index >= evals.len() { 20 | panic!("Layer index out of bounds"); 21 | } 22 | 23 | Multilinear::interpolate(&evals[layer_index]) 24 | } 25 | 26 | pub fn gen_l( 27 | b: &[F], 28 | c: &[F], 29 | ) -> Result>, &'static str> { 30 | // perfroming some santiy checks 31 | if b.len() != c.len() { 32 | return Err("Length of b and c must be the same"); 33 | } 34 | 35 | Ok(b.iter() 36 | .zip(c.iter()) 37 | .map(|(b, c)| { 38 | let coeffs = vec![*b, *c - b]; 39 | UnivariantPolynomial::new(coeffs) 40 | }) 41 | .collect()) 42 | } 43 | 44 | pub fn evaluate_l(l: &[UnivariantPolynomial], x: F) -> Vec { 45 | l.iter().map(|l_i| l_i.evaluate(&x)).collect() 46 | } 47 | 48 | pub fn gen_q( 49 | l: &[UnivariantPolynomial], 50 | w: Multilinear, 51 | ) -> Result, &'static str> { 52 | // performing some sanity checks 53 | if l.len() != w.num_vars() { 54 | return Err("Length of l and w must be the same"); 55 | } 56 | 57 | todo!() 58 | } 59 | 60 | pub fn perform_gkr_sumcheck_layer_one( 61 | claim: F, 62 | layer_one_r: Vec, 63 | add_mle: &Multilinear, 64 | mul_mle: &Multilinear, 65 | w_mle: &Multilinear, 66 | transcript: &mut FiatShamirTranscript, 67 | sum_check_proofs: &mut Vec>, 68 | w_i_b: &mut Vec, 69 | w_i_c: &mut Vec, 70 | ) -> (F, Vec, Vec, F, F) { 71 | let number_of_round = layer_one_r.len(); 72 | 73 | // add(r, b, c) ---> add(b, c) 74 | let add_b_c = add_mle.partial_evaluations(layer_one_r.clone(), vec![0; number_of_round]); 75 | // mul(r, b, c) ---> mul(b, c) 76 | let mul_b_c = mul_mle.partial_evaluations(layer_one_r, vec![0; number_of_round]); 77 | 78 | let wb = w_mle.clone(); 79 | let wc = w_mle.clone(); 80 | 81 | // w_i(b) + w_i(c) 82 | let wb_add_wc = wb.add_distinct(&wc); 83 | // w_i(b) * w_i(c) 84 | let wb_mul_wc = wb.mul_distinct(&wc); 85 | 86 | // add(b, c)(w_i(b) + w_i(c)) 87 | let f_b_c_add_section = ComposedMultilinear::new(vec![add_b_c, wb_add_wc]); 88 | // mul(b, c)(w_i(b) * w_i(c)) 89 | let f_b_c_mul_section = ComposedMultilinear::new(vec![mul_b_c, wb_mul_wc]); 90 | 91 | // f(b, c) = add(r, b, c)(w_i(b) + w_i(c)) + mul(r, b, c)(w_i(b) * w_i(c)) 92 | let f_b_c = vec![f_b_c_add_section, f_b_c_mul_section]; 93 | 94 | // this prover that the `claim` is the result of the evalution of the preivous layer 95 | let (sumcheck_proof, random_challenges) = 96 | MultiComposedProver::sum_check_proof_without_initial_polynomial(&f_b_c, &claim); 97 | 98 | transcript.append(sumcheck_proof.to_bytes()); 99 | sum_check_proofs.push(sumcheck_proof); 100 | 101 | let (rand_b, rand_c) = random_challenges.split_at(random_challenges.len() / 2); 102 | 103 | let eval_w_i_b = wb.evaluate(&rand_b.to_vec()).unwrap(); 104 | let eval_w_i_c = wc.evaluate(&rand_c.to_vec()).unwrap(); 105 | 106 | w_i_b.push(eval_w_i_b); 107 | w_i_c.push(eval_w_i_c); 108 | 109 | let alpha: F = transcript.sample_as_field_element(); 110 | let beta: F = transcript.sample_as_field_element(); 111 | 112 | let new_claim = alpha * eval_w_i_b + beta * eval_w_i_c; 113 | 114 | (new_claim, rand_b.to_vec(), rand_c.to_vec(), alpha, beta) 115 | } 116 | 117 | pub fn verifiy_gkr_sumcheck_layer_one( 118 | layer_one_expected_claim: &F, // this should be the excecution of layer zero 119 | layer_one_sum_check_proof: &ComposedSumCheckProof, // this is the sum check proof from layer one excecuted by the prover 120 | transcript: &mut FiatShamirTranscript, 121 | w_b: F, 122 | w_c: F, 123 | n_r: Vec, 124 | add_mle: &Multilinear, 125 | mul_mle: &Multilinear, 126 | ) -> (bool, F) { 127 | // check if the claim is the same as the expected claim 128 | if *layer_one_expected_claim != layer_one_sum_check_proof.sum { 129 | println!("Invalid sumcheck proof"); 130 | (false, F::ZERO); 131 | } 132 | 133 | transcript.append(layer_one_sum_check_proof.to_bytes()); 134 | 135 | let intermidate_claim_check = 136 | MultiComposedVerifier::verify_except_last_check(&layer_one_sum_check_proof); 137 | 138 | // performing sum check last check 139 | let mut r_b_c = n_r; 140 | r_b_c.extend_from_slice(&intermidate_claim_check.random_challenges); 141 | 142 | let add_b_c = add_mle.evaluate(&r_b_c).unwrap(); 143 | let mul_b_c = mul_mle.evaluate(&r_b_c).unwrap(); 144 | 145 | let add_section = add_b_c * (w_b + w_c); 146 | let mul_section = mul_b_c * (w_b * w_c); 147 | 148 | let f_b_c_eval = add_section + mul_section; 149 | 150 | if f_b_c_eval != intermidate_claim_check.claimed_sum { 151 | println!("Invalid sumcheck proof"); 152 | return (false, F::ZERO); 153 | } 154 | 155 | let alpha: F = transcript.sample_as_field_element(); 156 | let beta: F = transcript.sample_as_field_element(); 157 | 158 | let new_claim = alpha * w_b + beta * w_c; 159 | 160 | (true, new_claim) 161 | } 162 | -------------------------------------------------------------------------------- /circuits/src/adapters/r1cs.rs: -------------------------------------------------------------------------------- 1 | //! This goal of the module is to provide a way to transpile a circuit into a R1CS representation. 2 | 3 | use crate::{ 4 | interfaces::ExtractConstraintsInterface, 5 | primitives::{Circuit, Constraint, ConstraintRaw, ConstraintsWithLabelSize, GateType}, 6 | utils::compute_constraint_item, 7 | }; 8 | use std::collections::HashMap; 9 | 10 | impl ExtractConstraintsInterface for Circuit { 11 | /// Extracts the constraints from the circuit and returns them as a vector of constraints. 12 | fn extract_constraints(&self) -> ConstraintsWithLabelSize { 13 | let mut label_to_index_mapping = HashMap::new(); 14 | let mut latest_constraint_index = 1; 15 | let mut raw_constraints = Vec::::new(); 16 | 17 | for (layer_index, layer) in self.layers.iter().enumerate() { 18 | for (gate_index, gate) in layer.layer.iter().enumerate() { 19 | let c_label = compute_constraint_item(layer_index, gate_index); 20 | let a_label = compute_constraint_item(layer_index + 1, gate.inputs[0]); 21 | let b_label = compute_constraint_item(layer_index + 1, gate.inputs[1]); 22 | 23 | match label_to_index_mapping.entry(c_label) { 24 | std::collections::hash_map::Entry::Occupied(_) => {} 25 | std::collections::hash_map::Entry::Vacant(e) => { 26 | e.insert(latest_constraint_index); 27 | latest_constraint_index += 1; 28 | } 29 | } 30 | 31 | match label_to_index_mapping.entry(a_label) { 32 | std::collections::hash_map::Entry::Occupied(_) => {} 33 | std::collections::hash_map::Entry::Vacant(e) => { 34 | e.insert(latest_constraint_index); 35 | latest_constraint_index += 1; 36 | } 37 | } 38 | 39 | match label_to_index_mapping.entry(b_label) { 40 | std::collections::hash_map::Entry::Occupied(_) => {} 41 | std::collections::hash_map::Entry::Vacant(e) => { 42 | e.insert(latest_constraint_index); 43 | latest_constraint_index += 1; 44 | } 45 | } 46 | 47 | match gate.g_type { 48 | GateType::Add => { 49 | let labeled_constraint = ConstraintRaw { 50 | a: vec![a_label, b_label], 51 | b: vec![], 52 | c: vec![c_label], 53 | }; 54 | 55 | raw_constraints.push(labeled_constraint); 56 | } 57 | GateType::Mul => { 58 | let labeled_constraint = ConstraintRaw { 59 | a: vec![a_label], 60 | b: vec![b_label], 61 | c: vec![c_label], 62 | }; 63 | 64 | raw_constraints.push(labeled_constraint); 65 | } 66 | } 67 | } 68 | } 69 | 70 | let constraints = raw_constraints 71 | .iter() 72 | .map(|raw_constraint| raw_constraint.to_constraint(label_to_index_mapping.clone())) 73 | .collect::>(); 74 | 75 | ConstraintsWithLabelSize { 76 | constraints, 77 | label_size: latest_constraint_index, 78 | } 79 | } 80 | } 81 | 82 | #[cfg(test)] 83 | mod tests { 84 | use super::*; 85 | use crate::primitives::{CircuitLayer, Gate, Witness}; 86 | use ark_test_curves::bls12_381::Fr; 87 | 88 | // sample circuit evaluation 89 | // 100(*) - layer 0 90 | // / \ 91 | // 5(+)_0 20(*)_1 - layer 1 92 | // / \ / \ 93 | // 2 3 4 5 94 | #[test] 95 | fn test_circuit_to_r1cs() { 96 | let layer_0 = CircuitLayer::new(vec![Gate::new(GateType::Add, [0, 1])]); 97 | let layer_1 = CircuitLayer::new(vec![ 98 | Gate::new(GateType::Mul, [0, 1]), 99 | Gate::new(GateType::Add, [2, 3]), 100 | ]); 101 | let circuit = Circuit::new(vec![layer_0, layer_1]); 102 | 103 | let constraints = circuit.extract_constraints(); 104 | 105 | assert_eq!(constraints.label_size, 8); 106 | assert_eq!(constraints.constraints.len(), 3); 107 | 108 | let r1cs = constraints.to_r1cs_vec::(); 109 | assert_eq!(r1cs.a.len(), 3); 110 | assert_eq!(r1cs.b.len(), 3); 111 | assert_eq!(r1cs.c.len(), 3); 112 | } 113 | 114 | // sample circuit evaluation 115 | // 100(*) - layer 0 116 | // / \ 117 | // 5(+)_0 20(*)_1 - layer 1 118 | // / \ / \ 119 | // 2 3 4 5 120 | #[test] 121 | fn test_circuit_to_r1cs_with_checks() { 122 | let layer_0 = CircuitLayer::new(vec![Gate::new(GateType::Add, [0, 1])]); 123 | let layer_1 = CircuitLayer::new(vec![ 124 | Gate::new(GateType::Mul, [0, 1]), 125 | Gate::new(GateType::Add, [2, 3]), 126 | ]); 127 | let circuit = Circuit::new(vec![layer_0, layer_1]); 128 | 129 | let constraints = circuit.extract_constraints(); 130 | 131 | assert_eq!(constraints.label_size, 8); 132 | assert_eq!(constraints.constraints.len(), 3); 133 | 134 | let r1cs = constraints.to_r1cs_vec::(); 135 | 136 | let witness = Witness::new( 137 | vec![Fr::from(1u32)], 138 | vec![ 139 | Fr::from(15u32), 140 | Fr::from(6u32), 141 | Fr::from(9u32), 142 | Fr::from(2u32), 143 | Fr::from(3u32), 144 | Fr::from(4u32), 145 | Fr::from(5u32), 146 | ], 147 | ); 148 | 149 | println!("r1cs a: {:?}", r1cs.c); 150 | 151 | let r1cs_check = r1cs.check(witness.render()); 152 | assert!(r1cs_check, "this is the R1CS check"); 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /circuits/src/primitives.rs: -------------------------------------------------------------------------------- 1 | use crate::utils::check_init; 2 | use ark_ff::PrimeField; 3 | use std::collections::HashMap; 4 | 5 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 6 | pub enum GateType { 7 | /// This represents an addtion gate 8 | Add, 9 | /// This represents a multipication gate 10 | Mul, 11 | } 12 | 13 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 14 | pub struct Gate { 15 | /// This represents the gate-type 16 | pub g_type: GateType, 17 | /// This represents the inputs to this gate (this input to the gate are two finite field element) 18 | pub inputs: [usize; 2], 19 | } 20 | 21 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 22 | pub struct Constraint { 23 | // a, b, c; where c = a.b; 24 | pub a: Vec, 25 | pub b: Vec, 26 | pub c: Vec, 27 | } 28 | 29 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 30 | pub struct ConstraintsWithLabelSize { 31 | pub constraints: Vec, 32 | pub label_size: usize, 33 | } 34 | 35 | pub struct ConstraintRaw { 36 | pub a: Vec, 37 | pub b: Vec, 38 | pub c: Vec, 39 | } 40 | 41 | #[derive(Clone, PartialEq, Eq, Hash, Default, Debug)] 42 | pub struct CircuitLayer { 43 | /// This circuit layer is just a row of gates 44 | pub layer: Vec, 45 | } 46 | 47 | #[derive(Clone, PartialEq, Eq, Hash, Default, Debug)] 48 | pub struct Circuit { 49 | /// The circuit is a vector of layers 50 | pub layers: Vec, 51 | } 52 | 53 | #[derive(Clone, PartialEq, Eq, Hash, Default, Debug)] 54 | pub struct CircuitEvaluation { 55 | /// This is the curcuit evaluation on every layer 56 | pub layers: Vec>, 57 | } 58 | 59 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 60 | pub struct R1CS { 61 | /// This is the C matrix 62 | pub c: Vec>, 63 | /// This is the A matrix 64 | pub a: Vec>, 65 | /// This is the B matrix 66 | pub b: Vec>, 67 | } 68 | 69 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 70 | pub struct Witness { 71 | /// The public input to the circuit 72 | pub public_input: Vec, 73 | /// The auxiliary input to the circuit (private input) 74 | pub auxiliary_input: Vec, 75 | } 76 | 77 | impl Gate { 78 | pub fn new(g_type: GateType, inputs: [usize; 2]) -> Self { 79 | Gate { g_type, inputs } 80 | } 81 | } 82 | 83 | impl CircuitLayer { 84 | pub fn new(layer: Vec) -> Self { 85 | CircuitLayer { layer } 86 | } 87 | } 88 | 89 | impl Circuit { 90 | pub fn new(layers: Vec) -> Self { 91 | Circuit { layers } 92 | } 93 | 94 | pub fn random(num_of_layers: usize) -> Self { 95 | let mut layers = Vec::new(); 96 | 97 | for layer_index in 0..num_of_layers { 98 | let mut layer = Vec::new(); 99 | let number_of_gates = 2usize.pow(layer_index as u32); 100 | let number_of_inputs = 2usize.pow((layer_index + 1) as u32); 101 | 102 | for gate_index in 0..number_of_gates { 103 | let input_1 = (gate_index * 2) % number_of_inputs; 104 | let input_2 = (gate_index * 2 + 1) % number_of_inputs; 105 | let g_type = if layer_index % 2 == 0 { 106 | GateType::Add 107 | } else { 108 | GateType::Mul 109 | }; 110 | layer.push(Gate::new(g_type, [input_1, input_2])); 111 | } 112 | 113 | layers.push(CircuitLayer::new(layer)); 114 | } 115 | 116 | Circuit::new(layers) 117 | } 118 | } 119 | 120 | impl CircuitEvaluation { 121 | pub fn new(layers: Vec>) -> Self { 122 | CircuitEvaluation { layers } 123 | } 124 | } 125 | 126 | impl Constraint { 127 | pub fn new(a: Vec, b: Vec, c: Vec) -> Self { 128 | Constraint { a, b, c } 129 | } 130 | } 131 | 132 | impl ConstraintRaw { 133 | pub fn new(a: Vec, b: Vec, c: Vec) -> Self { 134 | ConstraintRaw { a, b, c } 135 | } 136 | 137 | pub fn to_constraint(&self, constraint_map: HashMap) -> Constraint { 138 | let a = self.a.iter().map(|x| constraint_map[x]).collect(); 139 | let b = self.b.iter().map(|x| constraint_map[x]).collect(); 140 | let c = self.c.iter().map(|x| constraint_map[x]).collect(); 141 | 142 | Constraint::new(a, b, c) 143 | } 144 | } 145 | 146 | impl ConstraintsWithLabelSize { 147 | pub fn new(constraints: Vec, label_size: usize) -> Self { 148 | ConstraintsWithLabelSize { 149 | constraints, 150 | label_size, 151 | } 152 | } 153 | 154 | pub fn to_r1cs_vec(&self) -> R1CS { 155 | let mut a = vec![vec![F::zero(); self.label_size]; self.constraints.len()]; 156 | let mut b = vec![vec![F::zero(); self.label_size]; self.constraints.len()]; 157 | let mut c = vec![vec![F::zero(); self.label_size]; self.constraints.len()]; 158 | 159 | for (c_i, constraint) in self.constraints.iter().enumerate() { 160 | if constraint.a.len() == 0 { 161 | a[c_i][0] = F::one(); 162 | } else { 163 | for a_val in constraint.a.iter() { 164 | a[c_i][*a_val] = F::one(); 165 | } 166 | } 167 | 168 | if constraint.b.len() == 0 { 169 | b[c_i][0] = F::one(); 170 | } else { 171 | for b_val in constraint.b.iter() { 172 | b[c_i][*b_val] = F::one(); 173 | } 174 | } 175 | 176 | if constraint.c.len() == 0 { 177 | c[c_i][0] = F::one(); 178 | } else { 179 | for c_val in constraint.c.iter() { 180 | c[c_i][*c_val] = F::one(); 181 | } 182 | } 183 | } 184 | 185 | R1CS::new(a, b, c) 186 | } 187 | } 188 | 189 | impl R1CS { 190 | pub fn new(a: Vec>, b: Vec>, c: Vec>) -> Self { 191 | Self { a, b, c } 192 | } 193 | 194 | pub fn check(&self, witness: Vec) -> bool { 195 | check_init( 196 | self.a.clone(), 197 | self.b.clone(), 198 | self.c.clone(), 199 | witness.clone(), 200 | ) 201 | } 202 | } 203 | 204 | impl Witness { 205 | pub fn new(public_input: Vec, auxiliary_input: Vec) -> Self { 206 | Self { 207 | public_input, 208 | auxiliary_input, 209 | } 210 | } 211 | 212 | pub fn render(&self) -> Vec { 213 | let mut ren = self.public_input.clone(); 214 | ren.extend(self.auxiliary_input.clone()); 215 | ren 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /polynomial/src/composed/multilinear.rs: -------------------------------------------------------------------------------- 1 | use crate::composed::interfaces::ComposedMultilinearInterface; 2 | use crate::interface::MultilinearPolynomialInterface; 3 | use crate::multilinear::Multilinear; 4 | use ark_ff::PrimeField; 5 | 6 | /// This is a composition of multilinear polynomials whose binding operation is multiplication 7 | #[derive(Clone, PartialEq, Eq, Hash, Default, Debug)] 8 | pub struct ComposedMultilinear { 9 | /// These are all the multilinear polynomials 10 | pub polys: Vec>, 11 | } 12 | 13 | impl ComposedMultilinear { 14 | /// This is the constructor for the composed multilinear polynomial 15 | pub fn new(polys: Vec>) -> Self { 16 | // check to see that all the polynomials have the same number of variables 17 | let n_vars = polys[0].num_vars(); 18 | assert!(polys.iter().all(|p| p.num_vars() == n_vars)); 19 | 20 | ComposedMultilinear { polys } 21 | } 22 | } 23 | 24 | impl MultilinearPolynomialInterface for ComposedMultilinear { 25 | fn num_vars(&self) -> usize { 26 | self.polys[0].num_vars() 27 | } 28 | 29 | fn partial_evaluation(&self, evaluation_point: F, variable_index: usize) -> Self { 30 | // this would perform partial evaluation on all the composing polynomials 31 | let mut new_polys = Vec::new(); 32 | 33 | for poly in &self.polys { 34 | new_polys.push(poly.partial_evaluation(evaluation_point, variable_index)); 35 | } 36 | 37 | ComposedMultilinear { polys: new_polys } 38 | } 39 | 40 | fn partial_evaluations(&self, evaluation_points: Vec, variable_indices: Vec) -> Self { 41 | let mut eval_polynomial = self.clone(); 42 | 43 | if evaluation_points.len() != variable_indices.len() { 44 | panic!( 45 | "The length of evaluation_points and variable_indices should be the same: {}, {}", 46 | evaluation_points.len(), 47 | variable_indices.len() 48 | ); 49 | } 50 | 51 | for i in 0..evaluation_points.len() { 52 | eval_polynomial = 53 | eval_polynomial.partial_evaluation(evaluation_points[i], variable_indices[i]); 54 | } 55 | 56 | eval_polynomial 57 | } 58 | 59 | fn evaluate(&self, point: &Vec) -> Option { 60 | let mut result = F::one(); 61 | 62 | for poly in &self.polys { 63 | let eval = poly.evaluate(point); 64 | match eval { 65 | Some(val) => result *= val, 66 | None => return None, 67 | } 68 | } 69 | 70 | Some(result) 71 | } 72 | 73 | fn extend_with_new_variables(&self, _: usize) -> Self { 74 | unimplemented!() 75 | } 76 | 77 | fn add_distinct(&self, _: &Self) -> Self { 78 | unimplemented!() 79 | } 80 | 81 | fn mul_distinct(&self, _: &Self) -> Self { 82 | unimplemented!() 83 | } 84 | 85 | fn interpolate(_: &[F]) -> Self { 86 | unimplemented!() 87 | } 88 | 89 | fn zero(_: usize) -> Self { 90 | Self { polys: vec![] } 91 | } 92 | 93 | fn is_zero(&self) -> bool { 94 | if self.polys.len() == 0 { 95 | return true; 96 | } else { 97 | if self.polys.iter().all(|p| p.is_zero()) { 98 | return true; 99 | } else { 100 | return false; 101 | } 102 | } 103 | } 104 | 105 | fn internal_add(&self, _: &Self) -> Self { 106 | unimplemented!() 107 | } 108 | 109 | fn internal_add_assign(&mut self, _: &Self) { 110 | unimplemented!() 111 | } 112 | 113 | fn to_bytes(&self) -> Vec { 114 | let mut bytes = vec![]; 115 | 116 | for poly in &self.polys { 117 | bytes.extend_from_slice(&poly.to_bytes()); 118 | } 119 | 120 | bytes 121 | } 122 | } 123 | 124 | impl ComposedMultilinearInterface for ComposedMultilinear { 125 | fn elementwise_product(&self) -> Vec { 126 | // Find the minimum length of the vectors 127 | let min_length = match self.polys.get(0) { 128 | Some(poly) => poly.evaluations.len(), 129 | None => 0, 130 | }; 131 | 132 | // Perform element-wise product 133 | (0..min_length) 134 | .map(|i| self.polys.iter().map(|v| v.evaluations[i]).product()) 135 | .collect() 136 | } 137 | 138 | fn max_degree(&self) -> usize { 139 | self.polys.len() 140 | } 141 | } 142 | 143 | #[cfg(test)] 144 | mod tests { 145 | use super::*; 146 | use ark_test_curves::bls12_381::Fr; 147 | 148 | #[test] 149 | fn test_evaluation() { 150 | let poly1 = Multilinear::new(vec![Fr::from(0), Fr::from(1), Fr::from(2), Fr::from(3)], 2); 151 | let poly2 = Multilinear::new(vec![Fr::from(0), Fr::from(0), Fr::from(0), Fr::from(1)], 2); 152 | 153 | let composed = ComposedMultilinear::new(vec![poly1, poly2]); 154 | 155 | let eval = composed.evaluate(&vec![Fr::from(2), Fr::from(3)]); 156 | assert_eq!(eval, Some(Fr::from(42))); 157 | } 158 | 159 | #[test] 160 | fn test_partial_evaluation() { 161 | let poly1 = Multilinear::new(vec![Fr::from(0), Fr::from(1), Fr::from(2), Fr::from(3)], 2); 162 | let poly2 = Multilinear::new(vec![Fr::from(0), Fr::from(0), Fr::from(0), Fr::from(1)], 2); 163 | 164 | let composed = ComposedMultilinear::new(vec![poly1, poly2]); 165 | 166 | let eval = composed.partial_evaluation(Fr::from(2), 0); 167 | assert_eq!(eval.evaluate(&vec![Fr::from(3)]), Some(Fr::from(42))); 168 | } 169 | 170 | #[test] 171 | fn test_partial_evaluations() { 172 | let poly1 = Multilinear::new(vec![Fr::from(0), Fr::from(1), Fr::from(2), Fr::from(3)], 2); 173 | let poly2 = Multilinear::new(vec![Fr::from(0), Fr::from(0), Fr::from(0), Fr::from(1)], 2); 174 | 175 | let composed = ComposedMultilinear::new(vec![poly1, poly2]); 176 | 177 | let eval = composed.partial_evaluations(vec![Fr::from(2)], vec![0]); 178 | assert_eq!(eval.evaluate(&vec![Fr::from(3)]), Some(Fr::from(42))); 179 | } 180 | 181 | #[test] 182 | fn test_elementwise_product() { 183 | let poly1 = Multilinear::new(vec![Fr::from(0), Fr::from(1), Fr::from(2), Fr::from(3)], 2); 184 | let poly2 = Multilinear::new(vec![Fr::from(0), Fr::from(0), Fr::from(0), Fr::from(1)], 2); 185 | 186 | let composed = ComposedMultilinear::new(vec![poly1, poly2]); 187 | 188 | let eval = composed.elementwise_product(); 189 | assert_eq!( 190 | eval, 191 | vec![Fr::from(0), Fr::from(0), Fr::from(0), Fr::from(3)] 192 | ); 193 | } 194 | 195 | #[test] 196 | fn test_elementwise_product_2() { 197 | let poly1 = Multilinear::new(vec![Fr::from(0), Fr::from(1), Fr::from(2), Fr::from(3)], 2); 198 | let poly2 = Multilinear::new(vec![Fr::from(1), Fr::from(4), Fr::from(0), Fr::from(5)], 2); 199 | 200 | let composed = ComposedMultilinear::new(vec![poly1, poly2]); 201 | 202 | let eval = composed.elementwise_product(); 203 | assert_eq!( 204 | eval, 205 | vec![Fr::from(0), Fr::from(4), Fr::from(0), Fr::from(15)] 206 | ); 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /groth16/src/primitives.rs: -------------------------------------------------------------------------------- 1 | use ark_ec::pairing::Pairing; 2 | use ark_ff::PrimeField; 3 | use polynomial::{ 4 | interface::UnivariantPolynomialInterface, univariant::UnivariantPolynomial, 5 | utils::compute_domain, 6 | }; 7 | use rand::rngs::OsRng; 8 | 9 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 10 | pub struct QAPPolysCoefficients { 11 | pub a: Vec>, 12 | pub b: Vec>, 13 | pub c: Vec>, 14 | } 15 | 16 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 17 | pub struct QAPPolys { 18 | pub a: Vec>, 19 | pub b: Vec>, 20 | pub c: Vec>, 21 | } 22 | 23 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 24 | pub struct QAP { 25 | /// This is the C matrix * witness in polynomial form 26 | pub cx: UnivariantPolynomial, 27 | /// This is the A matrix * witness in polynomial form 28 | pub ax: UnivariantPolynomial, 29 | /// This is the B matrix * witness in polynomial form 30 | pub bx: UnivariantPolynomial, 31 | /// this is the t polynomial 32 | pub t: UnivariantPolynomial, 33 | /// this is the h polynomial 34 | pub h: UnivariantPolynomial, 35 | } 36 | 37 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 38 | pub struct ToxicWaste { 39 | pub alpha: F, 40 | pub beta: F, 41 | pub gamma: F, 42 | pub delta: F, 43 | pub tau: F, 44 | } 45 | 46 | /// This is the trusted setup 47 | /// handles; 48 | /// Circuit specific trusted setup and noc-specific trusted setup 49 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 50 | pub struct TrustedSetup { 51 | phantom: std::marker::PhantomData

, 52 | } 53 | 54 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 55 | pub struct ProvingKey { 56 | pub alpha_g1: P::G1, 57 | pub beta_g1: P::G1, 58 | pub delta_g1: P::G2, 59 | pub powers_of_tau_g1: Vec, // from 0 to m - 1 60 | 61 | pub beta_g2: P::G2, 62 | pub delta_g2: P::G2, 63 | pub powers_of_tau_g2: Vec, // from 0 to m - 1 64 | } 65 | 66 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 67 | pub struct VerificationKey { 68 | pub alpha_g1: P::G1, 69 | 70 | pub beta_g2: P::G2, 71 | pub gamma_g2: P::G2, 72 | pub delta_g2: P::G2, 73 | } 74 | 75 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 76 | pub struct TrustedSetupExcecution { 77 | pub powers_of_tau_g1: Vec, // from 0 to 2*m - 2 78 | pub powers_of_tau_g2: Vec, // from 0 to m - 1 79 | pub beta_g2: P::G2, 80 | pub alpha_g1: P::G1, 81 | pub beta_g1: P::G1, 82 | pub c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_public: Vec, 83 | pub c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_private: Vec, 84 | pub powers_of_tau_t_poly_delta_inverse_g1: Vec, 85 | pub gamma_g2: P::G2, 86 | pub delta_g2: P::G2, 87 | pub delta_g1: P::G1, 88 | } 89 | 90 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 91 | pub struct Proof { 92 | pub a: P::G1, 93 | pub b: P::G2, 94 | pub c: P::G1, 95 | } 96 | 97 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] 98 | pub struct ProofRands { 99 | pub r: F, 100 | pub s: F, 101 | } 102 | 103 | impl ToxicWaste { 104 | pub fn random() -> Self { 105 | let rand_thread = &mut OsRng; 106 | 107 | let alpha = F::rand(rand_thread); 108 | let beta = F::rand(rand_thread); 109 | let gamma = F::rand(rand_thread); 110 | let delta = F::rand(rand_thread); 111 | let tau = F::rand(rand_thread); 112 | 113 | Self { 114 | alpha, 115 | beta, 116 | gamma, 117 | delta, 118 | tau, 119 | } 120 | } 121 | 122 | pub fn new(alpha: F, beta: F, gamma: F, delta: F, tau: F) -> Self { 123 | Self { 124 | alpha, 125 | beta, 126 | gamma, 127 | delta, 128 | tau, 129 | } 130 | } 131 | } 132 | 133 | impl ProofRands { 134 | pub fn random() -> Self { 135 | let rand_thread = &mut OsRng; 136 | 137 | let r = F::rand(rand_thread); 138 | let s = F::rand(rand_thread); 139 | 140 | Self { r, s } 141 | } 142 | 143 | pub fn new(r: F, s: F) -> Self { 144 | Self { r, s } 145 | } 146 | } 147 | 148 | impl QAP { 149 | pub fn new( 150 | cx: UnivariantPolynomial, 151 | ax: UnivariantPolynomial, 152 | bx: UnivariantPolynomial, 153 | t: UnivariantPolynomial, 154 | h: UnivariantPolynomial, 155 | ) -> Self { 156 | Self { cx, ax, bx, t, h } 157 | } 158 | 159 | pub fn compute_ht(&self) -> UnivariantPolynomial { 160 | self.h.clone() * self.t.clone() 161 | } 162 | 163 | pub fn qap_check(&self) -> bool { 164 | let ht = self.compute_ht(); 165 | let lhs = self.ax.clone() * self.bx.clone(); 166 | let check = lhs == ht + self.cx.clone(); 167 | check 168 | } 169 | } 170 | 171 | impl QAPPolysCoefficients { 172 | pub fn new(a: Vec>, b: Vec>, c: Vec>) -> Self { 173 | Self { a, b, c } 174 | } 175 | 176 | pub fn into_poly_rep(&self) -> QAPPolys { 177 | let domain_lenght = self.a[0].len(); 178 | let domain = compute_domain(domain_lenght, 1); 179 | 180 | let a = self 181 | .a 182 | .iter() 183 | .map(|y| UnivariantPolynomial::interpolate(y.clone(), domain.clone())) 184 | .collect(); 185 | let b = self 186 | .b 187 | .iter() 188 | .map(|y| UnivariantPolynomial::interpolate(y.clone(), domain.clone())) 189 | .collect(); 190 | let c = self 191 | .c 192 | .iter() 193 | .map(|y| UnivariantPolynomial::interpolate(y.clone(), domain.clone())) 194 | .collect(); 195 | 196 | QAPPolys { a, b, c } 197 | } 198 | } 199 | 200 | impl TrustedSetupExcecution

{ 201 | pub fn new( 202 | powers_of_tau_g1: Vec, 203 | powers_of_tau_g2: Vec, 204 | beta_g2: P::G2, 205 | alpha_g1: P::G1, 206 | beta_g1: P::G1, 207 | c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_public: Vec, 208 | c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_private: Vec, 209 | powers_of_tau_t_poly_delta_inverse_g1: Vec, 210 | gamma_g2: P::G2, 211 | delta_g2: P::G2, 212 | delta_g1: P::G1, 213 | ) -> Self { 214 | Self { 215 | powers_of_tau_g1, 216 | powers_of_tau_g2, 217 | beta_g2, 218 | alpha_g1, 219 | beta_g1, 220 | c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_public, 221 | c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_private, 222 | powers_of_tau_t_poly_delta_inverse_g1, 223 | gamma_g2, 224 | delta_g2, 225 | delta_g1, 226 | } 227 | } 228 | 229 | pub fn get_n_powers_of_tau_g1(&self, n: usize) -> Vec { 230 | self.powers_of_tau_g1[..n].to_vec() 231 | } 232 | } 233 | 234 | impl QAPPolys { 235 | pub fn new( 236 | a: Vec>, 237 | b: Vec>, 238 | c: Vec>, 239 | ) -> Self { 240 | Self { a, b, c } 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /groth16/README.md: -------------------------------------------------------------------------------- 1 | ## Usage Example 2 | ------------------ 3 | 4 | There are two major flow for running the Groth16 prover and verifier. 5 | 1. An already obtained R1CS, this could be from Circom or any other source. 6 | 2. Using the arithmetic `Circuit` struct to generate the R1CS and then the QAP. 7 | 8 | ### 1. Using an already obtained R1CS 9 | 10 | ```rust 11 | let r1cs = R1CS:: { 12 | a: vec![vec![ 13 | Fr::from(0u32), 14 | Fr::from(0u32), 15 | Fr::from(1u32), 16 | Fr::from(0u32), 17 | ]], 18 | b: vec![vec![ 19 | Fr::from(0u32), 20 | Fr::from(0u32), 21 | Fr::from(0u32), 22 | Fr::from(1u32), 23 | ]], 24 | c: vec![vec![ 25 | Fr::from(0u32), 26 | Fr::from(1u32), 27 | Fr::from(0u32), 28 | Fr::from(0u32), 29 | ]], 30 | }; 31 | 32 | let witness = Witness::new( 33 | vec![Fr::from(1u32)], 34 | vec![Fr::from(4223u32), Fr::from(41u32), Fr::from(103u32)], 35 | ); 36 | 37 | let r1cs_check = r1cs.check(witness.render()); 38 | assert!(r1cs_check, "this is the R1CS check"); 39 | 40 | let qap_poly_coefficients = r1cs.to_qap_poly_coefficients(); 41 | let qap_poly = qap_poly_coefficients.into_poly_rep(); 42 | 43 | let preprocessor = PreProcessor::new(r1cs, witness.clone()); 44 | let qap = preprocessor.preprocess(); 45 | 46 | let check = qap.qap_check(); 47 | assert_eq!(check, true); 48 | 49 | let toxic_waste = ToxicWaste::new( 50 | Fr::from(2u32), 51 | Fr::from(3u32), 52 | Fr::from(5u32), 53 | Fr::from(6u32), 54 | Fr::from(4u32), 55 | ); 56 | 57 | let trusted_setup = TrustedSetup::::run_trusted_setup( 58 | &toxic_waste, 59 | &qap_poly, 60 | qap.ax.degree(), 61 | ); 62 | 63 | let proof_rands = ProofRands::::new(Fr::from(3u32), Fr::from(5u32)); 64 | 65 | let groth16_proof = Groth16Protocol::::generate_proof( 66 | proof_rands, 67 | &trusted_setup, 68 | &qap, 69 | &witness, 70 | ); 71 | 72 | let is_valid = Groth16Protocol::::verify_proof( 73 | &groth16_proof, 74 | &trusted_setup, 75 | &witness.public_input, 76 | ); 77 | 78 | assert!(is_valid); 79 | ``` 80 | 81 | ### 2. Using the arithmetic `Circuit` struct to generate the R1CS and then the QAP. 82 | 83 | ```rust 84 | let layer_0 = CircuitLayer::new(vec![Gate::new(GateType::Mul, [0, 1])]); 85 | 86 | let circuit = Circuit::new(vec![layer_0]); 87 | let constraints = circuit.extract_constraints(); 88 | 89 | let r1cs = constraints.to_r1cs_vec::(); 90 | let witness = Witness::new( 91 | vec![Fr::from(1u32)], 92 | vec![Fr::from(4223u32), Fr::from(41u32), Fr::from(103u32)], 93 | ); 94 | let r1cs_check = r1cs.check(witness.render()); 95 | assert!(r1cs_check, "this is the R1CS check"); 96 | 97 | let qap_poly_coefficients = r1cs.to_qap_poly_coefficients(); 98 | let qap_poly = qap_poly_coefficients.into_poly_rep(); 99 | 100 | let preprocessor = PreProcessor::new(r1cs, witness.clone()); 101 | let qap = preprocessor.preprocess(); 102 | 103 | let check = qap.qap_check(); 104 | assert_eq!(check, true); 105 | 106 | let toxic_waste = ToxicWaste::new( 107 | Fr::from(2u32), 108 | Fr::from(3u32), 109 | Fr::from(5u32), 110 | Fr::from(6u32), 111 | Fr::from(4u32), 112 | ); 113 | 114 | let trusted_setup = TrustedSetup::::run_trusted_setup( 115 | &toxic_waste, 116 | &qap_poly, 117 | qap.ax.degree(), 118 | ); 119 | 120 | let proof_rands = ProofRands::::new(Fr::from(3u32), Fr::from(5u32)); 121 | 122 | let groth16_proof = Groth16Protocol::::generate_proof( 123 | proof_rands, 124 | &trusted_setup, 125 | &qap, 126 | &witness, 127 | ); 128 | 129 | let is_valid = Groth16Protocol::::verify_proof( 130 | &groth16_proof, 131 | &trusted_setup, 132 | &witness.public_input, 133 | ); 134 | 135 | assert!(is_valid); 136 | ``` 137 | 138 | 139 | 140 | 141 | 142 | ### The Groth16 Protocol (Theory of implementation) 143 | --------------------------- 144 | 145 | prerequisite for this study are; 146 | - Bilinear pairings and elliptic curves 147 | - Quadratic arithmetic programs (QAPs) 148 | 149 | Bilinear pairings and elliptic curves are fundamental to the Groth16 proving system and many other advanced cryptographic protocols. Elliptic curves provide a secure and efficient foundation, while bilinear pairings enable the construction of succinct, non-interactive proofs that are both powerful and practical for real-world applications. 150 | 151 | 152 | #### Elliptic Curves 153 | 154 | **Elliptic Curves Overview:** An elliptic curve is a set of points that satisfy a specific mathematical equation. Over a finite field $\mathbb{F}_q​$, an elliptic curve $E$ is typically defined by an equation of the form: $y^2 = x^3 + ax + b$ where $a$ and $b$ are coefficients in $\mathbb{F}_q$, and the curve is non-singular (i.e., it has no cusps or self-intersections), which requires the discriminant $4a^3 + 27b^2 \neq 0$. 155 | 156 | ### Bilinear Pairings in Groth16 157 | 158 | In the context of the Groth16 proving system, bilinear pairings are used to construct efficient proofs that are both small in size and quick to verify. The system relies on the properties of bilinear pairings to ensure that the proof verification can be performed using simple algebraic operations, making the process efficient even for complex statements. 159 | 160 | **Example Use in Groth16:** 161 | 162 | - **Setup Phase:** During the setup phase, a trusted party generates public parameters that include elements in $G_1$​, $G_2$​, and $G_T$. 163 | - **Proving Phase:** The prover uses these parameters to create a proof that certain computations were performed correctly. This involves operations in $G1$​ and $G2$. 164 | - **Verification Phase:** The verifier checks the proof by performing pairing operations $e$ and ensures that certain equations hold in $G_T$​. The bilinear nature of the pairing allows these checks to be performed efficiently. 165 | 166 | ### The Protocol 167 | The `Groth16` protocol in most cases, starts with a Circuit. A `Circuit` in ZKP is a structured way to represent a computation. It is analogous to a digital logic circuit used in computer engineering. 168 | 169 | **Structure:** 170 | 171 | - A circuit is composed of **inputs**, **gates**, and **outputs**. 172 | - **Inputs**: These are the values that the prover knows and wants to keep private (often called witnesses) along with the public inputs. 173 | - **Gates**: These perform basic operations (such as addition, multiplication, logical AND, OR) on the inputs. 174 | - **Outputs**: These are the results of the computations performed by the gates. 175 | 176 | **Types of Circuits:** 177 | 178 | - **Arithmetic Circuits**: These circuits use arithmetic gates (addition, multiplication) over a finite field. They are often used in zk-SNARKs because they can efficiently represent the types of computations involved in many cryptographic applications. 179 | - **Boolean Circuits**: These circuits use logical gates (AND, OR, NOT) and are more common in classical computer science but can be transformed into arithmetic circuits for use in zk-SNARKs. 180 | 181 | The next stage of the protocol is to convert this `Circuit` to a format called `R1CS` 182 | 183 | A rank-1 constraint system (R1CS) with n variables and m constraints and p public inputs has a witness vector $w∈F^n$. By convention, the first p elements of w are the public input and the first public input $w_0​$ is fixed to 1. The m constraints in R1CS are a product equation between three inner products: 184 | $$ 185 | (w⋅ai​)⋅(w⋅bi​)=w⋅ci​ 186 | $$ 187 | where vectors $(a_i​,b_i​,c_i​)∈F^3⋅^n$ specify the constraint. The constraint vectors are usually very sparse, typically only nonzero for a single or few values. These constraint vectors can be aggregated in $n×m$ matrices so that the whole constraint system can be concisely written using an element-wise product. 188 | 189 | $$ 190 | (w⋅A)∘(w⋅B)=w⋅C 191 | $$ 192 | 193 | After obtaining this R1CS representation, it needs to be transformed into its QAP representation to go further in this proof system. -------------------------------------------------------------------------------- /sha256-hash-function/README.md: -------------------------------------------------------------------------------- 1 | In the realm of cybersecurity, ensuring data integrity and authenticity is paramount. Cryptographic hash functions play a vital role in achieving this objective. One of the most widely employed and trusted algorithms in this domain is SHA-256 (Secure Hash Algorithm 256-bit). This introduction will delve into the concept of SHA-256, outlining its functionalities, key characteristics, and the prevalent applications that leverage its capabilities. 2 | 3 | 4 | 5 | In the realm of cybersecurity, ensuring data integrity and authenticity is paramount. Cryptographic hash functions play a vital role in achieving this objective. One of the most widely employed and trusted algorithms in this domain is SHA-256 (Secure Hash Algorithm 256-bit). This introduction will delve into the concept of SHA-256, outlining its functionalities, key characteristics, and the prevalent applications that leverage its capabilities. 6 | 7 | 8 | 9 | - Necessity for data integrity and authenticity: Briefly explain why data security is crucial and how it can be compromised. 10 | 11 | - Hash functions explained: Introduce the concept of hash functions, their role in cryptography, and how they differ from encryption. 12 | 13 | - SHA-256: A Secure Hashing Standard: Mention that SHA-256 belongs to the SHA-2 family, developed as a successor to the aging SHA-1 algorithm. 14 | 15 | 16 | ### Operations Used In SHA256 17 | It is important to note that SHA256 operations are done of 32 bits words:: *This is still questionable* 18 | 1. Exclusive OR (XOR): This operation returns `true` if the two inputs are different and `false` if otherwise. This is used in the SHA256 algorithm to give a balanced representation of the different `operands` used during this hash computation. In Rust, you can perform the XOR (exclusive OR) operation using the `^` operator. XOR is a bitwise operation that takes two-bit patterns of equal length and performs the logical exclusive OR operation on each pair of corresponding bits. The result is 1 if the bits are different and 0 if they are the same. 19 | ```rust 20 | //This is how to XOR in the RUST programming language 21 | fn main() { 22 | let a: u8 = 0b1100_1010; 23 | let b: u8 = 0b1010_1100; 24 | 25 | let result = a ^ b; 26 | 27 | println!("{:08b}", a); // Output: 11001010 28 | println!("{:08b}", b); // Output: 10101100 29 | println!("{:08b}", result); // Output: 01100110 30 | } 31 | ``` 32 | 2. Right Shift Operator (SHR_i): This shifts the bits of a 32-bit word by `n` number of bits to the right. Example; SHR_1(1011) == 1011 >> 1 == 0101. In Rust, the right shift operation can be performed using the `>>` operator. This operator shifts the bits of a number to the right by a specified number of positions. The bits that are shifted out of the rightmost position are discarded, and zeros are inserted from the left. 33 | ```rust 34 | fn main() { 35 | let value: u8 = 0b1100_1010; 36 | let shifted = value >> 3; 37 | 38 | println!("{:08b}", value); // Output: 11001010 39 | println!("{:08b}", shifted); // Output: 00011001 40 | } 41 | ``` 42 | 3. Rotation Right (ROTR_i): The rotation shift right operation, often abbreviated as "ROR" or "rotate right," is a bitwise operation that shifts the bits of a binary number to the right by a specified number of positions. Bits that are shifted out of the rightmost position are reintroduced at the leftmost position, creating a circular or rotating effect. 43 | ```sh 44 | # Consider an 8-bit binary number `11010010`. If we perform a right rotation by 3 positions, the result would be: 45 | 46 | Original: 11010010 47 | Step 1: 01101001 (shift right by 1) 48 | Step 2: 10110100 (shift right by 2) 49 | Step 3: 01011010 (shift right by 3) 50 | Result: 01011010 51 | ``` 52 | This is how it is done in RUST 53 | ```rust 54 | fn rotate_right(value: u8, shift: u32) -> u8 { 55 | // Ensure the shift amount is within the bounds of the bit width 56 | let shift = shift % 8; 57 | // Perform the rotation 58 | (value >> shift) | (value << (8 - shift)) 59 | } 60 | ``` 61 | 4. Addition Modulo 2^32: This is done by adding the operands and taking the modulus of 2 ^ 32. 62 | 63 | ### Functions used in SHA256 64 | There are 6 logical functions used by the SHA256 hash function They are as follows; 65 | 1. sigma_0: The sigma_0 function comprises of 4 operations, ROTR_7, ROTR_18, SHR_3 and XOR. The equation looking more like this: ROTR_7(x) ^ ROTR_18(x) ^ SHR_3(x); 66 | 2. sigma_1: The sigma_1 function very similar to the sigma_0 function but varies in the number of rotation. This equation is given in this manner; ROTR_17(x) ^ ROTR_19(x) ^ SHR_10(x) 67 | 3. prime_sigma_0: ROTR_2(x) ^ ROTR_13(x) ^ ROTR_22(x) 68 | 4. prime_sigma_1: ROTR_6(x) ^ ROTR_11(x) ^ ROTR_25(x) 69 | 5. choice Ch(𝑥,𝑦,𝑧)=(𝑥∧𝑦)⊕(¬𝑥∧𝑧) : Ch stands for choose (source: poncho) or choice, as the 𝑥 input chooses if the output is from 𝑦 or from 𝑧. More precisely, for each bit index, that result bit is according to the bit from 𝑦 (or respectively 𝑧) at this index, depending on if the bit from 𝑥 at this index is 1 (or respectively 0). 70 | 6. majority Maj(𝑥,𝑦,𝑧)=(𝑥∧𝑦)⊕(𝑥∧𝑧)⊕(𝑦∧𝑧): Maj stands for majority: for each bit index, that result bit is according to the majority of the 3 inputs bits for 𝑥 𝑦 and 𝑧 at this index. 71 | 7. compute_message_shedule_extension: 72 | 73 | _where ∧ is bitwise AND, ⊕ is bitwise exclusive-OR, and ¬ is bitwise negation. The functions are defined for bit vectors (of 32 bits in case fo SHA-256)._ 74 | 75 | ### Constant used in SHA256 76 | the 64 binary words K_i given by the 32 first bits of the fractional parts of the cube roots of the first 64 prime numbers; 77 | 78 | 0x428a2f98, 79 | 0x71374491, 80 | 0xb5c0fbcf, 81 | 0xe9b5dba5, 82 | 0x3956c25b, 83 | 0x59f111f1, 84 | 0x923f82a4, 85 | 0xab1c5ed5, 86 | 0xd807aa98, 87 | 0x12835b01, 88 | 0x243185be, 89 | 0x550c7dc3, 90 | 0x72be5d74, 91 | 0x80deb1fe, 92 | 0x9bdc06a7, 93 | 0xc19bf174, 94 | 0xe49b69c1, 95 | 0xefbe4786, 96 | 0x0fc19dc6, 97 | 0x240ca1cc, 98 | 0x2de92c6f, 99 | 0x4a7484aa, 100 | 0x5cb0a9dc, 101 | 0x76f988da, 102 | 0x983e5152, 103 | 0xa831c66d, 104 | 0xb00327c8, 105 | 0xbf597fc7, 106 | 0xc6e00bf3, 107 | 0xd5a79147, 108 | 0x06ca6351, 109 | 0x14292967, 110 | 0x27b70a85, 111 | 0x2e1b2138, 112 | 0x4d2c6dfc, 113 | 0x53380d13, 114 | 0x650a7354, 115 | 0x766a0abb, 116 | 0x81c2c92e, 117 | 0x92722c85, 118 | 0xa2bfe8a1, 119 | 0xa81a664b, 120 | 0xc24b8b70, 121 | 0xc76c51a3, 122 | 0xd192e819, 123 | 0xd6990624, 124 | 0xf40e3585, 125 | 0x106aa070, 126 | 0x19a4c116, 127 | 0x1e376c08, 128 | 0x2748774c, 129 | 0x34b0bcb5, 130 | 0x391c0cb3, 131 | 0x4ed8aa4a, 132 | 0x5b9cca4f, 133 | 0x682e6ff3, 134 | 0x748f82ee, 135 | 0x78a5636f, 136 | 0x84c87814, 137 | 0x8cc70208, 138 | 0x90befffa, 139 | 0xa4506ceb, 140 | 0xbef9a3f7, 141 | 0xc67178f2 142 | 143 | 144 | ### Preprocessing 145 | This entails all the stages of processes needed to be done before the hash computation commences. This are 4 stages within this stage. 146 | 147 | 1. Convert this message to binary 148 | 2. Padding: This involves padding the message until it reaches the nearest multiple of `512` 149 | first, a bit 1 is appended, 150 | • next, k bits 0 are appended, with k being the smallest positive integer such that l + 1 + k ≡ 448 151 | mod 512, where l is the length in bits of the initial message, 152 | • finally, the length l < 2 153 | 64 of the initial message is represented with exactly 64 bits, and these bits 154 | are added at the end of the message. 155 | The message shall always be padded, even if the initial length is already a multiple of 512. 156 | 157 | ```rust 158 | pub struct PreProcessor { 159 | blob: Vec 160 | } 161 | 162 | pub struct Block { 163 | w: Vec // [u32; 64] 164 | } 165 | 166 | trait PreProcessorInterface { 167 | // This is the vector of 512bits 168 | fn compute_blocks(&self) -> Vec 169 | } 170 | 171 | trait BlockInterface { 172 | // This is what is called the message schedule 173 | fn compute_message_shedule() -> [u32; 64]; 174 | } 175 | ``` 176 | 3. Expand the Message schedule. 177 | 4. Set initial hash values. 178 | ```rust 179 | pub const H: [u32; 8] = [ 180 | 0x6a09e667, 181 | 0xbb67ae85, 182 | 0x3c6ef372, 183 | 0xa54ff53a, 184 | 0x510e527f, 185 | 0x9b05688c, 186 | 0x1f83d9ab, 187 | 0x5be0cd19 188 | ]; 189 | ``` 190 | 191 | 192 | ### Hash Computation 193 | 194 | -------------------------------------------------------------------------------- /polynomial/src/utils.rs: -------------------------------------------------------------------------------- 1 | use crate::{interface::UnivariantPolynomialInterface, univariant::UnivariantPolynomial}; 2 | use ark_ff::PrimeField; 3 | 4 | pub fn get_langrange_basis( 5 | domain: &Vec, 6 | y_s: &Vec, 7 | ) -> Vec> { 8 | let mut basis = Vec::new(); 9 | 10 | if domain.len() != y_s.len() { 11 | panic!( 12 | "The length of domain and y_s should be the same: {}, {}", 13 | domain.len(), 14 | y_s.len() 15 | ); 16 | } 17 | 18 | for i in 0..domain.len() { 19 | let mut basis_element = UnivariantPolynomial::new(vec![F::one()]); 20 | 21 | for j in 0..domain.len() { 22 | if i == j { 23 | continue; 24 | } 25 | 26 | // basis_element *= "x - domain[j]" / (domain[i] - domain[j]); 27 | let numerator = UnivariantPolynomial::from_coefficients_vec(vec![-domain[j], F::one()]); 28 | let denominator = domain[i] - domain[j]; 29 | basis_element = basis_element 30 | * (numerator 31 | * UnivariantPolynomial::from_coefficients_vec(vec![denominator 32 | .inverse() 33 | .unwrap()])); 34 | } 35 | 36 | basis.push(basis_element * UnivariantPolynomial::from_coefficients_vec(vec![y_s[i]])); 37 | } 38 | 39 | basis 40 | } 41 | 42 | /// This function is a helper function used to evaluate a multilinear polynomial at a given point 43 | /// This is how the equation looks like: 44 | /// y = x * y_2 + (1 - x) * y_1 where x is a field element 45 | pub fn multilinear_evalutation_equation(x: F, y_1: F, y_2: F) -> F { 46 | x * y_2 + (F::one() - x) * y_1 47 | } 48 | 49 | /// returns a vector of (y_1, y_2) 50 | pub fn round_pairing_index(len: usize, delta: usize) -> Vec<(usize, usize)> { 51 | let mut result = Vec::new(); 52 | for y_1 in 0..len / 2 { 53 | result.push((y_1 + delta, (len / 2) + y_1 + delta)); 54 | } 55 | 56 | result 57 | } 58 | 59 | /// returns a vector of (y_1, y_2), this is used in a exrension manner 60 | pub fn round_pairing_index_ext(len: usize, log_iterations: usize) -> Vec<(usize, usize)> { 61 | let mut result = Vec::new(); 62 | let iterations = 1 << log_iterations; 63 | 64 | for _ in 0..iterations { 65 | let round = round_pairing_index(len / iterations, result.len() * 2); 66 | result.extend(round); 67 | } 68 | 69 | result 70 | } 71 | 72 | /// This function is used to compute the boolean hypercube of length n 73 | /// 74 | /// param n: The length of the boolean hypercube 75 | /// return: A vector of vectors that represents the boolean hypercube 76 | pub fn boolean_hypercube(n: usize) -> Vec> { 77 | let mut result = Vec::new(); 78 | for i in 0..1u128 << n { 79 | let mut current = Vec::new(); 80 | for j in 0..n { 81 | if (i >> j) & 1 == 1 { 82 | current.push(F::one()); 83 | } else { 84 | current.push(F::zero()); 85 | } 86 | } 87 | current.reverse(); 88 | result.push(current); 89 | } 90 | 91 | result 92 | } 93 | 94 | /// This is a function for doubling the evauation points, 95 | /// this is used for MLE addtion when the evauation length is not same 96 | pub fn double_elements(arr: &[T], times: usize) -> Vec 97 | where 98 | T: Clone, 99 | { 100 | let mut doubled_list = Vec::with_capacity(arr.len() * times); 101 | 102 | for element in arr.iter() { 103 | for _ in 0..1 << times { 104 | doubled_list.push(element.clone()); 105 | } 106 | } 107 | 108 | doubled_list 109 | } 110 | 111 | pub fn return_binary(mut num: u128) -> Vec { 112 | let mut binary: Vec = Vec::new(); 113 | while num > 0 { 114 | binary.push((num % 2) as u8); 115 | num /= 2; 116 | } 117 | binary.reverse(); 118 | binary 119 | } 120 | 121 | pub fn compute_domain(n: usize, pin: usize) -> Vec { 122 | let mut domain = Vec::new(); 123 | for i in pin..n + pin { 124 | domain.push(F::from(i as u128)); 125 | } 126 | 127 | domain 128 | } 129 | 130 | pub fn compute_number_of_variables(n: u128) -> (u128, u128) { 131 | if n == 0 { 132 | return (0, 0); 133 | } 134 | if n == 1 { 135 | return (1, 2); 136 | } 137 | 138 | let mut log_base_2 = n.ilog2(); 139 | let mut n_power_2 = 1 << log_base_2; 140 | 141 | if n != n_power_2 { 142 | log_base_2 += 1; 143 | n_power_2 = 1 << log_base_2; 144 | } 145 | 146 | (log_base_2 as u128, n_power_2) 147 | } 148 | 149 | #[cfg(test)] 150 | mod tests { 151 | use std::time::Instant; 152 | 153 | use super::*; 154 | use ark_test_curves::bls12_381::Fr; 155 | 156 | #[test] 157 | fn test_multilinear_evalutation_equation() { 158 | let x = Fr::from(5); 159 | let y_1 = Fr::from(3); 160 | let y_2 = Fr::from(2); 161 | 162 | assert_eq!(multilinear_evalutation_equation(x, y_1, y_2), Fr::from(-2)); 163 | } 164 | 165 | #[test] 166 | fn test_round_pairing_index() { 167 | let len = 4; 168 | let result = round_pairing_index(len, 0); 169 | assert_eq!(result, vec![(0, 2), (1, 3)]); 170 | } 171 | 172 | #[test] 173 | fn test_round_pairing_index_ext_0() { 174 | let len = 8; 175 | let result = round_pairing_index_ext(len, 0); 176 | assert_eq!(result, vec![(0, 4), (1, 5), (2, 6), (3, 7)]); 177 | } 178 | 179 | #[test] 180 | fn test_round_pairing_index_ext_1() { 181 | let len = 8; 182 | let result = round_pairing_index_ext(len, 1); 183 | assert_eq!(result, vec![(0, 2), (1, 3), (4, 6), (5, 7)]); 184 | } 185 | 186 | #[test] 187 | fn test_round_pairing_index_ext_2() { 188 | let len = 8; 189 | let result = round_pairing_index_ext(len, 2); 190 | assert_eq!(result, vec![(0, 1), (2, 3), (4, 5), (6, 7)]); 191 | } 192 | 193 | #[test] 194 | fn test_round_pairing_index_ext_16_0() { 195 | let len = 16; 196 | let result = round_pairing_index_ext(len, 0); 197 | assert_eq!( 198 | result, 199 | vec![ 200 | (0, 8), 201 | (1, 9), 202 | (2, 10), 203 | (3, 11), 204 | (4, 12), 205 | (5, 13), 206 | (6, 14), 207 | (7, 15) 208 | ] 209 | ); 210 | } 211 | 212 | #[test] 213 | fn test_round_pairing_index_ext_16_1() { 214 | let len = 16; 215 | let result = round_pairing_index_ext(len, 1); 216 | assert_eq!( 217 | result, 218 | vec![ 219 | (0, 4), 220 | (1, 5), 221 | (2, 6), 222 | (3, 7), 223 | (8, 12), 224 | (9, 13), 225 | (10, 14), 226 | (11, 15) 227 | ] 228 | ); 229 | } 230 | 231 | #[test] 232 | fn test_round_pairing_index_ext_16_2() { 233 | let len = 16; 234 | let result = round_pairing_index_ext(len, 2); 235 | assert_eq!( 236 | result, 237 | vec![ 238 | (0, 2), 239 | (1, 3), 240 | (4, 6), 241 | (5, 7), 242 | (8, 10), 243 | (9, 11), 244 | (12, 14), 245 | (13, 15) 246 | ] 247 | ); 248 | } 249 | 250 | #[test] 251 | fn test_round_pairing_index_ext_16_3() { 252 | let len = 16; 253 | let result = round_pairing_index_ext(len, 3); 254 | assert_eq!( 255 | result, 256 | vec![ 257 | (0, 1), 258 | (2, 3), 259 | (4, 5), 260 | (6, 7), 261 | (8, 9), 262 | (10, 11), 263 | (12, 13), 264 | (14, 15) 265 | ] 266 | ); 267 | } 268 | 269 | #[test] 270 | fn test_boolean_hypercube() { 271 | let now = Instant::now(); 272 | let result = boolean_hypercube::(3); 273 | println!("Time taken Hypercube 1: {:?}", now.elapsed()); 274 | println!("Result: {:?}", result); 275 | } 276 | 277 | #[test] 278 | fn test_compute_domain() { 279 | let domain = compute_domain::(4, 1); 280 | assert_eq!( 281 | domain, 282 | vec![Fr::from(1), Fr::from(2), Fr::from(3), Fr::from(4)] 283 | ); 284 | } 285 | } 286 | -------------------------------------------------------------------------------- /sum_check/src/composed/prover.rs: -------------------------------------------------------------------------------- 1 | use super::{ComposedSumCheckProof, RoundPoly}; 2 | use crate::interface::ComposedProverInterface; 3 | use ark_ff::{BigInteger, PrimeField}; 4 | use fiat_shamir::{interface::TranscriptInterface, FiatShamirTranscript}; 5 | use polynomial::{ 6 | composed::{interfaces::ComposedMultilinearInterface, multilinear::ComposedMultilinear}, 7 | interface::MultilinearPolynomialInterface, 8 | univariant::UnivariantPolynomial, 9 | }; 10 | 11 | #[derive(Clone, Default, Debug)] 12 | pub struct ComposedProver; 13 | 14 | impl ComposedProverInterface for ComposedProver { 15 | /// This function returns the sum of the multilinear polynomial evaluation over the boolean hypercube. 16 | fn calculate_sum(poly: &ComposedMultilinear) -> F { 17 | poly.elementwise_product().iter().sum() 18 | } 19 | 20 | /// This function returns the round zero computed polynomial 21 | fn compute_round_zero_poly( 22 | poly: &ComposedMultilinear, 23 | transcript: &mut FiatShamirTranscript, 24 | ) -> UnivariantPolynomial { 25 | let composed_poly_max_degree = poly.max_degree(); 26 | let mut round_0_poly_vec = Vec::new(); 27 | 28 | for i in 0..=composed_poly_max_degree { 29 | let instance = poly 30 | .partial_evaluation(F::from(i as u128), 0) 31 | .elementwise_product() 32 | .iter() 33 | .sum(); 34 | round_0_poly_vec.push(instance); 35 | } 36 | 37 | let round_0_poly = RoundPoly::new(round_0_poly_vec).interpolate(); 38 | 39 | transcript.append(round_0_poly.to_bytes()); 40 | 41 | round_0_poly 42 | } 43 | 44 | fn sum_check_proof( 45 | poly_: &ComposedMultilinear, 46 | transcript: &mut FiatShamirTranscript, 47 | sum: &F, 48 | ) -> (ComposedSumCheckProof, Vec) { 49 | let mut poly = poly_.clone(); 50 | let mut all_random_reponse = Vec::new(); 51 | let mut round_polys = Vec::new(); 52 | 53 | transcript.append(poly.to_bytes()); 54 | transcript.append(sum.into_bigint().to_bytes_be()); 55 | 56 | for _ in 0..poly.num_vars() { 57 | let mut round_poly_vec = Vec::new(); 58 | 59 | for i in 0..=poly.max_degree() { 60 | let instance = poly 61 | .partial_evaluation(F::from(i as u128), 0) 62 | .elementwise_product() 63 | .iter() 64 | .sum(); 65 | 66 | round_poly_vec.push(instance); 67 | } 68 | 69 | let round_poly = RoundPoly::new(round_poly_vec).interpolate(); 70 | transcript.append(round_poly.to_bytes()); 71 | 72 | let random_response = F::from_be_bytes_mod_order(&transcript.sample()); 73 | poly = poly.partial_evaluation(random_response, 0); 74 | 75 | all_random_reponse.push(random_response); 76 | round_polys.push(round_poly); 77 | } 78 | 79 | ( 80 | ComposedSumCheckProof { 81 | round_poly: round_polys, 82 | sum: *sum, 83 | }, 84 | all_random_reponse, 85 | ) 86 | } 87 | } 88 | 89 | #[cfg(test)] 90 | mod tests { 91 | use super::*; 92 | use crate::composed::verifier::ComposedVerifier; 93 | use crate::interface::ComposedVerifierInterface; 94 | use ark_test_curves::bls12_381::Fr; 95 | use polynomial::interface::PolynomialInterface; 96 | use polynomial::multilinear::Multilinear; 97 | 98 | #[test] 99 | fn test_calculate_sum() { 100 | let poly1 = Multilinear::new(vec![Fr::from(0), Fr::from(1), Fr::from(2), Fr::from(3)], 2); 101 | let poly2 = Multilinear::new(vec![Fr::from(0), Fr::from(0), Fr::from(0), Fr::from(1)], 2); 102 | 103 | let composed = ComposedMultilinear::new(vec![poly1, poly2]); 104 | 105 | let sum = ComposedProver::calculate_sum(&composed); 106 | assert_eq!(sum, Fr::from(3)); 107 | } 108 | 109 | #[test] 110 | fn test_calculate_sum_2() { 111 | let poly1 = Multilinear::new(vec![Fr::from(0), Fr::from(1), Fr::from(2), Fr::from(3)], 2); 112 | 113 | let composed = ComposedMultilinear::new(vec![poly1]); 114 | 115 | let sum = ComposedProver::calculate_sum(&composed); 116 | assert_eq!(sum, Fr::from(6)); 117 | } 118 | 119 | #[test] 120 | fn test_calculate_sum_3() { 121 | let poly = Multilinear::new( 122 | vec![ 123 | Fr::from(0), 124 | Fr::from(0), 125 | Fr::from(0), 126 | Fr::from(2), 127 | Fr::from(2), 128 | Fr::from(2), 129 | Fr::from(2), 130 | Fr::from(4), 131 | ], 132 | 3, 133 | ); 134 | 135 | let composed = ComposedMultilinear::new(vec![poly]); 136 | 137 | let sum = ComposedProver::calculate_sum(&composed); 138 | assert_eq!(sum, Fr::from(12)); 139 | } 140 | 141 | #[test] 142 | fn test_compute_round_zero_poly() { 143 | let poly1 = Multilinear::new(vec![Fr::from(0), Fr::from(1), Fr::from(2), Fr::from(3)], 2); 144 | 145 | let composed = ComposedMultilinear::new(vec![poly1]); 146 | 147 | let sum = ComposedProver::calculate_sum(&composed); 148 | 149 | let mut transcript = FiatShamirTranscript::default(); 150 | let round_0_poly = ComposedProver::compute_round_zero_poly(&composed, &mut transcript); 151 | 152 | let sum_half_0 = round_0_poly.evaluate(&Fr::from(0)); 153 | let sum_half_1 = round_0_poly.evaluate(&Fr::from(1)); 154 | 155 | assert_eq!(sum, sum_half_0 + sum_half_1); 156 | } 157 | 158 | #[test] 159 | fn test_compute_round_zero_poly_2() { 160 | let poly = Multilinear::new( 161 | vec![ 162 | Fr::from(0), 163 | Fr::from(0), 164 | Fr::from(0), 165 | Fr::from(2), 166 | Fr::from(2), 167 | Fr::from(2), 168 | Fr::from(2), 169 | Fr::from(4), 170 | ], 171 | 3, 172 | ); 173 | 174 | let composed = ComposedMultilinear::new(vec![poly]); 175 | 176 | let sum = ComposedProver::calculate_sum(&composed); 177 | 178 | let mut transcript = FiatShamirTranscript::default(); 179 | let round_0_poly = ComposedProver::compute_round_zero_poly(&composed, &mut transcript); 180 | 181 | let sum_half_0 = round_0_poly.evaluate(&Fr::from(0)); 182 | let sum_half_1 = round_0_poly.evaluate(&Fr::from(1)); 183 | 184 | assert_eq!(sum, sum_half_0 + sum_half_1); 185 | } 186 | 187 | #[test] 188 | fn test_compute_round_zero_poly_3() { 189 | let poly = Multilinear::new( 190 | vec![ 191 | Fr::from(0), 192 | Fr::from(0), 193 | Fr::from(0), 194 | Fr::from(2), 195 | Fr::from(2), 196 | Fr::from(2), 197 | Fr::from(2), 198 | Fr::from(4), 199 | ], 200 | 3, 201 | ); 202 | 203 | let composed = ComposedMultilinear::new(vec![poly]); 204 | 205 | let sum = ComposedProver::calculate_sum(&composed); 206 | 207 | let mut transcript = FiatShamirTranscript::default(); 208 | let round_0_poly = ComposedProver::compute_round_zero_poly(&composed, &mut transcript); 209 | 210 | let sum_half_0 = round_0_poly.evaluate(&Fr::from(0)); 211 | let sum_half_1 = round_0_poly.evaluate(&Fr::from(1)); 212 | 213 | println!("round_0_poly_vec: {:?}", round_0_poly); 214 | 215 | assert_eq!(sum, sum_half_0 + sum_half_1); 216 | } 217 | 218 | #[test] 219 | fn test_sum_check_proof() { 220 | let poly = Multilinear::new( 221 | vec![ 222 | Fr::from(0), 223 | Fr::from(0), 224 | Fr::from(2), 225 | Fr::from(7), 226 | Fr::from(3), 227 | Fr::from(3), 228 | Fr::from(6), 229 | Fr::from(11), 230 | ], 231 | 3, 232 | ); 233 | let composed = ComposedMultilinear::new(vec![poly]); 234 | let sum = ComposedProver::calculate_sum(&composed); 235 | 236 | let mut transcript = FiatShamirTranscript::default(); 237 | let (proof, _) = ComposedProver::sum_check_proof(&composed, &mut transcript, &sum); 238 | 239 | assert!(ComposedVerifier::verify(&proof, &composed)); 240 | } 241 | 242 | #[test] 243 | fn test_sum_check_proof_2() { 244 | let poly1 = Multilinear::new(vec![Fr::from(0), Fr::from(1), Fr::from(2), Fr::from(3)], 2); 245 | let poly2 = Multilinear::new(vec![Fr::from(0), Fr::from(0), Fr::from(0), Fr::from(1)], 2); 246 | 247 | let composed = ComposedMultilinear::new(vec![poly1, poly2]); 248 | let sum = ComposedProver::calculate_sum(&composed); 249 | 250 | let mut transcript = FiatShamirTranscript::default(); 251 | let (proof, _) = ComposedProver::sum_check_proof(&composed, &mut transcript, &sum); 252 | 253 | assert!(ComposedVerifier::verify(&proof, &composed)); 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /sum_check/src/prover.rs: -------------------------------------------------------------------------------- 1 | use crate::{data_structure::SumCheckProof, interface::ProverInterface}; 2 | use ark_ff::PrimeField; 3 | use fiat_shamir::{interface::TranscriptInterface, FiatShamirTranscript}; 4 | use polynomial::{ 5 | interface::MultilinearPolynomialInterface, multilinear::Multilinear, utils::boolean_hypercube, 6 | }; 7 | 8 | #[derive(Clone, Default, Debug)] 9 | pub struct Prover; 10 | 11 | impl ProverInterface for Prover { 12 | /// This function returns the sum of the multilinear polynomial evaluation over the boolean hypercube. 13 | fn calculate_sum(poly: &Multilinear) -> F { 14 | poly.evaluations.iter().sum() 15 | } 16 | 17 | /// This function returns the round zero computed polynomial 18 | fn compute_round_zero_poly>( 19 | poly: &P, 20 | transcript: &mut FiatShamirTranscript, 21 | ) -> P { 22 | let number_of_round = poly.num_vars() - 1; 23 | let bh = boolean_hypercube(number_of_round); 24 | let mut bh_partials = P::zero(1); // this is an accumulator 25 | 26 | for bh_i in bh { 27 | let current_partial = poly.partial_evaluations(bh_i, vec![1; number_of_round]); 28 | bh_partials.internal_add_assign(¤t_partial); 29 | } 30 | 31 | transcript.append(bh_partials.to_bytes()); 32 | bh_partials 33 | } 34 | 35 | /// This function computes sum check proof 36 | fn sum_check_proof + Clone>( 37 | poly: &P, 38 | transcript: &mut FiatShamirTranscript, 39 | sum: &F, 40 | ) -> SumCheckProof { 41 | let round_0_poly = Self::compute_round_zero_poly(poly, transcript); 42 | let mut all_random_reponse = Vec::new(); 43 | let mut round_poly = Vec::new(); 44 | 45 | for i in 1..poly.num_vars() { 46 | let number_of_round = poly.num_vars() - i - 1; 47 | let bh = boolean_hypercube::(number_of_round); 48 | 49 | let mut bh_partials = P::zero(1); 50 | let verifier_random_reponse_f = F::from_be_bytes_mod_order(&transcript.sample()); 51 | all_random_reponse.push(verifier_random_reponse_f); 52 | 53 | for bh_i in bh { 54 | let bh_len = bh_i.len(); 55 | let mut eval_vector = all_random_reponse.clone(); 56 | eval_vector.extend(bh_i); 57 | let mut eval_index = vec![0; all_random_reponse.len()]; 58 | let suffix_eval_index = vec![1; bh_len]; 59 | eval_index.extend(suffix_eval_index); 60 | 61 | let current_partial = poly.partial_evaluations(eval_vector, eval_index); 62 | 63 | bh_partials.internal_add_assign(¤t_partial); 64 | } 65 | 66 | transcript.append(bh_partials.to_bytes()); 67 | round_poly.push(bh_partials); 68 | } 69 | 70 | SumCheckProof { 71 | polynomial: poly.clone(), 72 | round_poly: round_poly.clone(), 73 | round_0_poly: round_0_poly.clone(), 74 | sum: sum.clone(), 75 | } 76 | } 77 | } 78 | 79 | #[cfg(test)] 80 | mod tests { 81 | use crate::{interface::VerifierInterface, verifier::Verifier}; 82 | 83 | use super::*; 84 | use ark_test_curves::bls12_381::Fr; 85 | 86 | #[test] 87 | fn test_sum_calculation() { 88 | let poly = Multilinear::new( 89 | vec![ 90 | Fr::from(0), 91 | Fr::from(0), 92 | Fr::from(0), 93 | Fr::from(2), 94 | Fr::from(2), 95 | Fr::from(2), 96 | Fr::from(2), 97 | Fr::from(4), 98 | ], 99 | 3, 100 | ); 101 | 102 | let sum = Prover::calculate_sum(&poly); 103 | assert_eq!(sum, Fr::from(12)); 104 | } 105 | 106 | #[test] 107 | fn test_compute_round_zero_poly() { 108 | let poly = Multilinear::new( 109 | vec![ 110 | Fr::from(0), 111 | Fr::from(0), 112 | Fr::from(0), 113 | Fr::from(2), 114 | Fr::from(2), 115 | Fr::from(2), 116 | Fr::from(2), 117 | Fr::from(4), 118 | ], 119 | 3, 120 | ); 121 | let mut transcript = FiatShamirTranscript::default(); 122 | let round_0_poly = Prover::compute_round_zero_poly(&poly, &mut transcript); 123 | assert_eq!(round_0_poly.evaluations, vec![Fr::from(2), Fr::from(10)]); 124 | } 125 | 126 | #[test] 127 | fn test_compute_round_zero_poly_2() { 128 | let poly = Multilinear::new( 129 | vec![ 130 | Fr::from(0), 131 | Fr::from(0), 132 | Fr::from(0), 133 | Fr::from(2), 134 | Fr::from(2), 135 | Fr::from(2), 136 | Fr::from(2), 137 | Fr::from(4), 138 | ], 139 | 3, 140 | ); 141 | let mut transcript = FiatShamirTranscript::default(); 142 | let round_0_poly = Prover::compute_round_zero_poly(&poly, &mut transcript); 143 | let sum = round_0_poly.evaluate(&vec![Fr::from(1)]).unwrap() 144 | + round_0_poly.evaluate(&vec![Fr::from(0)]).unwrap(); 145 | 146 | assert_eq!(sum, Fr::from(12)); 147 | } 148 | 149 | #[test] 150 | fn test_compute_round_zero_poly_3() { 151 | let poly = Multilinear::new( 152 | vec![ 153 | Fr::from(0), 154 | Fr::from(0), 155 | Fr::from(2), 156 | Fr::from(7), 157 | Fr::from(3), 158 | Fr::from(3), 159 | Fr::from(5), 160 | Fr::from(11), 161 | ], 162 | 3, 163 | ); 164 | 165 | let mut transcript = FiatShamirTranscript::default(); 166 | let round_0_poly = Prover::compute_round_zero_poly(&poly, &mut transcript); 167 | 168 | assert_eq!(round_0_poly.evaluations, vec![Fr::from(9), Fr::from(22)]); 169 | } 170 | 171 | #[test] 172 | fn test_compute_round_zero_poly_4() { 173 | let poly = Multilinear::new( 174 | vec![ 175 | Fr::from(0), 176 | Fr::from(0), 177 | Fr::from(2), 178 | Fr::from(7), 179 | Fr::from(3), 180 | Fr::from(3), 181 | Fr::from(5), 182 | Fr::from(11), 183 | ], 184 | 3, 185 | ); 186 | 187 | let mut transcript = FiatShamirTranscript::default(); 188 | let round_0_poly = Prover::compute_round_zero_poly(&poly, &mut transcript); 189 | let sum = round_0_poly.evaluate(&vec![Fr::from(1)]).unwrap() 190 | + round_0_poly.evaluate(&vec![Fr::from(0)]).unwrap(); 191 | 192 | assert_eq!(sum, Fr::from(31)); 193 | } 194 | 195 | #[test] 196 | fn test_compute_round_zero_poly_5() { 197 | let poly = Multilinear::new( 198 | vec![ 199 | Fr::from(0), 200 | Fr::from(0), 201 | Fr::from(0), 202 | Fr::from(0), 203 | Fr::from(0), 204 | Fr::from(1), 205 | Fr::from(1), 206 | Fr::from(1), 207 | Fr::from(0), 208 | Fr::from(0), 209 | Fr::from(0), 210 | Fr::from(0), 211 | Fr::from(0), 212 | Fr::from(0), 213 | Fr::from(0), 214 | Fr::from(0), 215 | ], 216 | 4, 217 | ); 218 | 219 | let mut transcript = FiatShamirTranscript::default(); 220 | let round_0_poly = Prover::compute_round_zero_poly(&poly, &mut transcript); 221 | 222 | let sum = round_0_poly.evaluate(&vec![Fr::from(1)]).unwrap() 223 | + round_0_poly.evaluate(&vec![Fr::from(0)]).unwrap(); 224 | assert_eq!(sum, Fr::from(3)); 225 | } 226 | 227 | #[test] 228 | fn test_sum_check_proof() { 229 | let poly = Multilinear::new( 230 | vec![ 231 | Fr::from(0), 232 | Fr::from(0), 233 | Fr::from(2), 234 | Fr::from(7), 235 | Fr::from(3), 236 | Fr::from(3), 237 | Fr::from(6), 238 | Fr::from(11), 239 | ], 240 | 3, 241 | ); 242 | let mut transcript = FiatShamirTranscript::default(); 243 | let sum = Prover::calculate_sum(&poly); 244 | let proof = Prover::sum_check_proof(&poly, &mut transcript, &sum); 245 | 246 | assert!(Verifier::verify(&proof)); 247 | } 248 | 249 | #[test] 250 | fn test_sum_check_proof_2() { 251 | let poly = Multilinear::new( 252 | vec![ 253 | Fr::from(0), 254 | Fr::from(0), 255 | Fr::from(0), 256 | Fr::from(0), 257 | Fr::from(0), 258 | Fr::from(1), 259 | Fr::from(1), 260 | Fr::from(1), 261 | Fr::from(0), 262 | Fr::from(0), 263 | Fr::from(0), 264 | Fr::from(0), 265 | Fr::from(0), 266 | Fr::from(0), 267 | Fr::from(0), 268 | Fr::from(0), 269 | ], 270 | 4, 271 | ); 272 | let mut transcript = FiatShamirTranscript::default(); 273 | let sum = Prover::calculate_sum(&poly); 274 | let proof = Prover::sum_check_proof(&poly, &mut transcript, &sum); 275 | 276 | assert!(Verifier::verify(&proof)); 277 | } 278 | 279 | #[test] 280 | fn test_sum_check_proof_3() { 281 | let poly = Multilinear::new( 282 | vec![ 283 | Fr::from(1), 284 | Fr::from(3), 285 | Fr::from(5), 286 | Fr::from(7), 287 | Fr::from(2), 288 | Fr::from(4), 289 | Fr::from(6), 290 | Fr::from(8), 291 | Fr::from(3), 292 | Fr::from(5), 293 | Fr::from(7), 294 | Fr::from(9), 295 | Fr::from(4), 296 | Fr::from(6), 297 | Fr::from(8), 298 | Fr::from(10), 299 | ], 300 | 4, 301 | ); 302 | let mut transcript = FiatShamirTranscript::default(); 303 | let sum = Prover::calculate_sum(&poly); 304 | let proof = Prover::sum_check_proof(&poly, &mut transcript, &sum); 305 | 306 | assert!(Verifier::verify(&proof)); 307 | } 308 | } 309 | -------------------------------------------------------------------------------- /groth16/src/tests/protocol.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | interfaces::{ 3 | PreProcessorInterface, ProtocolInterface, R1CSProcessingInterface, TrustedSetupInterface, 4 | }, 5 | preprocessing::PreProcessor, 6 | primitives::{ProofRands, ToxicWaste, TrustedSetup}, 7 | protocol::Groth16Protocol, 8 | }; 9 | use ark_test_curves::bls12_381::Fr; 10 | 11 | use circuits::{ 12 | interfaces::ExtractConstraintsInterface, 13 | primitives::{Circuit, CircuitLayer, Gate, GateType, Witness, R1CS}, 14 | }; 15 | use polynomial::interface::PolynomialInterface; 16 | 17 | #[test] 18 | fn test_valid_protocol() { 19 | let r1cs = R1CS:: { 20 | a: vec![ 21 | vec![ 22 | Fr::from(0u32), 23 | Fr::from(1u32), 24 | Fr::from(0u32), 25 | Fr::from(0u32), 26 | Fr::from(0u32), 27 | ], 28 | vec![ 29 | Fr::from(0u32), 30 | Fr::from(0u32), 31 | Fr::from(1u32), 32 | Fr::from(0u32), 33 | Fr::from(0u32), 34 | ], 35 | vec![ 36 | Fr::from(0u32), 37 | Fr::from(0u32), 38 | Fr::from(0u32), 39 | Fr::from(1u32), 40 | Fr::from(0u32), 41 | ], 42 | vec![ 43 | Fr::from(0u32), 44 | Fr::from(0u32), 45 | Fr::from(0u32), 46 | Fr::from(0u32), 47 | Fr::from(1u32), 48 | ], 49 | vec![ 50 | Fr::from(0u32), 51 | Fr::from(1u32), 52 | Fr::from(0u32), 53 | Fr::from(0u32), 54 | Fr::from(0u32), 55 | ], 56 | vec![ 57 | Fr::from(0u32), 58 | Fr::from(1u32), 59 | Fr::from(0u32), 60 | Fr::from(0u32), 61 | Fr::from(0u32), 62 | ], 63 | vec![ 64 | Fr::from(0u32), 65 | Fr::from(0u32), 66 | Fr::from(1u32), 67 | Fr::from(0u32), 68 | Fr::from(0u32), 69 | ], 70 | ], 71 | b: vec![ 72 | vec![ 73 | Fr::from(0u32), 74 | Fr::from(1u32), 75 | Fr::from(0u32), 76 | Fr::from(0u32), 77 | Fr::from(0u32), 78 | ], 79 | vec![ 80 | Fr::from(0u32), 81 | Fr::from(0u32), 82 | Fr::from(1u32), 83 | Fr::from(0u32), 84 | Fr::from(0u32), 85 | ], 86 | vec![ 87 | Fr::from(0u32), 88 | Fr::from(0u32), 89 | Fr::from(0u32), 90 | Fr::from(1u32), 91 | Fr::from(0u32), 92 | ], 93 | vec![ 94 | Fr::from(0u32), 95 | Fr::from(0u32), 96 | Fr::from(0u32), 97 | Fr::from(0u32), 98 | Fr::from(1u32), 99 | ], 100 | vec![ 101 | Fr::from(0u32), 102 | Fr::from(0u32), 103 | Fr::from(1u32), 104 | Fr::from(0u32), 105 | Fr::from(0u32), 106 | ], 107 | vec![ 108 | Fr::from(0u32), 109 | Fr::from(0u32), 110 | Fr::from(0u32), 111 | Fr::from(0u32), 112 | Fr::from(1u32), 113 | ], 114 | vec![ 115 | Fr::from(0u32), 116 | Fr::from(0u32), 117 | Fr::from(0u32), 118 | Fr::from(1u32), 119 | Fr::from(0u32), 120 | ], 121 | ], 122 | c: vec![ 123 | vec![ 124 | Fr::from(-2), 125 | Fr::from(3u32), 126 | Fr::from(0u32), 127 | Fr::from(0u32), 128 | Fr::from(0u32), 129 | ], 130 | vec![ 131 | Fr::from(-2), 132 | Fr::from(0u32), 133 | Fr::from(3u32), 134 | Fr::from(0u32), 135 | Fr::from(0u32), 136 | ], 137 | vec![ 138 | Fr::from(-2), 139 | Fr::from(0u32), 140 | Fr::from(0u32), 141 | Fr::from(3u32), 142 | Fr::from(0u32), 143 | ], 144 | vec![ 145 | Fr::from(-2), 146 | Fr::from(0u32), 147 | Fr::from(0u32), 148 | Fr::from(0u32), 149 | Fr::from(3u32), 150 | ], 151 | vec![ 152 | Fr::from(2u32), 153 | Fr::from(0u32), 154 | Fr::from(0u32), 155 | Fr::from(0u32), 156 | Fr::from(0u32), 157 | ], 158 | vec![ 159 | Fr::from(2u32), 160 | Fr::from(0u32), 161 | Fr::from(0u32), 162 | Fr::from(0u32), 163 | Fr::from(0u32), 164 | ], 165 | vec![ 166 | Fr::from(2u32), 167 | Fr::from(0u32), 168 | Fr::from(0u32), 169 | Fr::from(0u32), 170 | Fr::from(0u32), 171 | ], 172 | ], 173 | }; 174 | 175 | let witness = Witness::new( 176 | vec![Fr::from(1u32)], 177 | vec![ 178 | Fr::from(1u32), 179 | Fr::from(2u32), 180 | Fr::from(1u32), 181 | Fr::from(2u32), 182 | ], 183 | ); 184 | 185 | let r1cs_check = r1cs.check(witness.render()); 186 | assert!(r1cs_check, "this is the R1CS check"); 187 | 188 | let qap_poly_coefficients = r1cs.to_qap_poly_coefficients(); 189 | let qap_poly = qap_poly_coefficients.into_poly_rep(); 190 | 191 | let preprocessor = PreProcessor::new(r1cs, witness.clone()); 192 | let qap = preprocessor.preprocess(); 193 | 194 | let check = qap.qap_check(); 195 | assert_eq!(check, true); 196 | 197 | let toxic_waste = ToxicWaste::new( 198 | Fr::from(2u32), 199 | Fr::from(3u32), 200 | Fr::from(5u32), 201 | Fr::from(6u32), 202 | Fr::from(4u32), 203 | ); 204 | 205 | let trusted_setup = TrustedSetup::::run_trusted_setup( 206 | &toxic_waste, 207 | &qap_poly, 208 | qap.ax.degree(), 209 | ); 210 | 211 | let proof_rands = ProofRands::::new(Fr::from(3u32), Fr::from(5u32)); 212 | 213 | let groth16_proof = Groth16Protocol::::generate_proof( 214 | proof_rands, 215 | &trusted_setup, 216 | &qap, 217 | &witness, 218 | ); 219 | 220 | let is_valid = Groth16Protocol::::verify_proof( 221 | &groth16_proof, 222 | &trusted_setup, 223 | &witness.public_input, 224 | ); 225 | 226 | assert!(is_valid); 227 | } 228 | 229 | #[test] 230 | fn test_valid_protocol_2() { 231 | let r1cs = R1CS:: { 232 | a: vec![vec![ 233 | Fr::from(0u32), 234 | Fr::from(0u32), 235 | Fr::from(1u32), 236 | Fr::from(0u32), 237 | ]], 238 | b: vec![vec![ 239 | Fr::from(0u32), 240 | Fr::from(0u32), 241 | Fr::from(0u32), 242 | Fr::from(1u32), 243 | ]], 244 | c: vec![vec![ 245 | Fr::from(0u32), 246 | Fr::from(1u32), 247 | Fr::from(0u32), 248 | Fr::from(0u32), 249 | ]], 250 | }; 251 | 252 | let witness = Witness::new( 253 | vec![Fr::from(1u32)], 254 | vec![Fr::from(4223u32), Fr::from(41u32), Fr::from(103u32)], 255 | ); 256 | 257 | let r1cs_check = r1cs.check(witness.render()); 258 | assert!(r1cs_check, "this is the R1CS check"); 259 | 260 | let qap_poly_coefficients = r1cs.to_qap_poly_coefficients(); 261 | let qap_poly = qap_poly_coefficients.into_poly_rep(); 262 | 263 | let preprocessor = PreProcessor::new(r1cs, witness.clone()); 264 | let qap = preprocessor.preprocess(); 265 | 266 | let check = qap.qap_check(); 267 | assert_eq!(check, true); 268 | 269 | let toxic_waste = ToxicWaste::new( 270 | Fr::from(2u32), 271 | Fr::from(3u32), 272 | Fr::from(5u32), 273 | Fr::from(6u32), 274 | Fr::from(4u32), 275 | ); 276 | 277 | let trusted_setup = TrustedSetup::::run_trusted_setup( 278 | &toxic_waste, 279 | &qap_poly, 280 | qap.ax.degree(), 281 | ); 282 | 283 | let proof_rands = ProofRands::::new(Fr::from(3u32), Fr::from(5u32)); 284 | 285 | let groth16_proof = Groth16Protocol::::generate_proof( 286 | proof_rands, 287 | &trusted_setup, 288 | &qap, 289 | &witness, 290 | ); 291 | 292 | let is_valid = Groth16Protocol::::verify_proof( 293 | &groth16_proof, 294 | &trusted_setup, 295 | &witness.public_input, 296 | ); 297 | 298 | assert!(is_valid); 299 | } 300 | 301 | // running groth16 on this circuit 302 | // 100(*) - layer 0 303 | // / \ 304 | // 41 103 - input layer 305 | #[test] 306 | fn test_valid_protocol_on_arithmetic_circuit() { 307 | let layer_0 = CircuitLayer::new(vec![Gate::new(GateType::Mul, [0, 1])]); 308 | 309 | let circuit = Circuit::new(vec![layer_0]); 310 | let constraints = circuit.extract_constraints(); 311 | 312 | let r1cs = constraints.to_r1cs_vec::(); 313 | let witness = Witness::new( 314 | vec![Fr::from(1u32)], 315 | vec![Fr::from(4223u32), Fr::from(41u32), Fr::from(103u32)], 316 | ); 317 | let r1cs_check = r1cs.check(witness.render()); 318 | assert!(r1cs_check, "this is the R1CS check"); 319 | 320 | let qap_poly_coefficients = r1cs.to_qap_poly_coefficients(); 321 | let qap_poly = qap_poly_coefficients.into_poly_rep(); 322 | 323 | let preprocessor = PreProcessor::new(r1cs, witness.clone()); 324 | let qap = preprocessor.preprocess(); 325 | 326 | let check = qap.qap_check(); 327 | assert_eq!(check, true); 328 | 329 | let toxic_waste = ToxicWaste::new( 330 | Fr::from(2u32), 331 | Fr::from(3u32), 332 | Fr::from(5u32), 333 | Fr::from(6u32), 334 | Fr::from(4u32), 335 | ); 336 | 337 | let trusted_setup = TrustedSetup::::run_trusted_setup( 338 | &toxic_waste, 339 | &qap_poly, 340 | qap.ax.degree(), 341 | ); 342 | 343 | let proof_rands = ProofRands::::new(Fr::from(3u32), Fr::from(5u32)); 344 | 345 | let groth16_proof = Groth16Protocol::::generate_proof( 346 | proof_rands, 347 | &trusted_setup, 348 | &qap, 349 | &witness, 350 | ); 351 | 352 | let is_valid = Groth16Protocol::::verify_proof( 353 | &groth16_proof, 354 | &trusted_setup, 355 | &witness.public_input, 356 | ); 357 | 358 | assert!(is_valid); 359 | } 360 | -------------------------------------------------------------------------------- /groth16/src/utils.rs: -------------------------------------------------------------------------------- 1 | use ark_ec::{pairing::Pairing, Group}; 2 | use ark_ff::PrimeField; 3 | use polynomial::{ 4 | interface::{PolynomialInterface, UnivariantPolynomialInterface}, 5 | univariant::UnivariantPolynomial, 6 | }; 7 | 8 | /// This is the index of the public variables in the witness 9 | /// this is constant for groth16 10 | pub const PRIVATE_VARIABLES_INDEX: usize = 2; 11 | 12 | /// This function generates the t-polynomial for the circuit 13 | /// we get this; 14 | /// t(x) = (x-1)(x-2)(x-3)(x-4)(x-5)(x-6)(x-7) 15 | /// where 7 is the number of constraints 16 | pub fn generate_t_poly(number_of_constraints: usize) -> UnivariantPolynomial { 17 | let mut t = UnivariantPolynomial::from_coefficients_vec(vec![F::one()]); 18 | for i in 1..number_of_constraints + 1 { 19 | t = t * UnivariantPolynomial::from_coefficients_vec(vec![-F::from(i as u64), F::one()]); 20 | } 21 | 22 | t 23 | } 24 | 25 | /// tau = 5; 26 | /// powers_of_secret_gx = [g^5, g^10, g^15, g^20, g^25, g^30, g^35] 27 | pub fn linear_combination_homomorphic_poly_eval_g1

( 28 | poly: &UnivariantPolynomial, 29 | powers_of_secret_gx: &Vec, 30 | ) -> P::G1 31 | where 32 | P: Pairing, 33 | { 34 | poly.coefficients 35 | .iter() 36 | .enumerate() 37 | .fold(P::G1::default(), |mut acc, (index, coeff)| { 38 | let res = powers_of_secret_gx[index].mul_bigint(coeff.into_bigint()); 39 | acc = acc + res; 40 | acc 41 | }) 42 | } 43 | 44 | pub fn linear_combination_homomorphic_poly_eval_g2

( 45 | poly: &UnivariantPolynomial, 46 | powers_of_secret_gx: &Vec, 47 | ) -> P::G2 48 | where 49 | P: Pairing, 50 | { 51 | poly.coefficients 52 | .iter() 53 | .enumerate() 54 | .fold(P::G2::default(), |mut acc, (index, coeff)| { 55 | let res = powers_of_secret_gx[index].mul_bigint(coeff.into_bigint()); 56 | acc = acc + res; 57 | acc 58 | }) 59 | } 60 | 61 | /// This function generates the powers of tau for the circuit 62 | /// tau = 5; 63 | /// powers_of_tau_g1 = [g.5^0 g.5^1, g.5^2, g.5^3, g.5^4, g.5^5, g.5^6, g.5^7] 64 | pub fn generate_powers_of_tau_g1(tau: P::ScalarField, n: usize) -> Vec { 65 | let mut powers_of_tau_g1 = Vec::with_capacity(n); 66 | let mut tau_power = tau; 67 | let generator = P::G1::generator(); 68 | 69 | powers_of_tau_g1.push(generator); 70 | 71 | for _ in 1..n { 72 | powers_of_tau_g1.push(generator.mul_bigint(tau_power.into_bigint())); 73 | tau_power = tau_power * tau; 74 | } 75 | 76 | powers_of_tau_g1 77 | } 78 | 79 | pub fn generate_powers_of_tau_g2(tau: P::ScalarField, n: usize) -> Vec { 80 | let mut powers_of_tau_g2 = Vec::with_capacity(n); 81 | let mut tau_power = tau; 82 | let generator = P::G2::generator(); 83 | 84 | powers_of_tau_g2.push(generator); 85 | 86 | for _ in 1..n { 87 | powers_of_tau_g2.push(generator.mul_bigint(tau_power.into_bigint())); 88 | tau_power = tau_power * tau; 89 | } 90 | 91 | powers_of_tau_g2 92 | } 93 | 94 | pub fn generate_powers_of_tau_g1_alpha_or_beta( 95 | tau: P::ScalarField, 96 | alpha_or_beta: P::ScalarField, 97 | n: usize, 98 | ) -> Vec { 99 | let mut powers_of_tau_g1_alpha_or_beta = Vec::with_capacity(n); 100 | let mut tau_power = tau; 101 | let generator = P::G1::generator(); 102 | 103 | powers_of_tau_g1_alpha_or_beta.push(generator.mul_bigint(alpha_or_beta.into_bigint())); 104 | 105 | for _ in 1..n { 106 | let g1_p_of_tau = generator.mul_bigint(tau_power.into_bigint()); 107 | powers_of_tau_g1_alpha_or_beta.push(g1_p_of_tau.mul_bigint(alpha_or_beta.into_bigint())); 108 | tau_power = tau_power * tau; 109 | } 110 | 111 | powers_of_tau_g1_alpha_or_beta 112 | } 113 | 114 | pub fn generate_powers_of_tau_t_poly_delta_inverse_g1( 115 | tau: P::ScalarField, 116 | delta_inverse: P::ScalarField, 117 | t_poly: &UnivariantPolynomial, 118 | n: usize, 119 | ) -> Vec { 120 | let mut powers_of_tau_t_poly_delta_inverse_g1 = Vec::with_capacity(n); 121 | let mut tau_power = tau; 122 | let generator = P::G1::generator(); 123 | 124 | let first_element = t_poly.evaluate(&tau) * delta_inverse; 125 | powers_of_tau_t_poly_delta_inverse_g1.push(generator.mul_bigint(first_element.into_bigint())); 126 | 127 | for _ in 1..n { 128 | powers_of_tau_t_poly_delta_inverse_g1.push( 129 | generator.mul_bigint((tau_power * t_poly.evaluate(&tau) * delta_inverse).into_bigint()), 130 | ); 131 | tau_power = tau_power * tau; 132 | } 133 | 134 | powers_of_tau_t_poly_delta_inverse_g1 135 | } 136 | 137 | pub fn generate_c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_public( 138 | c_tau_plus_beta_a_tau_plus_alpha_b_tau: &Vec, 139 | gamma: &P::ScalarField, 140 | ) -> Vec { 141 | let mut result = Vec::with_capacity(c_tau_plus_beta_a_tau_plus_alpha_b_tau.len()); 142 | let generator = P::G1::generator(); 143 | 144 | for c in 0..PRIVATE_VARIABLES_INDEX { 145 | result.push( 146 | generator.mul_bigint((c_tau_plus_beta_a_tau_plus_alpha_b_tau[c] / gamma).into_bigint()), 147 | ); 148 | } 149 | 150 | result 151 | } 152 | 153 | pub fn generate_c_tau_plus_beta_a_tau_plus_alpha_b_tau_g1_private( 154 | c_tau_plus_beta_a_tau_plus_alpha_b_tau: &Vec, 155 | delta: &P::ScalarField, 156 | ) -> Vec { 157 | let mut result = Vec::with_capacity(c_tau_plus_beta_a_tau_plus_alpha_b_tau.len()); 158 | let generator = P::G1::generator(); 159 | 160 | for c in PRIVATE_VARIABLES_INDEX..c_tau_plus_beta_a_tau_plus_alpha_b_tau.len() { 161 | result.push( 162 | generator.mul_bigint((c_tau_plus_beta_a_tau_plus_alpha_b_tau[c] / delta).into_bigint()), 163 | ); 164 | } 165 | 166 | result 167 | } 168 | 169 | pub fn compute_l_i_of_tau_g1( 170 | a_poly_i: &UnivariantPolynomial, 171 | b_poly_i: &UnivariantPolynomial, 172 | c_poly_i: &UnivariantPolynomial, 173 | alpha_t_g1: Vec, 174 | beta_t_g1: Vec, 175 | t_g1: Vec, 176 | ) -> P::G1 { 177 | let beta_a_i_of_tau = linear_combination_homomorphic_poly_eval_g1::

(a_poly_i, &beta_t_g1); 178 | let alpha_b_i_of_tau = linear_combination_homomorphic_poly_eval_g1::

(b_poly_i, &alpha_t_g1); 179 | let c_i_of_tau = linear_combination_homomorphic_poly_eval_g1::

(c_poly_i, &t_g1); 180 | 181 | beta_a_i_of_tau + alpha_b_i_of_tau + c_i_of_tau 182 | } 183 | 184 | pub fn compute_delta_inverse_l_tau_g1( 185 | a_poly: &Vec>, 186 | b_poly: &Vec>, 187 | c_poly: &Vec>, 188 | alpha_t_g1: &Vec, 189 | beta_t_g1: &Vec, 190 | t_g1: &Vec, 191 | delta_inverse: &P::ScalarField, 192 | controlling_pin: usize, 193 | n: usize, 194 | ) -> Vec { 195 | let mut result = Vec::with_capacity(n); 196 | 197 | for i in controlling_pin..n { 198 | let l_p_of_tau_g1 = compute_l_i_of_tau_g1::

( 199 | &a_poly[i], 200 | &b_poly[i], 201 | &c_poly[i], 202 | alpha_t_g1.clone(), 203 | beta_t_g1.clone(), 204 | t_g1.clone(), 205 | ); 206 | let l_p_of_tau_g1_delta_inverse = l_p_of_tau_g1.mul_bigint(delta_inverse.into_bigint()); 207 | result.push(l_p_of_tau_g1_delta_inverse); 208 | } 209 | 210 | result 211 | } 212 | 213 | pub fn internal_product_g1(a: &Vec, b: &Vec) -> P::G1 { 214 | let mut result = P::G1::default(); 215 | 216 | for i in 0..b.len() { 217 | result += a[i].mul_bigint(b[i].into_bigint()); 218 | } 219 | 220 | result 221 | } 222 | 223 | pub fn internal_product_g2(a: &Vec, b: &Vec) -> P::G2 { 224 | let mut result = P::G2::default(); 225 | 226 | for i in 0..b.len() { 227 | result += a[i].mul_bigint(b[i].into_bigint()); 228 | } 229 | 230 | result 231 | } 232 | 233 | #[cfg(test)] 234 | mod tests { 235 | use super::*; 236 | use ark_ec::AffineRepr; 237 | use ark_test_curves::bls12_381::Fr; 238 | use polynomial::interface::PolynomialInterface; 239 | 240 | #[test] 241 | fn test_generate_t_poly() { 242 | // t(x) = (x-1)(x-2) 243 | let number_of_constraints = 2; 244 | let t = generate_t_poly::(number_of_constraints); 245 | 246 | let expected_t = UnivariantPolynomial::from_coefficients_vec(vec![ 247 | Fr::from(2), 248 | Fr::from(-3), 249 | Fr::from(1), 250 | ]); 251 | 252 | assert_eq!(t, expected_t); 253 | } 254 | 255 | #[test] 256 | fn test_generate_t_poly_0() { 257 | // t(x) = (x-1)(x-2)(x-3) 258 | let number_of_constraints = 3; 259 | let t = generate_t_poly::(number_of_constraints); 260 | 261 | let expected_t = UnivariantPolynomial::from_coefficients_vec(vec![ 262 | Fr::from(-6), 263 | Fr::from(11), 264 | Fr::from(-6), 265 | Fr::from(1), 266 | ]); 267 | 268 | assert_eq!(t, expected_t); 269 | } 270 | 271 | #[test] 272 | fn test_linear_combination_homomorphic_poly_eval_g1() { 273 | let powers_of_tau_g1 = 274 | generate_powers_of_tau_g1::(Fr::from(5u64), 3); 275 | // f(tau).G1 when tau = 5 is know and f(x) = 2x^2 + 3x + 1 276 | let poly = UnivariantPolynomial::from_coefficients_vec(vec![ 277 | Fr::from(1), 278 | Fr::from(3), 279 | Fr::from(2), 280 | ]); 281 | let res = linear_combination_homomorphic_poly_eval_g1::< 282 | ark_test_curves::bls12_381::Bls12_381, 283 | >(&poly, &powers_of_tau_g1); 284 | 285 | let generator = ark_test_curves::bls12_381::g1::G1Affine::generator(); 286 | let poly_at_tau = poly.evaluate(&Fr::from(5u64)); 287 | let expected_res = generator.mul_bigint(poly_at_tau.into_bigint()); 288 | 289 | assert_eq!(res, expected_res); 290 | } 291 | 292 | #[test] 293 | fn test_compute_l_i_of_tau_g1() { 294 | let a_i = UnivariantPolynomial::from_coefficients_vec(vec![Fr::from(1), Fr::from(2)]); 295 | let b_i = UnivariantPolynomial::from_coefficients_vec(vec![Fr::from(3), Fr::from(4)]); 296 | let c_i = UnivariantPolynomial::from_coefficients_vec(vec![Fr::from(5), Fr::from(6)]); 297 | 298 | let alpha = Fr::from(5); 299 | let beta = Fr::from(7); 300 | let tau = Fr::from(4); 301 | 302 | let alpha_t_g1 = generate_powers_of_tau_g1_alpha_or_beta::< 303 | ark_test_curves::bls12_381::Bls12_381, 304 | >(tau, alpha, 3); 305 | let beta_t_g1 = generate_powers_of_tau_g1_alpha_or_beta::< 306 | ark_test_curves::bls12_381::Bls12_381, 307 | >(tau, beta, 3); 308 | let t_g1 = generate_powers_of_tau_g1::(tau, 3); 309 | 310 | let l_of_i = (a_i.clone() * beta) + (b_i.clone() * alpha) + c_i.clone(); 311 | let l_of_i_at_tau = l_of_i.evaluate(&tau); 312 | 313 | let generator_1 = ark_test_curves::bls12_381::g1::G1Affine::generator(); 314 | 315 | let expected_res = generator_1.mul_bigint(l_of_i_at_tau.into_bigint()); 316 | 317 | let res = compute_l_i_of_tau_g1::( 318 | &a_i, &b_i, &c_i, alpha_t_g1, beta_t_g1, t_g1, 319 | ); 320 | 321 | assert_eq!(res, expected_res); 322 | } 323 | } 324 | -------------------------------------------------------------------------------- /polynomial/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ahash" 7 | version = "0.8.11" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" 10 | dependencies = [ 11 | "cfg-if", 12 | "once_cell", 13 | "version_check", 14 | "zerocopy", 15 | ] 16 | 17 | [[package]] 18 | name = "ark-ec" 19 | version = "0.4.2" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" 22 | dependencies = [ 23 | "ark-ff", 24 | "ark-poly", 25 | "ark-serialize", 26 | "ark-std", 27 | "derivative", 28 | "hashbrown", 29 | "itertools", 30 | "num-traits", 31 | "zeroize", 32 | ] 33 | 34 | [[package]] 35 | name = "ark-ff" 36 | version = "0.4.2" 37 | source = "registry+https://github.com/rust-lang/crates.io-index" 38 | checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" 39 | dependencies = [ 40 | "ark-ff-asm", 41 | "ark-ff-macros", 42 | "ark-serialize", 43 | "ark-std", 44 | "derivative", 45 | "digest", 46 | "itertools", 47 | "num-bigint", 48 | "num-traits", 49 | "paste", 50 | "rustc_version", 51 | "zeroize", 52 | ] 53 | 54 | [[package]] 55 | name = "ark-ff-asm" 56 | version = "0.4.2" 57 | source = "registry+https://github.com/rust-lang/crates.io-index" 58 | checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" 59 | dependencies = [ 60 | "quote", 61 | "syn 1.0.109", 62 | ] 63 | 64 | [[package]] 65 | name = "ark-ff-macros" 66 | version = "0.4.2" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" 69 | dependencies = [ 70 | "num-bigint", 71 | "num-traits", 72 | "proc-macro2", 73 | "quote", 74 | "syn 1.0.109", 75 | ] 76 | 77 | [[package]] 78 | name = "ark-poly" 79 | version = "0.4.2" 80 | source = "registry+https://github.com/rust-lang/crates.io-index" 81 | checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" 82 | dependencies = [ 83 | "ark-ff", 84 | "ark-serialize", 85 | "ark-std", 86 | "derivative", 87 | "hashbrown", 88 | ] 89 | 90 | [[package]] 91 | name = "ark-serialize" 92 | version = "0.4.2" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" 95 | dependencies = [ 96 | "ark-serialize-derive", 97 | "ark-std", 98 | "digest", 99 | "num-bigint", 100 | ] 101 | 102 | [[package]] 103 | name = "ark-serialize-derive" 104 | version = "0.4.2" 105 | source = "registry+https://github.com/rust-lang/crates.io-index" 106 | checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" 107 | dependencies = [ 108 | "proc-macro2", 109 | "quote", 110 | "syn 1.0.109", 111 | ] 112 | 113 | [[package]] 114 | name = "ark-std" 115 | version = "0.4.0" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" 118 | dependencies = [ 119 | "num-traits", 120 | "rand", 121 | ] 122 | 123 | [[package]] 124 | name = "ark-test-curves" 125 | version = "0.4.2" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | checksum = "83c22c2469f93dfcace9a98baabb7af1bc0c40de82c07cffbc0deba4acf41a90" 128 | dependencies = [ 129 | "ark-ec", 130 | "ark-ff", 131 | "ark-std", 132 | ] 133 | 134 | [[package]] 135 | name = "autocfg" 136 | version = "1.3.0" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" 139 | 140 | [[package]] 141 | name = "cfg-if" 142 | version = "1.0.0" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 145 | 146 | [[package]] 147 | name = "crypto-common" 148 | version = "0.1.6" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 151 | dependencies = [ 152 | "generic-array", 153 | "typenum", 154 | ] 155 | 156 | [[package]] 157 | name = "derivative" 158 | version = "2.2.0" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" 161 | dependencies = [ 162 | "proc-macro2", 163 | "quote", 164 | "syn 1.0.109", 165 | ] 166 | 167 | [[package]] 168 | name = "digest" 169 | version = "0.10.7" 170 | source = "registry+https://github.com/rust-lang/crates.io-index" 171 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 172 | dependencies = [ 173 | "crypto-common", 174 | ] 175 | 176 | [[package]] 177 | name = "either" 178 | version = "1.11.0" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" 181 | 182 | [[package]] 183 | name = "generic-array" 184 | version = "0.14.7" 185 | source = "registry+https://github.com/rust-lang/crates.io-index" 186 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 187 | dependencies = [ 188 | "typenum", 189 | "version_check", 190 | ] 191 | 192 | [[package]] 193 | name = "hashbrown" 194 | version = "0.13.2" 195 | source = "registry+https://github.com/rust-lang/crates.io-index" 196 | checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" 197 | dependencies = [ 198 | "ahash", 199 | ] 200 | 201 | [[package]] 202 | name = "itertools" 203 | version = "0.10.5" 204 | source = "registry+https://github.com/rust-lang/crates.io-index" 205 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 206 | dependencies = [ 207 | "either", 208 | ] 209 | 210 | [[package]] 211 | name = "num-bigint" 212 | version = "0.4.5" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" 215 | dependencies = [ 216 | "num-integer", 217 | "num-traits", 218 | ] 219 | 220 | [[package]] 221 | name = "num-integer" 222 | version = "0.1.46" 223 | source = "registry+https://github.com/rust-lang/crates.io-index" 224 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 225 | dependencies = [ 226 | "num-traits", 227 | ] 228 | 229 | [[package]] 230 | name = "num-traits" 231 | version = "0.2.19" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 234 | dependencies = [ 235 | "autocfg", 236 | ] 237 | 238 | [[package]] 239 | name = "once_cell" 240 | version = "1.19.0" 241 | source = "registry+https://github.com/rust-lang/crates.io-index" 242 | checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" 243 | 244 | [[package]] 245 | name = "paste" 246 | version = "1.0.15" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 249 | 250 | [[package]] 251 | name = "polynomial" 252 | version = "0.1.0" 253 | dependencies = [ 254 | "ark-ff", 255 | "ark-poly", 256 | "ark-test-curves", 257 | ] 258 | 259 | [[package]] 260 | name = "ppv-lite86" 261 | version = "0.2.17" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 264 | 265 | [[package]] 266 | name = "proc-macro2" 267 | version = "1.0.82" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" 270 | dependencies = [ 271 | "unicode-ident", 272 | ] 273 | 274 | [[package]] 275 | name = "quote" 276 | version = "1.0.36" 277 | source = "registry+https://github.com/rust-lang/crates.io-index" 278 | checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" 279 | dependencies = [ 280 | "proc-macro2", 281 | ] 282 | 283 | [[package]] 284 | name = "rand" 285 | version = "0.8.5" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 288 | dependencies = [ 289 | "rand_chacha", 290 | "rand_core", 291 | ] 292 | 293 | [[package]] 294 | name = "rand_chacha" 295 | version = "0.3.1" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 298 | dependencies = [ 299 | "ppv-lite86", 300 | "rand_core", 301 | ] 302 | 303 | [[package]] 304 | name = "rand_core" 305 | version = "0.6.4" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 308 | 309 | [[package]] 310 | name = "rustc_version" 311 | version = "0.4.0" 312 | source = "registry+https://github.com/rust-lang/crates.io-index" 313 | checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" 314 | dependencies = [ 315 | "semver", 316 | ] 317 | 318 | [[package]] 319 | name = "semver" 320 | version = "1.0.23" 321 | source = "registry+https://github.com/rust-lang/crates.io-index" 322 | checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" 323 | 324 | [[package]] 325 | name = "syn" 326 | version = "1.0.109" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 329 | dependencies = [ 330 | "proc-macro2", 331 | "quote", 332 | "unicode-ident", 333 | ] 334 | 335 | [[package]] 336 | name = "syn" 337 | version = "2.0.63" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" 340 | dependencies = [ 341 | "proc-macro2", 342 | "quote", 343 | "unicode-ident", 344 | ] 345 | 346 | [[package]] 347 | name = "typenum" 348 | version = "1.17.0" 349 | source = "registry+https://github.com/rust-lang/crates.io-index" 350 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 351 | 352 | [[package]] 353 | name = "unicode-ident" 354 | version = "1.0.12" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" 357 | 358 | [[package]] 359 | name = "version_check" 360 | version = "0.9.4" 361 | source = "registry+https://github.com/rust-lang/crates.io-index" 362 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 363 | 364 | [[package]] 365 | name = "zerocopy" 366 | version = "0.7.34" 367 | source = "registry+https://github.com/rust-lang/crates.io-index" 368 | checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" 369 | dependencies = [ 370 | "zerocopy-derive", 371 | ] 372 | 373 | [[package]] 374 | name = "zerocopy-derive" 375 | version = "0.7.34" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" 378 | dependencies = [ 379 | "proc-macro2", 380 | "quote", 381 | "syn 2.0.63", 382 | ] 383 | 384 | [[package]] 385 | name = "zeroize" 386 | version = "1.7.0" 387 | source = "registry+https://github.com/rust-lang/crates.io-index" 388 | checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" 389 | dependencies = [ 390 | "zeroize_derive", 391 | ] 392 | 393 | [[package]] 394 | name = "zeroize_derive" 395 | version = "1.4.2" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" 398 | dependencies = [ 399 | "proc-macro2", 400 | "quote", 401 | "syn 2.0.63", 402 | ] 403 | -------------------------------------------------------------------------------- /gkr/src/protocol.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_assignments)] 2 | 3 | use crate::{ 4 | interfaces::GKRProtocolInterface, 5 | primitives::GKRProof, 6 | utils::{gen_w_mle, perform_gkr_sumcheck_layer_one, verifiy_gkr_sumcheck_layer_one}, 7 | }; 8 | use ark_ff::PrimeField; 9 | use circuits::{ 10 | interfaces::GKRProtocolCircuitInterface, 11 | primitives::{Circuit, CircuitEvaluation}, 12 | }; 13 | use fiat_shamir::{interface::TranscriptInterface, FiatShamirTranscript}; 14 | use polynomial::{ 15 | composed::multilinear::ComposedMultilinear, interface::MultilinearPolynomialInterface, 16 | multilinear::Multilinear, 17 | }; 18 | use sum_check::{ 19 | composed::multicomposed::{MultiComposedProver, MultiComposedVerifier}, 20 | interface::{MultiComposedProverInterface, MultiComposedVerifierInterface}, 21 | }; 22 | 23 | pub struct GKRProtocol; 24 | 25 | impl GKRProtocolInterface for GKRProtocol { 26 | fn prove(circuit: &Circuit, evals: &CircuitEvaluation) -> GKRProof { 27 | let mut transcript = FiatShamirTranscript::new(vec![]); 28 | 29 | let mut sum_check_proofs = vec![]; 30 | let mut w_i_b = vec![]; 31 | let mut w_i_c = vec![]; 32 | 33 | let w_0_mle = gen_w_mle(&evals.layers, 0); 34 | transcript.append(w_0_mle.to_bytes()); 35 | 36 | let n_r = transcript.sample_n_as_field_elements(w_0_mle.num_vars); 37 | let mut claim = w_0_mle.evaluate(&n_r).unwrap(); 38 | 39 | let mut last_rand_b; 40 | let mut last_rand_c; 41 | let mut last_alpha; 42 | let mut last_beta; 43 | 44 | // Running sumcheck on layer one 45 | let (add_mle_layer_one, mul_mle_layer_one) = circuit.get_add_n_mul_mle::(0); 46 | let w_1_mle = gen_w_mle(&evals.layers, 1); 47 | let (layer_one_claim, layer_one_rand_b, layer_one_rand_c, layer_one_alpha, layer_one_beta) = 48 | perform_gkr_sumcheck_layer_one( 49 | claim, 50 | n_r.clone(), 51 | &add_mle_layer_one, 52 | &mul_mle_layer_one, 53 | &w_1_mle, 54 | &mut transcript, 55 | &mut sum_check_proofs, 56 | &mut w_i_b, 57 | &mut w_i_c, 58 | ); 59 | 60 | claim = layer_one_claim; 61 | last_rand_b = layer_one_rand_b; 62 | last_rand_c = layer_one_rand_c; 63 | last_alpha = layer_one_alpha; 64 | last_beta = layer_one_beta; 65 | 66 | // starting the GKR round reductions powered by sumcheck (layer 2 to n-1(excluding the input layer)) 67 | for l_index in 2..evals.layers.len() { 68 | let (add_mle, mul_mle) = circuit.get_add_n_mul_mle::(l_index - 1); 69 | let w_i_mle = gen_w_mle(&evals.layers, l_index); 70 | 71 | let number_of_round = last_rand_b.len(); 72 | 73 | // add(r_b, b, c) ---> add(b, c) 74 | let add_rb_b_c = 75 | add_mle.partial_evaluations(last_rand_b.clone(), vec![0; number_of_round]); 76 | // mul(r_b, b, c) ---> mul(b, c) 77 | let mul_rb_b_c = 78 | mul_mle.partial_evaluations(last_rand_b.clone(), vec![0; number_of_round]); 79 | 80 | // add(r_c, b, c) ---> add(b, c) 81 | let add_rc_b_c = 82 | add_mle.partial_evaluations(last_rand_c.clone(), vec![0; number_of_round]); 83 | // mul(r_c, b, c) ---> mul(b, c) 84 | let mul_rc_b_c = 85 | mul_mle.partial_evaluations(last_rand_c.clone(), vec![0; number_of_round]); 86 | 87 | // alpha * add(r_b, b, c) + beta * add(r_c, b, c) 88 | let alpha_beta_add_b_c = (add_rb_b_c * last_alpha) + (add_rc_b_c * last_beta); 89 | // alpha * mul(r_b, b, c) + beta * mul(r_c, b, c) 90 | let alpha_beta_mul_b_c = (mul_rb_b_c * last_alpha) + (mul_rc_b_c * last_beta); 91 | 92 | let wb = w_i_mle.clone(); 93 | let wc = w_i_mle.clone(); 94 | 95 | // w_i(b) + w_i(c) 96 | let wb_add_wc = wb.add_distinct(&wc); 97 | // w_i(b) * w_i(c) 98 | let wb_mul_wc = wb.mul_distinct(&wc); 99 | 100 | // alpha * add(r_b, b, c) + beta * add(r_c, b, c)(w_i(b) + w_i(c)) 101 | let f_b_c_add_section = ComposedMultilinear::new(vec![alpha_beta_add_b_c, wb_add_wc]); 102 | // alpha * mul(r_b, b, c) + beta * mul(r_c, b, c)(w_i(b) * w_i(c)) 103 | let f_b_c_mul_section = ComposedMultilinear::new(vec![alpha_beta_mul_b_c, wb_mul_wc]); 104 | 105 | // f(b, c) = alpha * add(r_b, b, c) + beta * add(r_c, b, c)(w_i(b) + w_i(c)) + alpha * mul(r_b, b, c) + beta * mul(r_c, b, c)(w_i(b) * w_i(c)) 106 | let f_b_c = vec![f_b_c_add_section, f_b_c_mul_section]; 107 | 108 | // this prover that the `claim` is the result of the evalution of the preivous layer 109 | let (sumcheck_proof, random_challenges) = 110 | MultiComposedProver::sum_check_proof_without_initial_polynomial(&f_b_c, &claim); 111 | 112 | transcript.append(sumcheck_proof.to_bytes()); 113 | sum_check_proofs.push(sumcheck_proof); 114 | 115 | let (rand_b, rand_c) = random_challenges.split_at(random_challenges.len() / 2); 116 | 117 | let eval_w_i_b = wb.evaluate(&rand_b.to_vec()).unwrap(); 118 | let eval_w_i_c = wc.evaluate(&rand_c.to_vec()).unwrap(); 119 | 120 | w_i_b.push(eval_w_i_b); 121 | w_i_c.push(eval_w_i_c); 122 | 123 | last_alpha = transcript.sample_as_field_element(); 124 | last_beta = transcript.sample_as_field_element(); 125 | 126 | last_rand_b = rand_b.to_vec(); 127 | last_rand_c = rand_c.to_vec(); 128 | 129 | claim = last_alpha * eval_w_i_b + last_beta * eval_w_i_c; 130 | } 131 | 132 | GKRProof { 133 | sum_check_proofs, 134 | w_i_b, 135 | w_i_c, 136 | w_0_mle, 137 | } 138 | } 139 | 140 | fn verify(circuit: &Circuit, input: &[F], proof: &GKRProof) -> bool { 141 | // performing some sanity checks 142 | if proof.sum_check_proofs.len() != proof.w_i_b.len() 143 | || proof.sum_check_proofs.len() != proof.w_i_c.len() 144 | { 145 | println!("Invalid GKR proof"); 146 | return false; 147 | } 148 | 149 | let mut transcript = FiatShamirTranscript::default(); 150 | transcript.append(proof.w_0_mle.to_bytes()); 151 | 152 | let n_r = transcript.sample_n_as_field_elements(proof.w_0_mle.num_vars); 153 | let mut claim = proof.w_0_mle.evaluate(&n_r).unwrap(); 154 | 155 | let mut last_rand_b = vec![]; 156 | let mut last_rand_c = vec![]; 157 | 158 | let mut last_alpha = F::ZERO; 159 | let mut last_beta = F::ZERO; 160 | 161 | // layer one verification logic 162 | let (add_mle, mul_mle) = circuit.get_add_n_mul_mle::(0); 163 | let (layer_one_verification_status, layer_one_sum) = verifiy_gkr_sumcheck_layer_one( 164 | &claim, 165 | &proof.sum_check_proofs[0], 166 | &mut transcript, 167 | proof.w_i_b[0], 168 | proof.w_i_c[0], 169 | n_r.clone(), 170 | &add_mle, 171 | &mul_mle, 172 | ); 173 | 174 | if !layer_one_verification_status { 175 | return false; 176 | } 177 | 178 | claim = layer_one_sum; 179 | 180 | // running GKR verification logic excluding the first layer 181 | for i in 1..proof.sum_check_proofs.len() { 182 | if proof.sum_check_proofs[i].sum != claim { 183 | println!("Invalid sumcheck proof"); 184 | return false; 185 | } 186 | 187 | transcript.append(proof.sum_check_proofs[i].to_bytes()); 188 | let intermidate_claim_check = 189 | MultiComposedVerifier::verify_except_last_check(&proof.sum_check_proofs[i]); 190 | 191 | // performing sum check last check 192 | let (rand_b, rand_c) = intermidate_claim_check 193 | .random_challenges 194 | .split_at(intermidate_claim_check.random_challenges.len() / 2); 195 | 196 | last_rand_b = rand_b.to_vec(); 197 | last_rand_c = rand_c.to_vec(); 198 | 199 | let w_b = proof.w_i_b[i]; 200 | let w_c = proof.w_i_c[i]; 201 | 202 | let alpha: F = transcript.sample_as_field_element(); 203 | let beta: F = transcript.sample_as_field_element(); 204 | 205 | claim = alpha * w_b + beta * w_c; 206 | 207 | last_alpha = alpha; 208 | last_beta = beta; 209 | } 210 | 211 | // performing verification for the input layer 212 | let w_in = Multilinear::interpolate(input); 213 | 214 | let w_in_b = w_in.evaluate(&last_rand_b).unwrap(); 215 | let w_in_c = w_in.evaluate(&last_rand_c).unwrap(); 216 | 217 | let expected_claim = last_alpha * w_in_b + last_beta * w_in_c; 218 | 219 | if expected_claim != claim { 220 | println!("Invalid sumcheck proof (expected_claim != claim)"); 221 | return false; 222 | } 223 | 224 | true 225 | } 226 | } 227 | 228 | #[cfg(test)] 229 | mod tests { 230 | use super::*; 231 | use ark_test_curves::bls12_381::Fr; 232 | use circuits::{ 233 | interfaces::CircuitInterface, 234 | primitives::{CircuitLayer, Gate, GateType}, 235 | }; 236 | 237 | #[test] 238 | fn test_gkr_protocol() { 239 | let layer_0 = CircuitLayer::new(vec![Gate::new(GateType::Add, [0, 1])]); 240 | let layer_1 = CircuitLayer::new(vec![ 241 | Gate::new(GateType::Mul, [0, 1]), 242 | Gate::new(GateType::Add, [2, 3]), 243 | ]); 244 | let layer_3 = CircuitLayer::new(vec![ 245 | Gate::new(GateType::Add, [0, 1]), 246 | Gate::new(GateType::Mul, [2, 3]), 247 | Gate::new(GateType::Mul, [4, 5]), 248 | Gate::new(GateType::Mul, [6, 7]), 249 | ]); 250 | let layer_4 = CircuitLayer::new(vec![ 251 | Gate::new(GateType::Mul, [0, 1]), 252 | Gate::new(GateType::Mul, [2, 3]), 253 | Gate::new(GateType::Mul, [4, 5]), 254 | Gate::new(GateType::Add, [6, 7]), 255 | Gate::new(GateType::Mul, [8, 9]), 256 | Gate::new(GateType::Add, [10, 11]), 257 | Gate::new(GateType::Mul, [12, 13]), 258 | Gate::new(GateType::Mul, [14, 15]), 259 | ]); 260 | 261 | let circuit = Circuit::new(vec![layer_0, layer_1, layer_3, layer_4]); 262 | let input = [ 263 | Fr::from(2u32), 264 | Fr::from(1u32), 265 | Fr::from(3u32), 266 | Fr::from(1u32), 267 | Fr::from(4u32), 268 | Fr::from(1u32), 269 | Fr::from(2u32), 270 | Fr::from(2u32), 271 | Fr::from(3u32), 272 | Fr::from(3u32), 273 | Fr::from(4u32), 274 | Fr::from(4u32), 275 | Fr::from(2u32), 276 | Fr::from(3u32), 277 | Fr::from(3u32), 278 | Fr::from(4u32), 279 | ]; 280 | 281 | let evaluation = circuit.evaluate(&input); 282 | 283 | assert_eq!(evaluation.layers[0][0], Fr::from(224u32)); 284 | 285 | let proof = GKRProtocol::prove(&circuit, &evaluation); 286 | 287 | assert!(GKRProtocol::verify(&circuit, &input, &proof)); 288 | } 289 | 290 | #[test] 291 | fn test_gkr_protocol_random_circuit() { 292 | let circuit = Circuit::random(8); 293 | let input = (0u64..256) 294 | .into_iter() 295 | .map(|x| Fr::from(x)) 296 | .collect::>(); 297 | 298 | let evaluation = circuit.evaluate(&input); 299 | 300 | let proof = GKRProtocol::prove(&circuit, &evaluation); 301 | 302 | assert!(GKRProtocol::verify(&circuit, &input, &proof)); 303 | } 304 | } 305 | --------------------------------------------------------------------------------