Skip to content

Commit 5e18d9a

Browse files
committed
add keccak_f precompiles & utilities
1 parent ba053c2 commit 5e18d9a

20 files changed

+2189
-45
lines changed

Cargo.lock

Lines changed: 49 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ cfg-if = "1.0"
3636
criterion = { version = "0.5", features = ["html_reports"] }
3737
crossbeam-channel = "0.5"
3838
itertools = "0.13"
39+
ndarray = "*"
3940
num-bigint = { version = "0.4.6" }
4041
num-derive = "0.4"
4142
num-traits = "0.2"

gkr_iop/Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,23 @@ ark-std.workspace = true
1414
ff_ext = { path = "../ff_ext" }
1515
itertools.workspace = true
1616
multilinear_extensions = { version = "0.1.0", path = "../multilinear_extensions" }
17+
ndarray.workspace = true
1718
p3-field.workspace = true
1819
p3-goldilocks.workspace = true
1920
rand.workspace = true
2021
rayon.workspace = true
2122
subprotocols = { path = "../subprotocols" }
2223
thiserror = "1"
24+
tiny-keccak.workspace = true
2325
transcript = { path = "../transcript" }
26+
27+
[dev-dependencies]
28+
criterion.workspace = true
29+
30+
[[bench]]
31+
harness = false
32+
name = "keccak_f"
33+
34+
[[bench]]
35+
harness = false
36+
name = "faster_keccak"

gkr_iop/benches/faster_keccak.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use std::time::Duration;
2+
3+
use criterion::*;
4+
use gkr_iop::precompiles::run_faster_keccakf;
5+
6+
use rand::{Rng, SeedableRng};
7+
criterion_group!(benches, keccak_f_fn);
8+
criterion_main!(benches);
9+
10+
const NUM_SAMPLES: usize = 10;
11+
12+
fn keccak_f_fn(c: &mut Criterion) {
13+
// expand more input size once runtime is acceptable
14+
let mut group = c.benchmark_group(format!("keccak_f"));
15+
group.sample_size(NUM_SAMPLES);
16+
17+
// Benchmark the proving time
18+
group.bench_function(BenchmarkId::new("keccak_f", format!("keccak_f")), |b| {
19+
b.iter_custom(|iters| {
20+
let mut time = Duration::new(0, 0);
21+
for _ in 0..iters {
22+
// Use seeded rng for debugging convenience
23+
let mut rng = rand::rngs::StdRng::seed_from_u64(42);
24+
let state1: [u64; 25] = std::array::from_fn(|_| rng.gen());
25+
let state2: [u64; 25] = std::array::from_fn(|_| rng.gen());
26+
27+
let instant = std::time::Instant::now();
28+
let _ = black_box(run_faster_keccakf(vec![state1, state2], false, false));
29+
let elapsed = instant.elapsed();
30+
time += elapsed;
31+
}
32+
33+
time
34+
});
35+
});
36+
37+
group.finish();
38+
}

gkr_iop/benches/keccak_f.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use std::time::Duration;
2+
3+
use criterion::*;
4+
use gkr_iop::precompiles::{run_faster_keccakf, run_keccakf};
5+
use p3_field::extension::BinomialExtensionField;
6+
use p3_goldilocks::Goldilocks;
7+
use rand::{Rng, SeedableRng};
8+
criterion_group!(benches, keccak_f_fn);
9+
criterion_main!(benches);
10+
11+
const NUM_SAMPLES: usize = 10;
12+
13+
fn keccak_f_fn(c: &mut Criterion) {
14+
// expand more input size once runtime is acceptable
15+
let mut group = c.benchmark_group(format!("keccak_f"));
16+
group.sample_size(NUM_SAMPLES);
17+
18+
// Benchmark the proving time
19+
group.bench_function(BenchmarkId::new("keccak_f", format!("keccak_f")), |b| {
20+
b.iter_custom(|iters| {
21+
let mut time = Duration::new(0, 0);
22+
for _ in 0..iters {
23+
// Use seeded rng for debugging convenience
24+
let mut rng = rand::rngs::StdRng::seed_from_u64(42);
25+
let state: [u64; 25] = std::array::from_fn(|_| rng.gen());
26+
27+
let instant = std::time::Instant::now();
28+
let _ = black_box(run_keccakf(state, false, false));
29+
let elapsed = instant.elapsed();
30+
time += elapsed;
31+
}
32+
33+
time
34+
});
35+
});
36+
37+
group.finish();
38+
}

gkr_iop/examples/multi_layer_logup.rs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@ use std::{marker::PhantomData, mem, sync::Arc};
22

33
use ff_ext::ExtensionField;
44
use gkr_iop::{
5-
ProtocolBuilder, ProtocolWitnessGenerator,
65
chip::Chip,
76
evaluation::{EvalExpression, PointAndEval},
87
gkr::{
9-
GKRCircuitWitness, GKRProverOutput,
108
layer::{Layer, LayerType, LayerWitness},
9+
GKRCircuitWitness, GKRProverOutput,
1110
},
11+
ProtocolBuilder, ProtocolWitnessGenerator,
1212
};
13-
use itertools::{Itertools, izip};
14-
use p3_field::{PrimeCharacteristicRing, extension::BinomialExtensionField};
13+
use itertools::{izip, Itertools};
14+
use p3_field::{extension::BinomialExtensionField, PrimeCharacteristicRing};
1515
use p3_goldilocks::Goldilocks;
16-
use rand::{Rng, rngs::OsRng};
16+
use rand::{rngs::OsRng, Rng};
1717
use subprotocols::expression::{Constant, Expression};
1818
use transcript::{BasicTranscript, Transcript};
1919

@@ -64,14 +64,15 @@ impl<E: ExtensionField> ProtocolBuilder for TowerChipLayout<E> {
6464
let height = self.params.height;
6565
let lookup_challenge = Expression::Const(self.lookup_challenge.clone());
6666

67-
self.output_cumulative_sum = chip.allocate_output_evals();
67+
self.output_cumulative_sum = chip.allocate_output_evals::<2>().try_into().unwrap();
6868

6969
// Tower layers
7070
let ([updated_table, count], challenges) = (0..height).fold(
7171
(self.output_cumulative_sum.clone(), vec![]),
7272
|([den, num], challenges), i| {
7373
let [den_0, den_1, num_0, num_1] = if i == height - 1 {
74-
// Allocate witnesses in the extension field, except numerator inputs in the base field.
74+
// Allocate witnesses in the extension field, except numerator inputs in the
75+
// base field.
7576
let ([num_0, num_1], [den_0, den_1]) = chip.allocate_wits_in_layer();
7677
[den_0, den_1, num_0, num_1]
7778
} else {
@@ -86,17 +87,20 @@ impl<E: ExtensionField> ProtocolBuilder for TowerChipLayout<E> {
8687
num_1.0.into(),
8788
];
8889
let (in_bases, in_exts) = if i == height - 1 {
89-
(vec![num_0.1.clone(), num_1.1.clone()], vec![
90-
den_0.1.clone(),
91-
den_1.1.clone(),
92-
])
90+
(
91+
vec![num_0.1.clone(), num_1.1.clone()],
92+
vec![den_0.1.clone(), den_1.1.clone()],
93+
)
9394
} else {
94-
(vec![], vec![
95-
den_0.1.clone(),
96-
den_1.1.clone(),
97-
num_0.1.clone(),
98-
num_1.1.clone(),
99-
])
95+
(
96+
vec![],
97+
vec![
98+
den_0.1.clone(),
99+
den_1.1.clone(),
100+
num_0.1.clone(),
101+
num_1.1.clone(),
102+
],
103+
)
100104
};
101105
chip.add_layer(Layer::new(
102106
format!("Tower_layer_{}", i),
@@ -109,6 +113,7 @@ impl<E: ExtensionField> ProtocolBuilder for TowerChipLayout<E> {
109113
in_bases,
110114
in_exts,
111115
vec![den, num],
116+
vec![],
112117
));
113118
let [challenge] = chip.allocate_challenges();
114119
(
@@ -138,6 +143,7 @@ impl<E: ExtensionField> ProtocolBuilder for TowerChipLayout<E> {
138143
vec![table.1.clone()],
139144
vec![],
140145
vec![updated_table],
146+
vec![],
141147
));
142148

143149
chip.allocate_base_opening(self.committed_table_id, table.1);

gkr_iop/src/chip/builder.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::array;
22

3+
use itertools::Itertools;
34
use subprotocols::expression::{Constant, Witness};
45

56
use crate::{
@@ -22,10 +23,11 @@ impl Chip {
2223
array::from_fn(|i| i + self.n_committed_exts - N)
2324
}
2425

25-
/// Allocate `Witness` and `EvalExpression` for the input polynomials in a layer.
26-
/// Where `Witness` denotes the index and `EvalExpression` denotes the position
27-
/// to place the evaluation of the polynomial after processing the layer prover
28-
/// for each polynomial. This should be called at most once for each layer!
26+
/// Allocate `Witness` and `EvalExpression` for the input polynomials in a
27+
/// layer. Where `Witness` denotes the index and `EvalExpression`
28+
/// denotes the position to place the evaluation of the polynomial after
29+
/// processing the layer prover for each polynomial. This should be
30+
/// called at most once for each layer!
2931
#[allow(clippy::type_complexity)]
3032
pub fn allocate_wits_in_layer<const M: usize, const N: usize>(
3133
&mut self,
@@ -51,9 +53,16 @@ impl Chip {
5153
}
5254

5355
/// Generate the evaluation expression for each output.
54-
pub fn allocate_output_evals<const N: usize>(&mut self) -> [EvalExpression; N] {
56+
pub fn allocate_output_evals<const N: usize>(&mut self) -> Vec<EvalExpression>
57+
// -> [EvalExpression; N]
58+
{
5559
self.n_evaluations += N;
56-
array::from_fn(|i| EvalExpression::Single(i + self.n_evaluations - N))
60+
//array::from_fn(|i| EvalExpression::Single(i + self.n_evaluations - N))
61+
// TODO: hotfix to avoid stack overflow, fix later
62+
(0..N)
63+
.into_iter()
64+
.map(|i| EvalExpression::Single(i + self.n_evaluations - N))
65+
.collect_vec()
5766
}
5867

5968
/// Allocate challenges.
@@ -62,14 +71,16 @@ impl Chip {
6271
array::from_fn(|i| Constant::Challenge(i + self.n_challenges - N))
6372
}
6473

65-
/// Allocate a PCS opening action to a base polynomial with index `wit_index`.
66-
/// The `EvalExpression` represents the expression to compute the evaluation.
74+
/// Allocate a PCS opening action to a base polynomial with index
75+
/// `wit_index`. The `EvalExpression` represents the expression to
76+
/// compute the evaluation.
6777
pub fn allocate_base_opening(&mut self, wit_index: usize, eval: EvalExpression) {
6878
self.base_openings.push((wit_index, eval));
6979
}
7080

71-
/// Allocate a PCS opening action to an ext polynomial with index `wit_index`.
72-
/// The `EvalExpression` represents the expression to compute the evaluation.
81+
/// Allocate a PCS opening action to an ext polynomial with index
82+
/// `wit_index`. The `EvalExpression` represents the expression to
83+
/// compute the evaluation.
7384
pub fn allocate_ext_opening(&mut self, wit_index: usize, eval: EvalExpression) {
7485
self.ext_openings.push((wit_index, eval));
7586
}

0 commit comments

Comments
 (0)