Browse Source

Update to `arkworks` libraries (#3)

Co-authored-by: Nicholas Ward <npward@berkeley.edu>
master
Pratyush Mishra 3 years ago
committed by GitHub
parent
commit
636f93a3e5
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
122 changed files with 910 additions and 9328 deletions
  1. +2
    -11
      .github/workflows/ci.yml
  2. +0
    -6
      AUTHORS
  3. +30
    -25
      Cargo.toml
  4. +13
    -76
      README.md
  5. +0
    -52
      cp-benches/Cargo.toml
  6. +0
    -53
      cp-benches/benches/crypto_primitives/comm.rs
  7. +0
    -48
      cp-benches/benches/crypto_primitives/crh.rs
  8. +0
    -25
      cp-benches/benches/crypto_primitives/prf.rs
  9. +0
    -89
      cp-benches/benches/crypto_primitives/signature.rs
  10. +0
    -52
      crypto-primitives/Cargo.toml
  11. +0
    -1
      crypto-primitives/LICENSE-APACHE
  12. +0
    -1
      crypto-primitives/LICENSE-MIT
  13. +0
    -133
      crypto-primitives/src/commitment/blake2s/constraints.rs
  14. +0
    -33
      crypto-primitives/src/commitment/blake2s/mod.rs
  15. +0
    -23
      crypto-primitives/src/commitment/constraints.rs
  16. +0
    -59
      crypto-primitives/src/commitment/injective_map/constraints.rs
  17. +0
    -44
      crypto-primitives/src/commitment/injective_map/mod.rs
  18. +0
    -30
      crypto-primitives/src/commitment/mod.rs
  19. +0
    -204
      crypto-primitives/src/commitment/pedersen/constraints.rs
  20. +0
    -125
      crypto-primitives/src/commitment/pedersen/mod.rs
  21. +0
    -180
      crypto-primitives/src/crh/bowe_hopwood/constraints.rs
  22. +0
    -197
      crypto-primitives/src/crh/bowe_hopwood/mod.rs
  23. +0
    -25
      crypto-primitives/src/crh/constraints.rs
  24. +0
    -98
      crypto-primitives/src/crh/injective_map/constraints.rs
  25. +0
    -59
      crypto-primitives/src/crh/injective_map/mod.rs
  26. +0
    -24
      crypto-primitives/src/crh/mod.rs
  27. +0
    -152
      crypto-primitives/src/crh/pedersen/constraints.rs
  28. +0
    -152
      crypto-primitives/src/crh/pedersen/mod.rs
  29. +0
    -59
      crypto-primitives/src/lib.rs
  30. +0
    -258
      crypto-primitives/src/merkle_tree/constraints.rs
  31. +0
    -449
      crypto-primitives/src/merkle_tree/mod.rs
  32. +0
    -51
      crypto-primitives/src/nizk/constraints.rs
  33. +0
    -797
      crypto-primitives/src/nizk/gm17/constraints.rs
  34. +0
    -87
      crypto-primitives/src/nizk/gm17/mod.rs
  35. +0
    -746
      crypto-primitives/src/nizk/groth16/constraints.rs
  36. +0
    -87
      crypto-primitives/src/nizk/groth16/mod.rs
  37. +0
    -115
      crypto-primitives/src/nizk/mod.rs
  38. +0
    -537
      crypto-primitives/src/prf/blake2s/constraints.rs
  39. +0
    -92
      crypto-primitives/src/prf/blake2s/mod.rs
  40. +0
    -20
      crypto-primitives/src/prf/constraints.rs
  41. +0
    -20
      crypto-primitives/src/prf/mod.rs
  42. +0
    -20
      crypto-primitives/src/signature/constraints.rs
  43. +0
    -104
      crypto-primitives/src/signature/mod.rs
  44. +0
    -158
      crypto-primitives/src/signature/schnorr/constraints.rs
  45. +0
    -229
      crypto-primitives/src/signature/schnorr/mod.rs
  46. +0
    -58
      r1cs-std/Cargo.toml
  47. +0
    -1
      r1cs-std/LICENSE-APACHE
  48. +0
    -1
      r1cs-std/LICENSE-MIT
  49. +0
    -422
      r1cs-std/src/fields/mod.rs
  50. +0
    -29
      r1cs-std/src/instantiated/bls12_377/curves.rs
  51. +0
    -32
      r1cs-std/src/instantiated/bls12_377/fields.rs
  52. +0
    -157
      r1cs-std/src/instantiated/bls12_377/mod.rs
  53. +0
    -9
      r1cs-std/src/instantiated/bls12_377/pairing.rs
  54. +0
    -12
      r1cs-std/src/instantiated/ed_on_bls12_377/curves.rs
  55. +0
    -10
      r1cs-std/src/instantiated/ed_on_bls12_377/fields.rs
  56. +0
    -107
      r1cs-std/src/instantiated/ed_on_bls12_377/mod.rs
  57. +0
    -12
      r1cs-std/src/instantiated/ed_on_bls12_381/curves.rs
  58. +0
    -9
      r1cs-std/src/instantiated/ed_on_bls12_381/fields.rs
  59. +0
    -107
      r1cs-std/src/instantiated/ed_on_bls12_381/mod.rs
  60. +0
    -12
      r1cs-std/src/instantiated/ed_on_bn254/curves.rs
  61. +0
    -9
      r1cs-std/src/instantiated/ed_on_bn254/fields.rs
  62. +0
    -107
      r1cs-std/src/instantiated/ed_on_bn254/mod.rs
  63. +0
    -103
      r1cs-std/src/instantiated/ed_on_bw6_761/mod.rs
  64. +0
    -12
      r1cs-std/src/instantiated/ed_on_cp6_782/curves.rs
  65. +0
    -10
      r1cs-std/src/instantiated/ed_on_cp6_782/fields.rs
  66. +0
    -108
      r1cs-std/src/instantiated/ed_on_cp6_782/mod.rs
  67. +0
    -12
      r1cs-std/src/instantiated/ed_on_mnt4_298/curves.rs
  68. +0
    -10
      r1cs-std/src/instantiated/ed_on_mnt4_298/fields.rs
  69. +0
    -107
      r1cs-std/src/instantiated/ed_on_mnt4_298/mod.rs
  70. +0
    -12
      r1cs-std/src/instantiated/ed_on_mnt4_753/curves.rs
  71. +0
    -10
      r1cs-std/src/instantiated/ed_on_mnt4_753/fields.rs
  72. +0
    -107
      r1cs-std/src/instantiated/ed_on_mnt4_753/mod.rs
  73. +0
    -29
      r1cs-std/src/instantiated/mnt4_298/curves.rs
  74. +0
    -26
      r1cs-std/src/instantiated/mnt4_298/fields.rs
  75. +0
    -157
      r1cs-std/src/instantiated/mnt4_298/mod.rs
  76. +0
    -9
      r1cs-std/src/instantiated/mnt4_298/pairing.rs
  77. +0
    -29
      r1cs-std/src/instantiated/mnt4_753/curves.rs
  78. +0
    -26
      r1cs-std/src/instantiated/mnt4_753/fields.rs
  79. +0
    -157
      r1cs-std/src/instantiated/mnt4_753/mod.rs
  80. +0
    -9
      r1cs-std/src/instantiated/mnt4_753/pairing.rs
  81. +0
    -29
      r1cs-std/src/instantiated/mnt6_298/curves.rs
  82. +0
    -26
      r1cs-std/src/instantiated/mnt6_298/fields.rs
  83. +0
    -157
      r1cs-std/src/instantiated/mnt6_298/mod.rs
  84. +0
    -9
      r1cs-std/src/instantiated/mnt6_298/pairing.rs
  85. +0
    -29
      r1cs-std/src/instantiated/mnt6_753/curves.rs
  86. +0
    -26
      r1cs-std/src/instantiated/mnt6_753/fields.rs
  87. +0
    -157
      r1cs-std/src/instantiated/mnt6_753/mod.rs
  88. +0
    -9
      r1cs-std/src/instantiated/mnt6_753/pairing.rs
  89. +0
    -38
      r1cs-std/src/instantiated/mod.rs
  90. +0
    -187
      r1cs-std/src/lib.rs
  91. +0
    -183
      r1cs-std/src/pairing/mod.rs
  92. +10
    -6
      src/alloc.rs
  93. +66
    -63
      src/bits/boolean.rs
  94. +12
    -8
      src/bits/mod.rs
  95. +7
    -7
      src/bits/uint.rs
  96. +33
    -32
      src/bits/uint8.rs
  97. +24
    -17
      src/eq.rs
  98. +14
    -13
      src/fields/cubic_extension.rs
  99. +35
    -31
      src/fields/fp/cmp.rs
  100. +24
    -20
      src/fields/fp/mod.rs

+ 2
- 11
.github/workflows/ci.yml

@ -117,14 +117,5 @@ jobs:
- name: r1cs-std
run: |
cd r1cs-std
cargo build -p r1cs-std --no-default-features --target aarch64-unknown-none
cargo check --examples -p r1cs-std --no-default-features --target aarch64-unknown-none
cd ..
- name: crypto-primitives
run: |
cd crypto-primitives
cargo build -p crypto-primitives --no-default-features --target aarch64-unknown-none
cargo check --examples -p crypto-primitives --no-default-features --target aarch64-unknown-none
cd ..
cargo build --no-default-features --target aarch64-unknown-none
cargo check --examples --no-default-features --target aarch64-unknown-none

+ 0
- 6
AUTHORS

@ -1,6 +0,0 @@
Sean Bowe
Alessandro Chiesa
Matthew Green
Ian Miers
Pratyush Mishra
Howard Wu

+ 30
- 25
Cargo.toml

@ -1,30 +1,35 @@
[workspace]
[package]
name = "ark-r1cs-std"
version = "0.1.0"
authors = [ "arkworks contributors" ]
description = "A standard library for constraint system gadgets"
homepage = "https://arworks.rs"
repository = "https://github.com/arkworks/r1cs-gadgets"
documentation = "https://docs.rs/ark-r1cs-std/"
keywords = ["zero knowledge", "cryptography", "zkSNARK", "SNARK", "r1cs"]
categories = ["cryptography"]
include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
license = "MIT/Apache-2.0"
edition = "2018"
members = [
"cp-benches",
"crypto-primitives",
"r1cs-std",
]
[dependencies]
ark-ff = { git = "https://github.com/arkworks-rs/algebra", default-features = false }
ark-ec = { git = "https://github.com/arkworks-rs/algebra", default-features = false }
ark-std = { git = "https://github.com/arkworks-rs/utils", default-features = false }
ark-relations = { git = "https://github.com/arkworks-rs/snark", default-features = false }
[profile.release]
opt-level = 3
lto = "thin"
incremental = true
derivative = { version = "2", features = ["use_core"] }
tracing = { version = "0.1", default-features = false, features = [ "attributes" ] }
[profile.bench]
opt-level = 3
debug = false
rpath = false
lto = "thin"
incremental = true
debug-assertions = false
[build-dependencies]
rustc_version = "0.2"
[profile.dev]
opt-level = 0
[dev-dependencies]
rand = { version = "0.7", default-features = false }
rand_xorshift = "0.2"
ark-test-curves = { git = "https://github.com/arkworks-rs/algebra", default-features = false, features = ["bls12_381_scalar_field"] }
[profile.test]
opt-level = 3
lto = "thin"
incremental = true
debug-assertions = true
debug = true
[features]
default = ["std"]
std = [ "ark-ff/std", "ark-relations/std", "ark-std/std" ]
parallel = [ "std", "ark-ff/parallel" ]

+ 13
- 76
README.md

@ -1,52 +1,18 @@
<h1 align="center">ZEXE (Zero knowledge EXEcution)</h1>
<h1 align="center">ark-r1cs-std</h1>
<p align="center">
<img src="https://github.com/scipr-lab/zexe/workflows/CI/badge.svg?branch=master">
<a href="https://github.com/scipr-lab/zexe/blob/master/AUTHORS"><img src="https://img.shields.io/badge/authors-SCIPR%20Lab-orange.svg"></a>
<a href="https://github.com/scipr-lab/zexe/blob/master/LICENSE-APACHE"><img src="https://img.shields.io/badge/license-APACHE-blue.svg"></a>
<a href="https://github.com/scipr-lab/zexe/blob/master/LICENSE-MIT"><img src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
<a href="https://deps.rs/repo/github/scipr-lab/zexe"><img src="https://deps.rs/repo/github/scipr-lab/zexe/status.svg"></a>
<img src="https://github.com/arkworks-rs/r1cs-std/workflows/CI/badge.svg?branch=master">
<a href="https://github.com/arkworks-rs/r1cs-std/blob/master/LICENSE-APACHE"><img src="https://img.shields.io/badge/license-APACHE-blue.svg"></a>
<a href="https://github.com/arkworks-rs/r1cs-std/blob/master/LICENSE-MIT"><img src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
<a href="https://deps.rs/repo/github/arkworks-rs/r1cs-std"><img src="https://deps.rs/repo/github/arkworks-rs/r1cs-std/status.svg"></a>
</p>
___ZEXE___ (pronounced */zeksē/*) is a Rust library for decentralized private computation.
The arkworks ecosystem consist of Rust libraries for designing and working with __zero knowledge succinct non-interactive arguments (zkSNARKs)__. This repository contains efficient implementations of constraint "gadgets" that enable checking common computations inside SNARKs, such as bit operations, finite field arithmetic, elliptic curve arithmetic, and pairings.
This library was initially developed as part of the paper *"[ZEXE: Enabling Decentralized Private Computation][zexe]"*, and it is released under the MIT License and the Apache v2 License (see [License](#license)).
This library is released under the MIT License and the Apache v2 License (see [License](#license)).
**WARNING:** This is an academic proof-of-concept prototype, and in particular has not received careful code review. This implementation is NOT ready for production use.
## Overview
This library implements a ledger-based system that enables users to execute offline computations and subsequently produce publicly-verifiable transactions that attest to the correctness of these offline executions. The transactions contain *zero-knowledge succinct arguments* (zkSNARKs) attesting to the correctness of the offline computations, and provide strong notions of privacy and succinctness.
- **Privacy** - transactions reveal no information about the offline computation.
- **Succinctness** - transactions can be validated in time that is independent of the offline computation.
- **Application isolation** - malicious applications cannot affect the execution of honest applications.
- **Application interaction** - applications can safely communicate with each other.
Informally, the library provides the ability to create transactions that run arbitrary (Turing-complete) scripts on hidden data stored on the ledger. In more detail, the library implements a cryptographic primitive known as *decentralized private computation* (DPC) schemes, which are described in detail in the [ZEXE paper][zexe].
## Directory structure
This repository contains several Rust crates that implement the different building blocks of ZEXE. The high-level structure of the repository is as follows.
* [`algebra-core`](algebra-core): Rust crate that provides generic arithmetic for finite fields and elliptic curves
* [`algebra`](algebra): Rust crate that provides concrete instantiations of some finite fields and elliptic curves
* [`crypto-primitives`](crypto-primitives): Rust crate that implements some useful cryptographic primitives (and constraints for them)
* [`dpc`](dpc): Rust crate that implements DPC schemes (the main cryptographic primitive in this repository)
* [`ff-fft`](ff-fft): Rust crate that provides efficient finite field polynomial arithmetic based on finite field FFTs
* [`r1cs-core`](r1cs-core): Rust crate that defines core interfaces for a Rank-1 Constraint System (R1CS)
* [`r1cs-std`](r1cs-std): Rust crate that provides various gadgets used to construct R1CS
* [`gm17`](gm17): Rust crate that implements the zkSNARK of [Groth and Maller][GM17]
* [`groth16`](groth16): Rust crate that implements the zkSNARK of [Groth][Groth16]
In addition, there is a [`bench-utils`](bench-utils) crate which contains infrastructure for benchmarking. This crate includes macros for timing code segments and is used for profiling the building blocks of ZEXE.
[GM17]: https://ia.cr/2017/540
[Groth16]: https://ia.cr/2016/260
## Build guide
The library compiles on the `stable` toolchain of the Rust compiler. To install the latest version of Rust, first install `rustup` by following the instructions [here](https://rustup.rs/), or via your platform's package manager. Once `rustup` is installed, install the Rust toolchain by invoking:
@ -56,8 +22,7 @@ rustup install stable
After that, use `cargo`, the standard Rust build tool, to build the library:
```bash
git clone https://github.com/scipr-lab/zexe.git
cd zexe/dpc
git clone https://github.com/arkworks-rs/r1cs-std.git
cargo build --release
```
@ -66,44 +31,14 @@ This library comes with unit tests for each of the provided crates. Run the test
cargo test
```
This library comes with benchmarks for the following crates:
- [`algebra`](algebra)
- [`dpc`](dpc)
These benchmarks require the nightly Rust toolchain; to install this, run `rustup install nightly`. Then, to run benchmarks, run the following command:
```bash
cargo +nightly bench
```
Compiling with `adcxq`, `adoxq` and `mulxq` instructions can lead to a 30-70% speedup. These are available on most `x86_64` platforms (Broadwell onwards for Intel and Ryzen onwards for AMD). Run the following command:
```bash
RUSTFLAGS="-C target-feature=+bmi2,+adx" cargo +nightly test/build/bench --features asm
```
Tip: If optimising for performance, your mileage may vary with passing `--emit=asm` to `RUSTFLAGS`.
To bench `algebra-benches` with greater accuracy, especially for functions with execution times on the order of nanoseconds, use the `n_fold` feature to run selected functions 1000x per iteration. To run with multiple features, make sure to double quote the features.
```bash
cargo +nightly bench --features "n_fold bls12_381"
```
## License
ZEXE is licensed under either of the following licenses, at your discretion.
This library is licensed under either of the following licenses, at your discretion.
* 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)
Unless you explicitly state otherwise, any contribution submitted for inclusion in ZEXE by you shall be dual licensed as above (as defined in the Apache v2 License), without any additional terms or conditions.
[zexe]: https://ia.cr/2018/962
## Reference paper
[_ZEXE: Enabling Decentralized Private Computation_][zexe]
[Sean Bowe](https://www.github.com/ebfull), Alessandro Chiesa, Matthew Green, Ian Miers, [Pratyush Mishra](https://www.github.com/pratyush), [Howard Wu](https://www.github.com/howardwu)
*IEEE S&P 2020* (*IACR ePrint Report 2018/962*)
Unless you explicitly state otherwise, any contribution submitted for inclusion in this library by you shall be dual licensed as above (as defined in the Apache v2 License), without any additional terms or conditions.
## Acknowledgements
@ -113,4 +48,6 @@ the National Science Foundation;
the UC Berkeley Center for Long-Term Cybersecurity;
and donations from the Ethereum Foundation, the Interchain Foundation, and Qtum.
Some parts of the finite field arithmetic, elliptic curve arithmetic, FFTs, and multi-threading infrastructure in the `algebra` crate have been adapted from code in the [`ff`](https://github.com/zkcrypto/ff), [`pairing`](https://github.com/zkcrypto/pairing), and [`bellman`](https://github.com/zkcrypto/bellman) crates, developed by [Sean Bowe](https://www.github.com/ebfull) and others from Zcash.
An earlier version of this library was developed as part of the paper *"[ZEXE: Enabling Decentralized Private Computation][zexe]"*.
[zexe]: https://ia.cr/2018/962

+ 0
- 52
cp-benches/Cargo.toml

@ -1,52 +0,0 @@
[package]
name = "cp-benches"
version = "0.1.1-alpha.0"
authors = [
"Sean Bowe",
"Alessandro Chiesa",
"Matthew Green",
"Ian Miers",
"Pratyush Mishra",
"Howard Wu"
]
description = "A library of cryptographic primitives that are used by Zexe"
homepage = "https://libzexe.org"
repository = "https://github.com/scipr/zexe"
documentation = "https://docs.rs/crypto-primitives/"
keywords = ["r1cs", "groth16", "gm17", "pedersen", "blake2s"]
categories = ["cryptography"]
include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
license = "MIT/Apache-2.0"
edition = "2018"
################################# Dependencies ################################
[dev-dependencies]
algebra = { git = "https://github.com/scipr-lab/zexe/", default-features = false, features = [ "ed_on_bls12_377" ] }
blake2 = { version = "0.8", default-features = false }
criterion = "0.3.1"
crypto-primitives = { path = "../crypto-primitives" }
rand = { version = "0.7" }
rand_xorshift = { version = "0.2" }
################################# Benchmarks ##################################
[[bench]]
name = "pedersen_crh"
path = "benches/crypto_primitives/crh.rs"
harness = false
[[bench]]
name = "pedersen_comm"
path = "benches/crypto_primitives/comm.rs"
harness = false
[[bench]]
name = "blake2s_prf"
path = "benches/crypto_primitives/prf.rs"
harness = false
[[bench]]
name = "schnorr_sig"
path = "benches/crypto_primitives/signature.rs"
harness = false

+ 0
- 53
cp-benches/benches/crypto_primitives/comm.rs

@ -1,53 +0,0 @@
use rand;
#[macro_use]
extern crate criterion;
use algebra::{ed_on_bls12_377::EdwardsProjective as Edwards, UniformRand};
use criterion::Criterion;
use crypto_primitives::commitment::{pedersen::*, CommitmentScheme};
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct CommWindow;
impl Window for CommWindow {
const WINDOW_SIZE: usize = 250;
const NUM_WINDOWS: usize = 8;
}
fn pedersen_comm_setup(c: &mut Criterion) {
c.bench_function("Pedersen Commitment Setup", move |b| {
b.iter(|| {
let mut rng = &mut rand::thread_rng();
Commitment::<Edwards, CommWindow>::setup(&mut rng).unwrap()
})
});
}
fn pedersen_comm_eval(c: &mut Criterion) {
let mut rng = &mut rand::thread_rng();
let parameters = Commitment::<Edwards, CommWindow>::setup(&mut rng).unwrap();
let input = vec![5u8; 128];
c.bench_function("Pedersen Commitment Eval", move |b| {
b.iter(|| {
let rng = &mut rand::thread_rng();
let commitment_randomness = Randomness::rand(rng);
Commitment::<Edwards, CommWindow>::commit(&parameters, &input, &commitment_randomness)
.unwrap()
})
});
}
criterion_group! {
name = comm_setup;
config = Criterion::default().sample_size(10);
targets = pedersen_comm_setup
}
criterion_group! {
name = comm_eval;
config = Criterion::default().sample_size(10);
targets = pedersen_comm_eval
}
criterion_main!(comm_setup, comm_eval);

+ 0
- 48
cp-benches/benches/crypto_primitives/crh.rs

@ -1,48 +0,0 @@
use rand;
#[macro_use]
extern crate criterion;
use algebra::ed_on_bls12_377::EdwardsProjective as Edwards;
use criterion::Criterion;
use crypto_primitives::crh::{pedersen::*, FixedLengthCRH};
#[derive(Clone, PartialEq, Eq, Hash)]
pub struct HashWindow;
impl Window for HashWindow {
const WINDOW_SIZE: usize = 250;
const NUM_WINDOWS: usize = 8;
}
fn pedersen_crh_setup(c: &mut Criterion) {
c.bench_function("Pedersen CRH Setup", move |b| {
b.iter(|| {
let mut rng = &mut rand::thread_rng();
CRH::<Edwards, HashWindow>::setup(&mut rng).unwrap()
})
});
}
fn pedersen_crh_eval(c: &mut Criterion) {
let mut rng = &mut rand::thread_rng();
let parameters = CRH::<Edwards, HashWindow>::setup(&mut rng).unwrap();
let input = vec![5u8; 128];
c.bench_function("Pedersen CRH Eval", move |b| {
b.iter(|| CRH::<Edwards, HashWindow>::evaluate(&parameters, &input).unwrap())
});
}
criterion_group! {
name = crh_setup;
config = Criterion::default().sample_size(10);
targets = pedersen_crh_setup
}
criterion_group! {
name = crh_eval;
config = Criterion::default().sample_size(10);
targets = pedersen_crh_eval
}
criterion_main!(crh_setup, crh_eval);

+ 0
- 25
cp-benches/benches/crypto_primitives/prf.rs

@ -1,25 +0,0 @@
use rand;
#[macro_use]
extern crate criterion;
use criterion::Criterion;
use crypto_primitives::prf::*;
use rand::Rng;
fn blake2s_prf_eval(c: &mut Criterion) {
let rng = &mut rand::thread_rng();
let input: [u8; 32] = rng.gen();
let seed: [u8; 32] = rng.gen();
c.bench_function("Blake2s PRF Eval", move |b| {
b.iter(|| Blake2s::evaluate(&seed, &input).unwrap())
});
}
criterion_group! {
name = prf_eval;
config = Criterion::default().sample_size(50);
targets = blake2s_prf_eval
}
criterion_main!(prf_eval);

+ 0
- 89
cp-benches/benches/crypto_primitives/signature.rs

@ -1,89 +0,0 @@
#[macro_use]
extern crate criterion;
use algebra::ed_on_bls12_377::EdwardsProjective as Edwards;
use blake2::Blake2s;
use criterion::Criterion;
use crypto_primitives::signature::{schnorr::*, SignatureScheme};
use rand::{self, Rng};
type SchnorrEdwards = Schnorr<Edwards, Blake2s>;
fn schnorr_signature_setup(c: &mut Criterion) {
c.bench_function("SchnorrEdwards: Setup", move |b| {
b.iter(|| {
let mut rng = &mut rand::thread_rng();
SchnorrEdwards::setup(&mut rng).unwrap()
})
});
}
fn schnorr_signature_keygen(c: &mut Criterion) {
let mut rng = &mut rand::thread_rng();
let parameters = SchnorrEdwards::setup(&mut rng).unwrap();
c.bench_function("SchnorrEdwards: KeyGen", move |b| {
b.iter(|| {
let mut rng = &mut rand::thread_rng();
SchnorrEdwards::keygen(&parameters, &mut rng).unwrap()
})
});
}
fn schnorr_signature_sign(c: &mut Criterion) {
let mut rng = &mut rand::thread_rng();
let parameters = SchnorrEdwards::setup(&mut rng).unwrap();
let (_, sk) = SchnorrEdwards::keygen(&parameters, &mut rng).unwrap();
let message = [100u8; 128];
c.bench_function("SchnorrEdwards: Sign", move |b| {
b.iter(|| {
let mut rng = &mut rand::thread_rng();
SchnorrEdwards::sign(&parameters, &sk, &message, &mut rng).unwrap()
})
});
}
fn schnorr_signature_verify(c: &mut Criterion) {
let mut rng = &mut rand::thread_rng();
let parameters = SchnorrEdwards::setup(&mut rng).unwrap();
let (pk, sk) = SchnorrEdwards::keygen(&parameters, &mut rng).unwrap();
let message = [100u8; 128];
let signature = SchnorrEdwards::sign(&parameters, &sk, &message, &mut rng).unwrap();
c.bench_function("SchnorrEdwards: Verify", move |b| {
b.iter(|| SchnorrEdwards::verify(&parameters, &pk, &message, &signature).unwrap())
});
}
fn schnorr_signature_randomize_pk(c: &mut Criterion) {
let mut rng = &mut rand::thread_rng();
let parameters = SchnorrEdwards::setup(&mut rng).unwrap();
let (pk, _) = SchnorrEdwards::keygen(&parameters, &mut rng).unwrap();
let randomness: [u8; 32] = rng.gen();
c.bench_function("SchnorrEdwards: Randomize PubKey", move |b| {
b.iter(|| SchnorrEdwards::randomize_public_key(&parameters, &pk, &randomness).unwrap())
});
}
fn schnorr_signature_randomize_signature(c: &mut Criterion) {
let mut rng = &mut rand::thread_rng();
let parameters = SchnorrEdwards::setup(&mut rng).unwrap();
let (_, sk) = SchnorrEdwards::keygen(&parameters, &mut rng).unwrap();
let randomness: [u8; 32] = rng.gen();
let message = [100u8; 128];
let signature = SchnorrEdwards::sign(&parameters, &sk, &message, &mut rng).unwrap();
c.bench_function("SchnorrEdwards: Randomize Signature", move |b| {
b.iter(|| {
SchnorrEdwards::randomize_signature(&parameters, &signature, &randomness).unwrap()
})
});
}
criterion_group! {
name = schnorr_sig;
config = Criterion::default().sample_size(20);
targets = schnorr_signature_setup, schnorr_signature_keygen, schnorr_signature_sign,
schnorr_signature_verify, schnorr_signature_randomize_pk, schnorr_signature_randomize_signature
}
criterion_main!(schnorr_sig);

+ 0
- 52
crypto-primitives/Cargo.toml

@ -1,52 +0,0 @@
[package]
name = "crypto-primitives"
version = "0.1.1-alpha.0"
authors = [
"Sean Bowe",
"Alessandro Chiesa",
"Matthew Green",
"Ian Miers",
"Pratyush Mishra",
"Howard Wu"
]
description = "A library of cryptographic primitives that are used by Zexe"
homepage = "https://libzexe.org"
repository = "https://github.com/scipr/zexe"
documentation = "https://docs.rs/crypto-primitives/"
keywords = ["r1cs", "groth16", "gm17", "pedersen", "blake2s"]
categories = ["cryptography"]
include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
license = "MIT/Apache-2.0"
edition = "2018"
################################# Dependencies ################################
[dependencies]
algebra-core = { git = "https://github.com/scipr-lab/zexe", default-features = false }
bench-utils = { git = "https://github.com/scipr-lab/zexe" }
blake2 = { version = "0.8", default-features = false }
digest = "0.8"
ff-fft = { git = "https://github.com/scipr-lab/zexe", default-features = false }
gm17 = { git = "https://github.com/scipr-lab/zexe", optional = true, default-features = false }
groth16 = { git = "https://github.com/scipr-lab/zexe", optional = true, default-features = false }
r1cs-core = { git = "https://github.com/scipr-lab/zexe", optional = true, default-features = false }
r1cs-std = { path = "../r1cs-std", optional = true, default-features = false }
rand = { version = "0.7", default-features = false }
rayon = { version = "1.0", optional = true }
derivative = { version = "2.0", features = ["use_core"] }
tracing = { version = "0.1", default-features = false, features = [ "attributes" ] }
[features]
default = ["std", "r1cs"]
r1cs = ["r1cs-core", "r1cs-std"]
std = [ "algebra-core/std", "r1cs-core/std", "r1cs-std/std"]
parallel = ["std", "rayon", "gm17/parallel", "groth16/parallel", "ff-fft/parallel"]
[dev-dependencies]
algebra = { git = "https://github.com/scipr-lab/zexe", default-features = false, features = [ "ed_on_bls12_381", "bls12_377", "mnt4_298", "mnt6_298" ] }
r1cs-std = { path = "../r1cs-std", default-features = false, features = [ "ed_on_bls12_381", "bls12_377", "mnt4_298", "mnt6_298" ] }
rand_xorshift = { version = "0.2" }

+ 0
- 1
crypto-primitives/LICENSE-APACHE

@ -1 +0,0 @@
../LICENSE-APACHE

+ 0
- 1
crypto-primitives/LICENSE-MIT

@ -1 +0,0 @@
../LICENSE-MIT

+ 0
- 133
crypto-primitives/src/commitment/blake2s/constraints.rs

@ -1,133 +0,0 @@
use r1cs_core::{Namespace, SynthesisError};
use crate::{
commitment::blake2s,
commitment::CommitmentGadget,
prf::blake2s::constraints::{evaluate_blake2s, OutputVar},
Vec,
};
use algebra_core::{Field, PrimeField};
use r1cs_std::prelude::*;
use core::borrow::Borrow;
#[derive(Clone)]
pub struct ParametersVar;
#[derive(Clone)]
pub struct RandomnessVar<F: Field>(pub Vec<UInt8<F>>);
pub struct CommGadget;
impl<F: PrimeField> CommitmentGadget<blake2s::Commitment, F> for CommGadget {
type OutputVar = OutputVar<F>;
type ParametersVar = ParametersVar;
type RandomnessVar = RandomnessVar<F>;
#[tracing::instrument(target = "r1cs", skip(input, r))]
fn commit(
_: &Self::ParametersVar,
input: &[UInt8<F>],
r: &Self::RandomnessVar,
) -> Result<Self::OutputVar, SynthesisError> {
let mut input_bits = Vec::with_capacity(512);
for byte in input.iter().chain(r.0.iter()) {
input_bits.extend_from_slice(&byte.to_bits_le()?);
}
let mut result = Vec::new();
for int in evaluate_blake2s(&input_bits)?.into_iter() {
let chunk = int.to_bytes()?;
result.extend_from_slice(&chunk);
}
Ok(OutputVar(result))
}
}
impl<ConstraintF: Field> AllocVar<(), ConstraintF> for ParametersVar {
#[tracing::instrument(target = "r1cs", skip(_cs, _f))]
fn new_variable<T: Borrow<()>>(
_cs: impl Into<Namespace<ConstraintF>>,
_f: impl FnOnce() -> Result<T, SynthesisError>,
_mode: AllocationMode,
) -> Result<Self, SynthesisError> {
Ok(ParametersVar)
}
}
impl<ConstraintF: PrimeField> AllocVar<[u8; 32], ConstraintF> for RandomnessVar<ConstraintF> {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<[u8; 32]>>(
cs: impl Into<Namespace<ConstraintF>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let bytes = f().map(|b| *b.borrow()).unwrap_or([0u8; 32]);
match mode {
AllocationMode::Constant => Ok(Self(UInt8::constant_vec(&bytes))),
AllocationMode::Input => UInt8::new_input_vec(cs, &bytes).map(Self),
AllocationMode::Witness => UInt8::new_witness_vec(cs, &bytes).map(Self),
}
}
}
#[cfg(test)]
mod test {
use crate::{
commitment::blake2s::{
constraints::{CommGadget, RandomnessVar},
Commitment,
},
commitment::{CommitmentGadget, CommitmentScheme},
};
use algebra::{ed_on_bls12_381::Fq as Fr, test_rng};
use r1cs_core::ConstraintSystem;
use r1cs_std::prelude::*;
use rand::Rng;
#[test]
fn commitment_gadget_test() {
let cs = ConstraintSystem::<Fr>::new_ref();
let input = [1u8; 32];
let rng = &mut test_rng();
type TestCOMM = Commitment;
type TestCOMMGadget = CommGadget;
let mut randomness = [0u8; 32];
rng.fill(&mut randomness);
let parameters = ();
let primitive_result = Commitment::commit(&parameters, &input, &randomness).unwrap();
let mut input_var = vec![];
for byte in &input {
input_var.push(UInt8::new_witness(cs.clone(), || Ok(*byte)).unwrap());
}
let mut randomness_var = vec![];
for r_byte in randomness.iter() {
randomness_var.push(UInt8::new_witness(cs.clone(), || Ok(r_byte)).unwrap());
}
let randomness_var = RandomnessVar(randomness_var);
let parameters_var =
<TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::ParametersVar::new_witness(
r1cs_core::ns!(cs, "gadget_parameters"),
|| Ok(&parameters),
)
.unwrap();
let result_var = <TestCOMMGadget as CommitmentGadget<TestCOMM, Fr>>::commit(
&parameters_var,
&input_var,
&randomness_var,
)
.unwrap();
for i in 0..32 {
assert_eq!(primitive_result[i], result_var.0[i].value().unwrap());
}
assert!(cs.is_satisfied().unwrap());
}
}

+ 0
- 33
crypto-primitives/src/commitment/blake2s/mod.rs

@ -1,33 +0,0 @@
use super::CommitmentScheme;
use crate::Error;
use blake2::Blake2s as b2s;
use digest::Digest;
use rand::Rng;
pub struct Commitment;
#[cfg(feature = "r1cs")]
pub mod constraints;
impl CommitmentScheme for Commitment {
type Parameters = ();
type Randomness = [u8; 32];
type Output = [u8; 32];
fn setup<R: Rng>(_: &mut R) -> Result<Self::Parameters, Error> {
Ok(())
}
fn commit(
_: &Self::Parameters,
input: &[u8],
r: &Self::Randomness,
) -> Result<Self::Output, Error> {
let mut h = b2s::new();
h.input(input);
h.input(r.as_ref());
let mut result = [0u8; 32];
result.copy_from_slice(&h.result());
Ok(result)
}
}

+ 0
- 23
crypto-primitives/src/commitment/constraints.rs

@ -1,23 +0,0 @@
use crate::commitment::CommitmentScheme;
use algebra_core::Field;
use core::fmt::Debug;
use r1cs_core::SynthesisError;
use r1cs_std::prelude::*;
pub trait CommitmentGadget<C: CommitmentScheme, ConstraintF: Field> {
type OutputVar: EqGadget<ConstraintF>
+ ToBytesGadget<ConstraintF>
+ AllocVar<C::Output, ConstraintF>
+ R1CSVar<ConstraintF>
+ Clone
+ Sized
+ Debug;
type ParametersVar: AllocVar<C::Parameters, ConstraintF> + Clone;
type RandomnessVar: AllocVar<C::Randomness, ConstraintF> + Clone;
fn commit(
parameters: &Self::ParametersVar,
input: &[UInt8<ConstraintF>],
r: &Self::RandomnessVar,
) -> Result<Self::OutputVar, SynthesisError>;
}

+ 0
- 59
crypto-primitives/src/commitment/injective_map/constraints.rs

@ -1,59 +0,0 @@
use crate::commitment::{
injective_map::{InjectiveMap, PedersenCommCompressor},
pedersen::{
constraints::{CommGadget, ParametersVar, RandomnessVar},
Window,
},
};
pub use crate::crh::injective_map::constraints::InjectiveMapGadget;
use algebra_core::{Field, PrimeField, ProjectiveCurve};
use r1cs_core::SynthesisError;
use r1cs_std::{
groups::{CurveVar, GroupOpsBounds},
uint8::UInt8,
};
use core::marker::PhantomData;
type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField;
pub struct CommitmentCompressorGadget<C, I, W, GG, IG>
where
C: ProjectiveCurve,
I: InjectiveMap<C>,
W: Window,
GG: CurveVar<C, ConstraintF<C>>,
IG: InjectiveMapGadget<C, I, GG>,
for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
{
_compressor: PhantomData<I>,
_compressor_gadget: PhantomData<IG>,
_comm: PhantomData<CommGadget<C, GG, W>>,
}
impl<C, I, GG, IG, W>
crate::commitment::CommitmentGadget<PedersenCommCompressor<C, I, W>, ConstraintF<C>>
for CommitmentCompressorGadget<C, I, W, GG, IG>
where
C: ProjectiveCurve,
I: InjectiveMap<C>,
GG: CurveVar<C, ConstraintF<C>>,
ConstraintF<C>: PrimeField,
IG: InjectiveMapGadget<C, I, GG>,
W: Window,
for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
{
type OutputVar = IG::OutputVar;
type ParametersVar = ParametersVar<C, GG>;
type RandomnessVar = RandomnessVar<ConstraintF<C>>;
fn commit(
parameters: &Self::ParametersVar,
input: &[UInt8<ConstraintF<C>>],
r: &Self::RandomnessVar,
) -> Result<Self::OutputVar, SynthesisError> {
let result = CommGadget::<C, GG, W>::commit(parameters, input, r)?;
IG::evaluate(&result)
}
}

+ 0
- 44
crypto-primitives/src/commitment/injective_map/mod.rs

@ -1,44 +0,0 @@
use crate::Error;
use core::marker::PhantomData;
use rand::Rng;
use super::{pedersen, CommitmentScheme};
pub use crate::crh::injective_map::InjectiveMap;
use algebra_core::ProjectiveCurve;
#[cfg(feature = "r1cs")]
pub mod constraints;
pub struct PedersenCommCompressor<C: ProjectiveCurve, I: InjectiveMap<C>, W: pedersen::Window> {
_group: PhantomData<C>,
_compressor: PhantomData<I>,
_comm: pedersen::Commitment<C, W>,
}
impl<C: ProjectiveCurve, I: InjectiveMap<C>, W: pedersen::Window> CommitmentScheme
for PedersenCommCompressor<C, I, W>
{
type Output = I::Output;
type Parameters = pedersen::Parameters<C>;
type Randomness = pedersen::Randomness<C>;
fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> {
let time = start_timer!(|| format!("PedersenCompressor::Setup"));
let params = pedersen::Commitment::<C, W>::setup(rng);
end_timer!(time);
params
}
fn commit(
parameters: &Self::Parameters,
input: &[u8],
randomness: &Self::Randomness,
) -> Result<Self::Output, Error> {
let eval_time = start_timer!(|| "PedersenCompressor::Eval");
let result = I::injective_map(&pedersen::Commitment::<C, W>::commit(
parameters, input, randomness,
)?)?;
end_timer!(eval_time);
Ok(result)
}
}

+ 0
- 30
crypto-primitives/src/commitment/mod.rs

@ -1,30 +0,0 @@
use algebra_core::UniformRand;
use core::{fmt::Debug, hash::Hash};
use rand::Rng;
use algebra_core::bytes::ToBytes;
pub mod blake2s;
pub mod injective_map;
pub mod pedersen;
#[cfg(feature = "r1cs")]
pub mod constraints;
#[cfg(feature = "r1cs")]
pub use constraints::*;
use crate::Error;
pub trait CommitmentScheme {
type Output: ToBytes + Clone + Default + Eq + Hash + Debug;
type Parameters: Clone;
type Randomness: Clone + ToBytes + Default + Eq + UniformRand + Debug;
fn setup<R: Rng>(r: &mut R) -> Result<Self::Parameters, Error>;
fn commit(
parameters: &Self::Parameters,
input: &[u8],
r: &Self::Randomness,
) -> Result<Self::Output, Error>;
}

+ 0
- 204
crypto-primitives/src/commitment/pedersen/constraints.rs

@ -1,204 +0,0 @@
use crate::{
commitment::pedersen::{Commitment, Parameters, Randomness},
crh::pedersen::Window,
Vec,
};
use algebra_core::{
fields::{Field, PrimeField},
to_bytes, ProjectiveCurve, Zero,
};
use r1cs_core::{Namespace, SynthesisError};
use core::{borrow::Borrow, marker::PhantomData};
use r1cs_std::prelude::*;
type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField;
#[derive(Derivative)]
#[derivative(Clone(bound = "C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>"))]
pub struct ParametersVar<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>>
where
for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
{
params: Parameters<C>,
#[doc(hidden)]
_group_var: PhantomData<GG>,
}
#[derive(Clone, Debug)]
pub struct RandomnessVar<F: Field>(Vec<UInt8<F>>);
pub struct CommGadget<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>, W: Window>
where
for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
{
#[doc(hidden)]
_curve: PhantomData<*const C>,
#[doc(hidden)]
_group_var: PhantomData<*const GG>,
#[doc(hidden)]
_window: PhantomData<*const W>,
}
impl<C, GG, W> crate::commitment::CommitmentGadget<Commitment<C, W>, ConstraintF<C>>
for CommGadget<C, GG, W>
where
C: ProjectiveCurve,
GG: CurveVar<C, ConstraintF<C>>,
W: Window,
for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
ConstraintF<C>: PrimeField,
{
type OutputVar = GG;
type ParametersVar = ParametersVar<C, GG>;
type RandomnessVar = RandomnessVar<ConstraintF<C>>;
#[tracing::instrument(target = "r1cs", skip(parameters, r))]
fn commit(
parameters: &Self::ParametersVar,
input: &[UInt8<ConstraintF<C>>],
r: &Self::RandomnessVar,
) -> Result<Self::OutputVar, SynthesisError> {
assert!((input.len() * 8) <= (W::WINDOW_SIZE * W::NUM_WINDOWS));
let mut padded_input = input.to_vec();
// Pad if input length is less than `W::WINDOW_SIZE * W::NUM_WINDOWS`.
if (input.len() * 8) < W::WINDOW_SIZE * W::NUM_WINDOWS {
let current_length = input.len();
for _ in current_length..((W::WINDOW_SIZE * W::NUM_WINDOWS) / 8) {
padded_input.push(UInt8::constant(0u8));
}
}
assert_eq!(padded_input.len() * 8, W::WINDOW_SIZE * W::NUM_WINDOWS);
assert_eq!(parameters.params.generators.len(), W::NUM_WINDOWS);
// Allocate new variable for commitment output.
let input_in_bits: Vec<Boolean<_>> = padded_input
.iter()
.flat_map(|byte| byte.to_bits_le().unwrap())
.collect();
let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE);
let mut result =
GG::precomputed_base_multiscalar_mul_le(&parameters.params.generators, input_in_bits)?;
// Compute h^r
let rand_bits: Vec<_> =
r.0.iter()
.flat_map(|byte| byte.to_bits_le().unwrap())
.collect();
result.precomputed_base_scalar_mul_le(
rand_bits
.iter()
.zip(&parameters.params.randomness_generator),
)?;
Ok(result)
}
}
impl<C, GG> AllocVar<Parameters<C>, ConstraintF<C>> for ParametersVar<C, GG>
where
C: ProjectiveCurve,
GG: CurveVar<C, ConstraintF<C>>,
for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
{
fn new_variable<T: Borrow<Parameters<C>>>(
_cs: impl Into<Namespace<ConstraintF<C>>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
_mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let params = f()?.borrow().clone();
Ok(ParametersVar {
params,
_group_var: PhantomData,
})
}
}
impl<C, F> AllocVar<Randomness<C>, F> for RandomnessVar<F>
where
C: ProjectiveCurve,
F: PrimeField,
{
fn new_variable<T: Borrow<Randomness<C>>>(
cs: impl Into<Namespace<F>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let r = to_bytes![&f().map(|b| b.borrow().0).unwrap_or(C::ScalarField::zero())].unwrap();
match mode {
AllocationMode::Constant => Ok(Self(UInt8::constant_vec(&r))),
AllocationMode::Input => UInt8::new_input_vec(cs, &r).map(Self),
AllocationMode::Witness => UInt8::new_witness_vec(cs, &r).map(Self),
}
}
}
#[cfg(test)]
mod test {
use algebra::{
ed_on_bls12_381::{EdwardsProjective as JubJub, Fq, Fr},
test_rng, UniformRand,
};
use crate::{
commitment::{
pedersen::{constraints::CommGadget, Commitment, Randomness},
CommitmentGadget, CommitmentScheme,
},
crh::pedersen,
};
use r1cs_core::ConstraintSystem;
use r1cs_std::{ed_on_bls12_381::EdwardsVar, prelude::*};
#[test]
fn commitment_gadget_test() {
let cs = ConstraintSystem::<Fq>::new_ref();
#[derive(Clone, PartialEq, Eq, Hash)]
pub(super) struct Window;
impl pedersen::Window for Window {
const WINDOW_SIZE: usize = 4;
const NUM_WINDOWS: usize = 8;
}
let input = [1u8; 4];
let rng = &mut test_rng();
type TestCOMM = Commitment<JubJub, Window>;
type TestCOMMGadget = CommGadget<JubJub, EdwardsVar, Window>;
let randomness = Randomness(Fr::rand(rng));
let parameters = Commitment::<JubJub, Window>::setup(rng).unwrap();
let primitive_result =
Commitment::<JubJub, Window>::commit(&parameters, &input, &randomness).unwrap();
let mut input_var = vec![];
for input_byte in input.iter() {
input_var.push(UInt8::new_witness(cs.clone(), || Ok(*input_byte)).unwrap());
}
let randomness_var =
<TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::RandomnessVar::new_witness(
r1cs_core::ns!(cs, "gadget_randomness"),
|| Ok(&randomness),
)
.unwrap();
let parameters_var =
<TestCOMMGadget as CommitmentGadget<TestCOMM, Fq>>::ParametersVar::new_witness(
r1cs_core::ns!(cs, "gadget_parameters"),
|| Ok(&parameters),
)
.unwrap();
let result_var =
TestCOMMGadget::commit(&parameters_var, &input_var, &randomness_var).unwrap();
let primitive_result = primitive_result;
assert_eq!(primitive_result, result_var.value().unwrap());
assert!(cs.is_satisfied().unwrap());
}
}

+ 0
- 125
crypto-primitives/src/commitment/pedersen/mod.rs

@ -1,125 +0,0 @@
use crate::{Error, Vec};
use algebra_core::{
bytes::ToBytes,
io::{Result as IoResult, Write},
BitIteratorLE, Field, FpParameters, PrimeField, ProjectiveCurve, ToConstraintField,
UniformRand,
};
use core::marker::PhantomData;
use rand::Rng;
use super::CommitmentScheme;
pub use crate::crh::pedersen::Window;
use crate::crh::{pedersen, FixedLengthCRH};
#[cfg(feature = "r1cs")]
pub mod constraints;
#[derive(Clone)]
pub struct Parameters<C: ProjectiveCurve> {
pub randomness_generator: Vec<C>,
pub generators: Vec<Vec<C>>,
}
pub struct Commitment<C: ProjectiveCurve, W: Window> {
group: PhantomData<C>,
window: PhantomData<W>,
}
#[derive(Derivative)]
#[derivative(Clone, PartialEq, Debug, Eq, Default)]
pub struct Randomness<C: ProjectiveCurve>(pub C::ScalarField);
impl<C: ProjectiveCurve> UniformRand for Randomness<C> {
#[inline]
fn rand<R: Rng + ?Sized>(rng: &mut R) -> Self {
Randomness(UniformRand::rand(rng))
}
}
impl<C: ProjectiveCurve> ToBytes for Randomness<C> {
fn write<W: Write>(&self, writer: W) -> IoResult<()> {
self.0.write(writer)
}
}
impl<C: ProjectiveCurve, W: Window> CommitmentScheme for Commitment<C, W> {
type Parameters = Parameters<C>;
type Randomness = Randomness<C>;
type Output = C::Affine;
fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> {
let time = start_timer!(|| format!(
"PedersenCOMM::Setup: {} {}-bit windows; {{0,1}}^{{{}}} -> C",
W::NUM_WINDOWS,
W::WINDOW_SIZE,
W::NUM_WINDOWS * W::WINDOW_SIZE
));
let num_powers = <C::ScalarField as PrimeField>::Params::MODULUS_BITS as usize;
let randomness_generator = pedersen::CRH::<C, W>::generator_powers(num_powers, rng);
let generators = pedersen::CRH::<C, W>::create_generators(rng);
end_timer!(time);
Ok(Self::Parameters {
randomness_generator,
generators,
})
}
fn commit(
parameters: &Self::Parameters,
input: &[u8],
randomness: &Self::Randomness,
) -> Result<Self::Output, Error> {
let commit_time = start_timer!(|| "PedersenCOMM::Commit");
// If the input is too long, return an error.
if input.len() > W::WINDOW_SIZE * W::NUM_WINDOWS {
panic!("incorrect input length: {:?}", input.len());
}
// Pad the input to the necessary length.
let mut padded_input = Vec::with_capacity(input.len());
let mut input = input;
if (input.len() * 8) < W::WINDOW_SIZE * W::NUM_WINDOWS {
let current_length = input.len();
padded_input.extend_from_slice(input);
for _ in current_length..((W::WINDOW_SIZE * W::NUM_WINDOWS) / 8) {
padded_input.push(0u8);
}
input = padded_input.as_slice();
}
assert_eq!(parameters.generators.len(), W::NUM_WINDOWS);
// Invoke Pedersen CRH here, to prevent code duplication.
let crh_parameters = pedersen::Parameters {
generators: parameters.generators.clone(),
};
let mut result: C = pedersen::CRH::<C, W>::evaluate(&crh_parameters, &input)?.into();
let randomize_time = start_timer!(|| "Randomize");
// Compute h^r.
for (bit, power) in BitIteratorLE::new(randomness.0.into_repr())
.into_iter()
.zip(&parameters.randomness_generator)
{
if bit {
result += power
}
}
end_timer!(randomize_time);
end_timer!(commit_time);
Ok(result.into())
}
}
impl<ConstraintF: Field, C: ProjectiveCurve + ToConstraintField<ConstraintF>>
ToConstraintField<ConstraintF> for Parameters<C>
{
#[inline]
fn to_field_elements(&self) -> Result<Vec<ConstraintF>, Error> {
Ok(Vec::new())
}
}

+ 0
- 180
crypto-primitives/src/crh/bowe_hopwood/constraints.rs

@ -1,180 +0,0 @@
use core::{borrow::Borrow, marker::PhantomData};
use crate::{
crh::{
bowe_hopwood::{Parameters, CHUNK_SIZE, CRH},
pedersen::Window,
FixedLengthCRHGadget,
},
Vec,
};
use algebra_core::{
curves::{ModelParameters, TEModelParameters},
Field,
};
use r1cs_core::{Namespace, SynthesisError};
use r1cs_std::{
alloc::AllocVar, groups::curves::twisted_edwards::AffineVar, prelude::*, uint8::UInt8,
};
use r1cs_std::bits::boolean::Boolean;
type ConstraintF<P> = <<P as ModelParameters>::BaseField as Field>::BasePrimeField;
#[derive(Derivative)]
#[derivative(Clone(bound = "P: TEModelParameters, W: Window"))]
pub struct ParametersVar<P: TEModelParameters, W: Window> {
params: Parameters<P>,
#[doc(hidden)]
_window: PhantomData<W>,
}
pub struct CRHGadget<P: TEModelParameters, F: FieldVar<P::BaseField, ConstraintF<P>>>
where
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
{
#[doc(hidden)]
_params: PhantomData<P>,
#[doc(hidden)]
_base_field: PhantomData<F>,
}
impl<P, F, W> FixedLengthCRHGadget<CRH<P, W>, ConstraintF<P>> for CRHGadget<P, F>
where
for<'a> &'a F: FieldOpsBounds<'a, P::BaseField, F>,
F: FieldVar<P::BaseField, ConstraintF<P>>,
F: TwoBitLookupGadget<ConstraintF<P>, TableConstant = P::BaseField>
+ ThreeBitCondNegLookupGadget<ConstraintF<P>, TableConstant = P::BaseField>,
P: TEModelParameters,
W: Window,
{
type OutputVar = AffineVar<P, F>;
type ParametersVar = ParametersVar<P, W>;
#[tracing::instrument(target = "r1cs", skip(parameters, input))]
fn evaluate(
parameters: &Self::ParametersVar,
input: &[UInt8<ConstraintF<P>>],
) -> Result<Self::OutputVar, SynthesisError> {
// Pad the input if it is not the current length.
let mut input_in_bits: Vec<Boolean<_>> = input
.iter()
.flat_map(|byte| byte.to_bits_le().unwrap())
.collect();
if (input_in_bits.len()) % CHUNK_SIZE != 0 {
let current_length = input_in_bits.len();
for _ in 0..(CHUNK_SIZE - current_length % CHUNK_SIZE) {
input_in_bits.push(Boolean::constant(false));
}
}
assert!(input_in_bits.len() % CHUNK_SIZE == 0);
assert_eq!(parameters.params.generators.len(), W::NUM_WINDOWS);
for generators in parameters.params.generators.iter() {
assert_eq!(generators.len(), W::WINDOW_SIZE);
}
// Allocate new variable for the result.
let input_in_bits = input_in_bits
.chunks(W::WINDOW_SIZE * CHUNK_SIZE)
.map(|x| x.chunks(CHUNK_SIZE).collect::<Vec<_>>())
.collect::<Vec<_>>();
let result = AffineVar::precomputed_base_3_bit_signed_digit_scalar_mul(
&parameters.params.generators,
&input_in_bits,
)?;
Ok(result)
}
}
impl<P, W> AllocVar<Parameters<P>, ConstraintF<P>> for ParametersVar<P, W>
where
P: TEModelParameters,
W: Window,
{
#[tracing::instrument(target = "r1cs", skip(_cs, f))]
fn new_variable<T: Borrow<Parameters<P>>>(
_cs: impl Into<Namespace<ConstraintF<P>>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
_mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let params = f()?.borrow().clone();
Ok(ParametersVar {
params,
_window: PhantomData,
})
}
}
#[cfg(test)]
mod test {
use rand::Rng;
use crate::crh::{
bowe_hopwood::{constraints::CRHGadget, CRH},
pedersen::Window as PedersenWindow,
FixedLengthCRH, FixedLengthCRHGadget,
};
use algebra::{
ed_on_bls12_381::{EdwardsParameters, Fq as Fr},
test_rng, ProjectiveCurve,
};
use r1cs_core::{ConstraintSystem, ConstraintSystemRef};
use r1cs_std::{alloc::AllocVar, ed_on_bls12_381::FqVar, uint8::UInt8, R1CSVar};
type TestCRH = CRH<EdwardsParameters, Window>;
type TestCRHGadget = CRHGadget<EdwardsParameters, FqVar>;
#[derive(Clone, PartialEq, Eq, Hash)]
pub(super) struct Window;
impl PedersenWindow for Window {
const WINDOW_SIZE: usize = 63;
const NUM_WINDOWS: usize = 8;
}
fn generate_input<R: Rng>(
cs: ConstraintSystemRef<Fr>,
rng: &mut R,
) -> ([u8; 189], Vec<UInt8<Fr>>) {
let mut input = [1u8; 189];
rng.fill_bytes(&mut input);
let mut input_bytes = vec![];
for byte in input.iter() {
input_bytes.push(UInt8::new_witness(cs.clone(), || Ok(byte)).unwrap());
}
(input, input_bytes)
}
#[test]
fn test_native_equality() {
let rng = &mut test_rng();
let cs = ConstraintSystem::<Fr>::new_ref();
let (input, input_var) = generate_input(cs.clone(), rng);
println!("number of constraints for input: {}", cs.num_constraints());
let parameters = TestCRH::setup(rng).unwrap();
let primitive_result = TestCRH::evaluate(&parameters, &input).unwrap();
let parameters_var =
<TestCRHGadget as FixedLengthCRHGadget<TestCRH, Fr>>::ParametersVar::new_witness(
r1cs_core::ns!(cs, "parameters_var"),
|| Ok(&parameters),
)
.unwrap();
println!(
"number of constraints for input + params: {}",
cs.num_constraints()
);
let result_var = TestCRHGadget::evaluate(&parameters_var, &input_var).unwrap();
println!("number of constraints total: {}", cs.num_constraints());
let primitive_result = primitive_result.into_affine();
assert_eq!(primitive_result, result_var.value().unwrap().into_affine());
assert!(cs.is_satisfied().unwrap());
}
}

+ 0
- 197
crypto-primitives/src/crh/bowe_hopwood/mod.rs

@ -1,197 +0,0 @@
use crate::{Error, Vec};
use core::{
fmt::{Debug, Formatter, Result as FmtResult},
marker::PhantomData,
};
use rand::Rng;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
use super::pedersen;
use crate::crh::FixedLengthCRH;
use algebra_core::{
biginteger::BigInteger, curves::twisted_edwards_extended::GroupProjective as TEProjective,
fields::PrimeField, ProjectiveCurve, TEModelParameters, UniformRand,
};
use ff_fft::cfg_chunks;
#[cfg(feature = "r1cs")]
pub mod constraints;
pub const CHUNK_SIZE: usize = 3;
#[derive(Derivative)]
#[derivative(Clone(bound = ""), Default(bound = ""))]
pub struct Parameters<P: TEModelParameters> {
pub generators: Vec<Vec<TEProjective<P>>>,
}
pub struct CRH<P: TEModelParameters, W: pedersen::Window> {
group: PhantomData<P>,
window: PhantomData<W>,
}
impl<P: TEModelParameters, W: pedersen::Window> CRH<P, W> {
pub fn create_generators<R: Rng>(rng: &mut R) -> Vec<Vec<TEProjective<P>>> {
let mut generators = Vec::new();
for _ in 0..W::NUM_WINDOWS {
let mut generators_for_segment = Vec::new();
let mut base = TEProjective::rand(rng);
for _ in 0..W::WINDOW_SIZE {
generators_for_segment.push(base);
for _ in 0..4 {
base.double_in_place();
}
}
generators.push(generators_for_segment);
}
generators
}
}
impl<P: TEModelParameters, W: pedersen::Window> FixedLengthCRH for CRH<P, W> {
const INPUT_SIZE_BITS: usize = pedersen::CRH::<TEProjective<P>, W>::INPUT_SIZE_BITS;
type Output = TEProjective<P>;
type Parameters = Parameters<P>;
fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> {
fn calculate_num_chunks_in_segment<F: PrimeField>() -> usize {
let upper_limit = F::modulus_minus_one_div_two();
let mut c = 0;
let mut range = F::BigInt::from(2_u64);
while range < upper_limit {
range.muln(4);
c += 1;
}
c
}
let maximum_num_chunks_in_segment = calculate_num_chunks_in_segment::<P::ScalarField>();
if W::WINDOW_SIZE > maximum_num_chunks_in_segment {
return Err(format!(
"Bowe-Hopwood-PedersenCRH hash must have a window size resulting in scalars < (p-1)/2, \
maximum segment size is {}",
maximum_num_chunks_in_segment
)
.into());
}
let time = start_timer!(|| format!(
"Bowe-Hopwood-PedersenCRH::Setup: {} segments of {} 3-bit chunks; {{0,1}}^{{{}}} -> P",
W::NUM_WINDOWS,
W::WINDOW_SIZE,
W::WINDOW_SIZE * W::NUM_WINDOWS * CHUNK_SIZE
));
let generators = Self::create_generators(rng);
end_timer!(time);
Ok(Self::Parameters { generators })
}
fn evaluate(parameters: &Self::Parameters, input: &[u8]) -> Result<Self::Output, Error> {
let eval_time = start_timer!(|| "BoweHopwoodPedersenCRH::Eval");
if (input.len() * 8) > W::WINDOW_SIZE * W::NUM_WINDOWS * CHUNK_SIZE {
panic!(
"incorrect input length {:?} for window params {:?}x{:?}x{}",
input.len(),
W::WINDOW_SIZE,
W::NUM_WINDOWS,
CHUNK_SIZE,
);
}
let mut padded_input = Vec::with_capacity(input.len());
let input = pedersen::bytes_to_bits(input);
// Pad the input if it is not the current length.
padded_input.extend_from_slice(&input);
if input.len() % CHUNK_SIZE != 0 {
let current_length = input.len();
for _ in 0..(CHUNK_SIZE - current_length % CHUNK_SIZE) {
padded_input.push(false);
}
}
assert_eq!(padded_input.len() % CHUNK_SIZE, 0);
assert_eq!(
parameters.generators.len(),
W::NUM_WINDOWS,
"Incorrect pp of size {:?} for window params {:?}x{:?}x{}",
parameters.generators.len(),
W::WINDOW_SIZE,
W::NUM_WINDOWS,
CHUNK_SIZE,
);
for generators in parameters.generators.iter() {
assert_eq!(generators.len(), W::WINDOW_SIZE);
}
assert_eq!(CHUNK_SIZE, 3);
// Compute sum of h_i^{sum of
// (1-2*c_{i,j,2})*(1+c_{i,j,0}+2*c_{i,j,1})*2^{4*(j-1)} for all j in segment}
// for all i. Described in section 5.4.1.7 in the Zcash protocol
// specification.
let result = cfg_chunks!(padded_input, W::WINDOW_SIZE * CHUNK_SIZE)
.zip(&parameters.generators)
.map(|(segment_bits, segment_generators)| {
cfg_chunks!(segment_bits, CHUNK_SIZE)
.zip(segment_generators)
.map(|(chunk_bits, generator)| {
let mut encoded = generator.clone();
if chunk_bits[0] {
encoded = encoded + generator;
}
if chunk_bits[1] {
encoded += &generator.double();
}
if chunk_bits[2] {
encoded = -encoded;
}
encoded
})
.sum::<TEProjective<P>>()
})
.sum::<TEProjective<P>>();
end_timer!(eval_time);
Ok(result)
}
}
impl<P: TEModelParameters> Debug for Parameters<P> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "Bowe-Hopwood-Pedersen Hash Parameters {{\n")?;
for (i, g) in self.generators.iter().enumerate() {
write!(f, "\t Generator {}: {:?}\n", i, g)?;
}
write!(f, "}}\n")
}
}
#[cfg(test)]
mod test {
use crate::{
crh::{bowe_hopwood::CRH, pedersen::Window},
FixedLengthCRH,
};
use algebra::{ed_on_bls12_381::EdwardsParameters, test_rng};
#[test]
fn test_simple_bh() {
#[derive(Clone)]
struct TestWindow {}
impl Window for TestWindow {
const WINDOW_SIZE: usize = 63;
const NUM_WINDOWS: usize = 8;
}
let rng = &mut test_rng();
let params = <CRH<EdwardsParameters, TestWindow> as FixedLengthCRH>::setup(rng).unwrap();
let _ =
<CRH<EdwardsParameters, TestWindow> as FixedLengthCRH>::evaluate(&params, &[1, 2, 3])
.unwrap();
}
}

+ 0
- 25
crypto-primitives/src/crh/constraints.rs

@ -1,25 +0,0 @@
use algebra_core::Field;
use core::fmt::Debug;
use crate::crh::FixedLengthCRH;
use r1cs_core::SynthesisError;
use r1cs_std::prelude::*;
pub trait FixedLengthCRHGadget<H: FixedLengthCRH, ConstraintF: Field>: Sized {
type OutputVar: EqGadget<ConstraintF>
+ ToBytesGadget<ConstraintF>
+ CondSelectGadget<ConstraintF>
+ AllocVar<H::Output, ConstraintF>
+ R1CSVar<ConstraintF>
+ Debug
+ Clone
+ Sized;
type ParametersVar: AllocVar<H::Parameters, ConstraintF> + Clone;
fn evaluate(
parameters: &Self::ParametersVar,
input: &[UInt8<ConstraintF>],
) -> Result<Self::OutputVar, SynthesisError>;
}

+ 0
- 98
crypto-primitives/src/crh/injective_map/constraints.rs

@ -1,98 +0,0 @@
use core::{fmt::Debug, marker::PhantomData};
use crate::crh::{
injective_map::{InjectiveMap, PedersenCRHCompressor, TECompressor},
pedersen::{constraints as ped_constraints, Window},
FixedLengthCRHGadget,
};
use algebra_core::{
curves::{
models::{ModelParameters, TEModelParameters},
twisted_edwards_extended::GroupProjective as TEProjective,
},
fields::{Field, PrimeField, SquareRootField},
ProjectiveCurve,
};
use r1cs_core::SynthesisError;
use r1cs_std::{
fields::fp::FpVar,
groups::{curves::twisted_edwards::AffineVar as TEVar, CurveVar},
prelude::*,
};
type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField;
pub trait InjectiveMapGadget<
C: ProjectiveCurve,
I: InjectiveMap<C>,
GG: CurveVar<C, ConstraintF<C>>,
> where
for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
{
type OutputVar: EqGadget<ConstraintF<C>>
+ ToBytesGadget<ConstraintF<C>>
+ CondSelectGadget<ConstraintF<C>>
+ AllocVar<I::Output, ConstraintF<C>>
+ R1CSVar<ConstraintF<C>, Value = I::Output>
+ Debug
+ Clone
+ Sized;
fn evaluate(ge: &GG) -> Result<Self::OutputVar, SynthesisError>;
}
pub struct TECompressorGadget;
impl<F, P> InjectiveMapGadget<TEProjective<P>, TECompressor, TEVar<P, FpVar<F>>>
for TECompressorGadget
where
F: PrimeField + SquareRootField,
P: TEModelParameters + ModelParameters<BaseField = F>,
{
type OutputVar = FpVar<F>;
fn evaluate(ge: &TEVar<P, FpVar<F>>) -> Result<Self::OutputVar, SynthesisError> {
Ok(ge.x.clone())
}
}
pub struct PedersenCRHCompressorGadget<C, I, W, GG, IG>
where
C: ProjectiveCurve,
I: InjectiveMap<C>,
W: Window,
GG: CurveVar<C, ConstraintF<C>>,
for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
IG: InjectiveMapGadget<C, I, GG>,
{
#[doc(hidden)]
_compressor: PhantomData<I>,
#[doc(hidden)]
_compressor_gadget: PhantomData<IG>,
#[doc(hidden)]
_crh: ped_constraints::CRHGadget<C, GG, W>,
}
impl<C, I, GG, IG, W> FixedLengthCRHGadget<PedersenCRHCompressor<C, I, W>, ConstraintF<C>>
for PedersenCRHCompressorGadget<C, I, W, GG, IG>
where
C: ProjectiveCurve,
I: InjectiveMap<C>,
GG: CurveVar<C, ConstraintF<C>>,
for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
IG: InjectiveMapGadget<C, I, GG>,
W: Window,
{
type OutputVar = IG::OutputVar;
type ParametersVar = ped_constraints::CRHParametersVar<C, GG>;
#[tracing::instrument(target = "r1cs", skip(parameters, input))]
fn evaluate(
parameters: &Self::ParametersVar,
input: &[UInt8<ConstraintF<C>>],
) -> Result<Self::OutputVar, SynthesisError> {
let result = ped_constraints::CRHGadget::<C, GG, W>::evaluate(parameters, input)?;
IG::evaluate(&result)
}
}

+ 0
- 59
crypto-primitives/src/crh/injective_map/mod.rs

@ -1,59 +0,0 @@
use crate::{CryptoError, Error};
use algebra_core::bytes::ToBytes;
use core::{fmt::Debug, hash::Hash, marker::PhantomData};
use rand::Rng;
use super::{pedersen, FixedLengthCRH};
use algebra_core::curves::{
models::{ModelParameters, TEModelParameters},
twisted_edwards_extended::{GroupAffine as TEAffine, GroupProjective as TEProjective},
ProjectiveCurve,
};
#[cfg(feature = "r1cs")]
pub mod constraints;
pub trait InjectiveMap<C: ProjectiveCurve> {
type Output: ToBytes + Clone + Eq + Hash + Default + Debug;
fn injective_map(ge: &C::Affine) -> Result<Self::Output, CryptoError>;
}
pub struct TECompressor;
impl<P: TEModelParameters> InjectiveMap<TEProjective<P>> for TECompressor {
type Output = <P as ModelParameters>::BaseField;
fn injective_map(ge: &TEAffine<P>) -> Result<Self::Output, CryptoError> {
debug_assert!(ge.is_in_correct_subgroup_assuming_on_curve());
Ok(ge.x)
}
}
pub struct PedersenCRHCompressor<C: ProjectiveCurve, I: InjectiveMap<C>, W: pedersen::Window> {
_group: PhantomData<C>,
_compressor: PhantomData<I>,
_crh: pedersen::CRH<C, W>,
}
impl<C: ProjectiveCurve, I: InjectiveMap<C>, W: pedersen::Window> FixedLengthCRH
for PedersenCRHCompressor<C, I, W>
{
const INPUT_SIZE_BITS: usize = pedersen::CRH::<C, W>::INPUT_SIZE_BITS;
type Output = I::Output;
type Parameters = pedersen::Parameters<C>;
fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> {
let time = start_timer!(|| format!("PedersenCRHCompressor::Setup"));
let params = pedersen::CRH::<C, W>::setup(rng);
end_timer!(time);
params
}
fn evaluate(parameters: &Self::Parameters, input: &[u8]) -> Result<Self::Output, Error> {
let eval_time = start_timer!(|| "PedersenCRHCompressor::Eval");
let result = I::injective_map(&pedersen::CRH::<C, W>::evaluate(parameters, input)?)?;
end_timer!(eval_time);
Ok(result)
}
}

+ 0
- 24
crypto-primitives/src/crh/mod.rs

@ -1,24 +0,0 @@
use algebra_core::bytes::ToBytes;
use core::hash::Hash;
use rand::Rng;
pub mod bowe_hopwood;
pub mod injective_map;
pub mod pedersen;
use crate::Error;
#[cfg(feature = "r1cs")]
pub mod constraints;
#[cfg(feature = "r1cs")]
pub use constraints::*;
pub trait FixedLengthCRH {
const INPUT_SIZE_BITS: usize;
type Output: ToBytes + Clone + Eq + core::fmt::Debug + Hash + Default;
type Parameters: Clone + Default;
fn setup<R: Rng>(r: &mut R) -> Result<Self::Parameters, Error>;
fn evaluate(parameters: &Self::Parameters, input: &[u8]) -> Result<Self::Output, Error>;
}

+ 0
- 152
crypto-primitives/src/crh/pedersen/constraints.rs

@ -1,152 +0,0 @@
use crate::{
crh::{
pedersen::{Parameters, Window, CRH},
FixedLengthCRHGadget,
},
Vec,
};
use algebra_core::{Field, ProjectiveCurve};
use r1cs_core::{Namespace, SynthesisError};
use r1cs_std::prelude::*;
use core::{borrow::Borrow, marker::PhantomData};
#[derive(Derivative)]
#[derivative(Clone(bound = "C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>"))]
pub struct CRHParametersVar<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>>
where
for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
{
params: Parameters<C>,
#[doc(hidden)]
_group_g: PhantomData<GG>,
}
type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField;
pub struct CRHGadget<C: ProjectiveCurve, GG: CurveVar<C, ConstraintF<C>>, W: Window>
where
for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
{
#[doc(hidden)]
_group: PhantomData<*const C>,
#[doc(hidden)]
_group_var: PhantomData<*const GG>,
#[doc(hidden)]
_window: PhantomData<*const W>,
}
impl<C, GG, W> FixedLengthCRHGadget<CRH<C, W>, ConstraintF<C>> for CRHGadget<C, GG, W>
where
C: ProjectiveCurve,
GG: CurveVar<C, ConstraintF<C>>,
W: Window,
for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
{
type OutputVar = GG;
type ParametersVar = CRHParametersVar<C, GG>;
#[tracing::instrument(target = "r1cs", skip(parameters, input))]
fn evaluate(
parameters: &Self::ParametersVar,
input: &[UInt8<ConstraintF<C>>],
) -> Result<Self::OutputVar, SynthesisError> {
let mut padded_input = input.to_vec();
// Pad the input if it is not the current length.
if input.len() * 8 < W::WINDOW_SIZE * W::NUM_WINDOWS {
let current_length = input.len();
for _ in current_length..(W::WINDOW_SIZE * W::NUM_WINDOWS / 8) {
padded_input.push(UInt8::constant(0u8));
}
}
assert_eq!(padded_input.len() * 8, W::WINDOW_SIZE * W::NUM_WINDOWS);
assert_eq!(parameters.params.generators.len(), W::NUM_WINDOWS);
// Allocate new variable for the result.
let input_in_bits: Vec<Boolean<_>> = padded_input
.iter()
.flat_map(|b| b.to_bits_le().unwrap())
.collect();
let input_in_bits = input_in_bits.chunks(W::WINDOW_SIZE);
let result =
GG::precomputed_base_multiscalar_mul_le(&parameters.params.generators, input_in_bits)?;
Ok(result)
}
}
impl<C, GG> AllocVar<Parameters<C>, ConstraintF<C>> for CRHParametersVar<C, GG>
where
C: ProjectiveCurve,
GG: CurveVar<C, ConstraintF<C>>,
for<'a> &'a GG: GroupOpsBounds<'a, C, GG>,
{
#[tracing::instrument(target = "r1cs", skip(_cs, f))]
fn new_variable<T: Borrow<Parameters<C>>>(
_cs: impl Into<Namespace<ConstraintF<C>>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
_mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let params = f()?.borrow().clone();
Ok(CRHParametersVar {
params,
_group_g: PhantomData,
})
}
}
#[cfg(test)]
mod test {
use crate::crh::{pedersen, pedersen::constraints::*, FixedLengthCRH, FixedLengthCRHGadget};
use algebra::{
ed_on_bls12_381::{EdwardsProjective as JubJub, Fq as Fr},
test_rng,
};
use r1cs_core::{ConstraintSystem, ConstraintSystemRef};
use r1cs_std::ed_on_bls12_381::EdwardsVar;
use rand::Rng;
type TestCRH = pedersen::CRH<JubJub, Window>;
type TestCRHGadget = CRHGadget<JubJub, EdwardsVar, Window>;
#[derive(Clone, PartialEq, Eq, Hash)]
pub(super) struct Window;
impl pedersen::Window for Window {
const WINDOW_SIZE: usize = 128;
const NUM_WINDOWS: usize = 8;
}
fn generate_input<R: Rng>(
cs: ConstraintSystemRef<Fr>,
rng: &mut R,
) -> ([u8; 128], Vec<UInt8<Fr>>) {
let mut input = [1u8; 128];
rng.fill_bytes(&mut input);
let mut input_bytes = vec![];
for byte in input.iter() {
input_bytes.push(UInt8::new_witness(cs.clone(), || Ok(byte)).unwrap());
}
(input, input_bytes)
}
#[test]
fn test_native_equality() {
let rng = &mut test_rng();
let cs = ConstraintSystem::<Fr>::new_ref();
let (input, input_var) = generate_input(cs.clone(), rng);
let parameters = TestCRH::setup(rng).unwrap();
let primitive_result = TestCRH::evaluate(&parameters, &input).unwrap();
let parameters_var =
CRHParametersVar::new_constant(r1cs_core::ns!(cs, "CRH Parameters"), &parameters)
.unwrap();
let result_var = TestCRHGadget::evaluate(&parameters_var, &input_var).unwrap();
let primitive_result = primitive_result;
assert_eq!(primitive_result, result_var.value().unwrap());
assert!(cs.is_satisfied().unwrap());
}
}

+ 0
- 152
crypto-primitives/src/crh/pedersen/mod.rs

@ -1,152 +0,0 @@
use crate::{Error, Vec};
use core::{
fmt::{Debug, Formatter, Result as FmtResult},
marker::PhantomData,
};
use rand::Rng;
#[cfg(feature = "parallel")]
use rayon::prelude::*;
use crate::crh::FixedLengthCRH;
use algebra_core::{Field, ProjectiveCurve, ToConstraintField};
use ff_fft::cfg_chunks;
#[cfg(feature = "r1cs")]
pub mod constraints;
pub trait Window: Clone {
const WINDOW_SIZE: usize;
const NUM_WINDOWS: usize;
}
#[derive(Clone, Default)]
pub struct Parameters<C: ProjectiveCurve> {
pub generators: Vec<Vec<C>>,
}
pub struct CRH<C: ProjectiveCurve, W: Window> {
group: PhantomData<C>,
window: PhantomData<W>,
}
impl<C: ProjectiveCurve, W: Window> CRH<C, W> {
pub fn create_generators<R: Rng>(rng: &mut R) -> Vec<Vec<C>> {
let mut generators_powers = Vec::new();
for _ in 0..W::NUM_WINDOWS {
generators_powers.push(Self::generator_powers(W::WINDOW_SIZE, rng));
}
generators_powers
}
pub fn generator_powers<R: Rng>(num_powers: usize, rng: &mut R) -> Vec<C> {
let mut cur_gen_powers = Vec::with_capacity(num_powers);
let mut base = C::rand(rng);
for _ in 0..num_powers {
cur_gen_powers.push(base);
base.double_in_place();
}
cur_gen_powers
}
}
impl<C: ProjectiveCurve, W: Window> FixedLengthCRH for CRH<C, W> {
const INPUT_SIZE_BITS: usize = W::WINDOW_SIZE * W::NUM_WINDOWS;
type Output = C::Affine;
type Parameters = Parameters<C>;
fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> {
let time = start_timer!(|| format!(
"PedersenCRH::Setup: {} {}-bit windows; {{0,1}}^{{{}}} -> C",
W::NUM_WINDOWS,
W::WINDOW_SIZE,
W::NUM_WINDOWS * W::WINDOW_SIZE
));
let generators = Self::create_generators(rng);
end_timer!(time);
Ok(Self::Parameters { generators })
}
fn evaluate(parameters: &Self::Parameters, input: &[u8]) -> Result<Self::Output, Error> {
let eval_time = start_timer!(|| "PedersenCRH::Eval");
if (input.len() * 8) > W::WINDOW_SIZE * W::NUM_WINDOWS {
panic!(
"incorrect input length {:?} for window params {:?}✕{:?}",
input.len(),
W::WINDOW_SIZE,
W::NUM_WINDOWS
);
}
let mut padded_input = Vec::with_capacity(input.len());
let mut input = input;
// Pad the input if it is not the current length.
if (input.len() * 8) < W::WINDOW_SIZE * W::NUM_WINDOWS {
let current_length = input.len();
padded_input.extend_from_slice(input);
for _ in current_length..((W::WINDOW_SIZE * W::NUM_WINDOWS) / 8) {
padded_input.push(0u8);
}
input = padded_input.as_slice();
}
assert_eq!(
parameters.generators.len(),
W::NUM_WINDOWS,
"Incorrect pp of size {:?}✕{:?} for window params {:?}✕{:?}",
parameters.generators[0].len(),
parameters.generators.len(),
W::WINDOW_SIZE,
W::NUM_WINDOWS
);
// Compute sum of h_i^{m_i} for all i.
let bits = bytes_to_bits(input);
let result = cfg_chunks!(bits, W::WINDOW_SIZE)
.zip(&parameters.generators)
.map(|(bits, generator_powers)| {
let mut encoded = C::zero();
for (bit, base) in bits.iter().zip(generator_powers.iter()) {
if *bit {
encoded += base;
}
}
encoded
})
.sum::<C>();
end_timer!(eval_time);
Ok(result.into())
}
}
pub fn bytes_to_bits(bytes: &[u8]) -> Vec<bool> {
let mut bits = Vec::with_capacity(bytes.len() * 8);
for byte in bytes {
for i in 0..8 {
let bit = (*byte >> i) & 1;
bits.push(bit == 1)
}
}
bits
}
impl<C: ProjectiveCurve> Debug for Parameters<C> {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
write!(f, "Pedersen Hash Parameters {{\n")?;
for (i, g) in self.generators.iter().enumerate() {
write!(f, "\t Generator {}: {:?}\n", i, g)?;
}
write!(f, "}}\n")
}
}
impl<ConstraintF: Field, C: ProjectiveCurve + ToConstraintField<ConstraintF>>
ToConstraintField<ConstraintF> for Parameters<C>
{
#[inline]
fn to_field_elements(&self) -> Result<Vec<ConstraintF>, Error> {
Ok(Vec::new())
}
}

+ 0
- 59
crypto-primitives/src/lib.rs

@ -1,59 +0,0 @@
#![cfg_attr(not(feature = "std"), no_std)]
#[macro_use]
extern crate bench_utils;
#[macro_use]
extern crate derivative;
#[macro_use]
extern crate alloc;
#[cfg(not(feature = "std"))]
pub(crate) use alloc::{borrow::ToOwned, boxed::Box, vec::Vec};
#[cfg(feature = "std")]
pub(crate) use std::{borrow::ToOwned, boxed::Box, vec::Vec};
pub mod commitment;
pub mod crh;
pub mod merkle_tree;
pub mod nizk;
pub mod prf;
pub mod signature;
pub use self::{
commitment::CommitmentScheme,
crh::FixedLengthCRH,
merkle_tree::{MerkleTree, Path},
nizk::NIZK,
prf::PRF,
signature::SignatureScheme,
};
#[cfg(feature = "r1cs")]
#[cfg(feature = "r1cs")]
pub use self::{
commitment::CommitmentGadget, crh::FixedLengthCRHGadget, merkle_tree::constraints::PathVar,
nizk::NIZKVerifierGadget, prf::PRFGadget, signature::SigRandomizePkGadget,
};
pub type Error = Box<dyn algebra_core::Error>;
#[derive(Debug)]
pub enum CryptoError {
IncorrectInputLength(usize),
NotPrimeOrder,
}
impl core::fmt::Display for CryptoError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let msg = match self {
CryptoError::IncorrectInputLength(len) => format!("input length is wrong: {}", len),
CryptoError::NotPrimeOrder => "element is not prime order".to_owned(),
};
write!(f, "{}", msg)
}
}
impl algebra_core::Error for CryptoError {}

+ 0
- 258
crypto-primitives/src/merkle_tree/constraints.rs

@ -1,258 +0,0 @@
use algebra_core::Field;
use r1cs_core::{Namespace, SynthesisError};
use r1cs_std::prelude::*;
use crate::{
crh::{FixedLengthCRH, FixedLengthCRHGadget},
merkle_tree::*,
};
use core::borrow::Borrow;
pub struct PathVar<P, HGadget, ConstraintF>
where
P: Config,
HGadget: FixedLengthCRHGadget<P::H, ConstraintF>,
ConstraintF: Field,
{
path: Vec<(HGadget::OutputVar, HGadget::OutputVar)>,
}
impl<P, CRHGadget, ConstraintF> PathVar<P, CRHGadget, ConstraintF>
where
P: Config,
ConstraintF: Field,
CRHGadget: FixedLengthCRHGadget<P::H, ConstraintF>,
<CRHGadget::OutputVar as R1CSVar<ConstraintF>>::Value: PartialEq,
{
#[tracing::instrument(target = "r1cs", skip(self, parameters, root, leaf))]
pub fn check_membership(
&self,
parameters: &CRHGadget::ParametersVar,
root: &CRHGadget::OutputVar,
leaf: impl ToBytesGadget<ConstraintF>,
) -> Result<Boolean<ConstraintF>, SynthesisError> {
assert_eq!(self.path.len(), P::HEIGHT - 1);
// Check that the hash of the given leaf matches the leaf hash in the membership
// proof.
let leaf_bits = leaf.to_bytes()?;
let leaf_hash = CRHGadget::evaluate(parameters, &leaf_bits)?;
let cs = leaf_hash.cs().or(root.cs());
// Check if leaf is one of the bottom-most siblings.
let leaf_is_left = Boolean::new_witness(r1cs_core::ns!(cs, "leaf_is_left"), || {
Ok(leaf_hash.value()?.eq(&self.path[0].0.value()?))
})?;
let mut result =
leaf_hash.is_eq(&leaf_is_left.select(&self.path[0].0, &self.path[0].1)?)?;
// Check levels between leaf level and root.
let mut previous_hash = leaf_hash;
for &(ref left_hash, ref right_hash) in &self.path {
// Check if the previous_hash matches the correct current hash.
let previous_is_left =
Boolean::new_witness(r1cs_core::ns!(cs, "previous_is_left"), || {
Ok(previous_hash.value()?.eq(&left_hash.value()?))
})?;
let ns = r1cs_core::ns!(cs, "enforcing that inner hash is correct");
let equality_cmp = previous_is_left.select(left_hash, right_hash)?;
result = result.and(&previous_hash.is_eq(&equality_cmp)?)?;
drop(ns);
previous_hash =
hash_inner_node::<P::H, CRHGadget, ConstraintF>(parameters, left_hash, right_hash)?;
}
result.and(&root.is_eq(&previous_hash)?)
}
}
pub(crate) fn hash_inner_node<H, HG, ConstraintF>(
parameters: &HG::ParametersVar,
left_child: &HG::OutputVar,
right_child: &HG::OutputVar,
) -> Result<HG::OutputVar, SynthesisError>
where
ConstraintF: Field,
H: FixedLengthCRH,
HG: FixedLengthCRHGadget<H, ConstraintF>,
{
let left_bytes = left_child.to_bytes()?;
let right_bytes = right_child.to_bytes()?;
let mut bytes = left_bytes;
bytes.extend_from_slice(&right_bytes);
HG::evaluate(parameters, &bytes)
}
impl<P, HGadget, ConstraintF> AllocVar<Path<P>, ConstraintF> for PathVar<P, HGadget, ConstraintF>
where
P: Config,
HGadget: FixedLengthCRHGadget<P::H, ConstraintF>,
ConstraintF: Field,
{
fn new_variable<T: Borrow<Path<P>>>(
cs: impl Into<Namespace<ConstraintF>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let ns = cs.into();
let cs = ns.cs();
f().and_then(|val| {
let mut path = Vec::new();
for &(ref l, ref r) in val.borrow().path.iter() {
let l_hash = HGadget::OutputVar::new_variable(
r1cs_core::ns!(cs, "l_child"),
|| Ok(l),
mode,
)?;
let r_hash = HGadget::OutputVar::new_variable(
r1cs_core::ns!(cs, "r_child"),
|| Ok(r),
mode,
)?;
path.push((l_hash, r_hash));
}
Ok(PathVar { path })
})
}
}
#[cfg(test)]
mod test {
use crate::{
crh::{
pedersen::{self, constraints::CRHGadget},
FixedLengthCRH, FixedLengthCRHGadget,
},
merkle_tree::*,
};
use algebra::ed_on_bls12_381::{EdwardsProjective as JubJub, Fq};
use r1cs_core::ConstraintSystem;
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;
use super::*;
use r1cs_std::ed_on_bls12_381::EdwardsVar;
#[derive(Clone)]
pub(super) struct Window4x256;
impl pedersen::Window for Window4x256 {
const WINDOW_SIZE: usize = 4;
const NUM_WINDOWS: usize = 256;
}
type H = pedersen::CRH<JubJub, Window4x256>;
type HG = CRHGadget<JubJub, EdwardsVar, Window4x256>;
struct JubJubMerkleTreeParams;
impl Config for JubJubMerkleTreeParams {
const HEIGHT: usize = 32;
type H = H;
}
type JubJubMerkleTree = MerkleTree<JubJubMerkleTreeParams>;
fn generate_merkle_tree(leaves: &[[u8; 30]], use_bad_root: bool) -> () {
let mut rng = XorShiftRng::seed_from_u64(9174123u64);
let crh_parameters = H::setup(&mut rng).unwrap();
let tree = JubJubMerkleTree::new(crh_parameters.clone(), leaves).unwrap();
let root = tree.root();
let cs = ConstraintSystem::<Fq>::new_ref();
for (i, leaf) in leaves.iter().enumerate() {
let proof = tree.generate_proof(i, &leaf).unwrap();
assert!(proof.verify(&crh_parameters, &root, &leaf).unwrap());
// Allocate Merkle Tree Root
let root = <HG as FixedLengthCRHGadget<H, _>>::OutputVar::new_witness(
r1cs_core::ns!(cs, "new_digest"),
|| {
if use_bad_root {
Ok(<H as FixedLengthCRH>::Output::default())
} else {
Ok(root)
}
},
)
.unwrap();
let constraints_from_digest = cs.num_constraints();
println!("constraints from digest: {}", constraints_from_digest);
// Allocate Parameters for CRH
let crh_parameters = <HG as FixedLengthCRHGadget<H, Fq>>::ParametersVar::new_constant(
r1cs_core::ns!(cs, "new_parameter"),
&crh_parameters,
)
.unwrap();
let constraints_from_parameters = cs.num_constraints() - constraints_from_digest;
println!(
"constraints from parameters: {}",
constraints_from_parameters
);
// Allocate Leaf
let leaf_g = UInt8::constant_vec(leaf);
let constraints_from_leaf =
cs.num_constraints() - constraints_from_parameters - constraints_from_digest;
println!("constraints from leaf: {}", constraints_from_leaf);
// Allocate Merkle Tree Path
let cw =
PathVar::<_, HG, _>::new_witness(r1cs_core::ns!(cs, "new_witness"), || Ok(&proof))
.unwrap();
for (i, (l, r)) in cw.path.iter().enumerate() {
assert_eq!(l.value().unwrap(), proof.path[i].0);
assert_eq!(r.value().unwrap(), proof.path[i].1);
}
let constraints_from_path = cs.num_constraints()
- constraints_from_parameters
- constraints_from_digest
- constraints_from_leaf;
println!("constraints from path: {}", constraints_from_path);
let leaf_g: &[_] = leaf_g.as_slice();
cw.check_membership(&crh_parameters, &root, &leaf_g)
.unwrap()
.enforce_equal(&Boolean::TRUE)
.unwrap();
let setup_constraints = constraints_from_leaf
+ constraints_from_digest
+ constraints_from_parameters
+ constraints_from_path;
println!(
"number of constraints: {}",
cs.num_constraints() - setup_constraints
);
}
assert!(cs.is_satisfied().unwrap());
}
#[test]
fn good_root_test() {
let mut leaves = Vec::new();
for i in 0..4u8 {
let input = [i; 30];
leaves.push(input);
}
generate_merkle_tree(&leaves, false);
}
#[should_panic]
#[test]
fn bad_root_test() {
let mut leaves = Vec::new();
for i in 0..4u8 {
let input = [i; 30];
leaves.push(input);
}
generate_merkle_tree(&leaves, true);
}
}

+ 0
- 449
crypto-primitives/src/merkle_tree/mod.rs

@ -1,449 +0,0 @@
use crate::{crh::FixedLengthCRH, Vec};
use algebra_core::bytes::ToBytes;
use core::fmt;
#[cfg(feature = "r1cs")]
pub mod constraints;
pub trait Config {
const HEIGHT: usize;
type H: FixedLengthCRH;
}
/// Stores the hashes of a particular path (in order) from leaf to root.
/// Our path `is_left_child()` if the boolean in `path` is true.
#[derive(Derivative)]
#[derivative(
Clone(bound = "P: Config"),
Debug(bound = "P: Config, <P::H as FixedLengthCRH>::Output: fmt::Debug")
)]
pub struct Path<P: Config> {
pub(crate) path: Vec<(
<P::H as FixedLengthCRH>::Output,
<P::H as FixedLengthCRH>::Output,
)>,
}
pub type Parameters<P> = <<P as Config>::H as FixedLengthCRH>::Parameters;
pub type Digest<P> = <<P as Config>::H as FixedLengthCRH>::Output;
impl<P: Config> Default for Path<P> {
fn default() -> Self {
let mut path = Vec::with_capacity(P::HEIGHT as usize);
for _i in 1..P::HEIGHT as usize {
path.push((
<P::H as FixedLengthCRH>::Output::default(),
<P::H as FixedLengthCRH>::Output::default(),
));
}
Self { path }
}
}
impl<P: Config> Path<P> {
pub fn verify<L: ToBytes>(
&self,
parameters: &<P::H as FixedLengthCRH>::Parameters,
root_hash: &<P::H as FixedLengthCRH>::Output,
leaf: &L,
) -> Result<bool, crate::Error> {
if self.path.len() != (P::HEIGHT - 1) as usize {
return Ok(false);
}
// Check that the given leaf matches the leaf in the membership proof.
let mut buffer = [0u8; 128];
if !self.path.is_empty() {
let claimed_leaf_hash = hash_leaf::<P::H, L>(parameters, leaf, &mut buffer)?;
// Check if leaf is one of the bottom-most siblings.
if claimed_leaf_hash != self.path[0].0 && claimed_leaf_hash != self.path[0].1 {
return Ok(false);
};
let mut prev = claimed_leaf_hash;
// Check levels between leaf level and root.
for &(ref hash, ref sibling_hash) in &self.path {
// Check if the previous hash matches the correct current hash.
if &prev != hash && &prev != sibling_hash {
return Ok(false);
};
prev = hash_inner_node::<P::H>(parameters, hash, sibling_hash, &mut buffer)?;
}
if root_hash != &prev {
return Ok(false);
}
Ok(true)
} else {
Ok(false)
}
}
}
pub struct MerkleTree<P: Config> {
tree: Vec<<P::H as FixedLengthCRH>::Output>,
padding_tree: Vec<(
<P::H as FixedLengthCRH>::Output,
<P::H as FixedLengthCRH>::Output,
)>,
parameters: <P::H as FixedLengthCRH>::Parameters,
root: Option<<P::H as FixedLengthCRH>::Output>,
}
impl<P: Config> MerkleTree<P> {
pub const HEIGHT: u8 = P::HEIGHT as u8;
pub fn blank(parameters: <P::H as FixedLengthCRH>::Parameters) -> Self {
MerkleTree {
tree: Vec::new(),
padding_tree: Vec::new(),
root: None,
parameters,
}
}
pub fn new<L: ToBytes>(
parameters: <P::H as FixedLengthCRH>::Parameters,
leaves: &[L],
) -> Result<Self, crate::Error> {
let new_time = start_timer!(|| "MerkleTree::New");
let last_level_size = leaves.len().next_power_of_two();
let tree_size = 2 * last_level_size - 1;
let tree_height = tree_height(tree_size);
assert!(tree_height as u8 <= Self::HEIGHT);
// Initialize the merkle tree.
let mut tree = Vec::with_capacity(tree_size);
let empty_hash = hash_empty::<P::H>(&parameters)?;
for _ in 0..tree_size {
tree.push(empty_hash.clone());
}
// Compute the starting indices for each level of the tree.
let mut index = 0;
let mut level_indices = Vec::with_capacity(tree_height);
for _ in 0..tree_height {
level_indices.push(index);
index = left_child(index);
}
// Compute and store the hash values for each leaf.
let last_level_index = level_indices.pop().unwrap_or(0);
let mut buffer = [0u8; 128];
for (i, leaf) in leaves.iter().enumerate() {
tree[last_level_index + i] = hash_leaf::<P::H, _>(&parameters, leaf, &mut buffer)?;
}
// Compute the hash values for every node in the tree.
let mut upper_bound = last_level_index;
let mut buffer = [0u8; 128];
level_indices.reverse();
for &start_index in &level_indices {
// Iterate over the current level.
for current_index in start_index..upper_bound {
let left_index = left_child(current_index);
let right_index = right_child(current_index);
// Compute Hash(left || right).
tree[current_index] = hash_inner_node::<P::H>(
&parameters,
&tree[left_index],
&tree[right_index],
&mut buffer,
)?;
}
upper_bound = start_index;
}
// Finished computing actual tree.
// Now, we compute the dummy nodes until we hit our HEIGHT goal.
let mut cur_height = tree_height;
let mut padding_tree = Vec::new();
let mut cur_hash = tree[0].clone();
let root_hash = if cur_height < Self::HEIGHT as usize {
while cur_height < (Self::HEIGHT - 1) as usize {
cur_hash =
hash_inner_node::<P::H>(&parameters, &cur_hash, &empty_hash, &mut buffer)?;
padding_tree.push((cur_hash.clone(), empty_hash.clone()));
cur_height += 1;
}
hash_inner_node::<P::H>(&parameters, &cur_hash, &empty_hash, &mut buffer)?
} else {
cur_hash
};
end_timer!(new_time);
Ok(MerkleTree {
tree,
padding_tree,
parameters,
root: Some(root_hash),
})
}
#[inline]
pub fn root(&self) -> <P::H as FixedLengthCRH>::Output {
self.root.clone().unwrap()
}
pub fn generate_proof<L: ToBytes>(
&self,
index: usize,
leaf: &L,
) -> Result<Path<P>, crate::Error> {
let prove_time = start_timer!(|| "MerkleTree::GenProof");
let mut path = Vec::new();
let mut buffer = [0u8; 128];
let leaf_hash = hash_leaf::<P::H, _>(&self.parameters, leaf, &mut buffer)?;
let tree_height = tree_height(self.tree.len());
let tree_index = convert_index_to_last_level(index, tree_height);
let empty_hash = hash_empty::<P::H>(&self.parameters)?;
// Check that the given index corresponds to the correct leaf.
if leaf_hash != self.tree[tree_index] {
return Err(Error::IncorrectLeafIndex(tree_index).into());
}
// Iterate from the leaf up to the root, storing all intermediate hash values.
let mut current_node = tree_index;
while !is_root(current_node) {
let sibling_node = sibling(current_node).unwrap();
let (curr_hash, sibling_hash) = (
self.tree[current_node].clone(),
self.tree[sibling_node].clone(),
);
if is_left_child(current_node) {
path.push((curr_hash, sibling_hash));
} else {
path.push((sibling_hash, curr_hash));
}
current_node = parent(current_node).unwrap();
}
// Store the root node. Set boolean as true for consistency with digest
// location.
assert!(path.len() < Self::HEIGHT as usize);
if path.len() != (Self::HEIGHT - 1) as usize {
path.push((self.tree[0].clone(), empty_hash));
for &(ref hash, ref sibling_hash) in &self.padding_tree {
path.push((hash.clone(), sibling_hash.clone()));
}
}
end_timer!(prove_time);
if path.len() != (Self::HEIGHT - 1) as usize {
return Err(Error::IncorrectPathLength(path.len()).into());
} else {
Ok(Path { path })
}
}
}
#[derive(Debug)]
pub enum Error {
IncorrectLeafIndex(usize),
IncorrectPathLength(usize),
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let msg = match self {
Error::IncorrectLeafIndex(index) => format!("incorrect leaf index: {}", index),
Error::IncorrectPathLength(len) => format!("incorrect path length: {}", len),
};
write!(f, "{}", msg)
}
}
impl algebra_core::Error for Error {}
/// Returns the height of the tree, given the size of the tree.
#[inline]
fn tree_height(tree_size: usize) -> usize {
if tree_size == 1 {
return 1;
}
algebra_core::log2(tree_size) as usize
}
/// Returns true iff the index represents the root.
#[inline]
fn is_root(index: usize) -> bool {
index == 0
}
/// Returns the index of the left child, given an index.
#[inline]
fn left_child(index: usize) -> usize {
2 * index + 1
}
/// Returns the index of the right child, given an index.
#[inline]
fn right_child(index: usize) -> usize {
2 * index + 2
}
/// Returns the index of the sibling, given an index.
#[inline]
fn sibling(index: usize) -> Option<usize> {
if index == 0 {
None
} else if is_left_child(index) {
Some(index + 1)
} else {
Some(index - 1)
}
}
/// Returns true iff the given index represents a left child.
#[inline]
fn is_left_child(index: usize) -> bool {
index % 2 == 1
}
/// Returns the index of the parent, given an index.
#[inline]
fn parent(index: usize) -> Option<usize> {
if index > 0 {
Some((index - 1) >> 1)
} else {
None
}
}
#[inline]
fn convert_index_to_last_level(index: usize, tree_height: usize) -> usize {
index + (1 << (tree_height - 1)) - 1
}
/// Returns the output hash, given a left and right hash value.
pub(crate) fn hash_inner_node<H: FixedLengthCRH>(
parameters: &H::Parameters,
left: &H::Output,
right: &H::Output,
buffer: &mut [u8],
) -> Result<H::Output, crate::Error> {
let bytes = algebra_core::to_bytes![left]?
.into_iter()
.chain(algebra_core::to_bytes![right]?);
buffer.iter_mut().zip(bytes).for_each(|(b, l_b)| *b = l_b);
H::evaluate(parameters, &buffer[..(H::INPUT_SIZE_BITS / 8)])
}
/// Returns the hash of a leaf.
pub(crate) fn hash_leaf<H: FixedLengthCRH, L: ToBytes>(
parameters: &H::Parameters,
leaf: &L,
buffer: &mut [u8],
) -> Result<H::Output, crate::Error> {
buffer
.iter_mut()
.zip(&algebra_core::to_bytes![leaf]?)
.for_each(|(b, l_b)| *b = *l_b);
H::evaluate(parameters, &buffer[..(H::INPUT_SIZE_BITS / 8)])
}
pub(crate) fn hash_empty<H: FixedLengthCRH>(
parameters: &H::Parameters,
) -> Result<H::Output, crate::Error> {
let empty_buffer = vec![0u8; H::INPUT_SIZE_BITS / 8];
H::evaluate(parameters, &empty_buffer)
}
#[cfg(test)]
mod test {
use crate::{
crh::{pedersen, *},
merkle_tree::*,
};
use algebra::{ed_on_bls12_381::EdwardsProjective as JubJub, Zero};
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;
#[derive(Clone)]
pub(super) struct Window4x256;
impl pedersen::Window for Window4x256 {
const WINDOW_SIZE: usize = 4;
const NUM_WINDOWS: usize = 256;
}
type H = pedersen::CRH<JubJub, Window4x256>;
struct JubJubMerkleTreeParams;
impl Config for JubJubMerkleTreeParams {
const HEIGHT: usize = 8;
type H = H;
}
type JubJubMerkleTree = MerkleTree<JubJubMerkleTreeParams>;
fn generate_merkle_tree<L: ToBytes + Clone + Eq>(leaves: &[L]) -> () {
let mut rng = XorShiftRng::seed_from_u64(9174123u64);
let crh_parameters = H::setup(&mut rng).unwrap();
let tree = JubJubMerkleTree::new(crh_parameters.clone(), &leaves).unwrap();
let root = tree.root();
for (i, leaf) in leaves.iter().enumerate() {
let proof = tree.generate_proof(i, &leaf).unwrap();
assert!(proof.verify(&crh_parameters, &root, &leaf).unwrap());
}
}
#[test]
fn good_root_test() {
let mut leaves = Vec::new();
for i in 0..4u8 {
leaves.push([i, i, i, i, i, i, i, i]);
}
generate_merkle_tree(&leaves);
let mut leaves = Vec::new();
for i in 0..100u8 {
leaves.push([i, i, i, i, i, i, i, i]);
}
generate_merkle_tree(&leaves);
}
#[test]
fn no_dummy_nodes_test() {
let mut leaves = Vec::new();
for i in 0..(1u8 << JubJubMerkleTree::HEIGHT - 1) {
leaves.push([i, i, i, i, i, i, i, i]);
}
generate_merkle_tree(&leaves);
}
#[test]
fn single_leaf_test() {
generate_merkle_tree(&[[1u8; 8]]);
}
fn bad_merkle_tree_verify<L: ToBytes + Clone + Eq>(leaves: &[L]) -> () {
let mut rng = XorShiftRng::seed_from_u64(13423423u64);
let crh_parameters = H::setup(&mut rng).unwrap();
let tree = JubJubMerkleTree::new(crh_parameters.clone(), &leaves).unwrap();
let root = JubJub::zero().into();
for (i, leaf) in leaves.iter().enumerate() {
let proof = tree.generate_proof(i, &leaf).unwrap();
assert!(proof.verify(&crh_parameters, &root, &leaf).unwrap());
}
}
#[should_panic]
#[test]
fn bad_root_test() {
let mut leaves = Vec::new();
for i in 0..4u8 {
leaves.push([i, i, i, i, i, i, i, i]);
}
generate_merkle_tree(&leaves);
let mut leaves = Vec::new();
for i in 0..100u8 {
leaves.push([i, i, i, i, i, i, i, i]);
}
bad_merkle_tree_verify(&leaves);
}
}

+ 0
- 51
crypto-primitives/src/nizk/constraints.rs

@ -1,51 +0,0 @@
use algebra_core::Field;
use core::borrow::Borrow;
use r1cs_core::{Namespace, SynthesisError};
use r1cs_std::prelude::*;
use crate::nizk::NIZK;
pub trait NIZKVerifierGadget<N: NIZK, ConstraintF: Field> {
type PreparedVerificationKeyVar;
type VerificationKeyVar: AllocVar<N::VerificationParameters, ConstraintF>
+ ToBytesGadget<ConstraintF>;
type ProofVar: AllocVar<N::Proof, ConstraintF>;
/// Optionally allocates `N::Proof` in `cs` without performing
/// subgroup checks.
///
/// The default implementation doesn't omit these checks.
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_proof_unchecked<T: Borrow<N::Proof>>(
cs: impl Into<Namespace<ConstraintF>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self::ProofVar, SynthesisError> {
Self::ProofVar::new_variable(cs, f, mode)
}
/// Optionally allocates `N::VerificationParameters` in `cs`
/// without performing subgroup checks.
///
/// The default implementation doesn't omit these checks.
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_verification_key_unchecked<T: Borrow<N::VerificationParameters>>(
cs: impl Into<Namespace<ConstraintF>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self::VerificationKeyVar, SynthesisError> {
Self::VerificationKeyVar::new_variable(cs, f, mode)
}
fn verify<'a, T: 'a + ToBitsGadget<ConstraintF> + ?Sized>(
verification_key: &Self::VerificationKeyVar,
input: impl IntoIterator<Item = &'a T>,
proof: &Self::ProofVar,
) -> Result<Boolean<ConstraintF>, SynthesisError>;
fn verify_prepared<'a, T: 'a + ToBitsGadget<ConstraintF> + ?Sized>(
prepared_verification_key: &Self::PreparedVerificationKeyVar,
input: impl IntoIterator<Item = &'a T>,
proof: &Self::ProofVar,
) -> Result<Boolean<ConstraintF>, SynthesisError>;
}

+ 0
- 797
crypto-primitives/src/nizk/gm17/constraints.rs

@ -1,797 +0,0 @@
use crate::{
nizk::{gm17::Gm17, NIZKVerifierGadget},
Vec,
};
use algebra_core::{AffineCurve, PairingEngine, ToConstraintField};
use r1cs_core::{ConstraintSynthesizer, Namespace, SynthesisError};
use r1cs_std::prelude::*;
use core::{borrow::Borrow, marker::PhantomData};
use gm17::{PreparedVerifyingKey, Proof, VerifyingKey};
#[derive(Derivative)]
#[derivative(Clone(bound = "P::G1Var: Clone, P::G2Var: Clone"))]
pub struct ProofVar<E: PairingEngine, P: PairingVar<E>> {
pub a: P::G1Var,
pub b: P::G2Var,
pub c: P::G1Var,
}
#[derive(Derivative)]
#[derivative(
Clone(bound = "P::G1Var: Clone, P::GTVar: Clone, P::G1PreparedVar: Clone, \
P::G2PreparedVar: Clone, ")
)]
pub struct VerifyingKeyVar<E: PairingEngine, P: PairingVar<E>> {
pub h_g2: P::G2Var,
pub g_alpha_g1: P::G1Var,
pub h_beta_g2: P::G2Var,
pub g_gamma_g1: P::G1Var,
pub h_gamma_g2: P::G2Var,
pub query: Vec<P::G1Var>,
}
impl<E: PairingEngine, P: PairingVar<E>> VerifyingKeyVar<E, P> {
#[tracing::instrument(target = "r1cs", skip(self))]
pub fn prepare(&self) -> Result<PreparedVerifyingKeyVar<E, P>, SynthesisError> {
let g_alpha_pc = P::prepare_g1(&self.g_alpha_g1)?;
let h_beta_pc = P::prepare_g2(&self.h_beta_g2)?;
let g_gamma_pc = P::prepare_g1(&self.g_gamma_g1)?;
let h_gamma_pc = P::prepare_g2(&self.h_gamma_g2)?;
let h_pc = P::prepare_g2(&self.h_g2)?;
Ok(PreparedVerifyingKeyVar {
g_alpha: self.g_alpha_g1.clone(),
h_beta: self.h_beta_g2.clone(),
g_alpha_pc,
h_beta_pc,
g_gamma_pc,
h_gamma_pc,
h_pc,
query: self.query.clone(),
})
}
}
#[derive(Derivative)]
#[derivative(
Clone(bound = "P::G1Var: Clone, P::GTVar: Clone, P::G1PreparedVar: Clone, \
P::G2PreparedVar: Clone, ")
)]
pub struct PreparedVerifyingKeyVar<E: PairingEngine, P: PairingVar<E>> {
pub g_alpha: P::G1Var,
pub h_beta: P::G2Var,
pub g_alpha_pc: P::G1PreparedVar,
pub h_beta_pc: P::G2PreparedVar,
pub g_gamma_pc: P::G1PreparedVar,
pub h_gamma_pc: P::G2PreparedVar,
pub h_pc: P::G2PreparedVar,
pub query: Vec<P::G1Var>,
}
pub struct Gm17VerifierGadget<E, P>
where
E: PairingEngine,
P: PairingVar<E>,
{
_pairing_engine: PhantomData<E>,
_pairing_gadget: PhantomData<P>,
}
impl<E, P, C, V> NIZKVerifierGadget<Gm17<E, C, V>, E::Fq> for Gm17VerifierGadget<E, P>
where
E: PairingEngine,
C: ConstraintSynthesizer<E::Fr>,
V: ToConstraintField<E::Fr>,
P: PairingVar<E>,
{
type PreparedVerificationKeyVar = PreparedVerifyingKeyVar<E, P>;
type VerificationKeyVar = VerifyingKeyVar<E, P>;
type ProofVar = ProofVar<E, P>;
/// Allocates `N::Proof` in `cs` without performing
/// subgroup checks.
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_proof_unchecked<T: Borrow<Proof<E>>>(
cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self::ProofVar, SynthesisError> {
let ns = cs.into();
let cs = ns.cs();
f().and_then(|proof| {
let proof = proof.borrow();
let a = CurveVar::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "Proof.a"),
|| Ok(proof.a.into_projective()),
mode,
)?;
let b = CurveVar::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "Proof.b"),
|| Ok(proof.b.into_projective()),
mode,
)?;
let c = CurveVar::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "Proof.c"),
|| Ok(proof.c.into_projective()),
mode,
)?;
Ok(ProofVar { a, b, c })
})
}
/// Allocates `N::Proof` in `cs` without performing
/// subgroup checks.
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_verification_key_unchecked<T: Borrow<VerifyingKey<E>>>(
cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self::VerificationKeyVar, SynthesisError> {
let ns = cs.into();
let cs = ns.cs();
f().and_then(|vk| {
let vk = vk.borrow();
let g_alpha_g1 = P::G1Var::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "g_alpha"),
|| Ok(vk.g_alpha_g1.into_projective()),
mode,
)?;
let h_g2 = P::G2Var::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "h"),
|| Ok(vk.h_g2.into_projective()),
mode,
)?;
let h_beta_g2 = P::G2Var::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "h_beta"),
|| Ok(vk.h_beta_g2.into_projective()),
mode,
)?;
let g_gamma_g1 = P::G1Var::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "g_gamma"),
|| Ok(vk.g_gamma_g1.into_projective()),
mode,
)?;
let h_gamma_g2 = P::G2Var::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "h_gamma"),
|| Ok(vk.h_gamma_g2.into_projective()),
mode,
)?;
let query = vk
.query
.iter()
.map(|g| {
P::G1Var::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "g"),
|| Ok(g.into_projective()),
mode,
)
})
.collect::<Result<Vec<_>, _>>()?;
Ok(VerifyingKeyVar {
g_alpha_g1,
h_g2,
h_beta_g2,
g_gamma_g1,
h_gamma_g2,
query,
})
})
}
#[tracing::instrument(target = "r1cs", skip(vk, input, proof))]
fn verify<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
vk: &Self::VerificationKeyVar,
input: impl IntoIterator<Item = &'a T>,
proof: &Self::ProofVar,
) -> Result<Boolean<E::Fq>, SynthesisError> {
let pvk = vk.prepare()?;
<Self as NIZKVerifierGadget<Gm17<E, C, V>, E::Fq>>::verify_prepared(&pvk, input, proof)
}
#[tracing::instrument(target = "r1cs", skip(pvk, input, proof))]
fn verify_prepared<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
pvk: &Self::PreparedVerificationKeyVar,
input: impl IntoIterator<Item = &'a T>,
proof: &Self::ProofVar,
) -> Result<Boolean<E::Fq>, SynthesisError> {
let pvk = pvk.clone();
// e(A*G^{alpha}, B*H^{beta}) = e(G^{alpha}, H^{beta}) * e(G^{psi}, H^{gamma}) *
// e(C, H) where psi = \sum_{i=0}^l input_i pvk.query[i]
let g_psi = {
let mut g_psi = pvk.query[0].clone();
let mut input_len = 1;
let mut input = input.into_iter();
for (input, b) in input.by_ref().zip(pvk.query.iter().skip(1)) {
let input_bits = input.to_bits_le()?;
g_psi += b.scalar_mul_le(input_bits.iter())?;
input_len += 1;
}
// Check that the input and the query in the verification are of the
// same length.
assert!(input_len == pvk.query.len() && input.next().is_none());
g_psi
};
let mut test1_a_g_alpha = proof.a.clone();
test1_a_g_alpha += pvk.g_alpha.clone();
let mut test1_b_h_beta = proof.b.clone();
test1_b_h_beta += pvk.h_beta.clone();
let test1_exp = {
test1_a_g_alpha = test1_a_g_alpha.negate()?;
let test1_a_g_alpha_prep = P::prepare_g1(&test1_a_g_alpha)?;
let test1_b_h_beta_prep = P::prepare_g2(&test1_b_h_beta)?;
let g_psi_prep = P::prepare_g1(&g_psi)?;
let c_prep = P::prepare_g1(&proof.c)?;
P::miller_loop(
&[
test1_a_g_alpha_prep,
g_psi_prep,
c_prep,
pvk.g_alpha_pc.clone(),
],
&[
test1_b_h_beta_prep,
pvk.h_gamma_pc.clone(),
pvk.h_pc.clone(),
pvk.h_beta_pc.clone(),
],
)?
};
let test1 = P::final_exponentiation(&test1_exp).unwrap();
// e(A, H^{gamma}) = e(G^{gamma}, B)
let test2_exp = {
let a_prep = P::prepare_g1(&proof.a)?;
// pvk.h_gamma_pc
//&pvk.g_gamma_pc
let proof_b = proof.b.negate()?;
let b_prep = P::prepare_g2(&proof_b)?;
P::miller_loop(&[a_prep, pvk.g_gamma_pc.clone()], &[pvk.h_gamma_pc, b_prep])?
};
let test2 = P::final_exponentiation(&test2_exp)?;
let one = P::GTVar::one();
test1.is_eq(&one)?.and(&test2.is_eq(&one)?)
}
}
impl<E, P> AllocVar<PreparedVerifyingKey<E>, E::Fq> for PreparedVerifyingKeyVar<E, P>
where
E: PairingEngine,
P: PairingVar<E>,
P::G1PreparedVar: AllocVar<E::G1Prepared, E::Fq>,
P::G2PreparedVar: AllocVar<E::G2Prepared, E::Fq>,
{
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<PreparedVerifyingKey<E>>>(
cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let ns = cs.into();
let cs = ns.cs();
f().and_then(|pvk| {
let pvk = pvk.borrow();
let g_alpha =
P::G1Var::new_variable(r1cs_core::ns!(cs, "g_alpha"), || Ok(pvk.g_alpha), mode)?;
let h_beta =
P::G2Var::new_variable(r1cs_core::ns!(cs, "h_beta"), || Ok(pvk.h_beta), mode)?;
let g_alpha_pc = P::G1PreparedVar::new_variable(
r1cs_core::ns!(cs, "g_alpha_pc"),
|| Ok(pvk.g_alpha.into()),
mode,
)?;
let h_beta_pc = P::G2PreparedVar::new_variable(
r1cs_core::ns!(cs, "h_beta_pc"),
|| Ok(pvk.h_beta.into()),
mode,
)?;
let g_gamma_pc = P::G1PreparedVar::new_variable(
r1cs_core::ns!(cs, "g_gamma_pc"),
|| Ok(&pvk.g_gamma_pc),
mode,
)?;
let h_gamma_pc = P::G2PreparedVar::new_variable(
r1cs_core::ns!(cs, "h_gamma_pc"),
|| Ok(&pvk.h_gamma_pc),
mode,
)?;
let h_pc =
P::G2PreparedVar::new_variable(r1cs_core::ns!(cs, "h_pc"), || Ok(&pvk.h_pc), mode)?;
let query =
Vec::new_variable(r1cs_core::ns!(cs, "query"), || Ok(pvk.query.clone()), mode)?;
Ok(Self {
g_alpha,
h_beta,
g_alpha_pc,
h_beta_pc,
g_gamma_pc,
h_gamma_pc,
h_pc,
query,
})
})
}
}
impl<E, P> AllocVar<VerifyingKey<E>, E::Fq> for VerifyingKeyVar<E, P>
where
E: PairingEngine,
P: PairingVar<E>,
{
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<VerifyingKey<E>>>(
cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let ns = cs.into();
let cs = ns.cs();
f().and_then(|vk| {
let vk = vk.borrow();
let g_alpha_g1 =
P::G1Var::new_variable(r1cs_core::ns!(cs, "g_alpha"), || Ok(vk.g_alpha_g1), mode)?;
let h_g2 = P::G2Var::new_variable(r1cs_core::ns!(cs, "h"), || Ok(vk.h_g2), mode)?;
let h_beta_g2 =
P::G2Var::new_variable(r1cs_core::ns!(cs, "h_beta"), || Ok(vk.h_beta_g2), mode)?;
let g_gamma_g1 =
P::G1Var::new_variable(r1cs_core::ns!(cs, "g_gamma"), || Ok(&vk.g_gamma_g1), mode)?;
let h_gamma_g2 =
P::G2Var::new_variable(r1cs_core::ns!(cs, "h_gamma"), || Ok(&vk.h_gamma_g2), mode)?;
let query =
Vec::new_variable(r1cs_core::ns!(cs, "query"), || Ok(vk.query.clone()), mode)?;
Ok(Self {
h_g2,
g_alpha_g1,
h_beta_g2,
g_gamma_g1,
h_gamma_g2,
query,
})
})
}
}
impl<E, P> AllocVar<Proof<E>, E::Fq> for ProofVar<E, P>
where
E: PairingEngine,
P: PairingVar<E>,
{
#[inline]
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<Proof<E>>>(
cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let ns = cs.into();
let cs = ns.cs();
f().and_then(|proof| {
let Proof { a, b, c } = proof.borrow().clone();
let a = P::G1Var::new_variable(cs.clone(), || Ok(a), mode)?;
let b = P::G2Var::new_variable(cs.clone(), || Ok(b), mode)?;
let c = P::G1Var::new_variable(r1cs_core::ns!(cs, "c"), || Ok(c), mode)?;
Ok(Self { a, b, c })
})
}
}
impl<E, P> ToBytesGadget<E::Fq> for VerifyingKeyVar<E, P>
where
E: PairingEngine,
P: PairingVar<E>,
{
#[inline]
fn to_bytes(&self) -> Result<Vec<UInt8<E::Fq>>, SynthesisError> {
let mut bytes = Vec::new();
bytes.extend_from_slice(&self.h_g2.to_bytes()?);
bytes.extend_from_slice(&self.g_alpha_g1.to_bytes()?);
bytes.extend_from_slice(&self.h_beta_g2.to_bytes()?);
bytes.extend_from_slice(&self.g_gamma_g1.to_bytes()?);
bytes.extend_from_slice(&self.h_gamma_g2.to_bytes()?);
for q in &self.query {
bytes.extend_from_slice(&q.to_bytes()?);
}
Ok(bytes)
}
}
#[cfg(test)]
mod test {
use gm17::*;
use r1cs_core::{
lc, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError,
};
use super::*;
use algebra::{
bls12_377::{Bls12_377, Fq, Fr},
test_rng, BitIteratorLE, Field, PrimeField,
};
use r1cs_std::{bls12_377::PairingVar as Bls12_377PairingVar, boolean::Boolean, Assignment};
use rand::Rng;
type TestProofSystem = Gm17<Bls12_377, Bench<Fr>, Fr>;
type TestVerifierGadget = Gm17VerifierGadget<Bls12_377, Bls12_377PairingVar>;
type TestProofVar = ProofVar<Bls12_377, Bls12_377PairingVar>;
type TestVkVar = VerifyingKeyVar<Bls12_377, Bls12_377PairingVar>;
struct Bench<F: Field> {
inputs: Vec<Option<F>>,
num_constraints: usize,
}
impl<F: Field> ConstraintSynthesizer<F> for Bench<F> {
fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
assert!(self.inputs.len() >= 2);
assert!(self.num_constraints >= self.inputs.len());
let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len());
for input in self.inputs {
let input_var = cs.new_input_variable(|| input.get())?;
variables.push((input, input_var));
}
for i in 0..self.num_constraints {
let new_entry = {
let (input_1_val, input_1_var) = variables[i];
let (input_2_val, input_2_var) = variables[i + 1];
let result_val = input_1_val
.and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2));
let result_var = cs.new_witness_variable(|| {
result_val.ok_or(SynthesisError::AssignmentMissing)
})?;
cs.enforce_constraint(
lc!() + input_1_var,
lc!() + input_2_var,
lc!() + result_var,
)
.unwrap();
(result_val, result_var)
};
variables.push(new_entry);
}
Ok(())
}
}
#[test]
fn gm17_verifier_test() {
let num_inputs = 100;
let num_constraints = num_inputs;
let rng = &mut test_rng();
let mut inputs: Vec<Option<Fr>> = Vec::with_capacity(num_inputs);
for _ in 0..num_inputs {
inputs.push(Some(rng.gen()));
}
let params = {
let c = Bench::<Fr> {
inputs: vec![None; num_inputs],
num_constraints,
};
generate_random_parameters(c, rng).unwrap()
};
{
let proof = {
// Create an instance of our circuit (with the
// witness)
let c = Bench {
inputs: inputs.clone(),
num_constraints,
};
// Create a gm17 proof with our parameters.
create_random_proof(c, &params, rng).unwrap()
};
// assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
let cs = ConstraintSystem::<Fq>::new_ref();
let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect();
let mut input_gadgets = Vec::new();
{
for input in inputs.into_iter() {
let input_bits: Vec<_> = BitIteratorLE::new(input.into_repr()).collect();
let input_bits =
Vec::<Boolean<Fq>>::new_input(r1cs_core::ns!(cs, "Input"), || {
Ok(input_bits)
})
.unwrap();
input_gadgets.push(input_bits);
}
}
let vk_gadget =
TestVkVar::new_input(r1cs_core::ns!(cs, "Vk"), || Ok(&params.vk)).unwrap();
let proof_gadget =
TestProofVar::new_witness(r1cs_core::ns!(cs, "Proof"), || Ok(proof.clone()))
.unwrap();
println!("Time to verify!\n\n\n\n");
<TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::verify(
&vk_gadget,
&input_gadgets,
&proof_gadget,
)
.unwrap()
.enforce_equal(&Boolean::TRUE)
.unwrap();
if !cs.is_satisfied().unwrap() {
println!("=========================================================");
println!("Unsatisfied constraints:");
println!("{:?}", cs.which_is_unsatisfied().unwrap());
println!("=========================================================");
}
// cs.print_named_objects();
assert!(cs.is_satisfied().unwrap());
}
}
}
#[cfg(test)]
mod test_recursive {
use gm17::*;
use r1cs_core::{
lc, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError,
};
use super::*;
use algebra::{
fields::{FftParameters, FpParameters},
mnt4_298::{Fq as MNT4Fq, FqParameters as MNT4FqParameters, Fr as MNT4Fr, MNT4_298},
mnt6_298::{Fq as MNT6Fq, FqParameters as MNT6FqParameters, Fr as MNT6Fr, MNT6_298},
test_rng, BigInteger, Field, PrimeField,
};
use r1cs_std::{
fields::fp::FpVar, mnt4_298::PairingVar as MNT4_298PairingVar,
mnt6_298::PairingVar as MNT6_298PairingVar, uint8::UInt8, Assignment,
};
use rand::Rng;
type TestProofSystem1 = Gm17<MNT6_298, Bench<MNT4Fq>, MNT6Fr>;
type TestVerifierGadget1 = Gm17VerifierGadget<MNT6_298, MNT6_298PairingVar>;
type TestProofVar1 = ProofVar<MNT6_298, MNT6_298PairingVar>;
type TestVkVar1 = VerifyingKeyVar<MNT6_298, MNT6_298PairingVar>;
type TestProofSystem2 = Gm17<MNT4_298, Wrapper, MNT4Fr>;
type TestVerifierGadget2 = Gm17VerifierGadget<MNT4_298, MNT4_298PairingVar>;
type TestProofVar2 = ProofVar<MNT4_298, MNT4_298PairingVar>;
type TestVkVar2 = VerifyingKeyVar<MNT4_298, MNT4_298PairingVar>;
#[derive(Clone)]
struct Bench<F: Field> {
inputs: Vec<Option<F>>,
num_constraints: usize,
}
impl<F: Field> ConstraintSynthesizer<F> for Bench<F> {
fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
assert!(self.inputs.len() >= 2);
assert!(self.num_constraints >= self.inputs.len());
let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len());
for input in self.inputs {
let input_var = cs.new_input_variable(|| input.get())?;
variables.push((input, input_var));
}
for i in 0..self.num_constraints {
let new_entry = {
let (input_1_val, input_1_var) = variables[i];
let (input_2_val, input_2_var) = variables[i + 1];
let result_val = input_1_val
.and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2));
let result_var = cs.new_witness_variable(|| {
result_val.ok_or(SynthesisError::AssignmentMissing)
})?;
cs.enforce_constraint(
lc!() + input_1_var,
lc!() + input_2_var,
lc!() + result_var,
)
.unwrap();
(result_val, result_var)
};
variables.push(new_entry);
}
Ok(())
}
}
struct Wrapper {
inputs: Vec<Option<MNT4Fq>>,
params: Parameters<MNT6_298>,
proof: Proof<MNT6_298>,
}
impl ConstraintSynthesizer<MNT6Fq> for Wrapper {
fn generate_constraints(
self,
cs: ConstraintSystemRef<MNT6Fq>,
) -> Result<(), SynthesisError> {
let params = self.params;
let proof = self.proof;
let inputs: Vec<_> = self
.inputs
.into_iter()
.map(|input| input.unwrap())
.collect();
let input_gadgets;
{
// Chain all input values in one large byte array.
let input_bytes = inputs
.clone()
.into_iter()
.flat_map(|input| {
input
.into_repr()
.as_ref()
.iter()
.flat_map(|l| l.to_le_bytes().to_vec())
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
// Allocate this byte array as input packed into field elements.
let input_bytes =
UInt8::new_input_vec(r1cs_core::ns!(cs, "Input"), &input_bytes[..])?;
// 40 byte
let element_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 8;
input_gadgets = input_bytes
.chunks(element_size)
.map(|chunk| {
chunk
.iter()
.flat_map(|byte| byte.to_bits_le().unwrap())
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
}
let vk_gadget = TestVkVar1::new_witness(r1cs_core::ns!(cs, "Vk"), || Ok(&params.vk))?;
let proof_gadget =
TestProofVar1::new_witness(r1cs_core::ns!(cs, "Proof"), || Ok(proof.clone()))
.unwrap();
<TestVerifierGadget1 as NIZKVerifierGadget<TestProofSystem1, MNT6Fq>>::verify(
&vk_gadget,
&input_gadgets,
&proof_gadget,
)?
.enforce_equal(&Boolean::TRUE)?;
Ok(())
}
}
#[test]
fn gm17_recursive_verifier_test() {
let num_inputs = 5;
let num_constraints = num_inputs;
let rng = &mut test_rng();
let mut inputs: Vec<Option<MNT4Fq>> = Vec::with_capacity(num_inputs);
for _ in 0..num_inputs {
inputs.push(Some(rng.gen()));
}
// Generate inner params and proof.
let inner_params = {
let c = Bench::<MNT4Fq> {
inputs: vec![None; num_inputs],
num_constraints,
};
generate_random_parameters(c, rng).unwrap()
};
let inner_proof = {
// Create an instance of our circuit (with the
// witness)
let c = Bench {
inputs: inputs.clone(),
num_constraints,
};
// Create a gm17 proof with our parameters.
create_random_proof(c, &inner_params, rng).unwrap()
};
// Generate outer params and proof.
let params = {
let c = Wrapper {
inputs: inputs.clone(),
params: inner_params.clone(),
proof: inner_proof.clone(),
};
generate_random_parameters(c, rng).unwrap()
};
{
let proof = {
// Create an instance of our circuit (with the
// witness)
let c = Wrapper {
inputs: inputs.clone(),
params: inner_params.clone(),
proof: inner_proof.clone(),
};
// Create a gm17 proof with our parameters.
create_random_proof(c, &params, rng).unwrap()
};
let cs = ConstraintSystem::<MNT4Fq>::new_ref();
let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect();
let mut input_gadgets = Vec::new();
{
let bigint_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64;
let mut input_bits = Vec::new();
for input in inputs.into_iter() {
let input_gadget =
FpVar::new_input(r1cs_core::ns!(cs, "Input"), || Ok(input)).unwrap();
let mut fp_bits = input_gadget.to_bits_le().unwrap();
// Use 320 bits per element.
for _ in fp_bits.len()..bigint_size {
fp_bits.push(Boolean::constant(false));
}
input_bits.extend_from_slice(&fp_bits);
}
// Pack input bits into field elements of the underlying circuit.
let max_size = 8 * (<MNT6FqParameters as FpParameters>::CAPACITY / 8) as usize;
let max_size = max_size as usize;
let bigint_size = <MNT6FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64;
for chunk in input_bits.chunks(max_size) {
let mut chunk = chunk.to_vec();
let len = chunk.len();
for _ in len..bigint_size {
chunk.push(Boolean::constant(false));
}
input_gadgets.push(chunk);
}
// assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
}
let vk_gadget =
TestVkVar2::new_input(r1cs_core::ns!(cs, "Vk"), || Ok(&params.vk)).unwrap();
let proof_gadget =
TestProofVar2::new_witness(r1cs_core::ns!(cs, "Proof"), || Ok(proof.clone()))
.unwrap();
println!("Time to verify!\n\n\n\n");
<TestVerifierGadget2 as NIZKVerifierGadget<TestProofSystem2, MNT4Fq>>::verify(
&vk_gadget,
&input_gadgets,
&proof_gadget,
)
.unwrap()
.enforce_equal(&Boolean::TRUE)
.unwrap();
if !cs.is_satisfied().unwrap() {
println!("=========================================================");
println!("Unsatisfied constraints:");
println!("{:?}", cs.which_is_unsatisfied().unwrap());
println!("=========================================================");
}
// cs.print_named_objects();
assert!(cs.is_satisfied().unwrap());
}
}
}

+ 0
- 87
crypto-primitives/src/nizk/gm17/mod.rs

@ -1,87 +0,0 @@
use crate::Error;
use algebra_core::PairingEngine;
use gm17::{
create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof,
Parameters, PreparedVerifyingKey, Proof, VerifyingKey,
};
use r1cs_core::ConstraintSynthesizer;
use rand::Rng;
use algebra_core::ToConstraintField;
use core::marker::PhantomData;
use super::NIZK;
#[cfg(feature = "r1cs")]
pub mod constraints;
/// Note: V should serialize its contents to `Vec<E::Fr>` in the same order as
/// during the constraint generation.
pub struct Gm17<
E: PairingEngine,
C: ConstraintSynthesizer<E::Fr>,
V: ToConstraintField<E::Fr> + ?Sized,
> {
#[doc(hidden)]
_engine: PhantomData<E>,
#[doc(hidden)]
_circuit: PhantomData<C>,
#[doc(hidden)]
_verifier_input: PhantomData<V>,
}
impl<E: PairingEngine, C: ConstraintSynthesizer<E::Fr>, V: ToConstraintField<E::Fr> + ?Sized> NIZK
for Gm17<E, C, V>
{
type Circuit = C;
type AssignedCircuit = C;
type VerifierInput = V;
type ProvingParameters = Parameters<E>;
type VerificationParameters = VerifyingKey<E>;
type PreparedVerificationParameters = PreparedVerifyingKey<E>;
type Proof = Proof<E>;
fn setup<R: Rng>(
circuit: Self::Circuit,
rng: &mut R,
) -> Result<
(
Self::ProvingParameters,
Self::PreparedVerificationParameters,
),
Error,
> {
let nizk_time = start_timer!(|| "{Groth-Maller 2017}::Setup");
let pp = generate_random_parameters::<E, Self::Circuit, R>(circuit, rng)?;
let vk = prepare_verifying_key(&pp.vk);
end_timer!(nizk_time);
Ok((pp, vk))
}
fn prove<R: Rng>(
pp: &Self::ProvingParameters,
input_and_witness: Self::AssignedCircuit,
rng: &mut R,
) -> Result<Self::Proof, Error> {
let proof_time = start_timer!(|| "{Groth-Maller 2017}::Prove");
let result = create_random_proof::<E, _, _>(input_and_witness, pp, rng)?;
end_timer!(proof_time);
Ok(result)
}
fn verify(
vk: &Self::PreparedVerificationParameters,
input: &Self::VerifierInput,
proof: &Self::Proof,
) -> Result<bool, Error> {
let verify_time = start_timer!(|| "{Groth-Maller 2017}::Verify");
let conversion_time = start_timer!(|| "Convert input to E::Fr");
let input = input.to_field_elements()?;
end_timer!(conversion_time);
let verification = start_timer!(|| format!("Verify proof w/ input len: {}", input.len()));
let result = verify_proof(&vk, proof, &input)?;
end_timer!(verification);
end_timer!(verify_time);
Ok(result)
}
}

+ 0
- 746
crypto-primitives/src/nizk/groth16/constraints.rs

@ -1,746 +0,0 @@
use crate::{
nizk::{groth16::Groth16, NIZKVerifierGadget},
Vec,
};
use algebra_core::{AffineCurve, PairingEngine, ToConstraintField};
use r1cs_core::{ConstraintSynthesizer, Namespace, SynthesisError};
use r1cs_std::prelude::*;
use core::{borrow::Borrow, marker::PhantomData};
use groth16::{PreparedVerifyingKey, Proof, VerifyingKey};
#[derive(Derivative)]
#[derivative(Clone(bound = "P::G1Var: Clone, P::G2Var: Clone"))]
pub struct ProofVar<E: PairingEngine, P: PairingVar<E>> {
pub a: P::G1Var,
pub b: P::G2Var,
pub c: P::G1Var,
}
#[derive(Derivative)]
#[derivative(
Clone(bound = "P::G1Var: Clone, P::GTVar: Clone, P::G1PreparedVar: Clone, \
P::G2PreparedVar: Clone, ")
)]
pub struct VerifyingKeyVar<E: PairingEngine, P: PairingVar<E>> {
pub alpha_g1: P::G1Var,
pub beta_g2: P::G2Var,
pub gamma_g2: P::G2Var,
pub delta_g2: P::G2Var,
pub gamma_abc_g1: Vec<P::G1Var>,
}
impl<E: PairingEngine, P: PairingVar<E>> VerifyingKeyVar<E, P> {
pub fn prepare(&self) -> Result<PreparedVerifyingKeyVar<E, P>, SynthesisError> {
let alpha_g1_pc = P::prepare_g1(&self.alpha_g1)?;
let beta_g2_pc = P::prepare_g2(&self.beta_g2)?;
let alpha_g1_beta_g2 = P::pairing(alpha_g1_pc, beta_g2_pc)?;
let gamma_g2_neg_pc = P::prepare_g2(&self.gamma_g2.negate()?)?;
let delta_g2_neg_pc = P::prepare_g2(&self.delta_g2.negate()?)?;
Ok(PreparedVerifyingKeyVar {
alpha_g1_beta_g2,
gamma_g2_neg_pc,
delta_g2_neg_pc,
gamma_abc_g1: self.gamma_abc_g1.clone(),
})
}
}
#[derive(Derivative)]
#[derivative(
Clone(bound = "P::G1Var: Clone, P::GTVar: Clone, P::G1PreparedVar: Clone, \
P::G2PreparedVar: Clone, ")
)]
pub struct PreparedVerifyingKeyVar<E: PairingEngine, P: PairingVar<E>> {
pub alpha_g1_beta_g2: P::GTVar,
pub gamma_g2_neg_pc: P::G2PreparedVar,
pub delta_g2_neg_pc: P::G2PreparedVar,
pub gamma_abc_g1: Vec<P::G1Var>,
}
pub struct Groth16VerifierGadget<E, P>
where
E: PairingEngine,
P: PairingVar<E>,
{
_pairing_engine: PhantomData<E>,
_pairing_gadget: PhantomData<P>,
}
impl<E, P, C, V> NIZKVerifierGadget<Groth16<E, C, V>, E::Fq> for Groth16VerifierGadget<E, P>
where
E: PairingEngine,
C: ConstraintSynthesizer<E::Fr>,
V: ToConstraintField<E::Fr>,
P: PairingVar<E>,
{
type PreparedVerificationKeyVar = PreparedVerifyingKeyVar<E, P>;
type VerificationKeyVar = VerifyingKeyVar<E, P>;
type ProofVar = ProofVar<E, P>;
/// Allocates `N::Proof` in `cs` without performing
/// subgroup checks.
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_proof_unchecked<T: Borrow<Proof<E>>>(
cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self::ProofVar, SynthesisError> {
let ns = cs.into();
let cs = ns.cs();
f().and_then(|proof| {
let proof = proof.borrow();
let a = CurveVar::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "Proof.a"),
|| Ok(proof.a.into_projective()),
mode,
)?;
let b = CurveVar::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "Proof.b"),
|| Ok(proof.b.into_projective()),
mode,
)?;
let c = CurveVar::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "Proof.c"),
|| Ok(proof.c.into_projective()),
mode,
)?;
Ok(ProofVar { a, b, c })
})
}
/// Allocates `N::Proof` in `cs` without performing
/// subgroup checks.
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_verification_key_unchecked<T: Borrow<VerifyingKey<E>>>(
cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self::VerificationKeyVar, SynthesisError> {
let ns = cs.into();
let cs = ns.cs();
f().and_then(|vk| {
let vk = vk.borrow();
let alpha_g1 = P::G1Var::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "alpha_g1"),
|| Ok(vk.alpha_g1.into_projective()),
mode,
)?;
let beta_g2 = P::G2Var::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "beta_g2"),
|| Ok(vk.beta_g2.into_projective()),
mode,
)?;
let gamma_g2 = P::G2Var::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "gamma_g2"),
|| Ok(vk.gamma_g2.into_projective()),
mode,
)?;
let delta_g2 = P::G2Var::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "delta_g2"),
|| Ok(vk.delta_g2.into_projective()),
mode,
)?;
let gamma_abc_g1 = vk
.gamma_abc_g1
.iter()
.map(|g| {
P::G1Var::new_variable_omit_prime_order_check(
r1cs_core::ns!(cs, "g"),
|| Ok(g.into_projective()),
mode,
)
})
.collect::<Result<Vec<_>, _>>()?;
Ok(VerifyingKeyVar {
alpha_g1,
beta_g2,
gamma_g2,
delta_g2,
gamma_abc_g1,
})
})
}
#[tracing::instrument(target = "r1cs", skip(vk, input, proof))]
fn verify<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
vk: &Self::VerificationKeyVar,
input: impl IntoIterator<Item = &'a T>,
proof: &Self::ProofVar,
) -> Result<Boolean<E::Fq>, SynthesisError> {
let pvk = vk.prepare()?;
<Self as NIZKVerifierGadget<Groth16<E, C, V>, E::Fq>>::verify_prepared(&pvk, input, proof)
}
#[tracing::instrument(target = "r1cs", skip(pvk, public_inputs, proof))]
fn verify_prepared<'a, T: 'a + ToBitsGadget<E::Fq> + ?Sized>(
pvk: &Self::PreparedVerificationKeyVar,
public_inputs: impl IntoIterator<Item = &'a T>,
proof: &Self::ProofVar,
) -> Result<Boolean<E::Fq>, SynthesisError> {
let pvk = pvk.clone();
let g_ic = {
let mut g_ic: P::G1Var = pvk.gamma_abc_g1[0].clone();
let mut input_len = 1;
let mut public_inputs = public_inputs.into_iter();
for (input, b) in public_inputs.by_ref().zip(pvk.gamma_abc_g1.iter().skip(1)) {
let encoded_input_i: P::G1Var = b.scalar_mul_le(input.to_bits_le()?.iter())?;
g_ic += encoded_input_i;
input_len += 1;
}
// Check that the input and the query in the verification are of the
// same length.
assert!(input_len == pvk.gamma_abc_g1.len() && public_inputs.next().is_none());
g_ic
};
let test_exp = {
let proof_a_prep = P::prepare_g1(&proof.a)?;
let proof_b_prep = P::prepare_g2(&proof.b)?;
let proof_c_prep = P::prepare_g1(&proof.c)?;
let g_ic_prep = P::prepare_g1(&g_ic)?;
P::miller_loop(
&[proof_a_prep, g_ic_prep, proof_c_prep],
&[
proof_b_prep,
pvk.gamma_g2_neg_pc.clone(),
pvk.delta_g2_neg_pc.clone(),
],
)?
};
let test = P::final_exponentiation(&test_exp)?;
test.is_eq(&pvk.alpha_g1_beta_g2)
}
}
impl<E, P> AllocVar<PreparedVerifyingKey<E>, E::Fq> for PreparedVerifyingKeyVar<E, P>
where
E: PairingEngine,
P: PairingVar<E>,
{
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<PreparedVerifyingKey<E>>>(
cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let ns = cs.into();
let cs = ns.cs();
f().and_then(|pvk| {
let pvk = pvk.borrow();
let alpha_g1_beta_g2 = P::GTVar::new_variable(
r1cs_core::ns!(cs, "alpha_g1_beta_g2"),
|| Ok(pvk.alpha_g1_beta_g2),
mode,
)?;
let gamma_g2_neg_pc = P::G2PreparedVar::new_variable(
r1cs_core::ns!(cs, "gamma_g2_neg_pc"),
|| Ok(pvk.gamma_g2_neg_pc.clone()),
mode,
)?;
let delta_g2_neg_pc = P::G2PreparedVar::new_variable(
r1cs_core::ns!(cs, "delta_g2_neg_pc"),
|| Ok(pvk.delta_g2_neg_pc.clone()),
mode,
)?;
let gamma_abc_g1 = Vec::new_variable(
r1cs_core::ns!(cs, "gamma_abc_g1"),
|| Ok(pvk.gamma_abc_g1.clone()),
mode,
)?;
Ok(Self {
alpha_g1_beta_g2,
gamma_g2_neg_pc,
delta_g2_neg_pc,
gamma_abc_g1,
})
})
}
}
impl<E, P> AllocVar<VerifyingKey<E>, E::Fq> for VerifyingKeyVar<E, P>
where
E: PairingEngine,
P: PairingVar<E>,
{
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<VerifyingKey<E>>>(
cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let ns = cs.into();
let cs = ns.cs();
f().and_then(|vk| {
let VerifyingKey {
alpha_g1,
beta_g2,
gamma_g2,
delta_g2,
gamma_abc_g1,
} = vk.borrow().clone();
let alpha_g1 =
P::G1Var::new_variable(r1cs_core::ns!(cs, "alpha_g1"), || Ok(alpha_g1), mode)?;
let beta_g2 =
P::G2Var::new_variable(r1cs_core::ns!(cs, "beta_g2"), || Ok(beta_g2), mode)?;
let gamma_g2 =
P::G2Var::new_variable(r1cs_core::ns!(cs, "gamma_g2"), || Ok(gamma_g2), mode)?;
let delta_g2 =
P::G2Var::new_variable(r1cs_core::ns!(cs, "delta_g2"), || Ok(delta_g2), mode)?;
let gamma_abc_g1 = Vec::new_variable(cs.clone(), || Ok(gamma_abc_g1), mode)?;
Ok(Self {
alpha_g1,
beta_g2,
gamma_g2,
delta_g2,
gamma_abc_g1,
})
})
}
}
impl<E, P> AllocVar<Proof<E>, E::Fq> for ProofVar<E, P>
where
E: PairingEngine,
P: PairingVar<E>,
{
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<Proof<E>>>(
cs: impl Into<Namespace<E::Fq>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let ns = cs.into();
let cs = ns.cs();
f().and_then(|proof| {
let Proof { a, b, c } = proof.borrow().clone();
let a = P::G1Var::new_variable(r1cs_core::ns!(cs, "a"), || Ok(a), mode)?;
let b = P::G2Var::new_variable(r1cs_core::ns!(cs, "b"), || Ok(b), mode)?;
let c = P::G1Var::new_variable(r1cs_core::ns!(cs, "c"), || Ok(c), mode)?;
Ok(Self { a, b, c })
})
}
}
impl<E, P> ToBytesGadget<E::Fq> for VerifyingKeyVar<E, P>
where
E: PairingEngine,
P: PairingVar<E>,
{
#[inline]
#[tracing::instrument(target = "r1cs", skip(self))]
fn to_bytes(&self) -> Result<Vec<UInt8<E::Fq>>, SynthesisError> {
let mut bytes = Vec::new();
bytes.extend_from_slice(&self.alpha_g1.to_bytes()?);
bytes.extend_from_slice(&self.beta_g2.to_bytes()?);
bytes.extend_from_slice(&self.gamma_g2.to_bytes()?);
bytes.extend_from_slice(&self.delta_g2.to_bytes()?);
for g in &self.gamma_abc_g1 {
bytes.extend_from_slice(&g.to_bytes()?);
}
Ok(bytes)
}
}
#[cfg(test)]
mod test {
use groth16::*;
use r1cs_core::{
lc, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError,
};
use super::*;
use algebra::{
bls12_377::{Bls12_377, Fq, Fr},
test_rng, BitIteratorLE, Field, PrimeField,
};
use r1cs_std::{bls12_377::PairingVar as Bls12_377PairingVar, boolean::Boolean, Assignment};
use rand::Rng;
type TestProofSystem = Groth16<Bls12_377, Bench<Fr>, Fr>;
type TestVerifierGadget = Groth16VerifierGadget<Bls12_377, Bls12_377PairingVar>;
type TestProofVar = ProofVar<Bls12_377, Bls12_377PairingVar>;
type TestVkVar = VerifyingKeyVar<Bls12_377, Bls12_377PairingVar>;
struct Bench<F: Field> {
inputs: Vec<Option<F>>,
num_constraints: usize,
}
impl<F: Field> ConstraintSynthesizer<F> for Bench<F> {
fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
assert!(self.inputs.len() >= 2);
assert!(self.num_constraints >= self.inputs.len());
let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len());
for input in self.inputs {
let input_var = cs.new_input_variable(|| input.get())?;
variables.push((input, input_var));
}
for i in 0..self.num_constraints {
let new_entry = {
let (input_1_val, input_1_var) = variables[i];
let (input_2_val, input_2_var) = variables[i + 1];
let result_val = input_1_val
.and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2));
let result_var = cs.new_witness_variable(|| {
result_val.ok_or(SynthesisError::AssignmentMissing)
})?;
cs.enforce_constraint(
lc!() + input_1_var,
lc!() + input_2_var,
lc!() + result_var,
)
.unwrap();
(result_val, result_var)
};
variables.push(new_entry);
}
Ok(())
}
}
#[test]
fn groth16_verifier_test() {
let num_inputs = 100;
let num_constraints = num_inputs;
let rng = &mut test_rng();
let mut inputs: Vec<Option<Fr>> = Vec::with_capacity(num_inputs);
for _ in 0..num_inputs {
inputs.push(Some(rng.gen()));
}
let params = {
let c = Bench::<Fr> {
inputs: vec![None; num_inputs],
num_constraints,
};
generate_random_parameters(c, rng).unwrap()
};
{
let proof = {
// Create an instance of our circuit (with the
// witness)
let c = Bench {
inputs: inputs.clone(),
num_constraints,
};
// Create a groth16 proof with our parameters.
create_random_proof(c, &params, rng).unwrap()
};
// assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
let cs = ConstraintSystem::<Fq>::new_ref();
let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect();
let mut input_gadgets = Vec::new();
{
for input in inputs.into_iter() {
let input_bits = BitIteratorLE::new(input.into_repr()).collect::<Vec<_>>();
let input_bits =
Vec::<Boolean<Fq>>::new_input(r1cs_core::ns!(cs, "Input"), || {
Ok(input_bits)
})
.unwrap();
input_gadgets.push(input_bits);
}
}
let vk_gadget =
TestVkVar::new_input(r1cs_core::ns!(cs, "Vk"), || Ok(&params.vk)).unwrap();
let proof_gadget =
TestProofVar::new_witness(r1cs_core::ns!(cs, "Proof"), || Ok(proof.clone()))
.unwrap();
println!("Time to verify!\n\n\n\n");
<TestVerifierGadget as NIZKVerifierGadget<TestProofSystem, Fq>>::verify(
&vk_gadget,
&input_gadgets,
&proof_gadget,
)
.unwrap()
.enforce_equal(&Boolean::TRUE)
.unwrap();
if !cs.is_satisfied().unwrap() {
println!("=========================================================");
println!("Unsatisfied constraints:");
println!("{:?}", cs.which_is_unsatisfied().unwrap());
println!("=========================================================");
}
// cs.print_named_objects();
assert!(cs.is_satisfied().unwrap());
}
}
}
#[cfg(test)]
mod test_recursive {
use groth16::*;
use r1cs_core::{
lc, ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, SynthesisError,
};
use super::*;
use algebra::{
fields::{FftParameters, FpParameters},
mnt4_298::{Fq as MNT4Fq, FqParameters as MNT4FqParameters, Fr as MNT4Fr, MNT4_298},
mnt6_298::{Fq as MNT6Fq, FqParameters as MNT6FqParameters, Fr as MNT6Fr, MNT6_298},
test_rng, BigInteger, Field, PrimeField,
};
use r1cs_std::{
fields::fp::FpVar, mnt4_298::PairingVar as MNT4_298PairingVar,
mnt6_298::PairingVar as MNT6_298PairingVar, uint8::UInt8, Assignment,
};
use rand::Rng;
type TestProofSystem1 = Groth16<MNT6_298, Bench<MNT4Fq>, MNT6Fr>;
type TestVerifierGadget1 = Groth16VerifierGadget<MNT6_298, MNT6_298PairingVar>;
type TestProofVar1 = ProofVar<MNT6_298, MNT6_298PairingVar>;
type TestVkVar1 = VerifyingKeyVar<MNT6_298, MNT6_298PairingVar>;
type TestProofSystem2 = Groth16<MNT4_298, Wrapper, MNT4Fr>;
type TestVerifierGadget2 = Groth16VerifierGadget<MNT4_298, MNT4_298PairingVar>;
type TestProofVar2 = ProofVar<MNT4_298, MNT4_298PairingVar>;
type TestVkVar2 = VerifyingKeyVar<MNT4_298, MNT4_298PairingVar>;
#[derive(Clone)]
struct Bench<F: Field> {
inputs: Vec<Option<F>>,
num_constraints: usize,
}
impl<F: Field> ConstraintSynthesizer<F> for Bench<F> {
fn generate_constraints(self, cs: ConstraintSystemRef<F>) -> Result<(), SynthesisError> {
assert!(self.inputs.len() >= 2);
assert!(self.num_constraints >= self.inputs.len());
let mut variables: Vec<_> = Vec::with_capacity(self.inputs.len());
for input in self.inputs {
let input_var = cs.new_input_variable(|| input.get())?;
variables.push((input, input_var));
}
for i in 0..self.num_constraints {
let new_entry = {
let (input_1_val, input_1_var) = variables[i];
let (input_2_val, input_2_var) = variables[i + 1];
let result_val = input_1_val
.and_then(|input_1| input_2_val.map(|input_2| input_1 * &input_2));
let result_var = cs.new_witness_variable(|| {
result_val.ok_or(SynthesisError::AssignmentMissing)
})?;
cs.enforce_constraint(
lc!() + input_1_var,
lc!() + input_2_var,
lc!() + result_var,
)
.unwrap();
(result_val, result_var)
};
variables.push(new_entry);
}
Ok(())
}
}
struct Wrapper {
inputs: Vec<Option<MNT4Fq>>,
params: Parameters<MNT6_298>,
proof: Proof<MNT6_298>,
}
impl ConstraintSynthesizer<MNT6Fq> for Wrapper {
fn generate_constraints(
self,
cs: ConstraintSystemRef<MNT6Fq>,
) -> Result<(), SynthesisError> {
let params = self.params;
let proof = self.proof;
let inputs: Vec<_> = self
.inputs
.into_iter()
.map(|input| input.unwrap())
.collect();
let input_gadgets;
{
// Chain all input values in one large byte array.
let input_bytes = inputs
.clone()
.into_iter()
.flat_map(|input| {
input
.into_repr()
.as_ref()
.iter()
.flat_map(|l| l.to_le_bytes().to_vec())
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
// Allocate this byte array as input packed into field elements.
let input_bytes =
UInt8::new_input_vec(r1cs_core::ns!(cs, "Input"), &input_bytes[..])?;
// 40 byte
let element_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 8;
input_gadgets = input_bytes
.chunks(element_size)
.map(|chunk| {
chunk
.iter()
.flat_map(|byte| byte.to_bits_le().unwrap())
.collect::<Vec<_>>()
})
.collect::<Vec<_>>();
}
let vk_gadget = TestVkVar1::new_witness(r1cs_core::ns!(cs, "Vk"), || Ok(&params.vk))?;
let proof_gadget =
TestProofVar1::new_witness(r1cs_core::ns!(cs, "Proof"), || Ok(proof.clone()))
.unwrap();
<TestVerifierGadget1 as NIZKVerifierGadget<TestProofSystem1, MNT6Fq>>::verify(
&vk_gadget,
&input_gadgets,
&proof_gadget,
)?
.enforce_equal(&Boolean::TRUE)?;
Ok(())
}
}
#[test]
fn groth16_recursive_verifier_test() {
let num_inputs = 5;
let num_constraints = num_inputs;
let rng = &mut test_rng();
let mut inputs: Vec<Option<MNT4Fq>> = Vec::with_capacity(num_inputs);
for _ in 0..num_inputs {
inputs.push(Some(rng.gen()));
}
// Generate inner params and proof.
let inner_params = {
let c = Bench::<MNT4Fq> {
inputs: vec![None; num_inputs],
num_constraints,
};
generate_random_parameters(c, rng).unwrap()
};
let inner_proof = {
// Create an instance of our circuit (with the
// witness)
let c = Bench {
inputs: inputs.clone(),
num_constraints,
};
// Create a groth16 proof with our parameters.
create_random_proof(c, &inner_params, rng).unwrap()
};
// Generate outer params and proof.
let params = {
let c = Wrapper {
inputs: inputs.clone(),
params: inner_params.clone(),
proof: inner_proof.clone(),
};
generate_random_parameters(c, rng).unwrap()
};
{
let proof = {
// Create an instance of our circuit (with the
// witness)
let c = Wrapper {
inputs: inputs.clone(),
params: inner_params.clone(),
proof: inner_proof.clone(),
};
// Create a groth16 proof with our parameters.
create_random_proof(c, &params, rng).unwrap()
};
let cs = ConstraintSystem::<MNT4Fq>::new_ref();
let inputs: Vec<_> = inputs.into_iter().map(|input| input.unwrap()).collect();
let mut input_gadgets = Vec::new();
{
let bigint_size = <MNT4FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64;
let mut input_bits = Vec::new();
for input in inputs.into_iter() {
let input_gadget =
FpVar::new_input(r1cs_core::ns!(cs, "Input"), || Ok(input)).unwrap();
let mut fp_bits = input_gadget.to_bits_le().unwrap();
// Use 320 bits per element.
for _ in fp_bits.len()..bigint_size {
fp_bits.push(Boolean::constant(false));
}
input_bits.extend_from_slice(&fp_bits);
}
// Pack input bits into field elements of the underlying circuit.
let max_size = 8 * (<MNT6FqParameters as FpParameters>::CAPACITY / 8) as usize;
let max_size = max_size as usize;
let bigint_size = <MNT6FqParameters as FftParameters>::BigInt::NUM_LIMBS * 64;
for chunk in input_bits.chunks(max_size) {
let mut chunk = chunk.to_vec();
let len = chunk.len();
for _ in len..bigint_size {
chunk.push(Boolean::constant(false));
}
input_gadgets.push(chunk);
}
// assert!(!verify_proof(&pvk, &proof, &[a]).unwrap());
}
let vk_gadget =
TestVkVar2::new_input(r1cs_core::ns!(cs, "Vk"), || Ok(&params.vk)).unwrap();
let proof_gadget =
TestProofVar2::new_witness(r1cs_core::ns!(cs, "Proof"), || Ok(proof.clone()))
.unwrap();
println!("Time to verify!\n\n\n\n");
<TestVerifierGadget2 as NIZKVerifierGadget<TestProofSystem2, MNT4Fq>>::verify(
&vk_gadget,
&input_gadgets,
&proof_gadget,
)
.unwrap()
.enforce_equal(&Boolean::TRUE)
.unwrap();
if !cs.is_satisfied().unwrap() {
println!("=========================================================");
println!("Unsatisfied constraints:");
println!("{:?}", cs.which_is_unsatisfied().unwrap());
println!("=========================================================");
}
assert!(cs.is_satisfied().unwrap());
}
}
}

+ 0
- 87
crypto-primitives/src/nizk/groth16/mod.rs

@ -1,87 +0,0 @@
use crate::Error;
use algebra_core::PairingEngine;
use groth16::{
create_random_proof, generate_random_parameters, prepare_verifying_key, verify_proof,
Parameters, PreparedVerifyingKey, Proof, VerifyingKey,
};
use r1cs_core::ConstraintSynthesizer;
use rand::Rng;
use algebra_core::ToConstraintField;
use core::marker::PhantomData;
use super::NIZK;
#[cfg(feature = "r1cs")]
pub mod constraints;
/// Note: V should serialize its contents to `Vec<E::Fr>` in the same order as
/// during the constraint generation.
pub struct Groth16<
E: PairingEngine,
C: ConstraintSynthesizer<E::Fr>,
V: ToConstraintField<E::Fr> + ?Sized,
> {
#[doc(hidden)]
_engine: PhantomData<E>,
#[doc(hidden)]
_circuit: PhantomData<C>,
#[doc(hidden)]
_verifier_input: PhantomData<V>,
}
impl<E: PairingEngine, C: ConstraintSynthesizer<E::Fr>, V: ToConstraintField<E::Fr> + ?Sized> NIZK
for Groth16<E, C, V>
{
type Circuit = C;
type AssignedCircuit = C;
type VerifierInput = V;
type ProvingParameters = Parameters<E>;
type VerificationParameters = VerifyingKey<E>;
type PreparedVerificationParameters = PreparedVerifyingKey<E>;
type Proof = Proof<E>;
fn setup<R: Rng>(
circuit: Self::Circuit,
rng: &mut R,
) -> Result<
(
Self::ProvingParameters,
Self::PreparedVerificationParameters,
),
Error,
> {
let nizk_time = start_timer!(|| "{Groth 2016}::Setup");
let pp = generate_random_parameters::<E, Self::Circuit, R>(circuit, rng)?;
let vk = prepare_verifying_key(&pp.vk);
end_timer!(nizk_time);
Ok((pp, vk))
}
fn prove<R: Rng>(
pp: &Self::ProvingParameters,
input_and_witness: Self::AssignedCircuit,
rng: &mut R,
) -> Result<Self::Proof, Error> {
let proof_time = start_timer!(|| "{Groth 2016}::Prove");
let result = create_random_proof::<E, _, _>(input_and_witness, pp, rng)?;
end_timer!(proof_time);
Ok(result)
}
fn verify(
vk: &Self::PreparedVerificationParameters,
input: &Self::VerifierInput,
proof: &Self::Proof,
) -> Result<bool, Error> {
let verify_time = start_timer!(|| "{Groth 2016}::Verify");
let conversion_time = start_timer!(|| "Convert input to E::Fr");
let input = input.to_field_elements()?;
end_timer!(conversion_time);
let verification = start_timer!(|| format!("Verify proof w/ input len: {}", input.len()));
let result = verify_proof(&vk, proof, &input)?;
end_timer!(verification);
end_timer!(verify_time);
Ok(result)
}
}

+ 0
- 115
crypto-primitives/src/nizk/mod.rs

@ -1,115 +0,0 @@
use algebra_core::bytes::ToBytes;
use rand::Rng;
#[cfg(feature = "gm17")]
pub mod gm17;
#[cfg(feature = "gm17")]
pub use self::gm17::Gm17;
#[cfg(feature = "groth16")]
pub mod groth16;
#[cfg(feature = "groth16")]
pub use self::groth16::Groth16;
#[cfg(feature = "r1cs")]
pub mod constraints;
#[cfg(feature = "r1cs")]
pub use constraints::*;
use crate::Error;
pub trait NIZK {
type Circuit;
type AssignedCircuit;
type VerifierInput: ?Sized;
type ProvingParameters: Clone;
type VerificationParameters: Clone + Default + From<Self::PreparedVerificationParameters>;
type PreparedVerificationParameters: Clone + Default + From<Self::VerificationParameters>;
type Proof: ToBytes + Clone + Default;
fn setup<R: Rng>(
circuit: Self::Circuit,
rng: &mut R,
) -> Result<
(
Self::ProvingParameters,
Self::PreparedVerificationParameters,
),
Error,
>;
fn prove<R: Rng>(
parameter: &Self::ProvingParameters,
input_and_witness: Self::AssignedCircuit,
rng: &mut R,
) -> Result<Self::Proof, Error>;
fn verify(
verifier_key: &Self::PreparedVerificationParameters,
input: &Self::VerifierInput,
proof: &Self::Proof,
) -> Result<bool, Error>;
}
#[cfg(all(feature = "gm17", test))]
mod test {
use algebra::test_rng;
use core::ops::AddAssign;
#[test]
fn test_gm17() {
use crate::nizk::{gm17::Gm17, NIZK};
use algebra::{
bls12_377::{Bls12_377, Fr},
One,
};
use r1cs_core::{lc, ConstraintSynthesizer, ConstraintSystemRef, SynthesisError, Variable};
#[derive(Copy, Clone)]
struct R1CSCircuit {
x: Option<Fr>,
sum: Option<Fr>,
w: Option<Fr>,
}
impl R1CSCircuit {
pub(super) fn new(x: Fr, sum: Fr, w: Fr) -> Self {
Self {
x: Some(x),
sum: Some(sum),
w: Some(w),
}
}
}
impl ConstraintSynthesizer<Fr> for R1CSCircuit {
fn generate_constraints(
self,
cs: ConstraintSystemRef<Fr>,
) -> Result<(), SynthesisError> {
let input = cs.new_input_variable(|| Ok(self.x.unwrap()))?;
let sum = cs.new_input_variable(|| Ok(self.sum.unwrap()))?;
let witness = cs.new_witness_variable(|| Ok(self.w.unwrap()))?;
cs.enforce_constraint(lc!() + sum, lc!() + Variable::One, lc!() + input + witness)?;
Ok(())
}
}
let mut sum = Fr::one();
sum.add_assign(&Fr::one());
let circuit = R1CSCircuit::new(Fr::one(), sum, Fr::one());
let rng = &mut test_rng();
let parameters = Gm17::<Bls12_377, R1CSCircuit, [Fr]>::setup(circuit, rng).unwrap();
let proof =
Gm17::<Bls12_377, R1CSCircuit, [Fr]>::prove(&parameters.0, circuit, rng).unwrap();
let result =
Gm17::<Bls12_377, R1CSCircuit, [Fr]>::verify(&parameters.1, &[Fr::one(), sum], &proof)
.unwrap();
assert!(result);
}
}

+ 0
- 537
crypto-primitives/src/prf/blake2s/constraints.rs

@ -1,537 +0,0 @@
use algebra_core::PrimeField;
use r1cs_core::{ConstraintSystemRef, Namespace, SynthesisError};
use crate::{prf::PRFGadget, Vec};
use r1cs_std::prelude::*;
use core::borrow::Borrow;
// 2.1. Parameters
// The following table summarizes various parameters and their ranges:
// | BLAKE2b | BLAKE2s |
// --------------+------------------+------------------+
// Bits in word | w = 64 | w = 32 |
// Rounds in F | r = 12 | r = 10 |
// Block bytes | bb = 128 | bb = 64 |
// Hash bytes | 1 <= nn <= 64 | 1 <= nn <= 32 |
// Key bytes | 0 <= kk <= 64 | 0 <= kk <= 32 |
// Input bytes | 0 <= ll < 2**128 | 0 <= ll < 2**64 |
// --------------+------------------+------------------+
// G Rotation | (R1, R2, R3, R4) | (R1, R2, R3, R4) |
// constants = | (32, 24, 16, 63) | (16, 12, 8, 7) |
// --------------+------------------+------------------+
//
const R1: usize = 16;
const R2: usize = 12;
const R3: usize = 8;
const R4: usize = 7;
// Round | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// ----------+-------------------------------------------------+
// SIGMA[0] | 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// SIGMA[1] | 14 10 4 8 9 15 13 6 1 12 0 2 11 7 5 3 |
// SIGMA[2] | 11 8 12 0 5 2 15 13 10 14 3 6 7 1 9 4 |
// SIGMA[3] | 7 9 3 1 13 12 11 14 2 6 5 10 4 0 15 8 |
// SIGMA[4] | 9 0 5 7 2 4 10 15 14 1 11 12 6 8 3 13 |
// SIGMA[5] | 2 12 6 10 0 11 8 3 4 13 7 5 15 14 1 9 |
// SIGMA[6] | 12 5 1 15 14 13 4 10 0 7 6 3 9 2 8 11 |
// SIGMA[7] | 13 11 7 14 12 1 3 9 5 0 15 4 8 6 2 10 |
// SIGMA[8] | 6 15 14 9 11 3 0 8 12 2 13 7 1 4 10 5 |
// SIGMA[9] | 10 2 8 4 7 6 1 5 15 11 9 14 3 12 13 0 |
// ----------+-------------------------------------------------+
//
const SIGMA: [[usize; 16]; 10] = [
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
[14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
[11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
[7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
[9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
[2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
[12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
[13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
[6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
];
// 3.1. Mixing Function G
// The G primitive function mixes two input words, "x" and "y", into
// four words indexed by "a", "b", "c", and "d" in the working vector
// v[0..15]. The full modified vector is returned. The rotation
// constants (R1, R2, R3, R4) are given in Section 2.1.
// FUNCTION G( v[0..15], a, b, c, d, x, y )
// |
// | v[a] := (v[a] + v[b] + x) mod 2**w
// | v[d] := (v[d] ^ v[a]) >>> R1
// | v[c] := (v[c] + v[d]) mod 2**w
// | v[b] := (v[b] ^ v[c]) >>> R2
// | v[a] := (v[a] + v[b] + y) mod 2**w
// | v[d] := (v[d] ^ v[a]) >>> R3
// | v[c] := (v[c] + v[d]) mod 2**w
// | v[b] := (v[b] ^ v[c]) >>> R4
// |
// | RETURN v[0..15]
// |
// END FUNCTION.
//
fn mixing_g<ConstraintF: PrimeField>(
v: &mut [UInt32<ConstraintF>],
a: usize,
b: usize,
c: usize,
d: usize,
x: &UInt32<ConstraintF>,
y: &UInt32<ConstraintF>,
) -> Result<(), SynthesisError> {
v[a] = UInt32::addmany(&[v[a].clone(), v[b].clone(), x.clone()])?;
v[d] = v[d].xor(&v[a])?.rotr(R1);
v[c] = UInt32::addmany(&[v[c].clone(), v[d].clone()])?;
v[b] = v[b].xor(&v[c])?.rotr(R2);
v[a] = UInt32::addmany(&[v[a].clone(), v[b].clone(), y.clone()])?;
v[d] = v[d].xor(&v[a])?.rotr(R3);
v[c] = UInt32::addmany(&[v[c].clone(), v[d].clone()])?;
v[b] = v[b].xor(&v[c])?.rotr(R4);
Ok(())
}
// 3.2. Compression Function F
// Compression function F takes as an argument the state vector "h",
// message block vector "m" (last block is padded with zeros to full
// block size, if required), 2w-bit offset counter "t", and final block
// indicator flag "f". Local vector v[0..15] is used in processing. F
// returns a new state vector. The number of rounds, "r", is 12 for
// BLAKE2b and 10 for BLAKE2s. Rounds are numbered from 0 to r - 1.
// FUNCTION F( h[0..7], m[0..15], t, f )
// |
// | // Initialize local work vector v[0..15]
// | v[0..7] := h[0..7] // First half from state.
// | v[8..15] := IV[0..7] // Second half from IV.
// |
// | v[12] := v[12] ^ (t mod 2**w) // Low word of the offset.
// | v[13] := v[13] ^ (t >> w) // High word.
// |
// | IF f = TRUE THEN // last block flag?
// | | v[14] := v[14] ^ 0xFF..FF // Invert all bits.
// | END IF.
// |
// | // Cryptographic mixing
// | FOR i = 0 TO r - 1 DO // Ten or twelve rounds.
// | |
// | | // Message word selection permutation for this round.
// | | s[0..15] := SIGMA[i mod 10][0..15]
// | |
// | | v := G( v, 0, 4, 8, 12, m[s[ 0]], m[s[ 1]] )
// | | v := G( v, 1, 5, 9, 13, m[s[ 2]], m[s[ 3]] )
// | | v := G( v, 2, 6, 10, 14, m[s[ 4]], m[s[ 5]] )
// | | v := G( v, 3, 7, 11, 15, m[s[ 6]], m[s[ 7]] )
// | |
// | | v := G( v, 0, 5, 10, 15, m[s[ 8]], m[s[ 9]] )
// | | v := G( v, 1, 6, 11, 12, m[s[10]], m[s[11]] )
// | | v := G( v, 2, 7, 8, 13, m[s[12]], m[s[13]] )
// | | v := G( v, 3, 4, 9, 14, m[s[14]], m[s[15]] )
// | |
// | END FOR
// |
// | FOR i = 0 TO 7 DO // XOR the two halves.
// | | h[i] := h[i] ^ v[i] ^ v[i + 8]
// | END FOR.
// |
// | RETURN h[0..7] // New state.
// |
// END FUNCTION.
//
fn blake2s_compression<ConstraintF: PrimeField>(
h: &mut [UInt32<ConstraintF>],
m: &[UInt32<ConstraintF>],
t: u64,
f: bool,
) -> Result<(), SynthesisError> {
assert_eq!(h.len(), 8);
assert_eq!(m.len(), 16);
// static const uint32_t blake2s_iv[8] =
// {
// 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
// 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
// };
//
let mut v = Vec::with_capacity(16);
v.extend_from_slice(h);
v.push(UInt32::constant(0x6A09E667));
v.push(UInt32::constant(0xBB67AE85));
v.push(UInt32::constant(0x3C6EF372));
v.push(UInt32::constant(0xA54FF53A));
v.push(UInt32::constant(0x510E527F));
v.push(UInt32::constant(0x9B05688C));
v.push(UInt32::constant(0x1F83D9AB));
v.push(UInt32::constant(0x5BE0CD19));
assert_eq!(v.len(), 16);
v[12] = v[12].xor(&UInt32::constant(t as u32))?;
v[13] = v[13].xor(&UInt32::constant((t >> 32) as u32))?;
if f {
v[14] = v[14].xor(&UInt32::constant(u32::max_value()))?;
}
for i in 0..10 {
let s = SIGMA[i % 10];
mixing_g(&mut v, 0, 4, 8, 12, &m[s[0]], &m[s[1]])?;
mixing_g(&mut v, 1, 5, 9, 13, &m[s[2]], &m[s[3]])?;
mixing_g(&mut v, 2, 6, 10, 14, &m[s[4]], &m[s[5]])?;
mixing_g(&mut v, 3, 7, 11, 15, &m[s[6]], &m[s[7]])?;
mixing_g(&mut v, 0, 5, 10, 15, &m[s[8]], &m[s[9]])?;
mixing_g(&mut v, 1, 6, 11, 12, &m[s[10]], &m[s[11]])?;
mixing_g(&mut v, 2, 7, 8, 13, &m[s[12]], &m[s[13]])?;
mixing_g(&mut v, 3, 4, 9, 14, &m[s[14]], &m[s[15]])?;
}
for i in 0..8 {
h[i] = h[i].xor(&v[i])?;
h[i] = h[i].xor(&v[i + 8])?;
}
Ok(())
}
// FUNCTION BLAKE2( d[0..dd-1], ll, kk, nn )
// |
// | h[0..7] := IV[0..7] // Initialization Vector.
// |
// | // Parameter block p[0]
// | h[0] := h[0] ^ 0x01010000 ^ (kk << 8) ^ nn
// |
// | // Process padded key and data blocks
// | IF dd > 1 THEN
// | | FOR i = 0 TO dd - 2 DO
// | | | h := F( h, d[i], (i + 1) * bb, FALSE )
// | | END FOR.
// | END IF.
// |
// | // Final block.
// | IF kk = 0 THEN
// | | h := F( h, d[dd - 1], ll, TRUE )
// | ELSE
// | | h := F( h, d[dd - 1], ll + bb, TRUE )
// | END IF.
// |
// | RETURN first "nn" bytes from little-endian word array h[].
// |
// END FUNCTION.
//
pub fn evaluate_blake2s<ConstraintF: PrimeField>(
input: &[Boolean<ConstraintF>],
) -> Result<Vec<UInt32<ConstraintF>>, SynthesisError> {
assert!(input.len() % 8 == 0);
let mut parameters = [0; 8];
parameters[0] = 0x01010000 ^ 32;
evaluate_blake2s_with_parameters(input, &parameters)
}
pub fn evaluate_blake2s_with_parameters<F: PrimeField>(
input: &[Boolean<F>],
parameters: &[u32; 8],
) -> Result<Vec<UInt32<F>>, SynthesisError> {
assert!(input.len() % 8 == 0);
let mut h = Vec::with_capacity(8);
h.push(UInt32::constant(0x6A09E667).xor(&UInt32::constant(parameters[0]))?);
h.push(UInt32::constant(0xBB67AE85).xor(&UInt32::constant(parameters[1]))?);
h.push(UInt32::constant(0x3C6EF372).xor(&UInt32::constant(parameters[2]))?);
h.push(UInt32::constant(0xA54FF53A).xor(&UInt32::constant(parameters[3]))?);
h.push(UInt32::constant(0x510E527F).xor(&UInt32::constant(parameters[4]))?);
h.push(UInt32::constant(0x9B05688C).xor(&UInt32::constant(parameters[5]))?);
h.push(UInt32::constant(0x1F83D9AB).xor(&UInt32::constant(parameters[6]))?);
h.push(UInt32::constant(0x5BE0CD19).xor(&UInt32::constant(parameters[7]))?);
let mut blocks: Vec<Vec<UInt32<F>>> = vec![];
for block in input.chunks(512) {
let mut this_block = Vec::with_capacity(16);
for word in block.chunks(32) {
let mut tmp = word.to_vec();
while tmp.len() < 32 {
tmp.push(Boolean::constant(false));
}
this_block.push(UInt32::from_bits_le(&tmp));
}
while this_block.len() < 16 {
this_block.push(UInt32::constant(0));
}
blocks.push(this_block);
}
if blocks.is_empty() {
blocks.push((0..16).map(|_| UInt32::constant(0)).collect());
}
for (i, block) in blocks[0..blocks.len() - 1].iter().enumerate() {
blake2s_compression(&mut h, block, ((i as u64) + 1) * 64, false)?;
}
blake2s_compression(
&mut h,
&blocks[blocks.len() - 1],
(input.len() / 8) as u64,
true,
)?;
Ok(h)
}
use crate::prf::Blake2s;
pub struct Blake2sGadget;
#[derive(Clone, Debug)]
pub struct OutputVar<ConstraintF: PrimeField>(pub Vec<UInt8<ConstraintF>>);
impl<ConstraintF: PrimeField> EqGadget<ConstraintF> for OutputVar<ConstraintF> {
#[tracing::instrument(target = "r1cs")]
fn is_eq(&self, other: &Self) -> Result<Boolean<ConstraintF>, SynthesisError> {
self.0.is_eq(&other.0)
}
/// If `should_enforce == true`, enforce that `self` and `other` are equal; else,
/// enforce a vacuously true statement.
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_equal(
&self,
other: &Self,
should_enforce: &Boolean<ConstraintF>,
) -> Result<(), SynthesisError> {
self.0.conditional_enforce_equal(&other.0, should_enforce)
}
/// If `should_enforce == true`, enforce that `self` and `other` are not equal; else,
/// enforce a vacuously true statement.
#[tracing::instrument(target = "r1cs")]
fn conditional_enforce_not_equal(
&self,
other: &Self,
should_enforce: &Boolean<ConstraintF>,
) -> Result<(), SynthesisError> {
self.0
.as_slice()
.conditional_enforce_not_equal(other.0.as_slice(), should_enforce)
}
}
impl<ConstraintF: PrimeField> ToBytesGadget<ConstraintF> for OutputVar<ConstraintF> {
#[inline]
fn to_bytes(&self) -> Result<Vec<UInt8<ConstraintF>>, SynthesisError> {
Ok(self.0.clone())
}
}
impl<ConstraintF: PrimeField> AllocVar<[u8; 32], ConstraintF> for OutputVar<ConstraintF> {
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_variable<T: Borrow<[u8; 32]>>(
cs: impl Into<Namespace<ConstraintF>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let bytes = f().map(|b| *b.borrow()).unwrap_or([0u8; 32]);
match mode {
AllocationMode::Constant => Ok(Self(UInt8::constant_vec(&bytes))),
AllocationMode::Input => UInt8::new_input_vec(cs, &bytes).map(Self),
AllocationMode::Witness => UInt8::new_witness_vec(cs, &bytes).map(Self),
}
}
}
impl<F: PrimeField> R1CSVar<F> for OutputVar<F> {
type Value = [u8; 32];
fn cs(&self) -> ConstraintSystemRef<F> {
self.0.cs()
}
fn value(&self) -> Result<Self::Value, SynthesisError> {
let mut value = [0u8; 32];
for (val_i, self_i) in value.iter_mut().zip(&self.0) {
*val_i = self_i.value()?;
}
Ok(value)
}
}
impl<F: PrimeField> PRFGadget<Blake2s, F> for Blake2sGadget {
type OutputVar = OutputVar<F>;
#[tracing::instrument(target = "r1cs", skip(cs))]
fn new_seed(cs: impl Into<Namespace<F>>, seed: &[u8; 32]) -> Vec<UInt8<F>> {
let ns = cs.into();
let cs = ns.cs();
UInt8::new_witness_vec(r1cs_core::ns!(cs, "New Blake2s seed"), seed).unwrap()
}
#[tracing::instrument(target = "r1cs", skip(seed, input))]
fn evaluate(seed: &[UInt8<F>], input: &[UInt8<F>]) -> Result<Self::OutputVar, SynthesisError> {
assert_eq!(seed.len(), 32);
let input: Vec<_> = seed
.iter()
.chain(input)
.flat_map(|b| b.to_bits_le().unwrap())
.collect();
let result: Vec<_> = evaluate_blake2s(&input)?
.into_iter()
.flat_map(|int| int.to_bytes().unwrap())
.collect();
Ok(OutputVar(result))
}
}
#[cfg(test)]
mod test {
use algebra::ed_on_bls12_381::Fq as Fr;
use rand::{Rng, SeedableRng};
use rand_xorshift::XorShiftRng;
use crate::prf::blake2s::{constraints::evaluate_blake2s, Blake2s as B2SPRF};
use blake2::VarBlake2s;
use r1cs_core::ConstraintSystem;
use super::Blake2sGadget;
use r1cs_std::prelude::*;
#[test]
fn test_blake2s_constraints() {
let cs = ConstraintSystem::<Fr>::new_ref();
let input_bits: Vec<_> = (0..512)
.map(|_| Boolean::new_witness(r1cs_core::ns!(cs, "input bit"), || Ok(true)).unwrap())
.collect();
evaluate_blake2s(&input_bits).unwrap();
assert!(cs.is_satisfied().unwrap());
assert_eq!(cs.num_constraints(), 21792);
}
#[test]
fn test_blake2s_prf() {
use crate::prf::{PRFGadget, PRF};
use rand::Rng;
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
let cs = ConstraintSystem::<Fr>::new_ref();
let mut seed = [0u8; 32];
rng.fill(&mut seed);
let mut input = [0u8; 32];
rng.fill(&mut input);
let seed_var = Blake2sGadget::new_seed(cs.clone(), &seed);
let input_var =
UInt8::new_witness_vec(r1cs_core::ns!(cs, "declare_input"), &input).unwrap();
let out = B2SPRF::evaluate(&seed, &input).unwrap();
let actual_out_var = <Blake2sGadget as PRFGadget<_, Fr>>::OutputVar::new_witness(
r1cs_core::ns!(cs, "declare_output"),
|| Ok(out),
)
.unwrap();
let output_var = Blake2sGadget::evaluate(&seed_var, &input_var).unwrap();
output_var.enforce_equal(&actual_out_var).unwrap();
if !cs.is_satisfied().unwrap() {
println!(
"which is unsatisfied: {:?}",
cs.which_is_unsatisfied().unwrap()
);
}
assert!(cs.is_satisfied().unwrap());
}
#[test]
fn test_blake2s_precomp_constraints() {
// Test that 512 fixed leading bits (constants)
// doesn't result in more constraints.
let cs = ConstraintSystem::<Fr>::new_ref();
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
let input_bits: Vec<_> = (0..512)
.map(|_| Boolean::constant(rng.gen()))
.chain((0..512).map(|_| {
Boolean::new_witness(r1cs_core::ns!(cs, "input bit"), || Ok(true)).unwrap()
}))
.collect();
evaluate_blake2s(&input_bits).unwrap();
assert!(cs.is_satisfied().unwrap());
assert_eq!(cs.num_constraints(), 21792);
}
#[test]
fn test_blake2s_constant_constraints() {
let cs = ConstraintSystem::<Fr>::new_ref();
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
let input_bits: Vec<_> = (0..512)
.map(|_| Boolean::<Fr>::constant(rng.gen()))
.collect();
evaluate_blake2s(&input_bits).unwrap();
assert_eq!(cs.num_constraints(), 0);
}
#[test]
fn test_blake2s() {
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for input_len in (0..32).chain((32..256).filter(|a| a % 8 == 0)) {
use digest::*;
let mut h = VarBlake2s::new_keyed(&[], 32);
let data: Vec<u8> = (0..input_len).map(|_| rng.gen()).collect();
h.input(&data);
let mut hash_result = Vec::with_capacity(h.output_size());
h.variable_result(|res| hash_result.extend_from_slice(res));
let cs = ConstraintSystem::<Fr>::new_ref();
let mut input_bits = vec![];
for input_byte in data.into_iter() {
for bit_i in 0..8 {
let cs = r1cs_core::ns!(cs, "input bit");
input_bits.push(
Boolean::new_witness(cs, || Ok((input_byte >> bit_i) & 1u8 == 1u8))
.unwrap(),
);
}
}
let r = evaluate_blake2s(&input_bits).unwrap();
assert!(cs.is_satisfied().unwrap());
let mut s = hash_result
.iter()
.flat_map(|&byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8));
for chunk in r {
for b in chunk.to_bits_le() {
match b {
Boolean::Is(b) => {
assert!(s.next().unwrap() == b.value().unwrap());
}
Boolean::Not(b) => {
assert!(s.next().unwrap() != b.value().unwrap());
}
Boolean::Constant(b) => {
assert!(input_len == 0);
assert!(s.next().unwrap() == b);
}
}
}
}
}
}
}

+ 0
- 92
crypto-primitives/src/prf/blake2s/mod.rs

@ -1,92 +0,0 @@
use alloc::vec::Vec;
use blake2::{Blake2s as B2s, VarBlake2s};
use digest::Digest;
use super::PRF;
use crate::CryptoError;
#[cfg(feature = "r1cs")]
pub mod constraints;
#[derive(Clone)]
pub struct Blake2s;
impl PRF for Blake2s {
type Input = [u8; 32];
type Output = [u8; 32];
type Seed = [u8; 32];
fn evaluate(seed: &Self::Seed, input: &Self::Input) -> Result<Self::Output, CryptoError> {
let eval_time = start_timer!(|| "Blake2s::Eval");
let mut h = B2s::new();
h.input(seed.as_ref());
h.input(input.as_ref());
let mut result = [0u8; 32];
result.copy_from_slice(&h.result());
end_timer!(eval_time);
Ok(result)
}
}
#[derive(Clone)]
pub struct Blake2sWithParameterBlock {
pub digest_length: u8,
pub key_length: u8,
pub fan_out: u8,
pub depth: u8,
pub leaf_length: u32,
pub node_offset: u32,
pub xof_digest_length: u16,
pub node_depth: u8,
pub inner_length: u8,
pub salt: [u8; 8],
pub personalization: [u8; 8],
}
impl Blake2sWithParameterBlock {
pub fn parameters(&self) -> [u32; 8] {
let mut parameters = [0; 8];
parameters[0] = u32::from_le_bytes([
self.digest_length,
self.key_length,
self.fan_out,
self.depth,
]);
parameters[1] = self.leaf_length;
parameters[2] = self.node_offset;
parameters[3] = u32::from_le_bytes([
self.xof_digest_length as u8,
(self.xof_digest_length >> 8) as u8,
self.node_depth,
self.inner_length,
]);
let mut salt_bytes_1 = [0; 4];
let mut salt_bytes_2 = [0; 4];
let mut personalization_bytes_1 = [0; 4];
let mut personalization_bytes_2 = [0; 4];
for i in 0..4 {
salt_bytes_1[i] = self.salt[i];
salt_bytes_2[i] = self.salt[4 + i];
personalization_bytes_1[i] = self.personalization[i];
personalization_bytes_2[i] = self.personalization[4 + i];
}
parameters[4] = u32::from_le_bytes(salt_bytes_1);
parameters[5] = u32::from_le_bytes(salt_bytes_2);
parameters[6] = u32::from_le_bytes(personalization_bytes_1);
parameters[7] = u32::from_le_bytes(personalization_bytes_2);
parameters
}
pub fn evaluate(&self, input: &[u8]) -> Vec<u8> {
use digest::*;
let eval_time = start_timer!(|| "Blake2sWithParameterBlock::Eval");
let mut h = VarBlake2s::with_parameter_block(&self.parameters());
h.input(input.as_ref());
end_timer!(eval_time);
let mut buf = Vec::with_capacity(h.output_size());
h.variable_result(|res| buf.extend_from_slice(res));
buf
}
}

+ 0
- 20
crypto-primitives/src/prf/constraints.rs

@ -1,20 +0,0 @@
use algebra_core::Field;
use core::fmt::Debug;
use crate::{prf::PRF, Vec};
use r1cs_core::{Namespace, SynthesisError};
use r1cs_std::prelude::*;
pub trait PRFGadget<P: PRF, F: Field> {
type OutputVar: EqGadget<F>
+ ToBytesGadget<F>
+ AllocVar<P::Output, F>
+ R1CSVar<F, Value = P::Output>
+ Clone
+ Debug;
fn new_seed(cs: impl Into<Namespace<F>>, seed: &P::Seed) -> Vec<UInt8<F>>;
fn evaluate(seed: &[UInt8<F>], input: &[UInt8<F>]) -> Result<Self::OutputVar, SynthesisError>;
}

+ 0
- 20
crypto-primitives/src/prf/mod.rs

@ -1,20 +0,0 @@
use algebra_core::bytes::{FromBytes, ToBytes};
use core::{fmt::Debug, hash::Hash};
use crate::CryptoError;
#[cfg(feature = "r1cs")]
pub mod constraints;
#[cfg(feature = "r1cs")]
pub use constraints::*;
pub mod blake2s;
pub use self::blake2s::*;
pub trait PRF {
type Input: FromBytes + Default;
type Output: ToBytes + Eq + Clone + Debug + Default + Hash;
type Seed: FromBytes + ToBytes + Clone + Default + Debug;
fn evaluate(seed: &Self::Seed, input: &Self::Input) -> Result<Self::Output, CryptoError>;
}

+ 0
- 20
crypto-primitives/src/signature/constraints.rs

@ -1,20 +0,0 @@
use algebra_core::Field;
use r1cs_core::SynthesisError;
use r1cs_std::prelude::*;
use crate::signature::SignatureScheme;
pub trait SigRandomizePkGadget<S: SignatureScheme, ConstraintF: Field> {
type ParametersVar: AllocVar<S::Parameters, ConstraintF> + Clone;
type PublicKeyVar: ToBytesGadget<ConstraintF>
+ EqGadget<ConstraintF>
+ AllocVar<S::PublicKey, ConstraintF>
+ Clone;
fn randomize(
parameters: &Self::ParametersVar,
public_key: &Self::PublicKeyVar,
randomness: &[UInt8<ConstraintF>],
) -> Result<Self::PublicKeyVar, SynthesisError>;
}

+ 0
- 104
crypto-primitives/src/signature/mod.rs

@ -1,104 +0,0 @@
use crate::Error;
use algebra_core::bytes::ToBytes;
use core::hash::Hash;
use rand::Rng;
#[cfg(feature = "r1cs")]
pub mod constraints;
#[cfg(feature = "r1cs")]
pub use constraints::*;
pub mod schnorr;
pub trait SignatureScheme {
type Parameters: Clone + Send + Sync;
type PublicKey: ToBytes + Hash + Eq + Clone + Default + Send + Sync;
type SecretKey: ToBytes + Clone + Default;
type Signature: Clone + Default + Send + Sync;
fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error>;
fn keygen<R: Rng>(
pp: &Self::Parameters,
rng: &mut R,
) -> Result<(Self::PublicKey, Self::SecretKey), Error>;
fn sign<R: Rng>(
pp: &Self::Parameters,
sk: &Self::SecretKey,
message: &[u8],
rng: &mut R,
) -> Result<Self::Signature, Error>;
fn verify(
pp: &Self::Parameters,
pk: &Self::PublicKey,
message: &[u8],
signature: &Self::Signature,
) -> Result<bool, Error>;
fn randomize_public_key(
pp: &Self::Parameters,
public_key: &Self::PublicKey,
randomness: &[u8],
) -> Result<Self::PublicKey, Error>;
fn randomize_signature(
pp: &Self::Parameters,
signature: &Self::Signature,
randomness: &[u8],
) -> Result<Self::Signature, Error>;
}
#[cfg(test)]
mod test {
use crate::signature::{schnorr, *};
use algebra::{
ed_on_bls12_381::EdwardsProjective as JubJub, groups::Group, test_rng, to_bytes,
UniformRand,
};
use blake2::Blake2s;
fn sign_and_verify<S: SignatureScheme>(message: &[u8]) {
let rng = &mut test_rng();
let parameters = S::setup::<_>(rng).unwrap();
let (pk, sk) = S::keygen(&parameters, rng).unwrap();
let sig = S::sign(&parameters, &sk, &message, rng).unwrap();
assert!(S::verify(&parameters, &pk, &message, &sig).unwrap());
}
fn failed_verification<S: SignatureScheme>(message: &[u8], bad_message: &[u8]) {
let rng = &mut test_rng();
let parameters = S::setup::<_>(rng).unwrap();
let (pk, sk) = S::keygen(&parameters, rng).unwrap();
let sig = S::sign(&parameters, &sk, message, rng).unwrap();
assert!(!S::verify(&parameters, &pk, bad_message, &sig).unwrap());
}
fn randomize_and_verify<S: SignatureScheme>(message: &[u8], randomness: &[u8]) {
let rng = &mut test_rng();
let parameters = S::setup::<_>(rng).unwrap();
let (pk, sk) = S::keygen(&parameters, rng).unwrap();
let sig = S::sign(&parameters, &sk, message, rng).unwrap();
assert!(S::verify(&parameters, &pk, message, &sig).unwrap());
let randomized_pk = S::randomize_public_key(&parameters, &pk, randomness).unwrap();
let randomized_sig = S::randomize_signature(&parameters, &sig, randomness).unwrap();
assert!(S::verify(&parameters, &randomized_pk, &message, &randomized_sig).unwrap());
}
#[test]
fn schnorr_signature_test() {
let message = "Hi, I am a Schnorr signature!";
let rng = &mut test_rng();
sign_and_verify::<schnorr::Schnorr<JubJub, Blake2s>>(message.as_bytes());
failed_verification::<schnorr::Schnorr<JubJub, Blake2s>>(
message.as_bytes(),
"Bad message".as_bytes(),
);
let random_scalar = to_bytes!(<JubJub as Group>::ScalarField::rand(rng)).unwrap();
randomize_and_verify::<schnorr::Schnorr<JubJub, Blake2s>>(
message.as_bytes(),
&random_scalar.as_slice(),
);
}
}

+ 0
- 158
crypto-primitives/src/signature/schnorr/constraints.rs

@ -1,158 +0,0 @@
use crate::Vec;
use algebra_core::{Field, ProjectiveCurve};
use r1cs_core::{Namespace, SynthesisError};
use r1cs_std::prelude::*;
use crate::signature::SigRandomizePkGadget;
use core::{borrow::Borrow, marker::PhantomData};
use crate::signature::schnorr::{Parameters, PublicKey, Schnorr};
use digest::Digest;
type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField;
#[derive(Clone)]
pub struct ParametersVar<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>>
where
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
generator: GC,
_curve: PhantomData<C>,
}
#[derive(Derivative)]
#[derivative(
Debug(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>"),
Clone(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>")
)]
pub struct PublicKeyVar<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>>
where
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
pub_key: GC,
#[doc(hidden)]
_group: PhantomData<*const C>,
}
pub struct SchnorrRandomizePkGadget<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>>
where
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
#[doc(hidden)]
_group: PhantomData<*const C>,
#[doc(hidden)]
_group_gadget: PhantomData<*const GC>,
}
impl<C, GC, D> SigRandomizePkGadget<Schnorr<C, D>, ConstraintF<C>>
for SchnorrRandomizePkGadget<C, GC>
where
C: ProjectiveCurve,
GC: CurveVar<C, ConstraintF<C>>,
D: Digest + Send + Sync,
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
type ParametersVar = ParametersVar<C, GC>;
type PublicKeyVar = PublicKeyVar<C, GC>;
#[tracing::instrument(target = "r1cs", skip(parameters, public_key, randomness))]
fn randomize(
parameters: &Self::ParametersVar,
public_key: &Self::PublicKeyVar,
randomness: &[UInt8<ConstraintF<C>>],
) -> Result<Self::PublicKeyVar, SynthesisError> {
let base = parameters.generator.clone();
let randomness = randomness
.iter()
.flat_map(|b| b.to_bits_le().unwrap())
.collect::<Vec<_>>();
let rand_pk = &public_key.pub_key + &base.scalar_mul_le(randomness.iter())?;
Ok(PublicKeyVar {
pub_key: rand_pk,
_group: PhantomData,
})
}
}
impl<C, GC, D> AllocVar<Parameters<C, D>, ConstraintF<C>> for ParametersVar<C, GC>
where
C: ProjectiveCurve,
GC: CurveVar<C, ConstraintF<C>>,
D: Digest,
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
fn new_variable<T: Borrow<Parameters<C, D>>>(
cs: impl Into<Namespace<ConstraintF<C>>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let generator = GC::new_variable(cs, || f().map(|g| g.borrow().generator), mode)?;
Ok(Self {
generator,
_curve: PhantomData,
})
}
}
impl<C, GC> AllocVar<PublicKey<C>, ConstraintF<C>> for PublicKeyVar<C, GC>
where
C: ProjectiveCurve,
GC: CurveVar<C, ConstraintF<C>>,
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
fn new_variable<T: Borrow<PublicKey<C>>>(
cs: impl Into<Namespace<ConstraintF<C>>>,
f: impl FnOnce() -> Result<T, SynthesisError>,
mode: AllocationMode,
) -> Result<Self, SynthesisError> {
let pub_key = GC::new_variable(cs, f, mode)?;
Ok(Self {
pub_key,
_group: PhantomData,
})
}
}
impl<C, GC> EqGadget<ConstraintF<C>> for PublicKeyVar<C, GC>
where
C: ProjectiveCurve,
GC: CurveVar<C, ConstraintF<C>>,
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
#[inline]
fn is_eq(&self, other: &Self) -> Result<Boolean<ConstraintF<C>>, SynthesisError> {
self.pub_key.is_eq(&other.pub_key)
}
#[inline]
fn conditional_enforce_equal(
&self,
other: &Self,
condition: &Boolean<ConstraintF<C>>,
) -> Result<(), SynthesisError> {
self.pub_key
.conditional_enforce_equal(&other.pub_key, condition)
}
#[inline]
fn conditional_enforce_not_equal(
&self,
other: &Self,
condition: &Boolean<ConstraintF<C>>,
) -> Result<(), SynthesisError> {
self.pub_key
.conditional_enforce_not_equal(&other.pub_key, condition)
}
}
impl<C, GC> ToBytesGadget<ConstraintF<C>> for PublicKeyVar<C, GC>
where
C: ProjectiveCurve,
GC: CurveVar<C, ConstraintF<C>>,
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
{
fn to_bytes(&self) -> Result<Vec<UInt8<ConstraintF<C>>>, SynthesisError> {
self.pub_key.to_bytes()
}
}

+ 0
- 229
crypto-primitives/src/signature/schnorr/mod.rs

@ -1,229 +0,0 @@
use crate::{Error, SignatureScheme, Vec};
use algebra_core::{
bytes::ToBytes,
fields::{Field, PrimeField},
io::{Result as IoResult, Write},
to_bytes, AffineCurve, One, ProjectiveCurve, ToConstraintField, UniformRand, Zero,
};
use core::{hash::Hash, marker::PhantomData};
use digest::Digest;
use rand::Rng;
#[cfg(feature = "r1cs")]
pub mod constraints;
pub struct Schnorr<C: ProjectiveCurve, D: Digest> {
_group: PhantomData<C>,
_hash: PhantomData<D>,
}
#[derive(Derivative)]
#[derivative(Clone(bound = "C: ProjectiveCurve, H: Digest"), Debug)]
pub struct Parameters<C: ProjectiveCurve, H: Digest> {
_hash: PhantomData<H>,
pub generator: C::Affine,
pub salt: [u8; 32],
}
pub type PublicKey<C> = <C as ProjectiveCurve>::Affine;
#[derive(Clone, Default, Debug)]
pub struct SecretKey<C: ProjectiveCurve>(pub C::ScalarField);
impl<C: ProjectiveCurve> ToBytes for SecretKey<C> {
#[inline]
fn write<W: Write>(&self, writer: W) -> IoResult<()> {
self.0.write(writer)
}
}
#[derive(Clone, Default, Debug)]
pub struct Signature<C: ProjectiveCurve> {
pub prover_response: C::ScalarField,
pub verifier_challenge: C::ScalarField,
}
impl<C: ProjectiveCurve + Hash, D: Digest + Send + Sync> SignatureScheme for Schnorr<C, D>
where
C::ScalarField: PrimeField,
{
type Parameters = Parameters<C, D>;
type PublicKey = PublicKey<C>;
type SecretKey = SecretKey<C>;
type Signature = Signature<C>;
fn setup<R: Rng>(rng: &mut R) -> Result<Self::Parameters, Error> {
let setup_time = start_timer!(|| "SchnorrSig::Setup");
let mut salt = [0u8; 32];
rng.fill_bytes(&mut salt);
let generator = C::rand(rng).into();
end_timer!(setup_time);
Ok(Parameters {
_hash: PhantomData,
generator,
salt,
})
}
fn keygen<R: Rng>(
parameters: &Self::Parameters,
rng: &mut R,
) -> Result<(Self::PublicKey, Self::SecretKey), Error> {
let keygen_time = start_timer!(|| "SchnorrSig::KeyGen");
let secret_key = C::ScalarField::rand(rng);
let public_key = parameters.generator.mul(secret_key).into();
end_timer!(keygen_time);
Ok((public_key, SecretKey(secret_key)))
}
fn sign<R: Rng>(
parameters: &Self::Parameters,
sk: &Self::SecretKey,
message: &[u8],
rng: &mut R,
) -> Result<Self::Signature, Error> {
let sign_time = start_timer!(|| "SchnorrSig::Sign");
// (k, e);
let (random_scalar, verifier_challenge) = loop {
// Sample a random scalar `k` from the prime scalar field.
let random_scalar: C::ScalarField = C::ScalarField::rand(rng);
// Commit to the random scalar via r := k · G.
// This is the prover's first msg in the Sigma protocol.
let prover_commitment = parameters.generator.mul(random_scalar).into_affine();
// Hash everything to get verifier challenge.
let mut hash_input = Vec::new();
hash_input.extend_from_slice(&parameters.salt);
hash_input.extend_from_slice(&to_bytes![prover_commitment]?);
hash_input.extend_from_slice(message);
// Compute the supposed verifier response: e := H(salt || r || msg);
if let Some(verifier_challenge) =
C::ScalarField::from_random_bytes(&D::digest(&hash_input))
{
break (random_scalar, verifier_challenge);
};
};
// k - xe;
let prover_response = random_scalar - &(verifier_challenge * &sk.0);
let signature = Signature {
prover_response,
verifier_challenge,
};
end_timer!(sign_time);
Ok(signature)
}
fn verify(
parameters: &Self::Parameters,
pk: &Self::PublicKey,
message: &[u8],
signature: &Self::Signature,
) -> Result<bool, Error> {
let verify_time = start_timer!(|| "SchnorrSig::Verify");
let Signature {
prover_response,
verifier_challenge,
} = signature;
let mut claimed_prover_commitment = parameters.generator.mul(*prover_response);
let public_key_times_verifier_challenge = pk.mul(*verifier_challenge);
claimed_prover_commitment += &public_key_times_verifier_challenge;
let claimed_prover_commitment = claimed_prover_commitment.into_affine();
let mut hash_input = Vec::new();
hash_input.extend_from_slice(&parameters.salt);
hash_input.extend_from_slice(&to_bytes![claimed_prover_commitment]?);
hash_input.extend_from_slice(&message);
let obtained_verifier_challenge = if let Some(obtained_verifier_challenge) =
C::ScalarField::from_random_bytes(&D::digest(&hash_input))
{
obtained_verifier_challenge
} else {
return Ok(false);
};
end_timer!(verify_time);
Ok(verifier_challenge == &obtained_verifier_challenge)
}
fn randomize_public_key(
parameters: &Self::Parameters,
public_key: &Self::PublicKey,
randomness: &[u8],
) -> Result<Self::PublicKey, Error> {
let rand_pk_time = start_timer!(|| "SchnorrSig::RandomizePubKey");
let randomized_pk = *public_key;
let base = parameters.generator;
let mut encoded = C::zero();
for bit in bytes_to_bits(randomness)
.into_iter()
.rev()
.skip_while(|b| !b)
{
encoded.double_in_place();
if bit {
encoded.add_assign_mixed(&base)
}
}
encoded.add_assign_mixed(&randomized_pk);
end_timer!(rand_pk_time);
Ok(encoded.into())
}
fn randomize_signature(
_parameter: &Self::Parameters,
signature: &Self::Signature,
randomness: &[u8],
) -> Result<Self::Signature, Error> {
let rand_signature_time = start_timer!(|| "SchnorrSig::RandomizeSig");
let Signature {
prover_response,
verifier_challenge,
} = signature;
let mut base = C::ScalarField::one();
let mut multiplier = C::ScalarField::zero();
for bit in bytes_to_bits(randomness) {
if bit {
multiplier += &base;
}
base.double_in_place();
}
let new_sig = Signature {
prover_response: *prover_response - &(*verifier_challenge * &multiplier),
verifier_challenge: *verifier_challenge,
};
end_timer!(rand_signature_time);
Ok(new_sig)
}
}
pub fn bytes_to_bits(bytes: &[u8]) -> Vec<bool> {
let mut bits = Vec::with_capacity(bytes.len() * 8);
for byte in bytes {
for i in 0..8 {
let bit = (*byte >> (8 - i - 1)) & 1;
bits.push(bit == 1);
}
}
bits
}
impl<ConstraintF: Field, C: ProjectiveCurve + ToConstraintField<ConstraintF>, D: Digest>
ToConstraintField<ConstraintF> for Parameters<C, D>
{
#[inline]
fn to_field_elements(&self) -> Result<Vec<ConstraintF>, Error> {
self.generator.into_projective().to_field_elements()
}
}

+ 0
- 58
r1cs-std/Cargo.toml

@ -1,58 +0,0 @@
[package]
name = "r1cs-std"
version = "0.1.1-alpha.0"
authors = [
"Sean Bowe",
"Alessandro Chiesa",
"Matthew Green",
"Ian Miers",
"Pratyush Mishra",
"Howard Wu"
]
description = "A standard library for constraint system gadgets"
homepage = "https://libzexe.org"
repository = "https://github.com/scipr/zexe"
documentation = "https://docs.rs/r1cs-std/"
keywords = ["zero knowledge", "cryptography", "zkSNARK", "SNARK"]
categories = ["cryptography"]
include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
license = "MIT/Apache-2.0"
edition = "2018"
################################# Dependencies ################################
[dependencies]
algebra = { git = "https://github.com/scipr-lab/zexe", default-features = false }
r1cs-core = { git = "https://github.com/scipr-lab/zexe", default-features = false }
derivative = { version = "2", features = ["use_core"] }
tracing = { version = "0.1", default-features = false, features = [ "attributes" ] }
[dev-dependencies]
rand = { version = "0.7", default-features = false }
rand_xorshift = { version = "0.2" }
# Currently this means that all downstream users of `r1cs-std` will be using
# `algebra` with the `bls12_381` feature. This is because of a cargo bug.
algebra = { git = "https://github.com/scipr-lab/zexe", default-features = false, features = [ "bls12_381" ] }
[features]
default = ["std"]
full = [
"bls12_377", "ed_on_bn254", "ed_on_bls12_381", "ed_on_bls12_377", "ed_on_cp6_782",
"ed_on_bw6_761", "ed_on_mnt4_298", "ed_on_mnt4_753", "mnt4_298", "mnt4_753", "mnt6_298", "mnt6_753"
]
bls12_377 = [ "algebra/bls12_377" ]
ed_on_bn254 = [ "algebra/ed_on_bn254" ]
ed_on_bls12_381 = [ "algebra/ed_on_bls12_381" ]
ed_on_bls12_377 = [ "algebra/ed_on_bls12_377" ]
ed_on_cp6_782 = [ "algebra/ed_on_cp6_782" ]
ed_on_bw6_761 = [ "algebra/ed_on_bw6_761", "algebra/ed_on_cp6_782" ]
ed_on_mnt4_298 = [ "algebra/ed_on_mnt4_298" ]
ed_on_mnt4_753 = [ "algebra/ed_on_mnt4_753" ]
mnt4_298 = [ "algebra/mnt4_298" ]
mnt4_753 = [ "algebra/mnt4_753" ]
mnt6_298 = [ "algebra/mnt6_298" ]
mnt6_753 = [ "algebra/mnt6_753" ]
std = [ "algebra/std", "r1cs-core/std" ]
parallel = [ "std", "algebra/parallel" ]

+ 0
- 1
r1cs-std/LICENSE-APACHE

@ -1 +0,0 @@
../LICENSE-APACHE

+ 0
- 1
r1cs-std/LICENSE-MIT

@ -1 +0,0 @@
../LICENSE-MIT

+ 0
- 422
r1cs-std/src/fields/mod.rs

@ -1,422 +0,0 @@
use algebra::{prelude::*, BitIteratorBE};
use core::{
fmt::Debug,
ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign},
};
use r1cs_core::SynthesisError;
use crate::{prelude::*, Assignment};
/// This module contains a generic implementation of cubic extension field variables.
/// That is, it implements the R1CS equivalent of `algebra_core::CubicExtField`.
pub mod cubic_extension;
/// This module contains a generic implementation of quadratic extension field variables.
/// That is, it implements the R1CS equivalent of `algebra_core::QuadExtField`.
pub mod quadratic_extension;
/// This module contains a generic implementation of prime field variables.
/// That is, it implements the R1CS equivalent of `algebra_core::Fp*`.
pub mod fp;
/// This module contains a generic implementation of the degree-12 tower extension field.
/// That is, it implements the R1CS equivalent of `algebra_core::Fp12`
pub mod fp12;
/// This module contains a generic implementation of the degree-2 tower extension field.
/// That is, it implements the R1CS equivalent of `algebra_core::Fp2`
pub mod fp2;
/// This module contains a generic implementation of the degree-3 tower extension field.
/// That is, it implements the R1CS equivalent of `algebra_core::Fp3`
pub mod fp3;
/// This module contains a generic implementation of the degree-4 tower extension field.
/// That is, it implements the R1CS equivalent of `algebra_core::Fp4`
pub mod fp4;
/// This module contains a generic implementation of the degree-6 tower extension field.
/// That is, it implements the R1CS equivalent of `algebra_core::fp6_2over3::Fp6`
pub mod fp6_2over3;
/// This module contains a generic implementation of the degree-6 tower extension field.
/// That is, it implements the R1CS equivalent of `algebra_core::fp6_3over2::Fp6`
pub mod fp6_3over2;
/// This trait is a hack used to work around the lack of implied bounds.
pub trait FieldOpsBounds<'a, F, T: 'a>:
Sized
+ Add<&'a T, Output = T>
+ Sub<&'a T, Output = T>
+ Mul<&'a T, Output = T>
+ Add<T, Output = T>
+ Sub<T, Output = T>
+ Mul<T, Output = T>
+ Add<F, Output = T>
+ Sub<F, Output = T>
+ Mul<F, Output = T>
{
}
/// A variable representing a field. Corresponds to the native type `F`.
pub trait FieldVar<F: Field, ConstraintF: Field>:
'static
+ Clone
+ From<Boolean<ConstraintF>>
+ R1CSVar<ConstraintF, Value = F>
+ EqGadget<ConstraintF>
+ ToBitsGadget<ConstraintF>
+ AllocVar<F, ConstraintF>
+ ToBytesGadget<ConstraintF>
+ CondSelectGadget<ConstraintF>
+ for<'a> FieldOpsBounds<'a, F, Self>
+ for<'a> AddAssign<&'a Self>
+ for<'a> SubAssign<&'a Self>
+ for<'a> MulAssign<&'a Self>
+ AddAssign<Self>
+ SubAssign<Self>
+ MulAssign<Self>
+ AddAssign<F>
+ SubAssign<F>
+ MulAssign<F>
+ Debug
{
/// Returns the constant `F::zero()`.
fn zero() -> Self;
/// Returns a `Boolean` representing whether `self == Self::zero()`.
fn is_zero(&self) -> Result<Boolean<ConstraintF>, SynthesisError> {
self.is_eq(&Self::zero())
}
/// Returns the constant `F::one()`.
fn one() -> Self;
/// Returns a `Boolean` representing whether `self == Self::one()`.
fn is_one(&self) -> Result<Boolean<ConstraintF>, SynthesisError> {
self.is_eq(&Self::one())
}
/// Returns a constant with value `v`.
///
/// This *should not* allocate any variables.
fn constant(v: F) -> Self;
/// Computes `self + self`.
fn double(&self) -> Result<Self, SynthesisError> {
Ok(self.clone() + self)
}
/// Sets `self = self + self`.
fn double_in_place(&mut self) -> Result<&mut Self, SynthesisError> {
*self += self.double()?;
Ok(self)
}
/// Coputes `-self`.
fn negate(&self) -> Result<Self, SynthesisError>;
/// Sets `self = -self`.
#[inline]
fn negate_in_place(&mut self) -> Result<&mut Self, SynthesisError> {
*self = self.negate()?;
Ok(self)
}
/// Computes `self * self`.
///
/// A default implementation is provided which just invokes the underlying
/// multiplication routine. However, this method should be specialized
/// for extension fields, where faster algorithms exist for squaring.
fn square(&self) -> Result<Self, SynthesisError> {
Ok(self.clone() * self)
}
/// Sets `self = self.square()`.
fn square_in_place(&mut self) -> Result<&mut Self, SynthesisError> {
*self = self.square()?;
Ok(self)
}
/// Enforces that `self * other == result`.
fn mul_equals(&self, other: &Self, result: &Self) -> Result<(), SynthesisError> {
let actual_result = self.clone() * other;
result.enforce_equal(&actual_result)
}
/// Enforces that `self * self == result`.
fn square_equals(&self, result: &Self) -> Result<(), SynthesisError> {
let actual_result = self.square()?;
result.enforce_equal(&actual_result)
}
/// Computes `result` such that `self * result == Self::one()`.
fn inverse(&self) -> Result<Self, SynthesisError>;
/// Returns `(self / denominator)`. but requires fewer constraints than
/// `self * denominator.inverse()`.
/// It is up to the caller to ensure that denominator is non-zero,
/// since in that case the result is unconstrained.
fn mul_by_inverse(&self, denominator: &Self) -> Result<Self, SynthesisError> {
let result = Self::new_witness(self.cs(), || {
let denominator_inv_native = denominator.value()?.inverse().get()?;
let result = self.value()? * &denominator_inv_native;
Ok(result)
})?;
result.mul_equals(&denominator, &self)?;
Ok(result)
}
/// Computes the frobenius map over `self`.
fn frobenius_map(&self, power: usize) -> Result<Self, SynthesisError>;
/// Sets `self = self.frobenius_map()`.
fn frobenius_map_in_place(&mut self, power: usize) -> Result<&mut Self, SynthesisError> {
*self = self.frobenius_map(power)?;
Ok(self)
}
/// Comptues `self^bits`, where `bits` is a *little-endian* bit-wise decomposition
/// of the exponent.
fn pow_le(&self, bits: &[Boolean<ConstraintF>]) -> Result<Self, SynthesisError> {
let mut res = Self::one();
let mut power = self.clone();
for bit in bits {
let tmp = res.clone() * &power;
res = bit.select(&tmp, &res)?;
power.square_in_place()?;
}
Ok(res)
}
/// Computes `self^S`, where S is interpreted as an little-endian u64-decomposition of
/// an integer.
fn pow_by_constant<S: AsRef<[u64]>>(&self, exp: S) -> Result<Self, SynthesisError> {
let mut res = Self::one();
for i in BitIteratorBE::without_leading_zeros(exp) {
res.square_in_place()?;
if i {
res *= self;
}
}
Ok(res)
}
}
#[cfg(test)]
pub(crate) mod tests {
use rand::{self, SeedableRng};
use rand_xorshift::XorShiftRng;
use crate::{fields::*, Vec};
use algebra::{test_rng, BitIteratorLE, Field, UniformRand};
use r1cs_core::{ConstraintSystem, SynthesisError};
#[allow(dead_code)]
pub(crate) fn field_test<F, ConstraintF, AF>() -> Result<(), SynthesisError>
where
F: Field,
ConstraintF: Field,
AF: FieldVar<F, ConstraintF>,
AF: TwoBitLookupGadget<ConstraintF, TableConstant = F>,
for<'a> &'a AF: FieldOpsBounds<'a, F, AF>,
{
let cs = ConstraintSystem::<ConstraintF>::new_ref();
let mut rng = test_rng();
let a_native = F::rand(&mut rng);
let b_native = F::rand(&mut rng);
let a = AF::new_witness(r1cs_core::ns!(cs, "generate_a"), || Ok(a_native))?;
let b = AF::new_witness(r1cs_core::ns!(cs, "generate_b"), || Ok(b_native))?;
let b_const = AF::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
let zero = AF::zero();
let zero_native = zero.value()?;
zero.enforce_equal(&zero)?;
let one = AF::one();
let one_native = one.value()?;
one.enforce_equal(&one)?;
one.enforce_not_equal(&zero)?;
let one_dup = &zero + &one;
one_dup.enforce_equal(&one)?;
let two = &one + &one;
two.enforce_equal(&two)?;
two.enforce_equal(&one.double()?)?;
two.enforce_not_equal(&one)?;
two.enforce_not_equal(&zero)?;
// a + 0 = a
let a_plus_zero = &a + &zero;
assert_eq!(a_plus_zero.value()?, a_native);
a_plus_zero.enforce_equal(&a)?;
a_plus_zero.enforce_not_equal(&a.double()?)?;
// a - 0 = a
let a_minus_zero = &a - &zero;
assert_eq!(a_minus_zero.value()?, a_native);
a_minus_zero.enforce_equal(&a)?;
// a - a = 0
let a_minus_a = &a - &a;
assert_eq!(a_minus_a.value()?, zero_native);
a_minus_a.enforce_equal(&zero)?;
// a + b = b + a
let a_b = &a + &b;
let b_a = &b + &a;
assert_eq!(a_b.value()?, a_native + &b_native);
a_b.enforce_equal(&b_a)?;
// (a + b) + a = a + (b + a)
let ab_a = &a_b + &a;
let a_ba = &a + &b_a;
assert_eq!(ab_a.value()?, a_native + &b_native + &a_native);
ab_a.enforce_equal(&a_ba)?;
let b_times_a_plus_b = &a_b * &b;
let b_times_b_plus_a = &b_a * &b;
assert_eq!(
b_times_a_plus_b.value()?,
b_native * &(b_native + &a_native)
);
assert_eq!(
b_times_a_plus_b.value()?,
(b_native + &a_native) * &b_native
);
assert_eq!(
b_times_a_plus_b.value()?,
(a_native + &b_native) * &b_native
);
b_times_b_plus_a.enforce_equal(&b_times_a_plus_b)?;
// a * 1 = a
assert_eq!((&a * &one).value()?, a_native * &one_native);
// a * b = b * a
let ab = &a * &b;
let ba = &b * &a;
assert_eq!(ab.value()?, ba.value()?);
assert_eq!(ab.value()?, a_native * &b_native);
let ab_const = &a * &b_const;
let b_const_a = &b_const * &a;
assert_eq!(ab_const.value()?, b_const_a.value()?);
assert_eq!(ab_const.value()?, ab.value()?);
assert_eq!(ab_const.value()?, a_native * &b_native);
// (a * b) * a = a * (b * a)
let ab_a = &ab * &a;
let a_ba = &a * &ba;
assert_eq!(ab_a.value()?, a_ba.value()?);
assert_eq!(ab_a.value()?, a_native * &b_native * &a_native);
let aa = &a * &a;
let a_squared = a.square()?;
a_squared.enforce_equal(&aa)?;
assert_eq!(aa.value()?, a_squared.value()?);
assert_eq!(aa.value()?, a_native.square());
let aa = &a * a.value()?;
a_squared.enforce_equal(&aa)?;
assert_eq!(aa.value()?, a_squared.value()?);
assert_eq!(aa.value()?, a_native.square());
let a_b2 = &a + b_native;
a_b.enforce_equal(&a_b2)?;
assert_eq!(a_b.value()?, a_b2.value()?);
let a_inv = a.inverse()?;
a_inv.mul_equals(&a, &one)?;
assert_eq!(a_inv.value()?, a.value()?.inverse().unwrap());
assert_eq!(a_inv.value()?, a_native.inverse().unwrap());
let a_b_inv = a.mul_by_inverse(&b)?;
a_b_inv.mul_equals(&b, &a)?;
assert_eq!(a_b_inv.value()?, a_native * b_native.inverse().unwrap());
// a * a * a = a^3
let bits = BitIteratorLE::without_trailing_zeros([3u64])
.map(Boolean::constant)
.collect::<Vec<_>>();
assert_eq!(a_native.pow([0x3]), a.pow_le(&bits)?.value()?);
// a * a * a = a^3
assert_eq!(a_native.pow([0x3]), a.pow_by_constant(&[0x3])?.value()?);
assert!(cs.is_satisfied().unwrap());
// a * a * a = a^3
let mut constants = [F::zero(); 4];
for c in &mut constants {
*c = UniformRand::rand(&mut test_rng());
}
let bits = [
Boolean::<ConstraintF>::constant(false),
Boolean::constant(true),
];
let lookup_result = AF::two_bit_lookup(&bits, constants.as_ref())?;
assert_eq!(lookup_result.value()?, constants[2]);
assert!(cs.is_satisfied().unwrap());
let f = F::from(1u128 << 64);
let f_bits = algebra::BitIteratorLE::new(&[0u64, 1u64]).collect::<Vec<_>>();
let fv = AF::new_witness(r1cs_core::ns!(cs, "alloc u128"), || Ok(f))?;
assert_eq!(fv.to_bits_le()?.value().unwrap()[..128], f_bits[..128]);
assert!(cs.is_satisfied().unwrap());
let r_native: F = UniformRand::rand(&mut test_rng());
let r = AF::new_witness(r1cs_core::ns!(cs, "r_native"), || Ok(r_native)).unwrap();
let _ = r.to_non_unique_bits_le()?;
assert!(cs.is_satisfied().unwrap());
let _ = r.to_bits_le()?;
assert!(cs.is_satisfied().unwrap());
let bytes = r.to_non_unique_bytes()?;
assert_eq!(
algebra::to_bytes!(r_native).unwrap(),
bytes.value().unwrap()
);
assert!(cs.is_satisfied().unwrap());
let bytes = r.to_bytes()?;
assert_eq!(
algebra::to_bytes!(r_native).unwrap(),
bytes.value().unwrap()
);
assert!(cs.is_satisfied().unwrap());
let ab_false = &a + (AF::from(Boolean::Constant(false)) * b_native);
assert_eq!(ab_false.value()?, a_native);
let ab_true = &a + (AF::from(Boolean::Constant(true)) * b_native);
assert_eq!(ab_true.value()?, a_native + &b_native);
if !cs.is_satisfied().unwrap() {
println!("{:?}", cs.which_is_unsatisfied().unwrap());
}
assert!(cs.is_satisfied().unwrap());
Ok(())
}
#[allow(dead_code)]
pub(crate) fn frobenius_tests<F: Field, ConstraintF, AF>(
maxpower: usize,
) -> Result<(), SynthesisError>
where
F: Field,
ConstraintF: Field,
AF: FieldVar<F, ConstraintF>,
for<'a> &'a AF: FieldOpsBounds<'a, F, AF>,
{
let cs = ConstraintSystem::<ConstraintF>::new_ref();
let mut rng = XorShiftRng::seed_from_u64(1231275789u64);
for i in 0..=maxpower {
let mut a = F::rand(&mut rng);
let mut a_gadget = AF::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a))?;
a_gadget.frobenius_map_in_place(i)?;
a.frobenius_map(i);
assert_eq!(a_gadget.value()?, a);
}
assert!(cs.is_satisfied().unwrap());
Ok(())
}
}

+ 0
- 29
r1cs-std/src/instantiated/bls12_377/curves.rs

@ -1,29 +0,0 @@
use crate::groups::bls12;
use algebra::bls12_377::Parameters;
/// An element of G1 in the BLS12-377 bilinear group.
pub type G1Var = bls12::G1Var<Parameters>;
/// An element of G2 in the BLS12-377 bilinear group.
pub type G2Var = bls12::G2Var<Parameters>;
/// Represents the cached precomputation that can be performed on a G1 element
/// which enables speeding up pairing computation.
pub type G1PreparedVar = bls12::G1PreparedVar<Parameters>;
/// Represents the cached precomputation that can be performed on a G2 element
/// which enables speeding up pairing computation.
pub type G2PreparedVar = bls12::G2PreparedVar<Parameters>;
#[test]
fn test() {
use algebra::curves::models::bls12::Bls12Parameters;
crate::groups::curves::short_weierstrass::test::<
<Parameters as Bls12Parameters>::G1Parameters,
G1Var,
>()
.unwrap();
crate::groups::curves::short_weierstrass::test::<
<Parameters as Bls12Parameters>::G2Parameters,
G2Var,
>()
.unwrap();
}

+ 0
- 32
r1cs-std/src/instantiated/bls12_377/fields.rs

@ -1,32 +0,0 @@
use algebra::bls12_377::{Fq, Fq12Parameters, Fq2Parameters, Fq6Parameters};
use crate::fields::{fp::FpVar, fp12::Fp12Var, fp2::Fp2Var, fp6_3over2::Fp6Var};
/// A variable that is the R1CS equivalent of `algebra::bls12_377::Fq`.
pub type FqVar = FpVar<Fq>;
/// A variable that is the R1CS equivalent of `algebra::bls12_377::Fq2`.
pub type Fq2Var = Fp2Var<Fq2Parameters>;
/// A variable that is the R1CS equivalent of `algebra::bls12_377::Fq6`.
pub type Fq6Var = Fp6Var<Fq6Parameters>;
/// A variable that is the R1CS equivalent of `algebra::bls12_377::Fq12`.
pub type Fq12Var = Fp12Var<Fq12Parameters>;
#[test]
fn bls12_377_field_test() {
use super::*;
use crate::fields::tests::*;
use algebra::bls12_377::{Fq, Fq12, Fq2, Fq6};
field_test::<_, _, FqVar>().unwrap();
frobenius_tests::<Fq, _, FqVar>(13).unwrap();
field_test::<_, _, Fq2Var>().unwrap();
frobenius_tests::<Fq2, _, Fq2Var>(13).unwrap();
field_test::<_, _, Fq6Var>().unwrap();
frobenius_tests::<Fq6, _, Fq6Var>(13).unwrap();
field_test::<_, _, Fq12Var>().unwrap();
frobenius_tests::<Fq12, _, Fq12Var>(13).unwrap();
}

+ 0
- 157
r1cs-std/src/instantiated/bls12_377/mod.rs

@ -1,157 +0,0 @@
//! This module implements the R1CS equivalent of `algebra::bls12_377`.
//!
//! It implements field variables for `algebra::bls12_377::{Fq, Fq2, Fq6, Fq12}`,
//! group variables for `algebra::bls12_377::{G1, G2}`, and implements constraint
//! generation for computing `Bls12_377::pairing`.
//!
//! The field underlying these constraints is `algebra::bls12_377::Fq`.
//!
//! # Examples
//!
//! One can perform standard algebraic operations on `FqVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! use algebra::{UniformRand, bls12_377::*};
//! use r1cs_core::*;
//! use r1cs_std::prelude::*;
//! use r1cs_std::bls12_377::*;
//!
//! let cs = ConstraintSystem::<Fq>::new_ref();
//! // This rng is just for test purposes; do not use it
//! // in real applications.
//! let mut rng = algebra::test_rng();
//!
//! // Generate some random `Fq` elements.
//! let a_native = Fq::rand(&mut rng);
//! let b_native = Fq::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = FqVar::new_witness(r1cs_core::ns!(cs, "generate_a"), || Ok(a_native))?;
//! let b = FqVar::new_witness(r1cs_core::ns!(cs, "generate_b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = FqVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = FqVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let one = FqVar::one();
//! let zero = FqVar::zero();
//!
//! // Sanity check one + one = two
//! let two = &one + &one + &zero;
//! two.enforce_equal(&one.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that the value of &a * &b is correct.
//! assert_eq!((&a * &b).value()?, a_native * &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! One can also perform standard algebraic operations on `G1Var` and `G2Var`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, bls12_377::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::bls12_377::*;
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate some random `G1` elements.
//! let a_native = G1Projective::rand(&mut rng);
//! let b_native = G1Projective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = G1Var::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = G1Var::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = G1Var::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = G1Var::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! // This returns the identity of `G1`.
//! let zero = G1Var::zero();
//!
//! // Sanity check one + one = two
//! let two_a = &a + &a + &zero;
//! two_a.enforce_equal(&a.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! Finally, one can check pairing computations as well:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, PairingEngine, bls12_377::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::bls12_377::{self, *};
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate random `G1` and `G2` elements.
//! let a_native = G1Projective::rand(&mut rng);
//! let b_native = G2Projective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = G1Var::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = G2Var::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = G1Var::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = G2Var::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let pairing_result_native = Bls12_377::pairing(a_native, b_native);
//!
//! // Prepare `a` and `b` for pairing.
//! let a_prep = bls12_377::PairingVar::prepare_g1(&a)?;
//! let b_prep = bls12_377::PairingVar::prepare_g2(&b)?;
//! let pairing_result = bls12_377::PairingVar::pairing(a_prep, b_prep)?;
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!(pairing_result.value()?, pairing_result_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! let a_prep_const = bls12_377::PairingVar::prepare_g1(&a_const)?;
//! let b_prep_const = bls12_377::PairingVar::prepare_g2(&b_const)?;
//! let pairing_result_const = bls12_377::PairingVar::pairing(a_prep_const, b_prep_const)?;
//! println!("Done here 3");
//!
//! pairing_result.enforce_equal(&pairing_result_const)?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
mod curves;
mod fields;
mod pairing;
pub use curves::*;
pub use fields::*;
pub use pairing::*;

+ 0
- 9
r1cs-std/src/instantiated/bls12_377/pairing.rs

@ -1,9 +0,0 @@
use algebra::bls12_377::Parameters;
/// Specifies the constraints for computing a pairing in the BLS12-377 bilinear group.
pub type PairingVar = crate::pairing::bls12::PairingVar<Parameters>;
#[test]
fn test() {
crate::pairing::tests::bilinearity_test::<algebra::Bls12_377, PairingVar>().unwrap()
}

+ 0
- 12
r1cs-std/src/instantiated/ed_on_bls12_377/curves.rs

@ -1,12 +0,0 @@
use crate::groups::curves::twisted_edwards::AffineVar;
use algebra::ed_on_bls12_377::*;
use crate::ed_on_bls12_377::FqVar;
/// A variable that is the R1CS equivalent of `algebra::ed_on_bls12_377::EdwardsAffine`.
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
#[test]
fn test() {
crate::groups::curves::twisted_edwards::test::<EdwardsParameters, EdwardsVar>().unwrap();
}

+ 0
- 10
r1cs-std/src/instantiated/ed_on_bls12_377/fields.rs

@ -1,10 +0,0 @@
use crate::fields::fp::FpVar;
use algebra::ed_on_bls12_377::fq::Fq;
/// A variable that is the R1CS equivalent of `algebra::ed_on_bls12_377::Fq`.
pub type FqVar = FpVar<Fq>;
#[test]
fn test() {
crate::fields::tests::field_test::<_, _, FqVar>().unwrap();
}

+ 0
- 107
r1cs-std/src/instantiated/ed_on_bls12_377/mod.rs

@ -1,107 +0,0 @@
//! This module implements the R1CS equivalent of `algebra::ed_on_bls12_377`.
//!
//! It implements field variables for `algebra::ed_on_bls12_377::Fq`,
//! and group variables for `algebra::ed_on_bls12_377::GroupProjective`.
//!
//! The field underlying these constraints is `algebra::ed_on_bls12_377::Fq`.
//!
//! # Examples
//!
//! One can perform standard algebraic operations on `FqVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! use algebra::{UniformRand, ed_on_bls12_377::*};
//! use r1cs_core::*;
//! use r1cs_std::prelude::*;
//! use r1cs_std::ed_on_bls12_377::*;
//!
//! let cs = ConstraintSystem::<Fq>::new_ref();
//! // This rng is just for test purposes; do not use it
//! // in real applications.
//! let mut rng = algebra::test_rng();
//!
//! // Generate some random `Fq` elements.
//! let a_native = Fq::rand(&mut rng);
//! let b_native = Fq::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = FqVar::new_witness(r1cs_core::ns!(cs, "generate_a"), || Ok(a_native))?;
//! let b = FqVar::new_witness(r1cs_core::ns!(cs, "generate_b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = FqVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = FqVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let one = FqVar::one();
//! let zero = FqVar::zero();
//!
//! // Sanity check one + one = two
//! let two = &one + &one + &zero;
//! two.enforce_equal(&one.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that the value of &a * &b is correct.
//! assert_eq!((&a * &b).value()?, a_native * &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! One can also perform standard algebraic operations on `EdwardsVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, ed_on_bls12_377::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::ed_on_bls12_377::*;
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate some random `Edwards` elements.
//! let a_native = EdwardsProjective::rand(&mut rng);
//! let b_native = EdwardsProjective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = EdwardsVar::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = EdwardsVar::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = EdwardsVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = EdwardsVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! // This returns the identity.
//! let zero = EdwardsVar::zero();
//!
//! // Sanity check one + one = two
//! let two_a = &a + &a + &zero;
//! two_a.enforce_equal(&a.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
mod curves;
mod fields;
pub use curves::*;
pub use fields::*;

+ 0
- 12
r1cs-std/src/instantiated/ed_on_bls12_381/curves.rs

@ -1,12 +0,0 @@
use crate::groups::curves::twisted_edwards::AffineVar;
use algebra::ed_on_bls12_381::*;
use crate::ed_on_bls12_381::FqVar;
/// A variable that is the R1CS equivalent of `algebra::ed_on_bls12_381::EdwardsAffine`.
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
#[test]
fn test() {
crate::groups::curves::twisted_edwards::test::<_, EdwardsVar>().unwrap();
}

+ 0
- 9
r1cs-std/src/instantiated/ed_on_bls12_381/fields.rs

@ -1,9 +0,0 @@
use crate::fields::fp::FpVar;
/// A variable that is the R1CS equivalent of `algebra::ed_on_bls12_381::Fq`.
pub type FqVar = FpVar<algebra::ed_on_bls12_381::Fq>;
#[test]
fn test() {
crate::fields::tests::field_test::<_, _, FqVar>().unwrap();
}

+ 0
- 107
r1cs-std/src/instantiated/ed_on_bls12_381/mod.rs

@ -1,107 +0,0 @@
//! This module implements the R1CS equivalent of `algebra::ed_on_bls12_381`.
//!
//! It implements field variables for `algebra::ed_on_bls12_381::Fq`,
//! and group variables for `algebra::ed_on_bls12_381::GroupProjective`.
//!
//! The field underlying these constraints is `algebra::ed_on_bls12_381::Fq`.
//!
//! # Examples
//!
//! One can perform standard algebraic operations on `FqVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! use algebra::{UniformRand, ed_on_bls12_381::*};
//! use r1cs_core::*;
//! use r1cs_std::prelude::*;
//! use r1cs_std::ed_on_bls12_381::*;
//!
//! let cs = ConstraintSystem::<Fq>::new_ref();
//! // This rng is just for test purposes; do not use it
//! // in real applications.
//! let mut rng = algebra::test_rng();
//!
//! // Generate some random `Fq` elements.
//! let a_native = Fq::rand(&mut rng);
//! let b_native = Fq::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = FqVar::new_witness(r1cs_core::ns!(cs, "generate_a"), || Ok(a_native))?;
//! let b = FqVar::new_witness(r1cs_core::ns!(cs, "generate_b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = FqVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = FqVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let one = FqVar::one();
//! let zero = FqVar::zero();
//!
//! // Sanity check one + one = two
//! let two = &one + &one + &zero;
//! two.enforce_equal(&one.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that the value of &a * &b is correct.
//! assert_eq!((&a * &b).value()?, a_native * &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! One can also perform standard algebraic operations on `EdwardsVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, ed_on_bls12_381::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::ed_on_bls12_381::*;
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate some random `Edwards` elements.
//! let a_native = EdwardsProjective::rand(&mut rng);
//! let b_native = EdwardsProjective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = EdwardsVar::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = EdwardsVar::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = EdwardsVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = EdwardsVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! // This returns the identity of `Edwards`.
//! let zero = EdwardsVar::zero();
//!
//! // Sanity check one + one = two
//! let two_a = &a + &a + &zero;
//! two_a.enforce_equal(&a.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
mod curves;
mod fields;
pub use curves::*;
pub use fields::*;

+ 0
- 12
r1cs-std/src/instantiated/ed_on_bn254/curves.rs

@ -1,12 +0,0 @@
use crate::groups::curves::twisted_edwards::AffineVar;
use algebra::ed_on_bn254::*;
use crate::ed_on_bn254::FqVar;
/// A variable that is the R1CS equivalent of `algebra::ed_on_bn254::EdwardsAffine`.
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
#[test]
fn test() {
crate::groups::curves::twisted_edwards::test::<_, EdwardsVar>().unwrap();
}

+ 0
- 9
r1cs-std/src/instantiated/ed_on_bn254/fields.rs

@ -1,9 +0,0 @@
use crate::fields::fp::FpVar;
/// A variable that is the R1CS equivalent of `algebra::ed_on_bn254::Fq`.
pub type FqVar = FpVar<algebra::ed_on_bn254::Fq>;
#[test]
fn test() {
crate::fields::tests::field_test::<_, _, FqVar>().unwrap();
}

+ 0
- 107
r1cs-std/src/instantiated/ed_on_bn254/mod.rs

@ -1,107 +0,0 @@
//! This module implements the R1CS equivalent of `algebra::ed_on_bn254`.
//!
//! It implements field variables for `algebra::ed_on_bn254::Fq`,
//! and group variables for `algebra::ed_on_bn254::GroupProjective`.
//!
//! The field underlying these constraints is `algebra::ed_on_bn254::Fq`.
//!
//! # Examples
//!
//! One can perform standard algebraic operations on `FqVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! use algebra::{UniformRand, ed_on_bn254::*};
//! use r1cs_core::*;
//! use r1cs_std::prelude::*;
//! use r1cs_std::ed_on_bn254::*;
//!
//! let cs = ConstraintSystem::<Fq>::new_ref();
//! // This rng is just for test purposes; do not use it
//! // in real applications.
//! let mut rng = algebra::test_rng();
//!
//! // Generate some random `Fq` elements.
//! let a_native = Fq::rand(&mut rng);
//! let b_native = Fq::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = FqVar::new_witness(r1cs_core::ns!(cs, "generate_a"), || Ok(a_native))?;
//! let b = FqVar::new_witness(r1cs_core::ns!(cs, "generate_b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = FqVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = FqVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let one = FqVar::one();
//! let zero = FqVar::zero();
//!
//! // Sanity check one + one = two
//! let two = &one + &one + &zero;
//! two.enforce_equal(&one.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that the value of &a * &b is correct.
//! assert_eq!((&a * &b).value()?, a_native * &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! One can also perform standard algebraic operations on `EdwardsVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, ed_on_bn254::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::ed_on_bn254::*;
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate some random `Edwards` elements.
//! let a_native = EdwardsProjective::rand(&mut rng);
//! let b_native = EdwardsProjective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = EdwardsVar::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = EdwardsVar::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = EdwardsVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = EdwardsVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! // This returns the identity of `Edwards`.
//! let zero = EdwardsVar::zero();
//!
//! // Sanity check one + one = two
//! let two_a = &a + &a + &zero;
//! two_a.enforce_equal(&a.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
mod curves;
mod fields;
pub use curves::*;
pub use fields::*;

+ 0
- 103
r1cs-std/src/instantiated/ed_on_bw6_761/mod.rs

@ -1,103 +0,0 @@
//! This module implements the R1CS equivalent of `algebra::ed_on_bw6_761`.
//!
//! It implements field variables for `algebra::ed_on_bw6_761::Fq`,
//! and group variables for `algebra::ed_on_bw6_761::GroupProjective`.
//!
//! The field underlying these constraints is `algebra::ed_on_bw6_761::Fq`.
//!
//! # Examples
//!
//! One can perform standard algebraic operations on `FqVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! use algebra::{UniformRand, ed_on_bw6_761::*};
//! use r1cs_core::*;
//! use r1cs_std::prelude::*;
//! use r1cs_std::ed_on_bw6_761::*;
//!
//! let cs = ConstraintSystem::<Fq>::new_ref();
//! // This rng is just for test purposes; do not use it
//! // in real applications.
//! let mut rng = algebra::test_rng();
//!
//! // Generate some random `Fq` elements.
//! let a_native = Fq::rand(&mut rng);
//! let b_native = Fq::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = FqVar::new_witness(r1cs_core::ns!(cs, "generate_a"), || Ok(a_native))?;
//! let b = FqVar::new_witness(r1cs_core::ns!(cs, "generate_b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = FqVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = FqVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let one = FqVar::one();
//! let zero = FqVar::zero();
//!
//! // Sanity check one + one = two
//! let two = &one + &one + &zero;
//! two.enforce_equal(&one.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that the value of &a * &b is correct.
//! assert_eq!((&a * &b).value()?, a_native * &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! One can also perform standard algebraic operations on `EdwardsVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, ed_on_bw6_761::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::ed_on_bw6_761::*;
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate some random `Edwards` elements.
//! let a_native = EdwardsProjective::rand(&mut rng);
//! let b_native = EdwardsProjective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = EdwardsVar::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = EdwardsVar::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = EdwardsVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = EdwardsVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! // This returns the identity of `Edwards`.
//! let zero = EdwardsVar::zero();
//!
//! // Sanity check one + one = two
//! let two_a = &a + &a + &zero;
//! two_a.enforce_equal(&a.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
pub use crate::instantiated::ed_on_cp6_782::*;

+ 0
- 12
r1cs-std/src/instantiated/ed_on_cp6_782/curves.rs

@ -1,12 +0,0 @@
use crate::groups::curves::twisted_edwards::AffineVar;
use algebra::ed_on_cp6_782::*;
use crate::instantiated::ed_on_cp6_782::FqVar;
/// A variable that is the R1CS equivalent of `algebra::ed_on_cp6_782::EdwardsAffine`.
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
#[test]
fn test() {
crate::groups::curves::twisted_edwards::test::<EdwardsParameters, EdwardsVar>().unwrap();
}

+ 0
- 10
r1cs-std/src/instantiated/ed_on_cp6_782/fields.rs

@ -1,10 +0,0 @@
use crate::fields::fp::FpVar;
use algebra::ed_on_cp6_782::fq::Fq;
/// A variable that is the R1CS equivalent of `algebra::ed_on_cp6_782::Fq`.
pub type FqVar = FpVar<Fq>;
#[test]
fn test() {
crate::fields::tests::field_test::<_, _, FqVar>().unwrap();
}

+ 0
- 108
r1cs-std/src/instantiated/ed_on_cp6_782/mod.rs

@ -1,108 +0,0 @@
#![allow(unreachable_pub)]
//! This module implements the R1CS equivalent of `algebra::ed_on_cp6_782`.
//!
//! It implements field variables for `algebra::ed_on_cp6_782::Fq`,
//! and group variables for `algebra::ed_on_cp6_782::GroupProjective`.
//!
//! The field underlying these constraints is `algebra::ed_on_cp6_782::Fq`.
//!
//! # Examples
//!
//! One can perform standard algebraic operations on `FqVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! use algebra::{UniformRand, ed_on_cp6_782::*};
//! use r1cs_core::*;
//! use r1cs_std::prelude::*;
//! use r1cs_std::ed_on_cp6_782::*;
//!
//! let cs = ConstraintSystem::<Fq>::new_ref();
//! // This rng is just for test purposes; do not use it
//! // in real applications.
//! let mut rng = algebra::test_rng();
//!
//! // Generate some random `Fq` elements.
//! let a_native = Fq::rand(&mut rng);
//! let b_native = Fq::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = FqVar::new_witness(r1cs_core::ns!(cs, "generate_a"), || Ok(a_native))?;
//! let b = FqVar::new_witness(r1cs_core::ns!(cs, "generate_b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = FqVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = FqVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let one = FqVar::one();
//! let zero = FqVar::zero();
//!
//! // Sanity check one + one = two
//! let two = &one + &one + &zero;
//! two.enforce_equal(&one.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that the value of &a * &b is correct.
//! assert_eq!((&a * &b).value()?, a_native * &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! One can also perform standard algebraic operations on `EdwardsVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, ed_on_cp6_782::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::ed_on_cp6_782::*;
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate some random `Edwards` elements.
//! let a_native = EdwardsProjective::rand(&mut rng);
//! let b_native = EdwardsProjective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = EdwardsVar::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = EdwardsVar::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = EdwardsVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = EdwardsVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! // This returns the identity of `Edwards`.
//! let zero = EdwardsVar::zero();
//!
//! // Sanity check one + one = two
//! let two_a = &a + &a + &zero;
//! two_a.enforce_equal(&a.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
mod curves;
mod fields;
pub use curves::*;
pub use fields::*;

+ 0
- 12
r1cs-std/src/instantiated/ed_on_mnt4_298/curves.rs

@ -1,12 +0,0 @@
use crate::groups::curves::twisted_edwards::AffineVar;
use algebra::ed_on_mnt4_298::*;
use crate::instantiated::ed_on_mnt4_298::fields::FqVar;
/// A variable that is the R1CS equivalent of `algebra::ed_on_mnt4_298::EdwardsAffine`.
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
#[test]
fn test() {
crate::groups::curves::twisted_edwards::test::<EdwardsParameters, EdwardsVar>().unwrap();
}

+ 0
- 10
r1cs-std/src/instantiated/ed_on_mnt4_298/fields.rs

@ -1,10 +0,0 @@
use crate::fields::fp::FpVar;
use algebra::ed_on_mnt4_298::fq::Fq;
/// A variable that is the R1CS equivalent of `algebra::ed_on_mnt4_298::Fq`.
pub type FqVar = FpVar<Fq>;
#[test]
fn test() {
crate::fields::tests::field_test::<_, _, FqVar>().unwrap();
}

+ 0
- 107
r1cs-std/src/instantiated/ed_on_mnt4_298/mod.rs

@ -1,107 +0,0 @@
//! This module implements the R1CS equivalent of `algebra::ed_on_mnt4_298`.
//!
//! It implements field variables for `algebra::ed_on_mnt4_298::Fq`,
//! and group variables for `algebra::ed_on_mnt4_298::GroupProjective`.
//!
//! The field underlying these constraints is `algebra::ed_on_mnt4_298::Fq`.
//!
//! # Examples
//!
//! One can perform standard algebraic operations on `FqVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! use algebra::{UniformRand, ed_on_mnt4_298::*};
//! use r1cs_core::*;
//! use r1cs_std::prelude::*;
//! use r1cs_std::ed_on_mnt4_298::*;
//!
//! let cs = ConstraintSystem::<Fq>::new_ref();
//! // This rng is just for test purposes; do not use it
//! // in real applications.
//! let mut rng = algebra::test_rng();
//!
//! // Generate some random `Fq` elements.
//! let a_native = Fq::rand(&mut rng);
//! let b_native = Fq::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = FqVar::new_witness(r1cs_core::ns!(cs, "generate_a"), || Ok(a_native))?;
//! let b = FqVar::new_witness(r1cs_core::ns!(cs, "generate_b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = FqVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = FqVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let one = FqVar::one();
//! let zero = FqVar::zero();
//!
//! // Sanity check one + one = two
//! let two = &one + &one + &zero;
//! two.enforce_equal(&one.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that the value of &a * &b is correct.
//! assert_eq!((&a * &b).value()?, a_native * &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! One can also perform standard algebraic operations on `EdwardsVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, ed_on_mnt4_298::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::ed_on_mnt4_298::*;
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate some random `Edwards` elements.
//! let a_native = EdwardsProjective::rand(&mut rng);
//! let b_native = EdwardsProjective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = EdwardsVar::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = EdwardsVar::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = EdwardsVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = EdwardsVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! // This returns the identity of `Edwards`.
//! let zero = EdwardsVar::zero();
//!
//! // Sanity check one + one = two
//! let two_a = &a + &a + &zero;
//! two_a.enforce_equal(&a.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
mod curves;
mod fields;
pub use curves::*;
pub use fields::*;

+ 0
- 12
r1cs-std/src/instantiated/ed_on_mnt4_753/curves.rs

@ -1,12 +0,0 @@
use crate::groups::curves::twisted_edwards::AffineVar;
use algebra::ed_on_mnt4_753::*;
use crate::instantiated::ed_on_mnt4_753::fields::FqVar;
/// A variable that is the R1CS equivalent of `algebra::ed_on_mnt4_753::EdwardsAffine`.
pub type EdwardsVar = AffineVar<EdwardsParameters, FqVar>;
#[test]
fn test() {
crate::groups::curves::twisted_edwards::test::<EdwardsParameters, EdwardsVar>().unwrap();
}

+ 0
- 10
r1cs-std/src/instantiated/ed_on_mnt4_753/fields.rs

@ -1,10 +0,0 @@
use crate::fields::fp::FpVar;
use algebra::ed_on_mnt4_753::fq::Fq;
/// A variable that is the R1CS equivalent of `algebra::ed_on_mnt4_753::Fq`.
pub type FqVar = FpVar<Fq>;
#[test]
fn test() {
crate::fields::tests::field_test::<_, _, FqVar>().unwrap();
}

+ 0
- 107
r1cs-std/src/instantiated/ed_on_mnt4_753/mod.rs

@ -1,107 +0,0 @@
//! This module implements the R1CS equivalent of `algebra::ed_on_mnt4_753`.
//!
//! It implements field variables for `algebra::ed_on_mnt4_753::Fq`,
//! and group variables for `algebra::ed_on_mnt4_753::GroupProjective`.
//!
//! The field underlying these constraints is `algebra::ed_on_mnt4_753::Fq`.
//!
//! # Examples
//!
//! One can perform standard algebraic operations on `FqVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! use algebra::{UniformRand, ed_on_mnt4_753::*};
//! use r1cs_core::*;
//! use r1cs_std::prelude::*;
//! use r1cs_std::ed_on_mnt4_753::*;
//!
//! let cs = ConstraintSystem::<Fq>::new_ref();
//! // This rng is just for test purposes; do not use it
//! // in real applications.
//! let mut rng = algebra::test_rng();
//!
//! // Generate some random `Fq` elements.
//! let a_native = Fq::rand(&mut rng);
//! let b_native = Fq::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = FqVar::new_witness(r1cs_core::ns!(cs, "generate_a"), || Ok(a_native))?;
//! let b = FqVar::new_witness(r1cs_core::ns!(cs, "generate_b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = FqVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = FqVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let one = FqVar::one();
//! let zero = FqVar::zero();
//!
//! // Sanity check one + one = two
//! let two = &one + &one + &zero;
//! two.enforce_equal(&one.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that the value of &a * &b is correct.
//! assert_eq!((&a * &b).value()?, a_native * &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! One can also perform standard algebraic operations on `EdwardsVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, ed_on_mnt4_753::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::ed_on_mnt4_753::*;
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate some random `Edwards` elements.
//! let a_native = EdwardsProjective::rand(&mut rng);
//! let b_native = EdwardsProjective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = EdwardsVar::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = EdwardsVar::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = EdwardsVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = EdwardsVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! // This returns the identity of `Edwards`.
//! let zero = EdwardsVar::zero();
//!
//! // Sanity check one + one = two
//! let two_a = &a + &a + &zero;
//! two_a.enforce_equal(&a.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
mod curves;
mod fields;
pub use curves::*;
pub use fields::*;

+ 0
- 29
r1cs-std/src/instantiated/mnt4_298/curves.rs

@ -1,29 +0,0 @@
use crate::groups::mnt4;
use algebra::mnt4_298::Parameters;
/// An element of G1 in the MNT4-298 bilinear group.
pub type G1Var = mnt4::G1Var<Parameters>;
/// An element of G2 in the MNT4-298 bilinear group.
pub type G2Var = mnt4::G2Var<Parameters>;
/// Represents the cached precomputation that can be performed on a G1 element
/// which enables speeding up pairing computation.
pub type G1PreparedVar = mnt4::G1PreparedVar<Parameters>;
/// Represents the cached precomputation that can be performed on a G2 element
/// which enables speeding up pairing computation.
pub type G2PreparedVar = mnt4::G2PreparedVar<Parameters>;
#[test]
fn test() {
use algebra::curves::models::mnt4::MNT4Parameters;
crate::groups::curves::short_weierstrass::test::<
<Parameters as MNT4Parameters>::G1Parameters,
G1Var,
>()
.unwrap();
crate::groups::curves::short_weierstrass::test::<
<Parameters as MNT4Parameters>::G2Parameters,
G2Var,
>()
.unwrap();
}

+ 0
- 26
r1cs-std/src/instantiated/mnt4_298/fields.rs

@ -1,26 +0,0 @@
use algebra::mnt4_298::{Fq, Fq2Parameters, Fq4Parameters};
use crate::fields::{fp::FpVar, fp2::Fp2Var, fp4::Fp4Var};
/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq`.
pub type FqVar = FpVar<Fq>;
/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq2`.
pub type Fq2Var = Fp2Var<Fq2Parameters>;
/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq4`.
pub type Fq4Var = Fp4Var<Fq4Parameters>;
#[test]
fn mnt4_298_field_gadgets_test() {
use super::*;
use crate::fields::tests::*;
use algebra::mnt4_298::{Fq, Fq2, Fq4};
field_test::<_, _, FqVar>().unwrap();
frobenius_tests::<Fq, _, FqVar>(13).unwrap();
field_test::<_, _, Fq2Var>().unwrap();
frobenius_tests::<Fq2, _, Fq2Var>(13).unwrap();
field_test::<_, _, Fq4Var>().unwrap();
frobenius_tests::<Fq4, _, Fq4Var>(13).unwrap();
}

+ 0
- 157
r1cs-std/src/instantiated/mnt4_298/mod.rs

@ -1,157 +0,0 @@
//! This module implements the R1CS equivalent of `algebra::mnt4_298`.
//!
//! It implements field variables for `algebra::mnt4_298::{Fq, Fq2, Fq4}`,
//! group variables for `algebra::mnt4_298::{G1, G2}`, and implements constraint
//! generation for computing `MNT4_298::pairing`.
//!
//! The field underlying these constraints is `algebra::mnt4_298::Fq`.
//!
//! # Examples
//!
//! One can perform standard algebraic operations on `FqVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! use algebra::{UniformRand, mnt4_298::*};
//! use r1cs_core::*;
//! use r1cs_std::prelude::*;
//! use r1cs_std::mnt4_298::*;
//!
//! let cs = ConstraintSystem::<Fq>::new_ref();
//! // This rng is just for test purposes; do not use it
//! // in real applications.
//! let mut rng = algebra::test_rng();
//!
//! // Generate some random `Fq` elements.
//! let a_native = Fq::rand(&mut rng);
//! let b_native = Fq::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = FqVar::new_witness(r1cs_core::ns!(cs, "generate_a"), || Ok(a_native))?;
//! let b = FqVar::new_witness(r1cs_core::ns!(cs, "generate_b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = FqVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = FqVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let one = FqVar::one();
//! let zero = FqVar::zero();
//!
//! // Sanity check one + one = two
//! let two = &one + &one + &zero;
//! two.enforce_equal(&one.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that the value of &a * &b is correct.
//! assert_eq!((&a * &b).value()?, a_native * &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! One can also perform standard algebraic operations on `G1Var` and `G2Var`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, mnt4_298::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::mnt4_298::*;
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate some random `G1` elements.
//! let a_native = G1Projective::rand(&mut rng);
//! let b_native = G1Projective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = G1Var::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = G1Var::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = G1Var::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = G1Var::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! // This returns the identity of `G1`.
//! let zero = G1Var::zero();
//!
//! // Sanity check one + one = two
//! let two_a = &a + &a + &zero;
//! two_a.enforce_equal(&a.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! Finally, one can check pairing computations as well:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, PairingEngine, mnt4_298::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::mnt4_298::{self, *};
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate random `G1` and `G2` elements.
//! let a_native = G1Projective::rand(&mut rng);
//! let b_native = G2Projective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = G1Var::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = G2Var::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = G1Var::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = G2Var::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let pairing_result_native = MNT4_298::pairing(a_native, b_native);
//!
//! // Prepare `a` and `b` for pairing.
//! let a_prep = mnt4_298::PairingVar::prepare_g1(&a)?;
//! let b_prep = mnt4_298::PairingVar::prepare_g2(&b)?;
//! let pairing_result = mnt4_298::PairingVar::pairing(a_prep, b_prep)?;
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!(pairing_result.value()?, pairing_result_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! let a_prep_const = mnt4_298::PairingVar::prepare_g1(&a_const)?;
//! let b_prep_const = mnt4_298::PairingVar::prepare_g2(&b_const)?;
//! let pairing_result_const = mnt4_298::PairingVar::pairing(a_prep_const, b_prep_const)?;
//! println!("Done here 3");
//!
//! pairing_result.enforce_equal(&pairing_result_const)?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
mod curves;
mod fields;
mod pairing;
pub use curves::*;
pub use fields::*;
pub use pairing::*;

+ 0
- 9
r1cs-std/src/instantiated/mnt4_298/pairing.rs

@ -1,9 +0,0 @@
use algebra::mnt4_298::Parameters;
/// Specifies the constraints for computing a pairing in the MNT4-298 bilinear group.
pub type PairingVar = crate::pairing::mnt4::PairingVar<Parameters>;
#[test]
fn test() {
crate::pairing::tests::bilinearity_test::<algebra::MNT4_298, PairingVar>().unwrap()
}

+ 0
- 29
r1cs-std/src/instantiated/mnt4_753/curves.rs

@ -1,29 +0,0 @@
use crate::groups::mnt4;
use algebra::mnt4_753::Parameters;
/// An element of G1 in the MNT4-753 bilinear group.
pub type G1Var = mnt4::G1Var<Parameters>;
/// An element of G2 in the MNT4-753 bilinear group.
pub type G2Var = mnt4::G2Var<Parameters>;
/// Represents the cached precomputation that can be performed on a G1 element
/// which enables speeding up pairing computation.
pub type G1PreparedVar = mnt4::G1PreparedVar<Parameters>;
/// Represents the cached precomputation that can be performed on a G2 element
/// which enables speeding up pairing computation.
pub type G2PreparedVar = mnt4::G2PreparedVar<Parameters>;
#[test]
fn test() {
use algebra::curves::models::mnt4::MNT4Parameters;
crate::groups::curves::short_weierstrass::test::<
<Parameters as MNT4Parameters>::G1Parameters,
G1Var,
>()
.unwrap();
crate::groups::curves::short_weierstrass::test::<
<Parameters as MNT4Parameters>::G2Parameters,
G2Var,
>()
.unwrap();
}

+ 0
- 26
r1cs-std/src/instantiated/mnt4_753/fields.rs

@ -1,26 +0,0 @@
use algebra::mnt4_753::{Fq, Fq2Parameters, Fq4Parameters};
use crate::fields::{fp::FpVar, fp2::Fp2Var, fp4::Fp4Var};
/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq`.
pub type FqVar = FpVar<Fq>;
/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq2`.
pub type Fq2Var = Fp2Var<Fq2Parameters>;
/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq4`.
pub type Fq4Var = Fp4Var<Fq4Parameters>;
#[test]
fn mnt4_753_field_gadgets_test() {
use super::*;
use crate::fields::tests::*;
use algebra::mnt4_753::{Fq, Fq2, Fq4};
field_test::<_, _, FqVar>().unwrap();
frobenius_tests::<Fq, _, FqVar>(13).unwrap();
field_test::<_, _, Fq2Var>().unwrap();
frobenius_tests::<Fq2, _, Fq2Var>(13).unwrap();
field_test::<_, _, Fq4Var>().unwrap();
frobenius_tests::<Fq4, _, Fq4Var>(13).unwrap();
}

+ 0
- 157
r1cs-std/src/instantiated/mnt4_753/mod.rs

@ -1,157 +0,0 @@
//! This module implements the R1CS equivalent of `algebra::mnt4_753`.
//!
//! It implements field variables for `algebra::mnt4_753::{Fq, Fq2, Fq4}`,
//! group variables for `algebra::mnt4_753::{G1, G2}`, and implements constraint
//! generation for computing `MNT4_753::pairing`.
//!
//! The field underlying these constraints is `algebra::mnt4_753::Fq`.
//!
//! # Examples
//!
//! One can perform standard algebraic operations on `FqVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! use algebra::{UniformRand, mnt4_753::*};
//! use r1cs_core::*;
//! use r1cs_std::prelude::*;
//! use r1cs_std::mnt4_753::*;
//!
//! let cs = ConstraintSystem::<Fq>::new_ref();
//! // This rng is just for test purposes; do not use it
//! // in real applications.
//! let mut rng = algebra::test_rng();
//!
//! // Generate some random `Fq` elements.
//! let a_native = Fq::rand(&mut rng);
//! let b_native = Fq::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = FqVar::new_witness(r1cs_core::ns!(cs, "generate_a"), || Ok(a_native))?;
//! let b = FqVar::new_witness(r1cs_core::ns!(cs, "generate_b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = FqVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = FqVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let one = FqVar::one();
//! let zero = FqVar::zero();
//!
//! // Sanity check one + one = two
//! let two = &one + &one + &zero;
//! two.enforce_equal(&one.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that the value of &a * &b is correct.
//! assert_eq!((&a * &b).value()?, a_native * &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! One can also perform standard algebraic operations on `G1Var` and `G2Var`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, mnt4_753::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::mnt4_753::*;
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate some random `G1` elements.
//! let a_native = G1Projective::rand(&mut rng);
//! let b_native = G1Projective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = G1Var::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = G1Var::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = G1Var::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = G1Var::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! // This returns the identity of `G1`.
//! let zero = G1Var::zero();
//!
//! // Sanity check one + one = two
//! let two_a = &a + &a + &zero;
//! two_a.enforce_equal(&a.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! Finally, one can check pairing computations as well:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, PairingEngine, mnt4_753::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::mnt4_753::{self, *};
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate random `G1` and `G2` elements.
//! let a_native = G1Projective::rand(&mut rng);
//! let b_native = G2Projective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = G1Var::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = G2Var::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = G1Var::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = G2Var::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let pairing_result_native = MNT4_753::pairing(a_native, b_native);
//!
//! // Prepare `a` and `b` for pairing.
//! let a_prep = mnt4_753::PairingVar::prepare_g1(&a)?;
//! let b_prep = mnt4_753::PairingVar::prepare_g2(&b)?;
//! let pairing_result = mnt4_753::PairingVar::pairing(a_prep, b_prep)?;
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!(pairing_result.value()?, pairing_result_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! let a_prep_const = mnt4_753::PairingVar::prepare_g1(&a_const)?;
//! let b_prep_const = mnt4_753::PairingVar::prepare_g2(&b_const)?;
//! let pairing_result_const = mnt4_753::PairingVar::pairing(a_prep_const, b_prep_const)?;
//! println!("Done here 3");
//!
//! pairing_result.enforce_equal(&pairing_result_const)?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
mod curves;
mod fields;
mod pairing;
pub use curves::*;
pub use fields::*;
pub use pairing::*;

+ 0
- 9
r1cs-std/src/instantiated/mnt4_753/pairing.rs

@ -1,9 +0,0 @@
use algebra::mnt4_753::Parameters;
/// Specifies the constraints for computing a pairing in the MNT4-753 bilinear group.
pub type PairingVar = crate::pairing::mnt4::PairingVar<Parameters>;
#[test]
fn test() {
crate::pairing::tests::bilinearity_test::<algebra::MNT4_753, PairingVar>().unwrap()
}

+ 0
- 29
r1cs-std/src/instantiated/mnt6_298/curves.rs

@ -1,29 +0,0 @@
use crate::groups::mnt6;
use algebra::mnt6_298::Parameters;
/// An element of G1 in the MNT6-298 bilinear group.
pub type G1Var = mnt6::G1Var<Parameters>;
/// An element of G2 in the MNT6-298 bilinear group.
pub type G2Var = mnt6::G2Var<Parameters>;
/// Represents the cached precomputation that can be performed on a G1 element
/// which enables speeding up pairing computation.
pub type G1PreparedVar = mnt6::G1PreparedVar<Parameters>;
/// Represents the cached precomputation that can be performed on a G2 element
/// which enables speeding up pairing computation.
pub type G2PreparedVar = mnt6::G2PreparedVar<Parameters>;
#[test]
fn test() {
use algebra::curves::models::mnt6::MNT6Parameters;
crate::groups::curves::short_weierstrass::test::<
<Parameters as MNT6Parameters>::G1Parameters,
G1Var,
>()
.unwrap();
crate::groups::curves::short_weierstrass::test::<
<Parameters as MNT6Parameters>::G2Parameters,
G2Var,
>()
.unwrap();
}

+ 0
- 26
r1cs-std/src/instantiated/mnt6_298/fields.rs

@ -1,26 +0,0 @@
use algebra::mnt6_298::{Fq, Fq3Parameters, Fq6Parameters};
use crate::fields::{fp::FpVar, fp3::Fp3Var, fp6_2over3::Fp6Var};
/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq`.
pub type FqVar = FpVar<Fq>;
/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq3`.
pub type Fq3Var = Fp3Var<Fq3Parameters>;
/// A variable that is the R1CS equivalent of `algebra::mnt4_298::Fq6`.
pub type Fq6Var = Fp6Var<Fq6Parameters>;
#[test]
fn mnt6_298_field_gadgets_test() {
use super::*;
use crate::fields::tests::*;
use algebra::mnt6_298::{Fq, Fq3, Fq6};
field_test::<_, _, FqVar>().unwrap();
frobenius_tests::<Fq, _, FqVar>(13).unwrap();
field_test::<_, _, Fq3Var>().unwrap();
frobenius_tests::<Fq3, _, Fq3Var>(13).unwrap();
field_test::<_, _, Fq6Var>().unwrap();
frobenius_tests::<Fq6, _, Fq6Var>(13).unwrap();
}

+ 0
- 157
r1cs-std/src/instantiated/mnt6_298/mod.rs

@ -1,157 +0,0 @@
//! This module implements the R1CS equivalent of `algebra::mnt6_298`.
//!
//! It implements field variables for `algebra::mnt6_298::{Fq, Fq3, Fq6}`,
//! group variables for `algebra::mnt6_298::{G1, G2}`, and implements constraint
//! generation for computing `MNT6_298::pairing`.
//!
//! The field underlying these constraints is `algebra::mnt6_298::Fq`.
//!
//! # Examples
//!
//! One can perform standard algebraic operations on `FqVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! use algebra::{UniformRand, mnt6_298::*};
//! use r1cs_core::*;
//! use r1cs_std::prelude::*;
//! use r1cs_std::mnt6_298::*;
//!
//! let cs = ConstraintSystem::<Fq>::new_ref();
//! // This rng is just for test purposes; do not use it
//! // in real applications.
//! let mut rng = algebra::test_rng();
//!
//! // Generate some random `Fq` elements.
//! let a_native = Fq::rand(&mut rng);
//! let b_native = Fq::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = FqVar::new_witness(r1cs_core::ns!(cs, "generate_a"), || Ok(a_native))?;
//! let b = FqVar::new_witness(r1cs_core::ns!(cs, "generate_b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = FqVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = FqVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let one = FqVar::one();
//! let zero = FqVar::zero();
//!
//! // Sanity check one + one = two
//! let two = &one + &one + &zero;
//! two.enforce_equal(&one.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that the value of &a * &b is correct.
//! assert_eq!((&a * &b).value()?, a_native * &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! One can also perform standard algebraic operations on `G1Var` and `G2Var`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, mnt6_298::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::mnt6_298::*;
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate some random `G1` elements.
//! let a_native = G1Projective::rand(&mut rng);
//! let b_native = G1Projective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = G1Var::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = G1Var::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = G1Var::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = G1Var::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! // This returns the identity of `G1`.
//! let zero = G1Var::zero();
//!
//! // Sanity check one + one = two
//! let two_a = &a + &a + &zero;
//! two_a.enforce_equal(&a.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! Finally, one can check pairing computations as well:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, PairingEngine, mnt6_298::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::mnt6_298::{self, *};
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate random `G1` and `G2` elements.
//! let a_native = G1Projective::rand(&mut rng);
//! let b_native = G2Projective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = G1Var::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = G2Var::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = G1Var::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = G2Var::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let pairing_result_native = MNT6_298::pairing(a_native, b_native);
//!
//! // Prepare `a` and `b` for pairing.
//! let a_prep = mnt6_298::PairingVar::prepare_g1(&a)?;
//! let b_prep = mnt6_298::PairingVar::prepare_g2(&b)?;
//! let pairing_result = mnt6_298::PairingVar::pairing(a_prep, b_prep)?;
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!(pairing_result.value()?, pairing_result_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! let a_prep_const = mnt6_298::PairingVar::prepare_g1(&a_const)?;
//! let b_prep_const = mnt6_298::PairingVar::prepare_g2(&b_const)?;
//! let pairing_result_const = mnt6_298::PairingVar::pairing(a_prep_const, b_prep_const)?;
//! println!("Done here 3");
//!
//! pairing_result.enforce_equal(&pairing_result_const)?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
mod curves;
mod fields;
mod pairing;
pub use curves::*;
pub use fields::*;
pub use pairing::*;

+ 0
- 9
r1cs-std/src/instantiated/mnt6_298/pairing.rs

@ -1,9 +0,0 @@
use algebra::mnt6_298::Parameters;
/// Specifies the constraints for computing a pairing in the MNT6-298 bilinear group.
pub type PairingVar = crate::pairing::mnt6::PairingVar<Parameters>;
#[test]
fn test() {
crate::pairing::tests::bilinearity_test::<algebra::MNT6_298, PairingVar>().unwrap()
}

+ 0
- 29
r1cs-std/src/instantiated/mnt6_753/curves.rs

@ -1,29 +0,0 @@
use crate::groups::mnt6;
use algebra::mnt6_753::Parameters;
/// An element of G1 in the MNT6-753 bilinear group.
pub type G1Var = mnt6::G1Var<Parameters>;
/// An element of G2 in the MNT6-753 bilinear group.
pub type G2Var = mnt6::G2Var<Parameters>;
/// Represents the cached precomputation that can be performed on a G1 element
/// which enables speeding up pairing computation.
pub type G1PreparedVar = mnt6::G1PreparedVar<Parameters>;
/// Represents the cached precomputation that can be performed on a G2 element
/// which enables speeding up pairing computation.
pub type G2PreparedVar = mnt6::G2PreparedVar<Parameters>;
#[test]
fn test() {
use algebra::curves::models::mnt6::MNT6Parameters;
crate::groups::curves::short_weierstrass::test::<
<Parameters as MNT6Parameters>::G1Parameters,
G1Var,
>()
.unwrap();
crate::groups::curves::short_weierstrass::test::<
<Parameters as MNT6Parameters>::G2Parameters,
G2Var,
>()
.unwrap();
}

+ 0
- 26
r1cs-std/src/instantiated/mnt6_753/fields.rs

@ -1,26 +0,0 @@
use algebra::mnt6_753::{Fq, Fq3Parameters, Fq6Parameters};
use crate::fields::{fp::FpVar, fp3::Fp3Var, fp6_2over3::Fp6Var};
/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq`.
pub type FqVar = FpVar<Fq>;
/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq3`.
pub type Fq3Var = Fp3Var<Fq3Parameters>;
/// A variable that is the R1CS equivalent of `algebra::mnt4_753::Fq6`.
pub type Fq6Var = Fp6Var<Fq6Parameters>;
#[test]
fn mnt6_753_field_gadgets_test() {
use super::*;
use crate::fields::tests::*;
use algebra::mnt6_753::{Fq, Fq3, Fq6};
field_test::<_, _, FqVar>().unwrap();
frobenius_tests::<Fq, _, FqVar>(13).unwrap();
field_test::<_, _, Fq3Var>().unwrap();
frobenius_tests::<Fq3, _, Fq3Var>(13).unwrap();
field_test::<_, _, Fq6Var>().unwrap();
frobenius_tests::<Fq6, _, Fq6Var>(13).unwrap();
}

+ 0
- 157
r1cs-std/src/instantiated/mnt6_753/mod.rs

@ -1,157 +0,0 @@
//! This module implements the R1CS equivalent of `algebra::mnt6_753`.
//!
//! It implements field variables for `algebra::mnt6_753::{Fq, Fq3, Fq6}`,
//! group variables for `algebra::mnt6_753::{G1, G2}`, and implements constraint
//! generation for computing `MNT6_753::pairing`.
//!
//! The field underlying these constraints is `algebra::mnt6_753::Fq`.
//!
//! # Examples
//!
//! One can perform standard algebraic operations on `FqVar`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! use algebra::{UniformRand, mnt6_753::*};
//! use r1cs_core::*;
//! use r1cs_std::prelude::*;
//! use r1cs_std::mnt6_753::*;
//!
//! let cs = ConstraintSystem::<Fq>::new_ref();
//! // This rng is just for test purposes; do not use it
//! // in real applications.
//! let mut rng = algebra::test_rng();
//!
//! // Generate some random `Fq` elements.
//! let a_native = Fq::rand(&mut rng);
//! let b_native = Fq::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = FqVar::new_witness(r1cs_core::ns!(cs, "generate_a"), || Ok(a_native))?;
//! let b = FqVar::new_witness(r1cs_core::ns!(cs, "generate_b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = FqVar::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = FqVar::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let one = FqVar::one();
//! let zero = FqVar::zero();
//!
//! // Sanity check one + one = two
//! let two = &one + &one + &zero;
//! two.enforce_equal(&one.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that the value of &a * &b is correct.
//! assert_eq!((&a * &b).value()?, a_native * &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! One can also perform standard algebraic operations on `G1Var` and `G2Var`:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, mnt6_753::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::mnt6_753::*;
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate some random `G1` elements.
//! let a_native = G1Projective::rand(&mut rng);
//! let b_native = G1Projective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = G1Var::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = G1Var::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = G1Var::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = G1Var::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! // This returns the identity of `G1`.
//! let zero = G1Var::zero();
//!
//! // Sanity check one + one = two
//! let two_a = &a + &a + &zero;
//! two_a.enforce_equal(&a.double()?)?;
//!
//! assert!(cs.is_satisfied()?);
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!((&a + &b).value()?, a_native + &b_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! (&a + &b).enforce_equal(&(&a_const + &b_const))?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
//!
//! Finally, one can check pairing computations as well:
//!
//! ```
//! # fn main() -> Result<(), r1cs_core::SynthesisError> {
//! # use algebra::{UniformRand, PairingEngine, mnt6_753::*};
//! # use r1cs_core::*;
//! # use r1cs_std::prelude::*;
//! # use r1cs_std::mnt6_753::{self, *};
//!
//! # let cs = ConstraintSystem::<Fq>::new_ref();
//! # let mut rng = algebra::test_rng();
//!
//! // Generate random `G1` and `G2` elements.
//! let a_native = G1Projective::rand(&mut rng);
//! let b_native = G2Projective::rand(&mut rng);
//!
//! // Allocate `a_native` and `b_native` as witness variables in `cs`.
//! let a = G1Var::new_witness(r1cs_core::ns!(cs, "a"), || Ok(a_native))?;
//! let b = G2Var::new_witness(r1cs_core::ns!(cs, "b"), || Ok(b_native))?;
//!
//! // Allocate `a_native` and `b_native` as constants in `cs`. This does not add any
//! // constraints or variables.
//! let a_const = G1Var::new_constant(r1cs_core::ns!(cs, "a_as_constant"), a_native)?;
//! let b_const = G2Var::new_constant(r1cs_core::ns!(cs, "b_as_constant"), b_native)?;
//!
//! let pairing_result_native = MNT6_753::pairing(a_native, b_native);
//!
//! // Prepare `a` and `b` for pairing.
//! let a_prep = mnt6_753::PairingVar::prepare_g1(&a)?;
//! let b_prep = mnt6_753::PairingVar::prepare_g2(&b)?;
//! let pairing_result = mnt6_753::PairingVar::pairing(a_prep, b_prep)?;
//!
//! // Check that the value of &a + &b is correct.
//! assert_eq!(pairing_result.value()?, pairing_result_native);
//!
//! // Check that operations on variables and constants are equivalent.
//! let a_prep_const = mnt6_753::PairingVar::prepare_g1(&a_const)?;
//! let b_prep_const = mnt6_753::PairingVar::prepare_g2(&b_const)?;
//! let pairing_result_const = mnt6_753::PairingVar::pairing(a_prep_const, b_prep_const)?;
//! println!("Done here 3");
//!
//! pairing_result.enforce_equal(&pairing_result_const)?;
//! assert!(cs.is_satisfied()?);
//! # Ok(())
//! # }
//! ```
mod curves;
mod fields;
mod pairing;
pub use curves::*;
pub use fields::*;
pub use pairing::*;

+ 0
- 9
r1cs-std/src/instantiated/mnt6_753/pairing.rs

@ -1,9 +0,0 @@
use algebra::mnt6_753::Parameters;
/// Specifies the constraints for computing a pairing in the MNT6-753 bilinear group.
pub type PairingVar = crate::pairing::mnt6::PairingVar<Parameters>;
#[test]
fn test() {
crate::pairing::tests::bilinearity_test::<algebra::MNT6_753, PairingVar>().unwrap()
}

+ 0
- 38
r1cs-std/src/instantiated/mod.rs

@ -1,38 +0,0 @@
#[cfg(feature = "bls12_377")]
pub mod bls12_377;
#[cfg(feature = "ed_on_bls12_377")]
pub mod ed_on_bls12_377;
#[cfg(feature = "ed_on_cp6_782")]
pub mod ed_on_cp6_782;
#[cfg(all(not(feature = "ed_on_cp6_782"), feature = "ed_on_bw6_761"))]
pub(crate) mod ed_on_cp6_782;
#[cfg(feature = "ed_on_bw6_761")]
pub mod ed_on_bw6_761;
#[cfg(feature = "ed_on_bn254")]
pub mod ed_on_bn254;
#[cfg(feature = "ed_on_bls12_381")]
pub mod ed_on_bls12_381;
#[cfg(feature = "ed_on_mnt4_298")]
pub mod ed_on_mnt4_298;
#[cfg(feature = "ed_on_mnt4_753")]
pub mod ed_on_mnt4_753;
#[cfg(feature = "mnt4_298")]
pub mod mnt4_298;
#[cfg(feature = "mnt4_753")]
pub mod mnt4_753;
#[cfg(feature = "mnt6_298")]
pub mod mnt6_298;
#[cfg(feature = "mnt6_753")]
pub mod mnt6_753;

+ 0
- 187
r1cs-std/src/lib.rs

@ -1,187 +0,0 @@
//! This crate implements common "gadgets" that make
//! programming rank-1 constraint systems easier.
#![cfg_attr(not(feature = "std"), no_std)]
#![deny(unused_import_braces, unused_qualifications, trivial_casts)]
#![deny(trivial_numeric_casts, variant_size_differences, unreachable_pub)]
#![deny(non_shorthand_field_patterns, unused_attributes, unused_imports)]
#![deny(unused_extern_crates, renamed_and_removed_lints, unused_allocation)]
#![deny(unused_comparisons, bare_trait_objects, const_err, unused_must_use)]
#![deny(unused_mut, unused_unsafe, private_in_public, unsafe_code)]
#![deny(missing_docs)]
#![forbid(unsafe_code)]
#[doc(hidden)]
#[cfg(all(test, not(feature = "std")))]
#[macro_use]
extern crate std;
#[doc(hidden)]
#[cfg(not(feature = "std"))]
extern crate alloc as ralloc;
#[doc(hidden)]
#[macro_use]
extern crate algebra;
#[doc(hidden)]
#[macro_use]
extern crate derivative;
/// Some utility macros for making downstream impls easier.
#[macro_use]
pub mod macros;
#[cfg(not(feature = "std"))]
use ralloc::vec::Vec;
#[cfg(feature = "std")]
use std::vec::Vec;
use algebra::prelude::Field;
/// This module implements gadgets related to bit manipulation, such as `Boolean` and `UInt`s.
pub mod bits;
pub use self::bits::*;
/// This module implements gadgets related to field arithmetic.
pub mod fields;
/// This module implements gadgets related to group arithmetic, and specifically elliptic curve arithmetic.
pub mod groups;
mod instantiated;
#[cfg(feature = "bls12_377")]
pub use instantiated::bls12_377;
#[cfg(feature = "ed_on_bn254")]
pub use instantiated::ed_on_bn254;
#[cfg(feature = "ed_on_bls12_377")]
pub use instantiated::ed_on_bls12_377;
#[cfg(feature = "ed_on_mnt4_298")]
pub use instantiated::ed_on_mnt4_298;
#[cfg(feature = "ed_on_mnt4_753")]
pub use instantiated::ed_on_mnt4_753;
#[cfg(feature = "ed_on_cp6_782")]
pub use instantiated::ed_on_cp6_782;
#[cfg(feature = "ed_on_bw6_761")]
pub use instantiated::ed_on_bw6_761;
#[cfg(feature = "ed_on_bls12_381")]
pub use instantiated::ed_on_bls12_381;
#[cfg(feature = "mnt4_298")]
pub use instantiated::mnt4_298;
#[cfg(feature = "mnt4_753")]
pub use instantiated::mnt4_753;
#[cfg(feature = "mnt6_298")]
pub use instantiated::mnt6_298;
#[cfg(feature = "mnt6_753")]
pub use instantiated::mnt6_753;
/// This module implements gadgets related to computing pairings in bilinear groups.
pub mod pairing;
/// This module describes a trait for allocating new variables in a constraint system.
pub mod alloc;
/// This module describes a trait for checking equality of variables.
pub mod eq;
/// This module describes traits for conditionally selecting a variable from a list of variables.
pub mod select;
#[allow(missing_docs)]
pub mod prelude {
pub use crate::{
alloc::*,
bits::{boolean::Boolean, uint32::UInt32, uint8::UInt8, ToBitsGadget, ToBytesGadget},
eq::*,
fields::{FieldOpsBounds, FieldVar},
groups::{CurveVar, GroupOpsBounds},
instantiated::*,
pairing::PairingVar,
select::*,
R1CSVar,
};
}
/// This trait describes some core functionality that is common to high-level variables,
/// such as `Boolean`s, `FieldVar`s, `GroupVar`s, etc.
pub trait R1CSVar<F: Field> {
/// The type of the "native" value that `Self` represents in the constraint system.
type Value: core::fmt::Debug + Eq + Clone;
/// Returns the underlying `ConstraintSystemRef`.
///
/// If `self` is a constant value, then this *must* return `r1cs_core::ConstraintSystemRef::None`.
fn cs(&self) -> r1cs_core::ConstraintSystemRef<F>;
/// Returns `true` if `self` is a circuit-generation-time constant.
fn is_constant(&self) -> bool {
self.cs().is_none()
}
/// Returns the value that is assigned to `self` in the underlying
/// `ConstraintSystem`.
fn value(&self) -> Result<Self::Value, r1cs_core::SynthesisError>;
}
impl<F: Field, T: R1CSVar<F>> R1CSVar<F> for [T] {
type Value = Vec<T::Value>;
fn cs(&self) -> r1cs_core::ConstraintSystemRef<F> {
let mut result = r1cs_core::ConstraintSystemRef::None;
for var in self {
result = var.cs().or(result);
}
result
}
fn value(&self) -> Result<Self::Value, r1cs_core::SynthesisError> {
let mut result = Vec::new();
for var in self {
result.push(var.value()?);
}
Ok(result)
}
}
impl<'a, F: Field, T: 'a + R1CSVar<F>> R1CSVar<F> for &'a T {
type Value = T::Value;
fn cs(&self) -> r1cs_core::ConstraintSystemRef<F> {
(*self).cs()
}
fn value(&self) -> Result<Self::Value, r1cs_core::SynthesisError> {
(*self).value()
}
}
/// A utility trait to convert `Self` to `Result<T, SynthesisErrorA`.>
pub trait Assignment<T> {
/// Converts `self` to `Result`.
fn get(self) -> Result<T, r1cs_core::SynthesisError>;
}
impl<T> Assignment<T> for Option<T> {
fn get(self) -> Result<T, r1cs_core::SynthesisError> {
self.ok_or(r1cs_core::SynthesisError::AssignmentMissing)
}
}
/// Specifies how to convert a variable of type `Self` to variables of
/// type `FpVar<ConstraintF>`
pub trait ToConstraintFieldGadget<ConstraintF: algebra::PrimeField> {
/// Converts `self` to `FpVar<ConstraintF>` variables.
fn to_constraint_field(
&self,
) -> Result<Vec<crate::fields::fp::FpVar<ConstraintF>>, r1cs_core::SynthesisError>;
}

+ 0
- 183
r1cs-std/src/pairing/mod.rs

@ -1,183 +0,0 @@
use crate::prelude::*;
use algebra::{Field, PairingEngine};
use core::fmt::Debug;
use r1cs_core::SynthesisError;
/// This module implements pairings for BLS12 bilinear groups.
pub mod bls12;
/// This module implements pairings for MNT4 bilinear groups.
pub mod mnt4;
/// This module implements pairings for MNT6 bilinear groups.
pub mod mnt6;
/// Specifies the constraints for computing a pairing in the yybilinear group `E`.
pub trait PairingVar<E: PairingEngine, ConstraintF: Field = <E as PairingEngine>::Fq> {
/// An variable representing an element of `G1`.
/// This is the R1CS equivalent of `E::G1Projective`.
type G1Var: CurveVar<E::G1Projective, ConstraintF>
+ AllocVar<E::G1Projective, ConstraintF>
+ AllocVar<E::G1Affine, ConstraintF>;
/// An variable representing an element of `G2`.
/// This is the R1CS equivalent of `E::G2Projective`.
type G2Var: CurveVar<E::G2Projective, ConstraintF>
+ AllocVar<E::G2Projective, ConstraintF>
+ AllocVar<E::G2Affine, ConstraintF>;
/// An variable representing an element of `GT`.
/// This is the R1CS equivalent of `E::GT`.
type GTVar: FieldVar<E::Fqk, ConstraintF>;
/// An variable representing cached precomputation that can speed up pairings computations.
/// This is the R1CS equivalent of `E::G1Prepared`.
type G1PreparedVar: ToBytesGadget<ConstraintF>
+ AllocVar<E::G1Prepared, ConstraintF>
+ Clone
+ Debug;
/// An variable representing cached precomputation that can speed up pairings computations.
/// This is the R1CS equivalent of `E::G2Prepared`.
type G2PreparedVar: ToBytesGadget<ConstraintF>
+ AllocVar<E::G2Prepared, ConstraintF>
+ Clone
+ Debug;
/// Computes a multi-miller loop between elements
/// of `p` and `q`.
fn miller_loop(
p: &[Self::G1PreparedVar],
q: &[Self::G2PreparedVar],
) -> Result<Self::GTVar, SynthesisError>;
/// Computes a final exponentiation over `p`.
fn final_exponentiation(p: &Self::GTVar) -> Result<Self::GTVar, SynthesisError>;
/// Computes a pairing over `p` and `q`.
#[tracing::instrument(target = "r1cs")]
fn pairing(
p: Self::G1PreparedVar,
q: Self::G2PreparedVar,
) -> Result<Self::GTVar, SynthesisError> {
let tmp = Self::miller_loop(&[p], &[q])?;
Self::final_exponentiation(&tmp)
}
/// Computes a product of pairings over the elements in `p` and `q`.
#[must_use]
#[tracing::instrument(target = "r1cs")]
fn product_of_pairings(
p: &[Self::G1PreparedVar],
q: &[Self::G2PreparedVar],
) -> Result<Self::GTVar, SynthesisError> {
let miller_result = Self::miller_loop(p, q)?;
Self::final_exponentiation(&miller_result)
}
/// Performs the precomputation to generate `Self::G1PreparedVar`.
fn prepare_g1(q: &Self::G1Var) -> Result<Self::G1PreparedVar, SynthesisError>;
/// Performs the precomputation to generate `Self::G2PreparedVar`.
fn prepare_g2(q: &Self::G2Var) -> Result<Self::G2PreparedVar, SynthesisError>;
}
#[cfg(test)]
pub(crate) mod tests {
use crate::{prelude::*, Vec};
use algebra::{
test_rng, BitIteratorLE, Field, PairingEngine, PrimeField, ProjectiveCurve, UniformRand,
};
use r1cs_core::{ConstraintSystem, SynthesisError};
#[allow(dead_code)]
pub(crate) fn bilinearity_test<E: PairingEngine, P: PairingVar<E>>(
) -> Result<(), SynthesisError>
where
for<'a> &'a P::G1Var: GroupOpsBounds<'a, E::G1Projective, P::G1Var>,
for<'a> &'a P::G2Var: GroupOpsBounds<'a, E::G2Projective, P::G2Var>,
for<'a> &'a P::GTVar: FieldOpsBounds<'a, E::Fqk, P::GTVar>,
{
let cs = ConstraintSystem::<E::Fq>::new_ref();
let mut rng = test_rng();
let a = E::G1Projective::rand(&mut rng);
let b = E::G2Projective::rand(&mut rng);
let s = E::Fr::rand(&mut rng);
let mut sa = a;
sa *= s;
let mut sb = b;
sb *= s;
let a_g = P::G1Var::new_witness(cs.clone(), || Ok(a.into_affine()))?;
let b_g = P::G2Var::new_witness(cs.clone(), || Ok(b.into_affine()))?;
let sa_g = P::G1Var::new_witness(cs.clone(), || Ok(sa.into_affine()))?;
let sb_g = P::G2Var::new_witness(cs.clone(), || Ok(sb.into_affine()))?;
let mut preparation_num_constraints = cs.num_constraints();
let a_prep_g = P::prepare_g1(&a_g)?;
let b_prep_g = P::prepare_g2(&b_g)?;
preparation_num_constraints = cs.num_constraints() - preparation_num_constraints;
println!(
"Preparation num constraints: {}",
preparation_num_constraints
);
let sa_prep_g = P::prepare_g1(&sa_g)?;
let sb_prep_g = P::prepare_g2(&sb_g)?;
let (ans1_g, ans1_n) = {
let ml_constraints = cs.num_constraints();
let ml_g = P::miller_loop(&[sa_prep_g], &[b_prep_g.clone()])?;
println!(
"ML num constraints: {}",
cs.num_constraints() - ml_constraints
);
let fe_constraints = cs.num_constraints();
let ans_g = P::final_exponentiation(&ml_g)?;
println!(
"FE num constraints: {}",
cs.num_constraints() - fe_constraints
);
let ans_n = E::pairing(sa, b);
(ans_g, ans_n)
};
let (ans2_g, ans2_n) = {
let ans_g = P::pairing(a_prep_g.clone(), sb_prep_g)?;
let ans_n = E::pairing(a, sb);
(ans_g, ans_n)
};
let (ans3_g, ans3_n) = {
let s_iter = BitIteratorLE::without_trailing_zeros(s.into_repr())
.map(Boolean::constant)
.collect::<Vec<_>>();
let mut ans_g = P::pairing(a_prep_g, b_prep_g)?;
let mut ans_n = E::pairing(a, b);
ans_n = ans_n.pow(s.into_repr());
ans_g = ans_g.pow_le(&s_iter)?;
(ans_g, ans_n)
};
ans1_g.enforce_equal(&ans2_g)?;
ans2_g.enforce_equal(&ans3_g)?;
assert_eq!(ans1_g.value()?, ans1_n, "Failed native test 1");
assert_eq!(ans2_g.value()?, ans2_n, "Failed native test 2");
assert_eq!(ans3_g.value()?, ans3_n, "Failed native test 3");
assert_eq!(ans1_n, ans2_n, "Failed ans1_native == ans2_native");
assert_eq!(ans2_n, ans3_n, "Failed ans2_native == ans3_native");
assert_eq!(ans1_g.value()?, ans3_g.value()?, "Failed ans1 == ans3");
assert_eq!(ans1_g.value()?, ans2_g.value()?, "Failed ans1 == ans2");
assert_eq!(ans2_g.value()?, ans3_g.value()?, "Failed ans2 == ans3");
if !cs.is_satisfied().unwrap() {
println!("Unsatisfied: {:?}", cs.which_is_unsatisfied());
}
assert!(cs.is_satisfied().unwrap(), "cs is not satisfied");
Ok(())
}
}

r1cs-std/src/alloc.rs → src/alloc.rs

@ -1,7 +1,7 @@
use crate::Vec;
use algebra::Field;
use ark_ff::Field;
use ark_relations::r1cs::{Namespace, SynthesisError};
use core::borrow::Borrow;
use r1cs_core::{Namespace, SynthesisError};
/// Describes the mode that a variable should be allocated in within
/// a `ConstraintSystem`.
@ -22,7 +22,8 @@ pub enum AllocationMode {
}
impl AllocationMode {
/// Outputs the maximum according to the relation `Constant < Input < Witness`.
/// Outputs the maximum according to the relation `Constant < Input <
/// Witness`.
pub fn max(&self, other: Self) -> Self {
use AllocationMode::*;
match (self, other) {
@ -34,7 +35,8 @@ impl AllocationMode {
}
}
/// Specifies how variables of type `Self` should be allocated in a `ConstraintSystem`.
/// Specifies how variables of type `Self` should be allocated in a
/// `ConstraintSystem`.
pub trait AllocVar<V, F: Field>
where
Self: Sized,
@ -59,7 +61,8 @@ where
Self::new_variable(cs, || Ok(t), AllocationMode::Constant)
}
/// Allocates a new public input of type `Self` in the `ConstraintSystem` `cs`.
/// Allocates a new public input of type `Self` in the `ConstraintSystem`
/// `cs`.
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_input<T: Borrow<V>>(
cs: impl Into<Namespace<F>>,
@ -68,7 +71,8 @@ where
Self::new_variable(cs, f, AllocationMode::Input)
}
/// Allocates a new private witness of type `Self` in the `ConstraintSystem` `cs`.
/// Allocates a new private witness of type `Self` in the `ConstraintSystem`
/// `cs`.
#[tracing::instrument(target = "r1cs", skip(cs, f))]
fn new_witness<T: Borrow<V>>(
cs: impl Into<Namespace<F>>,

r1cs-std/src/bits/boolean.rs → src/bits/boolean.rs

@ -1,8 +1,10 @@
use algebra::{BitIteratorBE, Field, PrimeField};
use ark_ff::{BitIteratorBE, Field, PrimeField};
use crate::{fields::fp::FpVar, prelude::*, Assignment, ToConstraintFieldGadget, Vec};
use ark_relations::r1cs::{
ConstraintSystemRef, LinearCombination, Namespace, SynthesisError, Variable,
};
use core::borrow::Borrow;
use r1cs_core::{lc, ConstraintSystemRef, LinearCombination, Namespace, SynthesisError, Variable};
/// Represents a variable in the constraint system which is guaranteed
/// to be either zero or one.
@ -277,11 +279,11 @@ impl Boolean {
/// This *does not* create any new variables or constraints.
///
/// ```
/// # fn main() -> Result<(), r1cs_core::SynthesisError> {
/// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
/// // We'll use the BLS12-381 scalar field for our constraints.
/// use algebra::bls12_381::Fr;
/// use r1cs_core::*;
/// use r1cs_std::prelude::*;
/// use ark_test_curves::bls12_381::Fr;
/// use ark_relations::r1cs::*;
/// use ark_r1cs_std::prelude::*;
///
/// let cs = ConstraintSystem::<Fr>::new_ref();
/// let t = Boolean::<Fr>::TRUE;
@ -308,10 +310,10 @@ impl Boolean {
///
/// This *does not* create any new variables or constraints.
/// ```
/// # fn main() -> Result<(), r1cs_core::SynthesisError> {
/// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
/// // We'll use the BLS12-381 scalar field for our constraints.
/// use algebra::bls12_381::Fr;
/// use r1cs_std::prelude::*;
/// use ark_test_curves::bls12_381::Fr;
/// use ark_r1cs_std::prelude::*;
///
/// let true_var = Boolean::<Fr>::TRUE;
/// let false_var = Boolean::<Fr>::FALSE;
@ -329,11 +331,11 @@ impl Boolean {
///
/// This *does not* create any new variables or constraints.
/// ```
/// # fn main() -> Result<(), r1cs_core::SynthesisError> {
/// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
/// // We'll use the BLS12-381 scalar field for our constraints.
/// use algebra::bls12_381::Fr;
/// use r1cs_core::*;
/// use r1cs_std::prelude::*;
/// use ark_test_curves::bls12_381::Fr;
/// use ark_relations::r1cs::*;
/// use ark_r1cs_std::prelude::*;
///
/// let cs = ConstraintSystem::<Fr>::new_ref();
///
@ -364,11 +366,11 @@ impl Boolean {
/// *does not* create any constraints or variables.
///
/// ```
/// # fn main() -> Result<(), r1cs_core::SynthesisError> {
/// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
/// // We'll use the BLS12-381 scalar field for our constraints.
/// use algebra::bls12_381::Fr;
/// use r1cs_core::*;
/// use r1cs_std::prelude::*;
/// use ark_test_curves::bls12_381::Fr;
/// use ark_relations::r1cs::*;
/// use ark_r1cs_std::prelude::*;
///
/// let cs = ConstraintSystem::<Fr>::new_ref();
///
@ -406,11 +408,11 @@ impl Boolean {
/// *does not* create any constraints or variables.
///
/// ```
/// # fn main() -> Result<(), r1cs_core::SynthesisError> {
/// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
/// // We'll use the BLS12-381 scalar field for our constraints.
/// use algebra::bls12_381::Fr;
/// use r1cs_core::*;
/// use r1cs_std::prelude::*;
/// use ark_test_curves::bls12_381::Fr;
/// use ark_relations::r1cs::*;
/// use ark_r1cs_std::prelude::*;
///
/// let cs = ConstraintSystem::<Fr>::new_ref();
///
@ -447,11 +449,11 @@ impl Boolean {
/// *does not* create any constraints or variables.
///
/// ```
/// # fn main() -> Result<(), r1cs_core::SynthesisError> {
/// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
/// // We'll use the BLS12-381 scalar field for our constraints.
/// use algebra::bls12_381::Fr;
/// use r1cs_core::*;
/// use r1cs_std::prelude::*;
/// use ark_test_curves::bls12_381::Fr;
/// use ark_relations::r1cs::*;
/// use ark_r1cs_std::prelude::*;
///
/// let cs = ConstraintSystem::<Fr>::new_ref();
///
@ -488,11 +490,11 @@ impl Boolean {
/// Outputs `bits[0] & bits[1] & ... & bits.last().unwrap()`.
///
/// ```
/// # fn main() -> Result<(), r1cs_core::SynthesisError> {
/// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
/// // We'll use the BLS12-381 scalar field for our constraints.
/// use algebra::bls12_381::Fr;
/// use r1cs_core::*;
/// use r1cs_std::prelude::*;
/// use ark_test_curves::bls12_381::Fr;
/// use ark_relations::r1cs::*;
/// use ark_r1cs_std::prelude::*;
///
/// let cs = ConstraintSystem::<Fr>::new_ref();
///
@ -525,11 +527,11 @@ impl Boolean {
/// Outputs `bits[0] | bits[1] | ... | bits.last().unwrap()`.
///
/// ```
/// # fn main() -> Result<(), r1cs_core::SynthesisError> {
/// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
/// // We'll use the BLS12-381 scalar field for our constraints.
/// use algebra::bls12_381::Fr;
/// use r1cs_core::*;
/// use r1cs_std::prelude::*;
/// use ark_test_curves::bls12_381::Fr;
/// use ark_relations::r1cs::*;
/// use ark_r1cs_std::prelude::*;
///
/// let cs = ConstraintSystem::<Fr>::new_ref();
///
@ -563,11 +565,11 @@ impl Boolean {
/// Outputs `(bits[0] & bits[1] & ... & bits.last().unwrap()).not()`.
///
/// ```
/// # fn main() -> Result<(), r1cs_core::SynthesisError> {
/// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
/// // We'll use the BLS12-381 scalar field for our constraints.
/// use algebra::bls12_381::Fr;
/// use r1cs_core::*;
/// use r1cs_std::prelude::*;
/// use ark_test_curves::bls12_381::Fr;
/// use ark_relations::r1cs::*;
/// use ark_r1cs_std::prelude::*;
///
/// let cs = ConstraintSystem::<Fr>::new_ref();
///
@ -590,7 +592,8 @@ impl Boolean {
/// Enforces that `Self::kary_nand(bits).is_eq(&Boolean::TRUE)`.
///
/// Informally, this means that at least one element in `bits` must be `false`.
/// Informally, this means that at least one element in `bits` must be
/// `false`.
#[tracing::instrument(target = "r1cs")]
fn enforce_kary_nand(bits: &[Self]) -> Result<(), SynthesisError> {
use Boolean::*;
@ -605,9 +608,10 @@ impl Boolean {
}
}
/// Enforces that `bits`, when interpreted as a integer, is less than `F::characteristic()`,
/// That is, interpret bits as a little-endian integer, and enforce that this integer
/// is "in the field Z_p", where `p = F::characteristic()` .
/// Enforces that `bits`, when interpreted as a integer, is less than
/// `F::characteristic()`, That is, interpret bits as a little-endian
/// integer, and enforce that this integer is "in the field Z_p", where
/// `p = F::characteristic()` .
#[tracing::instrument(target = "r1cs")]
pub fn enforce_in_field_le(bits: &[Self]) -> Result<(), SynthesisError> {
// `bits` < F::characteristic() <==> `bits` <= F::characteristic() -1
@ -681,15 +685,16 @@ impl Boolean {
Ok(current_run)
}
/// Conditionally selects one of `first` and `second` based on the value of `self`:
/// Conditionally selects one of `first` and `second` based on the value of
/// `self`:
///
/// If `self.is_eq(&Boolean::TRUE)`, this outputs `first`; else, it outputs `second`.
/// ```
/// # fn main() -> Result<(), r1cs_core::SynthesisError> {
/// If `self.is_eq(&Boolean::TRUE)`, this outputs `first`; else, it outputs
/// `second`. ```
/// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
/// // We'll use the BLS12-381 scalar field for our constraints.
/// use algebra::bls12_381::Fr;
/// use r1cs_core::*;
/// use r1cs_std::prelude::*;
/// use ark_test_curves::bls12_381::Fr;
/// use ark_relations::r1cs::*;
/// use ark_r1cs_std::prelude::*;
///
/// let cs = ConstraintSystem::<Fr>::new_ref();
///
@ -865,7 +870,6 @@ impl CondSelectGadget for Boolean {
Ok(if cond { a.value()? } else { b.value()? })
})?
.into();
//
// a = self; b = other; c = cond;
//
// r = c * a + (1 - c) * b
@ -901,10 +905,9 @@ impl CondSelectGadget for Boolean {
mod test {
use super::{AllocatedBit, Boolean};
use crate::prelude::*;
use algebra::{
bls12_381::Fr, BitIteratorBE, BitIteratorLE, Field, One, PrimeField, UniformRand, Zero,
};
use r1cs_core::{ConstraintSystem, Namespace, SynthesisError};
use ark_ff::{BitIteratorBE, BitIteratorLE, Field, One, PrimeField, UniformRand, Zero};
use ark_relations::r1cs::{ConstraintSystem, Namespace, SynthesisError};
use ark_test_curves::bls12_381::Fr;
use rand::SeedableRng;
use rand_xorshift::XorShiftRng;
@ -1093,7 +1096,7 @@ mod test {
}
let false_cond =
Boolean::new_witness(r1cs_core::ns!(cs, "cond"), || Ok(false))?;
Boolean::new_witness(ark_relations::ns!(cs, "cond"), || Ok(false))?;
a.conditional_enforce_equal(&b, &false_cond)?;
assert!(cs.is_satisfied().unwrap());
@ -1170,8 +1173,8 @@ mod test {
for second_operand in VARIANTS.iter().cloned() {
let cs = ConstraintSystem::<Fr>::new_ref();
let a = construct(r1cs_core::ns!(cs, "a"), first_operand)?;
let b = construct(r1cs_core::ns!(cs, "b"), second_operand)?;
let a = construct(ark_relations::ns!(cs, "a"), first_operand)?;
let b = construct(ark_relations::ns!(cs, "b"), second_operand)?;
let c = Boolean::xor(&a, &b)?;
assert!(cs.is_satisfied().unwrap());
@ -1300,9 +1303,9 @@ mod test {
for second_operand in VARIANTS.iter().cloned() {
let cs = ConstraintSystem::<Fr>::new_ref();
let cond = construct(r1cs_core::ns!(cs, "cond"), condition)?;
let a = construct(r1cs_core::ns!(cs, "a"), first_operand)?;
let b = construct(r1cs_core::ns!(cs, "b"), second_operand)?;
let cond = construct(ark_relations::ns!(cs, "cond"), condition)?;
let a = construct(ark_relations::ns!(cs, "a"), first_operand)?;
let b = construct(ark_relations::ns!(cs, "b"), second_operand)?;
let c = cond.select(&a, &b)?;
assert!(
@ -1332,8 +1335,8 @@ mod test {
for second_operand in VARIANTS.iter().cloned() {
let cs = ConstraintSystem::<Fr>::new_ref();
let a = construct(r1cs_core::ns!(cs, "a"), first_operand)?;
let b = construct(r1cs_core::ns!(cs, "b"), second_operand)?;
let a = construct(ark_relations::ns!(cs, "a"), first_operand)?;
let b = construct(ark_relations::ns!(cs, "b"), second_operand)?;
let c = a.or(&b)?;
assert!(cs.is_satisfied().unwrap());
@ -1453,8 +1456,8 @@ mod test {
for second_operand in VARIANTS.iter().cloned() {
let cs = ConstraintSystem::<Fr>::new_ref();
let a = construct(r1cs_core::ns!(cs, "a"), first_operand)?;
let b = construct(r1cs_core::ns!(cs, "b"), second_operand)?;
let a = construct(ark_relations::ns!(cs, "a"), first_operand)?;
let b = construct(ark_relations::ns!(cs, "b"), second_operand)?;
let c = a.and(&b)?;
assert!(cs.is_satisfied().unwrap());

r1cs-std/src/bits/mod.rs → src/bits/mod.rs

@ -2,15 +2,15 @@ use crate::{
bits::{boolean::Boolean, uint8::UInt8},
Vec,
};
use algebra::Field;
use r1cs_core::SynthesisError;
use ark_ff::Field;
use ark_relations::r1cs::SynthesisError;
/// This module contains `Boolean`, a R1CS equivalent of the `bool` type.
pub mod boolean;
/// This module contains `UInt8`, a R1CS equivalent of the `u8` type.
pub mod uint8;
/// This module contains a macro for generating `UIntN` types, which are R1CS equivalents of
/// `N`-bit unsigned integers.
/// This module contains a macro for generating `UIntN` types, which are R1CS
/// equivalents of `N`-bit unsigned integers.
#[macro_use]
pub mod uint;
@ -18,14 +18,16 @@ make_uint!(UInt16, 16, u16, uint16, "16");
make_uint!(UInt32, 32, u32, uint32, "32");
make_uint!(UInt64, 64, u64, uint64, "64");
/// Specifies constraints for conversion to a little-endian bit representation of `self`.
/// Specifies constraints for conversion to a little-endian bit representation
/// of `self`.
pub trait ToBitsGadget<F: Field> {
/// Outputs the canonical little-endian bit-wise representation of `self`.
///
/// This is the correct default for 99% of use cases.
fn to_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError>;
/// Outputs a possibly non-unique little-endian bit-wise representation of `self`.
/// Outputs a possibly non-unique little-endian bit-wise representation of
/// `self`.
///
/// If you're not absolutely certain that your usecase can get away with a
/// non-canonical representation, please use `self.to_bits()` instead.
@ -40,7 +42,8 @@ pub trait ToBitsGadget {
Ok(res)
}
/// Outputs a possibly non-unique big-endian bit-wise representation of `self`.
/// Outputs a possibly non-unique big-endian bit-wise representation of
/// `self`.
fn to_non_unique_bits_be(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
let mut res = self.to_non_unique_bits_le()?;
res.reverse();
@ -89,7 +92,8 @@ where
}
}
/// Specifies constraints for conversion to a little-endian byte representation of `self`.
/// Specifies constraints for conversion to a little-endian byte representation
/// of `self`.
pub trait ToBytesGadget<F: Field> {
/// Outputs a canonical, little-endian, byte decomposition of `self`.
///

r1cs-std/src/bits/uint.rs → src/bits/uint.rs

@ -6,12 +6,12 @@ macro_rules! make_uint {
#[doc = $native_doc_name]
#[doc = "`type."]
pub mod $mod_name {
use algebra::{Field, FpParameters, PrimeField};
use ark_ff::{Field, FpParameters, PrimeField};
use core::borrow::Borrow;
use core::convert::TryFrom;
use r1cs_core::{
lc, ConstraintSystemRef, LinearCombination, Namespace, SynthesisError, Variable,
use ark_relations::r1cs::{
ConstraintSystemRef, LinearCombination, Namespace, SynthesisError, Variable,
};
use crate::{
@ -357,8 +357,8 @@ macro_rules! make_uint {
mod test {
use super::$name;
use crate::{bits::boolean::Boolean, prelude::*, Vec};
use algebra::bls12_381::Fr;
use r1cs_core::{ConstraintSystem, SynthesisError};
use ark_test_curves::bls12_381::Fr;
use ark_relations::r1cs::{ConstraintSystem, SynthesisError};
use rand::{Rng, SeedableRng};
use rand_xorshift::XorShiftRng;
@ -481,10 +481,10 @@ macro_rules! make_uint {
let mut expected = (a ^ b).wrapping_add(c).wrapping_add(d);
let a_bit = $name::new_witness(r1cs_core::ns!(cs, "a_bit"), || Ok(a))?;
let a_bit = $name::new_witness(ark_relations::ns!(cs, "a_bit"), || Ok(a))?;
let b_bit = $name::constant(b);
let c_bit = $name::constant(c);
let d_bit = $name::new_witness(r1cs_core::ns!(cs, "d_bit"), || Ok(d))?;
let d_bit = $name::new_witness(ark_relations::ns!(cs, "d_bit"), || Ok(d))?;
let r = a_bit.xor(&b_bit).unwrap();
let r = $name::addmany(&[r, c_bit, d_bit]).unwrap();

r1cs-std/src/bits/uint8.rs → src/bits/uint8.rs

@ -1,7 +1,6 @@
use algebra::Field;
use algebra::{FpParameters, PrimeField, ToConstraintField};
use ark_ff::{Field, FpParameters, PrimeField, ToConstraintField};
use r1cs_core::{ConstraintSystemRef, Namespace, SynthesisError};
use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError};
use crate::{fields::fp::AllocatedFp, prelude::*, Assignment, Vec};
use core::borrow::Borrow;
@ -41,11 +40,11 @@ impl UInt8 {
///
/// This *does not* create any new variables or constraints.
/// ```
/// # fn main() -> Result<(), r1cs_core::SynthesisError> {
/// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
/// // We'll use the BLS12-381 scalar field for our constraints.
/// use algebra::bls12_381::Fr;
/// use r1cs_core::*;
/// use r1cs_std::prelude::*;
/// use ark_test_curves::bls12_381::Fr;
/// use ark_relations::r1cs::*;
/// use ark_r1cs_std::prelude::*;
///
/// let cs = ConstraintSystem::<Fr>::new_ref();
/// let var = vec![UInt8::new_witness(cs.clone(), || Ok(2))?];
@ -69,11 +68,11 @@ impl UInt8 {
/// This *does not* create new variables or constraints.
///
/// ```
/// # fn main() -> Result<(), r1cs_core::SynthesisError> {
/// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
/// // We'll use the BLS12-381 scalar field for our constraints.
/// use algebra::bls12_381::Fr;
/// use r1cs_core::*;
/// use r1cs_std::prelude::*;
/// use ark_test_curves::bls12_381::Fr;
/// use ark_relations::r1cs::*;
/// use ark_r1cs_std::prelude::*;
///
/// let cs = ConstraintSystem::<Fr>::new_ref();
/// let var = UInt8::new_witness(cs.clone(), || Ok(2))?;
@ -116,19 +115,19 @@ impl UInt8 {
}
/// Allocates a slice of `u8`'s as public inputs by first packing them into
/// elements of `F`, (thus reducing the number of input allocations), allocating
/// these elements as public inputs, and then converting these field variables
/// `FpVar<F>` variables back into bytes.
/// elements of `F`, (thus reducing the number of input allocations),
/// allocating these elements as public inputs, and then converting
/// these field variables `FpVar<F>` variables back into bytes.
///
/// From a user perspective, this trade-off adds constraints, but improves
/// verifier time and verification key size.
///
/// ```
/// # fn main() -> Result<(), r1cs_core::SynthesisError> {
/// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
/// // We'll use the BLS12-381 scalar field for our constraints.
/// use algebra::bls12_381::Fr;
/// use r1cs_core::*;
/// use r1cs_std::prelude::*;
/// use ark_test_curves::bls12_381::Fr;
/// use ark_relations::r1cs::*;
/// use ark_r1cs_std::prelude::*;
///
/// let cs = ConstraintSystem::<Fr>::new_ref();
/// let two = UInt8::new_witness(cs.clone(), || Ok(2))?;
@ -177,11 +176,11 @@ impl UInt8 {
/// `UInt8`.
///
/// ```
/// # fn main() -> Result<(), r1cs_core::SynthesisError> {
/// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
/// // We'll use the BLS12-381 scalar field for our constraints.
/// use algebra::bls12_381::Fr;
/// use r1cs_core::*;
/// use r1cs_std::prelude::*;
/// use ark_test_curves::bls12_381::Fr;
/// use ark_relations::r1cs::*;
/// use ark_r1cs_std::prelude::*;
///
/// let cs = ConstraintSystem::<Fr>::new_ref();
/// let var = UInt8::new_witness(cs.clone(), || Ok(128))?;
@ -222,11 +221,11 @@ impl UInt8 {
/// *does not* create any constraints or variables.
///
/// ```
/// # fn main() -> Result<(), r1cs_core::SynthesisError> {
/// # fn main() -> Result<(), ark_relations::r1cs::SynthesisError> {
/// // We'll use the BLS12-381 scalar field for our constraints.
/// use algebra::bls12_381::Fr;
/// use r1cs_core::*;
/// use r1cs_std::prelude::*;
/// use ark_test_curves::bls12_381::Fr;
/// use ark_relations::r1cs::*;
/// use ark_r1cs_std::prelude::*;
///
/// let cs = ConstraintSystem::<Fr>::new_ref();
/// let a = UInt8::new_witness(cs.clone(), || Ok(16))?;
@ -313,8 +312,8 @@ impl AllocVar for UInt8 {
mod test {
use super::UInt8;
use crate::{prelude::*, Vec};
use algebra::bls12_381::Fr;
use r1cs_core::{ConstraintSystem, SynthesisError};
use ark_relations::r1cs::{ConstraintSystem, SynthesisError};
use ark_test_curves::bls12_381::Fr;
use rand::{Rng, SeedableRng};
use rand_xorshift::XorShiftRng;
@ -322,7 +321,8 @@ mod test {
fn test_uint8_from_bits_to_bits() -> Result<(), SynthesisError> {
let cs = ConstraintSystem::<Fr>::new_ref();
let byte_val = 0b01110001;
let byte = UInt8::new_witness(r1cs_core::ns!(cs, "alloc value"), || Ok(byte_val)).unwrap();
let byte =
UInt8::new_witness(ark_relations::ns!(cs, "alloc value"), || Ok(byte_val)).unwrap();
let bits = byte.to_bits_le()?;
for (i, bit) in bits.iter().enumerate() {
assert_eq!(bit.value()?, (byte_val >> i) & 1 == 1)
@ -334,7 +334,8 @@ mod test {
fn test_uint8_new_input_vec() -> Result<(), SynthesisError> {
let cs = ConstraintSystem::<Fr>::new_ref();
let byte_vals = (64u8..128u8).collect::<Vec<_>>();
let bytes = UInt8::new_input_vec(r1cs_core::ns!(cs, "alloc value"), &byte_vals).unwrap();
let bytes =
UInt8::new_input_vec(ark_relations::ns!(cs, "alloc value"), &byte_vals).unwrap();
dbg!(bytes.value())?;
for (native, variable) in byte_vals.into_iter().zip(bytes) {
let bits = variable.to_bits_le()?;
@ -395,9 +396,9 @@ mod test {
let mut expected = a ^ b ^ c;
let a_bit = UInt8::new_witness(r1cs_core::ns!(cs, "a_bit"), || Ok(a)).unwrap();
let a_bit = UInt8::new_witness(ark_relations::ns!(cs, "a_bit"), || Ok(a)).unwrap();
let b_bit = UInt8::constant(b);
let c_bit = UInt8::new_witness(r1cs_core::ns!(cs, "c_bit"), || Ok(c)).unwrap();
let c_bit = UInt8::new_witness(ark_relations::ns!(cs, "c_bit"), || Ok(c)).unwrap();
let r = a_bit.xor(&b_bit).unwrap();
let r = r.xor(&c_bit).unwrap();

r1cs-std/src/eq.rs → src/eq.rs

@ -1,24 +1,28 @@
use crate::{prelude::*, Vec};
use algebra::Field;
use r1cs_core::SynthesisError;
use ark_ff::Field;
use ark_relations::r1cs::SynthesisError;
/// Specifies how to generate constraints that check for equality for two variables of type `Self`.
/// Specifies how to generate constraints that check for equality for two
/// variables of type `Self`.
pub trait EqGadget<F: Field> {
/// Output a `Boolean` value representing whether `self.value() == other.value()`.
/// Output a `Boolean` value representing whether `self.value() ==
/// other.value()`.
fn is_eq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError>;
/// Output a `Boolean` value representing whether `self.value() != other.value()`.
/// Output a `Boolean` value representing whether `self.value() !=
/// other.value()`.
///
/// By default, this is defined as `self.is_eq(other)?.not()`.
fn is_neq(&self, other: &Self) -> Result<Boolean<F>, SynthesisError> {
Ok(self.is_eq(other)?.not())
}
/// If `should_enforce == true`, enforce that `self` and `other` are equal; else,
/// enforce a vacuously true statement.
/// If `should_enforce == true`, enforce that `self` and `other` are equal;
/// else, enforce a vacuously true statement.
///
/// A safe default implementation is provided that generates the following constraints:
/// `self.is_eq(other)?.conditional_enforce_equal(&Boolean::TRUE, should_enforce)`.
/// A safe default implementation is provided that generates the following
/// constraints: `self.is_eq(other)?.conditional_enforce_equal(&Boolean:
/// :TRUE, should_enforce)`.
///
/// More efficient specialized implementation may be possible; implementors
/// are encouraged to carefully analyze the efficiency and safety of these.
@ -34,8 +38,9 @@ pub trait EqGadget {
/// Enforce that `self` and `other` are equal.
///
/// A safe default implementation is provided that generates the following constraints:
/// `self.conditional_enforce_equal(other, &Boolean::TRUE)`.
/// A safe default implementation is provided that generates the following
/// constraints: `self.conditional_enforce_equal(other,
/// &Boolean::TRUE)`.
///
/// More efficient specialized implementation may be possible; implementors
/// are encouraged to carefully analyze the efficiency and safety of these.
@ -44,11 +49,12 @@ pub trait EqGadget {
self.conditional_enforce_equal(other, &Boolean::constant(true))
}
/// If `should_enforce == true`, enforce that `self` and `other` are *not* equal; else,
/// enforce a vacuously true statement.
/// If `should_enforce == true`, enforce that `self` and `other` are *not*
/// equal; else, enforce a vacuously true statement.
///
/// A safe default implementation is provided that generates the following constraints:
/// `self.is_neq(other)?.conditional_enforce_equal(&Boolean::TRUE, should_enforce)`.
/// A safe default implementation is provided that generates the following
/// constraints: `self.is_neq(other)?.conditional_enforce_equal(&
/// Boolean::TRUE, should_enforce)`.
///
/// More efficient specialized implementation may be possible; implementors
/// are encouraged to carefully analyze the efficiency and safety of these.
@ -64,8 +70,9 @@ pub trait EqGadget {
/// Enforce that `self` and `other` are *not* equal.
///
/// A safe default implementation is provided that generates the following constraints:
/// `self.conditional_enforce_not_equal(other, &Boolean::TRUE)`.
/// A safe default implementation is provided that generates the following
/// constraints: `self.conditional_enforce_not_equal(other,
/// &Boolean::TRUE)`.
///
/// More efficient specialized implementation may be possible; implementors
/// are encouraged to carefully analyze the efficiency and safety of these.

r1cs-std/src/fields/cubic_extension.rs → src/fields/cubic_extension.rs

@ -1,19 +1,18 @@
use algebra::{
use ark_ff::{
fields::{CubicExtField, CubicExtParameters, Field},
Zero,
};
use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError};
use core::{borrow::Borrow, marker::PhantomData};
use r1cs_core::{ConstraintSystemRef, Namespace, SynthesisError};
use crate::fields::fp::FpVar;
use crate::{
fields::{FieldOpsBounds, FieldVar},
fields::{fp::FpVar, FieldOpsBounds, FieldVar},
prelude::*,
ToConstraintFieldGadget, Vec,
};
/// This struct is the `R1CS` equivalent of the cubic extension field type
/// in `algebra-core`, i.e. `algebra_core::CubicExtField`.
/// in `ark-ff`, i.e. `ark_ff::CubicExtField`.
#[derive(Derivative)]
#[derivative(Debug(bound = "BF: core::fmt::Debug"), Clone(bound = "BF: Clone"))]
#[must_use]
@ -31,14 +30,16 @@ where
_params: PhantomData<P>,
}
/// This trait describes parameters that are used to implement arithmetic for `CubicExtVar`.
/// This trait describes parameters that are used to implement arithmetic for
/// `CubicExtVar`.
pub trait CubicExtVarParams<BF: FieldVar<Self::BaseField, Self::BasePrimeField>>:
CubicExtParameters
where
for<'a> &'a BF: FieldOpsBounds<'a, Self::BaseField, BF>,
{
/// Multiply the base field of the `CubicExtVar` by the appropriate Frobenius coefficient.
/// This is equivalent to `Self::mul_base_field_by_frob_coeff(c1, c2, power)`.
/// Multiply the base field of the `CubicExtVar` by the appropriate
/// Frobenius coefficient. This is equivalent to
/// `Self::mul_base_field_by_frob_coeff(c1, c2, power)`.
fn mul_base_field_vars_by_frob_coeff(c1: &mut BF, c2: &mut BF, power: usize);
}
@ -58,8 +59,8 @@ where
}
}
/// Multiplies a variable of the base field by the cubic nonresidue `P::NONRESIDUE` that
/// is used to construct the extension field.
/// Multiplies a variable of the base field by the cubic nonresidue
/// `P::NONRESIDUE` that is used to construct the extension field.
#[inline]
pub fn mul_base_field_by_nonresidue(fe: &BF) -> Result<BF, SynthesisError> {
Ok(fe * P::NONRESIDUE)
@ -570,9 +571,9 @@ where
),
};
let c0 = BF::new_variable(r1cs_core::ns!(cs, "c0"), || c0, mode)?;
let c1 = BF::new_variable(r1cs_core::ns!(cs, "c1"), || c1, mode)?;
let c2 = BF::new_variable(r1cs_core::ns!(cs, "c2"), || c2, mode)?;
let c0 = BF::new_variable(ark_relations::ns!(cs, "c0"), || c0, mode)?;
let c1 = BF::new_variable(ark_relations::ns!(cs, "c1"), || c1, mode)?;
let c2 = BF::new_variable(ark_relations::ns!(cs, "c2"), || c2, mode)?;
Ok(Self::new(c0, c1, c2))
}
}

r1cs-std/src/fields/fp/cmp.rs → src/fields/fp/cmp.rs

@ -4,16 +4,16 @@ use crate::{
prelude::*,
ToBitsGadget,
};
use algebra::PrimeField;
use ark_ff::PrimeField;
use ark_relations::r1cs::{SynthesisError, Variable};
use core::cmp::Ordering;
use r1cs_core::{lc, SynthesisError, Variable};
impl<F: PrimeField> FpVar<F> {
/// This function enforces the ordering between `self` and `other`. The
/// constraint system will not be satisfied otherwise. If `self` should
/// also be checked for equality, e.g. `self <= other` instead of `self < other`, set
/// `should_also_check_quality` to `true`. This variant verifies `self` and `other`
/// are `<= (p-1)/2`.
/// also be checked for equality, e.g. `self <= other` instead of `self <
/// other`, set `should_also_check_quality` to `true`. This variant
/// verifies `self` and `other` are `<= (p-1)/2`.
#[tracing::instrument(target = "r1cs")]
pub fn enforce_cmp(
&self,
@ -27,9 +27,10 @@ impl FpVar {
/// This function enforces the ordering between `self` and `other`. The
/// constraint system will not be satisfied otherwise. If `self` should
/// also be checked for equality, e.g. `self <= other` instead of `self < other`, set
/// `should_also_check_quality` to `true`. This variant assumes `self` and `other`
/// are `<= (p-1)/2` and does not generate constraints to verify that.
/// also be checked for equality, e.g. `self <= other` instead of `self <
/// other`, set `should_also_check_quality` to `true`. This variant
/// assumes `self` and `other` are `<= (p-1)/2` and does not generate
/// constraints to verify that.
#[tracing::instrument(target = "r1cs")]
pub fn enforce_cmp_unchecked(
&self,
@ -41,12 +42,12 @@ impl FpVar {
left.enforce_smaller_than_unchecked(&right)
}
/// This function checks the ordering between `self` and `other`. It outputs self
/// `Boolean` that contains the result - `1` if true, `0` otherwise. The
/// constraint system will be satisfied in any case. If `self` should
/// also be checked for equality, e.g. `self <= other` instead of `self < other`, set
/// `should_also_check_quality` to `true`. This variant verifies `self` and `other`
/// are `<= (p-1)/2`.
/// This function checks the ordering between `self` and `other`. It outputs
/// self `Boolean` that contains the result - `1` if true, `0`
/// otherwise. The constraint system will be satisfied in any case. If
/// `self` should also be checked for equality, e.g. `self <= other`
/// instead of `self < other`, set `should_also_check_quality` to
/// `true`. This variant verifies `self` and `other` are `<= (p-1)/2`.
#[tracing::instrument(target = "r1cs")]
pub fn is_cmp(
&self,
@ -58,12 +59,13 @@ impl FpVar {
left.is_smaller_than(&right)
}
/// This function checks the ordering between `self` and `other`. It outputs a
/// `Boolean` that contains the result - `1` if true, `0` otherwise. The
/// constraint system will be satisfied in any case. If `self` should
/// also be checked for equality, e.g. `self <= other` instead of `self < other`, set
/// `should_also_check_quality` to `true`. This variant assumes `self` and `other`
/// are `<= (p-1)/2` and does not generate constraints to verify that.
/// This function checks the ordering between `self` and `other`. It outputs
/// a `Boolean` that contains the result - `1` if true, `0` otherwise.
/// The constraint system will be satisfied in any case. If `self`
/// should also be checked for equality, e.g. `self <= other` instead of
/// `self < other`, set `should_also_check_quality` to `true`. This
/// variant assumes `self` and `other` are `<= (p-1)/2` and does not
/// generate constraints to verify that.
#[tracing::instrument(target = "r1cs")]
pub fn is_cmp_unchecked(
&self,
@ -109,17 +111,17 @@ impl FpVar {
Ok(())
}
/// Helper function to check `self < other` and output a result bit. This function
/// verifies `self` and `other` are `<= (p-1)/2`.
/// Helper function to check `self < other` and output a result bit. This
/// function verifies `self` and `other` are `<= (p-1)/2`.
fn is_smaller_than(&self, other: &FpVar<F>) -> Result<Boolean<F>, SynthesisError> {
self.enforce_smaller_or_equal_than_mod_minus_one_div_two()?;
other.enforce_smaller_or_equal_than_mod_minus_one_div_two()?;
self.is_smaller_than_unchecked(other)
}
/// Helper function to check `self < other` and output a result bit. This function
/// assumes `self` and `other` are `<= (p-1)/2` and does not generate constraints
/// to verify that.
/// Helper function to check `self < other` and output a result bit. This
/// function assumes `self` and `other` are `<= (p-1)/2` and does not
/// generate constraints to verify that.
fn is_smaller_than_unchecked(&self, other: &FpVar<F>) -> Result<Boolean<F>, SynthesisError> {
Ok((self - other)
.double()?
@ -129,16 +131,17 @@ impl FpVar {
.clone())
}
/// Helper function to enforce `self < other`. This function verifies `self` and `other`
/// are `<= (p-1)/2`.
/// Helper function to enforce `self < other`. This function verifies `self`
/// and `other` are `<= (p-1)/2`.
fn enforce_smaller_than(&self, other: &FpVar<F>) -> Result<(), SynthesisError> {
self.enforce_smaller_or_equal_than_mod_minus_one_div_two()?;
other.enforce_smaller_or_equal_than_mod_minus_one_div_two()?;
self.enforce_smaller_than_unchecked(other)
}
/// Helper function to enforce `self < other`. This function assumes `self` and `other`
/// are `<= (p-1)/2` and does not generate constraints to verify that.
/// Helper function to enforce `self < other`. This function assumes `self`
/// and `other` are `<= (p-1)/2` and does not generate constraints to
/// verify that.
fn enforce_smaller_than_unchecked(&self, other: &FpVar<F>) -> Result<(), SynthesisError> {
let is_smaller_than = self.is_smaller_than_unchecked(other)?;
let lc_one = lc!() + Variable::One;
@ -155,8 +158,9 @@ mod test {
use std::cmp::Ordering;
use crate::{alloc::AllocVar, fields::fp::FpVar};
use algebra::{bls12_381::Fr, PrimeField, UniformRand};
use r1cs_core::ConstraintSystem;
use ark_ff::{PrimeField, UniformRand};
use ark_relations::r1cs::ConstraintSystem;
use ark_test_curves::bls12_381::Fr;
#[test]
fn test_cmp() {

r1cs-std/src/fields/fp/mod.rs → src/fields/fp/mod.rs

@ -1,10 +1,15 @@
use algebra::{BigInteger, FpParameters, PrimeField};
use r1cs_core::{lc, ConstraintSystemRef, LinearCombination, Namespace, SynthesisError, Variable};
use ark_ff::{BigInteger, FpParameters, PrimeField};
use ark_relations::r1cs::{
ConstraintSystemRef, LinearCombination, Namespace, SynthesisError, Variable,
};
use core::borrow::Borrow;
use crate::fields::{FieldOpsBounds, FieldVar};
use crate::{prelude::*, Assignment, ToConstraintFieldGadget, Vec};
use crate::{
fields::{FieldOpsBounds, FieldVar},
prelude::*,
Assignment, ToConstraintFieldGadget, Vec,
};
mod cmp;
@ -21,8 +26,8 @@ pub struct AllocatedFp {
}
impl<F: PrimeField> AllocatedFp<F> {
/// Constructs a new `AllocatedFp` from a (optional) value, a low-level Variable,
/// and a `ConstraintSystemRef`.
/// Constructs a new `AllocatedFp` from a (optional) value, a low-level
/// Variable, and a `ConstraintSystemRef`.
pub fn new(value: Option<F>, variable: Variable, cs: ConstraintSystemRef<F>) -> Self {
Self {
value,
@ -88,7 +93,8 @@ impl<'a, F: PrimeField> FieldOpsBounds<'a, F, Self> for FpVar {}
impl<'a, F: PrimeField> FieldOpsBounds<'a, F, FpVar<F>> for &'a FpVar<F> {}
impl<F: PrimeField> AllocatedFp<F> {
/// Constructs `Self` from a `Boolean`: if `other` is false, this outputs `zero`, else it outputs `one`.
/// Constructs `Self` from a `Boolean`: if `other` is false, this outputs
/// `zero`, else it outputs `one`.
pub fn from(other: Boolean<F>) -> Self {
let cs = other.cs();
let variable = cs.new_lc(other.lc()).unwrap();
@ -307,7 +313,8 @@ impl AllocatedFp {
// ----------------------
// constraint 1:
// (self - other) * multiplier = is_not_equal
// => (non_zero) * multiplier = 1 (satisfied, because multiplier = 1/(self - other)
// => (non_zero) * multiplier = 1 (satisfied, because multiplier = 1/(self -
// other)
//
// constraint 2:
// (self - other) * not(is_not_equal) = 0
@ -398,8 +405,8 @@ impl AllocatedFp {
}
}
/****************************************************************************/
/****************************************************************************/
/// *************************************************************************
/// *************************************************************************
impl<F: PrimeField> ToBitsGadget<F> for AllocatedFp<F> {
/// Outputs the unique bit-wise decomposition of `self` in *little-endian*
@ -417,7 +424,7 @@ impl ToBitsGadget for AllocatedFp {
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
let cs = self.cs.clone();
use algebra::BitIteratorBE;
use ark_ff::BitIteratorBE;
let mut bits = if let Some(value) = self.value {
let field_char = BitIteratorBE::new(F::characteristic());
let bits: Vec<_> = BitIteratorBE::new(value.into_repr())
@ -740,9 +747,6 @@ impl FieldVar for FpVar {
}
}
/****************************************************************************/
/****************************************************************************/
impl_ops!(
FpVar<F>,
F,
@ -807,8 +811,8 @@ impl_ops!(
F: PrimeField
);
/****************************************************************************/
/****************************************************************************/
/// *************************************************************************
/// *************************************************************************
impl<F: PrimeField> EqGadget<F> for FpVar<F> {
#[tracing::instrument(target = "r1cs")]
@ -870,7 +874,7 @@ impl ToBitsGadget for FpVar {
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bits_le(&self) -> Result<Vec<Boolean<F>>, SynthesisError> {
use algebra::BitIteratorLE;
use ark_ff::BitIteratorLE;
match self {
Self::Constant(c) => Ok(BitIteratorLE::without_trailing_zeros(&c.into_repr())
.map(Boolean::constant)
@ -886,7 +890,7 @@ impl ToBytesGadget for FpVar {
#[tracing::instrument(target = "r1cs")]
fn to_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
match self {
Self::Constant(c) => Ok(UInt8::constant_vec(&to_bytes![c].unwrap())),
Self::Constant(c) => Ok(UInt8::constant_vec(&ark_ff::to_bytes![c].unwrap())),
Self::Var(v) => v.to_bytes(),
}
}
@ -894,7 +898,7 @@ impl ToBytesGadget for FpVar {
#[tracing::instrument(target = "r1cs")]
fn to_non_unique_bytes(&self) -> Result<Vec<UInt8<F>>, SynthesisError> {
match self {
Self::Constant(c) => Ok(UInt8::constant_vec(&to_bytes![c].unwrap())),
Self::Constant(c) => Ok(UInt8::constant_vec(&ark_ff::to_bytes![c].unwrap())),
Self::Var(v) => v.to_non_unique_bytes(),
}
}
@ -925,7 +929,7 @@ impl CondSelectGadget for FpVar {
// cond * t + (1 - cond) * f
Ok(is.mul_constant(*t).add(&not.mul_constant(*f)).into())
}
(_, _) => {
(..) => {
let cs = cond.cs();
let true_value = match true_value {
Self::Constant(f) => AllocatedFp::new_constant(cs.clone(), f)?,

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save