Skip to content

Commit f9ea022

Browse files
authored
Sumcheck Rust Docs (#779)
1 parent 4500135 commit f9ea022

File tree

9 files changed

+425
-103
lines changed

9 files changed

+425
-103
lines changed
+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Sumcheck
2+
3+
## Sumcheck API Overview
4+
5+
### **Structs**
6+
7+
#### `SumcheckTranscriptConfig`
8+
Configuration structure for the SumCheck protocol’s transcript.
9+
10+
##### **Fields:**
11+
- `hash: &Hasher` - Reference to the hashing function used.
12+
- `domain_separator_label: Vec<u8>` - Domain separator label for transcript uniqueness.
13+
- `round_poly_label: Vec<u8>` - Label for the polynomial at each round.
14+
- `round_challenge_label: Vec<u8>` - Label for the challenge at each round.
15+
- `little_endian: bool` - Whether to use little-endian encoding.
16+
- `seed_rng: F` - Random number generator seed.
17+
18+
##### **Methods:**
19+
- **`new(hash, domain_separator_label, round_poly_label, round_challenge_label, little_endian, seed_rng) -> Self`**:
20+
Constructs a new `SumcheckTranscriptConfig` with explicit parameters.
21+
22+
- **`from_string_labels(hash, domain_separator_label, round_poly_label, round_challenge_label, little_endian, seed_rng) -> Self`**:
23+
Convenience constructor using string labels.
24+
25+
#### `SumcheckConfig`
26+
General configuration for the SumCheck execution.
27+
28+
##### **Fields:**
29+
- `stream: IcicleStreamHandle` - Stream for asynchronous execution (default: `nullptr`).
30+
- `use_extension_field: bool` - Whether to use an extension field for Fiat-Shamir transformation. Sumcheck currently does not support extension fields, always set to `false` otherwise return an error.
31+
- `batch: u64` - Number of input chunks to hash in batch (default: 1).
32+
- `are_inputs_on_device: bool` - Whether inputs reside on the device (e.g., GPU).
33+
- `is_async: bool` - Whether hashing is run asynchronously.
34+
- `ext: ConfigExtension` - Pointer to backend-specific configuration extensions.
35+
36+
##### **Methods:**
37+
- **`default() -> Self`**:
38+
Returns a default `SumcheckConfig` instance.
39+
40+
### **Traits**
41+
42+
#### `Sumcheck`
43+
Defines the main API for SumCheck operations.
44+
45+
##### **Associated Types:**
46+
- `Field: FieldImpl + Arithmetic` - The field implementation used.
47+
- `FieldConfig: FieldConfig + GenerateRandom<Self::Field> + FieldArithmetic<Self::Field>` - Field configuration.
48+
- `Proof: SumcheckProofOps<Self::Field>` - Type representing the proof.
49+
50+
##### **Methods:**
51+
- **`new() -> Result<Self, eIcicleError>`**:
52+
Initializes a new instance.
53+
54+
- **`prove(mle_polys, mle_poly_size, claimed_sum, combine_function, transcript_config, sumcheck_config) -> Self::Proof`**:
55+
Generates a proof for the polynomial sum over the Boolean hypercube.
56+
57+
- **`verify(proof, claimed_sum, transcript_config) -> Result<bool, eIcicleError>`**:
58+
Verifies the provided proof.
59+
60+
61+
#### `SumcheckProofOps`
62+
Operations for handling SumCheck proofs.
63+
64+
##### **Methods:**
65+
- **`get_round_polys(&self) -> Result<Vec<Vec<F>>, eIcicleError>`**:
66+
Retrieves the polynomials for each round.
67+
68+
- **`print(&self) -> eIcicleError`**::
69+
Prints the proof.
70+
71+
72+
## **Usage Example**
73+
74+
Below is an example demonstrating how to use the `sumcheck` module, adapted from the `check_sumcheck_simple` test.
75+
76+
```rust
77+
use icicle_core::sumcheck::{Sumcheck, SumcheckConfig, SumcheckTranscriptConfig};
78+
use icicle_core::field::FieldElement;
79+
use icicle_core::polynomial::Polynomial;
80+
use icicle_hash::keccak::Keccak256;
81+
82+
fn main() {
83+
// Initialize hashing function
84+
let hash = Keccak256::new(0).unwrap();
85+
86+
// Define a polynomial, e.g., f(x, y) = x + y
87+
let coefficients = vec![
88+
FieldElement::from(0), // Constant term
89+
FieldElement::from(1), // Coefficient for x
90+
FieldElement::from(1), // Coefficient for y
91+
];
92+
let poly = Polynomial::new(coefficients);
93+
94+
// Geerate mle polynomial
95+
let mut mle_poly = Vec::with_capacity(2);
96+
for _ in 0..4 {
97+
mle_poly.push(poly);
98+
}
99+
100+
// Calculate the expected sum over the Boolean hypercube {0,1}^2
101+
let expected_sum = FieldElement::from(4);
102+
103+
// Configure transcript and execution settings
104+
let transcript_config = SumcheckTranscriptConfig::from_string_labels(
105+
&hash,
106+
"domain_separator",
107+
"round_poly",
108+
"round_challenge",
109+
false, // big endian
110+
FieldElement::from(0),
111+
);
112+
let sumcheck_config = SumcheckConfig::default();
113+
114+
// define sumcheck lambda
115+
let combine_func = P::new_predefined(PreDefinedProgram::EQtimesABminusC).unwrap();
116+
117+
// Initialize prover
118+
let prover = Sumcheck::new().expect("Failed to create Sumcheck instance");
119+
120+
// Generate proof
121+
let proof = prover.prove(
122+
mle_poly.as_slice(),
123+
2, // Number of variables in the polynomial
124+
expected_sum,
125+
combine_func, // Use pre-defined combine function eq * (a * b - c)
126+
&transcript_config,
127+
&sumcheck_config,
128+
);
129+
130+
// Verify the proof
131+
let result = prover.verify(&proof, expected_sum, &transcript_config);
132+
assert!(result.is_ok() && result.unwrap(), "SumCheck proof verification failed!");
133+
}

docs/sidebars.ts

+5
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,11 @@ const rustBindingsApi = [
178178
label: "Merkle-Tree",
179179
id: "icicle/rust-bindings/merkle",
180180
},
181+
{
182+
"type": "doc",
183+
"label": "Sumcheck",
184+
"id": "icicle/rust-bindings/sumcheck"
185+
}
181186
// {
182187
// type: "doc",
183188
// label: "Multi GPU Support (TODO)",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Sumcheck
2+
3+
## Sumcheck API Overview
4+
5+
### **Structs**
6+
7+
#### `SumcheckTranscriptConfig`
8+
Configuration structure for the SumCheck protocol’s transcript.
9+
10+
##### **Fields:**
11+
- `hash: &Hasher` - Reference to the hashing function used.
12+
- `domain_separator_label: Vec<u8>` - Domain separator label for transcript uniqueness.
13+
- `round_poly_label: Vec<u8>` - Label for the polynomial at each round.
14+
- `round_challenge_label: Vec<u8>` - Label for the challenge at each round.
15+
- `little_endian: bool` - Whether to use little-endian encoding.
16+
- `seed_rng: F` - Random number generator seed.
17+
18+
##### **Methods:**
19+
- **`new(hash, domain_separator_label, round_poly_label, round_challenge_label, little_endian, seed_rng) -> Self`**:
20+
Constructs a new `SumcheckTranscriptConfig` with explicit parameters.
21+
22+
- **`from_string_labels(hash, domain_separator_label, round_poly_label, round_challenge_label, little_endian, seed_rng) -> Self`**:
23+
Convenience constructor using string labels.
24+
25+
#### `SumcheckConfig`
26+
General configuration for the SumCheck execution.
27+
28+
##### **Fields:**
29+
- `stream: IcicleStreamHandle` - Stream for asynchronous execution (default: `nullptr`).
30+
- `use_extension_field: bool` - Whether to use an extension field for Fiat-Shamir transformation. Sumcheck currently does not support extension fields, always set to `false` otherwise return an error.
31+
- `batch: u64` - Number of input chunks to hash in batch (default: 1).
32+
- `are_inputs_on_device: bool` - Whether inputs reside on the device (e.g., GPU).
33+
- `is_async: bool` - Whether hashing is run asynchronously.
34+
- `ext: ConfigExtension` - Pointer to backend-specific configuration extensions.
35+
36+
##### **Methods:**
37+
- **`default() -> Self`**:
38+
Returns a default `SumcheckConfig` instance.
39+
40+
### **Traits**
41+
42+
#### `Sumcheck`
43+
Defines the main API for SumCheck operations.
44+
45+
##### **Associated Types:**
46+
- `Field: FieldImpl + Arithmetic` - The field implementation used.
47+
- `FieldConfig: FieldConfig + GenerateRandom<Self::Field> + FieldArithmetic<Self::Field>` - Field configuration.
48+
- `Proof: SumcheckProofOps<Self::Field>` - Type representing the proof.
49+
50+
##### **Methods:**
51+
- **`new() -> Result<Self, eIcicleError>`**:
52+
Initializes a new instance.
53+
54+
- **`prove(mle_polys, mle_poly_size, claimed_sum, combine_function, transcript_config, sumcheck_config) -> Self::Proof`**:
55+
Generates a proof for the polynomial sum over the Boolean hypercube.
56+
57+
- **`verify(proof, claimed_sum, transcript_config) -> Result<bool, eIcicleError>`**:
58+
Verifies the provided proof.
59+
60+
61+
#### `SumcheckProofOps`
62+
Operations for handling SumCheck proofs.
63+
64+
##### **Methods:**
65+
- **`get_round_polys(&self) -> Result<Vec<Vec<F>>, eIcicleError>`**:
66+
Retrieves the polynomials for each round.
67+
68+
- **`print(&self) -> eIcicleError`**::
69+
Prints the proof.
70+
71+
72+
## **Usage Example**
73+
74+
Below is an example demonstrating how to use the `sumcheck` module, adapted from the `check_sumcheck_simple` test.
75+
76+
```rust
77+
use icicle_core::sumcheck::{Sumcheck, SumcheckConfig, SumcheckTranscriptConfig};
78+
use icicle_core::field::FieldElement;
79+
use icicle_core::polynomial::Polynomial;
80+
use icicle_hash::keccak::Keccak256;
81+
82+
fn main() {
83+
// Initialize hashing function
84+
let hash = Keccak256::new(0).unwrap();
85+
86+
// Define a polynomial, e.g., f(x, y) = x + y
87+
let coefficients = vec![
88+
FieldElement::from(0), // Constant term
89+
FieldElement::from(1), // Coefficient for x
90+
FieldElement::from(1), // Coefficient for y
91+
];
92+
let poly = Polynomial::new(coefficients);
93+
94+
// Geerate mle polynomial
95+
let mut mle_poly = Vec::with_capacity(2);
96+
for _ in 0..4 {
97+
mle_poly.push(poly);
98+
}
99+
100+
// Calculate the expected sum over the Boolean hypercube {0,1}^2
101+
let expected_sum = FieldElement::from(4);
102+
103+
// Configure transcript and execution settings
104+
let transcript_config = SumcheckTranscriptConfig::from_string_labels(
105+
&hash,
106+
"domain_separator",
107+
"round_poly",
108+
"round_challenge",
109+
false, // big endian
110+
FieldElement::from(0),
111+
);
112+
let sumcheck_config = SumcheckConfig::default();
113+
114+
// define sumcheck lambda
115+
let combine_func = P::new_predefined(PreDefinedProgram::EQtimesABminusC).unwrap();
116+
117+
// Initialize prover
118+
let prover = Sumcheck::new().expect("Failed to create Sumcheck instance");
119+
120+
// Generate proof
121+
let proof = prover.prove(
122+
mle_poly.as_slice(),
123+
2, // Number of variables in the polynomial
124+
expected_sum,
125+
combine_func, // Use pre-defined combine function eq * (a * b - c)
126+
&transcript_config,
127+
&sumcheck_config,
128+
);
129+
130+
// Verify the proof
131+
let result = prover.verify(&proof, expected_sum, &transcript_config);
132+
assert!(result.is_ok() && result.unwrap(), "SumCheck proof verification failed!");
133+
}

docs/versioned_sidebars/version-3.5.0-sidebars.json

+5
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,11 @@
231231
"type": "doc",
232232
"label": "Merkle-Tree",
233233
"id": "icicle/rust-bindings/merkle"
234+
},
235+
{
236+
"type": "doc",
237+
"label": "Sumcheck",
238+
"id": "icicle/rust-bindings/sumcheck"
234239
}
235240
]
236241
}

icicle/backend/cpu/src/hash/cpu_blake2s.cpp

+46-13
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212

1313
#include "icicle/backend/hash/blake2s_backend.h"
1414
#include "icicle/utils/modifiers.h"
15+
#include <taskflow/taskflow.hpp>
16+
#include "icicle/config_extension.h"
1517

1618
namespace icicle {
1719

@@ -26,19 +28,50 @@ namespace icicle {
2628
const auto single_input_size = get_single_chunk_size(
2729
size); // if size==0 using default input chunk size. This is useful for Merkle-Tree constructions
2830

29-
// TODO (future): use tasks manager to parallel across threads. Add option to config-extension to set #threads
30-
// with default=0. for now we don't do it and let the merkle-tree define the parallelizm so hashing a large batch
31-
// outside a merkle-tree context is not as fast as it could be.
32-
// Note that for batch=1 this has not effect.
33-
for (unsigned batch_idx = 0; batch_idx < config.batch; ++batch_idx) {
34-
int result = blake2s(
35-
output + batch_idx * digest_size_in_bytes, digest_size_in_bytes, input + batch_idx * single_input_size,
36-
single_input_size,
37-
nullptr, // No key used
38-
0 // Key length is 0
39-
);
40-
41-
if (result != 0) { return eIcicleError::UNKNOWN_ERROR; } // TODO Yuval error codes
31+
size_t num_chunks = 1;
32+
if (config.ext && config.ext->has(CpuBackendConfig::CPU_NOF_THREADS)) {
33+
num_chunks = config.ext && (config.ext->get<int>(CpuBackendConfig::CPU_NOF_THREADS) != 0)
34+
? config.ext->get<int>(CpuBackendConfig::CPU_NOF_THREADS)
35+
: // number of threads provided by config
36+
std::thread::hardware_concurrency(); // check machine properties (if provided with 0)
37+
}
38+
if (num_chunks <= 0) {
39+
ICICLE_LOG_WARNING << "Unable to detect number of hardware supported threads - fixing it to 1\n";
40+
num_chunks = 1;
41+
}
42+
size_t chunk_size = (config.batch + num_chunks - 1) / num_chunks;
43+
44+
if (num_chunks == 1) { // single thread without using taskflow
45+
for (unsigned batch_idx = 0; batch_idx < config.batch; ++batch_idx) {
46+
int result = blake2s(
47+
output + batch_idx * digest_size_in_bytes, digest_size_in_bytes, input + batch_idx * single_input_size,
48+
single_input_size,
49+
nullptr, // No key used
50+
0 // Key length is 0
51+
);
52+
53+
if (result != 0) { return eIcicleError::UNKNOWN_ERROR; }
54+
}
55+
} else {
56+
tf::Taskflow taskflow;
57+
tf::Executor executor;
58+
for (size_t i = 0; i < num_chunks; ++i) {
59+
size_t start_index = i * chunk_size;
60+
size_t end_index = std::min(start_index + chunk_size, static_cast<size_t>(config.batch));
61+
taskflow.emplace([&, start_index, end_index, output, digest_size_in_bytes, single_input_size, input]() {
62+
for (unsigned batch_idx = start_index; batch_idx < end_index; ++batch_idx) {
63+
int result = blake2s(
64+
output + batch_idx * digest_size_in_bytes, digest_size_in_bytes, input + batch_idx * single_input_size,
65+
single_input_size,
66+
nullptr, // No key used
67+
0 // Key length is 0
68+
);
69+
70+
if (result != 0) { return eIcicleError::UNKNOWN_ERROR; }
71+
}
72+
});
73+
}
74+
executor.run(taskflow).wait();
4275
}
4376
return eIcicleError::SUCCESS;
4477
}

0 commit comments

Comments
 (0)