From 2395ee59b41da681496c071201d98a2ca5e635e2 Mon Sep 17 00:00:00 2001 From: cliraa <113949669+cliraa@users.noreply.github.com> Date: Fri, 26 Jan 2024 10:32:37 -0400 Subject: [PATCH 1/9] Shamir secret sharing (#782) * Create lib.rs * Create shamir_secret_sharing.rs * Delete examples/src directory * Update Cargo.toml * Create lib.rs * Create shamir_secret_sharing.rs * Create Cargo.toml * Create README.md * Update shamir_secret_sharing.rs --- Cargo.toml | 2 +- examples/shamir_secret_sharing/Cargo.toml | 13 +++ examples/shamir_secret_sharing/README.md | 34 +++++++ examples/shamir_secret_sharing/src/lib.rs | 1 + .../src/shamir_secret_sharing.rs | 98 +++++++++++++++++++ 5 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 examples/shamir_secret_sharing/Cargo.toml create mode 100644 examples/shamir_secret_sharing/README.md create mode 100644 examples/shamir_secret_sharing/src/lib.rs create mode 100644 examples/shamir_secret_sharing/src/shamir_secret_sharing.rs diff --git a/Cargo.toml b/Cargo.toml index 062b70d47c..d2a8baa924 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [workspace] -members = ["math", "crypto", "gpu", "benches", "provers/plonk", "provers/stark", "provers/cairo", "provers/groth16", "provers/groth16/arkworks-adapter", "examples/merkle-tree-cli", "examples/prove-miden", "winterfell_adapter"] +members = ["math", "crypto", "gpu", "benches", "provers/plonk", "provers/stark", "provers/cairo", "provers/groth16", "provers/groth16/arkworks-adapter", "examples/merkle-tree-cli", "examples/prove-miden", "winterfell_adapter", "examples/shamir_secret_sharing"] exclude = ["ensure-no_std"] resolver = "2" diff --git a/examples/shamir_secret_sharing/Cargo.toml b/examples/shamir_secret_sharing/Cargo.toml new file mode 100644 index 0000000000..56cd2cb5f5 --- /dev/null +++ b/examples/shamir_secret_sharing/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "shamir_secret_sharing" +version.workspace = true +edition.workspace = true +license.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks.git" } +rand = { version = "0.8", features = [ "std", "std_rng" ] } diff --git a/examples/shamir_secret_sharing/README.md b/examples/shamir_secret_sharing/README.md new file mode 100644 index 0000000000..84fd1781aa --- /dev/null +++ b/examples/shamir_secret_sharing/README.md @@ -0,0 +1,34 @@ +# Shamir's Secret Sharing + +## Usage example + +```rust +// Definition of the secret +// Creation of 6 shares +// 3 shares will be used to recover the secret +let sss = ShamirSecretSharing { + secret: FE::new(1234), + n: 6, + k: 3, +}; + +// Polynomial calculation +let polynomial = sss.calculate_polynomial(); + +// Produce shares +let shares = sss.generating_shares(polynomial.clone()); + +// Specify the x and y coordinates of the shares to use +let shares_to_use_x = vec![shares.x[1], shares.x[3], shares.x[4]]; +let shares_to_use_y = vec![shares.y[1], shares.y[3], shares.y[4]]; + +// Interpolation +let poly_2 = sss.reconstructing(shares_to_use_x, shares_to_use_y); + +// Recover the free coefficient of the polynomial +let secret_recovered = sss.recover(&poly_2); + +// Verifications +assert_eq!(polynomial, poly_2); +assert_eq!(sss.secret, secret_recovered); +``` diff --git a/examples/shamir_secret_sharing/src/lib.rs b/examples/shamir_secret_sharing/src/lib.rs new file mode 100644 index 0000000000..00e0a42106 --- /dev/null +++ b/examples/shamir_secret_sharing/src/lib.rs @@ -0,0 +1 @@ +pub mod shamir_secret_sharing; diff --git a/examples/shamir_secret_sharing/src/shamir_secret_sharing.rs b/examples/shamir_secret_sharing/src/shamir_secret_sharing.rs new file mode 100644 index 0000000000..ec93b0ca6a --- /dev/null +++ b/examples/shamir_secret_sharing/src/shamir_secret_sharing.rs @@ -0,0 +1,98 @@ +use lambdaworks_math::{ + field::{element::FieldElement, traits::IsField}, + polynomial::Polynomial, +}; + +use rand::distributions::Standard; +use rand::prelude::Distribution; +use rand::random; + +pub struct ShamirSecretSharing { + secret: FieldElement, + n: usize, + k: usize, +} + +pub struct Shares { + pub x: Vec>, + pub y: Vec>, +} + +impl ShamirSecretSharing { + pub fn calculate_polynomial(&self) -> Polynomial> + where + Standard: Distribution<::BaseType>, + { + let mut coefficients = Vec::new(); + coefficients.push(self.secret.clone()); + for _ in 0..self.k - 1 { + coefficients.push(FieldElement::::new(random())); + } + + let polynomial = Polynomial::new(coefficients.as_slice()); + polynomial + } + + pub fn generating_shares(&self, polynomial: Polynomial>) -> Shares + where + Standard: Distribution<::BaseType>, + { + let mut shares_x: Vec> = Vec::new(); + let mut shares_y: Vec> = Vec::new(); + + for _ in 0..self.n { + let x = FieldElement::::new(random()); + let y = polynomial.evaluate(&x); + shares_x.push(x); + shares_y.push(y); + } + + Shares { + x: shares_x, + y: shares_y, + } + } + + pub fn reconstructing( + &self, + x: Vec>, + y: Vec>, + ) -> Polynomial> { + Polynomial::interpolate(&x, &y).unwrap() + } + + pub fn recover(&self, polynomial: &Polynomial>) -> FieldElement { + polynomial.coefficients()[0].clone() + } +} + +#[cfg(test)] +#[allow(non_snake_case)] +mod tests { + + use crate::shamir_secret_sharing::ShamirSecretSharing; + use lambdaworks_math::field::element::FieldElement; + use lambdaworks_math::field::fields::u64_prime_field::U64PrimeField; + + #[test] + fn shamir_secret_sharing_works() { + const ORDER: u64 = 1613; + type F = U64PrimeField; + type FE = FieldElement; + + let sss = ShamirSecretSharing { + secret: FE::new(1234), + n: 6, + k: 3, + }; + + let polynomial = sss.calculate_polynomial(); + let shares = sss.generating_shares(polynomial.clone()); + let shares_to_use_x = vec![shares.x[1], shares.x[3], shares.x[4]]; + let shares_to_use_y = vec![shares.y[1], shares.y[3], shares.y[4]]; + let poly_2 = sss.reconstructing(shares_to_use_x, shares_to_use_y); + let secret_recovered = sss.recover(&poly_2); + assert_eq!(polynomial, poly_2); + assert_eq!(sss.secret, secret_recovered); + } +} From 51affa888b63ed1334dea4c17be82eb222b06d77 Mon Sep 17 00:00:00 2001 From: Diego K <43053772+diegokingston@users.noreply.github.com> Date: Fri, 26 Jan 2024 11:38:32 -0300 Subject: [PATCH 2/9] Updating readmes (#780) * Updating readmes * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md --- README.md | 3 +- examples/README.md | 153 +++++++++++++++++++++++++++++++++++++++++++++ provers/README.md | 26 ++++++++ 3 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 examples/README.md create mode 100644 provers/README.md diff --git a/README.md b/README.md index da410fc3b0..eee7fd4442 100644 --- a/README.md +++ b/README.md @@ -96,11 +96,12 @@ List of symbols: | Marlin | :x: | :heavy_check_mark: | :x: | :x: | :x: | | GKR | :x: | :heavy_check_mark: | :x: | :heavy_check_mark: | :x: | | **Polynomial Commitment Schemes** | **Lambdaworks** | **Arkworks** | **Halo2** | **gnark** | **Constantine** | +| KZG10 | :heavy_check_mark: | ✔️ | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | FRI | 🏗️ | :x: | :x: | :heavy_check_mark: | :x: | | IPA | 🏗️ | ✔️ | :heavy_check_mark: | :x: | :x: | | Brakedown | :x: | :x: | :x: | :x: | :x: | | Basefold | :x: | :x: | :x: | :x: | :x: | -| KZG10 | :heavy_check_mark: | ✔️ | :heavy_check_mark: | :heavy_check_mark: | :x: | + | **Folding Schemes** | **Lambdaworks** | **Arkworks** | **Halo2** | **gnark** | **Constantine** | | Nova | :x: | :heavy_check_mark: | :x: | :x: | :x: | | Supernova | :x: | :x: | :x: | :x: | :x: | diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000000..9b943a6380 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,153 @@ +# lambdaworks examples + +This folder contains examples designed to learn how to use the different tools in lambdaworks, such as finite field arithmetics, elliptic curves, provers, and adapters. + +## Examples + +Below is a list of all lambdaworks examples in the folder: +- [Merkle tree CLI](https://github.com/lambdaclass/lambdaworks/tree/main/examples/merkle-tree-cli): generate inclusion proofs for an element inside a Merkle tree and verify them using a CLI +- [Proving Miden using lambdaworks STARK Platinum prover](https://github.com/lambdaclass/lambdaworks/tree/main/examples/prove-miden): Executes a Miden vm Fibonacci program, gets the execution trace and generates a proof (and verifies it) using STARK Platinum. + +You can also check [lambdaworks exercises](https://github.com/lambdaclass/lambdaworks/tree/main/exercises) to learn more. + +## Basic use of Finite Fields + +This library works with [finite fields](https://en.wikipedia.org/wiki/Finite_field). A `Field` is an abstract definition. It knows the modulus and defines how the operations are performed. + +We usually create a new `Field` by instantiating an optimized backend. For example, this is the definition of the Pallas field: + +```rust +// 4 is the number of 64-bit limbs needed to represent the field +type PallasMontgomeryBackendPrimeField = MontgomeryBackendPrimeField; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct MontgomeryConfigPallas255PrimeField; +impl IsModulus for MontgomeryConfigPallas255PrimeField { + const MODULUS: U256 = U256::from_hex_unchecked( + "40000000000000000000000000000000224698fc094cf91b992d30ed00000001", + ); +} + +pub type Pallas255PrimeField = + PallasMontgomeryBackendPrimeField; +``` + +Internally, it resolves all the constants needed and creates all the required operations for the field. + +Suppose we want to create a `FieldElement`. This is as easy as instantiating the `FieldElement` over a `Field` and calling a `from_hex` function. + +For example: + +```rust + let an_element = FieldElement::::from_hex_unchecked("030e480bed5fe53fa909cc0f8c4d99b8f9f2c016be4c41e13a4848797979c662") +``` + +Notice we can alias the `FieldElement` to something like + +```rust +type FE = FieldElement::; +``` + +Once we have a field, we can make all the operations. We usually suggest working with references, but copies work too. + +```rust +let field_a = FE::from_hex("3").unwrap(); +let field_b = FE::from_hex("7").unwrap(); + +// We can use pointers to avoid copying the values internally +let operation_result = &field_a * &field_b + +// But all the combinations of pointers and values works +let operation_result = field_a * field_b +``` + +Sometimes, optimized operations are preferred. For example, + +```rust +// We can make a square multiplying two numbers +let squared = field_a * field_a; +// Using exponentiation +let squared = +field_a.pow(FE::from_hex("2").unwrap()) +// Or using an optimized function +let squared = field_a.square() +``` + +ome useful instantiation methods are also provided for common constants and whenever const functions can be called. This is when creating functions that do not rely on the `IsField` trait since Rust does not support const functions in traits yet, + +```rust +// Defined for all field elements +// Efficient, but nonconst for the compiler +let zero = FE::zero() +let one = FE::one() + +// Const alternatives of the functions are provided, +// But the backend needs to be known at compile time. +// This requires adding a where clause to the function + +let zero = F::ZERO +let one = F::ONE +let const_intstantiated = FE::from_hex_unchecked("A1B2C3"); +``` + +You will notice traits are followed by an `Is`, so instead of accepting something of the form `IsField`, you can use `IsPrimeField` and access more functions. The most relevant is `.representative()`. This function returns a canonical representation of the element as a number, not a field. + +## Basic use of Elliptic curves + +lambdaworks supports different elliptic curves. Currently, we support the following elliptic curve types: +- Short Weiestrass: points $(x, y)$ satisfy the equation $y^2 = x^3 + a x + b$. The curve parameters are $a$ and $b$. All elliptic curves can be cast in this form. +- Edwards: points $(x, y)$ satisfy the equation $a x^2 + y^2 = 1 + d x^2 y^2$. The curve parameters are $a$ and $d$. +- Montgomery: points $(x, y)$ satisfy the equation $b y^2 = x^3 + a x^2 + x$. The curve parameters are $b$ and $a$. + +To create an elliptic curve in Short Weiestrass form, we have to implement the traits `IsEllipticCurve` and `IsShortWeierstrass`. Below we show how the Pallas curve is defined: +```rust +#[derive(Clone, Debug)] +pub struct PallasCurve; + +impl IsEllipticCurve for PallasCurve { + type BaseField = Pallas255PrimeField; + type PointRepresentation = ShortWeierstrassProjectivePoint; + + fn generator() -> Self::PointRepresentation { + Self::PointRepresentation::new([ + -FieldElement::::one(), + FieldElement::::from(2), + FieldElement::one(), + ]) + } +} + +impl IsShortWeierstrass for PallasCurve { + fn a() -> FieldElement { + FieldElement::from(0) + } + + fn b() -> FieldElement { + FieldElement::from(5) + } +} +``` + +All curve models have their `defining_equation` method, which allows us to check whether a given $(x,y)$ belongs to the elliptic curve. The `BaseField` is where the coordinates $x,y$ of the curve live. `generator()` provides a point $P$ in the elliptic curve such that, by repeatedly adding $P$ to itself, we can obtain all the points in the elliptic curve group. + +The `generator()` returns a vector with three components $(x,y,z)$, instead of the two $(x,y)$. lambdaworks represents points in projective coordinates, where operations like scalar multiplication are much faster. We can generate points by providing $(x,y)$ +```rust +let x = FE::from_hex_unchecked( + "bd1e740e6b1615ae4c508148ca0c53dbd43f7b2e206195ab638d7f45d51d6b5", + ); +let y = FE::from_hex_unchecked( + "13aacd107ca10b7f8aab570da1183b91d7d86dd723eaa2306b0ef9c5355b91d8", + ); +PallasCurve::create_point_from_affine(x, y).unwrap() +``` +If you provide an invalid point, there will be an error. You can obtain the point at infinity (which is the neutral element for the curve operation) by doing +```rust +let point_at_infinity = PallasCurve::neutral_element() +``` +Once we have points, we can do operations between points. We have the methods `operate_with_self` and `operate_with_other`. For example, +```rust +let g = PallasCurve::generator(); +let g2 = g.operate_with_self(2_u16); +let g3 = g.operate_with_other(&g2); +``` +`operate_with_self` takes as argument anything that implements the `IsUnsignedInteger` trait. This operator represents scalar multiplication. `operate_with_other` takes as argument another point in the elliptic curve. When we operate this way, the $z$ coordinate in the result may be different from $1$. We can transform it back to affine form by using `to_affine`. diff --git a/provers/README.md b/provers/README.md new file mode 100644 index 0000000000..320977db5b --- /dev/null +++ b/provers/README.md @@ -0,0 +1,26 @@ +# lambdaworks Provers + +Provers allow one party, the prover, to show to other parties, the verifiers, that a given computer program has been executed correctly by means of a cryptographic proof. This proof ideally satisfies the following two properties: it is fast to verify and its size is small (smaller than the size of the witness). All provers have a `prove` function, which takes some description of the program and other input and outputs a proof. There is also a `verify` function which takes the proof and other input and accepts or rejects the proof. + +This folder contains the different provers currently supported by lambdaworks: +- Groth 16 +- Plonk +- STARKs +- Cairo + +The reference papers for each of the provers is given below: +- [Groth 16](https://eprint.iacr.org/2016/260) +- [Plonk](https://eprint.iacr.org/2019/953) +- [STARKs](https://eprint.iacr.org/2018/046.pdf) + +A brief description of the Plonk and STARKs provers can be found [here](https://github.com/lambdaclass/lambdaworks/tree/main/docs/src) + +Using one prover or another depends on usecase and other desired properties. We recommend reading and understanding how each prover works, so as to choose the most adequate. +- Groth 16: Shortest proof length. Security depends on pairing-friendly elliptic curves. Needs a new trusted setup for every program you want to prove. +- Plonk (using KZG as commitment scheme): Short proof length. Security depends on pairing-friendly elliptic curves. Universal trusted setup. +- STARKs: longer proof length. Security depends on collision-resistant hash functions. Conjectured to be post-quantum secure. Transparent (no trusted setup). + +## Using provers + +- [Cairo prover](https://github.com/lambdaclass/lambdaworks/blob/main/provers/cairo/README.md) +- [Plonk prover](https://github.com/lambdaclass/lambdaworks/blob/main/provers/plonk/README.md) From 88e7fdd8daf238eac26c1bf15a40a00fcb4b2e59 Mon Sep 17 00:00:00 2001 From: Diego K <43053772+diegokingston@users.noreply.github.com> Date: Fri, 26 Jan 2024 15:41:13 -0300 Subject: [PATCH 3/9] fix table (#783) * fix table * Update README.md * Update README.md --- README.md | 3 ++- examples/README.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index eee7fd4442..eb0620369c 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,8 @@ Both Math and Crypto support wasm with target `wasm32-unknown-unknown`. To see a ## Examples - mini apps - [Merkle Tree CLI](https://github.com/lambdaclass/lambdaworks/tree/main/examples/merkle-tree-cli) +- [Proving Miden](https://github.com/lambdaclass/lambdaworks/tree/main/examples/prove-miden) +- [Shamir's secret sharing](https://github.com/lambdaclass/lambdaworks/tree/main/examples/shamir_secret_sharing) ## Exercises and Challenges - [lambdaworks exercises and challenges](https://github.com/lambdaclass/lambdaworks_exercises/tree/main) @@ -101,7 +103,6 @@ List of symbols: | IPA | 🏗️ | ✔️ | :heavy_check_mark: | :x: | :x: | | Brakedown | :x: | :x: | :x: | :x: | :x: | | Basefold | :x: | :x: | :x: | :x: | :x: | - | **Folding Schemes** | **Lambdaworks** | **Arkworks** | **Halo2** | **gnark** | **Constantine** | | Nova | :x: | :heavy_check_mark: | :x: | :x: | :x: | | Supernova | :x: | :x: | :x: | :x: | :x: | diff --git a/examples/README.md b/examples/README.md index 9b943a6380..44075b9ce4 100644 --- a/examples/README.md +++ b/examples/README.md @@ -5,7 +5,8 @@ This folder contains examples designed to learn how to use the different tools i ## Examples Below is a list of all lambdaworks examples in the folder: -- [Merkle tree CLI](https://github.com/lambdaclass/lambdaworks/tree/main/examples/merkle-tree-cli): generate inclusion proofs for an element inside a Merkle tree and verify them using a CLI +- [Shamir Secret Sharing](https://github.com/lambdaclass/lambdaworks/tree/main/examples/shamir_secret_sharing): implements example of [Shamir's secret sharing](https://en.wikipedia.org/wiki/Shamir%27s_secret_sharing). Shows use of polynomials and finite fields in lambdaworks. +- [Merkle tree CLI](https://github.com/lambdaclass/lambdaworks/tree/main/examples/merkle-tree-cli): generate inclusion proofs for an element inside a Merkle tree and verify them using a CLI. - [Proving Miden using lambdaworks STARK Platinum prover](https://github.com/lambdaclass/lambdaworks/tree/main/examples/prove-miden): Executes a Miden vm Fibonacci program, gets the execution trace and generates a proof (and verifies it) using STARK Platinum. You can also check [lambdaworks exercises](https://github.com/lambdaclass/lambdaworks/tree/main/exercises) to learn more. From 6f3f8786f06af9a21885b6cc1fb6ab3224e094d5 Mon Sep 17 00:00:00 2001 From: Diego K <43053772+diegokingston@users.noreply.github.com> Date: Fri, 26 Jan 2024 15:58:20 -0300 Subject: [PATCH 4/9] Update EC docs (#784) * Update EC docs * explain curves * Update README.md * Update README.md * Update README.md * Update README.md * Update README.md * Create README.md * Create README.md * Update README.md --- crypto/README.md | 7 ++ math/README.md | 9 ++ math/src/elliptic_curve/README.md | 134 ++++++++++++++++++++++++++++-- provers/README.md | 8 +- 4 files changed, 148 insertions(+), 10 deletions(-) create mode 100644 crypto/README.md create mode 100644 math/README.md diff --git a/crypto/README.md b/crypto/README.md new file mode 100644 index 0000000000..20f291d0bb --- /dev/null +++ b/crypto/README.md @@ -0,0 +1,7 @@ +# lambdaworks Crypto + +This folder contains different cryptographic primitives needed for proof systems. The main elements are: +- [Merkle trees](https://github.com/lambdaclass/lambdaworks/tree/main/crypto/src/merkle_tree) +- [Hash functions](https://github.com/lambdaclass/lambdaworks/tree/main/crypto/src/hash) +- [Fiat Shamir transformation](https://github.com/lambdaclass/lambdaworks/tree/main/crypto/src/fiat_shamir) +- [Polynomial commitment schemes](https://github.com/lambdaclass/lambdaworks/tree/main/crypto/src/commitments) diff --git a/math/README.md b/math/README.md new file mode 100644 index 0000000000..cc3810bc4f --- /dev/null +++ b/math/README.md @@ -0,0 +1,9 @@ +# lambdaworks Math + +This folder contains all the relevant mathematical building blocks needed for proof systems and cryptography. The main parts are: +- [Finite Fields](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/field) +- [Elliptic curves](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/elliptic_curve) +- [Polynomials - univariate and multivariate](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/polynomial) +- [Large unsigned integers](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/unsigned_integer) +- [Fast Fourier Transform](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/fft) +- [Optimized Multiscalar Multiplication](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/msm) diff --git a/math/src/elliptic_curve/README.md b/math/src/elliptic_curve/README.md index ba24cd2e82..dce09afff3 100644 --- a/math/src/elliptic_curve/README.md +++ b/math/src/elliptic_curve/README.md @@ -1,12 +1,134 @@ +# Elliptic curves +This folder contains the different elliptic curve models currently supported by lambdaworks. For an overview of the curve models, their addition formulas and coordinate systems, see [Hyperelliptic](https://hyperelliptic.org/EFD/g1p/index.html). The models currently supported are: +- [Short Weierstrass](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/elliptic_curve/short_weierstrass) +- [Twisted Edwards](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/elliptic_curve/edwards) +- [Montgomery](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/elliptic_curve/montgomery) + +Each of the curve models can have one or more coordinate systems, such as homogeneous projective, Jacobian, XZ coordinates, etc. These are used for reasons of performance. It is possible to define an operation, $\oplus$, taking two points over an elliptic curve, $E$ and obtain a third one, such that $(E, \oplus)$ is a group. + +## Short Weierstrass + +The following curves are currently supported: +- [BLS12-377](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/elliptic_curve/short_weierstrass/curves/bls12_377), a pairing-friendly elliptic curve (pairing implementation pending). +- [BLS12-381](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/elliptic_curve/short_weierstrass/curves/bls12_381), a pairing-friendly elliptic curve. +- [Pallas](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/elliptic_curve/short_weierstrass/curves/pallas), useful for recursive SNARKs when used with Vesta. +- [Vesta](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/elliptic_curve/short_weierstrass/curves/vesta), useful for recursive SNARKs when used with Pallas. +- [Starknet's curve](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/short_weierstrass/curves/stark_curve.rs) + +## Twisted Edwards + +The following curves are currently supported: +- [Ed448Goldilocks](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/edwards/curves/ed448_goldilocks.rs) +- [Bandersnatch](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/elliptic_curve/edwards/curves/bandersnatch) +- [TinyJubJub](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/edwards/curves/tiny_jub_jub.rs), only for learning purposes. + +## Montgomery + +The following curves are currently supported: +- [TinyJubJub](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/elliptic_curve/montgomery/curves/tiny_jub_jub.rs), only for learning purposes. + +## Implementing Elliptic Curves in lambdaworks + +In order to define your elliptic curve in lambdaworks, you need to implement some traits: +- `IsEllipticCurve` +- `IsShortWeierstrass` +- `IsEdwards` +- `IsMontgomery` + +To create an elliptic curve in Short Weiestrass form, we have to implement the traits `IsEllipticCurve` and `IsShortWeierstrass` (If you want a twisted Edwards, use `IsEdwards`. For Montgomery form, use `IsMontgomery`). Below we show how the Pallas curve is defined: ```rust -fn do_something_with_an_elliptic_curve(curve: T) { - let g1 = T::subgroup_generator(); // EllipticCurve trait - let g2 = T::secondary_subgroup_generator(); // Pairing trait - T::pairing(g1, g2); // Pairing trait +#[derive(Clone, Debug)] +pub struct PallasCurve; + +impl IsEllipticCurve for PallasCurve { + type BaseField = Pallas255PrimeField; + type PointRepresentation = ShortWeierstrassProjectivePoint; + + fn generator() -> Self::PointRepresentation { + Self::PointRepresentation::new([ + -FieldElement::::one(), + FieldElement::::from(2), + FieldElement::one(), + ]) + } +} - let p1 = T::create_point_from_affine(12, 12); // EllipticCurve trait +impl IsShortWeierstrass for PallasCurve { + fn a() -> FieldElement { + FieldElement::from(0) + } - let s = g1.operate_with(g2); // IsGroup trait + fn b() -> FieldElement { + FieldElement::from(5) + } } ``` + +Here, $a$ and $b$ are the parameters for the Elliptic Curve in Weiestrass form. All curve models have their `defining_equation` method, which allows us to check whether a given $(x,y)$ belongs to the elliptic curve. The `BaseField` is where the coordinates $x,y$ of the curve live. `generator()` gives a point $P$, such that, by doing $P, 2P, 3P, ... , nP$ ($2 P = P \oplus P$) we span all the elements that belong to the Elliptic Curve. + +To implement the `IsShortWeierstrass`, you need to first implement `IsEllipticCurve`. It has 3 methods, two of which need to be implemented for each curve `fn a()` and `fn b()` (the curve parameters) and `fn defining_equation()`, which computes $y^2 - x^3 - a x - b$. If this result is equal to the base field element 0, then the point satisfies the curve equation and is valid (note, however, that the point may not be in the appropriate subgroup of the curve!) + +## Defining points and operating with the curves + +All curves implement the trait `FromAffine`, which lets us define points by providing the pair of values $(x,y)$, where $x$ and $y$ should be in the `BaseField` of the curve. For example +```rust +let x = FE::from_hex_unchecked( + "bd1e740e6b1615ae4c508148ca0c53dbd43f7b2e206195ab638d7f45d51d6b5", + ); +let y = FE::from_hex_unchecked( + "13aacd107ca10b7f8aab570da1183b91d7d86dd723eaa2306b0ef9c5355b91d8", + ); +PallasCurve::create_point_from_affine(x, y).unwrap() +``` +The function has to check whether the point is valid, and, if not, returns an error. + +Each form and coordinate model has to implement the `IsGroup` trait, which will give us all the necessary operations for the group. We need to provide expressions for: +- `fn neutral_element()`, the neutral element for the group operation. In the case of elliptic curves, this is the point at infinity. +- `fn operate_with`, which defines the group operation; it takes two elements in the group and outputs a third one. +- `fn neg`, which gives the inverse of the element. +It also provides the method `fn operate_with_self`, which is used to indicate that repeteadly add one element against itself $n$ times. Here, $n$ should implement the `IsUnsignedInteger` trait. In the case of elliptic curves, this provides the scalar multiplication, $n P$, based on the double and add algorithm (square and multiply). + +Operating is done in the following way: +```rust +// We get a point +let g = PallasCurve::generator(); +let g2 = g.operate_with_self(2_u16); +let g3 = g.operate_with_other(&g2); +``` +`operate_with_self` takes as argument anything that implements the `IsUnsignedInteger` trait. `operate_with_other` takes as argument another point in the elliptic curve. When we operate this way, the $z$ coordinate in the result may be different from $1$. We can transform it back to affine form by using `to_affine`. For example, +```rust +let g = BLS12381Curve::generator(); +let g2 = g.operate_with_self(2_u64); + +// get x and y from affine coordinates +let g2_affine = g2.to_affine(); +let x = g2_affine.x(); +let y = g2_affine.y(); +``` + +## Multiscalar multiplication + +One common operation for different proof systems is the Mutiscalar Multiplication (MSM), which is given by a set of points $P_0 , P_1 , P_2 , ... , P_n$ and scalars $a_0 , a_1 , a_2 ... n_n$ (the scalars belong to the scalar field of the elliptic curve, which is the field whose size matches the size of the elliptic curve's group): +$$R = \sum_k a_k P_k$$ +This operation could be implemented by using `operate_with_self` with each point and scalar and then add the results using `operate_with`, but this is not efficient. lambdaworks provides an optimized [MSM using Pippenger's algorithm](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/msm/pippenger.rs). A naïve version is given [here](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/msm/naive.rs). Below we show how to use MSM in the context of a polynomial commitment scheme: the scalars are the coefficients of the polynomials and the points are provided by an SRS. +```rust +fn commit(&self, p: &Polynomial>) -> Self::Commitment { + let coefficients: Vec<_> = p + .coefficients + .iter() + .map(|coefficient| coefficient.representative()) + .collect(); + msm( + &coefficients, + &self.srs.powers_main_group[..coefficients.len()], + ) + .expect("`points` is sliced by `cs`'s length") + } +``` +## Pairing-friendly elliptic curves + +Pairings are an important calculation for BLS signatures and the KZG polynomial commitment scheme. These are functions mapping elements from groups of order $r$ belonging to an elliptic curve to the set of $r$-th roots of unity, $e: G_1 \times G_2 \rightarrow G_t$. They satisfy two properties: +1. Bilinearity +2. Non-degeneracy +Not all elliptic curves have efficiently computable pairings. If the curve is pairing-friendly, we can implement the trait `IsPairing`. Examples of pairing-friendly curves are BLS12-381, BLS12-377, BN254. Curves such as Pallas, Vesta, secp256k1 are not pairing-friendly. diff --git a/provers/README.md b/provers/README.md index 320977db5b..4ab43c9747 100644 --- a/provers/README.md +++ b/provers/README.md @@ -3,10 +3,10 @@ Provers allow one party, the prover, to show to other parties, the verifiers, that a given computer program has been executed correctly by means of a cryptographic proof. This proof ideally satisfies the following two properties: it is fast to verify and its size is small (smaller than the size of the witness). All provers have a `prove` function, which takes some description of the program and other input and outputs a proof. There is also a `verify` function which takes the proof and other input and accepts or rejects the proof. This folder contains the different provers currently supported by lambdaworks: -- Groth 16 -- Plonk -- STARKs -- Cairo +- [Groth 16](https://github.com/lambdaclass/lambdaworks/tree/main/provers/groth16) +- [Plonk](https://github.com/lambdaclass/lambdaworks/tree/main/provers/plonk) +- [STARKs](https://github.com/lambdaclass/lambdaworks/tree/main/provers/stark) +- [Cairo](https://github.com/lambdaclass/lambdaworks/tree/main/provers/cairo) The reference papers for each of the provers is given below: - [Groth 16](https://eprint.iacr.org/2016/260) From 9728b96bbfcf93f6bfcee0af5590a180b00c345f Mon Sep 17 00:00:00 2001 From: Federico Carrone Date: Sat, 27 Jan 2024 11:58:37 -0300 Subject: [PATCH 5/9] Update README.md --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index eb0620369c..b8ba4696dc 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,12 @@ This library provides efficient implementation of cryptographic primitives used +## Why we built lambdaworks + +Zero-Knowledge and Validity Proofs have gained a lot of attention over the last few years. We strongly believe in this potential and that is why we decided to start working in this challenging ecosystem, where math, cryptography and distributed systems meet. The main barrier in the beginning was not the cryptography or math but the lack of good libraries which are performant and developer friendly. There are some exceptions, though, like gnark or halo2. Some have nice APIs and are easy to work with, but they are not written in Rust, and some are written in Rust but have poor programming and engineering practices. Most of them don't have support for CUDA, Metal and WebGPU or distributed FFT calculation using schedulers like Dask. + +So, we decided to build our library, focusing on performance, with clear documentation and developer-focused. Our core team is a group of passionate people from different backgrounds and different strengths; we think that the whole is greater than just the addition of the parts. We don't want to be a compilation of every research result in the ZK space. We want this to be a library that can be used in production, not just in academic research. We want to offer developers the main building blocks and proof systems so that they can build their applications on top of this library. + ## [Documentation](https://lambdaclass.github.io/lambdaworks) ## Main crates @@ -56,12 +62,6 @@ If you use ```lambdaworks``` libraries in your research projects, please cite th } ``` -## Why we built lambdaworks - -Zero-Knowledge and Validity Proofs have gained a lot of attention over the last few years. We strongly believe in this potential and that is why we decided to start working in this challenging ecosystem, where math, cryptography and distributed systems meet. The main barrier in the beginning was not the cryptography or math but the lack of good libraries which are performant and developer friendly. There are some exceptions, though, like gnark or halo2. Some have nice APIs and are easy to work with, but they are not written in Rust, and some are written in Rust but have poor programming and engineering practices. Most of them don't have support for CUDA, Metal and WebGPU or distributed FFT calculation using schedulers like Dask. - -So, we decided to build our library, focusing on performance, with clear documentation and developer-focused. Our core team is a group of passionate people from different backgrounds and different strengths; we think that the whole is greater than just the addition of the parts. We don't want to be a compilation of every research result in the ZK space. We want this to be a library that can be used in production, not just in academic research. We want to offer developers the main building blocks and proof systems so that they can build their applications on top of this library. - ## List of features Disclaimer: This list contains cryptographic primitives and mathematical structures that we want to support in lambdaworks. It can be expanded later to include new primitives. If you find there is a mistake or there has been an update in another library, please let us know. From d3da31e0eed4d0c770ba5697a6ae437c46eea8b7 Mon Sep 17 00:00:00 2001 From: Federico Carrone Date: Sun, 28 Jan 2024 19:31:46 -0300 Subject: [PATCH 6/9] Update README.md --- README.md | 50 -------------------------------------------------- 1 file changed, 50 deletions(-) diff --git a/README.md b/README.md index b8ba4696dc..b8e75ae4ba 100644 --- a/README.md +++ b/README.md @@ -157,56 +157,6 @@ To serve the documentation locally, first install both [mdbook](https://rust-lan make docs ``` -## 📊 Benchmarks - -Benchmark results are hosted [here](https://lambdaclass.github.io/lambdaworks/bench). - -These are the results of execution of the benchmarks for finite field arithmetic using the STARK field prime (p = 3618502788666131213697322783095070105623107215331596699973092056135872020481). - -Differences of 3% are common for some measurements, so small differences are not statistically relevant. - -ARM - M1 - -| Operation| N | Arkworks | lambdaworks | -| -------- | --- | --------- | ----------- | -| `mul` | 10k | 112 μs | 115 μs | -| `add` | 1M | 8.5 ms | 7.0 ms | -| `sub` | 1M | 7.53 ms | 7.12 ms | -| `pow` | 10k | 11.2 ms | 12.4 ms | -| `invert` | 10k | 30.0 ms | 27.2 ms | - -x86 - AMD Ryzen 7 PRO - -| Operation | N | Arkworks (ASM)* | lambdaworks | -| -------- | --- | --------- | ----------- | -| `mul` | 10k | 118.9 us | 95.7 us | -| `add` | 1M | 6.8 ms | 5.4 ms | -| `sub` | 1M | 6.6 ms | 5.2 ms | -| `pow` | 10k | 10.6 ms | 9.4 ms | -| `invert` | 10k | 34.2 ms | 35.74 ms | - -*assembly feature was enabled manually for that bench, and is not activated by default when running criterion - -To run them locally, you will need `cargo-criterion` and `cargo-flamegraph`. Install it with: - -```bash -cargo install cargo-criterion -``` - -Run the complete benchmark suite with: - -```bash -make benchmarks -``` - -Run a specific benchmark suite with `cargo`, for example to run the one for `field`: - -```bash -make benchmark BENCH=field -``` - -You can check the generated HTML report in `target/criterion/reports/index.html` - ## 📚 References The following links, repos and projects have been important in the development of this library and we want to thank and acknowledge them. From 6b0995362e5baeec61f319abbe075a2f0e78f136 Mon Sep 17 00:00:00 2001 From: Federico Carrone Date: Sun, 28 Jan 2024 19:32:15 -0300 Subject: [PATCH 7/9] Update README.md --- math/src/field/README.md | 50 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/math/src/field/README.md b/math/src/field/README.md index 89e4afef6d..2b896ba33b 100644 --- a/math/src/field/README.md +++ b/math/src/field/README.md @@ -71,3 +71,53 @@ fn main() { ``` As you can see all the operators are already implemented automatically for you. + +## 📊 Benchmarks + +Benchmark results are hosted [here](https://lambdaclass.github.io/lambdaworks/bench). + +These are the results of execution of the benchmarks for finite field arithmetic using the STARK field prime (p = 3618502788666131213697322783095070105623107215331596699973092056135872020481). + +Differences of 3% are common for some measurements, so small differences are not statistically relevant. + +ARM - M1 + +| Operation| N | Arkworks | lambdaworks | +| -------- | --- | --------- | ----------- | +| `mul` | 10k | 112 μs | 115 μs | +| `add` | 1M | 8.5 ms | 7.0 ms | +| `sub` | 1M | 7.53 ms | 7.12 ms | +| `pow` | 10k | 11.2 ms | 12.4 ms | +| `invert` | 10k | 30.0 ms | 27.2 ms | + +x86 - AMD Ryzen 7 PRO + +| Operation | N | Arkworks (ASM)* | lambdaworks | +| -------- | --- | --------- | ----------- | +| `mul` | 10k | 118.9 us | 95.7 us | +| `add` | 1M | 6.8 ms | 5.4 ms | +| `sub` | 1M | 6.6 ms | 5.2 ms | +| `pow` | 10k | 10.6 ms | 9.4 ms | +| `invert` | 10k | 34.2 ms | 35.74 ms | + +*assembly feature was enabled manually for that bench, and is not activated by default when running criterion + +To run them locally, you will need `cargo-criterion` and `cargo-flamegraph`. Install it with: + +```bash +cargo install cargo-criterion +``` + +Run the complete benchmark suite with: + +```bash +make benchmarks +``` + +Run a specific benchmark suite with `cargo`, for example to run the one for `field`: + +```bash +make benchmark BENCH=field +``` + +You can check the generated HTML report in `target/criterion/reports/index.html` From ed7928a34450f2841d17dba356f31f6cd680f667 Mon Sep 17 00:00:00 2001 From: Diego K <43053772+diegokingston@users.noreply.github.com> Date: Mon, 29 Jan 2024 11:48:44 -0300 Subject: [PATCH 8/9] Create README.md polynomials (#785) * Create README.md polynomials * Update README.md * Update README.md * Update README.md --- math/src/polynomial/README.md | 68 +++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 math/src/polynomial/README.md diff --git a/math/src/polynomial/README.md b/math/src/polynomial/README.md new file mode 100644 index 0000000000..d4ca99d077 --- /dev/null +++ b/math/src/polynomial/README.md @@ -0,0 +1,68 @@ +# lambdaworks Polynomials + +Contains all the relevant tools for polynomials. Supports: +- [Univariate polynomials](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/polynomial/mod.rs) +- [Dense Multivariate polynomials](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/polynomial/dense_multilinear_poly.rs) and [Sparse Multilinear polynomials](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/polynomial/sparse_multilinear_poly.rs) + +lambdaworks's polynomials work over [Finite Fields](https://github.com/lambdaclass/lambdaworks/tree/main/math/src/field). + +## Univariate polynomials + +Univariate polynomials are expressions of the form $p(x) = a_0 + a_1 x + a_2 x^2 + ... + a_n x^n$, where $x$ is the indeterminate and $a_0, a_1 , ... , a_n$ take values over a finite field. The power with the highest non-zero coefficient is called the degree of the polynomial. A univariate polynomial is represented by means of the following struct: +```rust +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Polynomial { + pub coefficients: Vec, +} +``` +it contains the coefficients in increasing order (we start with the independent term, $a_0$, then $a_1$, and so on and so forth). To create a new polynomial, +```rust +let my_poly = Polynomial::new(&[FE::new(1), FE::new(2), FE::new(3)]) +``` +This creates the polynomial $p(x) = 1 + 2 x + 3 x^2$. If we provide additional zeros to the right, the `new` method will remove those unnecessary zeros. For example, +```rust +let my_poly = Polynomial::new(&[FE::new(1), FE::new(2), FE::new(3), FE::ZERO]) +``` +generates the same polynomial as before. We can also create a monomial, such as $5 x^4$ or $27 x^{120}$, which can be simpler sometimes (instead of providing a long list of zeros). To define a monomial, simply +```rust +let my_monomial = Polynomial::new_monomial(FE::new(27),6) +``` +generates the monomial $p(x) = 27 x^6$, which has a representation as polynomial $(0,0,0,0,0,0,27)$. + +Univariate polynomials have a [ring structure](https://en.wikipedia.org/wiki/Ring_(mathematics)): we can add, subtract, multiply and divide as we did with integers. For example, to add two polynomials, +```rust +let p_1 = Polynomial::new(&[FE::new(3), FE::new(4), FE::new(5)]) +let p_2 = Polynomial::new(&[FE::new(4), FE::new(6), FE::new(8)]) +let p_a = p_1 + p_2 +``` +Polynomial multiplication, +```rust +let p1 = Polynomial::new(&[FE::new(3), FE::new(3), FE::new(2)]); +let p2 = Polynomial::new(&[FE::new(4), FE::new(1)]); +assert_eq!( + p2 * p1, + Polynomial::new(&[FE::new(12), FE::new(15), FE::new(11), FE::new(2)]) + ); +``` +Division, +```rust +let p1 = Polynomial::new(&[FE::new(1), FE::new(3)]); +let p2 = Polynomial::new(&[FE::new(1), FE::new(3)]); +let p3 = p1.mul_with_ref(&p2); +assert_eq!(p3 / p2, p1); +``` +Note that, in the case of polynomial division, it may have a remainder. If you want to divide a polynomial $p(x)$ by $x - b$, you can use faster alternatives, such as `ruffini_division` or `ruffini_division_inplace`. + +Polynomials can also be evaluated at a point $x_0$ using `evaluate`. This provides the evaluation $p( x_0 ) = a_0 + a_1 x_0 + a_2 x_0^2 + ... + a_n x_0^n$. For example, +```rust +let p = Polynomial::new(&[FE::new(3), -FE::new(2), FE::new(4)]); +assert_eq!(p.evaluate(&FE::new(2)), FE::new(15)); +``` +evaluates the polynomial $p(x) = 3 - 2 x + 4 x^2$ at $2$ to yield $15$. If you need to evaluate at several points, you can use `evaluate_slice`. + +Alternatively, polynomials of degree $n$ can be defined by providing exactly $n + 1$ evaluations. For example, $p(1) = 1$ and $p(0) = 2$ defines a unique polynomial of degree $1$, $p(x) = 2 - x$. To obtain the coefficients of $p(x)$ we need to use the function `interpolate`, which takes to vectors, of equal length: the first contains the $x$ coordinates $(0,1)$ and the second, the $y$ components $(2,1)$ (note that we have to provide the evaluation points in the same order as their corresponding evaluations): +```rust +let p = Polynomial::interpolate(&[FE::new(0), FE::new(1)], &[FE::new(2), FE::new(1)]).unwrap(); +``` + +Many polynomial operations can go faster by using the [Fast Fourier Transform](https://github.com/lambdaclass/lambdaworks/blob/main/math/src/fft/polynomial.rs). From 66dc5b77740f284301c7b2900adb0c6d1e5f72d7 Mon Sep 17 00:00:00 2001 From: "protocolwhisper.eth" <57886661+protocolwhisper@users.noreply.github.com> Date: Mon, 29 Jan 2024 14:09:51 -0300 Subject: [PATCH 9/9] (feature): Benchmarking Poseidon (#703) * (feature): Benchmark Poseidon * (fix): Instantiation Poseidon * (fix): Updating imports * (rebase): Poseidon benchmark * (fix): bench parameters * (rebase): Fixing fmt error * Add missing newline * Undo removing of a newline --------- Co-authored-by: Mariano A. Nicolini Co-authored-by: Diego K <43053772+diegokingston@users.noreply.github.com> Co-authored-by: Mauro Toscano <12560266+MauroToscano@users.noreply.github.com> --- crypto/Cargo.toml | 4 ++++ crypto/benches/criterion_poseidon.rs | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 crypto/benches/criterion_poseidon.rs diff --git a/crypto/Cargo.toml b/crypto/Cargo.toml index b7c86f5975..78ccd9263c 100644 --- a/crypto/Cargo.toml +++ b/crypto/Cargo.toml @@ -35,3 +35,7 @@ harness = false [[bench]] name = "iai_merkle" harness = false + +[[bench]] +name= "criterion_poseidon" +harness=false diff --git a/crypto/benches/criterion_poseidon.rs b/crypto/benches/criterion_poseidon.rs new file mode 100644 index 0000000000..79574e7f72 --- /dev/null +++ b/crypto/benches/criterion_poseidon.rs @@ -0,0 +1,18 @@ +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use lambdaworks_crypto::hash::poseidon::starknet::PoseidonCairoStark252; +use lambdaworks_crypto::hash::poseidon::Poseidon; +use lambdaworks_math::field::element::FieldElement; +use lambdaworks_math::field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField; + +fn poseidon_benchmarks(c: &mut Criterion) { + let x = FieldElement::::from_hex("0x123456").unwrap(); + let y = FieldElement::::from_hex("0x789101").unwrap(); + let mut group = c.benchmark_group("Poseidon Benchmark"); + + // Benchmark with black_box is 0.41% faster + group.bench_function("Hashing with black_box", |bench| { + bench.iter(|| black_box(PoseidonCairoStark252::hash(&x, &y))) + }); +} +criterion_group!(poseidon, poseidon_benchmarks); +criterion_main!(poseidon);