Skip to content

Commit a44b63b

Browse files
authored
Reed Solomon Trait (#199)
* Reed Solomon: Trait for Reed Solomon specialization * Reed Solomon: switch to trait object instead of generics. * Reed Solomon: move to WhirConfig * fixup! Reed Solomon: move to WhirConfig * Clippy: silence missing fields in WhirConfig The vTables do not have an printable value. * main: split type reflection of field and merkle into two phases.
1 parent 3d627d3 commit a44b63b

8 files changed

Lines changed: 274 additions & 121 deletions

File tree

src/bin/benchmark.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::{
22
fs::OpenOptions,
33
io::Write,
4+
sync::Arc,
45
time::{Duration, Instant},
56
};
67

@@ -25,6 +26,7 @@ use whir::{
2526
HashCounter,
2627
},
2728
},
29+
ntt::RSDefault,
2830
parameters::{
2931
default_max_pow, DeduplicationStrategy, FoldingFactor, MerkleProofStrategy,
3032
MultivariateParameters, ProtocolParameters, SoundnessType,
@@ -285,7 +287,14 @@ fn run_whir<F, MerkleConfig>(
285287
initial_statement: false,
286288
..whir_params.clone()
287289
};
288-
let params = WhirConfig::<F, MerkleConfig, PowStrategy>::new(mv_params, whir_params);
290+
let reed_solomon = Arc::new(RSDefault);
291+
let basefield_reed_solomon = reed_solomon.clone();
292+
let params = WhirConfig::<F, MerkleConfig, PowStrategy>::new(
293+
reed_solomon,
294+
basefield_reed_solomon,
295+
mv_params,
296+
whir_params,
297+
);
289298
if !params.check_pow_bits() {
290299
println!("WARN: more PoW bits required than what specified.");
291300
}
@@ -356,7 +365,14 @@ fn run_whir<F, MerkleConfig>(
356365
prover::Prover, verifier::Verifier,
357366
};
358367

359-
let params = WhirConfig::<F, MerkleConfig, PowStrategy>::new(mv_params, whir_params);
368+
let reed_solomon = Arc::new(RSDefault);
369+
370+
let params = WhirConfig::<F, MerkleConfig, PowStrategy>::new(
371+
reed_solomon.clone(),
372+
reed_solomon,
373+
mv_params,
374+
whir_params,
375+
);
360376
if !params.check_pow_bits() {
361377
println!("WARN: more PoW bits required than what specified.");
362378
}

src/bin/main.rs

Lines changed: 77 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::time::Instant;
1+
use std::{sync::Arc, time::Instant};
22

33
use ark_crypto_primitives::{
44
crh::{CRHScheme, TwoToOneCRHScheme},
@@ -20,6 +20,7 @@ use whir::{
2020
HashCounter,
2121
},
2222
},
23+
ntt::{RSDefault, ReedSolomon},
2324
parameters::{
2425
default_max_pow, DeduplicationStrategy, FoldingFactor, MerkleProofStrategy,
2526
MultivariateParameters, ProtocolParameters, SoundnessType,
@@ -89,109 +90,76 @@ fn main() {
8990
args.pow_bits = Some(default_max_pow(args.num_variables, args.rate));
9091
}
9192

92-
let mut rng = ark_std::test_rng();
93-
94-
match (field, merkle) {
95-
(AvailableFields::Goldilocks1, AvailableMerkle::Blake3) => {
96-
use fields::Field64 as F;
97-
98-
let (leaf_hash_params, two_to_one_params) =
99-
default_config::<F, Blake3LeafHash<F>, Blake3Compress>(&mut rng);
100-
run_whir::<F, Blake3MerkleTreeParams<F>>(&args, leaf_hash_params, two_to_one_params);
101-
}
93+
runner(&args, field, merkle);
94+
}
10295

103-
(AvailableFields::Goldilocks1, AvailableMerkle::Keccak256) => {
96+
fn runner(args: &Args, field: AvailableFields, merkle: AvailableMerkle) {
97+
// Type reflection on field
98+
match field {
99+
AvailableFields::Goldilocks1 => {
104100
use fields::Field64 as F;
105-
106-
let (leaf_hash_params, two_to_one_params) =
107-
default_config::<F, KeccakLeafHash<F>, KeccakCompress>(&mut rng);
108-
run_whir::<F, KeccakMerkleTreeParams<F>>(&args, leaf_hash_params, two_to_one_params);
101+
runner_merkle::<F>(args, merkle);
109102
}
110-
111-
(AvailableFields::Goldilocks2, AvailableMerkle::Blake3) => {
103+
AvailableFields::Goldilocks2 => {
112104
use fields::Field64_2 as F;
113-
114-
let (leaf_hash_params, two_to_one_params) =
115-
default_config::<F, Blake3LeafHash<F>, Blake3Compress>(&mut rng);
116-
run_whir::<F, Blake3MerkleTreeParams<F>>(&args, leaf_hash_params, two_to_one_params);
105+
runner_merkle::<F>(args, merkle);
117106
}
118-
119-
(AvailableFields::Goldilocks2, AvailableMerkle::Keccak256) => {
120-
use fields::Field64_2 as F;
121-
122-
let (leaf_hash_params, two_to_one_params) =
123-
default_config::<F, KeccakLeafHash<F>, KeccakCompress>(&mut rng);
124-
run_whir::<F, KeccakMerkleTreeParams<F>>(&args, leaf_hash_params, two_to_one_params);
125-
}
126-
127-
(AvailableFields::Goldilocks3, AvailableMerkle::Blake3) => {
107+
AvailableFields::Goldilocks3 => {
128108
use fields::Field64_3 as F;
129-
130-
let (leaf_hash_params, two_to_one_params) =
131-
default_config::<F, Blake3LeafHash<F>, Blake3Compress>(&mut rng);
132-
run_whir::<F, Blake3MerkleTreeParams<F>>(&args, leaf_hash_params, two_to_one_params);
133-
}
134-
135-
(AvailableFields::Goldilocks3, AvailableMerkle::Keccak256) => {
136-
use fields::Field64_3 as F;
137-
138-
let (leaf_hash_params, two_to_one_params) =
139-
default_config::<F, KeccakLeafHash<F>, KeccakCompress>(&mut rng);
140-
run_whir::<F, KeccakMerkleTreeParams<F>>(&args, leaf_hash_params, two_to_one_params);
109+
runner_merkle::<F>(args, merkle);
141110
}
142-
143-
(AvailableFields::Field128, AvailableMerkle::Blake3) => {
111+
AvailableFields::Field128 => {
144112
use fields::Field128 as F;
145-
146-
let (leaf_hash_params, two_to_one_params) =
147-
default_config::<F, Blake3LeafHash<F>, Blake3Compress>(&mut rng);
148-
run_whir::<F, Blake3MerkleTreeParams<F>>(&args, leaf_hash_params, two_to_one_params);
113+
runner_merkle::<F>(args, merkle);
149114
}
150-
151-
(AvailableFields::Field128, AvailableMerkle::Keccak256) => {
152-
use fields::Field128 as F;
153-
154-
let (leaf_hash_params, two_to_one_params) =
155-
default_config::<F, KeccakLeafHash<F>, KeccakCompress>(&mut rng);
156-
run_whir::<F, KeccakMerkleTreeParams<F>>(&args, leaf_hash_params, two_to_one_params);
157-
}
158-
159-
(AvailableFields::Field192, AvailableMerkle::Blake3) => {
115+
AvailableFields::Field192 => {
160116
use fields::Field192 as F;
161-
162-
let (leaf_hash_params, two_to_one_params) =
163-
default_config::<F, Blake3LeafHash<F>, Blake3Compress>(&mut rng);
164-
run_whir::<F, Blake3MerkleTreeParams<F>>(&args, leaf_hash_params, two_to_one_params);
117+
runner_merkle::<F>(args, merkle);
165118
}
166-
167-
(AvailableFields::Field192, AvailableMerkle::Keccak256) => {
168-
use fields::Field192 as F;
169-
170-
let (leaf_hash_params, two_to_one_params) =
171-
default_config::<F, KeccakLeafHash<F>, KeccakCompress>(&mut rng);
172-
run_whir::<F, KeccakMerkleTreeParams<F>>(&args, leaf_hash_params, two_to_one_params);
119+
AvailableFields::Field256 => {
120+
use fields::Field256 as F;
121+
runner_merkle::<F>(args, merkle);
173122
}
123+
}
124+
}
174125

175-
(AvailableFields::Field256, AvailableMerkle::Blake3) => {
176-
use fields::Field256 as F;
126+
fn runner_merkle<F: FftField + CanonicalSerialize>(args: &Args, merkle: AvailableMerkle) {
127+
let mut rng = ark_std::test_rng();
128+
129+
let reed_solomon = Arc::new(RSDefault);
130+
let basefield_reed_solomon = reed_solomon.clone();
177131

132+
// Type reflection on merkle
133+
match merkle {
134+
AvailableMerkle::Blake3 => {
178135
let (leaf_hash_params, two_to_one_params) =
179136
default_config::<F, Blake3LeafHash<F>, Blake3Compress>(&mut rng);
180-
run_whir::<F, Blake3MerkleTreeParams<F>>(&args, leaf_hash_params, two_to_one_params);
137+
run_whir::<F, Blake3MerkleTreeParams<F>>(
138+
args,
139+
reed_solomon,
140+
basefield_reed_solomon,
141+
leaf_hash_params,
142+
two_to_one_params,
143+
);
181144
}
182-
183-
(AvailableFields::Field256, AvailableMerkle::Keccak256) => {
184-
use fields::Field256 as F;
185-
145+
AvailableMerkle::Keccak256 => {
186146
let (leaf_hash_params, two_to_one_params) =
187147
default_config::<F, KeccakLeafHash<F>, KeccakCompress>(&mut rng);
188-
run_whir::<F, KeccakMerkleTreeParams<F>>(&args, leaf_hash_params, two_to_one_params);
148+
run_whir::<F, KeccakMerkleTreeParams<F>>(
149+
args,
150+
reed_solomon,
151+
basefield_reed_solomon,
152+
leaf_hash_params,
153+
two_to_one_params,
154+
);
189155
}
190156
}
191157
}
192158

193159
fn run_whir<F, MerkleConfig>(
194160
args: &Args,
161+
reed_solomon: Arc<dyn ReedSolomon<F>>,
162+
basefield_reed_solomon: Arc<dyn ReedSolomon<F::BasePrimeField>>,
195163
leaf_hash_params: <<MerkleConfig as Config>::LeafHash as CRHScheme>::Parameters,
196164
two_to_one_params: <<MerkleConfig as Config>::TwoToOneHash as TwoToOneCRHScheme>::Parameters,
197165
) where
@@ -204,16 +172,30 @@ fn run_whir<F, MerkleConfig>(
204172
{
205173
match args.protocol_type {
206174
WhirType::PCS => {
207-
run_whir_pcs::<F, MerkleConfig>(args, leaf_hash_params, two_to_one_params);
175+
run_whir_pcs::<F, MerkleConfig>(
176+
args,
177+
reed_solomon,
178+
basefield_reed_solomon,
179+
leaf_hash_params,
180+
two_to_one_params,
181+
);
208182
}
209183
WhirType::LDT => {
210-
run_whir_as_ldt::<F, MerkleConfig>(args, leaf_hash_params, two_to_one_params);
184+
run_whir_as_ldt::<F, MerkleConfig>(
185+
args,
186+
reed_solomon,
187+
basefield_reed_solomon,
188+
leaf_hash_params,
189+
two_to_one_params,
190+
);
211191
}
212192
}
213193
}
214194

215195
fn run_whir_as_ldt<F, MerkleConfig>(
216196
args: &Args,
197+
reed_solomon: Arc<dyn ReedSolomon<F>>,
198+
basefield_reed_solomon: Arc<dyn ReedSolomon<F::BasePrimeField>>,
217199
leaf_hash_params: <<MerkleConfig as Config>::LeafHash as CRHScheme>::Parameters,
218200
two_to_one_params: <<MerkleConfig as Config>::TwoToOneHash as TwoToOneCRHScheme>::Parameters,
219201
) where
@@ -265,7 +247,12 @@ fn run_whir_as_ldt<F, MerkleConfig>(
265247
merkle_proof_strategy: MerkleProofStrategy::Compressed,
266248
};
267249

268-
let params = WhirConfig::<F, MerkleConfig, PowStrategy>::new(mv_params, whir_params);
250+
let params = WhirConfig::<F, MerkleConfig, PowStrategy>::new(
251+
reed_solomon,
252+
basefield_reed_solomon,
253+
mv_params,
254+
whir_params,
255+
);
269256

270257
let domainsep = DomainSeparator::new("🌪️")
271258
.commit_statement(&params)
@@ -328,6 +315,8 @@ fn run_whir_as_ldt<F, MerkleConfig>(
328315
#[allow(clippy::too_many_lines)]
329316
fn run_whir_pcs<F, MerkleConfig>(
330317
args: &Args,
318+
reed_solomon: Arc<dyn ReedSolomon<F>>,
319+
basefield_reed_solomon: Arc<dyn ReedSolomon<F::BasePrimeField>>,
331320
leaf_hash_params: <<MerkleConfig as Config>::LeafHash as CRHScheme>::Parameters,
332321
two_to_one_params: <<MerkleConfig as Config>::TwoToOneHash as TwoToOneCRHScheme>::Parameters,
333322
) where
@@ -381,7 +370,12 @@ fn run_whir_pcs<F, MerkleConfig>(
381370
merkle_proof_strategy: MerkleProofStrategy::Compressed,
382371
};
383372

384-
let params = WhirConfig::<F, MerkleConfig, PowStrategy>::new(mv_params, whir_params);
373+
let params = WhirConfig::<F, MerkleConfig, PowStrategy>::new(
374+
reed_solomon,
375+
basefield_reed_solomon,
376+
mv_params,
377+
whir_params,
378+
);
385379

386380
let domainsep = DomainSeparator::new("🌪️")
387381
.commit_statement(&params)

src/ntt/mod.rs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ pub fn interleaved_rs_encode<F: FftField>(
5050

5151
let rows = expanded_size / fold_factor_exp;
5252
let columns = fold_factor_exp;
53-
5453
//
5554
// 2. Convert from column-major (interleaved form) to row-major
5655
// representation.
@@ -63,6 +62,30 @@ pub fn interleaved_rs_encode<F: FftField>(
6362
result
6463
}
6564

65+
/// Trait for replacing the default Reed Solomon encoding ([`RSDefault`]) with an specialised Reed Solomon encoder for the FFTField and BasePrimeField
66+
pub trait ReedSolomon<F: FftField> {
67+
fn interleaved_encode(
68+
&self,
69+
interleaved_coeffs: &[F],
70+
expansion: usize,
71+
fold_factor: usize,
72+
) -> Vec<F>;
73+
}
74+
75+
/// Tag to select the built-in Reed Solomon Encoding
76+
pub struct RSDefault;
77+
78+
impl<F: FftField> ReedSolomon<F> for RSDefault {
79+
fn interleaved_encode(
80+
&self,
81+
interleaved_coeffs: &[F],
82+
expansion: usize,
83+
fold_factor: usize,
84+
) -> Vec<F> {
85+
interleaved_rs_encode(interleaved_coeffs, expansion, fold_factor)
86+
}
87+
}
88+
6689
#[cfg(test)]
6790
mod tests {
6891
use ark_ff::Field;
@@ -264,8 +287,10 @@ mod tests {
264287
folding_factor,
265288
);
266289

290+
let rs = RSDefault;
291+
267292
// Compute things the new way
268-
let interleaved_ntt = interleaved_rs_encode(&poly, expansion, folding_factor);
293+
let interleaved_ntt = rs.interleaved_encode(&poly, expansion, folding_factor);
269294
assert_eq!(expected, interleaved_ntt);
270295
}
271296
}

src/whir/batching.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
///
2626
#[cfg(test)]
2727
mod batching_tests {
28+
use std::sync::Arc;
29+
2830
use ark_std::UniformRand;
2931
use spongefish::DomainSeparator;
3032
use spongefish_pow::blake3::Blake3PoW;
@@ -37,6 +39,7 @@ mod batching_tests {
3739
parameters::default_config,
3840
},
3941
},
42+
ntt::RSDefault,
4043
parameters::{
4144
DeduplicationStrategy, FoldingFactor, MerkleProofStrategy, MultivariateParameters,
4245
ProtocolParameters, SoundnessType,
@@ -120,9 +123,11 @@ mod batching_tests {
120123
deduplication_strategy: DeduplicationStrategy::Enabled,
121124
merkle_proof_strategy: MerkleProofStrategy::Compressed,
122125
};
126+
let reed_solomon = Arc::new(RSDefault);
127+
let basefield_reed_solomon = reed_solomon.clone();
123128

124129
// Build global configuration from multivariate + protocol parameters
125-
let params = WhirConfig::new(mv_params, whir_params);
130+
let params = WhirConfig::new(reed_solomon, basefield_reed_solomon, mv_params, whir_params);
126131

127132
let mut poly_list = Vec::<CoefficientList<F>>::with_capacity(batch_size);
128133

0 commit comments

Comments
 (0)