Commit 1b2f0f17 authored by 董子豪's avatar 董子豪

rust proof system from github.com/a263200357

parent 6281e143
...@@ -127,7 +127,6 @@ func RunProvider(ctx context.Context, conn *connect.Connection, root string) err ...@@ -127,7 +127,6 @@ func RunProvider(ctx context.Context, conn *connect.Connection, root string) err
return err return err
} }
seed := data.(abi.PoStRandomness) seed := data.(abi.PoStRandomness)
fmt.Println(seed)
postProof, _, err := p.GenerateWindowPoStProofs(ctx, sids, sectorCommits, seed) postProof, _, err := p.GenerateWindowPoStProofs(ctx, sids, sectorCommits, seed)
if err != nil { if err != nil {
......
...@@ -54,7 +54,7 @@ func RunUser(ctx context.Context, conn *connect.Connection, root string, numFile ...@@ -54,7 +54,7 @@ func RunUser(ctx context.Context, conn *connect.Connection, root string, numFile
log.Infof("Generating random data") log.Infof("Generating random data")
filename := filepath.Join(root, fmt.Sprintf("input-%d.dat", i)) filename := filepath.Join(root, fmt.Sprintf("input-%d.dat", i))
r := rand.New(rand.NewSource(time.Now().UnixNano())) r := rand.New(rand.NewSource(time.Now().UnixNano()))
dataSize := uint64(r.Int63n(int64(sectorSize/8)))*32 + 4*sectorSize dataSize := uint64(r.Int63n(int64(sectorSize * 6))) + 6*sectorSize
b, err = seal.GenerateRandomData(filename, dataSize, b) b, err = seal.GenerateRandomData(filename, dataSize, b)
if err != nil { if err != nil {
return err return err
......
ok
\ No newline at end of file
{
"git": {
"sha1": "193370bfe6a73abc9f9422cba67b0a401f310be4"
}
}
version: 2.1
parameters:
nightly-version:
type: string
default: "nightly-2020-11-20"
#orbs:
# codecov: codecov/codecov@1.1.4
executors:
default:
machine:
image: ubuntu-1604-cuda-10.1:201909-23
working_directory: ~/gpuci
resource_class: gpu.nvidia.medium
restore-workspace: &restore-workspace
attach_workspace:
at: ~/
restore-cache: &restore-cache
restore_cache:
keys:
- cargo-v1-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
- repo-source-{{ .Branch }}-{{ .Revision }}
commands:
set-env-path:
steps:
- run:
name: Set the PATH env variable
command: |
# Also put the Rust LLVM tools into the PATH.
echo 'export PATH="$HOME:~/.cargo/bin:~/.rustup/toolchains/<< pipeline.parameters.nightly-version >>-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin:$PATH"' | tee --append $BASH_ENV
source $BASH_ENV
install-gpu-deps:
steps:
- run:
name: Install libraries for GPU tests
command: |
sudo apt-get update -y
sudo apt install -y ocl-icd-opencl-dev
test_target_pairing:
parameters:
target:
type: string
steps:
- *restore-workspace
- *restore-cache
- run:
name: Test pairing (<< parameters.target >>)
command: TARGET=<< parameters.target >> cargo test --no-default-features --features pairing
no_output_timeout: 15m
test_target_pairing_gpu:
parameters:
target:
type: string
steps:
- *restore-workspace
- *restore-cache
- run:
name: Test pairing (GPU) (<< parameters.target >>)
command: TARGET=<< parameters.target >> cargo test --release --no-default-features --features gpu,pairing
no_output_timeout: 30m
test_target_blst:
parameters:
target:
type: string
steps:
- *restore-workspace
- *restore-cache
- run:
name: Test blst (<< parameters.target >>)
command: TARGET=<< parameters.target >> cargo test --no-default-features --features blst
no_output_timeout: 15m
test_target_blst_gpu:
parameters:
target:
type: string
steps:
- *restore-workspace
- *restore-cache
- run:
name: Test blst (GPU) (<< parameters.target >>)
command: TARGET=<< parameters.target >> cargo test --release --no-default-features --features gpu,blst
no_output_timeout: 30m
jobs:
cargo_fetch:
executor: default
steps:
- checkout
- run: curl https://sh.rustup.rs -sSf | sh -s -- -y
- set-env-path
- run: echo $HOME
- run: cargo --version
- run: rustc --version
- run:
name: Update submodules
command: git submodule update --init --recursive
- run:
name: Calculate dependencies
command: cargo generate-lockfile
- restore_cache:
keys:
- cargo-v1-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
- run: cargo update
- run: cargo fetch
- run: rustup install $(cat rust-toolchain)
- run: rustup default $(cat rust-toolchain)
# A nightly build is needed for code coverage reporting
- run: rustup toolchain install --profile minimal << pipeline.parameters.nightly-version >>
- run: rustup component add rustfmt-preview
- run: rustup component add clippy-preview
- run: rustup component add --toolchain << pipeline.parameters.nightly-version >> llvm-tools-preview
- run: rustc --version
- run: rm -rf .git
- persist_to_workspace:
root: ~/
paths:
- gpuci
- save_cache:
key: cargo-v1-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
paths:
- "~/.cargo"
- "~/.rustup"
test_pairing_x86_64-unknown-linux-gnu:
executor: default
steps:
- set-env-path
- install-gpu-deps
- test_target_pairing:
target: "x86_64-unknown-linux-gnu"
test_pairing_gpu_x86_64-unknown-linux-gnu:
executor: default
steps:
- set-env-path
- install-gpu-deps
- test_target_pairing_gpu:
target: "x86_64-unknown-linux-gnu"
test_blst_x86_64-unknown-linux-gnu:
executor: default
steps:
- set-env-path
- install-gpu-deps
- test_target_blst:
target: "x86_64-unknown-linux-gnu"
test_blst_gpu_x86_64-unknown-linux-gnu:
executor: default
steps:
- set-env-path
- install-gpu-deps
- test_target_blst_gpu:
target: "x86_64-unknown-linux-gnu"
rustfmt:
executor: default
steps:
- *restore-workspace
- *restore-cache
- set-env-path
- run:
name: Run cargo fmt
command: cargo fmt --all -- --check
clippy:
executor: default
steps:
- *restore-workspace
- *restore-cache
- set-env-path
- run:
name: Run cargo clippy (blst)
command: cargo clippy --no-default-features --features blst
- run:
name: Run cargo clippy (pairing)
command: cargo clippy --no-default-features --features pairing
- run:
name: Run cargo clippy (gpu)
command: cargo clippy --features gpu
build_blst:
executor: default
steps:
- *restore-workspace
- *restore-cache
- set-env-path
- run:
name: Run cargo release build
command: cargo build --release --no-default-features --features blst
build_pairing:
executor: default
steps:
- *restore-workspace
- *restore-cache
- set-env-path
- run:
name: Run cargo release build
command: cargo build --release --no-default-features --features pairing
coverage_run:
executor: default
parameters:
cargo-args:
description: Addtional arguments for the cargo command
type: string
default: ""
test-args:
description: Additional arguments for the test executable (after the `--`)
type: string
default: ""
environment:
# Incremental build is not supported when profiling
CARGO_INCREMENTAL: 0
# -Zinstrument-coverage: enable llvm coverage instrumentation
# -Ccodegen-units=1: building in parallel is not supported when profiling
# -Copt-level=0: disable optimizations for more accurate coverage
# -Clink-dead-code: dead code should be considered as not covered code
# -Coverflow-checks=off: checking for overflow is not needed for coverage reporting
# -Cinline-threshold=0: do not inline
RUSTFLAGS: -Zinstrument-coverage -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Cinline-threshold=0
# Make sure that each run of an executable creates a new profile file, with the default
# name they would override each other
LLVM_PROFILE_FILE: "%m.profraw"
steps:
- *restore-workspace
- *restore-cache
- set-env-path
- install-gpu-deps
- run:
name: Generate coverage report
command: |
RUST_LOG=info cargo +<< pipeline.parameters.nightly-version >> test --features _coverage << parameters.cargo-args >> -- --nocapture << parameters.test-args >>
# Do *not* use sparse output. It leads to more lines that are not
# taken into account at all
llvm-profdata merge --output=default.profdata ./*.profraw
# The compiled files contain the coverage information. From running the tests we don't
# know what those files are called, hence use all files from the `./target/debug/deps`
# directory which don't have an extension.
OBJECT_FILES=$(find ./target/debug/deps/* -name '*' -not -name '*\.*' -printf '%p,'|head --bytes -1)
# Only export the coverage of this project, we don't care about coverage of
# dependencies
llvm-cov export --ignore-filename-regex=".cargo|.rustup" --format=lcov -instr-profile=default.profdata --object=${OBJECT_FILES} > lcov.info
## Codecov automatically merges the reports in case there are several ones uploaded
#- codecov/upload:
# file: lcov.info
workflows:
version: 2.1
test:
jobs:
- cargo_fetch
- rustfmt:
requires:
- cargo_fetch
- clippy:
requires:
- cargo_fetch
- test_pairing_x86_64-unknown-linux-gnu:
requires:
- cargo_fetch
- test_pairing_gpu_x86_64-unknown-linux-gnu:
requires:
- cargo_fetch
- test_blst_x86_64-unknown-linux-gnu:
requires:
- cargo_fetch
- test_blst_gpu_x86_64-unknown-linux-gnu:
requires:
- cargo_fetch
- build_blst:
requires:
- cargo_fetch
- build_pairing:
requires:
- cargo_fetch
#- coverage_run:
# name: coverage_default_features
# requires:
# - cargo_fetch
#- coverage_run:
# name: coverage_gpu_feature_lib
# cargo-args: "--features gpu --lib"
# # If run in parallel the GPU tests will block and hence fail
# test-args: "--test-threads=1"
# requires:
# - cargo_fetch
#- coverage_run:
# name: coverage_gpu_feature_integration
# cargo-args: "--features gpu --test '*'"
# # If run in parallel the GPU tests will block and hence fail
# test-args: "--test-threads=1"
# requires:
# - cargo_fetch
Copyrights in the "bellman" library are retained by their contributors. No
copyright assignment is required to contribute to the "bellman" library.
The "bellman" library is licensed under either of
* Apache License, Version 2.0, (see ./LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* MIT license (see ./LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.
Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
license, shall be dual licensed as above, without any additional terms or
conditions.
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies
#
# If you believe there's an error in this file please file an
# issue against the rust-lang/cargo repository. If you're
# editing this file be aware that the upstream Cargo.toml
# will likely look very different (and much more reasonable)
[package]
edition = "2018"
name = "bellperson"
version = "0.14.2"
authors = ["dignifiedquire <me@dignifiedquire.com>", "Sean Bowe <ewillbefull@gmail.com>"]
description = "zk-SNARK library"
homepage = "https://github.com/filecoin-project/bellman"
documentation = "https://docs.rs/bellperson"
readme = "README.md"
license = "MIT/Apache-2.0"
repository = "https://github.com/filecoin-project/bellman"
[[test]]
name = "mimc"
path = "tests/mimc.rs"
required-features = ["groth16"]
[[bench]]
name = "lc"
harness = false
[dependencies.bincode]
version = "1.3.1"
[dependencies.bit-vec]
version = "0.6"
[dependencies.blake2s_simd]
version = "0.5"
[dependencies.blstrs]
version = "0.3"
optional = true
[dependencies.byteorder]
version = "1"
[dependencies.crossbeam-channel]
version = "0.5.0"
[dependencies.digest]
version = "0.9.0"
[dependencies.ff]
version = "0.3.0"
package = "fff"
[dependencies.ff-cl-gen]
version = "0.3.0"
optional = true
[dependencies.fs2]
version = "0.4.3"
optional = true
[dependencies.groupy]
version = "0.4.1"
[dependencies.itertools]
version = "0.9.0"
[dependencies.lazy_static]
version = "1.4.0"
[dependencies.log]
version = "0.4.8"
[dependencies.memmap]
version = "0.7.0"
[dependencies.num_cpus]
version = "1"
[dependencies.paired]
version = "0.22.0"
optional = true
[dependencies.rand]
version = "0.7"
[dependencies.rand_core]
version = "0.5"
[dependencies.rayon]
version = "1.3.0"
[dependencies.rust-gpu-tools]
version = "0.3.0"
optional = true
[dependencies.rustc-hash]
version = "1.1.0"
[dependencies.serde]
version = "1.0"
features = ["derive"]
[dependencies.sha2]
version = "0.9"
[dependencies.thiserror]
version = "1.0.10"
[dev-dependencies.criterion]
version = "0.3.2"
[dev-dependencies.csv]
version = "1.1.5"
[dev-dependencies.env_logger]
version = "0.8.1"
[dev-dependencies.hex-literal]
version = "0.3"
[dev-dependencies.rand_chacha]
version = "0.2.2"
[dev-dependencies.rand_xorshift]
version = "0.2.0"
[dev-dependencies.tempfile]
version = "3.1.0"
[features]
_coverage = []
blst = ["blstrs", "groth16"]
default = ["pairing"]
gpu = ["rust-gpu-tools", "ff-cl-gen", "fs2"]
groth16 = []
pairing = ["paired", "groth16"]
[badges.maintenance]
status = "actively-developed"
[package]
name = "bellperson"
authors = [
"dignifiedquire <me@dignifiedquire.com>",
"Sean Bowe <ewillbefull@gmail.com>",
]
description = "zk-SNARK library"
documentation = "https://docs.rs/bellperson"
homepage = "https://github.com/filecoin-project/bellman"
license = "MIT/Apache-2.0"
repository = "https://github.com/filecoin-project/bellman"
version = "0.14.2"
readme = "README.md"
edition = "2018"
[dependencies]
bit-vec = "0.6"
blake2s_simd = "0.5"
ff = { version = "0.3.0", package = "fff" }
groupy = "0.4.1"
rand_core = "0.5"
byteorder = "1"
log = "0.4.8"
lazy_static = "1.4.0"
rand = "0.7"
rayon = "1.3.0"
memmap = "0.7.0"
thiserror = "1.0.10"
rustc-hash = "1.1.0"
num_cpus = "1"
crossbeam-channel = "0.5.0"
digest = "0.9.0"
itertools = "0.9.0"
bincode = "1.3.1"
serde = { version = "1.0", features = ["derive"] }
sha2 = "0.9"
# blst feature
blstrs = { version = "0.3", optional = true }
# pairing feature
paired = { version = "0.22.0", optional = true }
# gpu feature
rust-gpu-tools = { version = "0.3.0", optional = true }
ff-cl-gen = { version = "0.3.0", optional = true }
fs2 = { version = "0.4.3", optional = true }
[dev-dependencies]
hex-literal = "0.3"
rand_xorshift = "0.2.0"
env_logger = "0.8.1"
criterion = "0.3.2"
rand_chacha = "0.2.2"
csv = "1.1.5"
tempfile = "3.1.0"
[features]
default = ["pairing"]
gpu = ["rust-gpu-tools", "ff-cl-gen", "fs2"]
groth16 = []
blst = ["blstrs", "groth16"]
pairing = ["paired", "groth16"]
# This feature disables/modifies long running tests to make the suitable for code coverage
# reporting
_coverage = []
[[test]]
name = "mimc"
path = "tests/mimc.rs"
required-features = ["groth16"]
[badges]
maintenance = { status = "actively-developed" }
[[bench]]
name = "lc"
harness = false
This diff is collapsed.
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
# bellperson [![Crates.io](https://img.shields.io/crates/v/bellperson.svg)](https://crates.io/crates/bellperson)
> This is a fork of the great [bellman](https://github.com/zkcrypto/bellman) library.
`bellman` is a crate for building zk-SNARK circuits. It provides circuit traits
and primitive structures, as well as basic gadget implementations such as
booleans and number abstractions.
## Backend
There are currently two backends available for the implementation of Bls12 381:
- [`paired`](https://github.com/filecoin-project/paired) - pure Rust implementation
- [`blstrs`](https://github.com/filecoin-project/blstrs) - optimized with hand tuned assembly, using [blst](https://github.com/supranational/blst)
They can be selected at compile time with the mutually exclusive features `pairing` and `blst`. Specifying one of them is enough for a working library, no additional features need to be set.
The default for now is `pairing`, as the secure and audited choice.
## GPU
This fork contains GPU parallel acceleration to the FFT and Multiexponentation algorithms in the groth16 prover codebase under the compilation feature `gpu`, it can be used in combination with `pairing` or `blst`.
### Requirements
- NVIDIA or AMD GPU Graphics Driver
- OpenCL
( For AMD devices we recommend [ROCm](https://rocm-documentation.readthedocs.io/en/latest/Installation_Guide/Installation-Guide.html) )
### Environment variables
The gpu extension contains some env vars that may be set externally to this library.
- `BELLMAN_NO_GPU`
Will disable the GPU feature from the library and force usage of the CPU.
```rust
// Example
env::set_var("BELLMAN_NO_GPU", "1");
```
- `BELLMAN_VERIFIER`
Chooses the device in which the batched verifier is going to run. Can be `cpu`, `gpu` or `auto`.
```rust
Example
env::set_var("BELLMAN_VERIFIER", "gpu");
```
- `BELLMAN_CUSTOM_GPU`
Will allow for adding a GPU not in the tested list. This requires researching the name of the GPU device and the number of cores in the format `["name:cores"]`.
```rust
// Example
env::set_var("BELLMAN_CUSTOM_GPU", "GeForce RTX 2080 Ti:4352, GeForce GTX 1060:1280");
```
- `BELLMAN_CPU_UTILIZATION`
Can be set in the interval [0,1] to designate a proportion of the multiexponenation calculation to be moved to cpu in parallel to the GPU to keep all hardware occupied.
```rust
// Example
env::set_var("BELLMAN_CPU_UTILIZATION", "0.5");
```
#### Supported / Tested Cards
Depending on the size of the proof being passed to the gpu for work, certain cards will not be able to allocate enough memory to either the FFT or Multiexp kernel. Below are a list of devices that work for small sets. In the future we will add the cuttoff point at which a given card will not be able to allocate enough memory to utilize the GPU.
| Device Name | Cores | Comments |
|------------------------|-------|----------------|
| Quadro RTX 6000 | 4608 | |
| TITAN RTX | 4608 | |
| Tesla V100 | 5120 | |
| Tesla P100 | 3584 | |
| Tesla T4 | 2560 | |
| Quadro M5000 | 2048 | |
| GeForce RTX 3090 |10496 | |
| GeForce RTX 3080 | 8704 | |
| GeForce RTX 3070 | 5888 | |
| GeForce RTX 2080 Ti | 4352 | |
| GeForce RTX 2080 SUPER | 3072 | |
| GeForce RTX 2080 | 2944 | |
| GeForce RTX 2070 SUPER | 2560 | |
| GeForce GTX 1080 Ti | 3584 | |
| GeForce GTX 1080 | 2560 | |
| GeForce GTX 2060 | 1920 | |
| GeForce GTX 1660 Ti | 1536 | |
| GeForce GTX 1060 | 1280 | |
| GeForce GTX 1650 SUPER | 1280 | |
| GeForce GTX 1650 | 896 | |
| | | |
| gfx1010 | 2560 | AMD RX 5700 XT |
| gfx906 | 7400 | AMD RADEON VII |
|------------------------|-------|----------------|
### Running Tests
To run using the `pairing` backend, you can use:
```bash
RUSTFLAGS="-C target-cpu=native" cargo test --release --all --no-default-features --features pairing
```
To run using both the `gpu` and `blst` backend, you can use:
```bash
RUSTFLAGS="-C target-cpu=native" cargo test --release --all --no-default-features --features gpu,blst
```
To run the multiexp_consistency test you can use:
```bash
RUST_LOG=info cargo test --features gpu -- --exact multiexp::gpu_multiexp_consistency --nocapture
```
### Considerations
Bellperson uses `rust-gpu-tools` as its OpenCL backend, therefore you may see a
directory named `~/.rust-gpu-tools` in your home folder, which contains the
compiled binaries of OpenCL kernels used in this repository.
## License
Licensed under either of
- Apache License, Version 2.0, |[LICENSE-APACHE](LICENSE-APACHE) or
http://www.apache.org/licenses/LICENSE-2.0)
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
at your option.
### Contribution
Unless you explicitly state otherwise, any contribution intentionally
submitted for inclusion in the work by you, as defined in the Apache-2.0
license, shall be dual licensed as above, without any additional terms or
conditions.
# Using AMD GPUs
## Prerequisites
- [Install ROCm 3.5](https://rocmdocs.amd.com/en/latest/Installation_Guide/Installation-Guide.html#supported-operating-systems)
## Running tests
The environment variable `BELLMAN_PLATFORM` determines which backend will be used.
To use the AMD backend, you can do something like:
```bash
export BELLMAN_PLATFORM="AMD Accelerated Parallel Processing"
RUST_LOG=info cargo test --features gpu -- --exact multiexp::gpu_multiexp_consistency --nocapture
```
## Notes
- We had trouble in Ubuntu 20.04 when running a single computer with both NVIDIA and AMD cards.
- The initial kernel compilation may take > 60sec at start up. This is not a problem afterwards. A possible mitigation would be to add kernel binary caching in the ocl-fil crate.
# Security Policy
## Reporting a Vulnerability
For reporting *critical* and *security* bugs, please consult our [Security Policy and Responsible Disclosure Program information](https://github.com/filecoin-project/community/blob/master/SECURITY.md)
## Reporting a non security bug
For non-critical bugs, please simply file a GitHub issue on this repo.
use bellperson::{bls::Bls12, Index, LinearCombination, Variable};
use criterion::{black_box, criterion_group, criterion_main, Criterion};
use ff::{Field, ScalarEngine};
fn lc_benchmark(c: &mut Criterion) {
c.bench_function("LinearCombination::add((Fr, Variable))", |b| {
b.iter(|| {
let mut lc = LinearCombination::<Bls12>::zero();
for i in 0..100 {
let coeff = <Bls12 as ScalarEngine>::Fr::one();
lc = lc + (coeff, Variable::new_unchecked(Index::Aux(i)));
}
black_box(lc);
});
})
.bench_function("LinearCombination::add(LinearCombination)", |b| {
let mut lc1 = LinearCombination::<Bls12>::zero();
let mut lc2 = LinearCombination::<Bls12>::zero();
for i in 0..10 {
let coeff = <Bls12 as ScalarEngine>::Fr::one();
lc1 = lc1 + (coeff, Variable::new_unchecked(Index::Aux(i)));
let coeff = <Bls12 as ScalarEngine>::Fr::one();
lc2 = lc2 + (coeff, Variable::new_unchecked(Index::Aux(i * 2)));
}
b.iter(|| {
let mut lc = lc1.clone();
for _ in 0..10 {
lc = lc + &lc2;
}
black_box(lc);
});
});
}
criterion_group!(benches, lc_benchmark);
criterion_main!(benches);
pre-release-commit-message = "chore({{crate_name}}): release {{version}}"
pro-release-commit-message = "chore({{crate_name}}): starting development cycle for {{next_version}}"
no-dev-version = true
\ No newline at end of file
#[cfg(feature = "blst")]
pub use blstrs::{
Bls12, Compress, Engine, Fp as Fq, Fp12 as Fq12, Fp2 as Fq2, FpRepr as FqRepr, G1Affine,
G1Compressed, G1Projective, G1Uncompressed, G2Affine, G2Compressed, G2Prepared, G2Projective,
G2Uncompressed, PairingCurveAffine, Scalar as Fr, ScalarRepr as FrRepr,
};
#[cfg(feature = "pairing")]
pub use paired::{
bls12_381::{
Bls12, Fq, Fq12, Fq2, FqRepr, Fr, FrRepr, G1Affine, G1Compressed, G1Uncompressed, G2Affine,
G2Compressed, G2Prepared, G2Uncompressed, G1 as G1Projective, G2 as G2Projective,
},
Compress, Engine, PairingCurveAffine,
};
This diff is collapsed.
//! Self-contained sub-circuit implementations for various primitives.
pub mod test;
pub mod blake2s;
pub mod boolean;
pub mod lookup;
pub mod multieq;
pub mod multipack;
pub mod num;
pub mod sha256;
pub mod uint32;
use crate::SynthesisError;
// TODO: This should probably be removed and we
// should use existing helper methods on `Option`
// for mapping with an error.
/// This basically is just an extension to `Option`
/// which allows for a convenient mapping to an
/// error on `None`.
pub trait Assignment<T> {
fn get(&self) -> Result<&T, SynthesisError>;
}
impl<T> Assignment<T> for Option<T> {
fn get(&self) -> Result<&T, SynthesisError> {
match *self {
Some(ref v) => Ok(v),
None => Err(SynthesisError::AssignmentMissing),
}
}
}
This diff is collapsed.
This diff is collapsed.
//! Window table lookup gadgets.
use ff::{Field, ScalarEngine};
use super::boolean::Boolean;
use super::num::{AllocatedNum, Num};
use super::*;
use crate::ConstraintSystem;
// Synthesize the constants for each base pattern.
fn synth<'a, E: ScalarEngine, I>(window_size: usize, constants: I, assignment: &mut [E::Fr])
where
I: IntoIterator<Item = &'a E::Fr>,
{
assert_eq!(assignment.len(), 1 << window_size);
for (i, constant) in constants.into_iter().enumerate() {
let mut cur = assignment[i];
cur.negate();
cur.add_assign(constant);
assignment[i] = cur;
for (j, eval) in assignment.iter_mut().enumerate().skip(i + 1) {
if j & i == i {
eval.add_assign(&cur);
}
}
}
}
/// Performs a 3-bit window table lookup. `bits` is in
/// little-endian order.
pub fn lookup3_xy<E: ScalarEngine, CS>(
mut cs: CS,
bits: &[Boolean],
coords: &[(E::Fr, E::Fr)],
) -> Result<(AllocatedNum<E>, AllocatedNum<E>), SynthesisError>
where
CS: ConstraintSystem<E>,
{
assert_eq!(bits.len(), 3);
assert_eq!(coords.len(), 8);
// Calculate the index into `coords`
let i = match (
bits[0].get_value(),
bits[1].get_value(),
bits[2].get_value(),
) {
(Some(a_value), Some(b_value), Some(c_value)) => {
let mut tmp = 0;
if a_value {
tmp += 1;
}
if b_value {
tmp += 2;
}
if c_value {
tmp += 4;
}
Some(tmp)
}
_ => None,
};
// Allocate the x-coordinate resulting from the lookup
let res_x = AllocatedNum::alloc(cs.namespace(|| "x"), || Ok(coords[*i.get()?].0))?;
// Allocate the y-coordinate resulting from the lookup
let res_y = AllocatedNum::alloc(cs.namespace(|| "y"), || Ok(coords[*i.get()?].1))?;
// Compute the coefficients for the lookup constraints
let mut x_coeffs = [E::Fr::zero(); 8];
let mut y_coeffs = [E::Fr::zero(); 8];
synth::<E, _>(3, coords.iter().map(|c| &c.0), &mut x_coeffs);
synth::<E, _>(3, coords.iter().map(|c| &c.1), &mut y_coeffs);
let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[1], &bits[2])?;
let one = CS::one();
cs.enforce(
|| "x-coordinate lookup",
|lc| {
lc + (x_coeffs[0b001], one)
+ &bits[1].lc::<E>(one, x_coeffs[0b011])
+ &bits[2].lc::<E>(one, x_coeffs[0b101])
+ &precomp.lc::<E>(one, x_coeffs[0b111])
},
|lc| lc + &bits[0].lc::<E>(one, E::Fr::one()),
|lc| {
lc + res_x.get_variable()
- (x_coeffs[0b000], one)
- &bits[1].lc::<E>(one, x_coeffs[0b010])
- &bits[2].lc::<E>(one, x_coeffs[0b100])
- &precomp.lc::<E>(one, x_coeffs[0b110])
},
);
cs.enforce(
|| "y-coordinate lookup",
|lc| {
lc + (y_coeffs[0b001], one)
+ &bits[1].lc::<E>(one, y_coeffs[0b011])
+ &bits[2].lc::<E>(one, y_coeffs[0b101])
+ &precomp.lc::<E>(one, y_coeffs[0b111])
},
|lc| lc + &bits[0].lc::<E>(one, E::Fr::one()),
|lc| {
lc + res_y.get_variable()
- (y_coeffs[0b000], one)
- &bits[1].lc::<E>(one, y_coeffs[0b010])
- &bits[2].lc::<E>(one, y_coeffs[0b100])
- &precomp.lc::<E>(one, y_coeffs[0b110])
},
);
Ok((res_x, res_y))
}
/// Performs a 3-bit window table lookup, where
/// one of the bits is a sign bit.
pub fn lookup3_xy_with_conditional_negation<E: ScalarEngine, CS>(
mut cs: CS,
bits: &[Boolean],
coords: &[(E::Fr, E::Fr)],
) -> Result<(Num<E>, Num<E>), SynthesisError>
where
CS: ConstraintSystem<E>,
{
assert_eq!(bits.len(), 3);
assert_eq!(coords.len(), 4);
// Calculate the index into `coords`
let i = match (bits[0].get_value(), bits[1].get_value()) {
(Some(a_value), Some(b_value)) => {
let mut tmp = 0;
if a_value {
tmp += 1;
}
if b_value {
tmp += 2;
}
Some(tmp)
}
_ => None,
};
// Allocate the y-coordinate resulting from the lookup
// and conditional negation
let y = AllocatedNum::alloc(cs.namespace(|| "y"), || {
let mut tmp = coords[*i.get()?].1;
if *bits[2].get_value().get()? {
tmp.negate();
}
Ok(tmp)
})?;
let one = CS::one();
// Compute the coefficients for the lookup constraints
let mut x_coeffs = [E::Fr::zero(); 4];
let mut y_coeffs = [E::Fr::zero(); 4];
synth::<E, _>(2, coords.iter().map(|c| &c.0), &mut x_coeffs);
synth::<E, _>(2, coords.iter().map(|c| &c.1), &mut y_coeffs);
let precomp = Boolean::and(cs.namespace(|| "precomp"), &bits[0], &bits[1])?;
let x = Num::zero()
.add_bool_with_coeff(one, &Boolean::constant(true), x_coeffs[0b00])
.add_bool_with_coeff(one, &bits[0], x_coeffs[0b01])
.add_bool_with_coeff(one, &bits[1], x_coeffs[0b10])
.add_bool_with_coeff(one, &precomp, x_coeffs[0b11]);
let y_lc = precomp.lc::<E>(one, y_coeffs[0b11])
+ &bits[1].lc::<E>(one, y_coeffs[0b10])
+ &bits[0].lc::<E>(one, y_coeffs[0b01])
+ (y_coeffs[0b00], one);
cs.enforce(
|| "y-coordinate lookup",
|lc| lc + &y_lc + &y_lc,
|lc| lc + &bits[2].lc::<E>(one, E::Fr::one()),
|lc| lc + &y_lc - y.get_variable(),
);
Ok((x, y.into()))
}
#[cfg(test)]
mod test {
use super::*;
use crate::bls::{Bls12, Fr};
use crate::gadgets::boolean::{AllocatedBit, Boolean};
use crate::gadgets::test::*;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
#[test]
fn test_lookup3_xy() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..100 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let a_val = rng.next_u32() % 2 != 0;
let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap());
let b_val = rng.next_u32() % 2 != 0;
let b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap());
let c_val = rng.next_u32() % 2 != 0;
let c = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap());
let bits = vec![a, b, c];
let points: Vec<(Fr, Fr)> = (0..8)
.map(|_| (Fr::random(&mut rng), Fr::random(&mut rng)))
.collect();
let res = lookup3_xy(&mut cs, &bits, &points).unwrap();
assert!(cs.is_satisfied());
let mut index = 0;
if a_val {
index += 1
}
if b_val {
index += 2
}
if c_val {
index += 4
}
assert_eq!(res.0.get_value().unwrap(), points[index].0);
assert_eq!(res.1.get_value().unwrap(), points[index].1);
}
}
#[test]
fn test_lookup3_xy_with_conditional_negation() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
for _ in 0..100 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let a_val = rng.next_u32() % 2 != 0;
let a = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "a"), Some(a_val)).unwrap());
let b_val = rng.next_u32() % 2 != 0;
let b = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "b"), Some(b_val)).unwrap());
let c_val = rng.next_u32() % 2 != 0;
let c = Boolean::from(AllocatedBit::alloc(cs.namespace(|| "c"), Some(c_val)).unwrap());
let bits = vec![a, b, c];
let points: Vec<(Fr, Fr)> = (0..4)
.map(|_| (Fr::random(&mut rng), Fr::random(&mut rng)))
.collect();
let res = lookup3_xy_with_conditional_negation(&mut cs, &bits, &points).unwrap();
assert!(cs.is_satisfied());
let mut index = 0;
if a_val {
index += 1
}
if b_val {
index += 2
}
assert_eq!(res.0.get_value().unwrap(), points[index].0);
let mut tmp = points[index].1;
if c_val {
tmp.negate()
}
assert_eq!(res.1.get_value().unwrap(), tmp);
}
}
#[test]
fn test_synth() {
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
0xbc, 0xe5,
]);
let window_size = 4;
let mut assignment = vec![Fr::zero(); 1 << window_size];
let constants: Vec<_> = (0..(1 << window_size))
.map(|_| Fr::random(&mut rng))
.collect();
synth::<Bls12, _>(window_size, &constants, &mut assignment);
for b in 0..(1 << window_size) {
let mut acc = Fr::zero();
for j in 0..(1 << window_size) {
if j & b == j {
acc.add_assign(&assignment[j]);
}
}
assert_eq!(acc, constants[b]);
}
}
}
use ff::{Field, PrimeField, ScalarEngine};
use crate::{ConstraintSystem, LinearCombination, SynthesisError, Variable};
pub struct MultiEq<E: ScalarEngine, CS: ConstraintSystem<E>> {
cs: CS,
ops: usize,
bits_used: usize,
lhs: LinearCombination<E>,
rhs: LinearCombination<E>,
}
impl<E: ScalarEngine, CS: ConstraintSystem<E>> MultiEq<E, CS> {
pub fn new(cs: CS) -> Self {
MultiEq {
cs,
ops: 0,
bits_used: 0,
lhs: LinearCombination::zero(),
rhs: LinearCombination::zero(),
}
}
fn accumulate(&mut self) {
let ops = self.ops;
let lhs = self.lhs.clone();
let rhs = self.rhs.clone();
self.cs.enforce(
|| format!("multieq {}", ops),
|_| lhs,
|lc| lc + CS::one(),
|_| rhs,
);
self.lhs = LinearCombination::zero();
self.rhs = LinearCombination::zero();
self.bits_used = 0;
self.ops += 1;
}
pub fn enforce_equal(
&mut self,
num_bits: usize,
lhs: &LinearCombination<E>,
rhs: &LinearCombination<E>,
) {
// Check if we will exceed the capacity
if (E::Fr::CAPACITY as usize) <= (self.bits_used + num_bits) {
self.accumulate();
}
assert!((E::Fr::CAPACITY as usize) > (self.bits_used + num_bits));
let coeff = E::Fr::from_str("2").unwrap().pow(&[self.bits_used as u64]);
self.lhs = self.lhs.clone() + (coeff, lhs);
self.rhs = self.rhs.clone() + (coeff, rhs);
self.bits_used += num_bits;
}
}
impl<E: ScalarEngine, CS: ConstraintSystem<E>> Drop for MultiEq<E, CS> {
fn drop(&mut self) {
if self.bits_used > 0 {
self.accumulate();
}
}
}
impl<E: ScalarEngine, CS: ConstraintSystem<E>> ConstraintSystem<E> for MultiEq<E, CS> {
type Root = Self;
fn one() -> Variable {
CS::one()
}
fn alloc<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
self.cs.alloc(annotation, f)
}
fn alloc_input<F, A, AR>(&mut self, annotation: A, f: F) -> Result<Variable, SynthesisError>
where
F: FnOnce() -> Result<E::Fr, SynthesisError>,
A: FnOnce() -> AR,
AR: Into<String>,
{
self.cs.alloc_input(annotation, f)
}
fn enforce<A, AR, LA, LB, LC>(&mut self, annotation: A, a: LA, b: LB, c: LC)
where
A: FnOnce() -> AR,
AR: Into<String>,
LA: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LB: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
LC: FnOnce(LinearCombination<E>) -> LinearCombination<E>,
{
self.cs.enforce(annotation, a, b, c)
}
fn push_namespace<NR, N>(&mut self, name_fn: N)
where
NR: Into<String>,
N: FnOnce() -> NR,
{
self.cs.get_root().push_namespace(name_fn)
}
fn pop_namespace(&mut self) {
self.cs.get_root().pop_namespace()
}
fn get_root(&mut self) -> &mut Self::Root {
self
}
}
//! Helpers for packing vectors of bits into scalar field elements.
use super::boolean::Boolean;
use super::num::{AllocatedNum, Num};
use super::Assignment;
use crate::{ConstraintSystem, SynthesisError};
use ff::{Field, PrimeField, ScalarEngine};
/// Takes a sequence of booleans and exposes them as compact
/// public inputs
pub fn pack_into_inputs<E, CS>(mut cs: CS, bits: &[Boolean]) -> Result<(), SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
{
for (i, bits) in bits.chunks(E::Fr::CAPACITY as usize).enumerate() {
let mut num = Num::<E>::zero();
let mut coeff = E::Fr::one();
for bit in bits {
num = num.add_bool_with_coeff(CS::one(), bit, coeff);
coeff.double();
}
let input = cs.alloc_input(|| format!("input {}", i), || Ok(*num.get_value().get()?))?;
// num * 1 = input
cs.enforce(
|| format!("packing constraint {}", i),
|_| num.lc(E::Fr::one()),
|lc| lc + CS::one(),
|lc| lc + input,
);
}
Ok(())
}
pub fn bytes_to_bits(bytes: &[u8]) -> Vec<bool> {
bytes
.iter()
.flat_map(|&v| (0..8).rev().map(move |i| (v >> i) & 1 == 1))
.collect()
}
pub fn bytes_to_bits_le(bytes: &[u8]) -> Vec<bool> {
bytes
.iter()
.flat_map(|&v| (0..8).map(move |i| (v >> i) & 1 == 1))
.collect()
}
pub fn compute_multipacking<E: ScalarEngine>(bits: &[bool]) -> Vec<E::Fr> {
let mut result = vec![];
for bits in bits.chunks(E::Fr::CAPACITY as usize) {
let mut cur = E::Fr::zero();
let mut coeff = E::Fr::one();
for bit in bits {
if *bit {
cur.add_assign(&coeff);
}
coeff.double();
}
result.push(cur);
}
result
}
/// Takes a sequence of booleans and exposes them as a single compact Num.
pub fn pack_bits<E, CS>(mut cs: CS, bits: &[Boolean]) -> Result<AllocatedNum<E>, SynthesisError>
where
E: ScalarEngine,
CS: ConstraintSystem<E>,
{
let mut num = Num::<E>::zero();
let mut coeff = E::Fr::one();
for bit in bits.iter().take(E::Fr::CAPACITY as usize) {
num = num.add_bool_with_coeff(CS::one(), &bit, coeff);
coeff.double();
}
let alloc_num = AllocatedNum::alloc(cs.namespace(|| "input"), || {
num.get_value()
.ok_or_else(|| SynthesisError::AssignmentMissing)
})?;
// num * 1 = input
cs.enforce(
|| "packing constraint",
|_| num.lc(E::Fr::one()),
|lc| lc + CS::one(),
|lc| lc + alloc_num.get_variable(),
);
Ok(alloc_num)
}
#[test]
fn test_multipacking() {
use crate::bls::Bls12;
use crate::ConstraintSystem;
use rand_core::{RngCore, SeedableRng};
use rand_xorshift::XorShiftRng;
use super::boolean::{AllocatedBit, Boolean};
use crate::gadgets::test::*;
let mut rng = XorShiftRng::from_seed([
0x59, 0x62, 0xbe, 0x3d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
0xe5,
]);
for num_bits in 0..1500 {
let mut cs = TestConstraintSystem::<Bls12>::new();
let bits: Vec<bool> = (0..num_bits).map(|_| rng.next_u32() % 2 != 0).collect();
let circuit_bits = bits
.iter()
.enumerate()
.map(|(i, &b)| {
Boolean::from(
AllocatedBit::alloc(cs.namespace(|| format!("bit {}", i)), Some(b)).unwrap(),
)
})
.collect::<Vec<_>>();
let expected_inputs = compute_multipacking::<Bls12>(&bits);
pack_into_inputs(cs.namespace(|| "pack"), &circuit_bits).unwrap();
assert!(cs.is_satisfied());
assert!(cs.verify(&expected_inputs));
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#[cfg(feature = "gpu")]
use rust_gpu_tools::opencl;
#[derive(thiserror::Error, Debug)]
pub enum GPUError {
#[error("GPUError: {0}")]
Simple(&'static str),
#[cfg(feature = "gpu")]
#[error("OpenCL Error: {0}")]
OpenCL(#[from] opencl::GPUError),
#[cfg(feature = "gpu")]
#[error("GPU taken by a high priority process!")]
GPUTaken,
#[cfg(feature = "gpu")]
#[error("No kernel is initialized!")]
KernelUninitialized,
#[error("GPU accelerator is disabled!")]
GPUDisabled,
}
pub type GPUResult<T> = std::result::Result<T, GPUError>;
#[cfg(feature = "gpu")]
impl From<std::boxed::Box<dyn std::any::Any + std::marker::Send>> for GPUError {
fn from(e: std::boxed::Box<dyn std::any::Any + std::marker::Send>) -> Self {
match e.downcast::<Self>() {
Ok(err) => *err,
Err(_) => GPUError::Simple("An unknown GPU error happened!"),
}
}
}
use crate::bls::Engine;
use crate::gpu::{
error::{GPUError, GPUResult},
locks, sources,
};
use ff::Field;
use log::info;
use rust_gpu_tools::*;
use std::cmp;
const LOG2_MAX_ELEMENTS: usize = 32; // At most 2^32 elements is supported.
const MAX_LOG2_RADIX: u32 = 8; // Radix256
const MAX_LOG2_LOCAL_WORK_SIZE: u32 = 7; // 128
pub struct FFTKernel<E>
where
E: Engine,
{
program: opencl::Program,
pq_buffer: opencl::Buffer<E::Fr>,
omegas_buffer: opencl::Buffer<E::Fr>,
_lock: locks::GPULock, // RFC 1857: struct fields are dropped in the same order as they are declared.
priority: bool,
}
impl<E> FFTKernel<E>
where
E: Engine,
{
pub fn create(priority: bool) -> GPUResult<FFTKernel<E>> {
let lock = locks::GPULock::lock();
let devices = opencl::Device::all();
if devices.is_empty() {
return Err(GPUError::Simple("No working GPUs found!"));
}
// Select the first device for FFT
let device = devices[0].clone();
let src = sources::kernel::<E>(device.brand() == opencl::Brand::Nvidia);
let program = opencl::Program::from_opencl(device, &src)?;
let pq_buffer = program.create_buffer::<E::Fr>(1 << MAX_LOG2_RADIX >> 1)?;
let omegas_buffer = program.create_buffer::<E::Fr>(LOG2_MAX_ELEMENTS)?;
info!("FFT: 1 working device(s) selected.");
info!("FFT: Device 0: {}", program.device().name());
Ok(FFTKernel {
program,
pq_buffer,
omegas_buffer,
_lock: lock,
priority,
})
}
/// Peforms a FFT round
/// * `log_n` - Specifies log2 of number of elements
/// * `log_p` - Specifies log2 of `p`, (http://www.bealto.com/gpu-fft_group-1.html)
/// * `deg` - 1=>radix2, 2=>radix4, 3=>radix8, ...
/// * `max_deg` - The precalculated values pq` and `omegas` are valid for radix degrees up to `max_deg`
fn radix_fft_round(
&mut self,
src_buffer: &opencl::Buffer<E::Fr>,
dst_buffer: &opencl::Buffer<E::Fr>,
log_n: u32,
log_p: u32,
deg: u32,
max_deg: u32,
) -> GPUResult<()> {
if locks::PriorityLock::should_break(self.priority) {
return Err(GPUError::GPUTaken);
}
let n = 1u32 << log_n;
let local_work_size = 1 << cmp::min(deg - 1, MAX_LOG2_LOCAL_WORK_SIZE);
let global_work_size = (n >> deg) * local_work_size;
let kernel = self.program.create_kernel(
"radix_fft",
global_work_size as usize,
Some(local_work_size as usize),
);
kernel
.arg(src_buffer)
.arg(dst_buffer)
.arg(&self.pq_buffer)
.arg(&self.omegas_buffer)
.arg(opencl::LocalBuffer::<E::Fr>::new(1 << deg))
.arg(n)
.arg(log_p)
.arg(deg)
.arg(max_deg)
.run()?;
Ok(())
}
/// Share some precalculated values between threads to boost the performance
fn setup_pq_omegas(&mut self, omega: &E::Fr, n: usize, max_deg: u32) -> GPUResult<()> {
// Precalculate:
// [omega^(0/(2^(deg-1))), omega^(1/(2^(deg-1))), ..., omega^((2^(deg-1)-1)/(2^(deg-1)))]
let mut pq = vec![E::Fr::zero(); 1 << max_deg >> 1];
let twiddle = omega.pow([(n >> max_deg) as u64]);
pq[0] = E::Fr::one();
if max_deg > 1 {
pq[1] = twiddle;
for i in 2..(1 << max_deg >> 1) {
pq[i] = pq[i - 1];
pq[i].mul_assign(&twiddle);
}
}
self.pq_buffer.write_from(0, &pq)?;
// Precalculate [omega, omega^2, omega^4, omega^8, ..., omega^(2^31)]
let mut omegas = vec![E::Fr::zero(); 32];
omegas[0] = *omega;
for i in 1..LOG2_MAX_ELEMENTS {
omegas[i] = omegas[i - 1].pow([2u64]);
}
self.omegas_buffer.write_from(0, &omegas)?;
Ok(())
}
/// Performs FFT on `a`
/// * `omega` - Special value `omega` is used for FFT over finite-fields
/// * `log_n` - Specifies log2 of number of elements
pub fn radix_fft(&mut self, a: &mut [E::Fr], omega: &E::Fr, log_n: u32) -> GPUResult<()> {
let n = 1 << log_n;
let mut src_buffer = self.program.create_buffer::<E::Fr>(n)?;
let mut dst_buffer = self.program.create_buffer::<E::Fr>(n)?;
let max_deg = cmp::min(MAX_LOG2_RADIX, log_n);
self.setup_pq_omegas(omega, n, max_deg)?;
src_buffer.write_from(0, &*a)?;
let mut log_p = 0u32;
while log_p < log_n {
let deg = cmp::min(max_deg, log_n - log_p);
self.radix_fft_round(&src_buffer, &dst_buffer, log_n, log_p, deg, max_deg)?;
log_p += deg;
std::mem::swap(&mut src_buffer, &mut dst_buffer);
}
src_buffer.read_into(0, a)?;
Ok(())
}
}
This diff is collapsed.
This diff is collapsed.
mod error;
pub use self::error::*;
#[cfg(feature = "gpu")]
mod locks;
#[cfg(feature = "gpu")]
pub use self::locks::*;
#[cfg(feature = "gpu")]
mod sources;
#[cfg(feature = "gpu")]
pub use self::sources::*;
#[cfg(feature = "gpu")]
mod utils;
#[cfg(feature = "gpu")]
pub use self::utils::*;
#[cfg(feature = "gpu")]
mod fft;
#[cfg(feature = "gpu")]
pub use self::fft::*;
#[cfg(feature = "gpu")]
mod multiexp;
#[cfg(feature = "gpu")]
pub use self::multiexp::*;
#[cfg(not(feature = "gpu"))]
mod nogpu;
#[cfg(not(feature = "gpu"))]
pub use self::nogpu::*;
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment