-
Notifications
You must be signed in to change notification settings - Fork 189
Feat/univariate logup gkr #1188
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
Changes from 18 commits
9b1e4be
425f966
3909f3b
63339a6
c1bc086
0040d41
a14ec48
c3703e9
bdd26a0
64da7d1
866cc4c
9ac1f19
3caf15c
7bd9704
e4ec89d
cb0f6f1
a3919c8
2d73e22
3a5c460
e0030fb
d47a275
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,93 @@ | ||
| use lambdaworks_math::field::element::FieldElement; | ||
| use lambdaworks_math::field::fields::fft_friendly::quartic_babybear::Degree4BabyBearExtensionField; | ||
|
|
||
| use lambdaworks_gkr_logup::layer::Layer; | ||
| use lambdaworks_gkr_logup::prover; | ||
| use lambdaworks_gkr_logup::verifier::{verify, Gate}; | ||
|
|
||
| use lambdaworks_crypto::fiat_shamir::default_transcript::DefaultTranscript; | ||
|
|
||
| type F = Degree4BabyBearExtensionField; | ||
| type FE = FieldElement<F>; | ||
|
|
||
| fn main() { | ||
| println!("=== LogUp-GKR (Multilinear MLE) ===\n"); | ||
|
|
||
| test_logup_singles(); | ||
| test_read_only_memory(); | ||
|
|
||
| println!("\n=== All tests passed! ==="); | ||
| } | ||
|
|
||
| fn test_logup_singles() { | ||
| println!("Test 1: LogUp Singles (ROM lookup)"); | ||
|
|
||
| // z - access[i] denominators (multilinear MLE) | ||
| let z = FE::from(100u64); | ||
| let accesses: Vec<u64> = vec![20, 10, 20, 30, 10, 20, 40, 30]; | ||
|
|
||
| let mle_values: Vec<FE> = accesses.iter().map(|&a| z - FE::from(a)).collect(); | ||
|
|
||
| use lambdaworks_math::polynomial::DenseMultilinearPolynomial; | ||
| let mle = DenseMultilinearPolynomial::new(mle_values); | ||
|
|
||
| let layer = Layer::LogUpSingles { denominators: mle }; | ||
|
|
||
| println!(" Layer n_variables: {}", layer.n_variables()); | ||
|
|
||
| let mut transcript = DefaultTranscript::<F>::new(b"test1"); | ||
|
|
||
| match prover::prove(&mut transcript, layer) { | ||
| Ok((proof, _)) => { | ||
| println!(" Proof generated!"); | ||
|
|
||
| let gate = Gate::LogUp; | ||
| let mut transcript_verify = DefaultTranscript::<F>::new(b"test1"); | ||
|
|
||
| match verify(gate, &proof, &mut transcript_verify) { | ||
| Ok(_) => println!(" ✓ LogUp Singles works!"), | ||
| Err(e) => println!(" ✗ Verify error: {:?}", e), | ||
| } | ||
| } | ||
| Err(e) => println!(" Error: {:?}", e), | ||
| } | ||
| } | ||
|
|
||
| fn test_read_only_memory() { | ||
| println!("\nTest 2: Read Only Memory (2 columns)"); | ||
|
|
||
| let z = FE::from(1000u64); | ||
| let accesses: Vec<u64> = vec![5, 3, 5, 7, 3, 5, 9, 7]; | ||
| let table: Vec<u64> = vec![3, 5, 7, 9, 11, 13, 15, 17]; | ||
|
|
||
| let access_dens: Vec<FE> = accesses.iter().map(|&a| z - FE::from(a)).collect(); | ||
| let table_dens: Vec<FE> = table.iter().map(|&t| z - FE::from(t)).collect(); | ||
|
|
||
| use lambdaworks_math::polynomial::DenseMultilinearPolynomial; | ||
| let access_mle = DenseMultilinearPolynomial::new(access_dens); | ||
| let table_mle = DenseMultilinearPolynomial::new(table_dens); | ||
|
|
||
| let layer = Layer::LogUpMultiplicities { | ||
| numerators: table_mle, | ||
| denominators: access_mle, | ||
| }; | ||
|
|
||
| println!(" Layer n_variables: {}", layer.n_variables()); | ||
|
|
||
| let mut transcript = DefaultTranscript::<F>::new(b"test2"); | ||
|
|
||
| match prover::prove(&mut transcript, layer) { | ||
| Ok((proof, _)) => { | ||
| println!(" Proof generated!"); | ||
|
|
||
| let gate = Gate::LogUp; | ||
| let mut transcript_verify = DefaultTranscript::<F>::new(b"test2"); | ||
|
|
||
| match verify(gate, &proof, &mut transcript_verify) { | ||
| Ok(_) => println!(" ✓ Read Only Memory works!"), | ||
| Err(e) => println!(" ✗ Verify error: {:?}", e), | ||
| } | ||
| } | ||
| Err(e) => println!(" Error: {:?}", e), | ||
| } | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correctness:
Security:
Performance:
Bugs & Errors:
Code Simplicity:
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -76,9 +76,9 @@ fn main() { | |
| // Prove: batch both instances into a single GKR proof | ||
| // ------------------------------------------------------- | ||
| println!("--- Proving ---"); | ||
| let mut prover_channel = DefaultTranscript::<F>::new(&[]); | ||
| let mut prover_transcript = DefaultTranscript::<F>::new(&[]); | ||
| let (proof, _artifact) = | ||
| prove_batch(&mut prover_channel, vec![access_layer, table_layer]).unwrap(); | ||
| prove_batch(&mut prover_transcript, vec![access_layer, table_layer]).unwrap(); | ||
|
|
||
| println!( | ||
| "Batch proof: {} sumcheck layers, {} instances", | ||
|
|
@@ -91,8 +91,12 @@ fn main() { | |
| // Verify: batch verification | ||
| // ------------------------------------------------------- | ||
| println!("--- Verifying ---"); | ||
| let mut verifier_channel = DefaultTranscript::<F>::new(&[]); | ||
| let result = verify_batch(&[Gate::LogUp, Gate::LogUp], &proof, &mut verifier_channel); | ||
| let mut verifier_transcript = DefaultTranscript::<F>::new(&[]); | ||
| let result = verify_batch( | ||
| &[Gate::LogUp, Gate::LogUp], | ||
| &proof, | ||
| &mut verifier_transcript, | ||
| ); | ||
|
|
||
| match &result { | ||
| Ok(artifact) => { | ||
|
|
@@ -151,11 +155,16 @@ fn main() { | |
| denominators: DenseMultilinearPolynomial::new(table_dens2), | ||
| }; | ||
|
|
||
| let mut p_ch = DefaultTranscript::<F>::new(&[]); | ||
| let (bad_proof, _) = prove_batch(&mut p_ch, vec![bad_access_layer, table_layer2]).unwrap(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correctness
Security
Performance
Bugs & Errors
Code Simplicity
Overall, while the code shows positive strides in clarity and correctness, the handling of possible errors and ensuring security motives through constant-time operations need attention before considering merging. |
||
| let mut prover_transcript = DefaultTranscript::<F>::new(&[]); | ||
| let (bad_proof, _) = | ||
| prove_batch(&mut prover_transcript, vec![bad_access_layer, table_layer2]).unwrap(); | ||
|
|
||
| let mut v_ch = DefaultTranscript::<F>::new(&[]); | ||
| let bad_result = verify_batch(&[Gate::LogUp, Gate::LogUp], &bad_proof, &mut v_ch); | ||
| let mut verifier_transcript = DefaultTranscript::<F>::new(&[]); | ||
| let bad_result = verify_batch( | ||
| &[Gate::LogUp, Gate::LogUp], | ||
| &bad_proof, | ||
| &mut verifier_transcript, | ||
| ); | ||
|
|
||
| match &bad_result { | ||
| Ok(_) => println!("GKR verification: PASSED (each tree is internally consistent)"), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correctness
Security
Performance
Bugs & Errors
Code Simplicity
Consider addressing these points before merging the code. |
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| //! End-to-end example of the univariate LogUp-GKR IOP (Section 5 of ePrint 2023/1284). | ||
| //! | ||
| //! Demonstrates: | ||
| //! 1. LogUp Singles: ROM lookup with univariate commitments | ||
| //! 2. LogUp Multiplicities: table + multiplicities with univariate commitments | ||
| //! 3. Grand Product: simple product argument with univariate commitments | ||
|
|
||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Without more contextual information, it cannot be marked as suitable for merging as it stands, due to potential unchecked error scenarios and optimizations that might not be in place. |
||
| use lambdaworks_math::field::element::FieldElement; | ||
| use lambdaworks_math::field::fields::fft_friendly::quartic_babybear::Degree4BabyBearExtensionField; | ||
|
|
||
| use lambdaworks_crypto::fiat_shamir::default_transcript::DefaultTranscript; | ||
|
|
||
| use lambdaworks_gkr_logup::univariate::domain::CyclicDomain; | ||
| use lambdaworks_gkr_logup::univariate::iop::{prove_univariate, verify_univariate}; | ||
| use lambdaworks_gkr_logup::univariate::lagrange::UnivariateLagrange; | ||
| use lambdaworks_gkr_logup::univariate_layer::UnivariateLayer; | ||
| use lambdaworks_gkr_logup::verifier::Gate; | ||
|
|
||
| type F = Degree4BabyBearExtensionField; | ||
| type FE = FieldElement<F>; | ||
|
|
||
| fn main() { | ||
| println!("=== Univariate LogUp-GKR IOP (Section 5) ===\n"); | ||
|
|
||
| test_grand_product(); | ||
| test_logup_singles(); | ||
| test_logup_multiplicities(); | ||
|
|
||
| println!("\n=== All examples passed! ==="); | ||
| } | ||
|
|
||
| fn test_grand_product() { | ||
| println!("Example 1: Grand Product (univariate commitment)"); | ||
|
|
||
| let values: Vec<FE> = (1..=8).map(|i| FE::from(i as u64)).collect(); | ||
| let domain = CyclicDomain::new(3).unwrap(); | ||
| let uni = UnivariateLagrange::new(values, domain).unwrap(); | ||
|
|
||
| let layer = UnivariateLayer::GrandProduct { | ||
| values: uni, | ||
| commitment: None, | ||
| }; | ||
|
|
||
| let mut prover_transcript = DefaultTranscript::<F>::new(b"grand_product_example"); | ||
| let (proof, result) = prove_univariate(&mut prover_transcript, layer).unwrap(); | ||
|
|
||
| println!( | ||
| " Proof generated: {} GKR layers", | ||
| proof.gkr_proof.sumcheck_proofs.len() | ||
| ); | ||
| println!(" OOD point dimension: {}", result.ood_point.len()); | ||
| println!(" Claims to verify: {}", result.claims_to_verify.len()); | ||
|
|
||
| let mut verifier_transcript = DefaultTranscript::<F>::new(b"grand_product_example"); | ||
| verify_univariate(Gate::GrandProduct, &proof, &mut verifier_transcript).unwrap(); | ||
|
|
||
| println!(" ✓ Grand Product verified!\n"); | ||
| } | ||
|
|
||
| fn test_logup_singles() { | ||
| println!("Example 2: LogUp Singles (ROM lookup)"); | ||
|
|
||
| // Simulate a ROM lookup: 8 accesses to a table | ||
| let z = FE::from(100u64); | ||
| let accesses: Vec<u64> = vec![20, 10, 20, 30, 10, 20, 40, 30]; | ||
| let dens: Vec<FE> = accesses.iter().map(|&a| z - FE::from(a)).collect(); | ||
|
|
||
| let domain = CyclicDomain::new(3).unwrap(); | ||
| let uni = UnivariateLagrange::new(dens, domain).unwrap(); | ||
|
|
||
| let layer = UnivariateLayer::LogUpSingles { | ||
| denominators: uni, | ||
| denominator_commitment: None, | ||
| }; | ||
|
|
||
| let mut prover_transcript = DefaultTranscript::<F>::new(b"logup_singles_example"); | ||
| let (proof, result) = prove_univariate(&mut prover_transcript, layer).unwrap(); | ||
|
|
||
| println!( | ||
| " Proof generated: {} GKR layers", | ||
| proof.gkr_proof.sumcheck_proofs.len() | ||
| ); | ||
| println!(" OOD point dimension: {}", result.ood_point.len()); | ||
| println!(" Lagrange column size: {}", proof.lagrange_column.len()); | ||
|
|
||
| let mut verifier_transcript = DefaultTranscript::<F>::new(b"logup_singles_example"); | ||
| verify_univariate(Gate::LogUp, &proof, &mut verifier_transcript).unwrap(); | ||
|
|
||
| println!(" ✓ LogUp Singles verified!\n"); | ||
| } | ||
|
|
||
| fn test_logup_multiplicities() { | ||
| println!("Example 3: LogUp Multiplicities (table + multiplicities)"); | ||
|
|
||
| let z = FE::from(1000u64); | ||
| let table: Vec<u64> = vec![3, 5, 7, 9, 11, 13, 15, 17]; | ||
|
|
||
| let table_dens: Vec<FE> = table.iter().map(|&t| z - FE::from(t)).collect(); | ||
| let multiplicities: Vec<FE> = table.iter().map(|_| FE::one()).collect(); | ||
|
|
||
| let domain = CyclicDomain::new(3).unwrap(); | ||
| let num = UnivariateLagrange::new(multiplicities, domain.clone()).unwrap(); | ||
| let den = UnivariateLagrange::new(table_dens, domain).unwrap(); | ||
|
|
||
| let layer = UnivariateLayer::LogUpMultiplicities { | ||
| numerators: num, | ||
| denominators: den, | ||
| numerator_commitment: None, | ||
| denominator_commitment: None, | ||
| }; | ||
|
|
||
| let mut prover_transcript = DefaultTranscript::<F>::new(b"logup_mult_example"); | ||
| let (proof, result) = prove_univariate(&mut prover_transcript, layer).unwrap(); | ||
|
|
||
| println!( | ||
| " Proof generated: {} GKR layers", | ||
| proof.gkr_proof.sumcheck_proofs.len() | ||
| ); | ||
| println!(" Committed columns: {}", proof.committed_columns.len()); | ||
| println!(" OOD point dimension: {}", result.ood_point.len()); | ||
|
|
||
| let mut verifier_transcript = DefaultTranscript::<F>::new(b"logup_mult_example"); | ||
| verify_univariate(Gate::LogUp, &proof, &mut verifier_transcript).unwrap(); | ||
|
|
||
| println!(" ✓ LogUp Multiplicities verified!\n"); | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correctness
Security
Performance
Bugs & Errors
Code Simplicity
This code demonstrates structured tests for a cryptographic library but has multiple concerns around error handling and security aspects. Address these before merging. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correctness:
Security:
DefaultTranscriptimplementation and theprovefunctions are side-channel resistant and follow cryptographic practices such as zeroization and secure randomness. The snippet itself does not contain any suspicious constructs in this regard, but this needs confirmation in the broader implementation context.Performance:
Vec<Layer<F>>to collect layers suggests some memory allocations, which is standard for batch processing. Ensure that these allocations are efficient and unavoidable.Bugs & Errors:
make_grand_product_layerandmake_logup_layerhandle potential errors internally.saturating_subshould be carefully reviewed for correct handling.Code Simplicity:
channeltotranscriptlacks clear justification visually but might imply a semantic shift or improved clarity when referring to thetranscript. If there is indeed a difference, more refactoring could consolidate similar repetitive patterns.channeltotranscriptmainly impacts code readability and clarity, assumingtranscriptmore accurately describes the variable's purpose. No overly complex implementations or duplicated code in the provided snippet itself need addressing.