mirror of https://github.com/zcash/halo2.git
Compare commits
6 Commits
416313f1ed
...
fd92875c5b
Author | SHA1 | Date |
---|---|---|
ashWhiteHat | fd92875c5b | |
Daira-Emma Hopwood | 7df93fd855 | |
adria0 | daaa638966 | |
ashWhiteHat | 24e3ec3633 | |
ashWhiteHat | e00f0d1233 | |
ashWhiteHat | af1713f1d3 |
|
@ -12,7 +12,7 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- uses: actions-rs/toolchain@v1
|
- uses: actions-rs/toolchain@v1
|
||||||
with:
|
with:
|
||||||
toolchain: nightly
|
toolchain: '1.76.0'
|
||||||
override: true
|
override: true
|
||||||
|
|
||||||
# - name: Setup mdBook
|
# - name: Setup mdBook
|
||||||
|
@ -26,7 +26,7 @@ jobs:
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: install
|
command: install
|
||||||
args: mdbook --git https://github.com/HollowMan6/mdBook.git --rev 62e01b34c23b957579c04ee1b24b57814ed8a4d5
|
args: mdbook --git https://github.com/HollowMan6/mdBook.git --rev 5830c9555a4dc051675d17f1fcb04dd0920543e8
|
||||||
|
|
||||||
- name: Install mdbook-katex and mdbook-pdf
|
- name: Install mdbook-katex and mdbook-pdf
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
|
@ -40,6 +40,11 @@ jobs:
|
||||||
- name: Build halo2 book
|
- name: Build halo2 book
|
||||||
run: mdbook build book/
|
run: mdbook build book/
|
||||||
|
|
||||||
|
- uses: actions-rs/toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: nightly-2023-10-05
|
||||||
|
override: true
|
||||||
|
|
||||||
- name: Build latest rustdocs
|
- name: Build latest rustdocs
|
||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
|
|
|
@ -14,8 +14,6 @@ title = "The halo2 Book"
|
||||||
macros = "macros.txt"
|
macros = "macros.txt"
|
||||||
renderers = ["html"]
|
renderers = ["html"]
|
||||||
|
|
||||||
[output.katex]
|
|
||||||
|
|
||||||
[output.html]
|
[output.html]
|
||||||
|
|
||||||
[output.html.print]
|
[output.html.print]
|
||||||
|
|
|
@ -31,6 +31,10 @@ harness = false
|
||||||
name = "hashtocurve"
|
name = "hashtocurve"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "msm"
|
||||||
|
harness = false
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "plonk"
|
name = "plonk"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
#[macro_use]
|
||||||
|
extern crate criterion;
|
||||||
|
|
||||||
|
use crate::arithmetic::best_multiexp;
|
||||||
|
use crate::pasta::{EqAffine, Fp};
|
||||||
|
use crate::poly::commitment::Params;
|
||||||
|
use criterion::{BenchmarkId, Criterion};
|
||||||
|
use group::ff::Field;
|
||||||
|
use halo2_proofs::*;
|
||||||
|
use rand_core::OsRng;
|
||||||
|
|
||||||
|
fn criterion_benchmark(c: &mut Criterion) {
|
||||||
|
let mut group = c.benchmark_group("msm");
|
||||||
|
for k in 8..16 {
|
||||||
|
group
|
||||||
|
.bench_function(BenchmarkId::new("k", k), |b| {
|
||||||
|
let coeffs = (0..(1 << k)).map(|_| Fp::random(OsRng)).collect::<Vec<_>>();
|
||||||
|
let bases = Params::<EqAffine>::new(k).get_g();
|
||||||
|
|
||||||
|
b.iter(|| best_multiexp(&coeffs, &bases))
|
||||||
|
})
|
||||||
|
.sample_size(30);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(benches, criterion_benchmark);
|
||||||
|
criterion_main!(benches);
|
|
@ -7,7 +7,7 @@ use group::{
|
||||||
ff::{BatchInvert, PrimeField},
|
ff::{BatchInvert, PrimeField},
|
||||||
Group as _, GroupOpsOwned, ScalarMulOwned,
|
Group as _, GroupOpsOwned, ScalarMulOwned,
|
||||||
};
|
};
|
||||||
|
use maybe_rayon::prelude::*;
|
||||||
pub use pasta_curves::arithmetic::*;
|
pub use pasta_curves::arithmetic::*;
|
||||||
|
|
||||||
/// This represents an element of a group with basic operations that can be
|
/// This represents an element of a group with basic operations that can be
|
||||||
|
@ -25,44 +25,6 @@ where
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
fn multiexp_serial<C: CurveAffine>(coeffs: &[C::Scalar], bases: &[C], acc: &mut C::Curve) {
|
|
||||||
let coeffs: Vec<_> = coeffs.iter().map(|a| a.to_repr()).collect();
|
|
||||||
|
|
||||||
let c = if bases.len() < 4 {
|
|
||||||
1
|
|
||||||
} else if bases.len() < 32 {
|
|
||||||
3
|
|
||||||
} else {
|
|
||||||
(f64::from(bases.len() as u32)).ln().ceil() as usize
|
|
||||||
};
|
|
||||||
|
|
||||||
fn get_at<F: PrimeField>(segment: usize, c: usize, bytes: &F::Repr) -> usize {
|
|
||||||
let skip_bits = segment * c;
|
|
||||||
let skip_bytes = skip_bits / 8;
|
|
||||||
|
|
||||||
if skip_bytes >= 32 {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut v = [0; 8];
|
|
||||||
for (v, o) in v.iter_mut().zip(bytes.as_ref()[skip_bytes..].iter()) {
|
|
||||||
*v = *o;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut tmp = u64::from_le_bytes(v);
|
|
||||||
tmp >>= skip_bits - (skip_bytes * 8);
|
|
||||||
tmp %= 1 << c;
|
|
||||||
|
|
||||||
tmp as usize
|
|
||||||
}
|
|
||||||
|
|
||||||
let segments = (256 / c) + 1;
|
|
||||||
|
|
||||||
for current_segment in (0..segments).rev() {
|
|
||||||
for _ in 0..c {
|
|
||||||
*acc = acc.double();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
enum Bucket<C: CurveAffine> {
|
enum Bucket<C: CurveAffine> {
|
||||||
None,
|
None,
|
||||||
|
@ -94,23 +56,56 @@ fn multiexp_serial<C: CurveAffine>(coeffs: &[C::Scalar], bases: &[C], acc: &mut
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut buckets: Vec<Bucket<C>> = vec![Bucket::None; (1 << c) - 1];
|
#[derive(Clone)]
|
||||||
|
struct Buckets<C: CurveAffine> {
|
||||||
|
c: usize,
|
||||||
|
coeffs: Vec<Bucket<C>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: CurveAffine> Buckets<C> {
|
||||||
|
fn new(c: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
c,
|
||||||
|
coeffs: vec![Bucket::None; (1 << c) - 1],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sum(&mut self, coeffs: &[C::Scalar], bases: &[C], i: usize) -> C::Curve {
|
||||||
|
// get segmentation and add coeff to buckets content
|
||||||
for (coeff, base) in coeffs.iter().zip(bases.iter()) {
|
for (coeff, base) in coeffs.iter().zip(bases.iter()) {
|
||||||
let coeff = get_at::<C::Scalar>(current_segment, c, coeff);
|
let seg = self.get_at::<C::Scalar>(i, &coeff.to_repr());
|
||||||
if coeff != 0 {
|
if seg != 0 {
|
||||||
buckets[coeff - 1].add_assign(base);
|
self.coeffs[seg - 1].add_assign(base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Summation by parts
|
// Summation by parts
|
||||||
// e.g. 3a + 2b + 1c = a +
|
// e.g. 3a + 2b + 1c = a +
|
||||||
// (a) + b +
|
// (a) + b +
|
||||||
// ((a) + b) + c
|
// ((a) + b) + c
|
||||||
let mut running_sum = C::Curve::identity();
|
let mut acc = C::Curve::identity();
|
||||||
for exp in buckets.into_iter().rev() {
|
let mut sum = C::Curve::identity();
|
||||||
running_sum = exp.add(running_sum);
|
self.coeffs.iter().rev().for_each(|b| {
|
||||||
*acc += &running_sum;
|
sum = b.add(sum);
|
||||||
|
acc += sum;
|
||||||
|
});
|
||||||
|
acc
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_at<F: PrimeField>(&self, segment: usize, bytes: &F::Repr) -> usize {
|
||||||
|
let skip_bits = segment * self.c;
|
||||||
|
let skip_bytes = skip_bits / 8;
|
||||||
|
|
||||||
|
if skip_bytes >= 32 {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
let mut v = [0; 8];
|
||||||
|
for (v, o) in v.iter_mut().zip(bytes.as_ref()[skip_bytes..].iter()) {
|
||||||
|
*v = *o;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut tmp = u64::from_le_bytes(v);
|
||||||
|
tmp >>= skip_bits - (skip_bytes * 8);
|
||||||
|
(tmp % (1 << self.c)) as usize
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,29 +142,38 @@ pub fn small_multiexp<C: CurveAffine>(coeffs: &[C::Scalar], bases: &[C]) -> C::C
|
||||||
pub fn best_multiexp<C: CurveAffine>(coeffs: &[C::Scalar], bases: &[C]) -> C::Curve {
|
pub fn best_multiexp<C: CurveAffine>(coeffs: &[C::Scalar], bases: &[C]) -> C::Curve {
|
||||||
assert_eq!(coeffs.len(), bases.len());
|
assert_eq!(coeffs.len(), bases.len());
|
||||||
|
|
||||||
|
let c = if bases.len() < 4 {
|
||||||
|
1
|
||||||
|
} else if bases.len() < 32 {
|
||||||
|
3
|
||||||
|
} else {
|
||||||
|
(f64::from(bases.len() as u32)).ln().ceil() as usize
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut multi_buckets: Vec<Buckets<C>> = vec![Buckets::new(c); (256 / c) + 1];
|
||||||
let num_threads = multicore::current_num_threads();
|
let num_threads = multicore::current_num_threads();
|
||||||
if coeffs.len() > num_threads {
|
if coeffs.len() > num_threads {
|
||||||
let chunk = coeffs.len() / num_threads;
|
multi_buckets
|
||||||
let num_chunks = coeffs.chunks(chunk).len();
|
.par_iter_mut()
|
||||||
let mut results = vec![C::Curve::identity(); num_chunks];
|
.enumerate()
|
||||||
multicore::scope(|scope| {
|
.rev()
|
||||||
let chunk = coeffs.len() / num_threads;
|
.map(|(i, buckets)| {
|
||||||
|
let mut acc = buckets.sum(coeffs, bases, i);
|
||||||
for ((coeffs, bases), acc) in coeffs
|
(0..c * i).for_each(|_| acc = acc.double());
|
||||||
.chunks(chunk)
|
|
||||||
.zip(bases.chunks(chunk))
|
|
||||||
.zip(results.iter_mut())
|
|
||||||
{
|
|
||||||
scope.spawn(move |_| {
|
|
||||||
multiexp_serial(coeffs, bases, acc);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
results.iter().fold(C::Curve::identity(), |a, b| a + b)
|
|
||||||
} else {
|
|
||||||
let mut acc = C::Curve::identity();
|
|
||||||
multiexp_serial(coeffs, bases, &mut acc);
|
|
||||||
acc
|
acc
|
||||||
|
})
|
||||||
|
.reduce(|| C::Curve::identity(), |a, b| a + b)
|
||||||
|
} else {
|
||||||
|
multi_buckets
|
||||||
|
.iter_mut()
|
||||||
|
.enumerate()
|
||||||
|
.rev()
|
||||||
|
.map(|(i, buckets)| buckets.sum(coeffs, bases, i))
|
||||||
|
.fold(C::Curve::identity(), |mut sum, bucket| {
|
||||||
|
// restore original evaluation point
|
||||||
|
(0..c).for_each(|_| sum = sum.double());
|
||||||
|
sum + bucket
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue