Skip to content

Commit e6346e2

Browse files
committed
Merge branch 'dev' into return-zk
2 parents f7e6225 + 3043e8c commit e6346e2

File tree

14 files changed

+47
-105
lines changed

14 files changed

+47
-105
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ abomonation_derive = { version = "0.1.0", package = "abomonation_derive_ng" }
4040
tracing = "0.1.37"
4141
cfg-if = "1.0.0"
4242
once_cell = "1.18.0"
43-
itertools = "0.12.0" # zip_eq
43+
itertools = "0.13.0" # zip_eq
4444
rand = "0.8.5"
4545
ref-cast = "1.0.20" # allocation-less conversion in multilinear polys
4646
derive_more = "0.99.17" # lightens impl macros for pasta

examples/hashchain.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,9 @@ impl<G: Group> StepCircuit<G::Scalar> for HashChainCircuit<G> {
9696
let acc = &mut ns;
9797

9898
sponge.start(parameter, None, acc);
99-
neptune::sponge::api::SpongeAPI::absorb(&mut sponge, num_absorbs, &elt, acc);
99+
SpongeAPI::absorb(&mut sponge, num_absorbs, &elt, acc);
100100

101-
let output = neptune::sponge::api::SpongeAPI::squeeze(&mut sponge, 1, acc);
101+
let output = SpongeAPI::squeeze(&mut sponge, 1, acc);
102102
sponge.finish(acc).unwrap();
103103
Elt::ensure_allocated(&output[0], &mut ns.namespace(|| "ensure allocated"), true)?
104104
};

rust-toolchain.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[toolchain]
22
# The default profile includes rustc, rust-std, cargo, rust-docs, rustfmt and clippy.
33
profile = "default"
4-
channel = "1.76.0"
4+
channel = "1.78"
55
targets = [ "wasm32-unknown-unknown" ]
66

src/bellpepper/test_shape_cs.rs

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use ff::{Field, PrimeField};
1414
#[derive(Clone, Copy)]
1515
struct OrderedVariable(Variable);
1616

17+
#[allow(dead_code)]
1718
#[derive(Debug)]
1819
enum NamedObject {
1920
Constraint(usize),

src/gadgets/nonnative/mod.rs

-4
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,12 @@ use ff::PrimeField;
66

77
trait OptionExt<T> {
88
fn grab(&self) -> Result<&T, SynthesisError>;
9-
fn grab_mut(&mut self) -> Result<&mut T, SynthesisError>;
109
}
1110

1211
impl<T> OptionExt<T> for Option<T> {
1312
fn grab(&self) -> Result<&T, SynthesisError> {
1413
self.as_ref().ok_or(SynthesisError::AssignmentMissing)
1514
}
16-
fn grab_mut(&mut self) -> Result<&mut T, SynthesisError> {
17-
self.as_mut().ok_or(SynthesisError::AssignmentMissing)
18-
}
1915
}
2016

2117
trait BitAccess {

src/provider/poseidon.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ where
169169
assert_eq!(self.num_absorbs, self.state.len());
170170

171171
sponge.start(parameter, None, acc);
172-
neptune::sponge::api::SpongeAPI::absorb(
172+
SpongeAPI::absorb(
173173
&mut sponge,
174174
self.num_absorbs as u32,
175175
&(0..self.state.len())
@@ -178,7 +178,7 @@ where
178178
acc,
179179
);
180180

181-
let output = neptune::sponge::api::SpongeAPI::squeeze(&mut sponge, 1, acc);
181+
let output = SpongeAPI::squeeze(&mut sponge, 1, acc);
182182
sponge.finish(acc).unwrap();
183183
output
184184
};

src/provider/tests/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use serde_json::{Map, Value};
2626
// ) {
2727
// use rand_core::SeedableRng;
2828

29-
// let mut rng = rand::rngs::StdRng::seed_from_u64(num_vars as u64);
29+
// let mut rng = StdRng::seed_from_u64(num_vars as u64);
3030

3131
// let (poly, point, eval) =
3232
// crate::provider::util::test_utils::random_poly_with_eval::<E, StdRng>(num_vars, &mut rng);

src/provider/util/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ use serde::Serialize;
147147
// ) {
148148
// use rand_core::SeedableRng;
149149

150-
// let mut rng = rand::rngs::StdRng::seed_from_u64(num_vars as u64);
150+
// let mut rng = StdRng::seed_from_u64(num_vars as u64);
151151

152152
// let (poly, point, eval) = random_poly_with_eval::<E, StdRng>(num_vars, &mut rng);
153153

src/spartan/batched.rs

+1-11
Original file line numberDiff line numberDiff line change
@@ -490,17 +490,7 @@ impl<E: Engine, EE: EvaluationEngineTrait<E>> BatchedRelaxedR1CSSNARKTrait<E>
490490
let evals_Z = zip_with!(iter, (self.evals_W, U, r_y), |eval_W, U, r_y| {
491491
let eval_X = {
492492
// constant term
493-
let poly_X = iter::once((0, U.u))
494-
.chain(
495-
//remaining inputs
496-
U.X
497-
.iter()
498-
.enumerate()
499-
// filter_map uses the sparsity of the polynomial, if irrelevant
500-
// we should replace by UniPoly
501-
.filter_map(|(i, x_i)| (!x_i.is_zero_vartime()).then_some((i + 1, *x_i))),
502-
)
503-
.collect();
493+
let poly_X = iter::once(U.u).chain(U.X.iter().cloned()).collect();
504494
SparsePolynomial::new(r_y.len() - 1, poly_X).evaluate(&r_y[1..])
505495
};
506496
(E::Scalar::ONE - r_y[0]) * eval_W + r_y[0] * eval_X

src/spartan/batched_ppsnark.rs

+1-9
Original file line numberDiff line numberDiff line change
@@ -927,15 +927,7 @@ impl<E: Engine, EE: EvaluationEngineTrait<E>> BatchedRelaxedR1CSSNARKTrait<E>
927927

928928
let X = {
929929
// constant term
930-
let poly_X = std::iter::once((0, U.u))
931-
.chain(
932-
//remaining inputs
933-
(0..U.X.len())
934-
// filter_map uses the sparsity of the polynomial, if irrelevant
935-
// we should replace by UniPoly
936-
.filter_map(|i| (!U.X[i].is_zero_vartime()).then_some((i + 1, U.X[i]))),
937-
)
938-
.collect();
930+
let poly_X = std::iter::once(U.u).chain(U.X.iter().cloned()).collect();
939931
SparsePolynomial::new(num_vars_log, poly_X).evaluate(&rand_sc_unpad[1..])
940932
};
941933

src/spartan/math.rs

-15
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,8 @@
11
pub trait Math {
2-
fn pow2(self) -> usize;
3-
fn get_bits(self, num_bits: usize) -> Vec<bool>;
42
fn log_2(self) -> usize;
53
}
64

75
impl Math for usize {
8-
#[inline]
9-
fn pow2(self) -> usize {
10-
let base: Self = 2;
11-
base.pow(self as u32)
12-
}
13-
14-
/// Returns the `num_bits` from n in a canonical order
15-
fn get_bits(self, num_bits: usize) -> Vec<bool> {
16-
(0..num_bits)
17-
.map(|shift_amount| ((self & (1 << (num_bits - shift_amount - 1))) > 0))
18-
.collect::<Vec<bool>>()
19-
}
20-
216
fn log_2(self) -> usize {
227
assert_ne!(self, 0);
238

src/spartan/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ use crate::{
2727
};
2828
use ff::Field;
2929
use itertools::Itertools as _;
30-
use polys::multilinear::SparsePolynomial;
3130
use rayon::{iter::IntoParallelRefIterator, prelude::*};
3231
use rayon_scan::ScanParallelIterator as _;
3332
use ref_cast::RefCast;

src/spartan/polys/multilinear.rs

+36-44
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ use ff::PrimeField;
88
use itertools::Itertools as _;
99
use rand_core::{CryptoRng, RngCore};
1010
use rayon::prelude::{
11-
IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator,
12-
IntoParallelRefMutIterator, ParallelIterator,
11+
IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator,
1312
};
1413
use serde::{Deserialize, Serialize};
1514

@@ -130,47 +129,37 @@ impl<Scalar: PrimeField> Index<usize> for MultilinearPolynomial<Scalar> {
130129
}
131130

132131
/// Sparse multilinear polynomial, which means the $Z(\cdot)$ is zero at most points.
133-
/// So we do not have to store every evaluations of $Z(\cdot)$, only store the non-zero points.
134-
///
135-
/// For example, the evaluations are [0, 0, 0, 1, 0, 1, 0, 2].
136-
/// The sparse polynomial only store the non-zero values, [(3, 1), (5, 1), (7, 2)].
137-
/// In the tuple, the first is index, the second is value.
132+
/// In our context, sparse polynomials are non-zeros over the hypercube at locations that map to "small" integers
133+
/// We exploit this property to implement a time-optimal algorithm
138134
pub(crate) struct SparsePolynomial<Scalar> {
139135
num_vars: usize,
140-
Z: Vec<(usize, Scalar)>,
136+
Z: Vec<Scalar>,
141137
}
142138

143139
impl<Scalar: PrimeField> SparsePolynomial<Scalar> {
144-
pub fn new(num_vars: usize, Z: Vec<(usize, Scalar)>) -> Self {
140+
pub fn new(num_vars: usize, Z: Vec<Scalar>) -> Self {
145141
Self { num_vars, Z }
146142
}
147143

148-
/// Computes the $\tilde{eq}$ extension polynomial.
149-
/// return 1 when a == r, otherwise return 0.
150-
fn compute_chi(a: &[bool], r: &[Scalar]) -> Scalar {
151-
assert_eq!(a.len(), r.len());
152-
let mut chi_i = Scalar::ONE;
153-
for j in 0..r.len() {
154-
if a[j] {
155-
chi_i *= r[j];
156-
} else {
157-
chi_i *= Scalar::ONE - r[j];
158-
}
159-
}
160-
chi_i
161-
}
162-
163-
// Takes O(m log n) where m is the number of non-zero evaluations and n is the number of variables.
144+
// a time-optimal algorithm to evaluate sparse polynomials
164145
pub fn evaluate(&self, r: &[Scalar]) -> Scalar {
165146
assert_eq!(self.num_vars, r.len());
166147

167-
(0..self.Z.len())
168-
.into_par_iter()
169-
.map(|i| {
170-
let bits = (self.Z[i].0).get_bits(r.len());
171-
Self::compute_chi(&bits, r) * self.Z[i].1
172-
})
173-
.sum()
148+
let num_vars_z = self.Z.len().next_power_of_two().log_2();
149+
let chis = EqPolynomial::evals_from_points(&r[self.num_vars - 1 - num_vars_z..]);
150+
#[allow(clippy::disallowed_methods)]
151+
let eval_partial: Scalar = self
152+
.Z
153+
.iter()
154+
.zip(chis.iter())
155+
.map(|(z, chi)| *z * *chi)
156+
.sum();
157+
158+
let common = (0..self.num_vars - 1 - num_vars_z)
159+
.map(|i| (Scalar::ONE - r[i]))
160+
.product::<Scalar>();
161+
162+
common * eval_partial
174163
}
175164
}
176165

@@ -192,7 +181,7 @@ impl<Scalar: PrimeField> Add for MultilinearPolynomial<Scalar> {
192181

193182
#[cfg(test)]
194183
mod tests {
195-
use crate::provider::{self, bn256_grumpkin::bn256, secp_secq::secp256k1};
184+
use crate::provider::{bn256_grumpkin::bn256, secp_secq::secp256k1};
196185

197186
use super::*;
198187
use rand_chacha::ChaCha20Rng;
@@ -232,18 +221,21 @@ mod tests {
232221
}
233222

234223
fn test_sparse_polynomial_with<F: PrimeField>() {
235-
// Let the polynomial have 3 variables, p(x_1, x_2, x_3) = (x_1 + x_2) * x_3
236-
// Evaluations of the polynomial at boolean cube are [0, 0, 0, 1, 0, 1, 0, 2].
224+
// Let the polynomial have 4 variables, but is non-zero at only 3 locations (out of 2^4 = 16) over the hypercube
225+
let mut Z = vec![F::ONE, F::ONE, F::from(2)];
226+
let m_poly = SparsePolynomial::<F>::new(4, Z.clone());
237227

238-
let TWO = F::from(2);
239-
let Z = vec![(3, F::ONE), (5, F::ONE), (7, TWO)];
240-
let m_poly = SparsePolynomial::<F>::new(3, Z);
228+
Z.resize(16, F::ZERO); // append with zeros to make it a dense polynomial
229+
let m_poly_dense = MultilinearPolynomial::new(Z);
241230

242-
let x = vec![F::ONE, F::ONE, F::ONE];
243-
assert_eq!(m_poly.evaluate(x.as_slice()), TWO);
231+
// evaluation point
232+
let x = vec![F::from(5), F::from(8), F::from(5), F::from(3)];
244233

245-
let x = vec![F::ONE, F::ZERO, F::ONE];
246-
assert_eq!(m_poly.evaluate(x.as_slice()), F::ONE);
234+
// check evaluations
235+
assert_eq!(
236+
m_poly.evaluate(x.as_slice()),
237+
m_poly_dense.evaluate(x.as_slice())
238+
);
247239
}
248240

249241
#[test]
@@ -301,8 +293,8 @@ mod tests {
301293
#[test]
302294
fn test_evaluation() {
303295
test_evaluation_with::<pasta_curves::Fp>();
304-
test_evaluation_with::<provider::bn256_grumpkin::bn256::Scalar>();
305-
test_evaluation_with::<provider::secp_secq::secp256k1::Scalar>();
296+
test_evaluation_with::<bn256::Scalar>();
297+
test_evaluation_with::<secp256k1::Scalar>();
306298
}
307299

308300
/// This binds the variables of a multilinear polynomial to a provided sequence

src/supernova/mod.rs

-13
Original file line numberDiff line numberDiff line change
@@ -1182,19 +1182,6 @@ where
11821182
fn secondary_circuit(&self) -> Self::C2;
11831183
}
11841184

1185-
/// Extension trait to simplify getting scalar form of initial circuit index.
1186-
trait InitialProgramCounter<E1>: NonUniformCircuit<E1>
1187-
where
1188-
E1: CurveCycleEquipped,
1189-
{
1190-
/// Initial program counter is the initial circuit index as a `Scalar`.
1191-
fn initial_program_counter(&self) -> E1::Scalar {
1192-
E1::Scalar::from(self.initial_circuit_index() as u64)
1193-
}
1194-
}
1195-
1196-
impl<E1: CurveCycleEquipped, T: NonUniformCircuit<E1>> InitialProgramCounter<E1> for T {}
1197-
11981185
/// Compute the circuit digest of a supernova [`StepCircuit`].
11991186
///
12001187
/// Note for callers: This function should be called with its performance characteristics in mind.

0 commit comments

Comments
 (0)