diff --git a/.envrc b/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use flake diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml new file mode 100644 index 0000000..8db5089 --- /dev/null +++ b/.github/workflows/nix.yml @@ -0,0 +1,41 @@ +name: Nix CI + +on: + push: + branches: [main, dev] + pull_request: + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + # Runs the test suite via Nix (the `checks.tests` cargo-nextest derivation) + nix-test: + name: Nix Tests + # Change to warp-ubuntu-latest-x64-16x for a more powerful runner (GitHub App must be enabled for this repo) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: cachix/install-nix-action@v31 + with: + nix_path: nixpkgs=channel:nixos-unstable + github_access_token: ${{ secrets.GITHUB_TOKEN }} + - run: nix build --print-build-logs + - run: nix flake check --print-build-logs + + # Tests Nix devShell support on Ubuntu + nix-devshell: + name: Nix devShell Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: cachix/install-nix-action@v31 + with: + nix_path: nixpkgs=channel:nixos-unstable + github_access_token: ${{ secrets.GITHUB_TOKEN }} + - run: nix develop --command bash -c "cargo check --all-targets --features parallel" diff --git a/.gitignore b/.gitignore index 73fab07..9142fb8 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,7 @@ target/ # MSVC Windows builds of rustc generate these, which store debugging information *.pdb + +# Nix +.direnv/ +result* diff --git a/Cargo.lock b/Cargo.lock index fb8637c..b638a97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,18 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" + [[package]] name = "autocfg" version = "1.5.0" @@ -49,6 +61,20 @@ dependencies = [ "virtue", ] +[[package]] +name = "blake3" +version = "1.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures", +] + [[package]] name = "bumpalo" version = "3.20.2" @@ -61,6 +87,16 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" +[[package]] +name = "cc" +version = "1.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d6cac793997bd970000024b2934968efe83b382de4fdcf4fcb46b6ee4ad996" +dependencies = [ + "find-msvc-tools", + "shlex", +] + [[package]] name = "cfg-if" version = "1.0.4" @@ -130,6 +166,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + [[package]] name = "cpufeatures" version = "0.3.0" @@ -212,6 +254,12 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + [[package]] name = "getrandom" version = "0.4.3" @@ -315,6 +363,7 @@ dependencies = [ "criterion", "p3-air", "p3-baby-bear", + "p3-blake3", "p3-challenger", "p3-commit", "p3-dft", @@ -397,6 +446,16 @@ dependencies = [ "rand", ] +[[package]] +name = "p3-blake3" +version = "0.5.1" +source = "git+https://github.com/Plonky3/Plonky3?rev=e9d75614dd6816f9b5dbb4413c69be63536efd64#e9d75614dd6816f9b5dbb4413c69be63536efd64" +dependencies = [ + "blake3", + "p3-symmetric", + "p3-util", +] + [[package]] name = "p3-challenger" version = "0.5.1" @@ -826,6 +885,12 @@ dependencies = [ "zmij", ] +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + [[package]] name = "spin" version = "0.10.0" diff --git a/Cargo.toml b/Cargo.toml index 854467c..1668064 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ p3-dft = { git = "https://github.com/Plonky3/Plonky3", rev = "e9d75614dd6816f9b5 p3-field = { git = "https://github.com/Plonky3/Plonky3", rev = "e9d75614dd6816f9b5dbb4413c69be63536efd64" } p3-fri = { git = "https://github.com/Plonky3/Plonky3", rev = "e9d75614dd6816f9b5dbb4413c69be63536efd64" } p3-keccak = { git = "https://github.com/Plonky3/Plonky3", rev = "e9d75614dd6816f9b5dbb4413c69be63536efd64" } +p3-blake3 = { git = "https://github.com/Plonky3/Plonky3", rev = "e9d75614dd6816f9b5dbb4413c69be63536efd64" } p3-matrix = { git = "https://github.com/Plonky3/Plonky3", rev = "e9d75614dd6816f9b5dbb4413c69be63536efd64" } p3-maybe-rayon = { git = "https://github.com/Plonky3/Plonky3", rev = "e9d75614dd6816f9b5dbb4413c69be63536efd64" } p3-merkle-tree = { git = "https://github.com/Plonky3/Plonky3", rev = "e9d75614dd6816f9b5dbb4413c69be63536efd64" } diff --git a/README.md b/README.md index 32ec584..0be7fb3 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ lookup arguments for shared state. The protocol (`system`, `prover`, `verifier` modules) is generic over [`StarkGenericConfig`](src/config.rs). The crate ships one production -configuration, `GoldilocksKeccakConfig` in [`types`](src/types.rs): +configuration, `GoldilocksBlake3Config` in [`types`](src/types.rs): | Component | Choice | |-----------|-----------------------------------------------| diff --git a/benches/multi_stark.rs b/benches/multi_stark.rs index e25899c..c0edaa5 100644 --- a/benches/multi_stark.rs +++ b/benches/multi_stark.rs @@ -16,7 +16,7 @@ use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main}; use multi_stark::builder::symbolic::{SymbolicExpression, preprocessed_var, var}; use multi_stark::lookup::{Lookup, LookupAir}; use multi_stark::system::{System, SystemWitness}; -use multi_stark::types::{CommitmentParameters, FriParameters, GoldilocksKeccakConfig, Val}; +use multi_stark::types::{CommitmentParameters, FriParameters, GoldilocksBlake3Config, Val}; use multi_stark::{ p3_air::{Air, AirBuilder, BaseAir, WindowAccess}, p3_field::{Field, PrimeCharacteristicRing}, @@ -129,7 +129,7 @@ impl U32CS { fn build_witness( num_adds: usize, - system: &System, + system: &System, ) -> SystemWitness { let byte_width = 1; let add_width = 14; @@ -204,7 +204,7 @@ fn build_claims(num_adds: usize) -> Vec<[Val; 4]> { // --------------------------------------------------------------------------- fn bench_prove(c: &mut Criterion) { - let config = GoldilocksKeccakConfig::new( + let config = GoldilocksBlake3Config::new( CommitmentParameters { log_blowup: 1, cap_height: 0, @@ -244,7 +244,7 @@ fn bench_prove(c: &mut Criterion) { } fn bench_verify(c: &mut Criterion) { - let config = GoldilocksKeccakConfig::new( + let config = GoldilocksBlake3Config::new( CommitmentParameters { log_blowup: 1, cap_height: 0, diff --git a/deny.toml b/deny.toml index 8cf3ffe..5160653 100644 --- a/deny.toml +++ b/deny.toml @@ -95,8 +95,9 @@ allow = [ "Apache-2.0", "Unicode-3.0", "CC0-1.0", + # blake3 → arrayref; also allowed in ix's deny.toml + "BSD-2-Clause", #"Apache-2.0 WITH LLVM-exception", - #"BSD-2-Clause", ] # The confidence threshold for detecting a license from license text. # The higher the value, the more closely the license text must be to the diff --git a/examples/lookup_proof.rs b/examples/lookup_proof.rs index c209680..23bf945 100644 --- a/examples/lookup_proof.rs +++ b/examples/lookup_proof.rs @@ -15,7 +15,7 @@ use multi_stark::builder::symbolic::{SymbolicExpression, var}; use multi_stark::lookup::{Lookup, LookupAir}; use multi_stark::system::{System, SystemWitness}; -use multi_stark::types::{CommitmentParameters, FriParameters, GoldilocksKeccakConfig, Val}; +use multi_stark::types::{CommitmentParameters, FriParameters, GoldilocksBlake3Config, Val}; use multi_stark::{ p3_air::{Air, AirBuilder, BaseAir, WindowAccess}, p3_field::{Field, PrimeCharacteristicRing}, @@ -103,7 +103,7 @@ where } fn main() { - let config = GoldilocksKeccakConfig::new( + let config = GoldilocksBlake3Config::new( CommitmentParameters { log_blowup: 1, cap_height: 0, diff --git a/examples/pcs_example.rs b/examples/pcs_example.rs index 27e5cb7..a4540b8 100644 --- a/examples/pcs_example.rs +++ b/examples/pcs_example.rs @@ -18,7 +18,7 @@ use bincode::{config::standard, serde::encode_to_vec}; use multi_stark::config::StarkGenericConfig; use multi_stark::types::{ Challenger, Commitment, CommitmentParameters, Domain, ExtVal, FriParameters, - GoldilocksKeccakConfig, Pcs, PcsProof, ProverData, Val, + GoldilocksBlake3Config, Pcs, PcsProof, ProverData, Val, }; use p3_challenger::{CanObserve, FieldChallenger}; use p3_commit::{OpenedValues, Pcs as PcsTrait}; @@ -42,7 +42,7 @@ fn main() { query_proof_of_work_bits: 0, }; - let config = GoldilocksKeccakConfig::new(commitment_params, fri_params); + let config = GoldilocksBlake3Config::new(commitment_params, fri_params); let pcs = config.pcs(); // ── Build polynomial evaluations ───────────────────────────────────────── diff --git a/examples/preprocessed_proof.rs b/examples/preprocessed_proof.rs index dfea7a4..cd5bc28 100644 --- a/examples/preprocessed_proof.rs +++ b/examples/preprocessed_proof.rs @@ -14,7 +14,7 @@ use multi_stark::builder::symbolic::{SymbolicExpression, preprocessed_var, var}; use multi_stark::lookup::{Lookup, LookupAir}; use multi_stark::system::{System, SystemWitness}; -use multi_stark::types::{CommitmentParameters, FriParameters, GoldilocksKeccakConfig, Val}; +use multi_stark::types::{CommitmentParameters, FriParameters, GoldilocksBlake3Config, Val}; use multi_stark::{ p3_air::{Air, AirBuilder, BaseAir, WindowAccess}, p3_field::{Field, PrimeCharacteristicRing}, @@ -87,7 +87,7 @@ impl SquaresCS { } fn main() { - let config = GoldilocksKeccakConfig::new( + let config = GoldilocksBlake3Config::new( CommitmentParameters { log_blowup: 1, cap_height: 0, diff --git a/examples/simple_proof.rs b/examples/simple_proof.rs index e09c170..8cf3b61 100644 --- a/examples/simple_proof.rs +++ b/examples/simple_proof.rs @@ -11,7 +11,7 @@ use multi_stark::lookup::LookupAir; use multi_stark::system::{System, SystemWitness}; -use multi_stark::types::{CommitmentParameters, FriParameters, GoldilocksKeccakConfig, Val}; +use multi_stark::types::{CommitmentParameters, FriParameters, GoldilocksBlake3Config, Val}; use multi_stark::{ p3_air::{Air, AirBuilder, BaseAir, WindowAccess}, p3_field::PrimeCharacteristicRing, @@ -44,7 +44,7 @@ where } fn main() { - let config = GoldilocksKeccakConfig::new( + let config = GoldilocksBlake3Config::new( CommitmentParameters { log_blowup: 1, cap_height: 0, diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..c7879df --- /dev/null +++ b/flake.lock @@ -0,0 +1,117 @@ +{ + "nodes": { + "crane": { + "locked": { + "lastModified": 1783203018, + "narHash": "sha256-G6R9IT/xwFuu+CYBWDUAok6AdC4ERC4ZfPPFtEpxnZE=", + "owner": "ipetkov", + "repo": "crane", + "rev": "80db5bdc391be8a1794f6d8a2d56e3a84ebcede2", + "type": "github" + }, + "original": { + "owner": "ipetkov", + "repo": "crane", + "type": "github" + } + }, + "fenix": { + "inputs": { + "nixpkgs": "nixpkgs", + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1783676673, + "narHash": "sha256-A4Sy9xQrO5wTaPue9JISqSuJbFU/NECHLFQm70C1ehM=", + "owner": "nix-community", + "repo": "fenix", + "rev": "9239e256596333bf1eb49068e8544786c3a853c8", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, + "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1782949081, + "narHash": "sha256-vp6Y/Grm98ESt6ceOkWiHWyZRDV3J1RID4w+6NWK9yA=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "17c9d6cdfc60c64f4ee8d306f9bc0b4ccb51481e", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1783224372, + "narHash": "sha256-8i/87eeoqiGE4yOTjwSA3Eh/ziJRQEmd/unYU+K27sk=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "d407951447dcd00442e97087bf374aad70c04cea", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1782614948, + "narHash": "sha256-ePjCwr1sNm9NYUqywL7QfK3JnlS015msC+eBu2zKlp8=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "db3f255737b94216eb71cce308e2912cf6bc2d7c", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "root": { + "inputs": { + "crane": "crane", + "fenix": "fenix", + "flake-parts": "flake-parts", + "nixpkgs": [ + "fenix", + "nixpkgs" + ] + } + }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1783531694, + "narHash": "sha256-qnAn5Z/BhCj71mU/yWhRhapukrPYmIqu+kAsARdAHmg=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "e7e17b692a073ca9820d1822626646b9cc045153", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..8ed206b --- /dev/null +++ b/flake.nix @@ -0,0 +1,96 @@ +{ + description = "multi-stark Nix flake (Rust)"; + + inputs = { + # System packages, follows fenix so we stay in sync + nixpkgs.follows = "fenix/nixpkgs"; + + # Helper: flake-parts for easier outputs + flake-parts.url = "github:hercules-ci/flake-parts"; + + # Rust toolchain pinned from rust-toolchain.toml + fenix.url = "github:nix-community/fenix"; + + crane.url = "github:ipetkov/crane"; + }; + + outputs = + inputs@{ + nixpkgs, + flake-parts, + fenix, + crane, + ... + }: + flake-parts.lib.mkFlake { inherit inputs; } { + systems = [ + "aarch64-darwin" + "aarch64-linux" + "x86_64-darwin" + "x86_64-linux" + ]; + + perSystem = + { + system, + pkgs, + ... + }: + let + # Pins the Rust toolchain + rustToolchain = fenix.packages.${system}.fromToolchainFile { + file = ./rust-toolchain.toml; + sha256 = "sha256-SDu4snEWjuZU475PERvu+iO50Mi39KVjqCeJeNvpguU="; + }; + + craneLib = (crane.mkLib pkgs).overrideToolchain rustToolchain; + src = craneLib.cleanCargoSource ./.; + craneArgs = { + inherit src; + pname = "multi-stark"; + version = "0.1.0"; + strictDeps = true; + + buildInputs = pkgs.lib.optionals pkgs.stdenv.isDarwin [ + pkgs.libiconv + ]; + }; + cargoArtifacts = craneLib.buildDepsOnly craneArgs; + + multiStark = craneLib.buildPackage ( + craneArgs + // { + inherit cargoArtifacts; + cargoExtraArgs = "--locked --features parallel"; + } + ); + in + { + packages.default = multiStark; + + # `nix flake check` runs the test suite (the CI entrypoint). + # CARGO_PROFILE picks the profile (crane passes it as + # --cargo-profile); dev-ci matches ci.yml's optimized test build. + checks.tests = craneLib.cargoNextest ( + craneArgs + // { + inherit cargoArtifacts; + CARGO_PROFILE = "dev-ci"; + cargoNextestExtraArgs = "--workspace --features parallel"; + } + ); + + # Rust shell for host development (`cargo build`, `cargo test`). + devShells.default = pkgs.mkShell { + packages = with pkgs; [ + rustToolchain + rust-analyzer + cargo-deny + cargo-nextest + ]; + }; + + formatter = pkgs.alejandra; + }; + }; +} diff --git a/src/config.rs b/src/config.rs index aa21a9c..4dd809d 100644 --- a/src/config.rs +++ b/src/config.rs @@ -5,7 +5,7 @@ //! field, and the Fiat-Shamir challenger. The base field is determined //! transitively by the PCS ([`Val`]). The prover, verifier and system are //! generic over an implementation of this trait; see -//! [`crate::types::GoldilocksKeccakConfig`] for the reference instantiation. +//! [`crate::types::GoldilocksBlake3Config`] for the reference instantiation. use p3_challenger::{CanObserve, CanSample, FieldChallenger}; use p3_commit::{Pcs, PolynomialSpace}; diff --git a/src/lookup.rs b/src/lookup.rs index 8266f3b..27d69fd 100644 --- a/src/lookup.rs +++ b/src/lookup.rs @@ -290,7 +290,7 @@ mod tests { use crate::{ builder::symbolic::var, system::{ProverKey, System, SystemWitness}, - types::{CommitmentParameters, FriParameters, GoldilocksKeccakConfig, Val}, + types::{CommitmentParameters, FriParameters, GoldilocksBlake3Config, Val}, }; use super::*; @@ -385,16 +385,16 @@ mod tests { }; fn system() -> ( - System, - ProverKey, + System, + ProverKey, ) { - let config = GoldilocksKeccakConfig::new(COMMITMENT_PARAMETERS, FRI_PARAMETERS); + let config = GoldilocksBlake3Config::new(COMMITMENT_PARAMETERS, FRI_PARAMETERS); let even = LookupAir::new(CS::Even, CS::Even.lookups()); let odd = LookupAir::new(CS::Odd, CS::Odd.lookups()); System::new(config, [even, odd]) } - fn witness(system: &System) -> SystemWitness { + fn witness(system: &System) -> SystemWitness { let f = Val::from_u32; #[rustfmt::skip] let witness = SystemWitness::from_stage_1( diff --git a/src/system.rs b/src/system.rs index b40bd80..b56fd88 100644 --- a/src/system.rs +++ b/src/system.rs @@ -235,7 +235,7 @@ impl Circuit { #[cfg(test)] mod tests { use super::*; - use crate::types::{CommitmentParameters, FriParameters, GoldilocksKeccakConfig, Val}; + use crate::types::{CommitmentParameters, FriParameters, GoldilocksBlake3Config, Val}; use p3_air::{AirBuilder, WindowAccess}; /// A trivial AIR with a preprocessed trace of 4 rows and no constraints. @@ -298,7 +298,7 @@ mod tests { commit_proof_of_work_bits: 0, query_proof_of_work_bits: 0, }; - let config = GoldilocksKeccakConfig::new(commitment_parameters, fri_parameters); + let config = GoldilocksBlake3Config::new(commitment_parameters, fri_parameters); System::new(config, [LookupAir::new(HighDegreeAir, vec![])]); } @@ -317,7 +317,7 @@ mod tests { commit_proof_of_work_bits: 0, query_proof_of_work_bits: 0, }; - let config = GoldilocksKeccakConfig::new(commitment_parameters, fri_parameters); + let config = GoldilocksBlake3Config::new(commitment_parameters, fri_parameters); let (system, key) = System::new(config, [LookupAir::new(HighDegreeAir, vec![])]); let f = Val::from_u32; let trace = RowMajorMatrix::new(vec![f(2), f(32), f(1), f(1), f(3), f(243), f(0), f(0)], 2); @@ -341,7 +341,7 @@ mod tests { commit_proof_of_work_bits: 0, query_proof_of_work_bits: 0, }; - let config = GoldilocksKeccakConfig::new(commitment_parameters, fri_parameters); + let config = GoldilocksBlake3Config::new(commitment_parameters, fri_parameters); let (system, _key) = System::new(config, [LookupAir::new(Preprocessed, vec![])]); // The main trace has 8 rows but the preprocessed trace has 4. This // must panic instead of silently truncating the lookup rows. diff --git a/src/test_circuits/blake3.rs b/src/test_circuits/blake3.rs index 41aaca6..999afbc 100644 --- a/src/test_circuits/blake3.rs +++ b/src/test_circuits/blake3.rs @@ -4,7 +4,7 @@ mod tests { use crate::lookup::{Lookup, LookupAir}; use crate::system::{System, SystemWitness}; use crate::test_circuits::SymbExpr; - use crate::types::{CommitmentParameters, FriParameters, GoldilocksKeccakConfig, Val}; + use crate::types::{CommitmentParameters, FriParameters, GoldilocksBlake3Config, Val}; use p3_air::{Air, AirBuilder, BaseAir, WindowAccess}; use p3_field::{Field, PrimeCharacteristicRing, PrimeField64}; use p3_matrix::Matrix; @@ -1515,7 +1515,7 @@ mod tests { impl Blake3CompressionClaims { fn witness( &self, - system: &System, + system: &System, ) -> (Vec>, SystemWitness) { // Grabbing values from a claims @@ -2249,7 +2249,7 @@ mod tests { assert_eq!(actual, expected.to_vec()); // circuit testing - let config = GoldilocksKeccakConfig::new( + let config = GoldilocksBlake3Config::new( CommitmentParameters { log_blowup: 1, cap_height: 0, @@ -2437,7 +2437,7 @@ mod tests { fn run_test(claims: &Blake3CompressionClaims) { // circuit testing - let config = GoldilocksKeccakConfig::new( + let config = GoldilocksBlake3Config::new( CommitmentParameters { log_blowup: 1, cap_height: 0, diff --git a/src/test_circuits/byte_operations.rs b/src/test_circuits/byte_operations.rs index 76d8bf7..213419c 100644 --- a/src/test_circuits/byte_operations.rs +++ b/src/test_circuits/byte_operations.rs @@ -4,7 +4,7 @@ mod tests { use crate::lookup::{Lookup, LookupAir}; use crate::system::{System, SystemWitness}; use crate::test_circuits::SymbExpr; - use crate::types::{CommitmentParameters, FriParameters, GoldilocksKeccakConfig, Val}; + use crate::types::{CommitmentParameters, FriParameters, GoldilocksBlake3Config, Val}; use p3_air::{Air, AirBuilder, BaseAir}; use p3_field::{Field, PrimeCharacteristicRing}; use p3_matrix::dense::RowMajorMatrix; @@ -107,7 +107,7 @@ mod tests { } impl ByteCalls { - fn witness(&self, system: &System) -> SystemWitness { + fn witness(&self, system: &System) -> SystemWitness { let mut byte_trace = RowMajorMatrix::new(vec![Val::ZERO; TRACE_WIDTH * 256 * 256], TRACE_WIDTH); for (op, x, y) in self.calls.iter() { @@ -123,7 +123,7 @@ mod tests { #[test] fn byte_test() { - let config = GoldilocksKeccakConfig::new( + let config = GoldilocksBlake3Config::new( CommitmentParameters { log_blowup: 1, cap_height: 0, diff --git a/src/test_circuits/u32_add.rs b/src/test_circuits/u32_add.rs index d69b225..fb4fc02 100644 --- a/src/test_circuits/u32_add.rs +++ b/src/test_circuits/u32_add.rs @@ -9,7 +9,7 @@ mod tests { builder::symbolic::{preprocessed_var, var}, lookup::{Lookup, LookupAir}, system::{ProverKey, System, SystemWitness}, - types::{CommitmentParameters, FriParameters, GoldilocksKeccakConfig, Val}, + types::{CommitmentParameters, FriParameters, GoldilocksBlake3Config, Val}, }; enum U32CS { @@ -126,10 +126,10 @@ mod tests { } fn byte_system( - config: GoldilocksKeccakConfig, + config: GoldilocksBlake3Config, ) -> ( - System, - ProverKey, + System, + ProverKey, ) { let byte_table = LookupAir::new(U32CS::ByteTable, U32CS::ByteTable.lookups()); let u32_add = LookupAir::new(U32CS::U32Add, U32CS::U32Add.lookups()); @@ -141,7 +141,7 @@ mod tests { } impl AddCalls { - fn witness(&self, system: &System) -> SystemWitness { + fn witness(&self, system: &System) -> SystemWitness { let byte_width = 1; let add_width = 14; let mut byte_trace = RowMajorMatrix::new(vec![Val::ZERO; byte_width * 256], byte_width); @@ -192,7 +192,7 @@ mod tests { #[test] fn u32_add_proof() { - let config = GoldilocksKeccakConfig::new( + let config = GoldilocksBlake3Config::new( CommitmentParameters { log_blowup: 1, cap_height: 0, diff --git a/src/types.rs b/src/types.rs index fc88c03..ffc98ca 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,34 +1,28 @@ //! The reference STARK configuration: Goldilocks field with a degree-2 -//! binomial extension, Keccak-256 hashing, and a FRI-based PCS. +//! binomial extension, Blake3 hashing, and a FRI-based PCS. //! //! The generic protocol lives in [`crate::config`], [`crate::system`], //! [`crate::prover`] and [`crate::verifier`]; this module only provides a //! concrete, batteries-included instantiation. use crate::config::StarkGenericConfig; +use p3_blake3::Blake3; use p3_challenger::{HashChallenger, SerializingChallenger64}; use p3_commit::{ExtensionMmcs, Pcs as PcsTrait}; use p3_dft::Radix2DitParallel; use p3_field::{ExtensionField, Field, TwoAdicField, extension::BinomialExtensionField}; use p3_fri::{FriParameters as InnerFriParameters, TwoAdicFriPcs}; use p3_goldilocks::Goldilocks; -use p3_keccak::{Keccak256Hash, KeccakF}; use p3_merkle_tree::MerkleTreeMmcs; -use p3_symmetric::{CompressionFunctionFromHasher, PaddingFreeSponge, SerializingHasher}; +use p3_symmetric::{CompressionFunctionFromHasher, SerializingHasher}; pub type Val = Goldilocks; pub type PackedVal = ::Packing; pub type ExtVal = BinomialExtensionField; pub type PackedExtVal = >::ExtensionPacking; -pub type Challenger = SerializingChallenger64>; -pub type Mmcs = MerkleTreeMmcs< - [Val; p3_keccak::VECTOR_LEN], - [u64; p3_keccak::VECTOR_LEN], - SerializingHasher>, - KeccakCompressionFunction, - 2, - 4, ->; +pub type Challenger = SerializingChallenger64>; +pub type Mmcs = + MerkleTreeMmcs, Blake3CompressionFunction, 2, 32>; pub type ExtMmcs = ExtensionMmcs; pub type Pcs = TwoAdicFriPcs; @@ -40,7 +34,7 @@ pub type PcsError = >::Error; pub type PcsProof = >::Proof; /// The reference [`StarkGenericConfig`] implementation. -pub struct GoldilocksKeccakConfig { +pub struct GoldilocksBlake3Config { /// The PCS used to commit polynomials and prove opening proofs. pcs: Pcs, /// Seed for fresh challengers: a domain-separation tag followed by a @@ -53,7 +47,7 @@ pub struct GoldilocksKeccakConfig { max_quotient_degree: usize, } -impl GoldilocksKeccakConfig { +impl GoldilocksBlake3Config { pub fn new(commitment_parameters: CommitmentParameters, fri_parameters: FriParameters) -> Self { let pcs = new_pcs(commitment_parameters, fri_parameters); // Seed the challenger with a protocol tag for domain separation, @@ -85,7 +79,7 @@ impl GoldilocksKeccakConfig { } } -impl StarkGenericConfig for GoldilocksKeccakConfig { +impl StarkGenericConfig for GoldilocksBlake3Config { type Pcs = Pcs; type Challenge = ExtVal; type Challenger = Challenger; @@ -95,7 +89,7 @@ impl StarkGenericConfig for GoldilocksKeccakConfig { } fn initialise_challenger(&self) -> Challenger { - Challenger::from_hasher(self.challenger_seed.clone(), Keccak256Hash {}) + Challenger::from_hasher(self.challenger_seed.clone(), Blake3) } fn max_log_degree(&self) -> usize { @@ -137,14 +131,13 @@ pub struct FriParameters { pub query_proof_of_work_bits: usize, } -type KeccakCompressionFunction = - CompressionFunctionFromHasher, 2, 4>; +type Blake3CompressionFunction = CompressionFunctionFromHasher; type Dft = Radix2DitParallel; fn new_mmcs(cap_height: usize) -> Mmcs { - let u64_hash = PaddingFreeSponge::::new(KeccakF {}); - let field_hash = SerializingHasher::new(u64_hash); - let compress = KeccakCompressionFunction::new(u64_hash); + let byte_hash = Blake3; + let field_hash = SerializingHasher::new(byte_hash); + let compress = Blake3CompressionFunction::new(byte_hash); Mmcs::new(field_hash, compress, cap_height) } @@ -163,3 +156,100 @@ fn new_pcs(commitment_parameters: CommitmentParameters, fri_parameters: FriParam let dft = Dft::default(); Pcs::new(dft, val_mmcs, inner_parameters) } + +#[cfg(test)] +mod pcs_ref_gen { + use super::*; + use p3_commit::Mmcs as _; + use p3_field::PrimeCharacteristicRing; + use p3_matrix::dense::RowMajorMatrix; + use p3_symmetric::{CryptographicHasher, PseudoCompressionFunction}; + + fn limbs(d: [u8; 32]) -> [u64; 4] { + core::array::from_fn(|i| u64::from_le_bytes(d[i * 8..i * 8 + 8].try_into().unwrap())) + } + fn dig(xs: [u64; 4]) -> [u8; 32] { + let mut o = [0u8; 32]; + for i in 0..4 { + o[i * 8..i * 8 + 8].copy_from_slice(&xs[i].to_le_bytes()); + } + o + } + + /// Generates the Blake3 reference values asserted by `Ix/MultiStark/Tests.lean` + /// (`pcs_hash_test`, `pcs_merkle_test`). Run with `--nocapture` and copy. + #[test] + fn gen_pcs_refs() { + let f = Val::from_u32; + let fh = SerializingHasher::new(Blake3); + for n in [3u32, 17, 22, 20] { + let row: Vec = (1..=n).map(f).collect(); + println!("LEAF{} {:?}", n, limbs(fh.hash_iter(row))); + } + let comp = Blake3CompressionFunction::new(Blake3); + println!( + "COMPRESS {:?}", + limbs(comp.compress([dig([1, 2, 3, 4]), dig([5, 6, 7, 8])])) + ); + + // Merkle tree: matrices of heights 8/4/2 and widths 2/3/1, opened at index 5. + let mut m0 = vec![f(0); 16]; + m0[10] = f(11); + m0[11] = f(12); // row 5 = [11, 12] + let mut m1 = vec![f(0); 12]; + m1[6] = f(107); + m1[7] = f(108); + m1[8] = f(109); // row 2 = [107, 108, 109] + let mut m2 = vec![f(0); 2]; + m2[1] = f(202); // row 1 = [202] + let mmcs = new_mmcs(0); + let (commit, pd) = mmcs.commit(vec![ + RowMajorMatrix::new(m0, 2), + RowMajorMatrix::new(m1, 3), + RowMajorMatrix::new(m2, 1), + ]); + let bo = mmcs.open_batch(5, &pd); + println!("OPENED {:?}", bo.opened_values); + for (i, s) in bo.opening_proof.iter().enumerate() { + println!("SIB{} {:?}", i, limbs(*s)); + } + println!("COMMIT {:?}", commit); + } + + /// Regenerates the Blake3-challenger reference values for `sample_bits_test` + /// and `pcs_challenger4_test`. + #[test] + fn gen_challenger_refs() { + use p3_challenger::{CanObserve, CanSampleBits, FieldChallenger}; + use p3_field::{BasedVectorSpace, PrimeField64}; + let g = Val::from_u64; + fn el(e: ExtVal) -> (u64, u64) { + let s: &[Val] = e.as_basis_coefficients_slice(); + (s[0].as_canonical_u64(), s[1].as_canonical_u64()) + } + // sample_bits_test: observe 0x0102030405060708, sample_bits(20). + let mut ch = Challenger::from_hasher(vec![], Blake3); + ch.observe(g(0x0102030405060708)); + println!( + "SAMPLE_BITS {}", + CanSampleBits::::sample_bits(&mut ch, 20) + ); + // pcs_challenger4_test: the α_pcs/α_fri/β/index continuation. + let mut ch = Challenger::from_hasher(vec![], Blake3); + ch.observe(g(0x0102030405060708)); + ch.observe(g(0x1122334455667788)); + let apcs: ExtVal = ch.sample_algebra_element(); + let afri: ExtVal = ch.sample_algebra_element(); + println!("APCS {:?}", el(apcs)); + println!("AFRI {:?}", el(afri)); + ch.observe(g(0x00000000deadbeef)); + let beta: ExtVal = ch.sample_algebra_element(); + println!("BETA {:?}", el(beta)); + ch.observe(g(0x0a0b0c0d01020304)); + ch.observe(g(0x0000000000000002)); + println!( + "SAMPLE_BITS2 {}", + CanSampleBits::::sample_bits(&mut ch, 20) + ); + } +} diff --git a/src/verifier.rs b/src/verifier.rs index fcc4b98..d690310 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -624,7 +624,7 @@ mod tests { lookup::LookupAir, prover::Proof, system::{ProverKey, SystemWitness}, - types::{CommitmentParameters, ExtVal, FriParameters, GoldilocksKeccakConfig, Val}, + types::{CommitmentParameters, ExtVal, FriParameters, GoldilocksBlake3Config, Val}, }; use p3_air::{AirBuilder, BaseAir, WindowAccess}; use p3_matrix::dense::RowMajorMatrix; @@ -684,10 +684,10 @@ mod tests { }; fn system() -> ( - System, - ProverKey, + System, + ProverKey, ) { - let config = GoldilocksKeccakConfig::new(COMMITMENT_PARAMETERS, FRI_PARAMETERS); + let config = GoldilocksBlake3Config::new(COMMITMENT_PARAMETERS, FRI_PARAMETERS); let pythagorean_circuit = LookupAir::new(CS::Pythagorean, vec![]); let complex_circuit = LookupAir::new(CS::Complex, vec![]); System::new(config, [pythagorean_circuit, complex_circuit]) @@ -742,8 +742,8 @@ mod tests { /// Helper: creates a small system and valid proof for negative tests. fn small_system_and_proof() -> ( - System, - Proof, + System, + Proof, ) { let (system, key) = system(); let f = Val::from_u32;