Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Goldilocks example #147

Merged
merged 4 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[workspace]
members = [ "latticefold", "cyclotomic-rings"]
members = [ "latticefold", "cyclotomic-rings" ]
resolver = "2"

[workspace.package]
Expand All @@ -19,7 +19,7 @@ lattirust-ring = { git = "ssh://[email protected]/NethermindEth/lattirust.git", bra
num-bigint = { version = "0.4.5", default-features = false }
rand = { version = "0.8.5", default-features = false }
thiserror = { version = "2.0.3", default-features = false }

cyclotomic-rings = { path = "cyclotomic-rings", default-features = false }
[workspace.metadata.docs.rs]
# To build locally, use
# RUSTDOCFLAGS="--html-in-header docs-header.html" cargo doc --no-deps --document-private-items --open
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ Available packages:
- `latticefold`: main crate, contains the non-interactive folding scheme implementation, together with the Ajtai commitment scheme, R1CS/CCS structures, Fiat-Shamir transcript machinery, etc.
- `cyclotomic-rings`: contains the trait definition of a ring suitable to be used in the LatticeFold protocol, a few ready-to-use rings and short challenge set machinery.

## Examples

Check [latticefold-examples/README.md](examples/README.md) for examples.

## Frontends

Currently, the only way to define a circuit to be folded is by specifying it as a [rank-1 constraint system (R1CS)](https://github.com/NethermindEth/latticefold/blob/main/latticefold/src/arith/r1cs.rs) or a [customizable constraint system (CCS)](https://github.com/NethermindEth/latticefold/blob/main/latticefold/src/arith.rs).
Expand Down
3 changes: 2 additions & 1 deletion latticefold/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ ark-crypto-primitives = { workspace = true }
ark-ff = { workspace = true }
ark-serialize = { workspace = true }
ark-std = { workspace = true }
cyclotomic-rings = { path = "../cyclotomic-rings", default-features = false }
cyclotomic-rings = { workspace = true }
hashbrown = "0.15"
lattirust-linear-algebra = { workspace = true }
lattirust-poly = { workspace = true }
Expand Down Expand Up @@ -59,6 +59,7 @@ implicit_clone = "warn"
[dev-dependencies]
criterion = "0.5.1"
dhat = "0.3.2"
humansize = "2.1.3"

[[bench]]
name = "ajtai"
Expand Down
48 changes: 48 additions & 0 deletions latticefold/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use std::fs;
use std::path::Path;

fn main() -> Result<(), String> {
let out_dir = std::env::var("OUT_DIR").unwrap();

let dest_path = Path::new(&out_dir).join("generated.rs");

let generated_code = format!(
r#"
// This file was automatically generated by build.rs script.
// It can be used in examples with include! macro:
// include!(concat!(env!("OUT_DIR"), "/generated.rs"));
//
// Check examples/README.md file how to use environment variables to modify the file

use latticefold::decomposition_parameters::DecompositionParams;

#[derive(Clone)]
pub struct ExampleDP {{}}

impl DecompositionParams for ExampleDP {{
const B: u128 = {}; // Default: 1 << 15
const L: usize = {}; // Default: 5
const B_SMALL: usize = {}; // Default = 2
const K: usize = {}; // Default = 15
}}

const C: usize = {}; // Default = 4
const WIT_LEN: usize = {}; // Default = 4
const W: usize = WIT_LEN * ExampleDP::L;

"#,
std::env::var("PARAM_B").unwrap_or("1 << 15".to_string()),
std::env::var("PARAM_L").unwrap_or("5".to_string()),
std::env::var("PARAM_B_SMALL").unwrap_or("2".to_string()),
std::env::var("PARAM_K").unwrap_or("15".to_string()),
std::env::var("PARAM_C").unwrap_or("4".to_string()),
std::env::var("PARAM_WIT_LEN").unwrap_or("4".to_string()),
);

fs::write(&dest_path, generated_code).unwrap();

// Optionally tell Cargo when to rerun the build script
println!("cargo:rerun-if-changed=build.rs");

Ok(())
}
87 changes: 87 additions & 0 deletions latticefold/examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Examples README

This file explains how to use the examples in this repository. Examples demonstrate functionality and can be customized using environment variables. Instructions are provided for Linux/MacOS (bash/zsh) and Windows (PowerShell).

## Implemented examples
* goldilocks

## Customization with Environment Variables

The examples in this repository support customization via environment variables. You can modify the following parameters to tailor the behavior of the examples:

- **`DECOMPOSITION_B`**: Sets the value of `B` in `DecompositionParams`.
- Default: `32768` (equivalent to `1 << 15`)
- **`DECOMPOSITION_L`**: Sets the value of `L` in `DecompositionParams`.
- Default: `5`
- **`DECOMPOSITION_B_SMALL`**: Sets the value of `B_SMALL` in `DecompositionParams`.
- Default: `2`
- **`DECOMPOSITION_K`**: Sets the value of `K` in `DecompositionParams`.
- Default: `15`
- **`DECOMPOSITION_C`**: Sets the value of `C`, controlling challenge set parameters.
- Default: `4`
- **`DECOMPOSITION_WIT_LEN`**: Sets the witness length.
- Default: `4`

These parameters influence the behavior and output of the examples.

## Setting Environment Variables

### Linux/MacOS (bash/zsh)

1. Open a terminal.
2. Export the desired environment variables before running the examples. For example:

```bash
export DECOMPOSITION_B=65536
export DECOMPOSITION_L=6
export DECOMPOSITION_B_SMALL=3
export DECOMPOSITION_K=16
export DECOMPOSITION_C=5
export DECOMPOSITION_WIT_LEN=5

cargo run --example <example_name>
```

3. Replace `<example_name>` with the name of the example you want to run.

### Windows (PowerShell)

1. Open PowerShell.
2. Set the desired environment variables before running the examples. For example:

```powershell
$env:DECOMPOSITION_B=65536
$env:DECOMPOSITION_L=6
$env:DECOMPOSITION_B_SMALL=3
$env:DECOMPOSITION_K=16
$env:DECOMPOSITION_C=5
$env:DECOMPOSITION_WIT_LEN=5

cargo run --example <example_name>
```

3. Replace `<example_name>` with the name of the example you want to run.

## Example Output

When you modify environment variables, the generated parameters are automatically updated in the example's output. This allows for testing different configurations and validating results under various conditions.

## Default Values

If no environment variables are specified, the examples will run with the following defaults:

- `DECOMPOSITION_B`: `32768`
- `DECOMPOSITION_L`: `5`
- `DECOMPOSITION_B_SMALL`: `2`
- `DECOMPOSITION_K`: `15`
- `DECOMPOSITION_C`: `4`
- `DECOMPOSITION_WIT_LEN`: `4`

## Notes

- Ensure you rebuild the examples after modifying environment variables to see the changes.
```bash
cargo clean && cargo run --example <example_name>
```

- For detailed instructions on each example, refer to the example's source code or inline comments.
164 changes: 164 additions & 0 deletions latticefold/examples/goldilocks.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
use ark_serialize::{CanonicalSerialize, Compress};
use ark_std::rand::Rng;
use ark_std::test_rng;
use ark_std::vec::Vec;
use cyclotomic_rings::challenge_set::LatticefoldChallengeSet;
use cyclotomic_rings::rings::{GoldilocksChallengeSet, GoldilocksRingNTT, SuitableRing};
use latticefold::arith::r1cs::{get_test_z_split, to_F_matrix, R1CS};
use latticefold::arith::{Witness, CCCS, CCS, LCCCS};
use latticefold::commitment::AjtaiCommitmentScheme;
use latticefold::nifs::linearization::{LFLinearizationProver, LinearizationProver};
use latticefold::nifs::{NIFSProver, NIFSVerifier};
use latticefold::transcript::poseidon::PoseidonTranscript;
use lattirust_ring::Ring;
use std::time::Instant;

include!(concat!(env!("OUT_DIR"), "/generated.rs"));

/// Generates a test R1CS matrix for the equation x^3 + x + 5 = y
/// This will be changed to be easier to customized
pub fn get_test_r1cs<R: Ring>() -> R1CS<R> {
let a = to_F_matrix::<R>(vec![
vec![1, 0, 0, 0, 0, 0],
vec![0, 0, 0, 1, 0, 0],
vec![1, 0, 0, 0, 1, 0],
vec![0, 5, 0, 0, 0, 1],
]);
let b = to_F_matrix::<R>(vec![
vec![1, 0, 0, 0, 0, 0],
vec![1, 0, 0, 0, 0, 0],
vec![0, 1, 0, 0, 0, 0],
vec![0, 1, 0, 0, 0, 0],
]);
let c = to_F_matrix::<R>(vec![
vec![0, 0, 0, 1, 0, 0],
vec![0, 0, 0, 0, 1, 0],
vec![0, 0, 0, 0, 0, 1],
vec![0, 0, 1, 0, 0, 0],
]);

R1CS {
l: 1,
A: a,
B: b,
C: c,
}
}

/// Generates a CCS from a test R1CS matrix with specified parameters
pub fn get_test_ccs<R: Ring>(w: usize, l: usize) -> CCS<R> {
let r1cs = get_test_r1cs::<R>();
CCS::<R>::from_r1cs_padded(r1cs, w, l)
}

#[allow(clippy::type_complexity)]
fn setup_example_environment<
const C: usize,
RqNTT: SuitableRing,
DP: DecompositionParams,
const W: usize,
const WIT_LEN: usize,
CS: LatticefoldChallengeSet<RqNTT>,
>() -> (
LCCCS<C, RqNTT>,
Witness<RqNTT>,
CCCS<C, RqNTT>,
Witness<RqNTT>,
CCS<RqNTT>,
AjtaiCommitmentScheme<C, W, RqNTT>,
) {
let ccs = get_test_ccs::<RqNTT>(W, DP::L);
let mut rng = test_rng();
let (_, x_ccs, w_ccs) = get_test_z_split::<RqNTT>(rng.gen_range(0..64));
let scheme = AjtaiCommitmentScheme::rand(&mut rng);

let wit_i = Witness::from_w_ccs::<DP>(w_ccs);
let cm_i = CCCS {
cm: wit_i.commit::<C, W, DP>(&scheme).unwrap(),
x_ccs: x_ccs.clone(),
};

let rand_w_ccs: Vec<RqNTT> = (0..WIT_LEN).map(|i| RqNTT::from(i as u64)).collect();
let wit_acc = Witness::from_w_ccs::<DP>(rand_w_ccs);

let mut transcript = PoseidonTranscript::<RqNTT, CS>::default();
let (acc, _) = LFLinearizationProver::<_, PoseidonTranscript<RqNTT, CS>>::prove(
&cm_i,
&wit_acc,
&mut transcript,
&ccs,
)
.unwrap();

(acc, wit_acc, cm_i, wit_i, ccs, scheme)
}

type RqNTT = GoldilocksRingNTT;
type CS = GoldilocksChallengeSet;
type T = PoseidonTranscript<RqNTT, CS>;

fn main() {
println!("Setting up example environment...");

println!("Decomposition parameters:");
println!("\tB: {}", ExampleDP::B);
println!("\tL: {}", ExampleDP::L);
println!("\tB_SMALL: {}", ExampleDP::B_SMALL);
println!("\tK: {}", ExampleDP::K);

let (acc, wit_acc, cm_i, wit_i, ccs, scheme) =
setup_example_environment::<C, RqNTT, ExampleDP, W, WIT_LEN, CS>();

let mut prover_transcript = PoseidonTranscript::<RqNTT, CS>::default();
let mut verifier_transcript = PoseidonTranscript::<RqNTT, CS>::default();
println!("Generating proof...");
let start = Instant::now();

let (_, _, proof) = NIFSProver::<C, W, RqNTT, ExampleDP, T>::prove(
&acc,
&wit_acc,
&cm_i,
&wit_i,
&mut prover_transcript,
&ccs,
&scheme,
)
.unwrap();
let duration = start.elapsed();
println!("Proof generated in {:?}", duration);

let mut serialized_proof = Vec::new();

println!("Serializing proof (with compression)...");
proof
.serialize_with_mode(&mut serialized_proof, Compress::Yes)
.unwrap();
let compressed_size = serialized_proof.len();
println!(
"Proof size (with compression) size: {}",
humansize::format_size(compressed_size, humansize::BINARY)
);

println!("Serializing proof (without compression)...");
proof
.serialize_with_mode(&mut serialized_proof, Compress::No)
.unwrap();
let uncompressed_size = serialized_proof.len();
println!(
"Proof (without compression) size: {}",
humansize::format_size(uncompressed_size, humansize::BINARY)
);

println!("Verifying proof");
let start = Instant::now();
NIFSVerifier::<C, RqNTT, ExampleDP, T>::verify(
&acc,
&cm_i,
&proof,
&mut verifier_transcript,
&ccs,
)
.unwrap();
let duration = start.elapsed();
println!("Proof verified in {:?}", duration);
}
4 changes: 3 additions & 1 deletion latticefold/src/nifs.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::marker::PhantomData;
use ark_std::vec::Vec;

use cyclotomic_rings::rings::SuitableRing;
use lattirust_ring::OverField;
Expand Down Expand Up @@ -27,7 +29,7 @@ mod tests;

/// `C` is the length of Ajtai commitment vectors.
/// `NTT` is a cyclotomic ring in the NTT form.
#[derive(Clone)]
#[derive(Clone, CanonicalSerialize, CanonicalDeserialize)]
pub struct LFProof<const C: usize, NTT: OverField> {
pub linearization_proof: LinearizationProof<NTT>,
pub decomposition_proof_l: DecompositionProof<C, NTT>,
Expand Down
Loading