├── .gitmodules ├── docs ├── .gitignore ├── src │ ├── starks │ │ ├── cairo.md │ │ ├── cairo_cli.md │ │ ├── stone_prover │ │ │ ├── images │ │ │ │ ├── mem_pool.png │ │ │ │ ├── main_trace.png │ │ │ │ └── interaction_trace.png │ │ │ └── introduction.md │ │ ├── starks.md │ │ └── implementation.md │ ├── plonk │ │ ├── SUMMARY.md │ │ └── plonk.md │ ├── introduction.md │ ├── SUMMARY.md │ └── fft │ │ └── benchmarks.md └── book.toml ├── examples ├── prove-miden │ ├── .gitignore │ ├── README.md │ └── Cargo.toml ├── merkle-tree-cli │ ├── .gitignore │ ├── sample_tree.csv │ ├── Cargo.toml │ └── src │ │ └── commands.rs ├── rsa │ ├── src │ │ └── lib.rs │ └── Cargo.toml ├── shamir_secret_sharing │ ├── src │ │ └── lib.rs │ ├── Cargo.toml │ └── README.md ├── schnorr-signature │ ├── src │ │ ├── lib.rs │ │ └── common.rs │ └── Cargo.toml ├── pohlig-hellman-attack │ ├── src │ │ └── lib.rs │ └── Cargo.toml ├── prove-verify-circom │ ├── input_files │ │ ├── input.json │ │ └── test.circom │ ├── README.md │ ├── Cargo.toml │ └── src │ │ └── main.rs ├── pinocchio │ ├── src │ │ ├── lib.rs │ │ ├── common.rs │ │ └── prover.rs │ ├── Cargo.toml │ └── tests │ │ └── integration_test.rs └── baby-snark │ ├── example.json │ ├── src │ ├── lib.rs │ ├── utils.rs │ ├── scs.rs │ ├── common.rs │ ├── verifier.rs │ └── prover.rs │ └── Cargo.toml ├── crates ├── gpu │ ├── src │ │ ├── cuda │ │ │ ├── mod.rs │ │ │ └── abstractions │ │ │ │ ├── mod.rs │ │ │ │ └── errors.rs │ │ └── lib.rs │ ├── Cargo.toml │ └── build.rs ├── math │ ├── src │ │ ├── gpu │ │ │ ├── cuda │ │ │ │ ├── mod.rs │ │ │ │ ├── field │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── element.rs │ │ │ │ └── shaders │ │ │ │ │ ├── utils.h │ │ │ │ │ ├── fft │ │ │ │ │ ├── bitrev_permutation.cuh │ │ │ │ │ ├── fft.cuh │ │ │ │ │ └── twiddles.cuh │ │ │ │ │ └── field │ │ │ │ │ └── stark256.cu │ │ │ └── mod.rs │ │ ├── field │ │ │ ├── fields │ │ │ │ ├── binary │ │ │ │ │ └── mod.rs │ │ │ │ ├── mersenne31 │ │ │ │ │ └── mod.rs │ │ │ │ ├── vesta_field.rs │ │ │ │ ├── pallas_field.rs │ │ │ │ ├── secp256k1_field.rs │ │ │ │ ├── secp256r1_field.rs │ │ │ │ ├── secp256k1_scalarfield.rs │ │ │ │ ├── fft_friendly │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── u64_mersenne_montgomery_field.rs │ │ │ │ └── mod.rs │ │ │ ├── extensions │ │ │ │ └── mod.rs │ │ │ ├── test_fields │ │ │ │ └── mod.rs │ │ │ ├── errors.rs │ │ │ └── mod.rs │ │ ├── fft │ │ │ ├── gpu │ │ │ │ ├── mod.rs │ │ │ │ └── cuda │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── polynomial.rs │ │ │ ├── cpu │ │ │ │ ├── mod.rs │ │ │ │ ├── ops.rs │ │ │ │ └── bit_reversing.rs │ │ │ └── mod.rs │ │ ├── elliptic_curve │ │ │ ├── montgomery │ │ │ │ ├── curves │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── tiny_jub_jub.rs │ │ │ │ ├── mod.rs │ │ │ │ └── traits.rs │ │ │ ├── short_weierstrass │ │ │ │ ├── curves │ │ │ │ │ ├── pallas │ │ │ │ │ │ └── mod.rs │ │ │ │ │ ├── vesta │ │ │ │ │ │ └── mod.rs │ │ │ │ │ ├── grumpkin │ │ │ │ │ │ └── mod.rs │ │ │ │ │ ├── secp256k1 │ │ │ │ │ │ └── mod.rs │ │ │ │ │ ├── secp256r1 │ │ │ │ │ │ └── mod.rs │ │ │ │ │ ├── secq256k1 │ │ │ │ │ │ └── mod.rs │ │ │ │ │ ├── bls12_377 │ │ │ │ │ │ └── mod.rs │ │ │ │ │ ├── bn_254 │ │ │ │ │ │ ├── mod.rs │ │ │ │ │ │ └── default_types.rs │ │ │ │ │ ├── bls12_381 │ │ │ │ │ │ ├── mod.rs │ │ │ │ │ │ └── default_types.rs │ │ │ │ │ └── mod.rs │ │ │ │ ├── mod.rs │ │ │ │ └── errors.rs │ │ │ ├── edwards │ │ │ │ ├── curves │ │ │ │ │ ├── bandersnatch │ │ │ │ │ │ ├── mod.rs │ │ │ │ │ │ └── field.rs │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── tiny_jub_jub.rs │ │ │ │ ├── mod.rs │ │ │ │ └── traits.rs │ │ │ ├── mod.rs │ │ │ └── traits.rs │ │ ├── msm │ │ │ ├── mod.rs │ │ │ └── README.md │ │ ├── circle │ │ │ ├── errors.rs │ │ │ └── mod.rs │ │ ├── unsigned_integer │ │ │ ├── mod.rs │ │ │ └── traits.rs │ │ ├── lib.rs │ │ ├── polynomial │ │ │ └── error.rs │ │ ├── helpers.rs │ │ ├── errors.rs │ │ ├── cyclic_group.rs │ │ └── traits.rs │ ├── benches │ │ ├── polynomials │ │ │ ├── mod.rs │ │ │ ├── sparse_multilinear_poly.rs │ │ │ └── dense_multilinear_poly.rs │ │ ├── elliptic_curves │ │ │ ├── mod.rs │ │ │ ├── bls12_377.rs │ │ │ └── iai_bls12_377.rs │ │ ├── fields │ │ │ └── mod.rs │ │ ├── utils │ │ │ ├── mod.rs │ │ │ ├── fft_functions.rs │ │ │ ├── stark252_utils.rs │ │ │ └── u64_goldilocks_utils.rs │ │ ├── criterion_polynomial.rs │ │ ├── criterion_elliptic_curve.rs │ │ ├── iai_elliptic_curve.rs │ │ ├── criterion_field.rs │ │ └── iai_field.rs │ └── README.md ├── provers │ ├── stark │ │ └── src │ │ │ ├── tests │ │ │ └── mod.rs │ │ │ ├── proof │ │ │ ├── mod.rs │ │ │ └── errors.rs │ │ │ ├── constraints │ │ │ └── mod.rs │ │ │ ├── examples │ │ │ └── mod.rs │ │ │ ├── fri │ │ │ ├── fri_decommit.rs │ │ │ └── fri_commitment.rs │ │ │ ├── lib.rs │ │ │ ├── config.rs │ │ │ ├── context.rs │ │ │ ├── utils.rs │ │ │ └── domain.rs │ ├── plonk │ │ ├── src │ │ │ ├── constraint_system │ │ │ │ ├── examples │ │ │ │ │ ├── mod.rs │ │ │ │ │ └── pow.rs │ │ │ │ └── errors.rs │ │ │ ├── lib.rs │ │ │ └── test_utils │ │ │ │ └── mod.rs │ │ └── Cargo.toml │ ├── groth16 │ │ ├── circom-adapter │ │ │ ├── tests │ │ │ │ ├── vitalik_example │ │ │ │ │ ├── witness.json │ │ │ │ │ └── test.r1cs.json │ │ │ │ └── poseidon_test.rs │ │ │ ├── Cargo.toml │ │ │ └── src │ │ │ │ └── lib.rs │ │ ├── src │ │ │ ├── lib.rs │ │ │ ├── verifier.rs │ │ │ ├── r1cs.rs │ │ │ └── common.rs │ │ ├── Cargo.toml │ │ ├── arkworks-adapter │ │ │ └── Cargo.toml │ │ └── tests │ │ │ └── groth16.rs │ ├── winterfell_adapter │ │ ├── src │ │ │ ├── lib.rs │ │ │ ├── field_element │ │ │ │ └── mod.rs │ │ │ ├── examples │ │ │ │ └── mod.rs │ │ │ ├── utils.rs │ │ │ └── adapter │ │ │ │ └── public_inputs.rs │ │ └── Cargo.toml │ ├── sumcheck │ │ └── Cargo.toml │ ├── gkr │ │ └── Cargo.toml │ └── README.md └── crypto │ ├── src │ ├── commitments │ │ ├── mod.rs │ │ ├── test_srs │ │ │ └── srs_3_g1_elements.bin │ │ └── traits.rs │ ├── hash │ │ ├── poseidon │ │ │ ├── starknet │ │ │ │ └── mod.rs │ │ │ └── parameters.rs │ │ ├── mod.rs │ │ ├── rescue_prime │ │ │ └── mod.rs │ │ ├── README.md │ │ ├── monolith │ │ │ └── utils.rs │ │ └── pedersen │ │ │ └── parameters.rs │ ├── fiat_shamir │ │ ├── mod.rs │ │ ├── README.md │ │ ├── test_transcript.rs │ │ └── is_transcript.rs │ ├── merkle_tree │ │ ├── mod.rs │ │ ├── backends │ │ │ ├── mod.rs │ │ │ └── types.rs │ │ ├── test_merkle.rs │ │ └── traits.rs │ ├── lib.rs │ └── errors.rs │ ├── README.md │ ├── benches │ ├── criterion_poseidon.rs │ ├── criterion_pedersen.rs │ ├── criterion_merkle.rs │ └── iai_merkle.rs │ └── Cargo.toml ├── .github ├── CODEOWNERS ├── pull_request_template.md ├── workflows │ ├── gh-pages.yml │ ├── publish.yml │ └── iai_benchs_main.yml └── SECURITY.md ├── ensure-no_std ├── .cargo │ └── config.toml ├── src │ └── main.rs └── Cargo.toml ├── exercises ├── broken_heart │ ├── src │ │ └── lib.rs │ └── Cargo.toml ├── blind_trust │ ├── src │ │ └── lib.rs │ ├── proof │ ├── srs │ └── Cargo.toml ├── challenge_2 │ ├── srs.bin │ ├── Cargo.toml │ └── README.md ├── challenge_3 │ ├── srs.bin │ ├── Cargo.toml │ └── README.md ├── challenge_1 │ ├── src │ │ ├── solver.rs │ │ ├── field.rs │ │ ├── main.rs │ │ └── cypher.rs │ ├── Cargo.toml │ └── README.md └── README.md ├── Dockerfile ├── .rusty-hook.toml ├── default.nix ├── fuzz ├── Cargo.toml ├── no_gpu_fuzz │ └── fuzz_targets │ │ ├── deserialize_stark_proof.rs │ │ ├── field │ │ └── stark_field_addition.rs │ │ └── curve │ │ └── curve_grumpkin.rs ├── cuda_fuzz │ ├── Cargo.toml │ └── src │ │ ├── twiddles_generation_diff.rs │ │ ├── cuda_fft_fuzzer.rs │ │ └── polynomial_fft_diff.rs └── README.md ├── .gitignore ├── benches ├── benches │ ├── utils.rs │ ├── invert.rs │ ├── mul.rs │ ├── sqrt.rs │ ├── sub.rs │ ├── add.rs │ ├── pow.rs │ └── poseidon.rs └── Cargo.toml └── Makefile /.gitmodules: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | book 2 | -------------------------------------------------------------------------------- /docs/src/starks/cairo.md: -------------------------------------------------------------------------------- 1 | # Cairo 2 | -------------------------------------------------------------------------------- /docs/src/starks/cairo_cli.md: -------------------------------------------------------------------------------- 1 | # CLI 2 | -------------------------------------------------------------------------------- /examples/prove-miden/.gitignore: -------------------------------------------------------------------------------- 1 | *.json 2 | -------------------------------------------------------------------------------- /examples/merkle-tree-cli/.gitignore: -------------------------------------------------------------------------------- 1 | *.json 2 | -------------------------------------------------------------------------------- /crates/gpu/src/cuda/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod abstractions; 2 | -------------------------------------------------------------------------------- /crates/math/src/gpu/cuda/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod field; 2 | -------------------------------------------------------------------------------- /crates/math/src/gpu/cuda/field/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod element; 2 | -------------------------------------------------------------------------------- /crates/gpu/src/cuda/abstractions/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod errors; 2 | -------------------------------------------------------------------------------- /crates/math/src/field/fields/binary/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod field; 2 | -------------------------------------------------------------------------------- /examples/merkle-tree-cli/sample_tree.csv: -------------------------------------------------------------------------------- 1 | 0x12345;0x6789A;0xBCDEF -------------------------------------------------------------------------------- /crates/gpu/src/lib.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "cuda")] 2 | pub mod cuda; 3 | -------------------------------------------------------------------------------- /crates/provers/stark/src/tests/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod integration_tests; 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @lambdaclass/zk_research_and_development 2 | -------------------------------------------------------------------------------- /crates/crypto/src/commitments/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod kzg; 2 | pub mod traits; 3 | -------------------------------------------------------------------------------- /crates/math/src/gpu/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "cuda")] 2 | pub mod cuda; 3 | -------------------------------------------------------------------------------- /crates/math/src/fft/gpu/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "cuda")] 2 | pub mod cuda; 3 | -------------------------------------------------------------------------------- /examples/rsa/src/lib.rs: -------------------------------------------------------------------------------- 1 | mod rsa; 2 | 3 | pub use rsa::{RSAError, RSA}; 4 | -------------------------------------------------------------------------------- /examples/shamir_secret_sharing/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod shamir_secret_sharing; 2 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/montgomery/curves/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod tiny_jub_jub; 2 | -------------------------------------------------------------------------------- /crates/math/src/field/extensions/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cubic; 2 | pub mod quadratic; 3 | -------------------------------------------------------------------------------- /ensure-no_std/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | target = "wasm32-unknown-unknown" 3 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/short_weierstrass/curves/pallas/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod curve; 2 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/short_weierstrass/curves/vesta/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod curve; 2 | -------------------------------------------------------------------------------- /examples/schnorr-signature/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod common; 2 | pub mod schnorr_signature; 3 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/short_weierstrass/curves/grumpkin/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod curve; 2 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/short_weierstrass/curves/secp256k1/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod curve; 2 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/short_weierstrass/curves/secp256r1/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod curve; 2 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/short_weierstrass/curves/secq256k1/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod curve; 2 | -------------------------------------------------------------------------------- /crates/math/src/field/fields/mersenne31/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod extensions; 2 | pub mod field; 3 | -------------------------------------------------------------------------------- /crates/provers/plonk/src/constraint_system/examples/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod mimc; 2 | pub mod pow; 3 | -------------------------------------------------------------------------------- /crates/math/src/fft/gpu/cuda/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod ops; 2 | pub mod polynomial; 3 | pub mod state; 4 | -------------------------------------------------------------------------------- /crates/math/src/field/test_fields/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod u32_test_field; 2 | pub mod u64_test_field; 3 | -------------------------------------------------------------------------------- /crates/math/src/msm/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod naive; 2 | #[cfg(feature = "alloc")] 3 | pub mod pippenger; 4 | -------------------------------------------------------------------------------- /crates/provers/stark/src/proof/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod errors; 2 | pub mod options; 3 | pub mod stark; 4 | -------------------------------------------------------------------------------- /exercises/broken_heart/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod circuit; 2 | pub mod server; 3 | pub mod solution; 4 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/edwards/curves/bandersnatch/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod curve; 2 | pub mod field; 3 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:1.66 2 | 3 | WORKDIR /usr/src/elliptic-curves 4 | COPY . . 5 | 6 | CMD cargo test 7 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/edwards/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod curves; 2 | pub mod point; 3 | pub mod traits; 4 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/montgomery/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod curves; 2 | pub mod point; 3 | pub mod traits; 4 | -------------------------------------------------------------------------------- /examples/pohlig-hellman-attack/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod chinese_remainder_theorem; 2 | pub mod pohlig_hellman; 3 | -------------------------------------------------------------------------------- /exercises/blind_trust/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod circuit; 2 | pub mod sith_generate_proof; 3 | pub mod solution; 4 | -------------------------------------------------------------------------------- /crates/provers/stark/src/constraints/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod boundary; 2 | pub mod evaluator; 3 | pub mod transition; 4 | -------------------------------------------------------------------------------- /exercises/blind_trust/proof: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdaclass/lambdaworks/HEAD/exercises/blind_trust/proof -------------------------------------------------------------------------------- /exercises/blind_trust/srs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdaclass/lambdaworks/HEAD/exercises/blind_trust/srs -------------------------------------------------------------------------------- /crates/crypto/src/hash/poseidon/starknet/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod parameters; 2 | pub use parameters::PoseidonCairoStark252; 3 | -------------------------------------------------------------------------------- /exercises/challenge_2/srs.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdaclass/lambdaworks/HEAD/exercises/challenge_2/srs.bin -------------------------------------------------------------------------------- /exercises/challenge_3/srs.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdaclass/lambdaworks/HEAD/exercises/challenge_3/srs.bin -------------------------------------------------------------------------------- /crates/provers/groth16/circom-adapter/tests/vitalik_example/witness.json: -------------------------------------------------------------------------------- 1 | [ 2 | "1", 3 | "35", 4 | "3", 5 | "9" 6 | ] -------------------------------------------------------------------------------- /examples/prove-verify-circom/input_files/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "in": 3, 3 | "k": 12331548239589023489032859403859043 4 | } 5 | -------------------------------------------------------------------------------- /crates/math/src/circle/errors.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub enum CircleError { 3 | PointDoesntSatisfyCircleEquation, 4 | } 5 | -------------------------------------------------------------------------------- /crates/provers/winterfell_adapter/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod adapter; 2 | pub mod examples; 3 | pub mod field_element; 4 | pub mod utils; 5 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/edwards/curves/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bandersnatch; 2 | pub mod ed448_goldilocks; 3 | pub mod tiny_jub_jub; 4 | -------------------------------------------------------------------------------- /crates/provers/winterfell_adapter/src/field_element/mod.rs: -------------------------------------------------------------------------------- 1 | #[allow(clippy::op_ref)] 2 | pub mod element; 3 | pub mod positive_integer; 4 | -------------------------------------------------------------------------------- /crates/provers/plonk/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod constraint_system; 2 | pub mod prover; 3 | pub mod setup; 4 | pub mod test_utils; 5 | pub mod verifier; 6 | -------------------------------------------------------------------------------- /crates/math/src/circle/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cfft; 2 | pub mod cosets; 3 | pub mod errors; 4 | pub mod point; 5 | pub mod polynomial; 6 | pub mod twiddles; 7 | -------------------------------------------------------------------------------- /crates/provers/winterfell_adapter/src/examples/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cubic; 2 | pub mod fibonacci_2_terms; 3 | pub mod fibonacci_rap; 4 | pub mod miden_vm; 5 | -------------------------------------------------------------------------------- /crates/math/benches/polynomials/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod dense_multilinear_poly; 2 | pub mod polynomial; 3 | pub mod sparse_multilinear_poly; 4 | pub mod utils; 5 | -------------------------------------------------------------------------------- /docs/src/starks/stone_prover/images/mem_pool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdaclass/lambdaworks/HEAD/docs/src/starks/stone_prover/images/mem_pool.png -------------------------------------------------------------------------------- /crates/math/benches/elliptic_curves/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bls12_377; 2 | pub mod bls12_381; 3 | pub mod bn_254; 4 | pub mod iai_bls12_377; 5 | pub mod iai_bls12_381; 6 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/short_weierstrass/curves/bls12_377/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod curve; 2 | pub mod field_extension; 3 | pub mod pairing; 4 | pub mod twist; 5 | -------------------------------------------------------------------------------- /docs/src/starks/stone_prover/images/main_trace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdaclass/lambdaworks/HEAD/docs/src/starks/stone_prover/images/main_trace.png -------------------------------------------------------------------------------- /crates/crypto/src/fiat_shamir/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod default_transcript; 2 | pub mod is_transcript; 3 | #[cfg(feature = "test_fiat_shamir")] 4 | pub mod test_transcript; 5 | -------------------------------------------------------------------------------- /crates/crypto/src/hash/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod hash_to_field; 2 | pub mod monolith; 3 | pub mod pedersen; 4 | pub mod poseidon; 5 | pub mod rescue_prime; 6 | pub mod sha3; 7 | -------------------------------------------------------------------------------- /docs/src/starks/stone_prover/introduction.md: -------------------------------------------------------------------------------- 1 | # Stone prover documentation 2 | This section is a reference to the information gathered regarding Starkware's Stone prover. -------------------------------------------------------------------------------- /.rusty-hook.toml: -------------------------------------------------------------------------------- 1 | [hooks] 2 | pre-commit = "cargo test && cargo clippy --all-targets -- -D warnings && cargo fmt --all -- --check" 3 | 4 | [logging] 5 | verbose = true 6 | -------------------------------------------------------------------------------- /crates/provers/plonk/src/constraint_system/errors.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, PartialEq, Eq)] 2 | pub enum SolverError { 3 | InconsistentSystem, 4 | UnableToSolve, 5 | } 6 | -------------------------------------------------------------------------------- /docs/src/starks/stone_prover/images/interaction_trace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdaclass/lambdaworks/HEAD/docs/src/starks/stone_prover/images/interaction_trace.png -------------------------------------------------------------------------------- /examples/pinocchio/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod common; 2 | pub mod prover; 3 | pub mod qap; 4 | pub mod r1cs; 5 | pub mod setup; 6 | pub mod test_utils; 7 | pub mod verifier; 8 | -------------------------------------------------------------------------------- /crates/crypto/src/merkle_tree/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod backends; 2 | pub mod merkle; 3 | pub mod proof; 4 | #[cfg(test)] 5 | pub mod test_merkle; 6 | pub mod traits; 7 | mod utils; 8 | -------------------------------------------------------------------------------- /exercises/challenge_1/src/solver.rs: -------------------------------------------------------------------------------- 1 | use crate::field::ChallengeElement; 2 | 3 | pub fn solve() -> ChallengeElement { 4 | println!("Solving..."); 5 | todo!(); 6 | } 7 | -------------------------------------------------------------------------------- /crates/crypto/src/commitments/test_srs/srs_3_g1_elements.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lambdaclass/lambdaworks/HEAD/crates/crypto/src/commitments/test_srs/srs_3_g1_elements.bin -------------------------------------------------------------------------------- /crates/math/src/fft/cpu/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bit_reversing; 2 | pub mod fft; 3 | #[cfg(feature = "alloc")] 4 | pub mod ops; 5 | #[cfg(feature = "alloc")] 6 | pub mod roots_of_unity; 7 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import {} }: 2 | pkgs.mkShell { 3 | name = "cuda-env-shell"; 4 | buildInputs = with pkgs; [ 5 | git curl cargo rustc 6 | ]; 7 | } 8 | -------------------------------------------------------------------------------- /docs/src/plonk/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Lambdaworks Plonk Prover 2 | 3 | - [Recap](./recap.md) 4 | - [Protocol](./protocol.md) 5 | - [Implementation](./implementation.md) 6 | - [Circuit API](./constraint_system.md) -------------------------------------------------------------------------------- /crates/crypto/src/merkle_tree/backends/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod field_element; 2 | pub mod field_element_vector; 3 | /// Configurations for merkle trees 4 | /// Setting generics to some value 5 | pub mod types; 6 | -------------------------------------------------------------------------------- /crates/math/src/fft/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod cpu; 2 | pub mod errors; 3 | pub mod gpu; 4 | #[cfg(feature = "alloc")] 5 | pub mod polynomial; 6 | 7 | #[cfg(all(test, feature = "alloc"))] 8 | pub(crate) mod test_helpers; 9 | -------------------------------------------------------------------------------- /crates/math/benches/fields/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod baby_bear; 2 | pub mod binary; 3 | pub mod mersenne31; 4 | pub mod mersenne31_montgomery; 5 | pub mod stark252; 6 | pub mod u64_goldilocks; 7 | pub mod u64_goldilocks_montgomery; 8 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/short_weierstrass/curves/bn_254/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod compression; 2 | pub mod curve; 3 | pub mod default_types; 4 | pub mod field_extension; 5 | pub mod pairing; 6 | pub mod sqrt; 7 | pub mod twist; 8 | -------------------------------------------------------------------------------- /examples/baby-snark/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "u": [ 3 | [1, 3, 2, 4, 5], 4 | [-1, -2, 3, 4, -2], 5 | [1, 2, 3, 2, 2], 6 | [-3, -2, 0, 0, 0], 7 | [0, 9, 2, -1, 3] 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod edwards; 2 | pub mod montgomery; 3 | /// Implementation of ProjectivePoint, a generic projective point in a curve. 4 | pub mod point; 5 | pub mod short_weierstrass; 6 | pub mod traits; 7 | -------------------------------------------------------------------------------- /crates/provers/stark/src/proof/errors.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub enum InsecureOptionError { 3 | /// Field Size is not big enough 4 | FieldSize, 5 | /// Number of security bits is not enough 6 | LowSecurityBits, 7 | } 8 | -------------------------------------------------------------------------------- /crates/provers/sumcheck/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lambdaworks-sumcheck" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | 7 | [dependencies] 8 | lambdaworks-math.workspace = true 9 | lambdaworks-crypto.workspace = true 10 | -------------------------------------------------------------------------------- /exercises/challenge_1/src/field.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_math::field::{ 2 | element::FieldElement, fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, 3 | }; 4 | 5 | pub type ChallengeElement = FieldElement; 6 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/short_weierstrass/mod.rs: -------------------------------------------------------------------------------- 1 | /// Implementation of particular cases of elliptic curves. 2 | pub mod curves; 3 | /// Structs for points 4 | pub mod point; 5 | /// Common behaviour for Elliptic curves. 6 | pub mod traits; 7 | -------------------------------------------------------------------------------- /crates/math/benches/utils/mod.rs: -------------------------------------------------------------------------------- 1 | // Some of this modules are specific to a group of benchmarks, and so trigger warnings 2 | #![allow(dead_code)] 3 | pub mod fft_functions; 4 | pub mod stark252_utils; 5 | pub mod u64_goldilocks_utils; 6 | pub mod u64_utils; 7 | -------------------------------------------------------------------------------- /crates/math/src/field/errors.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug)] 2 | pub enum FieldError { 3 | DivisionByZero, 4 | /// Returns order of the calculated root of unity 5 | RootOfUnityError(u64), 6 | /// Can't calculate inverse of zero 7 | InvZeroError, 8 | } 9 | -------------------------------------------------------------------------------- /crates/math/src/unsigned_integer/mod.rs: -------------------------------------------------------------------------------- 1 | // By removing refs as clippy wants 2 | // Implementations with all the combination of reference and not references become recursive 3 | #[allow(clippy::op_ref)] 4 | pub mod element; 5 | pub mod montgomery; 6 | pub mod traits; 7 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod compression; 2 | pub mod curve; 3 | pub mod default_types; 4 | pub mod field_extension; 5 | pub mod sqrt; 6 | pub mod twist; 7 | 8 | #[cfg(feature = "alloc")] 9 | pub mod pairing; 10 | -------------------------------------------------------------------------------- /docs/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["Javier Chatruc", "Estéfano Bargas", "Mauro Toscano", "Diego Kingston", "Sergio Chouhy", "Agustín Garassino", "Mariano Nicolini"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "docs" 7 | 8 | [preprocessor.katex] 9 | -------------------------------------------------------------------------------- /crates/provers/plonk/src/test_utils/mod.rs: -------------------------------------------------------------------------------- 1 | /// A test circuit 2 | pub mod circuit_1; 3 | /// A test circuit 4 | pub mod circuit_2; 5 | /// Deserialize json to generate test circuits 6 | pub mod circuit_json; 7 | /// Useful tools to test plonk over different circuits 8 | pub mod utils; 9 | -------------------------------------------------------------------------------- /examples/pohlig-hellman-attack/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pohlig-hellman-attack" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | 8 | 9 | [dependencies] 10 | lambdaworks-math = { workspace = true } 11 | -------------------------------------------------------------------------------- /examples/baby-snark/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod common; 2 | pub mod scs; 3 | pub mod ssp; 4 | pub mod utils; 5 | 6 | mod prover; 7 | mod setup; 8 | mod verifier; 9 | 10 | pub use prover::{Proof, Prover}; 11 | pub use setup::{setup, ProvingKey, VerifyingKey}; 12 | pub use verifier::verify; 13 | -------------------------------------------------------------------------------- /crates/crypto/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::op_ref)] 2 | #![cfg_attr(not(feature = "std"), no_std)] 3 | #[macro_use] 4 | extern crate alloc; 5 | 6 | pub mod commitments; 7 | #[cfg(feature = "std")] 8 | pub mod errors; 9 | pub mod fiat_shamir; 10 | pub mod hash; 11 | pub mod merkle_tree; 12 | -------------------------------------------------------------------------------- /crates/provers/groth16/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod common; 2 | pub mod qap; 3 | pub mod r1cs; 4 | 5 | mod prover; 6 | mod setup; 7 | mod verifier; 8 | 9 | pub use prover::{Proof, Prover}; 10 | pub use qap::QuadraticArithmeticProgram; 11 | pub use r1cs::*; 12 | pub use setup::*; 13 | pub use verifier::verify; 14 | -------------------------------------------------------------------------------- /docs/src/starks/starks.md: -------------------------------------------------------------------------------- 1 | # STARK Prover 2 | 3 | The goal of this document is to give a good a understanding of our stark prover code. To this end, in the first section we go through a recap of how the proving system works at a high level mathematically; then we dive into how that's actually implemented in our code. 4 | -------------------------------------------------------------------------------- /exercises/README.md: -------------------------------------------------------------------------------- 1 | # Lambdaworks Exercises & Challenges 2 | 3 | Contains several examples and challenges to use Lambdaworks. 4 | 5 | Challenges 1, 2 and 3 appeared in [Ingonyama's CTF event](https://ingonyama.ctfd.io/) 6 | 7 | Challenges message, blind_trust and broken heart appeared in the first LambdaIngo ZK CTF 8 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/short_weierstrass/curves/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bls12_377; 2 | pub mod bls12_381; 3 | pub mod bn_254; 4 | pub mod grumpkin; 5 | pub mod pallas; 6 | pub mod secp256k1; 7 | pub mod secp256r1; 8 | pub mod secq256k1; 9 | pub mod stark_curve; 10 | pub mod test_curve_1; 11 | pub mod test_curve_2; 12 | pub mod vesta; 13 | -------------------------------------------------------------------------------- /examples/prove-verify-circom/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # Lambdaworks Circom Proving & Verification Example 4 | 5 | This programs converts Circom & SnarkJS generated constraints and witnesses into Lambdaworks-compatible instances, performs trusted setup, generates proof, and finally verifies the integrity of witness assignments. 6 | -------------------------------------------------------------------------------- /crates/provers/stark/src/examples/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod bit_flags; 2 | pub mod dummy_air; 3 | pub mod fibonacci_2_cols_shifted; 4 | pub mod fibonacci_2_columns; 5 | pub mod fibonacci_rap; 6 | pub mod quadratic_air; 7 | pub mod read_only_memory; 8 | pub mod read_only_memory_logup; 9 | pub mod simple_fibonacci; 10 | pub mod simple_periodic_cols; 11 | -------------------------------------------------------------------------------- /examples/pinocchio/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "pinocchio" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | 8 | [dependencies] 9 | lambdaworks-math = { workspace = true } 10 | lambdaworks-crypto = { workspace = true } 11 | rand_chacha = "0.3.1" 12 | rand = "0.8.5" -------------------------------------------------------------------------------- /exercises/challenge_1/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "block_cypher" 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 | lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks.git" } 10 | rand = "0.8.5" 11 | -------------------------------------------------------------------------------- /docs/src/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | This site hosts the main documentation for Lambdaworks as a whole. It is still a work in progress. 4 | 5 | ## Crates 6 | 7 | - [lambdaworks-math](https://crates.io/crates/lambdaworks-math) 8 | - [lambdaworks-crypto](https://crates.io/crates/lambdaworks-crypto) 9 | - [lambdaworks-gpu](https://crates.io/crates/lambdaworks-gpu) 10 | -------------------------------------------------------------------------------- /examples/prove-verify-circom/input_files/test.circom: -------------------------------------------------------------------------------- 1 | pragma circom 2.0.0; 2 | 3 | include "circomlib/mimc.circom"; 4 | 5 | template Test() { 6 | signal input in; 7 | signal input k; 8 | 9 | signal output out; 10 | 11 | component hash = MiMC7(10); 12 | 13 | hash.x_in <== in; 14 | hash.k <== k; 15 | 16 | out <== hash.out; 17 | } 18 | 19 | component main = Test(); 20 | -------------------------------------------------------------------------------- /exercises/challenge_1/src/main.rs: -------------------------------------------------------------------------------- 1 | use data::pairs; 2 | use solver::solve; 3 | 4 | use crate::cypher::evaluate; 5 | 6 | mod cypher; 7 | mod data; 8 | mod field; 9 | mod solver; 10 | 11 | fn main() { 12 | let key = solve(); 13 | 14 | let (p, c) = pairs()[0].clone(); 15 | assert_eq!(evaluate(&p, &key), c); 16 | 17 | println!("Found Key! {}", &key); 18 | } 19 | -------------------------------------------------------------------------------- /examples/prove-miden/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # Lambdaworks Polygon Miden Proving example 4 | 5 | This programs compiles and executes a miden fibonacci programs, obtains the trace, and then proves it and verifies it with lambdaworks Stark Platinum Prover. 6 | 7 | Special thanks to Polygon Miden team for providing the open source VM used here, the prover, and documenting the project. 8 | 9 | -------------------------------------------------------------------------------- /crates/crypto/src/fiat_shamir/README.md: -------------------------------------------------------------------------------- 1 | # Fiat-Shamir 2 | 3 | This contains the basic functionality to implement the [Fiat-Shamir heuristic](https://en.wikipedia.org/wiki/Fiat%E2%80%93Shamir_heuristic) ([see also](https://link.springer.com/chapter/10.1007/3-540-47721-7_12)). 4 | 5 | The transcript should be able to accept bytes or field elements and should output random challenges (field elements) from a uniform distribution. -------------------------------------------------------------------------------- /crates/crypto/src/hash/rescue_prime/mod.rs: -------------------------------------------------------------------------------- 1 | mod parameters; 2 | mod rescue_prime_optimized; 3 | mod utils; 4 | 5 | pub use rescue_prime_optimized::MdsMethod; 6 | pub use rescue_prime_optimized::RescuePrimeOptimized; 7 | 8 | use lambdaworks_math::field::element::FieldElement; 9 | use lambdaworks_math::field::fields::u64_goldilocks_field::Goldilocks64Field; 10 | 11 | pub type Fp = FieldElement; 12 | -------------------------------------------------------------------------------- /crates/math/src/field/mod.rs: -------------------------------------------------------------------------------- 1 | /// Implementation of FieldElement, a generic element of a field. 2 | pub mod element; 3 | pub mod errors; 4 | /// Implementation of quadratic extensions of fields. 5 | pub mod extensions; 6 | /// Implementation of particular cases of fields. 7 | pub mod fields; 8 | /// Field for test purposes. 9 | pub mod test_fields; 10 | /// Common behaviour for field elements. 11 | pub mod traits; 12 | -------------------------------------------------------------------------------- /examples/schnorr-signature/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "schnorr-siganture" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | 8 | 9 | [dependencies] 10 | lambdaworks-math = { workspace = true } 11 | lambdaworks-crypto = { workspace = true } 12 | sha3 = { version = "0.10.8", default-features = false } 13 | rand = "0.8.5" 14 | rand_chacha = "0.3.1" 15 | -------------------------------------------------------------------------------- /exercises/challenge_1/src/cypher.rs: -------------------------------------------------------------------------------- 1 | use crate::field::ChallengeElement; 2 | 3 | const ROUNDS: usize = 2_usize.pow(24); 4 | 5 | pub fn evaluate(x: &ChallengeElement, key: &ChallengeElement) -> ChallengeElement { 6 | (0..ROUNDS).fold(x.clone(), |acc, _| evaluate_round(&acc, key)) 7 | } 8 | 9 | pub fn evaluate_round(x: &ChallengeElement, key: &ChallengeElement) -> ChallengeElement { 10 | (x + key).pow(2_u64) 11 | } 12 | -------------------------------------------------------------------------------- /fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["no_gpu_fuzz", "cuda_fuzz"] 3 | resolver = "2" 4 | 5 | [workspace.package] 6 | edition = "2021" 7 | publish = false 8 | version = "0.1.1" 9 | 10 | [workspace.dependencies] 11 | lambdaworks-math = { path = "../math" } 12 | lambdaworks-gpu = { path = "../gpu" } 13 | stark-platinum-prover = { path = "../provers/stark" } 14 | libfuzzer-sys = "0.4" 15 | 16 | [profile.release] 17 | debug = 1 18 | -------------------------------------------------------------------------------- /exercises/challenge_2/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "template_solution_srs_1" 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 | lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks", rev = "366ac95" } 10 | lambdaworks-math= { git = "https://github.com/lambdaclass/lambdaworks", rev = "366ac95" } 11 | -------------------------------------------------------------------------------- /examples/baby-snark/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "baby-snark" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | lambdaworks-math = { workspace = true } 12 | lambdaworks-crypto = { workspace = true } 13 | rand_chacha = "0.3.1" 14 | rand = "0.8.5" 15 | -------------------------------------------------------------------------------- /examples/rsa/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rsa" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | 8 | [features] 9 | default = ["alloc"] 10 | alloc = ["lambdaworks-math/alloc"] 11 | 12 | [dependencies] 13 | num-bigint = "0.4" 14 | num-traits = "0.2" 15 | num-integer = "0.1" 16 | rand = "0.8" 17 | lambdaworks-math = { workspace = true, features = ["alloc"] } 18 | hex = "0.4" 19 | -------------------------------------------------------------------------------- /fuzz/no_gpu_fuzz/fuzz_targets/deserialize_stark_proof.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | use libfuzzer_sys::fuzz_target; 3 | use stark_platinum_prover::proof::stark::StarkProof; 4 | use lambdaworks_math::field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField; 5 | use lambdaworks_math::traits::Deserializable; 6 | 7 | 8 | fuzz_target!(|data: Vec| { 9 | 10 | let _proof = StarkProof::::deserialize(&data); 11 | 12 | }); 13 | -------------------------------------------------------------------------------- /crates/math/src/gpu/cuda/shaders/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | /// Reverses the `log2(size)` first bits of `i` 5 | __device__ unsigned reverse_index(unsigned i, unsigned size) 6 | { 7 | if (size == 1) 8 | { // TODO: replace this statement with an alternative solution. 9 | return i; 10 | } 11 | else 12 | { 13 | return __brev(i) >> (__clz(size) + 1); 14 | } 15 | } 16 | 17 | #endif // UTILS_H 18 | -------------------------------------------------------------------------------- /crates/provers/stark/src/fri/fri_decommit.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_crypto::merkle_tree::proof::Proof; 2 | use lambdaworks_math::field::element::FieldElement; 3 | use lambdaworks_math::field::traits::IsField; 4 | 5 | use crate::config::Commitment; 6 | 7 | #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] 8 | pub struct FriDecommitment { 9 | pub layers_auth_paths: Vec>, 10 | pub layers_evaluations_sym: Vec>, 11 | } 12 | -------------------------------------------------------------------------------- /crates/math/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![cfg_attr(not(feature = "std"), no_std)] 2 | 3 | #[cfg(feature = "alloc")] 4 | extern crate alloc; 5 | 6 | pub mod circle; 7 | pub mod cyclic_group; 8 | pub mod elliptic_curve; 9 | pub mod errors; 10 | pub mod field; 11 | pub mod helpers; 12 | pub mod traits; 13 | pub mod unsigned_integer; 14 | 15 | pub mod gpu; 16 | 17 | // These modules don't work in no-std mode 18 | pub mod fft; 19 | pub mod msm; 20 | #[cfg(feature = "alloc")] 21 | pub mod polynomial; 22 | -------------------------------------------------------------------------------- /examples/shamir_secret_sharing/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "shamir_secret_sharing" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | 12 | lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks.git" } 13 | rand = { version = "0.8", features = [ "std", "std_rng" ] } 14 | -------------------------------------------------------------------------------- /crates/provers/groth16/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lambdaworks-groth16" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | lambdaworks-math.workspace = true 12 | lambdaworks-crypto.workspace = true 13 | rand_chacha = "0.3.1" 14 | serde = "1.0" 15 | serde_json = "1.0" 16 | rand = "0.8.5" 17 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/short_weierstrass/errors.rs: -------------------------------------------------------------------------------- 1 | use crate::errors::{ByteConversionError, DeserializationError}; 2 | 3 | impl From for DeserializationError { 4 | fn from(error: ByteConversionError) -> Self { 5 | match error { 6 | ByteConversionError::FromBEBytesError => DeserializationError::FieldFromBytesError, 7 | ByteConversionError::FromLEBytesError => DeserializationError::FieldFromBytesError, 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /crates/provers/groth16/circom-adapter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lambdaworks-circom-adapter" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | lambdaworks-math.workspace = true 12 | lambdaworks-groth16.workspace = true 13 | 14 | serde = { version = "1.0", features = ["derive"] } 15 | serde_json = "1" 16 | -------------------------------------------------------------------------------- /crates/math/src/gpu/cuda/shaders/fft/bitrev_permutation.cuh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../utils.h" 4 | 5 | template 6 | inline __device__ void _bitrev_permutation(const Fp *input, Fp *result, const int len) 7 | { 8 | unsigned thread_pos = blockDim.x * blockIdx.x + threadIdx.x; 9 | if (thread_pos >= len) return; 10 | // TODO: guard is not needed for inputs of len >=block_size * 2, if len is pow of two 11 | 12 | result[thread_pos] = input[reverse_index(thread_pos, len)]; 13 | }; 14 | -------------------------------------------------------------------------------- /ensure-no_std/src/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use core::panic::PanicInfo; 5 | 6 | #[no_mangle] 7 | pub extern "C" fn _start() -> ! { 8 | loop {} 9 | } 10 | 11 | /// This function is called on panic. 12 | #[panic_handler] 13 | fn panic(_info: &PanicInfo) -> ! { 14 | loop {} 15 | } 16 | 17 | #[global_allocator] 18 | static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; 19 | 20 | #[allow(unused_imports)] 21 | use lambdaworks_crypto; 22 | #[allow(unused_imports)] 23 | use lambdaworks_math; 24 | -------------------------------------------------------------------------------- /crates/provers/plonk/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lambdaworks-plonk" 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 | lambdaworks-math.workspace = true 10 | lambdaworks-crypto.workspace = true 11 | 12 | serde = { version = "1.0", features = ["derive"] } 13 | serde_json = "1.0" 14 | sha3 = { version = "0.10.8", default-features = false } 15 | sha2 = { version = "0.10", default-features = false } 16 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # TITLE 2 | 3 | ## Description 4 | 5 | Description of the pull request changes and motivation. 6 | 7 | ## Type of change 8 | 9 | Please delete options that are not relevant. 10 | 11 | - [ ] New feature 12 | - [ ] Bug fix 13 | - [ ] Optimization 14 | 15 | ## Checklist 16 | - [ ] Linked to Github Issue 17 | - [ ] Unit tests added 18 | - [ ] This change requires new documentation. 19 | - [ ] Documentation has been added/updated. 20 | - [ ] This change is an Optimization 21 | - [ ] Benchmarks added/run 22 | -------------------------------------------------------------------------------- /crates/provers/gkr/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lambdaworks-gkr-prover" 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 | lambdaworks-math = { workspace = true } 10 | lambdaworks-crypto = { workspace = true } 11 | lambdaworks-sumcheck = { workspace = true } 12 | thiserror = "1.0" 13 | blake2 = "0.10" 14 | sha3 = "0.10.8" 15 | digest = "0.10" 16 | 17 | 18 | [lib] 19 | name = "lambdaworks_gkr_prover" 20 | path = "src/lib.rs" 21 | -------------------------------------------------------------------------------- /ensure-no_std/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "ensure-no_std" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | 7 | [dependencies] 8 | lambdaworks-crypto = { path = "../crates/crypto", default-features = false, features = [ 9 | "serde", 10 | ] } 11 | lambdaworks-math = { path = "../crates/math", default-features = false, features = [ 12 | "alloc", 13 | "lambdaworks-serde-binary", 14 | "lambdaworks-serde-string", 15 | ] } 16 | 17 | wee_alloc = "0.4.5" 18 | 19 | [profile.dev] 20 | panic = "abort" 21 | 22 | [profile.release] 23 | panic = "abort" 24 | -------------------------------------------------------------------------------- /exercises/blind_trust/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "blind_trust" 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 | rand = "0.8.5" 10 | 11 | 12 | lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks", rev = "8fcd64f" } 13 | lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks", rev = "8fcd64f" } 14 | lambdaworks-plonk = { git = "https://github.com/lambdaclass/lambdaworks_plonk_prover", rev = "6e39865"} 15 | 16 | -------------------------------------------------------------------------------- /exercises/challenge_3/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "power" 3 | version = "1.0.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | json = "0.12" 8 | serde = { version = "1.0", features = ["derive"] } 9 | actix-web = "4.3" 10 | env_logger = "0.10" 11 | log = "0.4" 12 | rand = "0.8" 13 | serde_json = "1" 14 | tokio = { version = "1.24.2", features = ["sync"] } 15 | lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks", rev = "366ac95" } 16 | lambdaworks-math= { git = "https://github.com/lambdaclass/lambdaworks", rev = "366ac95" } 17 | serde_cbor = "0.10" 18 | -------------------------------------------------------------------------------- /examples/prove-verify-circom/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "prove-verify-circom" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | 8 | [[bin]] 9 | name = "prove-verify-circom" 10 | path = "src/main.rs" 11 | 12 | [dependencies] 13 | lambdaworks-crypto = { workspace = true } 14 | lambdaworks-groth16 = { workspace = true } 15 | lambdaworks-math = { workspace = true, features = ["lambdaworks-serde-string"] } 16 | lambdaworks-circom-adapter = { workspace = true } 17 | serde = { version = "1.0" } 18 | serde_json = "1" 19 | -------------------------------------------------------------------------------- /examples/merkle-tree-cli/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "merkle-tree-cli" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | 8 | [[bin]] 9 | name = "merkle-tree-cli" 10 | path = "src/main.rs" 11 | 12 | [dependencies] 13 | clap = { version = "4.4.6", features = ["derive"] } 14 | lambdaworks-crypto = { workspace = true, features = ["serde"] } 15 | lambdaworks-math = { workspace = true, features = ["lambdaworks-serde-string"] } 16 | serde = { version = "1.0" } 17 | serde_json = "1" 18 | bincode = { version = "2.0.1", features = ["serde"] } 19 | -------------------------------------------------------------------------------- /exercises/broken_heart/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "irreducibull" 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 | lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks", rev = "d8f14cb"} 10 | lambdaworks-crypto = { git = "https://github.com/lambdaclass/lambdaworks", rev = "d8f14cb"} 11 | # lambdaworks-plonk = { git = "https://github.com/lambdaclass/lambdaworks_plonk_prover", rev="07e36bf"} 12 | lambdaworks-plonk = { path = "path/to/local/lambdaworks_plonk_prover"} 13 | -------------------------------------------------------------------------------- /crates/math/src/unsigned_integer/traits.rs: -------------------------------------------------------------------------------- 1 | use core::{ 2 | fmt::{Display, LowerHex, UpperHex}, 3 | ops::{Add, BitAnd, Shr, ShrAssign}, 4 | }; 5 | 6 | pub trait IsUnsignedInteger: 7 | Shr 8 | + ShrAssign 9 | + BitAnd 10 | + Eq 11 | + Ord 12 | + From 13 | + Copy 14 | + Display 15 | + LowerHex 16 | + UpperHex 17 | + Add 18 | { 19 | } 20 | 21 | impl IsUnsignedInteger for u128 {} 22 | impl IsUnsignedInteger for u64 {} 23 | impl IsUnsignedInteger for u32 {} 24 | impl IsUnsignedInteger for u16 {} 25 | impl IsUnsignedInteger for usize {} 26 | -------------------------------------------------------------------------------- /docs/src/starks/implementation.md: -------------------------------------------------------------------------------- 1 | # STARKs Prover Lambdaworks Implementation 2 | 3 | The goal of this section will be to go over the details of the implementation of the proving system. To this end, we will follow the flow the example in the `recap` chapter, diving deeper into the code when necessary and explaining how it fits into a more general case. 4 | 5 | This implementation couldn't be done without checking Facebook's [Winterfell](https://github.com/facebook/winterfell) and Max Gillett's [Giza](https://github.com/maxgillett/giza). We want to thank everyone involved in them, along with Shahar Papini and Lior Goldberg from Starkware who also provided us valuable insight. 6 | -------------------------------------------------------------------------------- /crates/crypto/src/fiat_shamir/test_transcript.rs: -------------------------------------------------------------------------------- 1 | use super::transcript::Transcript; 2 | 3 | /// This transcript will ALWAYS return the exact same value every time it's called. 4 | /// It is meant for testing only, never use this in production. 5 | pub struct TestTranscript; 6 | 7 | impl Transcript for TestTranscript { 8 | fn append(&mut self, _new_data: &[u8]) {} 9 | 10 | fn challenge(&mut self) -> [u8; 32] { 11 | [1; 32] 12 | } 13 | } 14 | 15 | impl Default for TestTranscript { 16 | fn default() -> Self { 17 | Self::new() 18 | } 19 | } 20 | 21 | impl TestTranscript { 22 | pub fn new() -> Self { 23 | Self {} 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/baby-snark/src/utils.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Neg; 2 | 3 | use crate::common::FrElement; 4 | 5 | pub fn i64_to_field(element: &i64) -> FrElement { 6 | let mut fr_element = FrElement::from(element.unsigned_abs()); 7 | if element.is_negative() { 8 | fr_element = fr_element.neg() 9 | } 10 | 11 | fr_element 12 | } 13 | 14 | pub fn i64_vec_to_field(elements: &[i64]) -> Vec { 15 | elements.iter().map(i64_to_field).collect() 16 | } 17 | 18 | pub fn i64_matrix_to_field(elements: &[&[i64]]) -> Vec> { 19 | let mut matrix = Vec::new(); 20 | for f in elements { 21 | matrix.push(i64_vec_to_field(f)); 22 | } 23 | matrix 24 | } 25 | -------------------------------------------------------------------------------- /fuzz/cuda_fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cuda_fuzz" 3 | version.workspace = true 4 | edition.workspace = true 5 | 6 | [package.metadata] 7 | cargo-fuzz = true 8 | 9 | [dependencies] 10 | lambdaworks-math = { workspace = true, features = ["cuda"] } 11 | lambdaworks-gpu = { workspace = true, features = ["cuda"] } 12 | honggfuzz = "0.5.55" 13 | 14 | [[bin]] 15 | name = "cuda_fft_fuzzer" 16 | path = "src/cuda_fft_fuzzer.rs" 17 | 18 | [[bin]] 19 | name = "polynomial_fft_diff" 20 | path = "src/polynomial_fft_diff.rs" 21 | test = false 22 | doc = false 23 | 24 | [[bin]] 25 | name = "twiddles_generation_diff" 26 | path = "src/twiddles_generation_diff.rs" 27 | test = false 28 | doc = false 29 | 30 | -------------------------------------------------------------------------------- /crates/provers/groth16/arkworks-adapter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "arkworks_adapter" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | lambdaworks-math.workspace = true 12 | lambdaworks-groth16.workspace = true 13 | ark-r1cs-std = { version = "0.4.0" } 14 | ark-bls12-381 = { version = "0.4.0" } 15 | ark-ff = { version = "0.4.2" } 16 | ark-relations = { version = "0.4.0" } 17 | ark-serialize = { version = "0.4.2" } 18 | num-bigint = { version = "0.4", default-features = false } 19 | rand = "0.8.5" 20 | -------------------------------------------------------------------------------- /crates/math/benches/criterion_polynomial.rs: -------------------------------------------------------------------------------- 1 | mod polynomials; 2 | use criterion::{criterion_group, criterion_main, Criterion}; 3 | use polynomials::{ 4 | dense_multilinear_poly::dense_multilinear_polynomial_benchmarks, 5 | polynomial::polynomial_benchmarks, 6 | sparse_multilinear_poly::sparse_multilinear_polynomial_benchmarks, 7 | }; 8 | use pprof::criterion::{Output, PProfProfiler}; 9 | 10 | criterion_group!( 11 | name = polynomial; 12 | config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); 13 | targets = polynomial_benchmarks, dense_multilinear_polynomial_benchmarks, sparse_multilinear_polynomial_benchmarks); 14 | criterion_main!(polynomial); 15 | -------------------------------------------------------------------------------- /crates/math/src/field/fields/vesta_field.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | field::fields::montgomery_backed_prime_fields::{IsModulus, MontgomeryBackendPrimeField}, 3 | unsigned_integer::element::U256, 4 | }; 5 | 6 | type VestaMontgomeryBackendPrimeField = MontgomeryBackendPrimeField; 7 | 8 | #[derive(Debug, Clone, PartialEq, Eq)] 9 | pub struct MontgomeryConfigVesta255PrimeField; 10 | impl IsModulus for MontgomeryConfigVesta255PrimeField { 11 | const MODULUS: U256 = U256::from_hex_unchecked( 12 | "0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001", 13 | ); 14 | } 15 | 16 | pub type Vesta255PrimeField = VestaMontgomeryBackendPrimeField; 17 | -------------------------------------------------------------------------------- /crates/math/benches/criterion_elliptic_curve.rs: -------------------------------------------------------------------------------- 1 | use criterion::{criterion_group, criterion_main, Criterion}; 2 | use pprof::criterion::{Output, PProfProfiler}; 3 | 4 | mod elliptic_curves; 5 | use elliptic_curves::{ 6 | bls12_377::bls12_377_elliptic_curve_benchmarks, bls12_381::bls12_381_elliptic_curve_benchmarks, 7 | bn_254::bn_254_elliptic_curve_benchmarks, 8 | }; 9 | 10 | criterion_group!( 11 | name = elliptic_curve_benches; 12 | config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); 13 | targets = bn_254_elliptic_curve_benchmarks, bls12_377_elliptic_curve_benchmarks, bls12_381_elliptic_curve_benchmarks 14 | ); 15 | criterion_main!(elliptic_curve_benches); 16 | -------------------------------------------------------------------------------- /crates/math/src/field/fields/pallas_field.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | field::fields::montgomery_backed_prime_fields::{IsModulus, MontgomeryBackendPrimeField}, 3 | unsigned_integer::element::U256, 4 | }; 5 | 6 | type PallasMontgomeryBackendPrimeField = MontgomeryBackendPrimeField; 7 | 8 | #[derive(Debug, Clone, PartialEq, Eq)] 9 | pub struct MontgomeryConfigPallas255PrimeField; 10 | impl IsModulus for MontgomeryConfigPallas255PrimeField { 11 | const MODULUS: U256 = U256::from_hex_unchecked( 12 | "40000000000000000000000000000000224698fc094cf91b992d30ed00000001", 13 | ); 14 | } 15 | 16 | pub type Pallas255PrimeField = 17 | PallasMontgomeryBackendPrimeField; 18 | -------------------------------------------------------------------------------- /crates/math/src/field/fields/secp256k1_field.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | field::fields::montgomery_backed_prime_fields::{IsModulus, MontgomeryBackendPrimeField}, 3 | unsigned_integer::element::U256, 4 | }; 5 | 6 | type Secp256k1MontgomeryBackendPrimeField = MontgomeryBackendPrimeField; 7 | 8 | #[derive(Debug, Clone, PartialEq, Eq)] 9 | pub struct MontgomeryConfigSecp256k1PrimeField; 10 | impl IsModulus for MontgomeryConfigSecp256k1PrimeField { 11 | const MODULUS: U256 = U256::from_hex_unchecked( 12 | "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 13 | ); 14 | } 15 | 16 | pub type Secp256k1PrimeField = 17 | Secp256k1MontgomeryBackendPrimeField; 18 | -------------------------------------------------------------------------------- /crates/math/src/field/fields/secp256r1_field.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | field::fields::montgomery_backed_prime_fields::{IsModulus, MontgomeryBackendPrimeField}, 3 | unsigned_integer::element::U256, 4 | }; 5 | 6 | type Secp256r1MontgomeryBackendPrimeField = MontgomeryBackendPrimeField; 7 | 8 | #[derive(Debug, Clone, PartialEq, Eq)] 9 | pub struct MontgomeryConfigSecp256r1PrimeField; 10 | impl IsModulus for MontgomeryConfigSecp256r1PrimeField { 11 | const MODULUS: U256 = U256::from_hex_unchecked( 12 | "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff", 13 | ); 14 | } 15 | 16 | pub type Secp256r1PrimeField = 17 | Secp256r1MontgomeryBackendPrimeField; 18 | -------------------------------------------------------------------------------- /crates/provers/stark/src/lib.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_math::field::{ 2 | element::FieldElement, fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, 3 | }; 4 | 5 | pub mod constraints; 6 | pub mod context; 7 | pub mod debug; 8 | pub mod domain; 9 | pub mod examples; 10 | pub mod frame; 11 | pub mod fri; 12 | pub mod grinding; 13 | pub mod proof; 14 | pub mod prover; 15 | pub mod table; 16 | pub mod trace; 17 | pub mod traits; 18 | pub mod transcript; 19 | pub mod utils; 20 | pub mod verifier; 21 | 22 | #[cfg(test)] 23 | pub mod tests; 24 | 25 | /// Configurations of the Prover available in compile time 26 | pub mod config; 27 | 28 | pub type PrimeField = Stark252PrimeField; 29 | pub type Felt252 = FieldElement; 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | **/target/** 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | **/proptest-regressions 13 | /output.txt 14 | flamegraph.svg 15 | proving_system/stark/src/cairo_run/program.memory 16 | proving_system/stark/src/cairo_run/program.trace 17 | 18 | **/*.metallib 19 | **/*.ptx 20 | 21 | **/.DS_Store 22 | 23 | ensure-no_std/target 24 | # Files from fuzzers are inside a corpus folder 25 | **/corpus/** 26 | **/artifacts/** 27 | /.idea/ 28 | 29 | -------------------------------------------------------------------------------- /crates/math/src/field/fields/secp256k1_scalarfield.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | field::fields::montgomery_backed_prime_fields::{IsModulus, MontgomeryBackendPrimeField}, 3 | unsigned_integer::element::U256, 4 | }; 5 | 6 | type Secp256k1MontgomeryBackendScalarField = MontgomeryBackendPrimeField; 7 | 8 | #[derive(Debug, Clone, PartialEq, Eq)] 9 | pub struct MontgomeryConfigSecp256k1ScalarField; 10 | impl IsModulus for MontgomeryConfigSecp256k1ScalarField { 11 | const MODULUS: U256 = U256::from_hex_unchecked( 12 | "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 13 | ); 14 | } 15 | 16 | pub type Secp256k1ScalarField = 17 | Secp256k1MontgomeryBackendScalarField; 18 | -------------------------------------------------------------------------------- /crates/math/benches/iai_elliptic_curve.rs: -------------------------------------------------------------------------------- 1 | mod elliptic_curves; 2 | 3 | use elliptic_curves::{iai_bls12_377::*, iai_bls12_381::*}; 4 | 5 | iai_callgrind::main!( 6 | callgrind_args = "toggle-collect=util::*"; 7 | functions = bls12_381_operate_with_g1, 8 | bls12_381_operate_with_g2, 9 | bls12_381_operate_with_self_g1, 10 | bls12_381_operate_with_self_g2, 11 | bls12_381_double_g1, 12 | bls12_381_double_g2, 13 | bls12_381_neg_g1, 14 | bls12_381_neg_g2, 15 | bls12_381_compress_g1, 16 | bls12_381_decompress_g1, 17 | bls12_381_subgroup_check_g1, 18 | bls12_381_ate_pairing, 19 | bls12_377_operate_with_g1, 20 | bls12_377_operate_with_self_g1, 21 | bls12_377_double_g1, 22 | bls12_377_neg_g1, 23 | ); 24 | -------------------------------------------------------------------------------- /examples/baby-snark/src/scs.rs: -------------------------------------------------------------------------------- 1 | use crate::common::FrElement; 2 | 3 | pub type Constraint = Vec; 4 | 5 | #[derive(Clone, Debug, PartialEq, Eq)] 6 | pub struct SquareConstraintSystem { 7 | pub constraints: Vec, 8 | pub number_of_public_inputs: usize, 9 | } 10 | 11 | impl SquareConstraintSystem { 12 | pub fn from_matrix(matrix: Vec>, number_of_public_inputs: usize) -> Self { 13 | Self { 14 | constraints: matrix, 15 | number_of_public_inputs, 16 | } 17 | } 18 | 19 | pub fn number_of_constraints(&self) -> usize { 20 | self.constraints.len() 21 | } 22 | 23 | pub fn input_size(&self) -> usize { 24 | self.constraints[0].len() 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /crates/crypto/src/hash/README.md: -------------------------------------------------------------------------------- 1 | # Hash functions 2 | 3 | This folder contains hash functions that are typically used in non-interactive proof systems. The hash functions we have implemented are: 4 | - [Monolith](./monolith/mod.rs) 5 | - [Poseidon](./poseidon/) 6 | - [Pedersen](./pedersen/) 7 | - [Rescue Prime](./rescue_prime/) 8 | 9 | Pedersen is based on elliptic curves, while [Monolith](https://eprint.iacr.org/2023/1025), [Poseidon](https://eprint.iacr.org/2019/458.pdf) and [Rescue Prime](https://eprint.iacr.org/2020/1143) are algebraic hash functions. 10 | 11 | For an introduction to hash functions, see [this intro](https://blog.alignedlayer.com/introduction-hash-functions-in-cryptography/) and [its follow-up](https://blog.alignedlayer.com/design-strategies-how-to-construct-a-hashing-mode-2/). -------------------------------------------------------------------------------- /docs/src/plonk/plonk.md: -------------------------------------------------------------------------------- 1 | # PLONK 2 | 3 | In this document, we present an in-depth analysis of PLONK and the specific version that has been implemented in Lambdaworks. Additionally, we provide a step-by-step guide on how to utilize our high-level API, which is designed to simplify the user experience. 4 | 5 | Our version of PLONK is heavily inspired by [gnark](https://github.com/ConsenSys/gnark). We would like to take this opportunity to express our gratitude to ConsenSys for generously sharing their source code with the community. 6 | 7 | We have written this document with the aim of making it accessible to both novice and advanced users. So, whether you're a newcomer to PLONK or an experienced user, you will find this document to be a valuable resource. 8 | 9 | - [Recap](./recap.md) 10 | - [Protocol](./protocol.md) 11 | - [Implementation](./implementation.md) -------------------------------------------------------------------------------- /crates/provers/stark/src/config.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_crypto::merkle_tree::{ 2 | backends::types::{BatchKeccak256Backend, Keccak256Backend}, 3 | merkle::MerkleTree, 4 | }; 5 | 6 | // Merkle Trees configuration 7 | 8 | // Security of both hashes should match 9 | 10 | pub type FriMerkleTreeBackend = Keccak256Backend; 11 | pub type FriMerkleTree = MerkleTree>; 12 | 13 | // If using hashes with 256-bit security, commitment size should be 32 14 | // If using hashes with 512-bit security, commitment size should be 64 15 | // TODO: Commitment type should be obtained from MerkleTrees 16 | pub const COMMITMENT_SIZE: usize = 32; 17 | pub type Commitment = [u8; COMMITMENT_SIZE]; 18 | 19 | pub type BatchedMerkleTreeBackend = BatchKeccak256Backend; 20 | pub type BatchedMerkleTree = MerkleTree>; 21 | -------------------------------------------------------------------------------- /crates/gpu/src/cuda/abstractions/errors.rs: -------------------------------------------------------------------------------- 1 | use thiserror::Error; 2 | 3 | #[derive(Debug, Error)] 4 | pub enum CudaError { 5 | #[error("The order of polynomial + 1 should a be power of 2. Got: {0}")] 6 | InvalidOrder(usize), 7 | #[error("Couldn't load compiled PTX: {0}")] 8 | PtxError(String), 9 | #[error("Couldn't get CUDA function: {0}")] 10 | FunctionError(String), 11 | #[error("Couldn't find a CUDA device: {0}")] 12 | DeviceNotFound(String), 13 | #[error("Couldn't allocate memory for copying: {0}")] 14 | AllocateMemory(String), 15 | #[error("Couldn't retrieve information from GPU: {0}")] 16 | RetrieveMemory(String), 17 | #[error("Couldn't launch CUDA function: {0}")] 18 | Launch(String), 19 | #[error("Index out of bounds: {0}. Length of buffer is {0}")] 20 | IndexOutOfBounds(usize, usize), 21 | } 22 | -------------------------------------------------------------------------------- /crates/provers/stark/src/context.rs: -------------------------------------------------------------------------------- 1 | use super::proof::options::ProofOptions; 2 | 3 | #[derive(Clone, Debug)] 4 | pub struct AirContext { 5 | pub proof_options: ProofOptions, 6 | pub trace_columns: usize, 7 | 8 | /// This is a vector with the indices of all the rows that constitute 9 | /// an evaluation frame. Note that, because of how we write all constraints 10 | /// in one method (`compute_transitions`), this vector needs to include the 11 | /// offsets that are needed to compute EVERY transition constraint, even if some 12 | /// constraints don't use all of the indexes in said offsets. 13 | pub transition_offsets: Vec, 14 | pub num_transition_constraints: usize, 15 | } 16 | 17 | impl AirContext { 18 | pub fn num_transition_constraints(&self) -> usize { 19 | self.num_transition_constraints 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /crates/math/src/msm/README.md: -------------------------------------------------------------------------------- 1 | # lambdaworks MultiScalar Multiplication (MSM) 2 | 3 | This contains implementations for the MultiScalar Multiplication (MSM): 4 | - Naïve 5 | - Pippenger 6 | 7 | [Multiscalar multiplication](https://blog.lambdaclass.com/multiscalar-multiplication-strategies-and-challenges/) is an important primitive that appears in some polynomial commitment schemes and proof systems. It is also at the core of [EIP-4844](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-4844.md). Given a set of scalars in a [finite field](../field/README.md) $a_0, a_1, ..., a_n$ and [elliptic curve points](../elliptic_curve/README.md) $P_0, P_1, ... , P_n$, the MSM computes 8 | $$P = \sum_k a_k P_k$$ 9 | where $a_k P_k$ is understood as applying the group operation with $P_k$ a number of $a_k$ times. For its application in a protocol, see [KZG](../../../crypto/src/commitments/README.md) -------------------------------------------------------------------------------- /crates/provers/groth16/src/verifier.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_math::{elliptic_curve::traits::IsPairing, msm::pippenger::msm}; 2 | 3 | use crate::common::{FrElement, Pairing}; 4 | use crate::prover::Proof; 5 | use crate::setup::VerifyingKey; 6 | 7 | pub fn verify(vk: &VerifyingKey, proof: &Proof, pub_inputs: &[FrElement]) -> bool { 8 | // [γ^{-1} * (β*l(τ) + α*r(τ) + o(τ))]_1 9 | let k_tau_assigned_verifier_g1 = msm( 10 | &pub_inputs 11 | .iter() 12 | .map(|elem| elem.representative()) 13 | .collect::>(), 14 | &vk.verifier_k_tau_g1, 15 | ) 16 | .unwrap(); 17 | 18 | Pairing::compute(&proof.pi3, &vk.delta_g2).unwrap() 19 | * vk.alpha_g1_times_beta_g2.clone() 20 | * Pairing::compute(&k_tau_assigned_verifier_g1, &vk.gamma_g2).unwrap() 21 | == Pairing::compute(&proof.pi1, &proof.pi2).unwrap() 22 | } 23 | -------------------------------------------------------------------------------- /crates/provers/groth16/circom-adapter/tests/poseidon_test.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_circom_adapter::{circom_to_lambda, read_circom_r1cs, read_circom_witness}; 2 | 3 | // Proves & verifies a Poseidon circuit with 1 input and 2 outputs. The input is decimal 100. 4 | #[test] 5 | fn poseidon_parse_prove_verify() { 6 | let circom_r1cs = 7 | read_circom_r1cs("./tests/poseidon/test.r1cs.json").expect("could not read r1cs"); 8 | let circom_wtns = 9 | read_circom_witness("./tests/poseidon/witness.json").expect("could not read witness"); 10 | 11 | let (qap, wtns, pubs) = circom_to_lambda(circom_r1cs, circom_wtns); 12 | 13 | let (pk, vk) = lambdaworks_groth16::setup(&qap); 14 | let proof = lambdaworks_groth16::Prover::prove(&wtns, &qap, &pk); 15 | let accept = lambdaworks_groth16::verify(&vk, &proof, &pubs); 16 | assert!(accept, "proof verification failed"); 17 | } 18 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/short_weierstrass/curves/bn_254/default_types.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | field::{ 3 | element::FieldElement, 4 | fields::montgomery_backed_prime_fields::{IsModulus, MontgomeryBackendPrimeField}, 5 | }, 6 | unsigned_integer::element::U256, 7 | }; 8 | 9 | #[derive(Clone, Debug)] 10 | pub struct FrConfig; 11 | 12 | /// Modulus of bn 254 subgroup r = 21888242871839275222246405745257275088548364400416034343698204186575808495617, aka order 13 | impl IsModulus for FrConfig { 14 | const MODULUS: U256 = U256::from_hex_unchecked( 15 | "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001", 16 | ); 17 | } 18 | 19 | /// FrField using MontgomeryBackend for Bn254 20 | pub type FrField = MontgomeryBackendPrimeField; 21 | /// FrElement using MontgomeryBackend for Bn254 22 | pub type FrElement = FieldElement; 23 | -------------------------------------------------------------------------------- /exercises/challenge_1/README.md: -------------------------------------------------------------------------------- 1 | # The Lost Relic 2 | 3 | During their quest to find the greatest treasure in the world, the One Piece, Luffy and his friends are wandering inside a subterranean maze. After many hours, they arrive at the door hiding an old relic, which can be instrumental to achieving their goal. The big problem is that it is made of sea stone and Luffy is unable to use his strength to break it. There are some inscriptions on the walls, which Nico Robin is able to translate. 4 | It says: 5 | "If you can find the secret hidden among these texts, the door will open." 6 | There are many input plaintexts and their corresponding ciphertexts, all of them encrypted using a custom MiMC algorithm under the same key. There are also many skeletons around, of all the people who have so far failed this test. Luckily, Usopp brought his computing device and will try to break the secret. What can he do to recover the secret? -------------------------------------------------------------------------------- /.github/workflows/gh-pages.yml: -------------------------------------------------------------------------------- 1 | name: Github Pages 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - "docs/**" 9 | pull_request: 10 | paths: 11 | - "docs/**" 12 | 13 | jobs: 14 | deploy: 15 | runs-on: ubuntu-20.04 16 | concurrency: 17 | group: ${{ github.workflow }}-${{ github.ref }} 18 | steps: 19 | - uses: actions/checkout@v2 20 | 21 | - name: Setup mdBook 22 | uses: peaceiris/actions-mdbook@v1 23 | with: 24 | mdbook-version: '0.4.10' 25 | 26 | - name: Install Katex 27 | run: cargo install mdbook-katex 28 | 29 | - run: mdbook build docs 30 | 31 | - name: Deploy 32 | uses: peaceiris/actions-gh-pages@v3 33 | if: ${{ github.ref == 'refs/heads/main' }} 34 | with: 35 | github_token: ${{ secrets.GITHUB_TOKEN }} 36 | publish_dir: ./docs/book 37 | -------------------------------------------------------------------------------- /crates/math/src/polynomial/error.rs: -------------------------------------------------------------------------------- 1 | use core::fmt::Display; 2 | 3 | #[derive(Debug)] 4 | pub enum MultilinearError { 5 | InvalidMergeLength, 6 | IncorrectNumberofEvaluationPoints(usize, usize), 7 | ChisAndEvalsLengthMismatch(usize, usize), 8 | } 9 | 10 | impl Display for MultilinearError { 11 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 12 | match self { 13 | MultilinearError::InvalidMergeLength => write!(f, "Invalid Merge Length"), 14 | MultilinearError::IncorrectNumberofEvaluationPoints(x, y) => { 15 | write!(f, "points: {x}, vars: {y}") 16 | } 17 | MultilinearError::ChisAndEvalsLengthMismatch(x, y) => { 18 | write!(f, "chis: {x}, evals: {y}") 19 | } 20 | } 21 | } 22 | } 23 | 24 | #[cfg(feature = "std")] 25 | impl std::error::Error for MultilinearError {} 26 | -------------------------------------------------------------------------------- /crates/math/README.md: -------------------------------------------------------------------------------- 1 | # lambdaworks-math [![Latest Version]][crates.io] 2 | 3 | [Latest Version]: https://img.shields.io/crates/v/lambdaworks-math.svg 4 | [crates.io]: https://crates.io/crates/lambdaworks-math 5 | 6 | 7 | ## Usage 8 | Add this to your `Cargo.toml` 9 | ```toml 10 | [dependencies] 11 | lambdaworks-math = "0.13.0" 12 | ``` 13 | 14 | ## Structure 15 | This crate contains all the relevant mathematical building blocks needed for proof systems and cryptography. The main parts are: 16 | - [Finite Fields](./src/field/README.md) 17 | - [Elliptic curves](./src/elliptic_curve/README.md) 18 | - [Polynomials - univariate and multivariate](./src/polynomial/README.md) 19 | - [CircleFFT](./src/circle/README.md) 20 | - [Large unsigned integers](./src/unsigned_integer/) 21 | - [Fast Fourier Transform](./src/fft/README.md) 22 | - [Optimized Multiscalar Multiplication](./src/msm/) 23 | - [Cyclic Group](./src/cyclic_group.rs) 24 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: publish 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | jobs: 9 | publish: 10 | name: Publish 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout sources 14 | uses: actions/checkout@v4 15 | - name: Install stable toolchain 16 | uses: dtolnay/rust-toolchain@1.90.0 17 | - name: Publish crate lambdaworks-gpu 18 | run: cargo publish -p lambdaworks-gpu --token ${{ secrets.CARGO_REGISTRY_TOKEN }} 19 | - name: Publish crate lambdaworks-math 20 | run: cargo publish -p lambdaworks-math --token ${{ secrets.CARGO_REGISTRY_TOKEN }} --features "parallel std alloc lambdaworks-serde-binary lambdaworks-serde-string proptest" 21 | - name: Publish crate lambdaworks-crypto 22 | run: cargo publish -p lambdaworks-crypto --token ${{ secrets.CARGO_REGISTRY_TOKEN }} --features "asm std serde parallel alloc" 23 | -------------------------------------------------------------------------------- /crates/gpu/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lambdaworks-gpu" 3 | description = "Modular math library for cryptography - GPU implementation" 4 | version.workspace = true 5 | edition.workspace = true 6 | license.workspace = true 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | thiserror = "1.0.38" 12 | 13 | [dev-dependencies] 14 | proptest = "1.1.0" 15 | rand = "0.8.5" 16 | 17 | [build-dependencies] 18 | walkdir = { version = "2.3.3", optional = true } 19 | 20 | [features] 21 | cuda = ["dep:walkdir"] 22 | 23 | # Some features activate compilation of code which isn't 24 | # supported in all machines (e.g. metal, cuda), so we won't 25 | # use `--all-features` in any case, instead every feature 26 | # that should compile in all cases will require to be added 27 | # as default. If you don't want to compile with all of these 28 | # use `--no-default-features`. 29 | default = [] 30 | -------------------------------------------------------------------------------- /crates/provers/winterfell_adapter/src/utils.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_math::field::traits::IsField; 2 | use stark_platinum_prover::fri::FieldElement; 3 | 4 | pub fn vec_lambda2winter + Copy>(input: &[FieldElement]) -> Vec { 5 | input.iter().map(|&e| *e.value()).collect() 6 | } 7 | 8 | pub fn vec_winter2lambda + Copy>(input: &[FE]) -> Vec> { 9 | input 10 | .iter() 11 | .map(|&e| FieldElement::::const_from_raw(e)) 12 | .collect() 13 | } 14 | 15 | pub fn matrix_lambda2winter + Copy>( 16 | input: &[Vec>], 17 | ) -> Vec> { 18 | input.iter().map(|v| vec_lambda2winter(v)).collect() 19 | } 20 | 21 | pub fn matrix_winter2lambda + Copy>( 22 | input: &[Vec], 23 | ) -> Vec>> { 24 | input.iter().map(|v| vec_winter2lambda(v)).collect() 25 | } 26 | -------------------------------------------------------------------------------- /crates/math/src/fft/cpu/ops.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | fft::errors::FFTError, 3 | field::{ 4 | element::FieldElement, 5 | traits::{IsFFTField, IsField, IsSubFieldOf}, 6 | }, 7 | }; 8 | 9 | use super::{bit_reversing::in_place_bit_reverse_permute, fft::in_place_nr_2radix_fft}; 10 | 11 | /// Executes Fast Fourier Transform over elements of a two-adic finite field `E` and domain in a 12 | /// subfield `F`. Usually used for fast polynomial evaluation. 13 | pub fn fft, E: IsField>( 14 | input: &[FieldElement], 15 | twiddles: &[FieldElement], 16 | ) -> Result>, FFTError> { 17 | if !input.len().is_power_of_two() { 18 | return Err(FFTError::InputError(input.len())); 19 | } 20 | 21 | let mut results = input.to_vec(); 22 | in_place_nr_2radix_fft(&mut results, twiddles); 23 | in_place_bit_reverse_permute(&mut results); 24 | 25 | Ok(results) 26 | } 27 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/edwards/curves/bandersnatch/field.rs: -------------------------------------------------------------------------------- 1 | //! Base field of bandersantch -- which is also the scalar field of BLS12-381 curve. 2 | 3 | use crate::{ 4 | field::{ 5 | element::FieldElement, 6 | fields::montgomery_backed_prime_fields::{IsModulus, MontgomeryBackendPrimeField}, 7 | }, 8 | unsigned_integer::element::U256, 9 | }; 10 | 11 | pub const BANDERSNATCH_PRIME_FIELD_ORDER: U256 = 12 | U256::from_hex_unchecked("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"); 13 | 14 | #[derive(Clone, Debug)] 15 | pub struct FqConfig; 16 | 17 | impl IsModulus for FqConfig { 18 | const MODULUS: U256 = BANDERSNATCH_PRIME_FIELD_ORDER; 19 | } 20 | 21 | pub type FqField = MontgomeryBackendPrimeField; 22 | 23 | impl FieldElement { 24 | pub fn new_base(a_hex: &str) -> Self { 25 | Self::new(U256::from(a_hex)) 26 | } 27 | } 28 | pub type FqElement = FieldElement; 29 | -------------------------------------------------------------------------------- /.github/workflows/iai_benchs_main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | 7 | jobs: 8 | cache_iai_benchs: 9 | name: Cache iai benchs of main 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Install valgrind 13 | run: | 14 | sudo apt update 15 | sudo apt-get install -y valgrind 16 | cargo install --version 0.3.1 iai-callgrind-runner 17 | - name: Install stable toolchain 18 | uses: dtolnay/rust-toolchain@stable 19 | with: 20 | toolchain: stable 21 | - uses: actions/checkout@v3 22 | - uses: Swatinem/rust-cache@v2 23 | with: 24 | shared-key: ${{ runner.os }}-benchmark-build-cache 25 | - name: Run benchmarks 26 | run: cargo bench --no-fail-fast --bench "iai_*" 27 | - name: Save cache 28 | uses: actions/cache/save@v3 29 | with: 30 | path: | 31 | */target 32 | key: ${{ runner.os }}-iai-benchmark-cache-${{ github.sha }} 33 | -------------------------------------------------------------------------------- /examples/shamir_secret_sharing/README.md: -------------------------------------------------------------------------------- 1 | # Shamir's Secret Sharing 2 | 3 | ## Usage example 4 | 5 | ```rust 6 | // Definition of the secret 7 | // Creation of 6 shares 8 | // 3 shares will be used to recover the secret 9 | let sss = ShamirSecretSharing { 10 | secret: FE::new(1234), 11 | n: 6, 12 | k: 3, 13 | }; 14 | 15 | // Polynomial calculation 16 | let polynomial = sss.calculate_polynomial(); 17 | 18 | // Produce shares 19 | let shares = sss.generating_shares(polynomial.clone()); 20 | 21 | // Specify the x and y coordinates of the shares to use 22 | let shares_to_use_x = vec![shares.x[1], shares.x[3], shares.x[4]]; 23 | let shares_to_use_y = vec![shares.y[1], shares.y[3], shares.y[4]]; 24 | 25 | // Interpolation 26 | let poly_2 = sss.reconstructing(shares_to_use_x, shares_to_use_y); 27 | 28 | // Recover the free coefficient of the polynomial 29 | let secret_recovered = sss.recover(&poly_2); 30 | 31 | // Verifications 32 | assert_eq!(polynomial, poly_2); 33 | assert_eq!(sss.secret, secret_recovered); 34 | ``` 35 | -------------------------------------------------------------------------------- /examples/merkle-tree-cli/src/commands.rs: -------------------------------------------------------------------------------- 1 | use clap::{Args, Parser, Subcommand}; 2 | 3 | #[derive(Parser, Debug)] 4 | #[command(author = "Lambdaworks", version, about)] 5 | pub struct MerkleArgs { 6 | #[clap(subcommand)] 7 | pub entity: MerkleEntity, 8 | } 9 | 10 | #[derive(Subcommand, Debug)] 11 | pub enum MerkleEntity { 12 | #[clap(about = "Generate a merkle tree")] 13 | GenerateTree(GenerateTreeArgs), 14 | #[clap(about = "Generate a merkle proof")] 15 | GenerateProof(GenerateProofArgs), 16 | #[clap(about = "Verify a merkle proof")] 17 | VerifyProof(VerifyArgs), 18 | } 19 | 20 | #[derive(Args, Debug)] 21 | pub struct GenerateTreeArgs { 22 | pub tree_path: String, 23 | } 24 | 25 | #[derive(Args, Debug)] 26 | pub struct GenerateProofArgs { 27 | pub tree_path: String, 28 | pub position: usize, 29 | } 30 | 31 | #[derive(Args, Debug)] 32 | pub struct VerifyArgs { 33 | pub root_path: String, 34 | pub index: usize, 35 | pub proof_path: String, 36 | pub leaf_path: String, 37 | } 38 | -------------------------------------------------------------------------------- /crates/crypto/README.md: -------------------------------------------------------------------------------- 1 | # lambdaworks-crypto [![Latest Version]][crates.io] 2 | 3 | [Latest Version]: https://img.shields.io/crates/v/lambdaworks-crypto.svg 4 | [crates.io]: https://crates.io/crates/lambdaworks-crypto 5 | 6 | ## Usage 7 | 8 | Add this to your `Cargo.toml` 9 | ```toml 10 | [dependencies] 11 | lambdaworks-crypto = "0.13.0" 12 | ``` 13 | 14 | ## Structure 15 | 16 | This crate contains different cryptographic primitives needed for proof systems. The main elements are: 17 | - [Merkle trees](./src/merkle_tree/) 18 | - [Hash functions](./src/hash/) 19 | - [Fiat Shamir transformation](./src/fiat_shamir/) 20 | - [Polynomial commitment schemes](./src/commitments/) 21 | 22 | For examples on: 23 | - How do Merkle trees work, refer to [Merkle CLI](../../examples/merkle-tree-cli/README.md) 24 | - Hash functions, refer to [Hash functions' readme](./src/hash/README.md) 25 | - Fiat-Shamir heuristic, refer to [Fiat-Shamir's readme](./src/fiat_shamir/README.md) 26 | - Polynomial commitment schemes, refer to [PCS's readme](./src/commitments/README.md) 27 | -------------------------------------------------------------------------------- /crates/math/src/field/fields/fft_friendly/mod.rs: -------------------------------------------------------------------------------- 1 | /// Implemenation of the Babybear Prime Field p = 2^31 - 2^27 + 1 2 | pub mod babybear; 3 | /// Implementation of the quadratic extension of the babybear field 4 | pub mod quadratic_babybear; 5 | /// Implementation of the extension of degree 4 of the babybear field using u64. 6 | pub mod quartic_babybear; 7 | /// Implementation of the prime field used in [Stark101](https://starkware.co/stark-101/) tutorial, p = 3 * 2^30 + 1 8 | pub mod stark_101_prime_field; 9 | /// Implementation of two-adic prime field over 256 bit unsigned integers. 10 | pub mod stark_252_prime_field; 11 | /// Implemenation of the Goldilocks Prime Field p = 2^64 - 2^32 + 1 12 | pub mod u64_goldilocks; 13 | /// Implemenation of the Mersenne Prime field p = 2^31 - 1 14 | pub mod u64_mersenne_montgomery_field; 15 | 16 | /// Inmplementation of the Babybear Prime Field p = 2^31 - 2^27 + 1 using u32 17 | pub mod babybear_u32; 18 | 19 | /// Implementation of the extension of degree 4 of the babybear field using u32. 20 | pub mod quartic_babybear_u32; 21 | -------------------------------------------------------------------------------- /examples/prove-miden/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "prove-miden" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | repository.workspace = true 7 | 8 | [[bin]] 9 | name = "prove-miden" 10 | path = "src/main.rs" 11 | 12 | [dependencies] 13 | lambdaworks-crypto = { workspace = true } 14 | lambdaworks-math = { workspace = true, features = ["lambdaworks-serde-string"] } 15 | lambdaworks-winterfell-adapter = { workspace = true } 16 | stark-platinum-prover = { git = "https://github.com/lambdaclass/lambdaworks", branch = "miden-version", features = [ 17 | "winter_compatibility", 18 | ] } 19 | 20 | serde = { version = "1.0" } 21 | serde_json = "1" 22 | bincode = { version = "2.0.1", features = ["serde"] } 23 | miden-core = { package = "miden-core", version = "0.7" } 24 | miden-assembly = { package = "miden-assembly", version = "0.7" } 25 | miden-processor = { package = "miden-processor", version = "0.7" } 26 | miden-air = { package = "miden-air", version = "0.7" } 27 | winter-prover = { package = "winter-prover", version = "0.6.4" } 28 | -------------------------------------------------------------------------------- /examples/schnorr-signature/src/common.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_math::{ 2 | elliptic_curve::{ 3 | short_weierstrass::curves::bn_254::{ 4 | curve::BN254Curve, 5 | default_types::{FrElement, FrField}, 6 | }, 7 | traits::IsEllipticCurve, 8 | }, 9 | unsigned_integer::element::U256, 10 | }; 11 | use rand::Rng; 12 | use rand_chacha::ChaCha20Rng; 13 | 14 | // We use the BN-254 Curve as the group. We could have used any other curve. 15 | pub type Curve = BN254Curve; 16 | 17 | // We use the finite field Fr where r is the number of elements that the curve has, 18 | // i.e. r is the order of the group G formed by the curve. 19 | pub type F = FrField; 20 | 21 | pub type FE = FrElement; 22 | 23 | pub type CurvePoint = ::PointRepresentation; 24 | 25 | pub fn sample_field_elem(mut rng: ChaCha20Rng) -> FE { 26 | FE::new(U256 { 27 | limbs: [ 28 | rng.gen::(), 29 | rng.gen::(), 30 | rng.gen::(), 31 | rng.gen::(), 32 | ], 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /crates/provers/groth16/circom-adapter/tests/vitalik_example/test.r1cs.json: -------------------------------------------------------------------------------- 1 | { 2 | "n8": 32, 3 | "prime": "52435875175126190479447740508185965837690552500527637822603658699938581184513", 4 | "nVars": 4, 5 | "nOutputs": 1, 6 | "nPubInputs": 0, 7 | "nPrvInputs": 1, 8 | "nLabels": 6, 9 | "nConstraints": 2, 10 | "useCustomGates": false, 11 | "constraints": [ 12 | [ 13 | { 14 | "2": "52435875175126190479447740508185965837690552500527637822603658699938581184512" 15 | }, 16 | { 17 | "2": "1" 18 | }, 19 | { 20 | "3": "52435875175126190479447740508185965837690552500527637822603658699938581184512" 21 | } 22 | ], 23 | [ 24 | { 25 | "3": "52435875175126190479447740508185965837690552500527637822603658699938581184512" 26 | }, 27 | { 28 | "2": "1" 29 | }, 30 | { 31 | "0": "5", 32 | "1": "52435875175126190479447740508185965837690552500527637822603658699938581184512", 33 | "2": "1" 34 | } 35 | ] 36 | ], 37 | "map": [ 38 | 0, 39 | 1, 40 | 2, 41 | 3 42 | ], 43 | "customGates": [ 44 | ], 45 | "customGatesUses": [ 46 | ] 47 | } -------------------------------------------------------------------------------- /crates/provers/winterfell_adapter/src/adapter/public_inputs.rs: -------------------------------------------------------------------------------- 1 | use winter_air::{Air, TraceInfo}; 2 | 3 | #[derive(Clone)] 4 | pub struct AirAdapterPublicInputs 5 | where 6 | A: Air, 7 | A::PublicInputs: Clone, 8 | M: Clone, 9 | { 10 | pub(crate) winterfell_public_inputs: A::PublicInputs, 11 | pub(crate) transition_exemptions: Vec, 12 | pub(crate) transition_offsets: Vec, 13 | pub(crate) trace_info: TraceInfo, 14 | pub(crate) metadata: M, 15 | } 16 | 17 | impl AirAdapterPublicInputs 18 | where 19 | A: Air, 20 | A::PublicInputs: Clone, 21 | M: Clone, 22 | { 23 | pub fn new( 24 | winterfell_public_inputs: A::PublicInputs, 25 | transition_exemptions: Vec, 26 | transition_offsets: Vec, 27 | trace_info: TraceInfo, 28 | metadata: M, 29 | ) -> Self { 30 | Self { 31 | winterfell_public_inputs, 32 | transition_exemptions, 33 | transition_offsets, 34 | trace_info, 35 | metadata, 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /crates/math/src/helpers.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "alloc")] 2 | use crate::field::{element::FieldElement, traits::IsFFTField}; 3 | 4 | /// Computes the power of two that is equal or greater than n 5 | pub fn next_power_of_two(n: u64) -> u64 { 6 | if n <= 1 { 7 | 1 8 | } else { 9 | (u64::MAX >> (n - 1).leading_zeros()) + 1 10 | } 11 | } 12 | 13 | /// Pads the trace table with zeros until the length of the columns of the trace 14 | /// is equal to a power of 2 15 | /// This is required to ensure that we can use the radix-2 Cooley-Tukey FFT algorithm 16 | #[cfg(feature = "alloc")] 17 | pub fn resize_to_next_power_of_two( 18 | trace_colums: &mut [alloc::vec::Vec>], 19 | ) { 20 | trace_colums.iter_mut().for_each(|col| { 21 | // TODO: Remove this unwrap. This may panic if the usize cant be 22 | // casted into a u64. 23 | let col_len = col.len().try_into().unwrap(); 24 | let next_power_of_two_len = next_power_of_two(col_len); 25 | col.resize(next_power_of_two_len as usize, FieldElement::::zero()) 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /crates/provers/stark/src/fri/fri_commitment.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_crypto::merkle_tree::{merkle::MerkleTree, traits::IsMerkleTreeBackend}; 2 | use lambdaworks_math::{ 3 | field::{element::FieldElement, traits::IsField}, 4 | traits::AsBytes, 5 | }; 6 | 7 | #[derive(Clone)] 8 | pub struct FriLayer 9 | where 10 | F: IsField, 11 | FieldElement: AsBytes, 12 | B: IsMerkleTreeBackend, 13 | { 14 | pub evaluation: Vec>, 15 | pub merkle_tree: MerkleTree, 16 | pub coset_offset: FieldElement, 17 | pub domain_size: usize, 18 | } 19 | 20 | impl FriLayer 21 | where 22 | F: IsField, 23 | FieldElement: AsBytes, 24 | B: IsMerkleTreeBackend, 25 | { 26 | pub fn new( 27 | evaluation: &[FieldElement], 28 | merkle_tree: MerkleTree, 29 | coset_offset: FieldElement, 30 | domain_size: usize, 31 | ) -> Self { 32 | Self { 33 | evaluation: evaluation.to_vec(), 34 | merkle_tree, 35 | coset_offset, 36 | domain_size, 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /crates/math/src/gpu/cuda/shaders/fft/fft.cuh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template 4 | inline __device__ void _radix2_dit_butterfly(Fp *input, 5 | const Fp *twiddles, 6 | const int stage, 7 | const int butterfly_count) 8 | { 9 | int thread_pos = blockDim.x * blockIdx.x + threadIdx.x; 10 | 11 | if (thread_pos >= butterfly_count) return; 12 | // TODO: guard is not needed for inputs of len >=block_size * 2, only if len is pow of two 13 | 14 | int half_group_size = butterfly_count >> stage; 15 | int group = thread_pos / half_group_size; 16 | 17 | int pos_in_group = thread_pos & (half_group_size - 1); 18 | int i = thread_pos * 2 - pos_in_group; // multiply quotient by 2 19 | 20 | Fp w = twiddles[group]; 21 | Fp a = input[i]; 22 | Fp b = input[i + half_group_size]; 23 | 24 | Fp res_1 = a + w * b; 25 | Fp res_2 = a - w * b; 26 | 27 | input[i] = res_1; // --\/-- 28 | input[i + half_group_size] = res_2; // --/\-- 29 | }; 30 | -------------------------------------------------------------------------------- /exercises/challenge_3/README.md: -------------------------------------------------------------------------------- 1 | # It is over 9000! 2 | 3 | The Saiyans have landed on planet earth. Our great defenders Krillin, Piccolo, Tien and Gohan 4 | have to hold on till Goku arrives on the scene. 5 | 6 | Vegeta and Nappa have scouters that indicate our heroes power levels 7 | and sadly we are not doing too well. 8 | 9 | Somehow, Gohan has raised his power level to `p_4(X) = 9000`, but it is not good enough. Piccolo `p_3(X)` can help but he is still regenerating, and Krillin `p_2(X)` and Tien `p_1(X)` are in bad shape. The total power of the team is computed as 10 | ``` 11 | P = p_1(X) * 0 + p_2(X) * 0 + p_3(X) * 0 + p_4(X) 12 | ``` 13 | At the current moment, the X is equal to `42`. 14 | 15 | Suddenly Gohan, and Piccolo recieve a message from Bulma that the scouters verify the sensed power level of individual enemies using KZG and for multiple enemies with batched KZG method. Vegeta knows for sure that the power level of Gohan is `p_4(X) = 9000`, so he will know if we change that. If only the team had a way to trick their opponents to believe that their total power level is `P > 9000` - then the enemies will surely flee. -------------------------------------------------------------------------------- /crates/crypto/src/merkle_tree/test_merkle.rs: -------------------------------------------------------------------------------- 1 | use core::marker::PhantomData; 2 | 3 | use lambdaworks_math::field::{element::FieldElement, traits::IsField}; 4 | 5 | use super::{merkle::MerkleTree, traits::IsMerkleTreeBackend}; 6 | 7 | pub type TestMerkleTree = MerkleTree>; 8 | 9 | #[derive(Debug, Clone)] 10 | 11 | /// This hasher is for testing purposes 12 | /// It adds the fields 13 | /// Under no circunstance it can be used in production 14 | pub struct TestBackend { 15 | phantom: PhantomData, 16 | } 17 | 18 | impl Default for TestBackend { 19 | fn default() -> Self { 20 | Self { 21 | phantom: Default::default(), 22 | } 23 | } 24 | } 25 | 26 | impl IsMerkleTreeBackend for TestBackend 27 | where 28 | FieldElement: Sync + Send, 29 | { 30 | type Node = FieldElement; 31 | type Data = FieldElement; 32 | 33 | fn hash_data(input: &Self::Data) -> Self::Node { 34 | input + input 35 | } 36 | 37 | fn hash_new_parent(left: &Self::Node, right: &Self::Node) -> Self::Node { 38 | left + right 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /crates/math/src/gpu/cuda/shaders/fft/twiddles.cuh: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../utils.h" 4 | 5 | // NOTE: In order to calculate the inverse twiddles, call with _omega = _omega.inverse() 6 | template 7 | inline __device__ void _calc_twiddles(Fp *result, const Fp &_omega, const int count) 8 | { 9 | unsigned thread_pos = blockDim.x * blockIdx.x + threadIdx.x; 10 | if (thread_pos >= count) return; 11 | // TODO: guard is not needed for count >=block_size * 2, if count is pow of two 12 | 13 | Fp omega = _omega; 14 | result[thread_pos] = omega.pow(thread_pos); 15 | }; 16 | 17 | // NOTE: In order to calculate the inverse twiddles, call with _omega = _omega.inverse() 18 | template 19 | inline __device__ void _calc_twiddles_bitrev(Fp *result, const Fp &_omega, const int count) 20 | { 21 | unsigned thread_pos = blockDim.x * blockIdx.x + threadIdx.x; 22 | if (thread_pos >= count) return; 23 | // TODO: guard is not needed for count >=block_size * 2, if count is pow of two 24 | 25 | Fp omega = _omega; 26 | result[thread_pos] = omega.pow(reverse_index(thread_pos, count)); 27 | }; 28 | 29 | 30 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/short_weierstrass/curves/bls12_381/default_types.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | field::{ 3 | element::FieldElement, 4 | fields::montgomery_backed_prime_fields::{IsModulus, MontgomeryBackendPrimeField}, 5 | traits::IsFFTField, 6 | }, 7 | unsigned_integer::element::{UnsignedInteger, U256}, 8 | }; 9 | 10 | #[derive(Clone, Debug)] 11 | pub struct FrConfig; 12 | 13 | /// Modulus of bls 12 381 subgroup 14 | impl IsModulus for FrConfig { 15 | const MODULUS: U256 = U256::from_hex_unchecked( 16 | "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001", 17 | ); 18 | } 19 | 20 | /// FrField using MontgomeryBackend for bls 12 381 21 | pub type FrField = MontgomeryBackendPrimeField; 22 | /// FrElement using MontgomeryBackend for bls 12 381 23 | pub type FrElement = FieldElement; 24 | 25 | impl IsFFTField for FrField { 26 | const TWO_ADICITY: u64 = 32; 27 | const TWO_ADIC_PRIMITVE_ROOT_OF_UNITY: Self::BaseType = UnsignedInteger::from_hex_unchecked( 28 | "2ab00961a08a499d84dd396c349d9b3cc5e433d6fa78eb2b54cc39d9bb30bbb7", 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /crates/math/src/gpu/cuda/field/element.rs: -------------------------------------------------------------------------------- 1 | use crate::field::{element::FieldElement, traits::IsField}; 2 | use cudarc::driver::safe::DeviceRepr; 3 | 4 | use core::ffi; 5 | 6 | #[derive(Clone)] 7 | pub(crate) struct CUDAFieldElement { 8 | value: F::BaseType, 9 | } 10 | 11 | impl CUDAFieldElement { 12 | /// Returns the underlying `value` 13 | pub fn value(&self) -> &F::BaseType { 14 | &self.value 15 | } 16 | } 17 | 18 | impl Default for CUDAFieldElement { 19 | fn default() -> Self { 20 | Self { value: F::zero() } 21 | } 22 | } 23 | 24 | unsafe impl DeviceRepr for CUDAFieldElement { 25 | fn as_kernel_param(&self) -> *mut ffi::c_void { 26 | [self].as_ptr() as *mut ffi::c_void 27 | } 28 | } 29 | 30 | impl From<&FieldElement> for CUDAFieldElement { 31 | fn from(elem: &FieldElement) -> Self { 32 | Self { 33 | value: elem.value().clone(), 34 | } 35 | } 36 | } 37 | 38 | impl From> for FieldElement { 39 | fn from(elem: CUDAFieldElement) -> Self { 40 | Self::from_raw(elem.value()) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/pinocchio/src/common.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_math::{ 2 | elliptic_curve::{ 3 | short_weierstrass::curves::bls12_381::{ 4 | curve::BLS12381Curve, default_types::FrElement, default_types::FrField, 5 | pairing::BLS12381AtePairing, twist::BLS12381TwistCurve, 6 | }, 7 | traits::IsEllipticCurve, 8 | }, 9 | unsigned_integer::element::U256, 10 | }; 11 | use rand::{Rng, SeedableRng}; 12 | 13 | pub type Curve = BLS12381Curve; 14 | pub type TwistedCurve = BLS12381TwistCurve; 15 | 16 | pub type FE = FrElement; 17 | pub type F = FrField; 18 | 19 | pub type Pairing = BLS12381AtePairing; 20 | 21 | pub type G1Point = ::PointRepresentation; 22 | pub type G2Point = ::PointRepresentation; 23 | 24 | pub const ORDER_R_MINUS_1_ROOT_UNITY: FE = FE::from_hex_unchecked("7"); 25 | 26 | pub fn sample_fr_elem() -> FE { 27 | let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(9001); 28 | FE::new(U256 { 29 | limbs: [ 30 | rng.gen::(), 31 | rng.gen::(), 32 | rng.gen::(), 33 | rng.gen::(), 34 | ], 35 | }) 36 | } 37 | -------------------------------------------------------------------------------- /docs/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Lambdaworks Documentation 2 | 3 | - [Introduction](./introduction.md) 4 | 5 | - [FFT Library]() 6 | - [Benchmarks](./fft/benchmarks.md) 7 | 8 | - [Plonk]() 9 | - [Recap](./plonk/recap.md) 10 | - [Protocol](./plonk/protocol.md) 11 | - [Implementation](./plonk/implementation.md) 12 | - [Circuit API](./plonk/constraint_system.md) 13 | 14 | - [STARKs](./starks/starks.md) 15 | - [Recap](./starks/recap.md) 16 | - [Protocol overview](./starks/protocol_overview.md) 17 | - [Protocol](./starks/protocol.md) 18 | - [Implementation](./starks/implementation.md) 19 | - [High Level API](./starks/api.md) 20 | - [Under the hood](./starks/under_the_hood.md) 21 | - [Stone prover](./starks/stone_prover/introduction.md) 22 | - [Plain layout trace description](./starks/stone_prover/trace_plain_layout.md) 23 | 24 | - [Cairo](./starks/cairo.md) 25 | - [Trace Formal Description](./starks/cairo_trace_succinct.md) 26 | - [Trace Detailed Description](./starks/cairo_trace_descriptive.md) 27 | - [RAP](./starks/cairo_rap.md) 28 | - [Virtual Columns](./starks/virtual_cols.md) 29 | - [Built-ins](./starks/builtins.md) 30 | - [CLI](./starks/cairo_cli.md) 31 | -------------------------------------------------------------------------------- /crates/math/src/errors.rs: -------------------------------------------------------------------------------- 1 | #[derive(Debug, PartialEq, Eq)] 2 | pub enum ByteConversionError { 3 | FromBEBytesError, 4 | FromLEBytesError, 5 | InvalidValue, 6 | PointNotInSubgroup, 7 | ValueNotCompressed, 8 | ValueNotReduced, 9 | } 10 | 11 | #[derive(Debug, PartialEq, Eq)] 12 | pub enum CreationError { 13 | InvalidHexString, 14 | InvalidDecString, 15 | HexStringIsTooBig, 16 | RepresentativeOutOfRange, 17 | EmptyString, 18 | } 19 | 20 | #[derive(Debug, PartialEq, Eq)] 21 | pub enum DeserializationError { 22 | InvalidAmountOfBytes, 23 | FieldFromBytesError, 24 | PointerSizeError, 25 | InvalidValue, 26 | } 27 | 28 | #[derive(Debug, PartialEq, Eq)] 29 | pub enum PairingError { 30 | PointNotInSubgroup, 31 | DivisionByZero, 32 | } 33 | 34 | impl From for DeserializationError { 35 | fn from(error: ByteConversionError) -> Self { 36 | match error { 37 | ByteConversionError::FromBEBytesError => DeserializationError::FieldFromBytesError, 38 | ByteConversionError::FromLEBytesError => DeserializationError::FieldFromBytesError, 39 | _ => DeserializationError::InvalidValue, 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /examples/prove-verify-circom/src/main.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_circom_adapter::*; 2 | use lambdaworks_groth16::*; 3 | 4 | /// This example demonstrates how to prove and verify a Circom circuit using the Groth16 prover. 5 | /// 6 | /// You can run with: 7 | /// 8 | /// ```sh 9 | /// cargo run --package prove-verify-circom --bin prove-verify-circom 10 | /// ``` 11 | fn main() { 12 | println!("Reading input files"); 13 | let circom_r1cs = 14 | read_circom_r1cs("./examples/prove-verify-circom/input_files/test.r1cs.json").unwrap(); 15 | let circom_witness = 16 | read_circom_witness("./examples/prove-verify-circom/input_files/witness.json").unwrap(); 17 | 18 | println!("Converting to Lambdaworks-compatible QAP and witness assignments"); 19 | let (qap, witness, _) = circom_to_lambda(circom_r1cs, circom_witness); 20 | 21 | println!("Performing trusted setup"); 22 | let (pk, vk) = setup(&qap); 23 | 24 | println!("Proving"); 25 | let proof = Prover::prove(&witness, &qap, &pk); 26 | 27 | println!("Verifying"); 28 | let accept = verify(&vk, &proof, &witness[..qap.num_of_public_inputs]); 29 | 30 | assert!(accept, "Proof verification failed!"); 31 | println!("Proof verified!"); 32 | } 33 | -------------------------------------------------------------------------------- /crates/math/src/field/fields/mod.rs: -------------------------------------------------------------------------------- 1 | /// Implementation of two-adic prime fields to use with the Fast Fourier Transform (FFT). 2 | pub mod fft_friendly; 3 | /// Implementation of the 32-bit Mersenne Prime field (p = 2^31 - 1) 4 | pub mod mersenne31; 5 | pub mod montgomery_backed_prime_fields; 6 | /// Implementation of the Goldilocks Prime field (p = 2^448 - 2^224 - 1) 7 | pub mod p448_goldilocks_prime_field; 8 | /// Implemenation of Pallas field 9 | pub mod pallas_field; 10 | /// Implementation of secp256k1 base field. 11 | pub mod secp256k1_field; 12 | /// Implementation of secp256k1 scalar field. 13 | pub mod secp256k1_scalarfield; 14 | /// Implementation of secp256r1 base field. 15 | pub mod secp256r1_field; 16 | pub mod u32_montgomery_backend_prime_field; 17 | /// Implementation of the u64 Goldilocks Prime field (p = 2^64 - 2^32 + 1) 18 | pub mod u64_goldilocks_field; 19 | /// Implementation of prime fields over 64 bit unsigned integers. 20 | pub mod u64_prime_field; 21 | 22 | /// Winterfell and miden field compatibility 23 | #[cfg(feature = "winter_compatibility")] 24 | pub mod winterfell; 25 | 26 | /// Implemenation of Vesta Prime field (p = 2^254 + 45560315531506369815346746415080538113) 27 | pub mod vesta_field; 28 | 29 | pub mod binary; 30 | -------------------------------------------------------------------------------- /crates/crypto/benches/criterion_poseidon.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | use lambdaworks_crypto::hash::poseidon::starknet::PoseidonCairoStark252; 3 | use lambdaworks_crypto::hash::poseidon::Poseidon; 4 | use lambdaworks_math::field::element::FieldElement; 5 | use lambdaworks_math::field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField; 6 | use lambdaworks_math::traits::ByteConversion; 7 | use rand::{RngCore, SeedableRng}; 8 | use rand_chacha::ChaCha8Rng; 9 | 10 | fn poseidon_benchmarks(c: &mut Criterion) { 11 | let mut rng = ChaCha8Rng::seed_from_u64(2); 12 | let mut felt1: [u8; 32] = Default::default(); 13 | rng.fill_bytes(&mut felt1); 14 | let mut felt2: [u8; 32] = Default::default(); 15 | rng.fill_bytes(&mut felt2); 16 | 17 | let x = FieldElement::::from_bytes_be(&felt1).unwrap(); 18 | let y = FieldElement::::from_bytes_be(&felt2).unwrap(); 19 | let mut group = c.benchmark_group("Poseidon Benchmark"); 20 | 21 | group.bench_function("Hashing with black_box", |bench| { 22 | bench.iter(|| black_box(PoseidonCairoStark252::hash(&x, &y))) 23 | }); 24 | } 25 | criterion_group!(poseidon, poseidon_benchmarks); 26 | criterion_main!(poseidon); 27 | -------------------------------------------------------------------------------- /benches/benches/utils.rs: -------------------------------------------------------------------------------- 1 | use ark_ff::BigInt; 2 | use ark_std::UniformRand; 3 | use ark_test_curves::starknet_fp::Fq; 4 | use lambdaworks_math::{ 5 | field::{ 6 | element::FieldElement, fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, 7 | }, 8 | unsigned_integer::element::UnsignedInteger, 9 | }; 10 | use rand::SeedableRng; 11 | 12 | /// Creates `amount` random elements 13 | pub fn generate_random_elements(amount: u64) -> Vec { 14 | let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(9001); 15 | let mut arkworks_vec = Vec::new(); 16 | for _i in 0..amount { 17 | let a = Fq::rand(&mut rng); 18 | arkworks_vec.push(a); 19 | } 20 | 21 | arkworks_vec 22 | } 23 | 24 | pub fn to_lambdaworks_vec(arkworks_vec: &[Fq]) -> Vec> { 25 | let mut lambdaworks_vec = Vec::new(); 26 | for &arkworks_felt in arkworks_vec { 27 | let big_int: BigInt<4> = arkworks_felt.into(); 28 | let mut limbs = big_int.0; 29 | limbs.reverse(); 30 | 31 | let a: FieldElement = FieldElement::from(&UnsignedInteger { limbs }); 32 | 33 | assert_eq!(a.representative().limbs, limbs); 34 | 35 | lambdaworks_vec.push(a); 36 | } 37 | 38 | lambdaworks_vec 39 | } 40 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/montgomery/traits.rs: -------------------------------------------------------------------------------- 1 | use crate::elliptic_curve::traits::IsEllipticCurve; 2 | use crate::field::element::FieldElement; 3 | use core::fmt::Debug; 4 | 5 | /// Trait to add elliptic curves behaviour to a struct. 6 | pub trait IsMontgomery: IsEllipticCurve + Clone + Debug { 7 | fn a() -> FieldElement; 8 | 9 | fn b() -> FieldElement; 10 | 11 | /// Evaluates the equation at (x, y). 12 | /// Used for checking if the point belongs to the elliptic curve. 13 | /// Equation: by^2 = x^3 + ax^2 + x. 14 | fn defining_equation( 15 | x: &FieldElement, 16 | y: &FieldElement, 17 | ) -> FieldElement { 18 | (Self::b() * y.square()) - (x.pow(3_u16) + Self::a() * x.square() + x) 19 | } 20 | 21 | /// Evaluates the equation at the projective point (x, y, z). 22 | /// Projective equation: zby^2 = x^3 + zax^2 + z^2x 23 | fn defining_equation_projective( 24 | x: &FieldElement, 25 | y: &FieldElement, 26 | z: &FieldElement, 27 | ) -> FieldElement { 28 | z * Self::b() * y.square() - x.pow(3_u16) - z * Self::a() * x.square() - z.square() * x 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /crates/crypto/benches/criterion_pedersen.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | use lambdaworks_crypto::hash::pedersen::Pedersen; 3 | use lambdaworks_crypto::hash::pedersen::PedersenStarkCurve; 4 | use lambdaworks_math::field::element::FieldElement; 5 | use lambdaworks_math::field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField; 6 | use lambdaworks_math::traits::ByteConversion; 7 | use rand::{RngCore, SeedableRng}; 8 | use rand_chacha::ChaCha8Rng; 9 | 10 | fn pedersen_benchmarks(c: &mut Criterion) { 11 | let mut rng = ChaCha8Rng::seed_from_u64(2); 12 | let mut felt1: [u8; 32] = Default::default(); 13 | rng.fill_bytes(&mut felt1); 14 | let mut felt2: [u8; 32] = Default::default(); 15 | rng.fill_bytes(&mut felt2); 16 | 17 | let x = FieldElement::::from_bytes_be(&felt1).unwrap(); 18 | let y = FieldElement::::from_bytes_be(&felt2).unwrap(); 19 | let mut group = c.benchmark_group("Pedersen Benchmark"); 20 | 21 | // Benchmark with black_box is 0.41% faster 22 | group.bench_function("Hashing with black_box", |bench| { 23 | bench.iter(|| black_box(PedersenStarkCurve::hash(&x, &y))) 24 | }); 25 | } 26 | criterion_group!(pedersen, pedersen_benchmarks); 27 | criterion_main!(pedersen); 28 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/edwards/traits.rs: -------------------------------------------------------------------------------- 1 | use crate::elliptic_curve::traits::IsEllipticCurve; 2 | use crate::field::element::FieldElement; 3 | use core::fmt::Debug; 4 | /// Trait to add elliptic curves behaviour to a struct. 5 | pub trait IsEdwards: IsEllipticCurve + Clone + Debug { 6 | fn a() -> FieldElement; 7 | 8 | fn d() -> FieldElement; 9 | 10 | // Edwards equation in affine coordinates: 11 | // ax^2 + y^2 - 1 = d * x^2 * y^2 12 | fn defining_equation( 13 | x: &FieldElement, 14 | y: &FieldElement, 15 | ) -> FieldElement { 16 | (Self::a() * x.pow(2_u16) + y.pow(2_u16)) 17 | - FieldElement::::one() 18 | - Self::d() * x.pow(2_u16) * y.pow(2_u16) 19 | } 20 | 21 | // Edwards equation in projective coordinates. 22 | // a * x^2 * z^2 + y^2 * z^2 - z^4 = d * x^2 * y^2 23 | fn defining_equation_projective( 24 | x: &FieldElement, 25 | y: &FieldElement, 26 | z: &FieldElement, 27 | ) -> FieldElement { 28 | Self::a() * x.square() * z.square() + y.square() * z.square() 29 | - z.square().square() 30 | - Self::d() * x.square() * y.square() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /crates/provers/stark/src/utils.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_crypto::merkle_tree::proof::Proof; 2 | use lambdaworks_math::errors::DeserializationError; 3 | 4 | use super::config::Commitment; 5 | 6 | pub fn serialize_proof(proof: &Proof) -> Vec { 7 | let mut bytes = vec![]; 8 | bytes.extend(proof.merkle_path.len().to_be_bytes()); 9 | for commitment in &proof.merkle_path { 10 | bytes.extend(commitment); 11 | } 12 | bytes 13 | } 14 | 15 | pub fn deserialize_proof(bytes: &[u8]) -> Result<(Proof, &[u8]), DeserializationError> { 16 | let mut bytes = bytes; 17 | let mut merkle_path = vec![]; 18 | let merkle_path_len = usize::from_be_bytes( 19 | bytes 20 | .get(..8) 21 | .ok_or(DeserializationError::InvalidAmountOfBytes)? 22 | .try_into() 23 | .map_err(|_| DeserializationError::InvalidAmountOfBytes)?, 24 | ); 25 | bytes = &bytes[8..]; 26 | 27 | for _ in 0..merkle_path_len { 28 | let commitment = bytes 29 | .get(..32) 30 | .ok_or(DeserializationError::InvalidAmountOfBytes)? 31 | .try_into() 32 | .map_err(|_| DeserializationError::InvalidAmountOfBytes)?; 33 | merkle_path.push(commitment); 34 | bytes = &bytes[32..]; 35 | } 36 | 37 | Ok((Proof { merkle_path }, bytes)) 38 | } 39 | -------------------------------------------------------------------------------- /crates/math/benches/utils/fft_functions.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | // clippy has false positive in benchmarks 3 | use criterion::black_box; 4 | use lambdaworks_math::fft::cpu::{ 5 | bit_reversing::in_place_bit_reverse_permute, 6 | fft::{in_place_nr_2radix_fft, in_place_nr_4radix_fft, in_place_rn_2radix_fft}, 7 | roots_of_unity::get_twiddles, 8 | }; 9 | use lambdaworks_math::{field::traits::RootsConfig, polynomial::Polynomial}; 10 | 11 | use super::stark252_utils::{F, FE}; 12 | 13 | pub fn ordered_fft_nr(input: &mut [FE], twiddles: &[FE]) { 14 | in_place_nr_2radix_fft(input, twiddles); 15 | } 16 | 17 | pub fn ordered_fft_rn(input: &mut [FE], twiddles: &[FE]) { 18 | in_place_rn_2radix_fft(input, twiddles); 19 | } 20 | 21 | pub fn ordered_fft_nr4(input: &mut [FE], twiddles: &[FE]) { 22 | in_place_nr_4radix_fft(input, twiddles); 23 | } 24 | 25 | pub fn twiddles_generation(order: u64, config: RootsConfig) { 26 | get_twiddles::(order, config).unwrap(); 27 | } 28 | 29 | pub fn bitrev_permute(input: &mut [FE]) { 30 | in_place_bit_reverse_permute(input); 31 | } 32 | 33 | pub fn poly_evaluate_fft(poly: &Polynomial) -> Vec { 34 | Polynomial::evaluate_fft::(poly, black_box(1), black_box(None)).unwrap() 35 | } 36 | 37 | pub fn poly_interpolate_fft(evals: &[FE]) { 38 | Polynomial::interpolate_fft::(evals).unwrap(); 39 | } 40 | -------------------------------------------------------------------------------- /crates/crypto/src/merkle_tree/backends/types.rs: -------------------------------------------------------------------------------- 1 | use sha2::{Sha256, Sha512}; 2 | use sha3::{Keccak256, Keccak512, Sha3_256, Sha3_512}; 3 | 4 | use super::{field_element::FieldElementBackend, field_element_vector::FieldElementVectorBackend}; 5 | 6 | // Field element backend definitions 7 | 8 | // - With 256 bit 9 | pub type Sha3_256Backend = FieldElementBackend; 10 | pub type Keccak256Backend = FieldElementBackend; 11 | pub type Sha2_256Backend = FieldElementBackend; 12 | 13 | // - With 512 bit 14 | pub type Sha3_512Backend = FieldElementBackend; 15 | pub type Keccak512Backend = FieldElementBackend; 16 | pub type Sha2_512Backend = FieldElementBackend; 17 | 18 | // Vector of field elements backend definitions 19 | 20 | // - With 256 bit 21 | pub type BatchSha3_256Backend = FieldElementVectorBackend; 22 | pub type BatchKeccak256Backend = FieldElementVectorBackend; 23 | pub type BatchSha2_256Backend = FieldElementVectorBackend; 24 | 25 | // - With 512 bit 26 | pub type BatchSha3_512Backend = FieldElementVectorBackend; 27 | pub type BatchKeccak512Backend = FieldElementVectorBackend; 28 | pub type BatchSha2_512Backend = FieldElementVectorBackend; 29 | -------------------------------------------------------------------------------- /fuzz/cuda_fuzz/src/twiddles_generation_diff.rs: -------------------------------------------------------------------------------- 1 | use honggfuzz::fuzz; 2 | use lambdaworks_math::{ 3 | fft::{ 4 | gpu::cuda::{ state::CudaState, ops::gen_twiddles }, 5 | cpu::roots_of_unity::get_twiddles, 6 | }, 7 | field::{ 8 | traits::RootsConfig, 9 | fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, 10 | }, 11 | }; 12 | 13 | fn main() { 14 | loop { 15 | fuzz!(|input: u64| { 16 | let state = CudaState::new().unwrap(); 17 | let roots_configurations = vec![RootsConfig::Natural, RootsConfig::BitReverseInversed, RootsConfig::BitReverse, RootsConfig::NaturalInversed]; 18 | 19 | for roots_config in roots_configurations { 20 | let gen_twiddles_cuda = gen_twiddles::(input, roots_config, &state); 21 | let get_twiddles_cpu = get_twiddles::(input, roots_config); 22 | 23 | match (gen_twiddles_cuda, get_twiddles_cpu) { 24 | (Ok(twiddles_cuda), Ok(twiddles_cpu)) => assert_eq!(twiddles_cuda, twiddles_cpu), 25 | (Err(_), Err(_)) => {}, 26 | (cuda, cpu) => panic!("Evaluate results didn't match. cuda.is_err(): {}, cpu.is_err(): {}", cuda.is_err(), cpu.is_err()) 27 | } 28 | } 29 | }); 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /crates/crypto/src/merkle_tree/traits.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | #[cfg(feature = "parallel")] 3 | use rayon::prelude::{IntoParallelRefIterator, ParallelIterator}; 4 | 5 | /// A backend for Merkle trees. This defines raw `Data` from which the Merkle 6 | /// tree is built from. It also defines the `Node` type and the hash function 7 | /// used to build parent nodes from children nodes. 8 | pub trait IsMerkleTreeBackend { 9 | type Node: PartialEq + Eq + Clone + Sync + Send; 10 | type Data: Sync + Send; 11 | 12 | /// This function takes a single variable `Data` and converts it to a node. 13 | fn hash_data(leaf: &Self::Data) -> Self::Node; 14 | 15 | /// This function takes the list of data from which the Merkle 16 | /// tree will be built from and converts it to a list of leaf nodes. 17 | fn hash_leaves(unhashed_leaves: &[Self::Data]) -> Vec { 18 | #[cfg(feature = "parallel")] 19 | let iter = unhashed_leaves.par_iter(); 20 | #[cfg(not(feature = "parallel"))] 21 | let iter = unhashed_leaves.iter(); 22 | 23 | iter.map(|leaf| Self::hash_data(leaf)).collect() 24 | } 25 | 26 | /// This function takes to children nodes and builds a new parent node. 27 | /// It will be used in the construction of the Merkle tree. 28 | fn hash_new_parent(child_1: &Self::Node, child_2: &Self::Node) -> Self::Node; 29 | } 30 | -------------------------------------------------------------------------------- /examples/baby-snark/src/common.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_math::{ 2 | elliptic_curve::{ 3 | short_weierstrass::curves::bls12_381::{ 4 | curve::BLS12381Curve, default_types::FrElement as FE, default_types::FrField as FrF, 5 | pairing::BLS12381AtePairing, twist::BLS12381TwistCurve, 6 | }, 7 | traits::{IsEllipticCurve, IsPairing}, 8 | }, 9 | field::element::FieldElement, 10 | unsigned_integer::element::U256, 11 | }; 12 | use rand::{Rng, SeedableRng}; 13 | 14 | pub type Curve = BLS12381Curve; 15 | pub type TwistedCurve = BLS12381TwistCurve; 16 | 17 | pub type FrElement = FE; 18 | pub type FrField = FrF; 19 | 20 | pub type Pairing = BLS12381AtePairing; 21 | 22 | pub type G1Point = ::PointRepresentation; 23 | pub type G2Point = ::PointRepresentation; 24 | pub type PairingOutput = FieldElement<::OutputField>; 25 | 26 | pub const ORDER_R_MINUS_1_ROOT_UNITY: FrElement = FrElement::from_hex_unchecked("7"); 27 | 28 | pub fn sample_fr_elem() -> FrElement { 29 | let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(9001); 30 | FrElement::new(U256 { 31 | limbs: [ 32 | rng.gen::(), 33 | rng.gen::(), 34 | rng.gen::(), 35 | rng.gen::(), 36 | ], 37 | }) 38 | } 39 | -------------------------------------------------------------------------------- /crates/crypto/src/errors.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | use lambdaworks_math::errors::DeserializationError; 4 | 5 | #[derive(Debug)] 6 | pub enum SrsFromFileError { 7 | FileError(io::Error), 8 | DeserializationError(lambdaworks_math::errors::DeserializationError), 9 | } 10 | 11 | impl From for SrsFromFileError { 12 | fn from(err: DeserializationError) -> SrsFromFileError { 13 | match err { 14 | DeserializationError::InvalidAmountOfBytes => { 15 | SrsFromFileError::DeserializationError(DeserializationError::InvalidAmountOfBytes) 16 | } 17 | 18 | DeserializationError::FieldFromBytesError => { 19 | SrsFromFileError::DeserializationError(DeserializationError::FieldFromBytesError) 20 | } 21 | 22 | DeserializationError::PointerSizeError => { 23 | SrsFromFileError::DeserializationError(DeserializationError::PointerSizeError) 24 | } 25 | 26 | DeserializationError::InvalidValue => { 27 | SrsFromFileError::DeserializationError(DeserializationError::InvalidValue) 28 | } 29 | } 30 | } 31 | } 32 | 33 | impl From for SrsFromFileError { 34 | fn from(err: std::io::Error) -> SrsFromFileError { 35 | SrsFromFileError::FileError(err) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /fuzz/no_gpu_fuzz/fuzz_targets/field/stark_field_addition.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use libfuzzer_sys::fuzz_target; 4 | use lambdaworks_math::field::{ 5 | element::FieldElement, 6 | fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, 7 | }; 8 | 9 | use lambdaworks_math::traits::ByteConversion; 10 | 11 | type FE = FieldElement; 12 | 13 | use ibig::{modular::ModuloRing, UBig}; 14 | 15 | fuzz_target!(|bytes: ([u8;32], [u8;32])| { 16 | let (bytes_a, bytes_b) = bytes; 17 | let a = FE::from_bytes_be(&bytes_a).unwrap(); 18 | let b = FE::from_bytes_be(&bytes_b).unwrap(); 19 | 20 | let a_hex = a.representative().to_string()[2..].to_string(); 21 | let b_hex = b.representative().to_string()[2..].to_string(); 22 | 23 | let c = a + &b; 24 | let c_hex = c.representative().to_string()[2..].to_string(); 25 | 26 | let prime = 27 | UBig::from_str_radix("800000000000011000000000000000000000000000000000000000000000001", 16).unwrap(); 28 | let cairo_ring = ModuloRing::new(&prime); 29 | 30 | let a_ring = cairo_ring.from(&UBig::from_str_radix(&a_hex, 16).unwrap()); 31 | let b_ring = cairo_ring.from(&UBig::from_str_radix(&b_hex, 16).unwrap()); 32 | let expected_c = a_ring + &b_ring; 33 | let expected_c_hex = expected_c.residue().in_radix(16).to_string(); 34 | 35 | assert_eq!(expected_c_hex, c_hex); 36 | }); 37 | 38 | -------------------------------------------------------------------------------- /docs/src/fft/benchmarks.md: -------------------------------------------------------------------------------- 1 | # FFT Benchmarks 2 | 3 | ## Polynomial interpolation methods comparison 4 | 5 | Three methods of polynomial interpolation were benchmarked, with different input sizes each time: 6 | 7 | - **CPU Lagrange:** Finding the Lagrange polynomial of a set of random points via a naive algorithm (see `math/src/polynomial.rs:interpolate()`) 8 | - **CPU FFT:** Finding the lowest degree polynomial that interpolates pairs of twiddle factors and Fourier coefficients (the results of applying the Fourier transform to the coefficients of a polynomial) (see `math/src/polynomial.rs:interpolate_fft()`). 9 | 10 | 11 | All values of time are in milliseconds. Those cases which were greater than 30 seconds were marked respectively as they're too slow and weren't worth to be benchmarked. The input size refers to *d + 1* where *d* is the polynomial's degree (so size is amount of coefficients). 12 | 13 | | Input size | CPU Lagrange | CPU FFT | 14 | |------------|--------------|-----------| 15 | | 2^4 | 2.2 ms | 0.2 ms | 16 | | 2^5 | 9.6 ms | 0.4 ms | 17 | | 2^6 | 42.6 ms | 0.8 ms | 18 | | 2^7 | 200.8 ms | 1.7 ms | 19 | | ... | ... | .. | 20 | | 2^21 | >30000 ms | 28745 ms | 21 | | 2^22 | >30000 ms | >30000 ms | 22 | | 2^23 | >30000 ms | >30000 ms | 23 | | 2^24 | >30000 ms | >30000 ms | 24 | -------------------------------------------------------------------------------- /examples/pinocchio/tests/integration_test.rs: -------------------------------------------------------------------------------- 1 | use pinocchio::common::FE; 2 | use pinocchio::prover::generate_proof; 3 | use pinocchio::setup::{setup, ToxicWaste}; 4 | use pinocchio::test_utils::{new_test_r1cs, test_qap_solver}; 5 | use pinocchio::verifier::verify; 6 | 7 | fn test_pinocchio(toxic_waste: ToxicWaste) { 8 | println!("Running Pinocchio test..."); 9 | let test_qap = new_test_r1cs().into(); 10 | // Setup 11 | let (evaluation_key, verification_key) = setup(&test_qap, toxic_waste); 12 | // Define inputs 13 | let inputs = [FE::from(1), FE::from(2), FE::from(3), FE::from(4)]; 14 | // Execute the QAP 15 | let (c_mid, c_output) = test_qap_solver(inputs.clone()); 16 | // Construct the full witness vector 17 | let mut c_vector = inputs.to_vec(); 18 | c_vector.push(c_mid); 19 | c_vector.push(c_output.clone()); 20 | // Generate proof 21 | let proof = generate_proof(&evaluation_key, &test_qap, &c_vector); 22 | let mut c_io_vector = inputs.to_vec(); 23 | c_io_vector.push(c_output); 24 | // Verify the proof 25 | let accepted = verify(&verification_key, &proof, &c_io_vector); 26 | assert!(accepted, "Proof verification failed"); 27 | println!("Proof verified successfully!"); 28 | } 29 | 30 | #[cfg(test)] 31 | #[test] 32 | fn test_pinocchio_random_toxic_waste() { 33 | let toxic_waste = ToxicWaste::sample(); 34 | test_pinocchio(toxic_waste); 35 | } 36 | -------------------------------------------------------------------------------- /benches/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lambdaworks-benches" 3 | version.workspace = true 4 | edition.workspace = true 5 | 6 | [dependencies] 7 | ark-ff = { git = "https://github.com/arkworks-rs/algebra", rev = "ef8f758" } 8 | ark-test-curves = { git = "https://github.com/arkworks-rs/algebra", rev = "ef8f758" } 9 | ark-std = "0.4.0" 10 | rand = "0.8.5" 11 | rand_chacha = "0.3.1" 12 | starknet-curve = { git = "https://github.com/xJonathanLEI/starknet-rs", tag = "starknet-curve/v0.4.2" } 13 | starknet-ff = { git = "https://github.com/xJonathanLEI/starknet-rs", tag = "starknet-ff/v0.3.7" } 14 | starknet-crypto = { git = "https://github.com/xJonathanLEI/starknet-rs", tag = "starknet-crypto/v0.6.2" } 15 | pathfinder-crypto = { git = "https://github.com/eqlabs/pathfinder.git" } 16 | 17 | lambdaworks-math.workspace = true 18 | lambdaworks-crypto.workspace = true 19 | 20 | [dev-dependencies] 21 | criterion = { version = "0.5.1", default-features = false } 22 | rand_chacha = "0.3.1" 23 | 24 | [[bench]] 25 | name = "add" 26 | harness = false 27 | 28 | [[bench]] 29 | name = "mul" 30 | harness = false 31 | 32 | [[bench]] 33 | name = "sub" 34 | harness = false 35 | 36 | [[bench]] 37 | name = "invert" 38 | harness = false 39 | 40 | [[bench]] 41 | name = "sqrt" 42 | harness = false 43 | 44 | [[bench]] 45 | name = "pow" 46 | harness = false 47 | 48 | [[bench]] 49 | name = "point" 50 | harness = false 51 | 52 | [[bench]] 53 | name = "poseidon" 54 | harness = false 55 | -------------------------------------------------------------------------------- /crates/math/benches/utils/stark252_utils.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_math::{ 2 | fft::cpu::{bit_reversing::in_place_bit_reverse_permute, roots_of_unity::get_twiddles}, 3 | field::{ 4 | element::FieldElement, fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, 5 | traits::RootsConfig, 6 | }, 7 | polynomial::Polynomial, 8 | unsigned_integer::element::UnsignedInteger, 9 | }; 10 | use rand::random; 11 | 12 | pub type F = Stark252PrimeField; 13 | pub type FE = FieldElement; 14 | 15 | // NOTE: intentional duplicate to help IAI skip setup code 16 | #[inline(never)] 17 | #[export_name = "util::bitrev_permute"] 18 | pub fn bitrev_permute(input: &mut [FE]) { 19 | in_place_bit_reverse_permute(input); 20 | } 21 | 22 | #[inline(never)] 23 | #[export_name = "util::rand_field_elements"] 24 | pub fn rand_field_elements(order: u64) -> Vec { 25 | let mut result = Vec::with_capacity(1 << order); 26 | for _ in 0..result.capacity() { 27 | let rand_big = UnsignedInteger { limbs: random() }; 28 | result.push(FE::new(rand_big)); 29 | } 30 | result 31 | } 32 | 33 | #[inline(never)] 34 | #[export_name = "util::rand_poly"] 35 | pub fn rand_poly(order: u64) -> Polynomial { 36 | Polynomial::new(&rand_field_elements(order)) 37 | } 38 | 39 | #[inline(never)] 40 | #[export_name = "util::get_twiddles"] 41 | pub fn twiddles(order: u64, config: RootsConfig) -> Vec { 42 | get_twiddles(order, config).unwrap() 43 | } 44 | -------------------------------------------------------------------------------- /crates/provers/groth16/tests/groth16.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_groth16::{common::*, setup, verify, Proof, Prover}; 2 | 3 | mod test_circuits; 4 | use test_circuits::*; 5 | 6 | #[test] 7 | fn vitalik() { 8 | let qap = test_circuits::vitalik_qap(); // x^3 + x + 5 = 35 9 | 10 | let (pk, vk) = setup(&qap); 11 | 12 | for w in [ 13 | ["0x1", "0x3", "0x23", "0x9", "0x1b", "0x1e"], 14 | ["0x1", "0x1", "0x7", "0x1", "0x1", "0x2"], 15 | ] { 16 | let w = w // x = 3 17 | .map(FrElement::from_hex_unchecked) 18 | .to_vec(); 19 | 20 | let serialized_proof = Prover::prove(&w, &qap, &pk).serialize(); 21 | let deserialized_proof = Proof::deserialize(&serialized_proof).unwrap(); 22 | 23 | let accept = verify(&vk, &deserialized_proof, &w[..qap.num_of_public_inputs]); 24 | assert!(accept); 25 | } 26 | } 27 | 28 | #[test] 29 | fn example() { 30 | let qap = test_qap_2(); 31 | let (pk, vk) = setup(&qap); 32 | 33 | // 1, x, y, ~out, sym_1, sym_2, sym_3, sym_4 34 | let w = ["0x1", "0x5", "0x3", "0x0", "0x19", "0x9", "0x0", "0x0"] // x = 3 35 | .map(FrElement::from_hex_unchecked) 36 | .to_vec(); 37 | 38 | let serialized_proof = Prover::prove(&w, &qap, &pk).serialize(); 39 | let deserialized_proof = Proof::deserialize(&serialized_proof).unwrap(); 40 | 41 | let accept = verify(&vk, &deserialized_proof, &w[..qap.num_of_public_inputs]); 42 | assert!(accept); 43 | } 44 | -------------------------------------------------------------------------------- /crates/crypto/benches/criterion_merkle.rs: -------------------------------------------------------------------------------- 1 | use core::time::Duration; 2 | use criterion::{criterion_group, criterion_main, Criterion}; 3 | use lambdaworks_crypto::merkle_tree::{ 4 | backends::field_element::FieldElementBackend, merkle::MerkleTree, 5 | }; 6 | use lambdaworks_math::{ 7 | field::element::FieldElement, 8 | field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, 9 | }; 10 | use sha3::Keccak256; 11 | 12 | type F = Stark252PrimeField; 13 | type FE = FieldElement; 14 | type TreeBackend = FieldElementBackend; 15 | 16 | fn merkle_tree_benchmarks(c: &mut Criterion) { 17 | let mut group = c.benchmark_group("Merkle Tree"); 18 | group.sample_size(10); 19 | group.measurement_time(Duration::from_secs(30)); 20 | 21 | // NOTE: the values to hash don't really matter, so let's go with the easy ones. 22 | 23 | let unhashed_leaves: Vec<_> = core::iter::successors(Some(FE::zero()), |s| Some(s + FE::one())) 24 | .take((1 << 20) + 1) 25 | .collect(); 26 | // `(1 << 20) + 1` exploits worst cases in terms of rounding up to powers of 2. 27 | 28 | group.bench_with_input( 29 | "build", 30 | unhashed_leaves.as_slice(), 31 | |bench, unhashed_leaves| { 32 | bench.iter_with_large_drop(|| MerkleTree::::build(unhashed_leaves)); 33 | }, 34 | ); 35 | 36 | group.finish(); 37 | } 38 | 39 | criterion_group!(merkle_tree, merkle_tree_benchmarks); 40 | criterion_main!(merkle_tree); 41 | -------------------------------------------------------------------------------- /crates/provers/groth16/src/r1cs.rs: -------------------------------------------------------------------------------- 1 | use crate::common::FrElement; 2 | use lambdaworks_math::field::{element::FieldElement, traits::IsField}; 3 | 4 | // To be improved with a front-end implementation 5 | // TODO: Use CS in Groth16 tests instead of a plain QAP 6 | #[derive(Clone, Debug, PartialEq, Eq)] 7 | pub struct ConstraintSystem { 8 | pub constraints: R1CS, 9 | pub witness: Vec>, 10 | } 11 | 12 | #[derive(Clone, Debug, PartialEq, Eq)] 13 | pub struct Constraint { 14 | pub a: Vec, 15 | pub b: Vec, 16 | pub c: Vec, 17 | } 18 | #[derive(Clone, Debug, PartialEq, Eq)] 19 | pub struct R1CS { 20 | pub constraints: Vec, 21 | pub number_of_inputs: usize, 22 | } 23 | 24 | impl R1CS { 25 | pub fn from_matrices( 26 | a: Vec>, 27 | b: Vec>, 28 | c: Vec>, 29 | number_of_inputs: usize, 30 | ) -> Self { 31 | Self { 32 | constraints: (0..a.len()) 33 | .map(|i| Constraint { 34 | a: a[i].clone(), 35 | b: b[i].clone(), 36 | c: c[i].clone(), 37 | }) 38 | .collect(), 39 | number_of_inputs, 40 | } 41 | } 42 | 43 | pub fn number_of_constraints(&self) -> usize { 44 | self.constraints.len() 45 | } 46 | 47 | pub fn witness_size(&self) -> usize { 48 | self.constraints[0].a.len() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /crates/provers/winterfell_adapter/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lambdaworks-winterfell-adapter" 3 | version.workspace = true 4 | edition.workspace = true 5 | license.workspace = true 6 | 7 | [dependencies] 8 | lambdaworks-math = { git = "https://github.com/lambdaclass/lambdaworks", branch = "miden-version", features = [ 9 | "winter_compatibility", 10 | ] } 11 | stark-platinum-prover = { git = "https://github.com/lambdaclass/lambdaworks", branch = "miden-version", features = [ 12 | "winter_compatibility", 13 | ] } 14 | 15 | rand = "0.8.5" 16 | winter-air = { package = "winter-air", version = "0.6.4", default-features = false } 17 | winter-prover = { package = "winter-prover", version = "0.6.4", default-features = false } 18 | winter-math = { package = "winter-math", version = "0.6.4", default-features = false } 19 | winter-utils = { package = "winter-utils", version = "0.6.4", default-features = false } 20 | miden-air = { package = "miden-air", version = "0.7", default-features = false } 21 | miden-core = { package = "miden-core", version = "0.7", default-features = false } 22 | miden-assembly = { package = "miden-assembly", version = "0.7", default-features = false } 23 | miden-processor = { package = "miden-processor", version = "0.7", default-features = false } 24 | sha3 = "0.10.8" 25 | 26 | [dev-dependencies] 27 | criterion = { version = "0.4", default-features = false } 28 | miden-prover = { package = "miden-prover", version = "0.7", default-features = false } 29 | 30 | [[bench]] 31 | name = "proving" 32 | harness = false 33 | -------------------------------------------------------------------------------- /crates/crypto/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lambdaworks-crypto" 3 | description = "Data structures and primitives for cryptography library" 4 | version.workspace = true 5 | edition.workspace = true 6 | license.workspace = true 7 | 8 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 9 | 10 | [dependencies] 11 | lambdaworks-math = { workspace = true, features = ["alloc"] } 12 | digest = "0.10.7" 13 | sha3 = { version = "0.10.8", default-features = false } 14 | sha2 = { version = "0.10", default-features = false } 15 | # Optional 16 | serde = { version = "1.0", default-features = false, features = [ 17 | "derive", 18 | "alloc", 19 | ], optional = true } 20 | rayon = { version = "1.8.0", optional = true } 21 | rand = { version = "0.8.5", default-features = false } 22 | rand_chacha = { version = "0.3.1", default-features = false } 23 | 24 | [dev-dependencies] 25 | criterion = "0.4" 26 | iai-callgrind.workspace = true 27 | rand = "0.8.5" 28 | rand_chacha = "0.3.1" 29 | 30 | [features] 31 | default = ["asm", "std"] 32 | asm = ["sha3/asm"] 33 | std = ["lambdaworks-math/std", "sha2/std", "sha3/std", "serde?/std"] 34 | serde = ["dep:serde"] 35 | test_fiat_shamir = [] 36 | parallel = ["dep:rayon"] 37 | alloc = [] 38 | 39 | [[bench]] 40 | name = "criterion_merkle" 41 | harness = false 42 | 43 | [[bench]] 44 | name = "iai_merkle" 45 | harness = false 46 | 47 | [[bench]] 48 | name = "criterion_poseidon" 49 | harness = false 50 | 51 | [[bench]] 52 | name = "criterion_pedersen" 53 | harness = false 54 | -------------------------------------------------------------------------------- /examples/baby-snark/src/verifier.rs: -------------------------------------------------------------------------------- 1 | use std::ops::Mul; 2 | 3 | use lambdaworks_math::cyclic_group::IsGroup; 4 | use lambdaworks_math::elliptic_curve::traits::IsEllipticCurve; 5 | use lambdaworks_math::{elliptic_curve::traits::IsPairing, msm::pippenger::msm}; 6 | 7 | use crate::common::{Curve, FrElement, Pairing, TwistedCurve}; 8 | use crate::prover::Proof; 9 | use crate::setup::VerifyingKey; 10 | 11 | pub fn verify(vk: &VerifyingKey, proof: &Proof, pub_inputs: &[FrElement]) -> bool { 12 | let v_w = &proof.v_w; 13 | let v_w_prime = &proof.v_w_prime; 14 | let h = &proof.h; 15 | let b_w = &proof.b_w; 16 | 17 | let mut accept = true; 18 | accept &= Pairing::compute(b_w, &vk.gamma_g2) == Pairing::compute(&vk.beta_gamma_g1, v_w_prime); 19 | accept &= Pairing::compute(v_w, &TwistedCurve::generator()) 20 | == Pairing::compute(&Curve::generator(), v_w_prime); 21 | let v_u = msm( 22 | &pub_inputs 23 | .iter() 24 | .map(|elem| elem.representative()) 25 | .collect::>(), 26 | &vk.u_tau_g1, 27 | ) 28 | .unwrap(); 29 | let v_u_prime = msm( 30 | &pub_inputs 31 | .iter() 32 | .map(|elem| elem.representative()) 33 | .collect::>(), 34 | &vk.u_tau_g2, 35 | ) 36 | .unwrap(); 37 | 38 | accept &= Pairing::compute(&v_u.operate_with(v_w), &v_u_prime.operate_with(v_w_prime)) 39 | .unwrap() 40 | .mul(&vk.inv_pairing_g1_g2) 41 | == Pairing::compute(h, &vk.t_tau_g2).unwrap(); 42 | accept 43 | } 44 | -------------------------------------------------------------------------------- /crates/provers/groth16/src/common.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_math::{ 2 | elliptic_curve::{ 3 | short_weierstrass::curves::bls12_381::{ 4 | curve::BLS12381Curve, default_types::FrElement as FE, default_types::FrField as FrF, 5 | pairing::BLS12381AtePairing, twist::BLS12381TwistCurve, 6 | }, 7 | traits::{IsEllipticCurve, IsPairing}, 8 | }, 9 | field::element::FieldElement, 10 | unsigned_integer::element::U256, 11 | }; 12 | use rand::{Rng, SeedableRng}; 13 | 14 | pub type Curve = BLS12381Curve; 15 | pub type TwistedCurve = BLS12381TwistCurve; 16 | 17 | pub type FrElement = FE; 18 | pub type FrField = FrF; 19 | 20 | pub type Pairing = BLS12381AtePairing; 21 | 22 | pub type G1Point = ::PointRepresentation; 23 | pub type G2Point = ::PointRepresentation; 24 | pub type PairingOutput = FieldElement<::OutputField>; 25 | 26 | /// Generator of the multiplicative group of Fr. Basically, the multiplicative group is obtained by taking 27 | /// powers of the element w: {w^0, w, w^2 , ... , w^{R - 2}} = Fr\{0} 28 | pub const ORDER_R_MINUS_1_ROOT_UNITY: FrElement = FrElement::from_hex_unchecked("7"); 29 | 30 | /// Returns a random element in Fr 31 | pub fn sample_fr_elem() -> FrElement { 32 | let mut rng = rand_chacha::ChaCha20Rng::from_entropy(); 33 | FrElement::new(U256 { 34 | limbs: [ 35 | rng.gen::(), 36 | rng.gen::(), 37 | rng.gen::(), 38 | rng.gen::(), 39 | ], 40 | }) 41 | } 42 | -------------------------------------------------------------------------------- /crates/math/benches/elliptic_curves/bls12_377.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, Criterion}; 2 | use lambdaworks_math::{ 3 | cyclic_group::IsGroup, 4 | elliptic_curve::{ 5 | short_weierstrass::curves::bls12_377::curve::BLS12377Curve, traits::IsEllipticCurve, 6 | }, 7 | }; 8 | use rand::{rngs::StdRng, Rng, SeedableRng}; 9 | 10 | #[allow(dead_code)] 11 | pub fn bls12_377_elliptic_curve_benchmarks(c: &mut Criterion) { 12 | let mut rng = StdRng::seed_from_u64(42); 13 | let a_val: u128 = rng.gen(); 14 | let b_val: u128 = rng.gen(); 15 | let a = BLS12377Curve::generator().operate_with_self(a_val); 16 | let b = BLS12377Curve::generator().operate_with_self(b_val); 17 | 18 | let mut group = c.benchmark_group("BLS12-377 Ops"); 19 | group.significance_level(0.1).sample_size(10000); 20 | group.throughput(criterion::Throughput::Elements(1)); 21 | 22 | // Operate_with G1 23 | group.bench_function("Operate_with_G1", |bencher| { 24 | bencher.iter(|| black_box(black_box(&a).operate_with(black_box(&b)))); 25 | }); 26 | 27 | // Operate_with_self G1 28 | group.bench_function("Operate_with_self_G1", |bencher| { 29 | bencher.iter(|| black_box(black_box(&a).operate_with_self(black_box(b_val)))); 30 | }); 31 | 32 | // Double G1 33 | group.bench_function("Double G1 {:?}", |bencher| { 34 | bencher.iter(|| black_box(black_box(&a).operate_with_self(black_box(2u64)))); 35 | }); 36 | 37 | // Neg G1 38 | group.bench_function("Neg G1 {:?}", |bencher| { 39 | bencher.iter(|| black_box(black_box(&a).neg())); 40 | }); 41 | } 42 | -------------------------------------------------------------------------------- /crates/math/benches/elliptic_curves/iai_bls12_377.rs: -------------------------------------------------------------------------------- 1 | use criterion::black_box; 2 | use lambdaworks_math::{ 3 | cyclic_group::IsGroup, 4 | elliptic_curve::{ 5 | short_weierstrass::{ 6 | curves::bls12_377::curve::BLS12377Curve, point::ShortWeierstrassProjectivePoint, 7 | }, 8 | traits::IsEllipticCurve, 9 | }, 10 | }; 11 | use rand::{rngs::StdRng, Rng, SeedableRng}; 12 | #[allow(dead_code)] 13 | type G1 = ShortWeierstrassProjectivePoint; 14 | 15 | #[allow(dead_code)] 16 | pub fn rand_points_g1() -> (G1, G1, u128, u128) { 17 | let mut rng = StdRng::seed_from_u64(42); 18 | let a_val = rng.gen(); 19 | let b_val = rng.gen(); 20 | let a = BLS12377Curve::generator().operate_with_self(a_val); 21 | let b = BLS12377Curve::generator().operate_with_self(b_val); 22 | (a, b, a_val, b_val) 23 | } 24 | 25 | #[allow(dead_code)] 26 | pub fn bls12_377_operate_with_g1() { 27 | let (a, b, _, _) = rand_points_g1(); 28 | let _ = black_box(black_box(&a).operate_with(black_box(&b))); 29 | } 30 | 31 | #[allow(dead_code)] 32 | pub fn bls12_377_operate_with_self_g1() { 33 | let (a, _, _, b_val) = rand_points_g1(); 34 | let _ = black_box(black_box(&a).operate_with_self(black_box(b_val))); 35 | } 36 | 37 | #[allow(dead_code)] 38 | pub fn bls12_377_double_g1() { 39 | let (a, _, _, _) = rand_points_g1(); 40 | let _ = black_box(black_box(&a).operate_with_self(black_box(2u64))); 41 | } 42 | 43 | #[allow(dead_code)] 44 | pub fn bls12_377_neg_g1() { 45 | let (a, _, _, _) = rand_points_g1(); 46 | let _ = black_box(black_box(&a).neg()); 47 | } 48 | -------------------------------------------------------------------------------- /benches/benches/invert.rs: -------------------------------------------------------------------------------- 1 | use ark_ff::Field; 2 | use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion}; 3 | use utils::generate_random_elements; 4 | 5 | use crate::utils::to_lambdaworks_vec; 6 | 7 | pub mod utils; 8 | 9 | const BENCHMARK_NAME: &str = "invert"; 10 | 11 | pub fn criterion_benchmark(c: &mut Criterion) { 12 | let arkworks_vec = generate_random_elements(10000).to_vec(); 13 | 14 | // arkworks-ff 15 | { 16 | c.bench_function( 17 | &format!("{BENCHMARK_NAME} 10000 elements| ark-ff - ef8f758"), 18 | |b| { 19 | b.iter_batched( 20 | || arkworks_vec.clone(), 21 | |mut v| { 22 | for mut elem in v.iter_mut() { 23 | black_box(black_box(&mut elem).inverse_in_place()); 24 | } 25 | }, 26 | BatchSize::LargeInput, 27 | ); 28 | }, 29 | ); 30 | } 31 | 32 | // lambdaworks-math 33 | { 34 | let lambdaworks_vec = to_lambdaworks_vec(&arkworks_vec); 35 | 36 | c.bench_function( 37 | &format!("{BENCHMARK_NAME} 10000 elements | lambdaworks",), 38 | |b| { 39 | b.iter(|| { 40 | for elem in lambdaworks_vec.iter() { 41 | black_box(black_box(&elem).inv().unwrap()); 42 | } 43 | }); 44 | }, 45 | ); 46 | } 47 | } 48 | 49 | criterion_group!(benches, criterion_benchmark); 50 | criterion_main!(benches); 51 | -------------------------------------------------------------------------------- /exercises/challenge_2/README.md: -------------------------------------------------------------------------------- 1 | # Breaking into the vault of Loki 2 | 3 | After years of careful investigation, you have reached the gate to Loki's vault in the icy mountains of Norway, where it is said that many great treasures and powerful weapons are hidden. The gate seems unbreakable, but you spot some ancient machinery with inscriptions in old runes. After some help from ChatGPT, you are able to translate the symbols and the whole message into modern English, and it reads: 4 | 5 | If you can prove that the polynomial 6 | 7 | $$ 8 | \begin{aligned} 9 | p(x) &= 69 +78x + 32x^2 + 65x^3 + 82x^4 + 71x^5 + 69x^6 + 78x^7 + 84x^8 + 73x^9 \newline &+78x^{10} + 65x^{11} + 32x^{12} + 78x^{13} + 65x^{14}+ 67x^{15} + 73x^{16} + 32x^{17} \newline 10 | &+ 84x^{18} + 73x^{19} + 69x^{20} + 82x^{21} + 82x^{22} + 65 x^{23} 11 | \end{aligned} 12 | $$ 13 | 14 | is equal to $3$ at $x = 1$ modulo the BLS12-381 $r$ parameter, then the gate will open. 15 | 16 | Below is a long list of bytes representing the SRS that can be used to perform KZG commitments. The machinery, after careful examination, performs the KZG verification using pairings. There is only one open place where you can place a wooden tablet with your answer, comprising 48 bytes. You guess this should be the proof of the KZG scheme, providing the point in compressed form, following the ZCash standard. The other elements contain the commitment to $p(x)$, the desired value $3$, and the point $x=1$. You ask ChatGPT for enlightenment, but it suddenly collapses and only shows the message: fatal error. Is this just an impossible task? Perhaps there is some trick to get by Loki's challenge... -------------------------------------------------------------------------------- /crates/crypto/benches/iai_merkle.rs: -------------------------------------------------------------------------------- 1 | use core::hint::black_box; 2 | use lambdaworks_crypto::{ 3 | hash::sha3::Sha3Hasher, 4 | merkle_tree::{backends::field_element::FieldElementBackend, merkle::MerkleTree}, 5 | }; 6 | use lambdaworks_math::{ 7 | field::element::FieldElement, 8 | field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, 9 | }; 10 | use sha3::Keccak256; 11 | 12 | type F = Stark252PrimeField; 13 | type FE = FieldElement; 14 | 15 | type TreeBackend = FieldElementBackend; 16 | 17 | #[inline(never)] 18 | #[export_name = "util::build_unhashed_leaves"] 19 | fn build_unhashed_leaves() -> Vec { 20 | // NOTE: the values to hash don't really matter, so let's go with the easy ones. 21 | core::iter::successors(Some(FE::zero()), |s| Some(s + FE::one())) 22 | // `(1 << 20) + 1` exploits worst cases in terms of rounding up to powers of 2. 23 | .take((1 << 20) + 1) 24 | .collect() 25 | } 26 | 27 | #[inline(never)] 28 | #[export_name = "util::build_hasher"] 29 | fn build_hasher() -> Box { 30 | Box::new(Sha3Hasher::new()) 31 | } 32 | 33 | #[inline(never)] 34 | fn merkle_tree_build_benchmark() { 35 | let unhashed_leaves = build_unhashed_leaves(); 36 | let result = black_box(MerkleTree::::build(black_box( 37 | &unhashed_leaves, 38 | ))); 39 | // Let's not count `drop` in our timings. 40 | core::mem::drop(result); 41 | } 42 | 43 | iai_callgrind::main!( 44 | callgrind_args = "toggle-collect=util::*,core::mem::drop"; 45 | functions = merkle_tree_build_benchmark, 46 | ); 47 | -------------------------------------------------------------------------------- /fuzz/README.md: -------------------------------------------------------------------------------- 1 | # Fuzzing 2 | There are three types of fuzzers distributed on different workspaces depending on the features (metal/cuda) they need. So you should make sure you cded into the right folder before running any of the commands. 3 | This directory contains three types of fuzzers distributed onto three different workspaces. `no_gpu_fuzz` and `metal_fuzz` both use `cargo-fuzz` and must be run with nightly, also the latter only runs on mac. `cuda_fuzz` runs on machines with nvida GPUs and uses `honggfuzz` which runs on most linux distros. 4 | 5 | ## Setup 6 | Run the following commands to get ready. 7 | 8 | ### cargo-fuzz 9 | * `cargo install cargo-fuzz` 10 | * `rustup toolchain install nightly` 11 | 12 | ### honggfuzz 13 | * `cargo install honggfuzz` 14 | * `apt install build-essential` 15 | * `apt-get install binutils-dev` 16 | * `sudo apt-get install libunwind-dev` 17 | * `sudo apt-get install lldb` 18 | 19 | ## Running the fuzzers 20 | * no_gpu & metal: `cargo +nightly fuzz run --fuzz-dir . ` 21 | * cuda: `cargo hfuzz run ` 22 | The targets can be found in the `fuzz_targets` directory. Normally the name of the file without the extension should work, if it doesn't, look up the name for that binary target in `Cargo.toml`. 23 | 24 | ## Debugging 25 | If a crash is found, an `artifacts/` or `hfuzz_workspace/cuda_fuzz` folder will be added, inside it you'll find the different reports. To get an lldb dump, run 26 | * no_gpu & metal: `cargo +nightly fuzz run --fuzz-dir . artifacts/` 27 | * cuda: `cargo hfuzz run-debug hfuzz_workspace/cuda_fuzz/` 28 | -------------------------------------------------------------------------------- /crates/math/src/field/fields/fft_friendly/u64_mersenne_montgomery_field.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | field::{ 3 | element::FieldElement, 4 | fields::montgomery_backed_prime_fields::{IsModulus, MontgomeryBackendPrimeField}, 5 | }, 6 | unsigned_integer::element::U64, 7 | }; 8 | 9 | pub type U64MontgomeryBackendPrimeField = MontgomeryBackendPrimeField; 10 | 11 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 12 | pub struct MontgomeryConfigMersenne31PrimeField; 13 | impl IsModulus for MontgomeryConfigMersenne31PrimeField { 14 | //Mersenne Prime p = 2^31 - 1 15 | const MODULUS: U64 = U64::from_u64(2147483647); 16 | } 17 | 18 | pub type Mersenne31MontgomeryPrimeField = 19 | U64MontgomeryBackendPrimeField; 20 | 21 | impl FieldElement { 22 | pub fn to_bytes_le(&self) -> [u8; 8] { 23 | let limbs = self.representative().limbs; 24 | limbs[0].to_le_bytes() 25 | } 26 | 27 | pub fn to_bytes_be(&self) -> [u8; 8] { 28 | let limbs = self.representative().limbs; 29 | limbs[0].to_be_bytes() 30 | } 31 | } 32 | 33 | #[allow(clippy::non_canonical_partial_ord_impl)] 34 | impl PartialOrd for FieldElement { 35 | fn partial_cmp(&self, other: &Self) -> Option { 36 | self.representative().partial_cmp(&other.representative()) 37 | } 38 | } 39 | 40 | impl Ord for FieldElement { 41 | fn cmp(&self, other: &Self) -> core::cmp::Ordering { 42 | self.representative().cmp(&other.representative()) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /crates/math/src/cyclic_group.rs: -------------------------------------------------------------------------------- 1 | use crate::unsigned_integer::traits::IsUnsignedInteger; 2 | 3 | pub trait IsGroup: Clone + PartialEq + Eq { 4 | /// Returns the neutral element of the group. The equality 5 | /// `neutral_element().operate_with(g) == g` must hold 6 | /// for every group element `g`. 7 | fn neutral_element() -> Self; 8 | 9 | /// Check if an element the neutral element. 10 | fn is_neutral_element(&self) -> bool { 11 | self == &Self::neutral_element() 12 | } 13 | 14 | /// Applies the group operation `times` times with itself 15 | /// The operation can be addition or multiplication depending on 16 | /// the notation of the particular group. 17 | fn operate_with_self(&self, mut exponent: T) -> Self { 18 | let mut result = Self::neutral_element(); 19 | let mut base = self.clone(); 20 | 21 | while exponent != T::from(0) { 22 | if exponent & T::from(1) == T::from(1) { 23 | result = Self::operate_with(&result, &base); 24 | } 25 | exponent >>= 1; 26 | base = Self::operate_with(&base, &base); 27 | } 28 | result 29 | } 30 | 31 | /// Applies the group operation between `self` and `other`. 32 | /// The operation can be addition or multiplication depending on 33 | /// the notation of the particular group. 34 | fn operate_with(&self, other: &Self) -> Self; 35 | 36 | /// Provides the inverse of the group element. 37 | /// This is the unique y such that for any x 38 | /// x.operate_with(y) returns the neutral element 39 | fn neg(&self) -> Self; 40 | } 41 | -------------------------------------------------------------------------------- /fuzz/cuda_fuzz/src/cuda_fft_fuzzer.rs: -------------------------------------------------------------------------------- 1 | #[macro_use] 2 | extern crate honggfuzz; 3 | use lambdaworks_math::{ 4 | fft::{ 5 | gpu::cuda::{ops::fft as fft_cuda, state::CudaState}, 6 | cpu::{ 7 | roots_of_unity::get_twiddles, 8 | ops::fft as fft_cpu 9 | } 10 | }, 11 | field::{ 12 | traits::RootsConfig, 13 | fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, 14 | element::FieldElement 15 | }, 16 | }; 17 | 18 | 19 | fn main() { 20 | loop { 21 | fuzz!(|data: Vec| { 22 | let mut input_raw = data; 23 | let mut inputs = Vec::new(); 24 | 25 | if input_raw.len() == 0 { 26 | input_raw.push(0u64); 27 | } 28 | 29 | for i in 0..input_raw.len() { 30 | let input_value = format!("{:x}", input_raw[i]); 31 | inputs.push(FieldElement::::from_hex_unchecked(&input_value)) 32 | } 33 | 34 | let twiddles = get_twiddles( 35 | inputs.len().trailing_zeros() as u64, 36 | RootsConfig::BitReverse, 37 | ) 38 | .unwrap(); 39 | 40 | let state = CudaState::new().unwrap(); 41 | println!("inputs {:?}", &inputs); 42 | println!("fft cpu{:?}", fft_cpu(&inputs, &twiddles)); 43 | 44 | match fft_cpu(&inputs, &twiddles) { 45 | Ok(fft_result) => assert_eq!(fft_result, fft_cuda(&inputs, &twiddles, &state).unwrap()), 46 | Err(_) => assert!(fft_cuda(&inputs, &twiddles, &state).is_err()) 47 | } 48 | }); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /crates/math/benches/criterion_field.rs: -------------------------------------------------------------------------------- 1 | use criterion::{criterion_group, criterion_main, Criterion}; 2 | use pprof::criterion::{Output, PProfProfiler}; 3 | 4 | mod fields; 5 | use fields::mersenne31::{mersenne31_extension_ops_benchmarks, mersenne31_ops_benchmarks}; 6 | use fields::mersenne31_montgomery::mersenne31_mont_ops_benchmarks; 7 | use fields::{ 8 | baby_bear::{ 9 | babybear_extension_ops_benchmarks_p3, babybear_p3_ops_benchmarks, 10 | babybear_u32_extension_ops_benchmarks, babybear_u32_ops_benchmarks, 11 | babybear_u64_extension_ops_benchmarks, babybear_u64_ops_benchmarks, 12 | }, 13 | binary::binary_ops_benchmarks, 14 | stark252::starkfield_ops_benchmarks, 15 | u64_goldilocks::u64_goldilocks_ops_benchmarks, 16 | u64_goldilocks_montgomery::u64_goldilocks_montgomery_ops_benchmarks, 17 | }; 18 | 19 | criterion_group!( 20 | name = field_benches; 21 | config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); 22 | 23 | targets = babybear_u32_ops_benchmarks, 24 | babybear_u32_extension_ops_benchmarks, 25 | babybear_u64_ops_benchmarks, 26 | babybear_u64_extension_ops_benchmarks, 27 | babybear_p3_ops_benchmarks, 28 | babybear_extension_ops_benchmarks_p3, 29 | binary_ops_benchmarks, 30 | mersenne31_ops_benchmarks, 31 | mersenne31_extension_ops_benchmarks, 32 | mersenne31_mont_ops_benchmarks, 33 | starkfield_ops_benchmarks, 34 | u64_goldilocks_ops_benchmarks, 35 | u64_goldilocks_montgomery_ops_benchmarks, 36 | ); 37 | criterion_main!(field_benches); 38 | -------------------------------------------------------------------------------- /crates/math/src/fft/cpu/bit_reversing.rs: -------------------------------------------------------------------------------- 1 | /// In-place bit-reverse permutation algorithm. Requires input length to be a power of two. 2 | pub fn in_place_bit_reverse_permute(input: &mut [E]) { 3 | for i in 0..input.len() { 4 | let bit_reversed_index = reverse_index(i, input.len() as u64); 5 | if bit_reversed_index > i { 6 | input.swap(i, bit_reversed_index); 7 | } 8 | } 9 | } 10 | 11 | /// Reverses the `log2(size)` first bits of `i` 12 | pub fn reverse_index(i: usize, size: u64) -> usize { 13 | if size == 1 { 14 | i 15 | } else { 16 | i.reverse_bits() >> (usize::BITS - size.trailing_zeros()) 17 | } 18 | } 19 | 20 | #[cfg(all(test, feature = "alloc"))] 21 | mod test { 22 | use super::*; 23 | use alloc::vec::Vec; 24 | 25 | // TODO: proptest would be better. 26 | #[test] 27 | fn bit_reverse_permutation_works() { 28 | let mut reversed: Vec = Vec::with_capacity(16); 29 | for i in 0..reversed.capacity() { 30 | reversed.push(reverse_index(i, reversed.capacity() as u64)); 31 | } 32 | assert_eq!( 33 | reversed[..], 34 | [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15] 35 | ); 36 | 37 | in_place_bit_reverse_permute(&mut reversed[..]); 38 | assert_eq!( 39 | reversed[..], 40 | [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] 41 | ); 42 | } 43 | 44 | #[test] 45 | fn bit_reverse_permutation_edge_case() { 46 | let mut edge_case = [0]; 47 | 48 | in_place_bit_reverse_permute(&mut edge_case[..]); 49 | assert_eq!(edge_case[..], [0]); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | We take the security of our project seriously. If you discover a vulnerability, we encourage you to report it responsibly so we can address it promptly. 6 | 7 | ### How to Report 8 | 9 | 1. Navigate to the **Security** tab of this repository. 10 | 2. Click on **"Report a Vulnerability"** to open the GitHub Security Advisories form. 11 | 3. Fill out the form with as much detail as possible, including: 12 | - A clear description of the issue. 13 | - Steps to reproduce the vulnerability. 14 | - The affected versions or components. 15 | - Any potential impact or severity details. 16 | 17 | Alternatively, you can send an email to **[security@lambdaclass.com](mailto:security@lambdaclass.com)** with the same details. 18 | 19 | ### Guidelines for Reporting 20 | 21 | - **Do not publicly disclose vulnerabilities** until we have confirmed and fixed the issue. 22 | - Include any proof-of-concept code, if possible, to help us verify the vulnerability more efficiently. 23 | - If applicable, specify if the vulnerability is already being exploited. 24 | 25 | ### Our Response Process 26 | 27 | - We commit to handling reports with diligence. 28 | - We will investigate all reported vulnerabilities thoroughly and transparently. 29 | - Once the vulnerability has been fixed, we will disclose the details publicly to ensure awareness and understanding. 30 | 31 | 32 | ### Reward Program 33 | 34 | While we do not currently offer a formal bug bounty program, we value your contribution and will recognize your efforts in our changelog or release notes (if you consent). 35 | 36 | Thank you for helping us improve the security of our project! 37 | -------------------------------------------------------------------------------- /crates/crypto/src/commitments/traits.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_math::{ 2 | field::{element::FieldElement, traits::IsField}, 3 | polynomial::Polynomial, 4 | }; 5 | 6 | pub trait IsCommitmentScheme { 7 | type Commitment; 8 | 9 | /// Create a commitment to a polynomial 10 | fn commit(&self, p: &Polynomial>) -> Self::Commitment; 11 | 12 | /// Create an evaluation proof for a polynomial at x equal to y 13 | /// p(x) = y 14 | fn open( 15 | &self, 16 | x: &FieldElement, 17 | y: &FieldElement, 18 | p: &Polynomial>, 19 | ) -> Self::Commitment; 20 | 21 | /// Create an evaluation proof for a slice of polynomials at x equal to y_i 22 | /// that is, we show that we evaluated correctly p_i (x) = y_i 23 | fn open_batch( 24 | &self, 25 | x: &FieldElement, 26 | y: &[FieldElement], 27 | p: &[Polynomial>], 28 | upsilon: &FieldElement, 29 | ) -> Self::Commitment; 30 | 31 | /// Verify an evaluation proof given the commitment to p, the point x and the evaluation y 32 | fn verify( 33 | &self, 34 | x: &FieldElement, 35 | y: &FieldElement, 36 | p_commitment: &Self::Commitment, 37 | proof: &Self::Commitment, 38 | ) -> bool; 39 | 40 | /// Verify an evaluation proof given the commitments to p, the point x and the evaluations ys 41 | fn verify_batch( 42 | &self, 43 | x: &FieldElement, 44 | ys: &[FieldElement], 45 | p_commitments: &[Self::Commitment], 46 | proof: &Self::Commitment, 47 | upsilon: &FieldElement, 48 | ) -> bool; 49 | } 50 | -------------------------------------------------------------------------------- /crates/provers/plonk/src/constraint_system/examples/pow.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_math::field::{element::FieldElement as FE, traits::IsPrimeField}; 2 | 3 | use crate::constraint_system::{ConstraintSystem, Variable}; 4 | 5 | /// A square and multiply implementation. 6 | pub fn pow( 7 | system: &mut ConstraintSystem, 8 | base: Variable, 9 | exponent: Variable, 10 | ) -> Variable { 11 | let exponent_bits = system.new_u32(&exponent); 12 | let mut result = system.new_constant(FE::one()); 13 | 14 | assert_eq!(exponent_bits.len(), 32); 15 | for (i, bit) in exponent_bits.iter().enumerate() { 16 | if i != 0 { 17 | result = system.mul(&result, &result); 18 | } 19 | let result_times_base = system.mul(&result, &base); 20 | result = system.if_else(bit, &result_times_base, &result); 21 | } 22 | result 23 | } 24 | 25 | #[cfg(test)] 26 | mod tests { 27 | use std::collections::HashMap; 28 | 29 | use lambdaworks_math::field::fields::u64_prime_field::U64PrimeField; 30 | 31 | use crate::constraint_system::{examples::pow::pow, ConstraintSystem}; 32 | use lambdaworks_math::field::element::FieldElement as FE; 33 | 34 | #[test] 35 | fn test_pow() { 36 | let system = &mut ConstraintSystem::>::new(); 37 | 38 | let base = system.new_variable(); 39 | let exponent = system.new_variable(); 40 | let result = pow(system, base, exponent); 41 | let inputs = HashMap::from([(base, FE::from(3)), (exponent, FE::from(10))]); 42 | 43 | let assignments = system.solve(inputs).unwrap(); 44 | assert_eq!(assignments.get(&result).unwrap(), &FE::from(59049)); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /crates/crypto/src/hash/monolith/utils.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | use lambdaworks_math::field::{ 3 | fields::mersenne31::field::{Mersenne31Field, MERSENNE_31_PRIME_FIELD_ORDER}, 4 | traits::IsField, 5 | }; 6 | use sha3::{digest::XofReader, Shake128Reader}; 7 | 8 | // Ported from https://github.com/Plonky3/Plonky3/blob/main/monolith 9 | 10 | pub type F = Mersenne31Field; 11 | 12 | pub fn random_matrix(shake: &mut Shake128Reader, n: usize, m: usize) -> Vec> { 13 | (0..n) 14 | .map(|_| (0..m).map(|_| random_field_element(shake)).collect()) 15 | .collect() 16 | } 17 | 18 | fn random_field_element(shake: &mut Shake128Reader) -> u32 { 19 | let mut val = shake_random_u32(shake); 20 | while val >= MERSENNE_31_PRIME_FIELD_ORDER { 21 | val = shake_random_u32(shake); 22 | } 23 | F::from_base_type(val) 24 | } 25 | 26 | pub fn dot_product(u: &[u32], v: &[u32]) -> u32 { 27 | Mersenne31Field::sum(u.iter().zip(v).map(|(x, y)| F::mul(x, y))) 28 | } 29 | 30 | pub fn get_random_y_i( 31 | shake: &mut Shake128Reader, 32 | width: usize, 33 | x_mask: u32, 34 | y_mask: u32, 35 | ) -> Vec { 36 | let mut res = vec![0; width]; 37 | 38 | for i in 0..width { 39 | let mut y_i = shake_random_u32(shake) & y_mask; 40 | let mut x_i = y_i & x_mask; 41 | while res.iter().take(i).any(|r| r & x_mask == x_i) { 42 | y_i = shake_random_u32(shake) & y_mask; 43 | x_i = y_i & x_mask; 44 | } 45 | res[i] = y_i; 46 | } 47 | 48 | res 49 | } 50 | 51 | fn shake_random_u32(shake: &mut Shake128Reader) -> u32 { 52 | let mut rand = [0u8; 4]; 53 | shake.read(&mut rand); 54 | u32::from_le_bytes(rand) 55 | } 56 | -------------------------------------------------------------------------------- /benches/benches/mul.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | use std::ops::Mul; 3 | use utils::generate_random_elements; 4 | 5 | use crate::utils::to_lambdaworks_vec; 6 | 7 | pub mod utils; 8 | 9 | const BENCHMARK_NAME: &str = "mul"; 10 | 11 | pub fn criterion_benchmark(c: &mut Criterion) { 12 | let arkworks_vec = generate_random_elements(20000); 13 | 14 | // arkworks-ff 15 | { 16 | c.bench_function( 17 | &format!("{BENCHMARK_NAME} 10K elements | ark-ff - commit: ef8f758 "), 18 | |b| { 19 | b.iter(|| { 20 | let mut iter = arkworks_vec.iter(); 21 | 22 | for _i in 0..10000 { 23 | let a = iter.next().unwrap(); 24 | let b = iter.next().unwrap(); 25 | black_box(black_box(a).mul(black_box(b))); 26 | } 27 | }); 28 | }, 29 | ); 30 | } 31 | 32 | // lambdaworks-math 33 | { 34 | let lambdaworks_vec = to_lambdaworks_vec(&arkworks_vec); 35 | 36 | c.bench_function( 37 | &format!("{BENCHMARK_NAME} 10K elements | lambdaworks",), 38 | |b| { 39 | b.iter(|| { 40 | let mut iter = lambdaworks_vec.iter(); 41 | 42 | for _i in 0..10000 { 43 | let a = iter.next().unwrap(); 44 | let b = iter.next().unwrap(); 45 | black_box(black_box(&a).mul(black_box(b))); 46 | } 47 | }); 48 | }, 49 | ); 50 | } 51 | } 52 | 53 | criterion_group!(benches, criterion_benchmark); 54 | criterion_main!(benches); 55 | -------------------------------------------------------------------------------- /crates/crypto/src/fiat_shamir/is_transcript.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_math::{ 2 | field::{ 3 | element::FieldElement, 4 | traits::{IsField, IsSubFieldOf}, 5 | }, 6 | traits::AsBytes, 7 | }; 8 | 9 | /// The functionality of a transcript to be used in the STARK Prove and Verify protocols. 10 | pub trait IsTranscript { 11 | /// Appends a field element to the transcript. 12 | fn append_field_element(&mut self, element: &FieldElement); 13 | /// Appends a bytes to the transcript. 14 | fn append_bytes(&mut self, new_bytes: &[u8]); 15 | /// Returns the inner state of the transcript that fully determines its outputs. 16 | fn state(&self) -> [u8; 32]; 17 | /// Returns a random field element. 18 | fn sample_field_element(&mut self) -> FieldElement; 19 | /// Returns a random index between 0 and `upper_bound`. 20 | fn sample_u64(&mut self, upper_bound: u64) -> u64; 21 | /// Returns a field element not contained in `lde_roots_of_unity_coset` or `trace_roots_of_unity`. 22 | fn sample_z_ood>( 23 | &mut self, 24 | lde_roots_of_unity_coset: &[FieldElement], 25 | trace_roots_of_unity: &[FieldElement], 26 | ) -> FieldElement 27 | where 28 | FieldElement: AsBytes, 29 | { 30 | loop { 31 | let value: FieldElement = self.sample_field_element(); 32 | if !lde_roots_of_unity_coset 33 | .iter() 34 | .any(|x| x.clone().to_extension() == value) 35 | && !trace_roots_of_unity 36 | .iter() 37 | .any(|x| x.clone().to_extension() == value) 38 | { 39 | return value; 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /crates/math/benches/polynomials/sparse_multilinear_poly.rs: -------------------------------------------------------------------------------- 1 | use super::utils::{rand_field_elements, rand_sparse_multilinear_poly}; 2 | use const_random::const_random; 3 | use core::hint::black_box; 4 | use criterion::Criterion; 5 | use lambdaworks_math::polynomial::sparse_multilinear_poly::SparseMultilinearPolynomial; 6 | use rand::random; 7 | 8 | pub fn sparse_multilinear_polynomial_benchmarks(c: &mut Criterion) { 9 | let mut group = c.benchmark_group("Polynomial"); 10 | let order = const_random!(u64) % 8; 11 | let num_vars = [3, 4, 5, 6, 7, 8, 9, 10]; 12 | 13 | for num_var in num_vars.iter() { 14 | group.bench_with_input( 15 | format!("evaluate {:?}", &num_var), 16 | num_var, 17 | |bench, num_var| { 18 | let poly = rand_sparse_multilinear_poly(*num_var, order); 19 | let r = rand_field_elements(order); 20 | bench.iter(|| poly.evaluate(black_box(&r))); 21 | }, 22 | ); 23 | } 24 | 25 | for num_var in num_vars.iter() { 26 | group.bench_with_input( 27 | format!("evaluate_with {:?}", &num_var), 28 | num_var, 29 | |bench, num_var| { 30 | let evals = rand_field_elements(order) 31 | .into_iter() 32 | .map(|eval| (random(), eval)) 33 | .collect::>(); 34 | let r = rand_field_elements(order); 35 | bench.iter(|| { 36 | SparseMultilinearPolynomial::evaluate_with( 37 | black_box(*num_var), 38 | black_box(&evals), 39 | black_box(&r), 40 | ) 41 | }); 42 | }, 43 | ); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /crates/gpu/build.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "cuda")] 2 | fn compile_cuda_shaders() { 3 | use std::process::Command; 4 | use walkdir::WalkDir; 5 | let source_dir = "../math/src/gpu/cuda/shaders"; 6 | 7 | // Tell cargo to invalidate the built crate whenever the source changes 8 | println!("cargo:rerun-if-changed={source_dir}"); 9 | 10 | let children: Vec<_> = WalkDir::new(source_dir) 11 | .into_iter() 12 | .map(Result::unwrap) 13 | .filter(|entry| { 14 | entry 15 | .path() 16 | .extension() 17 | .map(|x| x == "cu") 18 | .unwrap_or_default() 19 | }) 20 | .map(|entry| { 21 | let mut out_path = entry.path().to_owned(); 22 | out_path.set_extension("ptx"); 23 | 24 | println!( 25 | "cargo:warning=compiling:'{}'->'{}'", 26 | entry.path().display(), 27 | out_path.display(), 28 | ); 29 | 30 | Command::new("nvcc") 31 | .arg("-ptx") 32 | .arg(entry.path()) 33 | .arg("-o") 34 | .arg(out_path) 35 | .spawn() 36 | .unwrap() 37 | }) 38 | .collect(); 39 | 40 | children.into_iter().for_each(|child| { 41 | let res = child.wait_with_output().unwrap(); 42 | if !res.status.success() { 43 | println!(); 44 | println!("{}", String::from_utf8(res.stdout).unwrap()); 45 | println!(); 46 | eprintln!("{}", String::from_utf8(res.stderr).unwrap()); 47 | println!(); 48 | panic!("Compilation failed"); 49 | } 50 | }); 51 | } 52 | 53 | fn main() { 54 | #[cfg(feature = "cuda")] 55 | compile_cuda_shaders(); 56 | } 57 | -------------------------------------------------------------------------------- /crates/crypto/src/hash/pedersen/parameters.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_math::elliptic_curve::short_weierstrass::traits::IsShortWeierstrass; 2 | use lambdaworks_math::elliptic_curve::short_weierstrass::{ 3 | curves::stark_curve::StarkCurve, point::ShortWeierstrassProjectivePoint as Point, 4 | }; 5 | use lambdaworks_math::elliptic_curve::traits::IsEllipticCurve; 6 | use lambdaworks_math::field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField; 7 | use lambdaworks_math::field::traits::IsPrimeField; 8 | 9 | use crate::hash::pedersen::constants::*; 10 | 11 | pub trait PedersenParameters { 12 | type F: IsPrimeField + Clone; 13 | type EC: IsEllipticCurve + IsShortWeierstrass + Clone; 14 | 15 | const CURVE_CONST_BITS: usize; 16 | const TABLE_SIZE: usize; 17 | const SHIFT_POINT: Point; 18 | const POINTS_P1: [Point; 930]; 19 | const POINTS_P2: [Point; 15]; 20 | const POINTS_P3: [Point; 930]; 21 | const POINTS_P4: [Point; 15]; 22 | } 23 | 24 | pub struct PedersenStarkCurve; 25 | 26 | impl Default for PedersenStarkCurve { 27 | fn default() -> Self { 28 | Self::new() 29 | } 30 | } 31 | 32 | impl PedersenStarkCurve { 33 | pub fn new() -> Self { 34 | Self {} 35 | } 36 | } 37 | 38 | impl PedersenParameters for PedersenStarkCurve { 39 | type F = Stark252PrimeField; 40 | type EC = StarkCurve; 41 | 42 | const CURVE_CONST_BITS: usize = 4; 43 | const TABLE_SIZE: usize = (1 << Self::CURVE_CONST_BITS) - 1; 44 | const SHIFT_POINT: Point = shift_point(); 45 | const POINTS_P1: [Point; 930] = points_p1(); 46 | const POINTS_P2: [Point; 15] = points_p2(); 47 | const POINTS_P3: [Point; 930] = points_p3(); 48 | const POINTS_P4: [Point; 15] = points_p4(); 49 | } 50 | -------------------------------------------------------------------------------- /crates/math/benches/iai_field.rs: -------------------------------------------------------------------------------- 1 | use criterion::black_box; 2 | use utils::u64_utils; 3 | 4 | mod utils; 5 | 6 | #[inline(never)] 7 | fn fp_add_benchmarks() { 8 | let (x, y) = u64_utils::get_field_elements(); 9 | let _ = black_box(black_box(x) + black_box(y)); 10 | } 11 | 12 | #[inline(never)] 13 | fn fp_mul_benchmarks() { 14 | let (x, y) = u64_utils::get_field_elements(); 15 | let _ = black_box(black_box(x) * black_box(y)); 16 | } 17 | 18 | #[inline(never)] 19 | fn fp_pow_benchmarks() { 20 | let (x, _) = u64_utils::get_field_elements(); 21 | let y: u64 = 5; 22 | let _ = black_box(black_box(x).pow(black_box(y))); 23 | } 24 | 25 | #[inline(never)] 26 | fn fp_sub_benchmarks() { 27 | let (x, y) = u64_utils::get_field_elements(); 28 | let _ = black_box(black_box(x) - black_box(y)); 29 | } 30 | 31 | #[inline(never)] 32 | fn fp_inv_benchmarks() { 33 | let (x, _) = u64_utils::get_field_elements(); 34 | let _ = black_box(black_box(x).inv()); 35 | } 36 | 37 | #[inline(never)] 38 | fn fp_div_benchmarks() { 39 | let (x, y) = u64_utils::get_field_elements(); 40 | let _ = black_box(black_box(x) / black_box(y)); 41 | } 42 | 43 | #[inline(never)] 44 | fn fp_eq_benchmarks() { 45 | let (x, y) = u64_utils::get_field_elements(); 46 | let _ = black_box(black_box(x) == black_box(y)); 47 | } 48 | 49 | #[inline(never)] 50 | fn fp_sqrt_benchmarks() { 51 | // Make sure it has a square root 52 | let x = u64_utils::get_squared_field_element(); 53 | let _ = black_box(black_box(x).sqrt()); 54 | } 55 | 56 | iai_callgrind::main!( 57 | callgrind_args = "toggle-collect=util::*"; 58 | functions = fp_add_benchmarks, 59 | fp_mul_benchmarks, 60 | fp_pow_benchmarks, 61 | fp_sub_benchmarks, 62 | fp_inv_benchmarks, 63 | fp_div_benchmarks, 64 | fp_eq_benchmarks, 65 | fp_sqrt_benchmarks, 66 | ); 67 | -------------------------------------------------------------------------------- /fuzz/no_gpu_fuzz/fuzz_targets/curve/curve_grumpkin.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use libfuzzer_sys::fuzz_target; 4 | use lambdaworks_math::{ 5 | cyclic_group::IsGroup, 6 | elliptic_curve::{ 7 | traits::{IsEllipticCurve, IsPairing}, 8 | short_weierstrass::{ 9 | curves::grumpkin::curve::GrumpkinCurve, 10 | point::ShortWeierstrassProjectivePoint, 11 | } 12 | }, 13 | field::element::FieldElement, 14 | }; 15 | 16 | type LambdaG1 = ShortWeierstrassProjectivePoint; 17 | 18 | //TODO: derive arbitrary for Affine and Projective or change this to use &[u8] as input to cover more cases 19 | fuzz_target!(|values: (u64, u64)| { 20 | let (a_val, b_val) = values; 21 | 22 | let a_g1 = GrumpkinCurve::generator().operate_with_self(a_val); 23 | let b_g1 = GrumpkinCurve::generator().operate_with_self(b_val); 24 | 25 | // ***AXIOM SOUNDNESS*** 26 | let g1_zero = LambdaG1::neutral_element(); 27 | 28 | // -O = O 29 | assert_eq!(g1_zero.neg(), g1_zero, "Neutral mul element a failed"); 30 | 31 | // P * O = O 32 | assert_eq!(a_g1.operate_with(&g1_zero), a_g1, "Neutral operate_with element a failed"); 33 | assert_eq!(b_g1.operate_with(&g1_zero), b_g1, "Neutral operate_with element b failed"); 34 | 35 | // P * Q = Q * P 36 | assert_eq!(a_g1.operate_with(&b_g1), b_g1.operate_with(&a_g1), "Commutative add property failed"); 37 | 38 | // (P * Q) * R = Q * (P * R) 39 | let c_g1 = a_g1.operate_with(&b_g1); 40 | assert_eq!((a_g1.operate_with(&b_g1)).operate_with(&c_g1), a_g1.operate_with(&b_g1.operate_with(&c_g1)), "Associative operate_with property failed"); 41 | 42 | // P * -P = O 43 | assert_eq!(a_g1.operate_with(&a_g1.neg()), g1_zero, "Inverse add a failed"); 44 | assert_eq!(b_g1.operate_with(&b_g1.neg()), g1_zero, "Inverse add b failed"); 45 | }); 46 | -------------------------------------------------------------------------------- /benches/benches/sqrt.rs: -------------------------------------------------------------------------------- 1 | use ark_ff::Field; 2 | use ark_std::UniformRand; 3 | use ark_test_curves::starknet_fp::Fq as F; 4 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 5 | 6 | use crate::utils::to_lambdaworks_vec; 7 | 8 | pub mod utils; 9 | 10 | const BENCHMARK_NAME: &str = "sqrt"; 11 | 12 | pub fn criterion_benchmark(c: &mut Criterion) { 13 | let mut rng = ::seed_from_u64(9001); 14 | 15 | let mut arkworks_vec = Vec::new(); 16 | for _i in 0..100 { 17 | let a = F::rand(&mut rng); 18 | let square = a * a; 19 | arkworks_vec.push(square); 20 | } 21 | 22 | // arkworks-ff 23 | { 24 | c.bench_function( 25 | &format!("{BENCHMARK_NAME} 100 elements | ark-ff - ef8f758"), 26 | |b| { 27 | b.iter(|| { 28 | let mut iter = arkworks_vec.iter(); 29 | 30 | for _i in 0..100 { 31 | let a = iter.next().unwrap(); 32 | black_box(black_box(a).sqrt()); 33 | } 34 | }); 35 | }, 36 | ); 37 | } 38 | 39 | // lambdaworks-math 40 | { 41 | let lambdaworks_vec = to_lambdaworks_vec(&arkworks_vec); 42 | 43 | c.bench_function( 44 | &format!("{BENCHMARK_NAME} 100 elements | lambdaworks",), 45 | |b| { 46 | b.iter(|| { 47 | let mut iter = lambdaworks_vec.iter(); 48 | 49 | for _i in 0..100 { 50 | let a = iter.next().unwrap(); 51 | black_box(black_box(a).sqrt()); 52 | } 53 | }); 54 | }, 55 | ); 56 | } 57 | } 58 | 59 | criterion_group!(benches, criterion_benchmark); 60 | criterion_main!(benches); 61 | -------------------------------------------------------------------------------- /crates/math/benches/polynomials/dense_multilinear_poly.rs: -------------------------------------------------------------------------------- 1 | use super::utils::{rand_dense_multilinear_poly, rand_field_elements, FE}; 2 | use const_random::const_random; 3 | use core::hint::black_box; 4 | use criterion::Criterion; 5 | use lambdaworks_math::polynomial::dense_multilinear_poly::DenseMultilinearPolynomial; 6 | 7 | pub fn dense_multilinear_polynomial_benchmarks(c: &mut Criterion) { 8 | let mut group = c.benchmark_group("Polynomial"); 9 | let order = const_random!(u64) % 8; 10 | 11 | group.bench_function("evaluate", |bench| { 12 | let poly = rand_dense_multilinear_poly(order); 13 | let r = rand_field_elements(order); 14 | bench.iter(|| poly.evaluate(black_box(r.clone()))); 15 | }); 16 | 17 | group.bench_function("evaluate_with", |bench| { 18 | let evals = rand_field_elements(order); 19 | let r = rand_field_elements(order); 20 | 21 | bench.iter(|| DenseMultilinearPolynomial::evaluate_with(black_box(&evals), black_box(&r))); 22 | }); 23 | 24 | group.bench_function("merge", |bench| { 25 | let x_poly = rand_dense_multilinear_poly(order); 26 | let y_poly = rand_dense_multilinear_poly(order); 27 | bench.iter(|| { 28 | DenseMultilinearPolynomial::merge(black_box(&[x_poly.clone(), y_poly.clone()])) 29 | }); 30 | }); 31 | 32 | group.bench_function("add", |bench| { 33 | let x_poly = rand_dense_multilinear_poly(order); 34 | let y_poly = rand_dense_multilinear_poly(order); 35 | bench.iter(|| black_box(black_box(x_poly.clone()) + black_box(y_poly.clone()))); 36 | }); 37 | 38 | group.bench_function("mul", |bench| { 39 | let x_poly = rand_dense_multilinear_poly(order); 40 | let y = FE::new(rand::random::()); 41 | bench.iter(|| black_box(black_box(x_poly.clone()) * black_box(y))); 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/edwards/curves/tiny_jub_jub.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | elliptic_curve::{ 3 | edwards::{point::EdwardsProjectivePoint, traits::IsEdwards}, 4 | traits::IsEllipticCurve, 5 | }, 6 | field::{element::FieldElement, fields::u64_prime_field::U64PrimeField}, 7 | }; 8 | 9 | /// Taken from moonmath manual page 97 10 | #[derive(Debug, Clone)] 11 | pub struct TinyJubJubEdwards; 12 | 13 | impl IsEllipticCurve for TinyJubJubEdwards { 14 | type BaseField = U64PrimeField<13>; 15 | type PointRepresentation = EdwardsProjectivePoint; 16 | 17 | /// Returns the generator point of the TinyJubJub Edwards curve. 18 | /// 19 | /// This generator is taken from **Moonmath Manual (page 97)**. 20 | /// 21 | /// # Safety 22 | /// 23 | /// - The generator coordinates `(8, 5, 1)` are **predefined** and belong to the TinyJubJub curve. 24 | /// - `unwrap()` is used because the generator is a **verified valid point**, 25 | /// meaning there is **no risk** of runtime failure. 26 | /// - This function must **not** be modified unless the new generator is mathematically verified. 27 | fn generator() -> Self::PointRepresentation { 28 | // SAFETY: 29 | // - The generator point `(8, 5, 1)` is **mathematically valid** on the curve. 30 | // - `unwrap()` is safe because we **know** the point satisfies the curve equation. 31 | let point = Self::PointRepresentation::new([ 32 | FieldElement::from(8), 33 | FieldElement::from(5), 34 | FieldElement::one(), 35 | ]); 36 | point.unwrap() 37 | } 38 | } 39 | 40 | impl IsEdwards for TinyJubJubEdwards { 41 | fn a() -> FieldElement { 42 | FieldElement::from(3) 43 | } 44 | 45 | fn d() -> FieldElement { 46 | FieldElement::from(8) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/montgomery/curves/tiny_jub_jub.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | elliptic_curve::{ 3 | montgomery::{point::MontgomeryProjectivePoint, traits::IsMontgomery}, 4 | traits::IsEllipticCurve, 5 | }, 6 | field::{element::FieldElement, fields::u64_prime_field::U64PrimeField}, 7 | }; 8 | 9 | /// Taken from moonmath manual page 91 10 | #[derive(Debug, Clone)] 11 | pub struct TinyJubJubMontgomery; 12 | 13 | impl IsEllipticCurve for TinyJubJubMontgomery { 14 | type BaseField = U64PrimeField<13>; 15 | type PointRepresentation = MontgomeryProjectivePoint; 16 | 17 | /// Returns the generator point of the TinyJubJub Montgomery curve. 18 | /// 19 | /// This generator is taken from **Moonmath Manual (page 91)**. 20 | /// 21 | /// # Safety 22 | /// 23 | /// - The generator coordinates `(3, 5, 1)` are **predefined** and are **valid** points 24 | /// on the TinyJubJub Montgomery curve. 25 | /// - `unwrap()` is used because the generator is **guaranteed** to satisfy 26 | /// the Montgomery curve equation. 27 | /// - This function must **not** be modified unless the new generator is mathematically verified. 28 | fn generator() -> Self::PointRepresentation { 29 | // SAFETY: 30 | // - The generator point `(3, 5, 1)` is **mathematically verified**. 31 | // - `unwrap()` is safe because the input values **guarantee** validity. 32 | let point = Self::PointRepresentation::new([ 33 | FieldElement::from(3), 34 | FieldElement::from(5), 35 | FieldElement::one(), 36 | ]); 37 | point.unwrap() 38 | } 39 | } 40 | 41 | impl IsMontgomery for TinyJubJubMontgomery { 42 | fn a() -> FieldElement { 43 | FieldElement::from(6) 44 | } 45 | 46 | fn b() -> FieldElement { 47 | FieldElement::from(7) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /benches/benches/sub.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | use std::{ops::Sub, time::Duration}; 3 | use utils::{generate_random_elements, to_lambdaworks_vec}; 4 | 5 | pub mod utils; 6 | 7 | const BENCHMARK_NAME: &str = "sub"; 8 | 9 | pub fn criterion_benchmark(c: &mut Criterion) { 10 | let arkworks_vec = generate_random_elements(2000000); 11 | 12 | // arkworks-ff 13 | { 14 | c.bench_function( 15 | &format!("{BENCHMARK_NAME} 1M elements | ark-ff - ef8f758"), 16 | |b| { 17 | b.iter(|| { 18 | let mut iter = arkworks_vec.iter(); 19 | 20 | for _i in 0..1000000 { 21 | let a = iter.next().unwrap(); 22 | let b = iter.next().unwrap(); 23 | black_box(black_box(&a).sub(black_box(b))); 24 | } 25 | }); 26 | }, 27 | ); 28 | } 29 | 30 | // lambdaworks-math 31 | { 32 | let lambdaworks_vec = to_lambdaworks_vec(&arkworks_vec); 33 | c.bench_function( 34 | &format!("{BENCHMARK_NAME} 1M elements | lambdaworks",), 35 | |b| { 36 | b.iter(|| { 37 | let mut iter = lambdaworks_vec.iter(); 38 | 39 | for _i in 0..1000000 { 40 | let a = iter.next().unwrap(); 41 | let b = iter.next().unwrap(); 42 | black_box(black_box(&a).sub(black_box(b))); 43 | } 44 | }); 45 | }, 46 | ); 47 | } 48 | } 49 | 50 | criterion_group! { 51 | name = benches; 52 | config = Criterion::default() 53 | .significance_level(0.01) 54 | .measurement_time(Duration::from_secs(15)) 55 | .sample_size(500); 56 | targets = criterion_benchmark 57 | } 58 | criterion_main!(benches); 59 | -------------------------------------------------------------------------------- /crates/math/benches/utils/u64_goldilocks_utils.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_math::{ 2 | field::element::FieldElement, 3 | field::fields::fft_friendly::u64_goldilocks::U64GoldilocksPrimeField, polynomial::Polynomial, 4 | }; 5 | use rand::random; 6 | 7 | pub type FE = FieldElement; 8 | 9 | #[inline(never)] 10 | #[export_name = "u64_utils::fp_get_goldilocks_primes"] 11 | pub fn get_field_elements() -> ( 12 | FieldElement, 13 | FieldElement, 14 | ) { 15 | let x = FieldElement::::from_hex( 16 | "0x03d937c035c878245caf64531a5756109c53068da139362728feb561405371cb", 17 | ) 18 | .unwrap(); 19 | let y = FieldElement::::from_hex( 20 | "0x0208a0a10250e382e1e4bbe2880906c2791bf6275695e02fbbc6aeff9cd8b31a", 21 | ) 22 | .unwrap(); 23 | (x, y) 24 | } 25 | 26 | #[inline(never)] 27 | #[export_name = "u64_utils::fp_squared_goldilocks_prime"] 28 | pub fn get_squared_field_element() -> FieldElement { 29 | let (x, _) = get_field_elements(); 30 | x * x 31 | } 32 | 33 | #[allow(dead_code)] 34 | #[inline(never)] 35 | #[export_name = "u64_utils::rand_field_goldilocks_elements"] 36 | pub fn rand_field_elements(order: u64) -> Vec { 37 | let mut result = Vec::with_capacity(1 << order); 38 | for _ in 0..result.capacity() { 39 | result.push(FE::from(random::())); 40 | } 41 | result 42 | } 43 | 44 | #[allow(dead_code)] 45 | #[inline(never)] 46 | #[export_name = "u64_utils::rand_goldilocks_field_elements_pair"] 47 | pub fn rand_field_elements_pair() -> (FE, FE) { 48 | (FE::from(random::()), FE::from(random::())) 49 | } 50 | 51 | #[allow(dead_code)] 52 | #[inline(never)] 53 | #[export_name = "u64_utils::rand_goldilocks_poly"] 54 | pub fn rand_poly(order: u64) -> Polynomial { 55 | Polynomial::new(&rand_field_elements(order)) 56 | } 57 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: test clippy docker-shell nix-shell benchmarks benchmark docs build-cuda coverage clean 2 | 3 | FUZZ_DIR = fuzz/no_gpu_fuzz 4 | 5 | ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) 6 | 7 | test: 8 | cargo test 9 | 10 | clippy: 11 | cargo clippy --workspace --all-targets -- -D warnings 12 | cargo clippy --workspace --all-targets --features wasm -- -D warnings 13 | cargo clippy --workspace --all-targets --features parallel -- -D warnings 14 | cargo clippy --tests 15 | 16 | clippy-cuda: 17 | cargo clippy --workspace -F cuda -- -D warnings 18 | 19 | docker-shell: 20 | docker build -t rust-curves . 21 | docker run -it rust-curves bash 22 | 23 | nix-shell: 24 | nix-shell 25 | 26 | benchmarks: 27 | cargo criterion --workspace 28 | 29 | # BENCHMARK should be one of the [[bench]] names in Cargo.toml 30 | benchmark: 31 | cargo criterion --bench ${BENCH} 32 | 33 | flamegraph_stark: 34 | CARGO_PROFILE_BENCH_DEBUG=true cargo flamegraph --root --bench stark_benchmarks -- --bench 35 | 36 | coverage: 37 | cargo llvm-cov nextest --lcov --output-path lcov.info 38 | 39 | CUDA_DIR = math/src/gpu/cuda/shaders 40 | CUDA_FILES:=$(wildcard $(CUDA_DIR)/**/*.cu) 41 | CUDA_COMPILED:=$(patsubst $(CUDA_DIR)/%.cu, $(CUDA_DIR)/%.ptx, $(CUDA_FILES)) 42 | CUDA_HEADERS:=$(wildcard $(CUDA_DIR)/**/*.cuh) 43 | 44 | $(CUDA_DIR)/%.ptx: $(CUDA_DIR)/%.cu $(CUDA_HEADERS) 45 | nvcc -ptx $< -o $@ 46 | 47 | # This part compiles all .cu files in $(CUDA_DIR) 48 | build-cuda: $(CUDA_COMPILED) 49 | 50 | CUDAPATH = math/src/gpu/cuda/shaders 51 | build-cuda: 52 | nvcc -ptx $(CUDAPATH)/field/stark256.cu -o $(CUDAPATH)/field/stark256.ptx 53 | 54 | docs: 55 | cd docs && mdbook serve --open 56 | 57 | run-fuzzer: 58 | cargo +nightly fuzz run --fuzz-dir $(FUZZ_DIR) $(FUZZER) 59 | 60 | proof-deserializer-fuzzer: 61 | cargo +nightly fuzz run --fuzz-dir $(FUZZ_DIR) deserialize_stark_proof 62 | 63 | run-cuda-fuzzer: 64 | cd fuzz/cuda_fuzz 65 | cargo hfuzz run $(CUDAFUZZER) 66 | -------------------------------------------------------------------------------- /examples/pinocchio/src/prover.rs: -------------------------------------------------------------------------------- 1 | use crate::common::{G1Point, G2Point, FE}; 2 | use crate::qap::QuadraticArithmeticProgram; 3 | use crate::setup::EvaluationKey; 4 | use lambdaworks_math::msm::pippenger::msm; 5 | 6 | pub struct Proof { 7 | pub v: G1Point, 8 | pub w1: G1Point, 9 | pub w2: G2Point, 10 | pub y: G1Point, 11 | pub h: G2Point, 12 | pub v_prime: G1Point, 13 | pub w_prime: G1Point, 14 | pub y_prime: G1Point, 15 | pub z: G1Point, 16 | } 17 | 18 | pub fn generate_proof( 19 | evaluation_key: &EvaluationKey, 20 | qap: &QuadraticArithmeticProgram, 21 | qap_c_coefficients: &[FE], 22 | ) -> Proof { 23 | let cmid = 24 | &qap_c_coefficients[qap.number_of_inputs..qap_c_coefficients.len() - qap.number_of_outputs]; 25 | // We transform each FieldElement of the cmid into an UnsignedInteger so we can multiply them to g1. 26 | let c_mid = cmid 27 | .iter() 28 | .map(|elem| elem.representative()) 29 | .collect::>(); 30 | 31 | let h_polynomial = qap.h_polynomial(qap_c_coefficients); 32 | // We transform h_polynomial into UnsignedIntegers. 33 | let h_coefficients = h_polynomial 34 | .coefficients 35 | .iter() 36 | .map(|elem| elem.representative()) 37 | .collect::>(); 38 | let h_degree = h_polynomial.degree(); 39 | 40 | Proof { 41 | v: msm(&c_mid, &evaluation_key.g1_vk).unwrap(), 42 | w1: msm(&c_mid, &evaluation_key.g1_wk).unwrap(), 43 | w2: msm(&c_mid, &evaluation_key.g2_wk).unwrap(), 44 | y: msm(&c_mid, &evaluation_key.g1_yk).unwrap(), 45 | v_prime: msm(&c_mid, &evaluation_key.g1_alpha_vk).unwrap(), 46 | w_prime: msm(&c_mid, &evaluation_key.g1_alpha_wk).unwrap(), 47 | y_prime: msm(&c_mid, &evaluation_key.g1_alpha_yk).unwrap(), 48 | z: msm(&c_mid, &evaluation_key.g1_beta).unwrap(), 49 | h: msm(&h_coefficients, &evaluation_key.g2_s_i[..h_degree]).unwrap(), 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /fuzz/cuda_fuzz/src/polynomial_fft_diff.rs: -------------------------------------------------------------------------------- 1 | use honggfuzz::fuzz; 2 | use lambdaworks_math::{ 3 | fft::{ 4 | gpu::cuda::polynomial::{evaluate_fft_cuda, interpolate_fft_cuda}, 5 | polynomial::{evaluate_fft_cpu, interpolate_fft_cpu}, 6 | }, 7 | field::{ 8 | fields::fft_friendly::stark_252_prime_field::Stark252PrimeField, 9 | element::FieldElement, 10 | } 11 | }; 12 | 13 | fn main() { 14 | loop { 15 | fuzz!(|data: Vec| { 16 | let mut inputs_raw = data; 17 | let mut inputs = Vec::new(); 18 | 19 | if inputs_raw.len() == 0 { 20 | inputs_raw.push(0u64); 21 | } 22 | 23 | for i in 0..inputs_raw.len() { 24 | let input_value = format!("{:x}", inputs_raw[i]); 25 | inputs.push(FieldElement::::from_hex_unchecked(&input_value)) 26 | } 27 | 28 | let (fft_eval_cuda, fft_eval_cpu) = match (evaluate_fft_cuda(&inputs), evaluate_fft_cpu(&inputs)) { 29 | (Ok(fft_eval_cuda), Ok(fft_eval_cpu)) => { 30 | assert_eq!(fft_eval_cuda, fft_eval_cpu); 31 | (fft_eval_cuda.clone(), fft_eval_cpu.clone()) 32 | }, 33 | (Err(_), Err(_)) => { 34 | (inputs.clone(), inputs) 35 | }, 36 | (cuda, cpu) => panic!("Evaluate results didn't match. cuda.is_err(): {}, cpu.is_err(): {}", cuda.is_err(), cpu.is_err()) 37 | }; 38 | 39 | match (interpolate_fft_cuda(&fft_eval_cuda), interpolate_fft_cpu(&fft_eval_cpu)) { 40 | (Ok(interpolated_cuda), Ok(interpolated_cpu)) => { 41 | assert_eq!(interpolated_cuda, interpolated_cpu); 42 | }, 43 | (Err(_), Err(_)) => {}, 44 | (cuda, cpu) => panic!("Interpolate results didn't match. cuda.is_err(): {}, cpu.is_err(): {}", cuda.is_err(), cpu.is_err()) 45 | }; 46 | }); 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /benches/benches/add.rs: -------------------------------------------------------------------------------- 1 | use std::{ops::Add, time::Duration}; 2 | 3 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 4 | use utils::generate_random_elements; 5 | 6 | use crate::utils::to_lambdaworks_vec; 7 | 8 | pub mod utils; 9 | 10 | const BENCHMARK_NAME: &str = "add"; 11 | 12 | pub fn criterion_benchmark(c: &mut Criterion) { 13 | let arkworks_vec = generate_random_elements(2000000); 14 | 15 | // arkworks-ff 16 | { 17 | c.bench_function( 18 | &format!("{BENCHMARK_NAME} 1M elements | ark-ff - ef8f758"), 19 | |b| { 20 | b.iter(|| { 21 | let mut iter = arkworks_vec.iter(); 22 | 23 | for _i in 0..1000000 { 24 | let a = iter.next().unwrap(); 25 | let b = iter.next().unwrap(); 26 | black_box(black_box(&a).add(black_box(b))); 27 | } 28 | }); 29 | }, 30 | ); 31 | } 32 | 33 | // lambdaworks-math 34 | { 35 | let lambdaworks_vec = to_lambdaworks_vec(&arkworks_vec); 36 | 37 | c.bench_function( 38 | &format!("{BENCHMARK_NAME} 1M elements | lambdaworks",), 39 | |b| { 40 | b.iter(|| { 41 | let mut iter = lambdaworks_vec.iter(); 42 | 43 | for _i in 0..1000000 { 44 | let a = iter.next().unwrap(); 45 | let b = iter.next().unwrap(); 46 | black_box(black_box(&a).add(black_box(b))); 47 | } 48 | }); 49 | }, 50 | ); 51 | } 52 | } 53 | 54 | criterion_group! { 55 | name = benches; 56 | // This can be any expression that returns a `Criterion` object. 57 | config = Criterion::default() 58 | .significance_level(0.01) 59 | .measurement_time(Duration::from_secs(15)) 60 | .sample_size(300); 61 | targets = criterion_benchmark 62 | } 63 | criterion_main!(benches); 64 | -------------------------------------------------------------------------------- /crates/math/src/gpu/cuda/shaders/field/stark256.cu: -------------------------------------------------------------------------------- 1 | #include "./fp_u256.cuh" 2 | #include "../fft/fft.cuh" 3 | #include "../fft/twiddles.cuh" 4 | #include "../fft/bitrev_permutation.cuh" 5 | #include "../utils.h" 6 | 7 | namespace p256 8 | { 9 | // StarkWare field for Cairo 10 | // P = 11 | // 3618502788666131213697322783095070105623107215331596699973092056135872020481 12 | using Fp = Fp256< 13 | /* =N **/ /*u256(*/ 576460752303423505, 0, 0, 1 /*)*/, 14 | /* =R_SQUARED **/ /*u256(*/ 576413109808302096, 18446744073700081664, 15 | 5151653887, 18446741271209837569 /*)*/, 16 | /* =N_PRIME **/ /*u256(*/ 576460752303423504, 18446744073709551615, 17 | 18446744073709551615, 18446744073709551615 /*)*/ 18 | >; 19 | } // namespace p256 20 | 21 | extern "C" 22 | { 23 | __global__ void radix2_dit_butterfly( p256::Fp *input, 24 | const p256::Fp *twiddles, 25 | const int stage, 26 | const int butterfly_count) 27 | { 28 | _radix2_dit_butterfly(input, twiddles, stage, butterfly_count); 29 | } 30 | // NOTE: In order to calculate the inverse twiddles, call with _omega = _omega.inverse() 31 | __global__ void calc_twiddles(p256::Fp *result, const p256::Fp &_omega, const int count) 32 | { 33 | _calc_twiddles(result, _omega, count); 34 | }; 35 | 36 | // NOTE: In order to calculate the inverse twiddles, call with _omega = _omega.inverse() 37 | __global__ void calc_twiddles_bitrev(p256::Fp *result, 38 | const p256::Fp &_omega, 39 | const int count) 40 | { 41 | _calc_twiddles_bitrev(result, _omega, count); 42 | }; 43 | 44 | __global__ void bitrev_permutation( 45 | const p256::Fp *input, 46 | p256::Fp *result, 47 | const int len 48 | ) { 49 | _bitrev_permutation(input, result, len); 50 | }; 51 | } 52 | -------------------------------------------------------------------------------- /examples/baby-snark/src/prover.rs: -------------------------------------------------------------------------------- 1 | use crate::{common::*, setup::ProvingKey, ssp::SquareSpanProgram}; 2 | use lambdaworks_math::{cyclic_group::IsGroup, msm::pippenger::msm}; 3 | pub struct Proof { 4 | pub h: G1Point, 5 | pub v_w: G1Point, 6 | pub v_w_prime: G2Point, 7 | pub b_w: G1Point, 8 | } 9 | 10 | #[derive(Debug)] 11 | pub enum Error { 12 | WrongWitness, 13 | FirstInputElementIsNotOne, 14 | } 15 | 16 | pub struct Prover; 17 | impl Prover { 18 | pub fn prove( 19 | inputs: &[FrElement], 20 | ssp: &SquareSpanProgram, 21 | pk: &ProvingKey, 22 | ) -> Result { 23 | if inputs[0].ne(&FrElement::one()) { 24 | return Err(Error::FirstInputElementIsNotOne); 25 | } 26 | if !ssp.check_valid(inputs) { 27 | return Err(Error::WrongWitness); 28 | } 29 | 30 | // Sample randomness for hiding 31 | let delta = sample_fr_elem(); 32 | 33 | let h_coefficients = ssp 34 | .calculate_h_coefficients(inputs, &delta) 35 | .iter() 36 | .map(|elem| elem.representative()) 37 | .collect::>(); 38 | 39 | let h = msm(&h_coefficients, &pk.k_powers_of_tau_g1).unwrap(); 40 | let w = inputs 41 | .iter() 42 | .skip(ssp.number_of_public_inputs) 43 | .map(|elem| elem.representative()) 44 | .collect::>(); 45 | 46 | let v_w = msm(&w, &pk.u_tau_g1) 47 | .unwrap() 48 | .operate_with(&pk.t_tau_g1.operate_with_self(delta.representative())); 49 | 50 | let v_w_prime = msm(&w, &pk.u_tau_g2) 51 | .unwrap() 52 | .operate_with(&pk.t_tau_g2.operate_with_self(delta.representative())); 53 | 54 | let b_w = msm(&w, &pk.beta_u_tau_g1) 55 | .unwrap() 56 | .operate_with(&pk.beta_t_tau_g1.operate_with_self(delta.representative())); 57 | 58 | Ok(Proof { 59 | h, 60 | v_w, 61 | v_w_prime, 62 | b_w, 63 | }) 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /crates/provers/stark/src/domain.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_math::{ 2 | fft::cpu::roots_of_unity::get_powers_of_primitive_root_coset, 3 | field::{element::FieldElement, traits::IsFFTField}, 4 | }; 5 | 6 | use super::traits::AIR; 7 | 8 | pub struct Domain { 9 | pub(crate) root_order: u32, 10 | pub(crate) lde_roots_of_unity_coset: Vec>, 11 | pub(crate) trace_primitive_root: FieldElement, 12 | pub(crate) trace_roots_of_unity: Vec>, 13 | pub(crate) coset_offset: FieldElement, 14 | pub(crate) blowup_factor: usize, 15 | pub(crate) interpolation_domain_size: usize, 16 | } 17 | 18 | impl Domain { 19 | pub fn new(air: &A) -> Self 20 | where 21 | A: AIR, 22 | { 23 | // Initial definitions 24 | let blowup_factor = air.options().blowup_factor as usize; 25 | let coset_offset = FieldElement::from(air.options().coset_offset); 26 | let interpolation_domain_size = air.trace_length(); 27 | let root_order = air.trace_length().trailing_zeros(); 28 | // * Generate Coset 29 | let trace_primitive_root = F::get_primitive_root_of_unity(root_order as u64).unwrap(); 30 | let trace_roots_of_unity = get_powers_of_primitive_root_coset( 31 | root_order as u64, 32 | interpolation_domain_size, 33 | &FieldElement::one(), 34 | ) 35 | .unwrap(); 36 | 37 | let lde_root_order = (air.trace_length() * blowup_factor).trailing_zeros(); 38 | let lde_roots_of_unity_coset = get_powers_of_primitive_root_coset( 39 | lde_root_order as u64, 40 | air.trace_length() * blowup_factor, 41 | &coset_offset, 42 | ) 43 | .unwrap(); 44 | 45 | Self { 46 | root_order, 47 | lde_roots_of_unity_coset, 48 | trace_primitive_root, 49 | trace_roots_of_unity, 50 | blowup_factor, 51 | coset_offset, 52 | interpolation_domain_size, 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /crates/math/src/traits.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | errors::DeserializationError, 3 | field::{element::FieldElement, traits::IsField}, 4 | }; 5 | 6 | use crate::errors::ByteConversionError; 7 | /// A trait for converting an element to and from its byte representation and 8 | /// for getting an element from its byte representation in big-endian or 9 | /// little-endian order. 10 | pub trait ByteConversion { 11 | /// Returns the byte representation of the element in big-endian order.} 12 | #[cfg(feature = "alloc")] 13 | fn to_bytes_be(&self) -> alloc::vec::Vec; 14 | 15 | /// Returns the byte representation of the element in little-endian order. 16 | #[cfg(feature = "alloc")] 17 | fn to_bytes_le(&self) -> alloc::vec::Vec; 18 | 19 | /// Returns the element from its byte representation in big-endian order. 20 | fn from_bytes_be(bytes: &[u8]) -> Result 21 | where 22 | Self: Sized; 23 | 24 | /// Returns the element from its byte representation in little-endian order. 25 | fn from_bytes_le(bytes: &[u8]) -> Result 26 | where 27 | Self: Sized; 28 | } 29 | 30 | /// Serialize function without args 31 | /// Used for serialization when formatting options are not relevant 32 | #[cfg(feature = "alloc")] 33 | pub trait AsBytes { 34 | /// Default serialize without args 35 | fn as_bytes(&self) -> alloc::vec::Vec; 36 | } 37 | 38 | #[cfg(feature = "alloc")] 39 | impl AsBytes for u32 { 40 | fn as_bytes(&self) -> alloc::vec::Vec { 41 | self.to_le_bytes().to_vec() 42 | } 43 | } 44 | 45 | #[cfg(feature = "alloc")] 46 | impl AsBytes for u64 { 47 | fn as_bytes(&self) -> alloc::vec::Vec { 48 | self.to_le_bytes().to_vec() 49 | } 50 | } 51 | 52 | /// Deserialize function without args 53 | pub trait Deserializable { 54 | fn deserialize(bytes: &[u8]) -> Result 55 | where 56 | Self: Sized; 57 | } 58 | 59 | pub trait IsRandomFieldElementGenerator { 60 | fn generate(&self) -> FieldElement; 61 | } 62 | -------------------------------------------------------------------------------- /crates/math/src/elliptic_curve/traits.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | cyclic_group::IsGroup, 3 | errors::PairingError, 4 | field::{element::FieldElement, traits::IsField}, 5 | }; 6 | use core::fmt::Debug; 7 | 8 | #[derive(Debug, PartialEq, Eq)] 9 | pub enum EllipticCurveError { 10 | InvalidPoint, 11 | } 12 | 13 | pub trait IsEllipticCurve { 14 | /// BaseField is the field used for each of the coordinates of a point p 15 | /// belonging to the curve. 16 | type BaseField: IsField + Clone + Debug; 17 | 18 | /// The representation of the point. For example it can be projective 19 | /// coordinates, affine coordinates, XYZZ, depending on the curve and its 20 | /// possible optimizations. 21 | type PointRepresentation: IsGroup + FromAffine; 22 | 23 | /// Returns the generator of the main subgroup. 24 | fn generator() -> Self::PointRepresentation; 25 | 26 | /// Returns an affine point. 27 | fn create_point_from_affine( 28 | x: FieldElement, 29 | y: FieldElement, 30 | ) -> Result { 31 | Self::PointRepresentation::from_affine(x, y) 32 | } 33 | } 34 | 35 | pub trait FromAffine: Sized { 36 | fn from_affine(x: FieldElement, y: FieldElement) -> Result; 37 | } 38 | 39 | pub trait IsPairing { 40 | type G1Point: IsGroup; 41 | type G2Point: IsGroup; 42 | type OutputField: IsField; 43 | 44 | /// Compute the product of the pairings for a list of point pairs. 45 | /// More efficient than just calling the pairing for each pair of points individually 46 | fn compute_batch( 47 | pairs: &[(&Self::G1Point, &Self::G2Point)], 48 | ) -> Result, PairingError>; 49 | 50 | /// Compute the ate pairing between point `p` in G1 and `q` in G2. 51 | fn compute( 52 | p: &Self::G1Point, 53 | q: &Self::G2Point, 54 | ) -> Result, PairingError> { 55 | Self::compute_batch(&[(p, q)]) 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /crates/provers/README.md: -------------------------------------------------------------------------------- 1 | # lambdaworks Provers 2 | 3 | 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. 4 | 5 | This folder contains the different provers currently supported by lambdaworks: 6 | - [Groth 16](./groth16/) 7 | - [Plonk](./plonk/) 8 | - [STARKs](./stark/) 9 | - [Cairo](https://github.com/lambdaclass/lambdaworks/tree/a591186e6c4dd53301b03b4ddd69369abe99f960/provers/cairo) - This is only for learning purposes and no longer supported. The [docs](../docs/src/starks/) still contain information that could be useful to understand and learn how Cairo works. 10 | 11 | The reference papers for each of the provers is given below: 12 | - [Groth 16](https://eprint.iacr.org/2016/260) 13 | - [Plonk](https://eprint.iacr.org/2019/953) 14 | - [STARKs](https://eprint.iacr.org/2018/046.pdf) 15 | 16 | A brief description of the Plonk and STARKs provers can be found [here](https://github.com/lambdaclass/lambdaworks/tree/main/docs/src) 17 | 18 | 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. 19 | - Groth 16: Shortest proof length. Security depends on pairing-friendly elliptic curves. Needs a new trusted setup for every program you want to prove. 20 | - Plonk (using KZG as commitment scheme): Short proof length. Security depends on pairing-friendly elliptic curves. Universal trusted setup. 21 | - STARKs: longer proof length. Security depends on collision-resistant hash functions. Conjectured to be post-quantum secure. Transparent (no trusted setup). 22 | 23 | ## Using provers 24 | 25 | - [Plonk prover](./plonk/README.md) 26 | -------------------------------------------------------------------------------- /crates/crypto/src/hash/poseidon/parameters.rs: -------------------------------------------------------------------------------- 1 | use alloc::vec::Vec; 2 | use lambdaworks_math::field::{element::FieldElement as FE, traits::IsPrimeField}; 3 | 4 | /// Parameters for Poseidon 5 | /// MDS constants and rounds constants are stored as references to slices 6 | /// representing matrices of `N_MDS_MATRIX_ROWS * N_MDS_MATRIX_COLS` and 7 | /// `N_ROUND_CONSTANTS_ROWS * N_ROUND_CONSTANTS_COLS` respectively. 8 | /// We use this representation rather than an array because we can't use the 9 | /// associated constants for dimension, requiring many generic parameters 10 | /// otherwise. 11 | pub trait PermutationParameters { 12 | type F: IsPrimeField + 'static; 13 | 14 | const RATE: usize; 15 | const CAPACITY: usize; 16 | const ALPHA: u32; 17 | const N_FULL_ROUNDS: usize; 18 | const N_PARTIAL_ROUNDS: usize; 19 | const STATE_SIZE: usize = Self::RATE + Self::CAPACITY; 20 | 21 | const MDS_MATRIX: &'static [FE]; 22 | const N_MDS_MATRIX_ROWS: usize; 23 | const N_MDS_MATRIX_COLS: usize; 24 | 25 | const ROUND_CONSTANTS: &'static [FE]; 26 | const N_ROUND_CONSTANTS_ROWS: usize; 27 | const N_ROUND_CONSTANTS_COLS: usize; 28 | 29 | /// This is the mix function that operates with the MDS matrix 30 | /// Round Constants are sometimes picked to simplify this function, 31 | /// so it can be redefined by each set of permutation parameters if a simplification can be made to make it faster. Notice in that case, MDS constants may not be used. 32 | fn mix(state: &mut [FE]) { 33 | let mut new_state: Vec> = Vec::with_capacity(Self::STATE_SIZE); 34 | for i in 0..Self::STATE_SIZE { 35 | let mut new_e = FE::zero(); 36 | for (j, current_state) in state.iter().enumerate() { 37 | let mut mij = Self::MDS_MATRIX[i * Self::N_MDS_MATRIX_COLS + j].clone(); 38 | mij *= current_state; 39 | new_e += mij; 40 | } 41 | new_state.push(new_e); 42 | } 43 | state.clone_from_slice(&new_state[0..Self::STATE_SIZE]); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /benches/benches/pow.rs: -------------------------------------------------------------------------------- 1 | use ark_ff::Field; 2 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 3 | use rand::{Rng, SeedableRng}; 4 | use utils::generate_random_elements; 5 | 6 | use crate::utils::to_lambdaworks_vec; 7 | 8 | pub mod utils; 9 | 10 | const BENCHMARK_NAME: &str = "pow"; 11 | 12 | pub fn criterion_benchmark(c: &mut Criterion) { 13 | let arkworks_vec = generate_random_elements(20000); 14 | 15 | let mut rng = rand_chacha::ChaCha20Rng::seed_from_u64(9001); 16 | 17 | let mut v_ints = Vec::new(); 18 | for _i in 0..10000 { 19 | v_ints.push(rng.gen::()); 20 | } 21 | 22 | // arkworks-ff 23 | { 24 | c.bench_function( 25 | &format!("{BENCHMARK_NAME} 10K elements | ark-ff - ef8f758"), 26 | |b| { 27 | b.iter(|| { 28 | let mut iter = arkworks_vec.iter(); 29 | let mut iter_ints = v_ints.iter(); 30 | 31 | for _i in 0..10000 { 32 | let a = iter.next().unwrap(); 33 | let exp = iter_ints.next().unwrap(); 34 | black_box(black_box(&a).pow(black_box(&[*exp]))); 35 | } 36 | }); 37 | }, 38 | ); 39 | } 40 | 41 | // lambdaworks-math 42 | { 43 | let lambdaworks_vec = to_lambdaworks_vec(&arkworks_vec); 44 | 45 | c.bench_function( 46 | &format!("{BENCHMARK_NAME} 10K elements | lambdaworks",), 47 | |b| { 48 | b.iter(|| { 49 | let mut iter = lambdaworks_vec.iter(); 50 | let mut iter_ints = v_ints.iter(); 51 | 52 | for _i in 0..10000 { 53 | let a = iter.next().unwrap(); 54 | let exp = iter_ints.next().unwrap(); 55 | black_box(black_box(&a).pow(black_box(*exp))); 56 | } 57 | }); 58 | }, 59 | ); 60 | } 61 | } 62 | 63 | criterion_group!(benches, criterion_benchmark); 64 | criterion_main!(benches); 65 | -------------------------------------------------------------------------------- /crates/math/src/fft/gpu/cuda/polynomial.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | fft::{ 3 | errors::FFTError, 4 | gpu::cuda::{ops::gen_twiddles, state::CudaState}, 5 | }, 6 | field::{ 7 | element::FieldElement, 8 | traits::{IsFFTField, RootsConfig}, 9 | }, 10 | polynomial::Polynomial, 11 | }; 12 | 13 | use super::ops::fft; 14 | use lambdaworks_gpu::cuda::abstractions::errors::CudaError; 15 | 16 | pub fn evaluate_fft_cuda(coeffs: &[FieldElement]) -> Result>, CudaError> 17 | where 18 | F: IsFFTField, 19 | F::BaseType: Unpin, 20 | { 21 | let state = CudaState::new()?; 22 | let order = log2(coeffs.len())?; 23 | let twiddles = gen_twiddles::(order, RootsConfig::BitReverse, &state)?; 24 | 25 | fft(coeffs, &twiddles, &state) 26 | } 27 | 28 | /// Returns a new polynomial that interpolates `fft_evals`, which are evaluations using twiddle 29 | /// factors. This is considered to be the inverse operation of [evaluate_fft_cuda()]. 30 | pub fn interpolate_fft_cuda( 31 | fft_evals: &[FieldElement], 32 | ) -> Result>, FFTError> 33 | where 34 | F: IsFFTField, 35 | F::BaseType: Unpin, 36 | { 37 | let state = CudaState::new()?; 38 | 39 | // fft() can zero-pad the coeffs if there aren't 2^k of them (k being any integer). 40 | // TODO: twiddle factors need to be handled with too much care, the FFT API shouldn't accept 41 | // invalid twiddle factor collections. A better solution is needed. 42 | let order = log2(fft_evals.len())?; 43 | let twiddles = gen_twiddles::(order, RootsConfig::BitReverseInversed, &state)?; 44 | 45 | let coeffs = fft(fft_evals, &twiddles, &state)?; 46 | 47 | let scale_factor = FieldElement::from(fft_evals.len() as u64).inv().unwrap(); 48 | Ok(Polynomial::new(&coeffs).scale_coeffs(&scale_factor)) 49 | } 50 | 51 | // TODO: remove when fft works on non-multiple-of-two input length 52 | fn log2(n: usize) -> Result { 53 | if !n.is_power_of_two() { 54 | return Err(CudaError::InvalidOrder(n)); 55 | } 56 | Ok(n.trailing_zeros() as u64) 57 | } 58 | -------------------------------------------------------------------------------- /benches/benches/poseidon.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | use lambdaworks_crypto::hash::poseidon::starknet::PoseidonCairoStark252; 3 | use lambdaworks_crypto::hash::poseidon::Poseidon; 4 | use lambdaworks_math::field::element::FieldElement; 5 | use lambdaworks_math::field::fields::fft_friendly::stark_252_prime_field::Stark252PrimeField; 6 | use lambdaworks_math::traits::ByteConversion; 7 | use pathfinder_crypto::MontFelt; 8 | use rand::{RngCore, SeedableRng}; 9 | use rand_chacha::ChaCha8Rng; 10 | 11 | fn poseidon_benchmarks(c: &mut Criterion) { 12 | let mut group = c.benchmark_group("poseidon"); 13 | 14 | let mut rng = ChaCha8Rng::seed_from_u64(2); 15 | let mut felt1: [u8; 32] = Default::default(); 16 | rng.fill_bytes(&mut felt1); 17 | let mut felt2: [u8; 32] = Default::default(); 18 | rng.fill_bytes(&mut felt2); 19 | 20 | let lw_x = FieldElement::::from_bytes_be(&felt1).unwrap(); 21 | let lw_y = FieldElement::::from_bytes_be(&felt2).unwrap(); 22 | group.bench_function("lambdaworks", |bench| { 23 | bench.iter(|| black_box(PoseidonCairoStark252::hash(&lw_x, &lw_y))) 24 | }); 25 | 26 | let mut mont_x = lw_x.value().limbs; 27 | let mut mont_y = lw_y.value().limbs; 28 | 29 | // In order use the same field elements for starknet-rs and pathfinder, we have to reverse 30 | // the limbs order respect to the lambdaworks implementation. 31 | mont_x.reverse(); 32 | mont_y.reverse(); 33 | 34 | let sn_ff_x = starknet_crypto::FieldElement::from_mont(mont_x); 35 | let sn_ff_y = starknet_crypto::FieldElement::from_mont(mont_y); 36 | group.bench_function("starknet-rs", |bench| { 37 | bench.iter(|| black_box(starknet_crypto::poseidon_hash(sn_ff_x, sn_ff_y))) 38 | }); 39 | 40 | let pf_x = MontFelt(mont_x); 41 | let pf_y = MontFelt(mont_y); 42 | group.bench_function("pathfinder", |bench| { 43 | bench.iter(|| black_box(pathfinder_crypto::hash::poseidon_hash(pf_x, pf_y))) 44 | }); 45 | } 46 | criterion_group!(poseidon, poseidon_benchmarks); 47 | criterion_main!(poseidon); 48 | -------------------------------------------------------------------------------- /crates/provers/groth16/circom-adapter/src/lib.rs: -------------------------------------------------------------------------------- 1 | use lambdaworks_groth16::{common::FrElement, QuadraticArithmeticProgram}; 2 | 3 | mod readers; 4 | pub use readers::*; 5 | 6 | /// Given a [`CircomR1CS`] and [`CircomWitness`] it returns a [QAP](QuadraticArithmeticProgram), 7 | /// witness, and public signals; all compatible with Lambdaworks. 8 | pub fn circom_to_lambda( 9 | circom_r1cs: CircomR1CS, 10 | witness: CircomWitness, 11 | ) -> (QuadraticArithmeticProgram, Vec, Vec) { 12 | let num_of_outputs = circom_r1cs.num_outputs; 13 | let num_of_pub_inputs = circom_r1cs.num_pub_inputs; 14 | 15 | // we could get a slice using the QAP but the QAP does not keep track of the number of private inputs; 16 | // so instead we get the public signals here 17 | let public_inputs = witness[..num_of_pub_inputs + num_of_outputs + 1].to_vec(); 18 | 19 | // get L,R,O matrices from R1CS 20 | let [l, r, o] = build_lro_from_circom_r1cs(circom_r1cs); 21 | let qap = QuadraticArithmeticProgram::from_variable_matrices(public_inputs.len(), &l, &r, &o); 22 | 23 | (qap, witness, public_inputs) 24 | } 25 | 26 | /// Takes as input circom.r1cs.json file and outputs LRO matrices 27 | #[inline] 28 | fn build_lro_from_circom_r1cs(circom_r1cs: CircomR1CS) -> [Vec>; 3] { 29 | let mut l = vec![vec![FrElement::zero(); circom_r1cs.num_constraints]; circom_r1cs.num_vars]; 30 | let mut r = l.clone(); // same initial value as above 31 | let mut o = l.clone(); // same initial value as above 32 | 33 | // assign each constraint from the R1CS hash-maps to LRO matrices 34 | for (constraint_idx, constraint) in circom_r1cs.constraints.into_iter().enumerate() { 35 | // destructuring here to avoid clones 36 | let [lc, rc, oc] = constraint; 37 | 38 | for (var_idx, val) in lc { 39 | l[var_idx][constraint_idx] = val; 40 | } 41 | for (var_idx, val) in rc { 42 | r[var_idx][constraint_idx] = val; 43 | } 44 | for (var_idx, val) in oc { 45 | o[var_idx][constraint_idx] = val; 46 | } 47 | } 48 | 49 | [l, r, o] 50 | } 51 | --------------------------------------------------------------------------------