diff --git a/.gitignore b/.gitignore index f2af733bf1..81b392ca3b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,4 @@ **/*.rs.bk Cargo.lock .vscode -**/*.html .DS_Store diff --git a/Cargo.toml b/Cargo.toml index b7878ae843..fb0ba23519 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,21 @@ [workspace] members = [ "halo2", - "halo2_gadgets", "halo2_proofs", + "arithmetic/curves", + "primitives/poseidon" ] + +[profile.dev] +opt-level = 3 + +[profile.release] +opt-level = 3 +debug = false +debug-assertions = false +overflow-checks = false +lto = true +incremental = false +panic = "abort" +# codegen-units = 1 is not optimal on my machine; always profile locally to determine best preferences +# codegen-units = 1 diff --git a/arithmetic/curves/.github/workflows/ci.yml b/arithmetic/curves/.github/workflows/ci.yml new file mode 100644 index 0000000000..7f3475823a --- /dev/null +++ b/arithmetic/curves/.github/workflows/ci.yml @@ -0,0 +1,92 @@ +name: CI Check +on: + pull_request: + push: + branches: + - main + +jobs: + build: + if: github.event.pull_request.draft == false + name: Build + runs-on: ubuntu-latest + strategy: + matrix: + include: + - rust: 1.63.0 + feature: default + - rust: nightly + feature: asm + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + override: true + toolchain: ${{ matrix.rust }} + - name: Build + uses: actions-rs/cargo@v1 + with: + command: build + args: --features ${{ matrix.feature }} + + test: + if: github.event.pull_request.draft == false + name: Test + runs-on: ubuntu-latest + strategy: + matrix: + include: + - rust: 1.63.0 + feature: default + - rust: nightly + feature: asm + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + override: true + toolchain: ${{ matrix.rust }} + - name: Test + uses: actions-rs/cargo@v1 + with: + command: test + args: --verbose --release --all --features ${{ matrix.feature }} + + fmt: + if: github.event.pull_request.draft == false + name: Rustfmt + timeout-minutes: 30 + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + - run: rustup component add rustfmt + - uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check + + bench: + if: github.event.pull_request.draft == false + name: Bench + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + override: true + toolchain: nightly + - name: Bench arithmetic + uses: actions-rs/cargo@v1 + with: + command: test + args: --profile bench test_field -- --nocapture + - name: Bench assembly arithmetic + uses: actions-rs/cargo@v1 + with: + command: test + args: --profile bench test_field --features asm -- --nocapture diff --git a/arithmetic/curves/.gitignore b/arithmetic/curves/.gitignore new file mode 100644 index 0000000000..bceff729ff --- /dev/null +++ b/arithmetic/curves/.gitignore @@ -0,0 +1,5 @@ +/target +Cargo.lock +**/*.rs.bk +.vscode +**/*.html \ No newline at end of file diff --git a/arithmetic/curves/Cargo.toml b/arithmetic/curves/Cargo.toml new file mode 100644 index 0000000000..6d30863d8c --- /dev/null +++ b/arithmetic/curves/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "halo2curves" +version = "0.3.1" +authors = [ + "Sean Bowe ", + "Jack Grigg ", + "Alex Vlasov ", + "Alex Gluchowski " +] +license = "MIT/Apache-2.0" +edition = "2018" +readme = "README.md" +description = "Elliptic curve implementations and wrappers for halo2 library" + +[dev-dependencies] +criterion = { version = "0.3", features = ["html_reports"] } +rand_xorshift = "0.3" +ark-std = { version = "0.3", features = ["print-trace"] } + +[dependencies] +subtle = "2.4" +ff = "0.12" +group = "0.12" +pasta_curves = "0.4.1" +static_assertions = "1.1.0" +rand = "0.8" +rand_core = { version = "0.6", default-features = false } +lazy_static = { version = "1.4.0"} +num-bigint = "0.4.3" +num-traits = "0.2" +serde = { version = "1.0", default-features = false, features = ["derive"] } + +[features] +default = [] +asm = [] +prefetch = [] diff --git a/arithmetic/curves/LICENSE-APACHE b/arithmetic/curves/LICENSE-APACHE new file mode 100644 index 0000000000..f8e5e5ea03 --- /dev/null +++ b/arithmetic/curves/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. \ No newline at end of file diff --git a/arithmetic/curves/LICENSE-MIT b/arithmetic/curves/LICENSE-MIT new file mode 100644 index 0000000000..31aa79387f --- /dev/null +++ b/arithmetic/curves/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/arithmetic/curves/README.md b/arithmetic/curves/README.md new file mode 100644 index 0000000000..bf431dac4c --- /dev/null +++ b/arithmetic/curves/README.md @@ -0,0 +1,25 @@ +# BN256 pairing + +BN256 pairing library that implements original traits from `zkcrypto`, + +* [`zkcrypto/ff`](https://github.com/zkcrypto/ff) +* [`zkcrypto/group`](https://github.com/zkcrypto/group) +* [`zkcrypto/pairing`](https://github.com/zkcrypto/pairing) + +and plus + +`FieldExt`, `CurveExt` [traits](https://github.com/zcash/pasta_curves/tree/main/src/arithmetic) that are used in `halo2` library. + +This implementation is mostly ported from [matterlabs/pairing](https://github.com/matter-labs/pairing/tree/master/src/bn256) and [zkcrypto/bls12-381](https://github.com/zkcrypto/bls12_381). + +## Bench + +No assembly +``` +$ cargo test --profile bench test_field -- --nocapture +``` + +Assembly (returns rust nightly) +``` +$ cargo test --profile bench test_field --features asm -- --nocapture +``` diff --git a/arithmetic/curves/build.rs b/arithmetic/curves/build.rs new file mode 100644 index 0000000000..7ec963436c --- /dev/null +++ b/arithmetic/curves/build.rs @@ -0,0 +1,7 @@ +fn main() { + #[cfg(feature = "asm")] + if std::env::consts::ARCH != "x86_64" { + eprintln!("Currently feature `asm` can only be enabled on x86_64 arch."); + std::process::exit(1); + } +} diff --git a/arithmetic/curves/src/arithmetic.rs b/arithmetic/curves/src/arithmetic.rs new file mode 100644 index 0000000000..388a422ba9 --- /dev/null +++ b/arithmetic/curves/src/arithmetic.rs @@ -0,0 +1,125 @@ +//! This module provides common utilities, traits and structures for group and +//! field arithmetic. +//! +//! This module is temporary, and the extension traits defined here are expected to be +//! upstreamed into the `ff` and `group` crates after some refactoring. + +use subtle::{Choice, ConditionallySelectable, CtOption}; + +pub trait CurveAffineExt: pasta_curves::arithmetic::CurveAffine { + fn batch_add( + points: &mut [Self], + output_indices: &[u32], + num_points: usize, + offset: usize, + bases: &[Self], + base_positions: &[u32], + ); + + /// Unlike the `Coordinates` trait, this just returns the raw affine coordinates without checking `is_on_curve` + fn into_coordinates(self) -> (Self::Base, Self::Base) { + // fallback implementation + let coordinates = self.coordinates().unwrap(); + (*coordinates.x(), *coordinates.y()) + } +} + +pub(crate) fn sqrt_tonelli_shanks>( + f: &F, + tm1d2: S, +) -> CtOption { + use subtle::ConstantTimeEq; + + // w = self^((t - 1) // 2) + let w = f.pow_vartime(tm1d2); + + let mut v = F::S; + let mut x = w * f; + let mut b = x * w; + + // Initialize z as the 2^S root of unity. + let mut z = F::root_of_unity(); + + for max_v in (1..=F::S).rev() { + let mut k = 1; + let mut tmp = b.square(); + let mut j_less_than_v: Choice = 1.into(); + + for j in 2..max_v { + let tmp_is_one = tmp.ct_eq(&F::one()); + let squared = F::conditional_select(&tmp, &z, tmp_is_one).square(); + tmp = F::conditional_select(&squared, &tmp, tmp_is_one); + let new_z = F::conditional_select(&z, &squared, tmp_is_one); + j_less_than_v &= !j.ct_eq(&v); + k = u32::conditional_select(&j, &k, tmp_is_one); + z = F::conditional_select(&z, &new_z, j_less_than_v); + } + + let result = x * z; + x = F::conditional_select(&result, &x, b.ct_eq(&F::one())); + z = z.square(); + b *= z; + v = k; + } + + CtOption::new( + x, + (x * x).ct_eq(f), // Only return Some if it's the square root. + ) +} + +/// Compute a + b + carry, returning the result and the new carry over. +/// The carry input must be 0 or 1; otherwise the behavior is undefined. +/// The carryOut output is guaranteed to be 0 or 1. +#[inline(always)] +pub(crate) const fn adc(a: u64, b: u64, carry: bool) -> (u64, bool) { + a.carrying_add(b, carry) +} + +/// Compute a - b - borrow, returning the result and the new borrow. +#[inline(always)] +pub(crate) const fn sbb(a: u64, b: u64, borrow: bool) -> (u64, bool) { + a.borrowing_sub(b, borrow) +} + +/// Compute a + (b * c), returning the result and the new carry over. +// Alias madd1 +#[inline(always)] +pub(crate) const fn macx(a: u64, b: u64, c: u64) -> (u64, u64) { + b.carrying_mul(c, a) +} + +/// Compute a + (b * c) + carry, returning the result and the new carry over. +// Alias madd2 +#[inline(always)] +pub(crate) const fn mac(a: u64, b: u64, c: u64, carry: u64) -> (u64, u64) { + let (lo, hi) = b.carrying_mul(c, a); + let (lo, carry) = lo.overflowing_add(carry); + (lo, hi + carry as u64) +} + +/// Compute a * b, returning the result. +#[inline(always)] +pub(crate) fn mul_512(a: [u64; 4], b: [u64; 4]) -> [u64; 8] { + let (r0, carry) = macx(0, a[0], b[0]); + let (r1, carry) = macx(carry, a[0], b[1]); + let (r2, carry) = macx(carry, a[0], b[2]); + let (r3, carry_out) = macx(carry, a[0], b[3]); + + let (r1, carry) = macx(r1, a[1], b[0]); + let (r2, carry) = mac(r2, a[1], b[1], carry); + let (r3, carry) = mac(r3, a[1], b[2], carry); + let (r4, carry_out) = mac(carry_out, a[1], b[3], carry); + + let (r2, carry) = macx(r2, a[2], b[0]); + let (r3, carry) = mac(r3, a[2], b[1], carry); + let (r4, carry) = mac(r4, a[2], b[2], carry); + let (r5, carry_out) = mac(carry_out, a[2], b[3], carry); + + let (r3, carry) = macx(r3, a[3], b[0]); + let (r4, carry) = mac(r4, a[3], b[1], carry); + let (r5, carry) = mac(r5, a[3], b[2], carry); + let (r6, carry_out) = mac(carry_out, a[3], b[3], carry); + + [r0, r1, r2, r3, r4, r5, r6, carry_out] +} diff --git a/arithmetic/curves/src/bn256/assembly.rs b/arithmetic/curves/src/bn256/assembly.rs new file mode 100644 index 0000000000..c9294d9506 --- /dev/null +++ b/arithmetic/curves/src/bn256/assembly.rs @@ -0,0 +1,1378 @@ +macro_rules! assembly_field { + ( + $field:ident, + $modulus:ident, + $inv:ident, + $modulus_str:ident, + $two_inv:ident, + $root_of_unity_inv:ident, + $delta:ident, + $zeta:ident, + $r:ident, + $r2:ident, + $r3:ident + ) => { + use std::arch::asm; + + impl $field { + /// Returns zero, the additive identity. + #[inline] + pub const fn zero() -> $field { + $field([0, 0, 0, 0]) + } + + /// Returns one, the multiplicative identity. + #[inline] + pub const fn one() -> $field { + $r + } + + fn from_u512(limbs: [u64; 8]) -> $field { + // We reduce an arbitrary 512-bit number by decomposing it into two 256-bit digits + // with the higher bits multiplied by 2^256. Thus, we perform two reductions + // + // 1. the lower bits are multiplied by R^2, as normal + // 2. the upper bits are multiplied by R^2 * 2^256 = R^3 + // + // and computing their sum in the field. It remains to see that arbitrary 256-bit + // numbers can be placed into Montgomery form safely using the reduction. The + // reduction works so long as the product is less than R=2^256 multiplied by + // the modulus. This holds because for any `c` smaller than the modulus, we have + // that (2^256 - 1)*c is an acceptable product for the reduction. Therefore, the + // reduction always works so long as `c` is in the field; in this case it is either the + // constant `R2` or `R3`. + let d0 = $field([limbs[0], limbs[1], limbs[2], limbs[3]]); + let d1 = $field([limbs[4], limbs[5], limbs[6], limbs[7]]); + // Convert to Montgomery form + d0 * $r2 + d1 * $r3 + } + + /// Converts from an integer represented in little endian + /// into its (congruent) `$field` representation. + pub const fn from_raw(val: [u64; 4]) -> Self { + // Multiplication + let (r0, carry) = mac(0, val[0], $r2.0[0], 0); + let (r1, carry) = mac(0, val[0], $r2.0[1], carry); + let (r2, carry) = mac(0, val[0], $r2.0[2], carry); + let (r3, r4) = mac(0, val[0], $r2.0[3], carry); + + let (r1, carry) = mac(r1, val[1], $r2.0[0], 0); + let (r2, carry) = mac(r2, val[1], $r2.0[1], carry); + let (r3, carry) = mac(r3, val[1], $r2.0[2], carry); + let (r4, r5) = mac(r4, val[1], $r2.0[3], carry); + + let (r2, carry) = mac(r2, val[2], $r2.0[0], 0); + let (r3, carry) = mac(r3, val[2], $r2.0[1], carry); + let (r4, carry) = mac(r4, val[2], $r2.0[2], carry); + let (r5, r6) = mac(r5, val[2], $r2.0[3], carry); + + let (r3, carry) = mac(r3, val[3], $r2.0[0], 0); + let (r4, carry) = mac(r4, val[3], $r2.0[1], carry); + let (r5, carry) = mac(r5, val[3], $r2.0[2], carry); + let (r6, r7) = mac(r6, val[3], $r2.0[3], carry); + + // Montgomery reduction (first part) + let k = r0.wrapping_mul($inv); + let (_, carry) = mac(r0, k, $modulus.0[0], 0); + let (r1, carry) = mac(r1, k, $modulus.0[1], carry); + let (r2, carry) = mac(r2, k, $modulus.0[2], carry); + let (r3, carry) = mac(r3, k, $modulus.0[3], carry); + let (r4, carry2) = adc(r4, 0, carry); + + let k = r1.wrapping_mul($inv); + let (_, carry) = mac(r1, k, $modulus.0[0], 0); + let (r2, carry) = mac(r2, k, $modulus.0[1], carry); + let (r3, carry) = mac(r3, k, $modulus.0[2], carry); + let (r4, carry) = mac(r4, k, $modulus.0[3], carry); + let (r5, carry2) = adc(r5, carry2, carry); + + let k = r2.wrapping_mul($inv); + let (_, carry) = mac(r2, k, $modulus.0[0], 0); + let (r3, carry) = mac(r3, k, $modulus.0[1], carry); + let (r4, carry) = mac(r4, k, $modulus.0[2], carry); + let (r5, carry) = mac(r5, k, $modulus.0[3], carry); + let (r6, carry2) = adc(r6, carry2, carry); + + let k = r3.wrapping_mul($inv); + let (_, carry) = mac(r3, k, $modulus.0[0], 0); + let (r4, carry) = mac(r4, k, $modulus.0[1], carry); + let (r5, carry) = mac(r5, k, $modulus.0[2], carry); + let (r6, carry) = mac(r6, k, $modulus.0[3], carry); + let (r7, _) = adc(r7, carry2, carry); + + // Montgomery reduction (sub part) + let (d0, borrow) = sbb(r4, $modulus.0[0], 0); + let (d1, borrow) = sbb(r5, $modulus.0[1], borrow); + let (d2, borrow) = sbb(r6, $modulus.0[2], borrow); + let (d3, borrow) = sbb(r7, $modulus.0[3], borrow); + + let (d0, carry) = adc(d0, $modulus.0[0] & borrow, 0); + let (d1, carry) = adc(d1, $modulus.0[1] & borrow, carry); + let (d2, carry) = adc(d2, $modulus.0[2] & borrow, carry); + let (d3, _) = adc(d3, $modulus.0[3] & borrow, carry); + + $field([d0, d1, d2, d3]) + } + + /// Attempts to convert a little-endian byte representation of + /// a scalar into a `Fr`, failing if the input is not canonical. + pub fn from_bytes(bytes: &[u8; 32]) -> CtOption<$field> { + ::from_repr(*bytes) + } + + /// Converts an element of `Fr` into a byte representation in + /// little-endian byte order. + pub fn to_bytes(&self) -> [u8; 32] { + ::to_repr(self) + } + } + + impl Group for $field { + type Scalar = Self; + + fn group_zero() -> Self { + Self::zero() + } + fn group_add(&mut self, rhs: &Self) { + *self += *rhs; + } + fn group_sub(&mut self, rhs: &Self) { + *self -= *rhs; + } + fn group_scale(&mut self, by: &Self::Scalar) { + *self *= *by; + } + } + + impl fmt::Debug for $field { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let tmp = self.to_repr(); + write!(f, "0x")?; + for &b in tmp.iter().rev() { + write!(f, "{:02x}", b)?; + } + Ok(()) + } + } + + impl Default for $field { + #[inline] + fn default() -> Self { + Self::zero() + } + } + + impl From for $field { + fn from(bit: bool) -> $field { + if bit { + $field::one() + } else { + $field::zero() + } + } + } + + impl From for $field { + fn from(val: u64) -> $field { + $field([val, 0, 0, 0]) * $r2 + } + } + + impl ConstantTimeEq for $field { + fn ct_eq(&self, other: &Self) -> Choice { + self.0[0].ct_eq(&other.0[0]) + & self.0[1].ct_eq(&other.0[1]) + & self.0[2].ct_eq(&other.0[2]) + & self.0[3].ct_eq(&other.0[3]) + } + } + + impl core::cmp::Ord for $field { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + let left = self.to_repr(); + let right = other.to_repr(); + left.iter() + .zip(right.iter()) + .rev() + .find_map(|(left_byte, right_byte)| match left_byte.cmp(right_byte) { + core::cmp::Ordering::Equal => None, + res => Some(res), + }) + .unwrap_or(core::cmp::Ordering::Equal) + } + } + + impl core::cmp::PartialOrd for $field { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + + impl ConditionallySelectable for $field { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + $field([ + u64::conditional_select(&a.0[0], &b.0[0], choice), + u64::conditional_select(&a.0[1], &b.0[1], choice), + u64::conditional_select(&a.0[2], &b.0[2], choice), + u64::conditional_select(&a.0[3], &b.0[3], choice), + ]) + } + } + + impl<'a> Neg for &'a $field { + type Output = $field; + + #[inline] + fn neg(self) -> $field { + self.neg() + } + } + + impl Neg for $field { + type Output = $field; + + #[inline] + fn neg(self) -> $field { + -&self + } + } + + impl<'a, 'b> Sub<&'b $field> for &'a $field { + type Output = $field; + + #[inline] + fn sub(self, rhs: &'b $field) -> $field { + self.sub(rhs) + } + } + + impl<'a, 'b> Add<&'b $field> for &'a $field { + type Output = $field; + + #[inline] + fn add(self, rhs: &'b $field) -> $field { + self.add(rhs) + } + } + + impl<'a, 'b> Mul<&'b $field> for &'a $field { + type Output = $field; + + #[inline] + fn mul(self, rhs: &'b $field) -> $field { + self.mul(rhs) + } + } + + impl From<$field> for [u8; 32] { + fn from(value: $field) -> [u8; 32] { + value.to_repr() + } + } + + impl<'a> From<&'a $field> for [u8; 32] { + fn from(value: &'a $field) -> [u8; 32] { + value.to_repr() + } + } + + impl FieldExt for $field { + const MODULUS: &'static str = $modulus_str; + const TWO_INV: Self = $two_inv; + const ROOT_OF_UNITY_INV: Self = $root_of_unity_inv; + const DELTA: Self = $delta; + const ZETA: Self = $zeta; + + fn from_u128(v: u128) -> Self { + $field::from_raw([v as u64, (v >> 64) as u64, 0, 0]) + } + + /// Converts a 512-bit little endian integer into + /// a `$field` by reducing by the modulus. + fn from_bytes_wide(bytes: &[u8; 64]) -> $field { + $field::from_u512([ + u64::from_le_bytes(bytes[0..8].try_into().unwrap()), + u64::from_le_bytes(bytes[8..16].try_into().unwrap()), + u64::from_le_bytes(bytes[16..24].try_into().unwrap()), + u64::from_le_bytes(bytes[24..32].try_into().unwrap()), + u64::from_le_bytes(bytes[32..40].try_into().unwrap()), + u64::from_le_bytes(bytes[40..48].try_into().unwrap()), + u64::from_le_bytes(bytes[48..56].try_into().unwrap()), + u64::from_le_bytes(bytes[56..64].try_into().unwrap()), + ]) + } + + fn get_lower_128(&self) -> u128 { + let tmp = $field::montgomery_reduce(&[ + self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0, + ]); + + u128::from(tmp.0[0]) | (u128::from(tmp.0[1]) << 64) + } + } + + impl $crate::serde::SerdeObject for $field { + fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { + debug_assert_eq!(bytes.len(), 32); + let inner = + [0, 8, 16, 24].map(|i| u64::from_le_bytes(bytes[i..i + 8].try_into().unwrap())); + Self(inner) + } + fn from_raw_bytes(bytes: &[u8]) -> Option { + if bytes.len() != 32 { + return None; + } + let elt = Self::from_raw_bytes_unchecked(bytes); + is_less_than(&elt.0, &$modulus.0).then(|| elt) + } + fn to_raw_bytes(&self) -> Vec { + let mut res = Vec::with_capacity(32); + for limb in self.0.iter() { + res.extend_from_slice(&limb.to_le_bytes()); + } + res + } + fn read_raw_unchecked(reader: &mut R) -> Self { + let inner = [(); 4].map(|_| { + let mut buf = [0; 8]; + reader.read_exact(&mut buf).unwrap(); + u64::from_le_bytes(buf) + }); + Self(inner) + } + fn read_raw(reader: &mut R) -> std::io::Result { + let mut inner = [0u64; 4]; + for limb in inner.iter_mut() { + let mut buf = [0; 8]; + reader.read_exact(&mut buf)?; + *limb = u64::from_le_bytes(buf); + } + let elt = Self(inner); + is_less_than(&elt.0, &$modulus.0) + .then(|| elt) + .ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + "input number is not less than field modulus", + ) + }) + } + fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { + for limb in self.0.iter() { + writer.write_all(&limb.to_le_bytes())?; + } + Ok(()) + } + } + + /// Lexicographic comparison of Montgomery forms. + #[inline(always)] + fn is_less_than(x: &[u64; 4], y: &[u64; 4]) -> bool { + match x[3].cmp(&y[3]) { + core::cmp::Ordering::Less => return true, + core::cmp::Ordering::Greater => return false, + _ => {} + } + match x[2].cmp(&y[2]) { + core::cmp::Ordering::Less => return true, + core::cmp::Ordering::Greater => return false, + _ => {} + } + match x[1].cmp(&y[1]) { + core::cmp::Ordering::Less => return true, + core::cmp::Ordering::Greater => return false, + _ => {} + } + x[0].lt(&y[0]) + } + + impl $field { + /// Doubles this field element. + #[inline] + pub fn double(&self) -> $field { + let mut r0: u64; + let mut r1: u64; + let mut r2: u64; + let mut r3: u64; + unsafe { + asm!( + // load a array to former registers + "mov r8, qword ptr [{a_ptr} + 0]", + "mov r9, qword ptr [{a_ptr} + 8]", + "mov r10, qword ptr [{a_ptr} + 16]", + "mov r11, qword ptr [{a_ptr} + 24]", + + // // add a array and b array with carry + "add r8, r8", + "adcx r9, r9", + "adcx r10, r10", + "adcx r11, r11", + + // copy result array to latter registers + "mov r12, r8", + "mov r13, r9", + "mov r14, r10", + "mov r15, r11", + + // mod reduction + "sub r12, qword ptr [{m_ptr} + 0]", + "sbb r13, qword ptr [{m_ptr} + 8]", + "sbb r14, qword ptr [{m_ptr} + 16]", + "sbb r15, qword ptr [{m_ptr} + 24]", + + // if carry copy former registers to out areas + "cmovc r12, r8", + "cmovc r13, r9", + "cmovc r14, r10", + "cmovc r15, r11", + + m_ptr = in(reg) $modulus.0.as_ptr(), + a_ptr = in(reg) self.0.as_ptr(), + out("r8") _, + out("r9") _, + out("r10") _, + out("r11") _, + out("r12") r0, + out("r13") r1, + out("r14") r2, + out("r15") r3, + options(pure, readonly, nostack) + ); + } + $field([r0, r1, r2, r3]) + } + + /// Squares this element. + #[inline] + pub fn square(&self) -> $field { + let mut r0: u64; + let mut r1: u64; + let mut r2: u64; + let mut r3: u64; + unsafe { + asm!( + // schoolbook multiplication + // * | a0 | a1 | a2 | a3 + // b0 | b0 * a0 | b0 * a1 | b0 * a2 | b0 * a3 + // b1 | b1 * a0 | b1 * a1 | b1 * a2 | b1 * a3 + // b2 | b2 * a0 | b2 * a1 | b2 * a2 | b2 * a3 + // b3 | b3 * a0 | b3 * a1 | b3 * a2 | b3 * a3 + + // load value to registers + "mov r13, qword ptr [{a_ptr} + 0]", + "mov r14, qword ptr [{a_ptr} + 8]", + "mov r15, qword ptr [{a_ptr} + 16]", + + // `a0` + "mov rdx, r13", + + // a0 * b0 + "mulx r9, r8, r13", + + // a0 * b1 + "mulx r10, rax, r14", + "add r9, rax", + + // a0 * b2 + "mulx r11, rax, r15", + "adcx r10, rax", + + // a0 * b3 + "mulx r12, rax, qword ptr [{a_ptr} + 24]", + "adcx r11, rax", + "adc r12, 0", + + // `a1` + "mov rdx, r14", + + // a1 * b0 + "mulx rcx, rax, r13", + "add r9, rax", + "adcx r10, rcx", + "adc r11, 0", + + // a1 * b1 + "mulx rcx, rax, r14", + "add r10, rax", + "adcx r11, rcx", + "adc r12, 0", + "xor r13, r13", + + // a1 * b2 + "mulx rcx, rax, r15", + "add r11, rax", + "adcx r12, rcx", + "adc r13, 0", + "xor r14, r14", + + // a1 * b3 + "mulx rcx, rax, qword ptr [{a_ptr} + 24]", + "add r12, rax", + "adcx r13, rcx", + "adc r14, 0", + + // `a2` + "mov rdx, r15", + + // a2 * b0 + "mulx rcx, rax, qword ptr [{a_ptr} + 0]", + "add r10, rax", + "adcx r11, rcx", + "adc r12, 0", + + // a2 * b1 + "mulx rcx, rax, qword ptr [{a_ptr} + 8]", + "add r11, rax", + "adcx r12, rcx", + "adc r13, 0", + + // a2 * b2 + "mulx rcx, rax, r15", + "add r12, rax", + "adcx r13, rcx", + "adc r14, 0", + "xor r15, r15", + + // a2 * b3 + "mulx rcx, rax, qword ptr [{a_ptr} + 24]", + "add r13, rax", + "adcx r14, rcx", + "adc r15, 0", + + // `a3` + "mov rdx, qword ptr [{a_ptr} + 24]", + + // a3 * b0 + "mulx rcx, rax, qword ptr [{a_ptr} + 0]", + "add r11, rax", + "adcx r12, rcx", + "adc r13, 0", + + // a3 * b1 + "mulx rcx, rax, qword ptr [{a_ptr} + 8]", + "add r12, rax", + "adcx r13, rcx", + "adc r14, 0", + + // a3 * b2 + "mulx rcx, rax, qword ptr [{a_ptr} + 16]", + "add r13, rax", + "adcx r14, rcx", + "adc r15, 0", + + // a3 * b3 + "mulx rcx, rax, qword ptr [{a_ptr} + 24]", + "add r14, rax", + "adc r15, rcx", + + // montgomery reduction + // r8 ~ r15 + + // `r8` -> 0 + "mov rdx, {inv}", + "mulx rax, rdx, r8", + + // r8' * m0 + "mulx rcx, rax, qword ptr [{m_ptr} + 0]", + "add r8, rax", + "adcx r9, rcx", + "adc r10, 0", + + // r8' * m1 + "mulx rcx, rax, qword ptr [{m_ptr} + 8]", + "add r9, rax", + "adcx r10, rcx", + "adc r11, 0", + + // r8' * m2 + "mulx rcx, rax, qword ptr [{m_ptr} + 16]", + "add r10, rax", + "adcx r11, rcx", + "adc r12, 0", + + // r8' * m3 + "mulx rcx, rax, qword ptr [{m_ptr} + 24]", + "add r11, rax", + "adcx r12, rcx", + "adc r13, 0", + + // `r9` -> 0 + "mov rdx, {inv}", + "mulx rax, rdx, r9", + + // r9' * m0 + "mulx rax, rcx, qword ptr [{m_ptr} + 0]", + "add r9, rcx", + "adcx r10, rax", + "adc r11, 0", + + // r9' * m1 + "mulx rax, rcx, qword ptr [{m_ptr} + 8]", + "add r10, rcx", + "adcx r11, rax", + "adc r12, 0", + + // r9' * m2 + "mulx rax, rcx, qword ptr [{m_ptr} + 16]", + "add r11, rcx", + "adcx r12, rax", + "adc r13, 0", + + // r9' * m3 + "mulx rax, rcx, qword ptr [{m_ptr} + 24]", + "add r12, rcx", + "adcx r13, rax", + "adc r14, 0", + + // `r10` -> 0 + "mov rdx, {inv}", + "mulx rax, rdx, r10", + + // r10' * m0 + "mulx rax, rcx, qword ptr [{m_ptr} + 0]", + "add r10, rcx", + "adcx r11, rax", + "adc r12, 0", + + // r10' * m1 + "mulx rax, rcx, qword ptr [{m_ptr} + 8]", + "add r11, rcx", + "adcx r12, rax", + "adc r13, 0", + + // r10' * m2 + "mulx rax, rcx, qword ptr [{m_ptr} + 16]", + "add r12, rcx", + "adcx r13, rax", + "adc r14, 0", + + // r10' * m3 + "mulx rax, rcx, qword ptr [{m_ptr} + 24]", + "add r13, rcx", + "adcx r14, rax", + "adc r15, 0", + + // `r11` -> 0 + "mov rdx, {inv}", + "mulx rax, rdx, r11", + + // r11' * m0 + "mulx rax, rcx, qword ptr [{m_ptr} + 0]", + "add r11, rcx", + "adcx r12, rax", + "adc r13, 0", + + // r11' * m1 + "mulx rax, rcx, qword ptr [{m_ptr} + 8]", + "add r12, rcx", + "adcx r13, rax", + "adc r14, 0", + + // r11' * m2 + "mulx rax, rcx, qword ptr [{m_ptr} + 16]", + "add r13, rcx", + "adcx r14, rax", + "adc r15, 0", + + // r11' * m3 + "mulx rax, rcx, qword ptr [{m_ptr} + 24]", + "add r14, rcx", + "adcx r15, rax", + + // reduction if limbs is greater then mod + "mov r8, r12", + "mov r9, r13", + "mov r10, r14", + "mov r11, r15", + + "sub r8, qword ptr [{m_ptr} + 0]", + "sbb r9, qword ptr [{m_ptr} + 8]", + "sbb r10, qword ptr [{m_ptr} + 16]", + "sbb r11, qword ptr [{m_ptr} + 24]", + + "cmovc r8, r12", + "cmovc r9, r13", + "cmovc r10, r14", + "cmovc r11, r15", + + "mov r12, r8", + "mov r13, r9", + "mov r14, r10", + "mov r15, r11", + + "sub r12, qword ptr [{m_ptr} + 0]", + "sbb r13, qword ptr [{m_ptr} + 8]", + "sbb r14, qword ptr [{m_ptr} + 16]", + "sbb r15, qword ptr [{m_ptr} + 24]", + + "cmovc r12, r8", + "cmovc r13, r9", + "cmovc r14, r10", + "cmovc r15, r11", + + a_ptr = in(reg) self.0.as_ptr(), + m_ptr = in(reg) $modulus.0.as_ptr(), + inv = const $inv, + out("rax") _, + out("rcx") _, + out("rdx") _, + out("r8") _, + out("r9") _, + out("r10") _, + out("r11") _, + out("r12") r0, + out("r13") r1, + out("r14") r2, + out("r15") r3, + options(pure, readonly, nostack) + ) + } + + $field([r0, r1, r2, r3]) + } + + #[inline(always)] + pub(crate) fn montgomery_reduce(a: &[u64; 8]) -> $field { + let mut r0: u64; + let mut r1: u64; + let mut r2: u64; + let mut r3: u64; + + unsafe { + asm!( + // The Montgomery reduction here is based on Algorithm 14.32 in + // Handbook of Applied Cryptography + // . + + "mov r8, qword ptr [{a_ptr} + 0]", + "mov r9, qword ptr [{a_ptr} + 8]", + "mov r10, qword ptr [{a_ptr} + 16]", + "mov r11, qword ptr [{a_ptr} + 24]", + "mov r12, qword ptr [{a_ptr} + 32]", + "mov r13, qword ptr [{a_ptr} + 40]", + "mov r14, qword ptr [{a_ptr} + 48]", + "mov r15, qword ptr [{a_ptr} + 56]", + + // `r8` -> 0 + "mov rdx, {inv}", + "mulx rax, rdx, r8", + + // r8' * m0 + "mulx rcx, rax, qword ptr [{m_ptr} + 0]", + "add r8, rax", + "adcx r9, rcx", + "adc r10, 0", + + // r8' * m1 + "mulx rcx, rax, qword ptr [{m_ptr} + 8]", + "add r9, rax", + "adcx r10, rcx", + "adc r11, 0", + + // // r8' * m2 + "mulx rcx, rax, qword ptr [{m_ptr} + 16]", + "add r10, rax", + "adcx r11, rcx", + "adc r12, 0", + + // // r8' * m3 + "mulx rcx, rax, qword ptr [{m_ptr} + 24]", + "add r11, rax", + "adcx r12, rcx", + "adc r13, 0", + + // `r9` -> 0 + "mov rdx, {inv}", + "mulx rax, rdx, r9", + + // r9' * m0 + "mulx rax, rcx, qword ptr [{m_ptr} + 0]", + "add r9, rcx", + "adcx r10, rax", + "adc r11, 0", + + // r9' * m1 + "mulx rax, rcx, qword ptr [{m_ptr} + 8]", + "add r10, rcx", + "adcx r11, rax", + "adc r12, 0", + + // r9' * m2 + "mulx rax, rcx, qword ptr [{m_ptr} + 16]", + "add r11, rcx", + "adcx r12, rax", + "adc r13, 0", + + // r9' * m3 + "mulx rax, rcx, qword ptr [{m_ptr} + 24]", + "add r12, rcx", + "adcx r13, rax", + "adc r14, 0", + + // `r10` -> 0 + "mov rdx, {inv}", + "mulx rax, rdx, r10", + + // r10' * m0 + "mulx rax, rcx, qword ptr [{m_ptr} + 0]", + "add r10, rcx", + "adcx r11, rax", + "adc r12, 0", + + // r10' * m1 + "mulx rax, rcx, qword ptr [{m_ptr} + 8]", + "add r11, rcx", + "adcx r12, rax", + "adc r13, 0", + + // r10' * m2 + "mulx rax, rcx, qword ptr [{m_ptr} + 16]", + "add r12, rcx", + "adcx r13, rax", + "adc r14, 0", + + // r10' * m3 + "mulx rax, rcx, qword ptr [{m_ptr} + 24]", + "add r13, rcx", + "adcx r14, rax", + "adc r15, 0", + + // `r11` -> 0 + "mov rdx, {inv}", + "mulx rax, rdx, r11", + + // r11' * m0 + "mulx rax, rcx, qword ptr [{m_ptr} + 0]", + "add r11, rcx", + "adcx r12, rax", + "adc r13, 0", + + // r11' * m1 + "mulx rax, rcx, qword ptr [{m_ptr} + 8]", + "add r12, rcx", + "adcx r13, rax", + "adc r14, 0", + + // r11' * m2 + "mulx rax, rcx, qword ptr [{m_ptr} + 16]", + "add r13, rcx", + "adcx r14, rax", + "adc r15, 0", + + // r11' * m3 + "mulx rax, rcx, qword ptr [{m_ptr} + 24]", + "add r14, rcx", + "adcx r15, rax", + + // reduction if limbs is greater then mod + "mov r8, r12", + "mov r9, r13", + "mov r10, r14", + "mov r11, r15", + + "sub r8, qword ptr [{m_ptr} + 0]", + "sbb r9, qword ptr [{m_ptr} + 8]", + "sbb r10, qword ptr [{m_ptr} + 16]", + "sbb r11, qword ptr [{m_ptr} + 24]", + + "cmovc r8, r12", + "cmovc r9, r13", + "cmovc r10, r14", + "cmovc r11, r15", + + "mov r12, r8", + "mov r13, r9", + "mov r14, r10", + "mov r15, r11", + + "sub r12, qword ptr [{m_ptr} + 0]", + "sbb r13, qword ptr [{m_ptr} + 8]", + "sbb r14, qword ptr [{m_ptr} + 16]", + "sbb r15, qword ptr [{m_ptr} + 24]", + + "cmovc r12, r8", + "cmovc r13, r9", + "cmovc r14, r10", + "cmovc r15, r11", + + a_ptr = in(reg) a.as_ptr(), + m_ptr = in(reg) $modulus.0.as_ptr(), + inv = const $inv, + out("rax") _, + out("rcx") _, + out("rdx") _, + out("r8") _, + out("r9") _, + out("r10") _, + out("r11") _, + out("r12") r0, + out("r13") r1, + out("r14") r2, + out("r15") r3, + options(pure, readonly, nostack) + ) + } + + $field([r0, r1, r2, r3]) + } + + /// Multiplies `rhs` by `self`, returning the result. + #[inline] + pub fn mul(&self, rhs: &Self) -> $field { + let mut r0: u64; + let mut r1: u64; + let mut r2: u64; + let mut r3: u64; + unsafe { + asm!( + // schoolbook multiplication + // * | a0 | a1 | a2 | a3 + // b0 | b0 * a0 | b0 * a1 | b0 * a2 | b0 * a3 + // b1 | b1 * a0 | b1 * a1 | b1 * a2 | b1 * a3 + // b2 | b2 * a0 | b2 * a1 | b2 * a2 | b2 * a3 + // b3 | b3 * a0 | b3 * a1 | b3 * a2 | b3 * a3 + + // load value to registers + "mov r13, qword ptr [{b_ptr} + 0]", + "mov r14, qword ptr [{b_ptr} + 8]", + "mov r15, qword ptr [{b_ptr} + 16]", + + // `a0` + "mov rdx, qword ptr [{a_ptr} + 0]", + + // a0 * b0 + "mulx r9, r8, r13", + + // a0 * b1 + "mulx r10, rax, r14", + "add r9, rax", + + // a0 * b2 + "mulx r11, rax, r15", + "adcx r10, rax", + + // a0 * b3 + "mulx r12, rax, qword ptr [{b_ptr} + 24]", + "adcx r11, rax", + "adc r12, 0", + + // `a1` + "mov rdx, [{a_ptr} + 8]", + + // a1 * b0 + "mulx rcx, rax, r13", + "add r9, rax", + "adcx r10, rcx", + "adc r11, 0", + + // a1 * b1 + "mulx rcx, rax, r14", + "add r10, rax", + "adcx r11, rcx", + "adc r12, 0", + "xor r13, r13", + + // a1 * b2 + "mulx rcx, rax, r15", + "add r11, rax", + "adcx r12, rcx", + "adc r13, 0", + "xor r14, r14", + + // a1 * b3 + "mulx rcx, rax, qword ptr [{b_ptr} + 24]", + "add r12, rax", + "adcx r13, rcx", + "adc r14, 0", + + // `a2` + "mov rdx, [{a_ptr} + 16]", + + // a2 * b0 + "mulx rcx, rax, qword ptr [{b_ptr} + 0]", + "add r10, rax", + "adcx r11, rcx", + "adc r12, 0", + + // a2 * b1 + "mulx rcx, rax, qword ptr [{b_ptr} + 8]", + "add r11, rax", + "adcx r12, rcx", + "adc r13, 0", + + // a2 * b2 + "mulx rcx, rax, r15", + "add r12, rax", + "adcx r13, rcx", + "adc r14, 0", + "xor r15, r15", + + // a2 * b3 + "mulx rcx, rax, qword ptr [{b_ptr} + 24]", + "add r13, rax", + "adcx r14, rcx", + "adc r15, 0", + + // `a3` + "mov rdx, [{a_ptr} + 24]", + + // a3 * b0 + "mulx rcx, rax, qword ptr [{b_ptr} + 0]", + "add r11, rax", + "adcx r12, rcx", + "adc r13, 0", + + // a3 * b1 + "mulx rcx, rax, qword ptr [{b_ptr} + 8]", + "add r12, rax", + "adcx r13, rcx", + "adc r14, 0", + + // a3 * b2 + "mulx rcx, rax, qword ptr [{b_ptr} + 16]", + "add r13, rax", + "adcx r14, rcx", + "adc r15, 0", + + // a3 * b3 + "mulx rcx, rax, qword ptr [{b_ptr} + 24]", + "add r14, rax", + "adc r15, rcx", + + // montgomery reduction + // r8 ~ r15 + + // `r8` -> 0 + "mov rdx, {inv}", + "mulx rax, rdx, r8", + + // r8' * m0 + "mulx rcx, rax, qword ptr [{m_ptr} + 0]", + "add r8, rax", + "adcx r9, rcx", + "adc r10, 0", + + // r8' * m1 + "mulx rcx, rax, qword ptr [{m_ptr} + 8]", + "add r9, rax", + "adcx r10, rcx", + "adc r11, 0", + + // // r8' * m2 + "mulx rcx, rax, qword ptr [{m_ptr} + 16]", + "add r10, rax", + "adcx r11, rcx", + "adc r12, 0", + + // // r8' * m3 + "mulx rcx, rax, qword ptr [{m_ptr} + 24]", + "add r11, rax", + "adcx r12, rcx", + "adc r13, 0", + + // `r9` -> 0 + "mov rdx, {inv}", + "mulx rax, rdx, r9", + + // r9' * m0 + "mulx rax, rcx, qword ptr [{m_ptr} + 0]", + "add r9, rcx", + "adcx r10, rax", + "adc r11, 0", + + // r9' * m1 + "mulx rax, rcx, qword ptr [{m_ptr} + 8]", + "add r10, rcx", + "adcx r11, rax", + "adc r12, 0", + + // r9' * m2 + "mulx rax, rcx, qword ptr [{m_ptr} + 16]", + "add r11, rcx", + "adcx r12, rax", + "adc r13, 0", + + // r9' * m3 + "mulx rax, rcx, qword ptr [{m_ptr} + 24]", + "add r12, rcx", + "adcx r13, rax", + "adc r14, 0", + + // `r10` -> 0 + "mov rdx, {inv}", + "mulx rax, rdx, r10", + + // r10' * m0 + "mulx rax, rcx, qword ptr [{m_ptr} + 0]", + "add r10, rcx", + "adcx r11, rax", + "adc r12, 0", + + // r10' * m1 + "mulx rax, rcx, qword ptr [{m_ptr} + 8]", + "add r11, rcx", + "adcx r12, rax", + "adc r13, 0", + + // r10' * m2 + "mulx rax, rcx, qword ptr [{m_ptr} + 16]", + "add r12, rcx", + "adcx r13, rax", + "adc r14, 0", + + // r10' * m3 + "mulx rax, rcx, qword ptr [{m_ptr} + 24]", + "add r13, rcx", + "adcx r14, rax", + "adc r15, 0", + + // `r11` -> 0 + "mov rdx, {inv}", + "mulx rax, rdx, r11", + + // r11' * m0 + "mulx rax, rcx, qword ptr [{m_ptr} + 0]", + "add r11, rcx", + "adcx r12, rax", + "adc r13, 0", + + // r11' * m1 + "mulx rax, rcx, qword ptr [{m_ptr} + 8]", + "add r12, rcx", + "adcx r13, rax", + "adc r14, 0", + + // r11' * m2 + "mulx rax, rcx, qword ptr [{m_ptr} + 16]", + "add r13, rcx", + "adcx r14, rax", + "adc r15, 0", + + // r11' * m3 + "mulx rax, rcx, qword ptr [{m_ptr} + 24]", + "add r14, rcx", + "adcx r15, rax", + + // reduction if limbs is greater then mod + "mov r8, r12", + "mov r9, r13", + "mov r10, r14", + "mov r11, r15", + + "sub r8, qword ptr [{m_ptr} + 0]", + "sbb r9, qword ptr [{m_ptr} + 8]", + "sbb r10, qword ptr [{m_ptr} + 16]", + "sbb r11, qword ptr [{m_ptr} + 24]", + + "cmovc r8, r12", + "cmovc r9, r13", + "cmovc r10, r14", + "cmovc r11, r15", + + "mov r12, r8", + "mov r13, r9", + "mov r14, r10", + "mov r15, r11", + + "sub r12, qword ptr [{m_ptr} + 0]", + "sbb r13, qword ptr [{m_ptr} + 8]", + "sbb r14, qword ptr [{m_ptr} + 16]", + "sbb r15, qword ptr [{m_ptr} + 24]", + + "cmovc r12, r8", + "cmovc r13, r9", + "cmovc r14, r10", + "cmovc r15, r11", + + m_ptr = in(reg) $modulus.0.as_ptr(), + a_ptr = in(reg) self.0.as_ptr(), + b_ptr = in(reg) rhs.0.as_ptr(), + inv = const $inv, + out("rax") _, + out("rcx") _, + out("rdx") _, + out("r8") _, + out("r9") _, + out("r10") _, + out("r11") _, + out("r12") r0, + out("r13") r1, + out("r14") r2, + out("r15") r3, + options(pure, readonly, nostack) + ) + } + + $field([r0, r1, r2, r3]) + } + + /// Subtracts `rhs` from `self`, returning the result. + #[inline] + pub fn sub(&self, rhs: &Self) -> $field { + let mut r0: u64; + let mut r1: u64; + let mut r2: u64; + let mut r3: u64; + unsafe { + asm!( + // init modulus area + "xor r12, r12", + "xor r13, r13", + "xor r14, r14", + "xor r15, r15", + + // load a array to former registers + "mov r8, qword ptr [{a_ptr} + 0]", + "mov r9, qword ptr [{a_ptr} + 8]", + "mov r10, qword ptr [{a_ptr} + 16]", + "mov r11, qword ptr [{a_ptr} + 24]", + + // sub a array and b array with borrow + "sub r8, qword ptr [{b_ptr} + 0]", + "sbb r9, qword ptr [{b_ptr} + 8]", + "sbb r10, qword ptr [{b_ptr} + 16]", + "sbb r11, qword ptr [{b_ptr} + 24]", + + // if carry copy modulus + "cmovc r12, qword ptr [{m_ptr} + 0]", + "cmovc r13, qword ptr [{m_ptr} + 8]", + "cmovc r14, qword ptr [{m_ptr} + 16]", + "cmovc r15, qword ptr [{m_ptr} + 24]", + + // mod addition + "add r12, r8", + "adcx r13, r9", + "adcx r14, r10", + "adcx r15, r11", + + m_ptr = in(reg) $modulus.0.as_ptr(), + a_ptr = in(reg) self.0.as_ptr(), + b_ptr = in(reg) rhs.0.as_ptr(), + out("r8") _, + out("r9") _, + out("r10") _, + out("r11") _, + out("r12") r0, + out("r13") r1, + out("r14") r2, + out("r15") r3, + options(pure, readonly, nostack) + ); + } + $field([r0, r1, r2, r3]) + } + + /// Adds `rhs` to `self`, returning the result. + #[inline] + pub fn add(&self, rhs: &Self) -> $field { + let mut r0: u64; + let mut r1: u64; + let mut r2: u64; + let mut r3: u64; + unsafe { + asm!( + // load a array to former registers + "mov r8, qword ptr [{a_ptr} + 0]", + "mov r9, qword ptr [{a_ptr} + 8]", + "mov r10, qword ptr [{a_ptr} + 16]", + "mov r11, qword ptr [{a_ptr} + 24]", + + // add a array and b array with carry + "add r8, qword ptr [{b_ptr} + 0]", + "adcx r9, qword ptr [{b_ptr} + 8]", + "adcx r10, qword ptr [{b_ptr} + 16]", + "adcx r11, qword ptr [{b_ptr} + 24]", + + // copy result array to latter registers + "mov r12, r8", + "mov r13, r9", + "mov r14, r10", + "mov r15, r11", + + // mod reduction + "sub r12, qword ptr [{m_ptr} + 0]", + "sbb r13, qword ptr [{m_ptr} + 8]", + "sbb r14, qword ptr [{m_ptr} + 16]", + "sbb r15, qword ptr [{m_ptr} + 24]", + + // if carry copy former registers to out areas + "cmovc r12, r8", + "cmovc r13, r9", + "cmovc r14, r10", + "cmovc r15, r11", + + m_ptr = in(reg) $modulus.0.as_ptr(), + a_ptr = in(reg) self.0.as_ptr(), + b_ptr = in(reg) rhs.0.as_ptr(), + out("r8") _, + out("r9") _, + out("r10") _, + out("r11") _, + out("r12") r0, + out("r13") r1, + out("r14") r2, + out("r15") r3, + options(pure, readonly, nostack) + ); + } + $field([r0, r1, r2, r3]) + } + + /// Negates `self`. + #[inline] + pub fn neg(&self) -> $field { + let mut r0: u64; + let mut r1: u64; + let mut r2: u64; + let mut r3: u64; + unsafe { + asm!( + // load a array to former registers + "mov r8, qword ptr [{m_ptr} + 0]", + "mov r9, qword ptr [{m_ptr} + 8]", + "mov r10, qword ptr [{m_ptr} + 16]", + "mov r11, qword ptr [{m_ptr} + 24]", + + "sub r8, qword ptr [{a_ptr} + 0]", + "sbb r9, qword ptr [{a_ptr} + 8]", + "sbb r10, qword ptr [{a_ptr} + 16]", + "sbb r11, qword ptr [{a_ptr} + 24]", + + "mov r12, qword ptr [{a_ptr} + 0]", + "mov r13, qword ptr [{a_ptr} + 8]", + "mov r14, qword ptr [{a_ptr} + 16]", + "mov r15, qword ptr [{a_ptr} + 24]", + + "or r12, r13", + "or r14, r15", + "or r12, r14", + + "mov r13, 0xffffffffffffffff", + "cmp r12, 0x0000000000000000", + "cmove r13, r12", + + "and r8, r13", + "and r9, r13", + "and r10, r13", + "and r11, r13", + + a_ptr = in(reg) self.0.as_ptr(), + m_ptr = in(reg) $modulus.0.as_ptr(), + out("r8") r0, + out("r9") r1, + out("r10") r2, + out("r11") r3, + out("r12") _, + out("r13") _, + out("r14") _, + out("r15") _, + options(pure, readonly, nostack) + ) + } + $field([r0, r1, r2, r3]) + } + } + }; +} + +pub(crate) use assembly_field; diff --git a/arithmetic/curves/src/bn256/curve.rs b/arithmetic/curves/src/bn256/curve.rs new file mode 100644 index 0000000000..3450ed909c --- /dev/null +++ b/arithmetic/curves/src/bn256/curve.rs @@ -0,0 +1,335 @@ +use crate::arithmetic::mul_512; +use crate::bn256::Fq; +use crate::bn256::Fq2; +use crate::bn256::Fr; +use crate::{Coordinates, CurveAffine, CurveAffineExt, CurveExt, Group}; +use core::cmp; +use core::fmt::Debug; +use core::iter::Sum; +use core::ops::{Add, Mul, Neg, Sub}; +use ff::{Field, PrimeField}; +use group::Curve; +use group::{cofactor::CofactorGroup, prime::PrimeCurveAffine, Group as _, GroupEncoding}; +use pasta_curves::arithmetic::FieldExt; +use rand::RngCore; +use serde::{Deserialize, Serialize}; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +use crate::{ + batch_add, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, new_curve_impl, +}; + +new_curve_impl!( + (pub), + G1, + G1Affine, + G1Compressed, + Fq::size(), + Fq, + Fr, + (G1_GENERATOR_X,G1_GENERATOR_Y), + G1_B, + "bn256_g1", +); + +new_curve_impl!( + (pub), + G2, + G2Affine, + G2Compressed, + Fq2::size(), + Fq2, + Fr, + (G2_GENERATOR_X, G2_GENERATOR_Y), + G2_B, + "bn256_g2", +); + +impl CurveAffineExt for G1Affine { + batch_add!(); + + fn into_coordinates(self) -> (Self::Base, Self::Base) { + (self.x, self.y) + } +} + +impl CurveAffineExt for G2Affine { + batch_add!(); + + fn into_coordinates(self) -> (Self::Base, Self::Base) { + (self.x, self.y) + } +} + +const G1_GENERATOR_X: Fq = Fq::one(); +const G1_GENERATOR_Y: Fq = Fq::from_raw([2, 0, 0, 0]); +const G1_B: Fq = Fq::from_raw([3, 0, 0, 0]); +const ENDO_G1: [u64; 4] = [ + 0x7a7bd9d4391eb18du64, + 0x4ccef014a773d2cfu64, + 0x0000000000000002u64, + 0u64, +]; +const ENDO_G2: [u64; 4] = [0xd91d232ec7e0b3d7u64, 0x0000000000000002u64, 0u64, 0u64]; +const ENDO_MINUS_B1: [u64; 4] = [0x8211bbeb7d4f1128u64, 0x6f4d8248eeb859fcu64, 0u64, 0u64]; +const ENDO_B2: [u64; 4] = [0x89d3256894d213e3u64, 0u64, 0u64, 0u64]; +const ENDO_BETA: Fr = Fr::from_raw([ + 0x8b17ea66b99c90ddu64, + 0x5bfc41088d8daaa7u64, + 0xb3c4d79d41a91758u64, + 0x0u64, +]); + +const G2_B: Fq2 = Fq2 { + c0: Fq::from_raw([ + 0x3267e6dc24a138e5, + 0xb5b4c5e559dbefa3, + 0x81be18991be06ac3, + 0x2b149d40ceb8aaae, + ]), + c1: Fq::from_raw([ + 0xe4a2bd0685c315d2, + 0xa74fa084e52d1852, + 0xcd2cafadeed8fdf4, + 0x009713b03af0fed4, + ]), +}; + +const G2_GENERATOR_X: Fq2 = Fq2 { + c0: Fq::from_raw([ + 0x46debd5cd992f6ed, + 0x674322d4f75edadd, + 0x426a00665e5c4479, + 0x1800deef121f1e76, + ]), + c1: Fq::from_raw([ + 0x97e485b7aef312c2, + 0xf1aa493335a9e712, + 0x7260bfb731fb5d25, + 0x198e9393920d483a, + ]), +}; + +const G2_GENERATOR_Y: Fq2 = Fq2 { + c0: Fq::from_raw([ + 0x4ce6cc0166fa7daa, + 0xe3d1e7690c43d37b, + 0x4aab71808dcb408f, + 0x12c85ea5db8c6deb, + ]), + + c1: Fq::from_raw([ + 0x55acdadcd122975b, + 0xbc4b313370b38ef3, + 0xec9e99ad690c3395, + 0x090689d0585ff075, + ]), +}; + +trait CurveEndo: CurveExt { + fn endomorphism_base(&self) -> Self; + fn endomorphism_scalars(k: &Self::ScalarExt) -> (u128, u128); +} + +impl CurveEndo for G1 { + fn endomorphism_base(&self) -> Self { + Self { + x: self.x * Self::Base::ZETA, + y: -self.y, + z: self.z, + } + } + + fn endomorphism_scalars(k: &Self::ScalarExt) -> (u128, u128) { + #[cfg(feature = "asm")] + let input = Fr::montgomery_reduce(&[k.0[0], k.0[1], k.0[2], k.0[3], 0, 0, 0, 0]).0; + + #[cfg(not(feature = "asm"))] + let input = Fr::montgomery_reduce(k.0[0], k.0[1], k.0[2], k.0[3], 0, 0, 0, 0).0; + + let c1_512 = mul_512(ENDO_G2, input); + let c2_512 = mul_512(ENDO_G1, input); + + let c1_hi = [c1_512[4], c1_512[5], c1_512[6], c1_512[7]]; + let c2_hi = [c2_512[4], c2_512[5], c2_512[6], c2_512[7]]; + + let q1_512 = mul_512(c1_hi, ENDO_MINUS_B1); + let q2_512 = mul_512(c2_hi, ENDO_B2); + + let q1_lo = Self::ScalarExt::from_raw([q1_512[0], q1_512[1], q1_512[2], q1_512[3]]); + let q2_lo = Self::ScalarExt::from_raw([q2_512[0], q2_512[1], q2_512[2], q2_512[3]]); + + let k1 = q2_lo - q1_lo; + let k2 = (k1 * ENDO_BETA) + k; + + (k2.get_lower_128(), k1.get_lower_128()) + } +} + +impl CurveEndo for G2 { + fn endomorphism_base(&self) -> Self { + unimplemented!(); + } + + fn endomorphism_scalars(_: &Self::ScalarExt) -> (u128, u128) { + unimplemented!(); + } +} + +impl group::cofactor::CofactorGroup for G1 { + type Subgroup = G1; + + fn clear_cofactor(&self) -> Self { + *self + } + + fn into_subgroup(self) -> CtOption { + CtOption::new(self, 1.into()) + } + + fn is_torsion_free(&self) -> Choice { + 1.into() + } +} + +impl CofactorGroup for G2 { + type Subgroup = G2; + + fn clear_cofactor(&self) -> Self { + // "0x30644e72e131a029b85045b68181585e06ceecda572a2489345f2299c0f9fa8d" + let e: [u8; 32] = [ + 0x30, 0x64, 0x4e, 0x72, 0xe1, 0x31, 0xa0, 0x29, 0xb8, 0x50, 0x45, 0xb6, 0x81, 0x81, + 0x58, 0x5e, 0x06, 0xce, 0xec, 0xda, 0x57, 0x2a, 0x24, 0x89, 0x34, 0x5f, 0x22, 0x99, + 0xc0, 0xf9, 0xfa, 0x8d, + ]; + + // self * COFACTOR_G2 + let mut acc = G2::identity(); + for bit in e + .iter() + .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8))) + .skip(1) + { + acc = acc.double(); + acc = G2::conditional_select(&acc, &(acc + self), bit); + } + acc + } + + fn into_subgroup(self) -> CtOption { + unimplemented!(); + } + + fn is_torsion_free(&self) -> Choice { + // "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001" + let e: [u8; 32] = [ + 0x30, 0x64, 0x4e, 0x72, 0xe1, 0x31, 0xa0, 0x29, 0xb8, 0x50, 0x45, 0xb6, 0x81, 0x81, + 0x58, 0x5d, 0x28, 0x33, 0xe8, 0x48, 0x79, 0xb9, 0x70, 0x91, 0x43, 0xe1, 0xf5, 0x93, + 0xf0, 0x00, 0x00, 0x01, + ]; + + // self * GROUP_ORDER; + + let mut acc = G2::identity(); + for bit in e + .iter() + .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8))) + .skip(1) + { + acc = acc.double(); + acc = G2::conditional_select(&acc, &(acc + self), bit); + } + acc.is_identity() + } +} + +#[cfg(test)] +mod tests { + + use crate::bn256::{ + curve::{CurveEndo, ENDO_BETA}, + Fr, G1Affine, G1, G2, + }; + use ff::Field; + use rand_core::OsRng; + + use crate::CurveExt; + + #[test] + fn test_curve() { + crate::tests::curve::curve_tests::(); + crate::tests::curve::curve_tests::(); + } + + #[test] + fn test_endo_consistency() { + let g = G1::generator(); + assert_eq!(g * (-ENDO_BETA), g.endo()); + } + + #[test] + fn test_endomorphism() { + use crate::FieldExt; + + let scalar = Fr::random(OsRng); + let point = G1Affine::random(OsRng); + + let expected = point * scalar; + + let (part1, part2) = G1::endomorphism_scalars(&scalar); + + let k1 = Fr::from_u128(part1); + let k2 = Fr::from_u128(part2); + + let t1 = point * k1; + let base = G1::endomorphism_base(&point.into()); + + let t2 = base * k2; + let result = t1 + t2; + + let res_affine: G1Affine = result.into(); + let exp_affine: G1Affine = expected.into(); + + assert_eq!(res_affine, exp_affine); + } + + #[test] + fn test_serialization() { + crate::tests::curve::random_serialization_test::(); + crate::tests::curve::random_serialization_test::(); + } +} + +impl group::UncompressedEncoding for G1Affine { + type Uncompressed = G1Compressed; + + fn from_uncompressed(_: &Self::Uncompressed) -> CtOption { + unimplemented!(); + } + + fn from_uncompressed_unchecked(_: &Self::Uncompressed) -> CtOption { + unimplemented!(); + } + + fn to_uncompressed(&self) -> Self::Uncompressed { + unimplemented!(); + } +} + +impl group::UncompressedEncoding for G2Affine { + type Uncompressed = G2Compressed; + + fn from_uncompressed(_: &Self::Uncompressed) -> CtOption { + unimplemented!(); + } + + fn from_uncompressed_unchecked(_: &Self::Uncompressed) -> CtOption { + unimplemented!(); + } + + fn to_uncompressed(&self) -> Self::Uncompressed { + unimplemented!(); + } +} diff --git a/arithmetic/curves/src/bn256/engine.rs b/arithmetic/curves/src/bn256/engine.rs new file mode 100644 index 0000000000..87453c17be --- /dev/null +++ b/arithmetic/curves/src/bn256/engine.rs @@ -0,0 +1,838 @@ +#![allow(clippy::suspicious_arithmetic_impl)] +use crate::bn256::curve::*; +use crate::bn256::fq::*; +use crate::bn256::fq12::*; +use crate::bn256::fq2::*; +use crate::bn256::fq6::FROBENIUS_COEFF_FQ6_C1; +use crate::bn256::fr::*; +use crate::pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine}; +use core::borrow::Borrow; +use core::iter::Sum; +use core::ops::{Add, Mul, MulAssign, Neg, Sub}; +use ff::{Field, PrimeField}; +use group::cofactor::CofactorCurveAffine; +use group::Group; +use rand_core::RngCore; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; + +pub const BN_X: u64 = 4965661367192848881; + +// 6U+2 for in NAF form +pub const SIX_U_PLUS_2_NAF: [i8; 65] = [ + 0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0, + 1, 1, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0, + 0, 1, 0, 1, 1, +]; + +pub const XI_TO_Q_MINUS_1_OVER_2: Fq2 = Fq2 { + c0: Fq([ + 0xe4bbdd0c2936b629, + 0xbb30f162e133bacb, + 0x31a9d1b6f9645366, + 0x253570bea500f8dd, + ]), + c1: Fq([ + 0xa1d77ce45ffe77c7, + 0x07affd117826d1db, + 0x6d16bd27bb7edc6b, + 0x2c87200285defecc, + ]), +}; + +impl PairingCurveAffine for G1Affine { + type Pair = G2Affine; + type PairingResult = Gt; + + fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult { + pairing(self, other) + } +} + +impl PairingCurveAffine for G2Affine { + type Pair = G1Affine; + type PairingResult = Gt; + + fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult { + pairing(other, self) + } +} + +#[derive(Copy, Clone, Debug, Default)] +pub struct Gt(pub(crate) Fq12); + +impl std::fmt::Display for Gt { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{self:?}") + } +} + +impl ConstantTimeEq for Gt { + fn ct_eq(&self, other: &Self) -> Choice { + self.0.ct_eq(&other.0) + } +} + +impl ConditionallySelectable for Gt { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Gt(Fq12::conditional_select(&a.0, &b.0, choice)) + } +} + +impl Eq for Gt {} +impl PartialEq for Gt { + #[inline] + fn eq(&self, other: &Self) -> bool { + bool::from(self.ct_eq(other)) + } +} + +impl Gt { + /// Returns the group identity, which is $1$. + pub fn identity() -> Gt { + Gt(Fq12::one()) + } + + /// Doubles this group element. + pub fn double(&self) -> Gt { + Gt(self.0.square()) + } +} + +impl<'a> Neg for &'a Gt { + type Output = Gt; + + #[inline] + fn neg(self) -> Gt { + // The element is unitary, so we just conjugate. + let mut u = self.0; + u.conjugate(); + Gt(u) + } +} + +impl Neg for Gt { + type Output = Gt; + + #[inline] + fn neg(self) -> Gt { + -&self + } +} + +impl<'a, 'b> Add<&'b Gt> for &'a Gt { + type Output = Gt; + + #[inline] + fn add(self, rhs: &'b Gt) -> Gt { + Gt(self.0 * rhs.0) + } +} + +impl<'a, 'b> Sub<&'b Gt> for &'a Gt { + type Output = Gt; + + #[inline] + fn sub(self, rhs: &'b Gt) -> Gt { + self + (-rhs) + } +} + +impl<'a, 'b> Mul<&'b Fr> for &'a Gt { + type Output = Gt; + + fn mul(self, other: &'b Fr) -> Self::Output { + let mut acc = Gt::identity(); + + for bit in other + .to_repr() + .iter() + .rev() + .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8))) + .skip(1) + { + acc = acc.double(); + acc = Gt::conditional_select(&acc, &(acc + self), bit); + } + + acc + } +} + +use crate::{ + impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, + impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, +}; +impl_binops_additive!(Gt, Gt); +impl_binops_multiplicative!(Gt, Fr); + +impl Sum for Gt +where + T: Borrow, +{ + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::identity(), |acc, item| acc + item.borrow()) + } +} + +impl Group for Gt { + type Scalar = Fr; + + fn random(_: impl RngCore) -> Self { + unimplemented!(); + } + + fn identity() -> Self { + Self::identity() + } + + fn generator() -> Self { + unimplemented!(); + } + + fn is_identity(&self) -> Choice { + self.ct_eq(&Self::identity()) + } + + #[must_use] + fn double(&self) -> Self { + self.double() + } +} + +#[derive(Clone, Debug)] +pub struct G2Prepared { + pub(crate) coeffs: Vec<(Fq2, Fq2, Fq2)>, + pub(crate) infinity: bool, +} + +impl G2Prepared { + pub fn is_zero(&self) -> bool { + self.infinity + } + + pub fn from_affine(q: G2Affine) -> Self { + if bool::from(q.is_identity()) { + return G2Prepared { + coeffs: vec![], + infinity: true, + }; + } + + fn doubling_step(r: &mut G2) -> (Fq2, Fq2, Fq2) { + // Adaptation of Algorithm 26, https://eprint.iacr.org/2010/354.pdf + let mut tmp0 = r.x; + tmp0.square_assign(); + + let mut tmp1 = r.y; + tmp1.square_assign(); + + let mut tmp2 = tmp1; + tmp2.square_assign(); + + let mut tmp3 = tmp1; + tmp3 += &r.x; + tmp3.square_assign(); + tmp3 -= &tmp0; + tmp3 -= &tmp2; + tmp3.double_assign(); + + let mut tmp4 = tmp0; + tmp4.double_assign(); + tmp4 += &tmp0; + + let mut tmp6 = r.x; + tmp6 += &tmp4; + + let mut tmp5 = tmp4; + tmp5.square_assign(); + + let mut zsquared = r.z; + zsquared.square_assign(); + + r.x = tmp5; + r.x -= &tmp3; + r.x -= &tmp3; + + r.z += &r.y; + r.z.square_assign(); + r.z -= &tmp1; + r.z -= &zsquared; + + r.y = tmp3; + r.y -= &r.x; + r.y.mul_assign(&tmp4); + + tmp2.double_assign(); + tmp2.double_assign(); + tmp2.double_assign(); + + r.y -= &tmp2; + + // up to here everything was by algorith, line 11 + // use R instead of new T + + // tmp3 is the first part of line 12 + tmp3 = tmp4; + tmp3.mul_assign(&zsquared); + tmp3.double_assign(); + tmp3 = tmp3.neg(); + + // tmp6 is from line 14 + tmp6.square_assign(); + tmp6 -= &tmp0; + tmp6 -= &tmp5; + + tmp1.double_assign(); + tmp1.double_assign(); + + tmp6 -= &tmp1; + + // tmp0 is the first part of line 16 + tmp0 = r.z; + tmp0.mul_assign(&zsquared); + tmp0.double_assign(); + + (tmp0, tmp3, tmp6) + } + + fn addition_step(r: &mut G2, q: &G2Affine) -> (Fq2, Fq2, Fq2) { + // Adaptation of Algorithm 27, https://eprint.iacr.org/2010/354.pdf + let mut zsquared = r.z; + zsquared.square_assign(); + + let mut ysquared = q.y; + ysquared.square_assign(); + + // t0 corresponds to line 1 + let mut t0 = zsquared; + t0.mul_assign(&q.x); + + // t1 corresponds to lines 2 and 3 + let mut t1 = q.y; + t1 += &r.z; + t1.square_assign(); + t1 -= &ysquared; + t1 -= &zsquared; + t1.mul_assign(&zsquared); + + // t2 corresponds to line 4 + let mut t2 = t0; + t2 -= &r.x; + + // t3 corresponds to line 5 + let mut t3 = t2; + t3.square_assign(); + + // t4 corresponds to line 6 + let mut t4 = t3; + t4.double_assign(); + t4.double_assign(); + + // t5 corresponds to line 7 + let mut t5 = t4; + t5.mul_assign(&t2); + + // t6 corresponds to line 8 + let mut t6 = t1; + t6 -= &r.y; + t6 -= &r.y; + + // t9 corresponds to line 9 + let mut t9 = t6; + t9.mul_assign(&q.x); + + // corresponds to line 10 + let mut t7 = t4; + t7.mul_assign(&r.x); + + // corresponds to line 11, but assigns to r.x instead of T.x + r.x = t6; + r.x.square_assign(); + r.x -= &t5; + r.x -= &t7; + r.x -= &t7; + + // corresponds to line 12, but assigns to r.z instead of T.z + r.z += &t2; + r.z.square_assign(); + r.z -= &zsquared; + r.z -= &t3; + + // corresponds to line 13 + let mut t10 = q.y; + t10 += &r.z; + + // corresponds to line 14 + let mut t8 = t7; + t8 -= &r.x; + t8.mul_assign(&t6); + + // corresponds to line 15 + t0 = r.y; + t0.mul_assign(&t5); + t0.double_assign(); + + // corresponds to line 12, but assigns to r.y instead of T.y + r.y = t8; + r.y -= &t0; + + // corresponds to line 17 + t10.square_assign(); + t10 -= &ysquared; + + let mut ztsquared = r.z; + ztsquared.square_assign(); + + t10 -= &ztsquared; + + // corresponds to line 18 + t9.double_assign(); + t9 -= &t10; + + // t10 = 2*Zt from Algo 27, line 19 + t10 = r.z; + t10.double_assign(); + + // t1 = first multiplicator of line 21 + t6 = t6.neg(); + + t1 = t6; + t1.double_assign(); + + // t9 corresponds to t9 from Algo 27 + (t10, t1, t9) + } + + let mut coeffs = vec![]; + let mut r: G2 = q.into(); + + let mut negq = q; + negq = -negq; + + for i in (1..SIX_U_PLUS_2_NAF.len()).rev() { + coeffs.push(doubling_step(&mut r)); + let x = SIX_U_PLUS_2_NAF[i - 1]; + match x { + 1 => { + coeffs.push(addition_step(&mut r, &q)); + } + -1 => { + coeffs.push(addition_step(&mut r, &negq)); + } + _ => continue, + } + } + + let mut q1 = q; + + q1.x.c1 = q1.x.c1.neg(); + q1.x.mul_assign(&FROBENIUS_COEFF_FQ6_C1[1]); + + q1.y.c1 = q1.y.c1.neg(); + q1.y.mul_assign(&XI_TO_Q_MINUS_1_OVER_2); + + coeffs.push(addition_step(&mut r, &q1)); + + let mut minusq2 = q; + minusq2.x.mul_assign(&FROBENIUS_COEFF_FQ6_C1[2]); + + coeffs.push(addition_step(&mut r, &minusq2)); + + G2Prepared { + coeffs, + infinity: false, + } + } +} + +impl From for G2Prepared { + fn from(q: G2Affine) -> G2Prepared { + G2Prepared::from_affine(q) + } +} + +impl MillerLoopResult for Gt { + type Gt = Self; + // pub fn final_exponentiation(r: &Fq12) -> CtOption { + fn final_exponentiation(&self) -> Gt { + fn exp_by_x(f: &mut Fq12) { + let x = BN_X; + let mut res = Fq12::one(); + for i in (0..64).rev() { + res.cyclotomic_square(); + if ((x >> i) & 1) == 1 { + res.mul_assign(f); + } + } + *f = res; + } + + let r = self.0; + let mut f1 = self.0; + f1.conjugate(); + + Gt(r.invert() + .map(|mut f2| { + let mut r = f1; + r.mul_assign(&f2); + f2 = r; + r.frobenius_map(2); + r.mul_assign(&f2); + + let mut fp = r; + fp.frobenius_map(1); + + let mut fp2 = r; + fp2.frobenius_map(2); + let mut fp3 = fp2; + fp3.frobenius_map(1); + + let mut fu = r; + exp_by_x(&mut fu); + + let mut fu2 = fu; + exp_by_x(&mut fu2); + + let mut fu3 = fu2; + exp_by_x(&mut fu3); + + let mut y3 = fu; + y3.frobenius_map(1); + + let mut fu2p = fu2; + fu2p.frobenius_map(1); + + let mut fu3p = fu3; + fu3p.frobenius_map(1); + + let mut y2 = fu2; + y2.frobenius_map(2); + + let mut y0 = fp; + y0.mul_assign(&fp2); + y0.mul_assign(&fp3); + + let mut y1 = r; + y1.conjugate(); + + let mut y5 = fu2; + y5.conjugate(); + + y3.conjugate(); + + let mut y4 = fu; + y4.mul_assign(&fu2p); + y4.conjugate(); + + let mut y6 = fu3; + y6.mul_assign(&fu3p); + y6.conjugate(); + + y6.cyclotomic_square(); + y6.mul_assign(&y4); + y6.mul_assign(&y5); + + let mut t1 = y3; + t1.mul_assign(&y5); + t1.mul_assign(&y6); + + y6.mul_assign(&y2); + + t1.cyclotomic_square(); + t1.mul_assign(&y6); + t1.cyclotomic_square(); + + let mut t0 = t1; + t0.mul_assign(&y1); + + t1.mul_assign(&y0); + + t0.cyclotomic_square(); + t0.mul_assign(&t1); + + t0 + }) + .unwrap()) + } +} + +pub fn multi_miller_loop(terms: &[(&G1Affine, &G2Prepared)]) -> Gt { + let mut pairs = vec![]; + for &(p, q) in terms { + if !bool::from(p.is_identity()) && !q.is_zero() { + pairs.push((p, q.coeffs.iter())); + } + } + + // Final steps of the line function on prepared coefficients + fn ell(f: &mut Fq12, coeffs: &(Fq2, Fq2, Fq2), p: &G1Affine) { + let mut c0 = coeffs.0; + let mut c1 = coeffs.1; + + c0.c0.mul_assign(&p.y); + c0.c1.mul_assign(&p.y); + + c1.c0.mul_assign(&p.x); + c1.c1.mul_assign(&p.x); + + // Sparse multiplication in Fq12 + f.mul_by_034(&c0, &c1, &coeffs.2); + } + + let mut f = Fq12::one(); + + for i in (1..SIX_U_PLUS_2_NAF.len()).rev() { + if i != SIX_U_PLUS_2_NAF.len() - 1 { + f.square_assign(); + } + for &mut (p, ref mut coeffs) in &mut pairs { + ell(&mut f, coeffs.next().unwrap(), p); + } + let x = SIX_U_PLUS_2_NAF[i - 1]; + match x { + 1 => { + for &mut (p, ref mut coeffs) in &mut pairs { + ell(&mut f, coeffs.next().unwrap(), p); + } + } + -1 => { + for &mut (p, ref mut coeffs) in &mut pairs { + ell(&mut f, coeffs.next().unwrap(), p); + } + } + _ => continue, + } + } + + for &mut (p, ref mut coeffs) in &mut pairs { + ell(&mut f, coeffs.next().unwrap(), p); + } + + for &mut (p, ref mut coeffs) in &mut pairs { + ell(&mut f, coeffs.next().unwrap(), p); + } + + for &mut (_p, ref mut coeffs) in &mut pairs { + assert_eq!(coeffs.next(), None); + } + + Gt(f) +} + +pub fn pairing(g1: &G1Affine, g2: &G2Affine) -> Gt { + let g2 = G2Prepared::from_affine(*g2); + let terms: &[(&G1Affine, &G2Prepared)] = &[(g1, &g2)]; + let u = multi_miller_loop(terms); + u.final_exponentiation() +} + +#[derive(Clone, Debug)] +pub struct Bn256; + +impl Engine for Bn256 { + type Scalar = Fr; + type G1 = G1; + type G1Affine = G1Affine; + type G2 = G2; + type G2Affine = G2Affine; + type Gt = Gt; + + fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt { + pairing(p, q) + } +} + +impl MultiMillerLoop for Bn256 { + type G2Prepared = G2Prepared; + type Result = Gt; + + fn multi_miller_loop(terms: &[(&Self::G1Affine, &Self::G2Prepared)]) -> Self::Result { + multi_miller_loop(terms) + } +} + +#[cfg(test)] +use rand::SeedableRng; +#[cfg(test)] +use rand_xorshift::XorShiftRng; + +#[test] +fn test_pairing() { + let g1 = G1::generator(); + let mut g2 = G2::generator(); + g2 = g2.double(); + let pair12 = Bn256::pairing(&G1Affine::from(g1), &G2Affine::from(g2)); + + let mut g1 = G1::generator(); + let g2 = G2::generator(); + g1 = g1.double(); + let pair21 = Bn256::pairing(&G1Affine::from(g1), &G2Affine::from(g2)); + + assert_eq!(pair12, pair21); + + let g1 = G1::generator(); + let mut g2 = G2::generator(); + g2 = g2.double().double(); + let pair12 = Bn256::pairing(&G1Affine::from(g1), &G2Affine::from(g2)); + + let mut g1 = G1::generator(); + let mut g2 = G2::generator(); + g1 = g1.double(); + g2 = g2.double(); + let pair21 = Bn256::pairing(&G1Affine::from(g1), &G2Affine::from(g2)); + + assert_eq!(pair12, pair21); + + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + for _ in 0..1000 { + let a = Fr::random(&mut rng); + let b = Fr::random(&mut rng); + + let mut g1 = G1::generator(); + g1.mul_assign(a); + + let mut g2 = G2::generator(); + g1.mul_assign(b); + + let pair_ab = Bn256::pairing(&G1Affine::from(g1), &G2Affine::from(g2)); + + g1 = G1::generator(); + g1.mul_assign(b); + + g2 = G2::generator(); + g1.mul_assign(a); + + let pair_ba = Bn256::pairing(&G1Affine::from(g1), &G2Affine::from(g2)); + + assert_eq!(pair_ab, pair_ba); + } +} + +#[test] +fn random_bilinearity_tests() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let mut a = G1::generator(); + let ka = Fr::random(&mut rng); + a.mul_assign(ka); + + let mut b = G2::generator(); + let kb = Fr::random(&mut rng); + b.mul_assign(kb); + + let c = Fr::random(&mut rng); + let d = Fr::random(&mut rng); + + let mut ac = a; + ac.mul_assign(c); + + let mut ad = a; + ad.mul_assign(d); + + let mut bc = b; + bc.mul_assign(c); + + let mut bd = b; + bd.mul_assign(d); + + let acbd = Bn256::pairing(&G1Affine::from(ac), &G2Affine::from(bd)); + let adbc = Bn256::pairing(&G1Affine::from(ad), &G2Affine::from(bc)); + + let mut cd = c; + cd.mul_assign(&d); + + cd *= Fr([1, 0, 0, 0]); + + let abcd = Gt(Bn256::pairing(&G1Affine::from(a), &G2Affine::from(b)) + .0 + .pow_vartime(cd.0)); + + assert_eq!(acbd, adbc); + assert_eq!(acbd, abcd); + } +} + +#[test] +pub fn engine_tests() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..10 { + let a = G1Affine::from(G1::random(&mut rng)); + let b = G2Affine::from(G2::random(&mut rng)); + + assert!(a.pairing_with(&b) == b.pairing_with(&a)); + assert!(a.pairing_with(&b) == pairing(&a, &b)); + } + + for _ in 0..1000 { + let z1 = G1Affine::identity(); + let z2 = G2Prepared::from(G2Affine::identity()); + + let a = G1Affine::from(G1::random(&mut rng)); + let b = G2Prepared::from(G2Affine::from(G2::random(&mut rng))); + let c = G1Affine::from(G1::random(&mut rng)); + let d = G2Prepared::from(G2Affine::from(G2::random(&mut rng))); + + assert_eq!( + Fq12::one(), + multi_miller_loop(&[(&z1, &b)]).final_exponentiation().0, + ); + + assert_eq!( + Fq12::one(), + multi_miller_loop(&[(&a, &z2)]).final_exponentiation().0, + ); + + assert_eq!( + multi_miller_loop(&[(&z1, &b), (&c, &d)]).final_exponentiation(), + multi_miller_loop(&[(&a, &z2), (&c, &d)]).final_exponentiation(), + ); + + assert_eq!( + multi_miller_loop(&[(&a, &b), (&z1, &d)]).final_exponentiation(), + multi_miller_loop(&[(&a, &b), (&c, &z2)]).final_exponentiation(), + ); + } +} + +#[test] +fn random_miller_loop_tests() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + // Exercise a double miller loop + for _ in 0..1000 { + let a = G1Affine::from(G1::random(&mut rng)); + let b = G2Affine::from(G2::random(&mut rng)); + let c = G1Affine::from(G1::random(&mut rng)); + let d = G2Affine::from(G2::random(&mut rng)); + + let ab = pairing(&a, &b); + let cd = pairing(&c, &d); + + let mut abcd = ab; + abcd = Gt(abcd.0 * cd.0); + + let b = G2Prepared::from(b); + let d = G2Prepared::from(d); + + let abcd_with_double_loop = multi_miller_loop(&[(&a, &b), (&c, &d)]).final_exponentiation(); + + assert_eq!(abcd, abcd_with_double_loop); + } +} diff --git a/arithmetic/curves/src/bn256/fq.rs b/arithmetic/curves/src/bn256/fq.rs new file mode 100644 index 0000000000..b108e2ed9e --- /dev/null +++ b/arithmetic/curves/src/bn256/fq.rs @@ -0,0 +1,362 @@ +#[cfg(feature = "asm")] +use super::assembly::assembly_field; + +use super::LegendreSymbol; +use crate::arithmetic::{adc, mac, macx, sbb}; +use pasta_curves::arithmetic::{FieldExt, Group, SqrtRatio}; +use serde::{Deserialize, Serialize}; + +use core::convert::TryInto; +use core::fmt; +use core::ops::{Add, Mul, Neg, Sub}; +use ff::PrimeField; +use rand::RngCore; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +/// This represents an element of $\mathbb{F}_q$ where +/// +/// `p = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47` +/// +/// is the base field of the BN254 curve. +// The internal representation of this type is four 64-bit unsigned +// integers in little-endian order. `Fq` values are always in +// Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256. +#[derive(Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)] +pub struct Fq(pub(crate) [u64; 4]); + +/// Constant representing the modulus +/// q = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 +pub const MODULUS: Fq = Fq([ + 0x3c208c16d87cfd47, + 0x97816a916871ca8d, + 0xb85045b68181585d, + 0x30644e72e131a029, +]); + +/// INV = -(q^{-1} mod 2^64) mod 2^64 +const INV: u64 = 0x87d20782e4866389; + +/// R = 2^256 mod q +const R: Fq = Fq([ + 0xd35d438dc58f0d9d, + 0x0a78eb28f5c70b3d, + 0x666ea36f7879462c, + 0x0e0a77c19a07df2f, +]); + +/// R^2 = 2^512 mod q +const R2: Fq = Fq([ + 0xf32cfc5b538afa89, + 0xb5e71911d44501fb, + 0x47ab1eff0a417ff6, + 0x06d89f71cab8351f, +]); + +/// R^3 = 2^768 mod q +const R3: Fq = Fq([ + 0xb1cd6dafda1530df, + 0x62f210e6a7283db6, + 0xef7f0b0c0ada0afb, + 0x20fd6e902d592544, +]); + +pub const NEGATIVE_ONE: Fq = Fq([ + 0x68c3488912edefaa, + 0x8d087f6872aabf4f, + 0x51e1a24709081231, + 0x2259d6b14729c0fa, +]); + +const MODULUS_STR: &str = "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"; + +const TWO_INV: Fq = Fq::from_raw([ + 0x9e10460b6c3e7ea4, + 0xcbc0b548b438e546, + 0xdc2822db40c0ac2e, + 0x183227397098d014, +]); + +// Unused constant for base field +const ROOT_OF_UNITY_INV: Fq = Fq::zero(); + +// Unused constant for base field +const DELTA: Fq = Fq::zero(); + +/// `ZETA^3 = 1 mod r` where `ZETA^2 != 1 mod r` +const ZETA: Fq = Fq::from_raw([ + 0x5763473177fffffeu64, + 0xd4f263f1acdb5c4fu64, + 0x59e26bcea0d48bacu64, + 0x0u64, +]); + +use crate::{ + field_arithmetic, field_common, field_specific, impl_add_binop_specify_output, + impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, +}; +impl_binops_additive!(Fq, Fq); +impl_binops_multiplicative!(Fq, Fq); +#[cfg(not(feature = "asm"))] +field_common!( + Fq, + MODULUS, + INV, + MODULUS_STR, + TWO_INV, + ROOT_OF_UNITY_INV, + DELTA, + ZETA, + R, + R2, + R3 +); +#[cfg(not(feature = "asm"))] +field_arithmetic!(Fq, MODULUS, INV, sparse); +#[cfg(feature = "asm")] +assembly_field!( + Fq, + MODULUS, + INV, + MODULUS_STR, + TWO_INV, + ROOT_OF_UNITY_INV, + DELTA, + ZETA, + R, + R2, + R3 +); + +impl Fq { + pub const fn size() -> usize { + 32 + } + + pub fn legendre(&self) -> LegendreSymbol { + // s = self^((modulus - 1) // 2) + // 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3 + let s = &[ + 0x9e10460b6c3e7ea3u64, + 0xcbc0b548b438e546u64, + 0xdc2822db40c0ac2eu64, + 0x183227397098d014u64, + ]; + let s = self.pow(s); + if s == Self::zero() { + LegendreSymbol::Zero + } else if s == Self::one() { + LegendreSymbol::QuadraticResidue + } else { + LegendreSymbol::QuadraticNonResidue + } + } +} + +impl ff::Field for Fq { + fn random(mut rng: impl RngCore) -> Self { + let mut random_bytes = [0; 64]; + rng.fill_bytes(&mut random_bytes[..]); + + Self::from_bytes_wide(&random_bytes) + } + + #[inline(always)] + fn zero() -> Self { + Self::zero() + } + + #[inline(always)] + fn one() -> Self { + Self::one() + } + + fn double(&self) -> Self { + self.double() + } + + #[inline(always)] + fn square(&self) -> Self { + self.square() + } + + /// Computes the square root of this element, if it exists. + fn sqrt(&self) -> CtOption { + let tmp = self.pow(&[ + 0x4f082305b61f3f52, + 0x65e05aa45a1c72a3, + 0x6e14116da0605617, + 0x0c19139cb84c680a, + ]); + + CtOption::new(tmp, tmp.square().ct_eq(self)) + } + + /// Computes the multiplicative inverse of this element, + /// failing if the element is zero. + fn invert(&self) -> CtOption { + let tmp = self.pow(&[ + 0x3c208c16d87cfd45, + 0x97816a916871ca8d, + 0xb85045b68181585d, + 0x30644e72e131a029, + ]); + + CtOption::new(tmp, !self.ct_eq(&Self::zero())) + } +} + +impl ff::PrimeField for Fq { + type Repr = [u8; 32]; + + const NUM_BITS: u32 = 254; + const CAPACITY: u32 = 253; + + const S: u32 = 0; + + fn from_repr(repr: Self::Repr) -> CtOption { + let mut tmp = Fq([0, 0, 0, 0]); + + tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); + tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); + tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); + tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); + + // Try to subtract the modulus + let (_, borrow) = tmp.0[0].overflowing_sub(MODULUS.0[0]); + let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow); + let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow); + let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow); + + // If the element is smaller than MODULUS then the + // subtraction will underflow, producing a borrow value + // of 0xffff...ffff. Otherwise, it'll be zero. + let is_some = (borrow as u8) & 1; + + // Convert to Montgomery form by computing + // (a.R^0 * R^2) / R = a.R + tmp *= &R2; + + CtOption::new(tmp, Choice::from(is_some)) + } + + fn to_repr(&self) -> Self::Repr { + // Turn into canonical form by computing + // (a.R) / R = a + #[cfg(feature = "asm")] + let tmp = + Self::montgomery_reduce(&[self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0]); + + #[cfg(not(feature = "asm"))] + let tmp = Self::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]); + + let mut res = [0; 32]; + res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes()); + res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes()); + res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes()); + res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes()); + + res + } + + fn is_odd(&self) -> Choice { + Choice::from(self.to_repr()[0] & 1) + } + + fn multiplicative_generator() -> Self { + unimplemented!() + } + + fn root_of_unity() -> Self { + unimplemented!() + } +} + +impl SqrtRatio for Fq { + const T_MINUS1_OVER2: [u64; 4] = [0, 0, 0, 0]; + + fn get_lower_32(&self) -> u32 { + #[cfg(not(feature = "asm"))] + let tmp = Fq::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]); + + #[cfg(feature = "asm")] + let tmp = Fq::montgomery_reduce(&[self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0]); + + tmp.0[0] as u32 + } +} + +#[cfg(test)] +mod test { + use super::*; + use ff::Field; + use rand_core::OsRng; + + #[test] + fn test_sqrt_fq() { + let v = (Fq::TWO_INV).square().sqrt().unwrap(); + assert!(v == Fq::TWO_INV || (-v) == Fq::TWO_INV); + + for _ in 0..10000 { + let a = Fq::random(OsRng); + let mut b = a; + b = b.square(); + assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); + + let b = b.sqrt().unwrap(); + let mut negb = b; + negb = negb.neg(); + + assert!(a == b || a == negb); + } + + let mut c = Fq::one(); + for _ in 0..10000 { + let mut b = c; + b = b.square(); + assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); + + b = b.sqrt().unwrap(); + + if b != c { + b = b.neg(); + } + + assert_eq!(b, c); + + c += &Fq::one(); + } + } + + #[test] + fn test_from_u512() { + assert_eq!( + Fq::from_raw([ + 0x1f8905a172affa8a, + 0xde45ad177dcf3306, + 0xaaa7987907d73ae2, + 0x24d349431d468e30, + ]), + Fq::from_u512([ + 0xaaaaaaaaaaaaaaaa, + 0xaaaaaaaaaaaaaaaa, + 0xaaaaaaaaaaaaaaaa, + 0xaaaaaaaaaaaaaaaa, + 0xaaaaaaaaaaaaaaaa, + 0xaaaaaaaaaaaaaaaa, + 0xaaaaaaaaaaaaaaaa, + 0xaaaaaaaaaaaaaaaa + ]) + ); + } + + #[test] + fn test_field() { + crate::tests::field::random_field_tests::("fq".to_string()); + } + + #[test] + fn test_serialization() { + crate::tests::field::random_serialization_test::("fq".to_string()); + } +} diff --git a/arithmetic/curves/src/bn256/fq12.rs b/arithmetic/curves/src/bn256/fq12.rs new file mode 100644 index 0000000000..d98c7c0c9f --- /dev/null +++ b/arithmetic/curves/src/bn256/fq12.rs @@ -0,0 +1,592 @@ +use super::fq::Fq; +use super::fq2::Fq2; +use super::fq6::Fq6; +use core::ops::{Add, Mul, Neg, Sub}; +use ff::Field; +use rand::RngCore; +use serde::{Deserialize, Serialize}; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Hash, Serialize, Deserialize)] +pub struct Fq12 { + pub c0: Fq6, + pub c1: Fq6, +} + +impl ConditionallySelectable for Fq12 { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Fq12 { + c0: Fq6::conditional_select(&a.c0, &b.c0, choice), + c1: Fq6::conditional_select(&a.c1, &b.c1, choice), + } + } +} + +impl ConstantTimeEq for Fq12 { + fn ct_eq(&self, other: &Self) -> Choice { + self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) + } +} + +impl Neg for Fq12 { + type Output = Fq12; + + #[inline] + fn neg(self) -> Fq12 { + -&self + } +} + +impl<'a> Neg for &'a Fq12 { + type Output = Fq12; + + #[inline] + fn neg(self) -> Fq12 { + self.neg() + } +} + +impl<'a, 'b> Sub<&'b Fq12> for &'a Fq12 { + type Output = Fq12; + + #[inline] + fn sub(self, rhs: &'b Fq12) -> Fq12 { + self.sub(rhs) + } +} + +impl<'a, 'b> Add<&'b Fq12> for &'a Fq12 { + type Output = Fq12; + + #[inline] + fn add(self, rhs: &'b Fq12) -> Fq12 { + self.add(rhs) + } +} + +impl<'a, 'b> Mul<&'b Fq12> for &'a Fq12 { + type Output = Fq12; + + #[inline] + fn mul(self, rhs: &'b Fq12) -> Fq12 { + self.mul(rhs) + } +} + +use crate::{ + impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, + impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, +}; +impl_binops_additive!(Fq12, Fq12); +impl_binops_multiplicative!(Fq12, Fq12); + +impl Fq12 { + pub fn mul_assign(&mut self, other: &Self) { + let t0 = self.c0 * other.c0; + let mut t1 = self.c1 * other.c1; + let t2 = other.c0 + other.c1; + + self.c1 += &self.c0; + self.c1 *= &t2; + self.c1 -= &t0; + self.c1 -= &t1; + + t1.mul_by_nonresidue(); + self.c0 = t0 + t1; + } + + pub fn square_assign(&mut self) { + let mut ab = self.c0 * self.c1; + + let c0c1 = self.c0 + self.c1; + + let mut c0 = self.c1; + c0.mul_by_nonresidue(); + c0 += &self.c0; + c0 *= &c0c1; + c0 -= &ab; + self.c1 = ab; + self.c1 += &ab; + ab.mul_by_nonresidue(); + c0 -= &ab; + self.c0 = c0; + } + + pub fn double(&self) -> Self { + Self { + c0: self.c0.double(), + c1: self.c1.double(), + } + } + + pub fn double_assign(&mut self) { + self.c0 = self.c0.double(); + self.c1 = self.c1.double(); + } + + pub fn add(&self, other: &Self) -> Self { + Self { + c0: self.c0 + other.c0, + c1: self.c1 + other.c1, + } + } + + pub fn sub(&self, other: &Self) -> Self { + Self { + c0: self.c0 - other.c0, + c1: self.c1 - other.c1, + } + } + + pub fn mul(&self, other: &Self) -> Self { + let mut t = *other; + t.mul_assign(self); + t + } + + pub fn square(&self) -> Self { + let mut t = *self; + t.square_assign(); + t + } + + #[inline(always)] + pub fn neg(&self) -> Self { + Self { + c0: -self.c0, + c1: -self.c1, + } + } + + #[inline(always)] + pub fn conjugate(&mut self) { + self.c1 = -self.c1; + } + + // pub fn conjugate(&self) -> Self { + // Self { + // c0: self.c0, + // c1: -self.c1, + // } + // } + + pub fn frobenius_map(&mut self, power: usize) { + self.c0.frobenius_map(power); + self.c1.frobenius_map(power); + + self.c1.c0.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]); + self.c1.c1.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]); + self.c1.c2.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]); + } + + pub fn mul_by_014(&mut self, c0: &Fq2, c1: &Fq2, c4: &Fq2) { + let mut aa = self.c0; + aa.mul_by_01(c0, c1); + let mut bb = self.c1; + bb.mul_by_1(c4); + let o = c1 + c4; + self.c1 += &self.c0; + self.c1.mul_by_01(c0, &o); + self.c1 -= &aa; + self.c1 -= &bb; + self.c0 = bb; + self.c0.mul_by_nonresidue(); + self.c0 += &aa; + } + + pub fn mul_by_034(&mut self, c0: &Fq2, c3: &Fq2, c4: &Fq2) { + let t0 = Fq6 { + c0: self.c0.c0 * c0, + c1: self.c0.c1 * c0, + c2: self.c0.c2 * c0, + }; + let mut t1 = self.c1; + t1.mul_by_01(c3, c4); + let o = c0 + c3; + let mut t2 = self.c0 + self.c1; + t2.mul_by_01(&o, c4); + t2 -= t0; + self.c1 = t2 - t1; + t1.mul_by_nonresidue(); + self.c0 = t0 + t1; + } + + pub fn invert(&self) -> CtOption { + let mut c0s = self.c0; + c0s.square_assign(); + let mut c1s = self.c1; + c1s.square_assign(); + c1s.mul_by_nonresidue(); + c0s -= &c1s; + + c0s.invert().map(|t| { + let mut tmp = Fq12 { c0: t, c1: t }; + tmp.c0.mul_assign(&self.c0); + tmp.c1.mul_assign(&self.c1); + tmp.c1 = tmp.c1.neg(); + + tmp + }) + } + + pub fn cyclotomic_square(&mut self) { + fn fp4_square(c0: &mut Fq2, c1: &mut Fq2, a0: &Fq2, a1: &Fq2) { + let t0 = a0.square(); + let t1 = a1.square(); + let mut t2 = t1; + t2.mul_by_nonresidue(); + *c0 = t2 + t0; + t2 = a0 + a1; + t2.square_assign(); + t2 -= t0; + *c1 = t2 - t1; + } + + let mut t3 = Fq2::zero(); + let mut t4 = Fq2::zero(); + let mut t5 = Fq2::zero(); + let mut t6 = Fq2::zero(); + + fp4_square(&mut t3, &mut t4, &self.c0.c0, &self.c1.c1); + let mut t2 = t3 - self.c0.c0; + t2.double_assign(); + self.c0.c0 = t2 + t3; + + t2 = t4 + self.c1.c1; + t2.double_assign(); + self.c1.c1 = t2 + t4; + + fp4_square(&mut t3, &mut t4, &self.c1.c0, &self.c0.c2); + fp4_square(&mut t5, &mut t6, &self.c0.c1, &self.c1.c2); + + t2 = t3 - self.c0.c1; + t2.double_assign(); + self.c0.c1 = t2 + t3; + t2 = t4 + self.c1.c2; + t2.double_assign(); + self.c1.c2 = t2 + t4; + t3 = t6; + t3.mul_by_nonresidue(); + t2 = t3 + self.c1.c0; + t2.double_assign(); + self.c1.c0 = t2 + t3; + t2 = t5 - self.c0.c2; + t2.double_assign(); + self.c0.c2 = t2 + t5; + } +} + +impl Field for Fq12 { + fn random(mut rng: impl RngCore) -> Self { + Fq12 { + c0: Fq6::random(&mut rng), + c1: Fq6::random(&mut rng), + } + } + + fn zero() -> Self { + Fq12 { + c0: Fq6::zero(), + c1: Fq6::zero(), + } + } + + fn one() -> Self { + Fq12 { + c0: Fq6::one(), + c1: Fq6::zero(), + } + } + + fn is_zero(&self) -> Choice { + self.c0.is_zero() & self.c1.is_zero() + } + + fn square(&self) -> Self { + self.square() + } + + fn double(&self) -> Self { + self.double() + } + + fn sqrt(&self) -> CtOption { + unimplemented!() + } + + fn invert(&self) -> CtOption { + self.invert() + } +} + +// non_residue^((modulus^i-1)/6) for i=0,...,11 +pub const FROBENIUS_COEFF_FQ12_C1: [Fq2; 12] = [ + // Fq2(u + 9)**(((q^0) - 1) / 6) + // Fq points are represented in Montgomery form with R = 2^256 + Fq2 { + c0: Fq([ + 0xd35d438dc58f0d9d, + 0x0a78eb28f5c70b3d, + 0x666ea36f7879462c, + 0x0e0a77c19a07df2f, + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0]), + }, + // Fq2(u + 9)**(((q^1) - 1) / 6) + Fq2 { + c0: Fq([ + 0xaf9ba69633144907, + 0xca6b1d7387afb78a, + 0x11bded5ef08a2087, + 0x02f34d751a1f3a7c, + ]), + c1: Fq([ + 0xa222ae234c492d72, + 0xd00f02a4565de15b, + 0xdc2ff3a253dfc926, + 0x10a75716b3899551, + ]), + }, + // Fq2(u + 9)**(((q^2) - 1) / 6) + Fq2 { + c0: Fq([ + 0xca8d800500fa1bf2, + 0xf0c5d61468b39769, + 0x0e201271ad0d4418, + 0x04290f65bad856e6, + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0]), + }, + // Fq2(u + 9)**(((q^3) - 1) / 6) + Fq2 { + c0: Fq([ + 0x365316184e46d97d, + 0x0af7129ed4c96d9f, + 0x659da72fca1009b5, + 0x08116d8983a20d23, + ]), + c1: Fq([ + 0xb1df4af7c39c1939, + 0x3d9f02878a73bf7f, + 0x9b2220928caf0ae0, + 0x26684515eff054a6, + ]), + }, + // Fq2(u + 9)**(((q^4) - 1) / 6) + Fq2 { + c0: Fq([ + 0x3350c88e13e80b9c, + 0x7dce557cdb5e56b9, + 0x6001b4b8b615564a, + 0x2682e617020217e0, + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0]), + }, + // Fq2(u + 9)**(((q^5) - 1) / 6) + Fq2 { + c0: Fq([ + 0x86b76f821b329076, + 0x408bf52b4d19b614, + 0x53dfb9d0d985e92d, + 0x051e20146982d2a7, + ]), + c1: Fq([ + 0x0fbc9cd47752ebc7, + 0x6d8fffe33415de24, + 0xbef22cf038cf41b9, + 0x15c0edff3c66bf54, + ]), + }, + // Fq2(u + 9)**(((q^6) - 1) / 6) + Fq2 { + c0: Fq([ + 0x68c3488912edefaa, + 0x8d087f6872aabf4f, + 0x51e1a24709081231, + 0x2259d6b14729c0fa, + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0]), + }, + // Fq2(u + 9)**(((q^7) - 1) / 6) + Fq2 { + c0: Fq([ + 0x8c84e580a568b440, + 0xcd164d1de0c21302, + 0xa692585790f737d5, + 0x2d7100fdc71265ad, + ]), + c1: Fq([ + 0x99fdddf38c33cfd5, + 0xc77267ed1213e931, + 0xdc2052142da18f36, + 0x1fbcf75c2da80ad7, + ]), + }, + // Fq2(u + 9)**(((q^8) - 1) / 6) + Fq2 { + c0: Fq([ + 0x71930c11d782e155, + 0xa6bb947cffbe3323, + 0xaa303344d4741444, + 0x2c3b3f0d26594943, + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0]), + }, + // Fq2(u + 9)**(((q^9) - 1) / 6) + Fq2 { + c0: Fq([ + 0x05cd75fe8a3623ca, + 0x8c8a57f293a85cee, + 0x52b29e86b7714ea8, + 0x2852e0e95d8f9306, + ]), + c1: Fq([ + 0x8a41411f14e0e40e, + 0x59e26809ddfe0b0d, + 0x1d2e2523f4d24d7d, + 0x09fc095cf1414b83, + ]), + }, + // Fq2(u + 9)**(((q^10) - 1) / 6) + Fq2 { + c0: Fq([ + 0x08cfc388c494f1ab, + 0x19b315148d1373d4, + 0x584e90fdcb6c0213, + 0x09e1685bdf2f8849, + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0]), + }, + // Fq2(u + 9)**(((q^11) - 1) / 6) + Fq2 { + c0: Fq([ + 0xb5691c94bd4a6cd1, + 0x56f575661b581478, + 0x64708be5a7fb6f30, + 0x2b462e5e77aecd82, + ]), + c1: Fq([ + 0x2c63ef42612a1180, + 0x29f16aae345bec69, + 0xf95e18c648b216a4, + 0x1aa36073a4cae0d4, + ]), + }, +]; + +#[cfg(test)] +use rand::SeedableRng; +#[cfg(test)] +use rand_xorshift::XorShiftRng; + +#[test] +fn test_fq12_mul_by_014() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let c0 = Fq2::random(&mut rng); + let c1 = Fq2::random(&mut rng); + let c5 = Fq2::random(&mut rng); + let mut a = Fq12::random(&mut rng); + let mut b = a; + + a.mul_by_014(&c0, &c1, &c5); + b.mul_assign(&Fq12 { + c0: Fq6 { + c0, + c1, + c2: Fq2::zero(), + }, + c1: Fq6 { + c0: Fq2::zero(), + c1: c5, + c2: Fq2::zero(), + }, + }); + + assert_eq!(a, b); + } +} + +#[test] +fn test_fq12_mul_by_034() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let c0 = Fq2::random(&mut rng); + let c3 = Fq2::random(&mut rng); + let c4 = Fq2::random(&mut rng); + let mut a = Fq12::random(&mut rng); + let mut b = a; + + a.mul_by_034(&c0, &c3, &c4); + b.mul_assign(&Fq12 { + c0: Fq6 { + c0, + c1: Fq2::zero(), + c2: Fq2::zero(), + }, + c1: Fq6 { + c0: c3, + c1: c4, + c2: Fq2::zero(), + }, + }); + + assert_eq!(a, b); + } +} + +#[test] +fn test_squaring() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let mut a = Fq12::random(&mut rng); + let mut b = a; + b.mul_assign(&a); + a.square_assign(); + assert_eq!(a, b); + } +} + +#[test] +fn test_frobenius() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..100 { + for i in 0..14 { + let mut a = Fq12::random(&mut rng); + let mut b = a; + + for _ in 0..i { + a = a.pow_vartime([ + 0x3c208c16d87cfd47, + 0x97816a916871ca8d, + 0xb85045b68181585d, + 0x30644e72e131a029, + ]); + } + b.frobenius_map(i); + + assert_eq!(a, b); + } + } +} + +#[test] +fn test_field() { + crate::tests::field::random_field_tests::("fq12".to_string()); +} diff --git a/arithmetic/curves/src/bn256/fq2.rs b/arithmetic/curves/src/bn256/fq2.rs new file mode 100644 index 0000000000..c362669da0 --- /dev/null +++ b/arithmetic/curves/src/bn256/fq2.rs @@ -0,0 +1,841 @@ +use super::fq::{Fq, NEGATIVE_ONE}; +use super::LegendreSymbol; +use core::convert::TryInto; +use core::ops::{Add, Mul, Neg, Sub}; +use ff::Field; +use pasta_curves::arithmetic::{FieldExt, Group, SqrtRatio}; +use rand::RngCore; +use serde::{Deserialize, Serialize}; +use std::cmp::Ordering; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +/// An element of Fq2, represented by c0 + c1 * u. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] +pub struct Fq2 { + pub c0: Fq, + pub c1: Fq, +} + +/// `Fq2` elements are ordered lexicographically. +impl Ord for Fq2 { + #[inline(always)] + fn cmp(&self, other: &Fq2) -> Ordering { + match self.c1.cmp(&other.c1) { + Ordering::Greater => Ordering::Greater, + Ordering::Less => Ordering::Less, + Ordering::Equal => self.c0.cmp(&other.c0), + } + } +} + +impl PartialOrd for Fq2 { + #[inline(always)] + fn partial_cmp(&self, other: &Fq2) -> Option { + Some(self.cmp(other)) + } +} + +impl ConditionallySelectable for Fq2 { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Fq2 { + c0: Fq::conditional_select(&a.c0, &b.c0, choice), + c1: Fq::conditional_select(&a.c1, &b.c1, choice), + } + } +} + +impl ConstantTimeEq for Fq2 { + fn ct_eq(&self, other: &Self) -> Choice { + self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) + } +} + +impl Default for Fq2 { + #[inline] + fn default() -> Self { + Self::zero() + } +} + +impl From for [u8; 64] { + fn from(value: Fq2) -> [u8; 64] { + value.to_bytes() + } +} + +impl<'a> From<&'a Fq2> for [u8; 64] { + fn from(value: &'a Fq2) -> [u8; 64] { + value.to_bytes() + } +} + +impl Neg for Fq2 { + type Output = Fq2; + + #[inline] + fn neg(self) -> Fq2 { + -&self + } +} + +impl<'a> Neg for &'a Fq2 { + type Output = Fq2; + + #[inline] + fn neg(self) -> Fq2 { + self.neg() + } +} + +impl<'a, 'b> Sub<&'b Fq2> for &'a Fq2 { + type Output = Fq2; + + #[inline] + fn sub(self, rhs: &'b Fq2) -> Fq2 { + self.sub(rhs) + } +} + +impl<'a, 'b> Add<&'b Fq2> for &'a Fq2 { + type Output = Fq2; + + #[inline] + fn add(self, rhs: &'b Fq2) -> Fq2 { + self.add(rhs) + } +} + +impl<'a, 'b> Mul<&'b Fq2> for &'a Fq2 { + type Output = Fq2; + + #[inline] + fn mul(self, rhs: &'b Fq2) -> Fq2 { + self.mul(rhs) + } +} + +use crate::{ + impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, + impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, +}; +impl_binops_additive!(Fq2, Fq2); +impl_binops_multiplicative!(Fq2, Fq2); + +impl Fq2 { + pub const fn new(c0: Fq, c1: Fq) -> Self { + Fq2 { c0, c1 } + } + + pub const fn size() -> usize { + 64 + } + /// Attempts to convert a little-endian byte representation of + /// a scalar into a `Fq`, failing if the input is not canonical. + pub fn from_bytes(bytes: &[u8; 64]) -> CtOption { + let c0 = Fq::from_bytes(bytes[0..32].try_into().unwrap()); + let c1 = Fq::from_bytes(bytes[32..64].try_into().unwrap()); + CtOption::new( + Fq2 { + c0: c0.unwrap(), + c1: c1.unwrap(), + }, + c0.is_some() & c1.is_some(), + ) + } + + /// Converts an element of `Fq` into a byte representation in + /// little-endian byte order. + pub fn to_bytes(&self) -> [u8; 64] { + let mut res = [0u8; 64]; + let c0_bytes = self.c0.to_bytes(); + let c1_bytes = self.c1.to_bytes(); + res[0..32].copy_from_slice(&c0_bytes[..]); + res[32..64].copy_from_slice(&c1_bytes[..]); + res + } + + pub fn legendre(&self) -> LegendreSymbol { + self.norm().legendre() + } + + pub fn mul_assign(&mut self, other: &Self) { + let mut t1 = self.c0 * other.c0; + let mut t0 = self.c0 + self.c1; + let t2 = self.c1 * other.c1; + self.c1 = other.c0 + other.c1; + self.c0 = t1 - t2; + t1 += t2; + t0 *= self.c1; + self.c1 = t0 - t1; + } + + pub fn square_assign(&mut self) { + let ab = self.c0 * self.c1; + let c0c1 = self.c0 + self.c1; + let mut c0 = -self.c1; + c0 += self.c0; + c0 *= c0c1; + c0 -= ab; + self.c1 = ab.double(); + self.c0 = c0 + ab; + } + + pub fn double(&self) -> Self { + Self { + c0: self.c0.double(), + c1: self.c1.double(), + } + } + + pub fn double_assign(&mut self) { + self.c0 = self.c0.double(); + self.c1 = self.c1.double(); + } + + pub fn add(&self, other: &Self) -> Self { + Self { + c0: self.c0.add(&other.c0), + c1: self.c1.add(&other.c1), + } + } + + pub fn sub(&self, other: &Self) -> Self { + Self { + c0: self.c0.sub(&other.c0), + c1: self.c1.sub(&other.c1), + } + } + + pub fn mul(&self, other: &Self) -> Self { + let mut t = *other; + t.mul_assign(self); + t + } + + pub fn square(&self) -> Self { + let mut t = *self; + t.square_assign(); + t + } + + pub fn neg(&self) -> Self { + Self { + c0: self.c0.neg(), + c1: self.c1.neg(), + } + } + + // conjucate by negating c1 + pub fn conjugate(&mut self) { + self.c1 = -self.c1; + } + + pub fn frobenius_map(&mut self, power: usize) { + self.c1 *= &FROBENIUS_COEFF_FQ2_C1[power % 2]; + } + + /// Multiply this element by quadratic nonresidue 9 + u. + pub fn mul_by_nonresidue(&mut self) { + // (xi+y)(i+9) = (9x+y)i+(9y-x) + let t0 = self.c0; + let t1 = self.c1; + + // 8*x*i + 8*y + self.double_assign(); + self.double_assign(); + self.double_assign(); + + // 9*y + self.c0 += &t0; + // (9*y - x) + self.c0 -= &t1; + + // (9*x)i + self.c1 += &t1; + // (9*x + y) + self.c1 += &t0; + } + + // Multiply this element by ξ where ξ=i+9 + pub fn mul_by_xi(&mut self) { + // (xi+y)(i+9) = (9x+y)i+(9y-x) + let t0 = self.c0; + let t1 = self.c1; + + // 8*x*i + 8*y + self.double_assign(); + self.double_assign(); + self.double_assign(); + + // 9*y + self.c0 += &t0; + // (9*y - x) + self.c0 -= &t1; + + // (9*x)i + self.c1 += &t1; + // (9*x + y) + self.c1 += &t0; + } + + /// Norm of Fq2 as extension field in i over Fq + pub fn norm(&self) -> Fq { + let mut t0 = self.c0; + let mut t1 = self.c1; + t0 = t0.square(); + t1 = t1.square(); + t1 + t0 + } + + pub fn invert(&self) -> CtOption { + let mut t1 = self.c1; + t1 = t1.square(); + let mut t0 = self.c0; + t0 = t0.square(); + t0 += &t1; + t0.invert().map(|t| { + let mut tmp = Fq2 { + c0: self.c0, + c1: self.c1, + }; + tmp.c0 *= &t; + tmp.c1 *= &t; + tmp.c1 = -tmp.c1; + + tmp + }) + } +} + +impl Field for Fq2 { + fn random(mut rng: impl RngCore) -> Self { + Fq2 { + c0: Fq::random(&mut rng), + c1: Fq::random(&mut rng), + } + } + + fn zero() -> Self { + Fq2 { + c0: Fq::zero(), + c1: Fq::zero(), + } + } + + fn one() -> Self { + Fq2 { + c0: Fq::one(), + c1: Fq::zero(), + } + } + + fn is_zero(&self) -> Choice { + self.c0.is_zero() & self.c1.is_zero() + } + + fn square(&self) -> Self { + self.square() + } + + fn double(&self) -> Self { + self.double() + } + + fn sqrt(&self) -> CtOption { + // Algorithm 9, https://eprint.iacr.org/2012/685.pdf + + if self.is_zero().into() { + CtOption::new(Self::zero(), Choice::from(1)) + } else { + // a1 = self^((q - 3) / 4) + // 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f51 + let u: [u64; 4] = [ + 0x4f082305b61f3f51, + 0x65e05aa45a1c72a3, + 0x6e14116da0605617, + 0x0c19139cb84c680a, + ]; + let mut a1 = self.pow(&u); + let mut alpha = a1; + + alpha.square_assign(); + alpha.mul_assign(self); + let mut a0 = alpha; + a0.frobenius_map(1); + a0.mul_assign(&alpha); + + let neg1 = Fq2 { + c0: NEGATIVE_ONE, + c1: Fq::zero(), + }; + + if a0 == neg1 { + CtOption::new(a0, Choice::from(0)) + } else { + a1.mul_assign(self); + + if alpha == neg1 { + a1.mul_assign(&Fq2 { + c0: Fq::zero(), + c1: Fq::one(), + }); + } else { + alpha += &Fq2::one(); + // alpha = alpha^((q - 1) / 2) + // 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3 + let u: [u64; 4] = [ + 0x9e10460b6c3e7ea3, + 0xcbc0b548b438e546, + 0xdc2822db40c0ac2e, + 0x183227397098d014, + ]; + alpha = alpha.pow(&u); + a1.mul_assign(&alpha); + } + CtOption::new(a1, Choice::from(1)) + } + } + } + + fn invert(&self) -> CtOption { + self.invert() + } +} + +impl From for Fq2 { + fn from(bit: bool) -> Fq2 { + if bit { + Fq2::one() + } else { + Fq2::zero() + } + } +} + +impl From for Fq2 { + fn from(val: u64) -> Self { + Fq2 { + c0: Fq::from(val), + c1: Fq::zero(), + } + } +} + +impl FieldExt for Fq2 { + const MODULUS: &'static str = + "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47"; + + const ROOT_OF_UNITY_INV: Self = Fq2 { + c0: Fq::zero(), + c1: Fq::zero(), + }; + const DELTA: Self = Fq2 { + c0: Fq::zero(), + c1: Fq::zero(), + }; + const TWO_INV: Self = Fq2 { + c0: Fq::from_raw([ + 0x9e10460b6c3e7ea4, + 0xcbc0b548b438e546, + 0xdc2822db40c0ac2e, + 0x183227397098d014, + ]), + c1: Fq([0, 0, 0, 0]), + }; + const ZETA: Self = Fq2 { + c0: Fq::zero(), + c1: Fq::zero(), + }; + + /// Converts a 512-bit little endian integer into + /// a `Fq` by reducing by the modulus. + fn from_bytes_wide(bytes: &[u8; 64]) -> Self { + Self::new(Fq::from_bytes_wide(bytes), Fq::zero()) + } + + fn from_u128(v: u128) -> Self { + Fq2 { + c0: Fq::from_raw([v as u64, (v >> 64) as u64, 0, 0]), + c1: Fq::zero(), + } + } + + fn get_lower_128(&self) -> u128 { + self.c0.get_lower_128() + } + + // /// Writes this element in its normalized, little endian form into a buffer. + // fn write(&self, writer: &mut W) -> io::Result<()> { + // let compressed = self.to_bytes(); + // writer.write_all(&compressed[..]) + // } + + // /// Reads a normalized, little endian represented field element from a + // /// buffer. + // fn read(reader: &mut R) -> io::Result { + // let mut compressed = [0u8; 64]; + // reader.read_exact(&mut compressed[..])?; + // Option::from(Self::from_bytes(&compressed)) + // .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point encoding in proof")) + // } +} + +impl SqrtRatio for Fq2 { + const T_MINUS1_OVER2: [u64; 4] = [0, 0, 0, 0]; + + fn pow_by_t_minus1_over2(&self) -> Self { + unimplemented!(); + } + + fn get_lower_32(&self) -> u32 { + unimplemented!(); + } + + #[cfg(feature = "sqrt-table")] + fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { + unimplemented!(); + } + + #[cfg(feature = "sqrt-table")] + fn sqrt_alt(&self) -> (Choice, Self) { + unimplemented!(); + } +} + +impl Group for Fq2 { + type Scalar = Fq2; + + fn group_zero() -> Self { + Self::zero() + } + fn group_add(&mut self, rhs: &Self) { + *self += *rhs; + } + fn group_sub(&mut self, rhs: &Self) { + *self -= *rhs; + } + fn group_scale(&mut self, by: &Self::Scalar) { + *self *= *by; + } +} + +#[derive(Clone, Copy, Debug)] +pub struct Fq2Bytes([u8; 64]); + +impl Default for Fq2Bytes { + fn default() -> Self { + Self([0u8; 64]) + } +} + +impl AsMut<[u8]> for Fq2Bytes { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +impl AsRef<[u8]> for Fq2Bytes { + fn as_ref(&self) -> &[u8] { + &self.0 + } +} + +impl ff::PrimeField for Fq2 { + type Repr = Fq2Bytes; + + const NUM_BITS: u32 = 254; + const CAPACITY: u32 = 253; + + const S: u32 = 0; + + fn from_repr(repr: Self::Repr) -> CtOption { + let c0 = Fq::from_bytes(&repr.0[..32].try_into().unwrap()); + let c1 = Fq::from_bytes(&repr.0[32..].try_into().unwrap()); + // Disallow overflow representation + CtOption::new(Fq2::new(c0.unwrap(), c1.unwrap()), Choice::from(1)) + } + + fn to_repr(&self) -> Self::Repr { + Fq2Bytes(self.to_bytes()) + } + + fn is_odd(&self) -> Choice { + Choice::from(self.to_repr().as_ref()[0] & 1) + } + + fn multiplicative_generator() -> Self { + unimplemented!() + } + + fn root_of_unity() -> Self { + unimplemented!() + } +} + +impl crate::serde::SerdeObject for Fq2 { + fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { + debug_assert_eq!(bytes.len(), 64); + let [c0, c1] = [0, 32].map(|i| Fq::from_raw_bytes_unchecked(&bytes[i..i + 32])); + Self { c0, c1 } + } + fn from_raw_bytes(bytes: &[u8]) -> Option { + if bytes.len() != 64 { + return None; + } + let [c0, c1] = [0, 32].map(|i| Fq::from_raw_bytes(&bytes[i..i + 32])); + c0.zip(c1).map(|(c0, c1)| Self { c0, c1 }) + } + fn to_raw_bytes(&self) -> Vec { + let mut res = Vec::with_capacity(64); + for limb in self.c0.0.iter().chain(self.c1.0.iter()) { + res.extend_from_slice(&limb.to_le_bytes()); + } + res + } + fn read_raw_unchecked(reader: &mut R) -> Self { + let [c0, c1] = [(); 2].map(|_| Fq::read_raw_unchecked(reader)); + Self { c0, c1 } + } + fn read_raw(reader: &mut R) -> std::io::Result { + let c0 = Fq::read_raw(reader)?; + let c1 = Fq::read_raw(reader)?; + Ok(Self { c0, c1 }) + } + fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { + self.c0.write_raw(writer)?; + self.c1.write_raw(writer) + } +} + +pub const FROBENIUS_COEFF_FQ2_C1: [Fq; 2] = [ + // Fq(-1)**(((q^0) - 1) / 2) + // it's 1 in Montgommery form + Fq([ + 0xd35d438dc58f0d9d, + 0x0a78eb28f5c70b3d, + 0x666ea36f7879462c, + 0x0e0a77c19a07df2f, + ]), + // Fq(-1)**(((q^1) - 1) / 2) + Fq([ + 0x68c3488912edefaa, + 0x8d087f6872aabf4f, + 0x51e1a24709081231, + 0x2259d6b14729c0fa, + ]), +]; + +#[cfg(test)] +use rand::SeedableRng; +#[cfg(test)] +use rand_xorshift::XorShiftRng; + +#[test] +fn test_ser() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + let a0 = Fq2::random(&mut rng); + let a_bytes = a0.to_bytes(); + let a1 = Fq2::from_bytes(&a_bytes).unwrap(); + assert_eq!(a0, a1); +} + +#[test] +fn test_fq2_ordering() { + let mut a = Fq2 { + c0: Fq::zero(), + c1: Fq::zero(), + }; + + let mut b = a; + + assert!(a.cmp(&b) == Ordering::Equal); + b.c0 += &Fq::one(); + assert!(a.cmp(&b) == Ordering::Less); + a.c0 += &Fq::one(); + assert!(a.cmp(&b) == Ordering::Equal); + b.c1 += &Fq::one(); + assert!(a.cmp(&b) == Ordering::Less); + a.c0 += &Fq::one(); + assert!(a.cmp(&b) == Ordering::Less); + a.c1 += &Fq::one(); + assert!(a.cmp(&b) == Ordering::Greater); + b.c0 += &Fq::one(); + assert!(a.cmp(&b) == Ordering::Equal); +} + +#[test] +fn test_fq2_basics() { + assert_eq!( + Fq2 { + c0: Fq::zero(), + c1: Fq::zero(), + }, + Fq2::zero() + ); + assert_eq!( + Fq2 { + c0: Fq::one(), + c1: Fq::zero(), + }, + Fq2::one() + ); + assert_eq!(Fq2::zero().is_zero().unwrap_u8(), 1); + assert_eq!(Fq2::one().is_zero().unwrap_u8(), 0); + assert_eq!( + Fq2 { + c0: Fq::zero(), + c1: Fq::one(), + } + .is_zero() + .unwrap_u8(), + 0 + ); +} + +#[test] +fn test_fq2_squaring() { + let mut a = Fq2 { + c0: Fq::one(), + c1: Fq::one(), + }; // u + 1 + a.square_assign(); + assert_eq!( + a, + Fq2 { + c0: Fq::zero(), + c1: Fq::one() + Fq::one(), + } + ); // 2u + + let mut a = Fq2 { + c0: Fq::zero(), + c1: Fq::one(), + }; // u + a.square_assign(); + assert_eq!(a, { + let neg1 = -Fq::one(); + Fq2 { + c0: neg1, + c1: Fq::zero(), + } + }); // -1 +} + +#[test] +fn test_fq2_mul_nonresidue() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + let nine = Fq::one().double().double().double() + Fq::one(); + let nqr = Fq2 { + c0: nine, + c1: Fq::one(), + }; + + for _ in 0..1000 { + let mut a = Fq2::random(&mut rng); + let mut b = a; + a.mul_by_nonresidue(); + b.mul_assign(&nqr); + + assert_eq!(a, b); + } +} + +#[test] +fn test_fq2_legendre() { + assert_eq!(LegendreSymbol::Zero, Fq2::zero().legendre()); + // i^2 = -1 + let mut m1 = Fq2::one(); + m1 = m1.neg(); + assert_eq!(LegendreSymbol::QuadraticResidue, m1.legendre()); + m1.mul_by_nonresidue(); + assert_eq!(LegendreSymbol::QuadraticNonResidue, m1.legendre()); +} + +#[test] +pub fn test_sqrt() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..10000 { + let a = Fq2::random(&mut rng); + if a.legendre() == LegendreSymbol::QuadraticNonResidue { + assert!(bool::from(a.sqrt().is_none())); + } + } + + for _ in 0..10000 { + let a = Fq2::random(&mut rng); + let mut b = a; + b.square_assign(); + assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); + + let b = b.sqrt().unwrap(); + let mut negb = b; + negb = negb.neg(); + + assert!(a == b || a == negb); + } + + let mut c = Fq2::one(); + for _ in 0..10000 { + let mut b = c; + b.square_assign(); + assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); + + b = b.sqrt().unwrap(); + + if b != c { + b = b.neg(); + } + + assert_eq!(b, c); + + c += &Fq2::one(); + } +} + +#[test] +fn test_frobenius() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..100 { + for i in 0..14 { + let mut a = Fq2::random(&mut rng); + let mut b = a; + + for _ in 0..i { + a = a.pow(&[ + 0x3c208c16d87cfd47, + 0x97816a916871ca8d, + 0xb85045b68181585d, + 0x30644e72e131a029, + ]); + } + b.frobenius_map(i); + + assert_eq!(a, b); + } + } +} + +#[test] +fn test_field() { + crate::tests::field::random_field_tests::("fq2".to_string()); +} + +#[test] +fn test_serialization() { + crate::tests::field::random_serialization_test::("fq2".to_string()); +} diff --git a/arithmetic/curves/src/bn256/fq6.rs b/arithmetic/curves/src/bn256/fq6.rs new file mode 100644 index 0000000000..036414177f --- /dev/null +++ b/arithmetic/curves/src/bn256/fq6.rs @@ -0,0 +1,704 @@ +use super::fq::Fq; +use super::fq2::Fq2; +use core::ops::{Add, Mul, Neg, Sub}; +use ff::Field; +use rand::RngCore; +use serde::{Deserialize, Serialize}; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Hash, Serialize, Deserialize)] +pub struct Fq6 { + pub c0: Fq2, + pub c1: Fq2, + pub c2: Fq2, +} + +impl ConditionallySelectable for Fq6 { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Fq6 { + c0: Fq2::conditional_select(&a.c0, &b.c0, choice), + c1: Fq2::conditional_select(&a.c1, &b.c1, choice), + c2: Fq2::conditional_select(&a.c2, &b.c2, choice), + } + } +} + +impl ConstantTimeEq for Fq6 { + fn ct_eq(&self, other: &Self) -> Choice { + self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) & self.c2.ct_eq(&other.c2) + } +} + +impl Neg for Fq6 { + type Output = Fq6; + + #[inline] + fn neg(self) -> Fq6 { + -&self + } +} + +impl<'a> Neg for &'a Fq6 { + type Output = Fq6; + + #[inline] + fn neg(self) -> Fq6 { + self.neg() + } +} + +impl<'a, 'b> Sub<&'b Fq6> for &'a Fq6 { + type Output = Fq6; + + #[inline] + fn sub(self, rhs: &'b Fq6) -> Fq6 { + self.sub(rhs) + } +} + +impl<'a, 'b> Add<&'b Fq6> for &'a Fq6 { + type Output = Fq6; + + #[inline] + fn add(self, rhs: &'b Fq6) -> Fq6 { + self.add(rhs) + } +} + +impl<'a, 'b> Mul<&'b Fq6> for &'a Fq6 { + type Output = Fq6; + + #[inline] + fn mul(self, rhs: &'b Fq6) -> Fq6 { + self.mul(rhs) + } +} + +use crate::{ + impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, + impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, +}; +impl_binops_additive!(Fq6, Fq6); +impl_binops_multiplicative!(Fq6, Fq6); + +impl Fq6 { + pub fn mul_assign(&mut self, other: &Self) { + let mut a_a = self.c0; + let mut b_b = self.c1; + let mut c_c = self.c2; + a_a *= &other.c0; + b_b *= &other.c1; + c_c *= &other.c2; + + let mut t1 = other.c1; + t1 += &other.c2; + { + let mut tmp = self.c1; + tmp += &self.c2; + + t1 *= &tmp; + t1 -= &b_b; + t1 -= &c_c; + t1.mul_by_nonresidue(); + t1 += &a_a; + } + + let mut t3 = other.c0; + t3 += &other.c2; + { + let mut tmp = self.c0; + tmp += &self.c2; + + t3 *= &tmp; + t3 -= &a_a; + t3 += &b_b; + t3 -= &c_c; + } + + let mut t2 = other.c0; + t2 += &other.c1; + { + let mut tmp = self.c0; + tmp += &self.c1; + + t2 *= &tmp; + t2 -= &a_a; + t2 -= &b_b; + c_c.mul_by_nonresidue(); + t2 += &c_c; + } + + self.c0 = t1; + self.c1 = t2; + self.c2 = t3; + } + + pub fn square_assign(&mut self) { + // s0 = a^2 + let mut s0 = self.c0; + s0.square_assign(); + // s1 = 2ab + let mut ab = self.c0; + ab *= &self.c1; + let mut s1 = ab; + s1.double_assign(); + // s2 = (a - b + c)^2 + let mut s2 = self.c0; + s2 -= &self.c1; + s2 += &self.c2; + s2.square_assign(); + // bc + let mut bc = self.c1; + bc *= &self.c2; + // s3 = 2bc + let mut s3 = bc; + s3.double_assign(); + // s4 = c^2 + let mut s4 = self.c2; + s4.square_assign(); + + // new c0 = 2bc.mul_by_xi + a^2 + self.c0 = s3; + self.c0.mul_by_nonresidue(); + // self.c0.mul_by_xi(); + self.c0 += &s0; + + // new c1 = (c^2).mul_by_xi + 2ab + self.c1 = s4; + self.c1.mul_by_nonresidue(); + // self.c1.mul_by_xi(); + self.c1 += &s1; + + // new c2 = 2ab + (a - b + c)^2 + 2bc - a^2 - c^2 = b^2 + 2ac + self.c2 = s1; + self.c2 += &s2; + self.c2 += &s3; + self.c2 -= &s0; + self.c2 -= &s4; + } + + pub fn double(&self) -> Self { + Self { + c0: self.c0.double(), + c1: self.c1.double(), + c2: self.c2.double(), + } + } + + pub fn double_assign(&mut self) { + self.c0 = self.c0.double(); + self.c1 = self.c1.double(); + self.c2 = self.c2.double(); + } + + pub fn add(&self, other: &Self) -> Self { + Self { + c0: self.c0 + other.c0, + c1: self.c1 + other.c1, + c2: self.c2 + other.c2, + } + } + + pub fn sub(&self, other: &Self) -> Self { + Self { + c0: self.c0 - other.c0, + c1: self.c1 - other.c1, + c2: self.c2 - other.c2, + } + } + + pub fn mul(&self, other: &Self) -> Self { + let mut t = *other; + t.mul_assign(self); + t + } + + pub fn square(&self) -> Self { + let mut t = *self; + t.square_assign(); + t + } + + pub fn neg(&self) -> Self { + Self { + c0: -self.c0, + c1: -self.c1, + c2: -self.c2, + } + } + + pub fn frobenius_map(&mut self, power: usize) { + self.c0.frobenius_map(power); + self.c1.frobenius_map(power); + self.c2.frobenius_map(power); + + self.c1.mul_assign(&FROBENIUS_COEFF_FQ6_C1[power % 6]); + self.c2.mul_assign(&FROBENIUS_COEFF_FQ6_C2[power % 6]); + } + + /// Multiply by cubic nonresidue v. + pub fn mul_by_nonresidue(&mut self) { + use std::mem::swap; + swap(&mut self.c0, &mut self.c1); + swap(&mut self.c0, &mut self.c2); + // c0, c1, c2 -> c2, c0, c1 + self.c0.mul_by_nonresidue(); + } + + /// Multiply by cubic nonresidue v. + pub fn mul_by_v(&mut self) { + use std::mem::swap; + swap(&mut self.c0, &mut self.c1); + swap(&mut self.c0, &mut self.c2); + + self.c0.mul_by_xi(); + } + + pub fn mul_by_1(&mut self, c1: &Fq2) { + let mut b_b = self.c1; + b_b *= c1; + + let mut t1 = *c1; + { + let mut tmp = self.c1; + tmp += &self.c2; + + t1 *= &tmp; + t1 -= &b_b; + t1.mul_by_nonresidue(); + } + + let mut t2 = *c1; + { + let mut tmp = self.c0; + tmp += &self.c1; + + t2 *= &tmp; + t2 -= &b_b; + } + + self.c0 = t1; + self.c1 = t2; + self.c2 = b_b; + } + + pub fn mul_by_01(&mut self, c0: &Fq2, c1: &Fq2) { + let mut a_a = self.c0; + let mut b_b = self.c1; + a_a *= c0; + b_b *= c1; + + let mut t1 = *c1; + { + let mut tmp = self.c1; + tmp += &self.c2; + + t1 *= &tmp; + t1 -= &b_b; + t1.mul_by_nonresidue(); + t1 += &a_a; + } + + let mut t3 = *c0; + { + let mut tmp = self.c0; + tmp += &self.c2; + + t3 *= &tmp; + t3 -= &a_a; + t3 += &b_b; + } + + let mut t2 = *c0; + t2 += c1; + { + let mut tmp = self.c0; + tmp += &self.c1; + + t2 *= &tmp; + t2 -= &a_a; + t2 -= &b_b; + } + + self.c0 = t1; + self.c1 = t2; + self.c2 = t3; + } + + fn invert(&self) -> CtOption { + let mut c0 = self.c2; + c0.mul_by_nonresidue(); + c0 *= &self.c1; + c0 = -c0; + { + let mut c0s = self.c0; + c0s.square_assign(); + c0 += &c0s; + } + let mut c1 = self.c2; + c1.square_assign(); + c1.mul_by_nonresidue(); + { + let mut c01 = self.c0; + c01 *= &self.c1; + c1 -= &c01; + } + let mut c2 = self.c1; + c2.square_assign(); + { + let mut c02 = self.c0; + c02 *= &self.c2; + c2 -= &c02; + } + + let mut tmp1 = self.c2; + tmp1 *= &c1; + let mut tmp2 = self.c1; + tmp2 *= &c2; + tmp1 += &tmp2; + tmp1.mul_by_nonresidue(); + tmp2 = self.c0; + tmp2 *= &c0; + tmp1 += &tmp2; + + tmp1.invert().map(|t| { + let mut tmp = Fq6 { + c0: t, + c1: t, + c2: t, + }; + tmp.c0 *= &c0; + tmp.c1 *= &c1; + tmp.c2 *= &c2; + + tmp + }) + } +} + +impl Field for Fq6 { + fn random(mut rng: impl RngCore) -> Self { + Fq6 { + c0: Fq2::random(&mut rng), + c1: Fq2::random(&mut rng), + c2: Fq2::random(&mut rng), + } + } + + fn zero() -> Self { + Fq6 { + c0: Fq2::zero(), + c1: Fq2::zero(), + c2: Fq2::zero(), + } + } + + fn one() -> Self { + Fq6 { + c0: Fq2::one(), + c1: Fq2::zero(), + c2: Fq2::zero(), + } + } + + fn is_zero(&self) -> Choice { + self.c0.is_zero() & self.c1.is_zero() + } + + fn square(&self) -> Self { + self.square() + } + + fn double(&self) -> Self { + self.double() + } + + fn sqrt(&self) -> CtOption { + unimplemented!() + } + + fn invert(&self) -> CtOption { + self.invert() + } +} + +pub const FROBENIUS_COEFF_FQ6_C1: [Fq2; 6] = [ + // Fq2(u + 9)**(((q^0) - 1) / 3) + Fq2 { + c0: Fq([ + 0xd35d438dc58f0d9d, + 0x0a78eb28f5c70b3d, + 0x666ea36f7879462c, + 0x0e0a77c19a07df2f, + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0]), + }, + // Fq2(u + 9)**(((q^1) - 1) / 3) + // taken from go-ethereum and also re-calculated manually + Fq2 { + c0: Fq([ + 0xb5773b104563ab30, + 0x347f91c8a9aa6454, + 0x7a007127242e0991, + 0x1956bcd8118214ec, + ]), + c1: Fq([ + 0x6e849f1ea0aa4757, + 0xaa1c7b6d89f89141, + 0xb6e713cdfae0ca3a, + 0x26694fbb4e82ebc3, + ]), + }, + // Fq2(u + 9)**(((q^2) - 1) / 3) + // this one and other below are recalculated manually + Fq2 { + c0: Fq([ + 0x3350c88e13e80b9c, + 0x7dce557cdb5e56b9, + 0x6001b4b8b615564a, + 0x2682e617020217e0, + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0]), + }, + // Fq2(u + 9)**(((q^3) - 1) / 3) + Fq2 { + c0: Fq([ + 0xc9af22f716ad6bad, + 0xb311782a4aa662b2, + 0x19eeaf64e248c7f4, + 0x20273e77e3439f82, + ]), + c1: Fq([ + 0xacc02860f7ce93ac, + 0x3933d5817ba76b4c, + 0x69e6188b446c8467, + 0x0a46036d4417cc55, + ]), + }, + // Fq2(u + 9)**(((q^4) - 1) / 3) + Fq2 { + c0: Fq([ + 0x71930c11d782e155, + 0xa6bb947cffbe3323, + 0xaa303344d4741444, + 0x2c3b3f0d26594943, + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0]), + }, + // Fq2(u + 9)**(((q^5) - 1) / 3) + Fq2 { + c0: Fq([ + 0xf91aba2654e8e3b1, + 0x4771cb2fdc92ce12, + 0xdcb16ae0fc8bdf35, + 0x274aa195cd9d8be4, + ]), + c1: Fq([ + 0x5cfc50ae18811f8b, + 0x4bb28433cb43988c, + 0x4fd35f13c3b56219, + 0x301949bd2fc8883a, + ]), + }, +]; + +pub const FROBENIUS_COEFF_FQ6_C2: [Fq2; 6] = [ + // Fq2(u + 1)**(((2q^0) - 2) / 3) + Fq2 { + c0: Fq([ + 0xd35d438dc58f0d9d, + 0x0a78eb28f5c70b3d, + 0x666ea36f7879462c, + 0x0e0a77c19a07df2f, + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0]), + }, + // Fq2(u + 1)**(((2q^1) - 2) / 3) + Fq2 { + c0: Fq([ + 0x7361d77f843abe92, + 0xa5bb2bd3273411fb, + 0x9c941f314b3e2399, + 0x15df9cddbb9fd3ec, + ]), + c1: Fq([ + 0x5dddfd154bd8c949, + 0x62cb29a5a4445b60, + 0x37bc870a0c7dd2b9, + 0x24830a9d3171f0fd, + ]), + }, + // Fq2(u + 1)**(((2q^2) - 2) / 3) + Fq2 { + c0: Fq([ + 0x71930c11d782e155, + 0xa6bb947cffbe3323, + 0xaa303344d4741444, + 0x2c3b3f0d26594943, + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0]), + }, + // Fq2(u + 1)**(((2q^3) - 2) / 3) + Fq2 { + c0: Fq([ + 0x448a93a57b6762df, + 0xbfd62df528fdeadf, + 0xd858f5d00e9bd47a, + 0x06b03d4d3476ec58, + ]), + c1: Fq([ + 0x2b19daf4bcc936d1, + 0xa1a54e7a56f4299f, + 0xb533eee05adeaef1, + 0x170c812b84dda0b2, + ]), + }, + // Fq2(u + 1)**(((2q^4) - 2) / 3) + Fq2 { + c0: Fq([ + 0x3350c88e13e80b9c, + 0x7dce557cdb5e56b9, + 0x6001b4b8b615564a, + 0x2682e617020217e0, + ]), + c1: Fq([0x0, 0x0, 0x0, 0x0]), + }, + // Fq2(u + 1)**(((2q^5) - 2) / 3) + Fq2 { + c0: Fq([ + 0x843420f1d8dadbd6, + 0x31f010c9183fcdb2, + 0x436330b527a76049, + 0x13d47447f11adfe4, + ]), + c1: Fq([ + 0xef494023a857fa74, + 0x2a925d02d5ab101a, + 0x83b015829ba62f10, + 0x2539111d0c13aea3, + ]), + }, +]; + +#[cfg(test)] +use rand::SeedableRng; +#[cfg(test)] +use rand_xorshift::XorShiftRng; + +#[test] +fn test_fq6_mul_nonresidue() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + let nqr = Fq6 { + c0: Fq2::zero(), + c1: Fq2::one(), + c2: Fq2::zero(), + }; + + for _ in 0..1000 { + let mut a = Fq6::random(&mut rng); + let mut b = a; + a.mul_by_nonresidue(); + b.mul_assign(&nqr); + + assert_eq!(a, b); + } +} + +#[test] +fn test_fq6_mul_by_1() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let c1 = Fq2::random(&mut rng); + let mut a = Fq6::random(&mut rng); + let mut b = a; + + a.mul_by_1(&c1); + b.mul_assign(&Fq6 { + c0: Fq2::zero(), + c1, + c2: Fq2::zero(), + }); + + assert_eq!(a, b); + } +} + +#[test] +fn test_fq6_mul_by_01() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let c0 = Fq2::random(&mut rng); + let c1 = Fq2::random(&mut rng); + let mut a = Fq6::random(&mut rng); + let mut b = a; + + a.mul_by_01(&c0, &c1); + b.mul_assign(&Fq6 { + c0, + c1, + c2: Fq2::zero(), + }); + + assert_eq!(a, b); + } +} + +#[test] +fn test_squaring() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let mut a = Fq6::random(&mut rng); + let mut b = a; + b.mul_assign(&a); + a.square_assign(); + assert_eq!(a, b); + } +} + +#[test] +fn test_frobenius() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..100 { + for i in 0..14 { + let mut a = Fq6::random(&mut rng); + let mut b = a; + + for _ in 0..i { + a = a.pow_vartime([ + 0x3c208c16d87cfd47, + 0x97816a916871ca8d, + 0xb85045b68181585d, + 0x30644e72e131a029, + ]); + } + b.frobenius_map(i); + + assert_eq!(a, b); + } + } +} + +#[test] +fn test_field() { + crate::tests::field::random_field_tests::("fq6".to_string()); +} diff --git a/arithmetic/curves/src/bn256/fr.rs b/arithmetic/curves/src/bn256/fr.rs new file mode 100644 index 0000000000..9bddcda35d --- /dev/null +++ b/arithmetic/curves/src/bn256/fr.rs @@ -0,0 +1,373 @@ +#[cfg(feature = "asm")] +use super::assembly::assembly_field; + +use crate::arithmetic::{adc, mac, macx, sbb}; +use core::convert::TryInto; +use core::fmt; +use core::ops::{Add, Mul, Neg, Sub}; +use ff::PrimeField; +use pasta_curves::arithmetic::{FieldExt, Group, SqrtRatio}; +use rand::RngCore; +use serde::{Deserialize, Serialize}; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +/// This represents an element of $\mathbb{F}_r$ where +/// +/// `r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001` +/// +/// is the scalar field of the BN254 curve. +// The internal representation of this type is four 64-bit unsigned +// integers in little-endian order. `Fr` values are always in +// Montgomery form; i.e., Fr(a) = aR mod r, with R = 2^256. +#[derive(Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)] +// PartialEq is derived for Hash, but if privacy perservation is needed, then constant time functions should be used: +// see NCC-E001151-003 in https://research.nccgroup.com/2021/11/02/public-report-zcash-nu5-cryptography-review/ +pub struct Fr(pub(crate) [u64; 4]); + +/// Constant representing the modulus +/// r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 +pub const MODULUS: Fr = Fr([ + 0x43e1f593f0000001, + 0x2833e84879b97091, + 0xb85045b68181585d, + 0x30644e72e131a029, +]); + +const MODULUS_STR: &str = "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"; + +/// INV = -(r^{-1} mod 2^64) mod 2^64 +const INV: u64 = 0xc2e1f593efffffff; + +/// `R = 2^256 mod r` +/// `0xe0a77c19a07df2f666ea36f7879462e36fc76959f60cd29ac96341c4ffffffb` +const R: Fr = Fr([ + 0xac96341c4ffffffb, + 0x36fc76959f60cd29, + 0x666ea36f7879462e, + 0x0e0a77c19a07df2f, +]); + +/// `R^2 = 2^512 mod r` +/// `0x216d0b17f4e44a58c49833d53bb808553fe3ab1e35c59e31bb8e645ae216da7` +const R2: Fr = Fr([ + 0x1bb8e645ae216da7, + 0x53fe3ab1e35c59e3, + 0x8c49833d53bb8085, + 0x0216d0b17f4e44a5, +]); + +/// `R^3 = 2^768 mod r` +/// `0xcf8594b7fcc657c893cc664a19fcfed2a489cbe1cfbb6b85e94d8e1b4bf0040` +const R3: Fr = Fr([ + 0x5e94d8e1b4bf0040, + 0x2a489cbe1cfbb6b8, + 0x893cc664a19fcfed, + 0x0cf8594b7fcc657c, +]); + +/// `GENERATOR = 7 mod r` is a generator of the `r - 1` order multiplicative +/// subgroup, or in other words a primitive root of the field. +const GENERATOR: Fr = Fr::from_raw([0x07, 0x00, 0x00, 0x00]); + +const S: u32 = 28; + +/// GENERATOR^t where t * 2^s + 1 = r +/// with t odd. In other words, this +/// is a 2^s root of unity. +/// `0x3ddb9f5166d18b798865ea93dd31f743215cf6dd39329c8d34f1ed960c37c9c` +const ROOT_OF_UNITY: Fr = Fr::from_raw([ + 0xd34f1ed960c37c9c, + 0x3215cf6dd39329c8, + 0x98865ea93dd31f74, + 0x03ddb9f5166d18b7, +]); + +/// 1 / 2 mod r +const TWO_INV: Fr = Fr::from_raw([ + 0xa1f0fac9f8000001, + 0x9419f4243cdcb848, + 0xdc2822db40c0ac2e, + 0x183227397098d014, +]); + +/// 1 / ROOT_OF_UNITY mod r +const ROOT_OF_UNITY_INV: Fr = Fr::from_raw([ + 0x0ed3e50a414e6dba, + 0xb22625f59115aba7, + 0x1bbe587180f34361, + 0x048127174daabc26, +]); + +/// GENERATOR^{2^s} where t * 2^s + 1 = r +/// with t odd. In other words, this +/// is a t root of unity. +// 0x09226b6e22c6f0ca64ec26aad4c86e715b5f898e5e963f25870e56bbe533e9a2 +const DELTA: Fr = Fr::from_raw([ + 0x870e56bbe533e9a2, + 0x5b5f898e5e963f25, + 0x64ec26aad4c86e71, + 0x09226b6e22c6f0ca, +]); + +/// `ZETA^3 = 1 mod r` where `ZETA^2 != 1 mod r` +const ZETA: Fr = Fr::from_raw([ + 0xb8ca0b2d36636f23, + 0xcc37a73fec2bc5e9, + 0x048b6e193fd84104, + 0x30644e72e131a029, +]); + +use crate::{ + field_arithmetic, field_common, field_specific, impl_add_binop_specify_output, + impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, +}; +impl_binops_additive!(Fr, Fr); +impl_binops_multiplicative!(Fr, Fr); +#[cfg(not(feature = "asm"))] +field_common!( + Fr, + MODULUS, + INV, + MODULUS_STR, + TWO_INV, + ROOT_OF_UNITY_INV, + DELTA, + ZETA, + R, + R2, + R3 +); +#[cfg(not(feature = "asm"))] +field_arithmetic!(Fr, MODULUS, INV, sparse); +#[cfg(feature = "asm")] +assembly_field!( + Fr, + MODULUS, + INV, + MODULUS_STR, + TWO_INV, + ROOT_OF_UNITY_INV, + DELTA, + ZETA, + R, + R2, + R3 +); + +impl ff::Field for Fr { + fn random(mut rng: impl RngCore) -> Self { + Self::from_u512([ + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + ]) + } + + fn zero() -> Self { + Self::zero() + } + + fn one() -> Self { + Self::one() + } + + fn double(&self) -> Self { + self.double() + } + + fn is_zero_vartime(&self) -> bool { + self == &Self::zero() + } + + #[inline(always)] + fn square(&self) -> Self { + self.square() + } + + /// Computes the square root of this element, if it exists. + fn sqrt(&self) -> CtOption { + crate::arithmetic::sqrt_tonelli_shanks(self, ::T_MINUS1_OVER2) + } + + /// Computes the multiplicative inverse of this element, + /// failing if the element is zero. + fn invert(&self) -> CtOption { + let tmp = self.pow(&[ + 0x43e1f593efffffff, + 0x2833e84879b97091, + 0xb85045b68181585d, + 0x30644e72e131a029, + ]); + + CtOption::new(tmp, !self.ct_eq(&Self::zero())) + } +} + +impl ff::PrimeField for Fr { + type Repr = [u8; 32]; + + const NUM_BITS: u32 = 254; + const CAPACITY: u32 = 253; + const S: u32 = S; + + fn from_repr(repr: Self::Repr) -> CtOption { + let mut tmp = Fr([0, 0, 0, 0]); + + tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); + tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); + tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); + tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); + + // Try to subtract the modulus + let (_, borrow) = tmp.0[0].overflowing_sub(MODULUS.0[0]); + let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow); + let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow); + let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow); + + // If the element is smaller than MODULUS then the + // subtraction will underflow, producing a borrow value + // of 0xffff...ffff. Otherwise, it'll be zero. + let is_some = (borrow as u8) & 1; + + // Convert to Montgomery form by computing + // (a.R^0 * R^2) / R = a.R + tmp *= &R2; + + CtOption::new(tmp, Choice::from(is_some)) + } + + fn to_repr(&self) -> Self::Repr { + // Turn into canonical form by computing + // (a.R) / R = a + #[cfg(feature = "asm")] + let tmp = Fr::montgomery_reduce(&[self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0]); + + #[cfg(not(feature = "asm"))] + let tmp = Fr::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]); + + let mut res = [0; 32]; + res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes()); + res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes()); + res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes()); + res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes()); + + res + } + + fn is_odd(&self) -> Choice { + Choice::from(self.to_repr()[0] & 1) + } + + fn multiplicative_generator() -> Self { + GENERATOR + } + + fn root_of_unity() -> Self { + ROOT_OF_UNITY + } +} + +impl SqrtRatio for Fr { + /// `(t - 1) // 2` where t * 2^s + 1 = p with t odd. + const T_MINUS1_OVER2: [u64; 4] = [ + 0xcdcb848a1f0fac9f, + 0x0c0ac2e9419f4243, + 0x098d014dc2822db4, + 0x0000000183227397, + ]; + + fn get_lower_32(&self) -> u32 { + #[cfg(not(feature = "asm"))] + let tmp = Fr::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]); + + #[cfg(feature = "asm")] + let tmp = Fr::montgomery_reduce(&[self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0]); + + tmp.0[0] as u32 + } +} + +#[cfg(test)] +mod test { + use super::*; + use ff::Field; + use rand_core::OsRng; + + #[test] + fn test_sqrt() { + let v = (Fr::TWO_INV).square().sqrt().unwrap(); + assert!(v == Fr::TWO_INV || (-v) == Fr::TWO_INV); + + for _ in 0..10000 { + let a = Fr::random(OsRng); + let mut b = a; + b = b.square(); + + let b = b.sqrt().unwrap(); + let mut negb = b; + negb = negb.neg(); + + assert!(a == b || a == negb); + } + } + + #[test] + fn test_root_of_unity() { + assert_eq!( + Fr::root_of_unity().pow_vartime([1 << Fr::S, 0, 0, 0]), + Fr::one() + ); + } + + #[test] + fn test_inv_root_of_unity() { + assert_eq!(Fr::ROOT_OF_UNITY_INV, Fr::root_of_unity().invert().unwrap()); + } + + #[test] + fn test_field() { + crate::tests::field::random_field_tests::("bn256 scalar".to_string()); + } + + #[test] + fn test_delta() { + assert_eq!(Fr::DELTA, GENERATOR.pow(&[1u64 << Fr::S, 0, 0, 0])); + assert_eq!( + Fr::DELTA, + Fr::multiplicative_generator().pow(&[1u64 << Fr::S, 0, 0, 0]) + ); + } + + #[test] + fn test_from_u512() { + assert_eq!( + Fr::from_raw([ + 0x7e7140b5196b9e6f, + 0x9abac9e4157b6172, + 0xf04bc41062fd7322, + 0x1185fa9c9fef6326, + ]), + Fr::from_u512([ + 0xaaaaaaaaaaaaaaaa, + 0xaaaaaaaaaaaaaaaa, + 0xaaaaaaaaaaaaaaaa, + 0xaaaaaaaaaaaaaaaa, + 0xaaaaaaaaaaaaaaaa, + 0xaaaaaaaaaaaaaaaa, + 0xaaaaaaaaaaaaaaaa, + 0xaaaaaaaaaaaaaaaa + ]) + ); + } + + #[test] + fn test_serialization() { + crate::tests::field::random_serialization_test::("fr".to_string()); + } +} diff --git a/arithmetic/curves/src/bn256/mod.rs b/arithmetic/curves/src/bn256/mod.rs new file mode 100644 index 0000000000..9cd0894620 --- /dev/null +++ b/arithmetic/curves/src/bn256/mod.rs @@ -0,0 +1,25 @@ +mod curve; +mod engine; +mod fq; +mod fq12; +mod fq2; +mod fq6; +mod fr; + +#[cfg(feature = "asm")] +mod assembly; + +pub use curve::*; +pub use engine::*; +pub use fq::*; +pub use fq12::*; +pub use fq2::*; +pub use fq6::*; +pub use fr::*; + +#[derive(Debug, PartialEq, Eq)] +pub enum LegendreSymbol { + Zero = 0, + QuadraticResidue = 1, + QuadraticNonResidue = -1, +} diff --git a/arithmetic/curves/src/derive/curve.rs b/arithmetic/curves/src/derive/curve.rs new file mode 100644 index 0000000000..1d51aeaa38 --- /dev/null +++ b/arithmetic/curves/src/derive/curve.rs @@ -0,0 +1,1043 @@ +#[macro_export] +macro_rules! batch_add { + () => { + fn batch_add( + points: &mut [Self], + output_indices: &[u32], + num_points: usize, + offset: usize, + bases: &[Self], + base_positions: &[u32], + ) { + // assert!(Self::constant_a().is_zero()); + + let get_point = |point_data: u32| -> Self { + let negate = point_data & 0x80000000 != 0; + let base_idx = (point_data & 0x7FFFFFFF) as usize; + if negate { + bases[base_idx].neg() + } else { + bases[base_idx] + } + }; + + // Affine addition formula (P != Q): + // - lambda = (y_2 - y_1) / (x_2 - x_1) + // - x_3 = lambda^2 - (x_2 + x_1) + // - y_3 = lambda * (x_1 - x_3) - y_1 + + // Batch invert accumulator + let mut acc = Self::Base::one(); + + for i in (0..num_points).step_by(2) { + // Where that result of the point addition will be stored + let out_idx = output_indices[i >> 1] as usize - offset; + + #[cfg(all(feature = "prefetch", target_arch = "x86_64"))] + if i < num_points - 2 { + if LOAD_POINTS { + $crate::prefetch::(bases, base_positions[i + 2] as usize); + $crate::prefetch::(bases, base_positions[i + 3] as usize); + } + $crate::prefetch::( + points, + output_indices[(i >> 1) + 1] as usize - offset, + ); + } + if LOAD_POINTS { + points[i] = get_point(base_positions[i]); + points[i + 1] = get_point(base_positions[i + 1]); + } + + if COMPLETE { + // Nothing to do here if one of the points is zero + if (points[i].is_identity() | points[i + 1].is_identity()).into() { + continue; + } + + if points[i].x == points[i + 1].x { + if points[i].y == points[i + 1].y { + // Point doubling (P == Q) + // - s = (3 * x^2) / (2 * y) + // - x_2 = s^2 - (2 * x) + // - y_2 = s * (x - x_2) - y + + // (2 * x) + points[out_idx].x = points[i].x + points[i].x; + // x^2 + let xx = points[i].x.square(); + // (2 * y) + points[i + 1].x = points[i].y + points[i].y; + // (3 * x^2) * acc + points[i + 1].y = (xx + xx + xx) * acc; + // acc * (2 * y) + acc *= points[i + 1].x; + continue; + } else { + // Zero + points[i] = Self::identity(); + points[i + 1] = Self::identity(); + continue; + } + } + } + + // (x_2 + x_1) + points[out_idx].x = points[i].x + points[i + 1].x; + // (x_2 - x_1) + points[i + 1].x -= points[i].x; + // (y2 - y1) * acc + points[i + 1].y = (points[i + 1].y - points[i].y) * acc; + // acc * (x_2 - x_1) + acc *= points[i + 1].x; + } + + // Batch invert + if COMPLETE { + if (!acc.is_zero()).into() { + acc = acc.invert().unwrap(); + } + } else { + acc = acc.invert().unwrap(); + } + + for i in (0..num_points).step_by(2).rev() { + // Where that result of the point addition will be stored + let out_idx = output_indices[i >> 1] as usize - offset; + + #[cfg(all(feature = "prefetch", target_arch = "x86_64"))] + if i > 0 { + $crate::prefetch::( + points, + output_indices[(i >> 1) - 1] as usize - offset, + ); + } + + if COMPLETE { + // points[i] is zero so the sum is points[i + 1] + if points[i].is_identity().into() { + points[out_idx] = points[i + 1]; + continue; + } + // points[i + 1] is zero so the sum is points[i] + if points[i + 1].is_identity().into() { + points[out_idx] = points[i]; + continue; + } + } + + // lambda + points[i + 1].y *= acc; + // acc * (x_2 - x_1) + acc *= points[i + 1].x; + // x_3 = lambda^2 - (x_2 + x_1) + points[out_idx].x = points[i + 1].y.square() - points[out_idx].x; + // y_3 = lambda * (x_1 - x_3) - y_1 + points[out_idx].y = + points[i + 1].y * (points[i].x - points[out_idx].x) - points[i].y; + } + } + }; +} + +#[macro_export] +macro_rules! new_curve_impl { + (($($privacy:tt)*), + $name:ident, + $name_affine:ident, + $name_compressed:ident, + $compressed_size:expr, + $base:ident, + $scalar:ident, + $generator:expr, + $constant_b:expr, + $curve_id:literal, + ) => { + + #[derive(Copy, Clone, Debug, Serialize, Deserialize)] + $($privacy)* struct $name { + pub x: $base, + pub y: $base, + pub z: $base, + } + + #[derive(Copy, Clone, PartialEq, Hash, Serialize, Deserialize)] + $($privacy)* struct $name_affine { + pub x: $base, + pub y: $base, + } + + #[derive(Copy, Clone, Hash)] + $($privacy)* struct $name_compressed([u8; $compressed_size]); + + impl $name { + pub fn generator() -> Self { + let generator = $name_affine::generator(); + Self { + x: generator.x, + y: generator.y, + z: $base::one(), + } + } + + const fn curve_constant_b() -> $base { + $name_affine::curve_constant_b() + } + } + + impl $name_affine { + pub fn generator() -> Self { + Self { + x: $generator.0, + y: $generator.1, + } + } + + const fn curve_constant_b() -> $base { + $constant_b + } + + pub fn random(mut rng: impl RngCore) -> Self { + loop { + let x = $base::random(&mut rng); + let ysign = (rng.next_u32() % 2) as u8; + + let x3 = x.square() * x; + let y = (x3 + $name::curve_constant_b()).sqrt(); + if let Some(y) = Option::<$base>::from(y) { + let sign = y.to_bytes()[0] & 1; + let y = if ysign ^ sign == 0 { y } else { -y }; + + let p = $name_affine { + x, + y, + }; + + + use $crate::group::cofactor::CofactorGroup; + let p = p.to_curve(); + return p.clear_cofactor().to_affine() + } + } + } + } + + // Compressed + + impl std::fmt::Debug for $name_compressed { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + self.0[..].fmt(f) + } + } + + impl Default for $name_compressed { + fn default() -> Self { + $name_compressed([0; $compressed_size]) + } + } + + impl AsRef<[u8]> for $name_compressed { + fn as_ref(&self) -> &[u8] { + &self.0 + } + } + + impl AsMut<[u8]> for $name_compressed { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 + } + } + + + // Jacobian implementations + + impl<'a> From<&'a $name_affine> for $name { + fn from(p: &'a $name_affine) -> $name { + p.to_curve() + } + } + + impl From<$name_affine> for $name { + fn from(p: $name_affine) -> $name { + p.to_curve() + } + } + + impl Default for $name { + fn default() -> $name { + $name::identity() + } + } + + impl subtle::ConstantTimeEq for $name { + fn ct_eq(&self, other: &Self) -> Choice { + // Is (xz^2, yz^3, z) equal to (x'z'^2, yz'^3, z') when converted to affine? + + let z = other.z.square(); + let x1 = self.x * z; + let z = z * other.z; + let y1 = self.y * z; + let z = self.z.square(); + let x2 = other.x * z; + let z = z * self.z; + let y2 = other.y * z; + + let self_is_zero = self.is_identity(); + let other_is_zero = other.is_identity(); + + (self_is_zero & other_is_zero) // Both point at infinity + | ((!self_is_zero) & (!other_is_zero) & x1.ct_eq(&x2) & y1.ct_eq(&y2)) + // Neither point at infinity, coordinates are the same + } + + } + + impl subtle::ConditionallySelectable for $name { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + $name { + x: $base::conditional_select(&a.x, &b.x, choice), + y: $base::conditional_select(&a.y, &b.y, choice), + z: $base::conditional_select(&a.z, &b.z, choice), + } + } + } + + impl PartialEq for $name { + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } + } + + impl cmp::Eq for $name {} + + impl CurveExt for $name { + + type ScalarExt = $scalar; + type Base = $base; + type AffineExt = $name_affine; + + const CURVE_ID: &'static str = $curve_id; + + fn endo(&self) -> Self { + self.endomorphism_base() + } + + fn jacobian_coordinates(&self) -> ($base, $base, $base) { + (self.x, self.y, self.z) + } + + + fn hash_to_curve<'a>(_: &'a str) -> Box Self + 'a> { + unimplemented!(); + } + + fn is_on_curve(&self) -> Choice { + + let z2 = self.z.square(); + let z4 = z2.square(); + let z6 = z4 * z2; + (self.y.square() - self.x.square() * self.x) + .ct_eq(&(z6 * $name::curve_constant_b())) + | self.z.is_zero() + } + + fn b() -> Self::Base { + $name::curve_constant_b() + } + + fn a() -> Self::Base { + Self::Base::zero() + } + + fn new_jacobian(x: Self::Base, y: Self::Base, z: Self::Base) -> CtOption { + let p = $name { x, y, z }; + CtOption::new(p, p.is_on_curve()) + } + } + + impl group::Curve for $name { + + type AffineRepr = $name_affine; + + fn batch_normalize(p: &[Self], q: &mut [Self::AffineRepr]) { + assert_eq!(p.len(), q.len()); + + let mut acc = $base::one(); + for (p, q) in p.iter().zip(q.iter_mut()) { + // We use the `x` field of $name_affine to store the product + // of previous z-coordinates seen. + q.x = acc; + + // We will end up skipping all identities in p + acc = $base::conditional_select(&(acc * p.z), &acc, p.is_identity()); + } + + // This is the inverse, as all z-coordinates are nonzero and the ones + // that are not are skipped. + acc = acc.invert().unwrap(); + + for (p, q) in p.iter().rev().zip(q.iter_mut().rev()) { + let skip = p.is_identity(); + + // Compute tmp = 1/z + let tmp = q.x * acc; + + // Cancel out z-coordinate in denominator of `acc` + acc = $base::conditional_select(&(acc * p.z), &acc, skip); + + // Set the coordinates to the correct value + let tmp2 = tmp.square(); + let tmp3 = tmp2 * tmp; + + q.x = p.x * tmp2; + q.y = p.y * tmp3; + + *q = $name_affine::conditional_select(&q, &$name_affine::identity(), skip); + } + } + + fn to_affine(&self) -> Self::AffineRepr { + let zinv = self.z.invert().unwrap_or($base::zero()); + let zinv2 = zinv.square(); + let x = self.x * zinv2; + let zinv3 = zinv2 * zinv; + let y = self.y * zinv3; + + let tmp = $name_affine { + x, + y, + }; + + $name_affine::conditional_select(&tmp, &$name_affine::identity(), zinv.is_zero()) + } + } + + impl group::Group for $name { + type Scalar = $scalar; + + fn random(mut rng: impl RngCore) -> Self { + $name_affine::random(&mut rng).to_curve() + } + + fn double(&self) -> Self { + let a = self.x.square(); + let b = self.y.square(); + let c = b.square(); + let d = self.x + b; + let d = d.square(); + let d = d - a - c; + let d = d + d; + let e = a + a + a; + let f = e.square(); + let z3 = self.z * self.y; + let z3 = z3 + z3; + let x3 = f - (d + d); + let c = c + c; + let c = c + c; + let c = c + c; + let y3 = e * (d - x3) - c; + + let tmp = $name { + x: x3, + y: y3, + z: z3, + }; + + $name::conditional_select(&tmp, &$name::identity(), self.is_identity()) + } + + fn generator() -> Self { + $name::generator() + } + + fn identity() -> Self { + Self { + x: $base::zero(), + y: $base::zero(), + z: $base::zero(), + } + } + + fn is_identity(&self) -> Choice { + self.z.is_zero() + } + } + + impl GroupEncoding for $name { + type Repr = $name_compressed; + + fn from_bytes(bytes: &Self::Repr) -> CtOption { + $name_affine::from_bytes(bytes).map(Self::from) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { + $name_affine::from_bytes(bytes).map(Self::from) + } + + fn to_bytes(&self) -> Self::Repr { + $name_affine::from(self).to_bytes() + } + } + + impl $crate::serde::SerdeObject for $name { + fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { + debug_assert_eq!(bytes.len(), 3 * $base::size()); + let [x, y, z] = [0, 1, 2] + .map(|i| $base::from_raw_bytes_unchecked(&bytes[i * $base::size()..(i + 1) * $base::size()])); + Self { x, y, z } + } + fn from_raw_bytes(bytes: &[u8]) -> Option { + if bytes.len() != 3 * $base::size() { + return None; + } + let [x, y, z] = + [0, 1, 2].map(|i| $base::from_raw_bytes(&bytes[i * $base::size()..(i + 1) * $base::size()])); + x.zip(y).zip(z).and_then(|((x, y), z)| { + let res = Self { x, y, z }; + // Check that the point is on the curve. + bool::from(res.is_on_curve()).then(|| res) + }) + } + fn to_raw_bytes(&self) -> Vec { + let mut res = Vec::with_capacity(3 * $base::size()); + Self::write_raw(self, &mut res).unwrap(); + res + } + fn read_raw_unchecked(reader: &mut R) -> Self { + let [x, y, z] = [(); 3].map(|_| $base::read_raw_unchecked(reader)); + Self { x, y, z } + } + fn read_raw(reader: &mut R) -> std::io::Result { + let x = $base::read_raw(reader)?; + let y = $base::read_raw(reader)?; + let z = $base::read_raw(reader)?; + Ok(Self { x, y, z }) + } + fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { + self.x.write_raw(writer)?; + self.y.write_raw(writer)?; + self.z.write_raw(writer) + } + } + + impl group::prime::PrimeGroup for $name {} + + impl group::prime::PrimeCurve for $name { + type Affine = $name_affine; + } + + impl group::cofactor::CofactorCurve for $name { + type Affine = $name_affine; + } + + impl Group for $name { + type Scalar = $scalar; + + fn group_zero() -> Self { + Self::identity() + } + fn group_add(&mut self, rhs: &Self) { + *self += *rhs; + } + fn group_sub(&mut self, rhs: &Self) { + *self -= *rhs; + } + fn group_scale(&mut self, by: &Self::Scalar) { + *self *= *by; + } + } + + // Affine implementations + + impl std::fmt::Debug for $name_affine { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + if self.is_identity().into() { + write!(f, "Infinity") + } else { + write!(f, "({:?}, {:?})", self.x, self.y) + } + } + } + + impl<'a> From<&'a $name> for $name_affine { + fn from(p: &'a $name) -> $name_affine { + p.to_affine() + } + } + + impl From<$name> for $name_affine { + fn from(p: $name) -> $name_affine { + p.to_affine() + } + } + + impl Default for $name_affine { + fn default() -> $name_affine { + $name_affine::identity() + } + } + + impl subtle::ConstantTimeEq for $name_affine { + fn ct_eq(&self, other: &Self) -> Choice { + let z1 = self.is_identity(); + let z2 = other.is_identity(); + + (z1 & z2) | ((!z1) & (!z2) & (self.x.ct_eq(&other.x)) & (self.y.ct_eq(&other.y))) + } + } + + impl subtle::ConditionallySelectable for $name_affine { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + $name_affine { + x: $base::conditional_select(&a.x, &b.x, choice), + y: $base::conditional_select(&a.y, &b.y, choice), + } + } + } + + impl cmp::Eq for $name_affine {} + + impl group::GroupEncoding for $name_affine { + type Repr = $name_compressed; + + fn from_bytes(bytes: &Self::Repr) -> CtOption { + let bytes = &bytes.0; + let mut tmp = *bytes; + let ysign = Choice::from(tmp[$compressed_size - 1] >> 7); + tmp[$compressed_size - 1] &= 0b0111_1111; + let mut xbytes = [0u8; $base::size()]; + xbytes.copy_from_slice(&tmp[ ..$base::size()]); + + $base::from_bytes(&xbytes).and_then(|x| { + CtOption::new(Self::identity(), x.is_zero() & (!ysign)).or_else(|| { + let x3 = x.square() * x; + (x3 + $name::curve_constant_b()).sqrt().and_then(|y| { + let sign = Choice::from(y.to_bytes()[0] & 1); + + let y = $base::conditional_select(&y, &-y, ysign ^ sign); + + CtOption::new( + $name_affine { + x, + y, + }, + Choice::from(1u8), + ) + }) + }) + }) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { + Self::from_bytes(bytes) + } + + fn to_bytes(&self) -> Self::Repr { + if bool::from(self.is_identity()) { + $name_compressed::default() + } else { + let (x, y) = (self.x, self.y); + let sign = (y.to_bytes()[0] & 1) << 7; + let mut xbytes = [0u8; $compressed_size]; + xbytes[..$base::size()].copy_from_slice(&x.to_bytes()); + xbytes[$compressed_size - 1] |= sign; + $name_compressed(xbytes) + } + } + } + + impl $crate::serde::SerdeObject for $name_affine { + fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { + debug_assert_eq!(bytes.len(), 2 * $base::size()); + let [x, y] = + [0, $base::size()].map(|i| $base::from_raw_bytes_unchecked(&bytes[i..i + $base::size()])); + Self { x, y } + } + fn from_raw_bytes(bytes: &[u8]) -> Option { + if bytes.len() != 2 * $base::size() { + return None; + } + let [x, y] = [0, $base::size()].map(|i| $base::from_raw_bytes(&bytes[i..i + $base::size()])); + x.zip(y).and_then(|(x, y)| { + let res = Self { x, y }; + // Check that the point is on the curve. + bool::from(res.is_on_curve()).then(|| res) + }) + } + fn to_raw_bytes(&self) -> Vec { + let mut res = Vec::with_capacity(2 * $base::size()); + Self::write_raw(self, &mut res).unwrap(); + res + } + fn read_raw_unchecked(reader: &mut R) -> Self { + let [x, y] = [(); 2].map(|_| $base::read_raw_unchecked(reader)); + Self { x, y } + } + fn read_raw(reader: &mut R) -> std::io::Result { + let x = $base::read_raw(reader)?; + let y = $base::read_raw(reader)?; + Ok(Self { x, y }) + } + fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { + self.x.write_raw(writer)?; + self.y.write_raw(writer) + } + } + + impl group::prime::PrimeCurveAffine for $name_affine { + type Curve = $name; + type Scalar = $scalar; + + + fn generator() -> Self { + $name_affine::generator() + } + + fn identity() -> Self { + Self { + x: $base::zero(), + y: $base::zero(), + } + } + + fn is_identity(&self) -> Choice { + self.x.is_zero() & self.y.is_zero() + } + + fn to_curve(&self) -> Self::Curve { + $name { + x: self.x, + y: self.y, + z: $base::conditional_select(&$base::one(), &$base::zero(), self.is_identity()), + } + } + } + + impl group::cofactor::CofactorCurveAffine for $name_affine { + type Curve = $name; + type Scalar = $scalar; + + fn identity() -> Self { + ::identity() + } + + fn generator() -> Self { + ::generator() + } + + fn is_identity(&self) -> Choice { + ::is_identity(self) + } + + fn to_curve(&self) -> Self::Curve { + ::to_curve(self) + } + } + + + impl CurveAffine for $name_affine { + type ScalarExt = $scalar; + type Base = $base; + type CurveExt = $name; + + fn is_on_curve(&self) -> Choice { + // y^2 - x^3 - ax ?= b + (self.y.square() - self.x.square() * self.x).ct_eq(&$name::curve_constant_b()) + | self.is_identity() + } + + fn coordinates(&self) -> CtOption> { + Coordinates::from_xy( self.x, self.y ) + } + + fn from_xy(x: Self::Base, y: Self::Base) -> CtOption { + let p = $name_affine { + x, y + }; + CtOption::new(p, p.is_on_curve()) + } + + fn a() -> Self::Base { + Self::Base::zero() + } + + fn b() -> Self::Base { + $name::curve_constant_b() + } + } + + + impl_binops_additive!($name, $name); + impl_binops_additive!($name, $name_affine); + impl_binops_additive_specify_output!($name_affine, $name_affine, $name); + impl_binops_additive_specify_output!($name_affine, $name, $name); + impl_binops_multiplicative!($name, $scalar); + impl_binops_multiplicative_mixed!($name_affine, $scalar, $name); + + impl<'a> Neg for &'a $name { + type Output = $name; + + fn neg(self) -> $name { + $name { + x: self.x, + y: -self.y, + z: self.z, + } + } + } + + impl Neg for $name { + type Output = $name; + + fn neg(self) -> $name { + -&self + } + } + + impl Sum for $name + where + T: core::borrow::Borrow<$name>, + { + fn sum(iter: I) -> Self + where + I: Iterator, + { + iter.fold(Self::identity(), |acc, item| acc + item.borrow()) + } + } + + impl<'a, 'b> Add<&'a $name> for &'b $name { + type Output = $name; + + fn add(self, rhs: &'a $name) -> $name { + if bool::from(self.is_identity()) { + *rhs + } else if bool::from(rhs.is_identity()) { + *self + } else { + let z1z1 = self.z.square(); + let z2z2 = rhs.z.square(); + let u1 = self.x * z2z2; + let u2 = rhs.x * z1z1; + let s1 = self.y * z2z2 * rhs.z; + let s2 = rhs.y * z1z1 * self.z; + + if u1 == u2 { + if s1 == s2 { + self.double() + } else { + $name::identity() + } + } else { + let h = u2 - u1; + let i = (h + h).square(); + let j = h * i; + let r = s2 - s1; + let r = r + r; + let v = u1 * i; + let x3 = r.square() - j - v - v; + let s1 = s1 * j; + let s1 = s1 + s1; + let y3 = r * (v - x3) - s1; + let z3 = (self.z + rhs.z).square() - z1z1 - z2z2; + let z3 = z3 * h; + + $name { + x: x3, y: y3, z: z3 + } + } + } + } + } + + impl<'a, 'b> Add<&'a $name_affine> for &'b $name { + type Output = $name; + + fn add(self, rhs: &'a $name_affine) -> $name { + if bool::from(self.is_identity()) { + rhs.to_curve() + } else if bool::from(rhs.is_identity()) { + *self + } else { + let z1z1 = self.z.square(); + let u2 = rhs.x * z1z1; + let s2 = rhs.y * z1z1 * self.z; + + if self.x == u2 { + if self.y == s2 { + self.double() + } else { + $name::identity() + } + } else { + let h = u2 - self.x; + let hh = h.square(); + let i = hh + hh; + let i = i + i; + let j = h * i; + let r = s2 - self.y; + let r = r + r; + let v = self.x * i; + let x3 = r.square() - j - v - v; + let j = self.y * j; + let j = j + j; + let y3 = r * (v - x3) - j; + let z3 = (self.z + h).square() - z1z1 - hh; + + $name { + x: x3, y: y3, z: z3 + } + } + } + } + } + + impl<'a, 'b> Sub<&'a $name> for &'b $name { + type Output = $name; + + fn sub(self, other: &'a $name) -> $name { + self + (-other) + } + } + + impl<'a, 'b> Sub<&'a $name_affine> for &'b $name { + type Output = $name; + + fn sub(self, other: &'a $name_affine) -> $name { + self + (-other) + } + } + + + + #[allow(clippy::suspicious_arithmetic_impl)] + impl<'a, 'b> Mul<&'b $scalar> for &'a $name { + type Output = $name; + + // This is a simple double-and-add implementation of point + // multiplication, moving from most significant to least + // significant bit of the scalar. + + fn mul(self, other: &'b $scalar) -> Self::Output { + let mut acc = $name::identity(); + for bit in other + .to_repr() + .iter() + .rev() + .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8))) + { + acc = acc.double(); + acc = $name::conditional_select(&acc, &(acc + self), bit); + } + + acc + } + } + + impl<'a> Neg for &'a $name_affine { + type Output = $name_affine; + + fn neg(self) -> $name_affine { + $name_affine { + x: self.x, + y: -self.y, + } + } + } + + impl Neg for $name_affine { + type Output = $name_affine; + + fn neg(self) -> $name_affine { + -&self + } + } + + impl<'a, 'b> Add<&'a $name> for &'b $name_affine { + type Output = $name; + + fn add(self, rhs: &'a $name) -> $name { + rhs + self + } + } + + impl<'a, 'b> Add<&'a $name_affine> for &'b $name_affine { + type Output = $name; + + fn add(self, rhs: &'a $name_affine) -> $name { + if bool::from(self.is_identity()) { + rhs.to_curve() + } else if bool::from(rhs.is_identity()) { + self.to_curve() + } else { + if self.x == rhs.x { + if self.y == rhs.y { + self.to_curve().double() + } else { + $name::identity() + } + } else { + let h = rhs.x - self.x; + let hh = h.square(); + let i = hh + hh; + let i = i + i; + let j = h * i; + let r = rhs.y - self.y; + let r = r + r; + let v = self.x * i; + let x3 = r.square() - j - v - v; + let j = self.y * j; + let j = j + j; + let y3 = r * (v - x3) - j; + let z3 = h + h; + + $name { + x: x3, y: y3, z: z3 + } + } + } + } + } + + impl<'a, 'b> Sub<&'a $name_affine> for &'b $name_affine { + type Output = $name; + + fn sub(self, other: &'a $name_affine) -> $name { + self + (-other) + } + } + + impl<'a, 'b> Sub<&'a $name> for &'b $name_affine { + type Output = $name; + + fn sub(self, other: &'a $name) -> $name { + self + (-other) + } + } + + #[allow(clippy::suspicious_arithmetic_impl)] + impl<'a, 'b> Mul<&'b $scalar> for &'a $name_affine { + type Output = $name; + + fn mul(self, other: &'b $scalar) -> Self::Output { + let mut acc = $name::identity(); + + // This is a simple double-and-add implementation of point + // multiplication, moving from most significant to least + // significant bit of the scalar. + + for bit in other + .to_repr() + .iter() + .rev() + .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8))) + { + acc = acc.double(); + acc = $name::conditional_select(&acc, &(acc + self), bit); + } + + acc + } + } + }; +} diff --git a/arithmetic/curves/src/derive/field.rs b/arithmetic/curves/src/derive/field.rs new file mode 100644 index 0000000000..4021e14322 --- /dev/null +++ b/arithmetic/curves/src/derive/field.rs @@ -0,0 +1,736 @@ +#[macro_export] +macro_rules! field_common { + ( + $field:ident, + $modulus:ident, + $inv:ident, + $modulus_str:ident, + $two_inv:ident, + $root_of_unity_inv:ident, + $delta:ident, + $zeta:ident, + $r:ident, + $r2:ident, + $r3:ident + ) => { + impl $field { + /// Returns zero, the additive identity. + #[inline] + pub const fn zero() -> $field { + $field([0, 0, 0, 0]) + } + + /// Returns one, the multiplicative identity. + #[inline] + pub const fn one() -> $field { + $r + } + + fn from_u512(limbs: [u64; 8]) -> $field { + // We reduce an arbitrary 512-bit number by decomposing it into two 256-bit digits + // with the higher bits multiplied by 2^256. Thus, we perform two reductions + // + // 1. the lower bits are multiplied by R^2, as normal + // 2. the upper bits are multiplied by R^2 * 2^256 = R^3 + // + // and computing their sum in the field. It remains to see that arbitrary 256-bit + // numbers can be placed into Montgomery form safely using the reduction. The + // reduction works so long as the product is less than R=2^256 multiplied by + // the modulus. This holds because for any `c` smaller than the modulus, we have + // that (2^256 - 1)*c is an acceptable product for the reduction. Therefore, the + // reduction always works so long as `c` is in the field; in this case it is either the + // constant `R2` or `R3`. + let d0 = $field([limbs[0], limbs[1], limbs[2], limbs[3]]); + let d1 = $field([limbs[4], limbs[5], limbs[6], limbs[7]]); + // Convert to Montgomery form + d0 * $r2 + d1 * $r3 + } + + /// Converts from an integer represented in little endian + /// into its (congruent) `$field` representation. + pub const fn from_raw(val: [u64; 4]) -> Self { + (&$field(val)).mul(&$r2) + } + + /// Attempts to convert a little-endian byte representation of + /// a scalar into a `Fr`, failing if the input is not canonical. + pub fn from_bytes(bytes: &[u8; 32]) -> CtOption<$field> { + ::from_repr(*bytes) + } + + /// Converts an element of `Fr` into a byte representation in + /// little-endian byte order. + pub fn to_bytes(&self) -> [u8; 32] { + ::to_repr(self) + } + } + + impl Group for $field { + type Scalar = Self; + + fn group_zero() -> Self { + Self::zero() + } + fn group_add(&mut self, rhs: &Self) { + *self += *rhs; + } + fn group_sub(&mut self, rhs: &Self) { + *self -= *rhs; + } + fn group_scale(&mut self, by: &Self::Scalar) { + *self *= *by; + } + } + + impl fmt::Debug for $field { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let tmp = self.to_repr(); + write!(f, "0x")?; + for &b in tmp.iter().rev() { + write!(f, "{:02x}", b)?; + } + Ok(()) + } + } + + impl Default for $field { + #[inline] + fn default() -> Self { + Self::zero() + } + } + + impl From for $field { + fn from(bit: bool) -> $field { + if bit { + $field::one() + } else { + $field::zero() + } + } + } + + impl From for $field { + fn from(val: u64) -> $field { + $field([val, 0, 0, 0]) * $r2 + } + } + + impl ConstantTimeEq for $field { + fn ct_eq(&self, other: &Self) -> Choice { + self.0[0].ct_eq(&other.0[0]) + & self.0[1].ct_eq(&other.0[1]) + & self.0[2].ct_eq(&other.0[2]) + & self.0[3].ct_eq(&other.0[3]) + } + } + + impl core::cmp::Ord for $field { + fn cmp(&self, other: &Self) -> core::cmp::Ordering { + let left = self.to_repr(); + let right = other.to_repr(); + left.iter() + .zip(right.iter()) + .rev() + .find_map(|(left_byte, right_byte)| match left_byte.cmp(right_byte) { + core::cmp::Ordering::Equal => None, + res => Some(res), + }) + .unwrap_or(core::cmp::Ordering::Equal) + } + } + + impl core::cmp::PartialOrd for $field { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } + } + + impl ConditionallySelectable for $field { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + $field([ + u64::conditional_select(&a.0[0], &b.0[0], choice), + u64::conditional_select(&a.0[1], &b.0[1], choice), + u64::conditional_select(&a.0[2], &b.0[2], choice), + u64::conditional_select(&a.0[3], &b.0[3], choice), + ]) + } + } + + impl<'a> Neg for &'a $field { + type Output = $field; + + #[inline] + fn neg(self) -> $field { + self.neg() + } + } + + impl Neg for $field { + type Output = $field; + + #[inline] + fn neg(self) -> $field { + -&self + } + } + + impl<'a, 'b> Sub<&'b $field> for &'a $field { + type Output = $field; + + #[inline] + fn sub(self, rhs: &'b $field) -> $field { + self.sub(rhs) + } + } + + impl<'a, 'b> Add<&'b $field> for &'a $field { + type Output = $field; + + #[inline] + fn add(self, rhs: &'b $field) -> $field { + self.add(rhs) + } + } + + impl<'a, 'b> Mul<&'b $field> for &'a $field { + type Output = $field; + + #[inline] + fn mul(self, rhs: &'b $field) -> $field { + self.mul(rhs) + } + } + + impl From<[u64; 4]> for $field { + fn from(digits: [u64; 4]) -> Self { + Self::from_raw(digits) + } + } + + impl From<$field> for [u64; 4] { + fn from(elt: $field) -> [u64; 4] { + // Turn into canonical form by computing + // (a.R) / R = a + #[cfg(feature = "asm")] + let tmp = $field::montgomery_reduce(&[ + elt.0[0], elt.0[1], elt.0[2], elt.0[3], 0, 0, 0, 0, + ]); + + #[cfg(not(feature = "asm"))] + let tmp = $field::montgomery_reduce_short(elt.0[0], elt.0[1], elt.0[2], elt.0[3]); + + tmp.0 + } + } + + impl From<$field> for [u8; 32] { + fn from(value: $field) -> [u8; 32] { + value.to_repr() + } + } + + impl<'a> From<&'a $field> for [u8; 32] { + fn from(value: &'a $field) -> [u8; 32] { + value.to_repr() + } + } + + impl From<$field> for i128 { + fn from(value: $field) -> i128 { + let tmp: [u64; 4] = value.into(); + if tmp[2] == 0 && tmp[3] == 0 { + i128::from(tmp[0]) | (i128::from(tmp[1]) << 64) + } else { + // modulus - tmp + let (a0, borrow) = $modulus.0[0].overflowing_sub(tmp[0]); + let (a1, _) = sbb($modulus.0[1], tmp[1], borrow); + + -(i128::from(a0) | (i128::from(a1) << 64)) + } + } + } + + impl FieldExt for $field { + const MODULUS: &'static str = $modulus_str; + const TWO_INV: Self = $two_inv; + const ROOT_OF_UNITY_INV: Self = $root_of_unity_inv; + const DELTA: Self = $delta; + const ZETA: Self = $zeta; + + fn from_u128(v: u128) -> Self { + $field::from_raw([v as u64, (v >> 64) as u64, 0, 0]) + } + + /// Converts a 512-bit little endian integer into + /// a `$field` by reducing by the modulus. + fn from_bytes_wide(bytes: &[u8; 64]) -> $field { + $field::from_u512([ + u64::from_le_bytes(bytes[0..8].try_into().unwrap()), + u64::from_le_bytes(bytes[8..16].try_into().unwrap()), + u64::from_le_bytes(bytes[16..24].try_into().unwrap()), + u64::from_le_bytes(bytes[24..32].try_into().unwrap()), + u64::from_le_bytes(bytes[32..40].try_into().unwrap()), + u64::from_le_bytes(bytes[40..48].try_into().unwrap()), + u64::from_le_bytes(bytes[48..56].try_into().unwrap()), + u64::from_le_bytes(bytes[56..64].try_into().unwrap()), + ]) + } + + fn get_lower_128(&self) -> u128 { + let tmp = + $field::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]); + + u128::from(tmp.0[0]) | (u128::from(tmp.0[1]) << 64) + } + } + + impl $crate::serde::SerdeObject for $field { + fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self { + debug_assert_eq!(bytes.len(), 32); + let inner = + [0, 8, 16, 24].map(|i| u64::from_le_bytes(bytes[i..i + 8].try_into().unwrap())); + Self(inner) + } + fn from_raw_bytes(bytes: &[u8]) -> Option { + if bytes.len() != 32 { + return None; + } + let elt = Self::from_raw_bytes_unchecked(bytes); + Self::is_less_than(&elt.0, &$modulus.0).then(|| elt) + } + fn to_raw_bytes(&self) -> Vec { + let mut res = Vec::with_capacity(32); + for limb in self.0.iter() { + res.extend_from_slice(&limb.to_le_bytes()); + } + res + } + fn read_raw_unchecked(reader: &mut R) -> Self { + let inner = [(); 4].map(|_| { + let mut buf = [0; 8]; + reader.read_exact(&mut buf).unwrap(); + u64::from_le_bytes(buf) + }); + Self(inner) + } + fn read_raw(reader: &mut R) -> std::io::Result { + let mut inner = [0u64; 4]; + for limb in inner.iter_mut() { + let mut buf = [0; 8]; + reader.read_exact(&mut buf)?; + *limb = u64::from_le_bytes(buf); + } + let elt = Self(inner); + Self::is_less_than(&elt.0, &$modulus.0) + .then(|| elt) + .ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::InvalidData, + "input number is not less than field modulus", + ) + }) + } + fn write_raw(&self, writer: &mut W) -> std::io::Result<()> { + for limb in self.0.iter() { + writer.write_all(&limb.to_le_bytes())?; + } + Ok(()) + } + } + }; +} + +#[macro_export] +macro_rules! field_arithmetic { + ($field:ident, $modulus:ident, $inv:ident, $field_type:ident) => { + field_specific!($field, $modulus, $inv, $field_type); + impl $field { + /// Doubles this field element. + #[inline] + pub const fn double(&self) -> $field { + self.add(self) + } + + /// Squares this element. + #[inline] + pub const fn square(&self) -> $field { + let r0; + let mut r1; + let mut r2; + let mut r3; + let mut r4; + let mut r5; + let mut r6; + let mut r7; + let mut carry; + let mut carry2; + + (r1, carry) = self.0[0].widening_mul(self.0[1]); + (r2, carry) = self.0[0].carrying_mul(self.0[2], carry); + (r3, r4) = self.0[0].carrying_mul(self.0[3], carry); + + (r3, carry) = macx(r3, self.0[1], self.0[2]); + (r4, r5) = mac(r4, self.0[1], self.0[3], carry); + + (r5, r6) = macx(r5, self.0[2], self.0[3]); + + r7 = r6 >> 63; + r6 = (r6 << 1) | (r5 >> 63); + r5 = (r5 << 1) | (r4 >> 63); + r4 = (r4 << 1) | (r3 >> 63); + r3 = (r3 << 1) | (r2 >> 63); + r2 = (r2 << 1) | (r1 >> 63); + r1 <<= 1; + + (r0, carry) = self.0[0].widening_mul(self.0[0]); + (r1, carry2) = r1.overflowing_add(carry); + (r2, carry) = mac(r2, self.0[1], self.0[1], carry2 as u64); + (r3, carry2) = r3.overflowing_add(carry); + (r4, carry) = mac(r4, self.0[2], self.0[2], carry2 as u64); + (r5, carry2) = r5.overflowing_add(carry); + (r6, carry) = mac(r6, self.0[3], self.0[3], carry2 as u64); + r7 = r7.wrapping_add(carry); + + $field::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7) + } + + /// Subtracts `rhs` from `self`, returning the result. + #[inline] + pub const fn sub(&self, rhs: &Self) -> Self { + let (d0, borrow) = self.0[0].overflowing_sub(rhs.0[0]); + let (d1, borrow) = sbb(self.0[1], rhs.0[1], borrow); + let (d2, borrow) = sbb(self.0[2], rhs.0[2], borrow); + let (d3, borrow) = sbb(self.0[3], rhs.0[3], borrow); + + let borrow = 0u64.wrapping_sub(borrow as u64); + // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise + // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus. + let (d0, carry) = d0.overflowing_add($modulus.0[0] & borrow); + let (d1, carry) = adc(d1, $modulus.0[1] & borrow, carry); + let (d2, carry) = adc(d2, $modulus.0[2] & borrow, carry); + let (d3, _) = adc(d3, $modulus.0[3] & borrow, carry); + $field([d0, d1, d2, d3]) + } + + /// Negates `self`. + #[inline] + pub const fn neg(&self) -> Self { + if self.0[0] == 0 && self.0[1] == 0 && self.0[2] == 0 && self.0[3] == 0 { + return $field([0, 0, 0, 0]); + } + // Subtract `self` from `MODULUS` to negate. Ignore the final + // borrow because it cannot underflow; self is guaranteed to + // be in the field. + let (d0, borrow) = $modulus.0[0].overflowing_sub(self.0[0]); + let (d1, borrow) = sbb($modulus.0[1], self.0[1], borrow); + let (d2, borrow) = sbb($modulus.0[2], self.0[2], borrow); + let d3 = $modulus.0[3] - (self.0[3] + borrow as u64); + + $field([d0, d1, d2, d3]) + } + + /// Montgomery reduce where last 4 registers are 0 + #[inline(always)] + pub(crate) const fn montgomery_reduce_short( + mut r0: u64, + mut r1: u64, + mut r2: u64, + mut r3: u64, + ) -> $field { + // The Montgomery reduction here is based on Algorithm 14.32 in + // Handbook of Applied Cryptography + // . + let mut k; + + k = r0.wrapping_mul($inv); + (_, r0) = macx(r0, k, $modulus.0[0]); + (r1, r0) = mac(r1, k, $modulus.0[1], r0); + (r2, r0) = mac(r2, k, $modulus.0[2], r0); + (r3, r0) = mac(r3, k, $modulus.0[3], r0); + + k = r1.wrapping_mul($inv); + (_, r1) = macx(r1, k, $modulus.0[0]); + (r2, r1) = mac(r2, k, $modulus.0[1], r1); + (r3, r1) = mac(r3, k, $modulus.0[2], r1); + (r0, r1) = mac(r0, k, $modulus.0[3], r1); + + k = r2.wrapping_mul($inv); + (_, r2) = macx(r2, k, $modulus.0[0]); + (r3, r2) = mac(r3, k, $modulus.0[1], r2); + (r0, r2) = mac(r0, k, $modulus.0[2], r2); + (r1, r2) = mac(r1, k, $modulus.0[3], r2); + + k = r3.wrapping_mul($inv); + (_, r3) = macx(r3, k, $modulus.0[0]); + (r0, r3) = mac(r0, k, $modulus.0[1], r3); + (r1, r3) = mac(r1, k, $modulus.0[2], r3); + (r2, r3) = mac(r2, k, $modulus.0[3], r3); + + // Result may be within MODULUS of the correct value + (&$field([r0, r1, r2, r3])).sub(&$modulus) + } + + #[inline(always)] + fn is_less_than(x: &[u64; 4], y: &[u64; 4]) -> bool { + let (_, borrow) = x[0].overflowing_sub(y[0]); + let (_, borrow) = x[1].borrowing_sub(y[1], borrow); + let (_, borrow) = x[2].borrowing_sub(y[2], borrow); + let (_, borrow) = x[3].borrowing_sub(y[3], borrow); + borrow + } + } + }; +} + +#[macro_export] +macro_rules! field_specific { + ($field:ident, $modulus:ident, $inv:ident, sparse) => { + impl $field { + /// Adds `rhs` to `self`, returning the result. + #[inline] + pub const fn add(&self, rhs: &Self) -> Self { + let (d0, carry) = self.0[0].overflowing_add(rhs.0[0]); + let (d1, carry) = self.0[1].carrying_add(rhs.0[1], carry); + let (d2, carry) = self.0[2].carrying_add(rhs.0[2], carry); + // sparse means that the sum won't overflow the top register + let d3 = self.0[3] + rhs.0[3] + carry as u64; + + // Attempt to subtract the modulus, to ensure the value + // is smaller than the modulus. + (&$field([d0, d1, d2, d3])).sub(&$modulus) + } + + /// Multiplies `rhs` by `self`, returning the result. + #[inline] + pub const fn mul(&self, rhs: &Self) -> $field { + // When the highest bit in the top register of the modulus is 0 and the rest of the bits are not all 1, we can use an optimization from the gnark team: https://hackmd.io/@gnark/modular_multiplication + + // I think this is exactly the same as the previous `mul` implementation with `montgomery_reduce` at the end (where `montgomery_reduce` is slightly cheaper in "sparse" setting) + // Maybe the use of mutable variables is slightly more efficient? + let mut r0; + let mut r1; + let mut t0; + let mut t1; + let mut t2; + let mut t3; + let mut k; + + (t0, r0) = self.0[0].widening_mul(rhs.0[0]); + k = t0.wrapping_mul($inv); + (_, r1) = macx(t0, k, $modulus.0[0]); + (t1, r0) = self.0[0].carrying_mul(rhs.0[1], r0); + (t0, r1) = mac(t1, k, $modulus.0[1], r1); + (t2, r0) = self.0[0].carrying_mul(rhs.0[2], r0); + (t1, r1) = mac(t2, k, $modulus.0[2], r1); + (t3, r0) = self.0[0].carrying_mul(rhs.0[3], r0); + (t2, r1) = mac(t3, k, $modulus.0[3], r1); + t3 = r0 + r1; + + (t0, r0) = macx(t0, self.0[1], rhs.0[0]); + k = t0.wrapping_mul($inv); + (_, r1) = macx(t0, k, $modulus.0[0]); + (t1, r0) = mac(t1, self.0[1], rhs.0[1], r0); + (t0, r1) = mac(t1, k, $modulus.0[1], r1); + (t2, r0) = mac(t2, self.0[1], rhs.0[2], r0); + (t1, r1) = mac(t2, k, $modulus.0[2], r1); + (t3, r0) = mac(t3, self.0[1], rhs.0[3], r0); + (t2, r1) = mac(t3, k, $modulus.0[3], r1); + t3 = r0 + r1; + + (t0, r0) = macx(t0, self.0[2], rhs.0[0]); + k = t0.wrapping_mul($inv); + (_, r1) = macx(t0, k, $modulus.0[0]); + (t1, r0) = mac(t1, self.0[2], rhs.0[1], r0); + (t0, r1) = mac(t1, k, $modulus.0[1], r1); + (t2, r0) = mac(t2, self.0[2], rhs.0[2], r0); + (t1, r1) = mac(t2, k, $modulus.0[2], r1); + (t3, r0) = mac(t3, self.0[2], rhs.0[3], r0); + (t2, r1) = mac(t3, k, $modulus.0[3], r1); + t3 = r0 + r1; + + (t0, r0) = macx(t0, self.0[3], rhs.0[0]); + k = t0.wrapping_mul($inv); + (_, r1) = macx(t0, k, $modulus.0[0]); + (t1, r0) = mac(t1, self.0[3], rhs.0[1], r0); + (t0, r1) = mac(t1, k, $modulus.0[1], r1); + (t2, r0) = mac(t2, self.0[3], rhs.0[2], r0); + (t1, r1) = mac(t2, k, $modulus.0[2], r1); + (t3, r0) = mac(t3, self.0[3], rhs.0[3], r0); + (t2, r1) = mac(t3, k, $modulus.0[3], r1); + t3 = r0 + r1; + + // Result may be within MODULUS of the correct value + (&$field([t0, t1, t2, t3])).sub(&$modulus) + } + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + pub(crate) const fn montgomery_reduce( + r0: u64, + mut r1: u64, + mut r2: u64, + mut r3: u64, + mut r4: u64, + mut r5: u64, + mut r6: u64, + mut r7: u64, + ) -> $field { + // The Montgomery reduction here is based on Algorithm 14.32 in + // Handbook of Applied Cryptography + // . + let mut k; + let mut carry; + let mut carry2; + + k = r0.wrapping_mul($inv); + (_, carry) = macx(r0, k, $modulus.0[0]); + (r1, carry) = mac(r1, k, $modulus.0[1], carry); + (r2, carry) = mac(r2, k, $modulus.0[2], carry); + (r3, carry) = mac(r3, k, $modulus.0[3], carry); + (r4, carry2) = r4.overflowing_add(carry); + + k = r1.wrapping_mul($inv); + (_, carry) = macx(r1, k, $modulus.0[0]); + (r2, carry) = mac(r2, k, $modulus.0[1], carry); + (r3, carry) = mac(r3, k, $modulus.0[2], carry); + (r4, carry) = mac(r4, k, $modulus.0[3], carry); + (r5, carry2) = adc(r5, carry, carry2); + + k = r2.wrapping_mul($inv); + (_, carry) = macx(r2, k, $modulus.0[0]); + (r3, carry) = mac(r3, k, $modulus.0[1], carry); + (r4, carry) = mac(r4, k, $modulus.0[2], carry); + (r5, carry) = mac(r5, k, $modulus.0[3], carry); + (r6, carry2) = adc(r6, carry, carry2); + + k = r3.wrapping_mul($inv); + (_, carry) = macx(r3, k, $modulus.0[0]); + (r4, carry) = mac(r4, k, $modulus.0[1], carry); + (r5, carry) = mac(r5, k, $modulus.0[2], carry); + (r6, carry) = mac(r6, k, $modulus.0[3], carry); + (r7, _) = adc(r7, carry, carry2); + + // Result may be within MODULUS of the correct value + (&$field([r4, r5, r6, r7])).sub(&$modulus) + } + } + }; + ($field:ident, $modulus:ident, $inv:ident, dense) => { + impl $field { + /// Adds `rhs` to `self`, returning the result. + #[inline] + pub const fn add(&self, rhs: &Self) -> Self { + let (d0, carry) = self.0[0].overflowing_add(rhs.0[0]); + let (d1, carry) = adc(self.0[1], rhs.0[1], carry); + let (d2, carry) = adc(self.0[2], rhs.0[2], carry); + let (d3, carry) = adc(self.0[3], rhs.0[3], carry); + + // Attempt to subtract the modulus, to ensure the value + // is smaller than the modulus. + let (d0, borrow) = d0.overflowing_sub($modulus.0[0]); + let (d1, borrow) = sbb(d1, $modulus.0[1], borrow); + let (d2, borrow) = sbb(d2, $modulus.0[2], borrow); + let (d3, borrow) = sbb(d3, $modulus.0[3], borrow); + let borrow = (carry as u64).wrapping_sub(borrow as u64); + + let (d0, carry) = d0.overflowing_add($modulus.0[0] & borrow); + let (d1, carry) = adc(d1, $modulus.0[1] & borrow, carry); + let (d2, carry) = adc(d2, $modulus.0[2] & borrow, carry); + let (d3, _) = adc(d3, $modulus.0[3] & borrow, carry); + + $field([d0, d1, d2, d3]) + } + + /// Multiplies `rhs` by `self`, returning the result. + #[inline] + pub const fn mul(&self, rhs: &Self) -> $field { + // Schoolbook multiplication + + let (r0, carry) = mac(0, self.0[0], rhs.0[0], 0); + let (r1, carry) = mac(0, self.0[0], rhs.0[1], carry); + let (r2, carry) = mac(0, self.0[0], rhs.0[2], carry); + let (r3, r4) = mac(0, self.0[0], rhs.0[3], carry); + + let (r1, carry) = mac(r1, self.0[1], rhs.0[0], 0); + let (r2, carry) = mac(r2, self.0[1], rhs.0[1], carry); + let (r3, carry) = mac(r3, self.0[1], rhs.0[2], carry); + let (r4, r5) = mac(r4, self.0[1], rhs.0[3], carry); + + let (r2, carry) = mac(r2, self.0[2], rhs.0[0], 0); + let (r3, carry) = mac(r3, self.0[2], rhs.0[1], carry); + let (r4, carry) = mac(r4, self.0[2], rhs.0[2], carry); + let (r5, r6) = mac(r5, self.0[2], rhs.0[3], carry); + + let (r3, carry) = mac(r3, self.0[3], rhs.0[0], 0); + let (r4, carry) = mac(r4, self.0[3], rhs.0[1], carry); + let (r5, carry) = mac(r5, self.0[3], rhs.0[2], carry); + let (r6, r7) = mac(r6, self.0[3], rhs.0[3], carry); + + $field::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7) + } + + #[allow(clippy::too_many_arguments)] + #[inline(always)] + pub(crate) const fn montgomery_reduce( + r0: u64, + mut r1: u64, + mut r2: u64, + mut r3: u64, + mut r4: u64, + mut r5: u64, + mut r6: u64, + mut r7: u64, + ) -> Self { + // The Montgomery reduction here is based on Algorithm 14.32 in + // Handbook of Applied Cryptography + // . + let mut k; + let mut carry; + let mut carry2; + + k = r0.wrapping_mul($inv); + (_, carry) = macx(r0, k, $modulus.0[0]); + (r1, carry) = mac(r1, k, $modulus.0[1], carry); + (r2, carry) = mac(r2, k, $modulus.0[2], carry); + (r3, carry) = mac(r3, k, $modulus.0[3], carry); + (r4, carry2) = r4.overflowing_add(carry); + + k = r1.wrapping_mul($inv); + (_, carry) = k.carrying_mul($modulus.0[0], r1); + (r2, carry) = mac(r2, k, $modulus.0[1], carry); + (r3, carry) = mac(r3, k, $modulus.0[2], carry); + (r4, carry) = mac(r4, k, $modulus.0[3], carry); + (r5, carry2) = adc(r5, carry, carry2); + + k = r2.wrapping_mul($inv); + (_, carry) = macx(r2, k, $modulus.0[0]); + (r3, carry) = mac(r3, k, $modulus.0[1], carry); + (r4, carry) = mac(r4, k, $modulus.0[2], carry); + (r5, carry) = mac(r5, k, $modulus.0[3], carry); + (r6, carry2) = adc(r6, carry, carry2); + + k = r3.wrapping_mul($inv); + (_, carry) = macx(r3, k, $modulus.0[0]); + (r4, carry) = mac(r4, k, $modulus.0[1], carry); + (r5, carry) = mac(r5, k, $modulus.0[2], carry); + (r6, carry) = mac(r6, k, $modulus.0[3], carry); + (r7, carry2) = adc(r7, carry, carry2); + + // Result may be within MODULUS of the correct value + let mut borrow; + (r4, borrow) = r4.overflowing_sub($modulus.0[0]); + (r5, borrow) = sbb(r5, $modulus.0[1], borrow); + (r6, borrow) = sbb(r6, $modulus.0[2], borrow); + (r7, borrow) = sbb(r7, $modulus.0[3], borrow); + let borrow = (carry2 as u64).wrapping_sub(borrow as u64); + + (r4, carry2) = r4.overflowing_add($modulus.0[0] & borrow); + (r5, carry2) = adc(r5, $modulus.0[1] & borrow, carry2); + (r6, carry2) = adc(r6, $modulus.0[2] & borrow, carry2); + (r7, _) = adc(r7, $modulus.0[3] & borrow, carry2); + $field([r4, r5, r6, r7]) + } + } + }; +} diff --git a/arithmetic/curves/src/derive/mod.rs b/arithmetic/curves/src/derive/mod.rs new file mode 100644 index 0000000000..de8bc4ccb8 --- /dev/null +++ b/arithmetic/curves/src/derive/mod.rs @@ -0,0 +1,164 @@ +#[macro_use] +pub mod curve; +#[macro_use] +pub mod field; + +#[macro_export] +macro_rules! impl_add_binop_specify_output { + ($lhs:ident, $rhs:ident, $output:ident) => { + impl<'b> ::core::ops::Add<&'b $rhs> for $lhs { + type Output = $output; + + #[inline] + fn add(self, rhs: &'b $rhs) -> $output { + &self + rhs + } + } + + impl<'a> ::core::ops::Add<$rhs> for &'a $lhs { + type Output = $output; + + #[inline] + fn add(self, rhs: $rhs) -> $output { + self + &rhs + } + } + + impl ::core::ops::Add<$rhs> for $lhs { + type Output = $output; + + #[inline] + fn add(self, rhs: $rhs) -> $output { + &self + &rhs + } + } + }; +} + +#[macro_export] +macro_rules! impl_sub_binop_specify_output { + ($lhs:ident, $rhs:ident, $output:ident) => { + impl<'b> ::core::ops::Sub<&'b $rhs> for $lhs { + type Output = $output; + + #[inline] + fn sub(self, rhs: &'b $rhs) -> $output { + &self - rhs + } + } + + impl<'a> ::core::ops::Sub<$rhs> for &'a $lhs { + type Output = $output; + + #[inline] + fn sub(self, rhs: $rhs) -> $output { + self - &rhs + } + } + + impl ::core::ops::Sub<$rhs> for $lhs { + type Output = $output; + + #[inline] + fn sub(self, rhs: $rhs) -> $output { + &self - &rhs + } + } + }; +} + +#[macro_export] +macro_rules! impl_binops_additive_specify_output { + ($lhs:ident, $rhs:ident, $output:ident) => { + impl_add_binop_specify_output!($lhs, $rhs, $output); + impl_sub_binop_specify_output!($lhs, $rhs, $output); + }; +} + +#[macro_export] +macro_rules! impl_binops_multiplicative_mixed { + ($lhs:ident, $rhs:ident, $output:ident) => { + impl<'b> ::core::ops::Mul<&'b $rhs> for $lhs { + type Output = $output; + + #[inline] + fn mul(self, rhs: &'b $rhs) -> $output { + &self * rhs + } + } + + impl<'a> ::core::ops::Mul<$rhs> for &'a $lhs { + type Output = $output; + + #[inline] + fn mul(self, rhs: $rhs) -> $output { + self * &rhs + } + } + + impl ::core::ops::Mul<$rhs> for $lhs { + type Output = $output; + + #[inline] + fn mul(self, rhs: $rhs) -> $output { + &self * &rhs + } + } + }; +} + +#[macro_export] +macro_rules! impl_binops_additive { + ($lhs:ident, $rhs:ident) => { + impl_binops_additive_specify_output!($lhs, $rhs, $lhs); + + impl ::core::ops::SubAssign<$rhs> for $lhs { + #[inline] + fn sub_assign(&mut self, rhs: $rhs) { + *self = &*self - &rhs; + } + } + + impl ::core::ops::AddAssign<$rhs> for $lhs { + #[inline] + fn add_assign(&mut self, rhs: $rhs) { + *self = &*self + &rhs; + } + } + + impl<'b> ::core::ops::SubAssign<&'b $rhs> for $lhs { + #[inline] + fn sub_assign(&mut self, rhs: &'b $rhs) { + *self = &*self - rhs; + } + } + + impl<'b> ::core::ops::AddAssign<&'b $rhs> for $lhs { + #[inline] + fn add_assign(&mut self, rhs: &'b $rhs) { + *self = &*self + rhs; + } + } + }; +} + +#[macro_export] +macro_rules! impl_binops_multiplicative { + ($lhs:ident, $rhs:ident) => { + impl_binops_multiplicative_mixed!($lhs, $rhs, $lhs); + + impl ::core::ops::MulAssign<$rhs> for $lhs { + #[inline] + fn mul_assign(&mut self, rhs: $rhs) { + *self = &*self * &rhs; + } + } + + impl<'b> ::core::ops::MulAssign<&'b $rhs> for $lhs { + #[inline] + fn mul_assign(&mut self, rhs: &'b $rhs) { + *self = &*self * rhs; + } + } + }; +} diff --git a/arithmetic/curves/src/lib.rs b/arithmetic/curves/src/lib.rs new file mode 100644 index 0000000000..abdf1e2c57 --- /dev/null +++ b/arithmetic/curves/src/lib.rs @@ -0,0 +1,34 @@ +#![cfg_attr(feature = "asm", feature(asm_const))] +#![feature(bigint_helper_methods)] +#![feature(const_bigint_helper_methods)] + +mod arithmetic; + +pub mod bn256; +pub mod pairing; +pub mod pasta; +pub mod secp256k1; +pub mod serde; + +#[macro_use] +mod derive; + +pub use arithmetic::CurveAffineExt; +pub use pasta_curves::arithmetic::{Coordinates, CurveAffine, CurveExt, FieldExt, Group}; + +pub extern crate group; + +#[cfg(test)] +pub mod tests; + +#[cfg(all(feature = "prefetch", target_arch = "x86_64"))] +#[inline(always)] +pub fn prefetch(data: &[T], offset: usize) { + use core::arch::x86_64::_mm_prefetch; + unsafe { + _mm_prefetch( + data.as_ptr().offset(offset as isize) as *const i8, + core::arch::x86_64::_MM_HINT_T0, + ); + } +} diff --git a/arithmetic/curves/src/pairing.rs b/arithmetic/curves/src/pairing.rs new file mode 100644 index 0000000000..55586e7c9e --- /dev/null +++ b/arithmetic/curves/src/pairing.rs @@ -0,0 +1,93 @@ +use crate::{CurveAffine, FieldExt, Group as _Group}; +use core::ops::Mul; +use group::{ + prime::PrimeCurve, Group, GroupOps, GroupOpsOwned, ScalarMul, ScalarMulOwned, + UncompressedEncoding, +}; + +pub trait Engine: Sized + 'static + Clone { + /// This is the scalar field of the engine's groups. + type Scalar: FieldExt; + + /// The projective representation of an element in G1. + type G1: PrimeCurve + + From + + GroupOps + + GroupOpsOwned + + ScalarMul + + ScalarMulOwned + + _Group; + + /// The affine representation of an element in G1. + type G1Affine: PairingCurveAffine< + ScalarExt = Self::Scalar, + CurveExt = Self::G1, + Pair = Self::G2Affine, + PairingResult = Self::Gt, + > + From + + Mul + + for<'a> Mul<&'a Self::Scalar, Output = Self::G1>; + + /// The projective representation of an element in G2. + type G2: PrimeCurve + + From + + GroupOps + + GroupOpsOwned + + ScalarMul + + ScalarMulOwned; + + /// The affine representation of an element in G2. + type G2Affine: PairingCurveAffine< + ScalarExt = Self::Scalar, + CurveExt = Self::G2, + Pair = Self::G1Affine, + PairingResult = Self::Gt, + > + From + + Mul + + for<'a> Mul<&'a Self::Scalar, Output = Self::G2>; + + /// The extension field that hosts the target group of the pairing. + type Gt: Group + ScalarMul + ScalarMulOwned; + + /// Invoke the pairing function `G1 x G2 -> Gt` without the use of precomputation and + /// other optimizations. + fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt; +} + +/// Affine representation of an elliptic curve point that can be used +/// to perform pairings. +pub trait PairingCurveAffine: CurveAffine + UncompressedEncoding { + type Pair: PairingCurveAffine; + type PairingResult: Group; + + /// Perform a pairing + fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult; +} + +/// An engine that can compute sums of pairings in an efficient way. +pub trait MultiMillerLoop: Engine { + /// The prepared form of `Self::G2Affine`. + type G2Prepared: Clone + Send + Sync + From; + + /// The type returned by `Engine::miller_loop`. + type Result: MillerLoopResult; + + /// Computes $$\sum_{i=1}^n \textbf{ML}(a_i, b_i)$$ given a series of terms + /// $$(a_1, b_1), (a_2, b_2), ..., (a_n, b_n).$$ + fn multi_miller_loop(terms: &[(&Self::G1Affine, &Self::G2Prepared)]) -> Self::Result; +} + +/// Represents results of a Miller loop, one of the most expensive portions of the pairing +/// function. +/// +/// `MillerLoopResult`s cannot be compared with each other until +/// [`MillerLoopResult::final_exponentiation`] is called, which is also expensive. +pub trait MillerLoopResult { + /// The extension field that hosts the target group of the pairing. + type Gt: Group; + + /// This performs a "final exponentiation" routine to convert the result of a Miller + /// loop into an element of [`MillerLoopResult::Gt`], so that it can be compared with + /// other elements of `Gt`. + fn final_exponentiation(&self) -> Self::Gt; +} diff --git a/arithmetic/curves/src/pasta/mod.rs b/arithmetic/curves/src/pasta/mod.rs new file mode 100644 index 0000000000..ed94d11a47 --- /dev/null +++ b/arithmetic/curves/src/pasta/mod.rs @@ -0,0 +1 @@ +pub use pasta_curves::{pallas, vesta, Ep, EpAffine, Eq, EqAffine, Fp, Fq}; diff --git a/arithmetic/curves/src/secp256k1/curve.rs b/arithmetic/curves/src/secp256k1/curve.rs new file mode 100644 index 0000000000..c3de22b935 --- /dev/null +++ b/arithmetic/curves/src/secp256k1/curve.rs @@ -0,0 +1,146 @@ +use crate::secp256k1::Fp; +use crate::secp256k1::Fq; +use crate::{Coordinates, CurveAffine, CurveAffineExt, CurveExt, Group}; +use core::cmp; +use core::fmt::Debug; +use core::iter::Sum; +use core::ops::{Add, Mul, Neg, Sub}; +use ff::{Field, PrimeField}; +use group::Curve; +use group::{prime::PrimeCurveAffine, Group as _, GroupEncoding}; +use rand::RngCore; +use serde::{Deserialize, Serialize}; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +impl Secp256k1 { + fn endomorphism_base(&self) -> Self { + unimplemented!(); + } +} + +impl group::cofactor::CofactorGroup for Secp256k1 { + type Subgroup = Secp256k1; + + fn clear_cofactor(&self) -> Self { + *self + } + + fn into_subgroup(self) -> CtOption { + CtOption::new(self, 1.into()) + } + + fn is_torsion_free(&self) -> Choice { + 1.into() + } +} + +// Reference: https://neuromancer.sk/std/secg/secp256k1 +const SECP_GENERATOR_X: Fp = Fp::from_raw([ + 0x59F2815B16F81798, + 0x029BFCDB2DCE28D9, + 0x55A06295CE870B07, + 0x79BE667EF9DCBBAC, +]); +const SECP_GENERATOR_Y: Fp = Fp::from_raw([ + 0x9C47D08FFB10D4B8, + 0xFD17B448A6855419, + 0x5DA4FBFC0E1108A8, + 0x483ADA7726A3C465, +]); +const SECP_B: Fp = Fp::from_raw([7, 0, 0, 0]); + +use crate::{ + batch_add, impl_add_binop_specify_output, impl_binops_additive, + impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, new_curve_impl, +}; + +new_curve_impl!( + (pub), + Secp256k1, + Secp256k1Affine, + Secp256k1Compressed, + 33, + Fp, + Fq, + (SECP_GENERATOR_X,SECP_GENERATOR_Y), + SECP_B, + "secp256k1", +); + +impl CurveAffineExt for Secp256k1Affine { + batch_add!(); + + fn into_coordinates(self) -> (Self::Base, Self::Base) { + (self.x, self.y) + } +} + +#[test] +fn test_curve() { + crate::tests::curve::curve_tests::(); +} + +#[test] +fn test_serialization() { + crate::tests::curve::random_serialization_test::(); +} + +#[test] +fn ecdsa_example() { + use crate::group::Curve; + use crate::{CurveAffine, FieldExt}; + use rand_core::OsRng; + + fn mod_n(x: Fp) -> Fq { + let mut x_repr = [0u8; 32]; + x_repr.copy_from_slice(x.to_repr().as_ref()); + let mut x_bytes = [0u8; 64]; + x_bytes[..32].copy_from_slice(&x_repr[..]); + Fq::from_bytes_wide(&x_bytes) + } + + let g = Secp256k1::generator(); + + for _ in 0..1000 { + // Generate a key pair + let sk = Fq::random(OsRng); + let pk = (g * sk).to_affine(); + + // Generate a valid signature + // Suppose `m_hash` is the message hash + let msg_hash = Fq::random(OsRng); + + let (r, s) = { + // Draw arandomness + let k = Fq::random(OsRng); + let k_inv = k.invert().unwrap(); + + // Calculate `r` + let r_point = (g * k).to_affine().coordinates().unwrap(); + let x = r_point.x(); + let r = mod_n(*x); + + // Calculate `s` + let s = k_inv * (msg_hash + (r * sk)); + + (r, s) + }; + + { + // Verify + let s_inv = s.invert().unwrap(); + let u_1 = msg_hash * s_inv; + let u_2 = r * s_inv; + + let v_1 = g * u_1; + let v_2 = pk * u_2; + + let r_point = (v_1 + v_2).to_affine().coordinates().unwrap(); + let x_candidate = r_point.x(); + let r_candidate = mod_n(*x_candidate); + + assert_eq!(r, r_candidate); + } + } +} diff --git a/arithmetic/curves/src/secp256k1/fp.rs b/arithmetic/curves/src/secp256k1/fp.rs new file mode 100644 index 0000000000..94ab7ac499 --- /dev/null +++ b/arithmetic/curves/src/secp256k1/fp.rs @@ -0,0 +1,283 @@ +use core::convert::TryInto; +use core::fmt; +use core::ops::{Add, Mul, Neg, Sub}; + +use ff::PrimeField; +use rand::RngCore; +use serde::{Deserialize, Serialize}; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +use pasta_curves::arithmetic::{FieldExt, Group, SqrtRatio}; + +use crate::arithmetic::{adc, mac, macx, sbb}; + +/// This represents an element of $\mathbb{F}_p$ where +/// +/// `p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f` +/// +/// is the base field of the secp256k1 curve. +// The internal representation of this type is four 64-bit unsigned +// integers in little-endian order. `Fp` values are always in +// Montgomery form; i.e., Fp(a) = aR mod p, with R = 2^256. +#[derive(Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)] +pub struct Fp(pub(crate) [u64; 4]); + +/// Constant representing the modulus +/// p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f +const MODULUS: Fp = Fp([ + 0xfffffffefffffc2f, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, +]); + +/// The modulus as u32 limbs. +#[cfg(not(target_pointer_width = "64"))] +const MODULUS_LIMBS_32: [u32; 8] = [ + 0xffff_fc2f, + 0xffff_fffe, + 0xffff_ffff, + 0xffff_ffff, + 0xffff_ffff, + 0xffff_ffff, + 0xffff_ffff, + 0xffff_ffff, +]; + +/// Constant representing the modolus as static str +const MODULUS_STR: &str = "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"; + +/// INV = -(p^{-1} mod 2^64) mod 2^64 +const INV: u64 = 0xd838091dd2253531; + +/// R = 2^256 mod p +/// 0x1000003d1 +const R: Fp = Fp([0x1000003d1, 0, 0, 0]); + +/// R^2 = 2^512 mod p +/// 0x1000007a2000e90a1 +const R2: Fp = Fp([0x000007a2000e90a1, 0x1, 0, 0]); + +/// R^3 = 2^768 mod p +/// 0x100000b73002bb1e33795f671 +const R3: Fp = Fp([0x002bb1e33795f671, 0x100000b73, 0, 0]); + +/// 1 / 2 mod p +const TWO_INV: Fp = Fp::from_raw([ + 0xffffffff7ffffe18, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0x7fffffffffffffff, +]); + +const ZETA: Fp = Fp::zero(); +const DELTA: Fp = Fp::zero(); +const ROOT_OF_UNITY_INV: Fp = Fp::zero(); + +use crate::{ + field_arithmetic, field_common, field_specific, impl_add_binop_specify_output, + impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, +}; +impl_binops_additive!(Fp, Fp); +impl_binops_multiplicative!(Fp, Fp); +field_common!( + Fp, + MODULUS, + INV, + MODULUS_STR, + TWO_INV, + ROOT_OF_UNITY_INV, + DELTA, + ZETA, + R, + R2, + R3 +); +field_arithmetic!(Fp, MODULUS, INV, dense); + +impl Fp { + pub const fn size() -> usize { + 32 + } +} + +impl ff::Field for Fp { + fn random(mut rng: impl RngCore) -> Self { + Self::from_u512([ + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + ]) + } + + fn zero() -> Self { + Self::zero() + } + + fn one() -> Self { + Self::one() + } + + fn double(&self) -> Self { + self.double() + } + + #[inline(always)] + fn square(&self) -> Self { + self.square() + } + + /// Computes the square root of this element, if it exists. + fn sqrt(&self) -> CtOption { + let tmp = self.pow(&[ + 0xffffffffbfffff0c, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0x3fffffffffffffff, + ]); + + CtOption::new(tmp, tmp.square().ct_eq(self)) + } + + /// Computes the multiplicative inverse of this element, + /// failing if the element is zero. + fn invert(&self) -> CtOption { + let tmp = self.pow_vartime([ + 0xfffffffefffffc2d, + 0xffffffffffffffff, + 0xffffffffffffffff, + 0xffffffffffffffff, + ]); + + CtOption::new(tmp, !self.ct_eq(&Self::zero())) + } + + fn pow_vartime>(&self, exp: S) -> Self { + let mut res = Self::one(); + let mut found_one = false; + for e in exp.as_ref().iter().rev() { + for i in (0..64).rev() { + if found_one { + res = res.square(); + } + + if ((*e >> i) & 1) == 1 { + found_one = true; + res *= self; + } + } + } + res + } +} + +impl ff::PrimeField for Fp { + type Repr = [u8; 32]; + + const NUM_BITS: u32 = 256; + const CAPACITY: u32 = 255; + const S: u32 = 1; + + fn from_repr(repr: Self::Repr) -> CtOption { + let mut tmp = Fp([0, 0, 0, 0]); + + tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); + tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); + tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); + tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); + + // Try to subtract the modulus + let (_, borrow) = tmp.0[0].overflowing_sub(MODULUS.0[0]); + let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow); + let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow); + let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow); + + // If the element is smaller than MODULUS then the + // subtraction will underflow, producing a borrow value + // of 0xffff...ffff. Otherwise, it'll be zero. + let is_some = (borrow as u8) & 1; + + // Convert to Montgomery form by computing + // (a.R^0 * R^2) / R = a.R + tmp *= &R2; + + CtOption::new(tmp, Choice::from(is_some)) + } + + fn to_repr(&self) -> Self::Repr { + // Turn into canonical form by computing + // (a.R) / R = a + let tmp = Fp::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]); + + let mut res = [0; 32]; + res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes()); + res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes()); + res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes()); + res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes()); + + res + } + + fn is_odd(&self) -> Choice { + Choice::from(self.to_repr()[0] & 1) + } + + fn multiplicative_generator() -> Self { + unimplemented!(); + } + + fn root_of_unity() -> Self { + unimplemented!(); + } +} + +impl SqrtRatio for Fp { + const T_MINUS1_OVER2: [u64; 4] = [0, 0, 0, 0]; + + fn get_lower_32(&self) -> u32 { + let tmp = Fp::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]); + tmp.0[0] as u32 + } +} + +#[cfg(test)] +mod test { + use super::*; + use ff::Field; + use rand_core::OsRng; + + #[test] + fn test_sqrt() { + // NB: TWO_INV is standing in as a "random" field element + let v = (Fp::TWO_INV).square().sqrt().unwrap(); + assert!(v == Fp::TWO_INV || (-v) == Fp::TWO_INV); + + for _ in 0..10000 { + let a = Fp::random(OsRng); + let mut b = a; + b = b.square(); + + let b = b.sqrt().unwrap(); + let mut negb = b; + negb = negb.neg(); + + assert!(a == b || a == negb); + } + } + + #[test] + fn test_field() { + crate::tests::field::random_field_tests::("secp256k1 base".to_string()); + } + + #[test] + fn test_serialization() { + crate::tests::field::random_serialization_test::("secp256k1 base".to_string()); + } +} diff --git a/arithmetic/curves/src/secp256k1/fq.rs b/arithmetic/curves/src/secp256k1/fq.rs new file mode 100644 index 0000000000..6c8a3201c9 --- /dev/null +++ b/arithmetic/curves/src/secp256k1/fq.rs @@ -0,0 +1,326 @@ +use core::convert::TryInto; +use core::fmt; +use core::ops::{Add, Mul, Neg, Sub}; + +use ff::PrimeField; +use rand::RngCore; +use serde::{Deserialize, Serialize}; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +use crate::arithmetic::{adc, mac, macx, sbb}; + +use pasta_curves::arithmetic::{FieldExt, Group, SqrtRatio}; + +/// This represents an element of $\mathbb{F}_q$ where +/// +/// `q = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141` +/// +/// is the scalar field of the secp256k1 curve. +// The internal representation of this type is four 64-bit unsigned +// integers in little-endian order. `Fq` values are always in +// Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256. +#[derive(Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)] +pub struct Fq(pub(crate) [u64; 4]); + +/// Constant representing the modulus +/// q = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 +const MODULUS: Fq = Fq([ + 0xbfd25e8cd0364141, + 0xbaaedce6af48a03b, + 0xfffffffffffffffe, + 0xffffffffffffffff, +]); + +/// The modulus as u32 limbs. +#[cfg(not(target_pointer_width = "64"))] +const MODULUS_LIMBS_32: [u32; 8] = [ + 0xd036_4141, + 0xbfd2_5e8c, + 0xaf48_a03b, + 0xbaae_dce6, + 0xffff_fffe, + 0xffff_ffff, + 0xffff_ffff, + 0xffff_ffff, +]; + +///Constant representing the modulus as static str +const MODULUS_STR: &str = "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"; + +/// INV = -(q^{-1} mod 2^64) mod 2^64 +const INV: u64 = 0x4b0dff665588b13f; + +/// R = 2^256 mod q +/// 0x14551231950b75fc4402da1732fc9bebf +const R: Fq = Fq([0x402da1732fc9bebf, 0x4551231950b75fc4, 0x1, 0]); + +/// R^2 = 2^512 mod q +/// 0x9d671cd581c69bc5e697f5e45bcd07c6741496c20e7cf878896cf21467d7d140 +const R2: Fq = Fq([ + 0x896cf21467d7d140, + 0x741496c20e7cf878, + 0xe697f5e45bcd07c6, + 0x9d671cd581c69bc5, +]); + +/// R^3 = 2^768 mod q +/// 0x555d800c18ef116db1b31347f1d0b2da0017648444d4322c7bc0cfe0e9ff41ed +const R3: Fq = Fq([ + 0x7bc0cfe0e9ff41ed, + 0x0017648444d4322c, + 0xb1b31347f1d0b2da, + 0x555d800c18ef116d, +]); + +/// `GENERATOR = 7 mod r` is a generator of the `q - 1` order multiplicative +/// subgroup, or in other words a primitive root of the field. +const GENERATOR: Fq = Fq::from_raw([0x07, 0x00, 0x00, 0x00]); + +/// GENERATOR^t where t * 2^s + 1 = r +/// with t odd. In other words, this +/// is a 2^s root of unity. +/// `0xc1dc060e7a91986df9879a3fbc483a898bdeab680756045992f4b5402b052f2` +const ROOT_OF_UNITY: Fq = Fq::from_raw([ + 0x992f4b5402b052f2, + 0x98bdeab680756045, + 0xdf9879a3fbc483a8, + 0xc1dc060e7a91986, +]); + +/// 1 / ROOT_OF_UNITY mod q +const ROOT_OF_UNITY_INV: Fq = Fq::from_raw([ + 0xb6fb30a0884f0d1c, + 0x77a275910aa413c3, + 0xefc7b0c75b8cbb72, + 0xfd3ae181f12d7096, +]); + +/// 1 / 2 mod q +const TWO_INV: Fq = Fq::from_raw([ + 0xdfe92f46681b20a1, + 0x5d576e7357a4501d, + 0xffffffffffffffff, + 0x7fffffffffffffff, +]); + +const ZETA: Fq = Fq::zero(); +const DELTA: Fq = Fq::zero(); + +use crate::{ + field_arithmetic, field_common, field_specific, impl_add_binop_specify_output, + impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, +}; +impl_binops_additive!(Fq, Fq); +impl_binops_multiplicative!(Fq, Fq); +field_common!( + Fq, + MODULUS, + INV, + MODULUS_STR, + TWO_INV, + ROOT_OF_UNITY_INV, + DELTA, + ZETA, + R, + R2, + R3 +); +field_arithmetic!(Fq, MODULUS, INV, dense); + +impl Fq { + pub const fn size() -> usize { + 32 + } +} + +impl ff::Field for Fq { + fn random(mut rng: impl RngCore) -> Self { + Self::from_u512([ + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + rng.next_u64(), + ]) + } + + fn zero() -> Self { + Self::zero() + } + + fn one() -> Self { + Self::one() + } + + fn double(&self) -> Self { + self.double() + } + + #[inline(always)] + fn square(&self) -> Self { + self.square() + } + + /// Computes the square root of this element, if it exists. + fn sqrt(&self) -> CtOption { + crate::arithmetic::sqrt_tonelli_shanks(self, ::T_MINUS1_OVER2) + } + + /// Computes the multiplicative inverse of this element, + /// failing if the element is zero. + fn invert(&self) -> CtOption { + let tmp = self.pow_vartime([ + 0xbfd25e8cd036413f, + 0xbaaedce6af48a03b, + 0xfffffffffffffffe, + 0xffffffffffffffff, + ]); + + CtOption::new(tmp, !self.ct_eq(&Self::zero())) + } + + fn pow_vartime>(&self, exp: S) -> Self { + let mut res = Self::one(); + let mut found_one = false; + for e in exp.as_ref().iter().rev() { + for i in (0..64).rev() { + if found_one { + res = res.square(); + } + + if ((*e >> i) & 1) == 1 { + found_one = true; + res *= self; + } + } + } + res + } +} + +impl ff::PrimeField for Fq { + type Repr = [u8; 32]; + + const NUM_BITS: u32 = 256; + const CAPACITY: u32 = 255; + const S: u32 = 6; + + fn from_repr(repr: Self::Repr) -> CtOption { + let mut tmp = Fq([0, 0, 0, 0]); + + tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap()); + tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap()); + tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap()); + tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap()); + + // Try to subtract the modulus + let (_, borrow) = tmp.0[0].overflowing_sub(MODULUS.0[0]); + let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow); + let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow); + let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow); + + // If the element is smaller than MODULUS then the + // subtraction will underflow, producing a borrow value + // of 0xffff...ffff. Otherwise, it'll be zero. + let is_some = (borrow as u8) & 1; + + // Convert to Montgomery form by computing + // (a.R^0 * R^2) / R = a.R + tmp *= &R2; + + CtOption::new(tmp, Choice::from(is_some)) + } + + fn to_repr(&self) -> Self::Repr { + // Turn into canonical form by computing + // (a.R) / R = a + let tmp = Fq::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]); + + let mut res = [0; 32]; + res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes()); + res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes()); + res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes()); + res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes()); + + res + } + + fn is_odd(&self) -> Choice { + Choice::from(self.to_repr()[0] & 1) + } + + fn multiplicative_generator() -> Self { + GENERATOR + } + + fn root_of_unity() -> Self { + ROOT_OF_UNITY + } +} + +impl SqrtRatio for Fq { + const T_MINUS1_OVER2: [u64; 4] = [ + 0x777fa4bd19a06c82, + 0xfd755db9cd5e9140, + 0xffffffffffffffff, + 0x01ffffffffffffff, + ]; + + fn get_lower_32(&self) -> u32 { + let tmp = Fq::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]); + tmp.0[0] as u32 + } +} + +#[cfg(test)] +mod test { + use super::*; + use ff::Field; + use rand_core::OsRng; + + #[test] + fn test_sqrt() { + // NB: TWO_INV is standing in as a "random" field element + let v = (Fq::TWO_INV).square().sqrt().unwrap(); + assert!(v == Fq::TWO_INV || (-v) == Fq::TWO_INV); + + for _ in 0..10000 { + let a = Fq::random(OsRng); + let mut b = a; + b = b.square(); + + let b = b.sqrt().unwrap(); + let mut negb = b; + negb = negb.neg(); + + assert!(a == b || a == negb); + } + } + + #[test] + fn test_root_of_unity() { + assert_eq!( + Fq::root_of_unity().pow_vartime([1 << Fq::S, 0, 0, 0]), + Fq::one() + ); + } + + #[test] + fn test_inv_root_of_unity() { + assert_eq!(Fq::ROOT_OF_UNITY_INV, Fq::root_of_unity().invert().unwrap()); + } + + #[test] + fn test_field() { + crate::tests::field::random_field_tests::("secp256k1 scalar".to_string()); + } + + #[test] + fn test_serialization() { + crate::tests::field::random_serialization_test::("secp256k1 scalar".to_string()); + } +} diff --git a/arithmetic/curves/src/secp256k1/mod.rs b/arithmetic/curves/src/secp256k1/mod.rs new file mode 100644 index 0000000000..edc3c0974f --- /dev/null +++ b/arithmetic/curves/src/secp256k1/mod.rs @@ -0,0 +1,7 @@ +mod curve; +mod fp; +mod fq; + +pub use curve::*; +pub use fp::*; +pub use fq::*; diff --git a/arithmetic/curves/src/serde.rs b/arithmetic/curves/src/serde.rs new file mode 100644 index 0000000000..5d0f24fc1a --- /dev/null +++ b/arithmetic/curves/src/serde.rs @@ -0,0 +1,25 @@ +use std::io::{self, Read, Write}; + +/// Trait for converting raw bytes to/from the internal representation of a type. +/// For example, field elements are represented in Montgomery form and serialized/deserialized without Montgomery reduction. +pub trait SerdeObject: Sized { + /// The purpose of unchecked functions is to read the internal memory representation + /// of a type from bytes as quickly as possible. No sanitization checks are performed + /// to ensure the bytes represent a valid object. As such this function should only be + /// used internally as an extension of machine memory. It should not be used to deserialize + /// externally provided data. + fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self; + fn from_raw_bytes(bytes: &[u8]) -> Option; + + fn to_raw_bytes(&self) -> Vec; + + /// The purpose of unchecked functions is to read the internal memory representation + /// of a type from disk as quickly as possible. No sanitization checks are performed + /// to ensure the bytes represent a valid object. This function should only be used + /// internally when some machine state cannot be kept in memory (e.g., between runs) + /// and needs to be reloaded as quickly as possible. + fn read_raw_unchecked(reader: &mut R) -> Self; + fn read_raw(reader: &mut R) -> io::Result; + + fn write_raw(&self, writer: &mut W) -> io::Result<()>; +} diff --git a/arithmetic/curves/src/tests/curve.rs b/arithmetic/curves/src/tests/curve.rs new file mode 100644 index 0000000000..e6e6797f31 --- /dev/null +++ b/arithmetic/curves/src/tests/curve.rs @@ -0,0 +1,287 @@ +#![allow(clippy::eq_op)] +use crate::{group::GroupEncoding, serde::SerdeObject}; +use ff::Field; +use group::prime::PrimeCurveAffine; +use pasta_curves::arithmetic::{CurveAffine, CurveExt}; +use rand_core::OsRng; + +pub fn curve_tests() { + is_on_curve::(); + equality::(); + projective_to_affine_affine_to_projective::(); + projective_addition::(); + mixed_addition::(); + multiplication::(); + batch_normalize::(); + serdes::(); +} + +fn serdes() { + for _ in 0..100 { + let projective_point = G::random(OsRng); + let affine_point: G::AffineExt = projective_point.into(); + let projective_repr = projective_point.to_bytes(); + let affine_repr = affine_point.to_bytes(); + + println!( + "{:?} \n{:?}", + projective_repr.as_ref(), + affine_repr.as_ref() + ); + + let projective_point_rec = G::from_bytes(&projective_repr).unwrap(); + let projective_point_rec_unchecked = G::from_bytes(&projective_repr).unwrap(); + let affine_point_rec = G::AffineExt::from_bytes(&affine_repr).unwrap(); + let affine_point_rec_unchecked = G::AffineExt::from_bytes(&affine_repr).unwrap(); + + assert_eq!(projective_point, projective_point_rec); + assert_eq!(projective_point, projective_point_rec_unchecked); + assert_eq!(affine_point, affine_point_rec); + assert_eq!(affine_point, affine_point_rec_unchecked); + } +} + +pub fn random_serialization_test() +where + G: SerdeObject, + G::AffineExt: SerdeObject, +{ + for _ in 0..100 { + let projective_point = G::random(OsRng); + let affine_point: G::AffineExt = projective_point.into(); + + let projective_bytes = projective_point.to_raw_bytes(); + let projective_point_rec = G::from_raw_bytes(&projective_bytes).unwrap(); + assert_eq!(projective_point, projective_point_rec); + let mut buf = Vec::new(); + projective_point.write_raw(&mut buf).unwrap(); + let projective_point_rec = G::read_raw(&mut &buf[..]).unwrap(); + assert_eq!(projective_point, projective_point_rec); + + let affine_bytes = affine_point.to_raw_bytes(); + let affine_point_rec = G::AffineExt::from_raw_bytes(&affine_bytes).unwrap(); + assert_eq!(affine_point, affine_point_rec); + let mut buf = Vec::new(); + affine_point.write_raw(&mut buf).unwrap(); + let affine_point_rec = G::AffineExt::read_raw(&mut &buf[..]).unwrap(); + assert_eq!(affine_point, affine_point_rec); + } +} + +fn is_on_curve() { + assert!(bool::from(G::identity().is_on_curve())); + assert!(bool::from(G::generator().is_on_curve())); + assert!(bool::from(G::identity().is_on_curve())); + assert!(bool::from(G::generator().is_on_curve())); + + for _ in 0..100 { + let point = G::random(OsRng); + assert!(bool::from(point.is_on_curve())); + let affine_point: G::AffineExt = point.into(); + assert!(bool::from(affine_point.is_on_curve())); + } +} + +fn equality() { + let a = G::generator(); + let b = G::identity(); + + assert!(a.eq(&a)); + assert!(b.eq(&b)); + assert!(a != b); + assert!(b != a); + + for _ in 0..100 { + let a = G::random(OsRng); + let b = G::random(OsRng); + + assert!(a.eq(&a)); + assert!(b.eq(&b)); + assert!(a != b); + assert!(b != a); + + let a: G::AffineExt = a.into(); + let b: G::AffineExt = b.into(); + + assert!(a.eq(&a)); + assert!(b.eq(&b)); + assert!(a != b); + assert!(b != a); + } +} + +fn projective_to_affine_affine_to_projective() { + let a = G::generator(); + let b = G::identity(); + + assert!(bool::from(G::AffineExt::from(a).is_on_curve())); + assert!(!bool::from(G::AffineExt::from(a).is_identity())); + assert!(bool::from(G::AffineExt::from(b).is_on_curve())); + assert!(bool::from(G::AffineExt::from(b).is_identity())); + + let a = G::AffineExt::generator(); + let b = G::AffineExt::identity(); + + assert!(bool::from(G::from(a).is_on_curve())); + assert!(!bool::from(G::from(a).is_identity())); + assert!(bool::from(G::from(b).is_on_curve())); + assert!(bool::from(G::from(b).is_identity())); +} + +fn projective_addition() { + let a = G::identity(); + let b = G::identity(); + let c = a + b; + assert!(bool::from(c.is_identity())); + assert!(bool::from(c.is_on_curve())); + let c = a - b; + assert!(bool::from(c.is_identity())); + assert!(bool::from(c.is_on_curve())); + + let a = G::identity(); + let a = -a; + assert!(bool::from(a.is_on_curve())); + assert!(bool::from(a.is_identity())); + + let a = G::random(OsRng); + assert!(a == a + G::identity()); + assert!(a == G::identity() + a); + assert!(-a == G::identity() - a); + + let a = G::identity(); + let a = a.double(); + assert!(bool::from(c.is_on_curve())); + assert!(bool::from(a.is_identity())); + + let a = G::generator(); + let a = a.double(); + assert!(bool::from(c.is_on_curve())); + assert_eq!(a, G::generator() + G::generator()); + + let a = G::random(OsRng); + assert!(a.double() - a == a); + + let a = G::random(OsRng); + let b = G::random(OsRng); + let c = G::random(OsRng); + assert!((a + b).eq(&(b + a))); + assert!(a - b == -(b - a)); + assert!(c + (a + b) == a + (c + b)); + assert!((a - b) - c == (a - c) - b); + + let a = G::generator().double().double(); // 4P + let b = G::generator().double(); // 2P + let c = a + b; + + let mut d = G::generator(); + for _ in 0..5 { + d += G::generator(); + } + + assert!(c == d); + assert!(!bool::from(c.is_identity())); + assert!(bool::from(c.is_on_curve())); + assert!(!bool::from(d.is_identity())); + assert!(bool::from(d.is_on_curve())); +} + +fn mixed_addition() { + let a = G::identity(); + let b = G::AffineRepr::identity(); + let c = a + b; + assert!(bool::from(c.is_identity())); + assert!(bool::from(c.is_on_curve())); + let c = a - b; + assert!(bool::from(c.is_identity())); + assert!(bool::from(c.is_on_curve())); + + let a = G::identity(); + let a = -a; + assert!(bool::from(a.is_on_curve())); + assert!(bool::from(a.is_identity())); + let a = G::AffineExt::identity(); + let a = -a; + assert!(bool::from(a.is_on_curve())); + assert!(bool::from(a.is_identity())); + + let a: G::AffineExt = G::random(OsRng).into(); + assert!(a.to_curve() == a + G::AffineExt::identity()); + + let a = G::random(OsRng); + assert!(a.double() - a == a); + + let a = G::random(OsRng); + let b: G::AffineExt = G::random(OsRng).into(); + let c0 = a + b; + let c1 = a + G::from(b); + assert_eq!(c0, c1); +} + +fn batch_normalize() { + let a = G::generator().double(); + let b = a.double(); + let c = b.double(); + + for a_identity in (0..1).map(|n| n == 1) { + for b_identity in (0..1).map(|n| n == 1) { + for c_identity in (0..1).map(|n| n == 1) { + let mut v = [a, b, c]; + if a_identity { + v[0] = G::identity() + } + if b_identity { + v[1] = G::identity() + } + if c_identity { + v[2] = G::identity() + } + + let mut t = [ + G::AffineExt::identity(), + G::AffineExt::identity(), + G::AffineExt::identity(), + ]; + let expected = [ + G::AffineExt::from(v[0]), + G::AffineExt::from(v[1]), + G::AffineExt::from(v[2]), + ]; + + G::batch_normalize(&v[..], &mut t[..]); + + assert_eq!(&t[..], &expected[..]); + } + } + } +} + +fn multiplication() { + for _ in 1..1000 { + let s1 = G::ScalarExt::random(OsRng); + let s2 = G::ScalarExt::random(OsRng); + + let t0 = G::identity() * s1; + assert!(bool::from(t0.is_identity())); + + let a = G::random(OsRng); + let t0 = a * G::ScalarExt::one(); + assert_eq!(a, t0); + + let t0 = a * G::ScalarExt::zero(); + assert!(bool::from(t0.is_identity())); + + let t0 = a * s1 + a * s2; + + let s3 = s1 + s2; + let t1 = a * s3; + + assert_eq!(t0, t1); + + let mut t0 = a * s1; + let mut t1 = a * s2; + t0 += t1; + let s3 = s1 + s2; + t1 = a * s3; + assert_eq!(t0, t1); + } +} diff --git a/arithmetic/curves/src/tests/field.rs b/arithmetic/curves/src/tests/field.rs new file mode 100644 index 0000000000..ab89a19c44 --- /dev/null +++ b/arithmetic/curves/src/tests/field.rs @@ -0,0 +1,231 @@ +use ark_std::{end_timer, start_timer}; +use ff::Field; +use rand::{RngCore, SeedableRng}; +use rand_xorshift::XorShiftRng; + +use crate::serde::SerdeObject; + +pub fn random_field_tests(type_name: String) { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + random_multiplication_tests::(&mut rng, type_name.clone()); + random_addition_tests::(&mut rng, type_name.clone()); + random_subtraction_tests::(&mut rng, type_name.clone()); + random_negation_tests::(&mut rng, type_name.clone()); + random_doubling_tests::(&mut rng, type_name.clone()); + random_squaring_tests::(&mut rng, type_name.clone()); + random_inversion_tests::(&mut rng, type_name.clone()); + random_expansion_tests::(&mut rng, type_name); + + assert_eq!(F::zero().is_zero().unwrap_u8(), 1); + { + let mut z = F::zero(); + z = z.neg(); + assert_eq!(z.is_zero().unwrap_u8(), 1); + } + + assert!(bool::from(F::zero().invert().is_none())); + + // Multiplication by zero + { + let mut a = F::random(&mut rng); + a.mul_assign(&F::zero()); + assert_eq!(a.is_zero().unwrap_u8(), 1); + } + + // Addition by zero + { + let mut a = F::random(&mut rng); + let copy = a; + a.add_assign(&F::zero()); + assert_eq!(a, copy); + } +} + +fn random_multiplication_tests(mut rng: R, type_name: String) { + let message = format!("multiplication {}", type_name); + let start = start_timer!(|| message); + for _ in 0..1000000 { + let a = F::random(&mut rng); + let b = F::random(&mut rng); + let c = F::random(&mut rng); + + let mut t0 = a; // (a * b) * c + t0.mul_assign(&b); + t0.mul_assign(&c); + + let mut t1 = a; // (a * c) * b + t1.mul_assign(&c); + t1.mul_assign(&b); + + let mut t2 = b; // (b * c) * a + t2.mul_assign(&c); + t2.mul_assign(&a); + + assert_eq!(t0, t1); + assert_eq!(t1, t2); + } + end_timer!(start); +} + +fn random_addition_tests(mut rng: R, type_name: String) { + let message = format!("addition {}", type_name); + let start = start_timer!(|| message); + for _ in 0..1000000 { + let a = F::random(&mut rng); + let b = F::random(&mut rng); + let c = F::random(&mut rng); + + let mut t0 = a; // (a + b) + c + t0.add_assign(&b); + t0.add_assign(&c); + + let mut t1 = a; // (a + c) + b + t1.add_assign(&c); + t1.add_assign(&b); + + let mut t2 = b; // (b + c) + a + t2.add_assign(&c); + t2.add_assign(&a); + + assert_eq!(t0, t1); + assert_eq!(t1, t2); + } + end_timer!(start); +} + +fn random_subtraction_tests(mut rng: R, type_name: String) { + let message = format!("subtraction {}", type_name); + let start = start_timer!(|| message); + for _ in 0..1000000 { + let a = F::random(&mut rng); + let b = F::random(&mut rng); + + let mut t0 = a; // (a - b) + t0.sub_assign(&b); + + let mut t1 = b; // (b - a) + t1.sub_assign(&a); + + let mut t2 = t0; // (a - b) + (b - a) = 0 + t2.add_assign(&t1); + + assert_eq!(t2.is_zero().unwrap_u8(), 1); + } + end_timer!(start); +} + +fn random_negation_tests(mut rng: R, type_name: String) { + let message = format!("negation {}", type_name); + let start = start_timer!(|| message); + for _ in 0..1000000 { + let a = F::random(&mut rng); + let mut b = a; + b = b.neg(); + b.add_assign(&a); + + assert_eq!(b.is_zero().unwrap_u8(), 1); + } + end_timer!(start); +} + +fn random_doubling_tests(mut rng: R, type_name: String) { + let message = format!("doubling {}", type_name); + let start = start_timer!(|| message); + for _ in 0..1000000 { + let mut a = F::random(&mut rng); + let mut b = a; + a.add_assign(&b); + b = b.double(); + + assert_eq!(a, b); + } + end_timer!(start); +} + +fn random_squaring_tests(mut rng: R, type_name: String) { + let message = format!("squaring {}", type_name); + let start = start_timer!(|| message); + for _ in 0..1000000 { + let mut a = F::random(&mut rng); + let mut b = a; + a.mul_assign(&b); + b = b.square(); + + assert_eq!(a, b); + } + end_timer!(start); +} + +fn random_inversion_tests(mut rng: R, type_name: String) { + assert!(bool::from(F::zero().invert().is_none())); + + let message = format!("inversion {}", type_name); + let start = start_timer!(|| message); + for _ in 0..1000000 { + let mut a = F::random(&mut rng); + let b = a.invert().unwrap(); // probablistically nonzero + a.mul_assign(&b); + + assert_eq!(a, F::one()); + } + end_timer!(start); +} + +fn random_expansion_tests(mut rng: R, type_name: String) { + let message = format!("expansion {}", type_name); + let start = start_timer!(|| message); + for _ in 0..1000000 { + // Compare (a + b)(c + d) and (a*c + b*c + a*d + b*d) + + let a = F::random(&mut rng); + let b = F::random(&mut rng); + let c = F::random(&mut rng); + let d = F::random(&mut rng); + + let mut t0 = a; + t0.add_assign(&b); + let mut t1 = c; + t1.add_assign(&d); + t0.mul_assign(&t1); + + let mut t2 = a; + t2.mul_assign(&c); + let mut t3 = b; + t3.mul_assign(&c); + let mut t4 = a; + t4.mul_assign(&d); + let mut t5 = b; + t5.mul_assign(&d); + + t2.add_assign(&t3); + t2.add_assign(&t4); + t2.add_assign(&t5); + + assert_eq!(t0, t2); + } + end_timer!(start); +} + +pub fn random_serialization_test(type_name: String) { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + let message = format!("serialization {}", type_name); + let start = start_timer!(|| message); + for _ in 0..1000000 { + let a = F::random(&mut rng); + let bytes = a.to_raw_bytes(); + let b = F::from_raw_bytes(&bytes).unwrap(); + assert_eq!(a, b); + let mut buf = Vec::new(); + a.write_raw(&mut buf).unwrap(); + let b = F::read_raw(&mut &buf[..]).unwrap(); + assert_eq!(a, b); + } + end_timer!(start); +} diff --git a/arithmetic/curves/src/tests/mod.rs b/arithmetic/curves/src/tests/mod.rs new file mode 100644 index 0000000000..f773c8d786 --- /dev/null +++ b/arithmetic/curves/src/tests/mod.rs @@ -0,0 +1,2 @@ +pub mod curve; +pub mod field; diff --git a/docs/.lock b/docs/.lock new file mode 100755 index 0000000000..e69de29bb2 diff --git a/docs/COPYRIGHT.txt b/docs/COPYRIGHT.txt new file mode 100644 index 0000000000..34e48134cc --- /dev/null +++ b/docs/COPYRIGHT.txt @@ -0,0 +1,46 @@ +These documentation pages include resources by third parties. This copyright +file applies only to those resources. The following third party resources are +included, and carry their own copyright notices and license terms: + +* Fira Sans (FiraSans-Regular.woff2, FiraSans-Medium.woff2): + + Copyright (c) 2014, Mozilla Foundation https://mozilla.org/ + with Reserved Font Name Fira Sans. + + Copyright (c) 2014, Telefonica S.A. + + Licensed under the SIL Open Font License, Version 1.1. + See FiraSans-LICENSE.txt. + +* rustdoc.css, main.js, and playpen.js: + + Copyright 2015 The Rust Developers. + Licensed under the Apache License, Version 2.0 (see LICENSE-APACHE.txt) or + the MIT license (LICENSE-MIT.txt) at your option. + +* normalize.css: + + Copyright (c) Nicolas Gallagher and Jonathan Neal. + Licensed under the MIT license (see LICENSE-MIT.txt). + +* Source Code Pro (SourceCodePro-Regular.ttf.woff2, + SourceCodePro-Semibold.ttf.woff2, SourceCodePro-It.ttf.woff2): + + Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), + with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark + of Adobe Systems Incorporated in the United States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceCodePro-LICENSE.txt. + +* Source Serif 4 (SourceSerif4-Regular.ttf.woff2, SourceSerif4-Bold.ttf.woff2, + SourceSerif4-It.ttf.woff2): + + Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name + 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United + States and/or other countries. + + Licensed under the SIL Open Font License, Version 1.1. + See SourceSerif4-LICENSE.md. + +This copyright file is intended to be distributed with rustdoc output. diff --git a/docs/FiraSans-LICENSE.txt b/docs/FiraSans-LICENSE.txt new file mode 100644 index 0000000000..ff9afab064 --- /dev/null +++ b/docs/FiraSans-LICENSE.txt @@ -0,0 +1,94 @@ +Digitized data copyright (c) 2012-2015, The Mozilla Foundation and Telefonica S.A. +with Reserved Font Name < Fira >, + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/docs/FiraSans-Medium.woff2 b/docs/FiraSans-Medium.woff2 new file mode 100644 index 0000000000..7a1e5fc548 Binary files /dev/null and b/docs/FiraSans-Medium.woff2 differ diff --git a/docs/FiraSans-Regular.woff2 b/docs/FiraSans-Regular.woff2 new file mode 100644 index 0000000000..e766e06ccb Binary files /dev/null and b/docs/FiraSans-Regular.woff2 differ diff --git a/docs/LICENSE-APACHE.txt b/docs/LICENSE-APACHE.txt new file mode 100644 index 0000000000..16fe87b06e --- /dev/null +++ b/docs/LICENSE-APACHE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/docs/LICENSE-MIT.txt b/docs/LICENSE-MIT.txt new file mode 100644 index 0000000000..31aa79387f --- /dev/null +++ b/docs/LICENSE-MIT.txt @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/docs/NanumBarunGothic-LICENSE.txt b/docs/NanumBarunGothic-LICENSE.txt new file mode 100644 index 0000000000..0bf46682b5 --- /dev/null +++ b/docs/NanumBarunGothic-LICENSE.txt @@ -0,0 +1,99 @@ +Copyright (c) 2010, NAVER Corporation (https://www.navercorp.com/), + +with Reserved Font Name Nanum, Naver Nanum, NanumGothic, Naver NanumGothic, +NanumMyeongjo, Naver NanumMyeongjo, NanumBrush, Naver NanumBrush, NanumPen, +Naver NanumPen, Naver NanumGothicEco, NanumGothicEco, Naver NanumMyeongjoEco, +NanumMyeongjoEco, Naver NanumGothicLight, NanumGothicLight, NanumBarunGothic, +Naver NanumBarunGothic, NanumSquareRound, NanumBarunPen, MaruBuri + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/docs/NanumBarunGothic.ttf.woff2 b/docs/NanumBarunGothic.ttf.woff2 new file mode 100644 index 0000000000..1866ad4bce Binary files /dev/null and b/docs/NanumBarunGothic.ttf.woff2 differ diff --git a/docs/SourceCodePro-It.ttf.woff2 b/docs/SourceCodePro-It.ttf.woff2 new file mode 100644 index 0000000000..462c34efcd Binary files /dev/null and b/docs/SourceCodePro-It.ttf.woff2 differ diff --git a/docs/SourceCodePro-LICENSE.txt b/docs/SourceCodePro-LICENSE.txt new file mode 100644 index 0000000000..07542572e3 --- /dev/null +++ b/docs/SourceCodePro-LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2010, 2012 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/docs/SourceCodePro-Regular.ttf.woff2 b/docs/SourceCodePro-Regular.ttf.woff2 new file mode 100644 index 0000000000..10b558e0b6 Binary files /dev/null and b/docs/SourceCodePro-Regular.ttf.woff2 differ diff --git a/docs/SourceCodePro-Semibold.ttf.woff2 b/docs/SourceCodePro-Semibold.ttf.woff2 new file mode 100644 index 0000000000..5ec64eef0e Binary files /dev/null and b/docs/SourceCodePro-Semibold.ttf.woff2 differ diff --git a/docs/SourceSerif4-Bold.ttf.woff2 b/docs/SourceSerif4-Bold.ttf.woff2 new file mode 100644 index 0000000000..db57d21455 Binary files /dev/null and b/docs/SourceSerif4-Bold.ttf.woff2 differ diff --git a/docs/SourceSerif4-It.ttf.woff2 b/docs/SourceSerif4-It.ttf.woff2 new file mode 100644 index 0000000000..1cbc021a3a Binary files /dev/null and b/docs/SourceSerif4-It.ttf.woff2 differ diff --git a/docs/SourceSerif4-LICENSE.md b/docs/SourceSerif4-LICENSE.md new file mode 100644 index 0000000000..68ea189240 --- /dev/null +++ b/docs/SourceSerif4-LICENSE.md @@ -0,0 +1,93 @@ +Copyright 2014-2021 Adobe (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/docs/SourceSerif4-Regular.ttf.woff2 b/docs/SourceSerif4-Regular.ttf.woff2 new file mode 100644 index 0000000000..2db73fe2b4 Binary files /dev/null and b/docs/SourceSerif4-Regular.ttf.woff2 differ diff --git a/docs/ayu.css b/docs/ayu.css new file mode 100644 index 0000000000..55d0e436b7 --- /dev/null +++ b/docs/ayu.css @@ -0,0 +1 @@ + :root{--main-background-color:#0f1419;--main-color:#c5c5c5;--settings-input-color:#ffb454;--sidebar-background-color:#14191f;--sidebar-background-color-hover:rgba(70,70,70,0.33);--code-block-background-color:#191f26;--scrollbar-track-background-color:transparent;--scrollbar-thumb-background-color:#5c6773;--scrollbar-color:#5c6773 #24292f;--headings-border-bottom-color:#5c6773;--border-color:#5c6773;--button-background-color:#141920;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--search-input-focused-border-color:#5c6773;--copy-path-button-color:#fff;--copy-path-img-filter:invert(70%);--copy-path-img-hover-filter:invert(100%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--type-link-color:#ffa0a5;--trait-link-color:#39afd7;--assoc-item-link-color:#39afd7;--function-link-color:#fdd687;--macro-link-color:#a37acc;--keyword-link-color:#39afd7;--mod-link-color:#39afd7;--link-color:#39afd7;--sidebar-link-color:#53b1db;--sidebar-current-link-background-color:transparent;--search-result-link-focus-background-color:#3c3c3c;--stab-background-color:#314559;--stab-code-color:#e6e1cf;--search-color:#fff;--code-highlight-kw-color:#ff7733;--code-highlight-kw-2-color:#ff7733;--code-highlight-lifetime-color:#ff7733;--code-highlight-prelude-color:#69f2df;--code-highlight-prelude-val-color:#ff7733;--code-highlight-number-color:#b8cc52;--code-highlight-string-color:#b8cc52;--code-highlight-literal-color:#ff7733;--code-highlight-attribute-color:#e6e1cf;--code-highlight-self-color:#36a3d9;--code-highlight-macro-color:#a37acc;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#788797;--code-highlight-doc-comment-color:#a1ac88;}.slider{background-color:#ccc;}.slider:before{background-color:white;}input:focus+.slider{box-shadow:0 0 0 2px #0a84ff,0 0 0 6px rgba(10,132,255,0.3);}h1,h2,h3,h4{color:white;}h1 a{color:#fff;}h4{border:none;}.docblock code{color:#ffb454;}.code-header{color:#e6e1cf;}.docblock pre>code,pre>code{color:#e6e1cf;}.item-info code{color:#e6e1cf;}.docblock a>code{color:#39AFD7 !important;}pre,.rustdoc.source .example-wrap{color:#e6e1cf;}.rust-logo{filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff);}.sidebar .current,.sidebar a:hover{color:#ffb44c;}.sidebar-elems .location{color:#ff7733;}.src-line-numbers span{color:#5c6773;}.src-line-numbers .line-highlighted{color:#708090;background-color:rgba(255,236,164,0.06);padding-right:4px;border-right:1px solid #ffb44c;}.search-results a:hover{color:#fff !important;background-color:#3c3c3c;}.search-results a:focus{color:#fff !important;background-color:#3c3c3c;}.search-results a{color:#0096cf;}.search-results a div.desc{color:#c5c5c5;}.content .item-info::before{color:#ccc;}.sidebar h2 a,.sidebar h3 a{color:white;}body.source .example-wrap pre.rust a{background:#333;}details.rustdoc-toggle>summary::before{filter:invert(100%);}#crate-search-div::after{filter:invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg) brightness(94%) contrast(94%);}#crate-search:hover,#crate-search:focus{border-color:#e0e0e0 !important;}#crate-search-div:hover::after,#crate-search-div:focus-within::after{filter:invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg) brightness(113%) contrast(76%);}.module-item .stab,.import-item .stab{color:#000;}.result-name .primitive>i,.result-name .keyword>i{color:#788797;}.src-line-numbers :target{background-color:transparent;}pre.example-line-numbers{color:#5c67736e;border:none;}a.test-arrow{font-size:100%;color:#788797;border-radius:4px;background-color:rgba(57,175,215,0.09);}a.test-arrow:hover{background-color:rgba(57,175,215,0.368);color:#c5c5c5;}:target{background:rgba(255,236,164,0.06);border-right:3px solid rgba(255,180,76,0.85);}.search-failed a{color:#39AFD7;}.tooltip::after{background-color:#314559;color:#c5c5c5;}.tooltip::before{border-color:transparent #314559 transparent transparent;}.notable-traits-tooltiptext{background-color:#314559;}#titles>button.selected{background-color:#141920 !important;border-bottom:1px solid #ffb44c !important;border-top:none;}#titles>button:not(.selected){background-color:transparent !important;border:none;}#titles>button:hover{border-bottom:1px solid rgba(242,151,24,0.3);}#titles>button>div.count{color:#888;}pre.rust .lifetime{}pre.rust .kw{}#titles>button:hover,#titles>button.selected{}pre.rust .self,pre.rust .bool-val,pre.rust .prelude-val,pre.rust .attribute{}pre.rust .kw-2,pre.rust .prelude-ty{}kbd{color:#c5c5c5;background-color:#314559;box-shadow:inset 0 -1px 0 #5c6773;}#settings-menu>a,#help-button>a{color:#fff;}#settings-menu>a img{filter:invert(100);}#settings-menu>a:hover,#settings-menu>a:focus,#help-button>a:hover,#help-button>a:focus{border-color:#e0e0e0;}.search-results .result-name span.alias{color:#c5c5c5;}.search-results .result-name span.grey{color:#999;}#source-sidebar>.title{color:#fff;}#source-sidebar div.files>a:hover,details.dir-entry summary:hover,#source-sidebar div.files>a:focus,details.dir-entry summary:focus{background-color:#14191f;color:#ffb44c;}#source-sidebar div.files>a.selected{background-color:#14191f;color:#ffb44c;}.scraped-example-list .scrape-help{border-color:#aaa;color:#eee;}.scraped-example-list .scrape-help:hover{border-color:white;color:white;}.scraped-example .example-wrap .rust span.highlight{background:rgb(91,59,1);}.scraped-example .example-wrap .rust span.highlight.focus{background:rgb(124,75,15);}.scraped-example:not(.expanded) .code-wrapper:before{background:linear-gradient(to bottom,rgba(15,20,25,1),rgba(15,20,25,0));}.scraped-example:not(.expanded) .code-wrapper:after{background:linear-gradient(to top,rgba(15,20,25,1),rgba(15,20,25,0));}.toggle-line-inner{background:#999;}.toggle-line:hover .toggle-line-inner{background:#c5c5c5;} \ No newline at end of file diff --git a/docs/clipboard.svg b/docs/clipboard.svg new file mode 100644 index 0000000000..8adbd99630 --- /dev/null +++ b/docs/clipboard.svg @@ -0,0 +1 @@ + diff --git a/docs/crates.js b/docs/crates.js new file mode 100644 index 0000000000..aed5a6d840 --- /dev/null +++ b/docs/crates.js @@ -0,0 +1 @@ +window.ALL_CRATES = ["halo2","halo2_proofs","halo2curves","poseidon"]; \ No newline at end of file diff --git a/docs/dark.css b/docs/dark.css new file mode 100644 index 0000000000..7f314acf12 --- /dev/null +++ b/docs/dark.css @@ -0,0 +1 @@ +:root{--main-background-color:#353535;--main-color:#ddd;--settings-input-color:#2196f3;--sidebar-background-color:#505050;--sidebar-background-color-hover:#676767;--code-block-background-color:#2A2A2A;--scrollbar-track-background-color:#717171;--scrollbar-thumb-background-color:rgba(32,34,37,.6);--scrollbar-color:rgba(32,34,37,.6) #5a5a5a;--headings-border-bottom-color:#d2d2d2;--border-color:#e0e0e0;--button-background-color:#f0f0f0;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--search-input-focused-border-color:#008dfd;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(65%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--type-link-color:#2dbfb8;--trait-link-color:#b78cf2;--assoc-item-link-color:#d2991d;--function-link-color:#2bab63;--macro-link-color:#09bd00;--keyword-link-color:#d2991d;--mod-link-color:#d2991d;--link-color:#d2991d;--sidebar-link-color:#fdbf35;--sidebar-current-link-background-color:#444;--search-result-link-focus-background-color:#616161;--stab-background-color:#314559;--stab-code-color:#e6e1cf;--search-color:#111;--code-highlight-kw-color:#ab8ac1;--code-highlight-kw-2-color:#769acb;--code-highlight-lifetime-color:#d97f26;--code-highlight-prelude-color:#769acb;--code-highlight-prelude-val-color:#ee6868;--code-highlight-number-color:#83a300;--code-highlight-string-color:#83a300;--code-highlight-literal-color:#ee6868;--code-highlight-attribute-color:#ee6868;--code-highlight-self-color:#ee6868;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8d8d8b;--code-highlight-doc-comment-color:#8ca375;}.slider{background-color:#ccc;}.slider:before{background-color:white;}input:focus+.slider{box-shadow:0 0 0 2px #0a84ff,0 0 0 6px rgba(10,132,255,0.3);}.rust-logo{filter:drop-shadow(1px 0 0px #fff) drop-shadow(0 1px 0 #fff) drop-shadow(-1px 0 0 #fff) drop-shadow(0 -1px 0 #fff)}.src-line-numbers span{color:#3B91E2;}.src-line-numbers .line-highlighted{background-color:#0a042f !important;}.content .item-info::before{color:#ccc;}body.source .example-wrap pre.rust a{background:#333;}details.rustdoc-toggle>summary::before{filter:invert(100%);}#crate-search-div::after{filter:invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%);}#crate-search:hover,#crate-search:focus{border-color:#2196f3 !important;}#crate-search-div:hover::after,#crate-search-div:focus-within::after{filter:invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%);}.src-line-numbers :target{background-color:transparent;}pre.example-line-numbers{border-color:#4a4949;}a.test-arrow{color:#dedede;background-color:rgba(78,139,202,0.2);}a.test-arrow:hover{background-color:#4e8bca;}:target{background-color:#494a3d;border-right:3px solid #bb7410;}.search-failed a{color:#0089ff;}.tooltip::after{background-color:#000;color:#fff;border-color:#000;}.tooltip::before{border-color:transparent black transparent transparent;}.notable-traits-tooltiptext{background-color:#111;}#titles>button:not(.selected){background-color:#252525;border-top-color:#252525;}#titles>button:hover,#titles>button.selected{border-top-color:#0089ff;background-color:#353535;}#titles>button>div.count{color:#888;}kbd{color:#000;background-color:#fafbfc;box-shadow:inset 0 -1px 0 #c6cbd1;}#settings-menu>a,#help-button>a{color:#000;}#settings-menu>a:hover,#settings-menu>a:focus,#help-button>a:hover,#help-button>a:focus{border-color:#ffb900;}.search-results .result-name span.alias{color:#fff;}.search-results .result-name span.grey{color:#ccc;}#source-sidebar div.files>a:hover,details.dir-entry summary:hover,#source-sidebar div.files>a:focus,details.dir-entry summary:focus{background-color:#444;}#source-sidebar div.files>a.selected{background-color:#333;}.scraped-example-list .scrape-help{border-color:#aaa;color:#eee;}.scraped-example-list .scrape-help:hover{border-color:white;color:white;}.scraped-example .example-wrap .rust span.highlight{background:rgb(91,59,1);}.scraped-example .example-wrap .rust span.highlight.focus{background:rgb(124,75,15);}.scraped-example:not(.expanded) .code-wrapper:before{background:linear-gradient(to bottom,rgba(53,53,53,1),rgba(53,53,53,0));}.scraped-example:not(.expanded) .code-wrapper:after{background:linear-gradient(to top,rgba(53,53,53,1),rgba(53,53,53,0));}.toggle-line-inner{background:#999;}.toggle-line:hover .toggle-line-inner{background:#c5c5c5;} \ No newline at end of file diff --git a/docs/down-arrow.svg b/docs/down-arrow.svg new file mode 100644 index 0000000000..5d76a64e92 --- /dev/null +++ b/docs/down-arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/favicon-16x16.png b/docs/favicon-16x16.png new file mode 100644 index 0000000000..ea4b45cae1 Binary files /dev/null and b/docs/favicon-16x16.png differ diff --git a/docs/favicon-32x32.png b/docs/favicon-32x32.png new file mode 100644 index 0000000000..69b8613ce1 Binary files /dev/null and b/docs/favicon-32x32.png differ diff --git a/docs/favicon.svg b/docs/favicon.svg new file mode 100644 index 0000000000..8b34b51198 --- /dev/null +++ b/docs/favicon.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/docs/halo2/all.html b/docs/halo2/all.html new file mode 100644 index 0000000000..143fbe7eff --- /dev/null +++ b/docs/halo2/all.html @@ -0,0 +1 @@ +List of all items in this crate

List of all items

\ No newline at end of file diff --git a/docs/halo2/index.html b/docs/halo2/index.html new file mode 100644 index 0000000000..2ff2b4639e --- /dev/null +++ b/docs/halo2/index.html @@ -0,0 +1 @@ +halo2 - Rust
Expand description
\ No newline at end of file diff --git a/docs/halo2/sidebar-items.js b/docs/halo2/sidebar-items.js new file mode 100644 index 0000000000..5244ce01cc --- /dev/null +++ b/docs/halo2/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/docs/halo2_proofs/all.html b/docs/halo2_proofs/all.html new file mode 100644 index 0000000000..03fc2d7336 --- /dev/null +++ b/docs/halo2_proofs/all.html @@ -0,0 +1 @@ +List of all items in this crate

List of all items

Structs

Enums

Traits

Functions

Type Definitions

\ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/fn.best_fft.html b/docs/halo2_proofs/arithmetic/fn.best_fft.html new file mode 100644 index 0000000000..c280964286 --- /dev/null +++ b/docs/halo2_proofs/arithmetic/fn.best_fft.html @@ -0,0 +1,10 @@ +best_fft in halo2_proofs::arithmetic - Rust
pub fn best_fft<G: Group>(a: &mut [G], omega: G::Scalar, log_n: u32)
Expand description

Performs a radix-$2$ Fast-Fourier Transformation (FFT) on a vector of size +$n = 2^k$, when provided log_n = $k$ and an element of multiplicative +order $n$ called omega ($\omega$). The result is that the vector a, when +interpreted as the coefficients of a polynomial of degree $n - 1$, is +transformed into the evaluations of this polynomial at each of the $n$ +distinct powers of $\omega$. This transformation is invertible by providing +$\omega^{-1}$ in place of $\omega$ and dividing each resulting field element +by $n$.

+

This will use multithreading if beneficial.

+
\ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/fn.best_multiexp.html b/docs/halo2_proofs/arithmetic/fn.best_multiexp.html new file mode 100644 index 0000000000..8df2337cc3 --- /dev/null +++ b/docs/halo2_proofs/arithmetic/fn.best_multiexp.html @@ -0,0 +1,4 @@ +best_multiexp in halo2_proofs::arithmetic - Rust
pub fn best_multiexp<C: CurveAffine>(
    coeffs: &[C::Scalar],
    bases: &[C]
) -> C::Curve
Expand description

Performs a multi-exponentiation operation.

+

This function will panic if coeffs and bases have a different length.

+

This will use multithreading if beneficial.

+
\ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/fn.compute_inner_product.html b/docs/halo2_proofs/arithmetic/fn.compute_inner_product.html new file mode 100644 index 0000000000..151ef55bbe --- /dev/null +++ b/docs/halo2_proofs/arithmetic/fn.compute_inner_product.html @@ -0,0 +1,3 @@ +compute_inner_product in halo2_proofs::arithmetic - Rust
pub fn compute_inner_product<F: Field>(a: &[F], b: &[F]) -> F
Expand description

This computes the inner product of two vectors a and b.

+

This function will panic if the two vectors are not the same size.

+
\ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/fn.eval_polynomial.html b/docs/halo2_proofs/arithmetic/fn.eval_polynomial.html new file mode 100644 index 0000000000..1c21ecc802 --- /dev/null +++ b/docs/halo2_proofs/arithmetic/fn.eval_polynomial.html @@ -0,0 +1,2 @@ +eval_polynomial in halo2_proofs::arithmetic - Rust
pub fn eval_polynomial<F: Field>(poly: &[F], point: F) -> F
Expand description

This evaluates a provided polynomial (in coefficient form) at point.

+
\ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/fn.g_to_lagrange.html b/docs/halo2_proofs/arithmetic/fn.g_to_lagrange.html new file mode 100644 index 0000000000..b640a76b61 --- /dev/null +++ b/docs/halo2_proofs/arithmetic/fn.g_to_lagrange.html @@ -0,0 +1,2 @@ +g_to_lagrange in halo2_proofs::arithmetic - Rust
pub fn g_to_lagrange<C: CurveAffine>(
    g_projective: Vec<C::Curve>,
    k: u32
) -> Vec<C>
Expand description

Convert coefficient bases group elements to lagrange basis by inverse FFT.

+
\ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/fn.kate_division.html b/docs/halo2_proofs/arithmetic/fn.kate_division.html new file mode 100644 index 0000000000..813abdd7e7 --- /dev/null +++ b/docs/halo2_proofs/arithmetic/fn.kate_division.html @@ -0,0 +1,3 @@ +kate_division in halo2_proofs::arithmetic - Rust
pub fn kate_division<'a, F: Field, I: IntoIterator<Item = &'a F>>(
    a: I,
    b: F
) -> Vec<F>where
    I::IntoIter: DoubleEndedIterator + ExactSizeIterator,
Expand description

Divides polynomial a in X by X - b with +no remainder.

+
\ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/fn.lagrange_interpolate.html b/docs/halo2_proofs/arithmetic/fn.lagrange_interpolate.html new file mode 100644 index 0000000000..5c3d77b87b --- /dev/null +++ b/docs/halo2_proofs/arithmetic/fn.lagrange_interpolate.html @@ -0,0 +1,4 @@ +lagrange_interpolate in halo2_proofs::arithmetic - Rust
pub fn lagrange_interpolate<F: FieldExt>(points: &[F], evals: &[F]) -> Vec<F>
Expand description

Returns coefficients of an n - 1 degree polynomial given a set of n points +and their evaluations. This function will panic if two values in points +are the same.

+
\ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/fn.parallelize.html b/docs/halo2_proofs/arithmetic/fn.parallelize.html new file mode 100644 index 0000000000..3fd760a2f1 --- /dev/null +++ b/docs/halo2_proofs/arithmetic/fn.parallelize.html @@ -0,0 +1,3 @@ +parallelize in halo2_proofs::arithmetic - Rust
pub fn parallelize<T: Send, F: Fn(&mut [T], usize) + Send + Sync + Clone>(
    v: &mut [T],
    f: F
)
Expand description

This simple utility function will parallelize an operation that is to be +performed over a mutable slice.

+
\ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/fn.recursive_butterfly_arithmetic.html b/docs/halo2_proofs/arithmetic/fn.recursive_butterfly_arithmetic.html new file mode 100644 index 0000000000..f1def7bd8d --- /dev/null +++ b/docs/halo2_proofs/arithmetic/fn.recursive_butterfly_arithmetic.html @@ -0,0 +1,2 @@ +recursive_butterfly_arithmetic in halo2_proofs::arithmetic - Rust
pub fn recursive_butterfly_arithmetic<G: Group>(
    a: &mut [G],
    n: usize,
    twiddle_chunk: usize,
    twiddles: &[G::Scalar]
)
Expand description

This perform recursive butterfly arithmetic

+
\ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/fn.small_multiexp.html b/docs/halo2_proofs/arithmetic/fn.small_multiexp.html new file mode 100644 index 0000000000..7a696469d5 --- /dev/null +++ b/docs/halo2_proofs/arithmetic/fn.small_multiexp.html @@ -0,0 +1,3 @@ +small_multiexp in halo2_proofs::arithmetic - Rust
pub fn small_multiexp<C: CurveAffine>(
    coeffs: &[C::Scalar],
    bases: &[C]
) -> C::Curve
Expand description

Performs a small multi-exponentiation operation. +Uses the double-and-add algorithm with doublings shared across points.

+
\ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/index.html b/docs/halo2_proofs/arithmetic/index.html new file mode 100644 index 0000000000..d968de0788 --- /dev/null +++ b/docs/halo2_proofs/arithmetic/index.html @@ -0,0 +1,21 @@ +halo2_proofs::arithmetic - Rust
Expand description

This module provides common utilities, traits and structures for group, +field and polynomial arithmetic.

+

Traits

This trait is the affine counterpart to Curve and is used for +serialization, storage in memory, and inspection of $x$ and $y$ coordinates.
This trait is a common interface for dealing with elements of an elliptic +curve group in a “projective” form, where that arithmetic is usually more +efficient.
This trait represents an element of a field.
This trait is a common interface for dealing with elements of a finite +field.
This represents an element of a group with basic operations that can be +performed. This allows an FFT implementation (for example) to operate +generically over either a field or elliptic curve group.

Functions

Performs a radix-$2$ Fast-Fourier Transformation (FFT) on a vector of size +$n = 2^k$, when provided log_n = $k$ and an element of multiplicative +order $n$ called omega ($\omega$). The result is that the vector a, when +interpreted as the coefficients of a polynomial of degree $n - 1$, is +transformed into the evaluations of this polynomial at each of the $n$ +distinct powers of $\omega$. This transformation is invertible by providing +$\omega^{-1}$ in place of $\omega$ and dividing each resulting field element +by $n$.
Performs a multi-exponentiation operation.
This computes the inner product of two vectors a and b.
This evaluates a provided polynomial (in coefficient form) at point.
Convert coefficient bases group elements to lagrange basis by inverse FFT.
Divides polynomial a in X by X - b with +no remainder.
Returns coefficients of an n - 1 degree polynomial given a set of n points +and their evaluations. This function will panic if two values in points +are the same.
This simple utility function will parallelize an operation that is to be +performed over a mutable slice.
This perform recursive butterfly arithmetic
Performs a small multi-exponentiation operation. +Uses the double-and-add algorithm with doublings shared across points.
\ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/sidebar-items.js b/docs/halo2_proofs/arithmetic/sidebar-items.js new file mode 100644 index 0000000000..fbc5f52a53 --- /dev/null +++ b/docs/halo2_proofs/arithmetic/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":[["best_fft","Performs a radix-$2$ Fast-Fourier Transformation (FFT) on a vector of size $n = 2^k$, when provided `log_n` = $k$ and an element of multiplicative order $n$ called `omega` ($\\omega$). The result is that the vector `a`, when interpreted as the coefficients of a polynomial of degree $n - 1$, is transformed into the evaluations of this polynomial at each of the $n$ distinct powers of $\\omega$. This transformation is invertible by providing $\\omega^{-1}$ in place of $\\omega$ and dividing each resulting field element by $n$."],["best_multiexp","Performs a multi-exponentiation operation."],["compute_inner_product","This computes the inner product of two vectors `a` and `b`."],["eval_polynomial","This evaluates a provided polynomial (in coefficient form) at `point`."],["g_to_lagrange","Convert coefficient bases group elements to lagrange basis by inverse FFT."],["kate_division","Divides polynomial `a` in `X` by `X - b` with no remainder."],["lagrange_interpolate","Returns coefficients of an n - 1 degree polynomial given a set of n points and their evaluations. This function will panic if two values in `points` are the same."],["parallelize","This simple utility function will parallelize an operation that is to be performed over a mutable slice."],["recursive_butterfly_arithmetic","This perform recursive butterfly arithmetic"],["small_multiexp","Performs a small multi-exponentiation operation. Uses the double-and-add algorithm with doublings shared across points."]],"trait":[["CurveAffine","This trait is the affine counterpart to `Curve` and is used for serialization, storage in memory, and inspection of $x$ and $y$ coordinates."],["CurveExt","This trait is a common interface for dealing with elements of an elliptic curve group in a “projective” form, where that arithmetic is usually more efficient."],["Field","This trait represents an element of a field."],["FieldExt","This trait is a common interface for dealing with elements of a finite field."],["Group","This represents an element of a group with basic operations that can be performed. This allows an FFT implementation (for example) to operate generically over either a field or elliptic curve group."]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/trait.CurveAffine.html b/docs/halo2_proofs/arithmetic/trait.CurveAffine.html new file mode 100644 index 0000000000..382038eb5d --- /dev/null +++ b/docs/halo2_proofs/arithmetic/trait.CurveAffine.html @@ -0,0 +1,25 @@ +CurveAffine in halo2_proofs::arithmetic - Rust
pub trait CurveAffine: PrimeCurveAffine<Scalar = Self::ScalarExt, Curve = Self::CurveExt> + Default + Add<Self, Output = Self::Curve> + Sub<Self, Output = Self::Curve> + ConditionallySelectable + ConstantTimeEq + From<Self::Curve> {
+    type ScalarExt: FieldExt;
+    type Base: FieldExt;
+    type CurveExt: CurveExt<AffineExt = Self, ScalarExt = Self::ScalarExt>;
+
+    fn coordinates(&self) -> CtOption<Coordinates<Self>>;
+    fn from_xy(x: Self::Base, y: Self::Base) -> CtOption<Self>;
+    fn is_on_curve(&self) -> Choice;
+    fn a() -> Self::Base;
+    fn b() -> Self::Base;
+}
Expand description

This trait is the affine counterpart to Curve and is used for +serialization, storage in memory, and inspection of $x$ and $y$ coordinates.

+

Requires the alloc feature flag because of hash_to_curve on CurveExt.

+

Required Associated Types

The scalar field of this elliptic curve.

+

The base field over which this elliptic curve is constructed.

+

The projective form of the curve

+

Required Methods

Gets the coordinates of this point.

+

Returns None if this is the identity.

+

Obtains a point given $(x, y)$, failing if it is not on the +curve.

+

Returns whether or not this element is on the curve; should +always be true unless an “unchecked” API was used.

+

Returns the curve constant $a$.

+

Returns the curve constant $b$.

+

Implementations on Foreign Types

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/trait.CurveExt.html b/docs/halo2_proofs/arithmetic/trait.CurveExt.html new file mode 100644 index 0000000000..0316606ee3 --- /dev/null +++ b/docs/halo2_proofs/arithmetic/trait.CurveExt.html @@ -0,0 +1,46 @@ +CurveExt in halo2_proofs::arithmetic - Rust
pub trait CurveExt: PrimeCurve<Affine = Self::AffineExt, Scalar = Self::ScalarExt> + Group + Default + ConditionallySelectable + ConstantTimeEq + From<Self::Affine> + Group<Scalar = Self::Scalar> {
+    type ScalarExt: FieldExt;
+    type Base: FieldExt;
+    type AffineExt: CurveAffine<CurveExt = Self, ScalarExt = Self::ScalarExt, Output = Self, Output = Self> + Mul<Self::ScalarExt>;
+
+    const CURVE_ID: &'static str;
+
+    fn endo(&self) -> Self;
+    fn jacobian_coordinates(&self) -> (Self::Base, Self::Base, Self::Base);
+    fn hash_to_curve(domain_prefix: &'a str) -> Box<dyn Fn(&[u8]) + 'a, Global>;
+    fn is_on_curve(&self) -> Choice;
+    fn a() -> Self::Base;
+    fn b() -> Self::Base;
+    fn new_jacobian(x: Self::Base, y: Self::Base, z: Self::Base) -> CtOption<Self>;
+}
Expand description

This trait is a common interface for dealing with elements of an elliptic +curve group in a “projective” form, where that arithmetic is usually more +efficient.

+

Requires the alloc feature flag because of hash_to_curve.

+

Required Associated Types

The scalar field of this elliptic curve.

+

The base field over which this elliptic curve is constructed.

+

The affine version of the curve

+

Required Associated Constants

CURVE_ID used for hash-to-curve.

+

Required Methods

Apply the curve endomorphism by multiplying the x-coordinate +by an element of multiplicative order 3.

+

Return the Jacobian coordinates of this point.

+

Requests a hasher that accepts messages and returns near-uniformly +distributed elements in the group, given domain prefix domain_prefix.

+

This method is suitable for use as a random oracle.

+
Example
+
use pasta_curves::arithmetic::CurveExt;
+fn pedersen_commitment<C: CurveExt>(
+    x: C::ScalarExt,
+    r: C::ScalarExt,
+) -> C::Affine {
+    let hasher = C::hash_to_curve("z.cash:example_pedersen_commitment");
+    let g = hasher(b"g");
+    let h = hasher(b"h");
+    (g * x + &(h * r)).to_affine()
+}
+

Returns whether or not this element is on the curve; should +always be true unless an “unchecked” API was used.

+

Returns the curve constant a.

+

Returns the curve constant b.

+

Obtains a point given Jacobian coordinates $X : Y : Z$, failing +if the coordinates are not on the curve.

+

Implementations on Foreign Types

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/trait.Field.html b/docs/halo2_proofs/arithmetic/trait.Field.html new file mode 100644 index 0000000000..3c8d7ec8b5 --- /dev/null +++ b/docs/halo2_proofs/arithmetic/trait.Field.html @@ -0,0 +1,53 @@ +Field in halo2_proofs::arithmetic - Rust
pub trait Field: 'static + Sized + Eq + Copy + Clone + Default + Send + Sync + Debug + ConditionallySelectable + ConstantTimeEq + for<'a> Add<Self, Output = Self, Output = Self> + for<'a> Sub<Self, Output = Self, Output = Self> + for<'a> Mul<Self, Output = Self, Output = Self> + Neg<Output = Self> + for<'a> Add<&'a Self> + for<'a> Mul<&'a Self> + for<'a> Sub<&'a Self> + MulAssign<Self> + AddAssign<Self> + SubAssign<Self> + for<'a> MulAssign<&'a Self> + for<'a> AddAssign<&'a Self> + for<'a> SubAssign<&'a Self> {
+    fn random(rng: impl RngCore) -> Self;
+    fn zero() -> Self;
+    fn one() -> Self;
+    fn square(&self) -> Self;
+    fn double(&self) -> Self;
+    fn invert(&self) -> CtOption<Self>;
+    fn sqrt(&self) -> CtOption<Self>;
+
+    fn is_zero(&self) -> Choice { ... }
+    fn is_zero_vartime(&self) -> bool { ... }
+    fn cube(&self) -> Self { ... }
+    fn pow_vartime<S>(&self, exp: S) -> Self
    where
        S: AsRef<[u64]>
, + { ... } +}
Expand description

This trait represents an element of a field.

+

Required Methods

Returns an element chosen uniformly at random using a user-provided RNG.

+

Returns the zero element of the field, the additive identity.

+

Returns the one element of the field, the multiplicative identity.

+

Squares this element.

+

Doubles this element.

+

Computes the multiplicative inverse of this element, +failing if the element is zero.

+

Returns the square root of the field element, if it is +quadratic residue.

+

Provided Methods

Returns true iff this element is zero.

+

Returns true iff this element is zero.

+
Security
+

This method provides no constant-time guarantees. Implementors of the +Field trait may optimise this method using non-constant-time logic.

+

Cubes this element.

+

Exponentiates self by exp, where exp is a little-endian order +integer exponent.

+

This operation is variable time with respect to the exponent. If the +exponent is fixed, this operation is effectively constant time.

+

Implementations on Foreign Types

Computes the square root of this element, if it exists.

+

Computes the multiplicative inverse of this element, +failing if the element is zero.

+

Computes the square root of this element, if it exists.

+

Computes the multiplicative inverse of this element, +failing if the element is zero.

+

Computes the square root of this element, if it exists.

+

Computes the multiplicative inverse of this element, +failing if the element is zero.

+

Computes the square root of this element, if it exists.

+

Computes the multiplicative inverse of this element, +failing if the element is zero.

+

Computes the square root of this element, if it exists.

+

Computes the multiplicative inverse of this element, +failing if the element is zero.

+

Computes the square root of this element, if it exists.

+

Computes the multiplicative inverse of this element, +failing if the element is zero.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/trait.FieldExt.html b/docs/halo2_proofs/arithmetic/trait.FieldExt.html new file mode 100644 index 0000000000..350c404aa0 --- /dev/null +++ b/docs/halo2_proofs/arithmetic/trait.FieldExt.html @@ -0,0 +1,48 @@ +FieldExt in halo2_proofs::arithmetic - Rust
pub trait FieldExt: SqrtRatio + From<bool> + Ord + Group<Scalar = Self> {
+    const MODULUS: &'static str;
+    const ROOT_OF_UNITY_INV: Self;
+    const DELTA: Self;
+    const TWO_INV: Self;
+    const ZETA: Self;
+
+    fn from_u128(v: u128) -> Self;
+    fn from_bytes_wide(bytes: &[u8; 64]) -> Self;
+    fn get_lower_128(&self) -> u128;
+
+    fn pow(&self, by: &[u64; 4]) -> Self { ... }
+}
Expand description

This trait is a common interface for dealing with elements of a finite +field.

+

Required Associated Constants

Modulus of the field written as a string for display purposes

+

Inverse of PrimeField::root_of_unity()

+

Generator of the $t-order$ multiplicative subgroup

+

Inverse of $2$ in the field.

+

Element of multiplicative order $3$.

+

Required Methods

Obtains a field element congruent to the integer v.

+

Obtains a field element that is congruent to the provided little endian +byte representation of an integer.

+

Gets the lower 128 bits of this field element when expressed +canonically.

+

Provided Methods

Exponentiates self by by, where by is a little-endian order +integer exponent.

+

Implementations on Foreign Types

Converts a 512-bit little endian integer into +a $field by reducing by the modulus.

+

Converts a 512-bit little endian integer into +a $field by reducing by the modulus.

+

Converts a 512-bit little endian integer into +a $field by reducing by the modulus.

+

Converts a 512-bit little endian integer into +a $field by reducing by the modulus.

+

Converts a 512-bit little endian integer into +a Fq by reducing by the modulus.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/arithmetic/trait.Group.html b/docs/halo2_proofs/arithmetic/trait.Group.html new file mode 100644 index 0000000000..becf16f982 --- /dev/null +++ b/docs/halo2_proofs/arithmetic/trait.Group.html @@ -0,0 +1,17 @@ +Group in halo2_proofs::arithmetic - Rust
pub trait Group: 'static + Copy + Clone + Send + Sync {
+    type Scalar: FieldExt;
+
+    fn group_zero() -> Self;
+    fn group_add(&mut self, rhs: &Self);
+    fn group_sub(&mut self, rhs: &Self);
+    fn group_scale(&mut self, by: &Self::Scalar);
+}
Expand description

This represents an element of a group with basic operations that can be +performed. This allows an FFT implementation (for example) to operate +generically over either a field or elliptic curve group.

+

Required Associated Types

The group is assumed to be of prime order $p$. Scalar is the +associated scalar field of size $p$.

+

Required Methods

Returns the additive identity of the group.

+

Adds rhs to this group element.

+

Subtracts rhs from this group element.

+

Scales this group element by a scalar.

+

Implementations on Foreign Types

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/floor_planner/index.html b/docs/halo2_proofs/circuit/floor_planner/index.html new file mode 100644 index 0000000000..8e0faffa5f --- /dev/null +++ b/docs/halo2_proofs/circuit/floor_planner/index.html @@ -0,0 +1,2 @@ +halo2_proofs::circuit::floor_planner - Rust
Expand description

Implementations of common circuit floor planners.

+
\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/floor_planner/sidebar-items.js b/docs/halo2_proofs/circuit/floor_planner/sidebar-items.js new file mode 100644 index 0000000000..5244ce01cc --- /dev/null +++ b/docs/halo2_proofs/circuit/floor_planner/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {}; \ No newline at end of file diff --git a/docs/halo2_proofs/circuit/floor_planner/single_pass/struct.SimpleFloorPlanner.html b/docs/halo2_proofs/circuit/floor_planner/single_pass/struct.SimpleFloorPlanner.html new file mode 100644 index 0000000000..1dc33f81ee --- /dev/null +++ b/docs/halo2_proofs/circuit/floor_planner/single_pass/struct.SimpleFloorPlanner.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../halo2_proofs/circuit/struct.SimpleFloorPlanner.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/circuit/index.html b/docs/halo2_proofs/circuit/index.html new file mode 100644 index 0000000000..bd66c76c94 --- /dev/null +++ b/docs/halo2_proofs/circuit/index.html @@ -0,0 +1,4 @@ +halo2_proofs::circuit - Rust
Expand description

Traits and structs for implementing circuit components.

+

Modules

Implementations of common circuit floor planners.
Implementations of common circuit layouters.

Structs

An assigned cell.
A pointer to a cell within a circuit.
This is a “namespaced” layouter which borrows a Layouter (pushing a namespace +context) and, when dropped, pops out of the namespace context.
A region of the circuit in which a Chip can assign cells.
Index of a region in a layouter
Starting row of a region in a layouter
A simple FloorPlanner that performs minimal optimizations.
A lookup table in the circuit.
A value that might exist within a circuit.

Traits

A chip implements a set of instructions that can be used by gadgets.
A layout strategy within a circuit. The layouter is chip-agnostic and applies its +strategy to the context and config it is given.
\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/layouter/enum.RegionColumn.html b/docs/halo2_proofs/circuit/layouter/enum.RegionColumn.html new file mode 100644 index 0000000000..79fae2cf3b --- /dev/null +++ b/docs/halo2_proofs/circuit/layouter/enum.RegionColumn.html @@ -0,0 +1,36 @@ +RegionColumn in halo2_proofs::circuit::layouter - Rust
pub enum RegionColumn {
+    Column(Column<Any>),
+    Selector(Selector),
+}
Expand description

The virtual column involved in a region. This includes concrete columns, +as well as selectors that are not concrete columns at this stage.

+

Variants

Column(Column<Any>)

Concrete column

+

Selector(Selector)

Virtual column representing a (boolean) selector

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
This method returns an Ordering between self and other. Read more
Compares and returns the maximum of two values. Read more
Compares and returns the minimum of two values. Read more
Restrict a value to a certain interval. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
This method returns an ordering between self and other values if one exists. Read more
This method tests less than (for self and other) and is used by the < operator. Read more
This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
This method tests greater than (for self and other) and is used by the > operator. Read more
This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/layouter/index.html b/docs/halo2_proofs/circuit/layouter/index.html new file mode 100644 index 0000000000..e5a04abd89 --- /dev/null +++ b/docs/halo2_proofs/circuit/layouter/index.html @@ -0,0 +1,4 @@ +halo2_proofs::circuit::layouter - Rust
Expand description

Implementations of common circuit layouters.

+

Structs

The shape of a region. For a region at a certain index, we track +the set of columns it uses as well as the number of rows it uses.

Enums

The virtual column involved in a region. This includes concrete columns, +as well as selectors that are not concrete columns at this stage.

Traits

Helper trait for implementing a custom Layouter.
Helper trait for implementing a custom Layouter.
\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/layouter/sidebar-items.js b/docs/halo2_proofs/circuit/layouter/sidebar-items.js new file mode 100644 index 0000000000..d578694db1 --- /dev/null +++ b/docs/halo2_proofs/circuit/layouter/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":[["RegionColumn","The virtual column involved in a region. This includes concrete columns, as well as selectors that are not concrete columns at this stage."]],"struct":[["RegionShape","The shape of a region. For a region at a certain index, we track the set of columns it uses as well as the number of rows it uses."]],"trait":[["RegionLayouter","Helper trait for implementing a custom `Layouter`."],["TableLayouter","Helper trait for implementing a custom `Layouter`."]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/circuit/layouter/struct.RegionShape.html b/docs/halo2_proofs/circuit/layouter/struct.RegionShape.html new file mode 100644 index 0000000000..61e17c74f7 --- /dev/null +++ b/docs/halo2_proofs/circuit/layouter/struct.RegionShape.html @@ -0,0 +1,27 @@ +RegionShape in halo2_proofs::circuit::layouter - Rust
pub struct RegionShape { /* private fields */ }
Expand description

The shape of a region. For a region at a certain index, we track +the set of columns it uses as well as the number of rows it uses.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/layouter/trait.RegionLayouter.html b/docs/halo2_proofs/circuit/layouter/trait.RegionLayouter.html new file mode 100644 index 0000000000..5db9df9f25 --- /dev/null +++ b/docs/halo2_proofs/circuit/layouter/trait.RegionLayouter.html @@ -0,0 +1,53 @@ +RegionLayouter in halo2_proofs::circuit::layouter - Rust
pub trait RegionLayouter<F: Field>: Debug {
+    fn enable_selector<'v>(
        &'v mut self,
        annotation: &'v (dyn Fn() -> String + 'v),
        selector: &Selector,
        offset: usize
    ) -> Result<(), Error>; + fn assign_advice<'b, 'v>(
        &'b mut self,
        column: Column<Advice>,
        offset: usize,
        to: Value<Assigned<F>>
    ) -> Result<AssignedCell<&'v Assigned<F>, F>, Error>; + fn assign_advice_from_constant<'v>(
        &'v mut self,
        annotation: &'v (dyn Fn() -> String + 'v),
        column: Column<Advice>,
        offset: usize,
        constant: Assigned<F>
    ) -> Result<Cell, Error>; + fn assign_advice_from_instance<'v>(
        &mut self,
        annotation: &'v (dyn Fn() -> String + 'v),
        instance: Column<Instance>,
        row: usize,
        advice: Column<Advice>,
        offset: usize
    ) -> Result<(Cell, Value<F>), Error>; + fn assign_fixed(
        &mut self,
        column: Column<Fixed>,
        offset: usize,
        to: Assigned<F>
    ) -> Cell; + fn constrain_constant(
        &mut self,
        cell: Cell,
        constant: Assigned<F>
    ) -> Result<(), Error>; + fn constrain_equal(&mut self, left: &Cell, right: &Cell); + fn get_challenge(&self, challenge: Challenge) -> Value<F>; + fn next_phase(&mut self); +}
Expand description

Helper trait for implementing a custom Layouter.

+

This trait is used for implementing region assignments:

+ +
impl<'a, F: FieldExt, C: Chip<F>, CS: Assignment<F> + 'a> Layouter<C> for MyLayouter<'a, C, CS> {
+    fn assign_region(
+        &mut self,
+        assignment: impl FnOnce(Region<'_, F, C>) -> Result<(), Error>,
+    ) -> Result<(), Error> {
+        let region_index = self.regions.len();
+        self.regions.push(self.current_gate);
+
+        let mut region = MyRegion::new(self, region_index);
+        {
+            let region: &mut dyn RegionLayouter<F> = &mut region;
+            assignment(region.into())?;
+        }
+        self.current_gate += region.row_count;
+
+        Ok(())
+    }
+}
+

TODO: It would be great if we could constrain the columns in these types to be +“logical” columns that are guaranteed to correspond to the chip (and have come from +Chip::Config).

+

Required Methods

Enables a selector at the given offset.

+

Assign an advice column value (witness)

+

Assigns a constant value to the column advice at offset within this region.

+

The constant value will be assigned to a cell within one of the fixed columns +configured via ConstraintSystem::enable_constant.

+

Returns the advice cell that has been equality-constrained to the constant.

+

Assign the value of the instance column’s cell at absolute location +row to the column advice at offset within this region.

+

Returns the advice cell, and its value if known.

+

Assign a fixed value

+

Constrains a cell to have a constant value.

+

Returns an error if the cell is in a column where equality has not been enabled.

+

Constraint two cells to have the same value.

+

Returns an error if either of the cells is not within the given permutation.

+

Queries the value of the given challenge.

+

Returns Value::unknown() if the current synthesis phase is before the challenge can be queried.

+

Commit advice columns in current phase and squeeze challenges. +This can be called DURING synthesize.

+

Trait Implementations

Converts to this type from the input type.

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/layouter/trait.TableLayouter.html b/docs/halo2_proofs/circuit/layouter/trait.TableLayouter.html new file mode 100644 index 0000000000..9293596b1e --- /dev/null +++ b/docs/halo2_proofs/circuit/layouter/trait.TableLayouter.html @@ -0,0 +1,7 @@ +TableLayouter in halo2_proofs::circuit::layouter - Rust
pub trait TableLayouter<F: Field>: Debug {
+    fn assign_cell<'v>(
        &'v mut self,
        annotation: &'v (dyn Fn() -> String + 'v),
        column: TableColumn,
        offset: usize,
        to: &'v mut (dyn FnMut() -> Value<Assigned<F>> + 'v)
    ) -> Result<(), Error>; +}
Expand description

Helper trait for implementing a custom Layouter.

+

This trait is used for implementing table assignments.

+

Required Methods

Assigns a fixed value to a table cell.

+

Returns an error if the table cell has already been assigned to.

+

Trait Implementations

Converts to this type from the input type.

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/sidebar-items.js b/docs/halo2_proofs/circuit/sidebar-items.js new file mode 100644 index 0000000000..2f936eaca7 --- /dev/null +++ b/docs/halo2_proofs/circuit/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":[["floor_planner","Implementations of common circuit floor planners."],["layouter","Implementations of common circuit layouters."]],"struct":[["AssignedCell","An assigned cell."],["Cell","A pointer to a cell within a circuit."],["NamespacedLayouter","This is a “namespaced” layouter which borrows a `Layouter` (pushing a namespace context) and, when dropped, pops out of the namespace context."],["Region","A region of the circuit in which a [`Chip`] can assign cells."],["RegionIndex","Index of a region in a layouter"],["RegionStart","Starting row of a region in a layouter"],["SimpleFloorPlanner","A simple [`FloorPlanner`] that performs minimal optimizations."],["Table","A lookup table in the circuit."],["Value","A value that might exist within a circuit."]],"trait":[["Chip","A chip implements a set of instructions that can be used by gadgets."],["Layouter","A layout strategy within a circuit. The layouter is chip-agnostic and applies its strategy to the context and config it is given."]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/circuit/struct.AssignedCell.html b/docs/halo2_proofs/circuit/struct.AssignedCell.html new file mode 100644 index 0000000000..9f119002cb --- /dev/null +++ b/docs/halo2_proofs/circuit/struct.AssignedCell.html @@ -0,0 +1,35 @@ +AssignedCell in halo2_proofs::circuit - Rust
pub struct AssignedCell<V, F: Field> { /* private fields */ }
Expand description

An assigned cell.

+

Implementations

Returns the value of the AssignedCell.

+

Returns the cell.

+

Returns the field element value of the AssignedCell.

+

Evaluates this assigned cell’s value directly, performing an unbatched inversion +if necessary.

+

If the denominator is zero, the returned cell’s value is zero.

+

Copies the value to a given advice cell and constrains them to be equal.

+

Returns an error if either this cell or the given cell are in columns +where equality has not been enabled.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/struct.Cell.html b/docs/halo2_proofs/circuit/struct.Cell.html new file mode 100644 index 0000000000..3c443b02f7 --- /dev/null +++ b/docs/halo2_proofs/circuit/struct.Cell.html @@ -0,0 +1,28 @@ +Cell in halo2_proofs::circuit - Rust
pub struct Cell { /* private fields */ }
Expand description

A pointer to a cell within a circuit.

+

Implementations

Returns row offset

+

Returns reference to column

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/struct.NamespacedLayouter.html b/docs/halo2_proofs/circuit/struct.NamespacedLayouter.html new file mode 100644 index 0000000000..63202bb424 --- /dev/null +++ b/docs/halo2_proofs/circuit/struct.NamespacedLayouter.html @@ -0,0 +1,29 @@ +NamespacedLayouter in halo2_proofs::circuit - Rust
pub struct NamespacedLayouter<'a, F: Field, L: Layouter<F> + 'a>(_, _);
Expand description

This is a “namespaced” layouter which borrows a Layouter (pushing a namespace +context) and, when dropped, pops out of the namespace context.

+

Trait Implementations

Formats the value using the given formatter. Read more
Executes the destructor for this type. Read more
Represents the type of the “root” of this layouter, so that nested namespaces +can minimize indirection. Read more
Assign a region of gates to an absolute row number. Read more
Assign a table region to an absolute row number. Read more
Constrains a Cell to equal an instance column’s row value at an +absolute position. Read more
Queries the value of the given challenge. Read more
Gets the “root” of this assignment, bypassing the namespacing. Read more
Creates a new (sub)namespace and enters into it. Read more
Exits out of the existing namespace. Read more
Enters into a namespace.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/struct.Region.html b/docs/halo2_proofs/circuit/struct.Region.html new file mode 100644 index 0000000000..1125377fbd --- /dev/null +++ b/docs/halo2_proofs/circuit/struct.Region.html @@ -0,0 +1,53 @@ +Region in halo2_proofs::circuit - Rust
pub struct Region<'r, F: Field> { /* private fields */ }
Expand description

A region of the circuit in which a Chip can assign cells.

+

Inside a region, the chip may freely use relative offsets; the Layouter will +treat these assignments as a single “region” within the circuit.

+

The Layouter is allowed to optimise between regions as it sees fit. Chips must use +Region::constrain_equal to copy in variables assigned in other regions.

+

TODO: It would be great if we could constrain the columns in these types to be +“logical” columns that are guaranteed to correspond to the chip (and have come from +Chip::Config).

+

Implementations

Assign an advice column value (witness).

+

Even though to has FnMut bounds, it is guaranteed to be called at most once.

+

Assigns a constant value to the column advice at offset within this region.

+

The constant value will be assigned to a cell within one of the fixed columns +configured via ConstraintSystem::enable_constant.

+

Returns the advice cell.

+

Assign the value of the instance column’s cell at absolute location +row to the column advice at offset within this region.

+

Returns the advice cell, and its value if known.

+

Assign a fixed value.

+

Even though to has FnMut bounds, it is guaranteed to be called at most once.

+

Constrains a cell to have a constant value.

+

Returns an error if the cell is in a column where equality has not been enabled.

+

Constrains two cells to have the same value.

+

Returns an error if either of the cells are in columns where equality +has not been enabled.

+

Queries the value of the given challenge.

+

Returns Value::unknown() if the current synthesis phase is before the challenge can be queried.

+

Commit advice columns in current phase and squeeze challenges. +This can be called DURING synthesize.

+

Trait Implementations

Formats the value using the given formatter. Read more
Converts to this type from the input type.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/struct.RegionIndex.html b/docs/halo2_proofs/circuit/struct.RegionIndex.html new file mode 100644 index 0000000000..7f0ade03e6 --- /dev/null +++ b/docs/halo2_proofs/circuit/struct.RegionIndex.html @@ -0,0 +1,26 @@ +RegionIndex in halo2_proofs::circuit - Rust
pub struct RegionIndex(_);
Expand description

Index of a region in a layouter

+

Methods from Deref<Target = usize>

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
The resulting type after dereferencing.
Dereferences the value.
Converts to this type from the input type.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/struct.RegionStart.html b/docs/halo2_proofs/circuit/struct.RegionStart.html new file mode 100644 index 0000000000..736dbaa462 --- /dev/null +++ b/docs/halo2_proofs/circuit/struct.RegionStart.html @@ -0,0 +1,28 @@ +RegionStart in halo2_proofs::circuit - Rust
pub struct RegionStart(_);
Expand description

Starting row of a region in a layouter

+

Methods from Deref<Target = usize>

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
The resulting type after dereferencing.
Dereferences the value.
Converts to this type from the input type.
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/struct.SimpleFloorPlanner.html b/docs/halo2_proofs/circuit/struct.SimpleFloorPlanner.html new file mode 100644 index 0000000000..90008094d6 --- /dev/null +++ b/docs/halo2_proofs/circuit/struct.SimpleFloorPlanner.html @@ -0,0 +1,29 @@ +SimpleFloorPlanner in halo2_proofs::circuit - Rust
pub struct SimpleFloorPlanner;
Expand description

A simple FloorPlanner that performs minimal optimizations.

+

This floor planner is suitable for debugging circuits. It aims to reflect the circuit +“business logic” in the circuit layout as closely as possible. It uses a single-pass +layouter that does not reorder regions for optimal packing.

+

Trait Implementations

Formats the value using the given formatter. Read more
Given the provided cs, synthesize the given circuit. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/struct.Table.html b/docs/halo2_proofs/circuit/struct.Table.html new file mode 100644 index 0000000000..4b0f5f4811 --- /dev/null +++ b/docs/halo2_proofs/circuit/struct.Table.html @@ -0,0 +1,29 @@ +Table in halo2_proofs::circuit - Rust
pub struct Table<'r, F: Field> { /* private fields */ }
Expand description

A lookup table in the circuit.

+

Implementations

Assigns a fixed value to a table cell.

+

Returns an error if the table cell has already been assigned to.

+

Even though to has FnMut bounds, it is guaranteed to be called at most once.

+

Trait Implementations

Formats the value using the given formatter. Read more
Converts to this type from the input type.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/struct.Value.html b/docs/halo2_proofs/circuit/struct.Value.html new file mode 100644 index 0000000000..1367061259 --- /dev/null +++ b/docs/halo2_proofs/circuit/struct.Value.html @@ -0,0 +1,87 @@ +Value in halo2_proofs::circuit - Rust
pub struct Value<V> { /* private fields */ }
Expand description

A value that might exist within a circuit.

+

This behaves like Option<V> but differs in two key ways:

+
    +
  • It does not expose the enum cases, or provide an Option::unwrap equivalent. This +helps to ensure that unwitnessed values correctly propagate.
  • +
  • It provides pass-through implementations of common traits such as Add and Mul, +for improved usability.
  • +
+

Implementations

Constructs an unwitnessed value.

+

Constructs a known value.

+
Examples
+
use halo2_proofs::circuit::Value;
+
+let v = Value::known(37);
+

Converts from &Value<V> to Value<&V>.

+

Converts from &mut Value<V> to Value<&mut V>.

+

Enforces an assertion on the contained value, if known.

+

The assertion is ignored if self is Value::unknown(). Do not try to enforce +circuit constraints with this method!

+
Panics
+

Panics if f returns false.

+

Checks the contained value for an error condition, if known.

+

The error check is ignored if self is Value::unknown(). Do not try to +enforce circuit constraints with this method!

+

Maps a Value<V> to Value<W> by applying a function to the contained value.

+

Returns Value::unknown() if the value is Value::unknown(), otherwise calls +f with the wrapped value and returns the result.

+

Zips self with another Value.

+

If self is Value::known(s) and other is Value::known(o), this method +returns Value::known((s, o)). Otherwise, Value::unknown() is returned.

+

Unzips a value containing a tuple of two values.

+

If self is Value::known((a, b)), this method returns (Value::known(a), Value::known(b)). Otherwise, (Value::unknown(), Value::unknown())` is returned.

+

Maps a Value<&V> to a Value<V> by copying the contents of the value.

+

Maps a Value<&V> to a Value<V> by cloning the contents of the value.

+

Maps a Value<&mut V> to a Value<V> by copying the contents of the value.

+

Maps a Value<&mut V> to a Value<V> by cloning the contents of the value.

+

Transposes a Value<[V; LEN]> into a [Value<V>; LEN].

+

Value::unknown() will be mapped to [Value::unknown(); LEN].

+

Transposes a Value<impl IntoIterator<Item = V>> into a Vec<Value<V>>.

+

Value::unknown() will be mapped to vec![Value::unknown(); length].

+
Panics
+

Panics if self is Value::known(values) and values.len() != length.

+

Returns the field element corresponding to this value.

+

Returns the field element corresponding to this value.

+

Doubles this field element.

+
Examples
+

If you have a Value<F: Field>, convert it to Value<Assigned<F>> first:

+ +
use halo2_proofs::{circuit::Value, plonk::Assigned};
+
+let v = Value::known(F::from(2));
+let v: Value<Assigned<F>> = v.into();
+v.double();
+

Squares this field element.

+

Cubes this field element.

+

Inverts this assigned value (taking the inverse of zero to be zero).

+

Evaluates this value directly, performing an unbatched inversion if necessary.

+

If the denominator is zero, the returned value is zero.

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Converts to this type from the input type.

Takes each element in the Iterator: if it is Value::unknown(), no further +elements are taken, and the Value::unknown() is returned. Should no +Value::unknown() occur, a container of type V containing the values of each +Value is returned.

+
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/trait.Chip.html b/docs/halo2_proofs/circuit/trait.Chip.html new file mode 100644 index 0000000000..cee9192582 --- /dev/null +++ b/docs/halo2_proofs/circuit/trait.Chip.html @@ -0,0 +1,21 @@ +Chip in halo2_proofs::circuit - Rust
pub trait Chip<F: FieldExt>: Sized {
+    type Config: Debug + Clone;
+    type Loaded: Debug + Clone;
+
+    fn config(&self) -> &Self::Config;
+    fn loaded(&self) -> &Self::Loaded;
+}
Expand description

A chip implements a set of instructions that can be used by gadgets.

+

The chip stores state that is required at circuit synthesis time in +Chip::Config, which can be fetched via Chip::config.

+

The chip also loads any fixed configuration needed at synthesis time +using its own implementation of load, and stores it in Chip::Loaded. +This can be accessed via Chip::loaded.

+

Required Associated Types

A type that holds the configuration for this chip, and any other state it may need +during circuit synthesis, that can be derived during Circuit::configure.

+

A type that holds any general chip state that needs to be loaded at the start of +Circuit::synthesize. This might simply be () for some chips.

+

Required Methods

The chip holds its own configuration.

+

Provides access to general chip state loaded at the beginning of circuit +synthesis.

+

Panics if called before Chip::load.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/trait.Layouter.html b/docs/halo2_proofs/circuit/trait.Layouter.html new file mode 100644 index 0000000000..0e57aadeb1 --- /dev/null +++ b/docs/halo2_proofs/circuit/trait.Layouter.html @@ -0,0 +1,45 @@ +Layouter in halo2_proofs::circuit - Rust
pub trait Layouter<F: Field> {
+    type Root: Layouter<F>;
+
+    fn assign_region<A, AR, N, NR>(
        &mut self,
        name: N,
        assignment: A
    ) -> Result<AR, Error>
    where
        A: FnOnce(Region<'_, F>) -> Result<AR, Error>,
        N: Fn() -> NR,
        NR: Into<String>
; + fn assign_table<A, N, NR>(
        &mut self,
        name: N,
        assignment: A
    ) -> Result<(), Error>
    where
        A: FnMut(Table<'_, F>) -> Result<(), Error>,
        N: Fn() -> NR,
        NR: Into<String>
; + fn constrain_instance(
        &mut self,
        cell: Cell,
        column: Column<Instance>,
        row: usize
    ); + fn get_challenge(&self, challenge: Challenge) -> Value<F>; + fn get_root(&mut self) -> &mut Self::Root; + fn push_namespace<NR, N>(&mut self, name_fn: N)
    where
        NR: Into<String>,
        N: FnOnce() -> NR
; + fn pop_namespace(&mut self, gadget_name: Option<String>); + + fn namespace<NR, N>(
        &mut self,
        name_fn: N
    ) -> NamespacedLayouter<'_, F, Self::Root>
    where
        NR: Into<String>,
        N: FnOnce() -> NR
, + { ... } +}
Expand description

A layout strategy within a circuit. The layouter is chip-agnostic and applies its +strategy to the context and config it is given.

+

This abstracts over the circuit assignments, handling row indices etc.

+

Required Associated Types

Represents the type of the “root” of this layouter, so that nested namespaces +can minimize indirection.

+

Required Methods

Assign a region of gates to an absolute row number.

+

Inside the closure, the chip may freely use relative offsets; the Layouter will +treat these assignments as a single “region” within the circuit. Outside this +closure, the Layouter is allowed to optimise as it sees fit.

+ +
fn assign_region(&mut self, || "region name", |region| {
+    let config = chip.config();
+    region.assign_advice(config.a, offset, || { Some(value)});
+});
+

Assign a table region to an absolute row number.

+ +
fn assign_table(&mut self, || "table name", |table| {
+    let config = chip.config();
+    table.assign_fixed(config.a, offset, || { Some(value)});
+});
+

Constrains a Cell to equal an instance column’s row value at an +absolute position.

+

Queries the value of the given challenge.

+

Returns Value::unknown() if the current synthesis phase is before the challenge can be queried.

+

Gets the “root” of this assignment, bypassing the namespacing.

+

Not intended for downstream consumption; use Layouter::namespace instead.

+

Creates a new (sub)namespace and enters into it.

+

Not intended for downstream consumption; use Layouter::namespace instead.

+

Exits out of the existing namespace.

+

Not intended for downstream consumption; use Layouter::namespace instead.

+

Provided Methods

Enters into a namespace.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/circuit/value/struct.Value.html b/docs/halo2_proofs/circuit/value/struct.Value.html new file mode 100644 index 0000000000..ed941d34f1 --- /dev/null +++ b/docs/halo2_proofs/circuit/value/struct.Value.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/circuit/struct.Value.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/dev/enum.FailureLocation.html b/docs/halo2_proofs/dev/enum.FailureLocation.html new file mode 100644 index 0000000000..f18baa2830 --- /dev/null +++ b/docs/halo2_proofs/dev/enum.FailureLocation.html @@ -0,0 +1,42 @@ +FailureLocation in halo2_proofs::dev - Rust
pub enum FailureLocation {
+    InRegion {
+        region: Region,
+        offset: usize,
+    },
+    OutsideRegion {
+        row: usize,
+    },
+}
Expand description

The location within the circuit at which a particular VerifyFailure occurred.

+

Variants

InRegion

Fields

region: Region

The region in which the failure occurred.

+
offset: usize

The offset (relative to the start of the region) at which the failure +occurred.

+

A location inside a region.

+

OutsideRegion

Fields

row: usize

The circuit row on which the failure occurred.

+

A location outside of a region.

+

Trait Implementations

Formats the value using the given formatter. Read more
Formats the value using the given formatter. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Converts the given value to a String. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/dev/enum.VerifyFailure.html b/docs/halo2_proofs/dev/enum.VerifyFailure.html new file mode 100644 index 0000000000..f041213694 --- /dev/null +++ b/docs/halo2_proofs/dev/enum.VerifyFailure.html @@ -0,0 +1,90 @@ +VerifyFailure in halo2_proofs::dev - Rust
pub enum VerifyFailure {
+    CellNotAssigned {
+        gate: Gate,
+        region: Region,
+        gate_offset: usize,
+        column: Column<Any>,
+        offset: isize,
+    },
+    ConstraintNotSatisfied {
+        constraint: Constraint,
+        location: FailureLocation,
+        cell_values: Vec<(VirtualCell, String)>,
+    },
+    ConstraintPoisoned {
+        constraint: Constraint,
+    },
+    Lookup {
+        name: &'static str,
+        lookup_index: usize,
+        location: FailureLocation,
+    },
+    Permutation {
+        column: Column,
+        location: FailureLocation,
+    },
+}
Expand description

The reasons why a particular circuit is not satisfied.

+

Variants

CellNotAssigned

Fields

gate: Gate

The index of the active gate.

+
region: Region

The region in which this cell should be assigned.

+
gate_offset: usize

The offset (relative to the start of the region) at which the active gate +queries this cell.

+
column: Column<Any>

The column in which this cell should be assigned.

+
offset: isize

The offset (relative to the start of the region) at which this cell should be +assigned. This may be negative (for example, if a selector enables a gate at +offset 0, but the gate uses Rotation::prev()).

+

A cell used in an active gate was not assigned to.

+

ConstraintNotSatisfied

Fields

constraint: Constraint

The polynomial constraint that is not satisfied.

+
location: FailureLocation

The location at which this constraint is not satisfied.

+

FailureLocation::OutsideRegion is usually caused by a constraint that does +not contain a selector, and as a result is active on every row.

+
cell_values: Vec<(VirtualCell, String)>

The values of the virtual cells used by this constraint.

+

A constraint was not satisfied for a particular row.

+

ConstraintPoisoned

Fields

constraint: Constraint

The polynomial constraint that is not satisfied.

+

A constraint was active on an unusable row, and is likely missing a selector.

+

Lookup

Fields

name: &'static str

The name of the lookup that is not satisfied.

+
lookup_index: usize

The index of the lookup that is not satisfied. These indices are assigned in +the order in which ConstraintSystem::lookup is called during +Circuit::configure.

+
location: FailureLocation

The location at which the lookup is not satisfied.

+

FailureLocation::InRegion is most common, and may be due to the intentional +use of a lookup (if its inputs are conditional on a complex selector), or an +unintentional lookup constraint that overlaps the region (indicating that the +lookup’s inputs should be made conditional).

+

FailureLocation::OutsideRegion is uncommon, and could mean that:

+
    +
  • The input expressions do not correctly constrain a default value that exists +in the table when the lookup is not being used.
  • +
  • The input expressions use a column queried at a non-zero Rotation, and the +lookup is active on a row adjacent to an unrelated region.
  • +
+

A lookup input did not exist in its corresponding table.

+

Permutation

Fields

column: Column

The column in which this permutation is not satisfied.

+
location: FailureLocation

The location at which the permutation is not satisfied.

+

A permutation did not preserve the original value of a cell.

+

Trait Implementations

Formats the value using the given formatter. Read more
Formats the value using the given formatter. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Converts the given value to a String. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/dev/failure/enum.FailureLocation.html b/docs/halo2_proofs/dev/failure/enum.FailureLocation.html new file mode 100644 index 0000000000..ac2b6dd68c --- /dev/null +++ b/docs/halo2_proofs/dev/failure/enum.FailureLocation.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/dev/enum.FailureLocation.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/dev/failure/enum.VerifyFailure.html b/docs/halo2_proofs/dev/failure/enum.VerifyFailure.html new file mode 100644 index 0000000000..84e63f82f9 --- /dev/null +++ b/docs/halo2_proofs/dev/failure/enum.VerifyFailure.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/dev/enum.VerifyFailure.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/dev/gates/struct.CircuitGates.html b/docs/halo2_proofs/dev/gates/struct.CircuitGates.html new file mode 100644 index 0000000000..70d9984818 --- /dev/null +++ b/docs/halo2_proofs/dev/gates/struct.CircuitGates.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/dev/struct.CircuitGates.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/dev/index.html b/docs/halo2_proofs/dev/index.html new file mode 100644 index 0000000000..8dc586550d --- /dev/null +++ b/docs/halo2_proofs/dev/index.html @@ -0,0 +1,2 @@ +halo2_proofs::dev - Rust
Expand description

Tools for developing circuits.

+

Modules

Metadata about circuits.

Structs

A struct for collecting and displaying the gates within a circuit.
A test prover for debugging circuits.

Enums

The location within the circuit at which a particular VerifyFailure occurred.
The reasons why a particular circuit is not satisfied.
\ No newline at end of file diff --git a/docs/halo2_proofs/dev/metadata/index.html b/docs/halo2_proofs/dev/metadata/index.html new file mode 100644 index 0000000000..78e583a4cc --- /dev/null +++ b/docs/halo2_proofs/dev/metadata/index.html @@ -0,0 +1,3 @@ +halo2_proofs::dev::metadata - Rust
Expand description

Metadata about circuits.

+

Structs

Metadata about a column within a circuit.
Metadata about a configured constraint within a circuit.
Metadata about a configured gate within a circuit.
Metadata about an assigned region within a circuit.
A “virtual cell” is a PLONK cell that has been queried at a particular relative offset +within a custom gate.
\ No newline at end of file diff --git a/docs/halo2_proofs/dev/metadata/sidebar-items.js b/docs/halo2_proofs/dev/metadata/sidebar-items.js new file mode 100644 index 0000000000..9f324c339d --- /dev/null +++ b/docs/halo2_proofs/dev/metadata/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":[["Column","Metadata about a column within a circuit."],["Constraint","Metadata about a configured constraint within a circuit."],["Gate","Metadata about a configured gate within a circuit."],["Region","Metadata about an assigned region within a circuit."],["VirtualCell","A “virtual cell” is a PLONK cell that has been queried at a particular relative offset within a custom gate."]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/dev/metadata/struct.Column.html b/docs/halo2_proofs/dev/metadata/struct.Column.html new file mode 100644 index 0000000000..2c284bec6e --- /dev/null +++ b/docs/halo2_proofs/dev/metadata/struct.Column.html @@ -0,0 +1,30 @@ +Column in halo2_proofs::dev::metadata - Rust
pub struct Column { /* private fields */ }
Expand description

Metadata about a column within a circuit.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
Converts to this type from the input type.
This method returns an Ordering between self and other. Read more
Compares and returns the maximum of two values. Read more
Compares and returns the minimum of two values. Read more
Restrict a value to a certain interval. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
This method returns an ordering between self and other values if one exists. Read more
This method tests less than (for self and other) and is used by the < operator. Read more
This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
This method tests greater than (for self and other) and is used by the > operator. Read more
This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Converts the given value to a String. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/dev/metadata/struct.Constraint.html b/docs/halo2_proofs/dev/metadata/struct.Constraint.html new file mode 100644 index 0000000000..5b4fcc4430 --- /dev/null +++ b/docs/halo2_proofs/dev/metadata/struct.Constraint.html @@ -0,0 +1,28 @@ +Constraint in halo2_proofs::dev::metadata - Rust
pub struct Constraint { /* private fields */ }
Expand description

Metadata about a configured constraint within a circuit.

+

Trait Implementations

Formats the value using the given formatter. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Converts the given value to a String. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/dev/metadata/struct.Gate.html b/docs/halo2_proofs/dev/metadata/struct.Gate.html new file mode 100644 index 0000000000..c8929135c3 --- /dev/null +++ b/docs/halo2_proofs/dev/metadata/struct.Gate.html @@ -0,0 +1,28 @@ +Gate in halo2_proofs::dev::metadata - Rust
pub struct Gate { /* private fields */ }
Expand description

Metadata about a configured gate within a circuit.

+

Trait Implementations

Formats the value using the given formatter. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Converts the given value to a String. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/dev/metadata/struct.Region.html b/docs/halo2_proofs/dev/metadata/struct.Region.html new file mode 100644 index 0000000000..c2e0286e73 --- /dev/null +++ b/docs/halo2_proofs/dev/metadata/struct.Region.html @@ -0,0 +1,28 @@ +Region in halo2_proofs::dev::metadata - Rust
pub struct Region { /* private fields */ }
Expand description

Metadata about an assigned region within a circuit.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
Converts to this type from the input type.
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Converts the given value to a String. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/dev/metadata/struct.VirtualCell.html b/docs/halo2_proofs/dev/metadata/struct.VirtualCell.html new file mode 100644 index 0000000000..3c123754f8 --- /dev/null +++ b/docs/halo2_proofs/dev/metadata/struct.VirtualCell.html @@ -0,0 +1,31 @@ +VirtualCell in halo2_proofs::dev::metadata - Rust
pub struct VirtualCell { /* private fields */ }
Expand description

A “virtual cell” is a PLONK cell that has been queried at a particular relative offset +within a custom gate.

+

Trait Implementations

Formats the value using the given formatter. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
This method returns an Ordering between self and other. Read more
Compares and returns the maximum of two values. Read more
Compares and returns the minimum of two values. Read more
Restrict a value to a certain interval. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
This method returns an ordering between self and other values if one exists. Read more
This method tests less than (for self and other) and is used by the < operator. Read more
This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
This method tests greater than (for self and other) and is used by the > operator. Read more
This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Converts the given value to a String. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/dev/sidebar-items.js b/docs/halo2_proofs/dev/sidebar-items.js new file mode 100644 index 0000000000..daba74c878 --- /dev/null +++ b/docs/halo2_proofs/dev/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":[["FailureLocation","The location within the circuit at which a particular [`VerifyFailure`] occurred."],["VerifyFailure","The reasons why a particular circuit is not satisfied."]],"mod":[["metadata","Metadata about circuits."]],"struct":[["CircuitGates","A struct for collecting and displaying the gates within a circuit."],["MockProver","A test prover for debugging circuits."]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/dev/struct.CircuitGates.html b/docs/halo2_proofs/dev/struct.CircuitGates.html new file mode 100644 index 0000000000..a0f252f3e2 --- /dev/null +++ b/docs/halo2_proofs/dev/struct.CircuitGates.html @@ -0,0 +1,90 @@ +CircuitGates in halo2_proofs::dev - Rust
pub struct CircuitGates { /* private fields */ }
Expand description

A struct for collecting and displaying the gates within a circuit.

+

Examples

+
use ff::Field;
+use halo2_proofs::{
+    circuit::{Layouter, SimpleFloorPlanner},
+    dev::CircuitGates,
+    plonk::{Circuit, ConstraintSystem, Error},
+    poly::Rotation,
+};
+use halo2curves::pasta::pallas;
+
+#[derive(Copy, Clone)]
+struct MyConfig {}
+
+#[derive(Clone, Default)]
+struct MyCircuit {}
+
+impl<F: Field> Circuit<F> for MyCircuit {
+    type Config = MyConfig;
+    type FloorPlanner = SimpleFloorPlanner;
+
+    fn without_witnesses(&self) -> Self {
+        Self::default()
+    }
+
+    fn configure(meta: &mut ConstraintSystem<F>) -> MyConfig {
+        let a = meta.advice_column();
+        let b = meta.advice_column();
+        let c = meta.advice_column();
+        let s = meta.selector();
+
+        meta.create_gate("R1CS constraint", |meta| {
+            let a = meta.query_advice(a, Rotation::cur());
+            let b = meta.query_advice(b, Rotation::cur());
+            let c = meta.query_advice(c, Rotation::cur());
+            let s = meta.query_selector(s);
+
+            Some(("R1CS", s * (a * b - c)))
+        });
+
+        // We aren't using this circuit for anything in this example.
+        MyConfig {}
+    }
+
+    fn synthesize(&self, _: MyConfig, _: impl Layouter<F>) -> Result<(), Error> {
+        // Gates are known at configure time; it doesn't matter how we use them.
+        Ok(())
+    }
+}
+
+let gates = CircuitGates::collect::<pallas::Base, MyCircuit>();
+assert_eq!(
+    format!("{}", gates),
+    r#####"R1CS constraint:
+- R1CS:
+  S0 * (A0@0 * A1@0 - A2@0)
+Total gates: 1
+Total custom constraint polynomials: 1
+Total negations: 1
+Total additions: 1
+Total multiplications: 2
+"#####,
+);
+

Implementations

Collects the gates from within the circuit.

+

Prints the queries in this circuit to a CSV grid.

+

Trait Implementations

Formats the value using the given formatter. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Converts the given value to a String. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/dev/struct.MockProver.html b/docs/halo2_proofs/dev/struct.MockProver.html new file mode 100644 index 0000000000..107b99f8f1 --- /dev/null +++ b/docs/halo2_proofs/dev/struct.MockProver.html @@ -0,0 +1,162 @@ +MockProver in halo2_proofs::dev - Rust
pub struct MockProver<F: Group + Field> { /* private fields */ }
Expand description

A test prover for debugging circuits.

+

The normal proving process, when applied to a buggy circuit implementation, might +return proofs that do not validate when they should, but it can’t indicate anything +other than “something is invalid”. MockProver can be used to figure out why these +are invalid: it stores all the private inputs along with the circuit internals, and +then checks every constraint manually.

+

Examples

+
use halo2_proofs::{
+    arithmetic::FieldExt,
+    circuit::{Layouter, SimpleFloorPlanner, Value},
+    dev::{FailureLocation, MockProver, VerifyFailure},
+    plonk::{Advice, Any, Circuit, Column, ConstraintSystem, Error, Selector},
+    poly::Rotation,
+};
+use halo2curves::pasta::Fp;
+const K: u32 = 5;
+
+#[derive(Copy, Clone)]
+struct MyConfig {
+    a: Column<Advice>,
+    b: Column<Advice>,
+    c: Column<Advice>,
+    s: Selector,
+}
+
+#[derive(Clone, Default)]
+struct MyCircuit {
+    a: Value<u64>,
+    b: Value<u64>,
+}
+
+impl<F: FieldExt> Circuit<F> for MyCircuit {
+    type Config = MyConfig;
+    type FloorPlanner = SimpleFloorPlanner;
+
+    fn without_witnesses(&self) -> Self {
+        Self::default()
+    }
+
+    fn configure(meta: &mut ConstraintSystem<F>) -> MyConfig {
+        let a = meta.advice_column();
+        let b = meta.advice_column();
+        let c = meta.advice_column();
+        let s = meta.selector();
+
+        meta.create_gate("R1CS constraint", |meta| {
+            let a = meta.query_advice(a, Rotation::cur());
+            let b = meta.query_advice(b, Rotation::cur());
+            let c = meta.query_advice(c, Rotation::cur());
+            let s = meta.query_selector(s);
+
+            // BUG: Should be a * b - c
+            Some(("buggy R1CS", s * (a * b + c)))
+        });
+
+        MyConfig { a, b, c, s }
+    }
+
+    fn synthesize(&self, config: MyConfig, mut layouter: impl Layouter<F>) -> Result<(), Error> {
+        layouter.assign_region(|| "Example region", |mut region| {
+            config.s.enable(&mut region, 0)?;
+            region.assign_advice(|| "a", config.a, 0, || {
+                self.a.map(F::from)
+            })?;
+            region.assign_advice(|| "b", config.b, 0, || {
+                self.b.map(F::from)
+            })?;
+            region.assign_advice(|| "c", config.c, 0, || {
+                (self.a * self.b).map(F::from)
+            })?;
+            Ok(())
+        })
+    }
+}
+
+// Assemble the private inputs to the circuit.
+let circuit = MyCircuit {
+    a: Value::known(2),
+    b: Value::known(4),
+};
+
+// This circuit has no public inputs.
+let instance = vec![];
+
+let prover = MockProver::<Fp>::run(K, &circuit, instance).unwrap();
+assert_eq!(
+    prover.verify(),
+    Err(vec![VerifyFailure::ConstraintNotSatisfied {
+        constraint: ((0, "R1CS constraint").into(), 0, "buggy R1CS").into(),
+        location: FailureLocation::InRegion {
+            region: (0, "Example region").into(),
+            offset: 0,
+        },
+        cell_values: vec![
+            (((Any::advice(), 0).into(), 0).into(), "0x2".to_string()),
+            (((Any::advice(), 1).into(), 0).into(), "0x4".to_string()),
+            (((Any::advice(), 2).into(), 0).into(), "0x8".to_string()),
+        ],
+    }])
+);
+
+// If we provide a too-small K, we get an error.
+assert!(matches!(
+    MockProver::<Fp>::run(2, &circuit, vec![]).unwrap_err(),
+    Error::NotEnoughRowsAvailable {
+        current_k,
+    } if current_k == 2,
+));
+

Implementations

Runs a synthetic keygen-and-prove operation on the given circuit, collecting data +about the constraints and their assignments.

+

Returns Ok(()) if this MockProver is satisfied, or a list of errors indicating +the reasons that the circuit is not satisfied.

+

Returns Ok(()) if this MockProver is satisfied, or a list of errors indicating +the reasons that the circuit is not satisfied. +Constraints are only checked at gate_row_ids, +and lookup inputs are only checked at lookup_input_row_ids

+

Returns Ok(()) if this MockProver is satisfied, or a list of errors indicating +the reasons that the circuit is not satisfied. +Constraints and lookup are checked at usable_rows, parallelly.

+

Returns Ok(()) if this MockProver is satisfied, or a list of errors indicating +the reasons that the circuit is not satisfied. +Constraints are only checked at gate_row_ids, +and lookup inputs are only checked at lookup_input_row_ids, parallelly.

+

Panics if the circuit being checked by this MockProver is not satisfied.

+

Any verification failures will be pretty-printed to stderr before the function +panics.

+

Apart from the stderr output, this method is equivalent to:

+ +
assert_eq!(prover.verify(), Ok(()));
+

Panics if the circuit being checked by this MockProver is not satisfied.

+

Any verification failures will be pretty-printed to stderr before the function +panics.

+

Internally, this function uses a parallel aproach in order to verify the MockProver contents.

+

Apart from the stderr output, this method is equivalent to:

+ +
assert_eq!(prover.verify_par(), Ok(()));
+

Trait Implementations

Creates a new region and enters into it. Read more
Exits the current region. Read more
Enables a selector at the given row.
Queries the cell of an instance column at a particular absolute row. Read more
Assign an advice column value (witness)
Assign a fixed value
Assign two cells to have the same value
Fills a fixed column starting from the given row with value to.
Queries the value of the given challenge. Read more
Creates a new (sub)namespace and enters into it. Read more
Exits out of the existing namespace. Read more
Commit advice columns in current phase and squeeze challenges. This can be +called DURING synthesize. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/enum.SerdeFormat.html b/docs/halo2_proofs/enum.SerdeFormat.html new file mode 100644 index 0000000000..0632f94970 --- /dev/null +++ b/docs/halo2_proofs/enum.SerdeFormat.html @@ -0,0 +1,38 @@ +SerdeFormat in halo2_proofs - Rust
pub enum SerdeFormat {
+    Processed,
+    RawBytes,
+    RawBytesUnchecked,
+}
Expand description

This enum specifies how various types are serialized and deserialized.

+

Variants

Processed

Curve elements are serialized in compressed form. +Field elements are serialized in standard form, with endianness specified by the +PrimeField implementation.

+

RawBytes

Curve elements are serialized in uncompressed form. Field elements are serialized +in their internal Montgomery representation. +When deserializing, checks are performed to ensure curve elements indeed lie on the curve and field elements +are less than modulus.

+

RawBytesUnchecked

Serialization is the same as RawBytes, but no checks are performed.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/helpers/enum.SerdeFormat.html b/docs/halo2_proofs/helpers/enum.SerdeFormat.html new file mode 100644 index 0000000000..783293a7a5 --- /dev/null +++ b/docs/halo2_proofs/helpers/enum.SerdeFormat.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../halo2_proofs/enum.SerdeFormat.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/index.html b/docs/halo2_proofs/index.html new file mode 100644 index 0000000000..a70515ee79 --- /dev/null +++ b/docs/halo2_proofs/index.html @@ -0,0 +1,7 @@ +halo2_proofs - Rust
Expand description

Re-exports

pub use halo2curves;

Modules

This module provides common utilities, traits and structures for group, +field and polynomial arithmetic.
Traits and structs for implementing circuit components.
Tools for developing circuits.
This module provides an implementation of a variant of (Turbo)PLONK +that is designed specifically for the polynomial commitment scheme described +in the Halo paper.
Contains utilities for performing arithmetic over univariate polynomials in +various forms, including computing commitments to them and provably opening +the committed polynomials at arbitrary points.
This module contains utilities and traits for dealing with Fiat-Shamir +transcripts.

Enums

This enum specifies how various types are serialized and deserialized.
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/assigned/enum.Assigned.html b/docs/halo2_proofs/plonk/assigned/enum.Assigned.html new file mode 100644 index 0000000000..95ee7899d1 --- /dev/null +++ b/docs/halo2_proofs/plonk/assigned/enum.Assigned.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/enum.Assigned.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/enum.Any.html b/docs/halo2_proofs/plonk/circuit/enum.Any.html new file mode 100644 index 0000000000..c11e077199 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/enum.Any.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/enum.Any.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/enum.Expression.html b/docs/halo2_proofs/plonk/circuit/enum.Expression.html new file mode 100644 index 0000000000..11c72936ef --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/enum.Expression.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/enum.Expression.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.Advice.html b/docs/halo2_proofs/plonk/circuit/struct.Advice.html new file mode 100644 index 0000000000..2769fc3390 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.Advice.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.Advice.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.AdviceQuery.html b/docs/halo2_proofs/plonk/circuit/struct.AdviceQuery.html new file mode 100644 index 0000000000..919cfae3d8 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.AdviceQuery.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.AdviceQuery.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.Challenge.html b/docs/halo2_proofs/plonk/circuit/struct.Challenge.html new file mode 100644 index 0000000000..e9698f098f --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.Challenge.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.Challenge.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.Column.html b/docs/halo2_proofs/plonk/circuit/struct.Column.html new file mode 100644 index 0000000000..85364a03c2 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.Column.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.Column.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.Constraint.html b/docs/halo2_proofs/plonk/circuit/struct.Constraint.html new file mode 100644 index 0000000000..bd203515f7 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.Constraint.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.Constraint.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.ConstraintSystem.html b/docs/halo2_proofs/plonk/circuit/struct.ConstraintSystem.html new file mode 100644 index 0000000000..6d97c90777 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.ConstraintSystem.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.ConstraintSystem.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.Constraints.html b/docs/halo2_proofs/plonk/circuit/struct.Constraints.html new file mode 100644 index 0000000000..03a2936a72 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.Constraints.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.Constraints.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.FirstPhase.html b/docs/halo2_proofs/plonk/circuit/struct.FirstPhase.html new file mode 100644 index 0000000000..5e97050c39 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.FirstPhase.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.FirstPhase.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.Fixed.html b/docs/halo2_proofs/plonk/circuit/struct.Fixed.html new file mode 100644 index 0000000000..8d6fbb1241 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.Fixed.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.Fixed.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.FixedQuery.html b/docs/halo2_proofs/plonk/circuit/struct.FixedQuery.html new file mode 100644 index 0000000000..ed669bf709 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.FixedQuery.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.FixedQuery.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.Gate.html b/docs/halo2_proofs/plonk/circuit/struct.Gate.html new file mode 100644 index 0000000000..86527080cd --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.Gate.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.Gate.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.Instance.html b/docs/halo2_proofs/plonk/circuit/struct.Instance.html new file mode 100644 index 0000000000..adb41b839a --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.Instance.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.Instance.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.InstanceQuery.html b/docs/halo2_proofs/plonk/circuit/struct.InstanceQuery.html new file mode 100644 index 0000000000..7392bea326 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.InstanceQuery.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.InstanceQuery.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.PinnedConstraintSystem.html b/docs/halo2_proofs/plonk/circuit/struct.PinnedConstraintSystem.html new file mode 100644 index 0000000000..3363b279ca --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.PinnedConstraintSystem.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.PinnedConstraintSystem.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.SecondPhase.html b/docs/halo2_proofs/plonk/circuit/struct.SecondPhase.html new file mode 100644 index 0000000000..05294f9b6a --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.SecondPhase.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.SecondPhase.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.Selector.html b/docs/halo2_proofs/plonk/circuit/struct.Selector.html new file mode 100644 index 0000000000..ca6b5c90e1 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.Selector.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.Selector.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.TableColumn.html b/docs/halo2_proofs/plonk/circuit/struct.TableColumn.html new file mode 100644 index 0000000000..f0b54acc3a --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.TableColumn.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.TableColumn.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.ThirdPhase.html b/docs/halo2_proofs/plonk/circuit/struct.ThirdPhase.html new file mode 100644 index 0000000000..47d7d12115 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.ThirdPhase.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.ThirdPhase.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.VirtualCell.html b/docs/halo2_proofs/plonk/circuit/struct.VirtualCell.html new file mode 100644 index 0000000000..22dbcdd53e --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.VirtualCell.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.VirtualCell.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/struct.VirtualCells.html b/docs/halo2_proofs/plonk/circuit/struct.VirtualCells.html new file mode 100644 index 0000000000..10ac915c31 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/struct.VirtualCells.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/struct.VirtualCells.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/trait.Assignment.html b/docs/halo2_proofs/plonk/circuit/trait.Assignment.html new file mode 100644 index 0000000000..71aad7fd5b --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/trait.Assignment.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/trait.Assignment.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/trait.Circuit.html b/docs/halo2_proofs/plonk/circuit/trait.Circuit.html new file mode 100644 index 0000000000..fe022a36a3 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/trait.Circuit.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/trait.Circuit.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/trait.ColumnType.html b/docs/halo2_proofs/plonk/circuit/trait.ColumnType.html new file mode 100644 index 0000000000..e4cd97d60a --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/trait.ColumnType.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/trait.ColumnType.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/trait.FloorPlanner.html b/docs/halo2_proofs/plonk/circuit/trait.FloorPlanner.html new file mode 100644 index 0000000000..400e10b068 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/trait.FloorPlanner.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/trait.FloorPlanner.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/circuit/trait.Phase.html b/docs/halo2_proofs/plonk/circuit/trait.Phase.html new file mode 100644 index 0000000000..c351719bc8 --- /dev/null +++ b/docs/halo2_proofs/plonk/circuit/trait.Phase.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/trait.Phase.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/enum.Any.html b/docs/halo2_proofs/plonk/enum.Any.html new file mode 100644 index 0000000000..e9916d1c38 --- /dev/null +++ b/docs/halo2_proofs/plonk/enum.Any.html @@ -0,0 +1,39 @@ +Any in halo2_proofs::plonk - Rust
pub enum Any {
+    Advice(Advice),
+    Fixed,
+    Instance,
+}
Expand description

An enum over the Advice, Fixed, Instance structs

+

Variants

Advice(Advice)

An Advice variant

+

Fixed

A Fixed variant

+

Instance

An Instance variant

+

Implementations

Returns Advice variant in FirstPhase

+

Returns Advice variant in given Phase

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
This method returns an Ordering between self and other. Read more
Compares and returns the maximum of two values. Read more
Compares and returns the minimum of two values. Read more
Restrict a value to a certain interval. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
This method returns an ordering between self and other values if one exists. Read more
This method tests less than (for self and other) and is used by the < operator. Read more
This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
This method tests greater than (for self and other) and is used by the > operator. Read more
This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/enum.Assigned.html b/docs/halo2_proofs/plonk/enum.Assigned.html new file mode 100644 index 0000000000..77135e0385 --- /dev/null +++ b/docs/halo2_proofs/plonk/enum.Assigned.html @@ -0,0 +1,47 @@ +Assigned in halo2_proofs::plonk - Rust
pub enum Assigned<F> {
+    Zero,
+    Trivial(F),
+    Rational(F, F),
+}
Expand description

A value assigned to a cell within a circuit.

+

Stored as a fraction, so the backend can use batch inversion.

+

A denominator of zero maps to an assigned value of zero.

+

Variants

Zero

The field element zero.

+

Trivial(F)

A value that does not require inversion to evaluate.

+

Rational(F, F)

A value stored as a fraction to enable batch inversion.

+

Implementations

Returns the numerator.

+

Returns the denominator, if non-trivial.

+

Returns true iff this element is zero.

+

Doubles this element.

+

Squares this element.

+

Cubes this element.

+

Inverts this assigned value (taking the inverse of zero to be zero).

+

Evaluates this assigned value directly, performing an unbatched inversion if +necessary.

+

If the denominator is zero, this returns zero.

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/enum.Error.html b/docs/halo2_proofs/plonk/enum.Error.html new file mode 100644 index 0000000000..47cefd111f --- /dev/null +++ b/docs/halo2_proofs/plonk/enum.Error.html @@ -0,0 +1,54 @@ +Error in halo2_proofs::plonk - Rust
pub enum Error {
+    Synthesis,
+    InvalidInstances,
+    ConstraintSystemFailure,
+    BoundsFailure,
+    Opening,
+    Transcript(Error),
+    NotEnoughRowsAvailable {
+        current_k: u32,
+    },
+    InstanceTooLarge,
+    NotEnoughColumnsForConstants,
+    ColumnNotInPermutation(Column<Any>),
+}
Expand description

This is an error that could occur during proving or circuit synthesis.

+

Variants

Synthesis

This is an error that can occur during synthesis of the circuit, for +example, when the witness is not present.

+

InvalidInstances

The provided instances do not match the circuit parameters.

+

ConstraintSystemFailure

The constraint system is not satisfied.

+

BoundsFailure

Out of bounds index passed to a backend

+

Opening

Opening error

+

Transcript(Error)

Transcript error

+

NotEnoughRowsAvailable

Fields

current_k: u32

The current value of k being used.

+

k is too small for the given circuit.

+

InstanceTooLarge

Instance provided exceeds number of available rows

+

NotEnoughColumnsForConstants

Circuit synthesis requires global constants, but circuit configuration did not +call ConstraintSystem::enable_constant on fixed columns with sufficient space.

+

ColumnNotInPermutation(Column<Any>)

The instance sets up a copy constraint involving a column that has not been +included in the permutation.

+

Trait Implementations

Formats the value using the given formatter. Read more
Formats the value using the given formatter. Read more
The lower-level source of this error, if any. Read more
👎Deprecated since 1.42.0: use the Display impl or to_string()
👎Deprecated since 1.33.0: replaced by Error::source, which can support downcasting
🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type based access to context intended for error reports. Read more
Converts to this type from the input type.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
🔬This is a nightly-only experimental API. (provide_any)
Data providers should implement this method to provide all values they are able to +provide by using demand. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Converts the given value to a String. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/enum.Expression.html b/docs/halo2_proofs/plonk/enum.Expression.html new file mode 100644 index 0000000000..d641201072 --- /dev/null +++ b/docs/halo2_proofs/plonk/enum.Expression.html @@ -0,0 +1,57 @@ +Expression in halo2_proofs::plonk - Rust
pub enum Expression<F> {
+    Constant(F),
+    Selector(Selector),
+    Fixed(FixedQuery),
+    Advice(AdviceQuery),
+    Instance(InstanceQuery),
+    Challenge(Challenge),
+    Negated(Box<Expression<F>>),
+    Sum(Box<Expression<F>>, Box<Expression<F>>),
+    Product(Box<Expression<F>>, Box<Expression<F>>),
+    Scaled(Box<Expression<F>>, F),
+}
Expand description

Low-degree expression representing an identity that must hold over the committed columns.

+

Variants

Constant(F)

This is a constant polynomial

+

Selector(Selector)

This is a virtual selector

+

Fixed(FixedQuery)

This is a fixed column queried at a certain relative location

+

Advice(AdviceQuery)

This is an advice (witness) column queried at a certain relative location

+

Instance(InstanceQuery)

This is an instance (external) column queried at a certain relative location

+

Challenge(Challenge)

This is a challenge

+

Negated(Box<Expression<F>>)

This is a negated polynomial

+

Sum(Box<Expression<F>>, Box<Expression<F>>)

This is the sum of two polynomials

+

Product(Box<Expression<F>>, Box<Expression<F>>)

This is the product of two polynomials

+

Scaled(Box<Expression<F>>, F)

This is a scaled polynomial

+

Implementations

Evaluate the polynomial using the provided closures to perform the +operations.

+

Evaluate the polynomial lazily using the provided closures to perform the +operations.

+

Identifier for this expression. Expressions with identical identifiers +do the same calculation (but the expressions don’t need to be exactly equal +in how they are composed e.g. 1 + 2 and 2 + 1 can have the same identifier).

+

Compute the degree of this polynomial

+

Approximate the computational complexity of this expression.

+

Square this expression.

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
Converts to this type from the input type.
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/error/enum.Error.html b/docs/halo2_proofs/plonk/error/enum.Error.html new file mode 100644 index 0000000000..71cccb2f38 --- /dev/null +++ b/docs/halo2_proofs/plonk/error/enum.Error.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/enum.Error.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/fn.create_proof.html b/docs/halo2_proofs/plonk/fn.create_proof.html new file mode 100644 index 0000000000..c84e9a36a0 --- /dev/null +++ b/docs/halo2_proofs/plonk/fn.create_proof.html @@ -0,0 +1,5 @@ +create_proof in halo2_proofs::plonk - Rust
pub fn create_proof<'params, 'a, Scheme: CommitmentScheme, P: Prover<'params, Scheme>, E: EncodedChallenge<Scheme::Curve>, R: RngCore + 'a, T: TranscriptWrite<Scheme::Curve, E>, ConcreteCircuit: Circuit<Scheme::Scalar>>(
    params: &'params Scheme::ParamsProver,
    pk: &ProvingKey<Scheme::Curve>,
    circuits: &[ConcreteCircuit],
    instances: &[&[&'a [Scheme::Scalar]]],
    rng: R,
    transcript: &'a mut T
) -> Result<(), Error>
Expand description

This creates a proof for the provided circuit when given the public +parameters params and the proving key ProvingKey that was +generated previously for the same circuit. The provided instances +are zero-padded internally.

+
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/fn.keygen_pk.html b/docs/halo2_proofs/plonk/fn.keygen_pk.html new file mode 100644 index 0000000000..3b43a17469 --- /dev/null +++ b/docs/halo2_proofs/plonk/fn.keygen_pk.html @@ -0,0 +1,2 @@ +keygen_pk in halo2_proofs::plonk - Rust
pub fn keygen_pk<'params, C, P, ConcreteCircuit>(
    params: &P,
    vk: VerifyingKey<C>,
    circuit: &ConcreteCircuit
) -> Result<ProvingKey<C>, Error>where
    C: CurveAffine,
    P: Params<'params, C>,
    ConcreteCircuit: Circuit<C::Scalar>,
Expand description

Generate a ProvingKey from a VerifyingKey and an instance of Circuit.

+
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/fn.keygen_vk.html b/docs/halo2_proofs/plonk/fn.keygen_vk.html new file mode 100644 index 0000000000..77ccdec8be --- /dev/null +++ b/docs/halo2_proofs/plonk/fn.keygen_vk.html @@ -0,0 +1,2 @@ +keygen_vk in halo2_proofs::plonk - Rust
pub fn keygen_vk<'params, C, P, ConcreteCircuit>(
    params: &P,
    circuit: &ConcreteCircuit
) -> Result<VerifyingKey<C>, Error>where
    C: CurveAffine,
    P: Params<'params, C>,
    ConcreteCircuit: Circuit<C::Scalar>,
Expand description

Generate a VerifyingKey from an instance of Circuit.

+
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/fn.verify_proof.html b/docs/halo2_proofs/plonk/fn.verify_proof.html new file mode 100644 index 0000000000..3ecd59c348 --- /dev/null +++ b/docs/halo2_proofs/plonk/fn.verify_proof.html @@ -0,0 +1,2 @@ +verify_proof in halo2_proofs::plonk - Rust
pub fn verify_proof<'params, Scheme: CommitmentScheme, V: Verifier<'params, Scheme>, E: EncodedChallenge<Scheme::Curve>, T: TranscriptRead<Scheme::Curve, E>, Strategy: VerificationStrategy<'params, Scheme, V>>(
    params: &'params Scheme::ParamsVerifier,
    vk: &VerifyingKey<Scheme::Curve>,
    strategy: Strategy,
    instances: &[&[&[Scheme::Scalar]]],
    transcript: &mut T
) -> Result<Strategy::Output, Error>
Expand description

Returns a boolean indicating whether or not the proof is valid

+
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/index.html b/docs/halo2_proofs/plonk/index.html new file mode 100644 index 0000000000..72a8e57c85 --- /dev/null +++ b/docs/halo2_proofs/plonk/index.html @@ -0,0 +1,17 @@ +halo2_proofs::plonk - Rust
Expand description

This module provides an implementation of a variant of (Turbo)PLONK +that is designed specifically for the polynomial commitment scheme described +in the Halo paper.

+

Structs

An advice column
Query of advice column at a certain relative location
A verifier that checks multiple proofs in a batch. This requires the +batch crate feature to be enabled.
A challenge squeezed from transcript after advice columns at the phase have been committed.
A column with an index and type
An individual polynomial constraint.
This is a description of the circuit environment, such as the gate, column and +permutation arrangements.
A set of polynomial constraints with a common selector.
First phase
A fixed column
Query of fixed column at a certain relative location
Gate
An instance column
Query of instance column at a certain relative location
Represents the minimal parameters that determine a ConstraintSystem.
Minimal representation of a verification key that can be used to identify +its active contents.
This is a proving key which allows for the creation of proofs for a +particular circuit.
Second phase
A selector, representing a fixed boolean value per row of the circuit.
A fixed column of a lookup table.
Third phase
This is a verifying key which allows for the verification of proofs for a +particular circuit.
A “virtual cell” is a PLONK cell that has been queried at a particular relative offset +within a custom gate.
Exposes the “virtual cells” that can be queried while creating a custom gate or lookup +table.

Enums

An enum over the Advice, Fixed, Instance structs
A value assigned to a cell within a circuit.
This is an error that could occur during proving or circuit synthesis.
Low-degree expression representing an identity that must hold over the committed columns.

Traits

This trait allows a Circuit to direct some backend to assign a witness +for a constraint system.
This is a trait that circuits provide implementations for so that the +backend prover can ask the circuit to synthesize using some given +ConstraintSystem implementation.
A column type
A floor planning strategy for a circuit.
Phase of advice column

Functions

This creates a proof for the provided circuit when given the public +parameters params and the proving key ProvingKey that was +generated previously for the same circuit. The provided instances +are zero-padded internally.
Generate a ProvingKey from a VerifyingKey and an instance of Circuit.
Generate a VerifyingKey from an instance of Circuit.
Returns a boolean indicating whether or not the proof is valid
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/keygen/fn.keygen_pk.html b/docs/halo2_proofs/plonk/keygen/fn.keygen_pk.html new file mode 100644 index 0000000000..c760005e36 --- /dev/null +++ b/docs/halo2_proofs/plonk/keygen/fn.keygen_pk.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/fn.keygen_pk.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/keygen/fn.keygen_vk.html b/docs/halo2_proofs/plonk/keygen/fn.keygen_vk.html new file mode 100644 index 0000000000..cd6bd0f946 --- /dev/null +++ b/docs/halo2_proofs/plonk/keygen/fn.keygen_vk.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/fn.keygen_vk.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/prover/fn.create_proof.html b/docs/halo2_proofs/plonk/prover/fn.create_proof.html new file mode 100644 index 0000000000..dd11e45e79 --- /dev/null +++ b/docs/halo2_proofs/plonk/prover/fn.create_proof.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/fn.create_proof.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/sidebar-items.js b/docs/halo2_proofs/plonk/sidebar-items.js new file mode 100644 index 0000000000..06a4189d4f --- /dev/null +++ b/docs/halo2_proofs/plonk/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":[["Any","An enum over the Advice, Fixed, Instance structs"],["Assigned","A value assigned to a cell within a circuit."],["Error","This is an error that could occur during proving or circuit synthesis."],["Expression","Low-degree expression representing an identity that must hold over the committed columns."]],"fn":[["create_proof","This creates a proof for the provided `circuit` when given the public parameters `params` and the proving key [`ProvingKey`] that was generated previously for the same circuit. The provided `instances` are zero-padded internally."],["keygen_pk","Generate a `ProvingKey` from a `VerifyingKey` and an instance of `Circuit`."],["keygen_vk","Generate a `VerifyingKey` from an instance of `Circuit`."],["verify_proof","Returns a boolean indicating whether or not the proof is valid"]],"struct":[["Advice","An advice column"],["AdviceQuery","Query of advice column at a certain relative location"],["BatchVerifier","A verifier that checks multiple proofs in a batch. This requires the `batch` crate feature to be enabled."],["Challenge","A challenge squeezed from transcript after advice columns at the phase have been committed."],["Column","A column with an index and type"],["Constraint","An individual polynomial constraint."],["ConstraintSystem","This is a description of the circuit environment, such as the gate, column and permutation arrangements."],["Constraints","A set of polynomial constraints with a common selector."],["FirstPhase","First phase"],["Fixed","A fixed column"],["FixedQuery","Query of fixed column at a certain relative location"],["Gate","Gate"],["Instance","An instance column"],["InstanceQuery","Query of instance column at a certain relative location"],["PinnedConstraintSystem","Represents the minimal parameters that determine a `ConstraintSystem`."],["PinnedVerificationKey","Minimal representation of a verification key that can be used to identify its active contents."],["ProvingKey","This is a proving key which allows for the creation of proofs for a particular circuit."],["SecondPhase","Second phase"],["Selector","A selector, representing a fixed boolean value per row of the circuit."],["TableColumn","A fixed column of a lookup table."],["ThirdPhase","Third phase"],["VerifyingKey","This is a verifying key which allows for the verification of proofs for a particular circuit."],["VirtualCell","A “virtual cell” is a PLONK cell that has been queried at a particular relative offset within a custom gate."],["VirtualCells","Exposes the “virtual cells” that can be queried while creating a custom gate or lookup table."]],"trait":[["Assignment","This trait allows a [`Circuit`] to direct some backend to assign a witness for a constraint system."],["Circuit","This is a trait that circuits provide implementations for so that the backend prover can ask the circuit to synthesize using some given [`ConstraintSystem`] implementation."],["ColumnType","A column type"],["FloorPlanner","A floor planning strategy for a circuit."],["Phase","Phase of advice column"]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.Advice.html b/docs/halo2_proofs/plonk/struct.Advice.html new file mode 100644 index 0000000000..6202a89e15 --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.Advice.html @@ -0,0 +1,30 @@ +Advice in halo2_proofs::plonk - Rust
pub struct Advice { /* private fields */ }
Expand description

An advice column

+

Implementations

Returns Advice in given Phase

+

Phase of this column

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Converts to this type from the input type.
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.AdviceQuery.html b/docs/halo2_proofs/plonk/struct.AdviceQuery.html new file mode 100644 index 0000000000..a95dca0db0 --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.AdviceQuery.html @@ -0,0 +1,29 @@ +AdviceQuery in halo2_proofs::plonk - Rust
pub struct AdviceQuery { /* private fields */ }
Expand description

Query of advice column at a certain relative location

+

Implementations

Column index

+

Rotation of this query

+

Phase of this advice column

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.BatchVerifier.html b/docs/halo2_proofs/plonk/struct.BatchVerifier.html new file mode 100644 index 0000000000..e222234c69 --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.BatchVerifier.html @@ -0,0 +1,35 @@ +BatchVerifier in halo2_proofs::plonk - Rust
pub struct BatchVerifier<C: CurveAffine> { /* private fields */ }
Expand description

A verifier that checks multiple proofs in a batch. This requires the +batch crate feature to be enabled.

+

Implementations

Constructs a new batch verifier.

+

Adds a proof to the batch.

+

Finalizes the batch and checks its validity.

+

Returns false if some proof was invalid. If the caller needs to identify +specific failing proofs, it must re-process the proofs separately.

+

This uses OsRng internally instead of taking an R: RngCore argument, because +the internal parallelization requires access to a RNG that is guaranteed to not +clone its internal state when shared between threads.

+

Trait Implementations

Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.Challenge.html b/docs/halo2_proofs/plonk/struct.Challenge.html new file mode 100644 index 0000000000..aee2f15a8a --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.Challenge.html @@ -0,0 +1,30 @@ +Challenge in halo2_proofs::plonk - Rust
pub struct Challenge { /* private fields */ }
Expand description

A challenge squeezed from transcript after advice columns at the phase have been committed.

+

Implementations

Index of this challenge.

+

Phase of this challenge.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.Column.html b/docs/halo2_proofs/plonk/struct.Column.html new file mode 100644 index 0000000000..03b70340ab --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.Column.html @@ -0,0 +1,32 @@ +Column in halo2_proofs::plonk - Rust
pub struct Column<C: ColumnType> { /* private fields */ }
Expand description

A column with an index and type

+

Implementations

Index of this column.

+

Type of this column.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
This method returns an Ordering between self and other. Read more
Compares and returns the maximum of two values. Read more
Compares and returns the minimum of two values. Read more
Restrict a value to a certain interval. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
This method returns an ordering between self and other values if one exists. Read more
This method tests less than (for self and other) and is used by the < operator. Read more
This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
This method tests greater than (for self and other) and is used by the > operator. Read more
This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.Constraint.html b/docs/halo2_proofs/plonk/struct.Constraint.html new file mode 100644 index 0000000000..17ffc826b4 --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.Constraint.html @@ -0,0 +1,27 @@ +Constraint in halo2_proofs::plonk - Rust
pub struct Constraint<F: Field> { /* private fields */ }
Expand description

An individual polynomial constraint.

+

These are returned by the closures passed to ConstraintSystem::create_gate.

+

Trait Implementations

Formats the value using the given formatter. Read more
Converts to this type from the input type.
Converts to this type from the input type.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.ConstraintSystem.html b/docs/halo2_proofs/plonk/struct.ConstraintSystem.html new file mode 100644 index 0000000000..f936657136 --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.ConstraintSystem.html @@ -0,0 +1,78 @@ +ConstraintSystem in halo2_proofs::plonk - Rust
pub struct ConstraintSystem<F: Field> { /* private fields */ }
Expand description

This is a description of the circuit environment, such as the gate, column and +permutation arrangements.

+

Implementations

Obtain a pinned version of this constraint system; a structure with the +minimal parameters needed to determine the rest of the constraint +system.

+

Enables this fixed column to be used for global constant assignments.

+
Side-effects
+

The column will be equality-enabled.

+

Enable the ability to enforce equality over cells in this column

+

Add a lookup argument for some input expressions and table columns.

+

table_map returns a map between input expressions and the table columns +they need to match.

+

Add a lookup argument for some input expressions and table expressions.

+

table_map returns a map between input expressions and the table expressions +they need to match.

+

Sets the minimum degree required by the circuit, which can be set to a +larger amount than actually needed. This can be used, for example, to +force the permutation argument to involve more columns in the same set.

+

Creates a new gate.

+
Panics
+

A gate is required to contain polynomial constraints. This method will panic if +constraints returns an empty iterator.

+

Allocate a new (simple) selector. Simple selectors cannot be added to +expressions nor multiplied by other expressions containing simple +selectors. Also, simple selectors may not appear in lookup argument +inputs.

+

Allocate a new complex selector that can appear anywhere +within expressions.

+

Allocates a new fixed column that can be used in a lookup table.

+

Allocate a new fixed column

+

Allocate a new advice column at FirstPhase

+

Allocate a new advice column in given phase

+

Allocate a new instance column

+

Requests a challenge that is usable after the given phase.

+

Compute the degree of the constraint system (the maximum degree of all +constraints).

+

Compute the number of blinding factors necessary to perfectly blind +each of the prover’s witness polynomials.

+

Returns the minimum necessary rows that need to exist in order to +account for e.g. blinding factors.

+

Returns number of fixed columns

+

Returns number of advice columns

+

Returns number of instance columns

+

Returns number of challenges

+

Returns phase of advice columns

+

Returns phase of challenges

+

Returns gates

+

Returns advice queries

+

Returns instance queries

+

Returns fixed queries

+

Returns permutation argument

+

Returns lookup arguments

+

Returns constants

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.Constraints.html b/docs/halo2_proofs/plonk/struct.Constraints.html new file mode 100644 index 0000000000..7eb21705f6 --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.Constraints.html @@ -0,0 +1,58 @@ +Constraints in halo2_proofs::plonk - Rust
pub struct Constraints<F: Field, C: Into<Constraint<F>>, Iter: IntoIterator<Item = C>> { /* private fields */ }
Expand description

A set of polynomial constraints with a common selector.

+ +
use halo2_proofs::{plonk::{Constraints, Expression}, poly::Rotation};
+use halo2curves::pasta::Fp;
+
+let a = meta.advice_column();
+let b = meta.advice_column();
+let c = meta.advice_column();
+let s = meta.selector();
+
+meta.create_gate("foo", |meta| {
+    let next = meta.query_advice(a, Rotation::next());
+    let a = meta.query_advice(a, Rotation::cur());
+    let b = meta.query_advice(b, Rotation::cur());
+    let c = meta.query_advice(c, Rotation::cur());
+    let s_ternary = meta.query_selector(s);
+
+    let one_minus_a = Expression::Constant(Fp::one()) - a.clone();
+
+    Constraints::with_selector(
+        s_ternary,
+        std::array::IntoIter::new([
+            ("a is boolean", a.clone() * one_minus_a.clone()),
+            ("next == a ? b : c", next - (a * b + one_minus_a * c)),
+        ]),
+    )
+});
+

Note that the use of std::array::IntoIter::new is only necessary if you need to +support Rust 1.51 or 1.52. If your minimum supported Rust version is 1.53 or greater, +you can pass an array directly.

+

Implementations

Constructs a set of constraints that are controlled by the given selector.

+

Each constraint c in iterator will be converted into the constraint +selector * c.

+

Trait Implementations

Formats the value using the given formatter. Read more
The type of the elements being iterated over.
Which kind of iterator are we turning this into?
Creates an iterator from a value. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.FirstPhase.html b/docs/halo2_proofs/plonk/struct.FirstPhase.html new file mode 100644 index 0000000000..4571eddbfc --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.FirstPhase.html @@ -0,0 +1,26 @@ +FirstPhase in halo2_proofs::plonk - Rust
pub struct FirstPhase;
Expand description

First phase

+

Trait Implementations

Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.Fixed.html b/docs/halo2_proofs/plonk/struct.Fixed.html new file mode 100644 index 0000000000..ac526d3b5e --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.Fixed.html @@ -0,0 +1,28 @@ +Fixed in halo2_proofs::plonk - Rust
pub struct Fixed;
Expand description

A fixed column

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.FixedQuery.html b/docs/halo2_proofs/plonk/struct.FixedQuery.html new file mode 100644 index 0000000000..0372061657 --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.FixedQuery.html @@ -0,0 +1,28 @@ +FixedQuery in halo2_proofs::plonk - Rust
pub struct FixedQuery { /* private fields */ }
Expand description

Query of fixed column at a certain relative location

+

Implementations

Column index

+

Rotation of this query

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.Gate.html b/docs/halo2_proofs/plonk/struct.Gate.html new file mode 100644 index 0000000000..d7e59e77cc --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.Gate.html @@ -0,0 +1,27 @@ +Gate in halo2_proofs::plonk - Rust
pub struct Gate<F: Field> { /* private fields */ }
Expand description

Gate

+

Implementations

Returns constraints of this gate

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.Instance.html b/docs/halo2_proofs/plonk/struct.Instance.html new file mode 100644 index 0000000000..24a9d7b95e --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.Instance.html @@ -0,0 +1,28 @@ +Instance in halo2_proofs::plonk - Rust
pub struct Instance;
Expand description

An instance column

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.InstanceQuery.html b/docs/halo2_proofs/plonk/struct.InstanceQuery.html new file mode 100644 index 0000000000..ba89968f4d --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.InstanceQuery.html @@ -0,0 +1,28 @@ +InstanceQuery in halo2_proofs::plonk - Rust
pub struct InstanceQuery { /* private fields */ }
Expand description

Query of instance column at a certain relative location

+

Implementations

Column index

+

Rotation of this query

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.PinnedConstraintSystem.html b/docs/halo2_proofs/plonk/struct.PinnedConstraintSystem.html new file mode 100644 index 0000000000..0039fab7d8 --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.PinnedConstraintSystem.html @@ -0,0 +1,26 @@ +PinnedConstraintSystem in halo2_proofs::plonk - Rust
pub struct PinnedConstraintSystem<'a, F: Field> { /* private fields */ }
Expand description

Represents the minimal parameters that determine a ConstraintSystem.

+

Trait Implementations

Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.PinnedVerificationKey.html b/docs/halo2_proofs/plonk/struct.PinnedVerificationKey.html new file mode 100644 index 0000000000..879c028067 --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.PinnedVerificationKey.html @@ -0,0 +1,27 @@ +PinnedVerificationKey in halo2_proofs::plonk - Rust
pub struct PinnedVerificationKey<'a, C: CurveAffine> { /* private fields */ }
Expand description

Minimal representation of a verification key that can be used to identify +its active contents.

+

Trait Implementations

Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.ProvingKey.html b/docs/halo2_proofs/plonk/struct.ProvingKey.html new file mode 100644 index 0000000000..6b3e067ecb --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.ProvingKey.html @@ -0,0 +1,53 @@ +ProvingKey in halo2_proofs::plonk - Rust
pub struct ProvingKey<C: CurveAffine> { /* private fields */ }
Expand description

This is a proving key which allows for the creation of proofs for a +particular circuit.

+

Implementations

Get the underlying VerifyingKey.

+

Writes a proving key to a buffer.

+

Writes a curve element according to format:

+
    +
  • Processed: Writes a compressed curve element with coordinates in standard form. +Writes a field element in standard form, with endianness specified by the +PrimeField implementation.
  • +
  • Otherwise: Writes an uncompressed curve element with coordinates in Montgomery form +Writes a field element into raw bytes in its internal Montgomery representation, +WITHOUT performing the expensive Montgomery reduction. +Does so by first writing the verifying key and then serializing the rest of the data (in the form of field polynomials)
  • +
+

Reads a proving key from a buffer. +Does so by reading verification key first, and then deserializing the rest of the file into the remaining proving key data.

+

Reads a curve element from the buffer and parses it according to the format:

+
    +
  • Processed: Reads a compressed curve element and decompresses it. +Reads a field element in standard form, with endianness specified by the +PrimeField implementation, and checks that the element is less than the modulus.
  • +
  • RawBytes: Reads an uncompressed curve element with coordinates in Montgomery form. +Checks that field elements are less than modulus, and then checks that the point is on the curve.
  • +
  • RawBytesUnchecked: Reads an uncompressed curve element with coordinates in Montgomery form; +does not perform any checks
  • +
+

Writes a proving key to a vector of bytes using Self::write.

+

Reads a proving key from a slice of bytes using Self::read.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.SecondPhase.html b/docs/halo2_proofs/plonk/struct.SecondPhase.html new file mode 100644 index 0000000000..513fec826d --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.SecondPhase.html @@ -0,0 +1,26 @@ +SecondPhase in halo2_proofs::plonk - Rust
pub struct SecondPhase;
Expand description

Second phase

+

Trait Implementations

Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.Selector.html b/docs/halo2_proofs/plonk/struct.Selector.html new file mode 100644 index 0000000000..a3bf7d01ca --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.Selector.html @@ -0,0 +1,72 @@ +Selector in halo2_proofs::plonk - Rust
pub struct Selector(_, _);
Expand description

A selector, representing a fixed boolean value per row of the circuit.

+

Selectors can be used to conditionally enable (portions of) gates:

+ +
use halo2_proofs::poly::Rotation;
+
+let a = meta.advice_column();
+let b = meta.advice_column();
+let s = meta.selector();
+
+meta.create_gate("foo", |meta| {
+    let a = meta.query_advice(a, Rotation::prev());
+    let b = meta.query_advice(b, Rotation::cur());
+    let s = meta.query_selector(s);
+
+    // On rows where the selector is enabled, a is constrained to equal b.
+    // On rows where the selector is disabled, a and b can take any value.
+    vec![s * (a - b)]
+});
+

Selectors are disabled on all rows by default, and must be explicitly enabled on each +row when required:

+ +
use halo2_proofs::{
+    arithmetic::FieldExt,
+    circuit::{Chip, Layouter, Value},
+    plonk::{Advice, Column, Error, Selector},
+};
+
+struct Config {
+    a: Column<Advice>,
+    b: Column<Advice>,
+    s: Selector,
+}
+
+fn circuit_logic<F: FieldExt, C: Chip<F>>(chip: C, mut layouter: impl Layouter<F>) -> Result<(), Error> {
+    let config = chip.config();
+    layouter.assign_region(|| "bar", |mut region| {
+        region.assign_advice(|| "a", config.a, 0, || Value::known(F::one()))?;
+        region.assign_advice(|| "a", config.b, 1, || Value::known(F::one()))?;
+        config.s.enable(&mut region, 1)
+    })?;
+    Ok(())
+}
+

Implementations

Enable this selector at the given offset within the given region.

+

Is this selector “simple”? Simple selectors can only be multiplied +by expressions that contain no other simple selectors.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.TableColumn.html b/docs/halo2_proofs/plonk/struct.TableColumn.html new file mode 100644 index 0000000000..67f5226c5d --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.TableColumn.html @@ -0,0 +1,33 @@ +TableColumn in halo2_proofs::plonk - Rust
pub struct TableColumn { /* private fields */ }
Expand description

A fixed column of a lookup table.

+

A lookup table can be loaded into this column via Layouter::assign_table. Columns +can currently only contain a single table, but they may be used in multiple lookup +arguments via ConstraintSystem::lookup.

+

Lookup table columns are always “encumbered” by the lookup arguments they are used in; +they cannot simultaneously be used as general fixed columns.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.ThirdPhase.html b/docs/halo2_proofs/plonk/struct.ThirdPhase.html new file mode 100644 index 0000000000..4c5322d538 --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.ThirdPhase.html @@ -0,0 +1,26 @@ +ThirdPhase in halo2_proofs::plonk - Rust
pub struct ThirdPhase;
Expand description

Third phase

+

Trait Implementations

Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.VerifyingKey.html b/docs/halo2_proofs/plonk/struct.VerifyingKey.html new file mode 100644 index 0000000000..94ef9f9705 --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.VerifyingKey.html @@ -0,0 +1,57 @@ +VerifyingKey in halo2_proofs::plonk - Rust
pub struct VerifyingKey<C: CurveAffine> { /* private fields */ }
Expand description

This is a verifying key which allows for the verification of proofs for a +particular circuit.

+

Implementations

Writes a verifying key to a buffer.

+

Writes a curve element according to format:

+
    +
  • Processed: Writes a compressed curve element with coordinates in standard form. +Writes a field element in standard form, with endianness specified by the +PrimeField implementation.
  • +
  • Otherwise: Writes an uncompressed curve element with coordinates in Montgomery form +Writes a field element into raw bytes in its internal Montgomery representation, +WITHOUT performing the expensive Montgomery reduction.
  • +
+

Reads a verification key from a buffer.

+

Reads a curve element from the buffer and parses it according to the format:

+
    +
  • Processed: Reads a compressed curve element and decompresses it. +Reads a field element in standard form, with endianness specified by the +PrimeField implementation, and checks that the element is less than the modulus.
  • +
  • RawBytes: Reads an uncompressed curve element with coordinates in Montgomery form. +Checks that field elements are less than modulus, and then checks that the point is on the curve.
  • +
  • RawBytesUnchecked: Reads an uncompressed curve element with coordinates in Montgomery form; +does not perform any checks
  • +
+

Writes a verifying key to a vector of bytes using Self::write.

+

Reads a verification key from a slice of bytes using Self::read.

+

Hashes a verification key into a transcript.

+

Obtains a pinned representation of this verification key that contains +the minimal information necessary to reconstruct the verification key.

+

Returns commitments of fixed polynomials

+

Returns VerifyingKey of permutation

+

Returns ConstraintSystem

+

Get the underlying EvaluationDomain.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.VirtualCell.html b/docs/halo2_proofs/plonk/struct.VirtualCell.html new file mode 100644 index 0000000000..5c0a15414f --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.VirtualCell.html @@ -0,0 +1,27 @@ +VirtualCell in halo2_proofs::plonk - Rust
pub struct VirtualCell { /* private fields */ }
Expand description

A “virtual cell” is a PLONK cell that has been queried at a particular relative offset +within a custom gate.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.
Converts to this type from the input type.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/struct.VirtualCells.html b/docs/halo2_proofs/plonk/struct.VirtualCells.html new file mode 100644 index 0000000000..bab4ed380a --- /dev/null +++ b/docs/halo2_proofs/plonk/struct.VirtualCells.html @@ -0,0 +1,33 @@ +VirtualCells in halo2_proofs::plonk - Rust
pub struct VirtualCells<'a, F: Field> { /* private fields */ }
Expand description

Exposes the “virtual cells” that can be queried while creating a custom gate or lookup +table.

+

Implementations

Query a selector at the current position.

+

Query a fixed column at a relative position

+

Query an advice column at a relative position

+

Query an instance column at a relative position

+

Query an Any column at a relative position

+

Query a challenge

+

Trait Implementations

Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/trait.Assignment.html b/docs/halo2_proofs/plonk/trait.Assignment.html new file mode 100644 index 0000000000..e060d68165 --- /dev/null +++ b/docs/halo2_proofs/plonk/trait.Assignment.html @@ -0,0 +1,38 @@ +Assignment in halo2_proofs::plonk - Rust
pub trait Assignment<F: Field> {
+    fn enter_region<NR, N>(&mut self, name_fn: N)
    where
        NR: Into<String>,
        N: FnOnce() -> NR
; + fn exit_region(&mut self); + fn enable_selector<A, AR>(
        &mut self,
        annotation: A,
        selector: &Selector,
        row: usize
    ) -> Result<(), Error>
    where
        A: FnOnce() -> AR,
        AR: Into<String>
; + fn query_instance(
        &self,
        column: Column<Instance>,
        row: usize
    ) -> Result<Value<F>, Error>; + fn assign_advice<'r, 'v>(
        &'r mut self,
        column: Column<Advice>,
        row: usize,
        to: Value<Assigned<F>>
    ) -> Result<Value<&'v Assigned<F>>, Error>; + fn assign_fixed(&mut self, column: Column<Fixed>, row: usize, to: Assigned<F>); + fn copy(
        &mut self,
        left_column: Column<Any>,
        left_row: usize,
        right_column: Column<Any>,
        right_row: usize
    ); + fn fill_from_row(
        &mut self,
        column: Column<Fixed>,
        row: usize,
        to: Value<Assigned<F>>
    ) -> Result<(), Error>; + fn get_challenge(&self, challenge: Challenge) -> Value<F>; + fn push_namespace<NR, N>(&mut self, name_fn: N)
    where
        NR: Into<String>,
        N: FnOnce() -> NR
; + fn pop_namespace(&mut self, gadget_name: Option<String>); + + fn next_phase(&mut self) { ... } +}
Expand description

This trait allows a Circuit to direct some backend to assign a witness +for a constraint system.

+

Required Methods

Creates a new region and enters into it.

+

Panics if we are currently in a region (if exit_region was not called).

+

Not intended for downstream consumption; use Layouter::assign_region instead.

+

Exits the current region.

+

Panics if we are not currently in a region (if enter_region was not called).

+

Not intended for downstream consumption; use Layouter::assign_region instead.

+

Enables a selector at the given row.

+

Queries the cell of an instance column at a particular absolute row.

+

Returns the cell’s value, if known.

+

Assign an advice column value (witness)

+

Assign a fixed value

+

Assign two cells to have the same value

+

Fills a fixed column starting from the given row with value to.

+

Queries the value of the given challenge.

+

Returns Value::unknown() if the current synthesis phase is before the challenge can be queried.

+

Creates a new (sub)namespace and enters into it.

+

Not intended for downstream consumption; use Layouter::namespace instead.

+

Exits out of the existing namespace.

+

Not intended for downstream consumption; use Layouter::namespace instead.

+

Provided Methods

Commit advice columns in current phase and squeeze challenges. This can be +called DURING synthesize.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/trait.Circuit.html b/docs/halo2_proofs/plonk/trait.Circuit.html new file mode 100644 index 0000000000..77df8efd20 --- /dev/null +++ b/docs/halo2_proofs/plonk/trait.Circuit.html @@ -0,0 +1,21 @@ +Circuit in halo2_proofs::plonk - Rust
pub trait Circuit<F: Field> {
+    type Config: Clone;
+    type FloorPlanner: FloorPlanner;
+
+    fn without_witnesses(&self) -> Self;
+    fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config;
+    fn synthesize(
        &self,
        config: Self::Config,
        layouter: impl Layouter<F>
    ) -> Result<(), Error>; +}
Expand description

This is a trait that circuits provide implementations for so that the +backend prover can ask the circuit to synthesize using some given +ConstraintSystem implementation.

+

Required Associated Types

This is a configuration object that stores things like columns.

+

The floor planner used for this circuit. This is an associated type of the +Circuit trait because its behaviour is circuit-critical.

+

Required Methods

Returns a copy of this circuit with no witness values (i.e. all witnesses set to +None). For most circuits, this will be equal to Self::default().

+

The circuit is given an opportunity to describe the exact gate +arrangement, column arrangement, etc.

+

Given the provided cs, synthesize the circuit. The concrete type of +the caller will be different depending on the context, and they may or +may not expect to have a witness present.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/trait.ColumnType.html b/docs/halo2_proofs/plonk/trait.ColumnType.html new file mode 100644 index 0000000000..4cdb09753f --- /dev/null +++ b/docs/halo2_proofs/plonk/trait.ColumnType.html @@ -0,0 +1,2 @@ +ColumnType in halo2_proofs::plonk - Rust
pub trait ColumnType: 'static + Sized + Copy + Debug + PartialEq + Eq + Into<Any> { }
Expand description

A column type

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/trait.FloorPlanner.html b/docs/halo2_proofs/plonk/trait.FloorPlanner.html new file mode 100644 index 0000000000..2ca2fd7766 --- /dev/null +++ b/docs/halo2_proofs/plonk/trait.FloorPlanner.html @@ -0,0 +1,16 @@ +FloorPlanner in halo2_proofs::plonk - Rust
pub trait FloorPlanner {
+    fn synthesize<F: Field, CS: Assignment<F>, C: Circuit<F>>(
        cs: &mut CS,
        circuit: &C,
        config: C::Config,
        constants: Vec<Column<Fixed>>
    ) -> Result<(), Error>; +}
Expand description

A floor planning strategy for a circuit.

+

The floor planner is chip-agnostic and applies its strategy to the circuit it is used +within.

+

Required Methods

Given the provided cs, synthesize the given circuit.

+

constants is the list of fixed columns that the layouter may use to assign +global constant values. These columns will all have been equality-enabled.

+

Internally, a floor planner will perform the following operations:

+
    +
  • Instantiate a Layouter for this floor planner.
  • +
  • Perform any necessary setup or measurement tasks, which may involve one or more +calls to Circuit::default().synthesize(config, &mut layouter).
  • +
  • Call circuit.synthesize(config, &mut layouter) exactly once.
  • +
+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/trait.Phase.html b/docs/halo2_proofs/plonk/trait.Phase.html new file mode 100644 index 0000000000..01a4b38228 --- /dev/null +++ b/docs/halo2_proofs/plonk/trait.Phase.html @@ -0,0 +1,2 @@ +Phase in halo2_proofs::plonk - Rust
pub trait Phase: SealedPhase { }
Expand description

Phase of advice column

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/plonk/verifier/batch/struct.BatchVerifier.html b/docs/halo2_proofs/plonk/verifier/batch/struct.BatchVerifier.html new file mode 100644 index 0000000000..5086ea9b4f --- /dev/null +++ b/docs/halo2_proofs/plonk/verifier/batch/struct.BatchVerifier.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../halo2_proofs/plonk/struct.BatchVerifier.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/plonk/verifier/fn.verify_proof.html b/docs/halo2_proofs/plonk/verifier/fn.verify_proof.html new file mode 100644 index 0000000000..1b331b53e2 --- /dev/null +++ b/docs/halo2_proofs/plonk/verifier/fn.verify_proof.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/plonk/fn.verify_proof.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/poly/commitment/index.html b/docs/halo2_proofs/poly/commitment/index.html new file mode 100644 index 0000000000..deabdc4338 --- /dev/null +++ b/docs/halo2_proofs/poly/commitment/index.html @@ -0,0 +1,2 @@ +halo2_proofs::poly::commitment - Rust
Expand description

Generic commitment scheme structures

+

Structs

Wrapper type around a blinding factor.

Traits

Defines components of a commitment scheme.
Multi scalar multiplication engine
Parameters for circuit sysnthesis and prover parameters.
Parameters for circuit sysnthesis and prover parameters.
Verifier specific functionality with circuit constaints
Common multi-open prover interface for various commitment schemes
Common multi-open verifier interface for various commitment schemes
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/commitment/sidebar-items.js b/docs/halo2_proofs/poly/commitment/sidebar-items.js new file mode 100644 index 0000000000..1ff53cdf0a --- /dev/null +++ b/docs/halo2_proofs/poly/commitment/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":[["Blind","Wrapper type around a blinding factor."]],"trait":[["CommitmentScheme","Defines components of a commitment scheme."],["MSM","Multi scalar multiplication engine"],["Params","Parameters for circuit sysnthesis and prover parameters."],["ParamsProver","Parameters for circuit sysnthesis and prover parameters."],["ParamsVerifier","Verifier specific functionality with circuit constaints"],["Prover","Common multi-open prover interface for various commitment schemes"],["Verifier","Common multi-open verifier interface for various commitment schemes"]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/poly/commitment/struct.Blind.html b/docs/halo2_proofs/poly/commitment/struct.Blind.html new file mode 100644 index 0000000000..9e75f4c08e --- /dev/null +++ b/docs/halo2_proofs/poly/commitment/struct.Blind.html @@ -0,0 +1,29 @@ +Blind in halo2_proofs::poly::commitment - Rust
pub struct Blind<F>(pub F);
Expand description

Wrapper type around a blinding factor.

+

Tuple Fields

0: F

Implementations

Given rng creates new blinding scalar

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/commitment/trait.CommitmentScheme.html b/docs/halo2_proofs/poly/commitment/trait.CommitmentScheme.html new file mode 100644 index 0000000000..5a33ad525e --- /dev/null +++ b/docs/halo2_proofs/poly/commitment/trait.CommitmentScheme.html @@ -0,0 +1,16 @@ +CommitmentScheme in halo2_proofs::poly::commitment - Rust
pub trait CommitmentScheme {
+    type Scalar: FieldExt + Group;
+    type Curve: CurveAffine<ScalarExt = Self::Scalar>;
+    type ParamsProver: for<'params> ParamsProver<'params, Self::Curve, ParamsVerifier = Self::ParamsVerifier>;
+    type ParamsVerifier: for<'params> ParamsVerifier<'params, Self::Curve>;
+
+    fn new_params(k: u32) -> Self::ParamsProver;
+    fn read_params<R: Read>(reader: &mut R) -> Result<Self::ParamsProver>;
+}
Expand description

Defines components of a commitment scheme.

+

Required Associated Types

Application field of this commitment scheme

+

Elliptic curve used to commit the application and witnesses

+

Constant prover parameters

+

Constant verifier parameters

+

Required Methods

Wrapper for parameter generator

+

Wrapper for parameter reader

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/poly/commitment/trait.MSM.html b/docs/halo2_proofs/poly/commitment/trait.MSM.html new file mode 100644 index 0000000000..5113449df2 --- /dev/null +++ b/docs/halo2_proofs/poly/commitment/trait.MSM.html @@ -0,0 +1,17 @@ +MSM in halo2_proofs::poly::commitment - Rust
pub trait MSM<C: CurveAffine>: Clone + Debug + Send + Sync {
+    fn append_term(&mut self, scalar: C::Scalar, point: C::CurveExt);
+    fn add_msm(&mut self, other: &Self)
    where
        Self: Sized
; + fn scale(&mut self, factor: C::Scalar); + fn check(&self) -> bool; + fn eval(&self) -> C::CurveExt; + fn bases(&self) -> Vec<C::CurveExt>; + fn scalars(&self) -> Vec<C::Scalar>; +}
Expand description

Multi scalar multiplication engine

+

Required Methods

Add arbitrary term (the scalar and the point)

+

Add another multiexp into this one

+

Scale all scalars in the MSM by some scaling factor

+

Perform multiexp and check that it results in zero

+

Perform multiexp and return the result

+

Return base points

+

Scalars

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/poly/commitment/trait.Params.html b/docs/halo2_proofs/poly/commitment/trait.Params.html new file mode 100644 index 0000000000..b8c2d87401 --- /dev/null +++ b/docs/halo2_proofs/poly/commitment/trait.Params.html @@ -0,0 +1,23 @@ +Params in halo2_proofs::poly::commitment - Rust
pub trait Params<'params, C: CurveAffine>: Sized + Clone {
+    type MSM: MSM<C> + 'params;
+
+    fn k(&self) -> u32;
+    fn n(&self) -> u64;
+    fn downsize(&mut self, k: u32);
+    fn empty_msm(&'params self) -> Self::MSM;
+    fn commit_lagrange(
        &self,
        poly: &Polynomial<C::ScalarExt, LagrangeCoeff>,
        r: Blind<C::ScalarExt>
    ) -> C::CurveExt; + fn write<W: Write>(&self, writer: &mut W) -> Result<()>; + fn read<R: Read>(reader: &mut R) -> Result<Self>; +}
Expand description

Parameters for circuit sysnthesis and prover parameters.

+

Required Associated Types

Multi scalar multiplication engine

+

Required Methods

Logaritmic size of the circuit

+

Size of the circuit

+

Downsize Params with smaller k.

+

Generates an empty multiscalar multiplication struct using the +appropriate params.

+

This commits to a polynomial using its evaluations over the $2^k$ size +evaluation domain. The commitment will be blinded by the blinding factor +r.

+

Writes params to a buffer.

+

Reads params from a buffer.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/poly/commitment/trait.ParamsProver.html b/docs/halo2_proofs/poly/commitment/trait.ParamsProver.html new file mode 100644 index 0000000000..f08aeac197 --- /dev/null +++ b/docs/halo2_proofs/poly/commitment/trait.ParamsProver.html @@ -0,0 +1,16 @@ +ParamsProver in halo2_proofs::poly::commitment - Rust
pub trait ParamsProver<'params, C: CurveAffine>: Params<'params, C> {
+    type ParamsVerifier: ParamsVerifier<'params, C>;
+
+    fn new(k: u32) -> Self;
+    fn commit(
        &self,
        poly: &Polynomial<C::ScalarExt, Coeff>,
        r: Blind<C::ScalarExt>
    ) -> C::CurveExt; + fn get_g(&self) -> &[C]Notable traits for &mut [u8]impl Write for &mut [u8]impl Read for &[u8]; + fn verifier_params(&'params self) -> &'params Self::ParamsVerifier; +}
Expand description

Parameters for circuit sysnthesis and prover parameters.

+

Required Associated Types

Constant verifier parameters.

+

Required Methods

Returns new instance of parameters

+

This computes a commitment to a polynomial described by the provided +slice of coefficients. The commitment may be blinded by the blinding +factor r.

+

Getter for g generators

+

Returns verification parameters.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/poly/commitment/trait.ParamsVerifier.html b/docs/halo2_proofs/poly/commitment/trait.ParamsVerifier.html new file mode 100644 index 0000000000..ac2718b74e --- /dev/null +++ b/docs/halo2_proofs/poly/commitment/trait.ParamsVerifier.html @@ -0,0 +1,2 @@ +ParamsVerifier in halo2_proofs::poly::commitment - Rust
pub trait ParamsVerifier<'params, C: CurveAffine>: Params<'params, C> { }
Expand description

Verifier specific functionality with circuit constaints

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/poly/commitment/trait.Prover.html b/docs/halo2_proofs/poly/commitment/trait.Prover.html new file mode 100644 index 0000000000..6fc3e45599 --- /dev/null +++ b/docs/halo2_proofs/poly/commitment/trait.Prover.html @@ -0,0 +1,12 @@ +Prover in halo2_proofs::poly::commitment - Rust
pub trait Prover<'params, Scheme: CommitmentScheme> {
+    const QUERY_INSTANCE: bool;
+
+    fn new(params: &'params Scheme::ParamsProver) -> Self;
+    fn create_proof<'com, E: EncodedChallenge<Scheme::Curve>, T: TranscriptWrite<Scheme::Curve, E>, R, I>(
        &self,
        rng: R,
        transcript: &mut T,
        queries: I
    ) -> Result<()>
    where
        I: IntoIterator<Item = ProverQuery<'com, Scheme::Curve>> + Clone,
        R: RngCore
; +}
Expand description

Common multi-open prover interface for various commitment schemes

+

Required Associated Constants

Query instance or not

+

Required Methods

Creates new prover instance

+

Create a multi-opening proof

+

Implementors

Create a multi-opening proof

+

Create a multi-opening proof

+
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/commitment/trait.Verifier.html b/docs/halo2_proofs/poly/commitment/trait.Verifier.html new file mode 100644 index 0000000000..77cb2d24b3 --- /dev/null +++ b/docs/halo2_proofs/poly/commitment/trait.Verifier.html @@ -0,0 +1,16 @@ +Verifier in halo2_proofs::poly::commitment - Rust
pub trait Verifier<'params, Scheme: CommitmentScheme> {
+    type Guard: Guard<Scheme, MSMAccumulator = Self::MSMAccumulator>;
+    type MSMAccumulator;
+
+    const QUERY_INSTANCE: bool;
+
+    fn new(params: &'params Scheme::ParamsVerifier) -> Self;
+    fn verify_proof<'com, E: EncodedChallenge<Scheme::Curve>, T: TranscriptRead<Scheme::Curve, E>, I>(
        &self,
        transcript: &mut T,
        queries: I,
        msm: Self::MSMAccumulator
    ) -> Result<Self::Guard, Error>
    where
        'params: 'com,
        I: IntoIterator<Item = VerifierQuery<'com, Scheme::Curve, <Scheme::ParamsVerifier as Params<'params, Scheme::Curve>>::MSM>> + Clone
; +}
Expand description

Common multi-open verifier interface for various commitment schemes

+

Required Associated Types

Unfinalized verification result. This is returned in verification +to allow developer to compress or combined verification results

+

Accumulator fot comressed verification

+

Required Associated Constants

Query instance or not

+

Required Methods

Creates new verifier instance

+

Process the proof and returns unfinished result named Guard

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/poly/domain/struct.EvaluationDomain.html b/docs/halo2_proofs/poly/domain/struct.EvaluationDomain.html new file mode 100644 index 0000000000..6787b596a6 --- /dev/null +++ b/docs/halo2_proofs/poly/domain/struct.EvaluationDomain.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/poly/struct.EvaluationDomain.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/poly/domain/struct.PinnedEvaluationDomain.html b/docs/halo2_proofs/poly/domain/struct.PinnedEvaluationDomain.html new file mode 100644 index 0000000000..f7159290df --- /dev/null +++ b/docs/halo2_proofs/poly/domain/struct.PinnedEvaluationDomain.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/poly/struct.PinnedEvaluationDomain.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/poly/enum.Error.html b/docs/halo2_proofs/poly/enum.Error.html new file mode 100644 index 0000000000..90da5a54f3 --- /dev/null +++ b/docs/halo2_proofs/poly/enum.Error.html @@ -0,0 +1,31 @@ +Error in halo2_proofs::poly - Rust
pub enum Error {
+    OpeningError,
+    SamplingError,
+}
Expand description

This is an error that could occur during proving or circuit synthesis.

+

Variants

OpeningError

OpeningProof is not well-formed

+

SamplingError

Caller needs to re-sample a point

+

Trait Implementations

Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/index.html b/docs/halo2_proofs/poly/index.html new file mode 100644 index 0000000000..d06ada65af --- /dev/null +++ b/docs/halo2_proofs/poly/index.html @@ -0,0 +1,11 @@ +halo2_proofs::poly - Rust
Expand description

Contains utilities for performing arithmetic over univariate polynomials in +various forms, including computing commitments to them and provably opening +the committed polynomials at arbitrary points.

+

Modules

Generic commitment scheme structures
Inner product argument commitment scheme
KZG commitment scheme

Structs

The polynomial is defined as coefficients
This structure contains precomputed constants and other details needed for +performing operations on an evaluation domain of size $2^k$ and an extended +domain of size $2^{k} * j$ with $j \neq 0$.
The polynomial is defined as coefficients of Lagrange basis polynomials in +an extended size domain which supports multiplication
The polynomial is defined as coefficients of Lagrange basis polynomials
Represents the minimal parameters that determine an EvaluationDomain.
Represents a univariate polynomial defined over a field and a particular +basis.
A polynomial query at a point
Describes the relative rotation of a vector. Negative numbers represent +reverse (leftmost) rotations and positive numbers represent forward (rightmost) +rotations. Zero represents no rotation.
A polynomial query at a point

Enums

This is an error that could occur during proving or circuit synthesis.

Traits

The basis over which a polynomial is described.
Guards is unfinished verification result. Implement this to construct various +verification strategies such as aggregation and recursion.
Trait representing a strategy for verifying Halo 2 proofs.
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/commitment/fn.create_proof.html b/docs/halo2_proofs/poly/ipa/commitment/fn.create_proof.html new file mode 100644 index 0000000000..16b132d354 --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/commitment/fn.create_proof.html @@ -0,0 +1,12 @@ +create_proof in halo2_proofs::poly::ipa::commitment - Rust
pub fn create_proof<C: CurveAffine, E: EncodedChallenge<C>, R: RngCore, T: TranscriptWrite<C, E>>(
    params: &ParamsIPA<C>,
    rng: R,
    transcript: &mut T,
    p_poly: &Polynomial<C::Scalar, Coeff>,
    p_blind: Blind<C::Scalar>,
    x_3: C::Scalar
) -> Result<()>
Expand description

Create a polynomial commitment opening proof for the polynomial defined +by the coefficients px, the blinding factor blind used for the +polynomial commitment, and the point x that the polynomial is +evaluated at.

+

This function will panic if the provided polynomial is too large with +respect to the polynomial commitment parameters.

+

Important: This function assumes that the provided transcript has +already seen the common inputs: the polynomial commitment P, the claimed +opening v, and the point x. It’s probably also nice for the transcript +to have seen the elliptic curve description and the URS, if you want to +be rigorous.

+
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/commitment/fn.verify_proof.html b/docs/halo2_proofs/poly/ipa/commitment/fn.verify_proof.html new file mode 100644 index 0000000000..10a1625336 --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/commitment/fn.verify_proof.html @@ -0,0 +1,4 @@ +verify_proof in halo2_proofs::poly::ipa::commitment - Rust
pub fn verify_proof<'params, C: CurveAffine, E: EncodedChallenge<C>, T: TranscriptRead<C, E>>(
    params: &'params ParamsIPA<C>,
    msm: MSMIPA<'params, C>,
    transcript: &mut T,
    x: C::Scalar,
    v: C::Scalar
) -> Result<GuardIPA<'params, C>, Error>
Expand description

Checks to see if the proof represented within transcript is valid, and a +point x that the polynomial commitment P opens purportedly to the value +v. The provided msm should evaluate to the commitment P being opened.

+
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/commitment/index.html b/docs/halo2_proofs/poly/ipa/commitment/index.html new file mode 100644 index 0000000000..d895e3fbc9 --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/commitment/index.html @@ -0,0 +1,8 @@ +halo2_proofs::poly::ipa::commitment - Rust
Expand description

This module contains an implementation of the polynomial commitment scheme +described in the Halo paper.

+

Structs

Concrete IPA commitment scheme
Public parameters for IPA commitment scheme

Functions

Create a polynomial commitment opening proof for the polynomial defined +by the coefficients px, the blinding factor blind used for the +polynomial commitment, and the point x that the polynomial is +evaluated at.
Checks to see if the proof represented within transcript is valid, and a +point x that the polynomial commitment P opens purportedly to the value +v. The provided msm should evaluate to the commitment P being opened.

Type Definitions

Verifier parameters
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/commitment/prover/fn.create_proof.html b/docs/halo2_proofs/poly/ipa/commitment/prover/fn.create_proof.html new file mode 100644 index 0000000000..c241cfb9c9 --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/commitment/prover/fn.create_proof.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../../halo2_proofs/poly/ipa/commitment/fn.create_proof.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/commitment/sidebar-items.js b/docs/halo2_proofs/poly/ipa/commitment/sidebar-items.js new file mode 100644 index 0000000000..a4b52eb4eb --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/commitment/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"fn":[["create_proof","Create a polynomial commitment opening proof for the polynomial defined by the coefficients `px`, the blinding factor `blind` used for the polynomial commitment, and the point `x` that the polynomial is evaluated at."],["verify_proof","Checks to see if the proof represented within `transcript` is valid, and a point `x` that the polynomial commitment `P` opens purportedly to the value `v`. The provided `msm` should evaluate to the commitment `P` being opened."]],"struct":[["IPACommitmentScheme","Concrete IPA commitment scheme"],["ParamsIPA","Public parameters for IPA commitment scheme"]],"type":[["ParamsVerifierIPA","Verifier parameters"]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/commitment/struct.IPACommitmentScheme.html b/docs/halo2_proofs/poly/ipa/commitment/struct.IPACommitmentScheme.html new file mode 100644 index 0000000000..1edb713315 --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/commitment/struct.IPACommitmentScheme.html @@ -0,0 +1,37 @@ +IPACommitmentScheme in halo2_proofs::poly::ipa::commitment - Rust
pub struct IPACommitmentScheme<C: CurveAffine> { /* private fields */ }
Expand description

Concrete IPA commitment scheme

+

Trait Implementations

Application field of this commitment scheme
Elliptic curve used to commit the application and witnesses
Constant prover parameters
Constant verifier parameters
Wrapper for parameter generator
Wrapper for parameter reader
Formats the value using the given formatter. Read more

Define accumulator type as MSMIPA

+
Multi scalar engine which is not evaluated yet.

Create a multi-opening proof

+
Query instance or not
Creates new prover instance

Finalizes the batch and checks its validity.

+

Returns false if some proof was invalid. If the caller needs to identify +specific failing proofs, it must re-process the proofs separately.

+
The output type of this verification strategy after processing a proof.
Creates new verification strategy instance
Obtains an MSM from the verifier strategy and yields back the strategy’s +output. Read more

Finalizes the batch and checks its validity.

+

Returns false if some proof was invalid. If the caller needs to identify +specific failing proofs, it must re-process the proofs separately.

+
The output type of this verification strategy after processing a proof.
Creates new verification strategy instance
Obtains an MSM from the verifier strategy and yields back the strategy’s +output. Read more
Unfinalized verification result. This is returned in verification +to allow developer to compress or combined verification results Read more
Accumulator fot comressed verification
Query instance or not
Creates new verifier instance
Process the proof and returns unfinished result named Guard

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/commitment/struct.ParamsIPA.html b/docs/halo2_proofs/poly/ipa/commitment/struct.ParamsIPA.html new file mode 100644 index 0000000000..751ba3ffac --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/commitment/struct.ParamsIPA.html @@ -0,0 +1,37 @@ +ParamsIPA in halo2_proofs::poly::ipa::commitment - Rust
pub struct ParamsIPA<C: CurveAffine> { /* private fields */ }
Expand description

Public parameters for IPA commitment scheme

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

This commits to a polynomial using its evaluations over the $2^k$ size +evaluation domain. The commitment will be blinded by the blinding factor +r.

+

Writes params to a buffer.

+

Reads params from a buffer.

+
Multi scalar multiplication engine
Logaritmic size of the circuit
Size of the circuit
Downsize Params with smaller k.
Generates an empty multiscalar multiplication struct using the +appropriate params. Read more

Initializes parameters for the curve, given a random oracle to draw +points from.

+

This computes a commitment to a polynomial described by the provided +slice of coefficients. The commitment will be blinded by the blinding +factor r.

+
Constant verifier parameters.
Returns verification parameters.
Getter for g generators

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/commitment/type.ParamsVerifierIPA.html b/docs/halo2_proofs/poly/ipa/commitment/type.ParamsVerifierIPA.html new file mode 100644 index 0000000000..ae253d35e7 --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/commitment/type.ParamsVerifierIPA.html @@ -0,0 +1,2 @@ +ParamsVerifierIPA in halo2_proofs::poly::ipa::commitment - Rust
pub type ParamsVerifierIPA<C> = ParamsIPA<C>;
Expand description

Verifier parameters

+
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/commitment/verifier/fn.verify_proof.html b/docs/halo2_proofs/poly/ipa/commitment/verifier/fn.verify_proof.html new file mode 100644 index 0000000000..6170636c38 --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/commitment/verifier/fn.verify_proof.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../../halo2_proofs/poly/ipa/commitment/fn.verify_proof.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/index.html b/docs/halo2_proofs/poly/ipa/index.html new file mode 100644 index 0000000000..b53606a4e2 --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/index.html @@ -0,0 +1,5 @@ +halo2_proofs::poly::ipa - Rust
Expand description

Inner product argument commitment scheme

+

Modules

This module contains an implementation of the polynomial commitment scheme +described in the Halo paper.
Multiscalar multiplication engines
IPA multi-open scheme +This module contains an optimisation of the polynomial commitment opening +scheme described in the Halo paper.
Strategies used with KZG scheme
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/msm/index.html b/docs/halo2_proofs/poly/ipa/msm/index.html new file mode 100644 index 0000000000..4502568eab --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/msm/index.html @@ -0,0 +1,2 @@ +halo2_proofs::poly::ipa::msm - Rust
Expand description

Multiscalar multiplication engines

+

Structs

A multiscalar multiplication in the polynomial commitment scheme
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/msm/sidebar-items.js b/docs/halo2_proofs/poly/ipa/msm/sidebar-items.js new file mode 100644 index 0000000000..02ea62c310 --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/msm/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":[["MSMIPA","A multiscalar multiplication in the polynomial commitment scheme"]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/msm/struct.MSMIPA.html b/docs/halo2_proofs/poly/ipa/msm/struct.MSMIPA.html new file mode 100644 index 0000000000..fc5460c100 --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/msm/struct.MSMIPA.html @@ -0,0 +1,34 @@ +MSMIPA in halo2_proofs::poly::ipa::msm - Rust
pub struct MSMIPA<'params, C: CurveAffine> { /* private fields */ }
Expand description

A multiscalar multiplication in the polynomial commitment scheme

+

Implementations

Given verifier parameters Creates an empty multi scalar engine

+

Add another multiexp into this one

+

Add a value to the first entry of g_scalars.

+

Add a vector of scalars to g_scalars. This function will panic if the +caller provides a slice of scalars that is not of length params.n.

+

Add to w_scalar

+

Add to u_scalar

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Add another multiexp into this one

+
Add arbitrary term (the scalar and the point)
Scale all scalars in the MSM by some scaling factor
Perform multiexp and check that it results in zero
Perform multiexp and return the result
Return base points
Scalars

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/multiopen/index.html b/docs/halo2_proofs/poly/ipa/multiopen/index.html new file mode 100644 index 0000000000..3b4a656707 --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/multiopen/index.html @@ -0,0 +1,4 @@ +halo2_proofs::poly::ipa::multiopen - Rust
Expand description

IPA multi-open scheme +This module contains an optimisation of the polynomial commitment opening +scheme described in the Halo paper.

+

Structs

IPA multi-open prover
IPA multi-open verifier
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/multiopen/prover/struct.ProverIPA.html b/docs/halo2_proofs/poly/ipa/multiopen/prover/struct.ProverIPA.html new file mode 100644 index 0000000000..8aac7a2b58 --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/multiopen/prover/struct.ProverIPA.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../../halo2_proofs/poly/ipa/multiopen/struct.ProverIPA.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/multiopen/sidebar-items.js b/docs/halo2_proofs/poly/ipa/multiopen/sidebar-items.js new file mode 100644 index 0000000000..bebf71b56e --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/multiopen/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":[["ProverIPA","IPA multi-open prover"],["VerifierIPA","IPA multi-open verifier"]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/multiopen/struct.ProverIPA.html b/docs/halo2_proofs/poly/ipa/multiopen/struct.ProverIPA.html new file mode 100644 index 0000000000..62a833f053 --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/multiopen/struct.ProverIPA.html @@ -0,0 +1,27 @@ +ProverIPA in halo2_proofs::poly::ipa::multiopen - Rust
pub struct ProverIPA<'params, C: CurveAffine> { /* private fields */ }
Expand description

IPA multi-open prover

+

Trait Implementations

Formats the value using the given formatter. Read more

Create a multi-opening proof

+
Query instance or not
Creates new prover instance

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/multiopen/struct.VerifierIPA.html b/docs/halo2_proofs/poly/ipa/multiopen/struct.VerifierIPA.html new file mode 100644 index 0000000000..2aa7c458ef --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/multiopen/struct.VerifierIPA.html @@ -0,0 +1,35 @@ +VerifierIPA in halo2_proofs::poly::ipa::multiopen - Rust
pub struct VerifierIPA<'params, C: CurveAffine> { /* private fields */ }
Expand description

IPA multi-open verifier

+

Trait Implementations

Formats the value using the given formatter. Read more

Finalizes the batch and checks its validity.

+

Returns false if some proof was invalid. If the caller needs to identify +specific failing proofs, it must re-process the proofs separately.

+
The output type of this verification strategy after processing a proof.
Creates new verification strategy instance
Obtains an MSM from the verifier strategy and yields back the strategy’s +output. Read more

Finalizes the batch and checks its validity.

+

Returns false if some proof was invalid. If the caller needs to identify +specific failing proofs, it must re-process the proofs separately.

+
The output type of this verification strategy after processing a proof.
Creates new verification strategy instance
Obtains an MSM from the verifier strategy and yields back the strategy’s +output. Read more
Unfinalized verification result. This is returned in verification +to allow developer to compress or combined verification results Read more
Accumulator fot comressed verification
Query instance or not
Creates new verifier instance
Process the proof and returns unfinished result named Guard

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/multiopen/verifier/struct.VerifierIPA.html b/docs/halo2_proofs/poly/ipa/multiopen/verifier/struct.VerifierIPA.html new file mode 100644 index 0000000000..36dd0285e2 --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/multiopen/verifier/struct.VerifierIPA.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../../halo2_proofs/poly/ipa/multiopen/struct.VerifierIPA.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/sidebar-items.js b/docs/halo2_proofs/poly/ipa/sidebar-items.js new file mode 100644 index 0000000000..c920d1613a --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":[["commitment","This module contains an implementation of the polynomial commitment scheme described in the Halo paper."],["msm","Multiscalar multiplication engines"],["multiopen","IPA multi-open scheme This module contains an optimisation of the polynomial commitment opening scheme described in the Halo paper."],["strategy","Strategies used with KZG scheme"]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/strategy/index.html b/docs/halo2_proofs/poly/ipa/strategy/index.html new file mode 100644 index 0000000000..9bf7acf99b --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/strategy/index.html @@ -0,0 +1,2 @@ +halo2_proofs::poly::ipa::strategy - Rust
Expand description

Strategies used with KZG scheme

+

Structs

An accumulator instance consisting of an evaluation claim and a proof.
A verifier that checks multiple proofs in a batch.
Wrapper for verification accumulator
A verifier that checks single proof
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/strategy/sidebar-items.js b/docs/halo2_proofs/poly/ipa/strategy/sidebar-items.js new file mode 100644 index 0000000000..ef955eac5d --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/strategy/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":[["Accumulator","An accumulator instance consisting of an evaluation claim and a proof."],["AccumulatorStrategy","A verifier that checks multiple proofs in a batch."],["GuardIPA","Wrapper for verification accumulator"],["SingleStrategy","A verifier that checks single proof"]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/strategy/struct.Accumulator.html b/docs/halo2_proofs/poly/ipa/strategy/struct.Accumulator.html new file mode 100644 index 0000000000..3dc6158e6e --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/strategy/struct.Accumulator.html @@ -0,0 +1,32 @@ +Accumulator in halo2_proofs::poly::ipa::strategy - Rust
pub struct Accumulator<C: CurveAffine> {
+    pub g: C,
+    pub u_packed: Vec<C::Scalar>,
+}
Expand description

An accumulator instance consisting of an evaluation claim and a proof.

+

Fields

g: C

The claimed output of the linear-time polycommit opening protocol

+
u_packed: Vec<C::Scalar>

A vector of challenges u_0, …, u_{k - 1} sampled by the verifier, to +be used in computing G’_0.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/strategy/struct.AccumulatorStrategy.html b/docs/halo2_proofs/poly/ipa/strategy/struct.AccumulatorStrategy.html new file mode 100644 index 0000000000..a0b4afed4a --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/strategy/struct.AccumulatorStrategy.html @@ -0,0 +1,30 @@ +AccumulatorStrategy in halo2_proofs::poly::ipa::strategy - Rust
pub struct AccumulatorStrategy<'params, C: CurveAffine> { /* private fields */ }
Expand description

A verifier that checks multiple proofs in a batch.

+

Trait Implementations

Formats the value using the given formatter. Read more

Finalizes the batch and checks its validity.

+

Returns false if some proof was invalid. If the caller needs to identify +specific failing proofs, it must re-process the proofs separately.

+
The output type of this verification strategy after processing a proof.
Creates new verification strategy instance
Obtains an MSM from the verifier strategy and yields back the strategy’s +output. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/strategy/struct.GuardIPA.html b/docs/halo2_proofs/poly/ipa/strategy/struct.GuardIPA.html new file mode 100644 index 0000000000..dce9401662 --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/strategy/struct.GuardIPA.html @@ -0,0 +1,33 @@ +GuardIPA in halo2_proofs::poly::ipa::strategy - Rust
pub struct GuardIPA<'params, C: CurveAffine> { /* private fields */ }
Expand description

Wrapper for verification accumulator

+

Implementations

IPA specific operations

+

Lets caller supply the challenges and obtain an MSM with updated +scalars and points.

+

Lets caller supply the purported G point and simply appends +[-c] G to return an updated MSM.

+

Computes G = ⟨s, params.g⟩

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Define accumulator type as MSMIPA

+
Multi scalar engine which is not evaluated yet.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/ipa/strategy/struct.SingleStrategy.html b/docs/halo2_proofs/poly/ipa/strategy/struct.SingleStrategy.html new file mode 100644 index 0000000000..46b9a8cae9 --- /dev/null +++ b/docs/halo2_proofs/poly/ipa/strategy/struct.SingleStrategy.html @@ -0,0 +1,30 @@ +SingleStrategy in halo2_proofs::poly::ipa::strategy - Rust
pub struct SingleStrategy<'params, C: CurveAffine> { /* private fields */ }
Expand description

A verifier that checks single proof

+

Trait Implementations

Formats the value using the given formatter. Read more

Finalizes the batch and checks its validity.

+

Returns false if some proof was invalid. If the caller needs to identify +specific failing proofs, it must re-process the proofs separately.

+
The output type of this verification strategy after processing a proof.
Creates new verification strategy instance
Obtains an MSM from the verifier strategy and yields back the strategy’s +output. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/commitment/index.html b/docs/halo2_proofs/poly/kzg/commitment/index.html new file mode 100644 index 0000000000..95cc521a5f --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/commitment/index.html @@ -0,0 +1,2 @@ +halo2_proofs::poly::kzg::commitment - Rust
Expand description

KZG commitment scheme

+

Structs

Umbrella commitment scheme construction for all KZG variants
These are the public parameters for the polynomial commitment scheme.

Type Definitions

KZG multi-open verification parameters
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/commitment/sidebar-items.js b/docs/halo2_proofs/poly/kzg/commitment/sidebar-items.js new file mode 100644 index 0000000000..e7d555876c --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/commitment/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":[["KZGCommitmentScheme","Umbrella commitment scheme construction for all KZG variants"],["ParamsKZG","These are the public parameters for the polynomial commitment scheme."]],"type":[["ParamsVerifierKZG","KZG multi-open verification parameters"]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/commitment/struct.KZGCommitmentScheme.html b/docs/halo2_proofs/poly/kzg/commitment/struct.KZGCommitmentScheme.html new file mode 100644 index 0000000000..ac76312e19 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/commitment/struct.KZGCommitmentScheme.html @@ -0,0 +1,36 @@ +KZGCommitmentScheme in halo2_proofs::poly::kzg::commitment - Rust
pub struct KZGCommitmentScheme<E: Engine> { /* private fields */ }
Expand description

Umbrella commitment scheme construction for all KZG variants

+

Trait Implementations

Application field of this commitment scheme
Elliptic curve used to commit the application and witnesses
Constant prover parameters
Constant verifier parameters
Wrapper for parameter generator
Wrapper for parameter reader
Formats the value using the given formatter. Read more

Define accumulator type as DualMSM

+
Multi scalar engine which is not evaluated yet.

Create a multi-opening proof

+

Create a multi-opening proof

+
Query instance or not
Creates new prover instance

Create a multi-opening proof

+

Create a multi-opening proof

+
Query instance or not
Creates new prover instance
The output type of this verification strategy after processing a proof.
Creates new verification strategy instance
Obtains an MSM from the verifier strategy and yields back the strategy’s +output. Read more
Finalizes the batch and checks its validity. Read more
The output type of this verification strategy after processing a proof.
Creates new verification strategy instance
Obtains an MSM from the verifier strategy and yields back the strategy’s +output. Read more
Finalizes the batch and checks its validity. Read more
Unfinalized verification result. This is returned in verification +to allow developer to compress or combined verification results Read more
Accumulator fot comressed verification
Query instance or not
Creates new verifier instance
Process the proof and returns unfinished result named Guard

Verify a multi-opening proof

+
Unfinalized verification result. This is returned in verification +to allow developer to compress or combined verification results Read more
Accumulator fot comressed verification
Query instance or not
Creates new verifier instance

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/commitment/struct.ParamsKZG.html b/docs/halo2_proofs/poly/kzg/commitment/struct.ParamsKZG.html new file mode 100644 index 0000000000..5389a40bd7 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/commitment/struct.ParamsKZG.html @@ -0,0 +1,39 @@ +ParamsKZG in halo2_proofs::poly::kzg::commitment - Rust
pub struct ParamsKZG<E: Engine> { /* private fields */ }
Expand description

These are the public parameters for the polynomial commitment scheme.

+

Implementations

Initializes parameters for the curve, draws toxic secret from given rng. +MUST NOT be used in production.

+

Returns gernerator on G2

+

Returns first power of secret on G2

+

Writes parameters to buffer

+

Reads params from a buffer.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.

Writes params to a buffer.

+

Reads params from a buffer.

+
Multi scalar multiplication engine
Logaritmic size of the circuit
Size of the circuit
Downsize Params with smaller k.
Generates an empty multiscalar multiplication struct using the +appropriate params. Read more
This commits to a polynomial using its evaluations over the $2^k$ size +evaluation domain. The commitment will be blinded by the blinding factor +r. Read more
Constant verifier parameters.
Returns verification parameters.
Returns new instance of parameters
This computes a commitment to a polynomial described by the provided +slice of coefficients. The commitment may be blinded by the blinding +factor r. Read more
Getter for g generators

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/commitment/type.ParamsVerifierKZG.html b/docs/halo2_proofs/poly/kzg/commitment/type.ParamsVerifierKZG.html new file mode 100644 index 0000000000..bdb145107d --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/commitment/type.ParamsVerifierKZG.html @@ -0,0 +1,2 @@ +ParamsVerifierKZG in halo2_proofs::poly::kzg::commitment - Rust
pub type ParamsVerifierKZG<C> = ParamsKZG<C>;
Expand description

KZG multi-open verification parameters

+
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/index.html b/docs/halo2_proofs/poly/kzg/index.html new file mode 100644 index 0000000000..40b58ad58f --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/index.html @@ -0,0 +1,2 @@ +halo2_proofs::poly::kzg - Rust
Expand description

KZG commitment scheme

+

Modules

KZG commitment scheme
Multiscalar multiplication engines
KZG multi-open scheme
Strategies used with KZG scheme
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/msm/index.html b/docs/halo2_proofs/poly/kzg/msm/index.html new file mode 100644 index 0000000000..004cd92857 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/msm/index.html @@ -0,0 +1,2 @@ +halo2_proofs::poly::kzg::msm - Rust
Expand description

Multiscalar multiplication engines

+

Structs

Two channel MSM accumulator
A multiscalar multiplication in the polynomial commitment scheme
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/msm/sidebar-items.js b/docs/halo2_proofs/poly/kzg/msm/sidebar-items.js new file mode 100644 index 0000000000..bc953ccd19 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/msm/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":[["DualMSM","Two channel MSM accumulator"],["MSMKZG","A multiscalar multiplication in the polynomial commitment scheme"]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/msm/struct.DualMSM.html b/docs/halo2_proofs/poly/kzg/msm/struct.DualMSM.html new file mode 100644 index 0000000000..449fbf4770 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/msm/struct.DualMSM.html @@ -0,0 +1,30 @@ +DualMSM in halo2_proofs::poly::kzg::msm - Rust
pub struct DualMSM<'a, E: Engine> { /* private fields */ }
Expand description

Two channel MSM accumulator

+

Implementations

Create a new two channel MSM accumulator instance

+

Scale all scalars in the MSM by some scaling factor

+

Add another multiexp into this one

+

Performs final pairing check with given verifier params and two channel linear combination

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/msm/struct.MSMKZG.html b/docs/halo2_proofs/poly/kzg/msm/struct.MSMKZG.html new file mode 100644 index 0000000000..85ed65b30f --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/msm/struct.MSMKZG.html @@ -0,0 +1,28 @@ +MSMKZG in halo2_proofs::poly::kzg::msm - Rust
pub struct MSMKZG<E: Engine> { /* private fields */ }
Expand description

A multiscalar multiplication in the polynomial commitment scheme

+

Implementations

Create an empty MSM instance

+

Prepares all scalars in the MSM to linear combination

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Add arbitrary term (the scalar and the point)
Add another multiexp into this one
Scale all scalars in the MSM by some scaling factor
Perform multiexp and check that it results in zero
Perform multiexp and return the result
Return base points
Scalars

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/multiopen/gwc/prover/struct.ProverGWC.html b/docs/halo2_proofs/poly/kzg/multiopen/gwc/prover/struct.ProverGWC.html new file mode 100644 index 0000000000..b0455d0203 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/multiopen/gwc/prover/struct.ProverGWC.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../../../halo2_proofs/poly/kzg/multiopen/struct.ProverGWC.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/multiopen/gwc/verifier/struct.VerifierGWC.html b/docs/halo2_proofs/poly/kzg/multiopen/gwc/verifier/struct.VerifierGWC.html new file mode 100644 index 0000000000..b83cf6c201 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/multiopen/gwc/verifier/struct.VerifierGWC.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../../../halo2_proofs/poly/kzg/multiopen/struct.VerifierGWC.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/multiopen/index.html b/docs/halo2_proofs/poly/kzg/multiopen/index.html new file mode 100644 index 0000000000..597504c9bd --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/multiopen/index.html @@ -0,0 +1,2 @@ +halo2_proofs::poly::kzg::multiopen - Rust
Expand description

KZG multi-open scheme

+

Structs

Concrete KZG prover with GWC variant
Concrete KZG prover with SHPLONK variant
Concrete KZG verifier with GWC variant
Concrete KZG multiopen verifier with SHPLONK variant
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/multiopen/shplonk/prover/struct.ProverSHPLONK.html b/docs/halo2_proofs/poly/kzg/multiopen/shplonk/prover/struct.ProverSHPLONK.html new file mode 100644 index 0000000000..62b14bdaee --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/multiopen/shplonk/prover/struct.ProverSHPLONK.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../../../halo2_proofs/poly/kzg/multiopen/struct.ProverSHPLONK.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/multiopen/shplonk/verifier/struct.VerifierSHPLONK.html b/docs/halo2_proofs/poly/kzg/multiopen/shplonk/verifier/struct.VerifierSHPLONK.html new file mode 100644 index 0000000000..3f4cf0296d --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/multiopen/shplonk/verifier/struct.VerifierSHPLONK.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../../../../halo2_proofs/poly/kzg/multiopen/struct.VerifierSHPLONK.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/multiopen/sidebar-items.js b/docs/halo2_proofs/poly/kzg/multiopen/sidebar-items.js new file mode 100644 index 0000000000..7d90f59602 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/multiopen/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":[["ProverGWC","Concrete KZG prover with GWC variant"],["ProverSHPLONK","Concrete KZG prover with SHPLONK variant"],["VerifierGWC","Concrete KZG verifier with GWC variant"],["VerifierSHPLONK","Concrete KZG multiopen verifier with SHPLONK variant"]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/multiopen/struct.ProverGWC.html b/docs/halo2_proofs/poly/kzg/multiopen/struct.ProverGWC.html new file mode 100644 index 0000000000..17c0e5c348 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/multiopen/struct.ProverGWC.html @@ -0,0 +1,28 @@ +ProverGWC in halo2_proofs::poly::kzg::multiopen - Rust
pub struct ProverGWC<'params, E: Engine> { /* private fields */ }
Expand description

Concrete KZG prover with GWC variant

+

Trait Implementations

Formats the value using the given formatter. Read more

Create a multi-opening proof

+

Create a multi-opening proof

+
Query instance or not
Creates new prover instance

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/multiopen/struct.ProverSHPLONK.html b/docs/halo2_proofs/poly/kzg/multiopen/struct.ProverSHPLONK.html new file mode 100644 index 0000000000..651a4ee617 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/multiopen/struct.ProverSHPLONK.html @@ -0,0 +1,29 @@ +ProverSHPLONK in halo2_proofs::poly::kzg::multiopen - Rust
pub struct ProverSHPLONK<'a, E: Engine> { /* private fields */ }
Expand description

Concrete KZG prover with SHPLONK variant

+

Implementations

Given parameters creates new prover instance

+

Trait Implementations

Formats the value using the given formatter. Read more

Create a multi-opening proof

+

Create a multi-opening proof

+
Query instance or not
Creates new prover instance

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/multiopen/struct.VerifierGWC.html b/docs/halo2_proofs/poly/kzg/multiopen/struct.VerifierGWC.html new file mode 100644 index 0000000000..ba649ca7d2 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/multiopen/struct.VerifierGWC.html @@ -0,0 +1,27 @@ +VerifierGWC in halo2_proofs::poly::kzg::multiopen - Rust
pub struct VerifierGWC<'params, E: Engine> { /* private fields */ }
Expand description

Concrete KZG verifier with GWC variant

+

Trait Implementations

Formats the value using the given formatter. Read more
Unfinalized verification result. This is returned in verification +to allow developer to compress or combined verification results Read more
Accumulator fot comressed verification
Query instance or not
Creates new verifier instance
Process the proof and returns unfinished result named Guard

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/multiopen/struct.VerifierSHPLONK.html b/docs/halo2_proofs/poly/kzg/multiopen/struct.VerifierSHPLONK.html new file mode 100644 index 0000000000..3d5fba6bc9 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/multiopen/struct.VerifierSHPLONK.html @@ -0,0 +1,28 @@ +VerifierSHPLONK in halo2_proofs::poly::kzg::multiopen - Rust
pub struct VerifierSHPLONK<'params, E: Engine> { /* private fields */ }
Expand description

Concrete KZG multiopen verifier with SHPLONK variant

+

Trait Implementations

Formats the value using the given formatter. Read more

Verify a multi-opening proof

+
Unfinalized verification result. This is returned in verification +to allow developer to compress or combined verification results Read more
Accumulator fot comressed verification
Query instance or not
Creates new verifier instance

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/sidebar-items.js b/docs/halo2_proofs/poly/kzg/sidebar-items.js new file mode 100644 index 0000000000..d01671c235 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":[["commitment","KZG commitment scheme"],["msm","Multiscalar multiplication engines"],["multiopen","KZG multi-open scheme"],["strategy","Strategies used with KZG scheme"]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/strategy/index.html b/docs/halo2_proofs/poly/kzg/strategy/index.html new file mode 100644 index 0000000000..90376fd798 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/strategy/index.html @@ -0,0 +1,2 @@ +halo2_proofs::poly::kzg::strategy - Rust
Expand description

Strategies used with KZG scheme

+

Structs

A verifier that checks multiple proofs in a batch
Wrapper for linear verification accumulator
A verifier that checks a single proof
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/strategy/sidebar-items.js b/docs/halo2_proofs/poly/kzg/strategy/sidebar-items.js new file mode 100644 index 0000000000..3d48744d8f --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/strategy/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":[["AccumulatorStrategy","A verifier that checks multiple proofs in a batch"],["GuardKZG","Wrapper for linear verification accumulator"],["SingleStrategy","A verifier that checks a single proof"]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/strategy/struct.AccumulatorStrategy.html b/docs/halo2_proofs/poly/kzg/strategy/struct.AccumulatorStrategy.html new file mode 100644 index 0000000000..e8573a5120 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/strategy/struct.AccumulatorStrategy.html @@ -0,0 +1,29 @@ +AccumulatorStrategy in halo2_proofs::poly::kzg::strategy - Rust
pub struct AccumulatorStrategy<'params, E: Engine> { /* private fields */ }
Expand description

A verifier that checks multiple proofs in a batch

+

Implementations

Constructs an empty batch verifier

+

Constructs and initialized new batch verifier

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
The output type of this verification strategy after processing a proof.
Creates new verification strategy instance
Obtains an MSM from the verifier strategy and yields back the strategy’s +output. Read more
Finalizes the batch and checks its validity. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/strategy/struct.GuardKZG.html b/docs/halo2_proofs/poly/kzg/strategy/struct.GuardKZG.html new file mode 100644 index 0000000000..6628d33096 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/strategy/struct.GuardKZG.html @@ -0,0 +1,27 @@ +GuardKZG in halo2_proofs::poly::kzg::strategy - Rust
pub struct GuardKZG<'params, E: MultiMillerLoop + Debug> { /* private fields */ }
Expand description

Wrapper for linear verification accumulator

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Define accumulator type as DualMSM

+
Multi scalar engine which is not evaluated yet.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/kzg/strategy/struct.SingleStrategy.html b/docs/halo2_proofs/poly/kzg/strategy/struct.SingleStrategy.html new file mode 100644 index 0000000000..d76776c773 --- /dev/null +++ b/docs/halo2_proofs/poly/kzg/strategy/struct.SingleStrategy.html @@ -0,0 +1,28 @@ +SingleStrategy in halo2_proofs::poly::kzg::strategy - Rust
pub struct SingleStrategy<'params, E: Engine> { /* private fields */ }
Expand description

A verifier that checks a single proof

+

Implementations

Constructs an empty batch verifier

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
The output type of this verification strategy after processing a proof.
Creates new verification strategy instance
Obtains an MSM from the verifier strategy and yields back the strategy’s +output. Read more
Finalizes the batch and checks its validity. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/query/struct.ProverQuery.html b/docs/halo2_proofs/poly/query/struct.ProverQuery.html new file mode 100644 index 0000000000..545fb0ba78 --- /dev/null +++ b/docs/halo2_proofs/poly/query/struct.ProverQuery.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/poly/struct.ProverQuery.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/poly/query/struct.VerifierQuery.html b/docs/halo2_proofs/poly/query/struct.VerifierQuery.html new file mode 100644 index 0000000000..31f3db7c3e --- /dev/null +++ b/docs/halo2_proofs/poly/query/struct.VerifierQuery.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/poly/struct.VerifierQuery.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/poly/sidebar-items.js b/docs/halo2_proofs/poly/sidebar-items.js new file mode 100644 index 0000000000..b816c6a66e --- /dev/null +++ b/docs/halo2_proofs/poly/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":[["Error","This is an error that could occur during proving or circuit synthesis."]],"mod":[["commitment","Generic commitment scheme structures"],["ipa","Inner product argument commitment scheme"],["kzg","KZG commitment scheme"]],"struct":[["Coeff","The polynomial is defined as coefficients"],["EvaluationDomain","This structure contains precomputed constants and other details needed for performing operations on an evaluation domain of size $2^k$ and an extended domain of size $2^{k} * j$ with $j \\neq 0$."],["ExtendedLagrangeCoeff","The polynomial is defined as coefficients of Lagrange basis polynomials in an extended size domain which supports multiplication"],["LagrangeCoeff","The polynomial is defined as coefficients of Lagrange basis polynomials"],["PinnedEvaluationDomain","Represents the minimal parameters that determine an `EvaluationDomain`."],["Polynomial","Represents a univariate polynomial defined over a field and a particular basis."],["ProverQuery","A polynomial query at a point"],["Rotation","Describes the relative rotation of a vector. Negative numbers represent reverse (leftmost) rotations and positive numbers represent forward (rightmost) rotations. Zero represents no rotation."],["VerifierQuery","A polynomial query at a point"]],"trait":[["Basis","The basis over which a polynomial is described."],["Guard","Guards is unfinished verification result. Implement this to construct various verification strategies such as aggregation and recursion."],["VerificationStrategy","Trait representing a strategy for verifying Halo 2 proofs."]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/poly/strategy/trait.Guard.html b/docs/halo2_proofs/poly/strategy/trait.Guard.html new file mode 100644 index 0000000000..420ec6cf7b --- /dev/null +++ b/docs/halo2_proofs/poly/strategy/trait.Guard.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/poly/trait.Guard.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/poly/strategy/trait.VerificationStrategy.html b/docs/halo2_proofs/poly/strategy/trait.VerificationStrategy.html new file mode 100644 index 0000000000..5d6199c965 --- /dev/null +++ b/docs/halo2_proofs/poly/strategy/trait.VerificationStrategy.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2_proofs/poly/trait.VerificationStrategy.html...

+ + + \ No newline at end of file diff --git a/docs/halo2_proofs/poly/struct.Coeff.html b/docs/halo2_proofs/poly/struct.Coeff.html new file mode 100644 index 0000000000..33ecfff444 --- /dev/null +++ b/docs/halo2_proofs/poly/struct.Coeff.html @@ -0,0 +1,26 @@ +Coeff in halo2_proofs::poly - Rust
pub struct Coeff;
Expand description

The polynomial is defined as coefficients

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/struct.EvaluationDomain.html b/docs/halo2_proofs/poly/struct.EvaluationDomain.html new file mode 100644 index 0000000000..6153cbc40a --- /dev/null +++ b/docs/halo2_proofs/poly/struct.EvaluationDomain.html @@ -0,0 +1,91 @@ +EvaluationDomain in halo2_proofs::poly - Rust
pub struct EvaluationDomain<G: Group> { /* private fields */ }
Expand description

This structure contains precomputed constants and other details needed for +performing operations on an evaluation domain of size $2^k$ and an extended +domain of size $2^{k} * j$ with $j \neq 0$.

+

Implementations

This constructs a new evaluation domain object based on the provided +values $j, k$.

+

Obtains a polynomial in Lagrange form when given a vector of Lagrange +coefficients of size n; panics if the provided vector is the wrong +length.

+

Obtains a polynomial in coefficient form when given a vector of +coefficients of size n; panics if the provided vector is the wrong +length.

+

Returns an empty (zero) polynomial in the coefficient basis

+

Returns an empty (zero) polynomial in the Lagrange coefficient basis

+

Returns a constant polynomial in the Lagrange coefficient basis

+

Returns an empty (zero) polynomial in the extended Lagrange coefficient +basis

+

Returns a constant polynomial in the extended Lagrange coefficient +basis

+

This takes us from an n-length vector into the coefficient form.

+

This function will panic if the provided vector is not the correct +length.

+

This takes us from an n-length coefficient vector into a coset of the extended +evaluation domain, rotating by rotation if desired.

+

Rotate the extended domain polynomial over the original domain.

+

This takes us from the extended evaluation domain and gets us the +quotient polynomial coefficients.

+

This function will panic if the provided vector is not the correct +length.

+

This divides the polynomial (in the extended domain) by the vanishing +polynomial of the $2^k$ size domain.

+

Get the size of the domain

+

Get the size of the extended domain

+

Get the size of the extended domain

+

Get $\omega$, the generator of the $2^k$ order multiplicative subgroup.

+

Get $\omega^{-1}$, the inverse of the generator of the $2^k$ order +multiplicative subgroup.

+

Get the generator of the extended domain’s multiplicative subgroup.

+

Multiplies a value by some power of $\omega$, essentially rotating over +the domain.

+

Computes evaluations (at the point x, where xn = x^n) of Lagrange +basis polynomials l_i(X) defined such that l_i(omega^i) = 1 and +l_i(omega^j) = 0 for all j != i at each provided rotation i.

+
Implementation
+

The polynomial +$$\prod_{j=0,j \neq i}^{n - 1} (X - \omega^j)$$ +has a root at all points in the domain except $\omega^i$, where it evaluates to +$$\prod_{j=0,j \neq i}^{n - 1} (\omega^i - \omega^j)$$ +and so we divide that polynomial by this value to obtain $l_i(X)$. Since +$$\prod_{j=0,j \neq i}^{n - 1} (X - \omega^j) += \frac{X^n - 1}{X - \omega^i}$$ +then $l_i(x)$ for some $x$ is evaluated as +$$\left(\frac{x^n - 1}{x - \omega^i}\right) +\cdot \left(\frac{1}{\prod_{j=0,j \neq i}^{n - 1} (\omega^i - \omega^j)}\right).$$ +We refer to +$$1 \over \prod_{j=0,j \neq i}^{n - 1} (\omega^i - \omega^j)$$ +as the barycentric weight of $\omega^i$.

+

We know that for $i = 0$ +$$\frac{1}{\prod_{j=0,j \neq i}^{n - 1} (\omega^i - \omega^j)} = \frac{1}{n}.$$

+

If we multiply $(1 / n)$ by $\omega^i$ then we obtain +$$\frac{1}{\prod_{j=0,j \neq 0}^{n - 1} (\omega^i - \omega^j)} += \frac{1}{\prod_{j=0,j \neq i}^{n - 1} (\omega^i - \omega^j)}$$ +which is the barycentric weight of $\omega^i$.

+

Gets the quotient polynomial’s degree (as a multiple of n)

+

Obtain a pinned version of this evaluation domain; a structure with the +minimal parameters needed to determine the rest of the evaluation +domain.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/struct.ExtendedLagrangeCoeff.html b/docs/halo2_proofs/poly/struct.ExtendedLagrangeCoeff.html new file mode 100644 index 0000000000..2cfec84fda --- /dev/null +++ b/docs/halo2_proofs/poly/struct.ExtendedLagrangeCoeff.html @@ -0,0 +1,27 @@ +ExtendedLagrangeCoeff in halo2_proofs::poly - Rust
pub struct ExtendedLagrangeCoeff;
Expand description

The polynomial is defined as coefficients of Lagrange basis polynomials in +an extended size domain which supports multiplication

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/struct.LagrangeCoeff.html b/docs/halo2_proofs/poly/struct.LagrangeCoeff.html new file mode 100644 index 0000000000..66210bd6ea --- /dev/null +++ b/docs/halo2_proofs/poly/struct.LagrangeCoeff.html @@ -0,0 +1,26 @@ +LagrangeCoeff in halo2_proofs::poly - Rust
pub struct LagrangeCoeff;
Expand description

The polynomial is defined as coefficients of Lagrange basis polynomials

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/struct.PinnedEvaluationDomain.html b/docs/halo2_proofs/poly/struct.PinnedEvaluationDomain.html new file mode 100644 index 0000000000..95bd9948e6 --- /dev/null +++ b/docs/halo2_proofs/poly/struct.PinnedEvaluationDomain.html @@ -0,0 +1,26 @@ +PinnedEvaluationDomain in halo2_proofs::poly - Rust
pub struct PinnedEvaluationDomain<'a, G: Group> { /* private fields */ }
Expand description

Represents the minimal parameters that determine an EvaluationDomain.

+

Trait Implementations

Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/struct.Polynomial.html b/docs/halo2_proofs/poly/struct.Polynomial.html new file mode 100644 index 0000000000..e7a08b4f63 --- /dev/null +++ b/docs/halo2_proofs/poly/struct.Polynomial.html @@ -0,0 +1,2089 @@ +Polynomial in halo2_proofs::poly - Rust
pub struct Polynomial<F, B> { /* private fields */ }
Expand description

Represents a univariate polynomial defined over a field and a particular +basis.

+

Implementations

Iterate over the values, which are either in coefficient or evaluation +form depending on the basis B.

+

Iterate over the values mutably, which are either in coefficient or +evaluation form depending on the basis B.

+

Gets the size of this polynomial in terms of the number of +coefficients used to describe it.

+

Rotates the values in a Lagrange basis polynomial by Rotation

+

Methods from Deref<Target = [F]>

🔬This is a nightly-only experimental API. (slice_flatten)

Takes a &[[T; N]], and flattens it to a &[T].

+
Panics
+

This panics if the length of the resulting slice would overflow a usize.

+

This is only possible when flattening a slice of arrays of zero-sized +types, and thus tends to be irrelevant in practice. If +size_of::<T>() > 0, this will never panic.

+
Examples
+
#![feature(slice_flatten)]
+
+assert_eq!([[1, 2, 3], [4, 5, 6]].flatten(), &[1, 2, 3, 4, 5, 6]);
+
+assert_eq!(
+    [[1, 2, 3], [4, 5, 6]].flatten(),
+    [[1, 2], [3, 4], [5, 6]].flatten(),
+);
+
+let slice_of_empty_arrays: &[[i32; 0]] = &[[], [], [], [], []];
+assert!(slice_of_empty_arrays.flatten().is_empty());
+
+let empty_slice_of_arrays: &[[u32; 10]] = &[];
+assert!(empty_slice_of_arrays.flatten().is_empty());
+
🔬This is a nightly-only experimental API. (slice_flatten)

Takes a &mut [[T; N]], and flattens it to a &mut [T].

+
Panics
+

This panics if the length of the resulting slice would overflow a usize.

+

This is only possible when flattening a slice of arrays of zero-sized +types, and thus tends to be irrelevant in practice. If +size_of::<T>() > 0, this will never panic.

+
Examples
+
#![feature(slice_flatten)]
+
+fn add_5_to_all(slice: &mut [i32]) {
+    for i in slice {
+        *i += 5;
+    }
+}
+
+let mut array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
+add_5_to_all(array.flatten_mut());
+assert_eq!(array, [[6, 7, 8], [9, 10, 11], [12, 13, 14]]);
+
🔬This is a nightly-only experimental API. (sort_floats)

Sorts the slice of floats.

+

This sort is in-place (i.e. does not allocate), O(n * log(n)) worst-case, and uses +the ordering defined by f32::total_cmp.

+
Current implementation
+

This uses the same sorting algorithm as sort_unstable_by.

+
Examples
+
#![feature(sort_floats)]
+let mut v = [2.6, -5e-8, f32::NAN, 8.29, f32::INFINITY, -1.0, 0.0, -f32::INFINITY, -0.0];
+
+v.sort_floats();
+let sorted = [-f32::INFINITY, -1.0, -5e-8, -0.0, 0.0, 2.6, 8.29, f32::INFINITY, f32::NAN];
+assert_eq!(&v[..8], &sorted[..8]);
+assert!(v[8].is_nan());
+

Checks if all bytes in this slice are within the ASCII range.

+

Checks that two slices are an ASCII case-insensitive match.

+

Same as to_ascii_lowercase(a) == to_ascii_lowercase(b), +but without allocating and copying temporaries.

+

Converts this slice to its ASCII upper case equivalent in-place.

+

ASCII letters ‘a’ to ‘z’ are mapped to ‘A’ to ‘Z’, +but non-ASCII letters are unchanged.

+

To return a new uppercased value without modifying the existing one, use +to_ascii_uppercase.

+

Converts this slice to its ASCII lower case equivalent in-place.

+

ASCII letters ‘A’ to ‘Z’ are mapped to ‘a’ to ‘z’, +but non-ASCII letters are unchanged.

+

To return a new lowercased value without modifying the existing one, use +to_ascii_lowercase.

+

Returns an iterator that produces an escaped version of this slice, +treating it as an ASCII string.

+
Examples
+

+let s = b"0\t\r\n'\"\\\x9d";
+let escaped = s.escape_ascii().to_string();
+assert_eq!(escaped, "0\\t\\r\\n\\'\\\"\\\\\\x9d");
+
🔬This is a nightly-only experimental API. (byte_slice_trim_ascii)

Returns a byte slice with leading ASCII whitespace bytes removed.

+

‘Whitespace’ refers to the definition used by +u8::is_ascii_whitespace.

+
Examples
+
#![feature(byte_slice_trim_ascii)]
+
+assert_eq!(b" \t hello world\n".trim_ascii_start(), b"hello world\n");
+assert_eq!(b"  ".trim_ascii_start(), b"");
+assert_eq!(b"".trim_ascii_start(), b"");
+
🔬This is a nightly-only experimental API. (byte_slice_trim_ascii)

Returns a byte slice with trailing ASCII whitespace bytes removed.

+

‘Whitespace’ refers to the definition used by +u8::is_ascii_whitespace.

+
Examples
+
#![feature(byte_slice_trim_ascii)]
+
+assert_eq!(b"\r hello world\n ".trim_ascii_end(), b"\r hello world");
+assert_eq!(b"  ".trim_ascii_end(), b"");
+assert_eq!(b"".trim_ascii_end(), b"");
+
🔬This is a nightly-only experimental API. (byte_slice_trim_ascii)

Returns a byte slice with leading and trailing ASCII whitespace bytes +removed.

+

‘Whitespace’ refers to the definition used by +u8::is_ascii_whitespace.

+
Examples
+
#![feature(byte_slice_trim_ascii)]
+
+assert_eq!(b"\r hello world\n ".trim_ascii(), b"hello world");
+assert_eq!(b"  ".trim_ascii(), b"");
+assert_eq!(b"".trim_ascii(), b"");
+
🔬This is a nightly-only experimental API. (sort_floats)

Sorts the slice of floats.

+

This sort is in-place (i.e. does not allocate), O(n * log(n)) worst-case, and uses +the ordering defined by f64::total_cmp.

+
Current implementation
+

This uses the same sorting algorithm as sort_unstable_by.

+
Examples
+
#![feature(sort_floats)]
+let mut v = [2.6, -5e-8, f64::NAN, 8.29, f64::INFINITY, -1.0, 0.0, -f64::INFINITY, -0.0];
+
+v.sort_floats();
+let sorted = [-f64::INFINITY, -1.0, -5e-8, -0.0, 0.0, 2.6, 8.29, f64::INFINITY, f64::NAN];
+assert_eq!(&v[..8], &sorted[..8]);
+assert!(v[8].is_nan());
+

Returns the number of elements in the slice.

+
Examples
+
let a = [1, 2, 3];
+assert_eq!(a.len(), 3);
+

Returns true if the slice has a length of 0.

+
Examples
+
let a = [1, 2, 3];
+assert!(!a.is_empty());
+

Returns the first element of the slice, or None if it is empty.

+
Examples
+
let v = [10, 40, 30];
+assert_eq!(Some(&10), v.first());
+
+let w: &[i32] = &[];
+assert_eq!(None, w.first());
+

Returns a mutable pointer to the first element of the slice, or None if it is empty.

+
Examples
+
let x = &mut [0, 1, 2];
+
+if let Some(first) = x.first_mut() {
+    *first = 5;
+}
+assert_eq!(x, &[5, 1, 2]);
+

Returns the first and all the rest of the elements of the slice, or None if it is empty.

+
Examples
+
let x = &[0, 1, 2];
+
+if let Some((first, elements)) = x.split_first() {
+    assert_eq!(first, &0);
+    assert_eq!(elements, &[1, 2]);
+}
+

Returns the first and all the rest of the elements of the slice, or None if it is empty.

+
Examples
+
let x = &mut [0, 1, 2];
+
+if let Some((first, elements)) = x.split_first_mut() {
+    *first = 3;
+    elements[0] = 4;
+    elements[1] = 5;
+}
+assert_eq!(x, &[3, 4, 5]);
+

Returns the last and all the rest of the elements of the slice, or None if it is empty.

+
Examples
+
let x = &[0, 1, 2];
+
+if let Some((last, elements)) = x.split_last() {
+    assert_eq!(last, &2);
+    assert_eq!(elements, &[0, 1]);
+}
+

Returns the last and all the rest of the elements of the slice, or None if it is empty.

+
Examples
+
let x = &mut [0, 1, 2];
+
+if let Some((last, elements)) = x.split_last_mut() {
+    *last = 3;
+    elements[0] = 4;
+    elements[1] = 5;
+}
+assert_eq!(x, &[4, 5, 3]);
+

Returns the last element of the slice, or None if it is empty.

+
Examples
+
let v = [10, 40, 30];
+assert_eq!(Some(&30), v.last());
+
+let w: &[i32] = &[];
+assert_eq!(None, w.last());
+

Returns a mutable pointer to the last item in the slice.

+
Examples
+
let x = &mut [0, 1, 2];
+
+if let Some(last) = x.last_mut() {
+    *last = 10;
+}
+assert_eq!(x, &[0, 1, 10]);
+

Returns a reference to an element or subslice depending on the type of +index.

+
    +
  • If given a position, returns a reference to the element at that +position or None if out of bounds.
  • +
  • If given a range, returns the subslice corresponding to that range, +or None if out of bounds.
  • +
+
Examples
+
let v = [10, 40, 30];
+assert_eq!(Some(&40), v.get(1));
+assert_eq!(Some(&[10, 40][..]), v.get(0..2));
+assert_eq!(None, v.get(3));
+assert_eq!(None, v.get(0..4));
+

Returns a mutable reference to an element or subslice depending on the +type of index (see get) or None if the index is out of bounds.

+
Examples
+
let x = &mut [0, 1, 2];
+
+if let Some(elem) = x.get_mut(1) {
+    *elem = 42;
+}
+assert_eq!(x, &[0, 42, 2]);
+

Returns a reference to an element or subslice, without doing bounds +checking.

+

For a safe alternative see get.

+
Safety
+

Calling this method with an out-of-bounds index is undefined behavior +even if the resulting reference is not used.

+
Examples
+
let x = &[1, 2, 4];
+
+unsafe {
+    assert_eq!(x.get_unchecked(1), &2);
+}
+

Returns a mutable reference to an element or subslice, without doing +bounds checking.

+

For a safe alternative see get_mut.

+
Safety
+

Calling this method with an out-of-bounds index is undefined behavior +even if the resulting reference is not used.

+
Examples
+
let x = &mut [1, 2, 4];
+
+unsafe {
+    let elem = x.get_unchecked_mut(1);
+    *elem = 13;
+}
+assert_eq!(x, &[1, 13, 4]);
+

Returns a raw pointer to the slice’s buffer.

+

The caller must ensure that the slice outlives the pointer this +function returns, or else it will end up pointing to garbage.

+

The caller must also ensure that the memory the pointer (non-transitively) points to +is never written to (except inside an UnsafeCell) using this pointer or any pointer +derived from it. If you need to mutate the contents of the slice, use as_mut_ptr.

+

Modifying the container referenced by this slice may cause its buffer +to be reallocated, which would also make any pointers to it invalid.

+
Examples
+
let x = &[1, 2, 4];
+let x_ptr = x.as_ptr();
+
+unsafe {
+    for i in 0..x.len() {
+        assert_eq!(x.get_unchecked(i), &*x_ptr.add(i));
+    }
+}
+

Returns an unsafe mutable pointer to the slice’s buffer.

+

The caller must ensure that the slice outlives the pointer this +function returns, or else it will end up pointing to garbage.

+

Modifying the container referenced by this slice may cause its buffer +to be reallocated, which would also make any pointers to it invalid.

+
Examples
+
let x = &mut [1, 2, 4];
+let x_ptr = x.as_mut_ptr();
+
+unsafe {
+    for i in 0..x.len() {
+        *x_ptr.add(i) += 2;
+    }
+}
+assert_eq!(x, &[3, 4, 6]);
+

Returns the two raw pointers spanning the slice.

+

The returned range is half-open, which means that the end pointer +points one past the last element of the slice. This way, an empty +slice is represented by two equal pointers, and the difference between +the two pointers represents the size of the slice.

+

See as_ptr for warnings on using these pointers. The end pointer +requires extra caution, as it does not point to a valid element in the +slice.

+

This function is useful for interacting with foreign interfaces which +use two pointers to refer to a range of elements in memory, as is +common in C++.

+

It can also be useful to check if a pointer to an element refers to an +element of this slice:

+ +
let a = [1, 2, 3];
+let x = &a[1] as *const _;
+let y = &5 as *const _;
+
+assert!(a.as_ptr_range().contains(&x));
+assert!(!a.as_ptr_range().contains(&y));
+

Returns the two unsafe mutable pointers spanning the slice.

+

The returned range is half-open, which means that the end pointer +points one past the last element of the slice. This way, an empty +slice is represented by two equal pointers, and the difference between +the two pointers represents the size of the slice.

+

See as_mut_ptr for warnings on using these pointers. The end +pointer requires extra caution, as it does not point to a valid element +in the slice.

+

This function is useful for interacting with foreign interfaces which +use two pointers to refer to a range of elements in memory, as is +common in C++.

+

Swaps two elements in the slice.

+
Arguments
+
    +
  • a - The index of the first element
  • +
  • b - The index of the second element
  • +
+
Panics
+

Panics if a or b are out of bounds.

+
Examples
+
let mut v = ["a", "b", "c", "d", "e"];
+v.swap(2, 4);
+assert!(v == ["a", "b", "e", "d", "c"]);
+
🔬This is a nightly-only experimental API. (slice_swap_unchecked)

Swaps two elements in the slice, without doing bounds checking.

+

For a safe alternative see swap.

+
Arguments
+
    +
  • a - The index of the first element
  • +
  • b - The index of the second element
  • +
+
Safety
+

Calling this method with an out-of-bounds index is undefined behavior. +The caller has to ensure that a < self.len() and b < self.len().

+
Examples
+
#![feature(slice_swap_unchecked)]
+
+let mut v = ["a", "b", "c", "d"];
+// SAFETY: we know that 1 and 3 are both indices of the slice
+unsafe { v.swap_unchecked(1, 3) };
+assert!(v == ["a", "d", "c", "b"]);
+

Reverses the order of elements in the slice, in place.

+
Examples
+
let mut v = [1, 2, 3];
+v.reverse();
+assert!(v == [3, 2, 1]);
+

Returns an iterator over the slice.

+

The iterator yields all items from start to end.

+
Examples
+
let x = &[1, 2, 4];
+let mut iterator = x.iter();
+
+assert_eq!(iterator.next(), Some(&1));
+assert_eq!(iterator.next(), Some(&2));
+assert_eq!(iterator.next(), Some(&4));
+assert_eq!(iterator.next(), None);
+

Returns an iterator that allows modifying each value.

+

The iterator yields all items from start to end.

+
Examples
+
let x = &mut [1, 2, 4];
+for elem in x.iter_mut() {
+    *elem += 2;
+}
+assert_eq!(x, &[3, 4, 6]);
+

Returns an iterator over all contiguous windows of length +size. The windows overlap. If the slice is shorter than +size, the iterator returns no values.

+
Panics
+

Panics if size is 0.

+
Examples
+
let slice = ['r', 'u', 's', 't'];
+let mut iter = slice.windows(2);
+assert_eq!(iter.next().unwrap(), &['r', 'u']);
+assert_eq!(iter.next().unwrap(), &['u', 's']);
+assert_eq!(iter.next().unwrap(), &['s', 't']);
+assert!(iter.next().is_none());
+

If the slice is shorter than size:

+ +
let slice = ['f', 'o', 'o'];
+let mut iter = slice.windows(4);
+assert!(iter.next().is_none());
+

Returns an iterator over chunk_size elements of the slice at a time, starting at the +beginning of the slice.

+

The chunks are slices and do not overlap. If chunk_size does not divide the length of the +slice, then the last chunk will not have length chunk_size.

+

See chunks_exact for a variant of this iterator that returns chunks of always exactly +chunk_size elements, and rchunks for the same iterator but starting at the end of the +slice.

+
Panics
+

Panics if chunk_size is 0.

+
Examples
+
let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.chunks(2);
+assert_eq!(iter.next().unwrap(), &['l', 'o']);
+assert_eq!(iter.next().unwrap(), &['r', 'e']);
+assert_eq!(iter.next().unwrap(), &['m']);
+assert!(iter.next().is_none());
+

Returns an iterator over chunk_size elements of the slice at a time, starting at the +beginning of the slice.

+

The chunks are mutable slices, and do not overlap. If chunk_size does not divide the +length of the slice, then the last chunk will not have length chunk_size.

+

See chunks_exact_mut for a variant of this iterator that returns chunks of always +exactly chunk_size elements, and rchunks_mut for the same iterator but starting at +the end of the slice.

+
Panics
+

Panics if chunk_size is 0.

+
Examples
+
let v = &mut [0, 0, 0, 0, 0];
+let mut count = 1;
+
+for chunk in v.chunks_mut(2) {
+    for elem in chunk.iter_mut() {
+        *elem += count;
+    }
+    count += 1;
+}
+assert_eq!(v, &[1, 1, 2, 2, 3]);
+

Returns an iterator over chunk_size elements of the slice at a time, starting at the +beginning of the slice.

+

The chunks are slices and do not overlap. If chunk_size does not divide the length of the +slice, then the last up to chunk_size-1 elements will be omitted and can be retrieved +from the remainder function of the iterator.

+

Due to each chunk having exactly chunk_size elements, the compiler can often optimize the +resulting code better than in the case of chunks.

+

See chunks for a variant of this iterator that also returns the remainder as a smaller +chunk, and rchunks_exact for the same iterator but starting at the end of the slice.

+
Panics
+

Panics if chunk_size is 0.

+
Examples
+
let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.chunks_exact(2);
+assert_eq!(iter.next().unwrap(), &['l', 'o']);
+assert_eq!(iter.next().unwrap(), &['r', 'e']);
+assert!(iter.next().is_none());
+assert_eq!(iter.remainder(), &['m']);
+

Returns an iterator over chunk_size elements of the slice at a time, starting at the +beginning of the slice.

+

The chunks are mutable slices, and do not overlap. If chunk_size does not divide the +length of the slice, then the last up to chunk_size-1 elements will be omitted and can be +retrieved from the into_remainder function of the iterator.

+

Due to each chunk having exactly chunk_size elements, the compiler can often optimize the +resulting code better than in the case of chunks_mut.

+

See chunks_mut for a variant of this iterator that also returns the remainder as a +smaller chunk, and rchunks_exact_mut for the same iterator but starting at the end of +the slice.

+
Panics
+

Panics if chunk_size is 0.

+
Examples
+
let v = &mut [0, 0, 0, 0, 0];
+let mut count = 1;
+
+for chunk in v.chunks_exact_mut(2) {
+    for elem in chunk.iter_mut() {
+        *elem += count;
+    }
+    count += 1;
+}
+assert_eq!(v, &[1, 1, 2, 2, 0]);
+
🔬This is a nightly-only experimental API. (slice_as_chunks)

Splits the slice into a slice of N-element arrays, +assuming that there’s no remainder.

+
Safety
+

This may only be called when

+
    +
  • The slice splits exactly into N-element chunks (aka self.len() % N == 0).
  • +
  • N != 0.
  • +
+
Examples
+
#![feature(slice_as_chunks)]
+let slice: &[char] = &['l', 'o', 'r', 'e', 'm', '!'];
+let chunks: &[[char; 1]] =
+    // SAFETY: 1-element chunks never have remainder
+    unsafe { slice.as_chunks_unchecked() };
+assert_eq!(chunks, &[['l'], ['o'], ['r'], ['e'], ['m'], ['!']]);
+let chunks: &[[char; 3]] =
+    // SAFETY: The slice length (6) is a multiple of 3
+    unsafe { slice.as_chunks_unchecked() };
+assert_eq!(chunks, &[['l', 'o', 'r'], ['e', 'm', '!']]);
+
+// These would be unsound:
+// let chunks: &[[_; 5]] = slice.as_chunks_unchecked() // The slice length is not a multiple of 5
+// let chunks: &[[_; 0]] = slice.as_chunks_unchecked() // Zero-length chunks are never allowed
+
🔬This is a nightly-only experimental API. (slice_as_chunks)

Splits the slice into a slice of N-element arrays, +starting at the beginning of the slice, +and a remainder slice with length strictly less than N.

+
Panics
+

Panics if N is 0. This check will most probably get changed to a compile time +error before this method gets stabilized.

+
Examples
+
#![feature(slice_as_chunks)]
+let slice = ['l', 'o', 'r', 'e', 'm'];
+let (chunks, remainder) = slice.as_chunks();
+assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]);
+assert_eq!(remainder, &['m']);
+
🔬This is a nightly-only experimental API. (slice_as_chunks)

Splits the slice into a slice of N-element arrays, +starting at the end of the slice, +and a remainder slice with length strictly less than N.

+
Panics
+

Panics if N is 0. This check will most probably get changed to a compile time +error before this method gets stabilized.

+
Examples
+
#![feature(slice_as_chunks)]
+let slice = ['l', 'o', 'r', 'e', 'm'];
+let (remainder, chunks) = slice.as_rchunks();
+assert_eq!(remainder, &['l']);
+assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]);
+
🔬This is a nightly-only experimental API. (array_chunks)

Returns an iterator over N elements of the slice at a time, starting at the +beginning of the slice.

+

The chunks are array references and do not overlap. If N does not divide the +length of the slice, then the last up to N-1 elements will be omitted and can be +retrieved from the remainder function of the iterator.

+

This method is the const generic equivalent of chunks_exact.

+
Panics
+

Panics if N is 0. This check will most probably get changed to a compile time +error before this method gets stabilized.

+
Examples
+
#![feature(array_chunks)]
+let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.array_chunks();
+assert_eq!(iter.next().unwrap(), &['l', 'o']);
+assert_eq!(iter.next().unwrap(), &['r', 'e']);
+assert!(iter.next().is_none());
+assert_eq!(iter.remainder(), &['m']);
+
🔬This is a nightly-only experimental API. (slice_as_chunks)

Splits the slice into a slice of N-element arrays, +assuming that there’s no remainder.

+
Safety
+

This may only be called when

+
    +
  • The slice splits exactly into N-element chunks (aka self.len() % N == 0).
  • +
  • N != 0.
  • +
+
Examples
+
#![feature(slice_as_chunks)]
+let slice: &mut [char] = &mut ['l', 'o', 'r', 'e', 'm', '!'];
+let chunks: &mut [[char; 1]] =
+    // SAFETY: 1-element chunks never have remainder
+    unsafe { slice.as_chunks_unchecked_mut() };
+chunks[0] = ['L'];
+assert_eq!(chunks, &[['L'], ['o'], ['r'], ['e'], ['m'], ['!']]);
+let chunks: &mut [[char; 3]] =
+    // SAFETY: The slice length (6) is a multiple of 3
+    unsafe { slice.as_chunks_unchecked_mut() };
+chunks[1] = ['a', 'x', '?'];
+assert_eq!(slice, &['L', 'o', 'r', 'a', 'x', '?']);
+
+// These would be unsound:
+// let chunks: &[[_; 5]] = slice.as_chunks_unchecked_mut() // The slice length is not a multiple of 5
+// let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut() // Zero-length chunks are never allowed
+
🔬This is a nightly-only experimental API. (slice_as_chunks)

Splits the slice into a slice of N-element arrays, +starting at the beginning of the slice, +and a remainder slice with length strictly less than N.

+
Panics
+

Panics if N is 0. This check will most probably get changed to a compile time +error before this method gets stabilized.

+
Examples
+
#![feature(slice_as_chunks)]
+let v = &mut [0, 0, 0, 0, 0];
+let mut count = 1;
+
+let (chunks, remainder) = v.as_chunks_mut();
+remainder[0] = 9;
+for chunk in chunks {
+    *chunk = [count; 2];
+    count += 1;
+}
+assert_eq!(v, &[1, 1, 2, 2, 9]);
+
🔬This is a nightly-only experimental API. (slice_as_chunks)

Splits the slice into a slice of N-element arrays, +starting at the end of the slice, +and a remainder slice with length strictly less than N.

+
Panics
+

Panics if N is 0. This check will most probably get changed to a compile time +error before this method gets stabilized.

+
Examples
+
#![feature(slice_as_chunks)]
+let v = &mut [0, 0, 0, 0, 0];
+let mut count = 1;
+
+let (remainder, chunks) = v.as_rchunks_mut();
+remainder[0] = 9;
+for chunk in chunks {
+    *chunk = [count; 2];
+    count += 1;
+}
+assert_eq!(v, &[9, 1, 1, 2, 2]);
+
🔬This is a nightly-only experimental API. (array_chunks)

Returns an iterator over N elements of the slice at a time, starting at the +beginning of the slice.

+

The chunks are mutable array references and do not overlap. If N does not divide +the length of the slice, then the last up to N-1 elements will be omitted and +can be retrieved from the into_remainder function of the iterator.

+

This method is the const generic equivalent of chunks_exact_mut.

+
Panics
+

Panics if N is 0. This check will most probably get changed to a compile time +error before this method gets stabilized.

+
Examples
+
#![feature(array_chunks)]
+let v = &mut [0, 0, 0, 0, 0];
+let mut count = 1;
+
+for chunk in v.array_chunks_mut() {
+    *chunk = [count; 2];
+    count += 1;
+}
+assert_eq!(v, &[1, 1, 2, 2, 0]);
+
🔬This is a nightly-only experimental API. (array_windows)

Returns an iterator over overlapping windows of N elements of a slice, +starting at the beginning of the slice.

+

This is the const generic equivalent of windows.

+

If N is greater than the size of the slice, it will return no windows.

+
Panics
+

Panics if N is 0. This check will most probably get changed to a compile time +error before this method gets stabilized.

+
Examples
+
#![feature(array_windows)]
+let slice = [0, 1, 2, 3];
+let mut iter = slice.array_windows();
+assert_eq!(iter.next().unwrap(), &[0, 1]);
+assert_eq!(iter.next().unwrap(), &[1, 2]);
+assert_eq!(iter.next().unwrap(), &[2, 3]);
+assert!(iter.next().is_none());
+

Returns an iterator over chunk_size elements of the slice at a time, starting at the end +of the slice.

+

The chunks are slices and do not overlap. If chunk_size does not divide the length of the +slice, then the last chunk will not have length chunk_size.

+

See rchunks_exact for a variant of this iterator that returns chunks of always exactly +chunk_size elements, and chunks for the same iterator but starting at the beginning +of the slice.

+
Panics
+

Panics if chunk_size is 0.

+
Examples
+
let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.rchunks(2);
+assert_eq!(iter.next().unwrap(), &['e', 'm']);
+assert_eq!(iter.next().unwrap(), &['o', 'r']);
+assert_eq!(iter.next().unwrap(), &['l']);
+assert!(iter.next().is_none());
+

Returns an iterator over chunk_size elements of the slice at a time, starting at the end +of the slice.

+

The chunks are mutable slices, and do not overlap. If chunk_size does not divide the +length of the slice, then the last chunk will not have length chunk_size.

+

See rchunks_exact_mut for a variant of this iterator that returns chunks of always +exactly chunk_size elements, and chunks_mut for the same iterator but starting at the +beginning of the slice.

+
Panics
+

Panics if chunk_size is 0.

+
Examples
+
let v = &mut [0, 0, 0, 0, 0];
+let mut count = 1;
+
+for chunk in v.rchunks_mut(2) {
+    for elem in chunk.iter_mut() {
+        *elem += count;
+    }
+    count += 1;
+}
+assert_eq!(v, &[3, 2, 2, 1, 1]);
+

Returns an iterator over chunk_size elements of the slice at a time, starting at the +end of the slice.

+

The chunks are slices and do not overlap. If chunk_size does not divide the length of the +slice, then the last up to chunk_size-1 elements will be omitted and can be retrieved +from the remainder function of the iterator.

+

Due to each chunk having exactly chunk_size elements, the compiler can often optimize the +resulting code better than in the case of rchunks.

+

See rchunks for a variant of this iterator that also returns the remainder as a smaller +chunk, and chunks_exact for the same iterator but starting at the beginning of the +slice.

+
Panics
+

Panics if chunk_size is 0.

+
Examples
+
let slice = ['l', 'o', 'r', 'e', 'm'];
+let mut iter = slice.rchunks_exact(2);
+assert_eq!(iter.next().unwrap(), &['e', 'm']);
+assert_eq!(iter.next().unwrap(), &['o', 'r']);
+assert!(iter.next().is_none());
+assert_eq!(iter.remainder(), &['l']);
+

Returns an iterator over chunk_size elements of the slice at a time, starting at the end +of the slice.

+

The chunks are mutable slices, and do not overlap. If chunk_size does not divide the +length of the slice, then the last up to chunk_size-1 elements will be omitted and can be +retrieved from the into_remainder function of the iterator.

+

Due to each chunk having exactly chunk_size elements, the compiler can often optimize the +resulting code better than in the case of chunks_mut.

+

See rchunks_mut for a variant of this iterator that also returns the remainder as a +smaller chunk, and chunks_exact_mut for the same iterator but starting at the beginning +of the slice.

+
Panics
+

Panics if chunk_size is 0.

+
Examples
+
let v = &mut [0, 0, 0, 0, 0];
+let mut count = 1;
+
+for chunk in v.rchunks_exact_mut(2) {
+    for elem in chunk.iter_mut() {
+        *elem += count;
+    }
+    count += 1;
+}
+assert_eq!(v, &[0, 2, 2, 1, 1]);
+
🔬This is a nightly-only experimental API. (slice_group_by)

Returns an iterator over the slice producing non-overlapping runs +of elements using the predicate to separate them.

+

The predicate is called on two elements following themselves, +it means the predicate is called on slice[0] and slice[1] +then on slice[1] and slice[2] and so on.

+
Examples
+
#![feature(slice_group_by)]
+
+let slice = &[1, 1, 1, 3, 3, 2, 2, 2];
+
+let mut iter = slice.group_by(|a, b| a == b);
+
+assert_eq!(iter.next(), Some(&[1, 1, 1][..]));
+assert_eq!(iter.next(), Some(&[3, 3][..]));
+assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
+assert_eq!(iter.next(), None);
+

This method can be used to extract the sorted subslices:

+ +
#![feature(slice_group_by)]
+
+let slice = &[1, 1, 2, 3, 2, 3, 2, 3, 4];
+
+let mut iter = slice.group_by(|a, b| a <= b);
+
+assert_eq!(iter.next(), Some(&[1, 1, 2, 3][..]));
+assert_eq!(iter.next(), Some(&[2, 3][..]));
+assert_eq!(iter.next(), Some(&[2, 3, 4][..]));
+assert_eq!(iter.next(), None);
+
🔬This is a nightly-only experimental API. (slice_group_by)

Returns an iterator over the slice producing non-overlapping mutable +runs of elements using the predicate to separate them.

+

The predicate is called on two elements following themselves, +it means the predicate is called on slice[0] and slice[1] +then on slice[1] and slice[2] and so on.

+
Examples
+
#![feature(slice_group_by)]
+
+let slice = &mut [1, 1, 1, 3, 3, 2, 2, 2];
+
+let mut iter = slice.group_by_mut(|a, b| a == b);
+
+assert_eq!(iter.next(), Some(&mut [1, 1, 1][..]));
+assert_eq!(iter.next(), Some(&mut [3, 3][..]));
+assert_eq!(iter.next(), Some(&mut [2, 2, 2][..]));
+assert_eq!(iter.next(), None);
+

This method can be used to extract the sorted subslices:

+ +
#![feature(slice_group_by)]
+
+let slice = &mut [1, 1, 2, 3, 2, 3, 2, 3, 4];
+
+let mut iter = slice.group_by_mut(|a, b| a <= b);
+
+assert_eq!(iter.next(), Some(&mut [1, 1, 2, 3][..]));
+assert_eq!(iter.next(), Some(&mut [2, 3][..]));
+assert_eq!(iter.next(), Some(&mut [2, 3, 4][..]));
+assert_eq!(iter.next(), None);
+

Divides one slice into two at an index.

+

The first will contain all indices from [0, mid) (excluding +the index mid itself) and the second will contain all +indices from [mid, len) (excluding the index len itself).

+
Panics
+

Panics if mid > len.

+
Examples
+
let v = [1, 2, 3, 4, 5, 6];
+
+{
+   let (left, right) = v.split_at(0);
+   assert_eq!(left, []);
+   assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+}
+
+{
+    let (left, right) = v.split_at(2);
+    assert_eq!(left, [1, 2]);
+    assert_eq!(right, [3, 4, 5, 6]);
+}
+
+{
+    let (left, right) = v.split_at(6);
+    assert_eq!(left, [1, 2, 3, 4, 5, 6]);
+    assert_eq!(right, []);
+}
+

Divides one mutable slice into two at an index.

+

The first will contain all indices from [0, mid) (excluding +the index mid itself) and the second will contain all +indices from [mid, len) (excluding the index len itself).

+
Panics
+

Panics if mid > len.

+
Examples
+
let mut v = [1, 0, 3, 0, 5, 6];
+let (left, right) = v.split_at_mut(2);
+assert_eq!(left, [1, 0]);
+assert_eq!(right, [3, 0, 5, 6]);
+left[1] = 2;
+right[1] = 4;
+assert_eq!(v, [1, 2, 3, 4, 5, 6]);
+
🔬This is a nightly-only experimental API. (slice_split_at_unchecked)

Divides one slice into two at an index, without doing bounds checking.

+

The first will contain all indices from [0, mid) (excluding +the index mid itself) and the second will contain all +indices from [mid, len) (excluding the index len itself).

+

For a safe alternative see split_at.

+
Safety
+

Calling this method with an out-of-bounds index is undefined behavior +even if the resulting reference is not used. The caller has to ensure that +0 <= mid <= self.len().

+
Examples
+
#![feature(slice_split_at_unchecked)]
+
+let v = [1, 2, 3, 4, 5, 6];
+
+unsafe {
+   let (left, right) = v.split_at_unchecked(0);
+   assert_eq!(left, []);
+   assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+}
+
+unsafe {
+    let (left, right) = v.split_at_unchecked(2);
+    assert_eq!(left, [1, 2]);
+    assert_eq!(right, [3, 4, 5, 6]);
+}
+
+unsafe {
+    let (left, right) = v.split_at_unchecked(6);
+    assert_eq!(left, [1, 2, 3, 4, 5, 6]);
+    assert_eq!(right, []);
+}
+
🔬This is a nightly-only experimental API. (slice_split_at_unchecked)

Divides one mutable slice into two at an index, without doing bounds checking.

+

The first will contain all indices from [0, mid) (excluding +the index mid itself) and the second will contain all +indices from [mid, len) (excluding the index len itself).

+

For a safe alternative see split_at_mut.

+
Safety
+

Calling this method with an out-of-bounds index is undefined behavior +even if the resulting reference is not used. The caller has to ensure that +0 <= mid <= self.len().

+
Examples
+
#![feature(slice_split_at_unchecked)]
+
+let mut v = [1, 0, 3, 0, 5, 6];
+// scoped to restrict the lifetime of the borrows
+unsafe {
+    let (left, right) = v.split_at_mut_unchecked(2);
+    assert_eq!(left, [1, 0]);
+    assert_eq!(right, [3, 0, 5, 6]);
+    left[1] = 2;
+    right[1] = 4;
+}
+assert_eq!(v, [1, 2, 3, 4, 5, 6]);
+
🔬This is a nightly-only experimental API. (split_array)

Divides one slice into an array and a remainder slice at an index.

+

The array will contain all indices from [0, N) (excluding +the index N itself) and the slice will contain all +indices from [N, len) (excluding the index len itself).

+
Panics
+

Panics if N > len.

+
Examples
+
#![feature(split_array)]
+
+let v = &[1, 2, 3, 4, 5, 6][..];
+
+{
+   let (left, right) = v.split_array_ref::<0>();
+   assert_eq!(left, &[]);
+   assert_eq!(right, [1, 2, 3, 4, 5, 6]);
+}
+
+{
+    let (left, right) = v.split_array_ref::<2>();
+    assert_eq!(left, &[1, 2]);
+    assert_eq!(right, [3, 4, 5, 6]);
+}
+
+{
+    let (left, right) = v.split_array_ref::<6>();
+    assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
+    assert_eq!(right, []);
+}
+
🔬This is a nightly-only experimental API. (split_array)

Divides one mutable slice into an array and a remainder slice at an index.

+

The array will contain all indices from [0, N) (excluding +the index N itself) and the slice will contain all +indices from [N, len) (excluding the index len itself).

+
Panics
+

Panics if N > len.

+
Examples
+
#![feature(split_array)]
+
+let mut v = &mut [1, 0, 3, 0, 5, 6][..];
+let (left, right) = v.split_array_mut::<2>();
+assert_eq!(left, &mut [1, 0]);
+assert_eq!(right, [3, 0, 5, 6]);
+left[1] = 2;
+right[1] = 4;
+assert_eq!(v, [1, 2, 3, 4, 5, 6]);
+
🔬This is a nightly-only experimental API. (split_array)

Divides one slice into an array and a remainder slice at an index from +the end.

+

The slice will contain all indices from [0, len - N) (excluding +the index len - N itself) and the array will contain all +indices from [len - N, len) (excluding the index len itself).

+
Panics
+

Panics if N > len.

+
Examples
+
#![feature(split_array)]
+
+let v = &[1, 2, 3, 4, 5, 6][..];
+
+{
+   let (left, right) = v.rsplit_array_ref::<0>();
+   assert_eq!(left, [1, 2, 3, 4, 5, 6]);
+   assert_eq!(right, &[]);
+}
+
+{
+    let (left, right) = v.rsplit_array_ref::<2>();
+    assert_eq!(left, [1, 2, 3, 4]);
+    assert_eq!(right, &[5, 6]);
+}
+
+{
+    let (left, right) = v.rsplit_array_ref::<6>();
+    assert_eq!(left, []);
+    assert_eq!(right, &[1, 2, 3, 4, 5, 6]);
+}
+
🔬This is a nightly-only experimental API. (split_array)

Divides one mutable slice into an array and a remainder slice at an +index from the end.

+

The slice will contain all indices from [0, len - N) (excluding +the index N itself) and the array will contain all +indices from [len - N, len) (excluding the index len itself).

+
Panics
+

Panics if N > len.

+
Examples
+
#![feature(split_array)]
+
+let mut v = &mut [1, 0, 3, 0, 5, 6][..];
+let (left, right) = v.rsplit_array_mut::<4>();
+assert_eq!(left, [1, 0]);
+assert_eq!(right, &mut [3, 0, 5, 6]);
+left[1] = 2;
+right[1] = 4;
+assert_eq!(v, [1, 2, 3, 4, 5, 6]);
+

Returns an iterator over subslices separated by elements that match +pred. The matched element is not contained in the subslices.

+
Examples
+
let slice = [10, 40, 33, 20];
+let mut iter = slice.split(|num| num % 3 == 0);
+
+assert_eq!(iter.next().unwrap(), &[10, 40]);
+assert_eq!(iter.next().unwrap(), &[20]);
+assert!(iter.next().is_none());
+

If the first element is matched, an empty slice will be the first item +returned by the iterator. Similarly, if the last element in the slice +is matched, an empty slice will be the last item returned by the +iterator:

+ +
let slice = [10, 40, 33];
+let mut iter = slice.split(|num| num % 3 == 0);
+
+assert_eq!(iter.next().unwrap(), &[10, 40]);
+assert_eq!(iter.next().unwrap(), &[]);
+assert!(iter.next().is_none());
+

If two matched elements are directly adjacent, an empty slice will be +present between them:

+ +
let slice = [10, 6, 33, 20];
+let mut iter = slice.split(|num| num % 3 == 0);
+
+assert_eq!(iter.next().unwrap(), &[10]);
+assert_eq!(iter.next().unwrap(), &[]);
+assert_eq!(iter.next().unwrap(), &[20]);
+assert!(iter.next().is_none());
+

Returns an iterator over mutable subslices separated by elements that +match pred. The matched element is not contained in the subslices.

+
Examples
+
let mut v = [10, 40, 30, 20, 60, 50];
+
+for group in v.split_mut(|num| *num % 3 == 0) {
+    group[0] = 1;
+}
+assert_eq!(v, [1, 40, 30, 1, 60, 1]);
+

Returns an iterator over subslices separated by elements that match +pred. The matched element is contained in the end of the previous +subslice as a terminator.

+
Examples
+
let slice = [10, 40, 33, 20];
+let mut iter = slice.split_inclusive(|num| num % 3 == 0);
+
+assert_eq!(iter.next().unwrap(), &[10, 40, 33]);
+assert_eq!(iter.next().unwrap(), &[20]);
+assert!(iter.next().is_none());
+

If the last element of the slice is matched, +that element will be considered the terminator of the preceding slice. +That slice will be the last item returned by the iterator.

+ +
let slice = [3, 10, 40, 33];
+let mut iter = slice.split_inclusive(|num| num % 3 == 0);
+
+assert_eq!(iter.next().unwrap(), &[3]);
+assert_eq!(iter.next().unwrap(), &[10, 40, 33]);
+assert!(iter.next().is_none());
+

Returns an iterator over mutable subslices separated by elements that +match pred. The matched element is contained in the previous +subslice as a terminator.

+
Examples
+
let mut v = [10, 40, 30, 20, 60, 50];
+
+for group in v.split_inclusive_mut(|num| *num % 3 == 0) {
+    let terminator_idx = group.len()-1;
+    group[terminator_idx] = 1;
+}
+assert_eq!(v, [10, 40, 1, 20, 1, 1]);
+

Returns an iterator over subslices separated by elements that match +pred, starting at the end of the slice and working backwards. +The matched element is not contained in the subslices.

+
Examples
+
let slice = [11, 22, 33, 0, 44, 55];
+let mut iter = slice.rsplit(|num| *num == 0);
+
+assert_eq!(iter.next().unwrap(), &[44, 55]);
+assert_eq!(iter.next().unwrap(), &[11, 22, 33]);
+assert_eq!(iter.next(), None);
+

As with split(), if the first or last element is matched, an empty +slice will be the first (or last) item returned by the iterator.

+ +
let v = &[0, 1, 1, 2, 3, 5, 8];
+let mut it = v.rsplit(|n| *n % 2 == 0);
+assert_eq!(it.next().unwrap(), &[]);
+assert_eq!(it.next().unwrap(), &[3, 5]);
+assert_eq!(it.next().unwrap(), &[1, 1]);
+assert_eq!(it.next().unwrap(), &[]);
+assert_eq!(it.next(), None);
+

Returns an iterator over mutable subslices separated by elements that +match pred, starting at the end of the slice and working +backwards. The matched element is not contained in the subslices.

+
Examples
+
let mut v = [100, 400, 300, 200, 600, 500];
+
+let mut count = 0;
+for group in v.rsplit_mut(|num| *num % 3 == 0) {
+    count += 1;
+    group[0] = count;
+}
+assert_eq!(v, [3, 400, 300, 2, 600, 1]);
+

Returns an iterator over subslices separated by elements that match +pred, limited to returning at most n items. The matched element is +not contained in the subslices.

+

The last element returned, if any, will contain the remainder of the +slice.

+
Examples
+

Print the slice split once by numbers divisible by 3 (i.e., [10, 40], +[20, 60, 50]):

+ +
let v = [10, 40, 30, 20, 60, 50];
+
+for group in v.splitn(2, |num| *num % 3 == 0) {
+    println!("{group:?}");
+}
+

Returns an iterator over mutable subslices separated by elements that match +pred, limited to returning at most n items. The matched element is +not contained in the subslices.

+

The last element returned, if any, will contain the remainder of the +slice.

+
Examples
+
let mut v = [10, 40, 30, 20, 60, 50];
+
+for group in v.splitn_mut(2, |num| *num % 3 == 0) {
+    group[0] = 1;
+}
+assert_eq!(v, [1, 40, 30, 1, 60, 50]);
+

Returns an iterator over subslices separated by elements that match +pred limited to returning at most n items. This starts at the end of +the slice and works backwards. The matched element is not contained in +the subslices.

+

The last element returned, if any, will contain the remainder of the +slice.

+
Examples
+

Print the slice split once, starting from the end, by numbers divisible +by 3 (i.e., [50], [10, 40, 30, 20]):

+ +
let v = [10, 40, 30, 20, 60, 50];
+
+for group in v.rsplitn(2, |num| *num % 3 == 0) {
+    println!("{group:?}");
+}
+

Returns an iterator over subslices separated by elements that match +pred limited to returning at most n items. This starts at the end of +the slice and works backwards. The matched element is not contained in +the subslices.

+

The last element returned, if any, will contain the remainder of the +slice.

+
Examples
+
let mut s = [10, 40, 30, 20, 60, 50];
+
+for group in s.rsplitn_mut(2, |num| *num % 3 == 0) {
+    group[0] = 1;
+}
+assert_eq!(s, [1, 40, 30, 20, 60, 1]);
+

Returns true if the slice contains an element with the given value.

+

This operation is O(n).

+

Note that if you have a sorted slice, binary_search may be faster.

+
Examples
+
let v = [10, 40, 30];
+assert!(v.contains(&30));
+assert!(!v.contains(&50));
+

If you do not have a &T, but some other value that you can compare +with one (for example, String implements PartialEq<str>), you can +use iter().any:

+ +
let v = [String::from("hello"), String::from("world")]; // slice of `String`
+assert!(v.iter().any(|e| e == "hello")); // search with `&str`
+assert!(!v.iter().any(|e| e == "hi"));
+

Returns true if needle is a prefix of the slice.

+
Examples
+
let v = [10, 40, 30];
+assert!(v.starts_with(&[10]));
+assert!(v.starts_with(&[10, 40]));
+assert!(!v.starts_with(&[50]));
+assert!(!v.starts_with(&[10, 50]));
+

Always returns true if needle is an empty slice:

+ +
let v = &[10, 40, 30];
+assert!(v.starts_with(&[]));
+let v: &[u8] = &[];
+assert!(v.starts_with(&[]));
+

Returns true if needle is a suffix of the slice.

+
Examples
+
let v = [10, 40, 30];
+assert!(v.ends_with(&[30]));
+assert!(v.ends_with(&[40, 30]));
+assert!(!v.ends_with(&[50]));
+assert!(!v.ends_with(&[50, 30]));
+

Always returns true if needle is an empty slice:

+ +
let v = &[10, 40, 30];
+assert!(v.ends_with(&[]));
+let v: &[u8] = &[];
+assert!(v.ends_with(&[]));
+

Returns a subslice with the prefix removed.

+

If the slice starts with prefix, returns the subslice after the prefix, wrapped in Some. +If prefix is empty, simply returns the original slice.

+

If the slice does not start with prefix, returns None.

+
Examples
+
let v = &[10, 40, 30];
+assert_eq!(v.strip_prefix(&[10]), Some(&[40, 30][..]));
+assert_eq!(v.strip_prefix(&[10, 40]), Some(&[30][..]));
+assert_eq!(v.strip_prefix(&[50]), None);
+assert_eq!(v.strip_prefix(&[10, 50]), None);
+
+let prefix : &str = "he";
+assert_eq!(b"hello".strip_prefix(prefix.as_bytes()),
+           Some(b"llo".as_ref()));
+

Returns a subslice with the suffix removed.

+

If the slice ends with suffix, returns the subslice before the suffix, wrapped in Some. +If suffix is empty, simply returns the original slice.

+

If the slice does not end with suffix, returns None.

+
Examples
+
let v = &[10, 40, 30];
+assert_eq!(v.strip_suffix(&[30]), Some(&[10, 40][..]));
+assert_eq!(v.strip_suffix(&[40, 30]), Some(&[10][..]));
+assert_eq!(v.strip_suffix(&[50]), None);
+assert_eq!(v.strip_suffix(&[50, 30]), None);
+

Binary searches this slice for a given element. +This behaves similarly to contains if this slice is sorted.

+

If the value is found then Result::Ok is returned, containing the +index of the matching element. If there are multiple matches, then any +one of the matches could be returned. The index is chosen +deterministically, but is subject to change in future versions of Rust. +If the value is not found then Result::Err is returned, containing +the index where a matching element could be inserted while maintaining +sorted order.

+

See also binary_search_by, binary_search_by_key, and partition_point.

+
Examples
+

Looks up a series of four elements. The first is found, with a +uniquely determined position; the second and third are not +found; the fourth could match any position in [1, 4].

+ +
let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+
+assert_eq!(s.binary_search(&13),  Ok(9));
+assert_eq!(s.binary_search(&4),   Err(7));
+assert_eq!(s.binary_search(&100), Err(13));
+let r = s.binary_search(&1);
+assert!(match r { Ok(1..=4) => true, _ => false, });
+

If you want to find that whole range of matching items, rather than +an arbitrary matching one, that can be done using partition_point:

+ +
let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+
+let low = s.partition_point(|x| x < &1);
+assert_eq!(low, 1);
+let high = s.partition_point(|x| x <= &1);
+assert_eq!(high, 5);
+let r = s.binary_search(&1);
+assert!((low..high).contains(&r.unwrap()));
+
+assert!(s[..low].iter().all(|&x| x < 1));
+assert!(s[low..high].iter().all(|&x| x == 1));
+assert!(s[high..].iter().all(|&x| x > 1));
+
+// For something not found, the "range" of equal items is empty
+assert_eq!(s.partition_point(|x| x < &11), 9);
+assert_eq!(s.partition_point(|x| x <= &11), 9);
+assert_eq!(s.binary_search(&11), Err(9));
+

If you want to insert an item to a sorted vector, while maintaining +sort order, consider using partition_point:

+ +
let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+let num = 42;
+let idx = s.partition_point(|&x| x < num);
+// The above is equivalent to `let idx = s.binary_search(&num).unwrap_or_else(|x| x);`
+s.insert(idx, num);
+assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
+

Binary searches this slice with a comparator function. +This behaves similarly to contains if this slice is sorted.

+

The comparator function should implement an order consistent +with the sort order of the underlying slice, returning an +order code that indicates whether its argument is Less, +Equal or Greater the desired target.

+

If the value is found then Result::Ok is returned, containing the +index of the matching element. If there are multiple matches, then any +one of the matches could be returned. The index is chosen +deterministically, but is subject to change in future versions of Rust. +If the value is not found then Result::Err is returned, containing +the index where a matching element could be inserted while maintaining +sorted order.

+

See also binary_search, binary_search_by_key, and partition_point.

+
Examples
+

Looks up a series of four elements. The first is found, with a +uniquely determined position; the second and third are not +found; the fourth could match any position in [1, 4].

+ +
let s = [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+
+let seek = 13;
+assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Ok(9));
+let seek = 4;
+assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(7));
+let seek = 100;
+assert_eq!(s.binary_search_by(|probe| probe.cmp(&seek)), Err(13));
+let seek = 1;
+let r = s.binary_search_by(|probe| probe.cmp(&seek));
+assert!(match r { Ok(1..=4) => true, _ => false, });
+

Binary searches this slice with a key extraction function. +This behaves similarly to contains if this slice is sorted.

+

Assumes that the slice is sorted by the key, for instance with +sort_by_key using the same key extraction function.

+

If the value is found then Result::Ok is returned, containing the +index of the matching element. If there are multiple matches, then any +one of the matches could be returned. The index is chosen +deterministically, but is subject to change in future versions of Rust. +If the value is not found then Result::Err is returned, containing +the index where a matching element could be inserted while maintaining +sorted order.

+

See also binary_search, binary_search_by, and partition_point.

+
Examples
+

Looks up a series of four elements in a slice of pairs sorted by +their second elements. The first is found, with a uniquely +determined position; the second and third are not found; the +fourth could match any position in [1, 4].

+ +
let s = [(0, 0), (2, 1), (4, 1), (5, 1), (3, 1),
+         (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
+         (1, 21), (2, 34), (4, 55)];
+
+assert_eq!(s.binary_search_by_key(&13, |&(a, b)| b),  Ok(9));
+assert_eq!(s.binary_search_by_key(&4, |&(a, b)| b),   Err(7));
+assert_eq!(s.binary_search_by_key(&100, |&(a, b)| b), Err(13));
+let r = s.binary_search_by_key(&1, |&(a, b)| b);
+assert!(match r { Ok(1..=4) => true, _ => false, });
+

Sorts the slice, but might not preserve the order of equal elements.

+

This sort is unstable (i.e., may reorder equal elements), in-place +(i.e., does not allocate), and O(n * log(n)) worst-case.

+
Current implementation
+

The current algorithm is based on pattern-defeating quicksort by Orson Peters, +which combines the fast average case of randomized quicksort with the fast worst case of +heapsort, while achieving linear time on slices with certain patterns. It uses some +randomization to avoid degenerate cases, but with a fixed seed to always provide +deterministic behavior.

+

It is typically faster than stable sorting, except in a few special cases, e.g., when the +slice consists of several concatenated sorted sequences.

+
Examples
+
let mut v = [-5, 4, 1, -3, 2];
+
+v.sort_unstable();
+assert!(v == [-5, -3, 1, 2, 4]);
+

Sorts the slice with a comparator function, but might not preserve the order of equal +elements.

+

This sort is unstable (i.e., may reorder equal elements), in-place +(i.e., does not allocate), and O(n * log(n)) worst-case.

+

The comparator function must define a total ordering for the elements in the slice. If +the ordering is not total, the order of the elements is unspecified. An order is a +total order if it is (for all a, b and c):

+
    +
  • total and antisymmetric: exactly one of a < b, a == b or a > b is true, and
  • +
  • transitive, a < b and b < c implies a < c. The same must hold for both == and >.
  • +
+

For example, while f64 doesn’t implement Ord because NaN != NaN, we can use +partial_cmp as our sort function when we know the slice doesn’t contain a NaN.

+ +
let mut floats = [5f64, 4.0, 1.0, 3.0, 2.0];
+floats.sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
+assert_eq!(floats, [1.0, 2.0, 3.0, 4.0, 5.0]);
+
Current implementation
+

The current algorithm is based on pattern-defeating quicksort by Orson Peters, +which combines the fast average case of randomized quicksort with the fast worst case of +heapsort, while achieving linear time on slices with certain patterns. It uses some +randomization to avoid degenerate cases, but with a fixed seed to always provide +deterministic behavior.

+

It is typically faster than stable sorting, except in a few special cases, e.g., when the +slice consists of several concatenated sorted sequences.

+
Examples
+
let mut v = [5, 4, 1, 3, 2];
+v.sort_unstable_by(|a, b| a.cmp(b));
+assert!(v == [1, 2, 3, 4, 5]);
+
+// reverse sorting
+v.sort_unstable_by(|a, b| b.cmp(a));
+assert!(v == [5, 4, 3, 2, 1]);
+

Sorts the slice with a key extraction function, but might not preserve the order of equal +elements.

+

This sort is unstable (i.e., may reorder equal elements), in-place +(i.e., does not allocate), and O(m * n * log(n)) worst-case, where the key function is +O(m).

+
Current implementation
+

The current algorithm is based on pattern-defeating quicksort by Orson Peters, +which combines the fast average case of randomized quicksort with the fast worst case of +heapsort, while achieving linear time on slices with certain patterns. It uses some +randomization to avoid degenerate cases, but with a fixed seed to always provide +deterministic behavior.

+

Due to its key calling strategy, sort_unstable_by_key +is likely to be slower than sort_by_cached_key in +cases where the key function is expensive.

+
Examples
+
let mut v = [-5i32, 4, 1, -3, 2];
+
+v.sort_unstable_by_key(|k| k.abs());
+assert!(v == [1, 2, -3, 4, -5]);
+

Reorder the slice such that the element at index is at its final sorted position.

+

This reordering has the additional property that any value at position i < index will be +less than or equal to any value at a position j > index. Additionally, this reordering is +unstable (i.e. any number of equal elements may end up at position index), in-place +(i.e. does not allocate), and O(n) worst-case. This function is also/ known as “kth +element” in other libraries. It returns a triplet of the following from the reordered slice: +the subslice prior to index, the element at index, and the subslice after index; +accordingly, the values in those two subslices will respectively all be less-than-or-equal-to +and greater-than-or-equal-to the value of the element at index.

+
Current implementation
+

The current algorithm is based on the quickselect portion of the same quicksort algorithm +used for sort_unstable.

+
Panics
+

Panics when index >= len(), meaning it always panics on empty slices.

+
Examples
+
let mut v = [-5i32, 4, 1, -3, 2];
+
+// Find the median
+v.select_nth_unstable(2);
+
+// We are only guaranteed the slice will be one of the following, based on the way we sort
+// about the specified index.
+assert!(v == [-3, -5, 1, 2, 4] ||
+        v == [-5, -3, 1, 2, 4] ||
+        v == [-3, -5, 1, 4, 2] ||
+        v == [-5, -3, 1, 4, 2]);
+

Reorder the slice with a comparator function such that the element at index is at its +final sorted position.

+

This reordering has the additional property that any value at position i < index will be +less than or equal to any value at a position j > index using the comparator function. +Additionally, this reordering is unstable (i.e. any number of equal elements may end up at +position index), in-place (i.e. does not allocate), and O(n) worst-case. This function +is also known as “kth element” in other libraries. It returns a triplet of the following from +the slice reordered according to the provided comparator function: the subslice prior to +index, the element at index, and the subslice after index; accordingly, the values in +those two subslices will respectively all be less-than-or-equal-to and greater-than-or-equal-to +the value of the element at index.

+
Current implementation
+

The current algorithm is based on the quickselect portion of the same quicksort algorithm +used for sort_unstable.

+
Panics
+

Panics when index >= len(), meaning it always panics on empty slices.

+
Examples
+
let mut v = [-5i32, 4, 1, -3, 2];
+
+// Find the median as if the slice were sorted in descending order.
+v.select_nth_unstable_by(2, |a, b| b.cmp(a));
+
+// We are only guaranteed the slice will be one of the following, based on the way we sort
+// about the specified index.
+assert!(v == [2, 4, 1, -5, -3] ||
+        v == [2, 4, 1, -3, -5] ||
+        v == [4, 2, 1, -5, -3] ||
+        v == [4, 2, 1, -3, -5]);
+

Reorder the slice with a key extraction function such that the element at index is at its +final sorted position.

+

This reordering has the additional property that any value at position i < index will be +less than or equal to any value at a position j > index using the key extraction function. +Additionally, this reordering is unstable (i.e. any number of equal elements may end up at +position index), in-place (i.e. does not allocate), and O(n) worst-case. This function +is also known as “kth element” in other libraries. It returns a triplet of the following from +the slice reordered according to the provided key extraction function: the subslice prior to +index, the element at index, and the subslice after index; accordingly, the values in +those two subslices will respectively all be less-than-or-equal-to and greater-than-or-equal-to +the value of the element at index.

+
Current implementation
+

The current algorithm is based on the quickselect portion of the same quicksort algorithm +used for sort_unstable.

+
Panics
+

Panics when index >= len(), meaning it always panics on empty slices.

+
Examples
+
let mut v = [-5i32, 4, 1, -3, 2];
+
+// Return the median as if the array were sorted according to absolute value.
+v.select_nth_unstable_by_key(2, |a| a.abs());
+
+// We are only guaranteed the slice will be one of the following, based on the way we sort
+// about the specified index.
+assert!(v == [1, 2, -3, 4, -5] ||
+        v == [1, 2, -3, -5, 4] ||
+        v == [2, 1, -3, 4, -5] ||
+        v == [2, 1, -3, -5, 4]);
+
🔬This is a nightly-only experimental API. (slice_partition_dedup)

Moves all consecutive repeated elements to the end of the slice according to the +PartialEq trait implementation.

+

Returns two slices. The first contains no consecutive repeated elements. +The second contains all the duplicates in no specified order.

+

If the slice is sorted, the first returned slice contains no duplicates.

+
Examples
+
#![feature(slice_partition_dedup)]
+
+let mut slice = [1, 2, 2, 3, 3, 2, 1, 1];
+
+let (dedup, duplicates) = slice.partition_dedup();
+
+assert_eq!(dedup, [1, 2, 3, 2, 1]);
+assert_eq!(duplicates, [2, 3, 1]);
+
🔬This is a nightly-only experimental API. (slice_partition_dedup)

Moves all but the first of consecutive elements to the end of the slice satisfying +a given equality relation.

+

Returns two slices. The first contains no consecutive repeated elements. +The second contains all the duplicates in no specified order.

+

The same_bucket function is passed references to two elements from the slice and +must determine if the elements compare equal. The elements are passed in opposite order +from their order in the slice, so if same_bucket(a, b) returns true, a is moved +at the end of the slice.

+

If the slice is sorted, the first returned slice contains no duplicates.

+
Examples
+
#![feature(slice_partition_dedup)]
+
+let mut slice = ["foo", "Foo", "BAZ", "Bar", "bar", "baz", "BAZ"];
+
+let (dedup, duplicates) = slice.partition_dedup_by(|a, b| a.eq_ignore_ascii_case(b));
+
+assert_eq!(dedup, ["foo", "BAZ", "Bar", "baz"]);
+assert_eq!(duplicates, ["bar", "Foo", "BAZ"]);
+
🔬This is a nightly-only experimental API. (slice_partition_dedup)

Moves all but the first of consecutive elements to the end of the slice that resolve +to the same key.

+

Returns two slices. The first contains no consecutive repeated elements. +The second contains all the duplicates in no specified order.

+

If the slice is sorted, the first returned slice contains no duplicates.

+
Examples
+
#![feature(slice_partition_dedup)]
+
+let mut slice = [10, 20, 21, 30, 30, 20, 11, 13];
+
+let (dedup, duplicates) = slice.partition_dedup_by_key(|i| *i / 10);
+
+assert_eq!(dedup, [10, 20, 30, 20, 11]);
+assert_eq!(duplicates, [21, 30, 13]);
+

Rotates the slice in-place such that the first mid elements of the +slice move to the end while the last self.len() - mid elements move to +the front. After calling rotate_left, the element previously at index +mid will become the first element in the slice.

+
Panics
+

This function will panic if mid is greater than the length of the +slice. Note that mid == self.len() does not panic and is a no-op +rotation.

+
Complexity
+

Takes linear (in self.len()) time.

+
Examples
+
let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
+a.rotate_left(2);
+assert_eq!(a, ['c', 'd', 'e', 'f', 'a', 'b']);
+

Rotating a subslice:

+ +
let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
+a[1..5].rotate_left(1);
+assert_eq!(a, ['a', 'c', 'd', 'e', 'b', 'f']);
+

Rotates the slice in-place such that the first self.len() - k +elements of the slice move to the end while the last k elements move +to the front. After calling rotate_right, the element previously at +index self.len() - k will become the first element in the slice.

+
Panics
+

This function will panic if k is greater than the length of the +slice. Note that k == self.len() does not panic and is a no-op +rotation.

+
Complexity
+

Takes linear (in self.len()) time.

+
Examples
+
let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
+a.rotate_right(2);
+assert_eq!(a, ['e', 'f', 'a', 'b', 'c', 'd']);
+

Rotate a subslice:

+ +
let mut a = ['a', 'b', 'c', 'd', 'e', 'f'];
+a[1..5].rotate_right(1);
+assert_eq!(a, ['a', 'e', 'b', 'c', 'd', 'f']);
+

Fills self with elements by cloning value.

+
Examples
+
let mut buf = vec![0; 10];
+buf.fill(1);
+assert_eq!(buf, vec![1; 10]);
+

Fills self with elements returned by calling a closure repeatedly.

+

This method uses a closure to create new values. If you’d rather +Clone a given value, use fill. If you want to use the Default +trait to generate values, you can pass Default::default as the +argument.

+
Examples
+
let mut buf = vec![1; 10];
+buf.fill_with(Default::default);
+assert_eq!(buf, vec![0; 10]);
+

Copies the elements from src into self.

+

The length of src must be the same as self.

+
Panics
+

This function will panic if the two slices have different lengths.

+
Examples
+

Cloning two elements from a slice into another:

+ +
let src = [1, 2, 3, 4];
+let mut dst = [0, 0];
+
+// Because the slices have to be the same length,
+// we slice the source slice from four elements
+// to two. It will panic if we don't do this.
+dst.clone_from_slice(&src[2..]);
+
+assert_eq!(src, [1, 2, 3, 4]);
+assert_eq!(dst, [3, 4]);
+

Rust enforces that there can only be one mutable reference with no +immutable references to a particular piece of data in a particular +scope. Because of this, attempting to use clone_from_slice on a +single slice will result in a compile failure:

+ +
let mut slice = [1, 2, 3, 4, 5];
+
+slice[..2].clone_from_slice(&slice[3..]); // compile fail!
+

To work around this, we can use split_at_mut to create two distinct +sub-slices from a slice:

+ +
let mut slice = [1, 2, 3, 4, 5];
+
+{
+    let (left, right) = slice.split_at_mut(2);
+    left.clone_from_slice(&right[1..]);
+}
+
+assert_eq!(slice, [4, 5, 3, 4, 5]);
+

Copies all elements from src into self, using a memcpy.

+

The length of src must be the same as self.

+

If T does not implement Copy, use clone_from_slice.

+
Panics
+

This function will panic if the two slices have different lengths.

+
Examples
+

Copying two elements from a slice into another:

+ +
let src = [1, 2, 3, 4];
+let mut dst = [0, 0];
+
+// Because the slices have to be the same length,
+// we slice the source slice from four elements
+// to two. It will panic if we don't do this.
+dst.copy_from_slice(&src[2..]);
+
+assert_eq!(src, [1, 2, 3, 4]);
+assert_eq!(dst, [3, 4]);
+

Rust enforces that there can only be one mutable reference with no +immutable references to a particular piece of data in a particular +scope. Because of this, attempting to use copy_from_slice on a +single slice will result in a compile failure:

+ +
let mut slice = [1, 2, 3, 4, 5];
+
+slice[..2].copy_from_slice(&slice[3..]); // compile fail!
+

To work around this, we can use split_at_mut to create two distinct +sub-slices from a slice:

+ +
let mut slice = [1, 2, 3, 4, 5];
+
+{
+    let (left, right) = slice.split_at_mut(2);
+    left.copy_from_slice(&right[1..]);
+}
+
+assert_eq!(slice, [4, 5, 3, 4, 5]);
+

Copies elements from one part of the slice to another part of itself, +using a memmove.

+

src is the range within self to copy from. dest is the starting +index of the range within self to copy to, which will have the same +length as src. The two ranges may overlap. The ends of the two ranges +must be less than or equal to self.len().

+
Panics
+

This function will panic if either range exceeds the end of the slice, +or if the end of src is before the start.

+
Examples
+

Copying four bytes within a slice:

+ +
let mut bytes = *b"Hello, World!";
+
+bytes.copy_within(1..5, 8);
+
+assert_eq!(&bytes, b"Hello, Wello!");
+

Swaps all elements in self with those in other.

+

The length of other must be the same as self.

+
Panics
+

This function will panic if the two slices have different lengths.

+
Example
+

Swapping two elements across slices:

+ +
let mut slice1 = [0, 0];
+let mut slice2 = [1, 2, 3, 4];
+
+slice1.swap_with_slice(&mut slice2[2..]);
+
+assert_eq!(slice1, [3, 4]);
+assert_eq!(slice2, [1, 2, 0, 0]);
+

Rust enforces that there can only be one mutable reference to a +particular piece of data in a particular scope. Because of this, +attempting to use swap_with_slice on a single slice will result in +a compile failure:

+ +
let mut slice = [1, 2, 3, 4, 5];
+slice[..2].swap_with_slice(&mut slice[3..]); // compile fail!
+

To work around this, we can use split_at_mut to create two distinct +mutable sub-slices from a slice:

+ +
let mut slice = [1, 2, 3, 4, 5];
+
+{
+    let (left, right) = slice.split_at_mut(2);
+    left.swap_with_slice(&mut right[1..]);
+}
+
+assert_eq!(slice, [4, 5, 3, 1, 2]);
+

Transmute the slice to a slice of another type, ensuring alignment of the types is +maintained.

+

This method splits the slice into three distinct slices: prefix, correctly aligned middle +slice of a new type, and the suffix slice. The method may make the middle slice the greatest +length possible for a given type and input slice, but only your algorithm’s performance +should depend on that, not its correctness. It is permissible for all of the input data to +be returned as the prefix or suffix slice.

+

This method has no purpose when either input element T or output element U are +zero-sized and will return the original slice without splitting anything.

+
Safety
+

This method is essentially a transmute with respect to the elements in the returned +middle slice, so all the usual caveats pertaining to transmute::<T, U> also apply here.

+
Examples
+

Basic usage:

+ +
unsafe {
+    let bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
+    let (prefix, shorts, suffix) = bytes.align_to::<u16>();
+    // less_efficient_algorithm_for_bytes(prefix);
+    // more_efficient_algorithm_for_aligned_shorts(shorts);
+    // less_efficient_algorithm_for_bytes(suffix);
+}
+

Transmute the slice to a slice of another type, ensuring alignment of the types is +maintained.

+

This method splits the slice into three distinct slices: prefix, correctly aligned middle +slice of a new type, and the suffix slice. The method may make the middle slice the greatest +length possible for a given type and input slice, but only your algorithm’s performance +should depend on that, not its correctness. It is permissible for all of the input data to +be returned as the prefix or suffix slice.

+

This method has no purpose when either input element T or output element U are +zero-sized and will return the original slice without splitting anything.

+
Safety
+

This method is essentially a transmute with respect to the elements in the returned +middle slice, so all the usual caveats pertaining to transmute::<T, U> also apply here.

+
Examples
+

Basic usage:

+ +
unsafe {
+    let mut bytes: [u8; 7] = [1, 2, 3, 4, 5, 6, 7];
+    let (prefix, shorts, suffix) = bytes.align_to_mut::<u16>();
+    // less_efficient_algorithm_for_bytes(prefix);
+    // more_efficient_algorithm_for_aligned_shorts(shorts);
+    // less_efficient_algorithm_for_bytes(suffix);
+}
+
🔬This is a nightly-only experimental API. (portable_simd)

Split a slice into a prefix, a middle of aligned SIMD types, and a suffix.

+

This is a safe wrapper around slice::align_to, so has the same weak +postconditions as that method. You’re only assured that +self.len() == prefix.len() + middle.len() * LANES + suffix.len().

+

Notably, all of the following are possible:

+
    +
  • prefix.len() >= LANES.
  • +
  • middle.is_empty() despite self.len() >= 3 * LANES.
  • +
  • suffix.len() >= LANES.
  • +
+

That said, this is a safe method, so if you’re only writing safe code, +then this can at most cause incorrect logic, not unsoundness.

+
Panics
+

This will panic if the size of the SIMD type is different from +LANES times that of the scalar.

+

At the time of writing, the trait restrictions on Simd<T, LANES> keeps +that from ever happening, as only power-of-two numbers of lanes are +supported. It’s possible that, in the future, those restrictions might +be lifted in a way that would make it possible to see panics from this +method for something like LANES == 3.

+
Examples
+
#![feature(portable_simd)]
+use core::simd::SimdFloat;
+
+let short = &[1, 2, 3];
+let (prefix, middle, suffix) = short.as_simd::<4>();
+assert_eq!(middle, []); // Not enough elements for anything in the middle
+
+// They might be split in any possible way between prefix and suffix
+let it = prefix.iter().chain(suffix).copied();
+assert_eq!(it.collect::<Vec<_>>(), vec![1, 2, 3]);
+
+fn basic_simd_sum(x: &[f32]) -> f32 {
+    use std::ops::Add;
+    use std::simd::f32x4;
+    let (prefix, middle, suffix) = x.as_simd();
+    let sums = f32x4::from_array([
+        prefix.iter().copied().sum(),
+        0.0,
+        0.0,
+        suffix.iter().copied().sum(),
+    ]);
+    let sums = middle.iter().copied().fold(sums, f32x4::add);
+    sums.reduce_sum()
+}
+
+let numbers: Vec<f32> = (1..101).map(|x| x as _).collect();
+assert_eq!(basic_simd_sum(&numbers[1..99]), 4949.0);
+
🔬This is a nightly-only experimental API. (portable_simd)

Split a slice into a prefix, a middle of aligned SIMD types, and a suffix.

+

This is a safe wrapper around slice::align_to_mut, so has the same weak +postconditions as that method. You’re only assured that +self.len() == prefix.len() + middle.len() * LANES + suffix.len().

+

Notably, all of the following are possible:

+
    +
  • prefix.len() >= LANES.
  • +
  • middle.is_empty() despite self.len() >= 3 * LANES.
  • +
  • suffix.len() >= LANES.
  • +
+

That said, this is a safe method, so if you’re only writing safe code, +then this can at most cause incorrect logic, not unsoundness.

+

This is the mutable version of slice::as_simd; see that for examples.

+
Panics
+

This will panic if the size of the SIMD type is different from +LANES times that of the scalar.

+

At the time of writing, the trait restrictions on Simd<T, LANES> keeps +that from ever happening, as only power-of-two numbers of lanes are +supported. It’s possible that, in the future, those restrictions might +be lifted in a way that would make it possible to see panics from this +method for something like LANES == 3.

+
🔬This is a nightly-only experimental API. (is_sorted)

Checks if the elements of this slice are sorted.

+

That is, for each element a and its following element b, a <= b must hold. If the +slice yields exactly zero or one element, true is returned.

+

Note that if Self::Item is only PartialOrd, but not Ord, the above definition +implies that this function returns false if any two consecutive items are not +comparable.

+
Examples
+
#![feature(is_sorted)]
+let empty: [i32; 0] = [];
+
+assert!([1, 2, 2, 9].is_sorted());
+assert!(![1, 3, 2, 4].is_sorted());
+assert!([0].is_sorted());
+assert!(empty.is_sorted());
+assert!(![0.0, 1.0, f32::NAN].is_sorted());
+
🔬This is a nightly-only experimental API. (is_sorted)

Checks if the elements of this slice are sorted using the given comparator function.

+

Instead of using PartialOrd::partial_cmp, this function uses the given compare +function to determine the ordering of two elements. Apart from that, it’s equivalent to +is_sorted; see its documentation for more information.

+
🔬This is a nightly-only experimental API. (is_sorted)

Checks if the elements of this slice are sorted using the given key extraction function.

+

Instead of comparing the slice’s elements directly, this function compares the keys of the +elements, as determined by f. Apart from that, it’s equivalent to is_sorted; see its +documentation for more information.

+
Examples
+
#![feature(is_sorted)]
+
+assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len()));
+assert!(![-2i32, -1, 0, 3].is_sorted_by_key(|n| n.abs()));
+

Returns the index of the partition point according to the given predicate +(the index of the first element of the second partition).

+

The slice is assumed to be partitioned according to the given predicate. +This means that all elements for which the predicate returns true are at the start of the slice +and all elements for which the predicate returns false are at the end. +For example, [7, 15, 3, 5, 4, 12, 6] is a partitioned under the predicate x % 2 != 0 +(all odd numbers are at the start, all even at the end).

+

If this slice is not partitioned, the returned result is unspecified and meaningless, +as this method performs a kind of binary search.

+

See also binary_search, binary_search_by, and binary_search_by_key.

+
Examples
+
let v = [1, 2, 3, 3, 5, 6, 7];
+let i = v.partition_point(|&x| x < 5);
+
+assert_eq!(i, 4);
+assert!(v[..i].iter().all(|&x| x < 5));
+assert!(v[i..].iter().all(|&x| !(x < 5)));
+

If all elements of the slice match the predicate, including if the slice +is empty, then the length of the slice will be returned:

+ +
let a = [2, 4, 8];
+assert_eq!(a.partition_point(|x| x < &100), a.len());
+let a: [i32; 0] = [];
+assert_eq!(a.partition_point(|x| x < &100), 0);
+

If you want to insert an item to a sorted vector, while maintaining +sort order:

+ +
let mut s = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
+let num = 42;
+let idx = s.partition_point(|&x| x < num);
+s.insert(idx, num);
+assert_eq!(s, [0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]);
+
🔬This is a nightly-only experimental API. (slice_take)

Removes the subslice corresponding to the given range +and returns a reference to it.

+

Returns None and does not modify the slice if the given +range is out of bounds.

+

Note that this method only accepts one-sided ranges such as +2.. or ..6, but not 2..6.

+
Examples
+

Taking the first three elements of a slice:

+ +
#![feature(slice_take)]
+
+let mut slice: &[_] = &['a', 'b', 'c', 'd'];
+let mut first_three = slice.take(..3).unwrap();
+
+assert_eq!(slice, &['d']);
+assert_eq!(first_three, &['a', 'b', 'c']);
+

Taking the last two elements of a slice:

+ +
#![feature(slice_take)]
+
+let mut slice: &[_] = &['a', 'b', 'c', 'd'];
+let mut tail = slice.take(2..).unwrap();
+
+assert_eq!(slice, &['a', 'b']);
+assert_eq!(tail, &['c', 'd']);
+

Getting None when range is out of bounds:

+ +
#![feature(slice_take)]
+
+let mut slice: &[_] = &['a', 'b', 'c', 'd'];
+
+assert_eq!(None, slice.take(5..));
+assert_eq!(None, slice.take(..5));
+assert_eq!(None, slice.take(..=4));
+let expected: &[char] = &['a', 'b', 'c', 'd'];
+assert_eq!(Some(expected), slice.take(..4));
+
🔬This is a nightly-only experimental API. (slice_take)

Removes the subslice corresponding to the given range +and returns a mutable reference to it.

+

Returns None and does not modify the slice if the given +range is out of bounds.

+

Note that this method only accepts one-sided ranges such as +2.. or ..6, but not 2..6.

+
Examples
+

Taking the first three elements of a slice:

+ +
#![feature(slice_take)]
+
+let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
+let mut first_three = slice.take_mut(..3).unwrap();
+
+assert_eq!(slice, &mut ['d']);
+assert_eq!(first_three, &mut ['a', 'b', 'c']);
+

Taking the last two elements of a slice:

+ +
#![feature(slice_take)]
+
+let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
+let mut tail = slice.take_mut(2..).unwrap();
+
+assert_eq!(slice, &mut ['a', 'b']);
+assert_eq!(tail, &mut ['c', 'd']);
+

Getting None when range is out of bounds:

+ +
#![feature(slice_take)]
+
+let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
+
+assert_eq!(None, slice.take_mut(5..));
+assert_eq!(None, slice.take_mut(..5));
+assert_eq!(None, slice.take_mut(..=4));
+let expected: &mut [_] = &mut ['a', 'b', 'c', 'd'];
+assert_eq!(Some(expected), slice.take_mut(..4));
+
🔬This is a nightly-only experimental API. (slice_take)

Removes the first element of the slice and returns a reference +to it.

+

Returns None if the slice is empty.

+
Examples
+
#![feature(slice_take)]
+
+let mut slice: &[_] = &['a', 'b', 'c'];
+let first = slice.take_first().unwrap();
+
+assert_eq!(slice, &['b', 'c']);
+assert_eq!(first, &'a');
+
🔬This is a nightly-only experimental API. (slice_take)

Removes the first element of the slice and returns a mutable +reference to it.

+

Returns None if the slice is empty.

+
Examples
+
#![feature(slice_take)]
+
+let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
+let first = slice.take_first_mut().unwrap();
+*first = 'd';
+
+assert_eq!(slice, &['b', 'c']);
+assert_eq!(first, &'d');
+
🔬This is a nightly-only experimental API. (slice_take)

Removes the last element of the slice and returns a reference +to it.

+

Returns None if the slice is empty.

+
Examples
+
#![feature(slice_take)]
+
+let mut slice: &[_] = &['a', 'b', 'c'];
+let last = slice.take_last().unwrap();
+
+assert_eq!(slice, &['a', 'b']);
+assert_eq!(last, &'c');
+
🔬This is a nightly-only experimental API. (slice_take)

Removes the last element of the slice and returns a mutable +reference to it.

+

Returns None if the slice is empty.

+
Examples
+
#![feature(slice_take)]
+
+let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
+let last = slice.take_last_mut().unwrap();
+*last = 'd';
+
+assert_eq!(slice, &['a', 'b']);
+assert_eq!(last, &'d');
+

Returns a vector containing a copy of this slice where each byte +is mapped to its ASCII upper case equivalent.

+

ASCII letters ‘a’ to ‘z’ are mapped to ‘A’ to ‘Z’, +but non-ASCII letters are unchanged.

+

To uppercase the value in-place, use make_ascii_uppercase.

+

Returns a vector containing a copy of this slice where each byte +is mapped to its ASCII lower case equivalent.

+

ASCII letters ‘A’ to ‘Z’ are mapped to ‘a’ to ‘z’, +but non-ASCII letters are unchanged.

+

To lowercase the value in-place, use make_ascii_lowercase.

+

Sorts the slice.

+

This sort is stable (i.e., does not reorder equal elements) and O(n * log(n)) worst-case.

+

When applicable, unstable sorting is preferred because it is generally faster than stable +sorting and it doesn’t allocate auxiliary memory. +See sort_unstable.

+
Current implementation
+

The current algorithm is an adaptive, iterative merge sort inspired by +timsort. +It is designed to be very fast in cases where the slice is nearly sorted, or consists of +two or more sorted sequences concatenated one after another.

+

Also, it allocates temporary storage half the size of self, but for short slices a +non-allocating insertion sort is used instead.

+
Examples
+
let mut v = [-5, 4, 1, -3, 2];
+
+v.sort();
+assert!(v == [-5, -3, 1, 2, 4]);
+

Sorts the slice with a comparator function.

+

This sort is stable (i.e., does not reorder equal elements) and O(n * log(n)) worst-case.

+

The comparator function must define a total ordering for the elements in the slice. If +the ordering is not total, the order of the elements is unspecified. An order is a +total order if it is (for all a, b and c):

+
    +
  • total and antisymmetric: exactly one of a < b, a == b or a > b is true, and
  • +
  • transitive, a < b and b < c implies a < c. The same must hold for both == and >.
  • +
+

For example, while f64 doesn’t implement Ord because NaN != NaN, we can use +partial_cmp as our sort function when we know the slice doesn’t contain a NaN.

+ +
let mut floats = [5f64, 4.0, 1.0, 3.0, 2.0];
+floats.sort_by(|a, b| a.partial_cmp(b).unwrap());
+assert_eq!(floats, [1.0, 2.0, 3.0, 4.0, 5.0]);
+

When applicable, unstable sorting is preferred because it is generally faster than stable +sorting and it doesn’t allocate auxiliary memory. +See sort_unstable_by.

+
Current implementation
+

The current algorithm is an adaptive, iterative merge sort inspired by +timsort. +It is designed to be very fast in cases where the slice is nearly sorted, or consists of +two or more sorted sequences concatenated one after another.

+

Also, it allocates temporary storage half the size of self, but for short slices a +non-allocating insertion sort is used instead.

+
Examples
+
let mut v = [5, 4, 1, 3, 2];
+v.sort_by(|a, b| a.cmp(b));
+assert!(v == [1, 2, 3, 4, 5]);
+
+// reverse sorting
+v.sort_by(|a, b| b.cmp(a));
+assert!(v == [5, 4, 3, 2, 1]);
+

Sorts the slice with a key extraction function.

+

This sort is stable (i.e., does not reorder equal elements) and O(m * n * log(n)) +worst-case, where the key function is O(m).

+

For expensive key functions (e.g. functions that are not simple property accesses or +basic operations), sort_by_cached_key is likely to be +significantly faster, as it does not recompute element keys.

+

When applicable, unstable sorting is preferred because it is generally faster than stable +sorting and it doesn’t allocate auxiliary memory. +See sort_unstable_by_key.

+
Current implementation
+

The current algorithm is an adaptive, iterative merge sort inspired by +timsort. +It is designed to be very fast in cases where the slice is nearly sorted, or consists of +two or more sorted sequences concatenated one after another.

+

Also, it allocates temporary storage half the size of self, but for short slices a +non-allocating insertion sort is used instead.

+
Examples
+
let mut v = [-5i32, 4, 1, -3, 2];
+
+v.sort_by_key(|k| k.abs());
+assert!(v == [1, 2, -3, 4, -5]);
+

Sorts the slice with a key extraction function.

+

During sorting, the key function is called at most once per element, by using +temporary storage to remember the results of key evaluation. +The order of calls to the key function is unspecified and may change in future versions +of the standard library.

+

This sort is stable (i.e., does not reorder equal elements) and O(m * n + n * log(n)) +worst-case, where the key function is O(m).

+

For simple key functions (e.g., functions that are property accesses or +basic operations), sort_by_key is likely to be +faster.

+
Current implementation
+

The current algorithm is based on pattern-defeating quicksort by Orson Peters, +which combines the fast average case of randomized quicksort with the fast worst case of +heapsort, while achieving linear time on slices with certain patterns. It uses some +randomization to avoid degenerate cases, but with a fixed seed to always provide +deterministic behavior.

+

In the worst case, the algorithm allocates temporary storage in a Vec<(K, usize)> the +length of the slice.

+
Examples
+
let mut v = [-5i32, 4, 32, -3, 2];
+
+v.sort_by_cached_key(|k| k.to_string());
+assert!(v == [-3, -5, 2, 32, 4]);
+

Copies self into a new Vec.

+
Examples
+
let s = [10, 40, 30];
+let x = s.to_vec();
+// Here, `s` and `x` can be modified independently.
+
🔬This is a nightly-only experimental API. (allocator_api)

Copies self into a new Vec with an allocator.

+
Examples
+
#![feature(allocator_api)]
+
+use std::alloc::System;
+
+let s = [10, 40, 30];
+let x = s.to_vec_in(System);
+// Here, `s` and `x` can be modified independently.
+

Creates a vector by repeating a slice n times.

+
Panics
+

This function will panic if the capacity would overflow.

+
Examples
+

Basic usage:

+ +
assert_eq!([1, 2].repeat(3), vec![1, 2, 1, 2, 1, 2]);
+

A panic upon overflow:

+ +
// this will panic at runtime
+b"0123456789abcdef".repeat(usize::MAX);
+

Flattens a slice of T into a single value Self::Output.

+
Examples
+
assert_eq!(["hello", "world"].concat(), "helloworld");
+assert_eq!([[1, 2], [3, 4]].concat(), [1, 2, 3, 4]);
+

Flattens a slice of T into a single value Self::Output, placing a +given separator between each.

+
Examples
+
assert_eq!(["hello", "world"].join(" "), "hello world");
+assert_eq!([[1, 2], [3, 4]].join(&0), [1, 2, 0, 3, 4]);
+assert_eq!([[1, 2], [3, 4]].join(&[0, 0][..]), [1, 2, 0, 0, 3, 4]);
+
👎Deprecated since 1.3.0: renamed to join

Flattens a slice of T into a single value Self::Output, placing a +given separator between each.

+
Examples
+
assert_eq!(["hello", "world"].connect(" "), "hello world");
+assert_eq!([[1, 2], [3, 4]].connect(&0), [1, 2, 0, 3, 4]);
+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
The resulting type after dereferencing.
Dereferences the value.
Mutably dereferences the value.
The returned type after indexing.
Performs the indexing (container[index]) operation. Read more
The returned type after indexing.
Performs the indexing (container[index]) operation. Read more
The returned type after indexing.
Performs the indexing (container[index]) operation. Read more
Performs the mutable indexing (container[index]) operation. Read more
Performs the mutable indexing (container[index]) operation. Read more
Performs the mutable indexing (container[index]) operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/struct.ProverQuery.html b/docs/halo2_proofs/poly/struct.ProverQuery.html new file mode 100644 index 0000000000..4c3eead6f4 --- /dev/null +++ b/docs/halo2_proofs/poly/struct.ProverQuery.html @@ -0,0 +1,26 @@ +ProverQuery in halo2_proofs::poly - Rust
pub struct ProverQuery<'com, C: CurveAffine> { /* private fields */ }
Expand description

A polynomial query at a point

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/struct.Rotation.html b/docs/halo2_proofs/poly/struct.Rotation.html new file mode 100644 index 0000000000..888cb068d9 --- /dev/null +++ b/docs/halo2_proofs/poly/struct.Rotation.html @@ -0,0 +1,33 @@ +Rotation in halo2_proofs::poly - Rust
pub struct Rotation(pub i32);
Expand description

Describes the relative rotation of a vector. Negative numbers represent +reverse (leftmost) rotations and positive numbers represent forward (rightmost) +rotations. Zero represents no rotation.

+

Tuple Fields

0: i32

Implementations

The current location in the evaluation domain

+

The previous location in the evaluation domain

+

The next location in the evaluation domain

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/struct.VerifierQuery.html b/docs/halo2_proofs/poly/struct.VerifierQuery.html new file mode 100644 index 0000000000..576204e4ab --- /dev/null +++ b/docs/halo2_proofs/poly/struct.VerifierQuery.html @@ -0,0 +1,28 @@ +VerifierQuery in halo2_proofs::poly - Rust
pub struct VerifierQuery<'com, C: CurveAffine, M: MSM<C>> { /* private fields */ }
Expand description

A polynomial query at a point

+

Implementations

Create a new verifier query based on a commitment

+

Create a new verifier query based on a linear combination of commitments

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/trait.Basis.html b/docs/halo2_proofs/poly/trait.Basis.html new file mode 100644 index 0000000000..33181e9535 --- /dev/null +++ b/docs/halo2_proofs/poly/trait.Basis.html @@ -0,0 +1,2 @@ +Basis in halo2_proofs::poly - Rust
pub trait Basis: Copy + Debug + Send + Sync { }
Expand description

The basis over which a polynomial is described.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/poly/trait.Guard.html b/docs/halo2_proofs/poly/trait.Guard.html new file mode 100644 index 0000000000..d08d6261fc --- /dev/null +++ b/docs/halo2_proofs/poly/trait.Guard.html @@ -0,0 +1,8 @@ +Guard in halo2_proofs::poly - Rust
pub trait Guard<Scheme: CommitmentScheme> {
+    type MSMAccumulator;
+}
Expand description

Guards is unfinished verification result. Implement this to construct various +verification strategies such as aggregation and recursion.

+

Required Associated Types

Multi scalar engine which is not evaluated yet.

+

Implementors

Define accumulator type as MSMIPA

+

Define accumulator type as DualMSM

+
\ No newline at end of file diff --git a/docs/halo2_proofs/poly/trait.VerificationStrategy.html b/docs/halo2_proofs/poly/trait.VerificationStrategy.html new file mode 100644 index 0000000000..0ba0d0a138 --- /dev/null +++ b/docs/halo2_proofs/poly/trait.VerificationStrategy.html @@ -0,0 +1,15 @@ +VerificationStrategy in halo2_proofs::poly - Rust
pub trait VerificationStrategy<'params, Scheme: CommitmentScheme, V: Verifier<'params, Scheme>> {
+    type Output;
+
+    fn new(params: &'params Scheme::ParamsVerifier) -> Self;
+    fn process(
        self,
        f: impl FnOnce(V::MSMAccumulator) -> Result<V::Guard, Error>
    ) -> Result<Self::Output, Error>; + fn finalize(self) -> bool; +}
Expand description

Trait representing a strategy for verifying Halo 2 proofs.

+

Required Associated Types

The output type of this verification strategy after processing a proof.

+

Required Methods

Creates new verification strategy instance

+

Obtains an MSM from the verifier strategy and yields back the strategy’s +output.

+

Finalizes the batch and checks its validity.

+

Returns false if some proof was invalid. If the caller needs to identify +specific failing proofs, it must re-process the proofs separately.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/sidebar-items.js b/docs/halo2_proofs/sidebar-items.js new file mode 100644 index 0000000000..06752f9df9 --- /dev/null +++ b/docs/halo2_proofs/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"enum":[["SerdeFormat","This enum specifies how various types are serialized and deserialized."]],"mod":[["arithmetic","This module provides common utilities, traits and structures for group, field and polynomial arithmetic."],["circuit","Traits and structs for implementing circuit components."],["dev","Tools for developing circuits."],["plonk","This module provides an implementation of a variant of (Turbo)PLONK that is designed specifically for the polynomial commitment scheme described in the Halo paper."],["poly","Contains utilities for performing arithmetic over univariate polynomials in various forms, including computing commitments to them and provably opening the committed polynomials at arbitrary points."],["transcript","This module contains utilities and traits for dealing with Fiat-Shamir transcripts."]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/transcript/index.html b/docs/halo2_proofs/transcript/index.html new file mode 100644 index 0000000000..401c912680 --- /dev/null +++ b/docs/halo2_proofs/transcript/index.html @@ -0,0 +1,7 @@ +halo2_proofs::transcript - Rust
Expand description

This module contains utilities and traits for dealing with Fiat-Shamir +transcripts.

+

Structs

We will replace BLAKE2b with an algebraic hash function in a later version.
We will replace BLAKE2b with an algebraic hash function in a later version.
A 255-bit challenge.
The scalar representation of a verifier challenge.

Traits

EncodedChallenge<C> defines a challenge encoding with a Self::Input +that is used to derive the challenge encoding and get_challenge obtains +the real C::Scalar that the challenge encoding represents.
Generic transcript view (from either the prover or verifier’s perspective)
Transcript view from the perspective of a verifier that has access to an +input stream of data from the prover to the verifier.
Initializes transcript at verifier side.
Transcript view from the perspective of a prover that has access to an +output stream of messages from the prover to the verifier.
Manages begining and finising of transcript pipeline.
\ No newline at end of file diff --git a/docs/halo2_proofs/transcript/sidebar-items.js b/docs/halo2_proofs/transcript/sidebar-items.js new file mode 100644 index 0000000000..57beccf43a --- /dev/null +++ b/docs/halo2_proofs/transcript/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":[["Blake2bRead","We will replace BLAKE2b with an algebraic hash function in a later version."],["Blake2bWrite","We will replace BLAKE2b with an algebraic hash function in a later version."],["Challenge255","A 255-bit challenge."],["ChallengeScalar","The scalar representation of a verifier challenge."]],"trait":[["EncodedChallenge","`EncodedChallenge` defines a challenge encoding with a [`Self::Input`] that is used to derive the challenge encoding and `get_challenge` obtains the real `C::Scalar` that the challenge encoding represents."],["Transcript","Generic transcript view (from either the prover or verifier’s perspective)"],["TranscriptRead","Transcript view from the perspective of a verifier that has access to an input stream of data from the prover to the verifier."],["TranscriptReadBuffer","Initializes transcript at verifier side."],["TranscriptWrite","Transcript view from the perspective of a prover that has access to an output stream of messages from the prover to the verifier."],["TranscriptWriterBuffer","Manages begining and finising of transcript pipeline."]]}; \ No newline at end of file diff --git a/docs/halo2_proofs/transcript/struct.Blake2bRead.html b/docs/halo2_proofs/transcript/struct.Blake2bRead.html new file mode 100644 index 0000000000..4e44f2325b --- /dev/null +++ b/docs/halo2_proofs/transcript/struct.Blake2bRead.html @@ -0,0 +1,29 @@ +Blake2bRead in halo2_proofs::transcript - Rust
pub struct Blake2bRead<R: Read, C: CurveAffine, E: EncodedChallenge<C>> { /* private fields */ }
Expand description

We will replace BLAKE2b with an algebraic hash function in a later version.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Squeeze an encoded verifier challenge from the transcript.
Writing the point to the transcript without writing it to the proof, +treating it as a common input. Read more
Writing the scalar to the transcript without writing it to the proof, +treating it as a common input. Read more
Squeeze a typed challenge (in the scalar field) from the transcript.
Read a curve point from the prover.
Read a curve scalar from the prover.

Initialize a transcript given an input buffer.

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/transcript/struct.Blake2bWrite.html b/docs/halo2_proofs/transcript/struct.Blake2bWrite.html new file mode 100644 index 0000000000..e938d0f3f8 --- /dev/null +++ b/docs/halo2_proofs/transcript/struct.Blake2bWrite.html @@ -0,0 +1,28 @@ +Blake2bWrite in halo2_proofs::transcript - Rust
pub struct Blake2bWrite<W: Write, C: CurveAffine, E: EncodedChallenge<C>> { /* private fields */ }
Expand description

We will replace BLAKE2b with an algebraic hash function in a later version.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Squeeze an encoded verifier challenge from the transcript.
Writing the point to the transcript without writing it to the proof, +treating it as a common input. Read more
Writing the scalar to the transcript without writing it to the proof, +treating it as a common input. Read more
Squeeze a typed challenge (in the scalar field) from the transcript.
Write a curve point to the proof and the transcript.
Write a scalar to the proof and the transcript.
Initialize a transcript given an output buffer.
Conclude the interaction and return the output buffer (writer).

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/transcript/struct.Challenge255.html b/docs/halo2_proofs/transcript/struct.Challenge255.html new file mode 100644 index 0000000000..44ca26ce9b --- /dev/null +++ b/docs/halo2_proofs/transcript/struct.Challenge255.html @@ -0,0 +1,110 @@ +Challenge255 in halo2_proofs::transcript - Rust
pub struct Challenge255<C: CurveAffine>(_, _);
Expand description

A 255-bit challenge.

+

Methods from Deref<Target = [u8; 32]>

Returns a slice containing the entire array. Equivalent to &s[..].

+
🔬This is a nightly-only experimental API. (array_methods)

Borrows each element and returns an array of references with the same +size as self.

+
Example
+
#![feature(array_methods)]
+
+let floats = [3.1, 2.7, -1.0];
+let float_refs: [&f64; 3] = floats.each_ref();
+assert_eq!(float_refs, [&3.1, &2.7, &-1.0]);
+

This method is particularly useful if combined with other methods, like +map. This way, you can avoid moving the original +array if its elements are not Copy.

+ +
#![feature(array_methods)]
+
+let strings = ["Ferris".to_string(), "♥".to_string(), "Rust".to_string()];
+let is_ascii = strings.each_ref().map(|s| s.is_ascii());
+assert_eq!(is_ascii, [true, false, true]);
+
+// We can still access the original array: it has not been moved.
+assert_eq!(strings.len(), 3);
+
🔬This is a nightly-only experimental API. (split_array)

Divides one array reference into two at an index.

+

The first will contain all indices from [0, M) (excluding +the index M itself) and the second will contain all +indices from [M, N) (excluding the index N itself).

+
Panics
+

Panics if M > N.

+
Examples
+
#![feature(split_array)]
+
+let v = [1, 2, 3, 4, 5, 6];
+
+{
+   let (left, right) = v.split_array_ref::<0>();
+   assert_eq!(left, &[]);
+   assert_eq!(right, &[1, 2, 3, 4, 5, 6]);
+}
+
+{
+    let (left, right) = v.split_array_ref::<2>();
+    assert_eq!(left, &[1, 2]);
+    assert_eq!(right, &[3, 4, 5, 6]);
+}
+
+{
+    let (left, right) = v.split_array_ref::<6>();
+    assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
+    assert_eq!(right, &[]);
+}
+
🔬This is a nightly-only experimental API. (split_array)

Divides one array reference into two at an index from the end.

+

The first will contain all indices from [0, N - M) (excluding +the index N - M itself) and the second will contain all +indices from [N - M, N) (excluding the index N itself).

+
Panics
+

Panics if M > N.

+
Examples
+
#![feature(split_array)]
+
+let v = [1, 2, 3, 4, 5, 6];
+
+{
+   let (left, right) = v.rsplit_array_ref::<0>();
+   assert_eq!(left, &[1, 2, 3, 4, 5, 6]);
+   assert_eq!(right, &[]);
+}
+
+{
+    let (left, right) = v.rsplit_array_ref::<2>();
+    assert_eq!(left, &[1, 2, 3, 4]);
+    assert_eq!(right, &[5, 6]);
+}
+
+{
+    let (left, right) = v.rsplit_array_ref::<6>();
+    assert_eq!(left, &[]);
+    assert_eq!(right, &[1, 2, 3, 4, 5, 6]);
+}
+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
The resulting type after dereferencing.
Dereferences the value.
The Input type used to derive the challenge encoding. For example, +an input from the Poseidon hash would be a base field element; +an input from the Blake2b hash would be a [u8; 64]. Read more
Get an encoded challenge from a given input challenge.
Get a scalar field element from an encoded challenge.
Cast an encoded challenge as a typed ChallengeScalar.
Squeeze an encoded verifier challenge from the transcript.
Writing the point to the transcript without writing it to the proof, +treating it as a common input. Read more
Writing the scalar to the transcript without writing it to the proof, +treating it as a common input. Read more
Squeeze a typed challenge (in the scalar field) from the transcript.
Squeeze an encoded verifier challenge from the transcript.
Writing the point to the transcript without writing it to the proof, +treating it as a common input. Read more
Writing the scalar to the transcript without writing it to the proof, +treating it as a common input. Read more
Squeeze a typed challenge (in the scalar field) from the transcript.
Read a curve point from the prover.
Read a curve scalar from the prover.

Initialize a transcript given an input buffer.

+
Write a curve point to the proof and the transcript.
Write a scalar to the proof and the transcript.
Initialize a transcript given an output buffer.
Conclude the interaction and return the output buffer (writer).

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/transcript/struct.ChallengeScalar.html b/docs/halo2_proofs/transcript/struct.ChallengeScalar.html new file mode 100644 index 0000000000..536af9830e --- /dev/null +++ b/docs/halo2_proofs/transcript/struct.ChallengeScalar.html @@ -0,0 +1,28 @@ +ChallengeScalar in halo2_proofs::transcript - Rust
pub struct ChallengeScalar<C: CurveAffine, T> { /* private fields */ }
Expand description

The scalar representation of a verifier challenge.

+

The Type type can be used to scope the challenge to a specific context, or +set to () if no context is required.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
The resulting type after dereferencing.
Dereferences the value.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+
Instruments this type with the provided Span, returning an +Instrumented wrapper. Read more
Instruments this type with the current Span, returning an +Instrumented wrapper. Read more

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
The alignment of pointer.
The type for initializers.
Initializes a with the given initializer. Read more
Dereferences the given pointer. Read more
Mutably dereferences the given pointer. Read more
Drops the object pointed to by the given pointer. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
Attaches the provided Subscriber to this type, returning a +WithDispatch wrapper. Read more
Attaches the current default Subscriber to this type, returning a +WithDispatch wrapper. Read more
\ No newline at end of file diff --git a/docs/halo2_proofs/transcript/trait.EncodedChallenge.html b/docs/halo2_proofs/transcript/trait.EncodedChallenge.html new file mode 100644 index 0000000000..64f26a392f --- /dev/null +++ b/docs/halo2_proofs/transcript/trait.EncodedChallenge.html @@ -0,0 +1,17 @@ +EncodedChallenge in halo2_proofs::transcript - Rust
pub trait EncodedChallenge<C: CurveAffine> {
+    type Input;
+
+    fn new(challenge_input: &Self::Input) -> Self;
+    fn get_scalar(&self) -> C::Scalar;
+
+    fn as_challenge_scalar<T>(&self) -> ChallengeScalar<C, T> { ... }
+}
Expand description

EncodedChallenge<C> defines a challenge encoding with a Self::Input +that is used to derive the challenge encoding and get_challenge obtains +the real C::Scalar that the challenge encoding represents.

+

Required Associated Types

The Input type used to derive the challenge encoding. For example, +an input from the Poseidon hash would be a base field element; +an input from the Blake2b hash would be a [u8; 64].

+

Required Methods

Get an encoded challenge from a given input challenge.

+

Get a scalar field element from an encoded challenge.

+

Provided Methods

Cast an encoded challenge as a typed ChallengeScalar.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/transcript/trait.Transcript.html b/docs/halo2_proofs/transcript/trait.Transcript.html new file mode 100644 index 0000000000..eee140bbdc --- /dev/null +++ b/docs/halo2_proofs/transcript/trait.Transcript.html @@ -0,0 +1,14 @@ +Transcript in halo2_proofs::transcript - Rust
pub trait Transcript<C: CurveAffine, E: EncodedChallenge<C>> {
+    fn squeeze_challenge(&mut self) -> E;
+    fn common_point(&mut self, point: C) -> Result<()>;
+    fn common_scalar(&mut self, scalar: C::Scalar) -> Result<()>;
+
+    fn squeeze_challenge_scalar<T>(&mut self) -> ChallengeScalar<C, T> { ... }
+}
Expand description

Generic transcript view (from either the prover or verifier’s perspective)

+

Required Methods

Squeeze an encoded verifier challenge from the transcript.

+

Writing the point to the transcript without writing it to the proof, +treating it as a common input.

+

Writing the scalar to the transcript without writing it to the proof, +treating it as a common input.

+

Provided Methods

Squeeze a typed challenge (in the scalar field) from the transcript.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/transcript/trait.TranscriptRead.html b/docs/halo2_proofs/transcript/trait.TranscriptRead.html new file mode 100644 index 0000000000..4fdd0cab7d --- /dev/null +++ b/docs/halo2_proofs/transcript/trait.TranscriptRead.html @@ -0,0 +1,8 @@ +TranscriptRead in halo2_proofs::transcript - Rust
pub trait TranscriptRead<C: CurveAffine, E: EncodedChallenge<C>>: Transcript<C, E> {
+    fn read_point(&mut self) -> Result<C>;
+    fn read_scalar(&mut self) -> Result<C::Scalar>;
+}
Expand description

Transcript view from the perspective of a verifier that has access to an +input stream of data from the prover to the verifier.

+

Required Methods

Read a curve point from the prover.

+

Read a curve scalar from the prover.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/transcript/trait.TranscriptReadBuffer.html b/docs/halo2_proofs/transcript/trait.TranscriptReadBuffer.html new file mode 100644 index 0000000000..786f9d42cb --- /dev/null +++ b/docs/halo2_proofs/transcript/trait.TranscriptReadBuffer.html @@ -0,0 +1,5 @@ +TranscriptReadBuffer in halo2_proofs::transcript - Rust
pub trait TranscriptReadBuffer<R: Read, C: CurveAffine, E: EncodedChallenge<C>>: TranscriptRead<C, E> {
+    fn init(reader: R) -> Self;
+}
Expand description

Initializes transcript at verifier side.

+

Required Methods

Initialize a transcript given an input buffer.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/transcript/trait.TranscriptWrite.html b/docs/halo2_proofs/transcript/trait.TranscriptWrite.html new file mode 100644 index 0000000000..1fd8a980c3 --- /dev/null +++ b/docs/halo2_proofs/transcript/trait.TranscriptWrite.html @@ -0,0 +1,8 @@ +TranscriptWrite in halo2_proofs::transcript - Rust
pub trait TranscriptWrite<C: CurveAffine, E: EncodedChallenge<C>>: Transcript<C, E> {
+    fn write_point(&mut self, point: C) -> Result<()>;
+    fn write_scalar(&mut self, scalar: C::Scalar) -> Result<()>;
+}
Expand description

Transcript view from the perspective of a prover that has access to an +output stream of messages from the prover to the verifier.

+

Required Methods

Write a curve point to the proof and the transcript.

+

Write a scalar to the proof and the transcript.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2_proofs/transcript/trait.TranscriptWriterBuffer.html b/docs/halo2_proofs/transcript/trait.TranscriptWriterBuffer.html new file mode 100644 index 0000000000..85ff89a4ec --- /dev/null +++ b/docs/halo2_proofs/transcript/trait.TranscriptWriterBuffer.html @@ -0,0 +1,7 @@ +TranscriptWriterBuffer in halo2_proofs::transcript - Rust
pub trait TranscriptWriterBuffer<W: Write, C: CurveAffine, E: EncodedChallenge<C>>: TranscriptWrite<C, E> {
+    fn init(writer: W) -> Self;
+    fn finalize(self) -> W;
+}
Expand description

Manages begining and finising of transcript pipeline.

+

Required Methods

Initialize a transcript given an output buffer.

+

Conclude the interaction and return the output buffer (writer).

+

Implementors

\ No newline at end of file diff --git a/docs/halo2curves/all.html b/docs/halo2curves/all.html new file mode 100644 index 0000000000..0eb469eeea --- /dev/null +++ b/docs/halo2curves/all.html @@ -0,0 +1 @@ +List of all items in this crate
\ No newline at end of file diff --git a/docs/halo2curves/arithmetic/trait.CurveAffineExt.html b/docs/halo2curves/arithmetic/trait.CurveAffineExt.html new file mode 100644 index 0000000000..bd10aa490f --- /dev/null +++ b/docs/halo2curves/arithmetic/trait.CurveAffineExt.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../halo2curves/trait.CurveAffineExt.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/constant.BN_X.html b/docs/halo2curves/bn256/constant.BN_X.html new file mode 100644 index 0000000000..9cf5e5deb8 --- /dev/null +++ b/docs/halo2curves/bn256/constant.BN_X.html @@ -0,0 +1 @@ +BN_X in halo2curves::bn256 - Rust
pub const BN_X: u64 = 4965661367192848881;
\ No newline at end of file diff --git a/docs/halo2curves/bn256/constant.FROBENIUS_COEFF_FQ12_C1.html b/docs/halo2curves/bn256/constant.FROBENIUS_COEFF_FQ12_C1.html new file mode 100644 index 0000000000..12abe6af5b --- /dev/null +++ b/docs/halo2curves/bn256/constant.FROBENIUS_COEFF_FQ12_C1.html @@ -0,0 +1 @@ +FROBENIUS_COEFF_FQ12_C1 in halo2curves::bn256 - Rust
pub const FROBENIUS_COEFF_FQ12_C1: [Fq2; 12];
\ No newline at end of file diff --git a/docs/halo2curves/bn256/constant.FROBENIUS_COEFF_FQ2_C1.html b/docs/halo2curves/bn256/constant.FROBENIUS_COEFF_FQ2_C1.html new file mode 100644 index 0000000000..2ff25e730b --- /dev/null +++ b/docs/halo2curves/bn256/constant.FROBENIUS_COEFF_FQ2_C1.html @@ -0,0 +1 @@ +FROBENIUS_COEFF_FQ2_C1 in halo2curves::bn256 - Rust
pub const FROBENIUS_COEFF_FQ2_C1: [Fq; 2];
\ No newline at end of file diff --git a/docs/halo2curves/bn256/constant.FROBENIUS_COEFF_FQ6_C1.html b/docs/halo2curves/bn256/constant.FROBENIUS_COEFF_FQ6_C1.html new file mode 100644 index 0000000000..0a15d4874f --- /dev/null +++ b/docs/halo2curves/bn256/constant.FROBENIUS_COEFF_FQ6_C1.html @@ -0,0 +1 @@ +FROBENIUS_COEFF_FQ6_C1 in halo2curves::bn256 - Rust
pub const FROBENIUS_COEFF_FQ6_C1: [Fq2; 6];
\ No newline at end of file diff --git a/docs/halo2curves/bn256/constant.FROBENIUS_COEFF_FQ6_C2.html b/docs/halo2curves/bn256/constant.FROBENIUS_COEFF_FQ6_C2.html new file mode 100644 index 0000000000..62b0dc5b97 --- /dev/null +++ b/docs/halo2curves/bn256/constant.FROBENIUS_COEFF_FQ6_C2.html @@ -0,0 +1 @@ +FROBENIUS_COEFF_FQ6_C2 in halo2curves::bn256 - Rust
pub const FROBENIUS_COEFF_FQ6_C2: [Fq2; 6];
\ No newline at end of file diff --git a/docs/halo2curves/bn256/constant.NEGATIVE_ONE.html b/docs/halo2curves/bn256/constant.NEGATIVE_ONE.html new file mode 100644 index 0000000000..02b96d936f --- /dev/null +++ b/docs/halo2curves/bn256/constant.NEGATIVE_ONE.html @@ -0,0 +1 @@ +NEGATIVE_ONE in halo2curves::bn256 - Rust
pub const NEGATIVE_ONE: Fq;
\ No newline at end of file diff --git a/docs/halo2curves/bn256/constant.SIX_U_PLUS_2_NAF.html b/docs/halo2curves/bn256/constant.SIX_U_PLUS_2_NAF.html new file mode 100644 index 0000000000..38a375a922 --- /dev/null +++ b/docs/halo2curves/bn256/constant.SIX_U_PLUS_2_NAF.html @@ -0,0 +1 @@ +SIX_U_PLUS_2_NAF in halo2curves::bn256 - Rust
pub const SIX_U_PLUS_2_NAF: [i8; 65];
\ No newline at end of file diff --git a/docs/halo2curves/bn256/constant.XI_TO_Q_MINUS_1_OVER_2.html b/docs/halo2curves/bn256/constant.XI_TO_Q_MINUS_1_OVER_2.html new file mode 100644 index 0000000000..0ead9fcd85 --- /dev/null +++ b/docs/halo2curves/bn256/constant.XI_TO_Q_MINUS_1_OVER_2.html @@ -0,0 +1 @@ +XI_TO_Q_MINUS_1_OVER_2 in halo2curves::bn256 - Rust
pub const XI_TO_Q_MINUS_1_OVER_2: Fq2;
\ No newline at end of file diff --git a/docs/halo2curves/bn256/curve/struct.G1.html b/docs/halo2curves/bn256/curve/struct.G1.html new file mode 100644 index 0000000000..8c0ada5775 --- /dev/null +++ b/docs/halo2curves/bn256/curve/struct.G1.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/struct.G1.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/curve/struct.G1Affine.html b/docs/halo2curves/bn256/curve/struct.G1Affine.html new file mode 100644 index 0000000000..20144c0949 --- /dev/null +++ b/docs/halo2curves/bn256/curve/struct.G1Affine.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/struct.G1Affine.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/curve/struct.G1Compressed.html b/docs/halo2curves/bn256/curve/struct.G1Compressed.html new file mode 100644 index 0000000000..33cf27f41c --- /dev/null +++ b/docs/halo2curves/bn256/curve/struct.G1Compressed.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/struct.G1Compressed.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/curve/struct.G2.html b/docs/halo2curves/bn256/curve/struct.G2.html new file mode 100644 index 0000000000..42cf89067b --- /dev/null +++ b/docs/halo2curves/bn256/curve/struct.G2.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/struct.G2.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/curve/struct.G2Affine.html b/docs/halo2curves/bn256/curve/struct.G2Affine.html new file mode 100644 index 0000000000..32717b4dcb --- /dev/null +++ b/docs/halo2curves/bn256/curve/struct.G2Affine.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/struct.G2Affine.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/curve/struct.G2Compressed.html b/docs/halo2curves/bn256/curve/struct.G2Compressed.html new file mode 100644 index 0000000000..225f83dc86 --- /dev/null +++ b/docs/halo2curves/bn256/curve/struct.G2Compressed.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/struct.G2Compressed.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/engine/constant.BN_X.html b/docs/halo2curves/bn256/engine/constant.BN_X.html new file mode 100644 index 0000000000..dac654e596 --- /dev/null +++ b/docs/halo2curves/bn256/engine/constant.BN_X.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/constant.BN_X.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/engine/constant.SIX_U_PLUS_2_NAF.html b/docs/halo2curves/bn256/engine/constant.SIX_U_PLUS_2_NAF.html new file mode 100644 index 0000000000..163df429e1 --- /dev/null +++ b/docs/halo2curves/bn256/engine/constant.SIX_U_PLUS_2_NAF.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/constant.SIX_U_PLUS_2_NAF.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/engine/constant.XI_TO_Q_MINUS_1_OVER_2.html b/docs/halo2curves/bn256/engine/constant.XI_TO_Q_MINUS_1_OVER_2.html new file mode 100644 index 0000000000..26a18e3283 --- /dev/null +++ b/docs/halo2curves/bn256/engine/constant.XI_TO_Q_MINUS_1_OVER_2.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/constant.XI_TO_Q_MINUS_1_OVER_2.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/engine/fn.multi_miller_loop.html b/docs/halo2curves/bn256/engine/fn.multi_miller_loop.html new file mode 100644 index 0000000000..9937e3f56c --- /dev/null +++ b/docs/halo2curves/bn256/engine/fn.multi_miller_loop.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/fn.multi_miller_loop.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/engine/fn.pairing.html b/docs/halo2curves/bn256/engine/fn.pairing.html new file mode 100644 index 0000000000..7c248bf989 --- /dev/null +++ b/docs/halo2curves/bn256/engine/fn.pairing.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/fn.pairing.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/engine/struct.Bn256.html b/docs/halo2curves/bn256/engine/struct.Bn256.html new file mode 100644 index 0000000000..4ad3dc6d52 --- /dev/null +++ b/docs/halo2curves/bn256/engine/struct.Bn256.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/struct.Bn256.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/engine/struct.G2Prepared.html b/docs/halo2curves/bn256/engine/struct.G2Prepared.html new file mode 100644 index 0000000000..7e0ad53d96 --- /dev/null +++ b/docs/halo2curves/bn256/engine/struct.G2Prepared.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/struct.G2Prepared.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/engine/struct.Gt.html b/docs/halo2curves/bn256/engine/struct.Gt.html new file mode 100644 index 0000000000..c3dd5a465b --- /dev/null +++ b/docs/halo2curves/bn256/engine/struct.Gt.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/struct.Gt.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/enum.LegendreSymbol.html b/docs/halo2curves/bn256/enum.LegendreSymbol.html new file mode 100644 index 0000000000..0092fe64de --- /dev/null +++ b/docs/halo2curves/bn256/enum.LegendreSymbol.html @@ -0,0 +1,27 @@ +LegendreSymbol in halo2curves::bn256 - Rust
pub enum LegendreSymbol {
+    Zero,
+    QuadraticResidue,
+    QuadraticNonResidue,
+}

Variants

Zero

QuadraticResidue

QuadraticNonResidue

Trait Implementations

Formats the value using the given formatter. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/bn256/fn.multi_miller_loop.html b/docs/halo2curves/bn256/fn.multi_miller_loop.html new file mode 100644 index 0000000000..f21c454038 --- /dev/null +++ b/docs/halo2curves/bn256/fn.multi_miller_loop.html @@ -0,0 +1 @@ +multi_miller_loop in halo2curves::bn256 - Rust
pub fn multi_miller_loop(terms: &[(&G1Affine, &G2Prepared)]) -> Gt
\ No newline at end of file diff --git a/docs/halo2curves/bn256/fn.pairing.html b/docs/halo2curves/bn256/fn.pairing.html new file mode 100644 index 0000000000..b8fe1b18bd --- /dev/null +++ b/docs/halo2curves/bn256/fn.pairing.html @@ -0,0 +1 @@ +pairing in halo2curves::bn256 - Rust
pub fn pairing(g1: &G1Affine, g2: &G2Affine) -> Gt
\ No newline at end of file diff --git a/docs/halo2curves/bn256/fq/constant.NEGATIVE_ONE.html b/docs/halo2curves/bn256/fq/constant.NEGATIVE_ONE.html new file mode 100644 index 0000000000..d12549fc10 --- /dev/null +++ b/docs/halo2curves/bn256/fq/constant.NEGATIVE_ONE.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/constant.NEGATIVE_ONE.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/fq/struct.Fq.html b/docs/halo2curves/bn256/fq/struct.Fq.html new file mode 100644 index 0000000000..e9a57d7460 --- /dev/null +++ b/docs/halo2curves/bn256/fq/struct.Fq.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/struct.Fq.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/fq12/constant.FROBENIUS_COEFF_FQ12_C1.html b/docs/halo2curves/bn256/fq12/constant.FROBENIUS_COEFF_FQ12_C1.html new file mode 100644 index 0000000000..3ea4c3529a --- /dev/null +++ b/docs/halo2curves/bn256/fq12/constant.FROBENIUS_COEFF_FQ12_C1.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/constant.FROBENIUS_COEFF_FQ12_C1.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/fq12/struct.Fq12.html b/docs/halo2curves/bn256/fq12/struct.Fq12.html new file mode 100644 index 0000000000..fe55955751 --- /dev/null +++ b/docs/halo2curves/bn256/fq12/struct.Fq12.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/struct.Fq12.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/fq2/constant.FROBENIUS_COEFF_FQ2_C1.html b/docs/halo2curves/bn256/fq2/constant.FROBENIUS_COEFF_FQ2_C1.html new file mode 100644 index 0000000000..3d6109d56a --- /dev/null +++ b/docs/halo2curves/bn256/fq2/constant.FROBENIUS_COEFF_FQ2_C1.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/constant.FROBENIUS_COEFF_FQ2_C1.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/fq2/struct.Fq2.html b/docs/halo2curves/bn256/fq2/struct.Fq2.html new file mode 100644 index 0000000000..36549c4f84 --- /dev/null +++ b/docs/halo2curves/bn256/fq2/struct.Fq2.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/struct.Fq2.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/fq2/struct.Fq2Bytes.html b/docs/halo2curves/bn256/fq2/struct.Fq2Bytes.html new file mode 100644 index 0000000000..e6d0b5b83b --- /dev/null +++ b/docs/halo2curves/bn256/fq2/struct.Fq2Bytes.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/struct.Fq2Bytes.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/fq6/constant.FROBENIUS_COEFF_FQ6_C1.html b/docs/halo2curves/bn256/fq6/constant.FROBENIUS_COEFF_FQ6_C1.html new file mode 100644 index 0000000000..94b66c1190 --- /dev/null +++ b/docs/halo2curves/bn256/fq6/constant.FROBENIUS_COEFF_FQ6_C1.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/constant.FROBENIUS_COEFF_FQ6_C1.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/fq6/constant.FROBENIUS_COEFF_FQ6_C2.html b/docs/halo2curves/bn256/fq6/constant.FROBENIUS_COEFF_FQ6_C2.html new file mode 100644 index 0000000000..e51cb686bd --- /dev/null +++ b/docs/halo2curves/bn256/fq6/constant.FROBENIUS_COEFF_FQ6_C2.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/constant.FROBENIUS_COEFF_FQ6_C2.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/fq6/struct.Fq6.html b/docs/halo2curves/bn256/fq6/struct.Fq6.html new file mode 100644 index 0000000000..fb208ff745 --- /dev/null +++ b/docs/halo2curves/bn256/fq6/struct.Fq6.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/struct.Fq6.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/fr/struct.Fr.html b/docs/halo2curves/bn256/fr/struct.Fr.html new file mode 100644 index 0000000000..666515f206 --- /dev/null +++ b/docs/halo2curves/bn256/fr/struct.Fr.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/bn256/struct.Fr.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/bn256/index.html b/docs/halo2curves/bn256/index.html new file mode 100644 index 0000000000..cba951649c --- /dev/null +++ b/docs/halo2curves/bn256/index.html @@ -0,0 +1 @@ +halo2curves::bn256 - Rust
\ No newline at end of file diff --git a/docs/halo2curves/bn256/sidebar-items.js b/docs/halo2curves/bn256/sidebar-items.js new file mode 100644 index 0000000000..58d67f5c08 --- /dev/null +++ b/docs/halo2curves/bn256/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"constant":[["BN_X",""],["FROBENIUS_COEFF_FQ12_C1",""],["FROBENIUS_COEFF_FQ2_C1",""],["FROBENIUS_COEFF_FQ6_C1",""],["FROBENIUS_COEFF_FQ6_C2",""],["NEGATIVE_ONE",""],["SIX_U_PLUS_2_NAF",""],["XI_TO_Q_MINUS_1_OVER_2",""]],"enum":[["LegendreSymbol",""]],"fn":[["multi_miller_loop",""],["pairing",""]],"struct":[["Bn256",""],["Fq","This represents an element of $\\mathbb{F}_q$ where"],["Fq12",""],["Fq2","An element of Fq2, represented by c0 + c1 * u."],["Fq2Bytes",""],["Fq6",""],["Fr","This represents an element of $\\mathbb{F}_r$ where"],["G1",""],["G1Affine",""],["G1Compressed",""],["G2",""],["G2Affine",""],["G2Compressed",""],["G2Prepared",""],["Gt",""]]}; \ No newline at end of file diff --git a/docs/halo2curves/bn256/struct.Bn256.html b/docs/halo2curves/bn256/struct.Bn256.html new file mode 100644 index 0000000000..74899bef6f --- /dev/null +++ b/docs/halo2curves/bn256/struct.Bn256.html @@ -0,0 +1,23 @@ +Bn256 in halo2curves::bn256 - Rust
pub struct Bn256;

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
This is the scalar field of the engine’s groups.
The projective representation of an element in G1.
The affine representation of an element in G1.
The projective representation of an element in G2.
The affine representation of an element in G2.
The extension field that hosts the target group of the pairing.
Invoke the pairing function G1 x G2 -> Gt without the use of precomputation and +other optimizations. Read more
The prepared form of Self::G2Affine.
The type returned by Engine::miller_loop.
Computes $$\sum_{i=1}^n \textbf{ML}(a_i, b_i)$$ given a series of terms +$$(a_1, b_1), (a_2, b_2), …, (a_n, b_n).$$ Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/bn256/struct.Fq.html b/docs/halo2curves/bn256/struct.Fq.html new file mode 100644 index 0000000000..47ad12650d --- /dev/null +++ b/docs/halo2curves/bn256/struct.Fq.html @@ -0,0 +1,70 @@ +Fq in halo2curves::bn256 - Rust
pub struct Fq(_);
Expand description

This represents an element of $\mathbb{F}_q$ where

+

p = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47

+

is the base field of the BN254 curve.

+

Implementations

Returns zero, the additive identity.

+

Returns one, the multiplicative identity.

+

Converts from an integer represented in little endian +into its (congruent) $field representation.

+

Attempts to convert a little-endian byte representation of +a scalar into a Fr, failing if the input is not canonical.

+

Converts an element of Fr into a byte representation in +little-endian byte order.

+

Adds rhs to self, returning the result.

+

Multiplies rhs by self, returning the result.

+

Doubles this field element.

+

Squares this element.

+

Subtracts rhs from self, returning the result.

+

Negates self.

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Deserialize this value from the given Serde deserializer. Read more

Computes the square root of this element, if it exists.

+

Computes the multiplicative inverse of this element, +failing if the element is zero.

+
Returns an element chosen uniformly at random using a user-provided RNG.
Returns the zero element of the field, the additive identity.
Returns the one element of the field, the multiplicative identity.
Doubles this element.
Squares this element.
Returns true iff this element is zero.
Returns true iff this element is zero. Read more
Cubes this element.
Exponentiates self by exp, where exp is a little-endian order +integer exponent. Read more

Converts a 512-bit little endian integer into +a $field by reducing by the modulus.

+
Modulus of the field written as a string for display purposes
Inverse of $2$ in the field.
Inverse of PrimeField::root_of_unity()
Generator of the $t-order$ multiplicative subgroup
Element of multiplicative order $3$.
Obtains a field element congruent to the integer v.
Gets the lower 128 bits of this field element when expressed +canonically. Read more
Exponentiates self by by, where by is a little-endian order +integer exponent. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
The group is assumed to be of prime order $p$. Scalar is the +associated scalar field of size $p$. Read more
Returns the additive identity of the group.
Adds rhs to this group element.
Subtracts rhs from this group element.
Scales this group element by a scalar.
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method returns an Ordering between self and other. Read more
Compares and returns the maximum of two values. Read more
Compares and returns the minimum of two values. Read more
Restrict a value to a certain interval. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
This method returns an ordering between self and other values if one exists. Read more
This method tests less than (for self and other) and is used by the < operator. Read more
This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
This method tests greater than (for self and other) and is used by the > operator. Read more
This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
The prime field can be converted back and forth into this binary +representation. Read more
How many bits are needed to represent an element of this field.
How many bits of information can be reliably stored in the field element. Read more
An integer s satisfying the equation 2^s * t = modulus - 1 with t odd. Read more
Attempts to convert a byte representation of a field element into an element of +this prime field, failing if the input is not canonical (is not smaller than the +field’s modulus). Read more
Converts an element of the prime field into the standard byte representation for +this field. Read more
Returns true iff this element is odd.
Returns a fixed multiplicative generator of modulus - 1 order. This element must +also be a quadratic nonresidue. Read more
Returns the 2^s root of unity. Read more
Interpret a string of numbers as a (congruent) prime field element. +Does not accept unnecessary leading zeroes or a blank string. Read more
Attempts to convert a byte representation of a field element into an element of +this prime field, failing if the input is not canonical (is not smaller than the +field’s modulus). Read more
Returns true iff this element is even.
The purpose of unchecked functions is to read the internal memory representation +of a type from bytes as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. As such this function should only be +used internally as an extension of machine memory. It should not be used to deserialize +externally provided data. Read more
The purpose of unchecked functions is to read the internal memory representation +of a type from disk as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. This function should only be used +internally when some machine state cannot be kept in memory (e.g., between runs) +and needs to be reloaded as quickly as possible. Read more
Serialize this value into the given Serde serializer. Read more
The value $(T-1)/2$ such that $2^S \cdot T = p - 1$ with $T$ odd.
Gets the lower 32 bits of this field element when expressed +canonically. Read more
Raise this field element to the power [Self::T_MINUS1_OVER2]. Read more
Computes: Read more
Equivalent to Self::sqrt_ratio(self, one()).
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/bn256/struct.Fq12.html b/docs/halo2curves/bn256/struct.Fq12.html new file mode 100644 index 0000000000..99156da734 --- /dev/null +++ b/docs/halo2curves/bn256/struct.Fq12.html @@ -0,0 +1,31 @@ +Fq12 in halo2curves::bn256 - Rust
pub struct Fq12 {
+    pub c0: Fq6,
+    pub c1: Fq6,
+}

Fields

c0: Fq6c1: Fq6

Implementations

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Deserialize this value from the given Serde deserializer. Read more
Returns an element chosen uniformly at random using a user-provided RNG.
Returns the zero element of the field, the additive identity.
Returns the one element of the field, the multiplicative identity.
Returns true iff this element is zero.
Squares this element.
Doubles this element.
Returns the square root of the field element, if it is +quadratic residue. Read more
Computes the multiplicative inverse of this element, +failing if the element is zero. Read more
Returns true iff this element is zero. Read more
Cubes this element.
Exponentiates self by exp, where exp is a little-endian order +integer exponent. Read more
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
Serialize this value into the given Serde serializer. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/bn256/struct.Fq2.html b/docs/halo2curves/bn256/struct.Fq2.html new file mode 100644 index 0000000000..664daf0c65 --- /dev/null +++ b/docs/halo2curves/bn256/struct.Fq2.html @@ -0,0 +1,63 @@ +Fq2 in halo2curves::bn256 - Rust
pub struct Fq2 {
+    pub c0: Fq,
+    pub c1: Fq,
+}
Expand description

An element of Fq2, represented by c0 + c1 * u.

+

Fields

c0: Fqc1: Fq

Implementations

Attempts to convert a little-endian byte representation of +a scalar into a Fq, failing if the input is not canonical.

+

Converts an element of Fq into a byte representation in +little-endian byte order.

+

Multiply this element by quadratic nonresidue 9 + u.

+

Norm of Fq2 as extension field in i over Fq

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Deserialize this value from the given Serde deserializer. Read more
Returns an element chosen uniformly at random using a user-provided RNG.
Returns the zero element of the field, the additive identity.
Returns the one element of the field, the multiplicative identity.
Returns true iff this element is zero.
Squares this element.
Doubles this element.
Returns the square root of the field element, if it is +quadratic residue. Read more
Computes the multiplicative inverse of this element, +failing if the element is zero. Read more
Returns true iff this element is zero. Read more
Cubes this element.
Exponentiates self by exp, where exp is a little-endian order +integer exponent. Read more

Converts a 512-bit little endian integer into +a Fq by reducing by the modulus.

+
Modulus of the field written as a string for display purposes
Inverse of PrimeField::root_of_unity()
Generator of the $t-order$ multiplicative subgroup
Inverse of $2$ in the field.
Element of multiplicative order $3$.
Obtains a field element congruent to the integer v.
Gets the lower 128 bits of this field element when expressed +canonically. Read more
Exponentiates self by by, where by is a little-endian order +integer exponent. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
The group is assumed to be of prime order $p$. Scalar is the +associated scalar field of size $p$. Read more
Returns the additive identity of the group.
Adds rhs to this group element.
Subtracts rhs from this group element.
Scales this group element by a scalar.
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more

Fq2 elements are ordered lexicographically.

+
This method returns an Ordering between self and other. Read more
Compares and returns the maximum of two values. Read more
Compares and returns the minimum of two values. Read more
Restrict a value to a certain interval. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
This method returns an ordering between self and other values if one exists. Read more
This method tests less than (for self and other) and is used by the < operator. Read more
This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
This method tests greater than (for self and other) and is used by the > operator. Read more
This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
The prime field can be converted back and forth into this binary +representation. Read more
How many bits are needed to represent an element of this field.
How many bits of information can be reliably stored in the field element. Read more
An integer s satisfying the equation 2^s * t = modulus - 1 with t odd. Read more
Attempts to convert a byte representation of a field element into an element of +this prime field, failing if the input is not canonical (is not smaller than the +field’s modulus). Read more
Converts an element of the prime field into the standard byte representation for +this field. Read more
Returns true iff this element is odd.
Returns a fixed multiplicative generator of modulus - 1 order. This element must +also be a quadratic nonresidue. Read more
Returns the 2^s root of unity. Read more
Interpret a string of numbers as a (congruent) prime field element. +Does not accept unnecessary leading zeroes or a blank string. Read more
Attempts to convert a byte representation of a field element into an element of +this prime field, failing if the input is not canonical (is not smaller than the +field’s modulus). Read more
Returns true iff this element is even.
The purpose of unchecked functions is to read the internal memory representation +of a type from bytes as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. As such this function should only be +used internally as an extension of machine memory. It should not be used to deserialize +externally provided data. Read more
The purpose of unchecked functions is to read the internal memory representation +of a type from disk as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. This function should only be used +internally when some machine state cannot be kept in memory (e.g., between runs) +and needs to be reloaded as quickly as possible. Read more
Serialize this value into the given Serde serializer. Read more
The value $(T-1)/2$ such that $2^S \cdot T = p - 1$ with $T$ odd.
Raise this field element to the power [Self::T_MINUS1_OVER2]. Read more
Gets the lower 32 bits of this field element when expressed +canonically. Read more
Computes: Read more
Equivalent to Self::sqrt_ratio(self, one()).
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/bn256/struct.Fq2Bytes.html b/docs/halo2curves/bn256/struct.Fq2Bytes.html new file mode 100644 index 0000000000..9455557247 --- /dev/null +++ b/docs/halo2curves/bn256/struct.Fq2Bytes.html @@ -0,0 +1,23 @@ +Fq2Bytes in halo2curves::bn256 - Rust
pub struct Fq2Bytes(_);

Trait Implementations

Converts this type into a mutable reference of the (usually inferred) input type.
Converts this type into a shared reference of the (usually inferred) input type.
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Views self as an immutable bit-slice region with the O ordering.
Attempts to view self as an immutable bit-slice region with the O +ordering. Read more
Views self as a mutable bit-slice region with the O ordering.
Attempts to view self as a mutable bit-slice region with the O +ordering. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/bn256/struct.Fq6.html b/docs/halo2curves/bn256/struct.Fq6.html new file mode 100644 index 0000000000..979024a9be --- /dev/null +++ b/docs/halo2curves/bn256/struct.Fq6.html @@ -0,0 +1,34 @@ +Fq6 in halo2curves::bn256 - Rust
pub struct Fq6 {
+    pub c0: Fq2,
+    pub c1: Fq2,
+    pub c2: Fq2,
+}

Fields

c0: Fq2c1: Fq2c2: Fq2

Implementations

Multiply by cubic nonresidue v.

+

Multiply by cubic nonresidue v.

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Deserialize this value from the given Serde deserializer. Read more
Returns an element chosen uniformly at random using a user-provided RNG.
Returns the zero element of the field, the additive identity.
Returns the one element of the field, the multiplicative identity.
Returns true iff this element is zero.
Squares this element.
Doubles this element.
Returns the square root of the field element, if it is +quadratic residue. Read more
Computes the multiplicative inverse of this element, +failing if the element is zero. Read more
Returns true iff this element is zero. Read more
Cubes this element.
Exponentiates self by exp, where exp is a little-endian order +integer exponent. Read more
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
Serialize this value into the given Serde serializer. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/bn256/struct.Fr.html b/docs/halo2curves/bn256/struct.Fr.html new file mode 100644 index 0000000000..4633a27e6e --- /dev/null +++ b/docs/halo2curves/bn256/struct.Fr.html @@ -0,0 +1,71 @@ +Fr in halo2curves::bn256 - Rust
pub struct Fr(_);
Expand description

This represents an element of $\mathbb{F}_r$ where

+

r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001

+

is the scalar field of the BN254 curve.

+

Implementations

Returns zero, the additive identity.

+

Returns one, the multiplicative identity.

+

Converts from an integer represented in little endian +into its (congruent) $field representation.

+

Attempts to convert a little-endian byte representation of +a scalar into a Fr, failing if the input is not canonical.

+

Converts an element of Fr into a byte representation in +little-endian byte order.

+

Adds rhs to self, returning the result.

+

Multiplies rhs by self, returning the result.

+

Doubles this field element.

+

Squares this element.

+

Subtracts rhs from self, returning the result.

+

Negates self.

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Deserialize this value from the given Serde deserializer. Read more

Computes the square root of this element, if it exists.

+

Computes the multiplicative inverse of this element, +failing if the element is zero.

+
Returns an element chosen uniformly at random using a user-provided RNG.
Returns the zero element of the field, the additive identity.
Returns the one element of the field, the multiplicative identity.
Doubles this element.
Returns true iff this element is zero. Read more
Squares this element.
Returns true iff this element is zero.
Cubes this element.
Exponentiates self by exp, where exp is a little-endian order +integer exponent. Read more

Converts a 512-bit little endian integer into +a $field by reducing by the modulus.

+
Modulus of the field written as a string for display purposes
Inverse of $2$ in the field.
Inverse of PrimeField::root_of_unity()
Generator of the $t-order$ multiplicative subgroup
Element of multiplicative order $3$.
Obtains a field element congruent to the integer v.
Gets the lower 128 bits of this field element when expressed +canonically. Read more
Exponentiates self by by, where by is a little-endian order +integer exponent. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
The group is assumed to be of prime order $p$. Scalar is the +associated scalar field of size $p$. Read more
Returns the additive identity of the group.
Adds rhs to this group element.
Subtracts rhs from this group element.
Scales this group element by a scalar.
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method returns an Ordering between self and other. Read more
Compares and returns the maximum of two values. Read more
Compares and returns the minimum of two values. Read more
Restrict a value to a certain interval. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
This method returns an ordering between self and other values if one exists. Read more
This method tests less than (for self and other) and is used by the < operator. Read more
This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
This method tests greater than (for self and other) and is used by the > operator. Read more
This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
The prime field can be converted back and forth into this binary +representation. Read more
How many bits are needed to represent an element of this field.
How many bits of information can be reliably stored in the field element. Read more
An integer s satisfying the equation 2^s * t = modulus - 1 with t odd. Read more
Attempts to convert a byte representation of a field element into an element of +this prime field, failing if the input is not canonical (is not smaller than the +field’s modulus). Read more
Converts an element of the prime field into the standard byte representation for +this field. Read more
Returns true iff this element is odd.
Returns a fixed multiplicative generator of modulus - 1 order. This element must +also be a quadratic nonresidue. Read more
Returns the 2^s root of unity. Read more
Interpret a string of numbers as a (congruent) prime field element. +Does not accept unnecessary leading zeroes or a blank string. Read more
Attempts to convert a byte representation of a field element into an element of +this prime field, failing if the input is not canonical (is not smaller than the +field’s modulus). Read more
Returns true iff this element is even.
The purpose of unchecked functions is to read the internal memory representation +of a type from bytes as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. As such this function should only be +used internally as an extension of machine memory. It should not be used to deserialize +externally provided data. Read more
The purpose of unchecked functions is to read the internal memory representation +of a type from disk as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. This function should only be used +internally when some machine state cannot be kept in memory (e.g., between runs) +and needs to be reloaded as quickly as possible. Read more
Serialize this value into the given Serde serializer. Read more

(t - 1) // 2 where t * 2^s + 1 = p with t odd.

+
Gets the lower 32 bits of this field element when expressed +canonically. Read more
Raise this field element to the power [Self::T_MINUS1_OVER2]. Read more
Computes: Read more
Equivalent to Self::sqrt_ratio(self, one()).
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/bn256/struct.G1.html b/docs/halo2curves/bn256/struct.G1.html new file mode 100644 index 0000000000..a58cbb898c --- /dev/null +++ b/docs/halo2curves/bn256/struct.G1.html @@ -0,0 +1,49 @@ +G1 in halo2curves::bn256 - Rust
pub struct G1 {
+    pub x: Fq,
+    pub y: Fq,
+    pub z: Fq,
+}

Fields

x: Fqy: Fqz: Fq

Implementations

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
The large prime-order subgroup in which cryptographic operations are performed. +If Self implements PrimeGroup, then Self::Subgroup may be Self. Read more
Maps self to the prime-order subgroup by multiplying this element by some +k-multiple of the cofactor. Read more
Returns self if it is contained in the prime-order subgroup. Read more
Determines if this element is “torsion free”, i.e., is contained in the +prime-order subgroup. Read more
Determines if this element is of small order. Read more
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
The affine representation for this elliptic curve.
Converts a batch of projective elements into affine elements. This function will +panic if p.len() != q.len(). Read more
Converts this element into its affine representation.
The scalar field of this elliptic curve.
The base field over which this elliptic curve is constructed.
The affine version of the curve
CURVE_ID used for hash-to-curve.
Apply the curve endomorphism by multiplying the x-coordinate +by an element of multiplicative order 3. Read more
Return the Jacobian coordinates of this point.
Requests a hasher that accepts messages and returns near-uniformly +distributed elements in the group, given domain prefix domain_prefix. Read more
Returns whether or not this element is on the curve; should +always be true unless an “unchecked” API was used. Read more
Returns the curve constant b.
Returns the curve constant a.
Obtains a point given Jacobian coordinates $X : Y : Z$, failing +if the coordinates are not on the curve. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Deserialize this value from the given Serde deserializer. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Scalars modulo the order of this group’s scalar field.
Returns an element chosen uniformly at random from the non-identity elements of +this group. Read more
Doubles this element.
Returns a fixed generator of the prime-order subgroup.
Returns the additive identity, also known as the “neutral element”.
Determines if this point is the identity.
The group is assumed to be of prime order $p$. Scalar is the +associated scalar field of size $p$. Read more
Returns the additive identity of the group.
Adds rhs to this group element.
Subtracts rhs from this group element.
Scales this group element by a scalar.
The encoding of group elements. Read more
Attempts to deserialize a group element from its encoding.
Attempts to deserialize a group element, not checking if the element is valid. Read more
Converts this element into its byte encoding. This may or may not support +encoding the identity. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
The purpose of unchecked functions is to read the internal memory representation +of a type from bytes as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. As such this function should only be +used internally as an extension of machine memory. It should not be used to deserialize +externally provided data. Read more
The purpose of unchecked functions is to read the internal memory representation +of a type from disk as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. This function should only be used +internally when some machine state cannot be kept in memory (e.g., between runs) +and needs to be reloaded as quickly as possible. Read more
Serialize this value into the given Serde serializer. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Method which takes an iterator and generates Self from the elements by +“summing up” the items. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/bn256/struct.G1Affine.html b/docs/halo2curves/bn256/struct.G1Affine.html new file mode 100644 index 0000000000..93007fe86a --- /dev/null +++ b/docs/halo2curves/bn256/struct.G1Affine.html @@ -0,0 +1,43 @@ +G1Affine in halo2curves::bn256 - Rust
pub struct G1Affine {
+    pub x: Fq,
+    pub y: Fq,
+}

Fields

x: Fqy: Fq

Implementations

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Returns the additive identity.
Returns a fixed generator of unknown exponent.
Determines if this point represents the point at infinity; the +additive identity. Read more
Converts this element to its curve representation.
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
The scalar field of this elliptic curve.
The base field over which this elliptic curve is constructed.
The projective form of the curve
Returns whether or not this element is on the curve; should +always be true unless an “unchecked” API was used. Read more
Gets the coordinates of this point. Read more
Obtains a point given $(x, y)$, failing if it is not on the +curve. Read more
Returns the curve constant $a$.
Returns the curve constant $b$.
Unlike the Coordinates trait, this just returns the raw affine coordinates without checking is_on_curve
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Deserialize this value from the given Serde deserializer. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
The encoding of group elements. Read more
Attempts to deserialize a group element from its encoding.
Attempts to deserialize a group element, not checking if the element is valid. Read more
Converts this element into its byte encoding. This may or may not support +encoding the identity. Read more
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
Perform a pairing
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
Returns a fixed generator of unknown exponent.
Returns the additive identity.
Determines if this point represents the point at infinity; the +additive identity. Read more
Converts this element to its curve representation.
The purpose of unchecked functions is to read the internal memory representation +of a type from bytes as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. As such this function should only be +used internally as an extension of machine memory. It should not be used to deserialize +externally provided data. Read more
The purpose of unchecked functions is to read the internal memory representation +of a type from disk as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. This function should only be used +internally when some machine state cannot be kept in memory (e.g., between runs) +and needs to be reloaded as quickly as possible. Read more
Serialize this value into the given Serde serializer. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Attempts to deserialize an element from its uncompressed encoding.
Attempts to deserialize an uncompressed element, not checking if the element is in +the correct subgroup. Read more
Converts this element into its uncompressed encoding, so long as it’s not +the point at infinity. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/bn256/struct.G1Compressed.html b/docs/halo2curves/bn256/struct.G1Compressed.html new file mode 100644 index 0000000000..66c3291bdd --- /dev/null +++ b/docs/halo2curves/bn256/struct.G1Compressed.html @@ -0,0 +1,23 @@ +G1Compressed in halo2curves::bn256 - Rust
pub struct G1Compressed(_);

Trait Implementations

Converts this type into a mutable reference of the (usually inferred) input type.
Converts this type into a shared reference of the (usually inferred) input type.
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Views self as an immutable bit-slice region with the O ordering.
Attempts to view self as an immutable bit-slice region with the O +ordering. Read more
Views self as a mutable bit-slice region with the O ordering.
Attempts to view self as a mutable bit-slice region with the O +ordering. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/bn256/struct.G2.html b/docs/halo2curves/bn256/struct.G2.html new file mode 100644 index 0000000000..39c62b4a85 --- /dev/null +++ b/docs/halo2curves/bn256/struct.G2.html @@ -0,0 +1,49 @@ +G2 in halo2curves::bn256 - Rust
pub struct G2 {
+    pub x: Fq2,
+    pub y: Fq2,
+    pub z: Fq2,
+}

Fields

x: Fq2y: Fq2z: Fq2

Implementations

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
The large prime-order subgroup in which cryptographic operations are performed. +If Self implements PrimeGroup, then Self::Subgroup may be Self. Read more
Maps self to the prime-order subgroup by multiplying this element by some +k-multiple of the cofactor. Read more
Returns self if it is contained in the prime-order subgroup. Read more
Determines if this element is “torsion free”, i.e., is contained in the +prime-order subgroup. Read more
Determines if this element is of small order. Read more
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
The affine representation for this elliptic curve.
Converts a batch of projective elements into affine elements. This function will +panic if p.len() != q.len(). Read more
Converts this element into its affine representation.
The scalar field of this elliptic curve.
The base field over which this elliptic curve is constructed.
The affine version of the curve
CURVE_ID used for hash-to-curve.
Apply the curve endomorphism by multiplying the x-coordinate +by an element of multiplicative order 3. Read more
Return the Jacobian coordinates of this point.
Requests a hasher that accepts messages and returns near-uniformly +distributed elements in the group, given domain prefix domain_prefix. Read more
Returns whether or not this element is on the curve; should +always be true unless an “unchecked” API was used. Read more
Returns the curve constant b.
Returns the curve constant a.
Obtains a point given Jacobian coordinates $X : Y : Z$, failing +if the coordinates are not on the curve. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Deserialize this value from the given Serde deserializer. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Scalars modulo the order of this group’s scalar field.
Returns an element chosen uniformly at random from the non-identity elements of +this group. Read more
Doubles this element.
Returns a fixed generator of the prime-order subgroup.
Returns the additive identity, also known as the “neutral element”.
Determines if this point is the identity.
The group is assumed to be of prime order $p$. Scalar is the +associated scalar field of size $p$. Read more
Returns the additive identity of the group.
Adds rhs to this group element.
Subtracts rhs from this group element.
Scales this group element by a scalar.
The encoding of group elements. Read more
Attempts to deserialize a group element from its encoding.
Attempts to deserialize a group element, not checking if the element is valid. Read more
Converts this element into its byte encoding. This may or may not support +encoding the identity. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
The purpose of unchecked functions is to read the internal memory representation +of a type from bytes as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. As such this function should only be +used internally as an extension of machine memory. It should not be used to deserialize +externally provided data. Read more
The purpose of unchecked functions is to read the internal memory representation +of a type from disk as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. This function should only be used +internally when some machine state cannot be kept in memory (e.g., between runs) +and needs to be reloaded as quickly as possible. Read more
Serialize this value into the given Serde serializer. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Method which takes an iterator and generates Self from the elements by +“summing up” the items. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/bn256/struct.G2Affine.html b/docs/halo2curves/bn256/struct.G2Affine.html new file mode 100644 index 0000000000..bd660226e2 --- /dev/null +++ b/docs/halo2curves/bn256/struct.G2Affine.html @@ -0,0 +1,43 @@ +G2Affine in halo2curves::bn256 - Rust
pub struct G2Affine {
+    pub x: Fq2,
+    pub y: Fq2,
+}

Fields

x: Fq2y: Fq2

Implementations

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Returns the additive identity.
Returns a fixed generator of unknown exponent.
Determines if this point represents the point at infinity; the +additive identity. Read more
Converts this element to its curve representation.
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
The scalar field of this elliptic curve.
The base field over which this elliptic curve is constructed.
The projective form of the curve
Returns whether or not this element is on the curve; should +always be true unless an “unchecked” API was used. Read more
Gets the coordinates of this point. Read more
Obtains a point given $(x, y)$, failing if it is not on the +curve. Read more
Returns the curve constant $a$.
Returns the curve constant $b$.
Unlike the Coordinates trait, this just returns the raw affine coordinates without checking is_on_curve
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Deserialize this value from the given Serde deserializer. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
The encoding of group elements. Read more
Attempts to deserialize a group element from its encoding.
Attempts to deserialize a group element, not checking if the element is valid. Read more
Converts this element into its byte encoding. This may or may not support +encoding the identity. Read more
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
Perform a pairing
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
Returns a fixed generator of unknown exponent.
Returns the additive identity.
Determines if this point represents the point at infinity; the +additive identity. Read more
Converts this element to its curve representation.
The purpose of unchecked functions is to read the internal memory representation +of a type from bytes as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. As such this function should only be +used internally as an extension of machine memory. It should not be used to deserialize +externally provided data. Read more
The purpose of unchecked functions is to read the internal memory representation +of a type from disk as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. This function should only be used +internally when some machine state cannot be kept in memory (e.g., between runs) +and needs to be reloaded as quickly as possible. Read more
Serialize this value into the given Serde serializer. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Attempts to deserialize an element from its uncompressed encoding.
Attempts to deserialize an uncompressed element, not checking if the element is in +the correct subgroup. Read more
Converts this element into its uncompressed encoding, so long as it’s not +the point at infinity. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/bn256/struct.G2Compressed.html b/docs/halo2curves/bn256/struct.G2Compressed.html new file mode 100644 index 0000000000..fcda01a97a --- /dev/null +++ b/docs/halo2curves/bn256/struct.G2Compressed.html @@ -0,0 +1,23 @@ +G2Compressed in halo2curves::bn256 - Rust
pub struct G2Compressed(_);

Trait Implementations

Converts this type into a mutable reference of the (usually inferred) input type.
Converts this type into a shared reference of the (usually inferred) input type.
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Views self as an immutable bit-slice region with the O ordering.
Attempts to view self as an immutable bit-slice region with the O +ordering. Read more
Views self as a mutable bit-slice region with the O ordering.
Attempts to view self as a mutable bit-slice region with the O +ordering. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/bn256/struct.G2Prepared.html b/docs/halo2curves/bn256/struct.G2Prepared.html new file mode 100644 index 0000000000..38df730acf --- /dev/null +++ b/docs/halo2curves/bn256/struct.G2Prepared.html @@ -0,0 +1,21 @@ +G2Prepared in halo2curves::bn256 - Rust
pub struct G2Prepared { /* private fields */ }

Implementations

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Converts to this type from the input type.

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/bn256/struct.Gt.html b/docs/halo2curves/bn256/struct.Gt.html new file mode 100644 index 0000000000..b34e8b4a16 --- /dev/null +++ b/docs/halo2curves/bn256/struct.Gt.html @@ -0,0 +1,31 @@ +Gt in halo2curves::bn256 - Rust
pub struct Gt(_);

Implementations

Returns the group identity, which is $1$.

+

Doubles this group element.

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Formats the value using the given formatter. Read more
Scalars modulo the order of this group’s scalar field.
Returns an element chosen uniformly at random from the non-identity elements of +this group. Read more
Returns the additive identity, also known as the “neutral element”.
Returns a fixed generator of the prime-order subgroup.
Determines if this point is the identity.
Doubles this element.
The extension field that hosts the target group of the pairing.
This performs a “final exponentiation” routine to convert the result of a Miller +loop into an element of MillerLoopResult::Gt, so that it can be compared with +other elements of Gt. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Method which takes an iterator and generates Self from the elements by +“summing up” the items. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Converts the given value to a String. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/index.html b/docs/halo2curves/index.html new file mode 100644 index 0000000000..ef22e7292f --- /dev/null +++ b/docs/halo2curves/index.html @@ -0,0 +1,7 @@ +halo2curves - Rust

Re-exports

pub extern crate group;

Modules

Macros

Structs

The affine coordinates of a point on an elliptic curve.

Traits

This trait is the affine counterpart to Curve and is used for +serialization, storage in memory, and inspection of $x$ and $y$ coordinates.
This trait is a common interface for dealing with elements of an elliptic +curve group in a “projective” form, where that arithmetic is usually more +efficient.
This trait is a common interface for dealing with elements of a finite +field.
This represents an element of a group with basic operations that can be +performed. This allows an FFT implementation (for example) to operate +generically over either a field or elliptic curve group.
\ No newline at end of file diff --git a/docs/halo2curves/macro.batch_add!.html b/docs/halo2curves/macro.batch_add!.html new file mode 100644 index 0000000000..c7f7541ef7 --- /dev/null +++ b/docs/halo2curves/macro.batch_add!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.batch_add.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/macro.batch_add.html b/docs/halo2curves/macro.batch_add.html new file mode 100644 index 0000000000..39190967cc --- /dev/null +++ b/docs/halo2curves/macro.batch_add.html @@ -0,0 +1,4 @@ +batch_add in halo2curves - Rust
macro_rules! batch_add {
+    () => { ... };
+}
+
\ No newline at end of file diff --git a/docs/halo2curves/macro.field_arithmetic!.html b/docs/halo2curves/macro.field_arithmetic!.html new file mode 100644 index 0000000000..6a53b4f885 --- /dev/null +++ b/docs/halo2curves/macro.field_arithmetic!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.field_arithmetic.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/macro.field_arithmetic.html b/docs/halo2curves/macro.field_arithmetic.html new file mode 100644 index 0000000000..2bc4985718 --- /dev/null +++ b/docs/halo2curves/macro.field_arithmetic.html @@ -0,0 +1,4 @@ +field_arithmetic in halo2curves - Rust
macro_rules! field_arithmetic {
+    ($field:ident, $modulus:ident, $inv:ident, $field_type:ident) => { ... };
+}
+
\ No newline at end of file diff --git a/docs/halo2curves/macro.field_common!.html b/docs/halo2curves/macro.field_common!.html new file mode 100644 index 0000000000..f308f95915 --- /dev/null +++ b/docs/halo2curves/macro.field_common!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.field_common.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/macro.field_common.html b/docs/halo2curves/macro.field_common.html new file mode 100644 index 0000000000..45ec55be2a --- /dev/null +++ b/docs/halo2curves/macro.field_common.html @@ -0,0 +1,16 @@ +field_common in halo2curves - Rust
macro_rules! field_common {
+    (
+        $field:ident,
+        $modulus:ident,
+        $inv:ident,
+        $modulus_str:ident,
+        $two_inv:ident,
+        $root_of_unity_inv:ident,
+        $delta:ident,
+        $zeta:ident,
+        $r:ident,
+        $r2:ident,
+        $r3:ident
+    ) => { ... };
+}
+
\ No newline at end of file diff --git a/docs/halo2curves/macro.field_specific!.html b/docs/halo2curves/macro.field_specific!.html new file mode 100644 index 0000000000..5452e3290c --- /dev/null +++ b/docs/halo2curves/macro.field_specific!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.field_specific.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/macro.field_specific.html b/docs/halo2curves/macro.field_specific.html new file mode 100644 index 0000000000..96e843361e --- /dev/null +++ b/docs/halo2curves/macro.field_specific.html @@ -0,0 +1,5 @@ +field_specific in halo2curves - Rust
macro_rules! field_specific {
+    ($field:ident, $modulus:ident, $inv:ident, sparse) => { ... };
+    ($field:ident, $modulus:ident, $inv:ident, dense) => { ... };
+}
+
\ No newline at end of file diff --git a/docs/halo2curves/macro.impl_add_binop_specify_output!.html b/docs/halo2curves/macro.impl_add_binop_specify_output!.html new file mode 100644 index 0000000000..ac606d4f32 --- /dev/null +++ b/docs/halo2curves/macro.impl_add_binop_specify_output!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.impl_add_binop_specify_output.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/macro.impl_add_binop_specify_output.html b/docs/halo2curves/macro.impl_add_binop_specify_output.html new file mode 100644 index 0000000000..a5699d6a0b --- /dev/null +++ b/docs/halo2curves/macro.impl_add_binop_specify_output.html @@ -0,0 +1,4 @@ +impl_add_binop_specify_output in halo2curves - Rust
macro_rules! impl_add_binop_specify_output {
+    ($lhs:ident, $rhs:ident, $output:ident) => { ... };
+}
+
\ No newline at end of file diff --git a/docs/halo2curves/macro.impl_binops_additive!.html b/docs/halo2curves/macro.impl_binops_additive!.html new file mode 100644 index 0000000000..9495018192 --- /dev/null +++ b/docs/halo2curves/macro.impl_binops_additive!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.impl_binops_additive.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/macro.impl_binops_additive.html b/docs/halo2curves/macro.impl_binops_additive.html new file mode 100644 index 0000000000..644e14dbaa --- /dev/null +++ b/docs/halo2curves/macro.impl_binops_additive.html @@ -0,0 +1,4 @@ +impl_binops_additive in halo2curves - Rust
macro_rules! impl_binops_additive {
+    ($lhs:ident, $rhs:ident) => { ... };
+}
+
\ No newline at end of file diff --git a/docs/halo2curves/macro.impl_binops_additive_specify_output!.html b/docs/halo2curves/macro.impl_binops_additive_specify_output!.html new file mode 100644 index 0000000000..eaa62184ca --- /dev/null +++ b/docs/halo2curves/macro.impl_binops_additive_specify_output!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.impl_binops_additive_specify_output.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/macro.impl_binops_additive_specify_output.html b/docs/halo2curves/macro.impl_binops_additive_specify_output.html new file mode 100644 index 0000000000..bbd57280f4 --- /dev/null +++ b/docs/halo2curves/macro.impl_binops_additive_specify_output.html @@ -0,0 +1,4 @@ +impl_binops_additive_specify_output in halo2curves - Rust
macro_rules! impl_binops_additive_specify_output {
+    ($lhs:ident, $rhs:ident, $output:ident) => { ... };
+}
+
\ No newline at end of file diff --git a/docs/halo2curves/macro.impl_binops_multiplicative!.html b/docs/halo2curves/macro.impl_binops_multiplicative!.html new file mode 100644 index 0000000000..6c07317d42 --- /dev/null +++ b/docs/halo2curves/macro.impl_binops_multiplicative!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.impl_binops_multiplicative.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/macro.impl_binops_multiplicative.html b/docs/halo2curves/macro.impl_binops_multiplicative.html new file mode 100644 index 0000000000..96c3c89e20 --- /dev/null +++ b/docs/halo2curves/macro.impl_binops_multiplicative.html @@ -0,0 +1,4 @@ +impl_binops_multiplicative in halo2curves - Rust
macro_rules! impl_binops_multiplicative {
+    ($lhs:ident, $rhs:ident) => { ... };
+}
+
\ No newline at end of file diff --git a/docs/halo2curves/macro.impl_binops_multiplicative_mixed!.html b/docs/halo2curves/macro.impl_binops_multiplicative_mixed!.html new file mode 100644 index 0000000000..bff52b942d --- /dev/null +++ b/docs/halo2curves/macro.impl_binops_multiplicative_mixed!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.impl_binops_multiplicative_mixed.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/macro.impl_binops_multiplicative_mixed.html b/docs/halo2curves/macro.impl_binops_multiplicative_mixed.html new file mode 100644 index 0000000000..e575051b4d --- /dev/null +++ b/docs/halo2curves/macro.impl_binops_multiplicative_mixed.html @@ -0,0 +1,4 @@ +impl_binops_multiplicative_mixed in halo2curves - Rust
macro_rules! impl_binops_multiplicative_mixed {
+    ($lhs:ident, $rhs:ident, $output:ident) => { ... };
+}
+
\ No newline at end of file diff --git a/docs/halo2curves/macro.impl_sub_binop_specify_output!.html b/docs/halo2curves/macro.impl_sub_binop_specify_output!.html new file mode 100644 index 0000000000..48e1cc3f2f --- /dev/null +++ b/docs/halo2curves/macro.impl_sub_binop_specify_output!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.impl_sub_binop_specify_output.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/macro.impl_sub_binop_specify_output.html b/docs/halo2curves/macro.impl_sub_binop_specify_output.html new file mode 100644 index 0000000000..d603e48b19 --- /dev/null +++ b/docs/halo2curves/macro.impl_sub_binop_specify_output.html @@ -0,0 +1,4 @@ +impl_sub_binop_specify_output in halo2curves - Rust
macro_rules! impl_sub_binop_specify_output {
+    ($lhs:ident, $rhs:ident, $output:ident) => { ... };
+}
+
\ No newline at end of file diff --git a/docs/halo2curves/macro.new_curve_impl!.html b/docs/halo2curves/macro.new_curve_impl!.html new file mode 100644 index 0000000000..548efba6c8 --- /dev/null +++ b/docs/halo2curves/macro.new_curve_impl!.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to macro.new_curve_impl.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/macro.new_curve_impl.html b/docs/halo2curves/macro.new_curve_impl.html new file mode 100644 index 0000000000..fe6521ea58 --- /dev/null +++ b/docs/halo2curves/macro.new_curve_impl.html @@ -0,0 +1,14 @@ +new_curve_impl in halo2curves - Rust
macro_rules! new_curve_impl {
+    (($($privacy:tt)*),
+    $name:ident,
+    $name_affine:ident,
+    $name_compressed:ident,
+    $compressed_size:expr,
+    $base:ident,
+    $scalar:ident,
+    $generator:expr,
+    $constant_b:expr,
+    $curve_id:literal,
+    ) => { ... };
+}
+
\ No newline at end of file diff --git a/docs/halo2curves/pairing/index.html b/docs/halo2curves/pairing/index.html new file mode 100644 index 0000000000..753afcaf16 --- /dev/null +++ b/docs/halo2curves/pairing/index.html @@ -0,0 +1,3 @@ +halo2curves::pairing - Rust

Traits

Represents results of a Miller loop, one of the most expensive portions of the pairing +function.
An engine that can compute sums of pairings in an efficient way.
Affine representation of an elliptic curve point that can be used +to perform pairings.
\ No newline at end of file diff --git a/docs/halo2curves/pairing/sidebar-items.js b/docs/halo2curves/pairing/sidebar-items.js new file mode 100644 index 0000000000..6c34f1fea7 --- /dev/null +++ b/docs/halo2curves/pairing/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"trait":[["Engine",""],["MillerLoopResult","Represents results of a Miller loop, one of the most expensive portions of the pairing function."],["MultiMillerLoop","An engine that can compute sums of pairings in an efficient way."],["PairingCurveAffine","Affine representation of an elliptic curve point that can be used to perform pairings."]]}; \ No newline at end of file diff --git a/docs/halo2curves/pairing/trait.Engine.html b/docs/halo2curves/pairing/trait.Engine.html new file mode 100644 index 0000000000..5770c2c3b8 --- /dev/null +++ b/docs/halo2curves/pairing/trait.Engine.html @@ -0,0 +1,18 @@ +Engine in halo2curves::pairing - Rust
pub trait Engine: Sized + 'static + Clone {
+    type Scalar: FieldExt;
+    type G1: PrimeCurve<Scalar = Self::Scalar, Affine = Self::G1Affine> + From<Self::G1Affine> + GroupOps<Self::G1Affine> + GroupOpsOwned<Self::G1Affine> + ScalarMul<Self::Scalar> + ScalarMulOwned<Self::Scalar> + _Group<Scalar = Self::Scalar>;
+    type G1Affine: PairingCurveAffine<ScalarExt = Self::Scalar, CurveExt = Self::G1, Pair = Self::G2Affine, PairingResult = Self::Gt> + From<Self::G1> + Mul<Self::Scalar, Output = Self::G1> + for<'a> Mul<&'a Self::Scalar, Output = Self::G1>;
+    type G2: PrimeCurve<Scalar = Self::Scalar, Affine = Self::G2Affine> + From<Self::G2Affine> + GroupOps<Self::G2Affine> + GroupOpsOwned<Self::G2Affine> + ScalarMul<Self::Scalar> + ScalarMulOwned<Self::Scalar>;
+    type G2Affine: PairingCurveAffine<ScalarExt = Self::Scalar, CurveExt = Self::G2, Pair = Self::G1Affine, PairingResult = Self::Gt> + From<Self::G2> + Mul<Self::Scalar, Output = Self::G2> + for<'a> Mul<&'a Self::Scalar, Output = Self::G2>;
+    type Gt: Group<Scalar = Self::Scalar> + ScalarMul<Self::Scalar> + ScalarMulOwned<Self::Scalar>;
+
+    fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt;
+}

Required Associated Types

This is the scalar field of the engine’s groups.

+

The projective representation of an element in G1.

+

The affine representation of an element in G1.

+

The projective representation of an element in G2.

+

The affine representation of an element in G2.

+

The extension field that hosts the target group of the pairing.

+

Required Methods

Invoke the pairing function G1 x G2 -> Gt without the use of precomputation and +other optimizations.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2curves/pairing/trait.MillerLoopResult.html b/docs/halo2curves/pairing/trait.MillerLoopResult.html new file mode 100644 index 0000000000..71fead00b5 --- /dev/null +++ b/docs/halo2curves/pairing/trait.MillerLoopResult.html @@ -0,0 +1,13 @@ +MillerLoopResult in halo2curves::pairing - Rust
pub trait MillerLoopResult {
+    type Gt: Group;
+
+    fn final_exponentiation(&self) -> Self::Gt;
+}
Expand description

Represents results of a Miller loop, one of the most expensive portions of the pairing +function.

+

MillerLoopResults cannot be compared with each other until +MillerLoopResult::final_exponentiation is called, which is also expensive.

+

Required Associated Types

The extension field that hosts the target group of the pairing.

+

Required Methods

This performs a “final exponentiation” routine to convert the result of a Miller +loop into an element of MillerLoopResult::Gt, so that it can be compared with +other elements of Gt.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2curves/pairing/trait.MultiMillerLoop.html b/docs/halo2curves/pairing/trait.MultiMillerLoop.html new file mode 100644 index 0000000000..9726349da3 --- /dev/null +++ b/docs/halo2curves/pairing/trait.MultiMillerLoop.html @@ -0,0 +1,11 @@ +MultiMillerLoop in halo2curves::pairing - Rust
pub trait MultiMillerLoop: Engine {
+    type G2Prepared: Clone + Send + Sync + From<Self::G2Affine>;
+    type Result: MillerLoopResult<Gt = Self::Gt>;
+
+    fn multi_miller_loop(
        terms: &[(&Self::G1Affine, &Self::G2Prepared)]
    ) -> Self::Result; +}
Expand description

An engine that can compute sums of pairings in an efficient way.

+

Required Associated Types

The prepared form of Self::G2Affine.

+

The type returned by Engine::miller_loop.

+

Required Methods

Computes $$\sum_{i=1}^n \textbf{ML}(a_i, b_i)$$ given a series of terms +$$(a_1, b_1), (a_2, b_2), …, (a_n, b_n).$$

+

Implementors

\ No newline at end of file diff --git a/docs/halo2curves/pairing/trait.PairingCurveAffine.html b/docs/halo2curves/pairing/trait.PairingCurveAffine.html new file mode 100644 index 0000000000..72161de17c --- /dev/null +++ b/docs/halo2curves/pairing/trait.PairingCurveAffine.html @@ -0,0 +1,9 @@ +PairingCurveAffine in halo2curves::pairing - Rust
pub trait PairingCurveAffine: CurveAffine + UncompressedEncoding {
+    type Pair: PairingCurveAffine<Pair = Self>;
+    type PairingResult: Group;
+
+    fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult;
+}
Expand description

Affine representation of an elliptic curve point that can be used +to perform pairings.

+

Required Associated Types

Required Methods

Perform a pairing

+

Implementors

\ No newline at end of file diff --git a/docs/halo2curves/pasta/index.html b/docs/halo2curves/pasta/index.html new file mode 100644 index 0000000000..9060b32ddd --- /dev/null +++ b/docs/halo2curves/pasta/index.html @@ -0,0 +1,3 @@ +halo2curves::pasta - Rust

Modules

The Pallas and iso-Pallas elliptic curve groups.
The Vesta and iso-Vesta elliptic curve groups.

Structs

Represents a point in the projective coordinate space.
Represents a point in the affine coordinate space (or the point at +infinity).
Represents a point in the projective coordinate space.
Represents a point in the affine coordinate space (or the point at +infinity).
This represents an element of $\mathbb{F}_p$ where
This represents an element of $\mathbb{F}_q$ where
\ No newline at end of file diff --git a/docs/halo2curves/pasta/pallas/index.html b/docs/halo2curves/pasta/pallas/index.html new file mode 100644 index 0000000000..d58b57b52a --- /dev/null +++ b/docs/halo2curves/pasta/pallas/index.html @@ -0,0 +1,2 @@ +halo2curves::pasta::pallas - Rust
Expand description

The Pallas and iso-Pallas elliptic curve groups.

+

Type Definitions

A Pallas point in the affine coordinate space (or the point at infinity).
The base field of the Pallas and iso-Pallas curves.
A Pallas point in the projective coordinate space.
The scalar field of the Pallas and iso-Pallas curves.
\ No newline at end of file diff --git a/docs/halo2curves/pasta/pallas/sidebar-items.js b/docs/halo2curves/pasta/pallas/sidebar-items.js new file mode 100644 index 0000000000..5bbf4a4d14 --- /dev/null +++ b/docs/halo2curves/pasta/pallas/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"type":[["Affine","A Pallas point in the affine coordinate space (or the point at infinity)."],["Base","The base field of the Pallas and iso-Pallas curves."],["Point","A Pallas point in the projective coordinate space."],["Scalar","The scalar field of the Pallas and iso-Pallas curves."]]}; \ No newline at end of file diff --git a/docs/halo2curves/pasta/pallas/type.Affine.html b/docs/halo2curves/pasta/pallas/type.Affine.html new file mode 100644 index 0000000000..2fea6076be --- /dev/null +++ b/docs/halo2curves/pasta/pallas/type.Affine.html @@ -0,0 +1,2 @@ +Affine in halo2curves::pasta::pallas - Rust

Type Definition halo2curves::pasta::pallas::Affine

[]
pub type Affine = EpAffine;
Expand description

A Pallas point in the affine coordinate space (or the point at infinity).

+
\ No newline at end of file diff --git a/docs/halo2curves/pasta/pallas/type.Base.html b/docs/halo2curves/pasta/pallas/type.Base.html new file mode 100644 index 0000000000..ee793d5f5b --- /dev/null +++ b/docs/halo2curves/pasta/pallas/type.Base.html @@ -0,0 +1,2 @@ +Base in halo2curves::pasta::pallas - Rust

Type Definition halo2curves::pasta::pallas::Base

[]
pub type Base = Fp;
Expand description

The base field of the Pallas and iso-Pallas curves.

+
\ No newline at end of file diff --git a/docs/halo2curves/pasta/pallas/type.Point.html b/docs/halo2curves/pasta/pallas/type.Point.html new file mode 100644 index 0000000000..8ab681f120 --- /dev/null +++ b/docs/halo2curves/pasta/pallas/type.Point.html @@ -0,0 +1,2 @@ +Point in halo2curves::pasta::pallas - Rust

Type Definition halo2curves::pasta::pallas::Point

[]
pub type Point = Ep;
Expand description

A Pallas point in the projective coordinate space.

+
\ No newline at end of file diff --git a/docs/halo2curves/pasta/pallas/type.Scalar.html b/docs/halo2curves/pasta/pallas/type.Scalar.html new file mode 100644 index 0000000000..42c066a50e --- /dev/null +++ b/docs/halo2curves/pasta/pallas/type.Scalar.html @@ -0,0 +1,2 @@ +Scalar in halo2curves::pasta::pallas - Rust

Type Definition halo2curves::pasta::pallas::Scalar

[]
pub type Scalar = Fq;
Expand description

The scalar field of the Pallas and iso-Pallas curves.

+
\ No newline at end of file diff --git a/docs/halo2curves/pasta/sidebar-items.js b/docs/halo2curves/pasta/sidebar-items.js new file mode 100644 index 0000000000..c93ec60dbe --- /dev/null +++ b/docs/halo2curves/pasta/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"mod":[["pallas","The Pallas and iso-Pallas elliptic curve groups."],["vesta","The Vesta and iso-Vesta elliptic curve groups."]],"struct":[["Ep","Represents a point in the projective coordinate space."],["EpAffine","Represents a point in the affine coordinate space (or the point at infinity)."],["Eq","Represents a point in the projective coordinate space."],["EqAffine","Represents a point in the affine coordinate space (or the point at infinity)."],["Fp","This represents an element of $\\mathbb{F}_p$ where"],["Fq","This represents an element of $\\mathbb{F}_q$ where"]]}; \ No newline at end of file diff --git a/docs/halo2curves/pasta/struct.Ep.html b/docs/halo2curves/pasta/struct.Ep.html new file mode 100644 index 0000000000..84fa78e16d --- /dev/null +++ b/docs/halo2curves/pasta/struct.Ep.html @@ -0,0 +1,70 @@ +Ep in halo2curves::pasta - Rust
pub struct Ep { /* private fields */ }
Expand description

Represents a point in the projective coordinate space.

+

Implementations

Constants used for computing the isogeny from IsoEp to Ep.

+

Z = -13

+

(F::root_of_unity().invert().unwrap() * z).sqrt().unwrap()

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
The large prime-order subgroup in which cryptographic operations are performed. +If Self implements PrimeGroup, then Self::Subgroup may be Self. Read more
Maps self to the prime-order subgroup by multiplying this element by some +k-multiple of the cofactor. Read more
Returns self if it is contained in the prime-order subgroup. Read more
Determines if this element is “torsion free”, i.e., is contained in the +prime-order subgroup. Read more
Determines if this element is of small order. Read more
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
The affine representation for this elliptic curve.
Converts a batch of projective elements into affine elements. This function will +panic if p.len() != q.len(). Read more
Converts this element into its affine representation.

Apply the curve endomorphism by multiplying the x-coordinate +by an element of multiplicative order 3.

+
The scalar field of this elliptic curve.
The base field over which this elliptic curve is constructed.
The affine version of the curve
CURVE_ID used for hash-to-curve.
Requests a hasher that accepts messages and returns near-uniformly +distributed elements in the group, given domain prefix domain_prefix. Read more
Returns the curve constant a.
Returns the curve constant b.
Obtains a point given Jacobian coordinates $X : Y : Z$, failing +if the coordinates are not on the curve. Read more
Return the Jacobian coordinates of this point.
Returns whether or not this element is on the curve; should +always be true unless an “unchecked” API was used. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Scalars modulo the order of this group’s scalar field.
Returns an element chosen uniformly at random from the non-identity elements of +this group. Read more
Returns a fixed generator of the prime-order subgroup.
Doubles this element.
Returns the additive identity, also known as the “neutral element”.
Determines if this point is the identity.
The group is assumed to be of prime order $p$. Scalar is the +associated scalar field of size $p$. Read more
Returns the additive identity of the group.
Adds rhs to this group element.
Subtracts rhs from this group element.
Scales this group element by a scalar.
The encoding of group elements. Read more
Attempts to deserialize a group element from its encoding.
Attempts to deserialize a group element, not checking if the element is valid. Read more
Converts this element into its byte encoding. This may or may not support +encoding the identity. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Method which takes an iterator and generates Self from the elements by +“summing up” the items. Read more
Recommends a wNAF window size given the number of scalars you intend to multiply +a base by. Always returns a number between 2 and 22, inclusive. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/pasta/struct.EpAffine.html b/docs/halo2curves/pasta/struct.EpAffine.html new file mode 100644 index 0000000000..6ee6921143 --- /dev/null +++ b/docs/halo2curves/pasta/struct.EpAffine.html @@ -0,0 +1,32 @@ +EpAffine in halo2curves::pasta - Rust
pub struct EpAffine { /* private fields */ }
Expand description

Represents a point in the affine coordinate space (or the point at +infinity).

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Returns the additive identity.
Returns a fixed generator of unknown exponent.
Determines if this point represents the point at infinity; the +additive identity. Read more
Converts this element to its curve representation.
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
The scalar field of this elliptic curve.
The base field over which this elliptic curve is constructed.
The projective form of the curve
Returns whether or not this element is on the curve; should +always be true unless an “unchecked” API was used. Read more
Gets the coordinates of this point. Read more
Obtains a point given $(x, y)$, failing if it is not on the +curve. Read more
Returns the curve constant $a$.
Returns the curve constant $b$.
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
The encoding of group elements. Read more
Attempts to deserialize a group element from its encoding.
Attempts to deserialize a group element, not checking if the element is valid. Read more
Converts this element into its byte encoding. This may or may not support +encoding the identity. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
Returns a fixed generator of unknown exponent.
Returns the additive identity.
Determines if this point represents the point at infinity; the +additive identity. Read more
Converts this element to its curve representation.
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/pasta/struct.Eq.html b/docs/halo2curves/pasta/struct.Eq.html new file mode 100644 index 0000000000..25abba3758 --- /dev/null +++ b/docs/halo2curves/pasta/struct.Eq.html @@ -0,0 +1,70 @@ +Eq in halo2curves::pasta - Rust
pub struct Eq { /* private fields */ }
Expand description

Represents a point in the projective coordinate space.

+

Implementations

Constants used for computing the isogeny from IsoEq to Eq.

+

Z = -13

+

(F::root_of_unity().invert().unwrap() * z).sqrt().unwrap()

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
The large prime-order subgroup in which cryptographic operations are performed. +If Self implements PrimeGroup, then Self::Subgroup may be Self. Read more
Maps self to the prime-order subgroup by multiplying this element by some +k-multiple of the cofactor. Read more
Returns self if it is contained in the prime-order subgroup. Read more
Determines if this element is “torsion free”, i.e., is contained in the +prime-order subgroup. Read more
Determines if this element is of small order. Read more
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
The affine representation for this elliptic curve.
Converts a batch of projective elements into affine elements. This function will +panic if p.len() != q.len(). Read more
Converts this element into its affine representation.

Apply the curve endomorphism by multiplying the x-coordinate +by an element of multiplicative order 3.

+
The scalar field of this elliptic curve.
The base field over which this elliptic curve is constructed.
The affine version of the curve
CURVE_ID used for hash-to-curve.
Requests a hasher that accepts messages and returns near-uniformly +distributed elements in the group, given domain prefix domain_prefix. Read more
Returns the curve constant a.
Returns the curve constant b.
Obtains a point given Jacobian coordinates $X : Y : Z$, failing +if the coordinates are not on the curve. Read more
Return the Jacobian coordinates of this point.
Returns whether or not this element is on the curve; should +always be true unless an “unchecked” API was used. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Scalars modulo the order of this group’s scalar field.
Returns an element chosen uniformly at random from the non-identity elements of +this group. Read more
Returns a fixed generator of the prime-order subgroup.
Doubles this element.
Returns the additive identity, also known as the “neutral element”.
Determines if this point is the identity.
The group is assumed to be of prime order $p$. Scalar is the +associated scalar field of size $p$. Read more
Returns the additive identity of the group.
Adds rhs to this group element.
Subtracts rhs from this group element.
Scales this group element by a scalar.
The encoding of group elements. Read more
Attempts to deserialize a group element from its encoding.
Attempts to deserialize a group element, not checking if the element is valid. Read more
Converts this element into its byte encoding. This may or may not support +encoding the identity. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Method which takes an iterator and generates Self from the elements by +“summing up” the items. Read more
Recommends a wNAF window size given the number of scalars you intend to multiply +a base by. Always returns a number between 2 and 22, inclusive. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/pasta/struct.EqAffine.html b/docs/halo2curves/pasta/struct.EqAffine.html new file mode 100644 index 0000000000..5cebdb4a4f --- /dev/null +++ b/docs/halo2curves/pasta/struct.EqAffine.html @@ -0,0 +1,32 @@ +EqAffine in halo2curves::pasta - Rust
pub struct EqAffine { /* private fields */ }
Expand description

Represents a point in the affine coordinate space (or the point at +infinity).

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Returns the additive identity.
Returns a fixed generator of unknown exponent.
Determines if this point represents the point at infinity; the +additive identity. Read more
Converts this element to its curve representation.
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
The scalar field of this elliptic curve.
The base field over which this elliptic curve is constructed.
The projective form of the curve
Returns whether or not this element is on the curve; should +always be true unless an “unchecked” API was used. Read more
Gets the coordinates of this point. Read more
Obtains a point given $(x, y)$, failing if it is not on the +curve. Read more
Returns the curve constant $a$.
Returns the curve constant $b$.
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
The encoding of group elements. Read more
Attempts to deserialize a group element from its encoding.
Attempts to deserialize a group element, not checking if the element is valid. Read more
Converts this element into its byte encoding. This may or may not support +encoding the identity. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
Returns a fixed generator of unknown exponent.
Returns the additive identity.
Determines if this point represents the point at infinity; the +additive identity. Read more
Converts this element to its curve representation.
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/pasta/struct.Fp.html b/docs/halo2curves/pasta/struct.Fp.html new file mode 100644 index 0000000000..efddf38dd4 --- /dev/null +++ b/docs/halo2curves/pasta/struct.Fp.html @@ -0,0 +1,61 @@ +Fp in halo2curves::pasta - Rust
pub struct Fp(_);
Expand description

This represents an element of $\mathbb{F}_p$ where

+

p = 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001

+

is the base field of the Pallas curve.

+

Implementations

Returns zero, the additive identity.

+

Returns one, the multiplicative identity.

+

Doubles this field element.

+

Converts from an integer represented in little endian +into its (congruent) Fp representation.

+

Squares this element.

+

Multiplies rhs by self, returning the result.

+

Subtracts rhs from self, returning the result.

+

Adds rhs to self, returning the result.

+

Negates self.

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more

Computes the square root of this element, if it exists.

+

Computes the multiplicative inverse of this element, +failing if the element is zero.

+
Returns an element chosen uniformly at random using a user-provided RNG.
Returns the zero element of the field, the additive identity.
Returns the one element of the field, the multiplicative identity.
Doubles this element.
Squares this element.
Exponentiates self by exp, where exp is a little-endian order +integer exponent. Read more
Returns true iff this element is zero.
Returns true iff this element is zero. Read more
Cubes this element.

Converts a 512-bit little endian integer into +a Fp by reducing by the modulus.

+
Modulus of the field written as a string for display purposes
Inverse of PrimeField::root_of_unity()
Generator of the $t-order$ multiplicative subgroup
Inverse of $2$ in the field.
Element of multiplicative order $3$.
Obtains a field element congruent to the integer v.
Gets the lower 128 bits of this field element when expressed +canonically. Read more
Exponentiates self by by, where by is a little-endian order +integer exponent. Read more
Converts to this type from the input type.
Converts to this type from the input type.
The group is assumed to be of prime order $p$. Scalar is the +associated scalar field of size $p$. Read more
Returns the additive identity of the group.
Adds rhs to this group element.
Subtracts rhs from this group element.
Scales this group element by a scalar.
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method returns an Ordering between self and other. Read more
Compares and returns the maximum of two values. Read more
Compares and returns the minimum of two values. Read more
Restrict a value to a certain interval. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
This method returns an ordering between self and other values if one exists. Read more
This method tests less than (for self and other) and is used by the < operator. Read more
This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
This method tests greater than (for self and other) and is used by the > operator. Read more
This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
The prime field can be converted back and forth into this binary +representation. Read more
How many bits are needed to represent an element of this field.
How many bits of information can be reliably stored in the field element. Read more
An integer s satisfying the equation 2^s * t = modulus - 1 with t odd. Read more
Attempts to convert a byte representation of a field element into an element of +this prime field, failing if the input is not canonical (is not smaller than the +field’s modulus). Read more
Converts an element of the prime field into the standard byte representation for +this field. Read more
Returns true iff this element is odd.
Returns a fixed multiplicative generator of modulus - 1 order. This element must +also be a quadratic nonresidue. Read more
Returns the 2^s root of unity. Read more
Interpret a string of numbers as a (congruent) prime field element. +Does not accept unnecessary leading zeroes or a blank string. Read more
Attempts to convert a byte representation of a field element into an element of +this prime field, failing if the input is not canonical (is not smaller than the +field’s modulus). Read more
Returns true iff this element is even.
The backing store for a bit representation of a prime field element.
Converts an element of the prime field into a little-endian sequence of bits.
Returns the bits of the field characteristic (the modulus) in little-endian order.
The value $(T-1)/2$ such that $2^S \cdot T = p - 1$ with $T$ odd.
Raise this field element to the power [Self::T_MINUS1_OVER2]. Read more
Gets the lower 32 bits of this field element when expressed +canonically. Read more
Computes: Read more
Equivalent to Self::sqrt_ratio(self, one()).
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/pasta/struct.Fq.html b/docs/halo2curves/pasta/struct.Fq.html new file mode 100644 index 0000000000..0b84adb850 --- /dev/null +++ b/docs/halo2curves/pasta/struct.Fq.html @@ -0,0 +1,61 @@ +Fq in halo2curves::pasta - Rust
pub struct Fq(_);
Expand description

This represents an element of $\mathbb{F}_q$ where

+

q = 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001

+

is the base field of the Vesta curve.

+

Implementations

Returns zero, the additive identity.

+

Returns one, the multiplicative identity.

+

Doubles this field element.

+

Converts from an integer represented in little endian +into its (congruent) Fq representation.

+

Squares this element.

+

Multiplies rhs by self, returning the result.

+

Subtracts rhs from self, returning the result.

+

Adds rhs to self, returning the result.

+

Negates self.

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more

Computes the square root of this element, if it exists.

+

Computes the multiplicative inverse of this element, +failing if the element is zero.

+
Returns an element chosen uniformly at random using a user-provided RNG.
Returns the zero element of the field, the additive identity.
Returns the one element of the field, the multiplicative identity.
Doubles this element.
Squares this element.
Exponentiates self by exp, where exp is a little-endian order +integer exponent. Read more
Returns true iff this element is zero.
Returns true iff this element is zero. Read more
Cubes this element.

Converts a 512-bit little endian integer into +a Fq by reducing by the modulus.

+
Modulus of the field written as a string for display purposes
Inverse of PrimeField::root_of_unity()
Generator of the $t-order$ multiplicative subgroup
Inverse of $2$ in the field.
Element of multiplicative order $3$.
Obtains a field element congruent to the integer v.
Gets the lower 128 bits of this field element when expressed +canonically. Read more
Exponentiates self by by, where by is a little-endian order +integer exponent. Read more
Converts to this type from the input type.
Converts to this type from the input type.
The group is assumed to be of prime order $p$. Scalar is the +associated scalar field of size $p$. Read more
Returns the additive identity of the group.
Adds rhs to this group element.
Subtracts rhs from this group element.
Scales this group element by a scalar.
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method returns an Ordering between self and other. Read more
Compares and returns the maximum of two values. Read more
Compares and returns the minimum of two values. Read more
Restrict a value to a certain interval. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
This method returns an ordering between self and other values if one exists. Read more
This method tests less than (for self and other) and is used by the < operator. Read more
This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
This method tests greater than (for self and other) and is used by the > operator. Read more
This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
The prime field can be converted back and forth into this binary +representation. Read more
How many bits are needed to represent an element of this field.
How many bits of information can be reliably stored in the field element. Read more
An integer s satisfying the equation 2^s * t = modulus - 1 with t odd. Read more
Attempts to convert a byte representation of a field element into an element of +this prime field, failing if the input is not canonical (is not smaller than the +field’s modulus). Read more
Converts an element of the prime field into the standard byte representation for +this field. Read more
Returns true iff this element is odd.
Returns a fixed multiplicative generator of modulus - 1 order. This element must +also be a quadratic nonresidue. Read more
Returns the 2^s root of unity. Read more
Interpret a string of numbers as a (congruent) prime field element. +Does not accept unnecessary leading zeroes or a blank string. Read more
Attempts to convert a byte representation of a field element into an element of +this prime field, failing if the input is not canonical (is not smaller than the +field’s modulus). Read more
Returns true iff this element is even.
The backing store for a bit representation of a prime field element.
Converts an element of the prime field into a little-endian sequence of bits.
Returns the bits of the field characteristic (the modulus) in little-endian order.
The value $(T-1)/2$ such that $2^S \cdot T = p - 1$ with $T$ odd.
Raise this field element to the power [Self::T_MINUS1_OVER2]. Read more
Gets the lower 32 bits of this field element when expressed +canonically. Read more
Computes: Read more
Equivalent to Self::sqrt_ratio(self, one()).
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/pasta/vesta/index.html b/docs/halo2curves/pasta/vesta/index.html new file mode 100644 index 0000000000..93ddadfed0 --- /dev/null +++ b/docs/halo2curves/pasta/vesta/index.html @@ -0,0 +1,2 @@ +halo2curves::pasta::vesta - Rust
Expand description

The Vesta and iso-Vesta elliptic curve groups.

+

Type Definitions

A Vesta point in the affine coordinate space (or the point at infinity).
The base field of the Vesta and iso-Vesta curves.
A Vesta point in the projective coordinate space.
The scalar field of the Vesta and iso-Vesta curves.
\ No newline at end of file diff --git a/docs/halo2curves/pasta/vesta/sidebar-items.js b/docs/halo2curves/pasta/vesta/sidebar-items.js new file mode 100644 index 0000000000..02329460e1 --- /dev/null +++ b/docs/halo2curves/pasta/vesta/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"type":[["Affine","A Vesta point in the affine coordinate space (or the point at infinity)."],["Base","The base field of the Vesta and iso-Vesta curves."],["Point","A Vesta point in the projective coordinate space."],["Scalar","The scalar field of the Vesta and iso-Vesta curves."]]}; \ No newline at end of file diff --git a/docs/halo2curves/pasta/vesta/type.Affine.html b/docs/halo2curves/pasta/vesta/type.Affine.html new file mode 100644 index 0000000000..4b841a7d46 --- /dev/null +++ b/docs/halo2curves/pasta/vesta/type.Affine.html @@ -0,0 +1,2 @@ +Affine in halo2curves::pasta::vesta - Rust

Type Definition halo2curves::pasta::vesta::Affine

[]
pub type Affine = EqAffine;
Expand description

A Vesta point in the affine coordinate space (or the point at infinity).

+
\ No newline at end of file diff --git a/docs/halo2curves/pasta/vesta/type.Base.html b/docs/halo2curves/pasta/vesta/type.Base.html new file mode 100644 index 0000000000..19781d7dfa --- /dev/null +++ b/docs/halo2curves/pasta/vesta/type.Base.html @@ -0,0 +1,2 @@ +Base in halo2curves::pasta::vesta - Rust

Type Definition halo2curves::pasta::vesta::Base

[]
pub type Base = Fq;
Expand description

The base field of the Vesta and iso-Vesta curves.

+
\ No newline at end of file diff --git a/docs/halo2curves/pasta/vesta/type.Point.html b/docs/halo2curves/pasta/vesta/type.Point.html new file mode 100644 index 0000000000..2dabeb9973 --- /dev/null +++ b/docs/halo2curves/pasta/vesta/type.Point.html @@ -0,0 +1,2 @@ +Point in halo2curves::pasta::vesta - Rust

Type Definition halo2curves::pasta::vesta::Point

[]
pub type Point = Eq;
Expand description

A Vesta point in the projective coordinate space.

+
\ No newline at end of file diff --git a/docs/halo2curves/pasta/vesta/type.Scalar.html b/docs/halo2curves/pasta/vesta/type.Scalar.html new file mode 100644 index 0000000000..77bccd9eda --- /dev/null +++ b/docs/halo2curves/pasta/vesta/type.Scalar.html @@ -0,0 +1,2 @@ +Scalar in halo2curves::pasta::vesta - Rust

Type Definition halo2curves::pasta::vesta::Scalar

[]
pub type Scalar = Fp;
Expand description

The scalar field of the Vesta and iso-Vesta curves.

+
\ No newline at end of file diff --git a/docs/halo2curves/secp256k1/curve/struct.Secp256k1.html b/docs/halo2curves/secp256k1/curve/struct.Secp256k1.html new file mode 100644 index 0000000000..15c2a1abaa --- /dev/null +++ b/docs/halo2curves/secp256k1/curve/struct.Secp256k1.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/secp256k1/struct.Secp256k1.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/secp256k1/curve/struct.Secp256k1Affine.html b/docs/halo2curves/secp256k1/curve/struct.Secp256k1Affine.html new file mode 100644 index 0000000000..b712fc1168 --- /dev/null +++ b/docs/halo2curves/secp256k1/curve/struct.Secp256k1Affine.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/secp256k1/struct.Secp256k1Affine.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/secp256k1/curve/struct.Secp256k1Compressed.html b/docs/halo2curves/secp256k1/curve/struct.Secp256k1Compressed.html new file mode 100644 index 0000000000..ccfb6b88f0 --- /dev/null +++ b/docs/halo2curves/secp256k1/curve/struct.Secp256k1Compressed.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/secp256k1/struct.Secp256k1Compressed.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/secp256k1/fp/struct.Fp.html b/docs/halo2curves/secp256k1/fp/struct.Fp.html new file mode 100644 index 0000000000..3d9c251e88 --- /dev/null +++ b/docs/halo2curves/secp256k1/fp/struct.Fp.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/secp256k1/struct.Fp.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/secp256k1/fq/struct.Fq.html b/docs/halo2curves/secp256k1/fq/struct.Fq.html new file mode 100644 index 0000000000..d93cd9d1e9 --- /dev/null +++ b/docs/halo2curves/secp256k1/fq/struct.Fq.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../../halo2curves/secp256k1/struct.Fq.html...

+ + + \ No newline at end of file diff --git a/docs/halo2curves/secp256k1/index.html b/docs/halo2curves/secp256k1/index.html new file mode 100644 index 0000000000..044fcd307d --- /dev/null +++ b/docs/halo2curves/secp256k1/index.html @@ -0,0 +1 @@ +halo2curves::secp256k1 - Rust

Structs

This represents an element of $\mathbb{F}_p$ where
This represents an element of $\mathbb{F}_q$ where
\ No newline at end of file diff --git a/docs/halo2curves/secp256k1/sidebar-items.js b/docs/halo2curves/secp256k1/sidebar-items.js new file mode 100644 index 0000000000..34d9a83b73 --- /dev/null +++ b/docs/halo2curves/secp256k1/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":[["Fp","This represents an element of $\\mathbb{F}_p$ where"],["Fq","This represents an element of $\\mathbb{F}_q$ where"],["Secp256k1",""],["Secp256k1Affine",""],["Secp256k1Compressed",""]]}; \ No newline at end of file diff --git a/docs/halo2curves/secp256k1/struct.Fp.html b/docs/halo2curves/secp256k1/struct.Fp.html new file mode 100644 index 0000000000..6e8873ca28 --- /dev/null +++ b/docs/halo2curves/secp256k1/struct.Fp.html @@ -0,0 +1,70 @@ +Fp in halo2curves::secp256k1 - Rust
pub struct Fp(_);
Expand description

This represents an element of $\mathbb{F}_p$ where

+

p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f

+

is the base field of the secp256k1 curve.

+

Implementations

Returns zero, the additive identity.

+

Returns one, the multiplicative identity.

+

Converts from an integer represented in little endian +into its (congruent) $field representation.

+

Attempts to convert a little-endian byte representation of +a scalar into a Fr, failing if the input is not canonical.

+

Converts an element of Fr into a byte representation in +little-endian byte order.

+

Adds rhs to self, returning the result.

+

Multiplies rhs by self, returning the result.

+

Doubles this field element.

+

Squares this element.

+

Subtracts rhs from self, returning the result.

+

Negates self.

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Deserialize this value from the given Serde deserializer. Read more

Computes the square root of this element, if it exists.

+

Computes the multiplicative inverse of this element, +failing if the element is zero.

+
Returns an element chosen uniformly at random using a user-provided RNG.
Returns the zero element of the field, the additive identity.
Returns the one element of the field, the multiplicative identity.
Doubles this element.
Squares this element.
Exponentiates self by exp, where exp is a little-endian order +integer exponent. Read more
Returns true iff this element is zero.
Returns true iff this element is zero. Read more
Cubes this element.

Converts a 512-bit little endian integer into +a $field by reducing by the modulus.

+
Modulus of the field written as a string for display purposes
Inverse of $2$ in the field.
Inverse of PrimeField::root_of_unity()
Generator of the $t-order$ multiplicative subgroup
Element of multiplicative order $3$.
Obtains a field element congruent to the integer v.
Gets the lower 128 bits of this field element when expressed +canonically. Read more
Exponentiates self by by, where by is a little-endian order +integer exponent. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
The group is assumed to be of prime order $p$. Scalar is the +associated scalar field of size $p$. Read more
Returns the additive identity of the group.
Adds rhs to this group element.
Subtracts rhs from this group element.
Scales this group element by a scalar.
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method returns an Ordering between self and other. Read more
Compares and returns the maximum of two values. Read more
Compares and returns the minimum of two values. Read more
Restrict a value to a certain interval. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
This method returns an ordering between self and other values if one exists. Read more
This method tests less than (for self and other) and is used by the < operator. Read more
This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
This method tests greater than (for self and other) and is used by the > operator. Read more
This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
The prime field can be converted back and forth into this binary +representation. Read more
How many bits are needed to represent an element of this field.
How many bits of information can be reliably stored in the field element. Read more
An integer s satisfying the equation 2^s * t = modulus - 1 with t odd. Read more
Attempts to convert a byte representation of a field element into an element of +this prime field, failing if the input is not canonical (is not smaller than the +field’s modulus). Read more
Converts an element of the prime field into the standard byte representation for +this field. Read more
Returns true iff this element is odd.
Returns a fixed multiplicative generator of modulus - 1 order. This element must +also be a quadratic nonresidue. Read more
Returns the 2^s root of unity. Read more
Interpret a string of numbers as a (congruent) prime field element. +Does not accept unnecessary leading zeroes or a blank string. Read more
Attempts to convert a byte representation of a field element into an element of +this prime field, failing if the input is not canonical (is not smaller than the +field’s modulus). Read more
Returns true iff this element is even.
The purpose of unchecked functions is to read the internal memory representation +of a type from bytes as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. As such this function should only be +used internally as an extension of machine memory. It should not be used to deserialize +externally provided data. Read more
The purpose of unchecked functions is to read the internal memory representation +of a type from disk as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. This function should only be used +internally when some machine state cannot be kept in memory (e.g., between runs) +and needs to be reloaded as quickly as possible. Read more
Serialize this value into the given Serde serializer. Read more
The value $(T-1)/2$ such that $2^S \cdot T = p - 1$ with $T$ odd.
Gets the lower 32 bits of this field element when expressed +canonically. Read more
Raise this field element to the power [Self::T_MINUS1_OVER2]. Read more
Computes: Read more
Equivalent to Self::sqrt_ratio(self, one()).
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/secp256k1/struct.Fq.html b/docs/halo2curves/secp256k1/struct.Fq.html new file mode 100644 index 0000000000..ba5569a3c8 --- /dev/null +++ b/docs/halo2curves/secp256k1/struct.Fq.html @@ -0,0 +1,70 @@ +Fq in halo2curves::secp256k1 - Rust
pub struct Fq(_);
Expand description

This represents an element of $\mathbb{F}_q$ where

+

q = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141

+

is the scalar field of the secp256k1 curve.

+

Implementations

Returns zero, the additive identity.

+

Returns one, the multiplicative identity.

+

Converts from an integer represented in little endian +into its (congruent) $field representation.

+

Attempts to convert a little-endian byte representation of +a scalar into a Fr, failing if the input is not canonical.

+

Converts an element of Fr into a byte representation in +little-endian byte order.

+

Adds rhs to self, returning the result.

+

Multiplies rhs by self, returning the result.

+

Doubles this field element.

+

Squares this element.

+

Subtracts rhs from self, returning the result.

+

Negates self.

+

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Deserialize this value from the given Serde deserializer. Read more

Computes the square root of this element, if it exists.

+

Computes the multiplicative inverse of this element, +failing if the element is zero.

+
Returns an element chosen uniformly at random using a user-provided RNG.
Returns the zero element of the field, the additive identity.
Returns the one element of the field, the multiplicative identity.
Doubles this element.
Squares this element.
Exponentiates self by exp, where exp is a little-endian order +integer exponent. Read more
Returns true iff this element is zero.
Returns true iff this element is zero. Read more
Cubes this element.

Converts a 512-bit little endian integer into +a $field by reducing by the modulus.

+
Modulus of the field written as a string for display purposes
Inverse of $2$ in the field.
Inverse of PrimeField::root_of_unity()
Generator of the $t-order$ multiplicative subgroup
Element of multiplicative order $3$.
Obtains a field element congruent to the integer v.
Gets the lower 128 bits of this field element when expressed +canonically. Read more
Exponentiates self by by, where by is a little-endian order +integer exponent. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
The group is assumed to be of prime order $p$. Scalar is the +associated scalar field of size $p$. Read more
Returns the additive identity of the group.
Adds rhs to this group element.
Subtracts rhs from this group element.
Scales this group element by a scalar.
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method returns an Ordering between self and other. Read more
Compares and returns the maximum of two values. Read more
Compares and returns the minimum of two values. Read more
Restrict a value to a certain interval. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
This method returns an ordering between self and other values if one exists. Read more
This method tests less than (for self and other) and is used by the < operator. Read more
This method tests less than or equal to (for self and other) and is used by the <= +operator. Read more
This method tests greater than (for self and other) and is used by the > operator. Read more
This method tests greater than or equal to (for self and other) and is used by the >= +operator. Read more
The prime field can be converted back and forth into this binary +representation. Read more
How many bits are needed to represent an element of this field.
How many bits of information can be reliably stored in the field element. Read more
An integer s satisfying the equation 2^s * t = modulus - 1 with t odd. Read more
Attempts to convert a byte representation of a field element into an element of +this prime field, failing if the input is not canonical (is not smaller than the +field’s modulus). Read more
Converts an element of the prime field into the standard byte representation for +this field. Read more
Returns true iff this element is odd.
Returns a fixed multiplicative generator of modulus - 1 order. This element must +also be a quadratic nonresidue. Read more
Returns the 2^s root of unity. Read more
Interpret a string of numbers as a (congruent) prime field element. +Does not accept unnecessary leading zeroes or a blank string. Read more
Attempts to convert a byte representation of a field element into an element of +this prime field, failing if the input is not canonical (is not smaller than the +field’s modulus). Read more
Returns true iff this element is even.
The purpose of unchecked functions is to read the internal memory representation +of a type from bytes as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. As such this function should only be +used internally as an extension of machine memory. It should not be used to deserialize +externally provided data. Read more
The purpose of unchecked functions is to read the internal memory representation +of a type from disk as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. This function should only be used +internally when some machine state cannot be kept in memory (e.g., between runs) +and needs to be reloaded as quickly as possible. Read more
Serialize this value into the given Serde serializer. Read more
The value $(T-1)/2$ such that $2^S \cdot T = p - 1$ with $T$ odd.
Gets the lower 32 bits of this field element when expressed +canonically. Read more
Raise this field element to the power [Self::T_MINUS1_OVER2]. Read more
Computes: Read more
Equivalent to Self::sqrt_ratio(self, one()).
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/secp256k1/struct.Secp256k1.html b/docs/halo2curves/secp256k1/struct.Secp256k1.html new file mode 100644 index 0000000000..8e3cc29264 --- /dev/null +++ b/docs/halo2curves/secp256k1/struct.Secp256k1.html @@ -0,0 +1,49 @@ +Secp256k1 in halo2curves::secp256k1 - Rust
pub struct Secp256k1 {
+    pub x: Fp,
+    pub y: Fp,
+    pub z: Fp,
+}

Fields

x: Fpy: Fpz: Fp

Implementations

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
The large prime-order subgroup in which cryptographic operations are performed. +If Self implements PrimeGroup, then Self::Subgroup may be Self. Read more
Maps self to the prime-order subgroup by multiplying this element by some +k-multiple of the cofactor. Read more
Returns self if it is contained in the prime-order subgroup. Read more
Determines if this element is “torsion free”, i.e., is contained in the +prime-order subgroup. Read more
Determines if this element is of small order. Read more
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
The affine representation for this elliptic curve.
Converts a batch of projective elements into affine elements. This function will +panic if p.len() != q.len(). Read more
Converts this element into its affine representation.
The scalar field of this elliptic curve.
The base field over which this elliptic curve is constructed.
The affine version of the curve
CURVE_ID used for hash-to-curve.
Apply the curve endomorphism by multiplying the x-coordinate +by an element of multiplicative order 3. Read more
Return the Jacobian coordinates of this point.
Requests a hasher that accepts messages and returns near-uniformly +distributed elements in the group, given domain prefix domain_prefix. Read more
Returns whether or not this element is on the curve; should +always be true unless an “unchecked” API was used. Read more
Returns the curve constant b.
Returns the curve constant a.
Obtains a point given Jacobian coordinates $X : Y : Z$, failing +if the coordinates are not on the curve. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Deserialize this value from the given Serde deserializer. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Scalars modulo the order of this group’s scalar field.
Returns an element chosen uniformly at random from the non-identity elements of +this group. Read more
Doubles this element.
Returns a fixed generator of the prime-order subgroup.
Returns the additive identity, also known as the “neutral element”.
Determines if this point is the identity.
The group is assumed to be of prime order $p$. Scalar is the +associated scalar field of size $p$. Read more
Returns the additive identity of the group.
Adds rhs to this group element.
Subtracts rhs from this group element.
Scales this group element by a scalar.
The encoding of group elements. Read more
Attempts to deserialize a group element from its encoding.
Attempts to deserialize a group element, not checking if the element is valid. Read more
Converts this element into its byte encoding. This may or may not support +encoding the identity. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
Performs the *= operation. Read more
Performs the *= operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
The purpose of unchecked functions is to read the internal memory representation +of a type from bytes as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. As such this function should only be +used internally as an extension of machine memory. It should not be used to deserialize +externally provided data. Read more
The purpose of unchecked functions is to read the internal memory representation +of a type from disk as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. This function should only be used +internally when some machine state cannot be kept in memory (e.g., between runs) +and needs to be reloaded as quickly as possible. Read more
Serialize this value into the given Serde serializer. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more
Method which takes an iterator and generates Self from the elements by +“summing up” the items. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/secp256k1/struct.Secp256k1Affine.html b/docs/halo2curves/secp256k1/struct.Secp256k1Affine.html new file mode 100644 index 0000000000..4248f0130d --- /dev/null +++ b/docs/halo2curves/secp256k1/struct.Secp256k1Affine.html @@ -0,0 +1,41 @@ +Secp256k1Affine in halo2curves::secp256k1 - Rust
pub struct Secp256k1Affine {
+    pub x: Fp,
+    pub y: Fp,
+}

Fields

x: Fpy: Fp

Implementations

Trait Implementations

The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
The resulting type after applying the + operator.
Performs the + operation. Read more
Performs the += operation. Read more
Performs the += operation. Read more
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Returns the additive identity.
Returns a fixed generator of unknown exponent.
Determines if this point represents the point at infinity; the +additive identity. Read more
Converts this element to its curve representation.
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Determine if two items are equal. Read more
The scalar field of this elliptic curve.
The base field over which this elliptic curve is constructed.
The projective form of the curve
Returns whether or not this element is on the curve; should +always be true unless an “unchecked” API was used. Read more
Gets the coordinates of this point. Read more
Obtains a point given $(x, y)$, failing if it is not on the +curve. Read more
Returns the curve constant $a$.
Returns the curve constant $b$.
Unlike the Coordinates trait, this just returns the raw affine coordinates without checking is_on_curve
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Deserialize this value from the given Serde deserializer. Read more
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
Converts to this type from the input type.
The encoding of group elements. Read more
Attempts to deserialize a group element from its encoding.
Attempts to deserialize a group element, not checking if the element is valid. Read more
Converts this element into its byte encoding. This may or may not support +encoding the identity. Read more
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the * operator.
Performs the * operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
The resulting type after applying the - operator.
Performs the unary - operation. Read more
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more
Returns a fixed generator of unknown exponent.
Returns the additive identity.
Determines if this point represents the point at infinity; the +additive identity. Read more
Converts this element to its curve representation.
The purpose of unchecked functions is to read the internal memory representation +of a type from bytes as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. As such this function should only be +used internally as an extension of machine memory. It should not be used to deserialize +externally provided data. Read more
The purpose of unchecked functions is to read the internal memory representation +of a type from disk as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. This function should only be used +internally when some machine state cannot be kept in memory (e.g., between runs) +and needs to be reloaded as quickly as possible. Read more
Serialize this value into the given Serde serializer. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
The resulting type after applying the - operator.
Performs the - operation. Read more
Performs the -= operation. Read more
Performs the -= operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Negate self if choice == Choice(1); otherwise, leave it +unchanged. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/secp256k1/struct.Secp256k1Compressed.html b/docs/halo2curves/secp256k1/struct.Secp256k1Compressed.html new file mode 100644 index 0000000000..515983ff48 --- /dev/null +++ b/docs/halo2curves/secp256k1/struct.Secp256k1Compressed.html @@ -0,0 +1,23 @@ +Secp256k1Compressed in halo2curves::secp256k1 - Rust
pub struct Secp256k1Compressed(_);

Trait Implementations

Converts this type into a mutable reference of the (usually inferred) input type.
Converts this type into a shared reference of the (usually inferred) input type.
Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more
Feeds this value into the given Hasher. Read more
Feeds a slice of this type into the given Hasher. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Views self as an immutable bit-slice region with the O ordering.
Attempts to view self as an immutable bit-slice region with the O +ordering. Read more
Views self as a mutable bit-slice region with the O ordering.
Attempts to view self as a mutable bit-slice region with the O +ordering. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/serde/index.html b/docs/halo2curves/serde/index.html new file mode 100644 index 0000000000..4452885665 --- /dev/null +++ b/docs/halo2curves/serde/index.html @@ -0,0 +1,2 @@ +halo2curves::serde - Rust

Traits

Trait for converting raw bytes to/from the internal representation of a type. +For example, field elements are represented in Montgomery form and serialized/deserialized without Montgomery reduction.
\ No newline at end of file diff --git a/docs/halo2curves/serde/sidebar-items.js b/docs/halo2curves/serde/sidebar-items.js new file mode 100644 index 0000000000..e1cb40bdf5 --- /dev/null +++ b/docs/halo2curves/serde/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"trait":[["SerdeObject","Trait for converting raw bytes to/from the internal representation of a type. For example, field elements are represented in Montgomery form and serialized/deserialized without Montgomery reduction."]]}; \ No newline at end of file diff --git a/docs/halo2curves/serde/trait.SerdeObject.html b/docs/halo2curves/serde/trait.SerdeObject.html new file mode 100644 index 0000000000..44e76dbaf5 --- /dev/null +++ b/docs/halo2curves/serde/trait.SerdeObject.html @@ -0,0 +1,20 @@ +SerdeObject in halo2curves::serde - Rust
pub trait SerdeObject: Sized {
+    fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self;
+    fn from_raw_bytes(bytes: &[u8]) -> Option<Self>;
+    fn to_raw_bytes(&self) -> Vec<u8>;
+    fn read_raw_unchecked<R: Read>(reader: &mut R) -> Self;
+    fn read_raw<R: Read>(reader: &mut R) -> Result<Self>;
+    fn write_raw<W: Write>(&self, writer: &mut W) -> Result<()>;
+}
Expand description

Trait for converting raw bytes to/from the internal representation of a type. +For example, field elements are represented in Montgomery form and serialized/deserialized without Montgomery reduction.

+

Required Methods

The purpose of unchecked functions is to read the internal memory representation +of a type from bytes as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. As such this function should only be +used internally as an extension of machine memory. It should not be used to deserialize +externally provided data.

+

The purpose of unchecked functions is to read the internal memory representation +of a type from disk as quickly as possible. No sanitization checks are performed +to ensure the bytes represent a valid object. This function should only be used +internally when some machine state cannot be kept in memory (e.g., between runs) +and needs to be reloaded as quickly as possible.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2curves/sidebar-items.js b/docs/halo2curves/sidebar-items.js new file mode 100644 index 0000000000..f1baa4691f --- /dev/null +++ b/docs/halo2curves/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"externcrate":[["group",""]],"macro":[["batch_add",""],["field_arithmetic",""],["field_common",""],["field_specific",""],["impl_add_binop_specify_output",""],["impl_binops_additive",""],["impl_binops_additive_specify_output",""],["impl_binops_multiplicative",""],["impl_binops_multiplicative_mixed",""],["impl_sub_binop_specify_output",""],["new_curve_impl",""]],"mod":[["bn256",""],["pairing",""],["pasta",""],["secp256k1",""],["serde",""]],"struct":[["Coordinates","The affine coordinates of a point on an elliptic curve."]],"trait":[["CurveAffine","This trait is the affine counterpart to `Curve` and is used for serialization, storage in memory, and inspection of $x$ and $y$ coordinates."],["CurveAffineExt",""],["CurveExt","This trait is a common interface for dealing with elements of an elliptic curve group in a “projective” form, where that arithmetic is usually more efficient."],["FieldExt","This trait is a common interface for dealing with elements of a finite field."],["Group","This represents an element of a group with basic operations that can be performed. This allows an FFT implementation (for example) to operate generically over either a field or elliptic curve group."]]}; \ No newline at end of file diff --git a/docs/halo2curves/struct.Coordinates.html b/docs/halo2curves/struct.Coordinates.html new file mode 100644 index 0000000000..be3e59cef9 --- /dev/null +++ b/docs/halo2curves/struct.Coordinates.html @@ -0,0 +1,32 @@ +Coordinates in halo2curves - Rust
pub struct Coordinates<C>where
    C: CurveAffine,
{ /* private fields */ }
Expand description

The affine coordinates of a point on an elliptic curve.

+

Implementations

Obtains a Coordinates value given $(x, y)$, failing if it is not on the curve.

+

Returns the x-coordinate.

+

Equivalent to Coordinates::u.

+

Returns the y-coordinate.

+

Equivalent to Coordinates::v.

+

Returns the u-coordinate.

+

Equivalent to Coordinates::x.

+

Returns the v-coordinate.

+

Equivalent to Coordinates::y.

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Select a or b according to choice. Read more
Conditionally assign other to self, according to choice. Read more
Conditionally swap self and other if choice == 1; otherwise, +reassign both unto themselves. Read more
Formats the value using the given formatter. Read more
Returns the “default value” for a type. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/halo2curves/trait.CurveAffine.html b/docs/halo2curves/trait.CurveAffine.html new file mode 100644 index 0000000000..751cf249ca --- /dev/null +++ b/docs/halo2curves/trait.CurveAffine.html @@ -0,0 +1,25 @@ +CurveAffine in halo2curves - Rust
pub trait CurveAffine: PrimeCurveAffine<Scalar = Self::ScalarExt, Curve = Self::CurveExt> + Default + Add<Self, Output = Self::Curve> + Sub<Self, Output = Self::Curve> + ConditionallySelectable + ConstantTimeEq + From<Self::Curve> {
+    type ScalarExt: FieldExt;
+    type Base: FieldExt;
+    type CurveExt: CurveExt<AffineExt = Self, ScalarExt = Self::ScalarExt>;
+
+    fn coordinates(&self) -> CtOption<Coordinates<Self>>;
+    fn from_xy(x: Self::Base, y: Self::Base) -> CtOption<Self>;
+    fn is_on_curve(&self) -> Choice;
+    fn a() -> Self::Base;
+    fn b() -> Self::Base;
+}
Expand description

This trait is the affine counterpart to Curve and is used for +serialization, storage in memory, and inspection of $x$ and $y$ coordinates.

+

Requires the alloc feature flag because of hash_to_curve on CurveExt.

+

Required Associated Types

The scalar field of this elliptic curve.

+

The base field over which this elliptic curve is constructed.

+

The projective form of the curve

+

Required Methods

Gets the coordinates of this point.

+

Returns None if this is the identity.

+

Obtains a point given $(x, y)$, failing if it is not on the +curve.

+

Returns whether or not this element is on the curve; should +always be true unless an “unchecked” API was used.

+

Returns the curve constant $a$.

+

Returns the curve constant $b$.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2curves/trait.CurveAffineExt.html b/docs/halo2curves/trait.CurveAffineExt.html new file mode 100644 index 0000000000..7605649ccf --- /dev/null +++ b/docs/halo2curves/trait.CurveAffineExt.html @@ -0,0 +1,6 @@ +CurveAffineExt in halo2curves - Rust
pub trait CurveAffineExt: CurveAffine {
+    fn batch_add<const COMPLETE: bool, const LOAD_POINTS: bool>(
        points: &mut [Self],
        output_indices: &[u32],
        num_points: usize,
        offset: usize,
        bases: &[Self],
        base_positions: &[u32]
    ); + + fn into_coordinates(self) -> (Self::Base, Self::Base) { ... } +}

Required Methods

Provided Methods

Unlike the Coordinates trait, this just returns the raw affine coordinates without checking is_on_curve

+

Implementors

\ No newline at end of file diff --git a/docs/halo2curves/trait.CurveExt.html b/docs/halo2curves/trait.CurveExt.html new file mode 100644 index 0000000000..e1e6e6b510 --- /dev/null +++ b/docs/halo2curves/trait.CurveExt.html @@ -0,0 +1,46 @@ +CurveExt in halo2curves - Rust
pub trait CurveExt: PrimeCurve<Affine = Self::AffineExt, Scalar = Self::ScalarExt> + Group + Default + ConditionallySelectable + ConstantTimeEq + From<Self::Affine> + Group<Scalar = Self::Scalar> {
+    type ScalarExt: FieldExt;
+    type Base: FieldExt;
+    type AffineExt: CurveAffine<CurveExt = Self, ScalarExt = Self::ScalarExt, Output = Self, Output = Self> + Mul<Self::ScalarExt>;
+
+    const CURVE_ID: &'static str;
+
+    fn endo(&self) -> Self;
+    fn jacobian_coordinates(&self) -> (Self::Base, Self::Base, Self::Base);
+    fn hash_to_curve(domain_prefix: &'a str) -> Box<dyn Fn(&[u8]) + 'a, Global>;
+    fn is_on_curve(&self) -> Choice;
+    fn a() -> Self::Base;
+    fn b() -> Self::Base;
+    fn new_jacobian(x: Self::Base, y: Self::Base, z: Self::Base) -> CtOption<Self>;
+}
Expand description

This trait is a common interface for dealing with elements of an elliptic +curve group in a “projective” form, where that arithmetic is usually more +efficient.

+

Requires the alloc feature flag because of hash_to_curve.

+

Required Associated Types

The scalar field of this elliptic curve.

+

The base field over which this elliptic curve is constructed.

+

The affine version of the curve

+

Required Associated Constants

CURVE_ID used for hash-to-curve.

+

Required Methods

Apply the curve endomorphism by multiplying the x-coordinate +by an element of multiplicative order 3.

+

Return the Jacobian coordinates of this point.

+

Requests a hasher that accepts messages and returns near-uniformly +distributed elements in the group, given domain prefix domain_prefix.

+

This method is suitable for use as a random oracle.

+
Example
+
use pasta_curves::arithmetic::CurveExt;
+fn pedersen_commitment<C: CurveExt>(
+    x: C::ScalarExt,
+    r: C::ScalarExt,
+) -> C::Affine {
+    let hasher = C::hash_to_curve("z.cash:example_pedersen_commitment");
+    let g = hasher(b"g");
+    let h = hasher(b"h");
+    (g * x + &(h * r)).to_affine()
+}
+

Returns whether or not this element is on the curve; should +always be true unless an “unchecked” API was used.

+

Returns the curve constant a.

+

Returns the curve constant b.

+

Obtains a point given Jacobian coordinates $X : Y : Z$, failing +if the coordinates are not on the curve.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2curves/trait.FieldExt.html b/docs/halo2curves/trait.FieldExt.html new file mode 100644 index 0000000000..a729ffcb11 --- /dev/null +++ b/docs/halo2curves/trait.FieldExt.html @@ -0,0 +1,33 @@ +FieldExt in halo2curves - Rust
pub trait FieldExt: SqrtRatio + From<bool> + Ord + Group<Scalar = Self> {
+    const MODULUS: &'static str;
+    const ROOT_OF_UNITY_INV: Self;
+    const DELTA: Self;
+    const TWO_INV: Self;
+    const ZETA: Self;
+
+    fn from_u128(v: u128) -> Self;
+    fn from_bytes_wide(bytes: &[u8; 64]) -> Self;
+    fn get_lower_128(&self) -> u128;
+
+    fn pow(&self, by: &[u64; 4]) -> Self { ... }
+}
Expand description

This trait is a common interface for dealing with elements of a finite +field.

+

Required Associated Constants

Modulus of the field written as a string for display purposes

+

Inverse of PrimeField::root_of_unity()

+

Generator of the $t-order$ multiplicative subgroup

+

Inverse of $2$ in the field.

+

Element of multiplicative order $3$.

+

Required Methods

Obtains a field element congruent to the integer v.

+

Obtains a field element that is congruent to the provided little endian +byte representation of an integer.

+

Gets the lower 128 bits of this field element when expressed +canonically.

+

Provided Methods

Exponentiates self by by, where by is a little-endian order +integer exponent.

+

Implementors

\ No newline at end of file diff --git a/docs/halo2curves/trait.Group.html b/docs/halo2curves/trait.Group.html new file mode 100644 index 0000000000..15136af0f0 --- /dev/null +++ b/docs/halo2curves/trait.Group.html @@ -0,0 +1,17 @@ +Group in halo2curves - Rust
pub trait Group: 'static + Copy + Clone + Send + Sync {
+    type Scalar: FieldExt;
+
+    fn group_zero() -> Self;
+    fn group_add(&mut self, rhs: &Self);
+    fn group_sub(&mut self, rhs: &Self);
+    fn group_scale(&mut self, by: &Self::Scalar);
+}
Expand description

This represents an element of a group with basic operations that can be +performed. This allows an FFT implementation (for example) to operate +generically over either a field or elliptic curve group.

+

Required Associated Types

The group is assumed to be of prime order $p$. Scalar is the +associated scalar field of size $p$.

+

Required Methods

Returns the additive identity of the group.

+

Adds rhs to this group element.

+

Subtracts rhs from this group element.

+

Scales this group element by a scalar.

+

Implementors

\ No newline at end of file diff --git a/docs/help.html b/docs/help.html new file mode 100644 index 0000000000..fc9f37e10f --- /dev/null +++ b/docs/help.html @@ -0,0 +1 @@ +Rustdoc help

Rustdoc help

Back
\ No newline at end of file diff --git a/docs/implementors/core/clone/trait.Clone.js b/docs/implementors/core/clone/trait.Clone.js new file mode 100644 index 0000000000..dee04363e1 --- /dev/null +++ b/docs/implementors/core/clone/trait.Clone.js @@ -0,0 +1,5 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<V: Clone> Clone for Value<V>"],["impl Clone for RegionShape"],["impl Clone for RegionColumn"],["impl Clone for RegionIndex"],["impl Clone for RegionStart"],["impl Clone for Cell"],["impl<V: Clone, F: Clone + Field> Clone for AssignedCell<V, F>"],["impl<F: Clone> Clone for Assigned<F>"],["impl<C: Clone + ColumnType> Clone for Column<C>"],["impl Clone for Advice"],["impl Clone for Fixed"],["impl Clone for Instance"],["impl Clone for Any"],["impl Clone for Selector"],["impl Clone for FixedQuery"],["impl Clone for AdviceQuery"],["impl Clone for InstanceQuery"],["impl Clone for TableColumn"],["impl Clone for Challenge"],["impl<F: Clone> Clone for Expression<F>"],["impl Clone for VirtualCell"],["impl<F: Clone + Field> Clone for Gate<F>"],["impl<F: Clone + Field> Clone for ConstraintSystem<F>"],["impl<C: Clone + CurveAffine> Clone for VerifyingKey<C>where
    C::Scalar: Clone,
    C::Scalar: Clone,
    C::Scalar: Clone,
"],["impl<C: Clone + CurveAffine> Clone for ProvingKey<C>where
    C::Scalar: Clone,
    C::Scalar: Clone,
    C::Scalar: Clone,
    C::Scalar: Clone,
    C::Scalar: Clone,
    C::Scalar: Clone,
"],["impl<F: Clone> Clone for Blind<F>"],["impl<G: Clone + Group> Clone for EvaluationDomain<G>where
    G::Scalar: Clone,
    G::Scalar: Clone,
    G::Scalar: Clone,
    G::Scalar: Clone,
    G::Scalar: Clone,
    G::Scalar: Clone,
    G::Scalar: Clone,
    G::Scalar: Clone,
    G::Scalar: Clone,
    G::Scalar: Clone,
"],["impl<'com, C: Clone + CurveAffine> Clone for ProverQuery<'com, C>where
    C::Scalar: Clone,
    C::Scalar: Clone,
    C::Scalar: Clone,
"],["impl<'com, C: CurveAffine, M: MSM<C>> Clone for VerifierQuery<'com, C, M>"],["impl<C: Clone + CurveAffine> Clone for ParamsIPA<C>"],["impl<'params, C: Clone + CurveAffine> Clone for MSMIPA<'params, C>where
    C::Scalar: Clone,
    C::Scalar: Clone,
    C::Scalar: Clone,
    C::Base: Clone,
    C::Scalar: Clone,
    C::Base: Clone,
"],["impl<'params, C: Clone + CurveAffine> Clone for GuardIPA<'params, C>where
    C::Scalar: Clone,
    C::Scalar: Clone,
    C::Scalar: Clone,
"],["impl<C: Clone + CurveAffine> Clone for Accumulator<C>where
    C::Scalar: Clone,
"],["impl<E: Clone + Engine> Clone for ParamsKZG<E>where
    E::G1Affine: Clone,
    E::G1Affine: Clone,
    E::G2Affine: Clone,
    E::G2Affine: Clone,
"],["impl<E: Clone + Engine> Clone for MSMKZG<E>where
    E::Scalar: Clone,
    E::G1: Clone,
"],["impl<'a, E: Clone + Engine> Clone for DualMSM<'a, E>"],["impl<'params, E: Clone + MultiMillerLoop + Debug> Clone for GuardKZG<'params, E>"],["impl<'params, E: Clone + Engine> Clone for AccumulatorStrategy<'params, E>"],["impl<'params, E: Clone + Engine> Clone for SingleStrategy<'params, E>"],["impl Clone for Coeff"],["impl Clone for LagrangeCoeff"],["impl Clone for ExtendedLagrangeCoeff"],["impl<F: Clone, B: Clone> Clone for Polynomial<F, B>"],["impl Clone for Rotation"],["impl<R: Clone + Read, C: Clone + CurveAffine, E: Clone + EncodedChallenge<C>> Clone for Blake2bRead<R, C, E>"],["impl<W: Clone + Write, C: Clone + CurveAffine, E: Clone + EncodedChallenge<C>> Clone for Blake2bWrite<W, C, E>"],["impl<C: Clone + CurveAffine, T: Clone> Clone for ChallengeScalar<C, T>where
    C::Scalar: Clone,
"],["impl<C: Clone + CurveAffine> Clone for Challenge255<C>"],["impl Clone for Column"],["impl Clone for Region"],["impl Clone for SerdeFormat"]], +"halo2curves":[["impl Clone for G1"],["impl Clone for G1Affine"],["impl Clone for G1Compressed"],["impl Clone for G2"],["impl Clone for G2Affine"],["impl Clone for G2Compressed"],["impl Clone for Gt"],["impl Clone for G2Prepared"],["impl Clone for Bn256"],["impl Clone for Fq"],["impl Clone for Fq12"],["impl Clone for Fq2"],["impl Clone for Fq2Bytes"],["impl Clone for Fq6"],["impl Clone for Fr"],["impl Clone for Secp256k1"],["impl Clone for Secp256k1Affine"],["impl Clone for Secp256k1Compressed"],["impl Clone for Fp"],["impl Clone for Fq"]], +"poseidon":[["impl<F: Clone + FieldExt, const T: usize, const RATE: usize> Clone for Poseidon<F, T, RATE>"],["impl<F: Clone + FieldExt, const T: usize> Clone for State<F, T>"],["impl<F: Clone + FieldExt, const T: usize, const RATE: usize> Clone for Spec<F, T, RATE>"],["impl<F: Clone + FieldExt, const T: usize, const RATE: usize> Clone for MDSMatrices<F, T, RATE>"],["impl<F: Clone + FieldExt, const T: usize, const RATE: usize> Clone for MDSMatrix<F, T, RATE>"],["impl<F: Clone + FieldExt, const T: usize, const RATE: usize> Clone for SparseMDSMatrix<F, T, RATE>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/cmp/trait.Eq.js b/docs/implementors/core/cmp/trait.Eq.js new file mode 100644 index 0000000000..2fac165874 --- /dev/null +++ b/docs/implementors/core/cmp/trait.Eq.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[["impl Eq for RegionColumn"],["impl Eq for RegionStart"],["impl<F: Field> Eq for Assigned<F>"],["impl<C: Eq + ColumnType> Eq for Column<C>"],["impl Eq for Advice"],["impl Eq for Fixed"],["impl Eq for Instance"],["impl Eq for Any"],["impl Eq for Selector"],["impl Eq for TableColumn"],["impl Eq for Challenge"],["impl<F: Eq> Eq for Blind<F>"],["impl Eq for Column"],["impl Eq for VirtualCell"]], +"halo2curves":[["impl Eq for G1"],["impl Eq for G1Affine"],["impl Eq for G2"],["impl Eq for G2Affine"],["impl Eq for Gt"],["impl Eq for Fq"],["impl Eq for Fq12"],["impl Eq for Fq2"],["impl Eq for Fq6"],["impl Eq for Fr"],["impl Eq for LegendreSymbol"],["impl Eq for Secp256k1"],["impl Eq for Secp256k1Affine"],["impl Eq for Fp"],["impl Eq for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/cmp/trait.Ord.js b/docs/implementors/core/cmp/trait.Ord.js new file mode 100644 index 0000000000..bc279a9be7 --- /dev/null +++ b/docs/implementors/core/cmp/trait.Ord.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[["impl Ord for RegionColumn"],["impl<C: ColumnType> Ord for Column<C>"],["impl Ord for Any"],["impl Ord for Column"],["impl Ord for VirtualCell"]], +"halo2curves":[["impl Ord for Fq"],["impl Ord for Fq2"],["impl Ord for Fr"],["impl Ord for Fp"],["impl Ord for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/cmp/trait.PartialEq.js b/docs/implementors/core/cmp/trait.PartialEq.js new file mode 100644 index 0000000000..ef69bb8370 --- /dev/null +++ b/docs/implementors/core/cmp/trait.PartialEq.js @@ -0,0 +1,5 @@ +(function() {var implementors = { +"halo2_proofs":[["impl PartialEq<RegionColumn> for RegionColumn"],["impl PartialEq<RegionStart> for RegionStart"],["impl<F: Field> PartialEq<Assigned<F>> for Assigned<F>"],["impl<C: PartialEq + ColumnType> PartialEq<Column<C>> for Column<C>"],["impl PartialEq<Advice> for Advice"],["impl PartialEq<Fixed> for Fixed"],["impl PartialEq<Instance> for Instance"],["impl PartialEq<Any> for Any"],["impl PartialEq<Selector> for Selector"],["impl PartialEq<TableColumn> for TableColumn"],["impl PartialEq<Challenge> for Challenge"],["impl<F: PartialEq> PartialEq<Blind<F>> for Blind<F>"],["impl PartialEq<Rotation> for Rotation"],["impl PartialEq<Column> for Column"],["impl PartialEq<VirtualCell> for VirtualCell"],["impl PartialEq<Gate> for Gate"],["impl PartialEq<Constraint> for Constraint"],["impl PartialEq<Region> for Region"],["impl PartialEq<FailureLocation> for FailureLocation"],["impl PartialEq<VerifyFailure> for VerifyFailure"]], +"halo2curves":[["impl PartialEq<G1Affine> for G1Affine"],["impl PartialEq<G1> for G1"],["impl PartialEq<G2Affine> for G2Affine"],["impl PartialEq<G2> for G2"],["impl PartialEq<Gt> for Gt"],["impl PartialEq<Fq> for Fq"],["impl PartialEq<Fq12> for Fq12"],["impl PartialEq<Fq2> for Fq2"],["impl PartialEq<Fq6> for Fq6"],["impl PartialEq<Fr> for Fr"],["impl PartialEq<LegendreSymbol> for LegendreSymbol"],["impl PartialEq<Secp256k1Affine> for Secp256k1Affine"],["impl PartialEq<Secp256k1> for Secp256k1"],["impl PartialEq<Fp> for Fp"],["impl PartialEq<Fq> for Fq"]], +"poseidon":[["impl<F: PartialEq + FieldExt, const T: usize> PartialEq<State<F, T>> for State<F, T>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/cmp/trait.PartialOrd.js b/docs/implementors/core/cmp/trait.PartialOrd.js new file mode 100644 index 0000000000..70c7e43215 --- /dev/null +++ b/docs/implementors/core/cmp/trait.PartialOrd.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[["impl PartialOrd<RegionColumn> for RegionColumn"],["impl<C: ColumnType> PartialOrd<Column<C>> for Column<C>"],["impl PartialOrd<Any> for Any"],["impl PartialOrd<Column> for Column"],["impl PartialOrd<VirtualCell> for VirtualCell"]], +"halo2curves":[["impl PartialOrd<Fq> for Fq"],["impl PartialOrd<Fq2> for Fq2"],["impl PartialOrd<Fr> for Fr"],["impl PartialOrd<Fp> for Fp"],["impl PartialOrd<Fq> for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/convert/trait.AsMut.js b/docs/implementors/core/convert/trait.AsMut.js new file mode 100644 index 0000000000..940189ccf7 --- /dev/null +++ b/docs/implementors/core/convert/trait.AsMut.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl AsMut<[u8]> for G1Compressed"],["impl AsMut<[u8]> for G2Compressed"],["impl AsMut<[u8]> for Fq2Bytes"],["impl AsMut<[u8]> for Secp256k1Compressed"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/convert/trait.AsRef.js b/docs/implementors/core/convert/trait.AsRef.js new file mode 100644 index 0000000000..cc8b87d5dc --- /dev/null +++ b/docs/implementors/core/convert/trait.AsRef.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl AsRef<[u8]> for G1Compressed"],["impl AsRef<[u8]> for G2Compressed"],["impl AsRef<[u8]> for Fq2Bytes"],["impl AsRef<[u8]> for Secp256k1Compressed"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/convert/trait.From.js b/docs/implementors/core/convert/trait.From.js new file mode 100644 index 0000000000..4126007a7a --- /dev/null +++ b/docs/implementors/core/convert/trait.From.js @@ -0,0 +1,5 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<F: Field> From<Value<F>> for Value<Assigned<F>>"],["impl From<Column<Any>> for RegionColumn"],["impl From<Selector> for RegionColumn"],["impl From<usize> for RegionIndex"],["impl From<usize> for RegionStart"],["impl<'r, F: Field> From<&'r mut (dyn RegionLayouter<F> + 'r)> for Region<'r, F>"],["impl<'r, F: Field> From<&'r mut (dyn TableLayouter<F> + 'r)> for Table<'r, F>"],["impl<F: Field> From<&Assigned<F>> for Assigned<F>"],["impl<F: Field> From<&F> for Assigned<F>"],["impl<F: Field> From<F> for Assigned<F>"],["impl<F: Field> From<(F, F)> for Assigned<F>"],["impl From<Advice> for Any"],["impl From<Fixed> for Any"],["impl From<Instance> for Any"],["impl From<Column<Advice>> for Column<Any>"],["impl From<Column<Fixed>> for Column<Any>"],["impl From<Column<Instance>> for Column<Any>"],["impl<Col: Into<Column<Any>>> From<(Col, Rotation)> for VirtualCell"],["impl<F: Field> From<Expression<F>> for Constraint<F>"],["impl<F: Field> From<(&'static str, Expression<F>)> for Constraint<F>"],["impl<F: Field> From<Expression<F>> for Vec<Constraint<F>>"],["impl From<Error> for Error"],["impl<'params, E: MultiMillerLoop + Debug> From<&'params ParamsKZG<E>> for DualMSM<'params, E>"],["impl From<(Any, usize)> for Column"],["impl From<Column<Any>> for Column"],["impl From<(Column, i32)> for VirtualCell"],["impl From<(&'static str, Column, i32)> for VirtualCell"],["impl From<VirtualCell> for VirtualCell"],["impl From<(usize, &'static str)> for Gate"],["impl From<(Gate, usize, &'static str)> for Constraint"],["impl From<(usize, String)> for Region"],["impl From<(usize, &str)> for Region"]], +"halo2curves":[["impl<'a> From<&'a G1Affine> for G1"],["impl From<G1Affine> for G1"],["impl<'a> From<&'a G1> for G1Affine"],["impl From<G1> for G1Affine"],["impl<'a> From<&'a G2Affine> for G2"],["impl From<G2Affine> for G2"],["impl<'a> From<&'a G2> for G2Affine"],["impl From<G2> for G2Affine"],["impl From<G2Affine> for G2Prepared"],["impl From<bool> for Fq"],["impl From<u64> for Fq"],["impl From<[u64; 4]> for Fq"],["impl From<Fq> for [u64; 4]"],["impl From<Fq> for [u8; 32]"],["impl<'a> From<&'a Fq> for [u8; 32]"],["impl From<Fq> for i128"],["impl From<Fq2> for [u8; 64]"],["impl<'a> From<&'a Fq2> for [u8; 64]"],["impl From<bool> for Fq2"],["impl From<u64> for Fq2"],["impl From<bool> for Fr"],["impl From<u64> for Fr"],["impl From<[u64; 4]> for Fr"],["impl From<Fr> for [u64; 4]"],["impl From<Fr> for [u8; 32]"],["impl<'a> From<&'a Fr> for [u8; 32]"],["impl From<Fr> for i128"],["impl<'a> From<&'a Secp256k1Affine> for Secp256k1"],["impl From<Secp256k1Affine> for Secp256k1"],["impl<'a> From<&'a Secp256k1> for Secp256k1Affine"],["impl From<Secp256k1> for Secp256k1Affine"],["impl From<bool> for Fp"],["impl From<u64> for Fp"],["impl From<[u64; 4]> for Fp"],["impl From<Fp> for [u64; 4]"],["impl From<Fp> for [u8; 32]"],["impl<'a> From<&'a Fp> for [u8; 32]"],["impl From<Fp> for i128"],["impl From<bool> for Fq"],["impl From<u64> for Fq"],["impl From<[u64; 4]> for Fq"],["impl From<Fq> for [u64; 4]"],["impl From<Fq> for [u8; 32]"],["impl<'a> From<&'a Fq> for [u8; 32]"],["impl From<Fq> for i128"]], +"poseidon":[["impl<F: FieldExt, const T: usize, const RATE: usize> From<MDSMatrix<F, T, RATE>> for SparseMDSMatrix<F, T, RATE>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/convert/trait.TryFrom.js b/docs/implementors/core/convert/trait.TryFrom.js new file mode 100644 index 0000000000..0ed648f260 --- /dev/null +++ b/docs/implementors/core/convert/trait.TryFrom.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[["impl TryFrom<Column<Any>> for Column<Advice>"],["impl TryFrom<Column<Any>> for Column<Fixed>"],["impl TryFrom<Column<Any>> for Column<Instance>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/default/trait.Default.js b/docs/implementors/core/default/trait.Default.js new file mode 100644 index 0000000000..910b68efe5 --- /dev/null +++ b/docs/implementors/core/default/trait.Default.js @@ -0,0 +1,5 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<V> Default for Value<V>"],["impl Default for Advice"],["impl<F: Field> Default for ConstraintSystem<F>"],["impl<C: Default + CurveAffine> Default for BatchVerifier<C>"],["impl<F: FieldExt> Default for Blind<F>"],["impl<E: Default + Engine> Default for MSMKZG<E>where
    E::Scalar: Default,
    E::G1: Default,
"]], +"halo2curves":[["impl Default for G1Compressed"],["impl Default for G1"],["impl Default for G1Affine"],["impl Default for G2Compressed"],["impl Default for G2"],["impl Default for G2Affine"],["impl Default for Gt"],["impl Default for Fq"],["impl Default for Fq12"],["impl Default for Fq2"],["impl Default for Fq2Bytes"],["impl Default for Fq6"],["impl Default for Fr"],["impl Default for Secp256k1Compressed"],["impl Default for Secp256k1"],["impl Default for Secp256k1Affine"],["impl Default for Fp"],["impl Default for Fq"]], +"poseidon":[["impl<F: FieldExt, const T: usize> Default for State<F, T>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/error/trait.Error.js b/docs/implementors/core/error/trait.Error.js new file mode 100644 index 0000000000..b505e6ffdb --- /dev/null +++ b/docs/implementors/core/error/trait.Error.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[["impl Error for Error"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/fmt/trait.Debug.js b/docs/implementors/core/fmt/trait.Debug.js new file mode 100644 index 0000000000..237042463c --- /dev/null +++ b/docs/implementors/core/fmt/trait.Debug.js @@ -0,0 +1,5 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<V: Debug> Debug for Value<V>"],["impl Debug for SimpleFloorPlanner"],["impl Debug for RegionShape"],["impl Debug for RegionColumn"],["impl Debug for RegionIndex"],["impl Debug for RegionStart"],["impl Debug for Cell"],["impl<V: Debug, F: Debug + Field> Debug for AssignedCell<V, F>"],["impl<'r, F: Debug + Field> Debug for Region<'r, F>"],["impl<'r, F: Debug + Field> Debug for Table<'r, F>"],["impl<'a, F: Debug + Field, L: Debug + Layouter<F> + 'a> Debug for NamespacedLayouter<'a, F, L>"],["impl<F: Debug> Debug for Assigned<F>"],["impl<C: Debug + ColumnType> Debug for Column<C>"],["impl Debug for FirstPhase"],["impl Debug for SecondPhase"],["impl Debug for ThirdPhase"],["impl Debug for Advice"],["impl Debug for Fixed"],["impl Debug for Instance"],["impl Debug for Any"],["impl Debug for Selector"],["impl Debug for FixedQuery"],["impl Debug for AdviceQuery"],["impl Debug for InstanceQuery"],["impl Debug for TableColumn"],["impl Debug for Challenge"],["impl<F: Debug> Debug for Expression<F>"],["impl Debug for VirtualCell"],["impl<F: Debug + Field> Debug for Constraint<F>"],["impl<F: Debug + Field, C: Debug + Into<Constraint<F>>, Iter: Debug + IntoIterator<Item = C>> Debug for Constraints<F, C, Iter>"],["impl<F: Debug + Field> Debug for Gate<F>"],["impl<F: Debug + Field> Debug for ConstraintSystem<F>"],["impl<'a, F: Field> Debug for PinnedConstraintSystem<'a, F>"],["impl<'a, F: Debug + Field> Debug for VirtualCells<'a, F>"],["impl Debug for Error"],["impl<C: Debug + CurveAffine> Debug for BatchVerifier<C>"],["impl<C: Debug + CurveAffine> Debug for VerifyingKey<C>where
    C::Scalar: Debug,
    C::Scalar: Debug,
    C::Scalar: Debug,
"],["impl<'a, C: Debug + CurveAffine> Debug for PinnedVerificationKey<'a, C>where
    C::Scalar: Debug,
    C::Scalar: Debug,
"],["impl<C: Debug + CurveAffine> Debug for ProvingKey<C>where
    C::Scalar: Debug,
    C::Scalar: Debug,
    C::Scalar: Debug,
    C::Scalar: Debug,
    C::Scalar: Debug,
    C::Scalar: Debug,
"],["impl<F: Debug> Debug for Blind<F>"],["impl<G: Debug + Group> Debug for EvaluationDomain<G>where
    G::Scalar: Debug,
    G::Scalar: Debug,
    G::Scalar: Debug,
    G::Scalar: Debug,
    G::Scalar: Debug,
    G::Scalar: Debug,
    G::Scalar: Debug,
    G::Scalar: Debug,
    G::Scalar: Debug,
    G::Scalar: Debug,
"],["impl<'a, G: Debug + Group> Debug for PinnedEvaluationDomain<'a, G>where
    G::Scalar: Debug,
"],["impl<'com, C: Debug + CurveAffine> Debug for ProverQuery<'com, C>where
    C::Scalar: Debug,
    C::Scalar: Debug,
    C::Scalar: Debug,
"],["impl<'com, C: Debug + CurveAffine, M: Debug + MSM<C>> Debug for VerifierQuery<'com, C, M>where
    C::Scalar: Debug,
    C::Scalar: Debug,
"],["impl<C: Debug + CurveAffine> Debug for ParamsIPA<C>"],["impl<C: Debug + CurveAffine> Debug for IPACommitmentScheme<C>"],["impl<'params, C: Debug + CurveAffine> Debug for MSMIPA<'params, C>where
    C::Scalar: Debug,
    C::Scalar: Debug,
    C::Scalar: Debug,
    C::Base: Debug,
    C::Scalar: Debug,
    C::Base: Debug,
"],["impl<'params, C: Debug + CurveAffine> Debug for ProverIPA<'params, C>"],["impl<'params, C: Debug + CurveAffine> Debug for VerifierIPA<'params, C>"],["impl<'params, C: Debug + CurveAffine> Debug for GuardIPA<'params, C>where
    C::Scalar: Debug,
    C::Scalar: Debug,
    C::Scalar: Debug,
"],["impl<C: Debug + CurveAffine> Debug for Accumulator<C>where
    C::Scalar: Debug,
"],["impl<'params, C: Debug + CurveAffine> Debug for AccumulatorStrategy<'params, C>"],["impl<'params, C: Debug + CurveAffine> Debug for SingleStrategy<'params, C>"],["impl<E: Debug + Engine> Debug for ParamsKZG<E>where
    E::G1Affine: Debug,
    E::G1Affine: Debug,
    E::G2Affine: Debug,
    E::G2Affine: Debug,
"],["impl<E: Debug + Engine> Debug for KZGCommitmentScheme<E>"],["impl<E: Debug + Engine> Debug for MSMKZG<E>where
    E::Scalar: Debug,
    E::G1: Debug,
"],["impl<'a, E: Debug + Engine> Debug for DualMSM<'a, E>"],["impl<'params, E: Debug + Engine> Debug for ProverGWC<'params, E>"],["impl<'params, E: Debug + Engine> Debug for VerifierGWC<'params, E>"],["impl<'a, E: Debug + Engine> Debug for ProverSHPLONK<'a, E>"],["impl<'params, E: Debug + Engine> Debug for VerifierSHPLONK<'params, E>"],["impl<'params, E: Debug + MultiMillerLoop + Debug> Debug for GuardKZG<'params, E>"],["impl<'params, E: Debug + Engine> Debug for AccumulatorStrategy<'params, E>"],["impl<'params, E: Debug + Engine> Debug for SingleStrategy<'params, E>"],["impl Debug for Error"],["impl Debug for Coeff"],["impl Debug for LagrangeCoeff"],["impl Debug for ExtendedLagrangeCoeff"],["impl<F: Debug, B: Debug> Debug for Polynomial<F, B>"],["impl Debug for Rotation"],["impl<R: Debug + Read, C: Debug + CurveAffine, E: Debug + EncodedChallenge<C>> Debug for Blake2bRead<R, C, E>"],["impl<W: Debug + Write, C: Debug + CurveAffine, E: Debug + EncodedChallenge<C>> Debug for Blake2bWrite<W, C, E>"],["impl<C: Debug + CurveAffine, T: Debug> Debug for ChallengeScalar<C, T>where
    C::Scalar: Debug,
"],["impl<C: Debug + CurveAffine> Debug for Challenge255<C>"],["impl Debug for Column"],["impl Debug for VirtualCell"],["impl Debug for Gate"],["impl Debug for Constraint"],["impl Debug for Region"],["impl Debug for FailureLocation"],["impl Debug for VerifyFailure"],["impl Debug for CircuitGates"],["impl<F: Debug + Group + Field> Debug for MockProver<F>"],["impl Debug for SerdeFormat"]], +"halo2curves":[["impl Debug for G1"],["impl Debug for G1Compressed"],["impl Debug for G1Affine"],["impl Debug for G2"],["impl Debug for G2Compressed"],["impl Debug for G2Affine"],["impl Debug for Gt"],["impl Debug for G2Prepared"],["impl Debug for Bn256"],["impl Debug for Fq"],["impl Debug for Fq12"],["impl Debug for Fq2"],["impl Debug for Fq2Bytes"],["impl Debug for Fq6"],["impl Debug for Fr"],["impl Debug for LegendreSymbol"],["impl Debug for Secp256k1"],["impl Debug for Secp256k1Compressed"],["impl Debug for Secp256k1Affine"],["impl Debug for Fp"],["impl Debug for Fq"]], +"poseidon":[["impl<F: Debug + FieldExt, const T: usize, const RATE: usize> Debug for Poseidon<F, T, RATE>"],["impl<F: Debug + FieldExt, const T: usize> Debug for State<F, T>"],["impl<F: Debug + FieldExt, const T: usize, const RATE: usize> Debug for Spec<F, T, RATE>"],["impl<F: Debug + FieldExt, const T: usize, const RATE: usize> Debug for MDSMatrices<F, T, RATE>"],["impl<F: Debug + FieldExt, const T: usize, const RATE: usize> Debug for MDSMatrix<F, T, RATE>"],["impl<F: Debug + FieldExt, const T: usize, const RATE: usize> Debug for SparseMDSMatrix<F, T, RATE>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/fmt/trait.Display.js b/docs/implementors/core/fmt/trait.Display.js new file mode 100644 index 0000000000..93d0067d41 --- /dev/null +++ b/docs/implementors/core/fmt/trait.Display.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[["impl Display for Error"],["impl Display for Column"],["impl Display for VirtualCell"],["impl Display for Gate"],["impl Display for Constraint"],["impl Display for Region"],["impl Display for FailureLocation"],["impl Display for VerifyFailure"],["impl Display for CircuitGates"]], +"halo2curves":[["impl Display for Gt"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/hash/trait.Hash.js b/docs/implementors/core/hash/trait.Hash.js new file mode 100644 index 0000000000..3b3a06c5e3 --- /dev/null +++ b/docs/implementors/core/hash/trait.Hash.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[["impl Hash for RegionColumn"],["impl<C: Hash + ColumnType> Hash for Column<C>"],["impl Hash for Advice"],["impl Hash for Fixed"],["impl Hash for Instance"],["impl Hash for Any"],["impl Hash for Selector"],["impl Hash for TableColumn"],["impl Hash for Challenge"]], +"halo2curves":[["impl Hash for G1Affine"],["impl Hash for G1Compressed"],["impl Hash for G2Affine"],["impl Hash for G2Compressed"],["impl Hash for Fq"],["impl Hash for Fq12"],["impl Hash for Fq2"],["impl Hash for Fq6"],["impl Hash for Fr"],["impl Hash for Secp256k1Affine"],["impl Hash for Secp256k1Compressed"],["impl Hash for Fp"],["impl Hash for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/iter/traits/accum/trait.Sum.js b/docs/implementors/core/iter/traits/accum/trait.Sum.js new file mode 100644 index 0000000000..25b5797e98 --- /dev/null +++ b/docs/implementors/core/iter/traits/accum/trait.Sum.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl<T> Sum<T> for G1where
    T: Borrow<G1>,
"],["impl<T> Sum<T> for G2where
    T: Borrow<G2>,
"],["impl<T> Sum<T> for Gtwhere
    T: Borrow<Gt>,
"],["impl<T> Sum<T> for Secp256k1where
    T: Borrow<Secp256k1>,
"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/iter/traits/collect/trait.FromIterator.js b/docs/implementors/core/iter/traits/collect/trait.FromIterator.js new file mode 100644 index 0000000000..8884858439 --- /dev/null +++ b/docs/implementors/core/iter/traits/collect/trait.FromIterator.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<A, V: FromIterator<A>> FromIterator<Value<A>> for Value<V>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/iter/traits/collect/trait.IntoIterator.js b/docs/implementors/core/iter/traits/collect/trait.IntoIterator.js new file mode 100644 index 0000000000..bb5e180192 --- /dev/null +++ b/docs/implementors/core/iter/traits/collect/trait.IntoIterator.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<F: Field, C: Into<Constraint<F>>, Iter: IntoIterator<Item = C>> IntoIterator for Constraints<F, C, Iter>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/marker/trait.Copy.js b/docs/implementors/core/marker/trait.Copy.js new file mode 100644 index 0000000000..0f3fbf2b13 --- /dev/null +++ b/docs/implementors/core/marker/trait.Copy.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<V: Copy> Copy for Value<V>"],["impl Copy for RegionColumn"],["impl Copy for RegionIndex"],["impl Copy for RegionStart"],["impl Copy for Cell"],["impl<F: Copy> Copy for Assigned<F>"],["impl<C: Copy + ColumnType> Copy for Column<C>"],["impl Copy for Advice"],["impl Copy for Fixed"],["impl Copy for Instance"],["impl Copy for Any"],["impl Copy for Selector"],["impl Copy for FixedQuery"],["impl Copy for AdviceQuery"],["impl Copy for InstanceQuery"],["impl Copy for TableColumn"],["impl Copy for Challenge"],["impl<F: Copy> Copy for Blind<F>"],["impl Copy for Coeff"],["impl Copy for LagrangeCoeff"],["impl Copy for ExtendedLagrangeCoeff"],["impl Copy for Rotation"],["impl<C: Copy + CurveAffine, T: Copy> Copy for ChallengeScalar<C, T>where
    C::Scalar: Copy,
"],["impl<C: Copy + CurveAffine> Copy for Challenge255<C>"],["impl Copy for Column"],["impl Copy for SerdeFormat"]], +"halo2curves":[["impl Copy for G1"],["impl Copy for G1Affine"],["impl Copy for G1Compressed"],["impl Copy for G2"],["impl Copy for G2Affine"],["impl Copy for G2Compressed"],["impl Copy for Gt"],["impl Copy for Fq"],["impl Copy for Fq12"],["impl Copy for Fq2"],["impl Copy for Fq2Bytes"],["impl Copy for Fq6"],["impl Copy for Fr"],["impl Copy for Secp256k1"],["impl Copy for Secp256k1Affine"],["impl Copy for Secp256k1Compressed"],["impl Copy for Fp"],["impl Copy for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/marker/trait.Freeze.js b/docs/implementors/core/marker/trait.Freeze.js new file mode 100644 index 0000000000..2e6451994c --- /dev/null +++ b/docs/implementors/core/marker/trait.Freeze.js @@ -0,0 +1,5 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<V> Freeze for Value<V>where
    V: Freeze,
",1,["halo2_proofs::circuit::value::Value"]],["impl Freeze for SimpleFloorPlanner",1,["halo2_proofs::circuit::floor_planner::single_pass::SimpleFloorPlanner"]],["impl Freeze for RegionShape",1,["halo2_proofs::circuit::layouter::RegionShape"]],["impl Freeze for RegionColumn",1,["halo2_proofs::circuit::layouter::RegionColumn"]],["impl Freeze for RegionIndex",1,["halo2_proofs::circuit::RegionIndex"]],["impl Freeze for RegionStart",1,["halo2_proofs::circuit::RegionStart"]],["impl Freeze for Cell",1,["halo2_proofs::circuit::Cell"]],["impl<V, F> Freeze for AssignedCell<V, F>where
    V: Freeze,
",1,["halo2_proofs::circuit::AssignedCell"]],["impl<'r, F> Freeze for Region<'r, F>",1,["halo2_proofs::circuit::Region"]],["impl<'r, F> Freeze for Table<'r, F>",1,["halo2_proofs::circuit::Table"]],["impl<'a, F, L> Freeze for NamespacedLayouter<'a, F, L>",1,["halo2_proofs::circuit::NamespacedLayouter"]],["impl<F> Freeze for Assigned<F>where
    F: Freeze,
",1,["halo2_proofs::plonk::assigned::Assigned"]],["impl<C> Freeze for Column<C>where
    C: Freeze,
",1,["halo2_proofs::plonk::circuit::Column"]],["impl Freeze for FirstPhase",1,["halo2_proofs::plonk::circuit::FirstPhase"]],["impl Freeze for SecondPhase",1,["halo2_proofs::plonk::circuit::SecondPhase"]],["impl Freeze for ThirdPhase",1,["halo2_proofs::plonk::circuit::ThirdPhase"]],["impl Freeze for Advice",1,["halo2_proofs::plonk::circuit::Advice"]],["impl Freeze for Fixed",1,["halo2_proofs::plonk::circuit::Fixed"]],["impl Freeze for Instance",1,["halo2_proofs::plonk::circuit::Instance"]],["impl Freeze for Any",1,["halo2_proofs::plonk::circuit::Any"]],["impl Freeze for Selector",1,["halo2_proofs::plonk::circuit::Selector"]],["impl Freeze for FixedQuery",1,["halo2_proofs::plonk::circuit::FixedQuery"]],["impl Freeze for AdviceQuery",1,["halo2_proofs::plonk::circuit::AdviceQuery"]],["impl Freeze for InstanceQuery",1,["halo2_proofs::plonk::circuit::InstanceQuery"]],["impl Freeze for TableColumn",1,["halo2_proofs::plonk::circuit::TableColumn"]],["impl Freeze for Challenge",1,["halo2_proofs::plonk::circuit::Challenge"]],["impl<F> Freeze for Expression<F>where
    F: Freeze,
",1,["halo2_proofs::plonk::circuit::Expression"]],["impl Freeze for VirtualCell",1,["halo2_proofs::plonk::circuit::VirtualCell"]],["impl<F> Freeze for Constraint<F>where
    F: Freeze,
",1,["halo2_proofs::plonk::circuit::Constraint"]],["impl<F, C, Iter> Freeze for Constraints<F, C, Iter>where
    F: Freeze,
    Iter: Freeze,
",1,["halo2_proofs::plonk::circuit::Constraints"]],["impl<F> Freeze for Gate<F>",1,["halo2_proofs::plonk::circuit::Gate"]],["impl<F> Freeze for ConstraintSystem<F>",1,["halo2_proofs::plonk::circuit::ConstraintSystem"]],["impl<'a, F> Freeze for PinnedConstraintSystem<'a, F>",1,["halo2_proofs::plonk::circuit::PinnedConstraintSystem"]],["impl<'a, F> Freeze for VirtualCells<'a, F>",1,["halo2_proofs::plonk::circuit::VirtualCells"]],["impl Freeze for Error",1,["halo2_proofs::plonk::error::Error"]],["impl<C> Freeze for BatchVerifier<C>",1,["halo2_proofs::plonk::verifier::batch::BatchVerifier"]],["impl<C> Freeze for VerifyingKey<C>where
    <C as CurveAffine>::ScalarExt: Freeze,
",1,["halo2_proofs::plonk::VerifyingKey"]],["impl<'a, C> Freeze for PinnedVerificationKey<'a, C>",1,["halo2_proofs::plonk::PinnedVerificationKey"]],["impl<C> Freeze for ProvingKey<C>where
    <C as CurveAffine>::ScalarExt: Freeze,
",1,["halo2_proofs::plonk::ProvingKey"]],["impl<F> Freeze for Blind<F>where
    F: Freeze,
",1,["halo2_proofs::poly::commitment::Blind"]],["impl<G> Freeze for EvaluationDomain<G>where
    <G as Group>::Scalar: Freeze,
",1,["halo2_proofs::poly::domain::EvaluationDomain"]],["impl<'a, G> Freeze for PinnedEvaluationDomain<'a, G>",1,["halo2_proofs::poly::domain::PinnedEvaluationDomain"]],["impl<'com, C> Freeze for ProverQuery<'com, C>where
    <C as CurveAffine>::ScalarExt: Freeze,
",1,["halo2_proofs::poly::query::ProverQuery"]],["impl<'com, C, M> Freeze for VerifierQuery<'com, C, M>where
    <C as CurveAffine>::ScalarExt: Freeze,
",1,["halo2_proofs::poly::query::VerifierQuery"]],["impl<C> Freeze for ParamsIPA<C>where
    C: Freeze,
",1,["halo2_proofs::poly::ipa::commitment::ParamsIPA"]],["impl<C> Freeze for IPACommitmentScheme<C>",1,["halo2_proofs::poly::ipa::commitment::IPACommitmentScheme"]],["impl<'params, C> Freeze for MSMIPA<'params, C>where
    <C as CurveAffine>::ScalarExt: Freeze,
",1,["halo2_proofs::poly::ipa::msm::MSMIPA"]],["impl<'params, C> Freeze for ProverIPA<'params, C>",1,["halo2_proofs::poly::ipa::multiopen::prover::ProverIPA"]],["impl<'params, C> Freeze for VerifierIPA<'params, C>",1,["halo2_proofs::poly::ipa::multiopen::verifier::VerifierIPA"]],["impl<'params, C> Freeze for GuardIPA<'params, C>where
    <C as CurveAffine>::ScalarExt: Freeze,
",1,["halo2_proofs::poly::ipa::strategy::GuardIPA"]],["impl<C> Freeze for Accumulator<C>where
    C: Freeze,
",1,["halo2_proofs::poly::ipa::strategy::Accumulator"]],["impl<'params, C> Freeze for AccumulatorStrategy<'params, C>where
    <C as CurveAffine>::ScalarExt: Freeze,
",1,["halo2_proofs::poly::ipa::strategy::AccumulatorStrategy"]],["impl<'params, C> Freeze for SingleStrategy<'params, C>where
    <C as CurveAffine>::ScalarExt: Freeze,
",1,["halo2_proofs::poly::ipa::strategy::SingleStrategy"]],["impl<E> Freeze for ParamsKZG<E>where
    <E as Engine>::G2Affine: Freeze,
",1,["halo2_proofs::poly::kzg::commitment::ParamsKZG"]],["impl<E> Freeze for KZGCommitmentScheme<E>",1,["halo2_proofs::poly::kzg::commitment::KZGCommitmentScheme"]],["impl<E> Freeze for MSMKZG<E>",1,["halo2_proofs::poly::kzg::msm::MSMKZG"]],["impl<'a, E> Freeze for DualMSM<'a, E>",1,["halo2_proofs::poly::kzg::msm::DualMSM"]],["impl<'params, E> Freeze for ProverGWC<'params, E>",1,["halo2_proofs::poly::kzg::multiopen::gwc::prover::ProverGWC"]],["impl<'params, E> Freeze for VerifierGWC<'params, E>",1,["halo2_proofs::poly::kzg::multiopen::gwc::verifier::VerifierGWC"]],["impl<'a, E> Freeze for ProverSHPLONK<'a, E>",1,["halo2_proofs::poly::kzg::multiopen::shplonk::prover::ProverSHPLONK"]],["impl<'params, E> Freeze for VerifierSHPLONK<'params, E>",1,["halo2_proofs::poly::kzg::multiopen::shplonk::verifier::VerifierSHPLONK"]],["impl<'params, E> Freeze for GuardKZG<'params, E>",1,["halo2_proofs::poly::kzg::strategy::GuardKZG"]],["impl<'params, E> Freeze for AccumulatorStrategy<'params, E>",1,["halo2_proofs::poly::kzg::strategy::AccumulatorStrategy"]],["impl<'params, E> Freeze for SingleStrategy<'params, E>",1,["halo2_proofs::poly::kzg::strategy::SingleStrategy"]],["impl Freeze for Error",1,["halo2_proofs::poly::Error"]],["impl Freeze for Coeff",1,["halo2_proofs::poly::Coeff"]],["impl Freeze for LagrangeCoeff",1,["halo2_proofs::poly::LagrangeCoeff"]],["impl Freeze for ExtendedLagrangeCoeff",1,["halo2_proofs::poly::ExtendedLagrangeCoeff"]],["impl<F, B> Freeze for Polynomial<F, B>",1,["halo2_proofs::poly::Polynomial"]],["impl Freeze for Rotation",1,["halo2_proofs::poly::Rotation"]],["impl<R, C, E> Freeze for Blake2bRead<R, C, E>where
    R: Freeze,
",1,["halo2_proofs::transcript::Blake2bRead"]],["impl<W, C, E> Freeze for Blake2bWrite<W, C, E>where
    W: Freeze,
",1,["halo2_proofs::transcript::Blake2bWrite"]],["impl<C, T> Freeze for ChallengeScalar<C, T>where
    <C as CurveAffine>::ScalarExt: Freeze,
",1,["halo2_proofs::transcript::ChallengeScalar"]],["impl<C> Freeze for Challenge255<C>",1,["halo2_proofs::transcript::Challenge255"]],["impl Freeze for Column",1,["halo2_proofs::dev::metadata::Column"]],["impl Freeze for VirtualCell",1,["halo2_proofs::dev::metadata::VirtualCell"]],["impl Freeze for Gate",1,["halo2_proofs::dev::metadata::Gate"]],["impl Freeze for Constraint",1,["halo2_proofs::dev::metadata::Constraint"]],["impl Freeze for Region",1,["halo2_proofs::dev::metadata::Region"]],["impl Freeze for FailureLocation",1,["halo2_proofs::dev::failure::FailureLocation"]],["impl Freeze for VerifyFailure",1,["halo2_proofs::dev::failure::VerifyFailure"]],["impl Freeze for CircuitGates",1,["halo2_proofs::dev::gates::CircuitGates"]],["impl<F> Freeze for MockProver<F>",1,["halo2_proofs::dev::MockProver"]],["impl Freeze for SerdeFormat",1,["halo2_proofs::helpers::SerdeFormat"]]], +"halo2curves":[["impl Freeze for G1",1,["halo2curves::bn256::curve::G1"]],["impl Freeze for G1Affine",1,["halo2curves::bn256::curve::G1Affine"]],["impl Freeze for G1Compressed",1,["halo2curves::bn256::curve::G1Compressed"]],["impl Freeze for G2",1,["halo2curves::bn256::curve::G2"]],["impl Freeze for G2Affine",1,["halo2curves::bn256::curve::G2Affine"]],["impl Freeze for G2Compressed",1,["halo2curves::bn256::curve::G2Compressed"]],["impl Freeze for Gt",1,["halo2curves::bn256::engine::Gt"]],["impl Freeze for G2Prepared",1,["halo2curves::bn256::engine::G2Prepared"]],["impl Freeze for Bn256",1,["halo2curves::bn256::engine::Bn256"]],["impl Freeze for Fq",1,["halo2curves::bn256::fq::Fq"]],["impl Freeze for Fq12",1,["halo2curves::bn256::fq12::Fq12"]],["impl Freeze for Fq2",1,["halo2curves::bn256::fq2::Fq2"]],["impl Freeze for Fq2Bytes",1,["halo2curves::bn256::fq2::Fq2Bytes"]],["impl Freeze for Fq6",1,["halo2curves::bn256::fq6::Fq6"]],["impl Freeze for Fr",1,["halo2curves::bn256::fr::Fr"]],["impl Freeze for LegendreSymbol",1,["halo2curves::bn256::LegendreSymbol"]],["impl Freeze for Secp256k1",1,["halo2curves::secp256k1::curve::Secp256k1"]],["impl Freeze for Secp256k1Affine",1,["halo2curves::secp256k1::curve::Secp256k1Affine"]],["impl Freeze for Secp256k1Compressed",1,["halo2curves::secp256k1::curve::Secp256k1Compressed"]],["impl Freeze for Fp",1,["halo2curves::secp256k1::fp::Fp"]],["impl Freeze for Fq",1,["halo2curves::secp256k1::fq::Fq"]]], +"poseidon":[["impl<F, const T: usize, const RATE: usize> Freeze for Poseidon<F, T, RATE>where
    F: Freeze,
",1,["poseidon::poseidon::Poseidon"]],["impl<F, const T: usize> Freeze for State<F, T>where
    F: Freeze,
",1,["poseidon::spec::State"]],["impl<F, const T: usize, const RATE: usize> Freeze for Spec<F, T, RATE>where
    F: Freeze,
",1,["poseidon::spec::Spec"]],["impl<F, const T: usize, const RATE: usize> Freeze for MDSMatrices<F, T, RATE>where
    F: Freeze,
",1,["poseidon::spec::MDSMatrices"]],["impl<F, const T: usize, const RATE: usize> Freeze for MDSMatrix<F, T, RATE>where
    F: Freeze,
",1,["poseidon::spec::MDSMatrix"]],["impl<F, const T: usize, const RATE: usize> Freeze for SparseMDSMatrix<F, T, RATE>where
    F: Freeze,
",1,["poseidon::spec::SparseMDSMatrix"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/marker/trait.Send.js b/docs/implementors/core/marker/trait.Send.js new file mode 100644 index 0000000000..c5c70fd7d0 --- /dev/null +++ b/docs/implementors/core/marker/trait.Send.js @@ -0,0 +1,5 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<V> Send for Value<V>where
    V: Send,
",1,["halo2_proofs::circuit::value::Value"]],["impl Send for SimpleFloorPlanner",1,["halo2_proofs::circuit::floor_planner::single_pass::SimpleFloorPlanner"]],["impl Send for RegionShape",1,["halo2_proofs::circuit::layouter::RegionShape"]],["impl Send for RegionColumn",1,["halo2_proofs::circuit::layouter::RegionColumn"]],["impl Send for RegionIndex",1,["halo2_proofs::circuit::RegionIndex"]],["impl Send for RegionStart",1,["halo2_proofs::circuit::RegionStart"]],["impl Send for Cell",1,["halo2_proofs::circuit::Cell"]],["impl<V, F> Send for AssignedCell<V, F>where
    V: Send,
",1,["halo2_proofs::circuit::AssignedCell"]],["impl<'r, F> !Send for Region<'r, F>",1,["halo2_proofs::circuit::Region"]],["impl<'r, F> !Send for Table<'r, F>",1,["halo2_proofs::circuit::Table"]],["impl<'a, F, L> Send for NamespacedLayouter<'a, F, L>where
    L: Send,
",1,["halo2_proofs::circuit::NamespacedLayouter"]],["impl<F> Send for Assigned<F>where
    F: Send,
",1,["halo2_proofs::plonk::assigned::Assigned"]],["impl<C> Send for Column<C>where
    C: Send,
",1,["halo2_proofs::plonk::circuit::Column"]],["impl Send for FirstPhase",1,["halo2_proofs::plonk::circuit::FirstPhase"]],["impl Send for SecondPhase",1,["halo2_proofs::plonk::circuit::SecondPhase"]],["impl Send for ThirdPhase",1,["halo2_proofs::plonk::circuit::ThirdPhase"]],["impl Send for Advice",1,["halo2_proofs::plonk::circuit::Advice"]],["impl Send for Fixed",1,["halo2_proofs::plonk::circuit::Fixed"]],["impl Send for Instance",1,["halo2_proofs::plonk::circuit::Instance"]],["impl Send for Any",1,["halo2_proofs::plonk::circuit::Any"]],["impl Send for Selector",1,["halo2_proofs::plonk::circuit::Selector"]],["impl Send for FixedQuery",1,["halo2_proofs::plonk::circuit::FixedQuery"]],["impl Send for AdviceQuery",1,["halo2_proofs::plonk::circuit::AdviceQuery"]],["impl Send for InstanceQuery",1,["halo2_proofs::plonk::circuit::InstanceQuery"]],["impl Send for TableColumn",1,["halo2_proofs::plonk::circuit::TableColumn"]],["impl Send for Challenge",1,["halo2_proofs::plonk::circuit::Challenge"]],["impl<F> Send for Expression<F>where
    F: Send,
",1,["halo2_proofs::plonk::circuit::Expression"]],["impl Send for VirtualCell",1,["halo2_proofs::plonk::circuit::VirtualCell"]],["impl<F> Send for Constraint<F>",1,["halo2_proofs::plonk::circuit::Constraint"]],["impl<F, C, Iter> Send for Constraints<F, C, Iter>where
    Iter: Send,
",1,["halo2_proofs::plonk::circuit::Constraints"]],["impl<F> Send for Gate<F>",1,["halo2_proofs::plonk::circuit::Gate"]],["impl<F> Send for ConstraintSystem<F>",1,["halo2_proofs::plonk::circuit::ConstraintSystem"]],["impl<'a, F> Send for PinnedConstraintSystem<'a, F>",1,["halo2_proofs::plonk::circuit::PinnedConstraintSystem"]],["impl<'a, F> Send for VirtualCells<'a, F>",1,["halo2_proofs::plonk::circuit::VirtualCells"]],["impl Send for Error",1,["halo2_proofs::plonk::error::Error"]],["impl<C> Send for BatchVerifier<C>",1,["halo2_proofs::plonk::verifier::batch::BatchVerifier"]],["impl<C> Send for VerifyingKey<C>",1,["halo2_proofs::plonk::VerifyingKey"]],["impl<'a, C> Send for PinnedVerificationKey<'a, C>",1,["halo2_proofs::plonk::PinnedVerificationKey"]],["impl<C> Send for ProvingKey<C>",1,["halo2_proofs::plonk::ProvingKey"]],["impl<F> Send for Blind<F>where
    F: Send,
",1,["halo2_proofs::poly::commitment::Blind"]],["impl<G> Send for EvaluationDomain<G>",1,["halo2_proofs::poly::domain::EvaluationDomain"]],["impl<'a, G> Send for PinnedEvaluationDomain<'a, G>",1,["halo2_proofs::poly::domain::PinnedEvaluationDomain"]],["impl<'com, C> Send for ProverQuery<'com, C>",1,["halo2_proofs::poly::query::ProverQuery"]],["impl<'com, C, M> Send for VerifierQuery<'com, C, M>",1,["halo2_proofs::poly::query::VerifierQuery"]],["impl<C> Send for ParamsIPA<C>",1,["halo2_proofs::poly::ipa::commitment::ParamsIPA"]],["impl<C> Send for IPACommitmentScheme<C>",1,["halo2_proofs::poly::ipa::commitment::IPACommitmentScheme"]],["impl<'params, C> Send for MSMIPA<'params, C>",1,["halo2_proofs::poly::ipa::msm::MSMIPA"]],["impl<'params, C> Send for ProverIPA<'params, C>",1,["halo2_proofs::poly::ipa::multiopen::prover::ProverIPA"]],["impl<'params, C> Send for VerifierIPA<'params, C>",1,["halo2_proofs::poly::ipa::multiopen::verifier::VerifierIPA"]],["impl<'params, C> Send for GuardIPA<'params, C>",1,["halo2_proofs::poly::ipa::strategy::GuardIPA"]],["impl<C> Send for Accumulator<C>",1,["halo2_proofs::poly::ipa::strategy::Accumulator"]],["impl<'params, C> Send for AccumulatorStrategy<'params, C>",1,["halo2_proofs::poly::ipa::strategy::AccumulatorStrategy"]],["impl<'params, C> Send for SingleStrategy<'params, C>",1,["halo2_proofs::poly::ipa::strategy::SingleStrategy"]],["impl<E> Send for ParamsKZG<E>",1,["halo2_proofs::poly::kzg::commitment::ParamsKZG"]],["impl<E> Send for KZGCommitmentScheme<E>where
    E: Send,
",1,["halo2_proofs::poly::kzg::commitment::KZGCommitmentScheme"]],["impl<E> Send for MSMKZG<E>",1,["halo2_proofs::poly::kzg::msm::MSMKZG"]],["impl<'a, E> Send for DualMSM<'a, E>",1,["halo2_proofs::poly::kzg::msm::DualMSM"]],["impl<'params, E> Send for ProverGWC<'params, E>",1,["halo2_proofs::poly::kzg::multiopen::gwc::prover::ProverGWC"]],["impl<'params, E> Send for VerifierGWC<'params, E>",1,["halo2_proofs::poly::kzg::multiopen::gwc::verifier::VerifierGWC"]],["impl<'a, E> Send for ProverSHPLONK<'a, E>",1,["halo2_proofs::poly::kzg::multiopen::shplonk::prover::ProverSHPLONK"]],["impl<'params, E> Send for VerifierSHPLONK<'params, E>",1,["halo2_proofs::poly::kzg::multiopen::shplonk::verifier::VerifierSHPLONK"]],["impl<'params, E> Send for GuardKZG<'params, E>",1,["halo2_proofs::poly::kzg::strategy::GuardKZG"]],["impl<'params, E> Send for AccumulatorStrategy<'params, E>",1,["halo2_proofs::poly::kzg::strategy::AccumulatorStrategy"]],["impl<'params, E> Send for SingleStrategy<'params, E>",1,["halo2_proofs::poly::kzg::strategy::SingleStrategy"]],["impl Send for Error",1,["halo2_proofs::poly::Error"]],["impl Send for Coeff",1,["halo2_proofs::poly::Coeff"]],["impl Send for LagrangeCoeff",1,["halo2_proofs::poly::LagrangeCoeff"]],["impl Send for ExtendedLagrangeCoeff",1,["halo2_proofs::poly::ExtendedLagrangeCoeff"]],["impl<F, B> Send for Polynomial<F, B>where
    B: Send,
    F: Send,
",1,["halo2_proofs::poly::Polynomial"]],["impl Send for Rotation",1,["halo2_proofs::poly::Rotation"]],["impl<R, C, E> Send for Blake2bRead<R, C, E>where
    E: Send,
    R: Send,
",1,["halo2_proofs::transcript::Blake2bRead"]],["impl<W, C, E> Send for Blake2bWrite<W, C, E>where
    E: Send,
    W: Send,
",1,["halo2_proofs::transcript::Blake2bWrite"]],["impl<C, T> Send for ChallengeScalar<C, T>where
    T: Send,
",1,["halo2_proofs::transcript::ChallengeScalar"]],["impl<C> Send for Challenge255<C>",1,["halo2_proofs::transcript::Challenge255"]],["impl Send for Column",1,["halo2_proofs::dev::metadata::Column"]],["impl Send for VirtualCell",1,["halo2_proofs::dev::metadata::VirtualCell"]],["impl Send for Gate",1,["halo2_proofs::dev::metadata::Gate"]],["impl Send for Constraint",1,["halo2_proofs::dev::metadata::Constraint"]],["impl Send for Region",1,["halo2_proofs::dev::metadata::Region"]],["impl Send for FailureLocation",1,["halo2_proofs::dev::failure::FailureLocation"]],["impl Send for VerifyFailure",1,["halo2_proofs::dev::failure::VerifyFailure"]],["impl Send for CircuitGates",1,["halo2_proofs::dev::gates::CircuitGates"]],["impl<F> Send for MockProver<F>",1,["halo2_proofs::dev::MockProver"]],["impl Send for SerdeFormat",1,["halo2_proofs::helpers::SerdeFormat"]]], +"halo2curves":[["impl Send for G1",1,["halo2curves::bn256::curve::G1"]],["impl Send for G1Affine",1,["halo2curves::bn256::curve::G1Affine"]],["impl Send for G1Compressed",1,["halo2curves::bn256::curve::G1Compressed"]],["impl Send for G2",1,["halo2curves::bn256::curve::G2"]],["impl Send for G2Affine",1,["halo2curves::bn256::curve::G2Affine"]],["impl Send for G2Compressed",1,["halo2curves::bn256::curve::G2Compressed"]],["impl Send for Gt",1,["halo2curves::bn256::engine::Gt"]],["impl Send for G2Prepared",1,["halo2curves::bn256::engine::G2Prepared"]],["impl Send for Bn256",1,["halo2curves::bn256::engine::Bn256"]],["impl Send for Fq",1,["halo2curves::bn256::fq::Fq"]],["impl Send for Fq12",1,["halo2curves::bn256::fq12::Fq12"]],["impl Send for Fq2",1,["halo2curves::bn256::fq2::Fq2"]],["impl Send for Fq2Bytes",1,["halo2curves::bn256::fq2::Fq2Bytes"]],["impl Send for Fq6",1,["halo2curves::bn256::fq6::Fq6"]],["impl Send for Fr",1,["halo2curves::bn256::fr::Fr"]],["impl Send for LegendreSymbol",1,["halo2curves::bn256::LegendreSymbol"]],["impl Send for Secp256k1",1,["halo2curves::secp256k1::curve::Secp256k1"]],["impl Send for Secp256k1Affine",1,["halo2curves::secp256k1::curve::Secp256k1Affine"]],["impl Send for Secp256k1Compressed",1,["halo2curves::secp256k1::curve::Secp256k1Compressed"]],["impl Send for Fp",1,["halo2curves::secp256k1::fp::Fp"]],["impl Send for Fq",1,["halo2curves::secp256k1::fq::Fq"]]], +"poseidon":[["impl<F, const T: usize, const RATE: usize> Send for Poseidon<F, T, RATE>",1,["poseidon::poseidon::Poseidon"]],["impl<F, const T: usize> Send for State<F, T>",1,["poseidon::spec::State"]],["impl<F, const T: usize, const RATE: usize> Send for Spec<F, T, RATE>",1,["poseidon::spec::Spec"]],["impl<F, const T: usize, const RATE: usize> Send for MDSMatrices<F, T, RATE>",1,["poseidon::spec::MDSMatrices"]],["impl<F, const T: usize, const RATE: usize> Send for MDSMatrix<F, T, RATE>",1,["poseidon::spec::MDSMatrix"]],["impl<F, const T: usize, const RATE: usize> Send for SparseMDSMatrix<F, T, RATE>",1,["poseidon::spec::SparseMDSMatrix"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/marker/trait.StructuralEq.js b/docs/implementors/core/marker/trait.StructuralEq.js new file mode 100644 index 0000000000..87763645f6 --- /dev/null +++ b/docs/implementors/core/marker/trait.StructuralEq.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[["impl StructuralEq for RegionColumn"],["impl StructuralEq for RegionStart"],["impl<C: ColumnType> StructuralEq for Column<C>"],["impl StructuralEq for Advice"],["impl StructuralEq for Fixed"],["impl StructuralEq for Instance"],["impl StructuralEq for Any"],["impl StructuralEq for Selector"],["impl StructuralEq for TableColumn"],["impl StructuralEq for Challenge"],["impl<F> StructuralEq for Blind<F>"],["impl StructuralEq for Column"],["impl StructuralEq for VirtualCell"]], +"halo2curves":[["impl StructuralEq for Fq"],["impl StructuralEq for Fq12"],["impl StructuralEq for Fq2"],["impl StructuralEq for Fq6"],["impl StructuralEq for Fr"],["impl StructuralEq for LegendreSymbol"],["impl StructuralEq for Fp"],["impl StructuralEq for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/marker/trait.StructuralPartialEq.js b/docs/implementors/core/marker/trait.StructuralPartialEq.js new file mode 100644 index 0000000000..cbdbd6a039 --- /dev/null +++ b/docs/implementors/core/marker/trait.StructuralPartialEq.js @@ -0,0 +1,5 @@ +(function() {var implementors = { +"halo2_proofs":[["impl StructuralPartialEq for RegionColumn"],["impl StructuralPartialEq for RegionStart"],["impl<C: ColumnType> StructuralPartialEq for Column<C>"],["impl StructuralPartialEq for Advice"],["impl StructuralPartialEq for Fixed"],["impl StructuralPartialEq for Instance"],["impl StructuralPartialEq for Any"],["impl StructuralPartialEq for Selector"],["impl StructuralPartialEq for TableColumn"],["impl StructuralPartialEq for Challenge"],["impl<F> StructuralPartialEq for Blind<F>"],["impl StructuralPartialEq for Rotation"],["impl StructuralPartialEq for Column"],["impl StructuralPartialEq for VirtualCell"],["impl StructuralPartialEq for Gate"],["impl StructuralPartialEq for Constraint"],["impl StructuralPartialEq for Region"],["impl StructuralPartialEq for FailureLocation"],["impl StructuralPartialEq for VerifyFailure"]], +"halo2curves":[["impl StructuralPartialEq for G1Affine"],["impl StructuralPartialEq for G2Affine"],["impl StructuralPartialEq for Fq"],["impl StructuralPartialEq for Fq12"],["impl StructuralPartialEq for Fq2"],["impl StructuralPartialEq for Fq6"],["impl StructuralPartialEq for Fr"],["impl StructuralPartialEq for LegendreSymbol"],["impl StructuralPartialEq for Secp256k1Affine"],["impl StructuralPartialEq for Fp"],["impl StructuralPartialEq for Fq"]], +"poseidon":[["impl<F: FieldExt, const T: usize> StructuralPartialEq for State<F, T>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/marker/trait.Sync.js b/docs/implementors/core/marker/trait.Sync.js new file mode 100644 index 0000000000..e5baaa5664 --- /dev/null +++ b/docs/implementors/core/marker/trait.Sync.js @@ -0,0 +1,5 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<V> Sync for Value<V>where
    V: Sync,
",1,["halo2_proofs::circuit::value::Value"]],["impl Sync for SimpleFloorPlanner",1,["halo2_proofs::circuit::floor_planner::single_pass::SimpleFloorPlanner"]],["impl Sync for RegionShape",1,["halo2_proofs::circuit::layouter::RegionShape"]],["impl Sync for RegionColumn",1,["halo2_proofs::circuit::layouter::RegionColumn"]],["impl Sync for RegionIndex",1,["halo2_proofs::circuit::RegionIndex"]],["impl Sync for RegionStart",1,["halo2_proofs::circuit::RegionStart"]],["impl Sync for Cell",1,["halo2_proofs::circuit::Cell"]],["impl<V, F> Sync for AssignedCell<V, F>where
    V: Sync,
",1,["halo2_proofs::circuit::AssignedCell"]],["impl<'r, F> !Sync for Region<'r, F>",1,["halo2_proofs::circuit::Region"]],["impl<'r, F> !Sync for Table<'r, F>",1,["halo2_proofs::circuit::Table"]],["impl<'a, F, L> Sync for NamespacedLayouter<'a, F, L>where
    L: Sync,
",1,["halo2_proofs::circuit::NamespacedLayouter"]],["impl<F> Sync for Assigned<F>where
    F: Sync,
",1,["halo2_proofs::plonk::assigned::Assigned"]],["impl<C> Sync for Column<C>where
    C: Sync,
",1,["halo2_proofs::plonk::circuit::Column"]],["impl Sync for FirstPhase",1,["halo2_proofs::plonk::circuit::FirstPhase"]],["impl Sync for SecondPhase",1,["halo2_proofs::plonk::circuit::SecondPhase"]],["impl Sync for ThirdPhase",1,["halo2_proofs::plonk::circuit::ThirdPhase"]],["impl Sync for Advice",1,["halo2_proofs::plonk::circuit::Advice"]],["impl Sync for Fixed",1,["halo2_proofs::plonk::circuit::Fixed"]],["impl Sync for Instance",1,["halo2_proofs::plonk::circuit::Instance"]],["impl Sync for Any",1,["halo2_proofs::plonk::circuit::Any"]],["impl Sync for Selector",1,["halo2_proofs::plonk::circuit::Selector"]],["impl Sync for FixedQuery",1,["halo2_proofs::plonk::circuit::FixedQuery"]],["impl Sync for AdviceQuery",1,["halo2_proofs::plonk::circuit::AdviceQuery"]],["impl Sync for InstanceQuery",1,["halo2_proofs::plonk::circuit::InstanceQuery"]],["impl Sync for TableColumn",1,["halo2_proofs::plonk::circuit::TableColumn"]],["impl Sync for Challenge",1,["halo2_proofs::plonk::circuit::Challenge"]],["impl<F> Sync for Expression<F>where
    F: Sync,
",1,["halo2_proofs::plonk::circuit::Expression"]],["impl Sync for VirtualCell",1,["halo2_proofs::plonk::circuit::VirtualCell"]],["impl<F> Sync for Constraint<F>",1,["halo2_proofs::plonk::circuit::Constraint"]],["impl<F, C, Iter> Sync for Constraints<F, C, Iter>where
    Iter: Sync,
",1,["halo2_proofs::plonk::circuit::Constraints"]],["impl<F> Sync for Gate<F>",1,["halo2_proofs::plonk::circuit::Gate"]],["impl<F> Sync for ConstraintSystem<F>",1,["halo2_proofs::plonk::circuit::ConstraintSystem"]],["impl<'a, F> Sync for PinnedConstraintSystem<'a, F>",1,["halo2_proofs::plonk::circuit::PinnedConstraintSystem"]],["impl<'a, F> Sync for VirtualCells<'a, F>",1,["halo2_proofs::plonk::circuit::VirtualCells"]],["impl Sync for Error",1,["halo2_proofs::plonk::error::Error"]],["impl<C> Sync for BatchVerifier<C>",1,["halo2_proofs::plonk::verifier::batch::BatchVerifier"]],["impl<C> Sync for VerifyingKey<C>",1,["halo2_proofs::plonk::VerifyingKey"]],["impl<'a, C> Sync for PinnedVerificationKey<'a, C>",1,["halo2_proofs::plonk::PinnedVerificationKey"]],["impl<C> Sync for ProvingKey<C>",1,["halo2_proofs::plonk::ProvingKey"]],["impl<F> Sync for Blind<F>where
    F: Sync,
",1,["halo2_proofs::poly::commitment::Blind"]],["impl<G> Sync for EvaluationDomain<G>",1,["halo2_proofs::poly::domain::EvaluationDomain"]],["impl<'a, G> Sync for PinnedEvaluationDomain<'a, G>",1,["halo2_proofs::poly::domain::PinnedEvaluationDomain"]],["impl<'com, C> Sync for ProverQuery<'com, C>",1,["halo2_proofs::poly::query::ProverQuery"]],["impl<'com, C, M> Sync for VerifierQuery<'com, C, M>",1,["halo2_proofs::poly::query::VerifierQuery"]],["impl<C> Sync for ParamsIPA<C>",1,["halo2_proofs::poly::ipa::commitment::ParamsIPA"]],["impl<C> Sync for IPACommitmentScheme<C>",1,["halo2_proofs::poly::ipa::commitment::IPACommitmentScheme"]],["impl<'params, C> Sync for MSMIPA<'params, C>",1,["halo2_proofs::poly::ipa::msm::MSMIPA"]],["impl<'params, C> Sync for ProverIPA<'params, C>",1,["halo2_proofs::poly::ipa::multiopen::prover::ProverIPA"]],["impl<'params, C> Sync for VerifierIPA<'params, C>",1,["halo2_proofs::poly::ipa::multiopen::verifier::VerifierIPA"]],["impl<'params, C> Sync for GuardIPA<'params, C>",1,["halo2_proofs::poly::ipa::strategy::GuardIPA"]],["impl<C> Sync for Accumulator<C>",1,["halo2_proofs::poly::ipa::strategy::Accumulator"]],["impl<'params, C> Sync for AccumulatorStrategy<'params, C>",1,["halo2_proofs::poly::ipa::strategy::AccumulatorStrategy"]],["impl<'params, C> Sync for SingleStrategy<'params, C>",1,["halo2_proofs::poly::ipa::strategy::SingleStrategy"]],["impl<E> Sync for ParamsKZG<E>",1,["halo2_proofs::poly::kzg::commitment::ParamsKZG"]],["impl<E> Sync for KZGCommitmentScheme<E>where
    E: Sync,
",1,["halo2_proofs::poly::kzg::commitment::KZGCommitmentScheme"]],["impl<E> Sync for MSMKZG<E>",1,["halo2_proofs::poly::kzg::msm::MSMKZG"]],["impl<'a, E> Sync for DualMSM<'a, E>",1,["halo2_proofs::poly::kzg::msm::DualMSM"]],["impl<'params, E> Sync for ProverGWC<'params, E>",1,["halo2_proofs::poly::kzg::multiopen::gwc::prover::ProverGWC"]],["impl<'params, E> Sync for VerifierGWC<'params, E>",1,["halo2_proofs::poly::kzg::multiopen::gwc::verifier::VerifierGWC"]],["impl<'a, E> Sync for ProverSHPLONK<'a, E>",1,["halo2_proofs::poly::kzg::multiopen::shplonk::prover::ProverSHPLONK"]],["impl<'params, E> Sync for VerifierSHPLONK<'params, E>",1,["halo2_proofs::poly::kzg::multiopen::shplonk::verifier::VerifierSHPLONK"]],["impl<'params, E> Sync for GuardKZG<'params, E>",1,["halo2_proofs::poly::kzg::strategy::GuardKZG"]],["impl<'params, E> Sync for AccumulatorStrategy<'params, E>",1,["halo2_proofs::poly::kzg::strategy::AccumulatorStrategy"]],["impl<'params, E> Sync for SingleStrategy<'params, E>",1,["halo2_proofs::poly::kzg::strategy::SingleStrategy"]],["impl Sync for Error",1,["halo2_proofs::poly::Error"]],["impl Sync for Coeff",1,["halo2_proofs::poly::Coeff"]],["impl Sync for LagrangeCoeff",1,["halo2_proofs::poly::LagrangeCoeff"]],["impl Sync for ExtendedLagrangeCoeff",1,["halo2_proofs::poly::ExtendedLagrangeCoeff"]],["impl<F, B> Sync for Polynomial<F, B>where
    B: Sync,
    F: Sync,
",1,["halo2_proofs::poly::Polynomial"]],["impl Sync for Rotation",1,["halo2_proofs::poly::Rotation"]],["impl<R, C, E> Sync for Blake2bRead<R, C, E>where
    E: Sync,
    R: Sync,
",1,["halo2_proofs::transcript::Blake2bRead"]],["impl<W, C, E> Sync for Blake2bWrite<W, C, E>where
    E: Sync,
    W: Sync,
",1,["halo2_proofs::transcript::Blake2bWrite"]],["impl<C, T> Sync for ChallengeScalar<C, T>where
    T: Sync,
",1,["halo2_proofs::transcript::ChallengeScalar"]],["impl<C> Sync for Challenge255<C>",1,["halo2_proofs::transcript::Challenge255"]],["impl Sync for Column",1,["halo2_proofs::dev::metadata::Column"]],["impl Sync for VirtualCell",1,["halo2_proofs::dev::metadata::VirtualCell"]],["impl Sync for Gate",1,["halo2_proofs::dev::metadata::Gate"]],["impl Sync for Constraint",1,["halo2_proofs::dev::metadata::Constraint"]],["impl Sync for Region",1,["halo2_proofs::dev::metadata::Region"]],["impl Sync for FailureLocation",1,["halo2_proofs::dev::failure::FailureLocation"]],["impl Sync for VerifyFailure",1,["halo2_proofs::dev::failure::VerifyFailure"]],["impl Sync for CircuitGates",1,["halo2_proofs::dev::gates::CircuitGates"]],["impl<F> Sync for MockProver<F>",1,["halo2_proofs::dev::MockProver"]],["impl Sync for SerdeFormat",1,["halo2_proofs::helpers::SerdeFormat"]]], +"halo2curves":[["impl Sync for G1",1,["halo2curves::bn256::curve::G1"]],["impl Sync for G1Affine",1,["halo2curves::bn256::curve::G1Affine"]],["impl Sync for G1Compressed",1,["halo2curves::bn256::curve::G1Compressed"]],["impl Sync for G2",1,["halo2curves::bn256::curve::G2"]],["impl Sync for G2Affine",1,["halo2curves::bn256::curve::G2Affine"]],["impl Sync for G2Compressed",1,["halo2curves::bn256::curve::G2Compressed"]],["impl Sync for Gt",1,["halo2curves::bn256::engine::Gt"]],["impl Sync for G2Prepared",1,["halo2curves::bn256::engine::G2Prepared"]],["impl Sync for Bn256",1,["halo2curves::bn256::engine::Bn256"]],["impl Sync for Fq",1,["halo2curves::bn256::fq::Fq"]],["impl Sync for Fq12",1,["halo2curves::bn256::fq12::Fq12"]],["impl Sync for Fq2",1,["halo2curves::bn256::fq2::Fq2"]],["impl Sync for Fq2Bytes",1,["halo2curves::bn256::fq2::Fq2Bytes"]],["impl Sync for Fq6",1,["halo2curves::bn256::fq6::Fq6"]],["impl Sync for Fr",1,["halo2curves::bn256::fr::Fr"]],["impl Sync for LegendreSymbol",1,["halo2curves::bn256::LegendreSymbol"]],["impl Sync for Secp256k1",1,["halo2curves::secp256k1::curve::Secp256k1"]],["impl Sync for Secp256k1Affine",1,["halo2curves::secp256k1::curve::Secp256k1Affine"]],["impl Sync for Secp256k1Compressed",1,["halo2curves::secp256k1::curve::Secp256k1Compressed"]],["impl Sync for Fp",1,["halo2curves::secp256k1::fp::Fp"]],["impl Sync for Fq",1,["halo2curves::secp256k1::fq::Fq"]]], +"poseidon":[["impl<F, const T: usize, const RATE: usize> Sync for Poseidon<F, T, RATE>",1,["poseidon::poseidon::Poseidon"]],["impl<F, const T: usize> Sync for State<F, T>",1,["poseidon::spec::State"]],["impl<F, const T: usize, const RATE: usize> Sync for Spec<F, T, RATE>",1,["poseidon::spec::Spec"]],["impl<F, const T: usize, const RATE: usize> Sync for MDSMatrices<F, T, RATE>",1,["poseidon::spec::MDSMatrices"]],["impl<F, const T: usize, const RATE: usize> Sync for MDSMatrix<F, T, RATE>",1,["poseidon::spec::MDSMatrix"]],["impl<F, const T: usize, const RATE: usize> Sync for SparseMDSMatrix<F, T, RATE>",1,["poseidon::spec::SparseMDSMatrix"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/marker/trait.Unpin.js b/docs/implementors/core/marker/trait.Unpin.js new file mode 100644 index 0000000000..898660cb7e --- /dev/null +++ b/docs/implementors/core/marker/trait.Unpin.js @@ -0,0 +1,5 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<V> Unpin for Value<V>where
    V: Unpin,
",1,["halo2_proofs::circuit::value::Value"]],["impl Unpin for SimpleFloorPlanner",1,["halo2_proofs::circuit::floor_planner::single_pass::SimpleFloorPlanner"]],["impl Unpin for RegionShape",1,["halo2_proofs::circuit::layouter::RegionShape"]],["impl Unpin for RegionColumn",1,["halo2_proofs::circuit::layouter::RegionColumn"]],["impl Unpin for RegionIndex",1,["halo2_proofs::circuit::RegionIndex"]],["impl Unpin for RegionStart",1,["halo2_proofs::circuit::RegionStart"]],["impl Unpin for Cell",1,["halo2_proofs::circuit::Cell"]],["impl<V, F> Unpin for AssignedCell<V, F>where
    F: Unpin,
    V: Unpin,
",1,["halo2_proofs::circuit::AssignedCell"]],["impl<'r, F> Unpin for Region<'r, F>",1,["halo2_proofs::circuit::Region"]],["impl<'r, F> Unpin for Table<'r, F>",1,["halo2_proofs::circuit::Table"]],["impl<'a, F, L> Unpin for NamespacedLayouter<'a, F, L>where
    F: Unpin,
",1,["halo2_proofs::circuit::NamespacedLayouter"]],["impl<F> Unpin for Assigned<F>where
    F: Unpin,
",1,["halo2_proofs::plonk::assigned::Assigned"]],["impl<C> Unpin for Column<C>where
    C: Unpin,
",1,["halo2_proofs::plonk::circuit::Column"]],["impl Unpin for FirstPhase",1,["halo2_proofs::plonk::circuit::FirstPhase"]],["impl Unpin for SecondPhase",1,["halo2_proofs::plonk::circuit::SecondPhase"]],["impl Unpin for ThirdPhase",1,["halo2_proofs::plonk::circuit::ThirdPhase"]],["impl Unpin for Advice",1,["halo2_proofs::plonk::circuit::Advice"]],["impl Unpin for Fixed",1,["halo2_proofs::plonk::circuit::Fixed"]],["impl Unpin for Instance",1,["halo2_proofs::plonk::circuit::Instance"]],["impl Unpin for Any",1,["halo2_proofs::plonk::circuit::Any"]],["impl Unpin for Selector",1,["halo2_proofs::plonk::circuit::Selector"]],["impl Unpin for FixedQuery",1,["halo2_proofs::plonk::circuit::FixedQuery"]],["impl Unpin for AdviceQuery",1,["halo2_proofs::plonk::circuit::AdviceQuery"]],["impl Unpin for InstanceQuery",1,["halo2_proofs::plonk::circuit::InstanceQuery"]],["impl Unpin for TableColumn",1,["halo2_proofs::plonk::circuit::TableColumn"]],["impl Unpin for Challenge",1,["halo2_proofs::plonk::circuit::Challenge"]],["impl<F> Unpin for Expression<F>where
    F: Unpin,
",1,["halo2_proofs::plonk::circuit::Expression"]],["impl Unpin for VirtualCell",1,["halo2_proofs::plonk::circuit::VirtualCell"]],["impl<F> Unpin for Constraint<F>where
    F: Unpin,
",1,["halo2_proofs::plonk::circuit::Constraint"]],["impl<F, C, Iter> Unpin for Constraints<F, C, Iter>where
    F: Unpin,
    Iter: Unpin,
",1,["halo2_proofs::plonk::circuit::Constraints"]],["impl<F> Unpin for Gate<F>where
    F: Unpin,
",1,["halo2_proofs::plonk::circuit::Gate"]],["impl<F> Unpin for ConstraintSystem<F>where
    F: Unpin,
",1,["halo2_proofs::plonk::circuit::ConstraintSystem"]],["impl<'a, F> Unpin for PinnedConstraintSystem<'a, F>",1,["halo2_proofs::plonk::circuit::PinnedConstraintSystem"]],["impl<'a, F> Unpin for VirtualCells<'a, F>",1,["halo2_proofs::plonk::circuit::VirtualCells"]],["impl Unpin for Error",1,["halo2_proofs::plonk::error::Error"]],["impl<C> Unpin for BatchVerifier<C>where
    <C as CurveAffine>::ScalarExt: Unpin,
",1,["halo2_proofs::plonk::verifier::batch::BatchVerifier"]],["impl<C> Unpin for VerifyingKey<C>where
    C: Unpin,
    <C as CurveAffine>::ScalarExt: Unpin,
",1,["halo2_proofs::plonk::VerifyingKey"]],["impl<'a, C> Unpin for PinnedVerificationKey<'a, C>",1,["halo2_proofs::plonk::PinnedVerificationKey"]],["impl<C> Unpin for ProvingKey<C>where
    C: Unpin,
    <C as CurveAffine>::ScalarExt: Unpin,
",1,["halo2_proofs::plonk::ProvingKey"]],["impl<F> Unpin for Blind<F>where
    F: Unpin,
",1,["halo2_proofs::poly::commitment::Blind"]],["impl<G> Unpin for EvaluationDomain<G>where
    <G as Group>::Scalar: Unpin,
",1,["halo2_proofs::poly::domain::EvaluationDomain"]],["impl<'a, G> Unpin for PinnedEvaluationDomain<'a, G>",1,["halo2_proofs::poly::domain::PinnedEvaluationDomain"]],["impl<'com, C> Unpin for ProverQuery<'com, C>where
    <C as CurveAffine>::ScalarExt: Unpin,
",1,["halo2_proofs::poly::query::ProverQuery"]],["impl<'com, C, M> Unpin for VerifierQuery<'com, C, M>where
    <C as CurveAffine>::ScalarExt: Unpin,
",1,["halo2_proofs::poly::query::VerifierQuery"]],["impl<C> Unpin for ParamsIPA<C>where
    C: Unpin,
",1,["halo2_proofs::poly::ipa::commitment::ParamsIPA"]],["impl<C> Unpin for IPACommitmentScheme<C>where
    C: Unpin,
",1,["halo2_proofs::poly::ipa::commitment::IPACommitmentScheme"]],["impl<'params, C> Unpin for MSMIPA<'params, C>where
    <C as CurveAffine>::ScalarExt: Unpin,
",1,["halo2_proofs::poly::ipa::msm::MSMIPA"]],["impl<'params, C> Unpin for ProverIPA<'params, C>",1,["halo2_proofs::poly::ipa::multiopen::prover::ProverIPA"]],["impl<'params, C> Unpin for VerifierIPA<'params, C>",1,["halo2_proofs::poly::ipa::multiopen::verifier::VerifierIPA"]],["impl<'params, C> Unpin for GuardIPA<'params, C>where
    <C as CurveAffine>::ScalarExt: Unpin,
",1,["halo2_proofs::poly::ipa::strategy::GuardIPA"]],["impl<C> Unpin for Accumulator<C>where
    C: Unpin,
    <C as CurveAffine>::ScalarExt: Unpin,
",1,["halo2_proofs::poly::ipa::strategy::Accumulator"]],["impl<'params, C> Unpin for AccumulatorStrategy<'params, C>where
    <C as CurveAffine>::ScalarExt: Unpin,
",1,["halo2_proofs::poly::ipa::strategy::AccumulatorStrategy"]],["impl<'params, C> Unpin for SingleStrategy<'params, C>where
    <C as CurveAffine>::ScalarExt: Unpin,
",1,["halo2_proofs::poly::ipa::strategy::SingleStrategy"]],["impl<E> Unpin for ParamsKZG<E>where
    <E as Engine>::G1Affine: Unpin,
    <E as Engine>::G2Affine: Unpin,
",1,["halo2_proofs::poly::kzg::commitment::ParamsKZG"]],["impl<E> Unpin for KZGCommitmentScheme<E>where
    E: Unpin,
",1,["halo2_proofs::poly::kzg::commitment::KZGCommitmentScheme"]],["impl<E> Unpin for MSMKZG<E>where
    <E as Engine>::G1: Unpin,
    <E as Engine>::Scalar: Unpin,
",1,["halo2_proofs::poly::kzg::msm::MSMKZG"]],["impl<'a, E> Unpin for DualMSM<'a, E>where
    <E as Engine>::G1: Unpin,
    <E as Engine>::Scalar: Unpin,
",1,["halo2_proofs::poly::kzg::msm::DualMSM"]],["impl<'params, E> Unpin for ProverGWC<'params, E>",1,["halo2_proofs::poly::kzg::multiopen::gwc::prover::ProverGWC"]],["impl<'params, E> Unpin for VerifierGWC<'params, E>",1,["halo2_proofs::poly::kzg::multiopen::gwc::verifier::VerifierGWC"]],["impl<'a, E> Unpin for ProverSHPLONK<'a, E>",1,["halo2_proofs::poly::kzg::multiopen::shplonk::prover::ProverSHPLONK"]],["impl<'params, E> Unpin for VerifierSHPLONK<'params, E>",1,["halo2_proofs::poly::kzg::multiopen::shplonk::verifier::VerifierSHPLONK"]],["impl<'params, E> Unpin for GuardKZG<'params, E>where
    <E as Engine>::G1: Unpin,
    <E as Engine>::Scalar: Unpin,
",1,["halo2_proofs::poly::kzg::strategy::GuardKZG"]],["impl<'params, E> Unpin for AccumulatorStrategy<'params, E>where
    <E as Engine>::G1: Unpin,
    <E as Engine>::Scalar: Unpin,
",1,["halo2_proofs::poly::kzg::strategy::AccumulatorStrategy"]],["impl<'params, E> Unpin for SingleStrategy<'params, E>where
    <E as Engine>::G1: Unpin,
    <E as Engine>::Scalar: Unpin,
",1,["halo2_proofs::poly::kzg::strategy::SingleStrategy"]],["impl Unpin for Error",1,["halo2_proofs::poly::Error"]],["impl Unpin for Coeff",1,["halo2_proofs::poly::Coeff"]],["impl Unpin for LagrangeCoeff",1,["halo2_proofs::poly::LagrangeCoeff"]],["impl Unpin for ExtendedLagrangeCoeff",1,["halo2_proofs::poly::ExtendedLagrangeCoeff"]],["impl<F, B> Unpin for Polynomial<F, B>where
    B: Unpin,
    F: Unpin,
",1,["halo2_proofs::poly::Polynomial"]],["impl Unpin for Rotation",1,["halo2_proofs::poly::Rotation"]],["impl<R, C, E> Unpin for Blake2bRead<R, C, E>where
    C: Unpin,
    E: Unpin,
    R: Unpin,
",1,["halo2_proofs::transcript::Blake2bRead"]],["impl<W, C, E> Unpin for Blake2bWrite<W, C, E>where
    C: Unpin,
    E: Unpin,
    W: Unpin,
",1,["halo2_proofs::transcript::Blake2bWrite"]],["impl<C, T> Unpin for ChallengeScalar<C, T>where
    T: Unpin,
    <C as CurveAffine>::ScalarExt: Unpin,
",1,["halo2_proofs::transcript::ChallengeScalar"]],["impl<C> Unpin for Challenge255<C>where
    C: Unpin,
",1,["halo2_proofs::transcript::Challenge255"]],["impl Unpin for Column",1,["halo2_proofs::dev::metadata::Column"]],["impl Unpin for VirtualCell",1,["halo2_proofs::dev::metadata::VirtualCell"]],["impl Unpin for Gate",1,["halo2_proofs::dev::metadata::Gate"]],["impl Unpin for Constraint",1,["halo2_proofs::dev::metadata::Constraint"]],["impl Unpin for Region",1,["halo2_proofs::dev::metadata::Region"]],["impl Unpin for FailureLocation",1,["halo2_proofs::dev::failure::FailureLocation"]],["impl Unpin for VerifyFailure",1,["halo2_proofs::dev::failure::VerifyFailure"]],["impl Unpin for CircuitGates",1,["halo2_proofs::dev::gates::CircuitGates"]],["impl<F> Unpin for MockProver<F>where
    F: Unpin,
",1,["halo2_proofs::dev::MockProver"]],["impl Unpin for SerdeFormat",1,["halo2_proofs::helpers::SerdeFormat"]]], +"halo2curves":[["impl Unpin for G1",1,["halo2curves::bn256::curve::G1"]],["impl Unpin for G1Affine",1,["halo2curves::bn256::curve::G1Affine"]],["impl Unpin for G1Compressed",1,["halo2curves::bn256::curve::G1Compressed"]],["impl Unpin for G2",1,["halo2curves::bn256::curve::G2"]],["impl Unpin for G2Affine",1,["halo2curves::bn256::curve::G2Affine"]],["impl Unpin for G2Compressed",1,["halo2curves::bn256::curve::G2Compressed"]],["impl Unpin for Gt",1,["halo2curves::bn256::engine::Gt"]],["impl Unpin for G2Prepared",1,["halo2curves::bn256::engine::G2Prepared"]],["impl Unpin for Bn256",1,["halo2curves::bn256::engine::Bn256"]],["impl Unpin for Fq",1,["halo2curves::bn256::fq::Fq"]],["impl Unpin for Fq12",1,["halo2curves::bn256::fq12::Fq12"]],["impl Unpin for Fq2",1,["halo2curves::bn256::fq2::Fq2"]],["impl Unpin for Fq2Bytes",1,["halo2curves::bn256::fq2::Fq2Bytes"]],["impl Unpin for Fq6",1,["halo2curves::bn256::fq6::Fq6"]],["impl Unpin for Fr",1,["halo2curves::bn256::fr::Fr"]],["impl Unpin for LegendreSymbol",1,["halo2curves::bn256::LegendreSymbol"]],["impl Unpin for Secp256k1",1,["halo2curves::secp256k1::curve::Secp256k1"]],["impl Unpin for Secp256k1Affine",1,["halo2curves::secp256k1::curve::Secp256k1Affine"]],["impl Unpin for Secp256k1Compressed",1,["halo2curves::secp256k1::curve::Secp256k1Compressed"]],["impl Unpin for Fp",1,["halo2curves::secp256k1::fp::Fp"]],["impl Unpin for Fq",1,["halo2curves::secp256k1::fq::Fq"]]], +"poseidon":[["impl<F, const T: usize, const RATE: usize> Unpin for Poseidon<F, T, RATE>where
    F: Unpin,
",1,["poseidon::poseidon::Poseidon"]],["impl<F, const T: usize> Unpin for State<F, T>where
    F: Unpin,
",1,["poseidon::spec::State"]],["impl<F, const T: usize, const RATE: usize> Unpin for Spec<F, T, RATE>where
    F: Unpin,
",1,["poseidon::spec::Spec"]],["impl<F, const T: usize, const RATE: usize> Unpin for MDSMatrices<F, T, RATE>where
    F: Unpin,
",1,["poseidon::spec::MDSMatrices"]],["impl<F, const T: usize, const RATE: usize> Unpin for MDSMatrix<F, T, RATE>where
    F: Unpin,
",1,["poseidon::spec::MDSMatrix"]],["impl<F, const T: usize, const RATE: usize> Unpin for SparseMDSMatrix<F, T, RATE>where
    F: Unpin,
",1,["poseidon::spec::SparseMDSMatrix"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.Add.js b/docs/implementors/core/ops/arith/trait.Add.js new file mode 100644 index 0000000000..40074bf58f --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.Add.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<V, O> Add<Value<V>> for Value<V>where
    V: Add<Output = O>,
"],["impl<V, O> Add<&Value<V>> for &Value<V>where
    for<'v> &'v V: Add<Output = O>,
"],["impl<V, O> Add<Value<&V>> for Value<V>where
    for<'v> V: Add<&'v V, Output = O>,
"],["impl<V, O> Add<Value<V>> for Value<&V>where
    for<'v> &'v V: Add<V, Output = O>,
"],["impl<V, O> Add<&Value<V>> for Value<V>where
    for<'v> V: Add<&'v V, Output = O>,
"],["impl<V, O> Add<Value<V>> for &Value<V>where
    for<'v> &'v V: Add<V, Output = O>,
"],["impl<F: Field> Add<Value<F>> for Value<Assigned<F>>"],["impl<F: Field> Add<F> for Value<Assigned<F>>"],["impl<F: Field> Add<Value<F>> for Value<&Assigned<F>>"],["impl<F: Field> Add<F> for Value<&Assigned<F>>"],["impl<F: Field> Add<Assigned<F>> for Assigned<F>"],["impl<F: Field> Add<F> for Assigned<F>"],["impl<F: Field> Add<F> for &Assigned<F>"],["impl<F: Field> Add<&Assigned<F>> for Assigned<F>"],["impl<F: Field> Add<Assigned<F>> for &Assigned<F>"],["impl<F: Field> Add<&Assigned<F>> for &Assigned<F>"],["impl<F: Field> Add<Expression<F>> for Expression<F>"],["impl<F: FieldExt> Add<Blind<F>> for Blind<F>"],["impl<'a, F: Field, B: Basis> Add<&'a Polynomial<F, B>> for Polynomial<F, B>"]], +"halo2curves":[["impl<'b> Add<&'b G1> for G1"],["impl<'a> Add<G1> for &'a G1"],["impl Add<G1> for G1"],["impl<'b> Add<&'b G1Affine> for G1"],["impl<'a> Add<G1Affine> for &'a G1"],["impl Add<G1Affine> for G1"],["impl<'b> Add<&'b G1Affine> for G1Affine"],["impl<'a> Add<G1Affine> for &'a G1Affine"],["impl Add<G1Affine> for G1Affine"],["impl<'b> Add<&'b G1> for G1Affine"],["impl<'a> Add<G1> for &'a G1Affine"],["impl Add<G1> for G1Affine"],["impl<'a, 'b> Add<&'a G1> for &'b G1"],["impl<'a, 'b> Add<&'a G1Affine> for &'b G1"],["impl<'a, 'b> Add<&'a G1> for &'b G1Affine"],["impl<'a, 'b> Add<&'a G1Affine> for &'b G1Affine"],["impl<'b> Add<&'b G2> for G2"],["impl<'a> Add<G2> for &'a G2"],["impl Add<G2> for G2"],["impl<'b> Add<&'b G2Affine> for G2"],["impl<'a> Add<G2Affine> for &'a G2"],["impl Add<G2Affine> for G2"],["impl<'b> Add<&'b G2Affine> for G2Affine"],["impl<'a> Add<G2Affine> for &'a G2Affine"],["impl Add<G2Affine> for G2Affine"],["impl<'b> Add<&'b G2> for G2Affine"],["impl<'a> Add<G2> for &'a G2Affine"],["impl Add<G2> for G2Affine"],["impl<'a, 'b> Add<&'a G2> for &'b G2"],["impl<'a, 'b> Add<&'a G2Affine> for &'b G2"],["impl<'a, 'b> Add<&'a G2> for &'b G2Affine"],["impl<'a, 'b> Add<&'a G2Affine> for &'b G2Affine"],["impl<'a, 'b> Add<&'b Gt> for &'a Gt"],["impl<'b> Add<&'b Gt> for Gt"],["impl<'a> Add<Gt> for &'a Gt"],["impl Add<Gt> for Gt"],["impl<'b> Add<&'b Fq> for Fq"],["impl<'a> Add<Fq> for &'a Fq"],["impl Add<Fq> for Fq"],["impl<'a, 'b> Add<&'b Fq> for &'a Fq"],["impl<'a, 'b> Add<&'b Fq12> for &'a Fq12"],["impl<'b> Add<&'b Fq12> for Fq12"],["impl<'a> Add<Fq12> for &'a Fq12"],["impl Add<Fq12> for Fq12"],["impl<'a, 'b> Add<&'b Fq2> for &'a Fq2"],["impl<'b> Add<&'b Fq2> for Fq2"],["impl<'a> Add<Fq2> for &'a Fq2"],["impl Add<Fq2> for Fq2"],["impl<'a, 'b> Add<&'b Fq6> for &'a Fq6"],["impl<'b> Add<&'b Fq6> for Fq6"],["impl<'a> Add<Fq6> for &'a Fq6"],["impl Add<Fq6> for Fq6"],["impl<'b> Add<&'b Fr> for Fr"],["impl<'a> Add<Fr> for &'a Fr"],["impl Add<Fr> for Fr"],["impl<'a, 'b> Add<&'b Fr> for &'a Fr"],["impl<'b> Add<&'b Secp256k1> for Secp256k1"],["impl<'a> Add<Secp256k1> for &'a Secp256k1"],["impl Add<Secp256k1> for Secp256k1"],["impl<'b> Add<&'b Secp256k1Affine> for Secp256k1"],["impl<'a> Add<Secp256k1Affine> for &'a Secp256k1"],["impl Add<Secp256k1Affine> for Secp256k1"],["impl<'b> Add<&'b Secp256k1Affine> for Secp256k1Affine"],["impl<'a> Add<Secp256k1Affine> for &'a Secp256k1Affine"],["impl Add<Secp256k1Affine> for Secp256k1Affine"],["impl<'b> Add<&'b Secp256k1> for Secp256k1Affine"],["impl<'a> Add<Secp256k1> for &'a Secp256k1Affine"],["impl Add<Secp256k1> for Secp256k1Affine"],["impl<'a, 'b> Add<&'a Secp256k1> for &'b Secp256k1"],["impl<'a, 'b> Add<&'a Secp256k1Affine> for &'b Secp256k1"],["impl<'a, 'b> Add<&'a Secp256k1> for &'b Secp256k1Affine"],["impl<'a, 'b> Add<&'a Secp256k1Affine> for &'b Secp256k1Affine"],["impl<'b> Add<&'b Fp> for Fp"],["impl<'a> Add<Fp> for &'a Fp"],["impl Add<Fp> for Fp"],["impl<'a, 'b> Add<&'b Fp> for &'a Fp"],["impl<'b> Add<&'b Fq> for Fq"],["impl<'a> Add<Fq> for &'a Fq"],["impl Add<Fq> for Fq"],["impl<'a, 'b> Add<&'b Fq> for &'a Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.AddAssign.js b/docs/implementors/core/ops/arith/trait.AddAssign.js new file mode 100644 index 0000000000..dc03499189 --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.AddAssign.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<F: Field> AddAssign<Assigned<F>> for Assigned<F>"],["impl<F: Field> AddAssign<&Assigned<F>> for Assigned<F>"],["impl<F: FieldExt> AddAssign<Blind<F>> for Blind<F>"],["impl<F: FieldExt> AddAssign<F> for Blind<F>"]], +"halo2curves":[["impl AddAssign<G1> for G1"],["impl<'b> AddAssign<&'b G1> for G1"],["impl AddAssign<G1Affine> for G1"],["impl<'b> AddAssign<&'b G1Affine> for G1"],["impl AddAssign<G2> for G2"],["impl<'b> AddAssign<&'b G2> for G2"],["impl AddAssign<G2Affine> for G2"],["impl<'b> AddAssign<&'b G2Affine> for G2"],["impl AddAssign<Gt> for Gt"],["impl<'b> AddAssign<&'b Gt> for Gt"],["impl AddAssign<Fq> for Fq"],["impl<'b> AddAssign<&'b Fq> for Fq"],["impl AddAssign<Fq12> for Fq12"],["impl<'b> AddAssign<&'b Fq12> for Fq12"],["impl AddAssign<Fq2> for Fq2"],["impl<'b> AddAssign<&'b Fq2> for Fq2"],["impl AddAssign<Fq6> for Fq6"],["impl<'b> AddAssign<&'b Fq6> for Fq6"],["impl AddAssign<Fr> for Fr"],["impl<'b> AddAssign<&'b Fr> for Fr"],["impl AddAssign<Secp256k1> for Secp256k1"],["impl<'b> AddAssign<&'b Secp256k1> for Secp256k1"],["impl AddAssign<Secp256k1Affine> for Secp256k1"],["impl<'b> AddAssign<&'b Secp256k1Affine> for Secp256k1"],["impl AddAssign<Fp> for Fp"],["impl<'b> AddAssign<&'b Fp> for Fp"],["impl AddAssign<Fq> for Fq"],["impl<'b> AddAssign<&'b Fq> for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.Mul.js b/docs/implementors/core/ops/arith/trait.Mul.js new file mode 100644 index 0000000000..0dda93642e --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.Mul.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<V, O> Mul<Value<V>> for Value<V>where
    V: Mul<Output = O>,
"],["impl<V, O> Mul<&Value<V>> for &Value<V>where
    for<'v> &'v V: Mul<Output = O>,
"],["impl<V, O> Mul<Value<&V>> for Value<V>where
    for<'v> V: Mul<&'v V, Output = O>,
"],["impl<V, O> Mul<Value<V>> for Value<&V>where
    for<'v> &'v V: Mul<V, Output = O>,
"],["impl<V, O> Mul<&Value<V>> for Value<V>where
    for<'v> V: Mul<&'v V, Output = O>,
"],["impl<V, O> Mul<Value<V>> for &Value<V>where
    for<'v> &'v V: Mul<V, Output = O>,
"],["impl<F: Field> Mul<Value<F>> for Value<Assigned<F>>"],["impl<F: Field> Mul<F> for Value<Assigned<F>>"],["impl<F: Field> Mul<Value<F>> for Value<&Assigned<F>>"],["impl<F: Field> Mul<F> for Value<&Assigned<F>>"],["impl<F: Field> Mul<Assigned<F>> for Assigned<F>"],["impl<F: Field> Mul<F> for Assigned<F>"],["impl<F: Field> Mul<F> for &Assigned<F>"],["impl<F: Field> Mul<&Assigned<F>> for Assigned<F>"],["impl<F: Field> Mul<Expression<F>> for Expression<F>"],["impl<F: Field> Mul<F> for Expression<F>"],["impl<F: FieldExt> Mul<Blind<F>> for Blind<F>"],["impl<F: Field, B: Basis> Mul<F> for Polynomial<F, B>"]], +"halo2curves":[["impl<'b> Mul<&'b Fr> for G1"],["impl<'a> Mul<Fr> for &'a G1"],["impl Mul<Fr> for G1"],["impl<'b> Mul<&'b Fr> for G1Affine"],["impl<'a> Mul<Fr> for &'a G1Affine"],["impl Mul<Fr> for G1Affine"],["impl<'a, 'b> Mul<&'b Fr> for &'a G1"],["impl<'a, 'b> Mul<&'b Fr> for &'a G1Affine"],["impl<'b> Mul<&'b Fr> for G2"],["impl<'a> Mul<Fr> for &'a G2"],["impl Mul<Fr> for G2"],["impl<'b> Mul<&'b Fr> for G2Affine"],["impl<'a> Mul<Fr> for &'a G2Affine"],["impl Mul<Fr> for G2Affine"],["impl<'a, 'b> Mul<&'b Fr> for &'a G2"],["impl<'a, 'b> Mul<&'b Fr> for &'a G2Affine"],["impl<'a, 'b> Mul<&'b Fr> for &'a Gt"],["impl<'b> Mul<&'b Fr> for Gt"],["impl<'a> Mul<Fr> for &'a Gt"],["impl Mul<Fr> for Gt"],["impl<'b> Mul<&'b Fq> for Fq"],["impl<'a> Mul<Fq> for &'a Fq"],["impl Mul<Fq> for Fq"],["impl<'a, 'b> Mul<&'b Fq> for &'a Fq"],["impl<'a, 'b> Mul<&'b Fq12> for &'a Fq12"],["impl<'b> Mul<&'b Fq12> for Fq12"],["impl<'a> Mul<Fq12> for &'a Fq12"],["impl Mul<Fq12> for Fq12"],["impl<'a, 'b> Mul<&'b Fq2> for &'a Fq2"],["impl<'b> Mul<&'b Fq2> for Fq2"],["impl<'a> Mul<Fq2> for &'a Fq2"],["impl Mul<Fq2> for Fq2"],["impl<'a, 'b> Mul<&'b Fq6> for &'a Fq6"],["impl<'b> Mul<&'b Fq6> for Fq6"],["impl<'a> Mul<Fq6> for &'a Fq6"],["impl Mul<Fq6> for Fq6"],["impl<'b> Mul<&'b Fr> for Fr"],["impl<'a> Mul<Fr> for &'a Fr"],["impl Mul<Fr> for Fr"],["impl<'a, 'b> Mul<&'b Fr> for &'a Fr"],["impl<'b> Mul<&'b Fq> for Secp256k1"],["impl<'a> Mul<Fq> for &'a Secp256k1"],["impl Mul<Fq> for Secp256k1"],["impl<'b> Mul<&'b Fq> for Secp256k1Affine"],["impl<'a> Mul<Fq> for &'a Secp256k1Affine"],["impl Mul<Fq> for Secp256k1Affine"],["impl<'a, 'b> Mul<&'b Fq> for &'a Secp256k1"],["impl<'a, 'b> Mul<&'b Fq> for &'a Secp256k1Affine"],["impl<'b> Mul<&'b Fp> for Fp"],["impl<'a> Mul<Fp> for &'a Fp"],["impl Mul<Fp> for Fp"],["impl<'a, 'b> Mul<&'b Fp> for &'a Fp"],["impl<'b> Mul<&'b Fq> for Fq"],["impl<'a> Mul<Fq> for &'a Fq"],["impl Mul<Fq> for Fq"],["impl<'a, 'b> Mul<&'b Fq> for &'a Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.MulAssign.js b/docs/implementors/core/ops/arith/trait.MulAssign.js new file mode 100644 index 0000000000..ea6898084f --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.MulAssign.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<F: Field> MulAssign<Assigned<F>> for Assigned<F>"],["impl<F: Field> MulAssign<&Assigned<F>> for Assigned<F>"],["impl<F: FieldExt> MulAssign<Blind<F>> for Blind<F>"],["impl<F: FieldExt> MulAssign<F> for Blind<F>"]], +"halo2curves":[["impl MulAssign<Fr> for G1"],["impl<'b> MulAssign<&'b Fr> for G1"],["impl MulAssign<Fr> for G2"],["impl<'b> MulAssign<&'b Fr> for G2"],["impl MulAssign<Fr> for Gt"],["impl<'b> MulAssign<&'b Fr> for Gt"],["impl MulAssign<Fq> for Fq"],["impl<'b> MulAssign<&'b Fq> for Fq"],["impl MulAssign<Fq12> for Fq12"],["impl<'b> MulAssign<&'b Fq12> for Fq12"],["impl MulAssign<Fq2> for Fq2"],["impl<'b> MulAssign<&'b Fq2> for Fq2"],["impl MulAssign<Fq6> for Fq6"],["impl<'b> MulAssign<&'b Fq6> for Fq6"],["impl MulAssign<Fr> for Fr"],["impl<'b> MulAssign<&'b Fr> for Fr"],["impl MulAssign<Fq> for Secp256k1"],["impl<'b> MulAssign<&'b Fq> for Secp256k1"],["impl MulAssign<Fp> for Fp"],["impl<'b> MulAssign<&'b Fp> for Fp"],["impl MulAssign<Fq> for Fq"],["impl<'b> MulAssign<&'b Fq> for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.Neg.js b/docs/implementors/core/ops/arith/trait.Neg.js new file mode 100644 index 0000000000..def819d682 --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.Neg.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<V: Neg> Neg for Value<V>"],["impl<F: Field> Neg for Assigned<F>"],["impl<F: Field> Neg for &Assigned<F>"],["impl<F: Field> Neg for Expression<F>"]], +"halo2curves":[["impl<'a> Neg for &'a G1"],["impl Neg for G1"],["impl<'a> Neg for &'a G1Affine"],["impl Neg for G1Affine"],["impl<'a> Neg for &'a G2"],["impl Neg for G2"],["impl<'a> Neg for &'a G2Affine"],["impl Neg for G2Affine"],["impl<'a> Neg for &'a Gt"],["impl Neg for Gt"],["impl<'a> Neg for &'a Fq"],["impl Neg for Fq"],["impl Neg for Fq12"],["impl<'a> Neg for &'a Fq12"],["impl Neg for Fq2"],["impl<'a> Neg for &'a Fq2"],["impl Neg for Fq6"],["impl<'a> Neg for &'a Fq6"],["impl<'a> Neg for &'a Fr"],["impl Neg for Fr"],["impl<'a> Neg for &'a Secp256k1"],["impl Neg for Secp256k1"],["impl<'a> Neg for &'a Secp256k1Affine"],["impl Neg for Secp256k1Affine"],["impl<'a> Neg for &'a Fp"],["impl Neg for Fp"],["impl<'a> Neg for &'a Fq"],["impl Neg for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.Sub.js b/docs/implementors/core/ops/arith/trait.Sub.js new file mode 100644 index 0000000000..f7f286a5d3 --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.Sub.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<V, O> Sub<Value<V>> for Value<V>where
    V: Sub<Output = O>,
"],["impl<V, O> Sub<&Value<V>> for &Value<V>where
    for<'v> &'v V: Sub<Output = O>,
"],["impl<V, O> Sub<Value<&V>> for Value<V>where
    for<'v> V: Sub<&'v V, Output = O>,
"],["impl<V, O> Sub<Value<V>> for Value<&V>where
    for<'v> &'v V: Sub<V, Output = O>,
"],["impl<V, O> Sub<&Value<V>> for Value<V>where
    for<'v> V: Sub<&'v V, Output = O>,
"],["impl<V, O> Sub<Value<V>> for &Value<V>where
    for<'v> &'v V: Sub<V, Output = O>,
"],["impl<F: Field> Sub<Value<F>> for Value<Assigned<F>>"],["impl<F: Field> Sub<F> for Value<Assigned<F>>"],["impl<F: Field> Sub<Value<F>> for Value<&Assigned<F>>"],["impl<F: Field> Sub<F> for Value<&Assigned<F>>"],["impl<F: Field> Sub<Assigned<F>> for Assigned<F>"],["impl<F: Field> Sub<F> for Assigned<F>"],["impl<F: Field> Sub<F> for &Assigned<F>"],["impl<F: Field> Sub<&Assigned<F>> for Assigned<F>"],["impl<F: Field> Sub<Assigned<F>> for &Assigned<F>"],["impl<F: Field> Sub<&Assigned<F>> for &Assigned<F>"],["impl<F: Field> Sub<Expression<F>> for Expression<F>"],["impl<'a, F: Field, B: Basis> Sub<&'a Polynomial<F, B>> for Polynomial<F, B>"],["impl<'a, F: Field, B: Basis> Sub<F> for &'a Polynomial<F, B>"]], +"halo2curves":[["impl<'b> Sub<&'b G1> for G1"],["impl<'a> Sub<G1> for &'a G1"],["impl Sub<G1> for G1"],["impl<'b> Sub<&'b G1Affine> for G1"],["impl<'a> Sub<G1Affine> for &'a G1"],["impl Sub<G1Affine> for G1"],["impl<'b> Sub<&'b G1Affine> for G1Affine"],["impl<'a> Sub<G1Affine> for &'a G1Affine"],["impl Sub<G1Affine> for G1Affine"],["impl<'b> Sub<&'b G1> for G1Affine"],["impl<'a> Sub<G1> for &'a G1Affine"],["impl Sub<G1> for G1Affine"],["impl<'a, 'b> Sub<&'a G1> for &'b G1"],["impl<'a, 'b> Sub<&'a G1Affine> for &'b G1"],["impl<'a, 'b> Sub<&'a G1Affine> for &'b G1Affine"],["impl<'a, 'b> Sub<&'a G1> for &'b G1Affine"],["impl<'b> Sub<&'b G2> for G2"],["impl<'a> Sub<G2> for &'a G2"],["impl Sub<G2> for G2"],["impl<'b> Sub<&'b G2Affine> for G2"],["impl<'a> Sub<G2Affine> for &'a G2"],["impl Sub<G2Affine> for G2"],["impl<'b> Sub<&'b G2Affine> for G2Affine"],["impl<'a> Sub<G2Affine> for &'a G2Affine"],["impl Sub<G2Affine> for G2Affine"],["impl<'b> Sub<&'b G2> for G2Affine"],["impl<'a> Sub<G2> for &'a G2Affine"],["impl Sub<G2> for G2Affine"],["impl<'a, 'b> Sub<&'a G2> for &'b G2"],["impl<'a, 'b> Sub<&'a G2Affine> for &'b G2"],["impl<'a, 'b> Sub<&'a G2Affine> for &'b G2Affine"],["impl<'a, 'b> Sub<&'a G2> for &'b G2Affine"],["impl<'a, 'b> Sub<&'b Gt> for &'a Gt"],["impl<'b> Sub<&'b Gt> for Gt"],["impl<'a> Sub<Gt> for &'a Gt"],["impl Sub<Gt> for Gt"],["impl<'b> Sub<&'b Fq> for Fq"],["impl<'a> Sub<Fq> for &'a Fq"],["impl Sub<Fq> for Fq"],["impl<'a, 'b> Sub<&'b Fq> for &'a Fq"],["impl<'a, 'b> Sub<&'b Fq12> for &'a Fq12"],["impl<'b> Sub<&'b Fq12> for Fq12"],["impl<'a> Sub<Fq12> for &'a Fq12"],["impl Sub<Fq12> for Fq12"],["impl<'a, 'b> Sub<&'b Fq2> for &'a Fq2"],["impl<'b> Sub<&'b Fq2> for Fq2"],["impl<'a> Sub<Fq2> for &'a Fq2"],["impl Sub<Fq2> for Fq2"],["impl<'a, 'b> Sub<&'b Fq6> for &'a Fq6"],["impl<'b> Sub<&'b Fq6> for Fq6"],["impl<'a> Sub<Fq6> for &'a Fq6"],["impl Sub<Fq6> for Fq6"],["impl<'b> Sub<&'b Fr> for Fr"],["impl<'a> Sub<Fr> for &'a Fr"],["impl Sub<Fr> for Fr"],["impl<'a, 'b> Sub<&'b Fr> for &'a Fr"],["impl<'b> Sub<&'b Secp256k1> for Secp256k1"],["impl<'a> Sub<Secp256k1> for &'a Secp256k1"],["impl Sub<Secp256k1> for Secp256k1"],["impl<'b> Sub<&'b Secp256k1Affine> for Secp256k1"],["impl<'a> Sub<Secp256k1Affine> for &'a Secp256k1"],["impl Sub<Secp256k1Affine> for Secp256k1"],["impl<'b> Sub<&'b Secp256k1Affine> for Secp256k1Affine"],["impl<'a> Sub<Secp256k1Affine> for &'a Secp256k1Affine"],["impl Sub<Secp256k1Affine> for Secp256k1Affine"],["impl<'b> Sub<&'b Secp256k1> for Secp256k1Affine"],["impl<'a> Sub<Secp256k1> for &'a Secp256k1Affine"],["impl Sub<Secp256k1> for Secp256k1Affine"],["impl<'a, 'b> Sub<&'a Secp256k1> for &'b Secp256k1"],["impl<'a, 'b> Sub<&'a Secp256k1Affine> for &'b Secp256k1"],["impl<'a, 'b> Sub<&'a Secp256k1Affine> for &'b Secp256k1Affine"],["impl<'a, 'b> Sub<&'a Secp256k1> for &'b Secp256k1Affine"],["impl<'b> Sub<&'b Fp> for Fp"],["impl<'a> Sub<Fp> for &'a Fp"],["impl Sub<Fp> for Fp"],["impl<'a, 'b> Sub<&'b Fp> for &'a Fp"],["impl<'b> Sub<&'b Fq> for Fq"],["impl<'a> Sub<Fq> for &'a Fq"],["impl Sub<Fq> for Fq"],["impl<'a, 'b> Sub<&'b Fq> for &'a Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/arith/trait.SubAssign.js b/docs/implementors/core/ops/arith/trait.SubAssign.js new file mode 100644 index 0000000000..3e2c4a2c30 --- /dev/null +++ b/docs/implementors/core/ops/arith/trait.SubAssign.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<F: Field> SubAssign<Assigned<F>> for Assigned<F>"],["impl<F: Field> SubAssign<&Assigned<F>> for Assigned<F>"]], +"halo2curves":[["impl SubAssign<G1> for G1"],["impl<'b> SubAssign<&'b G1> for G1"],["impl SubAssign<G1Affine> for G1"],["impl<'b> SubAssign<&'b G1Affine> for G1"],["impl SubAssign<G2> for G2"],["impl<'b> SubAssign<&'b G2> for G2"],["impl SubAssign<G2Affine> for G2"],["impl<'b> SubAssign<&'b G2Affine> for G2"],["impl SubAssign<Gt> for Gt"],["impl<'b> SubAssign<&'b Gt> for Gt"],["impl SubAssign<Fq> for Fq"],["impl<'b> SubAssign<&'b Fq> for Fq"],["impl SubAssign<Fq12> for Fq12"],["impl<'b> SubAssign<&'b Fq12> for Fq12"],["impl SubAssign<Fq2> for Fq2"],["impl<'b> SubAssign<&'b Fq2> for Fq2"],["impl SubAssign<Fq6> for Fq6"],["impl<'b> SubAssign<&'b Fq6> for Fq6"],["impl SubAssign<Fr> for Fr"],["impl<'b> SubAssign<&'b Fr> for Fr"],["impl SubAssign<Secp256k1> for Secp256k1"],["impl<'b> SubAssign<&'b Secp256k1> for Secp256k1"],["impl SubAssign<Secp256k1Affine> for Secp256k1"],["impl<'b> SubAssign<&'b Secp256k1Affine> for Secp256k1"],["impl SubAssign<Fp> for Fp"],["impl<'b> SubAssign<&'b Fp> for Fp"],["impl SubAssign<Fq> for Fq"],["impl<'b> SubAssign<&'b Fq> for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/deref/trait.Deref.js b/docs/implementors/core/ops/deref/trait.Deref.js new file mode 100644 index 0000000000..407526c1f8 --- /dev/null +++ b/docs/implementors/core/ops/deref/trait.Deref.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[["impl Deref for RegionIndex"],["impl Deref for RegionStart"],["impl<F, B> Deref for Polynomial<F, B>"],["impl<C: CurveAffine, T> Deref for ChallengeScalar<C, T>"],["impl<C: CurveAffine> Deref for Challenge255<C>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/deref/trait.DerefMut.js b/docs/implementors/core/ops/deref/trait.DerefMut.js new file mode 100644 index 0000000000..5374ca0cd9 --- /dev/null +++ b/docs/implementors/core/ops/deref/trait.DerefMut.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<F, B> DerefMut for Polynomial<F, B>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/drop/trait.Drop.js b/docs/implementors/core/ops/drop/trait.Drop.js new file mode 100644 index 0000000000..f7284efbca --- /dev/null +++ b/docs/implementors/core/ops/drop/trait.Drop.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<'a, F: Field, L: Layouter<F> + 'a> Drop for NamespacedLayouter<'a, F, L>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/index/trait.Index.js b/docs/implementors/core/ops/index/trait.Index.js new file mode 100644 index 0000000000..6621746bf0 --- /dev/null +++ b/docs/implementors/core/ops/index/trait.Index.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<F, B> Index<usize> for Polynomial<F, B>"],["impl<F, B> Index<RangeFrom<usize>> for Polynomial<F, B>"],["impl<F, B> Index<RangeFull> for Polynomial<F, B>"]], +"poseidon":[["impl<F: FieldExt, const T: usize, const RATE: usize> Index<usize> for MDSMatrix<F, T, RATE>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/ops/index/trait.IndexMut.js b/docs/implementors/core/ops/index/trait.IndexMut.js new file mode 100644 index 0000000000..95d43431c5 --- /dev/null +++ b/docs/implementors/core/ops/index/trait.IndexMut.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<F, B> IndexMut<usize> for Polynomial<F, B>"],["impl<F, B> IndexMut<RangeFrom<usize>> for Polynomial<F, B>"],["impl<F, B> IndexMut<RangeFull> for Polynomial<F, B>"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/panic/unwind_safe/trait.RefUnwindSafe.js b/docs/implementors/core/panic/unwind_safe/trait.RefUnwindSafe.js new file mode 100644 index 0000000000..1cdaad667a --- /dev/null +++ b/docs/implementors/core/panic/unwind_safe/trait.RefUnwindSafe.js @@ -0,0 +1,5 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<V> RefUnwindSafe for Value<V>where
    V: RefUnwindSafe,
",1,["halo2_proofs::circuit::value::Value"]],["impl RefUnwindSafe for SimpleFloorPlanner",1,["halo2_proofs::circuit::floor_planner::single_pass::SimpleFloorPlanner"]],["impl RefUnwindSafe for RegionShape",1,["halo2_proofs::circuit::layouter::RegionShape"]],["impl RefUnwindSafe for RegionColumn",1,["halo2_proofs::circuit::layouter::RegionColumn"]],["impl RefUnwindSafe for RegionIndex",1,["halo2_proofs::circuit::RegionIndex"]],["impl RefUnwindSafe for RegionStart",1,["halo2_proofs::circuit::RegionStart"]],["impl RefUnwindSafe for Cell",1,["halo2_proofs::circuit::Cell"]],["impl<V, F> RefUnwindSafe for AssignedCell<V, F>where
    F: RefUnwindSafe,
    V: RefUnwindSafe,
",1,["halo2_proofs::circuit::AssignedCell"]],["impl<'r, F> !RefUnwindSafe for Region<'r, F>",1,["halo2_proofs::circuit::Region"]],["impl<'r, F> !RefUnwindSafe for Table<'r, F>",1,["halo2_proofs::circuit::Table"]],["impl<'a, F, L> RefUnwindSafe for NamespacedLayouter<'a, F, L>where
    F: RefUnwindSafe,
    L: RefUnwindSafe,
",1,["halo2_proofs::circuit::NamespacedLayouter"]],["impl<F> RefUnwindSafe for Assigned<F>where
    F: RefUnwindSafe,
",1,["halo2_proofs::plonk::assigned::Assigned"]],["impl<C> RefUnwindSafe for Column<C>where
    C: RefUnwindSafe,
",1,["halo2_proofs::plonk::circuit::Column"]],["impl RefUnwindSafe for FirstPhase",1,["halo2_proofs::plonk::circuit::FirstPhase"]],["impl RefUnwindSafe for SecondPhase",1,["halo2_proofs::plonk::circuit::SecondPhase"]],["impl RefUnwindSafe for ThirdPhase",1,["halo2_proofs::plonk::circuit::ThirdPhase"]],["impl RefUnwindSafe for Advice",1,["halo2_proofs::plonk::circuit::Advice"]],["impl RefUnwindSafe for Fixed",1,["halo2_proofs::plonk::circuit::Fixed"]],["impl RefUnwindSafe for Instance",1,["halo2_proofs::plonk::circuit::Instance"]],["impl RefUnwindSafe for Any",1,["halo2_proofs::plonk::circuit::Any"]],["impl RefUnwindSafe for Selector",1,["halo2_proofs::plonk::circuit::Selector"]],["impl RefUnwindSafe for FixedQuery",1,["halo2_proofs::plonk::circuit::FixedQuery"]],["impl RefUnwindSafe for AdviceQuery",1,["halo2_proofs::plonk::circuit::AdviceQuery"]],["impl RefUnwindSafe for InstanceQuery",1,["halo2_proofs::plonk::circuit::InstanceQuery"]],["impl RefUnwindSafe for TableColumn",1,["halo2_proofs::plonk::circuit::TableColumn"]],["impl RefUnwindSafe for Challenge",1,["halo2_proofs::plonk::circuit::Challenge"]],["impl<F> RefUnwindSafe for Expression<F>where
    F: RefUnwindSafe,
",1,["halo2_proofs::plonk::circuit::Expression"]],["impl RefUnwindSafe for VirtualCell",1,["halo2_proofs::plonk::circuit::VirtualCell"]],["impl<F> RefUnwindSafe for Constraint<F>where
    F: RefUnwindSafe,
",1,["halo2_proofs::plonk::circuit::Constraint"]],["impl<F, C, Iter> RefUnwindSafe for Constraints<F, C, Iter>where
    F: RefUnwindSafe,
    Iter: RefUnwindSafe,
",1,["halo2_proofs::plonk::circuit::Constraints"]],["impl<F> RefUnwindSafe for Gate<F>where
    F: RefUnwindSafe,
",1,["halo2_proofs::plonk::circuit::Gate"]],["impl<F> RefUnwindSafe for ConstraintSystem<F>where
    F: RefUnwindSafe,
",1,["halo2_proofs::plonk::circuit::ConstraintSystem"]],["impl<'a, F> RefUnwindSafe for PinnedConstraintSystem<'a, F>where
    F: RefUnwindSafe,
",1,["halo2_proofs::plonk::circuit::PinnedConstraintSystem"]],["impl<'a, F> RefUnwindSafe for VirtualCells<'a, F>where
    F: RefUnwindSafe,
",1,["halo2_proofs::plonk::circuit::VirtualCells"]],["impl !RefUnwindSafe for Error",1,["halo2_proofs::plonk::error::Error"]],["impl<C> RefUnwindSafe for BatchVerifier<C>where
    <C as CurveAffine>::ScalarExt: RefUnwindSafe,
",1,["halo2_proofs::plonk::verifier::batch::BatchVerifier"]],["impl<C> RefUnwindSafe for VerifyingKey<C>where
    C: RefUnwindSafe,
    <C as CurveAffine>::ScalarExt: RefUnwindSafe,
",1,["halo2_proofs::plonk::VerifyingKey"]],["impl<'a, C> RefUnwindSafe for PinnedVerificationKey<'a, C>where
    C: RefUnwindSafe,
    <C as CurveAffine>::ScalarExt: RefUnwindSafe,
",1,["halo2_proofs::plonk::PinnedVerificationKey"]],["impl<C> RefUnwindSafe for ProvingKey<C>where
    C: RefUnwindSafe,
    <C as CurveAffine>::ScalarExt: RefUnwindSafe,
",1,["halo2_proofs::plonk::ProvingKey"]],["impl<F> RefUnwindSafe for Blind<F>where
    F: RefUnwindSafe,
",1,["halo2_proofs::poly::commitment::Blind"]],["impl<G> RefUnwindSafe for EvaluationDomain<G>where
    <G as Group>::Scalar: RefUnwindSafe,
",1,["halo2_proofs::poly::domain::EvaluationDomain"]],["impl<'a, G> RefUnwindSafe for PinnedEvaluationDomain<'a, G>where
    <G as Group>::Scalar: RefUnwindSafe,
",1,["halo2_proofs::poly::domain::PinnedEvaluationDomain"]],["impl<'com, C> RefUnwindSafe for ProverQuery<'com, C>where
    <C as CurveAffine>::ScalarExt: RefUnwindSafe,
",1,["halo2_proofs::poly::query::ProverQuery"]],["impl<'com, C, M> RefUnwindSafe for VerifierQuery<'com, C, M>where
    C: RefUnwindSafe,
    M: RefUnwindSafe,
    <C as CurveAffine>::ScalarExt: RefUnwindSafe,
",1,["halo2_proofs::poly::query::VerifierQuery"]],["impl<C> RefUnwindSafe for ParamsIPA<C>where
    C: RefUnwindSafe,
",1,["halo2_proofs::poly::ipa::commitment::ParamsIPA"]],["impl<C> RefUnwindSafe for IPACommitmentScheme<C>where
    C: RefUnwindSafe,
",1,["halo2_proofs::poly::ipa::commitment::IPACommitmentScheme"]],["impl<'params, C> RefUnwindSafe for MSMIPA<'params, C>where
    C: RefUnwindSafe,
    <C as CurveAffine>::Base: RefUnwindSafe,
    <C as CurveAffine>::ScalarExt: RefUnwindSafe,
",1,["halo2_proofs::poly::ipa::msm::MSMIPA"]],["impl<'params, C> RefUnwindSafe for ProverIPA<'params, C>where
    C: RefUnwindSafe,
",1,["halo2_proofs::poly::ipa::multiopen::prover::ProverIPA"]],["impl<'params, C> RefUnwindSafe for VerifierIPA<'params, C>where
    C: RefUnwindSafe,
",1,["halo2_proofs::poly::ipa::multiopen::verifier::VerifierIPA"]],["impl<'params, C> RefUnwindSafe for GuardIPA<'params, C>where
    C: RefUnwindSafe,
    <C as CurveAffine>::Base: RefUnwindSafe,
    <C as CurveAffine>::ScalarExt: RefUnwindSafe,
",1,["halo2_proofs::poly::ipa::strategy::GuardIPA"]],["impl<C> RefUnwindSafe for Accumulator<C>where
    C: RefUnwindSafe,
    <C as CurveAffine>::ScalarExt: RefUnwindSafe,
",1,["halo2_proofs::poly::ipa::strategy::Accumulator"]],["impl<'params, C> RefUnwindSafe for AccumulatorStrategy<'params, C>where
    C: RefUnwindSafe,
    <C as CurveAffine>::Base: RefUnwindSafe,
    <C as CurveAffine>::ScalarExt: RefUnwindSafe,
",1,["halo2_proofs::poly::ipa::strategy::AccumulatorStrategy"]],["impl<'params, C> RefUnwindSafe for SingleStrategy<'params, C>where
    C: RefUnwindSafe,
    <C as CurveAffine>::Base: RefUnwindSafe,
    <C as CurveAffine>::ScalarExt: RefUnwindSafe,
",1,["halo2_proofs::poly::ipa::strategy::SingleStrategy"]],["impl<E> RefUnwindSafe for ParamsKZG<E>where
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
",1,["halo2_proofs::poly::kzg::commitment::ParamsKZG"]],["impl<E> RefUnwindSafe for KZGCommitmentScheme<E>where
    E: RefUnwindSafe,
",1,["halo2_proofs::poly::kzg::commitment::KZGCommitmentScheme"]],["impl<E> RefUnwindSafe for MSMKZG<E>where
    <E as Engine>::G1: RefUnwindSafe,
    <E as Engine>::Scalar: RefUnwindSafe,
",1,["halo2_proofs::poly::kzg::msm::MSMKZG"]],["impl<'a, E> RefUnwindSafe for DualMSM<'a, E>where
    <E as Engine>::G1: RefUnwindSafe,
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
    <E as Engine>::Scalar: RefUnwindSafe,
",1,["halo2_proofs::poly::kzg::msm::DualMSM"]],["impl<'params, E> RefUnwindSafe for ProverGWC<'params, E>where
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
",1,["halo2_proofs::poly::kzg::multiopen::gwc::prover::ProverGWC"]],["impl<'params, E> RefUnwindSafe for VerifierGWC<'params, E>where
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
",1,["halo2_proofs::poly::kzg::multiopen::gwc::verifier::VerifierGWC"]],["impl<'a, E> RefUnwindSafe for ProverSHPLONK<'a, E>where
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
",1,["halo2_proofs::poly::kzg::multiopen::shplonk::prover::ProverSHPLONK"]],["impl<'params, E> RefUnwindSafe for VerifierSHPLONK<'params, E>where
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
",1,["halo2_proofs::poly::kzg::multiopen::shplonk::verifier::VerifierSHPLONK"]],["impl<'params, E> RefUnwindSafe for GuardKZG<'params, E>where
    <E as Engine>::G1: RefUnwindSafe,
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
    <E as Engine>::Scalar: RefUnwindSafe,
",1,["halo2_proofs::poly::kzg::strategy::GuardKZG"]],["impl<'params, E> RefUnwindSafe for AccumulatorStrategy<'params, E>where
    <E as Engine>::G1: RefUnwindSafe,
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
    <E as Engine>::Scalar: RefUnwindSafe,
",1,["halo2_proofs::poly::kzg::strategy::AccumulatorStrategy"]],["impl<'params, E> RefUnwindSafe for SingleStrategy<'params, E>where
    <E as Engine>::G1: RefUnwindSafe,
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
    <E as Engine>::Scalar: RefUnwindSafe,
",1,["halo2_proofs::poly::kzg::strategy::SingleStrategy"]],["impl RefUnwindSafe for Error",1,["halo2_proofs::poly::Error"]],["impl RefUnwindSafe for Coeff",1,["halo2_proofs::poly::Coeff"]],["impl RefUnwindSafe for LagrangeCoeff",1,["halo2_proofs::poly::LagrangeCoeff"]],["impl RefUnwindSafe for ExtendedLagrangeCoeff",1,["halo2_proofs::poly::ExtendedLagrangeCoeff"]],["impl<F, B> RefUnwindSafe for Polynomial<F, B>where
    B: RefUnwindSafe,
    F: RefUnwindSafe,
",1,["halo2_proofs::poly::Polynomial"]],["impl RefUnwindSafe for Rotation",1,["halo2_proofs::poly::Rotation"]],["impl<R, C, E> RefUnwindSafe for Blake2bRead<R, C, E>where
    C: RefUnwindSafe,
    E: RefUnwindSafe,
    R: RefUnwindSafe,
",1,["halo2_proofs::transcript::Blake2bRead"]],["impl<W, C, E> RefUnwindSafe for Blake2bWrite<W, C, E>where
    C: RefUnwindSafe,
    E: RefUnwindSafe,
    W: RefUnwindSafe,
",1,["halo2_proofs::transcript::Blake2bWrite"]],["impl<C, T> RefUnwindSafe for ChallengeScalar<C, T>where
    T: RefUnwindSafe,
    <C as CurveAffine>::ScalarExt: RefUnwindSafe,
",1,["halo2_proofs::transcript::ChallengeScalar"]],["impl<C> RefUnwindSafe for Challenge255<C>where
    C: RefUnwindSafe,
",1,["halo2_proofs::transcript::Challenge255"]],["impl RefUnwindSafe for Column",1,["halo2_proofs::dev::metadata::Column"]],["impl RefUnwindSafe for VirtualCell",1,["halo2_proofs::dev::metadata::VirtualCell"]],["impl RefUnwindSafe for Gate",1,["halo2_proofs::dev::metadata::Gate"]],["impl RefUnwindSafe for Constraint",1,["halo2_proofs::dev::metadata::Constraint"]],["impl RefUnwindSafe for Region",1,["halo2_proofs::dev::metadata::Region"]],["impl RefUnwindSafe for FailureLocation",1,["halo2_proofs::dev::failure::FailureLocation"]],["impl RefUnwindSafe for VerifyFailure",1,["halo2_proofs::dev::failure::VerifyFailure"]],["impl RefUnwindSafe for CircuitGates",1,["halo2_proofs::dev::gates::CircuitGates"]],["impl<F> RefUnwindSafe for MockProver<F>where
    F: RefUnwindSafe,
",1,["halo2_proofs::dev::MockProver"]],["impl RefUnwindSafe for SerdeFormat",1,["halo2_proofs::helpers::SerdeFormat"]]], +"halo2curves":[["impl RefUnwindSafe for G1",1,["halo2curves::bn256::curve::G1"]],["impl RefUnwindSafe for G1Affine",1,["halo2curves::bn256::curve::G1Affine"]],["impl RefUnwindSafe for G1Compressed",1,["halo2curves::bn256::curve::G1Compressed"]],["impl RefUnwindSafe for G2",1,["halo2curves::bn256::curve::G2"]],["impl RefUnwindSafe for G2Affine",1,["halo2curves::bn256::curve::G2Affine"]],["impl RefUnwindSafe for G2Compressed",1,["halo2curves::bn256::curve::G2Compressed"]],["impl RefUnwindSafe for Gt",1,["halo2curves::bn256::engine::Gt"]],["impl RefUnwindSafe for G2Prepared",1,["halo2curves::bn256::engine::G2Prepared"]],["impl RefUnwindSafe for Bn256",1,["halo2curves::bn256::engine::Bn256"]],["impl RefUnwindSafe for Fq",1,["halo2curves::bn256::fq::Fq"]],["impl RefUnwindSafe for Fq12",1,["halo2curves::bn256::fq12::Fq12"]],["impl RefUnwindSafe for Fq2",1,["halo2curves::bn256::fq2::Fq2"]],["impl RefUnwindSafe for Fq2Bytes",1,["halo2curves::bn256::fq2::Fq2Bytes"]],["impl RefUnwindSafe for Fq6",1,["halo2curves::bn256::fq6::Fq6"]],["impl RefUnwindSafe for Fr",1,["halo2curves::bn256::fr::Fr"]],["impl RefUnwindSafe for LegendreSymbol",1,["halo2curves::bn256::LegendreSymbol"]],["impl RefUnwindSafe for Secp256k1",1,["halo2curves::secp256k1::curve::Secp256k1"]],["impl RefUnwindSafe for Secp256k1Affine",1,["halo2curves::secp256k1::curve::Secp256k1Affine"]],["impl RefUnwindSafe for Secp256k1Compressed",1,["halo2curves::secp256k1::curve::Secp256k1Compressed"]],["impl RefUnwindSafe for Fp",1,["halo2curves::secp256k1::fp::Fp"]],["impl RefUnwindSafe for Fq",1,["halo2curves::secp256k1::fq::Fq"]]], +"poseidon":[["impl<F, const T: usize, const RATE: usize> RefUnwindSafe for Poseidon<F, T, RATE>where
    F: RefUnwindSafe,
",1,["poseidon::poseidon::Poseidon"]],["impl<F, const T: usize> RefUnwindSafe for State<F, T>where
    F: RefUnwindSafe,
",1,["poseidon::spec::State"]],["impl<F, const T: usize, const RATE: usize> RefUnwindSafe for Spec<F, T, RATE>where
    F: RefUnwindSafe,
",1,["poseidon::spec::Spec"]],["impl<F, const T: usize, const RATE: usize> RefUnwindSafe for MDSMatrices<F, T, RATE>where
    F: RefUnwindSafe,
",1,["poseidon::spec::MDSMatrices"]],["impl<F, const T: usize, const RATE: usize> RefUnwindSafe for MDSMatrix<F, T, RATE>where
    F: RefUnwindSafe,
",1,["poseidon::spec::MDSMatrix"]],["impl<F, const T: usize, const RATE: usize> RefUnwindSafe for SparseMDSMatrix<F, T, RATE>where
    F: RefUnwindSafe,
",1,["poseidon::spec::SparseMDSMatrix"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/core/panic/unwind_safe/trait.UnwindSafe.js b/docs/implementors/core/panic/unwind_safe/trait.UnwindSafe.js new file mode 100644 index 0000000000..8193ae8135 --- /dev/null +++ b/docs/implementors/core/panic/unwind_safe/trait.UnwindSafe.js @@ -0,0 +1,5 @@ +(function() {var implementors = { +"halo2_proofs":[["impl<V> UnwindSafe for Value<V>where
    V: UnwindSafe,
",1,["halo2_proofs::circuit::value::Value"]],["impl UnwindSafe for SimpleFloorPlanner",1,["halo2_proofs::circuit::floor_planner::single_pass::SimpleFloorPlanner"]],["impl UnwindSafe for RegionShape",1,["halo2_proofs::circuit::layouter::RegionShape"]],["impl UnwindSafe for RegionColumn",1,["halo2_proofs::circuit::layouter::RegionColumn"]],["impl UnwindSafe for RegionIndex",1,["halo2_proofs::circuit::RegionIndex"]],["impl UnwindSafe for RegionStart",1,["halo2_proofs::circuit::RegionStart"]],["impl UnwindSafe for Cell",1,["halo2_proofs::circuit::Cell"]],["impl<V, F> UnwindSafe for AssignedCell<V, F>where
    F: UnwindSafe,
    V: UnwindSafe,
",1,["halo2_proofs::circuit::AssignedCell"]],["impl<'r, F> !UnwindSafe for Region<'r, F>",1,["halo2_proofs::circuit::Region"]],["impl<'r, F> !UnwindSafe for Table<'r, F>",1,["halo2_proofs::circuit::Table"]],["impl<'a, F, L> !UnwindSafe for NamespacedLayouter<'a, F, L>",1,["halo2_proofs::circuit::NamespacedLayouter"]],["impl<F> UnwindSafe for Assigned<F>where
    F: UnwindSafe,
",1,["halo2_proofs::plonk::assigned::Assigned"]],["impl<C> UnwindSafe for Column<C>where
    C: UnwindSafe,
",1,["halo2_proofs::plonk::circuit::Column"]],["impl UnwindSafe for FirstPhase",1,["halo2_proofs::plonk::circuit::FirstPhase"]],["impl UnwindSafe for SecondPhase",1,["halo2_proofs::plonk::circuit::SecondPhase"]],["impl UnwindSafe for ThirdPhase",1,["halo2_proofs::plonk::circuit::ThirdPhase"]],["impl UnwindSafe for Advice",1,["halo2_proofs::plonk::circuit::Advice"]],["impl UnwindSafe for Fixed",1,["halo2_proofs::plonk::circuit::Fixed"]],["impl UnwindSafe for Instance",1,["halo2_proofs::plonk::circuit::Instance"]],["impl UnwindSafe for Any",1,["halo2_proofs::plonk::circuit::Any"]],["impl UnwindSafe for Selector",1,["halo2_proofs::plonk::circuit::Selector"]],["impl UnwindSafe for FixedQuery",1,["halo2_proofs::plonk::circuit::FixedQuery"]],["impl UnwindSafe for AdviceQuery",1,["halo2_proofs::plonk::circuit::AdviceQuery"]],["impl UnwindSafe for InstanceQuery",1,["halo2_proofs::plonk::circuit::InstanceQuery"]],["impl UnwindSafe for TableColumn",1,["halo2_proofs::plonk::circuit::TableColumn"]],["impl UnwindSafe for Challenge",1,["halo2_proofs::plonk::circuit::Challenge"]],["impl<F> UnwindSafe for Expression<F>where
    F: UnwindSafe,
",1,["halo2_proofs::plonk::circuit::Expression"]],["impl UnwindSafe for VirtualCell",1,["halo2_proofs::plonk::circuit::VirtualCell"]],["impl<F> UnwindSafe for Constraint<F>where
    F: UnwindSafe,
",1,["halo2_proofs::plonk::circuit::Constraint"]],["impl<F, C, Iter> UnwindSafe for Constraints<F, C, Iter>where
    F: UnwindSafe,
    Iter: UnwindSafe,
",1,["halo2_proofs::plonk::circuit::Constraints"]],["impl<F> UnwindSafe for Gate<F>where
    F: UnwindSafe,
",1,["halo2_proofs::plonk::circuit::Gate"]],["impl<F> UnwindSafe for ConstraintSystem<F>where
    F: UnwindSafe,
",1,["halo2_proofs::plonk::circuit::ConstraintSystem"]],["impl<'a, F> UnwindSafe for PinnedConstraintSystem<'a, F>where
    F: RefUnwindSafe,
",1,["halo2_proofs::plonk::circuit::PinnedConstraintSystem"]],["impl<'a, F> !UnwindSafe for VirtualCells<'a, F>",1,["halo2_proofs::plonk::circuit::VirtualCells"]],["impl !UnwindSafe for Error",1,["halo2_proofs::plonk::error::Error"]],["impl<C> UnwindSafe for BatchVerifier<C>where
    <C as CurveAffine>::ScalarExt: UnwindSafe,
",1,["halo2_proofs::plonk::verifier::batch::BatchVerifier"]],["impl<C> UnwindSafe for VerifyingKey<C>where
    C: UnwindSafe,
    <C as CurveAffine>::ScalarExt: UnwindSafe,
",1,["halo2_proofs::plonk::VerifyingKey"]],["impl<'a, C> UnwindSafe for PinnedVerificationKey<'a, C>where
    C: RefUnwindSafe,
    <C as CurveAffine>::ScalarExt: RefUnwindSafe,
",1,["halo2_proofs::plonk::PinnedVerificationKey"]],["impl<C> UnwindSafe for ProvingKey<C>where
    C: UnwindSafe,
    <C as CurveAffine>::ScalarExt: UnwindSafe,
",1,["halo2_proofs::plonk::ProvingKey"]],["impl<F> UnwindSafe for Blind<F>where
    F: UnwindSafe,
",1,["halo2_proofs::poly::commitment::Blind"]],["impl<G> UnwindSafe for EvaluationDomain<G>where
    <G as Group>::Scalar: UnwindSafe,
",1,["halo2_proofs::poly::domain::EvaluationDomain"]],["impl<'a, G> UnwindSafe for PinnedEvaluationDomain<'a, G>where
    <G as Group>::Scalar: RefUnwindSafe,
",1,["halo2_proofs::poly::domain::PinnedEvaluationDomain"]],["impl<'com, C> UnwindSafe for ProverQuery<'com, C>where
    <C as CurveAffine>::ScalarExt: UnwindSafe + RefUnwindSafe,
",1,["halo2_proofs::poly::query::ProverQuery"]],["impl<'com, C, M> UnwindSafe for VerifierQuery<'com, C, M>where
    C: RefUnwindSafe,
    M: RefUnwindSafe,
    <C as CurveAffine>::ScalarExt: UnwindSafe,
",1,["halo2_proofs::poly::query::VerifierQuery"]],["impl<C> UnwindSafe for ParamsIPA<C>where
    C: UnwindSafe,
",1,["halo2_proofs::poly::ipa::commitment::ParamsIPA"]],["impl<C> UnwindSafe for IPACommitmentScheme<C>where
    C: UnwindSafe,
",1,["halo2_proofs::poly::ipa::commitment::IPACommitmentScheme"]],["impl<'params, C> UnwindSafe for MSMIPA<'params, C>where
    C: RefUnwindSafe,
    <C as CurveAffine>::Base: RefUnwindSafe,
    <C as CurveAffine>::ScalarExt: UnwindSafe + RefUnwindSafe,
",1,["halo2_proofs::poly::ipa::msm::MSMIPA"]],["impl<'params, C> UnwindSafe for ProverIPA<'params, C>where
    C: RefUnwindSafe,
",1,["halo2_proofs::poly::ipa::multiopen::prover::ProverIPA"]],["impl<'params, C> UnwindSafe for VerifierIPA<'params, C>where
    C: RefUnwindSafe,
",1,["halo2_proofs::poly::ipa::multiopen::verifier::VerifierIPA"]],["impl<'params, C> UnwindSafe for GuardIPA<'params, C>where
    C: RefUnwindSafe,
    <C as CurveAffine>::Base: RefUnwindSafe,
    <C as CurveAffine>::ScalarExt: UnwindSafe + RefUnwindSafe,
",1,["halo2_proofs::poly::ipa::strategy::GuardIPA"]],["impl<C> UnwindSafe for Accumulator<C>where
    C: UnwindSafe,
    <C as CurveAffine>::ScalarExt: UnwindSafe,
",1,["halo2_proofs::poly::ipa::strategy::Accumulator"]],["impl<'params, C> UnwindSafe for AccumulatorStrategy<'params, C>where
    C: RefUnwindSafe,
    <C as CurveAffine>::Base: RefUnwindSafe,
    <C as CurveAffine>::ScalarExt: UnwindSafe + RefUnwindSafe,
",1,["halo2_proofs::poly::ipa::strategy::AccumulatorStrategy"]],["impl<'params, C> UnwindSafe for SingleStrategy<'params, C>where
    C: RefUnwindSafe,
    <C as CurveAffine>::Base: RefUnwindSafe,
    <C as CurveAffine>::ScalarExt: UnwindSafe + RefUnwindSafe,
",1,["halo2_proofs::poly::ipa::strategy::SingleStrategy"]],["impl<E> UnwindSafe for ParamsKZG<E>where
    <E as Engine>::G1Affine: UnwindSafe,
    <E as Engine>::G2Affine: UnwindSafe,
",1,["halo2_proofs::poly::kzg::commitment::ParamsKZG"]],["impl<E> UnwindSafe for KZGCommitmentScheme<E>where
    E: UnwindSafe,
",1,["halo2_proofs::poly::kzg::commitment::KZGCommitmentScheme"]],["impl<E> UnwindSafe for MSMKZG<E>where
    <E as Engine>::G1: UnwindSafe,
    <E as Engine>::Scalar: UnwindSafe,
",1,["halo2_proofs::poly::kzg::msm::MSMKZG"]],["impl<'a, E> UnwindSafe for DualMSM<'a, E>where
    <E as Engine>::G1: UnwindSafe,
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
    <E as Engine>::Scalar: UnwindSafe,
",1,["halo2_proofs::poly::kzg::msm::DualMSM"]],["impl<'params, E> UnwindSafe for ProverGWC<'params, E>where
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
",1,["halo2_proofs::poly::kzg::multiopen::gwc::prover::ProverGWC"]],["impl<'params, E> UnwindSafe for VerifierGWC<'params, E>where
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
",1,["halo2_proofs::poly::kzg::multiopen::gwc::verifier::VerifierGWC"]],["impl<'a, E> UnwindSafe for ProverSHPLONK<'a, E>where
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
",1,["halo2_proofs::poly::kzg::multiopen::shplonk::prover::ProverSHPLONK"]],["impl<'params, E> UnwindSafe for VerifierSHPLONK<'params, E>where
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
",1,["halo2_proofs::poly::kzg::multiopen::shplonk::verifier::VerifierSHPLONK"]],["impl<'params, E> UnwindSafe for GuardKZG<'params, E>where
    <E as Engine>::G1: UnwindSafe,
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
    <E as Engine>::Scalar: UnwindSafe,
",1,["halo2_proofs::poly::kzg::strategy::GuardKZG"]],["impl<'params, E> UnwindSafe for AccumulatorStrategy<'params, E>where
    <E as Engine>::G1: UnwindSafe,
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
    <E as Engine>::Scalar: UnwindSafe,
",1,["halo2_proofs::poly::kzg::strategy::AccumulatorStrategy"]],["impl<'params, E> UnwindSafe for SingleStrategy<'params, E>where
    <E as Engine>::G1: UnwindSafe,
    <E as Engine>::G1Affine: RefUnwindSafe,
    <E as Engine>::G2Affine: RefUnwindSafe,
    <E as Engine>::Scalar: UnwindSafe,
",1,["halo2_proofs::poly::kzg::strategy::SingleStrategy"]],["impl UnwindSafe for Error",1,["halo2_proofs::poly::Error"]],["impl UnwindSafe for Coeff",1,["halo2_proofs::poly::Coeff"]],["impl UnwindSafe for LagrangeCoeff",1,["halo2_proofs::poly::LagrangeCoeff"]],["impl UnwindSafe for ExtendedLagrangeCoeff",1,["halo2_proofs::poly::ExtendedLagrangeCoeff"]],["impl<F, B> UnwindSafe for Polynomial<F, B>where
    B: UnwindSafe,
    F: UnwindSafe,
",1,["halo2_proofs::poly::Polynomial"]],["impl UnwindSafe for Rotation",1,["halo2_proofs::poly::Rotation"]],["impl<R, C, E> UnwindSafe for Blake2bRead<R, C, E>where
    C: UnwindSafe,
    E: UnwindSafe,
    R: UnwindSafe,
",1,["halo2_proofs::transcript::Blake2bRead"]],["impl<W, C, E> UnwindSafe for Blake2bWrite<W, C, E>where
    C: UnwindSafe,
    E: UnwindSafe,
    W: UnwindSafe,
",1,["halo2_proofs::transcript::Blake2bWrite"]],["impl<C, T> UnwindSafe for ChallengeScalar<C, T>where
    T: UnwindSafe,
    <C as CurveAffine>::ScalarExt: UnwindSafe,
",1,["halo2_proofs::transcript::ChallengeScalar"]],["impl<C> UnwindSafe for Challenge255<C>where
    C: UnwindSafe,
",1,["halo2_proofs::transcript::Challenge255"]],["impl UnwindSafe for Column",1,["halo2_proofs::dev::metadata::Column"]],["impl UnwindSafe for VirtualCell",1,["halo2_proofs::dev::metadata::VirtualCell"]],["impl UnwindSafe for Gate",1,["halo2_proofs::dev::metadata::Gate"]],["impl UnwindSafe for Constraint",1,["halo2_proofs::dev::metadata::Constraint"]],["impl UnwindSafe for Region",1,["halo2_proofs::dev::metadata::Region"]],["impl UnwindSafe for FailureLocation",1,["halo2_proofs::dev::failure::FailureLocation"]],["impl UnwindSafe for VerifyFailure",1,["halo2_proofs::dev::failure::VerifyFailure"]],["impl UnwindSafe for CircuitGates",1,["halo2_proofs::dev::gates::CircuitGates"]],["impl<F> UnwindSafe for MockProver<F>where
    F: UnwindSafe + RefUnwindSafe,
",1,["halo2_proofs::dev::MockProver"]],["impl UnwindSafe for SerdeFormat",1,["halo2_proofs::helpers::SerdeFormat"]]], +"halo2curves":[["impl UnwindSafe for G1",1,["halo2curves::bn256::curve::G1"]],["impl UnwindSafe for G1Affine",1,["halo2curves::bn256::curve::G1Affine"]],["impl UnwindSafe for G1Compressed",1,["halo2curves::bn256::curve::G1Compressed"]],["impl UnwindSafe for G2",1,["halo2curves::bn256::curve::G2"]],["impl UnwindSafe for G2Affine",1,["halo2curves::bn256::curve::G2Affine"]],["impl UnwindSafe for G2Compressed",1,["halo2curves::bn256::curve::G2Compressed"]],["impl UnwindSafe for Gt",1,["halo2curves::bn256::engine::Gt"]],["impl UnwindSafe for G2Prepared",1,["halo2curves::bn256::engine::G2Prepared"]],["impl UnwindSafe for Bn256",1,["halo2curves::bn256::engine::Bn256"]],["impl UnwindSafe for Fq",1,["halo2curves::bn256::fq::Fq"]],["impl UnwindSafe for Fq12",1,["halo2curves::bn256::fq12::Fq12"]],["impl UnwindSafe for Fq2",1,["halo2curves::bn256::fq2::Fq2"]],["impl UnwindSafe for Fq2Bytes",1,["halo2curves::bn256::fq2::Fq2Bytes"]],["impl UnwindSafe for Fq6",1,["halo2curves::bn256::fq6::Fq6"]],["impl UnwindSafe for Fr",1,["halo2curves::bn256::fr::Fr"]],["impl UnwindSafe for LegendreSymbol",1,["halo2curves::bn256::LegendreSymbol"]],["impl UnwindSafe for Secp256k1",1,["halo2curves::secp256k1::curve::Secp256k1"]],["impl UnwindSafe for Secp256k1Affine",1,["halo2curves::secp256k1::curve::Secp256k1Affine"]],["impl UnwindSafe for Secp256k1Compressed",1,["halo2curves::secp256k1::curve::Secp256k1Compressed"]],["impl UnwindSafe for Fp",1,["halo2curves::secp256k1::fp::Fp"]],["impl UnwindSafe for Fq",1,["halo2curves::secp256k1::fq::Fq"]]], +"poseidon":[["impl<F, const T: usize, const RATE: usize> UnwindSafe for Poseidon<F, T, RATE>where
    F: UnwindSafe,
",1,["poseidon::poseidon::Poseidon"]],["impl<F, const T: usize> UnwindSafe for State<F, T>where
    F: UnwindSafe,
",1,["poseidon::spec::State"]],["impl<F, const T: usize, const RATE: usize> UnwindSafe for Spec<F, T, RATE>where
    F: UnwindSafe,
",1,["poseidon::spec::Spec"]],["impl<F, const T: usize, const RATE: usize> UnwindSafe for MDSMatrices<F, T, RATE>where
    F: UnwindSafe,
",1,["poseidon::spec::MDSMatrices"]],["impl<F, const T: usize, const RATE: usize> UnwindSafe for MDSMatrix<F, T, RATE>where
    F: UnwindSafe,
",1,["poseidon::spec::MDSMatrix"]],["impl<F, const T: usize, const RATE: usize> UnwindSafe for SparseMDSMatrix<F, T, RATE>where
    F: UnwindSafe,
",1,["poseidon::spec::SparseMDSMatrix"]]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/ff/trait.Field.js b/docs/implementors/ff/trait.Field.js new file mode 100644 index 0000000000..d464b2d5ec --- /dev/null +++ b/docs/implementors/ff/trait.Field.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[], +"halo2curves":[["impl Field for Fq"],["impl Field for Fq12"],["impl Field for Fq2"],["impl Field for Fq6"],["impl Field for Fr"],["impl Field for Fp"],["impl Field for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/ff/trait.PrimeField.js b/docs/implementors/ff/trait.PrimeField.js new file mode 100644 index 0000000000..0d1ca2a764 --- /dev/null +++ b/docs/implementors/ff/trait.PrimeField.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl PrimeField for Fq"],["impl PrimeField for Fq2"],["impl PrimeField for Fr"],["impl PrimeField for Fp"],["impl PrimeField for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/group/cofactor/trait.CofactorCurve.js b/docs/implementors/group/cofactor/trait.CofactorCurve.js new file mode 100644 index 0000000000..77f854eb5f --- /dev/null +++ b/docs/implementors/group/cofactor/trait.CofactorCurve.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl CofactorCurve for G1"],["impl CofactorCurve for G2"],["impl CofactorCurve for Secp256k1"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/group/cofactor/trait.CofactorCurveAffine.js b/docs/implementors/group/cofactor/trait.CofactorCurveAffine.js new file mode 100644 index 0000000000..669f04a630 --- /dev/null +++ b/docs/implementors/group/cofactor/trait.CofactorCurveAffine.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl CofactorCurveAffine for G1Affine"],["impl CofactorCurveAffine for G2Affine"],["impl CofactorCurveAffine for Secp256k1Affine"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/group/cofactor/trait.CofactorGroup.js b/docs/implementors/group/cofactor/trait.CofactorGroup.js new file mode 100644 index 0000000000..8ecd2e65fb --- /dev/null +++ b/docs/implementors/group/cofactor/trait.CofactorGroup.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl CofactorGroup for G1"],["impl CofactorGroup for G2"],["impl CofactorGroup for Secp256k1"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/group/prime/trait.PrimeCurve.js b/docs/implementors/group/prime/trait.PrimeCurve.js new file mode 100644 index 0000000000..23d7847266 --- /dev/null +++ b/docs/implementors/group/prime/trait.PrimeCurve.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl PrimeCurve for G1"],["impl PrimeCurve for G2"],["impl PrimeCurve for Secp256k1"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/group/prime/trait.PrimeCurveAffine.js b/docs/implementors/group/prime/trait.PrimeCurveAffine.js new file mode 100644 index 0000000000..8f2c342856 --- /dev/null +++ b/docs/implementors/group/prime/trait.PrimeCurveAffine.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl PrimeCurveAffine for G1Affine"],["impl PrimeCurveAffine for G2Affine"],["impl PrimeCurveAffine for Secp256k1Affine"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/group/prime/trait.PrimeGroup.js b/docs/implementors/group/prime/trait.PrimeGroup.js new file mode 100644 index 0000000000..3b19697c14 --- /dev/null +++ b/docs/implementors/group/prime/trait.PrimeGroup.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl PrimeGroup for G1"],["impl PrimeGroup for G2"],["impl PrimeGroup for Secp256k1"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/group/trait.Curve.js b/docs/implementors/group/trait.Curve.js new file mode 100644 index 0000000000..bd124db7c0 --- /dev/null +++ b/docs/implementors/group/trait.Curve.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl Curve for G1"],["impl Curve for G2"],["impl Curve for Secp256k1"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/group/trait.Group.js b/docs/implementors/group/trait.Group.js new file mode 100644 index 0000000000..3c2f00ee00 --- /dev/null +++ b/docs/implementors/group/trait.Group.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl Group for G1"],["impl Group for G2"],["impl Group for Gt"],["impl Group for Secp256k1"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/group/trait.GroupEncoding.js b/docs/implementors/group/trait.GroupEncoding.js new file mode 100644 index 0000000000..238f8cba74 --- /dev/null +++ b/docs/implementors/group/trait.GroupEncoding.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl GroupEncoding for G1"],["impl GroupEncoding for G1Affine"],["impl GroupEncoding for G2"],["impl GroupEncoding for G2Affine"],["impl GroupEncoding for Secp256k1"],["impl GroupEncoding for Secp256k1Affine"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/group/trait.UncompressedEncoding.js b/docs/implementors/group/trait.UncompressedEncoding.js new file mode 100644 index 0000000000..21787ffece --- /dev/null +++ b/docs/implementors/group/trait.UncompressedEncoding.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl UncompressedEncoding for G1Affine"],["impl UncompressedEncoding for G2Affine"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/circuit/trait.Layouter.js b/docs/implementors/halo2_proofs/circuit/trait.Layouter.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/circuit/trait.Layouter.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/plonk/circuit/trait.Assignment.js b/docs/implementors/halo2_proofs/plonk/circuit/trait.Assignment.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/plonk/circuit/trait.Assignment.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/plonk/circuit/trait.ColumnType.js b/docs/implementors/halo2_proofs/plonk/circuit/trait.ColumnType.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/plonk/circuit/trait.ColumnType.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/plonk/circuit/trait.FloorPlanner.js b/docs/implementors/halo2_proofs/plonk/circuit/trait.FloorPlanner.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/plonk/circuit/trait.FloorPlanner.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/plonk/circuit/trait.Phase.js b/docs/implementors/halo2_proofs/plonk/circuit/trait.Phase.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/plonk/circuit/trait.Phase.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/poly/commitment/trait.CommitmentScheme.js b/docs/implementors/halo2_proofs/poly/commitment/trait.CommitmentScheme.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/poly/commitment/trait.CommitmentScheme.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/poly/commitment/trait.MSM.js b/docs/implementors/halo2_proofs/poly/commitment/trait.MSM.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/poly/commitment/trait.MSM.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/poly/commitment/trait.Params.js b/docs/implementors/halo2_proofs/poly/commitment/trait.Params.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/poly/commitment/trait.Params.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/poly/commitment/trait.ParamsProver.js b/docs/implementors/halo2_proofs/poly/commitment/trait.ParamsProver.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/poly/commitment/trait.ParamsProver.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/poly/commitment/trait.ParamsVerifier.js b/docs/implementors/halo2_proofs/poly/commitment/trait.ParamsVerifier.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/poly/commitment/trait.ParamsVerifier.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/poly/commitment/trait.Prover.js b/docs/implementors/halo2_proofs/poly/commitment/trait.Prover.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/poly/commitment/trait.Prover.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/poly/commitment/trait.Verifier.js b/docs/implementors/halo2_proofs/poly/commitment/trait.Verifier.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/poly/commitment/trait.Verifier.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/poly/strategy/trait.Guard.js b/docs/implementors/halo2_proofs/poly/strategy/trait.Guard.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/poly/strategy/trait.Guard.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/poly/strategy/trait.VerificationStrategy.js b/docs/implementors/halo2_proofs/poly/strategy/trait.VerificationStrategy.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/poly/strategy/trait.VerificationStrategy.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/poly/trait.Basis.js b/docs/implementors/halo2_proofs/poly/trait.Basis.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/poly/trait.Basis.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/transcript/trait.EncodedChallenge.js b/docs/implementors/halo2_proofs/transcript/trait.EncodedChallenge.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/transcript/trait.EncodedChallenge.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/transcript/trait.Transcript.js b/docs/implementors/halo2_proofs/transcript/trait.Transcript.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/transcript/trait.Transcript.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/transcript/trait.TranscriptRead.js b/docs/implementors/halo2_proofs/transcript/trait.TranscriptRead.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/transcript/trait.TranscriptRead.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/transcript/trait.TranscriptReadBuffer.js b/docs/implementors/halo2_proofs/transcript/trait.TranscriptReadBuffer.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/transcript/trait.TranscriptReadBuffer.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/transcript/trait.TranscriptWrite.js b/docs/implementors/halo2_proofs/transcript/trait.TranscriptWrite.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/transcript/trait.TranscriptWrite.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2_proofs/transcript/trait.TranscriptWriterBuffer.js b/docs/implementors/halo2_proofs/transcript/trait.TranscriptWriterBuffer.js new file mode 100644 index 0000000000..3c90c6340b --- /dev/null +++ b/docs/implementors/halo2_proofs/transcript/trait.TranscriptWriterBuffer.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2_proofs":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2curves/arithmetic/trait.CurveAffineExt.js b/docs/implementors/halo2curves/arithmetic/trait.CurveAffineExt.js new file mode 100644 index 0000000000..c3a6b91ed0 --- /dev/null +++ b/docs/implementors/halo2curves/arithmetic/trait.CurveAffineExt.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2curves/pairing/trait.Engine.js b/docs/implementors/halo2curves/pairing/trait.Engine.js new file mode 100644 index 0000000000..c3a6b91ed0 --- /dev/null +++ b/docs/implementors/halo2curves/pairing/trait.Engine.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2curves/pairing/trait.MillerLoopResult.js b/docs/implementors/halo2curves/pairing/trait.MillerLoopResult.js new file mode 100644 index 0000000000..c3a6b91ed0 --- /dev/null +++ b/docs/implementors/halo2curves/pairing/trait.MillerLoopResult.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2curves/pairing/trait.MultiMillerLoop.js b/docs/implementors/halo2curves/pairing/trait.MultiMillerLoop.js new file mode 100644 index 0000000000..c3a6b91ed0 --- /dev/null +++ b/docs/implementors/halo2curves/pairing/trait.MultiMillerLoop.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2curves/pairing/trait.PairingCurveAffine.js b/docs/implementors/halo2curves/pairing/trait.PairingCurveAffine.js new file mode 100644 index 0000000000..c3a6b91ed0 --- /dev/null +++ b/docs/implementors/halo2curves/pairing/trait.PairingCurveAffine.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/halo2curves/serde/trait.SerdeObject.js b/docs/implementors/halo2curves/serde/trait.SerdeObject.js new file mode 100644 index 0000000000..c3a6b91ed0 --- /dev/null +++ b/docs/implementors/halo2curves/serde/trait.SerdeObject.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/pasta_curves/arithmetic/curves/trait.CurveAffine.js b/docs/implementors/pasta_curves/arithmetic/curves/trait.CurveAffine.js new file mode 100644 index 0000000000..5145a67156 --- /dev/null +++ b/docs/implementors/pasta_curves/arithmetic/curves/trait.CurveAffine.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[], +"halo2curves":[["impl CurveAffine for G1Affine"],["impl CurveAffine for G2Affine"],["impl CurveAffine for Secp256k1Affine"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/pasta_curves/arithmetic/curves/trait.CurveExt.js b/docs/implementors/pasta_curves/arithmetic/curves/trait.CurveExt.js new file mode 100644 index 0000000000..7820e8071f --- /dev/null +++ b/docs/implementors/pasta_curves/arithmetic/curves/trait.CurveExt.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[], +"halo2curves":[["impl CurveExt for G1"],["impl CurveExt for G2"],["impl CurveExt for Secp256k1"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/pasta_curves/arithmetic/fields/trait.FieldExt.js b/docs/implementors/pasta_curves/arithmetic/fields/trait.FieldExt.js new file mode 100644 index 0000000000..13315dc820 --- /dev/null +++ b/docs/implementors/pasta_curves/arithmetic/fields/trait.FieldExt.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[], +"halo2curves":[["impl FieldExt for Fq"],["impl FieldExt for Fq2"],["impl FieldExt for Fr"],["impl FieldExt for Fp"],["impl FieldExt for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/pasta_curves/arithmetic/fields/trait.SqrtRatio.js b/docs/implementors/pasta_curves/arithmetic/fields/trait.SqrtRatio.js new file mode 100644 index 0000000000..5b01d8d4d8 --- /dev/null +++ b/docs/implementors/pasta_curves/arithmetic/fields/trait.SqrtRatio.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl SqrtRatio for Fq"],["impl SqrtRatio for Fq2"],["impl SqrtRatio for Fr"],["impl SqrtRatio for Fp"],["impl SqrtRatio for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/pasta_curves/arithmetic/trait.Group.js b/docs/implementors/pasta_curves/arithmetic/trait.Group.js new file mode 100644 index 0000000000..73bf41ab50 --- /dev/null +++ b/docs/implementors/pasta_curves/arithmetic/trait.Group.js @@ -0,0 +1,4 @@ +(function() {var implementors = { +"halo2_proofs":[], +"halo2curves":[["impl Group for G1"],["impl Group for G2"],["impl Group for Fq"],["impl Group for Fq2"],["impl Group for Fr"],["impl Group for Secp256k1"],["impl Group for Fp"],["impl Group for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/serde/de/trait.Deserialize.js b/docs/implementors/serde/de/trait.Deserialize.js new file mode 100644 index 0000000000..f0ee39335b --- /dev/null +++ b/docs/implementors/serde/de/trait.Deserialize.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl<'de> Deserialize<'de> for G1"],["impl<'de> Deserialize<'de> for G1Affine"],["impl<'de> Deserialize<'de> for G2"],["impl<'de> Deserialize<'de> for G2Affine"],["impl<'de> Deserialize<'de> for Fq"],["impl<'de> Deserialize<'de> for Fq12"],["impl<'de> Deserialize<'de> for Fq2"],["impl<'de> Deserialize<'de> for Fq6"],["impl<'de> Deserialize<'de> for Fr"],["impl<'de> Deserialize<'de> for Secp256k1"],["impl<'de> Deserialize<'de> for Secp256k1Affine"],["impl<'de> Deserialize<'de> for Fp"],["impl<'de> Deserialize<'de> for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/serde/ser/trait.Serialize.js b/docs/implementors/serde/ser/trait.Serialize.js new file mode 100644 index 0000000000..d1e2ff720c --- /dev/null +++ b/docs/implementors/serde/ser/trait.Serialize.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl Serialize for G1"],["impl Serialize for G1Affine"],["impl Serialize for G2"],["impl Serialize for G2Affine"],["impl Serialize for Fq"],["impl Serialize for Fq12"],["impl Serialize for Fq2"],["impl Serialize for Fq6"],["impl Serialize for Fr"],["impl Serialize for Secp256k1"],["impl Serialize for Secp256k1Affine"],["impl Serialize for Fp"],["impl Serialize for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/subtle/trait.ConditionallySelectable.js b/docs/implementors/subtle/trait.ConditionallySelectable.js new file mode 100644 index 0000000000..0556526ac3 --- /dev/null +++ b/docs/implementors/subtle/trait.ConditionallySelectable.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl ConditionallySelectable for G1"],["impl ConditionallySelectable for G1Affine"],["impl ConditionallySelectable for G2"],["impl ConditionallySelectable for G2Affine"],["impl ConditionallySelectable for Gt"],["impl ConditionallySelectable for Fq"],["impl ConditionallySelectable for Fq12"],["impl ConditionallySelectable for Fq2"],["impl ConditionallySelectable for Fq6"],["impl ConditionallySelectable for Fr"],["impl ConditionallySelectable for Secp256k1"],["impl ConditionallySelectable for Secp256k1Affine"],["impl ConditionallySelectable for Fp"],["impl ConditionallySelectable for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/implementors/subtle/trait.ConstantTimeEq.js b/docs/implementors/subtle/trait.ConstantTimeEq.js new file mode 100644 index 0000000000..2ea0d73e23 --- /dev/null +++ b/docs/implementors/subtle/trait.ConstantTimeEq.js @@ -0,0 +1,3 @@ +(function() {var implementors = { +"halo2curves":[["impl ConstantTimeEq for G1"],["impl ConstantTimeEq for G1Affine"],["impl ConstantTimeEq for G2"],["impl ConstantTimeEq for G2Affine"],["impl ConstantTimeEq for Gt"],["impl ConstantTimeEq for Fq"],["impl ConstantTimeEq for Fq12"],["impl ConstantTimeEq for Fq2"],["impl ConstantTimeEq for Fq6"],["impl ConstantTimeEq for Fr"],["impl ConstantTimeEq for Secp256k1"],["impl ConstantTimeEq for Secp256k1Affine"],["impl ConstantTimeEq for Fp"],["impl ConstantTimeEq for Fq"]] +};if (window.register_implementors) {window.register_implementors(implementors);} else {window.pending_implementors = implementors;}})() \ No newline at end of file diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000000..a0225dd969 --- /dev/null +++ b/docs/index.html @@ -0,0 +1 @@ + diff --git a/docs/light.css b/docs/light.css new file mode 100644 index 0000000000..1aa2dceef9 --- /dev/null +++ b/docs/light.css @@ -0,0 +1 @@ +:root{--main-background-color:white;--main-color:black;--settings-input-color:#2196f3;--sidebar-background-color:#F5F5F5;--sidebar-background-color-hover:#E0E0E0;--code-block-background-color:#F5F5F5;--scrollbar-track-background-color:#dcdcdc;--scrollbar-thumb-background-color:rgba(36,37,39,0.6);--scrollbar-color:rgba(36,37,39,0.6) #d9d9d9;--headings-border-bottom-color:#ddd;--border-color:#e0e0e0;--button-background-color:#fff;--right-side-color:grey;--code-attribute-color:#999;--toggles-color:#999;--search-input-focused-border-color:#66afe9;--copy-path-button-color:#999;--copy-path-img-filter:invert(50%);--copy-path-img-hover-filter:invert(35%);--codeblock-error-hover-color:rgb(255,0,0);--codeblock-error-color:rgba(255,0,0,.5);--codeblock-ignore-hover-color:rgb(255,142,0);--codeblock-ignore-color:rgba(255,142,0,.6);--type-link-color:#ad378a;--trait-link-color:#6e4fc9;--assoc-item-link-color:#3873ad;--function-link-color:#ad7c37;--macro-link-color:#068000;--keyword-link-color:#3873ad;--mod-link-color:#3873ad;--link-color:#3873ad;--sidebar-link-color:#356da4;--sidebar-current-link-background-color:#fff;--search-result-link-focus-background-color:#ccc;--stab-background-color:#fff5d6;--stab-code-color:#000;--search-color:#000;--code-highlight-kw-color:#8959a8;--code-highlight-kw-2-color:#4271ae;--code-highlight-lifetime-color:#b76514;--code-highlight-prelude-color:#4271ae;--code-highlight-prelude-val-color:#c82829;--code-highlight-number-color:#718c00;--code-highlight-string-color:#718c00;--code-highlight-literal-color:#c82829;--code-highlight-attribute-color:#c82829;--code-highlight-self-color:#c82829;--code-highlight-macro-color:#3e999f;--code-highlight-question-mark-color:#ff9011;--code-highlight-comment-color:#8e908c;--code-highlight-doc-comment-color:#4d4d4c;}.slider{background-color:#ccc;}.slider:before{background-color:white;}input:focus+.slider{box-shadow:0 0 0 2px #0a84ff,0 0 0 6px rgba(10,132,255,0.3);}.rust-logo{}.src-line-numbers span{color:#c67e2d;}.src-line-numbers .line-highlighted{background-color:#FDFFD3 !important;}.content .item-info::before{color:#ccc;}body.source .example-wrap pre.rust a{background:#eee;}#crate-search-div::after{filter:invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%);}#crate-search:hover,#crate-search:focus{border-color:#717171 !important;}#crate-search-div:hover::after,#crate-search-div:focus-within::after{filter:invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%);}.src-line-numbers :target{background-color:transparent;}pre.example-line-numbers{border-color:#c7c7c7;}a.test-arrow{color:#f5f5f5;background-color:rgba(78,139,202,0.2);}a.test-arrow:hover{background-color:#4e8bca;}:target{background:#FDFFD3;border-right:3px solid #AD7C37;}.search-failed a{color:#3873AD;}.tooltip::after{background-color:#000;color:#fff;}.tooltip::before{border-color:transparent black transparent transparent;}.notable-traits-tooltiptext{background-color:#eee;}#titles>button:not(.selected){background-color:#e6e6e6;border-top-color:#e6e6e6;}#titles>button:hover,#titles>button.selected{background-color:#ffffff;border-top-color:#0089ff;}#titles>button>div.count{color:#888;}kbd{color:#000;background-color:#fafbfc;box-shadow:inset 0 -1px 0 #c6cbd1;}#settings-menu>a,#help-button>a{color:#000;}#settings-menu>a:hover,#settings-menu>a:focus,#help-button>a:hover,#help-button>a:focus{border-color:#717171;}.search-results .result-name span.alias{color:#000;}.search-results .result-name span.grey{color:#999;}#source-sidebar div.files>a:hover,details.dir-entry summary:hover,#source-sidebar div.files>a:focus,details.dir-entry summary:focus{background-color:#E0E0E0;}#source-sidebar div.files>a.selected{background-color:#fff;}.scraped-example-list .scrape-help{border-color:#555;color:#333;}.scraped-example-list .scrape-help:hover{border-color:black;color:black;}.scraped-example .example-wrap .rust span.highlight{background:#fcffd6;}.scraped-example .example-wrap .rust span.highlight.focus{background:#f6fdb0;}.scraped-example:not(.expanded) .code-wrapper:before{background:linear-gradient(to bottom,rgba(255,255,255,1),rgba(255,255,255,0));}.scraped-example:not(.expanded) .code-wrapper:after{background:linear-gradient(to top,rgba(255,255,255,1),rgba(255,255,255,0));}.toggle-line-inner{background:#ccc;}.toggle-line:hover .toggle-line-inner{background:#999;} \ No newline at end of file diff --git a/docs/main.js b/docs/main.js new file mode 100644 index 0000000000..63d1a20b55 --- /dev/null +++ b/docs/main.js @@ -0,0 +1,8 @@ +"use strict";function getVar(name){const el=document.getElementById("rustdoc-vars");if(el){return el.attributes["data-"+name].value}else{return null}}function resourcePath(basename,extension){return getVar("root-path")+basename+getVar("resource-suffix")+extension}function hideMain(){addClass(document.getElementById(MAIN_ID),"hidden")}function showMain(){removeClass(document.getElementById(MAIN_ID),"hidden")}function elemIsInParent(elem,parent){while(elem&&elem!==document.body){if(elem===parent){return true}elem=elem.parentElement}return false}function blurHandler(event,parentElem,hideCallback){if(!elemIsInParent(document.activeElement,parentElem)&&!elemIsInParent(event.relatedTarget,parentElem)){hideCallback()}}(function(){window.rootPath=getVar("root-path");window.currentCrate=getVar("current-crate")}());function setMobileTopbar(){const mobileLocationTitle=document.querySelector(".mobile-topbar h2");const locationTitle=document.querySelector(".sidebar h2.location");if(mobileLocationTitle&&locationTitle){mobileLocationTitle.innerHTML=locationTitle.innerHTML}}function getVirtualKey(ev){if("key"in ev&&typeof ev.key!=="undefined"){return ev.key}const c=ev.charCode||ev.keyCode;if(c===27){return"Escape"}return String.fromCharCode(c)}const MAIN_ID="main-content";const SETTINGS_BUTTON_ID="settings-menu";const ALTERNATIVE_DISPLAY_ID="alternative-display";const NOT_DISPLAYED_ID="not-displayed";const HELP_BUTTON_ID="help-button";function getSettingsButton(){return document.getElementById(SETTINGS_BUTTON_ID)}function getHelpButton(){return document.getElementById(HELP_BUTTON_ID)}function getNakedUrl(){return window.location.href.split("?")[0].split("#")[0]}function insertAfter(newNode,referenceNode){referenceNode.parentNode.insertBefore(newNode,referenceNode.nextSibling)}function getOrCreateSection(id,classes){let el=document.getElementById(id);if(!el){el=document.createElement("section");el.id=id;el.className=classes;insertAfter(el,document.getElementById(MAIN_ID))}return el}function getAlternativeDisplayElem(){return getOrCreateSection(ALTERNATIVE_DISPLAY_ID,"content hidden")}function getNotDisplayedElem(){return getOrCreateSection(NOT_DISPLAYED_ID,"hidden")}function switchDisplayedElement(elemToDisplay){const el=getAlternativeDisplayElem();if(el.children.length>0){getNotDisplayedElem().appendChild(el.firstElementChild)}if(elemToDisplay===null){addClass(el,"hidden");showMain();return}el.appendChild(elemToDisplay);hideMain();removeClass(el,"hidden")}function browserSupportsHistoryApi(){return window.history&&typeof window.history.pushState==="function"}function loadCss(cssFileName){const link=document.createElement("link");link.href=resourcePath(cssFileName,".css");link.type="text/css";link.rel="stylesheet";document.getElementsByTagName("head")[0].appendChild(link)}(function(){const isHelpPage=window.location.pathname.endsWith("/help.html");function loadScript(url){const script=document.createElement("script");script.src=url;document.head.append(script)}getSettingsButton().onclick=event=>{if(event.ctrlKey||event.altKey||event.metaKey){return}addClass(getSettingsButton(),"rotate");event.preventDefault();loadCss("settings");loadScript(resourcePath("settings",".js"))};window.searchState={loadingText:"Loading search results...",input:document.getElementsByClassName("search-input")[0],outputElement:()=>{let el=document.getElementById("search");if(!el){el=document.createElement("section");el.id="search";getNotDisplayedElem().appendChild(el)}return el},title:document.title,titleBeforeSearch:document.title,timeout:null,currentTab:0,focusedByTab:[null,null,null],clearInputTimeout:()=>{if(searchState.timeout!==null){clearTimeout(searchState.timeout);searchState.timeout=null}},isDisplayed:()=>searchState.outputElement().parentElement.id===ALTERNATIVE_DISPLAY_ID,focus:()=>{searchState.input.focus()},defocus:()=>{searchState.input.blur()},showResults:search=>{if(search===null||typeof search==="undefined"){search=searchState.outputElement()}switchDisplayedElement(search);searchState.mouseMovedAfterSearch=false;document.title=searchState.title},hideResults:()=>{switchDisplayedElement(null);document.title=searchState.titleBeforeSearch;if(browserSupportsHistoryApi()){history.replaceState(null,window.currentCrate+" - Rust",getNakedUrl()+window.location.hash)}},getQueryStringParams:()=>{const params={};window.location.search.substring(1).split("&").map(s=>{const pair=s.split("=");params[decodeURIComponent(pair[0])]=typeof pair[1]==="undefined"?null:decodeURIComponent(pair[1])});return params},setup:()=>{const search_input=searchState.input;if(!searchState.input){return}let searchLoaded=false;function loadSearch(){if(!searchLoaded){searchLoaded=true;loadScript(resourcePath("search",".js"));loadScript(resourcePath("search-index",".js"))}}search_input.addEventListener("focus",()=>{search_input.origPlaceholder=search_input.placeholder;search_input.placeholder="Type your search here.";loadSearch()});if(search_input.value!==""){loadSearch()}const params=searchState.getQueryStringParams();if(params.search!==undefined){const search=searchState.outputElement();search.innerHTML="

"+searchState.loadingText+"

";searchState.showResults(search);loadSearch()}},};function getPageId(){if(window.location.hash){const tmp=window.location.hash.replace(/^#/,"");if(tmp.length>0){return tmp}}return null}const toggleAllDocsId="toggle-all-docs";let savedHash="";function handleHashes(ev){if(ev!==null&&searchState.isDisplayed()&&ev.newURL){switchDisplayedElement(null);const hash=ev.newURL.slice(ev.newURL.indexOf("#")+1);if(browserSupportsHistoryApi()){history.replaceState(null,"",getNakedUrl()+window.location.search+"#"+hash)}const elem=document.getElementById(hash);if(elem){elem.scrollIntoView()}}if(savedHash!==window.location.hash){savedHash=window.location.hash;if(savedHash.length===0){return}expandSection(savedHash.slice(1))}}function onHashChange(ev){hideSidebar();handleHashes(ev)}function openParentDetails(elem){while(elem){if(elem.tagName==="DETAILS"){elem.open=true}elem=elem.parentNode}}function expandSection(id){openParentDetails(document.getElementById(id))}function handleEscape(ev){searchState.clearInputTimeout();switchDisplayedElement(null);if(browserSupportsHistoryApi()){history.replaceState(null,window.currentCrate+" - Rust",getNakedUrl()+window.location.hash)}ev.preventDefault();searchState.defocus();window.hidePopoverMenus()}function handleShortcut(ev){const disableShortcuts=getSettingValue("disable-shortcuts")==="true";if(ev.ctrlKey||ev.altKey||ev.metaKey||disableShortcuts){return}if(document.activeElement.tagName==="INPUT"&&document.activeElement.type!=="checkbox"){switch(getVirtualKey(ev)){case"Escape":handleEscape(ev);break}}else{switch(getVirtualKey(ev)){case"Escape":handleEscape(ev);break;case"s":case"S":ev.preventDefault();searchState.focus();break;case"+":ev.preventDefault();expandAllDocs();break;case"-":ev.preventDefault();collapseAllDocs();break;case"?":showHelp();break;default:break}}}document.addEventListener("keypress",handleShortcut);document.addEventListener("keydown",handleShortcut);function addSidebarItems(){if(!window.SIDEBAR_ITEMS){return}const sidebar=document.getElementsByClassName("sidebar-elems")[0];function block(shortty,id,longty){const filtered=window.SIDEBAR_ITEMS[shortty];if(!filtered){return}const h3=document.createElement("h3");h3.innerHTML=`${longty}`;const ul=document.createElement("ul");ul.className="block "+shortty;for(const item of filtered){const name=item[0];const desc=item[1];let path;if(shortty==="mod"){path=name+"/index.html"}else{path=shortty+"."+name+".html"}const current_page=document.location.href.split("/").pop();const link=document.createElement("a");link.href=path;link.title=desc;if(path===current_page){link.className="current"}link.textContent=name;const li=document.createElement("li");li.appendChild(link);ul.appendChild(li)}sidebar.appendChild(h3);sidebar.appendChild(ul)}if(sidebar){block("primitive","primitives","Primitive Types");block("mod","modules","Modules");block("macro","macros","Macros");block("struct","structs","Structs");block("enum","enums","Enums");block("union","unions","Unions");block("constant","constants","Constants");block("static","static","Statics");block("trait","traits","Traits");block("fn","functions","Functions");block("type","types","Type Definitions");block("foreigntype","foreign-types","Foreign Types");block("keyword","keywords","Keywords");block("traitalias","trait-aliases","Trait Aliases")}}window.register_implementors=imp=>{const implementors=document.getElementById("implementors-list");const synthetic_implementors=document.getElementById("synthetic-implementors-list");const inlined_types=new Set();const TEXT_IDX=0;const SYNTHETIC_IDX=1;const TYPES_IDX=2;if(synthetic_implementors){onEachLazy(synthetic_implementors.getElementsByClassName("impl"),el=>{const aliases=el.getAttribute("data-aliases");if(!aliases){return}aliases.split(",").forEach(alias=>{inlined_types.add(alias)})})}let currentNbImpls=implementors.getElementsByClassName("impl").length;const traitName=document.querySelector("h1.fqn > .trait").textContent;const baseIdName="impl-"+traitName+"-";const libs=Object.getOwnPropertyNames(imp);const script=document.querySelector("script[data-ignore-extern-crates]");const ignoreExternCrates=script?script.getAttribute("data-ignore-extern-crates"):"";for(const lib of libs){if(lib===window.currentCrate||ignoreExternCrates.indexOf(lib)!==-1){continue}const structs=imp[lib];struct_loop:for(const struct of structs){const list=struct[SYNTHETIC_IDX]?synthetic_implementors:implementors;if(struct[SYNTHETIC_IDX]){for(const struct_type of struct[TYPES_IDX]){if(inlined_types.has(struct_type)){continue struct_loop}inlined_types.add(struct_type)}}const code=document.createElement("h3");code.innerHTML=struct[TEXT_IDX];addClass(code,"code-header");onEachLazy(code.getElementsByTagName("a"),elem=>{const href=elem.getAttribute("href");if(href&&href.indexOf("http")!==0){elem.setAttribute("href",window.rootPath+href)}});const currentId=baseIdName+currentNbImpls;const anchor=document.createElement("a");anchor.href="#"+currentId;addClass(anchor,"anchor");const display=document.createElement("div");display.id=currentId;addClass(display,"impl");display.appendChild(anchor);display.appendChild(code);list.appendChild(display);currentNbImpls+=1}}};if(window.pending_implementors){window.register_implementors(window.pending_implementors)}function addSidebarCrates(){if(!window.ALL_CRATES){return}const sidebarElems=document.getElementsByClassName("sidebar-elems")[0];if(!sidebarElems){return}const h3=document.createElement("h3");h3.innerHTML="Crates";const ul=document.createElement("ul");ul.className="block crate";for(const crate of window.ALL_CRATES){const link=document.createElement("a");link.href=window.rootPath+crate+"/index.html";if(window.rootPath!=="./"&&crate===window.currentCrate){link.className="current"}link.textContent=crate;const li=document.createElement("li");li.appendChild(link);ul.appendChild(li)}sidebarElems.appendChild(h3);sidebarElems.appendChild(ul)}function expandAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);removeClass(innerToggle,"will-expand");onEachLazy(document.getElementsByClassName("rustdoc-toggle"),e=>{if(!hasClass(e,"type-contents-toggle")){e.open=true}});innerToggle.title="collapse all docs";innerToggle.children[0].innerText="\u2212"}function collapseAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);addClass(innerToggle,"will-expand");onEachLazy(document.getElementsByClassName("rustdoc-toggle"),e=>{if(e.parentNode.id!=="implementations-list"||(!hasClass(e,"implementors-toggle")&&!hasClass(e,"type-contents-toggle"))){e.open=false}});innerToggle.title="expand all docs";innerToggle.children[0].innerText="+"}function toggleAllDocs(){const innerToggle=document.getElementById(toggleAllDocsId);if(!innerToggle){return}if(hasClass(innerToggle,"will-expand")){expandAllDocs()}else{collapseAllDocs()}}(function(){const toggles=document.getElementById(toggleAllDocsId);if(toggles){toggles.onclick=toggleAllDocs}const hideMethodDocs=getSettingValue("auto-hide-method-docs")==="true";const hideImplementations=getSettingValue("auto-hide-trait-implementations")==="true";const hideLargeItemContents=getSettingValue("auto-hide-large-items")!=="false";function setImplementorsTogglesOpen(id,open){const list=document.getElementById(id);if(list!==null){onEachLazy(list.getElementsByClassName("implementors-toggle"),e=>{e.open=open})}}if(hideImplementations){setImplementorsTogglesOpen("trait-implementations-list",false);setImplementorsTogglesOpen("blanket-implementations-list",false)}onEachLazy(document.getElementsByClassName("rustdoc-toggle"),e=>{if(!hideLargeItemContents&&hasClass(e,"type-contents-toggle")){e.open=true}if(hideMethodDocs&&hasClass(e,"method-toggle")){e.open=false}});const pageId=getPageId();if(pageId!==null){expandSection(pageId)}}());window.rustdoc_add_line_numbers_to_examples=()=>{onEachLazy(document.getElementsByClassName("rust-example-rendered"),x=>{const parent=x.parentNode;const line_numbers=parent.querySelectorAll(".example-line-numbers");if(line_numbers.length>0){return}const count=x.textContent.split("\n").length;const elems=[];for(let i=0;i{onEachLazy(document.getElementsByClassName("rust-example-rendered"),x=>{const parent=x.parentNode;const line_numbers=parent.querySelectorAll(".example-line-numbers");for(const node of line_numbers){parent.removeChild(node)}})};(function(){if(getSettingValue("line-numbers")==="true"){window.rustdoc_add_line_numbers_to_examples()}}());let oldSidebarScrollPosition=null;window.rustdocMobileScrollLock=function(){const mobile_topbar=document.querySelector(".mobile-topbar");if(window.innerWidth<=window.RUSTDOC_MOBILE_BREAKPOINT){oldSidebarScrollPosition=window.scrollY;document.body.style.width=`${document.body.offsetWidth}px`;document.body.style.position="fixed";document.body.style.top=`-${oldSidebarScrollPosition}px`;if(mobile_topbar){mobile_topbar.style.top=`${oldSidebarScrollPosition}px`;mobile_topbar.style.position="relative"}}else{oldSidebarScrollPosition=null}};window.rustdocMobileScrollUnlock=function(){const mobile_topbar=document.querySelector(".mobile-topbar");if(oldSidebarScrollPosition!==null){document.body.style.width="";document.body.style.position="";document.body.style.top="";if(mobile_topbar){mobile_topbar.style.top="";mobile_topbar.style.position=""}window.scrollTo(0,oldSidebarScrollPosition);oldSidebarScrollPosition=null}};function showSidebar(){window.rustdocMobileScrollLock();const sidebar=document.getElementsByClassName("sidebar")[0];addClass(sidebar,"shown")}function hideSidebar(){window.rustdocMobileScrollUnlock();const sidebar=document.getElementsByClassName("sidebar")[0];removeClass(sidebar,"shown")}window.addEventListener("resize",()=>{if(window.innerWidth>window.RUSTDOC_MOBILE_BREAKPOINT&&oldSidebarScrollPosition!==null){hideSidebar()}});function handleClick(id,f){const elem=document.getElementById(id);if(elem){elem.addEventListener("click",f)}}handleClick(MAIN_ID,()=>{hideSidebar()});onEachLazy(document.getElementsByTagName("a"),el=>{if(el.hash){el.addEventListener("click",()=>{expandSection(el.hash.slice(1));hideSidebar()})}});onEachLazy(document.querySelectorAll(".rustdoc-toggle > summary:not(.hideme)"),el=>{el.addEventListener("click",e=>{if(e.target.tagName!=="SUMMARY"&&e.target.tagName!=="A"){e.preventDefault()}})});onEachLazy(document.getElementsByClassName("notable-traits"),e=>{e.onclick=function(){this.getElementsByClassName("notable-traits-tooltiptext")[0].classList.toggle("force-tooltip")}});const sidebar_menu_toggle=document.getElementsByClassName("sidebar-menu-toggle")[0];if(sidebar_menu_toggle){sidebar_menu_toggle.addEventListener("click",()=>{const sidebar=document.getElementsByClassName("sidebar")[0];if(!hasClass(sidebar,"shown")){showSidebar()}else{hideSidebar()}})}function helpBlurHandler(event){blurHandler(event,getHelpButton(),window.hidePopoverMenus)}function buildHelpMenu(){const book_info=document.createElement("span");book_info.className="top";book_info.innerHTML="You can find more information in \ + the rustdoc book.";const shortcuts=[["?","Show this help dialog"],["S","Focus the search field"],["↑","Move up in search results"],["↓","Move down in search results"],["← / →","Switch result tab (when results focused)"],["⏎","Go to active search result"],["+","Expand all sections"],["-","Collapse all sections"],].map(x=>"
"+x[0].split(" ").map((y,index)=>((index&1)===0?""+y+"":" "+y+" ")).join("")+"
"+x[1]+"
").join("");const div_shortcuts=document.createElement("div");addClass(div_shortcuts,"shortcuts");div_shortcuts.innerHTML="

Keyboard Shortcuts

"+shortcuts+"
";const infos=["Prefix searches with a type followed by a colon (e.g., fn:) to \ + restrict the search to a given item kind.","Accepted kinds are: fn, mod, struct, \ + enum, trait, type, macro, \ + and const.","Search functions by type signature (e.g., vec -> usize or \ + -> vec)","Search multiple things at once by splitting your query with comma (e.g., \ + str,u8 or String,struct:Vec,test)","You can look for items with an exact name by putting double quotes around \ + your request: \"string\"","Look for items inside another one by searching for a path: vec::Vec",].map(x=>"

"+x+"

").join("");const div_infos=document.createElement("div");addClass(div_infos,"infos");div_infos.innerHTML="

Search Tricks

"+infos;const rustdoc_version=document.createElement("span");rustdoc_version.className="bottom";const rustdoc_version_code=document.createElement("code");rustdoc_version_code.innerText="rustdoc "+getVar("rustdoc-version");rustdoc_version.appendChild(rustdoc_version_code);const container=document.createElement("div");if(!isHelpPage){container.className="popover"}container.id="help";container.style.display="none";const side_by_side=document.createElement("div");side_by_side.className="side-by-side";side_by_side.appendChild(div_shortcuts);side_by_side.appendChild(div_infos);container.appendChild(book_info);container.appendChild(side_by_side);container.appendChild(rustdoc_version);if(isHelpPage){const help_section=document.createElement("section");help_section.appendChild(container);document.getElementById("main-content").appendChild(help_section);container.style.display="block"}else{const help_button=getHelpButton();help_button.appendChild(container);container.onblur=helpBlurHandler;container.onclick=event=>{event.preventDefault()};help_button.onblur=helpBlurHandler;help_button.children[0].onblur=helpBlurHandler}return container}window.hidePopoverMenus=function(){onEachLazy(document.querySelectorAll(".search-container .popover"),elem=>{elem.style.display="none"})};function getHelpMenu(buildNeeded){let menu=getHelpButton().querySelector(".popover");if(!menu&&buildNeeded){menu=buildHelpMenu()}return menu}function showHelp(){const menu=getHelpMenu(true);if(menu.style.display==="none"){window.hidePopoverMenus();menu.style.display=""}}if(isHelpPage){showHelp();document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click",event=>{const target=event.target;if(target.tagName!=="A"||target.parentElement.id!==HELP_BUTTON_ID||event.ctrlKey||event.altKey||event.metaKey){return}event.preventDefault()})}else{document.querySelector(`#${HELP_BUTTON_ID} > a`).addEventListener("click",event=>{const target=event.target;if(target.tagName!=="A"||target.parentElement.id!==HELP_BUTTON_ID||event.ctrlKey||event.altKey||event.metaKey){return}event.preventDefault();const menu=getHelpMenu(true);const shouldShowHelp=menu.style.display==="none";if(shouldShowHelp){showHelp()}else{window.hidePopoverMenus()}})}setMobileTopbar();addSidebarItems();addSidebarCrates();onHashChange(null);window.addEventListener("hashchange",onHashChange);searchState.setup()}());(function(){let reset_button_timeout=null;window.copy_path=but=>{const parent=but.parentElement;const path=[];onEach(parent.childNodes,child=>{if(child.tagName==="A"){path.push(child.textContent)}});const el=document.createElement("textarea");el.value=path.join("::");el.setAttribute("readonly","");el.style.position="absolute";el.style.left="-9999px";document.body.appendChild(el);el.select();document.execCommand("copy");document.body.removeChild(el);but.children[0].style.display="none";let tmp;if(but.childNodes.length<2){tmp=document.createTextNode("✓");but.appendChild(tmp)}else{onEachLazy(but.childNodes,e=>{if(e.nodeType===Node.TEXT_NODE){tmp=e;return true}});tmp.textContent="✓"}if(reset_button_timeout!==null){window.clearTimeout(reset_button_timeout)}function reset_button(){tmp.textContent="";reset_button_timeout=null;but.children[0].style.display=""}reset_button_timeout=window.setTimeout(reset_button,1000)}}()) \ No newline at end of file diff --git a/docs/normalize.css b/docs/normalize.css new file mode 100644 index 0000000000..469959f137 --- /dev/null +++ b/docs/normalize.css @@ -0,0 +1,2 @@ + /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ +html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:0.67em 0}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}img{border-style:none}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type="button"],[type="reset"],[type="submit"],button{-webkit-appearance:button}[type="button"]::-moz-focus-inner,[type="reset"]::-moz-focus-inner,[type="submit"]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type="button"]:-moz-focusring,[type="reset"]:-moz-focusring,[type="submit"]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{padding:0.35em 0.75em 0.625em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{vertical-align:baseline}textarea{overflow:auto}[type="checkbox"],[type="radio"]{box-sizing:border-box;padding:0}[type="number"]::-webkit-inner-spin-button,[type="number"]::-webkit-outer-spin-button{height:auto}[type="search"]{-webkit-appearance:textfield;outline-offset:-2px}[type="search"]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details{display:block}summary{display:list-item}template{display:none}[hidden]{display:none} \ No newline at end of file diff --git a/docs/noscript.css b/docs/noscript.css new file mode 100644 index 0000000000..e81ec197ac --- /dev/null +++ b/docs/noscript.css @@ -0,0 +1 @@ + #main-content .attributes{margin-left:0 !important;}#copy-path{display:none;}nav.sub{display:none;}.source .sidebar{display:none;} \ No newline at end of file diff --git a/docs/poseidon/all.html b/docs/poseidon/all.html new file mode 100644 index 0000000000..691bb0588f --- /dev/null +++ b/docs/poseidon/all.html @@ -0,0 +1 @@ +List of all items in this crate
\ No newline at end of file diff --git a/docs/poseidon/index.html b/docs/poseidon/index.html new file mode 100644 index 0000000000..500409d88b --- /dev/null +++ b/docs/poseidon/index.html @@ -0,0 +1,11 @@ +poseidon - Rust
Expand description

Poseidon hashing implemention with variable lenght input setting. This crate +also exposes constant parameters for circuit implementations

+

Structs

MDSMatrices holds the MDS matrix as well as transition matrix which is +also called pre_sparse_mds and sparse matrices that enables us to reduce +number of multiplications in apply MDS step
MDSMatrix is applied to State to achive linear layer of Poseidon
Poseidon hasher that maintains state and inputs and yields single element +output when desired
SparseMDSMatrix are in [row], [hat | identity] form and used in linear +layer of partial rounds instead of the original MDS
Spec holds construction parameters as well as constants that are used in +permutation step. Constants are planned to be hardcoded once transcript +design matures. Number of partial rounds can be deriven from number of +constants.
State is structure T sized field elements that are subjected to +permutation
\ No newline at end of file diff --git a/docs/poseidon/poseidon/struct.Poseidon.html b/docs/poseidon/poseidon/struct.Poseidon.html new file mode 100644 index 0000000000..77e7bed649 --- /dev/null +++ b/docs/poseidon/poseidon/struct.Poseidon.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../poseidon/struct.Poseidon.html...

+ + + \ No newline at end of file diff --git a/docs/poseidon/sidebar-items.js b/docs/poseidon/sidebar-items.js new file mode 100644 index 0000000000..3f79f33e36 --- /dev/null +++ b/docs/poseidon/sidebar-items.js @@ -0,0 +1 @@ +window.SIDEBAR_ITEMS = {"struct":[["MDSMatrices","`MDSMatrices` holds the MDS matrix as well as transition matrix which is also called `pre_sparse_mds` and sparse matrices that enables us to reduce number of multiplications in apply MDS step"],["MDSMatrix","`MDSMatrix` is applied to `State` to achive linear layer of Poseidon"],["Poseidon","Poseidon hasher that maintains state and inputs and yields single element output when desired"],["SparseMDSMatrix","`SparseMDSMatrix` are in `[row], [hat | identity]` form and used in linear layer of partial rounds instead of the original MDS"],["Spec","`Spec` holds construction parameters as well as constants that are used in permutation step. Constants are planned to be hardcoded once transcript design matures. Number of partial rounds can be deriven from number of constants."],["State","`State` is structure `T` sized field elements that are subjected to permutation"]]}; \ No newline at end of file diff --git a/docs/poseidon/spec/struct.MDSMatrices.html b/docs/poseidon/spec/struct.MDSMatrices.html new file mode 100644 index 0000000000..18b1e671aa --- /dev/null +++ b/docs/poseidon/spec/struct.MDSMatrices.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../poseidon/struct.MDSMatrices.html...

+ + + \ No newline at end of file diff --git a/docs/poseidon/spec/struct.MDSMatrix.html b/docs/poseidon/spec/struct.MDSMatrix.html new file mode 100644 index 0000000000..14d7367b61 --- /dev/null +++ b/docs/poseidon/spec/struct.MDSMatrix.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../poseidon/struct.MDSMatrix.html...

+ + + \ No newline at end of file diff --git a/docs/poseidon/spec/struct.SparseMDSMatrix.html b/docs/poseidon/spec/struct.SparseMDSMatrix.html new file mode 100644 index 0000000000..6845d1c6e4 --- /dev/null +++ b/docs/poseidon/spec/struct.SparseMDSMatrix.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../poseidon/struct.SparseMDSMatrix.html...

+ + + \ No newline at end of file diff --git a/docs/poseidon/spec/struct.Spec.html b/docs/poseidon/spec/struct.Spec.html new file mode 100644 index 0000000000..f3feae0f23 --- /dev/null +++ b/docs/poseidon/spec/struct.Spec.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../poseidon/struct.Spec.html...

+ + + \ No newline at end of file diff --git a/docs/poseidon/spec/struct.State.html b/docs/poseidon/spec/struct.State.html new file mode 100644 index 0000000000..fe06648b61 --- /dev/null +++ b/docs/poseidon/spec/struct.State.html @@ -0,0 +1,11 @@ + + + + + Redirection + + +

Redirecting to ../../poseidon/struct.State.html...

+ + + \ No newline at end of file diff --git a/docs/poseidon/struct.MDSMatrices.html b/docs/poseidon/struct.MDSMatrices.html new file mode 100644 index 0000000000..5a94db2318 --- /dev/null +++ b/docs/poseidon/struct.MDSMatrices.html @@ -0,0 +1,27 @@ +MDSMatrices in poseidon - Rust
pub struct MDSMatrices<F: FieldExt, const T: usize, const RATE: usize> { /* private fields */ }
Expand description

MDSMatrices holds the MDS matrix as well as transition matrix which is +also called pre_sparse_mds and sparse matrices that enables us to reduce +number of multiplications in apply MDS step

+

Implementations

Returns original MDS matrix

+

Returns transition matrix for sparse trick

+

Returns sparse matrices for partial rounds

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/poseidon/struct.MDSMatrix.html b/docs/poseidon/struct.MDSMatrix.html new file mode 100644 index 0000000000..e6f23dca31 --- /dev/null +++ b/docs/poseidon/struct.MDSMatrix.html @@ -0,0 +1,24 @@ +MDSMatrix in poseidon - Rust
pub struct MDSMatrix<F: FieldExt, const T: usize, const RATE: usize>(_);
Expand description

MDSMatrix is applied to State to achive linear layer of Poseidon

+

Implementations

Returns rows of the MDS matrix

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Assert the form and represent an MDS matrix as a sparse MDS matrix

+
The returned type after indexing.
Performs the indexing (container[index]) operation. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/poseidon/struct.Poseidon.html b/docs/poseidon/struct.Poseidon.html new file mode 100644 index 0000000000..073cdfd111 --- /dev/null +++ b/docs/poseidon/struct.Poseidon.html @@ -0,0 +1,27 @@ +Poseidon in poseidon - Rust
pub struct Poseidon<F: FieldExt, const T: usize, const RATE: usize> { /* private fields */ }
Expand description

Poseidon hasher that maintains state and inputs and yields single element +output when desired

+

Implementations

Constructs a clear state poseidon instance

+

Appends elements to the absorption line updates state while RATE is +full

+

Results a single element by absorbing already added inputs

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/poseidon/struct.SparseMDSMatrix.html b/docs/poseidon/struct.SparseMDSMatrix.html new file mode 100644 index 0000000000..d311d3a6aa --- /dev/null +++ b/docs/poseidon/struct.SparseMDSMatrix.html @@ -0,0 +1,26 @@ +SparseMDSMatrix in poseidon - Rust
pub struct SparseMDSMatrix<F: FieldExt, const T: usize, const RATE: usize> { /* private fields */ }
Expand description

SparseMDSMatrix are in [row], [hat | identity] form and used in linear +layer of partial rounds instead of the original MDS

+

Implementations

Returns the first row

+

Returns the first column without first element in the first row

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Assert the form and represent an MDS matrix as a sparse MDS matrix

+

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/poseidon/struct.Spec.html b/docs/poseidon/struct.Spec.html new file mode 100644 index 0000000000..5137bfcf6c --- /dev/null +++ b/docs/poseidon/struct.Spec.html @@ -0,0 +1,32 @@ +Spec in poseidon - Rust
pub struct Spec<F: FieldExt, const T: usize, const RATE: usize> { /* private fields */ }
Expand description

Spec holds construction parameters as well as constants that are used in +permutation step. Constants are planned to be hardcoded once transcript +design matures. Number of partial rounds can be deriven from number of +constants.

+

Implementations

Applies the Poseidon permutation to the given state

+

Number of full rounds

+

Set of MDS Matrices used in permutation line

+

Optimised round constants

+

Given number of round parameters constructs new Posedion instance +calculating unoptimized round constants with reference Grain then +calculates optimized constants and sparse matrices

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/poseidon/struct.State.html b/docs/poseidon/struct.State.html new file mode 100644 index 0000000000..b6fd03ea69 --- /dev/null +++ b/docs/poseidon/struct.State.html @@ -0,0 +1,27 @@ +State in poseidon - Rust
pub struct State<F: FieldExt, const T: usize>(_);
Expand description

State is structure T sized field elements that are subjected to +permutation

+

Implementations

Copies elements of the state

+

Trait Implementations

Returns a copy of the value. Read more
Performs copy-assignment from source. Read more
Formats the value using the given formatter. Read more

The capacity value is 2**64 + (o − 1) where o the output length.

+
This method tests for self and other values to be equal, and is used +by ==. Read more
This method tests for !=. The default implementation is almost always +sufficient, and should not be overridden without very good reason. Read more

Auto Trait Implementations

Blanket Implementations

Gets the TypeId of self. Read more
Immutably borrows from an owned value. Read more
Mutably borrows from an owned value. Read more
Converts self into T using Into<T>. Read more
Causes self to use its Binary implementation when Debug-formatted.
Causes self to use its Display implementation when +Debug-formatted. Read more
Causes self to use its LowerExp implementation when +Debug-formatted. Read more
Causes self to use its LowerHex implementation when +Debug-formatted. Read more
Causes self to use its Octal implementation when Debug-formatted.
Causes self to use its Pointer implementation when +Debug-formatted. Read more
Causes self to use its UpperExp implementation when +Debug-formatted. Read more
Causes self to use its UpperHex implementation when +Debug-formatted. Read more
Formats each item in a sequence. Read more

Returns the argument unchanged.

+

Calls U::from(self).

+

That is, this conversion is whatever the implementation of +From<T> for U chooses to do.

+
Pipes by value. This is generally the method you want to use. Read more
Borrows self and passes that borrow into the pipe function. Read more
Mutably borrows self and passes that borrow into the pipe function. Read more
Borrows self, then passes self.borrow() into the pipe function. Read more
Mutably borrows self, then passes self.borrow_mut() into the pipe +function. Read more
Borrows self, then passes self.as_ref() into the pipe function.
Mutably borrows self, then passes self.as_mut() into the pipe +function. Read more
Borrows self, then passes self.deref() into the pipe function.
Mutably borrows self, then passes self.deref_mut() into the pipe +function. Read more
Immutable access to a value. Read more
Mutable access to a value. Read more
Immutable access to the Borrow<B> of a value. Read more
Mutable access to the BorrowMut<B> of a value. Read more
Immutable access to the AsRef<R> view of a value. Read more
Mutable access to the AsMut<R> view of a value. Read more
Immutable access to the Deref::Target of a value. Read more
Mutable access to the Deref::Target of a value. Read more
Calls .tap() only in debug builds, and is erased in release builds.
Calls .tap_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow() only in debug builds, and is erased in release +builds. Read more
Calls .tap_borrow_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_ref_mut() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref() only in debug builds, and is erased in release +builds. Read more
Calls .tap_deref_mut() only in debug builds, and is erased in release +builds. Read more
The resulting type after obtaining ownership.
Creates owned data from borrowed data, usually by cloning. Read more
Uses borrowed data to replace owned data, usually by cloning. Read more
Attempts to convert self into T using TryInto<T>. Read more
The type returned in the event of a conversion error.
Performs the conversion.
The type returned in the event of a conversion error.
Performs the conversion.
\ No newline at end of file diff --git a/docs/rust-logo.svg b/docs/rust-logo.svg new file mode 100644 index 0000000000..62424d8ffd --- /dev/null +++ b/docs/rust-logo.svg @@ -0,0 +1,61 @@ + + + diff --git a/docs/rustdoc.css b/docs/rustdoc.css new file mode 100644 index 0000000000..52c1c712e3 --- /dev/null +++ b/docs/rustdoc.css @@ -0,0 +1 @@ + @font-face {font-family:'Fira Sans';font-style:normal;font-weight:400;src:local('Fira Sans'),url("FiraSans-Regular.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Fira Sans';font-style:normal;font-weight:500;src:local('Fira Sans Medium'),url("FiraSans-Medium.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:400;src:local('Source Serif 4'),url("SourceSerif4-Regular.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:italic;font-weight:400;src:local('Source Serif 4 Italic'),url("SourceSerif4-It.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Serif 4';font-style:normal;font-weight:700;src:local('Source Serif 4 Bold'),url("SourceSerif4-Bold.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:400;src:url("SourceCodePro-Regular.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:italic;font-weight:400;src:url("SourceCodePro-It.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'Source Code Pro';font-style:normal;font-weight:600;src:url("SourceCodePro-Semibold.ttf.woff2") format("woff2");font-display:swap;}@font-face {font-family:'NanumBarunGothic';src:url("NanumBarunGothic.ttf.woff2") format("woff2");font-display:swap;unicode-range:U+AC00-D7AF,U+1100-11FF,U+3130-318F,U+A960-A97F,U+D7B0-D7FF;}*{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}html{content:"";}@media (prefers-color-scheme:light){html{content:"light";}}@media (prefers-color-scheme:dark){html{content:"dark";}}body{font:1rem/1.5 "Source Serif 4",NanumBarunGothic,serif;margin:0;position:relative;overflow-wrap:break-word;overflow-wrap:anywhere;-webkit-font-feature-settings:"kern","liga";-moz-font-feature-settings:"kern","liga";font-feature-settings:"kern","liga";background-color:var(--main-background-color);color:var(--main-color);}h1{font-size:1.5rem;}h2{font-size:1.375rem;}h3{font-size:1.25rem;}h1,h2,h3,h4,h5,h6{font-weight:500;}h1,h2,h3,h4{margin:25px 0 15px 0;padding-bottom:6px;}.docblock h3,.docblock h4,h5,h6{margin:15px 0 5px 0;}.docblock>h2:first-child,.docblock>h3:first-child,.docblock>h4:first-child,.docblock>h5:first-child,.docblock>h6:first-child{margin-top:0;}h1.fqn{margin:0;padding:0;flex-grow:1;overflow-wrap:break-word;overflow-wrap:anywhere;}.main-heading{display:flex;flex-wrap:wrap;justify-content:space-between;padding-bottom:6px;margin-bottom:15px;}#toggle-all-docs{text-decoration:none;}.content h2,.top-doc .docblock>h3,.top-doc .docblock>h4{border-bottom:1px solid var(--headings-border-bottom-color);}h3.code-header{font-size:1.125rem;}h4.code-header{font-size:1rem;}.code-header{font-weight:600;margin:0;padding:0;}#crate-search,h1,h2,h3,h4,h5,h6,.sidebar,.mobile-topbar,.search-input,.search-results .result-name,.item-left>a,.out-of-band,span.since,a.srclink,#help-button>a,details.rustdoc-toggle.top-doc>summary,details.rustdoc-toggle.non-exhaustive>summary,.scraped-example-title,.more-examples-toggle summary,.more-examples-toggle .hide-more,.example-links a,ul.all-items{font-family:"Fira Sans",Arial,NanumBarunGothic,sans-serif;}a#toggle-all-docs,a.anchor,.small-section-header a,#source-sidebar a,pre.rust a,.sidebar h2 a,.sidebar h3 a,.mobile-topbar h2 a,h1 a,.search-results a,.module-item .stab,.import-item .stab,.result-name .primitive>i,.result-name .keyword>i,.method .where,.fn .where,.where.fmt-newline{color:var(--main-color);}.content span.enum,.content a.enum,.content span.struct,.content a.struct,.content span.union,.content a.union,.content span.primitive,.content a.primitive,.content span.type,.content a.type,.content span.foreigntype,.content a.foreigntype{color:var(--type-link-color);}.content span.trait,.content a.trait,.content span.traitalias,.content a.traitalias{color:var(--trait-link-color);}.content span.associatedtype,.content a.associatedtype,.content span.constant,.content a.constant,.content span.static,.content a.static{color:var(--assoc-item-link-color);}.content span.fn,.content a.fn,.content .fnname,.content span.method,.content a.method,.content span.tymethod,.content a.tymethod{color:var(--function-link-color);}.content span.attr,.content a.attr,.content span.derive,.content a.derive,.content span.macro,.content a.macro{color:var(--macro-link-color);}.content span.mod,.content a.mod{color:var(--mod-link-color);}.content span.keyword,.content a.keyword{color:var(--keyword-link-color);}a{color:var(--link-color);}ol,ul{padding-left:24px;}ul ul,ol ul,ul ol,ol ol{margin-bottom:.625em;}p{margin:0 0 .75em 0;}p:last-child{margin:0;}summary{outline:none;}button{padding:1px 6px;}.rustdoc{display:flex;flex-direction:row;flex-wrap:nowrap;}main{position:relative;flex-grow:1;padding:10px 15px 40px 45px;min-width:0;}.source main{padding:15px;}.width-limiter{max-width:960px;margin-right:auto;}.source .width-limiter{max-width:unset;}details:not(.rustdoc-toggle) summary{margin-bottom:.6em;}code,pre,a.test-arrow,.code-header{font-family:"Source Code Pro",monospace;}.docblock code,.docblock-short code{border-radius:3px;padding:0 0.125em;}.docblock pre code,.docblock-short pre code{padding:0;}pre{padding:14px;}.item-decl pre{overflow-x:auto;}.source .content pre{padding:20px;}img{max-width:100%;}.source .content{overflow:visible;}.sub-logo-container{line-height:0;}.sub-logo-container>img{height:60px;width:60px;object-fit:contain;}.sidebar,.mobile-topbar,.sidebar-menu-toggle{background-color:var(--sidebar-background-color);}.sidebar{font-size:0.875rem;width:200px;min-width:200px;overflow-y:scroll;position:sticky;height:100vh;top:0;left:0;}.rustdoc.source .sidebar{width:50px;min-width:0px;max-width:300px;flex-grow:0;flex-shrink:0;flex-basis:auto;border-right:1px solid;overflow-x:hidden;overflow-y:hidden;}.source .sidebar,#sidebar-toggle,#source-sidebar{background-color:var(--sidebar-background-color);}#sidebar-toggle>button:hover,#sidebar-toggle>button:focus{background-color:var(--sidebar-background-color-hover);}.source .sidebar>*:not(#sidebar-toggle){visibility:hidden;}.source-sidebar-expanded .source .sidebar{overflow-y:auto;width:300px;}.source-sidebar-expanded .source .sidebar>*:not(#sidebar-toggle){visibility:visible;}#all-types{margin-top:1em;}*{scrollbar-width:initial;scrollbar-color:var(--scrollbar-color);}.sidebar{scrollbar-width:thin;scrollbar-color:var(--scrollbar-color);}::-webkit-scrollbar{width:12px;}.sidebar::-webkit-scrollbar{width:8px;}::-webkit-scrollbar-track{-webkit-box-shadow:inset 0;background-color:var(--scrollbar-track-background-color);}.sidebar::-webkit-scrollbar-track{background-color:var(--scrollbar-track-background-color);}::-webkit-scrollbar-thumb,.sidebar::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb-background-color);}.hidden{display:none !important;}.sidebar .logo-container{display:flex;margin-top:10px;margin-bottom:10px;justify-content:center;}.version{overflow-wrap:break-word;}.logo-container>img{height:100px;width:100px;}ul.block,.block li{padding:0;margin:0;list-style:none;}.block a,.sidebar h2 a,.sidebar h3 a{display:block;padding:0.25rem;margin-left:-0.25rem;text-overflow:ellipsis;overflow:hidden;}.sidebar h2{overflow-wrap:anywhere;padding:0;margin:0;margin-top:0.7rem;margin-bottom:0.7rem;}.sidebar h3{font-size:1.125rem;padding:0;margin:0;}.sidebar-elems,.sidebar>h2{padding-left:24px;}.sidebar a,.sidebar .current{color:var(--sidebar-link-color);}.sidebar .current,.sidebar a:hover{background-color:var(--sidebar-current-link-background-color);}.sidebar-elems .block{margin-bottom:2em;}.sidebar-elems .block li a{white-space:nowrap;}.mobile-topbar{display:none;}.source .content pre.rust{overflow:auto;padding-left:0;}.rustdoc .example-wrap{display:flex;position:relative;margin-bottom:10px;}.rustdoc .example-wrap:last-child{margin-bottom:0px;}.rustdoc .example-wrap>pre{margin:0;flex-grow:1;overflow-x:auto;}.rustdoc .example-wrap>pre.example-line-numbers,.rustdoc .example-wrap>pre.src-line-numbers{flex-grow:0;overflow:initial;text-align:right;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;}.example-line-numbers{border:1px solid;padding:13px 8px;border-top-left-radius:5px;border-bottom-left-radius:5px;}.src-line-numbers span{cursor:pointer;}.search-loading{text-align:center;}.docblock-short{overflow-wrap:break-word;overflow-wrap:anywhere;overflow:hidden;text-overflow:ellipsis;}.docblock>:not(pre)>code,.docblock-short>code{white-space:pre-wrap;}.top-doc .docblock h2{font-size:1.375rem;}.top-doc .docblock h3{font-size:1.25rem;}.top-doc .docblock h4,.top-doc .docblock h5{font-size:1.125rem;}.top-doc .docblock h6{font-size:1rem;}.docblock h5{font-size:1rem;}.docblock h6{font-size:0.875rem;}.docblock{margin-left:24px;position:relative;}.docblock>:not(.more-examples-toggle):not(.example-wrap){max-width:100%;overflow-x:auto;}.out-of-band{flex-grow:0;font-size:1.125rem;}.docblock code,.docblock-short code,pre,.rustdoc.source .example-wrap{background-color:var(--code-block-background-color);}#main-content{position:relative;}.docblock table{margin:.5em 0;width:calc(100% - 2px);overflow-x:auto;display:block;border-collapse:collapse;}.docblock table td{padding:.5em;border:1px dashed var(--border-color);vertical-align:top;}.docblock table th{padding:.5em;text-align:left;border:1px solid var(--border-color);}.method .where,.fn .where,.where.fmt-newline{display:block;font-size:0.875rem;}.item-info{display:block;margin-left:24px;}.item-info code{font-size:0.875rem;}#main-content>.item-info{margin-top:0;margin-left:0;}nav.sub{flex-grow:1;flex-flow:row nowrap;margin:4px 0 25px 0;display:flex;align-items:center;}nav.sub form{flex-grow:1;}.source nav.sub{margin:0 0 15px 0;}.source nav.sub form{margin-left:32px;}a{text-decoration:none;}.small-section-header{display:flex;justify-content:space-between;position:relative;}.small-section-header:hover>.anchor{display:initial;}.impl:hover>.anchor,.trait-impl:hover>.anchor{display:inline-block;position:absolute;}.anchor{display:none;position:absolute;left:-0.5em;background:none !important;}.anchor.field{left:-5px;}.small-section-header>.anchor{left:-15px;padding-right:8px;}h2.small-section-header>.anchor{padding-right:6px;}.anchor::before{content:'§';}.main-heading a:hover,.example-wrap>pre.rust a:hover,.all-items a:hover,.docblock a:not(.test-arrow):not(.scrape-help):hover,.docblock-short a:not(.test-arrow):not(.scrape-help):hover,.item-info a{text-decoration:underline;}.crate.block a.current{font-weight:500;}table,.item-table{overflow-wrap:break-word;}.item-table{display:table;}.item-row{display:table-row;}.item-left,.item-right{display:table-cell;}.item-left{padding-right:1.25rem;}.search-container{position:relative;display:flex;height:34px;}.search-results-title{margin-top:0;white-space:nowrap;display:inline-flex;max-width:100%;align-items:baseline;}#crate-search-div{display:inline-block;position:relative;min-width:5em;}#crate-search{min-width:115px;padding:0;padding-left:4px;padding-right:23px;max-width:100%;text-overflow:ellipsis;border:1px solid var(--border-color);border-radius:4px;outline:none;cursor:pointer;-moz-appearance:none;-webkit-appearance:none;text-indent:0.01px;background-color:var(--main-background-color);color:inherit;line-height:1.5;font-weight:500;}@-moz-document url-prefix(){#crate-search{padding-left:0px;padding-right:19px;}}#crate-search-div::after{pointer-events:none;width:100%;height:100%;position:absolute;top:0;left:0;content:"";background-repeat:no-repeat;background-size:20px;background-position:calc(100% - 2px) 56%;background-image:url("down-arrow.svg");}#crate-search>option{font-size:1rem;}.search-input{-webkit-appearance:none;-moz-box-sizing:border-box !important;box-sizing:border-box !important;outline:none;border:1px solid var(--border-color);border-radius:2px;padding:8px;font-size:1rem;width:100%;background-color:var(--button-background-color);color:var(--search-color);}.search-input:focus{border-color:var(--search-input-focused-border-color);}.search-results{display:none;padding-bottom:2em;}.search-results.active{display:block;clear:both;}.search-results .desc>span{white-space:nowrap;text-overflow:ellipsis;overflow:hidden;display:block;}.search-results>a{display:block;margin-left:2px;margin-right:2px;border-bottom:1px solid #aaa3;}.search-results>a>div{display:flex;flex-flow:row wrap;}.search-results .result-name,.search-results div.desc{width:50%;}.search-results .result-name{padding-right:1em;}.search-results a:hover,.search-results a:focus{background-color:var(--search-result-link-focus-background-color);}.popover{font-size:1rem;position:absolute;right:0;z-index:2;display:block;margin-top:7px;border-radius:3px;border:1px solid var(--border-color);font-size:1rem;}.popover::before{content:'';position:absolute;right:11px;border:solid var(--border-color);border-width:1px 1px 0 0;display:inline-block;padding:4px;transform:rotate(-45deg);top:-5px;}.popover,.popover::before{background-color:var(--main-background-color);color:var(--main-color);}#help.popover{max-width:600px;}#help.popover::before{right:48px;}#help dt{float:left;clear:left;display:block;margin-right:0.5rem;}#help span.top,#help span.bottom{text-align:center;display:block;font-size:1.125rem;}#help span.top{margin:10px 0;border-bottom:1px solid var(--border-color);padding-bottom:4px;margin-bottom:6px;}#help span.bottom{clear:both;border-top:1px solid var(--border-color);}.side-by-side>div{width:50%;float:left;padding:0 20px 20px 17px;}.item-info .stab{width:fit-content;min-height:36px;display:flex;align-items:center;white-space:pre-wrap;}.stab{padding:3px;margin-bottom:5px;font-size:0.875rem;font-weight:normal;color:var(--main-color);background-color:var(--stab-background-color);}.stab.portability>code{background:none;color:var(--stab-code-color);}.stab .emoji{font-size:1.25rem;margin-right:0.3rem;}.docblock .stab{padding:0 0.125em;margin-bottom:0;}.emoji{text-shadow:1px 0 0 black,-1px 0 0 black,0 1px 0 black,0 -1px 0 black;}.module-item .stab,.import-item .stab{border-radius:3px;display:inline-block;font-size:0.875rem;line-height:1.2;margin-bottom:0;margin-left:0.3125em;padding:2px;vertical-align:text-bottom;}.module-item.unstable,.import-item.unstable{opacity:0.65;}.since{font-weight:normal;font-size:initial;}.rightside{padding-left:12px;padding-right:2px;float:right;}.rightside:not(a),.out-of-band{color:var(--right-side-color);}pre.rust{tab-size:4;-moz-tab-size:4;}pre.rust .kw{color:var(--code-highlight-kw-color);}pre.rust .kw-2{color:var(--code-highlight-kw-2-color);}pre.rust .lifetime{color:var(--code-highlight-lifetime-color);}pre.rust .prelude-ty{color:var(--code-highlight-prelude-color);}pre.rust .prelude-val{color:var(--code-highlight-prelude-val-color);}pre.rust .string{color:var(--code-highlight-string-color);}pre.rust .number{color:var(--code-highlight-number-color);}pre.rust .bool-val{color:var(--code-highlight-literal-color);}pre.rust .self{color:var(--code-highlight-self-color);}pre.rust .attribute{color:var(--code-highlight-attribute-color);}pre.rust .macro,pre.rust .macro-nonterminal{color:var(--code-highlight-macro-color);}pre.rust .question-mark{font-weight:bold;color:var(--code-highlight-question-mark-color);}pre.rust .comment{color:var(--code-highlight-comment-color);}pre.rust .doccomment{color:var(--code-highlight-doc-comment-color);}.example-wrap.compile_fail,.example-wrap.should_panic{border-left:2px solid var(--codeblock-error-color);}.ignore.example-wrap{border-left:2px solid var(--codeblock-ignore-color);}.example-wrap.compile_fail:hover,.example-wrap.should_panic:hover{border-left:2px solid var(--codeblock-error-hover-color);}.example-wrap.ignore:hover{border-left:2px solid var(--codeblock-ignore-hover-color);}.example-wrap.compile_fail .tooltip,.example-wrap.should_panic .tooltip{color:var(--codeblock-error-color);}.example-wrap.ignore .tooltip{color:var(--codeblock-ignore-color);}.example-wrap.compile_fail:hover .tooltip,.example-wrap.should_panic:hover .tooltip{color:var(--codeblock-error-hover-color);}.example-wrap.ignore:hover .tooltip{color:var(--codeblock-ignore-hover-color);}.example-wrap .tooltip{position:absolute;display:block;cursor:pointer;left:-25px;top:5px;}.example-wrap .tooltip::after{display:none;text-align:center;padding:5px 3px 3px 3px;border-radius:6px;margin-left:5px;font-size:1rem;border:1px solid var(--border-color);position:absolute;width:max-content;top:-2px;z-index:1;}.example-wrap .tooltip::before{content:" ";position:absolute;top:50%;left:16px;margin-top:-5px;border-width:5px;border-style:solid;display:none;z-index:1;}.example-wrap.ignore .tooltip::after{content:"This example is not tested";}.example-wrap.compile_fail .tooltip::after{content:"This example deliberately fails to compile";}.example-wrap.should_panic .tooltip::after{content:"This example panics";}.example-wrap.edition .tooltip::after{content:"This code runs with edition " attr(data-edition);}.example-wrap .tooltip:hover::before,.example-wrap .tooltip:hover::after{display:inline;}.example-wrap.compile_fail .tooltip,.example-wrap.should_panic .tooltip,.example-wrap.ignore .tooltip{font-weight:bold;font-size:1.25rem;}a.test-arrow{display:inline-block;visibility:hidden;position:absolute;padding:5px 10px 5px 10px;border-radius:5px;font-size:1.375rem;top:5px;right:5px;z-index:1;}.example-wrap:hover .test-arrow{visibility:visible;}.code-attribute{font-weight:300;color:var(--code-attribute-color);}.item-spacer{width:100%;height:12px;}.out-of-band>span.since{font-size:1.25rem;}h3.variant{font-weight:600;font-size:1.125rem;margin-bottom:10px;}.sub-variant h4{font-size:1rem;font-weight:400;margin-top:0;margin-bottom:0;}.sub-variant{margin-left:24px;margin-bottom:40px;}.sub-variant>.sub-variant-field{margin-left:24px;}:target>code,:target>.code-header{opacity:1;}:target{padding-right:3px;}.notable-traits-tooltip{display:inline-block;cursor:pointer;}.notable-traits:hover .notable-traits-tooltiptext,.notable-traits .notable-traits-tooltiptext.force-tooltip{display:inline-block;}.notable-traits .notable-traits-tooltiptext{display:none;padding:5px 3px 3px 3px;border-radius:6px;margin-left:5px;z-index:10;font-size:1rem;cursor:default;position:absolute;border:1px solid;}.notable-traits-tooltip::after{content:"\00a0\00a0\00a0";}.notable-traits .docblock{margin:0;}.notable-traits .notable{margin:0;margin-bottom:13px;font-size:1.1875rem;font-weight:600;display:block;}.notable-traits .docblock code.content{margin:0;padding:0;font-size:1.25rem;}.search-failed{text-align:center;margin-top:20px;display:none;}.search-failed.active{display:block;}.search-failed>ul{text-align:left;max-width:570px;margin-left:auto;margin-right:auto;}#titles{display:flex;flex-direction:row;gap:1px;margin-bottom:4px;}#titles>button{text-align:center;font-size:1.125rem;cursor:pointer;border:0;border-top:2px solid;flex:1;line-height:1.5;color:inherit;}#titles>button>div.count{display:inline-block;font-size:1rem;}.notable-traits{cursor:pointer;z-index:2;margin-left:5px;}#sidebar-toggle{position:sticky;top:0;left:0;font-size:1.25rem;border-bottom:1px solid;display:flex;height:40px;justify-content:center;align-items:center;z-index:10;}#source-sidebar{width:100%;overflow:auto;}#source-sidebar>.title{font-size:1.5rem;text-align:center;border-bottom:1px solid var(--border-color);margin-bottom:6px;}#sidebar-toggle>button{font-size:inherit;font-weight:bold;background:none;color:inherit;cursor:pointer;text-align:center;border:none;outline:none;position:absolute;top:0;bottom:0;left:0;right:0;width:100%;-webkit-appearance:none;opacity:1;}#settings-menu,#help-button{margin-left:4px;outline:none;}#settings-menu>a,#help-button>a,#copy-path{width:33px;cursor:pointer;line-height:1.5;}#settings-menu>a,#help-button>a{padding:5px;height:100%;display:block;background-color:var(--button-background-color);border:1px solid var(--border-color);border-radius:2px;}#copy-path{color:var(--copy-path-button-color);background:var(--main-background-color);height:34px;margin-left:10px;padding:0;padding-left:2px;border:0;}#copy-path>img{filter:var(--copy-path-img-filter);}#copy-path:hover>img{filter:var(--copy-path-img-hover-filter);}@keyframes rotating{from{transform:rotate(0deg);}to{transform:rotate(360deg);}}#settings-menu.rotate>a img{animation:rotating 2s linear infinite;}#help-button>a{text-align:center;font-size:20px;padding-top:2px;}kbd{display:inline-block;padding:3px 5px;font:15px monospace;line-height:10px;vertical-align:middle;border:solid 1px var(--border-color);border-radius:3px;cursor:default;}ul.all-items>li{list-style:none;}details.dir-entry{padding-left:4px;}details.dir-entry>summary::after{content:" ►";position:absolute;left:-15px;top:0px;font-size:80%;padding:2px 0px;width:25px;}details[open].dir-entry>summary::after{content:" ▼";}details.dir-entry>summary::-webkit-details-marker,details.dir-entry>summary::marker{display:none;}details.dir-entry>summary{margin:0 0 0 13px;list-style:none;cursor:pointer;position:relative;}details.dir-entry div.folders,details.dir-entry div.files{padding-left:23px;}details.dir-entry a{display:block;}details.rustdoc-toggle{contain:layout;position:relative;}details.rustdoc-toggle>summary.hideme{cursor:pointer;}details.rustdoc-toggle>summary{list-style:none;}details.rustdoc-toggle>summary::-webkit-details-marker,details.rustdoc-toggle>summary::marker{display:none;}details.rustdoc-toggle>summary.hideme>span{margin-left:9px;}details.rustdoc-toggle>summary::before{content:"";cursor:pointer;width:16px;height:16px;background-repeat:no-repeat;background-position:top left;display:inline-block;vertical-align:middle;opacity:.5;}details.rustdoc-toggle>summary.hideme>span,.more-examples-toggle summary,.more-examples-toggle .hide-more{color:var(--toggles-color);}details.rustdoc-toggle>summary::after{content:"Expand";overflow:hidden;width:0;height:0;position:absolute;}details.rustdoc-toggle>summary.hideme::after{content:"";}details.rustdoc-toggle>summary:focus::before,details.rustdoc-toggle>summary:hover::before{opacity:1;}details.rustdoc-toggle>summary:focus-visible::before{outline:1px dotted #000;outline-offset:1px;}details.rustdoc-toggle.top-doc>summary,details.rustdoc-toggle.top-doc>summary::before,details.rustdoc-toggle.non-exhaustive>summary,details.rustdoc-toggle.non-exhaustive>summary::before{font-size:1rem;}details.non-exhaustive{margin-bottom:8px;}details.rustdoc-toggle>summary.hideme::before{position:relative;}details.rustdoc-toggle>summary:not(.hideme)::before{position:absolute;left:-24px;top:4px;}.impl-items>details.rustdoc-toggle>summary:not(.hideme)::before{position:absolute;left:-24px;}details.rustdoc-toggle[open] >summary.hideme{position:absolute;}details.rustdoc-toggle[open] >summary.hideme>span{display:none;}details.rustdoc-toggle[open] >summary::before,details.rustdoc-toggle[open] >summary.hideme::before{background-image:url("toggle-minus.svg");}details.rustdoc-toggle>summary::before{background-image:url("toggle-plus.svg");}details.rustdoc-toggle[open] >summary::before,details.rustdoc-toggle[open] >summary.hideme::before{width:16px;height:16px;background-repeat:no-repeat;background-position:top left;display:inline-block;content:"";}details.rustdoc-toggle[open] >summary::after,details.rustdoc-toggle[open] >summary.hideme::after{content:"Collapse";}.docblock summary>*{display:inline-block;}.docblock>.example-wrap:first-child .tooltip{margin-top:16px;}@media (max-width:700px){*[id]{scroll-margin-top:45px;}.rustdoc{padding-top:0px;display:block;}main{padding-left:15px;padding-top:0px;}.main-heading{flex-direction:column;}.out-of-band{text-align:left;margin-left:initial;padding:initial;}.out-of-band .since::before{content:"Since ";}#copy-path{display:none;}.sidebar .sidebar-logo,.sidebar .location{display:none;}.sidebar{position:fixed;top:45px;left:-1000px;margin-left:0;margin:0;padding:0;z-index:11;height:calc(100vh - 45px);}.source main,.rustdoc.source .sidebar{top:0;padding:0;height:100vh;border:0;}.sidebar.shown,.source-sidebar-expanded .source .sidebar,.sidebar:focus-within{left:0;}.rustdoc.source>.sidebar{width:0;}.mobile-topbar h2{padding-bottom:0;margin:auto 0.5em auto auto;overflow:hidden;font-size:24px;}.mobile-topbar h2 a{display:block;text-overflow:ellipsis;overflow:hidden;white-space:nowrap;}.mobile-topbar .logo-container{max-height:45px;}.mobile-topbar .logo-container>img{max-width:35px;max-height:35px;margin-left:20px;margin-top:5px;margin-bottom:5px;}.mobile-topbar{display:flex;flex-direction:row;position:sticky;z-index:10;font-size:2rem;height:45px;width:100%;left:0;top:0;}.sidebar-menu-toggle{width:45px;font-size:32px;border:none;color:var(--main-color);}.sidebar-elems{margin-top:1em;background-color:var(--sidebar-background-color);}.content{margin-left:0px;}.anchor{display:none !important;}#titles>button>div.count{display:block;}#sidebar-filler{position:fixed;left:45px;width:calc(100% - 45px);top:0;height:45px;z-index:-1;border-bottom:1px solid;}#main-content>details.rustdoc-toggle>summary::before,#main-content>div>details.rustdoc-toggle>summary::before{left:-11px;}#sidebar-toggle{position:fixed;left:1px;top:100px;width:30px;font-size:1.5rem;text-align:center;padding:0;z-index:10;border-top-right-radius:3px;border-bottom-right-radius:3px;cursor:pointer;border:1px solid;border-left:0;}.source-sidebar-expanded #sidebar-toggle{left:unset;top:unset;width:unset;border-top-right-radius:unset;border-bottom-right-radius:unset;position:sticky;border:0;border-bottom:1px solid;}.notable-traits .notable-traits-tooltiptext{left:0;top:100%;}#help-button{display:none;}.item-table{display:block;}.item-row{display:flex;flex-flow:column wrap;}.item-left,.item-right{width:100%;}.search-results>a{border-bottom:1px solid #aaa9;padding:5px 0px;}.search-results .result-name,.search-results div.desc{width:100%;}.search-results div.desc,.item-right{padding-left:2em;}.source-sidebar-expanded .source .sidebar{max-width:100vw;width:100vw;}details.rustdoc-toggle:not(.top-doc)>summary{margin-left:10px;}.impl-items>details.rustdoc-toggle>summary:not(.hideme)::before,#main-content>details.rustdoc-toggle:not(.top-doc)>summary::before,#main-content>div>details.rustdoc-toggle>summary::before{left:-11px;}.impl-items>.item-info{margin-left:34px;}.source nav.sub{margin:0;padding:8px;}}@media print{nav.sidebar,nav.sub,.out-of-band,a.srclink,#copy-path,details.rustdoc-toggle[open] >summary::before,details.rustdoc-toggle>summary::before,details.rustdoc-toggle.top-doc>summary{display:none;}.docblock{margin-left:0;}main{padding:10px;}}@media (max-width:464px){.docblock{margin-left:12px;}.docblock code{overflow-wrap:break-word;overflow-wrap:anywhere;}nav.sub{flex-direction:column;}nav.sub form{align-self:stretch;}.sub-logo-container>img{height:35px;width:35px;}#sidebar-toggle{top:10px;}.source-sidebar-expanded #sidebar-toggle{top:unset;}}.method-toggle>summary,.implementors-toggle>summary,.impl,#implementors-list>.docblock,.impl-items>section,.methods>section{margin-bottom:0.75em;}.method-toggle[open]:not(:last-child),.implementors-toggle[open]:not(:last-child){margin-bottom:2em;}#trait-implementations-list .method-toggle:not(:last-child),#synthetic-implementations-list .method-toggle:not(:last-child),#blanket-implementations-list .method-toggle:not(:last-child){margin-bottom:1em;}.scraped-example-list .scrape-help{margin-left:10px;padding:0 4px;font-weight:normal;font-size:12px;position:relative;bottom:1px;background:transparent;border-width:1px;border-style:solid;border-radius:50px;}.scraped-example .code-wrapper{position:relative;display:flex;flex-direction:row;flex-wrap:wrap;width:100%;}.scraped-example:not(.expanded) .code-wrapper{max-height:240px;}.scraped-example:not(.expanded) .code-wrapper pre{overflow-y:hidden;max-height:240px;padding-bottom:0;}.scraped-example .code-wrapper .prev{position:absolute;top:0.25em;right:2.25em;z-index:100;cursor:pointer;}.scraped-example .code-wrapper .next{position:absolute;top:0.25em;right:1.25em;z-index:100;cursor:pointer;}.scraped-example .code-wrapper .expand{position:absolute;top:0.25em;right:0.25em;z-index:100;cursor:pointer;}.scraped-example:not(.expanded) .code-wrapper:before{content:" ";width:100%;height:5px;position:absolute;z-index:100;top:0;}.scraped-example:not(.expanded) .code-wrapper:after{content:" ";width:100%;height:5px;position:absolute;z-index:100;bottom:0;}.scraped-example .code-wrapper .src-line-numbers{margin:0;padding:14px 0;}.scraped-example .code-wrapper .src-line-numbers span{padding:0 14px;}.scraped-example .code-wrapper .example-wrap{flex:1;overflow-x:auto;overflow-y:hidden;margin-bottom:0;}.scraped-example:not(.expanded) .code-wrapper .example-wrap{overflow-x:hidden;}.scraped-example .code-wrapper .example-wrap pre.rust{overflow-x:inherit;width:inherit;overflow-y:hidden;}.more-examples-toggle{max-width:calc(100% + 25px);margin-top:10px;margin-left:-25px;}.more-examples-toggle .hide-more{margin-left:25px;margin-bottom:5px;cursor:pointer;}.more-scraped-examples{margin-left:5px;display:flex;flex-direction:row;}.more-scraped-examples-inner{width:calc(100% - 20px);}.toggle-line{align-self:stretch;margin-right:10px;margin-top:5px;padding:0 4px;cursor:pointer;}.toggle-line-inner{min-width:2px;height:100%;}.more-scraped-examples .scraped-example{margin-bottom:20px;}.more-scraped-examples .scraped-example:last-child{margin-bottom:0;}.example-links a{margin-top:20px;}.example-links ul{margin-bottom:0;} \ No newline at end of file diff --git a/docs/search-index.js b/docs/search-index.js new file mode 100644 index 0000000000..a70909df3e --- /dev/null +++ b/docs/search-index.js @@ -0,0 +1,8 @@ +var searchIndex = JSON.parse('{\ +"halo2":{"doc":"halo2","t":[],"n":[],"q":[],"d":[],"i":[],"f":[],"p":[]},\ +"halo2_proofs":{"doc":"halo2_proofs","t":[13,13,13,4,0,11,11,0,11,11,11,11,0,11,11,11,2,11,11,0,0,11,0,11,11,11,11,16,16,16,18,8,8,16,18,8,8,8,18,18,16,16,16,18,18,10,10,10,10,5,5,5,10,11,10,10,5,10,10,10,5,10,10,10,10,10,10,10,10,10,11,11,10,5,5,10,10,5,11,11,10,5,5,10,10,10,3,3,8,16,8,16,3,3,3,3,16,3,3,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,13,4,8,3,13,8,10,10,10,10,10,11,11,11,11,11,11,11,11,11,10,10,11,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,12,12,13,3,13,13,4,13,13,3,13,13,4,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,3,3,3,3,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,3,13,13,3,4,4,8,3,13,3,13,8,3,13,8,16,13,3,3,13,3,4,4,3,3,13,13,3,8,16,3,3,13,13,3,13,13,13,13,13,13,8,3,3,13,3,13,13,3,3,13,13,13,3,3,13,13,3,3,3,13,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,10,11,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,10,11,11,11,11,11,11,11,11,11,11,11,11,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,10,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,8,3,4,3,3,8,3,16,13,16,3,3,3,3,13,8,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,0,11,11,11,11,11,10,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,3,8,16,16,8,16,16,8,8,16,8,16,16,8,18,18,16,8,11,11,11,10,10,10,11,11,10,11,11,10,10,10,11,11,11,10,11,10,11,10,11,11,10,11,11,10,11,11,11,10,10,10,10,11,10,10,10,10,10,11,11,11,11,10,10,11,10,0,0,0,0,3,3,6,11,11,11,11,11,11,11,11,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,11,11,11,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,3,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,3,3,3,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,11,11,11,11,11,11,0,0,0,0,3,3,6,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,3,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,3,3,3,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,3,3,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,3,3,3,3,8,16,8,8,8,8,8,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,11,11,11,11,11,11,11,11,10,11,10,10,11,11,11,11,11,11,11,11,11,11,10,11,10,11,10,11,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,10,11,10,11],"n":["Processed","RawBytes","RawBytesUnchecked","SerdeFormat","arithmetic","borrow","borrow_mut","circuit","clone","clone_into","deref","deref_mut","dev","drop","fmt","from","halo2curves","init","into","plonk","poly","to_owned","transcript","try_from","try_into","type_id","vzip","AffineExt","Base","Base","CURVE_ID","CurveAffine","CurveExt","CurveExt","DELTA","Field","FieldExt","Group","MODULUS","ROOT_OF_UNITY_INV","Scalar","ScalarExt","ScalarExt","TWO_INV","ZETA","a","a","b","b","best_fft","best_multiexp","compute_inner_product","coordinates","cube","double","endo","eval_polynomial","from_bytes_wide","from_u128","from_xy","g_to_lagrange","get_lower_128","group_add","group_scale","group_sub","group_zero","hash_to_curve","invert","is_on_curve","is_on_curve","is_zero","is_zero_vartime","jacobian_coordinates","kate_division","lagrange_interpolate","new_jacobian","one","parallelize","pow","pow_vartime","random","recursive_butterfly_arithmetic","small_multiexp","sqrt","square","zero","AssignedCell","Cell","Chip","Config","Layouter","Loaded","NamespacedLayouter","Region","RegionIndex","RegionStart","Root","SimpleFloorPlanner","Table","Value","add","add","add","add","add","add","add","add","add","add","and_then","as_mut","as_ref","assert_if_known","assign_advice","assign_advice_from_constant","assign_advice_from_instance","assign_cell","assign_fixed","assign_region","assign_region","assign_table","assign_table","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","cell","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","cloned","cloned","column","column","config","constrain_constant","constrain_equal","constrain_instance","constrain_instance","copied","copied","copy_advice","cube","default","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","double","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","eq","error_if_known_and","evaluate","evaluate","floor_planner","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from_iter","get_challenge","get_challenge","get_challenge","get_root","get_root","init","init","init","init","init","init","init","init","init","into","into","into","into","into","into","into","into","into","into_field","invert","known","layouter","loaded","map","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","namespace","neg","next_phase","pop_namespace","pop_namespace","push_namespace","push_namespace","row_offset","row_offset","square","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","synthesize","to_field","to_owned","to_owned","to_owned","to_owned","to_owned","transpose_array","transpose_vec","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","unknown","unzip","value","value_field","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","zip","Column","RegionColumn","RegionLayouter","RegionShape","Selector","TableLayouter","assign_advice","assign_advice_from_constant","assign_advice_from_instance","assign_cell","assign_fixed","borrow","borrow","borrow_mut","borrow_mut","clone","clone","clone_into","clone_into","cmp","constrain_constant","constrain_equal","deref","deref","deref_mut","deref_mut","drop","drop","enable_selector","eq","fmt","fmt","from","from","from","from","get_challenge","hash","init","init","into","into","next_phase","partial_cmp","to_owned","to_owned","try_from","try_from","try_into","try_into","type_id","type_id","vzip","vzip","0","0","CellNotAssigned","CircuitGates","ConstraintNotSatisfied","ConstraintPoisoned","FailureLocation","InRegion","Lookup","MockProver","OutsideRegion","Permutation","VerifyFailure","assert_satisfied","assert_satisfied_par","assign_advice","assign_fixed","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","collect","copy","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","drop","drop","drop","drop","enable_selector","enter_region","eq","eq","exit_region","fill_from_row","fmt","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","get_challenge","init","init","init","init","into","into","into","into","metadata","pop_namespace","push_namespace","queries_to_csv","query_instance","run","to_string","to_string","to_string","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","verify","verify_at_rows","verify_at_rows_par","verify_par","vzip","vzip","vzip","vzip","offset","region","row","cell_values","column","column","constraint","constraint","gate","gate_offset","location","location","location","lookup_index","name","offset","region","Column","Constraint","Gate","Region","VirtualCell","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone_into","clone_into","cmp","cmp","deref","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","drop","drop","drop","drop","drop","eq","eq","eq","eq","eq","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","from","from","from","from","from","init","init","init","init","init","into","into","into","into","into","partial_cmp","partial_cmp","to_owned","to_owned","to_string","to_string","to_string","to_string","to_string","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","vzip","Advice","Advice","Advice","AdviceQuery","Any","Assigned","Assignment","BatchVerifier","BoundsFailure","Challenge","Challenge","Circuit","Column","ColumnNotInPermutation","ColumnType","Config","Constant","Constraint","ConstraintSystem","ConstraintSystemFailure","Constraints","Error","Expression","FirstPhase","Fixed","Fixed","Fixed","FixedQuery","FloorPlanner","FloorPlanner","Gate","Instance","Instance","Instance","InstanceQuery","InstanceTooLarge","InvalidInstances","Negated","NotEnoughColumnsForConstants","NotEnoughRowsAvailable","Opening","Phase","PinnedConstraintSystem","PinnedVerificationKey","Product","ProvingKey","Rational","Scaled","SecondPhase","Selector","Selector","Sum","Synthesis","TableColumn","ThirdPhase","Transcript","Trivial","VerifyingKey","VirtualCell","VirtualCells","Zero","add","add","add","add","add","add","add","add_assign","add_assign","add_proof","advice","advice_column","advice_column_in","advice_column_phase","advice_in","advice_queries","assign_advice","assign_fixed","blinding_factors","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","challenge_phase","challenge_usable_after","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","cmp","cmp","column_index","column_index","column_index","column_type","complex_selector","complexity","configure","constants","copy","create_gate","create_proof","cs","cube","default","default","default","degree","degree","denominator","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","double","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","enable","enable_constant","enable_equality","enable_selector","enter_region","eq","eq","eq","eq","eq","eq","eq","eq","eq","evaluate","evaluate","evaluate_lazy","exit_region","fill_from_row","finalize","fixed_column","fixed_commitments","fixed_queries","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from_bytes","from_bytes","gates","get_challenge","get_domain","get_vk","hash","hash","hash","hash","hash","hash","hash","hash","hash_into","identifier","index","index","init","init","init","init","init","init","init","init","init","init","init","init","init","init","init","init","init","init","init","init","init","init","init","init","init","init","init","init","instance_column","instance_queries","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into_iter","invert","is_simple","is_zero_vartime","keygen_pk","keygen_vk","lookup","lookup_any","lookup_table_column","lookups","minimum_rows","mul","mul","mul","mul","mul","mul","mul_assign","mul_assign","neg","neg","neg","new","new","next_phase","next_phase","num_advice_columns","num_challenges","num_fixed_columns","num_instance_columns","numerator","partial_cmp","partial_cmp","permutation","permutation","phase","phase","phase","pinned","pinned","polynomials","pop_namespace","provide","push_namespace","query_advice","query_any","query_challenge","query_fixed","query_instance","query_instance","query_selector","read","read","rotation","rotation","rotation","selector","set_minimum_degree","source","square","square","sub","sub","sub","sub","sub","sub","sub","sub_assign","sub_assign","synthesize","synthesize","to_bytes","to_bytes","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_string","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","verify_proof","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","with_selector","without_witnesses","write","write","0","0","0","1","0","0","current_k","0","0","0","0","0","0","0","0","0","0","1","1","1","0","Basis","Coeff","Error","EvaluationDomain","ExtendedLagrangeCoeff","Guard","LagrangeCoeff","MSMAccumulator","OpeningError","Output","PinnedEvaluationDomain","Polynomial","ProverQuery","Rotation","SamplingError","VerificationStrategy","VerifierQuery","add","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","coeff_from_vec","coeff_to_extended","commitment","constant_extended","constant_lagrange","cur","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","deref_mut","divide_by_vanishing_poly","drop","drop","drop","drop","drop","drop","drop","drop","drop","drop","empty_coeff","empty_extended","empty_lagrange","eq","extended_k","extended_len","extended_to_coeff","finalize","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","from","get_extended_omega","get_omega","get_omega_inv","get_quotient_poly_degree","index","index","index","index_mut","index_mut","index_mut","init","init","init","init","init","init","init","init","init","init","into","into","into","into","into","into","into","into","into","into","ipa","iter","iter_mut","k","kzg","l_i_range","lagrange_assigned_from_vec","lagrange_from_vec","lagrange_to_coeff","mul","new","new","new_commitment","new_msm","next","num_coeffs","pinned","prev","process","rotate","rotate_extended","rotate_omega","sub","sub","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","0","Blind","CommitmentScheme","Curve","Guard","MSM","MSM","MSMAccumulator","Params","ParamsProver","ParamsProver","ParamsVerifier","ParamsVerifier","ParamsVerifier","Prover","QUERY_INSTANCE","QUERY_INSTANCE","Scalar","Verifier","add","add_assign","add_assign","add_msm","append_term","bases","borrow","borrow_mut","check","clone","clone_into","commit","commit_lagrange","create_proof","default","deref","deref_mut","downsize","drop","empty_msm","eq","eval","fmt","from","get_g","init","into","k","mul","mul_assign","mul_assign","n","new","new","new","new","new_params","read","read_params","scalars","scale","to_owned","try_from","try_into","type_id","verifier_params","verify_proof","vzip","write","commitment","msm","multiopen","strategy","IPACommitmentScheme","ParamsIPA","ParamsVerifierIPA","borrow","borrow","borrow_mut","borrow_mut","clone","clone_into","commit","commit_lagrange","create_proof","deref","deref","deref_mut","deref_mut","downsize","drop","drop","empty_msm","fmt","fmt","from","from","get_g","init","init","into","into","k","n","new","new_params","read","read_params","to_owned","try_from","try_from","try_into","try_into","type_id","type_id","verifier_params","verify_proof","vzip","vzip","write","MSMIPA","add_constant_term","add_msm","add_msm","add_to_g_scalars","add_to_u_scalar","add_to_w_scalar","append_term","bases","borrow","borrow_mut","check","clone","clone_into","deref","deref_mut","drop","eval","fmt","from","init","into","new","scalars","scale","to_owned","try_from","try_into","type_id","vzip","ProverIPA","VerifierIPA","borrow","borrow","borrow_mut","borrow_mut","create_proof","deref","deref","deref_mut","deref_mut","drop","drop","fmt","fmt","from","from","init","init","into","into","new","new","try_from","try_from","try_into","try_into","type_id","type_id","verify_proof","vzip","vzip","Accumulator","AccumulatorStrategy","GuardIPA","SingleStrategy","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone_into","clone_into","compute_g","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","drop","drop","drop","drop","finalize","finalize","fmt","fmt","fmt","fmt","from","from","from","from","g","init","init","init","init","into","into","into","into","new","new","process","process","to_owned","to_owned","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","u_packed","use_challenges","use_g","vzip","vzip","vzip","vzip","commitment","msm","multiopen","strategy","KZGCommitmentScheme","ParamsKZG","ParamsVerifierKZG","borrow","borrow","borrow_mut","borrow_mut","clone","clone_into","commit","commit_lagrange","deref","deref","deref_mut","deref_mut","downsize","drop","drop","empty_msm","fmt","fmt","from","from","g2","get_g","init","init","into","into","k","n","new","new_params","read","read_custom","read_params","s_g2","setup","to_owned","try_from","try_from","try_into","try_into","type_id","type_id","verifier_params","vzip","vzip","write","write_custom","DualMSM","MSMKZG","add_msm","add_msm","append_term","bases","borrow","borrow","borrow_mut","borrow_mut","check","check","clone","clone","clone_into","clone_into","combine_with_base","default","deref","deref","deref_mut","deref_mut","drop","drop","eval","fmt","fmt","from","from","from","init","init","into","into","new","new","scalars","scale","scale","to_owned","to_owned","try_from","try_from","try_into","try_into","type_id","type_id","vzip","vzip","ProverGWC","ProverSHPLONK","VerifierGWC","VerifierSHPLONK","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","create_proof","create_proof","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","drop","drop","drop","drop","fmt","fmt","fmt","fmt","from","from","from","from","init","init","init","init","into","into","into","into","new","new","new","new","new","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","verify_proof","verify_proof","vzip","vzip","vzip","vzip","AccumulatorStrategy","GuardKZG","SingleStrategy","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone_into","clone_into","clone_into","deref","deref","deref","deref_mut","deref_mut","deref_mut","drop","drop","drop","finalize","finalize","fmt","fmt","fmt","from","from","from","init","init","init","into","into","into","new","new","new","new","process","process","to_owned","to_owned","to_owned","try_from","try_from","try_from","try_into","try_into","try_into","type_id","type_id","type_id","vzip","vzip","vzip","with","Blake2bRead","Blake2bWrite","Challenge255","ChallengeScalar","EncodedChallenge","Input","Transcript","TranscriptRead","TranscriptReadBuffer","TranscriptWrite","TranscriptWriterBuffer","as_challenge_scalar","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","common_point","common_point","common_point","common_scalar","common_scalar","common_scalar","deref","deref","deref","deref","deref","deref","deref_mut","deref_mut","deref_mut","deref_mut","drop","drop","drop","drop","finalize","finalize","fmt","fmt","fmt","fmt","from","from","from","from","get_scalar","get_scalar","init","init","init","init","init","init","init","init","into","into","into","into","new","new","read_point","read_point","read_scalar","read_scalar","squeeze_challenge","squeeze_challenge","squeeze_challenge","squeeze_challenge_scalar","to_owned","to_owned","to_owned","to_owned","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","write_point","write_point","write_scalar","write_scalar"],"q":["halo2_proofs","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::arithmetic","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::circuit","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::circuit::layouter","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::circuit::layouter::RegionColumn","","halo2_proofs::dev","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::dev::FailureLocation","","","halo2_proofs::dev::VerifyFailure","","","","","","","","","","","","","","halo2_proofs::dev::metadata","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::plonk","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::plonk::Any","halo2_proofs::plonk::Assigned","","","halo2_proofs::plonk::Error","","","halo2_proofs::plonk::Expression","","","","","","","","","","","","","halo2_proofs::poly","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::poly::commitment","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::poly::ipa","","","","halo2_proofs::poly::ipa::commitment","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::poly::ipa::msm","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::poly::ipa::multiopen","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::poly::ipa::strategy","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::poly::kzg","","","","halo2_proofs::poly::kzg::commitment","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::poly::kzg::msm","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::poly::kzg::multiopen","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::poly::kzg::strategy","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2_proofs::transcript","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],"d":["Curve elements are serialized in compressed form. Field …","Curve elements are serialized in uncompressed form. Field …","Serialization is the same as RawBytes, but no checks are …","This enum specifies how various types are serialized and …","This module provides common utilities, traits and …","","","Traits and structs for implementing circuit components.","","","","","Tools for developing circuits.","","","Returns the argument unchanged.","","","Calls U::from(self).","This module provides an implementation of a variant of …","Contains utilities for performing arithmetic over …","","This module contains utilities and traits for dealing with …","","","","","The affine version of the curve","The base field over which this elliptic curve is …","The base field over which this elliptic curve is …","CURVE_ID used for hash-to-curve.","This trait is the affine counterpart to Curve and is used …","This trait is a common interface for dealing with elements …","The projective form of the curve","Generator of the $t-order$ multiplicative subgroup","This trait represents an element of a field.","This trait is a common interface for dealing with elements …","This represents an element of a group with basic …","Modulus of the field written as a string for display …","Inverse of PrimeField::root_of_unity()","The group is assumed to be of prime order $p$. Scalar is …","The scalar field of this elliptic curve.","The scalar field of this elliptic curve.","Inverse of $2$ in the field.","Element of multiplicative order $3$.","Returns the curve constant a.","Returns the curve constant $a$.","Returns the curve constant b.","Returns the curve constant $b$.","Performs a radix-$2$ Fast-Fourier Transformation (FFT) on …","Performs a multi-exponentiation operation.","This computes the inner product of two vectors a and b.","Gets the coordinates of this point.","Cubes this element.","Doubles this element.","Apply the curve endomorphism by multiplying the …","This evaluates a provided polynomial (in coefficient form) …","Obtains a field element that is congruent to the provided …","Obtains a field element congruent to the integer v.","Obtains a point given $(x, y)$, failing if it is not on the","Convert coefficient bases group elements to lagrange basis …","Gets the lower 128 bits of this field element when …","Adds rhs to this group element.","Scales this group element by a scalar.","Subtracts rhs from this group element.","Returns the additive identity of the group.","Requests a hasher that accepts messages and returns …","Computes the multiplicative inverse of this element, …","Returns whether or not this element is on the curve; should","Returns whether or not this element is on the curve; should","Returns true iff this element is zero.","Returns true iff this element is zero.","Return the Jacobian coordinates of this point.","Divides polynomial a in X by X - b with no remainder.","Returns coefficients of an n - 1 degree polynomial given a …","Obtains a point given Jacobian coordinates $X : Y : Z$, …","Returns the one element of the field, the multiplicative …","This simple utility function will parallelize an operation …","Exponentiates self by by, where by is a little-endian order","Exponentiates self by exp, where exp is a little-endian …","Returns an element chosen uniformly at random using a …","This perform recursive butterfly arithmetic","Performs a small multi-exponentiation operation. Uses the …","Returns the square root of the field element, if it is …","Squares this element.","Returns the zero element of the field, the additive …","An assigned cell.","A pointer to a cell within a circuit.","A chip implements a set of instructions that can be used …","A type that holds the configuration for this chip, and any …","A layout strategy within a circuit. The layouter is …","A type that holds any general chip state that needs to be …","This is a “namespaced” layouter which borrows a …","A region of the circuit in which a Chip can assign cells.","Index of a region in a layouter","Starting row of a region in a layouter","Represents the type of the “root” of this layouter, so …","A simple FloorPlanner that performs minimal optimizations.","A lookup table in the circuit.","A value that might exist within a circuit.","","","","","","","","","","","Returns Value::unknown() if the value is Value::unknown(), …","Converts from &mut Value<V> to Value<&mut V>.","Converts from &Value<V> to Value<&V>.","Enforces an assertion on the contained value, if known.","Assign an advice column value (witness).","Assigns a constant value to the column advice at offset …","Assign the value of the instance column’s cell at …","Assigns a fixed value to a table cell.","Assign a fixed value.","Assign a region of gates to an absolute row number.","","Assign a table region to an absolute row number.","","","","","","","","","","","","","","","","","","","","Returns the cell.","","","","","","","","","","","Maps a Value<&V> to a Value<V> by cloning the contents of …","Maps a Value<&mut V> to a Value<V> by cloning the contents …","Returns reference to column","","The chip holds its own configuration.","Constrains a cell to have a constant value.","Constrains two cells to have the same value.","Constrains a Cell to equal an instance column’s row …","","Maps a Value<&V> to a Value<V> by copying the contents of …","Maps a Value<&mut V> to a Value<V> by copying the contents …","Copies the value to a given advice cell and constrains …","Cubes this field element.","","","","","","","","","","","","","","","","","","","","","","Doubles this field element.","","","","","","","","","","","","Checks the contained value for an error condition, if …","Evaluates this value directly, performing an unbatched …","Evaluates this assigned cell’s value directly, …","Implementations of common circuit floor planners.","","","","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","","","Returns the argument unchanged.","Returns the argument unchanged.","Takes each element in the Iterator: if it is …","Queries the value of the given challenge.","Queries the value of the given challenge.","","Gets the “root” of this assignment, bypassing the …","","","","","","","","","","","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Returns the field element corresponding to this value.","Inverts this assigned value (taking the inverse of zero to …","Constructs a known value.","Implementations of common circuit layouters.","Provides access to general chip state loaded at the …","Maps a Value<V> to Value<W> by applying a function to the …","","","","","","","","","","","Enters into a namespace.","","Commit advice columns in current phase and squeeze …","Exits out of the existing namespace.","","Creates a new (sub)namespace and enters into it.","","Returns row offset","","Squares this field element.","","","","","","","","","","","","Returns the field element corresponding to this value.","","","","","","Transposes a Value<[V; LEN]> into a [Value<V>; LEN].","Transposes a Value<impl IntoIterator<Item = V>> into a …","","","","","","","","","","","","","","","","","","","","","","","","","","","","Constructs an unwitnessed value.","Unzips a value containing a tuple of two values.","Returns the value of the AssignedCell.","Returns the field element value of the AssignedCell.","","","","","","","","","","Zips self with another Value.","Concrete column","The virtual column involved in a region. This includes …","Helper trait for implementing a custom Layouter.","The shape of a region. For a region at a certain index, we …","Virtual column representing a (boolean) selector","Helper trait for implementing a custom Layouter.","Assign an advice column value (witness)","Assigns a constant value to the column advice at offset …","Assign the value of the instance column’s cell at …","Assigns a fixed value to a table cell.","Assign a fixed value","","","","","","","","","","Constrains a cell to have a constant value.","Constraint two cells to have the same value.","","","","","","","Enables a selector at the given offset.","","","","Returns the argument unchanged.","","","Returns the argument unchanged.","Queries the value of the given challenge.","","","","Calls U::from(self).","Calls U::from(self).","Commit advice columns in current phase and squeeze …","","","","","","","","","","","","","","A cell used in an active gate was not assigned to.","A struct for collecting and displaying the gates within a …","A constraint was not satisfied for a particular row.","A constraint was active on an unusable row, and is likely …","The location within the circuit at which a particular …","A location inside a region.","A lookup input did not exist in its corresponding table.","A test prover for debugging circuits.","A location outside of a region.","A permutation did not preserve the original value of a …","The reasons why a particular circuit is not satisfied.","Panics if the circuit being checked by this MockProver is …","Panics if the circuit being checked by this MockProver is …","","","","","","","","","","","Collects the gates from within the circuit.","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","","","","","","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Metadata about circuits.","","","Prints the queries in this circuit to a CSV grid.","","Runs a synthetic keygen-and-prove operation on the given …","","","","","","","","","","","","","","","","Returns Ok(()) if this MockProver is satisfied, or a list …","Returns Ok(()) if this MockProver is satisfied, or a list …","Returns Ok(()) if this MockProver is satisfied, or a list …","Returns Ok(()) if this MockProver is satisfied, or a list …","","","","","The offset (relative to the start of the region) at which …","The region in which the failure occurred.","The circuit row on which the failure occurred.","The values of the virtual cells used by this constraint.","The column in which this cell should be assigned.","The column in which this permutation is not satisfied.","The polynomial constraint that is not satisfied.","The polynomial constraint that is not satisfied.","The index of the active gate.","The offset (relative to the start of the region) at which …","The location at which this constraint is not satisfied.","The location at which the lookup is not satisfied.","The location at which the permutation is not satisfied.","The index of the lookup that is not satisfied. These …","The name of the lookup that is not satisfied.","The offset (relative to the start of the region) at which …","The region in which this cell should be assigned.","Metadata about a column within a circuit.","Metadata about a configured constraint within a circuit.","Metadata about a configured gate within a circuit.","Metadata about an assigned region within a circuit.","A “virtual cell” is a PLONK cell that has been queried …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","","","","Returns the argument unchanged.","","Returns the argument unchanged.","","","","Returns the argument unchanged.","","","","","","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","An advice column","An Advice variant","This is an advice (witness) column queried at a certain …","Query of advice column at a certain relative location","An enum over the Advice, Fixed, Instance structs","A value assigned to a cell within a circuit.","This trait allows a Circuit to direct some backend to …","A verifier that checks multiple proofs in a batch. This …","Out of bounds index passed to a backend","A challenge squeezed from transcript after advice columns …","This is a challenge","This is a trait that circuits provide implementations for …","A column with an index and type","The instance sets up a copy constraint involving a column …","A column type","This is a configuration object that stores things like …","This is a constant polynomial","An individual polynomial constraint.","This is a description of the circuit environment, such as …","The constraint system is not satisfied.","A set of polynomial constraints with a common selector.","This is an error that could occur during proving or …","Low-degree expression representing an identity that must …","First phase","A fixed column","A Fixed variant","This is a fixed column queried at a certain relative …","Query of fixed column at a certain relative location","A floor planning strategy for a circuit.","The floor planner used for this circuit. This is an …","Gate","An instance column","An Instance variant","This is an instance (external) column queried at a certain …","Query of instance column at a certain relative location","Instance provided exceeds number of available rows","The provided instances do not match the circuit parameters.","This is a negated polynomial","Circuit synthesis requires global constants, but circuit …","k is too small for the given circuit.","Opening error","Phase of advice column","Represents the minimal parameters that determine a …","Minimal representation of a verification key that can be …","This is the product of two polynomials","This is a proving key which allows for the creation of …","A value stored as a fraction to enable batch inversion.","This is a scaled polynomial","Second phase","A selector, representing a fixed boolean value per row of …","This is a virtual selector","This is the sum of two polynomials","This is an error that can occur during synthesis of the …","A fixed column of a lookup table.","Third phase","Transcript error","A value that does not require inversion to evaluate.","This is a verifying key which allows for the verification …","A “virtual cell” is a PLONK cell that has been queried …","Exposes the “virtual cells” that can be queried while …","The field element zero.","","","","","","","","","","Adds a proof to the batch.","Returns Advice variant in FirstPhase","Allocate a new advice column at FirstPhase","Allocate a new advice column in given phase","Returns phase of advice columns","Returns Advice variant in given Phase","Returns advice queries","Assign an advice column value (witness)","Assign a fixed value","Compute the number of blinding factors necessary to …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns phase of challenges","Requests a challenge that is usable after the given phase.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Column index","Column index","Column index","Type of this column.","Allocate a new complex selector that can appear anywhere …","Approximate the computational complexity of this …","The circuit is given an opportunity to describe the exact …","Returns constants","Assign two cells to have the same value","Creates a new gate.","This creates a proof for the provided circuit when given …","Returns ConstraintSystem","Cubes this element.","","","","Compute the degree of this polynomial","Compute the degree of the constraint system (the maximum …","Returns the denominator, if non-trivial.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Doubles this element.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Enable this selector at the given offset within the given …","Enables this fixed column to be used for global constant …","Enable the ability to enforce equality over cells in this …","Enables a selector at the given row.","Creates a new region and enters into it.","","","","","","","","","","Evaluates this assigned value directly, performing an …","Evaluate the polynomial using the provided closures to …","Evaluate the polynomial lazily using the provided closures …","Exits the current region.","Fills a fixed column starting from the given row with …","Finalizes the batch and checks its validity.","Allocate a new fixed column","Returns commitments of fixed polynomials","Returns fixed queries","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns the argument unchanged.","","","","Returns the argument unchanged.","","","Returns the argument unchanged.","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","","","Returns the argument unchanged.","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","","Returns the argument unchanged.","Returns the argument unchanged.","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Reads a verification key from a slice of bytes using …","Reads a proving key from a slice of bytes using Self::read.","Returns gates","Queries the value of the given challenge.","Get the underlying EvaluationDomain.","Get the underlying VerifyingKey.","","","","","","","","","Hashes a verification key into a transcript.","Identifier for this expression. Expressions with identical …","Index of this column.","Index of this challenge.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Allocate a new instance column","Returns instance queries","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","","Inverts this assigned value (taking the inverse of zero to …","Is this selector “simple”? Simple selectors can only …","Returns true iff this element is zero.","Generate a ProvingKey from a VerifyingKey and an instance …","Generate a VerifyingKey from an instance of Circuit.","Add a lookup argument for some input expressions and table …","Add a lookup argument for some input expressions and table …","Allocates a new fixed column that can be used in a lookup …","Returns lookup arguments","Returns the minimum necessary rows that need to exist in …","","","","","","","","","","","","Returns Advice in given Phase","Constructs a new batch verifier.","Commit advice columns in current phase and squeeze …","Commit advice columns in current phase and squeeze …","Returns number of advice columns","Returns number of challenges","Returns number of fixed columns","Returns number of instance columns","Returns the numerator.","","","Returns permutation argument","Returns VerifyingKey of permutation","Phase of this column","Phase of this advice column","Phase of this challenge.","Obtain a pinned version of this constraint system; a …","Obtains a pinned representation of this verification key …","Returns constraints of this gate","Exits out of the existing namespace.","","Creates a new (sub)namespace and enters into it.","Query an advice column at a relative position","Query an Any column at a relative position","Query a challenge","Query a fixed column at a relative position","Queries the cell of an instance column at a particular …","Query an instance column at a relative position","Query a selector at the current position.","Reads a verification key from a buffer.","Reads a proving key from a buffer. Does so by reading …","Rotation of this query","Rotation of this query","Rotation of this query","Allocate a new (simple) selector. Simple selectors cannot …","Sets the minimum degree required by the circuit, which can …","","Squares this element.","Square this expression.","","","","","","","","","","Given the provided cs, synthesize the given circuit.","Given the provided cs, synthesize the circuit. The …","Writes a verifying key to a vector of bytes using …","Writes a proving key to a vector of bytes using Self::write…","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns a boolean indicating whether or not the proof is …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Constructs a set of constraints that are controlled by the …","Returns a copy of this circuit with no witness values …","Writes a verifying key to a buffer.","Writes a proving key to a buffer.","","","","","","","The current value of k being used.","","","","","","","","","","","","","","","The basis over which a polynomial is described.","The polynomial is defined as coefficients","This is an error that could occur during proving or …","This structure contains precomputed constants and other …","The polynomial is defined as coefficients of Lagrange …","Guards is unfinished verification result. Implement this …","The polynomial is defined as coefficients of Lagrange …","Multi scalar engine which is not evaluated yet.","OpeningProof is not well-formed","The output type of this verification strategy after …","Represents the minimal parameters that determine an …","Represents a univariate polynomial defined over a field …","A polynomial query at a point","Describes the relative rotation of a vector. Negative …","Caller needs to re-sample a point","Trait representing a strategy for verifying Halo 2 proofs.","A polynomial query at a point","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Obtains a polynomial in coefficient form when given a …","This takes us from an n-length coefficient vector into a …","Generic commitment scheme structures","Returns a constant polynomial in the extended Lagrange …","Returns a constant polynomial in the Lagrange coefficient …","The current location in the evaluation domain","","","","","","","","","","","","","","","","","","","","","","","This divides the polynomial (in the extended domain) by …","","","","","","","","","","","Returns an empty (zero) polynomial in the coefficient basis","Returns an empty (zero) polynomial in the extended …","Returns an empty (zero) polynomial in the Lagrange …","","Get the size of the extended domain","Get the size of the extended domain","This takes us from the extended evaluation domain and gets …","Finalizes the batch and checks its validity.","","","","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Get the generator of the extended domain’s …","Get $\\\\omega$, the generator of the $2^k$ order …","Get $\\\\omega^{-1}$, the inverse of the generator of the …","Gets the quotient polynomial’s degree (as a multiple of …","","","","","","","","","","","","","","","","","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Inner product argument commitment scheme","Iterate over the values, which are either in coefficient …","Iterate over the values mutably, which are either in …","Get the size of the domain","KZG commitment scheme","Computes evaluations (at the point x, where xn = x^n) of …","","Obtains a polynomial in Lagrange form when given a vector …","This takes us from an n-length vector into the coefficient …","","Creates new verification strategy instance","This constructs a new evaluation domain object based on …","Create a new verifier query based on a commitment","Create a new verifier query based on a linear combination …","The next location in the evaluation domain","Gets the size of this polynomial in terms of the number of …","Obtain a pinned version of this evaluation domain; a …","The previous location in the evaluation domain","Obtains an MSM from the verifier strategy and yields back …","Rotates the values in a Lagrange basis polynomial by …","Rotate the extended domain polynomial over the original …","Multiplies a value by some power of $\\\\omega$, essentially …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Wrapper type around a blinding factor.","Defines components of a commitment scheme.","Elliptic curve used to commit the application and witnesses","Unfinalized verification result. This is returned in …","Multi scalar multiplication engine","Multi scalar multiplication engine","Accumulator fot comressed verification","Parameters for circuit sysnthesis and prover parameters.","Parameters for circuit sysnthesis and prover parameters.","Constant prover parameters","Verifier specific functionality with circuit constaints","Constant verifier parameters","Constant verifier parameters.","Common multi-open prover interface for various commitment …","Query instance or not","Query instance or not","Application field of this commitment scheme","Common multi-open verifier interface for various …","","","","Add another multiexp into this one","Add arbitrary term (the scalar and the point)","Return base points","","","Perform multiexp and check that it results in zero","","","This computes a commitment to a polynomial described by …","This commits to a polynomial using its evaluations over …","Create a multi-opening proof","","","","Downsize Params with smaller k.","","Generates an empty multiscalar multiplication struct using …","","Perform multiexp and return the result","","Returns the argument unchanged.","Getter for g generators","","Calls U::from(self).","Logaritmic size of the circuit","","","","Size of the circuit","Returns new instance of parameters","Creates new prover instance","Creates new verifier instance","Given rng creates new blinding scalar","Wrapper for parameter generator","Reads params from a buffer.","Wrapper for parameter reader","Scalars","Scale all scalars in the MSM by some scaling factor","","","","","Returns verification parameters.","Process the proof and returns unfinished result named Guard","","Writes params to a buffer.","This module contains an implementation of the polynomial …","Multiscalar multiplication engines","IPA multi-open scheme This module contains an optimisation …","Strategies used with KZG scheme","Concrete IPA commitment scheme","Public parameters for IPA commitment scheme","Verifier parameters","","","","","","","This computes a commitment to a polynomial described by …","This commits to a polynomial using its evaluations over …","Create a polynomial commitment opening proof for the …","","","","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","","","","Calls U::from(self).","Calls U::from(self).","","","Initializes parameters for the curve, given a random …","","Reads params from a buffer.","","","","","","","","","","Checks to see if the proof represented within transcript …","","","Writes params to a buffer.","A multiscalar multiplication in the polynomial commitment …","Add a value to the first entry of g_scalars.","Add another multiexp into this one","Add another multiexp into this one","Add a vector of scalars to g_scalars. This function will …","Add to u_scalar","Add to w_scalar","","","","","","","","","","","","","Returns the argument unchanged.","","Calls U::from(self).","Given verifier parameters Creates an empty multi scalar …","","","","","","","","IPA multi-open prover","IPA multi-open verifier","","","","","Create a multi-opening proof","","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","","","Calls U::from(self).","Calls U::from(self).","","","","","","","","","","","","An accumulator instance consisting of an evaluation claim …","A verifier that checks multiple proofs in a batch.","Wrapper for verification accumulator","A verifier that checks single proof","","","","","","","","","","","","","Computes G = ⟨s, params.g⟩","","","","","","","","","","","","","Finalizes the batch and checks its validity.","Finalizes the batch and checks its validity.","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","The claimed output of the linear-time polycommit opening …","","","","","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","","","","","","","","","","","","","","","","","","","A vector of challenges u_0, …, u_{k - 1} sampled by the …","Lets caller supply the challenges and obtain an MSM with …","Lets caller supply the purported G point and simply appends","","","","","KZG commitment scheme","Multiscalar multiplication engines","KZG multi-open scheme","Strategies used with KZG scheme","Umbrella commitment scheme construction for all KZG …","These are the public parameters for the polynomial …","KZG multi-open verification parameters","","","","","","","","","","","","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns gernerator on G2","","","","Calls U::from(self).","Calls U::from(self).","","","","","Reads params from a buffer.","Reads params from a buffer.","","Returns first power of secret on G2","Initializes parameters for the curve, draws toxic secret …","","","","","","","","","","","Writes params to a buffer.","Writes parameters to buffer","Two channel MSM accumulator","A multiscalar multiplication in the polynomial commitment …","","Add another multiexp into this one","","","","","","","","Performs final pairing check with given verifier params …","","","","","Prepares all scalars in the MSM to linear combination","","","","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","","","","Calls U::from(self).","Calls U::from(self).","Create an empty MSM instance","Create a new two channel MSM accumulator instance","","","Scale all scalars in the MSM by some scaling factor","","","","","","","","","","","Concrete KZG prover with GWC variant","Concrete KZG prover with SHPLONK variant","Concrete KZG verifier with GWC variant","Concrete KZG multiopen verifier with SHPLONK variant","","","","","","","","","Create a multi-opening proof","Create a multi-opening proof","","","","","","","","","","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","","","","","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","","","","Given parameters creates new prover instance","","","","","","","","","","","","","","","Verify a multi-opening proof","","","","","A verifier that checks multiple proofs in a batch","Wrapper for linear verification accumulator","A verifier that checks a single proof","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","","","","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Constructs an empty batch verifier","","","Constructs an empty batch verifier","","","","","","","","","","","","","","","","","","Constructs and initialized new batch verifier","We will replace BLAKE2b with an algebraic hash function in …","We will replace BLAKE2b with an algebraic hash function in …","A 255-bit challenge.","The scalar representation of a verifier challenge.","EncodedChallenge<C> defines a challenge encoding with a …","The Input type used to derive the challenge encoding. For …","Generic transcript view (from either the prover or verifier…","Transcript view from the perspective of a verifier that …","Initializes transcript at verifier side.","Transcript view from the perspective of a prover that has …","Manages begining and finising of transcript pipeline.","Cast an encoded challenge as a typed ChallengeScalar.","","","","","","","","","","","","","","","","","Writing the point to the transcript without writing it to …","","","Writing the scalar to the transcript without writing it to …","","","","","","","","","","","","","","","","","Conclude the interaction and return the output buffer …","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Get a scalar field element from an encoded challenge.","","Initialize a transcript given an input buffer.","Initialize a transcript given an output buffer.","","Initialize a transcript given an input buffer.","","","","","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Get an encoded challenge from a given input challenge.","","Read a curve point from the prover.","","Read a curve scalar from the prover.","","Squeeze an encoded verifier challenge from the transcript.","","","Squeeze a typed challenge (in the scalar field) from the …","","","","","","","","","","","","","","","","","","","","","Write a curve point to the proof and the transcript.","","Write a scalar to the proof and the transcript.",""],"i":[1,1,1,0,0,1,1,0,1,1,1,1,0,1,1,1,0,1,1,0,0,1,0,1,1,1,1,148,148,13,148,0,0,13,21,0,0,0,21,21,60,148,13,21,21,148,13,148,13,0,0,0,13,8,8,148,0,21,21,13,0,21,60,60,60,60,148,8,148,13,8,8,148,0,0,148,8,0,21,8,8,0,0,8,8,8,0,0,0,149,0,149,0,0,0,0,40,0,0,0,27,27,27,27,27,27,27,27,27,27,27,27,27,27,29,29,29,36,29,40,41,40,41,27,45,42,43,39,33,29,36,41,27,45,42,43,39,33,29,36,41,33,27,42,43,39,33,27,42,43,39,33,27,27,39,33,149,29,29,40,41,27,27,33,27,27,27,45,42,42,43,43,39,33,29,36,41,27,45,42,43,39,33,29,36,41,27,27,45,42,43,39,33,29,36,41,41,43,27,27,33,0,27,45,42,43,39,33,29,36,41,27,27,45,42,42,43,43,39,33,29,29,36,36,41,27,40,29,41,40,41,27,45,42,43,39,33,29,36,41,27,45,42,43,39,33,29,36,41,27,27,27,0,149,27,27,27,27,27,27,27,27,27,27,27,40,27,29,40,41,40,41,39,33,27,27,27,27,27,27,27,27,27,27,27,45,27,27,42,43,39,33,27,27,27,45,42,43,39,33,29,36,41,27,45,42,43,39,33,29,36,41,27,45,42,43,39,33,29,36,41,27,27,33,33,27,45,42,43,39,33,29,36,41,27,55,0,0,0,55,0,46,46,46,47,46,54,55,54,55,54,55,54,55,55,46,46,54,55,54,55,54,55,46,55,54,55,54,55,55,55,46,55,54,55,54,55,46,55,54,55,54,55,54,55,54,55,54,55,150,151,63,0,63,63,0,62,63,0,62,63,0,59,59,59,59,62,63,61,59,62,63,61,59,61,59,62,63,61,59,62,63,61,59,62,63,61,59,59,59,62,63,59,59,62,62,63,63,61,61,59,62,63,61,59,59,62,63,61,59,62,63,61,59,0,59,59,61,59,59,62,63,61,62,63,61,59,62,63,61,59,62,63,61,59,59,59,59,59,62,63,61,59,152,152,153,154,155,156,154,157,155,155,154,158,156,158,158,155,155,0,0,0,0,0,66,68,69,70,67,66,68,69,70,67,66,67,66,67,66,68,66,68,69,70,67,66,68,69,70,67,66,68,69,70,67,66,68,69,70,67,66,66,68,68,69,69,70,70,67,67,66,66,66,68,68,68,68,69,69,70,70,67,67,67,66,68,69,70,67,66,68,69,70,67,66,68,66,67,66,68,69,70,67,66,68,69,70,67,66,68,69,70,67,66,68,69,70,67,66,68,69,70,67,0,58,72,0,0,0,0,0,34,0,72,0,0,34,0,159,72,0,0,34,0,0,0,0,0,58,72,0,0,159,0,0,58,72,0,34,34,72,34,34,34,0,0,0,72,0,26,72,0,0,72,72,34,0,0,34,26,0,0,0,26,26,26,26,26,26,26,72,26,26,73,58,75,75,75,58,75,160,160,75,87,26,31,88,89,90,30,38,35,58,57,78,79,80,37,49,72,71,91,92,81,75,93,34,73,82,94,83,87,26,31,88,89,90,30,38,35,58,57,78,79,80,37,49,72,71,91,92,81,75,93,34,73,82,94,83,75,75,26,31,30,38,35,58,57,78,79,80,37,49,72,71,81,75,82,83,26,31,30,38,35,58,57,78,79,80,37,49,72,71,81,75,82,83,31,58,78,79,80,31,75,72,159,75,160,75,0,82,26,30,75,73,72,75,26,87,26,31,88,89,90,30,38,35,58,57,78,79,80,37,49,72,71,91,92,81,75,93,34,73,82,94,83,87,26,31,88,89,90,30,38,35,58,57,78,79,80,37,49,72,71,91,92,81,75,93,34,73,82,94,83,26,87,26,31,88,89,90,30,38,35,58,57,78,79,80,37,49,72,71,91,92,81,75,93,34,73,82,94,83,57,75,75,160,160,26,31,30,38,35,58,57,37,49,26,72,72,160,160,73,75,82,75,87,26,31,88,89,90,30,38,35,58,57,78,79,80,37,49,72,71,91,92,81,75,93,34,34,73,82,94,83,87,26,26,26,26,26,31,31,31,31,88,89,90,30,38,35,58,58,58,58,57,78,79,80,37,49,72,71,71,91,91,91,92,81,75,93,34,34,73,82,94,83,82,83,75,160,82,83,31,30,38,35,58,57,37,49,82,72,31,49,87,26,31,88,89,90,30,38,35,58,57,78,79,80,37,49,72,71,91,92,81,75,93,34,73,82,94,83,75,75,87,26,31,88,89,90,30,38,35,58,57,78,79,80,37,49,72,71,91,92,81,75,93,34,73,82,94,83,92,26,57,26,0,0,75,75,75,75,75,26,26,26,26,72,72,26,26,26,26,72,30,73,160,160,75,75,75,75,26,31,58,75,82,30,79,49,75,82,81,160,34,160,93,93,93,93,160,93,93,82,83,78,79,80,75,75,34,26,72,26,26,26,26,26,26,72,26,26,161,159,82,83,26,31,30,38,35,58,57,78,79,80,37,49,72,71,81,75,82,83,34,87,26,31,31,31,31,88,89,90,30,38,35,58,57,78,79,80,37,49,72,71,91,92,81,75,93,34,73,82,94,83,87,26,31,88,89,90,30,38,35,58,57,78,79,80,37,49,72,71,91,92,81,75,93,34,73,82,94,83,87,26,31,88,89,90,30,38,35,58,57,78,79,80,37,49,72,71,91,92,81,75,93,34,73,82,94,83,0,87,26,31,88,89,90,30,38,35,58,57,78,79,80,37,49,72,71,91,92,81,75,93,34,73,82,94,83,92,159,82,83,162,163,164,164,165,166,167,168,169,170,171,172,173,174,175,176,177,175,176,177,100,0,0,0,0,0,0,0,178,114,104,0,0,0,0,114,0,0,106,97,113,107,109,114,110,111,112,106,100,97,113,107,109,114,110,111,112,106,100,97,107,109,110,111,112,106,100,97,107,109,110,111,112,106,100,97,97,0,97,97,100,97,113,107,109,114,110,111,112,106,106,100,97,113,107,109,114,110,111,112,106,106,100,97,97,113,107,109,114,110,111,112,106,100,97,97,97,100,97,97,97,104,97,113,107,109,114,110,111,112,106,100,97,113,107,109,114,110,111,112,106,100,97,97,97,97,106,106,106,106,106,106,97,113,107,109,114,110,111,112,106,100,97,113,107,109,114,110,111,112,106,100,0,106,106,97,0,97,97,97,97,106,104,97,109,109,100,106,97,100,104,106,97,97,106,106,97,107,109,110,111,112,106,100,97,113,107,109,114,110,111,112,106,100,97,113,107,109,114,110,111,112,106,100,97,113,107,109,114,110,111,112,106,100,97,113,107,109,114,110,111,112,106,100,117,0,0,102,103,0,179,103,0,0,102,0,102,180,0,181,103,102,0,117,117,117,108,108,108,117,117,108,117,117,180,179,181,117,117,117,179,117,179,117,108,117,117,180,117,117,179,117,117,117,179,180,181,103,117,102,179,102,108,108,117,117,117,117,180,103,117,179,0,0,0,0,0,0,0,119,121,119,121,119,119,119,119,0,119,121,119,121,119,119,121,119,119,121,119,121,119,119,121,119,121,119,119,119,121,119,121,119,119,121,119,121,119,121,119,0,119,121,119,0,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,120,0,0,123,124,123,124,123,123,124,123,124,123,124,123,124,123,124,123,124,123,124,123,124,123,124,123,124,123,124,124,123,124,0,0,0,0,122,125,126,127,122,125,126,127,122,125,122,125,122,122,125,126,127,122,125,126,127,122,125,126,127,126,127,122,125,126,127,122,125,126,127,125,122,125,126,127,122,125,126,127,126,127,126,127,122,125,122,125,126,127,122,125,126,127,122,125,126,127,125,122,122,122,125,126,127,0,0,0,0,0,0,0,129,131,129,131,129,129,129,129,129,131,129,131,129,129,131,129,129,131,129,131,129,129,129,131,129,131,129,129,129,131,129,129,131,129,129,129,129,131,129,131,129,131,129,129,131,129,129,0,0,130,133,130,130,130,133,130,133,130,133,130,133,130,133,130,130,130,133,130,133,130,133,130,130,133,130,133,133,130,133,130,133,130,133,130,130,133,130,133,130,133,130,133,130,133,130,133,0,0,0,0,134,136,135,137,134,136,135,137,134,135,134,136,135,137,134,136,135,137,134,136,135,137,134,136,135,137,134,136,135,137,134,136,135,137,134,136,135,137,134,136,135,135,137,134,136,135,137,134,136,135,137,134,136,135,137,136,137,134,136,135,137,0,0,0,138,139,140,138,139,140,138,139,140,138,139,140,138,139,140,138,139,140,138,139,140,139,140,138,139,140,138,139,140,138,139,140,138,139,140,139,139,140,140,139,140,138,139,140,138,139,140,138,139,140,138,139,140,138,139,140,139,0,0,0,0,0,143,0,0,0,0,0,143,144,146,141,147,144,146,141,147,144,146,141,147,144,146,141,147,182,144,146,182,144,146,144,146,141,141,147,147,144,146,141,147,144,146,141,147,183,146,144,146,141,147,144,146,141,147,143,147,184,183,144,144,146,146,141,147,144,146,141,147,143,147,185,144,185,144,182,144,146,182,144,146,141,147,144,146,141,147,144,146,141,147,144,146,141,147,144,146,141,147,186,146,186,146],"f":[0,0,0,0,0,[[]],[[]],0,[1,1],[[]],[2],[2],0,[2],[[1,3],4],[[]],0,[[],2],[[]],0,0,[[]],0,[[],5],[[],5],[[],6],[[]],0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,[[]],[[]],[[]],[[]],[7],[[]],[[],8],[[],[[10,[9]]]],[[]],[[]],[[]],[8,8],[[]],[11],[[],10],[[12,7],[[12,[13]]]],[[],11],[[]],[[]],[[]],[[]],[14,[[17,[15,16]]]],[[],10],[[],18],[[],18],[[],18],[[],19],[[]],[[20,8],[[12,[8]]]],[[],[[12,[21]]]],[[],10],[[]],[[[0,[15,22,23,24]]]],[[]],[[]],[25],[[2,2]],[[]],[[],10],[[]],[[]],0,0,0,0,0,0,0,0,0,0,0,0,0,0,[[[27,[[26,[8]]]],[27,[8]]]],[[27,27]],[[27,27]],[[27,27]],[[27,27]],[[27,27]],[[[27,[26]],8]],[[[27,[26]],[27,[8]]]],[[[27,[[26,[8]]]],8]],[[27,27]],[[27,28],27],[27,27],[27,27],[[27,28]],[[[29,[8]],[31,[30]],2,[27,[[32,[[26,[8]]]]]]],[[5,[[33,[26,8]],34]]]],[[[29,[8]],[31,[30]],2],[[5,[[33,[8]],34]]]],[[[29,[8]],[31,[35]],2,[31,[30]],2],[[5,[[33,[8,8]],34]]]],[[[36,[8]],37,2],[[5,[34]]]],[[[29,[8]],[31,[38]],2,[32,[[26,[8]]]]],39],[[],[[5,[34]]]],[[[41,[8,[40,[8]]]]],[[5,[34]]]],[[],[[5,[34]]]],[[[41,[8,[40,[8]]]]],[[5,[34]]]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[[33,[8]]],39],[[[27,[24]]],[[27,[24]]]],[42,42],[43,43],[39,39],[[[33,[24,[0,[24,8]]]]],[[33,[24,[0,[24,8]]]]]],[[]],[[]],[[]],[[]],[[]],[27,27],[27,27],[39,31],[[[33,[8]]],31],[[]],[[[29,[8]],39],[[5,[34]]]],[[[29,[8]],39,39]],[[39,[31,[35]],2]],[[[41,[8,[40,[8]]]],39,[31,[35]],2]],[27,27],[27,27],[[[33,[26,8]],29,[31,[30]],2],[[33,[26,8]]]],[27,[[27,[[26,[8]]]]]],[[],27],[2],[2],[2],[42],[2],[43],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[27,[[27,[[26,[8]]]]]],[2],[2],[2],[2],[2],[2],[2],[2],[2],[[[41,[8,[40,[8]]]]]],[[43,43],19],[[27,28],[[5,[34]]]],[[[27,[[26,[8]]]]],[[27,[8]]]],[[[33,[[26,[8]],8]]],[[33,[8,8]]]],0,[[[27,[44]],3],4],[[45,3],4],[[42,3],4],[[43,3],4],[[39,3],4],[[[33,[44,[0,[44,8]]]],3],4],[[[29,[[0,[44,8]]]],3],4],[[[36,[[0,[44,8]]]],3],4],[[[41,[[0,[44,8]],[0,[44,[40,[[0,[44,8]]]]]]]],3],4],[[[27,[8]]],[[27,[[26,[8]]]]]],[[]],[[]],[[]],[2,42],[2,43],[[]],[[]],[[]],[[]],[46,[[29,[8]]]],[47,[[36,[8]]]],[[]],[[]],[20,[[27,[48]]]],[49,27],[[[29,[8]],49],[[27,[8]]]],[[[41,[8,[40,[8]]]],49],[[27,[8]]]],[[]],[[[41,[8,[40,[8]]]]]],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[27,[[27,[[26,[8]]]]]],[27,[[27,[[26,[8]]]]]],[[],27],0,[[]],[[27,28],27],[[[27,[[26,[8]]]],8]],[[27,27]],[[27,27]],[[[27,[[26,[8]]]],[27,[8]]]],[[27,27]],[[[27,[26]],[27,[8]]]],[[27,27]],[[[27,[26]],8]],[[27,27]],[[27,27]],[[],41],[[[27,[50]]]],[[[29,[8]]]],[[[52,[51]]]],[[[41,[8,[40,[8]]]],[52,[51]]]],[[]],[[[41,[8,[40,[8]]]]]],[39,2],[[[33,[8]]],2],[27,[[27,[[26,[8]]]]]],[[27,27]],[[27,27]],[[27,27]],[[27,27]],[[27,27]],[[[27,[26]],8]],[[27,27]],[[[27,[26]],[27,[8]]]],[[[27,[[26,[8]]]],8]],[[[27,[[26,[8]]]],[27,[8]]]],[[[12,[[31,[38]]]]],[[5,[34]]]],[27,[[27,[[26,[8]]]]]],[[]],[[]],[[]],[[]],[[]],[27],[[27,2],[[12,[27]]]],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],27],[27],[[[33,[8]]],27],[[[33,[8]]],[[27,[[26,[8]]]]]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[27,27],27],0,0,0,0,0,0,[[[31,[30]],2,[27,[26]]],[[5,[[33,[26]],34]]]],[[15,[31,[30]],2,26],[[5,[39,34]]]],[[15,[31,[35]],2,[31,[30]],2],[[5,[34]]]],[[15,37,2,53],[[5,[34]]]],[[[31,[38]],2,26],39],[[]],[[]],[[]],[[]],[54,54],[55,55],[[]],[[]],[[55,55],56],[[39,26],[[5,[34]]]],[[39,39]],[2],[2],[2],[2],[2],[2],[[15,57,2],[[5,[34]]]],[[55,55],19],[[54,3],4],[[55,3],4],[[]],[[[31,[58]]],55],[57,55],[[]],[49,27],[55],[[],2],[[],2],[[]],[[]],[[]],[[55,55],[[52,[56]]]],[[]],[[]],[[],5],[[],5],[[],5],[[],5],[[],6],[[],6],[[]],[[]],0,0,0,0,0,0,0,0,0,0,0,0,0,[[[59,[21]]]],[[[59,[21]]]],[[[59,[[0,[8,60]]]],[31,[30]],2,[27,[[26,[[0,[8,60]]]]]]],[[5,[[27,[26]],34]]]],[[[59,[[0,[8,60]]]],[31,[38]],2,[26,[[0,[8,60]]]]]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],61],[[[59,[[0,[8,60]]]],[31,[58]],2,[31,[58]],2]],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[[[59,[[0,[8,60]]]],57,2],[[5,[34]]]],[[[59,[[0,[8,60]]]]]],[[62,62],19],[[63,63],19],[[[59,[[0,[8,60]]]]]],[[[59,[[0,[8,60]]]],[31,[38]],2,[27,[[26,[[0,[8,60]]]]]]],[[5,[34]]]],[[62,3],4],[[62,3],4],[[63,3],4],[[63,3],4],[[61,3],4],[[61,3],[[5,[64]]]],[[[59,[[0,[44,60,8]]]],3],4],[[]],[[]],[[]],[[]],[[[59,[[0,[8,60]]]],49],[[27,[[0,[8,60]]]]]],[[],2],[[],2],[[],2],[[],2],[[]],[[]],[[]],[[]],0,[[[59,[[0,[8,60]]]],[52,[51]]]],[[[59,[[0,[8,60]]]]]],[61,51],[[[59,[[0,[8,60]]]],[31,[35]],2],[[5,[[27,[[0,[8,60]]]],34]]]],[[7,[12,[[12,[21]]]]],[[5,[[59,[21]],34]]]],[[],51],[[],51],[[],51],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],6],[[],6],[[],6],[[],6],[[[59,[21]]],[[5,[[12,[63]]]]]],[[[59,[21]],[0,[24,65]],[0,[24,65]]],[[5,[[12,[63]]]]]],[[[59,[21]],[0,[24,65]],[0,[24,65]]],[[5,[[12,[63]]]]]],[[[59,[21]]],[[5,[[12,[63]]]]]],[[]],[[]],[[]],[[]],0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[66,66],[67,67],[[]],[[]],[[66,66],56],[[68,68],56],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[[66,66],19],[[68,68],19],[[69,69],19],[[70,70],19],[[67,67],19],[[66,3],4],[[66,3],4],[[68,3],4],[[68,3],4],[[69,3],4],[[69,3],4],[[70,3],4],[[70,3],4],[[67,3],4],[[67,3],4],[[[31,[58]]],66],[[],66],[[]],[[]],[[],68],[71,68],[[],68],[[]],[[],69],[[]],[[],70],[[],67],[[],67],[[]],[[],2],[[],2],[[],2],[[],2],[[],2],[[]],[[]],[[]],[[]],[[]],[[66,66],[[52,[56]]]],[[68,68],[[52,[56]]]],[[]],[[]],[[],51],[[],51],[[],51],[[],51],[[],51],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],6],[[],6],[[],6],[[],6],[[],6],[[]],[[]],[[]],[[]],[[]],0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,[[26,8],[[26,[8]]]],[[[26,[8]],[26,[8]]],[[26,[8]]]],[[26,26],[[26,[8]]]],[[[26,[8]],8],[[26,[8]]]],[[26,[26,[8]]],[[26,[8]]]],[[[26,[8]],[26,[8]]],[[26,[8]]]],[[[72,[8]],[72,[8]]],[[72,[8]]]],[[[26,[8]],[26,[8]]]],[[[26,[8]],[26,[8]]]],[[[73,[13]],[12,[[12,[12]]]],[12,[74]]]],[[],58],[[[75,[8]]],[[31,[30]]]],[[[75,[8]],76],[[31,[30]]]],[[[75,[8]]],[[12,[74]]]],[76,58],[[[75,[8]]],12],[[[31,[30]],2,[27,[26]]],[[5,[[27,[26]],34]]]],[[[31,[38]],2,26]],[[[75,[8]]],2],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[[75,[8]]],[[12,[74]]]],[[[75,[8]],76],49],[[[26,[24]]],[[26,[24]]]],[[[31,[[0,[24,77]]]]],[[31,[[0,[24,77]]]]]],[30,30],[38,38],[35,35],[58,58],[57,57],[78,78],[79,79],[80,80],[37,37],[49,49],[[[72,[24]]],[[72,[24]]]],[71,71],[[[81,[[0,[24,8]]]]],[[81,[[0,[24,8]]]]]],[[[75,[[0,[24,8]]]]],[[75,[[0,[24,8]]]]]],[[[82,[[0,[24,13]]]]],[[82,[[0,[24,13]]]]]],[[[83,[[0,[24,13]]]]],[[83,[[0,[24,13]]]]]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[[31,[77]],[31,[77]]],56],[[58,58],56],[78,2],[79,2],[80,2],[[[31,[77]]]],[[[75,[8]]],57],[[[72,[8]]],2],[75],[[[75,[8]]],12],[[[31,[58]],2,[31,[58]],2]],[[[75,[8]],14,28]],[[83,25],[[5,[34]]]],[[[82,[13]]],75],[[[26,[8]]],[[26,[8]]]],[[],30],[[],[[75,[8]]]],[[],[[73,[[0,[84,13]]]]]],[[[72,[8]]],2],[[[75,[8]]],2],[[[26,[8]]],[[52,[8]]]],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[[[26,[8]]],[[26,[8]]]],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[[57,29,2],[[5,[34]]]],[[[75,[8]],[31,[38]]]],[[[75,[8]],[32,[[31,[58]]]]]],[[57,2],[[5,[34]]]],[[]],[[[26,[8]],[26,[8]]],19],[[[31,[[0,[85,77]]]],31],19],[[30,30],19],[[38,38],19],[[35,35],19],[[58,58],19],[[57,57],19],[[37,37],19],[[49,49],19],[[[26,[8]]],8],[[[72,[8]]]],[[[72,[8]]],85],[[]],[[[31,[38]],2,[27,[26]]],[[5,[34]]]],[[[73,[13]],86,82],19],[[[75,[8]]],[[31,[38]]]],[[[82,[13]]],12],[[[75,[8]]],12],[[[87,[8]],3],4],[[[26,[44]],3],4],[[[31,[[0,[44,77]]]],3],4],[[88,3],4],[[89,3],4],[[90,3],4],[[30,3],4],[[38,3],4],[[35,3],4],[[58,3],4],[[57,3],4],[[78,3],4],[[79,3],4],[[80,3],4],[[37,3],4],[[49,3],4],[[[72,[44]],3],4],[[71,3],4],[[[91,[[0,[44,8]]]],3],4],[[[92,[[0,[44,8]],[0,[44,[32,[[91,[[0,[44,8]]]]]]]],[0,[44,20]]]],3],4],[[[81,[[0,[44,8]]]],3],4],[[[75,[[0,[44,8]]]],3],4],[[[93,[[0,[44,8]]]],3],4],[[34,3],4],[[34,3],4],[[[73,[[0,[44,13]]]],3],4],[[[82,[[0,[44,13]]]],3],4],[[[94,[[0,[44,13]]]],3],4],[[[83,[[0,[44,13]]]],3],4],[[]],[[],[[26,[8]]]],[8,[[26,[8]]]],[[],[[26,[8]]]],[[]],[26,[[26,[8]]]],[[[31,[30]]],[[31,[58]]]],[[]],[[[31,[38]]],[[31,[58]]]],[[[31,[35]]],[[31,[58]]]],[[]],[[]],[[]],[[]],[[]],[[]],[38,58],[30,58],[[]],[35,58],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],71],[[]],[[]],[[[72,[8]]],[[91,[8]]]],[[],[[91,[8]]]],[[]],[[]],[[]],[[]],[[]],[95,34],[[]],[[]],[[]],[[]],[1,[[96,[[82,[0]]]]]],[1,[[96,[[83,[0]]]]]],[[[75,[8]]],12],[49,27],[[[82,[13]]],97],[[[83,[13]]],82],[[[31,[[0,[98,77]]]]]],[30],[38],[35],[58],[57],[37],[49],[[[82,[13]]],96],[[[72,[8]]],51],[[[31,[77]]],2],[49,2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[[75,[8]]],[[31,[35]]]],[[[75,[8]]],12],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[[92,[8,[32,[[91,[8]]]],20]]]],[[[26,[8]]],[[26,[8]]]],[57,19],[[[26,[8]]],19],[82,[[5,[83,34]]]],[[],[[5,[82,34]]]],[[[75,[8]],14,28],2],[[[75,[8]],14,28],2],[[[75,[8]]],37],[[[75,[8]]],12],[[[75,[8]]],2],[[[26,[8]],[26,[8]]],[[26,[8]]]],[[26,8],[[26,[8]]]],[[[26,[8]],26],[[26,[8]]]],[[[26,[8]],8],[[26,[8]]]],[[[72,[8]],8],[[72,[8]]]],[[[72,[8]],[72,[8]]],[[72,[8]]]],[[[26,[8]],[26,[8]]]],[[[26,[8]],[26,[8]]]],[[[26,[8]]]],[26],[[[72,[8]]]],[76,30],[[],[[73,[13]]]],[[]],[[]],[[[75,[8]]],2],[[[75,[8]]],2],[[[75,[8]]],2],[[[75,[8]]],2],[[[26,[8]]],8],[[[31,[77]],[31,[77]]],[[52,[56]]]],[[58,58],[[52,[56]]]],0,0,[30,74],[79,74],[49,74],[[[75,[8]]],[[87,[8]]]],[[[82,[13]]],[[94,[13]]]],[[[81,[8]]]],[[[52,[51]]]],[99],[[]],[[[93,[8]],[31,[30]],100],[[72,[8]]]],[[[93,[8]],[32,[[31,[58]]]],100],[[72,[8]]]],[[[93,[8]],49],[[72,[8]]]],[[[93,[8]],[31,[38]],100],[[72,[8]]]],[[[31,[35]],2],[[5,[27,34]]]],[[[93,[8]],[31,[35]],100],[[72,[8]]]],[[[93,[8]],57],[[72,[8]]]],[1,[[96,[[82,[0]]]]]],[1,[[96,[[83,[0]]]]]],[78,100],[79,100],[80,100],[[[75,[8]]],57],[[[75,[8]],2]],[34,[[52,[101]]]],[[[26,[8]]],[[26,[8]]]],[[[72,[8]]],[[72,[8]]]],[[[26,[8]],[26,[8]]],[[26,[8]]]],[[26,26],[[26,[8]]]],[[[26,[8]],8],[[26,[8]]]],[[[26,[8]],[26,[8]]],[[26,[8]]]],[[26,8],[[26,[8]]]],[[26,[26,[8]]],[[26,[8]]]],[[[72,[8]],[72,[8]]],[[72,[8]]]],[[[26,[8]],[26,[8]]]],[[[26,[8]],[26,[8]]]],[[[12,[[31,[38]]]]],[[5,[34]]]],[40,[[5,[34]]]],[[[82,[0]],1],[[12,[74]]]],[[[83,[0]],1],[[12,[74]]]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],51],[[],5],[[],5],[[[31,[58]]],[[5,[[31,[30]]]]]],[[],5],[[[31,[58]]],[[5,[[31,[35]]]]]],[[[31,[58]]],[[5,[[31,[38]]]]]],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[82,[104,[102,[103,[102]]]]],[[5,[34]]]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[[72,[8]],20],[[92,[8,[32,[[91,[8]]]],20]]]],[[]],[[[82,[0]],1],96],[[[83,[0]],1],96],0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,[[[106,[8,105]],106],[[106,[8,105]]]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[[97,[[0,[24,60]]]]],[[97,[[0,[24,60]]]]]],[[[107,[[0,[24,13]]]]],[[107,[[0,[24,13]]]]]],[[[109,[13,[108,[13]]]]],[[109,[13,[108,[13]]]]]],[110,110],[111,111],[112,112],[[[106,[24,24]]],[[106,[24,24]]]],[100,100],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[[97,[60]],[12,[60]]],[[106,[60,110]]]],[[[97,[60]],[106,[60,110]]],[[106,[60,112]]]],0,[[[97,[60]],60],[[106,[60,112]]]],[[[97,[60]],60],[[106,[60,111]]]],[[],100],[2],[2],[2],[2],[2],[2],[2],[2],[106],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[106],[2],[2],[[[97,[60]],[106,[60,112]]],[[106,[60,112]]]],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[[[97,[60]]],[[106,[60,110]]]],[[[97,[60]]],[[106,[60,112]]]],[[[97,[60]]],[[106,[60,111]]]],[[100,100],19],[[[97,[60]]],7],[[[97,[60]]],2],[[[97,[60]],[106,[60,112]]],[[12,[60]]]],[[],19],[[[97,[[0,[44,60]]]],3],4],[[[113,[[0,[44,60]]]],3],4],[[[107,[[0,[44,13]]]],3],4],[[[109,[[0,[44,13]],[0,[44,[108,[[0,[44,13]]]]]]]],3],4],[[114,3],4],[[110,3],4],[[111,3],4],[[112,3],4],[[[106,[44,44]],3],4],[[100,3],4],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[[97,[60]]]],[[[97,[60]]]],[[[97,[60]]]],[[[97,[60]]],2],[[106,115]],[[106,[116,[2]]]],[[106,2]],[[106,[116,[2]]]],[[106,2]],[[106,115]],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[],2],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],0,[106,65],[106,65],[[[97,[60]]],7],0,[[[97,[60]],[0,[20,24]]],12],[[[97,[60]],[12,[[26,[60]]]]],[[106,[[26,[60]],111]]]],[[[97,[60]],[12,[60]]],[[106,[60,111]]]],[[[97,[60]],[106,[60,111]]],[[106,[60,110]]]],[[[106,[8,105]],8],[[106,[8,105]]]],[[]],[[7,7],[[97,[60]]]],[[],[[109,[13,[108,[13]]]]]],[[],[[109,[13,[108,[13]]]]]],[[],100],[106,2],[[[97,[60]]],[[113,[60]]]],[[],100],[28,[[5,[34]]]],[[[106,[8,111]],100],[[106,[8,111]]]],[[[97,[60]],106,100],[[106,[60,112]]]],[[[97,[60]],100]],[[[106,[8,105]],106],[[106,[8,105]]]],[[106,8],[[106,[8,105]]]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[],6],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,[[[117,[21]],[117,[21]]],[[117,[21]]]],[[[117,[21]],[117,[21]]]],[[[117,[21]],21]],[[]],[[]],[[],12],[[]],[[]],[[],19],[[[117,[24]]],[[117,[24]]]],[[]],[[106,117]],[[106,117]],[[],96],[[],[[117,[21]]]],[2],[2],[7],[2],[[]],[[[117,[85]],117],19],[[]],[[[117,[44]],3],4],[[]],[[]],[[],2],[[]],[[],7],[[[117,[21]],[117,[21]]],[[117,[21]]]],[[[117,[21]],21]],[[[117,[21]],[117,[21]]]],[[],118],[7],[[]],[[]],[[],[[117,[21]]]],[7],[[],96],[[],96],[[],12],[[]],[[]],[[],5],[[],5],[[],6],[[]],[[],[[5,[114]]]],[[]],[[],96],0,0,0,0,0,0,0,[[]],[[]],[[]],[[]],[[[119,[[0,[24,13]]]]],[[119,[[0,[24,13]]]]]],[[]],[[[119,[13]],106,117]],[[[119,[13]],106,117]],[[119,25,106,117],96],[2],[2],[2],[2],[[[119,[13]],7]],[2],[2],[[[119,[13]]],[[120,[13]]]],[[[119,[[0,[44,13]]]],3],4],[[[121,[[0,[44,13]]]],3],4],[[]],[[]],[[[119,[13]]]],[[],2],[[],2],[[]],[[]],[[[119,[13]]],7],[[[119,[13]]],118],[7,[[119,[13]]]],[7],[[],[[96,[[119,[13]]]]]],[[],96],[[]],[[],5],[[],5],[[],5],[[],5],[[],6],[[],6],[[[119,[13]]]],[[119,[120,[13]]],[[5,[[122,[13]],114]]]],[[]],[[]],[[[119,[13]]],96],0,[[[120,[13]]]],[[[120,[13]],[120,[13]]]],[[[120,[13]],[120,[13]]]],[[[120,[13]]]],[[[120,[13]]]],[[[120,[13]]]],[[[120,[13]]]],[[[120,[13]]],12],[[]],[[]],[[[120,[13]]],19],[[[120,[[0,[24,13]]]]],[[120,[[0,[24,13]]]]]],[[]],[2],[2],[2],[[[120,[13]]]],[[[120,[[0,[44,13]]]],3],4],[[]],[[],2],[[]],[86,[[120,[13]]]],[[[120,[13]]],12],[[[120,[13]]]],[[]],[[],5],[[],5],[[],6],[[]],0,0,[[]],[[]],[[]],[[]],[[[123,[13]]],96],[2],[2],[2],[2],[2],[2],[[[123,[[0,[44,13]]]],3],4],[[[124,[[0,[44,13]]]],3],4],[[]],[[]],[[],2],[[],2],[[]],[[]],[119,[[123,[13]]]],[86,[[124,[13]]]],[[],5],[[],5],[[],5],[[],5],[[],6],[[],6],[[[124,[13]],[120,[13]]],[[5,[114]]]],[[]],[[]],0,0,0,0,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[[122,[[0,[24,13]]]]],[[122,[[0,[24,13]]]]]],[[[125,[[0,[24,13]]]]],[[125,[[0,[24,13]]]]]],[[]],[[]],[[[122,[13]]],13],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[[[126,[13]]],19],[[[127,[13]]],19],[[[122,[[0,[44,13]]]],3],4],[[[125,[[0,[44,13]]]],3],4],[[[126,[[0,[44,13]]]],3],4],[[[127,[[0,[44,13]]]],3],4],[[]],[[]],[[]],[[]],0,[[],2],[[],2],[[],2],[[],2],[[]],[[]],[[]],[[]],[119,[[126,[13]]]],[119,[[127,[13]]]],[[[126,[13]],28],[[5,[34]]]],[[[127,[13]],28],[[5,[34]]]],[[]],[[]],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],6],[[],6],[[],6],[[],6],0,[[[122,[13]]],[[120,[13]]]],[[[122,[13]],13]],[[]],[[]],[[]],[[]],0,0,0,0,0,0,0,[[]],[[]],[[]],[[]],[[[129,[[0,[24,128]]]]],[[129,[[0,[24,128]]]]]],[[]],[[[129,[[0,[128,44]]]],106,117]],[[[129,[[0,[128,44]]]],106,117]],[2],[2],[2],[2],[[[129,[[0,[128,44]]]],7]],[2],[2],[[[129,[[0,[128,44]]]]],[[130,[[0,[128,44]]]]]],[[[129,[[0,[44,128]]]],3],4],[[[131,[[0,[44,128]]]],3],4],[[]],[[]],[[[129,[[0,[128,44]]]]]],[[[129,[[0,[128,44]]]]]],[[],2],[[],2],[[]],[[]],[[[129,[[0,[128,44]]]]],7],[[[129,[[0,[128,44]]]]],118],[7,[[129,[[0,[128,44]]]]]],[7],[[],[[96,[[129,[[0,[128,44]]]]]]]],[1,[[129,[[0,[128,44]]]]]],[[],96],[[[129,[[0,[128,44]]]]]],[[7,25],[[129,[[0,[128,44]]]]]],[[]],[[],5],[[],5],[[],5],[[],5],[[],6],[[],6],[[[129,[[0,[128,44]]]]]],[[]],[[]],[[[129,[[0,[128,44]]]]],96],[[[129,[[0,[128,44]]]],1]],0,0,[[[130,[[0,[128,44]]]],[130,[[0,[128,44]]]]]],[[[133,[[0,[132,44]]]],[133,[[0,[132,44]]]]]],[[[130,[[0,[128,44]]]]]],[[[130,[[0,[128,44]]]]],12],[[]],[[]],[[]],[[]],[[[130,[[0,[128,44]]]]],19],[[[133,[[0,[132,44]]]]],19],[[[130,[[0,[24,128]]]]],[[130,[[0,[24,128]]]]]],[[[133,[[0,[24,128]]]]],[[133,[[0,[24,128]]]]]],[[]],[[]],[[[130,[128]]]],[[],[[130,[[0,[84,128]]]]]],[2],[2],[2],[2],[2],[2],[[[130,[[0,[128,44]]]]]],[[[130,[[0,[44,128]]]],3],4],[[[133,[[0,[44,128]]]],3],4],[[]],[[]],[129,[[133,[[0,[132,44]]]]]],[[],2],[[],2],[[]],[[]],[[],[[130,[128]]]],[129,[[133,[[0,[132,44]]]]]],[[[130,[[0,[128,44]]]]],12],[[[130,[[0,[128,44]]]]]],[[[133,[[0,[132,44]]]]]],[[]],[[]],[[],5],[[],5],[[],5],[[],5],[[],6],[[],6],[[]],[[]],0,0,0,0,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[[134,[[0,[128,44]]]]],96],[[[135,[[0,[128,44]]]]],96],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[2],[[[134,[[0,[44,128]]]],3],4],[[[136,[[0,[44,128]]]],3],4],[[[135,[[0,[44,128]]]],3],4],[[[137,[[0,[44,128]]]],3],4],[[]],[[]],[[]],[[]],[[],2],[[],2],[[],2],[[],2],[[]],[[]],[[]],[[]],[129,[[134,[[0,[128,44]]]]]],[129,136],[129,[[135,[[0,[128,44]]]]]],[129,[[135,[128]]]],[129,137],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],6],[[],6],[[],6],[[],6],[[136,133],[[5,[114]]]],[[137,133],[[5,[114]]]],[[]],[[]],[[]],[[]],0,0,0,[[]],[[]],[[]],[[]],[[]],[[]],[[[138,[[0,[24,132,44]]]]],[[138,[[0,[24,132,44]]]]]],[[[139,[[0,[24,128]]]]],[[139,[[0,[24,128]]]]]],[[[140,[[0,[24,128]]]]],[[140,[[0,[24,128]]]]]],[[]],[[]],[[]],[2],[2],[2],[2],[2],[2],[2],[2],[2],[[[139,[[0,[132,44]]]]],19],[[[140,[[0,[132,44]]]]],19],[[[138,[[0,[44,132,44]]]],3],4],[[[139,[[0,[44,128]]]],3],4],[[[140,[[0,[44,128]]]],3],4],[[]],[[]],[[]],[[],2],[[],2],[[],2],[[]],[[]],[[]],[129,[[139,[[0,[132,44]]]]]],[129,[[139,[[0,[132,44]]]]]],[129,[[140,[[0,[132,44]]]]]],[129,[[140,[[0,[132,44]]]]]],[[[139,[[0,[132,44]]]],28],[[5,[34]]]],[[[140,[[0,[132,44]]]],28],[[5,[34]]]],[[]],[[]],[[]],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],6],[[],6],[[],6],[[]],[[]],[[]],[[[133,[[0,[132,44]]]]],[[139,[[0,[132,44]]]]]],0,0,0,0,0,0,0,0,0,0,0,[[],141],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[[144,[[0,[24,142]],[0,[24,13]],[0,[24,[143,[[0,[24,13]]]]]]]]],[[144,[[0,[24,142]],[0,[24,13]],[0,[24,[143,[[0,[24,13]]]]]]]]]],[[[146,[[0,[24,145]],[0,[24,13]],[0,[24,[143,[[0,[24,13]]]]]]]]],[[146,[[0,[24,145]],[0,[24,13]],[0,[24,[143,[[0,[24,13]]]]]]]]]],[[[141,[[0,[24,13]],24]]],[[141,[[0,[24,13]],24]]]],[[[147,[[0,[24,13]]]]],[[147,[[0,[24,13]]]]]],[[]],[[]],[[]],[[]],[[],96],[[[144,[142,13,[147,[13]]]],13],96],[[[146,[145,13,[147,[13]]]],13],96],[[],96],[[[144,[142,13,[147,[13]]]]],96],[[[146,[145,13,[147,[13]]]]],96],[2],[2],[[[141,[13]]]],[2],[[[147,[13]]]],[2],[2],[2],[2],[2],[2],[2],[2],[2],[[]],[[[146,[145,13,[147,[13]]]]],145],[[[144,[[0,[44,142]],[0,[44,13]],[0,[44,[143,[[0,[44,13]]]]]]]],3],4],[[[146,[[0,[44,145]],[0,[44,13]],[0,[44,[143,[[0,[44,13]]]]]]]],3],4],[[[141,[[0,[44,13]],44]],3],4],[[[147,[[0,[44,13]]]],3],4],[[]],[[]],[[]],[[]],[[]],[[[147,[13]]]],[[]],[[]],[[],2],[142,[[144,[142,13,[147,[13]]]]]],[145,[[146,[145,13,[147,[13]]]]]],[[],2],[[],2],[[],2],[[]],[[]],[[]],[[]],[[]],[[],[[147,[13]]]],[[],96],[[[144,[142,13,[147,[13]]]]],[[96,[13]]]],[[],96],[[[144,[142,13,[147,[13]]]]],96],[[]],[[[144,[142,13,[147,[13]]]]],[[147,[13]]]],[[[146,[145,13,[147,[13]]]]],[[147,[13]]]],[[],141],[[]],[[]],[[]],[[]],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],5],[[],6],[[],6],[[],6],[[],6],[[]],[[]],[[]],[[]],[[],96],[[[146,[145,13,[147,[13]]]],13],96],[[],96],[[[146,[145,13,[147,[13]]]]],96]],"p":[[4,"SerdeFormat"],[15,"usize"],[3,"Formatter"],[6,"Result"],[4,"Result"],[3,"TypeId"],[15,"u32"],[8,"Field"],[3,"Coordinates"],[3,"CtOption"],[15,"u128"],[3,"Vec"],[8,"CurveAffine"],[15,"str"],[8,"Fn"],[3,"Global"],[3,"Box"],[3,"Choice"],[15,"bool"],[8,"IntoIterator"],[8,"FieldExt"],[8,"Send"],[8,"Sync"],[8,"Clone"],[8,"RngCore"],[4,"Assigned"],[3,"Value"],[8,"FnOnce"],[3,"Region"],[3,"Advice"],[3,"Column"],[8,"Into"],[3,"AssignedCell"],[4,"Error"],[3,"Instance"],[3,"Table"],[3,"TableColumn"],[3,"Fixed"],[3,"Cell"],[8,"Layouter"],[3,"NamespacedLayouter"],[3,"RegionIndex"],[3,"RegionStart"],[8,"Debug"],[3,"SimpleFloorPlanner"],[8,"RegionLayouter"],[8,"TableLayouter"],[8,"FromIterator"],[3,"Challenge"],[8,"Neg"],[3,"String"],[4,"Option"],[8,"FnMut"],[3,"RegionShape"],[4,"RegionColumn"],[4,"Ordering"],[3,"Selector"],[4,"Any"],[3,"MockProver"],[8,"Group"],[3,"CircuitGates"],[4,"FailureLocation"],[4,"VerifyFailure"],[3,"Error"],[8,"Iterator"],[3,"Column"],[3,"Region"],[3,"VirtualCell"],[3,"Gate"],[3,"Constraint"],[3,"VirtualCell"],[4,"Expression"],[3,"BatchVerifier"],[15,"u8"],[3,"ConstraintSystem"],[8,"Phase"],[8,"ColumnType"],[3,"FixedQuery"],[3,"AdviceQuery"],[3,"InstanceQuery"],[3,"Gate"],[3,"VerifyingKey"],[3,"ProvingKey"],[8,"Default"],[8,"PartialEq"],[6,"ParamsVerifierIPA"],[3,"PinnedConstraintSystem"],[3,"FirstPhase"],[3,"SecondPhase"],[3,"ThirdPhase"],[3,"Constraint"],[3,"Constraints"],[3,"VirtualCells"],[3,"PinnedVerificationKey"],[3,"Error"],[6,"Result"],[3,"EvaluationDomain"],[8,"Hash"],[3,"Demand"],[3,"Rotation"],[8,"Error"],[8,"CommitmentScheme"],[8,"Verifier"],[8,"VerificationStrategy"],[8,"Basis"],[3,"Polynomial"],[3,"ProverQuery"],[8,"MSM"],[3,"VerifierQuery"],[3,"Coeff"],[3,"LagrangeCoeff"],[3,"ExtendedLagrangeCoeff"],[3,"PinnedEvaluationDomain"],[4,"Error"],[3,"RangeFull"],[3,"RangeFrom"],[3,"Blind"],[15,"u64"],[3,"ParamsIPA"],[3,"MSMIPA"],[3,"IPACommitmentScheme"],[3,"GuardIPA"],[3,"ProverIPA"],[3,"VerifierIPA"],[3,"Accumulator"],[3,"AccumulatorStrategy"],[3,"SingleStrategy"],[8,"Engine"],[3,"ParamsKZG"],[3,"MSMKZG"],[3,"KZGCommitmentScheme"],[8,"MultiMillerLoop"],[3,"DualMSM"],[3,"ProverGWC"],[3,"ProverSHPLONK"],[3,"VerifierGWC"],[3,"VerifierSHPLONK"],[3,"GuardKZG"],[3,"AccumulatorStrategy"],[3,"SingleStrategy"],[3,"ChallengeScalar"],[8,"Read"],[8,"EncodedChallenge"],[3,"Blake2bRead"],[8,"Write"],[3,"Blake2bWrite"],[3,"Challenge255"],[8,"CurveExt"],[8,"Chip"],[13,"Column"],[13,"Selector"],[13,"InRegion"],[13,"OutsideRegion"],[13,"ConstraintNotSatisfied"],[13,"CellNotAssigned"],[13,"Permutation"],[13,"ConstraintPoisoned"],[13,"Lookup"],[8,"Circuit"],[8,"Assignment"],[8,"FloorPlanner"],[13,"Advice"],[13,"Trivial"],[13,"Rational"],[13,"Transcript"],[13,"ColumnNotInPermutation"],[13,"NotEnoughRowsAvailable"],[13,"Constant"],[13,"Selector"],[13,"Fixed"],[13,"Advice"],[13,"Instance"],[13,"Challenge"],[13,"Negated"],[13,"Sum"],[13,"Product"],[13,"Scaled"],[8,"Guard"],[8,"Params"],[8,"ParamsProver"],[8,"Prover"],[8,"Transcript"],[8,"TranscriptWriterBuffer"],[8,"TranscriptReadBuffer"],[8,"TranscriptRead"],[8,"TranscriptWrite"]]},\ +"halo2curves":{"doc":"","t":[16,16,16,18,3,8,8,8,16,18,8,8,18,18,16,16,16,18,18,10,10,10,10,10,14,0,11,11,11,11,11,10,11,10,14,14,14,11,11,10,10,10,11,10,10,10,10,10,10,14,14,14,14,14,14,11,11,11,10,10,10,14,10,0,0,11,0,0,11,11,11,11,11,11,11,11,11,17,3,17,17,17,17,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,17,13,13,17,17,13,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,5,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,11,11,11,11,11,11,11,8,16,16,16,16,16,16,16,8,8,16,8,16,16,16,10,10,10,10,3,3,3,3,3,3,18,18,18,18,18,18,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,0,11,11,11,11,11,11,11,11,11,11,6,6,6,6,6,6,6,6,3,3,3,3,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,11,11,11,11,8,10,10,10,10,10,10],"n":["AffineExt","Base","Base","CURVE_ID","Coordinates","CurveAffine","CurveAffineExt","CurveExt","CurveExt","DELTA","FieldExt","Group","MODULUS","ROOT_OF_UNITY_INV","Scalar","ScalarExt","ScalarExt","TWO_INV","ZETA","a","a","b","b","batch_add","batch_add","bn256","borrow","borrow_mut","clone","clone_into","conditional_select","coordinates","default","endo","field_arithmetic","field_common","field_specific","fmt","from","from_bytes_wide","from_u128","from_xy","from_xy","get_lower_128","group_add","group_scale","group_sub","group_zero","hash_to_curve","impl_add_binop_specify_output","impl_binops_additive","impl_binops_additive_specify_output","impl_binops_multiplicative","impl_binops_multiplicative_mixed","impl_sub_binop_specify_output","into","into_coordinates","into_coordinates","is_on_curve","is_on_curve","jacobian_coordinates","new_curve_impl","new_jacobian","pairing","pasta","pow","secp256k1","serde","to_owned","try_from","try_into","type_id","u","v","vzip","x","y","BN_X","Bn256","FROBENIUS_COEFF_FQ12_C1","FROBENIUS_COEFF_FQ2_C1","FROBENIUS_COEFF_FQ6_C1","FROBENIUS_COEFF_FQ6_C2","Fq","Fq12","Fq2","Fq2Bytes","Fq6","Fr","G1","G1Affine","G1Compressed","G2","G2Affine","G2Compressed","G2Prepared","Gt","LegendreSymbol","NEGATIVE_ONE","QuadraticNonResidue","QuadraticResidue","SIX_U_PLUS_2_NAF","XI_TO_Q_MINUS_1_OVER_2","Zero","a","a","a","a","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","as_bits","as_bits","as_bits","as_mut","as_mut","as_mut","as_mut_bits","as_mut_bits","as_mut_bits","as_ref","as_ref","as_ref","b","b","b","b","batch_add","batch_add","batch_normalize","batch_normalize","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","c0","c0","c0","c1","c1","c1","c2","clear_cofactor","clear_cofactor","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","cmp","cmp","cmp","conditional_negate","conditional_negate","conditional_negate","conditional_negate","conditional_negate","conditional_negate","conditional_negate","conditional_negate","conditional_negate","conditional_negate","conditional_select","conditional_select","conditional_select","conditional_select","conditional_select","conditional_select","conditional_select","conditional_select","conditional_select","conditional_select","conjugate","conjugate","coordinates","coordinates","ct_eq","ct_eq","ct_eq","ct_eq","ct_eq","ct_eq","ct_eq","ct_eq","ct_eq","ct_eq","cyclotomic_square","default","default","default","default","default","default","default","default","default","default","default","default","default","deserialize","deserialize","deserialize","deserialize","deserialize","deserialize","deserialize","deserialize","deserialize","double","double","double","double","double","double","double","double","double","double","double","double","double","double","double_assign","double_assign","double_assign","endo","endo","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","eq","final_exponentiation","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","fmt","frobenius_map","frobenius_map","frobenius_map","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from_affine","from_bytes","from_bytes","from_bytes","from_bytes","from_bytes","from_bytes","from_bytes","from_bytes_unchecked","from_bytes_unchecked","from_bytes_unchecked","from_bytes_unchecked","from_bytes_wide","from_bytes_wide","from_bytes_wide","from_raw","from_raw","from_raw_bytes","from_raw_bytes","from_raw_bytes","from_raw_bytes","from_raw_bytes","from_raw_bytes","from_raw_bytes","from_raw_bytes_unchecked","from_raw_bytes_unchecked","from_raw_bytes_unchecked","from_raw_bytes_unchecked","from_raw_bytes_unchecked","from_raw_bytes_unchecked","from_raw_bytes_unchecked","from_repr","from_repr","from_repr","from_u128","from_u128","from_u128","from_uncompressed","from_uncompressed","from_uncompressed_unchecked","from_uncompressed_unchecked","from_xy","from_xy","generator","generator","generator","generator","generator","generator","generator","generator","generator","generator","generator","get_lower_128","get_lower_128","get_lower_128","get_lower_32","get_lower_32","get_lower_32","group_add","group_add","group_add","group_add","group_add","group_scale","group_scale","group_scale","group_scale","group_scale","group_sub","group_sub","group_sub","group_sub","group_sub","group_zero","group_zero","group_zero","group_zero","group_zero","hash","hash","hash","hash","hash","hash","hash","hash","hash","hash_to_curve","hash_to_curve","identity","identity","identity","identity","identity","identity","identity","identity","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into","into_coordinates","into_coordinates","into_subgroup","into_subgroup","invert","invert","invert","invert","invert","invert","invert","is_identity","is_identity","is_identity","is_identity","is_identity","is_identity","is_identity","is_odd","is_odd","is_odd","is_on_curve","is_on_curve","is_on_curve","is_on_curve","is_torsion_free","is_torsion_free","is_zero","is_zero","is_zero","is_zero","is_zero_vartime","jacobian_coordinates","jacobian_coordinates","legendre","legendre","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_by_01","mul_by_014","mul_by_034","mul_by_1","mul_by_nonresidue","mul_by_nonresidue","mul_by_v","mul_by_xi","multi_miller_loop","multi_miller_loop","multiplicative_generator","multiplicative_generator","multiplicative_generator","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","new","new_jacobian","new_jacobian","norm","one","one","one","one","one","one","one","pairing","pairing","pairing_with","pairing_with","partial_cmp","partial_cmp","partial_cmp","pow_by_t_minus1_over2","random","random","random","random","random","random","random","random","random","random","read_raw","read_raw","read_raw","read_raw","read_raw","read_raw","read_raw","read_raw_unchecked","read_raw_unchecked","read_raw_unchecked","read_raw_unchecked","read_raw_unchecked","read_raw_unchecked","read_raw_unchecked","root_of_unity","root_of_unity","root_of_unity","serialize","serialize","serialize","serialize","serialize","serialize","serialize","serialize","serialize","size","size","sqrt","sqrt","sqrt","sqrt","sqrt","square","square","square","square","square","square","square","square","square","square","square_assign","square_assign","square_assign","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sum","sum","sum","to_affine","to_affine","to_bytes","to_bytes","to_bytes","to_bytes","to_bytes","to_bytes","to_bytes","to_curve","to_curve","to_curve","to_curve","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_raw_bytes","to_raw_bytes","to_raw_bytes","to_raw_bytes","to_raw_bytes","to_raw_bytes","to_raw_bytes","to_repr","to_repr","to_repr","to_string","to_uncompressed","to_uncompressed","try_as_bits","try_as_bits","try_as_bits","try_as_mut_bits","try_as_mut_bits","try_as_mut_bits","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","vzip","write_raw","write_raw","write_raw","write_raw","write_raw","write_raw","write_raw","x","x","x","x","y","y","y","y","z","z","zero","zero","zero","zero","zero","zero","zero","Engine","G1","G1Affine","G2","G2Affine","G2Prepared","Gt","Gt","MillerLoopResult","MultiMillerLoop","Pair","PairingCurveAffine","PairingResult","Result","Scalar","final_exponentiation","multi_miller_loop","pairing","pairing_with","Ep","EpAffine","Eq","EqAffine","Fp","Fq","ISOGENY_CONSTANTS","ISOGENY_CONSTANTS","THETA","THETA","Z","Z","a","a","a","a","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","b","b","b","b","batch_normalize","batch_normalize","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","char_le_bits","char_le_bits","clear_cofactor","clear_cofactor","clone","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","cmp","cmp","conditional_negate","conditional_negate","conditional_negate","conditional_negate","conditional_negate","conditional_negate","conditional_select","conditional_select","conditional_select","conditional_select","conditional_select","conditional_select","coordinates","coordinates","ct_eq","ct_eq","ct_eq","ct_eq","ct_eq","ct_eq","default","default","default","default","default","default","double","double","double","double","double","double","endo","endo","eq","eq","eq","eq","eq","eq","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from_bytes","from_bytes","from_bytes","from_bytes","from_bytes_unchecked","from_bytes_unchecked","from_bytes_unchecked","from_bytes_unchecked","from_bytes_wide","from_bytes_wide","from_raw","from_raw","from_repr","from_repr","from_u128","from_u128","from_xy","from_xy","generator","generator","generator","generator","generator","generator","get_lower_128","get_lower_128","get_lower_32","get_lower_32","group_add","group_add","group_add","group_add","group_scale","group_scale","group_scale","group_scale","group_sub","group_sub","group_sub","group_sub","group_zero","group_zero","group_zero","group_zero","hash_to_curve","hash_to_curve","identity","identity","identity","identity","identity","identity","into","into","into","into","into","into","into_subgroup","into_subgroup","invert","invert","is_identity","is_identity","is_identity","is_identity","is_identity","is_identity","is_odd","is_odd","is_on_curve","is_on_curve","is_on_curve","is_on_curve","is_torsion_free","is_torsion_free","jacobian_coordinates","jacobian_coordinates","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","multiplicative_generator","multiplicative_generator","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","new_jacobian","new_jacobian","one","one","one","one","pallas","partial_cmp","partial_cmp","pow_by_t_minus1_over2","pow_by_t_minus1_over2","pow_vartime","pow_vartime","random","random","random","random","recommended_wnaf_for_num_scalars","recommended_wnaf_for_num_scalars","root_of_unity","root_of_unity","sqrt","sqrt","sqrt_alt","sqrt_alt","sqrt_ratio","sqrt_ratio","square","square","square","square","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sum","sum","to_affine","to_affine","to_bytes","to_bytes","to_bytes","to_bytes","to_curve","to_curve","to_curve","to_curve","to_le_bits","to_le_bits","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","to_repr","to_repr","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","vesta","vzip","vzip","vzip","vzip","vzip","vzip","zero","zero","zero","zero","Affine","Base","Point","Scalar","Affine","Base","Point","Scalar","Fp","Fq","Secp256k1","Secp256k1Affine","Secp256k1Compressed","a","a","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","add_assign","as_bits","as_mut","as_mut_bits","as_ref","b","b","batch_add","batch_normalize","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clear_cofactor","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","cmp","cmp","conditional_negate","conditional_negate","conditional_negate","conditional_negate","conditional_select","conditional_select","conditional_select","conditional_select","coordinates","ct_eq","ct_eq","ct_eq","ct_eq","default","default","default","default","default","deserialize","deserialize","deserialize","deserialize","double","double","double","double","double","endo","eq","eq","eq","eq","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from","from_bytes","from_bytes","from_bytes","from_bytes","from_bytes_unchecked","from_bytes_unchecked","from_bytes_wide","from_bytes_wide","from_raw","from_raw","from_raw_bytes","from_raw_bytes","from_raw_bytes","from_raw_bytes","from_raw_bytes_unchecked","from_raw_bytes_unchecked","from_raw_bytes_unchecked","from_raw_bytes_unchecked","from_repr","from_repr","from_u128","from_u128","from_xy","generator","generator","generator","generator","generator","get_lower_128","get_lower_128","get_lower_32","get_lower_32","group_add","group_add","group_add","group_scale","group_scale","group_scale","group_sub","group_sub","group_sub","group_zero","group_zero","group_zero","hash","hash","hash","hash","hash_to_curve","identity","identity","identity","into","into","into","into","into","into_coordinates","into_subgroup","invert","invert","is_identity","is_identity","is_identity","is_odd","is_odd","is_on_curve","is_on_curve","is_torsion_free","jacobian_coordinates","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","mul_assign","multiplicative_generator","multiplicative_generator","neg","neg","neg","neg","neg","neg","neg","neg","neg","neg","new_jacobian","one","one","one","one","partial_cmp","partial_cmp","pow_vartime","pow_vartime","random","random","random","random","read_raw","read_raw","read_raw","read_raw","read_raw_unchecked","read_raw_unchecked","read_raw_unchecked","read_raw_unchecked","root_of_unity","root_of_unity","serialize","serialize","serialize","serialize","size","size","sqrt","sqrt","square","square","square","square","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sub_assign","sum","to_affine","to_bytes","to_bytes","to_bytes","to_bytes","to_curve","to_curve","to_owned","to_owned","to_owned","to_owned","to_owned","to_raw_bytes","to_raw_bytes","to_raw_bytes","to_raw_bytes","to_repr","to_repr","try_as_bits","try_as_mut_bits","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","vzip","vzip","vzip","vzip","vzip","write_raw","write_raw","write_raw","write_raw","x","x","y","y","z","zero","zero","zero","zero","SerdeObject","from_raw_bytes","from_raw_bytes_unchecked","read_raw","read_raw_unchecked","to_raw_bytes","write_raw"],"q":["halo2curves","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2curves::bn256","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2curves::pairing","","","","","","","","","","","","","","","","","","","halo2curves::pasta","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2curves::pasta::pallas","","","","halo2curves::pasta::vesta","","","","halo2curves::secp256k1","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","halo2curves::serde","","","","","",""],"d":["The affine version of the curve","The base field over which this elliptic curve is …","The base field over which this elliptic curve is …","CURVE_ID used for hash-to-curve.","The affine coordinates of a point on an elliptic curve.","This trait is the affine counterpart to Curve and is used …","","This trait is a common interface for dealing with elements …","The projective form of the curve","Generator of the $t-order$ multiplicative subgroup","This trait is a common interface for dealing with elements …","This represents an element of a group with basic …","Modulus of the field written as a string for display …","Inverse of PrimeField::root_of_unity()","The group is assumed to be of prime order $p$. Scalar is …","The scalar field of this elliptic curve.","The scalar field of this elliptic curve.","Inverse of $2$ in the field.","Element of multiplicative order $3$.","Returns the curve constant a.","Returns the curve constant $a$.","Returns the curve constant b.","Returns the curve constant $b$.","","","","","","","","","Gets the coordinates of this point.","","Apply the curve endomorphism by multiplying the …","","","","","Returns the argument unchanged.","Obtains a field element that is congruent to the provided …","Obtains a field element congruent to the integer v.","Obtains a point given $(x, y)$, failing if it is not on the","Obtains a Coordinates value given $(x, y)$, failing if it …","Gets the lower 128 bits of this field element when …","Adds rhs to this group element.","Scales this group element by a scalar.","Subtracts rhs from this group element.","Returns the additive identity of the group.","Requests a hasher that accepts messages and returns …","","","","","","","Calls U::from(self).","Unlike the Coordinates trait, this just returns the raw …","Unlike the Coordinates trait, this just returns the raw …","Returns whether or not this element is on the curve; should","Returns whether or not this element is on the curve; should","Return the Jacobian coordinates of this point.","","Obtains a point given Jacobian coordinates $X : Y : Z$, …","","","Exponentiates self by by, where by is a little-endian order","","","","","","","Returns the u-coordinate.","Returns the v-coordinate.","","Returns the x-coordinate.","Returns the y-coordinate.","","","","","","","This represents an element of $\\\\mathbb{F}_q$ where","","An element of Fq2, represented by c0 + c1 * u.","","","This represents an element of $\\\\mathbb{F}_r$ where","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Adds rhs to self, returning the result.","","","","","","","","","","","","","","","","","Adds rhs to self, returning the result.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Doubles this group element.","Doubles this field element.","","","","","","","","","Doubles this field element.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns the argument unchanged.","","","Returns the argument unchanged.","","","Returns the argument unchanged.","","Returns the argument unchanged.","","","Returns the argument unchanged.","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","","Returns the argument unchanged.","","","","Returns the argument unchanged.","Returns the argument unchanged.","","Returns the argument unchanged.","","Returns the argument unchanged.","Returns the argument unchanged.","","","Returns the argument unchanged.","","Returns the argument unchanged.","","","","","","Attempts to convert a little-endian byte representation of …","Attempts to convert a little-endian byte representation of …","Attempts to convert a little-endian byte representation of …","","","","","Converts a 512-bit little endian integer into a $field by …","Converts a 512-bit little endian integer into a Fq by …","Converts a 512-bit little endian integer into a $field by …","Converts from an integer represented in little endian into …","Converts from an integer represented in little endian into …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns the group identity, which is $1$.","","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","","","","","Computes the multiplicative inverse of this element, …","","","","","","Computes the multiplicative inverse of this element, …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Multiplies rhs by self, returning the result.","","","","","","","","","","","","","","","","Multiplies rhs by self, returning the result.","","","","","","","","","","","","","","","","","","","","","","","","","","","","Multiply this element by quadratic nonresidue 9 + u.","Multiply by cubic nonresidue v.","Multiply by cubic nonresidue v.","","","","","","","","","","","","","","","","","","","Negates self.","","","","","","","","","","","","Negates self.","","","","Norm of Fq2 as extension field in i over Fq","Returns one, the multiplicative identity.","","","","","","Returns one, the multiplicative identity.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Computes the square root of this element, if it exists.","","","","Computes the square root of this element, if it exists.","","Squares this element.","","","","","","","Squares this element.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Subtracts rhs from self, returning the result.","","","","","","","","","","","","","","","","","","Subtracts rhs from self, returning the result.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Converts an element of Fr into a byte representation in …","Converts an element of Fq into a byte representation in …","Converts an element of Fr into a byte representation in …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns zero, the additive identity.","","","","","Returns zero, the additive identity.","","","The projective representation of an element in G1.","The affine representation of an element in G1.","The projective representation of an element in G2.","The affine representation of an element in G2.","The prepared form of Self::G2Affine.","The extension field that hosts the target group of the …","The extension field that hosts the target group of the …","Represents results of a Miller loop, one of the most …","An engine that can compute sums of pairings in an …","","Affine representation of an elliptic curve point that can …","","The type returned by Engine::miller_loop.","This is the scalar field of the engine’s groups.","This performs a “final exponentiation” routine to …","Computes $$\\\\sum_{i=1}^n \\\\textbf{ML}(a_i, b_i)$$ given a …","Invoke the pairing function G1 x G2 -> Gt without the use …","Perform a pairing","Represents a point in the projective coordinate space.","Represents a point in the affine coordinate space (or the …","Represents a point in the projective coordinate space.","Represents a point in the affine coordinate space (or the …","This represents an element of $\\\\mathbb{F}_p$ where","This represents an element of $\\\\mathbb{F}_q$ where","Constants used for computing the isogeny from IsoEp to Ep.","Constants used for computing the isogeny from IsoEq to Eq.","(F::root_of_unity().invert().unwrap() * z).sqrt().unwrap()","(F::root_of_unity().invert().unwrap() * z).sqrt().unwrap()","Z = -13","Z = -13","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Adds rhs to self, returning the result.","","","","Adds rhs to self, returning the result.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Doubles this field element.","Doubles this field element.","","Apply the curve endomorphism by multiplying the …","Apply the curve endomorphism by multiplying the …","","","","","","","","","","","","","Returns the argument unchanged.","","","Returns the argument unchanged.","","","","Returns the argument unchanged.","","Returns the argument unchanged.","","","Returns the argument unchanged.","","","Returns the argument unchanged.","","","","","","","","","","","Converts a 512-bit little endian integer into a Fp by …","Converts a 512-bit little endian integer into a Fq by …","Converts from an integer represented in little endian into …","Converts from an integer represented in little endian into …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","","","Computes the multiplicative inverse of this element, …","Computes the multiplicative inverse of this element, …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Multiplies rhs by self, returning the result.","","","","","Multiplies rhs by self, returning the result.","","","","","","","","","","","","","","","","","","","","Negates self.","","","Negates self.","","","","","Returns one, the multiplicative identity.","","","Returns one, the multiplicative identity.","The Pallas and iso-Pallas elliptic curve groups.","","","","","","","","","","","","","","","Computes the square root of this element, if it exists.","Computes the square root of this element, if it exists.","","","","","Squares this element.","","Squares this element.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Subtracts rhs from self, returning the result.","","","","","","","","","Subtracts rhs from self, returning the result.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","The Vesta and iso-Vesta elliptic curve groups.","","","","","","","Returns zero, the additive identity.","","Returns zero, the additive identity.","","A Pallas point in the affine coordinate space (or the …","The base field of the Pallas and iso-Pallas curves.","A Pallas point in the projective coordinate space.","The scalar field of the Pallas and iso-Pallas curves.","A Vesta point in the affine coordinate space (or the point …","The base field of the Vesta and iso-Vesta curves.","A Vesta point in the projective coordinate space.","The scalar field of the Vesta and iso-Vesta curves.","This represents an element of $\\\\mathbb{F}_p$ where","This represents an element of $\\\\mathbb{F}_q$ where","","","","","","","","","","","","","","","","","","","","","","","","","","Adds rhs to self, returning the result.","","","Adds rhs to self, returning the result.","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Doubles this field element.","","Doubles this field element.","","","","","","","","","","","","Returns the argument unchanged.","","","","Returns the argument unchanged.","","Returns the argument unchanged.","","","","Returns the argument unchanged.","Returns the argument unchanged.","","","","","","Attempts to convert a little-endian byte representation of …","Attempts to convert a little-endian byte representation of …","","","Converts a 512-bit little endian integer into a $field by …","Converts a 512-bit little endian integer into a $field by …","Converts from an integer represented in little endian into …","Converts from an integer represented in little endian into …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","","","Computes the multiplicative inverse of this element, …","Computes the multiplicative inverse of this element, …","","","","","","","","","","","","","","","","","","","","","","Multiplies rhs by self, returning the result.","Multiplies rhs by self, returning the result.","","","","","","","","","","","","","","","","","","Negates self.","","Negates self.","","","","Returns one, the multiplicative identity.","","Returns one, the multiplicative identity.","","","","","","","","","","","","","","","","","","","","","","","","","","Computes the square root of this element, if it exists.","Computes the square root of this element, if it exists.","","Squares this element.","","Squares this element.","","","","","","","","","","","","","","","","","Subtracts rhs from self, returning the result.","","","","","","","","","Subtracts rhs from self, returning the result.","","","","","","","","","","","","","Converts an element of Fr into a byte representation in …","Converts an element of Fr into a byte representation in …","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","Returns zero, the additive identity.","","","Returns zero, the additive identity.","Trait for converting raw bytes to/from the internal …","","The purpose of unchecked functions is to read the internal …","","The purpose of unchecked functions is to read the internal …","",""],"i":[57,57,58,57,0,0,0,0,58,59,0,0,59,59,60,57,58,59,59,57,58,57,58,61,0,0,2,2,2,2,2,58,2,57,0,0,0,2,2,59,59,58,2,59,60,60,60,60,57,0,0,0,0,0,0,2,61,61,57,58,57,0,57,0,0,59,0,0,2,2,2,2,2,2,2,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,32,0,0,32,14,15,16,17,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,18,18,18,18,19,19,19,19,19,20,20,20,20,20,21,21,21,21,21,22,22,22,22,22,23,23,23,23,23,14,14,14,14,16,16,16,16,18,18,19,19,20,20,21,21,22,22,23,23,25,26,27,25,26,27,25,26,27,25,26,27,14,15,16,17,15,17,14,16,14,15,25,16,17,26,18,28,29,19,20,21,27,22,23,32,14,15,25,16,17,26,18,28,29,19,20,21,27,22,23,32,20,21,22,20,21,22,22,14,16,14,15,25,16,17,26,18,28,29,19,20,21,27,22,23,14,15,25,16,17,26,18,28,29,19,20,21,27,22,23,19,21,23,14,15,16,17,18,19,20,21,22,23,14,15,16,17,18,19,20,21,22,23,20,21,15,17,14,15,16,17,18,19,20,21,22,23,20,14,15,25,16,17,26,18,19,20,21,27,22,23,14,15,16,17,19,20,21,22,23,14,16,18,18,19,19,20,20,21,21,22,22,23,23,20,21,22,14,16,14,15,16,17,18,19,20,21,22,23,32,18,14,15,25,16,17,26,18,18,28,29,19,20,21,27,22,23,32,20,21,22,14,14,14,15,15,15,25,16,16,16,17,17,17,26,18,28,28,29,19,19,19,19,20,21,21,21,27,22,23,23,23,23,32,28,14,15,16,17,19,21,23,14,15,16,17,19,21,23,19,23,14,15,16,17,19,21,23,14,15,16,17,19,21,23,19,21,23,19,21,23,15,17,15,17,15,17,14,14,15,15,15,16,16,17,17,17,18,19,21,23,19,21,23,14,16,19,21,23,14,16,19,21,23,14,16,19,21,23,14,16,19,21,23,15,25,17,26,19,20,21,22,23,14,16,14,15,15,16,17,17,18,18,14,15,25,16,17,26,18,28,29,19,20,21,27,22,23,32,15,17,14,16,19,20,20,21,21,22,23,14,15,15,16,17,17,18,19,21,23,14,15,16,17,14,16,28,20,21,22,23,14,16,19,21,14,14,14,14,15,15,15,15,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,19,20,20,20,20,20,21,21,21,21,21,22,22,22,22,22,23,23,23,23,23,14,14,16,16,18,18,19,19,20,20,20,21,21,21,22,22,22,23,23,22,20,20,22,21,22,22,21,0,29,19,21,23,14,14,15,15,16,16,17,17,18,18,19,19,19,20,20,20,21,21,21,22,22,22,23,23,23,21,14,16,21,19,19,20,21,22,23,23,0,29,15,17,19,21,23,21,14,15,16,17,18,19,20,21,22,23,14,15,16,17,19,21,23,14,15,16,17,19,21,23,19,21,23,14,15,16,17,19,20,21,22,23,19,21,19,20,21,22,23,19,19,20,20,21,21,22,22,23,23,20,21,22,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,18,18,18,18,19,19,19,19,19,20,20,20,20,20,21,21,21,21,21,22,22,22,22,22,23,23,23,23,23,14,14,14,14,16,16,16,16,18,18,19,19,20,20,21,21,22,22,23,23,14,16,18,14,16,14,15,16,17,19,21,23,15,15,17,17,14,15,25,16,17,26,18,28,29,19,20,21,27,22,23,14,15,16,17,19,21,23,19,21,23,18,15,17,25,26,27,25,26,27,14,15,25,16,17,26,18,28,29,19,20,21,27,22,23,32,14,15,25,16,17,26,18,28,29,19,20,21,27,22,23,32,14,15,25,16,17,26,18,28,29,19,20,21,27,22,23,32,14,15,25,16,17,26,18,28,29,19,20,21,27,22,23,32,14,15,16,17,19,21,23,14,15,16,17,14,15,16,17,14,16,19,19,20,21,22,23,23,0,62,62,62,62,63,62,64,0,0,65,0,65,63,62,64,63,62,65,0,0,0,0,0,0,43,45,43,45,43,45,43,44,45,46,43,43,43,43,43,43,43,43,44,44,44,44,44,44,44,44,45,45,45,45,45,45,45,45,46,46,46,46,46,46,46,46,47,47,47,47,47,48,48,48,48,48,43,43,43,43,45,45,45,45,47,47,48,48,43,44,45,46,43,45,43,44,45,46,47,48,43,44,45,46,47,48,47,48,43,45,43,44,45,46,47,48,43,44,45,46,47,48,47,48,43,44,45,46,47,48,43,44,45,46,47,48,44,46,43,44,45,46,47,48,43,44,45,46,47,48,43,45,47,47,48,48,43,45,43,44,45,46,47,48,43,44,45,46,47,48,43,43,43,44,44,44,45,45,45,46,46,46,47,47,47,48,48,48,43,44,45,46,43,44,45,46,47,48,47,48,47,48,47,48,44,46,43,44,44,45,46,46,47,48,47,48,43,45,47,48,43,45,47,48,43,45,47,48,43,45,47,48,43,45,43,44,44,45,46,46,43,44,45,46,47,48,43,45,47,48,43,44,44,45,46,46,47,48,43,44,45,46,43,45,43,45,43,43,43,43,44,44,44,44,45,45,45,45,46,46,46,46,47,47,47,47,47,48,48,48,48,48,43,43,45,45,47,47,48,48,47,48,43,43,44,44,45,45,46,46,47,47,47,48,48,48,43,45,47,47,48,48,0,47,48,47,48,47,48,43,45,47,48,43,45,47,48,47,48,47,48,47,48,47,47,48,48,43,43,43,43,43,43,43,43,44,44,44,44,44,44,44,44,45,45,45,45,45,45,45,45,46,46,46,46,46,46,46,46,47,47,47,47,47,48,48,48,48,48,43,43,43,43,45,45,45,45,47,47,48,48,43,45,43,45,43,44,45,46,44,44,46,46,47,48,43,44,45,46,47,48,47,48,43,44,45,46,47,48,43,44,45,46,47,48,43,44,45,46,47,48,0,43,44,45,46,47,48,47,47,48,48,0,0,0,0,0,0,0,0,0,0,0,0,0,51,52,51,51,51,51,51,51,51,51,52,52,52,52,52,52,52,52,53,53,53,53,53,54,54,54,54,54,51,51,51,51,53,53,54,54,55,55,55,55,51,52,52,51,51,52,55,53,54,51,52,55,53,54,51,51,52,55,53,54,51,52,55,53,54,53,54,51,52,53,54,51,52,53,54,52,51,52,53,54,51,52,55,53,54,51,52,53,54,51,53,53,54,54,51,51,52,53,54,51,52,55,53,54,51,51,51,52,52,52,55,53,53,53,53,54,54,54,54,51,52,53,54,51,52,53,54,53,54,51,52,53,54,51,52,53,54,53,54,53,54,52,51,51,52,52,52,53,54,53,54,51,53,54,51,53,54,51,53,54,51,53,54,52,55,53,54,51,51,52,52,51,52,55,53,54,52,51,53,54,51,52,52,53,54,51,52,51,51,51,51,51,51,52,52,52,52,53,53,53,53,53,54,54,54,54,54,51,51,53,53,54,54,53,54,51,51,52,52,53,53,53,54,54,54,51,53,53,54,54,53,54,53,54,51,52,53,54,51,52,53,54,51,52,53,54,53,54,51,52,53,54,53,54,53,54,53,53,54,54,51,51,51,51,51,51,51,51,52,52,52,52,52,52,52,52,53,53,53,53,53,54,54,54,54,54,51,51,51,51,53,53,54,54,51,51,51,52,53,54,52,52,51,52,55,53,54,51,52,53,54,53,54,55,55,51,52,55,53,54,51,52,55,53,54,51,52,55,53,54,51,52,55,53,54,51,52,53,54,51,52,51,52,51,53,53,54,54,0,66,66,66,66,66,66],"f":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,[[]],[[]],[[]],[[]],[[1,1]],0,0,[[]],[[]],[2,2],[[]],[[2,2,3],2],[[],[[4,[2]]]],[[],2],[[]],0,0,0,[[2,5],[[7,[6]]]],[[]],[[]],[8],[[],4],[[],[[4,[2]]]],[[],8],[[]],[[]],[[]],[[]],[9,[[12,[10,11]]]],0,0,0,0,0,0,[[]],[[]],[[]],[[],3],[[],3],[[]],0,[[],4],0,0,[[]],0,0,[[]],[[],7],[[],7],[[],13],[2],[2],[[]],[2],[2],0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,[[]],[[]],[[]],[[]],[[14,15],14],[[14,14],14],[[14,14],14],[[14,15],14],[[14,15],14],[[14,14],14],[[14,15],14],[[14,14],14],[[15,14],14],[[15,14],14],[[15,15],14],[[15,14],14],[[15,14],14],[[15,15],14],[[15,15],14],[[15,15],14],[[16,17],16],[[16,16],16],[[16,16],16],[[16,16],16],[[16,16],16],[[16,17],16],[[16,17],16],[[16,17],16],[[17,16],16],[[17,17],16],[[17,16],16],[[17,16],16],[[17,17],16],[[17,16],16],[[17,17],16],[[17,17],16],[[18,18],18],[[18,18],18],[[18,18],18],[[18,18],18],[[19,19],19],[[19,19],19],[[19,19],19],[[19,19],19],[[19,19],19],[[20,20],20],[[20,20],20],[[20,20],20],[[20,20],20],[[20,20],20],[[21,21],21],[[21,21],21],[[21,21],21],[[21,21],21],[[21,21],21],[[22,22],22],[[22,22],22],[[22,22],22],[[22,22],22],[[22,22],22],[[23,23],23],[[23,23],23],[[23,23],23],[[23,23],23],[[23,23],23],[[14,15]],[[14,14]],[[14,14]],[[14,15]],[[16,17]],[[16,16]],[[16,16]],[[16,17]],[[18,18]],[[18,18]],[[19,19]],[[19,19]],[[20,20]],[[20,20]],[[21,21]],[[21,21]],[[22,22]],[[22,22]],[[23,23]],[[23,23]],[[],24],[[],24],[[],24],[25],[26],[27],[[],24],[[],24],[[],24],[25],[26],[27],[[]],[[]],[[]],[[]],[[1,1]],[[1,1]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],0,0,0,0,0,0,0,[14,14],[16,16],[14,14],[15,15],[25,25],[16,16],[17,17],[26,26],[18,18],[28,28],[29,29],[19,19],[20,20],[21,21],[27,27],[22,22],[23,23],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[19,19],30],[[21,21],30],[[23,23],30],[3],[3],[3],[3],[3],[3],[3],[3],[3],[3],[[14,14,3],14],[[15,15,3],15],[[16,16,3],16],[[17,17,3],17],[[18,18,3],18],[[19,19,3],19],[[20,20,3],20],[[21,21,3],21],[[22,22,3],22],[[23,23,3],23],[20],[21],[15,[[4,[[2,[15]]]]]],[17,[[4,[[2,[17]]]]]],[[14,14],3],[[15,15],3],[[16,16],3],[[17,17],3],[[18,18],3],[[19,19],3],[[20,20],3],[[21,21],3],[[22,22],3],[[23,23],3],[20],[[],14],[[],15],[[],25],[[],16],[[],17],[[],26],[[],18],[[],19],[[],20],[[],21],[[],27],[[],22],[[],23],[[],[[7,[14]]]],[[],[[7,[15]]]],[[],[[7,[16]]]],[[],[[7,[17]]]],[[],[[7,[19]]]],[[],[[7,[20]]]],[[],[[7,[21]]]],[[],[[7,[22]]]],[[],[[7,[23]]]],[14,14],[16,16],[18,18],[18,18],[19,19],[19,19],[20,20],[20,20],[21,21],[21,21],[22,22],[22,22],[23,23],[23,23],[20],[21],[22],[14,14],[16,16],[[14,14],31],[[15,15],31],[[16,16],31],[[17,17],31],[[18,18],31],[[19,19],31],[[20,20],31],[[21,21],31],[[22,22],31],[[23,23],31],[[32,32],31],[18,18],[[14,5],33],[[15,5],[[7,[6]]]],[[25,5],33],[[16,5],33],[[17,5],[[7,[6]]]],[[26,5],33],[[18,5],33],[[18,5],33],[[28,5],33],[[29,5],33],[[19,5],33],[[20,5],33],[[21,5],33],[[27,5],33],[[22,5],33],[[23,5],33],[[32,5],33],[[20,1]],[[21,1]],[[22,1]],[[]],[15,14],[15,14],[[]],[14,15],[14,15],[[]],[17,16],[[]],[17,16],[16,17],[[]],[16,17],[[]],[[]],[[]],[17,28],[[]],[31,19],[[],19],[34,19],[[]],[[]],[31,21],[[]],[34,21],[[]],[[]],[34,23],[31,23],[[]],[[],23],[[]],[17,28],[[],[[4,[14]]]],[[],[[4,[15]]]],[[],[[4,[16]]]],[[],[[4,[17]]]],[[],[[4,[19]]]],[[],[[4,[21]]]],[[],[[4,[23]]]],[[],[[4,[14]]]],[[],[[4,[15]]]],[[],[[4,[16]]]],[[],[[4,[17]]]],[[],19],[[],21],[[],23],[[],19],[[],23],[[],[[35,[14]]]],[[],[[35,[15]]]],[[],[[35,[16]]]],[[],[[35,[17]]]],[[],[[35,[19]]]],[[],[[35,[21]]]],[[],[[35,[23]]]],[[],14],[[],15],[[],16],[[],17],[[],19],[[],21],[[],23],[[],[[4,[19]]]],[[],[[4,[21]]]],[[],[[4,[23]]]],[8,19],[8,21],[8,23],[[],[[4,[15]]]],[[],[[4,[17]]]],[[],[[4,[15]]]],[[],[[4,[17]]]],[[],[[4,[15]]]],[[],[[4,[17]]]],[[],14],[[],14],[[],15],[[],15],[[],15],[[],16],[[],16],[[],17],[[],17],[[],17],[[],18],[19,8],[21,8],[23,8],[19,36],[21,36],[23,36],[[14,14]],[[16,16]],[[19,19]],[[21,21]],[[23,23]],[14],[16],[19],[21],[23],[[14,14]],[[16,16]],[[19,19]],[[21,21]],[[23,23]],[[],14],[[],16],[[],19],[[],21],[[],23],[15],[25],[17],[26],[19],[20],[21],[22],[23],[9,[[12,[10]]]],[9,[[12,[10]]]],[[],14],[[],15],[[],15],[[],16],[[],17],[[],17],[[],18],[[],18],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[15],[17],[14,4],[16,4],[19,[[4,[19]]]],[20,[[4,[20]]]],[20,[[4,[20]]]],[21,[[4,[21]]]],[21,[[4,[21]]]],[22,[[4,[22]]]],[23,[[4,[23]]]],[14,3],[15,3],[15,3],[16,3],[17,3],[17,3],[18,3],[19,3],[21,3],[23,3],[14,3],[15,3],[16,3],[17,3],[14,3],[16,3],[28,31],[20,3],[21,3],[22,3],[23,31],[14],[16],[19,32],[21,32],[[14,23]],[[14,23],14],[[14,23],14],[[14,23],14],[[15,23],14],[[15,23]],[[15,23],14],[[15,23],14],[[16,23],16],[[16,23],16],[[16,23],16],[[16,23]],[[17,23],16],[[17,23],16],[[17,23],16],[[17,23]],[[18,23],18],[[18,23],18],[[18,23],18],[[18,23]],[[19,19],19],[[19,19],19],[[19,19],19],[[19,19],19],[[19,19],19],[[20,20],20],[[20,20],20],[[20,20],20],[[20,20],20],[[20,20],20],[[21,21],21],[[21,21],21],[[21,21],21],[[21,21],21],[[21,21],21],[[22,22],22],[[22,22],22],[[22,22],22],[[22,22],22],[[22,22],22],[[23,23],23],[[23,23],23],[[23,23],23],[[23,23],23],[[23,23],23],[[14,23]],[[14,23]],[[16,23]],[[16,23]],[[18,23]],[[18,23]],[[19,19]],[[19,19]],[[20,20]],[[20,20]],[[20,20]],[[21,21]],[[21,21]],[[21,21]],[[22,22]],[[22,22]],[[22,22]],[[23,23]],[[23,23]],[[22,21,21]],[[20,21,21,21]],[[20,21,21,21]],[[22,21]],[21],[22],[22],[21],[[],18],[[]],[[],19],[[],21],[[],23],[14,14],[14,14],[15,15],[15,15],[16,16],[16,16],[17,17],[17,17],[18,18],[18,18],[19,19],[19,19],[19,19],[20,20],[20,20],[20,20],[21,21],[21,21],[21,21],[22,22],[22,22],[22,22],[23,23],[23,23],[23,23],[[19,19],21],[[],[[4,[14]]]],[[],[[4,[16]]]],[21,19],[[],19],[[],19],[[],20],[[],21],[[],22],[[],23],[[],23],[[15,17],18],[[]],[15],[17],[[19,19],[[35,[30]]]],[[21,21],[[35,[30]]]],[[23,23],[[35,[30]]]],[21,21],[37,14],[37,15],[37,16],[37,17],[37,18],[37,19],[37,20],[37,21],[37,22],[37,23],[[],[[38,[14]]]],[[],[[38,[15]]]],[[],[[38,[16]]]],[[],[[38,[17]]]],[[],[[38,[19]]]],[[],[[38,[21]]]],[[],[[38,[23]]]],[[],14],[[],15],[[],16],[[],17],[[],19],[[],21],[[],23],[[],19],[[],21],[[],23],[14,7],[15,7],[16,7],[17,7],[19,7],[20,7],[21,7],[22,7],[23,7],[[],1],[[],1],[19,[[4,[19]]]],[20,[[4,[20]]]],[21,[[4,[21]]]],[22,[[4,[22]]]],[23,[[4,[23]]]],[19,19],[19,19],[20,20],[20,20],[21,21],[21,21],[22,22],[22,22],[23,23],[23,23],[20],[21],[22],[[14,15],14],[[14,15],14],[[14,15],14],[[14,14],14],[[14,15],14],[[14,14],14],[[14,14],14],[[14,14],14],[[15,15],14],[[15,15],14],[[15,15],14],[[15,14],14],[[15,14],14],[[15,14],14],[[15,15],14],[[15,14],14],[[16,17],16],[[16,16],16],[[16,17],16],[[16,17],16],[[16,16],16],[[16,16],16],[[16,16],16],[[16,17],16],[[17,17],16],[[17,16],16],[[17,16],16],[[17,17],16],[[17,17],16],[[17,16],16],[[17,16],16],[[17,17],16],[[18,18],18],[[18,18],18],[[18,18],18],[[18,18],18],[[19,19],19],[[19,19],19],[[19,19],19],[[19,19],19],[[19,19],19],[[20,20],20],[[20,20],20],[[20,20],20],[[20,20],20],[[20,20],20],[[21,21],21],[[21,21],21],[[21,21],21],[[21,21],21],[[21,21],21],[[22,22],22],[[22,22],22],[[22,22],22],[[22,22],22],[[22,22],22],[[23,23],23],[[23,23],23],[[23,23],23],[[23,23],23],[[23,23],23],[[14,15]],[[14,15]],[[14,14]],[[14,14]],[[16,17]],[[16,16]],[[16,17]],[[16,16]],[[18,18]],[[18,18]],[[19,19]],[[19,19]],[[20,20]],[[20,20]],[[21,21]],[[21,21]],[[22,22]],[[22,22]],[[23,23]],[[23,23]],[[],14],[[],16],[[],18],[14],[16],[14],[15],[16],[17],[19],[21],[23],[15],[15],[17],[17],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[14,[[40,[39]]]],[15,[[40,[39]]]],[16,[[40,[39]]]],[17,[[40,[39]]]],[19,[[40,[39]]]],[21,[[40,[39]]]],[23,[[40,[39]]]],[19],[21],[23],[[],41],[15],[17],[[],[[7,[24,42]]]],[[],[[7,[24,42]]]],[[],[[7,[24,42]]]],[[],[[7,[24,42]]]],[[],[[7,[24,42]]]],[[],[[7,[24,42]]]],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],13],[[],13],[[],13],[[],13],[[],13],[[],13],[[],13],[[],13],[[],13],[[],13],[[],13],[[],13],[[],13],[[],13],[[],13],[[],13],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[14,38],[15,38],[16,38],[17,38],[19,38],[21,38],[23,38],0,0,0,0,0,0,0,0,0,0,[[],19],[[],19],[[],20],[[],21],[[],22],[[],23],[[],23],0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,[[]],[[]],[[]],[[]],0,0,0,0,0,0,0,0,0,0,0,0,[[]],[[]],[[]],[[]],[[43,44],43],[[43,43],43],[[43,43],43],[[43,44],43],[[43,43],43],[[43,44],43],[[43,43],43],[[43,44],43],[[44,44],43],[[44,43],43],[[44,44],43],[[44,43],43],[[44,44],43],[[44,43],43],[[44,43],43],[[44,44],43],[[45,46],45],[[45,46],45],[[45,45],45],[[45,46],45],[[45,45],45],[[45,45],45],[[45,45],45],[[45,46],45],[[46,45],45],[[46,46],45],[[46,45],45],[[46,45],45],[[46,46],45],[[46,46],45],[[46,45],45],[[46,46],45],[[47,47],47],[[47,47],47],[[47,47],47],[[47,47],47],[[47,47],47],[[48,48],48],[[48,48],48],[[48,48],48],[[48,48],48],[[48,48],48],[[43,44]],[[43,44]],[[43,43]],[[43,43]],[[45,46]],[[45,45]],[[45,46]],[[45,45]],[[47,47]],[[47,47]],[[48,48]],[[48,48]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[],[[50,[49]]]],[[],[[50,[49]]]],[43,43],[45,45],[43,43],[44,44],[45,45],[46,46],[47,47],[48,48],[[]],[[]],[[]],[[]],[[]],[[]],[[47,47],30],[[48,48],30],[3],[3],[3],[3],[3],[3],[[43,43,3],43],[[44,44,3],44],[[45,45,3],45],[[46,46,3],46],[[47,47,3],47],[[48,48,3],48],[44,[[4,[[2,[44]]]]]],[46,[[4,[[2,[46]]]]]],[[43,43],3],[[44,44],3],[[45,45],3],[[46,46],3],[[47,47],3],[[48,48],3],[[],43],[[],44],[[],45],[[],46],[[],47],[[],48],[43,43],[45,45],[47,47],[47,47],[48,48],[48,48],[43,43],[45,45],[[43,43],31],[[44,44],31],[[45,45],31],[[46,46],31],[[47,47],31],[[48,48],31],[[43,5],[[7,[6]]]],[[44,5],[[7,[6]]]],[[45,5],[[7,[6]]]],[[46,5],[[7,[6]]]],[[47,5],[[7,[6]]]],[[48,5],[[7,[6]]]],[[]],[44,43],[44,43],[[]],[43,44],[43,44],[46,45],[[]],[46,45],[[]],[45,46],[45,46],[[]],[31,47],[34,47],[[]],[34,48],[31,48],[[],[[4,[43]]]],[[],[[4,[44]]]],[[],[[4,[45]]]],[[],[[4,[46]]]],[[],[[4,[43]]]],[[],[[4,[44]]]],[[],[[4,[45]]]],[[],[[4,[46]]]],[[],47],[[],48],[[],47],[[],48],[[],[[4,[47]]]],[[],[[4,[48]]]],[8,47],[8,48],[[],[[4,[44]]]],[[],[[4,[46]]]],[[],43],[[],44],[[],44],[[],45],[[],46],[[],46],[47,8],[48,8],[47,36],[48,36],[[43,43]],[[45,45]],[[47,47]],[[48,48]],[43],[45],[47],[48],[[43,43]],[[45,45]],[[47,47]],[[48,48]],[[],43],[[],45],[[],47],[[],48],[9,[[12,[10,11]]]],[9,[[12,[10,11]]]],[[],43],[[],44],[[],44],[[],45],[[],46],[[],46],[[]],[[]],[[]],[[]],[[]],[[]],[43,4],[45,4],[47,[[4,[47]]]],[48,[[4,[48]]]],[43,3],[44,3],[44,3],[45,3],[46,3],[46,3],[47,3],[48,3],[43,3],[44,3],[45,3],[46,3],[43,3],[45,3],[43],[45],[[43,48],43],[[43,48]],[[43,48],43],[[43,48],43],[[44,48],43],[[44,48],43],[[44,48]],[[44,48],43],[[45,47],45],[[45,47],45],[[45,47]],[[45,47],45],[[46,47],45],[[46,47],45],[[46,47]],[[46,47],45],[[47,47],47],[[47,47],47],[[47,47],47],[[47,47],47],[[47,47],47],[[48,48],48],[[48,48],48],[[48,48],48],[[48,48],48],[[48,48],48],[[43,48]],[[43,48]],[[45,47]],[[45,47]],[[47,47]],[[47,47]],[[48,48]],[[48,48]],[[],47],[[],48],[43,43],[43,43],[44,44],[44,44],[45,45],[45,45],[46,46],[46,46],[47,47],[47,47],[47,47],[48,48],[48,48],[48,48],[[],[[4,[43]]]],[[],[[4,[45]]]],[[],47],[[],47],[[],48],[[],48],0,[[47,47],[[35,[30]]]],[[48,48],[[35,[30]]]],[47,47],[48,48],[47,47],[48,48],[37,43],[37,45],[37,47],[37,48],[1,1],[1,1],[[],47],[[],48],[47,[[4,[47]]]],[48,[[4,[48]]]],[47],[48],[[47,47]],[[48,48]],[47,47],[47,47],[48,48],[48,48],[[43,43],43],[[43,43],43],[[43,43],43],[[43,44],43],[[43,44],43],[[43,44],43],[[43,43],43],[[43,44],43],[[44,44],43],[[44,44],43],[[44,44],43],[[44,43],43],[[44,43],43],[[44,44],43],[[44,43],43],[[44,43],43],[[45,46],45],[[45,45],45],[[45,45],45],[[45,46],45],[[45,46],45],[[45,45],45],[[45,45],45],[[45,46],45],[[46,45],45],[[46,46],45],[[46,46],45],[[46,46],45],[[46,45],45],[[46,45],45],[[46,46],45],[[46,45],45],[[47,47],47],[[47,47],47],[[47,47],47],[[47,47],47],[[47,47],47],[[48,48],48],[[48,48],48],[[48,48],48],[[48,48],48],[[48,48],48],[[43,43]],[[43,44]],[[43,43]],[[43,44]],[[45,46]],[[45,45]],[[45,45]],[[45,46]],[[47,47]],[[47,47]],[[48,48]],[[48,48]],[[],43],[[],45],[43],[45],[43],[44],[45],[46],[44],[44],[46],[46],[47,[[50,[49]]]],[48,[[50,[49]]]],[[]],[[]],[[]],[[]],[[]],[[]],[47],[48],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],13],[[],13],[[],13],[[],13],[[],13],[[],13],0,[[]],[[]],[[]],[[]],[[]],[[]],[[],47],[[],47],[[],48],[[],48],0,0,0,0,0,0,0,0,0,0,0,0,0,[[]],[[]],[[51,51],51],[[51,52],51],[[51,52],51],[[51,52],51],[[51,51],51],[[51,51],51],[[51,52],51],[[51,51],51],[[52,51],51],[[52,51],51],[[52,51],51],[[52,51],51],[[52,52],51],[[52,52],51],[[52,52],51],[[52,52],51],[[53,53],53],[[53,53],53],[[53,53],53],[[53,53],53],[[53,53],53],[[54,54],54],[[54,54],54],[[54,54],54],[[54,54],54],[[54,54],54],[[51,52]],[[51,52]],[[51,51]],[[51,51]],[[53,53]],[[53,53]],[[54,54]],[[54,54]],[[],24],[55],[[],24],[55],[[]],[[]],[[1,1]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[51,51],[51,51],[52,52],[55,55],[53,53],[54,54],[[]],[[]],[[]],[[]],[[]],[[53,53],30],[[54,54],30],[3],[3],[3],[3],[[51,51,3],51],[[52,52,3],52],[[53,53,3],53],[[54,54,3],54],[52,[[4,[[2,[52]]]]]],[[51,51],3],[[52,52],3],[[53,53],3],[[54,54],3],[[],51],[[],52],[[],55],[[],53],[[],54],[[],[[7,[51]]]],[[],[[7,[52]]]],[[],[[7,[53]]]],[[],[[7,[54]]]],[51,51],[53,53],[53,53],[54,54],[54,54],[51,51],[[51,51],31],[[52,52],31],[[53,53],31],[[54,54],31],[[51,5],33],[[52,5],[[7,[6]]]],[[55,5],33],[[53,5],33],[[54,5],33],[[]],[52,51],[52,51],[51,52],[[]],[51,52],[[]],[[],53],[34,53],[31,53],[[]],[[]],[[],54],[34,54],[31,54],[[],[[4,[51]]]],[[],[[4,[52]]]],[[],[[4,[53]]]],[[],[[4,[54]]]],[[],[[4,[51]]]],[[],[[4,[52]]]],[[],53],[[],54],[[],53],[[],54],[[],[[35,[51]]]],[[],[[35,[52]]]],[[],[[35,[53]]]],[[],[[35,[54]]]],[[],51],[[],52],[[],53],[[],54],[[],[[4,[53]]]],[[],[[4,[54]]]],[8,53],[8,54],[[],[[4,[52]]]],[[],51],[[],51],[[],52],[[],52],[[],52],[53,8],[54,8],[53,36],[54,36],[[51,51]],[[53,53]],[[54,54]],[51],[53],[54],[[51,51]],[[53,53]],[[54,54]],[[],51],[[],53],[[],54],[52],[55],[53],[54],[9,[[12,[10]]]],[[],51],[[],52],[[],52],[[]],[[]],[[]],[[]],[[]],[52],[51,4],[53,[[4,[53]]]],[54,[[4,[54]]]],[51,3],[52,3],[52,3],[53,3],[54,3],[51,3],[52,3],[51,3],[51],[[51,54],51],[[51,54],51],[[51,54],51],[[51,54]],[[52,54],51],[[52,54],51],[[52,54],51],[[52,54]],[[53,53],53],[[53,53],53],[[53,53],53],[[53,53],53],[[53,53],53],[[54,54],54],[[54,54],54],[[54,54],54],[[54,54],54],[[54,54],54],[[51,54]],[[51,54]],[[53,53]],[[53,53]],[[54,54]],[[54,54]],[[],53],[[],54],[51,51],[51,51],[52,52],[52,52],[53,53],[53,53],[53,53],[54,54],[54,54],[54,54],[[],[[4,[51]]]],[[],53],[[],53],[[],54],[[],54],[[53,53],[[35,[30]]]],[[54,54],[[35,[30]]]],[[53,56],53],[[54,56],54],[37,51],[37,52],[37,53],[37,54],[[],[[38,[51]]]],[[],[[38,[52]]]],[[],[[38,[53]]]],[[],[[38,[54]]]],[[],51],[[],52],[[],53],[[],54],[[],53],[[],54],[51,7],[52,7],[53,7],[54,7],[[],1],[[],1],[53,[[4,[53]]]],[54,[[4,[54]]]],[53,53],[53,53],[54,54],[54,54],[[51,51],51],[[51,52],51],[[51,52],51],[[51,52],51],[[51,51],51],[[51,51],51],[[51,52],51],[[51,51],51],[[52,52],51],[[52,51],51],[[52,51],51],[[52,51],51],[[52,52],51],[[52,52],51],[[52,52],51],[[52,51],51],[[53,53],53],[[53,53],53],[[53,53],53],[[53,53],53],[[53,53],53],[[54,54],54],[[54,54],54],[[54,54],54],[[54,54],54],[[54,54],54],[[51,52]],[[51,51]],[[51,51]],[[51,52]],[[53,53]],[[53,53]],[[54,54]],[[54,54]],[[],51],[51],[51],[52],[53],[54],[52],[52],[[]],[[]],[[]],[[]],[[]],[51,[[40,[39]]]],[52,[[40,[39]]]],[53,[[40,[39]]]],[54,[[40,[39]]]],[53],[54],[[],[[7,[24,42]]]],[[],[[7,[24,42]]]],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],7],[[],13],[[],13],[[],13],[[],13],[[],13],[[]],[[]],[[]],[[]],[[]],[51,38],[52,38],[53,38],[54,38],0,0,0,0,0,[[],53],[[],53],[[],54],[[],54],0,[[],35],[[]],[[],38],[[]],[[],[[40,[39]]]],[[],38]],"p":[[15,"usize"],[3,"Coordinates"],[3,"Choice"],[3,"CtOption"],[3,"Formatter"],[3,"Error"],[4,"Result"],[15,"u128"],[15,"str"],[8,"Fn"],[3,"Global"],[3,"Box"],[3,"TypeId"],[3,"G1"],[3,"G1Affine"],[3,"G2"],[3,"G2Affine"],[3,"Gt"],[3,"Fq"],[3,"Fq12"],[3,"Fq2"],[3,"Fq6"],[3,"Fr"],[3,"BitSlice"],[3,"G1Compressed"],[3,"G2Compressed"],[3,"Fq2Bytes"],[3,"G2Prepared"],[3,"Bn256"],[4,"Ordering"],[15,"bool"],[4,"LegendreSymbol"],[6,"Result"],[15,"u64"],[4,"Option"],[15,"u32"],[8,"RngCore"],[6,"Result"],[15,"u8"],[3,"Vec"],[3,"String"],[4,"BitSpanError"],[3,"Ep"],[3,"EpAffine"],[3,"Eq"],[3,"EqAffine"],[3,"Fp"],[3,"Fq"],[3,"Lsb0"],[3,"BitArray"],[3,"Secp256k1"],[3,"Secp256k1Affine"],[3,"Fp"],[3,"Fq"],[3,"Secp256k1Compressed"],[8,"AsRef"],[8,"CurveExt"],[8,"CurveAffine"],[8,"FieldExt"],[8,"Group"],[8,"CurveAffineExt"],[8,"Engine"],[8,"MultiMillerLoop"],[8,"MillerLoopResult"],[8,"PairingCurveAffine"],[8,"SerdeObject"]]},\ +"poseidon":{"doc":"Poseidon hashing implemention with variable lenght input …","t":[3,3,3,3,3,3,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11],"n":["MDSMatrices","MDSMatrix","Poseidon","SparseMDSMatrix","Spec","State","borrow","borrow","borrow","borrow","borrow","borrow","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","borrow_mut","clone","clone","clone","clone","clone","clone","clone_into","clone_into","clone_into","clone_into","clone_into","clone_into","col_hat","constants","default","eq","fmt","fmt","fmt","fmt","fmt","fmt","from","from","from","from","from","from","from","index","into","into","into","into","into","into","mds","mds_matrices","new","new","permute","pre_sparse_mds","r_f","row","rows","sparse_matrices","squeeze","to_owned","to_owned","to_owned","to_owned","to_owned","to_owned","try_from","try_from","try_from","try_from","try_from","try_from","try_into","try_into","try_into","try_into","try_into","try_into","type_id","type_id","type_id","type_id","type_id","type_id","update","vzip","vzip","vzip","vzip","vzip","vzip","words"],"q":["poseidon","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","",""],"d":["MDSMatrices holds the MDS matrix as well as transition …","MDSMatrix is applied to State to achive linear layer of …","Poseidon hasher that maintains state and inputs and yields …","SparseMDSMatrix are in [row], [hat | identity] form and …","Spec holds construction parameters as well as constants …","State is structure T sized field elements that are …","","","","","","","","","","","","","","","","","","","","","","","","","Returns the first column without first element in the …","Optimised round constants","The capacity value is 2**64 + (o − 1) where o the output …","","","","","","","","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Returns the argument unchanged.","Assert the form and represent an MDS matrix as a sparse …","Returns the argument unchanged.","","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Calls U::from(self).","Returns original MDS matrix","Set of MDS Matrices used in permutation line","Constructs a clear state poseidon instance","Given number of round parameters constructs new Posedion …","Applies the Poseidon permutation to the given state","Returns transition matrix for sparse trick","Number of full rounds","Returns the first row","Returns rows of the MDS matrix","Returns sparse matrices for partial rounds","Results a single element by absorbing already added inputs","","","","","","","","","","","","","","","","","","","","","","","","","Appends elements to the absorption line updates state …","","","","","","","Copies elements of the state"],"i":[0,0,0,0,0,0,3,4,5,6,7,8,3,4,5,6,7,8,3,4,5,6,7,8,3,4,5,6,7,8,8,5,4,4,3,4,5,6,7,8,3,4,5,6,7,8,8,7,3,4,5,6,7,8,6,5,3,5,5,6,5,8,7,6,3,3,4,5,6,7,8,3,4,5,6,7,8,3,4,5,6,7,8,3,4,5,6,7,8,3,3,4,5,6,7,8,4],"f":[0,0,0,0,0,0,[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[]],[[[3,[[0,[1,2]]]]],[[3,[[0,[1,2]]]]]],[[[4,[[0,[1,2]]]]],[[4,[[0,[1,2]]]]]],[[[5,[[0,[1,2]]]]],[[5,[[0,[1,2]]]]]],[[[6,[[0,[1,2]]]]],[[6,[[0,[1,2]]]]]],[[[7,[[0,[1,2]]]]],[[7,[[0,[1,2]]]]]],[[[8,[[0,[1,2]]]]],[[8,[[0,[1,2]]]]]],[[]],[[]],[[]],[[]],[[]],[[]],[[[8,[2]]]],0,[[],[[4,[2]]]],[[[4,[[0,[9,2]]]],4],10],[[[3,[[0,[11,2]]]],12],13],[[[4,[[0,[11,2]]]],12],13],[[[5,[[0,[11,2]]]],12],13],[[[6,[[0,[11,2]]]],12],13],[[[7,[[0,[11,2]]]],12],13],[[[8,[[0,[11,2]]]],12],13],[[]],[[]],[[]],[[]],[[]],[[[7,[2]]],[[8,[2]]]],[[]],[[[7,[2]],14]],[[]],[[]],[[]],[[]],[[]],[[]],[[[6,[2]]],7],[[[5,[2]]],6],[[14,14],[[3,[2]]]],[[14,14],[[5,[2]]]],[[[5,[2]],4]],[[[6,[2]]],7],[[[5,[2]]],14],[[[8,[2]]]],[[[7,[2]]]],[[[6,[2]]],15],[[[3,[2]]],2],[[]],[[]],[[]],[[]],[[]],[[]],[[],16],[[],16],[[],16],[[],16],[[],16],[[],16],[[],16],[[],16],[[],16],[[],16],[[],16],[[],16],[[],17],[[],17],[[],17],[[],17],[[],17],[[],17],[[[3,[2]]]],[[]],[[]],[[]],[[]],[[]],[[]],[[[4,[2]]]]],"p":[[8,"Clone"],[8,"FieldExt"],[3,"Poseidon"],[3,"State"],[3,"Spec"],[3,"MDSMatrices"],[3,"MDSMatrix"],[3,"SparseMDSMatrix"],[8,"PartialEq"],[15,"bool"],[8,"Debug"],[3,"Formatter"],[6,"Result"],[15,"usize"],[3,"Vec"],[4,"Result"],[3,"TypeId"]]}\ +}'); +if (typeof window !== 'undefined' && window.initSearch) {window.initSearch(searchIndex)}; +if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; diff --git a/docs/search.js b/docs/search.js new file mode 100644 index 0000000000..f0ccdfb1bf --- /dev/null +++ b/docs/search.js @@ -0,0 +1 @@ +"use strict";(function(){const itemTypes=["mod","externcrate","import","struct","enum","fn","type","static","trait","impl","tymethod","method","structfield","variant","macro","primitive","associatedtype","constant","associatedconstant","union","foreigntype","keyword","existential","attr","derive","traitalias",];const TY_PRIMITIVE=itemTypes.indexOf("primitive");const TY_KEYWORD=itemTypes.indexOf("keyword");const ROOT_PATH=typeof window!=="undefined"?window.rootPath:"../";function hasOwnPropertyRustdoc(obj,property){return Object.prototype.hasOwnProperty.call(obj,property)}function printTab(nb){let iter=0;let foundCurrentTab=false;let foundCurrentResultSet=false;onEachLazy(document.getElementById("titles").childNodes,elem=>{if(nb===iter){addClass(elem,"selected");foundCurrentTab=true}else{removeClass(elem,"selected")}iter+=1});iter=0;onEachLazy(document.getElementById("results").childNodes,elem=>{if(nb===iter){addClass(elem,"active");foundCurrentResultSet=true}else{removeClass(elem,"active")}iter+=1});if(foundCurrentTab&&foundCurrentResultSet){searchState.currentTab=nb}else if(nb!==0){printTab(0)}}const levenshtein_row2=[];function levenshtein(s1,s2){if(s1===s2){return 0}const s1_len=s1.length,s2_len=s2.length;if(s1_len&&s2_len){let i1=0,i2=0,a,b,c,c2;const row=levenshtein_row2;while(i1-".indexOf(c)!==-1}function isStopCharacter(c){return isWhitespace(c)||isEndCharacter(c)}function isErrorCharacter(c){return"()".indexOf(c)!==-1}function itemTypeFromName(typename){for(let i=0,len=itemTypes.length;i0){throw new Error("Cannot use literal search when there is more than one element")}parserState.pos+=1;const start=parserState.pos;const end=getIdentEndPosition(parserState);if(parserState.pos>=parserState.length){throw new Error("Unclosed `\"`")}else if(parserState.userQuery[end]!=="\""){throw new Error(`Unexpected \`${parserState.userQuery[end]}\` in a string element`)}else if(start===end){throw new Error("Cannot have empty string element")}parserState.pos+=1;query.literalSearch=true}function isPathStart(parserState){return parserState.userQuery.slice(parserState.pos,parserState.pos+2)==="::"}function isReturnArrow(parserState){return parserState.userQuery.slice(parserState.pos,parserState.pos+2)==="->"}function isIdentCharacter(c){return(c==="_"||(c>="0"&&c<="9")||(c>="a"&&c<="z")||(c>="A"&&c<="Z"))}function isSeparatorCharacter(c){return c===","||isWhitespaceCharacter(c)}function isWhitespaceCharacter(c){return c===" "||c==="\t"}function createQueryElement(query,parserState,name,generics,isInGenerics){if(name==="*"||(name.length===0&&generics.length===0)){return}if(query.literalSearch&&parserState.totalElems-parserState.genericsElems>0){throw new Error("You cannot have more than one element if you use quotes")}const pathSegments=name.split("::");if(pathSegments.length>1){for(let i=0,len=pathSegments.length;i=end){throw new Error("Found generics without a path")}parserState.pos+=1;getItemsBefore(query,parserState,generics,">")}if(start>=end&&generics.length===0){return}elems.push(createQueryElement(query,parserState,parserState.userQuery.slice(start,end),generics,isInGenerics))}function getItemsBefore(query,parserState,elems,endChar){let foundStopChar=true;while(parserState.pos"){extra="`<`"}else if(endChar===""){extra="`->`"}throw new Error("Unexpected `"+c+"` after "+extra)}if(!foundStopChar){if(endChar!==""){throw new Error(`Expected \`,\`, \` \` or \`${endChar}\`, found \`${c}\``)}throw new Error(`Expected \`,\` or \` \`, found \`${c}\``)}const posBefore=parserState.pos;getNextElem(query,parserState,elems,endChar===">");if(posBefore===parserState.pos){parserState.pos+=1}foundStopChar=false}parserState.pos+=1}function checkExtraTypeFilterCharacters(parserState){const query=parserState.userQuery;for(let pos=0;pos"){if(isReturnArrow(parserState)){break}throw new Error(`Unexpected \`${c}\` (did you mean \`->\`?)`)}throw new Error(`Unexpected \`${c}\``)}else if(c===":"&&!isPathStart(parserState)){if(parserState.typeFilter!==null){throw new Error("Unexpected `:`")}if(query.elems.length===0){throw new Error("Expected type filter before `:`")}else if(query.elems.length!==1||parserState.totalElems!==1){throw new Error("Unexpected `:`")}else if(query.literalSearch){throw new Error("You cannot use quotes on type filter")}checkExtraTypeFilterCharacters(parserState);parserState.typeFilter=query.elems.pop().name;parserState.pos+=1;parserState.totalElems=0;query.literalSearch=false;foundStopChar=true;continue}if(!foundStopChar){if(parserState.typeFilter!==null){throw new Error(`Expected \`,\`, \` \` or \`->\`, found \`${c}\``)}throw new Error(`Expected \`,\`, \` \`, \`:\` or \`->\`, found \`${c}\``)}before=query.elems.length;getNextElem(query,parserState,query.elems,false);if(query.elems.length===before){parserState.pos+=1}foundStopChar=false}while(parserState.pos`")}break}else{parserState.pos+=1}}}function newParsedQuery(userQuery){return{original:userQuery,userQuery:userQuery.toLowerCase(),typeFilter:NO_TYPE_FILTER,elems:[],returned:[],foundElems:0,literalSearch:false,error:null,}}function buildUrl(search,filterCrates){let extra="?search="+encodeURIComponent(search);if(filterCrates!==null){extra+="&filter-crate="+encodeURIComponent(filterCrates)}return getNakedUrl()+extra+window.location.hash}function getFilterCrates(){const elem=document.getElementById("crate-search");if(elem&&elem.value!=="all crates"&&hasOwnPropertyRustdoc(rawSearchIndex,elem.value)){return elem.value}return null}function parseQuery(userQuery){userQuery=userQuery.trim();const parserState={length:userQuery.length,pos:0,totalElems:0,genericsElems:0,typeFilter:null,userQuery:userQuery.toLowerCase(),};let query=newParsedQuery(userQuery);try{parseInput(query,parserState);if(parserState.typeFilter!==null){let typeFilter=parserState.typeFilter;if(typeFilter==="const"){typeFilter="constant"}query.typeFilter=itemTypeFromName(typeFilter)}}catch(err){query=newParsedQuery(userQuery);query.error=err.message;query.typeFilter=-1;return query}if(!query.literalSearch){query.literalSearch=parserState.totalElems>1}query.foundElems=query.elems.length+query.returned.length;return query}function createQueryResults(results_in_args,results_returned,results_others,parsedQuery){return{"in_args":results_in_args,"returned":results_returned,"others":results_others,"query":parsedQuery,}}function execQuery(parsedQuery,searchWords,filterCrates,currentCrate){const results_others={},results_in_args={},results_returned={};function transformResults(results){const duplicates={};const out=[];for(const result of results){if(result.id>-1){const obj=searchIndex[result.id];obj.lev=result.lev;const res=buildHrefAndPath(obj);obj.displayPath=pathSplitter(res[0]);obj.fullPath=obj.displayPath+obj.name;obj.fullPath+="|"+obj.ty;if(duplicates[obj.fullPath]){continue}duplicates[obj.fullPath]=true;obj.href=res[1];out.push(obj);if(out.length>=MAX_RESULTS){break}}}return out}function sortResults(results,isType,preferredCrate){const userQuery=parsedQuery.userQuery;const ar=[];for(const entry in results){if(hasOwnPropertyRustdoc(results,entry)){const result=results[entry];result.word=searchWords[result.id];result.item=searchIndex[result.id]||{};ar.push(result)}}results=ar;if(results.length===0){return[]}results.sort((aaa,bbb)=>{let a,b;a=(aaa.word!==userQuery);b=(bbb.word!==userQuery);if(a!==b){return a-b}a=(aaa.lev);b=(bbb.lev);if(a!==b){return a-b}a=(aaa.item.crate!==preferredCrate);b=(bbb.item.crate!==preferredCrate);if(a!==b){return a-b}a=aaa.word.length;b=bbb.word.length;if(a!==b){return a-b}a=aaa.word;b=bbb.word;if(a!==b){return(a>b?+1:-1)}a=(aaa.index<0);b=(bbb.index<0);if(a!==b){return a-b}a=aaa.index;b=bbb.index;if(a!==b){return a-b}if((aaa.item.ty===TY_PRIMITIVE&&bbb.item.ty!==TY_KEYWORD)||(aaa.item.ty===TY_KEYWORD&&bbb.item.ty!==TY_PRIMITIVE)){return-1}if((bbb.item.ty===TY_PRIMITIVE&&aaa.item.ty!==TY_PRIMITIVE)||(bbb.item.ty===TY_KEYWORD&&aaa.item.ty!==TY_KEYWORD)){return 1}a=(aaa.item.desc==="");b=(bbb.item.desc==="");if(a!==b){return a-b}a=aaa.item.ty;b=bbb.item.ty;if(a!==b){return a-b}a=aaa.item.path;b=bbb.item.path;if(a!==b){return(a>b?+1:-1)}return 0});let nameSplit=null;if(parsedQuery.elems.length===1){const hasPath=typeof parsedQuery.elems[0].path==="undefined";nameSplit=hasPath?null:parsedQuery.elems[0].path}for(const result of results){if(result.dontValidate){continue}const name=result.item.name.toLowerCase(),path=result.item.path.toLowerCase(),parent=result.item.parent;if(!isType&&!validateResult(name,path,nameSplit,parent)){result.id=-1}}return transformResults(results)}function checkGenerics(row,elem,defaultLev){if(row.generics.length===0){return elem.generics.length===0?defaultLev:MAX_LEV_DISTANCE+1}else if(row.generics.length>0&&row.generics[0].name===null){return checkGenerics(row.generics[0],elem,defaultLev)}let elem_name;if(elem.generics.length>0&&row.generics.length>=elem.generics.length){const elems=Object.create(null);for(const entry of row.generics){elem_name=entry.name;if(elem_name===""){if(checkGenerics(entry,elem,MAX_LEV_DISTANCE+1)!==0){return MAX_LEV_DISTANCE+1}continue}if(elems[elem_name]===undefined){elems[elem_name]=0}elems[elem_name]+=1}for(const generic of elem.generics){let match=null;if(elems[generic.name]){match=generic.name}else{for(elem_name in elems){if(!hasOwnPropertyRustdoc(elems,elem_name)){continue}if(elem_name===generic){match=elem_name;break}}}if(match===null){return MAX_LEV_DISTANCE+1}elems[match]-=1;if(elems[match]===0){delete elems[match]}}return 0}return MAX_LEV_DISTANCE+1}function checkIfInGenerics(row,elem){let lev=MAX_LEV_DISTANCE+1;for(const entry of row.generics){lev=Math.min(checkType(entry,elem,true),lev);if(lev===0){break}}return lev}function checkType(row,elem,literalSearch){if(row.name===null){if(row.generics.length>0){return checkIfInGenerics(row,elem)}return MAX_LEV_DISTANCE+1}let lev=levenshtein(row.name,elem.name);if(literalSearch){if(lev!==0){if(elem.generics.length===0){const checkGeneric=row.generics.length>0;if(checkGeneric&&row.generics.findIndex(tmp_elem=>tmp_elem.name===elem.name)!==-1){return 0}}return MAX_LEV_DISTANCE+1}else if(elem.generics.length>0){return checkGenerics(row,elem,MAX_LEV_DISTANCE+1)}return 0}else if(row.generics.length>0){if(elem.generics.length===0){if(lev===0){return 0}lev=checkIfInGenerics(row,elem);return lev+0.5}else if(lev>MAX_LEV_DISTANCE){return checkIfInGenerics(row,elem)}else{const tmp_lev=checkGenerics(row,elem,lev);if(tmp_lev>MAX_LEV_DISTANCE){return MAX_LEV_DISTANCE+1}return(tmp_lev+lev)/2}}else if(elem.generics.length>0){return MAX_LEV_DISTANCE+1}return lev}function findArg(row,elem,typeFilter){let lev=MAX_LEV_DISTANCE+1;if(row&&row.type&&row.type.inputs&&row.type.inputs.length>0){for(const input of row.type.inputs){if(!typePassesFilter(typeFilter,input.ty)){continue}lev=Math.min(lev,checkType(input,elem,parsedQuery.literalSearch));if(lev===0){return 0}}}return parsedQuery.literalSearch?MAX_LEV_DISTANCE+1:lev}function checkReturned(row,elem,typeFilter){let lev=MAX_LEV_DISTANCE+1;if(row&&row.type&&row.type.output.length>0){const ret=row.type.output;for(const ret_ty of ret){if(!typePassesFilter(typeFilter,ret_ty.ty)){continue}lev=Math.min(lev,checkType(ret_ty,elem,parsedQuery.literalSearch));if(lev===0){return 0}}}return parsedQuery.literalSearch?MAX_LEV_DISTANCE+1:lev}function checkPath(contains,ty){if(contains.length===0){return 0}let ret_lev=MAX_LEV_DISTANCE+1;const path=ty.path.split("::");if(ty.parent&&ty.parent.name){path.push(ty.parent.name.toLowerCase())}const length=path.length;const clength=contains.length;if(clength>length){return MAX_LEV_DISTANCE+1}for(let i=0;ilength){break}let lev_total=0;let aborted=false;for(let x=0;xMAX_LEV_DISTANCE){aborted=true;break}lev_total+=lev}if(!aborted){ret_lev=Math.min(ret_lev,Math.round(lev_total/clength))}}return ret_lev}function typePassesFilter(filter,type){if(filter<=NO_TYPE_FILTER||filter===type)return true;const name=itemTypes[type];switch(itemTypes[filter]){case"constant":return name==="associatedconstant";case"fn":return name==="method"||name==="tymethod";case"type":return name==="primitive"||name==="associatedtype";case"trait":return name==="traitalias"}return false}function createAliasFromItem(item){return{crate:item.crate,name:item.name,path:item.path,desc:item.desc,ty:item.ty,parent:item.parent,type:item.type,is_alias:true,}}function handleAliases(ret,query,filterCrates,currentCrate){const lowerQuery=query.toLowerCase();const aliases=[];const crateAliases=[];if(filterCrates!==null){if(ALIASES[filterCrates]&&ALIASES[filterCrates][lowerQuery]){const query_aliases=ALIASES[filterCrates][lowerQuery];for(const alias of query_aliases){aliases.push(createAliasFromItem(searchIndex[alias]))}}}else{Object.keys(ALIASES).forEach(crate=>{if(ALIASES[crate][lowerQuery]){const pushTo=crate===currentCrate?crateAliases:aliases;const query_aliases=ALIASES[crate][lowerQuery];for(const alias of query_aliases){pushTo.push(createAliasFromItem(searchIndex[alias]))}}})}const sortFunc=(aaa,bbb)=>{if(aaa.path{alias.alias=query;const res=buildHrefAndPath(alias);alias.displayPath=pathSplitter(res[0]);alias.fullPath=alias.displayPath+alias.name;alias.href=res[1];ret.others.unshift(alias);if(ret.others.length>MAX_RESULTS){ret.others.pop()}};aliases.forEach(pushFunc);crateAliases.forEach(pushFunc)}function addIntoResults(results,fullId,id,index,lev){if(lev===0||(!parsedQuery.literalSearch&&lev<=MAX_LEV_DISTANCE)){if(results[fullId]!==undefined){const result=results[fullId];if(result.dontValidate||result.lev<=lev){return}}results[fullId]={id:id,index:index,dontValidate:parsedQuery.literalSearch,lev:lev,}}}function handleSingleArg(row,pos,elem,results_others,results_in_args,results_returned){if(!row||(filterCrates!==null&&row.crate!==filterCrates)){return}let lev,lev_add=0,index=-1;const fullId=row.id;const in_args=findArg(row,elem,parsedQuery.typeFilter);const returned=checkReturned(row,elem,parsedQuery.typeFilter);addIntoResults(results_in_args,fullId,pos,index,in_args);addIntoResults(results_returned,fullId,pos,index,returned);if(!typePassesFilter(parsedQuery.typeFilter,row.ty)){return}const searchWord=searchWords[pos];if(parsedQuery.literalSearch){if(searchWord===elem.name){addIntoResults(results_others,fullId,pos,-1,0)}return}if(elem.name.length===0){if(row.type!==null){lev=checkGenerics(row.type,elem,MAX_LEV_DISTANCE+1);addIntoResults(results_others,fullId,pos,index,lev)}return}if(elem.fullPath.length>1){lev=checkPath(elem.pathWithoutLast,row);if(lev>MAX_LEV_DISTANCE||(parsedQuery.literalSearch&&lev!==0)){return}else if(lev>0){lev_add=lev/10}}if(searchWord.indexOf(elem.pathLast)>-1||row.normalizedName.indexOf(elem.pathLast)>-1){index=row.normalizedName.indexOf(elem.pathLast)}lev=levenshtein(searchWord,elem.pathLast);if(lev>0&&elem.pathLast.length>2&&searchWord.indexOf(elem.pathLast)>-1){if(elem.pathLast.length<6){lev=1}else{lev=0}}lev+=lev_add;if(lev>MAX_LEV_DISTANCE){return}else if(index!==-1&&elem.fullPath.length<2){lev-=1}if(lev<0){lev=0}addIntoResults(results_others,fullId,pos,index,lev)}function handleArgs(row,pos,results){if(!row||(filterCrates!==null&&row.crate!==filterCrates)){return}let totalLev=0;let nbLev=0;function checkArgs(elems,callback){for(const elem of elems){const lev=callback(row,elem,NO_TYPE_FILTER);if(lev<=1){nbLev+=1;totalLev+=lev}else{return false}}return true}if(!checkArgs(parsedQuery.elems,findArg)){return}if(!checkArgs(parsedQuery.returned,checkReturned)){return}if(nbLev===0){return}const lev=Math.round(totalLev/nbLev);addIntoResults(results,row.id,pos,0,lev)}function innerRunQuery(){let elem,i,nSearchWords,in_returned,row;if(parsedQuery.foundElems===1){if(parsedQuery.elems.length===1){elem=parsedQuery.elems[0];for(i=0,nSearchWords=searchWords.length;i0){for(i=0,nSearchWords=searchWords.length;i-1||path.indexOf(key)>-1||(parent!==undefined&&parent.name!==undefined&&parent.name.toLowerCase().indexOf(key)>-1)||levenshtein(name,key)<=MAX_LEV_DISTANCE)){return false}}return true}function nextTab(direction){const next=(searchState.currentTab+direction+3)%searchState.focusedByTab.length;searchState.focusedByTab[searchState.currentTab]=document.activeElement;printTab(next);focusSearchResult()}function focusSearchResult(){const target=searchState.focusedByTab[searchState.currentTab]||document.querySelectorAll(".search-results.active a").item(0)||document.querySelectorAll("#titles > button").item(searchState.currentTab);if(target){target.focus()}}function buildHrefAndPath(item){let displayPath;let href;const type=itemTypes[item.ty];const name=item.name;let path=item.path;if(type==="mod"){displayPath=path+"::";href=ROOT_PATH+path.replace(/::/g,"/")+"/"+name+"/index.html"}else if(type==="import"){displayPath=item.path+"::";href=ROOT_PATH+item.path.replace(/::/g,"/")+"/index.html#reexport."+name}else if(type==="primitive"||type==="keyword"){displayPath="";href=ROOT_PATH+path.replace(/::/g,"/")+"/"+type+"."+name+".html"}else if(type==="externcrate"){displayPath="";href=ROOT_PATH+name+"/index.html"}else if(item.parent!==undefined){const myparent=item.parent;let anchor="#"+type+"."+name;const parentType=itemTypes[myparent.ty];let pageType=parentType;let pageName=myparent.name;if(parentType==="primitive"){displayPath=myparent.name+"::"}else if(type==="structfield"&&parentType==="variant"){const enumNameIdx=item.path.lastIndexOf("::");const enumName=item.path.substr(enumNameIdx+2);path=item.path.substr(0,enumNameIdx);displayPath=path+"::"+enumName+"::"+myparent.name+"::";anchor="#variant."+myparent.name+".field."+name;pageType="enum";pageName=enumName}else{displayPath=path+"::"+myparent.name+"::"}href=ROOT_PATH+path.replace(/::/g,"/")+"/"+pageType+"."+pageName+".html"+anchor}else{displayPath=item.path+"::";href=ROOT_PATH+item.path.replace(/::/g,"/")+"/"+type+"."+name+".html"}return[displayPath,href]}function pathSplitter(path){const tmp=""+path.replace(/::/g,"::");if(tmp.endsWith("")){return tmp.slice(0,tmp.length-6)}return tmp}function addTab(array,query,display){let extraClass="";if(display===true){extraClass=" active"}const output=document.createElement("div");let length=0;if(array.length>0){output.className="search-results "+extraClass;array.forEach(item=>{const name=item.name;const type=itemTypes[item.ty];length+=1;let extra="";if(type==="primitive"){extra=" (primitive type)"}else if(type==="keyword"){extra=" (keyword)"}const link=document.createElement("a");link.className="result-"+type;link.href=item.href;const wrapper=document.createElement("div");const resultName=document.createElement("div");resultName.className="result-name";if(item.is_alias){const alias=document.createElement("span");alias.className="alias";const bold=document.createElement("b");bold.innerText=item.alias;alias.appendChild(bold);alias.insertAdjacentHTML("beforeend"," - see ");resultName.appendChild(alias)}resultName.insertAdjacentHTML("beforeend",item.displayPath+""+name+extra+"");wrapper.appendChild(resultName);const description=document.createElement("div");description.className="desc";const spanDesc=document.createElement("span");spanDesc.insertAdjacentHTML("beforeend",item.desc);description.appendChild(spanDesc);wrapper.appendChild(description);link.appendChild(wrapper);output.appendChild(link)})}else if(query.error===null){output.className="search-failed"+extraClass;output.innerHTML="No results :(
"+"Try on DuckDuckGo?

"+"Or try looking in one of these:"}return[output,length]}function makeTabHeader(tabNb,text,nbElems){if(searchState.currentTab===tabNb){return""}return""}function showResults(results,go_to_first,filterCrates){const search=searchState.outputElement();if(go_to_first||(results.others.length===1&&getSettingValue("go-to-only-result")==="true"&&(!search.firstChild||search.firstChild.innerText!==searchState.loadingText))){const elem=document.createElement("a");elem.href=results.others[0].href;removeClass(elem,"active");document.body.appendChild(elem);elem.click();return}if(results.query===undefined){results.query=parseQuery(searchState.input.value)}currentResults=results.query.userQuery;const ret_others=addTab(results.others,results.query,true);const ret_in_args=addTab(results.in_args,results.query,false);const ret_returned=addTab(results.returned,results.query,false);let currentTab=searchState.currentTab;if((currentTab===0&&ret_others[1]===0)||(currentTab===1&&ret_in_args[1]===0)||(currentTab===2&&ret_returned[1]===0)){if(ret_others[1]!==0){currentTab=0}else if(ret_in_args[1]!==0){currentTab=1}else if(ret_returned[1]!==0){currentTab=2}}let crates="";const crates_list=Object.keys(rawSearchIndex);if(crates_list.length>1){crates=" in 
"}let output=`

Results${crates}

`;if(results.query.error!==null){output+=`

Query parser error: "${results.query.error}".

`;output+="
"+makeTabHeader(0,"In Names",ret_others[1])+"
";currentTab=0}else if(results.query.foundElems<=1&&results.query.returned.length===0){output+="
"+makeTabHeader(0,"In Names",ret_others[1])+makeTabHeader(1,"In Parameters",ret_in_args[1])+makeTabHeader(2,"In Return Types",ret_returned[1])+"
"}else{const signatureTabTitle=results.query.elems.length===0?"In Function Return Types":results.query.returned.length===0?"In Function Parameters":"In Function Signatures";output+="
"+makeTabHeader(0,signatureTabTitle,ret_others[1])+"
";currentTab=0}const resultsElem=document.createElement("div");resultsElem.id="results";resultsElem.appendChild(ret_others[0]);resultsElem.appendChild(ret_in_args[0]);resultsElem.appendChild(ret_returned[0]);search.innerHTML=output;const crateSearch=document.getElementById("crate-search");if(crateSearch){crateSearch.addEventListener("input",updateCrate)}search.appendChild(resultsElem);searchState.showResults(search);const elems=document.getElementById("titles").childNodes;searchState.focusedByTab=[];let i=0;for(const elem of elems){const j=i;elem.onclick=()=>printTab(j);searchState.focusedByTab.push(null);i+=1}printTab(currentTab)}function search(e,forced){const params=searchState.getQueryStringParams();const query=parseQuery(searchState.input.value.trim());if(e){e.preventDefault()}if(!forced&&query.userQuery===currentResults){if(query.userQuery.length>0){putBackSearch()}return}let filterCrates=getFilterCrates();if(filterCrates===null&¶ms["filter-crate"]!==undefined){filterCrates=params["filter-crate"]}searchState.title="Results for "+query.original+" - Rust";if(browserSupportsHistoryApi()){const newURL=buildUrl(query.original,filterCrates);if(!history.state&&!params.search){history.pushState(null,"",newURL)}else{history.replaceState(null,"",newURL)}}showResults(execQuery(query,searchWords,filterCrates,window.currentCrate),params.go_to_first,filterCrates)}function buildItemSearchTypeAll(types,lowercasePaths){const PATH_INDEX_DATA=0;const GENERICS_DATA=1;return types.map(type=>{let pathIndex,generics;if(typeof type==="number"){pathIndex=type;generics=[]}else{pathIndex=type[PATH_INDEX_DATA];generics=buildItemSearchTypeAll(type[GENERICS_DATA],lowercasePaths)}return{name:pathIndex===0?null:lowercasePaths[pathIndex-1].name,ty:pathIndex===0?null:lowercasePaths[pathIndex-1].ty,generics:generics,}})}function buildFunctionSearchType(functionSearchType,lowercasePaths){const INPUTS_DATA=0;const OUTPUT_DATA=1;if(functionSearchType===0){return null}let inputs,output;if(typeof functionSearchType[INPUTS_DATA]==="number"){const pathIndex=functionSearchType[INPUTS_DATA];inputs=[{name:pathIndex===0?null:lowercasePaths[pathIndex-1].name,ty:pathIndex===0?null:lowercasePaths[pathIndex-1].ty,generics:[],}]}else{inputs=buildItemSearchTypeAll(functionSearchType[INPUTS_DATA],lowercasePaths)}if(functionSearchType.length>1){if(typeof functionSearchType[OUTPUT_DATA]==="number"){const pathIndex=functionSearchType[OUTPUT_DATA];output=[{name:pathIndex===0?null:lowercasePaths[pathIndex-1].name,ty:pathIndex===0?null:lowercasePaths[pathIndex-1].ty,generics:[],}]}else{output=buildItemSearchTypeAll(functionSearchType[OUTPUT_DATA],lowercasePaths)}}else{output=[]}return{inputs,output,}}function buildIndex(rawSearchIndex){searchIndex=[];const searchWords=[];let i,word;let currentIndex=0;let id=0;for(const crate in rawSearchIndex){if(!hasOwnPropertyRustdoc(rawSearchIndex,crate)){continue}let crateSize=0;const crateCorpus=rawSearchIndex[crate];searchWords.push(crate);const crateRow={crate:crate,ty:1,name:crate,path:"",desc:crateCorpus.doc,parent:undefined,type:null,id:id,normalizedName:crate.indexOf("_")===-1?crate:crate.replace(/_/g,""),};id+=1;searchIndex.push(crateRow);currentIndex+=1;const itemTypes=crateCorpus.t;const itemNames=crateCorpus.n;const itemPaths=crateCorpus.q;const itemDescs=crateCorpus.d;const itemParentIdxs=crateCorpus.i;const itemFunctionSearchTypes=crateCorpus.f;const paths=crateCorpus.p;const aliases=crateCorpus.a;const lowercasePaths=[];let len=paths.length;for(i=0;i0?paths[itemParentIdxs[i]-1]:undefined,type:buildFunctionSearchType(itemFunctionSearchTypes[i],lowercasePaths),id:id,normalizedName:word.indexOf("_")===-1?word:word.replace(/_/g,""),};id+=1;searchIndex.push(row);lastPath=row.path;crateSize+=1}if(aliases){ALIASES[crate]=Object.create(null);for(const alias_name in aliases){if(!hasOwnPropertyRustdoc(aliases,alias_name)){continue}if(!hasOwnPropertyRustdoc(ALIASES[crate],alias_name)){ALIASES[crate][alias_name]=[]}for(const local_alias of aliases[alias_name]){ALIASES[crate][alias_name].push(local_alias+currentIndex)}}}currentIndex+=crateSize}return searchWords}function onSearchSubmit(e){e.preventDefault();searchState.clearInputTimeout();search()}function putBackSearch(){const search_input=searchState.input;if(!searchState.input){return}if(search_input.value!==""&&!searchState.isDisplayed()){searchState.showResults();if(browserSupportsHistoryApi()){history.replaceState(null,"",buildUrl(search_input.value,getFilterCrates()))}document.title=searchState.title}}function registerSearchEvents(){const params=searchState.getQueryStringParams();if(searchState.input.value===""){searchState.input.value=params.search||""}const searchAfter500ms=()=>{searchState.clearInputTimeout();if(searchState.input.value.length===0){if(browserSupportsHistoryApi()){history.replaceState(null,window.currentCrate+" - Rust",getNakedUrl()+window.location.hash)}searchState.hideResults()}else{searchState.timeout=setTimeout(search,500)}};searchState.input.onkeyup=searchAfter500ms;searchState.input.oninput=searchAfter500ms;document.getElementsByClassName("search-form")[0].onsubmit=onSearchSubmit;searchState.input.onchange=e=>{if(e.target!==document.activeElement){return}searchState.clearInputTimeout();setTimeout(search,0)};searchState.input.onpaste=searchState.input.onchange;searchState.outputElement().addEventListener("keydown",e=>{if(e.altKey||e.ctrlKey||e.shiftKey||e.metaKey){return}if(e.which===38){const previous=document.activeElement.previousElementSibling;if(previous){previous.focus()}else{searchState.focus()}e.preventDefault()}else if(e.which===40){const next=document.activeElement.nextElementSibling;if(next){next.focus()}const rect=document.activeElement.getBoundingClientRect();if(window.innerHeight-rect.bottom{if(e.which===40){focusSearchResult();e.preventDefault()}});searchState.input.addEventListener("focus",()=>{putBackSearch()});searchState.input.addEventListener("blur",()=>{searchState.input.placeholder=searchState.input.origPlaceholder});if(browserSupportsHistoryApi()){const previousTitle=document.title;window.addEventListener("popstate",e=>{const params=searchState.getQueryStringParams();document.title=previousTitle;currentResults=null;if(params.search&¶ms.search.length>0){searchState.input.value=params.search;search(e)}else{searchState.input.value="";searchState.hideResults()}})}window.onpageshow=()=>{const qSearch=searchState.getQueryStringParams().search;if(searchState.input.value===""&&qSearch){searchState.input.value=qSearch}search()}}function updateCrate(ev){if(ev.target.value==="all crates"){const params=searchState.getQueryStringParams();const query=searchState.input.value.trim();if(!history.state&&!params.search){history.pushState(null,"",buildUrl(query,null))}else{history.replaceState(null,"",buildUrl(query,null))}}currentResults=null;search(undefined,true)}const searchWords=buildIndex(rawSearchIndex);if(typeof window!=="undefined"){registerSearchEvents();if(window.searchState.getQueryStringParams().search){search()}}if(typeof exports!=="undefined"){exports.initSearch=initSearch;exports.execQuery=execQuery;exports.parseQuery=parseQuery}return searchWords}if(typeof window!=="undefined"){window.initSearch=initSearch;if(window.searchIndex!==undefined){initSearch(window.searchIndex)}}else{initSearch({})}})() \ No newline at end of file diff --git a/docs/settings.css b/docs/settings.css new file mode 100644 index 0000000000..ab01e577c5 --- /dev/null +++ b/docs/settings.css @@ -0,0 +1 @@ +.setting-line{margin:0.6em 0 0.6em 0.3em;position:relative;}.setting-line .choices{display:flex;flex-wrap:wrap;}.setting-line .radio-line input{margin-right:0.3em;height:1.2rem;width:1.2rem;color:inherit;border:1px solid currentColor;outline:none;-webkit-appearance:none;cursor:pointer;border-radius:50%;}.setting-line .radio-line input+span{padding-bottom:1px;}.radio-line .setting-name{width:100%;}.radio-line .choice{margin-top:0.1em;margin-bottom:0.1em;min-width:3.8em;padding:0.3em;display:flex;align-items:center;cursor:pointer;}.radio-line .choice+.choice{margin-left:0.5em;}.toggle{position:relative;width:100%;margin-right:20px;display:flex;align-items:center;cursor:pointer;}.toggle input{opacity:0;position:absolute;}.slider{position:relative;width:45px;min-width:45px;display:block;height:28px;margin-right:20px;cursor:pointer;background-color:#ccc;transition:.3s;}.slider:before{position:absolute;content:"";height:19px;width:19px;left:4px;bottom:4px;transition:.3s;}input:checked+.slider:before{transform:translateX(19px);}.setting-line>.sub-settings{padding-left:42px;width:100%;display:block;}#settings .setting-line{margin:1.2em 0.6em;}.setting-line .radio-line input:checked{box-shadow:inset 0 0 0 3px var(--main-background-color);background-color:var(--settings-input-color);}.setting-line .radio-line input:focus{box-shadow:0 0 1px 1px var(--settings-input-color);}.setting-line .radio-line input:checked:focus{box-shadow:inset 0 0 0 3px var(--main-background-color),0 0 2px 2px var(--settings-input-color);}.setting-line .radio-line input:hover{border-color:var(--settings-input-color) !important;}input:checked+.slider{background-color:var(--settings-input-color);} \ No newline at end of file diff --git a/docs/settings.html b/docs/settings.html new file mode 100644 index 0000000000..4fb934ed77 --- /dev/null +++ b/docs/settings.html @@ -0,0 +1 @@ +Rustdoc settings

Rustdoc settings

Back
\ No newline at end of file diff --git a/docs/settings.js b/docs/settings.js new file mode 100644 index 0000000000..834d29269d --- /dev/null +++ b/docs/settings.js @@ -0,0 +1,11 @@ +"use strict";(function(){const isSettingsPage=window.location.pathname.endsWith("/settings.html");function changeSetting(settingName,value){updateLocalStorage(settingName,value);switch(settingName){case"theme":case"preferred-dark-theme":case"preferred-light-theme":case"use-system-theme":updateSystemTheme();updateLightAndDark();break;case"line-numbers":if(value===true){window.rustdoc_add_line_numbers_to_examples()}else{window.rustdoc_remove_line_numbers_from_examples()}break}}function handleKey(ev){if(ev.ctrlKey||ev.altKey||ev.metaKey){return}switch(getVirtualKey(ev)){case"Enter":case"Return":case"Space":ev.target.checked=!ev.target.checked;ev.preventDefault();break}}function showLightAndDark(){addClass(document.getElementById("theme").parentElement,"hidden");removeClass(document.getElementById("preferred-light-theme").parentElement,"hidden");removeClass(document.getElementById("preferred-dark-theme").parentElement,"hidden")}function hideLightAndDark(){addClass(document.getElementById("preferred-light-theme").parentElement,"hidden");addClass(document.getElementById("preferred-dark-theme").parentElement,"hidden");removeClass(document.getElementById("theme").parentElement,"hidden")}function updateLightAndDark(){if(getSettingValue("use-system-theme")!=="false"){showLightAndDark()}else{hideLightAndDark()}}function setEvents(settingsElement){updateLightAndDark();onEachLazy(settingsElement.getElementsByClassName("slider"),elem=>{const toggle=elem.previousElementSibling;const settingId=toggle.id;const settingValue=getSettingValue(settingId);if(settingValue!==null){toggle.checked=settingValue==="true"}toggle.onchange=function(){changeSetting(this.id,this.checked)};toggle.onkeyup=handleKey;toggle.onkeyrelease=handleKey});onEachLazy(settingsElement.getElementsByClassName("select-wrapper"),elem=>{const select=elem.getElementsByTagName("select")[0];const settingId=select.id;const settingValue=getSettingValue(settingId);if(settingValue!==null){select.value=settingValue}select.onchange=function(){changeSetting(this.id,this.value)}});onEachLazy(settingsElement.querySelectorAll("input[type=\"radio\"]"),elem=>{const settingId=elem.name;const settingValue=getSettingValue(settingId);if(settingValue!==null&&settingValue!=="null"){elem.checked=settingValue===elem.value}elem.addEventListener("change",ev=>{changeSetting(ev.target.name,ev.target.value)})})}function buildSettingsPageSections(settings){let output="";for(const setting of settings){output+="
";const js_data_name=setting["js_name"];const setting_name=setting["name"];if(setting["options"]!==undefined){output+=`
\ + ${setting_name}\ +
`;onEach(setting["options"],option=>{const checked=option===setting["default"]?" checked":"";output+=``});output+="
"}else{const checked=setting["default"]===true?" checked":"";output+=``}output+="
"}return output}function buildSettingsPage(){const themes=getVar("themes").split(",");const settings=[{"name":"Use system theme","js_name":"use-system-theme","default":true,},{"name":"Theme","js_name":"theme","default":"light","options":themes,},{"name":"Preferred light theme","js_name":"preferred-light-theme","default":"light","options":themes,},{"name":"Preferred dark theme","js_name":"preferred-dark-theme","default":"dark","options":themes,},{"name":"Auto-hide item contents for large items","js_name":"auto-hide-large-items","default":true,},{"name":"Auto-hide item methods' documentation","js_name":"auto-hide-method-docs","default":false,},{"name":"Auto-hide trait implementation documentation","js_name":"auto-hide-trait-implementations","default":false,},{"name":"Directly go to item in search if there is only one result","js_name":"go-to-only-result","default":false,},{"name":"Show line numbers on code examples","js_name":"line-numbers","default":false,},{"name":"Disable keyboard shortcuts","js_name":"disable-shortcuts","default":false,},];const elementKind=isSettingsPage?"section":"div";const innerHTML=`
${buildSettingsPageSections(settings)}
`;const el=document.createElement(elementKind);el.id="settings";if(!isSettingsPage){el.className="popover"}el.innerHTML=innerHTML;if(isSettingsPage){document.getElementById(MAIN_ID).appendChild(el)}else{el.setAttribute("tabindex","-1");getSettingsButton().appendChild(el)}return el}const settingsMenu=buildSettingsPage();function displaySettings(){settingsMenu.style.display=""}function settingsBlurHandler(event){blurHandler(event,getSettingsButton(),window.hidePopoverMenus)}if(isSettingsPage){getSettingsButton().onclick=function(event){event.preventDefault()}}else{const settingsButton=getSettingsButton();const settingsMenu=document.getElementById("settings");settingsButton.onclick=function(event){if(elemIsInParent(event.target,settingsMenu)){return}event.preventDefault();const shouldDisplaySettings=settingsMenu.style.display==="none";window.hidePopoverMenus();if(shouldDisplaySettings){displaySettings()}};settingsButton.onblur=settingsBlurHandler;settingsButton.querySelector("a").onblur=settingsBlurHandler;onEachLazy(settingsMenu.querySelectorAll("input"),el=>{el.onblur=settingsBlurHandler});settingsMenu.onblur=settingsBlurHandler}setTimeout(()=>{setEvents(settingsMenu);if(!isSettingsPage){displaySettings()}removeClass(getSettingsButton(),"rotate")},0)})() \ No newline at end of file diff --git a/docs/source-files.js b/docs/source-files.js new file mode 100644 index 0000000000..ff13e14dd4 --- /dev/null +++ b/docs/source-files.js @@ -0,0 +1,7 @@ +var sourcesIndex = JSON.parse('{\ +"halo2":["",[],["lib.rs"]],\ +"halo2_proofs":["",[["circuit",[["floor_planner",[],["single_pass.rs"]]],["floor_planner.rs","layouter.rs","value.rs"]],["dev",[["failure",[],["emitter.rs"]]],["failure.rs","gates.rs","metadata.rs","util.rs"]],["plonk",[["circuit",[],["compress_selectors.rs"]],["lookup",[],["prover.rs","verifier.rs"]],["permutation",[],["keygen.rs","prover.rs","verifier.rs"]],["vanishing",[],["prover.rs","verifier.rs"]],["verifier",[],["batch.rs"]]],["assigned.rs","circuit.rs","error.rs","evaluation.rs","keygen.rs","lookup.rs","permutation.rs","prover.rs","vanishing.rs","verifier.rs"]],["poly",[["ipa",[["commitment",[],["prover.rs","verifier.rs"]],["multiopen",[],["prover.rs","verifier.rs"]]],["commitment.rs","mod.rs","msm.rs","multiopen.rs","strategy.rs"]],["kzg",[["multiopen",[["gwc",[],["prover.rs","verifier.rs"]],["shplonk",[],["prover.rs","verifier.rs"]]],["gwc.rs","shplonk.rs"]]],["commitment.rs","mod.rs","msm.rs","multiopen.rs","strategy.rs"]]],["commitment.rs","domain.rs","query.rs","strategy.rs"]]],["arithmetic.rs","circuit.rs","dev.rs","helpers.rs","lib.rs","multicore.rs","plonk.rs","poly.rs","transcript.rs"]],\ +"halo2curves":["",[["bn256",[],["curve.rs","engine.rs","fq.rs","fq12.rs","fq2.rs","fq6.rs","fr.rs","mod.rs"]],["derive",[],["curve.rs","field.rs","mod.rs"]],["pasta",[],["mod.rs"]],["secp256k1",[],["curve.rs","fp.rs","fq.rs","mod.rs"]]],["arithmetic.rs","lib.rs","pairing.rs","serde.rs"]],\ +"poseidon":["",[],["grain.rs","lib.rs","matrix.rs","permutation.rs","poseidon.rs","spec.rs"]]\ +}'); +createSourceSidebar(); diff --git a/docs/source-script.js b/docs/source-script.js new file mode 100644 index 0000000000..d8b770a425 --- /dev/null +++ b/docs/source-script.js @@ -0,0 +1 @@ +"use strict";(function(){const rootPath=document.getElementById("rustdoc-vars").attributes["data-root-path"].value;const NAME_OFFSET=0;const DIRS_OFFSET=1;const FILES_OFFSET=2;function closeSidebarIfMobile(){if(window.innerWidth"){window.rustdocMobileScrollLock();addClass(document.documentElement,"source-sidebar-expanded");child.innerText="<";updateLocalStorage("source-sidebar-show","true")}else{window.rustdocMobileScrollUnlock();removeClass(document.documentElement,"source-sidebar-expanded");child.innerText=">";updateLocalStorage("source-sidebar-show","false")}}function createSidebarToggle(){const sidebarToggle=document.createElement("div");sidebarToggle.id="sidebar-toggle";const inner=document.createElement("button");if(getCurrentValue("source-sidebar-show")==="true"){inner.innerText="<"}else{inner.innerText=">"}inner.onclick=toggleSidebar;sidebarToggle.appendChild(inner);return sidebarToggle}function createSourceSidebar(){const container=document.querySelector("nav.sidebar");const sidebarToggle=createSidebarToggle();container.insertBefore(sidebarToggle,container.firstChild);const sidebar=document.createElement("div");sidebar.id="source-sidebar";let hasFoundFile=false;const title=document.createElement("div");title.className="title";title.innerText="Files";sidebar.appendChild(title);Object.keys(sourcesIndex).forEach(key=>{sourcesIndex[key][NAME_OFFSET]=key;hasFoundFile=createDirEntry(sourcesIndex[key],sidebar,"",hasFoundFile)});container.appendChild(sidebar);const selected_elem=sidebar.getElementsByClassName("selected")[0];if(typeof selected_elem!=="undefined"){selected_elem.focus()}}const lineNumbersRegex=/^#?(\d+)(?:-(\d+))?$/;function highlightSourceLines(match){if(typeof match==="undefined"){match=window.location.hash.match(lineNumbersRegex)}if(!match){return}let from=parseInt(match[1],10);let to=from;if(typeof match[2]!=="undefined"){to=parseInt(match[2],10)}if(to{onEachLazy(e.getElementsByTagName("span"),i_e=>{removeClass(i_e,"line-highlighted")})});for(let i=from;i<=to;++i){elem=document.getElementById(i);if(!elem){break}addClass(elem,"line-highlighted")}}const handleSourceHighlight=(function(){let prev_line_id=0;const set_fragment=name=>{const x=window.scrollX,y=window.scrollY;if(browserSupportsHistoryApi()){history.replaceState(null,null,"#"+name);highlightSourceLines()}else{location.replace("#"+name)}window.scrollTo(x,y)};return ev=>{let cur_line_id=parseInt(ev.target.id,10);if(isNaN(cur_line_id)){return}ev.preventDefault();if(ev.shiftKey&&prev_line_id){if(prev_line_id>cur_line_id){const tmp=prev_line_id;prev_line_id=cur_line_id;cur_line_id=tmp}set_fragment(prev_line_id+"-"+cur_line_id)}else{prev_line_id=cur_line_id;set_fragment(cur_line_id)}}}());window.addEventListener("hashchange",()=>{const match=window.location.hash.match(lineNumbersRegex);if(match){return highlightSourceLines(match)}});onEachLazy(document.getElementsByClassName("src-line-numbers"),el=>{el.addEventListener("click",handleSourceHighlight)});highlightSourceLines();window.createSourceSidebar=createSourceSidebar})() \ No newline at end of file diff --git a/docs/src/halo2/lib.rs.html b/docs/src/halo2/lib.rs.html new file mode 100644 index 0000000000..66c404cdf3 --- /dev/null +++ b/docs/src/halo2/lib.rs.html @@ -0,0 +1,16 @@ +lib.rs - source
1
+2
+3
+4
+5
+6
+7
+
//! # halo2
+
+#![cfg_attr(docsrs, feature(doc_cfg))]
+#![deny(rustdoc::broken_intra_doc_links)]
+#![deny(missing_debug_implementations)]
+#![deny(missing_docs)]
+#![deny(unsafe_code)]
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/arithmetic.rs.html b/docs/src/halo2_proofs/arithmetic.rs.html new file mode 100644 index 0000000000..6b09289366 --- /dev/null +++ b/docs/src/halo2_proofs/arithmetic.rs.html @@ -0,0 +1,1018 @@ +arithmetic.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+
//! This module provides common utilities, traits and structures for group,
+//! field and polynomial arithmetic.
+
+use super::multicore;
+pub use ff::Field;
+use group::{
+    ff::{BatchInvert, PrimeField},
+    Curve, Group as _,
+};
+
+pub use halo2curves::{CurveAffine, CurveExt, FieldExt, Group};
+
+fn multiexp_serial<C: CurveAffine>(coeffs: &[C::Scalar], bases: &[C], acc: &mut C::Curve) {
+    let coeffs: Vec<_> = coeffs.iter().map(|a| a.to_repr()).collect();
+
+    let c = if bases.len() < 4 {
+        1
+    } else if bases.len() < 32 {
+        3
+    } else {
+        (f64::from(bases.len() as u32)).ln().ceil() as usize
+    };
+
+    fn get_at<F: PrimeField>(segment: usize, c: usize, bytes: &F::Repr) -> usize {
+        let skip_bits = segment * c;
+        let skip_bytes = skip_bits / 8;
+
+        if skip_bytes >= 32 {
+            return 0;
+        }
+
+        let mut v = [0; 8];
+        for (v, o) in v.iter_mut().zip(bytes.as_ref()[skip_bytes..].iter()) {
+            *v = *o;
+        }
+
+        let mut tmp = u64::from_le_bytes(v);
+        tmp >>= skip_bits - (skip_bytes * 8);
+        tmp = tmp % (1 << c);
+
+        tmp as usize
+    }
+
+    let segments = (256 / c) + 1;
+
+    for current_segment in (0..segments).rev() {
+        for _ in 0..c {
+            *acc = acc.double();
+        }
+
+        #[derive(Clone, Copy)]
+        enum Bucket<C: CurveAffine> {
+            None,
+            Affine(C),
+            Projective(C::Curve),
+        }
+
+        impl<C: CurveAffine> Bucket<C> {
+            fn add_assign(&mut self, other: &C) {
+                *self = match *self {
+                    Bucket::None => Bucket::Affine(*other),
+                    Bucket::Affine(a) => Bucket::Projective(a + *other),
+                    Bucket::Projective(mut a) => {
+                        a += *other;
+                        Bucket::Projective(a)
+                    }
+                }
+            }
+
+            fn add(self, mut other: C::Curve) -> C::Curve {
+                match self {
+                    Bucket::None => other,
+                    Bucket::Affine(a) => {
+                        other += a;
+                        other
+                    }
+                    Bucket::Projective(a) => other + &a,
+                }
+            }
+        }
+
+        let mut buckets: Vec<Bucket<C>> = vec![Bucket::None; (1 << c) - 1];
+
+        for (coeff, base) in coeffs.iter().zip(bases.iter()) {
+            let coeff = get_at::<C::Scalar>(current_segment, c, coeff);
+            if coeff != 0 {
+                buckets[coeff - 1].add_assign(base);
+            }
+        }
+
+        // Summation by parts
+        // e.g. 3a + 2b + 1c = a +
+        //                    (a) + b +
+        //                    ((a) + b) + c
+        let mut running_sum = C::Curve::identity();
+        for exp in buckets.into_iter().rev() {
+            running_sum = exp.add(running_sum);
+            *acc = *acc + &running_sum;
+        }
+    }
+}
+
+/// Performs a small multi-exponentiation operation.
+/// Uses the double-and-add algorithm with doublings shared across points.
+pub fn small_multiexp<C: CurveAffine>(coeffs: &[C::Scalar], bases: &[C]) -> C::Curve {
+    let coeffs: Vec<_> = coeffs.iter().map(|a| a.to_repr()).collect();
+    let mut acc = C::Curve::identity();
+
+    // for byte idx
+    for byte_idx in (0..32).rev() {
+        // for bit idx
+        for bit_idx in (0..8).rev() {
+            acc = acc.double();
+            // for each coeff
+            for coeff_idx in 0..coeffs.len() {
+                let byte = coeffs[coeff_idx].as_ref()[byte_idx];
+                if ((byte >> bit_idx) & 1) != 0 {
+                    acc += bases[coeff_idx];
+                }
+            }
+        }
+    }
+
+    acc
+}
+
+/// Performs a multi-exponentiation operation.
+///
+/// This function will panic if coeffs and bases have a different length.
+///
+/// This will use multithreading if beneficial.
+pub fn best_multiexp<C: CurveAffine>(coeffs: &[C::Scalar], bases: &[C]) -> C::Curve {
+    assert_eq!(coeffs.len(), bases.len());
+
+    let num_threads = multicore::current_num_threads();
+    if coeffs.len() > num_threads {
+        let chunk = coeffs.len() / num_threads;
+        let num_chunks = coeffs.chunks(chunk).len();
+        let mut results = vec![C::Curve::identity(); num_chunks];
+        multicore::scope(|scope| {
+            let chunk = coeffs.len() / num_threads;
+
+            for ((coeffs, bases), acc) in coeffs
+                .chunks(chunk)
+                .zip(bases.chunks(chunk))
+                .zip(results.iter_mut())
+            {
+                scope.spawn(move |_| {
+                    multiexp_serial(coeffs, bases, acc);
+                });
+            }
+        });
+        results.iter().fold(C::Curve::identity(), |a, b| a + b)
+    } else {
+        let mut acc = C::Curve::identity();
+        multiexp_serial(coeffs, bases, &mut acc);
+        acc
+    }
+}
+
+/// Performs a radix-$2$ Fast-Fourier Transformation (FFT) on a vector of size
+/// $n = 2^k$, when provided `log_n` = $k$ and an element of multiplicative
+/// order $n$ called `omega` ($\omega$). The result is that the vector `a`, when
+/// interpreted as the coefficients of a polynomial of degree $n - 1$, is
+/// transformed into the evaluations of this polynomial at each of the $n$
+/// distinct powers of $\omega$. This transformation is invertible by providing
+/// $\omega^{-1}$ in place of $\omega$ and dividing each resulting field element
+/// by $n$.
+///
+/// This will use multithreading if beneficial.
+pub fn best_fft<G: Group>(a: &mut [G], omega: G::Scalar, log_n: u32) {
+    fn bitreverse(mut n: usize, l: usize) -> usize {
+        let mut r = 0;
+        for _ in 0..l {
+            r = (r << 1) | (n & 1);
+            n >>= 1;
+        }
+        r
+    }
+
+    let threads = multicore::current_num_threads();
+    let log_threads = log2_floor(threads);
+    let n = a.len() as usize;
+    assert_eq!(n, 1 << log_n);
+
+    for k in 0..n {
+        let rk = bitreverse(k, log_n as usize);
+        if k < rk {
+            a.swap(rk, k);
+        }
+    }
+
+    // precompute twiddle factors
+    let twiddles: Vec<_> = (0..(n / 2) as usize)
+        .scan(G::Scalar::one(), |w, _| {
+            let tw = *w;
+            w.group_scale(&omega);
+            Some(tw)
+        })
+        .collect();
+
+    if log_n <= log_threads {
+        let mut chunk = 2_usize;
+        let mut twiddle_chunk = (n / 2) as usize;
+        for _ in 0..log_n {
+            a.chunks_mut(chunk).for_each(|coeffs| {
+                let (left, right) = coeffs.split_at_mut(chunk / 2);
+
+                // case when twiddle factor is one
+                let (a, left) = left.split_at_mut(1);
+                let (b, right) = right.split_at_mut(1);
+                let t = b[0];
+                b[0] = a[0];
+                a[0].group_add(&t);
+                b[0].group_sub(&t);
+
+                left.iter_mut()
+                    .zip(right.iter_mut())
+                    .enumerate()
+                    .for_each(|(i, (a, b))| {
+                        let mut t = *b;
+                        t.group_scale(&twiddles[(i + 1) * twiddle_chunk]);
+                        *b = *a;
+                        a.group_add(&t);
+                        b.group_sub(&t);
+                    });
+            });
+            chunk *= 2;
+            twiddle_chunk /= 2;
+        }
+    } else {
+        recursive_butterfly_arithmetic(a, n, 1, &twiddles)
+    }
+}
+
+/// This perform recursive butterfly arithmetic
+pub fn recursive_butterfly_arithmetic<G: Group>(
+    a: &mut [G],
+    n: usize,
+    twiddle_chunk: usize,
+    twiddles: &[G::Scalar],
+) {
+    if n == 2 {
+        let t = a[1];
+        a[1] = a[0];
+        a[0].group_add(&t);
+        a[1].group_sub(&t);
+    } else {
+        let (left, right) = a.split_at_mut(n / 2);
+        rayon::join(
+            || recursive_butterfly_arithmetic(left, n / 2, twiddle_chunk * 2, twiddles),
+            || recursive_butterfly_arithmetic(right, n / 2, twiddle_chunk * 2, twiddles),
+        );
+
+        // case when twiddle factor is one
+        let (a, left) = left.split_at_mut(1);
+        let (b, right) = right.split_at_mut(1);
+        let t = b[0];
+        b[0] = a[0];
+        a[0].group_add(&t);
+        b[0].group_sub(&t);
+
+        left.iter_mut()
+            .zip(right.iter_mut())
+            .enumerate()
+            .for_each(|(i, (a, b))| {
+                let mut t = *b;
+                t.group_scale(&twiddles[(i + 1) * twiddle_chunk]);
+                *b = *a;
+                a.group_add(&t);
+                b.group_sub(&t);
+            });
+    }
+}
+
+/// Convert coefficient bases group elements to lagrange basis by inverse FFT.
+pub fn g_to_lagrange<C: CurveAffine>(g_projective: Vec<C::Curve>, k: u32) -> Vec<C> {
+    let n_inv = C::Scalar::TWO_INV.pow_vartime(&[k as u64, 0, 0, 0]);
+    let mut omega_inv = C::Scalar::ROOT_OF_UNITY_INV;
+    for _ in k..C::Scalar::S {
+        omega_inv = omega_inv.square();
+    }
+
+    let mut g_lagrange_projective = g_projective;
+    best_fft(&mut g_lagrange_projective, omega_inv, k);
+    parallelize(&mut g_lagrange_projective, |g, _| {
+        for g in g.iter_mut() {
+            *g *= n_inv;
+        }
+    });
+
+    let mut g_lagrange = vec![C::identity(); 1 << k];
+    parallelize(&mut g_lagrange, |g_lagrange, starts| {
+        C::Curve::batch_normalize(
+            &g_lagrange_projective[starts..(starts + g_lagrange.len())],
+            g_lagrange,
+        );
+    });
+
+    g_lagrange
+}
+
+/// This evaluates a provided polynomial (in coefficient form) at `point`.
+pub fn eval_polynomial<F: Field>(poly: &[F], point: F) -> F {
+    fn evaluate<F: Field>(poly: &[F], point: F) -> F {
+        poly.iter()
+            .rev()
+            .fold(F::zero(), |acc, coeff| acc * point + coeff)
+    }
+    let n = poly.len();
+    let num_threads = multicore::current_num_threads();
+    if n * 2 < num_threads {
+        evaluate(poly, point)
+    } else {
+        let chunk_size = (n + num_threads - 1) / num_threads;
+        let mut parts = vec![F::zero(); num_threads];
+        multicore::scope(|scope| {
+            for (chunk_idx, (out, poly)) in
+                parts.chunks_mut(1).zip(poly.chunks(chunk_size)).enumerate()
+            {
+                scope.spawn(move |_| {
+                    let start = chunk_idx * chunk_size;
+                    out[0] = evaluate(poly, point) * point.pow_vartime(&[start as u64, 0, 0, 0]);
+                });
+            }
+        });
+        parts.iter().fold(F::zero(), |acc, coeff| acc + coeff)
+    }
+}
+
+/// This computes the inner product of two vectors `a` and `b`.
+///
+/// This function will panic if the two vectors are not the same size.
+pub fn compute_inner_product<F: Field>(a: &[F], b: &[F]) -> F {
+    // TODO: parallelize?
+    assert_eq!(a.len(), b.len());
+
+    let mut acc = F::zero();
+    for (a, b) in a.iter().zip(b.iter()) {
+        acc += (*a) * (*b);
+    }
+
+    acc
+}
+
+/// Divides polynomial `a` in `X` by `X - b` with
+/// no remainder.
+pub fn kate_division<'a, F: Field, I: IntoIterator<Item = &'a F>>(a: I, mut b: F) -> Vec<F>
+where
+    I::IntoIter: DoubleEndedIterator + ExactSizeIterator,
+{
+    b = -b;
+    let a = a.into_iter();
+
+    let mut q = vec![F::zero(); a.len() - 1];
+
+    let mut tmp = F::zero();
+    for (q, r) in q.iter_mut().rev().zip(a.rev()) {
+        let mut lead_coeff = *r;
+        lead_coeff.sub_assign(&tmp);
+        *q = lead_coeff;
+        tmp = lead_coeff;
+        tmp.mul_assign(&b);
+    }
+
+    q
+}
+
+/// This simple utility function will parallelize an operation that is to be
+/// performed over a mutable slice.
+pub fn parallelize<T: Send, F: Fn(&mut [T], usize) + Send + Sync + Clone>(v: &mut [T], f: F) {
+    let n = v.len();
+    let num_threads = multicore::current_num_threads();
+    let mut chunk = (n as usize) / num_threads;
+    if chunk < num_threads {
+        chunk = n as usize;
+    }
+
+    multicore::scope(|scope| {
+        for (chunk_num, v) in v.chunks_mut(chunk).enumerate() {
+            let f = f.clone();
+            scope.spawn(move |_| {
+                let start = chunk_num * chunk;
+                f(v, start);
+            });
+        }
+    });
+}
+
+fn log2_floor(num: usize) -> u32 {
+    assert!(num > 0);
+
+    let mut pow = 0;
+
+    while (1 << (pow + 1)) <= num {
+        pow += 1;
+    }
+
+    pow
+}
+
+/// Returns coefficients of an n - 1 degree polynomial given a set of n points
+/// and their evaluations. This function will panic if two values in `points`
+/// are the same.
+pub fn lagrange_interpolate<F: FieldExt>(points: &[F], evals: &[F]) -> Vec<F> {
+    assert_eq!(points.len(), evals.len());
+    if points.len() == 1 {
+        // Constant polynomial
+        vec![evals[0]]
+    } else {
+        let mut denoms = Vec::with_capacity(points.len());
+        for (j, x_j) in points.iter().enumerate() {
+            let mut denom = Vec::with_capacity(points.len() - 1);
+            for x_k in points
+                .iter()
+                .enumerate()
+                .filter(|&(k, _)| k != j)
+                .map(|a| a.1)
+            {
+                denom.push(*x_j - x_k);
+            }
+            denoms.push(denom);
+        }
+        // Compute (x_j - x_k)^(-1) for each j != i
+        denoms.iter_mut().flat_map(|v| v.iter_mut()).batch_invert();
+
+        let mut final_poly = vec![F::zero(); points.len()];
+        for (j, (denoms, eval)) in denoms.into_iter().zip(evals.iter()).enumerate() {
+            let mut tmp: Vec<F> = Vec::with_capacity(points.len());
+            let mut product = Vec::with_capacity(points.len() - 1);
+            tmp.push(F::one());
+            for (x_k, denom) in points
+                .iter()
+                .enumerate()
+                .filter(|&(k, _)| k != j)
+                .map(|a| a.1)
+                .zip(denoms.into_iter())
+            {
+                product.resize(tmp.len() + 1, F::zero());
+                for ((a, b), product) in tmp
+                    .iter()
+                    .chain(std::iter::once(&F::zero()))
+                    .zip(std::iter::once(&F::zero()).chain(tmp.iter()))
+                    .zip(product.iter_mut())
+                {
+                    *product = *a * (-denom * x_k) + *b * denom;
+                }
+                std::mem::swap(&mut tmp, &mut product);
+            }
+            assert_eq!(tmp.len(), points.len());
+            assert_eq!(product.len(), points.len() - 1);
+            for (final_coeff, interpolation_coeff) in final_poly.iter_mut().zip(tmp.into_iter()) {
+                *final_coeff += interpolation_coeff * eval;
+            }
+        }
+        final_poly
+    }
+}
+
+pub(crate) fn evaluate_vanishing_polynomial<F: FieldExt>(roots: &[F], z: F) -> F {
+    fn evaluate<F: FieldExt>(roots: &[F], z: F) -> F {
+        roots.iter().fold(F::one(), |acc, point| (z - point) * acc)
+    }
+    let n = roots.len();
+    let num_threads = multicore::current_num_threads();
+    if n * 2 < num_threads {
+        evaluate(roots, z)
+    } else {
+        let chunk_size = (n + num_threads - 1) / num_threads;
+        let mut parts = vec![F::one(); num_threads];
+        multicore::scope(|scope| {
+            for (out, roots) in parts.chunks_mut(1).zip(roots.chunks(chunk_size)) {
+                scope.spawn(move |_| out[0] = evaluate(roots, z));
+            }
+        });
+        parts.iter().fold(F::one(), |acc, part| acc * part)
+    }
+}
+
+pub(crate) fn powers<F: FieldExt>(base: F) -> impl Iterator<Item = F> {
+    std::iter::successors(Some(F::one()), move |power| Some(base * power))
+}
+
+#[cfg(test)]
+use rand_core::OsRng;
+
+#[cfg(test)]
+use crate::halo2curves::pasta::Fp;
+
+#[test]
+fn test_lagrange_interpolate() {
+    let rng = OsRng;
+
+    let points = (0..5).map(|_| Fp::random(rng)).collect::<Vec<_>>();
+    let evals = (0..5).map(|_| Fp::random(rng)).collect::<Vec<_>>();
+
+    for coeffs in 0..5 {
+        let points = &points[0..coeffs];
+        let evals = &evals[0..coeffs];
+
+        let poly = lagrange_interpolate(points, evals);
+        assert_eq!(poly.len(), points.len());
+
+        for (point, eval) in points.iter().zip(evals) {
+            assert_eq!(eval_polynomial(&poly, *point), *eval);
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/circuit.rs.html b/docs/src/halo2_proofs/circuit.rs.html new file mode 100644 index 0000000000..4ea45215cd --- /dev/null +++ b/docs/src/halo2_proofs/circuit.rs.html @@ -0,0 +1,1132 @@ +circuit.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+
//! Traits and structs for implementing circuit components.
+
+use std::{convert::TryInto, fmt, marker::PhantomData};
+
+use ff::Field;
+
+use crate::{
+    arithmetic::FieldExt,
+    plonk::{
+        Advice, Any, Assigned, Challenge, Column, Error, Fixed, Instance, Selector, TableColumn,
+    },
+};
+
+mod value;
+pub use value::Value;
+
+pub mod floor_planner;
+pub use floor_planner::single_pass::SimpleFloorPlanner;
+
+pub mod layouter;
+
+/// A chip implements a set of instructions that can be used by gadgets.
+///
+/// The chip stores state that is required at circuit synthesis time in
+/// [`Chip::Config`], which can be fetched via [`Chip::config`].
+///
+/// The chip also loads any fixed configuration needed at synthesis time
+/// using its own implementation of `load`, and stores it in [`Chip::Loaded`].
+/// This can be accessed via [`Chip::loaded`].
+pub trait Chip<F: FieldExt>: Sized {
+    /// A type that holds the configuration for this chip, and any other state it may need
+    /// during circuit synthesis, that can be derived during [`Circuit::configure`].
+    ///
+    /// [`Circuit::configure`]: crate::plonk::Circuit::configure
+    type Config: fmt::Debug + Clone;
+
+    /// A type that holds any general chip state that needs to be loaded at the start of
+    /// [`Circuit::synthesize`]. This might simply be `()` for some chips.
+    ///
+    /// [`Circuit::synthesize`]: crate::plonk::Circuit::synthesize
+    type Loaded: fmt::Debug + Clone;
+
+    /// The chip holds its own configuration.
+    fn config(&self) -> &Self::Config;
+
+    /// Provides access to general chip state loaded at the beginning of circuit
+    /// synthesis.
+    ///
+    /// Panics if called before `Chip::load`.
+    fn loaded(&self) -> &Self::Loaded;
+}
+
+/// Index of a region in a layouter
+#[derive(Clone, Copy, Debug)]
+pub struct RegionIndex(usize);
+
+impl From<usize> for RegionIndex {
+    fn from(idx: usize) -> RegionIndex {
+        RegionIndex(idx)
+    }
+}
+
+impl std::ops::Deref for RegionIndex {
+    type Target = usize;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+/// Starting row of a region in a layouter
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+pub struct RegionStart(usize);
+
+impl From<usize> for RegionStart {
+    fn from(idx: usize) -> RegionStart {
+        RegionStart(idx)
+    }
+}
+
+impl std::ops::Deref for RegionStart {
+    type Target = usize;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+/// A pointer to a cell within a circuit.
+#[derive(Clone, Copy, Debug)]
+pub struct Cell {
+    /// Identifies the region in which this cell resides.
+    // region_index: RegionIndex,
+    /// The relative offset of this cell within its region.
+    row_offset: usize,
+    /// The column of this cell.
+    column: Column<Any>,
+}
+
+impl Cell {
+    /// Returns row offset
+    pub fn row_offset(&self) -> usize {
+        self.row_offset
+    }
+    /// Returns reference to column
+    pub fn column(&self) -> &Column<Any> {
+        &self.column
+    }
+}
+
+/// An assigned cell.
+#[derive(Clone, Debug)]
+pub struct AssignedCell<V, F: Field> {
+    value: Value<V>,
+    cell: Cell,
+    _marker: PhantomData<F>,
+}
+
+impl<V, F: Field> AssignedCell<V, F> {
+    /// Returns the value of the [`AssignedCell`].
+    pub fn value(&self) -> Value<&V> {
+        self.value.as_ref()
+    }
+
+    /// Returns the cell.
+    pub fn cell(&self) -> &Cell {
+        &self.cell
+    }
+
+    pub fn row_offset(&self) -> usize {
+        self.cell.row_offset
+    }
+
+    pub fn column(&self) -> &Column<Any> {
+        &self.cell.column
+    }
+}
+
+impl<V, F: Field> AssignedCell<V, F>
+where
+    for<'v> Assigned<F>: From<&'v V>,
+{
+    /// Returns the field element value of the [`AssignedCell`].
+    pub fn value_field(&self) -> Value<Assigned<F>> {
+        self.value.to_field()
+    }
+}
+
+impl<F: Field> AssignedCell<Assigned<F>, F> {
+    /// Evaluates this assigned cell's value directly, performing an unbatched inversion
+    /// if necessary.
+    ///
+    /// If the denominator is zero, the returned cell's value is zero.
+    pub fn evaluate(self) -> AssignedCell<F, F> {
+        AssignedCell {
+            value: self.value.evaluate(),
+            cell: self.cell,
+            _marker: Default::default(),
+        }
+    }
+}
+
+impl<'v, F: Field> AssignedCell<&'v Assigned<F>, F> {
+    /// Copies the value to a given advice cell and constrains them to be equal.
+    ///
+    /// Returns an error if either this cell or the given cell are in columns
+    /// where equality has not been enabled.
+    pub fn copy_advice(
+        &self,
+        region: &mut Region<'_, F>,
+        column: Column<Advice>,
+        offset: usize,
+    ) -> AssignedCell<&'_ Assigned<F>, F> {
+        let assigned_cell = region
+            .assign_advice(column, offset, self.value.map(|v| *v))
+            .unwrap_or_else(|err| panic!("{err:?}"));
+        region.constrain_equal(&assigned_cell.cell, &self.cell);
+        assigned_cell
+    }
+}
+
+/// A region of the circuit in which a [`Chip`] can assign cells.
+///
+/// Inside a region, the chip may freely use relative offsets; the [`Layouter`] will
+/// treat these assignments as a single "region" within the circuit.
+///
+/// The [`Layouter`] is allowed to optimise between regions as it sees fit. Chips must use
+/// [`Region::constrain_equal`] to copy in variables assigned in other regions.
+///
+/// TODO: It would be great if we could constrain the columns in these types to be
+/// "logical" columns that are guaranteed to correspond to the chip (and have come from
+/// `Chip::Config`).
+#[derive(Debug)]
+pub struct Region<'r, F: Field> {
+    region: &'r mut dyn layouter::RegionLayouter<F>,
+}
+
+impl<'r, F: Field> From<&'r mut dyn layouter::RegionLayouter<F>> for Region<'r, F> {
+    fn from(region: &'r mut dyn layouter::RegionLayouter<F>) -> Self {
+        Region { region }
+    }
+}
+
+impl<'r, F: Field> Region<'r, F> {
+    /// Enables a selector at the given offset.
+    pub(crate) fn enable_selector<A, AR>(
+        &mut self,
+        annotation: A,
+        selector: &Selector,
+        offset: usize,
+    ) -> Result<(), Error>
+    where
+        A: Fn() -> AR,
+        AR: Into<String>,
+    {
+        self.region
+            .enable_selector(&|| annotation().into(), selector, offset)
+    }
+
+    /// Assign an advice column value (witness).
+    ///
+    /// Even though `to` has `FnMut` bounds, it is guaranteed to be called at most once.
+    // The returned &'v Assigned<F> lives longer than the mutable borrow of &mut self
+    pub fn assign_advice<'v>(
+        //, V, VR, A, AR>(
+        &mut self,
+        //annotation: A,
+        column: Column<Advice>,
+        offset: usize,
+        to: Value<impl Into<Assigned<F>>>, // For now only accept Value<F>, later might change to Value<Assigned<F>> for batch inversion
+    ) -> Result<AssignedCell<&'v Assigned<F>, F>, Error> {
+        //let mut value = Value::unknown();
+        self.region.assign_advice(
+            //&|| annotation().into(),
+            column,
+            offset,
+            to.map(|v| v.into()),
+        )
+
+        /*
+        Ok(AssignedCell {
+            value,
+            cell,
+            _marker: PhantomData,
+        })
+        */
+    }
+
+    /// Assigns a constant value to the column `advice` at `offset` within this region.
+    ///
+    /// The constant value will be assigned to a cell within one of the fixed columns
+    /// configured via `ConstraintSystem::enable_constant`.
+    ///
+    /// Returns the advice cell.
+    pub fn assign_advice_from_constant<VR, A, AR>(
+        &mut self,
+        annotation: A,
+        column: Column<Advice>,
+        offset: usize,
+        constant: VR,
+    ) -> Result<AssignedCell<VR, F>, Error>
+    where
+        for<'vr> Assigned<F>: From<&'vr VR>,
+        A: Fn() -> AR,
+        AR: Into<String>,
+    {
+        let cell = self.region.assign_advice_from_constant(
+            &|| annotation().into(),
+            column,
+            offset,
+            (&constant).into(),
+        )?;
+
+        Ok(AssignedCell {
+            value: Value::known(constant),
+            cell,
+            _marker: PhantomData,
+        })
+    }
+
+    /// Assign the value of the instance column's cell at absolute location
+    /// `row` to the column `advice` at `offset` within this region.
+    ///
+    /// Returns the advice cell, and its value if known.
+    pub fn assign_advice_from_instance<A, AR>(
+        &mut self,
+        annotation: A,
+        instance: Column<Instance>,
+        row: usize,
+        advice: Column<Advice>,
+        offset: usize,
+    ) -> Result<AssignedCell<F, F>, Error>
+    where
+        A: Fn() -> AR,
+        AR: Into<String>,
+    {
+        let (cell, value) = self.region.assign_advice_from_instance(
+            &|| annotation().into(),
+            instance,
+            row,
+            advice,
+            offset,
+        )?;
+
+        Ok(AssignedCell {
+            value,
+            cell,
+            _marker: PhantomData,
+        })
+    }
+
+    /// Assign a fixed value.
+    ///
+    /// Even though `to` has `FnMut` bounds, it is guaranteed to be called at most once.
+    pub fn assign_fixed(
+        &mut self,
+        // annotation: A,
+        column: Column<Fixed>,
+        offset: usize,
+        to: impl Into<Assigned<F>>,
+    ) -> Cell {
+        self.region.assign_fixed(column, offset, to.into())
+        /*
+        Ok(AssignedCell {
+            value,
+            cell,
+            _marker: PhantomData,
+        })
+        */
+    }
+
+    /// Constrains a cell to have a constant value.
+    ///
+    /// Returns an error if the cell is in a column where equality has not been enabled.
+    pub fn constrain_constant<VR>(&mut self, cell: Cell, constant: VR) -> Result<(), Error>
+    where
+        VR: Into<Assigned<F>>,
+    {
+        self.region.constrain_constant(cell, constant.into())
+    }
+
+    /// Constrains two cells to have the same value.
+    ///
+    /// Returns an error if either of the cells are in columns where equality
+    /// has not been enabled.
+    pub fn constrain_equal(&mut self, left: &Cell, right: &Cell) {
+        self.region.constrain_equal(left, right);
+    }
+
+    /// Queries the value of the given challenge.
+    ///
+    /// Returns `Value::unknown()` if the current synthesis phase is before the challenge can be queried.
+    pub fn get_challenge(&self, challenge: Challenge) -> Value<F> {
+        self.region.get_challenge(challenge)
+    }
+
+    /// Commit advice columns in current phase and squeeze challenges.
+    /// This can be called DURING synthesize.
+    pub fn next_phase(&mut self) {
+        self.region.next_phase();
+    }
+}
+
+/// A lookup table in the circuit.
+#[derive(Debug)]
+pub struct Table<'r, F: Field> {
+    table: &'r mut dyn layouter::TableLayouter<F>,
+}
+
+impl<'r, F: Field> From<&'r mut dyn layouter::TableLayouter<F>> for Table<'r, F> {
+    fn from(table: &'r mut dyn layouter::TableLayouter<F>) -> Self {
+        Table { table }
+    }
+}
+
+impl<'r, F: Field> Table<'r, F> {
+    /// Assigns a fixed value to a table cell.
+    ///
+    /// Returns an error if the table cell has already been assigned to.
+    ///
+    /// Even though `to` has `FnMut` bounds, it is guaranteed to be called at most once.
+    pub fn assign_cell<'v, V, VR, A, AR>(
+        &'v mut self,
+        annotation: A,
+        column: TableColumn,
+        offset: usize,
+        mut to: V,
+    ) -> Result<(), Error>
+    where
+        V: FnMut() -> Value<VR> + 'v,
+        VR: Into<Assigned<F>>,
+        A: Fn() -> AR,
+        AR: Into<String>,
+    {
+        self.table
+            .assign_cell(&|| annotation().into(), column, offset, &mut || {
+                to().into_field()
+            })
+    }
+}
+
+/// A layout strategy within a circuit. The layouter is chip-agnostic and applies its
+/// strategy to the context and config it is given.
+///
+/// This abstracts over the circuit assignments, handling row indices etc.
+///
+pub trait Layouter<F: Field> {
+    /// Represents the type of the "root" of this layouter, so that nested namespaces
+    /// can minimize indirection.
+    type Root: Layouter<F>;
+
+    /// Assign a region of gates to an absolute row number.
+    ///
+    /// Inside the closure, the chip may freely use relative offsets; the `Layouter` will
+    /// treat these assignments as a single "region" within the circuit. Outside this
+    /// closure, the `Layouter` is allowed to optimise as it sees fit.
+    ///
+    /// ```ignore
+    /// fn assign_region(&mut self, || "region name", |region| {
+    ///     let config = chip.config();
+    ///     region.assign_advice(config.a, offset, || { Some(value)});
+    /// });
+    /// ```
+    fn assign_region<A, AR, N, NR>(&mut self, name: N, assignment: A) -> Result<AR, Error>
+    where
+        A: FnOnce(Region<'_, F>) -> Result<AR, Error>,
+        N: Fn() -> NR,
+        NR: Into<String>;
+
+    /// Assign a table region to an absolute row number.
+    ///
+    /// ```ignore
+    /// fn assign_table(&mut self, || "table name", |table| {
+    ///     let config = chip.config();
+    ///     table.assign_fixed(config.a, offset, || { Some(value)});
+    /// });
+    /// ```
+    fn assign_table<A, N, NR>(&mut self, name: N, assignment: A) -> Result<(), Error>
+    where
+        A: FnMut(Table<'_, F>) -> Result<(), Error>,
+        N: Fn() -> NR,
+        NR: Into<String>;
+
+    /// Constrains a [`Cell`] to equal an instance column's row value at an
+    /// absolute position.
+    fn constrain_instance(&mut self, cell: Cell, column: Column<Instance>, row: usize);
+
+    /// Queries the value of the given challenge.
+    ///
+    /// Returns `Value::unknown()` if the current synthesis phase is before the challenge can be queried.
+    fn get_challenge(&self, challenge: Challenge) -> Value<F>;
+
+    /// Gets the "root" of this assignment, bypassing the namespacing.
+    ///
+    /// Not intended for downstream consumption; use [`Layouter::namespace`] instead.
+    fn get_root(&mut self) -> &mut Self::Root;
+
+    /// Creates a new (sub)namespace and enters into it.
+    ///
+    /// Not intended for downstream consumption; use [`Layouter::namespace`] instead.
+    fn push_namespace<NR, N>(&mut self, name_fn: N)
+    where
+        NR: Into<String>,
+        N: FnOnce() -> NR;
+
+    /// Exits out of the existing namespace.
+    ///
+    /// Not intended for downstream consumption; use [`Layouter::namespace`] instead.
+    fn pop_namespace(&mut self, gadget_name: Option<String>);
+
+    /// Enters into a namespace.
+    fn namespace<NR, N>(&mut self, name_fn: N) -> NamespacedLayouter<'_, F, Self::Root>
+    where
+        NR: Into<String>,
+        N: FnOnce() -> NR,
+    {
+        self.get_root().push_namespace(name_fn);
+
+        NamespacedLayouter(self.get_root(), PhantomData)
+    }
+}
+
+/// This is a "namespaced" layouter which borrows a `Layouter` (pushing a namespace
+/// context) and, when dropped, pops out of the namespace context.
+#[derive(Debug)]
+pub struct NamespacedLayouter<'a, F: Field, L: Layouter<F> + 'a>(&'a mut L, PhantomData<F>);
+
+impl<'a, F: Field, L: Layouter<F> + 'a> Layouter<F> for NamespacedLayouter<'a, F, L> {
+    type Root = L::Root;
+
+    fn assign_region<A, AR, N, NR>(&mut self, name: N, assignment: A) -> Result<AR, Error>
+    where
+        A: FnOnce(Region<'_, F>) -> Result<AR, Error>,
+        N: Fn() -> NR,
+        NR: Into<String>,
+    {
+        self.0.assign_region(name, assignment)
+    }
+
+    fn assign_table<A, N, NR>(&mut self, name: N, assignment: A) -> Result<(), Error>
+    where
+        A: FnMut(Table<'_, F>) -> Result<(), Error>,
+        N: Fn() -> NR,
+        NR: Into<String>,
+    {
+        self.0.assign_table(name, assignment)
+    }
+
+    fn constrain_instance(&mut self, cell: Cell, column: Column<Instance>, row: usize) {
+        self.0.constrain_instance(cell, column, row);
+    }
+
+    fn get_challenge(&self, challenge: Challenge) -> Value<F> {
+        self.0.get_challenge(challenge)
+    }
+
+    fn get_root(&mut self) -> &mut Self::Root {
+        self.0.get_root()
+    }
+
+    fn push_namespace<NR, N>(&mut self, _name_fn: N)
+    where
+        NR: Into<String>,
+        N: FnOnce() -> NR,
+    {
+        panic!("Only the root's push_namespace should be called");
+    }
+
+    fn pop_namespace(&mut self, _gadget_name: Option<String>) {
+        panic!("Only the root's pop_namespace should be called");
+    }
+}
+
+impl<'a, F: Field, L: Layouter<F> + 'a> Drop for NamespacedLayouter<'a, F, L> {
+    fn drop(&mut self) {
+        let gadget_name = {
+            #[cfg(feature = "gadget-traces")]
+            {
+                let mut gadget_name = None;
+                let mut is_second_frame = false;
+                backtrace::trace(|frame| {
+                    if is_second_frame {
+                        // Resolve this instruction pointer to a symbol name.
+                        backtrace::resolve_frame(frame, |symbol| {
+                            gadget_name = symbol.name().map(|name| format!("{:#}", name));
+                        });
+
+                        // We are done!
+                        false
+                    } else {
+                        // We want the next frame.
+                        is_second_frame = true;
+                        true
+                    }
+                });
+                gadget_name
+            }
+
+            #[cfg(not(feature = "gadget-traces"))]
+            None
+        };
+
+        self.get_root().pop_namespace(gadget_name);
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/circuit/floor_planner.rs.html b/docs/src/halo2_proofs/circuit/floor_planner.rs.html new file mode 100644 index 0000000000..05c78a16fb --- /dev/null +++ b/docs/src/halo2_proofs/circuit/floor_planner.rs.html @@ -0,0 +1,14 @@ +floor_planner.rs - source
1
+2
+3
+4
+5
+6
+
//! Implementations of common circuit floor planners.
+
+pub(super) mod single_pass;
+
+// mod v1;
+//pub use v1::{V1Pass, V1};
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/circuit/floor_planner/single_pass.rs.html b/docs/src/halo2_proofs/circuit/floor_planner/single_pass.rs.html new file mode 100644 index 0000000000..35fd173f88 --- /dev/null +++ b/docs/src/halo2_proofs/circuit/floor_planner/single_pass.rs.html @@ -0,0 +1,1034 @@ +single_pass.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+
use std::cmp;
+use std::fmt;
+use std::marker::PhantomData;
+
+use ff::Field;
+use rustc_hash::FxHashMap;
+
+use crate::{
+    circuit::{
+        layouter::{RegionColumn, RegionLayouter, RegionShape, TableLayouter},
+        AssignedCell, Cell, Layouter, Region, RegionIndex, RegionStart, Table, Value,
+    },
+    plonk::{
+        Advice, Any, Assigned, Assignment, Challenge, Circuit, Column, Error, Fixed, FloorPlanner,
+        Instance, Selector, TableColumn,
+    },
+};
+
+/// A simple [`FloorPlanner`] that performs minimal optimizations.
+///
+/// This floor planner is suitable for debugging circuits. It aims to reflect the circuit
+/// "business logic" in the circuit layout as closely as possible. It uses a single-pass
+/// layouter that does not reorder regions for optimal packing.
+#[derive(Debug)]
+pub struct SimpleFloorPlanner;
+
+impl FloorPlanner for SimpleFloorPlanner {
+    fn synthesize<F: Field, CS: Assignment<F>, C: Circuit<F>>(
+        cs: &mut CS,
+        circuit: &C,
+        config: C::Config,
+        constants: Vec<Column<Fixed>>,
+    ) -> Result<(), Error> {
+        let layouter = SingleChipLayouter::new(cs, constants)?;
+        circuit.synthesize(config, layouter)
+    }
+}
+
+/// A [`Layouter`] for a single-chip circuit.
+pub struct SingleChipLayouter<'a, F: Field, CS: Assignment<F> + 'a> {
+    cs: &'a mut CS,
+    constants: Vec<Column<Fixed>>,
+    // Stores the starting row for each region.
+    // Edit: modify to just one region with RegionStart(0)
+    // regions: Vec<RegionStart>,
+    /// Stores the first empty row for each column.
+    columns: FxHashMap<RegionColumn, usize>,
+    /// Stores the table fixed columns.
+    table_columns: Vec<TableColumn>,
+    _marker: PhantomData<F>,
+}
+
+impl<'a, F: Field, CS: Assignment<F> + 'a> fmt::Debug for SingleChipLayouter<'a, F, CS> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("SingleChipLayouter")
+            //.field("regions", &self.regions)
+            .field("columns", &self.columns)
+            .finish()
+    }
+}
+
+impl<'a, F: Field, CS: Assignment<F>> SingleChipLayouter<'a, F, CS> {
+    /// Creates a new single-chip layouter.
+    pub fn new(cs: &'a mut CS, constants: Vec<Column<Fixed>>) -> Result<Self, Error> {
+        let ret = SingleChipLayouter {
+            cs,
+            constants,
+            // regions: vec![],
+            columns: FxHashMap::default(),
+            table_columns: vec![],
+            _marker: PhantomData,
+        };
+        Ok(ret)
+    }
+}
+
+impl<'a, F: Field, CS: Assignment<F> + 'a> Layouter<F> for SingleChipLayouter<'a, F, CS> {
+    type Root = Self;
+
+    fn assign_region<A, AR, N, NR>(&mut self, name: N, assignment: A) -> Result<AR, Error>
+    where
+        A: FnOnce(Region<'_, F>) -> Result<AR, Error>,
+        N: Fn() -> NR,
+        NR: Into<String>,
+    {
+        /*
+        let region_index = self.regions.len();
+
+        // Get shape of the region.
+        let mut shape = RegionShape::new(region_index.into());
+        {
+            let region: &mut dyn RegionLayouter<F> = &mut shape;
+            assignment(region.into())?;
+        }
+
+        // Lay out this region. We implement the simplest approach here: position the
+        // region starting at the earliest row for which none of the columns are in use.
+        let region_start = 0;
+        for column in &shape.columns {
+            region_start = cmp::max(region_start, self.columns.get(column).cloned().unwrap_or(0));
+        }
+        // self.regions.push(region_start.into());
+
+        // Update column usage information.
+        for column in shape.columns {
+            self.columns.insert(column, region_start + shape.row_count);
+        }*/
+
+        // Assign region cells.
+        self.cs.enter_region(name);
+        let mut region = SingleChipLayouterRegion::new(self, 0.into()); //region_index.into());
+        let result = {
+            let region: &mut dyn RegionLayouter<F> = &mut region;
+            assignment(region.into())
+        }?;
+        let constants_to_assign = region.constants;
+        self.cs.exit_region();
+
+        // Assign constants. For the simple floor planner, we assign constants in order in
+        // the first `constants` column.
+        if self.constants.is_empty() {
+            if !constants_to_assign.is_empty() {
+                return Err(Error::NotEnoughColumnsForConstants);
+            }
+        } else {
+            let constants_column = self.constants[0];
+            let next_constant_row = self
+                .columns
+                .entry(Column::<Any>::from(constants_column).into())
+                .or_default();
+            for (constant, advice) in constants_to_assign {
+                self.cs.assign_fixed(
+                    //|| format!("Constant({:?})", constant.evaluate()),
+                    constants_column,
+                    *next_constant_row,
+                    constant,
+                );
+                self.cs.copy(
+                    constants_column.into(),
+                    *next_constant_row,
+                    advice.column,
+                    advice.row_offset, // *self.regions[*advice.region_index] + advice.row_offset,
+                );
+                *next_constant_row += 1;
+            }
+        }
+
+        Ok(result)
+    }
+
+    fn assign_table<A, N, NR>(&mut self, name: N, mut assignment: A) -> Result<(), Error>
+    where
+        A: FnMut(Table<'_, F>) -> Result<(), Error>,
+        N: Fn() -> NR,
+        NR: Into<String>,
+    {
+        // Maintenance hazard: there is near-duplicate code in `v1::AssignmentPass::assign_table`.
+        // Assign table cells.
+        self.cs.enter_region(name);
+        let mut table = SimpleTableLayouter::new(self.cs, &self.table_columns);
+        {
+            let table: &mut dyn TableLayouter<F> = &mut table;
+            assignment(table.into())
+        }?;
+        let default_and_assigned = table.default_and_assigned;
+        self.cs.exit_region();
+
+        // Check that all table columns have the same length `first_unused`,
+        // and all cells up to that length are assigned.
+        let first_unused = {
+            match default_and_assigned
+                .values()
+                .map(|(_, assigned)| {
+                    if assigned.iter().all(|b| *b) {
+                        Some(assigned.len())
+                    } else {
+                        None
+                    }
+                })
+                .reduce(|acc, item| match (acc, item) {
+                    (Some(a), Some(b)) if a == b => Some(a),
+                    _ => None,
+                }) {
+                Some(Some(len)) => len,
+                _ => return Err(Error::Synthesis), // TODO better error
+            }
+        };
+
+        // Record these columns so that we can prevent them from being used again.
+        for column in default_and_assigned.keys() {
+            self.table_columns.push(*column);
+        }
+
+        for (col, (default_val, _)) in default_and_assigned {
+            // default_val must be Some because we must have assigned
+            // at least one cell in each column, and in that case we checked
+            // that all cells up to first_unused were assigned.
+            self.cs
+                .fill_from_row(col.inner(), first_unused, default_val.unwrap())?;
+        }
+
+        Ok(())
+    }
+
+    fn constrain_instance(&mut self, cell: Cell, instance: Column<Instance>, row: usize) {
+        self.cs.copy(
+            cell.column,
+            cell.row_offset, // *self.regions[*cell.region_index] + cell.row_offset,
+            instance.into(),
+            row,
+        );
+    }
+
+    fn get_challenge(&self, challenge: Challenge) -> Value<F> {
+        self.cs.get_challenge(challenge)
+    }
+
+    fn get_root(&mut self) -> &mut Self::Root {
+        self
+    }
+
+    fn push_namespace<NR, N>(&mut self, name_fn: N)
+    where
+        NR: Into<String>,
+        N: FnOnce() -> NR,
+    {
+        self.cs.push_namespace(name_fn)
+    }
+
+    fn pop_namespace(&mut self, gadget_name: Option<String>) {
+        self.cs.pop_namespace(gadget_name)
+    }
+}
+
+struct SingleChipLayouterRegion<'r, 'a, F: Field, CS: Assignment<F> + 'a> {
+    layouter: &'r mut SingleChipLayouter<'a, F, CS>,
+    region_index: RegionIndex,
+    /// Stores the constants to be assigned, and the cells to which they are copied.
+    constants: Vec<(Assigned<F>, Cell)>,
+}
+
+impl<'r, 'a, F: Field, CS: Assignment<F> + 'a> fmt::Debug
+    for SingleChipLayouterRegion<'r, 'a, F, CS>
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("SingleChipLayouterRegion")
+            .field("layouter", &self.layouter)
+            .field("region_index", &self.region_index)
+            .finish()
+    }
+}
+
+impl<'r, 'a, F: Field, CS: Assignment<F> + 'a> SingleChipLayouterRegion<'r, 'a, F, CS> {
+    fn new(layouter: &'r mut SingleChipLayouter<'a, F, CS>, region_index: RegionIndex) -> Self {
+        SingleChipLayouterRegion {
+            layouter,
+            region_index,
+            constants: vec![],
+        }
+    }
+}
+
+impl<'r, 'a, F: Field, CS: Assignment<F> + 'a> RegionLayouter<F>
+    for SingleChipLayouterRegion<'r, 'a, F, CS>
+{
+    fn enable_selector<'v>(
+        &'v mut self,
+        annotation: &'v (dyn Fn() -> String + 'v),
+        selector: &Selector,
+        offset: usize,
+    ) -> Result<(), Error> {
+        self.layouter.cs.enable_selector(
+            annotation, selector,
+            offset, // *self.layouter.regions[*self.region_index] + offset,
+        )
+    }
+
+    fn assign_advice<'b, 'v>(
+        &'b mut self,
+        // annotation: &'v (dyn Fn() -> String + 'v),
+        column: Column<Advice>,
+        offset: usize,
+        to: Value<Assigned<F>>, // &'v mut (dyn FnMut() -> Value<Assigned<F>> + 'v),
+    ) -> Result<AssignedCell<&'v Assigned<F>, F>, Error> {
+        let value = self.layouter.cs.assign_advice(
+            // annotation,
+            column, offset, //*self.layouter.regions[*self.region_index] + offset,
+            to,
+        )?;
+
+        Ok(AssignedCell {
+            value,
+            cell: Cell {
+                // region_index: self.region_index,
+                row_offset: offset,
+                column: column.into(),
+            },
+            _marker: PhantomData,
+        })
+    }
+
+    fn assign_advice_from_constant<'v>(
+        &'v mut self,
+        _annotation: &'v (dyn Fn() -> String + 'v),
+        column: Column<Advice>,
+        offset: usize,
+        constant: Assigned<F>,
+    ) -> Result<Cell, Error> {
+        let advice = self
+            .assign_advice(column, offset, Value::known(constant))?
+            .cell;
+        self.constrain_constant(advice, constant)?;
+
+        Ok(advice)
+    }
+
+    fn assign_advice_from_instance<'v>(
+        &mut self,
+        _annotation: &'v (dyn Fn() -> String + 'v),
+        instance: Column<Instance>,
+        row: usize,
+        advice: Column<Advice>,
+        offset: usize,
+    ) -> Result<(Cell, Value<F>), Error> {
+        let value = self.layouter.cs.query_instance(instance, row)?;
+
+        let cell = self
+            .assign_advice(advice, offset, value.map(|v| Assigned::Trivial(v)))?
+            .cell;
+
+        self.layouter.cs.copy(
+            cell.column,
+            cell.row_offset, // *self.layouter.regions[*cell.region_index] + cell.row_offset,
+            instance.into(),
+            row,
+        );
+
+        Ok((cell, value))
+    }
+
+    fn assign_fixed(
+        &mut self,
+        // annotation: &'v (dyn Fn() -> String + 'v),
+        column: Column<Fixed>,
+        offset: usize,
+        to: Assigned<F>,
+    ) -> Cell {
+        self.layouter.cs.assign_fixed(
+            column, offset, // *self.layouter.regions[*self.region_index] + offset,
+            to,
+        );
+
+        Cell {
+            // region_index: self.region_index,
+            row_offset: offset,
+            column: column.into(),
+        }
+    }
+
+    fn constrain_constant(&mut self, cell: Cell, constant: Assigned<F>) -> Result<(), Error> {
+        self.constants.push((constant, cell));
+        Ok(())
+    }
+
+    fn constrain_equal(&mut self, left: &Cell, right: &Cell) {
+        self.layouter.cs.copy(
+            left.column,
+            left.row_offset, // *self.layouter.regions[*left.region_index] + left.row_offset,
+            right.column,
+            right.row_offset, // *self.layouter.regions[*right.region_index] + right.row_offset,
+        );
+    }
+
+    fn get_challenge(&self, challenge: Challenge) -> Value<F> {
+        self.layouter.cs.get_challenge(challenge)
+    }
+
+    fn next_phase(&mut self) {
+        self.layouter.cs.next_phase();
+    }
+}
+
+/// The default value to fill a table column with.
+///
+/// - The outer `Option` tracks whether the value in row 0 of the table column has been
+///   assigned yet. This will always be `Some` once a valid table has been completely
+///   assigned.
+/// - The inner `Value` tracks whether the underlying `Assignment` is evaluating
+///   witnesses or not.
+type DefaultTableValue<F> = Option<Value<Assigned<F>>>;
+
+pub(crate) struct SimpleTableLayouter<'r, 'a, F: Field, CS: Assignment<F> + 'a> {
+    cs: &'a mut CS,
+    used_columns: &'r [TableColumn],
+    // maps from a fixed column to a pair (default value, vector saying which rows are assigned)
+    pub(crate) default_and_assigned: FxHashMap<TableColumn, (DefaultTableValue<F>, Vec<bool>)>,
+}
+
+impl<'r, 'a, F: Field, CS: Assignment<F> + 'a> fmt::Debug for SimpleTableLayouter<'r, 'a, F, CS> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("SimpleTableLayouter")
+            .field("used_columns", &self.used_columns)
+            .field("default_and_assigned", &self.default_and_assigned)
+            .finish()
+    }
+}
+
+impl<'r, 'a, F: Field, CS: Assignment<F> + 'a> SimpleTableLayouter<'r, 'a, F, CS> {
+    pub(crate) fn new(cs: &'a mut CS, used_columns: &'r [TableColumn]) -> Self {
+        SimpleTableLayouter {
+            cs,
+            used_columns,
+            default_and_assigned: FxHashMap::default(),
+        }
+    }
+}
+
+impl<'r, 'a, F: Field, CS: Assignment<F> + 'a> TableLayouter<F>
+    for SimpleTableLayouter<'r, 'a, F, CS>
+{
+    fn assign_cell<'v>(
+        &'v mut self,
+        _: &'v (dyn Fn() -> String + 'v),
+        column: TableColumn,
+        offset: usize,
+        to: &'v mut (dyn FnMut() -> Value<Assigned<F>> + 'v),
+    ) -> Result<(), Error> {
+        if self.used_columns.contains(&column) {
+            return Err(Error::Synthesis); // TODO better error
+        }
+
+        let entry = self.default_and_assigned.entry(column).or_default();
+
+        let value;
+        self.cs.assign_fixed(
+            // annotation,
+            column.inner(),
+            offset, // tables are always assigned starting at row 0
+            {
+                let res = to();
+                value = res;
+                res.assign()?
+            },
+        );
+
+        match (entry.0.is_none(), offset) {
+            // Use the value at offset 0 as the default value for this table column.
+            (true, 0) => entry.0 = Some(value),
+            // Since there is already an existing default value for this table column,
+            // the caller should not be attempting to assign another value at offset 0.
+            (false, 0) => return Err(Error::Synthesis), // TODO better error
+            _ => (),
+        }
+        if entry.1.len() <= offset {
+            entry.1.resize(offset + 1, false);
+        }
+        entry.1[offset] = true;
+
+        Ok(())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use halo2curves::pasta::vesta;
+
+    use super::SimpleFloorPlanner;
+    use crate::{
+        dev::MockProver,
+        plonk::{Advice, Circuit, Column, Error},
+    };
+
+    #[test]
+    fn not_enough_columns_for_constants() {
+        struct MyCircuit {}
+
+        impl Circuit<vesta::Scalar> for MyCircuit {
+            type Config = Column<Advice>;
+            type FloorPlanner = SimpleFloorPlanner;
+
+            fn without_witnesses(&self) -> Self {
+                MyCircuit {}
+            }
+
+            fn configure(meta: &mut crate::plonk::ConstraintSystem<vesta::Scalar>) -> Self::Config {
+                meta.advice_column()
+            }
+
+            fn synthesize(
+                &self,
+                config: Self::Config,
+                mut layouter: impl crate::circuit::Layouter<vesta::Scalar>,
+            ) -> Result<(), crate::plonk::Error> {
+                layouter.assign_region(
+                    || "assign constant",
+                    |mut region| {
+                        region.assign_advice_from_constant(
+                            || "one",
+                            config,
+                            0,
+                            vesta::Scalar::one(),
+                        )
+                    },
+                )?;
+
+                Ok(())
+            }
+        }
+
+        let circuit = MyCircuit {};
+        assert!(matches!(
+            MockProver::run(3, &circuit, vec![]).unwrap_err(),
+            Error::NotEnoughColumnsForConstants,
+        ));
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/circuit/layouter.rs.html b/docs/src/halo2_proofs/circuit/layouter.rs.html new file mode 100644 index 0000000000..72165ec413 --- /dev/null +++ b/docs/src/halo2_proofs/circuit/layouter.rs.html @@ -0,0 +1,624 @@ +layouter.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+
//! Implementations of common circuit layouters.
+
+use std::cmp;
+use std::collections::HashSet;
+use std::fmt;
+
+use ff::Field;
+
+use super::{AssignedCell, Cell, RegionIndex, Value};
+use crate::plonk::{
+    Advice, Any, Assigned, Challenge, Column, Error, Fixed, Instance, Selector, TableColumn,
+};
+
+/// Helper trait for implementing a custom [`Layouter`].
+///
+/// This trait is used for implementing region assignments:
+///
+/// ```ignore
+/// impl<'a, F: FieldExt, C: Chip<F>, CS: Assignment<F> + 'a> Layouter<C> for MyLayouter<'a, C, CS> {
+///     fn assign_region(
+///         &mut self,
+///         assignment: impl FnOnce(Region<'_, F, C>) -> Result<(), Error>,
+///     ) -> Result<(), Error> {
+///         let region_index = self.regions.len();
+///         self.regions.push(self.current_gate);
+///
+///         let mut region = MyRegion::new(self, region_index);
+///         {
+///             let region: &mut dyn RegionLayouter<F> = &mut region;
+///             assignment(region.into())?;
+///         }
+///         self.current_gate += region.row_count;
+///
+///         Ok(())
+///     }
+/// }
+/// ```
+///
+/// TODO: It would be great if we could constrain the columns in these types to be
+/// "logical" columns that are guaranteed to correspond to the chip (and have come from
+/// `Chip::Config`).
+///
+/// [`Layouter`]: super::Layouter
+pub trait RegionLayouter<F: Field>: fmt::Debug {
+    /// Enables a selector at the given offset.
+    fn enable_selector<'v>(
+        &'v mut self,
+        annotation: &'v (dyn Fn() -> String + 'v),
+        selector: &Selector,
+        offset: usize,
+    ) -> Result<(), Error>;
+
+    /// Assign an advice column value (witness)
+    fn assign_advice<'b, 'v>(
+        &'b mut self,
+        // annotation: &'v (dyn Fn() -> String + 'v),
+        column: Column<Advice>,
+        offset: usize,
+        to: Value<Assigned<F>>, // &'v mut (dyn FnMut() -> Value<Assigned<F>> + 'v),
+    ) -> Result<AssignedCell<&'v Assigned<F>, F>, Error>;
+
+    /// Assigns a constant value to the column `advice` at `offset` within this region.
+    ///
+    /// The constant value will be assigned to a cell within one of the fixed columns
+    /// configured via `ConstraintSystem::enable_constant`.
+    ///
+    /// Returns the advice cell that has been equality-constrained to the constant.
+    fn assign_advice_from_constant<'v>(
+        &'v mut self,
+        annotation: &'v (dyn Fn() -> String + 'v),
+        column: Column<Advice>,
+        offset: usize,
+        constant: Assigned<F>,
+    ) -> Result<Cell, Error>;
+
+    /// Assign the value of the instance column's cell at absolute location
+    /// `row` to the column `advice` at `offset` within this region.
+    ///
+    /// Returns the advice cell, and its value if known.
+    fn assign_advice_from_instance<'v>(
+        &mut self,
+        annotation: &'v (dyn Fn() -> String + 'v),
+        instance: Column<Instance>,
+        row: usize,
+        advice: Column<Advice>,
+        offset: usize,
+    ) -> Result<(Cell, Value<F>), Error>;
+
+    /// Assign a fixed value
+    fn assign_fixed(
+        &mut self,
+        // annotation: &'v (dyn Fn() -> String + 'v),
+        column: Column<Fixed>,
+        offset: usize,
+        to: Assigned<F>,
+    ) -> Cell;
+
+    /// Constrains a cell to have a constant value.
+    ///
+    /// Returns an error if the cell is in a column where equality has not been enabled.
+    fn constrain_constant(&mut self, cell: Cell, constant: Assigned<F>) -> Result<(), Error>;
+
+    /// Constraint two cells to have the same value.
+    ///
+    /// Returns an error if either of the cells is not within the given permutation.
+    fn constrain_equal(&mut self, left: &Cell, right: &Cell);
+
+    /// Queries the value of the given challenge.
+    ///
+    /// Returns `Value::unknown()` if the current synthesis phase is before the challenge can be queried.
+    fn get_challenge(&self, challenge: Challenge) -> Value<F>;
+
+    /// Commit advice columns in current phase and squeeze challenges.
+    /// This can be called DURING synthesize.
+    fn next_phase(&mut self);
+}
+
+/// Helper trait for implementing a custom [`Layouter`].
+///
+/// This trait is used for implementing table assignments.
+///
+/// [`Layouter`]: super::Layouter
+pub trait TableLayouter<F: Field>: fmt::Debug {
+    /// Assigns a fixed value to a table cell.
+    ///
+    /// Returns an error if the table cell has already been assigned to.
+    fn assign_cell<'v>(
+        &'v mut self,
+        annotation: &'v (dyn Fn() -> String + 'v),
+        column: TableColumn,
+        offset: usize,
+        to: &'v mut (dyn FnMut() -> Value<Assigned<F>> + 'v),
+    ) -> Result<(), Error>;
+}
+
+/// The shape of a region. For a region at a certain index, we track
+/// the set of columns it uses as well as the number of rows it uses.
+#[derive(Clone, Debug)]
+#[allow(dead_code)]
+pub struct RegionShape {
+    pub(super) region_index: RegionIndex,
+    pub(super) columns: HashSet<RegionColumn>,
+    pub(super) row_count: usize,
+}
+
+/// The virtual column involved in a region. This includes concrete columns,
+/// as well as selectors that are not concrete columns at this stage.
+#[derive(Eq, PartialEq, Copy, Clone, Debug, Hash)]
+pub enum RegionColumn {
+    /// Concrete column
+    Column(Column<Any>),
+    /// Virtual column representing a (boolean) selector
+    Selector(Selector),
+}
+
+impl From<Column<Any>> for RegionColumn {
+    fn from(column: Column<Any>) -> RegionColumn {
+        RegionColumn::Column(column)
+    }
+}
+
+impl From<Selector> for RegionColumn {
+    fn from(selector: Selector) -> RegionColumn {
+        RegionColumn::Selector(selector)
+    }
+}
+
+impl Ord for RegionColumn {
+    fn cmp(&self, other: &Self) -> cmp::Ordering {
+        match (self, other) {
+            (Self::Column(ref a), Self::Column(ref b)) => a.cmp(b),
+            (Self::Selector(ref a), Self::Selector(ref b)) => a.0.cmp(&b.0),
+            (Self::Column(_), Self::Selector(_)) => cmp::Ordering::Less,
+            (Self::Selector(_), Self::Column(_)) => cmp::Ordering::Greater,
+        }
+    }
+}
+
+impl PartialOrd for RegionColumn {
+    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+/*
+impl RegionShape {
+    /// Create a new `RegionShape` for a region at `region_index`.
+    pub fn new(region_index: RegionIndex) -> Self {
+        RegionShape {
+            region_index,
+            columns: HashSet::default(),
+            row_count: 0,
+        }
+    }
+
+    /// Get the `region_index` of a `RegionShape`.
+    pub fn region_index(&self) -> RegionIndex {
+        self.region_index
+    }
+
+    /// Get a reference to the set of `columns` used in a `RegionShape`.
+    pub fn columns(&self) -> &HashSet<RegionColumn> {
+        &self.columns
+    }
+
+    /// Get the `row_count` of a `RegionShape`.
+    pub fn row_count(&self) -> usize {
+        self.row_count
+    }
+}
+
+impl<F: Field> RegionLayouter<F> for RegionShape {
+    fn enable_selector<'v>(
+        &'v mut self,
+        _: &'v (dyn Fn() -> String + 'v),
+        selector: &Selector,
+        offset: usize,
+    ) -> Result<(), Error> {
+        // Track the selector's fixed column as part of the region's shape.
+        self.columns.insert((*selector).into());
+        self.row_count = cmp::max(self.row_count, offset + 1);
+        Ok(())
+    }
+
+    fn assign_advice<'v>(
+        &'v mut self,
+        //_: &'v (dyn Fn() -> String + 'v),
+        column: Column<Advice>,
+        offset: usize,
+        _to: Value<Assigned<F>>, // &'v mut (dyn FnMut() -> Value<Assigned<F>> + 'v),
+    ) -> Result<AssignedCell<&Assigned<F>, F>, Error> {
+        self.columns.insert(Column::<Any>::from(column).into());
+        self.row_count = cmp::max(self.row_count, offset + 1);
+
+        Ok(Cell {
+            region_index: self.region_index,
+            row_offset: offset,
+            column: column.into(),
+        });
+        todo!()
+    }
+
+    fn assign_advice_from_constant<'v>(
+        &'v mut self,
+        annotation: &'v (dyn Fn() -> String + 'v),
+        column: Column<Advice>,
+        offset: usize,
+        constant: Assigned<F>,
+    ) -> Result<Cell, Error> {
+        // The rest is identical to witnessing an advice cell.
+        self.assign_advice(column, offset, Value::known(constant))
+    }
+
+    fn assign_advice_from_instance<'v>(
+        &mut self,
+        _: &'v (dyn Fn() -> String + 'v),
+        _: Column<Instance>,
+        _: usize,
+        advice: Column<Advice>,
+        offset: usize,
+    ) -> Result<(Cell, Value<F>), Error> {
+        self.columns.insert(Column::<Any>::from(advice).into());
+        self.row_count = cmp::max(self.row_count, offset + 1);
+
+        Ok((
+            Cell {
+                region_index: self.region_index,
+                row_offset: offset,
+                column: advice.into(),
+            },
+            Value::unknown(),
+        ))
+    }
+
+    fn assign_fixed<'v>(
+        &'v mut self,
+        _: &'v (dyn Fn() -> String + 'v),
+        column: Column<Fixed>,
+        offset: usize,
+        _to: &'v mut (dyn FnMut() -> Value<Assigned<F>> + 'v),
+    ) -> Result<Cell, Error> {
+        self.columns.insert(Column::<Any>::from(column).into());
+        self.row_count = cmp::max(self.row_count, offset + 1);
+
+        Ok(Cell {
+            region_index: self.region_index,
+            row_offset: offset,
+            column: column.into(),
+        })
+    }
+
+    fn constrain_constant(&mut self, _cell: Cell, _constant: Assigned<F>) -> Result<(), Error> {
+        // Global constants don't affect the region shape.
+        Ok(())
+    }
+
+    fn constrain_equal(&mut self, _left: Cell, _right: Cell) -> Result<(), Error> {
+        // Equality constraints don't affect the region shape.
+        Ok(())
+    }
+
+    fn get_challenge(&self, _: Challenge) -> Value<F> {
+        Value::unknown()
+    }
+
+    fn next_phase(&mut self) -> Result<(), Error> {
+        // Region shapes don't care about phases.
+        Ok(())
+    }
+}
+*/
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/circuit/value.rs.html b/docs/src/halo2_proofs/circuit/value.rs.html new file mode 100644 index 0000000000..06875fec32 --- /dev/null +++ b/docs/src/halo2_proofs/circuit/value.rs.html @@ -0,0 +1,1398 @@ +value.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+
use std::borrow::Borrow;
+use std::ops::{Add, Mul, Neg, Sub};
+
+use group::ff::Field;
+
+use crate::plonk::{Assigned, Error};
+
+/// A value that might exist within a circuit.
+///
+/// This behaves like `Option<V>` but differs in two key ways:
+/// - It does not expose the enum cases, or provide an `Option::unwrap` equivalent. This
+///   helps to ensure that unwitnessed values correctly propagate.
+/// - It provides pass-through implementations of common traits such as `Add` and `Mul`,
+///   for improved usability.
+#[derive(Clone, Copy, Debug)]
+pub struct Value<V> {
+    inner: Option<V>,
+}
+
+impl<V> Default for Value<V> {
+    fn default() -> Self {
+        Self::unknown()
+    }
+}
+
+impl<V> Value<V> {
+    /// Constructs an unwitnessed value.
+    pub const fn unknown() -> Self {
+        Self { inner: None }
+    }
+
+    /// Constructs a known value.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use halo2_proofs::circuit::Value;
+    ///
+    /// let v = Value::known(37);
+    /// ```
+    pub const fn known(value: V) -> Self {
+        Self { inner: Some(value) }
+    }
+
+    /// Obtains the inner value for assigning into the circuit.
+    ///
+    /// Returns `Error::Synthesis` if this is [`Value::unknown()`].
+    pub(crate) fn assign(self) -> Result<V, Error> {
+        self.inner.ok_or(Error::Synthesis)
+    }
+
+    /// Converts from `&Value<V>` to `Value<&V>`.
+    pub fn as_ref(&self) -> Value<&V> {
+        Value {
+            inner: self.inner.as_ref(),
+        }
+    }
+
+    /// Converts from `&mut Value<V>` to `Value<&mut V>`.
+    pub fn as_mut(&mut self) -> Value<&mut V> {
+        Value {
+            inner: self.inner.as_mut(),
+        }
+    }
+
+    /// Enforces an assertion on the contained value, if known.
+    ///
+    /// The assertion is ignored if `self` is [`Value::unknown()`]. Do not try to enforce
+    /// circuit constraints with this method!
+    ///
+    /// # Panics
+    ///
+    /// Panics if `f` returns `false`.
+    pub fn assert_if_known<F: FnOnce(&V) -> bool>(&self, f: F) {
+        if let Some(value) = self.inner.as_ref() {
+            assert!(f(value));
+        }
+    }
+
+    /// Checks the contained value for an error condition, if known.
+    ///
+    /// The error check is ignored if `self` is [`Value::unknown()`]. Do not try to
+    /// enforce circuit constraints with this method!
+    pub fn error_if_known_and<F: FnOnce(&V) -> bool>(&self, f: F) -> Result<(), Error> {
+        match self.inner.as_ref() {
+            Some(value) if f(value) => Err(Error::Synthesis),
+            _ => Ok(()),
+        }
+    }
+
+    /// Maps a `Value<V>` to `Value<W>` by applying a function to the contained value.
+    pub fn map<W, F: FnOnce(V) -> W>(self, f: F) -> Value<W> {
+        Value {
+            inner: self.inner.map(f),
+        }
+    }
+
+    /// Returns [`Value::unknown()`] if the value is [`Value::unknown()`], otherwise calls
+    /// `f` with the wrapped value and returns the result.
+    pub fn and_then<W, F: FnOnce(V) -> Value<W>>(self, f: F) -> Value<W> {
+        match self.inner {
+            Some(v) => f(v),
+            None => Value::unknown(),
+        }
+    }
+
+    /// Zips `self` with another `Value`.
+    ///
+    /// If `self` is `Value::known(s)` and `other` is `Value::known(o)`, this method
+    /// returns `Value::known((s, o))`. Otherwise, [`Value::unknown()`] is returned.
+    pub fn zip<W>(self, other: Value<W>) -> Value<(V, W)> {
+        Value {
+            inner: self.inner.zip(other.inner),
+        }
+    }
+}
+
+impl<V, W> Value<(V, W)> {
+    /// Unzips a value containing a tuple of two values.
+    ///
+    /// If `self` is `Value::known((a, b)), this method returns
+    /// `(Value::known(a), Value::known(b))`. Otherwise,
+    /// `(Value::unknown(), Value::unknown())` is returned.
+    pub fn unzip(self) -> (Value<V>, Value<W>) {
+        match self.inner {
+            Some((a, b)) => (Value::known(a), Value::known(b)),
+            None => (Value::unknown(), Value::unknown()),
+        }
+    }
+}
+
+impl<V> Value<&V> {
+    /// Maps a `Value<&V>` to a `Value<V>` by copying the contents of the value.
+    #[must_use = "`self` will be dropped if the result is not used"]
+    pub fn copied(self) -> Value<V>
+    where
+        V: Copy,
+    {
+        Value {
+            inner: self.inner.copied(),
+        }
+    }
+
+    /// Maps a `Value<&V>` to a `Value<V>` by cloning the contents of the value.
+    #[must_use = "`self` will be dropped if the result is not used"]
+    pub fn cloned(self) -> Value<V>
+    where
+        V: Clone,
+    {
+        Value {
+            inner: self.inner.cloned(),
+        }
+    }
+}
+
+impl<V> Value<&mut V> {
+    /// Maps a `Value<&mut V>` to a `Value<V>` by copying the contents of the value.
+    #[must_use = "`self` will be dropped if the result is not used"]
+    pub fn copied(self) -> Value<V>
+    where
+        V: Copy,
+    {
+        Value {
+            inner: self.inner.copied(),
+        }
+    }
+
+    /// Maps a `Value<&mut V>` to a `Value<V>` by cloning the contents of the value.
+    #[must_use = "`self` will be dropped if the result is not used"]
+    pub fn cloned(self) -> Value<V>
+    where
+        V: Clone,
+    {
+        Value {
+            inner: self.inner.cloned(),
+        }
+    }
+}
+
+impl<V: Copy, const LEN: usize> Value<[V; LEN]> {
+    /// Transposes a `Value<[V; LEN]>` into a `[Value<V>; LEN]`.
+    ///
+    /// [`Value::unknown()`] will be mapped to `[Value::unknown(); LEN]`.
+    pub fn transpose_array(self) -> [Value<V>; LEN] {
+        let mut ret = [Value::unknown(); LEN];
+        if let Some(arr) = self.inner {
+            for (entry, value) in ret.iter_mut().zip(arr) {
+                *entry = Value::known(value);
+            }
+        }
+        ret
+    }
+}
+
+impl<V, I> Value<I>
+where
+    I: IntoIterator<Item = V>,
+    I::IntoIter: ExactSizeIterator,
+{
+    /// Transposes a `Value<impl IntoIterator<Item = V>>` into a `Vec<Value<V>>`.
+    ///
+    /// [`Value::unknown()`] will be mapped to `vec![Value::unknown(); length]`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if `self` is `Value::known(values)` and `values.len() != length`.
+    pub fn transpose_vec(self, length: usize) -> Vec<Value<V>> {
+        match self.inner {
+            Some(values) => {
+                let values = values.into_iter();
+                assert_eq!(values.len(), length);
+                values.map(Value::known).collect()
+            }
+            None => (0..length).map(|_| Value::unknown()).collect(),
+        }
+    }
+}
+
+//
+// FromIterator
+//
+
+impl<A, V: FromIterator<A>> FromIterator<Value<A>> for Value<V> {
+    /// Takes each element in the [`Iterator`]: if it is [`Value::unknown()`], no further
+    /// elements are taken, and the [`Value::unknown()`] is returned. Should no
+    /// [`Value::unknown()`] occur, a container of type `V` containing the values of each
+    /// [`Value`] is returned.
+    fn from_iter<I: IntoIterator<Item = Value<A>>>(iter: I) -> Self {
+        Self {
+            inner: iter.into_iter().map(|v| v.inner).collect(),
+        }
+    }
+}
+
+//
+// Neg
+//
+
+impl<V: Neg> Neg for Value<V> {
+    type Output = Value<V::Output>;
+
+    fn neg(self) -> Self::Output {
+        Value {
+            inner: self.inner.map(|v| -v),
+        }
+    }
+}
+
+//
+// Add
+//
+
+impl<V, O> Add for Value<V>
+where
+    V: Add<Output = O>,
+{
+    type Output = Value<O>;
+
+    fn add(self, rhs: Self) -> Self::Output {
+        Value {
+            inner: self.inner.zip(rhs.inner).map(|(a, b)| a + b),
+        }
+    }
+}
+
+impl<V, O> Add for &Value<V>
+where
+    for<'v> &'v V: Add<Output = O>,
+{
+    type Output = Value<O>;
+
+    fn add(self, rhs: Self) -> Self::Output {
+        Value {
+            inner: self
+                .inner
+                .as_ref()
+                .zip(rhs.inner.as_ref())
+                .map(|(a, b)| a + b),
+        }
+    }
+}
+
+impl<V, O> Add<Value<&V>> for Value<V>
+where
+    for<'v> V: Add<&'v V, Output = O>,
+{
+    type Output = Value<O>;
+
+    fn add(self, rhs: Value<&V>) -> Self::Output {
+        Value {
+            inner: self.inner.zip(rhs.inner).map(|(a, b)| a + b),
+        }
+    }
+}
+
+impl<V, O> Add<Value<V>> for Value<&V>
+where
+    for<'v> &'v V: Add<V, Output = O>,
+{
+    type Output = Value<O>;
+
+    fn add(self, rhs: Value<V>) -> Self::Output {
+        Value {
+            inner: self.inner.zip(rhs.inner).map(|(a, b)| a + b),
+        }
+    }
+}
+
+impl<V, O> Add<&Value<V>> for Value<V>
+where
+    for<'v> V: Add<&'v V, Output = O>,
+{
+    type Output = Value<O>;
+
+    fn add(self, rhs: &Self) -> Self::Output {
+        self + rhs.as_ref()
+    }
+}
+
+impl<V, O> Add<Value<V>> for &Value<V>
+where
+    for<'v> &'v V: Add<V, Output = O>,
+{
+    type Output = Value<O>;
+
+    fn add(self, rhs: Value<V>) -> Self::Output {
+        self.as_ref() + rhs
+    }
+}
+
+//
+// Sub
+//
+
+impl<V, O> Sub for Value<V>
+where
+    V: Sub<Output = O>,
+{
+    type Output = Value<O>;
+
+    fn sub(self, rhs: Self) -> Self::Output {
+        Value {
+            inner: self.inner.zip(rhs.inner).map(|(a, b)| a - b),
+        }
+    }
+}
+
+impl<V, O> Sub for &Value<V>
+where
+    for<'v> &'v V: Sub<Output = O>,
+{
+    type Output = Value<O>;
+
+    fn sub(self, rhs: Self) -> Self::Output {
+        Value {
+            inner: self
+                .inner
+                .as_ref()
+                .zip(rhs.inner.as_ref())
+                .map(|(a, b)| a - b),
+        }
+    }
+}
+
+impl<V, O> Sub<Value<&V>> for Value<V>
+where
+    for<'v> V: Sub<&'v V, Output = O>,
+{
+    type Output = Value<O>;
+
+    fn sub(self, rhs: Value<&V>) -> Self::Output {
+        Value {
+            inner: self.inner.zip(rhs.inner).map(|(a, b)| a - b),
+        }
+    }
+}
+
+impl<V, O> Sub<Value<V>> for Value<&V>
+where
+    for<'v> &'v V: Sub<V, Output = O>,
+{
+    type Output = Value<O>;
+
+    fn sub(self, rhs: Value<V>) -> Self::Output {
+        Value {
+            inner: self.inner.zip(rhs.inner).map(|(a, b)| a - b),
+        }
+    }
+}
+
+impl<V, O> Sub<&Value<V>> for Value<V>
+where
+    for<'v> V: Sub<&'v V, Output = O>,
+{
+    type Output = Value<O>;
+
+    fn sub(self, rhs: &Self) -> Self::Output {
+        self - rhs.as_ref()
+    }
+}
+
+impl<V, O> Sub<Value<V>> for &Value<V>
+where
+    for<'v> &'v V: Sub<V, Output = O>,
+{
+    type Output = Value<O>;
+
+    fn sub(self, rhs: Value<V>) -> Self::Output {
+        self.as_ref() - rhs
+    }
+}
+
+//
+// Mul
+//
+
+impl<V, O> Mul for Value<V>
+where
+    V: Mul<Output = O>,
+{
+    type Output = Value<O>;
+
+    fn mul(self, rhs: Self) -> Self::Output {
+        Value {
+            inner: self.inner.zip(rhs.inner).map(|(a, b)| a * b),
+        }
+    }
+}
+
+impl<V, O> Mul for &Value<V>
+where
+    for<'v> &'v V: Mul<Output = O>,
+{
+    type Output = Value<O>;
+
+    fn mul(self, rhs: Self) -> Self::Output {
+        Value {
+            inner: self
+                .inner
+                .as_ref()
+                .zip(rhs.inner.as_ref())
+                .map(|(a, b)| a * b),
+        }
+    }
+}
+
+impl<V, O> Mul<Value<&V>> for Value<V>
+where
+    for<'v> V: Mul<&'v V, Output = O>,
+{
+    type Output = Value<O>;
+
+    fn mul(self, rhs: Value<&V>) -> Self::Output {
+        Value {
+            inner: self.inner.zip(rhs.inner).map(|(a, b)| a * b),
+        }
+    }
+}
+
+impl<V, O> Mul<Value<V>> for Value<&V>
+where
+    for<'v> &'v V: Mul<V, Output = O>,
+{
+    type Output = Value<O>;
+
+    fn mul(self, rhs: Value<V>) -> Self::Output {
+        Value {
+            inner: self.inner.zip(rhs.inner).map(|(a, b)| a * b),
+        }
+    }
+}
+
+impl<V, O> Mul<&Value<V>> for Value<V>
+where
+    for<'v> V: Mul<&'v V, Output = O>,
+{
+    type Output = Value<O>;
+
+    fn mul(self, rhs: &Self) -> Self::Output {
+        self * rhs.as_ref()
+    }
+}
+
+impl<V, O> Mul<Value<V>> for &Value<V>
+where
+    for<'v> &'v V: Mul<V, Output = O>,
+{
+    type Output = Value<O>;
+
+    fn mul(self, rhs: Value<V>) -> Self::Output {
+        self.as_ref() * rhs
+    }
+}
+
+//
+// Assigned<Field>
+//
+
+impl<F: Field> From<Value<F>> for Value<Assigned<F>> {
+    fn from(value: Value<F>) -> Self {
+        Self {
+            inner: value.inner.map(Assigned::from),
+        }
+    }
+}
+
+impl<F: Field> Add<Value<F>> for Value<Assigned<F>> {
+    type Output = Value<Assigned<F>>;
+
+    fn add(self, rhs: Value<F>) -> Self::Output {
+        Value {
+            inner: self.inner.zip(rhs.inner).map(|(a, b)| a + b),
+        }
+    }
+}
+
+impl<F: Field> Add<F> for Value<Assigned<F>> {
+    type Output = Value<Assigned<F>>;
+
+    fn add(self, rhs: F) -> Self::Output {
+        self + Value::known(rhs)
+    }
+}
+
+impl<F: Field> Add<Value<F>> for Value<&Assigned<F>> {
+    type Output = Value<Assigned<F>>;
+
+    fn add(self, rhs: Value<F>) -> Self::Output {
+        Value {
+            inner: self.inner.zip(rhs.inner).map(|(a, b)| a + b),
+        }
+    }
+}
+
+impl<F: Field> Add<F> for Value<&Assigned<F>> {
+    type Output = Value<Assigned<F>>;
+
+    fn add(self, rhs: F) -> Self::Output {
+        self + Value::known(rhs)
+    }
+}
+
+impl<F: Field> Sub<Value<F>> for Value<Assigned<F>> {
+    type Output = Value<Assigned<F>>;
+
+    fn sub(self, rhs: Value<F>) -> Self::Output {
+        Value {
+            inner: self.inner.zip(rhs.inner).map(|(a, b)| a - b),
+        }
+    }
+}
+
+impl<F: Field> Sub<F> for Value<Assigned<F>> {
+    type Output = Value<Assigned<F>>;
+
+    fn sub(self, rhs: F) -> Self::Output {
+        self - Value::known(rhs)
+    }
+}
+
+impl<F: Field> Sub<Value<F>> for Value<&Assigned<F>> {
+    type Output = Value<Assigned<F>>;
+
+    fn sub(self, rhs: Value<F>) -> Self::Output {
+        Value {
+            inner: self.inner.zip(rhs.inner).map(|(a, b)| a - b),
+        }
+    }
+}
+
+impl<F: Field> Sub<F> for Value<&Assigned<F>> {
+    type Output = Value<Assigned<F>>;
+
+    fn sub(self, rhs: F) -> Self::Output {
+        self - Value::known(rhs)
+    }
+}
+
+impl<F: Field> Mul<Value<F>> for Value<Assigned<F>> {
+    type Output = Value<Assigned<F>>;
+
+    fn mul(self, rhs: Value<F>) -> Self::Output {
+        Value {
+            inner: self.inner.zip(rhs.inner).map(|(a, b)| a * b),
+        }
+    }
+}
+
+impl<F: Field> Mul<F> for Value<Assigned<F>> {
+    type Output = Value<Assigned<F>>;
+
+    fn mul(self, rhs: F) -> Self::Output {
+        self * Value::known(rhs)
+    }
+}
+
+impl<F: Field> Mul<Value<F>> for Value<&Assigned<F>> {
+    type Output = Value<Assigned<F>>;
+
+    fn mul(self, rhs: Value<F>) -> Self::Output {
+        Value {
+            inner: self.inner.zip(rhs.inner).map(|(a, b)| a * b),
+        }
+    }
+}
+
+impl<F: Field> Mul<F> for Value<&Assigned<F>> {
+    type Output = Value<Assigned<F>>;
+
+    fn mul(self, rhs: F) -> Self::Output {
+        self * Value::known(rhs)
+    }
+}
+
+impl<V> Value<V> {
+    /// Returns the field element corresponding to this value.
+    pub fn to_field<F: Field>(&self) -> Value<Assigned<F>>
+    where
+        for<'v> Assigned<F>: From<&'v V>,
+    {
+        Value {
+            inner: self.inner.as_ref().map(|v| v.into()),
+        }
+    }
+
+    /// Returns the field element corresponding to this value.
+    pub fn into_field<F: Field>(self) -> Value<Assigned<F>>
+    where
+        V: Into<Assigned<F>>,
+    {
+        Value {
+            inner: self.inner.map(|v| v.into()),
+        }
+    }
+
+    /// Doubles this field element.
+    ///
+    /// # Examples
+    ///
+    /// If you have a `Value<F: Field>`, convert it to `Value<Assigned<F>>` first:
+    /// ```
+    /// # use halo2curves::pasta::pallas::Base as F;
+    /// use halo2_proofs::{circuit::Value, plonk::Assigned};
+    ///
+    /// let v = Value::known(F::from(2));
+    /// let v: Value<Assigned<F>> = v.into();
+    /// v.double();
+    /// ```
+    pub fn double<F: Field>(&self) -> Value<Assigned<F>>
+    where
+        V: Borrow<Assigned<F>>,
+    {
+        Value {
+            inner: self.inner.as_ref().map(|v| v.borrow().double()),
+        }
+    }
+
+    /// Squares this field element.
+    pub fn square<F: Field>(&self) -> Value<Assigned<F>>
+    where
+        V: Borrow<Assigned<F>>,
+    {
+        Value {
+            inner: self.inner.as_ref().map(|v| v.borrow().square()),
+        }
+    }
+
+    /// Cubes this field element.
+    pub fn cube<F: Field>(&self) -> Value<Assigned<F>>
+    where
+        V: Borrow<Assigned<F>>,
+    {
+        Value {
+            inner: self.inner.as_ref().map(|v| v.borrow().cube()),
+        }
+    }
+
+    /// Inverts this assigned value (taking the inverse of zero to be zero).
+    pub fn invert<F: Field>(&self) -> Value<Assigned<F>>
+    where
+        V: Borrow<Assigned<F>>,
+    {
+        Value {
+            inner: self.inner.as_ref().map(|v| v.borrow().invert()),
+        }
+    }
+}
+
+impl<F: Field> Value<Assigned<F>> {
+    /// Evaluates this value directly, performing an unbatched inversion if necessary.
+    ///
+    /// If the denominator is zero, the returned value is zero.
+    pub fn evaluate(self) -> Value<F> {
+        Value {
+            inner: self.inner.map(|v| v.evaluate()),
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/dev.rs.html b/docs/src/halo2_proofs/dev.rs.html new file mode 100644 index 0000000000..b15dc51289 --- /dev/null +++ b/docs/src/halo2_proofs/dev.rs.html @@ -0,0 +1,3198 @@ +dev.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+
//! Tools for developing circuits.
+
+use std::collections::HashMap;
+use std::collections::HashSet;
+use std::fmt;
+use std::iter;
+use std::ops::{Add, Mul, Neg, Range};
+use std::sync::Arc;
+use std::time::{Duration, Instant};
+
+use blake2b_simd::blake2b;
+use ff::Field;
+
+use crate::{
+    arithmetic::{FieldExt, Group},
+    circuit,
+    plonk::{
+        permutation, Advice, Any, Assigned, Assignment, Challenge, Circuit, Column, ColumnType,
+        ConstraintSystem, Error, Expression, Fixed, FloorPlanner, Instance, Phase, Selector,
+        VirtualCell,
+    },
+    poly::Rotation,
+};
+use rayon::{
+    iter::{
+        IndexedParallelIterator, IntoParallelIterator, IntoParallelRefIterator, ParallelIterator,
+    },
+    slice::ParallelSliceMut,
+};
+
+pub mod metadata;
+mod util;
+
+mod failure;
+pub use failure::{FailureLocation, VerifyFailure};
+
+//pub mod cost;
+//pub use cost::CircuitCost;
+
+mod gates;
+pub use gates::CircuitGates;
+
+#[cfg(feature = "dev-graph")]
+mod graph;
+
+#[cfg(feature = "dev-graph")]
+#[cfg_attr(docsrs, doc(cfg(feature = "dev-graph")))]
+pub use graph::{circuit_dot_graph, layout::CircuitLayout};
+
+#[derive(Debug)]
+struct Region {
+    /// The name of the region. Not required to be unique.
+    name: String,
+    /// The columns involved in this region.
+    columns: HashSet<Column<Any>>,
+    /// The rows that this region starts and ends on, if known.
+    rows: Option<(usize, usize)>,
+    /// The selectors that have been enabled in this region. All other selectors are by
+    /// construction not enabled.
+    enabled_selectors: HashMap<Selector, Vec<usize>>,
+    /// The cells assigned in this region. We store this as a `HashMap` with count so that if any cells
+    /// are double-assigned, they will be visibly darker.
+    cells: HashMap<(Column<Any>, usize), usize>,
+}
+
+impl Region {
+    fn update_extent(&mut self, column: Column<Any>, row: usize) {
+        self.columns.insert(column);
+
+        // The region start is the earliest row assigned to.
+        // The region end is the latest row assigned to.
+        let (mut start, mut end) = self.rows.unwrap_or((row, row));
+        if row < start {
+            // The first row assigned was not at start 0 within the region.
+            start = row;
+        }
+        if row > end {
+            end = row;
+        }
+        self.rows = Some((start, end));
+    }
+}
+
+/// The value of a particular cell within the circuit.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum CellValue<F: Group + Field> {
+    // An unassigned cell.
+    Unassigned,
+    // A cell that has been assigned a value.
+    Assigned(F),
+    // A unique poisoned cell.
+    Poison(usize),
+}
+
+/// The value of a particular cell within the circuit.
+#[derive(Clone, Debug, PartialEq, Eq)]
+enum AdviceCellValue<F: Group + Field> {
+    // A cell that has been assigned a value.
+    Assigned(Arc<Assigned<F>>),
+    // A unique poisoned cell.
+    Poison(usize),
+}
+
+/// A value within an expression.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)]
+enum Value<F: Group + Field> {
+    Real(F),
+    Poison,
+}
+
+impl<F: Group + Field> From<CellValue<F>> for Value<F> {
+    fn from(value: CellValue<F>) -> Self {
+        match value {
+            // Cells that haven't been explicitly assigned to, default to zero.
+            CellValue::Unassigned => Value::Real(F::zero()),
+            CellValue::Assigned(v) => Value::Real(v),
+            CellValue::Poison(_) => Value::Poison,
+        }
+    }
+}
+
+impl<F: Group + Field> Neg for Value<F> {
+    type Output = Self;
+
+    fn neg(self) -> Self::Output {
+        match self {
+            Value::Real(a) => Value::Real(-a),
+            _ => Value::Poison,
+        }
+    }
+}
+
+impl<F: Group + Field> Add for Value<F> {
+    type Output = Self;
+
+    fn add(self, rhs: Self) -> Self::Output {
+        match (self, rhs) {
+            (Value::Real(a), Value::Real(b)) => Value::Real(a + b),
+            _ => Value::Poison,
+        }
+    }
+}
+
+impl<F: Group + Field> Mul for Value<F> {
+    type Output = Self;
+
+    fn mul(self, rhs: Self) -> Self::Output {
+        match (self, rhs) {
+            (Value::Real(a), Value::Real(b)) => Value::Real(a * b),
+            // If poison is multiplied by zero, then we treat the poison as unconstrained
+            // and we don't propagate it.
+            (Value::Real(x), Value::Poison) | (Value::Poison, Value::Real(x))
+                if x.is_zero_vartime() =>
+            {
+                Value::Real(F::zero())
+            }
+            _ => Value::Poison,
+        }
+    }
+}
+
+impl<F: Group + Field> Mul<F> for Value<F> {
+    type Output = Self;
+
+    fn mul(self, rhs: F) -> Self::Output {
+        match self {
+            Value::Real(lhs) => Value::Real(lhs * rhs),
+            // If poison is multiplied by zero, then we treat the poison as unconstrained
+            // and we don't propagate it.
+            Value::Poison if rhs.is_zero_vartime() => Value::Real(F::zero()),
+            _ => Value::Poison,
+        }
+    }
+}
+
+/// A test prover for debugging circuits.
+///
+/// The normal proving process, when applied to a buggy circuit implementation, might
+/// return proofs that do not validate when they should, but it can't indicate anything
+/// other than "something is invalid". `MockProver` can be used to figure out _why_ these
+/// are invalid: it stores all the private inputs along with the circuit internals, and
+/// then checks every constraint manually.
+///
+/// # Examples
+///
+/// ```
+/// use halo2_proofs::{
+///     arithmetic::FieldExt,
+///     circuit::{Layouter, SimpleFloorPlanner, Value},
+///     dev::{FailureLocation, MockProver, VerifyFailure},
+///     plonk::{Advice, Any, Circuit, Column, ConstraintSystem, Error, Selector},
+///     poly::Rotation,
+/// };
+/// use halo2curves::pasta::Fp;
+/// const K: u32 = 5;
+///
+/// #[derive(Copy, Clone)]
+/// struct MyConfig {
+///     a: Column<Advice>,
+///     b: Column<Advice>,
+///     c: Column<Advice>,
+///     s: Selector,
+/// }
+///
+/// #[derive(Clone, Default)]
+/// struct MyCircuit {
+///     a: Value<u64>,
+///     b: Value<u64>,
+/// }
+///
+/// impl<F: FieldExt> Circuit<F> for MyCircuit {
+///     type Config = MyConfig;
+///     type FloorPlanner = SimpleFloorPlanner;
+///
+///     fn without_witnesses(&self) -> Self {
+///         Self::default()
+///     }
+///
+///     fn configure(meta: &mut ConstraintSystem<F>) -> MyConfig {
+///         let a = meta.advice_column();
+///         let b = meta.advice_column();
+///         let c = meta.advice_column();
+///         let s = meta.selector();
+///
+///         meta.create_gate("R1CS constraint", |meta| {
+///             let a = meta.query_advice(a, Rotation::cur());
+///             let b = meta.query_advice(b, Rotation::cur());
+///             let c = meta.query_advice(c, Rotation::cur());
+///             let s = meta.query_selector(s);
+///
+///             // BUG: Should be a * b - c
+///             Some(("buggy R1CS", s * (a * b + c)))
+///         });
+///
+///         MyConfig { a, b, c, s }
+///     }
+///
+///     fn synthesize(&self, config: MyConfig, mut layouter: impl Layouter<F>) -> Result<(), Error> {
+///         layouter.assign_region(|| "Example region", |mut region| {
+///             config.s.enable(&mut region, 0)?;
+///             region.assign_advice(|| "a", config.a, 0, || {
+///                 self.a.map(F::from)
+///             })?;
+///             region.assign_advice(|| "b", config.b, 0, || {
+///                 self.b.map(F::from)
+///             })?;
+///             region.assign_advice(|| "c", config.c, 0, || {
+///                 (self.a * self.b).map(F::from)
+///             })?;
+///             Ok(())
+///         })
+///     }
+/// }
+///
+/// // Assemble the private inputs to the circuit.
+/// let circuit = MyCircuit {
+///     a: Value::known(2),
+///     b: Value::known(4),
+/// };
+///
+/// // This circuit has no public inputs.
+/// let instance = vec![];
+///
+/// let prover = MockProver::<Fp>::run(K, &circuit, instance).unwrap();
+/// assert_eq!(
+///     prover.verify(),
+///     Err(vec![VerifyFailure::ConstraintNotSatisfied {
+///         constraint: ((0, "R1CS constraint").into(), 0, "buggy R1CS").into(),
+///         location: FailureLocation::InRegion {
+///             region: (0, "Example region").into(),
+///             offset: 0,
+///         },
+///         cell_values: vec![
+///             (((Any::advice(), 0).into(), 0).into(), "0x2".to_string()),
+///             (((Any::advice(), 1).into(), 0).into(), "0x4".to_string()),
+///             (((Any::advice(), 2).into(), 0).into(), "0x8".to_string()),
+///         ],
+///     }])
+/// );
+///
+/// // If we provide a too-small K, we get an error.
+/// assert!(matches!(
+///     MockProver::<Fp>::run(2, &circuit, vec![]).unwrap_err(),
+///     Error::NotEnoughRowsAvailable {
+///         current_k,
+///     } if current_k == 2,
+/// ));
+/// ```
+#[derive(Debug)]
+pub struct MockProver<F: Group + Field> {
+    k: u32,
+    n: u32,
+    cs: ConstraintSystem<F>,
+
+    /// The regions in the circuit.
+    regions: Vec<Region>,
+    /// The current region being assigned to. Will be `None` after the circuit has been
+    /// synthesized.
+    current_region: Option<Region>,
+
+    // The fixed cells in the circuit, arranged as [column][row].
+    fixed: Vec<Vec<CellValue<F>>>,
+    // The advice cells in the circuit, arranged as [column][row].
+    advice: Vec<Vec<AdviceCellValue<F>>>,
+    // The instance cells in the circuit, arranged as [column][row].
+    instance: Vec<Vec<F>>,
+
+    selectors: Vec<Vec<bool>>,
+
+    challenges: Vec<F>,
+
+    permutation: permutation::keygen::Assembly,
+
+    // A range of available rows for assignment and copies.
+    usable_rows: Range<usize>,
+}
+
+impl<F: Field + Group> Assignment<F> for MockProver<F> {
+    fn enter_region<NR, N>(&mut self, name: N)
+    where
+        NR: Into<String>,
+        N: FnOnce() -> NR,
+    {
+        assert!(self.current_region.is_none());
+        self.current_region = Some(Region {
+            name: name().into(),
+            columns: HashSet::default(),
+            rows: None,
+            enabled_selectors: HashMap::default(),
+            cells: HashMap::default(),
+        });
+    }
+
+    fn exit_region(&mut self) {
+        self.regions.push(self.current_region.take().unwrap());
+    }
+
+    fn enable_selector<A, AR>(&mut self, _: A, selector: &Selector, row: usize) -> Result<(), Error>
+    where
+        A: FnOnce() -> AR,
+        AR: Into<String>,
+    {
+        if !self.usable_rows.contains(&row) {
+            return Err(Error::not_enough_rows_available(self.k));
+        }
+
+        // Track that this selector was enabled. We require that all selectors are enabled
+        // inside some region (i.e. no floating selectors).
+        self.current_region
+            .as_mut()
+            .unwrap()
+            .enabled_selectors
+            .entry(*selector)
+            .or_default()
+            .push(row);
+
+        self.selectors[selector.0][row] = true;
+
+        Ok(())
+    }
+
+    fn query_instance(
+        &self,
+        column: Column<Instance>,
+        row: usize,
+    ) -> Result<circuit::Value<F>, Error> {
+        if !self.usable_rows.contains(&row) {
+            return Err(Error::not_enough_rows_available(self.k));
+        }
+
+        self.instance
+            .get(column.index())
+            .and_then(|column| column.get(row))
+            .map(|v| circuit::Value::known(*v))
+            .ok_or(Error::BoundsFailure)
+    }
+
+    fn assign_advice<'r, 'v>(
+        //<V, VR, A, AR>(
+        &'r mut self,
+        //_: A,
+        column: Column<Advice>,
+        row: usize,
+        to: circuit::Value<Assigned<F>>,
+    ) -> Result<circuit::Value<&'v Assigned<F>>, Error> {
+        if !self.usable_rows.contains(&row) {
+            return Err(Error::not_enough_rows_available(self.k));
+        }
+
+        if let Some(region) = self.current_region.as_mut() {
+            region.update_extent(column.into(), row);
+            region
+                .cells
+                .entry((column.into(), row))
+                .and_modify(|count| *count += 1)
+                .or_default();
+        }
+
+        let advice_get_mut = self
+            .advice
+            .get_mut(column.index())
+            .and_then(|v| v.get_mut(row))
+            .ok_or(Error::BoundsFailure)?;
+
+        let val = Arc::new(to.assign()?);
+        let val_ref = Arc::downgrade(&val);
+        *advice_get_mut = AdviceCellValue::Assigned(val);
+
+        Ok(circuit::Value::known(unsafe { &*val_ref.as_ptr() }))
+    }
+
+    fn assign_fixed(&mut self, column: Column<Fixed>, row: usize, to: Assigned<F>) {
+        if !self.usable_rows.contains(&row) {
+            panic!("{:?}", Error::not_enough_rows_available(self.k));
+        }
+
+        if let Some(region) = self.current_region.as_mut() {
+            region.update_extent(column.into(), row);
+            region
+                .cells
+                .entry((column.into(), row))
+                .and_modify(|count| *count += 1)
+                .or_default();
+        }
+
+        *self
+            .fixed
+            .get_mut(column.index())
+            .and_then(|v| v.get_mut(row))
+            .unwrap_or_else(|| panic!("{:?}", Error::BoundsFailure)) =
+            CellValue::Assigned(to.evaluate());
+    }
+
+    fn copy(
+        &mut self,
+        left_column: Column<Any>,
+        left_row: usize,
+        right_column: Column<Any>,
+        right_row: usize,
+    ) {
+        if !self.usable_rows.contains(&left_row) || !self.usable_rows.contains(&right_row) {
+            panic!("{:?}", Error::not_enough_rows_available(self.k));
+        }
+
+        self.permutation
+            .copy(left_column, left_row, right_column, right_row)
+            .unwrap_or_else(|err| panic!("{err:?}"))
+    }
+
+    fn fill_from_row(
+        &mut self,
+        col: Column<Fixed>,
+        from_row: usize,
+        to: circuit::Value<Assigned<F>>,
+    ) -> Result<(), Error> {
+        if !self.usable_rows.contains(&from_row) {
+            return Err(Error::not_enough_rows_available(self.k));
+        }
+
+        for row in self.usable_rows.clone().skip(from_row) {
+            self.assign_fixed(col, row, to.assign()?);
+        }
+
+        Ok(())
+    }
+
+    fn get_challenge(&self, challenge: Challenge) -> circuit::Value<F> {
+        circuit::Value::known(self.challenges[challenge.index()])
+    }
+
+    fn push_namespace<NR, N>(&mut self, _: N)
+    where
+        NR: Into<String>,
+        N: FnOnce() -> NR,
+    {
+        // TODO: Do something with namespaces :)
+    }
+
+    fn pop_namespace(&mut self, _: Option<String>) {
+        // TODO: Do something with namespaces :)
+    }
+}
+
+impl<F: FieldExt> MockProver<F> {
+    /// Runs a synthetic keygen-and-prove operation on the given circuit, collecting data
+    /// about the constraints and their assignments.
+    pub fn run<ConcreteCircuit: Circuit<F>>(
+        k: u32,
+        circuit: &ConcreteCircuit,
+        instance: Vec<Vec<F>>,
+    ) -> Result<Self, Error> {
+        let n = 1 << k;
+
+        let mut cs = ConstraintSystem::default();
+        let config = ConcreteCircuit::configure(&mut cs);
+        let cs = cs;
+
+        if n < cs.minimum_rows() {
+            return Err(Error::not_enough_rows_available(k));
+        }
+
+        if instance.len() != cs.num_instance_columns {
+            return Err(Error::InvalidInstances);
+        }
+
+        let instance = instance
+            .into_iter()
+            .map(|mut instance| {
+                if instance.len() > n - (cs.blinding_factors() + 1) {
+                    return Err(Error::InstanceTooLarge);
+                }
+
+                instance.resize(n, F::zero());
+                Ok(instance)
+            })
+            .collect::<Result<Vec<_>, _>>()?;
+
+        // Fixed columns contain no blinding factors.
+        let fixed = vec![vec![CellValue::Unassigned; n]; cs.num_fixed_columns];
+        let selectors = vec![vec![false; n]; cs.num_selectors];
+        // Advice columns contain blinding factors.
+        let blinding_factors = cs.blinding_factors();
+        let usable_rows = n - (blinding_factors + 1);
+        let advice = vec![
+            {
+                // let mut column = vec![AdviceCellValue::Unassigned; n];
+                // Assign advice to 0 by default so we can have gates that query unassigned rotations to minimize number of distinct rotation sets, for SHPLONK optimization
+                let mut column =
+                    vec![AdviceCellValue::Assigned(Arc::new(Assigned::Trivial(F::zero()))); n];
+                // Poison unusable rows.
+                for (i, cell) in column.iter_mut().enumerate().skip(usable_rows) {
+                    *cell = AdviceCellValue::Poison(i);
+                }
+                column
+            };
+            cs.num_advice_columns
+        ];
+        let permutation = permutation::keygen::Assembly::new(n, &cs.permutation);
+        let constants = cs.constants.clone();
+
+        // Use hash chain to derive deterministic challenges for testing
+        let challenges = {
+            let mut hash: [u8; 64] = blake2b(b"Halo2-MockProver").as_bytes().try_into().unwrap();
+            iter::repeat_with(|| {
+                hash = blake2b(&hash).as_bytes().try_into().unwrap();
+                F::from_bytes_wide(&hash)
+            })
+            .take(cs.num_challenges)
+            .collect()
+        };
+
+        let mut prover = MockProver {
+            k,
+            n: n as u32,
+            cs,
+            regions: vec![],
+            current_region: None,
+            fixed,
+            advice,
+            instance,
+            selectors,
+            challenges,
+            permutation,
+            usable_rows: 0..usable_rows,
+        };
+
+        ConcreteCircuit::FloorPlanner::synthesize(&mut prover, circuit, config, constants)?;
+
+        let (cs, selector_polys) = prover.cs.compress_selectors(prover.selectors.clone());
+        prover.cs = cs;
+        prover.fixed.extend(selector_polys.into_iter().map(|poly| {
+            let mut v = vec![CellValue::Unassigned; n];
+            for (v, p) in v.iter_mut().zip(&poly[..]) {
+                *v = CellValue::Assigned(*p);
+            }
+            v
+        }));
+
+        Ok(prover)
+    }
+
+    /// Returns `Ok(())` if this `MockProver` is satisfied, or a list of errors indicating
+    /// the reasons that the circuit is not satisfied.
+    pub fn verify(&self) -> Result<(), Vec<VerifyFailure>> {
+        self.verify_at_rows(self.usable_rows.clone(), self.usable_rows.clone())
+    }
+
+    /// Returns `Ok(())` if this `MockProver` is satisfied, or a list of errors indicating
+    /// the reasons that the circuit is not satisfied.
+    /// Constraints are only checked at `gate_row_ids`,
+    /// and lookup inputs are only checked at `lookup_input_row_ids`
+    pub fn verify_at_rows<I: Clone + Iterator<Item = usize>>(
+        &self,
+        gate_row_ids: I,
+        lookup_input_row_ids: I,
+    ) -> Result<(), Vec<VerifyFailure>> {
+        let n = self.n as i32;
+
+        // check all the row ids are valid
+        for row_id in gate_row_ids.clone() {
+            if !self.usable_rows.contains(&row_id) {
+                panic!("invalid gate row id {}", row_id)
+            }
+        }
+        for row_id in lookup_input_row_ids.clone() {
+            if !self.usable_rows.contains(&row_id) {
+                panic!("invalid lookup row id {}", row_id)
+            }
+        }
+
+        // Check that within each region, all cells used in instantiated gates have been
+        // assigned to.
+
+        // Turn off this check because we might query unassigned cells to increase the rotation set size of a gate (for SHPLONK optimization)
+        /*
+        let selector_errors = self.regions.iter().enumerate().flat_map(|(r_i, r)| {
+            r.enabled_selectors.iter().flat_map(move |(selector, at)| {
+                // Find the gates enabled by this selector
+                self.cs
+                    .gates
+                    .iter()
+                    // Assume that if a queried selector is enabled, the user wants to use the
+                    // corresponding gate in some way.
+                    //
+                    // TODO: This will trip up on the reverse case, where leaving a selector
+                    // un-enabled keeps a gate enabled. We could alternatively require that
+                    // every selector is explicitly enabled or disabled on every row? But that
+                    // seems messy and confusing.
+                    .enumerate()
+                    .filter(move |(_, g)| g.queried_selectors().contains(selector))
+                    .flat_map(move |(gate_index, gate)| {
+                        at.iter().flat_map(move |selector_row| {
+                            // Selectors are queried with no rotation.
+                            let gate_row = *selector_row as i32;
+
+                            gate.queried_cells().iter().filter_map(move |cell| {
+                                // Determine where this cell should have been assigned.
+                                let cell_row = ((gate_row + n + cell.rotation.0) % n) as usize;
+
+                                // Check that it was assigned!
+                                if r.cells.contains_key(&(cell.column, cell_row)) {
+                                    None
+                                } else {
+                                    Some(VerifyFailure::CellNotAssigned {
+                                        gate: (gate_index, gate.name()).into(),
+                                        region: (r_i, r.name.clone()).into(),
+                                        gate_offset: *selector_row,
+                                        column: cell.column,
+                                        offset: cell_row as isize - r.rows.unwrap().0 as isize,
+                                    })
+                                }
+                            })
+                        })
+                    })
+            })
+        });
+        */
+
+        let advice = self
+            .advice
+            .iter()
+            .map(|advice| {
+                advice
+                    .iter()
+                    .map(|rc| match *rc {
+                        AdviceCellValue::Assigned(ref a) => CellValue::Assigned(match a.as_ref() {
+                            Assigned::Trivial(a) => *a,
+                            Assigned::Rational(a, b) => *a * b.invert().unwrap(),
+                            _ => F::zero(),
+                        }),
+                        AdviceCellValue::Poison(i) => CellValue::Poison(i),
+                    })
+                    .collect::<Vec<_>>()
+            })
+            .collect::<Vec<_>>();
+        let advice = &advice;
+        // Check that all gates are satisfied for all rows.
+        let gate_errors =
+            self.cs
+                .gates
+                .iter()
+                .enumerate()
+                .flat_map(|(gate_index, gate)| {
+                    let blinding_rows =
+                        (self.n as usize - (self.cs.blinding_factors() + 1))..(self.n as usize);
+                    (gate_row_ids
+                        .clone()
+                        .into_iter()
+                        .chain(blinding_rows.into_iter()))
+                    .flat_map(move |row| {
+                        let row = row as i32 + n;
+                        gate.polynomials().iter().enumerate().filter_map(
+                            move |(poly_index, poly)| match poly.evaluate_lazy(
+                                &|scalar| Value::Real(scalar),
+                                &|_| panic!("virtual selectors are removed during optimization"),
+                                &util::load(n, row, &self.cs.fixed_queries, &self.fixed),
+                                &util::load(n, row, &self.cs.advice_queries, advice),
+                                &util::load_instance(
+                                    n,
+                                    row,
+                                    &self.cs.instance_queries,
+                                    &self.instance,
+                                ),
+                                &|challenge| Value::Real(self.challenges[challenge.index()]),
+                                &|a| -a,
+                                &|a, b| a + b,
+                                &|a, b| a * b,
+                                &|a, scalar| a * scalar,
+                                &Value::Real(F::zero()),
+                            ) {
+                                Value::Real(x) if x.is_zero_vartime() => None,
+                                Value::Real(_) => Some(VerifyFailure::ConstraintNotSatisfied {
+                                    constraint: (
+                                        (gate_index, gate.name()).into(),
+                                        poly_index,
+                                        gate.constraint_name(poly_index),
+                                    )
+                                        .into(),
+                                    location: FailureLocation::find_expressions(
+                                        &self.cs,
+                                        &self.regions,
+                                        (row - n) as usize,
+                                        Some(poly).into_iter(),
+                                    ),
+                                    cell_values: util::cell_values(
+                                        gate,
+                                        poly,
+                                        &util::load(n, row, &self.cs.fixed_queries, &self.fixed),
+                                        &util::load(n, row, &self.cs.advice_queries, advice),
+                                        &util::load_instance(
+                                            n,
+                                            row,
+                                            &self.cs.instance_queries,
+                                            &self.instance,
+                                        ),
+                                    ),
+                                }),
+                                Value::Poison => Some(VerifyFailure::ConstraintPoisoned {
+                                    constraint: (
+                                        (gate_index, gate.name()).into(),
+                                        poly_index,
+                                        gate.constraint_name(poly_index),
+                                    )
+                                        .into(),
+                                }),
+                            },
+                        )
+                    })
+                });
+
+        let mut cached_table = Vec::new();
+        let mut cached_table_identifier = Vec::new();
+        // Check that all lookups exist in their respective tables.
+        let lookup_errors =
+            self.cs
+                .lookups
+                .iter()
+                .enumerate()
+                .flat_map(|(lookup_index, lookup)| {
+                    let load = |expression: &Expression<F>, row| {
+                        expression.evaluate_lazy(
+                            &|scalar| Value::Real(scalar),
+                            &|_| panic!("virtual selectors are removed during optimization"),
+                            &|query| {
+                                let query = self.cs.fixed_queries[query.index];
+                                let column_index = query.0.index();
+                                let rotation = query.1 .0;
+                                self.fixed[column_index]
+                                    [(row as i32 + n + rotation) as usize % n as usize]
+                                    .into()
+                            },
+                            &|query| {
+                                let query = self.cs.advice_queries[query.index];
+                                let column_index = query.0.index();
+                                let rotation = query.1 .0;
+                                advice[column_index]
+                                    [(row as i32 + n + rotation) as usize % n as usize]
+                                    .into()
+                            },
+                            &|query| {
+                                let query = self.cs.instance_queries[query.index];
+                                let column_index = query.0.index();
+                                let rotation = query.1 .0;
+                                Value::Real(
+                                    self.instance[column_index]
+                                        [(row as i32 + n + rotation) as usize % n as usize],
+                                )
+                            },
+                            &|challenge| Value::Real(self.challenges[challenge.index()]),
+                            &|a| -a,
+                            &|a, b| a + b,
+                            &|a, b| a * b,
+                            &|a, scalar| a * scalar,
+                            &Value::Real(F::zero()),
+                        )
+                    };
+
+                    assert!(lookup.table_expressions.len() == lookup.input_expressions.len());
+                    assert!(self.usable_rows.end > 0);
+
+                    // We optimize on the basis that the table might have been filled so that the last
+                    // usable row now has the fill contents (it doesn't matter if there was no filling).
+                    // Note that this "fill row" necessarily exists in the table, and we use that fact to
+                    // slightly simplify the optimization: we're only trying to check that all input rows
+                    // are contained in the table, and so we can safely just drop input rows that
+                    // match the fill row.
+                    let fill_row: Vec<_> = lookup
+                        .table_expressions
+                        .iter()
+                        .map(move |c| load(c, self.usable_rows.end - 1))
+                        .collect();
+
+                    let table_identifier = lookup
+                        .table_expressions
+                        .iter()
+                        .map(Expression::identifier)
+                        .collect::<Vec<_>>();
+                    if table_identifier != cached_table_identifier {
+                        cached_table_identifier = table_identifier;
+
+                        // In the real prover, the lookup expressions are never enforced on
+                        // unusable rows, due to the (1 - (l_last(X) + l_blind(X))) term.
+                        cached_table = self
+                            .usable_rows
+                            .clone()
+                            .filter_map(|table_row| {
+                                let t = lookup
+                                    .table_expressions
+                                    .iter()
+                                    .map(move |c| load(c, table_row))
+                                    .collect();
+
+                                if t != fill_row {
+                                    Some(t)
+                                } else {
+                                    None
+                                }
+                            })
+                            .collect();
+                        cached_table.sort_unstable();
+                    }
+                    let table = &cached_table;
+
+                    let mut inputs: Vec<(Vec<_>, usize)> = lookup_input_row_ids
+                        .clone()
+                        .into_iter()
+                        .filter_map(|input_row| {
+                            let t = lookup
+                                .input_expressions
+                                .iter()
+                                .map(move |c| load(c, input_row))
+                                .collect();
+
+                            if t != fill_row {
+                                // Also keep track of the original input row, since we're going to sort.
+                                Some((t, input_row))
+                            } else {
+                                None
+                            }
+                        })
+                        .collect();
+                    inputs.sort_unstable();
+
+                    let mut i = 0;
+                    inputs
+                        .iter()
+                        .filter_map(move |(input, input_row)| {
+                            while i < table.len() && &table[i] < input {
+                                i += 1;
+                            }
+                            if i == table.len() || &table[i] > input {
+                                assert!(table.binary_search(input).is_err());
+
+                                Some(VerifyFailure::Lookup {
+                                    name: lookup.name,
+                                    lookup_index,
+                                    location: FailureLocation::find_expressions(
+                                        &self.cs,
+                                        &self.regions,
+                                        *input_row,
+                                        lookup.input_expressions.iter(),
+                                    ),
+                                })
+                            } else {
+                                None
+                            }
+                        })
+                        .collect::<Vec<_>>()
+                });
+
+        // Check that permutations preserve the original values of the cells.
+        let perm_errors = {
+            // Original values of columns involved in the permutation.
+            let original = |column, row| {
+                self.cs
+                    .permutation
+                    .get_columns()
+                    .get(column)
+                    .map(|c: &Column<Any>| match c.column_type() {
+                        Any::Advice(_) => advice[c.index()][row],
+                        Any::Fixed => self.fixed[c.index()][row],
+                        Any::Instance => CellValue::Assigned(self.instance[c.index()][row]),
+                    })
+                    .unwrap()
+            };
+
+            // Iterate over each column of the permutation
+            self.permutation
+                .mapping
+                .iter()
+                .enumerate()
+                .flat_map(move |(column, values)| {
+                    // Iterate over each row of the column to check that the cell's
+                    // value is preserved by the mapping.
+                    values.iter().enumerate().filter_map(move |(row, cell)| {
+                        let original_cell = original(column, row);
+                        let permuted_cell = original(cell.0, cell.1);
+                        if original_cell == permuted_cell {
+                            None
+                        } else {
+                            let columns = self.cs.permutation.get_columns();
+                            let column = columns.get(column).unwrap();
+                            Some(VerifyFailure::Permutation {
+                                column: (*column).into(),
+                                location: FailureLocation::find(
+                                    &self.regions,
+                                    row,
+                                    Some(column).into_iter().cloned().collect(),
+                                ),
+                            })
+                        }
+                    })
+                })
+        };
+
+        let mut errors: Vec<_> = iter::empty()
+            //.chain(selector_errors)
+            .chain(gate_errors)
+            .chain(lookup_errors)
+            .chain(perm_errors)
+            .collect();
+        if errors.is_empty() {
+            Ok(())
+        } else {
+            // Remove any duplicate `ConstraintPoisoned` errors (we check all unavailable
+            // rows in case the trigger is row-specific, but the error message only points
+            // at the constraint).
+            errors.dedup_by(|a, b| match (a, b) {
+                (
+                    a @ VerifyFailure::ConstraintPoisoned { .. },
+                    b @ VerifyFailure::ConstraintPoisoned { .. },
+                ) => a == b,
+                _ => false,
+            });
+            Err(errors)
+        }
+    }
+
+    /// Returns `Ok(())` if this `MockProver` is satisfied, or a list of errors indicating
+    /// the reasons that the circuit is not satisfied.
+    /// Constraints and lookup are checked at `usable_rows`, parallelly.
+    pub fn verify_par(&self) -> Result<(), Vec<VerifyFailure>> {
+        self.verify_at_rows_par(self.usable_rows.clone(), self.usable_rows.clone())
+    }
+
+    /// Returns `Ok(())` if this `MockProver` is satisfied, or a list of errors indicating
+    /// the reasons that the circuit is not satisfied.
+    /// Constraints are only checked at `gate_row_ids`,
+    /// and lookup inputs are only checked at `lookup_input_row_ids`, parallelly.
+    pub fn verify_at_rows_par<I: Clone + Iterator<Item = usize>>(
+        &self,
+        gate_row_ids: I,
+        lookup_input_row_ids: I,
+    ) -> Result<(), Vec<VerifyFailure>> {
+        let n = self.n as i32;
+
+        let gate_row_ids = gate_row_ids.collect::<Vec<_>>();
+        let lookup_input_row_ids = lookup_input_row_ids.collect::<Vec<_>>();
+
+        // check all the row ids are valid
+        gate_row_ids.par_iter().for_each(|row_id| {
+            if !self.usable_rows.contains(row_id) {
+                panic!("invalid gate row id {}", row_id);
+            }
+        });
+        lookup_input_row_ids.par_iter().for_each(|row_id| {
+            if !self.usable_rows.contains(row_id) {
+                panic!("invalid gate row id {}", row_id);
+            }
+        });
+
+        // Check that within each region, all cells used in instantiated gates have been
+        // assigned to.
+        let selector_errors = self.regions.iter().enumerate().flat_map(|(r_i, r)| {
+            r.enabled_selectors.iter().flat_map(move |(selector, at)| {
+                // Find the gates enabled by this selector
+                self.cs
+                    .gates
+                    .iter()
+                    // Assume that if a queried selector is enabled, the user wants to use the
+                    // corresponding gate in some way.
+                    //
+                    // TODO: This will trip up on the reverse case, where leaving a selector
+                    // un-enabled keeps a gate enabled. We could alternatively require that
+                    // every selector is explicitly enabled or disabled on every row? But that
+                    // seems messy and confusing.
+                    .enumerate()
+                    .filter(move |(_, g)| g.queried_selectors().contains(selector))
+                    .flat_map(move |(gate_index, gate)| {
+                        at.par_iter()
+                            .flat_map(move |selector_row| {
+                                // Selectors are queried with no rotation.
+                                let gate_row = *selector_row as i32;
+
+                                gate.queried_cells()
+                                    .iter()
+                                    .filter_map(move |cell| {
+                                        // Determine where this cell should have been assigned.
+                                        let cell_row =
+                                            ((gate_row + n + cell.rotation.0) % n) as usize;
+
+                                        // Check that it was assigned!
+                                        if r.cells.contains_key(&(cell.column, cell_row)) {
+                                            None
+                                        } else {
+                                            Some(VerifyFailure::CellNotAssigned {
+                                                gate: (gate_index, gate.name()).into(),
+                                                region: (r_i, r.name.clone()).into(),
+                                                gate_offset: *selector_row,
+                                                column: cell.column,
+                                                offset: cell_row as isize
+                                                    - r.rows.unwrap().0 as isize,
+                                            })
+                                        }
+                                    })
+                                    .collect::<Vec<_>>()
+                            })
+                            .collect::<Vec<_>>()
+                    })
+            })
+        });
+
+        let advice = self
+            .advice
+            .iter()
+            .map(|advice| {
+                advice
+                    .iter()
+                    .map(|rc| match *rc {
+                        AdviceCellValue::Assigned(ref a) => CellValue::Assigned(match a.as_ref() {
+                            Assigned::Trivial(a) => *a,
+                            Assigned::Rational(a, b) => *a * b.invert().unwrap(),
+                            _ => F::zero(),
+                        }),
+                        AdviceCellValue::Poison(i) => CellValue::Poison(i),
+                    })
+                    .collect::<Vec<_>>()
+            })
+            .collect::<Vec<_>>();
+        let advice = &advice;
+        // Check that all gates are satisfied for all rows.
+        let gate_errors = self
+            .cs
+            .gates
+            .iter()
+            .enumerate()
+            .flat_map(|(gate_index, gate)| {
+                let blinding_rows =
+                    (self.n as usize - (self.cs.blinding_factors() + 1))..(self.n as usize);
+                (gate_row_ids
+                    .clone()
+                    .into_par_iter()
+                    .chain(blinding_rows.into_par_iter()))
+                .flat_map(move |row| {
+                    let row = row as i32 + n;
+                    gate.polynomials()
+                        .iter()
+                        .enumerate()
+                        .filter_map(move |(poly_index, poly)| {
+                            match poly.evaluate_lazy(
+                                &|scalar| Value::Real(scalar),
+                                &|_| panic!("virtual selectors are removed during optimization"),
+                                &util::load(n, row, &self.cs.fixed_queries, &self.fixed),
+                                &util::load(n, row, &self.cs.advice_queries, &advice),
+                                &util::load_instance(
+                                    n,
+                                    row,
+                                    &self.cs.instance_queries,
+                                    &self.instance,
+                                ),
+                                &|challenge| Value::Real(self.challenges[challenge.index()]),
+                                &|a| -a,
+                                &|a, b| a + b,
+                                &|a, b| a * b,
+                                &|a, scalar| a * scalar,
+                                &Value::Real(F::zero()),
+                            ) {
+                                Value::Real(x) if x.is_zero_vartime() => None,
+                                Value::Real(_) => Some(VerifyFailure::ConstraintNotSatisfied {
+                                    constraint: (
+                                        (gate_index, gate.name()).into(),
+                                        poly_index,
+                                        gate.constraint_name(poly_index),
+                                    )
+                                        .into(),
+                                    location: FailureLocation::find_expressions(
+                                        &self.cs,
+                                        &self.regions,
+                                        (row - n) as usize,
+                                        Some(poly).into_iter(),
+                                    ),
+                                    cell_values: util::cell_values(
+                                        gate,
+                                        poly,
+                                        &util::load(n, row, &self.cs.fixed_queries, &self.fixed),
+                                        &util::load(n, row, &self.cs.advice_queries, &advice),
+                                        &util::load_instance(
+                                            n,
+                                            row,
+                                            &self.cs.instance_queries,
+                                            &self.instance,
+                                        ),
+                                    ),
+                                }),
+                                Value::Poison => Some(VerifyFailure::ConstraintPoisoned {
+                                    constraint: (
+                                        (gate_index, gate.name()).into(),
+                                        poly_index,
+                                        gate.constraint_name(poly_index),
+                                    )
+                                        .into(),
+                                }),
+                            }
+                        })
+                        .collect::<Vec<_>>()
+                })
+                .collect::<Vec<_>>()
+            });
+
+        let mut cached_table = Vec::new();
+        let mut cached_table_identifier = Vec::new();
+        // Check that all lookups exist in their respective tables.
+        let lookup_errors =
+            self.cs
+                .lookups
+                .iter()
+                .enumerate()
+                .flat_map(|(lookup_index, lookup)| {
+                    let load = |expression: &Expression<F>, row| {
+                        expression.evaluate_lazy(
+                            &|scalar| Value::Real(scalar),
+                            &|_| panic!("virtual selectors are removed during optimization"),
+                            &|query| {
+                                self.fixed[query.column_index]
+                                    [(row as i32 + n + query.rotation.0) as usize % n as usize]
+                                    .into()
+                            },
+                            &|query| {
+                                advice[query.column_index]
+                                    [(row as i32 + n + query.rotation.0) as usize % n as usize]
+                                    .into()
+                            },
+                            &|query| {
+                                Value::Real(
+                                    self.instance[query.column_index]
+                                        [(row as i32 + n + query.rotation.0) as usize % n as usize],
+                                )
+                            },
+                            &|challenge| Value::Real(self.challenges[challenge.index()]),
+                            &|a| -a,
+                            &|a, b| a + b,
+                            &|a, b| a * b,
+                            &|a, scalar| a * scalar,
+                            &Value::Real(F::zero()),
+                        )
+                    };
+
+                    assert!(lookup.table_expressions.len() == lookup.input_expressions.len());
+                    assert!(self.usable_rows.end > 0);
+
+                    // We optimize on the basis that the table might have been filled so that the last
+                    // usable row now has the fill contents (it doesn't matter if there was no filling).
+                    // Note that this "fill row" necessarily exists in the table, and we use that fact to
+                    // slightly simplify the optimization: we're only trying to check that all input rows
+                    // are contained in the table, and so we can safely just drop input rows that
+                    // match the fill row.
+                    let fill_row: Vec<_> = lookup
+                        .table_expressions
+                        .iter()
+                        .map(move |c| load(c, self.usable_rows.end - 1))
+                        .collect();
+
+                    let table_identifier = lookup
+                        .table_expressions
+                        .iter()
+                        .map(Expression::identifier)
+                        .collect::<Vec<_>>();
+                    if table_identifier != cached_table_identifier {
+                        cached_table_identifier = table_identifier;
+
+                        // In the real prover, the lookup expressions are never enforced on
+                        // unusable rows, due to the (1 - (l_last(X) + l_blind(X))) term.
+                        cached_table = self
+                            .usable_rows
+                            .clone()
+                            .into_par_iter()
+                            .filter_map(|table_row| {
+                                let t = lookup
+                                    .table_expressions
+                                    .iter()
+                                    .map(move |c| load(c, table_row))
+                                    .collect();
+
+                                if t != fill_row {
+                                    Some(t)
+                                } else {
+                                    None
+                                }
+                            })
+                            .collect();
+                        cached_table.par_sort_unstable();
+                    }
+                    let table = &cached_table;
+
+                    let mut inputs: Vec<(Vec<_>, usize)> = lookup_input_row_ids
+                        .clone()
+                        .into_par_iter()
+                        .filter_map(|input_row| {
+                            let t = lookup
+                                .input_expressions
+                                .iter()
+                                .map(move |c| load(c, input_row))
+                                .collect();
+
+                            if t != fill_row {
+                                // Also keep track of the original input row, since we're going to sort.
+                                Some((t, input_row))
+                            } else {
+                                None
+                            }
+                        })
+                        .collect();
+                    inputs.par_sort_unstable();
+
+                    inputs
+                        .par_iter()
+                        .filter_map(move |(input, input_row)| {
+                            if table.binary_search(input).is_err() {
+                                Some(VerifyFailure::Lookup {
+                                    name: lookup.name,
+                                    lookup_index,
+                                    location: FailureLocation::find_expressions(
+                                        &self.cs,
+                                        &self.regions,
+                                        *input_row,
+                                        lookup.input_expressions.iter(),
+                                    ),
+                                })
+                            } else {
+                                None
+                            }
+                        })
+                        .collect::<Vec<_>>()
+                });
+
+        // Check that permutations preserve the original values of the cells.
+        let perm_errors = {
+            // Original values of columns involved in the permutation.
+            let original = |column, row| {
+                self.cs
+                    .permutation
+                    .get_columns()
+                    .get(column)
+                    .map(|c: &Column<Any>| match c.column_type() {
+                        Any::Advice(_) => advice[c.index()][row],
+                        Any::Fixed => self.fixed[c.index()][row],
+                        Any::Instance => CellValue::Assigned(self.instance[c.index()][row]),
+                    })
+                    .unwrap()
+            };
+
+            // Iterate over each column of the permutation
+            self.permutation
+                .mapping
+                .iter()
+                .enumerate()
+                .flat_map(move |(column, values)| {
+                    // Iterate over each row of the column to check that the cell's
+                    // value is preserved by the mapping.
+                    values
+                        .par_iter()
+                        .enumerate()
+                        .filter_map(move |(row, cell)| {
+                            let original_cell = original(column, row);
+                            let permuted_cell = original(cell.0, cell.1);
+                            if original_cell == permuted_cell {
+                                None
+                            } else {
+                                let columns = self.cs.permutation.get_columns();
+                                let column = columns.get(column).unwrap();
+                                Some(VerifyFailure::Permutation {
+                                    column: (*column).into(),
+                                    location: FailureLocation::find(
+                                        &self.regions,
+                                        row,
+                                        Some(column).into_iter().cloned().collect(),
+                                    ),
+                                })
+                            }
+                        })
+                        .collect::<Vec<_>>()
+                })
+        };
+
+        let mut errors: Vec<_> = iter::empty()
+            .chain(selector_errors)
+            .chain(gate_errors)
+            .chain(lookup_errors)
+            .chain(perm_errors)
+            .collect();
+        if errors.is_empty() {
+            Ok(())
+        } else {
+            // Remove any duplicate `ConstraintPoisoned` errors (we check all unavailable
+            // rows in case the trigger is row-specific, but the error message only points
+            // at the constraint).
+            errors.dedup_by(|a, b| match (a, b) {
+                (
+                    a @ VerifyFailure::ConstraintPoisoned { .. },
+                    b @ VerifyFailure::ConstraintPoisoned { .. },
+                ) => a == b,
+                _ => false,
+            });
+            Err(errors)
+        }
+    }
+
+    /// Panics if the circuit being checked by this `MockProver` is not satisfied.
+    ///
+    /// Any verification failures will be pretty-printed to stderr before the function
+    /// panics.
+    ///
+    /// Apart from the stderr output, this method is equivalent to:
+    /// ```ignore
+    /// assert_eq!(prover.verify(), Ok(()));
+    /// ```
+    pub fn assert_satisfied(&self) {
+        if let Err(errs) = self.verify() {
+            for err in errs {
+                err.emit(self);
+                eprintln!();
+            }
+            panic!("circuit was not satisfied");
+        }
+    }
+
+    /// Panics if the circuit being checked by this `MockProver` is not satisfied.
+    ///
+    /// Any verification failures will be pretty-printed to stderr before the function
+    /// panics.
+    ///
+    /// Internally, this function uses a parallel aproach in order to verify the `MockProver` contents.
+    ///
+    /// Apart from the stderr output, this method is equivalent to:
+    /// ```ignore
+    /// assert_eq!(prover.verify_par(), Ok(()));
+    /// ```
+    pub fn assert_satisfied_par(&self) {
+        if let Err(errs) = self.verify_par() {
+            for err in errs {
+                err.emit(self);
+                eprintln!();
+            }
+            panic!("circuit was not satisfied");
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use halo2curves::pasta::Fp;
+
+    use super::{FailureLocation, MockProver, VerifyFailure};
+    use crate::{
+        circuit::{Layouter, SimpleFloorPlanner, Value},
+        plonk::{
+            Advice, Any, Assigned, Circuit, Column, ConstraintSystem, Error, Expression, Selector,
+            TableColumn,
+        },
+        poly::Rotation,
+    };
+
+    #[test]
+    fn unassigned_cell() {
+        const K: u32 = 4;
+
+        #[derive(Clone)]
+        struct FaultyCircuitConfig {
+            a: Column<Advice>,
+            q: Selector,
+        }
+
+        struct FaultyCircuit {}
+
+        impl Circuit<Fp> for FaultyCircuit {
+            type Config = FaultyCircuitConfig;
+            type FloorPlanner = SimpleFloorPlanner;
+
+            fn configure(meta: &mut ConstraintSystem<Fp>) -> Self::Config {
+                let a = meta.advice_column();
+                let b = meta.advice_column();
+                let q = meta.selector();
+
+                meta.create_gate("Equality check", |cells| {
+                    let a = cells.query_advice(a, Rotation::prev());
+                    let b = cells.query_advice(b, Rotation::cur());
+                    let q = cells.query_selector(q);
+
+                    // If q is enabled, a and b must be assigned to.
+                    vec![q * (a - b)]
+                });
+
+                FaultyCircuitConfig { a, q }
+            }
+
+            fn without_witnesses(&self) -> Self {
+                Self {}
+            }
+
+            fn synthesize(
+                &self,
+                config: Self::Config,
+                mut layouter: impl Layouter<Fp>,
+            ) -> Result<(), Error> {
+                layouter.assign_region(
+                    || "Faulty synthesis",
+                    |mut region| {
+                        // Enable the equality gate.
+                        config.q.enable(&mut region, 1)?;
+
+                        // Assign a = 0.
+                        region.assign_advice(
+                            /*|| "a",*/ config.a,
+                            0,
+                            Value::known(Assigned::Trivial(Fp::zero())),
+                        )?;
+
+                        // BUG: Forget to assign b = 0! This could go unnoticed during
+                        // development, because cell values default to zero, which in this
+                        // case is fine, but for other assignments would be broken.
+                        Ok(())
+                    },
+                )
+            }
+        }
+
+        let prover = MockProver::run(K, &FaultyCircuit {}, vec![]).unwrap();
+        assert_eq!(
+            prover.verify(),
+            Err(vec![VerifyFailure::CellNotAssigned {
+                gate: (0, "Equality check").into(),
+                region: (0, "Faulty synthesis".to_owned()).into(),
+                gate_offset: 1,
+                column: Column::new(1, Any::advice()),
+                offset: 1,
+            }])
+        );
+    }
+
+    #[test]
+    fn bad_lookup() {
+        const K: u32 = 4;
+
+        #[derive(Clone)]
+        struct FaultyCircuitConfig {
+            a: Column<Advice>,
+            q: Selector,
+            table: TableColumn,
+        }
+
+        struct FaultyCircuit {}
+
+        impl Circuit<Fp> for FaultyCircuit {
+            type Config = FaultyCircuitConfig;
+            type FloorPlanner = SimpleFloorPlanner;
+
+            fn configure(meta: &mut ConstraintSystem<Fp>) -> Self::Config {
+                let a = meta.advice_column();
+                let q = meta.complex_selector();
+                let table = meta.lookup_table_column();
+
+                meta.lookup("lookup", |cells| {
+                    let a = cells.query_advice(a, Rotation::cur());
+                    let q = cells.query_selector(q);
+
+                    // If q is enabled, a must be in the table.
+                    // When q is not enabled, lookup the default value instead.
+                    let not_q = Expression::Constant(Fp::one()) - q.clone();
+                    let default = Expression::Constant(Fp::from(2));
+                    vec![(q * a + not_q * default, table)]
+                });
+
+                FaultyCircuitConfig { a, q, table }
+            }
+
+            fn without_witnesses(&self) -> Self {
+                Self {}
+            }
+
+            fn synthesize(
+                &self,
+                config: Self::Config,
+                mut layouter: impl Layouter<Fp>,
+            ) -> Result<(), Error> {
+                layouter.assign_table(
+                    || "Doubling table",
+                    |mut table| {
+                        (1..(1 << (K - 1)))
+                            .map(|i| {
+                                table.assign_cell(
+                                    || format!("table[{}] = {}", i, 2 * i),
+                                    config.table,
+                                    i - 1,
+                                    || Value::known(Fp::from(2 * i as u64)),
+                                )
+                            })
+                            .fold(Ok(()), |acc, res| acc.and(res))
+                    },
+                )?;
+
+                layouter.assign_region(
+                    || "Good synthesis",
+                    |mut region| {
+                        // Enable the lookup on rows 0 and 1.
+                        config.q.enable(&mut region, 0)?;
+                        config.q.enable(&mut region, 1)?;
+
+                        // Assign a = 2 and a = 6.
+                        region.assign_advice(
+                            // || "a = 2",
+                            config.a,
+                            0,
+                            Value::known(Assigned::Trivial(Fp::from(2))),
+                        )?;
+                        region.assign_advice(
+                            // || "a = 6",
+                            config.a,
+                            1,
+                            Value::known(Assigned::Trivial(Fp::from(6))),
+                        )?;
+
+                        Ok(())
+                    },
+                )?;
+
+                layouter.assign_region(
+                    || "Faulty synthesis",
+                    |mut region| {
+                        // Enable the lookup on rows 0 and 1.
+                        config.q.enable(&mut region, 0)?;
+                        config.q.enable(&mut region, 1)?;
+
+                        // Assign a = 4.
+                        region.assign_advice(
+                            // || "a = 4",
+                            config.a,
+                            0,
+                            Value::known(Assigned::Trivial(Fp::from(4))),
+                        )?;
+
+                        // BUG: Assign a = 5, which doesn't exist in the table!
+                        region.assign_advice(
+                            // || "a = 5",
+                            config.a,
+                            1,
+                            Value::known(Assigned::Trivial(Fp::from(5))),
+                        )?;
+
+                        Ok(())
+                    },
+                )
+            }
+        }
+
+        let prover = MockProver::run(K, &FaultyCircuit {}, vec![]).unwrap();
+        assert_eq!(
+            prover.verify(),
+            Err(vec![VerifyFailure::Lookup {
+                name: "lookup",
+                lookup_index: 0,
+                location: FailureLocation::InRegion {
+                    region: (2, "Faulty synthesis").into(),
+                    offset: 1,
+                }
+            }])
+        );
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/dev/failure.rs.html b/docs/src/halo2_proofs/dev/failure.rs.html new file mode 100644 index 0000000000..8d38c70fc6 --- /dev/null +++ b/docs/src/halo2_proofs/dev/failure.rs.html @@ -0,0 +1,1142 @@ +failure.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+
use std::collections::{BTreeMap, BTreeSet, HashSet};
+use std::fmt;
+use std::iter;
+
+use group::ff::Field;
+use halo2curves::FieldExt;
+
+use super::{
+    metadata,
+    util::{self, AnyQuery},
+    MockProver, Region,
+};
+use crate::dev::{AdviceCellValue, CellValue};
+use crate::plonk::Assigned;
+use crate::{
+    dev::Value,
+    plonk::{Any, Column, ConstraintSystem, Expression, Gate},
+    poly::Rotation,
+};
+
+mod emitter;
+
+/// The location within the circuit at which a particular [`VerifyFailure`] occurred.
+#[derive(Debug, PartialEq)]
+pub enum FailureLocation {
+    /// A location inside a region.
+    InRegion {
+        /// The region in which the failure occurred.
+        region: metadata::Region,
+        /// The offset (relative to the start of the region) at which the failure
+        /// occurred.
+        offset: usize,
+    },
+    /// A location outside of a region.
+    OutsideRegion {
+        /// The circuit row on which the failure occurred.
+        row: usize,
+    },
+}
+
+impl fmt::Display for FailureLocation {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::InRegion { region, offset } => write!(f, "in {} at offset {}", region, offset),
+            Self::OutsideRegion { row } => {
+                write!(f, "outside any region, on row {}", row)
+            }
+        }
+    }
+}
+
+impl FailureLocation {
+    pub(super) fn find_expressions<'a, F: Field>(
+        cs: &ConstraintSystem<F>,
+        regions: &[Region],
+        failure_row: usize,
+        failure_expressions: impl Iterator<Item = &'a Expression<F>>,
+    ) -> Self {
+        let failure_columns: HashSet<Column<Any>> = failure_expressions
+            .flat_map(|expression| {
+                expression.evaluate(
+                    &|_| vec![],
+                    &|_| panic!("virtual selectors are removed during optimization"),
+                    &|query| vec![cs.fixed_queries[query.index].0.into()],
+                    &|query| vec![cs.advice_queries[query.index].0.into()],
+                    &|query| vec![cs.instance_queries[query.index].0.into()],
+                    &|_| vec![],
+                    &|a| a,
+                    &|mut a, mut b| {
+                        a.append(&mut b);
+                        a
+                    },
+                    &|mut a, mut b| {
+                        a.append(&mut b);
+                        a
+                    },
+                    &|a, _| a,
+                )
+            })
+            .collect();
+
+        Self::find(regions, failure_row, failure_columns)
+    }
+
+    /// Figures out whether the given row and columns overlap an assigned region.
+    pub(super) fn find(
+        regions: &[Region],
+        failure_row: usize,
+        failure_columns: HashSet<Column<Any>>,
+    ) -> Self {
+        regions
+            .iter()
+            .enumerate()
+            .find(|(_, r)| {
+                if r.rows.is_none() {
+                    return false;
+                }
+                let (start, end) = r.rows.unwrap();
+                // We match the region if any input columns overlap, rather than all of
+                // them, because matching complex selector columns is hard. As long as
+                // regions are rectangles, and failures occur due to assignments entirely
+                // within single regions, "any" will be equivalent to "all". If these
+                // assumptions change, we'll start getting bug reports from users :)
+                (start..=end).contains(&failure_row) && !failure_columns.is_disjoint(&r.columns)
+            })
+            .map(|(r_i, r)| FailureLocation::InRegion {
+                region: (r_i, r.name.clone()).into(),
+                offset: failure_row as usize - r.rows.unwrap().0 as usize,
+            })
+            .unwrap_or_else(|| FailureLocation::OutsideRegion {
+                row: failure_row as usize,
+            })
+    }
+}
+
+/// The reasons why a particular circuit is not satisfied.
+#[derive(Debug, PartialEq)]
+pub enum VerifyFailure {
+    /// A cell used in an active gate was not assigned to.
+    CellNotAssigned {
+        /// The index of the active gate.
+        gate: metadata::Gate,
+        /// The region in which this cell should be assigned.
+        region: metadata::Region,
+        /// The offset (relative to the start of the region) at which the active gate
+        /// queries this cell.
+        gate_offset: usize,
+        /// The column in which this cell should be assigned.
+        column: Column<Any>,
+        /// The offset (relative to the start of the region) at which this cell should be
+        /// assigned. This may be negative (for example, if a selector enables a gate at
+        /// offset 0, but the gate uses `Rotation::prev()`).
+        offset: isize,
+    },
+    /// A constraint was not satisfied for a particular row.
+    ConstraintNotSatisfied {
+        /// The polynomial constraint that is not satisfied.
+        constraint: metadata::Constraint,
+        /// The location at which this constraint is not satisfied.
+        ///
+        /// `FailureLocation::OutsideRegion` is usually caused by a constraint that does
+        /// not contain a selector, and as a result is active on every row.
+        location: FailureLocation,
+        /// The values of the virtual cells used by this constraint.
+        cell_values: Vec<(metadata::VirtualCell, String)>,
+    },
+    /// A constraint was active on an unusable row, and is likely missing a selector.
+    ConstraintPoisoned {
+        /// The polynomial constraint that is not satisfied.
+        constraint: metadata::Constraint,
+    },
+    /// A lookup input did not exist in its corresponding table.
+    Lookup {
+        /// The name of the lookup that is not satisfied.
+        name: &'static str,
+        /// The index of the lookup that is not satisfied. These indices are assigned in
+        /// the order in which `ConstraintSystem::lookup` is called during
+        /// `Circuit::configure`.
+        lookup_index: usize,
+        /// The location at which the lookup is not satisfied.
+        ///
+        /// `FailureLocation::InRegion` is most common, and may be due to the intentional
+        /// use of a lookup (if its inputs are conditional on a complex selector), or an
+        /// unintentional lookup constraint that overlaps the region (indicating that the
+        /// lookup's inputs should be made conditional).
+        ///
+        /// `FailureLocation::OutsideRegion` is uncommon, and could mean that:
+        /// - The input expressions do not correctly constrain a default value that exists
+        ///   in the table when the lookup is not being used.
+        /// - The input expressions use a column queried at a non-zero `Rotation`, and the
+        ///   lookup is active on a row adjacent to an unrelated region.
+        location: FailureLocation,
+    },
+    /// A permutation did not preserve the original value of a cell.
+    Permutation {
+        /// The column in which this permutation is not satisfied.
+        column: metadata::Column,
+        /// The location at which the permutation is not satisfied.
+        location: FailureLocation,
+    },
+}
+
+impl fmt::Display for VerifyFailure {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::CellNotAssigned {
+                gate,
+                region,
+                gate_offset,
+                column,
+                offset,
+            } => {
+                write!(
+                    f,
+                    "{} uses {} at offset {}, which requires cell in column {:?} at offset {} to be assigned.",
+                    region, gate, gate_offset, column, offset
+                )
+            }
+            Self::ConstraintNotSatisfied {
+                constraint,
+                location,
+                cell_values,
+            } => {
+                writeln!(f, "{} is not satisfied {}", constraint, location)?;
+                for (name, value) in cell_values {
+                    writeln!(f, "- {} = {}", name, value)?;
+                }
+                Ok(())
+            }
+            Self::ConstraintPoisoned { constraint } => {
+                write!(
+                    f,
+                    "{} is active on an unusable row - missing selector?",
+                    constraint
+                )
+            }
+            Self::Lookup {
+                name,
+                lookup_index,
+                location,
+            } => {
+                write!(
+                    f,
+                    "Lookup {}(index: {}) is not satisfied {}",
+                    name, lookup_index, location
+                )
+            }
+            Self::Permutation { column, location } => {
+                write!(
+                    f,
+                    "Equality constraint not satisfied by cell ({:?}, {})",
+                    column, location
+                )
+            }
+        }
+    }
+}
+
+/// Renders `VerifyFailure::CellNotAssigned`.
+///
+/// ```text
+/// error: cell not assigned
+///   Cell layout in region 'Faulty synthesis':
+///     | Offset | A0 | A1 |
+///     +--------+----+----+
+///     |    0   | x0 |    |
+///     |    1   |    |  X | <--{ X marks the spot! 🦜
+///
+///   Gate 'Equality check' (applied at offset 1) queries these cells.
+/// ```
+fn render_cell_not_assigned<F: Field>(
+    gates: &[Gate<F>],
+    gate: &metadata::Gate,
+    region: &metadata::Region,
+    gate_offset: usize,
+    column: Column<Any>,
+    offset: isize,
+) {
+    // Collect the necessary rendering information:
+    // - The columns involved in this gate.
+    // - How many cells are in each column.
+    // - The grid of cell values, indexed by rotation.
+    let mut columns = BTreeMap::<metadata::Column, usize>::default();
+    let mut layout = BTreeMap::<i32, BTreeMap<metadata::Column, _>>::default();
+    for (i, cell) in gates[gate.index].queried_cells().iter().enumerate() {
+        let cell_column = cell.column.into();
+        *columns.entry(cell_column).or_default() += 1;
+        layout
+            .entry(cell.rotation.0)
+            .or_default()
+            .entry(cell_column)
+            .or_insert_with(|| {
+                if cell.column == column && gate_offset as i32 + cell.rotation.0 == offset as i32 {
+                    "X".to_string()
+                } else {
+                    format!("x{}", i)
+                }
+            });
+    }
+
+    eprintln!("error: cell not assigned");
+    emitter::render_cell_layout(
+        "  ",
+        &FailureLocation::InRegion {
+            region: region.clone(),
+            offset: gate_offset,
+        },
+        &columns,
+        &layout,
+        |row_offset, rotation| {
+            if (row_offset.unwrap() + rotation) as isize == offset {
+                eprint!(" <--{{ X marks the spot! 🦜");
+            }
+        },
+    );
+    eprintln!();
+    eprintln!(
+        "  Gate '{}' (applied at offset {}) queries these cells.",
+        gate.name, gate_offset
+    );
+}
+
+/// Renders `VerifyFailure::ConstraintNotSatisfied`.
+///
+/// ```text
+/// error: constraint not satisfied
+///   Cell layout in region 'somewhere':
+///     | Offset | A0 |
+///     +--------+----+
+///     |    0   | x0 | <--{ Gate 'foo' applied here
+///     |    1   | x1 |
+///
+///   Constraint 'bar':
+///     x1 + x1 * 0x100 + x1 * 0x10000 + x1 * 0x100_0000 - x0 = 0
+///
+///   Assigned cell values:
+///     x0 = 0x5
+///     x1 = 0x5
+/// ```
+fn render_constraint_not_satisfied<F: Field>(
+    gates: &[Gate<F>],
+    constraint: &metadata::Constraint,
+    location: &FailureLocation,
+    cell_values: &[(metadata::VirtualCell, String)],
+) {
+    // Collect the necessary rendering information:
+    // - The columns involved in this constraint.
+    // - How many cells are in each column.
+    // - The grid of cell values, indexed by rotation.
+    let mut columns = BTreeMap::<metadata::Column, usize>::default();
+    let mut layout = BTreeMap::<i32, BTreeMap<metadata::Column, _>>::default();
+    for (i, (cell, _)) in cell_values.iter().enumerate() {
+        *columns.entry(cell.column).or_default() += 1;
+        layout
+            .entry(cell.rotation)
+            .or_default()
+            .entry(cell.column)
+            .or_insert(format!("x{}", i));
+    }
+
+    eprintln!("error: constraint not satisfied");
+    emitter::render_cell_layout("  ", location, &columns, &layout, |_, rotation| {
+        if rotation == 0 {
+            eprint!(" <--{{ Gate '{}' applied here", constraint.gate.name);
+        }
+    });
+
+    // Print the unsatisfied constraint, in terms of the local variables.
+    eprintln!();
+    eprintln!("  Constraint '{}':", constraint.name);
+    eprintln!(
+        "    {} = 0",
+        emitter::expression_to_string(
+            &gates[constraint.gate.index].polynomials()[constraint.index],
+            &layout
+        )
+    );
+
+    // Print the map from local variables to assigned values.
+    eprintln!();
+    eprintln!("  Assigned cell values:");
+    for (i, (_, value)) in cell_values.iter().enumerate() {
+        eprintln!("    x{} = {}", i, value);
+    }
+}
+
+/// Renders `VerifyFailure::Lookup`.
+///
+/// ```text
+/// error: lookup input does not exist in table
+///   (L0) ∉ (F0)
+///
+///   Lookup inputs:
+///     L0 = x1 * x0 + (1 - x1) * 0x2
+///     ^
+///     | Cell layout in region 'Faulty synthesis':
+///     |   | Offset | A0 | F1 |
+///     |   +--------+----+----+
+///     |   |    1   | x0 | x1 | <--{ Lookup inputs queried here
+///     |
+///     | Assigned cell values:
+///     |   x0 = 0x5
+///     |   x1 = 1
+/// ```
+fn render_lookup<F: FieldExt>(
+    prover: &MockProver<F>,
+    name: &str,
+    lookup_index: usize,
+    location: &FailureLocation,
+) {
+    let n = prover.n as i32;
+    let cs = &prover.cs;
+    let lookup = &cs.lookups[lookup_index];
+
+    // Get the absolute row on which the lookup's inputs are being queried, so we can
+    // fetch the input values.
+    let row = match location {
+        FailureLocation::InRegion { region, offset } => {
+            prover.regions[region.index].rows.unwrap().0 + offset
+        }
+        FailureLocation::OutsideRegion { row } => *row,
+    } as i32;
+
+    // Recover the fixed columns from the table expressions. We don't allow composite
+    // expressions for the table side of lookups.
+    let lookup_columns = lookup.table_expressions.iter().map(|expr| {
+        expr.evaluate(
+            &|_| panic!("no constants in table expressions"),
+            &|_| panic!("no selectors in table expressions"),
+            &|query| format!("F{}", query.column_index),
+            &|query| format! {"A{}", query.column_index},
+            &|query| format! {"I{}", query.column_index},
+            &|challenge| format! {"C{}", challenge.index()},
+            &|query| format! {"-{}", query},
+            &|a, b| format! {"{} + {}", a,b},
+            &|a, b| format! {"{} * {}", a,b},
+            &|a, b| format! {"{} * {:?}", a, b},
+        )
+    });
+
+    fn cell_value<'a, F: FieldExt, Q: Into<AnyQuery> + Copy>(
+        load: impl Fn(Q) -> Value<F> + 'a,
+    ) -> impl Fn(Q) -> BTreeMap<metadata::VirtualCell, String> + 'a {
+        move |query| {
+            let AnyQuery {
+                column_type,
+                column_index,
+                rotation,
+                ..
+            } = query.into();
+            Some((
+                ((column_type, column_index).into(), rotation.0).into(),
+                match load(query) {
+                    Value::Real(v) => util::format_value(v),
+                    Value::Poison => unreachable!(),
+                },
+            ))
+            .into_iter()
+            .collect()
+        }
+    }
+
+    eprintln!("error: lookup input does not exist in table");
+    eprint!("  (");
+    for i in 0..lookup.input_expressions.len() {
+        eprint!("{}L{}", if i == 0 { "" } else { ", " }, i);
+    }
+    eprint!(") ∉ (");
+    for (i, column) in lookup_columns.enumerate() {
+        eprint!("{}{}", if i == 0 { "" } else { ", " }, column);
+    }
+    eprintln!(")");
+
+    eprintln!();
+    eprintln!("  Lookup '{}' inputs:", name);
+    let advice = prover
+        .advice
+        .iter()
+        .map(|advice| {
+            advice
+                .iter()
+                .map(|rc| match rc {
+                    AdviceCellValue::Assigned(a) => CellValue::Assigned(match a.as_ref() {
+                        Assigned::Trivial(a) => *a,
+                        _ => unreachable!(),
+                    }),
+                    AdviceCellValue::Poison(i) => CellValue::Poison(*i),
+                })
+                .collect::<Vec<_>>()
+        })
+        .collect::<Vec<_>>();
+    for (i, input) in lookup.input_expressions.iter().enumerate() {
+        // Fetch the cell values (since we don't store them in VerifyFailure::Lookup).
+        let cell_values = input.evaluate(
+            &|_| BTreeMap::default(),
+            &|_| panic!("virtual selectors are removed during optimization"),
+            &cell_value(&util::load(n, row, &cs.fixed_queries, &prover.fixed)),
+            &cell_value(&util::load(n, row, &cs.advice_queries, &advice)),
+            &cell_value(&util::load_instance(
+                n,
+                row,
+                &cs.instance_queries,
+                &prover.instance,
+            )),
+            &|_| BTreeMap::default(),
+            &|a| a,
+            &|mut a, mut b| {
+                a.append(&mut b);
+                a
+            },
+            &|mut a, mut b| {
+                a.append(&mut b);
+                a
+            },
+            &|a, _| a,
+        );
+
+        // Collect the necessary rendering information:
+        // - The columns involved in this constraint.
+        // - How many cells are in each column.
+        // - The grid of cell values, indexed by rotation.
+        let mut columns = BTreeMap::<metadata::Column, usize>::default();
+        let mut layout = BTreeMap::<i32, BTreeMap<metadata::Column, _>>::default();
+        for (i, (cell, _)) in cell_values.iter().enumerate() {
+            *columns.entry(cell.column).or_default() += 1;
+            layout
+                .entry(cell.rotation)
+                .or_default()
+                .entry(cell.column)
+                .or_insert(format!("x{}", i));
+        }
+
+        if i != 0 {
+            eprintln!();
+        }
+        eprintln!(
+            "    L{} = {}",
+            i,
+            emitter::expression_to_string(input, &layout)
+        );
+        eprintln!("    ^");
+        emitter::render_cell_layout("    | ", location, &columns, &layout, |_, rotation| {
+            if rotation == 0 {
+                eprint!(" <--{{ Lookup '{}' inputs queried here", name);
+            }
+        });
+
+        // Print the map from local variables to assigned values.
+        eprintln!("    |");
+        eprintln!("    | Assigned cell values:");
+        for (i, (_, value)) in cell_values.iter().enumerate() {
+            eprintln!("    |   x{} = {}", i, value);
+        }
+    }
+}
+
+impl VerifyFailure {
+    /// Emits this failure in pretty-printed format to stderr.
+    pub(super) fn emit<F: FieldExt>(&self, prover: &MockProver<F>) {
+        match self {
+            Self::CellNotAssigned {
+                gate,
+                region,
+                gate_offset,
+                column,
+                offset,
+            } => render_cell_not_assigned(
+                &prover.cs.gates,
+                gate,
+                region,
+                *gate_offset,
+                *column,
+                *offset,
+            ),
+            Self::ConstraintNotSatisfied {
+                constraint,
+                location,
+                cell_values,
+            } => {
+                render_constraint_not_satisfied(&prover.cs.gates, constraint, location, cell_values)
+            }
+            Self::Lookup {
+                name,
+                lookup_index,
+                location,
+            } => render_lookup(prover, name, *lookup_index, location),
+            _ => eprintln!("{}", self),
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/dev/failure/emitter.rs.html b/docs/src/halo2_proofs/dev/failure/emitter.rs.html new file mode 100644 index 0000000000..540fe478e5 --- /dev/null +++ b/docs/src/halo2_proofs/dev/failure/emitter.rs.html @@ -0,0 +1,346 @@ +emitter.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+
use std::collections::BTreeMap;
+use std::iter;
+
+use group::ff::Field;
+
+use super::FailureLocation;
+use crate::{
+    dev::{metadata, util},
+    plonk::{Advice, Any, Expression},
+};
+
+fn padded(p: char, width: usize, text: &str) -> String {
+    let pad = width - text.len();
+    format!(
+        "{}{}{}",
+        iter::repeat(p).take(pad - pad / 2).collect::<String>(),
+        text,
+        iter::repeat(p).take(pad / 2).collect::<String>(),
+    )
+}
+
+/// Renders a cell layout around a given failure location.
+///
+/// `highlight_row` is called at the end of each row, with the offset of the active row
+/// (if `location` is in a region), and the rotation of the current row relative to the
+/// active row.
+pub(super) fn render_cell_layout(
+    prefix: &str,
+    location: &FailureLocation,
+    columns: &BTreeMap<metadata::Column, usize>,
+    layout: &BTreeMap<i32, BTreeMap<metadata::Column, String>>,
+    highlight_row: impl Fn(Option<i32>, i32),
+) {
+    let col_width = |cells: usize| cells.to_string().len() + 3;
+
+    // If we are in a region, show rows at offsets relative to it. Otherwise, just show
+    // the rotations directly.
+    let offset = match location {
+        FailureLocation::InRegion { region, offset } => {
+            eprintln!("{}Cell layout in region '{}':", prefix, region.name);
+            eprint!("{}  | Offset |", prefix);
+            Some(*offset as i32)
+        }
+        FailureLocation::OutsideRegion { row } => {
+            eprintln!("{}Cell layout at row {}:", prefix, row);
+            eprint!("{}  |Rotation|", prefix);
+            None
+        }
+    };
+
+    // Print the assigned cells, and their region offset or rotation.
+    for (column, cells) in columns {
+        let width = col_width(*cells);
+        eprint!(
+            "{}|",
+            padded(
+                ' ',
+                width,
+                &format!(
+                    "{}{}",
+                    match column.column_type {
+                        Any::Advice(_) => "A",
+                        Any::Fixed => "F",
+                        Any::Instance => "I",
+                    },
+                    column.index,
+                )
+            )
+        );
+    }
+    eprintln!();
+    eprint!("{}  +--------+", prefix);
+    for cells in columns.values() {
+        eprint!("{}+", padded('-', col_width(*cells), ""));
+    }
+    eprintln!();
+    for (rotation, row) in layout {
+        eprint!(
+            "{}  |{}|",
+            prefix,
+            padded(' ', 8, &(offset.unwrap_or(0) + rotation).to_string())
+        );
+        for (col, cells) in columns {
+            let width = col_width(*cells);
+            eprint!(
+                "{}|",
+                padded(
+                    ' ',
+                    width,
+                    row.get(col).map(|s| s.as_str()).unwrap_or_default()
+                )
+            );
+        }
+        highlight_row(offset, *rotation);
+        eprintln!();
+    }
+}
+
+pub(super) fn expression_to_string<F: Field>(
+    expr: &Expression<F>,
+    layout: &BTreeMap<i32, BTreeMap<metadata::Column, String>>,
+) -> String {
+    expr.evaluate(
+        &util::format_value,
+        &|_| panic!("virtual selectors are removed during optimization"),
+        &|query| {
+            if let Some(label) = layout
+                .get(&query.rotation.0)
+                .and_then(|row| row.get(&(Any::Fixed, query.column_index).into()))
+            {
+                label.clone()
+            } else if query.rotation.0 == 0 {
+                // This is most likely a merged selector
+                format!("S{}", query.index)
+            } else {
+                // No idea how we'd get here...
+                format!("F{}@{}", query.column_index, query.rotation.0)
+            }
+        },
+        &|query| {
+            layout
+                .get(&query.rotation.0)
+                .and_then(|map| {
+                    map.get(
+                        &(
+                            Any::Advice(Advice { phase: query.phase }),
+                            query.column_index,
+                        )
+                            .into(),
+                    )
+                })
+                .cloned()
+                .unwrap_or_default()
+        },
+        &|query| {
+            layout
+                .get(&query.rotation.0)
+                .unwrap()
+                .get(&(Any::Instance, query.column_index).into())
+                .unwrap()
+                .clone()
+        },
+        &|challenge| format!("C{}({})", challenge.index(), challenge.phase()),
+        &|a| {
+            if a.contains(' ') {
+                format!("-({})", a)
+            } else {
+                format!("-{}", a)
+            }
+        },
+        &|a, b| {
+            if let Some(b) = b.strip_prefix('-') {
+                format!("{} - {}", a, b)
+            } else {
+                format!("{} + {}", a, b)
+            }
+        },
+        &|a, b| match (a.contains(' '), b.contains(' ')) {
+            (false, false) => format!("{} * {}", a, b),
+            (false, true) => format!("{} * ({})", a, b),
+            (true, false) => format!("({}) * {}", a, b),
+            (true, true) => format!("({}) * ({})", a, b),
+        },
+        &|a, s| {
+            if a.contains(' ') {
+                format!("({}) * {}", a, util::format_value(s))
+            } else {
+                format!("{} * {}", a, util::format_value(s))
+            }
+        },
+    )
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/dev/gates.rs.html b/docs/src/halo2_proofs/dev/gates.rs.html new file mode 100644 index 0000000000..9683c41bb8 --- /dev/null +++ b/docs/src/halo2_proofs/dev/gates.rs.html @@ -0,0 +1,616 @@ +gates.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+
use std::{
+    collections::BTreeSet,
+    fmt::{self, Write},
+};
+
+use ff::PrimeField;
+
+use crate::{
+    dev::util,
+    plonk::{
+        sealed::{self, SealedPhase},
+        Circuit, ConstraintSystem, FirstPhase,
+    },
+};
+
+#[derive(Debug)]
+struct Constraint {
+    name: &'static str,
+    expression: String,
+    queries: BTreeSet<String>,
+}
+
+#[derive(Debug)]
+struct Gate {
+    name: &'static str,
+    constraints: Vec<Constraint>,
+}
+
+/// A struct for collecting and displaying the gates within a circuit.
+///
+/// # Examples
+///
+/// ```
+/// use ff::Field;
+/// use halo2_proofs::{
+///     circuit::{Layouter, SimpleFloorPlanner},
+///     dev::CircuitGates,
+///     plonk::{Circuit, ConstraintSystem, Error},
+///     poly::Rotation,
+/// };
+/// use halo2curves::pasta::pallas;
+///
+/// #[derive(Copy, Clone)]
+/// struct MyConfig {}
+///
+/// #[derive(Clone, Default)]
+/// struct MyCircuit {}
+///
+/// impl<F: Field> Circuit<F> for MyCircuit {
+///     type Config = MyConfig;
+///     type FloorPlanner = SimpleFloorPlanner;
+///
+///     fn without_witnesses(&self) -> Self {
+///         Self::default()
+///     }
+///
+///     fn configure(meta: &mut ConstraintSystem<F>) -> MyConfig {
+///         let a = meta.advice_column();
+///         let b = meta.advice_column();
+///         let c = meta.advice_column();
+///         let s = meta.selector();
+///
+///         meta.create_gate("R1CS constraint", |meta| {
+///             let a = meta.query_advice(a, Rotation::cur());
+///             let b = meta.query_advice(b, Rotation::cur());
+///             let c = meta.query_advice(c, Rotation::cur());
+///             let s = meta.query_selector(s);
+///
+///             Some(("R1CS", s * (a * b - c)))
+///         });
+///
+///         // We aren't using this circuit for anything in this example.
+///         MyConfig {}
+///     }
+///
+///     fn synthesize(&self, _: MyConfig, _: impl Layouter<F>) -> Result<(), Error> {
+///         // Gates are known at configure time; it doesn't matter how we use them.
+///         Ok(())
+///     }
+/// }
+///
+/// let gates = CircuitGates::collect::<pallas::Base, MyCircuit>();
+/// assert_eq!(
+///     format!("{}", gates),
+///     r#####"R1CS constraint:
+/// - R1CS:
+///   S0 * (A0@0 * A1@0 - A2@0)
+/// Total gates: 1
+/// Total custom constraint polynomials: 1
+/// Total negations: 1
+/// Total additions: 1
+/// Total multiplications: 2
+/// "#####,
+/// );
+/// ```
+#[derive(Debug)]
+pub struct CircuitGates {
+    gates: Vec<Gate>,
+    total_negations: usize,
+    total_additions: usize,
+    total_multiplications: usize,
+}
+
+impl CircuitGates {
+    /// Collects the gates from within the circuit.
+    pub fn collect<F: PrimeField, C: Circuit<F>>() -> Self {
+        // Collect the graph details.
+        let mut cs = ConstraintSystem::default();
+        let _ = C::configure(&mut cs);
+
+        let gates = cs
+            .gates
+            .iter()
+            .map(|gate| Gate {
+                name: gate.name(),
+                constraints: gate
+                    .polynomials()
+                    .iter()
+                    .enumerate()
+                    .map(|(i, constraint)| Constraint {
+                        name: gate.constraint_name(i),
+                        expression: constraint.evaluate(
+                            &util::format_value,
+                            &|selector| format!("S{}", selector.0),
+                            &|query| format!("F{}@{}", query.column_index, query.rotation.0),
+                            &|query| {
+                                if query.phase == FirstPhase.to_sealed() {
+                                    format!("A{}@{}", query.column_index, query.rotation.0)
+                                } else {
+                                    format!(
+                                        "A{}({})@{}",
+                                        query.column_index,
+                                        query.phase(),
+                                        query.rotation.0
+                                    )
+                                }
+                            },
+                            &|query| format!("I{}@{}", query.column_index, query.rotation.0),
+                            &|challenge| format!("C{}({})", challenge.index(), challenge.phase()),
+                            &|a| {
+                                if a.contains(' ') {
+                                    format!("-({})", a)
+                                } else {
+                                    format!("-{}", a)
+                                }
+                            },
+                            &|a, b| {
+                                if let Some(b) = b.strip_prefix('-') {
+                                    format!("{} - {}", a, b)
+                                } else {
+                                    format!("{} + {}", a, b)
+                                }
+                            },
+                            &|a, b| match (a.contains(' '), b.contains(' ')) {
+                                (false, false) => format!("{} * {}", a, b),
+                                (false, true) => format!("{} * ({})", a, b),
+                                (true, false) => format!("({}) * {}", a, b),
+                                (true, true) => format!("({}) * ({})", a, b),
+                            },
+                            &|a, s| {
+                                if a.contains(' ') {
+                                    format!("({}) * {}", a, util::format_value(s))
+                                } else {
+                                    format!("{} * {}", a, util::format_value(s))
+                                }
+                            },
+                        ),
+                        queries: constraint.evaluate(
+                            &|_| BTreeSet::default(),
+                            &|selector| vec![format!("S{}", selector.0)].into_iter().collect(),
+                            &|query| {
+                                vec![format!("F{}@{}", query.column_index, query.rotation.0)]
+                                    .into_iter()
+                                    .collect()
+                            },
+                            &|query| {
+                                let query = if query.phase == FirstPhase.to_sealed() {
+                                    format!("A{}@{}", query.column_index, query.rotation.0)
+                                } else {
+                                    format!(
+                                        "A{}({})@{}",
+                                        query.column_index,
+                                        query.phase(),
+                                        query.rotation.0
+                                    )
+                                };
+                                vec![query].into_iter().collect()
+                            },
+                            &|query| {
+                                vec![format!("I{}@{}", query.column_index, query.rotation.0)]
+                                    .into_iter()
+                                    .collect()
+                            },
+                            &|challenge| {
+                                vec![format!("C{}({})", challenge.index(), challenge.phase())]
+                                    .into_iter()
+                                    .collect()
+                            },
+                            &|a| a,
+                            &|mut a, mut b| {
+                                a.append(&mut b);
+                                a
+                            },
+                            &|mut a, mut b| {
+                                a.append(&mut b);
+                                a
+                            },
+                            &|a, _| a,
+                        ),
+                    })
+                    .collect(),
+            })
+            .collect();
+
+        let (total_negations, total_additions, total_multiplications) = cs
+            .gates
+            .iter()
+            .flat_map(|gate| {
+                gate.polynomials().iter().map(|poly| {
+                    poly.evaluate(
+                        &|_| (0, 0, 0),
+                        &|_| (0, 0, 0),
+                        &|_| (0, 0, 0),
+                        &|_| (0, 0, 0),
+                        &|_| (0, 0, 0),
+                        &|_| (0, 0, 0),
+                        &|(a_n, a_a, a_m)| (a_n + 1, a_a, a_m),
+                        &|(a_n, a_a, a_m), (b_n, b_a, b_m)| (a_n + b_n, a_a + b_a + 1, a_m + b_m),
+                        &|(a_n, a_a, a_m), (b_n, b_a, b_m)| (a_n + b_n, a_a + b_a, a_m + b_m + 1),
+                        &|(a_n, a_a, a_m), _| (a_n, a_a, a_m + 1),
+                    )
+                })
+            })
+            .fold((0, 0, 0), |(acc_n, acc_a, acc_m), (n, a, m)| {
+                (acc_n + n, acc_a + a, acc_m + m)
+            });
+
+        CircuitGates {
+            gates,
+            total_negations,
+            total_additions,
+            total_multiplications,
+        }
+    }
+
+    /// Prints the queries in this circuit to a CSV grid.
+    pub fn queries_to_csv(&self) -> String {
+        let mut queries = BTreeSet::new();
+        for gate in &self.gates {
+            for constraint in &gate.constraints {
+                for query in &constraint.queries {
+                    queries.insert(query);
+                }
+            }
+        }
+
+        let mut ret = String::new();
+        let w = &mut ret;
+        for query in &queries {
+            write!(w, "{},", query).unwrap();
+        }
+        writeln!(w, "Name").unwrap();
+
+        for gate in &self.gates {
+            for constraint in &gate.constraints {
+                for query in &queries {
+                    if constraint.queries.contains(*query) {
+                        write!(w, "1").unwrap();
+                    } else {
+                        write!(w, "0").unwrap();
+                    }
+                    write!(w, ",").unwrap();
+                }
+                writeln!(w, "{}/{}", gate.name, constraint.name).unwrap();
+            }
+        }
+        ret
+    }
+}
+
+impl fmt::Display for CircuitGates {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+        for gate in &self.gates {
+            writeln!(f, "{}:", gate.name)?;
+            for constraint in &gate.constraints {
+                if constraint.name.is_empty() {
+                    writeln!(f, "- {}", constraint.expression)?;
+                } else {
+                    writeln!(f, "- {}:", constraint.name)?;
+                    writeln!(f, "  {}", constraint.expression)?;
+                }
+            }
+        }
+        writeln!(f, "Total gates: {}", self.gates.len())?;
+        writeln!(
+            f,
+            "Total custom constraint polynomials: {}",
+            self.gates
+                .iter()
+                .map(|gate| gate.constraints.len())
+                .sum::<usize>()
+        )?;
+        writeln!(f, "Total negations: {}", self.total_negations)?;
+        writeln!(f, "Total additions: {}", self.total_additions)?;
+        writeln!(f, "Total multiplications: {}", self.total_multiplications)
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/dev/metadata.rs.html b/docs/src/halo2_proofs/dev/metadata.rs.html new file mode 100644 index 0000000000..17a389c559 --- /dev/null +++ b/docs/src/halo2_proofs/dev/metadata.rs.html @@ -0,0 +1,352 @@ +metadata.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+
//! Metadata about circuits.
+
+use crate::plonk::{self, Any};
+use std::fmt;
+
+/// Metadata about a column within a circuit.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Column {
+    /// The type of the column.
+    pub(super) column_type: Any,
+    /// The index of the column.
+    pub(super) index: usize,
+}
+
+impl fmt::Display for Column {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "Column('{:?}', {})", self.column_type, self.index)
+    }
+}
+
+impl From<(Any, usize)> for Column {
+    fn from((column_type, index): (Any, usize)) -> Self {
+        Column { column_type, index }
+    }
+}
+
+impl From<plonk::Column<Any>> for Column {
+    fn from(column: plonk::Column<Any>) -> Self {
+        Column {
+            column_type: *column.column_type(),
+            index: column.index(),
+        }
+    }
+}
+
+/// A "virtual cell" is a PLONK cell that has been queried at a particular relative offset
+/// within a custom gate.
+#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct VirtualCell {
+    name: &'static str,
+    pub(super) column: Column,
+    pub(super) rotation: i32,
+}
+
+impl From<(Column, i32)> for VirtualCell {
+    fn from((column, rotation): (Column, i32)) -> Self {
+        VirtualCell {
+            name: "",
+            column,
+            rotation,
+        }
+    }
+}
+
+impl From<(&'static str, Column, i32)> for VirtualCell {
+    fn from((name, column, rotation): (&'static str, Column, i32)) -> Self {
+        VirtualCell {
+            name,
+            column,
+            rotation,
+        }
+    }
+}
+
+impl From<plonk::VirtualCell> for VirtualCell {
+    fn from(c: plonk::VirtualCell) -> Self {
+        VirtualCell {
+            name: "",
+            column: c.column.into(),
+            rotation: c.rotation.0,
+        }
+    }
+}
+
+impl fmt::Display for VirtualCell {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}@{}", self.column, self.rotation)?;
+        if !self.name.is_empty() {
+            write!(f, "({})", self.name)?;
+        }
+        Ok(())
+    }
+}
+
+/// Metadata about a configured gate within a circuit.
+#[derive(Debug, PartialEq)]
+pub struct Gate {
+    /// The index of the active gate. These indices are assigned in the order in which
+    /// `ConstraintSystem::create_gate` is called during `Circuit::configure`.
+    pub(super) index: usize,
+    /// The name of the active gate. These are specified by the gate creator (such as
+    /// a chip implementation), and is not enforced to be unique.
+    pub(super) name: &'static str,
+}
+
+impl fmt::Display for Gate {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "Gate {} ('{}')", self.index, self.name)
+    }
+}
+
+impl From<(usize, &'static str)> for Gate {
+    fn from((index, name): (usize, &'static str)) -> Self {
+        Gate { index, name }
+    }
+}
+
+/// Metadata about a configured constraint within a circuit.
+#[derive(Debug, PartialEq)]
+pub struct Constraint {
+    /// The gate containing the constraint.
+    pub(super) gate: Gate,
+    /// The index of the polynomial constraint within the gate. These indices correspond
+    /// to the order in which the constraints are returned from the closure passed to
+    /// `ConstraintSystem::create_gate` during `Circuit::configure`.
+    pub(super) index: usize,
+    /// The name of the constraint. This is specified by the gate creator (such as a chip
+    /// implementation), and is not enforced to be unique.
+    pub(super) name: &'static str,
+}
+
+impl fmt::Display for Constraint {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(
+            f,
+            "Constraint {}{} in gate {} ('{}')",
+            self.index,
+            if self.name.is_empty() {
+                String::new()
+            } else {
+                format!(" ('{}')", self.name)
+            },
+            self.gate.index,
+            self.gate.name,
+        )
+    }
+}
+
+impl From<(Gate, usize, &'static str)> for Constraint {
+    fn from((gate, index, name): (Gate, usize, &'static str)) -> Self {
+        Constraint { gate, index, name }
+    }
+}
+
+/// Metadata about an assigned region within a circuit.
+#[derive(Clone, Debug, PartialEq)]
+pub struct Region {
+    /// The index of the region. These indices are assigned in the order in which
+    /// `Layouter::assign_region` is called during `Circuit::synthesize`.
+    pub(super) index: usize,
+    /// The name of the region. This is specified by the region creator (such as a chip
+    /// implementation), and is not enforced to be unique.
+    pub(super) name: String,
+}
+
+impl fmt::Display for Region {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "Region {} ('{}')", self.index, self.name)
+    }
+}
+
+impl From<(usize, String)> for Region {
+    fn from((index, name): (usize, String)) -> Self {
+        Region { index, name }
+    }
+}
+
+impl From<(usize, &str)> for Region {
+    fn from((index, name): (usize, &str)) -> Self {
+        Region {
+            index,
+            name: name.to_owned(),
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/dev/util.rs.html b/docs/src/halo2_proofs/dev/util.rs.html new file mode 100644 index 0000000000..8fc02ff60c --- /dev/null +++ b/docs/src/halo2_proofs/dev/util.rs.html @@ -0,0 +1,326 @@ +util.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+
use std::collections::BTreeMap;
+
+use group::ff::Field;
+use halo2curves::FieldExt;
+
+use super::{metadata, CellValue, Value};
+use crate::{
+    plonk::{
+        Advice, AdviceQuery, Any, Column, ColumnType, Expression, FixedQuery, Gate, InstanceQuery,
+        VirtualCell,
+    },
+    poly::Rotation,
+};
+
+pub(crate) struct AnyQuery {
+    /// Query index
+    pub index: usize,
+    /// Column type
+    pub column_type: Any,
+    /// Column index
+    pub column_index: usize,
+    /// Rotation of this query
+    pub rotation: Rotation,
+}
+
+impl From<FixedQuery> for AnyQuery {
+    fn from(query: FixedQuery) -> Self {
+        Self {
+            index: query.index,
+            column_type: Any::Fixed,
+            column_index: query.column_index,
+            rotation: query.rotation,
+        }
+    }
+}
+
+impl From<AdviceQuery> for AnyQuery {
+    fn from(query: AdviceQuery) -> Self {
+        Self {
+            index: query.index,
+            column_type: Any::Advice(Advice { phase: query.phase }),
+            column_index: query.column_index,
+            rotation: query.rotation,
+        }
+    }
+}
+
+impl From<InstanceQuery> for AnyQuery {
+    fn from(query: InstanceQuery) -> Self {
+        Self {
+            index: query.index,
+            column_type: Any::Instance,
+            column_index: query.column_index,
+            rotation: query.rotation,
+        }
+    }
+}
+
+pub(super) fn format_value<F: Field>(v: F) -> String {
+    if v.is_zero_vartime() {
+        "0".into()
+    } else if v == F::one() {
+        "1".into()
+    } else if v == -F::one() {
+        "-1".into()
+    } else {
+        // Format value as hex.
+        let s = format!("{:?}", v);
+        // Remove leading zeroes.
+        let s = s.strip_prefix("0x").unwrap();
+        let s = s.trim_start_matches('0');
+        format!("0x{}", s)
+    }
+}
+
+pub(super) fn load<'a, F: FieldExt, T: ColumnType, Q: Into<AnyQuery> + Copy>(
+    n: i32,
+    row: i32,
+    queries: &'a [(Column<T>, Rotation)],
+    cells: &'a [Vec<CellValue<F>>],
+) -> impl Fn(Q) -> Value<F> + 'a {
+    move |query| {
+        let (column, at) = &queries[query.into().index];
+        let resolved_row = (row + at.0) % n;
+        cells[column.index()][resolved_row as usize].into()
+    }
+}
+
+pub(super) fn load_instance<'a, F: FieldExt, T: ColumnType, Q: Into<AnyQuery> + Copy>(
+    n: i32,
+    row: i32,
+    queries: &'a [(Column<T>, Rotation)],
+    cells: &'a [Vec<F>],
+) -> impl Fn(Q) -> Value<F> + 'a {
+    move |query| {
+        let (column, at) = &queries[query.into().index];
+        let resolved_row = (row + at.0) % n;
+        Value::Real(cells[column.index()][resolved_row as usize])
+    }
+}
+
+fn cell_value<'a, F: FieldExt, Q: Into<AnyQuery> + Copy>(
+    virtual_cells: &'a [VirtualCell],
+    load: impl Fn(Q) -> Value<F> + 'a,
+) -> impl Fn(Q) -> BTreeMap<metadata::VirtualCell, String> + 'a {
+    move |query| {
+        let AnyQuery {
+            column_type,
+            column_index,
+            rotation,
+            ..
+        } = query.into();
+        virtual_cells
+            .iter()
+            .find(|c| {
+                c.column.column_type() == &column_type
+                    && c.column.index() == column_index
+                    && c.rotation == rotation
+            })
+            // None indicates a selector, which we don't bother showing.
+            .map(|cell| {
+                (
+                    cell.clone().into(),
+                    match load(query) {
+                        Value::Real(v) => format_value(v),
+                        Value::Poison => unreachable!(),
+                    },
+                )
+            })
+            .into_iter()
+            .collect()
+    }
+}
+
+pub(super) fn cell_values<'a, F: FieldExt>(
+    gate: &Gate<F>,
+    poly: &Expression<F>,
+    load_fixed: impl Fn(FixedQuery) -> Value<F> + 'a,
+    load_advice: impl Fn(AdviceQuery) -> Value<F> + 'a,
+    load_instance: impl Fn(InstanceQuery) -> Value<F> + 'a,
+) -> Vec<(metadata::VirtualCell, String)> {
+    let virtual_cells = gate.queried_cells();
+    let cell_values = poly.evaluate(
+        &|_| BTreeMap::default(),
+        &|_| panic!("virtual selectors are removed during optimization"),
+        &cell_value(virtual_cells, load_fixed),
+        &cell_value(virtual_cells, load_advice),
+        &cell_value(virtual_cells, load_instance),
+        &|_| BTreeMap::default(),
+        &|a| a,
+        &|mut a, mut b| {
+            a.append(&mut b);
+            a
+        },
+        &|mut a, mut b| {
+            a.append(&mut b);
+            a
+        },
+        &|a, _| a,
+    );
+    cell_values.into_iter().collect()
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/helpers.rs.html b/docs/src/halo2_proofs/helpers.rs.html new file mode 100644 index 0000000000..da1e7f8588 --- /dev/null +++ b/docs/src/halo2_proofs/helpers.rs.html @@ -0,0 +1,294 @@ +helpers.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+
use crate::poly::Polynomial;
+use ff::PrimeField;
+use halo2curves::{pairing::Engine, serde::SerdeObject, CurveAffine};
+use std::io;
+
+/// This enum specifies how various types are serialized and deserialized.
+#[derive(Clone, Copy, Debug)]
+pub enum SerdeFormat {
+    /// Curve elements are serialized in compressed form.
+    /// Field elements are serialized in standard form, with endianness specified by the
+    /// `PrimeField` implementation.
+    Processed,
+    /// Curve elements are serialized in uncompressed form. Field elements are serialized
+    /// in their internal Montgomery representation.
+    /// When deserializing, checks are performed to ensure curve elements indeed lie on the curve and field elements
+    /// are less than modulus.
+    RawBytes,
+    /// Serialization is the same as `RawBytes`, but no checks are performed.
+    RawBytesUnchecked,
+}
+
+// Keep this trait for compatibility with IPA serialization
+pub(crate) trait CurveRead: CurveAffine {
+    /// Reads a compressed element from the buffer and attempts to parse it
+    /// using `from_bytes`.
+    fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
+        let mut compressed = Self::Repr::default();
+        reader.read_exact(compressed.as_mut())?;
+        Option::from(Self::from_bytes(&compressed))
+            .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Invalid point encoding in proof"))
+    }
+}
+impl<C: CurveAffine> CurveRead for C {}
+
+pub trait SerdeCurveAffine: CurveAffine + SerdeObject {
+    /// Reads an element from the buffer and parses it according to the `format`:
+    /// - `Processed`: Reads a compressed curve element and decompress it
+    /// - `RawBytes`: Reads an uncompressed curve element with coordinates in Montgomery form.
+    /// Checks that field elements are less than modulus, and then checks that the point is on the curve.
+    /// - `RawBytesUnchecked`: Reads an uncompressed curve element with coordinates in Montgomery form;
+    /// does not perform any checks
+    fn read<R: io::Read>(reader: &mut R, format: SerdeFormat) -> Self {
+        match format {
+            SerdeFormat::Processed => <Self as CurveRead>::read(reader).unwrap(),
+            SerdeFormat::RawBytes => <Self as SerdeObject>::read_raw(reader).unwrap(),
+            SerdeFormat::RawBytesUnchecked => <Self as SerdeObject>::read_raw_unchecked(reader),
+        }
+    }
+    /// Writes a curve element according to `format`:
+    /// - `Processed`: Writes a compressed curve element
+    /// - Otherwise: Writes an uncompressed curve element with coordinates in Montgomery form
+    fn write<W: io::Write>(&self, writer: &mut W, format: SerdeFormat) {
+        match format {
+            SerdeFormat::Processed => writer.write_all(self.to_bytes().as_ref()).unwrap(),
+            _ => self.write_raw(writer).unwrap(),
+        }
+    }
+}
+impl<C: CurveAffine + SerdeObject> SerdeCurveAffine for C {}
+
+pub trait SerdePrimeField: PrimeField + SerdeObject {
+    /// Reads a field element as bytes from the buffer according to the `format`:
+    /// - `Processed`: Reads a field element in standard form, with endianness specified by the
+    /// `PrimeField` implementation, and checks that the element is less than the modulus.
+    /// - `RawBytes`: Reads a field element from raw bytes in its internal Montgomery representations,
+    /// and checks that the element is less than the modulus.
+    /// - `RawBytesUnchecked`: Reads a field element in Montgomery form and performs no checks.
+    fn read<R: io::Read>(reader: &mut R, format: SerdeFormat) -> Self {
+        match format {
+            SerdeFormat::Processed => {
+                let mut compressed = Self::Repr::default();
+                reader.read_exact(compressed.as_mut()).unwrap();
+                Option::from(Self::from_repr(compressed))
+                    .unwrap_or_else(|| panic!("Invalid prime field point encoding"))
+            }
+            SerdeFormat::RawBytes => <Self as SerdeObject>::read_raw(reader).unwrap(),
+            SerdeFormat::RawBytesUnchecked => <Self as SerdeObject>::read_raw_unchecked(reader),
+        }
+    }
+
+    /// Writes a field element as bytes to the buffer according to the `format`:
+    /// - `Processed`: Writes a field element in standard form, with endianness specified by the
+    /// `PrimeField` implementation.
+    /// - Otherwise: Writes a field element into raw bytes in its internal Montgomery representation,
+    /// WITHOUT performing the expensive Montgomery reduction.
+    fn write<W: io::Write>(&self, writer: &mut W, format: SerdeFormat) {
+        match format {
+            SerdeFormat::Processed => writer.write_all(self.to_repr().as_ref()).unwrap(),
+            _ => self.write_raw(writer).unwrap(),
+        }
+    }
+}
+impl<F: PrimeField + SerdeObject> SerdePrimeField for F {}
+
+/// Convert a slice of `bool` into a `u8`.
+///
+/// Panics if the slice has length greater than 8.
+pub fn pack(bits: &[bool]) -> u8 {
+    let mut value = 0u8;
+    assert!(bits.len() <= 8);
+    for (bit_index, bit) in bits.iter().enumerate() {
+        value |= (*bit as u8) << bit_index;
+    }
+    value
+}
+
+/// Writes the first `bits.len()` bits of a `u8` into `bits`.
+pub fn unpack(byte: u8, bits: &mut [bool]) {
+    for (bit_index, bit) in bits.iter_mut().enumerate() {
+        *bit = (byte >> bit_index) & 1 == 1;
+    }
+}
+
+/// Reads a vector of polynomials from buffer
+pub(crate) fn read_polynomial_vec<R: io::Read, F: SerdePrimeField, B>(
+    reader: &mut R,
+    format: SerdeFormat,
+) -> Vec<Polynomial<F, B>> {
+    let mut len = [0u8; 4];
+    reader.read_exact(&mut len).unwrap();
+    let len = u32::from_be_bytes(len);
+
+    (0..len)
+        .map(|_| Polynomial::<F, B>::read(reader, format))
+        .collect()
+}
+
+/// Writes a slice of polynomials to buffer
+pub(crate) fn write_polynomial_slice<W: io::Write, F: SerdePrimeField, B>(
+    slice: &[Polynomial<F, B>],
+    writer: &mut W,
+    format: SerdeFormat,
+) {
+    writer
+        .write_all(&(slice.len() as u32).to_be_bytes())
+        .unwrap();
+    for poly in slice.iter() {
+        poly.write(writer, format);
+    }
+}
+
+/// Gets the total number of bytes of a slice of polynomials, assuming all polynomials are the same length
+pub(crate) fn polynomial_slice_byte_length<F: PrimeField, B>(slice: &[Polynomial<F, B>]) -> usize {
+    let field_len = F::default().to_repr().as_ref().len();
+    4 + slice.len() * (4 + field_len * slice.get(0).map(|poly| poly.len()).unwrap_or(0))
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/lib.rs.html b/docs/src/halo2_proofs/lib.rs.html new file mode 100644 index 0000000000..ab413d2ab1 --- /dev/null +++ b/docs/src/halo2_proofs/lib.rs.html @@ -0,0 +1,78 @@ +lib.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+
//! # halo2_proofs
+
+#![cfg_attr(docsrs, feature(doc_cfg))]
+// Build without warnings on stable 1.51 and later.
+#![allow(unknown_lints)]
+// Disable old lint warnings until our MSRV is at least 1.51.
+#![allow(renamed_and_removed_lints)]
+// Use the old lint name to build without warnings until our MSRV is at least 1.51.
+#![allow(clippy::unknown_clippy_lints)]
+// The actual lints we want to disable.
+#![allow(
+    clippy::op_ref,
+    clippy::assign_op_pattern,
+    clippy::too_many_arguments,
+    clippy::suspicious_arithmetic_impl,
+    clippy::many_single_char_names,
+    clippy::same_item_push,
+    clippy::upper_case_acronyms
+)]
+#![deny(broken_intra_doc_links)]
+#![deny(missing_debug_implementations)]
+// #![deny(missing_docs)]
+// #![deny(unsafe_code)]
+// Remove this once we update pasta_curves
+#![allow(unused_imports)]
+#![allow(clippy::derive_partial_eq_without_eq)]
+
+pub mod arithmetic;
+pub mod circuit;
+pub use halo2curves;
+mod multicore;
+pub mod plonk;
+pub mod poly;
+pub mod transcript;
+
+pub mod dev;
+mod helpers;
+pub use helpers::SerdeFormat;
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/multicore.rs.html b/docs/src/halo2_proofs/multicore.rs.html new file mode 100644 index 0000000000..8d09c9c1a3 --- /dev/null +++ b/docs/src/halo2_proofs/multicore.rs.html @@ -0,0 +1,12 @@ +multicore.rs - source
1
+2
+3
+4
+5
+
//! An interface for dealing with the kinds of parallel computations involved in
+//! `halo2`. It's currently just a (very!) thin wrapper around [`rayon`] but may
+//! be extended in the future to allow for various parallelism strategies.
+
+pub use rayon::{current_num_threads, scope, Scope};
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk.rs.html b/docs/src/halo2_proofs/plonk.rs.html new file mode 100644 index 0000000000..1cb76ea12e --- /dev/null +++ b/docs/src/halo2_proofs/plonk.rs.html @@ -0,0 +1,800 @@ +plonk.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+
//! This module provides an implementation of a variant of (Turbo)[PLONK][plonk]
+//! that is designed specifically for the polynomial commitment scheme described
+//! in the [Halo][halo] paper.
+//!
+//! [halo]: https://eprint.iacr.org/2019/1021
+//! [plonk]: https://eprint.iacr.org/2019/953
+
+use blake2b_simd::Params as Blake2bParams;
+use ff::PrimeField;
+use group::ff::Field;
+
+use crate::arithmetic::{CurveAffine, FieldExt};
+use crate::helpers::{
+    polynomial_slice_byte_length, read_polynomial_vec, write_polynomial_slice, SerdeCurveAffine,
+    SerdePrimeField,
+};
+use crate::poly::{
+    commitment::Params, Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff,
+    PinnedEvaluationDomain, Polynomial,
+};
+use crate::transcript::{ChallengeScalar, EncodedChallenge, Transcript};
+use crate::SerdeFormat;
+
+mod assigned;
+mod circuit;
+mod error;
+mod evaluation;
+mod keygen;
+mod lookup;
+pub(crate) mod permutation;
+mod vanishing;
+
+mod prover;
+mod verifier;
+
+pub use assigned::*;
+pub use circuit::*;
+pub use error::*;
+pub use keygen::*;
+pub use prover::*;
+pub use verifier::*;
+
+use evaluation::Evaluator;
+use std::io;
+
+/// This is a verifying key which allows for the verification of proofs for a
+/// particular circuit.
+#[derive(Clone, Debug)]
+pub struct VerifyingKey<C: CurveAffine> {
+    domain: EvaluationDomain<C::Scalar>,
+    fixed_commitments: Vec<C>,
+    permutation: permutation::VerifyingKey<C>,
+    cs: ConstraintSystem<C::Scalar>,
+    /// Cached maximum degree of `cs` (which doesn't change after construction).
+    cs_degree: usize,
+    /// The representative of this `VerifyingKey` in transcripts.
+    transcript_repr: C::Scalar,
+    selectors: Vec<Vec<bool>>,
+}
+
+impl<C: SerdeCurveAffine> VerifyingKey<C>
+where
+    C::Scalar: SerdePrimeField,
+{
+    /// Writes a verifying key to a buffer.
+    ///
+    /// Writes a curve element according to `format`:
+    /// - `Processed`: Writes a compressed curve element with coordinates in standard form.
+    /// Writes a field element in standard form, with endianness specified by the
+    /// `PrimeField` implementation.
+    /// - Otherwise: Writes an uncompressed curve element with coordinates in Montgomery form
+    /// Writes a field element into raw bytes in its internal Montgomery representation,
+    /// WITHOUT performing the expensive Montgomery reduction.
+    pub fn write<W: io::Write>(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> {
+        writer.write_all(&self.domain.k().to_be_bytes()).unwrap();
+        writer
+            .write_all(&(self.fixed_commitments.len() as u32).to_be_bytes())
+            .unwrap();
+        for commitment in &self.fixed_commitments {
+            commitment.write(writer, format);
+        }
+        self.permutation.write(writer, format);
+
+        // write self.selectors
+        for selector in &self.selectors {
+            // since `selector` is filled with `bool`, we pack them 8 at a time into bytes and then write
+            for bits in selector.chunks(8) {
+                writer.write_all(&[crate::helpers::pack(bits)]).unwrap();
+            }
+        }
+        Ok(())
+    }
+
+    /// Reads a verification key from a buffer.
+    ///
+    /// Reads a curve element from the buffer and parses it according to the `format`:
+    /// - `Processed`: Reads a compressed curve element and decompresses it.
+    /// Reads a field element in standard form, with endianness specified by the
+    /// `PrimeField` implementation, and checks that the element is less than the modulus.
+    /// - `RawBytes`: Reads an uncompressed curve element with coordinates in Montgomery form.
+    /// Checks that field elements are less than modulus, and then checks that the point is on the curve.
+    /// - `RawBytesUnchecked`: Reads an uncompressed curve element with coordinates in Montgomery form;
+    /// does not perform any checks
+    pub fn read<R: io::Read, ConcreteCircuit: Circuit<C::Scalar>>(
+        reader: &mut R,
+        format: SerdeFormat,
+    ) -> io::Result<Self> {
+        let mut k = [0u8; 4];
+        reader.read_exact(&mut k)?;
+        let k = u32::from_be_bytes(k);
+        let (domain, cs, _) = keygen::create_domain::<C, ConcreteCircuit>(k);
+        let mut num_fixed_columns = [0u8; 4];
+        reader.read_exact(&mut num_fixed_columns).unwrap();
+        let num_fixed_columns = u32::from_be_bytes(num_fixed_columns);
+
+        let fixed_commitments: Vec<_> = (0..num_fixed_columns)
+            .map(|_| C::read(reader, format))
+            .collect();
+
+        let permutation = permutation::VerifyingKey::read(reader, &cs.permutation, format);
+
+        // read selectors
+        let selectors: Vec<Vec<bool>> = vec![vec![false; 1 << k]; cs.num_selectors]
+            .into_iter()
+            .map(|mut selector| {
+                let mut selector_bytes = vec![0u8; (selector.len() + 7) / 8];
+                reader.read_exact(&mut selector_bytes).unwrap();
+                for (bits, byte) in selector.chunks_mut(8).into_iter().zip(selector_bytes) {
+                    crate::helpers::unpack(byte, bits);
+                }
+                selector
+            })
+            .collect();
+        let (cs, _) = cs.compress_selectors(selectors.clone());
+
+        Ok(Self::from_parts(
+            domain,
+            fixed_commitments,
+            permutation,
+            cs,
+            selectors,
+        ))
+    }
+
+    /// Writes a verifying key to a vector of bytes using [`Self::write`].
+    pub fn to_bytes(&self, format: SerdeFormat) -> Vec<u8> {
+        let mut bytes = Vec::<u8>::with_capacity(self.bytes_length());
+        Self::write(self, &mut bytes, format).expect("Writing to vector should not fail");
+        bytes
+    }
+
+    /// Reads a verification key from a slice of bytes using [`Self::read`].
+    pub fn from_bytes<ConcreteCircuit: Circuit<C::Scalar>>(
+        mut bytes: &[u8],
+        format: SerdeFormat,
+    ) -> io::Result<Self> {
+        Self::read::<_, ConcreteCircuit>(&mut bytes, format)
+    }
+}
+
+impl<C: CurveAffine> VerifyingKey<C> {
+    fn bytes_length(&self) -> usize {
+        8 + (self.fixed_commitments.len() * C::default().to_bytes().as_ref().len())
+            + self.permutation.bytes_length()
+            + self.selectors.len()
+                * (self
+                    .selectors
+                    .get(0)
+                    .map(|selector| selector.len() / 8 + 1)
+                    .unwrap_or(0))
+    }
+
+    fn from_parts(
+        domain: EvaluationDomain<C::Scalar>,
+        fixed_commitments: Vec<C>,
+        permutation: permutation::VerifyingKey<C>,
+        cs: ConstraintSystem<C::Scalar>,
+        selectors: Vec<Vec<bool>>,
+    ) -> Self {
+        // Compute cached values.
+        let cs_degree = cs.degree();
+
+        let mut vk = Self {
+            domain,
+            fixed_commitments,
+            permutation,
+            cs,
+            cs_degree,
+            // Temporary, this is not pinned.
+            transcript_repr: C::Scalar::zero(),
+            selectors,
+        };
+
+        let mut hasher = Blake2bParams::new()
+            .hash_length(64)
+            .personal(b"Halo2-Verify-Key")
+            .to_state();
+
+        let s = format!("{:?}", vk.pinned());
+
+        hasher.update(&(s.len() as u64).to_le_bytes());
+        hasher.update(s.as_bytes());
+
+        // Hash in final Blake2bState
+        vk.transcript_repr = C::Scalar::from_bytes_wide(hasher.finalize().as_array());
+
+        vk
+    }
+
+    /// Hashes a verification key into a transcript.
+    pub fn hash_into<E: EncodedChallenge<C>, T: Transcript<C, E>>(
+        &self,
+        transcript: &mut T,
+    ) -> io::Result<()> {
+        transcript.common_scalar(self.transcript_repr)?;
+
+        Ok(())
+    }
+
+    /// Obtains a pinned representation of this verification key that contains
+    /// the minimal information necessary to reconstruct the verification key.
+    pub fn pinned(&self) -> PinnedVerificationKey<'_, C> {
+        PinnedVerificationKey {
+            base_modulus: C::Base::MODULUS,
+            scalar_modulus: C::Scalar::MODULUS,
+            domain: self.domain.pinned(),
+            fixed_commitments: &self.fixed_commitments,
+            permutation: &self.permutation,
+            cs: self.cs.pinned(),
+        }
+    }
+
+    /// Returns commitments of fixed polynomials
+    pub fn fixed_commitments(&self) -> &Vec<C> {
+        &self.fixed_commitments
+    }
+
+    /// Returns `VerifyingKey` of permutation
+    pub fn permutation(&self) -> &permutation::VerifyingKey<C> {
+        &self.permutation
+    }
+
+    /// Returns `ConstraintSystem`
+    pub fn cs(&self) -> &ConstraintSystem<C::Scalar> {
+        &self.cs
+    }
+}
+
+/// Minimal representation of a verification key that can be used to identify
+/// its active contents.
+#[allow(dead_code)]
+#[derive(Debug)]
+pub struct PinnedVerificationKey<'a, C: CurveAffine> {
+    base_modulus: &'static str,
+    scalar_modulus: &'static str,
+    domain: PinnedEvaluationDomain<'a, C::Scalar>,
+    cs: PinnedConstraintSystem<'a, C::Scalar>,
+    fixed_commitments: &'a Vec<C>,
+    permutation: &'a permutation::VerifyingKey<C>,
+}
+/// This is a proving key which allows for the creation of proofs for a
+/// particular circuit.
+#[derive(Clone, Debug)]
+pub struct ProvingKey<C: CurveAffine> {
+    vk: VerifyingKey<C>,
+    l0: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
+    l_last: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
+    l_active_row: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
+    fixed_values: Vec<Polynomial<C::Scalar, LagrangeCoeff>>,
+    fixed_polys: Vec<Polynomial<C::Scalar, Coeff>>,
+    fixed_cosets: Vec<Polynomial<C::Scalar, ExtendedLagrangeCoeff>>,
+    permutation: permutation::ProvingKey<C>,
+    ev: Evaluator<C>,
+}
+
+impl<C: CurveAffine> ProvingKey<C> {
+    /// Get the underlying [`VerifyingKey`].
+    pub fn get_vk(&self) -> &VerifyingKey<C> {
+        &self.vk
+    }
+
+    /// Gets the total number of bytes in the serialization of `self`
+    fn bytes_length(&self) -> usize {
+        let scalar_len = C::Scalar::default().to_repr().as_ref().len();
+        self.vk.bytes_length()
+            + 12
+            + scalar_len * (self.l0.len() + self.l_last.len() + self.l_active_row.len())
+            + polynomial_slice_byte_length(&self.fixed_values)
+            + polynomial_slice_byte_length(&self.fixed_polys)
+            + polynomial_slice_byte_length(&self.fixed_cosets)
+            + self.permutation.bytes_length()
+    }
+}
+
+impl<C: SerdeCurveAffine> ProvingKey<C>
+where
+    C::Scalar: SerdePrimeField,
+{
+    /// Writes a proving key to a buffer.
+    ///
+    /// Writes a curve element according to `format`:
+    /// - `Processed`: Writes a compressed curve element with coordinates in standard form.
+    /// Writes a field element in standard form, with endianness specified by the
+    /// `PrimeField` implementation.
+    /// - Otherwise: Writes an uncompressed curve element with coordinates in Montgomery form
+    /// Writes a field element into raw bytes in its internal Montgomery representation,
+    /// WITHOUT performing the expensive Montgomery reduction.
+    /// Does so by first writing the verifying key and then serializing the rest of the data (in the form of field polynomials)
+    pub fn write<W: io::Write>(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> {
+        self.vk.write(writer, format).unwrap();
+        self.l0.write(writer, format);
+        self.l_last.write(writer, format);
+        self.l_active_row.write(writer, format);
+        write_polynomial_slice(&self.fixed_values, writer, format);
+        write_polynomial_slice(&self.fixed_polys, writer, format);
+        write_polynomial_slice(&self.fixed_cosets, writer, format);
+        self.permutation.write(writer, format);
+        Ok(())
+    }
+
+    /// Reads a proving key from a buffer.
+    /// Does so by reading verification key first, and then deserializing the rest of the file into the remaining proving key data.
+    ///
+    /// Reads a curve element from the buffer and parses it according to the `format`:
+    /// - `Processed`: Reads a compressed curve element and decompresses it.
+    /// Reads a field element in standard form, with endianness specified by the
+    /// `PrimeField` implementation, and checks that the element is less than the modulus.
+    /// - `RawBytes`: Reads an uncompressed curve element with coordinates in Montgomery form.
+    /// Checks that field elements are less than modulus, and then checks that the point is on the curve.
+    /// - `RawBytesUnchecked`: Reads an uncompressed curve element with coordinates in Montgomery form;
+    /// does not perform any checks
+    pub fn read<R: io::Read, ConcreteCircuit: Circuit<C::Scalar>>(
+        reader: &mut R,
+        format: SerdeFormat,
+    ) -> io::Result<Self> {
+        let vk = VerifyingKey::<C>::read::<R, ConcreteCircuit>(reader, format).unwrap();
+        let l0 = Polynomial::read(reader, format);
+        let l_last = Polynomial::read(reader, format);
+        let l_active_row = Polynomial::read(reader, format);
+        let fixed_values = read_polynomial_vec(reader, format);
+        let fixed_polys = read_polynomial_vec(reader, format);
+        let fixed_cosets = read_polynomial_vec(reader, format);
+        let permutation = permutation::ProvingKey::read(reader, format);
+        let ev = Evaluator::new(vk.cs());
+        Ok(Self {
+            vk,
+            l0,
+            l_last,
+            l_active_row,
+            fixed_values,
+            fixed_polys,
+            fixed_cosets,
+            permutation,
+            ev,
+        })
+    }
+
+    /// Writes a proving key to a vector of bytes using [`Self::write`].
+    pub fn to_bytes(&self, format: SerdeFormat) -> Vec<u8> {
+        let mut bytes = Vec::<u8>::with_capacity(self.bytes_length());
+        Self::write(self, &mut bytes, format).expect("Writing to vector should not fail");
+        bytes
+    }
+
+    /// Reads a proving key from a slice of bytes using [`Self::read`].
+    pub fn from_bytes<ConcreteCircuit: Circuit<C::Scalar>>(
+        mut bytes: &[u8],
+        format: SerdeFormat,
+    ) -> io::Result<Self> {
+        Self::read::<_, ConcreteCircuit>(&mut bytes, format)
+    }
+}
+
+impl<C: CurveAffine> VerifyingKey<C> {
+    /// Get the underlying [`EvaluationDomain`].
+    pub fn get_domain(&self) -> &EvaluationDomain<C::Scalar> {
+        &self.domain
+    }
+}
+
+#[derive(Clone, Copy, Debug)]
+struct Theta;
+type ChallengeTheta<F> = ChallengeScalar<F, Theta>;
+
+#[derive(Clone, Copy, Debug)]
+struct Beta;
+type ChallengeBeta<F> = ChallengeScalar<F, Beta>;
+
+#[derive(Clone, Copy, Debug)]
+struct Gamma;
+type ChallengeGamma<F> = ChallengeScalar<F, Gamma>;
+
+#[derive(Clone, Copy, Debug)]
+struct Y;
+type ChallengeY<F> = ChallengeScalar<F, Y>;
+
+#[derive(Clone, Copy, Debug)]
+struct X;
+type ChallengeX<F> = ChallengeScalar<F, X>;
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/assigned.rs.html b/docs/src/halo2_proofs/plonk/assigned.rs.html new file mode 100644 index 0000000000..152a9724b5 --- /dev/null +++ b/docs/src/halo2_proofs/plonk/assigned.rs.html @@ -0,0 +1,1334 @@ +assigned.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
+
+use group::ff::Field;
+
+/// A value assigned to a cell within a circuit.
+///
+/// Stored as a fraction, so the backend can use batch inversion.
+///
+/// A denominator of zero maps to an assigned value of zero.
+#[derive(Clone, Copy, Debug)]
+pub enum Assigned<F> {
+    /// The field element zero.
+    Zero,
+    /// A value that does not require inversion to evaluate.
+    Trivial(F),
+    /// A value stored as a fraction to enable batch inversion.
+    Rational(F, F),
+}
+
+impl<F: Field> From<&Assigned<F>> for Assigned<F> {
+    fn from(val: &Assigned<F>) -> Self {
+        *val
+    }
+}
+
+impl<F: Field> From<&F> for Assigned<F> {
+    fn from(numerator: &F) -> Self {
+        Assigned::Trivial(*numerator)
+    }
+}
+
+impl<F: Field> From<F> for Assigned<F> {
+    fn from(numerator: F) -> Self {
+        Assigned::Trivial(numerator)
+    }
+}
+
+impl<F: Field> From<(F, F)> for Assigned<F> {
+    fn from((numerator, denominator): (F, F)) -> Self {
+        Assigned::Rational(numerator, denominator)
+    }
+}
+
+impl<F: Field> PartialEq for Assigned<F> {
+    fn eq(&self, other: &Self) -> bool {
+        match (self, other) {
+            // At least one side is directly zero.
+            (Self::Zero, Self::Zero) => true,
+            (Self::Zero, x) | (x, Self::Zero) => x.is_zero_vartime(),
+
+            // One side is x/0 which maps to zero.
+            (Self::Rational(_, denominator), x) | (x, Self::Rational(_, denominator))
+                if denominator.is_zero_vartime() =>
+            {
+                x.is_zero_vartime()
+            }
+
+            // Okay, we need to do some actual math...
+            (Self::Trivial(lhs), Self::Trivial(rhs)) => lhs == rhs,
+            (Self::Trivial(x), Self::Rational(numerator, denominator))
+            | (Self::Rational(numerator, denominator), Self::Trivial(x)) => {
+                &(*x * denominator) == numerator
+            }
+            (
+                Self::Rational(lhs_numerator, lhs_denominator),
+                Self::Rational(rhs_numerator, rhs_denominator),
+            ) => *lhs_numerator * rhs_denominator == *lhs_denominator * rhs_numerator,
+        }
+    }
+}
+
+impl<F: Field> Eq for Assigned<F> {}
+
+impl<F: Field> Neg for Assigned<F> {
+    type Output = Assigned<F>;
+    fn neg(self) -> Self::Output {
+        match self {
+            Self::Zero => Self::Zero,
+            Self::Trivial(numerator) => Self::Trivial(-numerator),
+            Self::Rational(numerator, denominator) => Self::Rational(-numerator, denominator),
+        }
+    }
+}
+
+impl<F: Field> Neg for &Assigned<F> {
+    type Output = Assigned<F>;
+    fn neg(self) -> Self::Output {
+        -*self
+    }
+}
+
+impl<F: Field> Add for Assigned<F> {
+    type Output = Assigned<F>;
+    fn add(self, rhs: Assigned<F>) -> Assigned<F> {
+        match (self, rhs) {
+            // One side is directly zero.
+            (Self::Zero, _) => rhs,
+            (_, Self::Zero) => self,
+
+            // One side is x/0 which maps to zero.
+            (Self::Rational(_, denominator), other) | (other, Self::Rational(_, denominator))
+                if denominator.is_zero_vartime() =>
+            {
+                other
+            }
+
+            // Okay, we need to do some actual math...
+            (Self::Trivial(lhs), Self::Trivial(rhs)) => Self::Trivial(lhs + rhs),
+            (Self::Rational(numerator, denominator), Self::Trivial(other))
+            | (Self::Trivial(other), Self::Rational(numerator, denominator)) => {
+                Self::Rational(numerator + denominator * other, denominator)
+            }
+            (
+                Self::Rational(lhs_numerator, lhs_denominator),
+                Self::Rational(rhs_numerator, rhs_denominator),
+            ) => Self::Rational(
+                lhs_numerator * rhs_denominator + lhs_denominator * rhs_numerator,
+                lhs_denominator * rhs_denominator,
+            ),
+        }
+    }
+}
+
+impl<F: Field> Add<F> for Assigned<F> {
+    type Output = Assigned<F>;
+    fn add(self, rhs: F) -> Assigned<F> {
+        self + Self::Trivial(rhs)
+    }
+}
+
+impl<F: Field> Add<F> for &Assigned<F> {
+    type Output = Assigned<F>;
+    fn add(self, rhs: F) -> Assigned<F> {
+        *self + rhs
+    }
+}
+
+impl<F: Field> Add<&Assigned<F>> for Assigned<F> {
+    type Output = Assigned<F>;
+    fn add(self, rhs: &Self) -> Assigned<F> {
+        self + *rhs
+    }
+}
+
+impl<F: Field> Add<Assigned<F>> for &Assigned<F> {
+    type Output = Assigned<F>;
+    fn add(self, rhs: Assigned<F>) -> Assigned<F> {
+        *self + rhs
+    }
+}
+
+impl<F: Field> Add<&Assigned<F>> for &Assigned<F> {
+    type Output = Assigned<F>;
+    fn add(self, rhs: &Assigned<F>) -> Assigned<F> {
+        *self + *rhs
+    }
+}
+
+impl<F: Field> AddAssign for Assigned<F> {
+    fn add_assign(&mut self, rhs: Self) {
+        *self = *self + rhs;
+    }
+}
+
+impl<F: Field> AddAssign<&Assigned<F>> for Assigned<F> {
+    fn add_assign(&mut self, rhs: &Self) {
+        *self = *self + rhs;
+    }
+}
+
+impl<F: Field> Sub for Assigned<F> {
+    type Output = Assigned<F>;
+    fn sub(self, rhs: Assigned<F>) -> Assigned<F> {
+        self + (-rhs)
+    }
+}
+
+impl<F: Field> Sub<F> for Assigned<F> {
+    type Output = Assigned<F>;
+    fn sub(self, rhs: F) -> Assigned<F> {
+        self + (-rhs)
+    }
+}
+
+impl<F: Field> Sub<F> for &Assigned<F> {
+    type Output = Assigned<F>;
+    fn sub(self, rhs: F) -> Assigned<F> {
+        *self - rhs
+    }
+}
+
+impl<F: Field> Sub<&Assigned<F>> for Assigned<F> {
+    type Output = Assigned<F>;
+    fn sub(self, rhs: &Self) -> Assigned<F> {
+        self - *rhs
+    }
+}
+
+impl<F: Field> Sub<Assigned<F>> for &Assigned<F> {
+    type Output = Assigned<F>;
+    fn sub(self, rhs: Assigned<F>) -> Assigned<F> {
+        *self - rhs
+    }
+}
+
+impl<F: Field> Sub<&Assigned<F>> for &Assigned<F> {
+    type Output = Assigned<F>;
+    fn sub(self, rhs: &Assigned<F>) -> Assigned<F> {
+        *self - *rhs
+    }
+}
+
+impl<F: Field> SubAssign for Assigned<F> {
+    fn sub_assign(&mut self, rhs: Self) {
+        *self = *self - rhs;
+    }
+}
+
+impl<F: Field> SubAssign<&Assigned<F>> for Assigned<F> {
+    fn sub_assign(&mut self, rhs: &Self) {
+        *self = *self - rhs;
+    }
+}
+
+impl<F: Field> Mul for Assigned<F> {
+    type Output = Assigned<F>;
+    fn mul(self, rhs: Assigned<F>) -> Assigned<F> {
+        match (self, rhs) {
+            (Self::Zero, _) | (_, Self::Zero) => Self::Zero,
+            (Self::Trivial(lhs), Self::Trivial(rhs)) => Self::Trivial(lhs * rhs),
+            (Self::Rational(numerator, denominator), Self::Trivial(other))
+            | (Self::Trivial(other), Self::Rational(numerator, denominator)) => {
+                Self::Rational(numerator * other, denominator)
+            }
+            (
+                Self::Rational(lhs_numerator, lhs_denominator),
+                Self::Rational(rhs_numerator, rhs_denominator),
+            ) => Self::Rational(
+                lhs_numerator * rhs_numerator,
+                lhs_denominator * rhs_denominator,
+            ),
+        }
+    }
+}
+
+impl<F: Field> Mul<F> for Assigned<F> {
+    type Output = Assigned<F>;
+    fn mul(self, rhs: F) -> Assigned<F> {
+        self * Self::Trivial(rhs)
+    }
+}
+
+impl<F: Field> Mul<F> for &Assigned<F> {
+    type Output = Assigned<F>;
+    fn mul(self, rhs: F) -> Assigned<F> {
+        *self * rhs
+    }
+}
+
+impl<F: Field> Mul<&Assigned<F>> for Assigned<F> {
+    type Output = Assigned<F>;
+    fn mul(self, rhs: &Assigned<F>) -> Assigned<F> {
+        self * *rhs
+    }
+}
+
+impl<F: Field> MulAssign for Assigned<F> {
+    fn mul_assign(&mut self, rhs: Self) {
+        *self = *self * rhs;
+    }
+}
+
+impl<F: Field> MulAssign<&Assigned<F>> for Assigned<F> {
+    fn mul_assign(&mut self, rhs: &Self) {
+        *self = *self * rhs;
+    }
+}
+
+impl<F: Field> Assigned<F> {
+    /// Returns the numerator.
+    pub fn numerator(&self) -> F {
+        match self {
+            Self::Zero => F::zero(),
+            Self::Trivial(x) => *x,
+            Self::Rational(numerator, _) => *numerator,
+        }
+    }
+
+    /// Returns the denominator, if non-trivial.
+    pub fn denominator(&self) -> Option<F> {
+        match self {
+            Self::Zero => None,
+            Self::Trivial(_) => None,
+            Self::Rational(_, denominator) => Some(*denominator),
+        }
+    }
+
+    /// Returns true iff this element is zero.
+    pub fn is_zero_vartime(&self) -> bool {
+        match self {
+            Self::Zero => true,
+            Self::Trivial(x) => x.is_zero_vartime(),
+            // Assigned maps x/0 -> 0.
+            Self::Rational(numerator, denominator) => {
+                numerator.is_zero_vartime() || denominator.is_zero_vartime()
+            }
+        }
+    }
+
+    /// Doubles this element.
+    #[must_use]
+    pub fn double(&self) -> Self {
+        match self {
+            Self::Zero => Self::Zero,
+            Self::Trivial(x) => Self::Trivial(x.double()),
+            Self::Rational(numerator, denominator) => {
+                Self::Rational(numerator.double(), *denominator)
+            }
+        }
+    }
+
+    /// Squares this element.
+    #[must_use]
+    pub fn square(&self) -> Self {
+        match self {
+            Self::Zero => Self::Zero,
+            Self::Trivial(x) => Self::Trivial(x.square()),
+            Self::Rational(numerator, denominator) => {
+                Self::Rational(numerator.square(), denominator.square())
+            }
+        }
+    }
+
+    /// Cubes this element.
+    #[must_use]
+    pub fn cube(&self) -> Self {
+        self.square() * self
+    }
+
+    /// Inverts this assigned value (taking the inverse of zero to be zero).
+    pub fn invert(&self) -> Self {
+        match self {
+            Self::Zero => Self::Zero,
+            Self::Trivial(x) => Self::Rational(F::one(), *x),
+            Self::Rational(numerator, denominator) => Self::Rational(*denominator, *numerator),
+        }
+    }
+
+    /// Evaluates this assigned value directly, performing an unbatched inversion if
+    /// necessary.
+    ///
+    /// If the denominator is zero, this returns zero.
+    pub fn evaluate(self) -> F {
+        match self {
+            Self::Zero => F::zero(),
+            Self::Trivial(x) => x,
+            Self::Rational(numerator, denominator) => {
+                if denominator == F::one() {
+                    numerator
+                } else {
+                    numerator * denominator.invert().unwrap_or(F::zero())
+                }
+            }
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use halo2curves::pasta::Fp;
+
+    use super::Assigned;
+    // We use (numerator, denominator) in the comments below to denote a rational.
+    #[test]
+    fn add_trivial_to_inv0_rational() {
+        // a = 2
+        // b = (1,0)
+        let a = Assigned::Trivial(Fp::from(2));
+        let b = Assigned::Rational(Fp::one(), Fp::zero());
+
+        // 2 + (1,0) = 2 + 0 = 2
+        // This fails if addition is implemented using normal rules for rationals.
+        assert_eq!((a + b).evaluate(), a.evaluate());
+        assert_eq!((b + a).evaluate(), a.evaluate());
+    }
+
+    #[test]
+    fn add_rational_to_inv0_rational() {
+        // a = (1,2)
+        // b = (1,0)
+        let a = Assigned::Rational(Fp::one(), Fp::from(2));
+        let b = Assigned::Rational(Fp::one(), Fp::zero());
+
+        // (1,2) + (1,0) = (1,2) + 0 = (1,2)
+        // This fails if addition is implemented using normal rules for rationals.
+        assert_eq!((a + b).evaluate(), a.evaluate());
+        assert_eq!((b + a).evaluate(), a.evaluate());
+    }
+
+    #[test]
+    fn sub_trivial_from_inv0_rational() {
+        // a = 2
+        // b = (1,0)
+        let a = Assigned::Trivial(Fp::from(2));
+        let b = Assigned::Rational(Fp::one(), Fp::zero());
+
+        // (1,0) - 2 = 0 - 2 = -2
+        // This fails if subtraction is implemented using normal rules for rationals.
+        assert_eq!((b - a).evaluate(), (-a).evaluate());
+
+        // 2 - (1,0) = 2 - 0 = 2
+        assert_eq!((a - b).evaluate(), a.evaluate());
+    }
+
+    #[test]
+    fn sub_rational_from_inv0_rational() {
+        // a = (1,2)
+        // b = (1,0)
+        let a = Assigned::Rational(Fp::one(), Fp::from(2));
+        let b = Assigned::Rational(Fp::one(), Fp::zero());
+
+        // (1,0) - (1,2) = 0 - (1,2) = -(1,2)
+        // This fails if subtraction is implemented using normal rules for rationals.
+        assert_eq!((b - a).evaluate(), (-a).evaluate());
+
+        // (1,2) - (1,0) = (1,2) - 0 = (1,2)
+        assert_eq!((a - b).evaluate(), a.evaluate());
+    }
+
+    #[test]
+    fn mul_rational_by_inv0_rational() {
+        // a = (1,2)
+        // b = (1,0)
+        let a = Assigned::Rational(Fp::one(), Fp::from(2));
+        let b = Assigned::Rational(Fp::one(), Fp::zero());
+
+        // (1,2) * (1,0) = (1,2) * 0 = 0
+        assert_eq!((a * b).evaluate(), Fp::zero());
+
+        // (1,0) * (1,2) = 0 * (1,2) = 0
+        assert_eq!((b * a).evaluate(), Fp::zero());
+    }
+}
+
+#[cfg(test)]
+mod proptests {
+    use std::{
+        cmp,
+        convert::TryFrom,
+        ops::{Add, Mul, Neg, Sub},
+    };
+
+    use group::ff::Field;
+    use halo2curves::{pasta::Fp, FieldExt};
+    use proptest::{collection::vec, prelude::*, sample::select};
+
+    use super::Assigned;
+
+    trait UnaryOperand: Neg<Output = Self> {
+        fn double(&self) -> Self;
+        fn square(&self) -> Self;
+        fn cube(&self) -> Self;
+        fn inv0(&self) -> Self;
+    }
+
+    impl<F: Field> UnaryOperand for F {
+        fn double(&self) -> Self {
+            self.double()
+        }
+
+        fn square(&self) -> Self {
+            self.square()
+        }
+
+        fn cube(&self) -> Self {
+            self.cube()
+        }
+
+        fn inv0(&self) -> Self {
+            self.invert().unwrap_or(F::zero())
+        }
+    }
+
+    impl<F: Field> UnaryOperand for Assigned<F> {
+        fn double(&self) -> Self {
+            self.double()
+        }
+
+        fn square(&self) -> Self {
+            self.square()
+        }
+
+        fn cube(&self) -> Self {
+            self.cube()
+        }
+
+        fn inv0(&self) -> Self {
+            self.invert()
+        }
+    }
+
+    #[derive(Clone, Debug)]
+    enum UnaryOperator {
+        Neg,
+        Double,
+        Square,
+        Cube,
+        Inv0,
+    }
+
+    const UNARY_OPERATORS: &[UnaryOperator] = &[
+        UnaryOperator::Neg,
+        UnaryOperator::Double,
+        UnaryOperator::Square,
+        UnaryOperator::Cube,
+        UnaryOperator::Inv0,
+    ];
+
+    impl UnaryOperator {
+        fn apply<F: UnaryOperand>(&self, a: F) -> F {
+            match self {
+                Self::Neg => -a,
+                Self::Double => a.double(),
+                Self::Square => a.square(),
+                Self::Cube => a.cube(),
+                Self::Inv0 => a.inv0(),
+            }
+        }
+    }
+
+    trait BinaryOperand: Sized + Add<Output = Self> + Sub<Output = Self> + Mul<Output = Self> {}
+    impl<F: Field> BinaryOperand for F {}
+    impl<F: Field> BinaryOperand for Assigned<F> {}
+
+    #[derive(Clone, Debug)]
+    enum BinaryOperator {
+        Add,
+        Sub,
+        Mul,
+    }
+
+    const BINARY_OPERATORS: &[BinaryOperator] = &[
+        BinaryOperator::Add,
+        BinaryOperator::Sub,
+        BinaryOperator::Mul,
+    ];
+
+    impl BinaryOperator {
+        fn apply<F: BinaryOperand>(&self, a: F, b: F) -> F {
+            match self {
+                Self::Add => a + b,
+                Self::Sub => a - b,
+                Self::Mul => a * b,
+            }
+        }
+    }
+
+    #[derive(Clone, Debug)]
+    enum Operator {
+        Unary(UnaryOperator),
+        Binary(BinaryOperator),
+    }
+
+    prop_compose! {
+        /// Use narrow that can be easily reduced.
+        fn arb_element()(val in any::<u64>()) -> Fp {
+            Fp::from(val)
+        }
+    }
+
+    prop_compose! {
+        fn arb_trivial()(element in arb_element()) -> Assigned<Fp> {
+            Assigned::Trivial(element)
+        }
+    }
+
+    prop_compose! {
+        /// Generates half of the denominators as zero to represent a deferred inversion.
+        fn arb_rational()(
+            numerator in arb_element(),
+            denominator in prop_oneof![
+                1 => Just(Fp::zero()),
+                2 => arb_element(),
+            ],
+        ) -> Assigned<Fp> {
+            Assigned::Rational(numerator, denominator)
+        }
+    }
+
+    prop_compose! {
+        fn arb_operators(num_unary: usize, num_binary: usize)(
+            unary in vec(select(UNARY_OPERATORS), num_unary),
+            binary in vec(select(BINARY_OPERATORS), num_binary),
+        ) -> Vec<Operator> {
+            unary.into_iter()
+                .map(Operator::Unary)
+                .chain(binary.into_iter().map(Operator::Binary))
+                .collect()
+        }
+    }
+
+    prop_compose! {
+        fn arb_testcase()(
+            num_unary in 0usize..5,
+            num_binary in 0usize..5,
+        )(
+            values in vec(
+                prop_oneof![
+                    1 => Just(Assigned::Zero),
+                    2 => arb_trivial(),
+                    2 => arb_rational(),
+                ],
+                // Ensure that:
+                // - we have at least one value to apply unary operators to.
+                // - we can apply every binary operator pairwise sequentially.
+                cmp::max(if num_unary > 0 { 1 } else { 0 }, num_binary + 1)),
+            operations in arb_operators(num_unary, num_binary).prop_shuffle(),
+        ) -> (Vec<Assigned<Fp>>, Vec<Operator>) {
+            (values, operations)
+        }
+    }
+
+    proptest! {
+        #[test]
+        fn operation_commutativity((values, operations) in arb_testcase()) {
+            // Evaluate the values at the start.
+            let elements: Vec<_> = values.iter().cloned().map(|v| v.evaluate()).collect();
+
+            // Apply the operations to both the deferred and evaluated values.
+            fn evaluate<F: UnaryOperand + BinaryOperand>(
+                items: Vec<F>,
+                operators: &[Operator],
+            ) -> F {
+                let mut ops = operators.iter();
+
+                // Process all binary operators. We are guaranteed to have exactly as many
+                // binary operators as we need calls to the reduction closure.
+                let mut res = items.into_iter().reduce(|mut a, b| loop {
+                    match ops.next() {
+                        Some(Operator::Unary(op)) => a = op.apply(a),
+                        Some(Operator::Binary(op)) => break op.apply(a, b),
+                        None => unreachable!(),
+                    }
+                }).unwrap();
+
+                // Process any unary operators that weren't handled in the reduce() call
+                // above (either if we only had one item, or there were unary operators
+                // after the last binary operator). We are guaranteed to have no binary
+                // operators remaining at this point.
+                loop {
+                    match ops.next() {
+                        Some(Operator::Unary(op)) => res = op.apply(res),
+                        Some(Operator::Binary(_)) => unreachable!(),
+                        None => break res,
+                    }
+                }
+            }
+            let deferred_result = evaluate(values, &operations);
+            let evaluated_result = evaluate(elements, &operations);
+
+            // The two should be equal, i.e. deferred inversion should commute with the
+            // list of operations.
+            assert_eq!(deferred_result.evaluate(), evaluated_result);
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/circuit.rs.html b/docs/src/halo2_proofs/plonk/circuit.rs.html new file mode 100644 index 0000000000..9f13854417 --- /dev/null +++ b/docs/src/halo2_proofs/plonk/circuit.rs.html @@ -0,0 +1,4290 @@ +circuit.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+1723
+1724
+1725
+1726
+1727
+1728
+1729
+1730
+1731
+1732
+1733
+1734
+1735
+1736
+1737
+1738
+1739
+1740
+1741
+1742
+1743
+1744
+1745
+1746
+1747
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
+1765
+1766
+1767
+1768
+1769
+1770
+1771
+1772
+1773
+1774
+1775
+1776
+1777
+1778
+1779
+1780
+1781
+1782
+1783
+1784
+1785
+1786
+1787
+1788
+1789
+1790
+1791
+1792
+1793
+1794
+1795
+1796
+1797
+1798
+1799
+1800
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
+1818
+1819
+1820
+1821
+1822
+1823
+1824
+1825
+1826
+1827
+1828
+1829
+1830
+1831
+1832
+1833
+1834
+1835
+1836
+1837
+1838
+1839
+1840
+1841
+1842
+1843
+1844
+1845
+1846
+1847
+1848
+1849
+1850
+1851
+1852
+1853
+1854
+1855
+1856
+1857
+1858
+1859
+1860
+1861
+1862
+1863
+1864
+1865
+1866
+1867
+1868
+1869
+1870
+1871
+1872
+1873
+1874
+1875
+1876
+1877
+1878
+1879
+1880
+1881
+1882
+1883
+1884
+1885
+1886
+1887
+1888
+1889
+1890
+1891
+1892
+1893
+1894
+1895
+1896
+1897
+1898
+1899
+1900
+1901
+1902
+1903
+1904
+1905
+1906
+1907
+1908
+1909
+1910
+1911
+1912
+1913
+1914
+1915
+1916
+1917
+1918
+1919
+1920
+1921
+1922
+1923
+1924
+1925
+1926
+1927
+1928
+1929
+1930
+1931
+1932
+1933
+1934
+1935
+1936
+1937
+1938
+1939
+1940
+1941
+1942
+1943
+1944
+1945
+1946
+1947
+1948
+1949
+1950
+1951
+1952
+1953
+1954
+1955
+1956
+1957
+1958
+1959
+1960
+1961
+1962
+1963
+1964
+1965
+1966
+1967
+1968
+1969
+1970
+1971
+1972
+1973
+1974
+1975
+1976
+1977
+1978
+1979
+1980
+1981
+1982
+1983
+1984
+1985
+1986
+1987
+1988
+1989
+1990
+1991
+1992
+1993
+1994
+1995
+1996
+1997
+1998
+1999
+2000
+2001
+2002
+2003
+2004
+2005
+2006
+2007
+2008
+2009
+2010
+2011
+2012
+2013
+2014
+2015
+2016
+2017
+2018
+2019
+2020
+2021
+2022
+2023
+2024
+2025
+2026
+2027
+2028
+2029
+2030
+2031
+2032
+2033
+2034
+2035
+2036
+2037
+2038
+2039
+2040
+2041
+2042
+2043
+2044
+2045
+2046
+2047
+2048
+2049
+2050
+2051
+2052
+2053
+2054
+2055
+2056
+2057
+2058
+2059
+2060
+2061
+2062
+2063
+2064
+2065
+2066
+2067
+2068
+2069
+2070
+2071
+2072
+2073
+2074
+2075
+2076
+2077
+2078
+2079
+2080
+2081
+2082
+2083
+2084
+2085
+2086
+2087
+2088
+2089
+2090
+2091
+2092
+2093
+2094
+2095
+2096
+2097
+2098
+2099
+2100
+2101
+2102
+2103
+2104
+2105
+2106
+2107
+2108
+2109
+2110
+2111
+2112
+2113
+2114
+2115
+2116
+2117
+2118
+2119
+2120
+2121
+2122
+2123
+2124
+2125
+2126
+2127
+2128
+2129
+2130
+2131
+2132
+2133
+2134
+2135
+2136
+2137
+2138
+2139
+2140
+2141
+2142
+2143
+2144
+
use core::cmp::max;
+use core::ops::{Add, Mul};
+use ff::Field;
+use std::{
+    convert::TryFrom,
+    ops::{Neg, Sub},
+};
+
+use super::{lookup, permutation, Assigned, Error};
+use crate::{
+    circuit::{Layouter, Region, Value},
+    poly::Rotation,
+};
+use sealed::SealedPhase;
+
+mod compress_selectors;
+
+/// A column type
+pub trait ColumnType:
+    'static + Sized + Copy + std::fmt::Debug + PartialEq + Eq + Into<Any>
+{
+}
+
+/// A column with an index and type
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+pub struct Column<C: ColumnType> {
+    index: usize,
+    column_type: C,
+}
+
+impl<C: ColumnType> Column<C> {
+    #[cfg(test)]
+    pub(crate) fn new(index: usize, column_type: C) -> Self {
+        Column { index, column_type }
+    }
+
+    /// Index of this column.
+    pub fn index(&self) -> usize {
+        self.index
+    }
+
+    /// Type of this column.
+    pub fn column_type(&self) -> &C {
+        &self.column_type
+    }
+}
+
+impl<C: ColumnType> Ord for Column<C> {
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        // This ordering is consensus-critical! The layouters rely on deterministic column
+        // orderings.
+        match self.column_type.into().cmp(&other.column_type.into()) {
+            // Indices are assigned within column types.
+            std::cmp::Ordering::Equal => self.index.cmp(&other.index),
+            order => order,
+        }
+    }
+}
+
+impl<C: ColumnType> PartialOrd for Column<C> {
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+pub(crate) mod sealed {
+    use std::ops::Add;
+
+    /// Phase of advice column
+    #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+    pub struct Phase(pub(super) u8);
+
+    impl Phase {
+        pub fn prev(&self) -> Option<Phase> {
+            self.0.checked_sub(1).map(Phase)
+        }
+        pub fn next(&self) -> Phase {
+            assert!(self.0 < 2, "The API only supports three phases");
+            Phase(self.0 + 1)
+        }
+        pub fn to_u8(&self) -> u8 {
+            self.0
+        }
+    }
+
+    /// Sealed trait to help keep `Phase` private.
+    pub trait SealedPhase {
+        fn to_sealed(self) -> Phase;
+    }
+}
+
+/// Phase of advice column
+pub trait Phase: SealedPhase {}
+
+impl<P: SealedPhase> Phase for P {}
+
+/// First phase
+#[derive(Debug)]
+pub struct FirstPhase;
+
+impl SealedPhase for super::FirstPhase {
+    fn to_sealed(self) -> sealed::Phase {
+        sealed::Phase(0)
+    }
+}
+
+/// Second phase
+#[derive(Debug)]
+pub struct SecondPhase;
+
+impl SealedPhase for super::SecondPhase {
+    fn to_sealed(self) -> sealed::Phase {
+        sealed::Phase(1)
+    }
+}
+
+/// Third phase
+#[derive(Debug)]
+pub struct ThirdPhase;
+
+impl SealedPhase for super::ThirdPhase {
+    fn to_sealed(self) -> sealed::Phase {
+        sealed::Phase(2)
+    }
+}
+
+/// An advice column
+#[derive(Clone, Copy, Eq, PartialEq, Hash)]
+pub struct Advice {
+    pub(crate) phase: sealed::Phase,
+}
+
+impl Default for Advice {
+    fn default() -> Advice {
+        Advice {
+            phase: FirstPhase.to_sealed(),
+        }
+    }
+}
+
+impl Advice {
+    /// Returns `Advice` in given `Phase`
+    pub fn new<P: Phase>(phase: P) -> Advice {
+        Advice {
+            phase: phase.to_sealed(),
+        }
+    }
+
+    /// Phase of this column
+    pub fn phase(&self) -> u8 {
+        self.phase.0
+    }
+}
+
+impl std::fmt::Debug for Advice {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let mut debug_struct = f.debug_struct("Advice");
+        // Only show advice's phase if it's not in first phase.
+        if self.phase != FirstPhase.to_sealed() {
+            debug_struct.field("phase", &self.phase);
+        }
+        debug_struct.finish()
+    }
+}
+
+/// A fixed column
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+pub struct Fixed;
+
+/// An instance column
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+pub struct Instance;
+
+/// An enum over the Advice, Fixed, Instance structs
+#[derive(Clone, Copy, Eq, PartialEq, Hash)]
+pub enum Any {
+    /// An Advice variant
+    Advice(Advice),
+    /// A Fixed variant
+    Fixed,
+    /// An Instance variant
+    Instance,
+}
+
+impl Any {
+    /// Returns Advice variant in `FirstPhase`
+    pub fn advice() -> Any {
+        Any::Advice(Advice::default())
+    }
+
+    /// Returns Advice variant in given `Phase`
+    pub fn advice_in<P: Phase>(phase: P) -> Any {
+        Any::Advice(Advice::new(phase))
+    }
+}
+
+impl std::fmt::Debug for Any {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Any::Advice(advice) => {
+                let mut debug_struct = f.debug_struct("Advice");
+                // Only show advice's phase if it's not in first phase.
+                if advice.phase != FirstPhase.to_sealed() {
+                    debug_struct.field("phase", &advice.phase);
+                }
+                debug_struct.finish()
+            }
+            Any::Fixed => f.debug_struct("Fixed").finish(),
+            Any::Instance => f.debug_struct("Instance").finish(),
+        }
+    }
+}
+
+impl Ord for Any {
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        // This ordering is consensus-critical! The layouters rely on deterministic column
+        // orderings.
+        match (self, other) {
+            (Any::Instance, Any::Instance) | (Any::Fixed, Any::Fixed) => std::cmp::Ordering::Equal,
+            (Any::Advice(lhs), Any::Advice(rhs)) => lhs.phase.cmp(&rhs.phase),
+            // Across column types, sort Instance < Advice < Fixed.
+            (Any::Instance, Any::Advice(_))
+            | (Any::Advice(_), Any::Fixed)
+            | (Any::Instance, Any::Fixed) => std::cmp::Ordering::Less,
+            (Any::Fixed, Any::Instance)
+            | (Any::Fixed, Any::Advice(_))
+            | (Any::Advice(_), Any::Instance) => std::cmp::Ordering::Greater,
+        }
+    }
+}
+
+impl PartialOrd for Any {
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl ColumnType for Advice {}
+impl ColumnType for Fixed {}
+impl ColumnType for Instance {}
+impl ColumnType for Any {}
+
+impl From<Advice> for Any {
+    fn from(advice: Advice) -> Any {
+        Any::Advice(advice)
+    }
+}
+
+impl From<Fixed> for Any {
+    fn from(_: Fixed) -> Any {
+        Any::Fixed
+    }
+}
+
+impl From<Instance> for Any {
+    fn from(_: Instance) -> Any {
+        Any::Instance
+    }
+}
+
+impl From<Column<Advice>> for Column<Any> {
+    fn from(advice: Column<Advice>) -> Column<Any> {
+        Column {
+            index: advice.index(),
+            column_type: Any::Advice(advice.column_type),
+        }
+    }
+}
+
+impl From<Column<Fixed>> for Column<Any> {
+    fn from(advice: Column<Fixed>) -> Column<Any> {
+        Column {
+            index: advice.index(),
+            column_type: Any::Fixed,
+        }
+    }
+}
+
+impl From<Column<Instance>> for Column<Any> {
+    fn from(advice: Column<Instance>) -> Column<Any> {
+        Column {
+            index: advice.index(),
+            column_type: Any::Instance,
+        }
+    }
+}
+
+impl TryFrom<Column<Any>> for Column<Advice> {
+    type Error = &'static str;
+
+    fn try_from(any: Column<Any>) -> Result<Self, Self::Error> {
+        match any.column_type() {
+            Any::Advice(advice) => Ok(Column {
+                index: any.index(),
+                column_type: *advice,
+            }),
+            _ => Err("Cannot convert into Column<Advice>"),
+        }
+    }
+}
+
+impl TryFrom<Column<Any>> for Column<Fixed> {
+    type Error = &'static str;
+
+    fn try_from(any: Column<Any>) -> Result<Self, Self::Error> {
+        match any.column_type() {
+            Any::Fixed => Ok(Column {
+                index: any.index(),
+                column_type: Fixed,
+            }),
+            _ => Err("Cannot convert into Column<Fixed>"),
+        }
+    }
+}
+
+impl TryFrom<Column<Any>> for Column<Instance> {
+    type Error = &'static str;
+
+    fn try_from(any: Column<Any>) -> Result<Self, Self::Error> {
+        match any.column_type() {
+            Any::Instance => Ok(Column {
+                index: any.index(),
+                column_type: Instance,
+            }),
+            _ => Err("Cannot convert into Column<Instance>"),
+        }
+    }
+}
+
+/// A selector, representing a fixed boolean value per row of the circuit.
+///
+/// Selectors can be used to conditionally enable (portions of) gates:
+/// ```
+/// use halo2_proofs::poly::Rotation;
+/// # use halo2curves::pasta::Fp;
+/// # use halo2_proofs::plonk::ConstraintSystem;
+///
+/// # let mut meta = ConstraintSystem::<Fp>::default();
+/// let a = meta.advice_column();
+/// let b = meta.advice_column();
+/// let s = meta.selector();
+///
+/// meta.create_gate("foo", |meta| {
+///     let a = meta.query_advice(a, Rotation::prev());
+///     let b = meta.query_advice(b, Rotation::cur());
+///     let s = meta.query_selector(s);
+///
+///     // On rows where the selector is enabled, a is constrained to equal b.
+///     // On rows where the selector is disabled, a and b can take any value.
+///     vec![s * (a - b)]
+/// });
+/// ```
+///
+/// Selectors are disabled on all rows by default, and must be explicitly enabled on each
+/// row when required:
+/// ```
+/// use halo2_proofs::{
+///     arithmetic::FieldExt,
+///     circuit::{Chip, Layouter, Value},
+///     plonk::{Advice, Column, Error, Selector},
+/// };
+/// # use ff::Field;
+/// # use halo2_proofs::plonk::Fixed;
+///
+/// struct Config {
+///     a: Column<Advice>,
+///     b: Column<Advice>,
+///     s: Selector,
+/// }
+///
+/// fn circuit_logic<F: FieldExt, C: Chip<F>>(chip: C, mut layouter: impl Layouter<F>) -> Result<(), Error> {
+///     let config = chip.config();
+///     # let config: Config = todo!();
+///     layouter.assign_region(|| "bar", |mut region| {
+///         region.assign_advice(|| "a", config.a, 0, || Value::known(F::one()))?;
+///         region.assign_advice(|| "a", config.b, 1, || Value::known(F::one()))?;
+///         config.s.enable(&mut region, 1)
+///     })?;
+///     Ok(())
+/// }
+/// ```
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct Selector(pub(crate) usize, bool);
+
+impl Selector {
+    /// Enable this selector at the given offset within the given region.
+    pub fn enable<F: Field>(&self, region: &mut Region<F>, offset: usize) -> Result<(), Error> {
+        region.enable_selector(|| "", self, offset)
+    }
+
+    /// Is this selector "simple"? Simple selectors can only be multiplied
+    /// by expressions that contain no other simple selectors.
+    pub fn is_simple(&self) -> bool {
+        self.1
+    }
+}
+
+/// Query of fixed column at a certain relative location
+#[derive(Copy, Clone, Debug)]
+pub struct FixedQuery {
+    /// Query index
+    pub(crate) index: usize,
+    /// Column index
+    pub(crate) column_index: usize,
+    /// Rotation of this query
+    pub(crate) rotation: Rotation,
+}
+
+impl FixedQuery {
+    /// Column index
+    pub fn column_index(&self) -> usize {
+        self.column_index
+    }
+
+    /// Rotation of this query
+    pub fn rotation(&self) -> Rotation {
+        self.rotation
+    }
+}
+
+/// Query of advice column at a certain relative location
+#[derive(Copy, Clone, Debug)]
+pub struct AdviceQuery {
+    /// Query index
+    pub(crate) index: usize,
+    /// Column index
+    pub(crate) column_index: usize,
+    /// Rotation of this query
+    pub(crate) rotation: Rotation,
+    /// Phase of this advice column
+    pub(crate) phase: sealed::Phase,
+}
+
+impl AdviceQuery {
+    /// Column index
+    pub fn column_index(&self) -> usize {
+        self.column_index
+    }
+
+    /// Rotation of this query
+    pub fn rotation(&self) -> Rotation {
+        self.rotation
+    }
+
+    /// Phase of this advice column
+    pub fn phase(&self) -> u8 {
+        self.phase.0
+    }
+}
+
+/// Query of instance column at a certain relative location
+#[derive(Copy, Clone, Debug)]
+pub struct InstanceQuery {
+    /// Query index
+    pub(crate) index: usize,
+    /// Column index
+    pub(crate) column_index: usize,
+    /// Rotation of this query
+    pub(crate) rotation: Rotation,
+}
+
+impl InstanceQuery {
+    /// Column index
+    pub fn column_index(&self) -> usize {
+        self.column_index
+    }
+
+    /// Rotation of this query
+    pub fn rotation(&self) -> Rotation {
+        self.rotation
+    }
+}
+
+/// A fixed column of a lookup table.
+///
+/// A lookup table can be loaded into this column via [`Layouter::assign_table`]. Columns
+/// can currently only contain a single table, but they may be used in multiple lookup
+/// arguments via [`ConstraintSystem::lookup`].
+///
+/// Lookup table columns are always "encumbered" by the lookup arguments they are used in;
+/// they cannot simultaneously be used as general fixed columns.
+///
+/// [`Layouter::assign_table`]: crate::circuit::Layouter::assign_table
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+pub struct TableColumn {
+    /// The fixed column that this table column is stored in.
+    ///
+    /// # Security
+    ///
+    /// This inner column MUST NOT be exposed in the public API, or else chip developers
+    /// can load lookup tables into their circuits without default-value-filling the
+    /// columns, which can cause soundness bugs.
+    inner: Column<Fixed>,
+}
+
+impl TableColumn {
+    pub(crate) fn inner(&self) -> Column<Fixed> {
+        self.inner
+    }
+}
+
+/// A challenge squeezed from transcript after advice columns at the phase have been committed.
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
+pub struct Challenge {
+    index: usize,
+    phase: sealed::Phase,
+}
+
+impl Challenge {
+    /// Index of this challenge.
+    pub fn index(&self) -> usize {
+        self.index
+    }
+
+    /// Phase of this challenge.
+    pub fn phase(&self) -> u8 {
+        self.phase.0
+    }
+}
+
+/// This trait allows a [`Circuit`] to direct some backend to assign a witness
+/// for a constraint system.
+pub trait Assignment<F: Field> {
+    /// Creates a new region and enters into it.
+    ///
+    /// Panics if we are currently in a region (if `exit_region` was not called).
+    ///
+    /// Not intended for downstream consumption; use [`Layouter::assign_region`] instead.
+    ///
+    /// [`Layouter::assign_region`]: crate::circuit::Layouter#method.assign_region
+    fn enter_region<NR, N>(&mut self, name_fn: N)
+    where
+        NR: Into<String>,
+        N: FnOnce() -> NR;
+
+    /// Exits the current region.
+    ///
+    /// Panics if we are not currently in a region (if `enter_region` was not called).
+    ///
+    /// Not intended for downstream consumption; use [`Layouter::assign_region`] instead.
+    ///
+    /// [`Layouter::assign_region`]: crate::circuit::Layouter#method.assign_region
+    fn exit_region(&mut self);
+
+    /// Enables a selector at the given row.
+    fn enable_selector<A, AR>(
+        &mut self,
+        annotation: A,
+        selector: &Selector,
+        row: usize,
+    ) -> Result<(), Error>
+    where
+        A: FnOnce() -> AR,
+        AR: Into<String>;
+
+    /// Queries the cell of an instance column at a particular absolute row.
+    ///
+    /// Returns the cell's value, if known.
+    fn query_instance(&self, column: Column<Instance>, row: usize) -> Result<Value<F>, Error>;
+
+    /// Assign an advice column value (witness)
+    fn assign_advice<'r, 'v>(
+        //<V, VR, A, AR>(
+        &'r mut self,
+        // annotation: A,
+        column: Column<Advice>,
+        row: usize,
+        to: Value<Assigned<F>>, // V,
+    ) -> Result<Value<&'v Assigned<F>>, Error>;
+    // where
+    // V: FnOnce() -> Value<VR>,
+    // VR: Into<Assigned<F>>,
+    // A: FnOnce() -> AR,
+    // AR: Into<String>;
+
+    /// Assign a fixed value
+    fn assign_fixed(&mut self, column: Column<Fixed>, row: usize, to: Assigned<F>);
+
+    /// Assign two cells to have the same value
+    fn copy(
+        &mut self,
+        left_column: Column<Any>,
+        left_row: usize,
+        right_column: Column<Any>,
+        right_row: usize,
+    );
+
+    /// Fills a fixed `column` starting from the given `row` with value `to`.
+    fn fill_from_row(
+        &mut self,
+        column: Column<Fixed>,
+        row: usize,
+        to: Value<Assigned<F>>,
+    ) -> Result<(), Error>;
+
+    /// Queries the value of the given challenge.
+    ///
+    /// Returns `Value::unknown()` if the current synthesis phase is before the challenge can be queried.
+    fn get_challenge(&self, challenge: Challenge) -> Value<F>;
+
+    /// Creates a new (sub)namespace and enters into it.
+    ///
+    /// Not intended for downstream consumption; use [`Layouter::namespace`] instead.
+    ///
+    /// [`Layouter::namespace`]: crate::circuit::Layouter#method.namespace
+    fn push_namespace<NR, N>(&mut self, name_fn: N)
+    where
+        NR: Into<String>,
+        N: FnOnce() -> NR;
+
+    /// Exits out of the existing namespace.
+    ///
+    /// Not intended for downstream consumption; use [`Layouter::namespace`] instead.
+    ///
+    /// [`Layouter::namespace`]: crate::circuit::Layouter#method.namespace
+    fn pop_namespace(&mut self, gadget_name: Option<String>);
+
+    /// Commit advice columns in current phase and squeeze challenges. This can be
+    /// called DURING synthesize.
+    fn next_phase(&mut self) {}
+}
+
+/// A floor planning strategy for a circuit.
+///
+/// The floor planner is chip-agnostic and applies its strategy to the circuit it is used
+/// within.
+pub trait FloorPlanner {
+    /// Given the provided `cs`, synthesize the given circuit.
+    ///
+    /// `constants` is the list of fixed columns that the layouter may use to assign
+    /// global constant values. These columns will all have been equality-enabled.
+    ///
+    /// Internally, a floor planner will perform the following operations:
+    /// - Instantiate a [`Layouter`] for this floor planner.
+    /// - Perform any necessary setup or measurement tasks, which may involve one or more
+    ///   calls to `Circuit::default().synthesize(config, &mut layouter)`.
+    /// - Call `circuit.synthesize(config, &mut layouter)` exactly once.
+    fn synthesize<F: Field, CS: Assignment<F>, C: Circuit<F>>(
+        cs: &mut CS,
+        circuit: &C,
+        config: C::Config,
+        constants: Vec<Column<Fixed>>,
+    ) -> Result<(), Error>;
+}
+
+/// This is a trait that circuits provide implementations for so that the
+/// backend prover can ask the circuit to synthesize using some given
+/// [`ConstraintSystem`] implementation.
+pub trait Circuit<F: Field> {
+    /// This is a configuration object that stores things like columns.
+    type Config: Clone;
+    /// The floor planner used for this circuit. This is an associated type of the
+    /// `Circuit` trait because its behaviour is circuit-critical.
+    type FloorPlanner: FloorPlanner;
+
+    /// Returns a copy of this circuit with no witness values (i.e. all witnesses set to
+    /// `None`). For most circuits, this will be equal to `Self::default()`.
+    fn without_witnesses(&self) -> Self;
+
+    /// The circuit is given an opportunity to describe the exact gate
+    /// arrangement, column arrangement, etc.
+    fn configure(meta: &mut ConstraintSystem<F>) -> Self::Config;
+
+    /// Given the provided `cs`, synthesize the circuit. The concrete type of
+    /// the caller will be different depending on the context, and they may or
+    /// may not expect to have a witness present.
+    fn synthesize(&self, config: Self::Config, layouter: impl Layouter<F>) -> Result<(), Error>;
+}
+
+/// Low-degree expression representing an identity that must hold over the committed columns.
+#[derive(Clone)]
+pub enum Expression<F> {
+    /// This is a constant polynomial
+    Constant(F),
+    /// This is a virtual selector
+    Selector(Selector),
+    /// This is a fixed column queried at a certain relative location
+    Fixed(FixedQuery),
+    /// This is an advice (witness) column queried at a certain relative location
+    Advice(AdviceQuery),
+    /// This is an instance (external) column queried at a certain relative location
+    Instance(InstanceQuery),
+    /// This is a challenge
+    Challenge(Challenge),
+    /// This is a negated polynomial
+    Negated(Box<Expression<F>>),
+    /// This is the sum of two polynomials
+    Sum(Box<Expression<F>>, Box<Expression<F>>),
+    /// This is the product of two polynomials
+    Product(Box<Expression<F>>, Box<Expression<F>>),
+    /// This is a scaled polynomial
+    Scaled(Box<Expression<F>>, F),
+}
+
+impl<F: Field> Expression<F> {
+    /// Evaluate the polynomial using the provided closures to perform the
+    /// operations.
+    pub fn evaluate<T>(
+        &self,
+        constant: &impl Fn(F) -> T,
+        selector_column: &impl Fn(Selector) -> T,
+        fixed_column: &impl Fn(FixedQuery) -> T,
+        advice_column: &impl Fn(AdviceQuery) -> T,
+        instance_column: &impl Fn(InstanceQuery) -> T,
+        challenge: &impl Fn(Challenge) -> T,
+        negated: &impl Fn(T) -> T,
+        sum: &impl Fn(T, T) -> T,
+        product: &impl Fn(T, T) -> T,
+        scaled: &impl Fn(T, F) -> T,
+    ) -> T {
+        match self {
+            Expression::Constant(scalar) => constant(*scalar),
+            Expression::Selector(selector) => selector_column(*selector),
+            Expression::Fixed(query) => fixed_column(*query),
+            Expression::Advice(query) => advice_column(*query),
+            Expression::Instance(query) => instance_column(*query),
+            Expression::Challenge(value) => challenge(*value),
+            Expression::Negated(a) => {
+                let a = a.evaluate(
+                    constant,
+                    selector_column,
+                    fixed_column,
+                    advice_column,
+                    instance_column,
+                    challenge,
+                    negated,
+                    sum,
+                    product,
+                    scaled,
+                );
+                negated(a)
+            }
+            Expression::Sum(a, b) => {
+                let a = a.evaluate(
+                    constant,
+                    selector_column,
+                    fixed_column,
+                    advice_column,
+                    instance_column,
+                    challenge,
+                    negated,
+                    sum,
+                    product,
+                    scaled,
+                );
+                let b = b.evaluate(
+                    constant,
+                    selector_column,
+                    fixed_column,
+                    advice_column,
+                    instance_column,
+                    challenge,
+                    negated,
+                    sum,
+                    product,
+                    scaled,
+                );
+                sum(a, b)
+            }
+            Expression::Product(a, b) => {
+                let a = a.evaluate(
+                    constant,
+                    selector_column,
+                    fixed_column,
+                    advice_column,
+                    instance_column,
+                    challenge,
+                    negated,
+                    sum,
+                    product,
+                    scaled,
+                );
+                let b = b.evaluate(
+                    constant,
+                    selector_column,
+                    fixed_column,
+                    advice_column,
+                    instance_column,
+                    challenge,
+                    negated,
+                    sum,
+                    product,
+                    scaled,
+                );
+                product(a, b)
+            }
+            Expression::Scaled(a, f) => {
+                let a = a.evaluate(
+                    constant,
+                    selector_column,
+                    fixed_column,
+                    advice_column,
+                    instance_column,
+                    challenge,
+                    negated,
+                    sum,
+                    product,
+                    scaled,
+                );
+                scaled(a, *f)
+            }
+        }
+    }
+
+    /// Evaluate the polynomial lazily using the provided closures to perform the
+    /// operations.
+    pub fn evaluate_lazy<T: PartialEq>(
+        &self,
+        constant: &impl Fn(F) -> T,
+        selector_column: &impl Fn(Selector) -> T,
+        fixed_column: &impl Fn(FixedQuery) -> T,
+        advice_column: &impl Fn(AdviceQuery) -> T,
+        instance_column: &impl Fn(InstanceQuery) -> T,
+        challenge: &impl Fn(Challenge) -> T,
+        negated: &impl Fn(T) -> T,
+        sum: &impl Fn(T, T) -> T,
+        product: &impl Fn(T, T) -> T,
+        scaled: &impl Fn(T, F) -> T,
+        zero: &T,
+    ) -> T {
+        match self {
+            Expression::Constant(scalar) => constant(*scalar),
+            Expression::Selector(selector) => selector_column(*selector),
+            Expression::Fixed(query) => fixed_column(*query),
+            Expression::Advice(query) => advice_column(*query),
+            Expression::Instance(query) => instance_column(*query),
+            Expression::Challenge(value) => challenge(*value),
+            Expression::Negated(a) => {
+                let a = a.evaluate_lazy(
+                    constant,
+                    selector_column,
+                    fixed_column,
+                    advice_column,
+                    instance_column,
+                    challenge,
+                    negated,
+                    sum,
+                    product,
+                    scaled,
+                    zero,
+                );
+                negated(a)
+            }
+            Expression::Sum(a, b) => {
+                let a = a.evaluate_lazy(
+                    constant,
+                    selector_column,
+                    fixed_column,
+                    advice_column,
+                    instance_column,
+                    challenge,
+                    negated,
+                    sum,
+                    product,
+                    scaled,
+                    zero,
+                );
+                let b = b.evaluate_lazy(
+                    constant,
+                    selector_column,
+                    fixed_column,
+                    advice_column,
+                    instance_column,
+                    challenge,
+                    negated,
+                    sum,
+                    product,
+                    scaled,
+                    zero,
+                );
+                sum(a, b)
+            }
+            Expression::Product(a, b) => {
+                let (a, b) = if a.complexity() <= b.complexity() {
+                    (a, b)
+                } else {
+                    (b, a)
+                };
+                let a = a.evaluate_lazy(
+                    constant,
+                    selector_column,
+                    fixed_column,
+                    advice_column,
+                    instance_column,
+                    challenge,
+                    negated,
+                    sum,
+                    product,
+                    scaled,
+                    zero,
+                );
+
+                if a == *zero {
+                    a
+                } else {
+                    let b = b.evaluate_lazy(
+                        constant,
+                        selector_column,
+                        fixed_column,
+                        advice_column,
+                        instance_column,
+                        challenge,
+                        negated,
+                        sum,
+                        product,
+                        scaled,
+                        zero,
+                    );
+                    product(a, b)
+                }
+            }
+            Expression::Scaled(a, f) => {
+                let a = a.evaluate_lazy(
+                    constant,
+                    selector_column,
+                    fixed_column,
+                    advice_column,
+                    instance_column,
+                    challenge,
+                    negated,
+                    sum,
+                    product,
+                    scaled,
+                    zero,
+                );
+                scaled(a, *f)
+            }
+        }
+    }
+
+    fn write_identifier<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
+        match self {
+            Expression::Constant(scalar) => write!(writer, "{:?}", scalar),
+            Expression::Selector(selector) => write!(writer, "selector[{}]", selector.0),
+            Expression::Fixed(query) => {
+                write!(
+                    writer,
+                    "fixed[{}][{}]",
+                    query.column_index, query.rotation.0
+                )
+            }
+            Expression::Advice(query) => {
+                write!(
+                    writer,
+                    "advice[{}][{}]",
+                    query.column_index, query.rotation.0
+                )
+            }
+            Expression::Instance(query) => {
+                write!(
+                    writer,
+                    "instance[{}][{}]",
+                    query.column_index, query.rotation.0
+                )
+            }
+            Expression::Challenge(challenge) => {
+                write!(writer, "challenge[{}]", challenge.index())
+            }
+            Expression::Negated(a) => {
+                writer.write_all(b"(-")?;
+                a.write_identifier(writer)?;
+                writer.write_all(b")")
+            }
+            Expression::Sum(a, b) => {
+                writer.write_all(b"(")?;
+                a.write_identifier(writer)?;
+                writer.write_all(b"+")?;
+                b.write_identifier(writer)?;
+                writer.write_all(b")")
+            }
+            Expression::Product(a, b) => {
+                writer.write_all(b"(")?;
+                a.write_identifier(writer)?;
+                writer.write_all(b"*")?;
+                b.write_identifier(writer)?;
+                writer.write_all(b")")
+            }
+            Expression::Scaled(a, f) => {
+                a.write_identifier(writer)?;
+                write!(writer, "*{:?}", f)
+            }
+        }
+    }
+
+    /// Identifier for this expression. Expressions with identical identifiers
+    /// do the same calculation (but the expressions don't need to be exactly equal
+    /// in how they are composed e.g. `1 + 2` and `2 + 1` can have the same identifier).
+    pub fn identifier(&self) -> String {
+        let mut cursor = std::io::Cursor::new(Vec::new());
+        self.write_identifier(&mut cursor).unwrap();
+        String::from_utf8(cursor.into_inner()).unwrap()
+    }
+
+    /// Compute the degree of this polynomial
+    pub fn degree(&self) -> usize {
+        match self {
+            Expression::Constant(_) => 0,
+            Expression::Selector(_) => 1,
+            Expression::Fixed(_) => 1,
+            Expression::Advice(_) => 1,
+            Expression::Instance(_) => 1,
+            Expression::Challenge(_) => 0,
+            Expression::Negated(poly) => poly.degree(),
+            Expression::Sum(a, b) => max(a.degree(), b.degree()),
+            Expression::Product(a, b) => a.degree() + b.degree(),
+            Expression::Scaled(poly, _) => poly.degree(),
+        }
+    }
+
+    /// Approximate the computational complexity of this expression.
+    pub fn complexity(&self) -> usize {
+        match self {
+            Expression::Constant(_) => 0,
+            Expression::Selector(_) => 1,
+            Expression::Fixed(_) => 1,
+            Expression::Advice(_) => 1,
+            Expression::Instance(_) => 1,
+            Expression::Challenge(_) => 0,
+            Expression::Negated(poly) => poly.complexity() + 5,
+            Expression::Sum(a, b) => a.complexity() + b.complexity() + 15,
+            Expression::Product(a, b) => a.complexity() + b.complexity() + 30,
+            Expression::Scaled(poly, _) => poly.complexity() + 30,
+        }
+    }
+
+    /// Square this expression.
+    pub fn square(self) -> Self {
+        self.clone() * self
+    }
+
+    /// Returns whether or not this expression contains a simple `Selector`.
+    fn contains_simple_selector(&self) -> bool {
+        self.evaluate(
+            &|_| false,
+            &|selector| selector.is_simple(),
+            &|_| false,
+            &|_| false,
+            &|_| false,
+            &|_| false,
+            &|a| a,
+            &|a, b| a || b,
+            &|a, b| a || b,
+            &|a, _| a,
+        )
+    }
+
+    /// Extracts a simple selector from this gate, if present
+    fn extract_simple_selector(&self) -> Option<Selector> {
+        let op = |a, b| match (a, b) {
+            (Some(a), None) | (None, Some(a)) => Some(a),
+            (Some(_), Some(_)) => panic!("two simple selectors cannot be in the same expression"),
+            _ => None,
+        };
+
+        self.evaluate(
+            &|_| None,
+            &|selector| {
+                if selector.is_simple() {
+                    Some(selector)
+                } else {
+                    None
+                }
+            },
+            &|_| None,
+            &|_| None,
+            &|_| None,
+            &|_| None,
+            &|a| a,
+            &op,
+            &op,
+            &|a, _| a,
+        )
+    }
+}
+
+impl<F: std::fmt::Debug> std::fmt::Debug for Expression<F> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        match self {
+            Expression::Constant(scalar) => f.debug_tuple("Constant").field(scalar).finish(),
+            Expression::Selector(selector) => f.debug_tuple("Selector").field(selector).finish(),
+            // Skip enum variant and print query struct directly to maintain backwards compatibility.
+            Expression::Fixed(FixedQuery {
+                index,
+                column_index,
+                rotation,
+            }) => f
+                .debug_struct("Fixed")
+                .field("query_index", index)
+                .field("column_index", column_index)
+                .field("rotation", rotation)
+                .finish(),
+            Expression::Advice(AdviceQuery {
+                index,
+                column_index,
+                rotation,
+                phase,
+            }) => {
+                let mut debug_struct = f.debug_struct("Advice");
+                debug_struct
+                    .field("query_index", index)
+                    .field("column_index", column_index)
+                    .field("rotation", rotation);
+                // Only show advice's phase if it's not in first phase.
+                if *phase != FirstPhase.to_sealed() {
+                    debug_struct.field("phase", phase);
+                }
+                debug_struct.finish()
+            }
+            Expression::Instance(InstanceQuery {
+                index,
+                column_index,
+                rotation,
+            }) => f
+                .debug_struct("Instance")
+                .field("query_index", index)
+                .field("column_index", column_index)
+                .field("rotation", rotation)
+                .finish(),
+            Expression::Challenge(challenge) => {
+                f.debug_tuple("Challenge").field(challenge).finish()
+            }
+            Expression::Negated(poly) => f.debug_tuple("Negated").field(poly).finish(),
+            Expression::Sum(a, b) => f.debug_tuple("Sum").field(a).field(b).finish(),
+            Expression::Product(a, b) => f.debug_tuple("Product").field(a).field(b).finish(),
+            Expression::Scaled(poly, scalar) => {
+                f.debug_tuple("Scaled").field(poly).field(scalar).finish()
+            }
+        }
+    }
+}
+
+impl<F: Field> Neg for Expression<F> {
+    type Output = Expression<F>;
+    fn neg(self) -> Self::Output {
+        Expression::Negated(Box::new(self))
+    }
+}
+
+impl<F: Field> Add for Expression<F> {
+    type Output = Expression<F>;
+    fn add(self, rhs: Expression<F>) -> Expression<F> {
+        if self.contains_simple_selector() || rhs.contains_simple_selector() {
+            panic!("attempted to use a simple selector in an addition");
+        }
+        Expression::Sum(Box::new(self), Box::new(rhs))
+    }
+}
+
+impl<F: Field> Sub for Expression<F> {
+    type Output = Expression<F>;
+    fn sub(self, rhs: Expression<F>) -> Expression<F> {
+        if self.contains_simple_selector() || rhs.contains_simple_selector() {
+            panic!("attempted to use a simple selector in a subtraction");
+        }
+        Expression::Sum(Box::new(self), Box::new(-rhs))
+    }
+}
+
+impl<F: Field> Mul for Expression<F> {
+    type Output = Expression<F>;
+    fn mul(self, rhs: Expression<F>) -> Expression<F> {
+        if self.contains_simple_selector() && rhs.contains_simple_selector() {
+            panic!("attempted to multiply two expressions containing simple selectors");
+        }
+        Expression::Product(Box::new(self), Box::new(rhs))
+    }
+}
+
+impl<F: Field> Mul<F> for Expression<F> {
+    type Output = Expression<F>;
+    fn mul(self, rhs: F) -> Expression<F> {
+        Expression::Scaled(Box::new(self), rhs)
+    }
+}
+
+/// Represents an index into a vector where each entry corresponds to a distinct
+/// point that polynomials are queried at.
+#[derive(Copy, Clone, Debug)]
+pub(crate) struct PointIndex(pub usize);
+
+/// A "virtual cell" is a PLONK cell that has been queried at a particular relative offset
+/// within a custom gate.
+#[derive(Clone, Debug)]
+pub struct VirtualCell {
+    pub(crate) column: Column<Any>,
+    pub(crate) rotation: Rotation,
+}
+
+impl<Col: Into<Column<Any>>> From<(Col, Rotation)> for VirtualCell {
+    fn from((column, rotation): (Col, Rotation)) -> Self {
+        VirtualCell {
+            column: column.into(),
+            rotation,
+        }
+    }
+}
+
+/// An individual polynomial constraint.
+///
+/// These are returned by the closures passed to `ConstraintSystem::create_gate`.
+#[derive(Debug)]
+pub struct Constraint<F: Field> {
+    name: &'static str,
+    poly: Expression<F>,
+}
+
+impl<F: Field> From<Expression<F>> for Constraint<F> {
+    fn from(poly: Expression<F>) -> Self {
+        Constraint { name: "", poly }
+    }
+}
+
+impl<F: Field> From<(&'static str, Expression<F>)> for Constraint<F> {
+    fn from((name, poly): (&'static str, Expression<F>)) -> Self {
+        Constraint { name, poly }
+    }
+}
+
+impl<F: Field> From<Expression<F>> for Vec<Constraint<F>> {
+    fn from(poly: Expression<F>) -> Self {
+        vec![Constraint { name: "", poly }]
+    }
+}
+
+/// A set of polynomial constraints with a common selector.
+///
+/// ```
+/// use halo2_proofs::{plonk::{Constraints, Expression}, poly::Rotation};
+/// use halo2curves::pasta::Fp;
+/// # use halo2_proofs::plonk::ConstraintSystem;
+///
+/// # let mut meta = ConstraintSystem::<Fp>::default();
+/// let a = meta.advice_column();
+/// let b = meta.advice_column();
+/// let c = meta.advice_column();
+/// let s = meta.selector();
+///
+/// meta.create_gate("foo", |meta| {
+///     let next = meta.query_advice(a, Rotation::next());
+///     let a = meta.query_advice(a, Rotation::cur());
+///     let b = meta.query_advice(b, Rotation::cur());
+///     let c = meta.query_advice(c, Rotation::cur());
+///     let s_ternary = meta.query_selector(s);
+///
+///     let one_minus_a = Expression::Constant(Fp::one()) - a.clone();
+///
+///     Constraints::with_selector(
+///         s_ternary,
+///         std::array::IntoIter::new([
+///             ("a is boolean", a.clone() * one_minus_a.clone()),
+///             ("next == a ? b : c", next - (a * b + one_minus_a * c)),
+///         ]),
+///     )
+/// });
+/// ```
+///
+/// Note that the use of `std::array::IntoIter::new` is only necessary if you need to
+/// support Rust 1.51 or 1.52. If your minimum supported Rust version is 1.53 or greater,
+/// you can pass an array directly.
+#[derive(Debug)]
+pub struct Constraints<F: Field, C: Into<Constraint<F>>, Iter: IntoIterator<Item = C>> {
+    selector: Expression<F>,
+    constraints: Iter,
+}
+
+impl<F: Field, C: Into<Constraint<F>>, Iter: IntoIterator<Item = C>> Constraints<F, C, Iter> {
+    /// Constructs a set of constraints that are controlled by the given selector.
+    ///
+    /// Each constraint `c` in `iterator` will be converted into the constraint
+    /// `selector * c`.
+    pub fn with_selector(selector: Expression<F>, constraints: Iter) -> Self {
+        Constraints {
+            selector,
+            constraints,
+        }
+    }
+}
+
+fn apply_selector_to_constraint<F: Field, C: Into<Constraint<F>>>(
+    (selector, c): (Expression<F>, C),
+) -> Constraint<F> {
+    let constraint: Constraint<F> = c.into();
+    Constraint {
+        name: constraint.name,
+        poly: selector * constraint.poly,
+    }
+}
+
+type ApplySelectorToConstraint<F, C> = fn((Expression<F>, C)) -> Constraint<F>;
+type ConstraintsIterator<F, C, I> = std::iter::Map<
+    std::iter::Zip<std::iter::Repeat<Expression<F>>, I>,
+    ApplySelectorToConstraint<F, C>,
+>;
+
+impl<F: Field, C: Into<Constraint<F>>, Iter: IntoIterator<Item = C>> IntoIterator
+    for Constraints<F, C, Iter>
+{
+    type Item = Constraint<F>;
+    type IntoIter = ConstraintsIterator<F, C, Iter::IntoIter>;
+
+    fn into_iter(self) -> Self::IntoIter {
+        std::iter::repeat(self.selector)
+            .zip(self.constraints.into_iter())
+            .map(apply_selector_to_constraint)
+    }
+}
+
+/// Gate
+#[derive(Clone, Debug)]
+pub struct Gate<F: Field> {
+    name: &'static str,
+    constraint_names: Vec<&'static str>,
+    polys: Vec<Expression<F>>,
+    /// We track queried selectors separately from other cells, so that we can use them to
+    /// trigger debug checks on gates.
+    queried_selectors: Vec<Selector>,
+    queried_cells: Vec<VirtualCell>,
+}
+
+impl<F: Field> Gate<F> {
+    pub(crate) fn name(&self) -> &'static str {
+        self.name
+    }
+
+    pub(crate) fn constraint_name(&self, constraint_index: usize) -> &'static str {
+        self.constraint_names[constraint_index]
+    }
+
+    /// Returns constraints of this gate
+    pub fn polynomials(&self) -> &[Expression<F>] {
+        &self.polys
+    }
+
+    pub(crate) fn queried_selectors(&self) -> &[Selector] {
+        &self.queried_selectors
+    }
+
+    pub(crate) fn queried_cells(&self) -> &[VirtualCell] {
+        &self.queried_cells
+    }
+}
+
+/// This is a description of the circuit environment, such as the gate, column and
+/// permutation arrangements.
+#[derive(Debug, Clone)]
+pub struct ConstraintSystem<F: Field> {
+    pub(crate) num_fixed_columns: usize,
+    pub(crate) num_advice_columns: usize,
+    pub(crate) num_instance_columns: usize,
+    pub(crate) num_selectors: usize,
+    pub(crate) num_challenges: usize,
+
+    /// Contains the phase for each advice column. Should have same length as num_advice_columns.
+    pub(crate) advice_column_phase: Vec<sealed::Phase>,
+    /// Contains the phase for each challenge. Should have same length as num_challenges.
+    pub(crate) challenge_phase: Vec<sealed::Phase>,
+
+    /// This is a cached vector that maps virtual selectors to the concrete
+    /// fixed column that they were compressed into. This is just used by dev
+    /// tooling right now.
+    pub(crate) selector_map: Vec<Column<Fixed>>,
+
+    pub(crate) gates: Vec<Gate<F>>,
+    pub(crate) advice_queries: Vec<(Column<Advice>, Rotation)>,
+    // Contains an integer for each advice column
+    // identifying how many distinct queries it has
+    // so far; should be same length as num_advice_columns.
+    num_advice_queries: Vec<usize>,
+    pub(crate) instance_queries: Vec<(Column<Instance>, Rotation)>,
+    pub(crate) fixed_queries: Vec<(Column<Fixed>, Rotation)>,
+
+    // Permutation argument for performing equality constraints
+    pub(crate) permutation: permutation::Argument,
+
+    // Vector of lookup arguments, where each corresponds to a sequence of
+    // input expressions and a sequence of table expressions involved in the lookup.
+    pub(crate) lookups: Vec<lookup::Argument<F>>,
+
+    // Vector of fixed columns, which can be used to store constant values
+    // that are copied into advice columns.
+    pub(crate) constants: Vec<Column<Fixed>>,
+
+    pub(crate) minimum_degree: Option<usize>,
+}
+
+/// Represents the minimal parameters that determine a `ConstraintSystem`.
+#[allow(dead_code)]
+pub struct PinnedConstraintSystem<'a, F: Field> {
+    num_fixed_columns: &'a usize,
+    num_advice_columns: &'a usize,
+    num_instance_columns: &'a usize,
+    num_selectors: &'a usize,
+    num_challenges: &'a usize,
+    advice_column_phase: &'a Vec<sealed::Phase>,
+    challenge_phase: &'a Vec<sealed::Phase>,
+    gates: PinnedGates<'a, F>,
+    advice_queries: &'a Vec<(Column<Advice>, Rotation)>,
+    instance_queries: &'a Vec<(Column<Instance>, Rotation)>,
+    fixed_queries: &'a Vec<(Column<Fixed>, Rotation)>,
+    permutation: &'a permutation::Argument,
+    lookups: &'a Vec<lookup::Argument<F>>,
+    constants: &'a Vec<Column<Fixed>>,
+    minimum_degree: &'a Option<usize>,
+}
+
+impl<'a, F: Field> std::fmt::Debug for PinnedConstraintSystem<'a, F> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let mut debug_struct = f.debug_struct("PinnedConstraintSystem");
+        debug_struct
+            .field("num_fixed_columns", self.num_fixed_columns)
+            .field("num_advice_columns", self.num_advice_columns)
+            .field("num_instance_columns", self.num_instance_columns)
+            .field("num_selectors", self.num_selectors);
+        // Only show multi-phase related fields if it's used.
+        if *self.num_challenges > 0 {
+            debug_struct
+                .field("num_challenges", self.num_challenges)
+                .field("advice_column_phase", self.advice_column_phase)
+                .field("challenge_phase", self.challenge_phase);
+        }
+        debug_struct
+            .field("gates", &self.gates)
+            .field("advice_queries", self.advice_queries)
+            .field("instance_queries", self.instance_queries)
+            .field("fixed_queries", self.fixed_queries)
+            .field("permutation", self.permutation)
+            .field("lookups", self.lookups)
+            .field("constants", self.constants)
+            .field("minimum_degree", self.minimum_degree);
+        debug_struct.finish()
+    }
+}
+
+struct PinnedGates<'a, F: Field>(&'a Vec<Gate<F>>);
+
+impl<'a, F: Field> std::fmt::Debug for PinnedGates<'a, F> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+        f.debug_list()
+            .entries(self.0.iter().flat_map(|gate| gate.polynomials().iter()))
+            .finish()
+    }
+}
+
+impl<F: Field> Default for ConstraintSystem<F> {
+    fn default() -> ConstraintSystem<F> {
+        ConstraintSystem {
+            num_fixed_columns: 0,
+            num_advice_columns: 0,
+            num_instance_columns: 0,
+            num_selectors: 0,
+            num_challenges: 0,
+            advice_column_phase: Vec::new(),
+            challenge_phase: Vec::new(),
+            selector_map: vec![],
+            gates: vec![],
+            fixed_queries: Vec::new(),
+            advice_queries: Vec::new(),
+            num_advice_queries: Vec::new(),
+            instance_queries: Vec::new(),
+            permutation: permutation::Argument::new(),
+            lookups: Vec::new(),
+            constants: vec![],
+            minimum_degree: None,
+        }
+    }
+}
+
+impl<F: Field> ConstraintSystem<F> {
+    /// Obtain a pinned version of this constraint system; a structure with the
+    /// minimal parameters needed to determine the rest of the constraint
+    /// system.
+    pub fn pinned(&self) -> PinnedConstraintSystem<'_, F> {
+        PinnedConstraintSystem {
+            num_fixed_columns: &self.num_fixed_columns,
+            num_advice_columns: &self.num_advice_columns,
+            num_instance_columns: &self.num_instance_columns,
+            num_selectors: &self.num_selectors,
+            num_challenges: &self.num_challenges,
+            advice_column_phase: &self.advice_column_phase,
+            challenge_phase: &self.challenge_phase,
+            gates: PinnedGates(&self.gates),
+            fixed_queries: &self.fixed_queries,
+            advice_queries: &self.advice_queries,
+            instance_queries: &self.instance_queries,
+            permutation: &self.permutation,
+            lookups: &self.lookups,
+            constants: &self.constants,
+            minimum_degree: &self.minimum_degree,
+        }
+    }
+
+    /// Enables this fixed column to be used for global constant assignments.
+    ///
+    /// # Side-effects
+    ///
+    /// The column will be equality-enabled.
+    pub fn enable_constant(&mut self, column: Column<Fixed>) {
+        if !self.constants.contains(&column) {
+            self.constants.push(column);
+            self.enable_equality(column);
+        }
+    }
+
+    /// Enable the ability to enforce equality over cells in this column
+    pub fn enable_equality<C: Into<Column<Any>>>(&mut self, column: C) {
+        let column = column.into();
+        self.query_any_index(column, Rotation::cur());
+        self.permutation.add_column(column);
+    }
+
+    /// Add a lookup argument for some input expressions and table columns.
+    ///
+    /// `table_map` returns a map between input expressions and the table columns
+    /// they need to match.
+    pub fn lookup(
+        &mut self,
+        name: &'static str,
+        table_map: impl FnOnce(&mut VirtualCells<'_, F>) -> Vec<(Expression<F>, TableColumn)>,
+    ) -> usize {
+        let mut cells = VirtualCells::new(self);
+        let table_map = table_map(&mut cells)
+            .into_iter()
+            .map(|(input, table)| {
+                if input.contains_simple_selector() {
+                    panic!("expression containing simple selector supplied to lookup argument");
+                }
+
+                let table = cells.query_fixed(table.inner(), Rotation::cur());
+
+                (input, table)
+            })
+            .collect();
+
+        let index = self.lookups.len();
+
+        self.lookups.push(lookup::Argument::new(name, table_map));
+
+        index
+    }
+
+    /// Add a lookup argument for some input expressions and table expressions.
+    ///
+    /// `table_map` returns a map between input expressions and the table expressions
+    /// they need to match.
+    pub fn lookup_any(
+        &mut self,
+        name: &'static str,
+        table_map: impl FnOnce(&mut VirtualCells<'_, F>) -> Vec<(Expression<F>, Expression<F>)>,
+    ) -> usize {
+        let mut cells = VirtualCells::new(self);
+        let table_map = table_map(&mut cells);
+
+        let index = self.lookups.len();
+
+        self.lookups.push(lookup::Argument::new(name, table_map));
+
+        index
+    }
+
+    fn query_fixed_index(&mut self, column: Column<Fixed>, at: Rotation) -> usize {
+        // Return existing query, if it exists
+        for (index, fixed_query) in self.fixed_queries.iter().enumerate() {
+            if fixed_query == &(column, at) {
+                return index;
+            }
+        }
+
+        // Make a new query
+        let index = self.fixed_queries.len();
+        self.fixed_queries.push((column, at));
+
+        index
+    }
+
+    pub(crate) fn query_advice_index(&mut self, column: Column<Advice>, at: Rotation) -> usize {
+        // Return existing query, if it exists
+        for (index, advice_query) in self.advice_queries.iter().enumerate() {
+            if advice_query == &(column, at) {
+                return index;
+            }
+        }
+
+        // Make a new query
+        let index = self.advice_queries.len();
+        self.advice_queries.push((column, at));
+        self.num_advice_queries[column.index] += 1;
+
+        index
+    }
+
+    fn query_instance_index(&mut self, column: Column<Instance>, at: Rotation) -> usize {
+        // Return existing query, if it exists
+        for (index, instance_query) in self.instance_queries.iter().enumerate() {
+            if instance_query == &(column, at) {
+                return index;
+            }
+        }
+
+        // Make a new query
+        let index = self.instance_queries.len();
+        self.instance_queries.push((column, at));
+
+        index
+    }
+
+    fn query_any_index(&mut self, column: Column<Any>, at: Rotation) -> usize {
+        match column.column_type() {
+            Any::Advice(_) => {
+                self.query_advice_index(Column::<Advice>::try_from(column).unwrap(), at)
+            }
+            Any::Fixed => self.query_fixed_index(Column::<Fixed>::try_from(column).unwrap(), at),
+            Any::Instance => {
+                self.query_instance_index(Column::<Instance>::try_from(column).unwrap(), at)
+            }
+        }
+    }
+
+    pub(crate) fn get_advice_query_index(&self, column: Column<Advice>, at: Rotation) -> usize {
+        for (index, advice_query) in self.advice_queries.iter().enumerate() {
+            if advice_query == &(column, at) {
+                return index;
+            }
+        }
+
+        panic!("get_advice_query_index called for non-existent query");
+    }
+
+    pub(crate) fn get_fixed_query_index(&self, column: Column<Fixed>, at: Rotation) -> usize {
+        for (index, fixed_query) in self.fixed_queries.iter().enumerate() {
+            if fixed_query == &(column, at) {
+                return index;
+            }
+        }
+
+        panic!("get_fixed_query_index called for non-existent query");
+    }
+
+    pub(crate) fn get_instance_query_index(&self, column: Column<Instance>, at: Rotation) -> usize {
+        for (index, instance_query) in self.instance_queries.iter().enumerate() {
+            if instance_query == &(column, at) {
+                return index;
+            }
+        }
+
+        panic!("get_instance_query_index called for non-existent query");
+    }
+
+    pub(crate) fn get_any_query_index(&self, column: Column<Any>, at: Rotation) -> usize {
+        match column.column_type() {
+            Any::Advice(_) => {
+                self.get_advice_query_index(Column::<Advice>::try_from(column).unwrap(), at)
+            }
+            Any::Fixed => {
+                self.get_fixed_query_index(Column::<Fixed>::try_from(column).unwrap(), at)
+            }
+            Any::Instance => {
+                self.get_instance_query_index(Column::<Instance>::try_from(column).unwrap(), at)
+            }
+        }
+    }
+
+    /// Sets the minimum degree required by the circuit, which can be set to a
+    /// larger amount than actually needed. This can be used, for example, to
+    /// force the permutation argument to involve more columns in the same set.
+    pub fn set_minimum_degree(&mut self, degree: usize) {
+        self.minimum_degree = Some(degree);
+    }
+
+    /// Creates a new gate.
+    ///
+    /// # Panics
+    ///
+    /// A gate is required to contain polynomial constraints. This method will panic if
+    /// `constraints` returns an empty iterator.
+    pub fn create_gate<C: Into<Constraint<F>>, Iter: IntoIterator<Item = C>>(
+        &mut self,
+        name: &'static str,
+        constraints: impl FnOnce(&mut VirtualCells<'_, F>) -> Iter,
+    ) {
+        let mut cells = VirtualCells::new(self);
+        let constraints = constraints(&mut cells);
+        let queried_selectors = cells.queried_selectors;
+        let queried_cells = cells.queried_cells;
+
+        let (constraint_names, polys): (_, Vec<_>) = constraints
+            .into_iter()
+            .map(|c| c.into())
+            .map(|c| (c.name, c.poly))
+            .unzip();
+
+        assert!(
+            !polys.is_empty(),
+            "Gates must contain at least one constraint."
+        );
+
+        self.gates.push(Gate {
+            name,
+            constraint_names,
+            polys,
+            queried_selectors,
+            queried_cells,
+        });
+    }
+
+    /// This will compress selectors together depending on their provided
+    /// assignments. This `ConstraintSystem` will then be modified to add new
+    /// fixed columns (representing the actual selectors) and will return the
+    /// polynomials for those columns. Finally, an internal map is updated to
+    /// find which fixed column corresponds with a given `Selector`.
+    ///
+    /// Do not call this twice. Yes, this should be a builder pattern instead.
+    pub(crate) fn compress_selectors(mut self, selectors: Vec<Vec<bool>>) -> (Self, Vec<Vec<F>>) {
+        // The number of provided selector assignments must be the number we
+        // counted for this constraint system.
+        assert_eq!(selectors.len(), self.num_selectors);
+
+        // Compute the maximal degree of every selector. We only consider the
+        // expressions in gates, as lookup arguments cannot support simple
+        // selectors. Selectors that are complex or do not appear in any gates
+        // will have degree zero.
+        let mut degrees = vec![0; selectors.len()];
+        for expr in self.gates.iter().flat_map(|gate| gate.polys.iter()) {
+            if let Some(selector) = expr.extract_simple_selector() {
+                degrees[selector.0] = max(degrees[selector.0], expr.degree());
+            }
+        }
+
+        // We will not increase the degree of the constraint system, so we limit
+        // ourselves to the largest existing degree constraint.
+        let max_degree = self.degree();
+
+        let mut new_columns = vec![];
+        let (polys, selector_assignment) = compress_selectors::process(
+            selectors
+                .into_iter()
+                .zip(degrees.into_iter())
+                .enumerate()
+                .map(
+                    |(i, (activations, max_degree))| compress_selectors::SelectorDescription {
+                        selector: i,
+                        activations,
+                        max_degree,
+                    },
+                )
+                .collect(),
+            max_degree,
+            || {
+                let column = self.fixed_column();
+                new_columns.push(column);
+                Expression::Fixed(FixedQuery {
+                    index: self.query_fixed_index(column, Rotation::cur()),
+                    column_index: column.index,
+                    rotation: Rotation::cur(),
+                })
+            },
+        );
+
+        let mut selector_map = vec![None; selector_assignment.len()];
+        let mut selector_replacements = vec![None; selector_assignment.len()];
+        for assignment in selector_assignment {
+            selector_replacements[assignment.selector] = Some(assignment.expression);
+            selector_map[assignment.selector] = Some(new_columns[assignment.combination_index]);
+        }
+
+        self.selector_map = selector_map
+            .into_iter()
+            .map(|a| a.unwrap())
+            .collect::<Vec<_>>();
+        let selector_replacements = selector_replacements
+            .into_iter()
+            .map(|a| a.unwrap())
+            .collect::<Vec<_>>();
+
+        fn replace_selectors<F: Field>(
+            expr: &mut Expression<F>,
+            selector_replacements: &[Expression<F>],
+            must_be_nonsimple: bool,
+        ) {
+            *expr = expr.evaluate(
+                &|constant| Expression::Constant(constant),
+                &|selector| {
+                    if must_be_nonsimple {
+                        // Simple selectors are prohibited from appearing in
+                        // expressions in the lookup argument by
+                        // `ConstraintSystem`.
+                        assert!(!selector.is_simple());
+                    }
+
+                    selector_replacements[selector.0].clone()
+                },
+                &|query| Expression::Fixed(query),
+                &|query| Expression::Advice(query),
+                &|query| Expression::Instance(query),
+                &|challenge| Expression::Challenge(challenge),
+                &|a| -a,
+                &|a, b| a + b,
+                &|a, b| a * b,
+                &|a, f| a * f,
+            );
+        }
+
+        // Substitute selectors for the real fixed columns in all gates
+        for expr in self.gates.iter_mut().flat_map(|gate| gate.polys.iter_mut()) {
+            replace_selectors(expr, &selector_replacements, false);
+        }
+
+        // Substitute non-simple selectors for the real fixed columns in all
+        // lookup expressions
+        for expr in self.lookups.iter_mut().flat_map(|lookup| {
+            lookup
+                .input_expressions
+                .iter_mut()
+                .chain(lookup.table_expressions.iter_mut())
+        }) {
+            replace_selectors(expr, &selector_replacements, true);
+        }
+
+        (self, polys)
+    }
+
+    /// Allocate a new (simple) selector. Simple selectors cannot be added to
+    /// expressions nor multiplied by other expressions containing simple
+    /// selectors. Also, simple selectors may not appear in lookup argument
+    /// inputs.
+    pub fn selector(&mut self) -> Selector {
+        let index = self.num_selectors;
+        self.num_selectors += 1;
+        Selector(index, true)
+    }
+
+    /// Allocate a new complex selector that can appear anywhere
+    /// within expressions.
+    pub fn complex_selector(&mut self) -> Selector {
+        let index = self.num_selectors;
+        self.num_selectors += 1;
+        Selector(index, false)
+    }
+
+    /// Allocates a new fixed column that can be used in a lookup table.
+    pub fn lookup_table_column(&mut self) -> TableColumn {
+        TableColumn {
+            inner: self.fixed_column(),
+        }
+    }
+
+    /// Allocate a new fixed column
+    pub fn fixed_column(&mut self) -> Column<Fixed> {
+        let tmp = Column {
+            index: self.num_fixed_columns,
+            column_type: Fixed,
+        };
+        self.num_fixed_columns += 1;
+        tmp
+    }
+
+    /// Allocate a new advice column at `FirstPhase`
+    pub fn advice_column(&mut self) -> Column<Advice> {
+        self.advice_column_in(FirstPhase)
+    }
+
+    /// Allocate a new advice column in given phase
+    pub fn advice_column_in<P: Phase>(&mut self, phase: P) -> Column<Advice> {
+        let phase = phase.to_sealed();
+        if let Some(previous_phase) = phase.prev() {
+            self.assert_phase_exists(
+                previous_phase,
+                format!("Column<Advice> in later phase {:?}", phase).as_str(),
+            );
+        }
+
+        let tmp = Column {
+            index: self.num_advice_columns,
+            column_type: Advice { phase },
+        };
+        self.num_advice_columns += 1;
+        self.num_advice_queries.push(0);
+        self.advice_column_phase.push(phase);
+        tmp
+    }
+
+    /// Allocate a new instance column
+    pub fn instance_column(&mut self) -> Column<Instance> {
+        let tmp = Column {
+            index: self.num_instance_columns,
+            column_type: Instance,
+        };
+        self.num_instance_columns += 1;
+        tmp
+    }
+
+    /// Requests a challenge that is usable after the given phase.
+    pub fn challenge_usable_after<P: Phase>(&mut self, phase: P) -> Challenge {
+        let phase = phase.to_sealed();
+        self.assert_phase_exists(
+            phase,
+            format!("Challenge usable after phase {:?}", phase).as_str(),
+        );
+
+        let tmp = Challenge {
+            index: self.num_challenges,
+            phase,
+        };
+        self.num_challenges += 1;
+        self.challenge_phase.push(phase);
+        tmp
+    }
+
+    /// Helper funciotn to assert phase exists, to make sure phase-aware resources
+    /// are allocated in order, and to avoid any phase to be skipped accidentally
+    /// to cause unexpected issue in the future.
+    fn assert_phase_exists(&self, phase: sealed::Phase, resource: &str) {
+        self.advice_column_phase
+            .iter()
+            .find(|advice_column_phase| **advice_column_phase == phase)
+            .unwrap_or_else(|| {
+                panic!(
+                    "No Column<Advice> is used in phase {:?} while allocating a new {:?}",
+                    phase, resource
+                )
+            });
+    }
+
+    pub(crate) fn phases(&self) -> impl Iterator<Item = sealed::Phase> {
+        let max_phase = self
+            .advice_column_phase
+            .iter()
+            .max()
+            .map(|phase| phase.0)
+            .unwrap_or_default();
+        (0..=max_phase).map(sealed::Phase)
+    }
+
+    /// Compute the degree of the constraint system (the maximum degree of all
+    /// constraints).
+    pub fn degree(&self) -> usize {
+        // The permutation argument will serve alongside the gates, so must be
+        // accounted for.
+        let mut degree = self.permutation.required_degree();
+
+        // The lookup argument also serves alongside the gates and must be accounted
+        // for.
+        degree = std::cmp::max(
+            degree,
+            self.lookups
+                .iter()
+                .map(|l| l.required_degree())
+                .max()
+                .unwrap_or(1),
+        );
+
+        // Account for each gate to ensure our quotient polynomial is the
+        // correct degree and that our extended domain is the right size.
+        degree = std::cmp::max(
+            degree,
+            self.gates
+                .iter()
+                .flat_map(|gate| gate.polynomials().iter().map(|poly| poly.degree()))
+                .max()
+                .unwrap_or(0),
+        );
+
+        std::cmp::max(degree, self.minimum_degree.unwrap_or(1))
+    }
+
+    /// Compute the number of blinding factors necessary to perfectly blind
+    /// each of the prover's witness polynomials.
+    pub fn blinding_factors(&self) -> usize {
+        // All of the prover's advice columns are evaluated at no more than
+        let factors = *self.num_advice_queries.iter().max().unwrap_or(&1);
+        // distinct points during gate checks.
+
+        // - The permutation argument witness polynomials are evaluated at most 3 times.
+        // - Each lookup argument has independent witness polynomials, and they are
+        //   evaluated at most 2 times.
+        let factors = std::cmp::max(3, factors);
+
+        // Each polynomial is evaluated at most an additional time during
+        // multiopen (at x_3 to produce q_evals):
+        let factors = factors + 1;
+
+        // h(x) is derived by the other evaluations so it does not reveal
+        // anything; in fact it does not even appear in the proof.
+
+        // h(x_3) is also not revealed; the verifier only learns a single
+        // evaluation of a polynomial in x_1 which has h(x_3) and another random
+        // polynomial evaluated at x_3 as coefficients -- this random polynomial
+        // is "random_poly" in the vanishing argument.
+
+        // Add an additional blinding factor as a slight defense against
+        // off-by-one errors.
+        factors + 1
+    }
+
+    /// Returns the minimum necessary rows that need to exist in order to
+    /// account for e.g. blinding factors.
+    pub fn minimum_rows(&self) -> usize {
+        self.blinding_factors() // m blinding factors
+            + 1 // for l_{-(m + 1)} (l_last)
+            + 1 // for l_0 (just for extra breathing room for the permutation
+                // argument, to essentially force a separation in the
+                // permutation polynomial between the roles of l_last, l_0
+                // and the interstitial values.)
+            + 1 // for at least one row
+    }
+
+    /// Returns number of fixed columns
+    pub fn num_fixed_columns(&self) -> usize {
+        self.num_fixed_columns
+    }
+
+    /// Returns number of advice columns
+    pub fn num_advice_columns(&self) -> usize {
+        self.num_advice_columns
+    }
+
+    /// Returns number of instance columns
+    pub fn num_instance_columns(&self) -> usize {
+        self.num_instance_columns
+    }
+
+    /// Returns number of challenges
+    pub fn num_challenges(&self) -> usize {
+        self.num_challenges
+    }
+
+    /// Returns phase of advice columns
+    pub fn advice_column_phase(&self) -> Vec<u8> {
+        self.advice_column_phase
+            .iter()
+            .map(|phase| phase.0)
+            .collect()
+    }
+
+    /// Returns phase of challenges
+    pub fn challenge_phase(&self) -> Vec<u8> {
+        self.challenge_phase.iter().map(|phase| phase.0).collect()
+    }
+
+    /// Returns gates
+    pub fn gates(&self) -> &Vec<Gate<F>> {
+        &self.gates
+    }
+
+    /// Returns advice queries
+    pub fn advice_queries(&self) -> &Vec<(Column<Advice>, Rotation)> {
+        &self.advice_queries
+    }
+
+    /// Returns instance queries
+    pub fn instance_queries(&self) -> &Vec<(Column<Instance>, Rotation)> {
+        &self.instance_queries
+    }
+
+    /// Returns fixed queries
+    pub fn fixed_queries(&self) -> &Vec<(Column<Fixed>, Rotation)> {
+        &self.fixed_queries
+    }
+
+    /// Returns permutation argument
+    pub fn permutation(&self) -> &permutation::Argument {
+        &self.permutation
+    }
+
+    /// Returns lookup arguments
+    pub fn lookups(&self) -> &Vec<lookup::Argument<F>> {
+        &self.lookups
+    }
+
+    /// Returns constants
+    pub fn constants(&self) -> &Vec<Column<Fixed>> {
+        &self.constants
+    }
+}
+
+/// Exposes the "virtual cells" that can be queried while creating a custom gate or lookup
+/// table.
+#[derive(Debug)]
+pub struct VirtualCells<'a, F: Field> {
+    meta: &'a mut ConstraintSystem<F>,
+    queried_selectors: Vec<Selector>,
+    queried_cells: Vec<VirtualCell>,
+}
+
+impl<'a, F: Field> VirtualCells<'a, F> {
+    fn new(meta: &'a mut ConstraintSystem<F>) -> Self {
+        VirtualCells {
+            meta,
+            queried_selectors: vec![],
+            queried_cells: vec![],
+        }
+    }
+
+    /// Query a selector at the current position.
+    pub fn query_selector(&mut self, selector: Selector) -> Expression<F> {
+        self.queried_selectors.push(selector);
+        Expression::Selector(selector)
+    }
+
+    /// Query a fixed column at a relative position
+    pub fn query_fixed(&mut self, column: Column<Fixed>, at: Rotation) -> Expression<F> {
+        self.queried_cells.push((column, at).into());
+        Expression::Fixed(FixedQuery {
+            index: self.meta.query_fixed_index(column, at),
+            column_index: column.index,
+            rotation: at,
+        })
+    }
+
+    /// Query an advice column at a relative position
+    pub fn query_advice(&mut self, column: Column<Advice>, at: Rotation) -> Expression<F> {
+        self.queried_cells.push((column, at).into());
+        Expression::Advice(AdviceQuery {
+            index: self.meta.query_advice_index(column, at),
+            column_index: column.index,
+            rotation: at,
+            phase: column.column_type().phase,
+        })
+    }
+
+    /// Query an instance column at a relative position
+    pub fn query_instance(&mut self, column: Column<Instance>, at: Rotation) -> Expression<F> {
+        self.queried_cells.push((column, at).into());
+        Expression::Instance(InstanceQuery {
+            index: self.meta.query_instance_index(column, at),
+            column_index: column.index,
+            rotation: at,
+        })
+    }
+
+    /// Query an Any column at a relative position
+    pub fn query_any<C: Into<Column<Any>>>(&mut self, column: C, at: Rotation) -> Expression<F> {
+        let column = column.into();
+        match column.column_type() {
+            Any::Advice(_) => self.query_advice(Column::<Advice>::try_from(column).unwrap(), at),
+            Any::Fixed => self.query_fixed(Column::<Fixed>::try_from(column).unwrap(), at),
+            Any::Instance => self.query_instance(Column::<Instance>::try_from(column).unwrap(), at),
+        }
+    }
+
+    /// Query a challenge
+    pub fn query_challenge(&mut self, challenge: Challenge) -> Expression<F> {
+        Expression::Challenge(challenge)
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/circuit/compress_selectors.rs.html b/docs/src/halo2_proofs/plonk/circuit/compress_selectors.rs.html new file mode 100644 index 0000000000..401fefab0f --- /dev/null +++ b/docs/src/halo2_proofs/plonk/circuit/compress_selectors.rs.html @@ -0,0 +1,706 @@ +compress_selectors.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+
use super::Expression;
+use ff::Field;
+
+/// This describes a selector and where it is activated.
+#[derive(Debug, Clone)]
+pub struct SelectorDescription {
+    /// The selector that this description references, by index.
+    pub selector: usize,
+
+    /// The vector of booleans defining which rows are active for this selector.
+    pub activations: Vec<bool>,
+
+    /// The maximum degree of a gate involving this selector, including the
+    /// virtual selector itself. This means this will be at least 1 for any
+    /// expression containing a simple selector, even if that selector is not
+    /// multiplied by anything.
+    pub max_degree: usize,
+}
+
+/// This describes the assigned combination of a particular selector as well as
+/// the expression it should be substituted with.
+#[derive(Debug, Clone)]
+pub struct SelectorAssignment<F> {
+    /// The selector that this structure references, by index.
+    pub selector: usize,
+
+    /// The combination this selector was assigned to
+    pub combination_index: usize,
+
+    /// The expression we wish to substitute with
+    pub expression: Expression<F>,
+}
+
+/// This function takes a vector that defines each selector as well as a closure
+/// used to allocate new fixed columns, and returns the assignment of each
+/// combination as well as details about each selector assignment.
+///
+/// This function takes
+/// * `selectors`, a vector of `SelectorDescription`s that describe each
+///   selector
+/// * `max_degree`, the maximum allowed degree of any gate
+/// * `allocate_fixed_columns`, a closure that constructs a new fixed column and
+///   queries it at Rotation::cur(), returning the expression
+///
+/// and returns `Vec<Vec<F>>` containing the assignment of each new fixed column
+/// (which each correspond to a combination) as well as a vector of
+/// `SelectorAssignment` that the caller can use to perform the necessary
+/// substitutions to the constraint system.
+///
+/// This function is completely deterministic.
+pub fn process<F: Field, E>(
+    mut selectors: Vec<SelectorDescription>,
+    max_degree: usize,
+    mut allocate_fixed_column: E,
+) -> (Vec<Vec<F>>, Vec<SelectorAssignment<F>>)
+where
+    E: FnMut() -> Expression<F>,
+{
+    if selectors.is_empty() {
+        // There is nothing to optimize.
+        return (vec![], vec![]);
+    }
+
+    // The length of all provided selectors must be the same.
+    let n = selectors[0].activations.len();
+    assert!(selectors.iter().all(|a| a.activations.len() == n));
+
+    let mut combination_assignments = vec![];
+    let mut selector_assignments = vec![];
+
+    // All provided selectors of degree 0 are assumed to be either concrete
+    // selectors or do not appear in a gate. Let's address these first.
+    selectors.retain(|selector| {
+        if selector.max_degree == 0 {
+            // This is a complex selector, or a selector that does not appear in any
+            // gate constraint.
+            let expression = allocate_fixed_column();
+
+            let combination_assignment = selector
+                .activations
+                .iter()
+                .map(|b| if *b { F::one() } else { F::zero() })
+                .collect::<Vec<_>>();
+            let combination_index = combination_assignments.len();
+            combination_assignments.push(combination_assignment);
+            selector_assignments.push(SelectorAssignment {
+                selector: selector.selector,
+                combination_index,
+                expression,
+            });
+
+            false
+        } else {
+            true
+        }
+    });
+
+    // All of the remaining `selectors` are simple. Let's try to combine them.
+    // First, we compute the exclusion matrix that has (j, k) = true if selector
+    // j and selector k conflict -- that is, they are both enabled on the same
+    // row. This matrix is symmetric and the diagonal entries are false, so we
+    // only need to store the lower triangular entries.
+    let mut exclusion_matrix = (0..selectors.len())
+        .map(|i| vec![false; i])
+        .collect::<Vec<_>>();
+
+    for (i, rows) in selectors
+        .iter()
+        .map(|selector| &selector.activations)
+        .enumerate()
+    {
+        // Loop over the selectors previous to this one
+        for (j, other_selector) in selectors.iter().enumerate().take(i) {
+            // Look at what selectors are active at the same row
+            if rows
+                .iter()
+                .zip(other_selector.activations.iter())
+                .any(|(l, r)| l & r)
+            {
+                // Mark them as incompatible
+                exclusion_matrix[i][j] = true;
+            }
+        }
+    }
+
+    // Simple selectors that we've added to combinations already.
+    let mut added = vec![false; selectors.len()];
+
+    for (i, selector) in selectors.iter().enumerate() {
+        if added[i] {
+            continue;
+        }
+        added[i] = true;
+        assert!(selector.max_degree <= max_degree);
+        // This is used to keep track of the largest degree gate involved in the
+        // combination so far. We subtract by one to omit the virtual selector
+        // which will be substituted by the caller with the expression we give
+        // them.
+        let mut d = selector.max_degree - 1;
+        let mut combination = vec![selector];
+        let mut combination_added = vec![i];
+
+        // Try to find other selectors that can join this one.
+        'try_selectors: for (j, selector) in selectors.iter().enumerate().skip(i + 1) {
+            if d + combination.len() == max_degree {
+                // Short circuit; nothing can be added to this
+                // combination.
+                break 'try_selectors;
+            }
+
+            // Skip selectors that have been added to previous combinations
+            if added[j] {
+                continue 'try_selectors;
+            }
+
+            // Is this selector excluded from co-existing in the same
+            // combination with any of the other selectors so far?
+            for &i in combination_added.iter() {
+                if exclusion_matrix[j][i] {
+                    continue 'try_selectors;
+                }
+            }
+
+            // Can the new selector join the combination? Reminder: we use
+            // selector.max_degree - 1 to omit the influence of the virtual
+            // selector on the degree, as it will be substituted.
+            let new_d = std::cmp::max(d, selector.max_degree - 1);
+            if new_d + combination.len() + 1 > max_degree {
+                // Guess not.
+                continue 'try_selectors;
+            }
+
+            d = new_d;
+            combination.push(selector);
+            combination_added.push(j);
+            added[j] = true;
+        }
+
+        // Now, compute the selector and combination assignments.
+        let mut combination_assignment = vec![F::zero(); n];
+        let combination_len = combination.len();
+        let combination_index = combination_assignments.len();
+        let query = allocate_fixed_column();
+
+        let mut assigned_root = F::one();
+        selector_assignments.extend(combination.into_iter().map(|selector| {
+            // Compute the expression for substitution. This produces an expression of the
+            // form
+            //     q * Prod[i = 1..=combination_len, i != assigned_root](i - q)
+            //
+            // which is non-zero only on rows where `combination_assignment` is set to
+            // `assigned_root`. In particular, rows set to 0 correspond to all selectors
+            // being disabled.
+            let mut expression = query.clone();
+            let mut root = F::one();
+            for _ in 0..combination_len {
+                if root != assigned_root {
+                    expression = expression * (Expression::Constant(root) - query.clone());
+                }
+                root += F::one();
+            }
+
+            // Update the combination assignment
+            for (combination, selector) in combination_assignment
+                .iter_mut()
+                .zip(selector.activations.iter())
+            {
+                // This will not overwrite another selector's activations because
+                // we have ensured that selectors are disjoint.
+                if *selector {
+                    *combination = assigned_root;
+                }
+            }
+
+            assigned_root += F::one();
+
+            SelectorAssignment {
+                selector: selector.selector,
+                combination_index,
+                expression,
+            }
+        }));
+        combination_assignments.push(combination_assignment);
+    }
+
+    (combination_assignments, selector_assignments)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::{plonk::FixedQuery, poly::Rotation};
+    use halo2curves::pasta::Fp;
+    use proptest::collection::{vec, SizeRange};
+    use proptest::prelude::*;
+
+    prop_compose! {
+        fn arb_selector(assignment_size: usize, max_degree: usize)
+                       (degree in 0..max_degree,
+                        assignment in vec(any::<bool>(), assignment_size))
+                       -> (usize, Vec<bool>) {
+            (degree, assignment)
+        }
+    }
+
+    prop_compose! {
+        fn arb_selector_list(assignment_size: usize, max_degree: usize, num_selectors: impl Into<SizeRange>)
+                            (list in vec(arb_selector(assignment_size, max_degree), num_selectors))
+                            -> Vec<SelectorDescription>
+        {
+            list.into_iter().enumerate().map(|(i, (max_degree, activations))| {
+                SelectorDescription {
+                    selector: i,
+                    activations,
+                    max_degree,
+                }
+            }).collect()
+        }
+    }
+
+    prop_compose! {
+        fn arb_instance(max_assignment_size: usize,
+                        max_degree: usize,
+                        max_selectors: usize)
+                       (assignment_size in 1..max_assignment_size,
+                        degree in 1..max_degree,
+                        num_selectors in 1..max_selectors)
+                       (list in arb_selector_list(assignment_size, degree, num_selectors),
+                        degree in Just(degree))
+                       -> (Vec<SelectorDescription>, usize)
+        {
+            (list, degree)
+        }
+    }
+
+    proptest! {
+        #![proptest_config(ProptestConfig::with_cases(10000))]
+        #[test]
+        fn test_selector_combination((selectors, max_degree) in arb_instance(10, 10, 15)) {
+            let mut query = 0;
+            let (combination_assignments, selector_assignments) =
+                process::<Fp, _>(selectors.clone(), max_degree, || {
+                    let tmp = Expression::Fixed(FixedQuery {
+                        index: query,
+                        column_index: query,
+                        rotation: Rotation::cur(),
+                    });
+                    query += 1;
+                    tmp
+                });
+
+            {
+                let mut selectors_seen = vec![];
+                assert_eq!(selectors.len(), selector_assignments.len());
+                for selector in &selector_assignments {
+                    // Every selector should be assigned to a combination
+                    assert!(selector.combination_index < combination_assignments.len());
+                    assert!(!selectors_seen.contains(&selector.selector));
+                    selectors_seen.push(selector.selector);
+                }
+            }
+
+            // Test that, for each selector, the provided expression
+            //  1. evaluates to zero on rows where the selector's activation is off
+            //  2. evaluates to nonzero on rows where the selector's activation is on
+            //  3. is of degree d such that d + (selector.max_degree - 1) <= max_degree
+            //     OR selector.max_degree is zero
+            for selector in selector_assignments {
+                assert_eq!(
+                    selectors[selector.selector].activations.len(),
+                    combination_assignments[selector.combination_index].len()
+                );
+                for (&activation, &assignment) in selectors[selector.selector]
+                    .activations
+                    .iter()
+                    .zip(combination_assignments[selector.combination_index].iter())
+                {
+                    let eval = selector.expression.evaluate(
+                        &|c| c,
+                        &|_| panic!("should not occur in returned expressions"),
+                        &|query| {
+                            // Should be the correct combination in the expression
+                            assert_eq!(selector.combination_index, query.index);
+                            assignment
+                        },
+                        &|_| panic!("should not occur in returned expressions"),
+                        &|_| panic!("should not occur in returned expressions"),
+                        &|_| panic!("should not occur in returned expressions"),
+                        &|a| -a,
+                        &|a, b| a + b,
+                        &|a, b| a * b,
+                        &|a, f| a * f,
+                    );
+
+                    if activation {
+                        assert!(!eval.is_zero_vartime());
+                    } else {
+                        assert!(eval.is_zero_vartime());
+                    }
+                }
+
+                let expr_degree = selector.expression.degree();
+                assert!(expr_degree <= max_degree);
+                if selectors[selector.selector].max_degree > 0 {
+                    assert!(
+                        (selectors[selector.selector].max_degree - 1) + expr_degree <= max_degree
+                    );
+                }
+            }
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/error.rs.html b/docs/src/halo2_proofs/plonk/error.rs.html new file mode 100644 index 0000000000..101cbd6871 --- /dev/null +++ b/docs/src/halo2_proofs/plonk/error.rs.html @@ -0,0 +1,188 @@ +error.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+
use std::cmp;
+use std::error;
+use std::fmt;
+use std::io;
+
+use super::{Any, Column};
+
+/// This is an error that could occur during proving or circuit synthesis.
+// TODO: these errors need to be cleaned up
+#[derive(Debug)]
+pub enum Error {
+    /// This is an error that can occur during synthesis of the circuit, for
+    /// example, when the witness is not present.
+    Synthesis,
+    /// The provided instances do not match the circuit parameters.
+    InvalidInstances,
+    /// The constraint system is not satisfied.
+    ConstraintSystemFailure,
+    /// Out of bounds index passed to a backend
+    BoundsFailure,
+    /// Opening error
+    Opening,
+    /// Transcript error
+    Transcript(io::Error),
+    /// `k` is too small for the given circuit.
+    NotEnoughRowsAvailable {
+        /// The current value of `k` being used.
+        current_k: u32,
+    },
+    /// Instance provided exceeds number of available rows
+    InstanceTooLarge,
+    /// Circuit synthesis requires global constants, but circuit configuration did not
+    /// call [`ConstraintSystem::enable_constant`] on fixed columns with sufficient space.
+    ///
+    /// [`ConstraintSystem::enable_constant`]: crate::plonk::ConstraintSystem::enable_constant
+    NotEnoughColumnsForConstants,
+    /// The instance sets up a copy constraint involving a column that has not been
+    /// included in the permutation.
+    ColumnNotInPermutation(Column<Any>),
+}
+
+impl From<io::Error> for Error {
+    fn from(error: io::Error) -> Self {
+        // The only place we can get io::Error from is the transcript.
+        Error::Transcript(error)
+    }
+}
+
+impl Error {
+    /// Constructs an `Error::NotEnoughRowsAvailable`.
+    pub(crate) fn not_enough_rows_available(current_k: u32) -> Self {
+        Error::NotEnoughRowsAvailable { current_k }
+    }
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Error::Synthesis => write!(f, "General synthesis error"),
+            Error::InvalidInstances => write!(f, "Provided instances do not match the circuit"),
+            Error::ConstraintSystemFailure => write!(f, "The constraint system is not satisfied"),
+            Error::BoundsFailure => write!(f, "An out-of-bounds index was passed to the backend"),
+            Error::Opening => write!(f, "Multi-opening proof was invalid"),
+            Error::Transcript(e) => write!(f, "Transcript error: {}", e),
+            Error::NotEnoughRowsAvailable { current_k } => write!(
+                f,
+                "k = {} is too small for the given circuit. Try using a larger value of k",
+                current_k,
+            ),
+            Error::InstanceTooLarge => write!(f, "Instance vectors are larger than the circuit"),
+            Error::NotEnoughColumnsForConstants => {
+                write!(
+                    f,
+                    "Too few fixed columns are enabled for global constants usage"
+                )
+            }
+            Error::ColumnNotInPermutation(column) => write!(
+                f,
+                "Column {:?} must be included in the permutation. Help: try applying `meta.enable_equalty` on the column",
+                column
+            ),
+        }
+    }
+}
+
+impl error::Error for Error {
+    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
+        match self {
+            Error::Transcript(e) => Some(e),
+            _ => None,
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/evaluation.rs.html b/docs/src/halo2_proofs/plonk/evaluation.rs.html new file mode 100644 index 0000000000..7163b0622f --- /dev/null +++ b/docs/src/halo2_proofs/plonk/evaluation.rs.html @@ -0,0 +1,1576 @@ +evaluation.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+
use crate::multicore;
+use crate::plonk::lookup::prover::Committed;
+use crate::plonk::permutation::Argument;
+use crate::plonk::{lookup, permutation, AdviceQuery, Any, FixedQuery, InstanceQuery, ProvingKey};
+use crate::poly::Basis;
+use crate::{
+    arithmetic::{eval_polynomial, parallelize, CurveAffine, FieldExt},
+    poly::{
+        commitment::Params, Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff,
+        Polynomial, ProverQuery, Rotation,
+    },
+    transcript::{EncodedChallenge, TranscriptWrite},
+};
+use group::prime::PrimeCurve;
+use group::{
+    ff::{BatchInvert, Field},
+    Curve,
+};
+use std::any::TypeId;
+use std::convert::TryInto;
+use std::num::ParseIntError;
+use std::slice;
+use std::{
+    collections::BTreeMap,
+    iter,
+    ops::{Index, Mul, MulAssign},
+};
+
+use super::{ConstraintSystem, Expression};
+
+/// Return the index in the polynomial of size `isize` after rotation `rot`.
+fn get_rotation_idx(idx: usize, rot: i32, rot_scale: i32, isize: i32) -> usize {
+    (((idx as i32) + (rot * rot_scale)).rem_euclid(isize)) as usize
+}
+
+/// Value used in a calculation
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd)]
+pub enum ValueSource {
+    /// This is a constant value
+    Constant(usize),
+    /// This is an intermediate value
+    Intermediate(usize),
+    /// This is a fixed column
+    Fixed(usize, usize),
+    /// This is an advice (witness) column
+    Advice(usize, usize),
+    /// This is an instance (external) column
+    Instance(usize, usize),
+    /// This is a challenge
+    Challenge(usize),
+    /// beta
+    Beta(),
+    /// gamma
+    Gamma(),
+    /// theta
+    Theta(),
+    /// y
+    Y(),
+    /// Previous value
+    PreviousValue(),
+}
+
+impl Default for ValueSource {
+    fn default() -> Self {
+        ValueSource::Constant(0)
+    }
+}
+
+impl ValueSource {
+    /// Get the value for this source
+    pub fn get<F: Field, B: Basis>(
+        &self,
+        rotations: &[usize],
+        constants: &[F],
+        intermediates: &[F],
+        fixed_values: &[Polynomial<F, B>],
+        advice_values: &[Polynomial<F, B>],
+        instance_values: &[Polynomial<F, B>],
+        challenges: &[F],
+        beta: &F,
+        gamma: &F,
+        theta: &F,
+        y: &F,
+        previous_value: &F,
+    ) -> F {
+        match self {
+            ValueSource::Constant(idx) => constants[*idx],
+            ValueSource::Intermediate(idx) => intermediates[*idx],
+            ValueSource::Fixed(column_index, rotation) => {
+                fixed_values[*column_index][rotations[*rotation]]
+            }
+            ValueSource::Advice(column_index, rotation) => {
+                advice_values[*column_index][rotations[*rotation]]
+            }
+            ValueSource::Instance(column_index, rotation) => {
+                instance_values[*column_index][rotations[*rotation]]
+            }
+            ValueSource::Challenge(index) => challenges[*index],
+            ValueSource::Beta() => *beta,
+            ValueSource::Gamma() => *gamma,
+            ValueSource::Theta() => *theta,
+            ValueSource::Y() => *y,
+            ValueSource::PreviousValue() => *previous_value,
+        }
+    }
+}
+
+/// Calculation
+#[derive(Clone, Debug, PartialEq, Eq)]
+pub enum Calculation {
+    /// This is an addition
+    Add(ValueSource, ValueSource),
+    /// This is a subtraction
+    Sub(ValueSource, ValueSource),
+    /// This is a product
+    Mul(ValueSource, ValueSource),
+    /// This is a square
+    Square(ValueSource),
+    /// This is a double
+    Double(ValueSource),
+    /// This is a negation
+    Negate(ValueSource),
+    /// This is Horner's rule: `val = a; val = val * c + b[]`
+    Horner(ValueSource, Vec<ValueSource>, ValueSource),
+    /// This is a simple assignment
+    Store(ValueSource),
+}
+
+impl Calculation {
+    /// Get the resulting value of this calculation
+    pub fn evaluate<F: Field, B: Basis>(
+        &self,
+        rotations: &[usize],
+        constants: &[F],
+        intermediates: &[F],
+        fixed_values: &[Polynomial<F, B>],
+        advice_values: &[Polynomial<F, B>],
+        instance_values: &[Polynomial<F, B>],
+        challenges: &[F],
+        beta: &F,
+        gamma: &F,
+        theta: &F,
+        y: &F,
+        previous_value: &F,
+    ) -> F {
+        let get_value = |value: &ValueSource| {
+            value.get(
+                rotations,
+                constants,
+                intermediates,
+                fixed_values,
+                advice_values,
+                instance_values,
+                challenges,
+                beta,
+                gamma,
+                theta,
+                y,
+                previous_value,
+            )
+        };
+        match self {
+            Calculation::Add(a, b) => get_value(a) + get_value(b),
+            Calculation::Sub(a, b) => get_value(a) - get_value(b),
+            Calculation::Mul(a, b) => get_value(a) * get_value(b),
+            Calculation::Square(v) => get_value(v).square(),
+            Calculation::Double(v) => get_value(v).double(),
+            Calculation::Negate(v) => -get_value(v),
+            Calculation::Horner(start_value, parts, factor) => {
+                let factor = get_value(factor);
+                let mut value = get_value(start_value);
+                for part in parts.iter() {
+                    value = value * factor + get_value(part);
+                }
+                value
+            }
+            Calculation::Store(v) => get_value(v),
+        }
+    }
+}
+
+/// Evaluator
+#[derive(Clone, Default, Debug)]
+pub struct Evaluator<C: CurveAffine> {
+    ///  Custom gates evalution
+    pub custom_gates: GraphEvaluator<C>,
+    ///  Lookups evalution
+    pub lookups: Vec<GraphEvaluator<C>>,
+}
+
+/// GraphEvaluator
+#[derive(Clone, Debug)]
+pub struct GraphEvaluator<C: CurveAffine> {
+    /// Constants
+    pub constants: Vec<C::ScalarExt>,
+    /// Rotations
+    pub rotations: Vec<i32>,
+    /// Calculations
+    pub calculations: Vec<CalculationInfo>,
+    /// Number of intermediates
+    pub num_intermediates: usize,
+}
+
+/// EvaluationData
+#[derive(Default, Debug)]
+pub struct EvaluationData<C: CurveAffine> {
+    /// Intermediates
+    pub intermediates: Vec<C::ScalarExt>,
+    /// Rotations
+    pub rotations: Vec<usize>,
+}
+
+/// CaluclationInfo
+#[derive(Clone, Debug)]
+pub struct CalculationInfo {
+    /// Calculation
+    pub calculation: Calculation,
+    /// Target
+    pub target: usize,
+}
+
+impl<C: CurveAffine> Evaluator<C> {
+    /// Creates a new evaluation structure
+    pub fn new(cs: &ConstraintSystem<C::ScalarExt>) -> Self {
+        let mut ev = Evaluator::default();
+
+        // Custom gates
+        let mut parts = Vec::new();
+        for gate in cs.gates.iter() {
+            parts.extend(
+                gate.polynomials()
+                    .iter()
+                    .map(|poly| ev.custom_gates.add_expression(poly)),
+            );
+        }
+        ev.custom_gates.add_calculation(Calculation::Horner(
+            ValueSource::PreviousValue(),
+            parts,
+            ValueSource::Y(),
+        ));
+
+        // Lookups
+        for lookup in cs.lookups.iter() {
+            let mut graph = GraphEvaluator::default();
+
+            let mut evaluate_lc = |expressions: &Vec<Expression<_>>| {
+                let parts = expressions
+                    .iter()
+                    .map(|expr| graph.add_expression(expr))
+                    .collect();
+                graph.add_calculation(Calculation::Horner(
+                    ValueSource::Constant(0),
+                    parts,
+                    ValueSource::Theta(),
+                ))
+            };
+
+            // Input coset
+            let compressed_input_coset = evaluate_lc(&lookup.input_expressions);
+            // table coset
+            let compressed_table_coset = evaluate_lc(&lookup.table_expressions);
+            // z(\omega X) (a'(X) + \beta) (s'(X) + \gamma)
+            let right_gamma = graph.add_calculation(Calculation::Add(
+                compressed_table_coset,
+                ValueSource::Gamma(),
+            ));
+            let lc = graph.add_calculation(Calculation::Add(
+                compressed_input_coset,
+                ValueSource::Beta(),
+            ));
+            graph.add_calculation(Calculation::Mul(lc, right_gamma));
+
+            ev.lookups.push(graph);
+        }
+
+        ev
+    }
+
+    /// Evaluate h poly
+    pub(in crate::plonk) fn evaluate_h(
+        &self,
+        pk: &ProvingKey<C>,
+        advice_polys: &[&[Polynomial<C::ScalarExt, Coeff>]],
+        instance_polys: &[&[Polynomial<C::ScalarExt, Coeff>]],
+        challenges: &[C::ScalarExt],
+        y: C::ScalarExt,
+        beta: C::ScalarExt,
+        gamma: C::ScalarExt,
+        theta: C::ScalarExt,
+        lookups: &[Vec<lookup::prover::Committed<C>>],
+        permutations: &[permutation::prover::Committed<C>],
+    ) -> Polynomial<C::ScalarExt, ExtendedLagrangeCoeff> {
+        let domain = &pk.vk.domain;
+        let size = domain.extended_len();
+        let rot_scale = 1 << (domain.extended_k() - domain.k());
+        let fixed = &pk.fixed_cosets[..];
+        let extended_omega = domain.get_extended_omega();
+        let isize = size as i32;
+        let one = C::ScalarExt::one();
+        let l0 = &pk.l0;
+        let l_last = &pk.l_last;
+        let l_active_row = &pk.l_active_row;
+        let p = &pk.vk.cs.permutation;
+
+        // Calculate the advice and instance cosets
+        let advice: Vec<Vec<Polynomial<C::Scalar, ExtendedLagrangeCoeff>>> = advice_polys
+            .iter()
+            .map(|advice_polys| {
+                advice_polys
+                    .iter()
+                    .map(|poly| domain.coeff_to_extended(poly.clone()))
+                    .collect()
+            })
+            .collect();
+        let instance: Vec<Vec<Polynomial<C::Scalar, ExtendedLagrangeCoeff>>> = instance_polys
+            .iter()
+            .map(|instance_polys| {
+                instance_polys
+                    .iter()
+                    .map(|poly| domain.coeff_to_extended(poly.clone()))
+                    .collect()
+            })
+            .collect();
+
+        let mut values = domain.empty_extended();
+
+        // Core expression evaluations
+        let num_threads = multicore::current_num_threads();
+        for (((advice, instance), lookups), permutation) in advice
+            .iter()
+            .zip(instance.iter())
+            .zip(lookups.iter())
+            .zip(permutations.iter())
+        {
+            // Custom gates
+            multicore::scope(|scope| {
+                let chunk_size = (size + num_threads - 1) / num_threads;
+                for (thread_idx, values) in values.chunks_mut(chunk_size).enumerate() {
+                    let start = thread_idx * chunk_size;
+                    scope.spawn(move |_| {
+                        let mut eval_data = self.custom_gates.instance();
+                        for (i, value) in values.iter_mut().enumerate() {
+                            let idx = start + i;
+                            *value = self.custom_gates.evaluate(
+                                &mut eval_data,
+                                fixed,
+                                advice,
+                                instance,
+                                challenges,
+                                &beta,
+                                &gamma,
+                                &theta,
+                                &y,
+                                value,
+                                idx,
+                                rot_scale,
+                                isize,
+                            );
+                        }
+                    });
+                }
+            });
+
+            // Permutations
+            let sets = &permutation.sets;
+            if !sets.is_empty() {
+                let blinding_factors = pk.vk.cs.blinding_factors();
+                let last_rotation = Rotation(-((blinding_factors + 1) as i32));
+                let chunk_len = pk.vk.cs.degree() - 2;
+                let delta_start = beta * &C::Scalar::ZETA;
+
+                let first_set = sets.first().unwrap();
+                let last_set = sets.last().unwrap();
+
+                // Permutation constraints
+                parallelize(&mut values, |values, start| {
+                    let mut beta_term = extended_omega.pow_vartime(&[start as u64, 0, 0, 0]);
+                    for (i, value) in values.iter_mut().enumerate() {
+                        let idx = start + i;
+                        let r_next = get_rotation_idx(idx, 1, rot_scale, isize);
+                        let r_last = get_rotation_idx(idx, last_rotation.0, rot_scale, isize);
+
+                        // Enforce only for the first set.
+                        // l_0(X) * (1 - z_0(X)) = 0
+                        *value = *value * y
+                            + ((one - first_set.permutation_product_coset[idx]) * l0[idx]);
+                        // Enforce only for the last set.
+                        // l_last(X) * (z_l(X)^2 - z_l(X)) = 0
+                        *value = *value * y
+                            + ((last_set.permutation_product_coset[idx]
+                                * last_set.permutation_product_coset[idx]
+                                - last_set.permutation_product_coset[idx])
+                                * l_last[idx]);
+                        // Except for the first set, enforce.
+                        // l_0(X) * (z_i(X) - z_{i-1}(\omega^(last) X)) = 0
+                        for (set_idx, set) in sets.iter().enumerate() {
+                            if set_idx != 0 {
+                                *value = *value * y
+                                    + ((set.permutation_product_coset[idx]
+                                        - permutation.sets[set_idx - 1].permutation_product_coset
+                                            [r_last])
+                                        * l0[idx]);
+                            }
+                        }
+                        // And for all the sets we enforce:
+                        // (1 - (l_last(X) + l_blind(X))) * (
+                        //   z_i(\omega X) \prod_j (p(X) + \beta s_j(X) + \gamma)
+                        // - z_i(X) \prod_j (p(X) + \delta^j \beta X + \gamma)
+                        // )
+                        let mut current_delta = delta_start * beta_term;
+                        for ((set, columns), cosets) in sets
+                            .iter()
+                            .zip(p.columns.chunks(chunk_len))
+                            .zip(pk.permutation.cosets.chunks(chunk_len))
+                        {
+                            let mut left = set.permutation_product_coset[r_next];
+                            for (values, permutation) in columns
+                                .iter()
+                                .map(|&column| match column.column_type() {
+                                    Any::Advice(_) => &advice[column.index()],
+                                    Any::Fixed => &fixed[column.index()],
+                                    Any::Instance => &instance[column.index()],
+                                })
+                                .zip(cosets.iter())
+                            {
+                                left *= values[idx] + beta * permutation[idx] + gamma;
+                            }
+
+                            let mut right = set.permutation_product_coset[idx];
+                            for values in columns.iter().map(|&column| match column.column_type() {
+                                Any::Advice(_) => &advice[column.index()],
+                                Any::Fixed => &fixed[column.index()],
+                                Any::Instance => &instance[column.index()],
+                            }) {
+                                right *= values[idx] + current_delta + gamma;
+                                current_delta *= &C::Scalar::DELTA;
+                            }
+
+                            *value = *value * y + ((left - right) * l_active_row[idx]);
+                        }
+                        beta_term *= &extended_omega;
+                    }
+                });
+            }
+
+            // Lookups
+            for (n, lookup) in lookups.iter().enumerate() {
+                // Polynomials required for this lookup.
+                // Calculated here so these only have to be kept in memory for the short time
+                // they are actually needed.
+                let product_coset = pk.vk.domain.coeff_to_extended(lookup.product_poly.clone());
+                let permuted_input_coset = pk
+                    .vk
+                    .domain
+                    .coeff_to_extended(lookup.permuted_input_poly.clone());
+                let permuted_table_coset = pk
+                    .vk
+                    .domain
+                    .coeff_to_extended(lookup.permuted_table_poly.clone());
+
+                // Lookup constraints
+                parallelize(&mut values, |values, start| {
+                    let lookup_evaluator = &self.lookups[n];
+                    let mut eval_data = lookup_evaluator.instance();
+                    for (i, value) in values.iter_mut().enumerate() {
+                        let idx = start + i;
+
+                        let table_value = lookup_evaluator.evaluate(
+                            &mut eval_data,
+                            fixed,
+                            advice,
+                            instance,
+                            challenges,
+                            &beta,
+                            &gamma,
+                            &theta,
+                            &y,
+                            &C::ScalarExt::zero(),
+                            idx,
+                            rot_scale,
+                            isize,
+                        );
+
+                        let r_next = get_rotation_idx(idx, 1, rot_scale, isize);
+                        let r_prev = get_rotation_idx(idx, -1, rot_scale, isize);
+
+                        let a_minus_s = permuted_input_coset[idx] - permuted_table_coset[idx];
+                        // l_0(X) * (1 - z(X)) = 0
+                        *value = *value * y + ((one - product_coset[idx]) * l0[idx]);
+                        // l_last(X) * (z(X)^2 - z(X)) = 0
+                        *value = *value * y
+                            + ((product_coset[idx] * product_coset[idx] - product_coset[idx])
+                                * l_last[idx]);
+                        // (1 - (l_last(X) + l_blind(X))) * (
+                        //   z(\omega X) (a'(X) + \beta) (s'(X) + \gamma)
+                        //   - z(X) (\theta^{m-1} a_0(X) + ... + a_{m-1}(X) + \beta)
+                        //          (\theta^{m-1} s_0(X) + ... + s_{m-1}(X) + \gamma)
+                        // ) = 0
+                        *value = *value * y
+                            + ((product_coset[r_next]
+                                * (permuted_input_coset[idx] + beta)
+                                * (permuted_table_coset[idx] + gamma)
+                                - product_coset[idx] * table_value)
+                                * l_active_row[idx]);
+                        // Check that the first values in the permuted input expression and permuted
+                        // fixed expression are the same.
+                        // l_0(X) * (a'(X) - s'(X)) = 0
+                        *value = *value * y + (a_minus_s * l0[idx]);
+                        // Check that each value in the permuted lookup input expression is either
+                        // equal to the value above it, or the value at the same index in the
+                        // permuted table expression.
+                        // (1 - (l_last + l_blind)) * (a′(X) − s′(X))⋅(a′(X) − a′(\omega^{-1} X)) = 0
+                        *value = *value * y
+                            + (a_minus_s
+                                * (permuted_input_coset[idx] - permuted_input_coset[r_prev])
+                                * l_active_row[idx]);
+                    }
+                });
+            }
+        }
+        values
+    }
+}
+
+impl<C: CurveAffine> Default for GraphEvaluator<C> {
+    fn default() -> Self {
+        Self {
+            // Fixed positions to allow easy access
+            constants: vec![
+                C::ScalarExt::zero(),
+                C::ScalarExt::one(),
+                C::ScalarExt::from(2u64),
+            ],
+            rotations: Vec::new(),
+            calculations: Vec::new(),
+            num_intermediates: 0,
+        }
+    }
+}
+
+impl<C: CurveAffine> GraphEvaluator<C> {
+    /// Adds a rotation
+    fn add_rotation(&mut self, rotation: &Rotation) -> usize {
+        let position = self.rotations.iter().position(|&c| c == rotation.0);
+        match position {
+            Some(pos) => pos,
+            None => {
+                self.rotations.push(rotation.0);
+                self.rotations.len() - 1
+            }
+        }
+    }
+
+    /// Adds a constant
+    fn add_constant(&mut self, constant: &C::ScalarExt) -> ValueSource {
+        let position = self.constants.iter().position(|&c| c == *constant);
+        ValueSource::Constant(match position {
+            Some(pos) => pos,
+            None => {
+                self.constants.push(*constant);
+                self.constants.len() - 1
+            }
+        })
+    }
+
+    /// Adds a calculation.
+    /// Currently does the simplest thing possible: just stores the
+    /// resulting value so the result can be reused  when that calculation
+    /// is done multiple times.
+    fn add_calculation(&mut self, calculation: Calculation) -> ValueSource {
+        let existing_calculation = self
+            .calculations
+            .iter()
+            .find(|c| c.calculation == calculation);
+        match existing_calculation {
+            Some(existing_calculation) => ValueSource::Intermediate(existing_calculation.target),
+            None => {
+                let target = self.num_intermediates;
+                self.calculations.push(CalculationInfo {
+                    calculation,
+                    target,
+                });
+                self.num_intermediates += 1;
+                ValueSource::Intermediate(target)
+            }
+        }
+    }
+
+    /// Generates an optimized evaluation for the expression
+    fn add_expression(&mut self, expr: &Expression<C::ScalarExt>) -> ValueSource {
+        match expr {
+            Expression::Constant(scalar) => self.add_constant(scalar),
+            Expression::Selector(_selector) => unreachable!(),
+            Expression::Fixed(query) => {
+                let rot_idx = self.add_rotation(&query.rotation);
+                self.add_calculation(Calculation::Store(ValueSource::Fixed(
+                    query.column_index,
+                    rot_idx,
+                )))
+            }
+            Expression::Advice(query) => {
+                let rot_idx = self.add_rotation(&query.rotation);
+                self.add_calculation(Calculation::Store(ValueSource::Advice(
+                    query.column_index,
+                    rot_idx,
+                )))
+            }
+            Expression::Instance(query) => {
+                let rot_idx = self.add_rotation(&query.rotation);
+                self.add_calculation(Calculation::Store(ValueSource::Instance(
+                    query.column_index,
+                    rot_idx,
+                )))
+            }
+            Expression::Challenge(challenge) => self.add_calculation(Calculation::Store(
+                ValueSource::Challenge(challenge.index()),
+            )),
+            Expression::Negated(a) => match **a {
+                Expression::Constant(scalar) => self.add_constant(&-scalar),
+                _ => {
+                    let result_a = self.add_expression(a);
+                    match result_a {
+                        ValueSource::Constant(0) => result_a,
+                        _ => self.add_calculation(Calculation::Negate(result_a)),
+                    }
+                }
+            },
+            Expression::Sum(a, b) => {
+                // Undo subtraction stored as a + (-b) in expressions
+                match &**b {
+                    Expression::Negated(b_int) => {
+                        let result_a = self.add_expression(a);
+                        let result_b = self.add_expression(b_int);
+                        if result_a == ValueSource::Constant(0) {
+                            self.add_calculation(Calculation::Negate(result_b))
+                        } else if result_b == ValueSource::Constant(0) {
+                            result_a
+                        } else {
+                            self.add_calculation(Calculation::Sub(result_a, result_b))
+                        }
+                    }
+                    _ => {
+                        let result_a = self.add_expression(a);
+                        let result_b = self.add_expression(b);
+                        if result_a == ValueSource::Constant(0) {
+                            result_b
+                        } else if result_b == ValueSource::Constant(0) {
+                            result_a
+                        } else if result_a <= result_b {
+                            self.add_calculation(Calculation::Add(result_a, result_b))
+                        } else {
+                            self.add_calculation(Calculation::Add(result_b, result_a))
+                        }
+                    }
+                }
+            }
+            Expression::Product(a, b) => {
+                let result_a = self.add_expression(a);
+                let result_b = self.add_expression(b);
+                if result_a == ValueSource::Constant(0) || result_b == ValueSource::Constant(0) {
+                    ValueSource::Constant(0)
+                } else if result_a == ValueSource::Constant(1) {
+                    result_b
+                } else if result_b == ValueSource::Constant(1) {
+                    result_a
+                } else if result_a == ValueSource::Constant(2) {
+                    self.add_calculation(Calculation::Double(result_b))
+                } else if result_b == ValueSource::Constant(2) {
+                    self.add_calculation(Calculation::Double(result_a))
+                } else if result_a == result_b {
+                    self.add_calculation(Calculation::Square(result_a))
+                } else if result_a <= result_b {
+                    self.add_calculation(Calculation::Mul(result_a, result_b))
+                } else {
+                    self.add_calculation(Calculation::Mul(result_b, result_a))
+                }
+            }
+            Expression::Scaled(a, f) => {
+                if *f == C::ScalarExt::zero() {
+                    ValueSource::Constant(0)
+                } else if *f == C::ScalarExt::one() {
+                    self.add_expression(a)
+                } else {
+                    let cst = self.add_constant(f);
+                    let result_a = self.add_expression(a);
+                    self.add_calculation(Calculation::Mul(result_a, cst))
+                }
+            }
+        }
+    }
+
+    /// Creates a new evaluation structure
+    pub fn instance(&self) -> EvaluationData<C> {
+        EvaluationData {
+            intermediates: vec![C::ScalarExt::zero(); self.num_intermediates],
+            rotations: vec![0usize; self.rotations.len()],
+        }
+    }
+
+    pub fn evaluate<B: Basis>(
+        &self,
+        data: &mut EvaluationData<C>,
+        fixed: &[Polynomial<C::ScalarExt, B>],
+        advice: &[Polynomial<C::ScalarExt, B>],
+        instance: &[Polynomial<C::ScalarExt, B>],
+        challenges: &[C::ScalarExt],
+        beta: &C::ScalarExt,
+        gamma: &C::ScalarExt,
+        theta: &C::ScalarExt,
+        y: &C::ScalarExt,
+        previous_value: &C::ScalarExt,
+        idx: usize,
+        rot_scale: i32,
+        isize: i32,
+    ) -> C::ScalarExt {
+        // All rotation index values
+        for (rot_idx, rot) in self.rotations.iter().enumerate() {
+            data.rotations[rot_idx] = get_rotation_idx(idx, *rot, rot_scale, isize);
+        }
+
+        // All calculations, with cached intermediate results
+        for calc in self.calculations.iter() {
+            data.intermediates[calc.target] = calc.calculation.evaluate(
+                &data.rotations,
+                &self.constants,
+                &data.intermediates,
+                fixed,
+                advice,
+                instance,
+                challenges,
+                beta,
+                gamma,
+                theta,
+                y,
+                previous_value,
+            );
+        }
+
+        // Return the result of the last calculation (if any)
+        if let Some(calc) = self.calculations.last() {
+            data.intermediates[calc.target]
+        } else {
+            C::ScalarExt::zero()
+        }
+    }
+}
+
+/// Simple evaluation of an expression
+pub fn evaluate<F: FieldExt, B: Basis>(
+    expression: &Expression<F>,
+    size: usize,
+    rot_scale: i32,
+    fixed: &[Polynomial<F, B>],
+    advice: &[Polynomial<F, B>],
+    instance: &[Polynomial<F, B>],
+    challenges: &[F],
+) -> Vec<F> {
+    let mut values = vec![F::zero(); size];
+    let isize = size as i32;
+    parallelize(&mut values, |values, start| {
+        for (i, value) in values.iter_mut().enumerate() {
+            let idx = start + i;
+            *value = expression.evaluate(
+                &|scalar| scalar,
+                &|_| panic!("virtual selectors are removed during optimization"),
+                &|query| {
+                    fixed[query.column_index]
+                        [get_rotation_idx(idx, query.rotation.0, rot_scale, isize)]
+                },
+                &|query| {
+                    advice[query.column_index]
+                        [get_rotation_idx(idx, query.rotation.0, rot_scale, isize)]
+                },
+                &|query| {
+                    instance[query.column_index]
+                        [get_rotation_idx(idx, query.rotation.0, rot_scale, isize)]
+                },
+                &|challenge| challenges[challenge.index()],
+                &|a| -a,
+                &|a, b| a + &b,
+                &|a, b| a * b,
+                &|a, scalar| a * scalar,
+            );
+        }
+    });
+    values
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/keygen.rs.html b/docs/src/halo2_proofs/plonk/keygen.rs.html new file mode 100644 index 0000000000..5521695889 --- /dev/null +++ b/docs/src/halo2_proofs/plonk/keygen.rs.html @@ -0,0 +1,688 @@ +keygen.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+
#![allow(clippy::int_plus_one)]
+
+use std::ops::Range;
+
+use ff::Field;
+use group::Curve;
+
+use super::{
+    circuit::{
+        Advice, Any, Assignment, Circuit, Column, ConstraintSystem, Fixed, FloorPlanner, Instance,
+        Selector,
+    },
+    evaluation::Evaluator,
+    permutation, Assigned, Challenge, Error, Expression, LagrangeCoeff, Polynomial, ProvingKey,
+    VerifyingKey,
+};
+use crate::{
+    arithmetic::{parallelize, CurveAffine},
+    circuit::Value,
+    poly::{
+        batch_invert_assigned,
+        commitment::{Blind, Params, MSM},
+        EvaluationDomain,
+    },
+};
+
+pub(crate) fn create_domain<C, ConcreteCircuit>(
+    k: u32,
+) -> (
+    EvaluationDomain<C::Scalar>,
+    ConstraintSystem<C::Scalar>,
+    ConcreteCircuit::Config,
+)
+where
+    C: CurveAffine,
+    ConcreteCircuit: Circuit<C::Scalar>,
+{
+    let mut cs = ConstraintSystem::default();
+    let config = ConcreteCircuit::configure(&mut cs);
+
+    let degree = cs.degree();
+
+    let domain = EvaluationDomain::new(degree as u32, k);
+
+    (domain, cs, config)
+}
+
+/// Assembly to be used in circuit synthesis.
+#[derive(Debug)]
+struct Assembly<F: Field> {
+    k: u32,
+    fixed: Vec<Polynomial<Assigned<F>, LagrangeCoeff>>,
+    permutation: permutation::keygen::Assembly,
+    selectors: Vec<Vec<bool>>,
+    // A range of available rows for assignment and copies.
+    usable_rows: Range<usize>,
+    _marker: std::marker::PhantomData<F>,
+}
+
+impl<F: Field> Assignment<F> for Assembly<F> {
+    fn enter_region<NR, N>(&mut self, _: N)
+    where
+        NR: Into<String>,
+        N: FnOnce() -> NR,
+    {
+        // Do nothing; we don't care about regions in this context.
+    }
+
+    fn exit_region(&mut self) {
+        // Do nothing; we don't care about regions in this context.
+    }
+
+    fn enable_selector<A, AR>(&mut self, _: A, selector: &Selector, row: usize) -> Result<(), Error>
+    where
+        A: FnOnce() -> AR,
+        AR: Into<String>,
+    {
+        if !self.usable_rows.contains(&row) {
+            return Err(Error::not_enough_rows_available(self.k));
+        }
+
+        self.selectors[selector.0][row] = true;
+
+        Ok(())
+    }
+
+    fn query_instance(&self, _: Column<Instance>, row: usize) -> Result<Value<F>, Error> {
+        if !self.usable_rows.contains(&row) {
+            return Err(Error::not_enough_rows_available(self.k));
+        }
+
+        // There is no instance in this context.
+        Ok(Value::unknown())
+    }
+
+    fn assign_advice<'r, 'v>(
+        //<V, VR, A, AR>(
+        &'r mut self,
+        //_: A,
+        _: Column<Advice>,
+        _: usize,
+        _: Value<Assigned<F>>,
+    ) -> Result<Value<&'v Assigned<F>>, Error> {
+        Ok(Value::unknown())
+    }
+
+    fn assign_fixed(&mut self, column: Column<Fixed>, row: usize, to: Assigned<F>) {
+        if !self.usable_rows.contains(&row) {
+            panic!(
+                "Assign Fixed {:?}",
+                Error::not_enough_rows_available(self.k)
+            );
+        }
+
+        *self
+            .fixed
+            .get_mut(column.index())
+            .and_then(|v| v.get_mut(row))
+            .unwrap_or_else(|| panic!("{:?}", Error::BoundsFailure)) = to;
+    }
+
+    fn copy(
+        &mut self,
+        left_column: Column<Any>,
+        left_row: usize,
+        right_column: Column<Any>,
+        right_row: usize,
+    ) {
+        if !self.usable_rows.contains(&left_row) || !self.usable_rows.contains(&right_row) {
+            panic!("{:?}", Error::not_enough_rows_available(self.k));
+        }
+
+        self.permutation
+            .copy(left_column, left_row, right_column, right_row)
+            .unwrap_or_else(|err| panic!("{err:?}"))
+    }
+
+    fn fill_from_row(
+        &mut self,
+        column: Column<Fixed>,
+        from_row: usize,
+        to: Value<Assigned<F>>,
+    ) -> Result<(), Error> {
+        if !self.usable_rows.contains(&from_row) {
+            return Err(Error::not_enough_rows_available(self.k));
+        }
+
+        let col = self
+            .fixed
+            .get_mut(column.index())
+            .ok_or(Error::BoundsFailure)?;
+
+        let filler = to.assign()?;
+        for row in self.usable_rows.clone().skip(from_row) {
+            col[row] = filler;
+        }
+
+        Ok(())
+    }
+
+    fn get_challenge(&self, _: Challenge) -> Value<F> {
+        Value::unknown()
+    }
+
+    fn push_namespace<NR, N>(&mut self, _: N)
+    where
+        NR: Into<String>,
+        N: FnOnce() -> NR,
+    {
+        // Do nothing; we don't care about namespaces in this context.
+    }
+
+    fn pop_namespace(&mut self, _: Option<String>) {
+        // Do nothing; we don't care about namespaces in this context.
+    }
+}
+
+/// Generate a `VerifyingKey` from an instance of `Circuit`.
+pub fn keygen_vk<'params, C, P, ConcreteCircuit>(
+    params: &P,
+    circuit: &ConcreteCircuit,
+) -> Result<VerifyingKey<C>, Error>
+where
+    C: CurveAffine,
+    P: Params<'params, C>,
+    ConcreteCircuit: Circuit<C::Scalar>,
+{
+    let (domain, cs, config) = create_domain::<C, ConcreteCircuit>(params.k());
+
+    if (params.n() as usize) < cs.minimum_rows() {
+        return Err(Error::not_enough_rows_available(params.k()));
+    }
+
+    let mut assembly: Assembly<C::Scalar> = Assembly {
+        k: params.k(),
+        fixed: vec![domain.empty_lagrange_assigned(); cs.num_fixed_columns],
+        permutation: permutation::keygen::Assembly::new(params.n() as usize, &cs.permutation),
+        selectors: vec![vec![false; params.n() as usize]; cs.num_selectors],
+        usable_rows: 0..params.n() as usize - (cs.blinding_factors() + 1),
+        _marker: std::marker::PhantomData,
+    };
+
+    // Synthesize the circuit to obtain URS
+    ConcreteCircuit::FloorPlanner::synthesize(
+        &mut assembly,
+        circuit,
+        config,
+        cs.constants.clone(),
+    )?;
+
+    let mut fixed = batch_invert_assigned(assembly.fixed);
+    let (cs, selector_polys) = cs.compress_selectors(assembly.selectors.clone());
+    fixed.extend(
+        selector_polys
+            .into_iter()
+            .map(|poly| domain.lagrange_from_vec(poly)),
+    );
+
+    let permutation_vk = assembly
+        .permutation
+        .build_vk(params, &domain, &cs.permutation);
+
+    let fixed_commitments = fixed
+        .iter()
+        .map(|poly| params.commit_lagrange(poly, Blind::default()).to_affine())
+        .collect();
+
+    Ok(VerifyingKey::from_parts(
+        domain,
+        fixed_commitments,
+        permutation_vk,
+        cs,
+        assembly.selectors,
+    ))
+}
+
+/// Generate a `ProvingKey` from a `VerifyingKey` and an instance of `Circuit`.
+pub fn keygen_pk<'params, C, P, ConcreteCircuit>(
+    params: &P,
+    vk: VerifyingKey<C>,
+    circuit: &ConcreteCircuit,
+) -> Result<ProvingKey<C>, Error>
+where
+    C: CurveAffine,
+    P: Params<'params, C>,
+    ConcreteCircuit: Circuit<C::Scalar>,
+{
+    let mut cs = ConstraintSystem::default();
+    let config = ConcreteCircuit::configure(&mut cs);
+
+    let cs = cs;
+
+    if (params.n() as usize) < cs.minimum_rows() {
+        return Err(Error::not_enough_rows_available(params.k()));
+    }
+
+    let mut assembly: Assembly<C::Scalar> = Assembly {
+        k: params.k(),
+        fixed: vec![vk.domain.empty_lagrange_assigned(); cs.num_fixed_columns],
+        permutation: permutation::keygen::Assembly::new(params.n() as usize, &cs.permutation),
+        selectors: vec![vec![false; params.n() as usize]; cs.num_selectors],
+        usable_rows: 0..params.n() as usize - (cs.blinding_factors() + 1),
+        _marker: std::marker::PhantomData,
+    };
+
+    // Synthesize the circuit to obtain URS
+    ConcreteCircuit::FloorPlanner::synthesize(
+        &mut assembly,
+        circuit,
+        config,
+        cs.constants.clone(),
+    )?;
+
+    let mut fixed = batch_invert_assigned(assembly.fixed);
+    let (cs, selector_polys) = cs.compress_selectors(assembly.selectors);
+    fixed.extend(
+        selector_polys
+            .into_iter()
+            .map(|poly| vk.domain.lagrange_from_vec(poly)),
+    );
+
+    let fixed_polys: Vec<_> = fixed
+        .iter()
+        .map(|poly| vk.domain.lagrange_to_coeff(poly.clone()))
+        .collect();
+
+    let fixed_cosets = fixed_polys
+        .iter()
+        .map(|poly| vk.domain.coeff_to_extended(poly.clone()))
+        .collect();
+
+    let permutation_pk = assembly
+        .permutation
+        .build_pk(params, &vk.domain, &cs.permutation);
+
+    // Compute l_0(X)
+    // TODO: this can be done more efficiently
+    let mut l0 = vk.domain.empty_lagrange();
+    l0[0] = C::Scalar::one();
+    let l0 = vk.domain.lagrange_to_coeff(l0);
+    let l0 = vk.domain.coeff_to_extended(l0);
+
+    // Compute l_blind(X) which evaluates to 1 for each blinding factor row
+    // and 0 otherwise over the domain.
+    let mut l_blind = vk.domain.empty_lagrange();
+    for evaluation in l_blind[..].iter_mut().rev().take(cs.blinding_factors()) {
+        *evaluation = C::Scalar::one();
+    }
+    let l_blind = vk.domain.lagrange_to_coeff(l_blind);
+    let l_blind = vk.domain.coeff_to_extended(l_blind);
+
+    // Compute l_last(X) which evaluates to 1 on the first inactive row (just
+    // before the blinding factors) and 0 otherwise over the domain
+    let mut l_last = vk.domain.empty_lagrange();
+    l_last[params.n() as usize - cs.blinding_factors() - 1] = C::Scalar::one();
+    let l_last = vk.domain.lagrange_to_coeff(l_last);
+    let l_last = vk.domain.coeff_to_extended(l_last);
+
+    // Compute l_active_row(X)
+    let one = C::Scalar::one();
+    let mut l_active_row = vk.domain.empty_extended();
+    parallelize(&mut l_active_row, |values, start| {
+        for (i, value) in values.iter_mut().enumerate() {
+            let idx = i + start;
+            *value = one - (l_last[idx] + l_blind[idx]);
+        }
+    });
+
+    // Compute the optimized evaluation data structure
+    let ev = Evaluator::new(&vk.cs);
+
+    Ok(ProvingKey {
+        vk,
+        l0,
+        l_last,
+        l_active_row,
+        fixed_values: fixed,
+        fixed_polys,
+        fixed_cosets,
+        permutation: permutation_pk,
+        ev,
+    })
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/lookup.rs.html b/docs/src/halo2_proofs/plonk/lookup.rs.html new file mode 100644 index 0000000000..69ef54a6c0 --- /dev/null +++ b/docs/src/halo2_proofs/plonk/lookup.rs.html @@ -0,0 +1,190 @@ +lookup.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+
use super::circuit::Expression;
+use ff::Field;
+use std::fmt::{self, Debug};
+
+pub(crate) mod prover;
+pub(crate) mod verifier;
+
+#[derive(Clone)]
+pub struct Argument<F: Field> {
+    pub(crate) name: &'static str,
+    pub(crate) input_expressions: Vec<Expression<F>>,
+    pub(crate) table_expressions: Vec<Expression<F>>,
+}
+
+impl<F: Field> Debug for Argument<F> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_struct("Argument")
+            .field("input_expressions", &self.input_expressions)
+            .field("table_expressions", &self.table_expressions)
+            .finish()
+    }
+}
+
+impl<F: Field> Argument<F> {
+    /// Constructs a new lookup argument.
+    ///
+    /// `table_map` is a sequence of `(input, table)` tuples.
+    pub fn new(name: &'static str, table_map: Vec<(Expression<F>, Expression<F>)>) -> Self {
+        let (input_expressions, table_expressions) = table_map.into_iter().unzip();
+        Argument {
+            name,
+            input_expressions,
+            table_expressions,
+        }
+    }
+
+    pub(crate) fn required_degree(&self) -> usize {
+        assert_eq!(self.input_expressions.len(), self.table_expressions.len());
+
+        // The first value in the permutation poly should be one.
+        // degree 2:
+        // l_0(X) * (1 - z(X)) = 0
+        //
+        // The "last" value in the permutation poly should be a boolean, for
+        // completeness and soundness.
+        // degree 3:
+        // l_last(X) * (z(X)^2 - z(X)) = 0
+        //
+        // Enable the permutation argument for only the rows involved.
+        // degree (2 + input_degree + table_degree) or 4, whichever is larger:
+        // (1 - (l_last(X) + l_blind(X))) * (
+        //   z(\omega X) (a'(X) + \beta) (s'(X) + \gamma)
+        //   - z(X) (\theta^{m-1} a_0(X) + ... + a_{m-1}(X) + \beta) (\theta^{m-1} s_0(X) + ... + s_{m-1}(X) + \gamma)
+        // ) = 0
+        //
+        // The first two values of a' and s' should be the same.
+        // degree 2:
+        // l_0(X) * (a'(X) - s'(X)) = 0
+        //
+        // Either the two values are the same, or the previous
+        // value of a' is the same as the current value.
+        // degree 3:
+        // (1 - (l_last(X) + l_blind(X))) * (a′(X) − s′(X))⋅(a′(X) − a′(\omega^{-1} X)) = 0
+        let mut input_degree = 1;
+        for expr in self.input_expressions.iter() {
+            input_degree = std::cmp::max(input_degree, expr.degree());
+        }
+        let mut table_degree = 1;
+        for expr in self.table_expressions.iter() {
+            table_degree = std::cmp::max(table_degree, expr.degree());
+        }
+
+        // In practice because input_degree and table_degree are initialized to
+        // one, the latter half of this max() invocation is at least 4 always,
+        // rendering this call pointless except to be explicit in case we change
+        // the initialization of input_degree/table_degree in the future.
+        std::cmp::max(
+            // (1 - (l_last + l_blind)) z(\omega X) (a'(X) + \beta) (s'(X) + \gamma)
+            4,
+            // (1 - (l_last + l_blind)) z(X) (\theta^{m-1} a_0(X) + ... + a_{m-1}(X) + \beta) (\theta^{m-1} s_0(X) + ... + s_{m-1}(X) + \gamma)
+            2 + input_degree + table_degree,
+        )
+    }
+
+    /// Returns input of this argument
+    pub fn input_expressions(&self) -> &Vec<Expression<F>> {
+        &self.input_expressions
+    }
+
+    /// Returns table of this argument
+    pub fn table_expressions(&self) -> &Vec<Expression<F>> {
+        &self.table_expressions
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/lookup/prover.rs.html b/docs/src/halo2_proofs/plonk/lookup/prover.rs.html new file mode 100644 index 0000000000..346c67cac3 --- /dev/null +++ b/docs/src/halo2_proofs/plonk/lookup/prover.rs.html @@ -0,0 +1,952 @@ +prover.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+
use super::super::{
+    circuit::Expression, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, Error,
+    ProvingKey,
+};
+use super::Argument;
+use crate::plonk::evaluation::evaluate;
+use crate::{
+    arithmetic::{eval_polynomial, parallelize, CurveAffine, FieldExt},
+    poly::{
+        commitment::{Blind, Params},
+        Coeff, EvaluationDomain, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial, ProverQuery,
+        Rotation,
+    },
+    transcript::{EncodedChallenge, TranscriptWrite},
+};
+use group::{
+    ff::{BatchInvert, Field},
+    Curve,
+};
+use rand_core::RngCore;
+use std::{any::TypeId, convert::TryInto, num::ParseIntError, ops::Index};
+use std::{
+    collections::BTreeMap,
+    iter,
+    ops::{Mul, MulAssign},
+};
+
+#[derive(Debug)]
+pub(in crate::plonk) struct Permuted<C: CurveAffine> {
+    compressed_input_expression: Polynomial<C::Scalar, LagrangeCoeff>,
+    permuted_input_expression: Polynomial<C::Scalar, LagrangeCoeff>,
+    permuted_input_poly: Polynomial<C::Scalar, Coeff>,
+    permuted_input_blind: Blind<C::Scalar>,
+    compressed_table_expression: Polynomial<C::Scalar, LagrangeCoeff>,
+    permuted_table_expression: Polynomial<C::Scalar, LagrangeCoeff>,
+    permuted_table_poly: Polynomial<C::Scalar, Coeff>,
+    permuted_table_blind: Blind<C::Scalar>,
+}
+
+#[derive(Debug)]
+pub(in crate::plonk) struct Committed<C: CurveAffine> {
+    pub(in crate::plonk) permuted_input_poly: Polynomial<C::Scalar, Coeff>,
+    permuted_input_blind: Blind<C::Scalar>,
+    pub(in crate::plonk) permuted_table_poly: Polynomial<C::Scalar, Coeff>,
+    permuted_table_blind: Blind<C::Scalar>,
+    pub(in crate::plonk) product_poly: Polynomial<C::Scalar, Coeff>,
+    product_blind: Blind<C::Scalar>,
+}
+
+pub(in crate::plonk) struct Evaluated<C: CurveAffine> {
+    constructed: Committed<C>,
+}
+
+impl<F: FieldExt> Argument<F> {
+    /// Given a Lookup with input expressions [A_0, A_1, ..., A_{m-1}] and table expressions
+    /// [S_0, S_1, ..., S_{m-1}], this method
+    /// - constructs A_compressed = \theta^{m-1} A_0 + theta^{m-2} A_1 + ... + \theta A_{m-2} + A_{m-1}
+    ///   and S_compressed = \theta^{m-1} S_0 + theta^{m-2} S_1 + ... + \theta S_{m-2} + S_{m-1},
+    /// - permutes A_compressed and S_compressed using permute_expression_pair() helper,
+    ///   obtaining A' and S', and
+    /// - constructs Permuted<C> struct using permuted_input_value = A', and
+    ///   permuted_table_expression = S'.
+    /// The Permuted<C> struct is used to update the Lookup, and is then returned.
+    pub(in crate::plonk) fn commit_permuted<
+        'a,
+        'params: 'a,
+        C,
+        P: Params<'params, C>,
+        E: EncodedChallenge<C>,
+        R: RngCore,
+        T: TranscriptWrite<C, E>,
+    >(
+        &self,
+        pk: &ProvingKey<C>,
+        params: &P,
+        domain: &EvaluationDomain<C::Scalar>,
+        theta: ChallengeTheta<C>,
+        advice_values: &'a [Polynomial<C::Scalar, LagrangeCoeff>],
+        fixed_values: &'a [Polynomial<C::Scalar, LagrangeCoeff>],
+        instance_values: &'a [Polynomial<C::Scalar, LagrangeCoeff>],
+        challenges: &'a [C::Scalar],
+        mut rng: R,
+        transcript: &mut T,
+    ) -> Result<Permuted<C>, Error>
+    where
+        C: CurveAffine<ScalarExt = F>,
+        C::Curve: Mul<F, Output = C::Curve> + MulAssign<F>,
+    {
+        // Closure to get values of expressions and compress them
+        let compress_expressions = |expressions: &[Expression<C::Scalar>]| {
+            let compressed_expression = expressions
+                .iter()
+                .map(|expression| {
+                    pk.vk.domain.lagrange_from_vec(evaluate(
+                        expression,
+                        params.n() as usize,
+                        1,
+                        fixed_values,
+                        advice_values,
+                        instance_values,
+                        challenges,
+                    ))
+                })
+                .fold(domain.empty_lagrange(), |acc, expression| {
+                    acc * *theta + &expression
+                });
+            compressed_expression
+        };
+
+        // Get values of input expressions involved in the lookup and compress them
+        let compressed_input_expression = compress_expressions(&self.input_expressions);
+
+        // Get values of table expressions involved in the lookup and compress them
+        let compressed_table_expression = compress_expressions(&self.table_expressions);
+
+        // Permute compressed (InputExpression, TableExpression) pair
+        let (permuted_input_expression, permuted_table_expression) = permute_expression_pair(
+            pk,
+            params,
+            domain,
+            &mut rng,
+            &compressed_input_expression,
+            &compressed_table_expression,
+        )?;
+
+        // Closure to construct commitment to vector of values
+        let mut commit_values = |values: &Polynomial<C::Scalar, LagrangeCoeff>| {
+            let poly = pk.vk.domain.lagrange_to_coeff(values.clone());
+            let blind = Blind(C::Scalar::random(&mut rng));
+            let commitment = params.commit_lagrange(values, blind).to_affine();
+            (poly, blind, commitment)
+        };
+
+        // Commit to permuted input expression
+        let (permuted_input_poly, permuted_input_blind, permuted_input_commitment) =
+            commit_values(&permuted_input_expression);
+
+        // Commit to permuted table expression
+        let (permuted_table_poly, permuted_table_blind, permuted_table_commitment) =
+            commit_values(&permuted_table_expression);
+
+        // Hash permuted input commitment
+        transcript.write_point(permuted_input_commitment)?;
+
+        // Hash permuted table commitment
+        transcript.write_point(permuted_table_commitment)?;
+
+        Ok(Permuted {
+            compressed_input_expression,
+            permuted_input_expression,
+            permuted_input_poly,
+            permuted_input_blind,
+            compressed_table_expression,
+            permuted_table_expression,
+            permuted_table_poly,
+            permuted_table_blind,
+        })
+    }
+}
+
+impl<C: CurveAffine> Permuted<C> {
+    /// Given a Lookup with input expressions, table expressions, and the permuted
+    /// input expression and permuted table expression, this method constructs the
+    /// grand product polynomial over the lookup. The grand product polynomial
+    /// is used to populate the Product<C> struct. The Product<C> struct is
+    /// added to the Lookup and finally returned by the method.
+    pub(in crate::plonk) fn commit_product<
+        'params,
+        P: Params<'params, C>,
+        E: EncodedChallenge<C>,
+        R: RngCore,
+        T: TranscriptWrite<C, E>,
+    >(
+        self,
+        pk: &ProvingKey<C>,
+        params: &P,
+        beta: ChallengeBeta<C>,
+        gamma: ChallengeGamma<C>,
+        mut rng: R,
+        transcript: &mut T,
+    ) -> Result<Committed<C>, Error> {
+        let blinding_factors = pk.vk.cs.blinding_factors();
+        // Goal is to compute the products of fractions
+        //
+        // Numerator: (\theta^{m-1} a_0(\omega^i) + \theta^{m-2} a_1(\omega^i) + ... + \theta a_{m-2}(\omega^i) + a_{m-1}(\omega^i) + \beta)
+        //            * (\theta^{m-1} s_0(\omega^i) + \theta^{m-2} s_1(\omega^i) + ... + \theta s_{m-2}(\omega^i) + s_{m-1}(\omega^i) + \gamma)
+        // Denominator: (a'(\omega^i) + \beta) (s'(\omega^i) + \gamma)
+        //
+        // where a_j(X) is the jth input expression in this lookup,
+        // where a'(X) is the compression of the permuted input expressions,
+        // s_j(X) is the jth table expression in this lookup,
+        // s'(X) is the compression of the permuted table expressions,
+        // and i is the ith row of the expression.
+        let mut lookup_product = vec![C::Scalar::zero(); params.n() as usize];
+        // Denominator uses the permuted input expression and permuted table expression
+        parallelize(&mut lookup_product, |lookup_product, start| {
+            for ((lookup_product, permuted_input_value), permuted_table_value) in lookup_product
+                .iter_mut()
+                .zip(self.permuted_input_expression[start..].iter())
+                .zip(self.permuted_table_expression[start..].iter())
+            {
+                *lookup_product = (*beta + permuted_input_value) * &(*gamma + permuted_table_value);
+            }
+        });
+
+        // Batch invert to obtain the denominators for the lookup product
+        // polynomials
+        lookup_product.iter_mut().batch_invert();
+
+        // Finish the computation of the entire fraction by computing the numerators
+        // (\theta^{m-1} a_0(\omega^i) + \theta^{m-2} a_1(\omega^i) + ... + \theta a_{m-2}(\omega^i) + a_{m-1}(\omega^i) + \beta)
+        // * (\theta^{m-1} s_0(\omega^i) + \theta^{m-2} s_1(\omega^i) + ... + \theta s_{m-2}(\omega^i) + s_{m-1}(\omega^i) + \gamma)
+        parallelize(&mut lookup_product, |product, start| {
+            for (i, product) in product.iter_mut().enumerate() {
+                let i = i + start;
+
+                *product *= &(self.compressed_input_expression[i] + &*beta);
+                *product *= &(self.compressed_table_expression[i] + &*gamma);
+            }
+        });
+
+        // The product vector is a vector of products of fractions of the form
+        //
+        // Numerator: (\theta^{m-1} a_0(\omega^i) + \theta^{m-2} a_1(\omega^i) + ... + \theta a_{m-2}(\omega^i) + a_{m-1}(\omega^i) + \beta)
+        //            * (\theta^{m-1} s_0(\omega^i) + \theta^{m-2} s_1(\omega^i) + ... + \theta s_{m-2}(\omega^i) + s_{m-1}(\omega^i) + \gamma)
+        // Denominator: (a'(\omega^i) + \beta) (s'(\omega^i) + \gamma)
+        //
+        // where there are m input expressions and m table expressions,
+        // a_j(\omega^i) is the jth input expression in this lookup,
+        // a'j(\omega^i) is the permuted input expression,
+        // s_j(\omega^i) is the jth table expression in this lookup,
+        // s'(\omega^i) is the permuted table expression,
+        // and i is the ith row of the expression.
+
+        // Compute the evaluations of the lookup product polynomial
+        // over our domain, starting with z[0] = 1
+        let z = iter::once(C::Scalar::one())
+            .chain(lookup_product)
+            .scan(C::Scalar::one(), |state, cur| {
+                *state *= &cur;
+                Some(*state)
+            })
+            // Take all rows including the "last" row which should
+            // be a boolean (and ideally 1, else soundness is broken)
+            .take(params.n() as usize - blinding_factors)
+            // Chain random blinding factors.
+            .chain((0..blinding_factors).map(|_| C::Scalar::random(&mut rng)))
+            .collect::<Vec<_>>();
+        assert_eq!(z.len(), params.n() as usize);
+        let z = pk.vk.domain.lagrange_from_vec(z);
+
+        #[cfg(feature = "sanity-checks")]
+        // This test works only with intermediate representations in this method.
+        // It can be used for debugging purposes.
+        {
+            // While in Lagrange basis, check that product is correctly constructed
+            let u = (params.n() as usize) - (blinding_factors + 1);
+
+            // l_0(X) * (1 - z(X)) = 0
+            assert_eq!(z[0], C::Scalar::one());
+
+            // z(\omega X) (a'(X) + \beta) (s'(X) + \gamma)
+            // - z(X) (\theta^{m-1} a_0(X) + ... + a_{m-1}(X) + \beta) (\theta^{m-1} s_0(X) + ... + s_{m-1}(X) + \gamma)
+            for i in 0..u {
+                let mut left = z[i + 1];
+                let permuted_input_value = &self.permuted_input_expression[i];
+
+                let permuted_table_value = &self.permuted_table_expression[i];
+
+                left *= &(*beta + permuted_input_value);
+                left *= &(*gamma + permuted_table_value);
+
+                let mut right = z[i];
+                let mut input_term = self.compressed_input_expression[i];
+                let mut table_term = self.compressed_table_expression[i];
+
+                input_term += &(*beta);
+                table_term += &(*gamma);
+                right *= &(input_term * &table_term);
+
+                assert_eq!(left, right);
+            }
+
+            // l_last(X) * (z(X)^2 - z(X)) = 0
+            // Assertion will fail only when soundness is broken, in which
+            // case this z[u] value will be zero. (bad!)
+            assert_eq!(z[u], C::Scalar::one());
+        }
+
+        let product_blind = Blind(C::Scalar::random(rng));
+        let product_commitment = params.commit_lagrange(&z, product_blind).to_affine();
+        let z = pk.vk.domain.lagrange_to_coeff(z);
+
+        // Hash product commitment
+        transcript.write_point(product_commitment)?;
+
+        Ok(Committed::<C> {
+            permuted_input_poly: self.permuted_input_poly,
+            permuted_input_blind: self.permuted_input_blind,
+            permuted_table_poly: self.permuted_table_poly,
+            permuted_table_blind: self.permuted_table_blind,
+            product_poly: z,
+            product_blind,
+        })
+    }
+}
+
+impl<C: CurveAffine> Committed<C> {
+    pub(in crate::plonk) fn evaluate<E: EncodedChallenge<C>, T: TranscriptWrite<C, E>>(
+        self,
+        pk: &ProvingKey<C>,
+        x: ChallengeX<C>,
+        transcript: &mut T,
+    ) -> Result<Evaluated<C>, Error> {
+        let domain = &pk.vk.domain;
+        let x_inv = domain.rotate_omega(*x, Rotation::prev());
+        let x_next = domain.rotate_omega(*x, Rotation::next());
+
+        let product_eval = eval_polynomial(&self.product_poly, *x);
+        let product_next_eval = eval_polynomial(&self.product_poly, x_next);
+        let permuted_input_eval = eval_polynomial(&self.permuted_input_poly, *x);
+        let permuted_input_inv_eval = eval_polynomial(&self.permuted_input_poly, x_inv);
+        let permuted_table_eval = eval_polynomial(&self.permuted_table_poly, *x);
+
+        // Hash each advice evaluation
+        for eval in iter::empty()
+            .chain(Some(product_eval))
+            .chain(Some(product_next_eval))
+            .chain(Some(permuted_input_eval))
+            .chain(Some(permuted_input_inv_eval))
+            .chain(Some(permuted_table_eval))
+        {
+            transcript.write_scalar(eval)?;
+        }
+
+        Ok(Evaluated { constructed: self })
+    }
+}
+
+impl<C: CurveAffine> Evaluated<C> {
+    pub(in crate::plonk) fn open<'a>(
+        &'a self,
+        pk: &'a ProvingKey<C>,
+        x: ChallengeX<C>,
+    ) -> impl Iterator<Item = ProverQuery<'a, C>> + Clone {
+        let x_inv = pk.vk.domain.rotate_omega(*x, Rotation::prev());
+        let x_next = pk.vk.domain.rotate_omega(*x, Rotation::next());
+
+        iter::empty()
+            // Open lookup product commitments at x
+            .chain(Some(ProverQuery {
+                point: *x,
+                poly: &self.constructed.product_poly,
+                blind: self.constructed.product_blind,
+            }))
+            // Open lookup input commitments at x
+            .chain(Some(ProverQuery {
+                point: *x,
+                poly: &self.constructed.permuted_input_poly,
+                blind: self.constructed.permuted_input_blind,
+            }))
+            // Open lookup table commitments at x
+            .chain(Some(ProverQuery {
+                point: *x,
+                poly: &self.constructed.permuted_table_poly,
+                blind: self.constructed.permuted_table_blind,
+            }))
+            // Open lookup input commitments at x_inv
+            .chain(Some(ProverQuery {
+                point: x_inv,
+                poly: &self.constructed.permuted_input_poly,
+                blind: self.constructed.permuted_input_blind,
+            }))
+            // Open lookup product commitments at x_next
+            .chain(Some(ProverQuery {
+                point: x_next,
+                poly: &self.constructed.product_poly,
+                blind: self.constructed.product_blind,
+            }))
+    }
+}
+
+type ExpressionPair<F> = (Polynomial<F, LagrangeCoeff>, Polynomial<F, LagrangeCoeff>);
+
+/// Given a vector of input values A and a vector of table values S,
+/// this method permutes A and S to produce A' and S', such that:
+/// - like values in A' are vertically adjacent to each other; and
+/// - the first row in a sequence of like values in A' is the row
+///   that has the corresponding value in S'.
+/// This method returns (A', S') if no errors are encountered.
+fn permute_expression_pair<'params, C: CurveAffine, P: Params<'params, C>, R: RngCore>(
+    pk: &ProvingKey<C>,
+    params: &P,
+    domain: &EvaluationDomain<C::Scalar>,
+    mut rng: R,
+    input_expression: &Polynomial<C::Scalar, LagrangeCoeff>,
+    table_expression: &Polynomial<C::Scalar, LagrangeCoeff>,
+) -> Result<ExpressionPair<C::Scalar>, Error> {
+    let blinding_factors = pk.vk.cs.blinding_factors();
+    let usable_rows = params.n() as usize - (blinding_factors + 1);
+
+    let mut permuted_input_expression: Vec<C::Scalar> = input_expression.to_vec();
+    permuted_input_expression.truncate(usable_rows);
+
+    // Sort input lookup expression values
+    permuted_input_expression.sort();
+
+    // A BTreeMap of each unique element in the table expression and its count
+    let mut leftover_table_map: BTreeMap<C::Scalar, u32> = table_expression
+        .iter()
+        .take(usable_rows)
+        .fold(BTreeMap::new(), |mut acc, coeff| {
+            *acc.entry(*coeff).or_insert(0) += 1;
+            acc
+        });
+    let mut permuted_table_coeffs = vec![C::Scalar::zero(); usable_rows];
+
+    let mut repeated_input_rows = permuted_input_expression
+        .iter()
+        .zip(permuted_table_coeffs.iter_mut())
+        .enumerate()
+        .filter_map(|(row, (input_value, table_value))| {
+            // If this is the first occurrence of `input_value` in the input expression
+            if row == 0 || *input_value != permuted_input_expression[row - 1] {
+                *table_value = *input_value;
+                // Remove one instance of input_value from leftover_table_map
+                if let Some(count) = leftover_table_map.get_mut(input_value) {
+                    assert!(*count > 0);
+                    *count -= 1;
+                    None
+                } else {
+                    // Return error if input_value not found
+                    Some(Err(Error::ConstraintSystemFailure))
+                }
+            // If input value is repeated
+            } else {
+                Some(Ok(row))
+            }
+        })
+        .collect::<Result<Vec<_>, _>>()?;
+
+    // Populate permuted table at unfilled rows with leftover table elements
+    for (coeff, count) in leftover_table_map.iter() {
+        for _ in 0..*count {
+            permuted_table_coeffs[repeated_input_rows.pop().unwrap() as usize] = *coeff;
+        }
+    }
+    assert!(repeated_input_rows.is_empty());
+
+    permuted_input_expression
+        .extend((0..(blinding_factors + 1)).map(|_| C::Scalar::random(&mut rng)));
+    permuted_table_coeffs.extend((0..(blinding_factors + 1)).map(|_| C::Scalar::random(&mut rng)));
+    assert_eq!(permuted_input_expression.len(), params.n() as usize);
+    assert_eq!(permuted_table_coeffs.len(), params.n() as usize);
+
+    #[cfg(feature = "sanity-checks")]
+    {
+        let mut last = None;
+        for (a, b) in permuted_input_expression
+            .iter()
+            .zip(permuted_table_coeffs.iter())
+            .take(usable_rows)
+        {
+            if *a != *b {
+                assert_eq!(*a, last.unwrap());
+            }
+            last = Some(*a);
+        }
+    }
+
+    Ok((
+        domain.lagrange_from_vec(permuted_input_expression),
+        domain.lagrange_from_vec(permuted_table_coeffs),
+    ))
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/lookup/verifier.rs.html b/docs/src/halo2_proofs/plonk/lookup/verifier.rs.html new file mode 100644 index 0000000000..0af88e7a2e --- /dev/null +++ b/docs/src/halo2_proofs/plonk/lookup/verifier.rs.html @@ -0,0 +1,422 @@ +verifier.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+
use std::iter;
+
+use super::super::{
+    circuit::Expression, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX,
+};
+use super::Argument;
+use crate::{
+    arithmetic::{CurveAffine, FieldExt},
+    plonk::{Error, VerifyingKey},
+    poly::{commitment::MSM, Rotation, VerifierQuery},
+    transcript::{EncodedChallenge, TranscriptRead},
+};
+use ff::Field;
+
+pub struct PermutationCommitments<C: CurveAffine> {
+    permuted_input_commitment: C,
+    permuted_table_commitment: C,
+}
+
+pub struct Committed<C: CurveAffine> {
+    permuted: PermutationCommitments<C>,
+    product_commitment: C,
+}
+
+pub struct Evaluated<C: CurveAffine> {
+    committed: Committed<C>,
+    product_eval: C::Scalar,
+    product_next_eval: C::Scalar,
+    permuted_input_eval: C::Scalar,
+    permuted_input_inv_eval: C::Scalar,
+    permuted_table_eval: C::Scalar,
+}
+
+impl<F: FieldExt> Argument<F> {
+    pub(in crate::plonk) fn read_permuted_commitments<
+        C: CurveAffine,
+        E: EncodedChallenge<C>,
+        T: TranscriptRead<C, E>,
+    >(
+        &self,
+        transcript: &mut T,
+    ) -> Result<PermutationCommitments<C>, Error> {
+        let permuted_input_commitment = transcript.read_point()?;
+        let permuted_table_commitment = transcript.read_point()?;
+
+        Ok(PermutationCommitments {
+            permuted_input_commitment,
+            permuted_table_commitment,
+        })
+    }
+}
+
+impl<C: CurveAffine> PermutationCommitments<C> {
+    pub(in crate::plonk) fn read_product_commitment<
+        E: EncodedChallenge<C>,
+        T: TranscriptRead<C, E>,
+    >(
+        self,
+        transcript: &mut T,
+    ) -> Result<Committed<C>, Error> {
+        let product_commitment = transcript.read_point()?;
+
+        Ok(Committed {
+            permuted: self,
+            product_commitment,
+        })
+    }
+}
+
+impl<C: CurveAffine> Committed<C> {
+    pub(crate) fn evaluate<E: EncodedChallenge<C>, T: TranscriptRead<C, E>>(
+        self,
+        transcript: &mut T,
+    ) -> Result<Evaluated<C>, Error> {
+        let product_eval = transcript.read_scalar()?;
+        let product_next_eval = transcript.read_scalar()?;
+        let permuted_input_eval = transcript.read_scalar()?;
+        let permuted_input_inv_eval = transcript.read_scalar()?;
+        let permuted_table_eval = transcript.read_scalar()?;
+
+        Ok(Evaluated {
+            committed: self,
+            product_eval,
+            product_next_eval,
+            permuted_input_eval,
+            permuted_input_inv_eval,
+            permuted_table_eval,
+        })
+    }
+}
+
+impl<C: CurveAffine> Evaluated<C> {
+    pub(in crate::plonk) fn expressions<'a>(
+        &'a self,
+        l_0: C::Scalar,
+        l_last: C::Scalar,
+        l_blind: C::Scalar,
+        argument: &'a Argument<C::Scalar>,
+        theta: ChallengeTheta<C>,
+        beta: ChallengeBeta<C>,
+        gamma: ChallengeGamma<C>,
+        advice_evals: &[C::Scalar],
+        fixed_evals: &[C::Scalar],
+        instance_evals: &[C::Scalar],
+        challenges: &[C::Scalar],
+    ) -> impl Iterator<Item = C::Scalar> + 'a {
+        let active_rows = C::Scalar::one() - (l_last + l_blind);
+
+        let product_expression = || {
+            // z(\omega X) (a'(X) + \beta) (s'(X) + \gamma)
+            // - z(X) (\theta^{m-1} a_0(X) + ... + a_{m-1}(X) + \beta) (\theta^{m-1} s_0(X) + ... + s_{m-1}(X) + \gamma)
+            let left = self.product_next_eval
+                * &(self.permuted_input_eval + &*beta)
+                * &(self.permuted_table_eval + &*gamma);
+
+            let compress_expressions = |expressions: &[Expression<C::Scalar>]| {
+                expressions
+                    .iter()
+                    .map(|expression| {
+                        expression.evaluate(
+                            &|scalar| scalar,
+                            &|_| panic!("virtual selectors are removed during optimization"),
+                            &|query| fixed_evals[query.index],
+                            &|query| advice_evals[query.index],
+                            &|query| instance_evals[query.index],
+                            &|challenge| challenges[challenge.index()],
+                            &|a| -a,
+                            &|a, b| a + &b,
+                            &|a, b| a * &b,
+                            &|a, scalar| a * &scalar,
+                        )
+                    })
+                    .fold(C::Scalar::zero(), |acc, eval| acc * &*theta + &eval)
+            };
+            let right = self.product_eval
+                * &(compress_expressions(&argument.input_expressions) + &*beta)
+                * &(compress_expressions(&argument.table_expressions) + &*gamma);
+
+            (left - &right) * &active_rows
+        };
+
+        std::iter::empty()
+            .chain(
+                // l_0(X) * (1 - z'(X)) = 0
+                Some(l_0 * &(C::Scalar::one() - &self.product_eval)),
+            )
+            .chain(
+                // l_last(X) * (z(X)^2 - z(X)) = 0
+                Some(l_last * &(self.product_eval.square() - &self.product_eval)),
+            )
+            .chain(
+                // (1 - (l_last(X) + l_blind(X))) * (
+                //   z(\omega X) (a'(X) + \beta) (s'(X) + \gamma)
+                //   - z(X) (\theta^{m-1} a_0(X) + ... + a_{m-1}(X) + \beta) (\theta^{m-1} s_0(X) + ... + s_{m-1}(X) + \gamma)
+                // ) = 0
+                Some(product_expression()),
+            )
+            .chain(Some(
+                // l_0(X) * (a'(X) - s'(X)) = 0
+                l_0 * &(self.permuted_input_eval - &self.permuted_table_eval),
+            ))
+            .chain(Some(
+                // (1 - (l_last(X) + l_blind(X))) * (a′(X) − s′(X))⋅(a′(X) − a′(\omega^{-1} X)) = 0
+                (self.permuted_input_eval - &self.permuted_table_eval)
+                    * &(self.permuted_input_eval - &self.permuted_input_inv_eval)
+                    * &active_rows,
+            ))
+    }
+
+    pub(in crate::plonk) fn queries<'r, M: MSM<C> + 'r>(
+        &'r self,
+        vk: &'r VerifyingKey<C>,
+        x: ChallengeX<C>,
+    ) -> impl Iterator<Item = VerifierQuery<'r, C, M>> + Clone {
+        let x_inv = vk.domain.rotate_omega(*x, Rotation::prev());
+        let x_next = vk.domain.rotate_omega(*x, Rotation::next());
+
+        iter::empty()
+            // Open lookup product commitment at x
+            .chain(Some(VerifierQuery::new_commitment(
+                &self.committed.product_commitment,
+                *x,
+                self.product_eval,
+            )))
+            // Open lookup input commitments at x
+            .chain(Some(VerifierQuery::new_commitment(
+                &self.committed.permuted.permuted_input_commitment,
+                *x,
+                self.permuted_input_eval,
+            )))
+            // Open lookup table commitments at x
+            .chain(Some(VerifierQuery::new_commitment(
+                &self.committed.permuted.permuted_table_commitment,
+                *x,
+                self.permuted_table_eval,
+            )))
+            // Open lookup input commitments at \omega^{-1} x
+            .chain(Some(VerifierQuery::new_commitment(
+                &self.committed.permuted.permuted_input_commitment,
+                x_inv,
+                self.permuted_input_inv_eval,
+            )))
+            // Open lookup product commitment at \omega x
+            .chain(Some(VerifierQuery::new_commitment(
+                &self.committed.product_commitment,
+                x_next,
+                self.product_next_eval,
+            )))
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/permutation.rs.html b/docs/src/halo2_proofs/plonk/permutation.rs.html new file mode 100644 index 0000000000..aa6ae1940c --- /dev/null +++ b/docs/src/halo2_proofs/plonk/permutation.rs.html @@ -0,0 +1,320 @@ +permutation.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+
use super::circuit::{Any, Column};
+use crate::{
+    arithmetic::CurveAffine,
+    helpers::{
+        polynomial_slice_byte_length, read_polynomial_vec, write_polynomial_slice,
+        SerdeCurveAffine, SerdePrimeField,
+    },
+    poly::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial},
+    SerdeFormat,
+};
+use ff::PrimeField;
+
+pub(crate) mod keygen;
+pub(crate) mod prover;
+pub(crate) mod verifier;
+
+use std::io;
+
+/// A permutation argument.
+#[derive(Debug, Clone)]
+pub struct Argument {
+    /// A sequence of columns involved in the argument.
+    pub(super) columns: Vec<Column<Any>>,
+}
+
+impl Argument {
+    pub(crate) fn new() -> Self {
+        Argument { columns: vec![] }
+    }
+
+    /// Returns the minimum circuit degree required by the permutation argument.
+    /// The argument may use larger degree gates depending on the actual
+    /// circuit's degree and how many columns are involved in the permutation.
+    pub(crate) fn required_degree(&self) -> usize {
+        // degree 2:
+        // l_0(X) * (1 - z(X)) = 0
+        //
+        // We will fit as many polynomials p_i(X) as possible
+        // into the required degree of the circuit, so the
+        // following will not affect the required degree of
+        // this middleware.
+        //
+        // (1 - (l_last(X) + l_blind(X))) * (
+        //   z(\omega X) \prod (p(X) + \beta s_i(X) + \gamma)
+        // - z(X) \prod (p(X) + \delta^i \beta X + \gamma)
+        // )
+        //
+        // On the first sets of columns, except the first
+        // set, we will do
+        //
+        // l_0(X) * (z(X) - z'(\omega^(last) X)) = 0
+        //
+        // where z'(X) is the permutation for the previous set
+        // of columns.
+        //
+        // On the final set of columns, we will do
+        //
+        // degree 3:
+        // l_last(X) * (z'(X)^2 - z'(X)) = 0
+        //
+        // which will allow the last value to be zero to
+        // ensure the argument is perfectly complete.
+
+        // There are constraints of degree 3 regardless of the
+        // number of columns involved.
+        3
+    }
+
+    pub(crate) fn add_column(&mut self, column: Column<Any>) {
+        if !self.columns.contains(&column) {
+            self.columns.push(column);
+        }
+    }
+
+    pub fn get_columns(&self) -> Vec<Column<Any>> {
+        self.columns.clone()
+    }
+}
+
+/// The verifying key for a single permutation argument.
+#[derive(Clone, Debug)]
+pub struct VerifyingKey<C: CurveAffine> {
+    commitments: Vec<C>,
+}
+
+impl<C: CurveAffine> VerifyingKey<C> {
+    /// Returns commitments of sigma polynomials
+    pub fn commitments(&self) -> &Vec<C> {
+        &self.commitments
+    }
+
+    pub(crate) fn write<W: io::Write>(&self, writer: &mut W, format: SerdeFormat)
+    where
+        C: SerdeCurveAffine,
+    {
+        for commitment in &self.commitments {
+            commitment.write(writer, format);
+        }
+    }
+
+    pub(crate) fn read<R: io::Read>(
+        reader: &mut R,
+        argument: &Argument,
+        format: SerdeFormat,
+    ) -> Self
+    where
+        C: SerdeCurveAffine,
+    {
+        let commitments = (0..argument.columns.len())
+            .map(|_| C::read(reader, format))
+            .collect();
+        VerifyingKey { commitments }
+    }
+
+    pub(crate) fn bytes_length(&self) -> usize {
+        self.commitments.len() * C::default().to_bytes().as_ref().len()
+    }
+}
+
+/// The proving key for a single permutation argument.
+#[derive(Clone, Debug)]
+pub(crate) struct ProvingKey<C: CurveAffine> {
+    permutations: Vec<Polynomial<C::Scalar, LagrangeCoeff>>,
+    polys: Vec<Polynomial<C::Scalar, Coeff>>,
+    pub(super) cosets: Vec<Polynomial<C::Scalar, ExtendedLagrangeCoeff>>,
+}
+
+impl<C: SerdeCurveAffine> ProvingKey<C>
+where
+    C::Scalar: SerdePrimeField,
+{
+    /// Reads proving key for a single permutation argument from buffer using `Polynomial::read`.  
+    pub(super) fn read<R: io::Read>(reader: &mut R, format: SerdeFormat) -> Self {
+        let permutations = read_polynomial_vec(reader, format);
+        let polys = read_polynomial_vec(reader, format);
+        let cosets = read_polynomial_vec(reader, format);
+        ProvingKey {
+            permutations,
+            polys,
+            cosets,
+        }
+    }
+
+    /// Writes proving key for a single permutation argument to buffer using `Polynomial::write`.  
+    pub(super) fn write<W: io::Write>(&self, writer: &mut W, format: SerdeFormat) {
+        write_polynomial_slice(&self.permutations, writer, format);
+        write_polynomial_slice(&self.polys, writer, format);
+        write_polynomial_slice(&self.cosets, writer, format);
+    }
+}
+
+impl<C: CurveAffine> ProvingKey<C> {
+    /// Gets the total number of bytes in the serialization of `self`
+    pub(super) fn bytes_length(&self) -> usize {
+        polynomial_slice_byte_length(&self.permutations)
+            + polynomial_slice_byte_length(&self.polys)
+            + polynomial_slice_byte_length(&self.cosets)
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/permutation/keygen.rs.html b/docs/src/halo2_proofs/plonk/permutation/keygen.rs.html new file mode 100644 index 0000000000..932155c356 --- /dev/null +++ b/docs/src/halo2_proofs/plonk/permutation/keygen.rs.html @@ -0,0 +1,422 @@ +keygen.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+
use ff::Field;
+use group::Curve;
+
+use super::{Argument, ProvingKey, VerifyingKey};
+use crate::{
+    arithmetic::{CurveAffine, FieldExt},
+    plonk::{Any, Column, Error},
+    poly::{
+        commitment::{Blind, CommitmentScheme, Params},
+        EvaluationDomain,
+    },
+};
+
+#[derive(Debug)]
+pub(crate) struct Assembly {
+    columns: Vec<Column<Any>>,
+    pub(crate) mapping: Vec<Vec<(usize, usize)>>,
+    aux: Vec<Vec<(usize, usize)>>,
+    sizes: Vec<Vec<usize>>,
+}
+
+impl Assembly {
+    pub(crate) fn new(n: usize, p: &Argument) -> Self {
+        // Initialize the copy vector to keep track of copy constraints in all
+        // the permutation arguments.
+        let mut columns = vec![];
+        for i in 0..p.columns.len() {
+            // Computes [(i, 0), (i, 1), ..., (i, n - 1)]
+            columns.push((0..n).map(|j| (i, j)).collect());
+        }
+
+        // Before any equality constraints are applied, every cell in the permutation is
+        // in a 1-cycle; therefore mapping and aux are identical, because every cell is
+        // its own distinguished element.
+        Assembly {
+            columns: p.columns.clone(),
+            mapping: columns.clone(),
+            aux: columns,
+            sizes: vec![vec![1usize; n]; p.columns.len()],
+        }
+    }
+
+    pub(crate) fn copy(
+        &mut self,
+        left_column: Column<Any>,
+        left_row: usize,
+        right_column: Column<Any>,
+        right_row: usize,
+    ) -> Result<(), Error> {
+        let left_column = self
+            .columns
+            .iter()
+            .position(|c| c == &left_column)
+            .ok_or(Error::ColumnNotInPermutation(left_column))?;
+        let right_column = self
+            .columns
+            .iter()
+            .position(|c| c == &right_column)
+            .ok_or(Error::ColumnNotInPermutation(right_column))?;
+
+        // Check bounds
+        if left_row >= self.mapping[left_column].len()
+            || right_row >= self.mapping[right_column].len()
+        {
+            return Err(Error::BoundsFailure);
+        }
+
+        // See book/src/design/permutation.md for a description of this algorithm.
+
+        let mut left_cycle = self.aux[left_column][left_row];
+        let mut right_cycle = self.aux[right_column][right_row];
+
+        // If left and right are in the same cycle, do nothing.
+        if left_cycle == right_cycle {
+            return Ok(());
+        }
+
+        if self.sizes[left_cycle.0][left_cycle.1] < self.sizes[right_cycle.0][right_cycle.1] {
+            std::mem::swap(&mut left_cycle, &mut right_cycle);
+        }
+
+        // Merge the right cycle into the left one.
+        self.sizes[left_cycle.0][left_cycle.1] += self.sizes[right_cycle.0][right_cycle.1];
+        let mut i = right_cycle;
+        loop {
+            self.aux[i.0][i.1] = left_cycle;
+            i = self.mapping[i.0][i.1];
+            if i == right_cycle {
+                break;
+            }
+        }
+
+        let tmp = self.mapping[left_column][left_row];
+        self.mapping[left_column][left_row] = self.mapping[right_column][right_row];
+        self.mapping[right_column][right_row] = tmp;
+
+        Ok(())
+    }
+
+    pub(crate) fn build_vk<'params, C: CurveAffine, P: Params<'params, C>>(
+        self,
+        params: &P,
+        domain: &EvaluationDomain<C::Scalar>,
+        p: &Argument,
+    ) -> VerifyingKey<C> {
+        // Compute [omega^0, omega^1, ..., omega^{params.n - 1}]
+        let mut omega_powers = Vec::with_capacity(params.n() as usize);
+        {
+            let mut cur = C::Scalar::one();
+            for _ in 0..params.n() {
+                omega_powers.push(cur);
+                cur *= &domain.get_omega();
+            }
+        }
+
+        // Compute [omega_powers * \delta^0, omega_powers * \delta^1, ..., omega_powers * \delta^m]
+        let mut deltaomega = Vec::with_capacity(p.columns.len());
+        {
+            let mut cur = C::Scalar::one();
+            for _ in 0..p.columns.len() {
+                let mut omega_powers = omega_powers.clone();
+                for o in &mut omega_powers {
+                    *o *= &cur;
+                }
+
+                deltaomega.push(omega_powers);
+
+                cur *= &C::Scalar::DELTA;
+            }
+        }
+
+        // Pre-compute commitments for the URS.
+        let mut commitments = vec![];
+        for i in 0..p.columns.len() {
+            // Computes the permutation polynomial based on the permutation
+            // description in the assembly.
+            let mut permutation_poly = domain.empty_lagrange();
+            for (j, p) in permutation_poly.iter_mut().enumerate() {
+                let (permuted_i, permuted_j) = self.mapping[i][j];
+                *p = deltaomega[permuted_i][permuted_j];
+            }
+
+            // Compute commitment to permutation polynomial
+            commitments.push(
+                params
+                    .commit_lagrange(&permutation_poly, Blind::default())
+                    .to_affine(),
+            );
+        }
+        VerifyingKey { commitments }
+    }
+
+    pub(crate) fn build_pk<'params, C: CurveAffine, P: Params<'params, C>>(
+        self,
+        params: &P,
+        domain: &EvaluationDomain<C::Scalar>,
+        p: &Argument,
+    ) -> ProvingKey<C> {
+        // Compute [omega^0, omega^1, ..., omega^{params.n - 1}]
+        let mut omega_powers = Vec::with_capacity(params.n() as usize);
+        {
+            let mut cur = C::Scalar::one();
+            for _ in 0..params.n() {
+                omega_powers.push(cur);
+                cur *= &domain.get_omega();
+            }
+        }
+
+        // Compute [omega_powers * \delta^0, omega_powers * \delta^1, ..., omega_powers * \delta^m]
+        let mut deltaomega = Vec::with_capacity(p.columns.len());
+        {
+            let mut cur = C::Scalar::one();
+            for _ in 0..p.columns.len() {
+                let mut omega_powers = omega_powers.clone();
+                for o in &mut omega_powers {
+                    *o *= &cur;
+                }
+
+                deltaomega.push(omega_powers);
+
+                cur *= &C::Scalar::DELTA;
+            }
+        }
+
+        // Compute permutation polynomials, convert to coset form.
+        let mut permutations = vec![];
+        let mut polys = vec![];
+        let mut cosets = vec![];
+        for i in 0..p.columns.len() {
+            // Computes the permutation polynomial based on the permutation
+            // description in the assembly.
+            let mut permutation_poly = domain.empty_lagrange();
+            for (j, p) in permutation_poly.iter_mut().enumerate() {
+                let (permuted_i, permuted_j) = self.mapping[i][j];
+                *p = deltaomega[permuted_i][permuted_j];
+            }
+
+            // Store permutation polynomial and precompute its coset evaluation
+            permutations.push(permutation_poly.clone());
+            let poly = domain.lagrange_to_coeff(permutation_poly);
+            polys.push(poly.clone());
+            cosets.push(domain.coeff_to_extended(poly));
+        }
+        ProvingKey {
+            permutations,
+            polys,
+            cosets,
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/permutation/prover.rs.html b/docs/src/halo2_proofs/plonk/permutation/prover.rs.html new file mode 100644 index 0000000000..7ff0085d50 --- /dev/null +++ b/docs/src/halo2_proofs/plonk/permutation/prover.rs.html @@ -0,0 +1,658 @@ +prover.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+
use group::{
+    ff::{BatchInvert, Field},
+    Curve,
+};
+use rand_core::RngCore;
+use std::iter::{self, ExactSizeIterator};
+
+use super::super::{circuit::Any, ChallengeBeta, ChallengeGamma, ChallengeX};
+use super::{Argument, ProvingKey};
+use crate::{
+    arithmetic::{eval_polynomial, parallelize, CurveAffine, FieldExt},
+    plonk::{self, Error},
+    poly::{
+        self,
+        commitment::{Blind, Params},
+        Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial, ProverQuery, Rotation,
+    },
+    transcript::{EncodedChallenge, TranscriptWrite},
+};
+
+pub(crate) struct CommittedSet<C: CurveAffine> {
+    pub(crate) permutation_product_poly: Polynomial<C::Scalar, Coeff>,
+    pub(crate) permutation_product_coset: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
+    permutation_product_blind: Blind<C::Scalar>,
+}
+
+pub(crate) struct Committed<C: CurveAffine> {
+    pub(crate) sets: Vec<CommittedSet<C>>,
+}
+
+pub struct ConstructedSet<C: CurveAffine> {
+    permutation_product_poly: Polynomial<C::Scalar, Coeff>,
+    permutation_product_blind: Blind<C::Scalar>,
+}
+
+pub(crate) struct Constructed<C: CurveAffine> {
+    sets: Vec<ConstructedSet<C>>,
+}
+
+pub(crate) struct Evaluated<C: CurveAffine> {
+    constructed: Constructed<C>,
+}
+
+impl Argument {
+    pub(in crate::plonk) fn commit<
+        'params,
+        C: CurveAffine,
+        P: Params<'params, C>,
+        E: EncodedChallenge<C>,
+        R: RngCore,
+        T: TranscriptWrite<C, E>,
+    >(
+        &self,
+        params: &P,
+        pk: &plonk::ProvingKey<C>,
+        pkey: &ProvingKey<C>,
+        advice: &[Polynomial<C::Scalar, LagrangeCoeff>],
+        fixed: &[Polynomial<C::Scalar, LagrangeCoeff>],
+        instance: &[Polynomial<C::Scalar, LagrangeCoeff>],
+        beta: ChallengeBeta<C>,
+        gamma: ChallengeGamma<C>,
+        mut rng: R,
+        transcript: &mut T,
+    ) -> Result<Committed<C>, Error> {
+        let domain = &pk.vk.domain;
+
+        // How many columns can be included in a single permutation polynomial?
+        // We need to multiply by z(X) and (1 - (l_last(X) + l_blind(X))). This
+        // will never underflow because of the requirement of at least a degree
+        // 3 circuit for the permutation argument.
+        assert!(pk.vk.cs_degree >= 3);
+        let chunk_len = pk.vk.cs_degree - 2;
+        let blinding_factors = pk.vk.cs.blinding_factors();
+
+        // Each column gets its own delta power.
+        let mut deltaomega = C::Scalar::one();
+
+        // Track the "last" value from the previous column set
+        let mut last_z = C::Scalar::one();
+
+        let mut sets = vec![];
+
+        for (columns, permutations) in self
+            .columns
+            .chunks(chunk_len)
+            .zip(pkey.permutations.chunks(chunk_len))
+        {
+            // Goal is to compute the products of fractions
+            //
+            // (p_j(\omega^i) + \delta^j \omega^i \beta + \gamma) /
+            // (p_j(\omega^i) + \beta s_j(\omega^i) + \gamma)
+            //
+            // where p_j(X) is the jth column in this permutation,
+            // and i is the ith row of the column.
+
+            let mut modified_values = vec![C::Scalar::one(); params.n() as usize];
+
+            // Iterate over each column of the permutation
+            for (&column, permuted_column_values) in columns.iter().zip(permutations.iter()) {
+                let values = match column.column_type() {
+                    Any::Advice(_) => advice,
+                    Any::Fixed => fixed,
+                    Any::Instance => instance,
+                };
+                parallelize(&mut modified_values, |modified_values, start| {
+                    for ((modified_values, value), permuted_value) in modified_values
+                        .iter_mut()
+                        .zip(values[column.index()][start..].iter())
+                        .zip(permuted_column_values[start..].iter())
+                    {
+                        *modified_values *= &(*beta * permuted_value + &*gamma + value);
+                    }
+                });
+            }
+
+            // Invert to obtain the denominator for the permutation product polynomial
+            modified_values.batch_invert();
+
+            // Iterate over each column again, this time finishing the computation
+            // of the entire fraction by computing the numerators
+            for &column in columns.iter() {
+                let omega = domain.get_omega();
+                let values = match column.column_type() {
+                    Any::Advice(_) => advice,
+                    Any::Fixed => fixed,
+                    Any::Instance => instance,
+                };
+                parallelize(&mut modified_values, |modified_values, start| {
+                    let mut deltaomega = deltaomega * &omega.pow_vartime(&[start as u64, 0, 0, 0]);
+                    for (modified_values, value) in modified_values
+                        .iter_mut()
+                        .zip(values[column.index()][start..].iter())
+                    {
+                        // Multiply by p_j(\omega^i) + \delta^j \omega^i \beta
+                        *modified_values *= &(deltaomega * &*beta + &*gamma + value);
+                        deltaomega *= &omega;
+                    }
+                });
+                deltaomega *= &C::Scalar::DELTA;
+            }
+
+            // The modified_values vector is a vector of products of fractions
+            // of the form
+            //
+            // (p_j(\omega^i) + \delta^j \omega^i \beta + \gamma) /
+            // (p_j(\omega^i) + \beta s_j(\omega^i) + \gamma)
+            //
+            // where i is the index into modified_values, for the jth column in
+            // the permutation
+
+            // Compute the evaluations of the permutation product polynomial
+            // over our domain, starting with z[0] = 1
+            let mut z = vec![last_z];
+            for row in 1..(params.n() as usize) {
+                let mut tmp = z[row - 1];
+
+                tmp *= &modified_values[row - 1];
+                z.push(tmp);
+            }
+            let mut z = domain.lagrange_from_vec(z);
+            // Set blinding factors
+            for z in &mut z[params.n() as usize - blinding_factors..] {
+                *z = C::Scalar::random(&mut rng);
+            }
+            // Set new last_z
+            last_z = z[params.n() as usize - (blinding_factors + 1)];
+
+            let blind = Blind(C::Scalar::random(&mut rng));
+
+            let permutation_product_commitment_projective = params.commit_lagrange(&z, blind);
+            let permutation_product_blind = blind;
+            let z = domain.lagrange_to_coeff(z);
+            let permutation_product_poly = z.clone();
+
+            let permutation_product_coset = domain.coeff_to_extended(z.clone());
+
+            let permutation_product_commitment =
+                permutation_product_commitment_projective.to_affine();
+
+            // Hash the permutation product commitment
+            transcript.write_point(permutation_product_commitment)?;
+
+            sets.push(CommittedSet {
+                permutation_product_poly,
+                permutation_product_coset,
+                permutation_product_blind,
+            });
+        }
+
+        Ok(Committed { sets })
+    }
+}
+
+impl<C: CurveAffine> Committed<C> {
+    pub(in crate::plonk) fn construct(self) -> Constructed<C> {
+        Constructed {
+            sets: self
+                .sets
+                .iter()
+                .map(|set| ConstructedSet {
+                    permutation_product_poly: set.permutation_product_poly.clone(),
+                    permutation_product_blind: set.permutation_product_blind,
+                })
+                .collect(),
+        }
+    }
+}
+
+impl<C: CurveAffine> super::ProvingKey<C> {
+    pub(in crate::plonk) fn open(
+        &self,
+        x: ChallengeX<C>,
+    ) -> impl Iterator<Item = ProverQuery<'_, C>> + Clone {
+        self.polys.iter().map(move |poly| ProverQuery {
+            point: *x,
+            poly,
+            blind: Blind::default(),
+        })
+    }
+
+    pub(in crate::plonk) fn evaluate<E: EncodedChallenge<C>, T: TranscriptWrite<C, E>>(
+        &self,
+        x: ChallengeX<C>,
+        transcript: &mut T,
+    ) -> Result<(), Error> {
+        // Hash permutation evals
+        for eval in self.polys.iter().map(|poly| eval_polynomial(poly, *x)) {
+            transcript.write_scalar(eval)?;
+        }
+
+        Ok(())
+    }
+}
+
+impl<C: CurveAffine> Constructed<C> {
+    pub(in crate::plonk) fn evaluate<E: EncodedChallenge<C>, T: TranscriptWrite<C, E>>(
+        self,
+        pk: &plonk::ProvingKey<C>,
+        x: ChallengeX<C>,
+        transcript: &mut T,
+    ) -> Result<Evaluated<C>, Error> {
+        let domain = &pk.vk.domain;
+        let blinding_factors = pk.vk.cs.blinding_factors();
+
+        {
+            let mut sets = self.sets.iter();
+
+            while let Some(set) = sets.next() {
+                let permutation_product_eval = eval_polynomial(&set.permutation_product_poly, *x);
+
+                let permutation_product_next_eval = eval_polynomial(
+                    &set.permutation_product_poly,
+                    domain.rotate_omega(*x, Rotation::next()),
+                );
+
+                // Hash permutation product evals
+                for eval in iter::empty()
+                    .chain(Some(&permutation_product_eval))
+                    .chain(Some(&permutation_product_next_eval))
+                {
+                    transcript.write_scalar(*eval)?;
+                }
+
+                // If we have any remaining sets to process, evaluate this set at omega^u
+                // so we can constrain the last value of its running product to equal the
+                // first value of the next set's running product, chaining them together.
+                if sets.len() > 0 {
+                    let permutation_product_last_eval = eval_polynomial(
+                        &set.permutation_product_poly,
+                        domain.rotate_omega(*x, Rotation(-((blinding_factors + 1) as i32))),
+                    );
+
+                    transcript.write_scalar(permutation_product_last_eval)?;
+                }
+            }
+        }
+
+        Ok(Evaluated { constructed: self })
+    }
+}
+
+impl<C: CurveAffine> Evaluated<C> {
+    pub(in crate::plonk) fn open<'a>(
+        &'a self,
+        pk: &'a plonk::ProvingKey<C>,
+        x: ChallengeX<C>,
+    ) -> impl Iterator<Item = ProverQuery<'a, C>> + Clone {
+        let blinding_factors = pk.vk.cs.blinding_factors();
+        let x_next = pk.vk.domain.rotate_omega(*x, Rotation::next());
+        let x_last = pk
+            .vk
+            .domain
+            .rotate_omega(*x, Rotation(-((blinding_factors + 1) as i32)));
+
+        iter::empty()
+            .chain(self.constructed.sets.iter().flat_map(move |set| {
+                iter::empty()
+                    // Open permutation product commitments at x and \omega x
+                    .chain(Some(ProverQuery {
+                        point: *x,
+                        poly: &set.permutation_product_poly,
+                        blind: set.permutation_product_blind,
+                    }))
+                    .chain(Some(ProverQuery {
+                        point: x_next,
+                        poly: &set.permutation_product_poly,
+                        blind: set.permutation_product_blind,
+                    }))
+            }))
+            // Open it at \omega^{last} x for all but the last set. This rotation is only
+            // sensical for the first row, but we only use this rotation in a constraint
+            // that is gated on l_0.
+            .chain(
+                self.constructed
+                    .sets
+                    .iter()
+                    .rev()
+                    .skip(1)
+                    .flat_map(move |set| {
+                        Some(ProverQuery {
+                            point: x_last,
+                            poly: &set.permutation_product_poly,
+                            blind: set.permutation_product_blind,
+                        })
+                    }),
+            )
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/permutation/verifier.rs.html b/docs/src/halo2_proofs/plonk/permutation/verifier.rs.html new file mode 100644 index 0000000000..959eb69de4 --- /dev/null +++ b/docs/src/halo2_proofs/plonk/permutation/verifier.rs.html @@ -0,0 +1,506 @@ +verifier.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+
use ff::Field;
+use std::iter;
+
+use super::super::{circuit::Any, ChallengeBeta, ChallengeGamma, ChallengeX};
+use super::{Argument, VerifyingKey};
+use crate::{
+    arithmetic::{CurveAffine, FieldExt},
+    plonk::{self, Error},
+    poly::{commitment::MSM, Rotation, VerifierQuery},
+    transcript::{EncodedChallenge, TranscriptRead},
+};
+
+pub struct Committed<C: CurveAffine> {
+    permutation_product_commitments: Vec<C>,
+}
+
+pub struct EvaluatedSet<C: CurveAffine> {
+    permutation_product_commitment: C,
+    permutation_product_eval: C::Scalar,
+    permutation_product_next_eval: C::Scalar,
+    permutation_product_last_eval: Option<C::Scalar>,
+}
+
+pub struct CommonEvaluated<C: CurveAffine> {
+    permutation_evals: Vec<C::Scalar>,
+}
+
+pub struct Evaluated<C: CurveAffine> {
+    sets: Vec<EvaluatedSet<C>>,
+}
+
+impl Argument {
+    pub(crate) fn read_product_commitments<
+        C: CurveAffine,
+        E: EncodedChallenge<C>,
+        T: TranscriptRead<C, E>,
+    >(
+        &self,
+        vk: &plonk::VerifyingKey<C>,
+        transcript: &mut T,
+    ) -> Result<Committed<C>, Error> {
+        let chunk_len = vk.cs_degree - 2;
+
+        let permutation_product_commitments = self
+            .columns
+            .chunks(chunk_len)
+            .map(|_| transcript.read_point())
+            .collect::<Result<Vec<_>, _>>()?;
+
+        Ok(Committed {
+            permutation_product_commitments,
+        })
+    }
+}
+
+impl<C: CurveAffine> VerifyingKey<C> {
+    pub(in crate::plonk) fn evaluate<E: EncodedChallenge<C>, T: TranscriptRead<C, E>>(
+        &self,
+        transcript: &mut T,
+    ) -> Result<CommonEvaluated<C>, Error> {
+        let permutation_evals = self
+            .commitments
+            .iter()
+            .map(|_| transcript.read_scalar())
+            .collect::<Result<Vec<_>, _>>()?;
+
+        Ok(CommonEvaluated { permutation_evals })
+    }
+}
+
+impl<C: CurveAffine> Committed<C> {
+    pub(crate) fn evaluate<E: EncodedChallenge<C>, T: TranscriptRead<C, E>>(
+        self,
+        transcript: &mut T,
+    ) -> Result<Evaluated<C>, Error> {
+        let mut sets = vec![];
+
+        let mut iter = self.permutation_product_commitments.into_iter();
+
+        while let Some(permutation_product_commitment) = iter.next() {
+            let permutation_product_eval = transcript.read_scalar()?;
+            let permutation_product_next_eval = transcript.read_scalar()?;
+            let permutation_product_last_eval = if iter.len() > 0 {
+                Some(transcript.read_scalar()?)
+            } else {
+                None
+            };
+
+            sets.push(EvaluatedSet {
+                permutation_product_commitment,
+                permutation_product_eval,
+                permutation_product_next_eval,
+                permutation_product_last_eval,
+            });
+        }
+
+        Ok(Evaluated { sets })
+    }
+}
+
+impl<C: CurveAffine> Evaluated<C> {
+    pub(in crate::plonk) fn expressions<'a>(
+        &'a self,
+        vk: &'a plonk::VerifyingKey<C>,
+        p: &'a Argument,
+        common: &'a CommonEvaluated<C>,
+        advice_evals: &'a [C::Scalar],
+        fixed_evals: &'a [C::Scalar],
+        instance_evals: &'a [C::Scalar],
+        l_0: C::Scalar,
+        l_last: C::Scalar,
+        l_blind: C::Scalar,
+        beta: ChallengeBeta<C>,
+        gamma: ChallengeGamma<C>,
+        x: ChallengeX<C>,
+    ) -> impl Iterator<Item = C::Scalar> + 'a {
+        let chunk_len = vk.cs_degree - 2;
+        iter::empty()
+            // Enforce only for the first set.
+            // l_0(X) * (1 - z_0(X)) = 0
+            .chain(
+                self.sets.first().map(|first_set| {
+                    l_0 * &(C::Scalar::one() - &first_set.permutation_product_eval)
+                }),
+            )
+            // Enforce only for the last set.
+            // l_last(X) * (z_l(X)^2 - z_l(X)) = 0
+            .chain(self.sets.last().map(|last_set| {
+                (last_set.permutation_product_eval.square() - &last_set.permutation_product_eval)
+                    * &l_last
+            }))
+            // Except for the first set, enforce.
+            // l_0(X) * (z_i(X) - z_{i-1}(\omega^(last) X)) = 0
+            .chain(
+                self.sets
+                    .iter()
+                    .skip(1)
+                    .zip(self.sets.iter())
+                    .map(|(set, last_set)| {
+                        (
+                            set.permutation_product_eval,
+                            last_set.permutation_product_last_eval.unwrap(),
+                        )
+                    })
+                    .map(move |(set, prev_last)| (set - &prev_last) * &l_0),
+            )
+            // And for all the sets we enforce:
+            // (1 - (l_last(X) + l_blind(X))) * (
+            //   z_i(\omega X) \prod (p(X) + \beta s_i(X) + \gamma)
+            // - z_i(X) \prod (p(X) + \delta^i \beta X + \gamma)
+            // )
+            .chain(
+                self.sets
+                    .iter()
+                    .zip(p.columns.chunks(chunk_len))
+                    .zip(common.permutation_evals.chunks(chunk_len))
+                    .enumerate()
+                    .map(move |(chunk_index, ((set, columns), permutation_evals))| {
+                        let mut left = set.permutation_product_next_eval;
+                        for (eval, permutation_eval) in columns
+                            .iter()
+                            .map(|&column| match column.column_type() {
+                                Any::Advice(_) => {
+                                    advice_evals[vk.cs.get_any_query_index(column, Rotation::cur())]
+                                }
+                                Any::Fixed => {
+                                    fixed_evals[vk.cs.get_any_query_index(column, Rotation::cur())]
+                                }
+                                Any::Instance => {
+                                    instance_evals
+                                        [vk.cs.get_any_query_index(column, Rotation::cur())]
+                                }
+                            })
+                            .zip(permutation_evals.iter())
+                        {
+                            left *= &(eval + &(*beta * permutation_eval) + &*gamma);
+                        }
+
+                        let mut right = set.permutation_product_eval;
+                        let mut current_delta = (*beta * &*x)
+                            * &(C::Scalar::DELTA.pow_vartime(&[(chunk_index * chunk_len) as u64]));
+                        for eval in columns.iter().map(|&column| match column.column_type() {
+                            Any::Advice(_) => {
+                                advice_evals[vk.cs.get_any_query_index(column, Rotation::cur())]
+                            }
+                            Any::Fixed => {
+                                fixed_evals[vk.cs.get_any_query_index(column, Rotation::cur())]
+                            }
+                            Any::Instance => {
+                                instance_evals[vk.cs.get_any_query_index(column, Rotation::cur())]
+                            }
+                        }) {
+                            right *= &(eval + &current_delta + &*gamma);
+                            current_delta *= &C::Scalar::DELTA;
+                        }
+
+                        (left - &right) * (C::Scalar::one() - &(l_last + &l_blind))
+                    }),
+            )
+    }
+
+    pub(in crate::plonk) fn queries<'r, M: MSM<C> + 'r>(
+        &'r self,
+        vk: &'r plonk::VerifyingKey<C>,
+        x: ChallengeX<C>,
+    ) -> impl Iterator<Item = VerifierQuery<'r, C, M>> + Clone {
+        let blinding_factors = vk.cs.blinding_factors();
+        let x_next = vk.domain.rotate_omega(*x, Rotation::next());
+        let x_last = vk
+            .domain
+            .rotate_omega(*x, Rotation(-((blinding_factors + 1) as i32)));
+
+        iter::empty()
+            .chain(self.sets.iter().flat_map(move |set| {
+                iter::empty()
+                    // Open permutation product commitments at x and \omega^{-1} x
+                    // Open permutation product commitments at x and \omega x
+                    .chain(Some(VerifierQuery::new_commitment(
+                        &set.permutation_product_commitment,
+                        *x,
+                        set.permutation_product_eval,
+                    )))
+                    .chain(Some(VerifierQuery::new_commitment(
+                        &set.permutation_product_commitment,
+                        x_next,
+                        set.permutation_product_next_eval,
+                    )))
+            }))
+            // Open it at \omega^{last} x for all but the last set
+            .chain(self.sets.iter().rev().skip(1).flat_map(move |set| {
+                Some(VerifierQuery::new_commitment(
+                    &set.permutation_product_commitment,
+                    x_last,
+                    set.permutation_product_last_eval.unwrap(),
+                ))
+            }))
+    }
+}
+
+impl<C: CurveAffine> CommonEvaluated<C> {
+    pub(in crate::plonk) fn queries<'r, M: MSM<C> + 'r>(
+        &'r self,
+        vkey: &'r VerifyingKey<C>,
+        x: ChallengeX<C>,
+    ) -> impl Iterator<Item = VerifierQuery<'r, C, M>> + Clone {
+        // Open permutation commitments for each permutation argument at x
+        vkey.commitments
+            .iter()
+            .zip(self.permutation_evals.iter())
+            .map(move |(commitment, &eval)| VerifierQuery::new_commitment(commitment, *x, eval))
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/prover.rs.html b/docs/src/halo2_proofs/plonk/prover.rs.html new file mode 100644 index 0000000000..9647e942ee --- /dev/null +++ b/docs/src/halo2_proofs/plonk/prover.rs.html @@ -0,0 +1,1374 @@ +prover.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+
use ff::Field;
+use group::Curve;
+use halo2curves::CurveExt;
+use rand_core::RngCore;
+use std::collections::BTreeSet;
+use std::env::var;
+use std::marker::PhantomData;
+use std::ops::RangeTo;
+use std::rc::Rc;
+use std::sync::atomic::AtomicUsize;
+use std::time::Instant;
+use std::{collections::HashMap, iter, mem, sync::atomic::Ordering};
+
+use super::{
+    circuit::{
+        sealed::{self, SealedPhase},
+        Advice, Any, Assignment, Challenge, Circuit, Column, ConstraintSystem, FirstPhase, Fixed,
+        FloorPlanner, Instance, Selector,
+    },
+    lookup, permutation, vanishing, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX,
+    ChallengeY, Error, Expression, ProvingKey,
+};
+use crate::poly::batch_invert_assigned_ref;
+use crate::poly::commitment::ParamsProver;
+use crate::transcript::Transcript;
+use crate::{
+    arithmetic::{eval_polynomial, CurveAffine, FieldExt},
+    circuit::Value,
+    plonk::Assigned,
+    poly::{
+        self,
+        commitment::{Blind, CommitmentScheme, Params, Prover},
+        Basis, Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial, ProverQuery,
+    },
+};
+use crate::{
+    poly::batch_invert_assigned,
+    transcript::{EncodedChallenge, TranscriptWrite},
+};
+use group::prime::PrimeCurveAffine;
+
+/// This creates a proof for the provided `circuit` when given the public
+/// parameters `params` and the proving key [`ProvingKey`] that was
+/// generated previously for the same circuit. The provided `instances`
+/// are zero-padded internally.
+pub fn create_proof<
+    'params,
+    'a,
+    Scheme: CommitmentScheme,
+    P: Prover<'params, Scheme>,
+    E: EncodedChallenge<Scheme::Curve>,
+    R: RngCore + 'a,
+    T: TranscriptWrite<Scheme::Curve, E>,
+    ConcreteCircuit: Circuit<Scheme::Scalar>,
+>(
+    params: &'params Scheme::ParamsProver,
+    pk: &ProvingKey<Scheme::Curve>,
+    circuits: &[ConcreteCircuit],
+    instances: &[&[&'a [Scheme::Scalar]]],
+    mut rng: R,
+    mut transcript: &'a mut T,
+) -> Result<(), Error> {
+    for instance in instances.iter() {
+        if instance.len() != pk.vk.cs.num_instance_columns {
+            return Err(Error::InvalidInstances);
+        }
+    }
+
+    // Hash verification key into transcript
+    pk.vk.hash_into(transcript)?;
+
+    let domain = &pk.vk.domain;
+    let mut meta = ConstraintSystem::default();
+    let config = ConcreteCircuit::configure(&mut meta);
+
+    // Selector optimizations cannot be applied here; use the ConstraintSystem
+    // from the verification key.
+    let meta = &pk.vk.cs;
+
+    struct InstanceSingle<C: CurveAffine> {
+        pub instance_values: Vec<Polynomial<C::Scalar, LagrangeCoeff>>,
+        pub instance_polys: Vec<Polynomial<C::Scalar, Coeff>>,
+    }
+
+    let instance: Vec<InstanceSingle<Scheme::Curve>> = instances
+        .iter()
+        .map(|instance| -> Result<InstanceSingle<Scheme::Curve>, Error> {
+            let instance_values = instance
+                .iter()
+                .map(|values| {
+                    let mut poly = domain.empty_lagrange();
+                    assert_eq!(poly.len(), params.n() as usize);
+                    if values.len() > (poly.len() - (meta.blinding_factors() + 1)) {
+                        panic!("Error::InstanceTooLarge");
+                    }
+                    for (poly, value) in poly.iter_mut().zip(values.iter()) {
+                        *poly = *value;
+                    }
+                    poly
+                })
+                .collect::<Vec<_>>();
+
+            let instance_polys: Vec<_> = instance_values
+                .iter()
+                .map(|poly| {
+                    let lagrange_vec = domain.lagrange_from_vec(poly.to_vec());
+                    domain.lagrange_to_coeff(lagrange_vec)
+                })
+                .collect();
+
+            Ok(InstanceSingle {
+                instance_values,
+                instance_polys,
+            })
+        })
+        .collect::<Result<Vec<_>, _>>()?;
+
+    #[derive(Clone)]
+    struct AdviceSingle<C: CurveAffine, B: Basis> {
+        pub advice_polys: Vec<Polynomial<C::Scalar, B>>,
+        pub advice_blinds: Vec<Blind<C::Scalar>>,
+    }
+
+    struct WitnessCollection<'params, 'a, 'b, Scheme, P, C, E, R, T>
+    where
+        Scheme: CommitmentScheme<Curve = C>,
+        P: Prover<'params, Scheme>,
+        C: CurveAffine,
+        E: EncodedChallenge<C>,
+        R: RngCore + 'a,
+        T: TranscriptWrite<C, E>,
+    {
+        params: &'params Scheme::ParamsProver,
+        current_phase: sealed::Phase,
+        advice: Vec<Polynomial<Assigned<C::Scalar>, LagrangeCoeff>>,
+        challenges: &'b mut HashMap<usize, C::Scalar>,
+        instances: &'b [&'a [C::Scalar]],
+        usable_rows: RangeTo<usize>,
+        advice_single: AdviceSingle<C, LagrangeCoeff>,
+        instance_single: &'b InstanceSingle<C>,
+        rng: &'b mut R,
+        transcript: &'b mut &'a mut T,
+        column_indices: [Vec<usize>; 3],
+        challenge_indices: [Vec<usize>; 3],
+        unusable_rows_start: usize,
+        _marker: PhantomData<(P, E)>,
+    }
+
+    impl<'params, 'a, 'b, F, Scheme, P, C, E, R, T> Assignment<F>
+        for WitnessCollection<'params, 'a, 'b, Scheme, P, C, E, R, T>
+    where
+        F: FieldExt,
+        Scheme: CommitmentScheme<Curve = C>,
+        P: Prover<'params, Scheme>,
+        C: CurveAffine<ScalarExt = F>,
+        E: EncodedChallenge<C>,
+        R: RngCore,
+        T: TranscriptWrite<C, E>,
+    {
+        fn enter_region<NR, N>(&mut self, _: N)
+        where
+            NR: Into<String>,
+            N: FnOnce() -> NR,
+        {
+            // Do nothing; we don't care about regions in this context.
+        }
+
+        fn exit_region(&mut self) {
+            // Do nothing; we don't care about regions in this context.
+        }
+
+        fn enable_selector<A, AR>(&mut self, _: A, _: &Selector, _: usize) -> Result<(), Error>
+        where
+            A: FnOnce() -> AR,
+            AR: Into<String>,
+        {
+            // We only care about advice columns here
+
+            Ok(())
+        }
+
+        fn query_instance(&self, column: Column<Instance>, row: usize) -> Result<Value<F>, Error> {
+            if !self.usable_rows.contains(&row) {
+                return Err(Error::not_enough_rows_available(self.params.k()));
+            }
+
+            self.instances
+                .get(column.index())
+                .and_then(|column| column.get(row))
+                .map(|v| Value::known(*v))
+                .ok_or(Error::BoundsFailure)
+        }
+
+        fn assign_advice<'r, 'v>(
+            //<V, VR, A, AR>(
+            &'r mut self,
+            //_: A,
+            column: Column<Advice>,
+            row: usize,
+            to: Value<Assigned<F>>,
+        ) -> Result<Value<&'v Assigned<F>>, Error> {
+            // TODO: better to assign all at once, deal with phases later
+            // Ignore assignment of advice column in different phase than current one.
+            if self.current_phase != column.column_type().phase {
+                return Ok(Value::unknown());
+            }
+
+            if !self.usable_rows.contains(&row) {
+                return Err(Error::not_enough_rows_available(self.params.k()));
+            }
+
+            let advice_get_mut = self
+                .advice
+                .get_mut(column.index())
+                .expect("Not enough advice columns")
+                .get_mut(row)
+                .expect("Not enough rows");
+            // We can get another 3-4% decrease in witness gen time by using the following unsafe code, but this skips all array bound checks so we should use it only if the performance gain is really necessary:
+            /*
+            let advice_get_mut = unsafe {
+                self.advice
+                    .get_unchecked_mut(column.index())
+                    .get_unchecked_mut(row)
+            };
+            */
+            *advice_get_mut = to
+                .assign()
+                .expect("No Value::unknown() in advice column allowed during create_proof");
+            let immutable_raw_ptr = advice_get_mut as *const Assigned<F>;
+            Ok(Value::known(unsafe { &*immutable_raw_ptr }))
+        }
+
+        fn assign_fixed(&mut self, _: Column<Fixed>, _: usize, _: Assigned<F>) {
+            // We only care about advice columns here
+        }
+
+        fn copy(&mut self, _: Column<Any>, _: usize, _: Column<Any>, _: usize) {
+            // We only care about advice columns here
+        }
+
+        fn fill_from_row(
+            &mut self,
+            _: Column<Fixed>,
+            _: usize,
+            _: Value<Assigned<F>>,
+        ) -> Result<(), Error> {
+            Ok(())
+        }
+
+        fn get_challenge(&self, challenge: Challenge) -> Value<F> {
+            self.challenges
+                .get(&challenge.index())
+                .cloned()
+                .map(Value::known)
+                .unwrap_or_else(Value::unknown)
+        }
+
+        fn push_namespace<NR, N>(&mut self, _: N)
+        where
+            NR: Into<String>,
+            N: FnOnce() -> NR,
+        {
+            // Do nothing; we don't care about namespaces in this context.
+        }
+
+        fn pop_namespace(&mut self, _: Option<String>) {
+            // Do nothing; we don't care about namespaces in this context.
+        }
+
+        fn next_phase(&mut self) {
+            let phase = self.current_phase.to_u8() as usize;
+            if phase == 0 {
+                // Absorb instances into transcript.
+                // Do this here and not earlier in case we want to be able to mutate
+                // the instances during synthesize in FirstPhase in the future
+                if !P::QUERY_INSTANCE {
+                    for values in self.instances.iter() {
+                        for value in values.iter() {
+                            self.transcript
+                                .common_scalar(*value)
+                                .expect("Absorbing instance value to transcript failed");
+                        }
+                    }
+                } else {
+                    let instance_commitments_projective: Vec<_> = self
+                        .instance_single
+                        .instance_values
+                        .iter()
+                        .map(|poly| self.params.commit_lagrange(poly, Blind::default()))
+                        .collect();
+                    let mut instance_commitments =
+                        vec![C::identity(); instance_commitments_projective.len()];
+                    C::CurveExt::batch_normalize(
+                        &instance_commitments_projective,
+                        &mut instance_commitments,
+                    );
+                    let instance_commitments = instance_commitments;
+                    drop(instance_commitments_projective);
+
+                    for commitment in &instance_commitments {
+                        self.transcript
+                            .common_point(*commitment)
+                            .expect("Absorbing instance commitment to transcript failed");
+                    }
+                }
+            }
+            // Commit the advice columns in the current phase
+            let mut advice_values = batch_invert_assigned_ref::<F>(
+                self.column_indices
+                    .get(phase)
+                    .expect("The API only supports 3 phases right now")
+                    .iter()
+                    .map(|column_index| &self.advice[*column_index])
+                    .collect(),
+            );
+            // Add blinding factors to advice columns
+            for advice_values in &mut advice_values {
+                for cell in &mut advice_values[self.unusable_rows_start..] {
+                    *cell = F::random(&mut self.rng);
+                }
+            }
+            // Compute commitments to advice column polynomials
+            let blinds: Vec<_> = advice_values
+                .iter()
+                .map(|_| Blind(F::random(&mut self.rng)))
+                .collect();
+            let advice_commitments_projective: Vec<_> = advice_values
+                .iter()
+                .zip(blinds.iter())
+                .map(|(poly, blind)| self.params.commit_lagrange(poly, *blind))
+                .collect();
+            let mut advice_commitments = vec![C::identity(); advice_commitments_projective.len()];
+            C::CurveExt::batch_normalize(&advice_commitments_projective, &mut advice_commitments);
+            let advice_commitments = advice_commitments;
+            drop(advice_commitments_projective);
+
+            for commitment in &advice_commitments {
+                self.transcript
+                    .write_point(*commitment)
+                    .expect("Absorbing advice commitment to transcript failed");
+            }
+            for ((column_index, advice_poly), blind) in self.column_indices[phase]
+                .iter()
+                .zip(advice_values)
+                .zip(blinds)
+            {
+                self.advice_single.advice_polys[*column_index] = advice_poly;
+                self.advice_single.advice_blinds[*column_index] = blind;
+            }
+            for challenge_index in self.challenge_indices[phase].iter() {
+                let existing = self.challenges.insert(
+                    *challenge_index,
+                    *self.transcript.squeeze_challenge_scalar::<()>(),
+                );
+                assert!(existing.is_none());
+            }
+            self.current_phase = self.current_phase.next();
+        }
+    }
+
+    let mut column_indices = [(); 3].map(|_| vec![]);
+    for (index, phase) in meta.advice_column_phase.iter().enumerate() {
+        column_indices[phase.to_u8() as usize].push(index);
+    }
+    let mut challenge_indices = [(); 3].map(|_| vec![]);
+    for (index, phase) in meta.challenge_phase.iter().enumerate() {
+        challenge_indices[phase.to_u8() as usize].push(index);
+    }
+
+    let (advice, challenges) = {
+        let mut advice = Vec::with_capacity(instances.len());
+        let mut challenges = HashMap::<usize, Scheme::Scalar>::with_capacity(meta.num_challenges);
+
+        let unusable_rows_start = params.n() as usize - (meta.blinding_factors() + 1);
+        let phases = pk.vk.cs.phases().collect::<Vec<_>>();
+        let num_phases = phases.len();
+        // WARNING: this will currently not work if `circuits` has more than 1 circuit
+        // because the original API squeezes the challenges for a phase after running all circuits
+        // once in that phase.
+        assert_eq!(
+            circuits.len(),
+            1,
+            "New challenge API doesn't work with multiple circuits yet"
+        );
+        for ((circuit, instances), instance_single) in
+            circuits.iter().zip(instances).zip(instance.iter())
+        {
+            let mut witness: WitnessCollection<Scheme, P, _, E, _, _> = WitnessCollection {
+                params,
+                current_phase: phases[0],
+                advice: vec![domain.empty_lagrange_assigned(); meta.num_advice_columns],
+                instances,
+                challenges: &mut challenges,
+                // The prover will not be allowed to assign values to advice
+                // cells that exist within inactive rows, which include some
+                // number of blinding factors and an extra row for use in the
+                // permutation argument.
+                usable_rows: ..unusable_rows_start,
+                advice_single: AdviceSingle::<Scheme::Curve, LagrangeCoeff> {
+                    advice_polys: vec![domain.empty_lagrange(); meta.num_advice_columns],
+                    advice_blinds: vec![Blind::default(); meta.num_advice_columns],
+                },
+                instance_single,
+                rng: &mut rng,
+                transcript: &mut transcript,
+                column_indices: column_indices.clone(),
+                challenge_indices: challenge_indices.clone(),
+                unusable_rows_start,
+                _marker: PhantomData,
+            };
+
+            // while loop is for compatibility with circuits that do not use the new `next_phase` API to manage phases
+            // If the circuit uses the new API, then the while loop will only execute once
+            while witness.current_phase.to_u8() < num_phases as u8 {
+                // Synthesize the circuit to obtain the witness and other information.
+                ConcreteCircuit::FloorPlanner::synthesize(
+                    &mut witness,
+                    circuit,
+                    config.clone(),
+                    meta.constants.clone(),
+                )
+                .unwrap();
+                if witness.current_phase.to_u8() < num_phases as u8 {
+                    witness.next_phase();
+                }
+            }
+            advice.push(witness.advice_single);
+        }
+
+        assert_eq!(challenges.len(), meta.num_challenges);
+        let challenges = (0..meta.num_challenges)
+            .map(|index| challenges.remove(&index).unwrap())
+            .collect::<Vec<_>>();
+
+        (advice, challenges)
+    };
+
+    // Sample theta challenge for keeping lookup columns linearly independent
+    let theta: ChallengeTheta<_> = transcript.squeeze_challenge_scalar();
+
+    let lookups: Vec<Vec<lookup::prover::Permuted<Scheme::Curve>>> = instance
+        .iter()
+        .zip(advice.iter())
+        .map(|(instance, advice)| -> Result<Vec<_>, Error> {
+            // Construct and commit to permuted values for each lookup
+            pk.vk
+                .cs
+                .lookups
+                .iter()
+                .map(|lookup| {
+                    lookup.commit_permuted(
+                        pk,
+                        params,
+                        domain,
+                        theta,
+                        &advice.advice_polys,
+                        &pk.fixed_values,
+                        &instance.instance_values,
+                        &challenges,
+                        &mut rng,
+                        transcript,
+                    )
+                })
+                .collect()
+        })
+        .collect::<Result<Vec<_>, _>>()?;
+
+    // Sample beta challenge
+    let beta: ChallengeBeta<_> = transcript.squeeze_challenge_scalar();
+
+    // Sample gamma challenge
+    let gamma: ChallengeGamma<_> = transcript.squeeze_challenge_scalar();
+
+    // Commit to permutations.
+    let permutations: Vec<permutation::prover::Committed<Scheme::Curve>> = instance
+        .iter()
+        .zip(advice.iter())
+        .map(|(instance, advice)| {
+            pk.vk.cs.permutation.commit(
+                params,
+                pk,
+                &pk.permutation,
+                &advice.advice_polys,
+                &pk.fixed_values,
+                &instance.instance_values,
+                beta,
+                gamma,
+                &mut rng,
+                transcript,
+            )
+        })
+        .collect::<Result<Vec<_>, _>>()?;
+
+    let lookups: Vec<Vec<lookup::prover::Committed<Scheme::Curve>>> = lookups
+        .into_iter()
+        .map(|lookups| -> Result<Vec<_>, _> {
+            // Construct and commit to products for each lookup
+            lookups
+                .into_iter()
+                .map(|lookup| lookup.commit_product(pk, params, beta, gamma, &mut rng, transcript))
+                .collect::<Result<Vec<_>, _>>()
+        })
+        .collect::<Result<Vec<_>, _>>()?;
+
+    // Commit to the vanishing argument's random polynomial for blinding h(x_3)
+    let vanishing = vanishing::Argument::commit(params, domain, &mut rng, transcript)?;
+
+    // Obtain challenge for keeping all separate gates linearly independent
+    let y: ChallengeY<_> = transcript.squeeze_challenge_scalar();
+
+    // Calculate the advice polys
+    let advice: Vec<AdviceSingle<Scheme::Curve, Coeff>> = advice
+        .into_iter()
+        .map(
+            |AdviceSingle {
+                 advice_polys,
+                 advice_blinds,
+             }| {
+                AdviceSingle {
+                    advice_polys: advice_polys
+                        .into_iter()
+                        .map(|poly| domain.lagrange_to_coeff(poly))
+                        .collect::<Vec<_>>(),
+                    advice_blinds,
+                }
+            },
+        )
+        .collect();
+
+    // Evaluate the h(X) polynomial
+    let h_poly = pk.ev.evaluate_h(
+        pk,
+        &advice
+            .iter()
+            .map(|a| a.advice_polys.as_slice())
+            .collect::<Vec<_>>(),
+        &instance
+            .iter()
+            .map(|i| i.instance_polys.as_slice())
+            .collect::<Vec<_>>(),
+        &challenges,
+        *y,
+        *beta,
+        *gamma,
+        *theta,
+        &lookups,
+        &permutations,
+    );
+
+    // Construct the vanishing argument's h(X) commitments
+    let vanishing = vanishing.construct(params, domain, h_poly, &mut rng, transcript)?;
+
+    let x: ChallengeX<_> = transcript.squeeze_challenge_scalar();
+    let xn = x.pow(&[params.n(), 0, 0, 0]);
+
+    if P::QUERY_INSTANCE {
+        // Compute and hash instance evals for each circuit instance
+        for instance in instance.iter() {
+            // Evaluate polynomials at omega^i x
+            let instance_evals: Vec<_> = meta
+                .instance_queries
+                .iter()
+                .map(|&(column, at)| {
+                    eval_polynomial(
+                        &instance.instance_polys[column.index()],
+                        domain.rotate_omega(*x, at),
+                    )
+                })
+                .collect();
+
+            // Hash each instance column evaluation
+            for eval in instance_evals.iter() {
+                transcript.write_scalar(*eval)?;
+            }
+        }
+    }
+
+    // Compute and hash advice evals for each circuit instance
+    for advice in advice.iter() {
+        // Evaluate polynomials at omega^i x
+        let advice_evals: Vec<_> = meta
+            .advice_queries
+            .iter()
+            .map(|&(column, at)| {
+                eval_polynomial(
+                    &advice.advice_polys[column.index()],
+                    domain.rotate_omega(*x, at),
+                )
+            })
+            .collect();
+
+        // Hash each advice column evaluation
+        for eval in advice_evals.iter() {
+            transcript.write_scalar(*eval)?;
+        }
+    }
+
+    // Compute and hash fixed evals (shared across all circuit instances)
+    let fixed_evals: Vec<_> = meta
+        .fixed_queries
+        .iter()
+        .map(|&(column, at)| {
+            eval_polynomial(&pk.fixed_polys[column.index()], domain.rotate_omega(*x, at))
+        })
+        .collect();
+
+    // Hash each fixed column evaluation
+    for eval in fixed_evals.iter() {
+        transcript.write_scalar(*eval)?;
+    }
+
+    let vanishing = vanishing.evaluate(x, xn, domain, transcript)?;
+
+    // Evaluate common permutation data
+    pk.permutation.evaluate(x, transcript)?;
+
+    // Evaluate the permutations, if any, at omega^i x.
+    let permutations: Vec<permutation::prover::Evaluated<Scheme::Curve>> = permutations
+        .into_iter()
+        .map(|permutation| -> Result<_, _> { permutation.construct().evaluate(pk, x, transcript) })
+        .collect::<Result<Vec<_>, _>>()?;
+
+    // Evaluate the lookups, if any, at omega^i x.
+    let lookups: Vec<Vec<lookup::prover::Evaluated<Scheme::Curve>>> = lookups
+        .into_iter()
+        .map(|lookups| -> Result<Vec<_>, _> {
+            lookups
+                .into_iter()
+                .map(|p| p.evaluate(pk, x, transcript))
+                .collect::<Result<Vec<_>, _>>()
+        })
+        .collect::<Result<Vec<_>, _>>()?;
+
+    let instances = instance
+        .iter()
+        .zip(advice.iter())
+        .zip(permutations.iter())
+        .zip(lookups.iter())
+        .flat_map(|(((instance, advice), permutation), lookups)| {
+            iter::empty()
+                .chain(
+                    P::QUERY_INSTANCE
+                        .then_some(pk.vk.cs.instance_queries.iter().map(move |&(column, at)| {
+                            ProverQuery {
+                                point: domain.rotate_omega(*x, at),
+                                poly: &instance.instance_polys[column.index()],
+                                blind: Blind::default(),
+                            }
+                        }))
+                        .into_iter()
+                        .flatten(),
+                )
+                .chain(
+                    pk.vk
+                        .cs
+                        .advice_queries
+                        .iter()
+                        .map(move |&(column, at)| ProverQuery {
+                            point: domain.rotate_omega(*x, at),
+                            poly: &advice.advice_polys[column.index()],
+                            blind: advice.advice_blinds[column.index()],
+                        }),
+                )
+                .chain(permutation.open(pk, x))
+                .chain(lookups.iter().flat_map(move |p| p.open(pk, x)).into_iter())
+        })
+        .chain(
+            pk.vk
+                .cs
+                .fixed_queries
+                .iter()
+                .map(|&(column, at)| ProverQuery {
+                    point: domain.rotate_omega(*x, at),
+                    poly: &pk.fixed_polys[column.index()],
+                    blind: Blind::default(),
+                }),
+        )
+        .chain(pk.permutation.open(x))
+        // We query the h(X) polynomial at x
+        .chain(vanishing.open(x));
+
+    let prover = P::new(params);
+    prover
+        .create_proof(&mut rng, transcript, instances)
+        .map_err(|_| Error::ConstraintSystemFailure)
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/vanishing.rs.html b/docs/src/halo2_proofs/plonk/vanishing.rs.html new file mode 100644 index 0000000000..39cc5d3d9b --- /dev/null +++ b/docs/src/halo2_proofs/plonk/vanishing.rs.html @@ -0,0 +1,24 @@ +vanishing.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+
use std::marker::PhantomData;
+
+use crate::arithmetic::CurveAffine;
+
+mod prover;
+mod verifier;
+
+/// A vanishing argument.
+pub(crate) struct Argument<C: CurveAffine> {
+    _marker: PhantomData<C>,
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/vanishing/prover.rs.html b/docs/src/halo2_proofs/plonk/vanishing/prover.rs.html new file mode 100644 index 0000000000..58e0f58431 --- /dev/null +++ b/docs/src/halo2_proofs/plonk/vanishing/prover.rs.html @@ -0,0 +1,348 @@ +prover.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+
use std::iter;
+
+use ff::Field;
+use group::Curve;
+use rand_core::RngCore;
+
+use super::Argument;
+use crate::{
+    arithmetic::{eval_polynomial, CurveAffine, FieldExt},
+    plonk::{ChallengeX, ChallengeY, Error},
+    poly::{
+        self,
+        commitment::{Blind, ParamsProver},
+        Coeff, EvaluationDomain, ExtendedLagrangeCoeff, Polynomial, ProverQuery,
+    },
+    transcript::{EncodedChallenge, TranscriptWrite},
+};
+
+pub(in crate::plonk) struct Committed<C: CurveAffine> {
+    random_poly: Polynomial<C::Scalar, Coeff>,
+    random_blind: Blind<C::Scalar>,
+}
+
+pub(in crate::plonk) struct Constructed<C: CurveAffine> {
+    h_pieces: Vec<Polynomial<C::Scalar, Coeff>>,
+    h_blinds: Vec<Blind<C::Scalar>>,
+    committed: Committed<C>,
+}
+
+pub(in crate::plonk) struct Evaluated<C: CurveAffine> {
+    h_poly: Polynomial<C::Scalar, Coeff>,
+    h_blind: Blind<C::Scalar>,
+    committed: Committed<C>,
+}
+
+impl<C: CurveAffine> Argument<C> {
+    pub(in crate::plonk) fn commit<
+        'params,
+        P: ParamsProver<'params, C>,
+        E: EncodedChallenge<C>,
+        R: RngCore,
+        T: TranscriptWrite<C, E>,
+    >(
+        params: &P,
+        domain: &EvaluationDomain<C::Scalar>,
+        mut rng: R,
+        transcript: &mut T,
+    ) -> Result<Committed<C>, Error> {
+        // Sample a random polynomial of degree n - 1
+        let mut random_poly = domain.empty_coeff();
+        for coeff in random_poly.iter_mut() {
+            *coeff = C::Scalar::random(&mut rng);
+        }
+        // Sample a random blinding factor
+        let random_blind = Blind(C::Scalar::random(rng));
+
+        // Commit
+        let c = params.commit(&random_poly, random_blind).to_affine();
+        transcript.write_point(c)?;
+
+        Ok(Committed {
+            random_poly,
+            random_blind,
+        })
+    }
+}
+
+impl<C: CurveAffine> Committed<C> {
+    pub(in crate::plonk) fn construct<
+        'params,
+        P: ParamsProver<'params, C>,
+        E: EncodedChallenge<C>,
+        R: RngCore,
+        T: TranscriptWrite<C, E>,
+    >(
+        self,
+        params: &P,
+        domain: &EvaluationDomain<C::Scalar>,
+        h_poly: Polynomial<C::Scalar, ExtendedLagrangeCoeff>,
+        mut rng: R,
+        transcript: &mut T,
+    ) -> Result<Constructed<C>, Error> {
+        // Divide by t(X) = X^{params.n} - 1.
+        let h_poly = domain.divide_by_vanishing_poly(h_poly);
+
+        // Obtain final h(X) polynomial
+        let h_poly = domain.extended_to_coeff(h_poly);
+
+        // Split h(X) up into pieces
+        let h_pieces = h_poly
+            .chunks_exact(params.n() as usize)
+            .map(|v| domain.coeff_from_vec(v.to_vec()))
+            .collect::<Vec<_>>();
+        drop(h_poly);
+        let h_blinds: Vec<_> = h_pieces
+            .iter()
+            .map(|_| Blind(C::Scalar::random(&mut rng)))
+            .collect();
+
+        // Compute commitments to each h(X) piece
+        let h_commitments_projective: Vec<_> = h_pieces
+            .iter()
+            .zip(h_blinds.iter())
+            .map(|(h_piece, blind)| params.commit(h_piece, *blind))
+            .collect();
+        let mut h_commitments = vec![C::identity(); h_commitments_projective.len()];
+        C::Curve::batch_normalize(&h_commitments_projective, &mut h_commitments);
+        let h_commitments = h_commitments;
+
+        // Hash each h(X) piece
+        for c in h_commitments.iter() {
+            transcript.write_point(*c)?;
+        }
+
+        Ok(Constructed {
+            h_pieces,
+            h_blinds,
+            committed: self,
+        })
+    }
+}
+
+impl<C: CurveAffine> Constructed<C> {
+    pub(in crate::plonk) fn evaluate<E: EncodedChallenge<C>, T: TranscriptWrite<C, E>>(
+        self,
+        x: ChallengeX<C>,
+        xn: C::Scalar,
+        domain: &EvaluationDomain<C::Scalar>,
+        transcript: &mut T,
+    ) -> Result<Evaluated<C>, Error> {
+        let h_poly = self
+            .h_pieces
+            .iter()
+            .rev()
+            .fold(domain.empty_coeff(), |acc, eval| acc * xn + eval);
+
+        let h_blind = self
+            .h_blinds
+            .iter()
+            .rev()
+            .fold(Blind(C::Scalar::zero()), |acc, eval| {
+                acc * Blind(xn) + *eval
+            });
+
+        let random_eval = eval_polynomial(&self.committed.random_poly, *x);
+        transcript.write_scalar(random_eval)?;
+
+        Ok(Evaluated {
+            h_poly,
+            h_blind,
+            committed: self.committed,
+        })
+    }
+}
+
+impl<C: CurveAffine> Evaluated<C> {
+    pub(in crate::plonk) fn open(
+        &self,
+        x: ChallengeX<C>,
+    ) -> impl Iterator<Item = ProverQuery<'_, C>> + Clone {
+        iter::empty()
+            .chain(Some(ProverQuery {
+                point: *x,
+                poly: &self.h_poly,
+                blind: self.h_blind,
+            }))
+            .chain(Some(ProverQuery {
+                point: *x,
+                poly: &self.committed.random_poly,
+                blind: self.committed.random_blind,
+            }))
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/vanishing/verifier.rs.html b/docs/src/halo2_proofs/plonk/vanishing/verifier.rs.html new file mode 100644 index 0000000000..c7cb9e7a63 --- /dev/null +++ b/docs/src/halo2_proofs/plonk/vanishing/verifier.rs.html @@ -0,0 +1,278 @@ +verifier.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+
use std::iter;
+
+use ff::Field;
+
+use crate::{
+    arithmetic::CurveAffine,
+    plonk::{Error, VerifyingKey},
+    poly::{
+        commitment::{Params, MSM},
+        VerifierQuery,
+    },
+    transcript::{read_n_points, EncodedChallenge, TranscriptRead},
+};
+
+use super::super::{ChallengeX, ChallengeY};
+use super::Argument;
+
+pub struct Committed<C: CurveAffine> {
+    random_poly_commitment: C,
+}
+
+pub struct Constructed<C: CurveAffine> {
+    h_commitments: Vec<C>,
+    random_poly_commitment: C,
+}
+
+pub struct PartiallyEvaluated<C: CurveAffine> {
+    h_commitments: Vec<C>,
+    random_poly_commitment: C,
+    random_eval: C::Scalar,
+}
+
+pub struct Evaluated<C: CurveAffine, M: MSM<C>> {
+    h_commitment: M,
+    random_poly_commitment: C,
+    expected_h_eval: C::Scalar,
+    random_eval: C::Scalar,
+}
+
+impl<C: CurveAffine> Argument<C> {
+    pub(in crate::plonk) fn read_commitments_before_y<
+        E: EncodedChallenge<C>,
+        T: TranscriptRead<C, E>,
+    >(
+        transcript: &mut T,
+    ) -> Result<Committed<C>, Error> {
+        let random_poly_commitment = transcript.read_point()?;
+
+        Ok(Committed {
+            random_poly_commitment,
+        })
+    }
+}
+
+impl<C: CurveAffine> Committed<C> {
+    pub(in crate::plonk) fn read_commitments_after_y<
+        E: EncodedChallenge<C>,
+        T: TranscriptRead<C, E>,
+    >(
+        self,
+        vk: &VerifyingKey<C>,
+        transcript: &mut T,
+    ) -> Result<Constructed<C>, Error> {
+        // Obtain a commitment to h(X) in the form of multiple pieces of degree n - 1
+        let h_commitments = read_n_points(transcript, vk.domain.get_quotient_poly_degree())?;
+
+        Ok(Constructed {
+            h_commitments,
+            random_poly_commitment: self.random_poly_commitment,
+        })
+    }
+}
+
+impl<C: CurveAffine> Constructed<C> {
+    pub(in crate::plonk) fn evaluate_after_x<E: EncodedChallenge<C>, T: TranscriptRead<C, E>>(
+        self,
+        transcript: &mut T,
+    ) -> Result<PartiallyEvaluated<C>, Error> {
+        let random_eval = transcript.read_scalar()?;
+
+        Ok(PartiallyEvaluated {
+            h_commitments: self.h_commitments,
+            random_poly_commitment: self.random_poly_commitment,
+            random_eval,
+        })
+    }
+}
+
+impl<C: CurveAffine> PartiallyEvaluated<C> {
+    pub(in crate::plonk) fn verify<'params, P: Params<'params, C>>(
+        self,
+        params: &'params P,
+        expressions: impl Iterator<Item = C::Scalar>,
+        y: ChallengeY<C>,
+        xn: C::Scalar,
+    ) -> Evaluated<C, P::MSM> {
+        let expected_h_eval = expressions.fold(C::Scalar::zero(), |h_eval, v| h_eval * &*y + &v);
+        let expected_h_eval = expected_h_eval * ((xn - C::Scalar::one()).invert().unwrap());
+
+        let h_commitment =
+            self.h_commitments
+                .iter()
+                .rev()
+                .fold(params.empty_msm(), |mut acc, commitment| {
+                    acc.scale(xn);
+                    let commitment: C::CurveExt = (*commitment).into();
+                    acc.append_term(C::Scalar::one(), commitment);
+
+                    acc
+                });
+
+        Evaluated {
+            expected_h_eval,
+            h_commitment,
+            random_poly_commitment: self.random_poly_commitment,
+            random_eval: self.random_eval,
+        }
+    }
+}
+
+impl<C: CurveAffine, M: MSM<C>> Evaluated<C, M> {
+    pub(in crate::plonk) fn queries(
+        &self,
+        x: ChallengeX<C>,
+    ) -> impl Iterator<Item = VerifierQuery<C, M>> + Clone {
+        iter::empty()
+            .chain(Some(VerifierQuery::new_msm(
+                &self.h_commitment,
+                *x,
+                self.expected_h_eval,
+            )))
+            .chain(Some(VerifierQuery::new_commitment(
+                &self.random_poly_commitment,
+                *x,
+                self.random_eval,
+            )))
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/verifier.rs.html b/docs/src/halo2_proofs/plonk/verifier.rs.html new file mode 100644 index 0000000000..33def9aeb6 --- /dev/null +++ b/docs/src/halo2_proofs/plonk/verifier.rs.html @@ -0,0 +1,800 @@ +verifier.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+
use ff::Field;
+use group::Curve;
+use rand_core::RngCore;
+use std::iter;
+
+use super::{
+    vanishing, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, ChallengeY, Error,
+    VerifyingKey,
+};
+use crate::arithmetic::{compute_inner_product, CurveAffine, FieldExt};
+use crate::poly::commitment::{CommitmentScheme, Verifier};
+use crate::poly::VerificationStrategy;
+use crate::poly::{
+    commitment::{Blind, Params, MSM},
+    Guard, VerifierQuery,
+};
+use crate::transcript::{read_n_points, read_n_scalars, EncodedChallenge, TranscriptRead};
+
+#[cfg(feature = "batch")]
+mod batch;
+#[cfg(feature = "batch")]
+pub use batch::BatchVerifier;
+
+use crate::poly::commitment::ParamsVerifier;
+
+/// Returns a boolean indicating whether or not the proof is valid
+pub fn verify_proof<
+    'params,
+    Scheme: CommitmentScheme,
+    V: Verifier<'params, Scheme>,
+    E: EncodedChallenge<Scheme::Curve>,
+    T: TranscriptRead<Scheme::Curve, E>,
+    Strategy: VerificationStrategy<'params, Scheme, V>,
+>(
+    params: &'params Scheme::ParamsVerifier,
+    vk: &VerifyingKey<Scheme::Curve>,
+    strategy: Strategy,
+    instances: &[&[&[Scheme::Scalar]]],
+    transcript: &mut T,
+) -> Result<Strategy::Output, Error> {
+    // Check that instances matches the expected number of instance columns
+    for instances in instances.iter() {
+        if instances.len() != vk.cs.num_instance_columns {
+            return Err(Error::InvalidInstances);
+        }
+    }
+
+    let instance_commitments = if V::QUERY_INSTANCE {
+        instances
+            .iter()
+            .map(|instance| {
+                instance
+                    .iter()
+                    .map(|instance| {
+                        if instance.len() > params.n() as usize - (vk.cs.blinding_factors() + 1) {
+                            return Err(Error::InstanceTooLarge);
+                        }
+                        let mut poly = instance.to_vec();
+                        poly.resize(params.n() as usize, Scheme::Scalar::zero());
+                        let poly = vk.domain.lagrange_from_vec(poly);
+
+                        Ok(params.commit_lagrange(&poly, Blind::default()).to_affine())
+                    })
+                    .collect::<Result<Vec<_>, _>>()
+            })
+            .collect::<Result<Vec<_>, _>>()?
+    } else {
+        vec![vec![]; instances.len()]
+    };
+
+    let num_proofs = instance_commitments.len();
+
+    // Hash verification key into transcript
+    vk.hash_into(transcript)?;
+
+    if V::QUERY_INSTANCE {
+        for instance_commitments in instance_commitments.iter() {
+            // Hash the instance (external) commitments into the transcript
+            for commitment in instance_commitments {
+                transcript.common_point(*commitment)?
+            }
+        }
+    } else {
+        for instance in instances.iter() {
+            for instance in instance.iter() {
+                for value in instance.iter() {
+                    transcript.common_scalar(*value)?;
+                }
+            }
+        }
+    }
+
+    // Hash the prover's advice commitments into the transcript and squeeze challenges
+    let (advice_commitments, challenges) = {
+        let mut advice_commitments =
+            vec![vec![Scheme::Curve::default(); vk.cs.num_advice_columns]; num_proofs];
+        let mut challenges = vec![Scheme::Scalar::zero(); vk.cs.num_challenges];
+
+        for current_phase in vk.cs.phases() {
+            for advice_commitments in advice_commitments.iter_mut() {
+                for (phase, commitment) in vk
+                    .cs
+                    .advice_column_phase
+                    .iter()
+                    .zip(advice_commitments.iter_mut())
+                {
+                    if current_phase == *phase {
+                        *commitment = transcript.read_point()?;
+                    }
+                }
+            }
+            for (phase, challenge) in vk.cs.challenge_phase.iter().zip(challenges.iter_mut()) {
+                if current_phase == *phase {
+                    *challenge = *transcript.squeeze_challenge_scalar::<()>();
+                }
+            }
+        }
+
+        (advice_commitments, challenges)
+    };
+
+    // Sample theta challenge for keeping lookup columns linearly independent
+    let theta: ChallengeTheta<_> = transcript.squeeze_challenge_scalar();
+
+    let lookups_permuted = (0..num_proofs)
+        .map(|_| -> Result<Vec<_>, _> {
+            // Hash each lookup permuted commitment
+            vk.cs
+                .lookups
+                .iter()
+                .map(|argument| argument.read_permuted_commitments(transcript))
+                .collect::<Result<Vec<_>, _>>()
+        })
+        .collect::<Result<Vec<_>, _>>()?;
+
+    // Sample beta challenge
+    let beta: ChallengeBeta<_> = transcript.squeeze_challenge_scalar();
+
+    // Sample gamma challenge
+    let gamma: ChallengeGamma<_> = transcript.squeeze_challenge_scalar();
+
+    let permutations_committed = (0..num_proofs)
+        .map(|_| {
+            // Hash each permutation product commitment
+            vk.cs.permutation.read_product_commitments(vk, transcript)
+        })
+        .collect::<Result<Vec<_>, _>>()?;
+
+    let lookups_committed = lookups_permuted
+        .into_iter()
+        .map(|lookups| {
+            // Hash each lookup product commitment
+            lookups
+                .into_iter()
+                .map(|lookup| lookup.read_product_commitment(transcript))
+                .collect::<Result<Vec<_>, _>>()
+        })
+        .collect::<Result<Vec<_>, _>>()?;
+
+    let vanishing = vanishing::Argument::read_commitments_before_y(transcript)?;
+
+    // Sample y challenge, which keeps the gates linearly independent.
+    let y: ChallengeY<_> = transcript.squeeze_challenge_scalar();
+
+    let vanishing = vanishing.read_commitments_after_y(vk, transcript)?;
+
+    // Sample x challenge, which is used to ensure the circuit is
+    // satisfied with high probability.
+    let x: ChallengeX<_> = transcript.squeeze_challenge_scalar();
+    let instance_evals = if V::QUERY_INSTANCE {
+        (0..num_proofs)
+            .map(|_| -> Result<Vec<_>, _> {
+                read_n_scalars(transcript, vk.cs.instance_queries.len())
+            })
+            .collect::<Result<Vec<_>, _>>()?
+    } else {
+        let xn = x.pow(&[params.n() as u64, 0, 0, 0]);
+        let (min_rotation, max_rotation) =
+            vk.cs
+                .instance_queries
+                .iter()
+                .fold((0, 0), |(min, max), (_, rotation)| {
+                    if rotation.0 < min {
+                        (rotation.0, max)
+                    } else if rotation.0 > max {
+                        (min, rotation.0)
+                    } else {
+                        (min, max)
+                    }
+                });
+        let max_instance_len = instances
+            .iter()
+            .flat_map(|instance| instance.iter().map(|instance| instance.len()))
+            .max_by(Ord::cmp)
+            .unwrap_or_default();
+        let l_i_s = &vk.domain.l_i_range(
+            *x,
+            xn,
+            -max_rotation..max_instance_len as i32 + min_rotation.abs(),
+        );
+        instances
+            .iter()
+            .map(|instances| {
+                vk.cs
+                    .instance_queries
+                    .iter()
+                    .map(|(column, rotation)| {
+                        let instances = instances[column.index()];
+                        let offset = (max_rotation - rotation.0) as usize;
+                        compute_inner_product(instances, &l_i_s[offset..offset + instances.len()])
+                    })
+                    .collect::<Vec<_>>()
+            })
+            .collect::<Vec<_>>()
+    };
+
+    let advice_evals = (0..num_proofs)
+        .map(|_| -> Result<Vec<_>, _> { read_n_scalars(transcript, vk.cs.advice_queries.len()) })
+        .collect::<Result<Vec<_>, _>>()?;
+
+    let fixed_evals = read_n_scalars(transcript, vk.cs.fixed_queries.len())?;
+
+    let vanishing = vanishing.evaluate_after_x(transcript)?;
+
+    let permutations_common = vk.permutation.evaluate(transcript)?;
+
+    let permutations_evaluated = permutations_committed
+        .into_iter()
+        .map(|permutation| permutation.evaluate(transcript))
+        .collect::<Result<Vec<_>, _>>()?;
+
+    let lookups_evaluated = lookups_committed
+        .into_iter()
+        .map(|lookups| -> Result<Vec<_>, _> {
+            lookups
+                .into_iter()
+                .map(|lookup| lookup.evaluate(transcript))
+                .collect::<Result<Vec<_>, _>>()
+        })
+        .collect::<Result<Vec<_>, _>>()?;
+
+    // This check ensures the circuit is satisfied so long as the polynomial
+    // commitments open to the correct values.
+    let vanishing = {
+        // x^n
+        let xn = x.pow(&[params.n() as u64, 0, 0, 0]);
+
+        let blinding_factors = vk.cs.blinding_factors();
+        let l_evals = vk
+            .domain
+            .l_i_range(*x, xn, (-((blinding_factors + 1) as i32))..=0);
+        assert_eq!(l_evals.len(), 2 + blinding_factors);
+        let l_last = l_evals[0];
+        let l_blind: Scheme::Scalar = l_evals[1..(1 + blinding_factors)]
+            .iter()
+            .fold(Scheme::Scalar::zero(), |acc, eval| acc + eval);
+        let l_0 = l_evals[1 + blinding_factors];
+
+        // Compute the expected value of h(x)
+        let expressions = advice_evals
+            .iter()
+            .zip(instance_evals.iter())
+            .zip(permutations_evaluated.iter())
+            .zip(lookups_evaluated.iter())
+            .flat_map(|(((advice_evals, instance_evals), permutation), lookups)| {
+                let challenges = &challenges;
+                let fixed_evals = &fixed_evals;
+                std::iter::empty()
+                    // Evaluate the circuit using the custom gates provided
+                    .chain(vk.cs.gates.iter().flat_map(move |gate| {
+                        gate.polynomials().iter().map(move |poly| {
+                            poly.evaluate(
+                                &|scalar| scalar,
+                                &|_| panic!("virtual selectors are removed during optimization"),
+                                &|query| fixed_evals[query.index],
+                                &|query| advice_evals[query.index],
+                                &|query| instance_evals[query.index],
+                                &|challenge| challenges[challenge.index()],
+                                &|a| -a,
+                                &|a, b| a + &b,
+                                &|a, b| a * &b,
+                                &|a, scalar| a * &scalar,
+                            )
+                        })
+                    }))
+                    .chain(permutation.expressions(
+                        vk,
+                        &vk.cs.permutation,
+                        &permutations_common,
+                        advice_evals,
+                        fixed_evals,
+                        instance_evals,
+                        l_0,
+                        l_last,
+                        l_blind,
+                        beta,
+                        gamma,
+                        x,
+                    ))
+                    .chain(
+                        lookups
+                            .iter()
+                            .zip(vk.cs.lookups.iter())
+                            .flat_map(move |(p, argument)| {
+                                p.expressions(
+                                    l_0,
+                                    l_last,
+                                    l_blind,
+                                    argument,
+                                    theta,
+                                    beta,
+                                    gamma,
+                                    advice_evals,
+                                    fixed_evals,
+                                    instance_evals,
+                                    challenges,
+                                )
+                            })
+                            .into_iter(),
+                    )
+            });
+
+        vanishing.verify(params, expressions, y, xn)
+    };
+
+    let queries = instance_commitments
+        .iter()
+        .zip(instance_evals.iter())
+        .zip(advice_commitments.iter())
+        .zip(advice_evals.iter())
+        .zip(permutations_evaluated.iter())
+        .zip(lookups_evaluated.iter())
+        .flat_map(
+            |(
+                (
+                    (((instance_commitments, instance_evals), advice_commitments), advice_evals),
+                    permutation,
+                ),
+                lookups,
+            )| {
+                iter::empty()
+                    .chain(
+                        V::QUERY_INSTANCE
+                            .then_some(vk.cs.instance_queries.iter().enumerate().map(
+                                move |(query_index, &(column, at))| {
+                                    VerifierQuery::new_commitment(
+                                        &instance_commitments[column.index()],
+                                        vk.domain.rotate_omega(*x, at),
+                                        instance_evals[query_index],
+                                    )
+                                },
+                            ))
+                            .into_iter()
+                            .flatten(),
+                    )
+                    .chain(vk.cs.advice_queries.iter().enumerate().map(
+                        move |(query_index, &(column, at))| {
+                            VerifierQuery::new_commitment(
+                                &advice_commitments[column.index()],
+                                vk.domain.rotate_omega(*x, at),
+                                advice_evals[query_index],
+                            )
+                        },
+                    ))
+                    .chain(permutation.queries(vk, x))
+                    .chain(
+                        lookups
+                            .iter()
+                            .flat_map(move |p| p.queries(vk, x))
+                            .into_iter(),
+                    )
+            },
+        )
+        .chain(
+            vk.cs
+                .fixed_queries
+                .iter()
+                .enumerate()
+                .map(|(query_index, &(column, at))| {
+                    VerifierQuery::new_commitment(
+                        &vk.fixed_commitments[column.index()],
+                        vk.domain.rotate_omega(*x, at),
+                        fixed_evals[query_index],
+                    )
+                }),
+        )
+        .chain(permutations_common.queries(&vk.permutation, x))
+        .chain(vanishing.queries(x));
+
+    // We are now convinced the circuit is satisfied so long as the
+    // polynomial commitments open to the correct values.
+
+    let verifier = V::new(params);
+    strategy.process(|msm| {
+        verifier
+            .verify_proof(transcript, queries, msm)
+            .map_err(|_| Error::Opening)
+    })
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/plonk/verifier/batch.rs.html b/docs/src/halo2_proofs/plonk/verifier/batch.rs.html new file mode 100644 index 0000000000..7d3d8cc6e0 --- /dev/null +++ b/docs/src/halo2_proofs/plonk/verifier/batch.rs.html @@ -0,0 +1,268 @@ +batch.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+
use std::{io, marker::PhantomData};
+
+use group::ff::Field;
+use halo2curves::CurveAffine;
+use rand_core::{OsRng, RngCore};
+use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
+
+use super::{verify_proof, VerificationStrategy};
+use crate::{
+    multicore,
+    plonk::{Error, VerifyingKey},
+    poly::{
+        commitment::{Params, MSM},
+        ipa::{
+            commitment::{IPACommitmentScheme, ParamsVerifierIPA},
+            msm::MSMIPA,
+            multiopen::VerifierIPA,
+            strategy::GuardIPA,
+        },
+    },
+    transcript::{Blake2bRead, TranscriptReadBuffer},
+};
+
+/// A proof verification strategy that returns the proof's MSM.
+///
+/// `BatchVerifier` handles the accumulation of the MSMs for the batched proofs.
+#[derive(Debug)]
+struct BatchStrategy<'params, C: CurveAffine> {
+    msm: MSMIPA<'params, C>,
+}
+
+impl<'params, C: CurveAffine>
+    VerificationStrategy<'params, IPACommitmentScheme<C>, VerifierIPA<'params, C>>
+    for BatchStrategy<'params, C>
+{
+    type Output = MSMIPA<'params, C>;
+
+    fn new(params: &'params ParamsVerifierIPA<C>) -> Self {
+        BatchStrategy {
+            msm: MSMIPA::new(params),
+        }
+    }
+
+    fn process(
+        self,
+        f: impl FnOnce(MSMIPA<'params, C>) -> Result<GuardIPA<'params, C>, Error>,
+    ) -> Result<Self::Output, Error> {
+        let guard = f(self.msm)?;
+        Ok(guard.use_challenges())
+    }
+
+    fn finalize(self) -> bool {
+        unreachable!()
+    }
+}
+
+#[derive(Debug)]
+struct BatchItem<C: CurveAffine> {
+    instances: Vec<Vec<Vec<C::ScalarExt>>>,
+    proof: Vec<u8>,
+}
+
+/// A verifier that checks multiple proofs in a batch. **This requires the
+/// `batch` crate feature to be enabled.**
+#[derive(Debug, Default)]
+pub struct BatchVerifier<C: CurveAffine> {
+    items: Vec<BatchItem<C>>,
+}
+
+impl<C: CurveAffine> BatchVerifier<C> {
+    /// Constructs a new batch verifier.
+    pub fn new() -> Self {
+        Self { items: vec![] }
+    }
+
+    /// Adds a proof to the batch.
+    pub fn add_proof(&mut self, instances: Vec<Vec<Vec<C::Scalar>>>, proof: Vec<u8>) {
+        self.items.push(BatchItem { instances, proof })
+    }
+
+    /// Finalizes the batch and checks its validity.
+    ///
+    /// Returns `false` if *some* proof was invalid. If the caller needs to identify
+    /// specific failing proofs, it must re-process the proofs separately.
+    ///
+    /// This uses [`OsRng`] internally instead of taking an `R: RngCore` argument, because
+    /// the internal parallelization requires access to a RNG that is guaranteed to not
+    /// clone its internal state when shared between threads.
+    pub fn finalize(self, params: &ParamsVerifierIPA<C>, vk: &VerifyingKey<C>) -> bool {
+        fn accumulate_msm<'params, C: CurveAffine>(
+            mut acc: MSMIPA<'params, C>,
+            msm: MSMIPA<'params, C>,
+        ) -> MSMIPA<'params, C> {
+            // Scale the MSM by a random factor to ensure that if the existing MSM has
+            // `is_zero() == false` then this argument won't be able to interfere with it
+            // to make it true, with high probability.
+            acc.scale(C::Scalar::random(OsRng));
+
+            acc.add_msm(&msm);
+            acc
+        }
+
+        let final_msm = self
+            .items
+            .into_par_iter()
+            .enumerate()
+            .map(|(i, item)| {
+                let instances: Vec<Vec<_>> = item
+                    .instances
+                    .iter()
+                    .map(|i| i.iter().map(|c| &c[..]).collect())
+                    .collect();
+                let instances: Vec<_> = instances.iter().map(|i| &i[..]).collect();
+
+                let strategy = BatchStrategy::new(params);
+                let mut transcript = Blake2bRead::init(&item.proof[..]);
+                verify_proof(params, vk, strategy, &instances, &mut transcript).map_err(|e| {
+                    tracing::debug!("Batch item {} failed verification: {}", i, e);
+                    e
+                })
+            })
+            .try_fold(
+                || params.empty_msm(),
+                |msm, res| res.map(|proof_msm| accumulate_msm(msm, proof_msm)),
+            )
+            .try_reduce(|| params.empty_msm(), |a, b| Ok(accumulate_msm(a, b)));
+
+        match final_msm {
+            Ok(msm) => msm.check(),
+            Err(_) => false,
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly.rs.html b/docs/src/halo2_proofs/poly.rs.html new file mode 100644 index 0000000000..ca14f36307 --- /dev/null +++ b/docs/src/halo2_proofs/poly.rs.html @@ -0,0 +1,722 @@ +poly.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+
//! Contains utilities for performing arithmetic over univariate polynomials in
+//! various forms, including computing commitments to them and provably opening
+//! the committed polynomials at arbitrary points.
+
+use crate::arithmetic::parallelize;
+use crate::helpers::SerdePrimeField;
+use crate::plonk::Assigned;
+use crate::SerdeFormat;
+
+use ff::PrimeField;
+use group::ff::{BatchInvert, Field};
+use halo2curves::FieldExt;
+use std::fmt::Debug;
+use std::io;
+use std::marker::PhantomData;
+use std::ops::{Add, Deref, DerefMut, Index, IndexMut, Mul, RangeFrom, RangeFull, Sub};
+
+/// Generic commitment scheme structures
+pub mod commitment;
+mod domain;
+mod query;
+mod strategy;
+
+/// Inner product argument commitment scheme
+pub mod ipa;
+
+/// KZG commitment scheme
+pub mod kzg;
+
+#[cfg(test)]
+mod multiopen_test;
+
+pub use domain::*;
+pub use query::{ProverQuery, VerifierQuery};
+pub use strategy::{Guard, VerificationStrategy};
+
+/// This is an error that could occur during proving or circuit synthesis.
+// TODO: these errors need to be cleaned up
+#[derive(Debug)]
+pub enum Error {
+    /// OpeningProof is not well-formed
+    OpeningError,
+    /// Caller needs to re-sample a point
+    SamplingError,
+}
+
+/// The basis over which a polynomial is described.
+pub trait Basis: Copy + Debug + Send + Sync {}
+
+/// The polynomial is defined as coefficients
+#[derive(Clone, Copy, Debug)]
+pub struct Coeff;
+impl Basis for Coeff {}
+
+/// The polynomial is defined as coefficients of Lagrange basis polynomials
+#[derive(Clone, Copy, Debug)]
+pub struct LagrangeCoeff;
+impl Basis for LagrangeCoeff {}
+
+/// The polynomial is defined as coefficients of Lagrange basis polynomials in
+/// an extended size domain which supports multiplication
+#[derive(Clone, Copy, Debug)]
+pub struct ExtendedLagrangeCoeff;
+impl Basis for ExtendedLagrangeCoeff {}
+
+/// Represents a univariate polynomial defined over a field and a particular
+/// basis.
+#[derive(Clone, Debug)]
+pub struct Polynomial<F, B> {
+    values: Vec<F>,
+    _marker: PhantomData<B>,
+}
+
+impl<F, B> Index<usize> for Polynomial<F, B> {
+    type Output = F;
+
+    fn index(&self, index: usize) -> &F {
+        self.values.index(index)
+    }
+}
+
+impl<F, B> IndexMut<usize> for Polynomial<F, B> {
+    fn index_mut(&mut self, index: usize) -> &mut F {
+        self.values.index_mut(index)
+    }
+}
+
+impl<F, B> Index<RangeFrom<usize>> for Polynomial<F, B> {
+    type Output = [F];
+
+    fn index(&self, index: RangeFrom<usize>) -> &[F] {
+        self.values.index(index)
+    }
+}
+
+impl<F, B> IndexMut<RangeFrom<usize>> for Polynomial<F, B> {
+    fn index_mut(&mut self, index: RangeFrom<usize>) -> &mut [F] {
+        self.values.index_mut(index)
+    }
+}
+
+impl<F, B> Index<RangeFull> for Polynomial<F, B> {
+    type Output = [F];
+
+    fn index(&self, index: RangeFull) -> &[F] {
+        self.values.index(index)
+    }
+}
+
+impl<F, B> IndexMut<RangeFull> for Polynomial<F, B> {
+    fn index_mut(&mut self, index: RangeFull) -> &mut [F] {
+        self.values.index_mut(index)
+    }
+}
+
+impl<F, B> Deref for Polynomial<F, B> {
+    type Target = [F];
+
+    fn deref(&self) -> &[F] {
+        &self.values[..]
+    }
+}
+
+impl<F, B> DerefMut for Polynomial<F, B> {
+    fn deref_mut(&mut self) -> &mut [F] {
+        &mut self.values[..]
+    }
+}
+
+impl<F, B> Polynomial<F, B> {
+    /// Iterate over the values, which are either in coefficient or evaluation
+    /// form depending on the basis `B`.
+    pub fn iter(&self) -> impl Iterator<Item = &F> {
+        self.values.iter()
+    }
+
+    /// Iterate over the values mutably, which are either in coefficient or
+    /// evaluation form depending on the basis `B`.
+    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut F> {
+        self.values.iter_mut()
+    }
+
+    /// Gets the size of this polynomial in terms of the number of
+    /// coefficients used to describe it.
+    pub fn num_coeffs(&self) -> usize {
+        self.values.len()
+    }
+}
+
+impl<F: SerdePrimeField, B> Polynomial<F, B> {
+    /// Reads polynomial from buffer using `SerdePrimeField::read`.  
+    pub(crate) fn read<R: io::Read>(reader: &mut R, format: SerdeFormat) -> Self {
+        let mut poly_len = [0u8; 4];
+        reader.read_exact(&mut poly_len).unwrap();
+        let poly_len = u32::from_be_bytes(poly_len);
+        Self {
+            values: (0..poly_len).map(|_| F::read(reader, format)).collect(),
+            _marker: PhantomData,
+        }
+    }
+
+    /// Writes polynomial to buffer using `SerdePrimeField::write`.  
+    pub(crate) fn write<W: io::Write>(&self, writer: &mut W, format: SerdeFormat) {
+        writer
+            .write_all(&(self.values.len() as u32).to_be_bytes())
+            .unwrap();
+        for value in self.values.iter() {
+            value.write(writer, format);
+        }
+    }
+}
+
+/// Invert each polynomial in place for memory efficiency
+pub(crate) fn batch_invert_assigned_ref<F: FieldExt>(
+    assigned: Vec<&Polynomial<Assigned<F>, LagrangeCoeff>>,
+) -> Vec<Polynomial<F, LagrangeCoeff>> {
+    if assigned.is_empty() {
+        return vec![];
+    }
+    let n = assigned[0].num_coeffs();
+    // 1d vector better for memory allocation
+    let mut assigned_denominators: Vec<_> = assigned
+        .iter()
+        .flat_map(|f| f.iter().map(|value| value.denominator()))
+        .collect();
+
+    assigned_denominators
+        .iter_mut()
+        // If the denominator is trivial, we can skip it, reducing the
+        // size of the batch inversion.
+        .filter_map(|d| d.as_mut())
+        .batch_invert();
+
+    assigned
+        .iter()
+        .zip(assigned_denominators.chunks(n))
+        .map(|(poly, inv_denoms)| {
+            debug_assert_eq!(inv_denoms.len(), poly.values.len());
+            Polynomial {
+                values: poly
+                    .values
+                    .iter()
+                    .zip(inv_denoms.iter())
+                    .map(|(a, inv_den)| a.numerator() * inv_den.unwrap_or(F::one()))
+                    .collect(),
+                _marker: poly._marker,
+            }
+        })
+        .collect()
+}
+
+pub(crate) fn batch_invert_assigned<F: FieldExt>(
+    assigned: Vec<Polynomial<Assigned<F>, LagrangeCoeff>>,
+) -> Vec<Polynomial<F, LagrangeCoeff>> {
+    let mut assigned_denominators: Vec<_> = assigned
+        .iter()
+        .map(|f| {
+            f.iter()
+                .map(|value| value.denominator())
+                .collect::<Vec<_>>()
+        })
+        .collect();
+
+    assigned_denominators
+        .iter_mut()
+        .flat_map(|f| {
+            f.iter_mut()
+                // If the denominator is trivial, we can skip it, reducing the
+                // size of the batch inversion.
+                .filter_map(|d| d.as_mut())
+        })
+        .batch_invert();
+
+    assigned
+        .iter()
+        .zip(assigned_denominators.into_iter())
+        .map(|(poly, inv_denoms)| {
+            poly.invert(inv_denoms.into_iter().map(|d| d.unwrap_or_else(F::one)))
+        })
+        .collect()
+}
+
+impl<F: Field> Polynomial<Assigned<F>, LagrangeCoeff> {
+    pub(crate) fn invert(
+        &self,
+        inv_denoms: impl Iterator<Item = F> + ExactSizeIterator,
+    ) -> Polynomial<F, LagrangeCoeff> {
+        assert_eq!(inv_denoms.len(), self.values.len());
+        Polynomial {
+            values: self
+                .values
+                .iter()
+                .zip(inv_denoms.into_iter())
+                .map(|(a, inv_den)| a.numerator() * inv_den)
+                .collect(),
+            _marker: self._marker,
+        }
+    }
+}
+
+impl<'a, F: Field, B: Basis> Add<&'a Polynomial<F, B>> for Polynomial<F, B> {
+    type Output = Polynomial<F, B>;
+
+    fn add(mut self, rhs: &'a Polynomial<F, B>) -> Polynomial<F, B> {
+        parallelize(&mut self.values, |lhs, start| {
+            for (lhs, rhs) in lhs.iter_mut().zip(rhs.values[start..].iter()) {
+                *lhs += *rhs;
+            }
+        });
+
+        self
+    }
+}
+
+impl<'a, F: Field, B: Basis> Sub<&'a Polynomial<F, B>> for Polynomial<F, B> {
+    type Output = Polynomial<F, B>;
+
+    fn sub(mut self, rhs: &'a Polynomial<F, B>) -> Polynomial<F, B> {
+        parallelize(&mut self.values, |lhs, start| {
+            for (lhs, rhs) in lhs.iter_mut().zip(rhs.values[start..].iter()) {
+                *lhs -= *rhs;
+            }
+        });
+
+        self
+    }
+}
+
+impl<F: Field> Polynomial<F, LagrangeCoeff> {
+    /// Rotates the values in a Lagrange basis polynomial by `Rotation`
+    pub fn rotate(&self, rotation: Rotation) -> Polynomial<F, LagrangeCoeff> {
+        let mut values = self.values.clone();
+        if rotation.0 < 0 {
+            values.rotate_right((-rotation.0) as usize);
+        } else {
+            values.rotate_left(rotation.0 as usize);
+        }
+        Polynomial {
+            values,
+            _marker: PhantomData,
+        }
+    }
+}
+
+impl<F: Field, B: Basis> Mul<F> for Polynomial<F, B> {
+    type Output = Polynomial<F, B>;
+
+    fn mul(mut self, rhs: F) -> Polynomial<F, B> {
+        if rhs == F::zero() {
+            return Polynomial {
+                values: vec![F::zero(); self.len()],
+                _marker: PhantomData,
+            };
+        }
+        if rhs == F::one() {
+            return self;
+        }
+
+        parallelize(&mut self.values, |lhs, _| {
+            for lhs in lhs.iter_mut() {
+                *lhs *= rhs;
+            }
+        });
+
+        self
+    }
+}
+
+impl<'a, F: Field, B: Basis> Sub<F> for &'a Polynomial<F, B> {
+    type Output = Polynomial<F, B>;
+
+    fn sub(self, rhs: F) -> Polynomial<F, B> {
+        let mut res = self.clone();
+        res.values[0] -= rhs;
+        res
+    }
+}
+
+/// Describes the relative rotation of a vector. Negative numbers represent
+/// reverse (leftmost) rotations and positive numbers represent forward (rightmost)
+/// rotations. Zero represents no rotation.
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub struct Rotation(pub i32);
+
+impl Rotation {
+    /// The current location in the evaluation domain
+    pub fn cur() -> Rotation {
+        Rotation(0)
+    }
+
+    /// The previous location in the evaluation domain
+    pub fn prev() -> Rotation {
+        Rotation(-1)
+    }
+
+    /// The next location in the evaluation domain
+    pub fn next() -> Rotation {
+        Rotation(1)
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/commitment.rs.html b/docs/src/halo2_proofs/poly/commitment.rs.html new file mode 100644 index 0000000000..9c60d95c30 --- /dev/null +++ b/docs/src/halo2_proofs/poly/commitment.rs.html @@ -0,0 +1,494 @@ +commitment.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+
use super::{
+    query::{ProverQuery, VerifierQuery},
+    strategy::Guard,
+    Coeff, LagrangeCoeff, Polynomial,
+};
+use crate::poly::Error;
+use crate::transcript::{EncodedChallenge, TranscriptRead, TranscriptWrite};
+use ff::Field;
+use group::Curve;
+use halo2curves::{CurveAffine, CurveExt, FieldExt};
+use rand_core::RngCore;
+use std::{
+    fmt::Debug,
+    io::{self, Read, Write},
+    ops::{Add, AddAssign, Mul, MulAssign},
+};
+
+/// Defines components of a commitment scheme.
+pub trait CommitmentScheme {
+    /// Application field of this commitment scheme
+    type Scalar: FieldExt + halo2curves::Group;
+
+    /// Elliptic curve used to commit the application and witnesses
+    type Curve: CurveAffine<ScalarExt = Self::Scalar>;
+
+    /// Constant prover parameters
+    type ParamsProver: for<'params> ParamsProver<
+        'params,
+        Self::Curve,
+        ParamsVerifier = Self::ParamsVerifier,
+    >;
+
+    /// Constant verifier parameters
+    type ParamsVerifier: for<'params> ParamsVerifier<'params, Self::Curve>;
+
+    /// Wrapper for parameter generator
+    fn new_params(k: u32) -> Self::ParamsProver;
+
+    /// Wrapper for parameter reader
+    fn read_params<R: io::Read>(reader: &mut R) -> io::Result<Self::ParamsProver>;
+}
+
+/// Parameters for circuit sysnthesis and prover parameters.
+pub trait Params<'params, C: CurveAffine>: Sized + Clone {
+    /// Multi scalar multiplication engine
+    type MSM: MSM<C> + 'params;
+
+    /// Logaritmic size of the circuit
+    fn k(&self) -> u32;
+
+    /// Size of the circuit
+    fn n(&self) -> u64;
+
+    /// Downsize `Params` with smaller `k`.
+    fn downsize(&mut self, k: u32);
+
+    /// Generates an empty multiscalar multiplication struct using the
+    /// appropriate params.
+    fn empty_msm(&'params self) -> Self::MSM;
+
+    /// This commits to a polynomial using its evaluations over the $2^k$ size
+    /// evaluation domain. The commitment will be blinded by the blinding factor
+    /// `r`.
+    fn commit_lagrange(
+        &self,
+        poly: &Polynomial<C::ScalarExt, LagrangeCoeff>,
+        r: Blind<C::ScalarExt>,
+    ) -> C::CurveExt;
+
+    /// Writes params to a buffer.
+    fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()>;
+
+    /// Reads params from a buffer.
+    fn read<R: io::Read>(reader: &mut R) -> io::Result<Self>;
+}
+
+/// Parameters for circuit sysnthesis and prover parameters.
+pub trait ParamsProver<'params, C: CurveAffine>: Params<'params, C> {
+    /// Constant verifier parameters.
+    type ParamsVerifier: ParamsVerifier<'params, C>;
+
+    /// Returns new instance of parameters
+    fn new(k: u32) -> Self;
+
+    /// This computes a commitment to a polynomial described by the provided
+    /// slice of coefficients. The commitment may be blinded by the blinding
+    /// factor `r`.
+    fn commit(&self, poly: &Polynomial<C::ScalarExt, Coeff>, r: Blind<C::ScalarExt>)
+        -> C::CurveExt;
+
+    /// Getter for g generators
+    fn get_g(&self) -> &[C];
+
+    /// Returns verification parameters.
+    fn verifier_params(&'params self) -> &'params Self::ParamsVerifier;
+}
+
+/// Verifier specific functionality with circuit constaints
+pub trait ParamsVerifier<'params, C: CurveAffine>: Params<'params, C> {}
+
+/// Multi scalar multiplication engine
+pub trait MSM<C: CurveAffine>: Clone + Debug + Send + Sync {
+    /// Add arbitrary term (the scalar and the point)
+    fn append_term(&mut self, scalar: C::Scalar, point: C::CurveExt);
+
+    /// Add another multiexp into this one
+    fn add_msm(&mut self, other: &Self)
+    where
+        Self: Sized;
+
+    /// Scale all scalars in the MSM by some scaling factor
+    fn scale(&mut self, factor: C::Scalar);
+
+    /// Perform multiexp and check that it results in zero
+    fn check(&self) -> bool;
+
+    /// Perform multiexp and return the result
+    fn eval(&self) -> C::CurveExt;
+
+    /// Return base points
+    fn bases(&self) -> Vec<C::CurveExt>;
+
+    /// Scalars
+    fn scalars(&self) -> Vec<C::Scalar>;
+}
+
+/// Common multi-open prover interface for various commitment schemes
+pub trait Prover<'params, Scheme: CommitmentScheme> {
+    /// Query instance or not
+    const QUERY_INSTANCE: bool;
+
+    /// Creates new prover instance
+    fn new(params: &'params Scheme::ParamsProver) -> Self;
+
+    /// Create a multi-opening proof
+    fn create_proof<
+        'com,
+        E: EncodedChallenge<Scheme::Curve>,
+        T: TranscriptWrite<Scheme::Curve, E>,
+        R,
+        I,
+    >(
+        &self,
+        rng: R,
+        transcript: &mut T,
+        queries: I,
+    ) -> io::Result<()>
+    where
+        I: IntoIterator<Item = ProverQuery<'com, Scheme::Curve>> + Clone,
+        R: RngCore;
+}
+
+/// Common multi-open verifier interface for various commitment schemes
+pub trait Verifier<'params, Scheme: CommitmentScheme> {
+    /// Unfinalized verification result. This is returned in verification
+    /// to allow developer to compress or combined verification results
+    type Guard: Guard<Scheme, MSMAccumulator = Self::MSMAccumulator>;
+
+    /// Accumulator fot comressed verification
+    type MSMAccumulator;
+
+    /// Query instance or not
+    const QUERY_INSTANCE: bool;
+
+    /// Creates new verifier instance
+    fn new(params: &'params Scheme::ParamsVerifier) -> Self;
+
+    /// Process the proof and returns unfinished result named `Guard`
+    fn verify_proof<
+        'com,
+        E: EncodedChallenge<Scheme::Curve>,
+        T: TranscriptRead<Scheme::Curve, E>,
+        I,
+    >(
+        &self,
+        transcript: &mut T,
+        queries: I,
+        msm: Self::MSMAccumulator,
+    ) -> Result<Self::Guard, Error>
+    where
+        'params: 'com,
+        I: IntoIterator<
+                Item = VerifierQuery<
+                    'com,
+                    Scheme::Curve,
+                    <Scheme::ParamsVerifier as Params<'params, Scheme::Curve>>::MSM,
+                >,
+            > + Clone;
+}
+
+/// Wrapper type around a blinding factor.
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
+pub struct Blind<F>(pub F);
+
+impl<F: FieldExt> Default for Blind<F> {
+    fn default() -> Self {
+        Blind(F::one())
+    }
+}
+
+impl<F: FieldExt> Blind<F> {
+    /// Given `rng` creates new blinding scalar
+    pub fn new<R: RngCore>(rng: &mut R) -> Self {
+        Blind(F::random(rng))
+    }
+}
+
+impl<F: FieldExt> Add for Blind<F> {
+    type Output = Self;
+
+    fn add(self, rhs: Blind<F>) -> Self {
+        Blind(self.0 + rhs.0)
+    }
+}
+
+impl<F: FieldExt> Mul for Blind<F> {
+    type Output = Self;
+
+    fn mul(self, rhs: Blind<F>) -> Self {
+        Blind(self.0 * rhs.0)
+    }
+}
+
+impl<F: FieldExt> AddAssign for Blind<F> {
+    fn add_assign(&mut self, rhs: Blind<F>) {
+        self.0 += rhs.0;
+    }
+}
+
+impl<F: FieldExt> MulAssign for Blind<F> {
+    fn mul_assign(&mut self, rhs: Blind<F>) {
+        self.0 *= rhs.0;
+    }
+}
+
+impl<F: FieldExt> AddAssign<F> for Blind<F> {
+    fn add_assign(&mut self, rhs: F) {
+        self.0 += rhs;
+    }
+}
+
+impl<F: FieldExt> MulAssign<F> for Blind<F> {
+    fn mul_assign(&mut self, rhs: F) {
+        self.0 *= rhs;
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/domain.rs.html b/docs/src/halo2_proofs/poly/domain.rs.html new file mode 100644 index 0000000000..4dd23f71a8 --- /dev/null +++ b/docs/src/halo2_proofs/poly/domain.rs.html @@ -0,0 +1,1140 @@ +domain.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+
//! Contains utilities for performing polynomial arithmetic over an evaluation
+//! domain that is of a suitable size for the application.
+
+use crate::{
+    arithmetic::{best_fft, parallelize, FieldExt, Group},
+    plonk::Assigned,
+};
+
+use super::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial, Rotation};
+
+use group::ff::{BatchInvert, Field, PrimeField};
+
+use std::marker::PhantomData;
+
+/// This structure contains precomputed constants and other details needed for
+/// performing operations on an evaluation domain of size $2^k$ and an extended
+/// domain of size $2^{k} * j$ with $j \neq 0$.
+#[derive(Clone, Debug)]
+pub struct EvaluationDomain<G: Group> {
+    n: u64,
+    k: u32,
+    extended_k: u32,
+    omega: G::Scalar,
+    omega_inv: G::Scalar,
+    extended_omega: G::Scalar,
+    extended_omega_inv: G::Scalar,
+    g_coset: G::Scalar,
+    g_coset_inv: G::Scalar,
+    quotient_poly_degree: u64,
+    ifft_divisor: G::Scalar,
+    extended_ifft_divisor: G::Scalar,
+    t_evaluations: Vec<G::Scalar>,
+    barycentric_weight: G::Scalar,
+}
+
+impl<G: Group> EvaluationDomain<G> {
+    /// This constructs a new evaluation domain object based on the provided
+    /// values $j, k$.
+    pub fn new(j: u32, k: u32) -> Self {
+        // quotient_poly_degree * params.n - 1 is the degree of the quotient polynomial
+        let quotient_poly_degree = (j - 1) as u64;
+
+        // n = 2^k
+        let n = 1u64 << k;
+
+        // We need to work within an extended domain, not params.k but params.k + i
+        // for some integer i such that 2^(params.k + i) is sufficiently large to
+        // describe the quotient polynomial.
+        let mut extended_k = k;
+        while (1 << extended_k) < (n * quotient_poly_degree) {
+            extended_k += 1;
+        }
+
+        let mut extended_omega = G::Scalar::root_of_unity();
+
+        // Get extended_omega, the 2^{extended_k}'th root of unity
+        // The loop computes extended_omega = omega^{2 ^ (S - extended_k)}
+        // Notice that extended_omega ^ {2 ^ extended_k} = omega ^ {2^S} = 1.
+        for _ in extended_k..G::Scalar::S {
+            extended_omega = extended_omega.square();
+        }
+        let extended_omega = extended_omega;
+        let mut extended_omega_inv = extended_omega; // Inversion computed later
+
+        // Get omega, the 2^{k}'th root of unity (i.e. n'th root of unity)
+        // The loop computes omega = extended_omega ^ {2 ^ (extended_k - k)}
+        //           = (omega^{2 ^ (S - extended_k)})  ^ {2 ^ (extended_k - k)}
+        //           = omega ^ {2 ^ (S - k)}.
+        // Notice that omega ^ {2^k} = omega ^ {2^S} = 1.
+        let mut omega = extended_omega;
+        for _ in k..extended_k {
+            omega = omega.square();
+        }
+        let omega = omega;
+        let mut omega_inv = omega; // Inversion computed later
+
+        // We use zeta here because we know it generates a coset, and it's available
+        // already.
+        // The coset evaluation domain is:
+        // zeta {1, extended_omega, extended_omega^2, ..., extended_omega^{(2^extended_k) - 1}}
+        let g_coset = G::Scalar::ZETA;
+        let g_coset_inv = g_coset.square();
+
+        let mut t_evaluations = Vec::with_capacity(1 << (extended_k - k));
+        {
+            // Compute the evaluations of t(X) = X^n - 1 in the coset evaluation domain.
+            // We don't have to compute all of them, because it will repeat.
+            let orig = G::Scalar::ZETA.pow_vartime([n]);
+            let step = extended_omega.pow_vartime([n]);
+            let mut cur = orig;
+            loop {
+                t_evaluations.push(cur);
+                cur *= &step;
+                if cur == orig {
+                    break;
+                }
+            }
+            assert_eq!(t_evaluations.len(), 1 << (extended_k - k));
+
+            // Subtract 1 from each to give us t_evaluations[i] = t(zeta * extended_omega^i)
+            for coeff in &mut t_evaluations {
+                *coeff -= &G::Scalar::one();
+            }
+
+            // Invert, because we're dividing by this polynomial.
+            // We invert in a batch, below.
+        }
+
+        let mut ifft_divisor = G::Scalar::from(1 << k); // Inversion computed later
+        let mut extended_ifft_divisor = G::Scalar::from(1 << extended_k); // Inversion computed later
+
+        // The barycentric weight of 1 over the evaluation domain
+        // 1 / \prod_{i != 0} (1 - omega^i)
+        let mut barycentric_weight = G::Scalar::from(n); // Inversion computed later
+
+        // Compute batch inversion
+        t_evaluations
+            .iter_mut()
+            .chain(Some(&mut ifft_divisor))
+            .chain(Some(&mut extended_ifft_divisor))
+            .chain(Some(&mut barycentric_weight))
+            .chain(Some(&mut extended_omega_inv))
+            .chain(Some(&mut omega_inv))
+            .batch_invert();
+
+        EvaluationDomain {
+            n,
+            k,
+            extended_k,
+            omega,
+            omega_inv,
+            extended_omega,
+            extended_omega_inv,
+            g_coset,
+            g_coset_inv,
+            quotient_poly_degree,
+            ifft_divisor,
+            extended_ifft_divisor,
+            t_evaluations,
+            barycentric_weight,
+        }
+    }
+
+    /// Obtains a polynomial in Lagrange form when given a vector of Lagrange
+    /// coefficients of size `n`; panics if the provided vector is the wrong
+    /// length.
+    pub fn lagrange_from_vec(&self, values: Vec<G>) -> Polynomial<G, LagrangeCoeff> {
+        assert_eq!(values.len(), self.n as usize);
+
+        Polynomial {
+            values,
+            _marker: PhantomData,
+        }
+    }
+
+    pub fn lagrange_assigned_from_vec(
+        &self,
+        values: Vec<Assigned<G>>,
+    ) -> Polynomial<Assigned<G>, LagrangeCoeff> {
+        assert_eq!(values.len(), self.n as usize);
+
+        Polynomial {
+            values,
+            _marker: PhantomData,
+        }
+    }
+
+    /// Obtains a polynomial in coefficient form when given a vector of
+    /// coefficients of size `n`; panics if the provided vector is the wrong
+    /// length.
+    pub fn coeff_from_vec(&self, values: Vec<G>) -> Polynomial<G, Coeff> {
+        assert_eq!(values.len(), self.n as usize);
+
+        Polynomial {
+            values,
+            _marker: PhantomData,
+        }
+    }
+
+    /// Returns an empty (zero) polynomial in the coefficient basis
+    pub fn empty_coeff(&self) -> Polynomial<G, Coeff> {
+        Polynomial {
+            values: vec![G::group_zero(); self.n as usize],
+            _marker: PhantomData,
+        }
+    }
+
+    /// Returns an empty (zero) polynomial in the Lagrange coefficient basis
+    pub fn empty_lagrange(&self) -> Polynomial<G, LagrangeCoeff> {
+        Polynomial {
+            values: vec![G::group_zero(); self.n as usize],
+            _marker: PhantomData,
+        }
+    }
+
+    /// Returns an empty (zero) polynomial in the Lagrange coefficient basis, with
+    /// deferred inversions.
+    pub(crate) fn empty_lagrange_assigned(&self) -> Polynomial<Assigned<G>, LagrangeCoeff>
+    where
+        G: Field,
+    {
+        Polynomial {
+            values: vec![G::group_zero().into(); self.n as usize],
+            _marker: PhantomData,
+        }
+    }
+
+    /// Returns a constant polynomial in the Lagrange coefficient basis
+    pub fn constant_lagrange(&self, scalar: G) -> Polynomial<G, LagrangeCoeff> {
+        Polynomial {
+            values: vec![scalar; self.n as usize],
+            _marker: PhantomData,
+        }
+    }
+
+    /// Returns an empty (zero) polynomial in the extended Lagrange coefficient
+    /// basis
+    pub fn empty_extended(&self) -> Polynomial<G, ExtendedLagrangeCoeff> {
+        Polynomial {
+            values: vec![G::group_zero(); self.extended_len()],
+            _marker: PhantomData,
+        }
+    }
+
+    /// Returns a constant polynomial in the extended Lagrange coefficient
+    /// basis
+    pub fn constant_extended(&self, scalar: G) -> Polynomial<G, ExtendedLagrangeCoeff> {
+        Polynomial {
+            values: vec![scalar; self.extended_len()],
+            _marker: PhantomData,
+        }
+    }
+
+    /// This takes us from an n-length vector into the coefficient form.
+    ///
+    /// This function will panic if the provided vector is not the correct
+    /// length.
+    pub fn lagrange_to_coeff(&self, mut a: Polynomial<G, LagrangeCoeff>) -> Polynomial<G, Coeff> {
+        assert_eq!(a.values.len(), 1 << self.k);
+
+        // Perform inverse FFT to obtain the polynomial in coefficient form
+        Self::ifft(&mut a.values, self.omega_inv, self.k, self.ifft_divisor);
+
+        Polynomial {
+            values: a.values,
+            _marker: PhantomData,
+        }
+    }
+
+    /// This takes us from an n-length coefficient vector into a coset of the extended
+    /// evaluation domain, rotating by `rotation` if desired.
+    pub fn coeff_to_extended(
+        &self,
+        mut a: Polynomial<G, Coeff>,
+    ) -> Polynomial<G, ExtendedLagrangeCoeff> {
+        assert_eq!(a.values.len(), 1 << self.k);
+
+        self.distribute_powers_zeta(&mut a.values, true);
+        a.values.resize(self.extended_len(), G::group_zero());
+        best_fft(&mut a.values, self.extended_omega, self.extended_k);
+
+        Polynomial {
+            values: a.values,
+            _marker: PhantomData,
+        }
+    }
+
+    /// Rotate the extended domain polynomial over the original domain.
+    pub fn rotate_extended(
+        &self,
+        poly: &Polynomial<G, ExtendedLagrangeCoeff>,
+        rotation: Rotation,
+    ) -> Polynomial<G, ExtendedLagrangeCoeff> {
+        let new_rotation = ((1 << (self.extended_k - self.k)) * rotation.0.abs()) as usize;
+
+        let mut poly = poly.clone();
+
+        if rotation.0 >= 0 {
+            poly.values.rotate_left(new_rotation);
+        } else {
+            poly.values.rotate_right(new_rotation);
+        }
+
+        poly
+    }
+
+    /// This takes us from the extended evaluation domain and gets us the
+    /// quotient polynomial coefficients.
+    ///
+    /// This function will panic if the provided vector is not the correct
+    /// length.
+    // TODO/FIXME: caller should be responsible for truncating
+    pub fn extended_to_coeff(&self, mut a: Polynomial<G, ExtendedLagrangeCoeff>) -> Vec<G> {
+        assert_eq!(a.values.len(), self.extended_len());
+
+        // Inverse FFT
+        Self::ifft(
+            &mut a.values,
+            self.extended_omega_inv,
+            self.extended_k,
+            self.extended_ifft_divisor,
+        );
+
+        // Distribute powers to move from coset; opposite from the
+        // transformation we performed earlier.
+        self.distribute_powers_zeta(&mut a.values, false);
+
+        // Truncate it to match the size of the quotient polynomial; the
+        // evaluation domain might be slightly larger than necessary because
+        // it always lies on a power-of-two boundary.
+        a.values
+            .truncate((&self.n * self.quotient_poly_degree) as usize);
+
+        a.values
+    }
+
+    /// This divides the polynomial (in the extended domain) by the vanishing
+    /// polynomial of the $2^k$ size domain.
+    pub fn divide_by_vanishing_poly(
+        &self,
+        mut a: Polynomial<G, ExtendedLagrangeCoeff>,
+    ) -> Polynomial<G, ExtendedLagrangeCoeff> {
+        assert_eq!(a.values.len(), self.extended_len());
+
+        // Divide to obtain the quotient polynomial in the coset evaluation
+        // domain.
+        parallelize(&mut a.values, |h, mut index| {
+            for h in h {
+                h.group_scale(&self.t_evaluations[index % self.t_evaluations.len()]);
+                index += 1;
+            }
+        });
+
+        Polynomial {
+            values: a.values,
+            _marker: PhantomData,
+        }
+    }
+
+    /// Given a slice of group elements `[a_0, a_1, a_2, ...]`, this returns
+    /// `[a_0, [zeta]a_1, [zeta^2]a_2, a_3, [zeta]a_4, [zeta^2]a_5, a_6, ...]`,
+    /// where zeta is a cube root of unity in the multiplicative subgroup with
+    /// order (p - 1), i.e. zeta^3 = 1.
+    ///
+    /// `into_coset` should be set to `true` when moving into the coset,
+    /// and `false` when moving out. This toggles the choice of `zeta`.
+    fn distribute_powers_zeta(&self, a: &mut [G], into_coset: bool) {
+        let coset_powers = if into_coset {
+            [self.g_coset, self.g_coset_inv]
+        } else {
+            [self.g_coset_inv, self.g_coset]
+        };
+        parallelize(a, |a, mut index| {
+            for a in a {
+                // Distribute powers to move into/from coset
+                let i = index % (coset_powers.len() + 1);
+                if i != 0 {
+                    a.group_scale(&coset_powers[i - 1]);
+                }
+                index += 1;
+            }
+        });
+    }
+
+    fn ifft(a: &mut [G], omega_inv: G::Scalar, log_n: u32, divisor: G::Scalar) {
+        best_fft(a, omega_inv, log_n);
+        parallelize(a, |a, _| {
+            for a in a {
+                // Finish iFFT
+                a.group_scale(&divisor);
+            }
+        });
+    }
+
+    /// Get the size of the domain
+    pub fn k(&self) -> u32 {
+        self.k
+    }
+
+    /// Get the size of the extended domain
+    pub fn extended_k(&self) -> u32 {
+        self.extended_k
+    }
+
+    /// Get the size of the extended domain
+    pub fn extended_len(&self) -> usize {
+        1 << self.extended_k
+    }
+
+    /// Get $\omega$, the generator of the $2^k$ order multiplicative subgroup.
+    pub fn get_omega(&self) -> G::Scalar {
+        self.omega
+    }
+
+    /// Get $\omega^{-1}$, the inverse of the generator of the $2^k$ order
+    /// multiplicative subgroup.
+    pub fn get_omega_inv(&self) -> G::Scalar {
+        self.omega_inv
+    }
+
+    /// Get the generator of the extended domain's multiplicative subgroup.
+    pub fn get_extended_omega(&self) -> G::Scalar {
+        self.extended_omega
+    }
+
+    /// Multiplies a value by some power of $\omega$, essentially rotating over
+    /// the domain.
+    pub fn rotate_omega(&self, value: G::Scalar, rotation: Rotation) -> G::Scalar {
+        let mut point = value;
+        if rotation.0 >= 0 {
+            point *= &self.get_omega().pow_vartime(&[rotation.0 as u64]);
+        } else {
+            point *= &self
+                .get_omega_inv()
+                .pow_vartime(&[(rotation.0 as i64).unsigned_abs()]);
+        }
+        point
+    }
+
+    /// Computes evaluations (at the point `x`, where `xn = x^n`) of Lagrange
+    /// basis polynomials `l_i(X)` defined such that `l_i(omega^i) = 1` and
+    /// `l_i(omega^j) = 0` for all `j != i` at each provided rotation `i`.
+    ///
+    /// # Implementation
+    ///
+    /// The polynomial
+    ///     $$\prod_{j=0,j \neq i}^{n - 1} (X - \omega^j)$$
+    /// has a root at all points in the domain except $\omega^i$, where it evaluates to
+    ///     $$\prod_{j=0,j \neq i}^{n - 1} (\omega^i - \omega^j)$$
+    /// and so we divide that polynomial by this value to obtain $l_i(X)$. Since
+    ///     $$\prod_{j=0,j \neq i}^{n - 1} (X - \omega^j)
+    ///       = \frac{X^n - 1}{X - \omega^i}$$
+    /// then $l_i(x)$ for some $x$ is evaluated as
+    ///     $$\left(\frac{x^n - 1}{x - \omega^i}\right)
+    ///       \cdot \left(\frac{1}{\prod_{j=0,j \neq i}^{n - 1} (\omega^i - \omega^j)}\right).$$
+    /// We refer to
+    ///     $$1 \over \prod_{j=0,j \neq i}^{n - 1} (\omega^i - \omega^j)$$
+    /// as the barycentric weight of $\omega^i$.
+    ///
+    /// We know that for $i = 0$
+    ///     $$\frac{1}{\prod_{j=0,j \neq i}^{n - 1} (\omega^i - \omega^j)} = \frac{1}{n}.$$
+    ///
+    /// If we multiply $(1 / n)$ by $\omega^i$ then we obtain
+    ///     $$\frac{1}{\prod_{j=0,j \neq 0}^{n - 1} (\omega^i - \omega^j)}
+    ///       = \frac{1}{\prod_{j=0,j \neq i}^{n - 1} (\omega^i - \omega^j)}$$
+    /// which is the barycentric weight of $\omega^i$.
+    pub fn l_i_range<I: IntoIterator<Item = i32> + Clone>(
+        &self,
+        x: G::Scalar,
+        xn: G::Scalar,
+        rotations: I,
+    ) -> Vec<G::Scalar> {
+        let mut results;
+        {
+            let rotations = rotations.clone().into_iter();
+            results = Vec::with_capacity(rotations.size_hint().1.unwrap_or(0));
+            for rotation in rotations {
+                let rotation = Rotation(rotation);
+                let result = x - self.rotate_omega(G::Scalar::one(), rotation);
+                results.push(result);
+            }
+            results.iter_mut().batch_invert();
+        }
+
+        let common = (xn - G::Scalar::one()) * self.barycentric_weight;
+        for (rotation, result) in rotations.into_iter().zip(results.iter_mut()) {
+            let rotation = Rotation(rotation);
+            *result = self.rotate_omega(*result * common, rotation);
+        }
+
+        results
+    }
+
+    /// Gets the quotient polynomial's degree (as a multiple of n)
+    pub fn get_quotient_poly_degree(&self) -> usize {
+        self.quotient_poly_degree as usize
+    }
+
+    /// Obtain a pinned version of this evaluation domain; a structure with the
+    /// minimal parameters needed to determine the rest of the evaluation
+    /// domain.
+    pub fn pinned(&self) -> PinnedEvaluationDomain<'_, G> {
+        PinnedEvaluationDomain {
+            k: &self.k,
+            extended_k: &self.extended_k,
+            omega: &self.omega,
+        }
+    }
+}
+
+/// Represents the minimal parameters that determine an `EvaluationDomain`.
+#[allow(dead_code)]
+#[derive(Debug)]
+pub struct PinnedEvaluationDomain<'a, G: Group> {
+    k: &'a u32,
+    extended_k: &'a u32,
+    omega: &'a G::Scalar,
+}
+
+#[test]
+fn test_rotate() {
+    use rand_core::OsRng;
+
+    use crate::arithmetic::eval_polynomial;
+    use halo2curves::pasta::pallas::Scalar;
+
+    let domain = EvaluationDomain::<Scalar>::new(1, 3);
+    let rng = OsRng;
+
+    let mut poly = domain.empty_lagrange();
+    assert_eq!(poly.len(), 8);
+    for value in poly.iter_mut() {
+        *value = Scalar::random(rng);
+    }
+
+    let poly_rotated_cur = poly.rotate(Rotation::cur());
+    let poly_rotated_next = poly.rotate(Rotation::next());
+    let poly_rotated_prev = poly.rotate(Rotation::prev());
+
+    let poly = domain.lagrange_to_coeff(poly);
+    let poly_rotated_cur = domain.lagrange_to_coeff(poly_rotated_cur);
+    let poly_rotated_next = domain.lagrange_to_coeff(poly_rotated_next);
+    let poly_rotated_prev = domain.lagrange_to_coeff(poly_rotated_prev);
+
+    let x = Scalar::random(rng);
+
+    assert_eq!(
+        eval_polynomial(&poly[..], x),
+        eval_polynomial(&poly_rotated_cur[..], x)
+    );
+    assert_eq!(
+        eval_polynomial(&poly[..], x * domain.omega),
+        eval_polynomial(&poly_rotated_next[..], x)
+    );
+    assert_eq!(
+        eval_polynomial(&poly[..], x * domain.omega_inv),
+        eval_polynomial(&poly_rotated_prev[..], x)
+    );
+}
+
+#[test]
+fn test_l_i() {
+    use rand_core::OsRng;
+
+    use crate::arithmetic::{eval_polynomial, lagrange_interpolate};
+    use halo2curves::pasta::pallas::Scalar;
+    let domain = EvaluationDomain::<Scalar>::new(1, 3);
+
+    let mut l = vec![];
+    let mut points = vec![];
+    for i in 0..8 {
+        points.push(domain.omega.pow(&[i, 0, 0, 0]));
+    }
+    for i in 0..8 {
+        let mut l_i = vec![Scalar::zero(); 8];
+        l_i[i] = Scalar::one();
+        let l_i = lagrange_interpolate(&points[..], &l_i[..]);
+        l.push(l_i);
+    }
+
+    let x = Scalar::random(OsRng);
+    let xn = x.pow(&[8, 0, 0, 0]);
+
+    let evaluations = domain.l_i_range(x, xn, -7..=7);
+    for i in 0..8 {
+        assert_eq!(eval_polynomial(&l[i][..], x), evaluations[7 + i]);
+        assert_eq!(eval_polynomial(&l[(8 - i) % 8][..], x), evaluations[7 - i]);
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/ipa/commitment.rs.html b/docs/src/halo2_proofs/poly/ipa/commitment.rs.html new file mode 100644 index 0000000000..ba7d118271 --- /dev/null +++ b/docs/src/halo2_proofs/poly/ipa/commitment.rs.html @@ -0,0 +1,770 @@ +commitment.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+
//! This module contains an implementation of the polynomial commitment scheme
+//! described in the [Halo][halo] paper.
+//!
+//! [halo]: https://eprint.iacr.org/2019/1021
+
+use crate::arithmetic::{
+    best_fft, best_multiexp, g_to_lagrange, parallelize, CurveAffine, CurveExt, FieldExt, Group,
+};
+use crate::helpers::CurveRead;
+use crate::poly::commitment::{Blind, CommitmentScheme, Params, ParamsProver, ParamsVerifier, MSM};
+use crate::poly::ipa::msm::MSMIPA;
+use crate::poly::{Coeff, LagrangeCoeff, Polynomial};
+
+use ff::{Field, PrimeField};
+use group::{prime::PrimeCurveAffine, Curve, Group as _};
+use std::marker::PhantomData;
+use std::ops::{Add, AddAssign, Mul, MulAssign};
+
+mod prover;
+mod verifier;
+
+pub use prover::create_proof;
+pub use verifier::verify_proof;
+
+use std::io;
+
+/// Public parameters for IPA commitment scheme
+#[derive(Debug, Clone)]
+pub struct ParamsIPA<C: CurveAffine> {
+    pub(crate) k: u32,
+    pub(crate) n: u64,
+    pub(crate) g: Vec<C>,
+    pub(crate) g_lagrange: Vec<C>,
+    pub(crate) w: C,
+    pub(crate) u: C,
+}
+
+/// Concrete IPA commitment scheme
+#[derive(Debug)]
+pub struct IPACommitmentScheme<C: CurveAffine> {
+    _marker: PhantomData<C>,
+}
+
+impl<C: CurveAffine> CommitmentScheme for IPACommitmentScheme<C> {
+    type Scalar = C::ScalarExt;
+    type Curve = C;
+
+    type ParamsProver = ParamsIPA<C>;
+    type ParamsVerifier = ParamsVerifierIPA<C>;
+
+    fn new_params(k: u32) -> Self::ParamsProver {
+        ParamsIPA::new(k)
+    }
+
+    fn read_params<R: io::Read>(reader: &mut R) -> io::Result<Self::ParamsProver> {
+        ParamsIPA::read(reader)
+    }
+}
+
+/// Verifier parameters
+pub type ParamsVerifierIPA<C> = ParamsIPA<C>;
+
+impl<'params, C: CurveAffine> ParamsVerifier<'params, C> for ParamsIPA<C> {}
+
+impl<'params, C: CurveAffine> Params<'params, C> for ParamsIPA<C> {
+    type MSM = MSMIPA<'params, C>;
+
+    fn k(&self) -> u32 {
+        self.k
+    }
+
+    fn n(&self) -> u64 {
+        self.n
+    }
+
+    fn downsize(&mut self, k: u32) {
+        assert!(k <= self.k);
+
+        self.k = k;
+        self.n = 1 << k;
+        self.g.truncate(self.n as usize);
+        self.g_lagrange = g_to_lagrange(self.g.iter().map(|g| g.to_curve()).collect(), k);
+    }
+
+    fn empty_msm(&'params self) -> MSMIPA<C> {
+        MSMIPA::new(self)
+    }
+
+    /// This commits to a polynomial using its evaluations over the $2^k$ size
+    /// evaluation domain. The commitment will be blinded by the blinding factor
+    /// `r`.
+    fn commit_lagrange(
+        &self,
+        poly: &Polynomial<C::Scalar, LagrangeCoeff>,
+        r: Blind<C::Scalar>,
+    ) -> C::Curve {
+        let mut tmp_scalars = Vec::with_capacity(poly.len() + 1);
+        let mut tmp_bases = Vec::with_capacity(poly.len() + 1);
+
+        tmp_scalars.extend(poly.iter());
+        tmp_scalars.push(r.0);
+
+        tmp_bases.extend(self.g_lagrange.iter());
+        tmp_bases.push(self.w);
+
+        best_multiexp::<C>(&tmp_scalars, &tmp_bases)
+    }
+
+    /// Writes params to a buffer.
+    fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
+        writer.write_all(&self.k.to_le_bytes())?;
+        for g_element in &self.g {
+            writer.write_all(g_element.to_bytes().as_ref())?;
+        }
+        for g_lagrange_element in &self.g_lagrange {
+            writer.write_all(g_lagrange_element.to_bytes().as_ref())?;
+        }
+        writer.write_all(self.w.to_bytes().as_ref())?;
+        writer.write_all(self.u.to_bytes().as_ref())?;
+
+        Ok(())
+    }
+
+    /// Reads params from a buffer.
+    fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
+        let mut k = [0u8; 4];
+        reader.read_exact(&mut k[..])?;
+        let k = u32::from_le_bytes(k);
+
+        let n: u64 = 1 << k;
+
+        let g: Vec<_> = (0..n).map(|_| C::read(reader)).collect::<Result<_, _>>()?;
+        let g_lagrange: Vec<_> = (0..n).map(|_| C::read(reader)).collect::<Result<_, _>>()?;
+
+        let w = C::read(reader)?;
+        let u = C::read(reader)?;
+
+        Ok(Self {
+            k,
+            n,
+            g,
+            g_lagrange,
+            w,
+            u,
+        })
+    }
+}
+
+impl<'params, C: CurveAffine> ParamsProver<'params, C> for ParamsIPA<C> {
+    type ParamsVerifier = ParamsVerifierIPA<C>;
+
+    fn verifier_params(&'params self) -> &'params Self::ParamsVerifier {
+        self
+    }
+
+    /// Initializes parameters for the curve, given a random oracle to draw
+    /// points from.
+    fn new(k: u32) -> Self {
+        // This is usually a limitation on the curve, but we also want 32-bit
+        // architectures to be supported.
+        assert!(k < 32);
+
+        // In src/arithmetic/fields.rs we ensure that usize is at least 32 bits.
+
+        let n: u64 = 1 << k;
+
+        let g_projective = {
+            let mut g = Vec::with_capacity(n as usize);
+            g.resize(n as usize, C::Curve::identity());
+
+            parallelize(&mut g, move |g, start| {
+                let hasher = C::CurveExt::hash_to_curve("Halo2-Parameters");
+
+                for (i, g) in g.iter_mut().enumerate() {
+                    let i = (i + start) as u32;
+
+                    let mut message = [0u8; 5];
+                    message[1..5].copy_from_slice(&i.to_le_bytes());
+
+                    *g = hasher(&message);
+                }
+            });
+
+            g
+        };
+
+        let g = {
+            let mut g = vec![C::identity(); n as usize];
+            parallelize(&mut g, |g, starts| {
+                C::Curve::batch_normalize(&g_projective[starts..(starts + g.len())], g);
+            });
+            g
+        };
+
+        // Let's evaluate all of the Lagrange basis polynomials
+        // using an inverse FFT.
+        let g_lagrange = g_to_lagrange(g_projective, k);
+
+        let hasher = C::CurveExt::hash_to_curve("Halo2-Parameters");
+        let w = hasher(&[1]).to_affine();
+        let u = hasher(&[2]).to_affine();
+
+        ParamsIPA {
+            k,
+            n,
+            g,
+            g_lagrange,
+            w,
+            u,
+        }
+    }
+
+    /// This computes a commitment to a polynomial described by the provided
+    /// slice of coefficients. The commitment will be blinded by the blinding
+    /// factor `r`.
+    fn commit(&self, poly: &Polynomial<C::Scalar, Coeff>, r: Blind<C::Scalar>) -> C::Curve {
+        let mut tmp_scalars = Vec::with_capacity(poly.len() + 1);
+        let mut tmp_bases = Vec::with_capacity(poly.len() + 1);
+
+        tmp_scalars.extend(poly.iter());
+        tmp_scalars.push(r.0);
+
+        tmp_bases.extend(self.g.iter());
+        tmp_bases.push(self.w);
+
+        best_multiexp::<C>(&tmp_scalars, &tmp_bases)
+    }
+
+    fn get_g(&self) -> &[C] {
+        &self.g
+    }
+}
+
+#[cfg(test)]
+mod test {
+
+    use crate::arithmetic::{
+        best_fft, best_multiexp, parallelize, CurveAffine, CurveExt, FieldExt, Group,
+    };
+    use crate::helpers::CurveRead;
+    use crate::poly::commitment::ParamsProver;
+    use crate::poly::commitment::{Blind, CommitmentScheme, Params, MSM};
+    use crate::poly::ipa::commitment::{create_proof, verify_proof, ParamsIPA};
+    use crate::poly::ipa::msm::MSMIPA;
+    use crate::poly::{Coeff, LagrangeCoeff, Polynomial};
+
+    use ff::{Field, PrimeField};
+    use group::{prime::PrimeCurveAffine, Curve, Group as _};
+    use std::marker::PhantomData;
+    use std::ops::{Add, AddAssign, Mul, MulAssign};
+
+    use std::io;
+
+    #[test]
+    fn test_commit_lagrange_epaffine() {
+        const K: u32 = 6;
+
+        use rand_core::OsRng;
+
+        use crate::poly::EvaluationDomain;
+        use halo2curves::pasta::{EpAffine, Fq};
+
+        let params = ParamsIPA::<EpAffine>::new(K);
+        let domain = EvaluationDomain::new(1, K);
+
+        let mut a = domain.empty_lagrange();
+
+        for (i, a) in a.iter_mut().enumerate() {
+            *a = Fq::from(i as u64);
+        }
+
+        let b = domain.lagrange_to_coeff(a.clone());
+
+        let alpha = Blind(Fq::random(OsRng));
+
+        assert_eq!(params.commit(&b, alpha), params.commit_lagrange(&a, alpha));
+    }
+
+    #[test]
+    fn test_commit_lagrange_eqaffine() {
+        const K: u32 = 6;
+
+        use rand_core::OsRng;
+
+        use crate::poly::EvaluationDomain;
+        use halo2curves::pasta::{EqAffine, Fp};
+
+        let params: ParamsIPA<EqAffine> = ParamsIPA::<EqAffine>::new(K);
+        let domain = EvaluationDomain::new(1, K);
+
+        let mut a = domain.empty_lagrange();
+
+        for (i, a) in a.iter_mut().enumerate() {
+            *a = Fp::from(i as u64);
+        }
+
+        let b = domain.lagrange_to_coeff(a.clone());
+
+        let alpha = Blind(Fp::random(OsRng));
+
+        assert_eq!(params.commit(&b, alpha), params.commit_lagrange(&a, alpha));
+    }
+
+    #[test]
+    fn test_opening_proof() {
+        const K: u32 = 6;
+
+        use ff::Field;
+        use rand_core::OsRng;
+
+        use super::super::commitment::{Blind, Params};
+        use crate::arithmetic::{eval_polynomial, FieldExt};
+        use crate::halo2curves::pasta::{EpAffine, Fq};
+        use crate::poly::EvaluationDomain;
+        use crate::transcript::{
+            Blake2bRead, Blake2bWrite, Challenge255, Transcript, TranscriptRead, TranscriptWrite,
+        };
+
+        use crate::transcript::TranscriptReadBuffer;
+        use crate::transcript::TranscriptWriterBuffer;
+
+        let rng = OsRng;
+
+        let params = ParamsIPA::<EpAffine>::new(K);
+        let mut params_buffer = vec![];
+        <ParamsIPA<_> as Params<_>>::write(&params, &mut params_buffer).unwrap();
+        let params: ParamsIPA<EpAffine> = Params::read::<_>(&mut &params_buffer[..]).unwrap();
+
+        let domain = EvaluationDomain::new(1, K);
+
+        let mut px = domain.empty_coeff();
+
+        for (i, a) in px.iter_mut().enumerate() {
+            *a = Fq::from(i as u64);
+        }
+
+        let blind = Blind(Fq::random(rng));
+
+        let p = params.commit(&px, blind).to_affine();
+
+        let mut transcript =
+            Blake2bWrite::<Vec<u8>, EpAffine, Challenge255<EpAffine>>::init(vec![]);
+        transcript.write_point(p).unwrap();
+        let x = transcript.squeeze_challenge_scalar::<()>();
+        // Evaluate the polynomial
+        let v = eval_polynomial(&px, *x);
+        transcript.write_scalar(v).unwrap();
+
+        let (proof, ch_prover) = {
+            create_proof(&params, rng, &mut transcript, &px, blind, *x).unwrap();
+            let ch_prover = transcript.squeeze_challenge();
+            (transcript.finalize(), ch_prover)
+        };
+
+        // Verify the opening proof
+        let mut transcript =
+            Blake2bRead::<&[u8], EpAffine, Challenge255<EpAffine>>::init(&proof[..]);
+        let p_prime = transcript.read_point().unwrap();
+        assert_eq!(p, p_prime);
+        let x_prime = transcript.squeeze_challenge_scalar::<()>();
+        assert_eq!(*x, *x_prime);
+        let v_prime = transcript.read_scalar().unwrap();
+        assert_eq!(v, v_prime);
+
+        let mut commitment_msm = MSMIPA::new(&params);
+        commitment_msm.append_term(Field::one(), p.into());
+
+        let guard = verify_proof(&params, commitment_msm, &mut transcript, *x, v).unwrap();
+        let ch_verifier = transcript.squeeze_challenge();
+        assert_eq!(*ch_prover, *ch_verifier);
+
+        // Test guard behavior prior to checking another proof
+        {
+            // Test use_challenges()
+            let msm_challenges = guard.clone().use_challenges();
+            assert!(msm_challenges.check());
+
+            // Test use_g()
+            let g = guard.compute_g();
+            let (msm_g, _accumulator) = guard.clone().use_g(g);
+            assert!(msm_g.check());
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/ipa/commitment/prover.rs.html b/docs/src/halo2_proofs/poly/ipa/commitment/prover.rs.html new file mode 100644 index 0000000000..c5eecac160 --- /dev/null +++ b/docs/src/halo2_proofs/poly/ipa/commitment/prover.rs.html @@ -0,0 +1,336 @@ +prover.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+
use ff::Field;
+use rand_core::RngCore;
+
+use super::{Params, ParamsIPA};
+use crate::arithmetic::{
+    best_multiexp, compute_inner_product, eval_polynomial, parallelize, CurveAffine, FieldExt,
+};
+
+use crate::poly::commitment::ParamsProver;
+use crate::poly::{commitment::Blind, Coeff, Polynomial};
+use crate::transcript::{EncodedChallenge, TranscriptWrite};
+
+use group::Curve;
+use std::io::{self, Write};
+
+/// Create a polynomial commitment opening proof for the polynomial defined
+/// by the coefficients `px`, the blinding factor `blind` used for the
+/// polynomial commitment, and the point `x` that the polynomial is
+/// evaluated at.
+///
+/// This function will panic if the provided polynomial is too large with
+/// respect to the polynomial commitment parameters.
+///
+/// **Important:** This function assumes that the provided `transcript` has
+/// already seen the common inputs: the polynomial commitment P, the claimed
+/// opening v, and the point x. It's probably also nice for the transcript
+/// to have seen the elliptic curve description and the URS, if you want to
+/// be rigorous.
+pub fn create_proof<
+    C: CurveAffine,
+    E: EncodedChallenge<C>,
+    R: RngCore,
+    T: TranscriptWrite<C, E>,
+>(
+    params: &ParamsIPA<C>,
+    mut rng: R,
+    transcript: &mut T,
+    p_poly: &Polynomial<C::Scalar, Coeff>,
+    p_blind: Blind<C::Scalar>,
+    x_3: C::Scalar,
+) -> io::Result<()> {
+    // We're limited to polynomials of degree n - 1.
+    assert_eq!(p_poly.len(), params.n as usize);
+
+    // Sample a random polynomial (of same degree) that has a root at x_3, first
+    // by setting all coefficients to random values.
+    let mut s_poly = (*p_poly).clone();
+    for coeff in s_poly.iter_mut() {
+        *coeff = C::Scalar::random(&mut rng);
+    }
+    // Evaluate the random polynomial at x_3
+    let s_at_x3 = eval_polynomial(&s_poly[..], x_3);
+    // Subtract constant coefficient to get a random polynomial with a root at x_3
+    s_poly[0] = s_poly[0] - &s_at_x3;
+    // And sample a random blind
+    let s_poly_blind = Blind(C::Scalar::random(&mut rng));
+
+    // Write a commitment to the random polynomial to the transcript
+    let s_poly_commitment = params.commit(&s_poly, s_poly_blind).to_affine();
+    transcript.write_point(s_poly_commitment)?;
+
+    // Challenge that will ensure that the prover cannot change P but can only
+    // witness a random polynomial commitment that agrees with P at x_3, with high
+    // probability.
+    let xi = *transcript.squeeze_challenge_scalar::<()>();
+
+    // Challenge that ensures that the prover did not interfere with the U term
+    // in their commitments.
+    let z = *transcript.squeeze_challenge_scalar::<()>();
+
+    // We'll be opening `P' = P - [v] G_0 + [ξ] S` to ensure it has a root at
+    // zero.
+    let mut p_prime_poly = s_poly * xi + p_poly;
+    let v = eval_polynomial(&p_prime_poly, x_3);
+    p_prime_poly[0] = p_prime_poly[0] - &v;
+    let p_prime_blind = s_poly_blind * Blind(xi) + p_blind;
+
+    // This accumulates the synthetic blinding factor `f` starting
+    // with the blinding factor for `P'`.
+    let mut f = p_prime_blind.0;
+
+    // Initialize the vector `p_prime` as the coefficients of the polynomial.
+    let mut p_prime = p_prime_poly.values;
+    assert_eq!(p_prime.len(), params.n as usize);
+
+    // Initialize the vector `b` as the powers of `x_3`. The inner product of
+    // `p_prime` and `b` is the evaluation of the polynomial at `x_3`.
+    let mut b = Vec::with_capacity(1 << params.k);
+    {
+        let mut cur = C::Scalar::one();
+        for _ in 0..(1 << params.k) {
+            b.push(cur);
+            cur *= &x_3;
+        }
+    }
+
+    // Initialize the vector `G'` from the URS. We'll be progressively collapsing
+    // this vector into smaller and smaller vectors until it is of length 1.
+    let mut g_prime = params.g.clone();
+
+    // Perform the inner product argument, round by round.
+    for j in 0..params.k {
+        let half = 1 << (params.k - j - 1); // half the length of `p_prime`, `b`, `G'`
+
+        // Compute L, R
+        //
+        // TODO: If we modify multiexp to take "extra" bases, we could speed
+        // this piece up a bit by combining the multiexps.
+        let l_j = best_multiexp(&p_prime[half..], &g_prime[0..half]);
+        let r_j = best_multiexp(&p_prime[0..half], &g_prime[half..]);
+        let value_l_j = compute_inner_product(&p_prime[half..], &b[0..half]);
+        let value_r_j = compute_inner_product(&p_prime[0..half], &b[half..]);
+        let l_j_randomness = C::Scalar::random(&mut rng);
+        let r_j_randomness = C::Scalar::random(&mut rng);
+        let l_j = l_j + &best_multiexp(&[value_l_j * &z, l_j_randomness], &[params.u, params.w]);
+        let r_j = r_j + &best_multiexp(&[value_r_j * &z, r_j_randomness], &[params.u, params.w]);
+        let l_j = l_j.to_affine();
+        let r_j = r_j.to_affine();
+
+        // Feed L and R into the real transcript
+        transcript.write_point(l_j)?;
+        transcript.write_point(r_j)?;
+
+        let u_j = *transcript.squeeze_challenge_scalar::<()>();
+        let u_j_inv = u_j.invert().unwrap(); // TODO, bubble this up
+
+        // Collapse `p_prime` and `b`.
+        // TODO: parallelize
+        for i in 0..half {
+            p_prime[i] = p_prime[i] + &(p_prime[i + half] * &u_j_inv);
+            b[i] = b[i] + &(b[i + half] * &u_j);
+        }
+        p_prime.truncate(half);
+        b.truncate(half);
+
+        // Collapse `G'`
+        parallel_generator_collapse(&mut g_prime, u_j);
+        g_prime.truncate(half);
+
+        // Update randomness (the synthetic blinding factor at the end)
+        f += &(l_j_randomness * &u_j_inv);
+        f += &(r_j_randomness * &u_j);
+    }
+
+    // We have fully collapsed `p_prime`, `b`, `G'`
+    assert_eq!(p_prime.len(), 1);
+    let c = p_prime[0];
+
+    transcript.write_scalar(c)?;
+    transcript.write_scalar(f)?;
+
+    Ok(())
+}
+
+fn parallel_generator_collapse<C: CurveAffine>(g: &mut [C], challenge: C::Scalar) {
+    let len = g.len() / 2;
+    let (g_lo, g_hi) = g.split_at_mut(len);
+
+    parallelize(g_lo, |g_lo, start| {
+        let g_hi = &g_hi[start..];
+        let mut tmp = Vec::with_capacity(g_lo.len());
+        for (g_lo, g_hi) in g_lo.iter().zip(g_hi.iter()) {
+            tmp.push(g_lo.to_curve() + &(*g_hi * challenge));
+        }
+        C::Curve::batch_normalize(&tmp, g_lo);
+    });
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/ipa/commitment/verifier.rs.html b/docs/src/halo2_proofs/poly/ipa/commitment/verifier.rs.html new file mode 100644 index 0000000000..02653f4542 --- /dev/null +++ b/docs/src/halo2_proofs/poly/ipa/commitment/verifier.rs.html @@ -0,0 +1,214 @@ +verifier.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+
use std::io::Read;
+
+use group::{
+    ff::{BatchInvert, Field},
+    Curve,
+};
+
+use super::ParamsIPA;
+use crate::poly::ipa::commitment::{IPACommitmentScheme, ParamsVerifierIPA};
+use crate::{
+    arithmetic::{best_multiexp, CurveAffine},
+    poly::ipa::strategy::GuardIPA,
+};
+use crate::{
+    poly::{commitment::MSM, ipa::msm::MSMIPA, strategy::Guard, Error},
+    transcript::{EncodedChallenge, TranscriptRead},
+};
+
+/// Checks to see if the proof represented within `transcript` is valid, and a
+/// point `x` that the polynomial commitment `P` opens purportedly to the value
+/// `v`. The provided `msm` should evaluate to the commitment `P` being opened.
+pub fn verify_proof<'params, C: CurveAffine, E: EncodedChallenge<C>, T: TranscriptRead<C, E>>(
+    params: &'params ParamsIPA<C>,
+    mut msm: MSMIPA<'params, C>,
+    transcript: &mut T,
+    x: C::Scalar,
+    v: C::Scalar,
+) -> Result<GuardIPA<'params, C>, Error> {
+    let k = params.k as usize;
+
+    // P' = P - [v] G_0 + [ξ] S
+    msm.add_constant_term(-v); // add [-v] G_0
+    let s_poly_commitment = transcript.read_point().map_err(|_| Error::OpeningError)?;
+    let xi = *transcript.squeeze_challenge_scalar::<()>();
+    msm.append_term(xi, s_poly_commitment.into());
+
+    let z = *transcript.squeeze_challenge_scalar::<()>();
+
+    let mut rounds = vec![];
+    for _ in 0..k {
+        // Read L and R from the proof and write them to the transcript
+        let l = transcript.read_point().map_err(|_| Error::OpeningError)?;
+        let r = transcript.read_point().map_err(|_| Error::OpeningError)?;
+
+        let u_j_packed = transcript.squeeze_challenge();
+        let u_j = *u_j_packed.as_challenge_scalar::<()>();
+
+        rounds.push((l, r, u_j, /* to be inverted */ u_j, u_j_packed));
+    }
+
+    rounds
+        .iter_mut()
+        .map(|&mut (_, _, _, ref mut u_j, _)| u_j)
+        .batch_invert();
+
+    // This is the left-hand side of the verifier equation.
+    // P' + \sum([u_j^{-1}] L_j) + \sum([u_j] R_j)
+    let mut u = Vec::with_capacity(k);
+    let mut u_packed: Vec<C::Scalar> = Vec::with_capacity(k);
+    for (l, r, u_j, u_j_inv, u_j_packed) in rounds {
+        msm.append_term(u_j_inv, l.into());
+        msm.append_term(u_j, r.into());
+
+        u.push(u_j);
+        u_packed.push(u_j_packed.get_scalar());
+    }
+
+    // Our goal is to check that the left hand side of the verifier
+    // equation
+    //     P' + \sum([u_j^{-1}] L_j) + \sum([u_j] R_j)
+    // equals (given b = \mathbf{b}_0, and the prover's values c, f),
+    // the right-hand side
+    //   = [c] (G'_0 + [b * z] U) + [f] W
+    // Subtracting the right-hand side from both sides we get
+    //   P' + \sum([u_j^{-1}] L_j) + \sum([u_j] R_j)
+    //   + [-c] G'_0 + [-cbz] U + [-f] W
+    //   = 0
+
+    let c = transcript.read_scalar().map_err(|_| Error::SamplingError)?;
+    let neg_c = -c;
+    let f = transcript.read_scalar().map_err(|_| Error::SamplingError)?;
+    let b = compute_b(x, &u);
+
+    msm.add_to_u_scalar(neg_c * &b * &z);
+    msm.add_to_w_scalar(-f);
+
+    let guard = GuardIPA {
+        msm,
+        neg_c,
+        u,
+        u_packed,
+    };
+
+    Ok(guard)
+}
+
+/// Computes $\prod\limits_{i=0}^{k-1} (1 + u_{k - 1 - i} x^{2^i})$.
+fn compute_b<F: Field>(x: F, u: &[F]) -> F {
+    let mut tmp = F::one();
+    let mut cur = x;
+    for u_j in u.iter().rev() {
+        tmp *= F::one() + &(*u_j * &cur);
+        cur *= cur;
+    }
+    tmp
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/ipa/mod.rs.html b/docs/src/halo2_proofs/poly/ipa/mod.rs.html new file mode 100644 index 0000000000..8e4625eb31 --- /dev/null +++ b/docs/src/halo2_proofs/poly/ipa/mod.rs.html @@ -0,0 +1,16 @@ +mod.rs - source
1
+2
+3
+4
+5
+6
+7
+
pub mod commitment;
+/// Multiscalar multiplication engines
+pub mod msm;
+/// IPA multi-open scheme
+pub mod multiopen;
+/// Strategies used with KZG scheme
+pub mod strategy;
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/ipa/msm.rs.html b/docs/src/halo2_proofs/poly/ipa/msm.rs.html new file mode 100644 index 0000000000..593a2870fe --- /dev/null +++ b/docs/src/halo2_proofs/poly/ipa/msm.rs.html @@ -0,0 +1,558 @@ +msm.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+
use super::commitment::{IPACommitmentScheme, ParamsIPA};
+use crate::arithmetic::{best_multiexp, parallelize, CurveAffine};
+use crate::poly::{
+    commitment::{CommitmentScheme, Params, MSM},
+    ipa::commitment::ParamsVerifierIPA,
+};
+use ff::Field;
+use group::Group;
+use std::collections::BTreeMap;
+
+/// A multiscalar multiplication in the polynomial commitment scheme
+#[derive(Debug, Clone)]
+pub struct MSMIPA<'params, C: CurveAffine> {
+    pub(crate) params: &'params ParamsVerifierIPA<C>,
+    g_scalars: Option<Vec<C::Scalar>>,
+    w_scalar: Option<C::Scalar>,
+    u_scalar: Option<C::Scalar>,
+    // x-coordinate -> (scalar, y-coordinate)
+    other: BTreeMap<C::Base, (C::Scalar, C::Base)>,
+}
+
+impl<'a, C: CurveAffine> MSMIPA<'a, C> {
+    /// Given verifier parameters Creates an empty multi scalar engine
+    pub fn new(params: &'a ParamsVerifierIPA<C>) -> Self {
+        let g_scalars = None;
+        let w_scalar = None;
+        let u_scalar = None;
+        let other = BTreeMap::new();
+
+        Self {
+            g_scalars,
+            w_scalar,
+            u_scalar,
+            other,
+
+            params,
+        }
+    }
+
+    /// Add another multiexp into this one
+    pub fn add_msm(&mut self, other: &Self) {
+        for (x, (scalar, y)) in other.other.iter() {
+            self.other
+                .entry(*x)
+                .and_modify(|(our_scalar, our_y)| {
+                    if our_y == y {
+                        *our_scalar += *scalar;
+                    } else {
+                        assert!(*our_y == -*y);
+                        *our_scalar -= *scalar;
+                    }
+                })
+                .or_insert((*scalar, *y));
+        }
+
+        if let Some(g_scalars) = &other.g_scalars {
+            self.add_to_g_scalars(g_scalars);
+        }
+
+        if let Some(w_scalar) = &other.w_scalar {
+            self.add_to_w_scalar(*w_scalar);
+        }
+
+        if let Some(u_scalar) = &other.u_scalar {
+            self.add_to_u_scalar(*u_scalar);
+        }
+    }
+}
+
+impl<'a, C: CurveAffine> MSM<C> for MSMIPA<'a, C> {
+    fn append_term(&mut self, scalar: C::Scalar, point: C::Curve) {
+        if !bool::from(point.is_identity()) {
+            use group::Curve;
+            let point = point.to_affine();
+            let xy = point.coordinates().unwrap();
+            let x = *xy.x();
+            let y = *xy.y();
+
+            self.other
+                .entry(x)
+                .and_modify(|(our_scalar, our_y)| {
+                    if *our_y == y {
+                        *our_scalar += scalar;
+                    } else {
+                        assert!(*our_y == -y);
+                        *our_scalar -= scalar;
+                    }
+                })
+                .or_insert((scalar, y));
+        }
+    }
+
+    /// Add another multiexp into this one
+    fn add_msm(&mut self, other: &Self) {
+        for (x, (scalar, y)) in other.other.iter() {
+            self.other
+                .entry(*x)
+                .and_modify(|(our_scalar, our_y)| {
+                    if our_y == y {
+                        *our_scalar += *scalar;
+                    } else {
+                        assert!(*our_y == -*y);
+                        *our_scalar -= *scalar;
+                    }
+                })
+                .or_insert((*scalar, *y));
+        }
+
+        if let Some(g_scalars) = &other.g_scalars {
+            self.add_to_g_scalars(g_scalars);
+        }
+
+        if let Some(w_scalar) = &other.w_scalar {
+            self.add_to_w_scalar(*w_scalar);
+        }
+
+        if let Some(u_scalar) = &other.u_scalar {
+            self.add_to_u_scalar(*u_scalar);
+        }
+    }
+
+    fn scale(&mut self, factor: C::Scalar) {
+        if let Some(g_scalars) = &mut self.g_scalars {
+            for g_scalar in g_scalars {
+                *g_scalar *= &factor;
+            }
+        }
+
+        for other in self.other.values_mut() {
+            other.0 *= factor;
+        }
+
+        self.w_scalar = self.w_scalar.map(|a| a * &factor);
+        self.u_scalar = self.u_scalar.map(|a| a * &factor);
+    }
+
+    fn check(&self) -> bool {
+        bool::from(self.eval().is_identity())
+    }
+
+    fn eval(&self) -> C::Curve {
+        let len = self.g_scalars.as_ref().map(|v| v.len()).unwrap_or(0)
+            + self.w_scalar.map(|_| 1).unwrap_or(0)
+            + self.u_scalar.map(|_| 1).unwrap_or(0)
+            + self.other.len();
+        let mut scalars: Vec<C::Scalar> = Vec::with_capacity(len);
+        let mut bases: Vec<C> = Vec::with_capacity(len);
+
+        scalars.extend(self.other.values().map(|(scalar, _)| scalar));
+        bases.extend(
+            self.other
+                .iter()
+                .map(|(x, (_, y))| C::from_xy(*x, *y).unwrap()),
+        );
+
+        if let Some(w_scalar) = self.w_scalar {
+            scalars.push(w_scalar);
+            bases.push(self.params.w);
+        }
+
+        if let Some(u_scalar) = self.u_scalar {
+            scalars.push(u_scalar);
+            bases.push(self.params.u);
+        }
+
+        if let Some(g_scalars) = &self.g_scalars {
+            scalars.extend(g_scalars);
+            bases.extend(self.params.g.iter());
+        }
+
+        assert_eq!(scalars.len(), len);
+
+        best_multiexp(&scalars, &bases)
+    }
+
+    fn bases(&self) -> Vec<C::CurveExt> {
+        self.other
+            .iter()
+            .map(|(x, (_, y))| C::from_xy(*x, *y).unwrap().into())
+            .collect()
+    }
+
+    fn scalars(&self) -> Vec<C::Scalar> {
+        self.other.values().map(|(scalar, _)| *scalar).collect()
+    }
+}
+
+impl<'a, C: CurveAffine> MSMIPA<'a, C> {
+    /// Add a value to the first entry of `g_scalars`.
+    pub fn add_constant_term(&mut self, constant: C::Scalar) {
+        if let Some(g_scalars) = self.g_scalars.as_mut() {
+            g_scalars[0] += &constant;
+        } else {
+            let mut g_scalars = vec![C::Scalar::zero(); self.params.n as usize];
+            g_scalars[0] += &constant;
+            self.g_scalars = Some(g_scalars);
+        }
+    }
+
+    /// Add a vector of scalars to `g_scalars`. This function will panic if the
+    /// caller provides a slice of scalars that is not of length `params.n`.
+    pub fn add_to_g_scalars(&mut self, scalars: &[C::Scalar]) {
+        assert_eq!(scalars.len(), self.params.n as usize);
+        if let Some(g_scalars) = &mut self.g_scalars {
+            for (g_scalar, scalar) in g_scalars.iter_mut().zip(scalars.iter()) {
+                *g_scalar += scalar;
+            }
+        } else {
+            self.g_scalars = Some(scalars.to_vec());
+        }
+    }
+    /// Add to `w_scalar`
+    pub fn add_to_w_scalar(&mut self, scalar: C::Scalar) {
+        self.w_scalar = self.w_scalar.map_or(Some(scalar), |a| Some(a + &scalar));
+    }
+
+    /// Add to `u_scalar`
+    pub fn add_to_u_scalar(&mut self, scalar: C::Scalar) {
+        self.u_scalar = self.u_scalar.map_or(Some(scalar), |a| Some(a + &scalar));
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::ParamsIPA;
+    use crate::poly::commitment::ParamsProver;
+    use crate::poly::{
+        commitment::{Params, MSM},
+        ipa::msm::MSMIPA,
+    };
+    use group::Curve;
+    use halo2curves::{
+        pasta::{Ep, EpAffine, Fp, Fq},
+        CurveAffine,
+    };
+
+    #[test]
+    fn msm_arithmetic() {
+        let base: Ep = EpAffine::from_xy(-Fp::one(), Fp::from(2)).unwrap().into();
+        let base_viol = base + base;
+
+        let params = ParamsIPA::new(4);
+        let mut a: MSMIPA<EpAffine> = MSMIPA::new(&params);
+        a.append_term(Fq::one(), base);
+        // a = [1] P
+        assert!(!a.clone().check());
+        a.append_term(Fq::one(), base);
+        // a = [1+1] P
+        assert!(!a.clone().check());
+        a.append_term(-Fq::one(), base_viol);
+        // a = [1+1] P + [-1] 2P
+        assert!(a.clone().check());
+        let b = a.clone();
+
+        // Append a point that is the negation of an existing one.
+        a.append_term(Fq::from(4), -base);
+        // a = [1+1-4] P + [-1] 2P
+        assert!(!a.clone().check());
+        a.append_term(Fq::from(2), base_viol);
+        // a = [1+1-4] P + [-1+2] 2P
+        assert!(a.clone().check());
+
+        // Add two MSMs with common bases.
+        a.scale(Fq::from(3));
+        a.add_msm(&b);
+        // a = [3*(1+1)+(1+1-4)] P + [3*(-1)+(-1+2)] 2P
+        assert!(a.clone().check());
+
+        let mut c: MSMIPA<EpAffine> = MSMIPA::new(&params);
+        c.append_term(Fq::from(2), base);
+        c.append_term(Fq::one(), -base_viol);
+        // c = [2] P + [1] (-2P)
+        assert!(c.clone().check());
+        // Add two MSMs with bases that differ only in sign.
+        a.add_msm(&c);
+        assert!(a.check());
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/ipa/multiopen.rs.html b/docs/src/halo2_proofs/poly/ipa/multiopen.rs.html new file mode 100644 index 0000000000..cbd9ba0815 --- /dev/null +++ b/docs/src/halo2_proofs/poly/ipa/multiopen.rs.html @@ -0,0 +1,354 @@ +multiopen.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+
//! This module contains an optimisation of the polynomial commitment opening
+//! scheme described in the [Halo][halo] paper.
+//!
+//! [halo]: https://eprint.iacr.org/2019/1021
+
+use std::collections::{BTreeMap, BTreeSet};
+
+use super::*;
+use crate::{
+    arithmetic::{CurveAffine, FieldExt},
+    poly::query::Query,
+    transcript::ChallengeScalar,
+};
+
+mod prover;
+mod verifier;
+
+pub use prover::ProverIPA;
+pub use verifier::VerifierIPA;
+
+#[derive(Clone, Copy, Debug)]
+struct X1 {}
+/// Challenge for compressing openings at the same point sets together.
+type ChallengeX1<F> = ChallengeScalar<F, X1>;
+
+#[derive(Clone, Copy, Debug)]
+struct X2 {}
+/// Challenge for keeping the multi-point quotient polynomial terms linearly independent.
+type ChallengeX2<F> = ChallengeScalar<F, X2>;
+
+#[derive(Clone, Copy, Debug)]
+struct X3 {}
+/// Challenge point at which the commitments are opened.
+type ChallengeX3<F> = ChallengeScalar<F, X3>;
+
+#[derive(Clone, Copy, Debug)]
+struct X4 {}
+/// Challenge for collapsing the openings of the various remaining polynomials at x_3
+/// together.
+type ChallengeX4<F> = ChallengeScalar<F, X4>;
+
+#[derive(Debug)]
+struct CommitmentData<F, T: PartialEq> {
+    pub(crate) commitment: T,
+    pub(crate) set_index: usize,
+    pub(crate) point_indices: Vec<usize>,
+    pub(crate) evals: Vec<F>,
+}
+
+impl<F, T: PartialEq> CommitmentData<F, T> {
+    fn new(commitment: T) -> Self {
+        CommitmentData {
+            commitment,
+            set_index: 0,
+            point_indices: vec![],
+            evals: vec![],
+        }
+    }
+}
+
+type IntermediateSets<F, Q> = (
+    Vec<CommitmentData<<Q as Query<F>>::Eval, <Q as Query<F>>::Commitment>>,
+    Vec<Vec<F>>,
+);
+
+fn construct_intermediate_sets<F: FieldExt, I, Q: Query<F>>(queries: I) -> IntermediateSets<F, Q>
+where
+    I: IntoIterator<Item = Q> + Clone,
+{
+    // Construct sets of unique commitments and corresponding information about
+    // their queries.
+    let mut commitment_map: Vec<CommitmentData<Q::Eval, Q::Commitment>> = vec![];
+
+    // Also construct mapping from a unique point to a point_index. This defines
+    // an ordering on the points.
+    let mut point_index_map = BTreeMap::new();
+
+    // Iterate over all of the queries, computing the ordering of the points
+    // while also creating new commitment data.
+    for query in queries.clone() {
+        let num_points = point_index_map.len();
+        let point_idx = point_index_map
+            .entry(query.get_point())
+            .or_insert(num_points);
+
+        if let Some(pos) = commitment_map
+            .iter()
+            .position(|comm| comm.commitment == query.get_commitment())
+        {
+            commitment_map[pos].point_indices.push(*point_idx);
+        } else {
+            let mut tmp = CommitmentData::new(query.get_commitment());
+            tmp.point_indices.push(*point_idx);
+            commitment_map.push(tmp);
+        }
+    }
+
+    // Also construct inverse mapping from point_index to the point
+    let mut inverse_point_index_map = BTreeMap::new();
+    for (&point, &point_index) in point_index_map.iter() {
+        inverse_point_index_map.insert(point_index, point);
+    }
+
+    // Construct map of unique ordered point_idx_sets to their set_idx
+    let mut point_idx_sets = BTreeMap::new();
+    // Also construct mapping from commitment to point_idx_set
+    let mut commitment_set_map = Vec::new();
+
+    for commitment_data in commitment_map.iter() {
+        let mut point_index_set = BTreeSet::new();
+        // Note that point_index_set is ordered, unlike point_indices
+        for &point_index in commitment_data.point_indices.iter() {
+            point_index_set.insert(point_index);
+        }
+
+        // Push point_index_set to CommitmentData for the relevant commitment
+        commitment_set_map.push((commitment_data.commitment, point_index_set.clone()));
+
+        let num_sets = point_idx_sets.len();
+        point_idx_sets.entry(point_index_set).or_insert(num_sets);
+    }
+
+    // Initialise empty evals vec for each unique commitment
+    for commitment_data in commitment_map.iter_mut() {
+        let len = commitment_data.point_indices.len();
+        commitment_data.evals = vec![Q::Eval::default(); len];
+    }
+
+    // Populate set_index, evals and points for each commitment using point_idx_sets
+    for query in queries {
+        // The index of the point at which the commitment is queried
+        let point_index = point_index_map.get(&query.get_point()).unwrap();
+
+        // The point_index_set at which the commitment was queried
+        let mut point_index_set = BTreeSet::new();
+        for (commitment, point_idx_set) in commitment_set_map.iter() {
+            if query.get_commitment() == *commitment {
+                point_index_set = point_idx_set.clone();
+            }
+        }
+        assert!(!point_index_set.is_empty());
+
+        // The set_index of the point_index_set
+        let set_index = point_idx_sets.get(&point_index_set).unwrap();
+        for commitment_data in commitment_map.iter_mut() {
+            if query.get_commitment() == commitment_data.commitment {
+                commitment_data.set_index = *set_index;
+            }
+        }
+        let point_index_set: Vec<usize> = point_index_set.iter().cloned().collect();
+
+        // The offset of the point_index in the point_index_set
+        let point_index_in_set = point_index_set
+            .iter()
+            .position(|i| i == point_index)
+            .unwrap();
+
+        for commitment_data in commitment_map.iter_mut() {
+            if query.get_commitment() == commitment_data.commitment {
+                // Insert the eval using the ordering of the point_index_set
+                commitment_data.evals[point_index_in_set] = query.get_eval();
+            }
+        }
+    }
+
+    // Get actual points in each point set
+    let mut point_sets: Vec<Vec<F>> = vec![Vec::new(); point_idx_sets.len()];
+    for (point_idx_set, &set_idx) in point_idx_sets.iter() {
+        for &point_idx in point_idx_set.iter() {
+            let point = inverse_point_index_map.get(&point_idx).unwrap();
+            point_sets[set_idx].push(*point);
+        }
+    }
+
+    (commitment_map, point_sets)
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/ipa/multiopen/prover.rs.html b/docs/src/halo2_proofs/poly/ipa/multiopen/prover.rs.html new file mode 100644 index 0000000000..8de3187284 --- /dev/null +++ b/docs/src/halo2_proofs/poly/ipa/multiopen/prover.rs.html @@ -0,0 +1,250 @@ +prover.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+
use super::{
+    construct_intermediate_sets, ChallengeX1, ChallengeX2, ChallengeX3, ChallengeX4, Query,
+};
+use crate::arithmetic::{eval_polynomial, kate_division, CurveAffine, FieldExt};
+use crate::poly::commitment::ParamsProver;
+use crate::poly::commitment::{Blind, Params, Prover};
+use crate::poly::ipa::commitment::{self, IPACommitmentScheme, ParamsIPA};
+use crate::poly::query::ProverQuery;
+use crate::poly::{Coeff, Polynomial};
+use crate::transcript::{EncodedChallenge, TranscriptWrite};
+
+use ff::Field;
+use group::Curve;
+use rand_core::RngCore;
+use std::io;
+use std::marker::PhantomData;
+
+/// IPA multi-open prover
+#[derive(Debug)]
+pub struct ProverIPA<'params, C: CurveAffine> {
+    pub(crate) params: &'params ParamsIPA<C>,
+}
+
+impl<'params, C: CurveAffine> Prover<'params, IPACommitmentScheme<C>> for ProverIPA<'params, C> {
+    const QUERY_INSTANCE: bool = true;
+
+    fn new(params: &'params ParamsIPA<C>) -> Self {
+        Self { params }
+    }
+
+    /// Create a multi-opening proof
+    fn create_proof<'com, Z: EncodedChallenge<C>, T: TranscriptWrite<C, Z>, R, I>(
+        &self,
+        mut rng: R,
+        transcript: &mut T,
+        queries: I,
+    ) -> io::Result<()>
+    where
+        I: IntoIterator<Item = ProverQuery<'com, C>> + Clone,
+        R: RngCore,
+    {
+        let x_1: ChallengeX1<_> = transcript.squeeze_challenge_scalar();
+        let x_2: ChallengeX2<_> = transcript.squeeze_challenge_scalar();
+
+        let (poly_map, point_sets) = construct_intermediate_sets(queries);
+
+        // Collapse openings at same point sets together into single openings using
+        // x_1 challenge.
+        let mut q_polys: Vec<Option<Polynomial<C::Scalar, Coeff>>> = vec![None; point_sets.len()];
+        let mut q_blinds = vec![Blind(C::Scalar::zero()); point_sets.len()];
+
+        {
+            let mut accumulate = |set_idx: usize,
+                                  new_poly: &Polynomial<C::Scalar, Coeff>,
+                                  blind: Blind<C::Scalar>| {
+                if let Some(poly) = &q_polys[set_idx] {
+                    q_polys[set_idx] = Some(poly.clone() * *x_1 + new_poly);
+                } else {
+                    q_polys[set_idx] = Some(new_poly.clone());
+                }
+                q_blinds[set_idx] *= *x_1;
+                q_blinds[set_idx] += blind;
+            };
+
+            for commitment_data in poly_map.into_iter() {
+                accumulate(
+                    commitment_data.set_index,        // set_idx,
+                    commitment_data.commitment.poly,  // poly,
+                    commitment_data.commitment.blind, // blind,
+                );
+            }
+        }
+
+        let q_prime_poly = point_sets
+            .iter()
+            .zip(q_polys.iter())
+            .fold(None, |q_prime_poly, (points, poly)| {
+                let mut poly = points
+                    .iter()
+                    .fold(poly.clone().unwrap().values, |poly, point| {
+                        kate_division(&poly, *point)
+                    });
+                poly.resize(self.params.n as usize, C::Scalar::zero());
+                let poly = Polynomial {
+                    values: poly,
+                    _marker: PhantomData,
+                };
+
+                if q_prime_poly.is_none() {
+                    Some(poly)
+                } else {
+                    q_prime_poly.map(|q_prime_poly| q_prime_poly * *x_2 + &poly)
+                }
+            })
+            .unwrap();
+
+        let q_prime_blind = Blind(C::Scalar::random(&mut rng));
+        let q_prime_commitment = self.params.commit(&q_prime_poly, q_prime_blind).to_affine();
+
+        transcript.write_point(q_prime_commitment)?;
+
+        let x_3: ChallengeX3<_> = transcript.squeeze_challenge_scalar();
+
+        // Prover sends u_i for all i, which correspond to the evaluation
+        // of each Q polynomial commitment at x_3.
+        for q_i_poly in &q_polys {
+            transcript.write_scalar(eval_polynomial(q_i_poly.as_ref().unwrap(), *x_3))?;
+        }
+
+        let x_4: ChallengeX4<_> = transcript.squeeze_challenge_scalar();
+
+        let (p_poly, p_poly_blind) = q_polys.into_iter().zip(q_blinds.into_iter()).fold(
+            (q_prime_poly, q_prime_blind),
+            |(q_prime_poly, q_prime_blind), (poly, blind)| {
+                (
+                    q_prime_poly * *x_4 + &poly.unwrap(),
+                    Blind((q_prime_blind.0 * &(*x_4)) + &blind.0),
+                )
+            },
+        );
+
+        commitment::create_proof(self.params, rng, transcript, &p_poly, p_poly_blind, *x_3)
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/ipa/multiopen/verifier.rs.html b/docs/src/halo2_proofs/poly/ipa/multiopen/verifier.rs.html new file mode 100644 index 0000000000..835804cbe3 --- /dev/null +++ b/docs/src/halo2_proofs/poly/ipa/multiopen/verifier.rs.html @@ -0,0 +1,298 @@ +verifier.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+
use std::fmt::Debug;
+use std::io::Read;
+use std::marker::PhantomData;
+
+use ff::Field;
+use rand_core::RngCore;
+
+use super::{
+    construct_intermediate_sets, ChallengeX1, ChallengeX2, ChallengeX3, ChallengeX4, Query,
+};
+use crate::arithmetic::{eval_polynomial, lagrange_interpolate, CurveAffine, FieldExt};
+use crate::poly::commitment::{Params, Verifier, MSM};
+use crate::poly::ipa::commitment::{IPACommitmentScheme, ParamsIPA, ParamsVerifierIPA};
+use crate::poly::ipa::msm::MSMIPA;
+use crate::poly::ipa::strategy::GuardIPA;
+use crate::poly::query::{CommitmentReference, VerifierQuery};
+use crate::poly::strategy::VerificationStrategy;
+use crate::poly::Error;
+use crate::transcript::{EncodedChallenge, TranscriptRead};
+
+/// IPA multi-open verifier
+#[derive(Debug)]
+pub struct VerifierIPA<'params, C: CurveAffine> {
+    params: &'params ParamsIPA<C>,
+}
+
+impl<'params, C: CurveAffine> Verifier<'params, IPACommitmentScheme<C>>
+    for VerifierIPA<'params, C>
+{
+    type Guard = GuardIPA<'params, C>;
+    type MSMAccumulator = MSMIPA<'params, C>;
+
+    const QUERY_INSTANCE: bool = true;
+
+    fn new(params: &'params ParamsVerifierIPA<C>) -> Self {
+        Self { params }
+    }
+
+    fn verify_proof<'com, E: EncodedChallenge<C>, T: TranscriptRead<C, E>, I>(
+        &self,
+        transcript: &mut T,
+        queries: I,
+        mut msm: MSMIPA<'params, C>,
+    ) -> Result<Self::Guard, Error>
+    where
+        'params: 'com,
+        I: IntoIterator<Item = VerifierQuery<'com, C, MSMIPA<'params, C>>> + Clone,
+    {
+        // Sample x_1 for compressing openings at the same point sets together
+        let x_1: ChallengeX1<_> = transcript.squeeze_challenge_scalar();
+
+        // Sample a challenge x_2 for keeping the multi-point quotient
+        // polynomial terms linearly independent.
+        let x_2: ChallengeX2<_> = transcript.squeeze_challenge_scalar();
+
+        let (commitment_map, point_sets) = construct_intermediate_sets(queries);
+
+        // Compress the commitments and expected evaluations at x together.
+        // using the challenge x_1
+        let mut q_commitments: Vec<_> = vec![self.params.empty_msm(); point_sets.len()];
+
+        // A vec of vecs of evals. The outer vec corresponds to the point set,
+        // while the inner vec corresponds to the points in a particular set.
+        let mut q_eval_sets = Vec::with_capacity(point_sets.len());
+        for point_set in point_sets.iter() {
+            q_eval_sets.push(vec![C::Scalar::zero(); point_set.len()]);
+        }
+        {
+            let mut accumulate = |set_idx: usize,
+                                  new_commitment: CommitmentReference<C, MSMIPA<'params, C>>,
+                                  evals: Vec<C::Scalar>| {
+                q_commitments[set_idx].scale(*x_1);
+                match new_commitment {
+                    CommitmentReference::Commitment(c) => {
+                        q_commitments[set_idx].append_term(C::Scalar::one(), (*c).into());
+                    }
+                    CommitmentReference::MSM(msm) => {
+                        q_commitments[set_idx].add_msm(msm);
+                    }
+                }
+                for (eval, set_eval) in evals.iter().zip(q_eval_sets[set_idx].iter_mut()) {
+                    *set_eval *= &(*x_1);
+                    *set_eval += eval;
+                }
+            };
+
+            // Each commitment corresponds to evaluations at a set of points.
+            // For each set, we collapse each commitment's evals pointwise.
+            for commitment_data in commitment_map.into_iter() {
+                accumulate(
+                    commitment_data.set_index,  // set_idx,
+                    commitment_data.commitment, // commitment,
+                    commitment_data.evals,      // evals
+                );
+            }
+        }
+
+        // Obtain the commitment to the multi-point quotient polynomial f(X).
+        let q_prime_commitment = transcript.read_point().map_err(|_| Error::SamplingError)?;
+
+        // Sample a challenge x_3 for checking that f(X) was committed to
+        // correctly.
+        let x_3: ChallengeX3<_> = transcript.squeeze_challenge_scalar();
+
+        // u is a vector containing the evaluations of the Q polynomial
+        // commitments at x_3
+        let mut u = Vec::with_capacity(q_eval_sets.len());
+        for _ in 0..q_eval_sets.len() {
+            u.push(transcript.read_scalar().map_err(|_| Error::SamplingError)?);
+        }
+
+        // We can compute the expected msm_eval at x_3 using the u provided
+        // by the prover and from x_2
+        let msm_eval = point_sets
+            .iter()
+            .zip(q_eval_sets.iter())
+            .zip(u.iter())
+            .fold(
+                C::Scalar::zero(),
+                |msm_eval, ((points, evals), proof_eval)| {
+                    let r_poly = lagrange_interpolate(points, evals);
+                    let r_eval = eval_polynomial(&r_poly, *x_3);
+                    let eval = points.iter().fold(*proof_eval - &r_eval, |eval, point| {
+                        eval * &(*x_3 - point).invert().unwrap()
+                    });
+                    msm_eval * &(*x_2) + &eval
+                },
+            );
+
+        // Sample a challenge x_4 that we will use to collapse the openings of
+        // the various remaining polynomials at x_3 together.
+        let x_4: ChallengeX4<_> = transcript.squeeze_challenge_scalar();
+
+        // Compute the final commitment that has to be opened
+        msm.append_term(C::Scalar::one(), q_prime_commitment.into());
+        let (msm, v) = q_commitments.into_iter().zip(u.iter()).fold(
+            (msm, msm_eval),
+            |(mut msm, msm_eval), (q_commitment, q_eval)| {
+                msm.scale(*x_4);
+                msm.add_msm(&q_commitment);
+                (msm, msm_eval * &(*x_4) + q_eval)
+            },
+        );
+
+        // Verify the opening proof
+        super::commitment::verify_proof(self.params, msm, transcript, *x_3, v)
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/ipa/strategy.rs.html b/docs/src/halo2_proofs/poly/ipa/strategy.rs.html new file mode 100644 index 0000000000..fde574fd35 --- /dev/null +++ b/docs/src/halo2_proofs/poly/ipa/strategy.rs.html @@ -0,0 +1,354 @@ +strategy.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+
use std::marker::PhantomData;
+
+use super::commitment::{IPACommitmentScheme, ParamsIPA, ParamsVerifierIPA};
+use super::msm::MSMIPA;
+use super::multiopen::VerifierIPA;
+use crate::poly::commitment::CommitmentScheme;
+use crate::transcript::TranscriptRead;
+use crate::{
+    arithmetic::best_multiexp,
+    plonk::Error,
+    poly::{
+        commitment::MSM,
+        strategy::{Guard, VerificationStrategy},
+    },
+    transcript::EncodedChallenge,
+};
+use ff::Field;
+use group::Curve;
+use halo2curves::CurveAffine;
+use rand_core::{OsRng, RngCore};
+
+/// Wrapper for verification accumulator
+#[derive(Debug, Clone)]
+pub struct GuardIPA<'params, C: CurveAffine> {
+    pub(crate) msm: MSMIPA<'params, C>,
+    pub(crate) neg_c: C::Scalar,
+    pub(crate) u: Vec<C::Scalar>,
+    pub(crate) u_packed: Vec<C::Scalar>,
+}
+
+/// An accumulator instance consisting of an evaluation claim and a proof.
+#[derive(Debug, Clone)]
+pub struct Accumulator<C: CurveAffine> {
+    /// The claimed output of the linear-time polycommit opening protocol
+    pub g: C,
+
+    /// A vector of challenges u_0, ..., u_{k - 1} sampled by the verifier, to
+    /// be used in computing G'_0.
+    pub u_packed: Vec<C::Scalar>,
+}
+
+/// Define accumulator type as `MSMIPA`
+impl<'params, C: CurveAffine> Guard<IPACommitmentScheme<C>> for GuardIPA<'params, C> {
+    type MSMAccumulator = MSMIPA<'params, C>;
+}
+
+/// IPA specific operations
+impl<'params, C: CurveAffine> GuardIPA<'params, C> {
+    /// Lets caller supply the challenges and obtain an MSM with updated
+    /// scalars and points.
+    pub fn use_challenges(mut self) -> MSMIPA<'params, C> {
+        let s = compute_s(&self.u, self.neg_c);
+        self.msm.add_to_g_scalars(&s);
+
+        self.msm
+    }
+
+    /// Lets caller supply the purported G point and simply appends
+    /// [-c] G to return an updated MSM.
+    pub fn use_g(mut self, g: C) -> (MSMIPA<'params, C>, Accumulator<C>) {
+        self.msm.append_term(self.neg_c, g.into());
+
+        let accumulator = Accumulator {
+            g,
+            u_packed: self.u_packed,
+        };
+
+        (self.msm, accumulator)
+    }
+
+    /// Computes G = ⟨s, params.g⟩
+    pub fn compute_g(&self) -> C {
+        let s = compute_s(&self.u, C::Scalar::one());
+
+        best_multiexp(&s, &self.msm.params.g).to_affine()
+    }
+}
+
+/// A verifier that checks multiple proofs in a batch.
+#[derive(Debug)]
+pub struct AccumulatorStrategy<'params, C: CurveAffine> {
+    msm: MSMIPA<'params, C>,
+}
+
+impl<'params, C: CurveAffine>
+    VerificationStrategy<'params, IPACommitmentScheme<C>, VerifierIPA<'params, C>>
+    for AccumulatorStrategy<'params, C>
+{
+    type Output = Self;
+
+    fn new(params: &'params ParamsIPA<C>) -> Self {
+        AccumulatorStrategy {
+            msm: MSMIPA::new(params),
+        }
+    }
+
+    fn process(
+        mut self,
+        f: impl FnOnce(MSMIPA<'params, C>) -> Result<GuardIPA<'params, C>, Error>,
+    ) -> Result<Self::Output, Error> {
+        self.msm.scale(C::Scalar::random(OsRng));
+        let guard = f(self.msm)?;
+
+        Ok(Self {
+            msm: guard.use_challenges(),
+        })
+    }
+
+    /// Finalizes the batch and checks its validity.
+    ///
+    /// Returns `false` if *some* proof was invalid. If the caller needs to identify
+    /// specific failing proofs, it must re-process the proofs separately.
+    #[must_use]
+    fn finalize(self) -> bool {
+        self.msm.check()
+    }
+}
+
+/// A verifier that checks single proof
+#[derive(Debug)]
+pub struct SingleStrategy<'params, C: CurveAffine> {
+    msm: MSMIPA<'params, C>,
+}
+
+impl<'params, C: CurveAffine>
+    VerificationStrategy<'params, IPACommitmentScheme<C>, VerifierIPA<'params, C>>
+    for SingleStrategy<'params, C>
+{
+    type Output = ();
+
+    fn new(params: &'params ParamsIPA<C>) -> Self {
+        SingleStrategy {
+            msm: MSMIPA::new(params),
+        }
+    }
+
+    fn process(
+        self,
+        f: impl FnOnce(MSMIPA<'params, C>) -> Result<GuardIPA<'params, C>, Error>,
+    ) -> Result<Self::Output, Error> {
+        let guard = f(self.msm)?;
+        let msm = guard.use_challenges();
+        if msm.check() {
+            Ok(())
+        } else {
+            Err(Error::ConstraintSystemFailure)
+        }
+    }
+
+    /// Finalizes the batch and checks its validity.
+    ///
+    /// Returns `false` if *some* proof was invalid. If the caller needs to identify
+    /// specific failing proofs, it must re-process the proofs separately.
+    #[must_use]
+    fn finalize(self) -> bool {
+        unreachable!()
+    }
+}
+
+/// Computes the coefficients of $g(X) = \prod\limits_{i=0}^{k-1} (1 + u_{k - 1 - i} X^{2^i})$.
+fn compute_s<F: Field>(u: &[F], init: F) -> Vec<F> {
+    assert!(!u.is_empty());
+    let mut v = vec![F::zero(); 1 << u.len()];
+    v[0] = init;
+
+    for (len, u_j) in u.iter().rev().enumerate().map(|(i, u_j)| (1 << i, u_j)) {
+        let (left, right) = v.split_at_mut(len);
+        let right = &mut right[0..len];
+        right.copy_from_slice(left);
+        for v in right {
+            *v *= u_j;
+        }
+    }
+
+    v
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/kzg/commitment.rs.html b/docs/src/halo2_proofs/poly/kzg/commitment.rs.html new file mode 100644 index 0000000000..f850adf4ab --- /dev/null +++ b/docs/src/halo2_proofs/poly/kzg/commitment.rs.html @@ -0,0 +1,798 @@ +commitment.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+
use crate::arithmetic::{
+    best_fft, best_multiexp, g_to_lagrange, parallelize, CurveAffine, CurveExt, FieldExt, Group,
+};
+use crate::helpers::SerdeCurveAffine;
+use crate::poly::commitment::{Blind, CommitmentScheme, Params, ParamsProver, ParamsVerifier, MSM};
+use crate::poly::{Coeff, LagrangeCoeff, Polynomial};
+use crate::SerdeFormat;
+
+use ff::{Field, PrimeField};
+use group::{prime::PrimeCurveAffine, Curve, Group as _};
+use halo2curves::pairing::Engine;
+use rand_core::{OsRng, RngCore};
+use std::fmt::Debug;
+use std::marker::PhantomData;
+use std::ops::{Add, AddAssign, Mul, MulAssign};
+
+use std::io;
+
+use super::msm::MSMKZG;
+
+/// These are the public parameters for the polynomial commitment scheme.
+#[derive(Debug, Clone)]
+pub struct ParamsKZG<E: Engine> {
+    pub(crate) k: u32,
+    pub(crate) n: u64,
+    pub(crate) g: Vec<E::G1Affine>,
+    pub(crate) g_lagrange: Vec<E::G1Affine>,
+    pub(crate) g2: E::G2Affine,
+    pub(crate) s_g2: E::G2Affine,
+}
+
+/// Umbrella commitment scheme construction for all KZG variants
+#[derive(Debug)]
+pub struct KZGCommitmentScheme<E: Engine> {
+    _marker: PhantomData<E>,
+}
+
+impl<E: Engine + Debug> CommitmentScheme for KZGCommitmentScheme<E>
+where
+    E::G1Affine: SerdeCurveAffine,
+    E::G2Affine: SerdeCurveAffine,
+{
+    type Scalar = E::Scalar;
+    type Curve = E::G1Affine;
+
+    type ParamsProver = ParamsKZG<E>;
+    type ParamsVerifier = ParamsVerifierKZG<E>;
+
+    fn new_params(k: u32) -> Self::ParamsProver {
+        ParamsKZG::new(k)
+    }
+
+    fn read_params<R: io::Read>(reader: &mut R) -> io::Result<Self::ParamsProver> {
+        ParamsKZG::read(reader)
+    }
+}
+
+impl<E: Engine + Debug> ParamsKZG<E> {
+    /// Initializes parameters for the curve, draws toxic secret from given rng.
+    /// MUST NOT be used in production.
+    pub fn setup<R: RngCore>(k: u32, rng: R) -> Self {
+        // Largest root of unity exponent of the Engine is `2^E::Scalar::S`, so we can
+        // only support FFTs of polynomials below degree `2^E::Scalar::S`.
+        assert!(k <= E::Scalar::S);
+        let n: u64 = 1 << k;
+
+        // Calculate g = [G1, [s] G1, [s^2] G1, ..., [s^(n-1)] G1] in parallel.
+        let g1 = E::G1Affine::generator();
+        let s = <E::Scalar>::random(rng);
+
+        let mut g_projective = vec![E::G1::group_zero(); n as usize];
+        parallelize(&mut g_projective, |g, start| {
+            let mut current_g: E::G1 = g1.into();
+            current_g *= s.pow_vartime(&[start as u64]);
+            for g in g.iter_mut() {
+                *g = current_g;
+                current_g *= s;
+            }
+        });
+
+        let g = {
+            let mut g = vec![E::G1Affine::identity(); n as usize];
+            parallelize(&mut g, |g, starts| {
+                E::G1::batch_normalize(&g_projective[starts..(starts + g.len())], g);
+            });
+            g
+        };
+
+        let mut g_lagrange_projective = vec![E::G1::group_zero(); n as usize];
+        let mut root = E::Scalar::ROOT_OF_UNITY_INV.invert().unwrap();
+        for _ in k..E::Scalar::S {
+            root = root.square();
+        }
+        let n_inv = Option::<E::Scalar>::from(E::Scalar::from(n).invert())
+            .expect("inversion should be ok for n = 1<<k");
+        let multiplier = (s.pow_vartime(&[n as u64]) - E::Scalar::one()) * n_inv;
+        parallelize(&mut g_lagrange_projective, |g, start| {
+            for (idx, g) in g.iter_mut().enumerate() {
+                let offset = start + idx;
+                let root_pow = root.pow_vartime(&[offset as u64]);
+                let scalar = multiplier * root_pow * (s - root_pow).invert().unwrap();
+                *g = g1 * scalar;
+            }
+        });
+
+        let g_lagrange = {
+            let mut g_lagrange = vec![E::G1Affine::identity(); n as usize];
+            parallelize(&mut g_lagrange, |g_lagrange, starts| {
+                E::G1::batch_normalize(
+                    &g_lagrange_projective[starts..(starts + g_lagrange.len())],
+                    g_lagrange,
+                );
+            });
+            drop(g_lagrange_projective);
+            g_lagrange
+        };
+
+        let g2 = <E::G2Affine as PrimeCurveAffine>::generator();
+        let s_g2 = (g2 * s).into();
+
+        Self {
+            k,
+            n,
+            g,
+            g_lagrange,
+            g2,
+            s_g2,
+        }
+    }
+
+    /// Returns gernerator on G2
+    pub fn g2(&self) -> E::G2Affine {
+        self.g2
+    }
+
+    /// Returns first power of secret on G2
+    pub fn s_g2(&self) -> E::G2Affine {
+        self.s_g2
+    }
+
+    /// Writes parameters to buffer
+    pub fn write_custom<W: io::Write>(&self, writer: &mut W, format: SerdeFormat)
+    where
+        E::G1Affine: SerdeCurveAffine,
+        E::G2Affine: SerdeCurveAffine,
+    {
+        writer.write_all(&self.k.to_le_bytes()).unwrap();
+        for el in self.g.iter() {
+            el.write(writer, format);
+        }
+        for el in self.g_lagrange.iter() {
+            el.write(writer, format);
+        }
+        self.g2.write(writer, format);
+        self.s_g2.write(writer, format);
+    }
+
+    /// Reads params from a buffer.
+    pub fn read_custom<R: io::Read>(reader: &mut R, format: SerdeFormat) -> Self
+    where
+        E::G1Affine: SerdeCurveAffine,
+        E::G2Affine: SerdeCurveAffine,
+    {
+        let mut k = [0u8; 4];
+        reader.read_exact(&mut k[..]).unwrap();
+        let k = u32::from_le_bytes(k);
+        let n = 1 << k;
+
+        let (g, g_lagrange) = match format {
+            SerdeFormat::Processed => {
+                use group::GroupEncoding;
+                let load_points_from_file_parallelly =
+                    |reader: &mut R| -> Vec<Option<E::G1Affine>> {
+                        let mut points_compressed =
+                            vec![<<E as Engine>::G1Affine as GroupEncoding>::Repr::default(); n];
+                        for points_compressed in points_compressed.iter_mut() {
+                            reader.read_exact((*points_compressed).as_mut()).unwrap();
+                        }
+
+                        let mut points = vec![Option::<E::G1Affine>::None; n];
+                        parallelize(&mut points, |points, chunks| {
+                            for (i, point) in points.iter_mut().enumerate() {
+                                *point = Option::from(E::G1Affine::from_bytes(
+                                    &points_compressed[chunks + i],
+                                ));
+                            }
+                        });
+                        points
+                    };
+
+                let g = load_points_from_file_parallelly(reader);
+                let g: Vec<<E as Engine>::G1Affine> = g
+                    .iter()
+                    .map(|point| point.unwrap_or_else(|| panic!("invalid point encoding")))
+                    .collect();
+                let g_lagrange = load_points_from_file_parallelly(reader);
+                let g_lagrange: Vec<<E as Engine>::G1Affine> = g_lagrange
+                    .iter()
+                    .map(|point| point.unwrap_or_else(|| panic!("invalid point encoding")))
+                    .collect();
+                (g, g_lagrange)
+            }
+            SerdeFormat::RawBytes => {
+                let g = (0..n)
+                    .map(|_| <E::G1Affine as SerdeCurveAffine>::read(reader, format))
+                    .collect();
+                let g_lagrange = (0..n)
+                    .map(|_| <E::G1Affine as SerdeCurveAffine>::read(reader, format))
+                    .collect();
+                (g, g_lagrange)
+            }
+            SerdeFormat::RawBytesUnchecked => {
+                // avoid try branching for performance
+                let g = (0..n)
+                    .map(|_| <E::G1Affine as SerdeCurveAffine>::read(reader, format))
+                    .collect::<Vec<_>>();
+                let g_lagrange = (0..n)
+                    .map(|_| <E::G1Affine as SerdeCurveAffine>::read(reader, format))
+                    .collect::<Vec<_>>();
+                (g, g_lagrange)
+            }
+        };
+
+        let g2 = E::G2Affine::read(reader, format);
+        let s_g2 = E::G2Affine::read(reader, format);
+
+        Self {
+            k,
+            n: n as u64,
+            g,
+            g_lagrange,
+            g2,
+            s_g2,
+        }
+    }
+}
+
+// TODO: see the issue at https://github.com/appliedzkp/halo2/issues/45
+// So we probably need much smaller verifier key. However for new bases in g1 should be in verifier keys.
+/// KZG multi-open verification parameters
+pub type ParamsVerifierKZG<C> = ParamsKZG<C>;
+
+impl<'params, E: Engine + Debug> Params<'params, E::G1Affine> for ParamsKZG<E>
+where
+    E::G1Affine: SerdeCurveAffine,
+    E::G2Affine: SerdeCurveAffine,
+{
+    type MSM = MSMKZG<E>;
+
+    fn k(&self) -> u32 {
+        self.k
+    }
+
+    fn n(&self) -> u64 {
+        self.n
+    }
+
+    fn downsize(&mut self, k: u32) {
+        assert!(k <= self.k);
+
+        self.k = k;
+        self.n = 1 << k;
+
+        self.g.truncate(self.n as usize);
+        self.g_lagrange = g_to_lagrange(self.g.iter().map(|g| g.to_curve()).collect(), k);
+    }
+
+    fn empty_msm(&'params self) -> MSMKZG<E> {
+        MSMKZG::new()
+    }
+
+    fn commit_lagrange(
+        &self,
+        poly: &Polynomial<E::Scalar, LagrangeCoeff>,
+        _: Blind<E::Scalar>,
+    ) -> E::G1 {
+        let size = poly.len();
+        assert!(self.n() >= size as u64);
+        best_multiexp(poly, &self.g_lagrange[0..size])
+    }
+
+    /// Writes params to a buffer.
+    fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()> {
+        Ok(self.write_custom(writer, SerdeFormat::RawBytesUnchecked))
+    }
+
+    /// Reads params from a buffer.
+    fn read<R: io::Read>(reader: &mut R) -> io::Result<Self> {
+        Ok(Self::read_custom(reader, SerdeFormat::RawBytesUnchecked))
+    }
+}
+
+impl<'params, E: Engine + Debug> ParamsVerifier<'params, E::G1Affine> for ParamsKZG<E>
+where
+    E::G1Affine: SerdeCurveAffine,
+    E::G2Affine: SerdeCurveAffine,
+{
+}
+
+impl<'params, E: Engine + Debug> ParamsProver<'params, E::G1Affine> for ParamsKZG<E>
+where
+    E::G1Affine: SerdeCurveAffine,
+    E::G2Affine: SerdeCurveAffine,
+{
+    type ParamsVerifier = ParamsVerifierKZG<E>;
+
+    fn verifier_params(&'params self) -> &'params Self::ParamsVerifier {
+        self
+    }
+
+    fn new(k: u32) -> Self {
+        Self::setup(k, OsRng)
+    }
+
+    fn commit(&self, poly: &Polynomial<E::Scalar, Coeff>, _: Blind<E::Scalar>) -> E::G1 {
+        let size = poly.len();
+        assert!(self.n() >= size as u64);
+        best_multiexp(poly, &self.g[0..size])
+    }
+
+    fn get_g(&self) -> &[E::G1Affine] {
+        &self.g
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use crate::arithmetic::{
+        best_fft, best_multiexp, parallelize, CurveAffine, CurveExt, FieldExt, Group,
+    };
+    use crate::poly::commitment::ParamsProver;
+    use crate::poly::commitment::{Blind, CommitmentScheme, Params, MSM};
+    use crate::poly::kzg::commitment::{ParamsKZG, ParamsVerifierKZG};
+    use crate::poly::kzg::msm::MSMKZG;
+    use crate::poly::kzg::multiopen::ProverSHPLONK;
+    use crate::poly::{Coeff, LagrangeCoeff, Polynomial};
+
+    use ff::{Field, PrimeField};
+    use group::{prime::PrimeCurveAffine, Curve, Group as _};
+    use halo2curves::bn256::G1Affine;
+    use std::marker::PhantomData;
+    use std::ops::{Add, AddAssign, Mul, MulAssign};
+
+    use std::io;
+
+    #[test]
+    fn test_commit_lagrange() {
+        const K: u32 = 6;
+
+        use rand_core::OsRng;
+
+        use crate::poly::EvaluationDomain;
+        use halo2curves::bn256::{Bn256, Fr};
+
+        let params = ParamsKZG::<Bn256>::new(K);
+        let domain = EvaluationDomain::new(1, K);
+
+        let mut a = domain.empty_lagrange();
+
+        for (i, a) in a.iter_mut().enumerate() {
+            *a = Fr::from(i as u64);
+        }
+
+        let b = domain.lagrange_to_coeff(a.clone());
+
+        let alpha = Blind(Fr::random(OsRng));
+
+        assert_eq!(params.commit(&b, alpha), params.commit_lagrange(&a, alpha));
+    }
+
+    #[test]
+    fn test_parameter_serialisation_roundtrip() {
+        const K: u32 = 4;
+
+        use ff::Field;
+        use rand_core::OsRng;
+
+        use super::super::commitment::{Blind, Params};
+        use crate::arithmetic::{eval_polynomial, FieldExt};
+        use crate::halo2curves::bn256::{Bn256, Fr};
+        use crate::poly::EvaluationDomain;
+
+        let params0 = ParamsKZG::<Bn256>::new(K);
+        let mut data = vec![];
+        <ParamsKZG<_> as Params<_>>::write(&params0, &mut data).unwrap();
+        let params1: ParamsKZG<Bn256> = Params::read::<_>(&mut &data[..]).unwrap();
+
+        assert_eq!(params0.k, params1.k);
+        assert_eq!(params0.n, params1.n);
+        assert_eq!(params0.g.len(), params1.g.len());
+        assert_eq!(params0.g_lagrange.len(), params1.g_lagrange.len());
+
+        assert_eq!(params0.g, params1.g);
+        assert_eq!(params0.g_lagrange, params1.g_lagrange);
+        assert_eq!(params0.g2, params1.g2);
+        assert_eq!(params0.s_g2, params1.s_g2);
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/kzg/mod.rs.html b/docs/src/halo2_proofs/poly/kzg/mod.rs.html new file mode 100644 index 0000000000..660b215dec --- /dev/null +++ b/docs/src/halo2_proofs/poly/kzg/mod.rs.html @@ -0,0 +1,18 @@ +mod.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+
/// KZG commitment scheme
+pub mod commitment;
+/// Multiscalar multiplication engines
+pub mod msm;
+/// KZG multi-open scheme
+pub mod multiopen;
+/// Strategies used with KZG scheme
+pub mod strategy;
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/kzg/msm.rs.html b/docs/src/halo2_proofs/poly/kzg/msm.rs.html new file mode 100644 index 0000000000..8827680d81 --- /dev/null +++ b/docs/src/halo2_proofs/poly/kzg/msm.rs.html @@ -0,0 +1,342 @@ +msm.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+
use std::fmt::Debug;
+
+use super::commitment::{KZGCommitmentScheme, ParamsKZG};
+use crate::{
+    arithmetic::{best_multiexp, parallelize, CurveAffine},
+    poly::commitment::MSM,
+};
+use group::{Curve, Group};
+use halo2curves::pairing::{Engine, MillerLoopResult, MultiMillerLoop};
+
+/// A multiscalar multiplication in the polynomial commitment scheme
+#[derive(Clone, Default, Debug)]
+pub struct MSMKZG<E: Engine> {
+    pub(crate) scalars: Vec<E::Scalar>,
+    pub(crate) bases: Vec<E::G1>,
+}
+
+impl<E: Engine> MSMKZG<E> {
+    /// Create an empty MSM instance
+    pub fn new() -> Self {
+        MSMKZG {
+            scalars: vec![],
+            bases: vec![],
+        }
+    }
+
+    /// Prepares all scalars in the MSM to linear combination
+    pub fn combine_with_base(&mut self, base: E::Scalar) {
+        use ff::Field;
+        let mut acc = E::Scalar::one();
+        if !self.scalars.is_empty() {
+            for scalar in self.scalars.iter_mut().rev() {
+                *scalar *= &acc;
+                acc *= base;
+            }
+        }
+    }
+}
+
+impl<E: Engine + Debug> MSM<E::G1Affine> for MSMKZG<E> {
+    fn append_term(&mut self, scalar: E::Scalar, point: E::G1) {
+        self.scalars.push(scalar);
+        self.bases.push(point);
+    }
+
+    fn add_msm(&mut self, other: &Self) {
+        self.scalars.extend(other.scalars().iter());
+        self.bases.extend(other.bases().iter());
+    }
+
+    fn scale(&mut self, factor: E::Scalar) {
+        if !self.scalars.is_empty() {
+            parallelize(&mut self.scalars, |scalars, _| {
+                for other_scalar in scalars {
+                    *other_scalar *= &factor;
+                }
+            })
+        }
+    }
+
+    fn check(&self) -> bool {
+        bool::from(self.eval().is_identity())
+    }
+
+    fn eval(&self) -> E::G1 {
+        use group::prime::PrimeCurveAffine;
+        let mut bases = vec![E::G1Affine::identity(); self.scalars.len()];
+        E::G1::batch_normalize(&self.bases, &mut bases);
+        best_multiexp(&self.scalars, &bases)
+    }
+
+    fn bases(&self) -> Vec<E::G1> {
+        self.bases.clone()
+    }
+
+    fn scalars(&self) -> Vec<E::Scalar> {
+        self.scalars.clone()
+    }
+}
+
+/// A projective point collector
+#[derive(Debug, Clone)]
+pub(crate) struct PreMSM<E: Engine> {
+    projectives_msms: Vec<MSMKZG<E>>,
+}
+
+impl<E: Engine + Debug> PreMSM<E> {
+    pub(crate) fn new() -> Self {
+        PreMSM {
+            projectives_msms: vec![],
+        }
+    }
+
+    pub(crate) fn normalize(self) -> MSMKZG<E> {
+        use group::prime::PrimeCurveAffine;
+
+        let (scalars, bases) = self
+            .projectives_msms
+            .into_iter()
+            .map(|msm| (msm.scalars, msm.bases))
+            .unzip::<_, _, Vec<_>, Vec<_>>();
+
+        MSMKZG {
+            scalars: scalars.into_iter().flatten().collect(),
+            bases: bases.into_iter().flatten().collect(),
+        }
+    }
+
+    pub(crate) fn add_msm(&mut self, other: MSMKZG<E>) {
+        self.projectives_msms.push(other);
+    }
+}
+
+impl<'params, E: MultiMillerLoop + Debug> From<&'params ParamsKZG<E>> for DualMSM<'params, E> {
+    fn from(params: &'params ParamsKZG<E>) -> Self {
+        DualMSM::new(params)
+    }
+}
+
+/// Two channel MSM accumulator
+#[derive(Debug, Clone)]
+pub struct DualMSM<'a, E: Engine> {
+    pub(crate) params: &'a ParamsKZG<E>,
+    pub(crate) left: MSMKZG<E>,
+    pub(crate) right: MSMKZG<E>,
+}
+
+impl<'a, E: MultiMillerLoop + Debug> DualMSM<'a, E> {
+    /// Create a new two channel MSM accumulator instance
+    pub fn new(params: &'a ParamsKZG<E>) -> Self {
+        Self {
+            params,
+            left: MSMKZG::new(),
+            right: MSMKZG::new(),
+        }
+    }
+
+    /// Scale all scalars in the MSM by some scaling factor
+    pub fn scale(&mut self, e: E::Scalar) {
+        self.left.scale(e);
+        self.right.scale(e);
+    }
+
+    /// Add another multiexp into this one
+    pub fn add_msm(&mut self, other: Self) {
+        self.left.add_msm(&other.left);
+        self.right.add_msm(&other.right);
+    }
+
+    /// Performs final pairing check with given verifier params and two channel linear combination
+    pub fn check(self) -> bool {
+        let s_g2_prepared = E::G2Prepared::from(self.params.s_g2);
+        let n_g2_prepared = E::G2Prepared::from(-self.params.g2);
+
+        let left = self.left.eval();
+        let right = self.right.eval();
+
+        let (term_1, term_2) = (
+            (&left.into(), &s_g2_prepared),
+            (&right.into(), &n_g2_prepared),
+        );
+        let terms = &[term_1, term_2];
+
+        bool::from(
+            E::multi_miller_loop(&terms[..])
+                .final_exponentiation()
+                .is_identity(),
+        )
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/kzg/multiopen.rs.html b/docs/src/halo2_proofs/poly/kzg/multiopen.rs.html new file mode 100644 index 0000000000..76a32a4cc5 --- /dev/null +++ b/docs/src/halo2_proofs/poly/kzg/multiopen.rs.html @@ -0,0 +1,12 @@ +multiopen.rs - source
1
+2
+3
+4
+5
+
mod gwc;
+mod shplonk;
+
+pub use gwc::*;
+pub use shplonk::*;
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/kzg/multiopen/gwc.rs.html b/docs/src/halo2_proofs/poly/kzg/multiopen/gwc.rs.html new file mode 100644 index 0000000000..6eaabda3ae --- /dev/null +++ b/docs/src/halo2_proofs/poly/kzg/multiopen/gwc.rs.html @@ -0,0 +1,124 @@ +gwc.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+
mod prover;
+mod verifier;
+
+pub use prover::ProverGWC;
+pub use verifier::VerifierGWC;
+
+use crate::{
+    arithmetic::{eval_polynomial, CurveAffine, FieldExt},
+    poly::{
+        commitment::{Params, ParamsVerifier},
+        query::Query,
+        Coeff, Polynomial,
+    },
+    transcript::ChallengeScalar,
+};
+
+use std::{
+    collections::{BTreeMap, BTreeSet},
+    marker::PhantomData,
+};
+
+#[derive(Clone, Copy, Debug)]
+struct U {}
+type ChallengeU<F> = ChallengeScalar<F, U>;
+
+#[derive(Clone, Copy, Debug)]
+struct V {}
+type ChallengeV<F> = ChallengeScalar<F, V>;
+
+struct CommitmentData<F: FieldExt, Q: Query<F>> {
+    queries: Vec<Q>,
+    point: F,
+    _marker: PhantomData<F>,
+}
+
+fn construct_intermediate_sets<F: FieldExt, I, Q: Query<F>>(queries: I) -> Vec<CommitmentData<F, Q>>
+where
+    I: IntoIterator<Item = Q> + Clone,
+{
+    let mut point_query_map: Vec<(F, Vec<Q>)> = Vec::new();
+    for query in queries {
+        if let Some(pos) = point_query_map
+            .iter()
+            .position(|(point, _)| *point == query.get_point())
+        {
+            let (_, queries) = &mut point_query_map[pos];
+            queries.push(query);
+        } else {
+            point_query_map.push((query.get_point(), vec![query]));
+        }
+    }
+
+    point_query_map
+        .into_iter()
+        .map(|(point, queries)| CommitmentData {
+            queries,
+            point,
+            _marker: PhantomData,
+        })
+        .collect()
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/kzg/multiopen/gwc/prover.rs.html b/docs/src/halo2_proofs/poly/kzg/multiopen/gwc/prover.rs.html new file mode 100644 index 0000000000..551ffced92 --- /dev/null +++ b/docs/src/halo2_proofs/poly/kzg/multiopen/gwc/prover.rs.html @@ -0,0 +1,186 @@ +prover.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+
use super::{construct_intermediate_sets, ChallengeV, Query};
+use crate::arithmetic::{eval_polynomial, kate_division, powers, CurveAffine, FieldExt};
+use crate::helpers::SerdeCurveAffine;
+use crate::poly::commitment::ParamsProver;
+use crate::poly::commitment::Prover;
+use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG};
+use crate::poly::query::ProverQuery;
+use crate::poly::Rotation;
+use crate::poly::{
+    commitment::{Blind, Params},
+    Coeff, Polynomial,
+};
+use crate::transcript::{EncodedChallenge, TranscriptWrite};
+
+use ff::Field;
+use group::Curve;
+use halo2curves::pairing::Engine;
+use rand_core::RngCore;
+use std::fmt::Debug;
+use std::io::{self, Write};
+use std::marker::PhantomData;
+
+/// Concrete KZG prover with GWC variant
+#[derive(Debug)]
+pub struct ProverGWC<'params, E: Engine> {
+    params: &'params ParamsKZG<E>,
+}
+
+/// Create a multi-opening proof
+impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme<E>> for ProverGWC<'params, E>
+where
+    E::G1Affine: SerdeCurveAffine,
+    E::G2Affine: SerdeCurveAffine,
+{
+    const QUERY_INSTANCE: bool = false;
+
+    fn new(params: &'params ParamsKZG<E>) -> Self {
+        Self { params }
+    }
+
+    /// Create a multi-opening proof
+    fn create_proof<
+        'com,
+        Ch: EncodedChallenge<E::G1Affine>,
+        T: TranscriptWrite<E::G1Affine, Ch>,
+        R,
+        I,
+    >(
+        &self,
+        _: R,
+        transcript: &mut T,
+        queries: I,
+    ) -> io::Result<()>
+    where
+        I: IntoIterator<Item = ProverQuery<'com, E::G1Affine>> + Clone,
+        R: RngCore,
+    {
+        let v: ChallengeV<_> = transcript.squeeze_challenge_scalar();
+        let commitment_data = construct_intermediate_sets(queries);
+
+        for commitment_at_a_point in commitment_data.iter() {
+            let z = commitment_at_a_point.point;
+            let (poly_batch, eval_batch) = commitment_at_a_point
+                .queries
+                .iter()
+                .zip(powers(*v))
+                .map(|(query, power_of_v)| {
+                    assert_eq!(query.get_point(), z);
+
+                    let poly = query.get_commitment().poly;
+                    let eval = query.get_eval();
+
+                    (poly.clone() * power_of_v, eval * power_of_v)
+                })
+                .reduce(|(poly_acc, eval_acc), (poly, eval)| (poly_acc + &poly, eval_acc + eval))
+                .unwrap();
+
+            let poly_batch = &poly_batch - eval_batch;
+            let witness_poly = Polynomial {
+                values: kate_division(&poly_batch.values, z),
+                _marker: PhantomData,
+            };
+            let w = self
+                .params
+                .commit(&witness_poly, Blind::default())
+                .to_affine();
+
+            transcript.write_point(w)?;
+        }
+        Ok(())
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/kzg/multiopen/gwc/verifier.rs.html b/docs/src/halo2_proofs/poly/kzg/multiopen/gwc/verifier.rs.html new file mode 100644 index 0000000000..5063058575 --- /dev/null +++ b/docs/src/halo2_proofs/poly/kzg/multiopen/gwc/verifier.rs.html @@ -0,0 +1,262 @@ +verifier.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+
use std::fmt::Debug;
+use std::io::Read;
+use std::marker::PhantomData;
+
+use super::{construct_intermediate_sets, ChallengeU, ChallengeV};
+use crate::arithmetic::{eval_polynomial, lagrange_interpolate, powers, CurveAffine, FieldExt};
+use crate::helpers::SerdeCurveAffine;
+use crate::poly::commitment::Verifier;
+use crate::poly::commitment::MSM;
+use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG};
+use crate::poly::kzg::msm::{DualMSM, MSMKZG};
+use crate::poly::kzg::strategy::{AccumulatorStrategy, GuardKZG, SingleStrategy};
+use crate::poly::query::Query;
+use crate::poly::query::{CommitmentReference, VerifierQuery};
+use crate::poly::strategy::VerificationStrategy;
+use crate::poly::{
+    commitment::{Params, ParamsVerifier},
+    Error,
+};
+use crate::transcript::{EncodedChallenge, TranscriptRead};
+
+use ff::Field;
+use group::Group;
+use halo2curves::pairing::{Engine, MillerLoopResult, MultiMillerLoop};
+use rand_core::OsRng;
+
+#[derive(Debug)]
+/// Concrete KZG verifier with GWC variant
+pub struct VerifierGWC<'params, E: Engine> {
+    params: &'params ParamsKZG<E>,
+}
+
+impl<'params, E> Verifier<'params, KZGCommitmentScheme<E>> for VerifierGWC<'params, E>
+where
+    E: MultiMillerLoop + Debug,
+    E::G1Affine: SerdeCurveAffine,
+    E::G2Affine: SerdeCurveAffine,
+{
+    type Guard = GuardKZG<'params, E>;
+    type MSMAccumulator = DualMSM<'params, E>;
+
+    const QUERY_INSTANCE: bool = false;
+
+    fn new(params: &'params ParamsKZG<E>) -> Self {
+        Self { params }
+    }
+
+    fn verify_proof<
+        'com,
+        Ch: EncodedChallenge<E::G1Affine>,
+        T: TranscriptRead<E::G1Affine, Ch>,
+        I,
+    >(
+        &self,
+        transcript: &mut T,
+        queries: I,
+        mut msm_accumulator: DualMSM<'params, E>,
+    ) -> Result<Self::Guard, Error>
+    where
+        I: IntoIterator<Item = VerifierQuery<'com, E::G1Affine, MSMKZG<E>>> + Clone,
+    {
+        let v: ChallengeV<_> = transcript.squeeze_challenge_scalar();
+
+        let commitment_data = construct_intermediate_sets(queries);
+
+        let w: Vec<E::G1Affine> = (0..commitment_data.len())
+            .map(|_| transcript.read_point().map_err(|_| Error::SamplingError))
+            .collect::<Result<Vec<E::G1Affine>, Error>>()?;
+
+        let u: ChallengeU<_> = transcript.squeeze_challenge_scalar();
+
+        let mut commitment_multi = MSMKZG::<E>::new();
+        let mut eval_multi = E::Scalar::zero();
+
+        let mut witness = MSMKZG::<E>::new();
+        let mut witness_with_aux = MSMKZG::<E>::new();
+
+        for ((commitment_at_a_point, wi), power_of_u) in
+            commitment_data.iter().zip(w.into_iter()).zip(powers(*u))
+        {
+            assert!(!commitment_at_a_point.queries.is_empty());
+            let z = commitment_at_a_point.point;
+
+            let (mut commitment_batch, eval_batch) = commitment_at_a_point
+                .queries
+                .iter()
+                .zip(powers(*v))
+                .map(|(query, power_of_v)| {
+                    assert_eq!(query.get_point(), z);
+
+                    let commitment = match query.get_commitment() {
+                        CommitmentReference::Commitment(c) => {
+                            let mut msm = MSMKZG::<E>::new();
+                            msm.append_term(power_of_v, (*c).into());
+                            msm
+                        }
+                        CommitmentReference::MSM(msm) => {
+                            let mut msm = msm.clone();
+                            msm.scale(power_of_v);
+                            msm
+                        }
+                    };
+                    let eval = power_of_v * query.get_eval();
+
+                    (commitment, eval)
+                })
+                .reduce(|(mut commitment_acc, eval_acc), (commitment, eval)| {
+                    commitment_acc.add_msm(&commitment);
+                    (commitment_acc, eval_acc + eval)
+                })
+                .unwrap();
+
+            commitment_batch.scale(power_of_u);
+            commitment_multi.add_msm(&commitment_batch);
+            eval_multi += power_of_u * eval_batch;
+
+            witness_with_aux.append_term(power_of_u * z, wi.into());
+            witness.append_term(power_of_u, wi.into());
+        }
+
+        msm_accumulator.left.add_msm(&witness);
+
+        msm_accumulator.right.add_msm(&witness_with_aux);
+        msm_accumulator.right.add_msm(&commitment_multi);
+        let g0: E::G1 = self.params.g[0].into();
+        msm_accumulator.right.append_term(eval_multi, -g0);
+
+        Ok(Self::Guard::new(msm_accumulator))
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/kzg/multiopen/shplonk.rs.html b/docs/src/halo2_proofs/poly/kzg/multiopen/shplonk.rs.html new file mode 100644 index 0000000000..c1966aabc1 --- /dev/null +++ b/docs/src/halo2_proofs/poly/kzg/multiopen/shplonk.rs.html @@ -0,0 +1,530 @@ +shplonk.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+
mod prover;
+mod verifier;
+
+pub use prover::ProverSHPLONK;
+use rayon::prelude::*;
+use rustc_hash::FxHashSet;
+pub use verifier::VerifierSHPLONK;
+
+use crate::{
+    arithmetic::{eval_polynomial, lagrange_interpolate, CurveAffine, FieldExt},
+    poly::{query::Query, Coeff, Polynomial},
+    transcript::ChallengeScalar,
+};
+use rayon::prelude::*;
+use std::{
+    collections::{btree_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet},
+    hash::Hash,
+    marker::PhantomData,
+    sync::Arc,
+};
+
+#[derive(Clone, Copy, Debug)]
+struct U {}
+type ChallengeU<F> = ChallengeScalar<F, U>;
+
+#[derive(Clone, Copy, Debug)]
+struct V {}
+type ChallengeV<F> = ChallengeScalar<F, V>;
+
+#[derive(Clone, Copy, Debug)]
+struct Y {}
+type ChallengeY<F> = ChallengeScalar<F, Y>;
+
+#[derive(Debug, Clone, PartialEq)]
+struct Commitment<F: FieldExt, T: PartialEq + Clone>((T, Vec<F>));
+
+impl<F: FieldExt, T: PartialEq + Clone> Commitment<F, T> {
+    fn get(&self) -> T {
+        self.0 .0.clone()
+    }
+
+    fn evals(&self) -> Vec<F> {
+        self.0 .1.clone()
+    }
+}
+
+#[derive(Debug, Clone, PartialEq)]
+struct RotationSet<F: FieldExt, T: PartialEq + Clone> {
+    commitments: Vec<Commitment<F, T>>,
+    points: Vec<F>,
+}
+
+#[derive(Debug, PartialEq)]
+struct IntermediateSets<F: FieldExt + Hash, Q: Query<F>> {
+    rotation_sets: Vec<RotationSet<F, Q::Commitment>>,
+    super_point_set: FxHashSet<F>,
+}
+
+fn construct_intermediate_sets<F: FieldExt + Hash, I, Q: Query<F, Eval = F>>(
+    queries: I,
+) -> IntermediateSets<F, Q>
+where
+    I: IntoIterator<Item = Q> + Clone,
+{
+    let queries = queries.into_iter().collect::<Vec<_>>();
+
+    // Find evaluation of a commitment at a rotation
+    let get_eval = |commitment: Q::Commitment, rotation: F| -> F {
+        queries
+            .iter()
+            .find(|query| query.get_commitment() == commitment && query.get_point() == rotation)
+            .unwrap()
+            .get_eval()
+    };
+
+    // All points that appear in queries
+    let mut super_point_set = FxHashSet::default();
+
+    // Collect rotation sets for each commitment
+    // Example elements in the vector:
+    // (C_0, {r_5}),
+    // (C_1, {r_1, r_2, r_3}),
+    // (C_2, {r_2, r_3, r_4}),
+    // (C_3, {r_2, r_3, r_4}),
+    // ...
+    let mut commitment_rotation_set_map: Vec<(Q::Commitment, FxHashSet<F>)> = vec![];
+    for query in queries.iter() {
+        let rotation = query.get_point();
+        super_point_set.insert(rotation);
+        if let Some(commitment_rotation_set) = commitment_rotation_set_map
+            .iter_mut()
+            .find(|(commitment, _)| *commitment == query.get_commitment())
+        {
+            let (_, rotation_set) = commitment_rotation_set;
+            rotation_set.insert(rotation);
+        } else {
+            commitment_rotation_set_map.push((
+                query.get_commitment(),
+                FxHashSet::from_iter(core::iter::once(rotation)),
+            ));
+        };
+    }
+
+    // Flatten rotation sets and collect commitments that opens against each commitment set
+    // Example elements in the vector:
+    // {r_5}: [C_0],
+    // {r_1, r_2, r_3} : [C_1]
+    // {r_2, r_3, r_4} : [C_2, C_3],
+    // ...
+    let mut rotation_set_commitment_map: Vec<(FxHashSet<F>, Vec<Q::Commitment>)> = vec![];
+    for (commitment, rotation_set) in commitment_rotation_set_map.into_iter() {
+        if let Some(rotation_set_commitment) = rotation_set_commitment_map
+            .iter_mut()
+            .find(|(set, _)| set == &rotation_set)
+        {
+            let (_, commitments) = rotation_set_commitment;
+            commitments.push(commitment);
+        } else {
+            rotation_set_commitment_map.push((rotation_set, vec![commitment]));
+        };
+    }
+
+    let rotation_sets = rotation_set_commitment_map
+        .into_par_iter()
+        .map(|(rotations, commitments)| {
+            let rotations_vec = rotations.iter().collect::<Vec<_>>();
+            let commitments: Vec<Commitment<F, Q::Commitment>> = commitments
+                .into_par_iter()
+                .map(|commitment| {
+                    let evals: Vec<F> = rotations_vec
+                        .par_iter()
+                        .map(|&&rotation| get_eval(commitment, rotation))
+                        .collect();
+                    Commitment((commitment, evals))
+                })
+                .collect();
+
+            RotationSet {
+                commitments,
+                points: rotations.into_iter().collect(),
+            }
+        })
+        .collect::<Vec<RotationSet<_, _>>>();
+
+    IntermediateSets {
+        rotation_sets,
+        super_point_set,
+    }
+}
+
+#[cfg(test)]
+mod proptests {
+    use proptest::{
+        collection::vec,
+        prelude::*,
+        sample::{select, subsequence},
+        strategy::Strategy,
+    };
+
+    use super::{construct_intermediate_sets, Commitment, IntermediateSets};
+    use crate::poly::Rotation;
+    use halo2curves::{bn256::Fr, FieldExt};
+
+    use std::collections::BTreeMap;
+    use std::convert::TryFrom;
+
+    #[derive(Debug, Clone)]
+    struct MyQuery<F> {
+        point: F,
+        eval: F,
+        commitment: usize,
+    }
+
+    impl super::Query<Fr> for MyQuery<Fr> {
+        type Commitment = usize;
+        type Eval = Fr;
+
+        fn get_point(&self) -> Fr {
+            self.point
+        }
+
+        fn get_eval(&self) -> Self::Eval {
+            self.eval
+        }
+
+        fn get_commitment(&self) -> Self::Commitment {
+            self.commitment
+        }
+    }
+
+    prop_compose! {
+        fn arb_point()(
+            bytes in vec(any::<u8>(), 64)
+        ) -> Fr {
+            Fr::from_bytes_wide(&<[u8; 64]>::try_from(bytes).unwrap())
+        }
+    }
+
+    prop_compose! {
+        fn arb_query(commitment: usize, point: Fr)(
+            eval in arb_point()
+        ) -> MyQuery<Fr> {
+            MyQuery {
+                point,
+                eval,
+                commitment
+            }
+        }
+    }
+
+    prop_compose! {
+        // Mapping from column index to point index.
+        fn arb_queries_inner(num_points: usize, num_cols: usize, num_queries: usize)(
+            col_indices in vec(select((0..num_cols).collect::<Vec<_>>()), num_queries),
+            point_indices in vec(select((0..num_points).collect::<Vec<_>>()), num_queries)
+        ) -> Vec<(usize, usize)> {
+            col_indices.into_iter().zip(point_indices.into_iter()).collect()
+        }
+    }
+
+    prop_compose! {
+        fn compare_queries(
+            num_points: usize,
+            num_cols: usize,
+            num_queries: usize,
+        )(
+            points_1 in vec(arb_point(), num_points),
+            points_2 in vec(arb_point(), num_points),
+            mapping in arb_queries_inner(num_points, num_cols, num_queries)
+        )(
+            queries_1 in mapping.iter().map(|(commitment, point_idx)| arb_query(*commitment, points_1[*point_idx])).collect::<Vec<_>>(),
+            queries_2 in mapping.iter().map(|(commitment, point_idx)| arb_query(*commitment, points_2[*point_idx])).collect::<Vec<_>>(),
+        ) -> (
+            Vec<MyQuery<Fr>>,
+            Vec<MyQuery<Fr>>
+        ) {
+            (
+                queries_1,
+                queries_2,
+            )
+        }
+    }
+
+    proptest! {
+        #[test]
+        fn test_intermediate_sets(
+            (queries_1, queries_2) in compare_queries(8, 8, 16)
+        ) {
+            let IntermediateSets { rotation_sets, .. } = construct_intermediate_sets(queries_1);
+            let commitment_sets = rotation_sets.iter().map(|data|
+                data.commitments.iter().map(Commitment::get).collect::<Vec<_>>()
+            ).collect::<Vec<_>>();
+
+            // It shouldn't matter what the point or eval values are; we should get
+            // the same exact point set indices and point indices again.
+            let IntermediateSets { rotation_sets: new_rotation_sets, .. } = construct_intermediate_sets(queries_2);
+            let new_commitment_sets = new_rotation_sets.iter().map(|data|
+                data.commitments.iter().map(Commitment::get).collect::<Vec<_>>()
+            ).collect::<Vec<_>>();
+
+            assert_eq!(commitment_sets, new_commitment_sets);
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/kzg/multiopen/shplonk/prover.rs.html b/docs/src/halo2_proofs/poly/kzg/multiopen/shplonk/prover.rs.html new file mode 100644 index 0000000000..af19955990 --- /dev/null +++ b/docs/src/halo2_proofs/poly/kzg/multiopen/shplonk/prover.rs.html @@ -0,0 +1,578 @@ +prover.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+
use super::{
+    construct_intermediate_sets, ChallengeU, ChallengeV, ChallengeY, Commitment, Query, RotationSet,
+};
+use crate::arithmetic::{
+    eval_polynomial, evaluate_vanishing_polynomial, kate_division, lagrange_interpolate,
+    parallelize, powers, CurveAffine, FieldExt,
+};
+use crate::helpers::SerdeCurveAffine;
+use crate::poly::commitment::{Blind, ParamsProver, Prover};
+use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG};
+use crate::poly::query::{PolynomialPointer, ProverQuery};
+use crate::poly::Rotation;
+use crate::poly::{commitment::Params, Coeff, Polynomial};
+use crate::transcript::{EncodedChallenge, TranscriptWrite};
+
+use ff::Field;
+use group::Curve;
+use halo2curves::pairing::Engine;
+use rand_core::RngCore;
+use rayon::prelude::*;
+use rustc_hash::FxHashSet;
+use std::fmt::Debug;
+use std::hash::Hash;
+use std::io::{self, Write};
+use std::marker::PhantomData;
+use std::ops::MulAssign;
+
+fn div_by_vanishing<F: FieldExt>(poly: Polynomial<F, Coeff>, roots: &[F]) -> Vec<F> {
+    let poly = roots
+        .iter()
+        .fold(poly.values, |poly, point| kate_division(&poly, *point));
+
+    poly
+}
+
+struct CommitmentExtension<'a, C: CurveAffine> {
+    commitment: Commitment<C::Scalar, PolynomialPointer<'a, C>>,
+    low_degree_equivalent: Polynomial<C::Scalar, Coeff>,
+}
+
+impl<'a, C: CurveAffine> Commitment<C::Scalar, PolynomialPointer<'a, C>> {
+    fn extend(&self, points: &[C::Scalar]) -> CommitmentExtension<'a, C> {
+        let poly = lagrange_interpolate(points, &self.evals()[..]);
+
+        let low_degree_equivalent = Polynomial {
+            values: poly,
+            _marker: PhantomData,
+        };
+
+        CommitmentExtension {
+            commitment: self.clone(),
+            low_degree_equivalent,
+        }
+    }
+}
+
+impl<'a, C: CurveAffine> CommitmentExtension<'a, C> {
+    fn linearisation_contribution(&self, u: C::Scalar) -> Polynomial<C::Scalar, Coeff> {
+        let p_x = self.commitment.get().poly;
+        let r_eval = eval_polynomial(&self.low_degree_equivalent.values[..], u);
+        p_x - r_eval
+    }
+
+    fn quotient_contribution(&self) -> Polynomial<C::Scalar, Coeff> {
+        let len = self.low_degree_equivalent.len();
+        let mut p_x = self.commitment.get().poly.clone();
+        parallelize(&mut p_x.values[0..len], |lhs, start| {
+            for (lhs, rhs) in lhs
+                .iter_mut()
+                .zip(self.low_degree_equivalent.values[start..].iter())
+            {
+                *lhs -= *rhs;
+            }
+        });
+        p_x
+    }
+}
+
+struct RotationSetExtension<'a, C: CurveAffine> {
+    commitments: Vec<CommitmentExtension<'a, C>>,
+    points: Vec<C::Scalar>,
+}
+
+impl<'a, C: CurveAffine> RotationSet<C::Scalar, PolynomialPointer<'a, C>> {
+    fn extend(self, commitments: Vec<CommitmentExtension<'a, C>>) -> RotationSetExtension<'a, C> {
+        RotationSetExtension {
+            commitments,
+            points: self.points,
+        }
+    }
+}
+
+/// Concrete KZG prover with SHPLONK variant
+#[derive(Debug)]
+pub struct ProverSHPLONK<'a, E: Engine> {
+    params: &'a ParamsKZG<E>,
+}
+
+impl<'a, E: Engine> ProverSHPLONK<'a, E> {
+    /// Given parameters creates new prover instance
+    pub fn new(params: &'a ParamsKZG<E>) -> Self {
+        Self { params }
+    }
+}
+
+/// Create a multi-opening proof
+impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme<E>>
+    for ProverSHPLONK<'params, E>
+where
+    E::G1Affine: SerdeCurveAffine,
+    E::G2Affine: SerdeCurveAffine,
+    E::Scalar: Hash,
+{
+    const QUERY_INSTANCE: bool = false;
+
+    fn new(params: &'params ParamsKZG<E>) -> Self {
+        Self { params }
+    }
+
+    /// Create a multi-opening proof
+    fn create_proof<
+        'com,
+        Ch: EncodedChallenge<E::G1Affine>,
+        T: TranscriptWrite<E::G1Affine, Ch>,
+        R,
+        I,
+    >(
+        &self,
+        _: R,
+        transcript: &mut T,
+        queries: I,
+    ) -> io::Result<()>
+    where
+        I: IntoIterator<Item = ProverQuery<'com, E::G1Affine>> + Clone,
+        R: RngCore,
+    {
+        // TODO: explore if it is safe to use same challenge
+        // for different sets that are already combined with anoter challenge
+        let y: ChallengeY<_> = transcript.squeeze_challenge_scalar();
+
+        let quotient_contribution =
+            |rotation_set: &RotationSetExtension<E::G1Affine>| -> Polynomial<E::Scalar, Coeff> {
+                // [P_i_0(X) - R_i_0(X), P_i_1(X) - R_i_1(X), ... ]
+                let numerators = rotation_set
+                    .commitments
+                    .par_iter()
+                    .map(|commitment| commitment.quotient_contribution())
+                    .collect::<Vec<_>>();
+
+                // define numerator polynomial as
+                // N_i_j(X) = (P_i_j(X) - R_i_j(X))
+                // and combine polynomials with same evaluation point set
+                // N_i(X) = linear_combinination(y, N_i_j(X))
+                // where y is random scalar to combine numerator polynomials
+                let n_x = numerators
+                    .into_iter()
+                    .zip(powers(*y))
+                    .map(|(numerator, power_of_y)| numerator * power_of_y)
+                    .reduce(|acc, numerator| acc + &numerator)
+                    .unwrap();
+
+                let points = &rotation_set.points[..];
+
+                // quotient contribution of this evaluation set is
+                // Q_i(X) = N_i(X) / Z_i(X) where
+                // Z_i(X) = (x - r_i_0) * (x - r_i_1) * ...
+                let mut poly = div_by_vanishing(n_x, points);
+                poly.resize(self.params.n as usize, E::Scalar::zero());
+
+                Polynomial {
+                    values: poly,
+                    _marker: PhantomData,
+                }
+            };
+
+        let intermediate_sets = construct_intermediate_sets(queries);
+        let (rotation_sets, super_point_set) = (
+            intermediate_sets.rotation_sets,
+            intermediate_sets.super_point_set,
+        );
+
+        let rotation_sets: Vec<RotationSetExtension<E::G1Affine>> = rotation_sets
+            .into_par_iter()
+            .map(|rotation_set| {
+                let commitments: Vec<CommitmentExtension<E::G1Affine>> = rotation_set
+                    .commitments
+                    .par_iter()
+                    .map(|commitment_data| commitment_data.extend(&rotation_set.points))
+                    .collect();
+                rotation_set.extend(commitments)
+            })
+            .collect();
+
+        let v: ChallengeV<_> = transcript.squeeze_challenge_scalar();
+
+        let quotient_polynomials = rotation_sets
+            .par_iter()
+            .map(quotient_contribution)
+            .collect::<Vec<_>>();
+
+        let h_x: Polynomial<E::Scalar, Coeff> = quotient_polynomials
+            .into_iter()
+            .zip(powers(*v))
+            .map(|(poly, power_of_v)| poly * power_of_v)
+            .reduce(|acc, poly| acc + &poly)
+            .unwrap();
+
+        let h = self.params.commit(&h_x, Blind::default()).to_affine();
+        transcript.write_point(h)?;
+        let u: ChallengeU<_> = transcript.squeeze_challenge_scalar();
+
+        let linearisation_contribution =
+            |rotation_set: RotationSetExtension<E::G1Affine>| -> (Polynomial<E::Scalar, Coeff>, E::Scalar) {
+                let mut diffs = super_point_set.clone();
+                for point in rotation_set.points.iter() {
+                    diffs.remove(point);
+                }
+                let diffs = diffs.into_iter().collect::<Vec<_>>();
+
+                // calculate difference vanishing polynomial evaluation
+                let z_i = evaluate_vanishing_polynomial(&diffs[..], *u);
+
+                // inner linearisation contibutions are
+                // [P_i_0(X) - r_i_0, P_i_1(X) - r_i_1, ... ] where
+                // r_i_j = R_i_j(u) is the evaluation of low degree equivalent polynomial
+                // where u is random evaluation point
+                let inner_contributions = rotation_set
+                    .commitments
+                    .par_iter()
+                    .map(|commitment| commitment.linearisation_contribution(*u)).collect::<Vec<_>>();
+
+                // define inner contributor polynomial as
+                // L_i_j(X) = (P_i_j(X) - r_i_j)
+                // and combine polynomials with same evaluation point set
+                // L_i(X) = linear_combinination(y, L_i_j(X))
+                // where y is random scalar to combine inner contibutors
+                let l_x: Polynomial<E::Scalar, Coeff> = inner_contributions.into_iter().zip(powers(*y)).map(|(poly, power_of_y)| poly * power_of_y).reduce(|acc, poly| acc + &poly).unwrap();
+
+                // finally scale l_x by difference vanishing polynomial evaluation z_i
+                (l_x * z_i, z_i)
+            };
+
+        #[allow(clippy::type_complexity)]
+        let (linearisation_contibutions, z_diffs): (
+            Vec<Polynomial<E::Scalar, Coeff>>,
+            Vec<E::Scalar>,
+        ) = rotation_sets
+            .into_par_iter()
+            .map(linearisation_contribution)
+            .unzip();
+
+        let l_x: Polynomial<E::Scalar, Coeff> = linearisation_contibutions
+            .into_iter()
+            .zip(powers(*v))
+            .map(|(poly, power_of_v)| poly * power_of_v)
+            .reduce(|acc, poly| acc + &poly)
+            .unwrap();
+
+        let super_point_set = super_point_set.into_iter().collect::<Vec<_>>();
+        let zt_eval = evaluate_vanishing_polynomial(&super_point_set[..], *u);
+        let l_x = l_x - &(h_x * zt_eval);
+
+        // sanity check
+        #[cfg(debug_assertions)]
+        {
+            let must_be_zero = eval_polynomial(&l_x.values[..], *u);
+            assert_eq!(must_be_zero, E::Scalar::zero());
+        }
+
+        let mut h_x = div_by_vanishing(l_x, &[*u]);
+
+        // normalize coefficients by the coefficient of the first polynomial
+        let z_0_diff_inv = z_diffs[0].invert().unwrap();
+        for h_i in h_x.iter_mut() {
+            h_i.mul_assign(z_0_diff_inv)
+        }
+
+        let h_x = Polynomial {
+            values: h_x,
+            _marker: PhantomData,
+        };
+
+        let h = self.params.commit(&h_x, Blind::default()).to_affine();
+        transcript.write_point(h)?;
+
+        Ok(())
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/kzg/multiopen/shplonk/verifier.rs.html b/docs/src/halo2_proofs/poly/kzg/multiopen/shplonk/verifier.rs.html new file mode 100644 index 0000000000..bd0cd2499f --- /dev/null +++ b/docs/src/halo2_proofs/poly/kzg/multiopen/shplonk/verifier.rs.html @@ -0,0 +1,302 @@ +verifier.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+
use std::fmt::Debug;
+use std::hash::Hash;
+use std::io::Read;
+
+use super::ChallengeY;
+use super::{construct_intermediate_sets, ChallengeU, ChallengeV};
+use crate::arithmetic::{
+    eval_polynomial, evaluate_vanishing_polynomial, lagrange_interpolate, powers, CurveAffine,
+    FieldExt,
+};
+use crate::helpers::SerdeCurveAffine;
+use crate::poly::commitment::Verifier;
+use crate::poly::commitment::MSM;
+use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG};
+use crate::poly::kzg::msm::DualMSM;
+use crate::poly::kzg::msm::{PreMSM, MSMKZG};
+use crate::poly::kzg::strategy::{AccumulatorStrategy, GuardKZG, SingleStrategy};
+use crate::poly::query::Query;
+use crate::poly::query::{CommitmentReference, VerifierQuery};
+use crate::poly::strategy::VerificationStrategy;
+use crate::poly::{
+    commitment::{Params, ParamsVerifier},
+    Error,
+};
+use crate::transcript::{EncodedChallenge, TranscriptRead};
+use ff::Field;
+use group::Group;
+use halo2curves::pairing::{Engine, MillerLoopResult, MultiMillerLoop};
+use rand_core::OsRng;
+use std::ops::MulAssign;
+
+/// Concrete KZG multiopen verifier with SHPLONK variant
+#[derive(Debug)]
+pub struct VerifierSHPLONK<'params, E: Engine> {
+    params: &'params ParamsKZG<E>,
+}
+
+impl<'params, E> Verifier<'params, KZGCommitmentScheme<E>> for VerifierSHPLONK<'params, E>
+where
+    E: MultiMillerLoop + Debug,
+    E::G1Affine: SerdeCurveAffine,
+    E::G2Affine: SerdeCurveAffine,
+    E::Scalar: Hash,
+{
+    type Guard = GuardKZG<'params, E>;
+    type MSMAccumulator = DualMSM<'params, E>;
+
+    const QUERY_INSTANCE: bool = false;
+
+    fn new(params: &'params ParamsKZG<E>) -> Self {
+        Self { params }
+    }
+
+    /// Verify a multi-opening proof
+    fn verify_proof<
+        'com,
+        Ch: EncodedChallenge<E::G1Affine>,
+        T: TranscriptRead<E::G1Affine, Ch>,
+        I,
+    >(
+        &self,
+        transcript: &mut T,
+        queries: I,
+        mut msm_accumulator: DualMSM<'params, E>,
+    ) -> Result<Self::Guard, Error>
+    where
+        I: IntoIterator<Item = VerifierQuery<'com, E::G1Affine, MSMKZG<E>>> + Clone,
+    {
+        let intermediate_sets = construct_intermediate_sets(queries);
+        let (rotation_sets, super_point_set) = (
+            intermediate_sets.rotation_sets,
+            intermediate_sets.super_point_set,
+        );
+
+        let y: ChallengeY<_> = transcript.squeeze_challenge_scalar();
+        let v: ChallengeV<_> = transcript.squeeze_challenge_scalar();
+
+        let h1 = transcript.read_point().map_err(|_| Error::SamplingError)?;
+        let u: ChallengeU<_> = transcript.squeeze_challenge_scalar();
+        let h2 = transcript.read_point().map_err(|_| Error::SamplingError)?;
+
+        let (mut z_0_diff_inverse, mut z_0) = (E::Scalar::zero(), E::Scalar::zero());
+        let (mut outer_msm, mut r_outer_acc) = (PreMSM::<E>::new(), E::Scalar::zero());
+        for (i, (rotation_set, power_of_v)) in rotation_sets.iter().zip(powers(*v)).enumerate() {
+            let diffs: Vec<E::Scalar> = super_point_set
+                .iter()
+                .filter(|point| !rotation_set.points.contains(point))
+                .copied()
+                .collect();
+            let mut z_diff_i = evaluate_vanishing_polynomial(&diffs[..], *u);
+
+            // normalize coefficients by the coefficient of the first commitment
+            if i == 0 {
+                z_0 = evaluate_vanishing_polynomial(&rotation_set.points[..], *u);
+                z_0_diff_inverse = z_diff_i.invert().unwrap();
+                z_diff_i = E::Scalar::one();
+            } else {
+                z_diff_i.mul_assign(z_0_diff_inverse);
+            }
+
+            let (mut inner_msm, r_inner_acc) = rotation_set
+                .commitments
+                .iter()
+                .zip(powers(*y))
+                .map(|(commitment_data, power_of_y)| {
+                    // calculate low degree equivalent
+                    let r_x = lagrange_interpolate(
+                        &rotation_set.points[..],
+                        &commitment_data.evals()[..],
+                    );
+                    let r_eval = power_of_y * eval_polynomial(&r_x[..], *u);
+                    let msm = match commitment_data.get() {
+                        CommitmentReference::Commitment(c) => {
+                            let mut msm = MSMKZG::<E>::new();
+                            msm.append_term(power_of_y, (*c).into());
+                            msm
+                        }
+                        CommitmentReference::MSM(msm) => {
+                            let mut msm = msm.clone();
+                            msm.scale(power_of_y);
+                            msm
+                        }
+                    };
+                    (msm, r_eval)
+                })
+                .reduce(|(mut msm_acc, r_eval_acc), (msm, r_eval)| {
+                    msm_acc.add_msm(&msm);
+                    (msm_acc, r_eval_acc + r_eval)
+                })
+                .unwrap();
+
+            inner_msm.scale(power_of_v * z_diff_i);
+            outer_msm.add_msm(inner_msm);
+            r_outer_acc += power_of_v * r_inner_acc * z_diff_i;
+        }
+        let mut outer_msm = outer_msm.normalize();
+        let g1: E::G1 = self.params.g[0].into();
+        outer_msm.append_term(-r_outer_acc, g1);
+        outer_msm.append_term(-z_0, h1.into());
+        outer_msm.append_term(*u, h2.into());
+
+        msm_accumulator
+            .left
+            .append_term(E::Scalar::one(), h2.into());
+
+        msm_accumulator.right.add_msm(&outer_msm);
+
+        Ok(Self::Guard::new(msm_accumulator))
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/kzg/strategy.rs.html b/docs/src/halo2_proofs/poly/kzg/strategy.rs.html new file mode 100644 index 0000000000..811674d47e --- /dev/null +++ b/docs/src/halo2_proofs/poly/kzg/strategy.rs.html @@ -0,0 +1,320 @@ +strategy.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+
use std::{fmt::Debug, marker::PhantomData};
+
+use super::{
+    commitment::{KZGCommitmentScheme, ParamsKZG},
+    msm::{DualMSM, MSMKZG},
+    multiopen::VerifierGWC,
+};
+use crate::{
+    helpers::SerdeCurveAffine,
+    plonk::Error,
+    poly::{
+        commitment::{Verifier, MSM},
+        ipa::msm::MSMIPA,
+        strategy::{Guard, VerificationStrategy},
+    },
+    transcript::{EncodedChallenge, TranscriptRead},
+};
+use ff::Field;
+use group::Group;
+use halo2curves::{
+    pairing::{Engine, MillerLoopResult, MultiMillerLoop},
+    CurveAffine,
+};
+use rand_core::OsRng;
+
+/// Wrapper for linear verification accumulator
+#[derive(Debug, Clone)]
+pub struct GuardKZG<'params, E: MultiMillerLoop + Debug> {
+    pub(crate) msm_accumulator: DualMSM<'params, E>,
+}
+
+/// Define accumulator type as `DualMSM`
+impl<'params, E> Guard<KZGCommitmentScheme<E>> for GuardKZG<'params, E>
+where
+    E: MultiMillerLoop + Debug,
+    E::G1Affine: SerdeCurveAffine,
+    E::G2Affine: SerdeCurveAffine,
+{
+    type MSMAccumulator = DualMSM<'params, E>;
+}
+
+/// KZG specific operations
+impl<'params, E: MultiMillerLoop + Debug> GuardKZG<'params, E> {
+    pub(crate) fn new(msm_accumulator: DualMSM<'params, E>) -> Self {
+        Self { msm_accumulator }
+    }
+}
+
+/// A verifier that checks multiple proofs in a batch
+#[derive(Clone, Debug)]
+pub struct AccumulatorStrategy<'params, E: Engine> {
+    pub(crate) msm_accumulator: DualMSM<'params, E>,
+}
+
+impl<'params, E: MultiMillerLoop + Debug> AccumulatorStrategy<'params, E> {
+    /// Constructs an empty batch verifier
+    pub fn new(params: &'params ParamsKZG<E>) -> Self {
+        AccumulatorStrategy {
+            msm_accumulator: DualMSM::new(params),
+        }
+    }
+
+    /// Constructs and initialized new batch verifier
+    pub fn with(msm_accumulator: DualMSM<'params, E>) -> Self {
+        AccumulatorStrategy { msm_accumulator }
+    }
+}
+
+/// A verifier that checks a single proof
+#[derive(Clone, Debug)]
+pub struct SingleStrategy<'params, E: Engine> {
+    pub(crate) msm: DualMSM<'params, E>,
+}
+
+impl<'params, E: MultiMillerLoop + Debug> SingleStrategy<'params, E> {
+    /// Constructs an empty batch verifier
+    pub fn new(params: &'params ParamsKZG<E>) -> Self {
+        SingleStrategy {
+            msm: DualMSM::new(params),
+        }
+    }
+}
+
+impl<
+        'params,
+        E: MultiMillerLoop + Debug,
+        V: Verifier<
+            'params,
+            KZGCommitmentScheme<E>,
+            MSMAccumulator = DualMSM<'params, E>,
+            Guard = GuardKZG<'params, E>,
+        >,
+    > VerificationStrategy<'params, KZGCommitmentScheme<E>, V> for AccumulatorStrategy<'params, E>
+where
+    E::G1Affine: SerdeCurveAffine,
+    E::G2Affine: SerdeCurveAffine,
+{
+    type Output = Self;
+
+    fn new(params: &'params ParamsKZG<E>) -> Self {
+        AccumulatorStrategy::new(params)
+    }
+
+    fn process(
+        mut self,
+        f: impl FnOnce(V::MSMAccumulator) -> Result<V::Guard, Error>,
+    ) -> Result<Self::Output, Error> {
+        self.msm_accumulator.scale(E::Scalar::random(OsRng));
+
+        // Guard is updated with new msm contributions
+        let guard = f(self.msm_accumulator)?;
+        Ok(Self {
+            msm_accumulator: guard.msm_accumulator,
+        })
+    }
+
+    fn finalize(self) -> bool {
+        self.msm_accumulator.check()
+    }
+}
+
+impl<
+        'params,
+        E: MultiMillerLoop + Debug,
+        V: Verifier<
+            'params,
+            KZGCommitmentScheme<E>,
+            MSMAccumulator = DualMSM<'params, E>,
+            Guard = GuardKZG<'params, E>,
+        >,
+    > VerificationStrategy<'params, KZGCommitmentScheme<E>, V> for SingleStrategy<'params, E>
+where
+    E::G1Affine: SerdeCurveAffine,
+    E::G2Affine: SerdeCurveAffine,
+{
+    type Output = ();
+
+    fn new(params: &'params ParamsKZG<E>) -> Self {
+        Self::new(params)
+    }
+
+    fn process(
+        self,
+        f: impl FnOnce(V::MSMAccumulator) -> Result<V::Guard, Error>,
+    ) -> Result<Self::Output, Error> {
+        // Guard is updated with new msm contributions
+        let guard = f(self.msm)?;
+        let msm = guard.msm_accumulator;
+        if msm.check() {
+            Ok(())
+        } else {
+            Err(Error::ConstraintSystemFailure)
+        }
+    }
+
+    fn finalize(self) -> bool {
+        unreachable!();
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/query.rs.html b/docs/src/halo2_proofs/poly/query.rs.html new file mode 100644 index 0000000000..1adf359c2b --- /dev/null +++ b/docs/src/halo2_proofs/poly/query.rs.html @@ -0,0 +1,276 @@ +query.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+
use std::{fmt::Debug, ops::Deref};
+
+use super::commitment::{Blind, CommitmentScheme, Params, MSM};
+use crate::{
+    arithmetic::eval_polynomial,
+    poly::{commitment, Coeff, Polynomial},
+};
+use ff::Field;
+use halo2curves::CurveAffine;
+
+pub trait Query<F>: Sized + Clone + Send + Sync {
+    type Commitment: PartialEq + Copy + Send + Sync;
+    type Eval: Clone + Default + Debug;
+
+    fn get_point(&self) -> F;
+    fn get_eval(&self) -> Self::Eval;
+    fn get_commitment(&self) -> Self::Commitment;
+}
+
+/// A polynomial query at a point
+#[derive(Debug, Clone)]
+pub struct ProverQuery<'com, C: CurveAffine> {
+    /// point at which polynomial is queried
+    pub(crate) point: C::Scalar,
+    /// coefficients of polynomial
+    pub(crate) poly: &'com Polynomial<C::Scalar, Coeff>,
+    /// blinding factor of polynomial
+    pub(crate) blind: Blind<C::Scalar>,
+}
+
+#[doc(hidden)]
+#[derive(Copy, Clone)]
+pub struct PolynomialPointer<'com, C: CurveAffine> {
+    pub(crate) poly: &'com Polynomial<C::Scalar, Coeff>,
+    pub(crate) blind: Blind<C::Scalar>,
+}
+
+impl<'com, C: CurveAffine> PartialEq for PolynomialPointer<'com, C> {
+    fn eq(&self, other: &Self) -> bool {
+        std::ptr::eq(self.poly, other.poly)
+    }
+}
+
+impl<'com, C: CurveAffine> Query<C::Scalar> for ProverQuery<'com, C> {
+    type Commitment = PolynomialPointer<'com, C>;
+    type Eval = C::Scalar;
+
+    fn get_point(&self) -> C::Scalar {
+        self.point
+    }
+    fn get_eval(&self) -> Self::Eval {
+        eval_polynomial(&self.poly[..], self.get_point())
+    }
+    fn get_commitment(&self) -> Self::Commitment {
+        PolynomialPointer {
+            poly: self.poly,
+            blind: self.blind,
+        }
+    }
+}
+
+impl<'com, C: CurveAffine, M: MSM<C>> VerifierQuery<'com, C, M> {
+    /// Create a new verifier query based on a commitment
+    pub fn new_commitment(commitment: &'com C, point: C::Scalar, eval: C::Scalar) -> Self {
+        VerifierQuery {
+            point,
+            eval,
+            commitment: CommitmentReference::Commitment(commitment),
+        }
+    }
+
+    /// Create a new verifier query based on a linear combination of commitments
+    pub fn new_msm(msm: &'com M, point: C::Scalar, eval: C::Scalar) -> VerifierQuery<'com, C, M> {
+        VerifierQuery {
+            point,
+            eval,
+            commitment: CommitmentReference::MSM(msm),
+        }
+    }
+}
+
+/// A polynomial query at a point
+#[derive(Debug)]
+pub struct VerifierQuery<'com, C: CurveAffine, M: MSM<C>> {
+    /// point at which polynomial is queried
+    pub(crate) point: C::Scalar,
+    /// commitment to polynomial
+    pub(crate) commitment: CommitmentReference<'com, C, M>,
+    /// evaluation of polynomial at query point
+    pub(crate) eval: C::Scalar,
+}
+
+impl<'com, C: CurveAffine, M: MSM<C>> Clone for VerifierQuery<'com, C, M> {
+    fn clone(&self) -> Self {
+        Self {
+            point: self.point,
+            commitment: self.commitment,
+            eval: self.eval,
+        }
+    }
+}
+
+#[derive(Clone, Debug)]
+pub enum CommitmentReference<'r, C: CurveAffine, M: MSM<C>> {
+    Commitment(&'r C),
+    MSM(&'r M),
+}
+
+impl<'r, C: CurveAffine, M: MSM<C>> Copy for CommitmentReference<'r, C, M> {}
+
+impl<'r, C: CurveAffine, M: MSM<C>> PartialEq for CommitmentReference<'r, C, M> {
+    #![allow(clippy::vtable_address_comparisons)]
+    fn eq(&self, other: &Self) -> bool {
+        match (self, other) {
+            (&CommitmentReference::Commitment(a), &CommitmentReference::Commitment(b)) => {
+                std::ptr::eq(a, b)
+            }
+            (&CommitmentReference::MSM(a), &CommitmentReference::MSM(b)) => std::ptr::eq(a, b),
+            _ => false,
+        }
+    }
+}
+
+impl<'com, C: CurveAffine, M: MSM<C>> Query<C::Scalar> for VerifierQuery<'com, C, M> {
+    type Eval = C::Scalar;
+    type Commitment = CommitmentReference<'com, C, M>;
+
+    fn get_point(&self) -> C::Scalar {
+        self.point
+    }
+    fn get_eval(&self) -> C::Scalar {
+        self.eval
+    }
+    fn get_commitment(&self) -> Self::Commitment {
+        self.commitment
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/poly/strategy.rs.html b/docs/src/halo2_proofs/poly/strategy.rs.html new file mode 100644 index 0000000000..b54f647734 --- /dev/null +++ b/docs/src/halo2_proofs/poly/strategy.rs.html @@ -0,0 +1,76 @@ +strategy.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+
use halo2curves::CurveAffine;
+use rand_core::RngCore;
+
+use super::commitment::{CommitmentScheme, Verifier, MSM};
+use crate::{
+    plonk::Error,
+    transcript::{EncodedChallenge, TranscriptRead},
+};
+
+/// Guards is unfinished verification result. Implement this to construct various
+/// verification strategies such as aggregation and recursion.
+pub trait Guard<Scheme: CommitmentScheme> {
+    /// Multi scalar engine which is not evaluated yet.
+    type MSMAccumulator;
+}
+
+/// Trait representing a strategy for verifying Halo 2 proofs.
+pub trait VerificationStrategy<'params, Scheme: CommitmentScheme, V: Verifier<'params, Scheme>> {
+    /// The output type of this verification strategy after processing a proof.
+    type Output;
+
+    /// Creates new verification strategy instance
+    fn new(params: &'params Scheme::ParamsVerifier) -> Self;
+
+    /// Obtains an MSM from the verifier strategy and yields back the strategy's
+    /// output.
+    fn process(
+        self,
+        f: impl FnOnce(V::MSMAccumulator) -> Result<V::Guard, Error>,
+    ) -> Result<Self::Output, Error>;
+
+    /// Finalizes the batch and checks its validity.
+    ///
+    /// Returns `false` if *some* proof was invalid. If the caller needs to identify
+    /// specific failing proofs, it must re-process the proofs separately.
+    fn finalize(self) -> bool;
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2_proofs/transcript.rs.html b/docs/src/halo2_proofs/transcript.rs.html new file mode 100644 index 0000000000..a0b9cd54c4 --- /dev/null +++ b/docs/src/halo2_proofs/transcript.rs.html @@ -0,0 +1,660 @@ +transcript.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+
//! This module contains utilities and traits for dealing with Fiat-Shamir
+//! transcripts.
+
+use blake2b_simd::{Params as Blake2bParams, State as Blake2bState};
+use group::ff::PrimeField;
+use std::convert::TryInto;
+
+use halo2curves::{Coordinates, CurveAffine, FieldExt};
+
+use std::io::{self, Read, Write};
+use std::marker::PhantomData;
+
+/// Prefix to a prover's message soliciting a challenge
+const BLAKE2B_PREFIX_CHALLENGE: u8 = 0;
+
+/// Prefix to a prover's message containing a curve point
+const BLAKE2B_PREFIX_POINT: u8 = 1;
+
+/// Prefix to a prover's message containing a scalar
+const BLAKE2B_PREFIX_SCALAR: u8 = 2;
+
+/// Generic transcript view (from either the prover or verifier's perspective)
+pub trait Transcript<C: CurveAffine, E: EncodedChallenge<C>> {
+    /// Squeeze an encoded verifier challenge from the transcript.
+    fn squeeze_challenge(&mut self) -> E;
+
+    /// Squeeze a typed challenge (in the scalar field) from the transcript.
+    fn squeeze_challenge_scalar<T>(&mut self) -> ChallengeScalar<C, T> {
+        ChallengeScalar {
+            inner: self.squeeze_challenge().get_scalar(),
+            _marker: PhantomData,
+        }
+    }
+
+    /// Writing the point to the transcript without writing it to the proof,
+    /// treating it as a common input.
+    fn common_point(&mut self, point: C) -> io::Result<()>;
+
+    /// Writing the scalar to the transcript without writing it to the proof,
+    /// treating it as a common input.
+    fn common_scalar(&mut self, scalar: C::Scalar) -> io::Result<()>;
+}
+
+/// Transcript view from the perspective of a verifier that has access to an
+/// input stream of data from the prover to the verifier.
+pub trait TranscriptRead<C: CurveAffine, E: EncodedChallenge<C>>: Transcript<C, E> {
+    /// Read a curve point from the prover.
+    fn read_point(&mut self) -> io::Result<C>;
+
+    /// Read a curve scalar from the prover.
+    fn read_scalar(&mut self) -> io::Result<C::Scalar>;
+}
+
+/// Transcript view from the perspective of a prover that has access to an
+/// output stream of messages from the prover to the verifier.
+pub trait TranscriptWrite<C: CurveAffine, E: EncodedChallenge<C>>: Transcript<C, E> {
+    /// Write a curve point to the proof and the transcript.
+    fn write_point(&mut self, point: C) -> io::Result<()>;
+
+    /// Write a scalar to the proof and the transcript.
+    fn write_scalar(&mut self, scalar: C::Scalar) -> io::Result<()>;
+}
+
+/// Initializes transcript at verifier side.
+pub trait TranscriptReadBuffer<R: Read, C: CurveAffine, E: EncodedChallenge<C>>:
+    TranscriptRead<C, E>
+{
+    /// Initialize a transcript given an input buffer.
+    fn init(reader: R) -> Self;
+}
+
+/// Manages begining and finising of transcript pipeline.
+pub trait TranscriptWriterBuffer<W: Write, C: CurveAffine, E: EncodedChallenge<C>>:
+    TranscriptWrite<C, E>
+{
+    /// Initialize a transcript given an output buffer.
+    fn init(writer: W) -> Self;
+
+    /// Conclude the interaction and return the output buffer (writer).
+    fn finalize(self) -> W;
+}
+
+/// We will replace BLAKE2b with an algebraic hash function in a later version.
+#[derive(Debug, Clone)]
+pub struct Blake2bRead<R: Read, C: CurveAffine, E: EncodedChallenge<C>> {
+    state: Blake2bState,
+    reader: R,
+    _marker: PhantomData<(C, E)>,
+}
+
+impl<R: Read, C: CurveAffine> TranscriptReadBuffer<R, C, Challenge255<C>>
+    for Blake2bRead<R, C, Challenge255<C>>
+{
+    /// Initialize a transcript given an input buffer.
+    fn init(reader: R) -> Self {
+        Blake2bRead {
+            state: Blake2bParams::new()
+                .hash_length(64)
+                .personal(b"Halo2-Transcript")
+                .to_state(),
+            reader,
+            _marker: PhantomData,
+        }
+    }
+}
+
+impl<R: Read, C: CurveAffine> TranscriptRead<C, Challenge255<C>>
+    for Blake2bRead<R, C, Challenge255<C>>
+{
+    fn read_point(&mut self) -> io::Result<C> {
+        let mut compressed = C::Repr::default();
+        self.reader.read_exact(compressed.as_mut())?;
+        let point: C = Option::from(C::from_bytes(&compressed)).ok_or_else(|| {
+            io::Error::new(io::ErrorKind::Other, "invalid point encoding in proof")
+        })?;
+        self.common_point(point)?;
+
+        Ok(point)
+    }
+
+    fn read_scalar(&mut self) -> io::Result<C::Scalar> {
+        let mut data = <C::Scalar as PrimeField>::Repr::default();
+        self.reader.read_exact(data.as_mut())?;
+        let scalar: C::Scalar = Option::from(C::Scalar::from_repr(data)).ok_or_else(|| {
+            io::Error::new(
+                io::ErrorKind::Other,
+                "invalid field element encoding in proof",
+            )
+        })?;
+        self.common_scalar(scalar)?;
+
+        Ok(scalar)
+    }
+}
+
+impl<R: Read, C: CurveAffine> Transcript<C, Challenge255<C>>
+    for Blake2bRead<R, C, Challenge255<C>>
+{
+    fn squeeze_challenge(&mut self) -> Challenge255<C> {
+        self.state.update(&[BLAKE2B_PREFIX_CHALLENGE]);
+        let hasher = self.state.clone();
+        let result: [u8; 64] = hasher.finalize().as_bytes().try_into().unwrap();
+        Challenge255::<C>::new(&result)
+    }
+
+    fn common_point(&mut self, point: C) -> io::Result<()> {
+        self.state.update(&[BLAKE2B_PREFIX_POINT]);
+        let coords: Coordinates<C> = Option::from(point.coordinates()).ok_or_else(|| {
+            io::Error::new(
+                io::ErrorKind::Other,
+                "cannot write points at infinity to the transcript",
+            )
+        })?;
+        self.state.update(coords.x().to_repr().as_ref());
+        self.state.update(coords.y().to_repr().as_ref());
+
+        Ok(())
+    }
+
+    fn common_scalar(&mut self, scalar: C::Scalar) -> io::Result<()> {
+        self.state.update(&[BLAKE2B_PREFIX_SCALAR]);
+        self.state.update(scalar.to_repr().as_ref());
+
+        Ok(())
+    }
+}
+
+/// We will replace BLAKE2b with an algebraic hash function in a later version.
+#[derive(Debug, Clone)]
+pub struct Blake2bWrite<W: Write, C: CurveAffine, E: EncodedChallenge<C>> {
+    state: Blake2bState,
+    writer: W,
+    _marker: PhantomData<(C, E)>,
+}
+
+impl<W: Write, C: CurveAffine> TranscriptWriterBuffer<W, C, Challenge255<C>>
+    for Blake2bWrite<W, C, Challenge255<C>>
+{
+    fn init(writer: W) -> Self {
+        Blake2bWrite {
+            state: Blake2bParams::new()
+                .hash_length(64)
+                .personal(b"Halo2-Transcript")
+                .to_state(),
+            writer,
+            _marker: PhantomData,
+        }
+    }
+
+    fn finalize(self) -> W {
+        // TODO: handle outstanding scalars? see issue #138
+        self.writer
+    }
+}
+
+impl<W: Write, C: CurveAffine> TranscriptWrite<C, Challenge255<C>>
+    for Blake2bWrite<W, C, Challenge255<C>>
+{
+    fn write_point(&mut self, point: C) -> io::Result<()> {
+        self.common_point(point)?;
+        let compressed = point.to_bytes();
+        self.writer.write_all(compressed.as_ref())
+    }
+    fn write_scalar(&mut self, scalar: C::Scalar) -> io::Result<()> {
+        self.common_scalar(scalar)?;
+        let data = scalar.to_repr();
+        self.writer.write_all(data.as_ref())
+    }
+}
+
+impl<W: Write, C: CurveAffine> Transcript<C, Challenge255<C>>
+    for Blake2bWrite<W, C, Challenge255<C>>
+{
+    fn squeeze_challenge(&mut self) -> Challenge255<C> {
+        self.state.update(&[BLAKE2B_PREFIX_CHALLENGE]);
+        let hasher = self.state.clone();
+        let result: [u8; 64] = hasher.finalize().as_bytes().try_into().unwrap();
+        Challenge255::<C>::new(&result)
+    }
+
+    fn common_point(&mut self, point: C) -> io::Result<()> {
+        self.state.update(&[BLAKE2B_PREFIX_POINT]);
+        let coords: Coordinates<C> = Option::from(point.coordinates()).ok_or_else(|| {
+            io::Error::new(
+                io::ErrorKind::Other,
+                "cannot write points at infinity to the transcript",
+            )
+        })?;
+        self.state.update(coords.x().to_repr().as_ref());
+        self.state.update(coords.y().to_repr().as_ref());
+
+        Ok(())
+    }
+
+    fn common_scalar(&mut self, scalar: C::Scalar) -> io::Result<()> {
+        self.state.update(&[BLAKE2B_PREFIX_SCALAR]);
+        self.state.update(scalar.to_repr().as_ref());
+
+        Ok(())
+    }
+}
+
+/// The scalar representation of a verifier challenge.
+///
+/// The `Type` type can be used to scope the challenge to a specific context, or
+/// set to `()` if no context is required.
+#[derive(Copy, Clone, Debug)]
+pub struct ChallengeScalar<C: CurveAffine, T> {
+    inner: C::Scalar,
+    _marker: PhantomData<T>,
+}
+
+impl<C: CurveAffine, T> std::ops::Deref for ChallengeScalar<C, T> {
+    type Target = C::Scalar;
+
+    fn deref(&self) -> &Self::Target {
+        &self.inner
+    }
+}
+
+/// `EncodedChallenge<C>` defines a challenge encoding with a [`Self::Input`]
+/// that is used to derive the challenge encoding and `get_challenge` obtains
+/// the _real_ `C::Scalar` that the challenge encoding represents.
+pub trait EncodedChallenge<C: CurveAffine> {
+    /// The Input type used to derive the challenge encoding. For example,
+    /// an input from the Poseidon hash would be a base field element;
+    /// an input from the Blake2b hash would be a [u8; 64].
+    type Input;
+
+    /// Get an encoded challenge from a given input challenge.
+    fn new(challenge_input: &Self::Input) -> Self;
+
+    /// Get a scalar field element from an encoded challenge.
+    fn get_scalar(&self) -> C::Scalar;
+
+    /// Cast an encoded challenge as a typed `ChallengeScalar`.
+    fn as_challenge_scalar<T>(&self) -> ChallengeScalar<C, T> {
+        ChallengeScalar {
+            inner: self.get_scalar(),
+            _marker: PhantomData,
+        }
+    }
+}
+
+/// A 255-bit challenge.
+#[derive(Copy, Clone, Debug)]
+pub struct Challenge255<C: CurveAffine>([u8; 32], PhantomData<C>);
+
+impl<C: CurveAffine> std::ops::Deref for Challenge255<C> {
+    type Target = [u8; 32];
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl<C: CurveAffine> EncodedChallenge<C> for Challenge255<C> {
+    type Input = [u8; 64];
+
+    fn new(challenge_input: &[u8; 64]) -> Self {
+        Challenge255(
+            C::Scalar::from_bytes_wide(challenge_input)
+                .to_repr()
+                .as_ref()
+                .try_into()
+                .expect("Scalar fits into 256 bits"),
+            PhantomData,
+        )
+    }
+    fn get_scalar(&self) -> C::Scalar {
+        let mut repr = <C::Scalar as PrimeField>::Repr::default();
+        repr.as_mut().copy_from_slice(&self.0);
+        C::Scalar::from_repr(repr).unwrap()
+    }
+}
+
+pub(crate) fn read_n_points<C: CurveAffine, E: EncodedChallenge<C>, T: TranscriptRead<C, E>>(
+    transcript: &mut T,
+    n: usize,
+) -> io::Result<Vec<C>> {
+    (0..n).map(|_| transcript.read_point()).collect()
+}
+
+pub(crate) fn read_n_scalars<C: CurveAffine, E: EncodedChallenge<C>, T: TranscriptRead<C, E>>(
+    transcript: &mut T,
+    n: usize,
+) -> io::Result<Vec<C::Scalar>> {
+    (0..n).map(|_| transcript.read_scalar()).collect()
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/arithmetic.rs.html b/docs/src/halo2curves/arithmetic.rs.html new file mode 100644 index 0000000000..0f83848fa8 --- /dev/null +++ b/docs/src/halo2curves/arithmetic.rs.html @@ -0,0 +1,252 @@ +arithmetic.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+
//! This module provides common utilities, traits and structures for group and
+//! field arithmetic.
+//!
+//! This module is temporary, and the extension traits defined here are expected to be
+//! upstreamed into the `ff` and `group` crates after some refactoring.
+
+use subtle::{Choice, ConditionallySelectable, CtOption};
+
+pub trait CurveAffineExt: pasta_curves::arithmetic::CurveAffine {
+    fn batch_add<const COMPLETE: bool, const LOAD_POINTS: bool>(
+        points: &mut [Self],
+        output_indices: &[u32],
+        num_points: usize,
+        offset: usize,
+        bases: &[Self],
+        base_positions: &[u32],
+    );
+
+    /// Unlike the `Coordinates` trait, this just returns the raw affine coordinates without checking `is_on_curve`
+    fn into_coordinates(self) -> (Self::Base, Self::Base) {
+        // fallback implementation
+        let coordinates = self.coordinates().unwrap();
+        (*coordinates.x(), *coordinates.y())
+    }
+}
+
+pub(crate) fn sqrt_tonelli_shanks<F: ff::PrimeField, S: AsRef<[u64]>>(
+    f: &F,
+    tm1d2: S,
+) -> CtOption<F> {
+    use subtle::ConstantTimeEq;
+
+    // w = self^((t - 1) // 2)
+    let w = f.pow_vartime(tm1d2);
+
+    let mut v = F::S;
+    let mut x = w * f;
+    let mut b = x * w;
+
+    // Initialize z as the 2^S root of unity.
+    let mut z = F::root_of_unity();
+
+    for max_v in (1..=F::S).rev() {
+        let mut k = 1;
+        let mut tmp = b.square();
+        let mut j_less_than_v: Choice = 1.into();
+
+        for j in 2..max_v {
+            let tmp_is_one = tmp.ct_eq(&F::one());
+            let squared = F::conditional_select(&tmp, &z, tmp_is_one).square();
+            tmp = F::conditional_select(&squared, &tmp, tmp_is_one);
+            let new_z = F::conditional_select(&z, &squared, tmp_is_one);
+            j_less_than_v &= !j.ct_eq(&v);
+            k = u32::conditional_select(&j, &k, tmp_is_one);
+            z = F::conditional_select(&z, &new_z, j_less_than_v);
+        }
+
+        let result = x * z;
+        x = F::conditional_select(&result, &x, b.ct_eq(&F::one()));
+        z = z.square();
+        b *= z;
+        v = k;
+    }
+
+    CtOption::new(
+        x,
+        (x * x).ct_eq(f), // Only return Some if it's the square root.
+    )
+}
+
+/// Compute a + b + carry, returning the result and the new carry over.
+/// The carry input must be 0 or 1; otherwise the behavior is undefined.
+/// The carryOut output is guaranteed to be 0 or 1.
+#[inline(always)]
+pub(crate) const fn adc(a: u64, b: u64, carry: bool) -> (u64, bool) {
+    a.carrying_add(b, carry)
+}
+
+/// Compute a - b - borrow, returning the result and the new borrow.
+#[inline(always)]
+pub(crate) const fn sbb(a: u64, b: u64, borrow: bool) -> (u64, bool) {
+    a.borrowing_sub(b, borrow)
+}
+
+/// Compute a + (b * c), returning the result and the new carry over.
+// Alias madd1
+#[inline(always)]
+pub(crate) const fn macx(a: u64, b: u64, c: u64) -> (u64, u64) {
+    b.carrying_mul(c, a)
+}
+
+/// Compute a + (b * c) + carry, returning the result and the new carry over.
+// Alias madd2
+#[inline(always)]
+pub(crate) const fn mac(a: u64, b: u64, c: u64, carry: u64) -> (u64, u64) {
+    let (lo, hi) = b.carrying_mul(c, a);
+    let (lo, carry) = lo.overflowing_add(carry);
+    (lo, hi + carry as u64)
+}
+
+/// Compute a * b, returning the result.
+#[inline(always)]
+pub(crate) fn mul_512(a: [u64; 4], b: [u64; 4]) -> [u64; 8] {
+    let (r0, carry) = macx(0, a[0], b[0]);
+    let (r1, carry) = macx(carry, a[0], b[1]);
+    let (r2, carry) = macx(carry, a[0], b[2]);
+    let (r3, carry_out) = macx(carry, a[0], b[3]);
+
+    let (r1, carry) = macx(r1, a[1], b[0]);
+    let (r2, carry) = mac(r2, a[1], b[1], carry);
+    let (r3, carry) = mac(r3, a[1], b[2], carry);
+    let (r4, carry_out) = mac(carry_out, a[1], b[3], carry);
+
+    let (r2, carry) = macx(r2, a[2], b[0]);
+    let (r3, carry) = mac(r3, a[2], b[1], carry);
+    let (r4, carry) = mac(r4, a[2], b[2], carry);
+    let (r5, carry_out) = mac(carry_out, a[2], b[3], carry);
+
+    let (r3, carry) = macx(r3, a[3], b[0]);
+    let (r4, carry) = mac(r4, a[3], b[1], carry);
+    let (r5, carry) = mac(r5, a[3], b[2], carry);
+    let (r6, carry_out) = mac(carry_out, a[3], b[3], carry);
+
+    [r0, r1, r2, r3, r4, r5, r6, carry_out]
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/bn256/curve.rs.html b/docs/src/halo2curves/bn256/curve.rs.html new file mode 100644 index 0000000000..97f590061c --- /dev/null +++ b/docs/src/halo2curves/bn256/curve.rs.html @@ -0,0 +1,672 @@ +curve.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+
use crate::arithmetic::mul_512;
+use crate::bn256::Fq;
+use crate::bn256::Fq2;
+use crate::bn256::Fr;
+use crate::{Coordinates, CurveAffine, CurveAffineExt, CurveExt, Group};
+use core::cmp;
+use core::fmt::Debug;
+use core::iter::Sum;
+use core::ops::{Add, Mul, Neg, Sub};
+use ff::{Field, PrimeField};
+use group::Curve;
+use group::{cofactor::CofactorGroup, prime::PrimeCurveAffine, Group as _, GroupEncoding};
+use pasta_curves::arithmetic::FieldExt;
+use rand::RngCore;
+use serde::{Deserialize, Serialize};
+use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
+
+use crate::{
+    batch_add, impl_add_binop_specify_output, impl_binops_additive,
+    impl_binops_additive_specify_output, impl_binops_multiplicative,
+    impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, new_curve_impl,
+};
+
+new_curve_impl!(
+    (pub),
+    G1,
+    G1Affine,
+    G1Compressed,
+    Fq::size(),
+    Fq,
+    Fr,
+    (G1_GENERATOR_X,G1_GENERATOR_Y),
+    G1_B,
+    "bn256_g1",
+);
+
+new_curve_impl!(
+    (pub),
+    G2,
+    G2Affine,
+    G2Compressed,
+    Fq2::size(),
+    Fq2,
+    Fr,
+    (G2_GENERATOR_X, G2_GENERATOR_Y),
+    G2_B,
+    "bn256_g2",
+);
+
+impl CurveAffineExt for G1Affine {
+    batch_add!();
+
+    fn into_coordinates(self) -> (Self::Base, Self::Base) {
+        (self.x, self.y)
+    }
+}
+
+impl CurveAffineExt for G2Affine {
+    batch_add!();
+
+    fn into_coordinates(self) -> (Self::Base, Self::Base) {
+        (self.x, self.y)
+    }
+}
+
+const G1_GENERATOR_X: Fq = Fq::one();
+const G1_GENERATOR_Y: Fq = Fq::from_raw([2, 0, 0, 0]);
+const G1_B: Fq = Fq::from_raw([3, 0, 0, 0]);
+const ENDO_G1: [u64; 4] = [
+    0x7a7bd9d4391eb18du64,
+    0x4ccef014a773d2cfu64,
+    0x0000000000000002u64,
+    0u64,
+];
+const ENDO_G2: [u64; 4] = [0xd91d232ec7e0b3d7u64, 0x0000000000000002u64, 0u64, 0u64];
+const ENDO_MINUS_B1: [u64; 4] = [0x8211bbeb7d4f1128u64, 0x6f4d8248eeb859fcu64, 0u64, 0u64];
+const ENDO_B2: [u64; 4] = [0x89d3256894d213e3u64, 0u64, 0u64, 0u64];
+const ENDO_BETA: Fr = Fr::from_raw([
+    0x8b17ea66b99c90ddu64,
+    0x5bfc41088d8daaa7u64,
+    0xb3c4d79d41a91758u64,
+    0x0u64,
+]);
+
+const G2_B: Fq2 = Fq2 {
+    c0: Fq::from_raw([
+        0x3267e6dc24a138e5,
+        0xb5b4c5e559dbefa3,
+        0x81be18991be06ac3,
+        0x2b149d40ceb8aaae,
+    ]),
+    c1: Fq::from_raw([
+        0xe4a2bd0685c315d2,
+        0xa74fa084e52d1852,
+        0xcd2cafadeed8fdf4,
+        0x009713b03af0fed4,
+    ]),
+};
+
+const G2_GENERATOR_X: Fq2 = Fq2 {
+    c0: Fq::from_raw([
+        0x46debd5cd992f6ed,
+        0x674322d4f75edadd,
+        0x426a00665e5c4479,
+        0x1800deef121f1e76,
+    ]),
+    c1: Fq::from_raw([
+        0x97e485b7aef312c2,
+        0xf1aa493335a9e712,
+        0x7260bfb731fb5d25,
+        0x198e9393920d483a,
+    ]),
+};
+
+const G2_GENERATOR_Y: Fq2 = Fq2 {
+    c0: Fq::from_raw([
+        0x4ce6cc0166fa7daa,
+        0xe3d1e7690c43d37b,
+        0x4aab71808dcb408f,
+        0x12c85ea5db8c6deb,
+    ]),
+
+    c1: Fq::from_raw([
+        0x55acdadcd122975b,
+        0xbc4b313370b38ef3,
+        0xec9e99ad690c3395,
+        0x090689d0585ff075,
+    ]),
+};
+
+trait CurveEndo: CurveExt {
+    fn endomorphism_base(&self) -> Self;
+    fn endomorphism_scalars(k: &Self::ScalarExt) -> (u128, u128);
+}
+
+impl CurveEndo for G1 {
+    fn endomorphism_base(&self) -> Self {
+        Self {
+            x: self.x * Self::Base::ZETA,
+            y: -self.y,
+            z: self.z,
+        }
+    }
+
+    fn endomorphism_scalars(k: &Self::ScalarExt) -> (u128, u128) {
+        #[cfg(feature = "asm")]
+        let input = Fr::montgomery_reduce(&[k.0[0], k.0[1], k.0[2], k.0[3], 0, 0, 0, 0]).0;
+
+        #[cfg(not(feature = "asm"))]
+        let input = Fr::montgomery_reduce(k.0[0], k.0[1], k.0[2], k.0[3], 0, 0, 0, 0).0;
+
+        let c1_512 = mul_512(ENDO_G2, input);
+        let c2_512 = mul_512(ENDO_G1, input);
+
+        let c1_hi = [c1_512[4], c1_512[5], c1_512[6], c1_512[7]];
+        let c2_hi = [c2_512[4], c2_512[5], c2_512[6], c2_512[7]];
+
+        let q1_512 = mul_512(c1_hi, ENDO_MINUS_B1);
+        let q2_512 = mul_512(c2_hi, ENDO_B2);
+
+        let q1_lo = Self::ScalarExt::from_raw([q1_512[0], q1_512[1], q1_512[2], q1_512[3]]);
+        let q2_lo = Self::ScalarExt::from_raw([q2_512[0], q2_512[1], q2_512[2], q2_512[3]]);
+
+        let k1 = q2_lo - q1_lo;
+        let k2 = (k1 * ENDO_BETA) + k;
+
+        (k2.get_lower_128(), k1.get_lower_128())
+    }
+}
+
+impl CurveEndo for G2 {
+    fn endomorphism_base(&self) -> Self {
+        unimplemented!();
+    }
+
+    fn endomorphism_scalars(_: &Self::ScalarExt) -> (u128, u128) {
+        unimplemented!();
+    }
+}
+
+impl group::cofactor::CofactorGroup for G1 {
+    type Subgroup = G1;
+
+    fn clear_cofactor(&self) -> Self {
+        *self
+    }
+
+    fn into_subgroup(self) -> CtOption<Self::Subgroup> {
+        CtOption::new(self, 1.into())
+    }
+
+    fn is_torsion_free(&self) -> Choice {
+        1.into()
+    }
+}
+
+impl CofactorGroup for G2 {
+    type Subgroup = G2;
+
+    fn clear_cofactor(&self) -> Self {
+        // "0x30644e72e131a029b85045b68181585e06ceecda572a2489345f2299c0f9fa8d"
+        let e: [u8; 32] = [
+            0x30, 0x64, 0x4e, 0x72, 0xe1, 0x31, 0xa0, 0x29, 0xb8, 0x50, 0x45, 0xb6, 0x81, 0x81,
+            0x58, 0x5e, 0x06, 0xce, 0xec, 0xda, 0x57, 0x2a, 0x24, 0x89, 0x34, 0x5f, 0x22, 0x99,
+            0xc0, 0xf9, 0xfa, 0x8d,
+        ];
+
+        // self * COFACTOR_G2
+        let mut acc = G2::identity();
+        for bit in e
+            .iter()
+            .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
+            .skip(1)
+        {
+            acc = acc.double();
+            acc = G2::conditional_select(&acc, &(acc + self), bit);
+        }
+        acc
+    }
+
+    fn into_subgroup(self) -> CtOption<Self::Subgroup> {
+        unimplemented!();
+    }
+
+    fn is_torsion_free(&self) -> Choice {
+        // "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"
+        let e: [u8; 32] = [
+            0x30, 0x64, 0x4e, 0x72, 0xe1, 0x31, 0xa0, 0x29, 0xb8, 0x50, 0x45, 0xb6, 0x81, 0x81,
+            0x58, 0x5d, 0x28, 0x33, 0xe8, 0x48, 0x79, 0xb9, 0x70, 0x91, 0x43, 0xe1, 0xf5, 0x93,
+            0xf0, 0x00, 0x00, 0x01,
+        ];
+
+        // self * GROUP_ORDER;
+
+        let mut acc = G2::identity();
+        for bit in e
+            .iter()
+            .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
+            .skip(1)
+        {
+            acc = acc.double();
+            acc = G2::conditional_select(&acc, &(acc + self), bit);
+        }
+        acc.is_identity()
+    }
+}
+
+#[cfg(test)]
+mod tests {
+
+    use crate::bn256::{
+        curve::{CurveEndo, ENDO_BETA},
+        Fr, G1Affine, G1, G2,
+    };
+    use ff::Field;
+    use rand_core::OsRng;
+
+    use crate::CurveExt;
+
+    #[test]
+    fn test_curve() {
+        crate::tests::curve::curve_tests::<G1>();
+        crate::tests::curve::curve_tests::<G2>();
+    }
+
+    #[test]
+    fn test_endo_consistency() {
+        let g = G1::generator();
+        assert_eq!(g * (-ENDO_BETA), g.endo());
+    }
+
+    #[test]
+    fn test_endomorphism() {
+        use crate::FieldExt;
+
+        let scalar = Fr::random(OsRng);
+        let point = G1Affine::random(OsRng);
+
+        let expected = point * scalar;
+
+        let (part1, part2) = G1::endomorphism_scalars(&scalar);
+
+        let k1 = Fr::from_u128(part1);
+        let k2 = Fr::from_u128(part2);
+
+        let t1 = point * k1;
+        let base = G1::endomorphism_base(&point.into());
+
+        let t2 = base * k2;
+        let result = t1 + t2;
+
+        let res_affine: G1Affine = result.into();
+        let exp_affine: G1Affine = expected.into();
+
+        assert_eq!(res_affine, exp_affine);
+    }
+
+    #[test]
+    fn test_serialization() {
+        crate::tests::curve::random_serialization_test::<G1>();
+        crate::tests::curve::random_serialization_test::<G2>();
+    }
+}
+
+impl group::UncompressedEncoding for G1Affine {
+    type Uncompressed = G1Compressed;
+
+    fn from_uncompressed(_: &Self::Uncompressed) -> CtOption<Self> {
+        unimplemented!();
+    }
+
+    fn from_uncompressed_unchecked(_: &Self::Uncompressed) -> CtOption<Self> {
+        unimplemented!();
+    }
+
+    fn to_uncompressed(&self) -> Self::Uncompressed {
+        unimplemented!();
+    }
+}
+
+impl group::UncompressedEncoding for G2Affine {
+    type Uncompressed = G2Compressed;
+
+    fn from_uncompressed(_: &Self::Uncompressed) -> CtOption<Self> {
+        unimplemented!();
+    }
+
+    fn from_uncompressed_unchecked(_: &Self::Uncompressed) -> CtOption<Self> {
+        unimplemented!();
+    }
+
+    fn to_uncompressed(&self) -> Self::Uncompressed {
+        unimplemented!();
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/bn256/engine.rs.html b/docs/src/halo2curves/bn256/engine.rs.html new file mode 100644 index 0000000000..268f6b1074 --- /dev/null +++ b/docs/src/halo2curves/bn256/engine.rs.html @@ -0,0 +1,1678 @@ +engine.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+
#![allow(clippy::suspicious_arithmetic_impl)]
+use crate::bn256::curve::*;
+use crate::bn256::fq::*;
+use crate::bn256::fq12::*;
+use crate::bn256::fq2::*;
+use crate::bn256::fq6::FROBENIUS_COEFF_FQ6_C1;
+use crate::bn256::fr::*;
+use crate::pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine};
+use core::borrow::Borrow;
+use core::iter::Sum;
+use core::ops::{Add, Mul, MulAssign, Neg, Sub};
+use ff::{Field, PrimeField};
+use group::cofactor::CofactorCurveAffine;
+use group::Group;
+use rand_core::RngCore;
+use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
+
+pub const BN_X: u64 = 4965661367192848881;
+
+// 6U+2 for in NAF form
+pub const SIX_U_PLUS_2_NAF: [i8; 65] = [
+    0, 0, 0, 1, 0, 1, 0, -1, 0, 0, 1, -1, 0, 0, 1, 0, 0, 1, 1, 0, -1, 0, 0, 1, 0, -1, 0, 0, 0, 0,
+    1, 1, 1, 0, 0, -1, 0, 0, 1, 0, 0, 0, 0, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, 0, 0, 1, 1, 0, -1, 0,
+    0, 1, 0, 1, 1,
+];
+
+pub const XI_TO_Q_MINUS_1_OVER_2: Fq2 = Fq2 {
+    c0: Fq([
+        0xe4bbdd0c2936b629,
+        0xbb30f162e133bacb,
+        0x31a9d1b6f9645366,
+        0x253570bea500f8dd,
+    ]),
+    c1: Fq([
+        0xa1d77ce45ffe77c7,
+        0x07affd117826d1db,
+        0x6d16bd27bb7edc6b,
+        0x2c87200285defecc,
+    ]),
+};
+
+impl PairingCurveAffine for G1Affine {
+    type Pair = G2Affine;
+    type PairingResult = Gt;
+
+    fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
+        pairing(self, other)
+    }
+}
+
+impl PairingCurveAffine for G2Affine {
+    type Pair = G1Affine;
+    type PairingResult = Gt;
+
+    fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult {
+        pairing(other, self)
+    }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+pub struct Gt(pub(crate) Fq12);
+
+impl std::fmt::Display for Gt {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(f, "{self:?}")
+    }
+}
+
+impl ConstantTimeEq for Gt {
+    fn ct_eq(&self, other: &Self) -> Choice {
+        self.0.ct_eq(&other.0)
+    }
+}
+
+impl ConditionallySelectable for Gt {
+    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
+        Gt(Fq12::conditional_select(&a.0, &b.0, choice))
+    }
+}
+
+impl Eq for Gt {}
+impl PartialEq for Gt {
+    #[inline]
+    fn eq(&self, other: &Self) -> bool {
+        bool::from(self.ct_eq(other))
+    }
+}
+
+impl Gt {
+    /// Returns the group identity, which is $1$.
+    pub fn identity() -> Gt {
+        Gt(Fq12::one())
+    }
+
+    /// Doubles this group element.
+    pub fn double(&self) -> Gt {
+        Gt(self.0.square())
+    }
+}
+
+impl<'a> Neg for &'a Gt {
+    type Output = Gt;
+
+    #[inline]
+    fn neg(self) -> Gt {
+        // The element is unitary, so we just conjugate.
+        let mut u = self.0;
+        u.conjugate();
+        Gt(u)
+    }
+}
+
+impl Neg for Gt {
+    type Output = Gt;
+
+    #[inline]
+    fn neg(self) -> Gt {
+        -&self
+    }
+}
+
+impl<'a, 'b> Add<&'b Gt> for &'a Gt {
+    type Output = Gt;
+
+    #[inline]
+    fn add(self, rhs: &'b Gt) -> Gt {
+        Gt(self.0 * rhs.0)
+    }
+}
+
+impl<'a, 'b> Sub<&'b Gt> for &'a Gt {
+    type Output = Gt;
+
+    #[inline]
+    fn sub(self, rhs: &'b Gt) -> Gt {
+        self + (-rhs)
+    }
+}
+
+impl<'a, 'b> Mul<&'b Fr> for &'a Gt {
+    type Output = Gt;
+
+    fn mul(self, other: &'b Fr) -> Self::Output {
+        let mut acc = Gt::identity();
+
+        for bit in other
+            .to_repr()
+            .iter()
+            .rev()
+            .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
+            .skip(1)
+        {
+            acc = acc.double();
+            acc = Gt::conditional_select(&acc, &(acc + self), bit);
+        }
+
+        acc
+    }
+}
+
+use crate::{
+    impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output,
+    impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
+};
+impl_binops_additive!(Gt, Gt);
+impl_binops_multiplicative!(Gt, Fr);
+
+impl<T> Sum<T> for Gt
+where
+    T: Borrow<Gt>,
+{
+    fn sum<I>(iter: I) -> Self
+    where
+        I: Iterator<Item = T>,
+    {
+        iter.fold(Self::identity(), |acc, item| acc + item.borrow())
+    }
+}
+
+impl Group for Gt {
+    type Scalar = Fr;
+
+    fn random(_: impl RngCore) -> Self {
+        unimplemented!();
+    }
+
+    fn identity() -> Self {
+        Self::identity()
+    }
+
+    fn generator() -> Self {
+        unimplemented!();
+    }
+
+    fn is_identity(&self) -> Choice {
+        self.ct_eq(&Self::identity())
+    }
+
+    #[must_use]
+    fn double(&self) -> Self {
+        self.double()
+    }
+}
+
+#[derive(Clone, Debug)]
+pub struct G2Prepared {
+    pub(crate) coeffs: Vec<(Fq2, Fq2, Fq2)>,
+    pub(crate) infinity: bool,
+}
+
+impl G2Prepared {
+    pub fn is_zero(&self) -> bool {
+        self.infinity
+    }
+
+    pub fn from_affine(q: G2Affine) -> Self {
+        if bool::from(q.is_identity()) {
+            return G2Prepared {
+                coeffs: vec![],
+                infinity: true,
+            };
+        }
+
+        fn doubling_step(r: &mut G2) -> (Fq2, Fq2, Fq2) {
+            // Adaptation of Algorithm 26, https://eprint.iacr.org/2010/354.pdf
+            let mut tmp0 = r.x;
+            tmp0.square_assign();
+
+            let mut tmp1 = r.y;
+            tmp1.square_assign();
+
+            let mut tmp2 = tmp1;
+            tmp2.square_assign();
+
+            let mut tmp3 = tmp1;
+            tmp3 += &r.x;
+            tmp3.square_assign();
+            tmp3 -= &tmp0;
+            tmp3 -= &tmp2;
+            tmp3.double_assign();
+
+            let mut tmp4 = tmp0;
+            tmp4.double_assign();
+            tmp4 += &tmp0;
+
+            let mut tmp6 = r.x;
+            tmp6 += &tmp4;
+
+            let mut tmp5 = tmp4;
+            tmp5.square_assign();
+
+            let mut zsquared = r.z;
+            zsquared.square_assign();
+
+            r.x = tmp5;
+            r.x -= &tmp3;
+            r.x -= &tmp3;
+
+            r.z += &r.y;
+            r.z.square_assign();
+            r.z -= &tmp1;
+            r.z -= &zsquared;
+
+            r.y = tmp3;
+            r.y -= &r.x;
+            r.y.mul_assign(&tmp4);
+
+            tmp2.double_assign();
+            tmp2.double_assign();
+            tmp2.double_assign();
+
+            r.y -= &tmp2;
+
+            // up to here everything was by algorith, line 11
+            // use R instead of new T
+
+            // tmp3 is the first part of line 12
+            tmp3 = tmp4;
+            tmp3.mul_assign(&zsquared);
+            tmp3.double_assign();
+            tmp3 = tmp3.neg();
+
+            // tmp6 is from line 14
+            tmp6.square_assign();
+            tmp6 -= &tmp0;
+            tmp6 -= &tmp5;
+
+            tmp1.double_assign();
+            tmp1.double_assign();
+
+            tmp6 -= &tmp1;
+
+            // tmp0 is the first part of line 16
+            tmp0 = r.z;
+            tmp0.mul_assign(&zsquared);
+            tmp0.double_assign();
+
+            (tmp0, tmp3, tmp6)
+        }
+
+        fn addition_step(r: &mut G2, q: &G2Affine) -> (Fq2, Fq2, Fq2) {
+            // Adaptation of Algorithm 27, https://eprint.iacr.org/2010/354.pdf
+            let mut zsquared = r.z;
+            zsquared.square_assign();
+
+            let mut ysquared = q.y;
+            ysquared.square_assign();
+
+            // t0 corresponds to line 1
+            let mut t0 = zsquared;
+            t0.mul_assign(&q.x);
+
+            // t1 corresponds to lines 2 and 3
+            let mut t1 = q.y;
+            t1 += &r.z;
+            t1.square_assign();
+            t1 -= &ysquared;
+            t1 -= &zsquared;
+            t1.mul_assign(&zsquared);
+
+            // t2 corresponds to line 4
+            let mut t2 = t0;
+            t2 -= &r.x;
+
+            // t3 corresponds to line 5
+            let mut t3 = t2;
+            t3.square_assign();
+
+            // t4 corresponds to line 6
+            let mut t4 = t3;
+            t4.double_assign();
+            t4.double_assign();
+
+            // t5 corresponds to line 7
+            let mut t5 = t4;
+            t5.mul_assign(&t2);
+
+            // t6 corresponds to line 8
+            let mut t6 = t1;
+            t6 -= &r.y;
+            t6 -= &r.y;
+
+            // t9 corresponds to line 9
+            let mut t9 = t6;
+            t9.mul_assign(&q.x);
+
+            // corresponds to line 10
+            let mut t7 = t4;
+            t7.mul_assign(&r.x);
+
+            // corresponds to line 11, but assigns to r.x instead of T.x
+            r.x = t6;
+            r.x.square_assign();
+            r.x -= &t5;
+            r.x -= &t7;
+            r.x -= &t7;
+
+            // corresponds to line 12, but assigns to r.z instead of T.z
+            r.z += &t2;
+            r.z.square_assign();
+            r.z -= &zsquared;
+            r.z -= &t3;
+
+            // corresponds to line 13
+            let mut t10 = q.y;
+            t10 += &r.z;
+
+            // corresponds to line 14
+            let mut t8 = t7;
+            t8 -= &r.x;
+            t8.mul_assign(&t6);
+
+            // corresponds to line 15
+            t0 = r.y;
+            t0.mul_assign(&t5);
+            t0.double_assign();
+
+            // corresponds to line 12, but assigns to r.y instead of T.y
+            r.y = t8;
+            r.y -= &t0;
+
+            // corresponds to line 17
+            t10.square_assign();
+            t10 -= &ysquared;
+
+            let mut ztsquared = r.z;
+            ztsquared.square_assign();
+
+            t10 -= &ztsquared;
+
+            // corresponds to line 18
+            t9.double_assign();
+            t9 -= &t10;
+
+            // t10 = 2*Zt from Algo 27, line 19
+            t10 = r.z;
+            t10.double_assign();
+
+            // t1 = first multiplicator of line 21
+            t6 = t6.neg();
+
+            t1 = t6;
+            t1.double_assign();
+
+            // t9 corresponds to t9 from Algo 27
+            (t10, t1, t9)
+        }
+
+        let mut coeffs = vec![];
+        let mut r: G2 = q.into();
+
+        let mut negq = q;
+        negq = -negq;
+
+        for i in (1..SIX_U_PLUS_2_NAF.len()).rev() {
+            coeffs.push(doubling_step(&mut r));
+            let x = SIX_U_PLUS_2_NAF[i - 1];
+            match x {
+                1 => {
+                    coeffs.push(addition_step(&mut r, &q));
+                }
+                -1 => {
+                    coeffs.push(addition_step(&mut r, &negq));
+                }
+                _ => continue,
+            }
+        }
+
+        let mut q1 = q;
+
+        q1.x.c1 = q1.x.c1.neg();
+        q1.x.mul_assign(&FROBENIUS_COEFF_FQ6_C1[1]);
+
+        q1.y.c1 = q1.y.c1.neg();
+        q1.y.mul_assign(&XI_TO_Q_MINUS_1_OVER_2);
+
+        coeffs.push(addition_step(&mut r, &q1));
+
+        let mut minusq2 = q;
+        minusq2.x.mul_assign(&FROBENIUS_COEFF_FQ6_C1[2]);
+
+        coeffs.push(addition_step(&mut r, &minusq2));
+
+        G2Prepared {
+            coeffs,
+            infinity: false,
+        }
+    }
+}
+
+impl From<G2Affine> for G2Prepared {
+    fn from(q: G2Affine) -> G2Prepared {
+        G2Prepared::from_affine(q)
+    }
+}
+
+impl MillerLoopResult for Gt {
+    type Gt = Self;
+    // pub fn final_exponentiation(r: &Fq12) -> CtOption<Fq12> {
+    fn final_exponentiation(&self) -> Gt {
+        fn exp_by_x(f: &mut Fq12) {
+            let x = BN_X;
+            let mut res = Fq12::one();
+            for i in (0..64).rev() {
+                res.cyclotomic_square();
+                if ((x >> i) & 1) == 1 {
+                    res.mul_assign(f);
+                }
+            }
+            *f = res;
+        }
+
+        let r = self.0;
+        let mut f1 = self.0;
+        f1.conjugate();
+
+        Gt(r.invert()
+            .map(|mut f2| {
+                let mut r = f1;
+                r.mul_assign(&f2);
+                f2 = r;
+                r.frobenius_map(2);
+                r.mul_assign(&f2);
+
+                let mut fp = r;
+                fp.frobenius_map(1);
+
+                let mut fp2 = r;
+                fp2.frobenius_map(2);
+                let mut fp3 = fp2;
+                fp3.frobenius_map(1);
+
+                let mut fu = r;
+                exp_by_x(&mut fu);
+
+                let mut fu2 = fu;
+                exp_by_x(&mut fu2);
+
+                let mut fu3 = fu2;
+                exp_by_x(&mut fu3);
+
+                let mut y3 = fu;
+                y3.frobenius_map(1);
+
+                let mut fu2p = fu2;
+                fu2p.frobenius_map(1);
+
+                let mut fu3p = fu3;
+                fu3p.frobenius_map(1);
+
+                let mut y2 = fu2;
+                y2.frobenius_map(2);
+
+                let mut y0 = fp;
+                y0.mul_assign(&fp2);
+                y0.mul_assign(&fp3);
+
+                let mut y1 = r;
+                y1.conjugate();
+
+                let mut y5 = fu2;
+                y5.conjugate();
+
+                y3.conjugate();
+
+                let mut y4 = fu;
+                y4.mul_assign(&fu2p);
+                y4.conjugate();
+
+                let mut y6 = fu3;
+                y6.mul_assign(&fu3p);
+                y6.conjugate();
+
+                y6.cyclotomic_square();
+                y6.mul_assign(&y4);
+                y6.mul_assign(&y5);
+
+                let mut t1 = y3;
+                t1.mul_assign(&y5);
+                t1.mul_assign(&y6);
+
+                y6.mul_assign(&y2);
+
+                t1.cyclotomic_square();
+                t1.mul_assign(&y6);
+                t1.cyclotomic_square();
+
+                let mut t0 = t1;
+                t0.mul_assign(&y1);
+
+                t1.mul_assign(&y0);
+
+                t0.cyclotomic_square();
+                t0.mul_assign(&t1);
+
+                t0
+            })
+            .unwrap())
+    }
+}
+
+pub fn multi_miller_loop(terms: &[(&G1Affine, &G2Prepared)]) -> Gt {
+    let mut pairs = vec![];
+    for &(p, q) in terms {
+        if !bool::from(p.is_identity()) && !q.is_zero() {
+            pairs.push((p, q.coeffs.iter()));
+        }
+    }
+
+    // Final steps of the line function on prepared coefficients
+    fn ell(f: &mut Fq12, coeffs: &(Fq2, Fq2, Fq2), p: &G1Affine) {
+        let mut c0 = coeffs.0;
+        let mut c1 = coeffs.1;
+
+        c0.c0.mul_assign(&p.y);
+        c0.c1.mul_assign(&p.y);
+
+        c1.c0.mul_assign(&p.x);
+        c1.c1.mul_assign(&p.x);
+
+        // Sparse multiplication in Fq12
+        f.mul_by_034(&c0, &c1, &coeffs.2);
+    }
+
+    let mut f = Fq12::one();
+
+    for i in (1..SIX_U_PLUS_2_NAF.len()).rev() {
+        if i != SIX_U_PLUS_2_NAF.len() - 1 {
+            f.square_assign();
+        }
+        for &mut (p, ref mut coeffs) in &mut pairs {
+            ell(&mut f, coeffs.next().unwrap(), p);
+        }
+        let x = SIX_U_PLUS_2_NAF[i - 1];
+        match x {
+            1 => {
+                for &mut (p, ref mut coeffs) in &mut pairs {
+                    ell(&mut f, coeffs.next().unwrap(), p);
+                }
+            }
+            -1 => {
+                for &mut (p, ref mut coeffs) in &mut pairs {
+                    ell(&mut f, coeffs.next().unwrap(), p);
+                }
+            }
+            _ => continue,
+        }
+    }
+
+    for &mut (p, ref mut coeffs) in &mut pairs {
+        ell(&mut f, coeffs.next().unwrap(), p);
+    }
+
+    for &mut (p, ref mut coeffs) in &mut pairs {
+        ell(&mut f, coeffs.next().unwrap(), p);
+    }
+
+    for &mut (_p, ref mut coeffs) in &mut pairs {
+        assert_eq!(coeffs.next(), None);
+    }
+
+    Gt(f)
+}
+
+pub fn pairing(g1: &G1Affine, g2: &G2Affine) -> Gt {
+    let g2 = G2Prepared::from_affine(*g2);
+    let terms: &[(&G1Affine, &G2Prepared)] = &[(g1, &g2)];
+    let u = multi_miller_loop(terms);
+    u.final_exponentiation()
+}
+
+#[derive(Clone, Debug)]
+pub struct Bn256;
+
+impl Engine for Bn256 {
+    type Scalar = Fr;
+    type G1 = G1;
+    type G1Affine = G1Affine;
+    type G2 = G2;
+    type G2Affine = G2Affine;
+    type Gt = Gt;
+
+    fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt {
+        pairing(p, q)
+    }
+}
+
+impl MultiMillerLoop for Bn256 {
+    type G2Prepared = G2Prepared;
+    type Result = Gt;
+
+    fn multi_miller_loop(terms: &[(&Self::G1Affine, &Self::G2Prepared)]) -> Self::Result {
+        multi_miller_loop(terms)
+    }
+}
+
+#[cfg(test)]
+use rand::SeedableRng;
+#[cfg(test)]
+use rand_xorshift::XorShiftRng;
+
+#[test]
+fn test_pairing() {
+    let g1 = G1::generator();
+    let mut g2 = G2::generator();
+    g2 = g2.double();
+    let pair12 = Bn256::pairing(&G1Affine::from(g1), &G2Affine::from(g2));
+
+    let mut g1 = G1::generator();
+    let g2 = G2::generator();
+    g1 = g1.double();
+    let pair21 = Bn256::pairing(&G1Affine::from(g1), &G2Affine::from(g2));
+
+    assert_eq!(pair12, pair21);
+
+    let g1 = G1::generator();
+    let mut g2 = G2::generator();
+    g2 = g2.double().double();
+    let pair12 = Bn256::pairing(&G1Affine::from(g1), &G2Affine::from(g2));
+
+    let mut g1 = G1::generator();
+    let mut g2 = G2::generator();
+    g1 = g1.double();
+    g2 = g2.double();
+    let pair21 = Bn256::pairing(&G1Affine::from(g1), &G2Affine::from(g2));
+
+    assert_eq!(pair12, pair21);
+
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+    for _ in 0..1000 {
+        let a = Fr::random(&mut rng);
+        let b = Fr::random(&mut rng);
+
+        let mut g1 = G1::generator();
+        g1.mul_assign(a);
+
+        let mut g2 = G2::generator();
+        g1.mul_assign(b);
+
+        let pair_ab = Bn256::pairing(&G1Affine::from(g1), &G2Affine::from(g2));
+
+        g1 = G1::generator();
+        g1.mul_assign(b);
+
+        g2 = G2::generator();
+        g1.mul_assign(a);
+
+        let pair_ba = Bn256::pairing(&G1Affine::from(g1), &G2Affine::from(g2));
+
+        assert_eq!(pair_ab, pair_ba);
+    }
+}
+
+#[test]
+fn random_bilinearity_tests() {
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+
+    for _ in 0..1000 {
+        let mut a = G1::generator();
+        let ka = Fr::random(&mut rng);
+        a.mul_assign(ka);
+
+        let mut b = G2::generator();
+        let kb = Fr::random(&mut rng);
+        b.mul_assign(kb);
+
+        let c = Fr::random(&mut rng);
+        let d = Fr::random(&mut rng);
+
+        let mut ac = a;
+        ac.mul_assign(c);
+
+        let mut ad = a;
+        ad.mul_assign(d);
+
+        let mut bc = b;
+        bc.mul_assign(c);
+
+        let mut bd = b;
+        bd.mul_assign(d);
+
+        let acbd = Bn256::pairing(&G1Affine::from(ac), &G2Affine::from(bd));
+        let adbc = Bn256::pairing(&G1Affine::from(ad), &G2Affine::from(bc));
+
+        let mut cd = c;
+        cd.mul_assign(&d);
+
+        cd *= Fr([1, 0, 0, 0]);
+
+        let abcd = Gt(Bn256::pairing(&G1Affine::from(a), &G2Affine::from(b))
+            .0
+            .pow_vartime(cd.0));
+
+        assert_eq!(acbd, adbc);
+        assert_eq!(acbd, abcd);
+    }
+}
+
+#[test]
+pub fn engine_tests() {
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+
+    for _ in 0..10 {
+        let a = G1Affine::from(G1::random(&mut rng));
+        let b = G2Affine::from(G2::random(&mut rng));
+
+        assert!(a.pairing_with(&b) == b.pairing_with(&a));
+        assert!(a.pairing_with(&b) == pairing(&a, &b));
+    }
+
+    for _ in 0..1000 {
+        let z1 = G1Affine::identity();
+        let z2 = G2Prepared::from(G2Affine::identity());
+
+        let a = G1Affine::from(G1::random(&mut rng));
+        let b = G2Prepared::from(G2Affine::from(G2::random(&mut rng)));
+        let c = G1Affine::from(G1::random(&mut rng));
+        let d = G2Prepared::from(G2Affine::from(G2::random(&mut rng)));
+
+        assert_eq!(
+            Fq12::one(),
+            multi_miller_loop(&[(&z1, &b)]).final_exponentiation().0,
+        );
+
+        assert_eq!(
+            Fq12::one(),
+            multi_miller_loop(&[(&a, &z2)]).final_exponentiation().0,
+        );
+
+        assert_eq!(
+            multi_miller_loop(&[(&z1, &b), (&c, &d)]).final_exponentiation(),
+            multi_miller_loop(&[(&a, &z2), (&c, &d)]).final_exponentiation(),
+        );
+
+        assert_eq!(
+            multi_miller_loop(&[(&a, &b), (&z1, &d)]).final_exponentiation(),
+            multi_miller_loop(&[(&a, &b), (&c, &z2)]).final_exponentiation(),
+        );
+    }
+}
+
+#[test]
+fn random_miller_loop_tests() {
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+
+    // Exercise a double miller loop
+    for _ in 0..1000 {
+        let a = G1Affine::from(G1::random(&mut rng));
+        let b = G2Affine::from(G2::random(&mut rng));
+        let c = G1Affine::from(G1::random(&mut rng));
+        let d = G2Affine::from(G2::random(&mut rng));
+
+        let ab = pairing(&a, &b);
+        let cd = pairing(&c, &d);
+
+        let mut abcd = ab;
+        abcd = Gt(abcd.0 * cd.0);
+
+        let b = G2Prepared::from(b);
+        let d = G2Prepared::from(d);
+
+        let abcd_with_double_loop = multi_miller_loop(&[(&a, &b), (&c, &d)]).final_exponentiation();
+
+        assert_eq!(abcd, abcd_with_double_loop);
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/bn256/fq.rs.html b/docs/src/halo2curves/bn256/fq.rs.html new file mode 100644 index 0000000000..8e6f0d5a57 --- /dev/null +++ b/docs/src/halo2curves/bn256/fq.rs.html @@ -0,0 +1,726 @@ +fq.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+
#[cfg(feature = "asm")]
+use super::assembly::assembly_field;
+
+use super::LegendreSymbol;
+use crate::arithmetic::{adc, mac, macx, sbb};
+use pasta_curves::arithmetic::{FieldExt, Group, SqrtRatio};
+use serde::{Deserialize, Serialize};
+
+use core::convert::TryInto;
+use core::fmt;
+use core::ops::{Add, Mul, Neg, Sub};
+use ff::PrimeField;
+use rand::RngCore;
+use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
+
+/// This represents an element of $\mathbb{F}_q$ where
+///
+/// `p = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47`
+///
+/// is the base field of the BN254 curve.
+// The internal representation of this type is four 64-bit unsigned
+// integers in little-endian order. `Fq` values are always in
+// Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256.
+#[derive(Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
+pub struct Fq(pub(crate) [u64; 4]);
+
+/// Constant representing the modulus
+/// q = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47
+pub const MODULUS: Fq = Fq([
+    0x3c208c16d87cfd47,
+    0x97816a916871ca8d,
+    0xb85045b68181585d,
+    0x30644e72e131a029,
+]);
+
+/// INV = -(q^{-1} mod 2^64) mod 2^64
+const INV: u64 = 0x87d20782e4866389;
+
+/// R = 2^256 mod q
+const R: Fq = Fq([
+    0xd35d438dc58f0d9d,
+    0x0a78eb28f5c70b3d,
+    0x666ea36f7879462c,
+    0x0e0a77c19a07df2f,
+]);
+
+/// R^2 = 2^512 mod q
+const R2: Fq = Fq([
+    0xf32cfc5b538afa89,
+    0xb5e71911d44501fb,
+    0x47ab1eff0a417ff6,
+    0x06d89f71cab8351f,
+]);
+
+/// R^3 = 2^768 mod q
+const R3: Fq = Fq([
+    0xb1cd6dafda1530df,
+    0x62f210e6a7283db6,
+    0xef7f0b0c0ada0afb,
+    0x20fd6e902d592544,
+]);
+
+pub const NEGATIVE_ONE: Fq = Fq([
+    0x68c3488912edefaa,
+    0x8d087f6872aabf4f,
+    0x51e1a24709081231,
+    0x2259d6b14729c0fa,
+]);
+
+const MODULUS_STR: &str = "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47";
+
+const TWO_INV: Fq = Fq::from_raw([
+    0x9e10460b6c3e7ea4,
+    0xcbc0b548b438e546,
+    0xdc2822db40c0ac2e,
+    0x183227397098d014,
+]);
+
+// Unused constant for base field
+const ROOT_OF_UNITY_INV: Fq = Fq::zero();
+
+// Unused constant for base field
+const DELTA: Fq = Fq::zero();
+
+/// `ZETA^3 = 1 mod r` where `ZETA^2 != 1 mod r`
+const ZETA: Fq = Fq::from_raw([
+    0x5763473177fffffeu64,
+    0xd4f263f1acdb5c4fu64,
+    0x59e26bcea0d48bacu64,
+    0x0u64,
+]);
+
+use crate::{
+    field_arithmetic, field_common, field_specific, impl_add_binop_specify_output,
+    impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative,
+    impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
+};
+impl_binops_additive!(Fq, Fq);
+impl_binops_multiplicative!(Fq, Fq);
+#[cfg(not(feature = "asm"))]
+field_common!(
+    Fq,
+    MODULUS,
+    INV,
+    MODULUS_STR,
+    TWO_INV,
+    ROOT_OF_UNITY_INV,
+    DELTA,
+    ZETA,
+    R,
+    R2,
+    R3
+);
+#[cfg(not(feature = "asm"))]
+field_arithmetic!(Fq, MODULUS, INV, sparse);
+#[cfg(feature = "asm")]
+assembly_field!(
+    Fq,
+    MODULUS,
+    INV,
+    MODULUS_STR,
+    TWO_INV,
+    ROOT_OF_UNITY_INV,
+    DELTA,
+    ZETA,
+    R,
+    R2,
+    R3
+);
+
+impl Fq {
+    pub const fn size() -> usize {
+        32
+    }
+
+    pub fn legendre(&self) -> LegendreSymbol {
+        // s = self^((modulus - 1) // 2)
+        // 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3
+        let s = &[
+            0x9e10460b6c3e7ea3u64,
+            0xcbc0b548b438e546u64,
+            0xdc2822db40c0ac2eu64,
+            0x183227397098d014u64,
+        ];
+        let s = self.pow(s);
+        if s == Self::zero() {
+            LegendreSymbol::Zero
+        } else if s == Self::one() {
+            LegendreSymbol::QuadraticResidue
+        } else {
+            LegendreSymbol::QuadraticNonResidue
+        }
+    }
+}
+
+impl ff::Field for Fq {
+    fn random(mut rng: impl RngCore) -> Self {
+        let mut random_bytes = [0; 64];
+        rng.fill_bytes(&mut random_bytes[..]);
+
+        Self::from_bytes_wide(&random_bytes)
+    }
+
+    #[inline(always)]
+    fn zero() -> Self {
+        Self::zero()
+    }
+
+    #[inline(always)]
+    fn one() -> Self {
+        Self::one()
+    }
+
+    fn double(&self) -> Self {
+        self.double()
+    }
+
+    #[inline(always)]
+    fn square(&self) -> Self {
+        self.square()
+    }
+
+    /// Computes the square root of this element, if it exists.
+    fn sqrt(&self) -> CtOption<Self> {
+        let tmp = self.pow(&[
+            0x4f082305b61f3f52,
+            0x65e05aa45a1c72a3,
+            0x6e14116da0605617,
+            0x0c19139cb84c680a,
+        ]);
+
+        CtOption::new(tmp, tmp.square().ct_eq(self))
+    }
+
+    /// Computes the multiplicative inverse of this element,
+    /// failing if the element is zero.
+    fn invert(&self) -> CtOption<Self> {
+        let tmp = self.pow(&[
+            0x3c208c16d87cfd45,
+            0x97816a916871ca8d,
+            0xb85045b68181585d,
+            0x30644e72e131a029,
+        ]);
+
+        CtOption::new(tmp, !self.ct_eq(&Self::zero()))
+    }
+}
+
+impl ff::PrimeField for Fq {
+    type Repr = [u8; 32];
+
+    const NUM_BITS: u32 = 254;
+    const CAPACITY: u32 = 253;
+
+    const S: u32 = 0;
+
+    fn from_repr(repr: Self::Repr) -> CtOption<Self> {
+        let mut tmp = Fq([0, 0, 0, 0]);
+
+        tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap());
+        tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap());
+        tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap());
+        tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap());
+
+        // Try to subtract the modulus
+        let (_, borrow) = tmp.0[0].overflowing_sub(MODULUS.0[0]);
+        let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow);
+        let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow);
+        let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow);
+
+        // If the element is smaller than MODULUS then the
+        // subtraction will underflow, producing a borrow value
+        // of 0xffff...ffff. Otherwise, it'll be zero.
+        let is_some = (borrow as u8) & 1;
+
+        // Convert to Montgomery form by computing
+        // (a.R^0 * R^2) / R = a.R
+        tmp *= &R2;
+
+        CtOption::new(tmp, Choice::from(is_some))
+    }
+
+    fn to_repr(&self) -> Self::Repr {
+        // Turn into canonical form by computing
+        // (a.R) / R = a
+        #[cfg(feature = "asm")]
+        let tmp =
+            Self::montgomery_reduce(&[self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0]);
+
+        #[cfg(not(feature = "asm"))]
+        let tmp = Self::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]);
+
+        let mut res = [0; 32];
+        res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes());
+        res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes());
+        res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes());
+        res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes());
+
+        res
+    }
+
+    fn is_odd(&self) -> Choice {
+        Choice::from(self.to_repr()[0] & 1)
+    }
+
+    fn multiplicative_generator() -> Self {
+        unimplemented!()
+    }
+
+    fn root_of_unity() -> Self {
+        unimplemented!()
+    }
+}
+
+impl SqrtRatio for Fq {
+    const T_MINUS1_OVER2: [u64; 4] = [0, 0, 0, 0];
+
+    fn get_lower_32(&self) -> u32 {
+        #[cfg(not(feature = "asm"))]
+        let tmp = Fq::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]);
+
+        #[cfg(feature = "asm")]
+        let tmp = Fq::montgomery_reduce(&[self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0]);
+
+        tmp.0[0] as u32
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use ff::Field;
+    use rand_core::OsRng;
+
+    #[test]
+    fn test_sqrt_fq() {
+        let v = (Fq::TWO_INV).square().sqrt().unwrap();
+        assert!(v == Fq::TWO_INV || (-v) == Fq::TWO_INV);
+
+        for _ in 0..10000 {
+            let a = Fq::random(OsRng);
+            let mut b = a;
+            b = b.square();
+            assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue);
+
+            let b = b.sqrt().unwrap();
+            let mut negb = b;
+            negb = negb.neg();
+
+            assert!(a == b || a == negb);
+        }
+
+        let mut c = Fq::one();
+        for _ in 0..10000 {
+            let mut b = c;
+            b = b.square();
+            assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue);
+
+            b = b.sqrt().unwrap();
+
+            if b != c {
+                b = b.neg();
+            }
+
+            assert_eq!(b, c);
+
+            c += &Fq::one();
+        }
+    }
+
+    #[test]
+    fn test_from_u512() {
+        assert_eq!(
+            Fq::from_raw([
+                0x1f8905a172affa8a,
+                0xde45ad177dcf3306,
+                0xaaa7987907d73ae2,
+                0x24d349431d468e30,
+            ]),
+            Fq::from_u512([
+                0xaaaaaaaaaaaaaaaa,
+                0xaaaaaaaaaaaaaaaa,
+                0xaaaaaaaaaaaaaaaa,
+                0xaaaaaaaaaaaaaaaa,
+                0xaaaaaaaaaaaaaaaa,
+                0xaaaaaaaaaaaaaaaa,
+                0xaaaaaaaaaaaaaaaa,
+                0xaaaaaaaaaaaaaaaa
+            ])
+        );
+    }
+
+    #[test]
+    fn test_field() {
+        crate::tests::field::random_field_tests::<Fq>("fq".to_string());
+    }
+
+    #[test]
+    fn test_serialization() {
+        crate::tests::field::random_serialization_test::<Fq>("fq".to_string());
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/bn256/fq12.rs.html b/docs/src/halo2curves/bn256/fq12.rs.html new file mode 100644 index 0000000000..7991ef5f35 --- /dev/null +++ b/docs/src/halo2curves/bn256/fq12.rs.html @@ -0,0 +1,1186 @@ +fq12.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+
use super::fq::Fq;
+use super::fq2::Fq2;
+use super::fq6::Fq6;
+use core::ops::{Add, Mul, Neg, Sub};
+use ff::Field;
+use rand::RngCore;
+use serde::{Deserialize, Serialize};
+use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Hash, Serialize, Deserialize)]
+pub struct Fq12 {
+    pub c0: Fq6,
+    pub c1: Fq6,
+}
+
+impl ConditionallySelectable for Fq12 {
+    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
+        Fq12 {
+            c0: Fq6::conditional_select(&a.c0, &b.c0, choice),
+            c1: Fq6::conditional_select(&a.c1, &b.c1, choice),
+        }
+    }
+}
+
+impl ConstantTimeEq for Fq12 {
+    fn ct_eq(&self, other: &Self) -> Choice {
+        self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1)
+    }
+}
+
+impl Neg for Fq12 {
+    type Output = Fq12;
+
+    #[inline]
+    fn neg(self) -> Fq12 {
+        -&self
+    }
+}
+
+impl<'a> Neg for &'a Fq12 {
+    type Output = Fq12;
+
+    #[inline]
+    fn neg(self) -> Fq12 {
+        self.neg()
+    }
+}
+
+impl<'a, 'b> Sub<&'b Fq12> for &'a Fq12 {
+    type Output = Fq12;
+
+    #[inline]
+    fn sub(self, rhs: &'b Fq12) -> Fq12 {
+        self.sub(rhs)
+    }
+}
+
+impl<'a, 'b> Add<&'b Fq12> for &'a Fq12 {
+    type Output = Fq12;
+
+    #[inline]
+    fn add(self, rhs: &'b Fq12) -> Fq12 {
+        self.add(rhs)
+    }
+}
+
+impl<'a, 'b> Mul<&'b Fq12> for &'a Fq12 {
+    type Output = Fq12;
+
+    #[inline]
+    fn mul(self, rhs: &'b Fq12) -> Fq12 {
+        self.mul(rhs)
+    }
+}
+
+use crate::{
+    impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output,
+    impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
+};
+impl_binops_additive!(Fq12, Fq12);
+impl_binops_multiplicative!(Fq12, Fq12);
+
+impl Fq12 {
+    pub fn mul_assign(&mut self, other: &Self) {
+        let t0 = self.c0 * other.c0;
+        let mut t1 = self.c1 * other.c1;
+        let t2 = other.c0 + other.c1;
+
+        self.c1 += &self.c0;
+        self.c1 *= &t2;
+        self.c1 -= &t0;
+        self.c1 -= &t1;
+
+        t1.mul_by_nonresidue();
+        self.c0 = t0 + t1;
+    }
+
+    pub fn square_assign(&mut self) {
+        let mut ab = self.c0 * self.c1;
+
+        let c0c1 = self.c0 + self.c1;
+
+        let mut c0 = self.c1;
+        c0.mul_by_nonresidue();
+        c0 += &self.c0;
+        c0 *= &c0c1;
+        c0 -= &ab;
+        self.c1 = ab;
+        self.c1 += &ab;
+        ab.mul_by_nonresidue();
+        c0 -= &ab;
+        self.c0 = c0;
+    }
+
+    pub fn double(&self) -> Self {
+        Self {
+            c0: self.c0.double(),
+            c1: self.c1.double(),
+        }
+    }
+
+    pub fn double_assign(&mut self) {
+        self.c0 = self.c0.double();
+        self.c1 = self.c1.double();
+    }
+
+    pub fn add(&self, other: &Self) -> Self {
+        Self {
+            c0: self.c0 + other.c0,
+            c1: self.c1 + other.c1,
+        }
+    }
+
+    pub fn sub(&self, other: &Self) -> Self {
+        Self {
+            c0: self.c0 - other.c0,
+            c1: self.c1 - other.c1,
+        }
+    }
+
+    pub fn mul(&self, other: &Self) -> Self {
+        let mut t = *other;
+        t.mul_assign(self);
+        t
+    }
+
+    pub fn square(&self) -> Self {
+        let mut t = *self;
+        t.square_assign();
+        t
+    }
+
+    #[inline(always)]
+    pub fn neg(&self) -> Self {
+        Self {
+            c0: -self.c0,
+            c1: -self.c1,
+        }
+    }
+
+    #[inline(always)]
+    pub fn conjugate(&mut self) {
+        self.c1 = -self.c1;
+    }
+
+    // pub fn conjugate(&self) -> Self {
+    //     Self {
+    //         c0: self.c0,
+    //         c1: -self.c1,
+    //     }
+    // }
+
+    pub fn frobenius_map(&mut self, power: usize) {
+        self.c0.frobenius_map(power);
+        self.c1.frobenius_map(power);
+
+        self.c1.c0.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]);
+        self.c1.c1.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]);
+        self.c1.c2.mul_assign(&FROBENIUS_COEFF_FQ12_C1[power % 12]);
+    }
+
+    pub fn mul_by_014(&mut self, c0: &Fq2, c1: &Fq2, c4: &Fq2) {
+        let mut aa = self.c0;
+        aa.mul_by_01(c0, c1);
+        let mut bb = self.c1;
+        bb.mul_by_1(c4);
+        let o = c1 + c4;
+        self.c1 += &self.c0;
+        self.c1.mul_by_01(c0, &o);
+        self.c1 -= &aa;
+        self.c1 -= &bb;
+        self.c0 = bb;
+        self.c0.mul_by_nonresidue();
+        self.c0 += &aa;
+    }
+
+    pub fn mul_by_034(&mut self, c0: &Fq2, c3: &Fq2, c4: &Fq2) {
+        let t0 = Fq6 {
+            c0: self.c0.c0 * c0,
+            c1: self.c0.c1 * c0,
+            c2: self.c0.c2 * c0,
+        };
+        let mut t1 = self.c1;
+        t1.mul_by_01(c3, c4);
+        let o = c0 + c3;
+        let mut t2 = self.c0 + self.c1;
+        t2.mul_by_01(&o, c4);
+        t2 -= t0;
+        self.c1 = t2 - t1;
+        t1.mul_by_nonresidue();
+        self.c0 = t0 + t1;
+    }
+
+    pub fn invert(&self) -> CtOption<Self> {
+        let mut c0s = self.c0;
+        c0s.square_assign();
+        let mut c1s = self.c1;
+        c1s.square_assign();
+        c1s.mul_by_nonresidue();
+        c0s -= &c1s;
+
+        c0s.invert().map(|t| {
+            let mut tmp = Fq12 { c0: t, c1: t };
+            tmp.c0.mul_assign(&self.c0);
+            tmp.c1.mul_assign(&self.c1);
+            tmp.c1 = tmp.c1.neg();
+
+            tmp
+        })
+    }
+
+    pub fn cyclotomic_square(&mut self) {
+        fn fp4_square(c0: &mut Fq2, c1: &mut Fq2, a0: &Fq2, a1: &Fq2) {
+            let t0 = a0.square();
+            let t1 = a1.square();
+            let mut t2 = t1;
+            t2.mul_by_nonresidue();
+            *c0 = t2 + t0;
+            t2 = a0 + a1;
+            t2.square_assign();
+            t2 -= t0;
+            *c1 = t2 - t1;
+        }
+
+        let mut t3 = Fq2::zero();
+        let mut t4 = Fq2::zero();
+        let mut t5 = Fq2::zero();
+        let mut t6 = Fq2::zero();
+
+        fp4_square(&mut t3, &mut t4, &self.c0.c0, &self.c1.c1);
+        let mut t2 = t3 - self.c0.c0;
+        t2.double_assign();
+        self.c0.c0 = t2 + t3;
+
+        t2 = t4 + self.c1.c1;
+        t2.double_assign();
+        self.c1.c1 = t2 + t4;
+
+        fp4_square(&mut t3, &mut t4, &self.c1.c0, &self.c0.c2);
+        fp4_square(&mut t5, &mut t6, &self.c0.c1, &self.c1.c2);
+
+        t2 = t3 - self.c0.c1;
+        t2.double_assign();
+        self.c0.c1 = t2 + t3;
+        t2 = t4 + self.c1.c2;
+        t2.double_assign();
+        self.c1.c2 = t2 + t4;
+        t3 = t6;
+        t3.mul_by_nonresidue();
+        t2 = t3 + self.c1.c0;
+        t2.double_assign();
+        self.c1.c0 = t2 + t3;
+        t2 = t5 - self.c0.c2;
+        t2.double_assign();
+        self.c0.c2 = t2 + t5;
+    }
+}
+
+impl Field for Fq12 {
+    fn random(mut rng: impl RngCore) -> Self {
+        Fq12 {
+            c0: Fq6::random(&mut rng),
+            c1: Fq6::random(&mut rng),
+        }
+    }
+
+    fn zero() -> Self {
+        Fq12 {
+            c0: Fq6::zero(),
+            c1: Fq6::zero(),
+        }
+    }
+
+    fn one() -> Self {
+        Fq12 {
+            c0: Fq6::one(),
+            c1: Fq6::zero(),
+        }
+    }
+
+    fn is_zero(&self) -> Choice {
+        self.c0.is_zero() & self.c1.is_zero()
+    }
+
+    fn square(&self) -> Self {
+        self.square()
+    }
+
+    fn double(&self) -> Self {
+        self.double()
+    }
+
+    fn sqrt(&self) -> CtOption<Self> {
+        unimplemented!()
+    }
+
+    fn invert(&self) -> CtOption<Self> {
+        self.invert()
+    }
+}
+
+// non_residue^((modulus^i-1)/6) for i=0,...,11
+pub const FROBENIUS_COEFF_FQ12_C1: [Fq2; 12] = [
+    // Fq2(u + 9)**(((q^0) - 1) / 6)
+    // Fq points are represented in Montgomery form with R = 2^256
+    Fq2 {
+        c0: Fq([
+            0xd35d438dc58f0d9d,
+            0x0a78eb28f5c70b3d,
+            0x666ea36f7879462c,
+            0x0e0a77c19a07df2f,
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0]),
+    },
+    // Fq2(u + 9)**(((q^1) - 1) / 6)
+    Fq2 {
+        c0: Fq([
+            0xaf9ba69633144907,
+            0xca6b1d7387afb78a,
+            0x11bded5ef08a2087,
+            0x02f34d751a1f3a7c,
+        ]),
+        c1: Fq([
+            0xa222ae234c492d72,
+            0xd00f02a4565de15b,
+            0xdc2ff3a253dfc926,
+            0x10a75716b3899551,
+        ]),
+    },
+    // Fq2(u + 9)**(((q^2) - 1) / 6)
+    Fq2 {
+        c0: Fq([
+            0xca8d800500fa1bf2,
+            0xf0c5d61468b39769,
+            0x0e201271ad0d4418,
+            0x04290f65bad856e6,
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0]),
+    },
+    // Fq2(u + 9)**(((q^3) - 1) / 6)
+    Fq2 {
+        c0: Fq([
+            0x365316184e46d97d,
+            0x0af7129ed4c96d9f,
+            0x659da72fca1009b5,
+            0x08116d8983a20d23,
+        ]),
+        c1: Fq([
+            0xb1df4af7c39c1939,
+            0x3d9f02878a73bf7f,
+            0x9b2220928caf0ae0,
+            0x26684515eff054a6,
+        ]),
+    },
+    // Fq2(u + 9)**(((q^4) - 1) / 6)
+    Fq2 {
+        c0: Fq([
+            0x3350c88e13e80b9c,
+            0x7dce557cdb5e56b9,
+            0x6001b4b8b615564a,
+            0x2682e617020217e0,
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0]),
+    },
+    // Fq2(u + 9)**(((q^5) - 1) / 6)
+    Fq2 {
+        c0: Fq([
+            0x86b76f821b329076,
+            0x408bf52b4d19b614,
+            0x53dfb9d0d985e92d,
+            0x051e20146982d2a7,
+        ]),
+        c1: Fq([
+            0x0fbc9cd47752ebc7,
+            0x6d8fffe33415de24,
+            0xbef22cf038cf41b9,
+            0x15c0edff3c66bf54,
+        ]),
+    },
+    // Fq2(u + 9)**(((q^6) - 1) / 6)
+    Fq2 {
+        c0: Fq([
+            0x68c3488912edefaa,
+            0x8d087f6872aabf4f,
+            0x51e1a24709081231,
+            0x2259d6b14729c0fa,
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0]),
+    },
+    // Fq2(u + 9)**(((q^7) - 1) / 6)
+    Fq2 {
+        c0: Fq([
+            0x8c84e580a568b440,
+            0xcd164d1de0c21302,
+            0xa692585790f737d5,
+            0x2d7100fdc71265ad,
+        ]),
+        c1: Fq([
+            0x99fdddf38c33cfd5,
+            0xc77267ed1213e931,
+            0xdc2052142da18f36,
+            0x1fbcf75c2da80ad7,
+        ]),
+    },
+    // Fq2(u + 9)**(((q^8) - 1) / 6)
+    Fq2 {
+        c0: Fq([
+            0x71930c11d782e155,
+            0xa6bb947cffbe3323,
+            0xaa303344d4741444,
+            0x2c3b3f0d26594943,
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0]),
+    },
+    // Fq2(u + 9)**(((q^9) - 1) / 6)
+    Fq2 {
+        c0: Fq([
+            0x05cd75fe8a3623ca,
+            0x8c8a57f293a85cee,
+            0x52b29e86b7714ea8,
+            0x2852e0e95d8f9306,
+        ]),
+        c1: Fq([
+            0x8a41411f14e0e40e,
+            0x59e26809ddfe0b0d,
+            0x1d2e2523f4d24d7d,
+            0x09fc095cf1414b83,
+        ]),
+    },
+    // Fq2(u + 9)**(((q^10) - 1) / 6)
+    Fq2 {
+        c0: Fq([
+            0x08cfc388c494f1ab,
+            0x19b315148d1373d4,
+            0x584e90fdcb6c0213,
+            0x09e1685bdf2f8849,
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0]),
+    },
+    // Fq2(u + 9)**(((q^11) - 1) / 6)
+    Fq2 {
+        c0: Fq([
+            0xb5691c94bd4a6cd1,
+            0x56f575661b581478,
+            0x64708be5a7fb6f30,
+            0x2b462e5e77aecd82,
+        ]),
+        c1: Fq([
+            0x2c63ef42612a1180,
+            0x29f16aae345bec69,
+            0xf95e18c648b216a4,
+            0x1aa36073a4cae0d4,
+        ]),
+    },
+];
+
+#[cfg(test)]
+use rand::SeedableRng;
+#[cfg(test)]
+use rand_xorshift::XorShiftRng;
+
+#[test]
+fn test_fq12_mul_by_014() {
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+
+    for _ in 0..1000 {
+        let c0 = Fq2::random(&mut rng);
+        let c1 = Fq2::random(&mut rng);
+        let c5 = Fq2::random(&mut rng);
+        let mut a = Fq12::random(&mut rng);
+        let mut b = a;
+
+        a.mul_by_014(&c0, &c1, &c5);
+        b.mul_assign(&Fq12 {
+            c0: Fq6 {
+                c0,
+                c1,
+                c2: Fq2::zero(),
+            },
+            c1: Fq6 {
+                c0: Fq2::zero(),
+                c1: c5,
+                c2: Fq2::zero(),
+            },
+        });
+
+        assert_eq!(a, b);
+    }
+}
+
+#[test]
+fn test_fq12_mul_by_034() {
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+
+    for _ in 0..1000 {
+        let c0 = Fq2::random(&mut rng);
+        let c3 = Fq2::random(&mut rng);
+        let c4 = Fq2::random(&mut rng);
+        let mut a = Fq12::random(&mut rng);
+        let mut b = a;
+
+        a.mul_by_034(&c0, &c3, &c4);
+        b.mul_assign(&Fq12 {
+            c0: Fq6 {
+                c0,
+                c1: Fq2::zero(),
+                c2: Fq2::zero(),
+            },
+            c1: Fq6 {
+                c0: c3,
+                c1: c4,
+                c2: Fq2::zero(),
+            },
+        });
+
+        assert_eq!(a, b);
+    }
+}
+
+#[test]
+fn test_squaring() {
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+
+    for _ in 0..1000 {
+        let mut a = Fq12::random(&mut rng);
+        let mut b = a;
+        b.mul_assign(&a);
+        a.square_assign();
+        assert_eq!(a, b);
+    }
+}
+
+#[test]
+fn test_frobenius() {
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+
+    for _ in 0..100 {
+        for i in 0..14 {
+            let mut a = Fq12::random(&mut rng);
+            let mut b = a;
+
+            for _ in 0..i {
+                a = a.pow_vartime([
+                    0x3c208c16d87cfd47,
+                    0x97816a916871ca8d,
+                    0xb85045b68181585d,
+                    0x30644e72e131a029,
+                ]);
+            }
+            b.frobenius_map(i);
+
+            assert_eq!(a, b);
+        }
+    }
+}
+
+#[test]
+fn test_field() {
+    crate::tests::field::random_field_tests::<Fq12>("fq12".to_string());
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/bn256/fq2.rs.html b/docs/src/halo2curves/bn256/fq2.rs.html new file mode 100644 index 0000000000..37ccaab43d --- /dev/null +++ b/docs/src/halo2curves/bn256/fq2.rs.html @@ -0,0 +1,1684 @@ +fq2.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+
use super::fq::{Fq, NEGATIVE_ONE};
+use super::LegendreSymbol;
+use core::convert::TryInto;
+use core::ops::{Add, Mul, Neg, Sub};
+use ff::Field;
+use pasta_curves::arithmetic::{FieldExt, Group, SqrtRatio};
+use rand::RngCore;
+use serde::{Deserialize, Serialize};
+use std::cmp::Ordering;
+use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
+
+/// An element of Fq2, represented by c0 + c1 * u.
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
+pub struct Fq2 {
+    pub c0: Fq,
+    pub c1: Fq,
+}
+
+/// `Fq2` elements are ordered lexicographically.
+impl Ord for Fq2 {
+    #[inline(always)]
+    fn cmp(&self, other: &Fq2) -> Ordering {
+        match self.c1.cmp(&other.c1) {
+            Ordering::Greater => Ordering::Greater,
+            Ordering::Less => Ordering::Less,
+            Ordering::Equal => self.c0.cmp(&other.c0),
+        }
+    }
+}
+
+impl PartialOrd for Fq2 {
+    #[inline(always)]
+    fn partial_cmp(&self, other: &Fq2) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl ConditionallySelectable for Fq2 {
+    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
+        Fq2 {
+            c0: Fq::conditional_select(&a.c0, &b.c0, choice),
+            c1: Fq::conditional_select(&a.c1, &b.c1, choice),
+        }
+    }
+}
+
+impl ConstantTimeEq for Fq2 {
+    fn ct_eq(&self, other: &Self) -> Choice {
+        self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1)
+    }
+}
+
+impl Default for Fq2 {
+    #[inline]
+    fn default() -> Self {
+        Self::zero()
+    }
+}
+
+impl From<Fq2> for [u8; 64] {
+    fn from(value: Fq2) -> [u8; 64] {
+        value.to_bytes()
+    }
+}
+
+impl<'a> From<&'a Fq2> for [u8; 64] {
+    fn from(value: &'a Fq2) -> [u8; 64] {
+        value.to_bytes()
+    }
+}
+
+impl Neg for Fq2 {
+    type Output = Fq2;
+
+    #[inline]
+    fn neg(self) -> Fq2 {
+        -&self
+    }
+}
+
+impl<'a> Neg for &'a Fq2 {
+    type Output = Fq2;
+
+    #[inline]
+    fn neg(self) -> Fq2 {
+        self.neg()
+    }
+}
+
+impl<'a, 'b> Sub<&'b Fq2> for &'a Fq2 {
+    type Output = Fq2;
+
+    #[inline]
+    fn sub(self, rhs: &'b Fq2) -> Fq2 {
+        self.sub(rhs)
+    }
+}
+
+impl<'a, 'b> Add<&'b Fq2> for &'a Fq2 {
+    type Output = Fq2;
+
+    #[inline]
+    fn add(self, rhs: &'b Fq2) -> Fq2 {
+        self.add(rhs)
+    }
+}
+
+impl<'a, 'b> Mul<&'b Fq2> for &'a Fq2 {
+    type Output = Fq2;
+
+    #[inline]
+    fn mul(self, rhs: &'b Fq2) -> Fq2 {
+        self.mul(rhs)
+    }
+}
+
+use crate::{
+    impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output,
+    impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
+};
+impl_binops_additive!(Fq2, Fq2);
+impl_binops_multiplicative!(Fq2, Fq2);
+
+impl Fq2 {
+    pub const fn new(c0: Fq, c1: Fq) -> Self {
+        Fq2 { c0, c1 }
+    }
+
+    pub const fn size() -> usize {
+        64
+    }
+    /// Attempts to convert a little-endian byte representation of
+    /// a scalar into a `Fq`, failing if the input is not canonical.
+    pub fn from_bytes(bytes: &[u8; 64]) -> CtOption<Fq2> {
+        let c0 = Fq::from_bytes(bytes[0..32].try_into().unwrap());
+        let c1 = Fq::from_bytes(bytes[32..64].try_into().unwrap());
+        CtOption::new(
+            Fq2 {
+                c0: c0.unwrap(),
+                c1: c1.unwrap(),
+            },
+            c0.is_some() & c1.is_some(),
+        )
+    }
+
+    /// Converts an element of `Fq` into a byte representation in
+    /// little-endian byte order.
+    pub fn to_bytes(&self) -> [u8; 64] {
+        let mut res = [0u8; 64];
+        let c0_bytes = self.c0.to_bytes();
+        let c1_bytes = self.c1.to_bytes();
+        res[0..32].copy_from_slice(&c0_bytes[..]);
+        res[32..64].copy_from_slice(&c1_bytes[..]);
+        res
+    }
+
+    pub fn legendre(&self) -> LegendreSymbol {
+        self.norm().legendre()
+    }
+
+    pub fn mul_assign(&mut self, other: &Self) {
+        let mut t1 = self.c0 * other.c0;
+        let mut t0 = self.c0 + self.c1;
+        let t2 = self.c1 * other.c1;
+        self.c1 = other.c0 + other.c1;
+        self.c0 = t1 - t2;
+        t1 += t2;
+        t0 *= self.c1;
+        self.c1 = t0 - t1;
+    }
+
+    pub fn square_assign(&mut self) {
+        let ab = self.c0 * self.c1;
+        let c0c1 = self.c0 + self.c1;
+        let mut c0 = -self.c1;
+        c0 += self.c0;
+        c0 *= c0c1;
+        c0 -= ab;
+        self.c1 = ab.double();
+        self.c0 = c0 + ab;
+    }
+
+    pub fn double(&self) -> Self {
+        Self {
+            c0: self.c0.double(),
+            c1: self.c1.double(),
+        }
+    }
+
+    pub fn double_assign(&mut self) {
+        self.c0 = self.c0.double();
+        self.c1 = self.c1.double();
+    }
+
+    pub fn add(&self, other: &Self) -> Self {
+        Self {
+            c0: self.c0.add(&other.c0),
+            c1: self.c1.add(&other.c1),
+        }
+    }
+
+    pub fn sub(&self, other: &Self) -> Self {
+        Self {
+            c0: self.c0.sub(&other.c0),
+            c1: self.c1.sub(&other.c1),
+        }
+    }
+
+    pub fn mul(&self, other: &Self) -> Self {
+        let mut t = *other;
+        t.mul_assign(self);
+        t
+    }
+
+    pub fn square(&self) -> Self {
+        let mut t = *self;
+        t.square_assign();
+        t
+    }
+
+    pub fn neg(&self) -> Self {
+        Self {
+            c0: self.c0.neg(),
+            c1: self.c1.neg(),
+        }
+    }
+
+    // conjucate by negating c1
+    pub fn conjugate(&mut self) {
+        self.c1 = -self.c1;
+    }
+
+    pub fn frobenius_map(&mut self, power: usize) {
+        self.c1 *= &FROBENIUS_COEFF_FQ2_C1[power % 2];
+    }
+
+    /// Multiply this element by quadratic nonresidue 9 + u.
+    pub fn mul_by_nonresidue(&mut self) {
+        // (xi+y)(i+9) = (9x+y)i+(9y-x)
+        let t0 = self.c0;
+        let t1 = self.c1;
+
+        // 8*x*i + 8*y
+        self.double_assign();
+        self.double_assign();
+        self.double_assign();
+
+        // 9*y
+        self.c0 += &t0;
+        // (9*y - x)
+        self.c0 -= &t1;
+
+        // (9*x)i
+        self.c1 += &t1;
+        // (9*x + y)
+        self.c1 += &t0;
+    }
+
+    // Multiply this element by ξ where ξ=i+9
+    pub fn mul_by_xi(&mut self) {
+        // (xi+y)(i+9) = (9x+y)i+(9y-x)
+        let t0 = self.c0;
+        let t1 = self.c1;
+
+        // 8*x*i + 8*y
+        self.double_assign();
+        self.double_assign();
+        self.double_assign();
+
+        // 9*y
+        self.c0 += &t0;
+        // (9*y - x)
+        self.c0 -= &t1;
+
+        // (9*x)i
+        self.c1 += &t1;
+        // (9*x + y)
+        self.c1 += &t0;
+    }
+
+    /// Norm of Fq2 as extension field in i over Fq
+    pub fn norm(&self) -> Fq {
+        let mut t0 = self.c0;
+        let mut t1 = self.c1;
+        t0 = t0.square();
+        t1 = t1.square();
+        t1 + t0
+    }
+
+    pub fn invert(&self) -> CtOption<Self> {
+        let mut t1 = self.c1;
+        t1 = t1.square();
+        let mut t0 = self.c0;
+        t0 = t0.square();
+        t0 += &t1;
+        t0.invert().map(|t| {
+            let mut tmp = Fq2 {
+                c0: self.c0,
+                c1: self.c1,
+            };
+            tmp.c0 *= &t;
+            tmp.c1 *= &t;
+            tmp.c1 = -tmp.c1;
+
+            tmp
+        })
+    }
+}
+
+impl Field for Fq2 {
+    fn random(mut rng: impl RngCore) -> Self {
+        Fq2 {
+            c0: Fq::random(&mut rng),
+            c1: Fq::random(&mut rng),
+        }
+    }
+
+    fn zero() -> Self {
+        Fq2 {
+            c0: Fq::zero(),
+            c1: Fq::zero(),
+        }
+    }
+
+    fn one() -> Self {
+        Fq2 {
+            c0: Fq::one(),
+            c1: Fq::zero(),
+        }
+    }
+
+    fn is_zero(&self) -> Choice {
+        self.c0.is_zero() & self.c1.is_zero()
+    }
+
+    fn square(&self) -> Self {
+        self.square()
+    }
+
+    fn double(&self) -> Self {
+        self.double()
+    }
+
+    fn sqrt(&self) -> CtOption<Self> {
+        // Algorithm 9, https://eprint.iacr.org/2012/685.pdf
+
+        if self.is_zero().into() {
+            CtOption::new(Self::zero(), Choice::from(1))
+        } else {
+            // a1 = self^((q - 3) / 4)
+            // 0xc19139cb84c680a6e14116da060561765e05aa45a1c72a34f082305b61f3f51
+            let u: [u64; 4] = [
+                0x4f082305b61f3f51,
+                0x65e05aa45a1c72a3,
+                0x6e14116da0605617,
+                0x0c19139cb84c680a,
+            ];
+            let mut a1 = self.pow(&u);
+            let mut alpha = a1;
+
+            alpha.square_assign();
+            alpha.mul_assign(self);
+            let mut a0 = alpha;
+            a0.frobenius_map(1);
+            a0.mul_assign(&alpha);
+
+            let neg1 = Fq2 {
+                c0: NEGATIVE_ONE,
+                c1: Fq::zero(),
+            };
+
+            if a0 == neg1 {
+                CtOption::new(a0, Choice::from(0))
+            } else {
+                a1.mul_assign(self);
+
+                if alpha == neg1 {
+                    a1.mul_assign(&Fq2 {
+                        c0: Fq::zero(),
+                        c1: Fq::one(),
+                    });
+                } else {
+                    alpha += &Fq2::one();
+                    // alpha = alpha^((q - 1) / 2)
+                    // 0x183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea3
+                    let u: [u64; 4] = [
+                        0x9e10460b6c3e7ea3,
+                        0xcbc0b548b438e546,
+                        0xdc2822db40c0ac2e,
+                        0x183227397098d014,
+                    ];
+                    alpha = alpha.pow(&u);
+                    a1.mul_assign(&alpha);
+                }
+                CtOption::new(a1, Choice::from(1))
+            }
+        }
+    }
+
+    fn invert(&self) -> CtOption<Self> {
+        self.invert()
+    }
+}
+
+impl From<bool> for Fq2 {
+    fn from(bit: bool) -> Fq2 {
+        if bit {
+            Fq2::one()
+        } else {
+            Fq2::zero()
+        }
+    }
+}
+
+impl From<u64> for Fq2 {
+    fn from(val: u64) -> Self {
+        Fq2 {
+            c0: Fq::from(val),
+            c1: Fq::zero(),
+        }
+    }
+}
+
+impl FieldExt for Fq2 {
+    const MODULUS: &'static str =
+        "0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47";
+
+    const ROOT_OF_UNITY_INV: Self = Fq2 {
+        c0: Fq::zero(),
+        c1: Fq::zero(),
+    };
+    const DELTA: Self = Fq2 {
+        c0: Fq::zero(),
+        c1: Fq::zero(),
+    };
+    const TWO_INV: Self = Fq2 {
+        c0: Fq::from_raw([
+            0x9e10460b6c3e7ea4,
+            0xcbc0b548b438e546,
+            0xdc2822db40c0ac2e,
+            0x183227397098d014,
+        ]),
+        c1: Fq([0, 0, 0, 0]),
+    };
+    const ZETA: Self = Fq2 {
+        c0: Fq::zero(),
+        c1: Fq::zero(),
+    };
+
+    /// Converts a 512-bit little endian integer into
+    /// a `Fq` by reducing by the modulus.
+    fn from_bytes_wide(bytes: &[u8; 64]) -> Self {
+        Self::new(Fq::from_bytes_wide(bytes), Fq::zero())
+    }
+
+    fn from_u128(v: u128) -> Self {
+        Fq2 {
+            c0: Fq::from_raw([v as u64, (v >> 64) as u64, 0, 0]),
+            c1: Fq::zero(),
+        }
+    }
+
+    fn get_lower_128(&self) -> u128 {
+        self.c0.get_lower_128()
+    }
+
+    // /// Writes this element in its normalized, little endian form into a buffer.
+    // fn write<W: Write>(&self, writer: &mut W) -> io::Result<()> {
+    //     let compressed = self.to_bytes();
+    //     writer.write_all(&compressed[..])
+    // }
+
+    // /// Reads a normalized, little endian represented field element from a
+    // /// buffer.
+    // fn read<R: Read>(reader: &mut R) -> io::Result<Self> {
+    //     let mut compressed = [0u8; 64];
+    //     reader.read_exact(&mut compressed[..])?;
+    //     Option::from(Self::from_bytes(&compressed))
+    //         .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point encoding in proof"))
+    // }
+}
+
+impl SqrtRatio for Fq2 {
+    const T_MINUS1_OVER2: [u64; 4] = [0, 0, 0, 0];
+
+    fn pow_by_t_minus1_over2(&self) -> Self {
+        unimplemented!();
+    }
+
+    fn get_lower_32(&self) -> u32 {
+        unimplemented!();
+    }
+
+    #[cfg(feature = "sqrt-table")]
+    fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) {
+        unimplemented!();
+    }
+
+    #[cfg(feature = "sqrt-table")]
+    fn sqrt_alt(&self) -> (Choice, Self) {
+        unimplemented!();
+    }
+}
+
+impl Group for Fq2 {
+    type Scalar = Fq2;
+
+    fn group_zero() -> Self {
+        Self::zero()
+    }
+    fn group_add(&mut self, rhs: &Self) {
+        *self += *rhs;
+    }
+    fn group_sub(&mut self, rhs: &Self) {
+        *self -= *rhs;
+    }
+    fn group_scale(&mut self, by: &Self::Scalar) {
+        *self *= *by;
+    }
+}
+
+#[derive(Clone, Copy, Debug)]
+pub struct Fq2Bytes([u8; 64]);
+
+impl Default for Fq2Bytes {
+    fn default() -> Self {
+        Self([0u8; 64])
+    }
+}
+
+impl AsMut<[u8]> for Fq2Bytes {
+    fn as_mut(&mut self) -> &mut [u8] {
+        &mut self.0
+    }
+}
+
+impl AsRef<[u8]> for Fq2Bytes {
+    fn as_ref(&self) -> &[u8] {
+        &self.0
+    }
+}
+
+impl ff::PrimeField for Fq2 {
+    type Repr = Fq2Bytes;
+
+    const NUM_BITS: u32 = 254;
+    const CAPACITY: u32 = 253;
+
+    const S: u32 = 0;
+
+    fn from_repr(repr: Self::Repr) -> CtOption<Self> {
+        let c0 = Fq::from_bytes(&repr.0[..32].try_into().unwrap());
+        let c1 = Fq::from_bytes(&repr.0[32..].try_into().unwrap());
+        // Disallow overflow representation
+        CtOption::new(Fq2::new(c0.unwrap(), c1.unwrap()), Choice::from(1))
+    }
+
+    fn to_repr(&self) -> Self::Repr {
+        Fq2Bytes(self.to_bytes())
+    }
+
+    fn is_odd(&self) -> Choice {
+        Choice::from(self.to_repr().as_ref()[0] & 1)
+    }
+
+    fn multiplicative_generator() -> Self {
+        unimplemented!()
+    }
+
+    fn root_of_unity() -> Self {
+        unimplemented!()
+    }
+}
+
+impl crate::serde::SerdeObject for Fq2 {
+    fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self {
+        debug_assert_eq!(bytes.len(), 64);
+        let [c0, c1] = [0, 32].map(|i| Fq::from_raw_bytes_unchecked(&bytes[i..i + 32]));
+        Self { c0, c1 }
+    }
+    fn from_raw_bytes(bytes: &[u8]) -> Option<Self> {
+        if bytes.len() != 64 {
+            return None;
+        }
+        let [c0, c1] = [0, 32].map(|i| Fq::from_raw_bytes(&bytes[i..i + 32]));
+        c0.zip(c1).map(|(c0, c1)| Self { c0, c1 })
+    }
+    fn to_raw_bytes(&self) -> Vec<u8> {
+        let mut res = Vec::with_capacity(64);
+        for limb in self.c0.0.iter().chain(self.c1.0.iter()) {
+            res.extend_from_slice(&limb.to_le_bytes());
+        }
+        res
+    }
+    fn read_raw_unchecked<R: std::io::Read>(reader: &mut R) -> Self {
+        let [c0, c1] = [(); 2].map(|_| Fq::read_raw_unchecked(reader));
+        Self { c0, c1 }
+    }
+    fn read_raw<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
+        let c0 = Fq::read_raw(reader)?;
+        let c1 = Fq::read_raw(reader)?;
+        Ok(Self { c0, c1 })
+    }
+    fn write_raw<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
+        self.c0.write_raw(writer)?;
+        self.c1.write_raw(writer)
+    }
+}
+
+pub const FROBENIUS_COEFF_FQ2_C1: [Fq; 2] = [
+    // Fq(-1)**(((q^0) - 1) / 2)
+    // it's 1 in Montgommery form
+    Fq([
+        0xd35d438dc58f0d9d,
+        0x0a78eb28f5c70b3d,
+        0x666ea36f7879462c,
+        0x0e0a77c19a07df2f,
+    ]),
+    // Fq(-1)**(((q^1) - 1) / 2)
+    Fq([
+        0x68c3488912edefaa,
+        0x8d087f6872aabf4f,
+        0x51e1a24709081231,
+        0x2259d6b14729c0fa,
+    ]),
+];
+
+#[cfg(test)]
+use rand::SeedableRng;
+#[cfg(test)]
+use rand_xorshift::XorShiftRng;
+
+#[test]
+fn test_ser() {
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+
+    let a0 = Fq2::random(&mut rng);
+    let a_bytes = a0.to_bytes();
+    let a1 = Fq2::from_bytes(&a_bytes).unwrap();
+    assert_eq!(a0, a1);
+}
+
+#[test]
+fn test_fq2_ordering() {
+    let mut a = Fq2 {
+        c0: Fq::zero(),
+        c1: Fq::zero(),
+    };
+
+    let mut b = a;
+
+    assert!(a.cmp(&b) == Ordering::Equal);
+    b.c0 += &Fq::one();
+    assert!(a.cmp(&b) == Ordering::Less);
+    a.c0 += &Fq::one();
+    assert!(a.cmp(&b) == Ordering::Equal);
+    b.c1 += &Fq::one();
+    assert!(a.cmp(&b) == Ordering::Less);
+    a.c0 += &Fq::one();
+    assert!(a.cmp(&b) == Ordering::Less);
+    a.c1 += &Fq::one();
+    assert!(a.cmp(&b) == Ordering::Greater);
+    b.c0 += &Fq::one();
+    assert!(a.cmp(&b) == Ordering::Equal);
+}
+
+#[test]
+fn test_fq2_basics() {
+    assert_eq!(
+        Fq2 {
+            c0: Fq::zero(),
+            c1: Fq::zero(),
+        },
+        Fq2::zero()
+    );
+    assert_eq!(
+        Fq2 {
+            c0: Fq::one(),
+            c1: Fq::zero(),
+        },
+        Fq2::one()
+    );
+    assert_eq!(Fq2::zero().is_zero().unwrap_u8(), 1);
+    assert_eq!(Fq2::one().is_zero().unwrap_u8(), 0);
+    assert_eq!(
+        Fq2 {
+            c0: Fq::zero(),
+            c1: Fq::one(),
+        }
+        .is_zero()
+        .unwrap_u8(),
+        0
+    );
+}
+
+#[test]
+fn test_fq2_squaring() {
+    let mut a = Fq2 {
+        c0: Fq::one(),
+        c1: Fq::one(),
+    }; // u + 1
+    a.square_assign();
+    assert_eq!(
+        a,
+        Fq2 {
+            c0: Fq::zero(),
+            c1: Fq::one() + Fq::one(),
+        }
+    ); // 2u
+
+    let mut a = Fq2 {
+        c0: Fq::zero(),
+        c1: Fq::one(),
+    }; // u
+    a.square_assign();
+    assert_eq!(a, {
+        let neg1 = -Fq::one();
+        Fq2 {
+            c0: neg1,
+            c1: Fq::zero(),
+        }
+    }); // -1
+}
+
+#[test]
+fn test_fq2_mul_nonresidue() {
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+    let nine = Fq::one().double().double().double() + Fq::one();
+    let nqr = Fq2 {
+        c0: nine,
+        c1: Fq::one(),
+    };
+
+    for _ in 0..1000 {
+        let mut a = Fq2::random(&mut rng);
+        let mut b = a;
+        a.mul_by_nonresidue();
+        b.mul_assign(&nqr);
+
+        assert_eq!(a, b);
+    }
+}
+
+#[test]
+fn test_fq2_legendre() {
+    assert_eq!(LegendreSymbol::Zero, Fq2::zero().legendre());
+    // i^2 = -1
+    let mut m1 = Fq2::one();
+    m1 = m1.neg();
+    assert_eq!(LegendreSymbol::QuadraticResidue, m1.legendre());
+    m1.mul_by_nonresidue();
+    assert_eq!(LegendreSymbol::QuadraticNonResidue, m1.legendre());
+}
+
+#[test]
+pub fn test_sqrt() {
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+
+    for _ in 0..10000 {
+        let a = Fq2::random(&mut rng);
+        if a.legendre() == LegendreSymbol::QuadraticNonResidue {
+            assert!(bool::from(a.sqrt().is_none()));
+        }
+    }
+
+    for _ in 0..10000 {
+        let a = Fq2::random(&mut rng);
+        let mut b = a;
+        b.square_assign();
+        assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue);
+
+        let b = b.sqrt().unwrap();
+        let mut negb = b;
+        negb = negb.neg();
+
+        assert!(a == b || a == negb);
+    }
+
+    let mut c = Fq2::one();
+    for _ in 0..10000 {
+        let mut b = c;
+        b.square_assign();
+        assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue);
+
+        b = b.sqrt().unwrap();
+
+        if b != c {
+            b = b.neg();
+        }
+
+        assert_eq!(b, c);
+
+        c += &Fq2::one();
+    }
+}
+
+#[test]
+fn test_frobenius() {
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+
+    for _ in 0..100 {
+        for i in 0..14 {
+            let mut a = Fq2::random(&mut rng);
+            let mut b = a;
+
+            for _ in 0..i {
+                a = a.pow(&[
+                    0x3c208c16d87cfd47,
+                    0x97816a916871ca8d,
+                    0xb85045b68181585d,
+                    0x30644e72e131a029,
+                ]);
+            }
+            b.frobenius_map(i);
+
+            assert_eq!(a, b);
+        }
+    }
+}
+
+#[test]
+fn test_field() {
+    crate::tests::field::random_field_tests::<Fq2>("fq2".to_string());
+}
+
+#[test]
+fn test_serialization() {
+    crate::tests::field::random_serialization_test::<Fq2>("fq2".to_string());
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/bn256/fq6.rs.html b/docs/src/halo2curves/bn256/fq6.rs.html new file mode 100644 index 0000000000..5b7fd12947 --- /dev/null +++ b/docs/src/halo2curves/bn256/fq6.rs.html @@ -0,0 +1,1410 @@ +fq6.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+
use super::fq::Fq;
+use super::fq2::Fq2;
+use core::ops::{Add, Mul, Neg, Sub};
+use ff::Field;
+use rand::RngCore;
+use serde::{Deserialize, Serialize};
+use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Default, Hash, Serialize, Deserialize)]
+pub struct Fq6 {
+    pub c0: Fq2,
+    pub c1: Fq2,
+    pub c2: Fq2,
+}
+
+impl ConditionallySelectable for Fq6 {
+    fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
+        Fq6 {
+            c0: Fq2::conditional_select(&a.c0, &b.c0, choice),
+            c1: Fq2::conditional_select(&a.c1, &b.c1, choice),
+            c2: Fq2::conditional_select(&a.c2, &b.c2, choice),
+        }
+    }
+}
+
+impl ConstantTimeEq for Fq6 {
+    fn ct_eq(&self, other: &Self) -> Choice {
+        self.c0.ct_eq(&other.c0) & self.c1.ct_eq(&other.c1) & self.c2.ct_eq(&other.c2)
+    }
+}
+
+impl Neg for Fq6 {
+    type Output = Fq6;
+
+    #[inline]
+    fn neg(self) -> Fq6 {
+        -&self
+    }
+}
+
+impl<'a> Neg for &'a Fq6 {
+    type Output = Fq6;
+
+    #[inline]
+    fn neg(self) -> Fq6 {
+        self.neg()
+    }
+}
+
+impl<'a, 'b> Sub<&'b Fq6> for &'a Fq6 {
+    type Output = Fq6;
+
+    #[inline]
+    fn sub(self, rhs: &'b Fq6) -> Fq6 {
+        self.sub(rhs)
+    }
+}
+
+impl<'a, 'b> Add<&'b Fq6> for &'a Fq6 {
+    type Output = Fq6;
+
+    #[inline]
+    fn add(self, rhs: &'b Fq6) -> Fq6 {
+        self.add(rhs)
+    }
+}
+
+impl<'a, 'b> Mul<&'b Fq6> for &'a Fq6 {
+    type Output = Fq6;
+
+    #[inline]
+    fn mul(self, rhs: &'b Fq6) -> Fq6 {
+        self.mul(rhs)
+    }
+}
+
+use crate::{
+    impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output,
+    impl_binops_multiplicative, impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
+};
+impl_binops_additive!(Fq6, Fq6);
+impl_binops_multiplicative!(Fq6, Fq6);
+
+impl Fq6 {
+    pub fn mul_assign(&mut self, other: &Self) {
+        let mut a_a = self.c0;
+        let mut b_b = self.c1;
+        let mut c_c = self.c2;
+        a_a *= &other.c0;
+        b_b *= &other.c1;
+        c_c *= &other.c2;
+
+        let mut t1 = other.c1;
+        t1 += &other.c2;
+        {
+            let mut tmp = self.c1;
+            tmp += &self.c2;
+
+            t1 *= &tmp;
+            t1 -= &b_b;
+            t1 -= &c_c;
+            t1.mul_by_nonresidue();
+            t1 += &a_a;
+        }
+
+        let mut t3 = other.c0;
+        t3 += &other.c2;
+        {
+            let mut tmp = self.c0;
+            tmp += &self.c2;
+
+            t3 *= &tmp;
+            t3 -= &a_a;
+            t3 += &b_b;
+            t3 -= &c_c;
+        }
+
+        let mut t2 = other.c0;
+        t2 += &other.c1;
+        {
+            let mut tmp = self.c0;
+            tmp += &self.c1;
+
+            t2 *= &tmp;
+            t2 -= &a_a;
+            t2 -= &b_b;
+            c_c.mul_by_nonresidue();
+            t2 += &c_c;
+        }
+
+        self.c0 = t1;
+        self.c1 = t2;
+        self.c2 = t3;
+    }
+
+    pub fn square_assign(&mut self) {
+        // s0 = a^2
+        let mut s0 = self.c0;
+        s0.square_assign();
+        // s1 = 2ab
+        let mut ab = self.c0;
+        ab *= &self.c1;
+        let mut s1 = ab;
+        s1.double_assign();
+        // s2 = (a - b + c)^2
+        let mut s2 = self.c0;
+        s2 -= &self.c1;
+        s2 += &self.c2;
+        s2.square_assign();
+        // bc
+        let mut bc = self.c1;
+        bc *= &self.c2;
+        // s3 = 2bc
+        let mut s3 = bc;
+        s3.double_assign();
+        // s4 = c^2
+        let mut s4 = self.c2;
+        s4.square_assign();
+
+        // new c0 = 2bc.mul_by_xi + a^2
+        self.c0 = s3;
+        self.c0.mul_by_nonresidue();
+        // self.c0.mul_by_xi();
+        self.c0 += &s0;
+
+        // new c1 = (c^2).mul_by_xi + 2ab
+        self.c1 = s4;
+        self.c1.mul_by_nonresidue();
+        // self.c1.mul_by_xi();
+        self.c1 += &s1;
+
+        // new c2 = 2ab + (a - b + c)^2 + 2bc - a^2 - c^2 = b^2 + 2ac
+        self.c2 = s1;
+        self.c2 += &s2;
+        self.c2 += &s3;
+        self.c2 -= &s0;
+        self.c2 -= &s4;
+    }
+
+    pub fn double(&self) -> Self {
+        Self {
+            c0: self.c0.double(),
+            c1: self.c1.double(),
+            c2: self.c2.double(),
+        }
+    }
+
+    pub fn double_assign(&mut self) {
+        self.c0 = self.c0.double();
+        self.c1 = self.c1.double();
+        self.c2 = self.c2.double();
+    }
+
+    pub fn add(&self, other: &Self) -> Self {
+        Self {
+            c0: self.c0 + other.c0,
+            c1: self.c1 + other.c1,
+            c2: self.c2 + other.c2,
+        }
+    }
+
+    pub fn sub(&self, other: &Self) -> Self {
+        Self {
+            c0: self.c0 - other.c0,
+            c1: self.c1 - other.c1,
+            c2: self.c2 - other.c2,
+        }
+    }
+
+    pub fn mul(&self, other: &Self) -> Self {
+        let mut t = *other;
+        t.mul_assign(self);
+        t
+    }
+
+    pub fn square(&self) -> Self {
+        let mut t = *self;
+        t.square_assign();
+        t
+    }
+
+    pub fn neg(&self) -> Self {
+        Self {
+            c0: -self.c0,
+            c1: -self.c1,
+            c2: -self.c2,
+        }
+    }
+
+    pub fn frobenius_map(&mut self, power: usize) {
+        self.c0.frobenius_map(power);
+        self.c1.frobenius_map(power);
+        self.c2.frobenius_map(power);
+
+        self.c1.mul_assign(&FROBENIUS_COEFF_FQ6_C1[power % 6]);
+        self.c2.mul_assign(&FROBENIUS_COEFF_FQ6_C2[power % 6]);
+    }
+
+    /// Multiply by cubic nonresidue v.
+    pub fn mul_by_nonresidue(&mut self) {
+        use std::mem::swap;
+        swap(&mut self.c0, &mut self.c1);
+        swap(&mut self.c0, &mut self.c2);
+        // c0, c1, c2 -> c2, c0, c1
+        self.c0.mul_by_nonresidue();
+    }
+
+    /// Multiply by cubic nonresidue v.
+    pub fn mul_by_v(&mut self) {
+        use std::mem::swap;
+        swap(&mut self.c0, &mut self.c1);
+        swap(&mut self.c0, &mut self.c2);
+
+        self.c0.mul_by_xi();
+    }
+
+    pub fn mul_by_1(&mut self, c1: &Fq2) {
+        let mut b_b = self.c1;
+        b_b *= c1;
+
+        let mut t1 = *c1;
+        {
+            let mut tmp = self.c1;
+            tmp += &self.c2;
+
+            t1 *= &tmp;
+            t1 -= &b_b;
+            t1.mul_by_nonresidue();
+        }
+
+        let mut t2 = *c1;
+        {
+            let mut tmp = self.c0;
+            tmp += &self.c1;
+
+            t2 *= &tmp;
+            t2 -= &b_b;
+        }
+
+        self.c0 = t1;
+        self.c1 = t2;
+        self.c2 = b_b;
+    }
+
+    pub fn mul_by_01(&mut self, c0: &Fq2, c1: &Fq2) {
+        let mut a_a = self.c0;
+        let mut b_b = self.c1;
+        a_a *= c0;
+        b_b *= c1;
+
+        let mut t1 = *c1;
+        {
+            let mut tmp = self.c1;
+            tmp += &self.c2;
+
+            t1 *= &tmp;
+            t1 -= &b_b;
+            t1.mul_by_nonresidue();
+            t1 += &a_a;
+        }
+
+        let mut t3 = *c0;
+        {
+            let mut tmp = self.c0;
+            tmp += &self.c2;
+
+            t3 *= &tmp;
+            t3 -= &a_a;
+            t3 += &b_b;
+        }
+
+        let mut t2 = *c0;
+        t2 += c1;
+        {
+            let mut tmp = self.c0;
+            tmp += &self.c1;
+
+            t2 *= &tmp;
+            t2 -= &a_a;
+            t2 -= &b_b;
+        }
+
+        self.c0 = t1;
+        self.c1 = t2;
+        self.c2 = t3;
+    }
+
+    fn invert(&self) -> CtOption<Self> {
+        let mut c0 = self.c2;
+        c0.mul_by_nonresidue();
+        c0 *= &self.c1;
+        c0 = -c0;
+        {
+            let mut c0s = self.c0;
+            c0s.square_assign();
+            c0 += &c0s;
+        }
+        let mut c1 = self.c2;
+        c1.square_assign();
+        c1.mul_by_nonresidue();
+        {
+            let mut c01 = self.c0;
+            c01 *= &self.c1;
+            c1 -= &c01;
+        }
+        let mut c2 = self.c1;
+        c2.square_assign();
+        {
+            let mut c02 = self.c0;
+            c02 *= &self.c2;
+            c2 -= &c02;
+        }
+
+        let mut tmp1 = self.c2;
+        tmp1 *= &c1;
+        let mut tmp2 = self.c1;
+        tmp2 *= &c2;
+        tmp1 += &tmp2;
+        tmp1.mul_by_nonresidue();
+        tmp2 = self.c0;
+        tmp2 *= &c0;
+        tmp1 += &tmp2;
+
+        tmp1.invert().map(|t| {
+            let mut tmp = Fq6 {
+                c0: t,
+                c1: t,
+                c2: t,
+            };
+            tmp.c0 *= &c0;
+            tmp.c1 *= &c1;
+            tmp.c2 *= &c2;
+
+            tmp
+        })
+    }
+}
+
+impl Field for Fq6 {
+    fn random(mut rng: impl RngCore) -> Self {
+        Fq6 {
+            c0: Fq2::random(&mut rng),
+            c1: Fq2::random(&mut rng),
+            c2: Fq2::random(&mut rng),
+        }
+    }
+
+    fn zero() -> Self {
+        Fq6 {
+            c0: Fq2::zero(),
+            c1: Fq2::zero(),
+            c2: Fq2::zero(),
+        }
+    }
+
+    fn one() -> Self {
+        Fq6 {
+            c0: Fq2::one(),
+            c1: Fq2::zero(),
+            c2: Fq2::zero(),
+        }
+    }
+
+    fn is_zero(&self) -> Choice {
+        self.c0.is_zero() & self.c1.is_zero()
+    }
+
+    fn square(&self) -> Self {
+        self.square()
+    }
+
+    fn double(&self) -> Self {
+        self.double()
+    }
+
+    fn sqrt(&self) -> CtOption<Self> {
+        unimplemented!()
+    }
+
+    fn invert(&self) -> CtOption<Self> {
+        self.invert()
+    }
+}
+
+pub const FROBENIUS_COEFF_FQ6_C1: [Fq2; 6] = [
+    // Fq2(u + 9)**(((q^0) - 1) / 3)
+    Fq2 {
+        c0: Fq([
+            0xd35d438dc58f0d9d,
+            0x0a78eb28f5c70b3d,
+            0x666ea36f7879462c,
+            0x0e0a77c19a07df2f,
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0]),
+    },
+    // Fq2(u + 9)**(((q^1) - 1) / 3)
+    // taken from go-ethereum and also re-calculated manually
+    Fq2 {
+        c0: Fq([
+            0xb5773b104563ab30,
+            0x347f91c8a9aa6454,
+            0x7a007127242e0991,
+            0x1956bcd8118214ec,
+        ]),
+        c1: Fq([
+            0x6e849f1ea0aa4757,
+            0xaa1c7b6d89f89141,
+            0xb6e713cdfae0ca3a,
+            0x26694fbb4e82ebc3,
+        ]),
+    },
+    // Fq2(u + 9)**(((q^2) - 1) / 3)
+    // this one and other below are recalculated manually
+    Fq2 {
+        c0: Fq([
+            0x3350c88e13e80b9c,
+            0x7dce557cdb5e56b9,
+            0x6001b4b8b615564a,
+            0x2682e617020217e0,
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0]),
+    },
+    // Fq2(u + 9)**(((q^3) - 1) / 3)
+    Fq2 {
+        c0: Fq([
+            0xc9af22f716ad6bad,
+            0xb311782a4aa662b2,
+            0x19eeaf64e248c7f4,
+            0x20273e77e3439f82,
+        ]),
+        c1: Fq([
+            0xacc02860f7ce93ac,
+            0x3933d5817ba76b4c,
+            0x69e6188b446c8467,
+            0x0a46036d4417cc55,
+        ]),
+    },
+    // Fq2(u + 9)**(((q^4) - 1) / 3)
+    Fq2 {
+        c0: Fq([
+            0x71930c11d782e155,
+            0xa6bb947cffbe3323,
+            0xaa303344d4741444,
+            0x2c3b3f0d26594943,
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0]),
+    },
+    // Fq2(u + 9)**(((q^5) - 1) / 3)
+    Fq2 {
+        c0: Fq([
+            0xf91aba2654e8e3b1,
+            0x4771cb2fdc92ce12,
+            0xdcb16ae0fc8bdf35,
+            0x274aa195cd9d8be4,
+        ]),
+        c1: Fq([
+            0x5cfc50ae18811f8b,
+            0x4bb28433cb43988c,
+            0x4fd35f13c3b56219,
+            0x301949bd2fc8883a,
+        ]),
+    },
+];
+
+pub const FROBENIUS_COEFF_FQ6_C2: [Fq2; 6] = [
+    // Fq2(u + 1)**(((2q^0) - 2) / 3)
+    Fq2 {
+        c0: Fq([
+            0xd35d438dc58f0d9d,
+            0x0a78eb28f5c70b3d,
+            0x666ea36f7879462c,
+            0x0e0a77c19a07df2f,
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0]),
+    },
+    // Fq2(u + 1)**(((2q^1) - 2) / 3)
+    Fq2 {
+        c0: Fq([
+            0x7361d77f843abe92,
+            0xa5bb2bd3273411fb,
+            0x9c941f314b3e2399,
+            0x15df9cddbb9fd3ec,
+        ]),
+        c1: Fq([
+            0x5dddfd154bd8c949,
+            0x62cb29a5a4445b60,
+            0x37bc870a0c7dd2b9,
+            0x24830a9d3171f0fd,
+        ]),
+    },
+    // Fq2(u + 1)**(((2q^2) - 2) / 3)
+    Fq2 {
+        c0: Fq([
+            0x71930c11d782e155,
+            0xa6bb947cffbe3323,
+            0xaa303344d4741444,
+            0x2c3b3f0d26594943,
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0]),
+    },
+    // Fq2(u + 1)**(((2q^3) - 2) / 3)
+    Fq2 {
+        c0: Fq([
+            0x448a93a57b6762df,
+            0xbfd62df528fdeadf,
+            0xd858f5d00e9bd47a,
+            0x06b03d4d3476ec58,
+        ]),
+        c1: Fq([
+            0x2b19daf4bcc936d1,
+            0xa1a54e7a56f4299f,
+            0xb533eee05adeaef1,
+            0x170c812b84dda0b2,
+        ]),
+    },
+    // Fq2(u + 1)**(((2q^4) - 2) / 3)
+    Fq2 {
+        c0: Fq([
+            0x3350c88e13e80b9c,
+            0x7dce557cdb5e56b9,
+            0x6001b4b8b615564a,
+            0x2682e617020217e0,
+        ]),
+        c1: Fq([0x0, 0x0, 0x0, 0x0]),
+    },
+    // Fq2(u + 1)**(((2q^5) - 2) / 3)
+    Fq2 {
+        c0: Fq([
+            0x843420f1d8dadbd6,
+            0x31f010c9183fcdb2,
+            0x436330b527a76049,
+            0x13d47447f11adfe4,
+        ]),
+        c1: Fq([
+            0xef494023a857fa74,
+            0x2a925d02d5ab101a,
+            0x83b015829ba62f10,
+            0x2539111d0c13aea3,
+        ]),
+    },
+];
+
+#[cfg(test)]
+use rand::SeedableRng;
+#[cfg(test)]
+use rand_xorshift::XorShiftRng;
+
+#[test]
+fn test_fq6_mul_nonresidue() {
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+
+    let nqr = Fq6 {
+        c0: Fq2::zero(),
+        c1: Fq2::one(),
+        c2: Fq2::zero(),
+    };
+
+    for _ in 0..1000 {
+        let mut a = Fq6::random(&mut rng);
+        let mut b = a;
+        a.mul_by_nonresidue();
+        b.mul_assign(&nqr);
+
+        assert_eq!(a, b);
+    }
+}
+
+#[test]
+fn test_fq6_mul_by_1() {
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+
+    for _ in 0..1000 {
+        let c1 = Fq2::random(&mut rng);
+        let mut a = Fq6::random(&mut rng);
+        let mut b = a;
+
+        a.mul_by_1(&c1);
+        b.mul_assign(&Fq6 {
+            c0: Fq2::zero(),
+            c1,
+            c2: Fq2::zero(),
+        });
+
+        assert_eq!(a, b);
+    }
+}
+
+#[test]
+fn test_fq6_mul_by_01() {
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+
+    for _ in 0..1000 {
+        let c0 = Fq2::random(&mut rng);
+        let c1 = Fq2::random(&mut rng);
+        let mut a = Fq6::random(&mut rng);
+        let mut b = a;
+
+        a.mul_by_01(&c0, &c1);
+        b.mul_assign(&Fq6 {
+            c0,
+            c1,
+            c2: Fq2::zero(),
+        });
+
+        assert_eq!(a, b);
+    }
+}
+
+#[test]
+fn test_squaring() {
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+
+    for _ in 0..1000 {
+        let mut a = Fq6::random(&mut rng);
+        let mut b = a;
+        b.mul_assign(&a);
+        a.square_assign();
+        assert_eq!(a, b);
+    }
+}
+
+#[test]
+fn test_frobenius() {
+    let mut rng = XorShiftRng::from_seed([
+        0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc,
+        0xe5,
+    ]);
+
+    for _ in 0..100 {
+        for i in 0..14 {
+            let mut a = Fq6::random(&mut rng);
+            let mut b = a;
+
+            for _ in 0..i {
+                a = a.pow_vartime([
+                    0x3c208c16d87cfd47,
+                    0x97816a916871ca8d,
+                    0xb85045b68181585d,
+                    0x30644e72e131a029,
+                ]);
+            }
+            b.frobenius_map(i);
+
+            assert_eq!(a, b);
+        }
+    }
+}
+
+#[test]
+fn test_field() {
+    crate::tests::field::random_field_tests::<Fq6>("fq6".to_string());
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/bn256/fr.rs.html b/docs/src/halo2curves/bn256/fr.rs.html new file mode 100644 index 0000000000..a724b08df9 --- /dev/null +++ b/docs/src/halo2curves/bn256/fr.rs.html @@ -0,0 +1,748 @@ +fr.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+
#[cfg(feature = "asm")]
+use super::assembly::assembly_field;
+
+use crate::arithmetic::{adc, mac, macx, sbb};
+use core::convert::TryInto;
+use core::fmt;
+use core::ops::{Add, Mul, Neg, Sub};
+use ff::PrimeField;
+use pasta_curves::arithmetic::{FieldExt, Group, SqrtRatio};
+use rand::RngCore;
+use serde::{Deserialize, Serialize};
+use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
+
+/// This represents an element of $\mathbb{F}_r$ where
+///
+/// `r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001`
+///
+/// is the scalar field of the BN254 curve.
+// The internal representation of this type is four 64-bit unsigned
+// integers in little-endian order. `Fr` values are always in
+// Montgomery form; i.e., Fr(a) = aR mod r, with R = 2^256.
+#[derive(Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
+// PartialEq is derived for Hash, but if privacy perservation is needed, then constant time functions should be used:
+// see NCC-E001151-003 in https://research.nccgroup.com/2021/11/02/public-report-zcash-nu5-cryptography-review/
+pub struct Fr(pub(crate) [u64; 4]);
+
+/// Constant representing the modulus
+/// r = 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001
+pub const MODULUS: Fr = Fr([
+    0x43e1f593f0000001,
+    0x2833e84879b97091,
+    0xb85045b68181585d,
+    0x30644e72e131a029,
+]);
+
+const MODULUS_STR: &str = "0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001";
+
+/// INV = -(r^{-1} mod 2^64) mod 2^64
+const INV: u64 = 0xc2e1f593efffffff;
+
+/// `R = 2^256 mod r`
+/// `0xe0a77c19a07df2f666ea36f7879462e36fc76959f60cd29ac96341c4ffffffb`
+const R: Fr = Fr([
+    0xac96341c4ffffffb,
+    0x36fc76959f60cd29,
+    0x666ea36f7879462e,
+    0x0e0a77c19a07df2f,
+]);
+
+/// `R^2 = 2^512 mod r`
+/// `0x216d0b17f4e44a58c49833d53bb808553fe3ab1e35c59e31bb8e645ae216da7`
+const R2: Fr = Fr([
+    0x1bb8e645ae216da7,
+    0x53fe3ab1e35c59e3,
+    0x8c49833d53bb8085,
+    0x0216d0b17f4e44a5,
+]);
+
+/// `R^3 = 2^768 mod r`
+/// `0xcf8594b7fcc657c893cc664a19fcfed2a489cbe1cfbb6b85e94d8e1b4bf0040`
+const R3: Fr = Fr([
+    0x5e94d8e1b4bf0040,
+    0x2a489cbe1cfbb6b8,
+    0x893cc664a19fcfed,
+    0x0cf8594b7fcc657c,
+]);
+
+/// `GENERATOR = 7 mod r` is a generator of the `r - 1` order multiplicative
+/// subgroup, or in other words a primitive root of the field.
+const GENERATOR: Fr = Fr::from_raw([0x07, 0x00, 0x00, 0x00]);
+
+const S: u32 = 28;
+
+/// GENERATOR^t where t * 2^s + 1 = r
+/// with t odd. In other words, this
+/// is a 2^s root of unity.
+/// `0x3ddb9f5166d18b798865ea93dd31f743215cf6dd39329c8d34f1ed960c37c9c`
+const ROOT_OF_UNITY: Fr = Fr::from_raw([
+    0xd34f1ed960c37c9c,
+    0x3215cf6dd39329c8,
+    0x98865ea93dd31f74,
+    0x03ddb9f5166d18b7,
+]);
+
+/// 1 / 2 mod r
+const TWO_INV: Fr = Fr::from_raw([
+    0xa1f0fac9f8000001,
+    0x9419f4243cdcb848,
+    0xdc2822db40c0ac2e,
+    0x183227397098d014,
+]);
+
+/// 1 / ROOT_OF_UNITY mod r
+const ROOT_OF_UNITY_INV: Fr = Fr::from_raw([
+    0x0ed3e50a414e6dba,
+    0xb22625f59115aba7,
+    0x1bbe587180f34361,
+    0x048127174daabc26,
+]);
+
+/// GENERATOR^{2^s} where t * 2^s + 1 = r
+/// with t odd. In other words, this
+/// is a t root of unity.
+// 0x09226b6e22c6f0ca64ec26aad4c86e715b5f898e5e963f25870e56bbe533e9a2
+const DELTA: Fr = Fr::from_raw([
+    0x870e56bbe533e9a2,
+    0x5b5f898e5e963f25,
+    0x64ec26aad4c86e71,
+    0x09226b6e22c6f0ca,
+]);
+
+/// `ZETA^3 = 1 mod r` where `ZETA^2 != 1 mod r`
+const ZETA: Fr = Fr::from_raw([
+    0xb8ca0b2d36636f23,
+    0xcc37a73fec2bc5e9,
+    0x048b6e193fd84104,
+    0x30644e72e131a029,
+]);
+
+use crate::{
+    field_arithmetic, field_common, field_specific, impl_add_binop_specify_output,
+    impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative,
+    impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
+};
+impl_binops_additive!(Fr, Fr);
+impl_binops_multiplicative!(Fr, Fr);
+#[cfg(not(feature = "asm"))]
+field_common!(
+    Fr,
+    MODULUS,
+    INV,
+    MODULUS_STR,
+    TWO_INV,
+    ROOT_OF_UNITY_INV,
+    DELTA,
+    ZETA,
+    R,
+    R2,
+    R3
+);
+#[cfg(not(feature = "asm"))]
+field_arithmetic!(Fr, MODULUS, INV, sparse);
+#[cfg(feature = "asm")]
+assembly_field!(
+    Fr,
+    MODULUS,
+    INV,
+    MODULUS_STR,
+    TWO_INV,
+    ROOT_OF_UNITY_INV,
+    DELTA,
+    ZETA,
+    R,
+    R2,
+    R3
+);
+
+impl ff::Field for Fr {
+    fn random(mut rng: impl RngCore) -> Self {
+        Self::from_u512([
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+        ])
+    }
+
+    fn zero() -> Self {
+        Self::zero()
+    }
+
+    fn one() -> Self {
+        Self::one()
+    }
+
+    fn double(&self) -> Self {
+        self.double()
+    }
+
+    fn is_zero_vartime(&self) -> bool {
+        self == &Self::zero()
+    }
+
+    #[inline(always)]
+    fn square(&self) -> Self {
+        self.square()
+    }
+
+    /// Computes the square root of this element, if it exists.
+    fn sqrt(&self) -> CtOption<Self> {
+        crate::arithmetic::sqrt_tonelli_shanks(self, <Self as SqrtRatio>::T_MINUS1_OVER2)
+    }
+
+    /// Computes the multiplicative inverse of this element,
+    /// failing if the element is zero.
+    fn invert(&self) -> CtOption<Self> {
+        let tmp = self.pow(&[
+            0x43e1f593efffffff,
+            0x2833e84879b97091,
+            0xb85045b68181585d,
+            0x30644e72e131a029,
+        ]);
+
+        CtOption::new(tmp, !self.ct_eq(&Self::zero()))
+    }
+}
+
+impl ff::PrimeField for Fr {
+    type Repr = [u8; 32];
+
+    const NUM_BITS: u32 = 254;
+    const CAPACITY: u32 = 253;
+    const S: u32 = S;
+
+    fn from_repr(repr: Self::Repr) -> CtOption<Self> {
+        let mut tmp = Fr([0, 0, 0, 0]);
+
+        tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap());
+        tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap());
+        tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap());
+        tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap());
+
+        // Try to subtract the modulus
+        let (_, borrow) = tmp.0[0].overflowing_sub(MODULUS.0[0]);
+        let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow);
+        let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow);
+        let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow);
+
+        // If the element is smaller than MODULUS then the
+        // subtraction will underflow, producing a borrow value
+        // of 0xffff...ffff. Otherwise, it'll be zero.
+        let is_some = (borrow as u8) & 1;
+
+        // Convert to Montgomery form by computing
+        // (a.R^0 * R^2) / R = a.R
+        tmp *= &R2;
+
+        CtOption::new(tmp, Choice::from(is_some))
+    }
+
+    fn to_repr(&self) -> Self::Repr {
+        // Turn into canonical form by computing
+        // (a.R) / R = a
+        #[cfg(feature = "asm")]
+        let tmp = Fr::montgomery_reduce(&[self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0]);
+
+        #[cfg(not(feature = "asm"))]
+        let tmp = Fr::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]);
+
+        let mut res = [0; 32];
+        res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes());
+        res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes());
+        res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes());
+        res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes());
+
+        res
+    }
+
+    fn is_odd(&self) -> Choice {
+        Choice::from(self.to_repr()[0] & 1)
+    }
+
+    fn multiplicative_generator() -> Self {
+        GENERATOR
+    }
+
+    fn root_of_unity() -> Self {
+        ROOT_OF_UNITY
+    }
+}
+
+impl SqrtRatio for Fr {
+    /// `(t - 1) // 2` where t * 2^s + 1 = p with t odd.
+    const T_MINUS1_OVER2: [u64; 4] = [
+        0xcdcb848a1f0fac9f,
+        0x0c0ac2e9419f4243,
+        0x098d014dc2822db4,
+        0x0000000183227397,
+    ];
+
+    fn get_lower_32(&self) -> u32 {
+        #[cfg(not(feature = "asm"))]
+        let tmp = Fr::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]);
+
+        #[cfg(feature = "asm")]
+        let tmp = Fr::montgomery_reduce(&[self.0[0], self.0[1], self.0[2], self.0[3], 0, 0, 0, 0]);
+
+        tmp.0[0] as u32
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use ff::Field;
+    use rand_core::OsRng;
+
+    #[test]
+    fn test_sqrt() {
+        let v = (Fr::TWO_INV).square().sqrt().unwrap();
+        assert!(v == Fr::TWO_INV || (-v) == Fr::TWO_INV);
+
+        for _ in 0..10000 {
+            let a = Fr::random(OsRng);
+            let mut b = a;
+            b = b.square();
+
+            let b = b.sqrt().unwrap();
+            let mut negb = b;
+            negb = negb.neg();
+
+            assert!(a == b || a == negb);
+        }
+    }
+
+    #[test]
+    fn test_root_of_unity() {
+        assert_eq!(
+            Fr::root_of_unity().pow_vartime([1 << Fr::S, 0, 0, 0]),
+            Fr::one()
+        );
+    }
+
+    #[test]
+    fn test_inv_root_of_unity() {
+        assert_eq!(Fr::ROOT_OF_UNITY_INV, Fr::root_of_unity().invert().unwrap());
+    }
+
+    #[test]
+    fn test_field() {
+        crate::tests::field::random_field_tests::<Fr>("bn256 scalar".to_string());
+    }
+
+    #[test]
+    fn test_delta() {
+        assert_eq!(Fr::DELTA, GENERATOR.pow(&[1u64 << Fr::S, 0, 0, 0]));
+        assert_eq!(
+            Fr::DELTA,
+            Fr::multiplicative_generator().pow(&[1u64 << Fr::S, 0, 0, 0])
+        );
+    }
+
+    #[test]
+    fn test_from_u512() {
+        assert_eq!(
+            Fr::from_raw([
+                0x7e7140b5196b9e6f,
+                0x9abac9e4157b6172,
+                0xf04bc41062fd7322,
+                0x1185fa9c9fef6326,
+            ]),
+            Fr::from_u512([
+                0xaaaaaaaaaaaaaaaa,
+                0xaaaaaaaaaaaaaaaa,
+                0xaaaaaaaaaaaaaaaa,
+                0xaaaaaaaaaaaaaaaa,
+                0xaaaaaaaaaaaaaaaa,
+                0xaaaaaaaaaaaaaaaa,
+                0xaaaaaaaaaaaaaaaa,
+                0xaaaaaaaaaaaaaaaa
+            ])
+        );
+    }
+
+    #[test]
+    fn test_serialization() {
+        crate::tests::field::random_serialization_test::<Fr>("fr".to_string());
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/bn256/mod.rs.html b/docs/src/halo2curves/bn256/mod.rs.html new file mode 100644 index 0000000000..e0c8e3bc6e --- /dev/null +++ b/docs/src/halo2curves/bn256/mod.rs.html @@ -0,0 +1,52 @@ +mod.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+
mod curve;
+mod engine;
+mod fq;
+mod fq12;
+mod fq2;
+mod fq6;
+mod fr;
+
+#[cfg(feature = "asm")]
+mod assembly;
+
+pub use curve::*;
+pub use engine::*;
+pub use fq::*;
+pub use fq12::*;
+pub use fq2::*;
+pub use fq6::*;
+pub use fr::*;
+
+#[derive(Debug, PartialEq, Eq)]
+pub enum LegendreSymbol {
+    Zero = 0,
+    QuadraticResidue = 1,
+    QuadraticNonResidue = -1,
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/derive/curve.rs.html b/docs/src/halo2curves/derive/curve.rs.html new file mode 100644 index 0000000000..461f7bb5bd --- /dev/null +++ b/docs/src/halo2curves/derive/curve.rs.html @@ -0,0 +1,2088 @@ +curve.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+
#[macro_export]
+macro_rules! batch_add {
+    () => {
+        fn batch_add<const COMPLETE: bool, const LOAD_POINTS: bool>(
+            points: &mut [Self],
+            output_indices: &[u32],
+            num_points: usize,
+            offset: usize,
+            bases: &[Self],
+            base_positions: &[u32],
+        ) {
+            // assert!(Self::constant_a().is_zero());
+
+            let get_point = |point_data: u32| -> Self {
+                let negate = point_data & 0x80000000 != 0;
+                let base_idx = (point_data & 0x7FFFFFFF) as usize;
+                if negate {
+                    bases[base_idx].neg()
+                } else {
+                    bases[base_idx]
+                }
+            };
+
+            // Affine addition formula (P != Q):
+            // - lambda = (y_2 - y_1) / (x_2 - x_1)
+            // - x_3 = lambda^2 - (x_2 + x_1)
+            // - y_3 = lambda * (x_1 - x_3) - y_1
+
+            // Batch invert accumulator
+            let mut acc = Self::Base::one();
+
+            for i in (0..num_points).step_by(2) {
+                // Where that result of the point addition will be stored
+                let out_idx = output_indices[i >> 1] as usize - offset;
+
+                #[cfg(all(feature = "prefetch", target_arch = "x86_64"))]
+                if i < num_points - 2 {
+                    if LOAD_POINTS {
+                        $crate::prefetch::<Self>(bases, base_positions[i + 2] as usize);
+                        $crate::prefetch::<Self>(bases, base_positions[i + 3] as usize);
+                    }
+                    $crate::prefetch::<Self>(
+                        points,
+                        output_indices[(i >> 1) + 1] as usize - offset,
+                    );
+                }
+                if LOAD_POINTS {
+                    points[i] = get_point(base_positions[i]);
+                    points[i + 1] = get_point(base_positions[i + 1]);
+                }
+
+                if COMPLETE {
+                    // Nothing to do here if one of the points is zero
+                    if (points[i].is_identity() | points[i + 1].is_identity()).into() {
+                        continue;
+                    }
+
+                    if points[i].x == points[i + 1].x {
+                        if points[i].y == points[i + 1].y {
+                            // Point doubling (P == Q)
+                            // - s = (3 * x^2) / (2 * y)
+                            // - x_2 = s^2 - (2 * x)
+                            // - y_2 = s * (x - x_2) - y
+
+                            // (2 * x)
+                            points[out_idx].x = points[i].x + points[i].x;
+                            // x^2
+                            let xx = points[i].x.square();
+                            // (2 * y)
+                            points[i + 1].x = points[i].y + points[i].y;
+                            // (3 * x^2) * acc
+                            points[i + 1].y = (xx + xx + xx) * acc;
+                            // acc * (2 * y)
+                            acc *= points[i + 1].x;
+                            continue;
+                        } else {
+                            // Zero
+                            points[i] = Self::identity();
+                            points[i + 1] = Self::identity();
+                            continue;
+                        }
+                    }
+                }
+
+                // (x_2 + x_1)
+                points[out_idx].x = points[i].x + points[i + 1].x;
+                // (x_2 - x_1)
+                points[i + 1].x -= points[i].x;
+                // (y2 - y1) * acc
+                points[i + 1].y = (points[i + 1].y - points[i].y) * acc;
+                // acc * (x_2 - x_1)
+                acc *= points[i + 1].x;
+            }
+
+            // Batch invert
+            if COMPLETE {
+                if (!acc.is_zero()).into() {
+                    acc = acc.invert().unwrap();
+                }
+            } else {
+                acc = acc.invert().unwrap();
+            }
+
+            for i in (0..num_points).step_by(2).rev() {
+                // Where that result of the point addition will be stored
+                let out_idx = output_indices[i >> 1] as usize - offset;
+
+                #[cfg(all(feature = "prefetch", target_arch = "x86_64"))]
+                if i > 0 {
+                    $crate::prefetch::<Self>(
+                        points,
+                        output_indices[(i >> 1) - 1] as usize - offset,
+                    );
+                }
+
+                if COMPLETE {
+                    // points[i] is zero so the sum is points[i + 1]
+                    if points[i].is_identity().into() {
+                        points[out_idx] = points[i + 1];
+                        continue;
+                    }
+                    // points[i + 1] is zero so the sum is points[i]
+                    if points[i + 1].is_identity().into() {
+                        points[out_idx] = points[i];
+                        continue;
+                    }
+                }
+
+                // lambda
+                points[i + 1].y *= acc;
+                // acc * (x_2 - x_1)
+                acc *= points[i + 1].x;
+                // x_3 = lambda^2 - (x_2 + x_1)
+                points[out_idx].x = points[i + 1].y.square() - points[out_idx].x;
+                // y_3 = lambda * (x_1 - x_3) - y_1
+                points[out_idx].y =
+                    points[i + 1].y * (points[i].x - points[out_idx].x) - points[i].y;
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! new_curve_impl {
+    (($($privacy:tt)*),
+    $name:ident,
+    $name_affine:ident,
+    $name_compressed:ident,
+    $compressed_size:expr,
+    $base:ident,
+    $scalar:ident,
+    $generator:expr,
+    $constant_b:expr,
+    $curve_id:literal,
+    ) => {
+
+        #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
+        $($privacy)* struct $name {
+            pub x: $base,
+            pub y: $base,
+            pub z: $base,
+        }
+
+        #[derive(Copy, Clone, PartialEq, Hash, Serialize, Deserialize)]
+        $($privacy)* struct $name_affine {
+            pub x: $base,
+            pub y: $base,
+        }
+
+        #[derive(Copy, Clone, Hash)]
+        $($privacy)* struct $name_compressed([u8; $compressed_size]);
+
+        impl $name {
+            pub fn generator() -> Self {
+                let generator = $name_affine::generator();
+                Self {
+                    x: generator.x,
+                    y: generator.y,
+                    z: $base::one(),
+                }
+            }
+
+            const fn curve_constant_b() -> $base {
+                $name_affine::curve_constant_b()
+            }
+        }
+
+        impl $name_affine {
+            pub fn generator() -> Self {
+                Self {
+                    x: $generator.0,
+                    y: $generator.1,
+                }
+            }
+
+            const fn curve_constant_b() -> $base {
+                $constant_b
+            }
+
+            pub fn random(mut rng: impl RngCore) -> Self {
+                loop {
+                    let x = $base::random(&mut rng);
+                    let ysign = (rng.next_u32() % 2) as u8;
+
+                    let x3 = x.square() * x;
+                    let y = (x3 + $name::curve_constant_b()).sqrt();
+                    if let Some(y) = Option::<$base>::from(y) {
+                        let sign = y.to_bytes()[0] & 1;
+                        let y = if ysign ^ sign == 0 { y } else { -y };
+
+                        let p = $name_affine {
+                            x,
+                            y,
+                        };
+
+
+                        use $crate::group::cofactor::CofactorGroup;
+                        let p = p.to_curve();
+                        return p.clear_cofactor().to_affine()
+                    }
+                }
+            }
+        }
+
+        // Compressed
+
+        impl std::fmt::Debug for $name_compressed {
+            fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
+                self.0[..].fmt(f)
+            }
+        }
+
+        impl Default for $name_compressed {
+            fn default() -> Self {
+                $name_compressed([0; $compressed_size])
+            }
+        }
+
+        impl AsRef<[u8]> for $name_compressed {
+            fn as_ref(&self) -> &[u8] {
+                &self.0
+            }
+        }
+
+        impl AsMut<[u8]> for $name_compressed {
+            fn as_mut(&mut self) -> &mut [u8] {
+                &mut self.0
+            }
+        }
+
+
+        // Jacobian implementations
+
+        impl<'a> From<&'a $name_affine> for $name {
+            fn from(p: &'a $name_affine) -> $name {
+                p.to_curve()
+            }
+        }
+
+        impl From<$name_affine> for $name {
+            fn from(p: $name_affine) -> $name {
+                p.to_curve()
+            }
+        }
+
+        impl Default for $name {
+            fn default() -> $name {
+                $name::identity()
+            }
+        }
+
+        impl subtle::ConstantTimeEq for $name {
+            fn ct_eq(&self, other: &Self) -> Choice {
+                // Is (xz^2, yz^3, z) equal to (x'z'^2, yz'^3, z') when converted to affine?
+
+                let z = other.z.square();
+                let x1 = self.x * z;
+                let z = z * other.z;
+                let y1 = self.y * z;
+                let z = self.z.square();
+                let x2 = other.x * z;
+                let z = z * self.z;
+                let y2 = other.y * z;
+
+                let self_is_zero = self.is_identity();
+                let other_is_zero = other.is_identity();
+
+                (self_is_zero & other_is_zero) // Both point at infinity
+                            | ((!self_is_zero) & (!other_is_zero) & x1.ct_eq(&x2) & y1.ct_eq(&y2))
+                // Neither point at infinity, coordinates are the same
+            }
+
+        }
+
+        impl subtle::ConditionallySelectable for $name {
+            fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
+                $name {
+                    x: $base::conditional_select(&a.x, &b.x, choice),
+                    y: $base::conditional_select(&a.y, &b.y, choice),
+                    z: $base::conditional_select(&a.z, &b.z, choice),
+                }
+            }
+        }
+
+        impl PartialEq for $name {
+            fn eq(&self, other: &Self) -> bool {
+                self.ct_eq(other).into()
+            }
+        }
+
+        impl cmp::Eq for $name {}
+
+        impl CurveExt for $name {
+
+            type ScalarExt = $scalar;
+            type Base = $base;
+            type AffineExt = $name_affine;
+
+            const CURVE_ID: &'static str = $curve_id;
+
+            fn endo(&self) -> Self {
+                self.endomorphism_base()
+            }
+
+            fn jacobian_coordinates(&self) -> ($base, $base, $base) {
+               (self.x, self.y, self.z)
+            }
+
+
+            fn hash_to_curve<'a>(_: &'a str) -> Box<dyn Fn(&[u8]) -> Self + 'a> {
+                unimplemented!();
+            }
+
+            fn is_on_curve(&self) -> Choice {
+
+                let z2 = self.z.square();
+                let z4 = z2.square();
+                let z6 = z4 * z2;
+                (self.y.square() - self.x.square() * self.x)
+                    .ct_eq(&(z6 * $name::curve_constant_b()))
+                    | self.z.is_zero()
+            }
+
+            fn b() -> Self::Base {
+                $name::curve_constant_b()
+            }
+
+            fn a() -> Self::Base {
+                Self::Base::zero()
+            }
+
+            fn new_jacobian(x: Self::Base, y: Self::Base, z: Self::Base) -> CtOption<Self> {
+                let p = $name { x, y, z };
+                CtOption::new(p, p.is_on_curve())
+            }
+        }
+
+        impl group::Curve for $name {
+
+            type AffineRepr = $name_affine;
+
+            fn batch_normalize(p: &[Self], q: &mut [Self::AffineRepr]) {
+                assert_eq!(p.len(), q.len());
+
+                let mut acc = $base::one();
+                for (p, q) in p.iter().zip(q.iter_mut()) {
+                    // We use the `x` field of $name_affine to store the product
+                    // of previous z-coordinates seen.
+                    q.x = acc;
+
+                    // We will end up skipping all identities in p
+                    acc = $base::conditional_select(&(acc * p.z), &acc, p.is_identity());
+                }
+
+                // This is the inverse, as all z-coordinates are nonzero and the ones
+                // that are not are skipped.
+                acc = acc.invert().unwrap();
+
+                for (p, q) in p.iter().rev().zip(q.iter_mut().rev()) {
+                    let skip = p.is_identity();
+
+                    // Compute tmp = 1/z
+                    let tmp = q.x * acc;
+
+                    // Cancel out z-coordinate in denominator of `acc`
+                    acc = $base::conditional_select(&(acc * p.z), &acc, skip);
+
+                    // Set the coordinates to the correct value
+                    let tmp2 = tmp.square();
+                    let tmp3 = tmp2 * tmp;
+
+                    q.x = p.x * tmp2;
+                    q.y = p.y * tmp3;
+
+                    *q = $name_affine::conditional_select(&q, &$name_affine::identity(), skip);
+                }
+            }
+
+            fn to_affine(&self) -> Self::AffineRepr {
+                let zinv = self.z.invert().unwrap_or($base::zero());
+                let zinv2 = zinv.square();
+                let x = self.x * zinv2;
+                let zinv3 = zinv2 * zinv;
+                let y = self.y * zinv3;
+
+                let tmp = $name_affine {
+                    x,
+                    y,
+                };
+
+                $name_affine::conditional_select(&tmp, &$name_affine::identity(), zinv.is_zero())
+            }
+        }
+
+        impl group::Group for $name {
+            type Scalar = $scalar;
+
+            fn random(mut rng: impl RngCore) -> Self {
+                $name_affine::random(&mut rng).to_curve()
+            }
+
+            fn double(&self) -> Self {
+                let a = self.x.square();
+                let b = self.y.square();
+                let c = b.square();
+                let d = self.x + b;
+                let d = d.square();
+                let d = d - a - c;
+                let d = d + d;
+                let e = a + a + a;
+                let f = e.square();
+                let z3 = self.z * self.y;
+                let z3 = z3 + z3;
+                let x3 = f - (d + d);
+                let c = c + c;
+                let c = c + c;
+                let c = c + c;
+                let y3 = e * (d - x3) - c;
+
+                let tmp = $name {
+                    x: x3,
+                    y: y3,
+                    z: z3,
+                };
+
+                $name::conditional_select(&tmp, &$name::identity(), self.is_identity())
+            }
+
+            fn generator() -> Self {
+                $name::generator()
+            }
+
+            fn identity() -> Self {
+                Self {
+                    x: $base::zero(),
+                    y: $base::zero(),
+                    z: $base::zero(),
+                }
+            }
+
+            fn is_identity(&self) -> Choice {
+                self.z.is_zero()
+            }
+        }
+
+        impl GroupEncoding for $name {
+            type Repr = $name_compressed;
+
+            fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
+                $name_affine::from_bytes(bytes).map(Self::from)
+            }
+
+            fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
+                $name_affine::from_bytes(bytes).map(Self::from)
+            }
+
+            fn to_bytes(&self) -> Self::Repr {
+                $name_affine::from(self).to_bytes()
+            }
+        }
+
+        impl $crate::serde::SerdeObject for $name {
+            fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self {
+                debug_assert_eq!(bytes.len(), 3 * $base::size());
+                let [x, y, z] = [0, 1, 2]
+                    .map(|i| $base::from_raw_bytes_unchecked(&bytes[i * $base::size()..(i + 1) * $base::size()]));
+                Self { x, y, z }
+            }
+            fn from_raw_bytes(bytes: &[u8]) -> Option<Self> {
+                if bytes.len() != 3 * $base::size() {
+                    return None;
+                }
+                let [x, y, z] =
+                    [0, 1, 2].map(|i| $base::from_raw_bytes(&bytes[i * $base::size()..(i + 1) * $base::size()]));
+                x.zip(y).zip(z).and_then(|((x, y), z)| {
+                    let res = Self { x, y, z };
+                    // Check that the point is on the curve.
+                    bool::from(res.is_on_curve()).then(|| res)
+                })
+            }
+            fn to_raw_bytes(&self) -> Vec<u8> {
+                let mut res = Vec::with_capacity(3 * $base::size());
+                Self::write_raw(self, &mut res).unwrap();
+                res
+            }
+            fn read_raw_unchecked<R: std::io::Read>(reader: &mut R) -> Self {
+                let [x, y, z] = [(); 3].map(|_| $base::read_raw_unchecked(reader));
+                Self { x, y, z }
+            }
+            fn read_raw<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
+                let x = $base::read_raw(reader)?;
+                let y = $base::read_raw(reader)?;
+                let z = $base::read_raw(reader)?;
+                Ok(Self { x, y, z })
+            }
+            fn write_raw<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
+                self.x.write_raw(writer)?;
+                self.y.write_raw(writer)?;
+                self.z.write_raw(writer)
+            }
+        }
+
+        impl group::prime::PrimeGroup for $name {}
+
+        impl group::prime::PrimeCurve for $name {
+            type Affine = $name_affine;
+        }
+
+        impl group::cofactor::CofactorCurve for $name {
+            type Affine = $name_affine;
+        }
+
+        impl Group for $name {
+            type Scalar = $scalar;
+
+            fn group_zero() -> Self {
+                Self::identity()
+            }
+            fn group_add(&mut self, rhs: &Self) {
+                *self += *rhs;
+            }
+            fn group_sub(&mut self, rhs: &Self) {
+                *self -= *rhs;
+            }
+            fn group_scale(&mut self, by: &Self::Scalar) {
+                *self *= *by;
+            }
+        }
+
+        // Affine implementations
+
+        impl std::fmt::Debug for $name_affine {
+            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+                if self.is_identity().into() {
+                    write!(f, "Infinity")
+                } else {
+                    write!(f, "({:?}, {:?})", self.x, self.y)
+                }
+            }
+        }
+
+        impl<'a> From<&'a $name> for $name_affine {
+            fn from(p: &'a $name) -> $name_affine {
+                p.to_affine()
+            }
+        }
+
+        impl From<$name> for $name_affine {
+            fn from(p: $name) -> $name_affine {
+                p.to_affine()
+            }
+        }
+
+        impl Default for $name_affine {
+            fn default() -> $name_affine {
+                $name_affine::identity()
+            }
+        }
+
+        impl subtle::ConstantTimeEq for $name_affine {
+            fn ct_eq(&self, other: &Self) -> Choice {
+                let z1 = self.is_identity();
+                let z2 = other.is_identity();
+
+                (z1 & z2) | ((!z1) & (!z2) & (self.x.ct_eq(&other.x)) & (self.y.ct_eq(&other.y)))
+            }
+        }
+
+        impl subtle::ConditionallySelectable for $name_affine {
+            fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
+                $name_affine {
+                    x: $base::conditional_select(&a.x, &b.x, choice),
+                    y: $base::conditional_select(&a.y, &b.y, choice),
+                }
+            }
+        }
+
+        impl cmp::Eq for $name_affine {}
+
+        impl group::GroupEncoding for $name_affine {
+            type Repr = $name_compressed;
+
+            fn from_bytes(bytes: &Self::Repr) -> CtOption<Self> {
+                let bytes = &bytes.0;
+                let mut tmp = *bytes;
+                let ysign = Choice::from(tmp[$compressed_size - 1] >> 7);
+                tmp[$compressed_size - 1] &= 0b0111_1111;
+                let mut xbytes = [0u8; $base::size()];
+                xbytes.copy_from_slice(&tmp[ ..$base::size()]);
+
+                $base::from_bytes(&xbytes).and_then(|x| {
+                    CtOption::new(Self::identity(), x.is_zero() & (!ysign)).or_else(|| {
+                        let x3 = x.square() * x;
+                        (x3 + $name::curve_constant_b()).sqrt().and_then(|y| {
+                            let sign = Choice::from(y.to_bytes()[0] & 1);
+
+                            let y = $base::conditional_select(&y, &-y, ysign ^ sign);
+
+                            CtOption::new(
+                                $name_affine {
+                                    x,
+                                    y,
+                                },
+                                Choice::from(1u8),
+                            )
+                        })
+                    })
+                })
+            }
+
+            fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption<Self> {
+                Self::from_bytes(bytes)
+            }
+
+            fn to_bytes(&self) -> Self::Repr {
+                if bool::from(self.is_identity()) {
+                    $name_compressed::default()
+                } else {
+                    let (x, y) = (self.x, self.y);
+                    let sign = (y.to_bytes()[0] & 1) << 7;
+                    let mut xbytes = [0u8; $compressed_size];
+                    xbytes[..$base::size()].copy_from_slice(&x.to_bytes());
+                    xbytes[$compressed_size - 1] |= sign;
+                    $name_compressed(xbytes)
+                }
+            }
+        }
+
+        impl $crate::serde::SerdeObject for $name_affine {
+            fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self {
+                debug_assert_eq!(bytes.len(), 2 * $base::size());
+                let [x, y] =
+                    [0, $base::size()].map(|i| $base::from_raw_bytes_unchecked(&bytes[i..i + $base::size()]));
+                Self { x, y }
+            }
+            fn from_raw_bytes(bytes: &[u8]) -> Option<Self> {
+                if bytes.len() != 2 * $base::size() {
+                    return None;
+                }
+                let [x, y] = [0, $base::size()].map(|i| $base::from_raw_bytes(&bytes[i..i + $base::size()]));
+                x.zip(y).and_then(|(x, y)| {
+                    let res = Self { x, y };
+                    // Check that the point is on the curve.
+                    bool::from(res.is_on_curve()).then(|| res)
+                })
+            }
+            fn to_raw_bytes(&self) -> Vec<u8> {
+                let mut res = Vec::with_capacity(2 * $base::size());
+                Self::write_raw(self, &mut res).unwrap();
+                res
+            }
+            fn read_raw_unchecked<R: std::io::Read>(reader: &mut R) -> Self {
+                let [x, y] = [(); 2].map(|_| $base::read_raw_unchecked(reader));
+                Self { x, y }
+            }
+            fn read_raw<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
+                let x = $base::read_raw(reader)?;
+                let y = $base::read_raw(reader)?;
+                Ok(Self { x, y })
+            }
+            fn write_raw<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
+                self.x.write_raw(writer)?;
+                self.y.write_raw(writer)
+            }
+        }
+
+        impl group::prime::PrimeCurveAffine for $name_affine {
+            type Curve = $name;
+            type Scalar = $scalar;
+
+
+            fn generator() -> Self {
+                $name_affine::generator()
+            }
+
+            fn identity() -> Self {
+                Self {
+                    x: $base::zero(),
+                    y: $base::zero(),
+                }
+            }
+
+            fn is_identity(&self) -> Choice {
+                self.x.is_zero() & self.y.is_zero()
+            }
+
+            fn to_curve(&self) -> Self::Curve {
+                $name {
+                    x: self.x,
+                    y: self.y,
+                    z: $base::conditional_select(&$base::one(), &$base::zero(), self.is_identity()),
+                }
+            }
+        }
+
+        impl group::cofactor::CofactorCurveAffine for $name_affine {
+            type Curve = $name;
+            type Scalar = $scalar;
+
+            fn identity() -> Self {
+                <Self as group::prime::PrimeCurveAffine>::identity()
+            }
+
+            fn generator() -> Self {
+                <Self as group::prime::PrimeCurveAffine>::generator()
+            }
+
+            fn is_identity(&self) -> Choice {
+                <Self as group::prime::PrimeCurveAffine>::is_identity(self)
+            }
+
+            fn to_curve(&self) -> Self::Curve {
+                <Self as group::prime::PrimeCurveAffine>::to_curve(self)
+            }
+        }
+
+
+        impl CurveAffine for $name_affine {
+            type ScalarExt = $scalar;
+            type Base = $base;
+            type CurveExt = $name;
+
+            fn is_on_curve(&self) -> Choice {
+                // y^2 - x^3 - ax ?= b
+                (self.y.square() - self.x.square() * self.x).ct_eq(&$name::curve_constant_b())
+                    | self.is_identity()
+            }
+
+            fn coordinates(&self) -> CtOption<Coordinates<Self>> {
+                Coordinates::from_xy( self.x, self.y )
+            }
+
+            fn from_xy(x: Self::Base, y: Self::Base) -> CtOption<Self> {
+                let p = $name_affine {
+                    x, y
+                };
+                CtOption::new(p, p.is_on_curve())
+            }
+
+            fn a() -> Self::Base {
+                Self::Base::zero()
+            }
+
+            fn b() -> Self::Base {
+                $name::curve_constant_b()
+            }
+        }
+
+
+        impl_binops_additive!($name, $name);
+        impl_binops_additive!($name, $name_affine);
+        impl_binops_additive_specify_output!($name_affine, $name_affine, $name);
+        impl_binops_additive_specify_output!($name_affine, $name, $name);
+        impl_binops_multiplicative!($name, $scalar);
+        impl_binops_multiplicative_mixed!($name_affine, $scalar, $name);
+
+        impl<'a> Neg for &'a $name {
+            type Output = $name;
+
+            fn neg(self) -> $name {
+                $name {
+                    x: self.x,
+                    y: -self.y,
+                    z: self.z,
+                }
+            }
+        }
+
+        impl Neg for $name {
+            type Output = $name;
+
+            fn neg(self) -> $name {
+                -&self
+            }
+        }
+
+        impl<T> Sum<T> for $name
+        where
+            T: core::borrow::Borrow<$name>,
+        {
+            fn sum<I>(iter: I) -> Self
+            where
+                I: Iterator<Item = T>,
+            {
+                iter.fold(Self::identity(), |acc, item| acc + item.borrow())
+            }
+        }
+
+        impl<'a, 'b> Add<&'a $name> for &'b $name {
+            type Output = $name;
+
+            fn add(self, rhs: &'a $name) -> $name {
+                if bool::from(self.is_identity()) {
+                    *rhs
+                } else if bool::from(rhs.is_identity()) {
+                    *self
+                } else {
+                    let z1z1 = self.z.square();
+                    let z2z2 = rhs.z.square();
+                    let u1 = self.x * z2z2;
+                    let u2 = rhs.x * z1z1;
+                    let s1 = self.y * z2z2 * rhs.z;
+                    let s2 = rhs.y * z1z1 * self.z;
+
+                    if u1 == u2 {
+                        if s1 == s2 {
+                            self.double()
+                        } else {
+                            $name::identity()
+                        }
+                    } else {
+                        let h = u2 - u1;
+                        let i = (h + h).square();
+                        let j = h * i;
+                        let r = s2 - s1;
+                        let r = r + r;
+                        let v = u1 * i;
+                        let x3 = r.square() - j - v - v;
+                        let s1 = s1 * j;
+                        let s1 = s1 + s1;
+                        let y3 = r * (v - x3) - s1;
+                        let z3 = (self.z + rhs.z).square() - z1z1 - z2z2;
+                        let z3 = z3 * h;
+
+                        $name {
+                            x: x3, y: y3, z: z3
+                        }
+                    }
+                }
+            }
+        }
+
+        impl<'a, 'b> Add<&'a $name_affine> for &'b $name {
+            type Output = $name;
+
+            fn add(self, rhs: &'a $name_affine) -> $name {
+                if bool::from(self.is_identity()) {
+                    rhs.to_curve()
+                } else if bool::from(rhs.is_identity()) {
+                    *self
+                } else {
+                    let z1z1 = self.z.square();
+                    let u2 = rhs.x * z1z1;
+                    let s2 = rhs.y * z1z1 * self.z;
+
+                    if self.x == u2 {
+                        if self.y == s2 {
+                            self.double()
+                        } else {
+                            $name::identity()
+                        }
+                    } else {
+                        let h = u2 - self.x;
+                        let hh = h.square();
+                        let i = hh + hh;
+                        let i = i + i;
+                        let j = h * i;
+                        let r = s2 - self.y;
+                        let r = r + r;
+                        let v = self.x * i;
+                        let x3 = r.square() - j - v - v;
+                        let j = self.y * j;
+                        let j = j + j;
+                        let y3 = r * (v - x3) - j;
+                        let z3 = (self.z + h).square() - z1z1 - hh;
+
+                        $name {
+                            x: x3, y: y3, z: z3
+                        }
+                    }
+                }
+            }
+        }
+
+        impl<'a, 'b> Sub<&'a $name> for &'b $name {
+            type Output = $name;
+
+            fn sub(self, other: &'a $name) -> $name {
+                self + (-other)
+            }
+        }
+
+        impl<'a, 'b> Sub<&'a $name_affine> for &'b $name {
+            type Output = $name;
+
+            fn sub(self, other: &'a $name_affine) -> $name {
+                self + (-other)
+            }
+        }
+
+
+
+        #[allow(clippy::suspicious_arithmetic_impl)]
+        impl<'a, 'b> Mul<&'b $scalar> for &'a $name {
+            type Output = $name;
+
+            // This is a simple double-and-add implementation of point
+            // multiplication, moving from most significant to least
+            // significant bit of the scalar.
+
+            fn mul(self, other: &'b $scalar) -> Self::Output {
+                let mut acc = $name::identity();
+                for bit in other
+                    .to_repr()
+                    .iter()
+                    .rev()
+                    .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
+                {
+                    acc = acc.double();
+                    acc = $name::conditional_select(&acc, &(acc + self), bit);
+                }
+
+                acc
+            }
+        }
+
+        impl<'a> Neg for &'a $name_affine {
+            type Output = $name_affine;
+
+            fn neg(self) -> $name_affine {
+                $name_affine {
+                    x: self.x,
+                    y: -self.y,
+                }
+            }
+        }
+
+        impl Neg for $name_affine {
+            type Output = $name_affine;
+
+            fn neg(self) -> $name_affine {
+                -&self
+            }
+        }
+
+        impl<'a, 'b> Add<&'a $name> for &'b $name_affine {
+            type Output = $name;
+
+            fn add(self, rhs: &'a $name) -> $name {
+                rhs + self
+            }
+        }
+
+        impl<'a, 'b> Add<&'a $name_affine> for &'b $name_affine {
+            type Output = $name;
+
+            fn add(self, rhs: &'a $name_affine) -> $name {
+                if bool::from(self.is_identity()) {
+                    rhs.to_curve()
+                } else if bool::from(rhs.is_identity()) {
+                    self.to_curve()
+                } else {
+                    if self.x == rhs.x {
+                        if self.y == rhs.y {
+                            self.to_curve().double()
+                        } else {
+                            $name::identity()
+                        }
+                    } else {
+                        let h = rhs.x - self.x;
+                        let hh = h.square();
+                        let i = hh + hh;
+                        let i = i + i;
+                        let j = h * i;
+                        let r = rhs.y - self.y;
+                        let r = r + r;
+                        let v = self.x * i;
+                        let x3 = r.square() - j - v - v;
+                        let j = self.y * j;
+                        let j = j + j;
+                        let y3 = r * (v - x3) - j;
+                        let z3 = h + h;
+
+                        $name {
+                            x: x3, y: y3, z: z3
+                        }
+                    }
+                }
+            }
+        }
+
+        impl<'a, 'b> Sub<&'a $name_affine> for &'b $name_affine {
+            type Output = $name;
+
+            fn sub(self, other: &'a $name_affine) -> $name {
+                self + (-other)
+            }
+        }
+
+        impl<'a, 'b> Sub<&'a $name> for &'b $name_affine {
+            type Output = $name;
+
+            fn sub(self, other: &'a $name) -> $name {
+                self + (-other)
+            }
+        }
+
+        #[allow(clippy::suspicious_arithmetic_impl)]
+        impl<'a, 'b> Mul<&'b $scalar> for &'a $name_affine {
+            type Output = $name;
+
+            fn mul(self, other: &'b $scalar) -> Self::Output {
+                let mut acc = $name::identity();
+
+                // This is a simple double-and-add implementation of point
+                // multiplication, moving from most significant to least
+                // significant bit of the scalar.
+
+                for bit in other
+                    .to_repr()
+                    .iter()
+                    .rev()
+                    .flat_map(|byte| (0..8).rev().map(move |i| Choice::from((byte >> i) & 1u8)))
+                {
+                    acc = acc.double();
+                    acc = $name::conditional_select(&acc, &(acc + self), bit);
+                }
+
+                acc
+            }
+        }
+    };
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/derive/field.rs.html b/docs/src/halo2curves/derive/field.rs.html new file mode 100644 index 0000000000..44ea7d7fc1 --- /dev/null +++ b/docs/src/halo2curves/derive/field.rs.html @@ -0,0 +1,1474 @@ +field.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+
#[macro_export]
+macro_rules! field_common {
+    (
+        $field:ident,
+        $modulus:ident,
+        $inv:ident,
+        $modulus_str:ident,
+        $two_inv:ident,
+        $root_of_unity_inv:ident,
+        $delta:ident,
+        $zeta:ident,
+        $r:ident,
+        $r2:ident,
+        $r3:ident
+    ) => {
+        impl $field {
+            /// Returns zero, the additive identity.
+            #[inline]
+            pub const fn zero() -> $field {
+                $field([0, 0, 0, 0])
+            }
+
+            /// Returns one, the multiplicative identity.
+            #[inline]
+            pub const fn one() -> $field {
+                $r
+            }
+
+            fn from_u512(limbs: [u64; 8]) -> $field {
+                // We reduce an arbitrary 512-bit number by decomposing it into two 256-bit digits
+                // with the higher bits multiplied by 2^256. Thus, we perform two reductions
+                //
+                // 1. the lower bits are multiplied by R^2, as normal
+                // 2. the upper bits are multiplied by R^2 * 2^256 = R^3
+                //
+                // and computing their sum in the field. It remains to see that arbitrary 256-bit
+                // numbers can be placed into Montgomery form safely using the reduction. The
+                // reduction works so long as the product is less than R=2^256 multiplied by
+                // the modulus. This holds because for any `c` smaller than the modulus, we have
+                // that (2^256 - 1)*c is an acceptable product for the reduction. Therefore, the
+                // reduction always works so long as `c` is in the field; in this case it is either the
+                // constant `R2` or `R3`.
+                let d0 = $field([limbs[0], limbs[1], limbs[2], limbs[3]]);
+                let d1 = $field([limbs[4], limbs[5], limbs[6], limbs[7]]);
+                // Convert to Montgomery form
+                d0 * $r2 + d1 * $r3
+            }
+
+            /// Converts from an integer represented in little endian
+            /// into its (congruent) `$field` representation.
+            pub const fn from_raw(val: [u64; 4]) -> Self {
+                (&$field(val)).mul(&$r2)
+            }
+
+            /// Attempts to convert a little-endian byte representation of
+            /// a scalar into a `Fr`, failing if the input is not canonical.
+            pub fn from_bytes(bytes: &[u8; 32]) -> CtOption<$field> {
+                <Self as ff::PrimeField>::from_repr(*bytes)
+            }
+
+            /// Converts an element of `Fr` into a byte representation in
+            /// little-endian byte order.
+            pub fn to_bytes(&self) -> [u8; 32] {
+                <Self as ff::PrimeField>::to_repr(self)
+            }
+        }
+
+        impl Group for $field {
+            type Scalar = Self;
+
+            fn group_zero() -> Self {
+                Self::zero()
+            }
+            fn group_add(&mut self, rhs: &Self) {
+                *self += *rhs;
+            }
+            fn group_sub(&mut self, rhs: &Self) {
+                *self -= *rhs;
+            }
+            fn group_scale(&mut self, by: &Self::Scalar) {
+                *self *= *by;
+            }
+        }
+
+        impl fmt::Debug for $field {
+            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+                let tmp = self.to_repr();
+                write!(f, "0x")?;
+                for &b in tmp.iter().rev() {
+                    write!(f, "{:02x}", b)?;
+                }
+                Ok(())
+            }
+        }
+
+        impl Default for $field {
+            #[inline]
+            fn default() -> Self {
+                Self::zero()
+            }
+        }
+
+        impl From<bool> for $field {
+            fn from(bit: bool) -> $field {
+                if bit {
+                    $field::one()
+                } else {
+                    $field::zero()
+                }
+            }
+        }
+
+        impl From<u64> for $field {
+            fn from(val: u64) -> $field {
+                $field([val, 0, 0, 0]) * $r2
+            }
+        }
+
+        impl ConstantTimeEq for $field {
+            fn ct_eq(&self, other: &Self) -> Choice {
+                self.0[0].ct_eq(&other.0[0])
+                    & self.0[1].ct_eq(&other.0[1])
+                    & self.0[2].ct_eq(&other.0[2])
+                    & self.0[3].ct_eq(&other.0[3])
+            }
+        }
+
+        impl core::cmp::Ord for $field {
+            fn cmp(&self, other: &Self) -> core::cmp::Ordering {
+                let left = self.to_repr();
+                let right = other.to_repr();
+                left.iter()
+                    .zip(right.iter())
+                    .rev()
+                    .find_map(|(left_byte, right_byte)| match left_byte.cmp(right_byte) {
+                        core::cmp::Ordering::Equal => None,
+                        res => Some(res),
+                    })
+                    .unwrap_or(core::cmp::Ordering::Equal)
+            }
+        }
+
+        impl core::cmp::PartialOrd for $field {
+            fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
+                Some(self.cmp(other))
+            }
+        }
+
+        impl ConditionallySelectable for $field {
+            fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
+                $field([
+                    u64::conditional_select(&a.0[0], &b.0[0], choice),
+                    u64::conditional_select(&a.0[1], &b.0[1], choice),
+                    u64::conditional_select(&a.0[2], &b.0[2], choice),
+                    u64::conditional_select(&a.0[3], &b.0[3], choice),
+                ])
+            }
+        }
+
+        impl<'a> Neg for &'a $field {
+            type Output = $field;
+
+            #[inline]
+            fn neg(self) -> $field {
+                self.neg()
+            }
+        }
+
+        impl Neg for $field {
+            type Output = $field;
+
+            #[inline]
+            fn neg(self) -> $field {
+                -&self
+            }
+        }
+
+        impl<'a, 'b> Sub<&'b $field> for &'a $field {
+            type Output = $field;
+
+            #[inline]
+            fn sub(self, rhs: &'b $field) -> $field {
+                self.sub(rhs)
+            }
+        }
+
+        impl<'a, 'b> Add<&'b $field> for &'a $field {
+            type Output = $field;
+
+            #[inline]
+            fn add(self, rhs: &'b $field) -> $field {
+                self.add(rhs)
+            }
+        }
+
+        impl<'a, 'b> Mul<&'b $field> for &'a $field {
+            type Output = $field;
+
+            #[inline]
+            fn mul(self, rhs: &'b $field) -> $field {
+                self.mul(rhs)
+            }
+        }
+
+        impl From<[u64; 4]> for $field {
+            fn from(digits: [u64; 4]) -> Self {
+                Self::from_raw(digits)
+            }
+        }
+
+        impl From<$field> for [u64; 4] {
+            fn from(elt: $field) -> [u64; 4] {
+                // Turn into canonical form by computing
+                // (a.R) / R = a
+                #[cfg(feature = "asm")]
+                let tmp = $field::montgomery_reduce(&[
+                    elt.0[0], elt.0[1], elt.0[2], elt.0[3], 0, 0, 0, 0,
+                ]);
+
+                #[cfg(not(feature = "asm"))]
+                let tmp = $field::montgomery_reduce_short(elt.0[0], elt.0[1], elt.0[2], elt.0[3]);
+
+                tmp.0
+            }
+        }
+
+        impl From<$field> for [u8; 32] {
+            fn from(value: $field) -> [u8; 32] {
+                value.to_repr()
+            }
+        }
+
+        impl<'a> From<&'a $field> for [u8; 32] {
+            fn from(value: &'a $field) -> [u8; 32] {
+                value.to_repr()
+            }
+        }
+
+        impl From<$field> for i128 {
+            fn from(value: $field) -> i128 {
+                let tmp: [u64; 4] = value.into();
+                if tmp[2] == 0 && tmp[3] == 0 {
+                    i128::from(tmp[0]) | (i128::from(tmp[1]) << 64)
+                } else {
+                    // modulus - tmp
+                    let (a0, borrow) = $modulus.0[0].overflowing_sub(tmp[0]);
+                    let (a1, _) = sbb($modulus.0[1], tmp[1], borrow);
+
+                    -(i128::from(a0) | (i128::from(a1) << 64))
+                }
+            }
+        }
+
+        impl FieldExt for $field {
+            const MODULUS: &'static str = $modulus_str;
+            const TWO_INV: Self = $two_inv;
+            const ROOT_OF_UNITY_INV: Self = $root_of_unity_inv;
+            const DELTA: Self = $delta;
+            const ZETA: Self = $zeta;
+
+            fn from_u128(v: u128) -> Self {
+                $field::from_raw([v as u64, (v >> 64) as u64, 0, 0])
+            }
+
+            /// Converts a 512-bit little endian integer into
+            /// a `$field` by reducing by the modulus.
+            fn from_bytes_wide(bytes: &[u8; 64]) -> $field {
+                $field::from_u512([
+                    u64::from_le_bytes(bytes[0..8].try_into().unwrap()),
+                    u64::from_le_bytes(bytes[8..16].try_into().unwrap()),
+                    u64::from_le_bytes(bytes[16..24].try_into().unwrap()),
+                    u64::from_le_bytes(bytes[24..32].try_into().unwrap()),
+                    u64::from_le_bytes(bytes[32..40].try_into().unwrap()),
+                    u64::from_le_bytes(bytes[40..48].try_into().unwrap()),
+                    u64::from_le_bytes(bytes[48..56].try_into().unwrap()),
+                    u64::from_le_bytes(bytes[56..64].try_into().unwrap()),
+                ])
+            }
+
+            fn get_lower_128(&self) -> u128 {
+                let tmp =
+                    $field::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]);
+
+                u128::from(tmp.0[0]) | (u128::from(tmp.0[1]) << 64)
+            }
+        }
+
+        impl $crate::serde::SerdeObject for $field {
+            fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self {
+                debug_assert_eq!(bytes.len(), 32);
+                let inner =
+                    [0, 8, 16, 24].map(|i| u64::from_le_bytes(bytes[i..i + 8].try_into().unwrap()));
+                Self(inner)
+            }
+            fn from_raw_bytes(bytes: &[u8]) -> Option<Self> {
+                if bytes.len() != 32 {
+                    return None;
+                }
+                let elt = Self::from_raw_bytes_unchecked(bytes);
+                Self::is_less_than(&elt.0, &$modulus.0).then(|| elt)
+            }
+            fn to_raw_bytes(&self) -> Vec<u8> {
+                let mut res = Vec::with_capacity(32);
+                for limb in self.0.iter() {
+                    res.extend_from_slice(&limb.to_le_bytes());
+                }
+                res
+            }
+            fn read_raw_unchecked<R: std::io::Read>(reader: &mut R) -> Self {
+                let inner = [(); 4].map(|_| {
+                    let mut buf = [0; 8];
+                    reader.read_exact(&mut buf).unwrap();
+                    u64::from_le_bytes(buf)
+                });
+                Self(inner)
+            }
+            fn read_raw<R: std::io::Read>(reader: &mut R) -> std::io::Result<Self> {
+                let mut inner = [0u64; 4];
+                for limb in inner.iter_mut() {
+                    let mut buf = [0; 8];
+                    reader.read_exact(&mut buf)?;
+                    *limb = u64::from_le_bytes(buf);
+                }
+                let elt = Self(inner);
+                Self::is_less_than(&elt.0, &$modulus.0)
+                    .then(|| elt)
+                    .ok_or_else(|| {
+                        std::io::Error::new(
+                            std::io::ErrorKind::InvalidData,
+                            "input number is not less than field modulus",
+                        )
+                    })
+            }
+            fn write_raw<W: std::io::Write>(&self, writer: &mut W) -> std::io::Result<()> {
+                for limb in self.0.iter() {
+                    writer.write_all(&limb.to_le_bytes())?;
+                }
+                Ok(())
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! field_arithmetic {
+    ($field:ident, $modulus:ident, $inv:ident, $field_type:ident) => {
+        field_specific!($field, $modulus, $inv, $field_type);
+        impl $field {
+            /// Doubles this field element.
+            #[inline]
+            pub const fn double(&self) -> $field {
+                self.add(self)
+            }
+
+            /// Squares this element.
+            #[inline]
+            pub const fn square(&self) -> $field {
+                let r0;
+                let mut r1;
+                let mut r2;
+                let mut r3;
+                let mut r4;
+                let mut r5;
+                let mut r6;
+                let mut r7;
+                let mut carry;
+                let mut carry2;
+
+                (r1, carry) = self.0[0].widening_mul(self.0[1]);
+                (r2, carry) = self.0[0].carrying_mul(self.0[2], carry);
+                (r3, r4) = self.0[0].carrying_mul(self.0[3], carry);
+
+                (r3, carry) = macx(r3, self.0[1], self.0[2]);
+                (r4, r5) = mac(r4, self.0[1], self.0[3], carry);
+
+                (r5, r6) = macx(r5, self.0[2], self.0[3]);
+
+                r7 = r6 >> 63;
+                r6 = (r6 << 1) | (r5 >> 63);
+                r5 = (r5 << 1) | (r4 >> 63);
+                r4 = (r4 << 1) | (r3 >> 63);
+                r3 = (r3 << 1) | (r2 >> 63);
+                r2 = (r2 << 1) | (r1 >> 63);
+                r1 <<= 1;
+
+                (r0, carry) = self.0[0].widening_mul(self.0[0]);
+                (r1, carry2) = r1.overflowing_add(carry);
+                (r2, carry) = mac(r2, self.0[1], self.0[1], carry2 as u64);
+                (r3, carry2) = r3.overflowing_add(carry);
+                (r4, carry) = mac(r4, self.0[2], self.0[2], carry2 as u64);
+                (r5, carry2) = r5.overflowing_add(carry);
+                (r6, carry) = mac(r6, self.0[3], self.0[3], carry2 as u64);
+                r7 = r7.wrapping_add(carry);
+
+                $field::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7)
+            }
+
+            /// Subtracts `rhs` from `self`, returning the result.
+            #[inline]
+            pub const fn sub(&self, rhs: &Self) -> Self {
+                let (d0, borrow) = self.0[0].overflowing_sub(rhs.0[0]);
+                let (d1, borrow) = sbb(self.0[1], rhs.0[1], borrow);
+                let (d2, borrow) = sbb(self.0[2], rhs.0[2], borrow);
+                let (d3, borrow) = sbb(self.0[3], rhs.0[3], borrow);
+
+                let borrow = 0u64.wrapping_sub(borrow as u64);
+                // If underflow occurred on the final limb, borrow = 0xfff...fff, otherwise
+                // borrow = 0x000...000. Thus, we use it as a mask to conditionally add the modulus.
+                let (d0, carry) = d0.overflowing_add($modulus.0[0] & borrow);
+                let (d1, carry) = adc(d1, $modulus.0[1] & borrow, carry);
+                let (d2, carry) = adc(d2, $modulus.0[2] & borrow, carry);
+                let (d3, _) = adc(d3, $modulus.0[3] & borrow, carry);
+                $field([d0, d1, d2, d3])
+            }
+
+            /// Negates `self`.
+            #[inline]
+            pub const fn neg(&self) -> Self {
+                if self.0[0] == 0 && self.0[1] == 0 && self.0[2] == 0 && self.0[3] == 0 {
+                    return $field([0, 0, 0, 0]);
+                }
+                // Subtract `self` from `MODULUS` to negate. Ignore the final
+                // borrow because it cannot underflow; self is guaranteed to
+                // be in the field.
+                let (d0, borrow) = $modulus.0[0].overflowing_sub(self.0[0]);
+                let (d1, borrow) = sbb($modulus.0[1], self.0[1], borrow);
+                let (d2, borrow) = sbb($modulus.0[2], self.0[2], borrow);
+                let d3 = $modulus.0[3] - (self.0[3] + borrow as u64);
+
+                $field([d0, d1, d2, d3])
+            }
+
+            /// Montgomery reduce where last 4 registers are 0
+            #[inline(always)]
+            pub(crate) const fn montgomery_reduce_short(
+                mut r0: u64,
+                mut r1: u64,
+                mut r2: u64,
+                mut r3: u64,
+            ) -> $field {
+                // The Montgomery reduction here is based on Algorithm 14.32 in
+                // Handbook of Applied Cryptography
+                // <http://cacr.uwaterloo.ca/hac/about/chap14.pdf>.
+                let mut k;
+
+                k = r0.wrapping_mul($inv);
+                (_, r0) = macx(r0, k, $modulus.0[0]);
+                (r1, r0) = mac(r1, k, $modulus.0[1], r0);
+                (r2, r0) = mac(r2, k, $modulus.0[2], r0);
+                (r3, r0) = mac(r3, k, $modulus.0[3], r0);
+
+                k = r1.wrapping_mul($inv);
+                (_, r1) = macx(r1, k, $modulus.0[0]);
+                (r2, r1) = mac(r2, k, $modulus.0[1], r1);
+                (r3, r1) = mac(r3, k, $modulus.0[2], r1);
+                (r0, r1) = mac(r0, k, $modulus.0[3], r1);
+
+                k = r2.wrapping_mul($inv);
+                (_, r2) = macx(r2, k, $modulus.0[0]);
+                (r3, r2) = mac(r3, k, $modulus.0[1], r2);
+                (r0, r2) = mac(r0, k, $modulus.0[2], r2);
+                (r1, r2) = mac(r1, k, $modulus.0[3], r2);
+
+                k = r3.wrapping_mul($inv);
+                (_, r3) = macx(r3, k, $modulus.0[0]);
+                (r0, r3) = mac(r0, k, $modulus.0[1], r3);
+                (r1, r3) = mac(r1, k, $modulus.0[2], r3);
+                (r2, r3) = mac(r2, k, $modulus.0[3], r3);
+
+                // Result may be within MODULUS of the correct value
+                (&$field([r0, r1, r2, r3])).sub(&$modulus)
+            }
+
+            #[inline(always)]
+            fn is_less_than(x: &[u64; 4], y: &[u64; 4]) -> bool {
+                let (_, borrow) = x[0].overflowing_sub(y[0]);
+                let (_, borrow) = x[1].borrowing_sub(y[1], borrow);
+                let (_, borrow) = x[2].borrowing_sub(y[2], borrow);
+                let (_, borrow) = x[3].borrowing_sub(y[3], borrow);
+                borrow
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! field_specific {
+    ($field:ident, $modulus:ident, $inv:ident, sparse) => {
+        impl $field {
+            /// Adds `rhs` to `self`, returning the result.
+            #[inline]
+            pub const fn add(&self, rhs: &Self) -> Self {
+                let (d0, carry) = self.0[0].overflowing_add(rhs.0[0]);
+                let (d1, carry) = self.0[1].carrying_add(rhs.0[1], carry);
+                let (d2, carry) = self.0[2].carrying_add(rhs.0[2], carry);
+                // sparse means that the sum won't overflow the top register
+                let d3 = self.0[3] + rhs.0[3] + carry as u64;
+
+                // Attempt to subtract the modulus, to ensure the value
+                // is smaller than the modulus.
+                (&$field([d0, d1, d2, d3])).sub(&$modulus)
+            }
+
+            /// Multiplies `rhs` by `self`, returning the result.
+            #[inline]
+            pub const fn mul(&self, rhs: &Self) -> $field {
+                // When the highest bit in the top register of the modulus is 0 and the rest of the bits are not all 1, we can use an optimization from the gnark team: https://hackmd.io/@gnark/modular_multiplication
+
+                // I think this is exactly the same as the previous `mul` implementation with `montgomery_reduce` at the end (where `montgomery_reduce` is slightly cheaper in "sparse" setting)
+                // Maybe the use of mutable variables is slightly more efficient?
+                let mut r0;
+                let mut r1;
+                let mut t0;
+                let mut t1;
+                let mut t2;
+                let mut t3;
+                let mut k;
+
+                (t0, r0) = self.0[0].widening_mul(rhs.0[0]);
+                k = t0.wrapping_mul($inv);
+                (_, r1) = macx(t0, k, $modulus.0[0]);
+                (t1, r0) = self.0[0].carrying_mul(rhs.0[1], r0);
+                (t0, r1) = mac(t1, k, $modulus.0[1], r1);
+                (t2, r0) = self.0[0].carrying_mul(rhs.0[2], r0);
+                (t1, r1) = mac(t2, k, $modulus.0[2], r1);
+                (t3, r0) = self.0[0].carrying_mul(rhs.0[3], r0);
+                (t2, r1) = mac(t3, k, $modulus.0[3], r1);
+                t3 = r0 + r1;
+
+                (t0, r0) = macx(t0, self.0[1], rhs.0[0]);
+                k = t0.wrapping_mul($inv);
+                (_, r1) = macx(t0, k, $modulus.0[0]);
+                (t1, r0) = mac(t1, self.0[1], rhs.0[1], r0);
+                (t0, r1) = mac(t1, k, $modulus.0[1], r1);
+                (t2, r0) = mac(t2, self.0[1], rhs.0[2], r0);
+                (t1, r1) = mac(t2, k, $modulus.0[2], r1);
+                (t3, r0) = mac(t3, self.0[1], rhs.0[3], r0);
+                (t2, r1) = mac(t3, k, $modulus.0[3], r1);
+                t3 = r0 + r1;
+
+                (t0, r0) = macx(t0, self.0[2], rhs.0[0]);
+                k = t0.wrapping_mul($inv);
+                (_, r1) = macx(t0, k, $modulus.0[0]);
+                (t1, r0) = mac(t1, self.0[2], rhs.0[1], r0);
+                (t0, r1) = mac(t1, k, $modulus.0[1], r1);
+                (t2, r0) = mac(t2, self.0[2], rhs.0[2], r0);
+                (t1, r1) = mac(t2, k, $modulus.0[2], r1);
+                (t3, r0) = mac(t3, self.0[2], rhs.0[3], r0);
+                (t2, r1) = mac(t3, k, $modulus.0[3], r1);
+                t3 = r0 + r1;
+
+                (t0, r0) = macx(t0, self.0[3], rhs.0[0]);
+                k = t0.wrapping_mul($inv);
+                (_, r1) = macx(t0, k, $modulus.0[0]);
+                (t1, r0) = mac(t1, self.0[3], rhs.0[1], r0);
+                (t0, r1) = mac(t1, k, $modulus.0[1], r1);
+                (t2, r0) = mac(t2, self.0[3], rhs.0[2], r0);
+                (t1, r1) = mac(t2, k, $modulus.0[2], r1);
+                (t3, r0) = mac(t3, self.0[3], rhs.0[3], r0);
+                (t2, r1) = mac(t3, k, $modulus.0[3], r1);
+                t3 = r0 + r1;
+
+                // Result may be within MODULUS of the correct value
+                (&$field([t0, t1, t2, t3])).sub(&$modulus)
+            }
+
+            #[allow(clippy::too_many_arguments)]
+            #[inline(always)]
+            pub(crate) const fn montgomery_reduce(
+                r0: u64,
+                mut r1: u64,
+                mut r2: u64,
+                mut r3: u64,
+                mut r4: u64,
+                mut r5: u64,
+                mut r6: u64,
+                mut r7: u64,
+            ) -> $field {
+                // The Montgomery reduction here is based on Algorithm 14.32 in
+                // Handbook of Applied Cryptography
+                // <http://cacr.uwaterloo.ca/hac/about/chap14.pdf>.
+                let mut k;
+                let mut carry;
+                let mut carry2;
+
+                k = r0.wrapping_mul($inv);
+                (_, carry) = macx(r0, k, $modulus.0[0]);
+                (r1, carry) = mac(r1, k, $modulus.0[1], carry);
+                (r2, carry) = mac(r2, k, $modulus.0[2], carry);
+                (r3, carry) = mac(r3, k, $modulus.0[3], carry);
+                (r4, carry2) = r4.overflowing_add(carry);
+
+                k = r1.wrapping_mul($inv);
+                (_, carry) = macx(r1, k, $modulus.0[0]);
+                (r2, carry) = mac(r2, k, $modulus.0[1], carry);
+                (r3, carry) = mac(r3, k, $modulus.0[2], carry);
+                (r4, carry) = mac(r4, k, $modulus.0[3], carry);
+                (r5, carry2) = adc(r5, carry, carry2);
+
+                k = r2.wrapping_mul($inv);
+                (_, carry) = macx(r2, k, $modulus.0[0]);
+                (r3, carry) = mac(r3, k, $modulus.0[1], carry);
+                (r4, carry) = mac(r4, k, $modulus.0[2], carry);
+                (r5, carry) = mac(r5, k, $modulus.0[3], carry);
+                (r6, carry2) = adc(r6, carry, carry2);
+
+                k = r3.wrapping_mul($inv);
+                (_, carry) = macx(r3, k, $modulus.0[0]);
+                (r4, carry) = mac(r4, k, $modulus.0[1], carry);
+                (r5, carry) = mac(r5, k, $modulus.0[2], carry);
+                (r6, carry) = mac(r6, k, $modulus.0[3], carry);
+                (r7, _) = adc(r7, carry, carry2);
+
+                // Result may be within MODULUS of the correct value
+                (&$field([r4, r5, r6, r7])).sub(&$modulus)
+            }
+        }
+    };
+    ($field:ident, $modulus:ident, $inv:ident, dense) => {
+        impl $field {
+            /// Adds `rhs` to `self`, returning the result.
+            #[inline]
+            pub const fn add(&self, rhs: &Self) -> Self {
+                let (d0, carry) = self.0[0].overflowing_add(rhs.0[0]);
+                let (d1, carry) = adc(self.0[1], rhs.0[1], carry);
+                let (d2, carry) = adc(self.0[2], rhs.0[2], carry);
+                let (d3, carry) = adc(self.0[3], rhs.0[3], carry);
+
+                // Attempt to subtract the modulus, to ensure the value
+                // is smaller than the modulus.
+                let (d0, borrow) = d0.overflowing_sub($modulus.0[0]);
+                let (d1, borrow) = sbb(d1, $modulus.0[1], borrow);
+                let (d2, borrow) = sbb(d2, $modulus.0[2], borrow);
+                let (d3, borrow) = sbb(d3, $modulus.0[3], borrow);
+                let borrow = (carry as u64).wrapping_sub(borrow as u64);
+
+                let (d0, carry) = d0.overflowing_add($modulus.0[0] & borrow);
+                let (d1, carry) = adc(d1, $modulus.0[1] & borrow, carry);
+                let (d2, carry) = adc(d2, $modulus.0[2] & borrow, carry);
+                let (d3, _) = adc(d3, $modulus.0[3] & borrow, carry);
+
+                $field([d0, d1, d2, d3])
+            }
+
+            /// Multiplies `rhs` by `self`, returning the result.
+            #[inline]
+            pub const fn mul(&self, rhs: &Self) -> $field {
+                // Schoolbook multiplication
+
+                let (r0, carry) = mac(0, self.0[0], rhs.0[0], 0);
+                let (r1, carry) = mac(0, self.0[0], rhs.0[1], carry);
+                let (r2, carry) = mac(0, self.0[0], rhs.0[2], carry);
+                let (r3, r4) = mac(0, self.0[0], rhs.0[3], carry);
+
+                let (r1, carry) = mac(r1, self.0[1], rhs.0[0], 0);
+                let (r2, carry) = mac(r2, self.0[1], rhs.0[1], carry);
+                let (r3, carry) = mac(r3, self.0[1], rhs.0[2], carry);
+                let (r4, r5) = mac(r4, self.0[1], rhs.0[3], carry);
+
+                let (r2, carry) = mac(r2, self.0[2], rhs.0[0], 0);
+                let (r3, carry) = mac(r3, self.0[2], rhs.0[1], carry);
+                let (r4, carry) = mac(r4, self.0[2], rhs.0[2], carry);
+                let (r5, r6) = mac(r5, self.0[2], rhs.0[3], carry);
+
+                let (r3, carry) = mac(r3, self.0[3], rhs.0[0], 0);
+                let (r4, carry) = mac(r4, self.0[3], rhs.0[1], carry);
+                let (r5, carry) = mac(r5, self.0[3], rhs.0[2], carry);
+                let (r6, r7) = mac(r6, self.0[3], rhs.0[3], carry);
+
+                $field::montgomery_reduce(r0, r1, r2, r3, r4, r5, r6, r7)
+            }
+
+            #[allow(clippy::too_many_arguments)]
+            #[inline(always)]
+            pub(crate) const fn montgomery_reduce(
+                r0: u64,
+                mut r1: u64,
+                mut r2: u64,
+                mut r3: u64,
+                mut r4: u64,
+                mut r5: u64,
+                mut r6: u64,
+                mut r7: u64,
+            ) -> Self {
+                // The Montgomery reduction here is based on Algorithm 14.32 in
+                // Handbook of Applied Cryptography
+                // <http://cacr.uwaterloo.ca/hac/about/chap14.pdf>.
+                let mut k;
+                let mut carry;
+                let mut carry2;
+
+                k = r0.wrapping_mul($inv);
+                (_, carry) = macx(r0, k, $modulus.0[0]);
+                (r1, carry) = mac(r1, k, $modulus.0[1], carry);
+                (r2, carry) = mac(r2, k, $modulus.0[2], carry);
+                (r3, carry) = mac(r3, k, $modulus.0[3], carry);
+                (r4, carry2) = r4.overflowing_add(carry);
+
+                k = r1.wrapping_mul($inv);
+                (_, carry) = k.carrying_mul($modulus.0[0], r1);
+                (r2, carry) = mac(r2, k, $modulus.0[1], carry);
+                (r3, carry) = mac(r3, k, $modulus.0[2], carry);
+                (r4, carry) = mac(r4, k, $modulus.0[3], carry);
+                (r5, carry2) = adc(r5, carry, carry2);
+
+                k = r2.wrapping_mul($inv);
+                (_, carry) = macx(r2, k, $modulus.0[0]);
+                (r3, carry) = mac(r3, k, $modulus.0[1], carry);
+                (r4, carry) = mac(r4, k, $modulus.0[2], carry);
+                (r5, carry) = mac(r5, k, $modulus.0[3], carry);
+                (r6, carry2) = adc(r6, carry, carry2);
+
+                k = r3.wrapping_mul($inv);
+                (_, carry) = macx(r3, k, $modulus.0[0]);
+                (r4, carry) = mac(r4, k, $modulus.0[1], carry);
+                (r5, carry) = mac(r5, k, $modulus.0[2], carry);
+                (r6, carry) = mac(r6, k, $modulus.0[3], carry);
+                (r7, carry2) = adc(r7, carry, carry2);
+
+                // Result may be within MODULUS of the correct value
+                let mut borrow;
+                (r4, borrow) = r4.overflowing_sub($modulus.0[0]);
+                (r5, borrow) = sbb(r5, $modulus.0[1], borrow);
+                (r6, borrow) = sbb(r6, $modulus.0[2], borrow);
+                (r7, borrow) = sbb(r7, $modulus.0[3], borrow);
+                let borrow = (carry2 as u64).wrapping_sub(borrow as u64);
+
+                (r4, carry2) = r4.overflowing_add($modulus.0[0] & borrow);
+                (r5, carry2) = adc(r5, $modulus.0[1] & borrow, carry2);
+                (r6, carry2) = adc(r6, $modulus.0[2] & borrow, carry2);
+                (r7, _) = adc(r7, $modulus.0[3] & borrow, carry2);
+                $field([r4, r5, r6, r7])
+            }
+        }
+    };
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/derive/mod.rs.html b/docs/src/halo2curves/derive/mod.rs.html new file mode 100644 index 0000000000..973c4129ff --- /dev/null +++ b/docs/src/halo2curves/derive/mod.rs.html @@ -0,0 +1,330 @@ +mod.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+
#[macro_use]
+pub mod curve;
+#[macro_use]
+pub mod field;
+
+#[macro_export]
+macro_rules! impl_add_binop_specify_output {
+    ($lhs:ident, $rhs:ident, $output:ident) => {
+        impl<'b> ::core::ops::Add<&'b $rhs> for $lhs {
+            type Output = $output;
+
+            #[inline]
+            fn add(self, rhs: &'b $rhs) -> $output {
+                &self + rhs
+            }
+        }
+
+        impl<'a> ::core::ops::Add<$rhs> for &'a $lhs {
+            type Output = $output;
+
+            #[inline]
+            fn add(self, rhs: $rhs) -> $output {
+                self + &rhs
+            }
+        }
+
+        impl ::core::ops::Add<$rhs> for $lhs {
+            type Output = $output;
+
+            #[inline]
+            fn add(self, rhs: $rhs) -> $output {
+                &self + &rhs
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! impl_sub_binop_specify_output {
+    ($lhs:ident, $rhs:ident, $output:ident) => {
+        impl<'b> ::core::ops::Sub<&'b $rhs> for $lhs {
+            type Output = $output;
+
+            #[inline]
+            fn sub(self, rhs: &'b $rhs) -> $output {
+                &self - rhs
+            }
+        }
+
+        impl<'a> ::core::ops::Sub<$rhs> for &'a $lhs {
+            type Output = $output;
+
+            #[inline]
+            fn sub(self, rhs: $rhs) -> $output {
+                self - &rhs
+            }
+        }
+
+        impl ::core::ops::Sub<$rhs> for $lhs {
+            type Output = $output;
+
+            #[inline]
+            fn sub(self, rhs: $rhs) -> $output {
+                &self - &rhs
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! impl_binops_additive_specify_output {
+    ($lhs:ident, $rhs:ident, $output:ident) => {
+        impl_add_binop_specify_output!($lhs, $rhs, $output);
+        impl_sub_binop_specify_output!($lhs, $rhs, $output);
+    };
+}
+
+#[macro_export]
+macro_rules! impl_binops_multiplicative_mixed {
+    ($lhs:ident, $rhs:ident, $output:ident) => {
+        impl<'b> ::core::ops::Mul<&'b $rhs> for $lhs {
+            type Output = $output;
+
+            #[inline]
+            fn mul(self, rhs: &'b $rhs) -> $output {
+                &self * rhs
+            }
+        }
+
+        impl<'a> ::core::ops::Mul<$rhs> for &'a $lhs {
+            type Output = $output;
+
+            #[inline]
+            fn mul(self, rhs: $rhs) -> $output {
+                self * &rhs
+            }
+        }
+
+        impl ::core::ops::Mul<$rhs> for $lhs {
+            type Output = $output;
+
+            #[inline]
+            fn mul(self, rhs: $rhs) -> $output {
+                &self * &rhs
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! impl_binops_additive {
+    ($lhs:ident, $rhs:ident) => {
+        impl_binops_additive_specify_output!($lhs, $rhs, $lhs);
+
+        impl ::core::ops::SubAssign<$rhs> for $lhs {
+            #[inline]
+            fn sub_assign(&mut self, rhs: $rhs) {
+                *self = &*self - &rhs;
+            }
+        }
+
+        impl ::core::ops::AddAssign<$rhs> for $lhs {
+            #[inline]
+            fn add_assign(&mut self, rhs: $rhs) {
+                *self = &*self + &rhs;
+            }
+        }
+
+        impl<'b> ::core::ops::SubAssign<&'b $rhs> for $lhs {
+            #[inline]
+            fn sub_assign(&mut self, rhs: &'b $rhs) {
+                *self = &*self - rhs;
+            }
+        }
+
+        impl<'b> ::core::ops::AddAssign<&'b $rhs> for $lhs {
+            #[inline]
+            fn add_assign(&mut self, rhs: &'b $rhs) {
+                *self = &*self + rhs;
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! impl_binops_multiplicative {
+    ($lhs:ident, $rhs:ident) => {
+        impl_binops_multiplicative_mixed!($lhs, $rhs, $lhs);
+
+        impl ::core::ops::MulAssign<$rhs> for $lhs {
+            #[inline]
+            fn mul_assign(&mut self, rhs: $rhs) {
+                *self = &*self * &rhs;
+            }
+        }
+
+        impl<'b> ::core::ops::MulAssign<&'b $rhs> for $lhs {
+            #[inline]
+            fn mul_assign(&mut self, rhs: &'b $rhs) {
+                *self = &*self * rhs;
+            }
+        }
+    };
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/lib.rs.html b/docs/src/halo2curves/lib.rs.html new file mode 100644 index 0000000000..409b3e06a5 --- /dev/null +++ b/docs/src/halo2curves/lib.rs.html @@ -0,0 +1,70 @@ +lib.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+
#![cfg_attr(feature = "asm", feature(asm_const))]
+#![feature(bigint_helper_methods)]
+#![feature(const_bigint_helper_methods)]
+
+mod arithmetic;
+
+pub mod bn256;
+pub mod pairing;
+pub mod pasta;
+pub mod secp256k1;
+pub mod serde;
+
+#[macro_use]
+mod derive;
+
+pub use arithmetic::CurveAffineExt;
+pub use pasta_curves::arithmetic::{Coordinates, CurveAffine, CurveExt, FieldExt, Group};
+
+pub extern crate group;
+
+#[cfg(test)]
+pub mod tests;
+
+#[cfg(all(feature = "prefetch", target_arch = "x86_64"))]
+#[inline(always)]
+pub fn prefetch<T>(data: &[T], offset: usize) {
+    use core::arch::x86_64::_mm_prefetch;
+    unsafe {
+        _mm_prefetch(
+            data.as_ptr().offset(offset as isize) as *const i8,
+            core::arch::x86_64::_MM_HINT_T0,
+        );
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/pairing.rs.html b/docs/src/halo2curves/pairing.rs.html new file mode 100644 index 0000000000..e94a082483 --- /dev/null +++ b/docs/src/halo2curves/pairing.rs.html @@ -0,0 +1,188 @@ +pairing.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+
use crate::{CurveAffine, FieldExt, Group as _Group};
+use core::ops::Mul;
+use group::{
+    prime::PrimeCurve, Group, GroupOps, GroupOpsOwned, ScalarMul, ScalarMulOwned,
+    UncompressedEncoding,
+};
+
+pub trait Engine: Sized + 'static + Clone {
+    /// This is the scalar field of the engine's groups.
+    type Scalar: FieldExt;
+
+    /// The projective representation of an element in G1.
+    type G1: PrimeCurve<Scalar = Self::Scalar, Affine = Self::G1Affine>
+        + From<Self::G1Affine>
+        + GroupOps<Self::G1Affine>
+        + GroupOpsOwned<Self::G1Affine>
+        + ScalarMul<Self::Scalar>
+        + ScalarMulOwned<Self::Scalar>
+        + _Group<Scalar = Self::Scalar>;
+
+    /// The affine representation of an element in G1.
+    type G1Affine: PairingCurveAffine<
+            ScalarExt = Self::Scalar,
+            CurveExt = Self::G1,
+            Pair = Self::G2Affine,
+            PairingResult = Self::Gt,
+        > + From<Self::G1>
+        + Mul<Self::Scalar, Output = Self::G1>
+        + for<'a> Mul<&'a Self::Scalar, Output = Self::G1>;
+
+    /// The projective representation of an element in G2.
+    type G2: PrimeCurve<Scalar = Self::Scalar, Affine = Self::G2Affine>
+        + From<Self::G2Affine>
+        + GroupOps<Self::G2Affine>
+        + GroupOpsOwned<Self::G2Affine>
+        + ScalarMul<Self::Scalar>
+        + ScalarMulOwned<Self::Scalar>;
+
+    /// The affine representation of an element in G2.
+    type G2Affine: PairingCurveAffine<
+            ScalarExt = Self::Scalar,
+            CurveExt = Self::G2,
+            Pair = Self::G1Affine,
+            PairingResult = Self::Gt,
+        > + From<Self::G2>
+        + Mul<Self::Scalar, Output = Self::G2>
+        + for<'a> Mul<&'a Self::Scalar, Output = Self::G2>;
+
+    /// The extension field that hosts the target group of the pairing.
+    type Gt: Group<Scalar = Self::Scalar> + ScalarMul<Self::Scalar> + ScalarMulOwned<Self::Scalar>;
+
+    /// Invoke the pairing function `G1 x G2 -> Gt` without the use of precomputation and
+    /// other optimizations.
+    fn pairing(p: &Self::G1Affine, q: &Self::G2Affine) -> Self::Gt;
+}
+
+/// Affine representation of an elliptic curve point that can be used
+/// to perform pairings.
+pub trait PairingCurveAffine: CurveAffine + UncompressedEncoding {
+    type Pair: PairingCurveAffine<Pair = Self>;
+    type PairingResult: Group;
+
+    /// Perform a pairing
+    fn pairing_with(&self, other: &Self::Pair) -> Self::PairingResult;
+}
+
+/// An engine that can compute sums of pairings in an efficient way.
+pub trait MultiMillerLoop: Engine {
+    /// The prepared form of `Self::G2Affine`.
+    type G2Prepared: Clone + Send + Sync + From<Self::G2Affine>;
+
+    /// The type returned by `Engine::miller_loop`.
+    type Result: MillerLoopResult<Gt = Self::Gt>;
+
+    /// Computes $$\sum_{i=1}^n \textbf{ML}(a_i, b_i)$$ given a series of terms
+    /// $$(a_1, b_1), (a_2, b_2), ..., (a_n, b_n).$$
+    fn multi_miller_loop(terms: &[(&Self::G1Affine, &Self::G2Prepared)]) -> Self::Result;
+}
+
+/// Represents results of a Miller loop, one of the most expensive portions of the pairing
+/// function.
+///
+/// `MillerLoopResult`s cannot be compared with each other until
+/// [`MillerLoopResult::final_exponentiation`] is called, which is also expensive.
+pub trait MillerLoopResult {
+    /// The extension field that hosts the target group of the pairing.
+    type Gt: Group;
+
+    /// This performs a "final exponentiation" routine to convert the result of a Miller
+    /// loop into an element of [`MillerLoopResult::Gt`], so that it can be compared with
+    /// other elements of `Gt`.
+    fn final_exponentiation(&self) -> Self::Gt;
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/pasta/mod.rs.html b/docs/src/halo2curves/pasta/mod.rs.html new file mode 100644 index 0000000000..9eed655840 --- /dev/null +++ b/docs/src/halo2curves/pasta/mod.rs.html @@ -0,0 +1,4 @@ +mod.rs - source
1
+
pub use pasta_curves::{pallas, vesta, Ep, EpAffine, Eq, EqAffine, Fp, Fq};
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/secp256k1/curve.rs.html b/docs/src/halo2curves/secp256k1/curve.rs.html new file mode 100644 index 0000000000..901b27eee9 --- /dev/null +++ b/docs/src/halo2curves/secp256k1/curve.rs.html @@ -0,0 +1,294 @@ +curve.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+
use crate::secp256k1::Fp;
+use crate::secp256k1::Fq;
+use crate::{Coordinates, CurveAffine, CurveAffineExt, CurveExt, Group};
+use core::cmp;
+use core::fmt::Debug;
+use core::iter::Sum;
+use core::ops::{Add, Mul, Neg, Sub};
+use ff::{Field, PrimeField};
+use group::Curve;
+use group::{prime::PrimeCurveAffine, Group as _, GroupEncoding};
+use rand::RngCore;
+use serde::{Deserialize, Serialize};
+use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
+
+impl Secp256k1 {
+    fn endomorphism_base(&self) -> Self {
+        unimplemented!();
+    }
+}
+
+impl group::cofactor::CofactorGroup for Secp256k1 {
+    type Subgroup = Secp256k1;
+
+    fn clear_cofactor(&self) -> Self {
+        *self
+    }
+
+    fn into_subgroup(self) -> CtOption<Self::Subgroup> {
+        CtOption::new(self, 1.into())
+    }
+
+    fn is_torsion_free(&self) -> Choice {
+        1.into()
+    }
+}
+
+// Reference: https://neuromancer.sk/std/secg/secp256k1
+const SECP_GENERATOR_X: Fp = Fp::from_raw([
+    0x59F2815B16F81798,
+    0x029BFCDB2DCE28D9,
+    0x55A06295CE870B07,
+    0x79BE667EF9DCBBAC,
+]);
+const SECP_GENERATOR_Y: Fp = Fp::from_raw([
+    0x9C47D08FFB10D4B8,
+    0xFD17B448A6855419,
+    0x5DA4FBFC0E1108A8,
+    0x483ADA7726A3C465,
+]);
+const SECP_B: Fp = Fp::from_raw([7, 0, 0, 0]);
+
+use crate::{
+    batch_add, impl_add_binop_specify_output, impl_binops_additive,
+    impl_binops_additive_specify_output, impl_binops_multiplicative,
+    impl_binops_multiplicative_mixed, impl_sub_binop_specify_output, new_curve_impl,
+};
+
+new_curve_impl!(
+    (pub),
+    Secp256k1,
+    Secp256k1Affine,
+    Secp256k1Compressed,
+    33,
+    Fp,
+    Fq,
+    (SECP_GENERATOR_X,SECP_GENERATOR_Y),
+    SECP_B,
+    "secp256k1",
+);
+
+impl CurveAffineExt for Secp256k1Affine {
+    batch_add!();
+
+    fn into_coordinates(self) -> (Self::Base, Self::Base) {
+        (self.x, self.y)
+    }
+}
+
+#[test]
+fn test_curve() {
+    crate::tests::curve::curve_tests::<Secp256k1>();
+}
+
+#[test]
+fn test_serialization() {
+    crate::tests::curve::random_serialization_test::<Secp256k1>();
+}
+
+#[test]
+fn ecdsa_example() {
+    use crate::group::Curve;
+    use crate::{CurveAffine, FieldExt};
+    use rand_core::OsRng;
+
+    fn mod_n(x: Fp) -> Fq {
+        let mut x_repr = [0u8; 32];
+        x_repr.copy_from_slice(x.to_repr().as_ref());
+        let mut x_bytes = [0u8; 64];
+        x_bytes[..32].copy_from_slice(&x_repr[..]);
+        Fq::from_bytes_wide(&x_bytes)
+    }
+
+    let g = Secp256k1::generator();
+
+    for _ in 0..1000 {
+        // Generate a key pair
+        let sk = Fq::random(OsRng);
+        let pk = (g * sk).to_affine();
+
+        // Generate a valid signature
+        // Suppose `m_hash` is the message hash
+        let msg_hash = Fq::random(OsRng);
+
+        let (r, s) = {
+            // Draw arandomness
+            let k = Fq::random(OsRng);
+            let k_inv = k.invert().unwrap();
+
+            // Calculate `r`
+            let r_point = (g * k).to_affine().coordinates().unwrap();
+            let x = r_point.x();
+            let r = mod_n(*x);
+
+            // Calculate `s`
+            let s = k_inv * (msg_hash + (r * sk));
+
+            (r, s)
+        };
+
+        {
+            // Verify
+            let s_inv = s.invert().unwrap();
+            let u_1 = msg_hash * s_inv;
+            let u_2 = r * s_inv;
+
+            let v_1 = g * u_1;
+            let v_2 = pk * u_2;
+
+            let r_point = (v_1 + v_2).to_affine().coordinates().unwrap();
+            let x_candidate = r_point.x();
+            let r_candidate = mod_n(*x_candidate);
+
+            assert_eq!(r, r_candidate);
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/secp256k1/fp.rs.html b/docs/src/halo2curves/secp256k1/fp.rs.html new file mode 100644 index 0000000000..f6d062031d --- /dev/null +++ b/docs/src/halo2curves/secp256k1/fp.rs.html @@ -0,0 +1,568 @@ +fp.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+
use core::convert::TryInto;
+use core::fmt;
+use core::ops::{Add, Mul, Neg, Sub};
+
+use ff::PrimeField;
+use rand::RngCore;
+use serde::{Deserialize, Serialize};
+use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
+
+use pasta_curves::arithmetic::{FieldExt, Group, SqrtRatio};
+
+use crate::arithmetic::{adc, mac, macx, sbb};
+
+/// This represents an element of $\mathbb{F}_p$ where
+///
+/// `p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f`
+///
+/// is the base field of the secp256k1 curve.
+// The internal representation of this type is four 64-bit unsigned
+// integers in little-endian order. `Fp` values are always in
+// Montgomery form; i.e., Fp(a) = aR mod p, with R = 2^256.
+#[derive(Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
+pub struct Fp(pub(crate) [u64; 4]);
+
+/// Constant representing the modulus
+/// p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f
+const MODULUS: Fp = Fp([
+    0xfffffffefffffc2f,
+    0xffffffffffffffff,
+    0xffffffffffffffff,
+    0xffffffffffffffff,
+]);
+
+/// The modulus as u32 limbs.
+#[cfg(not(target_pointer_width = "64"))]
+const MODULUS_LIMBS_32: [u32; 8] = [
+    0xffff_fc2f,
+    0xffff_fffe,
+    0xffff_ffff,
+    0xffff_ffff,
+    0xffff_ffff,
+    0xffff_ffff,
+    0xffff_ffff,
+    0xffff_ffff,
+];
+
+/// Constant representing the modolus as static str
+const MODULUS_STR: &str = "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f";
+
+/// INV = -(p^{-1} mod 2^64) mod 2^64
+const INV: u64 = 0xd838091dd2253531;
+
+/// R = 2^256 mod p
+/// 0x1000003d1
+const R: Fp = Fp([0x1000003d1, 0, 0, 0]);
+
+/// R^2 = 2^512 mod p
+/// 0x1000007a2000e90a1
+const R2: Fp = Fp([0x000007a2000e90a1, 0x1, 0, 0]);
+
+/// R^3 = 2^768 mod p
+/// 0x100000b73002bb1e33795f671
+const R3: Fp = Fp([0x002bb1e33795f671, 0x100000b73, 0, 0]);
+
+/// 1 / 2 mod p
+const TWO_INV: Fp = Fp::from_raw([
+    0xffffffff7ffffe18,
+    0xffffffffffffffff,
+    0xffffffffffffffff,
+    0x7fffffffffffffff,
+]);
+
+const ZETA: Fp = Fp::zero();
+const DELTA: Fp = Fp::zero();
+const ROOT_OF_UNITY_INV: Fp = Fp::zero();
+
+use crate::{
+    field_arithmetic, field_common, field_specific, impl_add_binop_specify_output,
+    impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative,
+    impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
+};
+impl_binops_additive!(Fp, Fp);
+impl_binops_multiplicative!(Fp, Fp);
+field_common!(
+    Fp,
+    MODULUS,
+    INV,
+    MODULUS_STR,
+    TWO_INV,
+    ROOT_OF_UNITY_INV,
+    DELTA,
+    ZETA,
+    R,
+    R2,
+    R3
+);
+field_arithmetic!(Fp, MODULUS, INV, dense);
+
+impl Fp {
+    pub const fn size() -> usize {
+        32
+    }
+}
+
+impl ff::Field for Fp {
+    fn random(mut rng: impl RngCore) -> Self {
+        Self::from_u512([
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+        ])
+    }
+
+    fn zero() -> Self {
+        Self::zero()
+    }
+
+    fn one() -> Self {
+        Self::one()
+    }
+
+    fn double(&self) -> Self {
+        self.double()
+    }
+
+    #[inline(always)]
+    fn square(&self) -> Self {
+        self.square()
+    }
+
+    /// Computes the square root of this element, if it exists.
+    fn sqrt(&self) -> CtOption<Self> {
+        let tmp = self.pow(&[
+            0xffffffffbfffff0c,
+            0xffffffffffffffff,
+            0xffffffffffffffff,
+            0x3fffffffffffffff,
+        ]);
+
+        CtOption::new(tmp, tmp.square().ct_eq(self))
+    }
+
+    /// Computes the multiplicative inverse of this element,
+    /// failing if the element is zero.
+    fn invert(&self) -> CtOption<Self> {
+        let tmp = self.pow_vartime([
+            0xfffffffefffffc2d,
+            0xffffffffffffffff,
+            0xffffffffffffffff,
+            0xffffffffffffffff,
+        ]);
+
+        CtOption::new(tmp, !self.ct_eq(&Self::zero()))
+    }
+
+    fn pow_vartime<S: AsRef<[u64]>>(&self, exp: S) -> Self {
+        let mut res = Self::one();
+        let mut found_one = false;
+        for e in exp.as_ref().iter().rev() {
+            for i in (0..64).rev() {
+                if found_one {
+                    res = res.square();
+                }
+
+                if ((*e >> i) & 1) == 1 {
+                    found_one = true;
+                    res *= self;
+                }
+            }
+        }
+        res
+    }
+}
+
+impl ff::PrimeField for Fp {
+    type Repr = [u8; 32];
+
+    const NUM_BITS: u32 = 256;
+    const CAPACITY: u32 = 255;
+    const S: u32 = 1;
+
+    fn from_repr(repr: Self::Repr) -> CtOption<Self> {
+        let mut tmp = Fp([0, 0, 0, 0]);
+
+        tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap());
+        tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap());
+        tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap());
+        tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap());
+
+        // Try to subtract the modulus
+        let (_, borrow) = tmp.0[0].overflowing_sub(MODULUS.0[0]);
+        let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow);
+        let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow);
+        let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow);
+
+        // If the element is smaller than MODULUS then the
+        // subtraction will underflow, producing a borrow value
+        // of 0xffff...ffff. Otherwise, it'll be zero.
+        let is_some = (borrow as u8) & 1;
+
+        // Convert to Montgomery form by computing
+        // (a.R^0 * R^2) / R = a.R
+        tmp *= &R2;
+
+        CtOption::new(tmp, Choice::from(is_some))
+    }
+
+    fn to_repr(&self) -> Self::Repr {
+        // Turn into canonical form by computing
+        // (a.R) / R = a
+        let tmp = Fp::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]);
+
+        let mut res = [0; 32];
+        res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes());
+        res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes());
+        res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes());
+        res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes());
+
+        res
+    }
+
+    fn is_odd(&self) -> Choice {
+        Choice::from(self.to_repr()[0] & 1)
+    }
+
+    fn multiplicative_generator() -> Self {
+        unimplemented!();
+    }
+
+    fn root_of_unity() -> Self {
+        unimplemented!();
+    }
+}
+
+impl SqrtRatio for Fp {
+    const T_MINUS1_OVER2: [u64; 4] = [0, 0, 0, 0];
+
+    fn get_lower_32(&self) -> u32 {
+        let tmp = Fp::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]);
+        tmp.0[0] as u32
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use ff::Field;
+    use rand_core::OsRng;
+
+    #[test]
+    fn test_sqrt() {
+        // NB: TWO_INV is standing in as a "random" field element
+        let v = (Fp::TWO_INV).square().sqrt().unwrap();
+        assert!(v == Fp::TWO_INV || (-v) == Fp::TWO_INV);
+
+        for _ in 0..10000 {
+            let a = Fp::random(OsRng);
+            let mut b = a;
+            b = b.square();
+
+            let b = b.sqrt().unwrap();
+            let mut negb = b;
+            negb = negb.neg();
+
+            assert!(a == b || a == negb);
+        }
+    }
+
+    #[test]
+    fn test_field() {
+        crate::tests::field::random_field_tests::<Fp>("secp256k1 base".to_string());
+    }
+
+    #[test]
+    fn test_serialization() {
+        crate::tests::field::random_serialization_test::<Fp>("secp256k1 base".to_string());
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/secp256k1/fq.rs.html b/docs/src/halo2curves/secp256k1/fq.rs.html new file mode 100644 index 0000000000..90d71500aa --- /dev/null +++ b/docs/src/halo2curves/secp256k1/fq.rs.html @@ -0,0 +1,654 @@ +fq.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+
use core::convert::TryInto;
+use core::fmt;
+use core::ops::{Add, Mul, Neg, Sub};
+
+use ff::PrimeField;
+use rand::RngCore;
+use serde::{Deserialize, Serialize};
+use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
+
+use crate::arithmetic::{adc, mac, macx, sbb};
+
+use pasta_curves::arithmetic::{FieldExt, Group, SqrtRatio};
+
+/// This represents an element of $\mathbb{F}_q$ where
+///
+/// `q = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141`
+///
+/// is the scalar field of the secp256k1 curve.
+// The internal representation of this type is four 64-bit unsigned
+// integers in little-endian order. `Fq` values are always in
+// Montgomery form; i.e., Fq(a) = aR mod q, with R = 2^256.
+#[derive(Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
+pub struct Fq(pub(crate) [u64; 4]);
+
+/// Constant representing the modulus
+/// q = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
+const MODULUS: Fq = Fq([
+    0xbfd25e8cd0364141,
+    0xbaaedce6af48a03b,
+    0xfffffffffffffffe,
+    0xffffffffffffffff,
+]);
+
+/// The modulus as u32 limbs.
+#[cfg(not(target_pointer_width = "64"))]
+const MODULUS_LIMBS_32: [u32; 8] = [
+    0xd036_4141,
+    0xbfd2_5e8c,
+    0xaf48_a03b,
+    0xbaae_dce6,
+    0xffff_fffe,
+    0xffff_ffff,
+    0xffff_ffff,
+    0xffff_ffff,
+];
+
+///Constant representing the modulus as static str
+const MODULUS_STR: &str = "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141";
+
+/// INV = -(q^{-1} mod 2^64) mod 2^64
+const INV: u64 = 0x4b0dff665588b13f;
+
+/// R = 2^256 mod q
+/// 0x14551231950b75fc4402da1732fc9bebf
+const R: Fq = Fq([0x402da1732fc9bebf, 0x4551231950b75fc4, 0x1, 0]);
+
+/// R^2 = 2^512 mod q
+/// 0x9d671cd581c69bc5e697f5e45bcd07c6741496c20e7cf878896cf21467d7d140
+const R2: Fq = Fq([
+    0x896cf21467d7d140,
+    0x741496c20e7cf878,
+    0xe697f5e45bcd07c6,
+    0x9d671cd581c69bc5,
+]);
+
+/// R^3 = 2^768 mod q
+/// 0x555d800c18ef116db1b31347f1d0b2da0017648444d4322c7bc0cfe0e9ff41ed
+const R3: Fq = Fq([
+    0x7bc0cfe0e9ff41ed,
+    0x0017648444d4322c,
+    0xb1b31347f1d0b2da,
+    0x555d800c18ef116d,
+]);
+
+/// `GENERATOR = 7 mod r` is a generator of the `q - 1` order multiplicative
+/// subgroup, or in other words a primitive root of the field.
+const GENERATOR: Fq = Fq::from_raw([0x07, 0x00, 0x00, 0x00]);
+
+/// GENERATOR^t where t * 2^s + 1 = r
+/// with t odd. In other words, this
+/// is a 2^s root of unity.
+/// `0xc1dc060e7a91986df9879a3fbc483a898bdeab680756045992f4b5402b052f2`
+const ROOT_OF_UNITY: Fq = Fq::from_raw([
+    0x992f4b5402b052f2,
+    0x98bdeab680756045,
+    0xdf9879a3fbc483a8,
+    0xc1dc060e7a91986,
+]);
+
+/// 1 / ROOT_OF_UNITY mod q
+const ROOT_OF_UNITY_INV: Fq = Fq::from_raw([
+    0xb6fb30a0884f0d1c,
+    0x77a275910aa413c3,
+    0xefc7b0c75b8cbb72,
+    0xfd3ae181f12d7096,
+]);
+
+/// 1 / 2 mod q
+const TWO_INV: Fq = Fq::from_raw([
+    0xdfe92f46681b20a1,
+    0x5d576e7357a4501d,
+    0xffffffffffffffff,
+    0x7fffffffffffffff,
+]);
+
+const ZETA: Fq = Fq::zero();
+const DELTA: Fq = Fq::zero();
+
+use crate::{
+    field_arithmetic, field_common, field_specific, impl_add_binop_specify_output,
+    impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative,
+    impl_binops_multiplicative_mixed, impl_sub_binop_specify_output,
+};
+impl_binops_additive!(Fq, Fq);
+impl_binops_multiplicative!(Fq, Fq);
+field_common!(
+    Fq,
+    MODULUS,
+    INV,
+    MODULUS_STR,
+    TWO_INV,
+    ROOT_OF_UNITY_INV,
+    DELTA,
+    ZETA,
+    R,
+    R2,
+    R3
+);
+field_arithmetic!(Fq, MODULUS, INV, dense);
+
+impl Fq {
+    pub const fn size() -> usize {
+        32
+    }
+}
+
+impl ff::Field for Fq {
+    fn random(mut rng: impl RngCore) -> Self {
+        Self::from_u512([
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+            rng.next_u64(),
+        ])
+    }
+
+    fn zero() -> Self {
+        Self::zero()
+    }
+
+    fn one() -> Self {
+        Self::one()
+    }
+
+    fn double(&self) -> Self {
+        self.double()
+    }
+
+    #[inline(always)]
+    fn square(&self) -> Self {
+        self.square()
+    }
+
+    /// Computes the square root of this element, if it exists.
+    fn sqrt(&self) -> CtOption<Self> {
+        crate::arithmetic::sqrt_tonelli_shanks(self, <Self as SqrtRatio>::T_MINUS1_OVER2)
+    }
+
+    /// Computes the multiplicative inverse of this element,
+    /// failing if the element is zero.
+    fn invert(&self) -> CtOption<Self> {
+        let tmp = self.pow_vartime([
+            0xbfd25e8cd036413f,
+            0xbaaedce6af48a03b,
+            0xfffffffffffffffe,
+            0xffffffffffffffff,
+        ]);
+
+        CtOption::new(tmp, !self.ct_eq(&Self::zero()))
+    }
+
+    fn pow_vartime<S: AsRef<[u64]>>(&self, exp: S) -> Self {
+        let mut res = Self::one();
+        let mut found_one = false;
+        for e in exp.as_ref().iter().rev() {
+            for i in (0..64).rev() {
+                if found_one {
+                    res = res.square();
+                }
+
+                if ((*e >> i) & 1) == 1 {
+                    found_one = true;
+                    res *= self;
+                }
+            }
+        }
+        res
+    }
+}
+
+impl ff::PrimeField for Fq {
+    type Repr = [u8; 32];
+
+    const NUM_BITS: u32 = 256;
+    const CAPACITY: u32 = 255;
+    const S: u32 = 6;
+
+    fn from_repr(repr: Self::Repr) -> CtOption<Self> {
+        let mut tmp = Fq([0, 0, 0, 0]);
+
+        tmp.0[0] = u64::from_le_bytes(repr[0..8].try_into().unwrap());
+        tmp.0[1] = u64::from_le_bytes(repr[8..16].try_into().unwrap());
+        tmp.0[2] = u64::from_le_bytes(repr[16..24].try_into().unwrap());
+        tmp.0[3] = u64::from_le_bytes(repr[24..32].try_into().unwrap());
+
+        // Try to subtract the modulus
+        let (_, borrow) = tmp.0[0].overflowing_sub(MODULUS.0[0]);
+        let (_, borrow) = sbb(tmp.0[1], MODULUS.0[1], borrow);
+        let (_, borrow) = sbb(tmp.0[2], MODULUS.0[2], borrow);
+        let (_, borrow) = sbb(tmp.0[3], MODULUS.0[3], borrow);
+
+        // If the element is smaller than MODULUS then the
+        // subtraction will underflow, producing a borrow value
+        // of 0xffff...ffff. Otherwise, it'll be zero.
+        let is_some = (borrow as u8) & 1;
+
+        // Convert to Montgomery form by computing
+        // (a.R^0 * R^2) / R = a.R
+        tmp *= &R2;
+
+        CtOption::new(tmp, Choice::from(is_some))
+    }
+
+    fn to_repr(&self) -> Self::Repr {
+        // Turn into canonical form by computing
+        // (a.R) / R = a
+        let tmp = Fq::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]);
+
+        let mut res = [0; 32];
+        res[0..8].copy_from_slice(&tmp.0[0].to_le_bytes());
+        res[8..16].copy_from_slice(&tmp.0[1].to_le_bytes());
+        res[16..24].copy_from_slice(&tmp.0[2].to_le_bytes());
+        res[24..32].copy_from_slice(&tmp.0[3].to_le_bytes());
+
+        res
+    }
+
+    fn is_odd(&self) -> Choice {
+        Choice::from(self.to_repr()[0] & 1)
+    }
+
+    fn multiplicative_generator() -> Self {
+        GENERATOR
+    }
+
+    fn root_of_unity() -> Self {
+        ROOT_OF_UNITY
+    }
+}
+
+impl SqrtRatio for Fq {
+    const T_MINUS1_OVER2: [u64; 4] = [
+        0x777fa4bd19a06c82,
+        0xfd755db9cd5e9140,
+        0xffffffffffffffff,
+        0x01ffffffffffffff,
+    ];
+
+    fn get_lower_32(&self) -> u32 {
+        let tmp = Fq::montgomery_reduce_short(self.0[0], self.0[1], self.0[2], self.0[3]);
+        tmp.0[0] as u32
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use ff::Field;
+    use rand_core::OsRng;
+
+    #[test]
+    fn test_sqrt() {
+        // NB: TWO_INV is standing in as a "random" field element
+        let v = (Fq::TWO_INV).square().sqrt().unwrap();
+        assert!(v == Fq::TWO_INV || (-v) == Fq::TWO_INV);
+
+        for _ in 0..10000 {
+            let a = Fq::random(OsRng);
+            let mut b = a;
+            b = b.square();
+
+            let b = b.sqrt().unwrap();
+            let mut negb = b;
+            negb = negb.neg();
+
+            assert!(a == b || a == negb);
+        }
+    }
+
+    #[test]
+    fn test_root_of_unity() {
+        assert_eq!(
+            Fq::root_of_unity().pow_vartime([1 << Fq::S, 0, 0, 0]),
+            Fq::one()
+        );
+    }
+
+    #[test]
+    fn test_inv_root_of_unity() {
+        assert_eq!(Fq::ROOT_OF_UNITY_INV, Fq::root_of_unity().invert().unwrap());
+    }
+
+    #[test]
+    fn test_field() {
+        crate::tests::field::random_field_tests::<Fq>("secp256k1 scalar".to_string());
+    }
+
+    #[test]
+    fn test_serialization() {
+        crate::tests::field::random_serialization_test::<Fq>("secp256k1 scalar".to_string());
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/secp256k1/mod.rs.html b/docs/src/halo2curves/secp256k1/mod.rs.html new file mode 100644 index 0000000000..9adb39d210 --- /dev/null +++ b/docs/src/halo2curves/secp256k1/mod.rs.html @@ -0,0 +1,16 @@ +mod.rs - source
1
+2
+3
+4
+5
+6
+7
+
mod curve;
+mod fp;
+mod fq;
+
+pub use curve::*;
+pub use fp::*;
+pub use fq::*;
+
+
\ No newline at end of file diff --git a/docs/src/halo2curves/serde.rs.html b/docs/src/halo2curves/serde.rs.html new file mode 100644 index 0000000000..50b437f203 --- /dev/null +++ b/docs/src/halo2curves/serde.rs.html @@ -0,0 +1,52 @@ +serde.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+
use std::io::{self, Read, Write};
+
+/// Trait for converting raw bytes to/from the internal representation of a type.
+/// For example, field elements are represented in Montgomery form and serialized/deserialized without Montgomery reduction.
+pub trait SerdeObject: Sized {
+    /// The purpose of unchecked functions is to read the internal memory representation
+    /// of a type from bytes as quickly as possible. No sanitization checks are performed
+    /// to ensure the bytes represent a valid object. As such this function should only be
+    /// used internally as an extension of machine memory. It should not be used to deserialize
+    /// externally provided data.
+    fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self;
+    fn from_raw_bytes(bytes: &[u8]) -> Option<Self>;
+
+    fn to_raw_bytes(&self) -> Vec<u8>;
+
+    /// The purpose of unchecked functions is to read the internal memory representation
+    /// of a type from disk as quickly as possible. No sanitization checks are performed
+    /// to ensure the bytes represent a valid object. This function should only be used
+    /// internally when some machine state cannot be kept in memory (e.g., between runs)
+    /// and needs to be reloaded as quickly as possible.
+    fn read_raw_unchecked<R: Read>(reader: &mut R) -> Self;
+    fn read_raw<R: Read>(reader: &mut R) -> io::Result<Self>;
+
+    fn write_raw<W: Write>(&self, writer: &mut W) -> io::Result<()>;
+}
+
+
\ No newline at end of file diff --git a/docs/src/poseidon/grain.rs.html b/docs/src/poseidon/grain.rs.html new file mode 100644 index 0000000000..6bff5f7f35 --- /dev/null +++ b/docs/src/poseidon/grain.rs.html @@ -0,0 +1,324 @@ +grain.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+
use crate::spec::MDSMatrix;
+use halo2curves::FieldExt;
+use std::marker::PhantomData;
+
+/// Grain initializes round constants and MDS matrix at given sponge parameters
+pub(super) struct Grain<F: FieldExt, const T: usize, const RATE: usize> {
+    bit_sequence: Vec<bool>,
+    _field: PhantomData<F>,
+}
+
+impl<F: FieldExt, const T: usize, const RATE: usize> Grain<F, T, RATE> {
+    pub(crate) fn generate(r_f: usize, r_p: usize) -> (Vec<[F; T]>, MDSMatrix<F, T, RATE>) {
+        debug_assert!(T > 1 && T == RATE + 1);
+
+        // Support only prime field construction
+        const FIELD_TYPE: u8 = 1u8;
+        // Support only \alpha s-box
+        const SBOX_TYPE: u8 = 0;
+
+        let field_size = F::NUM_BITS;
+        let n_bytes = F::Repr::default().as_ref().len();
+        assert_eq!((field_size as f32 / 8.0).ceil() as usize, n_bytes);
+        assert_eq!(r_f % 2, 0);
+
+        // Pseudo random number generation. See:
+        // Initialization of the Grain LFSR Used for Parameter Generation
+        // Supplementary Material Section F
+        // https://eprint.iacr.org/2019/458.pdf
+        let mut bit_sequence: Vec<bool> = Vec::new();
+        append_bits(&mut bit_sequence, 2, FIELD_TYPE);
+        append_bits(&mut bit_sequence, 4, SBOX_TYPE);
+        append_bits(&mut bit_sequence, 12, field_size);
+        append_bits(&mut bit_sequence, 12, T as u32);
+        append_bits(&mut bit_sequence, 10, r_f as u16);
+        append_bits(&mut bit_sequence, 10, r_p as u16);
+        append_bits(&mut bit_sequence, 30, 0b111111111111111111111111111111u128);
+        debug_assert_eq!(bit_sequence.len(), 80);
+
+        let mut grain: Grain<F, T, RATE> = Grain {
+            bit_sequence,
+            _field: PhantomData,
+        };
+
+        for _ in 0..160 {
+            grain.new_bit();
+        }
+        assert_eq!(grain.bit_sequence.len(), 80);
+
+        let number_of_rounds = r_p as usize + r_f as usize;
+        let constants = (0..number_of_rounds)
+            .map(|_| {
+                let mut round_constants = [F::zero(); T];
+                for c in round_constants.iter_mut() {
+                    *c = grain.next_field_element();
+                }
+                round_constants
+            })
+            .collect::<Vec<[F; T]>>();
+
+        let (mut xs, mut ys) = ([F::zero(); T], [F::zero(); T]);
+        for x in xs.iter_mut() {
+            *x = grain.next_field_element_without_rejection();
+        }
+        for y in ys.iter_mut() {
+            *y = grain.next_field_element_without_rejection();
+        }
+
+        (constants, MDSMatrix::cauchy(&xs, &ys))
+    }
+
+    /// Credit: https://github.com/zcash/halo2/tree/main/halo2_gadgets/src/primitives/poseidon
+    /// Returns the next field element from this Grain instantiation.
+    pub(super) fn next_field_element(&mut self) -> F {
+        // Loop until we get an element in the field.
+        loop {
+            let mut bytes = F::Repr::default();
+
+            // Poseidon reference impl interprets the bits as a repr in MSB order, because
+            // it's easy to do that in Python. Meanwhile, our field elements all use LSB
+            // order. There's little motivation to diverge from the reference impl; these
+            // are all constants, so we aren't introducing big-endianness into the rest of
+            // the circuit (assuming unkeyed Poseidon, but we probably wouldn't want to
+            // implement Grain inside a circuit, so we'd use a different round constant
+            // derivation function there).
+            let view = bytes.as_mut();
+            for (i, bit) in self.take(F::NUM_BITS as usize).enumerate() {
+                // If we diverged from the reference impl and interpreted the bits in LSB
+                // order, we would remove this line.
+                let i = F::NUM_BITS as usize - 1 - i;
+
+                view[i / 8] |= if bit { 1 << (i % 8) } else { 0 };
+            }
+
+            if let Some(f) = F::from_repr_vartime(bytes) {
+                break f;
+            }
+        }
+    }
+
+    /// Credit: https://github.com/zcash/halo2/tree/main/halo2_gadgets/src/primitives/poseidon
+    /// Returns the next field element from this Grain instantiation, without
+    /// using rejection sampling.
+    pub(super) fn next_field_element_without_rejection(&mut self) -> F {
+        let mut bytes = [0u8; 64];
+
+        // Poseidon reference impl interprets the bits as a repr in MSB order, because
+        // it's easy to do that in Python. Additionally, it does not use rejection
+        // sampling in cases where the constants don't specifically need to be uniformly
+        // random for security. We do not provide APIs that take a field-element-sized
+        // array and reduce it modulo the field order, because those are unsafe APIs to
+        // offer generally (accidentally using them can lead to divergence in consensus
+        // systems due to not rejecting canonical forms).
+        //
+        // Given that we don't want to diverge from the reference implementation, we
+        // hack around this restriction by serializing the bits into a 64-byte
+        // array and then calling F::from_bytes_wide. PLEASE DO NOT COPY THIS
+        // INTO YOUR OWN CODE!
+        let view = bytes.as_mut();
+        for (i, bit) in self.take(F::NUM_BITS as usize).enumerate() {
+            // If we diverged from the reference impl and interpreted the bits in LSB
+            // order, we would remove this line.
+            let i = F::NUM_BITS as usize - 1 - i;
+
+            view[i / 8] |= if bit { 1 << (i % 8) } else { 0 };
+        }
+
+        F::from_bytes_wide(&bytes)
+    }
+
+    fn new_bit(&mut self) -> bool {
+        // See supplementary material Section F. Step 2.
+        // https://eprint.iacr.org/2019/458.pdf
+        let new_bit = vec![62, 51, 38, 23, 13usize]
+            .iter()
+            .fold(self.bit_sequence[0], |acc, pos| {
+                acc ^ self.bit_sequence[*pos]
+            });
+        assert_eq!(self.bit_sequence.len(), 80);
+        self.bit_sequence.remove(0);
+        self.bit_sequence.push(new_bit);
+        new_bit
+    }
+}
+
+impl<F: FieldExt, const T: usize, const RATE: usize> Iterator for Grain<F, T, RATE> {
+    type Item = bool;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        while !self.new_bit() {
+            self.new_bit();
+        }
+        Some(self.new_bit())
+    }
+}
+
+fn append_bits<T: Into<u128>>(vec: &mut Vec<bool>, n: usize, from: T) {
+    let val = from.into() as u128;
+    for i in (0..n).rev() {
+        vec.push((val >> i) & 1 != 0);
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/poseidon/lib.rs.html b/docs/src/poseidon/lib.rs.html new file mode 100644 index 0000000000..bcfb83a906 --- /dev/null +++ b/docs/src/poseidon/lib.rs.html @@ -0,0 +1,30 @@ +lib.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+
//! Poseidon hashing implemention with variable lenght input setting. This crate
+//! also exposes constant parameters for circuit implementations
+
+#![deny(missing_debug_implementations)]
+#![deny(missing_docs)]
+
+mod grain;
+mod matrix;
+mod permutation;
+mod poseidon;
+mod spec;
+
+pub use crate::poseidon::Poseidon;
+pub use crate::spec::{MDSMatrices, MDSMatrix, SparseMDSMatrix, Spec, State};
+
+
\ No newline at end of file diff --git a/docs/src/poseidon/matrix.rs.html b/docs/src/poseidon/matrix.rs.html new file mode 100644 index 0000000000..4eac919ec5 --- /dev/null +++ b/docs/src/poseidon/matrix.rs.html @@ -0,0 +1,292 @@ +matrix.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+
//! Most of these operations here are not suitable for general purpose matrix
+//! operations. Besides vector multiplication other operations are presented
+//! with the intention of construction of parameters and are not used in the
+//! actual permutation process.
+
+use halo2curves::FieldExt;
+
+#[derive(PartialEq, Debug, Clone)]
+pub(crate) struct Matrix<F: FieldExt, const T: usize>(pub(crate) [[F; T]; T]);
+
+impl<F: FieldExt, const T: usize> Default for Matrix<F, T> {
+    fn default() -> Self {
+        Matrix([[F::zero(); T]; T])
+    }
+}
+
+impl<F: FieldExt, const T: usize> Matrix<F, T> {
+    #[inline]
+    pub(crate) fn zero_matrix() -> Self {
+        Self([[F::zero(); T]; T])
+    }
+
+    #[inline]
+    pub(crate) fn identity() -> Self {
+        let mut m = Self::zero_matrix();
+        for i in 0..T {
+            m.set(i, i, F::one())
+        }
+        m
+    }
+
+    pub(crate) fn set(&mut self, row: usize, col: usize, value: F) {
+        self.0[row][col] = value;
+    }
+
+    pub(crate) fn from_vec(vec: Vec<Vec<F>>) -> Self {
+        let n = vec.len();
+        // Expect square and well formed matrix
+        for row in vec.iter() {
+            assert_eq!(row.len(), n);
+        }
+
+        let mut result = Self::default();
+        for (row_result, row_inverted) in result.0.iter_mut().zip(vec.iter()) {
+            for (result_cell, cell) in row_result.iter_mut().zip(row_inverted.iter()) {
+                *result_cell = *cell
+            }
+        }
+        result
+    }
+
+    pub(crate) fn transpose(&self) -> Self {
+        let mut result = Self::default();
+        for (i, row) in self.0.iter().enumerate() {
+            for (j, e) in row.iter().enumerate() {
+                result.0[j][i] = *e
+            }
+        }
+        result
+    }
+
+    pub(crate) fn mul(&self, other: &Self) -> Self {
+        let mut result = Self::default();
+        for i in 0..T {
+            for j in 0..T {
+                for k in 0..T {
+                    result.0[i][j] += self.0[i][k] * other.0[k][j];
+                }
+            }
+        }
+        result
+    }
+
+    pub(crate) fn mul_vector(&self, v: &[F; T]) -> [F; T] {
+        let mut result = [F::zero(); T];
+        for (row, cell) in self.0.iter().zip(result.iter_mut()) {
+            for (a_i, v_i) in row.iter().zip(v.iter()) {
+                *cell += *v_i * *a_i;
+            }
+        }
+        result
+    }
+
+    // This is very pesky implementation of matrix inversion,
+    // It won't even alarm when a matrix is not invertable.
+    pub(crate) fn invert(&self) -> Self {
+        let identity = Self::identity();
+
+        let mut m: Vec<Vec<F>> = identity
+            .0
+            .iter()
+            .zip(self.0.iter())
+            .map(|(u_row, v_row)| {
+                let mut row = v_row.to_vec();
+                row.extend(u_row.to_vec());
+                row
+            })
+            .collect();
+
+        for i in 0..T {
+            for j in 0..T {
+                if i != j {
+                    let r = m[j][i] * m[i][i].invert().unwrap();
+                    for k in 0..2 * T {
+                        let e = m[i][k];
+                        m[j][k] -= r * e;
+                    }
+                }
+            }
+        }
+
+        let mut res = Self::default();
+        for (i, row) in m.iter_mut().enumerate().take(T) {
+            for j in T..2 * T {
+                let e = row[i];
+                row[j] *= e.invert().unwrap()
+            }
+        }
+
+        for (i, row) in m.iter().enumerate().take(T) {
+            for j in 0..T {
+                res.set(i, j, row[j + T]);
+            }
+        }
+        res
+    }
+
+    #[inline]
+    pub(crate) fn w<const RATE: usize>(&self) -> [F; RATE] {
+        assert_eq!(RATE + 1, T);
+        self.0
+            .iter()
+            .skip(1)
+            .map(|row| row[0])
+            .collect::<Vec<F>>()
+            .try_into()
+            .unwrap()
+    }
+
+    #[inline]
+    pub(crate) fn sub<const RATE: usize>(&self) -> Matrix<F, RATE> {
+        assert_eq!(RATE + 1, T);
+        Matrix::<F, RATE>::from_vec(self.0.iter().skip(1).map(|row| row[1..].to_vec()).collect())
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/poseidon/permutation.rs.html b/docs/src/poseidon/permutation.rs.html new file mode 100644 index 0000000000..d2ff5c510b --- /dev/null +++ b/docs/src/poseidon/permutation.rs.html @@ -0,0 +1,416 @@ +permutation.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+
use crate::spec::{Spec, State};
+use halo2curves::FieldExt;
+
+impl<F: FieldExt, const T: usize, const RATE: usize> Spec<F, T, RATE> {
+    /// Applies the Poseidon permutation to the given state
+    pub fn permute(&self, state: &mut State<F, T>) {
+        let r_f = self.r_f / 2;
+
+        // First half of the full rounds
+        {
+            state.add_constants(&self.constants.start[0]);
+            for round_constants in self.constants.start.iter().skip(1).take(r_f - 1) {
+                state.sbox_full();
+                state.add_constants(round_constants);
+                self.mds_matrices.mds.apply(state);
+            }
+            state.sbox_full();
+            state.add_constants(self.constants.start.last().unwrap());
+            self.mds_matrices.pre_sparse_mds.apply(state)
+        }
+
+        // Partial rounds
+        {
+            for (round_constant, sparse_mds) in self
+                .constants
+                .partial
+                .iter()
+                .zip(self.mds_matrices.sparse_matrices.iter())
+            {
+                state.sbox_part();
+                state.add_constant(round_constant);
+                sparse_mds.apply(state);
+            }
+        }
+
+        // Second half of the full rounds
+        {
+            for round_constants in self.constants.end.iter() {
+                state.sbox_full();
+                state.add_constants(round_constants);
+                self.mds_matrices.mds.apply(state);
+            }
+            state.sbox_full();
+            self.mds_matrices.mds.apply(state);
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::State;
+    use crate::spec::{tests::SpecRef, Spec};
+    use group::ff::PrimeField;
+    use halo2curves::bn256::Fr;
+    use halo2curves::FieldExt;
+
+    /// We want to keep unoptimized poseidion construction and permutation to
+    /// cross test with optimized one
+    impl<F: FieldExt, const T: usize, const RATE: usize> SpecRef<F, T, RATE> {
+        fn permute(&self, state: &mut State<F, T>) {
+            let (r_f, r_p) = (self.r_f / 2, self.r_p);
+
+            for constants in self.constants.iter().take(r_f) {
+                state.add_constants(constants);
+                state.sbox_full();
+                self.mds.apply(state);
+            }
+
+            for constants in self.constants.iter().skip(r_f).take(r_p) {
+                state.add_constants(constants);
+                state.sbox_part();
+                self.mds.apply(state);
+            }
+
+            for constants in self.constants.iter().skip(r_f + r_p) {
+                state.add_constants(constants);
+                state.sbox_full();
+                self.mds.apply(state);
+            }
+        }
+    }
+
+    #[test]
+    fn cross_test() {
+        use halo2curves::group::ff::Field;
+        use rand_core::OsRng;
+        use std::time::Instant;
+
+        macro_rules! run_test {
+            (
+                $([$RF:expr, $RP:expr, $T:expr, $RATE:expr]),*
+            ) => {
+                $(
+                    {
+                        const R_F: usize = $RF;
+                        const R_P: usize = $RP;
+                        const T: usize = $T;
+                        const RATE: usize = $RATE;
+                        let mut state = State(
+                            (0..T)
+                                .map(|_| Fr::random(OsRng))
+                                .collect::<Vec<Fr>>()
+                                .try_into().unwrap(),
+                        );
+                        let spec = SpecRef::<Fr, T, RATE>::new(R_F, R_P);
+                        let mut state_expected = state.clone();
+                        spec.permute(&mut state_expected);
+
+                        let spec = Spec::<Fr, T, RATE>::new(R_F, R_P);
+                        let now = Instant::now();
+                        {
+                            spec.permute(&mut state);
+                        }
+                        let elapsed = now.elapsed();
+                        println!("Elapsed: {:.2?}", elapsed);
+                        assert_eq!(state_expected, state);
+                    }
+                )*
+            };
+        }
+        run_test!([8, 57, 3, 2]);
+        run_test!([8, 57, 4, 3]);
+        run_test!([8, 57, 5, 4]);
+        run_test!([8, 57, 6, 5]);
+        run_test!([8, 57, 7, 6]);
+        run_test!([8, 57, 8, 7]);
+        run_test!([8, 57, 9, 8]);
+        run_test!([8, 57, 10, 9]);
+    }
+
+    #[test]
+    fn test_against_test_vectors() {
+        // https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/test_vectors.txt
+        // poseidonperm_x5_254_3
+        {
+            const R_F: usize = 8;
+            const R_P: usize = 57;
+            const T: usize = 3;
+            const RATE: usize = 2;
+
+            let state = State(
+                vec![0u64, 1, 2]
+                    .into_iter()
+                    .map(Fr::from)
+                    .collect::<Vec<Fr>>()
+                    .try_into()
+                    .unwrap(),
+            );
+
+            let spec_ref = SpecRef::<Fr, T, RATE>::new(R_F, R_P);
+            let mut state_0 = state.clone();
+
+            spec_ref.permute(&mut state_0);
+            let expected = vec![
+                "7853200120776062878684798364095072458815029376092732009249414926327459813530",
+                "7142104613055408817911962100316808866448378443474503659992478482890339429929",
+                "6549537674122432311777789598043107870002137484850126429160507761192163713804",
+            ];
+            for (word, expected) in state_0.words().into_iter().zip(expected.iter()) {
+                assert_eq!(word, Fr::from_str_vartime(expected).unwrap());
+            }
+
+            let spec = Spec::<Fr, T, RATE>::new(R_F, R_P);
+            let mut state_1 = state;
+            spec.permute(&mut state_1);
+            assert_eq!(state_0, state_1);
+        }
+
+        // https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/test_vectors.txt
+        // poseidonperm_x5_254_5
+        {
+            const R_F: usize = 8;
+            const R_P: usize = 60;
+            const T: usize = 5;
+            const RATE: usize = 4;
+
+            let state = State(
+                vec![0u64, 1, 2, 3, 4]
+                    .into_iter()
+                    .map(Fr::from)
+                    .collect::<Vec<Fr>>()
+                    .try_into()
+                    .unwrap(),
+            );
+
+            let spec_ref = SpecRef::<Fr, T, RATE>::new(R_F, R_P);
+            let mut state_0 = state.clone();
+
+            spec_ref.permute(&mut state_0);
+            let expected = vec![
+                "18821383157269793795438455681495246036402687001665670618754263018637548127333",
+                "7817711165059374331357136443537800893307845083525445872661165200086166013245",
+                "16733335996448830230979566039396561240864200624113062088822991822580465420551",
+                "6644334865470350789317807668685953492649391266180911382577082600917830417726",
+                "3372108894677221197912083238087960099443657816445944159266857514496320565191",
+            ];
+            for (word, expected) in state_0.words().into_iter().zip(expected.iter()) {
+                assert_eq!(word, Fr::from_str_vartime(expected).unwrap());
+            }
+
+            let spec = Spec::<Fr, T, RATE>::new(R_F, R_P);
+            let mut state_1 = state;
+            spec.permute(&mut state_1);
+            assert_eq!(state_0, state_1);
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/src/poseidon/poseidon.rs.html b/docs/src/poseidon/poseidon.rs.html new file mode 100644 index 0000000000..eaa15cc30b --- /dev/null +++ b/docs/src/poseidon/poseidon.rs.html @@ -0,0 +1,376 @@ +poseidon.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+
use crate::{Spec, State};
+use halo2curves::FieldExt;
+
+/// Poseidon hasher that maintains state and inputs and yields single element
+/// output when desired
+#[derive(Debug, Clone)]
+pub struct Poseidon<F: FieldExt, const T: usize, const RATE: usize> {
+    state: State<F, T>,
+    spec: Spec<F, T, RATE>,
+    absorbing: Vec<F>,
+}
+
+impl<F: FieldExt, const T: usize, const RATE: usize> Poseidon<F, T, RATE> {
+    /// Constructs a clear state poseidon instance
+    pub fn new(r_f: usize, r_p: usize) -> Self {
+        Self {
+            spec: Spec::new(r_f, r_p),
+            state: State::default(),
+            absorbing: Vec::new(),
+        }
+    }
+
+    /// Appends elements to the absorption line updates state while `RATE` is
+    /// full
+    pub fn update(&mut self, elements: &[F]) {
+        let mut input_elements = self.absorbing.clone();
+        input_elements.extend_from_slice(elements);
+
+        for chunk in input_elements.chunks(RATE) {
+            if chunk.len() < RATE {
+                // Must be the last iteration of this update. Feed unpermutaed inputs to the
+                // absorbation line
+                self.absorbing = chunk.to_vec();
+            } else {
+                // Add new chunk of inputs for the next permutation cycle.
+                for (input_element, state) in chunk.iter().zip(self.state.0.iter_mut().skip(1)) {
+                    state.add_assign(input_element);
+                }
+                // Perform intermediate permutation
+                self.spec.permute(&mut self.state);
+                // Flush the absorption line
+                self.absorbing.clear();
+            }
+        }
+    }
+
+    /// Results a single element by absorbing already added inputs
+    pub fn squeeze(&mut self) -> F {
+        let mut last_chunk = self.absorbing.clone();
+        {
+            // Expect padding offset to be in [0, RATE)
+            debug_assert!(last_chunk.len() < RATE);
+        }
+        // Add the finishing sign of the variable length hashing. Note that this mut
+        // also apply when absorbing line is empty
+        last_chunk.push(F::one());
+        // Add the last chunk of inputs to the state for the final permutation cycle
+
+        for (input_element, state) in last_chunk.iter().zip(self.state.0.iter_mut().skip(1)) {
+            state.add_assign(input_element);
+        }
+
+        // Perform final permutation
+        self.spec.permute(&mut self.state);
+        // Flush the absorption line
+        self.absorbing.clear();
+        // Returns the challenge while preserving internal state
+        self.state.result()
+    }
+}
+
+#[test]
+fn test_padding() {
+    use group::ff::Field;
+    use halo2curves::bn256::Fr;
+
+    const R_F: usize = 8;
+    const R_P: usize = 57;
+    const T: usize = 5;
+    const RATE: usize = 4;
+
+    use rand_core::OsRng;
+
+    // w/o extra permutation
+    {
+        let mut poseidon = Poseidon::<Fr, T, RATE>::new(R_F, R_P);
+        let number_of_permutation = 5;
+        let number_of_inputs = RATE * number_of_permutation - 1;
+        let inputs = (0..number_of_inputs)
+            .map(|_| Fr::random(OsRng))
+            .collect::<Vec<Fr>>();
+        poseidon.update(&inputs[..]);
+        let result_0 = poseidon.squeeze();
+
+        let spec = poseidon.spec.clone();
+        let mut inputs = inputs.clone();
+        inputs.push(Fr::one());
+        assert!(inputs.len() % RATE == 0);
+        let mut state = State::<Fr, T>::default();
+        for chunk in inputs.chunks(RATE) {
+            let mut inputs = vec![Fr::zero()];
+            inputs.extend_from_slice(chunk);
+            state.add_constants(&inputs.try_into().unwrap());
+            spec.permute(&mut state)
+        }
+        let result_1 = state.result();
+
+        assert_eq!(result_0, result_1);
+    }
+
+    // w/ extra permutation
+    {
+        let mut poseidon = Poseidon::<Fr, T, RATE>::new(R_F, R_P);
+        let number_of_permutation = 5;
+        let number_of_inputs = RATE * number_of_permutation;
+        let inputs = (0..number_of_inputs)
+            .map(|_| Fr::random(OsRng))
+            .collect::<Vec<Fr>>();
+        poseidon.update(&inputs[..]);
+        let result_0 = poseidon.squeeze();
+
+        let spec = poseidon.spec.clone();
+        let mut inputs = inputs.clone();
+        let mut extra_padding = vec![Fr::zero(); RATE];
+        extra_padding[0] = Fr::one();
+        inputs.extend(extra_padding);
+
+        assert!(inputs.len() % RATE == 0);
+        let mut state = State::<Fr, T>::default();
+        for chunk in inputs.chunks(RATE) {
+            let mut inputs = vec![Fr::zero()];
+            inputs.extend_from_slice(chunk);
+            state.add_constants(&inputs.try_into().unwrap());
+            spec.permute(&mut state)
+        }
+        let result_1 = state.result();
+
+        assert_eq!(result_0, result_1);
+    }
+
+    // Much generic comparision
+    fn run<const T: usize, const RATE: usize>() {
+        for number_of_iters in 1..25 {
+            let mut poseidon = Poseidon::<Fr, T, RATE>::new(R_F, R_P);
+
+            let mut inputs = vec![];
+            for number_of_inputs in 0..=number_of_iters {
+                let chunk = (0..number_of_inputs)
+                    .map(|_| Fr::random(OsRng))
+                    .collect::<Vec<Fr>>();
+                poseidon.update(&chunk[..]);
+                inputs.extend(chunk);
+            }
+            let result_0 = poseidon.squeeze();
+
+            // Accept below as reference and check consistency
+            inputs.push(Fr::one());
+            let offset = inputs.len() % RATE;
+            if offset != 0 {
+                inputs.extend(vec![Fr::zero(); RATE - offset]);
+            }
+
+            let spec = poseidon.spec.clone();
+            let mut state = State::<Fr, T>::default();
+            for chunk in inputs.chunks(RATE) {
+                // First element is zero
+                let mut round_inputs = vec![Fr::zero()];
+                // Round inputs must be T sized now
+                round_inputs.extend_from_slice(chunk);
+
+                state.add_constants(&round_inputs.try_into().unwrap());
+                spec.permute(&mut state)
+            }
+            let result_1 = state.result();
+            assert_eq!(result_0, result_1);
+        }
+    }
+
+    run::<3, 2>();
+    run::<4, 3>();
+    run::<5, 4>();
+    run::<6, 5>();
+    run::<7, 6>();
+    run::<8, 7>();
+    run::<9, 8>();
+    run::<10, 9>();
+}
+
+
\ No newline at end of file diff --git a/docs/src/poseidon/spec.rs.html b/docs/src/poseidon/spec.rs.html new file mode 100644 index 0000000000..3f9e0320ff --- /dev/null +++ b/docs/src/poseidon/spec.rs.html @@ -0,0 +1,850 @@ +spec.rs - source
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+
use std::ops::Index;
+
+use crate::{grain::Grain, matrix::Matrix};
+use halo2curves::FieldExt;
+
+/// `State` is structure `T` sized field elements that are subjected to
+/// permutation
+#[derive(Clone, Debug, PartialEq)]
+pub struct State<F: FieldExt, const T: usize>(pub(crate) [F; T]);
+
+impl<F: FieldExt, const T: usize> Default for State<F, T> {
+    /// The capacity value is 2**64 + (o − 1) where o the output length.
+    fn default() -> Self {
+        let mut state = [F::zero(); T];
+        state[0] = F::from_u128(1 << 64);
+        State(state)
+    }
+}
+
+impl<F: FieldExt, const T: usize> State<F, T> {
+    /// Applies sbox for all elements of the state.
+    /// Only supports `alpha = 5` sbox case.
+    pub(crate) fn sbox_full(&mut self) {
+        for e in self.0.iter_mut() {
+            let tmp = e.mul(*e);
+            e.mul_assign(tmp);
+            e.mul_assign(tmp);
+        }
+    }
+
+    /// Partial round sbox applies sbox to the first element of the state.
+    /// Only supports `alpha = 5` sbox case
+    pub(crate) fn sbox_part(&mut self) {
+        let tmp = self.0[0].mul(self.0[0]);
+        self.0[0].mul_assign(tmp);
+        self.0[0].mul_assign(tmp);
+    }
+
+    /// Adds constants to all elements of the state
+    pub(crate) fn add_constants(&mut self, constants: &[F; T]) {
+        for (e, constant) in self.0.iter_mut().zip(constants.iter()) {
+            e.add_assign(constant)
+        }
+    }
+
+    /// Only adds a constant to the first element of the state.It is used with
+    /// optimized rounds constants where only single element is added in
+    /// each partial round
+    pub(crate) fn add_constant(&mut self, constant: &F) {
+        self.0[0].add_assign(constant)
+    }
+
+    /// Copies elements of the state
+    pub fn words(&self) -> [F; T] {
+        self.0
+    }
+
+    /// Second element of the state is the result
+    pub(crate) fn result(&self) -> F {
+        self.0[1]
+    }
+}
+
+/// `Spec` holds construction parameters as well as constants that are used in
+/// permutation step. Constants are planned to be hardcoded once transcript
+/// design matures. Number of partial rounds can be deriven from number of
+/// constants.
+#[derive(Debug, Clone)]
+pub struct Spec<F: FieldExt, const T: usize, const RATE: usize> {
+    pub(crate) r_f: usize,
+    pub(crate) mds_matrices: MDSMatrices<F, T, RATE>,
+    pub(crate) constants: OptimizedConstants<F, T>,
+}
+
+impl<F: FieldExt, const T: usize, const RATE: usize> Spec<F, T, RATE> {
+    /// Number of full rounds
+    pub fn r_f(&self) -> usize {
+        self.r_f.clone()
+    }
+    /// Set of MDS Matrices used in permutation line
+    pub fn mds_matrices(&self) -> &MDSMatrices<F, T, RATE> {
+        &self.mds_matrices
+    }
+    /// Optimised round constants
+    pub fn constants(&self) -> &OptimizedConstants<F, T> {
+        &self.constants
+    }
+}
+
+/// `OptimizedConstants` has round constants that are added each round. While
+/// full rounds has T sized constants there is a single constant for each
+/// partial round
+#[derive(Debug, Clone)]
+pub struct OptimizedConstants<F: FieldExt, const T: usize> {
+    pub(crate) start: Vec<[F; T]>,
+    pub(crate) partial: Vec<F>,
+    pub(crate) end: Vec<[F; T]>,
+}
+
+impl<F: FieldExt, const T: usize> OptimizedConstants<F, T> {
+    /// Returns rounds constants for first part of full rounds
+    pub fn start(&self) -> &Vec<[F; T]> {
+        &self.start
+    }
+
+    /// Returns rounds constants for partial rounds
+    pub fn partial(&self) -> &Vec<F> {
+        &self.partial
+    }
+
+    /// Returns rounds constants for second part of full rounds
+    pub fn end(&self) -> &Vec<[F; T]> {
+        &self.end
+    }
+}
+
+/// `MDSMatrices` holds the MDS matrix as well as transition matrix which is
+/// also called `pre_sparse_mds` and sparse matrices that enables us to reduce
+/// number of multiplications in apply MDS step
+#[derive(Debug, Clone)]
+pub struct MDSMatrices<F: FieldExt, const T: usize, const RATE: usize> {
+    pub(crate) mds: MDSMatrix<F, T, RATE>,
+    pub(crate) pre_sparse_mds: MDSMatrix<F, T, RATE>,
+    pub(crate) sparse_matrices: Vec<SparseMDSMatrix<F, T, RATE>>,
+}
+
+impl<F: FieldExt, const T: usize, const RATE: usize> MDSMatrices<F, T, RATE> {
+    /// Returns original MDS matrix
+    pub fn mds(&self) -> &MDSMatrix<F, T, RATE> {
+        &self.mds
+    }
+
+    /// Returns transition matrix for sparse trick
+    pub fn pre_sparse_mds(&self) -> &MDSMatrix<F, T, RATE> {
+        &self.pre_sparse_mds
+    }
+
+    /// Returns sparse matrices for partial rounds
+    pub fn sparse_matrices(&self) -> &Vec<SparseMDSMatrix<F, T, RATE>> {
+        &self.sparse_matrices
+    }
+}
+
+/// `MDSMatrix` is applied to `State` to achive linear layer of Poseidon
+#[derive(Clone, Debug)]
+pub struct MDSMatrix<F: FieldExt, const T: usize, const RATE: usize>(pub(crate) Matrix<F, T>);
+
+impl<F: FieldExt, const T: usize, const RATE: usize> Index<usize> for MDSMatrix<F, T, RATE> {
+    type Output = [F; T];
+
+    fn index(&self, idx: usize) -> &Self::Output {
+        &self.0 .0[idx]
+    }
+}
+
+impl<F: FieldExt, const T: usize, const RATE: usize> MDSMatrix<F, T, RATE> {
+    /// Applies `MDSMatrix` to the state
+    pub(crate) fn apply(&self, state: &mut State<F, T>) {
+        state.0 = self.0.mul_vector(&state.0);
+    }
+
+    /// Given two `T` sized vector constructs the `t * t` Cauchy matrix
+    pub(super) fn cauchy(xs: &[F; T], ys: &[F; T]) -> Self {
+        let mut m = Matrix::default();
+        for (i, x) in xs.iter().enumerate() {
+            for (j, y) in ys.iter().enumerate() {
+                let sum = *x + *y;
+                debug_assert!(!sum.is_zero_vartime());
+                m.set(i, j, sum.invert().unwrap());
+            }
+        }
+        MDSMatrix(m)
+    }
+
+    /// Inverts the MDS matrix
+    fn invert(&self) -> Self {
+        Self(self.0.invert())
+    }
+
+    /// Used in calculation of optimized round constants. Calculates `v' = M *
+    /// v` where vectors are `T` sized
+    fn mul_constants(&self, v: &[F; T]) -> [F; T] {
+        self.0.mul_vector(v)
+    }
+
+    /// Multiplies two MDS matrices. Used in sparse matrix calculations
+    fn mul(&self, other: &Self) -> Self {
+        Self(self.0.mul(&other.0))
+    }
+
+    fn transpose(&self) -> Self {
+        Self(self.0.transpose())
+    }
+
+    /// See Section B in Supplementary Material https://eprint.iacr.org/2019/458.pdf
+    /// Factorises an MDS matrix `M` into `M'` and `M''` where `M = M' *  M''`.
+    /// Resulted `M''` matrices are the sparse ones while `M'` will contribute
+    /// to the accumulator of the process
+    fn factorise(&self) -> (Self, SparseMDSMatrix<F, T, RATE>) {
+        // Given `(t-1 * t-1)` MDS matrix called `hat` constructs the matrix in
+        // form `[[1 | 0], [0 | m]]`
+        let prime = |hat: Matrix<F, RATE>| -> MDSMatrix<F, T, RATE> {
+            let mut prime = Matrix::identity();
+            for (prime_row, hat_row) in prime.0.iter_mut().skip(1).zip(hat.0.iter()) {
+                for (el_prime, el_hat) in prime_row.iter_mut().skip(1).zip(hat_row.iter()) {
+                    *el_prime = *el_hat;
+                }
+            }
+            Self(prime)
+        };
+
+        // Given `(t-1)` sized `w_hat` vector constructs the matrix in form
+        // `[[m_0_0 | m_0_i], [w_hat | identity]]`
+        let prime_prime = |w_hat: [F; RATE]| -> Self {
+            let mut prime_prime = Matrix::identity();
+            prime_prime.0[0] = self.0 .0[0];
+            for (row, w) in prime_prime.0.iter_mut().skip(1).zip(w_hat.iter()) {
+                row[0] = *w
+            }
+            Self(prime_prime)
+        };
+
+        let w = self.0.w();
+        let m_hat = self.0.sub::<RATE>();
+        let m_hat_inverse = m_hat.invert();
+        let w_hat = m_hat_inverse.mul_vector(&w);
+        (prime(m_hat), prime_prime(w_hat).transpose().into())
+    }
+
+    /// Returns rows of the MDS matrix
+    pub fn rows(&self) -> [[F; T]; T] {
+        self.0 .0
+    }
+}
+
+/// `SparseMDSMatrix` are in `[row], [hat | identity]` form and used in linear
+/// layer of partial rounds instead of the original MDS
+#[derive(Debug, Clone)]
+pub struct SparseMDSMatrix<F: FieldExt, const T: usize, const RATE: usize> {
+    pub(crate) row: [F; T],
+    pub(crate) col_hat: [F; RATE],
+}
+
+impl<F: FieldExt, const T: usize, const RATE: usize> SparseMDSMatrix<F, T, RATE> {
+    /// Returns the first row
+    pub fn row(&self) -> &[F; T] {
+        &self.row
+    }
+
+    /// Returns the first column without first element in the first row
+    pub fn col_hat(&self) -> &[F; RATE] {
+        &self.col_hat
+    }
+
+    /// Applies the sparse MDS matrix to the state
+    pub(crate) fn apply(&self, state: &mut State<F, T>) {
+        let words = state.words();
+        state.0[0] = self
+            .row
+            .iter()
+            .zip(words.iter())
+            .fold(F::zero(), |acc, (e, cell)| acc + (*e * *cell));
+
+        for ((new_word, col_el), word) in (state.0)
+            .iter_mut()
+            .skip(1)
+            .zip(self.col_hat.iter())
+            .zip(words.iter().skip(1))
+        {
+            *new_word = *col_el * words[0] + word;
+        }
+    }
+}
+
+impl<F: FieldExt, const T: usize, const RATE: usize> From<MDSMatrix<F, T, RATE>>
+    for SparseMDSMatrix<F, T, RATE>
+{
+    /// Assert the form and represent an MDS matrix as a sparse MDS matrix
+    fn from(mds: MDSMatrix<F, T, RATE>) -> Self {
+        let mds = mds.0;
+        for (i, row) in mds.0.iter().enumerate().skip(1) {
+            for (j, _) in row.iter().enumerate().skip(1) {
+                assert_eq!(row[j], if i != j { F::zero() } else { F::one() });
+            }
+        }
+
+        let (mut row, mut col_hat) = ([F::zero(); T], [F::zero(); RATE]);
+        for (row_el, el) in row.iter_mut().zip(mds.0[0].iter()) {
+            *row_el = *el
+        }
+        for (col_el, row) in col_hat.iter_mut().zip(mds.0.iter().skip(1)) {
+            *col_el = row[0]
+        }
+
+        SparseMDSMatrix { row, col_hat }
+    }
+}
+
+impl<F: FieldExt, const T: usize, const RATE: usize> Spec<F, T, RATE> {
+    /// Given number of round parameters constructs new Posedion instance
+    /// calculating unoptimized round constants with reference `Grain` then
+    /// calculates optimized constants and sparse matrices
+    pub fn new(r_f: usize, r_p: usize) -> Self {
+        let (unoptimized_constants, mds) = Grain::generate(r_f, r_p);
+        let constants = Self::calculate_optimized_constants(r_f, r_p, unoptimized_constants, &mds);
+        let (sparse_matrices, pre_sparse_mds) = Self::calculate_sparse_matrices(r_p, &mds);
+
+        Self {
+            r_f,
+            constants,
+            mds_matrices: MDSMatrices {
+                mds,
+                sparse_matrices,
+                pre_sparse_mds,
+            },
+        }
+    }
+
+    fn calculate_optimized_constants(
+        r_f: usize,
+        r_p: usize,
+        constants: Vec<[F; T]>,
+        mds: &MDSMatrix<F, T, RATE>,
+    ) -> OptimizedConstants<F, T> {
+        let inverse_mds = mds.invert();
+        let (number_of_rounds, r_f_half) = (r_f + r_p, r_f / 2);
+        assert_eq!(constants.len(), number_of_rounds);
+
+        // Calculate optimized constants for first half of the full rounds
+        let mut constants_start: Vec<[F; T]> = vec![[F::zero(); T]; r_f_half];
+        constants_start[0] = constants[0].clone();
+        for (optimized, constants) in constants_start
+            .iter_mut()
+            .skip(1)
+            .zip(constants.iter().skip(1))
+        {
+            *optimized = inverse_mds.mul_constants(constants);
+        }
+
+        // Calculate constants for partial rounds
+        let mut acc = constants[r_f_half + r_p].clone();
+        let mut constants_partial = vec![F::zero(); r_p];
+        for (optimized, constants) in constants_partial
+            .iter_mut()
+            .rev()
+            .zip(constants.iter().skip(r_f_half).rev().skip(r_f_half))
+        {
+            let mut tmp = inverse_mds.mul_constants(&acc);
+            *optimized = tmp[0];
+
+            tmp[0] = F::zero();
+            for ((acc, tmp), constant) in acc
+                .iter_mut()
+                .zip(tmp.into_iter())
+                .zip(constants.into_iter())
+            {
+                *acc = tmp + constant
+            }
+        }
+        constants_start.push(inverse_mds.mul_constants(&acc));
+
+        // Calculate optimized constants for ending half of the full rounds
+        let mut constants_end: Vec<[F; T]> = vec![[F::zero(); T]; r_f_half - 1];
+        for (optimized, constants) in constants_end
+            .iter_mut()
+            .zip(constants.iter().skip(r_f_half + r_p + 1))
+        {
+            *optimized = inverse_mds.mul_constants(constants);
+        }
+
+        OptimizedConstants {
+            start: constants_start,
+            partial: constants_partial,
+            end: constants_end,
+        }
+    }
+
+    fn calculate_sparse_matrices(
+        r_p: usize,
+        mds: &MDSMatrix<F, T, RATE>,
+    ) -> (Vec<SparseMDSMatrix<F, T, RATE>>, MDSMatrix<F, T, RATE>) {
+        let mds = mds.transpose();
+        let mut acc = mds.clone();
+        let mut sparse_matrices = (0..r_p)
+            .map(|_| {
+                let (m_prime, m_prime_prime) = acc.factorise();
+                acc = mds.mul(&m_prime);
+                m_prime_prime
+            })
+            .collect::<Vec<SparseMDSMatrix<F, T, RATE>>>();
+
+        sparse_matrices.reverse();
+        (sparse_matrices, acc.transpose())
+    }
+}
+
+#[cfg(test)]
+pub(super) mod tests {
+    use halo2curves::FieldExt;
+
+    use super::MDSMatrix;
+    use crate::grain::Grain;
+
+    /// We want to keep unoptimized parameters to cross test with optimized one
+    pub(crate) struct SpecRef<F: FieldExt, const T: usize, const RATE: usize> {
+        pub(crate) r_f: usize,
+        pub(crate) r_p: usize,
+        pub(crate) mds: MDSMatrix<F, T, RATE>,
+        pub(crate) constants: Vec<[F; T]>,
+    }
+
+    impl<F: FieldExt, const T: usize, const RATE: usize> SpecRef<F, T, RATE> {
+        pub(crate) fn new(r_f: usize, r_p: usize) -> Self {
+            let (constants, mds) = Grain::generate(r_f, r_p);
+
+            SpecRef {
+                r_f,
+                r_p,
+                mds,
+                constants,
+            }
+        }
+    }
+}
+
+
\ No newline at end of file diff --git a/docs/storage.js b/docs/storage.js new file mode 100644 index 0000000000..17c1da81f1 --- /dev/null +++ b/docs/storage.js @@ -0,0 +1 @@ +"use strict";const darkThemes=["dark","ayu"];window.currentTheme=document.getElementById("themeStyle");window.mainTheme=document.getElementById("mainThemeStyle");window.RUSTDOC_MOBILE_BREAKPOINT=700;const settingsDataset=(function(){const settingsElement=document.getElementById("default-settings");if(settingsElement===null){return null}const dataset=settingsElement.dataset;if(dataset===undefined){return null}return dataset})();function getSettingValue(settingName){const current=getCurrentValue(settingName);if(current!==null){return current}if(settingsDataset!==null){const def=settingsDataset[settingName.replace(/-/g,"_")];if(def!==undefined){return def}}return null}const localStoredTheme=getSettingValue("theme");const savedHref=[];function hasClass(elem,className){return elem&&elem.classList&&elem.classList.contains(className)}function addClass(elem,className){if(!elem||!elem.classList){return}elem.classList.add(className)}function removeClass(elem,className){if(!elem||!elem.classList){return}elem.classList.remove(className)}function onEach(arr,func,reversed){if(arr&&arr.length>0&&func){if(reversed){const length=arr.length;for(let i=length-1;i>=0;--i){if(func(arr[i])){return true}}}else{for(const elem of arr){if(func(elem)){return true}}}}return false}function onEachLazy(lazyArray,func,reversed){return onEach(Array.prototype.slice.call(lazyArray),func,reversed)}function updateLocalStorage(name,value){try{window.localStorage.setItem("rustdoc-"+name,value)}catch(e){}}function getCurrentValue(name){try{return window.localStorage.getItem("rustdoc-"+name)}catch(e){return null}}function switchTheme(styleElem,mainStyleElem,newTheme,saveTheme){const newHref=mainStyleElem.href.replace(/\/rustdoc([^/]*)\.css/,"/"+newTheme+"$1"+".css");if(saveTheme){updateLocalStorage("theme",newTheme)}if(styleElem.href===newHref){return}let found=false;if(savedHref.length===0){onEachLazy(document.getElementsByTagName("link"),el=>{savedHref.push(el.href)})}onEach(savedHref,el=>{if(el===newHref){found=true;return true}});if(found){styleElem.href=newHref}}function useSystemTheme(value){if(value===undefined){value=true}updateLocalStorage("use-system-theme",value);const toggle=document.getElementById("use-system-theme");if(toggle&&toggle instanceof HTMLInputElement){toggle.checked=value}}const updateSystemTheme=(function(){if(!window.matchMedia){return()=>{const cssTheme=getComputedStyle(document.documentElement).getPropertyValue("content");switchTheme(window.currentTheme,window.mainTheme,JSON.parse(cssTheme)||"light",true)}}const mql=window.matchMedia("(prefers-color-scheme: dark)");function handlePreferenceChange(mql){const use=theme=>{switchTheme(window.currentTheme,window.mainTheme,theme,true)};if(getSettingValue("use-system-theme")!=="false"){const lightTheme=getSettingValue("preferred-light-theme")||"light";const darkTheme=getSettingValue("preferred-dark-theme")||"dark";if(mql.matches){use(darkTheme)}else{use(lightTheme)}}else{use(getSettingValue("theme"))}}mql.addListener(handlePreferenceChange);return()=>{handlePreferenceChange(mql)}})();function switchToSavedTheme(){switchTheme(window.currentTheme,window.mainTheme,getSettingValue("theme")||"light",false)}if(getSettingValue("use-system-theme")!=="false"&&window.matchMedia){if(getSettingValue("use-system-theme")===null&&getSettingValue("preferred-dark-theme")===null&&darkThemes.indexOf(localStoredTheme)>=0){updateLocalStorage("preferred-dark-theme",localStoredTheme)}updateSystemTheme()}else{switchToSavedTheme()}if(getSettingValue("source-sidebar-show")==="true"){addClass(document.documentElement,"source-sidebar-expanded")}window.addEventListener("pageshow",ev=>{if(ev.persisted){setTimeout(switchToSavedTheme,0)}}) \ No newline at end of file diff --git a/docs/toggle-minus.svg b/docs/toggle-minus.svg new file mode 100644 index 0000000000..73154788a0 --- /dev/null +++ b/docs/toggle-minus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/toggle-plus.svg b/docs/toggle-plus.svg new file mode 100644 index 0000000000..08b17033e1 --- /dev/null +++ b/docs/toggle-plus.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/wheel.svg b/docs/wheel.svg new file mode 100644 index 0000000000..01da3b24c7 --- /dev/null +++ b/docs/wheel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/halo2_gadgets/CHANGELOG.md b/halo2_gadgets/CHANGELOG.md deleted file mode 100644 index 41019f9cea..0000000000 --- a/halo2_gadgets/CHANGELOG.md +++ /dev/null @@ -1,121 +0,0 @@ -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to Rust's notion of -[Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [Unreleased] - -## [0.2.0] - 2022-06-23 -### Added -- `halo2_gadgets::utilities::RangeConstrained>::bitrange_of` - -### Changed -All APIs that represented witnessed values as `Option` now represent them as -`halo2_proofs::circuit::Value`. The core API changes are listed below. - -- Migrated to `halo2_proofs 0.2.0`. -- The following APIs now take `Value<_>` instead of `Option<_>`: - - `halo2_gadgets::ecc`: - - `EccInstructions::{witness_point, witness_point_non_id}` - - `EccInstructions::{witness_scalar_var, witness_scalar_fixed}` - - `ScalarVar::new` - - `ScalarFixed::new` - - `NonIdentityPoint::new` - - `Point::new` - - `halo2_gadgets::sinsemilla`: - - `SinsemillaInstructions::witness_message_piece` - - `MessagePiece::{from_field_elem, from_subpieces}` - - `halo2_gadgets::sinsemilla::merkle`: - - `MerklePath::construct` - - `halo2_gadgets::utilities`: - - `UtilitiesInstructions::load_private` - - `RangeConstrained::witness_short` - - `halo2_gadgets::utilities::cond_swap`: - - `CondSwapInstructions::swap` - - `halo2_gadgets::utilities::decompose_running_sum`: - - `RunningSumConfig::witness_decompose` - - `halo2_gadgets::utilities::lookup_range_check`: - - `LookupRangeCheckConfig::{witness_check, witness_short_check}` -- The following APIs now return `Value<_>` instead of `Option<_>`: - - `halo2_gadgets::ecc::chip`: - - `EccPoint::{point, is_identity}` - - `NonIdentityEccPoint::point` - - `halo2_gadgets::utilities`: - - `FieldValue::value` - - `Var::value` - - `RangeConstrained::value` -- `halo2_gadgets::sha256::BlockWord` is now a newtype wrapper around - `Value` instead of `Option`. - -### Removed -- `halo2_gadgets::utilities::RangeConstrained>::bitrange_of` - -## [0.1.0] - 2022-05-10 -### Added -- `halo2_gadgets::utilities`: - - `FieldValue` trait. - - `RangeConstrained` newtype wrapper. -- `halo2_gadgets::ecc`: - - `EccInstructions::witness_scalar_var` API to witness a full-width scalar - used in variable-base scalar multiplication. - - `EccInstructions::witness_scalar_fixed`, to witness a full-width scalar - used in fixed-base scalar multiplication. - - `EccInstructions::scalar_fixed_from_signed_short`, to construct a signed - short scalar used in fixed-base scalar multiplication from its magnitude and - sign. - - `BaseFitsInScalarInstructions` trait that can be implemented for a curve - whose base field fits into its scalar field. This provides a method - `scalar_var_from_base` that converts a base field element that exists as - a variable in the circuit, into a scalar to be used in variable-base - scalar multiplication. - - `ScalarFixed::new` - - `ScalarFixedShort::new` - - `ScalarVar::new` and `ScalarVar::from_base` gadget APIs. -- `halo2_gadgets::ecc::chip`: - - `ScalarVar` enum with `BaseFieldElem` and `FullWidth` variants. `FullWidth` - is unimplemented for `halo2_gadgets v0.1.0`. -- `halo2_gadgets::poseidon`: - - `primitives` (moved from `halo2_gadgets::primitives::poseidon`) -- `halo2_gadgets::sinsemilla`: - - `primitives` (moved from `halo2_gadgets::primitives::sinsemilla`) - - `MessagePiece::from_subpieces` - -### Changed -- `halo2_gadgets::ecc`: - - `EccInstructions::ScalarVar` is now treated as a full-width scalar, instead - of being restricted to a base field element. - - `EccInstructions::mul` now takes a `Self::ScalarVar` as argument, instead - of assuming that the scalar fits in a base field element `Self::Var`. - - `EccInstructions::mul_fixed` now takes a `Self::ScalarFixed` as argument, - instead of requiring that the chip always witness a new scalar. - - `EccInstructions::mul_fixed_short` now takes a `Self::ScalarFixedShort` as - argument, instead of the magnitude and sign directly. - - `FixedPoint::mul` now takes `ScalarFixed` instead of `Option`. - - `FixedPointShort::mul` now takes `ScalarFixedShort` instead of - `(EccChip::Var, EccChip::Var)`. -- `halo2_gadgets::ecc::chip`: - - `FixedPoint::u` now returns `Vec<[::Repr; H]>` - instead of `Vec<[[u8; 32]; H]>`. - - `ScalarKind` has been renamed to `FixedScalarKind`. -- `halo2_gadgets::sinsemilla`: - - `CommitDomain::{commit, short_commit}` now take the trapdoor `r` as an - `ecc::ScalarFixed` instead of `Option`. - - `merkle::MerklePath` can now be constructed with more or fewer than two - `MerkleChip`s. - -### Removed -- `halo2_gadgets::primitives` (use `halo2_gadgets::poseidon::primitives` or - `halo2_gadgets::sinsemilla::primitives` instead). - -## [0.1.0-beta.3] - 2022-04-06 -### Changed -- Migrated to `halo2_proofs 0.1.0-beta.4`. - -## [0.1.0-beta.2] - 2022-03-22 -### Changed -- Migrated to `halo2_proofs 0.1.0-beta.3`. - -## [0.1.0-beta.1] - 2022-02-14 -Initial release! diff --git a/halo2_gadgets/Cargo.toml b/halo2_gadgets/Cargo.toml deleted file mode 100644 index 6025ef7297..0000000000 --- a/halo2_gadgets/Cargo.toml +++ /dev/null @@ -1,66 +0,0 @@ -[package] -name = "halo2_gadgets" -version = "0.2.0" -authors = [ - "Sean Bowe ", - "Jack Grigg ", - "Daira Hopwood ", - "Ying Tong Lai ", - "Kris Nuttycombe ", -] -edition = "2021" -rust-version = "1.56.1" -description = "Reusable gadgets and chip implementations for Halo 2" -license = "MIT OR Apache-2.0" -repository = "https://github.com/zcash/halo2" -readme = "README.md" -categories = ["cryptography"] -keywords = ["halo", "proofs", "zcash", "zkp", "zkSNARKs"] - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = ["--cfg", "docsrs", "--html-in-header", "katex-header.html"] - -[dependencies] -arrayvec = "0.7.0" -bitvec = "1" -ff = "0.12" -group = "0.12" -halo2_proofs = { version = "0.2", path = "../halo2_proofs" } -lazy_static = "1" -halo2curves = { git = 'https://github.com/privacy-scaling-explorations/halo2curves', tag = '0.3.0' } -proptest = { version = "1.0.0", optional = true } -rand = "0.8" -subtle = "2.3" -uint = "0.9.2" # MSRV 1.56.1 - -# Developer tooling dependencies -plotters = { version = "0.3.0", optional = true } - -[dev-dependencies] -criterion = "0.3" -proptest = "1.0.0" - -[target.'cfg(unix)'.dev-dependencies] -pprof = { version = "0.8", features = ["criterion", "flamegraph"] } # MSRV 1.56 - -[lib] -bench = false - -[features] -dev-graph = ["halo2_proofs/dev-graph", "plotters"] -test-dependencies = ["proptest"] -unstable = [] - -[[bench]] -name = "primitives" -harness = false - -[[bench]] -name = "poseidon" -harness = false - -[[bench]] -name = "sha256" -harness = false -required-features = ["unstable"] diff --git a/halo2_gadgets/README.md b/halo2_gadgets/README.md deleted file mode 100644 index 4ed744f81f..0000000000 --- a/halo2_gadgets/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# halo2_gadgets [![Crates.io](https://img.shields.io/crates/v/halo2_gadgets.svg)](https://crates.io/crates/halo2_gadgets) # - -Requires Rust 1.56.1+. - -## Documentation - -- [The Halo 2 Book](https://zcash.github.io/halo2/) -- [Crate documentation](https://docs.rs/halo2_gadgets) - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or - http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally -submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or -conditions. diff --git a/halo2_gadgets/benches/poseidon.rs b/halo2_gadgets/benches/poseidon.rs deleted file mode 100644 index 581b42fb73..0000000000 --- a/halo2_gadgets/benches/poseidon.rs +++ /dev/null @@ -1,222 +0,0 @@ -use ff::Field; -use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - plonk::{ - create_proof, keygen_pk, keygen_vk, verify_proof, Advice, Circuit, Column, - ConstraintSystem, Error, Instance, - }, - poly::{ - commitment::ParamsProver, - ipa::{ - commitment::{IPACommitmentScheme, ParamsIPA}, - multiopen::ProverIPA, - strategy::SingleStrategy, - }, - VerificationStrategy, - }, - transcript::{ - Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, - }, -}; -use halo2curves::pasta::{pallas, vesta, EqAffine, Fp}; - -use halo2_gadgets::poseidon::{ - primitives::{self as poseidon, ConstantLength, Spec}, - Hash, Pow5Chip, Pow5Config, -}; -use std::convert::TryInto; -use std::marker::PhantomData; - -use criterion::{criterion_group, criterion_main, Criterion}; -use rand::rngs::OsRng; - -#[derive(Clone, Copy)] -struct HashCircuit -where - S: Spec + Clone + Copy, -{ - message: Value<[Fp; L]>, - _spec: PhantomData, -} - -#[derive(Debug, Clone)] -struct MyConfig { - input: [Column; L], - expected: Column, - poseidon_config: Pow5Config, -} - -impl Circuit - for HashCircuit -where - S: Spec + Copy + Clone, -{ - type Config = MyConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self { - message: Value::unknown(), - _spec: PhantomData, - } - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let state = (0..WIDTH).map(|_| meta.advice_column()).collect::>(); - let expected = meta.instance_column(); - meta.enable_equality(expected); - let partial_sbox = meta.advice_column(); - - let rc_a = (0..WIDTH).map(|_| meta.fixed_column()).collect::>(); - let rc_b = (0..WIDTH).map(|_| meta.fixed_column()).collect::>(); - - meta.enable_constant(rc_b[0]); - - Self::Config { - input: state[..RATE].try_into().unwrap(), - expected, - poseidon_config: Pow5Chip::configure::( - meta, - state.try_into().unwrap(), - partial_sbox, - rc_a.try_into().unwrap(), - rc_b.try_into().unwrap(), - ), - } - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let chip = Pow5Chip::construct(config.poseidon_config.clone()); - - let message = layouter.assign_region( - || "load message", - |mut region| { - let message_word = |i: usize| { - let value = self.message.map(|message_vals| message_vals[i]); - region.assign_advice( - || format!("load message_{}", i), - config.input[i], - 0, - || value, - ) - }; - - let message: Result, Error> = (0..L).map(message_word).collect(); - Ok(message?.try_into().unwrap()) - }, - )?; - - let hasher = Hash::<_, _, S, ConstantLength, WIDTH, RATE>::init( - chip, - layouter.namespace(|| "init"), - )?; - let output = hasher.hash(layouter.namespace(|| "hash"), message)?; - - layouter.constrain_instance(output.cell(), config.expected, 0) - } -} - -#[derive(Debug, Clone, Copy)] -struct MySpec; - -impl Spec for MySpec { - fn full_rounds() -> usize { - 8 - } - - fn partial_rounds() -> usize { - 56 - } - - fn sbox(val: Fp) -> Fp { - val.pow_vartime(&[5]) - } - - fn secure_mds() -> usize { - 0 - } -} - -const K: u32 = 7; - -fn bench_poseidon( - name: &str, - c: &mut Criterion, -) where - S: Spec + Copy + Clone, -{ - // Initialize the polynomial commitment parameters - let params: ParamsIPA = ParamsIPA::new(K); - - let empty_circuit = HashCircuit:: { - message: Value::unknown(), - _spec: PhantomData, - }; - - // Initialize the proving key - let vk = keygen_vk(¶ms, &empty_circuit).expect("keygen_vk should not fail"); - let pk = keygen_pk(¶ms, vk, &empty_circuit).expect("keygen_pk should not fail"); - - let prover_name = name.to_string() + "-prover"; - let verifier_name = name.to_string() + "-verifier"; - - let mut rng = OsRng; - let message: [Fp; L] = (0..L) - .map(|_| pallas::Base::random(rng)) - .collect::>() - .try_into() - .unwrap(); - let output = poseidon::Hash::<_, S, ConstantLength, WIDTH, RATE>::init().hash(message); - - let circuit = HashCircuit:: { - message: Value::known(message), - _spec: PhantomData, - }; - - // Create a proof - let mut transcript = Blake2bWrite::<_, EqAffine, Challenge255<_>>::init(vec![]); - - c.bench_function(&prover_name, |b| { - b.iter(|| { - create_proof::, ProverIPA<_>, _, _, _, _>( - ¶ms, - &pk, - &[circuit], - &[&[&[output]]], - &mut rng, - &mut transcript, - ) - .expect("proof generation should not fail") - }) - }); - - let proof = transcript.finalize(); - - c.bench_function(&verifier_name, |b| { - b.iter(|| { - let strategy = SingleStrategy::new(¶ms); - let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); - assert!(verify_proof( - ¶ms, - pk.get_vk(), - strategy, - &[&[&[output]]], - &mut transcript - ) - .is_ok()); - }); - }); -} - -fn criterion_benchmark(c: &mut Criterion) { - bench_poseidon::, 3, 2, 2>("WIDTH = 3, RATE = 2", c); - bench_poseidon::, 9, 8, 8>("WIDTH = 9, RATE = 8", c); - bench_poseidon::, 12, 11, 11>("WIDTH = 12, RATE = 11", c); -} - -criterion_group!(benches, criterion_benchmark); -criterion_main!(benches); diff --git a/halo2_gadgets/benches/primitives.rs b/halo2_gadgets/benches/primitives.rs deleted file mode 100644 index 5397efce05..0000000000 --- a/halo2_gadgets/benches/primitives.rs +++ /dev/null @@ -1,68 +0,0 @@ -use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; -use ff::Field; -use halo2_gadgets::{ - poseidon::primitives::{self as poseidon, ConstantLength, P128Pow5T3}, - sinsemilla::primitives as sinsemilla, -}; - -use halo2curves::pasta::pallas; -#[cfg(unix)] -use pprof::criterion::{Output, PProfProfiler}; -use rand::{rngs::OsRng, Rng}; - -fn bench_primitives(c: &mut Criterion) { - let mut rng = OsRng; - - { - let mut group = c.benchmark_group("Poseidon"); - - let message = [pallas::Base::random(rng), pallas::Base::random(rng)]; - - group.bench_function("2-to-1", |b| { - b.iter(|| { - poseidon::Hash::<_, P128Pow5T3, ConstantLength<2>, 3, 2>::init().hash(message) - }) - }); - } - - { - let mut group = c.benchmark_group("Sinsemilla"); - - let hasher = sinsemilla::HashDomain::new("hasher"); - let committer = sinsemilla::CommitDomain::new("committer"); - let bits: Vec = (0..1086).map(|_| rng.gen()).collect(); - let r = pallas::Scalar::random(rng); - - // Benchmark the input sizes we use in Orchard: - // - 510 bits for Commit^ivk - // - 520 bits for MerkleCRH - // - 1086 bits for NoteCommit - for size in [510, 520, 1086] { - group.bench_function(BenchmarkId::new("hash-to-point", size), |b| { - b.iter(|| hasher.hash_to_point(bits[..size].iter().cloned())) - }); - - group.bench_function(BenchmarkId::new("hash", size), |b| { - b.iter(|| hasher.hash(bits[..size].iter().cloned())) - }); - - group.bench_function(BenchmarkId::new("commit", size), |b| { - b.iter(|| committer.commit(bits[..size].iter().cloned(), &r)) - }); - - group.bench_function(BenchmarkId::new("short-commit", size), |b| { - b.iter(|| committer.commit(bits[..size].iter().cloned(), &r)) - }); - } - } -} - -#[cfg(unix)] -criterion_group! { - name = benches; - config = Criterion::default().with_profiler(PProfProfiler::new(100, Output::Flamegraph(None))); - targets = bench_primitives -} -#[cfg(not(unix))] -criterion_group!(benches, bench_primitives); -criterion_main!(benches); diff --git a/halo2_gadgets/benches/sha256.rs b/halo2_gadgets/benches/sha256.rs deleted file mode 100644 index 670956cb0d..0000000000 --- a/halo2_gadgets/benches/sha256.rs +++ /dev/null @@ -1,176 +0,0 @@ -use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - plonk::{create_proof, keygen_pk, keygen_vk, verify_proof, Circuit, ConstraintSystem, Error}, - poly::commitment::Params, - transcript::{Blake2bRead, Blake2bWrite, Challenge255}, -}; -use halo2curves::pasta::{pallas, EqAffine}; -use rand::rngs::OsRng; - -use std::{ - fs::File, - io::{prelude::*, BufReader}, - path::Path, -}; - -use criterion::{criterion_group, criterion_main, Criterion}; - -use halo2_gadgets::sha256::{BlockWord, Sha256, Table16Chip, Table16Config, BLOCK_SIZE}; - -use halo2_proofs::{ - poly::{ - commitment::ParamsProver, - ipa::{ - commitment::{IPACommitmentScheme, ParamsIPA}, - multiopen::{ProverIPA, VerifierIPA}, - strategy::AccumulatorStrategy, - }, - }, - transcript::{TranscriptReadBuffer, TranscriptWriterBuffer}, -}; - -#[allow(dead_code)] -fn bench(name: &str, k: u32, c: &mut Criterion) { - #[derive(Default)] - struct MyCircuit {} - - impl Circuit for MyCircuit { - type Config = Table16Config; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - Table16Chip::configure(meta) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - Table16Chip::load(config.clone(), &mut layouter)?; - let table16_chip = Table16Chip::construct(config); - - // Test vector: "abc" - let test_input = [ - BlockWord(Value::known(0b01100001011000100110001110000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000011000)), - ]; - - // Create a message of length 31 blocks - let mut input = Vec::with_capacity(31 * BLOCK_SIZE); - for _ in 0..31 { - input.extend_from_slice(&test_input); - } - - Sha256::digest(table16_chip, layouter.namespace(|| "'abc' * 2"), &input)?; - - Ok(()) - } - } - - // Initialize the polynomial commitment parameters - let params_path = Path::new("./benches/sha256_assets/sha256_params"); - if File::open(¶ms_path).is_err() { - let params: ParamsIPA = ParamsIPA::new(k); - let mut buf = Vec::new(); - - params.write(&mut buf).expect("Failed to write params"); - let mut file = File::create(¶ms_path).expect("Failed to create sha256_params"); - - file.write_all(&buf[..]) - .expect("Failed to write params to file"); - } - - let params_fs = File::open(¶ms_path).expect("couldn't load sha256_params"); - let params: ParamsIPA = - ParamsIPA::read::<_>(&mut BufReader::new(params_fs)).expect("Failed to read params"); - - let empty_circuit: MyCircuit = MyCircuit {}; - - // Initialize the proving key - let vk = keygen_vk(¶ms, &empty_circuit).expect("keygen_vk should not fail"); - let pk = keygen_pk(¶ms, vk, &empty_circuit).expect("keygen_pk should not fail"); - - let circuit: MyCircuit = MyCircuit {}; - - // let prover_name = name.to_string() + "-prover"; - let verifier_name = name.to_string() + "-verifier"; - - // /// Benchmark proof creation - // c.bench_function(&prover_name, |b| { - // b.iter(|| { - // let mut transcript = Blake2bWrite::init(Fq::one()); - // create_proof(¶ms, &pk, &circuit, &[], &mut transcript) - // .expect("proof generation should not fail"); - // let proof: Vec = transcript.finalize(); - // }); - // }); - - // Create a proof - let proof_path = Path::new("./benches/sha256_assets/sha256_proof"); - if File::open(&proof_path).is_err() { - let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); - create_proof::, ProverIPA<_>, _, _, _, _>( - ¶ms, - &pk, - &[circuit], - &[], - OsRng, - &mut transcript, - ) - .expect("proof generation should not fail"); - let proof: Vec = transcript.finalize(); - let mut file = File::create(&proof_path).expect("Failed to create sha256_proof"); - file.write_all(&proof[..]).expect("Failed to write proof"); - } - - let mut proof_fs = File::open(&proof_path).expect("couldn't load sha256_proof"); - let mut proof = Vec::::new(); - proof_fs - .read_to_end(&mut proof) - .expect("Couldn't read proof"); - - c.bench_function(&verifier_name, |b| { - b.iter(|| { - use halo2_proofs::poly::VerificationStrategy; - let strategy = AccumulatorStrategy::new(¶ms); - let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); - let strategy = verify_proof::, VerifierIPA<_>, _, _, _>( - ¶ms, - pk.get_vk(), - strategy, - &[], - &mut transcript, - ) - .unwrap(); - assert!(strategy.finalize()); - }); - }); -} - -#[allow(dead_code)] -fn criterion_benchmark(c: &mut Criterion) { - bench("sha256", 17, c); - // bench("sha256", 20, c); -} - -criterion_group!(benches, criterion_benchmark); -criterion_main!(benches); diff --git a/halo2_gadgets/katex-header.html b/halo2_gadgets/katex-header.html deleted file mode 100644 index 98e85904fa..0000000000 --- a/halo2_gadgets/katex-header.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - \ No newline at end of file diff --git a/halo2_gadgets/proptest-regressions/constants/util.txt b/halo2_gadgets/proptest-regressions/constants/util.txt deleted file mode 100644 index 9e49b54616..0000000000 --- a/halo2_gadgets/proptest-regressions/constants/util.txt +++ /dev/null @@ -1,7 +0,0 @@ -# Seeds for failure cases proptest has generated in the past. It is -# automatically read and these particular cases re-run before any -# novel cases are generated. -# -# It is recommended to check this file in to source control so that -# everyone who runs the test benefits from these saved cases. -cc 251d6e9f7ad2f5cd8679dec6b69aa9c879baae8742791b19669c136aef12deac # shrinks to scalar = 0x0000000000000000000000000000000000000000000000000000000000000000, window_num_bits = 6 diff --git a/halo2_gadgets/src/ecc.rs b/halo2_gadgets/src/ecc.rs deleted file mode 100644 index 08f34b15f2..0000000000 --- a/halo2_gadgets/src/ecc.rs +++ /dev/null @@ -1,918 +0,0 @@ -//! Elliptic curve operations. - -use std::fmt::Debug; - -use halo2_proofs::{ - arithmetic::CurveAffine, - circuit::{Chip, Layouter, Value}, - plonk::Error, -}; - -use crate::utilities::UtilitiesInstructions; - -pub mod chip; - -/// The set of circuit instructions required to use the ECC gadgets. -pub trait EccInstructions: - Chip + UtilitiesInstructions + Clone + Debug + Eq -{ - /// Variable representing a scalar used in variable-base scalar mul. - /// - /// This type is treated as a full-width scalar. However, if `Self` implements - /// [`BaseFitsInScalarInstructions`] then this may also be constructed from an element - /// of the base field. - type ScalarVar: Clone + Debug; - /// Variable representing a full-width element of the elliptic curve's - /// scalar field, to be used for fixed-base scalar mul. - type ScalarFixed: Clone + Debug; - /// Variable representing a signed short element of the elliptic curve's - /// scalar field, to be used for fixed-base scalar mul. - /// - /// A `ScalarFixedShort` must be in the range [-(2^64 - 1), 2^64 - 1]. - type ScalarFixedShort: Clone + Debug; - /// Variable representing an elliptic curve point. - type Point: From + Clone + Debug; - /// Variable representing a non-identity elliptic curve point. - type NonIdentityPoint: Clone + Debug; - /// Variable representing the affine short Weierstrass x-coordinate of an - /// elliptic curve point. - type X: Clone + Debug; - /// Enumeration of the set of fixed bases to be used in scalar mul. - /// TODO: When associated consts can be used as const generics, introduce - /// `Self::NUM_WINDOWS`, `Self::NUM_WINDOWS_BASE_FIELD`, `Self::NUM_WINDOWS_SHORT` - /// and use them to differentiate `FixedPoints` types. - type FixedPoints: FixedPoints; - - /// Constrains point `a` to be equal in value to point `b`. - fn constrain_equal( - &self, - layouter: &mut impl Layouter, - a: &Self::Point, - b: &Self::Point, - ) -> Result<(), Error>; - - /// Witnesses the given point as a private input to the circuit. - /// This allows the point to be the identity, mapped to (0, 0) in - /// affine coordinates. - fn witness_point( - &self, - layouter: &mut impl Layouter, - value: Value, - ) -> Result; - - /// Witnesses the given point as a private input to the circuit. - /// This returns an error if the point is the identity. - fn witness_point_non_id( - &self, - layouter: &mut impl Layouter, - value: Value, - ) -> Result; - - /// Witnesses a full-width scalar to be used in variable-base multiplication. - fn witness_scalar_var( - &self, - layouter: &mut impl Layouter, - value: Value, - ) -> Result; - - /// Witnesses a full-width scalar to be used in fixed-base multiplication. - fn witness_scalar_fixed( - &self, - layouter: &mut impl Layouter, - value: Value, - ) -> Result; - - /// Converts a magnitude and sign that exists as variables in the circuit into a - /// signed short scalar to be used in fixed-base scalar multiplication. - fn scalar_fixed_from_signed_short( - &self, - layouter: &mut impl Layouter, - magnitude_sign: (Self::Var, Self::Var), - ) -> Result; - - /// Extracts the x-coordinate of a point. - fn extract_p + Clone>(point: &Point) -> Self::X; - - /// Performs incomplete point addition, returning `a + b`. - /// - /// This returns an error in exceptional cases. - fn add_incomplete( - &self, - layouter: &mut impl Layouter, - a: &Self::NonIdentityPoint, - b: &Self::NonIdentityPoint, - ) -> Result; - - /// Performs complete point addition, returning `a + b`. - fn add + Clone, B: Into + Clone>( - &self, - layouter: &mut impl Layouter, - a: &A, - b: &B, - ) -> Result; - - /// Performs variable-base scalar multiplication, returning `[scalar] base`. - fn mul( - &self, - layouter: &mut impl Layouter, - scalar: &Self::ScalarVar, - base: &Self::NonIdentityPoint, - ) -> Result<(Self::Point, Self::ScalarVar), Error>; - - /// Performs fixed-base scalar multiplication using a full-width scalar, returning `[scalar] base`. - fn mul_fixed( - &self, - layouter: &mut impl Layouter, - scalar: &Self::ScalarFixed, - base: &>::FullScalar, - ) -> Result<(Self::Point, Self::ScalarFixed), Error>; - - /// Performs fixed-base scalar multiplication using a short signed scalar, returning - /// `[scalar] base`. - fn mul_fixed_short( - &self, - layouter: &mut impl Layouter, - scalar: &Self::ScalarFixedShort, - base: &>::ShortScalar, - ) -> Result<(Self::Point, Self::ScalarFixedShort), Error>; - - /// Performs fixed-base scalar multiplication using a base field element as the scalar. - /// In the current implementation, this base field element must be output from another - /// instruction. - fn mul_fixed_base_field_elem( - &self, - layouter: &mut impl Layouter, - base_field_elem: Self::Var, - base: &>::Base, - ) -> Result; -} - -/// Instructions that can be implemented for a curve whose base field fits into -/// its scalar field. -pub trait BaseFitsInScalarInstructions: EccInstructions { - /// Converts a base field element that exists as a variable in the circuit - /// into a scalar to be used in variable-base scalar multiplication. - fn scalar_var_from_base( - &self, - layouter: &mut impl Layouter, - base: &Self::Var, - ) -> Result; -} - -/// Defines the fixed points for a given instantiation of the ECC chip. -pub trait FixedPoints: Debug + Eq + Clone { - /// Fixed points that can be used with full-width scalar multiplication. - type FullScalar: Debug + Eq + Clone; - /// Fixed points that can be used with short scalar multiplication. - type ShortScalar: Debug + Eq + Clone; - /// Fixed points that can be multiplied by base field elements. - type Base: Debug + Eq + Clone; -} - -/// An integer representing an element of the scalar field for a specific elliptic curve. -#[derive(Debug)] -pub struct ScalarVar> { - chip: EccChip, - inner: EccChip::ScalarVar, -} - -impl> ScalarVar { - /// Witnesses the given full-width scalar. - /// - /// Depending on the `EccChip` implementation, this may either witness the scalar - /// immediately, or delay witnessing until its first use in [`NonIdentityPoint::mul`]. - pub fn new( - chip: EccChip, - mut layouter: impl Layouter, - value: Value, - ) -> Result { - let scalar = chip.witness_scalar_var(&mut layouter, value); - scalar.map(|inner| ScalarVar { chip, inner }) - } -} - -impl> ScalarVar { - /// Constructs a scalar from an existing base-field element. - pub fn from_base( - chip: EccChip, - mut layouter: impl Layouter, - base: &EccChip::Var, - ) -> Result { - let scalar = chip.scalar_var_from_base(&mut layouter, base); - scalar.map(|inner| ScalarVar { chip, inner }) - } -} - -/// An integer representing an element of the scalar field for a specific elliptic curve, -/// for [`FixedPoint`] scalar multiplication. -#[derive(Debug)] -pub struct ScalarFixed> { - chip: EccChip, - inner: EccChip::ScalarFixed, -} - -impl> ScalarFixed { - /// Witnesses the given full-width scalar. - /// - /// Depending on the `EccChip` implementation, this may either witness the scalar - /// immediately, or delay witnessing until its first use in [`FixedPoint::mul`]. - pub fn new( - chip: EccChip, - mut layouter: impl Layouter, - value: Value, - ) -> Result { - let scalar = chip.witness_scalar_fixed(&mut layouter, value); - scalar.map(|inner| ScalarFixed { chip, inner }) - } -} - -/// A signed short (64-bit) integer represented as an element of the scalar field for a -/// specific elliptic curve, to be used for [`FixedPointShort`] scalar multiplication. -#[derive(Debug)] -pub struct ScalarFixedShort> { - chip: EccChip, - inner: EccChip::ScalarFixedShort, -} - -impl> ScalarFixedShort { - /// Converts the given signed short scalar. - /// - /// `magnitude_sign` must be a tuple of two circuit-assigned values: - /// - An unsigned integer of at most 64 bits. - /// - A sign value that is either 1 or -1. - /// - /// Depending on the `EccChip` implementation, the scalar may either be constrained - /// immediately by this constructor, or lazily constrained when it is first used in - /// [`FixedPointShort::mul`]. - pub fn new( - chip: EccChip, - mut layouter: impl Layouter, - magnitude_sign: (EccChip::Var, EccChip::Var), - ) -> Result { - let scalar = chip.scalar_fixed_from_signed_short(&mut layouter, magnitude_sign); - scalar.map(|inner| ScalarFixedShort { chip, inner }) - } -} - -/// A point on a specific elliptic curve that is guaranteed to not be the identity. -#[derive(Copy, Clone, Debug)] -pub struct NonIdentityPoint> { - chip: EccChip, - inner: EccChip::NonIdentityPoint, -} - -impl> NonIdentityPoint { - /// Constructs a new point with the given value. - pub fn new( - chip: EccChip, - mut layouter: impl Layouter, - value: Value, - ) -> Result { - let point = chip.witness_point_non_id(&mut layouter, value); - point.map(|inner| NonIdentityPoint { chip, inner }) - } - - /// Constrains this point to be equal in value to another point. - pub fn constrain_equal> + Clone>( - &self, - mut layouter: impl Layouter, - other: &Other, - ) -> Result<(), Error> { - let other: Point = (other.clone()).into(); - self.chip.constrain_equal( - &mut layouter, - &Point::::from(self.clone()).inner, - &other.inner, - ) - } - - /// Returns the inner point. - pub fn inner(&self) -> &EccChip::NonIdentityPoint { - &self.inner - } - - /// Extracts the x-coordinate of a point. - pub fn extract_p(&self) -> X { - X::from_inner(self.chip.clone(), EccChip::extract_p(&self.inner)) - } - - /// Wraps the given point (obtained directly from an instruction) in a gadget. - pub fn from_inner(chip: EccChip, inner: EccChip::NonIdentityPoint) -> Self { - NonIdentityPoint { chip, inner } - } - - /// Returns `self + other` using complete addition. - pub fn add> + Clone>( - &self, - mut layouter: impl Layouter, - other: &Other, - ) -> Result, Error> { - let other: Point = (other.clone()).into(); - - assert_eq!(self.chip, other.chip); - self.chip - .add(&mut layouter, &self.inner, &other.inner) - .map(|inner| Point { - chip: self.chip.clone(), - inner, - }) - } - - /// Returns `self + other` using incomplete addition. - /// The arguments are type-constrained not to be the identity point, - /// and since exceptional cases return an Error, the result also cannot - /// be the identity point. - pub fn add_incomplete( - &self, - mut layouter: impl Layouter, - other: &Self, - ) -> Result { - assert_eq!(self.chip, other.chip); - self.chip - .add_incomplete(&mut layouter, &self.inner, &other.inner) - .map(|inner| NonIdentityPoint { - chip: self.chip.clone(), - inner, - }) - } - - /// Returns `[by] self`. - #[allow(clippy::type_complexity)] - pub fn mul( - &self, - mut layouter: impl Layouter, - by: ScalarVar, - ) -> Result<(Point, ScalarVar), Error> { - assert_eq!(self.chip, by.chip); - self.chip - .mul(&mut layouter, &by.inner, &self.inner.clone()) - .map(|(point, scalar)| { - ( - Point { - chip: self.chip.clone(), - inner: point, - }, - ScalarVar { - chip: self.chip.clone(), - inner: scalar, - }, - ) - }) - } -} - -impl + Clone + Debug + Eq> - From> for Point -{ - fn from(non_id_point: NonIdentityPoint) -> Self { - Self { - chip: non_id_point.chip, - inner: non_id_point.inner.into(), - } - } -} - -/// A point on a specific elliptic curve. -#[derive(Copy, Clone, Debug)] -pub struct Point + Clone + Debug + Eq> { - chip: EccChip, - inner: EccChip::Point, -} - -impl + Clone + Debug + Eq> Point { - /// Constructs a new point with the given value. - pub fn new( - chip: EccChip, - mut layouter: impl Layouter, - value: Value, - ) -> Result { - let point = chip.witness_point(&mut layouter, value); - point.map(|inner| Point { chip, inner }) - } - - /// Constrains this point to be equal in value to another point. - pub fn constrain_equal> + Clone>( - &self, - mut layouter: impl Layouter, - other: &Other, - ) -> Result<(), Error> { - let other: Point = (other.clone()).into(); - self.chip - .constrain_equal(&mut layouter, &self.inner, &other.inner) - } - - /// Returns the inner point. - pub fn inner(&self) -> &EccChip::Point { - &self.inner - } - - /// Extracts the x-coordinate of a point. - pub fn extract_p(&self) -> X { - X::from_inner(self.chip.clone(), EccChip::extract_p(&self.inner)) - } - - /// Wraps the given point (obtained directly from an instruction) in a gadget. - pub fn from_inner(chip: EccChip, inner: EccChip::Point) -> Self { - Point { chip, inner } - } - - /// Returns `self + other` using complete addition. - pub fn add> + Clone>( - &self, - mut layouter: impl Layouter, - other: &Other, - ) -> Result, Error> { - let other: Point = (other.clone()).into(); - - assert_eq!(self.chip, other.chip); - self.chip - .add(&mut layouter, &self.inner, &other.inner) - .map(|inner| Point { - chip: self.chip.clone(), - inner, - }) - } -} - -/// The affine short Weierstrass x-coordinate of a point on a specific elliptic curve. -#[derive(Debug)] -pub struct X> { - chip: EccChip, - inner: EccChip::X, -} - -impl> X { - /// Wraps the given x-coordinate (obtained directly from an instruction) in a gadget. - pub fn from_inner(chip: EccChip, inner: EccChip::X) -> Self { - X { chip, inner } - } - - /// Returns the inner x-coordinate. - pub fn inner(&self) -> &EccChip::X { - &self.inner - } -} - -/// Precomputed multiples of a fixed point, for full-width scalar multiplication. -/// -/// Fixing the curve point enables window tables to be baked into the circuit, making -/// scalar multiplication more efficient. These window tables are tuned to full-width -/// scalar multiplication. -#[derive(Clone, Debug)] -pub struct FixedPoint> { - chip: EccChip, - inner: >::FullScalar, -} - -/// Precomputed multiples of a fixed point, that can be multiplied by base-field elements. -/// -/// Fixing the curve point enables window tables to be baked into the circuit, making -/// scalar multiplication more efficient. These window tables are tuned to scalar -/// multiplication by base-field elements. -#[derive(Clone, Debug)] -pub struct FixedPointBaseField> { - chip: EccChip, - inner: >::Base, -} - -/// Precomputed multiples of a fixed point, for short signed scalar multiplication. -#[derive(Clone, Debug)] -pub struct FixedPointShort> { - chip: EccChip, - inner: >::ShortScalar, -} - -impl> FixedPoint { - #[allow(clippy::type_complexity)] - /// Returns `[by] self`. - pub fn mul( - &self, - mut layouter: impl Layouter, - by: ScalarFixed, - ) -> Result<(Point, ScalarFixed), Error> { - assert_eq!(self.chip, by.chip); - self.chip - .mul_fixed(&mut layouter, &by.inner, &self.inner) - .map(|(point, scalar)| { - ( - Point { - chip: self.chip.clone(), - inner: point, - }, - ScalarFixed { - chip: self.chip.clone(), - inner: scalar, - }, - ) - }) - } - - /// Wraps the given fixed base (obtained directly from an instruction) in a gadget. - pub fn from_inner( - chip: EccChip, - inner: >::FullScalar, - ) -> Self { - Self { chip, inner } - } -} - -impl> FixedPointBaseField { - #[allow(clippy::type_complexity)] - /// Returns `[by] self`. - pub fn mul( - &self, - mut layouter: impl Layouter, - by: EccChip::Var, - ) -> Result, Error> { - self.chip - .mul_fixed_base_field_elem(&mut layouter, by, &self.inner) - .map(|inner| Point { - chip: self.chip.clone(), - inner, - }) - } - - /// Wraps the given fixed base (obtained directly from an instruction) in a gadget. - pub fn from_inner( - chip: EccChip, - inner: >::Base, - ) -> Self { - Self { chip, inner } - } -} - -impl> FixedPointShort { - #[allow(clippy::type_complexity)] - /// Returns `[by] self`. - pub fn mul( - &self, - mut layouter: impl Layouter, - by: ScalarFixedShort, - ) -> Result<(Point, ScalarFixedShort), Error> { - assert_eq!(self.chip, by.chip); - self.chip - .mul_fixed_short(&mut layouter, &by.inner, &self.inner) - .map(|(point, scalar)| { - ( - Point { - chip: self.chip.clone(), - inner: point, - }, - ScalarFixedShort { - chip: self.chip.clone(), - inner: scalar, - }, - ) - }) - } - - /// Wraps the given fixed base (obtained directly from an instruction) in a gadget. - pub fn from_inner( - chip: EccChip, - inner: >::ShortScalar, - ) -> Self { - Self { chip, inner } - } -} - -#[cfg(test)] -pub(crate) mod tests { - use ff::PrimeField; - use group::{prime::PrimeCurveAffine, Curve, Group}; - - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use halo2curves::pasta::pallas; - use lazy_static::lazy_static; - - use super::{ - chip::{ - find_zs_and_us, BaseFieldElem, EccChip, EccConfig, FixedPoint, FullScalar, ShortScalar, - H, NUM_WINDOWS, NUM_WINDOWS_SHORT, - }, - FixedPoints, - }; - use crate::utilities::lookup_range_check::LookupRangeCheckConfig; - - #[derive(Debug, Eq, PartialEq, Clone)] - pub(crate) struct TestFixedBases; - #[derive(Debug, Eq, PartialEq, Clone)] - pub(crate) struct FullWidth(pallas::Affine, &'static [(u64, [pallas::Base; H])]); - #[derive(Debug, Eq, PartialEq, Clone)] - pub(crate) struct BaseField; - #[derive(Debug, Eq, PartialEq, Clone)] - pub(crate) struct Short; - - lazy_static! { - static ref BASE: pallas::Affine = pallas::Point::generator().to_affine(); - static ref ZS_AND_US: Vec<(u64, [pallas::Base; H])> = - find_zs_and_us(*BASE, NUM_WINDOWS).unwrap(); - static ref ZS_AND_US_SHORT: Vec<(u64, [pallas::Base; H])> = - find_zs_and_us(*BASE, NUM_WINDOWS_SHORT).unwrap(); - } - - impl FullWidth { - pub(crate) fn from_pallas_generator() -> Self { - FullWidth(*BASE, &ZS_AND_US) - } - - pub(crate) fn from_parts( - base: pallas::Affine, - zs_and_us: &'static [(u64, [pallas::Base; H])], - ) -> Self { - FullWidth(base, zs_and_us) - } - } - - impl FixedPoint for FullWidth { - type FixedScalarKind = FullScalar; - - fn generator(&self) -> pallas::Affine { - self.0 - } - - fn u(&self) -> Vec<[[u8; 32]; H]> { - self.1 - .iter() - .map(|(_, us)| { - [ - us[0].to_repr(), - us[1].to_repr(), - us[2].to_repr(), - us[3].to_repr(), - us[4].to_repr(), - us[5].to_repr(), - us[6].to_repr(), - us[7].to_repr(), - ] - }) - .collect() - } - - fn z(&self) -> Vec { - self.1.iter().map(|(z, _)| *z).collect() - } - } - - impl FixedPoint for BaseField { - type FixedScalarKind = BaseFieldElem; - - fn generator(&self) -> pallas::Affine { - *BASE - } - - fn u(&self) -> Vec<[[u8; 32]; H]> { - ZS_AND_US - .iter() - .map(|(_, us)| { - [ - us[0].to_repr(), - us[1].to_repr(), - us[2].to_repr(), - us[3].to_repr(), - us[4].to_repr(), - us[5].to_repr(), - us[6].to_repr(), - us[7].to_repr(), - ] - }) - .collect() - } - - fn z(&self) -> Vec { - ZS_AND_US.iter().map(|(z, _)| *z).collect() - } - } - - impl FixedPoint for Short { - type FixedScalarKind = ShortScalar; - - fn generator(&self) -> pallas::Affine { - *BASE - } - - fn u(&self) -> Vec<[[u8; 32]; H]> { - ZS_AND_US_SHORT - .iter() - .map(|(_, us)| { - [ - us[0].to_repr(), - us[1].to_repr(), - us[2].to_repr(), - us[3].to_repr(), - us[4].to_repr(), - us[5].to_repr(), - us[6].to_repr(), - us[7].to_repr(), - ] - }) - .collect() - } - - fn z(&self) -> Vec { - ZS_AND_US_SHORT.iter().map(|(z, _)| *z).collect() - } - } - - impl FixedPoints for TestFixedBases { - type FullScalar = FullWidth; - type ShortScalar = Short; - type Base = BaseField; - } - - struct MyCircuit { - test_errors: bool, - } - - #[allow(non_snake_case)] - impl Circuit for MyCircuit { - type Config = EccConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - MyCircuit { test_errors: false } - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let advices = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - let lookup_table = meta.lookup_table_column(); - let lagrange_coeffs = [ - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - ]; - // Shared fixed column for loading constants - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table); - EccChip::::configure(meta, advices, lagrange_coeffs, range_check) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let chip = EccChip::construct(config.clone()); - - // Load 10-bit lookup table. In the Action circuit, this will be - // provided by the Sinsemilla chip. - config.lookup_config.load(&mut layouter)?; - - // Generate a random non-identity point P - let p_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); // P - let p = super::NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "P"), - Value::known(p_val), - )?; - let p_neg = -p_val; - let p_neg = super::NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "-P"), - Value::known(p_neg), - )?; - - // Generate a random non-identity point Q - let q_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); // Q - let q = super::NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "Q"), - Value::known(q_val), - )?; - - // Make sure P and Q are not the same point. - assert_ne!(p_val, q_val); - - // Test that we can witness the identity as a point, but not as a non-identity point. - { - let _ = super::Point::new( - chip.clone(), - layouter.namespace(|| "identity"), - Value::known(pallas::Affine::identity()), - )?; - - super::NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "identity"), - Value::known(pallas::Affine::identity()), - ) - .expect_err("Trying to witness the identity should return an error"); - } - - // Test witness non-identity point - { - super::chip::witness_point::tests::test_witness_non_id( - chip.clone(), - layouter.namespace(|| "witness non-identity point"), - ) - } - - // Test complete addition - { - super::chip::add::tests::test_add( - chip.clone(), - layouter.namespace(|| "complete addition"), - p_val, - &p, - q_val, - &q, - &p_neg, - )?; - } - - // Test incomplete addition - { - super::chip::add_incomplete::tests::test_add_incomplete( - chip.clone(), - layouter.namespace(|| "incomplete addition"), - p_val, - &p, - q_val, - &q, - &p_neg, - self.test_errors, - )?; - } - - // Test variable-base scalar multiplication - { - super::chip::mul::tests::test_mul( - chip.clone(), - layouter.namespace(|| "variable-base scalar mul"), - &p, - p_val, - )?; - } - - // Test full-width fixed-base scalar multiplication - { - super::chip::mul_fixed::full_width::tests::test_mul_fixed( - chip.clone(), - layouter.namespace(|| "full-width fixed-base scalar mul"), - )?; - } - - // Test signed short fixed-base scalar multiplication - { - super::chip::mul_fixed::short::tests::test_mul_fixed_short( - chip.clone(), - layouter.namespace(|| "signed short fixed-base scalar mul"), - )?; - } - - // Test fixed-base scalar multiplication with a base field element - { - super::chip::mul_fixed::base_field_elem::tests::test_mul_fixed_base_field( - chip, - layouter.namespace(|| "fixed-base scalar mul with base field element"), - )?; - } - - Ok(()) - } - } - - #[test] - fn ecc_chip() { - let k = 13; - let circuit = MyCircuit { test_errors: true }; - let prover = MockProver::run(k, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())) - } - - #[cfg(feature = "dev-graph")] - #[test] - fn print_ecc_chip() { - use plotters::prelude::*; - - let root = BitMapBackend::new("ecc-chip-layout.png", (1024, 7680)).into_drawing_area(); - root.fill(&WHITE).unwrap(); - let root = root.titled("Ecc Chip Layout", ("sans-serif", 60)).unwrap(); - - let circuit = MyCircuit { test_errors: false }; - halo2_proofs::dev::CircuitLayout::default() - .render(13, &circuit, &root) - .unwrap(); - } -} diff --git a/halo2_gadgets/src/ecc/chip.rs b/halo2_gadgets/src/ecc/chip.rs deleted file mode 100644 index 466234e6b7..0000000000 --- a/halo2_gadgets/src/ecc/chip.rs +++ /dev/null @@ -1,614 +0,0 @@ -//! Chip implementations for the ECC gadgets. - -use super::{BaseFitsInScalarInstructions, EccInstructions, FixedPoints}; -use crate::{ - sinsemilla::primitives as sinsemilla, - utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, -}; -use arrayvec::ArrayVec; - -use ff::PrimeField; -use group::prime::PrimeCurveAffine; -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{Advice, Assigned, Column, ConstraintSystem, Error, Fixed}, -}; -use halo2curves::{pasta::pallas, CurveAffine}; - -use std::convert::TryInto; - -pub(super) mod add; -pub(super) mod add_incomplete; -pub mod constants; -pub(super) mod mul; -pub(super) mod mul_fixed; -pub(super) mod witness_point; - -pub use constants::*; - -// Exposed for Sinsemilla. -pub(crate) use mul::incomplete::DoubleAndAdd; - -/// A curve point represented in affine (x, y) coordinates, or the -/// identity represented as (0, 0). -/// Each coordinate is assigned to a cell. -#[derive(Clone, Debug)] -pub struct EccPoint { - /// x-coordinate - /// - /// Stored as an `Assigned` to enable batching inversions. - x: AssignedCell, pallas::Base>, - /// y-coordinate - /// - /// Stored as an `Assigned` to enable batching inversions. - y: AssignedCell, pallas::Base>, -} - -impl EccPoint { - /// Constructs a point from its coordinates, without checking they are on the curve. - /// - /// This is an internal API that we only use where we know we have a valid curve point - /// (specifically inside Sinsemilla). - pub(crate) fn from_coordinates_unchecked( - x: AssignedCell, pallas::Base>, - y: AssignedCell, pallas::Base>, - ) -> Self { - EccPoint { x, y } - } - - /// Returns the value of this curve point, if known. - pub fn point(&self) -> Value { - self.x.value().zip(self.y.value()).map(|(x, y)| { - if x.is_zero_vartime() && y.is_zero_vartime() { - pallas::Affine::identity() - } else { - pallas::Affine::from_xy(x.evaluate(), y.evaluate()).unwrap() - } - }) - } - /// The cell containing the affine short-Weierstrass x-coordinate, - /// or 0 for the zero point. - pub fn x(&self) -> AssignedCell { - self.x.clone().evaluate() - } - /// The cell containing the affine short-Weierstrass y-coordinate, - /// or 0 for the zero point. - pub fn y(&self) -> AssignedCell { - self.y.clone().evaluate() - } - - #[cfg(test)] - fn is_identity(&self) -> Value { - self.x.value().map(|x| x.is_zero_vartime()) - } -} - -/// A non-identity point represented in affine (x, y) coordinates. -/// Each coordinate is assigned to a cell. -#[derive(Clone, Debug)] -pub struct NonIdentityEccPoint { - /// x-coordinate - /// - /// Stored as an `Assigned` to enable batching inversions. - x: AssignedCell, pallas::Base>, - /// y-coordinate - /// - /// Stored as an `Assigned` to enable batching inversions. - y: AssignedCell, pallas::Base>, -} - -impl NonIdentityEccPoint { - /// Constructs a point from its coordinates, without checking they are on the curve. - /// - /// This is an internal API that we only use where we know we have a valid non-identity - /// curve point (specifically inside Sinsemilla). - pub(crate) fn from_coordinates_unchecked( - x: AssignedCell, pallas::Base>, - y: AssignedCell, pallas::Base>, - ) -> Self { - NonIdentityEccPoint { x, y } - } - - /// Returns the value of this curve point, if known. - pub fn point(&self) -> Value { - self.x.value().zip(self.y.value()).map(|(x, y)| { - assert!(!x.is_zero_vartime() && !y.is_zero_vartime()); - pallas::Affine::from_xy(x.evaluate(), y.evaluate()).unwrap() - }) - } - /// The cell containing the affine short-Weierstrass x-coordinate. - pub fn x(&self) -> AssignedCell { - self.x.clone().evaluate() - } - /// The cell containing the affine short-Weierstrass y-coordinate. - pub fn y(&self) -> AssignedCell { - self.y.clone().evaluate() - } -} - -impl From for EccPoint { - fn from(non_id_point: NonIdentityEccPoint) -> Self { - Self { - x: non_id_point.x, - y: non_id_point.y, - } - } -} - -/// Configuration for [`EccChip`]. -#[derive(Clone, Debug, Eq, PartialEq)] -#[allow(non_snake_case)] -pub struct EccConfig> { - /// Advice columns needed by instructions in the ECC chip. - pub advices: [Column; 10], - - /// Incomplete addition - add_incomplete: add_incomplete::Config, - - /// Complete addition - add: add::Config, - - /// Variable-base scalar multiplication - mul: mul::Config, - - /// Fixed-base full-width scalar multiplication - mul_fixed_full: mul_fixed::full_width::Config, - /// Fixed-base signed short scalar multiplication - mul_fixed_short: mul_fixed::short::Config, - /// Fixed-base mul using a base field element as a scalar - mul_fixed_base_field: mul_fixed::base_field_elem::Config, - - /// Witness point - witness_point: witness_point::Config, - - /// Lookup range check using 10-bit lookup table - pub lookup_config: LookupRangeCheckConfig, -} - -/// A trait representing the kind of scalar used with a particular `FixedPoint`. -/// -/// This trait exists because of limitations around const generics. -pub trait FixedScalarKind { - /// The number of windows that this scalar kind requires. - const NUM_WINDOWS: usize; -} - -/// Type marker representing a full-width scalar for use in fixed-base scalar -/// multiplication. -#[derive(Debug)] -pub enum FullScalar {} -impl FixedScalarKind for FullScalar { - const NUM_WINDOWS: usize = NUM_WINDOWS; -} - -/// Type marker representing a signed 64-bit scalar for use in fixed-base scalar -/// multiplication. -#[derive(Debug)] -pub enum ShortScalar {} -impl FixedScalarKind for ShortScalar { - const NUM_WINDOWS: usize = NUM_WINDOWS_SHORT; -} - -/// Type marker representing a base field element being used as a scalar in fixed-base -/// scalar multiplication. -#[derive(Debug)] -pub enum BaseFieldElem {} -impl FixedScalarKind for BaseFieldElem { - const NUM_WINDOWS: usize = NUM_WINDOWS; -} - -/// Returns information about a fixed point that is required by [`EccChip`]. -/// -/// For each window required by `Self::FixedScalarKind`, $z$ is a field element such that for -/// each point $(x, y)$ in the window: -/// - $z + y = u^2$ (some square in the field); and -/// - $z - y$ is not a square. -/// -/// TODO: When associated consts can be used as const generics, introduce a -/// `const NUM_WINDOWS: usize` associated const, and return `NUM_WINDOWS`-sized -/// arrays instead of `Vec`s. -pub trait FixedPoint: std::fmt::Debug + Eq + Clone { - /// The kind of scalar that this fixed point can be multiplied by. - type FixedScalarKind: FixedScalarKind; - - /// Returns the generator for this fixed point. - fn generator(&self) -> C; - - /// Returns the $u$ values for this fixed point. - fn u(&self) -> Vec<[::Repr; H]>; - - /// Returns the $z$ value for this fixed point. - fn z(&self) -> Vec; - - /// Returns the Lagrange coefficients for this fixed point. - fn lagrange_coeffs(&self) -> Vec<[C::Base; H]> { - compute_lagrange_coeffs(self.generator(), Self::FixedScalarKind::NUM_WINDOWS) - } -} - -/// An [`EccInstructions`] chip that uses 10 advice columns. -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct EccChip> { - config: EccConfig, -} - -impl> Chip for EccChip { - type Config = EccConfig; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -impl> UtilitiesInstructions - for EccChip -{ - type Var = AssignedCell; -} - -impl> EccChip { - /// Reconstructs this chip from the given config. - pub fn construct(config: >::Config) -> Self { - Self { config } - } - - /// # Side effects - /// - /// All columns in `advices` will be equality-enabled. - #[allow(non_snake_case)] - pub fn configure( - meta: &mut ConstraintSystem, - advices: [Column; 10], - lagrange_coeffs: [Column; 8], - range_check: LookupRangeCheckConfig, - ) -> >::Config { - // Create witness point gate - let witness_point = witness_point::Config::configure(meta, advices[0], advices[1]); - // Create incomplete point addition gate - let add_incomplete = - add_incomplete::Config::configure(meta, advices[0], advices[1], advices[2], advices[3]); - - // Create complete point addition gate - let add = add::Config::configure( - meta, advices[0], advices[1], advices[2], advices[3], advices[4], advices[5], - advices[6], advices[7], advices[8], - ); - - // Create variable-base scalar mul gates - let mul = mul::Config::configure(meta, add, range_check, advices); - - // Create config that is shared across short, base-field, and full-width - // fixed-base scalar mul. - let mul_fixed = mul_fixed::Config::::configure( - meta, - lagrange_coeffs, - advices[4], - advices[5], - add, - add_incomplete, - ); - - // Create gate that is only used in full-width fixed-base scalar mul. - let mul_fixed_full = - mul_fixed::full_width::Config::::configure(meta, mul_fixed.clone()); - - // Create gate that is only used in short fixed-base scalar mul. - let mul_fixed_short = - mul_fixed::short::Config::::configure(meta, mul_fixed.clone()); - - // Create gate that is only used in fixed-base mul using a base field element. - let mul_fixed_base_field = mul_fixed::base_field_elem::Config::::configure( - meta, - advices[6..9].try_into().unwrap(), - range_check, - mul_fixed, - ); - - EccConfig { - advices, - add_incomplete, - add, - mul, - mul_fixed_full, - mul_fixed_short, - mul_fixed_base_field, - witness_point, - lookup_config: range_check, - } - } -} - -/// A full-width scalar used for fixed-base scalar multiplication. -/// This is decomposed into 85 3-bit windows in little-endian order, -/// i.e. `windows` = [k_0, k_1, ..., k_84] (for a 255-bit scalar) -/// where `scalar = k_0 + k_1 * (2^3) + ... + k_84 * (2^3)^84` and -/// each `k_i` is in the range [0..2^3). -#[derive(Clone, Debug)] -pub struct EccScalarFixed { - value: Value, - /// The circuit-assigned windows representing this scalar, or `None` if the scalar has - /// not been used yet. - windows: Option, { NUM_WINDOWS }>>, -} - -// TODO: Make V a `u64` -type MagnitudeCell = AssignedCell; -// TODO: Make V an enum Sign { Positive, Negative } -type SignCell = AssignedCell; -type MagnitudeSign = (MagnitudeCell, SignCell); - -/// A signed short scalar used for fixed-base scalar multiplication. -/// A short scalar must have magnitude in the range [0..2^64), with -/// a sign of either 1 or -1. -/// This is decomposed into 3-bit windows in little-endian order -/// using a running sum `z`, where z_{i+1} = (z_i - a_i) / (2^3) -/// for element α = a_0 + (2^3) a_1 + ... + (2^{3(n-1)}) a_{n-1}. -/// Each `a_i` is in the range [0..2^3). -/// -/// `windows` = [k_0, k_1, ..., k_21] (for a 64-bit magnitude) -/// where `scalar = k_0 + k_1 * (2^3) + ... + k_84 * (2^3)^84` and -/// each `k_i` is in the range [0..2^3). -/// k_21 must be a single bit, i.e. 0 or 1. -#[derive(Clone, Debug)] -pub struct EccScalarFixedShort { - magnitude: MagnitudeCell, - sign: SignCell, - /// The circuit-assigned running sum constraining this signed short scalar, or `None` - /// if the scalar has not been used yet. - running_sum: - Option, { NUM_WINDOWS_SHORT + 1 }>>, -} - -/// A base field element used for fixed-base scalar multiplication. -/// This is decomposed into 3-bit windows in little-endian order -/// using a running sum `z`, where z_{i+1} = (z_i - a_i) / (2^3) -/// for element α = a_0 + (2^3) a_1 + ... + (2^{3(n-1)}) a_{n-1}. -/// Each `a_i` is in the range [0..2^3). -/// -/// `running_sum` = [z_0, ..., z_85], where we expect z_85 = 0. -/// Since z_0 is initialized as the scalar α, we store it as -/// `base_field_elem`. -#[derive(Clone, Debug)] -struct EccBaseFieldElemFixed { - base_field_elem: AssignedCell, - running_sum: ArrayVec, { NUM_WINDOWS + 1 }>, -} - -impl EccBaseFieldElemFixed { - fn base_field_elem(&self) -> AssignedCell { - self.base_field_elem.clone() - } -} - -/// An enumeration of the possible types of scalars used in variable-base -/// multiplication. -#[derive(Clone, Debug)] -pub enum ScalarVar { - /// An element of the elliptic curve's base field, that is used as a scalar - /// in variable-base scalar mul. - /// - /// It is not true in general that a scalar field element fits in a curve's - /// base field, and in particular it is untrue for the Pallas curve, whose - /// scalar field `Fq` is larger than its base field `Fp`. - /// - /// However, the only use of variable-base scalar mul in the Orchard protocol - /// is in deriving diversified addresses `[ivk] g_d`, and `ivk` is guaranteed - /// to be in the base field of the curve. (See non-normative notes in - /// [4.2.3 Orchard Key Components][orchardkeycomponents].) - /// - /// [orchardkeycomponents]: https://zips.z.cash/protocol/protocol.pdf#orchardkeycomponents - BaseFieldElem(AssignedCell), - /// A full-width scalar. This is unimplemented for halo2_gadgets v0.1.0. - FullWidth, -} - -impl> EccInstructions for EccChip -where - >::Base: - FixedPoint, - >::FullScalar: - FixedPoint, - >::ShortScalar: - FixedPoint, -{ - type ScalarFixed = EccScalarFixed; - type ScalarFixedShort = EccScalarFixedShort; - type ScalarVar = ScalarVar; - type Point = EccPoint; - type NonIdentityPoint = NonIdentityEccPoint; - type X = AssignedCell; - type FixedPoints = Fixed; - - fn constrain_equal( - &self, - layouter: &mut impl Layouter, - a: &Self::Point, - b: &Self::Point, - ) -> Result<(), Error> { - layouter.assign_region( - || "constrain equal", - |mut region| { - // Constrain x-coordinates - region.constrain_equal(a.x().cell(), b.x().cell())?; - // Constrain x-coordinates - region.constrain_equal(a.y().cell(), b.y().cell()) - }, - ) - } - - fn witness_point( - &self, - layouter: &mut impl Layouter, - value: Value, - ) -> Result { - let config = self.config().witness_point; - layouter.assign_region( - || "witness point", - |mut region| config.point(value, 0, &mut region), - ) - } - - fn witness_point_non_id( - &self, - layouter: &mut impl Layouter, - value: Value, - ) -> Result { - let config = self.config().witness_point; - layouter.assign_region( - || "witness non-identity point", - |mut region| config.point_non_id(value, 0, &mut region), - ) - } - - fn witness_scalar_var( - &self, - _layouter: &mut impl Layouter, - _value: Value, - ) -> Result { - // This is unimplemented for halo2_gadgets v0.1.0. - todo!() - } - - fn witness_scalar_fixed( - &self, - _layouter: &mut impl Layouter, - value: Value, - ) -> Result { - Ok(EccScalarFixed { - value, - // This chip uses lazy witnessing. - windows: None, - }) - } - - fn scalar_fixed_from_signed_short( - &self, - _layouter: &mut impl Layouter, - (magnitude, sign): MagnitudeSign, - ) -> Result { - Ok(EccScalarFixedShort { - magnitude, - sign, - // This chip uses lazy constraining. - running_sum: None, - }) - } - - fn extract_p + Clone>(point: &Point) -> Self::X { - let point: EccPoint = (point.clone()).into(); - point.x() - } - - fn add_incomplete( - &self, - layouter: &mut impl Layouter, - a: &Self::NonIdentityPoint, - b: &Self::NonIdentityPoint, - ) -> Result { - let config = self.config().add_incomplete; - layouter.assign_region( - || "incomplete point addition", - |mut region| config.assign_region(a, b, 0, &mut region), - ) - } - - fn add + Clone, B: Into + Clone>( - &self, - layouter: &mut impl Layouter, - a: &A, - b: &B, - ) -> Result { - let config = self.config().add; - layouter.assign_region( - || "complete point addition", - |mut region| { - config.assign_region(&(a.clone()).into(), &(b.clone()).into(), 0, &mut region) - }, - ) - } - - fn mul( - &self, - layouter: &mut impl Layouter, - scalar: &Self::ScalarVar, - base: &Self::NonIdentityPoint, - ) -> Result<(Self::Point, Self::ScalarVar), Error> { - let config = self.config().mul; - match scalar { - ScalarVar::BaseFieldElem(scalar) => config.assign( - layouter.namespace(|| "variable-base scalar mul"), - scalar.clone(), - base, - ), - ScalarVar::FullWidth => { - todo!() - } - } - } - - fn mul_fixed( - &self, - layouter: &mut impl Layouter, - scalar: &Self::ScalarFixed, - base: &>::FullScalar, - ) -> Result<(Self::Point, Self::ScalarFixed), Error> { - let config = self.config().mul_fixed_full.clone(); - config.assign( - layouter.namespace(|| format!("fixed-base mul of {:?}", base)), - scalar, - base, - ) - } - - fn mul_fixed_short( - &self, - layouter: &mut impl Layouter, - scalar: &Self::ScalarFixedShort, - base: &>::ShortScalar, - ) -> Result<(Self::Point, Self::ScalarFixedShort), Error> { - let config = self.config().mul_fixed_short.clone(); - config.assign( - layouter.namespace(|| format!("short fixed-base mul of {:?}", base)), - scalar, - base, - ) - } - - fn mul_fixed_base_field_elem( - &self, - layouter: &mut impl Layouter, - base_field_elem: AssignedCell, - base: &>::Base, - ) -> Result { - let config = self.config().mul_fixed_base_field.clone(); - config.assign( - layouter.namespace(|| format!("base-field elem fixed-base mul of {:?}", base)), - base_field_elem, - base, - ) - } -} - -impl> BaseFitsInScalarInstructions - for EccChip -where - >::Base: - FixedPoint, - >::FullScalar: - FixedPoint, - >::ShortScalar: - FixedPoint, -{ - fn scalar_var_from_base( - &self, - _layouter: &mut impl Layouter, - base: &Self::Var, - ) -> Result { - Ok(ScalarVar::BaseFieldElem(base.clone())) - } -} diff --git a/halo2_gadgets/src/ecc/chip/add.rs b/halo2_gadgets/src/ecc/chip/add.rs deleted file mode 100644 index 9f24d0d7dd..0000000000 --- a/halo2_gadgets/src/ecc/chip/add.rs +++ /dev/null @@ -1,456 +0,0 @@ -use super::EccPoint; -use halo2_proofs::{ - circuit::Region, - plonk::{Advice, Assigned, Column, ConstraintSystem, Constraints, Error, Expression, Selector}, - poly::Rotation, -}; -use halo2curves::{pasta::pallas, FieldExt}; -use std::collections::HashSet; - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct Config { - q_add: Selector, - // lambda - lambda: Column, - // x-coordinate of P in P + Q = R - pub x_p: Column, - // y-coordinate of P in P + Q = R - pub y_p: Column, - // x-coordinate of Q or R in P + Q = R - pub x_qr: Column, - // y-coordinate of Q or R in P + Q = R - pub y_qr: Column, - // α = inv0(x_q - x_p) - alpha: Column, - // β = inv0(x_p) - beta: Column, - // γ = inv0(x_q) - gamma: Column, - // δ = inv0(y_p + y_q) if x_q = x_p, 0 otherwise - delta: Column, -} - -impl Config { - #[allow(clippy::too_many_arguments)] - pub(super) fn configure( - meta: &mut ConstraintSystem, - x_p: Column, - y_p: Column, - x_qr: Column, - y_qr: Column, - lambda: Column, - alpha: Column, - beta: Column, - gamma: Column, - delta: Column, - ) -> Self { - meta.enable_equality(x_p); - meta.enable_equality(y_p); - meta.enable_equality(x_qr); - meta.enable_equality(y_qr); - - let config = Self { - q_add: meta.selector(), - x_p, - y_p, - x_qr, - y_qr, - lambda, - alpha, - beta, - gamma, - delta, - }; - - config.create_gate(meta); - - config - } - - pub(crate) fn advice_columns(&self) -> HashSet> { - [ - self.x_p, - self.y_p, - self.x_qr, - self.y_qr, - self.lambda, - self.alpha, - self.beta, - self.gamma, - self.delta, - ] - .into_iter() - .collect() - } - - pub(crate) fn output_columns(&self) -> HashSet> { - [self.x_qr, self.y_qr].into_iter().collect() - } - - fn create_gate(&self, meta: &mut ConstraintSystem) { - // https://p.z.cash/halo2-0.1:ecc-complete-addition - meta.create_gate("complete addition", |meta| { - let q_add = meta.query_selector(self.q_add); - let x_p = meta.query_advice(self.x_p, Rotation::cur()); - let y_p = meta.query_advice(self.y_p, Rotation::cur()); - let x_q = meta.query_advice(self.x_qr, Rotation::cur()); - let y_q = meta.query_advice(self.y_qr, Rotation::cur()); - let x_r = meta.query_advice(self.x_qr, Rotation::next()); - let y_r = meta.query_advice(self.y_qr, Rotation::next()); - let lambda = meta.query_advice(self.lambda, Rotation::cur()); - - // α = inv0(x_q - x_p) - let alpha = meta.query_advice(self.alpha, Rotation::cur()); - // β = inv0(x_p) - let beta = meta.query_advice(self.beta, Rotation::cur()); - // γ = inv0(x_q) - let gamma = meta.query_advice(self.gamma, Rotation::cur()); - // δ = inv0(y_p + y_q) if x_q = x_p, 0 otherwise - let delta = meta.query_advice(self.delta, Rotation::cur()); - - // Useful composite expressions - // (x_q − x_p) - let x_q_minus_x_p = x_q.clone() - x_p.clone(); - // (x_p - x_r) - let x_p_minus_x_r = x_p.clone() - x_r.clone(); - // (y_q + y_p) - let y_q_plus_y_p = y_q.clone() + y_p.clone(); - // α ⋅(x_q - x_p) - let if_alpha = x_q_minus_x_p.clone() * alpha; - // β ⋅ x_p - let if_beta = x_p.clone() * beta; - // γ ⋅ x_q - let if_gamma = x_q.clone() * gamma; - // δ ⋅(y_q + y_p) - let if_delta = y_q_plus_y_p.clone() * delta; - - // Useful constants - let one = Expression::Constant(pallas::Base::one()); - let two = Expression::Constant(pallas::Base::from(2)); - let three = Expression::Constant(pallas::Base::from(3)); - - // (x_q − x_p)⋅((x_q − x_p)⋅λ − (y_q−y_p)) = 0 - let poly1 = { - let y_q_minus_y_p = y_q.clone() - y_p.clone(); // (y_q − y_p) - let incomplete = x_q_minus_x_p.clone() * lambda.clone() - y_q_minus_y_p; // (x_q − x_p)⋅λ − (y_q−y_p) - - // q_add ⋅(x_q − x_p)⋅((x_q − x_p)⋅λ − (y_q−y_p)) - x_q_minus_x_p.clone() * incomplete - }; - - // (1 - (x_q - x_p)⋅α)⋅(2y_p ⋅λ - 3x_p^2) = 0 - let poly2 = { - let three_x_p_sq = three * x_p.clone().square(); // 3x_p^2 - let two_y_p = two * y_p.clone(); // 2y_p - let tangent_line = two_y_p * lambda.clone() - three_x_p_sq; // (2y_p ⋅λ - 3x_p^2) - - // q_add ⋅(1 - (x_q - x_p)⋅α)⋅(2y_p ⋅λ - 3x_p^2) - (one.clone() - if_alpha.clone()) * tangent_line - }; - - // (λ^2 - x_p - x_q - x_r) - let nonexceptional_x_r = - lambda.clone().square() - x_p.clone() - x_q.clone() - x_r.clone(); - // (λ ⋅(x_p - x_r) - y_p - y_r) - let nonexceptional_y_r = lambda * x_p_minus_x_r - y_p.clone() - y_r.clone(); - - // x_p⋅x_q⋅(x_q - x_p)⋅(λ^2 - x_p - x_q - x_r) = 0 - let poly3a = - x_p.clone() * x_q.clone() * x_q_minus_x_p.clone() * nonexceptional_x_r.clone(); - - // x_p⋅x_q⋅(x_q - x_p)⋅(λ ⋅(x_p - x_r) - y_p - y_r) = 0 - let poly3b = x_p.clone() * x_q.clone() * x_q_minus_x_p * nonexceptional_y_r.clone(); - - // x_p⋅x_q⋅(y_q + y_p)⋅(λ^2 - x_p - x_q - x_r) = 0 - let poly3c = x_p.clone() * x_q.clone() * y_q_plus_y_p.clone() * nonexceptional_x_r; - - // x_p⋅x_q⋅(y_q + y_p)⋅(λ ⋅(x_p - x_r) - y_p - y_r) = 0 - let poly3d = x_p.clone() * x_q.clone() * y_q_plus_y_p * nonexceptional_y_r; - - // (1 - x_p * β) * (x_r - x_q) = 0 - let poly4a = (one.clone() - if_beta.clone()) * (x_r.clone() - x_q); - - // (1 - x_p * β) * (y_r - y_q) = 0 - let poly4b = (one.clone() - if_beta) * (y_r.clone() - y_q); - - // (1 - x_q * γ) * (x_r - x_p) = 0 - let poly5a = (one.clone() - if_gamma.clone()) * (x_r.clone() - x_p); - - // (1 - x_q * γ) * (y_r - y_p) = 0 - let poly5b = (one.clone() - if_gamma) * (y_r.clone() - y_p); - - // ((1 - (x_q - x_p) * α - (y_q + y_p) * δ)) * x_r - let poly6a = (one.clone() - if_alpha.clone() - if_delta.clone()) * x_r; - - // ((1 - (x_q - x_p) * α - (y_q + y_p) * δ)) * y_r - let poly6b = (one - if_alpha - if_delta) * y_r; - - Constraints::with_selector( - q_add, - [ - ("1", poly1), - ("2", poly2), - ("3a", poly3a), - ("3b", poly3b), - ("3c", poly3c), - ("3d", poly3d), - ("4a", poly4a), - ("4b", poly4b), - ("5a", poly5a), - ("5b", poly5b), - ("6a", poly6a), - ("6b", poly6b), - ], - ) - }); - } - - pub(super) fn assign_region( - &self, - p: &EccPoint, - q: &EccPoint, - offset: usize, - region: &mut Region<'_, pallas::Base>, - ) -> Result { - // Enable `q_add` selector - self.q_add.enable(region, offset)?; - - // Copy point `p` into `x_p`, `y_p` columns - p.x.copy_advice(|| "x_p", region, self.x_p, offset)?; - p.y.copy_advice(|| "y_p", region, self.y_p, offset)?; - - // Copy point `q` into `x_qr`, `y_qr` columns - q.x.copy_advice(|| "x_q", region, self.x_qr, offset)?; - q.y.copy_advice(|| "y_q", region, self.y_qr, offset)?; - - let (x_p, y_p) = (p.x.value(), p.y.value()); - let (x_q, y_q) = (q.x.value(), q.y.value()); - - // Assign α = inv0(x_q - x_p) - let alpha = (x_q - x_p).invert(); - region.assign_advice(|| "α", self.alpha, offset, || alpha)?; - - // Assign β = inv0(x_p) - let beta = x_p.invert(); - region.assign_advice(|| "β", self.beta, offset, || beta)?; - - // Assign γ = inv0(x_q) - let gamma = x_q.invert(); - region.assign_advice(|| "γ", self.gamma, offset, || gamma)?; - - // Assign δ = inv0(y_q + y_p) if x_q = x_p, 0 otherwise - let delta = x_p - .zip(x_q) - .zip(y_p) - .zip(y_q) - .map(|(((x_p, x_q), y_p), y_q)| { - if x_q == x_p { - (y_q + y_p).invert() - } else { - Assigned::Zero - } - }); - region.assign_advice(|| "δ", self.delta, offset, || delta)?; - - #[allow(clippy::collapsible_else_if)] - // Assign lambda - let lambda = - x_p.zip(y_p) - .zip(x_q) - .zip(y_q) - .zip(alpha) - .map(|((((x_p, y_p), x_q), y_q), alpha)| { - if x_q != x_p { - // λ = (y_q - y_p)/(x_q - x_p) - // Here, alpha = inv0(x_q - x_p), which suffices since we - // know that x_q != x_p in this branch. - (y_q - y_p) * alpha - } else { - if !y_p.is_zero_vartime() { - // 3(x_p)^2 - let three_x_p_sq = x_p.square() * pallas::Base::from(3); - // 1 / 2(y_p) - let inv_two_y_p = y_p.invert() * pallas::Base::TWO_INV; - // λ = 3(x_p)^2 / 2(y_p) - three_x_p_sq * inv_two_y_p - } else { - Assigned::Zero - } - } - }); - region.assign_advice(|| "λ", self.lambda, offset, || lambda)?; - - // Calculate (x_r, y_r) - let r = - x_p.zip(y_p) - .zip(x_q) - .zip(y_q) - .zip(lambda) - .map(|((((x_p, y_p), x_q), y_q), lambda)| { - { - if x_p.is_zero_vartime() { - // 0 + Q = Q - (*x_q, *y_q) - } else if x_q.is_zero_vartime() { - // P + 0 = P - (*x_p, *y_p) - } else if (x_q == x_p) && (*y_q == -y_p) { - // P + (-P) maps to (0,0) - (Assigned::Zero, Assigned::Zero) - } else { - // x_r = λ^2 - x_p - x_q - let x_r = lambda.square() - x_p - x_q; - // y_r = λ(x_p - x_r) - y_p - let y_r = lambda * (x_p - x_r) - y_p; - (x_r, y_r) - } - } - }); - - // Assign x_r - let x_r = r.map(|r| r.0); - let x_r_cell = region.assign_advice(|| "x_r", self.x_qr, offset + 1, || x_r)?; - - // Assign y_r - let y_r = r.map(|r| r.1); - let y_r_cell = region.assign_advice(|| "y_r", self.y_qr, offset + 1, || y_r)?; - - let result = EccPoint { - x: x_r_cell, - y: y_r_cell, - }; - - #[cfg(test)] - // Check that the correct sum is obtained. - { - use group::Curve; - - let p = p.point(); - let q = q.point(); - let real_sum = p.zip(q).map(|(p, q)| p + q); - let result = result.point(); - - real_sum - .zip(result) - .assert_if_known(|(real_sum, result)| &real_sum.to_affine() == result); - } - - Ok(result) - } -} - -#[cfg(test)] -pub mod tests { - use group::{prime::PrimeCurveAffine, Curve}; - use halo2_proofs::{ - circuit::{Layouter, Value}, - plonk::Error, - }; - use halo2curves::{pasta::pallas, CurveExt}; - - use crate::ecc::{chip::EccPoint, EccInstructions, NonIdentityPoint}; - - #[allow(clippy::too_many_arguments)] - pub fn test_add< - EccChip: EccInstructions + Clone + Eq + std::fmt::Debug, - >( - chip: EccChip, - mut layouter: impl Layouter, - p_val: pallas::Affine, - p: &NonIdentityPoint, - q_val: pallas::Affine, - q: &NonIdentityPoint, - p_neg: &NonIdentityPoint, - ) -> Result<(), Error> { - // Make sure P and Q are not the same point. - assert_ne!(p_val, q_val); - - // Check complete addition P + (-P) - let zero = { - let result = p.add(layouter.namespace(|| "P + (-P)"), p_neg)?; - result - .inner() - .is_identity() - .assert_if_known(|is_identity| *is_identity); - result - }; - - // Check complete addition 𝒪 + 𝒪 - { - let result = zero.add(layouter.namespace(|| "𝒪 + 𝒪"), &zero)?; - result.constrain_equal(layouter.namespace(|| "𝒪 + 𝒪 = 𝒪"), &zero)?; - } - - // Check P + Q - { - let result = p.add(layouter.namespace(|| "P + Q"), q)?; - let witnessed_result = NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "witnessed P + Q"), - Value::known((p_val + q_val).to_affine()), - )?; - result.constrain_equal(layouter.namespace(|| "constrain P + Q"), &witnessed_result)?; - } - - // P + P - { - let result = p.add(layouter.namespace(|| "P + P"), p)?; - let witnessed_result = NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "witnessed P + P"), - Value::known((p_val + p_val).to_affine()), - )?; - result.constrain_equal(layouter.namespace(|| "constrain P + P"), &witnessed_result)?; - } - - // P + 𝒪 - { - let result = p.add(layouter.namespace(|| "P + 𝒪"), &zero)?; - result.constrain_equal(layouter.namespace(|| "P + 𝒪 = P"), p)?; - } - - // 𝒪 + P - { - let result = zero.add(layouter.namespace(|| "𝒪 + P"), p)?; - result.constrain_equal(layouter.namespace(|| "𝒪 + P = P"), p)?; - } - - // (x, y) + (ζx, y) should behave like normal P + Q. - let endo_p = p_val.to_curve().endo(); - let endo_p = NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "endo(P)"), - Value::known(endo_p.to_affine()), - )?; - p.add(layouter.namespace(|| "P + endo(P)"), &endo_p)?; - - // (x, y) + (ζx, -y) should also behave like normal P + Q. - let endo_p_neg = (-p_val).to_curve().endo(); - let endo_p_neg = NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "endo(-P)"), - Value::known(endo_p_neg.to_affine()), - )?; - p.add(layouter.namespace(|| "P + endo(-P)"), &endo_p_neg)?; - - // (x, y) + ((ζ^2)x, y) - let endo_2_p = p_val.to_curve().endo().endo(); - let endo_2_p = NonIdentityPoint::new( - chip.clone(), - layouter.namespace(|| "endo^2(P)"), - Value::known(endo_2_p.to_affine()), - )?; - p.add(layouter.namespace(|| "P + endo^2(P)"), &endo_2_p)?; - - // (x, y) + ((ζ^2)x, -y) - let endo_2_p_neg = (-p_val).to_curve().endo().endo(); - let endo_2_p_neg = NonIdentityPoint::new( - chip, - layouter.namespace(|| "endo^2(-P)"), - Value::known(endo_2_p_neg.to_affine()), - )?; - p.add(layouter.namespace(|| "P + endo^2(-P)"), &endo_2_p_neg)?; - - Ok(()) - } -} diff --git a/halo2_gadgets/src/ecc/chip/add_incomplete.rs b/halo2_gadgets/src/ecc/chip/add_incomplete.rs deleted file mode 100644 index a28391c9e1..0000000000 --- a/halo2_gadgets/src/ecc/chip/add_incomplete.rs +++ /dev/null @@ -1,195 +0,0 @@ -use std::collections::HashSet; - -use super::NonIdentityEccPoint; -use halo2_proofs::{ - circuit::Region, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Selector}, - poly::Rotation, -}; -use halo2curves::pasta::pallas; - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct Config { - q_add_incomplete: Selector, - // x-coordinate of P in P + Q = R - pub x_p: Column, - // y-coordinate of P in P + Q = R - pub y_p: Column, - // x-coordinate of Q or R in P + Q = R - pub x_qr: Column, - // y-coordinate of Q or R in P + Q = R - pub y_qr: Column, -} - -impl Config { - pub(super) fn configure( - meta: &mut ConstraintSystem, - x_p: Column, - y_p: Column, - x_qr: Column, - y_qr: Column, - ) -> Self { - meta.enable_equality(x_p); - meta.enable_equality(y_p); - meta.enable_equality(x_qr); - meta.enable_equality(y_qr); - - let config = Self { - q_add_incomplete: meta.selector(), - x_p, - y_p, - x_qr, - y_qr, - }; - - config.create_gate(meta); - - config - } - - pub(crate) fn advice_columns(&self) -> HashSet> { - [self.x_p, self.y_p, self.x_qr, self.y_qr] - .into_iter() - .collect() - } - - fn create_gate(&self, meta: &mut ConstraintSystem) { - // https://p.z.cash/halo2-0.1:ecc-incomplete-addition - meta.create_gate("incomplete addition", |meta| { - let q_add_incomplete = meta.query_selector(self.q_add_incomplete); - let x_p = meta.query_advice(self.x_p, Rotation::cur()); - let y_p = meta.query_advice(self.y_p, Rotation::cur()); - let x_q = meta.query_advice(self.x_qr, Rotation::cur()); - let y_q = meta.query_advice(self.y_qr, Rotation::cur()); - let x_r = meta.query_advice(self.x_qr, Rotation::next()); - let y_r = meta.query_advice(self.y_qr, Rotation::next()); - - // (x_r + x_q + x_p)⋅(x_p − x_q)^2 − (y_p − y_q)^2 = 0 - let poly1 = { - (x_r.clone() + x_q.clone() + x_p.clone()) - * (x_p.clone() - x_q.clone()) - * (x_p.clone() - x_q.clone()) - - (y_p.clone() - y_q.clone()).square() - }; - - // (y_r + y_q)(x_p − x_q) − (y_p − y_q)(x_q − x_r) = 0 - let poly2 = (y_r + y_q.clone()) * (x_p - x_q.clone()) - (y_p - y_q) * (x_q - x_r); - - Constraints::with_selector(q_add_incomplete, [("x_r", poly1), ("y_r", poly2)]) - }); - } - - pub(super) fn assign_region( - &self, - p: &NonIdentityEccPoint, - q: &NonIdentityEccPoint, - offset: usize, - region: &mut Region<'_, pallas::Base>, - ) -> Result { - // Enable `q_add_incomplete` selector - self.q_add_incomplete.enable(region, offset)?; - - // Handle exceptional cases - let (x_p, y_p) = (p.x.value(), p.y.value()); - let (x_q, y_q) = (q.x.value(), q.y.value()); - x_p.zip(y_p) - .zip(x_q) - .zip(y_q) - .error_if_known_and(|(((x_p, y_p), x_q), y_q)| { - // P is point at infinity - (x_p.is_zero_vartime() && y_p.is_zero_vartime()) - // Q is point at infinity - || (x_q.is_zero_vartime() && y_q.is_zero_vartime()) - // x_p = x_q - || (x_p == x_q) - })?; - - // Copy point `p` into `x_p`, `y_p` columns - p.x.copy_advice(|| "x_p", region, self.x_p, offset)?; - p.y.copy_advice(|| "y_p", region, self.y_p, offset)?; - - // Copy point `q` into `x_qr`, `y_qr` columns - q.x.copy_advice(|| "x_q", region, self.x_qr, offset)?; - q.y.copy_advice(|| "y_q", region, self.y_qr, offset)?; - - // Compute the sum `P + Q = R` - let r = x_p - .zip(y_p) - .zip(x_q) - .zip(y_q) - .map(|(((x_p, y_p), x_q), y_q)| { - { - // λ = (y_q - y_p)/(x_q - x_p) - let lambda = (y_q - y_p) * (x_q - x_p).invert(); - // x_r = λ^2 - x_p - x_q - let x_r = lambda.square() - x_p - x_q; - // y_r = λ(x_p - x_r) - y_p - let y_r = lambda * (x_p - x_r) - y_p; - (x_r, y_r) - } - }); - - // Assign the sum to `x_qr`, `y_qr` columns in the next row - let x_r = r.map(|r| r.0); - let x_r_var = region.assign_advice(|| "x_r", self.x_qr, offset + 1, || x_r)?; - - let y_r = r.map(|r| r.1); - let y_r_var = region.assign_advice(|| "y_r", self.y_qr, offset + 1, || y_r)?; - - let result = NonIdentityEccPoint { - x: x_r_var, - y: y_r_var, - }; - - Ok(result) - } -} - -#[cfg(test)] -pub mod tests { - use group::Curve; - use halo2_proofs::{ - circuit::{Layouter, Value}, - plonk::Error, - }; - use halo2curves::pasta::pallas; - - use crate::ecc::{EccInstructions, NonIdentityPoint}; - - #[allow(clippy::too_many_arguments)] - pub fn test_add_incomplete< - EccChip: EccInstructions + Clone + Eq + std::fmt::Debug, - >( - chip: EccChip, - mut layouter: impl Layouter, - p_val: pallas::Affine, - p: &NonIdentityPoint, - q_val: pallas::Affine, - q: &NonIdentityPoint, - p_neg: &NonIdentityPoint, - test_errors: bool, - ) -> Result<(), Error> { - // P + Q - { - let result = p.add_incomplete(layouter.namespace(|| "P + Q"), q)?; - let witnessed_result = NonIdentityPoint::new( - chip, - layouter.namespace(|| "witnessed P + Q"), - Value::known((p_val + q_val).to_affine()), - )?; - result.constrain_equal(layouter.namespace(|| "constrain P + Q"), &witnessed_result)?; - } - - if test_errors { - // P + P should return an error - p.add_incomplete(layouter.namespace(|| "P + P"), p) - .expect_err("P + P should return an error"); - - // P + (-P) should return an error - p.add_incomplete(layouter.namespace(|| "P + (-P)"), p_neg) - .expect_err("P + (-P) should return an error"); - } - - Ok(()) - } -} diff --git a/halo2_gadgets/src/ecc/chip/constants.rs b/halo2_gadgets/src/ecc/chip/constants.rs deleted file mode 100644 index cecbbae99a..0000000000 --- a/halo2_gadgets/src/ecc/chip/constants.rs +++ /dev/null @@ -1,276 +0,0 @@ -//! Constants required for the ECC chip. - -use arrayvec::ArrayVec; -use group::{ - ff::{Field, PrimeField}, - Curve, -}; -use halo2_proofs::arithmetic::lagrange_interpolate; -use halo2curves::{pasta::pallas, CurveAffine, FieldExt}; - -/// Window size for fixed-base scalar multiplication -pub const FIXED_BASE_WINDOW_SIZE: usize = 3; - -/// $2^{`FIXED_BASE_WINDOW_SIZE`}$ -pub const H: usize = 1 << FIXED_BASE_WINDOW_SIZE; - -/// Number of windows for a full-width scalar -pub const NUM_WINDOWS: usize = - (pallas::Scalar::NUM_BITS as usize + FIXED_BASE_WINDOW_SIZE - 1) / FIXED_BASE_WINDOW_SIZE; - -/// Number of windows for a short signed scalar -pub const NUM_WINDOWS_SHORT: usize = - (L_SCALAR_SHORT + FIXED_BASE_WINDOW_SIZE - 1) / FIXED_BASE_WINDOW_SIZE; - -/// $\ell_\mathsf{value}$ -/// Number of bits in an unsigned short scalar. -pub(crate) const L_SCALAR_SHORT: usize = 64; - -/// The Pallas scalar field modulus is $q = 2^{254} + \mathsf{t_q}$. -/// -pub(crate) const T_Q: u128 = 45560315531506369815346746415080538113; - -/// The Pallas base field modulus is $p = 2^{254} + \mathsf{t_p}$. -/// -pub(crate) const T_P: u128 = 45560315531419706090280762371685220353; - -/// For each fixed base, we calculate its scalar multiples in three-bit windows. -/// Each window will have $2^3 = 8$ points. The tables are computed as described in -/// [the Halo 2 book](https://zcash.github.io/halo2/design/gadgets/ecc/fixed-base-scalar-mul.html#load-fixed-base). -fn compute_window_table(base: C, num_windows: usize) -> Vec<[C; H]> { - let mut window_table: Vec<[C; H]> = Vec::with_capacity(num_windows); - - // Generate window table entries for all windows but the last. - // For these first `num_windows - 1` windows, we compute the multiple [(k+2)*(2^3)^w]B. - // Here, w ranges from [0..`num_windows - 1`) - for w in 0..(num_windows - 1) { - window_table.push( - (0..H) - .map(|k| { - // scalar = (k+2)*(8^w) - let scalar = C::Scalar::from(k as u64 + 2) - * C::Scalar::from(H as u64).pow(&[w as u64, 0, 0, 0]); - (base * scalar).to_affine() - }) - .collect::>() - .into_inner() - .unwrap(), - ); - } - - // Generate window table entries for the last window, w = `num_windows - 1`. - // For the last window, we compute [k * (2^3)^w - sum]B, where sum is defined - // as sum = \sum_{j = 0}^{`num_windows - 2`} 2^{3j+1} - let sum = (0..(num_windows - 1)).fold(C::Scalar::zero(), |acc, j| { - acc + C::Scalar::from(2).pow(&[FIXED_BASE_WINDOW_SIZE as u64 * j as u64 + 1, 0, 0, 0]) - }); - window_table.push( - (0..H) - .map(|k| { - // scalar = k * (2^3)^w - sum, where w = `num_windows - 1` - let scalar = C::Scalar::from(k as u64) - * C::Scalar::from(H as u64).pow(&[(num_windows - 1) as u64, 0, 0, 0]) - - sum; - (base * scalar).to_affine() - }) - .collect::>() - .into_inner() - .unwrap(), - ); - - window_table -} - -/// For each window, we interpolate the $x$-coordinate. -/// Here, we pre-compute and store the coefficients of the interpolation polynomial. -pub fn compute_lagrange_coeffs(base: C, num_windows: usize) -> Vec<[C::Base; H]> { - // We are interpolating over the 3-bit window, k \in [0..8) - let points: Vec<_> = (0..H).map(|i| C::Base::from(i as u64)).collect(); - - let window_table = compute_window_table(base, num_windows); - - window_table - .iter() - .map(|window_points| { - let x_window_points: Vec<_> = window_points - .iter() - .map(|point| *point.coordinates().unwrap().x()) - .collect(); - lagrange_interpolate(&points, &x_window_points) - .into_iter() - .collect::>() - .into_inner() - .unwrap() - }) - .collect() -} - -/// For each window, $z$ is a field element such that for each point $(x, y)$ in the window: -/// - $z + y = u^2$ (some square in the field); and -/// - $z - y$ is not a square. -/// If successful, return a vector of `(z: u64, us: [C::Base; H])` for each window. -/// -/// This function was used to generate the `z`s and `u`s for the Orchard fixed -/// bases. The outputs of this function have been stored as constants, and it -/// is not called anywhere in this codebase. However, we keep this function here -/// as a utility for those who wish to use it with different parameters. -pub fn find_zs_and_us( - base: C, - num_windows: usize, -) -> Option> { - // Closure to find z and u's for one window - let find_z_and_us = |window_points: &[C]| { - assert_eq!(H, window_points.len()); - - let ys: Vec<_> = window_points - .iter() - .map(|point| *point.coordinates().unwrap().y()) - .collect(); - (0..(1000 * (1 << (2 * H)))).find_map(|z| { - ys.iter() - .map(|&y| { - if (-y + C::Base::from(z)).sqrt().is_none().into() { - (y + C::Base::from(z)).sqrt().into() - } else { - None - } - }) - .collect::>>() - .map(|us| (z, us.into_inner().unwrap())) - }) - }; - - let window_table = compute_window_table(base, num_windows); - window_table - .iter() - .map(|window_points| find_z_and_us(window_points)) - .collect() -} - -/// Test that the z-values and u-values satisfy the conditions: -/// 1. z + y = u^2, -/// 2. z - y is not a square -/// for the y-coordinate of each fixed-base multiple in each window. -#[cfg(any(test, feature = "test-dependencies"))] -#[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] -pub fn test_zs_and_us(base: C, z: &[u64], u: &[[[u8; 32]; H]], num_windows: usize) { - let window_table = compute_window_table(base, num_windows); - - for ((u, z), window_points) in u.iter().zip(z.iter()).zip(window_table) { - for (u, point) in u.iter().zip(window_points.iter()) { - let y = *point.coordinates().unwrap().y(); - let mut u_repr = ::Repr::default(); - u_repr.as_mut().copy_from_slice(u); - let u = C::Base::from_repr(u_repr).unwrap(); - assert_eq!(C::Base::from(*z) + y, u * u); // allow either square root - assert!(bool::from((C::Base::from(*z) - y).sqrt().is_none())); - } - } -} - -/// Test that Lagrange interpolation coefficients reproduce the correct x-coordinate -/// for each fixed-base multiple in each window. -#[cfg(any(test, feature = "test-dependencies"))] -#[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] -pub fn test_lagrange_coeffs(base: C, num_windows: usize) { - /// Evaluate y = f(x) given the coefficients of f(x) - fn evaluate(x: u8, coeffs: &[C::Base]) -> C::Base { - let x = C::Base::from(x as u64); - coeffs - .iter() - .rev() - .cloned() - .reduce(|acc, coeff| acc * x + coeff) - .unwrap_or_else(C::Base::zero) - } - - let lagrange_coeffs = compute_lagrange_coeffs(base, num_windows); - - // Check first 84 windows, i.e. `k_0, k_1, ..., k_83` - for (idx, coeffs) in lagrange_coeffs[0..(num_windows - 1)].iter().enumerate() { - // Test each three-bit chunk in this window. - for bits in 0..(H as u8) { - { - // Interpolate the x-coordinate using this window's coefficients - let interpolated_x = evaluate::(bits, coeffs); - - // Compute the actual x-coordinate of the multiple [(k+2)*(8^w)]B. - let point = base - * C::Scalar::from(bits as u64 + 2) - * C::Scalar::from(H as u64).pow(&[idx as u64, 0, 0, 0]); - let x = *point.to_affine().coordinates().unwrap().x(); - - // Check that the interpolated x-coordinate matches the actual one. - assert_eq!(x, interpolated_x); - } - } - } - - // Check last window. - for bits in 0..(H as u8) { - // Interpolate the x-coordinate using the last window's coefficients - let interpolated_x = evaluate::(bits, &lagrange_coeffs[num_windows - 1]); - - // Compute the actual x-coordinate of the multiple [k * (8^84) - offset]B, - // where offset = \sum_{j = 0}^{83} 2^{3j+1} - let offset = (0..(num_windows - 1)).fold(C::Scalar::zero(), |acc, w| { - acc + C::Scalar::from(2).pow(&[FIXED_BASE_WINDOW_SIZE as u64 * w as u64 + 1, 0, 0, 0]) - }); - let scalar = C::Scalar::from(bits as u64) - * C::Scalar::from(H as u64).pow(&[(num_windows - 1) as u64, 0, 0, 0]) - - offset; - let point = base * scalar; - let x = *point.to_affine().coordinates().unwrap().x(); - - // Check that the interpolated x-coordinate matches the actual one. - assert_eq!(x, interpolated_x); - } -} - -#[cfg(test)] -mod tests { - use group::{ff::Field, Curve, Group}; - use halo2curves::{pasta::pallas, CurveAffine, FieldExt}; - use proptest::prelude::*; - - use super::{compute_window_table, find_zs_and_us, test_lagrange_coeffs, H, NUM_WINDOWS}; - - prop_compose! { - /// Generate an arbitrary Pallas point. - pub fn arb_point()(bytes in prop::array::uniform32(0u8..)) -> pallas::Point { - // Instead of rejecting out-of-range bytes, let's reduce them. - let mut buf = [0; 64]; - buf[..32].copy_from_slice(&bytes); - let scalar = pallas::Scalar::from_bytes_wide(&buf); - pallas::Point::generator() * scalar - } - } - - proptest! { - #[test] - fn lagrange_coeffs( - base in arb_point(), - ) { - test_lagrange_coeffs(base.to_affine(), NUM_WINDOWS); - } - } - - #[test] - fn zs_and_us() { - let base = pallas::Point::random(rand::rngs::OsRng); - let (z, u): (Vec, Vec<[pallas::Base; H]>) = - find_zs_and_us(base.to_affine(), NUM_WINDOWS) - .unwrap() - .into_iter() - .unzip(); - let window_table = compute_window_table(base.to_affine(), NUM_WINDOWS); - - for ((u, z), window_points) in u.iter().zip(z.iter()).zip(window_table) { - for (u, point) in u.iter().zip(window_points.iter()) { - let y = *point.coordinates().unwrap().y(); - assert_eq!(pallas::Base::from(*z) + y, u * u); // allow either square root - assert!(bool::from((pallas::Base::from(*z) - y).sqrt().is_none())); - } - } - } -} diff --git a/halo2_gadgets/src/ecc/chip/mul.rs b/halo2_gadgets/src/ecc/chip/mul.rs deleted file mode 100644 index 26c705a17c..0000000000 --- a/halo2_gadgets/src/ecc/chip/mul.rs +++ /dev/null @@ -1,587 +0,0 @@ -use super::{add, EccPoint, NonIdentityEccPoint, ScalarVar, T_Q}; -use crate::{ - sinsemilla::primitives as sinsemilla, - utilities::{bool_check, lookup_range_check::LookupRangeCheckConfig, ternary}, -}; -use std::{ - convert::TryInto, - ops::{Deref, Range}, -}; - -use ff::PrimeField; -use halo2_proofs::{ - arithmetic::FieldExt, - circuit::{AssignedCell, Layouter, Region, Value}, - plonk::{Advice, Assigned, Column, ConstraintSystem, Constraints, Error, Selector}, - poly::Rotation, -}; -use uint::construct_uint; - -use halo2curves::pasta::pallas; - -mod complete; -pub(super) mod incomplete; -mod overflow; - -/// Number of bits for which complete addition needs to be used in variable-base -/// scalar multiplication -const NUM_COMPLETE_BITS: usize = 3; - -// Bits used in incomplete addition. k_{254} to k_{4} inclusive -const INCOMPLETE_LEN: usize = pallas::Scalar::NUM_BITS as usize - 1 - NUM_COMPLETE_BITS; -const INCOMPLETE_RANGE: Range = 0..INCOMPLETE_LEN; - -// Bits k_{254} to k_{4} inclusive are used in incomplete addition. -// The `hi` half is k_{254} to k_{130} inclusive (length 125 bits). -// (It is a coincidence that k_{130} matches the boundary of the -// overflow check described in [the book](https://zcash.github.io/halo2/design/gadgets/ecc/var-base-scalar-mul.html#overflow-check).) -const INCOMPLETE_HI_RANGE: Range = 0..INCOMPLETE_HI_LEN; -const INCOMPLETE_HI_LEN: usize = INCOMPLETE_LEN / 2; - -// Bits k_{254} to k_{4} inclusive are used in incomplete addition. -// The `lo` half is k_{129} to k_{4} inclusive (length 126 bits). -const INCOMPLETE_LO_RANGE: Range = INCOMPLETE_HI_LEN..INCOMPLETE_LEN; -const INCOMPLETE_LO_LEN: usize = INCOMPLETE_LEN - INCOMPLETE_HI_LEN; - -// Bits k_{3} to k_{1} inclusive are used in complete addition. -// Bit k_{0} is handled separately. -const COMPLETE_RANGE: Range = INCOMPLETE_LEN..(INCOMPLETE_LEN + NUM_COMPLETE_BITS); - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { - // Selector used to check switching logic on LSB - q_mul_lsb: Selector, - // Configuration used in complete addition - add_config: add::Config, - // Configuration used for `hi` bits of the scalar - hi_config: incomplete::Config, - // Configuration used for `lo` bits of the scalar - lo_config: incomplete::Config, - // Configuration used for complete addition part of double-and-add algorithm - complete_config: complete::Config, - // Configuration used to check for overflow - overflow_config: overflow::Config, -} - -impl Config { - pub(super) fn configure( - meta: &mut ConstraintSystem, - add_config: add::Config, - lookup_config: LookupRangeCheckConfig, - advices: [Column; 10], - ) -> Self { - let hi_config = incomplete::Config::configure( - meta, advices[9], advices[3], advices[0], advices[1], advices[4], advices[5], - ); - let lo_config = incomplete::Config::configure( - meta, advices[6], advices[7], advices[0], advices[1], advices[8], advices[2], - ); - let complete_config = complete::Config::configure(meta, advices[9], add_config); - let overflow_config = - overflow::Config::configure(meta, lookup_config, advices[6..9].try_into().unwrap()); - - let config = Self { - q_mul_lsb: meta.selector(), - add_config, - hi_config, - lo_config, - complete_config, - overflow_config, - }; - - config.create_gate(meta); - - assert_eq!( - config.hi_config.double_and_add.x_p, config.lo_config.double_and_add.x_p, - "x_p is shared across hi and lo halves." - ); - assert_eq!( - config.hi_config.y_p, config.lo_config.y_p, - "y_p is shared across hi and lo halves." - ); - - // For both hi_config and lo_config: - // z and lambda1 are assigned on the same row as the add_config output. - // Therefore, z and lambda1 must not overlap with add_config.x_qr, add_config.y_qr. - let add_config_outputs = config.add_config.output_columns(); - { - assert!( - !add_config_outputs.contains(&config.hi_config.z), - "incomplete config z cannot overlap with complete addition columns." - ); - assert!( - !add_config_outputs.contains(&config.hi_config.double_and_add.lambda_1), - "incomplete config lambda1 cannot overlap with complete addition columns." - ); - } - { - assert!( - !add_config_outputs.contains(&config.lo_config.z), - "incomplete config z cannot overlap with complete addition columns." - ); - assert!( - !add_config_outputs.contains(&config.lo_config.double_and_add.lambda_1), - "incomplete config lambda1 cannot overlap with complete addition columns." - ); - } - - config - } - - fn create_gate(&self, meta: &mut ConstraintSystem) { - // If `lsb` is 0, (x, y) = (x_p, -y_p). If `lsb` is 1, (x, y) = (0,0). - // https://p.z.cash/halo2-0.1:ecc-var-mul-lsb-gate?partial - meta.create_gate("LSB check", |meta| { - let q_mul_lsb = meta.query_selector(self.q_mul_lsb); - - let z_1 = meta.query_advice(self.complete_config.z_complete, Rotation::cur()); - let z_0 = meta.query_advice(self.complete_config.z_complete, Rotation::next()); - let x_p = meta.query_advice(self.add_config.x_p, Rotation::cur()); - let y_p = meta.query_advice(self.add_config.y_p, Rotation::cur()); - let base_x = meta.query_advice(self.add_config.x_p, Rotation::next()); - let base_y = meta.query_advice(self.add_config.y_p, Rotation::next()); - - // z_0 = 2 * z_1 + k_0 - // => k_0 = z_0 - 2 * z_1 - let lsb = z_0 - z_1 * pallas::Base::from(2); - - let bool_check = bool_check(lsb.clone()); - - // `lsb` = 0 => (x_p, y_p) = (x, -y) - // `lsb` = 1 => (x_p, y_p) = (0,0) - let lsb_x = ternary(lsb.clone(), x_p.clone(), x_p - base_x); - let lsb_y = ternary(lsb, y_p.clone(), y_p + base_y); - - Constraints::with_selector( - q_mul_lsb, - [ - ("bool_check", bool_check), - ("lsb_x", lsb_x), - ("lsb_y", lsb_y), - ], - ) - }); - } - - pub(super) fn assign( - &self, - mut layouter: impl Layouter, - alpha: AssignedCell, - base: &NonIdentityEccPoint, - ) -> Result<(EccPoint, ScalarVar), Error> { - let (result, zs): (EccPoint, Vec>) = layouter.assign_region( - || "variable-base scalar mul", - |mut region| { - let offset = 0; - - // Case `base` into an `EccPoint` for later use. - let base_point: EccPoint = base.clone().into(); - - // Decompose `k = alpha + t_q` bitwise (big-endian bit order). - let bits = decompose_for_scalar_mul(alpha.value()); - - // Define ranges for each part of the algorithm. - let bits_incomplete_hi = &bits[INCOMPLETE_HI_RANGE]; - let bits_incomplete_lo = &bits[INCOMPLETE_LO_RANGE]; - let lsb = bits[pallas::Scalar::NUM_BITS as usize - 1]; - - // Initialize the accumulator `acc = [2]base` using complete addition. - let acc = - self.add_config - .assign_region(&base_point, &base_point, offset, &mut region)?; - - // Increase the offset by 1 after complete addition. - let offset = offset + 1; - - // Initialize the running sum for scalar decomposition to zero. - // - // `incomplete::Config::double_and_add` will copy this cell directly into - // itself. This is fine because we are just assigning the same value to - // the same cell twice, and then applying an equality constraint between - // the cell and itself (which the permutation argument treats as a no-op). - let z_init = Z(region.assign_advice_from_constant( - || "z_init = 0", - self.hi_config.z, - offset, - pallas::Base::zero(), - )?); - - // Double-and-add (incomplete addition) for the `hi` half of the scalar decomposition - let (x_a, y_a, zs_incomplete_hi) = self.hi_config.double_and_add( - &mut region, - offset, - base, - bits_incomplete_hi, - (X(acc.x), Y(acc.y), z_init.clone()), - )?; - - // Double-and-add (incomplete addition) for the `lo` half of the scalar decomposition - let z = zs_incomplete_hi.last().expect("should not be empty"); - let (x_a, y_a, zs_incomplete_lo) = self.lo_config.double_and_add( - &mut region, - offset, - base, - bits_incomplete_lo, - (x_a, y_a, z.clone()), - )?; - - // Move from incomplete addition to complete addition. - // Inside incomplete::double_and_add, the offset was increased once after initialization - // of the running sum. - // Then, the final assignment of double-and-add was made on row + offset + 1. - // Outside of incomplete addition, we must account for these offset increases by adding - // 2 to the incomplete addition length. - assert!(INCOMPLETE_LO_RANGE.len() >= INCOMPLETE_HI_RANGE.len()); - let offset = offset + INCOMPLETE_LO_RANGE.len() + 2; - - // Complete addition - let (acc, zs_complete) = { - let z = zs_incomplete_lo.last().expect("should not be empty"); - // Bits used in complete addition. k_{3} to k_{1} inclusive - // The LSB k_{0} is handled separately. - let bits_complete = &bits[COMPLETE_RANGE]; - self.complete_config.assign_region( - &mut region, - offset, - bits_complete, - &base_point, - x_a, - y_a, - z.clone(), - )? - }; - - // Each iteration of the complete addition uses two rows. - let offset = offset + COMPLETE_RANGE.len() * 2; - - // Process the least significant bit - let z_1 = zs_complete.last().unwrap().clone(); - let (result, z_0) = self.process_lsb(&mut region, offset, base, acc, z_1, lsb)?; - - #[cfg(test)] - // Check that the correct multiple is obtained. - { - use group::Curve; - - let base = base.point(); - let alpha = alpha - .value() - .map(|alpha| pallas::Scalar::from_repr(alpha.to_repr()).unwrap()); - let real_mul = base.zip(alpha).map(|(base, alpha)| base * alpha); - let result = result.point(); - - real_mul - .zip(result) - .assert_if_known(|(real_mul, result)| &real_mul.to_affine() == result); - } - - let zs = { - let mut zs = std::iter::empty() - .chain(Some(z_init)) - .chain(zs_incomplete_hi.into_iter()) - .chain(zs_incomplete_lo.into_iter()) - .chain(zs_complete.into_iter()) - .chain(Some(z_0)) - .collect::>(); - assert_eq!(zs.len(), pallas::Scalar::NUM_BITS as usize + 1); - - // This reverses zs to give us [z_0, z_1, ..., z_{254}, z_{255}]. - zs.reverse(); - zs - }; - - Ok((result, zs)) - }, - )?; - - self.overflow_config.overflow_check( - layouter.namespace(|| "overflow check"), - alpha.clone(), - &zs, - )?; - - Ok((result, ScalarVar::BaseFieldElem(alpha))) - } - - /// Processes the final scalar bit `k_0`. - /// - /// Assumptions for this sub-region: - /// - `acc_x` and `acc_y` are assigned in row `offset` by the previous complete - /// addition. They will be copied into themselves. - /// - `z_1 is assigned in row `offset` by the mul::complete region assignment. We only - /// use its value here. - /// - /// `x_p` and `y_p` are assigned here, and then copied into themselves by the complete - /// addition subregion. - /// - /// ```text - /// | x_p | y_p | acc_x | acc_y | complete addition | z_1 | q_mul_lsb = 1 - /// |base_x|base_y| res_x | res_y | | | | | | z_0 | - /// ``` - /// - /// [Specification](https://p.z.cash/halo2-0.1:ecc-var-mul-lsb-gate?partial). - fn process_lsb( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - base: &NonIdentityEccPoint, - acc: EccPoint, - z_1: Z, - lsb: Value, - ) -> Result<(EccPoint, Z), Error> { - // Enforce switching logic on LSB using a custom gate - self.q_mul_lsb.enable(region, offset)?; - - // z_1 has been assigned at (z_complete, offset). - // Assign z_0 = 2⋅z_1 + k_0 - let z_0 = { - let z_0_val = z_1.value().zip(lsb).map(|(z_1, lsb)| { - let lsb = pallas::Base::from(lsb as u64); - z_1 * pallas::Base::from(2) + lsb - }); - let z_0_cell = region.assign_advice( - || "z_0", - self.complete_config.z_complete, - offset + 1, - || z_0_val, - )?; - - Z(z_0_cell) - }; - - // Copy in `base_x`, `base_y` to use in the LSB gate - base.x() - .copy_advice(|| "copy base_x", region, self.add_config.x_p, offset + 1)?; - base.y() - .copy_advice(|| "copy base_y", region, self.add_config.y_p, offset + 1)?; - - // If `lsb` is 0, return `Acc + (-P)`. If `lsb` is 1, simply return `Acc + 0`. - let x = lsb.and_then(|lsb| { - if !lsb { - base.x.value().cloned() - } else { - Value::known(Assigned::Zero) - } - }); - - let y = lsb.and_then(|lsb| { - if !lsb { - -base.y.value() - } else { - Value::known(Assigned::Zero) - } - }); - - let x_cell = region.assign_advice(|| "x", self.add_config.x_p, offset, || x)?; - let y_cell = region.assign_advice(|| "y", self.add_config.y_p, offset, || y)?; - - let p = EccPoint { - x: x_cell, - y: y_cell, - }; - - // Return the result of the final complete addition as `[scalar]B` - let result = self.add_config.assign_region(&p, &acc, offset, region)?; - - Ok((result, z_0)) - } -} - -#[derive(Clone, Debug)] -// `x`-coordinate of the accumulator. -struct X(AssignedCell, F>); -impl Deref for X { - type Target = AssignedCell, F>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Clone, Debug)] -// `y`-coordinate of the accumulator. -struct Y(AssignedCell, F>); -impl Deref for Y { - type Target = AssignedCell, F>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Clone, Debug)] -// Cumulative sum `z` used to decompose the scalar. -struct Z(AssignedCell); -impl Deref for Z { - type Target = AssignedCell; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -// https://p.z.cash/halo2-0.1:ecc-var-mul-witness-scalar?partial -#[allow(clippy::assign_op_pattern)] -#[allow(clippy::ptr_offset_with_cast)] -fn decompose_for_scalar_mul(scalar: Value<&pallas::Base>) -> Vec> { - construct_uint! { - struct U256(4); - } - - let bitstring = scalar.map(|scalar| { - // We use `k = scalar + t_q` in the double-and-add algorithm, where - // the scalar field `F_q = 2^254 + t_q`. - // Note that the addition `scalar + t_q` is not reduced. - // - let scalar = U256::from_little_endian(&scalar.to_repr()); - let t_q = U256::from_little_endian(&T_Q.to_le_bytes()); - let k = scalar + t_q; - - // Little-endian bit representation of `k`. - let bitstring = { - let mut le_bytes = [0u8; 32]; - k.to_little_endian(&mut le_bytes); - le_bytes - .into_iter() - .flat_map(|byte| (0..8).map(move |shift| (byte >> shift) % 2 == 1)) - }; - - // Take the first 255 bits. - bitstring - .take(pallas::Scalar::NUM_BITS as usize) - .collect::>() - }); - - // Transpose. - let mut bitstring = bitstring.transpose_vec(pallas::Scalar::NUM_BITS as usize); - // Reverse to get the big-endian bit representation. - bitstring.reverse(); - bitstring -} - -#[cfg(test)] -pub mod tests { - use group::{ - ff::{Field, PrimeField}, - Curve, - }; - use halo2_proofs::{ - circuit::{Chip, Layouter, Value}, - plonk::Error, - }; - use halo2curves::pasta::pallas; - use rand::rngs::OsRng; - - use crate::{ - ecc::{ - chip::{EccChip, EccPoint}, - tests::TestFixedBases, - EccInstructions, NonIdentityPoint, Point, ScalarVar, - }, - utilities::UtilitiesInstructions, - }; - - pub(crate) fn test_mul( - chip: EccChip, - mut layouter: impl Layouter, - p: &NonIdentityPoint>, - p_val: pallas::Affine, - ) -> Result<(), Error> { - let column = chip.config().advices[0]; - - fn constrain_equal_non_id< - EccChip: EccInstructions + Clone + Eq + std::fmt::Debug, - >( - chip: EccChip, - mut layouter: impl Layouter, - base_val: pallas::Affine, - scalar_val: pallas::Base, - result: Point, - ) -> Result<(), Error> { - // Move scalar from base field into scalar field (which always fits - // for Pallas). - let scalar = pallas::Scalar::from_repr(scalar_val.to_repr()).unwrap(); - let expected = NonIdentityPoint::new( - chip, - layouter.namespace(|| "expected point"), - Value::known((base_val * scalar).to_affine()), - )?; - result.constrain_equal(layouter.namespace(|| "constrain result"), &expected) - } - - // [a]B - { - let scalar_val = pallas::Base::random(OsRng); - let (result, _) = { - let scalar = chip.load_private( - layouter.namespace(|| "random scalar"), - column, - Value::known(scalar_val), - )?; - let scalar = ScalarVar::from_base( - chip.clone(), - layouter.namespace(|| "ScalarVar from_base"), - &scalar, - )?; - p.mul(layouter.namespace(|| "random [a]B"), scalar)? - }; - constrain_equal_non_id( - chip.clone(), - layouter.namespace(|| "random [a]B"), - p_val, - scalar_val, - result, - )?; - } - - // [0]B should return (0,0) since variable-base scalar multiplication - // uses complete addition for the final bits of the scalar. - { - let scalar_val = pallas::Base::zero(); - let (result, _) = { - let scalar = chip.load_private( - layouter.namespace(|| "zero"), - column, - Value::known(scalar_val), - )?; - let scalar = ScalarVar::from_base( - chip.clone(), - layouter.namespace(|| "ScalarVar from_base"), - &scalar, - )?; - p.mul(layouter.namespace(|| "[0]B"), scalar)? - }; - result - .inner() - .is_identity() - .assert_if_known(|is_identity| *is_identity); - } - - // [-1]B (the largest possible base field element) - { - let scalar_val = -pallas::Base::one(); - let (result, _) = { - let scalar = chip.load_private( - layouter.namespace(|| "-1"), - column, - Value::known(scalar_val), - )?; - let scalar = ScalarVar::from_base( - chip.clone(), - layouter.namespace(|| "ScalarVar from_base"), - &scalar, - )?; - p.mul(layouter.namespace(|| "[-1]B"), scalar)? - }; - constrain_equal_non_id( - chip, - layouter.namespace(|| "[-1]B"), - p_val, - scalar_val, - result, - )?; - } - - Ok(()) - } -} diff --git a/halo2_gadgets/src/ecc/chip/mul/complete.rs b/halo2_gadgets/src/ecc/chip/mul/complete.rs deleted file mode 100644 index d23294d2fb..0000000000 --- a/halo2_gadgets/src/ecc/chip/mul/complete.rs +++ /dev/null @@ -1,196 +0,0 @@ -use super::super::{add, EccPoint}; -use super::{COMPLETE_RANGE, X, Y, Z}; -use crate::utilities::{bool_check, ternary}; - -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Expression, Selector}, - poly::Rotation, -}; - -use halo2curves::pasta::pallas; - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { - // Selector used to constrain the cells used in complete addition. - q_mul_decompose_var: Selector, - // Advice column used to decompose scalar in complete addition. - pub z_complete: Column, - // Configuration used in complete addition - add_config: add::Config, -} - -impl Config { - pub(super) fn configure( - meta: &mut ConstraintSystem, - z_complete: Column, - add_config: add::Config, - ) -> Self { - meta.enable_equality(z_complete); - - let config = Self { - q_mul_decompose_var: meta.selector(), - z_complete, - add_config, - }; - - config.create_gate(meta); - - config - } - - /// Gate used to check scalar decomposition is correct. - /// This is used to check the bits used in complete addition, since the incomplete - /// addition gate (controlled by `q_mul`) already checks scalar decomposition for - /// the other bits. - fn create_gate(&self, meta: &mut ConstraintSystem) { - // | y_p | z_complete | - // -------------------- - // | y_p | z_{i + 1} | - // | | base_y | - // | | z_i | - // https://p.z.cash/halo2-0.1:ecc-var-mul-complete-gate - meta.create_gate( - "Decompose scalar for complete bits of variable-base mul", - |meta| { - let q_mul_decompose_var = meta.query_selector(self.q_mul_decompose_var); - // z_{i + 1} - let z_prev = meta.query_advice(self.z_complete, Rotation::prev()); - // z_i - let z_next = meta.query_advice(self.z_complete, Rotation::next()); - - // k_{i} = z_{i} - 2⋅z_{i+1} - let k = z_next - Expression::Constant(pallas::Base::from(2)) * z_prev; - // (k_i) ⋅ (1 - k_i) = 0 - let bool_check = bool_check(k.clone()); - - // base_y - let base_y = meta.query_advice(self.z_complete, Rotation::cur()); - // y_p - let y_p = meta.query_advice(self.add_config.y_p, Rotation::prev()); - - // k_i = 0 => y_p = -base_y - // k_i = 1 => y_p = base_y - let y_switch = ternary(k, base_y.clone() - y_p.clone(), base_y + y_p); - - Constraints::with_selector( - q_mul_decompose_var, - [("bool_check", bool_check), ("y_switch", y_switch)], - ) - }, - ); - } - - #[allow(clippy::type_complexity)] - #[allow(non_snake_case)] - #[allow(clippy::too_many_arguments)] - pub(super) fn assign_region( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - bits: &[Value], - base: &EccPoint, - x_a: X, - y_a: Y, - z: Z, - ) -> Result<(EccPoint, Vec>), Error> { - // Make sure we have the correct number of bits for the complete addition - // part of variable-base scalar mul. - assert_eq!(bits.len(), COMPLETE_RANGE.len()); - - // Enable selectors for complete range - for row in 0..COMPLETE_RANGE.len() { - // Each iteration uses 2 rows (two complete additions) - let row = 2 * row; - // Check scalar decomposition for each iteration. Since the gate enabled by - // `q_mul_decompose_var` queries the previous row, we enable the selector on - // `row + offset + 1` (instead of `row + offset`). - self.q_mul_decompose_var.enable(region, row + offset + 1)?; - } - - // Use x_a, y_a output from incomplete addition - let mut acc = EccPoint { x: x_a.0, y: y_a.0 }; - - // Copy running sum `z` from incomplete addition - let mut z = { - let z = z.copy_advice( - || "Copy `z` running sum from incomplete addition", - region, - self.z_complete, - offset, - )?; - Z(z) - }; - - // Store interstitial running sum `z`s in vector - let mut zs: Vec> = Vec::with_capacity(bits.len()); - - // Complete addition - for (iter, k) in bits.iter().enumerate() { - // Each iteration uses 2 rows (two complete additions) - let row = 2 * iter; - - // | x_p | y_p | x_qr | y_qr | z_complete | - // ------------------------------------------ - // | U_x | U_y | acc_x | acc_y | z_{i + 1} | row + offset - // |acc_x|acc_y|acc+U_x|acc+U_y| base_y | - // | | | res_x | res_y | z_i | - - // Update `z`. - z = { - // z_next = z_cur * 2 + k_next - let z_val = z.value() * Value::known(pallas::Base::from(2)) - + k.map(|k| pallas::Base::from(k as u64)); - let z_cell = - region.assign_advice(|| "z", self.z_complete, row + offset + 2, || z_val)?; - Z(z_cell) - }; - zs.push(z.clone()); - - // Assign `y_p` for complete addition. - let y_p = { - let base_y = base.y.copy_advice( - || "Copy `base.y`", - region, - self.z_complete, - row + offset + 1, - )?; - - // If the bit is set, use `y`; if the bit is not set, use `-y` - let y_p = - base_y - .value() - .cloned() - .zip(k.as_ref()) - .map(|(base_y, k)| if !k { -base_y } else { base_y }); - - // Assign the conditionally-negated y coordinate into the cell it will be - // used from by both the complete addition gate, and the decomposition and - // conditional negation gate. - // - // The complete addition gate will copy this cell onto itself. This is - // fine because we are just assigning the same value to the same cell - // twice, and then applying an equality constraint between the cell and - // itself (which the permutation argument treats as a no-op). - region.assign_advice(|| "y_p", self.add_config.y_p, row + offset, || y_p)? - }; - - // U = P if the bit is set; U = -P is the bit is not set. - let U = EccPoint { - x: base.x.clone(), - y: y_p, - }; - - // Acc + U - let tmp_acc = self - .add_config - .assign_region(&U, &acc, row + offset, region)?; - - // Acc + U + Acc - acc = self - .add_config - .assign_region(&acc, &tmp_acc, row + offset + 1, region)?; - } - Ok((acc, zs)) - } -} diff --git a/halo2_gadgets/src/ecc/chip/mul/incomplete.rs b/halo2_gadgets/src/ecc/chip/mul/incomplete.rs deleted file mode 100644 index bfe51c7e2e..0000000000 --- a/halo2_gadgets/src/ecc/chip/mul/incomplete.rs +++ /dev/null @@ -1,372 +0,0 @@ -use super::super::NonIdentityEccPoint; -use super::{X, Y, Z}; -use crate::utilities::bool_check; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::{ - Advice, Column, ConstraintSystem, Constraints, Error, Expression, Selector, VirtualCells, - }, - poly::Rotation, -}; -use halo2curves::{pasta::pallas, FieldExt}; - -/// A helper struct for implementing single-row double-and-add using incomplete addition. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub(crate) struct DoubleAndAdd { - // x-coordinate of the accumulator in each double-and-add iteration. - pub(crate) x_a: Column, - // x-coordinate of the point being added in each double-and-add iteration. - pub(crate) x_p: Column, - // lambda1 in each double-and-add iteration. - pub(crate) lambda_1: Column, - // lambda2 in each double-and-add iteration. - pub(crate) lambda_2: Column, -} - -impl DoubleAndAdd { - /// Derives the expression `x_r = lambda_1^2 - x_a - x_p`. - pub(crate) fn x_r( - &self, - meta: &mut VirtualCells, - rotation: Rotation, - ) -> Expression { - let x_a = meta.query_advice(self.x_a, rotation); - let x_p = meta.query_advice(self.x_p, rotation); - let lambda_1 = meta.query_advice(self.lambda_1, rotation); - lambda_1.square() - x_a - x_p - } - - /// Derives the expression `Y_A = (lambda_1 + lambda_2) * (x_a - x_r)`. - /// - /// Note that this is missing the factor of `1/2`; the Sinsemilla constraints factor - /// it out, so we leave it up to the caller to handle it. - #[allow(non_snake_case)] - pub(crate) fn Y_A( - &self, - meta: &mut VirtualCells, - rotation: Rotation, - ) -> Expression { - let x_a = meta.query_advice(self.x_a, rotation); - let lambda_1 = meta.query_advice(self.lambda_1, rotation); - let lambda_2 = meta.query_advice(self.lambda_2, rotation); - (lambda_1 + lambda_2) * (x_a - self.x_r(meta, rotation)) - } -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub(crate) struct Config { - // Selector constraining the first row of incomplete addition. - pub(super) q_mul_1: Selector, - // Selector constraining the main loop of incomplete addition. - pub(super) q_mul_2: Selector, - // Selector constraining the last row of incomplete addition. - pub(super) q_mul_3: Selector, - // Cumulative sum used to decompose the scalar. - pub(super) z: Column, - // Logic specific to merged double-and-add. - pub(super) double_and_add: DoubleAndAdd, - // y-coordinate of the point being added in each double-and-add iteration. - pub(super) y_p: Column, -} - -impl Config { - pub(super) fn configure( - meta: &mut ConstraintSystem, - z: Column, - x_a: Column, - x_p: Column, - y_p: Column, - lambda_1: Column, - lambda_2: Column, - ) -> Self { - meta.enable_equality(z); - meta.enable_equality(lambda_1); - - let config = Self { - q_mul_1: meta.selector(), - q_mul_2: meta.selector(), - q_mul_3: meta.selector(), - z, - double_and_add: DoubleAndAdd { - x_a, - x_p, - lambda_1, - lambda_2, - }, - y_p, - }; - - config.create_gate(meta); - - config - } - - // Gate for incomplete addition part of variable-base scalar multiplication. - fn create_gate(&self, meta: &mut ConstraintSystem) { - // Closure to compute x_{R,i} = λ_{1,i}^2 - x_{A,i} - x_{P,i} - let x_r = |meta: &mut VirtualCells, rotation: Rotation| { - self.double_and_add.x_r(meta, rotation) - }; - - // Closure to compute y_{A,i} = (λ_{1,i} + λ_{2,i}) * (x_{A,i} - x_{R,i}) / 2 - let y_a = |meta: &mut VirtualCells, rotation: Rotation| { - self.double_and_add.Y_A(meta, rotation) * pallas::Base::TWO_INV - }; - - // Constraints used for q_mul_{2, 3} == 1 - // https://p.z.cash/halo2-0.1:ecc-var-mul-incomplete-main-loop?partial - // https://p.z.cash/halo2-0.1:ecc-var-mul-incomplete-last-row?partial - let for_loop = |meta: &mut VirtualCells, - y_a_next: Expression| { - let one = Expression::Constant(pallas::Base::one()); - - // z_i - let z_cur = meta.query_advice(self.z, Rotation::cur()); - // z_{i+1} - let z_prev = meta.query_advice(self.z, Rotation::prev()); - // x_{A,i} - let x_a_cur = meta.query_advice(self.double_and_add.x_a, Rotation::cur()); - // x_{A,i-1} - let x_a_next = meta.query_advice(self.double_and_add.x_a, Rotation::next()); - // x_{P,i} - let x_p_cur = meta.query_advice(self.double_and_add.x_p, Rotation::cur()); - // y_{P,i} - let y_p_cur = meta.query_advice(self.y_p, Rotation::cur()); - // λ_{1,i} - let lambda1_cur = meta.query_advice(self.double_and_add.lambda_1, Rotation::cur()); - // λ_{2,i} - let lambda2_cur = meta.query_advice(self.double_and_add.lambda_2, Rotation::cur()); - - let y_a_cur = y_a(meta, Rotation::cur()); - - // The current bit in the scalar decomposition, k_i = z_i - 2⋅z_{i+1}. - // Recall that we assigned the cumulative variable `z_i` in descending order, - // i from n down to 0. So z_{i+1} corresponds to the `z_prev` query. - let k = z_cur - z_prev * pallas::Base::from(2); - // Check booleanity of decomposition. - let bool_check = bool_check(k.clone()); - - // λ_{1,i}⋅(x_{A,i} − x_{P,i}) − y_{A,i} + (2k_i - 1) y_{P,i} = 0 - let gradient_1 = lambda1_cur * (x_a_cur.clone() - x_p_cur) - y_a_cur.clone() - + (k * pallas::Base::from(2) - one) * y_p_cur; - - // λ_{2,i}^2 − x_{A,i-1} − x_{R,i} − x_{A,i} = 0 - let secant_line = lambda2_cur.clone().square() - - x_a_next.clone() - - x_r(meta, Rotation::cur()) - - x_a_cur.clone(); - - // λ_{2,i}⋅(x_{A,i} − x_{A,i-1}) − y_{A,i} − y_{A,i-1} = 0 - let gradient_2 = lambda2_cur * (x_a_cur - x_a_next) - y_a_cur - y_a_next; - - std::iter::empty() - .chain(Some(("bool_check", bool_check))) - .chain(Some(("gradient_1", gradient_1))) - .chain(Some(("secant_line", secant_line))) - .chain(Some(("gradient_2", gradient_2))) - }; - - // q_mul_1 == 1 checks - // https://p.z.cash/halo2-0.1:ecc-var-mul-incomplete-first-row - meta.create_gate("q_mul_1 == 1 checks", |meta| { - let q_mul_1 = meta.query_selector(self.q_mul_1); - - let y_a_next = y_a(meta, Rotation::next()); - let y_a_witnessed = meta.query_advice(self.double_and_add.lambda_1, Rotation::cur()); - Constraints::with_selector(q_mul_1, Some(("init y_a", y_a_witnessed - y_a_next))) - }); - - // q_mul_2 == 1 checks - // https://p.z.cash/halo2-0.1:ecc-var-mul-incomplete-main-loop?partial - meta.create_gate("q_mul_2 == 1 checks", |meta| { - let q_mul_2 = meta.query_selector(self.q_mul_2); - - let y_a_next = y_a(meta, Rotation::next()); - - // x_{P,i} - let x_p_cur = meta.query_advice(self.double_and_add.x_p, Rotation::cur()); - // x_{P,i-1} - let x_p_next = meta.query_advice(self.double_and_add.x_p, Rotation::next()); - // y_{P,i} - let y_p_cur = meta.query_advice(self.y_p, Rotation::cur()); - // y_{P,i-1} - let y_p_next = meta.query_advice(self.y_p, Rotation::next()); - - // The base used in double-and-add remains constant. We check that its - // x- and y- coordinates are the same throughout. - let x_p_check = x_p_cur - x_p_next; - let y_p_check = y_p_cur - y_p_next; - - Constraints::with_selector( - q_mul_2, - std::iter::empty() - .chain(Some(("x_p_check", x_p_check))) - .chain(Some(("y_p_check", y_p_check))) - .chain(for_loop(meta, y_a_next)), - ) - }); - - // q_mul_3 == 1 checks - // https://p.z.cash/halo2-0.1:ecc-var-mul-incomplete-last-row?partial - meta.create_gate("q_mul_3 == 1 checks", |meta| { - let q_mul_3 = meta.query_selector(self.q_mul_3); - let y_a_final = meta.query_advice(self.double_and_add.lambda_1, Rotation::next()); - Constraints::with_selector(q_mul_3, for_loop(meta, y_a_final)) - }); - } - - /// We perform incomplete addition on all but the last three bits of the - /// decomposed scalar. - /// We split the bits in the incomplete addition range into "hi" and "lo" - /// halves and process them side by side, using the same rows but with - /// non-overlapping columns. The base is never the identity point even at - /// the boundary between halves. - /// Returns (x, y, z). - #[allow(clippy::type_complexity)] - pub(super) fn double_and_add( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - base: &NonIdentityEccPoint, - bits: &[Value], - acc: (X, Y, Z), - ) -> Result<(X, Y, Vec>), Error> { - // Check that we have the correct number of bits for this double-and-add. - assert_eq!(bits.len(), NUM_BITS); - - // Handle exceptional cases - let (x_p, y_p) = (base.x.value().cloned(), base.y.value().cloned()); - let (x_a, y_a) = (acc.0.value().cloned(), acc.1.value().cloned()); - - x_a.zip(y_a) - .zip(x_p.zip(y_p)) - .error_if_known_and(|((x_a, y_a), (x_p, y_p))| { - // A is point at infinity - (x_p.is_zero_vartime() && y_p.is_zero_vartime()) - // Q is point at infinity - || (x_a.is_zero_vartime() && y_a.is_zero_vartime()) - // x_p = x_a - || (x_p == x_a) - })?; - - // Set q_mul values - { - // q_mul_1 = 1 on offset 0 - self.q_mul_1.enable(region, offset)?; - - let offset = offset + 1; - // q_mul_2 = 1 on all rows after offset 0, excluding the last row. - for idx in 0..(NUM_BITS - 1) { - self.q_mul_2.enable(region, offset + idx)?; - } - - // q_mul_3 = 1 on the last row. - self.q_mul_3.enable(region, offset + NUM_BITS - 1)?; - } - - // Initialise double-and-add - let (mut x_a, mut y_a, mut z) = { - // Initialise the running `z` sum for the scalar bits. - let z = acc.2.copy_advice(|| "starting z", region, self.z, offset)?; - - // Initialise acc - let x_a = acc.0.copy_advice( - || "starting x_a", - region, - self.double_and_add.x_a, - offset + 1, - )?; - let y_a = acc.1.copy_advice( - || "starting y_a", - region, - self.double_and_add.lambda_1, - offset, - )?; - - (x_a, y_a.value().cloned(), z) - }; - - // Increase offset by 1; we used row 0 for initializing `z`. - let offset = offset + 1; - - // Initialise vector to store all interstitial `z` running sum values. - let mut zs: Vec> = Vec::with_capacity(bits.len()); - - // Incomplete addition - for (row, k) in bits.iter().enumerate() { - // z_{i} = 2 * z_{i+1} + k_i - // https://p.z.cash/halo2-0.1:ecc-var-mul-witness-scalar?partial - let z_val = z - .value() - .zip(k.as_ref()) - .map(|(z_val, k)| pallas::Base::from(2) * z_val + pallas::Base::from(*k as u64)); - z = region.assign_advice(|| "z", self.z, row + offset, || z_val)?; - zs.push(Z(z.clone())); - - // Assign `x_p`, `y_p` - region.assign_advice(|| "x_p", self.double_and_add.x_p, row + offset, || x_p)?; - region.assign_advice(|| "y_p", self.y_p, row + offset, || y_p)?; - - // If the bit is set, use `y`; if the bit is not set, use `-y` - let y_p = y_p - .zip(k.as_ref()) - .map(|(y_p, k)| if !k { -y_p } else { y_p }); - - // Compute and assign λ1⋅(x_A − x_P) = y_A − y_P - let lambda1 = y_a - .zip(y_p) - .zip(x_a.value()) - .zip(x_p) - .map(|(((y_a, y_p), x_a), x_p)| (y_a - y_p) * (x_a - x_p).invert()); - region.assign_advice( - || "lambda1", - self.double_and_add.lambda_1, - row + offset, - || lambda1, - )?; - - // x_R = λ1^2 - x_A - x_P - let x_r = lambda1 - .zip(x_a.value()) - .zip(x_p) - .map(|((lambda1, x_a), x_p)| lambda1.square() - x_a - x_p); - - // λ2 = (2(y_A) / (x_A - x_R)) - λ1 - let lambda2 = - lambda1 - .zip(y_a) - .zip(x_a.value()) - .zip(x_r) - .map(|(((lambda1, y_a), x_a), x_r)| { - y_a * pallas::Base::from(2) * (x_a - x_r).invert() - lambda1 - }); - region.assign_advice( - || "lambda2", - self.double_and_add.lambda_2, - row + offset, - || lambda2, - )?; - - // Compute and assign `x_a` for the next row - let x_a_new = lambda2.square() - x_a.value() - x_r; - y_a = lambda2 * (x_a.value() - x_a_new) - y_a; - let x_a_val = x_a_new; - x_a = region.assign_advice( - || "x_a", - self.double_and_add.x_a, - row + offset + 1, - || x_a_val, - )?; - } - - // Witness final y_a - let y_a = region.assign_advice( - || "y_a", - self.double_and_add.lambda_1, - offset + NUM_BITS, - || y_a, - )?; - - Ok((X(x_a), Y(y_a), zs)) - } -} diff --git a/halo2_gadgets/src/ecc/chip/mul/overflow.rs b/halo2_gadgets/src/ecc/chip/mul/overflow.rs deleted file mode 100644 index 0d7bd69692..0000000000 --- a/halo2_gadgets/src/ecc/chip/mul/overflow.rs +++ /dev/null @@ -1,208 +0,0 @@ -use super::{T_Q, Z}; -use crate::{ - sinsemilla::primitives as sinsemilla, utilities::lookup_range_check::LookupRangeCheckConfig, -}; - -use halo2_proofs::circuit::AssignedCell; -use halo2_proofs::{ - circuit::Layouter, - plonk::{Advice, Assigned, Column, ConstraintSystem, Constraints, Error, Expression, Selector}, - poly::Rotation, -}; - -use halo2curves::{pasta::pallas, FieldExt}; - -use std::iter; - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct Config { - // Selector to check z_0 = alpha + t_q (mod p) - q_mul_overflow: Selector, - // 10-bit lookup table - lookup_config: LookupRangeCheckConfig, - // Advice columns - advices: [Column; 3], -} - -impl Config { - pub(super) fn configure( - meta: &mut ConstraintSystem, - lookup_config: LookupRangeCheckConfig, - advices: [Column; 3], - ) -> Self { - for advice in advices.iter() { - meta.enable_equality(*advice); - } - - let config = Self { - q_mul_overflow: meta.selector(), - lookup_config, - advices, - }; - - config.create_gate(meta); - - config - } - - fn create_gate(&self, meta: &mut ConstraintSystem) { - // https://p.z.cash/halo2-0.1:ecc-var-mul-overflow - meta.create_gate("overflow checks", |meta| { - let q_mul_overflow = meta.query_selector(self.q_mul_overflow); - - // Constant expressions - let one = Expression::Constant(pallas::Base::one()); - let two_pow_124 = Expression::Constant(pallas::Base::from_u128(1 << 124)); - let two_pow_130 = - two_pow_124.clone() * Expression::Constant(pallas::Base::from_u128(1 << 6)); - - let z_0 = meta.query_advice(self.advices[0], Rotation::prev()); - let z_130 = meta.query_advice(self.advices[0], Rotation::cur()); - let eta = meta.query_advice(self.advices[0], Rotation::next()); - - let k_254 = meta.query_advice(self.advices[1], Rotation::prev()); - let alpha = meta.query_advice(self.advices[1], Rotation::cur()); - - // s_minus_lo_130 = s - sum_{i = 0}^{129} 2^i ⋅ s_i - let s_minus_lo_130 = meta.query_advice(self.advices[1], Rotation::next()); - - let s = meta.query_advice(self.advices[2], Rotation::cur()); - let s_check = s - (alpha.clone() + k_254.clone() * two_pow_130); - - // q = 2^254 + t_q is the Pallas scalar field modulus. - // We cast t_q into the base field to check alpha + t_q (mod p). - let t_q = Expression::Constant(pallas::Base::from_u128(T_Q)); - - // z_0 - alpha - t_q = 0 (mod p) - let recovery = z_0 - alpha - t_q; - - // k_254 * (z_130 - 2^124) = 0 - let lo_zero = k_254.clone() * (z_130.clone() - two_pow_124); - - // k_254 * s_minus_lo_130 = 0 - let s_minus_lo_130_check = k_254.clone() * s_minus_lo_130.clone(); - - // (1 - k_254) * (1 - z_130 * eta) * s_minus_lo_130 = 0 - let canonicity = (one.clone() - k_254) * (one - z_130 * eta) * s_minus_lo_130; - - Constraints::with_selector( - q_mul_overflow, - iter::empty() - .chain(Some(("s_check", s_check))) - .chain(Some(("recovery", recovery))) - .chain(Some(("lo_zero", lo_zero))) - .chain(Some(("s_minus_lo_130_check", s_minus_lo_130_check))) - .chain(Some(("canonicity", canonicity))), - ) - }); - } - - pub(super) fn overflow_check( - &self, - mut layouter: impl Layouter, - alpha: AssignedCell, - zs: &[Z], // [z_0, z_1, ..., z_{254}, z_{255}] - ) -> Result<(), Error> { - // s = alpha + k_254 ⋅ 2^130 is witnessed here, and then copied into - // the decomposition as well as the overflow check gate. - // In the overflow check gate, we check that s is properly derived - // from alpha and k_254. - let s = { - let k_254 = zs[254].clone(); - let s_val = alpha - .value() - .zip(k_254.value()) - .map(|(alpha, k_254)| alpha + k_254 * pallas::Base::from_u128(1 << 65).square()); - - layouter.assign_region( - || "s = alpha + k_254 ⋅ 2^130", - |mut region| { - region.assign_advice( - || "s = alpha + k_254 ⋅ 2^130", - self.advices[0], - 0, - || s_val, - ) - }, - )? - }; - - // Subtract the first 130 low bits of s = alpha + k_254 ⋅ 2^130 - // using thirteen 10-bit lookups, s_{0..=129} - let s_minus_lo_130 = - self.s_minus_lo_130(layouter.namespace(|| "decompose s_{0..=129}"), s.clone())?; - - layouter.assign_region( - || "overflow check", - |mut region| { - let offset = 0; - - // Enable overflow check gate - self.q_mul_overflow.enable(&mut region, offset + 1)?; - - // Copy `z_0` - zs[0].copy_advice(|| "copy z_0", &mut region, self.advices[0], offset)?; - - // Copy `z_130` - zs[130].copy_advice(|| "copy z_130", &mut region, self.advices[0], offset + 1)?; - - // Witness η = inv0(z_130), where inv0(x) = 0 if x = 0, 1/x otherwise - { - let eta = zs[130].value().map(|z_130| Assigned::from(z_130).invert()); - region.assign_advice( - || "η = inv0(z_130)", - self.advices[0], - offset + 2, - || eta, - )?; - } - - // Copy `k_254` = z_254 - zs[254].copy_advice(|| "copy k_254", &mut region, self.advices[1], offset)?; - - // Copy original alpha - alpha.copy_advice( - || "copy original alpha", - &mut region, - self.advices[1], - offset + 1, - )?; - - // Copy weighted sum of the decomposition of s = alpha + k_254 ⋅ 2^130. - s_minus_lo_130.copy_advice( - || "copy s_minus_lo_130", - &mut region, - self.advices[1], - offset + 2, - )?; - - // Copy witnessed s to check that it was properly derived from alpha and k_254. - s.copy_advice(|| "copy s", &mut region, self.advices[2], offset + 1)?; - - Ok(()) - }, - )?; - - Ok(()) - } - - fn s_minus_lo_130( - &self, - mut layouter: impl Layouter, - s: AssignedCell, - ) -> Result, Error> { - // Number of k-bit words we can use in the lookup decomposition. - let num_words = 130 / sinsemilla::K; - assert!(num_words * sinsemilla::K == 130); - - // Decompose the low 130 bits of `s` using thirteen 10-bit lookups. - let zs = self.lookup_config.copy_check( - layouter.namespace(|| "Decompose low 130 bits of s"), - s, - num_words, - false, - )?; - // (s - (2^0 s_0 + 2^1 s_1 + ... + 2^129 s_129)) / 2^130 - Ok(zs[zs.len() - 1].clone()) - } -} diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed.rs b/halo2_gadgets/src/ecc/chip/mul_fixed.rs deleted file mode 100644 index 909dd171d3..0000000000 --- a/halo2_gadgets/src/ecc/chip/mul_fixed.rs +++ /dev/null @@ -1,498 +0,0 @@ -use super::{ - add, add_incomplete, EccBaseFieldElemFixed, EccScalarFixed, EccScalarFixedShort, FixedPoint, - NonIdentityEccPoint, FIXED_BASE_WINDOW_SIZE, H, -}; -use crate::utilities::decompose_running_sum::RunningSumConfig; - -use std::marker::PhantomData; - -use group::{ - ff::{PrimeField, PrimeFieldBits}, - Curve, -}; -use halo2_proofs::{ - circuit::{AssignedCell, Region, Value}, - plonk::{ - Advice, Column, ConstraintSystem, Constraints, Error, Expression, Fixed, Selector, - VirtualCells, - }, - poly::Rotation, -}; -use halo2curves::{pasta::pallas, CurveAffine, FieldExt}; -use lazy_static::lazy_static; - -pub mod base_field_elem; -pub mod full_width; -pub mod short; - -lazy_static! { - static ref TWO_SCALAR: pallas::Scalar = pallas::Scalar::from(2); - // H = 2^3 (3-bit window) - static ref H_SCALAR: pallas::Scalar = pallas::Scalar::from(H as u64); - static ref H_BASE: pallas::Base = pallas::Base::from(H as u64); -} - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Config> { - running_sum_config: RunningSumConfig, - // The fixed Lagrange interpolation coefficients for `x_p`. - lagrange_coeffs: [Column; H], - // The fixed `z` for each window such that `y + z = u^2`. - fixed_z: Column, - // Decomposition of an `n-1`-bit scalar into `k`-bit windows: - // a = a_0 + 2^k(a_1) + 2^{2k}(a_2) + ... + 2^{(n-1)k}(a_{n-1}) - window: Column, - // y-coordinate of accumulator (only used in the final row). - u: Column, - // Configuration for `add` - add_config: add::Config, - // Configuration for `add_incomplete` - add_incomplete_config: add_incomplete::Config, - _marker: PhantomData, -} - -impl> Config { - #[allow(clippy::too_many_arguments)] - pub(super) fn configure( - meta: &mut ConstraintSystem, - lagrange_coeffs: [Column; H], - window: Column, - u: Column, - add_config: add::Config, - add_incomplete_config: add_incomplete::Config, - ) -> Self { - meta.enable_equality(window); - meta.enable_equality(u); - - let q_running_sum = meta.selector(); - let running_sum_config = RunningSumConfig::configure(meta, q_running_sum, window); - - let config = Self { - running_sum_config, - lagrange_coeffs, - fixed_z: meta.fixed_column(), - window, - u, - add_config, - add_incomplete_config, - _marker: PhantomData, - }; - - // Check relationships between `add_config` and `add_incomplete_config`. - assert_eq!( - config.add_config.x_p, config.add_incomplete_config.x_p, - "add and add_incomplete are used internally in mul_fixed." - ); - assert_eq!( - config.add_config.y_p, config.add_incomplete_config.y_p, - "add and add_incomplete are used internally in mul_fixed." - ); - for advice in [config.window, config.u].iter() { - assert_ne!( - *advice, config.add_config.x_qr, - "Do not overlap with output columns of add." - ); - assert_ne!( - *advice, config.add_config.y_qr, - "Do not overlap with output columns of add." - ); - } - - config.running_sum_coords_gate(meta); - - config - } - - /// Check that each window in the running sum decomposition uses the correct y_p - /// and interpolated x_p. - /// - /// This gate is used both in the mul_fixed::base_field_elem and mul_fixed::short - /// helpers, which decompose the scalar using a running sum. - /// - /// This gate is not used in the mul_fixed::full_width helper, since the full-width - /// scalar is witnessed directly as three-bit windows instead of being decomposed - /// via a running sum. - fn running_sum_coords_gate(&self, meta: &mut ConstraintSystem) { - meta.create_gate("Running sum coordinates check", |meta| { - let q_mul_fixed_running_sum = - meta.query_selector(self.running_sum_config.q_range_check()); - - let z_cur = meta.query_advice(self.window, Rotation::cur()); - let z_next = meta.query_advice(self.window, Rotation::next()); - - // z_{i+1} = (z_i - a_i) / 2^3 - // => a_i = z_i - z_{i+1} * 2^3 - let word = z_cur - z_next * pallas::Base::from(H as u64); - - Constraints::with_selector(q_mul_fixed_running_sum, self.coords_check(meta, word)) - }); - } - - /// [Specification](https://p.z.cash/halo2-0.1:ecc-fixed-mul-coordinates). - #[allow(clippy::op_ref)] - fn coords_check( - &self, - meta: &mut VirtualCells<'_, pallas::Base>, - window: Expression, - ) -> Vec<(&'static str, Expression)> { - let y_p = meta.query_advice(self.add_config.y_p, Rotation::cur()); - let x_p = meta.query_advice(self.add_config.x_p, Rotation::cur()); - let z = meta.query_fixed(self.fixed_z, Rotation::cur()); - let u = meta.query_advice(self.u, Rotation::cur()); - - let window_pow: Vec> = (0..H) - .map(|pow| { - (0..pow).fold(Expression::Constant(pallas::Base::one()), |acc, _| { - acc * window.clone() - }) - }) - .collect(); - - let interpolated_x = window_pow.iter().zip(self.lagrange_coeffs.iter()).fold( - Expression::Constant(pallas::Base::zero()), - |acc, (window_pow, coeff)| { - acc + (window_pow.clone() * meta.query_fixed(*coeff, Rotation::cur())) - }, - ); - - // Check interpolation of x-coordinate - let x_check = interpolated_x - x_p.clone(); - // Check that `y + z = u^2`, where `z` is fixed and `u`, `y` are witnessed - let y_check = u.square() - y_p.clone() - z; - // Check that (x, y) is on the curve - let on_curve = - y_p.square() - x_p.clone().square() * x_p - Expression::Constant(pallas::Affine::b()); - - vec![ - ("check x", x_check), - ("check y", y_check), - ("on-curve", on_curve), - ] - } - - #[allow(clippy::type_complexity)] - fn assign_region_inner, const NUM_WINDOWS: usize>( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - scalar: &ScalarFixed, - base: &F, - coords_check_toggle: Selector, - ) -> Result<(NonIdentityEccPoint, NonIdentityEccPoint), Error> { - // Assign fixed columns for given fixed base - self.assign_fixed_constants::(region, offset, base, coords_check_toggle)?; - - // Initialize accumulator - let acc = self.initialize_accumulator::(region, offset, base, scalar)?; - - // Process all windows excluding least and most significant windows - let acc = self.add_incomplete::(region, offset, acc, base, scalar)?; - - // Process most significant window - let mul_b = self.process_msb::(region, offset, base, scalar)?; - - Ok((acc, mul_b)) - } - - /// [Specification](https://p.z.cash/halo2-0.1:ecc-fixed-mul-load-base). - fn assign_fixed_constants, const NUM_WINDOWS: usize>( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - base: &F, - coords_check_toggle: Selector, - ) -> Result<(), Error> { - let mut constants = None; - let build_constants = || { - let lagrange_coeffs = base.lagrange_coeffs(); - assert_eq!(lagrange_coeffs.len(), NUM_WINDOWS); - - let z = base.z(); - assert_eq!(z.len(), NUM_WINDOWS); - - (lagrange_coeffs, z) - }; - - // Assign fixed columns for given fixed base - for window in 0..NUM_WINDOWS { - coords_check_toggle.enable(region, window + offset)?; - - // Assign x-coordinate Lagrange interpolation coefficients - for k in 0..H { - region.assign_fixed( - || { - format!( - "Lagrange interpolation coeff for window: {:?}, k: {:?}", - window, k - ) - }, - self.lagrange_coeffs[k], - window + offset, - || { - if constants.as_ref().is_none() { - constants = Some(build_constants()); - } - let lagrange_coeffs = &constants.as_ref().unwrap().0; - Value::known(lagrange_coeffs[window][k]) - }, - )?; - } - - // Assign z-values for each window - region.assign_fixed( - || format!("z-value for window: {:?}", window), - self.fixed_z, - window + offset, - || { - let z = &constants.as_ref().unwrap().1; - Value::known(pallas::Base::from(z[window])) - }, - )?; - } - - Ok(()) - } - - /// Assigns the values used to process a window. - fn process_window, const NUM_WINDOWS: usize>( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - w: usize, - k_usize: Value, - window_scalar: Value, - base: &F, - ) -> Result { - let base_value = base.generator(); - let base_u = base.u(); - assert_eq!(base_u.len(), NUM_WINDOWS); - - // Compute [window_scalar]B - let mul_b = { - let mul_b = window_scalar.map(|scalar| base_value * scalar); - let mul_b = mul_b.map(|mul_b| mul_b.to_affine().coordinates().unwrap()); - - let x = mul_b.map(|mul_b| { - let x = *mul_b.x(); - assert!(x != pallas::Base::zero()); - x.into() - }); - let x = region.assign_advice( - || format!("mul_b_x, window {}", w), - self.add_config.x_p, - offset + w, - || x, - )?; - - let y = mul_b.map(|mul_b| { - let y = *mul_b.y(); - assert!(y != pallas::Base::zero()); - y.into() - }); - let y = region.assign_advice( - || format!("mul_b_y, window {}", w), - self.add_config.y_p, - offset + w, - || y, - )?; - - NonIdentityEccPoint { x, y } - }; - - // Assign u = (y_p + z_w).sqrt() - let u_val = k_usize.map(|k| pallas::Base::from_repr(base_u[w][k]).unwrap()); - region.assign_advice(|| "u", self.u, offset + w, || u_val)?; - - Ok(mul_b) - } - - fn initialize_accumulator, const NUM_WINDOWS: usize>( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - base: &F, - scalar: &ScalarFixed, - ) -> Result { - // Recall that the message at each window `w` is represented as - // `m_w = [(k_w + 2) ⋅ 8^w]B`. - // When `w = 0`, we have `m_0 = [(k_0 + 2)]B`. - let w = 0; - let k0 = scalar.windows_field()[0]; - let k0_usize = scalar.windows_usize()[0]; - self.process_lower_bits::<_, NUM_WINDOWS>(region, offset, w, k0, k0_usize, base) - } - - fn add_incomplete, const NUM_WINDOWS: usize>( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - mut acc: NonIdentityEccPoint, - base: &F, - scalar: &ScalarFixed, - ) -> Result { - let scalar_windows_field = scalar.windows_field(); - let scalar_windows_usize = scalar.windows_usize(); - assert_eq!(scalar_windows_field.len(), NUM_WINDOWS); - - for (w, (k, k_usize)) in scalar_windows_field - .into_iter() - .zip(scalar_windows_usize) - .enumerate() - // The MSB is processed separately. - .take(NUM_WINDOWS - 1) - // Skip k_0 (already processed). - .skip(1) - { - // Compute [(k_w + 2) ⋅ 8^w]B - // - // This assigns the coordinates of the returned point into the input cells for - // the incomplete addition gate, which will then copy them into themselves. - let mul_b = - self.process_lower_bits::<_, NUM_WINDOWS>(region, offset, w, k, k_usize, base)?; - - // Add to the accumulator. - // - // After the first loop, the accumulator will already be in the input cells - // for the incomplete addition gate, and will be copied into themselves. - acc = self - .add_incomplete_config - .assign_region(&mul_b, &acc, offset + w, region)?; - } - Ok(acc) - } - - /// Assigns the values used to process a window that does not contain the MSB. - fn process_lower_bits, const NUM_WINDOWS: usize>( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - w: usize, - k: Value, - k_usize: Value, - base: &F, - ) -> Result { - // `scalar = [(k_w + 2) ⋅ 8^w] - let scalar = k.map(|k| (k + *TWO_SCALAR) * (*H_SCALAR).pow(&[w as u64, 0, 0, 0])); - - self.process_window::<_, NUM_WINDOWS>(region, offset, w, k_usize, scalar, base) - } - - /// Assigns the values used to process the window containing the MSB. - fn process_msb, const NUM_WINDOWS: usize>( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - base: &F, - scalar: &ScalarFixed, - ) -> Result { - let k_usize = scalar.windows_usize()[NUM_WINDOWS - 1]; - - // offset_acc = \sum_{j = 0}^{NUM_WINDOWS - 2} 2^{FIXED_BASE_WINDOW_SIZE*j + 1} - let offset_acc = (0..(NUM_WINDOWS - 1)).fold(pallas::Scalar::zero(), |acc, w| { - acc + (*TWO_SCALAR).pow(&[FIXED_BASE_WINDOW_SIZE as u64 * w as u64 + 1, 0, 0, 0]) - }); - - // `scalar = [k * 8^(NUM_WINDOWS - 1) - offset_acc]`. - let scalar = scalar.windows_field()[scalar.windows_field().len() - 1] - .map(|k| k * (*H_SCALAR).pow(&[(NUM_WINDOWS - 1) as u64, 0, 0, 0]) - offset_acc); - - self.process_window::<_, NUM_WINDOWS>( - region, - offset, - NUM_WINDOWS - 1, - k_usize, - scalar, - base, - ) - } -} - -enum ScalarFixed { - FullWidth(EccScalarFixed), - Short(EccScalarFixedShort), - BaseFieldElem(EccBaseFieldElemFixed), -} - -impl From<&EccScalarFixed> for ScalarFixed { - fn from(scalar_fixed: &EccScalarFixed) -> Self { - Self::FullWidth(scalar_fixed.clone()) - } -} - -impl From<&EccScalarFixedShort> for ScalarFixed { - fn from(scalar_fixed: &EccScalarFixedShort) -> Self { - Self::Short(scalar_fixed.clone()) - } -} - -impl From<&EccBaseFieldElemFixed> for ScalarFixed { - fn from(base_field_elem: &EccBaseFieldElemFixed) -> Self { - Self::BaseFieldElem(base_field_elem.clone()) - } -} - -impl ScalarFixed { - /// The scalar decomposition was done in the base field. For computation - /// outside the circuit, we now convert them back into the scalar field. - /// - /// This function does not require that the base field fits inside the scalar field, - /// because the window size fits into either field. - fn windows_field(&self) -> Vec> { - let running_sum_to_windows = |zs: Vec>| { - (0..(zs.len() - 1)) - .map(|idx| { - let z_cur = zs[idx].value(); - let z_next = zs[idx + 1].value(); - let word = z_cur - z_next * Value::known(*H_BASE); - // This assumes that the endianness of the encodings of pallas::Base - // and pallas::Scalar are the same. They happen to be, but we need to - // be careful if this is generalised. - word.map(|word| pallas::Scalar::from_repr(word.to_repr()).unwrap()) - }) - .collect::>() - }; - match self { - Self::BaseFieldElem(scalar) => running_sum_to_windows(scalar.running_sum.to_vec()), - Self::Short(scalar) => running_sum_to_windows( - scalar - .running_sum - .as_ref() - .expect("EccScalarFixedShort has been constrained") - .to_vec(), - ), - Self::FullWidth(scalar) => scalar - .windows - .as_ref() - .expect("EccScalarFixed has been witnessed") - .iter() - .map(|bits| { - // This assumes that the endianness of the encodings of pallas::Base - // and pallas::Scalar are the same. They happen to be, but we need to - // be careful if this is generalised. - bits.value() - .map(|value| pallas::Scalar::from_repr(value.to_repr()).unwrap()) - }) - .collect::>(), - } - } - - /// The scalar decomposition is guaranteed to be in three-bit windows, so we construct - /// `usize` indices from the lowest three bits of each window field element for - /// convenient indexing into `u`-values. - fn windows_usize(&self) -> Vec> { - self.windows_field() - .iter() - .map(|window| { - window.map(|window| { - window - .to_le_bits() - .iter() - .by_vals() - .take(FIXED_BASE_WINDOW_SIZE) - .rev() - .fold(0, |acc, b| 2 * acc + if b { 1 } else { 0 }) - }) - }) - .collect::>() - } -} diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs deleted file mode 100644 index 08fd34e313..0000000000 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/base_field_elem.rs +++ /dev/null @@ -1,528 +0,0 @@ -use super::super::{EccBaseFieldElemFixed, EccPoint, FixedPoints, NUM_WINDOWS, T_P}; -use super::H_BASE; - -use crate::utilities::bool_check; -use crate::{ - sinsemilla::primitives as sinsemilla, - utilities::{bitrange_subset, lookup_range_check::LookupRangeCheckConfig, range_check}, -}; - -use group::ff::PrimeField; -use halo2_proofs::{ - circuit::{AssignedCell, Layouter}, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Expression, Selector}, - poly::Rotation, -}; -use halo2curves::{pasta::pallas, FieldExt}; - -use std::convert::TryInto; - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Config> { - q_mul_fixed_base_field: Selector, - canon_advices: [Column; 3], - lookup_config: LookupRangeCheckConfig, - super_config: super::Config, -} - -impl> Config { - pub(crate) fn configure( - meta: &mut ConstraintSystem, - canon_advices: [Column; 3], - lookup_config: LookupRangeCheckConfig, - super_config: super::Config, - ) -> Self { - for advice in canon_advices.iter() { - meta.enable_equality(*advice); - } - - let config = Self { - q_mul_fixed_base_field: meta.selector(), - canon_advices, - lookup_config, - super_config, - }; - - let add_incomplete_advices = config.super_config.add_incomplete_config.advice_columns(); - for canon_advice in config.canon_advices.iter() { - assert!( - !add_incomplete_advices.contains(canon_advice), - "Deconflict canon_advice columns with incomplete addition columns." - ); - } - - config.create_gate(meta); - - config - } - - fn create_gate(&self, meta: &mut ConstraintSystem) { - // Check that the base field element is canonical. - // https://p.z.cash/halo2-0.1:ecc-fixed-mul-base-canonicity - meta.create_gate("Canonicity checks", |meta| { - let q_mul_fixed_base_field = meta.query_selector(self.q_mul_fixed_base_field); - - let alpha = meta.query_advice(self.canon_advices[0], Rotation::prev()); - // The last three bits of α. - let z_84_alpha = meta.query_advice(self.canon_advices[2], Rotation::prev()); - - // Decompose α into three pieces, in little-endian order: - // α = α_0 (252 bits) || α_1 (2 bits) || α_2 (1 bit). - // - // α_0 is derived, not witnessed. - let alpha_0 = { - let two_pow_252 = pallas::Base::from_u128(1 << 126).square(); - alpha - (z_84_alpha.clone() * two_pow_252) - }; - let alpha_1 = meta.query_advice(self.canon_advices[1], Rotation::cur()); - let alpha_2 = meta.query_advice(self.canon_advices[2], Rotation::cur()); - - let alpha_0_prime = meta.query_advice(self.canon_advices[0], Rotation::cur()); - let z_13_alpha_0_prime = meta.query_advice(self.canon_advices[0], Rotation::next()); - let z_44_alpha = meta.query_advice(self.canon_advices[1], Rotation::next()); - let z_43_alpha = meta.query_advice(self.canon_advices[2], Rotation::next()); - - let decomposition_checks = { - // Range-constrain α_1 to be 2 bits - let alpha_1_range_check = range_check(alpha_1.clone(), 1 << 2); - // Boolean-constrain α_2 - let alpha_2_range_check = bool_check(alpha_2.clone()); - // Check that α_1 + 2^2 α_2 = z_84_alpha - let z_84_alpha_check = z_84_alpha.clone() - - (alpha_1.clone() + alpha_2.clone() * pallas::Base::from(1 << 2)); - - std::iter::empty() - .chain(Some(("alpha_1_range_check", alpha_1_range_check))) - .chain(Some(("alpha_2_range_check", alpha_2_range_check))) - .chain(Some(("z_84_alpha_check", z_84_alpha_check))) - }; - - // Check α_0_prime = α_0 + 2^130 - t_p - let alpha_0_prime_check = { - let two_pow_130 = Expression::Constant(pallas::Base::from_u128(1 << 65).square()); - let t_p = Expression::Constant(pallas::Base::from_u128(T_P)); - alpha_0_prime - (alpha_0 + two_pow_130 - t_p) - }; - - // We want to enforce canonicity of a 255-bit base field element, α. - // That is, we want to check that 0 ≤ α < p, where p is Pallas base - // field modulus p = 2^254 + t_p - // = 2^254 + 45560315531419706090280762371685220353. - // Note that t_p < 2^130. - // - // α has been decomposed into three pieces in little-endian order: - // α = α_0 (252 bits) || α_1 (2 bits) || α_2 (1 bit). - // = α_0 + 2^252 α_1 + 2^254 α_2. - // - // If the MSB α_2 = 1, then: - // - α_2 = 1 => α_1 = 0, and - // - α_2 = 1 => α_0 < t_p. To enforce this: - // - α_2 = 1 => 0 ≤ α_0 < 2^130 - // - alpha_0_hi_120 = 0 (constrain α_0 to be 132 bits) - // - a_43 = 0 or 1 (constrain α_0[130..=131] to be 0) - // - α_2 = 1 => 0 ≤ α_0 + 2^130 - t_p < 2^130 - // => 13 ten-bit lookups of α_0 + 2^130 - t_p - // => z_13_alpha_0_prime = 0 - // - let canon_checks = { - // alpha_0_hi_120 = z_44 - 2^120 z_84 - let alpha_0_hi_120 = { - let two_pow_120 = - Expression::Constant(pallas::Base::from_u128(1 << 60).square()); - z_44_alpha.clone() - z_84_alpha * two_pow_120 - }; - // a_43 = z_43 - (2^3)z_44 - let a_43 = z_43_alpha - z_44_alpha * *H_BASE; - - std::iter::empty() - .chain(Some(("MSB = 1 => alpha_1 = 0", alpha_2.clone() * alpha_1))) - .chain(Some(( - "MSB = 1 => alpha_0_hi_120 = 0", - alpha_2.clone() * alpha_0_hi_120, - ))) - .chain(Some(( - "MSB = 1 => a_43 = 0 or 1", - alpha_2.clone() * bool_check(a_43), - ))) - .chain(Some(( - "MSB = 1 => z_13_alpha_0_prime = 0", - alpha_2 * z_13_alpha_0_prime, - ))) - }; - - Constraints::with_selector( - q_mul_fixed_base_field, - canon_checks - .chain(decomposition_checks) - .chain(Some(("alpha_0_prime check", alpha_0_prime_check))), - ) - }); - } - - pub fn assign( - &self, - mut layouter: impl Layouter, - scalar: AssignedCell, - base: &>::Base, - ) -> Result - where - >::Base: super::super::FixedPoint, - { - let (scalar, acc, mul_b) = layouter.assign_region( - || "Base-field elem fixed-base mul (incomplete addition)", - |mut region| { - let offset = 0; - - // Decompose scalar - let scalar = { - let running_sum = self.super_config.running_sum_config.copy_decompose( - &mut region, - offset, - scalar.clone(), - true, - pallas::Base::NUM_BITS as usize, - NUM_WINDOWS, - )?; - EccBaseFieldElemFixed { - base_field_elem: running_sum[0].clone(), - running_sum: (*running_sum).as_slice().try_into().unwrap(), - } - }; - - let (acc, mul_b) = self.super_config.assign_region_inner::<_, NUM_WINDOWS>( - &mut region, - offset, - &(&scalar).into(), - base, - self.super_config.running_sum_config.q_range_check(), - )?; - - Ok((scalar, acc, mul_b)) - }, - )?; - - // Add to the accumulator and return the final result as `[scalar]B`. - let result = layouter.assign_region( - || "Base-field elem fixed-base mul (complete addition)", - |mut region| { - self.super_config.add_config.assign_region( - &mul_b.clone().into(), - &acc.clone().into(), - 0, - &mut region, - ) - }, - )?; - - #[cfg(test)] - // Check that the correct multiple is obtained. - { - use super::super::FixedPoint; - use group::Curve; - - let scalar = &scalar - .base_field_elem() - .value() - .map(|scalar| pallas::Scalar::from_repr(scalar.to_repr()).unwrap()); - let real_mul = scalar.map(|scalar| base.generator() * scalar); - let result = result.point(); - - real_mul - .zip(result) - .assert_if_known(|(real_mul, result)| &real_mul.to_affine() == result); - } - - // We want to enforce canonicity of a 255-bit base field element, α. - // That is, we want to check that 0 ≤ α < p, where p is Pallas base - // field modulus p = 2^254 + t_p - // = 2^254 + 45560315531419706090280762371685220353. - // Note that t_p < 2^130. - // - // α has been decomposed into three pieces in little-endian order: - // α = α_0 (252 bits) || α_1 (2 bits) || α_2 (1 bit). - // = α_0 + 2^252 α_1 + 2^254 α_2. - // - // If the MSB α_2 = 1, then: - // - α_2 = 1 => α_1 = 0, and - // - α_2 = 1 => α_0 < t_p. To enforce this: - // - α_2 = 1 => 0 ≤ α_0 < 2^130 - // => 13 ten-bit lookups of α_0 - // - α_2 = 1 => 0 ≤ α_0 + 2^130 - t_p < 2^130 - // => 13 ten-bit lookups of α_0 + 2^130 - t_p - // => z_13_alpha_0_prime = 0 - // - let (alpha, running_sum) = (scalar.base_field_elem, &scalar.running_sum); - let z_43_alpha = running_sum[43].clone(); - let z_44_alpha = running_sum[44].clone(); - let z_84_alpha = running_sum[84].clone(); - - // α_0 = α - z_84_alpha * 2^252 - let alpha_0 = alpha - .value() - .zip(z_84_alpha.value()) - .map(|(alpha, z_84_alpha)| { - let two_pow_252 = pallas::Base::from_u128(1 << 126).square(); - alpha - z_84_alpha * two_pow_252 - }); - - let (alpha_0_prime, z_13_alpha_0_prime) = { - // alpha_0_prime = alpha + 2^130 - t_p. - let alpha_0_prime = alpha_0.map(|alpha_0| { - let two_pow_130 = pallas::Base::from_u128(1 << 65).square(); - let t_p = pallas::Base::from_u128(T_P); - alpha_0 + two_pow_130 - t_p - }); - let zs = self.lookup_config.witness_check( - layouter.namespace(|| "Lookup range check alpha_0 + 2^130 - t_p"), - alpha_0_prime, - 13, - false, - )?; - let alpha_0_prime = zs[0].clone(); - - (alpha_0_prime, zs[13].clone()) - }; - - layouter.assign_region( - || "Canonicity checks", - |mut region| { - // Activate canonicity check gate - self.q_mul_fixed_base_field.enable(&mut region, 1)?; - - // Offset 0 - { - let offset = 0; - - // Copy α - alpha.copy_advice(|| "Copy α", &mut region, self.canon_advices[0], offset)?; - - // z_84_alpha = the top three bits of alpha. - z_84_alpha.copy_advice( - || "Copy z_84_alpha", - &mut region, - self.canon_advices[2], - offset, - )?; - } - - // Offset 1 - { - let offset = 1; - // Copy alpha_0_prime = alpha_0 + 2^130 - t_p. - // We constrain this in the custom gate to be derived correctly. - alpha_0_prime.copy_advice( - || "Copy α_0 + 2^130 - t_p", - &mut region, - self.canon_advices[0], - offset, - )?; - - // Decompose α into three pieces, - // α = α_0 (252 bits) || α_1 (2 bits) || α_2 (1 bit). - // We only need to witness α_1 and α_2. α_0 is derived in the gate. - // Witness α_1 = α[252..=253] - let alpha_1 = alpha.value().map(|alpha| bitrange_subset(alpha, 252..254)); - region.assign_advice( - || "α_1 = α[252..=253]", - self.canon_advices[1], - offset, - || alpha_1, - )?; - - // Witness the MSB α_2 = α[254] - let alpha_2 = alpha.value().map(|alpha| bitrange_subset(alpha, 254..255)); - region.assign_advice( - || "α_2 = α[254]", - self.canon_advices[2], - offset, - || alpha_2, - )?; - } - - // Offset 2 - { - let offset = 2; - // Copy z_13_alpha_0_prime - z_13_alpha_0_prime.copy_advice( - || "Copy z_13_alpha_0_prime", - &mut region, - self.canon_advices[0], - offset, - )?; - - // Copy z_44_alpha - z_44_alpha.copy_advice( - || "Copy z_44_alpha", - &mut region, - self.canon_advices[1], - offset, - )?; - - // Copy z_43_alpha - z_43_alpha.copy_advice( - || "Copy z_43_alpha", - &mut region, - self.canon_advices[2], - offset, - )?; - } - - Ok(()) - }, - )?; - - Ok(result) - } -} - -#[cfg(test)] -pub mod tests { - use group::{ - ff::{Field, PrimeField}, - Curve, - }; - use halo2_proofs::{ - circuit::{Chip, Layouter, Value}, - plonk::Error, - }; - use halo2curves::pasta::pallas; - use rand::rngs::OsRng; - - use crate::{ - ecc::{ - chip::{EccChip, FixedPoint, H}, - tests::{BaseField, TestFixedBases}, - FixedPointBaseField, NonIdentityPoint, Point, - }, - utilities::UtilitiesInstructions, - }; - - pub(crate) fn test_mul_fixed_base_field( - chip: EccChip, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - test_single_base( - chip.clone(), - layouter.namespace(|| "base_field_elem"), - FixedPointBaseField::from_inner(chip, BaseField), - BaseField.generator(), - ) - } - - #[allow(clippy::op_ref)] - fn test_single_base( - chip: EccChip, - mut layouter: impl Layouter, - base: FixedPointBaseField>, - base_val: pallas::Affine, - ) -> Result<(), Error> { - let rng = OsRng; - - let column = chip.config().advices[0]; - - fn constrain_equal_non_id( - chip: EccChip, - mut layouter: impl Layouter, - base_val: pallas::Affine, - scalar_val: pallas::Base, - result: Point>, - ) -> Result<(), Error> { - // Move scalar from base field into scalar field (which always fits for Pallas). - let scalar = pallas::Scalar::from_repr(scalar_val.to_repr()).unwrap(); - let expected = NonIdentityPoint::new( - chip, - layouter.namespace(|| "expected point"), - Value::known((base_val * scalar).to_affine()), - )?; - result.constrain_equal(layouter.namespace(|| "constrain result"), &expected) - } - - // [a]B - { - let scalar_fixed = pallas::Base::random(rng); - let result = { - let scalar_fixed = chip.load_private( - layouter.namespace(|| "random base field element"), - column, - Value::known(scalar_fixed), - )?; - base.mul(layouter.namespace(|| "random [a]B"), scalar_fixed)? - }; - constrain_equal_non_id( - chip.clone(), - layouter.namespace(|| "random [a]B"), - base_val, - scalar_fixed, - result, - )?; - } - - // There is a single canonical sequence of window values for which a doubling occurs on the last step: - // 1333333333333333333333333333333333333333333333333333333333333333333333333333333333334 in octal. - // (There is another *non-canonical* sequence - // 5333333333333333333333333333333333333333332711161673731021062440252244051273333333333 in octal.) - { - let h = pallas::Base::from(H as u64); - let scalar_fixed = "1333333333333333333333333333333333333333333333333333333333333333333333333333333333334" - .chars() - .fold(pallas::Base::zero(), |acc, c| { - acc * &h + &pallas::Base::from(c.to_digit(8).unwrap() as u64) - }); - let result = { - let scalar_fixed = chip.load_private( - layouter.namespace(|| "mul with double"), - column, - Value::known(scalar_fixed), - )?; - base.mul(layouter.namespace(|| "mul with double"), scalar_fixed)? - }; - constrain_equal_non_id( - chip.clone(), - layouter.namespace(|| "mul with double"), - base_val, - scalar_fixed, - result, - )?; - } - - // [0]B should return (0,0) since it uses complete addition - // on the last step. - { - let scalar_fixed = pallas::Base::zero(); - let result = { - let scalar_fixed = chip.load_private( - layouter.namespace(|| "zero"), - column, - Value::known(scalar_fixed), - )?; - base.mul(layouter.namespace(|| "mul by zero"), scalar_fixed)? - }; - result - .inner() - .is_identity() - .assert_if_known(|is_identity| *is_identity); - } - - // [-1]B is the largest base field element - { - let scalar_fixed = -pallas::Base::one(); - let result = { - let scalar_fixed = chip.load_private( - layouter.namespace(|| "-1"), - column, - Value::known(scalar_fixed), - )?; - base.mul(layouter.namespace(|| "mul by -1"), scalar_fixed)? - }; - constrain_equal_non_id( - chip, - layouter.namespace(|| "mul by -1"), - base_val, - scalar_fixed, - result, - )?; - } - - Ok(()) - } -} diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs deleted file mode 100644 index b82620c283..0000000000 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/full_width.rs +++ /dev/null @@ -1,316 +0,0 @@ -use super::super::{EccPoint, EccScalarFixed, FixedPoints, FIXED_BASE_WINDOW_SIZE, H, NUM_WINDOWS}; - -use crate::utilities::{decompose_word, range_check}; -use arrayvec::ArrayVec; -use ff::PrimeField; -use halo2_proofs::{ - circuit::{AssignedCell, Layouter, Region, Value}, - plonk::{ConstraintSystem, Constraints, Error, Selector}, - poly::Rotation, -}; -use halo2curves::pasta::pallas; - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Config> { - q_mul_fixed_full: Selector, - super_config: super::Config, -} - -impl> Config { - pub(crate) fn configure( - meta: &mut ConstraintSystem, - super_config: super::Config, - ) -> Self { - let config = Self { - q_mul_fixed_full: meta.selector(), - super_config, - }; - - config.create_gate(meta); - - config - } - - fn create_gate(&self, meta: &mut ConstraintSystem) { - // Check that each window `k` is within 3 bits - // https://p.z.cash/halo2-0.1:ecc-fixed-mul-full-word - meta.create_gate("Full-width fixed-base scalar mul", |meta| { - let q_mul_fixed_full = meta.query_selector(self.q_mul_fixed_full); - let window = meta.query_advice(self.super_config.window, Rotation::cur()); - - Constraints::with_selector( - q_mul_fixed_full, - self.super_config - .coords_check(meta, window.clone()) - .into_iter() - // Constrain each window to a 3-bit value: - // window * (1 - window) * ... * (7 - window) - .chain(Some(("window range check", range_check(window, H)))), - ) - }); - } - - /// Witnesses the given scalar as `NUM_WINDOWS` 3-bit windows. - /// - /// The scalar is allowed to be non-canonical. - fn witness( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - scalar: Value, - ) -> Result { - let windows = self.decompose_scalar_fixed::<{ pallas::Scalar::NUM_BITS as usize }>( - scalar, offset, region, - )?; - - Ok(EccScalarFixed { - value: scalar, - windows: Some(windows), - }) - } - - /// Witnesses the given scalar as `NUM_WINDOWS` 3-bit windows. - /// - /// The scalar is allowed to be non-canonical. - fn decompose_scalar_fixed( - &self, - scalar: Value, - offset: usize, - region: &mut Region<'_, pallas::Base>, - ) -> Result, NUM_WINDOWS>, Error> { - // Enable `q_mul_fixed_full` selector - for idx in 0..NUM_WINDOWS { - self.q_mul_fixed_full.enable(region, offset + idx)?; - } - - // Decompose scalar into `k-bit` windows - let scalar_windows: Value> = scalar.map(|scalar| { - decompose_word::(&scalar, SCALAR_NUM_BITS, FIXED_BASE_WINDOW_SIZE) - }); - - // Transpose `Value>` into `Vec>`. - let scalar_windows = scalar_windows - .map(|windows| { - windows - .into_iter() - .map(|window| pallas::Base::from(window as u64)) - }) - .transpose_vec(NUM_WINDOWS); - - // Store the scalar decomposition - let mut windows: ArrayVec, NUM_WINDOWS> = - ArrayVec::new(); - for (idx, window) in scalar_windows.into_iter().enumerate() { - let window_cell = region.assign_advice( - || format!("k[{:?}]", offset + idx), - self.super_config.window, - offset + idx, - || window, - )?; - windows.push(window_cell); - } - - Ok(windows) - } - - pub fn assign( - &self, - mut layouter: impl Layouter, - scalar: &EccScalarFixed, - base: &>::FullScalar, - ) -> Result<(EccPoint, EccScalarFixed), Error> - where - >::FullScalar: - super::super::FixedPoint, - { - let (scalar, acc, mul_b) = layouter.assign_region( - || "Full-width fixed-base mul (incomplete addition)", - |mut region| { - let offset = 0; - - // Lazily witness the scalar. - let scalar = match scalar.windows { - None => self.witness(&mut region, offset, scalar.value), - Some(_) => todo!("unimplemented for halo2_gadgets v0.1.0"), - }?; - - let (acc, mul_b) = self.super_config.assign_region_inner::<_, NUM_WINDOWS>( - &mut region, - offset, - &(&scalar).into(), - base, - self.q_mul_fixed_full, - )?; - - Ok((scalar, acc, mul_b)) - }, - )?; - - // Add to the accumulator and return the final result as `[scalar]B`. - let result = layouter.assign_region( - || "Full-width fixed-base mul (last window, complete addition)", - |mut region| { - self.super_config.add_config.assign_region( - &mul_b.clone().into(), - &acc.clone().into(), - 0, - &mut region, - ) - }, - )?; - - #[cfg(test)] - // Check that the correct multiple is obtained. - { - use super::super::FixedPoint; - use group::Curve; - - let real_mul = scalar.value.map(|scalar| base.generator() * scalar); - let result = result.point(); - - real_mul - .zip(result) - .assert_if_known(|(real_mul, result)| &real_mul.to_affine() == result); - } - - Ok((result, scalar)) - } -} - -#[cfg(test)] -pub mod tests { - use group::{ff::Field, Curve}; - use halo2_proofs::{ - circuit::{Layouter, Value}, - plonk::Error, - }; - use halo2curves::pasta::pallas; - use rand::rngs::OsRng; - - use crate::ecc::{ - chip::{EccChip, FixedPoint as _, H}, - tests::{FullWidth, TestFixedBases}, - FixedPoint, NonIdentityPoint, Point, ScalarFixed, - }; - - pub(crate) fn test_mul_fixed( - chip: EccChip, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let test_base = FullWidth::from_pallas_generator(); - test_single_base( - chip.clone(), - layouter.namespace(|| "full_width"), - FixedPoint::from_inner(chip, test_base.clone()), - test_base.generator(), - )?; - - Ok(()) - } - - #[allow(clippy::op_ref)] - fn test_single_base( - chip: EccChip, - mut layouter: impl Layouter, - base: FixedPoint>, - base_val: pallas::Affine, - ) -> Result<(), Error> { - fn constrain_equal_non_id( - chip: EccChip, - mut layouter: impl Layouter, - base_val: pallas::Affine, - scalar_val: pallas::Scalar, - result: Point>, - ) -> Result<(), Error> { - let expected = NonIdentityPoint::new( - chip, - layouter.namespace(|| "expected point"), - Value::known((base_val * scalar_val).to_affine()), - )?; - result.constrain_equal(layouter.namespace(|| "constrain result"), &expected) - } - - // [a]B - { - let scalar_fixed = pallas::Scalar::random(OsRng); - let by = ScalarFixed::new( - chip.clone(), - layouter.namespace(|| "random a"), - Value::known(scalar_fixed), - )?; - - let (result, _) = base.mul(layouter.namespace(|| "random [a]B"), by)?; - constrain_equal_non_id( - chip.clone(), - layouter.namespace(|| "random [a]B"), - base_val, - scalar_fixed, - result, - )?; - } - - // There is a single canonical sequence of window values for which a doubling occurs on the last step: - // 1333333333333333333333333333333333333333333333333333333333333333333333333333333333334 in octal. - // (There is another *non-canonical* sequence - // 5333333333333333333333333333333333333333332711161673731021062440252244051273333333333 in octal.) - { - const LAST_DOUBLING: &str = "1333333333333333333333333333333333333333333333333333333333333333333333333333333333334"; - let h = pallas::Scalar::from(H as u64); - let scalar_fixed = LAST_DOUBLING - .chars() - .fold(pallas::Scalar::zero(), |acc, c| { - acc * &h + &pallas::Scalar::from(c.to_digit(8).unwrap() as u64) - }); - let by = ScalarFixed::new( - chip.clone(), - layouter.namespace(|| LAST_DOUBLING), - Value::known(scalar_fixed), - )?; - let (result, _) = base.mul(layouter.namespace(|| "mul with double"), by)?; - - constrain_equal_non_id( - chip.clone(), - layouter.namespace(|| "mul with double"), - base_val, - scalar_fixed, - result, - )?; - } - - // [0]B should return (0,0) since it uses complete addition - // on the last step. - { - let scalar_fixed = pallas::Scalar::zero(); - let zero = ScalarFixed::new( - chip.clone(), - layouter.namespace(|| "0"), - Value::known(scalar_fixed), - )?; - let (result, _) = base.mul(layouter.namespace(|| "mul by zero"), zero)?; - result - .inner() - .is_identity() - .assert_if_known(|is_identity| *is_identity); - } - - // [-1]B is the largest scalar field element. - { - let scalar_fixed = -pallas::Scalar::one(); - let neg_1 = ScalarFixed::new( - chip.clone(), - layouter.namespace(|| "-1"), - Value::known(scalar_fixed), - )?; - let (result, _) = base.mul(layouter.namespace(|| "mul by -1"), neg_1)?; - constrain_equal_non_id( - chip, - layouter.namespace(|| "mul by -1"), - base_val, - scalar_fixed, - result, - )?; - } - - Ok(()) - } -} diff --git a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs b/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs deleted file mode 100644 index 844d88d134..0000000000 --- a/halo2_gadgets/src/ecc/chip/mul_fixed/short.rs +++ /dev/null @@ -1,663 +0,0 @@ -use std::convert::TryInto; - -use super::super::{EccPoint, EccScalarFixedShort, FixedPoints, L_SCALAR_SHORT, NUM_WINDOWS_SHORT}; -use crate::{ecc::chip::MagnitudeSign, utilities::bool_check}; - -use halo2_proofs::{ - circuit::{Layouter, Region}, - plonk::{ConstraintSystem, Constraints, Error, Expression, Selector}, - poly::Rotation, -}; -use halo2curves::pasta::pallas; - -#[derive(Clone, Debug, Eq, PartialEq)] -pub struct Config> { - // Selector used for fixed-base scalar mul with short signed exponent. - q_mul_fixed_short: Selector, - super_config: super::Config, -} - -impl> Config { - pub(crate) fn configure( - meta: &mut ConstraintSystem, - super_config: super::Config, - ) -> Self { - let config = Self { - q_mul_fixed_short: meta.selector(), - super_config, - }; - - config.create_gate(meta); - - config - } - - fn create_gate(&self, meta: &mut ConstraintSystem) { - // Gate contains the following constraints: - // - https://p.z.cash/halo2-0.1:ecc-fixed-mul-short-msb - // - https://p.z.cash/halo2-0.1:ecc-fixed-mul-short-conditional-neg - meta.create_gate("Short fixed-base mul gate", |meta| { - let q_mul_fixed_short = meta.query_selector(self.q_mul_fixed_short); - let y_p = meta.query_advice(self.super_config.add_config.y_p, Rotation::cur()); - let y_a = meta.query_advice(self.super_config.add_config.y_qr, Rotation::cur()); - // z_21 = k_21 - let last_window = meta.query_advice(self.super_config.u, Rotation::cur()); - let sign = meta.query_advice(self.super_config.window, Rotation::cur()); - - let one = Expression::Constant(pallas::Base::one()); - - // Check that last window is either 0 or 1. - let last_window_check = bool_check(last_window); - // Check that sign is either 1 or -1. - let sign_check = sign.clone().square() - one; - - // `(x_a, y_a)` is the result of `[m]B`, where `m` is the magnitude. - // We conditionally negate this result using `y_p = y_a * s`, where `s` is the sign. - - // Check that the final `y_p = y_a` or `y_p = -y_a` - // - // This constraint is redundant / unnecessary, because `sign` is constrained - // to -1 or 1 by `sign_check`, and `negation_check` therefore permits a strict - // subset of the cases that this constraint permits. - let y_check = (y_p.clone() - y_a.clone()) * (y_p.clone() + y_a.clone()); - - // Check that the correct sign is witnessed s.t. sign * y_p = y_a - let negation_check = sign * y_p - y_a; - - Constraints::with_selector( - q_mul_fixed_short, - [ - ("last_window_check", last_window_check), - ("sign_check", sign_check), - ("y_check", y_check), - ("negation_check", negation_check), - ], - ) - }); - } - - /// Constraints `magnitude` to be at most 66 bits. - /// - /// The final window is separately constrained to be a single bit, which completes the - /// 64-bit range constraint. - fn decompose( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - magnitude_sign: MagnitudeSign, - ) -> Result { - let (magnitude, sign) = magnitude_sign; - - // Decompose magnitude - let running_sum = self.super_config.running_sum_config.copy_decompose( - region, - offset, - magnitude.clone(), - true, - L_SCALAR_SHORT, - NUM_WINDOWS_SHORT, - )?; - - Ok(EccScalarFixedShort { - magnitude, - sign, - running_sum: Some((*running_sum).as_slice().try_into().unwrap()), - }) - } - - pub fn assign( - &self, - mut layouter: impl Layouter, - scalar: &EccScalarFixedShort, - base: &>::ShortScalar, - ) -> Result<(EccPoint, EccScalarFixedShort), Error> - where - >::ShortScalar: - super::super::FixedPoint, - { - let (scalar, acc, mul_b) = layouter.assign_region( - || "Short fixed-base mul (incomplete addition)", - |mut region| { - let offset = 0; - - // Decompose the scalar - let scalar = match scalar.running_sum { - None => self.decompose( - &mut region, - offset, - (scalar.magnitude.clone(), scalar.sign.clone()), - ), - Some(_) => todo!("unimplemented for halo2_gadgets v0.1.0"), - }?; - - let (acc, mul_b) = self - .super_config - .assign_region_inner::<_, NUM_WINDOWS_SHORT>( - &mut region, - offset, - &(&scalar).into(), - base, - self.super_config.running_sum_config.q_range_check(), - )?; - - Ok((scalar, acc, mul_b)) - }, - )?; - - // Last window - let result = layouter.assign_region( - || "Short fixed-base mul (most significant word)", - |mut region| { - let offset = 0; - // Add to the cumulative sum to get `[magnitude]B`. - let magnitude_mul = self.super_config.add_config.assign_region( - &mul_b.clone().into(), - &acc.clone().into(), - offset, - &mut region, - )?; - - // Increase offset by 1 after complete addition - let offset = offset + 1; - - // Copy sign to `window` column - let sign = scalar.sign.copy_advice( - || "sign", - &mut region, - self.super_config.window, - offset, - )?; - - // Copy last window to `u` column. - // (Although the last window is not a `u` value; we are copying it into the `u` - // column because there is an available cell there.) - let z_21 = scalar.running_sum.as_ref().unwrap()[21].clone(); - z_21.copy_advice(|| "last_window", &mut region, self.super_config.u, offset)?; - - // Conditionally negate `y`-coordinate - let y_val = sign.value().and_then(|sign| { - if sign == &-pallas::Base::one() { - -magnitude_mul.y.value() - } else { - magnitude_mul.y.value().cloned() - } - }); - - // Enable mul_fixed_short selector on final row - self.q_mul_fixed_short.enable(&mut region, offset)?; - - // Assign final `y` to `y_p` column and return final point - let y_var = region.assign_advice( - || "y_var", - self.super_config.add_config.y_p, - offset, - || y_val, - )?; - - Ok(EccPoint { - x: magnitude_mul.x, - y: y_var, - }) - }, - )?; - - #[cfg(test)] - // Check that the correct multiple is obtained. - // This inlined test is only done for valid 64-bit magnitudes - // and valid +/- 1 signs. - // Invalid values result in constraint failures which are - // tested at the circuit-level. - { - use super::super::FixedPoint; - use group::{ff::PrimeField, Curve}; - - scalar - .magnitude - .value() - .zip(scalar.sign.value()) - .zip(result.point()) - .assert_if_known(|((magnitude, sign), result)| { - let magnitude_is_valid = - magnitude <= &&pallas::Base::from(0xFFFF_FFFF_FFFF_FFFFu64); - let sign_is_valid = sign.square() == pallas::Base::one(); - // Only check the result if the magnitude and sign are valid. - !(magnitude_is_valid && sign_is_valid) || { - let scalar = { - // Move magnitude from base field into scalar field (which always fits - // for Pallas). - let magnitude = pallas::Scalar::from_repr(magnitude.to_repr()).unwrap(); - - let sign = if sign == &&pallas::Base::one() { - pallas::Scalar::one() - } else { - -pallas::Scalar::one() - }; - - magnitude * sign - }; - let real_mul = base.generator() * scalar; - - &real_mul.to_affine() == result - } - }); - } - - Ok((result, scalar)) - } -} - -#[cfg(test)] -pub mod tests { - use group::{ff::PrimeField, Curve}; - use halo2_proofs::{ - arithmetic::CurveAffine, - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{Any, Error}, - }; - use halo2curves::{pasta::pallas, FieldExt}; - - use crate::{ - ecc::{ - chip::{EccChip, FixedPoint, MagnitudeSign}, - tests::{Short, TestFixedBases}, - FixedPointShort, NonIdentityPoint, Point, ScalarFixedShort, - }, - utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, - }; - - #[allow(clippy::op_ref)] - pub(crate) fn test_mul_fixed_short( - chip: EccChip, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // test_short - let base_val = Short.generator(); - let test_short = FixedPointShort::from_inner(chip.clone(), Short); - - fn load_magnitude_sign( - chip: EccChip, - mut layouter: impl Layouter, - magnitude: pallas::Base, - sign: pallas::Base, - ) -> Result { - let column = chip.config().advices[0]; - let magnitude = chip.load_private( - layouter.namespace(|| "magnitude"), - column, - Value::known(magnitude), - )?; - let sign = - chip.load_private(layouter.namespace(|| "sign"), column, Value::known(sign))?; - - Ok((magnitude, sign)) - } - - fn constrain_equal_non_id( - chip: EccChip, - mut layouter: impl Layouter, - base_val: pallas::Affine, - scalar_val: pallas::Scalar, - result: Point>, - ) -> Result<(), Error> { - let expected = NonIdentityPoint::new( - chip, - layouter.namespace(|| "expected point"), - Value::known((base_val * scalar_val).to_affine()), - )?; - result.constrain_equal(layouter.namespace(|| "constrain result"), &expected) - } - - let magnitude_signs = [ - ("random [a]B", pallas::Base::from(rand::random::()), { - let mut random_sign = pallas::Base::one(); - if rand::random::() { - random_sign = -random_sign; - } - random_sign - }), - ( - "[2^64 - 1]B", - pallas::Base::from(0xFFFF_FFFF_FFFF_FFFFu64), - pallas::Base::one(), - ), - ( - "-[2^64 - 1]B", - pallas::Base::from(0xFFFF_FFFF_FFFF_FFFFu64), - -pallas::Base::one(), - ), - // There is a single canonical sequence of window values for which a doubling occurs on the last step: - // 1333333333333333333334 in octal. - // [0xB6DB_6DB6_DB6D_B6DC] B - ( - "mul_with_double", - pallas::Base::from(0xB6DB_6DB6_DB6D_B6DCu64), - pallas::Base::one(), - ), - ( - "mul_with_double negative", - pallas::Base::from(0xB6DB_6DB6_DB6D_B6DCu64), - -pallas::Base::one(), - ), - ]; - - for (name, magnitude, sign) in magnitude_signs.iter() { - let (result, _) = { - let magnitude_sign = load_magnitude_sign( - chip.clone(), - layouter.namespace(|| *name), - *magnitude, - *sign, - )?; - let by = ScalarFixedShort::new( - chip.clone(), - layouter.namespace(|| "signed short scalar"), - magnitude_sign, - )?; - test_short.mul(layouter.namespace(|| *name), by)? - }; - // Move from base field into scalar field - let scalar = { - let magnitude = pallas::Scalar::from_repr(magnitude.to_repr()).unwrap(); - let sign = if *sign == pallas::Base::one() { - pallas::Scalar::one() - } else { - -pallas::Scalar::one() - }; - magnitude * sign - }; - constrain_equal_non_id( - chip.clone(), - layouter.namespace(|| *name), - base_val, - scalar, - result, - )?; - } - - let zero_magnitude_signs = [ - ("mul by +zero", pallas::Base::zero(), pallas::Base::one()), - ("mul by -zero", pallas::Base::zero(), -pallas::Base::one()), - ]; - - for (name, magnitude, sign) in zero_magnitude_signs.iter() { - let (result, _) = { - let magnitude_sign = load_magnitude_sign( - chip.clone(), - layouter.namespace(|| *name), - *magnitude, - *sign, - )?; - let by = ScalarFixedShort::new( - chip.clone(), - layouter.namespace(|| "signed short scalar"), - magnitude_sign, - )?; - test_short.mul(layouter.namespace(|| *name), by)? - }; - result - .inner() - .is_identity() - .assert_if_known(|is_identity| *is_identity); - } - - Ok(()) - } - - #[test] - fn invalid_magnitude_sign() { - use crate::{ - ecc::chip::{EccConfig, FixedPoint}, - utilities::UtilitiesInstructions, - }; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::{FailureLocation, MockProver, VerifyFailure}, - plonk::{Circuit, ConstraintSystem, Error}, - }; - - #[derive(Default)] - struct MyCircuit { - magnitude: Value, - sign: Value, - // For test checking - magnitude_error: Value, - } - - impl UtilitiesInstructions for MyCircuit { - type Var = AssignedCell; - } - - impl Circuit for MyCircuit { - type Config = EccConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let advices = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - let lookup_table = meta.lookup_table_column(); - let lagrange_coeffs = [ - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - ]; - - // Shared fixed column for loading constants - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup_table); - EccChip::::configure(meta, advices, lagrange_coeffs, range_check) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let column = config.advices[0]; - - let short_config = config.mul_fixed_short.clone(); - let magnitude_sign = { - let magnitude = self.load_private( - layouter.namespace(|| "load magnitude"), - column, - self.magnitude, - )?; - let sign = - self.load_private(layouter.namespace(|| "load sign"), column, self.sign)?; - ScalarFixedShort::new( - EccChip::construct(config), - layouter.namespace(|| "signed short scalar"), - (magnitude, sign), - )? - }; - - short_config.assign(layouter, &magnitude_sign.inner, &Short)?; - - Ok(()) - } - } - - // Copied from halo2_proofs::dev::util - fn format_value(v: pallas::Base) -> String { - use ff::Field; - if v.is_zero_vartime() { - "0".into() - } else if v == pallas::Base::one() { - "1".into() - } else if v == -pallas::Base::one() { - "-1".into() - } else { - // Format value as hex. - let s = format!("{:?}", v); - // Remove leading zeroes. - let s = s.strip_prefix("0x").unwrap(); - let s = s.trim_start_matches('0'); - format!("0x{}", s) - } - } - - // Magnitude larger than 64 bits should fail - { - let circuits = [ - // 2^64 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 64)), - sign: Value::known(pallas::Base::one()), - magnitude_error: Value::known(pallas::Base::from(1 << 1)), - }, - // -2^64 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 64)), - sign: Value::known(-pallas::Base::one()), - magnitude_error: Value::known(pallas::Base::from(1 << 1)), - }, - // 2^66 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 66)), - sign: Value::known(pallas::Base::one()), - magnitude_error: Value::known(pallas::Base::from(1 << 3)), - }, - // -2^66 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 66)), - sign: Value::known(-pallas::Base::one()), - magnitude_error: Value::known(pallas::Base::from(1 << 3)), - }, - // 2^254 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 127).square()), - sign: Value::known(pallas::Base::one()), - magnitude_error: Value::known( - pallas::Base::from_u128(1 << 95).square() * pallas::Base::from(2), - ), - }, - // -2^254 - MyCircuit { - magnitude: Value::known(pallas::Base::from_u128(1 << 127).square()), - sign: Value::known(-pallas::Base::one()), - magnitude_error: Value::known( - pallas::Base::from_u128(1 << 95).square() * pallas::Base::from(2), - ), - }, - ]; - - for circuit in circuits.iter() { - let prover = MockProver::::run(11, circuit, vec![]).unwrap(); - circuit.magnitude_error.assert_if_known(|magnitude_error| { - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::ConstraintNotSatisfied { - constraint: ( - (17, "Short fixed-base mul gate").into(), - 0, - "last_window_check", - ) - .into(), - location: FailureLocation::InRegion { - region: (3, "Short fixed-base mul (most significant word)") - .into(), - offset: 1, - }, - cell_values: vec![( - ((Any::advice(), 5).into(), 0).into(), - format_value(*magnitude_error), - )], - }, - VerifyFailure::Permutation { - column: (Any::Fixed, 9).into(), - location: FailureLocation::OutsideRegion { row: 0 }, - }, - VerifyFailure::Permutation { - column: (Any::advice(), 4).into(), - location: FailureLocation::InRegion { - region: (2, "Short fixed-base mul (incomplete addition)") - .into(), - offset: 22, - }, - }, - ]) - ); - true - }); - } - } - - // Sign that is not +/- 1 should fail - { - let magnitude_u64 = rand::random::(); - let circuit = MyCircuit { - magnitude: Value::known(pallas::Base::from(magnitude_u64)), - sign: Value::known(pallas::Base::zero()), - magnitude_error: Value::unknown(), - }; - - let negation_check_y = { - *(Short.generator() * pallas::Scalar::from(magnitude_u64)) - .to_affine() - .coordinates() - .unwrap() - .y() - }; - - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::ConstraintNotSatisfied { - constraint: ((17, "Short fixed-base mul gate").into(), 1, "sign_check") - .into(), - location: FailureLocation::InRegion { - region: (3, "Short fixed-base mul (most significant word)").into(), - offset: 1, - }, - cell_values: vec![(((Any::advice(), 4).into(), 0).into(), "0".to_string())], - }, - VerifyFailure::ConstraintNotSatisfied { - constraint: ( - (17, "Short fixed-base mul gate").into(), - 3, - "negation_check" - ) - .into(), - location: FailureLocation::InRegion { - region: (3, "Short fixed-base mul (most significant word)").into(), - offset: 1, - }, - cell_values: vec![ - ( - ((Any::advice(), 1).into(), 0).into(), - format_value(negation_check_y), - ), - ( - ((Any::advice(), 3).into(), 0).into(), - format_value(negation_check_y), - ), - (((Any::advice(), 4).into(), 0).into(), "0".to_string()), - ], - } - ]) - ); - } - } -} diff --git a/halo2_gadgets/src/ecc/chip/witness_point.rs b/halo2_gadgets/src/ecc/chip/witness_point.rs deleted file mode 100644 index ef83bbde54..0000000000 --- a/halo2_gadgets/src/ecc/chip/witness_point.rs +++ /dev/null @@ -1,174 +0,0 @@ -use super::{EccPoint, NonIdentityEccPoint}; - -use group::prime::PrimeCurveAffine; - -use halo2_proofs::{ - circuit::{AssignedCell, Region, Value}, - plonk::{ - Advice, Assigned, Column, ConstraintSystem, Constraints, Error, Expression, Selector, - VirtualCells, - }, - poly::Rotation, -}; -use halo2curves::{pasta::pallas, CurveAffine}; - -type Coordinates = ( - AssignedCell, pallas::Base>, - AssignedCell, pallas::Base>, -); - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct Config { - q_point: Selector, - q_point_non_id: Selector, - // x-coordinate - pub x: Column, - // y-coordinate - pub y: Column, -} - -impl Config { - pub(super) fn configure( - meta: &mut ConstraintSystem, - x: Column, - y: Column, - ) -> Self { - let config = Self { - q_point: meta.selector(), - q_point_non_id: meta.selector(), - x, - y, - }; - - config.create_gate(meta); - - config - } - - fn create_gate(&self, meta: &mut ConstraintSystem) { - let curve_eqn = |meta: &mut VirtualCells| { - let x = meta.query_advice(self.x, Rotation::cur()); - let y = meta.query_advice(self.y, Rotation::cur()); - - // y^2 = x^3 + b - y.square() - (x.clone().square() * x) - Expression::Constant(pallas::Affine::b()) - }; - - // https://p.z.cash/halo2-0.1:ecc-witness-point - meta.create_gate("witness point", |meta| { - // Check that the point being witnessed is either: - // - the identity, which is mapped to (0, 0) in affine coordinates; or - // - a valid curve point y^2 = x^3 + b, where b = 5 in the Pallas equation - - let q_point = meta.query_selector(self.q_point); - let x = meta.query_advice(self.x, Rotation::cur()); - let y = meta.query_advice(self.y, Rotation::cur()); - - // We can't use `Constraints::with_selector` because that creates constraints - // of the form `q_point * (x * curve_eqn)`, but this was implemented without - // parentheses, and thus evaluates as `(q_point * x) * curve_eqn`, which is - // structurally different in the pinned verifying key. - [ - ("x == 0 v on_curve", q_point.clone() * x * curve_eqn(meta)), - ("y == 0 v on_curve", q_point * y * curve_eqn(meta)), - ] - }); - - // https://p.z.cash/halo2-0.1:ecc-witness-non-identity-point - meta.create_gate("witness non-identity point", |meta| { - // Check that the point being witnessed is a valid curve point y^2 = x^3 + b, - // where b = 5 in the Pallas equation - - let q_point_non_id = meta.query_selector(self.q_point_non_id); - - Constraints::with_selector(q_point_non_id, Some(("on_curve", curve_eqn(meta)))) - }); - } - - fn assign_xy( - &self, - value: Value<(Assigned, Assigned)>, - offset: usize, - region: &mut Region<'_, pallas::Base>, - ) -> Result { - // Assign `x` value - let x_val = value.map(|value| value.0); - let x_var = region.assign_advice(|| "x", self.x, offset, || x_val)?; - - // Assign `y` value - let y_val = value.map(|value| value.1); - let y_var = region.assign_advice(|| "y", self.y, offset, || y_val)?; - - Ok((x_var, y_var)) - } - - /// Assigns a point that can be the identity. - pub(super) fn point( - &self, - value: Value, - offset: usize, - region: &mut Region<'_, pallas::Base>, - ) -> Result { - // Enable `q_point` selector - self.q_point.enable(region, offset)?; - - let value = value.map(|value| { - // Map the identity to (0, 0). - if value == pallas::Affine::identity() { - (Assigned::Zero, Assigned::Zero) - } else { - let value = value.coordinates().unwrap(); - (value.x().into(), value.y().into()) - } - }); - - self.assign_xy(value, offset, region) - .map(|(x, y)| EccPoint { x, y }) - } - - /// Assigns a non-identity point. - pub(super) fn point_non_id( - &self, - value: Value, - offset: usize, - region: &mut Region<'_, pallas::Base>, - ) -> Result { - // Enable `q_point_non_id` selector - self.q_point_non_id.enable(region, offset)?; - - // Return an error if the point is the identity. - value.error_if_known_and(|value| value == &pallas::Affine::identity())?; - - let value = value.map(|value| { - let value = value.coordinates().unwrap(); - (value.x().into(), value.y().into()) - }); - - self.assign_xy(value, offset, region) - .map(|(x, y)| NonIdentityEccPoint { x, y }) - } -} - -#[cfg(test)] -pub mod tests { - use halo2_proofs::circuit::Layouter; - use halo2curves::pasta::pallas; - - use super::*; - use crate::ecc::{EccInstructions, NonIdentityPoint}; - - pub fn test_witness_non_id< - EccChip: EccInstructions + Clone + Eq + std::fmt::Debug, - >( - chip: EccChip, - mut layouter: impl Layouter, - ) { - // Witnessing the identity should return an error. - NonIdentityPoint::new( - chip, - layouter.namespace(|| "witness identity"), - Value::known(pallas::Affine::identity()), - ) - .expect_err("witnessing 𝒪 should return an error"); - } -} diff --git a/halo2_gadgets/src/lib.rs b/halo2_gadgets/src/lib.rs deleted file mode 100644 index 8d4d4292b0..0000000000 --- a/halo2_gadgets/src/lib.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! This crate provides various common gadgets and chips for use with `halo2_proofs`. -//! -//! # Gadgets -//! -//! Gadgets are an abstraction for writing reusable and interoperable circuit logic. They -//! do not create any circuit constraints or assignments themselves, instead interacting -//! with the circuit through a defined "instruction set". A circuit developer uses gadgets -//! by instantiating them with a particular choice of chip. -//! -//! # Chips -//! -//! Chips implement the low-level circuit constraints. The same instructions may be -//! implemented by multiple chips, enabling different performance trade-offs to be made. -//! Chips can be highly optimised by their developers, as long as they conform to the -//! defined instructions. - -#![cfg_attr(docsrs, feature(doc_cfg))] -// Temporary until we have more of the crate implemented. -#![allow(dead_code)] -// Catch documentation errors caused by code changes. -#![deny(rustdoc::broken_intra_doc_links)] -#![deny(missing_debug_implementations)] -#![deny(missing_docs)] -#![deny(unsafe_code)] - -pub mod ecc; -pub mod poseidon; -#[cfg(feature = "unstable")] -#[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] -pub mod sha256; -pub mod sinsemilla; -pub mod utilities; diff --git a/halo2_gadgets/src/poseidon.rs b/halo2_gadgets/src/poseidon.rs deleted file mode 100644 index 1350075146..0000000000 --- a/halo2_gadgets/src/poseidon.rs +++ /dev/null @@ -1,297 +0,0 @@ -//! The Poseidon algebraic hash function. - -use std::convert::TryInto; -use std::fmt; -use std::marker::PhantomData; - -use group::ff::Field; -use halo2_proofs::{ - arithmetic::FieldExt, - circuit::{AssignedCell, Chip, Layouter}, - plonk::Error, -}; - -mod pow5; -pub use pow5::{Pow5Chip, Pow5Config, StateWord}; - -pub mod primitives; -use primitives::{Absorbing, ConstantLength, Domain, Spec, SpongeMode, Squeezing, State}; - -/// A word from the padded input to a Poseidon sponge. -#[derive(Clone, Debug)] -pub enum PaddedWord { - /// A message word provided by the prover. - Message(AssignedCell), - /// A padding word, that will be fixed in the circuit parameters. - Padding(F), -} - -/// The set of circuit instructions required to use the Poseidon permutation. -pub trait PoseidonInstructions, const T: usize, const RATE: usize>: - Chip -{ - /// Variable representing the word over which the Poseidon permutation operates. - type Word: Clone + fmt::Debug + From> + Into>; - - /// Applies the Poseidon permutation to the given state. - fn permute( - &self, - layouter: &mut impl Layouter, - initial_state: &State, - ) -> Result, Error>; -} - -/// The set of circuit instructions required to use the [`Sponge`] and [`Hash`] gadgets. -/// -/// [`Hash`]: self::Hash -pub trait PoseidonSpongeInstructions< - F: FieldExt, - S: Spec, - D: Domain, - const T: usize, - const RATE: usize, ->: PoseidonInstructions -{ - /// Returns the initial empty state for the given domain. - fn initial_state(&self, layouter: &mut impl Layouter) - -> Result, Error>; - - /// Adds the given input to the state. - fn add_input( - &self, - layouter: &mut impl Layouter, - initial_state: &State, - input: &Absorbing, RATE>, - ) -> Result, Error>; - - /// Extracts sponge output from the given state. - fn get_output(state: &State) -> Squeezing; -} - -/// A word over which the Poseidon permutation operates. -#[derive(Debug)] -pub struct Word< - F: FieldExt, - PoseidonChip: PoseidonInstructions, - S: Spec, - const T: usize, - const RATE: usize, -> { - inner: PoseidonChip::Word, -} - -impl< - F: FieldExt, - PoseidonChip: PoseidonInstructions, - S: Spec, - const T: usize, - const RATE: usize, - > Word -{ - /// The word contained in this gadget. - pub fn inner(&self) -> PoseidonChip::Word { - self.inner.clone() - } - - /// Construct a [`Word`] gadget from the inner word. - pub fn from_inner(inner: PoseidonChip::Word) -> Self { - Self { inner } - } -} - -fn poseidon_sponge< - F: FieldExt, - PoseidonChip: PoseidonSpongeInstructions, - S: Spec, - D: Domain, - const T: usize, - const RATE: usize, ->( - chip: &PoseidonChip, - mut layouter: impl Layouter, - state: &mut State, - input: Option<&Absorbing, RATE>>, -) -> Result, Error> { - if let Some(input) = input { - *state = chip.add_input(&mut layouter, state, input)?; - } - *state = chip.permute(&mut layouter, state)?; - Ok(PoseidonChip::get_output(state)) -} - -/// A Poseidon sponge. -#[derive(Debug)] -pub struct Sponge< - F: FieldExt, - PoseidonChip: PoseidonSpongeInstructions, - S: Spec, - M: SpongeMode, - D: Domain, - const T: usize, - const RATE: usize, -> { - chip: PoseidonChip, - mode: M, - state: State, - _marker: PhantomData, -} - -impl< - F: FieldExt, - PoseidonChip: PoseidonSpongeInstructions, - S: Spec, - D: Domain, - const T: usize, - const RATE: usize, - > Sponge, RATE>, D, T, RATE> -{ - /// Constructs a new duplex sponge for the given Poseidon specification. - pub fn new(chip: PoseidonChip, mut layouter: impl Layouter) -> Result { - chip.initial_state(&mut layouter).map(|state| Sponge { - chip, - mode: Absorbing( - (0..RATE) - .map(|_| None) - .collect::>() - .try_into() - .unwrap(), - ), - state, - _marker: PhantomData::default(), - }) - } - - /// Absorbs an element into the sponge. - pub fn absorb( - &mut self, - mut layouter: impl Layouter, - value: PaddedWord, - ) -> Result<(), Error> { - for entry in self.mode.0.iter_mut() { - if entry.is_none() { - *entry = Some(value); - return Ok(()); - } - } - - // We've already absorbed as many elements as we can - let _ = poseidon_sponge( - &self.chip, - layouter.namespace(|| "PoseidonSponge"), - &mut self.state, - Some(&self.mode), - )?; - self.mode = Absorbing::init_with(value); - - Ok(()) - } - - /// Transitions the sponge into its squeezing state. - #[allow(clippy::type_complexity)] - pub fn finish_absorbing( - mut self, - mut layouter: impl Layouter, - ) -> Result, D, T, RATE>, Error> - { - let mode = poseidon_sponge( - &self.chip, - layouter.namespace(|| "PoseidonSponge"), - &mut self.state, - Some(&self.mode), - )?; - - Ok(Sponge { - chip: self.chip, - mode, - state: self.state, - _marker: PhantomData::default(), - }) - } -} - -impl< - F: FieldExt, - PoseidonChip: PoseidonSpongeInstructions, - S: Spec, - D: Domain, - const T: usize, - const RATE: usize, - > Sponge, D, T, RATE> -{ - /// Squeezes an element from the sponge. - pub fn squeeze(&mut self, mut layouter: impl Layouter) -> Result, Error> { - loop { - for entry in self.mode.0.iter_mut() { - if let Some(inner) = entry.take() { - return Ok(inner.into()); - } - } - - // We've already squeezed out all available elements - self.mode = poseidon_sponge( - &self.chip, - layouter.namespace(|| "PoseidonSponge"), - &mut self.state, - None, - )?; - } - } -} - -/// A Poseidon hash function, built around a sponge. -#[derive(Debug)] -pub struct Hash< - F: FieldExt, - PoseidonChip: PoseidonSpongeInstructions, - S: Spec, - D: Domain, - const T: usize, - const RATE: usize, -> { - sponge: Sponge, RATE>, D, T, RATE>, -} - -impl< - F: FieldExt, - PoseidonChip: PoseidonSpongeInstructions, - S: Spec, - D: Domain, - const T: usize, - const RATE: usize, - > Hash -{ - /// Initializes a new hasher. - pub fn init(chip: PoseidonChip, layouter: impl Layouter) -> Result { - Sponge::new(chip, layouter).map(|sponge| Hash { sponge }) - } -} - -impl< - F: FieldExt, - PoseidonChip: PoseidonSpongeInstructions, T, RATE>, - S: Spec, - const T: usize, - const RATE: usize, - const L: usize, - > Hash, T, RATE> -{ - /// Hashes the given input. - pub fn hash( - mut self, - mut layouter: impl Layouter, - message: [AssignedCell; L], - ) -> Result, Error> { - for (i, value) in message - .into_iter() - .map(PaddedWord::Message) - .chain( as Domain>::padding(L).map(PaddedWord::Padding)) - .enumerate() - { - self.sponge - .absorb(layouter.namespace(|| format!("absorb_{}", i)), value)?; - } - self.sponge - .finish_absorbing(layouter.namespace(|| "finish absorbing"))? - .squeeze(layouter.namespace(|| "squeeze")) - } -} diff --git a/halo2_gadgets/src/poseidon/pow5.rs b/halo2_gadgets/src/poseidon/pow5.rs deleted file mode 100644 index 7b9862e5b6..0000000000 --- a/halo2_gadgets/src/poseidon/pow5.rs +++ /dev/null @@ -1,888 +0,0 @@ -use std::convert::TryInto; -use std::iter; - -use halo2_proofs::{ - arithmetic::FieldExt, - circuit::{AssignedCell, Cell, Chip, Layouter, Region, Value}, - plonk::{ - Advice, Any, Column, ConstraintSystem, Constraints, Error, Expression, Fixed, Selector, - }, - poly::Rotation, -}; - -use super::{ - primitives::{Absorbing, Domain, Mds, Spec, Squeezing, State}, - PaddedWord, PoseidonInstructions, PoseidonSpongeInstructions, -}; -use crate::utilities::Var; - -/// Configuration for a [`Pow5Chip`]. -#[derive(Clone, Debug)] -pub struct Pow5Config { - pub(crate) state: [Column; WIDTH], - partial_sbox: Column, - rc_a: [Column; WIDTH], - rc_b: [Column; WIDTH], - s_full: Selector, - s_partial: Selector, - s_pad_and_add: Selector, - - half_full_rounds: usize, - half_partial_rounds: usize, - alpha: [u64; 4], - round_constants: Vec<[F; WIDTH]>, - m_reg: Mds, - m_inv: Mds, -} - -/// A Poseidon chip using an $x^5$ S-Box. -/// -/// The chip is implemented using a single round per row for full rounds, and two rounds -/// per row for partial rounds. -#[derive(Debug)] -pub struct Pow5Chip { - config: Pow5Config, -} - -impl Pow5Chip { - /// Configures this chip for use in a circuit. - /// - /// # Side-effects - /// - /// All columns in `state` will be equality-enabled. - // - // TODO: Does the rate need to be hard-coded here, or only the width? It probably - // needs to be known wherever we implement the hashing gadget, but it isn't strictly - // necessary for the permutation. - pub fn configure>( - meta: &mut ConstraintSystem, - state: [Column; WIDTH], - partial_sbox: Column, - rc_a: [Column; WIDTH], - rc_b: [Column; WIDTH], - ) -> Pow5Config { - assert_eq!(RATE, WIDTH - 1); - // Generate constants for the Poseidon permutation. - // This gadget requires R_F and R_P to be even. - assert!(S::full_rounds() & 1 == 0); - assert!(S::partial_rounds() & 1 == 0); - let half_full_rounds = S::full_rounds() / 2; - let half_partial_rounds = S::partial_rounds() / 2; - let (round_constants, m_reg, m_inv) = S::constants(); - - // This allows state words to be initialized (by constraining them equal to fixed - // values), and used in a permutation from an arbitrary region. rc_a is used in - // every permutation round, while rc_b is empty in the initial and final full - // rounds, so we use rc_b as "scratch space" for fixed values (enabling potential - // layouter optimisations). - for column in iter::empty() - .chain(state.iter().cloned().map(Column::::from)) - .chain(rc_b.iter().cloned().map(Column::::from)) - { - meta.enable_equality(column); - } - - let s_full = meta.selector(); - let s_partial = meta.selector(); - let s_pad_and_add = meta.selector(); - - let alpha = [5, 0, 0, 0]; - let pow_5 = |v: Expression| { - let v2 = v.clone() * v.clone(); - v2.clone() * v2 * v - }; - - meta.create_gate("full round", |meta| { - let s_full = meta.query_selector(s_full); - - Constraints::with_selector( - s_full, - (0..WIDTH) - .map(|next_idx| { - let state_next = meta.query_advice(state[next_idx], Rotation::next()); - let expr = (0..WIDTH) - .map(|idx| { - let state_cur = meta.query_advice(state[idx], Rotation::cur()); - let rc_a = meta.query_fixed(rc_a[idx], Rotation::cur()); - pow_5(state_cur + rc_a) * m_reg[next_idx][idx] - }) - .reduce(|acc, term| acc + term) - .expect("WIDTH > 0"); - expr - state_next - }) - .collect::>(), - ) - }); - - meta.create_gate("partial rounds", |meta| { - let cur_0 = meta.query_advice(state[0], Rotation::cur()); - let mid_0 = meta.query_advice(partial_sbox, Rotation::cur()); - - let rc_a0 = meta.query_fixed(rc_a[0], Rotation::cur()); - let rc_b0 = meta.query_fixed(rc_b[0], Rotation::cur()); - - let s_partial = meta.query_selector(s_partial); - - use halo2_proofs::plonk::VirtualCells; - let mid = |idx: usize, meta: &mut VirtualCells| { - let mid = mid_0.clone() * m_reg[idx][0]; - (1..WIDTH).fold(mid, |acc, cur_idx| { - let cur = meta.query_advice(state[cur_idx], Rotation::cur()); - let rc_a = meta.query_fixed(rc_a[cur_idx], Rotation::cur()); - acc + (cur + rc_a) * m_reg[idx][cur_idx] - }) - }; - - let next = |idx: usize, meta: &mut VirtualCells| { - (0..WIDTH) - .map(|next_idx| { - let next = meta.query_advice(state[next_idx], Rotation::next()); - next * m_inv[idx][next_idx] - }) - .reduce(|acc, next| acc + next) - .expect("WIDTH > 0") - }; - - let partial_round_linear = |idx: usize, meta: &mut VirtualCells| { - let rc_b = meta.query_fixed(rc_b[idx], Rotation::cur()); - mid(idx, meta) + rc_b - next(idx, meta) - }; - - Constraints::with_selector( - s_partial, - std::iter::empty() - // state[0] round a - .chain(Some(pow_5(cur_0 + rc_a0) - mid_0.clone())) - // state[0] round b - .chain(Some(pow_5(mid(0, meta) + rc_b0) - next(0, meta))) - .chain((1..WIDTH).map(|idx| partial_round_linear(idx, meta))) - .collect::>(), - ) - }); - - meta.create_gate("pad-and-add", |meta| { - let initial_state_rate = meta.query_advice(state[RATE], Rotation::prev()); - let output_state_rate = meta.query_advice(state[RATE], Rotation::next()); - - let s_pad_and_add = meta.query_selector(s_pad_and_add); - - let pad_and_add = |idx: usize| { - let initial_state = meta.query_advice(state[idx], Rotation::prev()); - let input = meta.query_advice(state[idx], Rotation::cur()); - let output_state = meta.query_advice(state[idx], Rotation::next()); - - // We pad the input by storing the required padding in fixed columns and - // then constraining the corresponding input columns to be equal to it. - initial_state + input - output_state - }; - - Constraints::with_selector( - s_pad_and_add, - (0..RATE) - .map(pad_and_add) - // The capacity element is never altered by the input. - .chain(Some(initial_state_rate - output_state_rate)) - .collect::>(), - ) - }); - - Pow5Config { - state, - partial_sbox, - rc_a, - rc_b, - s_full, - s_partial, - s_pad_and_add, - half_full_rounds, - half_partial_rounds, - alpha, - round_constants, - m_reg, - m_inv, - } - } - - /// Construct a [`Pow5Chip`]. - pub fn construct(config: Pow5Config) -> Self { - Pow5Chip { config } - } -} - -impl Chip for Pow5Chip { - type Config = Pow5Config; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -impl, const WIDTH: usize, const RATE: usize> - PoseidonInstructions for Pow5Chip -{ - type Word = StateWord; - - fn permute( - &self, - layouter: &mut impl Layouter, - initial_state: &State, - ) -> Result, Error> { - let config = self.config(); - - layouter.assign_region( - || "permute state", - |mut region| { - // Load the initial state into this region. - let state = Pow5State::load(&mut region, config, initial_state)?; - - let state = (0..config.half_full_rounds).fold(Ok(state), |res, r| { - res.and_then(|state| state.full_round(&mut region, config, r, r)) - })?; - - let state = (0..config.half_partial_rounds).fold(Ok(state), |res, r| { - res.and_then(|state| { - state.partial_round( - &mut region, - config, - config.half_full_rounds + 2 * r, - config.half_full_rounds + r, - ) - }) - })?; - - let state = (0..config.half_full_rounds).fold(Ok(state), |res, r| { - res.and_then(|state| { - state.full_round( - &mut region, - config, - config.half_full_rounds + 2 * config.half_partial_rounds + r, - config.half_full_rounds + config.half_partial_rounds + r, - ) - }) - })?; - - Ok(state.0) - }, - ) - } -} - -impl< - F: FieldExt, - S: Spec, - D: Domain, - const WIDTH: usize, - const RATE: usize, - > PoseidonSpongeInstructions for Pow5Chip -{ - fn initial_state( - &self, - layouter: &mut impl Layouter, - ) -> Result, Error> { - let config = self.config(); - let state = layouter.assign_region( - || format!("initial state for domain {}", D::name()), - |mut region| { - let mut state = Vec::with_capacity(WIDTH); - let mut load_state_word = |i: usize, value: F| -> Result<_, Error> { - let var = region.assign_advice_from_constant( - || format!("state_{}", i), - config.state[i], - 0, - value, - )?; - state.push(StateWord(var)); - - Ok(()) - }; - - for i in 0..RATE { - load_state_word(i, F::zero())?; - } - load_state_word(RATE, D::initial_capacity_element())?; - - Ok(state) - }, - )?; - - Ok(state.try_into().unwrap()) - } - - fn add_input( - &self, - layouter: &mut impl Layouter, - initial_state: &State, - input: &Absorbing, RATE>, - ) -> Result, Error> { - let config = self.config(); - layouter.assign_region( - || format!("add input for domain {}", D::name()), - |mut region| { - config.s_pad_and_add.enable(&mut region, 1)?; - - // Load the initial state into this region. - let load_state_word = |i: usize| { - initial_state[i] - .0 - .copy_advice( - || format!("load state_{}", i), - &mut region, - config.state[i], - 0, - ) - .map(StateWord) - }; - let initial_state: Result, Error> = - (0..WIDTH).map(load_state_word).collect(); - let initial_state = initial_state?; - - // Load the input into this region. - let load_input_word = |i: usize| { - let constraint_var = match input.0[i].clone() { - Some(PaddedWord::Message(word)) => word, - Some(PaddedWord::Padding(padding_value)) => region.assign_fixed( - || format!("load pad_{}", i), - config.rc_b[i], - 1, - || Value::known(padding_value), - )?, - _ => panic!("Input is not padded"), - }; - constraint_var - .copy_advice( - || format!("load input_{}", i), - &mut region, - config.state[i], - 1, - ) - .map(StateWord) - }; - let input: Result, Error> = (0..RATE).map(load_input_word).collect(); - let input = input?; - - // Constrain the output. - let constrain_output_word = |i: usize| { - let value = initial_state[i].0.value().copied() - + input - .get(i) - .map(|word| word.0.value().cloned()) - // The capacity element is never altered by the input. - .unwrap_or_else(|| Value::known(F::zero())); - region - .assign_advice( - || format!("load output_{}", i), - config.state[i], - 2, - || value, - ) - .map(StateWord) - }; - - let output: Result, Error> = (0..WIDTH).map(constrain_output_word).collect(); - output.map(|output| output.try_into().unwrap()) - }, - ) - } - - fn get_output(state: &State) -> Squeezing { - Squeezing( - state[..RATE] - .iter() - .map(|word| Some(word.clone())) - .collect::>() - .try_into() - .unwrap(), - ) - } -} - -/// A word in the Poseidon state. -#[derive(Clone, Debug)] -pub struct StateWord(AssignedCell); - -impl From> for AssignedCell { - fn from(state_word: StateWord) -> AssignedCell { - state_word.0 - } -} - -impl From> for StateWord { - fn from(cell_value: AssignedCell) -> StateWord { - StateWord(cell_value) - } -} - -impl Var for StateWord { - fn cell(&self) -> Cell { - self.0.cell() - } - - fn value(&self) -> Value { - self.0.value().cloned() - } -} - -#[derive(Debug)] -struct Pow5State([StateWord; WIDTH]); - -impl Pow5State { - fn full_round( - self, - region: &mut Region, - config: &Pow5Config, - round: usize, - offset: usize, - ) -> Result { - Self::round(region, config, round, offset, config.s_full, |_| { - let q = self.0.iter().enumerate().map(|(idx, word)| { - word.0 - .value() - .map(|v| *v + config.round_constants[round][idx]) - }); - let r: Value> = q.map(|q| q.map(|q| q.pow(&config.alpha))).collect(); - let m = &config.m_reg; - let state = m.iter().map(|m_i| { - r.as_ref().map(|r| { - r.iter() - .enumerate() - .fold(F::zero(), |acc, (j, r_j)| acc + m_i[j] * r_j) - }) - }); - - Ok((round + 1, state.collect::>().try_into().unwrap())) - }) - } - - fn partial_round( - self, - region: &mut Region, - config: &Pow5Config, - round: usize, - offset: usize, - ) -> Result { - Self::round(region, config, round, offset, config.s_partial, |region| { - let m = &config.m_reg; - let p: Value> = self.0.iter().map(|word| word.0.value().cloned()).collect(); - - let r: Value> = p.map(|p| { - let r_0 = (p[0] + config.round_constants[round][0]).pow(&config.alpha); - let r_i = p[1..] - .iter() - .enumerate() - .map(|(i, p_i)| *p_i + config.round_constants[round][i + 1]); - std::iter::empty().chain(Some(r_0)).chain(r_i).collect() - }); - - region.assign_advice( - || format!("round_{} partial_sbox", round), - config.partial_sbox, - offset, - || r.as_ref().map(|r| r[0]), - )?; - - let p_mid: Value> = m - .iter() - .map(|m_i| { - r.as_ref().map(|r| { - m_i.iter() - .zip(r.iter()) - .fold(F::zero(), |acc, (m_ij, r_j)| acc + *m_ij * r_j) - }) - }) - .collect(); - - // Load the second round constants. - let mut load_round_constant = |i: usize| { - region.assign_fixed( - || format!("round_{} rc_{}", round + 1, i), - config.rc_b[i], - offset, - || Value::known(config.round_constants[round + 1][i]), - ) - }; - for i in 0..WIDTH { - load_round_constant(i)?; - } - - let r_mid: Value> = p_mid.map(|p| { - let r_0 = (p[0] + config.round_constants[round + 1][0]).pow(&config.alpha); - let r_i = p[1..] - .iter() - .enumerate() - .map(|(i, p_i)| *p_i + config.round_constants[round + 1][i + 1]); - std::iter::empty().chain(Some(r_0)).chain(r_i).collect() - }); - - let state: Vec> = m - .iter() - .map(|m_i| { - r_mid.as_ref().map(|r| { - m_i.iter() - .zip(r.iter()) - .fold(F::zero(), |acc, (m_ij, r_j)| acc + *m_ij * r_j) - }) - }) - .collect(); - - Ok((round + 2, state.try_into().unwrap())) - }) - } - - fn load( - region: &mut Region, - config: &Pow5Config, - initial_state: &State, WIDTH>, - ) -> Result { - let load_state_word = |i: usize| { - initial_state[i] - .0 - .copy_advice(|| format!("load state_{}", i), region, config.state[i], 0) - .map(StateWord) - }; - - let state: Result, _> = (0..WIDTH).map(load_state_word).collect(); - state.map(|state| Pow5State(state.try_into().unwrap())) - } - - fn round( - region: &mut Region, - config: &Pow5Config, - round: usize, - offset: usize, - round_gate: Selector, - round_fn: impl FnOnce(&mut Region) -> Result<(usize, [Value; WIDTH]), Error>, - ) -> Result { - // Enable the required gate. - round_gate.enable(region, offset)?; - - // Load the round constants. - let mut load_round_constant = |i: usize| { - region.assign_fixed( - || format!("round_{} rc_{}", round, i), - config.rc_a[i], - offset, - || Value::known(config.round_constants[round][i]), - ) - }; - for i in 0..WIDTH { - load_round_constant(i)?; - } - - // Compute the next round's state. - let (next_round, next_state) = round_fn(region)?; - - let next_state_word = |i: usize| { - let value = next_state[i]; - let var = region.assign_advice( - || format!("round_{} state_{}", next_round, i), - config.state[i], - offset + 1, - || value, - )?; - Ok(StateWord(var)) - }; - - let next_state: Result, _> = (0..WIDTH).map(next_state_word).collect(); - next_state.map(|next_state| Pow5State(next_state.try_into().unwrap())) - } -} - -#[cfg(test)] -mod tests { - use group::ff::{Field, PrimeField}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use halo2curves::pasta::{pallas, Fp}; - use rand::rngs::OsRng; - - use super::{PoseidonInstructions, Pow5Chip, Pow5Config, StateWord}; - use crate::poseidon::{ - primitives::{self as poseidon, ConstantLength, P128Pow5T3 as OrchardNullifier, Spec}, - Hash, - }; - use std::convert::TryInto; - use std::marker::PhantomData; - - struct PermuteCircuit, const WIDTH: usize, const RATE: usize>( - PhantomData, - ); - - impl, const WIDTH: usize, const RATE: usize> Circuit - for PermuteCircuit - { - type Config = Pow5Config; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - PermuteCircuit::(PhantomData) - } - - fn configure(meta: &mut ConstraintSystem) -> Pow5Config { - let state = (0..WIDTH).map(|_| meta.advice_column()).collect::>(); - let partial_sbox = meta.advice_column(); - - let rc_a = (0..WIDTH).map(|_| meta.fixed_column()).collect::>(); - let rc_b = (0..WIDTH).map(|_| meta.fixed_column()).collect::>(); - - Pow5Chip::configure::( - meta, - state.try_into().unwrap(), - partial_sbox, - rc_a.try_into().unwrap(), - rc_b.try_into().unwrap(), - ) - } - - fn synthesize( - &self, - config: Pow5Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let initial_state = layouter.assign_region( - || "prepare initial state", - |mut region| { - let state_word = |i: usize| { - let value = Value::known(Fp::from(i as u64)); - let var = region.assign_advice( - || format!("load state_{}", i), - config.state[i], - 0, - || value, - )?; - Ok(StateWord(var)) - }; - - let state: Result, Error> = (0..WIDTH).map(state_word).collect(); - Ok(state?.try_into().unwrap()) - }, - )?; - - let chip = Pow5Chip::construct(config.clone()); - let final_state = as PoseidonInstructions< - Fp, - S, - WIDTH, - RATE, - >>::permute(&chip, &mut layouter, &initial_state)?; - - // For the purpose of this test, compute the real final state inline. - let mut expected_final_state = (0..WIDTH) - .map(|idx| Fp::from(idx as u64)) - .collect::>() - .try_into() - .unwrap(); - let (round_constants, mds, _) = S::constants(); - poseidon::permute::<_, S, WIDTH, RATE>( - &mut expected_final_state, - &mds, - &round_constants, - ); - - layouter.assign_region( - || "constrain final state", - |mut region| { - let mut final_state_word = |i: usize| { - let var = region.assign_advice( - || format!("load final_state_{}", i), - config.state[i], - 0, - || Value::known(expected_final_state[i]), - )?; - region.constrain_equal(final_state[i].0.cell(), var.cell()) - }; - - for i in 0..(WIDTH) { - final_state_word(i)?; - } - - Ok(()) - }, - ) - } - } - - #[test] - fn poseidon_permute() { - let k = 6; - let circuit = PermuteCircuit::(PhantomData); - let prover = MockProver::run(k, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())) - } - - struct HashCircuit< - S: Spec, - const WIDTH: usize, - const RATE: usize, - const L: usize, - > { - message: Value<[Fp; L]>, - // For the purpose of this test, witness the result. - // TODO: Move this into an instance column. - output: Value, - _spec: PhantomData, - } - - impl, const WIDTH: usize, const RATE: usize, const L: usize> - Circuit for HashCircuit - { - type Config = Pow5Config; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self { - message: Value::unknown(), - output: Value::unknown(), - _spec: PhantomData, - } - } - - fn configure(meta: &mut ConstraintSystem) -> Pow5Config { - let state = (0..WIDTH).map(|_| meta.advice_column()).collect::>(); - let partial_sbox = meta.advice_column(); - - let rc_a = (0..WIDTH).map(|_| meta.fixed_column()).collect::>(); - let rc_b = (0..WIDTH).map(|_| meta.fixed_column()).collect::>(); - - meta.enable_constant(rc_b[0]); - - Pow5Chip::configure::( - meta, - state.try_into().unwrap(), - partial_sbox, - rc_a.try_into().unwrap(), - rc_b.try_into().unwrap(), - ) - } - - fn synthesize( - &self, - config: Pow5Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let chip = Pow5Chip::construct(config.clone()); - - let message = layouter.assign_region( - || "load message", - |mut region| { - let message_word = |i: usize| { - let value = self.message.map(|message_vals| message_vals[i]); - region.assign_advice( - || format!("load message_{}", i), - config.state[i], - 0, - || value, - ) - }; - - let message: Result, Error> = (0..L).map(message_word).collect(); - Ok(message?.try_into().unwrap()) - }, - )?; - - let hasher = Hash::<_, _, S, ConstantLength, WIDTH, RATE>::init( - chip, - layouter.namespace(|| "init"), - )?; - let output = hasher.hash(layouter.namespace(|| "hash"), message)?; - - layouter.assign_region( - || "constrain output", - |mut region| { - let expected_var = region.assign_advice( - || "load output", - config.state[0], - 0, - || self.output, - )?; - region.constrain_equal(output.cell(), expected_var.cell()) - }, - ) - } - } - - #[test] - fn poseidon_hash() { - let rng = OsRng; - - let message = [Fp::random(rng), Fp::random(rng)]; - let output = - poseidon::Hash::<_, OrchardNullifier, ConstantLength<2>, 3, 2>::init().hash(message); - - let k = 6; - let circuit = HashCircuit:: { - message: Value::known(message), - output: Value::known(output), - _spec: PhantomData, - }; - let prover = MockProver::run(k, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())) - } - - #[test] - fn poseidon_hash_longer_input() { - let rng = OsRng; - - let message = [Fp::random(rng), Fp::random(rng), Fp::random(rng)]; - let output = - poseidon::Hash::<_, OrchardNullifier, ConstantLength<3>, 3, 2>::init().hash(message); - - let k = 7; - let circuit = HashCircuit:: { - message: Value::known(message), - output: Value::known(output), - _spec: PhantomData, - }; - let prover = MockProver::run(k, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())) - } - - #[test] - fn hash_test_vectors() { - for tv in crate::poseidon::primitives::test_vectors::fp::hash() { - let message = [ - pallas::Base::from_repr(tv.input[0]).unwrap(), - pallas::Base::from_repr(tv.input[1]).unwrap(), - ]; - let output = poseidon::Hash::<_, OrchardNullifier, ConstantLength<2>, 3, 2>::init() - .hash(message); - - let k = 6; - let circuit = HashCircuit:: { - message: Value::known(message), - output: Value::known(output), - _spec: PhantomData, - }; - let prover = MockProver::run(k, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - } - - #[cfg(feature = "dev-graph")] - #[test] - fn print_poseidon_chip() { - use plotters::prelude::*; - - let root = BitMapBackend::new("poseidon-chip-layout.png", (1024, 768)).into_drawing_area(); - root.fill(&WHITE).unwrap(); - let root = root - .titled("Poseidon Chip Layout", ("sans-serif", 60)) - .unwrap(); - - let circuit = HashCircuit:: { - message: Value::unknown(), - output: Value::unknown(), - _spec: PhantomData, - }; - halo2_proofs::dev::CircuitLayout::default() - .render(6, &circuit, &root) - .unwrap(); - } -} diff --git a/halo2_gadgets/src/poseidon/primitives.rs b/halo2_gadgets/src/poseidon/primitives.rs deleted file mode 100644 index 4d7d5b038a..0000000000 --- a/halo2_gadgets/src/poseidon/primitives.rs +++ /dev/null @@ -1,396 +0,0 @@ -//! The Poseidon algebraic hash function. - -use std::convert::TryInto; -use std::fmt; -use std::iter; -use std::marker::PhantomData; - -use halo2_proofs::arithmetic::FieldExt; - -pub(crate) mod fp; -pub(crate) mod fq; -pub(crate) mod grain; -pub(crate) mod mds; - -#[cfg(test)] -pub(crate) mod test_vectors; - -mod p128pow5t3; -pub use p128pow5t3::P128Pow5T3; - -use grain::SboxType; - -/// The type used to hold permutation state. -pub(crate) type State = [F; T]; - -/// The type used to hold sponge rate. -pub(crate) type SpongeRate = [Option; RATE]; - -/// The type used to hold the MDS matrix and its inverse. -pub(crate) type Mds = [[F; T]; T]; - -/// A specification for a Poseidon permutation. -pub trait Spec: fmt::Debug { - /// The number of full rounds for this specification. - /// - /// This must be an even number. - fn full_rounds() -> usize; - - /// The number of partial rounds for this specification. - fn partial_rounds() -> usize; - - /// The S-box for this specification. - fn sbox(val: F) -> F; - - /// Side-loaded index of the first correct and secure MDS that will be generated by - /// the reference implementation. - /// - /// This is used by the default implementation of [`Spec::constants`]. If you are - /// hard-coding the constants, you may leave this unimplemented. - fn secure_mds() -> usize; - - /// Generates `(round_constants, mds, mds^-1)` corresponding to this specification. - fn constants() -> (Vec<[F; T]>, Mds, Mds) { - let r_f = Self::full_rounds(); - let r_p = Self::partial_rounds(); - - let mut grain = grain::Grain::new(SboxType::Pow, T as u16, r_f as u16, r_p as u16); - - let round_constants = (0..(r_f + r_p)) - .map(|_| { - let mut rc_row = [F::zero(); T]; - for (rc, value) in rc_row - .iter_mut() - .zip((0..T).map(|_| grain.next_field_element())) - { - *rc = value; - } - rc_row - }) - .collect(); - - let (mds, mds_inv) = mds::generate_mds::(&mut grain, Self::secure_mds()); - - (round_constants, mds, mds_inv) - } -} - -/// Runs the Poseidon permutation on the given state. -pub(crate) fn permute, const T: usize, const RATE: usize>( - state: &mut State, - mds: &Mds, - round_constants: &[[F; T]], -) { - let r_f = S::full_rounds() / 2; - let r_p = S::partial_rounds(); - - let apply_mds = |state: &mut State| { - let mut new_state = [F::zero(); T]; - // Matrix multiplication - #[allow(clippy::needless_range_loop)] - for i in 0..T { - for j in 0..T { - new_state[i] += mds[i][j] * state[j]; - } - } - *state = new_state; - }; - - let full_round = |state: &mut State, rcs: &[F; T]| { - for (word, rc) in state.iter_mut().zip(rcs.iter()) { - *word = S::sbox(*word + rc); - } - apply_mds(state); - }; - - let part_round = |state: &mut State, rcs: &[F; T]| { - for (word, rc) in state.iter_mut().zip(rcs.iter()) { - *word += rc; - } - // In a partial round, the S-box is only applied to the first state word. - state[0] = S::sbox(state[0]); - apply_mds(state); - }; - - iter::empty() - .chain(iter::repeat(&full_round as &dyn Fn(&mut State, &[F; T])).take(r_f)) - .chain(iter::repeat(&part_round as &dyn Fn(&mut State, &[F; T])).take(r_p)) - .chain(iter::repeat(&full_round as &dyn Fn(&mut State, &[F; T])).take(r_f)) - .zip(round_constants.iter()) - .fold(state, |state, (round, rcs)| { - round(state, rcs); - state - }); -} - -fn poseidon_sponge, const T: usize, const RATE: usize>( - state: &mut State, - input: Option<&Absorbing>, - mds_matrix: &Mds, - round_constants: &[[F; T]], -) -> Squeezing { - if let Some(Absorbing(input)) = input { - // `Iterator::zip` short-circuits when one iterator completes, so this will only - // mutate the rate portion of the state. - for (word, value) in state.iter_mut().zip(input.iter()) { - *word += value.expect("poseidon_sponge is called with a padded input"); - } - } - - permute::(state, mds_matrix, round_constants); - - let mut output = [None; RATE]; - for (word, value) in output.iter_mut().zip(state.iter()) { - *word = Some(*value); - } - Squeezing(output) -} - -mod private { - pub trait SealedSpongeMode {} - impl SealedSpongeMode for super::Absorbing {} - impl SealedSpongeMode for super::Squeezing {} -} - -/// The state of the `Sponge`. -pub trait SpongeMode: private::SealedSpongeMode {} - -/// The absorbing state of the `Sponge`. -#[derive(Debug)] -pub struct Absorbing(pub(crate) SpongeRate); - -/// The squeezing state of the `Sponge`. -#[derive(Debug)] -pub struct Squeezing(pub(crate) SpongeRate); - -impl SpongeMode for Absorbing {} -impl SpongeMode for Squeezing {} - -impl Absorbing { - pub(crate) fn init_with(val: F) -> Self { - Self( - iter::once(Some(val)) - .chain((1..RATE).map(|_| None)) - .collect::>() - .try_into() - .unwrap(), - ) - } -} - -/// A Poseidon sponge. -pub(crate) struct Sponge< - F: FieldExt, - S: Spec, - M: SpongeMode, - const T: usize, - const RATE: usize, -> { - mode: M, - state: State, - mds_matrix: Mds, - round_constants: Vec<[F; T]>, - _marker: PhantomData, -} - -impl, const T: usize, const RATE: usize> - Sponge, T, RATE> -{ - /// Constructs a new sponge for the given Poseidon specification. - pub(crate) fn new(initial_capacity_element: F) -> Self { - let (round_constants, mds_matrix, _) = S::constants(); - - let mode = Absorbing([None; RATE]); - let mut state = [F::zero(); T]; - state[RATE] = initial_capacity_element; - - Sponge { - mode, - state, - mds_matrix, - round_constants, - _marker: PhantomData::default(), - } - } - - /// Absorbs an element into the sponge. - pub(crate) fn absorb(&mut self, value: F) { - for entry in self.mode.0.iter_mut() { - if entry.is_none() { - *entry = Some(value); - return; - } - } - - // We've already absorbed as many elements as we can - let _ = poseidon_sponge::( - &mut self.state, - Some(&self.mode), - &self.mds_matrix, - &self.round_constants, - ); - self.mode = Absorbing::init_with(value); - } - - /// Transitions the sponge into its squeezing state. - pub(crate) fn finish_absorbing(mut self) -> Sponge, T, RATE> { - let mode = poseidon_sponge::( - &mut self.state, - Some(&self.mode), - &self.mds_matrix, - &self.round_constants, - ); - - Sponge { - mode, - state: self.state, - mds_matrix: self.mds_matrix, - round_constants: self.round_constants, - _marker: PhantomData::default(), - } - } -} - -impl, const T: usize, const RATE: usize> - Sponge, T, RATE> -{ - /// Squeezes an element from the sponge. - pub(crate) fn squeeze(&mut self) -> F { - loop { - for entry in self.mode.0.iter_mut() { - if let Some(e) = entry.take() { - return e; - } - } - - // We've already squeezed out all available elements - self.mode = poseidon_sponge::( - &mut self.state, - None, - &self.mds_matrix, - &self.round_constants, - ); - } - } -} - -/// A domain in which a Poseidon hash function is being used. -pub trait Domain { - /// Iterator that outputs padding field elements. - type Padding: IntoIterator; - - /// The name of this domain, for debug formatting purposes. - fn name() -> String; - - /// The initial capacity element, encoding this domain. - fn initial_capacity_element() -> F; - - /// Returns the padding to be appended to the input. - fn padding(input_len: usize) -> Self::Padding; -} - -/// A Poseidon hash function used with constant input length. -/// -/// Domain specified in [ePrint 2019/458 section 4.2](https://eprint.iacr.org/2019/458.pdf). -#[derive(Clone, Copy, Debug)] -pub struct ConstantLength; - -impl Domain for ConstantLength { - type Padding = iter::Take>; - - fn name() -> String { - format!("ConstantLength<{}>", L) - } - - fn initial_capacity_element() -> F { - // Capacity value is $length \cdot 2^64 + (o-1)$ where o is the output length. - // We hard-code an output length of 1. - F::from_u128((L as u128) << 64) - } - - fn padding(input_len: usize) -> Self::Padding { - assert_eq!(input_len, L); - // For constant-input-length hashing, we pad the input with zeroes to a multiple - // of RATE. On its own this would not be sponge-compliant padding, but the - // Poseidon authors encode the constant length into the capacity element, ensuring - // that inputs of different lengths do not share the same permutation. - let k = (L + RATE - 1) / RATE; - iter::repeat(F::zero()).take(k * RATE - L) - } -} - -/// A Poseidon hash function, built around a sponge. -pub struct Hash< - F: FieldExt, - S: Spec, - D: Domain, - const T: usize, - const RATE: usize, -> { - sponge: Sponge, T, RATE>, - _domain: PhantomData, -} - -impl, D: Domain, const T: usize, const RATE: usize> - fmt::Debug for Hash -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Hash") - .field("width", &T) - .field("rate", &RATE) - .field("R_F", &S::full_rounds()) - .field("R_P", &S::partial_rounds()) - .field("domain", &D::name()) - .finish() - } -} - -impl, D: Domain, const T: usize, const RATE: usize> - Hash -{ - /// Initializes a new hasher. - pub fn init() -> Self { - Hash { - sponge: Sponge::new(D::initial_capacity_element()), - _domain: PhantomData::default(), - } - } -} - -impl, const T: usize, const RATE: usize, const L: usize> - Hash, T, RATE> -{ - /// Hashes the given input. - pub fn hash(mut self, message: [F; L]) -> F { - for value in message - .into_iter() - .chain( as Domain>::padding(L)) - { - self.sponge.absorb(value); - } - self.sponge.finish_absorbing().squeeze() - } -} - -#[cfg(test)] -mod tests { - use halo2curves::{pasta::pallas, FieldExt}; - - use super::{permute, ConstantLength, Hash, P128Pow5T3 as OrchardNullifier, Spec}; - - #[test] - fn orchard_spec_equivalence() { - let message = [pallas::Base::from(6), pallas::Base::from(42)]; - - let (round_constants, mds, _) = OrchardNullifier::constants(); - - let hasher = Hash::<_, OrchardNullifier, ConstantLength<2>, 3, 2>::init(); - let result = hasher.hash(message); - - // The result should be equivalent to just directly applying the permutation and - // taking the first state element as the output. - let mut state = [message[0], message[1], pallas::Base::from_u128(2 << 64)]; - permute::<_, OrchardNullifier, 3, 2>(&mut state, &mds, &round_constants); - assert_eq!(state[0], result); - } -} diff --git a/halo2_gadgets/src/poseidon/primitives/fp.rs b/halo2_gadgets/src/poseidon/primitives/fp.rs deleted file mode 100644 index 38b38937fb..0000000000 --- a/halo2_gadgets/src/poseidon/primitives/fp.rs +++ /dev/null @@ -1,1431 +0,0 @@ -//! Constants for using Poseidon with the Pallas field. -//! -//! The constants can be reproduced by running the following Sage script from -//! [this repository](https://github.com/daira/pasta-hadeshash): -//! -//! ```text -//! $ sage generate_parameters_grain.sage 1 0 255 3 8 56 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001 -//! ``` -use halo2curves::pasta::pallas; - -// Number of round constants: 192 -// Round constants for GF(p): -pub(crate) const ROUND_CONSTANTS: [[pallas::Base; 3]; 64] = [ - [ - pallas::Base::from_raw([ - 0x5753_8c25_9642_6303, - 0x4e71_162f_3100_3b70, - 0x353f_628f_76d1_10f3, - 0x360d_7470_611e_473d, - ]), - pallas::Base::from_raw([ - 0xbdb7_4213_bf63_188b, - 0x4908_ac2f_12eb_e06f, - 0x5dc3_c6c5_febf_aa31, - 0x2bab_94d7_ae22_2d13, - ]), - pallas::Base::from_raw([ - 0x0939_d927_53cc_5dc8, - 0xef77_e7d7_3676_6c5d, - 0x2bf0_3e1a_29aa_871f, - 0x150c_93fe_f652_fb1c, - ]), - ], - [ - pallas::Base::from_raw([ - 0x1425_9dce_5377_82b2, - 0x03cc_0a60_141e_894e, - 0x955d_55db_56dc_57c1, - 0x3270_661e_6892_8b3a, - ]), - pallas::Base::from_raw([ - 0xce9f_b9ff_c345_afb3, - 0xb407_c370_f2b5_a1cc, - 0xa0b7_afe4_e205_7299, - 0x073f_116f_0412_2e25, - ]), - pallas::Base::from_raw([ - 0x8eba_d76f_c715_54d8, - 0x55c9_cd20_61ae_93ca, - 0x7aff_d09c_1f53_f5fd, - 0x2a32_ec5c_4ee5_b183, - ]), - ], - [ - pallas::Base::from_raw([ - 0x2d8c_cbe2_92ef_eead, - 0x634d_24fc_6e25_59f2, - 0x651e_2cfc_7406_28ca, - 0x2703_26ee_039d_f19e, - ]), - pallas::Base::from_raw([ - 0xa068_fc37_c182_e274, - 0x8af8_95bc_e012_f182, - 0xdc10_0fe7_fcfa_5491, - 0x27c6_642a_c633_bc66, - ]), - pallas::Base::from_raw([ - 0x9ca1_8682_e26d_7ff9, - 0x710e_1fb6_ab97_6a45, - 0xd27f_5739_6989_129d, - 0x1bdf_d8b0_1401_c70a, - ]), - ], - [ - pallas::Base::from_raw([ - 0xc832_d824_261a_35ea, - 0xf4f6_fb3f_9054_d373, - 0x14b9_d6a9_c84d_d678, - 0x162a_14c6_2f9a_89b8, - ]), - pallas::Base::from_raw([ - 0xf798_2466_7b5b_6bec, - 0xac0a_1fc7_1e2c_f0c0, - 0x2af6_f79e_3127_feea, - 0x2d19_3e0f_76de_586b, - ]), - pallas::Base::from_raw([ - 0x5d0b_f58d_c8a4_aa94, - 0x4fef_f829_8499_0ff8, - 0x8169_6ef1_104e_674f, - 0x044c_a3cc_4a85_d73b, - ]), - ], - [ - pallas::Base::from_raw([ - 0x6198_785f_0cd6_b9af, - 0xb8d9_e2d4_f314_f46f, - 0x1d04_5341_6d3e_235c, - 0x1cba_f2b3_71da_c6a8, - ]), - pallas::Base::from_raw([ - 0x343e_0761_0f3f_ede5, - 0x293c_4ab0_38fd_bbdc, - 0x0e6c_49d0_61b6_b5f4, - 0x1d5b_2777_692c_205b, - ]), - pallas::Base::from_raw([ - 0xf60e_971b_8d73_b04f, - 0x06a9_adb0_c1e6_f962, - 0xaa30_535b_dd74_9a7e, - 0x2e9b_dbba_3dd3_4bff, - ]), - ], - [ - pallas::Base::from_raw([ - 0x035a_1366_1f22_418b, - 0xde40_fbe2_6d04_7b05, - 0x8bd5_bae3_6969_299f, - 0x2de1_1886_b180_11ca, - ]), - pallas::Base::from_raw([ - 0xbc99_8884_ba96_a721, - 0x2ab9_395c_449b_e947, - 0x0d5b_4a3f_1841_dcd8, - 0x2e07_de17_80b8_a70d, - ]), - pallas::Base::from_raw([ - 0x825e_4c2b_b749_25ca, - 0x2504_40a9_9d6b_8af3, - 0xbbdb_63db_d52d_ad16, - 0x0f69_f185_4d20_ca0c, - ]), - ], - [ - pallas::Base::from_raw([ - 0x816c_0594_22dc_705e, - 0x6ce5_1135_07f9_6de9, - 0x0d13_5dc6_39fb_09a4, - 0x2eb1_b254_17fe_1767, - ]), - pallas::Base::from_raw([ - 0xb8b1_bdf4_953b_d82c, - 0xff36_c661_d26c_c42d, - 0x8c24_cb44_c3fa_b48a, - 0x115c_d0a0_643c_fb98, - ]), - pallas::Base::from_raw([ - 0xde80_1612_311d_04cd, - 0xbb57_ddf1_4e0f_958a, - 0x066d_7378_b999_868b, - 0x26ca_293f_7b2c_462d, - ]), - ], - [ - pallas::Base::from_raw([ - 0xf520_9d14_b248_20ca, - 0x0f16_0bf9_f71e_967f, - 0x2a83_0aa1_6241_2cd9, - 0x17bf_1b93_c4c7_e01a, - ]), - pallas::Base::from_raw([ - 0x05c8_6f2e_7dc2_93c5, - 0xe03c_0354_bd8c_fd38, - 0xa24f_8456_369c_85df, - 0x35b4_1a7a_c4f3_c571, - ]), - pallas::Base::from_raw([ - 0x72ac_156a_f435_d09e, - 0x64e1_4d3b_eb2d_ddde, - 0x4359_2799_4849_bea9, - 0x3b14_8008_0523_c439, - ]), - ], - [ - pallas::Base::from_raw([ - 0x2716_18d8_74b1_4c6d, - 0x08e2_8644_2a2d_3eb2, - 0x4950_856d_c907_d575, - 0x2cc6_8100_31dc_1b0d, - ]), - pallas::Base::from_raw([ - 0x91f3_18c0_9f0c_b566, - 0x9e51_7aa9_3b78_341d, - 0x0596_18e2_afd2_ef99, - 0x25bd_bbed_a1bd_e8c1, - ]), - pallas::Base::from_raw([ - 0xc631_3487_073f_7f7b, - 0x2a5e_d0a2_7b61_926c, - 0xb95f_33c2_5dde_8ac0, - 0x392a_4a87_58e0_6ee8, - ]), - ], - [ - pallas::Base::from_raw([ - 0xe7bb_cef0_2eb5_866c, - 0x5e6a_6fd1_5db8_9365, - 0x9aa6_111f_4de0_0948, - 0x272a_5587_8a08_442b, - ]), - pallas::Base::from_raw([ - 0x9b92_5b3c_5b21_e0e2, - 0xa6eb_ba01_1694_dd12, - 0xefa1_3c4e_60e2_6239, - 0x2d5b_308b_0cf0_2cdf, - ]), - pallas::Base::from_raw([ - 0xef38_c57c_3116_73ac, - 0x44df_f42f_18b4_6c56, - 0xdd5d_293d_72e2_e5f2, - 0x1654_9fc6_af2f_3b72, - ]), - ], - [ - pallas::Base::from_raw([ - 0x9b71_26d9_b468_60df, - 0x7639_8265_3442_0311, - 0xfa69_c3a2_ad52_f76d, - 0x1b10_bb7a_82af_ce39, - ]), - pallas::Base::from_raw([ - 0x90d2_7f6a_00b7_dfc8, - 0xd1b3_6968_ba04_05c0, - 0xc79c_2df7_dc98_a3be, - 0x0f1e_7505_ebd9_1d2f, - ]), - pallas::Base::from_raw([ - 0xff45_7756_b819_bb20, - 0x797f_d6e3_f18e_b1ca, - 0x537a_7497_a3b4_3f46, - 0x2f31_3faf_0d3f_6187, - ]), - ], - [ - pallas::Base::from_raw([ - 0xf0bc_3e73_2ecb_26f6, - 0x5cad_11eb_f0f7_ceb8, - 0xfa3c_a61c_0ed1_5bc5, - 0x3a5c_bb6d_e450_b481, - ]), - pallas::Base::from_raw([ - 0x8655_27cb_ca91_5982, - 0x51ba_a6e2_0f89_2b62, - 0xd920_86e2_53b4_39d6, - 0x3dab_54bc_9bef_688d, - ]), - pallas::Base::from_raw([ - 0x3680_45ac_f2b7_1ae3, - 0x4c24_b33b_410f_efd4, - 0xe280_d316_7012_3f74, - 0x06db_fb42_b979_884d, - ]), - ], - [ - pallas::Base::from_raw([ - 0xa7fc_32d2_2f18_b9d3, - 0xb8d2_de72_e3d2_c9ec, - 0xc6f0_39ea_1973_a63e, - 0x068d_6b46_08aa_e810, - ]), - pallas::Base::from_raw([ - 0x2b5d_fcc5_5725_55df, - 0xb868_a7d7_e1f1_f69a, - 0x0ee2_58c9_b8fd_fccd, - 0x366e_bfaf_a3ad_381c, - ]), - pallas::Base::from_raw([ - 0xe6bc_229e_95bc_76b1, - 0x7ef6_6d89_d044_d022, - 0x04db_3024_f41d_3f56, - 0x3967_8f65_512f_1ee4, - ]), - ], - [ - pallas::Base::from_raw([ - 0xe534_c88f_e53d_85fe, - 0xcf82_c25f_99dc_01a4, - 0xd58b_7750_a3bc_2fe1, - 0x2166_8f01_6a80_63c0, - ]), - pallas::Base::from_raw([ - 0x4bef_429b_c533_1608, - 0xe34d_ea56_439f_e195, - 0x1bc7_4936_3e98_a768, - 0x39d0_0994_a8a5_046a, - ]), - pallas::Base::from_raw([ - 0x770c_956f_60d8_81b3, - 0xb163_d416_05d3_9f99, - 0x6b20_3bbe_12fb_3425, - 0x1f9d_bdc3_f843_1263, - ]), - ], - [ - pallas::Base::from_raw([ - 0x9794_a9f7_c336_eab2, - 0xbe0b_c829_fe5e_66c6, - 0xe5f1_7b9e_0ee0_cab6, - 0x0277_45a9_cddf_ad95, - ]), - pallas::Base::from_raw([ - 0x5202_5657_abd8_aee0, - 0x2fa4_3fe2_0a45_c78d, - 0x788d_695c_61e9_3212, - 0x1cec_0803_c504_b635, - ]), - pallas::Base::from_raw([ - 0xd387_2a95_59a0_3a73, - 0xed50_82c8_dbf3_1365, - 0x7207_7448_ef87_cc6e, - 0x1235_23d7_5e9f_abc1, - ]), - ], - [ - pallas::Base::from_raw([ - 0x0017_79e3_a1d3_57f4, - 0x27fe_ba35_975e_e7e5, - 0xf419_b848_e5d6_94bf, - 0x1723_d145_2c9c_f02d, - ]), - pallas::Base::from_raw([ - 0x9dab_1ee4_dcf9_6622, - 0x21c3_f776_f572_836d, - 0xfcc0_573d_7e61_3694, - 0x1739_d180_a160_10bd, - ]), - pallas::Base::from_raw([ - 0x7029_0452_042d_048d, - 0xfafa_96fb_eb0a_b893, - 0xacce_3239_1794_b627, - 0x2d4e_6354_da9c_c554, - ]), - ], - [ - pallas::Base::from_raw([ - 0x670b_cf6f_8b48_5dcd, - 0x8f3b_d43f_9926_0621, - 0x4a86_9553_c9d0_07f8, - 0x153e_e614_2e53_5e33, - ]), - pallas::Base::from_raw([ - 0xd258_d2e2_b778_2172, - 0x968a_d442_4af8_3700, - 0x635e_f7e7_a430_b486, - 0x0c45_bfd3_a69a_aa65, - ]), - pallas::Base::from_raw([ - 0x0e56_33d2_51f7_3307, - 0x6897_ac0a_8ffa_5ff1, - 0xf2d5_6aec_8314_4600, - 0x0adf_d53b_256a_6957, - ]), - ], - [ - pallas::Base::from_raw([ - 0xac9d_36a8_b751_6d63, - 0x3f87_b28f_1c1b_e4bd, - 0x8cd1_726b_7cba_b8ee, - 0x315d_2ac8_ebdb_ac3c, - ]), - pallas::Base::from_raw([ - 0x299c_e44e_a423_d8e1, - 0xc9bb_60d1_f695_9879, - 0xcfae_c23d_2b16_883f, - 0x1b84_7271_2d02_eef4, - ]), - pallas::Base::from_raw([ - 0xc4a5_4041_98ad_f70c, - 0x367d_2c54_e369_28c9, - 0xbd0b_70fa_2255_eb6f, - 0x3c1c_d07e_fda6_ff24, - ]), - ], - [ - pallas::Base::from_raw([ - 0xbbe5_23ae_f9ab_107a, - 0x4a16_073f_738f_7e0c, - 0x687f_4e51_b2e1_dcd3, - 0x1360_52d2_6bb3_d373, - ]), - pallas::Base::from_raw([ - 0x676c_36c2_4ef9_67dd, - 0x7b3c_fbb8_7303_2681, - 0xc1bd_d859_a123_2a1d, - 0x16c9_6bee_f6a0_a848, - ]), - pallas::Base::from_raw([ - 0x067e_ec7f_2d63_40c4, - 0x0123_87ba_b4f1_662d, - 0x2ab7_fed8_f499_a9fb, - 0x284b_38c5_7ff6_5c26, - ]), - ], - [ - pallas::Base::from_raw([ - 0xaf1d_ff20_4c92_2f86, - 0xfc06_772c_1c04_11a6, - 0x39e2_4219_8897_d17c, - 0x0c59_93d1_75e8_1f66, - ]), - pallas::Base::from_raw([ - 0xbbf5_3f67_b1f8_7b15, - 0xf248_87ad_48e1_7759, - 0xfcda_655d_1ba9_c8f9, - 0x03bf_7a3f_7bd0_43da, - ]), - pallas::Base::from_raw([ - 0x9b5c_d09e_36d8_be62, - 0x4c8f_9cbe_69f0_e827, - 0xb0cf_9995_67f0_0e73, - 0x3188_fe4e_e9f9_fafb, - ]), - ], - [ - pallas::Base::from_raw([ - 0xafea_99a2_ec6c_595a, - 0x3af5_bf77_c1c4_2652, - 0x5a39_768c_480d_61e1, - 0x171f_528c_cf65_8437, - ]), - pallas::Base::from_raw([ - 0x5a05_63b9_b8e9_f1d5, - 0x812c_3286_ee70_0067, - 0x196e_4185_9b35_ef88, - 0x12f4_175c_4ab4_5afc, - ]), - pallas::Base::from_raw([ - 0x0e74_d4d3_6911_8b79, - 0x7e23_e1aa_be96_cfab, - 0x8f8f_dcf8_00a9_ac69, - 0x3a50_9e15_5cb7_ebfd, - ]), - ], - [ - pallas::Base::from_raw([ - 0x9871_2c65_678c_fd30, - 0x984b_c8f2_e4c1_b69e, - 0x1a89_920e_2504_c3b3, - 0x10f2_a685_df4a_27c8, - ]), - pallas::Base::from_raw([ - 0xe8a1_6728_cc9d_4918, - 0x5457_3c93_33c5_6321, - 0x1d8d_93d5_4ab9_1a0e, - 0x09e5_f497_90c8_a0e2, - ]), - pallas::Base::from_raw([ - 0x609a_7403_47cf_5fea, - 0x42d1_7ed6_ee0f_ab7e, - 0x2bf3_5705_d9f8_4a34, - 0x352d_69be_d80e_e3e5, - ]), - ], - [ - pallas::Base::from_raw([ - 0x3a75_8af6_fa84_e0e8, - 0xc634_debd_281b_76a6, - 0x4915_62fa_f2b1_90d3, - 0x058e_e73b_a9f3_f293, - ]), - pallas::Base::from_raw([ - 0x621a_1325_10a4_3904, - 0x092c_b921_19bc_76be, - 0xcd0f_1fc5_5b1a_3250, - 0x232f_99cc_911e_ddd9, - ]), - pallas::Base::from_raw([ - 0xc3b9_7c1e_301b_c213, - 0xf9ef_d52c_a6bc_2961, - 0x86c2_2c6c_5d48_69f0, - 0x201b_eed7_b8f3_ab81, - ]), - ], - [ - pallas::Base::from_raw([ - 0xbf6b_3431_ba94_e9bc, - 0x2938_8842_744a_1210, - 0xa1c9_291d_5860_2f51, - 0x1376_dce6_5800_30c6, - ]), - pallas::Base::from_raw([ - 0x6454_843c_5486_d7b3, - 0x072b_a8b0_2d92_e722, - 0x2b33_56c3_8238_f761, - 0x1793_199e_6fd6_ba34, - ]), - pallas::Base::from_raw([ - 0x06a3_f1d3_b433_311b, - 0x3c66_160d_c62a_acac, - 0x9fee_9c20_c87a_67df, - 0x22de_7a74_88dc_c735, - ]), - ], - [ - pallas::Base::from_raw([ - 0x30d6_e3fd_516b_47a8, - 0xdbe0_b77f_ae77_e1d0, - 0xdf8f_f37f_e2d8_edf8, - 0x3514_d5e9_066b_b160, - ]), - pallas::Base::from_raw([ - 0x1937_7427_137a_81c7, - 0xff45_3d6f_900f_144a, - 0xf919_a00d_abbf_5fa5, - 0x30cd_3006_931a_d636, - ]), - pallas::Base::from_raw([ - 0x5b6a_7422_0692_b506, - 0x8f9e_4b2c_ae2e_bb51, - 0x41f8_1a5c_f613_c8df, - 0x253d_1a5c_5293_4127, - ]), - ], - [ - pallas::Base::from_raw([ - 0x73f6_66cb_86a4_8e8e, - 0x851b_3a59_c990_fafc, - 0xa35e_9613_e7f5_fe92, - 0x035b_461c_02d7_9d19, - ]), - pallas::Base::from_raw([ - 0x7cfb_f86a_3aa0_4780, - 0x92b1_283c_2d5f_ccde, - 0x5bc0_0eed_d56b_93e0, - 0x23a9_9280_79d1_75bd, - ]), - pallas::Base::from_raw([ - 0xf1e4_ccd7_3fa0_0a82, - 0xb5e2_ea34_36ee_f957, - 0xf159_4a07_63c6_11ab, - 0x13a7_785a_e134_ea92, - ]), - ], - [ - pallas::Base::from_raw([ - 0xbbf0_4f52_52de_4279, - 0x3889_c578_6344_6d88, - 0x4962_ae3c_0da1_7e31, - 0x39fc_e308_b7d4_3c57, - ]), - pallas::Base::from_raw([ - 0x3b57_e344_89b5_3fad, - 0xbef0_0a08_c6ed_38d2, - 0xc0fd_f016_62f6_0d22, - 0x1aae_1883_3f8e_1d3a, - ]), - pallas::Base::from_raw([ - 0x5551_3e03_3398_513f, - 0x27c1_b3fd_8f85_d8a8, - 0x8b2e_80c0_64fd_83ed, - 0x1a76_1ce8_2400_af01, - ]), - ], - [ - pallas::Base::from_raw([ - 0x5244_ca74_9b73_e481, - 0xdcf6_af28_30a5_0287, - 0x16dd_1a87_ca22_e1cc, - 0x275a_03e4_5add_a7c3, - ]), - pallas::Base::from_raw([ - 0x58a2_53cf_b6a9_5786, - 0x07e5_6145_3fc5_648b, - 0xeb08_e47e_5fea_bcf8, - 0x2e5a_10f0_8b5a_b8bb, - ]), - pallas::Base::from_raw([ - 0xe033_d82c_efe7_8ce3, - 0xc141_a5b6_d594_bec4, - 0xb84e_9c33_3b29_32f1, - 0x1459_cb85_8720_8473, - ]), - ], - [ - pallas::Base::from_raw([ - 0x5cec_7e7b_338f_be1b, - 0x52f9_332f_bffc_fbbd, - 0x7b92_ce81_0e14_a400, - 0x193a_e592_1d78_b5de, - ]), - pallas::Base::from_raw([ - 0x6022_4be6_7248_e82c, - 0x3743_84f4_a072_8205, - 0x8911_1fb2_c466_0281, - 0x3097_898a_5d00_11a4, - ]), - pallas::Base::from_raw([ - 0x5499_80de_8629_30f5, - 0x1979_b2d1_c465_b4d9, - 0x5717_82fd_96ce_54b4, - 0x378d_97bf_8c86_4ae7, - ]), - ], - [ - pallas::Base::from_raw([ - 0x37ea_32a9_71d1_7884, - 0xdbc7_f5cb_4609_3421, - 0x8813_6287_ce37_6b08, - 0x2eb0_4ea7_c01d_97ec, - ]), - pallas::Base::from_raw([ - 0xead3_726f_1af2_e7b0, - 0x861c_bda4_7680_4e6c, - 0x2302_a1c2_2e49_baec, - 0x3642_5347_ea03_f641, - ]), - pallas::Base::from_raw([ - 0xecd6_27e5_9590_d09e, - 0x3f5b_5ca5_a19a_9701, - 0xcc99_6cd8_5c98_a1d8, - 0x26b7_2df4_7408_ad42, - ]), - ], - [ - pallas::Base::from_raw([ - 0x59be_ce31_f0a3_1e95, - 0xde01_212e_e458_8f89, - 0x1f05_636c_610b_89aa, - 0x1301_80e4_4e29_24db, - ]), - pallas::Base::from_raw([ - 0x9ea8_e7bc_7926_3550, - 0xdf77_93cc_89e5_b52f, - 0x7327_5aca_ed5f_579c, - 0x219e_9773_7d39_79ba, - ]), - pallas::Base::from_raw([ - 0x9c12_635d_f251_d153, - 0x3b06_72dd_7d42_cbb4, - 0x3461_363f_81c4_89a2, - 0x3cdb_9359_8a5c_a528, - ]), - ], - [ - pallas::Base::from_raw([ - 0x2861_ce16_f219_d5a9, - 0x4ad0_4470_45a7_c5aa, - 0x2072_4b92_7a0c_a81c, - 0x0e59_e6f3_32d7_ed37, - ]), - pallas::Base::from_raw([ - 0x43b0_a3fc_ff20_36bd, - 0x172c_c07b_9d33_fbf9, - 0x3d73_6946_7222_697a, - 0x1b06_4342_d51a_4275, - ]), - pallas::Base::from_raw([ - 0x3eb3_1022_8a0e_5f6c, - 0x78fa_9fb9_1712_21b7, - 0x2f36_3c55_b288_2e0b, - 0x30b8_2a99_8cbd_8e8a, - ]), - ], - [ - pallas::Base::from_raw([ - 0xe46f_6d42_9874_0107, - 0x8ad7_1ea7_15be_0573, - 0x63df_7a76_e858_a4aa, - 0x23e4_ab37_183a_cba4, - ]), - pallas::Base::from_raw([ - 0xfca9_95e2_b599_14a1, - 0xacfe_1464_0de0_44f2, - 0x5d33_094e_0bed_a75b, - 0x2795_d5c5_fa42_8022, - ]), - pallas::Base::from_raw([ - 0xc26d_909d_ee8b_53c0, - 0xa668_7c3d_f16c_8fe4, - 0xd765_f26d_d03f_4c45, - 0x3001_ca40_1e89_601c, - ]), - ], - [ - pallas::Base::from_raw([ - 0xe7fe_a6bd_f347_1380, - 0xe84b_5beb_ae4e_501d, - 0xf7bf_86e8_9280_827f, - 0x0072_e45c_c676_b08e, - ]), - pallas::Base::from_raw([ - 0xd0c5_4dde_b26b_86c0, - 0xb648_29e2_d40e_41bd, - 0xe2ab_e4c5_18ce_599e, - 0x13de_7054_8487_4bb5, - ]), - pallas::Base::from_raw([ - 0x3891_5b43_2a99_59a5, - 0x82bb_18e5_af1b_05bb, - 0x3159_50f1_211d_efe8, - 0x0408_a9fc_f9d6_1abf, - ]), - ], - [ - pallas::Base::from_raw([ - 0x3407_0cbe_e268_86a0, - 0xae4d_23b0_b41b_e9a8, - 0xbb4e_4a14_00cc_d2c4, - 0x2780_b9e7_5b55_676e, - ]), - pallas::Base::from_raw([ - 0x9405_5920_98b4_056f, - 0xdc4d_8fbe_fe24_405a, - 0xf803_33ec_8563_4ac9, - 0x3a57_0d4d_7c4e_7ac3, - ]), - pallas::Base::from_raw([ - 0x78d2_b247_8995_20b4, - 0xe2cc_1507_bebd_cc62, - 0xf347_c247_fcf0_9294, - 0x0c13_cca7_cb1f_9d2c, - ]), - ], - [ - pallas::Base::from_raw([ - 0x2e8c_88f7_7074_70e0, - 0x0b50_bb2e_b82d_f74d, - 0xd261_4a19_7c6b_794b, - 0x14f5_9baa_03cd_0ca4, - ]), - pallas::Base::from_raw([ - 0xbe52_476e_0a16_f3be, - 0xa51d_54ed_e661_67f5, - 0x6f54_6e17_04c3_9c60, - 0x307d_efee_925d_fb43, - ]), - pallas::Base::from_raw([ - 0x380b_67d8_0473_dce3, - 0x6611_0683_6adf_e5e7, - 0x7a07_e767_4b5a_2621, - 0x1960_cd51_1a91_e060, - ]), - ], - [ - pallas::Base::from_raw([ - 0x15aa_f1f7_7125_89dd, - 0xb8ee_335d_8828_4cbe, - 0xca2a_d0fb_5667_2500, - 0x2301_ef9c_63ea_84c5, - ]), - pallas::Base::from_raw([ - 0x5e68_478c_4d60_27a9, - 0xc861_82d1_b424_6b58, - 0xd10f_4cd5_2be9_7f6b, - 0x029a_5a47_da79_a488, - ]), - pallas::Base::from_raw([ - 0x2cc4_f962_eaae_2260, - 0xf97f_e46b_6a92_5428, - 0x2360_d17d_890e_55cb, - 0x32d7_b16a_7f11_cc96, - ]), - ], - [ - pallas::Base::from_raw([ - 0xc0ca_b915_d536_3d9f, - 0xa5f2_404c_d7b3_5eb0, - 0x18e8_57a9_8d49_8cf7, - 0x2670_3e48_c03b_81ca, - ]), - pallas::Base::from_raw([ - 0xf691_123a_e112_b928, - 0xf443_88bd_6b89_221e, - 0x88ac_8d25_a246_03f1, - 0x0486_82a3_5b32_65bc, - ]), - pallas::Base::from_raw([ - 0x3ab7_defc_b8d8_03e2, - 0x91d6_e171_5164_775e, - 0xd72c_ddc6_cf06_b507, - 0x06b1_3904_41fa_7030, - ]), - ], - [ - pallas::Base::from_raw([ - 0xbcd7_9541_4a6e_2e86, - 0x43b3_60f6_386a_86d7, - 0x1689_426d_ce05_fcd8, - 0x31aa_0eeb_868c_626d, - ]), - pallas::Base::from_raw([ - 0xed77_f5d5_76b9_9cc3, - 0x90ef_d8f4_1b20_78b2, - 0x057a_bad3_764c_104b, - 0x2394_64f7_5bf7_b6af, - ]), - pallas::Base::from_raw([ - 0xb2cb_4873_07c1_cecf, - 0xa5cc_47c5_9654_b2a7, - 0xa45e_19ed_813a_54ab, - 0x0a64_d4c0_4fd4_26bd, - ]), - ], - [ - pallas::Base::from_raw([ - 0x1f73_1532_2f65_8735, - 0x777c_7a92_1a06_2e9d, - 0x576a_4ad2_5986_0fb1, - 0x21fb_bdbb_7367_0734, - ]), - pallas::Base::from_raw([ - 0x6743_2400_3fc5_2146, - 0x5b86_d294_63d3_1564, - 0xd937_1ca2_eb95_acf3, - 0x31b8_6f3c_f017_05d4, - ]), - pallas::Base::from_raw([ - 0x7045_f48a_a4eb_4f6f, - 0x1354_1d65_157e_e1ce, - 0x05ef_1736_d090_56f6, - 0x2bfd_e533_5437_7c91, - ]), - ], - [ - pallas::Base::from_raw([ - 0x5a13_a58d_2001_1e2f, - 0xf4d5_239c_11d0_eafa, - 0xd558_f36e_65f8_eca7, - 0x1233_ca93_6ec2_4671, - ]), - pallas::Base::from_raw([ - 0x6e70_af0a_7a92_4b3a, - 0x8780_58d0_234a_576f, - 0xc437_846d_8e0b_2b30, - 0x27d4_52a4_3ac7_dea2, - ]), - pallas::Base::from_raw([ - 0xa025_76b9_4392_f980, - 0x6a30_641a_1c3d_87b2, - 0xe816_ea8d_a493_e0fa, - 0x2699_dba8_2184_e413, - ]), - ], - [ - pallas::Base::from_raw([ - 0x608c_6f7a_61b5_6e55, - 0xf185_8466_4f8c_ab49, - 0xc398_8bae_e42e_4b10, - 0x36c7_22f0_efcc_8803, - ]), - pallas::Base::from_raw([ - 0x6e49_ac17_0dbb_7fcd, - 0x85c3_8899_a7b5_a833, - 0x08b0_f2ec_89cc_aa37, - 0x02b3_ff48_861e_339b, - ]), - pallas::Base::from_raw([ - 0xa8c5_ae03_ad98_e405, - 0x6fc3_ff4c_49eb_59ad, - 0x6016_2f44_27bc_657b, - 0x0b70_d061_d58d_8a7f, - ]), - ], - [ - pallas::Base::from_raw([ - 0x2e06_cc4a_f33b_0a06, - 0xad3d_e8be_46ed_9693, - 0xf875_3ade_b9d7_cee2, - 0x3fc2_a13f_127f_96a4, - ]), - pallas::Base::from_raw([ - 0xc120_80ac_117e_e15f, - 0x00cb_3d62_1e17_1d80, - 0x1bd6_3434_ac8c_419f, - 0x0c41_a6e4_8dd2_3a51, - ]), - pallas::Base::from_raw([ - 0x9685_213e_9692_f5e1, - 0x72aa_ad7e_4e75_339d, - 0xed44_7653_7169_084e, - 0x2de8_072a_6bd8_6884, - ]), - ], - [ - pallas::Base::from_raw([ - 0x0ad0_1184_567b_027c, - 0xb81c_f735_cc9c_39c0, - 0x9d34_96a3_d9fe_05ec, - 0x0355_7a8f_7b38_a17f, - ]), - pallas::Base::from_raw([ - 0x45bc_b5ac_0082_6abc, - 0x060f_4336_3d81_8e54, - 0xee97_6d34_282f_1a37, - 0x0b5f_5955_2f49_8735, - ]), - pallas::Base::from_raw([ - 0x2f29_09e1_7e22_b0df, - 0xf5d6_46e5_7507_e548, - 0xfedb_b185_70dc_7300, - 0x0e29_23a5_fee7_b878, - ]), - ], - [ - pallas::Base::from_raw([ - 0xf71e_ed73_f15b_3326, - 0xcf1c_b37c_3b03_2af6, - 0xc787_be97_020a_7fdd, - 0x1d78_5005_a7a0_0592, - ]), - pallas::Base::from_raw([ - 0x0acf_bfb2_23f8_f00d, - 0xa590_b88a_3b06_0294, - 0x0ba5_fedc_b8f2_5bd2, - 0x1ad7_72c2_73d9_c6df, - ]), - pallas::Base::from_raw([ - 0xc1ce_13d6_0f2f_5031, - 0x8105_10eb_61f0_672d, - 0xa78f_3275_c278_234b, - 0x027b_d647_85fc_bd2a, - ]), - ], - [ - pallas::Base::from_raw([ - 0x8337_f5e0_7923_a853, - 0xe224_3134_6945_7b8e, - 0xce6f_8ffe_a103_1b6d, - 0x2080_0f44_1b4a_0526, - ]), - pallas::Base::from_raw([ - 0xa33d_7bed_89a4_408a, - 0x36cd_c8ee_d662_ad37, - 0x6eea_2cd4_9f43_12b4, - 0x3d5a_d61d_7b65_f938, - ]), - pallas::Base::from_raw([ - 0x3bbb_ae94_cc19_5284, - 0x1df9_6cc0_3ea4_b26d, - 0x02c5_f91b_e4dd_8e3d, - 0x1333_8bc3_51fc_46dd, - ]), - ], - [ - pallas::Base::from_raw([ - 0xc527_1c29_7852_819e, - 0x646c_49f9_b46c_bf19, - 0xb87d_b1e2_af3e_a923, - 0x25e5_2be5_07c9_2760, - ]), - pallas::Base::from_raw([ - 0x5c38_0ab7_01b5_2ea9, - 0xa34c_83a3_485c_6b2d, - 0x7109_6d8b_1b98_3c98, - 0x1c49_2d64_c157_aaa4, - ]), - pallas::Base::from_raw([ - 0xa20c_0b3d_a0da_4ca3, - 0xd434_87bc_288d_f682, - 0xf4e6_c5e7_a573_f592, - 0x0c5b_8015_7999_2718, - ]), - ], - [ - pallas::Base::from_raw([ - 0x7ea3_3c93_e408_33cf, - 0x584e_9e62_a7f9_554e, - 0x6869_5c0c_d7cb_f43d, - 0x1090_b1b4_d2be_be7a, - ]), - pallas::Base::from_raw([ - 0xe383_e1ec_3baa_8d69, - 0x1b21_8e35_ecf2_328e, - 0x68f5_ce5c_bed1_9cad, - 0x33e3_8018_a801_387a, - ]), - pallas::Base::from_raw([ - 0xb76b_0b3d_787e_e953, - 0x5f4a_02d2_8729_e3ae, - 0xeef8_d83d_0e87_6bac, - 0x1654_af18_772b_2da5, - ]), - ], - [ - pallas::Base::from_raw([ - 0xef7c_e6a0_1326_5477, - 0xbb08_9387_0367_ec6c, - 0x4474_2de8_8c5a_b0d5, - 0x1678_be3c_c9c6_7993, - ]), - pallas::Base::from_raw([ - 0xaf5d_4789_3348_f766, - 0xdaf1_8183_55b1_3b4f, - 0x7ff9_c6be_546e_928a, - 0x3780_bd1e_01f3_4c22, - ]), - pallas::Base::from_raw([ - 0xa123_8032_0d7c_c1de, - 0x5d11_e69a_a6c0_b98c, - 0x0786_018e_7cb7_7267, - 0x1e83_d631_5c9f_125b, - ]), - ], - [ - pallas::Base::from_raw([ - 0x1799_603e_855c_e731, - 0xc486_894d_76e0_c33b, - 0x160b_4155_2f29_31c8, - 0x354a_fd0a_2f9d_0b26, - ]), - pallas::Base::from_raw([ - 0x8b99_7ee0_6be1_bff3, - 0x60b0_0dbe_1fac_ed07, - 0x2d8a_ffa6_2905_c5a5, - 0x00cd_6d29_f166_eadc, - ]), - pallas::Base::from_raw([ - 0x08d0_6419_1708_2f2c, - 0xc60d_0197_3f18_3057, - 0xdbe0_e3d7_cdbc_66ef, - 0x1d62_1935_2768_e3ae, - ]), - ], - [ - pallas::Base::from_raw([ - 0xfa08_dd98_0638_7577, - 0xafe3_ca1d_b8d4_f529, - 0xe48d_2370_d7d1_a142, - 0x1463_36e2_5db5_181d, - ]), - pallas::Base::from_raw([ - 0xa901_d3ce_84de_0ad4, - 0x022e_54b4_9c13_d907, - 0x997a_2116_3e2e_43df, - 0x0005_d8e0_85fd_72ee, - ]), - pallas::Base::from_raw([ - 0x1c36_f313_4196_4484, - 0x6f8e_bc1d_2296_021a, - 0x0dd5_e61c_8a4e_8642, - 0x364e_97c7_a389_3227, - ]), - ], - [ - pallas::Base::from_raw([ - 0xd7a0_0c03_d2e0_baaa, - 0xfa97_ec80_ad30_7a52, - 0x561c_6fff_1534_6878, - 0x0118_9910_671b_c16b, - ]), - pallas::Base::from_raw([ - 0x63fd_8ac5_7a95_ca8c, - 0x4c0f_7e00_1df4_90aa, - 0x5229_dfaa_0123_1a45, - 0x162a_7c80_f4d2_d12e, - ]), - pallas::Base::from_raw([ - 0x32e6_9efb_22f4_0b96, - 0xcaff_31b4_fda3_2124, - 0x2604_e4af_b09f_8603, - 0x2a0d_6c09_5766_66bb, - ]), - ], - [ - pallas::Base::from_raw([ - 0xc0a0_180f_8cbf_c0d2, - 0xf444_d10d_63a7_4e2c, - 0xe16a_4d60_3d5a_808e, - 0x0978_e5c5_1e1e_5649, - ]), - pallas::Base::from_raw([ - 0x03f4_460e_bc35_1b6e, - 0x0508_7d90_3bda_cfd1, - 0xebe1_9bbd_ce25_1011, - 0x1bdc_ee3a_aca9_cd25, - ]), - pallas::Base::from_raw([ - 0xf619_64bf_3ade_7670, - 0x0c94_7321_e007_5e3f, - 0xe494_7914_0b19_44fd, - 0x1862_cccb_70b5_b885, - ]), - ], - [ - pallas::Base::from_raw([ - 0xc326_7da6_e94a_dc50, - 0x39ee_99c1_cc6e_5dda, - 0xbc26_cc88_3a19_87e1, - 0x1f3e_91d8_63c1_6922, - ]), - pallas::Base::from_raw([ - 0x0f85_b4ac_2c36_7406, - 0xfa66_1465_c656_ad99, - 0xef5c_08f8_478f_663a, - 0x1af4_7a48_a601_6a49, - ]), - pallas::Base::from_raw([ - 0x0eab_cd87_e7d0_1b15, - 0x1c36_98b0_a2e3_da10, - 0x009d_5733_8c69_3505, - 0x3c8e_e901_956e_3d3f, - ]), - ], - [ - pallas::Base::from_raw([ - 0x8b94_7721_8967_3476, - 0xe10c_e2b7_069f_4dbd, - 0x68d0_b024_f591_b520, - 0x1660_a8cd_e7fe_c553, - ]), - pallas::Base::from_raw([ - 0x9d8d_0f67_fdaa_79d5, - 0x3963_c2c1_f558_6e2f, - 0x1303_9363_34dd_1132, - 0x0f6d_9919_29d5_e4e7, - ]), - pallas::Base::from_raw([ - 0x7a43_3091_e1ce_2d3a, - 0x4e7f_da77_0712_f343, - 0xcc62_5eaa_ab52_b4dc, - 0x02b9_cea1_921c_d9f6, - ]), - ], - [ - pallas::Base::from_raw([ - 0x3797_b2d8_3760_43b3, - 0xd8ca_f468_976f_0472, - 0x214f_7c67_84ac_b565, - 0x14a3_23b9_9b90_0331, - ]), - pallas::Base::from_raw([ - 0x347f_ef2c_00f0_953a, - 0x718b_7fbc_7788_af78, - 0xec01_ea79_642d_5760, - 0x1904_76b5_80cb_9277, - ]), - pallas::Base::from_raw([ - 0xff4e_7e6f_b268_dfd7, - 0x9660_902b_6008_7651, - 0xa424_63d3_0b44_2b6f, - 0x090a_3a9d_869d_2eef, - ]), - ], - [ - pallas::Base::from_raw([ - 0xf983_387e_a045_6203, - 0xe365_0013_04f9_a11e, - 0x0dbe_8fd2_270a_6795, - 0x3877_a955_8636_7567, - ]), - pallas::Base::from_raw([ - 0x39c0_af0f_e01f_4a06, - 0x6011_8c53_a218_1352, - 0x5df3_9a2c_c63d_dc0a, - 0x2d89_4691_240f_e953, - ]), - pallas::Base::from_raw([ - 0x1aca_9eaf_9bba_9850, - 0x5914_e855_eeb4_4aa1, - 0x7ef7_1780_2016_6189, - 0x21b9_c182_92bd_bc59, - ]), - ], - [ - pallas::Base::from_raw([ - 0x33f5_09a7_4ad9_d39b, - 0x272e_1cc6_c36a_2968, - 0x505a_05f2_a6ae_834c, - 0x2fe7_6be7_cff7_23e2, - ]), - pallas::Base::from_raw([ - 0x0df9_fa97_277f_a8b4, - 0xd15b_ff84_0dda_e8a5, - 0x9299_81d7_cfce_253b, - 0x187a_a448_f391_e3ca, - ]), - pallas::Base::from_raw([ - 0xf0c6_6af5_ffc7_3736, - 0x663c_cf7b_2ffe_4b5e, - 0x007a_b3aa_3617_f422, - 0x0b70_83ad_7517_07bf, - ]), - ], - [ - pallas::Base::from_raw([ - 0x2f9b_20f1_fbd4_9791, - 0x1975_b962_f6cb_8e0b, - 0x3bc4_ca99_02c5_2acb, - 0x030d_dbb4_7049_3f16, - ]), - pallas::Base::from_raw([ - 0x3a1c_62ca_8fbf_2525, - 0x8fb8_ab9d_60ea_17b2, - 0x950b_0ab1_8d35_46df, - 0x3130_fbaf_fb5a_a82a, - ]), - pallas::Base::from_raw([ - 0x43a8_7618_0dc3_82e0, - 0x15ce_2ead_2fcd_051e, - 0x4f74_d74b_ac2e_e457, - 0x337f_5447_07c4_30f0, - ]), - ], - [ - pallas::Base::from_raw([ - 0x26de_98a8_736d_1d11, - 0x7d8e_471a_9fb9_5fef, - 0xac9d_91b0_930d_ac75, - 0x3499_7991_9015_394f, - ]), - pallas::Base::from_raw([ - 0xccfc_b618_31d5_c775, - 0x3bf9_3da6_fff3_1d95, - 0x2305_cd7a_921e_c5f1, - 0x027c_c4ef_e3fb_35dd, - ]), - pallas::Base::from_raw([ - 0xc3fa_2629_635d_27de, - 0x67f1_c6b7_3147_64af, - 0x61b7_1a36_9868_2ad2, - 0x037f_9f23_6595_4c5b, - ]), - ], - [ - pallas::Base::from_raw([ - 0x77c5_b024_8483_71ae, - 0x6041_4abe_362d_01c9, - 0x10f1_cc6d_f8b4_bcd7, - 0x1f69_7cac_4d07_feb7, - ]), - pallas::Base::from_raw([ - 0x786a_dd24_4aa0_ef29, - 0x3145_c478_0631_09d6, - 0x26e6_c851_fbd5_72a6, - 0x267a_750f_e5d7_cfbc, - ]), - pallas::Base::from_raw([ - 0x180e_2b4d_3e75_6f65, - 0xaf28_5fa8_2ce4_fae5, - 0x678c_9996_d9a4_72c8, - 0x0c91_feab_4a43_193a, - ]), - ], - [ - pallas::Base::from_raw([ - 0x79c4_7c57_3ac4_10f7, - 0x7e3b_83af_4a4b_a3ba, - 0x2186_c303_8ea0_5e69, - 0x1745_569a_0a3e_3014, - ]), - pallas::Base::from_raw([ - 0x1e03_8852_2696_191f, - 0xfdff_66c6_f3b5_ffe1, - 0xeca5_1207_78a5_6711, - 0x2986_3d54_6e7e_7c0d, - ]), - pallas::Base::from_raw([ - 0x2f22_5e63_66bf_e390, - 0xa79a_03df_8339_94c6, - 0xbf06_bae4_9ef8_53f6, - 0x1148_d6ab_2bd0_0192, - ]), - ], - [ - pallas::Base::from_raw([ - 0xf4f6_331a_8b26_5d15, - 0xf745_f45d_350d_41d4, - 0xe18b_1499_060d_a366, - 0x02e0_e121_b0f3_dfef, - ]), - pallas::Base::from_raw([ - 0x078a_e6aa_1510_54b7, - 0x6904_0173_6d44_a653, - 0xb89e_f73a_40a2_b274, - 0x0d0a_a46e_76a6_a278, - ]), - pallas::Base::from_raw([ - 0x9a4d_532c_7b6e_0958, - 0x392d_de71_0f1f_06db, - 0xeee5_45f3_fa6d_3d08, - 0x1394_3675_b04a_a986, - ]), - ], - [ - pallas::Base::from_raw([ - 0x961f_c818_dcbb_66b5, - 0xc9f2_b325_7530_dafe, - 0xd97a_11d6_3088_f5d9, - 0x2901_ec61_942d_34aa, - ]), - pallas::Base::from_raw([ - 0xfdf5_44b9_63d1_fdc7, - 0x22ff_a2a2_af9f_a3e3, - 0xf431_d544_34a3_e0cf, - 0x2020_4a21_05d2_2e7e, - ]), - pallas::Base::from_raw([ - 0x1211_b9e2_190d_6852, - 0xa004_abe8_e015_28c4, - 0x5c1e_3e9e_27a5_71c3, - 0x3a8a_6282_9512_1d5c, - ]), - ], -]; -// Secure MDS: 0 -// n: 255 -// t: 3 -// N: 765 -// Result Algorithm 1: -// [True, 0] -// Result Algorithm 2: -// [True, None] -// Result Algorithm 3: -// [True, None] -// Prime number: 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001 -// MDS matrix: -pub(crate) const MDS: [[pallas::Base; 3]; 3] = [ - [ - pallas::Base::from_raw([ - 0x323f_2486_d7e1_1b63, - 0x97d7_a0ab_2385_0b56, - 0xb3d5_9fbd_c8c9_ead4, - 0x0ab5_e5b8_74a6_8de7, - ]), - pallas::Base::from_raw([ - 0x8eca_5596_e996_ab5e, - 0x240d_4a7c_bf73_5736, - 0x293f_0f0d_886c_7954, - 0x3191_6628_e58a_5abb, - ]), - pallas::Base::from_raw([ - 0x19d1_cf25_d8e8_345d, - 0xa0a3_b71a_5fb1_5735, - 0xd803_952b_bb36_4fdf, - 0x07c0_45d5_f5e9_e5a6, - ]), - ], - [ - pallas::Base::from_raw([ - 0xd049_cdc8_d085_167c, - 0x3a0a_4640_48bd_770a, - 0xf8e2_4f66_822c_2d9f, - 0x2331_6263_0ebf_9ed7, - ]), - pallas::Base::from_raw([ - 0x4022_7011_3e04_7a2e, - 0x78f8_365c_85bb_ab07, - 0xb366_6454_8d60_957d, - 0x25ca_e259_9892_a8b0, - ]), - pallas::Base::from_raw([ - 0xf84d_806f_685f_747a, - 0x9aad_3d82_62ef_d83f, - 0x7493_8717_989a_1957, - 0x22f5_b5e1_e608_1c97, - ]), - ], - [ - pallas::Base::from_raw([ - 0xfee7_a994_4f84_dbe4, - 0x2168_0eab_c56b_c15d, - 0xf333_aa91_c383_3464, - 0x2e29_dd59_c64b_1037, - ]), - pallas::Base::from_raw([ - 0xc771_effa_4326_3664, - 0xcbea_f48b_3a06_24c3, - 0x92d1_5e7d_ceef_1665, - 0x1d1a_ab4e_c1cd_6788, - ]), - pallas::Base::from_raw([ - 0x1563_9415_f6e8_5ef1, - 0x7587_2c39_b59a_31f6, - 0x51e0_cbea_d655_16b9, - 0x3bf7_6308_6a18_9364, - ]), - ], -]; - -pub(crate) const MDS_INV: [[pallas::Base; 3]; 3] = [ - [ - pallas::Base::from_raw([ - 0xc6de_463c_d140_4e6b, - 0x4543_705f_35e9_8ab5, - 0xcc59_ffd0_0de8_6443, - 0x2cc0_57f3_fa14_687a, - ]), - pallas::Base::from_raw([ - 0x1718_4041_7cab_7576, - 0xfadb_f8ae_7ae2_4796, - 0x5fd7_2b55_df20_8385, - 0x32e7_c439_f2f9_67e5, - ]), - pallas::Base::from_raw([ - 0x9426_45bd_7d44_64e0, - 0x1403_db6f_5030_2040, - 0xf461_778a_bf6c_91fa, - 0x2eae_5df8_c311_5969, - ]), - ], - [ - pallas::Base::from_raw([ - 0xa1ca_1516_a4a1_a6a0, - 0x13f0_74fd_e9a1_8b29, - 0xdb18_b4ae_fe68_d26d, - 0x07bf_3684_8106_7199, - ]), - pallas::Base::from_raw([ - 0xe824_25bc_1b23_a059, - 0xbb1d_6504_0c85_c1bf, - 0x018a_918b_9dac_5dad, - 0x2aec_6906_c63f_3cf1, - ]), - pallas::Base::from_raw([ - 0xe054_1adf_238e_0781, - 0x76b2_a713_9db7_1b36, - 0x1215_944a_64a2_46b2, - 0x0952_e024_3aec_2af0, - ]), - ], - [ - pallas::Base::from_raw([ - 0x2a41_8d8d_73a7_c908, - 0xaef9_112e_952f_dbb5, - 0x723a_63a0_c09d_ab26, - 0x2fcb_ba6f_9159_a219, - ]), - pallas::Base::from_raw([ - 0x76ef_ab42_d4fb_a90b, - 0xc5e4_960d_7424_cd37, - 0xb4dd_d4b4_d645_2256, - 0x1ec7_3725_74f3_851b, - ]), - pallas::Base::from_raw([ - 0xadc8_933c_6f3c_72ee, - 0x87a7_435d_30f8_be81, - 0x3c26_fa4b_7d25_b1e4, - 0x0d0c_2efd_6472_f12a, - ]), - ], -]; diff --git a/halo2_gadgets/src/poseidon/primitives/fq.rs b/halo2_gadgets/src/poseidon/primitives/fq.rs deleted file mode 100644 index 3629318adc..0000000000 --- a/halo2_gadgets/src/poseidon/primitives/fq.rs +++ /dev/null @@ -1,1431 +0,0 @@ -//! Constants for using Poseidon with the Vesta field. -//! -//! The constants can be reproduced by running the following Sage script from -//! [this repository](https://github.com/daira/pasta-hadeshash): -//! -//! ```text -//! sage generate_parameters_grain.sage 1 0 255 3 8 56 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001 -//! ``` -use halo2curves::pasta::vesta; - -// Number of round constants: 192 -// Round constants for GF(p): -pub(crate) const ROUND_CONSTANTS: [[vesta::Base; 3]; 64] = [ - [ - vesta::Base::from_raw([ - 0x5753_8c25_9642_6303, - 0x4e71_162f_3100_3b70, - 0x353f_628f_76d1_10f3, - 0x360d_7470_611e_473d, - ]), - vesta::Base::from_raw([ - 0xbdb7_4213_bf63_188b, - 0x4908_ac2f_12eb_e06f, - 0x5dc3_c6c5_febf_aa31, - 0x2bab_94d7_ae22_2d13, - ]), - vesta::Base::from_raw([ - 0x0939_d927_53cc_5dc8, - 0xef77_e7d7_3676_6c5d, - 0x2bf0_3e1a_29aa_871f, - 0x150c_93fe_f652_fb1c, - ]), - ], - [ - vesta::Base::from_raw([ - 0x1425_9dce_5377_82b2, - 0x03cc_0a60_141e_894e, - 0x955d_55db_56dc_57c1, - 0x3270_661e_6892_8b3a, - ]), - vesta::Base::from_raw([ - 0xce9f_b9ff_c345_afb3, - 0xb407_c370_f2b5_a1cc, - 0xa0b7_afe4_e205_7299, - 0x073f_116f_0412_2e25, - ]), - vesta::Base::from_raw([ - 0x8eba_d76f_c715_54d8, - 0x55c9_cd20_61ae_93ca, - 0x7aff_d09c_1f53_f5fd, - 0x2a32_ec5c_4ee5_b183, - ]), - ], - [ - vesta::Base::from_raw([ - 0x2d8c_cbe2_92ef_eead, - 0x634d_24fc_6e25_59f2, - 0x651e_2cfc_7406_28ca, - 0x2703_26ee_039d_f19e, - ]), - vesta::Base::from_raw([ - 0xa068_fc37_c182_e274, - 0x8af8_95bc_e012_f182, - 0xdc10_0fe7_fcfa_5491, - 0x27c6_642a_c633_bc66, - ]), - vesta::Base::from_raw([ - 0x9ca1_8682_e26d_7ff9, - 0x710e_1fb6_ab97_6a45, - 0xd27f_5739_6989_129d, - 0x1bdf_d8b0_1401_c70a, - ]), - ], - [ - vesta::Base::from_raw([ - 0xc832_d824_261a_35ea, - 0xf4f6_fb3f_9054_d373, - 0x14b9_d6a9_c84d_d678, - 0x162a_14c6_2f9a_89b8, - ]), - vesta::Base::from_raw([ - 0xf798_2466_7b5b_6bec, - 0xac0a_1fc7_1e2c_f0c0, - 0x2af6_f79e_3127_feea, - 0x2d19_3e0f_76de_586b, - ]), - vesta::Base::from_raw([ - 0x5d0b_f58d_c8a4_aa94, - 0x4fef_f829_8499_0ff8, - 0x8169_6ef1_104e_674f, - 0x044c_a3cc_4a85_d73b, - ]), - ], - [ - vesta::Base::from_raw([ - 0x6198_785f_0cd6_b9af, - 0xb8d9_e2d4_f314_f46f, - 0x1d04_5341_6d3e_235c, - 0x1cba_f2b3_71da_c6a8, - ]), - vesta::Base::from_raw([ - 0x343e_0761_0f3f_ede5, - 0x293c_4ab0_38fd_bbdc, - 0x0e6c_49d0_61b6_b5f4, - 0x1d5b_2777_692c_205b, - ]), - vesta::Base::from_raw([ - 0xf60e_971b_8d73_b04f, - 0x06a9_adb0_c1e6_f962, - 0xaa30_535b_dd74_9a7e, - 0x2e9b_dbba_3dd3_4bff, - ]), - ], - [ - vesta::Base::from_raw([ - 0x035a_1366_1f22_418b, - 0xde40_fbe2_6d04_7b05, - 0x8bd5_bae3_6969_299f, - 0x2de1_1886_b180_11ca, - ]), - vesta::Base::from_raw([ - 0xbc99_8884_ba96_a721, - 0x2ab9_395c_449b_e947, - 0x0d5b_4a3f_1841_dcd8, - 0x2e07_de17_80b8_a70d, - ]), - vesta::Base::from_raw([ - 0x825e_4c2b_b749_25ca, - 0x2504_40a9_9d6b_8af3, - 0xbbdb_63db_d52d_ad16, - 0x0f69_f185_4d20_ca0c, - ]), - ], - [ - vesta::Base::from_raw([ - 0x816c_0594_22dc_705e, - 0x6ce5_1135_07f9_6de9, - 0x0d13_5dc6_39fb_09a4, - 0x2eb1_b254_17fe_1767, - ]), - vesta::Base::from_raw([ - 0xb8b1_bdf4_953b_d82c, - 0xff36_c661_d26c_c42d, - 0x8c24_cb44_c3fa_b48a, - 0x115c_d0a0_643c_fb98, - ]), - vesta::Base::from_raw([ - 0xde80_1612_311d_04cd, - 0xbb57_ddf1_4e0f_958a, - 0x066d_7378_b999_868b, - 0x26ca_293f_7b2c_462d, - ]), - ], - [ - vesta::Base::from_raw([ - 0xf520_9d14_b248_20ca, - 0x0f16_0bf9_f71e_967f, - 0x2a83_0aa1_6241_2cd9, - 0x17bf_1b93_c4c7_e01a, - ]), - vesta::Base::from_raw([ - 0x05c8_6f2e_7dc2_93c5, - 0xe03c_0354_bd8c_fd38, - 0xa24f_8456_369c_85df, - 0x35b4_1a7a_c4f3_c571, - ]), - vesta::Base::from_raw([ - 0x72ac_156a_f435_d09e, - 0x64e1_4d3b_eb2d_ddde, - 0x4359_2799_4849_bea9, - 0x3b14_8008_0523_c439, - ]), - ], - [ - vesta::Base::from_raw([ - 0x2716_18d8_74b1_4c6d, - 0x08e2_8644_2a2d_3eb2, - 0x4950_856d_c907_d575, - 0x2cc6_8100_31dc_1b0d, - ]), - vesta::Base::from_raw([ - 0x91f3_18c0_9f0c_b566, - 0x9e51_7aa9_3b78_341d, - 0x0596_18e2_afd2_ef99, - 0x25bd_bbed_a1bd_e8c1, - ]), - vesta::Base::from_raw([ - 0xc631_3487_073f_7f7b, - 0x2a5e_d0a2_7b61_926c, - 0xb95f_33c2_5dde_8ac0, - 0x392a_4a87_58e0_6ee8, - ]), - ], - [ - vesta::Base::from_raw([ - 0xe7bb_cef0_2eb5_866c, - 0x5e6a_6fd1_5db8_9365, - 0x9aa6_111f_4de0_0948, - 0x272a_5587_8a08_442b, - ]), - vesta::Base::from_raw([ - 0x9b92_5b3c_5b21_e0e2, - 0xa6eb_ba01_1694_dd12, - 0xefa1_3c4e_60e2_6239, - 0x2d5b_308b_0cf0_2cdf, - ]), - vesta::Base::from_raw([ - 0xef38_c57c_3116_73ac, - 0x44df_f42f_18b4_6c56, - 0xdd5d_293d_72e2_e5f2, - 0x1654_9fc6_af2f_3b72, - ]), - ], - [ - vesta::Base::from_raw([ - 0x9b71_26d9_b468_60df, - 0x7639_8265_3442_0311, - 0xfa69_c3a2_ad52_f76d, - 0x1b10_bb7a_82af_ce39, - ]), - vesta::Base::from_raw([ - 0x90d2_7f6a_00b7_dfc8, - 0xd1b3_6968_ba04_05c0, - 0xc79c_2df7_dc98_a3be, - 0x0f1e_7505_ebd9_1d2f, - ]), - vesta::Base::from_raw([ - 0xff45_7756_b819_bb20, - 0x797f_d6e3_f18e_b1ca, - 0x537a_7497_a3b4_3f46, - 0x2f31_3faf_0d3f_6187, - ]), - ], - [ - vesta::Base::from_raw([ - 0xf0bc_3e73_2ecb_26f6, - 0x5cad_11eb_f0f7_ceb8, - 0xfa3c_a61c_0ed1_5bc5, - 0x3a5c_bb6d_e450_b481, - ]), - vesta::Base::from_raw([ - 0x8655_27cb_ca91_5982, - 0x51ba_a6e2_0f89_2b62, - 0xd920_86e2_53b4_39d6, - 0x3dab_54bc_9bef_688d, - ]), - vesta::Base::from_raw([ - 0x3680_45ac_f2b7_1ae3, - 0x4c24_b33b_410f_efd4, - 0xe280_d316_7012_3f74, - 0x06db_fb42_b979_884d, - ]), - ], - [ - vesta::Base::from_raw([ - 0xa7fc_32d2_2f18_b9d3, - 0xb8d2_de72_e3d2_c9ec, - 0xc6f0_39ea_1973_a63e, - 0x068d_6b46_08aa_e810, - ]), - vesta::Base::from_raw([ - 0x2b5d_fcc5_5725_55df, - 0xb868_a7d7_e1f1_f69a, - 0x0ee2_58c9_b8fd_fccd, - 0x366e_bfaf_a3ad_381c, - ]), - vesta::Base::from_raw([ - 0xe6bc_229e_95bc_76b1, - 0x7ef6_6d89_d044_d022, - 0x04db_3024_f41d_3f56, - 0x3967_8f65_512f_1ee4, - ]), - ], - [ - vesta::Base::from_raw([ - 0xe534_c88f_e53d_85fe, - 0xcf82_c25f_99dc_01a4, - 0xd58b_7750_a3bc_2fe1, - 0x2166_8f01_6a80_63c0, - ]), - vesta::Base::from_raw([ - 0x4bef_429b_c533_1608, - 0xe34d_ea56_439f_e195, - 0x1bc7_4936_3e98_a768, - 0x39d0_0994_a8a5_046a, - ]), - vesta::Base::from_raw([ - 0x770c_956f_60d8_81b3, - 0xb163_d416_05d3_9f99, - 0x6b20_3bbe_12fb_3425, - 0x1f9d_bdc3_f843_1263, - ]), - ], - [ - vesta::Base::from_raw([ - 0x9794_a9f7_c336_eab2, - 0xbe0b_c829_fe5e_66c6, - 0xe5f1_7b9e_0ee0_cab6, - 0x0277_45a9_cddf_ad95, - ]), - vesta::Base::from_raw([ - 0x5202_5657_abd8_aee0, - 0x2fa4_3fe2_0a45_c78d, - 0x788d_695c_61e9_3212, - 0x1cec_0803_c504_b635, - ]), - vesta::Base::from_raw([ - 0xd387_2a95_59a0_3a73, - 0xed50_82c8_dbf3_1365, - 0x7207_7448_ef87_cc6e, - 0x1235_23d7_5e9f_abc1, - ]), - ], - [ - vesta::Base::from_raw([ - 0x0017_79e3_a1d3_57f4, - 0x27fe_ba35_975e_e7e5, - 0xf419_b848_e5d6_94bf, - 0x1723_d145_2c9c_f02d, - ]), - vesta::Base::from_raw([ - 0x9dab_1ee4_dcf9_6622, - 0x21c3_f776_f572_836d, - 0xfcc0_573d_7e61_3694, - 0x1739_d180_a160_10bd, - ]), - vesta::Base::from_raw([ - 0x7029_0452_042d_048d, - 0xfafa_96fb_eb0a_b893, - 0xacce_3239_1794_b627, - 0x2d4e_6354_da9c_c554, - ]), - ], - [ - vesta::Base::from_raw([ - 0x670b_cf6f_8b48_5dcd, - 0x8f3b_d43f_9926_0621, - 0x4a86_9553_c9d0_07f8, - 0x153e_e614_2e53_5e33, - ]), - vesta::Base::from_raw([ - 0xd258_d2e2_b778_2172, - 0x968a_d442_4af8_3700, - 0x635e_f7e7_a430_b486, - 0x0c45_bfd3_a69a_aa65, - ]), - vesta::Base::from_raw([ - 0x0e56_33d2_51f7_3307, - 0x6897_ac0a_8ffa_5ff1, - 0xf2d5_6aec_8314_4600, - 0x0adf_d53b_256a_6957, - ]), - ], - [ - vesta::Base::from_raw([ - 0xac9d_36a8_b751_6d63, - 0x3f87_b28f_1c1b_e4bd, - 0x8cd1_726b_7cba_b8ee, - 0x315d_2ac8_ebdb_ac3c, - ]), - vesta::Base::from_raw([ - 0x299c_e44e_a423_d8e1, - 0xc9bb_60d1_f695_9879, - 0xcfae_c23d_2b16_883f, - 0x1b84_7271_2d02_eef4, - ]), - vesta::Base::from_raw([ - 0xc4a5_4041_98ad_f70c, - 0x367d_2c54_e369_28c9, - 0xbd0b_70fa_2255_eb6f, - 0x3c1c_d07e_fda6_ff24, - ]), - ], - [ - vesta::Base::from_raw([ - 0xbbe5_23ae_f9ab_107a, - 0x4a16_073f_738f_7e0c, - 0x687f_4e51_b2e1_dcd3, - 0x1360_52d2_6bb3_d373, - ]), - vesta::Base::from_raw([ - 0x676c_36c2_4ef9_67dd, - 0x7b3c_fbb8_7303_2681, - 0xc1bd_d859_a123_2a1d, - 0x16c9_6bee_f6a0_a848, - ]), - vesta::Base::from_raw([ - 0x067e_ec7f_2d63_40c4, - 0x0123_87ba_b4f1_662d, - 0x2ab7_fed8_f499_a9fb, - 0x284b_38c5_7ff6_5c26, - ]), - ], - [ - vesta::Base::from_raw([ - 0xaf1d_ff20_4c92_2f86, - 0xfc06_772c_1c04_11a6, - 0x39e2_4219_8897_d17c, - 0x0c59_93d1_75e8_1f66, - ]), - vesta::Base::from_raw([ - 0xbbf5_3f67_b1f8_7b15, - 0xf248_87ad_48e1_7759, - 0xfcda_655d_1ba9_c8f9, - 0x03bf_7a3f_7bd0_43da, - ]), - vesta::Base::from_raw([ - 0x9b5c_d09e_36d8_be62, - 0x4c8f_9cbe_69f0_e827, - 0xb0cf_9995_67f0_0e73, - 0x3188_fe4e_e9f9_fafb, - ]), - ], - [ - vesta::Base::from_raw([ - 0xafea_99a2_ec6c_595a, - 0x3af5_bf77_c1c4_2652, - 0x5a39_768c_480d_61e1, - 0x171f_528c_cf65_8437, - ]), - vesta::Base::from_raw([ - 0x5a05_63b9_b8e9_f1d5, - 0x812c_3286_ee70_0067, - 0x196e_4185_9b35_ef88, - 0x12f4_175c_4ab4_5afc, - ]), - vesta::Base::from_raw([ - 0x0e74_d4d3_6911_8b79, - 0x7e23_e1aa_be96_cfab, - 0x8f8f_dcf8_00a9_ac69, - 0x3a50_9e15_5cb7_ebfd, - ]), - ], - [ - vesta::Base::from_raw([ - 0x9871_2c65_678c_fd30, - 0x984b_c8f2_e4c1_b69e, - 0x1a89_920e_2504_c3b3, - 0x10f2_a685_df4a_27c8, - ]), - vesta::Base::from_raw([ - 0xe8a1_6728_cc9d_4918, - 0x5457_3c93_33c5_6321, - 0x1d8d_93d5_4ab9_1a0e, - 0x09e5_f497_90c8_a0e2, - ]), - vesta::Base::from_raw([ - 0x609a_7403_47cf_5fea, - 0x42d1_7ed6_ee0f_ab7e, - 0x2bf3_5705_d9f8_4a34, - 0x352d_69be_d80e_e3e5, - ]), - ], - [ - vesta::Base::from_raw([ - 0x3a75_8af6_fa84_e0e8, - 0xc634_debd_281b_76a6, - 0x4915_62fa_f2b1_90d3, - 0x058e_e73b_a9f3_f293, - ]), - vesta::Base::from_raw([ - 0x621a_1325_10a4_3904, - 0x092c_b921_19bc_76be, - 0xcd0f_1fc5_5b1a_3250, - 0x232f_99cc_911e_ddd9, - ]), - vesta::Base::from_raw([ - 0xc3b9_7c1e_301b_c213, - 0xf9ef_d52c_a6bc_2961, - 0x86c2_2c6c_5d48_69f0, - 0x201b_eed7_b8f3_ab81, - ]), - ], - [ - vesta::Base::from_raw([ - 0xbf6b_3431_ba94_e9bc, - 0x2938_8842_744a_1210, - 0xa1c9_291d_5860_2f51, - 0x1376_dce6_5800_30c6, - ]), - vesta::Base::from_raw([ - 0x6454_843c_5486_d7b3, - 0x072b_a8b0_2d92_e722, - 0x2b33_56c3_8238_f761, - 0x1793_199e_6fd6_ba34, - ]), - vesta::Base::from_raw([ - 0x06a3_f1d3_b433_311b, - 0x3c66_160d_c62a_acac, - 0x9fee_9c20_c87a_67df, - 0x22de_7a74_88dc_c735, - ]), - ], - [ - vesta::Base::from_raw([ - 0x30d6_e3fd_516b_47a8, - 0xdbe0_b77f_ae77_e1d0, - 0xdf8f_f37f_e2d8_edf8, - 0x3514_d5e9_066b_b160, - ]), - vesta::Base::from_raw([ - 0x1937_7427_137a_81c7, - 0xff45_3d6f_900f_144a, - 0xf919_a00d_abbf_5fa5, - 0x30cd_3006_931a_d636, - ]), - vesta::Base::from_raw([ - 0x5b6a_7422_0692_b506, - 0x8f9e_4b2c_ae2e_bb51, - 0x41f8_1a5c_f613_c8df, - 0x253d_1a5c_5293_4127, - ]), - ], - [ - vesta::Base::from_raw([ - 0x73f6_66cb_86a4_8e8e, - 0x851b_3a59_c990_fafc, - 0xa35e_9613_e7f5_fe92, - 0x035b_461c_02d7_9d19, - ]), - vesta::Base::from_raw([ - 0x7cfb_f86a_3aa0_4780, - 0x92b1_283c_2d5f_ccde, - 0x5bc0_0eed_d56b_93e0, - 0x23a9_9280_79d1_75bd, - ]), - vesta::Base::from_raw([ - 0xf1e4_ccd7_3fa0_0a82, - 0xb5e2_ea34_36ee_f957, - 0xf159_4a07_63c6_11ab, - 0x13a7_785a_e134_ea92, - ]), - ], - [ - vesta::Base::from_raw([ - 0xbbf0_4f52_52de_4279, - 0x3889_c578_6344_6d88, - 0x4962_ae3c_0da1_7e31, - 0x39fc_e308_b7d4_3c57, - ]), - vesta::Base::from_raw([ - 0x3b57_e344_89b5_3fad, - 0xbef0_0a08_c6ed_38d2, - 0xc0fd_f016_62f6_0d22, - 0x1aae_1883_3f8e_1d3a, - ]), - vesta::Base::from_raw([ - 0x5551_3e03_3398_513f, - 0x27c1_b3fd_8f85_d8a8, - 0x8b2e_80c0_64fd_83ed, - 0x1a76_1ce8_2400_af01, - ]), - ], - [ - vesta::Base::from_raw([ - 0x5244_ca74_9b73_e481, - 0xdcf6_af28_30a5_0287, - 0x16dd_1a87_ca22_e1cc, - 0x275a_03e4_5add_a7c3, - ]), - vesta::Base::from_raw([ - 0x58a2_53cf_b6a9_5786, - 0x07e5_6145_3fc5_648b, - 0xeb08_e47e_5fea_bcf8, - 0x2e5a_10f0_8b5a_b8bb, - ]), - vesta::Base::from_raw([ - 0xe033_d82c_efe7_8ce3, - 0xc141_a5b6_d594_bec4, - 0xb84e_9c33_3b29_32f1, - 0x1459_cb85_8720_8473, - ]), - ], - [ - vesta::Base::from_raw([ - 0x5cec_7e7b_338f_be1b, - 0x52f9_332f_bffc_fbbd, - 0x7b92_ce81_0e14_a400, - 0x193a_e592_1d78_b5de, - ]), - vesta::Base::from_raw([ - 0x6022_4be6_7248_e82c, - 0x3743_84f4_a072_8205, - 0x8911_1fb2_c466_0281, - 0x3097_898a_5d00_11a4, - ]), - vesta::Base::from_raw([ - 0x5499_80de_8629_30f5, - 0x1979_b2d1_c465_b4d9, - 0x5717_82fd_96ce_54b4, - 0x378d_97bf_8c86_4ae7, - ]), - ], - [ - vesta::Base::from_raw([ - 0x37ea_32a9_71d1_7884, - 0xdbc7_f5cb_4609_3421, - 0x8813_6287_ce37_6b08, - 0x2eb0_4ea7_c01d_97ec, - ]), - vesta::Base::from_raw([ - 0xead3_726f_1af2_e7b0, - 0x861c_bda4_7680_4e6c, - 0x2302_a1c2_2e49_baec, - 0x3642_5347_ea03_f641, - ]), - vesta::Base::from_raw([ - 0xecd6_27e5_9590_d09e, - 0x3f5b_5ca5_a19a_9701, - 0xcc99_6cd8_5c98_a1d8, - 0x26b7_2df4_7408_ad42, - ]), - ], - [ - vesta::Base::from_raw([ - 0x59be_ce31_f0a3_1e95, - 0xde01_212e_e458_8f89, - 0x1f05_636c_610b_89aa, - 0x1301_80e4_4e29_24db, - ]), - vesta::Base::from_raw([ - 0x9ea8_e7bc_7926_3550, - 0xdf77_93cc_89e5_b52f, - 0x7327_5aca_ed5f_579c, - 0x219e_9773_7d39_79ba, - ]), - vesta::Base::from_raw([ - 0x9c12_635d_f251_d153, - 0x3b06_72dd_7d42_cbb4, - 0x3461_363f_81c4_89a2, - 0x3cdb_9359_8a5c_a528, - ]), - ], - [ - vesta::Base::from_raw([ - 0x2861_ce16_f219_d5a9, - 0x4ad0_4470_45a7_c5aa, - 0x2072_4b92_7a0c_a81c, - 0x0e59_e6f3_32d7_ed37, - ]), - vesta::Base::from_raw([ - 0x43b0_a3fc_ff20_36bd, - 0x172c_c07b_9d33_fbf9, - 0x3d73_6946_7222_697a, - 0x1b06_4342_d51a_4275, - ]), - vesta::Base::from_raw([ - 0x3eb3_1022_8a0e_5f6c, - 0x78fa_9fb9_1712_21b7, - 0x2f36_3c55_b288_2e0b, - 0x30b8_2a99_8cbd_8e8a, - ]), - ], - [ - vesta::Base::from_raw([ - 0xe46f_6d42_9874_0107, - 0x8ad7_1ea7_15be_0573, - 0x63df_7a76_e858_a4aa, - 0x23e4_ab37_183a_cba4, - ]), - vesta::Base::from_raw([ - 0xfca9_95e2_b599_14a1, - 0xacfe_1464_0de0_44f2, - 0x5d33_094e_0bed_a75b, - 0x2795_d5c5_fa42_8022, - ]), - vesta::Base::from_raw([ - 0xc26d_909d_ee8b_53c0, - 0xa668_7c3d_f16c_8fe4, - 0xd765_f26d_d03f_4c45, - 0x3001_ca40_1e89_601c, - ]), - ], - [ - vesta::Base::from_raw([ - 0xe7fe_a6bd_f347_1380, - 0xe84b_5beb_ae4e_501d, - 0xf7bf_86e8_9280_827f, - 0x0072_e45c_c676_b08e, - ]), - vesta::Base::from_raw([ - 0xd0c5_4dde_b26b_86c0, - 0xb648_29e2_d40e_41bd, - 0xe2ab_e4c5_18ce_599e, - 0x13de_7054_8487_4bb5, - ]), - vesta::Base::from_raw([ - 0x3891_5b43_2a99_59a5, - 0x82bb_18e5_af1b_05bb, - 0x3159_50f1_211d_efe8, - 0x0408_a9fc_f9d6_1abf, - ]), - ], - [ - vesta::Base::from_raw([ - 0x3407_0cbe_e268_86a0, - 0xae4d_23b0_b41b_e9a8, - 0xbb4e_4a14_00cc_d2c4, - 0x2780_b9e7_5b55_676e, - ]), - vesta::Base::from_raw([ - 0x9405_5920_98b4_056f, - 0xdc4d_8fbe_fe24_405a, - 0xf803_33ec_8563_4ac9, - 0x3a57_0d4d_7c4e_7ac3, - ]), - vesta::Base::from_raw([ - 0x78d2_b247_8995_20b4, - 0xe2cc_1507_bebd_cc62, - 0xf347_c247_fcf0_9294, - 0x0c13_cca7_cb1f_9d2c, - ]), - ], - [ - vesta::Base::from_raw([ - 0x2e8c_88f7_7074_70e0, - 0x0b50_bb2e_b82d_f74d, - 0xd261_4a19_7c6b_794b, - 0x14f5_9baa_03cd_0ca4, - ]), - vesta::Base::from_raw([ - 0xbe52_476e_0a16_f3be, - 0xa51d_54ed_e661_67f5, - 0x6f54_6e17_04c3_9c60, - 0x307d_efee_925d_fb43, - ]), - vesta::Base::from_raw([ - 0x380b_67d8_0473_dce3, - 0x6611_0683_6adf_e5e7, - 0x7a07_e767_4b5a_2621, - 0x1960_cd51_1a91_e060, - ]), - ], - [ - vesta::Base::from_raw([ - 0x15aa_f1f7_7125_89dd, - 0xb8ee_335d_8828_4cbe, - 0xca2a_d0fb_5667_2500, - 0x2301_ef9c_63ea_84c5, - ]), - vesta::Base::from_raw([ - 0x5e68_478c_4d60_27a9, - 0xc861_82d1_b424_6b58, - 0xd10f_4cd5_2be9_7f6b, - 0x029a_5a47_da79_a488, - ]), - vesta::Base::from_raw([ - 0x2cc4_f962_eaae_2260, - 0xf97f_e46b_6a92_5428, - 0x2360_d17d_890e_55cb, - 0x32d7_b16a_7f11_cc96, - ]), - ], - [ - vesta::Base::from_raw([ - 0xc0ca_b915_d536_3d9f, - 0xa5f2_404c_d7b3_5eb0, - 0x18e8_57a9_8d49_8cf7, - 0x2670_3e48_c03b_81ca, - ]), - vesta::Base::from_raw([ - 0xf691_123a_e112_b928, - 0xf443_88bd_6b89_221e, - 0x88ac_8d25_a246_03f1, - 0x0486_82a3_5b32_65bc, - ]), - vesta::Base::from_raw([ - 0x3ab7_defc_b8d8_03e2, - 0x91d6_e171_5164_775e, - 0xd72c_ddc6_cf06_b507, - 0x06b1_3904_41fa_7030, - ]), - ], - [ - vesta::Base::from_raw([ - 0xbcd7_9541_4a6e_2e86, - 0x43b3_60f6_386a_86d7, - 0x1689_426d_ce05_fcd8, - 0x31aa_0eeb_868c_626d, - ]), - vesta::Base::from_raw([ - 0xed77_f5d5_76b9_9cc3, - 0x90ef_d8f4_1b20_78b2, - 0x057a_bad3_764c_104b, - 0x2394_64f7_5bf7_b6af, - ]), - vesta::Base::from_raw([ - 0xb2cb_4873_07c1_cecf, - 0xa5cc_47c5_9654_b2a7, - 0xa45e_19ed_813a_54ab, - 0x0a64_d4c0_4fd4_26bd, - ]), - ], - [ - vesta::Base::from_raw([ - 0x1f73_1532_2f65_8735, - 0x777c_7a92_1a06_2e9d, - 0x576a_4ad2_5986_0fb1, - 0x21fb_bdbb_7367_0734, - ]), - vesta::Base::from_raw([ - 0x6743_2400_3fc5_2146, - 0x5b86_d294_63d3_1564, - 0xd937_1ca2_eb95_acf3, - 0x31b8_6f3c_f017_05d4, - ]), - vesta::Base::from_raw([ - 0x7045_f48a_a4eb_4f6f, - 0x1354_1d65_157e_e1ce, - 0x05ef_1736_d090_56f6, - 0x2bfd_e533_5437_7c91, - ]), - ], - [ - vesta::Base::from_raw([ - 0x5a13_a58d_2001_1e2f, - 0xf4d5_239c_11d0_eafa, - 0xd558_f36e_65f8_eca7, - 0x1233_ca93_6ec2_4671, - ]), - vesta::Base::from_raw([ - 0x6e70_af0a_7a92_4b3a, - 0x8780_58d0_234a_576f, - 0xc437_846d_8e0b_2b30, - 0x27d4_52a4_3ac7_dea2, - ]), - vesta::Base::from_raw([ - 0xa025_76b9_4392_f980, - 0x6a30_641a_1c3d_87b2, - 0xe816_ea8d_a493_e0fa, - 0x2699_dba8_2184_e413, - ]), - ], - [ - vesta::Base::from_raw([ - 0x608c_6f7a_61b5_6e55, - 0xf185_8466_4f8c_ab49, - 0xc398_8bae_e42e_4b10, - 0x36c7_22f0_efcc_8803, - ]), - vesta::Base::from_raw([ - 0x6e49_ac17_0dbb_7fcd, - 0x85c3_8899_a7b5_a833, - 0x08b0_f2ec_89cc_aa37, - 0x02b3_ff48_861e_339b, - ]), - vesta::Base::from_raw([ - 0xa8c5_ae03_ad98_e405, - 0x6fc3_ff4c_49eb_59ad, - 0x6016_2f44_27bc_657b, - 0x0b70_d061_d58d_8a7f, - ]), - ], - [ - vesta::Base::from_raw([ - 0x2e06_cc4a_f33b_0a06, - 0xad3d_e8be_46ed_9693, - 0xf875_3ade_b9d7_cee2, - 0x3fc2_a13f_127f_96a4, - ]), - vesta::Base::from_raw([ - 0xc120_80ac_117e_e15f, - 0x00cb_3d62_1e17_1d80, - 0x1bd6_3434_ac8c_419f, - 0x0c41_a6e4_8dd2_3a51, - ]), - vesta::Base::from_raw([ - 0x9685_213e_9692_f5e1, - 0x72aa_ad7e_4e75_339d, - 0xed44_7653_7169_084e, - 0x2de8_072a_6bd8_6884, - ]), - ], - [ - vesta::Base::from_raw([ - 0x0ad0_1184_567b_027c, - 0xb81c_f735_cc9c_39c0, - 0x9d34_96a3_d9fe_05ec, - 0x0355_7a8f_7b38_a17f, - ]), - vesta::Base::from_raw([ - 0x45bc_b5ac_0082_6abc, - 0x060f_4336_3d81_8e54, - 0xee97_6d34_282f_1a37, - 0x0b5f_5955_2f49_8735, - ]), - vesta::Base::from_raw([ - 0x2f29_09e1_7e22_b0df, - 0xf5d6_46e5_7507_e548, - 0xfedb_b185_70dc_7300, - 0x0e29_23a5_fee7_b878, - ]), - ], - [ - vesta::Base::from_raw([ - 0xf71e_ed73_f15b_3326, - 0xcf1c_b37c_3b03_2af6, - 0xc787_be97_020a_7fdd, - 0x1d78_5005_a7a0_0592, - ]), - vesta::Base::from_raw([ - 0x0acf_bfb2_23f8_f00d, - 0xa590_b88a_3b06_0294, - 0x0ba5_fedc_b8f2_5bd2, - 0x1ad7_72c2_73d9_c6df, - ]), - vesta::Base::from_raw([ - 0xc1ce_13d6_0f2f_5031, - 0x8105_10eb_61f0_672d, - 0xa78f_3275_c278_234b, - 0x027b_d647_85fc_bd2a, - ]), - ], - [ - vesta::Base::from_raw([ - 0x8337_f5e0_7923_a853, - 0xe224_3134_6945_7b8e, - 0xce6f_8ffe_a103_1b6d, - 0x2080_0f44_1b4a_0526, - ]), - vesta::Base::from_raw([ - 0xa33d_7bed_89a4_408a, - 0x36cd_c8ee_d662_ad37, - 0x6eea_2cd4_9f43_12b4, - 0x3d5a_d61d_7b65_f938, - ]), - vesta::Base::from_raw([ - 0x3bbb_ae94_cc19_5284, - 0x1df9_6cc0_3ea4_b26d, - 0x02c5_f91b_e4dd_8e3d, - 0x1333_8bc3_51fc_46dd, - ]), - ], - [ - vesta::Base::from_raw([ - 0xc527_1c29_7852_819e, - 0x646c_49f9_b46c_bf19, - 0xb87d_b1e2_af3e_a923, - 0x25e5_2be5_07c9_2760, - ]), - vesta::Base::from_raw([ - 0x5c38_0ab7_01b5_2ea9, - 0xa34c_83a3_485c_6b2d, - 0x7109_6d8b_1b98_3c98, - 0x1c49_2d64_c157_aaa4, - ]), - vesta::Base::from_raw([ - 0xa20c_0b3d_a0da_4ca3, - 0xd434_87bc_288d_f682, - 0xf4e6_c5e7_a573_f592, - 0x0c5b_8015_7999_2718, - ]), - ], - [ - vesta::Base::from_raw([ - 0x7ea3_3c93_e408_33cf, - 0x584e_9e62_a7f9_554e, - 0x6869_5c0c_d7cb_f43d, - 0x1090_b1b4_d2be_be7a, - ]), - vesta::Base::from_raw([ - 0xe383_e1ec_3baa_8d69, - 0x1b21_8e35_ecf2_328e, - 0x68f5_ce5c_bed1_9cad, - 0x33e3_8018_a801_387a, - ]), - vesta::Base::from_raw([ - 0xb76b_0b3d_787e_e953, - 0x5f4a_02d2_8729_e3ae, - 0xeef8_d83d_0e87_6bac, - 0x1654_af18_772b_2da5, - ]), - ], - [ - vesta::Base::from_raw([ - 0xef7c_e6a0_1326_5477, - 0xbb08_9387_0367_ec6c, - 0x4474_2de8_8c5a_b0d5, - 0x1678_be3c_c9c6_7993, - ]), - vesta::Base::from_raw([ - 0xaf5d_4789_3348_f766, - 0xdaf1_8183_55b1_3b4f, - 0x7ff9_c6be_546e_928a, - 0x3780_bd1e_01f3_4c22, - ]), - vesta::Base::from_raw([ - 0xa123_8032_0d7c_c1de, - 0x5d11_e69a_a6c0_b98c, - 0x0786_018e_7cb7_7267, - 0x1e83_d631_5c9f_125b, - ]), - ], - [ - vesta::Base::from_raw([ - 0x1799_603e_855c_e731, - 0xc486_894d_76e0_c33b, - 0x160b_4155_2f29_31c8, - 0x354a_fd0a_2f9d_0b26, - ]), - vesta::Base::from_raw([ - 0x8b99_7ee0_6be1_bff3, - 0x60b0_0dbe_1fac_ed07, - 0x2d8a_ffa6_2905_c5a5, - 0x00cd_6d29_f166_eadc, - ]), - vesta::Base::from_raw([ - 0x08d0_6419_1708_2f2c, - 0xc60d_0197_3f18_3057, - 0xdbe0_e3d7_cdbc_66ef, - 0x1d62_1935_2768_e3ae, - ]), - ], - [ - vesta::Base::from_raw([ - 0xfa08_dd98_0638_7577, - 0xafe3_ca1d_b8d4_f529, - 0xe48d_2370_d7d1_a142, - 0x1463_36e2_5db5_181d, - ]), - vesta::Base::from_raw([ - 0xa901_d3ce_84de_0ad4, - 0x022e_54b4_9c13_d907, - 0x997a_2116_3e2e_43df, - 0x0005_d8e0_85fd_72ee, - ]), - vesta::Base::from_raw([ - 0x1c36_f313_4196_4484, - 0x6f8e_bc1d_2296_021a, - 0x0dd5_e61c_8a4e_8642, - 0x364e_97c7_a389_3227, - ]), - ], - [ - vesta::Base::from_raw([ - 0xd7a0_0c03_d2e0_baaa, - 0xfa97_ec80_ad30_7a52, - 0x561c_6fff_1534_6878, - 0x0118_9910_671b_c16b, - ]), - vesta::Base::from_raw([ - 0x63fd_8ac5_7a95_ca8c, - 0x4c0f_7e00_1df4_90aa, - 0x5229_dfaa_0123_1a45, - 0x162a_7c80_f4d2_d12e, - ]), - vesta::Base::from_raw([ - 0x32e6_9efb_22f4_0b96, - 0xcaff_31b4_fda3_2124, - 0x2604_e4af_b09f_8603, - 0x2a0d_6c09_5766_66bb, - ]), - ], - [ - vesta::Base::from_raw([ - 0xc0a0_180f_8cbf_c0d2, - 0xf444_d10d_63a7_4e2c, - 0xe16a_4d60_3d5a_808e, - 0x0978_e5c5_1e1e_5649, - ]), - vesta::Base::from_raw([ - 0x03f4_460e_bc35_1b6e, - 0x0508_7d90_3bda_cfd1, - 0xebe1_9bbd_ce25_1011, - 0x1bdc_ee3a_aca9_cd25, - ]), - vesta::Base::from_raw([ - 0xf619_64bf_3ade_7670, - 0x0c94_7321_e007_5e3f, - 0xe494_7914_0b19_44fd, - 0x1862_cccb_70b5_b885, - ]), - ], - [ - vesta::Base::from_raw([ - 0xc326_7da6_e94a_dc50, - 0x39ee_99c1_cc6e_5dda, - 0xbc26_cc88_3a19_87e1, - 0x1f3e_91d8_63c1_6922, - ]), - vesta::Base::from_raw([ - 0x0f85_b4ac_2c36_7406, - 0xfa66_1465_c656_ad99, - 0xef5c_08f8_478f_663a, - 0x1af4_7a48_a601_6a49, - ]), - vesta::Base::from_raw([ - 0x0eab_cd87_e7d0_1b15, - 0x1c36_98b0_a2e3_da10, - 0x009d_5733_8c69_3505, - 0x3c8e_e901_956e_3d3f, - ]), - ], - [ - vesta::Base::from_raw([ - 0x8b94_7721_8967_3476, - 0xe10c_e2b7_069f_4dbd, - 0x68d0_b024_f591_b520, - 0x1660_a8cd_e7fe_c553, - ]), - vesta::Base::from_raw([ - 0x9d8d_0f67_fdaa_79d5, - 0x3963_c2c1_f558_6e2f, - 0x1303_9363_34dd_1132, - 0x0f6d_9919_29d5_e4e7, - ]), - vesta::Base::from_raw([ - 0x7a43_3091_e1ce_2d3a, - 0x4e7f_da77_0712_f343, - 0xcc62_5eaa_ab52_b4dc, - 0x02b9_cea1_921c_d9f6, - ]), - ], - [ - vesta::Base::from_raw([ - 0x3797_b2d8_3760_43b3, - 0xd8ca_f468_976f_0472, - 0x214f_7c67_84ac_b565, - 0x14a3_23b9_9b90_0331, - ]), - vesta::Base::from_raw([ - 0x347f_ef2c_00f0_953a, - 0x718b_7fbc_7788_af78, - 0xec01_ea79_642d_5760, - 0x1904_76b5_80cb_9277, - ]), - vesta::Base::from_raw([ - 0xff4e_7e6f_b268_dfd7, - 0x9660_902b_6008_7651, - 0xa424_63d3_0b44_2b6f, - 0x090a_3a9d_869d_2eef, - ]), - ], - [ - vesta::Base::from_raw([ - 0xf983_387e_a045_6203, - 0xe365_0013_04f9_a11e, - 0x0dbe_8fd2_270a_6795, - 0x3877_a955_8636_7567, - ]), - vesta::Base::from_raw([ - 0x39c0_af0f_e01f_4a06, - 0x6011_8c53_a218_1352, - 0x5df3_9a2c_c63d_dc0a, - 0x2d89_4691_240f_e953, - ]), - vesta::Base::from_raw([ - 0x1aca_9eaf_9bba_9850, - 0x5914_e855_eeb4_4aa1, - 0x7ef7_1780_2016_6189, - 0x21b9_c182_92bd_bc59, - ]), - ], - [ - vesta::Base::from_raw([ - 0x33f5_09a7_4ad9_d39b, - 0x272e_1cc6_c36a_2968, - 0x505a_05f2_a6ae_834c, - 0x2fe7_6be7_cff7_23e2, - ]), - vesta::Base::from_raw([ - 0x0df9_fa97_277f_a8b4, - 0xd15b_ff84_0dda_e8a5, - 0x9299_81d7_cfce_253b, - 0x187a_a448_f391_e3ca, - ]), - vesta::Base::from_raw([ - 0xf0c6_6af5_ffc7_3736, - 0x663c_cf7b_2ffe_4b5e, - 0x007a_b3aa_3617_f422, - 0x0b70_83ad_7517_07bf, - ]), - ], - [ - vesta::Base::from_raw([ - 0x2f9b_20f1_fbd4_9791, - 0x1975_b962_f6cb_8e0b, - 0x3bc4_ca99_02c5_2acb, - 0x030d_dbb4_7049_3f16, - ]), - vesta::Base::from_raw([ - 0x3a1c_62ca_8fbf_2525, - 0x8fb8_ab9d_60ea_17b2, - 0x950b_0ab1_8d35_46df, - 0x3130_fbaf_fb5a_a82a, - ]), - vesta::Base::from_raw([ - 0x43a8_7618_0dc3_82e0, - 0x15ce_2ead_2fcd_051e, - 0x4f74_d74b_ac2e_e457, - 0x337f_5447_07c4_30f0, - ]), - ], - [ - vesta::Base::from_raw([ - 0x26de_98a8_736d_1d11, - 0x7d8e_471a_9fb9_5fef, - 0xac9d_91b0_930d_ac75, - 0x3499_7991_9015_394f, - ]), - vesta::Base::from_raw([ - 0xccfc_b618_31d5_c775, - 0x3bf9_3da6_fff3_1d95, - 0x2305_cd7a_921e_c5f1, - 0x027c_c4ef_e3fb_35dd, - ]), - vesta::Base::from_raw([ - 0xc3fa_2629_635d_27de, - 0x67f1_c6b7_3147_64af, - 0x61b7_1a36_9868_2ad2, - 0x037f_9f23_6595_4c5b, - ]), - ], - [ - vesta::Base::from_raw([ - 0x77c5_b024_8483_71ae, - 0x6041_4abe_362d_01c9, - 0x10f1_cc6d_f8b4_bcd7, - 0x1f69_7cac_4d07_feb7, - ]), - vesta::Base::from_raw([ - 0x786a_dd24_4aa0_ef29, - 0x3145_c478_0631_09d6, - 0x26e6_c851_fbd5_72a6, - 0x267a_750f_e5d7_cfbc, - ]), - vesta::Base::from_raw([ - 0x180e_2b4d_3e75_6f65, - 0xaf28_5fa8_2ce4_fae5, - 0x678c_9996_d9a4_72c8, - 0x0c91_feab_4a43_193a, - ]), - ], - [ - vesta::Base::from_raw([ - 0x79c4_7c57_3ac4_10f7, - 0x7e3b_83af_4a4b_a3ba, - 0x2186_c303_8ea0_5e69, - 0x1745_569a_0a3e_3014, - ]), - vesta::Base::from_raw([ - 0x1e03_8852_2696_191f, - 0xfdff_66c6_f3b5_ffe1, - 0xeca5_1207_78a5_6711, - 0x2986_3d54_6e7e_7c0d, - ]), - vesta::Base::from_raw([ - 0x2f22_5e63_66bf_e390, - 0xa79a_03df_8339_94c6, - 0xbf06_bae4_9ef8_53f6, - 0x1148_d6ab_2bd0_0192, - ]), - ], - [ - vesta::Base::from_raw([ - 0xf4f6_331a_8b26_5d15, - 0xf745_f45d_350d_41d4, - 0xe18b_1499_060d_a366, - 0x02e0_e121_b0f3_dfef, - ]), - vesta::Base::from_raw([ - 0x078a_e6aa_1510_54b7, - 0x6904_0173_6d44_a653, - 0xb89e_f73a_40a2_b274, - 0x0d0a_a46e_76a6_a278, - ]), - vesta::Base::from_raw([ - 0x9a4d_532c_7b6e_0958, - 0x392d_de71_0f1f_06db, - 0xeee5_45f3_fa6d_3d08, - 0x1394_3675_b04a_a986, - ]), - ], - [ - vesta::Base::from_raw([ - 0x961f_c818_dcbb_66b5, - 0xc9f2_b325_7530_dafe, - 0xd97a_11d6_3088_f5d9, - 0x2901_ec61_942d_34aa, - ]), - vesta::Base::from_raw([ - 0xfdf5_44b9_63d1_fdc7, - 0x22ff_a2a2_af9f_a3e3, - 0xf431_d544_34a3_e0cf, - 0x2020_4a21_05d2_2e7e, - ]), - vesta::Base::from_raw([ - 0x1211_b9e2_190d_6852, - 0xa004_abe8_e015_28c4, - 0x5c1e_3e9e_27a5_71c3, - 0x3a8a_6282_9512_1d5c, - ]), - ], -]; - -// n: 255 -// t: 3 -// N: 765 -// Result Algorithm 1: -// [True, 0] -// Result Algorithm 2: -// [True, None] -// Result Algorithm 3: -// [True, None] -// Prime number: 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001 -// MDS matrix: -pub(crate) const MDS: [[vesta::Base; 3]; 3] = [ - [ - vesta::Base::from_raw([ - 0xeb4f_1f74_2963_421f, - 0x5f71_0afc_43dd_c5f6, - 0x9191_3f56_cf21_af2b, - 0x1853_b497_7c6f_a227, - ]), - vesta::Base::from_raw([ - 0x45e5_1db6_ac6f_e4a7, - 0x5a0f_a4df_a500_bcad, - 0x63f4_84c1_0fcf_0586, - 0x3d83_1189_cfbb_c452, - ]), - vesta::Base::from_raw([ - 0xd188_37f9_8347_f137, - 0x3f89_65c7_8083_8a94, - 0x4ba8_8b9e_4017_19c0, - 0x3a0e_3f84_d3c1_77d8, - ]), - ], - [ - vesta::Base::from_raw([ - 0x84fd_7923_337c_f77e, - 0x2896_f8d0_fd5c_9a75, - 0x8e9d_c529_f471_8f83, - 0x35e2_6e39_8450_6279, - ]), - vesta::Base::from_raw([ - 0x3eb9_24f5_6fff_7908, - 0x3641_cecf_3a2a_5a8a, - 0x00cd_7dbe_a799_70ab, - 0x10a8_1663_02cb_753c, - ]), - vesta::Base::from_raw([ - 0xb672_27c1_a141_ae94, - 0x198e_1aee_777e_2521, - 0xf434_92ce_5121_4b00, - 0x314f_762a_506d_321b, - ]), - ], - [ - vesta::Base::from_raw([ - 0xabcb_d614_eaf5_eba1, - 0xa90f_28b0_cb31_76fb, - 0xcb2e_ab86_ef31_d915, - 0x07b8_5627_c832_782a, - ]), - vesta::Base::from_raw([ - 0xc255_efd0_06b5_db1c, - 0xb5d9_85dc_1630_a4b2, - 0x9756_4e1b_5d1a_c72f, - 0x2a2d_e13e_70f2_7e16, - ]), - vesta::Base::from_raw([ - 0xcffd_f529_3334_29fc, - 0x21e3_af7e_f123_32cd, - 0xfff5_40a8_7327_c7ce, - 0x2c60_94d1_c6e1_caba, - ]), - ], -]; - -pub(crate) const MDS_INV: [[vesta::Base; 3]; 3] = [ - [ - vesta::Base::from_raw([ - 0xb204_ddc6_5e58_2044, - 0x47a6_0484_b0a9_9c91, - 0xcaf5_4d78_24c1_200e, - 0x36df_4950_21cf_7828, - ]), - vesta::Base::from_raw([ - 0x6a6b_94ad_aa0d_9c9e, - 0xe2cd_38b9_59d4_61ff, - 0xe43e_c4bf_3e0d_f00c, - 0x034f_beae_4650_c2c7, - ]), - vesta::Base::from_raw([ - 0xa862_7a02_8c1a_f7d6, - 0x841b_ebf1_a15b_746e, - 0x1fd5_6832_d0ab_5570, - 0x20a8_64d6_790f_7c1c, - ]), - ], - [ - vesta::Base::from_raw([ - 0x3470_d5c5_53bc_9d20, - 0x1f95_660f_eb5d_b121, - 0xdd31_97ac_c894_9076, - 0x2d08_703d_48ec_d7dc, - ]), - vesta::Base::from_raw([ - 0x6b5b_42b0_67d8_30f3, - 0x6169_b6fa_721a_470e, - 0xeff3_18a2_8983_158a, - 0x2db1_0ecd_507a_2f27, - ]), - vesta::Base::from_raw([ - 0xfbae_b537_d278_4760, - 0x0068_e709_07e7_089d, - 0x926a_5fc0_cc1e_f726, - 0x0c8a_58c0_6473_cdfa, - ]), - ], - [ - vesta::Base::from_raw([ - 0x3a5a_ca10_7129_6e61, - 0x4ad4_442e_96c9_d5e8, - 0x5432_f0c0_b908_a411, - 0x2a64_2dca_695d_744d, - ]), - vesta::Base::from_raw([ - 0x1bd9_bfcb_be02_5ff1, - 0x24f6_ad43_b703_ad90, - 0xebb7_238d_f00d_17e7, - 0x114e_c796_fb40_3f5f, - ]), - vesta::Base::from_raw([ - 0x67f0_642e_14a9_c3bf, - 0xf6a6_9176_7069_7a97, - 0x0408_110d_c66e_b147, - 0x2825_e067_5968_dbeb, - ]), - ], -]; diff --git a/halo2_gadgets/src/poseidon/primitives/grain.rs b/halo2_gadgets/src/poseidon/primitives/grain.rs deleted file mode 100644 index f3cf94f761..0000000000 --- a/halo2_gadgets/src/poseidon/primitives/grain.rs +++ /dev/null @@ -1,193 +0,0 @@ -//! The Grain LFSR in self-shrinking mode, as used by Poseidon. - -use std::marker::PhantomData; - -use bitvec::prelude::*; -use halo2_proofs::arithmetic::FieldExt; - -const STATE: usize = 80; - -#[derive(Debug, Clone, Copy)] -pub(super) enum FieldType { - /// GF(2^n) - #[allow(dead_code)] - Binary, - /// GF(p) - PrimeOrder, -} - -impl FieldType { - fn tag(&self) -> u8 { - match self { - FieldType::Binary => 0, - FieldType::PrimeOrder => 1, - } - } -} - -#[derive(Debug, Clone, Copy)] -pub(super) enum SboxType { - /// x^alpha - Pow, - /// x^(-1) - #[allow(dead_code)] - Inv, -} - -impl SboxType { - fn tag(&self) -> u8 { - match self { - SboxType::Pow => 0, - SboxType::Inv => 1, - } - } -} - -pub(super) struct Grain { - state: BitArr!(for 80, in u8, Msb0), - next_bit: usize, - _field: PhantomData, -} - -impl Grain { - pub(super) fn new(sbox: SboxType, t: u16, r_f: u16, r_p: u16) -> Self { - // Initialize the LFSR state. - let mut state = bitarr![u8, Msb0; 1; STATE]; - let mut set_bits = |offset: usize, len, value| { - // Poseidon reference impl sets initial state bits in MSB order. - for i in 0..len { - *state.get_mut(offset + len - 1 - i).unwrap() = (value >> i) & 1 != 0; - } - }; - set_bits(0, 2, FieldType::PrimeOrder.tag() as u16); - set_bits(2, 4, sbox.tag() as u16); - set_bits(6, 12, F::NUM_BITS as u16); - set_bits(18, 12, t); - set_bits(30, 10, r_f); - set_bits(40, 10, r_p); - - let mut grain = Grain { - state, - next_bit: STATE, - _field: PhantomData::default(), - }; - - // Discard the first 160 bits. - for _ in 0..20 { - grain.load_next_8_bits(); - grain.next_bit = STATE; - } - - grain - } - - fn load_next_8_bits(&mut self) { - let mut new_bits = 0u8; - for i in 0..8 { - new_bits |= ((self.state[i + 62] - ^ self.state[i + 51] - ^ self.state[i + 38] - ^ self.state[i + 23] - ^ self.state[i + 13] - ^ self.state[i]) as u8) - << i; - } - self.state.rotate_left(8); - self.next_bit -= 8; - for i in 0..8 { - *self.state.get_mut(self.next_bit + i).unwrap() = (new_bits >> i) & 1 != 0; - } - } - - fn get_next_bit(&mut self) -> bool { - if self.next_bit == STATE { - self.load_next_8_bits(); - } - let ret = self.state[self.next_bit]; - self.next_bit += 1; - ret - } - - /// Returns the next field element from this Grain instantiation. - pub(super) fn next_field_element(&mut self) -> F { - // Loop until we get an element in the field. - loop { - let mut bytes = F::Repr::default(); - - // Poseidon reference impl interprets the bits as a repr in MSB order, because - // it's easy to do that in Python. Meanwhile, our field elements all use LSB - // order. There's little motivation to diverge from the reference impl; these - // are all constants, so we aren't introducing big-endianness into the rest of - // the circuit (assuming unkeyed Poseidon, but we probably wouldn't want to - // implement Grain inside a circuit, so we'd use a different round constant - // derivation function there). - let view = bytes.as_mut(); - for (i, bit) in self.take(F::NUM_BITS as usize).enumerate() { - // If we diverged from the reference impl and interpreted the bits in LSB - // order, we would remove this line. - let i = F::NUM_BITS as usize - 1 - i; - - view[i / 8] |= if bit { 1 << (i % 8) } else { 0 }; - } - - if let Some(f) = F::from_repr_vartime(bytes) { - break f; - } - } - } - - /// Returns the next field element from this Grain instantiation, without using - /// rejection sampling. - pub(super) fn next_field_element_without_rejection(&mut self) -> F { - let mut bytes = [0u8; 64]; - - // Poseidon reference impl interprets the bits as a repr in MSB order, because - // it's easy to do that in Python. Additionally, it does not use rejection - // sampling in cases where the constants don't specifically need to be uniformly - // random for security. We do not provide APIs that take a field-element-sized - // array and reduce it modulo the field order, because those are unsafe APIs to - // offer generally (accidentally using them can lead to divergence in consensus - // systems due to not rejecting canonical forms). - // - // Given that we don't want to diverge from the reference implementation, we hack - // around this restriction by serializing the bits into a 64-byte array and then - // calling F::from_bytes_wide. PLEASE DO NOT COPY THIS INTO YOUR OWN CODE! - let view = bytes.as_mut(); - for (i, bit) in self.take(F::NUM_BITS as usize).enumerate() { - // If we diverged from the reference impl and interpreted the bits in LSB - // order, we would remove this line. - let i = F::NUM_BITS as usize - 1 - i; - - view[i / 8] |= if bit { 1 << (i % 8) } else { 0 }; - } - - F::from_bytes_wide(&bytes) - } -} - -impl Iterator for Grain { - type Item = bool; - - fn next(&mut self) -> Option { - // Evaluate bits in pairs: - // - If the first bit is a 1, output the second bit. - // - If the first bit is a 0, discard the second bit. - while !self.get_next_bit() { - self.get_next_bit(); - } - Some(self.get_next_bit()) - } -} - -#[cfg(test)] -mod tests { - use halo2curves::pasta::Fp; - - use super::{Grain, SboxType}; - - #[test] - fn grain() { - let mut grain = Grain::::new(SboxType::Pow, 3, 8, 56); - let _f = grain.next_field_element(); - } -} diff --git a/halo2_gadgets/src/poseidon/primitives/mds.rs b/halo2_gadgets/src/poseidon/primitives/mds.rs deleted file mode 100644 index fb809e3a79..0000000000 --- a/halo2_gadgets/src/poseidon/primitives/mds.rs +++ /dev/null @@ -1,123 +0,0 @@ -use halo2_proofs::arithmetic::FieldExt; - -use super::{grain::Grain, Mds}; - -pub(super) fn generate_mds( - grain: &mut Grain, - mut select: usize, -) -> (Mds, Mds) { - let (xs, ys, mds) = loop { - // Generate two [F; T] arrays of unique field elements. - let (xs, ys) = loop { - let mut vals: Vec<_> = (0..2 * T) - .map(|_| grain.next_field_element_without_rejection()) - .collect(); - - // Check that we have unique field elements. - let mut unique = vals.clone(); - unique.sort_unstable(); - unique.dedup(); - if vals.len() == unique.len() { - let rhs = vals.split_off(T); - break (vals, rhs); - } - }; - - // We need to ensure that the MDS is secure. Instead of checking the MDS against - // the relevant algorithms directly, we witness a fixed number of MDS matrices - // that we need to sample from the given Grain state before obtaining a secure - // matrix. This can be determined out-of-band via the reference implementation in - // Sage. - if select != 0 { - select -= 1; - continue; - } - - // Generate a Cauchy matrix, with elements a_ij in the form: - // a_ij = 1/(x_i + y_j); x_i + y_j != 0 - // - // It would be much easier to use the alternate definition: - // a_ij = 1/(x_i - y_j); x_i - y_j != 0 - // - // These are clearly equivalent on `y <- -y`, but it is easier to work with the - // negative formulation, because ensuring that xs ∪ ys is unique implies that - // x_i - y_j != 0 by construction (whereas the positive case does not hold). It - // also makes computation of the matrix inverse simpler below (the theorem used - // was formulated for the negative definition). - // - // However, the Poseidon paper and reference impl use the positive formulation, - // and we want to rely on the reference impl for MDS security, so we use the same - // formulation. - let mut mds = [[F::zero(); T]; T]; - #[allow(clippy::needless_range_loop)] - for i in 0..T { - for j in 0..T { - let sum = xs[i] + ys[j]; - // We leverage the secure MDS selection counter to also check this. - assert!(!sum.is_zero_vartime()); - mds[i][j] = sum.invert().unwrap(); - } - } - - break (xs, ys, mds); - }; - - // Compute the inverse. All square Cauchy matrices have a non-zero determinant and - // thus are invertible. The inverse for a Cauchy matrix of the form: - // - // a_ij = 1/(x_i - y_j); x_i - y_j != 0 - // - // has elements b_ij given by: - // - // b_ij = (x_j - y_i) A_j(y_i) B_i(x_j) (Schechter 1959, Theorem 1) - // - // where A_i(x) and B_i(x) are the Lagrange polynomials for xs and ys respectively. - // - // We adapt this to the positive Cauchy formulation by negating ys. - let mut mds_inv = [[F::zero(); T]; T]; - let l = |xs: &[F], j, x: F| { - let x_j = xs[j]; - xs.iter().enumerate().fold(F::one(), |acc, (m, x_m)| { - if m == j { - acc - } else { - // We can invert freely; by construction, the elements of xs are distinct. - acc * (x - x_m) * (x_j - x_m).invert().unwrap() - } - }) - }; - let neg_ys: Vec<_> = ys.iter().map(|y| -*y).collect(); - for i in 0..T { - for j in 0..T { - mds_inv[i][j] = (xs[j] - neg_ys[i]) * l(&xs, j, neg_ys[i]) * l(&neg_ys, i, xs[j]); - } - } - - (mds, mds_inv) -} - -#[cfg(test)] -mod tests { - use halo2curves::pasta::Fp; - - use super::{generate_mds, Grain}; - - #[test] - fn poseidon_mds() { - const T: usize = 3; - let mut grain = Grain::new(super::super::grain::SboxType::Pow, T as u16, 8, 56); - let (mds, mds_inv) = generate_mds::(&mut grain, 0); - - // Verify that MDS * MDS^-1 = I. - #[allow(clippy::needless_range_loop)] - for i in 0..T { - for j in 0..T { - let expected = if i == j { Fp::one() } else { Fp::zero() }; - assert_eq!( - (0..T).fold(Fp::zero(), |acc, k| acc + (mds[i][k] * mds_inv[k][j])), - expected - ); - } - } - } -} diff --git a/halo2_gadgets/src/poseidon/primitives/p128pow5t3.rs b/halo2_gadgets/src/poseidon/primitives/p128pow5t3.rs deleted file mode 100644 index 379c399b4e..0000000000 --- a/halo2_gadgets/src/poseidon/primitives/p128pow5t3.rs +++ /dev/null @@ -1,313 +0,0 @@ -use halo2_proofs::arithmetic::Field; -use halo2curves::pasta::{pallas::Base as Fp, vesta::Base as Fq}; - -use super::{Mds, Spec}; - -/// Poseidon-128 using the $x^5$ S-box, with a width of 3 field elements, and the -/// standard number of rounds for 128-bit security "with margin". -/// -/// The standard specification for this set of parameters (on either of the Pasta -/// fields) uses $R_F = 8, R_P = 56$. This is conveniently an even number of -/// partial rounds, making it easier to construct a Halo 2 circuit. -#[derive(Debug)] -pub struct P128Pow5T3; - -impl Spec for P128Pow5T3 { - fn full_rounds() -> usize { - 8 - } - - fn partial_rounds() -> usize { - 56 - } - - fn sbox(val: Fp) -> Fp { - val.pow_vartime(&[5]) - } - - fn secure_mds() -> usize { - unimplemented!() - } - - fn constants() -> (Vec<[Fp; 3]>, Mds, Mds) { - ( - super::fp::ROUND_CONSTANTS[..].to_vec(), - super::fp::MDS, - super::fp::MDS_INV, - ) - } -} - -impl Spec for P128Pow5T3 { - fn full_rounds() -> usize { - 8 - } - - fn partial_rounds() -> usize { - 56 - } - - fn sbox(val: Fq) -> Fq { - val.pow_vartime(&[5]) - } - - fn secure_mds() -> usize { - unimplemented!() - } - - fn constants() -> (Vec<[Fq; 3]>, Mds, Mds) { - ( - super::fq::ROUND_CONSTANTS[..].to_vec(), - super::fq::MDS, - super::fq::MDS_INV, - ) - } -} - -#[cfg(test)] -mod tests { - use ff::PrimeField; - use std::marker::PhantomData; - - use halo2curves::FieldExt; - - use super::{ - super::{fp, fq}, - Fp, Fq, - }; - use crate::poseidon::primitives::{permute, ConstantLength, Hash, Spec}; - - /// The same Poseidon specification as poseidon::P128Pow5T3, but constructed - /// such that its constants will be generated at runtime. - #[derive(Debug)] - pub struct P128Pow5T3Gen(PhantomData); - - impl P128Pow5T3Gen { - pub fn new() -> Self { - P128Pow5T3Gen(PhantomData::default()) - } - } - - impl Spec for P128Pow5T3Gen { - fn full_rounds() -> usize { - 8 - } - - fn partial_rounds() -> usize { - 56 - } - - fn sbox(val: F) -> F { - val.pow_vartime(&[5]) - } - - fn secure_mds() -> usize { - SECURE_MDS - } - } - - #[test] - fn verify_constants() { - fn verify_constants_helper( - expected_round_constants: [[F; 3]; 64], - expected_mds: [[F; 3]; 3], - expected_mds_inv: [[F; 3]; 3], - ) { - let (round_constants, mds, mds_inv) = P128Pow5T3Gen::::constants(); - - for (actual, expected) in round_constants - .iter() - .flatten() - .zip(expected_round_constants.iter().flatten()) - { - assert_eq!(actual, expected); - } - - for (actual, expected) in mds.iter().flatten().zip(expected_mds.iter().flatten()) { - assert_eq!(actual, expected); - } - - for (actual, expected) in mds_inv - .iter() - .flatten() - .zip(expected_mds_inv.iter().flatten()) - { - assert_eq!(actual, expected); - } - } - - verify_constants_helper(fp::ROUND_CONSTANTS, fp::MDS, fp::MDS_INV); - verify_constants_helper(fq::ROUND_CONSTANTS, fq::MDS, fq::MDS_INV); - } - - #[test] - fn test_against_reference() { - { - // , using parameters from - // `generate_parameters_grain.sage 1 0 255 3 8 56 0x40000000000000000000000000000000224698fc094cf91b992d30ed00000001`. - // The test vector is generated by `sage poseidonperm_x5_pallas_3.sage --rust` - - let mut input = [ - Fp::from_raw([ - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - ]), - Fp::from_raw([ - 0x0000_0000_0000_0001, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - ]), - Fp::from_raw([ - 0x0000_0000_0000_0002, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - ]), - ]; - - let expected_output = [ - Fp::from_raw([ - 0xaeb1_bc02_4aec_a456, - 0xf7e6_9a71_d0b6_42a0, - 0x94ef_b364_f966_240f, - 0x2a52_6acd_0b64_b453, - ]), - Fp::from_raw([ - 0x012a_3e96_28e5_b82a, - 0xdcd4_2e7f_bed9_dafe, - 0x76ff_7dae_343d_5512, - 0x13c5_d156_8b4a_a430, - ]), - Fp::from_raw([ - 0x3590_29a1_d34e_9ddd, - 0xf7cf_dfe1_bda4_2c7b, - 0x256f_cd59_7984_561a, - 0x0a49_c868_c697_6544, - ]), - ]; - - permute::, 3, 2>(&mut input, &fp::MDS, &fp::ROUND_CONSTANTS); - assert_eq!(input, expected_output); - } - - { - // , using parameters from - // `generate_parameters_grain.sage 1 0 255 3 8 56 0x40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001`. - // The test vector is generated by `sage poseidonperm_x5_vesta_3.sage --rust` - - let mut input = [ - Fq::from_raw([ - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - ]), - Fq::from_raw([ - 0x0000_0000_0000_0001, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - ]), - Fq::from_raw([ - 0x0000_0000_0000_0002, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - 0x0000_0000_0000_0000, - ]), - ]; - - let expected_output = [ - Fq::from_raw([ - 0x0eb0_8ea8_13be_be59, - 0x4d43_d197_3dd3_36c6, - 0xeddd_74f2_2f8f_2ff7, - 0x315a_1f4c_db94_2f7c, - ]), - Fq::from_raw([ - 0xf9f1_26e6_1ea1_65f1, - 0x413e_e0eb_7bbd_2198, - 0x642a_dee0_dd13_aa48, - 0x3be4_75f2_d764_2bde, - ]), - Fq::from_raw([ - 0x14d5_4237_2a7b_a0d9, - 0x5019_bfd4_e042_3fa0, - 0x117f_db24_20d8_ea60, - 0x25ab_8aec_e953_7168, - ]), - ]; - - permute::, 3, 2>(&mut input, &fq::MDS, &fq::ROUND_CONSTANTS); - assert_eq!(input, expected_output); - } - } - - #[test] - fn permute_test_vectors() { - { - let (round_constants, mds, _) = super::P128Pow5T3::constants(); - - for tv in crate::poseidon::primitives::test_vectors::fp::permute() { - let mut state = [ - Fp::from_repr(tv.initial_state[0]).unwrap(), - Fp::from_repr(tv.initial_state[1]).unwrap(), - Fp::from_repr(tv.initial_state[2]).unwrap(), - ]; - - permute::(&mut state, &mds, &round_constants); - - for (expected, actual) in tv.final_state.iter().zip(state.iter()) { - assert_eq!(&actual.to_repr(), expected); - } - } - } - - { - let (round_constants, mds, _) = super::P128Pow5T3::constants(); - - for tv in crate::poseidon::primitives::test_vectors::fq::permute() { - let mut state = [ - Fq::from_repr(tv.initial_state[0]).unwrap(), - Fq::from_repr(tv.initial_state[1]).unwrap(), - Fq::from_repr(tv.initial_state[2]).unwrap(), - ]; - - permute::(&mut state, &mds, &round_constants); - - for (expected, actual) in tv.final_state.iter().zip(state.iter()) { - assert_eq!(&actual.to_repr(), expected); - } - } - } - } - - #[test] - fn hash_test_vectors() { - for tv in crate::poseidon::primitives::test_vectors::fp::hash() { - let message = [ - Fp::from_repr(tv.input[0]).unwrap(), - Fp::from_repr(tv.input[1]).unwrap(), - ]; - - let result = - Hash::<_, super::P128Pow5T3, ConstantLength<2>, 3, 2>::init().hash(message); - - assert_eq!(result.to_repr(), tv.output); - } - - for tv in crate::poseidon::primitives::test_vectors::fq::hash() { - let message = [ - Fq::from_repr(tv.input[0]).unwrap(), - Fq::from_repr(tv.input[1]).unwrap(), - ]; - - let result = - Hash::<_, super::P128Pow5T3, ConstantLength<2>, 3, 2>::init().hash(message); - - assert_eq!(result.to_repr(), tv.output); - } - } -} diff --git a/halo2_gadgets/src/poseidon/primitives/test_vectors.rs b/halo2_gadgets/src/poseidon/primitives/test_vectors.rs deleted file mode 100644 index 1c345a4853..0000000000 --- a/halo2_gadgets/src/poseidon/primitives/test_vectors.rs +++ /dev/null @@ -1,1261 +0,0 @@ -//! Test vectors for [`OrchardNullifier`]. - -pub(crate) struct PermuteTestVector { - pub(crate) initial_state: [[u8; 32]; 3], - pub(crate) final_state: [[u8; 32]; 3], -} - -pub(crate) struct HashTestVector { - pub(crate) input: [[u8; 32]; 2], - pub(crate) output: [u8; 32], -} - -pub(crate) mod fp { - use super::*; - - pub(crate) fn permute() -> Vec { - use PermuteTestVector as TestVector; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/orchard_poseidon/permute/fp.py - vec![ - TestVector { - initial_state: [ - [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - [ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - [ - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - ], - final_state: [ - [ - 0x56, 0xa4, 0xec, 0x4a, 0x02, 0xbc, 0xb1, 0xae, 0xa0, 0x42, 0xb6, 0xd0, - 0x71, 0x9a, 0xe6, 0xf7, 0x0f, 0x24, 0x66, 0xf9, 0x64, 0xb3, 0xef, 0x94, - 0x53, 0xb4, 0x64, 0x0b, 0xcd, 0x6a, 0x52, 0x2a, - ], - [ - 0x2a, 0xb8, 0xe5, 0x28, 0x96, 0x3e, 0x2a, 0x01, 0xfe, 0xda, 0xd9, 0xbe, - 0x7f, 0x2e, 0xd4, 0xdc, 0x12, 0x55, 0x3d, 0x34, 0xae, 0x7d, 0xff, 0x76, - 0x30, 0xa4, 0x4a, 0x8b, 0x56, 0xd1, 0xc5, 0x13, - ], - [ - 0xdd, 0x9d, 0x4e, 0xd3, 0xa1, 0x29, 0x90, 0x35, 0x7b, 0x2c, 0xa4, 0xbd, - 0xe1, 0xdf, 0xcf, 0xf7, 0x1a, 0x56, 0x84, 0x79, 0x59, 0xcd, 0x6f, 0x25, - 0x44, 0x65, 0x97, 0xc6, 0x68, 0xc8, 0x49, 0x0a, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x5c, 0x7a, 0x8f, 0x73, 0xad, 0xfc, 0x70, 0xfb, 0x3f, 0x13, 0x94, 0x49, - 0xac, 0x6b, 0x57, 0x07, 0x4c, 0x4d, 0x6e, 0x66, 0xb1, 0x64, 0x93, 0x9d, - 0xaf, 0xfa, 0x2e, 0xf6, 0xee, 0x69, 0x21, 0x08, - ], - [ - 0x1a, 0xdd, 0x86, 0xb3, 0xf2, 0xe1, 0xbd, 0xa6, 0x2a, 0x5d, 0x2e, 0x0e, - 0x98, 0x2b, 0x77, 0xe6, 0xb0, 0xef, 0x9c, 0xa3, 0xf2, 0x49, 0x88, 0xc7, - 0xb3, 0x53, 0x42, 0x01, 0xcf, 0xb1, 0xcd, 0x0d, - ], - [ - 0xbd, 0x69, 0xb8, 0x25, 0x32, 0xb6, 0x94, 0x0f, 0xf2, 0x59, 0x0f, 0x67, - 0x9b, 0xa9, 0xc7, 0x27, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, - 0xa5, 0xe2, 0x9d, 0x4e, 0x30, 0xa7, 0x35, 0x14, - ], - ], - final_state: [ - [ - 0xd0, 0x6e, 0x2f, 0x83, 0x38, 0x92, 0x8a, 0x7e, 0xe7, 0x38, 0x0c, 0x77, - 0x92, 0x80, 0x87, 0xcd, 0xa2, 0xfd, 0x29, 0x61, 0xa1, 0x52, 0x69, 0x03, - 0x7a, 0x22, 0xd6, 0xd1, 0x20, 0xae, 0xdd, 0x21, - ], - [ - 0x29, 0x55, 0xa4, 0x5f, 0x41, 0x6f, 0x10, 0xd6, 0xbc, 0x79, 0xac, 0x94, - 0xd0, 0xc0, 0x69, 0xc9, 0x49, 0xe5, 0xf4, 0xbd, 0x09, 0x48, 0x1e, 0x1f, - 0x36, 0x8c, 0xb9, 0xb8, 0xee, 0x51, 0x14, 0x0d, - ], - [ - 0x0d, 0x83, 0x76, 0xbb, 0xe9, 0xd6, 0x5d, 0x2b, 0x1e, 0x13, 0x6f, 0xb7, - 0xd9, 0x82, 0xab, 0x87, 0xc5, 0x1c, 0x40, 0x30, 0x44, 0xbe, 0x5c, 0x79, - 0x9d, 0x56, 0xbb, 0x68, 0xac, 0xf9, 0x5b, 0x10, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0xbc, 0x50, 0x98, 0x42, 0x55, 0xd6, 0xaf, 0xbe, 0x9e, 0xf9, 0x28, 0x48, - 0xed, 0x5a, 0xc0, 0x08, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, 0xbc, 0xb6, - 0x4b, 0x69, 0x68, 0x91, 0x2a, 0x63, 0x81, 0x0e, - ], - [ - 0x3d, 0xc1, 0x66, 0xd5, 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, - 0xb5, 0xfd, 0x93, 0x13, 0xe8, 0xc7, 0x20, 0x3d, 0x99, 0x6a, 0xf7, 0xd4, - 0x77, 0x08, 0x37, 0x56, 0xd5, 0x9a, 0xf8, 0x0d, - ], - [ - 0x05, 0xa7, 0x45, 0xf4, 0x5d, 0x7f, 0xf6, 0xdb, 0x10, 0xbc, 0x67, 0xfd, - 0xf0, 0xf0, 0x3e, 0xbf, 0x81, 0x30, 0xab, 0x33, 0x36, 0x26, 0x97, 0xb0, - 0xe4, 0xe4, 0xc7, 0x63, 0xcc, 0xb8, 0xf6, 0x36, - ], - ], - final_state: [ - [ - 0x0b, 0x77, 0xec, 0x53, 0x07, 0x14, 0x5a, 0x0c, 0x05, 0x2d, 0xc7, 0xa9, - 0xd6, 0xf9, 0x6a, 0xc3, 0x41, 0xae, 0x72, 0x64, 0x08, 0x32, 0xd5, 0x8e, - 0x51, 0xeb, 0x92, 0xa4, 0x17, 0x80, 0x17, 0x12, - ], - [ - 0x3b, 0x52, 0x3f, 0x44, 0xf0, 0x0e, 0x46, 0x3f, 0x8b, 0x0f, 0xd7, 0xd4, - 0xfc, 0x0e, 0x28, 0x0c, 0xdb, 0xde, 0xb9, 0x27, 0xf1, 0x81, 0x68, 0x07, - 0x7b, 0xb3, 0x62, 0xf2, 0x67, 0x5a, 0x2e, 0x18, - ], - [ - 0x95, 0x7a, 0x97, 0x06, 0xff, 0xcc, 0x35, 0x15, 0x64, 0xae, 0x80, 0x2a, - 0x99, 0x11, 0x31, 0x4c, 0x05, 0xe2, 0x3e, 0x22, 0xaf, 0xcf, 0x83, 0x40, - 0x59, 0xdf, 0x80, 0xfa, 0xc1, 0x05, 0x76, 0x26, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, 0xfa, 0x3d, 0x5a, - 0x57, 0xef, 0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, 0xfb, - 0x1a, 0x38, 0xe0, 0x1d, 0x94, 0x90, 0x3d, 0x3c, - ], - [ - 0x3d, 0x0a, 0xd3, 0x36, 0x1f, 0xec, 0x09, 0x77, 0x90, 0xd9, 0xbe, 0x0e, - 0x42, 0x98, 0x8d, 0x7d, 0x25, 0xc9, 0xa1, 0x38, 0xf4, 0x9b, 0x1a, 0x53, - 0x7e, 0xdc, 0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x11, - ], - [ - 0xa4, 0xaf, 0x9d, 0xb6, 0xd2, 0x7b, 0x50, 0x72, 0x83, 0x5f, 0x0c, 0x3e, - 0x88, 0x39, 0x5e, 0xd7, 0xa4, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, - 0xb9, 0xda, 0x94, 0x8d, 0x32, 0x0d, 0xad, 0x16, - ], - ], - final_state: [ - [ - 0x67, 0x80, 0x08, 0x3f, 0x7f, 0x82, 0xcb, 0x42, 0x54, 0xe7, 0xb6, 0x6f, - 0x4b, 0x83, 0x84, 0x6a, 0xc9, 0x77, 0x3f, 0xb9, 0xc3, 0x9c, 0x6e, 0xc9, - 0x81, 0x8b, 0x06, 0x22, 0x23, 0x09, 0x55, 0x2a, - ], - [ - 0xa5, 0xf9, 0xa5, 0x7e, 0x2c, 0x40, 0xb1, 0x58, 0xd8, 0x16, 0x53, 0x43, - 0xe6, 0x02, 0x65, 0x2c, 0x3e, 0xfc, 0x0b, 0x64, 0xdd, 0xca, 0xee, 0xe5, - 0xce, 0x3d, 0x95, 0x1f, 0xd5, 0x9f, 0x50, 0x08, - ], - [ - 0xdc, 0xa4, 0x64, 0x36, 0x12, 0x7c, 0x47, 0x7e, 0x83, 0x95, 0x0f, 0xa0, - 0x7c, 0xc6, 0x8a, 0x56, 0x6e, 0x54, 0x18, 0x55, 0xad, 0xc2, 0x68, 0x52, - 0x97, 0x87, 0x35, 0x24, 0x88, 0x92, 0x1e, 0x3b, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x4d, 0x54, 0x31, 0xe6, 0x43, 0x7d, 0x0b, 0x5b, 0xed, 0xbb, 0xcd, 0xaf, - 0x34, 0x5b, 0x86, 0xc4, 0x12, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, - 0x42, 0x76, 0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x11, - ], - [ - 0xdd, 0x0c, 0x7a, 0x1d, 0x81, 0x1c, 0x7d, 0x9c, 0xd4, 0x6d, 0x37, 0x7b, - 0x3f, 0xde, 0xab, 0x3f, 0xb6, 0x79, 0xf3, 0xdc, 0x60, 0x1d, 0x00, 0x82, - 0x85, 0xed, 0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0x3c, - ], - [ - 0x19, 0xe4, 0xaa, 0xc0, 0x35, 0x90, 0x17, 0xec, 0x85, 0xa1, 0x83, 0xd2, - 0x20, 0x53, 0xdb, 0x33, 0xf7, 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, - 0x37, 0x83, 0x65, 0xc8, 0xf7, 0x39, 0x3c, 0x14, - ], - ], - final_state: [ - [ - 0x89, 0x99, 0x8e, 0x5e, 0x0f, 0xa1, 0x95, 0x2a, 0x40, 0xb8, 0xb5, 0x2b, - 0x62, 0xd9, 0x45, 0x70, 0xa4, 0x9a, 0x7d, 0x91, 0xdd, 0x22, 0x6d, 0x69, - 0x2b, 0xc9, 0xb1, 0xa6, 0x13, 0xc9, 0x08, 0x30, - ], - [ - 0xd0, 0xee, 0x44, 0xd9, 0xa9, 0x0d, 0x90, 0x79, 0xef, 0xfb, 0x24, 0x86, - 0xd3, 0xd8, 0x4d, 0x1a, 0x18, 0x4e, 0xdf, 0x14, 0x97, 0x0b, 0xac, 0x36, - 0xc7, 0x48, 0x04, 0xc7, 0xff, 0xbe, 0xe5, 0x0b, - ], - [ - 0x04, 0x81, 0x45, 0xa6, 0x61, 0xce, 0x78, 0x7c, 0x7e, 0x12, 0x2a, 0xc6, - 0x44, 0x7e, 0x9b, 0xa3, 0x93, 0xd3, 0x67, 0xac, 0x05, 0x4f, 0xaa, 0xc5, - 0xb7, 0xb5, 0xf7, 0x19, 0x2b, 0x2f, 0xde, 0x21, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, - 0x79, 0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, - 0x32, 0xb4, 0xf4, 0x73, 0xf4, 0x68, 0xa0, 0x08, - ], - [ - 0xe6, 0x23, 0x89, 0xfc, 0x16, 0x57, 0xe0, 0xde, 0xf0, 0xb6, 0x32, 0xc6, - 0xae, 0x25, 0xf9, 0xf7, 0x83, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, 0x15, 0x3d, - 0x88, 0x2d, 0x2b, 0x21, 0x03, 0x59, 0x65, 0x15, - ], - [ - 0xeb, 0x94, 0x94, 0xc6, 0xd2, 0x27, 0xe2, 0x16, 0x3b, 0x46, 0x99, 0xd9, - 0x91, 0xf4, 0x33, 0xbf, 0x94, 0x86, 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, - 0x73, 0x1e, 0x98, 0x5d, 0x99, 0x58, 0x9c, 0x0b, - ], - ], - final_state: [ - [ - 0xce, 0x2d, 0x1f, 0x8d, 0x67, 0x7f, 0xfb, 0xfd, 0x73, 0xb2, 0x35, 0xe8, - 0xc6, 0x87, 0xfb, 0x42, 0x18, 0x7f, 0x78, 0x81, 0xc3, 0xce, 0x9c, 0x79, - 0x4f, 0x2b, 0xd4, 0x61, 0x40, 0xf7, 0xcc, 0x2a, - ], - [ - 0xaf, 0x82, 0x92, 0x39, 0xb6, 0xd5, 0x5d, 0x5f, 0x43, 0xec, 0x6f, 0x32, - 0xb8, 0x4a, 0x2a, 0x01, 0x1e, 0x64, 0xc5, 0x74, 0x73, 0x9f, 0x87, 0xcb, - 0x47, 0xdc, 0x70, 0x23, 0x83, 0xfa, 0x5a, 0x34, - ], - [ - 0x03, 0xd1, 0x08, 0x5b, 0x21, 0x4c, 0x69, 0xb8, 0xbf, 0xe8, 0x91, 0x02, - 0xbd, 0x61, 0x7e, 0xce, 0x0c, 0x54, 0x00, 0x17, 0x96, 0x40, 0x41, 0x05, - 0xc5, 0x33, 0x30, 0xd2, 0x49, 0x58, 0x1d, 0x0f, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0xb7, 0x38, 0xe8, 0xaa, 0x0a, 0x15, 0x26, 0xa5, 0xbd, 0xef, 0x61, 0x31, - 0x20, 0x37, 0x2e, 0x83, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, - 0xeb, 0xbc, 0x86, 0x2d, 0xed, 0x42, 0x43, 0x1e, - ], - [ - 0x91, 0x47, 0x69, 0x30, 0xe3, 0x38, 0x5c, 0xd3, 0xe3, 0x37, 0x9e, 0x38, - 0x53, 0xd9, 0x34, 0x67, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, - 0x6d, 0x75, 0xa4, 0xa6, 0xf2, 0x65, 0x72, 0x10, - ], - [ - 0x4b, 0x19, 0x22, 0x32, 0xec, 0xb9, 0xf0, 0xc0, 0x24, 0x11, 0xe5, 0x25, - 0x96, 0xbc, 0x5e, 0x90, 0x45, 0x7e, 0x74, 0x59, 0x39, 0xff, 0xed, 0xbd, - 0x12, 0x86, 0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11, - ], - ], - final_state: [ - [ - 0x5f, 0xcc, 0xd8, 0x7d, 0x2f, 0x66, 0x7b, 0x9e, 0xe3, 0x88, 0xf3, 0x4c, - 0x1c, 0x71, 0x06, 0x87, 0x12, 0x7b, 0xff, 0x5b, 0x02, 0x21, 0xfd, 0x8a, - 0x52, 0x94, 0x88, 0x66, 0x91, 0x57, 0x94, 0x2b, - ], - [ - 0x89, 0x62, 0xb5, 0x80, 0x30, 0xaa, 0x63, 0x52, 0xd9, 0x90, 0xf3, 0xb9, - 0x00, 0x1c, 0xcb, 0xe8, 0x8a, 0x56, 0x27, 0x58, 0x1b, 0xbf, 0xb9, 0x01, - 0xac, 0x4a, 0x6a, 0xed, 0xfa, 0xe5, 0xc6, 0x34, - ], - [ - 0x7c, 0x0b, 0x76, 0x59, 0xf2, 0x4c, 0x98, 0xaf, 0x31, 0x0e, 0x3e, 0x8d, - 0x82, 0xb5, 0xf3, 0x99, 0x43, 0x3c, 0xdd, 0xa5, 0x8f, 0x48, 0xd9, 0xef, - 0x8d, 0xd0, 0xca, 0x86, 0x42, 0x72, 0xda, 0x3f, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x7b, 0x41, 0x7a, 0xdb, 0x63, 0xb3, 0x71, 0x22, 0xa5, 0xbf, 0x62, 0xd2, - 0x6f, 0x1e, 0x7f, 0x26, 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, - 0x82, 0x85, 0x7d, 0xee, 0xcc, 0x40, 0xa9, 0x0d, - ], - [ - 0x5e, 0x29, 0x35, 0x39, 0x71, 0xb3, 0x49, 0x94, 0xb6, 0x21, 0xb0, 0xb2, - 0x61, 0xae, 0xb3, 0x78, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, - 0xb9, 0x27, 0xb7, 0xfa, 0xe2, 0xdb, 0x58, 0x31, - ], - [ - 0x05, 0x41, 0x5d, 0x46, 0x42, 0x78, 0x9d, 0x38, 0xf5, 0x0b, 0x8d, 0xbc, - 0xc1, 0x29, 0xca, 0xb3, 0xd1, 0x7d, 0x19, 0xf3, 0x35, 0x5b, 0xcf, 0x73, - 0xce, 0xcb, 0x8c, 0xb8, 0xa5, 0xda, 0x01, 0x30, - ], - ], - final_state: [ - [ - 0x9e, 0xe1, 0xad, 0xdc, 0x6f, 0x64, 0xda, 0xb6, 0xac, 0xdc, 0xea, 0xec, - 0xc1, 0xfb, 0xbc, 0x8a, 0x32, 0x45, 0x8e, 0x49, 0xc1, 0x9e, 0x79, 0x85, - 0x56, 0xc6, 0x4b, 0x59, 0x8b, 0xa6, 0xff, 0x14, - ], - [ - 0x42, 0xcc, 0x10, 0x36, 0x4f, 0xd6, 0x59, 0xc3, 0xcc, 0x77, 0x25, 0x84, - 0xdb, 0x91, 0xc4, 0x9a, 0x38, 0x67, 0x2b, 0x69, 0x24, 0x93, 0xb9, 0x07, - 0x5f, 0x16, 0x53, 0xca, 0x1f, 0xae, 0x1c, 0x33, - ], - [ - 0xff, 0x41, 0xf3, 0x51, 0x80, 0x14, 0x56, 0xc4, 0x96, 0x0b, 0x39, 0x3a, - 0xff, 0xa8, 0x62, 0x13, 0xa7, 0xea, 0xc0, 0x6c, 0x66, 0x21, 0x3b, 0x45, - 0xc3, 0xb5, 0x0e, 0xc6, 0x48, 0xd6, 0x7d, 0x0d, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x71, 0x52, 0xf1, 0x39, 0x36, 0xa2, 0x70, 0x57, 0x26, 0x70, 0xdc, 0x82, - 0xd3, 0x90, 0x26, 0xc6, 0xcb, 0x4c, 0xd4, 0xb0, 0xf7, 0xf5, 0xaa, 0x2a, - 0x4f, 0x5a, 0x53, 0x41, 0xec, 0x5d, 0xd7, 0x15, - ], - [ - 0x40, 0x6f, 0x2f, 0xdd, 0x2a, 0xfa, 0x73, 0x3f, 0x5f, 0x64, 0x1c, 0x8c, - 0x21, 0x86, 0x2a, 0x1b, 0xaf, 0xce, 0x26, 0x09, 0xd9, 0xee, 0xcf, 0xa1, - 0x58, 0xcf, 0xb5, 0xcd, 0x79, 0xf8, 0x80, 0x08, - ], - [ - 0xe2, 0x15, 0xdc, 0x7d, 0x96, 0x57, 0xba, 0xd3, 0xfb, 0x88, 0xb0, 0x1e, - 0x99, 0x38, 0x44, 0x54, 0x36, 0x24, 0xc2, 0x5f, 0xa9, 0x59, 0xcc, 0x97, - 0x48, 0x9c, 0xe7, 0x57, 0x45, 0x82, 0x4b, 0x37, - ], - ], - final_state: [ - [ - 0x63, 0x09, 0x15, 0xd7, 0xd8, 0x25, 0xeb, 0x74, 0x37, 0xb0, 0xe4, 0x6e, - 0x37, 0x28, 0x6a, 0x88, 0xb3, 0x89, 0xdc, 0x69, 0x85, 0x93, 0x07, 0x11, - 0x6d, 0x34, 0x7b, 0x98, 0xca, 0x14, 0x5c, 0x31, - ], - [ - 0xaa, 0x58, 0x1b, 0xae, 0xe9, 0x4f, 0xb5, 0x46, 0xa7, 0x61, 0xf1, 0x7a, - 0x5d, 0x6e, 0xaa, 0x70, 0x29, 0x52, 0x78, 0x42, 0xf3, 0x1c, 0x39, 0x87, - 0xb8, 0x68, 0xed, 0x7d, 0xaf, 0xfd, 0xb5, 0x34, - ], - [ - 0x7d, 0xc1, 0x17, 0xb3, 0x39, 0x1a, 0xab, 0x85, 0xde, 0x9f, 0x42, 0x4d, - 0xb6, 0x65, 0x1e, 0x00, 0x45, 0xab, 0x79, 0x98, 0xf2, 0x8e, 0x54, 0x10, - 0x15, 0x35, 0x90, 0x61, 0x99, 0xce, 0x1f, 0x1a, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x86, 0x8c, 0x53, 0x23, 0x9c, 0xfb, 0xdf, 0x73, 0xca, 0xec, 0x65, 0x60, - 0x40, 0x37, 0x31, 0x4f, 0xaa, 0xce, 0xb5, 0x62, 0x18, 0xc6, 0xbd, 0x30, - 0xf8, 0x37, 0x4a, 0xc1, 0x33, 0x86, 0x79, 0x3f, - ], - [ - 0x21, 0xa9, 0xfb, 0x80, 0xad, 0x03, 0xbc, 0x0c, 0xda, 0x4a, 0x44, 0x94, - 0x6c, 0x00, 0xe1, 0xb1, 0xa1, 0xdf, 0x0e, 0x5b, 0x87, 0xb5, 0xbe, 0xce, - 0x47, 0x7a, 0x70, 0x96, 0x49, 0xe9, 0x50, 0x06, - ], - [ - 0x04, 0x91, 0x39, 0x48, 0x25, 0x64, 0xf1, 0x85, 0xc7, 0x90, 0x0e, 0x83, - 0xc7, 0x38, 0x07, 0x0a, 0xf6, 0x55, 0x6d, 0xf6, 0xed, 0x4b, 0x4d, 0xdd, - 0x3d, 0x9a, 0x69, 0xf5, 0x33, 0x57, 0xd7, 0x36, - ], - ], - final_state: [ - [ - 0x6a, 0x5a, 0x19, 0x19, 0xa4, 0x49, 0xa5, 0xe0, 0x29, 0x71, 0x1f, 0x48, - 0x8a, 0xdb, 0xd6, 0xb0, 0x3e, 0x5c, 0x92, 0x7b, 0x6f, 0x9d, 0x9d, 0x35, - 0xc5, 0xb3, 0xcc, 0xeb, 0x76, 0x60, 0x52, 0x03, - ], - [ - 0x80, 0x47, 0x5b, 0x46, 0x89, 0x59, 0x61, 0x47, 0xab, 0x2a, 0xdf, 0x01, - 0x73, 0xdb, 0x28, 0x9b, 0x3a, 0x26, 0xa1, 0x04, 0x84, 0x21, 0x73, 0xe8, - 0x8b, 0xdb, 0xfe, 0xc0, 0x4a, 0x28, 0x67, 0x1b, - ], - [ - 0x1e, 0xf3, 0xc8, 0xd0, 0xf5, 0x44, 0x44, 0xf5, 0x55, 0xb1, 0x5f, 0x7b, - 0xc9, 0xfa, 0x4f, 0xfa, 0x0f, 0x56, 0x7c, 0x0f, 0x19, 0xac, 0x7d, 0x0f, - 0xf9, 0x44, 0xfd, 0x36, 0x42, 0x6e, 0x32, 0x3a, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x7d, 0x4f, 0x5c, 0xcb, 0x01, 0x64, 0x3c, 0x31, 0xdb, 0x84, 0x5e, 0xec, - 0xd5, 0xd6, 0x3d, 0xc1, 0x6a, 0x95, 0xe3, 0x02, 0x5b, 0x97, 0x92, 0xff, - 0xf7, 0xf2, 0x44, 0xfc, 0x71, 0x62, 0x69, 0x39, - ], - [ - 0x26, 0xd6, 0x2e, 0x95, 0x96, 0xfa, 0x82, 0x5c, 0x6b, 0xf2, 0x1a, 0xff, - 0x9e, 0x68, 0x62, 0x5a, 0x19, 0x24, 0x40, 0xea, 0x06, 0x82, 0x81, 0x23, - 0xd9, 0x78, 0x84, 0x80, 0x6f, 0x15, 0xfa, 0x08, - ], - [ - 0xd9, 0x52, 0x75, 0x4a, 0x23, 0x64, 0xb6, 0x66, 0xff, 0xc3, 0x0f, 0xdb, - 0x01, 0x47, 0x86, 0xda, 0x3a, 0x61, 0x28, 0xae, 0xf7, 0x84, 0xa6, 0x46, - 0x10, 0xa8, 0x9d, 0x1a, 0x70, 0x99, 0x21, 0x2d, - ], - ], - final_state: [ - [ - 0x1b, 0x4a, 0xc9, 0xbe, 0xf5, 0x6b, 0xdb, 0x6f, 0xb4, 0x2d, 0x3e, 0x3c, - 0xd3, 0xa2, 0xac, 0x70, 0xa4, 0xc4, 0x0c, 0x42, 0x5b, 0x0b, 0xd6, 0x67, - 0x9c, 0xa5, 0x7b, 0x30, 0x7e, 0xf1, 0xd4, 0x2f, - ], - [ - 0x1a, 0x2e, 0xf4, 0x11, 0x94, 0xaa, 0xa2, 0x34, 0x32, 0xe0, 0x86, 0xed, - 0x8a, 0xdb, 0xd1, 0xde, 0xec, 0x3c, 0x7c, 0xb3, 0x96, 0xde, 0x35, 0xba, - 0xe9, 0x5a, 0xaf, 0x5a, 0x08, 0xa0, 0xec, 0x36, - ], - [ - 0x68, 0xeb, 0x80, 0xc7, 0x3e, 0x2c, 0xcb, 0xde, 0xe1, 0xba, 0x71, 0x24, - 0x77, 0x61, 0xd5, 0xb5, 0xec, 0xc6, 0x20, 0xe6, 0xe4, 0x8e, 0x00, 0x3b, - 0x02, 0x3d, 0x9f, 0x55, 0x61, 0x66, 0x2f, 0x20, - ], - ], - }, - ] - } - - pub(crate) fn hash() -> Vec { - use HashTestVector as TestVector; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/orchard_poseidon/hash/fp.py - vec![ - TestVector { - input: [ - [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - [ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - ], - output: [ - 0x83, 0x58, 0xd7, 0x11, 0xa0, 0x32, 0x9d, 0x38, 0xbe, 0xcd, 0x54, 0xfb, 0xa7, - 0xc2, 0x83, 0xed, 0x3e, 0x08, 0x9a, 0x39, 0xc9, 0x1b, 0x6a, 0x9d, 0x10, 0xef, - 0xb0, 0x2b, 0xc3, 0xf1, 0x2f, 0x06, - ], - }, - TestVector { - input: [ - [ - 0x5c, 0x7a, 0x8f, 0x73, 0xad, 0xfc, 0x70, 0xfb, 0x3f, 0x13, 0x94, 0x49, - 0xac, 0x6b, 0x57, 0x07, 0x4c, 0x4d, 0x6e, 0x66, 0xb1, 0x64, 0x93, 0x9d, - 0xaf, 0xfa, 0x2e, 0xf6, 0xee, 0x69, 0x21, 0x08, - ], - [ - 0x1a, 0xdd, 0x86, 0xb3, 0xf2, 0xe1, 0xbd, 0xa6, 0x2a, 0x5d, 0x2e, 0x0e, - 0x98, 0x2b, 0x77, 0xe6, 0xb0, 0xef, 0x9c, 0xa3, 0xf2, 0x49, 0x88, 0xc7, - 0xb3, 0x53, 0x42, 0x01, 0xcf, 0xb1, 0xcd, 0x0d, - ], - ], - output: [ - 0xdb, 0x26, 0x75, 0xff, 0x3e, 0xf8, 0xfe, 0x30, 0xc4, 0xd5, 0xde, 0x61, 0xca, - 0xc0, 0x2a, 0x8e, 0xf1, 0xa0, 0x85, 0x23, 0xbe, 0x92, 0x39, 0x4b, 0x79, 0xd2, - 0x67, 0x26, 0x30, 0x3b, 0xe6, 0x03, - ], - }, - TestVector { - input: [ - [ - 0xbd, 0x69, 0xb8, 0x25, 0x32, 0xb6, 0x94, 0x0f, 0xf2, 0x59, 0x0f, 0x67, - 0x9b, 0xa9, 0xc7, 0x27, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, - 0xa5, 0xe2, 0x9d, 0x4e, 0x30, 0xa7, 0x35, 0x14, - ], - [ - 0xbc, 0x50, 0x98, 0x42, 0x55, 0xd6, 0xaf, 0xbe, 0x9e, 0xf9, 0x28, 0x48, - 0xed, 0x5a, 0xc0, 0x08, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, 0xbc, 0xb6, - 0x4b, 0x69, 0x68, 0x91, 0x2a, 0x63, 0x81, 0x0e, - ], - ], - output: [ - 0xf5, 0x12, 0x1d, 0x1e, 0x1d, 0x5c, 0xfe, 0x8d, 0xa8, 0x96, 0xac, 0x0f, 0x9c, - 0x18, 0x3d, 0x76, 0x00, 0x31, 0xf6, 0xef, 0x8c, 0x7a, 0x41, 0xe6, 0x5e, 0xb0, - 0x07, 0xcd, 0xdc, 0x1d, 0x14, 0x3d, - ], - }, - TestVector { - input: [ - [ - 0x3d, 0xc1, 0x66, 0xd5, 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, - 0xb5, 0xfd, 0x93, 0x13, 0xe8, 0xc7, 0x20, 0x3d, 0x99, 0x6a, 0xf7, 0xd4, - 0x77, 0x08, 0x37, 0x56, 0xd5, 0x9a, 0xf8, 0x0d, - ], - [ - 0x05, 0xa7, 0x45, 0xf4, 0x5d, 0x7f, 0xf6, 0xdb, 0x10, 0xbc, 0x67, 0xfd, - 0xf0, 0xf0, 0x3e, 0xbf, 0x81, 0x30, 0xab, 0x33, 0x36, 0x26, 0x97, 0xb0, - 0xe4, 0xe4, 0xc7, 0x63, 0xcc, 0xb8, 0xf6, 0x36, - ], - ], - output: [ - 0xa4, 0x16, 0xa5, 0xe7, 0x13, 0x51, 0x36, 0xa0, 0x50, 0x56, 0x90, 0x00, 0x58, - 0xfa, 0x50, 0xbf, 0x18, 0x6a, 0xd7, 0x33, 0x90, 0xac, 0xe6, 0x32, 0x3d, 0x8d, - 0x81, 0xaa, 0x8a, 0xdb, 0xd4, 0x11, - ], - }, - TestVector { - input: [ - [ - 0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, 0xfa, 0x3d, 0x5a, - 0x57, 0xef, 0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, 0xfb, - 0x1a, 0x38, 0xe0, 0x1d, 0x94, 0x90, 0x3d, 0x3c, - ], - [ - 0x3d, 0x0a, 0xd3, 0x36, 0x1f, 0xec, 0x09, 0x77, 0x90, 0xd9, 0xbe, 0x0e, - 0x42, 0x98, 0x8d, 0x7d, 0x25, 0xc9, 0xa1, 0x38, 0xf4, 0x9b, 0x1a, 0x53, - 0x7e, 0xdc, 0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x11, - ], - ], - output: [ - 0x1a, 0xba, 0xf3, 0x06, 0xfe, 0xd0, 0x5f, 0xa8, 0x92, 0x84, 0x8c, 0x49, 0xf6, - 0xba, 0x10, 0x41, 0x63, 0x43, 0x3f, 0x3f, 0x63, 0x31, 0x08, 0xa1, 0x3b, 0xc1, - 0x5b, 0x2a, 0x1d, 0x55, 0xd4, 0x0c, - ], - }, - TestVector { - input: [ - [ - 0xa4, 0xaf, 0x9d, 0xb6, 0xd2, 0x7b, 0x50, 0x72, 0x83, 0x5f, 0x0c, 0x3e, - 0x88, 0x39, 0x5e, 0xd7, 0xa4, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, - 0xb9, 0xda, 0x94, 0x8d, 0x32, 0x0d, 0xad, 0x16, - ], - [ - 0x4d, 0x54, 0x31, 0xe6, 0x43, 0x7d, 0x0b, 0x5b, 0xed, 0xbb, 0xcd, 0xaf, - 0x34, 0x5b, 0x86, 0xc4, 0x12, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, - 0x42, 0x76, 0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x11, - ], - ], - output: [ - 0x04, 0xa1, 0x8a, 0xeb, 0x59, 0x3f, 0x79, 0x0b, 0x76, 0xa3, 0x99, 0xb7, 0xc1, - 0x52, 0x8a, 0xcd, 0xed, 0xe9, 0x3b, 0x3b, 0x2c, 0x49, 0x6b, 0xd7, 0x1b, 0xd5, - 0x87, 0xcb, 0xd7, 0xcf, 0xdf, 0x35, - ], - }, - TestVector { - input: [ - [ - 0xdd, 0x0c, 0x7a, 0x1d, 0x81, 0x1c, 0x7d, 0x9c, 0xd4, 0x6d, 0x37, 0x7b, - 0x3f, 0xde, 0xab, 0x3f, 0xb6, 0x79, 0xf3, 0xdc, 0x60, 0x1d, 0x00, 0x82, - 0x85, 0xed, 0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0x3c, - ], - [ - 0x19, 0xe4, 0xaa, 0xc0, 0x35, 0x90, 0x17, 0xec, 0x85, 0xa1, 0x83, 0xd2, - 0x20, 0x53, 0xdb, 0x33, 0xf7, 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, - 0x37, 0x83, 0x65, 0xc8, 0xf7, 0x39, 0x3c, 0x14, - ], - ], - output: [ - 0x11, 0x03, 0xcc, 0xdc, 0x00, 0xd0, 0xf3, 0x5f, 0x65, 0x83, 0x14, 0x11, 0x6b, - 0xc2, 0xbc, 0xd9, 0x43, 0x74, 0xa9, 0x1f, 0xf9, 0x87, 0x7e, 0x70, 0x66, 0x33, - 0x29, 0x04, 0x2b, 0xd2, 0xf6, 0x1f, - ], - }, - TestVector { - input: [ - [ - 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, - 0x79, 0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, - 0x32, 0xb4, 0xf4, 0x73, 0xf4, 0x68, 0xa0, 0x08, - ], - [ - 0xe6, 0x23, 0x89, 0xfc, 0x16, 0x57, 0xe0, 0xde, 0xf0, 0xb6, 0x32, 0xc6, - 0xae, 0x25, 0xf9, 0xf7, 0x83, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, 0x15, 0x3d, - 0x88, 0x2d, 0x2b, 0x21, 0x03, 0x59, 0x65, 0x15, - ], - ], - output: [ - 0xf8, 0xf8, 0xc6, 0x5f, 0x43, 0x7c, 0x45, 0xbe, 0xac, 0x11, 0xeb, 0x7d, 0x9e, - 0x47, 0x58, 0x6d, 0x87, 0x9a, 0xfd, 0x6f, 0x93, 0x04, 0x35, 0xbe, 0x0c, 0x01, - 0xd1, 0x9c, 0x89, 0x5b, 0x8d, 0x10, - ], - }, - TestVector { - input: [ - [ - 0xeb, 0x94, 0x94, 0xc6, 0xd2, 0x27, 0xe2, 0x16, 0x3b, 0x46, 0x99, 0xd9, - 0x91, 0xf4, 0x33, 0xbf, 0x94, 0x86, 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, - 0x73, 0x1e, 0x98, 0x5d, 0x99, 0x58, 0x9c, 0x0b, - ], - [ - 0xb7, 0x38, 0xe8, 0xaa, 0x0a, 0x15, 0x26, 0xa5, 0xbd, 0xef, 0x61, 0x31, - 0x20, 0x37, 0x2e, 0x83, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, - 0xeb, 0xbc, 0x86, 0x2d, 0xed, 0x42, 0x43, 0x1e, - ], - ], - output: [ - 0x5a, 0xeb, 0x48, 0x96, 0x21, 0xb0, 0x2e, 0x8e, 0x69, 0x27, 0xb9, 0x4f, 0xd2, - 0x9a, 0x61, 0x01, 0x83, 0xdf, 0x7f, 0x42, 0x87, 0xe9, 0xcb, 0xf1, 0xcc, 0xc8, - 0x81, 0xd7, 0xd0, 0xb7, 0x38, 0x27, - ], - }, - TestVector { - input: [ - [ - 0x91, 0x47, 0x69, 0x30, 0xe3, 0x38, 0x5c, 0xd3, 0xe3, 0x37, 0x9e, 0x38, - 0x53, 0xd9, 0x34, 0x67, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, - 0x6d, 0x75, 0xa4, 0xa6, 0xf2, 0x65, 0x72, 0x10, - ], - [ - 0x4b, 0x19, 0x22, 0x32, 0xec, 0xb9, 0xf0, 0xc0, 0x24, 0x11, 0xe5, 0x25, - 0x96, 0xbc, 0x5e, 0x90, 0x45, 0x7e, 0x74, 0x59, 0x39, 0xff, 0xed, 0xbd, - 0x12, 0x86, 0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11, - ], - ], - output: [ - 0xb0, 0x14, 0x47, 0x20, 0xf5, 0xf2, 0xa2, 0x5d, 0x49, 0x2a, 0x50, 0x4e, 0xc0, - 0x73, 0x7f, 0x09, 0x7e, 0xd8, 0x52, 0x17, 0x4f, 0x55, 0xf5, 0x86, 0x30, 0x91, - 0x30, 0x6c, 0x1a, 0xf2, 0x00, 0x35, - ], - }, - TestVector { - input: [ - [ - 0x7b, 0x41, 0x7a, 0xdb, 0x63, 0xb3, 0x71, 0x22, 0xa5, 0xbf, 0x62, 0xd2, - 0x6f, 0x1e, 0x7f, 0x26, 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, - 0x82, 0x85, 0x7d, 0xee, 0xcc, 0x40, 0xa9, 0x0d, - ], - [ - 0x5e, 0x29, 0x35, 0x39, 0x71, 0xb3, 0x49, 0x94, 0xb6, 0x21, 0xb0, 0xb2, - 0x61, 0xae, 0xb3, 0x78, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, - 0xb9, 0x27, 0xb7, 0xfa, 0xe2, 0xdb, 0x58, 0x31, - ], - ], - output: [ - 0xbb, 0xbe, 0xb7, 0x42, 0xd6, 0xe7, 0xc0, 0x1a, 0xdb, 0xf4, 0xd3, 0x85, 0x5e, - 0x35, 0xfe, 0xc4, 0x62, 0x04, 0x30, 0x89, 0xc1, 0x8b, 0xa8, 0x02, 0x90, 0x64, - 0x7b, 0xb0, 0xe5, 0x81, 0xad, 0x11, - ], - }, - ] - } -} - -pub(crate) mod fq { - use super::*; - - pub(crate) fn permute() -> Vec { - use PermuteTestVector as TestVector; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/orchard_poseidon/permute/fq.py - vec![ - TestVector { - initial_state: [ - [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - [ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - [ - 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - ], - final_state: [ - [ - 0x59, 0xbe, 0xbe, 0x13, 0xa8, 0x8e, 0xb0, 0x0e, 0xc6, 0x36, 0xd3, 0x3d, - 0x97, 0xd1, 0x43, 0x4d, 0xf7, 0x2f, 0x8f, 0x2f, 0xf2, 0x74, 0xdd, 0xed, - 0x7c, 0x2f, 0x94, 0xdb, 0x4c, 0x1f, 0x5a, 0x31, - ], - [ - 0xf1, 0x65, 0xa1, 0x1e, 0xe6, 0x26, 0xf1, 0xf9, 0x98, 0x21, 0xbd, 0x7b, - 0xeb, 0xe0, 0x3e, 0x41, 0x48, 0xaa, 0x13, 0xdd, 0xe0, 0xde, 0x2a, 0x64, - 0xde, 0x2b, 0x64, 0xd7, 0xf2, 0x75, 0xe4, 0x3b, - ], - [ - 0xd9, 0xa0, 0x7b, 0x2a, 0x37, 0x42, 0xd5, 0x14, 0xa0, 0x3f, 0x42, 0xe0, - 0xd4, 0xbf, 0x19, 0x50, 0x60, 0xea, 0xd8, 0x20, 0x24, 0xdb, 0x7f, 0x11, - 0x68, 0x71, 0x53, 0xe9, 0xec, 0x8a, 0xab, 0x25, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x5c, 0x7a, 0x8f, 0x73, 0x79, 0x42, 0x57, 0x08, 0x7e, 0x63, 0x4c, 0x49, - 0xac, 0x6b, 0x57, 0x07, 0x4c, 0x4d, 0x6e, 0x66, 0xb1, 0x64, 0x93, 0x9d, - 0xaf, 0xfa, 0x2e, 0xf6, 0xee, 0x69, 0x21, 0x08, - ], - [ - 0x1a, 0xdd, 0x86, 0xb3, 0x8a, 0x6d, 0x8a, 0xc0, 0xa6, 0xfd, 0x9e, 0x0d, - 0x98, 0x2b, 0x77, 0xe6, 0xb0, 0xef, 0x9c, 0xa3, 0xf2, 0x49, 0x88, 0xc7, - 0xb3, 0x53, 0x42, 0x01, 0xcf, 0xb1, 0xcd, 0x0d, - ], - [ - 0xbd, 0x69, 0xb8, 0x25, 0xca, 0x41, 0x61, 0x29, 0x6e, 0xfa, 0x7f, 0x66, - 0x9b, 0xa9, 0xc7, 0x27, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, - 0xa5, 0xe2, 0x9d, 0x4e, 0x30, 0xa7, 0x35, 0x14, - ], - ], - final_state: [ - [ - 0xcd, 0x8f, 0x83, 0x92, 0xdf, 0xc7, 0x72, 0x8f, 0x5f, 0x6d, 0x85, 0x4c, - 0xc4, 0x60, 0x70, 0xa4, 0x0c, 0xba, 0x7a, 0x80, 0x33, 0x2d, 0xdc, 0x65, - 0xcb, 0xe2, 0x4a, 0xc3, 0xde, 0x23, 0x5e, 0x0e, - ], - [ - 0xc2, 0x53, 0xe5, 0x95, 0x3c, 0x83, 0xaa, 0x8a, 0x23, 0xd4, 0xd5, 0x58, - 0x7f, 0xbf, 0xc0, 0x7e, 0x78, 0x33, 0x1f, 0x7d, 0x46, 0xd1, 0xf5, 0xfa, - 0x54, 0x4d, 0x6a, 0xbd, 0xd4, 0x24, 0x1b, 0x27, - ], - [ - 0xb8, 0xc8, 0x33, 0x9b, 0xf9, 0x47, 0x2a, 0xd1, 0xc5, 0x27, 0xb7, 0x5e, - 0x99, 0x81, 0x2c, 0xa9, 0x1c, 0x5c, 0xbd, 0x7f, 0x4d, 0x46, 0x6f, 0x1a, - 0x13, 0x5a, 0x67, 0x50, 0x66, 0x76, 0x64, 0x34, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0xbc, 0x50, 0x98, 0x42, 0xb9, 0xa7, 0x62, 0xe5, 0x58, 0xea, 0x51, 0x47, - 0xed, 0x5a, 0xc0, 0x08, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, 0xbc, 0xb6, - 0x4b, 0x69, 0x68, 0x91, 0x2a, 0x63, 0x81, 0x0e, - ], - [ - 0x3d, 0xc1, 0x66, 0xd5, 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, - 0xb5, 0xfd, 0x93, 0x13, 0xe8, 0xc7, 0x20, 0x3d, 0x99, 0x6a, 0xf7, 0xd4, - 0x77, 0x08, 0x37, 0x56, 0xd5, 0x9a, 0xf8, 0x0d, - ], - [ - 0x05, 0xa7, 0x45, 0xf4, 0x29, 0xc5, 0xdc, 0xe8, 0x4e, 0x0c, 0x20, 0xfd, - 0xf0, 0xf0, 0x3e, 0xbf, 0x81, 0x30, 0xab, 0x33, 0x36, 0x26, 0x97, 0xb0, - 0xe4, 0xe4, 0xc7, 0x63, 0xcc, 0xb8, 0xf6, 0x36, - ], - ], - final_state: [ - [ - 0xa3, 0x5b, 0x56, 0x64, 0x62, 0x4a, 0x78, 0x49, 0x9e, 0xce, 0xe0, 0xfa, - 0x05, 0x18, 0x79, 0xa2, 0xad, 0x1c, 0xa4, 0x53, 0x9b, 0x5b, 0xd2, 0xa4, - 0x67, 0xe2, 0xea, 0x8d, 0x4e, 0x2d, 0x40, 0x08, - ], - [ - 0x36, 0xc2, 0x21, 0x7a, 0xe5, 0x75, 0xaa, 0xf8, 0xf2, 0x54, 0xd6, 0xe0, - 0x60, 0x10, 0x1c, 0xdc, 0x85, 0xaa, 0x39, 0x3c, 0x09, 0x54, 0x3b, 0xf0, - 0x48, 0x99, 0x7a, 0x7c, 0x5c, 0xb9, 0x27, 0x02, - ], - [ - 0x38, 0x12, 0x7e, 0xbe, 0xaf, 0x11, 0xae, 0x56, 0x64, 0x47, 0x14, 0x05, - 0x29, 0x3b, 0x60, 0x1c, 0x43, 0xf0, 0x3e, 0x8e, 0x40, 0x78, 0x11, 0x3a, - 0x63, 0x37, 0x10, 0x11, 0x9f, 0x9a, 0x1b, 0x1f, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, 0xfa, 0x3d, 0x5a, - 0x57, 0xef, 0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, 0xfb, - 0x1a, 0x38, 0xe0, 0x1d, 0x94, 0x90, 0x3d, 0x3c, - ], - [ - 0x3d, 0x0a, 0xd3, 0x36, 0xeb, 0x31, 0xf0, 0x83, 0xce, 0x29, 0x77, 0x0e, - 0x42, 0x98, 0x8d, 0x7d, 0x25, 0xc9, 0xa1, 0x38, 0xf4, 0x9b, 0x1a, 0x53, - 0x7e, 0xdc, 0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x11, - ], - [ - 0xa4, 0xaf, 0x9d, 0xb6, 0x36, 0x4d, 0x03, 0x99, 0x3d, 0x50, 0x35, 0x3d, - 0x88, 0x39, 0x5e, 0xd7, 0xa4, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, - 0xb9, 0xda, 0x94, 0x8d, 0x32, 0x0d, 0xad, 0x16, - ], - ], - final_state: [ - [ - 0x5c, 0x76, 0x63, 0x4f, 0xc7, 0x1a, 0x43, 0x7a, 0x3c, 0xc7, 0x89, 0x9d, - 0xb3, 0xb5, 0x1c, 0xea, 0xe6, 0x9a, 0xd0, 0x0b, 0x14, 0x96, 0xa6, 0x80, - 0x32, 0xd3, 0x83, 0x17, 0x37, 0x08, 0x79, 0x18, - ], - [ - 0xd3, 0xcc, 0x4e, 0xab, 0x45, 0x0a, 0xac, 0xc4, 0x5f, 0x9b, 0x32, 0x7e, - 0xbb, 0x9a, 0x50, 0xb8, 0x59, 0xca, 0x08, 0x0e, 0x10, 0x6b, 0x54, 0xc3, - 0x1c, 0x09, 0xc2, 0x1e, 0x1d, 0x79, 0xdf, 0x2a, - ], - [ - 0x09, 0x1e, 0x8f, 0x1e, 0xe9, 0xba, 0x00, 0xa3, 0xe3, 0xcf, 0x85, 0xd5, - 0xd6, 0x95, 0x3d, 0x25, 0xe0, 0x1e, 0x8b, 0xdb, 0x43, 0xde, 0x0f, 0xb7, - 0x30, 0x82, 0x4e, 0x6a, 0x8f, 0x69, 0x7e, 0x1c, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x4d, 0x54, 0x31, 0xe6, 0xdb, 0x08, 0xd8, 0x74, 0x69, 0x5c, 0x3e, 0xaf, - 0x34, 0x5b, 0x86, 0xc4, 0x12, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, - 0x42, 0x76, 0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x11, - ], - [ - 0xdd, 0x0c, 0x7a, 0x1d, 0xe5, 0xed, 0x2f, 0xc3, 0x8e, 0x5e, 0x60, 0x7a, - 0x3f, 0xde, 0xab, 0x3f, 0xb6, 0x79, 0xf3, 0xdc, 0x60, 0x1d, 0x00, 0x82, - 0x85, 0xed, 0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0x3c, - ], - [ - 0x19, 0xe4, 0xaa, 0xc0, 0xcd, 0x1b, 0xe4, 0x05, 0x02, 0x42, 0xf4, 0xd1, - 0x20, 0x53, 0xdb, 0x33, 0xf7, 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, - 0x37, 0x83, 0x65, 0xc8, 0xf7, 0x39, 0x3c, 0x14, - ], - ], - final_state: [ - [ - 0x00, 0xff, 0x3c, 0x20, 0xd5, 0xac, 0x28, 0x33, 0xe6, 0xd3, 0x84, 0x27, - 0xd0, 0x44, 0x06, 0x17, 0x9e, 0x31, 0xf3, 0xde, 0xd0, 0xe0, 0x33, 0xab, - 0x4f, 0x51, 0xfc, 0xb4, 0x28, 0xf8, 0x39, 0x1b, - ], - [ - 0x2a, 0x63, 0x7a, 0xa0, 0x4f, 0xb8, 0x0d, 0x9c, 0x50, 0xf3, 0x16, 0xb6, - 0x36, 0x7f, 0xa4, 0xf6, 0xed, 0x52, 0xd0, 0x7c, 0x99, 0xa1, 0x30, 0x29, - 0xd9, 0x3f, 0xae, 0xd3, 0xdd, 0x1e, 0xbc, 0x2f, - ], - [ - 0x12, 0x31, 0x54, 0xbb, 0x87, 0x60, 0x13, 0x94, 0x5f, 0x54, 0x69, 0x34, - 0x9d, 0x5f, 0xc3, 0xfc, 0xfc, 0xc9, 0xd2, 0xda, 0xb8, 0x06, 0x43, 0x0d, - 0x49, 0x69, 0x46, 0xf3, 0xbf, 0x2b, 0x61, 0x11, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, - 0x79, 0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, - 0x32, 0xb4, 0xf4, 0x73, 0xf4, 0x68, 0xa0, 0x08, - ], - [ - 0xe6, 0x23, 0x89, 0xfc, 0xe2, 0x9c, 0xc6, 0xeb, 0x2e, 0x07, 0xeb, 0xc5, - 0xae, 0x25, 0xf9, 0xf7, 0x83, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, 0x15, 0x3d, - 0x88, 0x2d, 0x2b, 0x21, 0x03, 0x59, 0x65, 0x15, - ], - [ - 0xeb, 0x94, 0x94, 0xc6, 0x6a, 0xb3, 0xae, 0x30, 0xb7, 0xe6, 0x09, 0xd9, - 0x91, 0xf4, 0x33, 0xbf, 0x94, 0x86, 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, - 0x73, 0x1e, 0x98, 0x5d, 0x99, 0x58, 0x9c, 0x0b, - ], - ], - final_state: [ - [ - 0xe7, 0x1e, 0xb4, 0x88, 0x51, 0xd7, 0x73, 0xb5, 0xa3, 0xb5, 0xd2, 0xb6, - 0xf6, 0xeb, 0x01, 0xc3, 0x79, 0x3f, 0x2f, 0xeb, 0xdf, 0xd1, 0xb9, 0x53, - 0xf0, 0x6f, 0xa9, 0x59, 0xc7, 0x26, 0xbc, 0x18, - ], - [ - 0x37, 0x71, 0xf8, 0x29, 0xfb, 0xf2, 0x74, 0x87, 0xf1, 0xdf, 0x2b, 0x5e, - 0xe9, 0x94, 0x97, 0x0b, 0x14, 0xd7, 0x13, 0xce, 0xae, 0x73, 0xa6, 0x33, - 0x95, 0x78, 0x4d, 0xcd, 0xf9, 0xaa, 0x30, 0x30, - ], - [ - 0x48, 0x06, 0xaf, 0xf7, 0x5e, 0xd3, 0xc6, 0xb9, 0x72, 0x1b, 0xc5, 0x23, - 0x0d, 0xd7, 0x76, 0xf9, 0x27, 0x44, 0x62, 0x90, 0x97, 0xcf, 0x5c, 0x2b, - 0x7f, 0x14, 0x2c, 0xf2, 0x74, 0xa5, 0x07, 0x37, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0xb7, 0x38, 0xe8, 0xaa, 0xd6, 0x5a, 0x0c, 0xb2, 0xfb, 0x3f, 0x1a, 0x31, - 0x20, 0x37, 0x2e, 0x83, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, - 0xeb, 0xbc, 0x86, 0x2d, 0xed, 0x42, 0x43, 0x1e, - ], - [ - 0x91, 0x47, 0x69, 0x30, 0xaf, 0x7e, 0x42, 0xe0, 0x21, 0x88, 0x56, 0x38, - 0x53, 0xd9, 0x34, 0x67, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, - 0x6d, 0x75, 0xa4, 0xa6, 0xf2, 0x65, 0x72, 0x10, - ], - [ - 0x4b, 0x19, 0x22, 0x32, 0xec, 0xb9, 0xf0, 0xc0, 0x24, 0x11, 0xe5, 0x25, - 0x96, 0xbc, 0x5e, 0x90, 0x45, 0x7e, 0x74, 0x59, 0x39, 0xff, 0xed, 0xbd, - 0x12, 0x86, 0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11, - ], - ], - final_state: [ - [ - 0x9d, 0x58, 0x16, 0x08, 0x94, 0x8a, 0xd0, 0x15, 0xf5, 0x38, 0x82, 0xc0, - 0x2d, 0x22, 0x40, 0x2f, 0x71, 0xbd, 0x52, 0x7a, 0xb6, 0xb0, 0xbd, 0xab, - 0x5e, 0xaf, 0xef, 0x0c, 0xd9, 0x41, 0xe8, 0x33, - ], - [ - 0xf4, 0x69, 0xd9, 0x80, 0x6d, 0x0b, 0x9d, 0x92, 0x46, 0x6b, 0xbd, 0xe4, - 0x90, 0x4b, 0x88, 0x2d, 0x29, 0xcc, 0x45, 0x6d, 0xef, 0xa4, 0x77, 0x3f, - 0x5d, 0x9a, 0x92, 0x79, 0x6c, 0x60, 0xed, 0x1d, - ], - [ - 0x3c, 0xf1, 0xa7, 0x38, 0x35, 0xf9, 0x42, 0x5d, 0x46, 0x87, 0xa0, 0x9b, - 0xea, 0xcf, 0x48, 0x9a, 0xa6, 0x0e, 0xcb, 0xfc, 0xae, 0xa0, 0x61, 0xc9, - 0x7e, 0xd3, 0x72, 0x86, 0x1c, 0x08, 0x0a, 0x3d, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x7b, 0x41, 0x7a, 0xdb, 0xfb, 0x3e, 0x3e, 0x3c, 0x21, 0x60, 0xd3, 0xd1, - 0x6f, 0x1e, 0x7f, 0x26, 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, - 0x82, 0x85, 0x7d, 0xee, 0xcc, 0x40, 0xa9, 0x0d, - ], - [ - 0x5e, 0x29, 0x35, 0x39, 0x3d, 0xf9, 0x2f, 0xa1, 0xf4, 0x71, 0x68, 0xb2, - 0x61, 0xae, 0xb3, 0x78, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, - 0xb9, 0x27, 0xb7, 0xfa, 0xe2, 0xdb, 0x58, 0x31, - ], - [ - 0x05, 0x41, 0x5d, 0x46, 0x42, 0x78, 0x9d, 0x38, 0xf5, 0x0b, 0x8d, 0xbc, - 0xc1, 0x29, 0xca, 0xb3, 0xd1, 0x7d, 0x19, 0xf3, 0x35, 0x5b, 0xcf, 0x73, - 0xce, 0xcb, 0x8c, 0xb8, 0xa5, 0xda, 0x01, 0x30, - ], - ], - final_state: [ - [ - 0x73, 0x2c, 0x01, 0x83, 0x41, 0x7f, 0xdf, 0x33, 0x43, 0xc1, 0xef, 0x69, - 0xfd, 0xf6, 0xb3, 0xe7, 0xfd, 0x52, 0x9e, 0xe8, 0x44, 0x63, 0x48, 0xf2, - 0x78, 0x50, 0x74, 0xaf, 0xe2, 0x97, 0xe5, 0x39, - ], - [ - 0xc0, 0x33, 0xd0, 0x1c, 0xb2, 0x29, 0x7f, 0x14, 0xdc, 0xcf, 0x8a, 0x37, - 0xc8, 0x90, 0x02, 0x09, 0x46, 0x5c, 0xc7, 0x41, 0x24, 0x50, 0xe0, 0xb0, - 0x82, 0x84, 0xf9, 0xaa, 0xa1, 0x18, 0xde, 0x34, - ], - [ - 0x17, 0xf9, 0xa6, 0x65, 0x38, 0x93, 0xea, 0x76, 0xbe, 0x60, 0x00, 0x20, - 0xb8, 0xff, 0xbf, 0xd9, 0x53, 0xae, 0x4a, 0x94, 0xad, 0x00, 0x10, 0x43, - 0x37, 0xb9, 0xf7, 0xde, 0x69, 0x88, 0x60, 0x31, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x71, 0x52, 0xf1, 0x39, 0x36, 0xa2, 0x70, 0x57, 0x26, 0x70, 0xdc, 0x82, - 0xd3, 0x90, 0x26, 0xc6, 0xcb, 0x4c, 0xd4, 0xb0, 0xf7, 0xf5, 0xaa, 0x2a, - 0x4f, 0x5a, 0x53, 0x41, 0xec, 0x5d, 0xd7, 0x15, - ], - [ - 0x40, 0x6f, 0x2f, 0xdd, 0x2a, 0xfa, 0x73, 0x3f, 0x5f, 0x64, 0x1c, 0x8c, - 0x21, 0x86, 0x2a, 0x1b, 0xaf, 0xce, 0x26, 0x09, 0xd9, 0xee, 0xcf, 0xa1, - 0x58, 0xcf, 0xb5, 0xcd, 0x79, 0xf8, 0x80, 0x08, - ], - [ - 0xe2, 0x15, 0xdc, 0x7d, 0x62, 0x9d, 0xa0, 0xe0, 0x39, 0xd9, 0x68, 0x1e, - 0x99, 0x38, 0x44, 0x54, 0x36, 0x24, 0xc2, 0x5f, 0xa9, 0x59, 0xcc, 0x97, - 0x48, 0x9c, 0xe7, 0x57, 0x45, 0x82, 0x4b, 0x37, - ], - ], - final_state: [ - [ - 0x16, 0x0a, 0x24, 0x98, 0x48, 0x62, 0xea, 0xe0, 0xa3, 0x33, 0x50, 0x7b, - 0x36, 0x11, 0x93, 0x13, 0x71, 0xc6, 0x1d, 0x8e, 0x65, 0x71, 0x38, 0xcf, - 0xb2, 0xfa, 0x3b, 0x0f, 0x4d, 0xe5, 0xed, 0x3b, - ], - [ - 0xc5, 0xbd, 0x5a, 0x00, 0x44, 0xb6, 0xdb, 0xfe, 0x88, 0xb6, 0x97, 0xf7, - 0x1e, 0xa0, 0x55, 0xb4, 0xe2, 0x32, 0x42, 0x66, 0x6b, 0xf4, 0xe1, 0xb0, - 0x27, 0x52, 0xee, 0xce, 0x08, 0xfb, 0xe8, 0x05, - ], - [ - 0x30, 0x34, 0xdc, 0x8e, 0x8d, 0x4f, 0x6e, 0x33, 0x53, 0x83, 0xb9, 0x01, - 0x35, 0x8a, 0xe4, 0xb7, 0x5f, 0xcc, 0xc7, 0x22, 0x69, 0xdb, 0x83, 0x37, - 0x89, 0xce, 0xd4, 0xc0, 0xad, 0x83, 0x25, 0x1e, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x86, 0x8c, 0x53, 0x23, 0x9c, 0xfb, 0xdf, 0x73, 0xca, 0xec, 0x65, 0x60, - 0x40, 0x37, 0x31, 0x4f, 0xaa, 0xce, 0xb5, 0x62, 0x18, 0xc6, 0xbd, 0x30, - 0xf8, 0x37, 0x4a, 0xc1, 0x33, 0x86, 0x79, 0x3f, - ], - [ - 0x21, 0xa9, 0xfb, 0x80, 0xad, 0x03, 0xbc, 0x0c, 0xda, 0x4a, 0x44, 0x94, - 0x6c, 0x00, 0xe1, 0xb1, 0xa1, 0xdf, 0x0e, 0x5b, 0x87, 0xb5, 0xbe, 0xce, - 0x47, 0x7a, 0x70, 0x96, 0x49, 0xe9, 0x50, 0x06, - ], - [ - 0x04, 0x91, 0x39, 0x48, 0xf1, 0xa9, 0xd7, 0x92, 0x05, 0xe1, 0xc6, 0x82, - 0xc7, 0x38, 0x07, 0x0a, 0xf6, 0x55, 0x6d, 0xf6, 0xed, 0x4b, 0x4d, 0xdd, - 0x3d, 0x9a, 0x69, 0xf5, 0x33, 0x57, 0xd7, 0x36, - ], - ], - final_state: [ - [ - 0x63, 0xe6, 0x3f, 0x14, 0xcc, 0x49, 0xec, 0x8f, 0x59, 0x93, 0x33, 0xae, - 0x04, 0x2c, 0xb4, 0x0c, 0x6f, 0xa8, 0x5f, 0x2d, 0x67, 0x64, 0xde, 0xad, - 0x13, 0x16, 0x44, 0x04, 0x97, 0x8b, 0x12, 0x03, - ], - [ - 0xc5, 0x61, 0xf3, 0x87, 0xb4, 0xaa, 0x32, 0x60, 0x09, 0x0f, 0x01, 0x73, - 0x88, 0x01, 0xb5, 0x34, 0xbe, 0x39, 0x6a, 0x13, 0xee, 0x11, 0x6b, 0x21, - 0xdb, 0x76, 0x10, 0x69, 0x59, 0x3d, 0xb6, 0x2f, - ], - [ - 0x10, 0x1a, 0x4b, 0xfd, 0x56, 0x89, 0xd5, 0x5a, 0xa7, 0x0e, 0xcf, 0x44, - 0x6d, 0xc3, 0x1a, 0x89, 0xbc, 0x62, 0xde, 0xb7, 0xed, 0x36, 0xf5, 0x49, - 0x19, 0x9c, 0xe1, 0x7b, 0xac, 0xe7, 0x32, 0x1b, - ], - ], - }, - TestVector { - initial_state: [ - [ - 0x7d, 0x4f, 0x5c, 0xcb, 0x99, 0xef, 0x08, 0x4b, 0x57, 0x25, 0xcf, 0xeb, - 0xd5, 0xd6, 0x3d, 0xc1, 0x6a, 0x95, 0xe3, 0x02, 0x5b, 0x97, 0x92, 0xff, - 0xf7, 0xf2, 0x44, 0xfc, 0x71, 0x62, 0x69, 0x39, - ], - [ - 0x26, 0xd6, 0x2e, 0x95, 0x96, 0xfa, 0x82, 0x5c, 0x6b, 0xf2, 0x1a, 0xff, - 0x9e, 0x68, 0x62, 0x5a, 0x19, 0x24, 0x40, 0xea, 0x06, 0x82, 0x81, 0x23, - 0xd9, 0x78, 0x84, 0x80, 0x6f, 0x15, 0xfa, 0x08, - ], - [ - 0xd9, 0x52, 0x75, 0x4a, 0xef, 0xa9, 0x9c, 0x73, 0x3d, 0x14, 0xc8, 0xda, - 0x01, 0x47, 0x86, 0xda, 0x3a, 0x61, 0x28, 0xae, 0xf7, 0x84, 0xa6, 0x46, - 0x10, 0xa8, 0x9d, 0x1a, 0x70, 0x99, 0x21, 0x2d, - ], - ], - final_state: [ - [ - 0x45, 0xed, 0x54, 0x17, 0x40, 0x7b, 0xfd, 0xb7, 0x97, 0xbc, 0xfe, 0x70, - 0x74, 0xdf, 0xf8, 0x0e, 0x32, 0xa5, 0x62, 0xed, 0x88, 0x73, 0x78, 0x1d, - 0xbc, 0xf4, 0xf6, 0x7e, 0x06, 0xbe, 0x0c, 0x23, - ], - [ - 0x13, 0x2f, 0x3f, 0x55, 0xd8, 0xfb, 0xfd, 0x46, 0x7b, 0x2a, 0xe2, 0x2b, - 0x8c, 0x64, 0x93, 0x43, 0x64, 0xcf, 0x9c, 0x4a, 0x0b, 0x07, 0xed, 0xb4, - 0x02, 0x87, 0xc3, 0x92, 0xc9, 0xc1, 0x45, 0x12, - ], - [ - 0xd0, 0x51, 0xc3, 0x7f, 0xf6, 0x4c, 0xad, 0xa2, 0xb4, 0x82, 0xf1, 0x1f, - 0x85, 0x64, 0x39, 0x6b, 0x75, 0xe3, 0xf8, 0x1b, 0x35, 0x52, 0xd8, 0x9a, - 0xf4, 0x92, 0xcf, 0x00, 0x52, 0x3c, 0x04, 0x15, - ], - ], - }, - ] - } - - pub(crate) fn hash() -> Vec { - use HashTestVector as TestVector; - - // From https://github.com/zcash-hackworks/zcash-test-vectors/blob/master/orchard_poseidon/hash/fq.py - vec![ - TestVector { - input: [ - [ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - [ - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], - ], - output: [ - 0x4e, 0x68, 0xf6, 0x85, 0x70, 0x29, 0x57, 0xf3, 0xbf, 0x54, 0x6b, 0x7a, 0x09, - 0x01, 0x31, 0x4e, 0x51, 0x4f, 0x19, 0x5e, 0xe3, 0xb1, 0x64, 0x46, 0x22, 0x77, - 0x9d, 0x93, 0xdf, 0x96, 0xba, 0x15, - ], - }, - TestVector { - input: [ - [ - 0x5c, 0x7a, 0x8f, 0x73, 0x79, 0x42, 0x57, 0x08, 0x7e, 0x63, 0x4c, 0x49, - 0xac, 0x6b, 0x57, 0x07, 0x4c, 0x4d, 0x6e, 0x66, 0xb1, 0x64, 0x93, 0x9d, - 0xaf, 0xfa, 0x2e, 0xf6, 0xee, 0x69, 0x21, 0x08, - ], - [ - 0x1a, 0xdd, 0x86, 0xb3, 0x8a, 0x6d, 0x8a, 0xc0, 0xa6, 0xfd, 0x9e, 0x0d, - 0x98, 0x2b, 0x77, 0xe6, 0xb0, 0xef, 0x9c, 0xa3, 0xf2, 0x49, 0x88, 0xc7, - 0xb3, 0x53, 0x42, 0x01, 0xcf, 0xb1, 0xcd, 0x0d, - ], - ], - output: [ - 0x0c, 0x0a, 0xd9, 0x0a, 0x2e, 0x0c, 0xba, 0x0e, 0xe6, 0xa5, 0x5a, 0xc5, 0x38, - 0xa4, 0x35, 0xc9, 0x39, 0x04, 0x98, 0xae, 0xb5, 0x30, 0x3e, 0x3d, 0xad, 0x70, - 0x3a, 0xd1, 0xdc, 0xdb, 0x43, 0x2b, - ], - }, - TestVector { - input: [ - [ - 0xbd, 0x69, 0xb8, 0x25, 0xca, 0x41, 0x61, 0x29, 0x6e, 0xfa, 0x7f, 0x66, - 0x9b, 0xa9, 0xc7, 0x27, 0x1f, 0xe0, 0x1f, 0x7e, 0x9c, 0x8e, 0x36, 0xd6, - 0xa5, 0xe2, 0x9d, 0x4e, 0x30, 0xa7, 0x35, 0x14, - ], - [ - 0xbc, 0x50, 0x98, 0x42, 0xb9, 0xa7, 0x62, 0xe5, 0x58, 0xea, 0x51, 0x47, - 0xed, 0x5a, 0xc0, 0x08, 0x62, 0xc2, 0xfa, 0x7b, 0x2f, 0xec, 0xbc, 0xb6, - 0x4b, 0x69, 0x68, 0x91, 0x2a, 0x63, 0x81, 0x0e, - ], - ], - output: [ - 0xa6, 0x0c, 0xc8, 0xb8, 0x53, 0xaf, 0xce, 0xdb, 0xa1, 0x44, 0x65, 0xd5, 0x31, - 0xc7, 0x3c, 0xbc, 0xe1, 0x9e, 0x46, 0x0b, 0xa8, 0x04, 0x62, 0x2d, 0xf5, 0x21, - 0x23, 0x1d, 0xa1, 0x21, 0xc6, 0x08, - ], - }, - TestVector { - input: [ - [ - 0x3d, 0xc1, 0x66, 0xd5, 0x6a, 0x1d, 0x62, 0xf5, 0xa8, 0xd7, 0x55, 0x1d, - 0xb5, 0xfd, 0x93, 0x13, 0xe8, 0xc7, 0x20, 0x3d, 0x99, 0x6a, 0xf7, 0xd4, - 0x77, 0x08, 0x37, 0x56, 0xd5, 0x9a, 0xf8, 0x0d, - ], - [ - 0x05, 0xa7, 0x45, 0xf4, 0x29, 0xc5, 0xdc, 0xe8, 0x4e, 0x0c, 0x20, 0xfd, - 0xf0, 0xf0, 0x3e, 0xbf, 0x81, 0x30, 0xab, 0x33, 0x36, 0x26, 0x97, 0xb0, - 0xe4, 0xe4, 0xc7, 0x63, 0xcc, 0xb8, 0xf6, 0x36, - ], - ], - output: [ - 0xad, 0xa8, 0xca, 0xe4, 0x6a, 0x04, 0x2d, 0x00, 0xb0, 0x2e, 0x33, 0xc3, 0x6e, - 0x65, 0x8c, 0x22, 0x13, 0xfe, 0x81, 0x34, 0x53, 0x8b, 0x56, 0x03, 0x19, 0xe9, - 0x99, 0xf3, 0xf5, 0x82, 0x90, 0x00, - ], - }, - TestVector { - input: [ - [ - 0x49, 0x5c, 0x22, 0x2f, 0x7f, 0xba, 0x1e, 0x31, 0xde, 0xfa, 0x3d, 0x5a, - 0x57, 0xef, 0xc2, 0xe1, 0xe9, 0xb0, 0x1a, 0x03, 0x55, 0x87, 0xd5, 0xfb, - 0x1a, 0x38, 0xe0, 0x1d, 0x94, 0x90, 0x3d, 0x3c, - ], - [ - 0x3d, 0x0a, 0xd3, 0x36, 0xeb, 0x31, 0xf0, 0x83, 0xce, 0x29, 0x77, 0x0e, - 0x42, 0x98, 0x8d, 0x7d, 0x25, 0xc9, 0xa1, 0x38, 0xf4, 0x9b, 0x1a, 0x53, - 0x7e, 0xdc, 0xf0, 0x4b, 0xe3, 0x4a, 0x98, 0x11, - ], - ], - output: [ - 0x19, 0x94, 0x9f, 0xc7, 0x74, 0x04, 0x99, 0x37, 0x00, 0x58, 0x12, 0x7d, 0x04, - 0x0f, 0x11, 0x24, 0x5e, 0xba, 0x6c, 0x37, 0x80, 0xe9, 0x3e, 0x26, 0x16, 0xf4, - 0xc1, 0x77, 0x56, 0x30, 0x78, 0x2d, - ], - }, - TestVector { - input: [ - [ - 0xa4, 0xaf, 0x9d, 0xb6, 0x36, 0x4d, 0x03, 0x99, 0x3d, 0x50, 0x35, 0x3d, - 0x88, 0x39, 0x5e, 0xd7, 0xa4, 0x1b, 0x00, 0x52, 0xad, 0x80, 0x84, 0xa8, - 0xb9, 0xda, 0x94, 0x8d, 0x32, 0x0d, 0xad, 0x16, - ], - [ - 0x4d, 0x54, 0x31, 0xe6, 0xdb, 0x08, 0xd8, 0x74, 0x69, 0x5c, 0x3e, 0xaf, - 0x34, 0x5b, 0x86, 0xc4, 0x12, 0x1f, 0xc0, 0x0f, 0xe7, 0xf2, 0x35, 0x73, - 0x42, 0x76, 0xd3, 0x8d, 0x47, 0xf1, 0xe1, 0x11, - ], - ], - output: [ - 0x29, 0x6e, 0xba, 0xb4, 0xb4, 0x5a, 0xb9, 0x20, 0x97, 0xa7, 0xe6, 0xe7, 0xcc, - 0x6d, 0xd7, 0xd4, 0x7a, 0x12, 0x3e, 0x85, 0x50, 0xa3, 0x3d, 0xf1, 0x20, 0xcc, - 0xa5, 0x38, 0x90, 0x67, 0x1b, 0x21, - ], - }, - TestVector { - input: [ - [ - 0xdd, 0x0c, 0x7a, 0x1d, 0xe5, 0xed, 0x2f, 0xc3, 0x8e, 0x5e, 0x60, 0x7a, - 0x3f, 0xde, 0xab, 0x3f, 0xb6, 0x79, 0xf3, 0xdc, 0x60, 0x1d, 0x00, 0x82, - 0x85, 0xed, 0xcb, 0xda, 0xe6, 0x9c, 0xe8, 0x3c, - ], - [ - 0x19, 0xe4, 0xaa, 0xc0, 0xcd, 0x1b, 0xe4, 0x05, 0x02, 0x42, 0xf4, 0xd1, - 0x20, 0x53, 0xdb, 0x33, 0xf7, 0x34, 0x76, 0xf2, 0x1a, 0x48, 0x2e, 0xc9, - 0x37, 0x83, 0x65, 0xc8, 0xf7, 0x39, 0x3c, 0x14, - ], - ], - output: [ - 0xa8, 0x87, 0x6e, 0x8d, 0x2f, 0x30, 0x0a, 0x62, 0x05, 0x4b, 0x49, 0x4c, 0x8f, - 0x21, 0xc1, 0xd0, 0xad, 0xbd, 0xac, 0x89, 0xbf, 0x2a, 0xad, 0x9f, 0x3c, 0x1b, - 0x10, 0xc4, 0x78, 0x8c, 0x2d, 0x3d, - ], - }, - TestVector { - input: [ - [ - 0xe2, 0x88, 0x53, 0x15, 0xeb, 0x46, 0x71, 0x09, 0x8b, 0x79, 0x53, 0x5e, - 0x79, 0x0f, 0xe5, 0x3e, 0x29, 0xfe, 0xf2, 0xb3, 0x76, 0x66, 0x97, 0xac, - 0x32, 0xb4, 0xf4, 0x73, 0xf4, 0x68, 0xa0, 0x08, - ], - [ - 0xe6, 0x23, 0x89, 0xfc, 0xe2, 0x9c, 0xc6, 0xeb, 0x2e, 0x07, 0xeb, 0xc5, - 0xae, 0x25, 0xf9, 0xf7, 0x83, 0xb2, 0x7d, 0xb5, 0x9a, 0x4a, 0x15, 0x3d, - 0x88, 0x2d, 0x2b, 0x21, 0x03, 0x59, 0x65, 0x15, - ], - ], - output: [ - 0xc2, 0xda, 0xcb, 0x1e, 0xea, 0xed, 0x88, 0x0b, 0x87, 0xd0, 0x4d, 0xd9, 0x61, - 0x95, 0x73, 0x0e, 0x98, 0xbd, 0x0f, 0x14, 0x77, 0x7b, 0x3e, 0xf0, 0xda, 0x40, - 0xe4, 0xc0, 0x87, 0xb1, 0x9d, 0x28, - ], - }, - TestVector { - input: [ - [ - 0xeb, 0x94, 0x94, 0xc6, 0x6a, 0xb3, 0xae, 0x30, 0xb7, 0xe6, 0x09, 0xd9, - 0x91, 0xf4, 0x33, 0xbf, 0x94, 0x86, 0xa7, 0xaf, 0xcf, 0x4a, 0x0d, 0x9c, - 0x73, 0x1e, 0x98, 0x5d, 0x99, 0x58, 0x9c, 0x0b, - ], - [ - 0xb7, 0x38, 0xe8, 0xaa, 0xd6, 0x5a, 0x0c, 0xb2, 0xfb, 0x3f, 0x1a, 0x31, - 0x20, 0x37, 0x2e, 0x83, 0x1a, 0x20, 0xda, 0x8a, 0xba, 0x18, 0xd1, 0xdb, - 0xeb, 0xbc, 0x86, 0x2d, 0xed, 0x42, 0x43, 0x1e, - ], - ], - output: [ - 0x5a, 0x55, 0xe3, 0x08, 0x2e, 0x55, 0xa5, 0x66, 0xb9, 0xca, 0xb1, 0xca, 0xf4, - 0x48, 0xf7, 0x0f, 0x8c, 0x9a, 0x53, 0xa1, 0xc9, 0xf6, 0x9e, 0x2a, 0x80, 0xdd, - 0xb8, 0x58, 0x3f, 0x99, 0x01, 0x26, - ], - }, - TestVector { - input: [ - [ - 0x91, 0x47, 0x69, 0x30, 0xaf, 0x7e, 0x42, 0xe0, 0x21, 0x88, 0x56, 0x38, - 0x53, 0xd9, 0x34, 0x67, 0xe0, 0x01, 0xaf, 0xa2, 0xfb, 0x8d, 0xc3, 0x43, - 0x6d, 0x75, 0xa4, 0xa6, 0xf2, 0x65, 0x72, 0x10, - ], - [ - 0x4b, 0x19, 0x22, 0x32, 0xec, 0xb9, 0xf0, 0xc0, 0x24, 0x11, 0xe5, 0x25, - 0x96, 0xbc, 0x5e, 0x90, 0x45, 0x7e, 0x74, 0x59, 0x39, 0xff, 0xed, 0xbd, - 0x12, 0x86, 0x3c, 0xe7, 0x1a, 0x02, 0xaf, 0x11, - ], - ], - output: [ - 0xca, 0xc6, 0x68, 0x8a, 0x3d, 0x2a, 0x7d, 0xca, 0xe1, 0xd4, 0x60, 0x1f, 0x9b, - 0xf0, 0x6d, 0x58, 0x00, 0x8f, 0x24, 0x85, 0x6a, 0xe6, 0x00, 0xf0, 0xe0, 0x90, - 0x07, 0x23, 0xaf, 0xa1, 0x20, 0x03, - ], - }, - TestVector { - input: [ - [ - 0x7b, 0x41, 0x7a, 0xdb, 0xfb, 0x3e, 0x3e, 0x3c, 0x21, 0x60, 0xd3, 0xd1, - 0x6f, 0x1e, 0x7f, 0x26, 0x8f, 0xb8, 0x6b, 0x12, 0xb5, 0x6d, 0xa9, 0xc3, - 0x82, 0x85, 0x7d, 0xee, 0xcc, 0x40, 0xa9, 0x0d, - ], - [ - 0x5e, 0x29, 0x35, 0x39, 0x3d, 0xf9, 0x2f, 0xa1, 0xf4, 0x71, 0x68, 0xb2, - 0x61, 0xae, 0xb3, 0x78, 0x6d, 0xd9, 0x84, 0xd5, 0x67, 0xdb, 0x28, 0x57, - 0xb9, 0x27, 0xb7, 0xfa, 0xe2, 0xdb, 0x58, 0x31, - ], - ], - output: [ - 0xd7, 0xe7, 0x83, 0x91, 0x97, 0x83, 0xb0, 0x8b, 0x5f, 0xad, 0x08, 0x9d, 0x57, - 0x1e, 0xc1, 0x8f, 0xb4, 0x63, 0x28, 0x53, 0x99, 0x3f, 0x35, 0xe3, 0xee, 0x54, - 0x3d, 0x4e, 0xed, 0xf6, 0x5f, 0x38, - ], - }, - ] - } -} diff --git a/halo2_gadgets/src/sha256.rs b/halo2_gadgets/src/sha256.rs deleted file mode 100644 index 19a658df3a..0000000000 --- a/halo2_gadgets/src/sha256.rs +++ /dev/null @@ -1,166 +0,0 @@ -//! The [SHA-256] hash function. -//! -//! [SHA-256]: https://tools.ietf.org/html/rfc6234 - -use std::cmp::min; -use std::convert::TryInto; -use std::fmt; - -use halo2_proofs::{ - arithmetic::FieldExt, - circuit::{Chip, Layouter}, - plonk::Error, -}; - -mod table16; - -pub use table16::{BlockWord, Table16Chip, Table16Config}; - -/// The size of a SHA-256 block, in 32-bit words. -pub const BLOCK_SIZE: usize = 16; -/// The size of a SHA-256 digest, in 32-bit words. -const DIGEST_SIZE: usize = 8; - -/// The set of circuit instructions required to use the [`Sha256`] gadget. -pub trait Sha256Instructions: Chip { - /// Variable representing the SHA-256 internal state. - type State: Clone + fmt::Debug; - /// Variable representing a 32-bit word of the input block to the SHA-256 compression - /// function. - type BlockWord: Copy + fmt::Debug + Default; - - /// Places the SHA-256 IV in the circuit, returning the initial state variable. - fn initialization_vector(&self, layouter: &mut impl Layouter) -> Result; - - /// Creates an initial state from the output state of a previous block - fn initialization( - &self, - layouter: &mut impl Layouter, - init_state: &Self::State, - ) -> Result; - - /// Starting from the given initialized state, processes a block of input and returns the - /// final state. - fn compress( - &self, - layouter: &mut impl Layouter, - initialized_state: &Self::State, - input: [Self::BlockWord; BLOCK_SIZE], - ) -> Result; - - /// Converts the given state into a message digest. - fn digest( - &self, - layouter: &mut impl Layouter, - state: &Self::State, - ) -> Result<[Self::BlockWord; DIGEST_SIZE], Error>; -} - -/// The output of a SHA-256 circuit invocation. -#[derive(Debug)] -pub struct Sha256Digest([BlockWord; DIGEST_SIZE]); - -/// A gadget that constrains a SHA-256 invocation. It supports input at a granularity of -/// 32 bits. -#[derive(Debug)] -pub struct Sha256> { - chip: CS, - state: CS::State, - cur_block: Vec, - length: usize, -} - -impl> Sha256 { - /// Create a new hasher instance. - pub fn new(chip: Sha256Chip, mut layouter: impl Layouter) -> Result { - let state = chip.initialization_vector(&mut layouter)?; - Ok(Sha256 { - chip, - state, - cur_block: Vec::with_capacity(BLOCK_SIZE), - length: 0, - }) - } - - /// Digest data, updating the internal state. - pub fn update( - &mut self, - mut layouter: impl Layouter, - mut data: &[Sha256Chip::BlockWord], - ) -> Result<(), Error> { - self.length += data.len() * 32; - - // Fill the current block, if possible. - let remaining = BLOCK_SIZE - self.cur_block.len(); - let (l, r) = data.split_at(min(remaining, data.len())); - self.cur_block.extend_from_slice(l); - data = r; - - // If we still don't have a full block, we are done. - if self.cur_block.len() < BLOCK_SIZE { - return Ok(()); - } - - // Process the now-full current block. - self.state = self.chip.compress( - &mut layouter, - &self.state, - self.cur_block[..] - .try_into() - .expect("cur_block.len() == BLOCK_SIZE"), - )?; - self.cur_block.clear(); - - // Process any additional full blocks. - let mut chunks_iter = data.chunks_exact(BLOCK_SIZE); - for chunk in &mut chunks_iter { - self.state = self.chip.initialization(&mut layouter, &self.state)?; - self.state = self.chip.compress( - &mut layouter, - &self.state, - chunk.try_into().expect("chunk.len() == BLOCK_SIZE"), - )?; - } - - // Cache the remaining partial block, if any. - let rem = chunks_iter.remainder(); - self.cur_block.extend_from_slice(rem); - - Ok(()) - } - - /// Retrieve result and consume hasher instance. - pub fn finalize( - mut self, - mut layouter: impl Layouter, - ) -> Result, Error> { - // Pad the remaining block - if !self.cur_block.is_empty() { - let padding = vec![Sha256Chip::BlockWord::default(); BLOCK_SIZE - self.cur_block.len()]; - self.cur_block.extend_from_slice(&padding); - self.state = self.chip.initialization(&mut layouter, &self.state)?; - self.state = self.chip.compress( - &mut layouter, - &self.state, - self.cur_block[..] - .try_into() - .expect("cur_block.len() == BLOCK_SIZE"), - )?; - } - self.chip - .digest(&mut layouter, &self.state) - .map(Sha256Digest) - } - - /// Convenience function to compute hash of the data. It will handle hasher creation, - /// data feeding and finalization. - pub fn digest( - chip: Sha256Chip, - mut layouter: impl Layouter, - data: &[Sha256Chip::BlockWord], - ) -> Result, Error> { - let mut hasher = Self::new(chip, layouter.namespace(|| "init"))?; - hasher.update(layouter.namespace(|| "update"), data)?; - hasher.finalize(layouter.namespace(|| "finalize")) - } -} diff --git a/halo2_gadgets/src/sha256/table16.rs b/halo2_gadgets/src/sha256/table16.rs deleted file mode 100644 index c4919158bc..0000000000 --- a/halo2_gadgets/src/sha256/table16.rs +++ /dev/null @@ -1,515 +0,0 @@ -use std::convert::TryInto; -use std::marker::PhantomData; - -use super::Sha256Instructions; -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter, Region, Value}, - plonk::{Advice, Any, Assigned, Column, ConstraintSystem, Error}, -}; -use halo2curves::pasta::pallas; - -mod compression; -mod gates; -mod message_schedule; -mod spread_table; -mod util; - -use compression::*; -use gates::*; -use message_schedule::*; -use spread_table::*; -use util::*; - -const ROUNDS: usize = 64; -const STATE: usize = 8; - -#[allow(clippy::unreadable_literal)] -pub(crate) const ROUND_CONSTANTS: [u32; ROUNDS] = [ - 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, -]; - -const IV: [u32; STATE] = [ - 0x6a09_e667, - 0xbb67_ae85, - 0x3c6e_f372, - 0xa54f_f53a, - 0x510e_527f, - 0x9b05_688c, - 0x1f83_d9ab, - 0x5be0_cd19, -]; - -#[derive(Clone, Copy, Debug, Default)] -/// A word in a `Table16` message block. -// TODO: Make the internals of this struct private. -pub struct BlockWord(pub Value); - -#[derive(Clone, Debug)] -/// Little-endian bits (up to 64 bits) -pub struct Bits([bool; LEN]); - -impl Bits { - fn spread(&self) -> [bool; SPREAD] { - spread_bits(self.0) - } -} - -impl std::ops::Deref for Bits { - type Target = [bool; LEN]; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl From<[bool; LEN]> for Bits { - fn from(bits: [bool; LEN]) -> Self { - Self(bits) - } -} - -impl From<&Bits> for [bool; LEN] { - fn from(bits: &Bits) -> Self { - bits.0 - } -} - -impl From<&Bits> for Assigned { - fn from(bits: &Bits) -> Assigned { - assert!(LEN <= 64); - pallas::Base::from(lebs2ip(&bits.0)).into() - } -} - -impl From<&Bits<16>> for u16 { - fn from(bits: &Bits<16>) -> u16 { - lebs2ip(&bits.0) as u16 - } -} - -impl From for Bits<16> { - fn from(int: u16) -> Bits<16> { - Bits(i2lebsp::<16>(int.into())) - } -} - -impl From<&Bits<32>> for u32 { - fn from(bits: &Bits<32>) -> u32 { - lebs2ip(&bits.0) as u32 - } -} - -impl From for Bits<32> { - fn from(int: u32) -> Bits<32> { - Bits(i2lebsp::<32>(int.into())) - } -} - -#[derive(Clone, Debug)] -pub struct AssignedBits(AssignedCell, pallas::Base>); - -impl std::ops::Deref for AssignedBits { - type Target = AssignedCell, pallas::Base>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl AssignedBits { - fn assign_bits + std::fmt::Debug + Clone>( - region: &mut Region<'_, pallas::Base>, - annotation: A, - column: impl Into>, - offset: usize, - value: Value, - ) -> Result - where - A: Fn() -> AR, - AR: Into, - >::Error: std::fmt::Debug, - { - let value: Value<[bool; LEN]> = value.map(|v| v.try_into().unwrap()); - let value: Value> = value.map(|v| v.into()); - - let column: Column = column.into(); - match column.column_type() { - Any::Advice(_) => { - region.assign_advice(annotation, column.try_into().unwrap(), offset, || { - value.clone() - }) - } - Any::Fixed => { - region.assign_fixed(annotation, column.try_into().unwrap(), offset, || { - value.clone() - }) - } - _ => panic!("Cannot assign to instance column"), - } - .map(AssignedBits) - } -} - -impl AssignedBits<16> { - fn value_u16(&self) -> Value { - self.value().map(|v| v.into()) - } - - fn assign( - region: &mut Region<'_, pallas::Base>, - annotation: A, - column: impl Into>, - offset: usize, - value: Value, - ) -> Result - where - A: Fn() -> AR, - AR: Into, - { - let column: Column = column.into(); - let value: Value> = value.map(|v| v.into()); - match column.column_type() { - Any::Advice(_) => { - region.assign_advice(annotation, column.try_into().unwrap(), offset, || { - value.clone() - }) - } - Any::Fixed => { - region.assign_fixed(annotation, column.try_into().unwrap(), offset, || { - value.clone() - }) - } - _ => panic!("Cannot assign to instance column"), - } - .map(AssignedBits) - } -} - -impl AssignedBits<32> { - fn value_u32(&self) -> Value { - self.value().map(|v| v.into()) - } - - fn assign( - region: &mut Region<'_, pallas::Base>, - annotation: A, - column: impl Into>, - offset: usize, - value: Value, - ) -> Result - where - A: Fn() -> AR, - AR: Into, - { - let column: Column = column.into(); - let value: Value> = value.map(|v| v.into()); - match column.column_type() { - Any::Advice(_) => { - region.assign_advice(annotation, column.try_into().unwrap(), offset, || { - value.clone() - }) - } - Any::Fixed => { - region.assign_fixed(annotation, column.try_into().unwrap(), offset, || { - value.clone() - }) - } - _ => panic!("Cannot assign to instance column"), - } - .map(AssignedBits) - } -} - -/// Configuration for a [`Table16Chip`]. -#[derive(Clone, Debug)] -pub struct Table16Config { - lookup: SpreadTableConfig, - message_schedule: MessageScheduleConfig, - compression: CompressionConfig, -} - -/// A chip that implements SHA-256 with a maximum lookup table size of $2^16$. -#[derive(Clone, Debug)] -pub struct Table16Chip { - config: Table16Config, - _marker: PhantomData, -} - -impl Chip for Table16Chip { - type Config = Table16Config; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -impl Table16Chip { - /// Reconstructs this chip from the given config. - pub fn construct(config: >::Config) -> Self { - Self { - config, - _marker: PhantomData, - } - } - - /// Configures a circuit to include this chip. - pub fn configure( - meta: &mut ConstraintSystem, - ) -> >::Config { - // Columns required by this chip: - let message_schedule = meta.advice_column(); - let extras = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - - // - Three advice columns to interact with the lookup table. - let input_tag = meta.advice_column(); - let input_dense = meta.advice_column(); - let input_spread = meta.advice_column(); - - let lookup = SpreadTableChip::configure(meta, input_tag, input_dense, input_spread); - let lookup_inputs = lookup.input.clone(); - - // Rename these here for ease of matching the gates to the specification. - let _a_0 = lookup_inputs.tag; - let a_1 = lookup_inputs.dense; - let a_2 = lookup_inputs.spread; - let a_3 = extras[0]; - let a_4 = extras[1]; - let a_5 = message_schedule; - let a_6 = extras[2]; - let a_7 = extras[3]; - let a_8 = extras[4]; - let _a_9 = extras[5]; - - // Add all advice columns to permutation - for column in [a_1, a_2, a_3, a_4, a_5, a_6, a_7, a_8].iter() { - meta.enable_equality(*column); - } - - let compression = - CompressionConfig::configure(meta, lookup_inputs.clone(), message_schedule, extras); - - let message_schedule = - MessageScheduleConfig::configure(meta, lookup_inputs, message_schedule, extras); - - Table16Config { - lookup, - message_schedule, - compression, - } - } - - /// Loads the lookup table required by this chip into the circuit. - pub fn load( - config: Table16Config, - layouter: &mut impl Layouter, - ) -> Result<(), Error> { - SpreadTableChip::load(config.lookup, layouter) - } -} - -impl Sha256Instructions for Table16Chip { - type State = State; - type BlockWord = BlockWord; - - fn initialization_vector( - &self, - layouter: &mut impl Layouter, - ) -> Result { - self.config().compression.initialize_with_iv(layouter, IV) - } - - fn initialization( - &self, - layouter: &mut impl Layouter, - init_state: &Self::State, - ) -> Result { - self.config() - .compression - .initialize_with_state(layouter, init_state.clone()) - } - - // Given an initialized state and an input message block, compress the - // message block and return the final state. - fn compress( - &self, - layouter: &mut impl Layouter, - initialized_state: &Self::State, - input: [Self::BlockWord; super::BLOCK_SIZE], - ) -> Result { - let config = self.config(); - let (_, w_halves) = config.message_schedule.process(layouter, input)?; - config - .compression - .compress(layouter, initialized_state.clone(), w_halves) - } - - fn digest( - &self, - layouter: &mut impl Layouter, - state: &Self::State, - ) -> Result<[Self::BlockWord; super::DIGEST_SIZE], Error> { - // Copy the dense forms of the state variable chunks down to this gate. - // Reconstruct the 32-bit dense words. - self.config().compression.digest(layouter, state.clone()) - } -} - -/// Common assignment patterns used by Table16 regions. -trait Table16Assignment { - /// Assign cells for general spread computation used in sigma, ch, ch_neg, maj gates - #[allow(clippy::too_many_arguments)] - #[allow(clippy::type_complexity)] - fn assign_spread_outputs( - &self, - region: &mut Region<'_, pallas::Base>, - lookup: &SpreadInputs, - a_3: Column, - row: usize, - r_0_even: Value<[bool; 16]>, - r_0_odd: Value<[bool; 16]>, - r_1_even: Value<[bool; 16]>, - r_1_odd: Value<[bool; 16]>, - ) -> Result< - ( - (AssignedBits<16>, AssignedBits<16>), - (AssignedBits<16>, AssignedBits<16>), - ), - Error, - > { - // Lookup R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - let r_0_even = SpreadVar::with_lookup( - region, - lookup, - row - 1, - r_0_even.map(SpreadWord::<16, 32>::new), - )?; - let r_0_odd = - SpreadVar::with_lookup(region, lookup, row, r_0_odd.map(SpreadWord::<16, 32>::new))?; - let r_1_even = SpreadVar::with_lookup( - region, - lookup, - row + 1, - r_1_even.map(SpreadWord::<16, 32>::new), - )?; - let r_1_odd = SpreadVar::with_lookup( - region, - lookup, - row + 2, - r_1_odd.map(SpreadWord::<16, 32>::new), - )?; - - // Assign and copy R_1^{odd} - r_1_odd - .spread - .copy_advice(|| "Assign and copy R_1^{odd}", region, a_3, row)?; - - Ok(( - (r_0_even.dense, r_1_even.dense), - (r_0_odd.dense, r_1_odd.dense), - )) - } - - /// Assign outputs of sigma gates - #[allow(clippy::too_many_arguments)] - fn assign_sigma_outputs( - &self, - region: &mut Region<'_, pallas::Base>, - lookup: &SpreadInputs, - a_3: Column, - row: usize, - r_0_even: Value<[bool; 16]>, - r_0_odd: Value<[bool; 16]>, - r_1_even: Value<[bool; 16]>, - r_1_odd: Value<[bool; 16]>, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let (even, _odd) = self.assign_spread_outputs( - region, lookup, a_3, row, r_0_even, r_0_odd, r_1_even, r_1_odd, - )?; - - Ok(even) - } -} - -#[cfg(test)] -#[cfg(feature = "dev-graph")] -mod tests { - use super::super::{Sha256, BLOCK_SIZE}; - use super::{message_schedule::msg_schedule_test_input, Table16Chip, Table16Config}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use halo2curves::pasta::pallas; - - #[test] - fn print_sha256_circuit() { - use plotters::prelude::*; - struct MyCircuit {} - - impl Circuit for MyCircuit { - type Config = Table16Config; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - MyCircuit {} - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - Table16Chip::configure(meta) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let table16_chip = Table16Chip::construct(config.clone()); - Table16Chip::load(config, &mut layouter)?; - - // Test vector: "abc" - let test_input = msg_schedule_test_input(); - - // Create a message of length 31 blocks - let mut input = Vec::with_capacity(31 * BLOCK_SIZE); - for _ in 0..31 { - input.extend_from_slice(&test_input); - } - - Sha256::digest(table16_chip, layouter.namespace(|| "'abc' * 31"), &input)?; - - Ok(()) - } - } - - let root = - BitMapBackend::new("sha-256-table16-chip-layout.png", (1024, 3480)).into_drawing_area(); - root.fill(&WHITE).unwrap(); - let root = root - .titled("16-bit Table SHA-256 Chip", ("sans-serif", 60)) - .unwrap(); - - let circuit = MyCircuit {}; - halo2_proofs::dev::CircuitLayout::default() - .render::(17, &circuit, &root) - .unwrap(); - } -} diff --git a/halo2_gadgets/src/sha256/table16/compression.rs b/halo2_gadgets/src/sha256/table16/compression.rs deleted file mode 100644 index 62deb42937..0000000000 --- a/halo2_gadgets/src/sha256/table16/compression.rs +++ /dev/null @@ -1,1005 +0,0 @@ -use super::{ - super::DIGEST_SIZE, - util::{i2lebsp, lebs2ip}, - AssignedBits, BlockWord, SpreadInputs, SpreadVar, Table16Assignment, ROUNDS, STATE, -}; -use halo2_proofs::{ - circuit::{Layouter, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, Selector}, - poly::Rotation, -}; -use halo2curves::pasta::pallas; -use std::convert::TryInto; -use std::ops::Range; - -mod compression_gates; -mod compression_util; -mod subregion_digest; -mod subregion_initial; -mod subregion_main; - -use compression_gates::CompressionGate; - -pub trait UpperSigmaVar< - const A_LEN: usize, - const B_LEN: usize, - const C_LEN: usize, - const D_LEN: usize, -> -{ - fn spread_a(&self) -> Value<[bool; A_LEN]>; - fn spread_b(&self) -> Value<[bool; B_LEN]>; - fn spread_c(&self) -> Value<[bool; C_LEN]>; - fn spread_d(&self) -> Value<[bool; D_LEN]>; - - fn xor_upper_sigma(&self) -> Value<[bool; 64]> { - self.spread_a() - .zip(self.spread_b()) - .zip(self.spread_c()) - .zip(self.spread_d()) - .map(|(((a, b), c), d)| { - let xor_0 = b - .iter() - .chain(c.iter()) - .chain(d.iter()) - .chain(a.iter()) - .copied() - .collect::>(); - let xor_1 = c - .iter() - .chain(d.iter()) - .chain(a.iter()) - .chain(b.iter()) - .copied() - .collect::>(); - let xor_2 = d - .iter() - .chain(a.iter()) - .chain(b.iter()) - .chain(c.iter()) - .copied() - .collect::>(); - - let xor_0 = lebs2ip::<64>(&xor_0.try_into().unwrap()); - let xor_1 = lebs2ip::<64>(&xor_1.try_into().unwrap()); - let xor_2 = lebs2ip::<64>(&xor_2.try_into().unwrap()); - - i2lebsp(xor_0 + xor_1 + xor_2) - }) - } -} - -/// A variable that represents the `[A,B,C,D]` words of the SHA-256 internal state. -/// -/// The structure of this variable is influenced by the following factors: -/// - In `Σ_0(A)` we need `A` to be split into pieces `(a,b,c,d)` of lengths `(2,11,9,10)` -/// bits respectively (counting from the little end), as well as their spread forms. -/// - `Maj(A,B,C)` requires having the bits of each input in spread form. For `A` we can -/// reuse the pieces from `Σ_0(A)`. Since `B` and `C` are assigned from `A` and `B` -/// respectively in each round, we therefore also have the same pieces in earlier rows. -/// We align the columns to make it efficient to copy-constrain these forms where they -/// are needed. -#[derive(Clone, Debug)] -pub struct AbcdVar { - a: SpreadVar<2, 4>, - b: SpreadVar<11, 22>, - c_lo: SpreadVar<3, 6>, - c_mid: SpreadVar<3, 6>, - c_hi: SpreadVar<3, 6>, - d: SpreadVar<10, 20>, -} - -impl AbcdVar { - fn a_range() -> Range { - 0..2 - } - - fn b_range() -> Range { - 2..13 - } - - fn c_lo_range() -> Range { - 13..16 - } - - fn c_mid_range() -> Range { - 16..19 - } - - fn c_hi_range() -> Range { - 19..22 - } - - fn d_range() -> Range { - 22..32 - } - - fn pieces(val: u32) -> Vec> { - let val: [bool; 32] = i2lebsp(val.into()); - vec![ - val[Self::a_range()].to_vec(), - val[Self::b_range()].to_vec(), - val[Self::c_lo_range()].to_vec(), - val[Self::c_mid_range()].to_vec(), - val[Self::c_hi_range()].to_vec(), - val[Self::d_range()].to_vec(), - ] - } -} - -impl UpperSigmaVar<4, 22, 18, 20> for AbcdVar { - fn spread_a(&self) -> Value<[bool; 4]> { - self.a.spread.value().map(|v| v.0) - } - - fn spread_b(&self) -> Value<[bool; 22]> { - self.b.spread.value().map(|v| v.0) - } - - fn spread_c(&self) -> Value<[bool; 18]> { - self.c_lo - .spread - .value() - .zip(self.c_mid.spread.value()) - .zip(self.c_hi.spread.value()) - .map(|((c_lo, c_mid), c_hi)| { - c_lo.iter() - .chain(c_mid.iter()) - .chain(c_hi.iter()) - .copied() - .collect::>() - .try_into() - .unwrap() - }) - } - - fn spread_d(&self) -> Value<[bool; 20]> { - self.d.spread.value().map(|v| v.0) - } -} - -/// A variable that represents the `[E,F,G,H]` words of the SHA-256 internal state. -/// -/// The structure of this variable is influenced by the following factors: -/// - In `Σ_1(E)` we need `E` to be split into pieces `(a,b,c,d)` of lengths `(6,5,14,7)` -/// bits respectively (counting from the little end), as well as their spread forms. -/// - `Ch(E,F,G)` requires having the bits of each input in spread form. For `E` we can -/// reuse the pieces from `Σ_1(E)`. Since `F` and `G` are assigned from `E` and `F` -/// respectively in each round, we therefore also have the same pieces in earlier rows. -/// We align the columns to make it efficient to copy-constrain these forms where they -/// are needed. -#[derive(Clone, Debug)] -pub struct EfghVar { - a_lo: SpreadVar<3, 6>, - a_hi: SpreadVar<3, 6>, - b_lo: SpreadVar<2, 4>, - b_hi: SpreadVar<3, 6>, - c: SpreadVar<14, 28>, - d: SpreadVar<7, 14>, -} - -impl EfghVar { - fn a_lo_range() -> Range { - 0..3 - } - - fn a_hi_range() -> Range { - 3..6 - } - - fn b_lo_range() -> Range { - 6..8 - } - - fn b_hi_range() -> Range { - 8..11 - } - - fn c_range() -> Range { - 11..25 - } - - fn d_range() -> Range { - 25..32 - } - - fn pieces(val: u32) -> Vec> { - let val: [bool; 32] = i2lebsp(val.into()); - vec![ - val[Self::a_lo_range()].to_vec(), - val[Self::a_hi_range()].to_vec(), - val[Self::b_lo_range()].to_vec(), - val[Self::b_hi_range()].to_vec(), - val[Self::c_range()].to_vec(), - val[Self::d_range()].to_vec(), - ] - } -} - -impl UpperSigmaVar<12, 10, 28, 14> for EfghVar { - fn spread_a(&self) -> Value<[bool; 12]> { - self.a_lo - .spread - .value() - .zip(self.a_hi.spread.value()) - .map(|(a_lo, a_hi)| { - a_lo.iter() - .chain(a_hi.iter()) - .copied() - .collect::>() - .try_into() - .unwrap() - }) - } - - fn spread_b(&self) -> Value<[bool; 10]> { - self.b_lo - .spread - .value() - .zip(self.b_hi.spread.value()) - .map(|(b_lo, b_hi)| { - b_lo.iter() - .chain(b_hi.iter()) - .copied() - .collect::>() - .try_into() - .unwrap() - }) - } - - fn spread_c(&self) -> Value<[bool; 28]> { - self.c.spread.value().map(|v| v.0) - } - - fn spread_d(&self) -> Value<[bool; 14]> { - self.d.spread.value().map(|v| v.0) - } -} - -#[derive(Clone, Debug)] -pub struct RoundWordDense(AssignedBits<16>, AssignedBits<16>); - -impl From<(AssignedBits<16>, AssignedBits<16>)> for RoundWordDense { - fn from(halves: (AssignedBits<16>, AssignedBits<16>)) -> Self { - Self(halves.0, halves.1) - } -} - -impl RoundWordDense { - pub fn value(&self) -> Value { - self.0 - .value_u16() - .zip(self.1.value_u16()) - .map(|(lo, hi)| lo as u32 + (1 << 16) * hi as u32) - } -} - -#[derive(Clone, Debug)] -pub struct RoundWordSpread(AssignedBits<32>, AssignedBits<32>); - -impl From<(AssignedBits<32>, AssignedBits<32>)> for RoundWordSpread { - fn from(halves: (AssignedBits<32>, AssignedBits<32>)) -> Self { - Self(halves.0, halves.1) - } -} - -impl RoundWordSpread { - pub fn value(&self) -> Value { - self.0 - .value_u32() - .zip(self.1.value_u32()) - .map(|(lo, hi)| lo as u64 + (1 << 32) * hi as u64) - } -} - -#[derive(Clone, Debug)] -pub struct RoundWordA { - pieces: Option, - dense_halves: RoundWordDense, - spread_halves: Option, -} - -impl RoundWordA { - pub fn new( - pieces: AbcdVar, - dense_halves: RoundWordDense, - spread_halves: RoundWordSpread, - ) -> Self { - RoundWordA { - pieces: Some(pieces), - dense_halves, - spread_halves: Some(spread_halves), - } - } - - pub fn new_dense(dense_halves: RoundWordDense) -> Self { - RoundWordA { - pieces: None, - dense_halves, - spread_halves: None, - } - } -} - -#[derive(Clone, Debug)] -pub struct RoundWordE { - pieces: Option, - dense_halves: RoundWordDense, - spread_halves: Option, -} - -impl RoundWordE { - pub fn new( - pieces: EfghVar, - dense_halves: RoundWordDense, - spread_halves: RoundWordSpread, - ) -> Self { - RoundWordE { - pieces: Some(pieces), - dense_halves, - spread_halves: Some(spread_halves), - } - } - - pub fn new_dense(dense_halves: RoundWordDense) -> Self { - RoundWordE { - pieces: None, - dense_halves, - spread_halves: None, - } - } -} - -#[derive(Clone, Debug)] -pub struct RoundWord { - dense_halves: RoundWordDense, - spread_halves: RoundWordSpread, -} - -impl RoundWord { - pub fn new(dense_halves: RoundWordDense, spread_halves: RoundWordSpread) -> Self { - RoundWord { - dense_halves, - spread_halves, - } - } -} - -/// The internal state for SHA-256. -#[derive(Clone, Debug)] -pub struct State { - a: Option, - b: Option, - c: Option, - d: Option, - e: Option, - f: Option, - g: Option, - h: Option, -} - -impl State { - #[allow(clippy::many_single_char_names)] - #[allow(clippy::too_many_arguments)] - pub fn new( - a: StateWord, - b: StateWord, - c: StateWord, - d: StateWord, - e: StateWord, - f: StateWord, - g: StateWord, - h: StateWord, - ) -> Self { - State { - a: Some(a), - b: Some(b), - c: Some(c), - d: Some(d), - e: Some(e), - f: Some(f), - g: Some(g), - h: Some(h), - } - } - - pub fn empty_state() -> Self { - State { - a: None, - b: None, - c: None, - d: None, - e: None, - f: None, - g: None, - h: None, - } - } -} - -#[derive(Clone, Debug)] -pub enum StateWord { - A(RoundWordA), - B(RoundWord), - C(RoundWord), - D(RoundWordDense), - E(RoundWordE), - F(RoundWord), - G(RoundWord), - H(RoundWordDense), -} - -#[derive(Clone, Debug)] -pub(super) struct CompressionConfig { - lookup: SpreadInputs, - message_schedule: Column, - extras: [Column; 6], - - s_ch: Selector, - s_ch_neg: Selector, - s_maj: Selector, - s_h_prime: Selector, - s_a_new: Selector, - s_e_new: Selector, - - s_upper_sigma_0: Selector, - s_upper_sigma_1: Selector, - - // Decomposition gate for AbcdVar - s_decompose_abcd: Selector, - // Decomposition gate for EfghVar - s_decompose_efgh: Selector, - - s_digest: Selector, -} - -impl Table16Assignment for CompressionConfig {} - -impl CompressionConfig { - pub(super) fn configure( - meta: &mut ConstraintSystem, - lookup: SpreadInputs, - message_schedule: Column, - extras: [Column; 6], - ) -> Self { - let s_ch = meta.selector(); - let s_ch_neg = meta.selector(); - let s_maj = meta.selector(); - let s_h_prime = meta.selector(); - let s_a_new = meta.selector(); - let s_e_new = meta.selector(); - - let s_upper_sigma_0 = meta.selector(); - let s_upper_sigma_1 = meta.selector(); - - // Decomposition gate for AbcdVar - let s_decompose_abcd = meta.selector(); - // Decomposition gate for EfghVar - let s_decompose_efgh = meta.selector(); - - let s_digest = meta.selector(); - - // Rename these here for ease of matching the gates to the specification. - let a_0 = lookup.tag; - let a_1 = lookup.dense; - let a_2 = lookup.spread; - let a_3 = extras[0]; - let a_4 = extras[1]; - let a_5 = message_schedule; - let a_6 = extras[2]; - let a_7 = extras[3]; - let a_8 = extras[4]; - let a_9 = extras[5]; - - // Decompose `A,B,C,D` words into (2, 11, 9, 10)-bit chunks. - // `c` is split into (3, 3, 3)-bit c_lo, c_mid, c_hi. - meta.create_gate("decompose ABCD", |meta| { - let s_decompose_abcd = meta.query_selector(s_decompose_abcd); - let a = meta.query_advice(a_3, Rotation::next()); // 2-bit chunk - let spread_a = meta.query_advice(a_4, Rotation::next()); - let b = meta.query_advice(a_1, Rotation::cur()); // 11-bit chunk - let spread_b = meta.query_advice(a_2, Rotation::cur()); - let tag_b = meta.query_advice(a_0, Rotation::cur()); - let c_lo = meta.query_advice(a_3, Rotation::cur()); // 3-bit chunk - let spread_c_lo = meta.query_advice(a_4, Rotation::cur()); - let c_mid = meta.query_advice(a_5, Rotation::cur()); // 3-bit chunk - let spread_c_mid = meta.query_advice(a_6, Rotation::cur()); - let c_hi = meta.query_advice(a_5, Rotation::next()); // 3-bit chunk - let spread_c_hi = meta.query_advice(a_6, Rotation::next()); - let d = meta.query_advice(a_1, Rotation::next()); // 7-bit chunk - let spread_d = meta.query_advice(a_2, Rotation::next()); - let tag_d = meta.query_advice(a_0, Rotation::next()); - let word_lo = meta.query_advice(a_7, Rotation::cur()); - let spread_word_lo = meta.query_advice(a_8, Rotation::cur()); - let word_hi = meta.query_advice(a_7, Rotation::next()); - let spread_word_hi = meta.query_advice(a_8, Rotation::next()); - - CompressionGate::s_decompose_abcd( - s_decompose_abcd, - a, - spread_a, - b, - spread_b, - tag_b, - c_lo, - spread_c_lo, - c_mid, - spread_c_mid, - c_hi, - spread_c_hi, - d, - spread_d, - tag_d, - word_lo, - spread_word_lo, - word_hi, - spread_word_hi, - ) - }); - - // Decompose `E,F,G,H` words into (6, 5, 14, 7)-bit chunks. - // `a` is split into (3, 3)-bit a_lo, a_hi - // `b` is split into (2, 3)-bit b_lo, b_hi - meta.create_gate("Decompose EFGH", |meta| { - let s_decompose_efgh = meta.query_selector(s_decompose_efgh); - let a_lo = meta.query_advice(a_3, Rotation::next()); // 3-bit chunk - let spread_a_lo = meta.query_advice(a_4, Rotation::next()); - let a_hi = meta.query_advice(a_5, Rotation::next()); // 3-bit chunk - let spread_a_hi = meta.query_advice(a_6, Rotation::next()); - let b_lo = meta.query_advice(a_3, Rotation::cur()); // 2-bit chunk - let spread_b_lo = meta.query_advice(a_4, Rotation::cur()); - let b_hi = meta.query_advice(a_5, Rotation::cur()); // 3-bit chunk - let spread_b_hi = meta.query_advice(a_6, Rotation::cur()); - let c = meta.query_advice(a_1, Rotation::next()); // 14-bit chunk - let spread_c = meta.query_advice(a_2, Rotation::next()); - let tag_c = meta.query_advice(a_0, Rotation::next()); - let d = meta.query_advice(a_1, Rotation::cur()); // 7-bit chunk - let spread_d = meta.query_advice(a_2, Rotation::cur()); - let tag_d = meta.query_advice(a_0, Rotation::cur()); - let word_lo = meta.query_advice(a_7, Rotation::cur()); - let spread_word_lo = meta.query_advice(a_8, Rotation::cur()); - let word_hi = meta.query_advice(a_7, Rotation::next()); - let spread_word_hi = meta.query_advice(a_8, Rotation::next()); - - CompressionGate::s_decompose_efgh( - s_decompose_efgh, - a_lo, - spread_a_lo, - a_hi, - spread_a_hi, - b_lo, - spread_b_lo, - b_hi, - spread_b_hi, - c, - spread_c, - tag_c, - d, - spread_d, - tag_d, - word_lo, - spread_word_lo, - word_hi, - spread_word_hi, - ) - }); - - // s_upper_sigma_0 on abcd words - // (2, 11, 9, 10)-bit chunks - meta.create_gate("s_upper_sigma_0", |meta| { - let s_upper_sigma_0 = meta.query_selector(s_upper_sigma_0); - let spread_r0_even = meta.query_advice(a_2, Rotation::prev()); - let spread_r0_odd = meta.query_advice(a_2, Rotation::cur()); - let spread_r1_even = meta.query_advice(a_2, Rotation::next()); - let spread_r1_odd = meta.query_advice(a_3, Rotation::cur()); - - let spread_a = meta.query_advice(a_3, Rotation::next()); - let spread_b = meta.query_advice(a_5, Rotation::cur()); - let spread_c_lo = meta.query_advice(a_3, Rotation::prev()); - let spread_c_mid = meta.query_advice(a_4, Rotation::prev()); - let spread_c_hi = meta.query_advice(a_4, Rotation::next()); - let spread_d = meta.query_advice(a_4, Rotation::cur()); - - CompressionGate::s_upper_sigma_0( - s_upper_sigma_0, - spread_r0_even, - spread_r0_odd, - spread_r1_even, - spread_r1_odd, - spread_a, - spread_b, - spread_c_lo, - spread_c_mid, - spread_c_hi, - spread_d, - ) - }); - - // s_upper_sigma_1 on efgh words - // (6, 5, 14, 7)-bit chunks - meta.create_gate("s_upper_sigma_1", |meta| { - let s_upper_sigma_1 = meta.query_selector(s_upper_sigma_1); - let spread_r0_even = meta.query_advice(a_2, Rotation::prev()); - let spread_r0_odd = meta.query_advice(a_2, Rotation::cur()); - let spread_r1_even = meta.query_advice(a_2, Rotation::next()); - let spread_r1_odd = meta.query_advice(a_3, Rotation::cur()); - let spread_a_lo = meta.query_advice(a_3, Rotation::next()); - let spread_a_hi = meta.query_advice(a_4, Rotation::next()); - let spread_b_lo = meta.query_advice(a_3, Rotation::prev()); - let spread_b_hi = meta.query_advice(a_4, Rotation::prev()); - let spread_c = meta.query_advice(a_5, Rotation::cur()); - let spread_d = meta.query_advice(a_4, Rotation::cur()); - - CompressionGate::s_upper_sigma_1( - s_upper_sigma_1, - spread_r0_even, - spread_r0_odd, - spread_r1_even, - spread_r1_odd, - spread_a_lo, - spread_a_hi, - spread_b_lo, - spread_b_hi, - spread_c, - spread_d, - ) - }); - - // s_ch on efgh words - // First part of choice gate on (E, F, G), E ∧ F - meta.create_gate("s_ch", |meta| { - let s_ch = meta.query_selector(s_ch); - let spread_p0_even = meta.query_advice(a_2, Rotation::prev()); - let spread_p0_odd = meta.query_advice(a_2, Rotation::cur()); - let spread_p1_even = meta.query_advice(a_2, Rotation::next()); - let spread_p1_odd = meta.query_advice(a_3, Rotation::cur()); - let spread_e_lo = meta.query_advice(a_3, Rotation::prev()); - let spread_e_hi = meta.query_advice(a_4, Rotation::prev()); - let spread_f_lo = meta.query_advice(a_3, Rotation::next()); - let spread_f_hi = meta.query_advice(a_4, Rotation::next()); - - CompressionGate::s_ch( - s_ch, - spread_p0_even, - spread_p0_odd, - spread_p1_even, - spread_p1_odd, - spread_e_lo, - spread_e_hi, - spread_f_lo, - spread_f_hi, - ) - }); - - // s_ch_neg on efgh words - // Second part of Choice gate on (E, F, G), ¬E ∧ G - meta.create_gate("s_ch_neg", |meta| { - let s_ch_neg = meta.query_selector(s_ch_neg); - let spread_q0_even = meta.query_advice(a_2, Rotation::prev()); - let spread_q0_odd = meta.query_advice(a_2, Rotation::cur()); - let spread_q1_even = meta.query_advice(a_2, Rotation::next()); - let spread_q1_odd = meta.query_advice(a_3, Rotation::cur()); - let spread_e_lo = meta.query_advice(a_5, Rotation::prev()); - let spread_e_hi = meta.query_advice(a_5, Rotation::cur()); - let spread_e_neg_lo = meta.query_advice(a_3, Rotation::prev()); - let spread_e_neg_hi = meta.query_advice(a_4, Rotation::prev()); - let spread_g_lo = meta.query_advice(a_3, Rotation::next()); - let spread_g_hi = meta.query_advice(a_4, Rotation::next()); - - CompressionGate::s_ch_neg( - s_ch_neg, - spread_q0_even, - spread_q0_odd, - spread_q1_even, - spread_q1_odd, - spread_e_lo, - spread_e_hi, - spread_e_neg_lo, - spread_e_neg_hi, - spread_g_lo, - spread_g_hi, - ) - }); - - // s_maj on abcd words - meta.create_gate("s_maj", |meta| { - let s_maj = meta.query_selector(s_maj); - let spread_m0_even = meta.query_advice(a_2, Rotation::prev()); - let spread_m0_odd = meta.query_advice(a_2, Rotation::cur()); - let spread_m1_even = meta.query_advice(a_2, Rotation::next()); - let spread_m1_odd = meta.query_advice(a_3, Rotation::cur()); - let spread_a_lo = meta.query_advice(a_4, Rotation::prev()); - let spread_a_hi = meta.query_advice(a_5, Rotation::prev()); - let spread_b_lo = meta.query_advice(a_4, Rotation::cur()); - let spread_b_hi = meta.query_advice(a_5, Rotation::cur()); - let spread_c_lo = meta.query_advice(a_4, Rotation::next()); - let spread_c_hi = meta.query_advice(a_5, Rotation::next()); - - CompressionGate::s_maj( - s_maj, - spread_m0_even, - spread_m0_odd, - spread_m1_even, - spread_m1_odd, - spread_a_lo, - spread_a_hi, - spread_b_lo, - spread_b_hi, - spread_c_lo, - spread_c_hi, - ) - }); - - // s_h_prime to compute H' = H + Ch(E, F, G) + s_upper_sigma_1(E) + K + W - meta.create_gate("s_h_prime", |meta| { - let s_h_prime = meta.query_selector(s_h_prime); - let h_prime_lo = meta.query_advice(a_7, Rotation::next()); - let h_prime_hi = meta.query_advice(a_8, Rotation::next()); - let h_prime_carry = meta.query_advice(a_9, Rotation::next()); - let sigma_e_lo = meta.query_advice(a_4, Rotation::cur()); - let sigma_e_hi = meta.query_advice(a_5, Rotation::cur()); - let ch_lo = meta.query_advice(a_1, Rotation::cur()); - let ch_hi = meta.query_advice(a_6, Rotation::next()); - let ch_neg_lo = meta.query_advice(a_5, Rotation::prev()); - let ch_neg_hi = meta.query_advice(a_5, Rotation::next()); - let h_lo = meta.query_advice(a_7, Rotation::prev()); - let h_hi = meta.query_advice(a_7, Rotation::cur()); - let k_lo = meta.query_advice(a_6, Rotation::prev()); - let k_hi = meta.query_advice(a_6, Rotation::cur()); - let w_lo = meta.query_advice(a_8, Rotation::prev()); - let w_hi = meta.query_advice(a_8, Rotation::cur()); - - CompressionGate::s_h_prime( - s_h_prime, - h_prime_lo, - h_prime_hi, - h_prime_carry, - sigma_e_lo, - sigma_e_hi, - ch_lo, - ch_hi, - ch_neg_lo, - ch_neg_hi, - h_lo, - h_hi, - k_lo, - k_hi, - w_lo, - w_hi, - ) - }); - - // s_a_new - meta.create_gate("s_a_new", |meta| { - let s_a_new = meta.query_selector(s_a_new); - let a_new_lo = meta.query_advice(a_8, Rotation::cur()); - let a_new_hi = meta.query_advice(a_8, Rotation::next()); - let a_new_carry = meta.query_advice(a_9, Rotation::cur()); - let sigma_a_lo = meta.query_advice(a_6, Rotation::cur()); - let sigma_a_hi = meta.query_advice(a_6, Rotation::next()); - let maj_abc_lo = meta.query_advice(a_1, Rotation::cur()); - let maj_abc_hi = meta.query_advice(a_3, Rotation::prev()); - let h_prime_lo = meta.query_advice(a_7, Rotation::prev()); - let h_prime_hi = meta.query_advice(a_8, Rotation::prev()); - - CompressionGate::s_a_new( - s_a_new, - a_new_lo, - a_new_hi, - a_new_carry, - sigma_a_lo, - sigma_a_hi, - maj_abc_lo, - maj_abc_hi, - h_prime_lo, - h_prime_hi, - ) - }); - - // s_e_new - meta.create_gate("s_e_new", |meta| { - let s_e_new = meta.query_selector(s_e_new); - let e_new_lo = meta.query_advice(a_8, Rotation::cur()); - let e_new_hi = meta.query_advice(a_8, Rotation::next()); - let e_new_carry = meta.query_advice(a_9, Rotation::next()); - let d_lo = meta.query_advice(a_7, Rotation::cur()); - let d_hi = meta.query_advice(a_7, Rotation::next()); - let h_prime_lo = meta.query_advice(a_7, Rotation::prev()); - let h_prime_hi = meta.query_advice(a_8, Rotation::prev()); - - CompressionGate::s_e_new( - s_e_new, - e_new_lo, - e_new_hi, - e_new_carry, - d_lo, - d_hi, - h_prime_lo, - h_prime_hi, - ) - }); - - // s_digest for final round - meta.create_gate("s_digest", |meta| { - let s_digest = meta.query_selector(s_digest); - let lo_0 = meta.query_advice(a_3, Rotation::cur()); - let hi_0 = meta.query_advice(a_4, Rotation::cur()); - let word_0 = meta.query_advice(a_5, Rotation::cur()); - let lo_1 = meta.query_advice(a_6, Rotation::cur()); - let hi_1 = meta.query_advice(a_7, Rotation::cur()); - let word_1 = meta.query_advice(a_8, Rotation::cur()); - let lo_2 = meta.query_advice(a_3, Rotation::next()); - let hi_2 = meta.query_advice(a_4, Rotation::next()); - let word_2 = meta.query_advice(a_5, Rotation::next()); - let lo_3 = meta.query_advice(a_6, Rotation::next()); - let hi_3 = meta.query_advice(a_7, Rotation::next()); - let word_3 = meta.query_advice(a_8, Rotation::next()); - - CompressionGate::s_digest( - s_digest, lo_0, hi_0, word_0, lo_1, hi_1, word_1, lo_2, hi_2, word_2, lo_3, hi_3, - word_3, - ) - }); - - CompressionConfig { - lookup, - message_schedule, - extras, - s_ch, - s_ch_neg, - s_maj, - s_h_prime, - s_a_new, - s_e_new, - s_upper_sigma_0, - s_upper_sigma_1, - s_decompose_abcd, - s_decompose_efgh, - s_digest, - } - } - - /// Initialize compression with a constant Initialization Vector of 32-byte words. - /// Returns an initialized state. - pub(super) fn initialize_with_iv( - &self, - layouter: &mut impl Layouter, - init_state: [u32; STATE], - ) -> Result { - let mut new_state = State::empty_state(); - layouter.assign_region( - || "initialize_with_iv", - |mut region| { - new_state = self.initialize_iv(&mut region, init_state)?; - Ok(()) - }, - )?; - Ok(new_state) - } - - /// Initialize compression with some initialized state. This could be a state - /// output from a previous compression round. - pub(super) fn initialize_with_state( - &self, - layouter: &mut impl Layouter, - init_state: State, - ) -> Result { - let mut new_state = State::empty_state(); - layouter.assign_region( - || "initialize_with_state", - |mut region| { - new_state = self.initialize_state(&mut region, init_state.clone())?; - Ok(()) - }, - )?; - Ok(new_state) - } - - /// Given an initialized state and a message schedule, perform 64 compression rounds. - pub(super) fn compress( - &self, - layouter: &mut impl Layouter, - initialized_state: State, - w_halves: [(AssignedBits<16>, AssignedBits<16>); ROUNDS], - ) -> Result { - let mut state = State::empty_state(); - layouter.assign_region( - || "compress", - |mut region| { - state = initialized_state.clone(); - for (idx, w_halves) in w_halves.iter().enumerate() { - state = self.assign_round(&mut region, idx.into(), state.clone(), w_halves)?; - } - Ok(()) - }, - )?; - Ok(state) - } - - /// After the final round, convert the state into the final digest. - pub(super) fn digest( - &self, - layouter: &mut impl Layouter, - state: State, - ) -> Result<[BlockWord; DIGEST_SIZE], Error> { - let mut digest = [BlockWord(Value::known(0)); DIGEST_SIZE]; - layouter.assign_region( - || "digest", - |mut region| { - digest = self.assign_digest(&mut region, state.clone())?; - - Ok(()) - }, - )?; - Ok(digest) - } -} - -#[cfg(test)] -mod tests { - use super::super::{ - super::BLOCK_SIZE, msg_schedule_test_input, BlockWord, Table16Chip, Table16Config, IV, - }; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use halo2curves::pasta::pallas; - - #[test] - fn compress() { - struct MyCircuit {} - - impl Circuit for MyCircuit { - type Config = Table16Config; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - MyCircuit {} - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - Table16Chip::configure(meta) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - Table16Chip::load(config.clone(), &mut layouter)?; - - // Test vector: "abc" - let input: [BlockWord; BLOCK_SIZE] = msg_schedule_test_input(); - - let (_, w_halves) = config.message_schedule.process(&mut layouter, input)?; - - let compression = config.compression.clone(); - let initial_state = compression.initialize_with_iv(&mut layouter, IV)?; - - let state = config - .compression - .compress(&mut layouter, initial_state, w_halves)?; - - let digest = config.compression.digest(&mut layouter, state)?; - for (idx, digest_word) in digest.iter().enumerate() { - digest_word.0.assert_if_known(|digest_word| { - (*digest_word as u64 + IV[idx] as u64) as u32 - == super::compression_util::COMPRESSION_OUTPUT[idx] - }); - } - - Ok(()) - } - } - - let circuit: MyCircuit = MyCircuit {}; - - let prover = match MockProver::::run(17, &circuit, vec![]) { - Ok(prover) => prover, - Err(e) => panic!("{:?}", e), - }; - assert_eq!(prover.verify(), Ok(())); - } -} diff --git a/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs b/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs deleted file mode 100644 index e22a10210c..0000000000 --- a/halo2_gadgets/src/sha256/table16/compression/compression_gates.rs +++ /dev/null @@ -1,444 +0,0 @@ -use super::super::{util::*, Gate}; -use halo2_proofs::{ - arithmetic::FieldExt, - plonk::{Constraint, Constraints, Expression}, -}; -use std::marker::PhantomData; - -pub struct CompressionGate(PhantomData); - -impl CompressionGate { - fn ones() -> Expression { - Expression::Constant(F::one()) - } - - // Decompose `A,B,C,D` words - // (2, 11, 9, 10)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_decompose_abcd( - s_decompose_abcd: Expression, - a: Expression, - spread_a: Expression, - b: Expression, - spread_b: Expression, - tag_b: Expression, - c_lo: Expression, - spread_c_lo: Expression, - c_mid: Expression, - spread_c_mid: Expression, - c_hi: Expression, - spread_c_hi: Expression, - d: Expression, - spread_d: Expression, - tag_d: Expression, - word_lo: Expression, - spread_word_lo: Expression, - word_hi: Expression, - spread_word_hi: Expression, - ) -> Constraints< - F, - (&'static str, Expression), - impl Iterator)>, - > { - let check_spread_and_range = - Gate::three_bit_spread_and_range(c_lo.clone(), spread_c_lo.clone()) - .chain(Gate::three_bit_spread_and_range( - c_mid.clone(), - spread_c_mid.clone(), - )) - .chain(Gate::three_bit_spread_and_range( - c_hi.clone(), - spread_c_hi.clone(), - )) - .chain(Gate::two_bit_spread_and_range(a.clone(), spread_a.clone())); - let range_check_tag_b = Gate::range_check(tag_b, 0, 2); - let range_check_tag_d = Gate::range_check(tag_d, 0, 1); - let dense_check = a - + b * F::from(1 << 2) - + c_lo * F::from(1 << 13) - + c_mid * F::from(1 << 16) - + c_hi * F::from(1 << 19) - + d * F::from(1 << 22) - + word_lo * (-F::one()) - + word_hi * F::from(1 << 16) * (-F::one()); - let spread_check = spread_a - + spread_b * F::from(1 << 4) - + spread_c_lo * F::from(1 << 26) - + spread_c_mid * F::from(1 << 32) - + spread_c_hi * F::from(1 << 38) - + spread_d * F::from(1 << 44) - + spread_word_lo * (-F::one()) - + spread_word_hi * F::from(1 << 32) * (-F::one()); - - Constraints::with_selector( - s_decompose_abcd, - check_spread_and_range - .chain(Some(("range_check_tag_b", range_check_tag_b))) - .chain(Some(("range_check_tag_d", range_check_tag_d))) - .chain(Some(("dense_check", dense_check))) - .chain(Some(("spread_check", spread_check))), - ) - } - - // Decompose `E,F,G,H` words - // (6, 5, 14, 7)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_decompose_efgh( - s_decompose_efgh: Expression, - a_lo: Expression, - spread_a_lo: Expression, - a_hi: Expression, - spread_a_hi: Expression, - b_lo: Expression, - spread_b_lo: Expression, - b_hi: Expression, - spread_b_hi: Expression, - c: Expression, - spread_c: Expression, - tag_c: Expression, - d: Expression, - spread_d: Expression, - tag_d: Expression, - word_lo: Expression, - spread_word_lo: Expression, - word_hi: Expression, - spread_word_hi: Expression, - ) -> Constraints< - F, - (&'static str, Expression), - impl Iterator)>, - > { - let check_spread_and_range = - Gate::three_bit_spread_and_range(a_lo.clone(), spread_a_lo.clone()) - .chain(Gate::three_bit_spread_and_range( - a_hi.clone(), - spread_a_hi.clone(), - )) - .chain(Gate::three_bit_spread_and_range( - b_hi.clone(), - spread_b_hi.clone(), - )) - .chain(Gate::two_bit_spread_and_range( - b_lo.clone(), - spread_b_lo.clone(), - )); - let range_check_tag_c = Gate::range_check(tag_c, 0, 4); - let range_check_tag_d = Gate::range_check(tag_d, 0, 0); - let dense_check = a_lo - + a_hi * F::from(1 << 3) - + b_lo * F::from(1 << 6) - + b_hi * F::from(1 << 8) - + c * F::from(1 << 11) - + d * F::from(1 << 25) - + word_lo * (-F::one()) - + word_hi * F::from(1 << 16) * (-F::one()); - let spread_check = spread_a_lo - + spread_a_hi * F::from(1 << 6) - + spread_b_lo * F::from(1 << 12) - + spread_b_hi * F::from(1 << 16) - + spread_c * F::from(1 << 22) - + spread_d * F::from(1 << 50) - + spread_word_lo * (-F::one()) - + spread_word_hi * F::from(1 << 32) * (-F::one()); - - Constraints::with_selector( - s_decompose_efgh, - check_spread_and_range - .chain(Some(("range_check_tag_c", range_check_tag_c))) - .chain(Some(("range_check_tag_d", range_check_tag_d))) - .chain(Some(("dense_check", dense_check))) - .chain(Some(("spread_check", spread_check))), - ) - } - - // s_upper_sigma_0 on abcd words - // (2, 11, 9, 10)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_upper_sigma_0( - s_upper_sigma_0: Expression, - spread_r0_even: Expression, - spread_r0_odd: Expression, - spread_r1_even: Expression, - spread_r1_odd: Expression, - spread_a: Expression, - spread_b: Expression, - spread_c_lo: Expression, - spread_c_mid: Expression, - spread_c_hi: Expression, - spread_d: Expression, - ) -> Option<(&'static str, Expression)> { - let spread_witness = spread_r0_even - + spread_r0_odd * F::from(2) - + (spread_r1_even + spread_r1_odd * F::from(2)) * F::from(1 << 32); - let xor_0 = spread_b.clone() - + spread_c_lo.clone() * F::from(1 << 22) - + spread_c_mid.clone() * F::from(1 << 28) - + spread_c_hi.clone() * F::from(1 << 34) - + spread_d.clone() * F::from(1 << 40) - + spread_a.clone() * F::from(1 << 60); - let xor_1 = spread_c_lo.clone() - + spread_c_mid.clone() * F::from(1 << 6) - + spread_c_hi.clone() * F::from(1 << 12) - + spread_d.clone() * F::from(1 << 18) - + spread_a.clone() * F::from(1 << 38) - + spread_b.clone() * F::from(1 << 42); - let xor_2 = spread_d - + spread_a * F::from(1 << 20) - + spread_b * F::from(1 << 24) - + spread_c_lo * F::from(1 << 46) - + spread_c_mid * F::from(1 << 52) - + spread_c_hi * F::from(1 << 58); - let xor = xor_0 + xor_1 + xor_2; - let check = spread_witness + (xor * -F::one()); - - Some(("s_upper_sigma_0", s_upper_sigma_0 * check)) - } - - // s_upper_sigma_1 on efgh words - // (6, 5, 14, 7)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_upper_sigma_1( - s_upper_sigma_1: Expression, - spread_r0_even: Expression, - spread_r0_odd: Expression, - spread_r1_even: Expression, - spread_r1_odd: Expression, - spread_a_lo: Expression, - spread_a_hi: Expression, - spread_b_lo: Expression, - spread_b_hi: Expression, - spread_c: Expression, - spread_d: Expression, - ) -> Option<(&'static str, Expression)> { - let spread_witness = spread_r0_even - + spread_r0_odd * F::from(2) - + (spread_r1_even + spread_r1_odd * F::from(2)) * F::from(1 << 32); - - let xor_0 = spread_b_lo.clone() - + spread_b_hi.clone() * F::from(1 << 4) - + spread_c.clone() * F::from(1 << 10) - + spread_d.clone() * F::from(1 << 38) - + spread_a_lo.clone() * F::from(1 << 52) - + spread_a_hi.clone() * F::from(1 << 58); - let xor_1 = spread_c.clone() - + spread_d.clone() * F::from(1 << 28) - + spread_a_lo.clone() * F::from(1 << 42) - + spread_a_hi.clone() * F::from(1 << 48) - + spread_b_lo.clone() * F::from(1 << 54) - + spread_b_hi.clone() * F::from(1 << 58); - let xor_2 = spread_d - + spread_a_lo * F::from(1 << 14) - + spread_a_hi * F::from(1 << 20) - + spread_b_lo * F::from(1 << 26) - + spread_b_hi * F::from(1 << 30) - + spread_c * F::from(1 << 36); - let xor = xor_0 + xor_1 + xor_2; - let check = spread_witness + (xor * -F::one()); - - Some(("s_upper_sigma_1", s_upper_sigma_1 * check)) - } - - // First part of choice gate on (E, F, G), E ∧ F - #[allow(clippy::too_many_arguments)] - pub fn s_ch( - s_ch: Expression, - spread_p0_even: Expression, - spread_p0_odd: Expression, - spread_p1_even: Expression, - spread_p1_odd: Expression, - spread_e_lo: Expression, - spread_e_hi: Expression, - spread_f_lo: Expression, - spread_f_hi: Expression, - ) -> Option<(&'static str, Expression)> { - let lhs_lo = spread_e_lo + spread_f_lo; - let lhs_hi = spread_e_hi + spread_f_hi; - let lhs = lhs_lo + lhs_hi * F::from(1 << 32); - - let rhs_even = spread_p0_even + spread_p1_even * F::from(1 << 32); - let rhs_odd = spread_p0_odd + spread_p1_odd * F::from(1 << 32); - let rhs = rhs_even + rhs_odd * F::from(2); - - let check = lhs + rhs * -F::one(); - - Some(("s_ch", s_ch * check)) - } - - // Second part of Choice gate on (E, F, G), ¬E ∧ G - #[allow(clippy::too_many_arguments)] - pub fn s_ch_neg( - s_ch_neg: Expression, - spread_q0_even: Expression, - spread_q0_odd: Expression, - spread_q1_even: Expression, - spread_q1_odd: Expression, - spread_e_lo: Expression, - spread_e_hi: Expression, - spread_e_neg_lo: Expression, - spread_e_neg_hi: Expression, - spread_g_lo: Expression, - spread_g_hi: Expression, - ) -> Constraints< - F, - (&'static str, Expression), - impl Iterator)>, - > { - let neg_check = { - let evens = Self::ones() * F::from(MASK_EVEN_32 as u64); - // evens - spread_e_lo = spread_e_neg_lo - let lo_check = spread_e_neg_lo.clone() + spread_e_lo + (evens.clone() * (-F::one())); - // evens - spread_e_hi = spread_e_neg_hi - let hi_check = spread_e_neg_hi.clone() + spread_e_hi + (evens * (-F::one())); - - std::iter::empty() - .chain(Some(("lo_check", lo_check))) - .chain(Some(("hi_check", hi_check))) - }; - - let lhs_lo = spread_e_neg_lo + spread_g_lo; - let lhs_hi = spread_e_neg_hi + spread_g_hi; - let lhs = lhs_lo + lhs_hi * F::from(1 << 32); - - let rhs_even = spread_q0_even + spread_q1_even * F::from(1 << 32); - let rhs_odd = spread_q0_odd + spread_q1_odd * F::from(1 << 32); - let rhs = rhs_even + rhs_odd * F::from(2); - - Constraints::with_selector(s_ch_neg, neg_check.chain(Some(("s_ch_neg", lhs - rhs)))) - } - - // Majority gate on (A, B, C) - #[allow(clippy::too_many_arguments)] - pub fn s_maj( - s_maj: Expression, - spread_m_0_even: Expression, - spread_m_0_odd: Expression, - spread_m_1_even: Expression, - spread_m_1_odd: Expression, - spread_a_lo: Expression, - spread_a_hi: Expression, - spread_b_lo: Expression, - spread_b_hi: Expression, - spread_c_lo: Expression, - spread_c_hi: Expression, - ) -> Option<(&'static str, Expression)> { - let maj_even = spread_m_0_even + spread_m_1_even * F::from(1 << 32); - let maj_odd = spread_m_0_odd + spread_m_1_odd * F::from(1 << 32); - let maj = maj_even + maj_odd * F::from(2); - - let a = spread_a_lo + spread_a_hi * F::from(1 << 32); - let b = spread_b_lo + spread_b_hi * F::from(1 << 32); - let c = spread_c_lo + spread_c_hi * F::from(1 << 32); - let sum = a + b + c; - - Some(("maj", s_maj * (sum - maj))) - } - - // s_h_prime to get H' = H + Ch(E, F, G) + s_upper_sigma_1(E) + K + W - #[allow(clippy::too_many_arguments)] - pub fn s_h_prime( - s_h_prime: Expression, - h_prime_lo: Expression, - h_prime_hi: Expression, - h_prime_carry: Expression, - sigma_e_lo: Expression, - sigma_e_hi: Expression, - ch_lo: Expression, - ch_hi: Expression, - ch_neg_lo: Expression, - ch_neg_hi: Expression, - h_lo: Expression, - h_hi: Expression, - k_lo: Expression, - k_hi: Expression, - w_lo: Expression, - w_hi: Expression, - ) -> Option<(&'static str, Expression)> { - let lo = h_lo + ch_lo + ch_neg_lo + sigma_e_lo + k_lo + w_lo; - let hi = h_hi + ch_hi + ch_neg_hi + sigma_e_hi + k_hi + w_hi; - - let sum = lo + hi * F::from(1 << 16); - let h_prime = h_prime_lo + h_prime_hi * F::from(1 << 16); - - let check = sum - (h_prime_carry * F::from(1 << 32)) - h_prime; - - Some(("s_h_prime", s_h_prime * check)) - } - - // s_a_new to get A_new = H' + Maj(A, B, C) + s_upper_sigma_0(A) - #[allow(clippy::too_many_arguments)] - pub fn s_a_new( - s_a_new: Expression, - a_new_lo: Expression, - a_new_hi: Expression, - a_new_carry: Expression, - sigma_a_lo: Expression, - sigma_a_hi: Expression, - maj_abc_lo: Expression, - maj_abc_hi: Expression, - h_prime_lo: Expression, - h_prime_hi: Expression, - ) -> Option<(&'static str, Expression)> { - let lo = sigma_a_lo + maj_abc_lo + h_prime_lo; - let hi = sigma_a_hi + maj_abc_hi + h_prime_hi; - let sum = lo + hi * F::from(1 << 16); - let a_new = a_new_lo + a_new_hi * F::from(1 << 16); - - let check = sum - (a_new_carry * F::from(1 << 32)) - a_new; - - Some(("s_a_new", s_a_new * check)) - } - - // s_e_new to get E_new = H' + D - #[allow(clippy::too_many_arguments)] - pub fn s_e_new( - s_e_new: Expression, - e_new_lo: Expression, - e_new_hi: Expression, - e_new_carry: Expression, - d_lo: Expression, - d_hi: Expression, - h_prime_lo: Expression, - h_prime_hi: Expression, - ) -> Option<(&'static str, Expression)> { - let lo = h_prime_lo + d_lo; - let hi = h_prime_hi + d_hi; - let sum = lo + hi * F::from(1 << 16); - let e_new = e_new_lo + e_new_hi * F::from(1 << 16); - - let check = sum - (e_new_carry * F::from(1 << 32)) - e_new; - - Some(("s_e_new", s_e_new * check)) - } - - // s_digest on final round - #[allow(clippy::too_many_arguments)] - pub fn s_digest( - s_digest: Expression, - lo_0: Expression, - hi_0: Expression, - word_0: Expression, - lo_1: Expression, - hi_1: Expression, - word_1: Expression, - lo_2: Expression, - hi_2: Expression, - word_2: Expression, - lo_3: Expression, - hi_3: Expression, - word_3: Expression, - ) -> impl IntoIterator> { - let check_lo_hi = |lo: Expression, hi: Expression, word: Expression| { - lo + hi * F::from(1 << 16) - word - }; - - Constraints::with_selector( - s_digest, - [ - ("check_lo_hi_0", check_lo_hi(lo_0, hi_0, word_0)), - ("check_lo_hi_1", check_lo_hi(lo_1, hi_1, word_1)), - ("check_lo_hi_2", check_lo_hi(lo_2, hi_2, word_2)), - ("check_lo_hi_3", check_lo_hi(lo_3, hi_3, word_3)), - ], - ) - } -} diff --git a/halo2_gadgets/src/sha256/table16/compression/compression_util.rs b/halo2_gadgets/src/sha256/table16/compression/compression_util.rs deleted file mode 100644 index 324fe8f695..0000000000 --- a/halo2_gadgets/src/sha256/table16/compression/compression_util.rs +++ /dev/null @@ -1,991 +0,0 @@ -use super::{ - AbcdVar, CompressionConfig, EfghVar, RoundWord, RoundWordA, RoundWordDense, RoundWordE, - RoundWordSpread, State, UpperSigmaVar, -}; -use crate::sha256::table16::{ - util::*, AssignedBits, SpreadVar, SpreadWord, StateWord, Table16Assignment, -}; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::{Advice, Column, Error}, -}; -use halo2curves::pasta::pallas; -use std::convert::TryInto; - -// Test vector 'abc' -#[cfg(test)] -pub const COMPRESSION_OUTPUT: [u32; 8] = [ - 0b10111010011110000001011010111111, - 0b10001111000000011100111111101010, - 0b01000001010000010100000011011110, - 0b01011101101011100010001000100011, - 0b10110000000000110110000110100011, - 0b10010110000101110111101010011100, - 0b10110100000100001111111101100001, - 0b11110010000000000001010110101101, -]; - -// Rows needed for each gate -pub const SIGMA_0_ROWS: usize = 4; -pub const SIGMA_1_ROWS: usize = 4; -pub const CH_ROWS: usize = 8; -pub const MAJ_ROWS: usize = 4; -pub const DECOMPOSE_ABCD: usize = 2; -pub const DECOMPOSE_EFGH: usize = 2; - -// Rows needed for main subregion -pub const SUBREGION_MAIN_LEN: usize = 64; -pub const SUBREGION_MAIN_WORD: usize = - DECOMPOSE_ABCD + SIGMA_0_ROWS + DECOMPOSE_EFGH + SIGMA_1_ROWS + CH_ROWS + MAJ_ROWS; -pub const SUBREGION_MAIN_ROWS: usize = SUBREGION_MAIN_LEN * SUBREGION_MAIN_WORD; - -/// The initial round. -pub struct InitialRound; - -/// A main round index. -#[derive(Debug, Copy, Clone)] -pub struct MainRoundIdx(usize); - -/// Round index. -#[derive(Debug, Copy, Clone)] -pub enum RoundIdx { - Init, - Main(MainRoundIdx), -} - -impl From for RoundIdx { - fn from(_: InitialRound) -> Self { - RoundIdx::Init - } -} - -impl From for RoundIdx { - fn from(idx: MainRoundIdx) -> Self { - RoundIdx::Main(idx) - } -} - -impl MainRoundIdx { - pub(crate) fn as_usize(&self) -> usize { - self.0 - } -} - -impl From for MainRoundIdx { - fn from(idx: usize) -> Self { - MainRoundIdx(idx) - } -} - -impl std::ops::Add for MainRoundIdx { - type Output = Self; - - fn add(self, rhs: usize) -> Self::Output { - MainRoundIdx(self.0 + rhs) - } -} - -impl Ord for MainRoundIdx { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - self.0.cmp(&other.0) - } -} - -impl PartialOrd for MainRoundIdx { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl PartialEq for MainRoundIdx { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } -} - -impl Eq for MainRoundIdx {} - -/// Returns starting row number of a compression round -pub fn get_round_row(round_idx: RoundIdx) -> usize { - match round_idx { - RoundIdx::Init => 0, - RoundIdx::Main(MainRoundIdx(idx)) => { - assert!(idx < 64); - (idx as usize) * SUBREGION_MAIN_WORD - } - } -} - -pub fn get_decompose_e_row(round_idx: RoundIdx) -> usize { - get_round_row(round_idx) -} - -pub fn get_decompose_f_row(round_idx: InitialRound) -> usize { - get_decompose_e_row(round_idx.into()) + DECOMPOSE_EFGH -} - -pub fn get_decompose_g_row(round_idx: InitialRound) -> usize { - get_decompose_f_row(round_idx) + DECOMPOSE_EFGH -} - -pub fn get_upper_sigma_1_row(round_idx: MainRoundIdx) -> usize { - get_decompose_e_row(round_idx.into()) + DECOMPOSE_EFGH + 1 -} - -pub fn get_ch_row(round_idx: MainRoundIdx) -> usize { - get_decompose_e_row(round_idx.into()) + DECOMPOSE_EFGH + SIGMA_1_ROWS + 1 -} - -pub fn get_ch_neg_row(round_idx: MainRoundIdx) -> usize { - get_ch_row(round_idx) + CH_ROWS / 2 -} - -pub fn get_decompose_a_row(round_idx: RoundIdx) -> usize { - match round_idx { - RoundIdx::Init => get_h_row(round_idx) + DECOMPOSE_EFGH, - RoundIdx::Main(mri) => get_ch_neg_row(mri) - 1 + CH_ROWS / 2, - } -} - -pub fn get_upper_sigma_0_row(round_idx: MainRoundIdx) -> usize { - get_decompose_a_row(round_idx.into()) + DECOMPOSE_ABCD + 1 -} - -pub fn get_decompose_b_row(round_idx: InitialRound) -> usize { - get_decompose_a_row(round_idx.into()) + DECOMPOSE_ABCD -} - -pub fn get_decompose_c_row(round_idx: InitialRound) -> usize { - get_decompose_b_row(round_idx) + DECOMPOSE_ABCD -} - -pub fn get_maj_row(round_idx: MainRoundIdx) -> usize { - get_upper_sigma_0_row(round_idx) + SIGMA_0_ROWS -} - -// Get state word rows -pub fn get_h_row(round_idx: RoundIdx) -> usize { - match round_idx { - RoundIdx::Init => get_decompose_g_row(InitialRound) + DECOMPOSE_EFGH, - RoundIdx::Main(mri) => get_ch_row(mri) - 1, - } -} - -pub fn get_h_prime_row(round_idx: MainRoundIdx) -> usize { - get_ch_row(round_idx) -} - -pub fn get_d_row(round_idx: RoundIdx) -> usize { - match round_idx { - RoundIdx::Init => get_decompose_c_row(InitialRound) + DECOMPOSE_ABCD, - RoundIdx::Main(mri) => get_ch_row(mri) + 2, - } -} - -pub fn get_e_new_row(round_idx: MainRoundIdx) -> usize { - get_d_row(round_idx.into()) -} - -pub fn get_a_new_row(round_idx: MainRoundIdx) -> usize { - get_maj_row(round_idx) -} - -pub fn get_digest_abcd_row() -> usize { - SUBREGION_MAIN_ROWS -} - -pub fn get_digest_efgh_row() -> usize { - get_digest_abcd_row() + 2 -} - -impl CompressionConfig { - pub(super) fn decompose_abcd( - &self, - region: &mut Region<'_, pallas::Base>, - row: usize, - val: Value, - ) -> Result { - self.s_decompose_abcd.enable(region, row)?; - - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - - let spread_pieces = val.map(AbcdVar::pieces); - let spread_pieces = spread_pieces.transpose_vec(6); - - let a = SpreadVar::without_lookup( - region, - a_3, - row + 1, - a_4, - row + 1, - spread_pieces[0].clone().map(SpreadWord::<2, 4>::try_new), - )?; - let b = SpreadVar::with_lookup( - region, - &self.lookup, - row, - spread_pieces[1].clone().map(SpreadWord::<11, 22>::try_new), - )?; - let c_lo = SpreadVar::without_lookup( - region, - a_3, - row, - a_4, - row, - spread_pieces[2].clone().map(SpreadWord::<3, 6>::try_new), - )?; - let c_mid = SpreadVar::without_lookup( - region, - a_5, - row, - a_6, - row, - spread_pieces[3].clone().map(SpreadWord::<3, 6>::try_new), - )?; - let c_hi = SpreadVar::without_lookup( - region, - a_5, - row + 1, - a_6, - row + 1, - spread_pieces[4].clone().map(SpreadWord::<3, 6>::try_new), - )?; - let d = SpreadVar::with_lookup( - region, - &self.lookup, - row + 1, - spread_pieces[5].clone().map(SpreadWord::<10, 20>::try_new), - )?; - - Ok(AbcdVar { - a, - b, - c_lo, - c_mid, - c_hi, - d, - }) - } - - pub(super) fn decompose_efgh( - &self, - region: &mut Region<'_, pallas::Base>, - row: usize, - val: Value, - ) -> Result { - self.s_decompose_efgh.enable(region, row)?; - - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - - let spread_pieces = val.map(EfghVar::pieces); - let spread_pieces = spread_pieces.transpose_vec(6); - - let a_lo = SpreadVar::without_lookup( - region, - a_3, - row + 1, - a_4, - row + 1, - spread_pieces[0].clone().map(SpreadWord::try_new), - )?; - let a_hi = SpreadVar::without_lookup( - region, - a_5, - row + 1, - a_6, - row + 1, - spread_pieces[1].clone().map(SpreadWord::try_new), - )?; - let b_lo = SpreadVar::without_lookup( - region, - a_3, - row, - a_4, - row, - spread_pieces[2].clone().map(SpreadWord::try_new), - )?; - let b_hi = SpreadVar::without_lookup( - region, - a_5, - row, - a_6, - row, - spread_pieces[3].clone().map(SpreadWord::try_new), - )?; - let c = SpreadVar::with_lookup( - region, - &self.lookup, - row + 1, - spread_pieces[4].clone().map(SpreadWord::try_new), - )?; - let d = SpreadVar::with_lookup( - region, - &self.lookup, - row, - spread_pieces[5].clone().map(SpreadWord::try_new), - )?; - - Ok(EfghVar { - a_lo, - a_hi, - b_lo, - b_hi, - c, - d, - }) - } - - pub(super) fn decompose_a( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: RoundIdx, - a_val: Value, - ) -> Result { - let row = get_decompose_a_row(round_idx); - - let (dense_halves, spread_halves) = self.assign_word_halves(region, row, a_val)?; - let a_pieces = self.decompose_abcd(region, row, a_val)?; - Ok(RoundWordA::new(a_pieces, dense_halves, spread_halves)) - } - - pub(super) fn decompose_e( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: RoundIdx, - e_val: Value, - ) -> Result { - let row = get_decompose_e_row(round_idx); - - let (dense_halves, spread_halves) = self.assign_word_halves(region, row, e_val)?; - let e_pieces = self.decompose_efgh(region, row, e_val)?; - Ok(RoundWordE::new(e_pieces, dense_halves, spread_halves)) - } - - pub(super) fn assign_upper_sigma_0( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - word: AbcdVar, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - // Rename these here for ease of matching the gates to the specification. - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - - let row = get_upper_sigma_0_row(round_idx); - - self.s_upper_sigma_0.enable(region, row)?; - - // Assign `spread_a` and copy constraint - word.a - .spread - .copy_advice(|| "spread_a", region, a_3, row + 1)?; - // Assign `spread_b` and copy constraint - word.b.spread.copy_advice(|| "spread_b", region, a_5, row)?; - // Assign `spread_c_lo` and copy constraint - word.c_lo - .spread - .copy_advice(|| "spread_c_lo", region, a_3, row - 1)?; - // Assign `spread_c_mid` and copy constraint - word.c_mid - .spread - .copy_advice(|| "spread_c_mid", region, a_4, row - 1)?; - // Assign `spread_c_hi` and copy constraint - word.c_hi - .spread - .copy_advice(|| "spread_c_hi", region, a_4, row + 1)?; - // Assign `spread_d` and copy constraint - word.d.spread.copy_advice(|| "spread_d", region, a_4, row)?; - - // Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - let r = word.xor_upper_sigma(); - let r_0: Value<[bool; 32]> = r.map(|r| r[..32].try_into().unwrap()); - let r_0_even = r_0.map(even_bits); - let r_0_odd = r_0.map(odd_bits); - - let r_1: Value<[bool; 32]> = r.map(|r| r[32..].try_into().unwrap()); - let r_1_even = r_1.map(even_bits); - let r_1_odd = r_1.map(odd_bits); - - self.assign_sigma_outputs( - region, - &self.lookup, - a_3, - row, - r_0_even, - r_0_odd, - r_1_even, - r_1_odd, - ) - } - - pub(super) fn assign_upper_sigma_1( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - word: EfghVar, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - // Rename these here for ease of matching the gates to the specification. - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - - let row = get_upper_sigma_1_row(round_idx); - - self.s_upper_sigma_1.enable(region, row)?; - - // Assign `spread_a_lo` and copy constraint - word.a_lo - .spread - .copy_advice(|| "spread_a_lo", region, a_3, row + 1)?; - // Assign `spread_a_hi` and copy constraint - word.a_hi - .spread - .copy_advice(|| "spread_a_hi", region, a_4, row + 1)?; - // Assign `spread_b_lo` and copy constraint - word.b_lo - .spread - .copy_advice(|| "spread_b_lo", region, a_3, row - 1)?; - // Assign `spread_b_hi` and copy constraint - word.b_hi - .spread - .copy_advice(|| "spread_b_hi", region, a_4, row - 1)?; - // Assign `spread_c` and copy constraint - word.c.spread.copy_advice(|| "spread_c", region, a_5, row)?; - // Assign `spread_d` and copy constraint - word.d.spread.copy_advice(|| "spread_d", region, a_4, row)?; - - // Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - // Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - let r = word.xor_upper_sigma(); - let r_0: Value<[bool; 32]> = r.map(|r| r[..32].try_into().unwrap()); - let r_0_even = r_0.map(even_bits); - let r_0_odd = r_0.map(odd_bits); - - let r_1: Value<[bool; 32]> = r.map(|r| r[32..].try_into().unwrap()); - let r_1_even = r_1.map(even_bits); - let r_1_odd = r_1.map(odd_bits); - - self.assign_sigma_outputs( - region, - &self.lookup, - a_3, - row, - r_0_even, - r_0_odd, - r_1_even, - r_1_odd, - ) - } - - fn assign_ch_outputs( - &self, - region: &mut Region<'_, pallas::Base>, - row: usize, - r_0_even: Value<[bool; 16]>, - r_0_odd: Value<[bool; 16]>, - r_1_even: Value<[bool; 16]>, - r_1_odd: Value<[bool; 16]>, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let a_3 = self.extras[0]; - - let (_even, odd) = self.assign_spread_outputs( - region, - &self.lookup, - a_3, - row, - r_0_even, - r_0_odd, - r_1_even, - r_1_odd, - )?; - - Ok(odd) - } - - pub(super) fn assign_ch( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - spread_halves_e: RoundWordSpread, - spread_halves_f: RoundWordSpread, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - - let row = get_ch_row(round_idx); - - self.s_ch.enable(region, row)?; - - // Assign and copy spread_e_lo, spread_e_hi - spread_halves_e - .0 - .copy_advice(|| "spread_e_lo", region, a_3, row - 1)?; - spread_halves_e - .1 - .copy_advice(|| "spread_e_hi", region, a_4, row - 1)?; - - // Assign and copy spread_f_lo, spread_f_hi - spread_halves_f - .0 - .copy_advice(|| "spread_f_lo", region, a_3, row + 1)?; - spread_halves_f - .1 - .copy_advice(|| "spread_f_hi", region, a_4, row + 1)?; - - let p: Value<[bool; 64]> = spread_halves_e - .value() - .zip(spread_halves_f.value()) - .map(|(e, f)| i2lebsp(e + f)); - - let p_0: Value<[bool; 32]> = p.map(|p| p[..32].try_into().unwrap()); - let p_0_even = p_0.map(even_bits); - let p_0_odd = p_0.map(odd_bits); - - let p_1: Value<[bool; 32]> = p.map(|p| p[32..].try_into().unwrap()); - let p_1_even = p_1.map(even_bits); - let p_1_odd = p_1.map(odd_bits); - - self.assign_ch_outputs(region, row, p_0_even, p_0_odd, p_1_even, p_1_odd) - } - - pub(super) fn assign_ch_neg( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - spread_halves_e: RoundWordSpread, - spread_halves_g: RoundWordSpread, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let row = get_ch_neg_row(round_idx); - - self.s_ch_neg.enable(region, row)?; - - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - - // Assign and copy spread_e_lo, spread_e_hi - spread_halves_e - .0 - .copy_advice(|| "spread_e_lo", region, a_5, row - 1)?; - spread_halves_e - .1 - .copy_advice(|| "spread_e_hi", region, a_5, row)?; - - // Assign and copy spread_g_lo, spread_g_hi - spread_halves_g - .0 - .copy_advice(|| "spread_g_lo", region, a_3, row + 1)?; - spread_halves_g - .1 - .copy_advice(|| "spread_g_hi", region, a_4, row + 1)?; - - // Calculate neg_e_lo - let spread_neg_e_lo = spread_halves_e - .0 - .value() - .map(|spread_e_lo| negate_spread(spread_e_lo.0)); - // Assign spread_neg_e_lo - AssignedBits::<32>::assign_bits( - region, - || "spread_neg_e_lo", - a_3, - row - 1, - spread_neg_e_lo, - )?; - - // Calculate neg_e_hi - let spread_neg_e_hi = spread_halves_e - .1 - .value() - .map(|spread_e_hi| negate_spread(spread_e_hi.0)); - // Assign spread_neg_e_hi - AssignedBits::<32>::assign_bits( - region, - || "spread_neg_e_hi", - a_4, - row - 1, - spread_neg_e_hi, - )?; - - let p: Value<[bool; 64]> = { - let spread_neg_e = spread_neg_e_lo - .zip(spread_neg_e_hi) - .map(|(lo, hi)| lebs2ip(&lo) + (1 << 32) * lebs2ip(&hi)); - spread_neg_e - .zip(spread_halves_g.value()) - .map(|(neg_e, g)| i2lebsp(neg_e + g)) - }; - - let p_0: Value<[bool; 32]> = p.map(|p| p[..32].try_into().unwrap()); - let p_0_even = p_0.map(even_bits); - let p_0_odd = p_0.map(odd_bits); - - let p_1: Value<[bool; 32]> = p.map(|p| p[32..].try_into().unwrap()); - let p_1_even = p_1.map(even_bits); - let p_1_odd = p_1.map(odd_bits); - - self.assign_ch_outputs(region, row, p_0_even, p_0_odd, p_1_even, p_1_odd) - } - - fn assign_maj_outputs( - &self, - region: &mut Region<'_, pallas::Base>, - row: usize, - r_0_even: Value<[bool; 16]>, - r_0_odd: Value<[bool; 16]>, - r_1_even: Value<[bool; 16]>, - r_1_odd: Value<[bool; 16]>, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let a_3 = self.extras[0]; - let (_even, odd) = self.assign_spread_outputs( - region, - &self.lookup, - a_3, - row, - r_0_even, - r_0_odd, - r_1_even, - r_1_odd, - )?; - - Ok(odd) - } - - pub(super) fn assign_maj( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - spread_halves_a: RoundWordSpread, - spread_halves_b: RoundWordSpread, - spread_halves_c: RoundWordSpread, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - - let row = get_maj_row(round_idx); - - self.s_maj.enable(region, row)?; - - // Assign and copy spread_a_lo, spread_a_hi - spread_halves_a - .0 - .copy_advice(|| "spread_a_lo", region, a_4, row - 1)?; - spread_halves_a - .1 - .copy_advice(|| "spread_a_hi", region, a_5, row - 1)?; - - // Assign and copy spread_b_lo, spread_b_hi - spread_halves_b - .0 - .copy_advice(|| "spread_b_lo", region, a_4, row)?; - spread_halves_b - .1 - .copy_advice(|| "spread_b_hi", region, a_5, row)?; - - // Assign and copy spread_c_lo, spread_c_hi - spread_halves_c - .0 - .copy_advice(|| "spread_c_lo", region, a_4, row + 1)?; - spread_halves_c - .1 - .copy_advice(|| "spread_c_hi", region, a_5, row + 1)?; - - let m: Value<[bool; 64]> = spread_halves_a - .value() - .zip(spread_halves_b.value()) - .zip(spread_halves_c.value()) - .map(|((a, b), c)| i2lebsp(a + b + c)); - - let m_0: Value<[bool; 32]> = m.map(|m| m[..32].try_into().unwrap()); - let m_0_even = m_0.map(even_bits); - let m_0_odd = m_0.map(odd_bits); - - let m_1: Value<[bool; 32]> = m.map(|m| m[32..].try_into().unwrap()); - let m_1_even = m_1.map(even_bits); - let m_1_odd = m_1.map(odd_bits); - - self.assign_maj_outputs(region, row, m_0_even, m_0_odd, m_1_even, m_1_odd) - } - - // s_h_prime to get H' = H + Ch(E, F, G) + s_upper_sigma_1(E) + K + W - #[allow(clippy::too_many_arguments)] - pub(super) fn assign_h_prime( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - h: RoundWordDense, - ch: (AssignedBits<16>, AssignedBits<16>), - ch_neg: (AssignedBits<16>, AssignedBits<16>), - sigma_1: (AssignedBits<16>, AssignedBits<16>), - k: u32, - w: &(AssignedBits<16>, AssignedBits<16>), - ) -> Result { - let row = get_h_prime_row(round_idx); - self.s_h_prime.enable(region, row)?; - - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - let a_7 = self.extras[3]; - let a_8 = self.extras[4]; - let a_9 = self.extras[5]; - - // Assign and copy h - h.0.copy_advice(|| "h_lo", region, a_7, row - 1)?; - h.1.copy_advice(|| "h_hi", region, a_7, row)?; - - // Assign and copy sigma_1 - sigma_1.0.copy_advice(|| "sigma_1_lo", region, a_4, row)?; - sigma_1.1.copy_advice(|| "sigma_1_hi", region, a_5, row)?; - - // Assign k - let k: [bool; 32] = i2lebsp(k.into()); - let k_lo: [bool; 16] = k[..16].try_into().unwrap(); - let k_hi: [bool; 16] = k[16..].try_into().unwrap(); - { - AssignedBits::<16>::assign_bits(region, || "k_lo", a_6, row - 1, Value::known(k_lo))?; - AssignedBits::<16>::assign_bits(region, || "k_hi", a_6, row, Value::known(k_hi))?; - } - - // Assign and copy w - w.0.copy_advice(|| "w_lo", region, a_8, row - 1)?; - w.1.copy_advice(|| "w_hi", region, a_8, row)?; - - // Assign and copy ch - ch.1.copy_advice(|| "ch_neg_hi", region, a_6, row + 1)?; - - // Assign and copy ch_neg - ch_neg.0.copy_advice(|| "ch_neg_lo", region, a_5, row - 1)?; - ch_neg.1.copy_advice(|| "ch_neg_hi", region, a_5, row + 1)?; - - // Assign h_prime_lo, h_prime_hi, h_prime_carry - { - let (h_prime, h_prime_carry) = sum_with_carry(vec![ - (h.0.value_u16(), h.1.value_u16()), - (ch.0.value_u16(), ch.1.value_u16()), - (ch_neg.0.value_u16(), ch_neg.1.value_u16()), - (sigma_1.0.value_u16(), sigma_1.1.value_u16()), - ( - Value::known(lebs2ip(&k_lo) as u16), - Value::known(lebs2ip(&k_hi) as u16), - ), - (w.0.value_u16(), w.1.value_u16()), - ]); - - region.assign_advice( - || "h_prime_carry", - a_9, - row + 1, - || h_prime_carry.map(|value| pallas::Base::from(value as u64)), - )?; - - let h_prime: Value<[bool; 32]> = h_prime.map(|w| i2lebsp(w.into())); - let h_prime_lo: Value<[bool; 16]> = h_prime.map(|w| w[..16].try_into().unwrap()); - let h_prime_hi: Value<[bool; 16]> = h_prime.map(|w| w[16..].try_into().unwrap()); - - let h_prime_lo = - AssignedBits::<16>::assign_bits(region, || "h_prime_lo", a_7, row + 1, h_prime_lo)?; - let h_prime_hi = - AssignedBits::<16>::assign_bits(region, || "h_prime_hi", a_8, row + 1, h_prime_hi)?; - - Ok((h_prime_lo, h_prime_hi).into()) - } - } - - // s_e_new to get E_new = H' + D - pub(super) fn assign_e_new( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - d: &RoundWordDense, - h_prime: &RoundWordDense, - ) -> Result { - let row = get_e_new_row(round_idx); - - self.s_e_new.enable(region, row)?; - - let a_7 = self.extras[3]; - let a_8 = self.extras[4]; - let a_9 = self.extras[5]; - - // Assign and copy d_lo, d_hi - d.0.copy_advice(|| "d_lo", region, a_7, row)?; - d.1.copy_advice(|| "d_hi", region, a_7, row + 1)?; - - // Assign e_new, e_new_carry - let (e_new, e_new_carry) = sum_with_carry(vec![ - (h_prime.0.value_u16(), h_prime.1.value_u16()), - (d.0.value_u16(), d.1.value_u16()), - ]); - - let e_new_dense = self.assign_word_halves_dense(region, row, a_8, row + 1, a_8, e_new)?; - region.assign_advice( - || "e_new_carry", - a_9, - row + 1, - || e_new_carry.map(pallas::Base::from), - )?; - - Ok(e_new_dense) - } - - // s_a_new to get A_new = H' + Maj(A, B, C) + s_upper_sigma_0(A) - pub(super) fn assign_a_new( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - maj: (AssignedBits<16>, AssignedBits<16>), - sigma_0: (AssignedBits<16>, AssignedBits<16>), - h_prime: RoundWordDense, - ) -> Result { - let row = get_a_new_row(round_idx); - - self.s_a_new.enable(region, row)?; - - let a_3 = self.extras[0]; - let a_6 = self.extras[2]; - let a_7 = self.extras[3]; - let a_8 = self.extras[4]; - let a_9 = self.extras[5]; - - // Assign and copy maj_1 - maj.1.copy_advice(|| "maj_1_hi", region, a_3, row - 1)?; - - // Assign and copy sigma_0 - sigma_0.0.copy_advice(|| "sigma_0_lo", region, a_6, row)?; - sigma_0 - .1 - .copy_advice(|| "sigma_0_hi", region, a_6, row + 1)?; - - // Assign and copy h_prime - h_prime - .0 - .copy_advice(|| "h_prime_lo", region, a_7, row - 1)?; - h_prime - .1 - .copy_advice(|| "h_prime_hi", region, a_8, row - 1)?; - - // Assign a_new, a_new_carry - let (a_new, a_new_carry) = sum_with_carry(vec![ - (h_prime.0.value_u16(), h_prime.1.value_u16()), - (sigma_0.0.value_u16(), sigma_0.1.value_u16()), - (maj.0.value_u16(), maj.1.value_u16()), - ]); - - let a_new_dense = self.assign_word_halves_dense(region, row, a_8, row + 1, a_8, a_new)?; - region.assign_advice( - || "a_new_carry", - a_9, - row, - || a_new_carry.map(pallas::Base::from), - )?; - - Ok(a_new_dense) - } - - pub fn assign_word_halves_dense( - &self, - region: &mut Region<'_, pallas::Base>, - lo_row: usize, - lo_col: Column, - hi_row: usize, - hi_col: Column, - word: Value, - ) -> Result { - let word: Value<[bool; 32]> = word.map(|w| i2lebsp(w.into())); - - let lo = { - let lo: Value<[bool; 16]> = word.map(|w| w[..16].try_into().unwrap()); - AssignedBits::<16>::assign_bits(region, || "lo", lo_col, lo_row, lo)? - }; - - let hi = { - let hi: Value<[bool; 16]> = word.map(|w| w[16..].try_into().unwrap()); - AssignedBits::<16>::assign_bits(region, || "hi", hi_col, hi_row, hi)? - }; - - Ok((lo, hi).into()) - } - - // Assign hi and lo halves for both dense and spread versions of a word - #[allow(clippy::type_complexity)] - pub fn assign_word_halves( - &self, - region: &mut Region<'_, pallas::Base>, - row: usize, - word: Value, - ) -> Result<(RoundWordDense, RoundWordSpread), Error> { - // Rename these here for ease of matching the gates to the specification. - let a_7 = self.extras[3]; - let a_8 = self.extras[4]; - - let word: Value<[bool; 32]> = word.map(|w| i2lebsp(w.into())); - let lo: Value<[bool; 16]> = word.map(|w| w[..16].try_into().unwrap()); - let hi: Value<[bool; 16]> = word.map(|w| w[16..].try_into().unwrap()); - - let w_lo = SpreadVar::without_lookup(region, a_7, row, a_8, row, lo.map(SpreadWord::new))?; - let w_hi = - SpreadVar::without_lookup(region, a_7, row + 1, a_8, row + 1, hi.map(SpreadWord::new))?; - - Ok(( - (w_lo.dense, w_hi.dense).into(), - (w_lo.spread, w_hi.spread).into(), - )) - } -} - -#[allow(clippy::many_single_char_names)] -pub fn match_state( - state: State, -) -> ( - RoundWordA, - RoundWord, - RoundWord, - RoundWordDense, - RoundWordE, - RoundWord, - RoundWord, - RoundWordDense, -) { - let a = match state.a { - Some(StateWord::A(a)) => a, - _ => unreachable!(), - }; - let b = match state.b { - Some(StateWord::B(b)) => b, - _ => unreachable!(), - }; - let c = match state.c { - Some(StateWord::C(c)) => c, - _ => unreachable!(), - }; - let d = match state.d { - Some(StateWord::D(d)) => d, - _ => unreachable!(), - }; - let e = match state.e { - Some(StateWord::E(e)) => e, - _ => unreachable!(), - }; - let f = match state.f { - Some(StateWord::F(f)) => f, - _ => unreachable!(), - }; - let g = match state.g { - Some(StateWord::G(g)) => g, - _ => unreachable!(), - }; - let h = match state.h { - Some(StateWord::H(h)) => h, - _ => unreachable!(), - }; - - (a, b, c, d, e, f, g, h) -} diff --git a/halo2_gadgets/src/sha256/table16/compression/subregion_digest.rs b/halo2_gadgets/src/sha256/table16/compression/subregion_digest.rs deleted file mode 100644 index aa30f80af7..0000000000 --- a/halo2_gadgets/src/sha256/table16/compression/subregion_digest.rs +++ /dev/null @@ -1,102 +0,0 @@ -use super::super::{super::DIGEST_SIZE, BlockWord, RoundWordDense}; -use super::{compression_util::*, CompressionConfig, State}; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::{Advice, Column, Error}, -}; -use halo2curves::pasta::pallas; - -impl CompressionConfig { - #[allow(clippy::many_single_char_names)] - pub fn assign_digest( - &self, - region: &mut Region<'_, pallas::Base>, - state: State, - ) -> Result<[BlockWord; DIGEST_SIZE], Error> { - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - let a_7 = self.extras[3]; - let a_8 = self.extras[4]; - - let (a, b, c, d, e, f, g, h) = match_state(state); - - let abcd_row = 0; - self.s_digest.enable(region, abcd_row)?; - let efgh_row = abcd_row + 2; - self.s_digest.enable(region, efgh_row)?; - - // Assign digest for A, B, C, D - a.dense_halves - .0 - .copy_advice(|| "a_lo", region, a_3, abcd_row)?; - a.dense_halves - .1 - .copy_advice(|| "a_hi", region, a_4, abcd_row)?; - let a = a.dense_halves.value(); - region.assign_advice( - || "a", - a_5, - abcd_row, - || a.map(|a| pallas::Base::from(a as u64)), - )?; - - let b = self.assign_digest_word(region, abcd_row, a_6, a_7, a_8, b.dense_halves)?; - let c = self.assign_digest_word(region, abcd_row + 1, a_3, a_4, a_5, c.dense_halves)?; - let d = self.assign_digest_word(region, abcd_row + 1, a_6, a_7, a_8, d)?; - - // Assign digest for E, F, G, H - e.dense_halves - .0 - .copy_advice(|| "e_lo", region, a_3, efgh_row)?; - e.dense_halves - .1 - .copy_advice(|| "e_hi", region, a_4, efgh_row)?; - let e = e.dense_halves.value(); - region.assign_advice( - || "e", - a_5, - efgh_row, - || e.map(|e| pallas::Base::from(e as u64)), - )?; - - let f = self.assign_digest_word(region, efgh_row, a_6, a_7, a_8, f.dense_halves)?; - let g = self.assign_digest_word(region, efgh_row + 1, a_3, a_4, a_5, g.dense_halves)?; - let h = self.assign_digest_word(region, efgh_row + 1, a_6, a_7, a_8, h)?; - - Ok([ - BlockWord(a), - BlockWord(b), - BlockWord(c), - BlockWord(d), - BlockWord(e), - BlockWord(f), - BlockWord(g), - BlockWord(h), - ]) - } - - fn assign_digest_word( - &self, - region: &mut Region<'_, pallas::Base>, - row: usize, - lo_col: Column, - hi_col: Column, - word_col: Column, - dense_halves: RoundWordDense, - ) -> Result, Error> { - dense_halves.0.copy_advice(|| "lo", region, lo_col, row)?; - dense_halves.1.copy_advice(|| "hi", region, hi_col, row)?; - - let val = dense_halves.value(); - region.assign_advice( - || "word", - word_col, - row, - || val.map(|val| pallas::Base::from(val as u64)), - )?; - - Ok(val) - } -} diff --git a/halo2_gadgets/src/sha256/table16/compression/subregion_initial.rs b/halo2_gadgets/src/sha256/table16/compression/subregion_initial.rs deleted file mode 100644 index a487dc0c87..0000000000 --- a/halo2_gadgets/src/sha256/table16/compression/subregion_initial.rs +++ /dev/null @@ -1,157 +0,0 @@ -use super::super::{RoundWord, StateWord, STATE}; -use super::{compression_util::*, CompressionConfig, State}; - -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::Error, -}; -use halo2curves::pasta::pallas; - -impl CompressionConfig { - #[allow(clippy::many_single_char_names)] - pub fn initialize_iv( - &self, - region: &mut Region<'_, pallas::Base>, - iv: [u32; STATE], - ) -> Result { - let a_7 = self.extras[3]; - - // Decompose E into (6, 5, 14, 7)-bit chunks - let e = self.decompose_e(region, RoundIdx::Init, Value::known(iv[4]))?; - - // Decompose F, G - let f = self.decompose_f(region, InitialRound, Value::known(iv[5]))?; - let g = self.decompose_g(region, InitialRound, Value::known(iv[6]))?; - - // Assign H - let h_row = get_h_row(RoundIdx::Init); - let h = - self.assign_word_halves_dense(region, h_row, a_7, h_row + 1, a_7, Value::known(iv[7]))?; - - // Decompose A into (2, 11, 9, 10)-bit chunks - let a = self.decompose_a(region, RoundIdx::Init, Value::known(iv[0]))?; - - // Decompose B, C - let b = self.decompose_b(region, InitialRound, Value::known(iv[1]))?; - let c = self.decompose_c(region, InitialRound, Value::known(iv[2]))?; - - // Assign D - let d_row = get_d_row(RoundIdx::Init); - let d = - self.assign_word_halves_dense(region, d_row, a_7, d_row + 1, a_7, Value::known(iv[3]))?; - - Ok(State::new( - StateWord::A(a), - StateWord::B(b), - StateWord::C(c), - StateWord::D(d), - StateWord::E(e), - StateWord::F(f), - StateWord::G(g), - StateWord::H(h), - )) - } - - #[allow(clippy::many_single_char_names)] - pub fn initialize_state( - &self, - region: &mut Region<'_, pallas::Base>, - state: State, - ) -> Result { - let a_7 = self.extras[3]; - let (a, b, c, d, e, f, g, h) = match_state(state); - - // Decompose E into (6, 5, 14, 7)-bit chunks - let e = e.dense_halves.value(); - let e = self.decompose_e(region, RoundIdx::Init, e)?; - - // Decompose F, G - let f = f.dense_halves.value(); - let f = self.decompose_f(region, InitialRound, f)?; - let g = g.dense_halves.value(); - let g = self.decompose_g(region, InitialRound, g)?; - - // Assign H - let h = h.value(); - let h_row = get_h_row(RoundIdx::Init); - let h = self.assign_word_halves_dense(region, h_row, a_7, h_row + 1, a_7, h)?; - - // Decompose A into (2, 11, 9, 10)-bit chunks - let a = a.dense_halves.value(); - let a = self.decompose_a(region, RoundIdx::Init, a)?; - - // Decompose B, C - let b = b.dense_halves.value(); - let b = self.decompose_b(region, InitialRound, b)?; - let c = c.dense_halves.value(); - let c = self.decompose_c(region, InitialRound, c)?; - - // Assign D - let d = d.value(); - let d_row = get_d_row(RoundIdx::Init); - let d = self.assign_word_halves_dense(region, d_row, a_7, d_row + 1, a_7, d)?; - - Ok(State::new( - StateWord::A(a), - StateWord::B(b), - StateWord::C(c), - StateWord::D(d), - StateWord::E(e), - StateWord::F(f), - StateWord::G(g), - StateWord::H(h), - )) - } - - fn decompose_b( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: InitialRound, - b_val: Value, - ) -> Result { - let row = get_decompose_b_row(round_idx); - - let (dense_halves, spread_halves) = self.assign_word_halves(region, row, b_val)?; - self.decompose_abcd(region, row, b_val)?; - Ok(RoundWord::new(dense_halves, spread_halves)) - } - - fn decompose_c( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: InitialRound, - c_val: Value, - ) -> Result { - let row = get_decompose_c_row(round_idx); - - let (dense_halves, spread_halves) = self.assign_word_halves(region, row, c_val)?; - self.decompose_abcd(region, row, c_val)?; - Ok(RoundWord::new(dense_halves, spread_halves)) - } - - fn decompose_f( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: InitialRound, - f_val: Value, - ) -> Result { - let row = get_decompose_f_row(round_idx); - - let (dense_halves, spread_halves) = self.assign_word_halves(region, row, f_val)?; - self.decompose_efgh(region, row, f_val)?; - Ok(RoundWord::new(dense_halves, spread_halves)) - } - - fn decompose_g( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: InitialRound, - g_val: Value, - ) -> Result { - let row = get_decompose_g_row(round_idx); - - let (dense_halves, spread_halves) = self.assign_word_halves(region, row, g_val)?; - self.decompose_efgh(region, row, g_val)?; - Ok(RoundWord::new(dense_halves, spread_halves)) - } -} diff --git a/halo2_gadgets/src/sha256/table16/compression/subregion_main.rs b/halo2_gadgets/src/sha256/table16/compression/subregion_main.rs deleted file mode 100644 index bda188a866..0000000000 --- a/halo2_gadgets/src/sha256/table16/compression/subregion_main.rs +++ /dev/null @@ -1,127 +0,0 @@ -use super::super::{AssignedBits, RoundWord, RoundWordA, RoundWordE, StateWord, ROUND_CONSTANTS}; -use super::{compression_util::*, CompressionConfig, State}; -use halo2_proofs::{circuit::Region, plonk::Error}; -use halo2curves::pasta::pallas; - -impl CompressionConfig { - #[allow(clippy::many_single_char_names)] - pub fn assign_round( - &self, - region: &mut Region<'_, pallas::Base>, - round_idx: MainRoundIdx, - state: State, - schedule_word: &(AssignedBits<16>, AssignedBits<16>), - ) -> Result { - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_7 = self.extras[3]; - - let (a, b, c, d, e, f, g, h) = match_state(state); - - // s_upper_sigma_1(E) - let sigma_1 = self.assign_upper_sigma_1(region, round_idx, e.pieces.clone().unwrap())?; - - // Ch(E, F, G) - let ch = self.assign_ch( - region, - round_idx, - e.spread_halves.clone().unwrap(), - f.spread_halves.clone(), - )?; - let ch_neg = self.assign_ch_neg( - region, - round_idx, - e.spread_halves.clone().unwrap(), - g.spread_halves.clone(), - )?; - - // s_upper_sigma_0(A) - let sigma_0 = self.assign_upper_sigma_0(region, round_idx, a.pieces.clone().unwrap())?; - - // Maj(A, B, C) - let maj = self.assign_maj( - region, - round_idx, - a.spread_halves.clone().unwrap(), - b.spread_halves.clone(), - c.spread_halves.clone(), - )?; - - // H' = H + Ch(E, F, G) + s_upper_sigma_1(E) + K + W - let h_prime = self.assign_h_prime( - region, - round_idx, - h, - ch, - ch_neg, - sigma_1, - ROUND_CONSTANTS[round_idx.as_usize()], - schedule_word, - )?; - - // E_new = H' + D - let e_new_dense = self.assign_e_new(region, round_idx, &d, &h_prime)?; - let e_new_val = e_new_dense.value(); - - // A_new = H' + Maj(A, B, C) + sigma_0(A) - let a_new_dense = self.assign_a_new(region, round_idx, maj, sigma_0, h_prime)?; - let a_new_val = a_new_dense.value(); - - if round_idx < 63.into() { - // Assign and copy A_new - let a_new_row = get_decompose_a_row((round_idx + 1).into()); - a_new_dense - .0 - .copy_advice(|| "a_new_lo", region, a_7, a_new_row)?; - a_new_dense - .1 - .copy_advice(|| "a_new_hi", region, a_7, a_new_row + 1)?; - - // Assign and copy E_new - let e_new_row = get_decompose_e_row((round_idx + 1).into()); - e_new_dense - .0 - .copy_advice(|| "e_new_lo", region, a_7, e_new_row)?; - e_new_dense - .1 - .copy_advice(|| "e_new_hi", region, a_7, e_new_row + 1)?; - - // Decompose A into (2, 11, 9, 10)-bit chunks - let a_new = self.decompose_a(region, (round_idx + 1).into(), a_new_val)?; - - // Decompose E into (6, 5, 14, 7)-bit chunks - let e_new = self.decompose_e(region, (round_idx + 1).into(), e_new_val)?; - - Ok(State::new( - StateWord::A(a_new), - StateWord::B(RoundWord::new(a.dense_halves, a.spread_halves.unwrap())), - StateWord::C(b), - StateWord::D(c.dense_halves), - StateWord::E(e_new), - StateWord::F(RoundWord::new(e.dense_halves, e.spread_halves.unwrap())), - StateWord::G(f), - StateWord::H(g.dense_halves), - )) - } else { - let abcd_row = get_digest_abcd_row(); - let efgh_row = get_digest_efgh_row(); - - let a_final = - self.assign_word_halves_dense(region, abcd_row, a_3, abcd_row, a_4, a_new_val)?; - - let e_final = - self.assign_word_halves_dense(region, efgh_row, a_3, efgh_row, a_4, e_new_val)?; - - Ok(State::new( - StateWord::A(RoundWordA::new_dense(a_final)), - StateWord::B(RoundWord::new(a.dense_halves, a.spread_halves.unwrap())), - StateWord::C(b), - StateWord::D(c.dense_halves), - StateWord::E(RoundWordE::new_dense(e_final)), - StateWord::F(RoundWord::new(e.dense_halves, e.spread_halves.unwrap())), - StateWord::G(f), - StateWord::H(g.dense_halves), - )) - } - } -} diff --git a/halo2_gadgets/src/sha256/table16/gates.rs b/halo2_gadgets/src/sha256/table16/gates.rs deleted file mode 100644 index 4f268092db..0000000000 --- a/halo2_gadgets/src/sha256/table16/gates.rs +++ /dev/null @@ -1,124 +0,0 @@ -use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; - -pub struct Gate(pub Expression); - -impl Gate { - fn ones() -> Expression { - Expression::Constant(F::one()) - } - - // Helper gates - fn lagrange_interpolate( - var: Expression, - points: Vec, - evals: Vec, - ) -> (F, Expression) { - assert_eq!(points.len(), evals.len()); - let deg = points.len(); - - fn factorial(n: u64) -> u64 { - if n < 2 { - 1 - } else { - n * factorial(n - 1) - } - } - - // Scale the whole expression by factor to avoid divisions - let factor = factorial((deg - 1) as u64); - - let numerator = |var: Expression, eval: u32, idx: u64| { - let mut expr = Self::ones(); - for i in 0..deg { - let i = i as u64; - if i != idx { - expr = expr * (Self::ones() * (-F::one()) * F::from(i) + var.clone()); - } - } - expr * F::from(u64::from(eval)) - }; - let denominator = |idx: i32| { - let mut denom: i32 = 1; - for i in 0..deg { - let i = i as i32; - if i != idx { - denom *= idx - i - } - } - if denom < 0 { - -F::one() * F::from(factor / (-denom as u64)) - } else { - F::from(factor / (denom as u64)) - } - }; - - let mut expr = Self::ones() * F::zero(); - for ((idx, _), eval) in points.iter().enumerate().zip(evals.iter()) { - expr = expr + numerator(var.clone(), *eval, idx as u64) * denominator(idx as i32) - } - - (F::from(factor), expr) - } - - pub fn range_check(value: Expression, lower_range: u64, upper_range: u64) -> Expression { - let mut expr = Self::ones(); - for i in lower_range..(upper_range + 1) { - expr = expr * (Self::ones() * (-F::one()) * F::from(i) + value.clone()) - } - expr - } - - /// Spread and range check on 2-bit word - pub fn two_bit_spread_and_range( - dense: Expression, - spread: Expression, - ) -> impl Iterator)> { - let two_bit_spread = |dense: Expression, spread: Expression| { - let (factor, lagrange_poly) = Self::lagrange_interpolate( - dense, - vec![0b00, 0b01, 0b10, 0b11], - vec![0b0000, 0b0001, 0b0100, 0b0101], - ); - - lagrange_poly - spread * factor - }; - - std::iter::empty() - .chain(Some(( - "two_bit_range_check", - Self::range_check(dense.clone(), 0, (1 << 2) - 1), - ))) - .chain(Some(( - "two_bit_spread_check", - two_bit_spread(dense, spread), - ))) - } - - /// Spread and range check on 3-bit word - pub fn three_bit_spread_and_range( - dense: Expression, - spread: Expression, - ) -> impl Iterator)> { - let three_bit_spread = |dense: Expression, spread: Expression| { - let (factor, lagrange_poly) = Self::lagrange_interpolate( - dense, - vec![0b000, 0b001, 0b010, 0b011, 0b100, 0b101, 0b110, 0b111], - vec![ - 0b000000, 0b000001, 0b000100, 0b000101, 0b010000, 0b010001, 0b010100, 0b010101, - ], - ); - - lagrange_poly - spread * factor - }; - - std::iter::empty() - .chain(Some(( - "three_bit_range_check", - Self::range_check(dense.clone(), 0, (1 << 3) - 1), - ))) - .chain(Some(( - "three_bit_spread_check", - three_bit_spread(dense, spread), - ))) - } -} diff --git a/halo2_gadgets/src/sha256/table16/message_schedule.rs b/halo2_gadgets/src/sha256/table16/message_schedule.rs deleted file mode 100644 index 690e086c49..0000000000 --- a/halo2_gadgets/src/sha256/table16/message_schedule.rs +++ /dev/null @@ -1,455 +0,0 @@ -use std::convert::TryInto; - -use super::{super::BLOCK_SIZE, AssignedBits, BlockWord, SpreadInputs, Table16Assignment, ROUNDS}; -use halo2_proofs::{ - circuit::Layouter, - plonk::{Advice, Column, ConstraintSystem, Error, Selector}, - poly::Rotation, -}; -use halo2curves::pasta::pallas; - -mod schedule_gates; -mod schedule_util; -mod subregion1; -mod subregion2; -mod subregion3; - -use schedule_gates::ScheduleGate; -use schedule_util::*; - -#[cfg(test)] -pub use schedule_util::msg_schedule_test_input; - -#[derive(Clone, Debug)] -pub(super) struct MessageWord(AssignedBits<32>); - -impl std::ops::Deref for MessageWord { - type Target = AssignedBits<32>; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[derive(Clone, Debug)] -pub(super) struct MessageScheduleConfig { - lookup: SpreadInputs, - message_schedule: Column, - extras: [Column; 6], - - /// Construct a word using reduce_4. - s_word: Selector, - /// Decomposition gate for W_0, W_62, W_63. - s_decompose_0: Selector, - /// Decomposition gate for W_[1..14] - s_decompose_1: Selector, - /// Decomposition gate for W_[14..49] - s_decompose_2: Selector, - /// Decomposition gate for W_[49..62] - s_decompose_3: Selector, - /// sigma_0 gate for W_[1..14] - s_lower_sigma_0: Selector, - /// sigma_1 gate for W_[49..62] - s_lower_sigma_1: Selector, - /// sigma_0_v2 gate for W_[14..49] - s_lower_sigma_0_v2: Selector, - /// sigma_1_v2 gate for W_[14..49] - s_lower_sigma_1_v2: Selector, -} - -impl Table16Assignment for MessageScheduleConfig {} - -impl MessageScheduleConfig { - /// Configures the message schedule. - /// - /// `message_schedule` is the column into which the message schedule will be placed. - /// The caller must create appropriate permutations in order to load schedule words - /// into the compression rounds. - /// - /// `extras` contains columns that the message schedule will only use for internal - /// gates, and will not place any constraints on (such as lookup constraints) outside - /// itself. - #[allow(clippy::many_single_char_names)] - pub(super) fn configure( - meta: &mut ConstraintSystem, - lookup: SpreadInputs, - message_schedule: Column, - extras: [Column; 6], - ) -> Self { - // Create fixed columns for the selectors we will require. - let s_word = meta.selector(); - let s_decompose_0 = meta.selector(); - let s_decompose_1 = meta.selector(); - let s_decompose_2 = meta.selector(); - let s_decompose_3 = meta.selector(); - let s_lower_sigma_0 = meta.selector(); - let s_lower_sigma_1 = meta.selector(); - let s_lower_sigma_0_v2 = meta.selector(); - let s_lower_sigma_1_v2 = meta.selector(); - - // Rename these here for ease of matching the gates to the specification. - let a_0 = lookup.tag; - let a_1 = lookup.dense; - let a_2 = lookup.spread; - let a_3 = extras[0]; - let a_4 = extras[1]; - let a_5 = message_schedule; - let a_6 = extras[2]; - let a_7 = extras[3]; - let a_8 = extras[4]; - let a_9 = extras[5]; - - // s_word for W_[16..64] - meta.create_gate("s_word for W_[16..64]", |meta| { - let s_word = meta.query_selector(s_word); - - let sigma_0_lo = meta.query_advice(a_6, Rotation::prev()); - let sigma_0_hi = meta.query_advice(a_6, Rotation::cur()); - - let sigma_1_lo = meta.query_advice(a_7, Rotation::prev()); - let sigma_1_hi = meta.query_advice(a_7, Rotation::cur()); - - let w_minus_9_lo = meta.query_advice(a_8, Rotation::prev()); - let w_minus_9_hi = meta.query_advice(a_8, Rotation::cur()); - - let w_minus_16_lo = meta.query_advice(a_3, Rotation::prev()); - let w_minus_16_hi = meta.query_advice(a_4, Rotation::prev()); - - let word = meta.query_advice(a_5, Rotation::cur()); - let carry = meta.query_advice(a_9, Rotation::cur()); - - ScheduleGate::s_word( - s_word, - sigma_0_lo, - sigma_0_hi, - sigma_1_lo, - sigma_1_hi, - w_minus_9_lo, - w_minus_9_hi, - w_minus_16_lo, - w_minus_16_hi, - word, - carry, - ) - }); - - // s_decompose_0 for all words - meta.create_gate("s_decompose_0", |meta| { - let s_decompose_0 = meta.query_selector(s_decompose_0); - let lo = meta.query_advice(a_3, Rotation::cur()); - let hi = meta.query_advice(a_4, Rotation::cur()); - let word = meta.query_advice(a_5, Rotation::cur()); - - ScheduleGate::s_decompose_0(s_decompose_0, lo, hi, word) - }); - - // s_decompose_1 for W_[1..14] - // (3, 4, 11, 14)-bit chunks - meta.create_gate("s_decompose_1", |meta| { - let s_decompose_1 = meta.query_selector(s_decompose_1); - let a = meta.query_advice(a_3, Rotation::next()); // 3-bit chunk - let b = meta.query_advice(a_4, Rotation::next()); // 4-bit chunk - let c = meta.query_advice(a_1, Rotation::next()); // 11-bit chunk - let tag_c = meta.query_advice(a_0, Rotation::next()); - let d = meta.query_advice(a_1, Rotation::cur()); // 14-bit chunk - let tag_d = meta.query_advice(a_0, Rotation::cur()); - let word = meta.query_advice(a_5, Rotation::cur()); - - ScheduleGate::s_decompose_1(s_decompose_1, a, b, c, tag_c, d, tag_d, word) - }); - - // s_decompose_2 for W_[14..49] - // (3, 4, 3, 7, 1, 1, 13)-bit chunks - meta.create_gate("s_decompose_2", |meta| { - let s_decompose_2 = meta.query_selector(s_decompose_2); - let a = meta.query_advice(a_3, Rotation::prev()); // 3-bit chunk - let b = meta.query_advice(a_1, Rotation::next()); // 4-bit chunk - let c = meta.query_advice(a_4, Rotation::prev()); // 3-bit chunk - let d = meta.query_advice(a_1, Rotation::cur()); // 7-bit chunk - let tag_d = meta.query_advice(a_0, Rotation::cur()); - let e = meta.query_advice(a_3, Rotation::next()); // 1-bit chunk - let f = meta.query_advice(a_4, Rotation::next()); // 1-bit chunk - let g = meta.query_advice(a_1, Rotation::prev()); // 13-bit chunk - let tag_g = meta.query_advice(a_0, Rotation::prev()); - let word = meta.query_advice(a_5, Rotation::cur()); - - ScheduleGate::s_decompose_2(s_decompose_2, a, b, c, d, tag_d, e, f, g, tag_g, word) - }); - - // s_decompose_3 for W_49 to W_61 - // (10, 7, 2, 13)-bit chunks - meta.create_gate("s_decompose_3", |meta| { - let s_decompose_3 = meta.query_selector(s_decompose_3); - let a = meta.query_advice(a_1, Rotation::next()); // 10-bit chunk - let tag_a = meta.query_advice(a_0, Rotation::next()); - let b = meta.query_advice(a_4, Rotation::next()); // 7-bit chunk - let c = meta.query_advice(a_3, Rotation::next()); // 2-bit chunk - let d = meta.query_advice(a_1, Rotation::cur()); // 13-bit chunk - let tag_d = meta.query_advice(a_0, Rotation::cur()); - let word = meta.query_advice(a_5, Rotation::cur()); - - ScheduleGate::s_decompose_3(s_decompose_3, a, tag_a, b, c, d, tag_d, word) - }); - - // sigma_0 v1 on W_[1..14] - // (3, 4, 11, 14)-bit chunks - meta.create_gate("sigma_0 v1", |meta| { - ScheduleGate::s_lower_sigma_0( - meta.query_selector(s_lower_sigma_0), - meta.query_advice(a_2, Rotation::prev()), // spread_r0_even - meta.query_advice(a_2, Rotation::cur()), // spread_r0_odd - meta.query_advice(a_2, Rotation::next()), // spread_r1_even - meta.query_advice(a_3, Rotation::cur()), // spread_r1_odd - meta.query_advice(a_5, Rotation::next()), // a - meta.query_advice(a_6, Rotation::next()), // spread_a - meta.query_advice(a_6, Rotation::cur()), // b - meta.query_advice(a_3, Rotation::prev()), // b_lo - meta.query_advice(a_4, Rotation::prev()), // spread_b_lo - meta.query_advice(a_5, Rotation::prev()), // b_hi - meta.query_advice(a_6, Rotation::prev()), // spread_b_hi - meta.query_advice(a_4, Rotation::cur()), // spread_c - meta.query_advice(a_5, Rotation::cur()), // spread_d - ) - }); - - // sigma_0 v2 on W_[14..49] - // (3, 4, 3, 7, 1, 1, 13)-bit chunks - meta.create_gate("sigma_0 v2", |meta| { - ScheduleGate::s_lower_sigma_0_v2( - meta.query_selector(s_lower_sigma_0_v2), - meta.query_advice(a_2, Rotation::prev()), // spread_r0_even - meta.query_advice(a_2, Rotation::cur()), // spread_r0_odd - meta.query_advice(a_2, Rotation::next()), // spread_r1_even - meta.query_advice(a_3, Rotation::cur()), // spread_r1_odd - meta.query_advice(a_3, Rotation::next()), // a - meta.query_advice(a_4, Rotation::next()), // spread_a - meta.query_advice(a_6, Rotation::cur()), // b - meta.query_advice(a_3, Rotation::prev()), // b_lo - meta.query_advice(a_4, Rotation::prev()), // spread_b_lo - meta.query_advice(a_5, Rotation::prev()), // b_hi - meta.query_advice(a_6, Rotation::prev()), // spread_b_hi - meta.query_advice(a_5, Rotation::next()), // c - meta.query_advice(a_6, Rotation::next()), // spread_c - meta.query_advice(a_4, Rotation::cur()), // spread_d - meta.query_advice(a_7, Rotation::cur()), // spread_e - meta.query_advice(a_7, Rotation::next()), // spread_f - meta.query_advice(a_5, Rotation::cur()), // spread_g - ) - }); - - // sigma_1 v2 on W_14 to W_48 - // (3, 4, 3, 7, 1, 1, 13)-bit chunks - meta.create_gate("sigma_1 v2", |meta| { - ScheduleGate::s_lower_sigma_1_v2( - meta.query_selector(s_lower_sigma_1_v2), - meta.query_advice(a_2, Rotation::prev()), // spread_r0_even - meta.query_advice(a_2, Rotation::cur()), // spread_r0_odd - meta.query_advice(a_2, Rotation::next()), // spread_r1_even - meta.query_advice(a_3, Rotation::cur()), // spread_r1_odd - meta.query_advice(a_3, Rotation::next()), // a - meta.query_advice(a_4, Rotation::next()), // spread_a - meta.query_advice(a_6, Rotation::cur()), // b - meta.query_advice(a_3, Rotation::prev()), // b_lo - meta.query_advice(a_4, Rotation::prev()), // spread_b_lo - meta.query_advice(a_5, Rotation::prev()), // b_hi - meta.query_advice(a_6, Rotation::prev()), // spread_b_hi - meta.query_advice(a_5, Rotation::next()), // c - meta.query_advice(a_6, Rotation::next()), // spread_c - meta.query_advice(a_4, Rotation::cur()), // spread_d - meta.query_advice(a_7, Rotation::cur()), // spread_e - meta.query_advice(a_7, Rotation::next()), // spread_f - meta.query_advice(a_5, Rotation::cur()), // spread_g - ) - }); - - // sigma_1 v1 on W_49 to W_61 - // (10, 7, 2, 13)-bit chunks - meta.create_gate("sigma_1 v1", |meta| { - ScheduleGate::s_lower_sigma_1( - meta.query_selector(s_lower_sigma_1), - meta.query_advice(a_2, Rotation::prev()), // spread_r0_even - meta.query_advice(a_2, Rotation::cur()), // spread_r0_odd - meta.query_advice(a_2, Rotation::next()), // spread_r1_even - meta.query_advice(a_3, Rotation::cur()), // spread_r1_odd - meta.query_advice(a_4, Rotation::cur()), // spread_a - meta.query_advice(a_6, Rotation::cur()), // b - meta.query_advice(a_3, Rotation::prev()), // b_lo - meta.query_advice(a_4, Rotation::prev()), // spread_b_lo - meta.query_advice(a_5, Rotation::prev()), // b_mid - meta.query_advice(a_6, Rotation::prev()), // spread_b_mid - meta.query_advice(a_5, Rotation::next()), // b_hi - meta.query_advice(a_6, Rotation::next()), // spread_b_hi - meta.query_advice(a_3, Rotation::next()), // c - meta.query_advice(a_4, Rotation::next()), // spread_c - meta.query_advice(a_5, Rotation::cur()), // spread_d - ) - }); - - MessageScheduleConfig { - lookup, - message_schedule, - extras, - s_word, - s_decompose_0, - s_decompose_1, - s_decompose_2, - s_decompose_3, - s_lower_sigma_0, - s_lower_sigma_1, - s_lower_sigma_0_v2, - s_lower_sigma_1_v2, - } - } - - #[allow(clippy::type_complexity)] - pub(super) fn process( - &self, - layouter: &mut impl Layouter, - input: [BlockWord; BLOCK_SIZE], - ) -> Result< - ( - [MessageWord; ROUNDS], - [(AssignedBits<16>, AssignedBits<16>); ROUNDS], - ), - Error, - > { - let mut w = Vec::::with_capacity(ROUNDS); - let mut w_halves = Vec::<(AssignedBits<16>, AssignedBits<16>)>::with_capacity(ROUNDS); - - layouter.assign_region( - || "process message block", - |mut region| { - w = Vec::::with_capacity(ROUNDS); - w_halves = Vec::<(AssignedBits<16>, AssignedBits<16>)>::with_capacity(ROUNDS); - - // Assign all fixed columns - for index in 1..14 { - let row = get_word_row(index); - self.s_decompose_1.enable(&mut region, row)?; - self.s_lower_sigma_0.enable(&mut region, row + 3)?; - } - - for index in 14..49 { - let row = get_word_row(index); - self.s_decompose_2.enable(&mut region, row)?; - self.s_lower_sigma_0_v2.enable(&mut region, row + 3)?; - self.s_lower_sigma_1_v2 - .enable(&mut region, row + SIGMA_0_V2_ROWS + 3)?; - - let new_word_idx = index + 2; - self.s_word - .enable(&mut region, get_word_row(new_word_idx - 16) + 1)?; - } - - for index in 49..62 { - let row = get_word_row(index); - self.s_decompose_3.enable(&mut region, row)?; - self.s_lower_sigma_1.enable(&mut region, row + 3)?; - - let new_word_idx = index + 2; - self.s_word - .enable(&mut region, get_word_row(new_word_idx - 16) + 1)?; - } - - for index in 0..64 { - let row = get_word_row(index); - self.s_decompose_0.enable(&mut region, row)?; - } - - // Assign W[0..16] - for (i, word) in input.iter().enumerate() { - let (word, halves) = self.assign_word_and_halves(&mut region, word.0, i)?; - w.push(MessageWord(word)); - w_halves.push(halves); - } - - // Returns the output of sigma_0 on W_[1..14] - let lower_sigma_0_output = self.assign_subregion1(&mut region, &input[1..14])?; - - // sigma_0_v2 and sigma_1_v2 on W_[14..49] - // Returns the output of sigma_0_v2 on W_[36..49], to be used in subregion3 - let lower_sigma_0_v2_output = self.assign_subregion2( - &mut region, - lower_sigma_0_output, - &mut w, - &mut w_halves, - )?; - - // sigma_1 v1 on W[49..62] - self.assign_subregion3( - &mut region, - lower_sigma_0_v2_output, - &mut w, - &mut w_halves, - )?; - - Ok(()) - }, - )?; - - Ok((w.try_into().unwrap(), w_halves.try_into().unwrap())) - } -} - -#[cfg(test)] -mod tests { - use super::super::{ - super::BLOCK_SIZE, util::lebs2ip, BlockWord, SpreadTableChip, Table16Chip, Table16Config, - }; - use super::schedule_util::*; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use halo2curves::pasta::pallas; - - #[test] - fn message_schedule() { - struct MyCircuit {} - - impl Circuit for MyCircuit { - type Config = Table16Config; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - MyCircuit {} - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - Table16Chip::configure(meta) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Load lookup table - SpreadTableChip::load(config.lookup.clone(), &mut layouter)?; - - // Provide input - // Test vector: "abc" - let inputs: [BlockWord; BLOCK_SIZE] = msg_schedule_test_input(); - - // Run message_scheduler to get W_[0..64] - let (w, _) = config.message_schedule.process(&mut layouter, inputs)?; - for (word, test_word) in w.iter().zip(MSG_SCHEDULE_TEST_OUTPUT.iter()) { - word.value().assert_if_known(|bits| { - let word: u32 = lebs2ip(bits) as u32; - word == *test_word - }); - } - Ok(()) - } - } - - let circuit: MyCircuit = MyCircuit {}; - - let prover = match MockProver::::run(17, &circuit, vec![]) { - Ok(prover) => prover, - Err(e) => panic!("{:?}", e), - }; - assert_eq!(prover.verify(), Ok(())); - } -} diff --git a/halo2_gadgets/src/sha256/table16/message_schedule/schedule_gates.rs b/halo2_gadgets/src/sha256/table16/message_schedule/schedule_gates.rs deleted file mode 100644 index fab51bd373..0000000000 --- a/halo2_gadgets/src/sha256/table16/message_schedule/schedule_gates.rs +++ /dev/null @@ -1,396 +0,0 @@ -use super::super::Gate; -use halo2_proofs::{arithmetic::FieldExt, plonk::Expression}; -use std::marker::PhantomData; - -pub struct ScheduleGate(PhantomData); - -impl ScheduleGate { - /// s_word for W_16 to W_63 - #[allow(clippy::too_many_arguments)] - pub fn s_word( - s_word: Expression, - sigma_0_lo: Expression, - sigma_0_hi: Expression, - sigma_1_lo: Expression, - sigma_1_hi: Expression, - w_minus_9_lo: Expression, - w_minus_9_hi: Expression, - w_minus_16_lo: Expression, - w_minus_16_hi: Expression, - word: Expression, - carry: Expression, - ) -> impl Iterator)> { - let lo = sigma_0_lo + sigma_1_lo + w_minus_9_lo + w_minus_16_lo; - let hi = sigma_0_hi + sigma_1_hi + w_minus_9_hi + w_minus_16_hi; - - let word_check = lo - + hi * F::from(1 << 16) - + (carry.clone() * F::from(1 << 32) * (-F::one())) - + (word * (-F::one())); - let carry_check = Gate::range_check(carry, 0, 3); - - [("word_check", word_check), ("carry_check", carry_check)] - .into_iter() - .map(move |(name, poly)| (name, s_word.clone() * poly)) - } - - /// s_decompose_0 for all words - pub fn s_decompose_0( - s_decompose_0: Expression, - lo: Expression, - hi: Expression, - word: Expression, - ) -> Option<(&'static str, Expression)> { - let check = lo + hi * F::from(1 << 16) - word; - Some(("s_decompose_0", s_decompose_0 * check)) - } - - /// s_decompose_1 for W_1 to W_13 - /// (3, 4, 11, 14)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_decompose_1( - s_decompose_1: Expression, - a: Expression, - b: Expression, - c: Expression, - tag_c: Expression, - d: Expression, - tag_d: Expression, - word: Expression, - ) -> impl Iterator)> { - let decompose_check = a - + b * F::from(1 << 3) - + c * F::from(1 << 7) - + d * F::from(1 << 18) - + word * (-F::one()); - let range_check_tag_c = Gate::range_check(tag_c, 0, 2); - let range_check_tag_d = Gate::range_check(tag_d, 0, 4); - - [ - ("decompose_check", decompose_check), - ("range_check_tag_c", range_check_tag_c), - ("range_check_tag_d", range_check_tag_d), - ] - .into_iter() - .map(move |(name, poly)| (name, s_decompose_1.clone() * poly)) - } - - /// s_decompose_2 for W_14 to W_48 - /// (3, 4, 3, 7, 1, 1, 13)-bit chunks - #[allow(clippy::many_single_char_names)] - #[allow(clippy::too_many_arguments)] - pub fn s_decompose_2( - s_decompose_2: Expression, - a: Expression, - b: Expression, - c: Expression, - d: Expression, - tag_d: Expression, - e: Expression, - f: Expression, - g: Expression, - tag_g: Expression, - word: Expression, - ) -> impl Iterator)> { - let decompose_check = a - + b * F::from(1 << 3) - + c * F::from(1 << 7) - + d * F::from(1 << 10) - + e * F::from(1 << 17) - + f * F::from(1 << 18) - + g * F::from(1 << 19) - + word * (-F::one()); - let range_check_tag_d = Gate::range_check(tag_d, 0, 0); - let range_check_tag_g = Gate::range_check(tag_g, 0, 3); - - [ - ("decompose_check", decompose_check), - ("range_check_tag_g", range_check_tag_g), - ("range_check_tag_d", range_check_tag_d), - ] - .into_iter() - .map(move |(name, poly)| (name, s_decompose_2.clone() * poly)) - } - - /// s_decompose_3 for W_49 to W_61 - /// (10, 7, 2, 13)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_decompose_3( - s_decompose_3: Expression, - a: Expression, - tag_a: Expression, - b: Expression, - c: Expression, - d: Expression, - tag_d: Expression, - word: Expression, - ) -> impl Iterator)> { - let decompose_check = a - + b * F::from(1 << 10) - + c * F::from(1 << 17) - + d * F::from(1 << 19) - + word * (-F::one()); - let range_check_tag_a = Gate::range_check(tag_a, 0, 1); - let range_check_tag_d = Gate::range_check(tag_d, 0, 3); - - [ - ("decompose_check", decompose_check), - ("range_check_tag_a", range_check_tag_a), - ("range_check_tag_d", range_check_tag_d), - ] - .into_iter() - .map(move |(name, poly)| (name, s_decompose_3.clone() * poly)) - } - - /// b_lo + 2^2 * b_mid = b, on W_[1..49] - fn check_b(b: Expression, b_lo: Expression, b_hi: Expression) -> Expression { - let expected_b = b_lo + b_hi * F::from(1 << 2); - expected_b - b - } - - /// sigma_0 v1 on W_1 to W_13 - /// (3, 4, 11, 14)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_lower_sigma_0( - s_lower_sigma_0: Expression, - spread_r0_even: Expression, - spread_r0_odd: Expression, - spread_r1_even: Expression, - spread_r1_odd: Expression, - a: Expression, - spread_a: Expression, - b: Expression, - b_lo: Expression, - spread_b_lo: Expression, - b_hi: Expression, - spread_b_hi: Expression, - spread_c: Expression, - spread_d: Expression, - ) -> impl Iterator)> { - let check_spread_and_range = - Gate::two_bit_spread_and_range(b_lo.clone(), spread_b_lo.clone()) - .chain(Gate::two_bit_spread_and_range( - b_hi.clone(), - spread_b_hi.clone(), - )) - .chain(Gate::three_bit_spread_and_range(a, spread_a.clone())); - let check_b = Self::check_b(b, b_lo, b_hi); - let spread_witness = spread_r0_even - + spread_r0_odd * F::from(2) - + (spread_r1_even + spread_r1_odd * F::from(2)) * F::from(1 << 32); - let xor_0 = spread_b_lo.clone() - + spread_b_hi.clone() * F::from(1 << 4) - + spread_c.clone() * F::from(1 << 8) - + spread_d.clone() * F::from(1 << 30); - let xor_1 = spread_c.clone() - + spread_d.clone() * F::from(1 << 22) - + spread_a.clone() * F::from(1 << 50) - + spread_b_lo.clone() * F::from(1 << 56) - + spread_b_hi.clone() * F::from(1 << 60); - let xor_2 = spread_d - + spread_a * F::from(1 << 28) - + spread_b_lo * F::from(1 << 34) - + spread_b_hi * F::from(1 << 38) - + spread_c * F::from(1 << 42); - let xor = xor_0 + xor_1 + xor_2; - - check_spread_and_range - .chain(Some(("check_b", check_b))) - .chain(Some(("lower_sigma_0", spread_witness - xor))) - .map(move |(name, poly)| (name, s_lower_sigma_0.clone() * poly)) - } - - /// sigma_1 v1 on W_49 to W_61 - /// (10, 7, 2, 13)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_lower_sigma_1( - s_lower_sigma_1: Expression, - spread_r0_even: Expression, - spread_r0_odd: Expression, - spread_r1_even: Expression, - spread_r1_odd: Expression, - spread_a: Expression, - b: Expression, - b_lo: Expression, - spread_b_lo: Expression, - b_mid: Expression, - spread_b_mid: Expression, - b_hi: Expression, - spread_b_hi: Expression, - c: Expression, - spread_c: Expression, - spread_d: Expression, - ) -> impl Iterator)> { - let check_spread_and_range = - Gate::two_bit_spread_and_range(b_lo.clone(), spread_b_lo.clone()) - .chain(Gate::two_bit_spread_and_range( - b_mid.clone(), - spread_b_mid.clone(), - )) - .chain(Gate::two_bit_spread_and_range(c, spread_c.clone())) - .chain(Gate::three_bit_spread_and_range( - b_hi.clone(), - spread_b_hi.clone(), - )); - // b_lo + 2^2 * b_mid + 2^4 * b_hi = b, on W_[49..62] - let check_b1 = { - let expected_b = b_lo + b_mid * F::from(1 << 2) + b_hi * F::from(1 << 4); - expected_b - b - }; - let spread_witness = spread_r0_even - + spread_r0_odd * F::from(2) - + (spread_r1_even + spread_r1_odd * F::from(2)) * F::from(1 << 32); - let xor_0 = spread_b_lo.clone() - + spread_b_mid.clone() * F::from(1 << 4) - + spread_b_hi.clone() * F::from(1 << 8) - + spread_c.clone() * F::from(1 << 14) - + spread_d.clone() * F::from(1 << 18); - let xor_1 = spread_c.clone() - + spread_d.clone() * F::from(1 << 4) - + spread_a.clone() * F::from(1 << 30) - + spread_b_lo.clone() * F::from(1 << 50) - + spread_b_mid.clone() * F::from(1 << 54) - + spread_b_hi.clone() * F::from(1 << 58); - let xor_2 = spread_d - + spread_a * F::from(1 << 26) - + spread_b_lo * F::from(1 << 46) - + spread_b_mid * F::from(1 << 50) - + spread_b_hi * F::from(1 << 54) - + spread_c * F::from(1 << 60); - let xor = xor_0 + xor_1 + xor_2; - - check_spread_and_range - .chain(Some(("check_b1", check_b1))) - .chain(Some(("lower_sigma_1", spread_witness - xor))) - .map(move |(name, poly)| (name, s_lower_sigma_1.clone() * poly)) - } - - /// sigma_0 v2 on W_14 to W_48 - /// (3, 4, 3, 7, 1, 1, 13)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_lower_sigma_0_v2( - s_lower_sigma_0_v2: Expression, - spread_r0_even: Expression, - spread_r0_odd: Expression, - spread_r1_even: Expression, - spread_r1_odd: Expression, - a: Expression, - spread_a: Expression, - b: Expression, - b_lo: Expression, - spread_b_lo: Expression, - b_hi: Expression, - spread_b_hi: Expression, - c: Expression, - spread_c: Expression, - spread_d: Expression, - spread_e: Expression, - spread_f: Expression, - spread_g: Expression, - ) -> impl Iterator)> { - let check_spread_and_range = - Gate::two_bit_spread_and_range(b_lo.clone(), spread_b_lo.clone()) - .chain(Gate::two_bit_spread_and_range( - b_hi.clone(), - spread_b_hi.clone(), - )) - .chain(Gate::three_bit_spread_and_range(a, spread_a.clone())) - .chain(Gate::three_bit_spread_and_range(c, spread_c.clone())); - let check_b = Self::check_b(b, b_lo, b_hi); - let spread_witness = spread_r0_even - + spread_r0_odd * F::from(2) - + (spread_r1_even + spread_r1_odd * F::from(2)) * F::from(1 << 32); - let xor_0 = spread_b_lo.clone() - + spread_b_hi.clone() * F::from(1 << 4) - + spread_c.clone() * F::from(1 << 8) - + spread_d.clone() * F::from(1 << 14) - + spread_e.clone() * F::from(1 << 28) - + spread_f.clone() * F::from(1 << 30) - + spread_g.clone() * F::from(1 << 32); - let xor_1 = spread_c.clone() - + spread_d.clone() * F::from(1 << 6) - + spread_e.clone() * F::from(1 << 20) - + spread_f.clone() * F::from(1 << 22) - + spread_g.clone() * F::from(1 << 24) - + spread_a.clone() * F::from(1 << 50) - + spread_b_lo.clone() * F::from(1 << 56) - + spread_b_hi.clone() * F::from(1 << 60); - let xor_2 = spread_f - + spread_g * F::from(1 << 2) - + spread_a * F::from(1 << 28) - + spread_b_lo * F::from(1 << 34) - + spread_b_hi * F::from(1 << 38) - + spread_c * F::from(1 << 42) - + spread_d * F::from(1 << 48) - + spread_e * F::from(1 << 62); - let xor = xor_0 + xor_1 + xor_2; - - check_spread_and_range - .chain(Some(("check_b", check_b))) - .chain(Some(("lower_sigma_0_v2", spread_witness - xor))) - .map(move |(name, poly)| (name, s_lower_sigma_0_v2.clone() * poly)) - } - - /// sigma_1 v2 on W_14 to W_48 - /// (3, 4, 3, 7, 1, 1, 13)-bit chunks - #[allow(clippy::too_many_arguments)] - pub fn s_lower_sigma_1_v2( - s_lower_sigma_1_v2: Expression, - spread_r0_even: Expression, - spread_r0_odd: Expression, - spread_r1_even: Expression, - spread_r1_odd: Expression, - a: Expression, - spread_a: Expression, - b: Expression, - b_lo: Expression, - spread_b_lo: Expression, - b_hi: Expression, - spread_b_hi: Expression, - c: Expression, - spread_c: Expression, - spread_d: Expression, - spread_e: Expression, - spread_f: Expression, - spread_g: Expression, - ) -> impl Iterator)> { - let check_spread_and_range = - Gate::two_bit_spread_and_range(b_lo.clone(), spread_b_lo.clone()) - .chain(Gate::two_bit_spread_and_range( - b_hi.clone(), - spread_b_hi.clone(), - )) - .chain(Gate::three_bit_spread_and_range(a, spread_a.clone())) - .chain(Gate::three_bit_spread_and_range(c, spread_c.clone())); - let check_b = Self::check_b(b, b_lo, b_hi); - let spread_witness = spread_r0_even - + spread_r0_odd * F::from(2) - + (spread_r1_even + spread_r1_odd * F::from(2)) * F::from(1 << 32); - let xor_0 = spread_d.clone() - + spread_e.clone() * F::from(1 << 14) - + spread_f.clone() * F::from(1 << 16) - + spread_g.clone() * F::from(1 << 18); - let xor_1 = spread_e.clone() - + spread_f.clone() * F::from(1 << 2) - + spread_g.clone() * F::from(1 << 4) - + spread_a.clone() * F::from(1 << 30) - + spread_b_lo.clone() * F::from(1 << 36) - + spread_b_hi.clone() * F::from(1 << 40) - + spread_c.clone() * F::from(1 << 44) - + spread_d.clone() * F::from(1 << 50); - let xor_2 = spread_g - + spread_a * F::from(1 << 26) - + spread_b_lo * F::from(1 << 32) - + spread_b_hi * F::from(1 << 36) - + spread_c * F::from(1 << 40) - + spread_d * F::from(1 << 46) - + spread_e * F::from(1 << 60) - + spread_f * F::from(1 << 62); - let xor = xor_0 + xor_1 + xor_2; - - check_spread_and_range - .chain(Some(("check_b", check_b))) - .chain(Some(("lower_sigma_1_v2", spread_witness - xor))) - .map(move |(name, poly)| (name, s_lower_sigma_1_v2.clone() * poly)) - } -} diff --git a/halo2_gadgets/src/sha256/table16/message_schedule/schedule_util.rs b/halo2_gadgets/src/sha256/table16/message_schedule/schedule_util.rs deleted file mode 100644 index 79a9fa2621..0000000000 --- a/halo2_gadgets/src/sha256/table16/message_schedule/schedule_util.rs +++ /dev/null @@ -1,184 +0,0 @@ -use super::super::AssignedBits; -use super::MessageScheduleConfig; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::Error, -}; -use halo2curves::pasta::pallas; - -#[cfg(test)] -use super::super::{super::BLOCK_SIZE, BlockWord, ROUNDS}; - -// Rows needed for each gate -pub const DECOMPOSE_0_ROWS: usize = 2; -pub const DECOMPOSE_1_ROWS: usize = 2; -pub const DECOMPOSE_2_ROWS: usize = 3; -pub const DECOMPOSE_3_ROWS: usize = 2; -pub const SIGMA_0_V1_ROWS: usize = 4; -pub const SIGMA_0_V2_ROWS: usize = 4; -pub const SIGMA_1_V1_ROWS: usize = 4; -pub const SIGMA_1_V2_ROWS: usize = 4; - -// Rows needed for each subregion -pub const SUBREGION_0_LEN: usize = 1; // W_0 -pub const SUBREGION_0_ROWS: usize = SUBREGION_0_LEN * DECOMPOSE_0_ROWS; -pub const SUBREGION_1_WORD: usize = DECOMPOSE_1_ROWS + SIGMA_0_V1_ROWS; -pub const SUBREGION_1_LEN: usize = 13; // W_[1..14] -pub const SUBREGION_1_ROWS: usize = SUBREGION_1_LEN * SUBREGION_1_WORD; -pub const SUBREGION_2_WORD: usize = DECOMPOSE_2_ROWS + SIGMA_0_V2_ROWS + SIGMA_1_V2_ROWS; -pub const SUBREGION_2_LEN: usize = 35; // W_[14..49] -pub const SUBREGION_2_ROWS: usize = SUBREGION_2_LEN * SUBREGION_2_WORD; -pub const SUBREGION_3_WORD: usize = DECOMPOSE_3_ROWS + SIGMA_1_V1_ROWS; -pub const SUBREGION_3_LEN: usize = 13; // W[49..62] -pub const SUBREGION_3_ROWS: usize = SUBREGION_3_LEN * SUBREGION_3_WORD; -// pub const SUBREGION_4_LEN: usize = 2; // W_[62..64] -// pub const SUBREGION_4_ROWS: usize = SUBREGION_4_LEN * DECOMPOSE_0_ROWS; - -/// Returns row number of a word -pub fn get_word_row(word_idx: usize) -> usize { - assert!(word_idx <= 63); - if word_idx == 0 { - 0 - } else if (1..=13).contains(&word_idx) { - SUBREGION_0_ROWS + SUBREGION_1_WORD * (word_idx - 1) as usize - } else if (14..=48).contains(&word_idx) { - SUBREGION_0_ROWS + SUBREGION_1_ROWS + SUBREGION_2_WORD * (word_idx - 14) + 1 - } else if (49..=61).contains(&word_idx) { - SUBREGION_0_ROWS - + SUBREGION_1_ROWS - + SUBREGION_2_ROWS - + SUBREGION_3_WORD * (word_idx - 49) as usize - } else { - SUBREGION_0_ROWS - + SUBREGION_1_ROWS - + SUBREGION_2_ROWS - + SUBREGION_3_ROWS - + DECOMPOSE_0_ROWS * (word_idx - 62) as usize - } -} - -/// Test vector: "abc" -#[cfg(test)] -pub fn msg_schedule_test_input() -> [BlockWord; BLOCK_SIZE] { - [ - BlockWord(Value::known(0b01100001011000100110001110000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000000000)), - BlockWord(Value::known(0b00000000000000000000000000011000)), - ] -} - -#[cfg(test)] -pub const MSG_SCHEDULE_TEST_OUTPUT: [u32; ROUNDS] = [ - 0b01100001011000100110001110000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000000000, - 0b00000000000000000000000000011000, - 0b01100001011000100110001110000000, - 0b00000000000011110000000000000000, - 0b01111101101010000110010000000101, - 0b01100000000000000000001111000110, - 0b00111110100111010111101101111000, - 0b00000001100000111111110000000000, - 0b00010010110111001011111111011011, - 0b11100010111000101100001110001110, - 0b11001000001000010101110000011010, - 0b10110111001101100111100110100010, - 0b11100101101111000011100100001001, - 0b00110010011001100011110001011011, - 0b10011101001000001001110101100111, - 0b11101100100001110010011011001011, - 0b01110000001000010011100010100100, - 0b11010011101101111001011100111011, - 0b10010011111101011001100101111111, - 0b00111011011010001011101001110011, - 0b10101111111101001111111111000001, - 0b11110001000010100101110001100010, - 0b00001010100010110011100110010110, - 0b01110010101011111000001100001010, - 0b10010100000010011110001100111110, - 0b00100100011001000001010100100010, - 0b10011111010001111011111110010100, - 0b11110000101001100100111101011010, - 0b00111110001001000110101001111001, - 0b00100111001100110011101110100011, - 0b00001100010001110110001111110010, - 0b10000100000010101011111100100111, - 0b01111010001010010000110101011101, - 0b00000110010111000100001111011010, - 0b11111011001111101000100111001011, - 0b11001100011101100001011111011011, - 0b10111001111001100110110000110100, - 0b10101001100110010011011001100111, - 0b10000100101110101101111011011101, - 0b11000010000101000110001010111100, - 0b00010100100001110100011100101100, - 0b10110010000011110111101010011001, - 0b11101111010101111011100111001101, - 0b11101011111001101011001000111000, - 0b10011111111000110000100101011110, - 0b01111000101111001000110101001011, - 0b10100100001111111100111100010101, - 0b01100110100010110010111111111000, - 0b11101110101010111010001011001100, - 0b00010010101100011110110111101011, -]; - -impl MessageScheduleConfig { - // Assign a word and its hi and lo halves - pub fn assign_word_and_halves( - &self, - region: &mut Region<'_, pallas::Base>, - word: Value, - word_idx: usize, - ) -> Result<(AssignedBits<32>, (AssignedBits<16>, AssignedBits<16>)), Error> { - // Rename these here for ease of matching the gates to the specification. - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - - let row = get_word_row(word_idx); - - let w_lo = { - let w_lo_val = word.map(|word| word as u16); - AssignedBits::<16>::assign(region, || format!("W_{}_lo", word_idx), a_3, row, w_lo_val)? - }; - let w_hi = { - let w_hi_val = word.map(|word| (word >> 16) as u16); - AssignedBits::<16>::assign(region, || format!("W_{}_hi", word_idx), a_4, row, w_hi_val)? - }; - - let word = AssignedBits::<32>::assign( - region, - || format!("W_{}", word_idx), - self.message_schedule, - row, - word, - )?; - - Ok((word, (w_lo, w_hi))) - } -} diff --git a/halo2_gadgets/src/sha256/table16/message_schedule/subregion1.rs b/halo2_gadgets/src/sha256/table16/message_schedule/subregion1.rs deleted file mode 100644 index 947c9dda2a..0000000000 --- a/halo2_gadgets/src/sha256/table16/message_schedule/subregion1.rs +++ /dev/null @@ -1,223 +0,0 @@ -use super::super::{util::*, AssignedBits, BlockWord, SpreadVar, SpreadWord, Table16Assignment}; -use super::{schedule_util::*, MessageScheduleConfig}; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::Error, -}; -use halo2curves::pasta::pallas; -use std::convert::TryInto; - -// A word in subregion 1 -// (3, 4, 11, 14)-bit chunks -#[derive(Debug)] -pub struct Subregion1Word { - index: usize, - a: AssignedBits<3>, - b: AssignedBits<4>, - c: AssignedBits<11>, - d: AssignedBits<14>, - spread_c: AssignedBits<22>, - spread_d: AssignedBits<28>, -} - -impl Subregion1Word { - fn spread_a(&self) -> Value<[bool; 6]> { - self.a.value().map(|v| v.spread()) - } - - fn spread_b(&self) -> Value<[bool; 8]> { - self.b.value().map(|v| v.spread()) - } - - fn spread_c(&self) -> Value<[bool; 22]> { - self.spread_c.value().map(|v| v.0) - } - - fn spread_d(&self) -> Value<[bool; 28]> { - self.spread_d.value().map(|v| v.0) - } - - fn xor_lower_sigma_0(&self) -> Value<[bool; 64]> { - self.spread_a() - .zip(self.spread_b()) - .zip(self.spread_c()) - .zip(self.spread_d()) - .map(|(((a, b), c), d)| { - let xor_0 = b - .iter() - .chain(c.iter()) - .chain(d.iter()) - .chain(std::iter::repeat(&false).take(6)) - .copied() - .collect::>(); - let xor_1 = c - .iter() - .chain(d.iter()) - .chain(a.iter()) - .chain(b.iter()) - .copied() - .collect::>(); - let xor_2 = d - .iter() - .chain(a.iter()) - .chain(b.iter()) - .chain(c.iter()) - .copied() - .collect::>(); - - let xor_0 = lebs2ip::<64>(&xor_0.try_into().unwrap()); - let xor_1 = lebs2ip::<64>(&xor_1.try_into().unwrap()); - let xor_2 = lebs2ip::<64>(&xor_2.try_into().unwrap()); - - i2lebsp(xor_0 + xor_1 + xor_2) - }) - } -} - -impl MessageScheduleConfig { - pub fn assign_subregion1( - &self, - region: &mut Region<'_, pallas::Base>, - input: &[BlockWord], - ) -> Result, AssignedBits<16>)>, Error> { - assert_eq!(input.len(), SUBREGION_1_LEN); - Ok(input - .iter() - .enumerate() - .map(|(idx, word)| { - // s_decompose_1 on W_[1..14] - let subregion1_word = self - .decompose_subregion1_word( - region, - word.0.map(|word| i2lebsp(word.into())), - idx + 1, - ) - .unwrap(); - - // lower_sigma_0 on W_[1..14] - self.lower_sigma_0(region, subregion1_word).unwrap() - }) - .collect::>()) - } - - /// Pieces of length [3, 4, 11, 14] - fn decompose_subregion1_word( - &self, - region: &mut Region<'_, pallas::Base>, - word: Value<[bool; 32]>, - index: usize, - ) -> Result { - let row = get_word_row(index); - - // Rename these here for ease of matching the gates to the specification. - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - - let pieces = word.map(|word| { - vec![ - word[0..3].to_vec(), - word[3..7].to_vec(), - word[7..18].to_vec(), - word[18..32].to_vec(), - ] - }); - let pieces = pieces.transpose_vec(4); - - // Assign `a` (3-bit piece) - let a = - AssignedBits::<3>::assign_bits(region, || "word_a", a_3, row + 1, pieces[0].clone())?; - // Assign `b` (4-bit piece) - let b = - AssignedBits::<4>::assign_bits(region, || "word_b", a_4, row + 1, pieces[1].clone())?; - - // Assign `c` (11-bit piece) lookup - let spread_c = pieces[2].clone().map(SpreadWord::try_new); - let spread_c = SpreadVar::with_lookup(region, &self.lookup, row + 1, spread_c)?; - - // Assign `d` (14-bit piece) lookup - let spread_d = pieces[3].clone().map(SpreadWord::try_new); - let spread_d = SpreadVar::with_lookup(region, &self.lookup, row, spread_d)?; - - Ok(Subregion1Word { - index, - a, - b, - c: spread_c.dense, - d: spread_d.dense, - spread_c: spread_c.spread, - spread_d: spread_d.spread, - }) - } - - // sigma_0 v1 on a word in W_1 to W_13 - // (3, 4, 11, 14)-bit chunks - fn lower_sigma_0( - &self, - region: &mut Region<'_, pallas::Base>, - word: Subregion1Word, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - - let row = get_word_row(word.index) + 3; - - // Assign `a` and copy constraint - word.a.copy_advice(|| "a", region, a_5, row + 1)?; - - // Witness `spread_a` - let spread_a = word.a.value().map(|bits| spread_bits(bits.0)); - AssignedBits::<6>::assign_bits(region, || "spread_a", a_6, row + 1, spread_a)?; - - // Split `b` (4-bit chunk) into `b_hi` and `b_lo` - // Assign `b_lo`, `spread_b_lo` - let b_lo: Value<[bool; 2]> = word.b.value().map(|b| b.0[..2].try_into().unwrap()); - let spread_b_lo = b_lo.map(spread_bits); - { - AssignedBits::<2>::assign_bits(region, || "b_lo", a_3, row - 1, b_lo)?; - - AssignedBits::<4>::assign_bits(region, || "spread_b_lo", a_4, row - 1, spread_b_lo)?; - }; - - // Split `b` (2-bit chunk) into `b_hi` and `b_lo` - // Assign `b_hi`, `spread_b_hi` - let b_hi: Value<[bool; 2]> = word.b.value().map(|b| b.0[2..].try_into().unwrap()); - let spread_b_hi = b_hi.map(spread_bits); - { - AssignedBits::<2>::assign_bits(region, || "b_hi", a_5, row - 1, b_hi)?; - - AssignedBits::<4>::assign_bits(region, || "spread_b_hi", a_6, row - 1, spread_b_hi)?; - }; - - // Assign `b` and copy constraint - word.b.copy_advice(|| "b", region, a_6, row)?; - - // Assign `spread_c` and copy constraint - word.spread_c.copy_advice(|| "spread_c", region, a_4, row)?; - - // Assign `spread_d` and copy constraint - word.spread_d.copy_advice(|| "spread_d", region, a_5, row)?; - - // Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - let r = word.xor_lower_sigma_0(); - let r_0: Value<[bool; 32]> = r.map(|r| r[..32].try_into().unwrap()); - let r_0_even = r_0.map(even_bits); - let r_0_odd = r_0.map(odd_bits); - - let r_1: Value<[bool; 32]> = r.map(|r| r[32..].try_into().unwrap()); - let r_1_even = r_1.map(even_bits); - let r_1_odd = r_1.map(odd_bits); - - self.assign_sigma_outputs( - region, - &self.lookup, - a_3, - row, - r_0_even, - r_0_odd, - r_1_even, - r_1_odd, - ) - } -} diff --git a/halo2_gadgets/src/sha256/table16/message_schedule/subregion2.rs b/halo2_gadgets/src/sha256/table16/message_schedule/subregion2.rs deleted file mode 100644 index 43e96c934f..0000000000 --- a/halo2_gadgets/src/sha256/table16/message_schedule/subregion2.rs +++ /dev/null @@ -1,487 +0,0 @@ -use super::super::{util::*, AssignedBits, Bits, SpreadVar, SpreadWord, Table16Assignment}; -use super::{schedule_util::*, MessageScheduleConfig, MessageWord}; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::Error, -}; -use halo2curves::pasta::pallas; -use std::convert::TryInto; - -/// A word in subregion 2 -/// (3, 4, 3, 7, 1, 1, 13)-bit chunks -#[derive(Clone, Debug)] -pub struct Subregion2Word { - index: usize, - a: AssignedBits<3>, - b: AssignedBits<4>, - c: AssignedBits<3>, - d: AssignedBits<7>, - e: AssignedBits<1>, - f: AssignedBits<1>, - g: AssignedBits<13>, - spread_d: AssignedBits<14>, - spread_g: AssignedBits<26>, -} - -impl Subregion2Word { - fn spread_a(&self) -> Value<[bool; 6]> { - self.a.value().map(|v| v.spread()) - } - - fn spread_b(&self) -> Value<[bool; 8]> { - self.b.value().map(|v| v.spread()) - } - - fn spread_c(&self) -> Value<[bool; 6]> { - self.c.value().map(|v| v.spread()) - } - - fn spread_d(&self) -> Value<[bool; 14]> { - self.spread_d.value().map(|v| v.0) - } - - fn spread_e(&self) -> Value<[bool; 2]> { - self.e.value().map(|v| v.spread()) - } - - fn spread_f(&self) -> Value<[bool; 2]> { - self.f.value().map(|v| v.spread()) - } - - fn spread_g(&self) -> Value<[bool; 26]> { - self.spread_g.value().map(|v| v.0) - } - - fn xor_sigma_0(&self) -> Value<[bool; 64]> { - self.spread_a() - .zip(self.spread_b()) - .zip(self.spread_c()) - .zip(self.spread_d()) - .zip(self.spread_e()) - .zip(self.spread_f()) - .zip(self.spread_g()) - .map(|((((((a, b), c), d), e), f), g)| { - let xor_0 = b - .iter() - .chain(c.iter()) - .chain(d.iter()) - .chain(e.iter()) - .chain(f.iter()) - .chain(g.iter()) - .chain(std::iter::repeat(&false).take(6)) - .copied() - .collect::>(); - - let xor_1 = c - .iter() - .chain(d.iter()) - .chain(e.iter()) - .chain(f.iter()) - .chain(g.iter()) - .chain(a.iter()) - .chain(b.iter()) - .copied() - .collect::>(); - - let xor_2 = f - .iter() - .chain(g.iter()) - .chain(a.iter()) - .chain(b.iter()) - .chain(c.iter()) - .chain(d.iter()) - .chain(e.iter()) - .copied() - .collect::>(); - - let xor_0 = lebs2ip::<64>(&xor_0.try_into().unwrap()); - let xor_1 = lebs2ip::<64>(&xor_1.try_into().unwrap()); - let xor_2 = lebs2ip::<64>(&xor_2.try_into().unwrap()); - - i2lebsp(xor_0 + xor_1 + xor_2) - }) - } - - fn xor_sigma_1(&self) -> Value<[bool; 64]> { - self.spread_a() - .zip(self.spread_b()) - .zip(self.spread_c()) - .zip(self.spread_d()) - .zip(self.spread_e()) - .zip(self.spread_f()) - .zip(self.spread_g()) - .map(|((((((a, b), c), d), e), f), g)| { - let xor_0 = d - .iter() - .chain(e.iter()) - .chain(f.iter()) - .chain(g.iter()) - .chain(std::iter::repeat(&false).take(20)) - .copied() - .collect::>(); - - let xor_1 = e - .iter() - .chain(f.iter()) - .chain(g.iter()) - .chain(a.iter()) - .chain(b.iter()) - .chain(c.iter()) - .chain(d.iter()) - .copied() - .collect::>(); - - let xor_2 = g - .iter() - .chain(a.iter()) - .chain(b.iter()) - .chain(c.iter()) - .chain(d.iter()) - .chain(e.iter()) - .chain(f.iter()) - .copied() - .collect::>(); - - let xor_0 = lebs2ip::<64>(&xor_0.try_into().unwrap()); - let xor_1 = lebs2ip::<64>(&xor_1.try_into().unwrap()); - let xor_2 = lebs2ip::<64>(&xor_2.try_into().unwrap()); - - i2lebsp(xor_0 + xor_1 + xor_2) - }) - } -} - -impl MessageScheduleConfig { - // W_[14..49] - pub fn assign_subregion2( - &self, - region: &mut Region<'_, pallas::Base>, - lower_sigma_0_output: Vec<(AssignedBits<16>, AssignedBits<16>)>, - w: &mut Vec, - w_halves: &mut Vec<(AssignedBits<16>, AssignedBits<16>)>, - ) -> Result, AssignedBits<16>)>, Error> { - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - let a_7 = self.extras[3]; - let a_8 = self.extras[4]; - let a_9 = self.extras[5]; - - let mut lower_sigma_0_v2_results = - Vec::<(AssignedBits<16>, AssignedBits<16>)>::with_capacity(SUBREGION_2_LEN); - let mut lower_sigma_1_v2_results = - Vec::<(AssignedBits<16>, AssignedBits<16>)>::with_capacity(SUBREGION_2_LEN); - - // Closure to compose new word - // W_i = sigma_1(W_{i - 2}) + W_{i - 7} + sigma_0(W_{i - 15}) + W_{i - 16} - // e.g. W_16 = sigma_1(W_14) + W_9 + sigma_0(W_1) + W_0 - - // sigma_0(W_[1..14]) will be used to get the new W_[16..29] - // sigma_0_v2(W_[14..36]) will be used to get the new W_[29..51] - // sigma_1_v2(W_[14..49]) will be used to get the W_[16..51] - // The lowest-index words involved will be W_[0..13] - let mut new_word = |idx: usize, - sigma_0_output: &(AssignedBits<16>, AssignedBits<16>)| - -> Result, AssignedBits<16>)>, Error> { - // Decompose word into (3, 4, 3, 7, 1, 1, 13)-bit chunks - let word = self.decompose_word(region, w[idx].value(), idx)?; - - // sigma_0 v2 and sigma_1 v2 on word - lower_sigma_0_v2_results.push(self.lower_sigma_0_v2(region, word.clone())?); - lower_sigma_1_v2_results.push(self.lower_sigma_1_v2(region, word)?); - - let new_word_idx = idx + 2; - - // Copy sigma_0(W_{i - 15}) output from Subregion 1 - sigma_0_output.0.copy_advice( - || format!("sigma_0(W_{})_lo", new_word_idx - 15), - region, - a_6, - get_word_row(new_word_idx - 16), - )?; - sigma_0_output.1.copy_advice( - || format!("sigma_0(W_{})_hi", new_word_idx - 15), - region, - a_6, - get_word_row(new_word_idx - 16) + 1, - )?; - - // Copy sigma_1(W_{i - 2}) - lower_sigma_1_v2_results[new_word_idx - 16].0.copy_advice( - || format!("sigma_1(W_{})_lo", new_word_idx - 2), - region, - a_7, - get_word_row(new_word_idx - 16), - )?; - lower_sigma_1_v2_results[new_word_idx - 16].1.copy_advice( - || format!("sigma_1(W_{})_hi", new_word_idx - 2), - region, - a_7, - get_word_row(new_word_idx - 16) + 1, - )?; - - // Copy W_{i - 7} - w_halves[new_word_idx - 7].0.copy_advice( - || format!("W_{}_lo", new_word_idx - 7), - region, - a_8, - get_word_row(new_word_idx - 16), - )?; - w_halves[new_word_idx - 7].1.copy_advice( - || format!("W_{}_hi", new_word_idx - 7), - region, - a_8, - get_word_row(new_word_idx - 16) + 1, - )?; - - // Calculate W_i, carry_i - let (word, carry) = sum_with_carry(vec![ - ( - lower_sigma_1_v2_results[new_word_idx - 16].0.value_u16(), - lower_sigma_1_v2_results[new_word_idx - 16].1.value_u16(), - ), - ( - w_halves[new_word_idx - 7].0.value_u16(), - w_halves[new_word_idx - 7].1.value_u16(), - ), - (sigma_0_output.0.value_u16(), sigma_0_output.1.value_u16()), - ( - w_halves[new_word_idx - 16].0.value_u16(), - w_halves[new_word_idx - 16].1.value_u16(), - ), - ]); - - // Assign W_i, carry_i - region.assign_advice( - || format!("W_{}", new_word_idx), - a_5, - get_word_row(new_word_idx - 16) + 1, - || word.map(|word| pallas::Base::from(word as u64)), - )?; - region.assign_advice( - || format!("carry_{}", new_word_idx), - a_9, - get_word_row(new_word_idx - 16) + 1, - || carry.map(|carry| pallas::Base::from(carry as u64)), - )?; - let (word, halves) = self.assign_word_and_halves(region, word, new_word_idx)?; - w.push(MessageWord(word)); - w_halves.push(halves); - - Ok(lower_sigma_0_v2_results.clone()) - }; - - let mut tmp_lower_sigma_0_v2_results: Vec<(AssignedBits<16>, AssignedBits<16>)> = - Vec::with_capacity(SUBREGION_2_LEN); - - // Use up all the output from Subregion 1 lower_sigma_0 - for i in 14..27 { - tmp_lower_sigma_0_v2_results = new_word(i, &lower_sigma_0_output[i - 14])?; - } - - for i in 27..49 { - tmp_lower_sigma_0_v2_results = - new_word(i, &tmp_lower_sigma_0_v2_results[i + 2 - 15 - 14])?; - } - - // Return lower_sigma_0_v2 output for W_[36..49] - Ok(lower_sigma_0_v2_results.split_off(36 - 14)) - } - - /// Pieces of length [3, 4, 3, 7, 1, 1, 13] - fn decompose_word( - &self, - region: &mut Region<'_, pallas::Base>, - word: Value<&Bits<32>>, - index: usize, - ) -> Result { - let row = get_word_row(index); - - let pieces = word.map(|word| { - vec![ - word[0..3].to_vec(), - word[3..7].to_vec(), - word[7..10].to_vec(), - word[10..17].to_vec(), - vec![word[17]], - vec![word[18]], - word[19..32].to_vec(), - ] - }); - let pieces = pieces.transpose_vec(7); - - // Rename these here for ease of matching the gates to the specification. - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - - // Assign `a` (3-bit piece) - let a = AssignedBits::<3>::assign_bits(region, || "a", a_3, row - 1, pieces[0].clone())?; - - // Assign `b` (4-bit piece) lookup - let spread_b: Value> = pieces[1].clone().map(SpreadWord::try_new); - let spread_b = SpreadVar::with_lookup(region, &self.lookup, row + 1, spread_b)?; - - // Assign `c` (3-bit piece) - let c = AssignedBits::<3>::assign_bits(region, || "c", a_4, row - 1, pieces[2].clone())?; - - // Assign `d` (7-bit piece) lookup - let spread_d: Value> = pieces[3].clone().map(SpreadWord::try_new); - let spread_d = SpreadVar::with_lookup(region, &self.lookup, row, spread_d)?; - - // Assign `e` (1-bit piece) - let e = AssignedBits::<1>::assign_bits(region, || "e", a_3, row + 1, pieces[4].clone())?; - - // Assign `f` (1-bit piece) - let f = AssignedBits::<1>::assign_bits(region, || "f", a_4, row + 1, pieces[5].clone())?; - - // Assign `g` (13-bit piece) lookup - let spread_g = pieces[6].clone().map(SpreadWord::try_new); - let spread_g = SpreadVar::with_lookup(region, &self.lookup, row - 1, spread_g)?; - - Ok(Subregion2Word { - index, - a, - b: spread_b.dense, - c, - d: spread_d.dense, - e, - f, - g: spread_g.dense, - spread_d: spread_d.spread, - spread_g: spread_g.spread, - }) - } - - /// A word in subregion 2 - /// (3, 4, 3, 7, 1, 1, 13)-bit chunks - #[allow(clippy::type_complexity)] - fn assign_lower_sigma_v2_pieces( - &self, - region: &mut Region<'_, pallas::Base>, - row: usize, - word: &Subregion2Word, - ) -> Result<(), Error> { - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - let a_7 = self.extras[3]; - - // Assign `a` and copy constraint - word.a.copy_advice(|| "a", region, a_3, row + 1)?; - - // Witness `spread_a` - AssignedBits::<6>::assign_bits(region, || "spread_a", a_4, row + 1, word.spread_a())?; - - // Split `b` (4-bit chunk) into `b_hi` and `b_lo` - // Assign `b_lo`, `spread_b_lo` - - let b_lo: Value<[bool; 2]> = word.b.value().map(|b| b.0[..2].try_into().unwrap()); - let spread_b_lo = b_lo.map(spread_bits); - { - AssignedBits::<2>::assign_bits(region, || "b_lo", a_3, row - 1, b_lo)?; - - AssignedBits::<4>::assign_bits(region, || "spread_b_lo", a_4, row - 1, spread_b_lo)?; - }; - - // Split `b` (2-bit chunk) into `b_hi` and `b_lo` - // Assign `b_hi`, `spread_b_hi` - let b_hi: Value<[bool; 2]> = word.b.value().map(|b| b.0[2..].try_into().unwrap()); - let spread_b_hi = b_hi.map(spread_bits); - { - AssignedBits::<2>::assign_bits(region, || "b_hi", a_5, row - 1, b_hi)?; - - AssignedBits::<4>::assign_bits(region, || "spread_b_hi", a_6, row - 1, spread_b_hi)?; - }; - - // Assign `b` and copy constraint - word.b.copy_advice(|| "b", region, a_6, row)?; - - // Assign `c` and copy constraint - word.c.copy_advice(|| "c", region, a_5, row + 1)?; - - // Witness `spread_c` - AssignedBits::<6>::assign_bits(region, || "spread_c", a_6, row + 1, word.spread_c())?; - - // Assign `spread_d` and copy constraint - word.spread_d.copy_advice(|| "spread_d", region, a_4, row)?; - - // Assign `e` and copy constraint - word.e.copy_advice(|| "e", region, a_7, row)?; - - // Assign `f` and copy constraint - word.f.copy_advice(|| "f", region, a_7, row + 1)?; - - // Assign `spread_g` and copy constraint - word.spread_g.copy_advice(|| "spread_g", region, a_5, row)?; - - Ok(()) - } - - fn lower_sigma_0_v2( - &self, - region: &mut Region<'_, pallas::Base>, - word: Subregion2Word, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let a_3 = self.extras[0]; - let row = get_word_row(word.index) + 3; - - // Assign lower sigma_v2 pieces - self.assign_lower_sigma_v2_pieces(region, row, &word)?; - - // Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - let r = word.xor_sigma_0(); - let r_0: Value<[bool; 32]> = r.map(|r| r[..32].try_into().unwrap()); - let r_0_even = r_0.map(even_bits); - let r_0_odd = r_0.map(odd_bits); - - let r_1: Value<[bool; 32]> = r.map(|r| r[32..].try_into().unwrap()); - let r_1_even = r_1.map(even_bits); - let r_1_odd = r_1.map(odd_bits); - - self.assign_sigma_outputs( - region, - &self.lookup, - a_3, - row, - r_0_even, - r_0_odd, - r_1_even, - r_1_odd, - ) - } - - fn lower_sigma_1_v2( - &self, - region: &mut Region<'_, pallas::Base>, - word: Subregion2Word, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let a_3 = self.extras[0]; - let row = get_word_row(word.index) + SIGMA_0_V2_ROWS + 3; - - // Assign lower sigma_v2 pieces - self.assign_lower_sigma_v2_pieces(region, row, &word)?; - - // (3, 4, 3, 7, 1, 1, 13) - // Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - // Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - let r = word.xor_sigma_1(); - let r_0: Value<[bool; 32]> = r.map(|r| r[..32].try_into().unwrap()); - let r_0_even = r_0.map(even_bits); - let r_0_odd = r_0.map(odd_bits); - - let r_1: Value<[bool; 32]> = r.map(|r| r[32..].try_into().unwrap()); - let r_1_even = r_1.map(even_bits); - let r_1_odd = r_1.map(odd_bits); - - self.assign_sigma_outputs( - region, - &self.lookup, - a_3, - row, - r_0_even, - r_0_odd, - r_1_even, - r_1_odd, - ) - } -} diff --git a/halo2_gadgets/src/sha256/table16/message_schedule/subregion3.rs b/halo2_gadgets/src/sha256/table16/message_schedule/subregion3.rs deleted file mode 100644 index b23046e42e..0000000000 --- a/halo2_gadgets/src/sha256/table16/message_schedule/subregion3.rs +++ /dev/null @@ -1,320 +0,0 @@ -use super::super::{util::*, AssignedBits, Bits, SpreadVar, SpreadWord, Table16Assignment}; -use super::{schedule_util::*, MessageScheduleConfig, MessageWord}; -use halo2_proofs::{ - circuit::{Region, Value}, - plonk::Error, -}; -use halo2curves::pasta::pallas; -use std::convert::TryInto; - -// A word in subregion 3 -// (10, 7, 2, 13)-bit chunks -pub struct Subregion3Word { - index: usize, - #[allow(dead_code)] - a: AssignedBits<10>, - b: AssignedBits<7>, - c: AssignedBits<2>, - #[allow(dead_code)] - d: AssignedBits<13>, - spread_a: AssignedBits<20>, - spread_d: AssignedBits<26>, -} - -impl Subregion3Word { - fn spread_a(&self) -> Value<[bool; 20]> { - self.spread_a.value().map(|v| v.0) - } - - fn spread_b(&self) -> Value<[bool; 14]> { - self.b.value().map(|v| v.spread()) - } - - fn spread_c(&self) -> Value<[bool; 4]> { - self.c.value().map(|v| v.spread()) - } - - fn spread_d(&self) -> Value<[bool; 26]> { - self.spread_d.value().map(|v| v.0) - } - - fn xor_lower_sigma_1(&self) -> Value<[bool; 64]> { - self.spread_a() - .zip(self.spread_b()) - .zip(self.spread_c()) - .zip(self.spread_d()) - .map(|(((a, b), c), d)| { - let xor_0 = b - .iter() - .chain(c.iter()) - .chain(d.iter()) - .chain(std::iter::repeat(&false).take(20)) - .copied() - .collect::>(); - - let xor_1 = c - .iter() - .chain(d.iter()) - .chain(a.iter()) - .chain(b.iter()) - .copied() - .collect::>(); - let xor_2 = d - .iter() - .chain(a.iter()) - .chain(b.iter()) - .chain(c.iter()) - .copied() - .collect::>(); - - let xor_0 = lebs2ip::<64>(&xor_0.try_into().unwrap()); - let xor_1 = lebs2ip::<64>(&xor_1.try_into().unwrap()); - let xor_2 = lebs2ip::<64>(&xor_2.try_into().unwrap()); - - i2lebsp(xor_0 + xor_1 + xor_2) - }) - } -} - -impl MessageScheduleConfig { - // W_[49..62] - pub fn assign_subregion3( - &self, - region: &mut Region<'_, pallas::Base>, - lower_sigma_0_v2_output: Vec<(AssignedBits<16>, AssignedBits<16>)>, - w: &mut Vec, - w_halves: &mut Vec<(AssignedBits<16>, AssignedBits<16>)>, - ) -> Result<(), Error> { - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - let a_7 = self.extras[3]; - let a_8 = self.extras[4]; - let a_9 = self.extras[5]; - - // Closure to compose new word - // W_i = sigma_1(W_{i - 2}) + W_{i - 7} + sigma_0(W_{i - 15}) + W_{i - 16} - // e.g. W_51 = sigma_1(W_49) + W_44 + sigma_0(W_36) + W_35 - - // sigma_0_v2(W_[36..49]) will be used to get the new W_[51..64] - // sigma_1(W_[49..62]) will also be used to get the W_[51..64] - // The lowest-index words involved will be W_[35..58] - let mut new_word = |idx: usize| -> Result<(), Error> { - // Decompose word into (10, 7, 2, 13)-bit chunks - let subregion3_word = self.decompose_subregion3_word(region, w[idx].value(), idx)?; - - // sigma_1 on subregion3_word - let (r_0_even, r_1_even) = self.lower_sigma_1(region, subregion3_word)?; - - let new_word_idx = idx + 2; - - // Copy sigma_0_v2(W_{i - 15}) output from Subregion 2 - lower_sigma_0_v2_output[idx - 49].0.copy_advice( - || format!("sigma_0(W_{})_lo", new_word_idx - 15), - region, - a_6, - get_word_row(new_word_idx - 16), - )?; - lower_sigma_0_v2_output[idx - 49].1.copy_advice( - || format!("sigma_0(W_{})_hi", new_word_idx - 15), - region, - a_6, - get_word_row(new_word_idx - 16) + 1, - )?; - - // Copy sigma_1(W_{i - 2}) - r_0_even.copy_advice( - || format!("sigma_1(W_{})_lo", new_word_idx - 2), - region, - a_7, - get_word_row(new_word_idx - 16), - )?; - r_1_even.copy_advice( - || format!("sigma_1(W_{})_hi", new_word_idx - 2), - region, - a_7, - get_word_row(new_word_idx - 16) + 1, - )?; - - // Copy W_{i - 7} - w_halves[new_word_idx - 7].0.copy_advice( - || format!("W_{}_lo", new_word_idx - 7), - region, - a_8, - get_word_row(new_word_idx - 16), - )?; - w_halves[new_word_idx - 7].1.copy_advice( - || format!("W_{}_hi", new_word_idx - 7), - region, - a_8, - get_word_row(new_word_idx - 16) + 1, - )?; - - // Calculate W_i, carry_i - let (word, carry) = sum_with_carry(vec![ - (r_0_even.value_u16(), r_1_even.value_u16()), - ( - w_halves[new_word_idx - 7].0.value_u16(), - w_halves[new_word_idx - 7].1.value_u16(), - ), - ( - lower_sigma_0_v2_output[idx - 49].0.value_u16(), - lower_sigma_0_v2_output[idx - 49].1.value_u16(), - ), - ( - w_halves[new_word_idx - 16].0.value_u16(), - w_halves[new_word_idx - 16].1.value_u16(), - ), - ]); - - // Assign W_i, carry_i - region.assign_advice( - || format!("W_{}", new_word_idx), - a_5, - get_word_row(new_word_idx - 16) + 1, - || word.map(|word| pallas::Base::from(word as u64)), - )?; - region.assign_advice( - || format!("carry_{}", new_word_idx), - a_9, - get_word_row(new_word_idx - 16) + 1, - || carry.map(|carry| pallas::Base::from(carry as u64)), - )?; - let (word, halves) = self.assign_word_and_halves(region, word, new_word_idx)?; - w.push(MessageWord(word)); - w_halves.push(halves); - - Ok(()) - }; - - for i in 49..62 { - new_word(i)?; - } - - Ok(()) - } - - /// Pieces of length [10, 7, 2, 13] - fn decompose_subregion3_word( - &self, - region: &mut Region<'_, pallas::Base>, - word: Value<&Bits<32>>, - index: usize, - ) -> Result { - let row = get_word_row(index); - - // Rename these here for ease of matching the gates to the specification. - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - - let pieces = word.map(|word| { - vec![ - word[0..10].to_vec(), - word[10..17].to_vec(), - word[17..19].to_vec(), - word[19..32].to_vec(), - ] - }); - let pieces = pieces.transpose_vec(4); - - // Assign `a` (10-bit piece) - let spread_a = pieces[0].clone().map(SpreadWord::try_new); - let spread_a = SpreadVar::with_lookup(region, &self.lookup, row + 1, spread_a)?; - - // Assign `b` (7-bit piece) - let b = AssignedBits::<7>::assign_bits(region, || "b", a_4, row + 1, pieces[1].clone())?; - - // Assign `c` (2-bit piece) - let c = AssignedBits::<2>::assign_bits(region, || "c", a_3, row + 1, pieces[2].clone())?; - - // Assign `d` (13-bit piece) lookup - let spread_d = pieces[3].clone().map(SpreadWord::try_new); - let spread_d = SpreadVar::with_lookup(region, &self.lookup, row, spread_d)?; - - Ok(Subregion3Word { - index, - a: spread_a.dense, - b, - c, - d: spread_d.dense, - spread_a: spread_a.spread, - spread_d: spread_d.spread, - }) - } - - fn lower_sigma_1( - &self, - region: &mut Region<'_, pallas::Base>, - word: Subregion3Word, - ) -> Result<(AssignedBits<16>, AssignedBits<16>), Error> { - let a_3 = self.extras[0]; - let a_4 = self.extras[1]; - let a_5 = self.message_schedule; - let a_6 = self.extras[2]; - - let row = get_word_row(word.index) + 3; - - // Assign `spread_a` and copy constraint - word.spread_a.copy_advice(|| "spread_a", region, a_4, row)?; - - // Split `b` (7-bit chunk) into (2, 2, 3)-bit `b_lo`, `b_mid` and `b_hi`. - // Assign `b_lo`, `spread_b_lo`, `b_mid`, `spread_b_mid`, `b_hi`, `spread_b_hi`. - - // b_lo (2-bit chunk) - { - let b_lo: Value<[bool; 2]> = word.b.value().map(|v| v[0..2].try_into().unwrap()); - let b_lo = b_lo.map(SpreadWord::<2, 4>::new); - SpreadVar::without_lookup(region, a_3, row - 1, a_4, row - 1, b_lo)?; - } - - // b_mid (2-bit chunk) - { - let b_mid: Value<[bool; 2]> = word.b.value().map(|v| v[2..4].try_into().unwrap()); - let b_mid = b_mid.map(SpreadWord::<2, 4>::new); - SpreadVar::without_lookup(region, a_5, row - 1, a_6, row - 1, b_mid)?; - } - - // b_hi (3-bit chunk) - { - let b_hi: Value<[bool; 3]> = word.b.value().map(|v| v[4..7].try_into().unwrap()); - let b_hi = b_hi.map(SpreadWord::<3, 6>::new); - SpreadVar::without_lookup(region, a_5, row + 1, a_6, row + 1, b_hi)?; - } - - // Assign `b` and copy constraint - word.b.copy_advice(|| "b", region, a_6, row)?; - - // Assign `c` and copy constraint - word.c.copy_advice(|| "c", region, a_3, row + 1)?; - - // Witness `spread_c` - { - let spread_c = word.c.value().map(spread_bits); - AssignedBits::<4>::assign_bits(region, || "spread_c", a_4, row + 1, spread_c)?; - } - - // Assign `spread_d` and copy constraint - word.spread_d.copy_advice(|| "spread_d", region, a_5, row)?; - - // (10, 7, 2, 13) - // Calculate R_0^{even}, R_0^{odd}, R_1^{even}, R_1^{odd} - let r = word.xor_lower_sigma_1(); - let r_0: Value<[bool; 32]> = r.map(|r| r[..32].try_into().unwrap()); - let r_0_even = r_0.map(even_bits); - let r_0_odd = r_0.map(odd_bits); - - let r_1: Value<[bool; 32]> = r.map(|r| r[32..].try_into().unwrap()); - let r_1_even = r_1.map(even_bits); - let r_1_odd = r_1.map(odd_bits); - - self.assign_sigma_outputs( - region, - &self.lookup, - a_3, - row, - r_0_even, - r_0_odd, - r_1_even, - r_1_odd, - ) - } -} diff --git a/halo2_gadgets/src/sha256/table16/spread_table.rs b/halo2_gadgets/src/sha256/table16/spread_table.rs deleted file mode 100644 index 3e1488e9ac..0000000000 --- a/halo2_gadgets/src/sha256/table16/spread_table.rs +++ /dev/null @@ -1,448 +0,0 @@ -use super::{util::*, AssignedBits}; -use halo2_proofs::{ - arithmetic::FieldExt, - circuit::{Chip, Layouter, Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Error, TableColumn}, - poly::Rotation, -}; -use halo2curves::pasta::pallas; -use std::convert::TryInto; -use std::marker::PhantomData; - -const BITS_7: usize = 1 << 7; -const BITS_10: usize = 1 << 10; -const BITS_11: usize = 1 << 11; -const BITS_13: usize = 1 << 13; -const BITS_14: usize = 1 << 14; - -/// An input word into a lookup, containing (tag, dense, spread) -#[derive(Copy, Clone, Debug)] -pub(super) struct SpreadWord { - pub tag: u8, - pub dense: [bool; DENSE], - pub spread: [bool; SPREAD], -} - -/// Helper function that returns tag of 16-bit input -pub fn get_tag(input: u16) -> u8 { - let input = input as usize; - if input < BITS_7 { - 0 - } else if input < BITS_10 { - 1 - } else if input < BITS_11 { - 2 - } else if input < BITS_13 { - 3 - } else if input < BITS_14 { - 4 - } else { - 5 - } -} - -impl SpreadWord { - pub(super) fn new(dense: [bool; DENSE]) -> Self { - assert!(DENSE <= 16); - SpreadWord { - tag: get_tag(lebs2ip(&dense) as u16), - dense, - spread: spread_bits(dense), - } - } - - pub(super) fn try_new + std::fmt::Debug>(dense: T) -> Self - where - >::Error: std::fmt::Debug, - { - assert!(DENSE <= 16); - let dense: [bool; DENSE] = dense.try_into().unwrap(); - SpreadWord { - tag: get_tag(lebs2ip(&dense) as u16), - dense, - spread: spread_bits(dense), - } - } -} - -/// A variable stored in advice columns corresponding to a row of [`SpreadTableConfig`]. -#[derive(Clone, Debug)] -pub(super) struct SpreadVar { - pub tag: Value, - pub dense: AssignedBits, - pub spread: AssignedBits, -} - -impl SpreadVar { - pub(super) fn with_lookup( - region: &mut Region<'_, pallas::Base>, - cols: &SpreadInputs, - row: usize, - word: Value>, - ) -> Result { - let tag = word.map(|word| word.tag); - let dense_val = word.map(|word| word.dense); - let spread_val = word.map(|word| word.spread); - - region.assign_advice( - || "tag", - cols.tag, - row, - || tag.map(|tag| pallas::Base::from(tag as u64)), - )?; - - let dense = - AssignedBits::::assign_bits(region, || "dense", cols.dense, row, dense_val)?; - - let spread = - AssignedBits::::assign_bits(region, || "spread", cols.spread, row, spread_val)?; - - Ok(SpreadVar { tag, dense, spread }) - } - - pub(super) fn without_lookup( - region: &mut Region<'_, pallas::Base>, - dense_col: Column, - dense_row: usize, - spread_col: Column, - spread_row: usize, - word: Value>, - ) -> Result { - let tag = word.map(|word| word.tag); - let dense_val = word.map(|word| word.dense); - let spread_val = word.map(|word| word.spread); - - let dense = AssignedBits::::assign_bits( - region, - || "dense", - dense_col, - dense_row, - dense_val, - )?; - - let spread = AssignedBits::::assign_bits( - region, - || "spread", - spread_col, - spread_row, - spread_val, - )?; - - Ok(SpreadVar { tag, dense, spread }) - } -} - -#[derive(Clone, Debug)] -pub(super) struct SpreadInputs { - pub(super) tag: Column, - pub(super) dense: Column, - pub(super) spread: Column, -} - -#[derive(Clone, Debug)] -pub(super) struct SpreadTable { - pub(super) tag: TableColumn, - pub(super) dense: TableColumn, - pub(super) spread: TableColumn, -} - -#[derive(Clone, Debug)] -pub(super) struct SpreadTableConfig { - pub input: SpreadInputs, - pub table: SpreadTable, -} - -#[derive(Clone, Debug)] -pub(super) struct SpreadTableChip { - config: SpreadTableConfig, - _marker: PhantomData, -} - -impl Chip for SpreadTableChip { - type Config = SpreadTableConfig; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -impl SpreadTableChip { - pub fn configure( - meta: &mut ConstraintSystem, - input_tag: Column, - input_dense: Column, - input_spread: Column, - ) -> >::Config { - let table_tag = meta.lookup_table_column(); - let table_dense = meta.lookup_table_column(); - let table_spread = meta.lookup_table_column(); - - meta.lookup("lookup", |meta| { - let tag_cur = meta.query_advice(input_tag, Rotation::cur()); - let dense_cur = meta.query_advice(input_dense, Rotation::cur()); - let spread_cur = meta.query_advice(input_spread, Rotation::cur()); - - vec![ - (tag_cur, table_tag), - (dense_cur, table_dense), - (spread_cur, table_spread), - ] - }); - - SpreadTableConfig { - input: SpreadInputs { - tag: input_tag, - dense: input_dense, - spread: input_spread, - }, - table: SpreadTable { - tag: table_tag, - dense: table_dense, - spread: table_spread, - }, - } - } - - pub fn load( - config: SpreadTableConfig, - layouter: &mut impl Layouter, - ) -> Result<>::Loaded, Error> { - layouter.assign_table( - || "spread table", - |mut table| { - // We generate the row values lazily (we only need them during keygen). - let mut rows = SpreadTableConfig::generate::(); - - for index in 0..(1 << 16) { - let mut row = None; - table.assign_cell( - || "tag", - config.table.tag, - index, - || { - row = rows.next(); - Value::known(row.map(|(tag, _, _)| tag).unwrap()) - }, - )?; - table.assign_cell( - || "dense", - config.table.dense, - index, - || Value::known(row.map(|(_, dense, _)| dense).unwrap()), - )?; - table.assign_cell( - || "spread", - config.table.spread, - index, - || Value::known(row.map(|(_, _, spread)| spread).unwrap()), - )?; - } - - Ok(()) - }, - ) - } -} - -impl SpreadTableConfig { - fn generate() -> impl Iterator { - (1..=(1 << 16)).scan( - (F::zero(), F::zero(), F::zero()), - |(tag, dense, spread), i| { - // We computed this table row in the previous iteration. - let res = (*tag, *dense, *spread); - - // i holds the zero-indexed row number for the next table row. - match i { - BITS_7 | BITS_10 | BITS_11 | BITS_13 | BITS_14 => *tag += F::one(), - _ => (), - } - *dense += F::one(); - if i & 1 == 0 { - // On even-numbered rows we recompute the spread. - *spread = F::zero(); - for b in 0..16 { - if (i >> b) & 1 != 0 { - *spread += F::from(1 << (2 * b)); - } - } - } else { - // On odd-numbered rows we add one. - *spread += F::one(); - } - - Some(res) - }, - ) - } -} - -#[cfg(test)] -mod tests { - use super::{get_tag, SpreadTableChip, SpreadTableConfig}; - use rand::Rng; - - use halo2_proofs::{ - arithmetic::FieldExt, - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Advice, Circuit, Column, ConstraintSystem, Error}, - }; - use halo2curves::pasta::Fp; - - #[test] - fn lookup_table() { - /// This represents an advice column at a certain row in the ConstraintSystem - #[derive(Copy, Clone, Debug)] - pub struct Variable(Column, usize); - - struct MyCircuit {} - - impl Circuit for MyCircuit { - type Config = SpreadTableConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - MyCircuit {} - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let input_tag = meta.advice_column(); - let input_dense = meta.advice_column(); - let input_spread = meta.advice_column(); - - SpreadTableChip::configure(meta, input_tag, input_dense, input_spread) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - SpreadTableChip::load(config.clone(), &mut layouter)?; - - layouter.assign_region( - || "spread_test", - |mut gate| { - let mut row = 0; - let mut add_row = |tag, dense, spread| -> Result<(), Error> { - gate.assign_advice( - || "tag", - config.input.tag, - row, - || Value::known(tag), - )?; - gate.assign_advice( - || "dense", - config.input.dense, - row, - || Value::known(dense), - )?; - gate.assign_advice( - || "spread", - config.input.spread, - row, - || Value::known(spread), - )?; - row += 1; - Ok(()) - }; - - // Test the first few small values. - add_row(F::zero(), F::from(0b000), F::from(0b000000))?; - add_row(F::zero(), F::from(0b001), F::from(0b000001))?; - add_row(F::zero(), F::from(0b010), F::from(0b000100))?; - add_row(F::zero(), F::from(0b011), F::from(0b000101))?; - add_row(F::zero(), F::from(0b100), F::from(0b010000))?; - add_row(F::zero(), F::from(0b101), F::from(0b010001))?; - - // Test the tag boundaries: - // 7-bit - add_row(F::zero(), F::from(0b1111111), F::from(0b01010101010101))?; - add_row(F::one(), F::from(0b10000000), F::from(0b0100000000000000))?; - // - 10-bit - add_row( - F::one(), - F::from(0b1111111111), - F::from(0b01010101010101010101), - )?; - add_row( - F::from(2), - F::from(0b10000000000), - F::from(0b0100000000000000000000), - )?; - // - 11-bit - add_row( - F::from(2), - F::from(0b11111111111), - F::from(0b0101010101010101010101), - )?; - add_row( - F::from(3), - F::from(0b100000000000), - F::from(0b010000000000000000000000), - )?; - // - 13-bit - add_row( - F::from(3), - F::from(0b1111111111111), - F::from(0b01010101010101010101010101), - )?; - add_row( - F::from(4), - F::from(0b10000000000000), - F::from(0b0100000000000000000000000000), - )?; - // - 14-bit - add_row( - F::from(4), - F::from(0b11111111111111), - F::from(0b0101010101010101010101010101), - )?; - add_row( - F::from(5), - F::from(0b100000000000000), - F::from(0b010000000000000000000000000000), - )?; - - // Test random lookup values - let mut rng = rand::thread_rng(); - - fn interleave_u16_with_zeros(word: u16) -> u32 { - let mut word: u32 = word.into(); - word = (word ^ (word << 8)) & 0x00ff00ff; - word = (word ^ (word << 4)) & 0x0f0f0f0f; - word = (word ^ (word << 2)) & 0x33333333; - word = (word ^ (word << 1)) & 0x55555555; - word - } - - for _ in 0..10 { - let word: u16 = rng.gen(); - add_row( - F::from(u64::from(get_tag(word))), - F::from(u64::from(word)), - F::from(u64::from(interleave_u16_with_zeros(word))), - )?; - } - - Ok(()) - }, - ) - } - } - - let circuit: MyCircuit = MyCircuit {}; - - let prover = match MockProver::::run(17, &circuit, vec![]) { - Ok(prover) => prover, - Err(e) => panic!("{:?}", e), - }; - assert_eq!(prover.verify(), Ok(())); - } -} diff --git a/halo2_gadgets/src/sha256/table16/util.rs b/halo2_gadgets/src/sha256/table16/util.rs deleted file mode 100644 index 6a790d3797..0000000000 --- a/halo2_gadgets/src/sha256/table16/util.rs +++ /dev/null @@ -1,117 +0,0 @@ -use halo2_proofs::circuit::Value; - -pub const MASK_EVEN_32: u32 = 0x55555555; - -/// The sequence of bits representing a u64 in little-endian order. -/// -/// # Panics -/// -/// Panics if the expected length of the sequence `NUM_BITS` exceeds -/// 64. -pub fn i2lebsp(int: u64) -> [bool; NUM_BITS] { - /// Takes in an FnMut closure and returns a constant-length array with elements of - /// type `Output`. - fn gen_const_array( - closure: impl FnMut(usize) -> Output, - ) -> [Output; LEN] { - gen_const_array_with_default(Default::default(), closure) - } - - fn gen_const_array_with_default( - default_value: Output, - closure: impl FnMut(usize) -> Output, - ) -> [Output; LEN] { - let mut ret: [Output; LEN] = [default_value; LEN]; - for (bit, val) in ret.iter_mut().zip((0..LEN).map(closure)) { - *bit = val; - } - ret - } - - assert!(NUM_BITS <= 64); - gen_const_array(|mask: usize| (int & (1 << mask)) != 0) -} - -/// Returns the integer representation of a little-endian bit-array. -/// Panics if the number of bits exceeds 64. -pub fn lebs2ip(bits: &[bool; K]) -> u64 { - assert!(K <= 64); - bits.iter() - .enumerate() - .fold(0u64, |acc, (i, b)| acc + if *b { 1 << i } else { 0 }) -} - -/// Helper function that interleaves a little-endian bit-array with zeros -/// in the odd indices. That is, it takes the array -/// [b_0, b_1, ..., b_n] -/// to -/// [b_0, 0, b_1, 0, ..., b_n, 0]. -/// Panics if bit-array is longer than 16 bits. -pub fn spread_bits( - bits: impl Into<[bool; DENSE]>, -) -> [bool; SPREAD] { - assert_eq!(DENSE * 2, SPREAD); - assert!(DENSE <= 16); - - let bits: [bool; DENSE] = bits.into(); - let mut spread = [false; SPREAD]; - - for (idx, bit) in bits.iter().enumerate() { - spread[idx * 2] = *bit; - } - - spread -} - -/// Negates the even bits in a spread bit-array. -pub fn negate_spread(arr: [bool; LEN]) -> [bool; LEN] { - assert_eq!(LEN % 2, 0); - - let mut neg = arr; - for even_idx in (0..LEN).step_by(2) { - let odd_idx = even_idx + 1; - assert!(!arr[odd_idx]); - - neg[even_idx] = !arr[even_idx]; - } - - neg -} - -/// Returns even bits in a bit-array -pub fn even_bits(bits: [bool; LEN]) -> [bool; HALF] { - assert_eq!(LEN % 2, 0); - let mut even_bits = [false; HALF]; - for idx in 0..HALF { - even_bits[idx] = bits[idx * 2] - } - even_bits -} - -/// Returns odd bits in a bit-array -pub fn odd_bits(bits: [bool; LEN]) -> [bool; HALF] { - assert_eq!(LEN % 2, 0); - let mut odd_bits = [false; HALF]; - for idx in 0..HALF { - odd_bits[idx] = bits[idx * 2 + 1] - } - odd_bits -} - -/// Given a vector of words as vec![(lo: u16, hi: u16)], returns their sum: u32, along -/// with a carry bit. -pub fn sum_with_carry(words: Vec<(Value, Value)>) -> (Value, Value) { - let words_lo: Value> = words.iter().map(|(lo, _)| lo.map(|lo| lo as u64)).collect(); - let words_hi: Value> = words.iter().map(|(_, hi)| hi.map(|hi| hi as u64)).collect(); - - let sum: Value = { - let sum_lo: Value = words_lo.map(|vec| vec.iter().sum()); - let sum_hi: Value = words_hi.map(|vec| vec.iter().sum()); - sum_lo.zip(sum_hi).map(|(lo, hi)| lo + (1 << 16) * hi) - }; - - let carry = sum.map(|sum| (sum >> 32) as u64); - let sum = sum.map(|sum| sum as u32); - - (sum, carry) -} diff --git a/halo2_gadgets/src/sinsemilla.rs b/halo2_gadgets/src/sinsemilla.rs deleted file mode 100644 index 3cec450ea1..0000000000 --- a/halo2_gadgets/src/sinsemilla.rs +++ /dev/null @@ -1,755 +0,0 @@ -//! The [Sinsemilla] hash function. -//! -//! [Sinsemilla]: https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash -use crate::{ - ecc::{self, EccInstructions, FixedPoints}, - utilities::{FieldValue, RangeConstrained, Var}, -}; -use group::ff::{Field, PrimeField}; -use halo2_proofs::{ - circuit::{Layouter, Value}, - plonk::Error, -}; -use halo2curves::CurveAffine; -use std::fmt::Debug; - -pub mod chip; -pub mod merkle; -mod message; -pub mod primitives; - -/// The set of circuit instructions required to use the [`Sinsemilla`](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html) gadget. -/// This trait is bounded on two constant parameters: `K`, the number of bits -/// in each word accepted by the Sinsemilla hash, and `MAX_WORDS`, the maximum -/// number of words that a single hash instance can process. -pub trait SinsemillaInstructions { - /// A variable in the circuit. - type CellValue: Var; - - /// A message composed of [`Self::MessagePiece`]s. - type Message: From>; - - /// A piece in a message containing a number of `K`-bit words. - /// A [`Self::MessagePiece`] fits in a single base field element, - /// which means it can only contain up to `N` words, where - /// `N*K <= C::Base::CAPACITY`. - /// - /// For example, in the case `K = 10`, `CAPACITY = 254`, we can fit - /// up to `N = 25` words in a single base field element. - type MessagePiece: Clone + Debug; - - /// A cumulative sum `z` is used to decompose a Sinsemilla message. It - /// produces intermediate values for each word in the message, such - /// that `z_next` = (`z_cur` - `word_next`) / `2^K`. - /// - /// These intermediate values are useful for range checks on subsets - /// of the Sinsemilla message. Sinsemilla messages in the Orchard - /// protocol are composed of field elements, and we need to check - /// the canonicity of the field element encodings in certain cases. - type RunningSum; - - /// The x-coordinate of a point output of [`Self::hash_to_point`]. - type X; - /// A point output of [`Self::hash_to_point`]. - type NonIdentityPoint: Clone + Debug; - /// A type enumerating the fixed points used in `CommitDomains`. - type FixedPoints: FixedPoints; - - /// HashDomains used in this instruction. - type HashDomains: HashDomains; - /// CommitDomains used in this instruction. - type CommitDomains: CommitDomains; - - /// Witness a message piece given a field element. Returns a [`Self::MessagePiece`] - /// encoding the given message. - /// - /// # Panics - /// - /// Panics if `num_words` exceed the maximum number of `K`-bit words that - /// can fit into a single base field element. - fn witness_message_piece( - &self, - layouter: impl Layouter, - value: Value, - num_words: usize, - ) -> Result; - - /// Hashes a message to an ECC curve point. - /// This returns both the resulting point, as well as the message - /// decomposition in the form of intermediate values in a cumulative - /// sum. - /// - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - fn hash_to_point( - &self, - layouter: impl Layouter, - Q: C, - message: Self::Message, - ) -> Result<(Self::NonIdentityPoint, Vec), Error>; - - /// Extracts the x-coordinate of the output of a Sinsemilla hash. - fn extract(point: &Self::NonIdentityPoint) -> Self::X; -} - -/// A message to be hashed. -/// -/// Composed of [`MessagePiece`]s with bitlength some multiple of `K`. -/// -/// [`MessagePiece`]: SinsemillaInstructions::MessagePiece -#[derive(Clone, Debug)] -pub struct Message -where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, -{ - chip: SinsemillaChip, - inner: SinsemillaChip::Message, -} - -impl - Message -where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, -{ - fn from_bitstring( - chip: SinsemillaChip, - mut layouter: impl Layouter, - bitstring: Vec>, - ) -> Result { - // Message must be composed of `K`-bit words. - assert_eq!(bitstring.len() % K, 0); - - // Message must have at most `MAX_WORDS` words. - assert!(bitstring.len() / K <= MAX_WORDS); - - // Each message piece must have at most `floor(C::CAPACITY / K)` words. - let piece_num_words = C::Base::CAPACITY as usize / K; - let pieces: Result, _> = bitstring - .chunks(piece_num_words * K) - .enumerate() - .map( - |(i, piece)| -> Result, Error> { - MessagePiece::from_bitstring( - chip.clone(), - layouter.namespace(|| format!("message piece {}", i)), - piece, - ) - }, - ) - .collect(); - - pieces.map(|pieces| Self::from_pieces(chip, pieces)) - } - - /// Constructs a message from a vector of [`MessagePiece`]s. - /// - /// [`MessagePiece`]: SinsemillaInstructions::MessagePiece - pub fn from_pieces( - chip: SinsemillaChip, - pieces: Vec>, - ) -> Self { - Self { - chip, - inner: pieces - .into_iter() - .map(|piece| piece.inner) - .collect::>() - .into(), - } - } -} - -/// A message piece with a bitlength of some multiple of `K`. -#[derive(Copy, Clone, Debug)] -pub struct MessagePiece -where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, -{ - chip: SinsemillaChip, - inner: SinsemillaChip::MessagePiece, -} - -impl - MessagePiece -where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, -{ - /// Returns the inner MessagePiece contained in this gadget. - pub fn inner(&self) -> SinsemillaChip::MessagePiece { - self.inner.clone() - } -} - -impl - MessagePiece -where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, -{ - fn from_bitstring( - chip: SinsemillaChip, - layouter: impl Layouter, - bitstring: &[Value], - ) -> Result { - // Message must be composed of `K`-bit words. - assert_eq!(bitstring.len() % K, 0); - let num_words = bitstring.len() / K; - - // Each message piece must have at most `floor(C::Base::CAPACITY / K)` words. - // This ensures that the all-ones bitstring is canonical in the field. - let piece_max_num_words = C::Base::CAPACITY as usize / K; - assert!(num_words <= piece_max_num_words as usize); - - // Closure to parse a bitstring (little-endian) into a base field element. - let to_base_field = |bits: &[Value]| -> Value { - let bits: Value> = bits.iter().cloned().collect(); - bits.map(|bits| { - bits.into_iter().rev().fold(C::Base::zero(), |acc, bit| { - if bit { - acc.double() + C::Base::one() - } else { - acc.double() - } - }) - }) - }; - - let piece_value = to_base_field(bitstring); - Self::from_field_elem(chip, layouter, piece_value, num_words) - } - - /// Constructs a MessagePiece from a field element. - pub fn from_field_elem( - chip: SinsemillaChip, - layouter: impl Layouter, - field_elem: Value, - num_words: usize, - ) -> Result { - let inner = chip.witness_message_piece(layouter, field_elem, num_words)?; - Ok(Self { chip, inner }) - } - - /// Constructs a `MessagePiece` by concatenating a sequence of [`RangeConstrained`] - /// subpiece values. - /// - /// The `MessagePiece` is assigned to the circuit, but not constrained in any way. - /// - /// # Panics - /// - /// Panics if the total number of bits across the subpieces is not a multiple of the - /// word size, or if the required bitshift for any subpiece is greater than 63 bits. - pub fn from_subpieces( - chip: SinsemillaChip, - layouter: impl Layouter, - subpieces: impl IntoIterator>>, - ) -> Result { - let (field_elem, total_bits) = subpieces.into_iter().fold( - (Value::known(C::Base::zero()), 0), - |(acc, bits), subpiece| { - assert!(bits < 64); - let subpiece_shifted = subpiece - .inner() - .value() - .map(|v| C::Base::from(1 << bits) * v); - (acc + subpiece_shifted, bits + subpiece.num_bits()) - }, - ); - - // Message must be composed of `K`-bit words. - assert_eq!(total_bits % K, 0); - let num_words = total_bits / K; - - Self::from_field_elem(chip, layouter, field_elem, num_words) - } -} - -/// A domain in which $\mathsf{SinsemillaHashToPoint}$ and $\mathsf{SinsemillaHash}$ can -/// be used. -#[derive(Debug)] -#[allow(non_snake_case)] -pub struct HashDomain< - C: CurveAffine, - SinsemillaChip, - EccChip, - const K: usize, - const MAX_WORDS: usize, -> where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, - EccChip: EccInstructions< - C, - NonIdentityPoint = >::NonIdentityPoint, - FixedPoints = >::FixedPoints, - > + Clone - + Debug - + Eq, -{ - sinsemilla_chip: SinsemillaChip, - ecc_chip: EccChip, - Q: C, -} - -impl - HashDomain -where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, - EccChip: EccInstructions< - C, - NonIdentityPoint = >::NonIdentityPoint, - FixedPoints = >::FixedPoints, - > + Clone - + Debug - + Eq, -{ - #[allow(non_snake_case)] - /// Constructs a new `HashDomain` for the given domain. - pub fn new( - sinsemilla_chip: SinsemillaChip, - ecc_chip: EccChip, - domain: &SinsemillaChip::HashDomains, - ) -> Self { - HashDomain { - sinsemilla_chip, - ecc_chip, - Q: domain.Q(), - } - } - - #[allow(clippy::type_complexity)] - /// $\mathsf{SinsemillaHashToPoint}$ from [§ 5.4.1.9][concretesinsemillahash]. - /// - /// [concretesinsemillahash]: https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash - pub fn hash_to_point( - &self, - layouter: impl Layouter, - message: Message, - ) -> Result<(ecc::NonIdentityPoint, Vec), Error> { - assert_eq!(self.sinsemilla_chip, message.chip); - self.sinsemilla_chip - .hash_to_point(layouter, self.Q, message.inner) - .map(|(point, zs)| (ecc::NonIdentityPoint::from_inner(self.ecc_chip.clone(), point), zs)) - } - - /// $\mathsf{SinsemillaHash}$ from [§ 5.4.1.9][concretesinsemillahash]. - /// - /// [concretesinsemillahash]: https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash - #[allow(clippy::type_complexity)] - pub fn hash( - &self, - layouter: impl Layouter, - message: Message, - ) -> Result<(ecc::X, Vec), Error> { - assert_eq!(self.sinsemilla_chip, message.chip); - let (p, zs) = self.hash_to_point(layouter, message)?; - Ok((p.extract_p(), zs)) - } -} - -/// Trait allowing circuit's Sinsemilla CommitDomains to be enumerated. -pub trait CommitDomains, H: HashDomains>: - Clone + Debug -{ - /// Returns the fixed point corresponding to the R constant used for - /// randomization in this CommitDomain. - fn r(&self) -> F::FullScalar; - - /// Returns the HashDomain contained in this CommitDomain - fn hash_domain(&self) -> H; -} - -/// Trait allowing circuit's Sinsemilla HashDomains to be enumerated. -#[allow(non_snake_case)] -pub trait HashDomains: Clone + Debug { - /// Returns the `Q` constant for this domain. - fn Q(&self) -> C; -} - -/// Gadget representing a domain in which $\mathsf{SinsemillaCommit}$ and -/// $\mathsf{SinsemillaShortCommit}$ can be used. -#[derive(Debug)] -#[allow(non_snake_case)] -pub struct CommitDomain< - C: CurveAffine, - SinsemillaChip, - EccChip, - const K: usize, - const MAX_WORDS: usize, -> where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, - EccChip: EccInstructions< - C, - NonIdentityPoint = >::NonIdentityPoint, - FixedPoints = >::FixedPoints, - > + Clone - + Debug - + Eq, -{ - M: HashDomain, - R: ecc::FixedPoint, -} - -impl - CommitDomain -where - SinsemillaChip: SinsemillaInstructions + Clone + Debug + Eq, - EccChip: EccInstructions< - C, - NonIdentityPoint = >::NonIdentityPoint, - FixedPoints = >::FixedPoints, - > + Clone - + Debug - + Eq, -{ - /// Constructs a new `CommitDomain` for the given domain. - pub fn new( - sinsemilla_chip: SinsemillaChip, - ecc_chip: EccChip, - // TODO: Instead of using SinsemilllaChip::CommitDomains, just use something that implements a CommitDomains trait - domain: &SinsemillaChip::CommitDomains, - ) -> Self { - CommitDomain { - M: HashDomain::new(sinsemilla_chip, ecc_chip.clone(), &domain.hash_domain()), - R: ecc::FixedPoint::from_inner(ecc_chip, domain.r()), - } - } - - #[allow(clippy::type_complexity)] - /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. - /// - /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit - pub fn commit( - &self, - mut layouter: impl Layouter, - message: Message, - r: ecc::ScalarFixed, - ) -> Result< - ( - ecc::Point, - Vec, - ), - Error, - > { - assert_eq!(self.M.sinsemilla_chip, message.chip); - let (blind, _) = self.R.mul(layouter.namespace(|| "[r] R"), r)?; - let (p, zs) = self.M.hash_to_point(layouter.namespace(|| "M"), message)?; - let commitment = p.add(layouter.namespace(|| "M + [r] R"), &blind)?; - Ok((commitment, zs)) - } - - #[allow(clippy::type_complexity)] - /// $\mathsf{SinsemillaShortCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. - /// - /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit - pub fn short_commit( - &self, - mut layouter: impl Layouter, - message: Message, - r: ecc::ScalarFixed, - ) -> Result<(ecc::X, Vec), Error> { - assert_eq!(self.M.sinsemilla_chip, message.chip); - let (p, zs) = self.commit(layouter.namespace(|| "commit"), message, r)?; - Ok((p.extract_p(), zs)) - } -} - -#[cfg(test)] -pub(crate) mod tests { - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use rand::rngs::OsRng; - - use super::{ - chip::{SinsemillaChip, SinsemillaConfig}, - CommitDomain, CommitDomains, HashDomain, HashDomains, Message, MessagePiece, - }; - - use crate::{ - ecc::ScalarFixed, - sinsemilla::primitives::{self as sinsemilla, K}, - { - ecc::{ - chip::{find_zs_and_us, EccChip, EccConfig, H, NUM_WINDOWS}, - tests::{FullWidth, TestFixedBases}, - NonIdentityPoint, - }, - utilities::lookup_range_check::LookupRangeCheckConfig, - }, - }; - - use group::{ff::Field, Curve}; - use halo2curves::pasta::pallas; - use lazy_static::lazy_static; - - use std::convert::TryInto; - - pub(crate) const PERSONALIZATION: &str = "MerkleCRH"; - - lazy_static! { - static ref COMMIT_DOMAIN: sinsemilla::CommitDomain = - sinsemilla::CommitDomain::new(PERSONALIZATION); - static ref Q: pallas::Affine = COMMIT_DOMAIN.Q().to_affine(); - static ref R: pallas::Affine = COMMIT_DOMAIN.R().to_affine(); - static ref R_ZS_AND_US: Vec<(u64, [pallas::Base; H])> = - find_zs_and_us(*R, NUM_WINDOWS).unwrap(); - } - - #[derive(Debug, Clone, Eq, PartialEq)] - pub(crate) struct TestHashDomain; - impl HashDomains for TestHashDomain { - fn Q(&self) -> pallas::Affine { - *Q - } - } - - // This test does not make use of the CommitDomain. - #[derive(Debug, Clone, Eq, PartialEq)] - pub(crate) struct TestCommitDomain; - impl CommitDomains for TestCommitDomain { - fn r(&self) -> FullWidth { - FullWidth::from_parts(*R, &R_ZS_AND_US) - } - - fn hash_domain(&self) -> TestHashDomain { - TestHashDomain - } - } - - struct MyCircuit {} - - impl Circuit for MyCircuit { - #[allow(clippy::type_complexity)] - type Config = ( - EccConfig, - SinsemillaConfig, - SinsemillaConfig, - ); - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - MyCircuit {} - } - - #[allow(non_snake_case)] - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let advices = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - - // Shared fixed column for loading constants - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - let table_idx = meta.lookup_table_column(); - let lagrange_coeffs = [ - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - meta.fixed_column(), - ]; - - // Fixed columns for the Sinsemilla generator lookup table - let lookup = ( - table_idx, - meta.lookup_table_column(), - meta.lookup_table_column(), - ); - - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx); - - let ecc_config = - EccChip::::configure(meta, advices, lagrange_coeffs, range_check); - - let config1 = SinsemillaChip::configure( - meta, - advices[..5].try_into().unwrap(), - advices[2], - lagrange_coeffs[0], - lookup, - range_check, - ); - let config2 = SinsemillaChip::configure( - meta, - advices[5..].try_into().unwrap(), - advices[7], - lagrange_coeffs[1], - lookup, - range_check, - ); - (ecc_config, config1, config2) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let rng = OsRng; - - let ecc_chip = EccChip::construct(config.0); - - // The two `SinsemillaChip`s share the same lookup table. - SinsemillaChip::::load( - config.1.clone(), - &mut layouter, - )?; - - // This MerkleCRH example is purely for illustrative purposes. - // It is not an implementation of the Orchard protocol spec. - { - let chip1 = SinsemillaChip::construct(config.1); - - let merkle_crh = HashDomain::new(chip1.clone(), ecc_chip.clone(), &TestHashDomain); - - // Layer 31, l = MERKLE_DEPTH - 1 - layer = 0 - let l_bitstring = vec![Value::known(false); K]; - let l = MessagePiece::from_bitstring( - chip1.clone(), - layouter.namespace(|| "l"), - &l_bitstring, - )?; - - // Left leaf - let left_bitstring: Vec> = (0..250) - .map(|_| Value::known(rand::random::())) - .collect(); - let left = MessagePiece::from_bitstring( - chip1.clone(), - layouter.namespace(|| "left"), - &left_bitstring, - )?; - - // Right leaf - let right_bitstring: Vec> = (0..250) - .map(|_| Value::known(rand::random::())) - .collect(); - let right = MessagePiece::from_bitstring( - chip1.clone(), - layouter.namespace(|| "right"), - &right_bitstring, - )?; - - let l_bitstring: Value> = l_bitstring.into_iter().collect(); - let left_bitstring: Value> = left_bitstring.into_iter().collect(); - let right_bitstring: Value> = right_bitstring.into_iter().collect(); - - // Witness expected parent - let expected_parent = { - let expected_parent = l_bitstring.zip(left_bitstring.zip(right_bitstring)).map( - |(l, (left, right))| { - let merkle_crh = sinsemilla::HashDomain::from_Q((*Q).into()); - let point = merkle_crh - .hash_to_point( - l.into_iter() - .chain(left.into_iter()) - .chain(right.into_iter()), - ) - .unwrap(); - point.to_affine() - }, - ); - - NonIdentityPoint::new( - ecc_chip.clone(), - layouter.namespace(|| "Witness expected parent"), - expected_parent, - )? - }; - - // Parent - let (parent, _) = { - let message = Message::from_pieces(chip1, vec![l, left, right]); - merkle_crh.hash_to_point(layouter.namespace(|| "parent"), message)? - }; - - parent.constrain_equal( - layouter.namespace(|| "parent == expected parent"), - &expected_parent, - )?; - } - - { - let chip2 = SinsemillaChip::construct(config.2); - - let test_commit = - CommitDomain::new(chip2.clone(), ecc_chip.clone(), &TestCommitDomain); - let r_val = pallas::Scalar::random(rng); - let message: Vec> = (0..500) - .map(|_| Value::known(rand::random::())) - .collect(); - - let (result, _) = { - let r = ScalarFixed::new( - ecc_chip.clone(), - layouter.namespace(|| "r"), - Value::known(r_val), - )?; - let message = Message::from_bitstring( - chip2, - layouter.namespace(|| "witness message"), - message.clone(), - )?; - test_commit.commit(layouter.namespace(|| "commit"), message, r)? - }; - - // Witness expected result. - let expected_result = { - let message: Value> = message.into_iter().collect(); - let expected_result = message.map(|message| { - let domain = sinsemilla::CommitDomain::new(PERSONALIZATION); - let point = domain.commit(message.into_iter(), &r_val).unwrap(); - point.to_affine() - }); - - NonIdentityPoint::new( - ecc_chip, - layouter.namespace(|| "Witness expected result"), - expected_result, - )? - }; - - result.constrain_equal( - layouter.namespace(|| "result == expected result"), - &expected_result, - ) - } - } - } - - #[test] - fn sinsemilla_chip() { - let k = 11; - let circuit = MyCircuit {}; - let prover = MockProver::run(k, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())) - } - - #[cfg(feature = "dev-graph")] - #[test] - fn print_sinsemilla_chip() { - use plotters::prelude::*; - - let root = - BitMapBackend::new("sinsemilla-hash-layout.png", (1024, 7680)).into_drawing_area(); - root.fill(&WHITE).unwrap(); - let root = root.titled("SinsemillaHash", ("sans-serif", 60)).unwrap(); - - let circuit = MyCircuit {}; - halo2_proofs::dev::CircuitLayout::default() - .render(11, &circuit, &root) - .unwrap(); - } -} diff --git a/halo2_gadgets/src/sinsemilla/chip.rs b/halo2_gadgets/src/sinsemilla/chip.rs deleted file mode 100644 index a6788e55e1..0000000000 --- a/halo2_gadgets/src/sinsemilla/chip.rs +++ /dev/null @@ -1,327 +0,0 @@ -//! Chip implementations for the Sinsemilla gadgets. - -use super::{ - message::{Message, MessagePiece}, - primitives as sinsemilla, CommitDomains, HashDomains, SinsemillaInstructions, -}; -use crate::{ - ecc::{ - chip::{DoubleAndAdd, NonIdentityEccPoint}, - FixedPoints, - }, - utilities::lookup_range_check::LookupRangeCheckConfig, -}; -use std::marker::PhantomData; - -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{ - Advice, Column, ConstraintSystem, Constraints, Error, Expression, Fixed, Selector, - TableColumn, VirtualCells, - }, - poly::Rotation, -}; -use halo2curves::pasta::pallas; - -mod generator_table; -use generator_table::GeneratorTableConfig; - -mod hash_to_point; - -/// Configuration for the Sinsemilla hash chip -#[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaConfig -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - /// Binary selector used in lookup argument and in the body of the Sinsemilla hash. - q_sinsemilla1: Selector, - /// Non-binary selector used in lookup argument and in the body of the Sinsemilla hash. - q_sinsemilla2: Column, - /// q_sinsemilla2 is used to define a synthetic selector, - /// q_sinsemilla3 = (q_sinsemilla2) ⋅ (q_sinsemilla2 - 1) - /// Simple selector used to constrain hash initialization to be consistent with - /// the y-coordinate of the domain $Q$. - q_sinsemilla4: Selector, - /// Fixed column used to load the y-coordinate of the domain $Q$. - fixed_y_q: Column, - /// Logic specific to merged double-and-add. - double_and_add: DoubleAndAdd, - /// Advice column used to load the message. - bits: Column, - /// Advice column used to witness message pieces. This may or may not be the same - /// column as `bits`. - witness_pieces: Column, - /// The lookup table where $(\mathsf{idx}, x_p, y_p)$ are loaded for the $2^K$ - /// generators of the Sinsemilla hash. - pub(super) generator_table: GeneratorTableConfig, - /// An advice column configured to perform lookup range checks. - lookup_config: LookupRangeCheckConfig, - _marker: PhantomData<(Hash, Commit, F)>, -} - -impl SinsemillaConfig -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - /// Returns an array of all advice columns in this config, in arbitrary order. - pub(super) fn advices(&self) -> [Column; 5] { - [ - self.double_and_add.x_a, - self.double_and_add.x_p, - self.bits, - self.double_and_add.lambda_1, - self.double_and_add.lambda_2, - ] - } - - /// Returns the lookup range check config used in this config. - pub fn lookup_config(&self) -> LookupRangeCheckConfig { - self.lookup_config - } - - /// Derives the expression `q_s3 = (q_s2) * (q_s2 - 1)`. - fn q_s3(&self, meta: &mut VirtualCells) -> Expression { - let one = Expression::Constant(pallas::Base::one()); - let q_s2 = meta.query_fixed(self.q_sinsemilla2, Rotation::cur()); - q_s2.clone() * (q_s2 - one) - } -} - -/// A chip that implements 10-bit Sinsemilla using a lookup table and 5 advice columns. -/// -/// [Chip description](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html#plonk--halo-2-constraints). -#[derive(Eq, PartialEq, Clone, Debug)] -pub struct SinsemillaChip -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - config: SinsemillaConfig, -} - -impl Chip for SinsemillaChip -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - type Config = SinsemillaConfig; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -impl SinsemillaChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - /// Reconstructs this chip from the given config. - pub fn construct(config: >::Config) -> Self { - Self { config } - } - - /// Loads the lookup table required by this chip into the circuit. - pub fn load( - config: SinsemillaConfig, - layouter: &mut impl Layouter, - ) -> Result<>::Loaded, Error> { - // Load the lookup table. - config.generator_table.load(layouter) - } - - /// # Side-effects - /// - /// All columns in `advices` and will be equality-enabled. - #[allow(clippy::too_many_arguments)] - #[allow(non_snake_case)] - pub fn configure( - meta: &mut ConstraintSystem, - advices: [Column; 5], - witness_pieces: Column, - fixed_y_q: Column, - lookup: (TableColumn, TableColumn, TableColumn), - range_check: LookupRangeCheckConfig, - ) -> >::Config { - // Enable equality on all advice columns - for advice in advices.iter() { - meta.enable_equality(*advice); - } - - let config = SinsemillaConfig:: { - q_sinsemilla1: meta.complex_selector(), - q_sinsemilla2: meta.fixed_column(), - q_sinsemilla4: meta.selector(), - fixed_y_q, - double_and_add: DoubleAndAdd { - x_a: advices[0], - x_p: advices[1], - lambda_1: advices[3], - lambda_2: advices[4], - }, - bits: advices[2], - witness_pieces, - generator_table: GeneratorTableConfig { - table_idx: lookup.0, - table_x: lookup.1, - table_y: lookup.2, - }, - lookup_config: range_check, - _marker: PhantomData, - }; - - // Set up lookup argument - GeneratorTableConfig::configure(meta, config.clone()); - - let two = pallas::Base::from(2); - - // Closures for expressions that are derived multiple times - // x_r = lambda_1^2 - x_a - x_p - let x_r = |meta: &mut VirtualCells, rotation| { - config.double_and_add.x_r(meta, rotation) - }; - - // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) - let Y_A = |meta: &mut VirtualCells, rotation| { - config.double_and_add.Y_A(meta, rotation) - }; - - // Check that the initial x_A, x_P, lambda_1, lambda_2 are consistent with y_Q. - // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial - meta.create_gate("Initial y_Q", |meta| { - let q_s4 = meta.query_selector(config.q_sinsemilla4); - let y_q = meta.query_fixed(config.fixed_y_q, Rotation::cur()); - - // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) - let Y_A_cur = Y_A(meta, Rotation::cur()); - - // 2 * y_q - Y_{A,0} = 0 - let init_y_q_check = y_q * two - Y_A_cur; - - Constraints::with_selector(q_s4, Some(("init_y_q_check", init_y_q_check))) - }); - - // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial - meta.create_gate("Sinsemilla gate", |meta| { - let q_s1 = meta.query_selector(config.q_sinsemilla1); - let q_s3 = config.q_s3(meta); - - let lambda_1_next = meta.query_advice(config.double_and_add.lambda_1, Rotation::next()); - let lambda_2_cur = meta.query_advice(config.double_and_add.lambda_2, Rotation::cur()); - let x_a_cur = meta.query_advice(config.double_and_add.x_a, Rotation::cur()); - let x_a_next = meta.query_advice(config.double_and_add.x_a, Rotation::next()); - - // x_r = lambda_1^2 - x_a_cur - x_p - let x_r = x_r(meta, Rotation::cur()); - - // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) - let Y_A_cur = Y_A(meta, Rotation::cur()); - - // Y_A = (lambda_1 + lambda_2) * (x_a - x_r) - let Y_A_next = Y_A(meta, Rotation::next()); - - // lambda2^2 - (x_a_next + x_r + x_a_cur) = 0 - let secant_line = - lambda_2_cur.clone().square() - (x_a_next.clone() + x_r + x_a_cur.clone()); - - // lhs - rhs = 0, where - // - lhs = 4 * lambda_2_cur * (x_a_cur - x_a_next) - // - rhs = (2 * Y_A_cur + (2 - q_s3) * Y_A_next + 2 * q_s3 * y_a_final) - let y_check = { - // lhs = 4 * lambda_2_cur * (x_a_cur - x_a_next) - let lhs = lambda_2_cur * pallas::Base::from(4) * (x_a_cur - x_a_next); - - // rhs = 2 * Y_A_cur + (2 - q_s3) * Y_A_next + 2 * q_s3 * y_a_final - let rhs = { - // y_a_final is assigned to the lambda1 column on the next offset. - let y_a_final = lambda_1_next; - - Y_A_cur * two - + (Expression::Constant(two) - q_s3.clone()) * Y_A_next - + q_s3 * two * y_a_final - }; - lhs - rhs - }; - - Constraints::with_selector(q_s1, [("Secant line", secant_line), ("y check", y_check)]) - }); - - config - } -} - -// Implement `SinsemillaInstructions` for `SinsemillaChip` -impl SinsemillaInstructions - for SinsemillaChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - type CellValue = AssignedCell; - - type Message = Message; - type MessagePiece = MessagePiece; - - type RunningSum = Vec; - - type X = AssignedCell; - type NonIdentityPoint = NonIdentityEccPoint; - type FixedPoints = F; - - type HashDomains = Hash; - type CommitDomains = Commit; - - fn witness_message_piece( - &self, - mut layouter: impl Layouter, - field_elem: Value, - num_words: usize, - ) -> Result { - let config = self.config().clone(); - - let cell = layouter.assign_region( - || "witness message piece", - |mut region| { - region.assign_advice( - || "witness message piece", - config.witness_pieces, - 0, - || field_elem, - ) - }, - )?; - Ok(MessagePiece::new(cell, num_words)) - } - - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - fn hash_to_point( - &self, - mut layouter: impl Layouter, - Q: pallas::Affine, - message: Self::Message, - ) -> Result<(Self::NonIdentityPoint, Vec), Error> { - layouter.assign_region( - || "hash_to_point", - |mut region| self.hash_message(&mut region, Q, &message), - ) - } - - fn extract(point: &Self::NonIdentityPoint) -> Self::X { - point.x() - } -} diff --git a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs b/halo2_gadgets/src/sinsemilla/chip/generator_table.rs deleted file mode 100644 index a653c13b35..0000000000 --- a/halo2_gadgets/src/sinsemilla/chip/generator_table.rs +++ /dev/null @@ -1,97 +0,0 @@ -use halo2_proofs::{ - circuit::{Layouter, Value}, - plonk::{ConstraintSystem, Error, Expression, TableColumn}, - poly::Rotation, -}; - -use super::{CommitDomains, FixedPoints, HashDomains}; -use crate::sinsemilla::primitives::{self as sinsemilla, SINSEMILLA_S}; -use halo2curves::{pasta::pallas, FieldExt}; - -/// Table containing independent generators S[0..2^k] -#[derive(Eq, PartialEq, Copy, Clone, Debug)] -pub struct GeneratorTableConfig { - pub table_idx: TableColumn, - pub table_x: TableColumn, - pub table_y: TableColumn, -} - -impl GeneratorTableConfig { - #[allow(clippy::too_many_arguments)] - #[allow(non_snake_case)] - /// Even though the lookup table can be used in other parts of the circuit, - /// this specific configuration sets up Sinsemilla-specific constraints - /// controlled by `q_sinsemilla`, and would likely not apply to other chips. - pub fn configure( - meta: &mut ConstraintSystem, - config: super::SinsemillaConfig, - ) where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, - { - let (table_idx, table_x, table_y) = ( - config.generator_table.table_idx, - config.generator_table.table_x, - config.generator_table.table_y, - ); - - // https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial - meta.lookup("lookup", |meta| { - let q_s1 = meta.query_selector(config.q_sinsemilla1); - let q_s2 = meta.query_fixed(config.q_sinsemilla2, Rotation::cur()); - let q_s3 = config.q_s3(meta); - let q_run = q_s2 - q_s3; - - // m_{i+1} = z_{i} - 2^K * q_{run,i} * z_{i + 1} - // Note that the message words m_i's are 1-indexed while the - // running sum z_i's are 0-indexed. - let word = { - let z_cur = meta.query_advice(config.bits, Rotation::cur()); - let z_next = meta.query_advice(config.bits, Rotation::next()); - z_cur - (q_run * z_next * pallas::Base::from(1 << sinsemilla::K)) - }; - - let x_p = meta.query_advice(config.double_and_add.x_p, Rotation::cur()); - - // y_{p,i} = (Y_{A,i} / 2) - lambda1 * (x_{A,i} - x_{P,i}) - let y_p = { - let lambda1 = meta.query_advice(config.double_and_add.lambda_1, Rotation::cur()); - let x_a = meta.query_advice(config.double_and_add.x_a, Rotation::cur()); - let Y_A = config.double_and_add.Y_A(meta, Rotation::cur()); - - (Y_A * pallas::Base::TWO_INV) - (lambda1 * (x_a - x_p.clone())) - }; - - // Lookup expressions default to the first entry when `q_s1` - // is not enabled. - let (init_x, init_y) = SINSEMILLA_S[0]; - let not_q_s1 = Expression::Constant(pallas::Base::one()) - q_s1.clone(); - - let m = q_s1.clone() * word; // The first table index is 0. - let x_p = q_s1.clone() * x_p + not_q_s1.clone() * init_x; - let y_p = q_s1 * y_p + not_q_s1 * init_y; - - vec![(m, table_idx), (x_p, table_x), (y_p, table_y)] - }); - } - - pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_table( - || "generator_table", - |mut table| { - for (index, (x, y)) in SINSEMILLA_S.iter().enumerate() { - table.assign_cell( - || "table_idx", - self.table_idx, - index, - || Value::known(pallas::Base::from(index as u64)), - )?; - table.assign_cell(|| "table_x", self.table_x, index, || Value::known(*x))?; - table.assign_cell(|| "table_y", self.table_y, index, || Value::known(*y))?; - } - Ok(()) - }, - ) - } -} diff --git a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs b/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs deleted file mode 100644 index 70eab6b86d..0000000000 --- a/halo2_gadgets/src/sinsemilla/chip/hash_to_point.rs +++ /dev/null @@ -1,414 +0,0 @@ -use super::super::{CommitDomains, HashDomains, SinsemillaInstructions}; -use super::{NonIdentityEccPoint, SinsemillaChip}; -use crate::{ - ecc::FixedPoints, - sinsemilla::primitives::{self as sinsemilla, lebs2ip_k, INV_TWO_POW_K, SINSEMILLA_S}, -}; - -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Region, Value}, - plonk::{Assigned, Error}, -}; - -use group::ff::{PrimeField, PrimeFieldBits}; -use halo2curves::{pasta::pallas, CurveAffine, FieldExt}; - -use std::ops::Deref; - -impl SinsemillaChip -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - /// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial). - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - pub(super) fn hash_message( - &self, - region: &mut Region<'_, pallas::Base>, - Q: pallas::Affine, - message: &>::Message, - ) -> Result< - ( - NonIdentityEccPoint, - Vec>>, - ), - Error, - > { - let config = self.config().clone(); - let mut offset = 0; - - // Get the `x`- and `y`-coordinates of the starting `Q` base. - let x_q = *Q.coordinates().unwrap().x(); - let y_q = *Q.coordinates().unwrap().y(); - - // Constrain the initial x_a, lambda_1, lambda_2, x_p using the q_sinsemilla4 - // selector. - let mut y_a: Y = { - // Enable `q_sinsemilla4` on the first row. - config.q_sinsemilla4.enable(region, offset)?; - region.assign_fixed( - || "fixed y_q", - config.fixed_y_q, - offset, - || Value::known(y_q), - )?; - - Value::known(y_q.into()).into() - }; - - // Constrain the initial x_q to equal the x-coordinate of the domain's `Q`. - let mut x_a: X = { - let x_a = region.assign_advice_from_constant( - || "fixed x_q", - config.double_and_add.x_a, - offset, - x_q.into(), - )?; - - x_a.into() - }; - - let mut zs_sum: Vec>> = Vec::new(); - - // Hash each piece in the message. - for (idx, piece) in message.iter().enumerate() { - let final_piece = idx == message.len() - 1; - - // The value of the accumulator after this piece is processed. - let (x, y, zs) = self.hash_piece(region, offset, piece, x_a, y_a, final_piece)?; - - // Since each message word takes one row to process, we increase - // the offset by `piece.num_words` on each iteration. - offset += piece.num_words(); - - // Update the accumulator to the latest value. - x_a = x; - y_a = y; - zs_sum.push(zs); - } - - // Assign the final y_a. - let y_a = { - // Assign the final y_a. - let y_a_cell = - region.assign_advice(|| "y_a", config.double_and_add.lambda_1, offset, || y_a.0)?; - - // Assign lambda_2 and x_p zero values since they are queried - // in the gate. (The actual values do not matter since they are - // multiplied by zero.) - { - region.assign_advice( - || "dummy lambda2", - config.double_and_add.lambda_2, - offset, - || Value::known(pallas::Base::zero()), - )?; - region.assign_advice( - || "dummy x_p", - config.double_and_add.x_p, - offset, - || Value::known(pallas::Base::zero()), - )?; - } - - y_a_cell - }; - - #[cfg(test)] - #[allow(non_snake_case)] - // Check equivalence to result from primitives::sinsemilla::hash_to_point - { - use crate::sinsemilla::primitives::{K, S_PERSONALIZATION}; - - use group::{prime::PrimeCurveAffine, Curve}; - use halo2curves::CurveExt; - - let field_elems: Value> = message - .iter() - .map(|piece| piece.field_elem().map(|elem| (elem, piece.num_words()))) - .collect(); - - field_elems - .zip(x_a.value().zip(y_a.value())) - .assert_if_known(|(field_elems, (x_a, y_a))| { - // Get message as a bitstring. - let bitstring: Vec = field_elems - .iter() - .flat_map(|(elem, num_words)| { - elem.to_le_bits().into_iter().take(K * num_words) - }) - .collect(); - - let hasher_S = pallas::Point::hash_to_curve(S_PERSONALIZATION); - let S = |chunk: &[bool]| hasher_S(&lebs2ip_k(chunk).to_le_bytes()); - - // We can use complete addition here because it differs from - // incomplete addition with negligible probability. - let expected_point = bitstring - .chunks(K) - .fold(Q.to_curve(), |acc, chunk| (acc + S(chunk)) + acc); - let actual_point = - pallas::Affine::from_xy(x_a.evaluate(), y_a.evaluate()).unwrap(); - expected_point.to_affine() == actual_point - }); - } - - x_a.value() - .zip(y_a.value()) - .error_if_known_and(|(x_a, y_a)| x_a.is_zero_vartime() || y_a.is_zero_vartime())?; - Ok(( - NonIdentityEccPoint::from_coordinates_unchecked(x_a.0, y_a), - zs_sum, - )) - } - - #[allow(clippy::type_complexity)] - /// Hashes a message piece containing `piece.length` number of `K`-bit words. - /// - /// To avoid a duplicate assignment, the accumulator x-coordinate provided - /// by the caller is not copied. This only works because `hash_piece()` is - /// an internal API. Before this call to `hash_piece()`, x_a MUST have been - /// already assigned within this region at the correct offset. - fn hash_piece( - &self, - region: &mut Region<'_, pallas::Base>, - offset: usize, - piece: &>::MessagePiece, - mut x_a: X, - mut y_a: Y, - final_piece: bool, - ) -> Result< - ( - X, - Y, - Vec>, - ), - Error, - > { - let config = self.config().clone(); - - // Selector assignments - { - // Enable `q_sinsemilla1` selector on every row. - for row in 0..piece.num_words() { - config.q_sinsemilla1.enable(region, offset + row)?; - } - - // Set `q_sinsemilla2` fixed column to 1 on every row but the last. - for row in 0..(piece.num_words() - 1) { - region.assign_fixed( - || "q_s2 = 1", - config.q_sinsemilla2, - offset + row, - || Value::known(pallas::Base::one()), - )?; - } - - // Set `q_sinsemilla2` fixed column to 0 on the last row if this is - // not the final piece, or to 2 on the last row of the final piece. - region.assign_fixed( - || { - if final_piece { - "q_s2 for final piece" - } else { - "q_s2 between pieces" - } - }, - config.q_sinsemilla2, - offset + piece.num_words() - 1, - || { - Value::known(if final_piece { - pallas::Base::from(2) - } else { - pallas::Base::zero() - }) - }, - )?; - } - - // Message piece as K * piece.length bitstring - let bitstring: Value> = piece.field_elem().map(|value| { - value - .to_le_bits() - .into_iter() - .take(sinsemilla::K * piece.num_words()) - .collect() - }); - - let words: Value> = bitstring.map(|bitstring| { - bitstring - .chunks_exact(sinsemilla::K) - .map(lebs2ip_k) - .collect() - }); - - // Get (x_p, y_p) for each word. - let generators: Value> = words.clone().map(|words| { - words - .iter() - .map(|word| SINSEMILLA_S[*word as usize]) - .collect() - }); - - // Convert `words` from `Value>` to `Vec>` - let words = words.transpose_vec(piece.num_words()); - - // Decompose message piece into `K`-bit pieces with a running sum `z`. - let zs = { - let mut zs = Vec::with_capacity(piece.num_words() + 1); - - // Copy message and initialize running sum `z` to decompose message in-circuit - let initial_z = piece.cell_value().copy_advice( - || "z_0 (copy of message piece)", - region, - config.bits, - offset, - )?; - zs.push(initial_z); - - // Assign cumulative sum such that for 0 <= i < n, - // z_i = 2^K * z_{i + 1} + m_{i + 1} - // => z_{i + 1} = (z_i - m_{i + 1}) / 2^K - // - // For a message piece m = m_1 + 2^K m_2 + ... + 2^{K(n-1)} m_n}, initialize z_0 = m. - // We end up with z_n = 0. (z_n is not directly encoded as a cell value; - // it is implicitly taken as 0 by adjusting the definition of m_{i+1}.) - let mut z = piece.field_elem(); - let inv_2_k = Value::known(pallas::Base::from_repr(INV_TWO_POW_K).unwrap()); - - // We do not assign the final z_n as it is constrained to be zero. - for (idx, word) in words[0..(words.len() - 1)].iter().enumerate() { - let word = word.map(|word| pallas::Base::from(word as u64)); - // z_{i + 1} = (z_i - m_{i + 1}) / 2^K - z = (z - word) * inv_2_k; - let cell = region.assign_advice( - || format!("z_{:?}", idx + 1), - config.bits, - offset + idx + 1, - || z, - )?; - zs.push(cell) - } - - zs - }; - - // The accumulator x-coordinate provided by the caller MUST have been assigned - // within this region. - - let generators = generators.transpose_vec(piece.num_words()); - - for (row, gen) in generators.iter().enumerate() { - let x_p = gen.map(|gen| gen.0); - let y_p = gen.map(|gen| gen.1); - - // Assign `x_p` - region.assign_advice(|| "x_p", config.double_and_add.x_p, offset + row, || x_p)?; - - // Compute and assign `lambda_1` - let lambda_1 = { - let lambda_1 = (y_a.0 - y_p) * (x_a.value() - x_p).invert(); - - // Assign lambda_1 - region.assign_advice( - || "lambda_1", - config.double_and_add.lambda_1, - offset + row, - || lambda_1, - )?; - - lambda_1 - }; - - // Compute `x_r` - let x_r = lambda_1.square() - x_a.value() - x_p; - - // Compute and assign `lambda_2` - let lambda_2 = { - let lambda_2 = - y_a.0 * pallas::Base::from(2) * (x_a.value() - x_r).invert() - lambda_1; - - region.assign_advice( - || "lambda_2", - config.double_and_add.lambda_2, - offset + row, - || lambda_2, - )?; - - lambda_2 - }; - - // Compute and assign `x_a` for the next row. - let x_a_new: X = { - let x_a_new = lambda_2.square() - x_a.value() - x_r; - - let x_a_cell = region.assign_advice( - || "x_a", - config.double_and_add.x_a, - offset + row + 1, - || x_a_new, - )?; - - x_a_cell.into() - }; - - // Compute y_a for the next row. - let y_a_new: Y = - (lambda_2 * (x_a.value() - x_a_new.value()) - y_a.0).into(); - - // Update the mutable `x_a`, `y_a` variables. - x_a = x_a_new; - y_a = y_a_new; - } - - Ok((x_a, y_a, zs)) - } -} - -/// The x-coordinate of the accumulator in a Sinsemilla hash instance. -struct X(AssignedCell, F>); - -impl From, F>> for X { - fn from(cell_value: AssignedCell, F>) -> Self { - X(cell_value) - } -} - -impl Deref for X { - type Target = AssignedCell, F>; - - fn deref(&self) -> &AssignedCell, F> { - &self.0 - } -} - -/// The y-coordinate of the accumulator in a Sinsemilla hash instance. -/// -/// This is never actually witnessed until the last round, since it -/// can be derived from other variables. Thus it only exists as a field -/// element, not a `CellValue`. -struct Y(Value>); - -impl From>> for Y { - fn from(value: Value>) -> Self { - Y(value) - } -} - -impl Deref for Y { - type Target = Value>; - - fn deref(&self) -> &Value> { - &self.0 - } -} diff --git a/halo2_gadgets/src/sinsemilla/merkle.rs b/halo2_gadgets/src/sinsemilla/merkle.rs deleted file mode 100644 index a9ae781d5c..0000000000 --- a/halo2_gadgets/src/sinsemilla/merkle.rs +++ /dev/null @@ -1,398 +0,0 @@ -//! Gadgets for implementing a Merkle tree with Sinsemilla. - -use halo2_proofs::{ - circuit::{Chip, Layouter, Value}, - plonk::Error, -}; -use halo2curves::CurveAffine; - -use super::{HashDomains, SinsemillaInstructions}; - -use crate::utilities::{cond_swap::CondSwapInstructions, i2lebsp, UtilitiesInstructions}; - -pub mod chip; - -/// SWU hash-to-curve personalization for the Merkle CRH generator -pub const MERKLE_CRH_PERSONALIZATION: &str = "z.cash:Orchard-MerkleCRH"; - -/// Instructions to check the validity of a Merkle path of a given `PATH_LENGTH`. -/// The hash function used is a Sinsemilla instance with `K`-bit words. -/// The hash function can process `MAX_WORDS` words. -pub trait MerkleInstructions< - C: CurveAffine, - const PATH_LENGTH: usize, - const K: usize, - const MAX_WORDS: usize, ->: - SinsemillaInstructions - + CondSwapInstructions - + UtilitiesInstructions - + Chip -{ - /// Compute MerkleCRH for a given `layer`. The hash that computes the root - /// is at layer 0, and the hashes that are applied to two leaves are at - /// layer `MERKLE_DEPTH - 1` = layer 31. - #[allow(non_snake_case)] - fn hash_layer( - &self, - layouter: impl Layouter, - Q: C, - l: usize, - left: Self::Var, - right: Self::Var, - ) -> Result; -} - -/// Gadget representing a Merkle path that proves a leaf exists in a Merkle tree at a -/// specific position. -#[derive(Clone, Debug)] -pub struct MerklePath< - C: CurveAffine, - MerkleChip, - const PATH_LENGTH: usize, - const K: usize, - const MAX_WORDS: usize, - const PAR: usize, -> where - MerkleChip: MerkleInstructions + Clone, -{ - chips: [MerkleChip; PAR], - domain: MerkleChip::HashDomains, - leaf_pos: Value, - // The Merkle path is ordered from leaves to root. - path: Value<[C::Base; PATH_LENGTH]>, -} - -impl< - C: CurveAffine, - MerkleChip, - const PATH_LENGTH: usize, - const K: usize, - const MAX_WORDS: usize, - const PAR: usize, - > MerklePath -where - MerkleChip: MerkleInstructions + Clone, -{ - /// Constructs a [`MerklePath`]. - /// - /// A circuit may have many more columns available than are required by a single - /// `MerkleChip`. To make better use of the available circuit area, the `MerklePath` - /// gadget will distribute its path hashing across each `MerkleChip` in `chips`, such - /// that each chip processes `ceil(PATH_LENGTH / PAR)` layers (with the last chip - /// processing fewer layers if the division is inexact). - pub fn construct( - chips: [MerkleChip; PAR], - domain: MerkleChip::HashDomains, - leaf_pos: Value, - path: Value<[C::Base; PATH_LENGTH]>, - ) -> Self { - assert_ne!(PAR, 0); - Self { - chips, - domain, - leaf_pos, - path, - } - } -} - -#[allow(non_snake_case)] -impl< - C: CurveAffine, - MerkleChip, - const PATH_LENGTH: usize, - const K: usize, - const MAX_WORDS: usize, - const PAR: usize, - > MerklePath -where - MerkleChip: MerkleInstructions + Clone, -{ - /// Calculates the root of the tree containing the given leaf at this Merkle path. - /// - /// Implements [Zcash Protocol Specification Section 4.9: Merkle Path Validity][merklepath]. - /// - /// [merklepath]: https://zips.z.cash/protocol/protocol.pdf#merklepath - pub fn calculate_root( - &self, - mut layouter: impl Layouter, - leaf: MerkleChip::Var, - ) -> Result { - // Each chip processes `ceil(PATH_LENGTH / PAR)` layers. - let layers_per_chip = (PATH_LENGTH + PAR - 1) / PAR; - - // Assign each layer to a chip. - let chips = (0..PATH_LENGTH).map(|i| self.chips[i / layers_per_chip].clone()); - - // The Merkle path is ordered from leaves to root, which is consistent with the - // little-endian representation of `pos` below. - let path = self.path.transpose_array(); - - // Get position as a PATH_LENGTH-bit bitstring (little-endian bit order). - let pos: [Value; PATH_LENGTH] = { - let pos: Value<[bool; PATH_LENGTH]> = self.leaf_pos.map(|pos| i2lebsp(pos as u64)); - pos.transpose_array() - }; - - let Q = self.domain.Q(); - - let mut node = leaf; - for (l, ((sibling, pos), chip)) in path.iter().zip(pos.iter()).zip(chips).enumerate() { - // `l` = MERKLE_DEPTH - layer - 1, which is the index obtained from - // enumerating this Merkle path (going from leaf to root). - // For example, when `layer = 31` (the first sibling on the Merkle path), - // we have `l` = 32 - 31 - 1 = 0. - // On the other hand, when `layer = 0` (the final sibling on the Merkle path), - // we have `l` = 32 - 0 - 1 = 31. - - // Constrain which of (node, sibling) is (left, right) with a conditional swap - // tied to the current bit of the position. - let pair = { - let pair = (node, *sibling); - - // Swap node and sibling if needed - chip.swap(layouter.namespace(|| "node position"), pair, *pos)? - }; - - // Compute the node in layer l from its children: - // M^l_i = MerkleCRH(l, M^{l+1}_{2i}, M^{l+1}_{2i+1}) - node = chip.hash_layer( - layouter.namespace(|| format!("MerkleCRH({}, left, right)", l)), - Q, - l, - pair.0, - pair.1, - )?; - } - - Ok(node) - } -} - -#[cfg(test)] -pub mod tests { - use super::{ - chip::{MerkleChip, MerkleConfig}, - MerklePath, - }; - - use crate::{ - ecc::tests::TestFixedBases, - sinsemilla::{ - chip::SinsemillaChip, - tests::{TestCommitDomain, TestHashDomain}, - HashDomains, - }, - utilities::{i2lebsp, lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions}, - }; - - use group::ff::{Field, PrimeField, PrimeFieldBits}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use halo2curves::pasta::pallas; - - use rand::{rngs::OsRng, RngCore}; - use std::{convert::TryInto, iter}; - - const MERKLE_DEPTH: usize = 32; - - #[derive(Default)] - struct MyCircuit { - leaf: Value, - leaf_pos: Value, - merkle_path: Value<[pallas::Base; MERKLE_DEPTH]>, - } - - impl Circuit for MyCircuit { - type Config = ( - MerkleConfig, - MerkleConfig, - ); - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let advices = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - - // Shared fixed column for loading constants - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - // NB: In the actual Action circuit, these fixed columns will be reused - // by other chips. For this test, we are creating new fixed columns. - let fixed_y_q_1 = meta.fixed_column(); - let fixed_y_q_2 = meta.fixed_column(); - - // Fixed columns for the Sinsemilla generator lookup table - let lookup = ( - meta.lookup_table_column(), - meta.lookup_table_column(), - meta.lookup_table_column(), - ); - - let range_check = LookupRangeCheckConfig::configure(meta, advices[9], lookup.0); - - let sinsemilla_config_1 = SinsemillaChip::configure( - meta, - advices[5..].try_into().unwrap(), - advices[7], - fixed_y_q_1, - lookup, - range_check, - ); - let config1 = MerkleChip::configure(meta, sinsemilla_config_1); - - let sinsemilla_config_2 = SinsemillaChip::configure( - meta, - advices[..5].try_into().unwrap(), - advices[2], - fixed_y_q_2, - lookup, - range_check, - ); - let config2 = MerkleChip::configure(meta, sinsemilla_config_2); - - (config1, config2) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Load generator table (shared across both configs) - SinsemillaChip::::load( - config.0.sinsemilla_config.clone(), - &mut layouter, - )?; - - // Construct Merkle chips which will be placed side-by-side in the circuit. - let chip_1 = MerkleChip::construct(config.0.clone()); - let chip_2 = MerkleChip::construct(config.1.clone()); - - let leaf = chip_1.load_private( - layouter.namespace(|| ""), - config.0.cond_swap_config.a(), - self.leaf, - )?; - - let path = MerklePath { - chips: [chip_1, chip_2], - domain: TestHashDomain, - leaf_pos: self.leaf_pos, - path: self.merkle_path, - }; - - let computed_final_root = - path.calculate_root(layouter.namespace(|| "calculate root"), leaf)?; - - self.leaf - .zip(self.leaf_pos) - .zip(self.merkle_path) - .zip(computed_final_root.value()) - .assert_if_known(|(((leaf, leaf_pos), merkle_path), computed_final_root)| { - // The expected final root - let final_root = - merkle_path - .iter() - .enumerate() - .fold(*leaf, |node, (l, sibling)| { - let l = l as u8; - let (left, right) = if leaf_pos & (1 << l) == 0 { - (&node, sibling) - } else { - (sibling, &node) - }; - - use crate::sinsemilla::primitives as sinsemilla; - let merkle_crh = - sinsemilla::HashDomain::from_Q(TestHashDomain.Q().into()); - - merkle_crh - .hash( - iter::empty() - .chain(i2lebsp::<10>(l as u64).iter().copied()) - .chain( - left.to_le_bits() - .iter() - .by_vals() - .take(pallas::Base::NUM_BITS as usize), - ) - .chain( - right - .to_le_bits() - .iter() - .by_vals() - .take(pallas::Base::NUM_BITS as usize), - ), - ) - .unwrap_or(pallas::Base::zero()) - }); - - // Check the computed final root against the expected final root. - computed_final_root == &&final_root - }); - - Ok(()) - } - } - - #[test] - fn merkle_chip() { - let mut rng = OsRng; - - // Choose a random leaf and position - let leaf = pallas::Base::random(rng); - let pos = rng.next_u32(); - - // Choose a path of random inner nodes - let path: Vec<_> = (0..(MERKLE_DEPTH)) - .map(|_| pallas::Base::random(rng)) - .collect(); - - // The root is provided as a public input in the Orchard circuit. - - let circuit = MyCircuit { - leaf: Value::known(leaf), - leaf_pos: Value::known(pos), - merkle_path: Value::known(path.try_into().unwrap()), - }; - - let prover = MockProver::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())) - } - - #[cfg(feature = "dev-graph")] - #[test] - fn print_merkle_chip() { - use plotters::prelude::*; - - let root = BitMapBackend::new("merkle-path-layout.png", (1024, 7680)).into_drawing_area(); - root.fill(&WHITE).unwrap(); - let root = root.titled("MerkleCRH Path", ("sans-serif", 60)).unwrap(); - - let circuit = MyCircuit::default(); - halo2_proofs::dev::CircuitLayout::default() - .show_labels(false) - .render(11, &circuit, &root) - .unwrap(); - } -} diff --git a/halo2_gadgets/src/sinsemilla/merkle/chip.rs b/halo2_gadgets/src/sinsemilla/merkle/chip.rs deleted file mode 100644 index 97da766d0c..0000000000 --- a/halo2_gadgets/src/sinsemilla/merkle/chip.rs +++ /dev/null @@ -1,529 +0,0 @@ -//! Chip implementing a Merkle hash using Sinsemilla as the hash function. - -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Selector}, - poly::Rotation, -}; -use halo2curves::{pasta::pallas, FieldExt}; - -use super::MerkleInstructions; - -use crate::{ - sinsemilla::{primitives as sinsemilla, MessagePiece}, - utilities::RangeConstrained, - { - ecc::FixedPoints, - sinsemilla::{ - chip::{SinsemillaChip, SinsemillaConfig}, - CommitDomains, HashDomains, SinsemillaInstructions, - }, - utilities::{ - cond_swap::{CondSwapChip, CondSwapConfig, CondSwapInstructions}, - UtilitiesInstructions, - }, - }, -}; -use group::ff::PrimeField; - -/// Configuration for the `MerkleChip` implementation. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleConfig -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - advices: [Column; 5], - q_decompose: Selector, - pub(super) cond_swap_config: CondSwapConfig, - pub(super) sinsemilla_config: SinsemillaConfig, -} - -/// Chip implementing `MerkleInstructions`. -/// -/// This chip specifically implements `MerkleInstructions::hash_layer` as the `MerkleCRH` -/// function `hash = SinsemillaHash(Q, 𝑙⋆ || left⋆ || right⋆)`, where: -/// - `𝑙⋆ = I2LEBSP_10(l)` -/// - `left⋆ = I2LEBSP_255(left)` -/// - `right⋆ = I2LEBSP_255(right)` -/// -/// This chip does **NOT** constrain `left⋆` and `right⋆` to be canonical encodings of -/// `left` and `right`. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct MerkleChip -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - config: MerkleConfig, -} - -impl Chip for MerkleChip -where - Hash: HashDomains, - Fixed: FixedPoints, - Commit: CommitDomains, -{ - type Config = MerkleConfig; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -impl MerkleChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - /// Configures the [`MerkleChip`]. - pub fn configure( - meta: &mut ConstraintSystem, - sinsemilla_config: SinsemillaConfig, - ) -> MerkleConfig { - // All five advice columns are equality-enabled by SinsemillaConfig. - let advices = sinsemilla_config.advices(); - let cond_swap_config = CondSwapChip::configure(meta, advices); - - // This selector enables the decomposition gate. - let q_decompose = meta.selector(); - - // Check that pieces have been decomposed correctly for Sinsemilla hash. - // - // - // a = a_0||a_1 = l || (bits 0..=239 of left) - // b = b_0||b_1||b_2 - // = (bits 240..=249 of left) || (bits 250..=254 of left) || (bits 0..=4 of right) - // c = bits 5..=254 of right - // - // The message pieces `a`, `b`, `c` are constrained by Sinsemilla to be - // 250 bits, 20 bits, and 250 bits respectively. - // - // The pieces and subpieces are arranged in the following configuration: - // | A_0 | A_1 | A_2 | A_3 | A_4 | q_decompose | - // ------------------------------------------------------- - // | a | b | c | left | right | 1 | - // | z1_a | z1_b | b_1 | b_2 | l | 0 | - meta.create_gate("Decomposition check", |meta| { - let q_decompose = meta.query_selector(q_decompose); - let l_whole = meta.query_advice(advices[4], Rotation::next()); - - let two_pow_5 = pallas::Base::from(1 << 5); - let two_pow_10 = two_pow_5.square(); - - // a_whole is constrained by Sinsemilla to be 250 bits. - let a_whole = meta.query_advice(advices[0], Rotation::cur()); - // b_whole is constrained by Sinsemilla to be 20 bits. - let b_whole = meta.query_advice(advices[1], Rotation::cur()); - // c_whole is constrained by Sinsemilla to be 250 bits. - let c_whole = meta.query_advice(advices[2], Rotation::cur()); - let left_node = meta.query_advice(advices[3], Rotation::cur()); - let right_node = meta.query_advice(advices[4], Rotation::cur()); - - // a = a_0||a_1 = l || (bits 0..=239 of left) - // - // z_1 of SinsemillaHash(a) = a_1 - // => a_0 = a - (a_1 * 2^10) - let z1_a = meta.query_advice(advices[0], Rotation::next()); - let a_1 = z1_a; - // Derive a_0 (constrained by SinsemillaHash to be 10 bits) - let a_0 = a_whole - a_1.clone() * two_pow_10; - - // b = b_0||b_1||b_2 - // = (bits 240..=249 of left) || (bits 250..=254 of left) || (bits 0..=4 of right) - // The Orchard specification allows this representation to be non-canonical. - // - // - // z_1 of SinsemillaHash(b) = b_1 + 2^5 b_2 - // => b_0 = b - (z1_b * 2^10) - let z1_b = meta.query_advice(advices[1], Rotation::next()); - // b_1 has been constrained to be 5 bits outside this gate. - let b_1 = meta.query_advice(advices[2], Rotation::next()); - // b_2 has been constrained to be 5 bits outside this gate. - let b_2 = meta.query_advice(advices[3], Rotation::next()); - // Constrain b_1 + 2^5 b_2 = z1_b - // https://p.z.cash/halo2-0.1:sinsemilla-merkle-crh-bit-lengths?partial - let b1_b2_check = z1_b.clone() - (b_1.clone() + b_2.clone() * two_pow_5); - // Derive b_0 (constrained by SinsemillaHash to be 10 bits) - let b_0 = b_whole - (z1_b * two_pow_10); - - // Check that left = a_1 (240 bits) || b_0 (10 bits) || b_1 (5 bits) - // https://p.z.cash/halo2-0.1:sinsemilla-merkle-crh-decomposition?partial - let left_check = { - let reconstructed = { - let two_pow_240 = pallas::Base::from_u128(1 << 120).square(); - a_1 + (b_0 + b_1 * two_pow_10) * two_pow_240 - }; - reconstructed - left_node - }; - - // Check that right = b_2 (5 bits) || c (250 bits) - // The Orchard specification allows this representation to be non-canonical. - // - // https://p.z.cash/halo2-0.1:sinsemilla-merkle-crh-decomposition?partial - let right_check = b_2 + c_whole * two_pow_5 - right_node; - - Constraints::with_selector( - q_decompose, - [ - ("l_check", a_0 - l_whole), - ("left_check", left_check), - ("right_check", right_check), - ("b1_b2_check", b1_b2_check), - ], - ) - }); - - MerkleConfig { - advices, - q_decompose, - cond_swap_config, - sinsemilla_config, - } - } - - /// Constructs a [`MerkleChip`] given a [`MerkleConfig`]. - pub fn construct(config: MerkleConfig) -> Self { - MerkleChip { config } - } -} - -impl - MerkleInstructions - for MerkleChip -where - Hash: HashDomains + Eq, - F: FixedPoints, - Commit: CommitDomains + Eq, -{ - #[allow(non_snake_case)] - fn hash_layer( - &self, - mut layouter: impl Layouter, - Q: pallas::Affine, - // l = MERKLE_DEPTH - layer - 1 - l: usize, - left: Self::Var, - right: Self::Var, - ) -> Result { - let config = self.config().clone(); - - // We need to hash `l || left || right`, where `l` is a 10-bit value. - // We allow `left` and `right` to be non-canonical 255-bit encodings. - // - // a = a_0||a_1 = l || (bits 0..=239 of left) - // b = b_0||b_1||b_2 - // = (bits 240..=249 of left) || (bits 250..=254 of left) || (bits 0..=4 of right) - // c = bits 5..=254 of right - // - // We start by witnessing all of the individual pieces, and range-constraining the - // short pieces b_1 and b_2. - // - // https://p.z.cash/halo2-0.1:sinsemilla-merkle-crh-bit-lengths?partial - - // `a = a_0||a_1` = `l` || (bits 0..=239 of `left`) - let a = MessagePiece::from_subpieces( - self.clone(), - layouter.namespace(|| "Witness a = a_0 || a_1"), - [ - RangeConstrained::bitrange_of(Value::known(&pallas::Base::from(l as u64)), 0..10), - RangeConstrained::bitrange_of(left.value(), 0..240), - ], - )?; - - // b = b_0 || b_1 || b_2 - // = (bits 240..=249 of left) || (bits 250..=254 of left) || (bits 0..=4 of right) - let (b_1, b_2, b) = { - // b_0 = (bits 240..=249 of `left`) - let b_0 = RangeConstrained::bitrange_of(left.value(), 240..250); - - // b_1 = (bits 250..=254 of `left`) - // Constrain b_1 to 5 bits. - let b_1 = RangeConstrained::witness_short( - &config.sinsemilla_config.lookup_config(), - layouter.namespace(|| "b_1"), - left.value(), - 250..(pallas::Base::NUM_BITS as usize), - )?; - - // b_2 = (bits 0..=4 of `right`) - // Constrain b_2 to 5 bits. - let b_2 = RangeConstrained::witness_short( - &config.sinsemilla_config.lookup_config(), - layouter.namespace(|| "b_2"), - right.value(), - 0..5, - )?; - - let b = MessagePiece::from_subpieces( - self.clone(), - layouter.namespace(|| "Witness b = b_0 || b_1 || b_2"), - [b_0, b_1.value(), b_2.value()], - )?; - - (b_1, b_2, b) - }; - - // c = bits 5..=254 of `right` - let c = MessagePiece::from_subpieces( - self.clone(), - layouter.namespace(|| "Witness c"), - [RangeConstrained::bitrange_of( - right.value(), - 5..(pallas::Base::NUM_BITS as usize), - )], - )?; - - // hash = SinsemillaHash(Q, 𝑙⋆ || left⋆ || right⋆) - // - // `hash = ⊥` is handled internally to `SinsemillaChip::hash_to_point`: incomplete - // addition constraints allows ⊥ to occur, and then during synthesis it detects - // these edge cases and raises an error (aborting proof creation). - // - // Note that MerkleCRH as-defined maps ⊥ to 0. This is for completeness outside - // the circuit (so that the ⊥ does not propagate into the type system). The chip - // explicitly doesn't map ⊥ to 0; in fact it cannot, as doing so would require - // constraints that amount to using complete addition. The rationale for excluding - // this map is the same as why Sinsemilla uses incomplete addition: this situation - // yields a nontrivial discrete log relation, and by assumption it is hard to find - // these. - // - // https://p.z.cash/proto:merkle-crh-orchard - let (point, zs) = self.hash_to_point( - layouter.namespace(|| format!("hash at l = {}", l)), - Q, - vec![a.inner(), b.inner(), c.inner()].into(), - )?; - let hash = Self::extract(&point); - - // `SinsemillaChip::hash_to_point` returns the running sum for each `MessagePiece`. - // Grab the outputs we need for the decomposition constraints. - let z1_a = zs[0][1].clone(); - let z1_b = zs[1][1].clone(); - - // Check that the pieces have been decomposed properly. - // - // The pieces and subpieces are arranged in the following configuration: - // | A_0 | A_1 | A_2 | A_3 | A_4 | q_decompose | - // ------------------------------------------------------- - // | a | b | c | left | right | 1 | - // | z1_a | z1_b | b_1 | b_2 | l | 0 | - { - layouter.assign_region( - || "Check piece decomposition", - |mut region| { - // Set the fixed column `l` to the current l. - // Recall that l = MERKLE_DEPTH - layer - 1. - // The layer with 2^n nodes is called "layer n". - config.q_decompose.enable(&mut region, 0)?; - region.assign_advice_from_constant( - || format!("l {}", l), - config.advices[4], - 1, - pallas::Base::from(l as u64), - )?; - - // Offset 0 - // Copy and assign `a` at the correct position. - a.inner().cell_value().copy_advice( - || "copy a", - &mut region, - config.advices[0], - 0, - )?; - // Copy and assign `b` at the correct position. - b.inner().cell_value().copy_advice( - || "copy b", - &mut region, - config.advices[1], - 0, - )?; - // Copy and assign `c` at the correct position. - c.inner().cell_value().copy_advice( - || "copy c", - &mut region, - config.advices[2], - 0, - )?; - // Copy and assign the left node at the correct position. - left.copy_advice(|| "left", &mut region, config.advices[3], 0)?; - // Copy and assign the right node at the correct position. - right.copy_advice(|| "right", &mut region, config.advices[4], 0)?; - - // Offset 1 - // Copy and assign z_1 of SinsemillaHash(a) = a_1 - z1_a.copy_advice(|| "z1_a", &mut region, config.advices[0], 1)?; - // Copy and assign z_1 of SinsemillaHash(b) = b_1 - z1_b.copy_advice(|| "z1_b", &mut region, config.advices[1], 1)?; - // Copy `b_1`, which has been constrained to be a 5-bit value - b_1.inner() - .copy_advice(|| "b_1", &mut region, config.advices[2], 1)?; - // Copy `b_2`, which has been constrained to be a 5-bit value - b_2.inner() - .copy_advice(|| "b_2", &mut region, config.advices[3], 1)?; - - Ok(()) - }, - )?; - } - - // Check layer hash output against Sinsemilla primitives hash - #[cfg(test)] - { - use crate::{sinsemilla::primitives::HashDomain, utilities::i2lebsp}; - - use group::ff::PrimeFieldBits; - - left.value() - .zip(right.value()) - .zip(hash.value()) - .assert_if_known(|((left, right), hash)| { - let l = i2lebsp::<10>(l as u64); - let left: Vec<_> = left - .to_le_bits() - .iter() - .by_vals() - .take(pallas::Base::NUM_BITS as usize) - .collect(); - let right: Vec<_> = right - .to_le_bits() - .iter() - .by_vals() - .take(pallas::Base::NUM_BITS as usize) - .collect(); - let merkle_crh = HashDomain::from_Q(Q.into()); - - let mut message = l.to_vec(); - message.extend_from_slice(&left); - message.extend_from_slice(&right); - - let expected = merkle_crh.hash(message.into_iter()).unwrap(); - - expected.to_repr() == hash.to_repr() - }); - } - - Ok(hash) - } -} - -impl UtilitiesInstructions for MerkleChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - type Var = AssignedCell; -} - -impl CondSwapInstructions for MerkleChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - #[allow(clippy::type_complexity)] - fn swap( - &self, - layouter: impl Layouter, - pair: (Self::Var, Value), - swap: Value, - ) -> Result<(Self::Var, Self::Var), Error> { - let config = self.config().cond_swap_config.clone(); - let chip = CondSwapChip::::construct(config); - chip.swap(layouter, pair, swap) - } -} - -impl SinsemillaInstructions - for MerkleChip -where - Hash: HashDomains, - F: FixedPoints, - Commit: CommitDomains, -{ - type CellValue = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::CellValue; - - type Message = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::Message; - type MessagePiece = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::MessagePiece; - type RunningSum = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::RunningSum; - - type X = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::X; - type NonIdentityPoint = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::NonIdentityPoint; - type FixedPoints = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::FixedPoints; - - type HashDomains = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::HashDomains; - type CommitDomains = as SinsemillaInstructions< - pallas::Affine, - { sinsemilla::K }, - { sinsemilla::C }, - >>::CommitDomains; - - fn witness_message_piece( - &self, - layouter: impl Layouter, - value: Value, - num_words: usize, - ) -> Result { - let config = self.config().sinsemilla_config.clone(); - let chip = SinsemillaChip::::construct(config); - chip.witness_message_piece(layouter, value, num_words) - } - - #[allow(non_snake_case)] - #[allow(clippy::type_complexity)] - fn hash_to_point( - &self, - layouter: impl Layouter, - Q: pallas::Affine, - message: Self::Message, - ) -> Result<(Self::NonIdentityPoint, Vec>), Error> { - let config = self.config().sinsemilla_config.clone(); - let chip = SinsemillaChip::::construct(config); - chip.hash_to_point(layouter, Q, message) - } - - fn extract(point: &Self::NonIdentityPoint) -> Self::X { - SinsemillaChip::::extract(point) - } -} diff --git a/halo2_gadgets/src/sinsemilla/message.rs b/halo2_gadgets/src/sinsemilla/message.rs deleted file mode 100644 index 6bb72e2f1e..0000000000 --- a/halo2_gadgets/src/sinsemilla/message.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Gadget and chips for the Sinsemilla hash function. -use ff::PrimeFieldBits; -use halo2_proofs::{ - arithmetic::FieldExt, - circuit::{AssignedCell, Cell, Value}, -}; -use std::fmt::Debug; - -/// A [`Message`] composed of several [`MessagePiece`]s. -#[derive(Clone, Debug)] -pub struct Message(Vec>); - -impl - From>> for Message -{ - fn from(pieces: Vec>) -> Self { - // A message cannot contain more than `MAX_WORDS` words. - assert!(pieces.iter().map(|piece| piece.num_words()).sum::() < MAX_WORDS); - Message(pieces) - } -} - -impl std::ops::Deref - for Message -{ - type Target = [MessagePiece]; - - fn deref(&self) -> &[MessagePiece] { - &self.0 - } -} - -/// A [`MessagePiece`] of some bitlength. -/// -/// The piece must fit within a base field element, which means its length -/// cannot exceed the base field's `NUM_BITS`. -#[derive(Clone, Debug)] -pub struct MessagePiece { - cell_value: AssignedCell, - /// The number of K-bit words in this message piece. - num_words: usize, -} - -impl MessagePiece { - pub fn new(cell_value: AssignedCell, num_words: usize) -> Self { - assert!(num_words * K < F::NUM_BITS as usize); - Self { - cell_value, - num_words, - } - } - - pub fn num_words(&self) -> usize { - self.num_words - } - - pub fn cell(&self) -> Cell { - self.cell_value.cell() - } - - pub fn field_elem(&self) -> Value { - self.cell_value.value().cloned() - } - - pub fn cell_value(&self) -> AssignedCell { - self.cell_value.clone() - } -} diff --git a/halo2_gadgets/src/sinsemilla/primitives.rs b/halo2_gadgets/src/sinsemilla/primitives.rs deleted file mode 100644 index fd2e4aea72..0000000000 --- a/halo2_gadgets/src/sinsemilla/primitives.rs +++ /dev/null @@ -1,308 +0,0 @@ -//! Implementation of Sinsemilla outside the circuit. - -use group::{Curve, Wnaf}; -use halo2_proofs::arithmetic::{CurveAffine, CurveExt}; -use halo2curves::pasta::pallas; -use subtle::CtOption; - -mod addition; -use self::addition::IncompletePoint; -mod sinsemilla_s; -pub use sinsemilla_s::SINSEMILLA_S; - -/// Number of bits of each message piece in $\mathsf{SinsemillaHashToPoint}$ -pub const K: usize = 10; - -/// $\frac{1}{2^K}$ -pub const INV_TWO_POW_K: [u8; 32] = [ - 1, 0, 192, 196, 160, 229, 70, 82, 221, 165, 74, 202, 85, 7, 62, 34, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 240, 63, -]; - -/// The largest integer such that $2^c \leq (r_P - 1) / 2$, where $r_P$ is the order -/// of Pallas. -pub const C: usize = 253; - -// Sinsemilla Q generators - -/// SWU hash-to-curve personalization for Sinsemilla $Q$ generators. -pub const Q_PERSONALIZATION: &str = "z.cash:SinsemillaQ"; - -// Sinsemilla S generators - -/// SWU hash-to-curve personalization for Sinsemilla $S$ generators. -pub const S_PERSONALIZATION: &str = "z.cash:SinsemillaS"; - -pub(crate) fn lebs2ip_k(bits: &[bool]) -> u32 { - assert!(bits.len() == K); - bits.iter() - .enumerate() - .fold(0u32, |acc, (i, b)| acc + if *b { 1 << i } else { 0 }) -} - -/// Coordinate extractor for Pallas. -/// -/// Defined in [Zcash Protocol Spec § 5.4.9.7: Coordinate Extractor for Pallas][concreteextractorpallas]. -/// -/// [concreteextractorpallas]: https://zips.z.cash/protocol/nu5.pdf#concreteextractorpallas -fn extract_p_bottom(point: CtOption) -> CtOption { - point.map(|p| { - p.to_affine() - .coordinates() - .map(|c| *c.x()) - .unwrap_or_else(pallas::Base::zero) - }) -} - -/// Pads the given iterator (which MUST have length $\leq K * C$) with zero-bits to a -/// multiple of $K$ bits. -struct Pad> { - /// The iterator we are padding. - inner: I, - /// The measured length of the inner iterator. - /// - /// This starts as a lower bound, and will be accurate once `padding_left.is_some()`. - len: usize, - /// The amount of padding that remains to be emitted. - padding_left: Option, -} - -impl> Pad { - fn new(inner: I) -> Self { - Pad { - inner, - len: 0, - padding_left: None, - } - } -} - -impl> Iterator for Pad { - type Item = bool; - - fn next(&mut self) -> Option { - loop { - // If we have identified the required padding, the inner iterator has ended, - // and we will never poll it again. - if let Some(n) = self.padding_left.as_mut() { - if *n == 0 { - // Either we already emitted all necessary padding, or there was no - // padding required. - break None; - } else { - // Emit the next padding bit. - *n -= 1; - break Some(false); - } - } else if let Some(ret) = self.inner.next() { - // We haven't reached the end of the inner iterator yet. - self.len += 1; - assert!(self.len <= K * C); - break Some(ret); - } else { - // Inner iterator just ended, so we now know its length. - let rem = self.len % K; - if rem > 0 { - // The inner iterator requires padding in the range [1,K). - self.padding_left = Some(K - rem); - } else { - // No padding required. - self.padding_left = Some(0); - } - } - } - } -} - -/// A domain in which $\mathsf{SinsemillaHashToPoint}$ and $\mathsf{SinsemillaHash}$ can -/// be used. -#[derive(Debug, Clone)] -#[allow(non_snake_case)] -pub struct HashDomain { - Q: pallas::Point, -} - -impl HashDomain { - /// Constructs a new `HashDomain` with a specific prefix string. - pub fn new(domain: &str) -> Self { - HashDomain { - Q: pallas::Point::hash_to_curve(Q_PERSONALIZATION)(domain.as_bytes()), - } - } - - /// $\mathsf{SinsemillaHashToPoint}$ from [§ 5.4.1.9][concretesinsemillahash]. - /// - /// [concretesinsemillahash]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillahash - pub fn hash_to_point(&self, msg: impl Iterator) -> CtOption { - self.hash_to_point_inner(msg).into() - } - - #[allow(non_snake_case)] - fn hash_to_point_inner(&self, msg: impl Iterator) -> IncompletePoint { - let padded: Vec<_> = Pad::new(msg).collect(); - - padded - .chunks(K) - .fold(IncompletePoint::from(self.Q), |acc, chunk| { - let (S_x, S_y) = SINSEMILLA_S[lebs2ip_k(chunk) as usize]; - let S_chunk = pallas::Affine::from_xy(S_x, S_y).unwrap(); - (acc + S_chunk) + acc - }) - } - - /// $\mathsf{SinsemillaHash}$ from [§ 5.4.1.9][concretesinsemillahash]. - /// - /// [concretesinsemillahash]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillahash - /// - /// # Panics - /// - /// This panics if the message length is greater than [`K`] * [`C`] - pub fn hash(&self, msg: impl Iterator) -> CtOption { - extract_p_bottom(self.hash_to_point(msg)) - } - - /// Constructs a new `HashDomain` from a given `Q`. - /// - /// This is only for testing use. - #[cfg(test)] - #[allow(non_snake_case)] - pub(crate) fn from_Q(Q: pallas::Point) -> Self { - HashDomain { Q } - } - - /// Returns the Sinsemilla $Q$ constant for this domain. - #[cfg(any(test, feature = "test-dependencies"))] - #[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] - #[allow(non_snake_case)] - pub fn Q(&self) -> pallas::Point { - self.Q - } -} - -/// A domain in which $\mathsf{SinsemillaCommit}$ and $\mathsf{SinsemillaShortCommit}$ can -/// be used. -#[derive(Debug)] -#[allow(non_snake_case)] -pub struct CommitDomain { - M: HashDomain, - R: pallas::Point, -} - -impl CommitDomain { - /// Constructs a new `CommitDomain` with a specific prefix string. - pub fn new(domain: &str) -> Self { - let m_prefix = format!("{}-M", domain); - let r_prefix = format!("{}-r", domain); - let hasher_r = pallas::Point::hash_to_curve(&r_prefix); - CommitDomain { - M: HashDomain::new(&m_prefix), - R: hasher_r(&[]), - } - } - - /// $\mathsf{SinsemillaCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. - /// - /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit - #[allow(non_snake_case)] - pub fn commit( - &self, - msg: impl Iterator, - r: &pallas::Scalar, - ) -> CtOption { - // We use complete addition for the blinding factor. - CtOption::::from(self.M.hash_to_point_inner(msg)) - .map(|p| p + Wnaf::new().scalar(r).base(self.R)) - } - - /// $\mathsf{SinsemillaShortCommit}$ from [§ 5.4.8.4][concretesinsemillacommit]. - /// - /// [concretesinsemillacommit]: https://zips.z.cash/protocol/nu5.pdf#concretesinsemillacommit - pub fn short_commit( - &self, - msg: impl Iterator, - r: &pallas::Scalar, - ) -> CtOption { - extract_p_bottom(self.commit(msg, r)) - } - - /// Returns the Sinsemilla $R$ constant for this domain. - #[cfg(any(test, feature = "test-dependencies"))] - #[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] - #[allow(non_snake_case)] - pub fn R(&self) -> pallas::Point { - self.R - } - - /// Returns the Sinsemilla $Q$ constant for this domain. - #[cfg(any(test, feature = "test-dependencies"))] - #[cfg_attr(docsrs, doc(cfg(feature = "test-dependencies")))] - #[allow(non_snake_case)] - pub fn Q(&self) -> pallas::Point { - self.M.Q - } -} - -#[cfg(test)] -mod tests { - use super::{Pad, K}; - use halo2curves::{pasta::pallas, CurveExt}; - - #[test] - fn pad() { - assert_eq!( - Pad::new([].iter().cloned()).collect::>(), - vec![false; 0] - ); - assert_eq!( - Pad::new([true].iter().cloned()).collect::>(), - vec![true, false, false, false, false, false, false, false, false, false] - ); - assert_eq!( - Pad::new([true, true].iter().cloned()).collect::>(), - vec![true, true, false, false, false, false, false, false, false, false] - ); - assert_eq!( - Pad::new([true, true, true].iter().cloned()).collect::>(), - vec![true, true, true, false, false, false, false, false, false, false] - ); - assert_eq!( - Pad::new( - [true, true, false, true, false, true, false, true, false, true] - .iter() - .cloned() - ) - .collect::>(), - vec![true, true, false, true, false, true, false, true, false, true] - ); - assert_eq!( - Pad::new( - [true, true, false, true, false, true, false, true, false, true, true] - .iter() - .cloned() - ) - .collect::>(), - vec![ - true, true, false, true, false, true, false, true, false, true, true, false, false, - false, false, false, false, false, false, false - ] - ); - } - - #[test] - fn sinsemilla_s() { - use super::sinsemilla_s::SINSEMILLA_S; - use group::Curve; - use halo2curves::CurveAffine; - - let hasher = pallas::Point::hash_to_curve(super::S_PERSONALIZATION); - - for j in 0..(1u32 << K) { - let computed = { - let point = hasher(&j.to_le_bytes()).to_affine().coordinates().unwrap(); - (*point.x(), *point.y()) - }; - let actual = SINSEMILLA_S[j as usize]; - assert_eq!(computed, actual); - } - } -} diff --git a/halo2_gadgets/src/sinsemilla/primitives/addition.rs b/halo2_gadgets/src/sinsemilla/primitives/addition.rs deleted file mode 100644 index 9d4574dca1..0000000000 --- a/halo2_gadgets/src/sinsemilla/primitives/addition.rs +++ /dev/null @@ -1,73 +0,0 @@ -use std::ops::Add; - -use group::{cofactor::CofactorCurveAffine, Group}; -use halo2curves::pasta::pallas; -use subtle::{ConstantTimeEq, CtOption}; - -/// P ∪ {⊥} -/// -/// Simulated incomplete addition built over complete addition. -#[derive(Clone, Copy, Debug)] -pub(super) struct IncompletePoint(CtOption); - -impl From for IncompletePoint { - fn from(p: pallas::Point) -> Self { - IncompletePoint(CtOption::new(p, 1.into())) - } -} - -impl From for CtOption { - fn from(p: IncompletePoint) -> Self { - p.0 - } -} - -impl Add for IncompletePoint { - type Output = IncompletePoint; - - #[allow(clippy::suspicious_arithmetic_impl)] - fn add(self, rhs: Self) -> Self::Output { - // ⊥ ⸭ ⊥ = ⊥ - // ⊥ ⸭ P = ⊥ - IncompletePoint(self.0.and_then(|p| { - // P ⸭ ⊥ = ⊥ - rhs.0.and_then(|q| { - // 0 ⸭ 0 = ⊥ - // 0 ⸭ P = ⊥ - // P ⸭ 0 = ⊥ - // (x, y) ⸭ (x', y') = ⊥ if x == x' - // (x, y) ⸭ (x', y') = (x, y) + (x', y') if x != x' - CtOption::new( - p + q, - !(p.is_identity() | q.is_identity() | p.ct_eq(&q) | p.ct_eq(&-q)), - ) - }) - })) - } -} - -impl Add for IncompletePoint { - type Output = IncompletePoint; - - /// Specialisation of incomplete addition for mixed addition. - #[allow(clippy::suspicious_arithmetic_impl)] - fn add(self, rhs: pallas::Affine) -> Self::Output { - // ⊥ ⸭ ⊥ = ⊥ - // ⊥ ⸭ P = ⊥ - IncompletePoint(self.0.and_then(|p| { - // P ⸭ ⊥ = ⊥ is satisfied by definition. - let q = rhs.to_curve(); - - // 0 ⸭ 0 = ⊥ - // 0 ⸭ P = ⊥ - // P ⸭ 0 = ⊥ - // (x, y) ⸭ (x', y') = ⊥ if x == x' - // (x, y) ⸭ (x', y') = (x, y) + (x', y') if x != x' - CtOption::new( - // Use mixed addition for efficiency. - p + rhs, - !(p.is_identity() | q.is_identity() | p.ct_eq(&q) | p.ct_eq(&-q)), - ) - })) - } -} diff --git a/halo2_gadgets/src/sinsemilla/primitives/sinsemilla_s.rs b/halo2_gadgets/src/sinsemilla/primitives/sinsemilla_s.rs deleted file mode 100644 index c72fe5841f..0000000000 --- a/halo2_gadgets/src/sinsemilla/primitives/sinsemilla_s.rs +++ /dev/null @@ -1,14344 +0,0 @@ -use super::K; -use halo2curves::pasta::pallas; - -/// The precomputed bases for the [Sinsemilla hash function][concretesinsemillahash]. -/// -/// [concretesinsemillahash]: https://zips.z.cash/protocol/protocol.pdf#concretesinsemillahash -pub const SINSEMILLA_S: [(pallas::Base, pallas::Base); 1 << K] = [ - ( - pallas::Base::from_raw([ - 0x5a91_eb91_2044_ea5f, - 0x29a0_5baf_bede_62b5, - 0x1431_d4ea_7d4a_fc7b, - 0x0db5_218b_e688_1f0f, - ]), - pallas::Base::from_raw([ - 0x17c2_4f76_bf8e_6483, - 0x944a_041c_2e65_ba01, - 0x9caf_6629_8493_d5d0, - 0x2f0f_40c2_f152_a01c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xce4a_e33e_a108_af91, - 0xe677_00ca_2464_9b8f, - 0xc8fd_33eb_3917_5404, - 0x2111_12b4_b3e1_9518, - ]), - pallas::Base::from_raw([ - 0x1d83_c293_f810_c5ee, - 0xb43c_744a_670e_19bc, - 0xa38a_3e79_cd5a_35fe, - 0x06c5_9939_93ad_b03b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x22e0_c475_a18f_6d24, - 0xf40c_b333_4b54_11c0, - 0x4661_a4e2_355b_9b33, - 0x25b3_2ccd_49f9_25a3, - ]), - pallas::Base::from_raw([ - 0xa67d_6b8d_b8fd_9757, - 0x4be1_ebb9_f945_ccd2, - 0x7d53_d0f3_23b4_4711, - 0x140f_f2ba_70d0_692c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa5fa_ef0f_0419_dabc, - 0x6539_ca12_938b_1826, - 0x60ff_465c_d02c_701f, - 0x1421_5a48_e118_32c9, - ]), - pallas::Base::from_raw([ - 0x011d_5d36_25ca_36dc, - 0x97b6_3b4b_53e2_ad56, - 0xc711_a0b9_0b58_03bd, - 0x1066_6957_becb_884d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xcd48_cef6_4bed_0936, - 0x0e94_8b52_f738_61ce, - 0x9ab9_b595_d23f_059f, - 0x315c_f93b_9e63_151c, - ]), - pallas::Base::from_raw([ - 0xe257_7684_a31c_721a, - 0x81ef_1386_c070_a51d, - 0x2afb_9a52_d043_78ca, - 0x2c54_c0b3_8dfb_ad40, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1e62_9662_aa5a_3fdf, - 0x94fb_57dc_9d31_389b, - 0x63c5_542e_be6c_3ab7, - 0x1d74_51a5_7e92_5ec5, - ]), - pallas::Base::from_raw([ - 0x934c_1dc8_aaca_454b, - 0xc086_048c_4eef_c0dd, - 0xc49c_1472_164b_6fbc, - 0x0a4b_5139_9347_7ec7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7e7c_cebd_ac44_118f, - 0xe055_272f_8429_ff1c, - 0x3c80_b5f8_24a7_5f24, - 0x0d3d_3c74_10d4_4668, - ]), - pallas::Base::from_raw([ - 0x79ea_b21b_b522_55cc, - 0x1268_61c0_de4f_0982, - 0xa02e_3186_23a5_5ae9, - 0x2b94_e712_9758_334f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0e77_383e_d712_9d2f, - 0x6283_df71_4b0f_9b18, - 0x0864_617c_d666_062c, - 0x197e_faba_7491_0b57, - ]), - pallas::Base::from_raw([ - 0x85b8_e2cb_12fd_c127, - 0x7a88_75b5_de27_45cd, - 0x8df5_6a97_ed99_d31b, - 0x34d9_5547_d6e9_56a9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd21c_d292_6b24_b055, - 0xa416_7a07_7246_418e, - 0x3e29_11ab_ef54_9b47, - 0x305a_d0e8_b11c_ee66, - ]), - pallas::Base::from_raw([ - 0x9b39_73cf_a5bf_b938, - 0x12a2_0ca5_d138_80d6, - 0x8207_1242_c3b7_34a4, - 0x3e25_9102_6dbb_bfd8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf6bc_e362_6b48_56be, - 0xdf5e_e6f1_5b66_3484, - 0xbc37_bdf1_4766_3e61, - 0x2a80_ed20_aecc_771f, - ]), - pallas::Base::from_raw([ - 0xaeaf_58cd_40d9_d753, - 0x6776_81a1_39a9_44eb, - 0xdb78_4220_d080_d1ae, - 0x3bed_9f53_2f89_c873, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa96d_351c_69e7_3b34, - 0xe5df_e62c_bb74_b432, - 0x3e0b_f886_c563_3909, - 0x1169_679d_516b_0f52, - ]), - pallas::Base::from_raw([ - 0x447f_2648_3a56_52ee, - 0x77d8_03b3_afe8_3912, - 0xbe1e_a779_988f_4fd3, - 0x24dc_58d8_46ef_f85d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x851d_c62e_bc87_5030, - 0x1957_510c_703c_5765, - 0xd439_8de8_3aae_c992, - 0x0a64_5164_e0e0_d1cb, - ]), - pallas::Base::from_raw([ - 0xd768_494c_1aa6_936d, - 0x0c89_d7ee_a548_c2a4, - 0x7e1f_87b7_9978_76b1, - 0x153f_b63d_3879_f182, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc565_0619_42a8_3439, - 0x7716_f57c_193a_3df2, - 0x1325_b0e1_8d7a_ea0a, - 0x05a9_1753_a68b_7601, - ]), - pallas::Base::from_raw([ - 0x2443_2316_26bd_d43c, - 0x959f_e764_a3f2_575f, - 0xd709_6a40_9799_144e, - 0x1c29_c630_347e_9508, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe843_6f46_1411_e72a, - 0x2c1a_4034_7249_2a59, - 0x1347_0a8d_938a_b691, - 0x25e3_34b5_cec9_3544, - ]), - pallas::Base::from_raw([ - 0xcec5_d233_9cad_4b3d, - 0xa40d_0761_a4cc_45ab, - 0x194c_d250_2d80_84b2, - 0x0160_64db_6159_2474, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe2f0_65b5_2537_5cc9, - 0x2528_5987_8c88_25ab, - 0x9252_31c1_bc9d_6a66, - 0x379c_2bd0_c190_9c7e, - ]), - pallas::Base::from_raw([ - 0xa0fb_efa7_6375_9430, - 0x430e_1e41_7b73_83f0, - 0xddea_123a_66f3_6e40, - 0x11a9_c254_99d5_9f1b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0b5a_9e1e_862e_edaa, - 0xc0a3_4382_61ff_61c6, - 0x4b41_f6dc_4801_f3a1, - 0x0c6f_c7b2_d365_6f82, - ]), - pallas::Base::from_raw([ - 0xf30d_50e8_3e60_3bb5, - 0x589f_b478_7d54_8e5f, - 0x06d5_b032_d1ea_0eeb, - 0x2492_a76d_96dc_fe8e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0719_4d69_3a4f_e5d9, - 0xc3f4_ced6_5ced_7022, - 0x1965_c5c3_f9ee_e6b7, - 0x0c17_5d45_3bb5_0e04, - ]), - pallas::Base::from_raw([ - 0x6e28_e65c_02a8_979a, - 0x9155_bdb2_213a_1ec2, - 0xa592_5dd2_ac1b_a08a, - 0x106e_3d4f_2d01_2990, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2af5_5769_718f_6d0a, - 0x0acc_0135_db3d_9c80, - 0x31f8_9d95_9313_5e05, - 0x26e5_eae3_20ed_b155, - ]), - pallas::Base::from_raw([ - 0xd75b_fdee_b95f_d1c9, - 0x1e63_a80a_818c_5374, - 0x4bb1_c3e6_0f0b_c040, - 0x1d05_882a_cd14_4b0c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7ec3_90f2_5e39_5b94, - 0x4230_0755_c68f_a549, - 0x9210_9733_af81_0407, - 0x310d_60d7_14eb_00d9, - ]), - pallas::Base::from_raw([ - 0xce04_43cb_4410_650a, - 0xb1c0_4053_f900_ef43, - 0x4087_e7a3_9312_1fdd, - 0x3ee2_559e_cdce_ec5c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa2a0_b2bb_c709_eb43, - 0x8ade_17ea_bf18_0624, - 0xbe3d_cee5_1eac_8187, - 0x1719_0481_09ec_ac8d, - ]), - pallas::Base::from_raw([ - 0x2abc_973a_cc15_a05b, - 0x50a8_df0b_570a_193a, - 0x87f1_e098_4f0e_1d44, - 0x1267_3ac5_b9fe_f8c5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb461_d0fe_6d58_3369, - 0xccbc_110f_c982_9287, - 0x0263_da47_2626_a5f0, - 0x1289_d222_9c37_19c6, - ]), - pallas::Base::from_raw([ - 0x7f84_d109_f869_6212, - 0xe7b6_8435_60c9_f37e, - 0xc9ab_26a3_a8a3_b9aa, - 0x08a7_e5e9_d4ad_1e44, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd657_d70e_67a6_cffb, - 0x1bc2_8f7a_f5d8_d663, - 0x176c_cb97_5e2e_acdd, - 0x08dc_48f1_a91c_222a, - ]), - pallas::Base::from_raw([ - 0xc6aa_0ceb_40b6_128c, - 0x94a1_9ee5_c270_a217, - 0x9f79_f114_a1f4_083a, - 0x21f4_0941_aa55_b3d0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x84c6_e703_7113_c2c1, - 0x9549_5a9a_5e2c_f521, - 0xae9d_c0a2_1bc8_b85e, - 0x2bde_7809_257f_2d02, - ]), - pallas::Base::from_raw([ - 0xa114_c0a6_314e_d2f9, - 0x9be7_e608_3d7e_876f, - 0xc105_6823_d929_fd2a, - 0x15ac_6d2a_83e2_50bd, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb0fe_9fd5_a421_340b, - 0x48e4_f171_3c9e_cd26, - 0xe4f4_ac71_3d4a_95bc, - 0x312b_6128_1ab5_d033, - ]), - pallas::Base::from_raw([ - 0x405b_d400_afdb_5d9c, - 0xaaeb_8090_ef6b_9390, - 0x7469_c0b3_e23c_53dd, - 0x2e4f_21bf_b05d_4559, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa0bf_d82b_7612_2e84, - 0x6c78_ca0a_b548_2d27, - 0x75ae_5653_62af_eb1d, - 0x089b_3b7f_8bd4_ea08, - ]), - pallas::Base::from_raw([ - 0x7fca_3834_c670_2579, - 0xa062_31d2_085d_6258, - 0xb32f_6836_d782_eb34, - 0x3708_e831_35ae_10c4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9f6d_c014_6c05_c7fe, - 0x1119_b3b5_d67c_a65f, - 0x45bf_6d2e_f7e6_fe54, - 0x0141_08ac_9ab6_3e4f, - ]), - pallas::Base::from_raw([ - 0x57f9_36e7_a514_d173, - 0x3d4e_a9b8_283e_a3f2, - 0x0b45_9bbe_bf56_d8df, - 0x0096_be83_6417_c3ce, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbf84_7e6e_a60a_1e10, - 0x007d_0da9_59a1_8af7, - 0x9b66_6f39_805d_f26e, - 0x2dda_a8b1_c70d_4798, - ]), - pallas::Base::from_raw([ - 0x8afa_e4a1_2104_3215, - 0xfc45_281d_665c_435f, - 0xcf42_5d23_97a4_d0d6, - 0x203b_d5e4_3544_e416, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6355_a342_c769_b991, - 0xaf94_3561_7ca8_fba5, - 0x9bc6_1953_1bc6_867c, - 0x35c6_b4b2_7ce9_8c84, - ]), - pallas::Base::from_raw([ - 0x358b_52f2_aa05_d0e2, - 0x1e36_f404_1069_11a7, - 0xdfb1_775d_f512_925e, - 0x2f0e_4cff_2885_5660, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9bc6_45aa_659d_394f, - 0x63fb_f9d5_aff5_52c2, - 0x2a81_a1f9_157d_0ddf, - 0x0840_8d6d_792b_1bdd, - ]), - pallas::Base::from_raw([ - 0x6214_c9e0_a442_6fed, - 0x580c_2dc1_b2dc_4db0, - 0xdf6e_7ce6_7c07_8b91, - 0x149b_86c7_aa0a_5807, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2366_fb20_016a_d15d, - 0x7e11_a509_32be_92a2, - 0xdf46_3c90_d34d_85db, - 0x3b7d_3524_37fb_ddae, - ]), - pallas::Base::from_raw([ - 0xd701_78a2_e2e7_3b2c, - 0xeb76_7a60_49bb_fd17, - 0xa081_0c5a_7118_8504, - 0x30e1_da14_7a31_ac8a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x996c_1cc3_79a3_05e2, - 0x61d9_35a7_da7f_f9df, - 0xe77e_3c50_0e84_d1fe, - 0x119d_6098_c1df_c009, - ]), - pallas::Base::from_raw([ - 0xe83c_68f6_0bac_ad89, - 0xe3e4_5f6b_7f33_8aea, - 0xcb02_edb7_2703_0a11, - 0x0dfe_fcd8_c7a0_37d2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0249_e1ef_c0c1_2e3f, - 0xfd35_f750_fc1b_140e, - 0x34cc_fd25_ee0a_24a4, - 0x2d85_ea37_1450_e936, - ]), - pallas::Base::from_raw([ - 0xea03_7e87_7076_c6a6, - 0x1e86_054a_7181_9a98, - 0xc8b2_0a67_de55_ffdd, - 0x2fa0_f1dc_c560_6ead, - ]), - ), - ( - pallas::Base::from_raw([ - 0x149d_4058_8269_142a, - 0xc47e_8699_87cd_0c7e, - 0x9083_84e4_4ce8_c260, - 0x0d65_ccec_99ef_3d51, - ]), - pallas::Base::from_raw([ - 0x3d9f_bece_1b95_bb5c, - 0x7369_87ea_5b12_60ce, - 0x69c5_cc43_e099_3c2c, - 0x1296_2805_bcb2_5e3d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfd0f_79ac_f857_70f6, - 0x2cad_5ad0_3b87_58f2, - 0xd79d_4eba_953a_f087, - 0x0074_778c_62d8_0363, - ]), - pallas::Base::from_raw([ - 0x4d53_43bd_75b7_04b2, - 0xfb69_64df_389f_bd6c, - 0x0999_4f51_36f1_c414, - 0x0776_f4ae_c6cb_4e85, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2207_b16e_8cac_9dc4, - 0x6fcc_2464_92c3_0265, - 0x1f05_e00a_14f4_b845, - 0x01a9_d4be_c204_e872, - ]), - pallas::Base::from_raw([ - 0xf783_69ae_24fb_81a8, - 0xf741_a8a2_38ae_9967, - 0x4408_0885_faae_b30d, - 0x03f7_7f1f_49b9_18e6, - ]), - ), - ( - pallas::Base::from_raw([ - 0xad73_e083_fd4b_c101, - 0xb299_c606_ca3b_197f, - 0x61c8_0000_0ba8_6506, - 0x1691_35f3_c4b5_4f76, - ]), - pallas::Base::from_raw([ - 0x8760_58ce_eb92_e28c, - 0x34f0_16e0_f86c_0e2d, - 0x86b0_495e_c47b_3f50, - 0x03f1_c42b_c4c5_85ff, - ]), - ), - ( - pallas::Base::from_raw([ - 0x017d_94b7_2cab_798c, - 0x8d6d_cb5b_18aa_f523, - 0x8e08_8b5d_8994_c20b, - 0x19ba_e178_e635_fe13, - ]), - pallas::Base::from_raw([ - 0xab27_84b4_994a_0119, - 0x9da4_fe0e_635c_7e33, - 0x1143_8112_caa2_afc4, - 0x3acf_da94_ded9_c4e7, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbbce_cb08_317a_55bc, - 0x36aa_ddcd_3238_f0e6, - 0xdf00_05b6_e6ab_d61e, - 0x2527_c64e_053d_087c, - ]), - pallas::Base::from_raw([ - 0x6be8_48ee_033a_68ef, - 0x55a3_f9ac_d4f4_cee1, - 0xf6dd_57ce_d465_28bf, - 0x1e27_ea7d_b509_cc96, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe5bc_12d9_9516_4280, - 0x2a00_0dc2_5125_5df6, - 0xa936_924b_164c_d882, - 0x34a9_358a_32a8_ce49, - ]), - pallas::Base::from_raw([ - 0x60e8_77e4_dfcb_aca2, - 0x0aa5_3e88_25f8_a521, - 0xe325_6cc5_83dd_f098, - 0x3bdb_fc5c_5aa3_cdb8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6d95_f7ea_ea3d_16d8, - 0x03c0_4e9a_6bd6_5383, - 0xec05_bb17_c4fe_b283, - 0x289e_03a5_ed1f_3b07, - ]), - pallas::Base::from_raw([ - 0x2b6a_c52f_feb1_7686, - 0xbcb7_da92_4e49_8948, - 0xa995_cd81_d04d_dbd3, - 0x0c46_6c57_1159_224a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6093_9be7_a4d2_9f0c, - 0x1518_62a2_b799_0aa2, - 0x44a3_e62c_1ce7_8cc2, - 0x201e_25ea_427d_e5f3, - ]), - pallas::Base::from_raw([ - 0x5853_5ee9_27ff_6b4f, - 0xa9ba_b5b3_9592_7126, - 0x2c60_0708_e61e_5681, - 0x31d4_68f6_37a7_026d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x97ec_2bda_32f9_27b3, - 0x7e79_9f38_c361_ed87, - 0x588f_ac0b_d601_fa88, - 0x275f_7736_734d_27fe, - ]), - pallas::Base::from_raw([ - 0x6426_8a27_c545_d9b9, - 0x46a0_a23d_c423_01eb, - 0xac7d_e04c_dccf_c81c, - 0x3030_4778_8312_b499, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9491_a146_3215_8028, - 0xee63_c9c2_6401_e1ab, - 0xe68f_139c_e3e6_847b, - 0x0ce9_e803_9aca_842f, - ]), - pallas::Base::from_raw([ - 0xe09d_04d1_25c7_4609, - 0x3770_bbd0_c05e_f8ad, - 0xdd8b_8c88_a169_9567, - 0x2d99_3912_f127_a6e4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe531_5459_6f63_dd08, - 0xf7a0_13fe_10a1_9fc0, - 0xd7b4_76dc_ac74_a040, - 0x08a0_75bf_2f3f_783f, - ]), - pallas::Base::from_raw([ - 0x1962_3209_80d2_b200, - 0x3da6_e1b6_5f7f_1977, - 0x6168_4dbf_f2db_9c35, - 0x3c21_4bf5_b381_9204, - ]), - ), - ( - pallas::Base::from_raw([ - 0x46fc_698d_e305_8e9d, - 0xed82_7429_e58b_0e53, - 0xff3b_2ab5_65d8_30e8, - 0x2ee6_898e_6f25_1e50, - ]), - pallas::Base::from_raw([ - 0x2fea_1665_b778_7f9e, - 0xa84c_eb52_339e_9083, - 0xfc32_2809_6906_9bf6, - 0x22a0_7570_d244_95a4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8b2e_1430_028d_9350, - 0xa9ad_41fb_bf86_26c0, - 0xecff_6798_0a63_b4a7, - 0x38ec_640b_0d84_abd2, - ]), - pallas::Base::from_raw([ - 0xda17_249d_9fd9_ddc4, - 0x3862_5d42_a318_2c13, - 0x74b0_4c68_5377_a262, - 0x1e61_c8ab_ab50_80ed, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9263_3bf4_9d92_db8c, - 0x5b42_7e02_12d6_fcc3, - 0xd20c_2b5b_3c99_9c68, - 0x34a7_46a8_736d_3635, - ]), - pallas::Base::from_raw([ - 0x484c_9af1_9fc0_7320, - 0x2362_4c04_4eb0_ddc2, - 0x27e8_3514_854d_3b73, - 0x3064_16e8_7ca7_c73b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x32d4_110d_cc45_356b, - 0x48f4_7f5e_fc03_07ae, - 0x7853_0e2b_f3ff_9683, - 0x36d6_91ab_da05_2e5f, - ]), - pallas::Base::from_raw([ - 0xbedb_da77_5302_ff2e, - 0x4a4c_5917_f279_7024, - 0x0a89_7f1c_02e3_d7f5, - 0x01ac_b0f3_614f_a0e4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4ed3_24c0_f046_d8ff, - 0xd81f_1aca_41bc_54b4, - 0x633d_70fd_3193_5850, - 0x2f15_eb03_9398_a90e, - ]), - pallas::Base::from_raw([ - 0xe7be_4499_5af7_37c9, - 0x073c_911b_0333_2ce7, - 0x6ea6_25ed_f5ff_2dda, - 0x0290_63f6_092d_d3df, - ]), - ), - ( - pallas::Base::from_raw([ - 0x15f2_260b_7092_c6c1, - 0x00fd_36e3_678b_2424, - 0x1463_36d5_403d_3290, - 0x26cc_d620_a8dd_a6be, - ]), - pallas::Base::from_raw([ - 0x24d6_05f8_d93c_5bf6, - 0xbe50_1490_75ca_0894, - 0x70ea_d543_4183_1118, - 0x197e_4293_be61_e514, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9b50_3271_5c73_4456, - 0x2aff_79cf_b329_881f, - 0x20ad_27f7_8677_2305, - 0x1fb2_df9c_0084_6254, - ]), - pallas::Base::from_raw([ - 0xd726_501c_633c_d28f, - 0xee75_e9bd_87c7_1d7e, - 0xe5a0_ffd1_3d7a_a3dc, - 0x3501_2a18_8aab_9aed, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa5e3_3bb7_1725_a038, - 0x1a6f_44fa_d126_caec, - 0xc682_0c7b_8b6b_3c11, - 0x1e69_1a87_f24b_4f92, - ]), - pallas::Base::from_raw([ - 0xef4b_cf4f_cd8d_ce42, - 0x9ed4_61f9_5a17_0c8a, - 0x885b_451a_cc3e_7b33, - 0x17e0_4dc9_ffb0_95b4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe134_a4de_1af0_e032, - 0x6055_abca_fd65_aa29, - 0x8109_bd0f_7563_29f6, - 0x3d92_2e0c_6fcd_9ba6, - ]), - pallas::Base::from_raw([ - 0xa51d_b5ff_c901_49ed, - 0x8886_223c_be3a_44da, - 0x9cf3_0d83_8bc7_63f1, - 0x23d6_dc61_5576_d09a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x79e2_836e_2b2a_990c, - 0x982d_0f03_434f_7eb9, - 0x8bd2_b47f_e76c_d5ab, - 0x1560_a3d5_02ce_9002, - ]), - pallas::Base::from_raw([ - 0x38ca_701d_79f6_f538, - 0x0e6a_15a2_265a_5ca7, - 0x6941_bbbd_ce8a_3cdb, - 0x22ed_bcbd_725d_71c2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xeb62_42b4_9b2b_17cc, - 0xdc45_c0bf_cfb3_b708, - 0x1ae9_71ab_fd1a_3f3e, - 0x3850_926a_6116_f9d5, - ]), - pallas::Base::from_raw([ - 0xdb46_22f9_99d5_1a3a, - 0xddcd_2618_7398_1ef3, - 0x3bb5_8508_b3d1_3894, - 0x2001_6ee8_a7ee_6a67, - ]), - ), - ( - pallas::Base::from_raw([ - 0x40e7_fdbf_ba4d_a620, - 0xf056_b930_22e3_f9ce, - 0x02b8_ee49_e734_7325, - 0x1d6f_f561_e1bc_8de3, - ]), - pallas::Base::from_raw([ - 0xb84e_027a_8189_369d, - 0x22f2_75da_0766_031d, - 0x4fe5_1687_c170_f2ec, - 0x3b2a_c069_39e1_17d1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6207_1eeb_79ef_b20c, - 0x0e39_0101_9c6f_6b1a, - 0xad9a_b2d4_0863_083d, - 0x24bb_0da6_d98e_430c, - ]), - pallas::Base::from_raw([ - 0xdc8e_7552_5328_2784, - 0x97f0_d36b_389a_5e23, - 0xdf59_27ec_4ddf_9bb4, - 0x205f_0b78_f827_4d40, - ]), - ), - ( - pallas::Base::from_raw([ - 0x01cd_96f6_680d_43ce, - 0xead1_e981_b589_56ef, - 0x7c6c_198f_61d3_59b6, - 0x2f8e_652c_a28e_caab, - ]), - pallas::Base::from_raw([ - 0xf893_e5c8_f34a_0ff0, - 0xc70a_cb32_4520_0e27, - 0xf8c6_36ea_ae29_6dc6, - 0x2328_82c1_1d67_4489, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd48e_2c48_68be_2a7f, - 0xfd76_3124_e97c_3785, - 0x2494_17a0_2862_5a76, - 0x1adb_8e39_5814_6bb6, - ]), - pallas::Base::from_raw([ - 0xc5b2_a933_33d8_2271, - 0xc234_101f_038d_cceb, - 0x14f3_b690_9f60_efab, - 0x27ba_de97_ba05_a771, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3781_a814_a454_5341, - 0xa839_4f11_8db0_db87, - 0x5f89_9340_4408_04e2, - 0x32c2_7af2_a581_5018, - ]), - pallas::Base::from_raw([ - 0x5072_470a_53d8_4521, - 0xf3ca_f426_f878_4d19, - 0x59c7_fc07_0d03_a314, - 0x05c9_4781_d82a_2a15, - ]), - ), - ( - pallas::Base::from_raw([ - 0x80d1_8205_7021_0e5c, - 0xc3c1_9d74_bb05_c3fd, - 0xb4d7_0972_795d_dc32, - 0x1703_d858_90b0_1ff2, - ]), - pallas::Base::from_raw([ - 0x48a1_ba30_d95b_8f1c, - 0xd8f0_0c72_cf1d_2306, - 0x13ac_ce4c_3128_9a52, - 0x3e18_5f4b_f046_df12, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6fe5_75df_15be_5ace, - 0x2c1f_ad80_7746_0b25, - 0x1fb9_8d91_95ff_e580, - 0x25d2_f86b_25f6_0374, - ]), - pallas::Base::from_raw([ - 0xe56d_dd9b_adaa_a04d, - 0x443a_5452_103d_3d0c, - 0x268f_e354_2b01_c30f, - 0x360a_d0af_c036_b6ec, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd5be_3219_7358_df23, - 0x36cd_6c6c_65c0_9b4d, - 0x2886_ca9d_7d3a_f212, - 0x0ad0_c100_2c7f_f83f, - ]), - pallas::Base::from_raw([ - 0x965c_3680_c268_ea30, - 0x90c2_1c88_c78f_7abd, - 0xadbd_7dfd_d32e_b481, - 0x3e32_3f87_fe7e_9cc8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa927_c4f7_bcbc_65c9, - 0xb16b_54b4_356c_da95, - 0x467d_21ce_c0a1_946a, - 0x3a94_7a7a_8ba8_fcf3, - ]), - pallas::Base::from_raw([ - 0x6ad5_c82f_2e6b_802b, - 0x2134_5b22_9afa_da8c, - 0xfc8f_90bb_fa9c_a1d5, - 0x1760_5d23_3ef4_1cfb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x745b_4736_84f8_b6ff, - 0x2fa7_72e6_7d28_f226, - 0x7f5c_281c_0a58_3d12, - 0x2101_b974_3906_2e3a, - ]), - pallas::Base::from_raw([ - 0xe616_1109_cf4e_3a62, - 0x250e_baad_119d_1842, - 0xfbd4_356a_24bc_0f49, - 0x197f_86a7_7da6_fbe4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5078_ccf0_65b4_a022, - 0xcadd_f679_760c_cec1, - 0x57f9_1931_9550_a0f2, - 0x1999_0351_202f_4b81, - ]), - pallas::Base::from_raw([ - 0xba4c_1093_d57d_9f32, - 0xa80a_f145_0a0f_e90f, - 0x640a_4328_7313_6af7, - 0x1965_465f_d2eb_c138, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4d75_75df_d86d_6ffc, - 0x8c7b_72c0_1499_bab5, - 0x8354_9fe9_4386_40f6, - 0x01a5_1723_6d7d_92c7, - ]), - pallas::Base::from_raw([ - 0x850e_9adf_152d_9d66, - 0xb87b_f256_43ee_366e, - 0x39dd_1caf_086d_f29c, - 0x2b2e_cbfa_0c18_5cfa, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2ff4_d2c3_2c0c_fb5e, - 0x5b66_20fb_1e78_2e48, - 0x164e_048f_a6a6_a139, - 0x1177_de98_7417_d289, - ]), - pallas::Base::from_raw([ - 0x4473_f63c_8b63_96f8, - 0x8813_7018_e47c_7668, - 0x6e54_658a_9365_58d6, - 0x1565_f32e_c124_4d16, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd3f8_b046_ad64_54ca, - 0x0783_8e28_f074_59fb, - 0x2c26_6e07_3920_1035, - 0x1ade_ae43_961e_58b4, - ]), - pallas::Base::from_raw([ - 0xcbac_9225_97cc_0885, - 0x0297_41f2_ecb8_bb41, - 0x52f7_8881_bca8_0ffe, - 0x2626_3bd7_d9ea_3997, - ]), - ), - ( - pallas::Base::from_raw([ - 0x239b_b01c_10ba_15ee, - 0xe0de_2e2f_e883_21d9, - 0x249e_a03d_0db2_8458, - 0x02a1_1010_c364_a8ea, - ]), - pallas::Base::from_raw([ - 0xbd63_66bd_80d3_bf55, - 0xb968_3e0e_df85_70d0, - 0xf00a_642f_04ed_e36b, - 0x37ff_d622_b30b_a504, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc31a_07a7_d2f5_79be, - 0x93e0_4a16_dd86_733b, - 0xbec9_12d1_386f_ac07, - 0x1991_25d9_b76c_e739, - ]), - pallas::Base::from_raw([ - 0x976a_9a8c_0d17_a731, - 0xaf6f_c9c4_4420_7256, - 0x7e5b_0ef8_957e_bf8d, - 0x1afe_401a_7512_9532, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3be4_fa65_6613_b0fa, - 0x3a1f_be61_2e26_94e4, - 0x0091_a6fc_3b5e_dd57, - 0x39fd_5dda_cf6b_ead4, - ]), - pallas::Base::from_raw([ - 0xf61e_8e10_a02d_938d, - 0x303d_5afb_e1b1_5c24, - 0x4f3b_c283_f1c5_9415, - 0x19ea_636b_25ee_6d68, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2f71_d6ff_1108_c379, - 0x3338_649b_c8f8_2416, - 0x29cb_7fba_0970_1000, - 0x3206_be8d_debb_c71c, - ]), - pallas::Base::from_raw([ - 0x4797_990c_97ff_3dc0, - 0xb0f3_243c_bc1b_97bc, - 0x8017_28af_4cf3_8a59, - 0x3f56_eb32_53df_1196, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5b66_3474_6e09_2e1f, - 0xc2e2_87f5_f9ef_0a82, - 0x2442_95dd_210c_66ca, - 0x1d88_ea2d_bc4c_95ae, - ]), - pallas::Base::from_raw([ - 0xe19d_8eb8_f861_3356, - 0x4b53_10d6_7f10_e971, - 0x1ae6_394e_2861_00bf, - 0x0bc9_988e_3ea3_35e3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc3be_adb7_c20e_f2de, - 0xe8ca_eb5c_5b32_9708, - 0x7c0b_c8f5_a91d_631b, - 0x357d_7b0d_bb96_a87f, - ]), - pallas::Base::from_raw([ - 0xad73_6f6d_e6f6_ed85, - 0xa176_6fea_071e_6309, - 0x73ff_1119_546e_4400, - 0x37b5_a0a3_1732_6eb9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x71fb_d7b6_ec81_457b, - 0xa3db_880b_8ebd_e2f8, - 0x6fae_9d5e_77f7_7282, - 0x3922_33fe_aae5_f4d8, - ]), - pallas::Base::from_raw([ - 0x10db_938c_736f_6d80, - 0x343d_e723_56d1_9731, - 0x78b3_c37a_9d5d_a468, - 0x1617_300e_9160_0a2b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x424a_8877_5bac_1aa3, - 0xa8c8_36e8_7e8c_c0e5, - 0xc371_2374_03fe_9264, - 0x26f1_c98a_7a66_a30e, - ]), - pallas::Base::from_raw([ - 0x51a3_b36e_0db2_44d9, - 0x3eea_1d88_887d_e035, - 0x25cb_a902_d51f_f3da, - 0x36e7_0b90_4548_6468, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2728_fdb5_0b61_d1c1, - 0xcb71_a070_6ed1_1521, - 0x0509_29be_1d07_ab6f, - 0x21d2_7b62_2b7e_c84c, - ]), - pallas::Base::from_raw([ - 0xe13a_1cfe_7ee0_cf80, - 0xae30_8c36_a8e1_6416, - 0xed99_fb9e_9ce0_6d84, - 0x34a7_cab8_9803_1842, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfdbb_35ef_3aeb_c28f, - 0x834b_2806_1e44_0e87, - 0xbd65_25e3_6607_150d, - 0x183c_3d98_886a_d987, - ]), - pallas::Base::from_raw([ - 0xefb2_e06e_bf3d_5ba9, - 0x8d2e_e783_371a_b957, - 0xca32_80bd_b0c7_07f8, - 0x1de1_6b88_08f5_68f0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x786d_bdc0_924e_ec5b, - 0xe210_6c1c_189c_4147, - 0x7a4b_a8ab_bb17_0ad5, - 0x27d2_5cca_176a_5ec8, - ]), - pallas::Base::from_raw([ - 0xbccc_549c_6a1a_38e3, - 0xffe7_d383_bcd5_f8c1, - 0x1e45_0633_f24b_c870, - 0x346e_0709_ab95_21c1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5e73_f44f_3cca_5a3e, - 0xa965_c7a3_dd6c_7e35, - 0x3ec6_eee4_1149_89dc, - 0x1083_dfea_d4be_6b07, - ]), - pallas::Base::from_raw([ - 0x294d_4b25_9ddb_cf9c, - 0x7ace_974e_8045_61c6, - 0x507e_843f_4d68_c0cd, - 0x0a2d_8f78_fec0_e925, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf05e_c78b_2d6d_b205, - 0x74ed_d93b_8da6_3fc5, - 0x2d14_ee3d_c962_e1b5, - 0x3d96_e779_a206_75e2, - ]), - pallas::Base::from_raw([ - 0x74b0_20fc_2442_53df, - 0x5e67_731c_8a84_c1e5, - 0x76b9_572f_ee83_9cca, - 0x20ec_4fc7_e584_793d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x618d_3a50_bf2f_9c6c, - 0x2c9e_12ad_d09d_53c9, - 0xc40e_e12a_9971_a79c, - 0x2193_5e49_8cdb_4af2, - ]), - pallas::Base::from_raw([ - 0x526d_a471_4847_0d71, - 0x91b6_ada6_7e06_44fd, - 0x0ed3_0fc8_f6f1_8eb0, - 0x3339_a9d2_a7ce_d503, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5083_6ba9_ebe2_c4d2, - 0x1a97_6e48_cf4e_b89f, - 0x8704_3936_d76c_17ad, - 0x29af_2213_94b4_1751, - ]), - pallas::Base::from_raw([ - 0xf644_cd10_7f09_50c3, - 0x8884_71c3_01ea_94bc, - 0x8937_b2cf_3be6_5258, - 0x2647_20f5_e202_98cb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x95c7_2972_4e5a_6bdd, - 0xcc55_a697_2f1e_750b, - 0xb9b7_90c3_f913_c375, - 0x1ddf_0c2a_bcd6_126c, - ]), - pallas::Base::from_raw([ - 0xb261_7fe7_e51f_68c2, - 0xaf6a_f700_27e2_8cd1, - 0x22e8_5bb5_4a2c_2e77, - 0x04af_6cfe_6abe_1c31, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8ea6_8c4e_c05f_e2f3, - 0x0155_d4ad_ba7b_31ef, - 0xa5ea_74df_1d84_ead9, - 0x2523_0890_0a38_e897, - ]), - pallas::Base::from_raw([ - 0xa64a_883e_1163_2151, - 0xd107_d743_2477_f8ff, - 0x0daf_49f8_7158_36fc, - 0x3e81_0b63_687a_6435, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb8e8_f1d3_9d83_1327, - 0xeefd_129a_2f23_fb16, - 0x5ce7_95e9_417c_4b58, - 0x3579_508c_8c75_a170, - ]), - pallas::Base::from_raw([ - 0xe1b9_574c_e4b2_5e71, - 0xa37c_b44d_e87e_b515, - 0xf492_24b9_9d55_8ab8, - 0x09c4_997f_9e5b_f623, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5010_3905_13ee_f907, - 0x4719_6aaa_d39a_a899, - 0x54de_851b_e709_1a02, - 0x2784_a297_4957_e70e, - ]), - pallas::Base::from_raw([ - 0x24ee_caef_9885_dfab, - 0xd189_3009_5f27_f678, - 0x1fd3_6af4_15d9_091f, - 0x084b_ec81_b437_8e44, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb19f_74b4_e493_4f13, - 0xe3a0_e81b_f084_e23c, - 0xafb2_ef1f_aea3_231b, - 0x0281_e846_acc0_87ee, - ]), - pallas::Base::from_raw([ - 0xd975_d00f_7393_542f, - 0xf8ae_f91e_ec9e_59d0, - 0xd285_8c11_b9c5_280c, - 0x3b00_5d52_5add_f883, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7b66_98ea_e221_f3ec, - 0xaa52_8c99_81e3_ef9d, - 0x8594_5e1a_bb14_af22, - 0x005a_5676_d642_01e0, - ]), - pallas::Base::from_raw([ - 0xf403_21aa_0a31_021b, - 0x4b9d_4172_43e9_01ce, - 0xdcef_30a1_fffd_6fe4, - 0x115c_5d90_17e7_5c6b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb50b_a31a_29ee_735f, - 0xe087_4244_55be_9f05, - 0x4b3d_5356_7f34_bb41, - 0x3592_dfa2_ef73_8fd5, - ]), - pallas::Base::from_raw([ - 0x5eea_a2b4_5eaa_ac7f, - 0xba64_a158_5df4_da51, - 0x64f2_1e18_e2a1_a18b, - 0x2744_472c_60b3_f4f4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1ab7_7d4c_5a3a_d076, - 0xecef_342e_138f_55a9, - 0xe581_d4cf_1cbd_f93b, - 0x0ea1_f359_9f7d_3d5c, - ]), - pallas::Base::from_raw([ - 0xfc25_aea5_9fe3_c15f, - 0xc8eb_d71a_f44f_64e0, - 0xaa6b_2e54_38b5_a5ed, - 0x1cd7_d950_1f7e_fb20, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb92c_cc75_d2f6_7ef9, - 0x7c8c_7050_bb4b_c76c, - 0xae06_dd71_3e7c_b705, - 0x12e7_b66e_0a99_9a6f, - ]), - pallas::Base::from_raw([ - 0xce73_174c_46de_1a90, - 0xf233_8c5c_dce6_3624, - 0x7311_d0f1_6107_caba, - 0x07c5_3cd8_2f6e_3bc1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x679f_68cb_0663_880c, - 0x22eb_3ab9_b8f2_c733, - 0x8c9a_cbf2_ee17_7ad5, - 0x0215_4cc2_96b2_c905, - ]), - pallas::Base::from_raw([ - 0xf9f8_7298_bb53_de4c, - 0xdf36_8c20_1ec4_1690, - 0x4964_d682_c5ab_2e0e, - 0x1c40_fd23_1fb7_cd69, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2119_8bfc_8956_b75d, - 0x991d_620b_35a4_b565, - 0x71ea_c445_814e_d86d, - 0x28c7_9db6_4739_3f32, - ]), - pallas::Base::from_raw([ - 0x14ce_2060_ae17_f113, - 0xbe45_fdc5_1246_fc50, - 0x8e1c_4319_10ac_be73, - 0x1312_53c6_1783_912e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x026d_767e_1005_dd37, - 0x0759_23a2_1a64_428a, - 0xeeae_4507_b79d_6a0e, - 0x37d5_760d_8173_256b, - ]), - pallas::Base::from_raw([ - 0x5214_d99e_936f_56c0, - 0x26a0_b50e_6731_2f58, - 0x3dfa_7029_6ec1_d238, - 0x170c_0df2_5f28_1a90, - ]), - ), - ( - pallas::Base::from_raw([ - 0x397a_3bcb_ba4d_bd68, - 0xf577_2816_06d1_1af5, - 0x0814_30b5_220c_1e6e, - 0x04ee_cac4_45e3_73c9, - ]), - pallas::Base::from_raw([ - 0x3de6_619d_1a4f_65d1, - 0x680e_a92b_eb54_6b7a, - 0x01d4_31ba_19fc_51bf, - 0x070c_35d1_13a7_0730, - ]), - ), - ( - pallas::Base::from_raw([ - 0x327a_43da_e34b_c50b, - 0x9227_b80c_f9ef_6317, - 0x207b_c331_727a_65f5, - 0x2f5b_368e_9519_0487, - ]), - pallas::Base::from_raw([ - 0x59da_f9c7_044b_8bc1, - 0x1ab3_944a_4c78_5084, - 0xb716_6a13_ed9f_a130, - 0x2165_91e0_c300_e0b9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5fa9_1288_f21f_b95f, - 0xbbd2_13a8_837b_4744, - 0x0a4a_3270_6938_5d8c, - 0x2db9_f193_d5c5_c9c1, - ]), - pallas::Base::from_raw([ - 0x7bbd_9898_1a1a_9bff, - 0x4ad2_4d15_ef54_060e, - 0x8824_c7a3_915e_035e, - 0x04ea_a03b_8152_e316, - ]), - ), - ( - pallas::Base::from_raw([ - 0x718e_5117_e211_d00c, - 0x6820_04a7_e806_2c61, - 0xe14d_1252_02ee_8806, - 0x35d6_bbce_17ad_d8be, - ]), - pallas::Base::from_raw([ - 0x6d50_9095_573e_853e, - 0x9be9_bb45_bd5d_ff54, - 0xd142_d615_c2b2_e50a, - 0x0d21_45dc_b049_831c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8fe4_32aa_3577_54fb, - 0x4766_8513_94d3_898b, - 0x776f_85d0_c89d_75c4, - 0x1144_091e_1eb0_8134, - ]), - pallas::Base::from_raw([ - 0x398f_9036_dcb4_9364, - 0xaaa7_1f19_dd46_1c3e, - 0xda24_0bf3_7b5d_659e, - 0x1c09_8238_7bf2_3870, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6570_c993_e75f_d9fd, - 0x5595_d3ee_e187_37f9, - 0x0629_32a7_cec7_4b58, - 0x0202_816c_bc84_b4fa, - ]), - pallas::Base::from_raw([ - 0x1df0_9e9c_5fb9_da74, - 0xb847_f271_42f4_50ee, - 0xf499_343b_da75_dca6, - 0x1781_323b_7425_6726, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5aff_0d37_7f88_51d2, - 0x7353_2959_e87d_bfb3, - 0x634c_476c_fbb7_1c96, - 0x11df_8818_cefd_7683, - ]), - pallas::Base::from_raw([ - 0x35ac_fac4_4577_543d, - 0x5c8f_db44_1658_61fc, - 0x4b19_0f39_cf3c_fb30, - 0x27dc_c868_42a3_d6b8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x706f_36b5_bce1_6334, - 0xed63_bc8e_d67e_8f0d, - 0x5389_8211_d9a1_148b, - 0x084e_1a66_ed1d_9f9a, - ]), - pallas::Base::from_raw([ - 0xa9e0_e924_9383_6ee5, - 0x54c4_d664_8f95_0861, - 0xe2de_beff_8d23_4306, - 0x2038_1989_0b48_2b10, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3afe_f81c_330c_8ad7, - 0x8f31_b38b_3cb7_7f46, - 0x0be8_a9e3_b4bc_f237, - 0x09ce_729b_7917_ae58, - ]), - pallas::Base::from_raw([ - 0xd199_ef86_4732_8de0, - 0x7b03_6744_a3f5_8144, - 0xa545_b8ef_580a_7994, - 0x1074_1c11_9769_07ab, - ]), - ), - ( - pallas::Base::from_raw([ - 0xcc3d_d69a_86da_b9af, - 0xd4e7_5a09_d52b_0b3e, - 0xe8ad_091d_8b10_7f75, - 0x2b43_cc2e_f8d8_f01e, - ]), - pallas::Base::from_raw([ - 0xbd14_0c51_b03d_0f63, - 0x1006_923c_4bcf_285d, - 0x7221_7a99_120c_7911, - 0x012f_2b79_8f53_056f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0beb_949f_a313_486c, - 0x0d5c_e4d6_059d_abf8, - 0x4991_4b41_76f5_2b16, - 0x1a14_5dc7_97b5_eb4c, - ]), - pallas::Base::from_raw([ - 0x9b0a_fb2b_b5fb_dc02, - 0xb72e_d001_8b32_e67e, - 0x8dc1_f4ac_e7f6_40a1, - 0x0a03_99e6_e2c1_35e8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x24e5_3cfc_0a85_3bd6, - 0xc691_a440_5284_538a, - 0x285f_8587_a2ca_3f67, - 0x0049_29ba_589a_b1ac, - ]), - pallas::Base::from_raw([ - 0x47d0_0f51_b59e_11b5, - 0x034c_e6c5_4f24_d018, - 0xcdfa_fdf5_9352_2277, - 0x1740_01a4_cd80_e459, - ]), - ), - ( - pallas::Base::from_raw([ - 0x05f2_fba6_88e4_64cd, - 0xcc07_4f11_8393_de4e, - 0x8cd3_84d1_2d3a_f616, - 0x082e_c561_65bd_c5db, - ]), - pallas::Base::from_raw([ - 0x0ff4_d463_cdf6_1438, - 0xb9d4_8513_1297_820b, - 0x577a_ab49_6011_7b6f, - 0x189f_caa5_6f47_de49, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6a66_f234_459d_9c05, - 0x52b3_b4e7_046a_0ca2, - 0x5f0c_f5c7_ac0b_8673, - 0x2d4d_378b_8ab7_0f4d, - ]), - pallas::Base::from_raw([ - 0x25e8_c3f3_463b_7de3, - 0x1db7_6493_b323_dd0c, - 0x96a6_cbc7_69f8_7c7f, - 0x0433_09e4_d57b_65e1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xcf05_4d04_c520_e0a0, - 0xd540_edc7_1ca1_3af1, - 0x4993_044b_77dd_0400, - 0x1b0e_a9cd_b77e_ff99, - ]), - pallas::Base::from_raw([ - 0x6928_0ea8_321c_cd3b, - 0x72ab_b895_a1a8_f03d, - 0xf3d3_938f_2c87_7734, - 0x1270_1769_ae73_6bcf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3e52_a2f0_ad5f_a12d, - 0x4418_5ba6_38bc_b064, - 0xef8b_d3ef_5bf1_6622, - 0x3ef5_5ec2_16b2_28bf, - ]), - pallas::Base::from_raw([ - 0xb82b_cb14_f2f4_9c05, - 0x1ecb_aee5_356e_0958, - 0xd850_681c_85cd_d83a, - 0x1328_7a30_a3cd_c18a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x76c9_1531_675b_e4d2, - 0xbff3_efc0_f5e7_a3d5, - 0xbf16_1feb_c704_2e5a, - 0x0033_a85c_5e3e_212d, - ]), - pallas::Base::from_raw([ - 0xb3fe_295f_735b_1607, - 0x4c07_169f_2f85_8811, - 0x53af_cd3d_e314_e24b, - 0x33dd_2f1a_9d46_44fc, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8e41_0696_97e7_8171, - 0x26ff_1208_32bf_c795, - 0x0bd7_0aa4_1196_808a, - 0x3ae0_f344_40d2_99f5, - ]), - pallas::Base::from_raw([ - 0x2474_b70b_2dad_669a, - 0x4603_66a7_e898_713f, - 0xb369_5b24_0bd9_aeba, - 0x3c74_bb6d_465e_e2ea, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6e89_42a3_91dd_c2ea, - 0xc38a_28e1_fcf3_fba9, - 0xeb31_2651_5a79_f178, - 0x341f_5e3d_2d3a_415b, - ]), - pallas::Base::from_raw([ - 0x7449_ce64_375e_4ca8, - 0x0602_745a_0fb3_6d33, - 0x2958_f891_d370_9055, - 0x09b2_2212_2dc8_e043, - ]), - ), - ( - pallas::Base::from_raw([ - 0x06b4_c662_7f86_1a17, - 0x6892_8a55_09f7_1a30, - 0x0f16_7e0c_216f_c514, - 0x3d3a_af95_d02a_5c26, - ]), - pallas::Base::from_raw([ - 0xf1df_9dff_4331_9bc6, - 0x3728_ab5b_c9a6_f755, - 0x8c73_0235_2ed7_3f95, - 0x3f65_6e0c_c790_2ba0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9f45_5904_d062_3f0a, - 0x7823_029e_72a6_7bb6, - 0x99fb_f22c_510a_2be4, - 0x2e85_df2d_4723_8ae7, - ]), - pallas::Base::from_raw([ - 0x327d_317b_e878_66e3, - 0xa45e_75ef_95df_3e94, - 0x7b1a_c76d_c402_0f49, - 0x3a60_fbcd_a37c_815e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x17df_a08e_e2a4_a5c2, - 0x0d37_fdbf_7f39_3cc8, - 0x5f65_0aee_69a3_3aab, - 0x21cc_cd3f_512f_6fef, - ]), - pallas::Base::from_raw([ - 0x5501_f47b_1934_3bbb, - 0xc629_25da_839b_5703, - 0xe869_5dff_4ac7_98db, - 0x2616_31c0_e0e8_b1b3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x11b8_7af9_9e00_27df, - 0xafd7_bf48_d6fc_a4f1, - 0xd540_1aff_42f4_c233, - 0x158d_6245_8d40_37b2, - ]), - pallas::Base::from_raw([ - 0x8b6f_fd47_6243_eb36, - 0x6c6d_2aa6_425d_192e, - 0x9148_af15_de60_624c, - 0x3e87_9938_3886_00a0, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfe07_2c77_e4e1_e7c2, - 0x93d8_3c8c_e662_68de, - 0x619f_5102_29bc_739b, - 0x3a66_5f24_c02b_af59, - ]), - pallas::Base::from_raw([ - 0xc557_f198_58c8_a876, - 0x7731_9895_7381_1af9, - 0x6b7d_918d_995d_93e6, - 0x307f_067d_c98e_9636, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa436_5475_6a68_c675, - 0x88f2_f299_794f_3553, - 0x7f11_45b8_74ae_62c7, - 0x0dee_f81a_0f27_b481, - ]), - pallas::Base::from_raw([ - 0x993e_47cf_7f5e_cf8c, - 0xe810_5d2c_1b5e_0447, - 0xcaad_b923_1a1d_ac82, - 0x147a_8969_4b2b_e230, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4723_e366_ae1e_6184, - 0xee04_327f_d719_ea9b, - 0x24db_be73_e152_f27d, - 0x2100_9976_6171_438d, - ]), - pallas::Base::from_raw([ - 0xefe4_8e4e_9b94_1267, - 0xacb1_8986_fab0_a084, - 0x7b10_5663_ae11_ea5e, - 0x274f_221d_771c_400c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5cb8_1790_8657_3d1e, - 0xdd05_63de_2edd_ddc4, - 0x78ba_e557_b388_ffeb, - 0x1a84_b9f1_4ad0_365d, - ]), - pallas::Base::from_raw([ - 0xd1da_bfb8_e966_236a, - 0x57d3_fa91_cbd6_0cc8, - 0xdc92_8096_0248_333a, - 0x376c_21b4_5247_997f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x13f0_c07a_dc21_f7b1, - 0x2a5c_69e9_05fe_854b, - 0x0573_d14d_1d7d_da4f, - 0x193e_e5da_b674_a49d, - ]), - pallas::Base::from_raw([ - 0x7fa1_74ca_714a_4b90, - 0xfe21_aa2e_52a5_a793, - 0x69dc_b536_0f5b_c791, - 0x1b16_b237_03d7_e26c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xeaf6_6865_27d4_b8e6, - 0x1aa0_aab4_2666_1fcf, - 0x1aa7_9baf_a2a0_5e73, - 0x3589_722c_8ec2_4085, - ]), - pallas::Base::from_raw([ - 0x4142_0491_d747_fb8f, - 0xc20b_63f7_728a_bf57, - 0xf61d_1974_ab2a_d20b, - 0x3a16_a2b3_28cd_a978, - ]), - ), - ( - pallas::Base::from_raw([ - 0x479a_9ac8_e884_e011, - 0x504e_93b0_cd03_ae26, - 0xc711_9e1f_1319_e977, - 0x3793_11e7_db77_15e7, - ]), - pallas::Base::from_raw([ - 0xf05b_ef48_6578_ec58, - 0x05b9_b52f_deca_50dd, - 0x6c92_c4fe_9bf6_95a2, - 0x2ae6_65e4_8ad7_556d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9418_f007_3a11_5039, - 0x84ba_f7e6_293c_aa1d, - 0x4be5_7bb5_6c37_e8e8, - 0x2e01_0c6c_ba9d_2f9e, - ]), - pallas::Base::from_raw([ - 0xb30c_63c5_793a_1373, - 0xc2a7_a868_e4da_a692, - 0x789f_e67b_b71f_b6dd, - 0x2812_c192_3126_8e2a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8a3e_8b6d_d6fb_bcb6, - 0xfab6_9586_3583_cbe2, - 0x3d2e_3c47_a4bf_b5a1, - 0x1715_0e76_b351_e99d, - ]), - pallas::Base::from_raw([ - 0x2ea8_22fa_65a4_7757, - 0x1f2f_e64a_c655_741c, - 0xd1aa_205a_f5ac_9570, - 0x27cf_dd88_0836_c8e9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7d30_5f29_822a_7979, - 0x8082_4fc1_a364_96e2, - 0xf73d_1cf4_c77a_0f4d, - 0x1c9c_be3c_6a19_26be, - ]), - pallas::Base::from_raw([ - 0xaa17_af8c_1c76_1823, - 0x09d0_a290_baf6_e926, - 0xf61c_06f8_b5d6_c22b, - 0x172f_1a6d_fc32_d9cd, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5ad3_8743_b520_2fb9, - 0x083a_2695_50be_40d2, - 0xb911_1803_3f67_cde3, - 0x2846_f462_30cf_b810, - ]), - pallas::Base::from_raw([ - 0xe223_b5e7_e937_c54c, - 0xf2c5_77fd_b08b_3f21, - 0xb6c1_652b_7505_a7d3, - 0x2c8f_a498_2e60_e130, - ]), - ), - ( - pallas::Base::from_raw([ - 0x56bb_e185_4175_95f3, - 0xecc1_0053_9407_c202, - 0x90a5_c415_7630_fd2e, - 0x1f33_8ef2_6410_ce20, - ]), - pallas::Base::from_raw([ - 0x1a3b_5459_1a56_b7d4, - 0x2711_c42b_cfc8_bd25, - 0xb313_42d6_a462_1965, - 0x1e04_5727_6c6a_be28, - ]), - ), - ( - pallas::Base::from_raw([ - 0x33f0_122d_1fc2_e9d6, - 0xbbaf_07e2_6d0d_b5f4, - 0xada4_e1db_90f2_0928, - 0x320d_78d3_7e1f_9b51, - ]), - pallas::Base::from_raw([ - 0x6d4f_fe2f_b80e_79f9, - 0x1697_46f5_0160_9c4d, - 0x9c94_aa69_371f_e117, - 0x08ff_a47d_8297_7661, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0eed_415f_7d55_1715, - 0xf420_3b98_aa11_457b, - 0x9053_f3d5_4476_0afb, - 0x02c2_03ba_dea2_76a1, - ]), - pallas::Base::from_raw([ - 0x55d7_024a_e842_a5af, - 0xb58c_03ba_9deb_cd2f, - 0x0c6b_c8b6_ceaa_42b5, - 0x3b4e_7fab_6e35_5c3e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xea9d_81f8_6a0d_dbe9, - 0xce0f_2809_3257_e6f1, - 0x0039_3b64_fd52_ff04, - 0x2942_5821_8d23_ef24, - ]), - pallas::Base::from_raw([ - 0xbb7f_710f_9517_dc5b, - 0xb9db_1453_43ab_48ca, - 0x94cd_60e3_1fe8_3451, - 0x2be1_7ce0_f798_be8b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd971_ee8b_071f_3aa2, - 0x6542_046f_2f21_6648, - 0x7011_a0b4_c4c5_2feb, - 0x176a_75e4_305d_c7cb, - ]), - pallas::Base::from_raw([ - 0xb8fe_680b_ce75_ae24, - 0x8549_cbf6_c3d2_7b44, - 0xa8ee_92a7_6a40_c587, - 0x09e6_b0ba_013d_f131, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb80b_9e97_64fd_da65, - 0xb0c0_b411_0bc5_8a2d, - 0xac1b_b1a0_c6e1_5c55, - 0x36a4_4d41_d37a_70e8, - ]), - pallas::Base::from_raw([ - 0x6a77_efb2_81aa_e72f, - 0xc578_8686_9b58_faa7, - 0xab74_33bd_7e33_68dc, - 0x1792_ad2e_7f54_a000, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8792_f6ef_0395_a9a7, - 0xd375_7f3d_66c2_7229, - 0x6949_e876_d5c7_9010, - 0x176c_f116_0c7f_8ba7, - ]), - pallas::Base::from_raw([ - 0xf0f5_d8f0_a98d_c2bf, - 0x4118_e09e_ac6c_d9e9, - 0x4ed1_51e4_5f97_f657, - 0x13e7_3756_26b8_54e4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbccd_3257_f3c2_06d0, - 0x3139_8eae_f991_a342, - 0x5a2d_4414_2fa3_5a6c, - 0x3cef_bcc7_13f6_3152, - ]), - pallas::Base::from_raw([ - 0xc806_3b97_017e_00ab, - 0x5e20_fdd5_44b5_acc3, - 0x6cce_c0f6_ef8f_18cd, - 0x14ee_4b77_ec6a_bfeb, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc096_2238_58db_eab3, - 0x5c0e_61b0_db10_ef29, - 0x6c9a_f1ed_8acb_1da4, - 0x3f76_fe73_c425_d939, - ]), - pallas::Base::from_raw([ - 0xdad4_82e8_b280_556f, - 0xc3f4_06de_7fdc_c54e, - 0x37ca_88b8_1d36_54b9, - 0x0261_f776_7244_a4d3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7e1c_ca9a_a12a_8efe, - 0x948b_62a8_c522_ec9b, - 0x9dbb_049b_218c_3df8, - 0x1efd_3a6c_d255_af78, - ]), - pallas::Base::from_raw([ - 0xa4b5_0f75_4d65_0a1f, - 0x25b7_6c86_a75e_2c13, - 0xfd6c_6887_ef4d_1d53, - 0x0a59_0bd3_71bc_51f0, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdcee_cea8_b8d0_d650, - 0x4f2d_8b8d_6a29_f2d4, - 0x43d0_528f_eaf9_11eb, - 0x2404_4c52_546c_2b52, - ]), - pallas::Base::from_raw([ - 0x96c3_facd_1cf0_d9f6, - 0xca63_6712_9f50_6ad8, - 0x2f85_d005_fa5f_9b5b, - 0x069e_153f_9896_c130, - ]), - ), - ( - pallas::Base::from_raw([ - 0x686e_8212_4c61_d957, - 0xc7aa_9bde_a486_649e, - 0xd3c2_91e0_d4a3_7a8d, - 0x0107_e2e3_2c5f_28f3, - ]), - pallas::Base::from_raw([ - 0xab0b_45df_c3d7_591b, - 0xf7b5_854a_710b_f63d, - 0x544d_c8f1_2e0c_26f3, - 0x2d9b_95a7_30cc_ea85, - ]), - ), - ( - pallas::Base::from_raw([ - 0x513d_33c2_95ce_56f0, - 0xbd2b_2fdd_7fd7_7031, - 0x5d4f_47fe_09e2_e031, - 0x2f94_4842_7b80_54b4, - ]), - pallas::Base::from_raw([ - 0xdf6f_d665_d36a_7467, - 0x5dc9_191f_2fea_6b07, - 0xeca2_ef63_7140_6422, - 0x0171_50c0_96da_f72c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x367a_1d4f_87ce_2858, - 0x9d54_5c07_8137_cd19, - 0xdf1a_2072_738f_3bfd, - 0x114e_4120_52f0_25d4, - ]), - pallas::Base::from_raw([ - 0x18fd_28df_bf66_d5ea, - 0x8bbd_77f0_f949_9a75, - 0x6362_4f99_f3e8_453b, - 0x2780_edfe_8a38_8449, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7402_3082_0ea9_5ad4, - 0x63b2_7be5_3550_2ffd, - 0x91dc_cb3e_fbe2_60b6, - 0x25e2_bfb1_0f32_3477, - ]), - pallas::Base::from_raw([ - 0xadc0_3a71_39b4_094f, - 0xedf8_c60f_b4d1_c2bb, - 0x6911_0947_b702_9fcb, - 0x01f4_2fe0_a850_8065, - ]), - ), - ( - pallas::Base::from_raw([ - 0xff2d_cd62_e596_b4d0, - 0xc7d3_1ad4_5af5_0fc8, - 0xa0bf_73fa_b1a6_63fd, - 0x01c5_4695_7e3e_a005, - ]), - pallas::Base::from_raw([ - 0xefeb_aacf_938f_6779, - 0x6986_3f6e_07de_7291, - 0xc06e_8e67_ade6_e796, - 0x164b_abe7_7966_9ae9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1c33_6e51_b527_8fe0, - 0x830f_0267_88b0_060b, - 0xe589_fe8a_6136_cdf4, - 0x04e2_bb36_ec30_315b, - ]), - pallas::Base::from_raw([ - 0xcde6_5cb5_9334_5bfb, - 0x10a1_fb83_4287_f5f4, - 0x37c7_a20c_4619_28c1, - 0x2adc_5a85_4126_6b62, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3932_ba35_42e2_61ba, - 0x3a1e_399e_82de_4dcd, - 0x3a5f_6dff_03ac_3c73, - 0x2cbd_15f4_53d9_16a9, - ]), - pallas::Base::from_raw([ - 0x2425_a35f_a98d_8937, - 0x0a66_a2d3_5d9f_588c, - 0xf832_8c5a_3951_852b, - 0x0848_6f66_b4a2_dd55, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa4c3_8380_3a4d_9564, - 0x109a_bd0c_31eb_54f2, - 0xa83d_57b4_b012_a211, - 0x3949_c80c_4cfd_3f85, - ]), - pallas::Base::from_raw([ - 0xfdcd_3f0d_1ef1_9e40, - 0x47f8_5477_4692_b481, - 0x60fc_0e1d_252f_8607, - 0x1547_2a08_45c3_dc19, - ]), - ), - ( - pallas::Base::from_raw([ - 0x042e_596d_48e5_7baf, - 0xd9d7_3041_cb15_f628, - 0x65ec_a378_4e88_0916, - 0x059f_7f0d_27e9_01da, - ]), - pallas::Base::from_raw([ - 0xd37d_77d4_4cf8_b443, - 0xbfa1_72a6_7d41_76ec, - 0xd8c8_b761_2524_7b4e, - 0x079b_6488_5c2d_24f5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd29f_0703_a4b5_6dbe, - 0x75e2_6aa8_956b_46fc, - 0x84a4_49e7_02e2_2806, - 0x38bb_f1d6_ceac_121c, - ]), - pallas::Base::from_raw([ - 0xc772_1a73_3066_b6d1, - 0x1737_55f3_b53b_ec06, - 0x3c2a_bd62_3e1e_2c21, - 0x088d_d43b_6366_0116, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa116_6f77_055a_8bb6, - 0x6385_2d8c_5889_8da4, - 0x34b4_f4cd_754b_7717, - 0x1526_aa2d_f3e7_515f, - ]), - pallas::Base::from_raw([ - 0x4085_c51a_2657_e4b8, - 0x9679_5ea4_4624_8645, - 0xc804_03a1_e3d6_3998, - 0x199c_c2b0_2132_4b08, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa52a_db5d_d168_77c2, - 0x6b03_f922_0b52_af2e, - 0x7fc8_01e8_b4ef_22bd, - 0x12e5_67c2_ec81_2f1d, - ]), - pallas::Base::from_raw([ - 0x0309_4014_a4e8_c20b, - 0xe7bf_0cd6_a200_a8cc, - 0xc608_65fe_fb5b_94ea, - 0x0993_1445_3f68_41ac, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbfd7_fd57_8b6f_75d8, - 0xf07e_f86e_d33d_296a, - 0x5054_c978_d48e_ee12, - 0x0b3d_76cb_4f6f_c43a, - ]), - pallas::Base::from_raw([ - 0xbef7_625a_4eed_90eb, - 0x1f8d_bade_22fe_73f7, - 0xc960_ab94_3ae5_1bfe, - 0x0858_b2d8_865c_973e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe2e4_3c37_843a_04dd, - 0x28e9_8a1e_6966_e7c0, - 0x6ac4_304f_d629_f5a1, - 0x2dfc_f1e1_ec0c_32fb, - ]), - pallas::Base::from_raw([ - 0xbd67_15f8_99d0_7f6e, - 0xcb85_5a99_89cc_47ff, - 0xdd2d_2426_6872_35c4, - 0x1968_0ec6_a3a3_fcb8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa5ab_b96e_1f94_1076, - 0x51b5_b451_b97a_0268, - 0xd7e0_dc4f_58ed_e375, - 0x2bee_18a5_f76d_7e63, - ]), - pallas::Base::from_raw([ - 0xed7d_80be_441d_d7b4, - 0xa4c2_d30a_3c19_cf3b, - 0xac4f_739b_2e1f_91ed, - 0x3562_48da_e389_3d81, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7c79_fc8c_4dcb_a1c0, - 0x8162_1c35_b958_c1a1, - 0x0a41_6e19_3265_f04d, - 0x009e_4848_45e1_7f41, - ]), - pallas::Base::from_raw([ - 0x712d_9394_ab35_ebd1, - 0x6312_e11e_d8e1_49fb, - 0x84af_9933_77e5_1ade, - 0x3f42_3c6c_cd36_1dc9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf371_6e56_7f23_b1e1, - 0x538f_3c4d_6a0d_4994, - 0xaf2a_6e2a_b089_32ec, - 0x2f3e_49c7_37a2_98af, - ]), - pallas::Base::from_raw([ - 0xc5eb_afba_dcc3_18cc, - 0x64f2_6b4c_6339_fd3d, - 0x5ef0_9554_fa27_b6cc, - 0x21dd_5ec1_51e4_e135, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc382_c4ea_f9e5_4b3c, - 0x47ea_f27a_b13e_c143, - 0x2a6c_3775_caaf_400f, - 0x08d1_cba6_65ee_26df, - ]), - pallas::Base::from_raw([ - 0xfdf2_f10d_f382_cd25, - 0x812b_4d72_4045_d2f3, - 0xc1c3_32e2_6422_084b, - 0x26a4_9ea4_f176_8cd3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe132_91ea_94e5_9353, - 0x7d69_5680_fc7b_82e5, - 0xada6_bc9f_fcd7_fe02, - 0x2ad4_e94f_ac41_1335, - ]), - pallas::Base::from_raw([ - 0xf166_8557_d845_98ef, - 0xb6f8_78df_9c3a_5c6a, - 0x0993_e2b9_0073_8ccf, - 0x09b0_6867_4885_ae31, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4161_dea7_2c51_a176, - 0x147b_e228_82c1_8e17, - 0xf47c_b827_d4af_8bcd, - 0x30a0_5ec4_90a9_aa33, - ]), - pallas::Base::from_raw([ - 0x3209_f6db_3ea8_a841, - 0x1d9c_06c6_ea2d_6905, - 0x6afe_34c8_ac39_628f, - 0x35f8_03ed_ac2f_acde, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbe8d_dfdb_83eb_b5ed, - 0x185a_8a55_57ab_07c3, - 0x109c_99b1_64d5_ebb0, - 0x0243_40be_c0e7_c4f7, - ]), - pallas::Base::from_raw([ - 0x6b51_37b6_6b10_0439, - 0x6f2e_00fe_1a1d_1ecd, - 0xe2af_ff62_7ab4_5f97, - 0x31d1_3ebc_0bad_4368, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe52c_00c2_77e0_805b, - 0x289a_6cfc_00e4_613e, - 0xba6d_64e6_b80e_af43, - 0x028d_bb3a_a2eb_10e1, - ]), - pallas::Base::from_raw([ - 0xb5e0_5d84_b2c2_af71, - 0x8ca8_19c8_ed2d_d4b4, - 0xbf23_1285_894e_181d, - 0x13dd_55ec_af42_2820, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7cd5_9e64_f479_5578, - 0xb2e4_8301_4dad_1d12, - 0x69bc_3333_f3ae_7a7b, - 0x1d8b_bee3_8e56_ce73, - ]), - pallas::Base::from_raw([ - 0x62ed_e032_93f3_6d8e, - 0xe0ff_b670_42fd_4d90, - 0x28e5_b97c_3c9d_1811, - 0x1a6e_4ed7_56c2_b230, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0828_358e_7ca1_8645, - 0x4e14_04d0_c831_fc41, - 0xa2d9_42ef_1ded_82b9, - 0x2fb8_9978_33e6_41c9, - ]), - pallas::Base::from_raw([ - 0x1fa1_883b_1222_e351, - 0x8a92_e672_a65c_2998, - 0x2c95_70ae_0ce3_66ac, - 0x2182_c430_2f94_8f79, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7137_1420_909c_4455, - 0x79a8_72fa_e5ff_4895, - 0x64c5_8a11_259d_2d60, - 0x1b4a_243f_2c40_9d0b, - ]), - pallas::Base::from_raw([ - 0x24b7_097b_3e5c_77cf, - 0x103c_bbe4_8a2c_d3c1, - 0xfb53_ff35_bd2b_0ac1, - 0x3520_075c_da2f_93c3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf70f_d61e_7311_192b, - 0x663f_6658_1f78_66bb, - 0xb223_dcf3_6099_76c2, - 0x22c3_ced3_c628_b166, - ]), - pallas::Base::from_raw([ - 0xc390_e15b_4656_71ea, - 0x839c_7a74_12c7_d85b, - 0x9eab_c165_478d_f2c2, - 0x0426_245e_279f_b951, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf32e_587b_08ac_a16a, - 0xef0f_0954_a0d1_18d6, - 0x663a_0d0e_0f93_711b, - 0x3ba9_d989_09c2_1586, - ]), - pallas::Base::from_raw([ - 0x67b0_fe69_78fa_f39b, - 0x4365_7c97_5d17_8817, - 0x3634_3954_9a26_d391, - 0x2912_61a5_3c05_d61d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb213_f8dc_16d9_4935, - 0x6c08_5bb9_8b3f_b3d8, - 0x3c8e_7712_a323_61cb, - 0x1186_5328_9691_8dbf, - ]), - pallas::Base::from_raw([ - 0xdd0f_6a6f_c395_0461, - 0x402e_cdec_f30a_8b9a, - 0x63c0_5442_4a3d_9c82, - 0x1e3b_87b0_e601_4734, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd2bf_fe22_3f25_f8aa, - 0x3d13_dad2_88e3_899a, - 0xe40c_042b_1047_1796, - 0x20ef_355f_b2b9_b7a4, - ]), - pallas::Base::from_raw([ - 0x2584_fc90_05a4_4eb7, - 0xc73d_0faa_e860_285e, - 0xa3a9_e4b5_9dce_93f6, - 0x1002_4764_5a67_73fa, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb44d_d4ef_f05f_ee9d, - 0xd311_e35e_57c3_af04, - 0x6afa_e748_df35_ace0, - 0x2852_47bf_ed5c_af05, - ]), - pallas::Base::from_raw([ - 0x67e1_bbc4_0409_5959, - 0x1064_023c_f1ce_c606, - 0x12ea_7b93_7755_8d2c, - 0x14e6_9d5a_a6ca_0da4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3dad_64a1_41cc_bf58, - 0xcd45_cc95_e1bb_6d96, - 0x4f71_1071_c168_9f44, - 0x0f42_27ce_35ad_602c, - ]), - pallas::Base::from_raw([ - 0x54ef_0524_e72a_f65c, - 0x7baf_4d83_432e_dfbc, - 0x3479_4bfb_b7eb_9917, - 0x1bad_5ff2_bc75_3f5e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x17df_6323_6eb4_e4a0, - 0xec9a_1e58_c280_b973, - 0x5a8d_46ad_12ab_e217, - 0x0222_2ecc_4b1f_79a4, - ]), - pallas::Base::from_raw([ - 0x8dc6_c26b_627e_cfc3, - 0xcad4_3492_8c57_feac, - 0x4c7e_c57f_f201_761e, - 0x1a7a_19c9_ebec_a09f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfbdd_d33a_def4_3e8f, - 0xd650_1c5d_0b0f_e30a, - 0x6fd5_fd34_c4c8_ef1b, - 0x337e_4fbe_c8b3_3a4e, - ]), - pallas::Base::from_raw([ - 0xfe9a_5311_7c98_6fb1, - 0x90fe_d9ee_d112_899c, - 0xa935_19db_c171_8814, - 0x1a32_d859_2e42_f132, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbd1f_570e_d595_ab4c, - 0x2e11_069e_dc17_bceb, - 0x5c63_4ef5_02d2_93e8, - 0x3be4_949d_9d7b_53c5, - ]), - pallas::Base::from_raw([ - 0xf087_456a_6cc0_0eac, - 0xb68e_6724_73b7_edeb, - 0x9548_e552_8391_9a99, - 0x0107_0f1f_04ae_b5d6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x493a_9aea_3262_6e17, - 0x7b8e_4c15_74b2_e969, - 0x8053_61b6_b5f2_ca98, - 0x39d7_c501_1792_79a3, - ]), - pallas::Base::from_raw([ - 0x53d3_5c19_43dc_f2e9, - 0xba13_604f_47bf_3260, - 0x8324_b8e7_4d46_596a, - 0x1882_9bdb_b7d8_45eb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0d27_0a51_f183_e9e8, - 0xd276_a7f9_3066_8f03, - 0xd48d_97b5_9e5d_88e9, - 0x0e8a_ee90_45a1_44e1, - ]), - pallas::Base::from_raw([ - 0x2818_4a9f_3fa0_bb40, - 0x710f_acd0_0450_af64, - 0x900f_4bdf_1974_6e9f, - 0x27a4_2da3_2115_76d4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb689_cf40_37dc_668d, - 0x9377_0a01_142d_c428, - 0x3134_eac4_c878_08fd, - 0x3afc_9061_8065_68ed, - ]), - pallas::Base::from_raw([ - 0x60c7_7d3d_3fad_57b6, - 0x59f4_9ebc_34aa_59b3, - 0x9d63_d009_0c0a_7384, - 0x2559_c358_bc86_61ce, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5c09_5692_145c_79b4, - 0xda8b_bb5f_49bd_b0b4, - 0x4135_2c94_9dbf_9dd7, - 0x0453_dc79_9e74_8178, - ]), - pallas::Base::from_raw([ - 0xda01_9f05_07c7_9539, - 0xe639_45d5_2aef_6d32, - 0x4119_4ec6_4943_39e2, - 0x2ea2_ef55_be81_fd44, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf49f_4fa9_04be_f892, - 0x62dc_978b_3700_3ffb, - 0x6702_e625_4263_44a6, - 0x3b3b_e12c_dc8e_7efc, - ]), - pallas::Base::from_raw([ - 0x10bd_e67f_93e4_1090, - 0x8ccc_a11e_ecb0_991e, - 0x50dd_72f0_eb8a_e400, - 0x3f3c_db56_a787_8aad, - ]), - ), - ( - pallas::Base::from_raw([ - 0xff0a_53a6_55f4_b430, - 0x0fbe_41a2_841c_8e6b, - 0xe44a_6249_5534_24da, - 0x3d16_d183_cfd9_e4f3, - ]), - pallas::Base::from_raw([ - 0xf173_7a47_4a12_010d, - 0x3386_2a20_5ae3_010c, - 0x9475_ac8c_7cc9_6eb2, - 0x2d5e_edba_92e3_787e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xec32_bdcc_3ab6_8bc8, - 0x5ef1_c68d_8205_6ba8, - 0x2a79_c6b1_760f_230a, - 0x0269_c007_4842_ac02, - ]), - pallas::Base::from_raw([ - 0xdea5_6a73_acf7_0dd7, - 0xefae_24fd_d605_d32c, - 0x7644_0179_5a72_8a8f, - 0x29bf_5935_ee3b_cf0d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xafec_fca4_d928_57e0, - 0xa2ef_4a25_2d8d_462a, - 0x3f9c_1cd2_7b1f_8c08, - 0x3f06_e865_ae86_e74e, - ]), - pallas::Base::from_raw([ - 0x2bca_60c6_542a_5cce, - 0x2017_a0ca_ddf9_1f45, - 0x9ee1_6a4f_f103_b9cf, - 0x3795_5bec_4580_dd2a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8691_e4b4_c1cf_edc6, - 0xb4f6_468c_8120_fd13, - 0x05b1_7517_b826_dc89, - 0x0c61_3568_3cef_710c, - ]), - pallas::Base::from_raw([ - 0xb119_025f_6be2_1c59, - 0xe60e_c8d4_cc1a_34da, - 0x61ba_a8f8_bd7a_34ff, - 0x1c27_2a98_a433_d3ba, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc775_8f6e_229b_53c4, - 0x8187_14e3_1fd4_834f, - 0x9b72_1c14_5292_b1f4, - 0x2ad0_635e_fd85_69a0, - ]), - pallas::Base::from_raw([ - 0x359a_b6e7_a119_d83e, - 0x598f_fc63_1f64_1ef0, - 0x444e_4b2b_7792_20fd, - 0x03df_5258_e7c9_9279, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9134_5261_be30_5e2e, - 0xe6d4_a11d_a37a_2874, - 0xba1c_281f_b344_e7ec, - 0x160d_d9d7_58da_88b5, - ]), - pallas::Base::from_raw([ - 0xdade_8f8f_bbfe_566a, - 0x2000_6526_5423_f35f, - 0x0f19_01f2_71a6_22a5, - 0x32a0_503a_fecb_2320, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0683_5997_1217_55ba, - 0x2a57_c9d0_8730_2e1b, - 0x8f07_c57b_3fdc_d076, - 0x0849_b2af_ec11_13b5, - ]), - pallas::Base::from_raw([ - 0x13d6_5361_9c27_882d, - 0x84d9_028a_a60f_5d93, - 0xf1ee_437b_33fa_62f2, - 0x0c6f_0de4_3fdb_971d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6e23_4404_9793_ef67, - 0x7cd5_90e5_4c92_3c41, - 0x27dc_0ed1_1611_45fe, - 0x1ce0_4ef4_cfb4_c9b1, - ]), - pallas::Base::from_raw([ - 0xfd5b_9f8f_ddcf_d367, - 0x6a5d_c6bd_9379_c9c2, - 0xc297_9ece_527b_63b8, - 0x323d_873d_580f_2a72, - ]), - ), - ( - pallas::Base::from_raw([ - 0x44f9_82c7_c31d_7a89, - 0x9846_e859_178d_60b5, - 0xa50a_5197_85d6_70ac, - 0x0777_8711_9138_56b7, - ]), - pallas::Base::from_raw([ - 0x8fa1_5093_7040_054c, - 0xe0af_8de4_84a8_b394, - 0x6ed9_fa7f_468f_261d, - 0x26e0_8f4c_2f70_048a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1610_366a_bf41_9b15, - 0x5495_33a5_f504_49cf, - 0xff03_7486_34b9_7494, - 0x2ccd_de83_e509_6a23, - ]), - pallas::Base::from_raw([ - 0x9724_c725_1ffe_d7b2, - 0x014a_a2d1_b3b7_bba7, - 0xed28_d6ab_01bd_03b9, - 0x04d8_9a55_3cc8_37fd, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5053_2dc7_a8cb_ce3d, - 0x9332_681a_8979_6c93, - 0x1b1c_f355_e7aa_959f, - 0x0b04_c461_9897_ec8b, - ]), - pallas::Base::from_raw([ - 0x91c0_9815_eac2_6003, - 0xdf44_c95a_8b52_8f05, - 0xfb9d_53b9_32a2_96c5, - 0x05f7_a7c0_514d_9481, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe9e8_2ebd_f36a_c3aa, - 0xd63c_3aba_dde3_84c6, - 0xa065_4794_bbd5_57d2, - 0x2af1_74e3_b8eb_6bb4, - ]), - pallas::Base::from_raw([ - 0xc1b7_ec28_b61c_bc1c, - 0xa6df_1fd9_3b44_ada5, - 0x41b4_1fbd_54b7_40e1, - 0x07b6_b7b5_6200_d6ae, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf809_14b1_c60c_7c25, - 0xc96e_9d7a_d9d2_0bbb, - 0x9bf1_14b6_065a_6090, - 0x07f3_c075_3999_631c, - ]), - pallas::Base::from_raw([ - 0x6d84_a970_41fb_fe71, - 0x7367_f8cc_4832_6aed, - 0x9fa4_b09a_b998_980d, - 0x10b5_51f4_4081_9d9b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x13b2_211f_8488_06eb, - 0x8761_a8e5_68bd_a93f, - 0xfe79_18b0_b2c7_bedb, - 0x0eb8_9428_e7fa_66e6, - ]), - pallas::Base::from_raw([ - 0xa4ae_5cd1_74dd_020f, - 0x0a36_7483_d7bc_ebd5, - 0x02ee_e479_a589_b49f, - 0x381f_443f_f703_3d02, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbfe9_7299_65ea_ab6c, - 0x91d7_c643_d196_223e, - 0xc1c4_1ee0_2fba_0ee2, - 0x0391_a582_eed5_9211, - ]), - pallas::Base::from_raw([ - 0xf6f5_ac50_5fbe_870a, - 0x4532_ce4f_a3a9_10b7, - 0x2e04_95dc_076f_edfc, - 0x2566_6899_b070_c78e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x59d3_31f8_f73a_4699, - 0xb89e_a133_6b3e_ec84, - 0x67bb_8592_e68f_95da, - 0x0917_436e_03ed_fafc, - ]), - pallas::Base::from_raw([ - 0x2728_c13f_7768_6f7e, - 0x2615_d6e8_f42a_f8eb, - 0x5cc5_df77_1ffb_5726, - 0x00a0_eb9f_912d_b497, - ]), - ), - ( - pallas::Base::from_raw([ - 0x45a5_12f7_5fc1_61de, - 0x0fc6_e344_3c96_5554, - 0x4fea_37c5_2155_ebd0, - 0x07c2_cfac_599f_e891, - ]), - pallas::Base::from_raw([ - 0xd32a_935d_3c0c_02bb, - 0x6263_1e68_432b_5e9c, - 0x072c_bed2_1f3d_b393, - 0x28ed_e749_83dc_4b16, - ]), - ), - ( - pallas::Base::from_raw([ - 0x06de_4839_8da8_baee, - 0x68cc_20a7_0293_f4e0, - 0xde3f_a9e2_2477_7654, - 0x3fd6_fa54_176a_beb5, - ]), - pallas::Base::from_raw([ - 0x5353_f59f_e5a7_9799, - 0x1782_1d05_f83b_d46d, - 0x426d_078d_a05e_5fc3, - 0x278e_e806_7443_d6e7, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc062_01cb_8329_3f63, - 0x2612_bb03_e6c3_5ca8, - 0x6cf4_e8c9_485f_b2b2, - 0x1df7_2e99_3570_d89e, - ]), - pallas::Base::from_raw([ - 0x78a4_d3c2_1b6d_70a7, - 0x14d8_c82f_b0c1_2f69, - 0xf678_2daa_4988_4ae3, - 0x35d2_eef4_df12_fd4f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb4ae_fdcc_23b0_19ed, - 0xac89_a1b7_c189_9999, - 0x3c5b_8165_4f7a_0a2d, - 0x0ab3_7d69_1765_1d3f, - ]), - pallas::Base::from_raw([ - 0xa130_f549_d03d_7b10, - 0xfe3e_fba5_af76_b8c7, - 0x479c_b292_d515_4d68, - 0x08ed_b127_7cd1_5737, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7250_3581_4ad1_9e66, - 0x9fad_6a01_94a2_09c1, - 0xea98_3f3f_0138_1a13, - 0x17b3_e97c_781f_885b, - ]), - pallas::Base::from_raw([ - 0x871a_12ed_525d_b6df, - 0xadc2_9db0_5909_a3d7, - 0x9807_df73_70cc_dace, - 0x31cc_cbe8_16e8_1804, - ]), - ), - ( - pallas::Base::from_raw([ - 0x42b6_c7a3_8516_301a, - 0x6485_544d_58aa_3fec, - 0xe105_5ca4_0c25_2a01, - 0x3ced_acc5_ade8_6885, - ]), - pallas::Base::from_raw([ - 0x4de5_edcc_e563_c20c, - 0x0879_53b7_6a36_36ea, - 0x1eda_cf9c_e6ca_a3a3, - 0x3f82_b415_4198_b3b1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2781_6103_15f5_7658, - 0xfcc0_b779_a51d_a582, - 0x99df_bff3_92f2_e1d7, - 0x1e09_2f1e_a84d_ae01, - ]), - pallas::Base::from_raw([ - 0x1e6f_2bc5_8ea2_2080, - 0x8ed9_b15d_0399_5f75, - 0x727a_eba9_910e_20af, - 0x38c6_dc55_925a_cbb1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x91fc_bc05_db22_2747, - 0x25bc_36c1_336b_0c2c, - 0x4df4_c949_dcfe_5263, - 0x2eec_785b_ec90_be5a, - ]), - pallas::Base::from_raw([ - 0x4d7e_fc93_c1b1_5b65, - 0x2def_facc_0fdc_986b, - 0x1250_98ef_caa3_a74d, - 0x0624_77fe_5983_41c1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb63d_7e66_55d5_e3ea, - 0xfb16_b4cb_6165_cc87, - 0x36d2_6c4d_6ae2_1690, - 0x166a_c76c_81f8_449d, - ]), - pallas::Base::from_raw([ - 0x82e2_3968_9388_5c2b, - 0x1b87_9d98_85df_6a30, - 0x5407_156d_69ad_ce04, - 0x0906_bd2d_e5cc_fafa, - ]), - ), - ( - pallas::Base::from_raw([ - 0x737c_cc41_9796_7823, - 0x1007_28e0_1f6f_ec97, - 0xfc9b_08d3_ba9e_2d24, - 0x06f5_aae5_2940_c965, - ]), - pallas::Base::from_raw([ - 0x28f1_62cd_2885_43be, - 0x3f9e_680d_fcad_3865, - 0x8661_0321_76b3_13ce, - 0x14bd_d4cd_abb9_372f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6c25_b3d7_e74e_4edf, - 0x67fb_ae65_2ead_0439, - 0xc182_0837_bf0b_8a51, - 0x3bc9_ce19_4df3_7d84, - ]), - pallas::Base::from_raw([ - 0x6a05_2e74_98de_40b8, - 0xca78_a073_4c6d_7fc7, - 0x5a0a_a126_7469_ec62, - 0x2f17_851c_850f_c7ed, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3317_c03a_fd91_fc0d, - 0x380d_9ecf_fea8_a93c, - 0x7ecd_e1bc_3a9f_b86e, - 0x1770_3f7b_98a4_afe3, - ]), - pallas::Base::from_raw([ - 0xc54b_5020_c9a0_f2c7, - 0xc66b_05c3_adef_c98c, - 0xf38d_a7ae_8e47_7d10, - 0x3784_0c9a_9c1b_eff5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5093_7efe_a739_821e, - 0x7ff8_6ca2_faa1_106e, - 0x252a_974b_7e9d_2cf1, - 0x1b69_d19c_d62b_b010, - ]), - pallas::Base::from_raw([ - 0xc16f_5a7f_12a2_844e, - 0xae53_d0bb_8ead_5714, - 0xa3c7_0af5_6666_4f67, - 0x3ecb_b98a_9351_1276, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbdc5_4853_e848_f0e9, - 0x1b28_67be_1e77_2485, - 0xe0f5_1554_daca_9e94, - 0x1186_da13_89c4_b670, - ]), - pallas::Base::from_raw([ - 0x1651_3d05_c776_2b00, - 0x20b2_e3a4_b95f_872b, - 0xbf7c_eb39_15fc_1332, - 0x0423_5acc_ac90_496a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x01b0_7e5d_d856_259f, - 0x7f43_208f_a155_b0c1, - 0x8928_e815_2193_8b73, - 0x178d_9714_a538_7eac, - ]), - pallas::Base::from_raw([ - 0xfcb4_658a_4c20_46bb, - 0x6bc7_e482_a235_c77f, - 0x44e8_f7b0_3fb7_88ff, - 0x3ce7_7772_6e04_3742, - ]), - ), - ( - pallas::Base::from_raw([ - 0x55ee_eaa0_d43e_91da, - 0xc90e_6024_78ca_5f27, - 0x6c2a_ec40_cbb6_e051, - 0x0bff_365c_4a48_be7c, - ]), - pallas::Base::from_raw([ - 0x145a_ef04_d8ea_8dc9, - 0x2d56_9b48_e5c8_414d, - 0x781c_943a_068f_fe73, - 0x3361_9f38_967a_b97b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xacbe_71a5_7996_2bd4, - 0x3a08_766b_9cb9_e72b, - 0x1588_d82c_533d_b065, - 0x30d6_c1d1_7767_c3e6, - ]), - pallas::Base::from_raw([ - 0x5d52_0dac_efe4_6e17, - 0xd87a_651f_6eab_7d3f, - 0x6a75_591f_324e_b6db, - 0x1a5d_9a98_7774_d8e4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0225_72e9_ae01_ff6b, - 0xce5a_1ad2_ef36_212b, - 0x14c1_0f42_da3d_b3ad, - 0x2267_625e_16a9_0f0e, - ]), - pallas::Base::from_raw([ - 0x7bf4_5dd3_d6d6_71ec, - 0x01bb_0a02_1198_ccac, - 0x15d0_34ca_24fa_48fa, - 0x19a8_8c5b_dd76_c0e2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfdd9_7cc1_34fa_1e2d, - 0x3714_b775_9ccf_8134, - 0xb76b_7ae3_d982_6b77, - 0x1ecb_f631_e1bd_91a2, - ]), - pallas::Base::from_raw([ - 0xb611_00ce_ead1_4ede, - 0x9f64_dc5c_9bf7_633c, - 0x315e_4d26_f06e_c2e6, - 0x024a_535a_5088_6f26, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9c75_4f1e_74b6_2341, - 0xc229_dbf2_cfa3_2ca1, - 0x8012_a006_e1b9_9678, - 0x289a_7df4_9f8e_2205, - ]), - pallas::Base::from_raw([ - 0xa292_86b7_14cc_854c, - 0x63c0_5a80_bab8_b239, - 0x77bc_a95b_3393_16df, - 0x0aa1_78e8_67c4_6e06, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6983_e305_abeb_b0fc, - 0x4047_8611_cde4_c624, - 0xcdee_dbfe_557f_b7ed, - 0x04e8_1c14_8e02_18d1, - ]), - pallas::Base::from_raw([ - 0xe556_8d33_21a8_0629, - 0x97f8_66e9_f2bb_ae53, - 0xcea5_b64e_5002_2bbb, - 0x1a34_52e0_acea_f51a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3405_d717_8cc7_2c52, - 0x28a7_a504_399a_1e1b, - 0xf170_e239_f7e9_c844, - 0x1cd3_6395_bb69_dc88, - ]), - pallas::Base::from_raw([ - 0x675b_0b51_04e6_8e2d, - 0x187f_6ecc_1ded_2163, - 0x1a53_421e_85e3_7079, - 0x158a_e3c7_752b_7751, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5500_883e_12a9_cfd7, - 0x9cd8_0402_12bd_4753, - 0x1f75_8954_f62b_dad5, - 0x0bbb_fa9c_c2fe_d2d0, - ]), - pallas::Base::from_raw([ - 0x19e6_d909_4824_a28d, - 0x8cd6_c4c0_9883_3e51, - 0xb646_194f_becc_6f59, - 0x3420_e2ec_d734_13e5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x80a9_e5e3_1610_f69e, - 0xdd9c_4a92_1056_8e20, - 0xf86c_aeb6_c85c_4356, - 0x31ad_dfcc_5e4b_700d, - ]), - pallas::Base::from_raw([ - 0xe9ab_d914_79e1_df04, - 0xb7f0_23f3_36f6_74dc, - 0xa9d2_3371_7f13_8bb6, - 0x1f15_2617_cb34_976f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x960d_00a3_fb22_5078, - 0x9988_7156_0e61_3f5f, - 0xb2ba_af97_cca6_a3eb, - 0x2e7f_19e7_c704_b5fd, - ]), - pallas::Base::from_raw([ - 0x57bb_469f_0dd9_b209, - 0x9c40_8186_c84a_bd26, - 0x5413_30b7_2445_9760, - 0x3ea7_3777_ee4f_b850, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6241_5e2d_be88_0053, - 0xe65d_815b_0595_5f7a, - 0x6b5b_e7ed_43e0_5474, - 0x29f9_ef3c_013d_20ff, - ]), - pallas::Base::from_raw([ - 0x645c_e074_cff0_711a, - 0x9b08_6e5e_0ae6_30dc, - 0x1765_5ee6_7ff2_68df, - 0x2830_190f_e6ea_62a9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf9a6_568b_9c61_4281, - 0x4bf3_f37b_d546_d5ce, - 0x47fc_7710_3474_7b14, - 0x3a46_2aa4_f76a_f9ef, - ]), - pallas::Base::from_raw([ - 0x480d_19d7_aeef_4c79, - 0xab60_e175_aefb_931d, - 0x4d55_85d0_c71f_a5b4, - 0x0a96_8e62_97d5_9535, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe436_903f_24ac_9df9, - 0x9300_ddf0_1da8_17a6, - 0x123e_6839_b4bc_932a, - 0x2718_8488_35fd_d77f, - ]), - pallas::Base::from_raw([ - 0x52e4_7abd_9b09_46bc, - 0xc085_3ece_0feb_e4a5, - 0xf3f8_35c8_347e_995d, - 0x19de_e913_2cc0_a224, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa453_83a9_b4e6_a758, - 0x9015_00b5_23c1_e447, - 0xe85e_c0c8_8626_5736, - 0x1461_a8e6_40c8_f85a, - ]), - pallas::Base::from_raw([ - 0x501d_08ea_fd72_b2c8, - 0xeb63_ec79_4f6d_f403, - 0xf1e3_f250_1c53_0d19, - 0x062e_d759_693d_19d8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa2c4_a38d_b249_fc75, - 0x8ae4_0721_77c7_8590, - 0x03dc_4b04_8d5b_9ea5, - 0x0d89_0d38_e803_317d, - ]), - pallas::Base::from_raw([ - 0x3e10_ee60_9358_ada7, - 0x3509_48eb_0862_d70e, - 0x75aa_80df_185a_8c1c, - 0x37e7_c380_d027_a877, - ]), - ), - ( - pallas::Base::from_raw([ - 0xaafd_a565_f09a_06cf, - 0x91e9_f0c0_b668_00eb, - 0xba89_4a61_9a9a_5deb, - 0x35ab_6c2f_a72a_67a5, - ]), - pallas::Base::from_raw([ - 0xdd34_5830_bbc1_a26f, - 0xc3d2_140c_6fc3_9747, - 0x6580_4aaa_a4a3_f62c, - 0x2c8a_da2b_1b04_9e5f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x641e_246a_98ad_630f, - 0x72ab_91de_19b3_2e2c, - 0x5c92_774b_2169_b661, - 0x1e1a_c543_70ce_61cd, - ]), - pallas::Base::from_raw([ - 0x9cb2_3ff5_285b_8448, - 0x9bb4_a42b_f331_6727, - 0x62dd_a513_c86e_4720, - 0x2138_a0f0_4fd0_ae85, - ]), - ), - ( - pallas::Base::from_raw([ - 0x05ff_8a30_31c8_c2c0, - 0x320c_4e8a_b37d_13af, - 0x5fe1_6192_7de0_0a62, - 0x3239_6eec_c899_df01, - ]), - pallas::Base::from_raw([ - 0xf86a_5aa7_254c_db0b, - 0xfff8_6343_7c50_4001, - 0x907e_ce31_13c4_2834, - 0x0083_9120_fef6_4f04, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0da3_5615_e80b_7105, - 0xcd0d_35c7_83f5_ea68, - 0x1956_8f17_fd14_c784, - 0x3844_169d_8e21_5b80, - ]), - pallas::Base::from_raw([ - 0x1fcc_6ff4_1c9b_ed51, - 0x34e5_9481_5dd7_ec6b, - 0x0ba0_d316_7cad_7c5d, - 0x3ec0_c83c_398a_638e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x30e3_dd2a_caa8_9e23, - 0xca56_24c7_a921_34aa, - 0x569a_4c5d_be62_0c0a, - 0x0bb5_f435_f064_07e1, - ]), - pallas::Base::from_raw([ - 0xdfe8_e197_5e22_f53b, - 0x8dfa_bec5_7137_b1fb, - 0x01e1_9f98_b685_ae1a, - 0x28c1_1490_0528_c2c1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3dcc_f7ce_0ad8_e4f8, - 0x588e_312e_199e_763b, - 0x8c6a_a52f_0325_558d, - 0x29c4_ba69_c672_f4f3, - ]), - pallas::Base::from_raw([ - 0x19ec_f218_7171_52d7, - 0x06ee_7a55_fa38_ba4e, - 0xd8f0_a4f2_6c3c_fd95, - 0x3ef7_61af_4dbb_7f0c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1f0f_baad_04bb_5f75, - 0x4aef_02b6_56f4_e2f0, - 0x4c89_9bff_b8a0_8ea4, - 0x3f4e_7e2c_a1c7_708d, - ]), - pallas::Base::from_raw([ - 0x02f6_7a10_1c9c_9bbf, - 0x05f3_0cdb_8ba2_8ad6, - 0xc13a_c49a_1560_a8e2, - 0x1534_bedb_9435_5918, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfa87_6dff_b810_be23, - 0x72c7_0ce1_e075_2041, - 0x07c8_bf38_511f_3cef, - 0x1a6c_5f3e_ed1b_e25b, - ]), - pallas::Base::from_raw([ - 0x51dd_c0ae_85fa_65b0, - 0x835b_4dca_4cc3_3f47, - 0x1bd6_02bd_221a_6807, - 0x32c2_3d1a_8a90_ae9f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0eed_532c_a114_960d, - 0x6983_2d07_9745_030d, - 0x0cb8_8c0e_c597_8792, - 0x3ed4_46f3_babd_8fbc, - ]), - pallas::Base::from_raw([ - 0x2fa7_9562_7ce7_6ebb, - 0x7e21_5019_7c86_5e0b, - 0x6d0e_6986_0b16_2609, - 0x17ed_a803_03d2_9dbd, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5add_f07f_2875_4f6e, - 0xded2_1019_ce38_6e69, - 0xba11_5d0e_d146_4546, - 0x1cb8_adf5_6bf7_d57b, - ]), - pallas::Base::from_raw([ - 0x74b3_43e7_3067_5c9f, - 0xaabe_1a6c_c038_250c, - 0x8ef9_5802_7c5c_eb68, - 0x26f7_2308_b634_cbf3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe697_9cd0_2e2a_09a3, - 0xbfb4_1ab4_b141_08b6, - 0x290d_dd81_2cb0_5761, - 0x2a6c_642d_8d10_e582, - ]), - pallas::Base::from_raw([ - 0x8536_8a2a_e13e_84a4, - 0x9ece_6cb2_499e_86d2, - 0xa6d1_0304_1f4e_6811, - 0x1749_3586_294f_c00b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd000_f933_b288_c9ec, - 0x0008_fa27_b1fc_f86c, - 0x77b8_dc36_5ede_0af6, - 0x289d_ea2d_59eb_3f26, - ]), - pallas::Base::from_raw([ - 0x6ee9_9aad_2b6e_4dfc, - 0xa357_f9fb_63b5_5c8d, - 0xb99d_03c4_98a8_d710, - 0x2cfd_b980_9dc3_4f19, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4a3f_f24b_fabd_5cdf, - 0x7415_5bb3_3633_20e8, - 0xf605_add9_99a6_a3b6, - 0x0365_39f1_3da5_3f58, - ]), - pallas::Base::from_raw([ - 0x4aa5_e910_0459_c408, - 0xe4df_d4e4_dbfc_3099, - 0xece4_6d1e_47e1_8bae, - 0x2571_fbf8_3aaf_0f52, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc08b_755a_6fa6_56f0, - 0xac17_cbd2_3558_19a6, - 0x0e1d_63a9_76de_d59f, - 0x0f0d_bacc_068f_cd71, - ]), - pallas::Base::from_raw([ - 0x9ab6_8817_d366_c236, - 0x7ada_4276_3f88_5fd7, - 0x083d_de4f_9fe3_44ec, - 0x33de_e193_caf7_4d09, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3595_8bfd_2887_b46e, - 0x5f38_9101_f1be_4e28, - 0xf9d1_acba_99ed_08d5, - 0x34ae_a666_fa73_373e, - ]), - pallas::Base::from_raw([ - 0x8550_386d_b269_6cc2, - 0xace0_f26f_8504_9ec0, - 0x8e1e_d46d_9d3d_5454, - 0x0978_82d8_5b44_aeee, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1337_19a0_5435_a760, - 0xeb59_3ab7_0fce_fad0, - 0x066b_89a8_bf0d_853a, - 0x1a05_df20_1bf7_016e, - ]), - pallas::Base::from_raw([ - 0x69f0_568a_7e88_6ac6, - 0x90d1_fb1a_ccb8_880d, - 0x81f3_cb9b_0f87_03f4, - 0x28e5_0389_a936_6ecf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x50bb_3f29_64dd_d715, - 0xd5aa_f9a6_dc3f_7706, - 0x6e6d_1433_c49c_3c3d, - 0x1a87_0e90_b006_4440, - ]), - pallas::Base::from_raw([ - 0x8f4a_8f0d_9ffe_2a67, - 0x3df7_ff37_8b3d_e8b2, - 0xe200_ac50_b2e5_224a, - 0x2ea8_be75_625f_19d6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9352_f3ae_79df_84a6, - 0xd821_c76a_b91e_7cd2, - 0x1516_8b7d_afe5_369b, - 0x39b2_d1b3_ed5f_2801, - ]), - pallas::Base::from_raw([ - 0xe3c1_c8d3_4ac0_cded, - 0x2467_48bb_7fb8_12b2, - 0xf18d_46f6_9a23_e9ca, - 0x12b1_73bf_3cbd_5773, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0d92_cb07_476a_c74d, - 0x9179_b82a_91e5_9ea2, - 0xd5fc_3ab3_d692_f5e0, - 0x3dee_efd0_00c3_3a50, - ]), - pallas::Base::from_raw([ - 0xce37_7044_fa32_43cd, - 0x23ea_04ca_a975_a183, - 0x3aa3_b02e_ec62_b871, - 0x04a9_2111_c558_8ef0, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdc97_a102_7da5_665f, - 0xa1bb_5b5d_cefd_5818, - 0x7b4e_1a76_62cd_3571, - 0x3aa3_d99b_5276_2d70, - ]), - pallas::Base::from_raw([ - 0x94bd_7936_fec3_7759, - 0x7216_4b55_232e_5a3c, - 0x756b_e2a2_52bd_b271, - 0x33f2_bb74_d656_6f3b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc8fd_7256_d6dc_d9b9, - 0xca03_c9d8_7f65_7f5e, - 0xfd39_43fa_2bf6_46db, - 0x22c1_594f_6399_a591, - ]), - pallas::Base::from_raw([ - 0xa3d3_1b89_58be_066c, - 0x3776_df4c_4371_d751, - 0x6b4f_1dcd_0000_7a87, - 0x3a6d_83e9_a433_e219, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2bac_92ca_749d_8ca1, - 0xcdff_b76a_d983_64c1, - 0x4a71_9e43_074b_e266, - 0x211d_199f_4af1_3d31, - ]), - pallas::Base::from_raw([ - 0x615c_f375_7d8a_3f72, - 0xe271_0a4e_2b25_e0cf, - 0xe07e_62f8_a9e1_180f, - 0x3668_5169_d28f_4663, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5026_b92b_a025_7211, - 0x0f61_be9a_2a03_558b, - 0x6eb5_4fce_c558_57ce, - 0x3193_20a0_380e_6bd7, - ]), - pallas::Base::from_raw([ - 0x6fe5_1d43_554a_f6a8, - 0x6ff0_48c0_b9c9_f972, - 0xb6f3_7bca_07a3_0477, - 0x01b4_080c_f397_6ea1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0c85_14b2_21c5_bf83, - 0x6a65_f7f8_f786_f1e3, - 0x3c45_3a2c_865b_f046, - 0x18e2_8c3f_fbc1_e707, - ]), - pallas::Base::from_raw([ - 0xb311_7e90_19e0_60bd, - 0x682c_b029_85d5_f279, - 0x2d07_1839_acf3_3c80, - 0x24fb_be5a_09e4_252a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3f38_1349_fd30_13dd, - 0x50a3_3f2c_64f9_acc4, - 0xbdfc_c29a_eaae_4852, - 0x08cd_e7f1_737e_4d1f, - ]), - pallas::Base::from_raw([ - 0xc9eb_95f1_0d2e_cff9, - 0x2e16_091e_e8fa_7cb8, - 0x2338_d545_b2b1_87df, - 0x2f9c_01cd_934a_39a5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2f4f_2486_fa98_dd32, - 0x5ab3_50b9_9429_ab02, - 0x4d00_5b08_67f9_fb09, - 0x3779_1b28_6244_fb4c, - ]), - pallas::Base::from_raw([ - 0xf37a_1b41_ad70_19ed, - 0x3d58_6291_0404_eff3, - 0x3710_9d64_690b_7131, - 0x323d_fe2b_648a_0a01, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2c99_1b63_424c_90ac, - 0xcde0_e148_9201_19b1, - 0x6b0a_cdcd_a94e_23dd, - 0x0a83_ec85_5467_a25b, - ]), - pallas::Base::from_raw([ - 0xe2ae_b456_e029_5ff5, - 0xbbf2_157e_95d4_0f9e, - 0xfcf3_8385_5286_2123, - 0x09d4_c6b8_6321_1860, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5a98_269b_b68a_dd6a, - 0x1efe_b941_4639_b22a, - 0x3571_1c04_46ae_622b, - 0x0724_0c4e_61e2_c404, - ]), - pallas::Base::from_raw([ - 0x4ef2_32c5_b9e0_bf79, - 0x2849_2c6d_82b9_4679, - 0x6dc9_c162_d595_5ace, - 0x23a1_46c9_cb46_7e4b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0ea6_e467_1688_5744, - 0xd73a_c7a9_3c06_0f51, - 0x1b46_3eef_0911_0ff0, - 0x25f5_1a1b_8b2b_15b0, - ]), - pallas::Base::from_raw([ - 0x0e94_24d7_d847_cff0, - 0x9eca_1c26_c8d3_4d22, - 0x3e7c_44f4_a071_358a, - 0x02e0_3e55_9e85_2acc, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfaf6_e963_4f72_548c, - 0x75ba_6678_06cb_3018, - 0xdd5c_4dc1_f6a6_1ed0, - 0x358a_aa4a_969c_7d11, - ]), - pallas::Base::from_raw([ - 0x7192_b88c_0b41_26f7, - 0xdcbf_5faa_5173_d672, - 0x2844_3f7b_d7c5_386b, - 0x0326_622d_0d54_8882, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf31d_8620_1649_f08d, - 0x1fc2_50c9_c62e_1cdb, - 0x3fa2_7d7f_c12a_308b, - 0x087a_7698_3f2b_40d6, - ]), - pallas::Base::from_raw([ - 0x1dfe_55f8_f11a_cf1f, - 0xee33_c9fd_9995_34ef, - 0xc306_776a_68aa_2318, - 0x2ac3_5afb_37f0_64ac, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3ade_cfe8_e5e3_3497, - 0x6c41_930f_374a_cbed, - 0x12b0_f864_c7a8_8ad8, - 0x370f_dfb0_97f4_2558, - ]), - pallas::Base::from_raw([ - 0x7220_b1e4_1ab5_cf99, - 0x1632_92de_779c_623c, - 0xb034_0022_4b4a_86e7, - 0x309b_afa2_6ef2_925b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3406_5012_f9c0_5127, - 0xc828_f419_9900_4b75, - 0xf6d7_a11d_f480_e3f3, - 0x2d33_2d46_fc42_f207, - ]), - pallas::Base::from_raw([ - 0x2e46_6250_9e68_6ee3, - 0xabfd_de7c_df9e_5e25, - 0xfd57_0e95_4b02_75d5, - 0x2477_ef02_28ea_9a13, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbc3e_e22f_76ca_58be, - 0x3ea8_77d8_d59b_c50b, - 0xa88b_9b65_778b_d746, - 0x3ac6_7681_a682_1563, - ]), - pallas::Base::from_raw([ - 0x012d_26a1_75a2_a60c, - 0xd293_1675_5b9e_520e, - 0x7bb3_81b2_f90a_0804, - 0x33a1_bb0d_70de_7a89, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb0ca_c9ca_8444_ee90, - 0x968e_19ad_ff27_1d61, - 0x3f26_3e09_835a_f66b, - 0x05bd_71f7_da1c_0c64, - ]), - pallas::Base::from_raw([ - 0x61e9_dece_6f85_2582, - 0xe5d1_17ee_5df5_c9f5, - 0xa3d6_5b5f_bc5d_8147, - 0x3b58_829c_1b3c_754e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x39e8_9116_b59c_ef80, - 0xe8ee_3f15_868d_9a99, - 0x4b32_6add_a5d5_8444, - 0x14fe_9402_9ff7_9f66, - ]), - pallas::Base::from_raw([ - 0x8f66_4020_0012_b5cb, - 0x6fcc_c979_1537_fa13, - 0xd19e_3ecc_386a_8282, - 0x162c_c785_6d5c_74dd, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdcc0_2e8e_07fe_88af, - 0xbd3b_2a17_ffae_f834, - 0x0c6f_3298_640b_78d5, - 0x34a4_a683_e010_cf56, - ]), - pallas::Base::from_raw([ - 0x63f3_abee_7273_ea33, - 0x0537_702e_040b_92a5, - 0x547d_6ec3_8dd6_3bc9, - 0x0064_5b12_758a_1545, - ]), - ), - ( - pallas::Base::from_raw([ - 0xee8e_7e91_b30f_5175, - 0x9118_328b_98b1_2a4f, - 0x0c6b_7d43_ce19_2ef5, - 0x2683_6545_f707_77c2, - ]), - pallas::Base::from_raw([ - 0xd798_780b_8fd5_f829, - 0xc468_a05e_0278_eba4, - 0xb7fa_f13c_0064_7ac1, - 0x322a_6aee_3ba4_d176, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1e3b_4dd6_6189_13dd, - 0x248b_f2dd_da95_8f94, - 0x8216_4826_97e1_1826, - 0x21ac_9398_a5e7_dcec, - ]), - pallas::Base::from_raw([ - 0x772d_8d75_5b4c_3ff4, - 0x7677_d0f9_ffdf_bce3, - 0x10a3_b808_a28e_401f, - 0x3f6e_5b46_b349_c86e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5585_d887_f1be_367c, - 0xaf07_cc5a_a53a_b659, - 0x923e_92e1_35a8_1746, - 0x3bf2_268c_f24d_f183, - ]), - pallas::Base::from_raw([ - 0x6fe6_0473_5e78_a74d, - 0x39a1_9091_b746_8447, - 0xa594_c45e_b7ed_cbeb, - 0x0bc9_13da_4cca_ecc3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1dd4_2c2c_c537_4903, - 0xa6cd_7de7_d439_ae61, - 0x15db_897f_3b7a_4b07, - 0x385c_81f8_ce51_3dd7, - ]), - pallas::Base::from_raw([ - 0x0ed8_0b1c_199e_8dc9, - 0x79e2_6722_5b1d_39ed, - 0x8b04_7941_6c0b_072f, - 0x1507_a637_5325_d934, - ]), - ), - ( - pallas::Base::from_raw([ - 0xaf31_86eb_84ad_4635, - 0xa779_6331_ccd3_0336, - 0xf128_6ce2_c67c_671f, - 0x00c1_b469_5cb2_7c0a, - ]), - pallas::Base::from_raw([ - 0x7c4f_be0e_1cae_a3da, - 0xc17b_1bad_0248_be18, - 0xbddd_f903_c50f_6c61, - 0x2f3f_845e_eaa9_03e7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7338_6610_264b_147f, - 0xe78a_eae6_e018_7005, - 0x909e_4f4d_6e92_b8fc, - 0x20ec_33c4_98b4_3f28, - ]), - pallas::Base::from_raw([ - 0x29a8_eaa1_5507_3eea, - 0x729d_227c_2a31_1b0f, - 0xb154_9c99_6dee_651b, - 0x3060_2ac3_8a24_17f5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3fa1_0f32_fc38_d1e7, - 0x1130_716c_d00c_2e12, - 0x8b7b_e7ee_bb9c_cf07, - 0x03dc_0d4e_7c25_b4c8, - ]), - pallas::Base::from_raw([ - 0xcc37_2d2f_1cf0_494e, - 0xf281_1971_693f_a7cb, - 0x71c8_5723_0112_d789, - 0x0b3a_4062_de68_d35a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2e57_965d_8fe6_3cf5, - 0x1e7d_0375_96cf_b42f, - 0xe4eb_acfa_e071_f221, - 0x18c8_30aa_25a9_b96b, - ]), - pallas::Base::from_raw([ - 0x1e35_c955_b145_dba5, - 0x38bf_a239_4c66_8c55, - 0x2b79_b6c0_0ae1_44e5, - 0x3306_70f2_2a1a_de18, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0337_c17d_8089_522c, - 0x8cf3_b7f9_e509_1e93, - 0x30c2_0095_5bf9_2882, - 0x1803_6e94_3474_308f, - ]), - pallas::Base::from_raw([ - 0x83ac_e960_14ab_f3bb, - 0x39e9_4c89_6758_a248, - 0x3b82_4eaf_babb_2278, - 0x05fc_dc8a_770e_abbe, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4d15_af9f_a6dc_11ec, - 0x9688_b4f7_fa83_b756, - 0xa900_9592_c556_2c12, - 0x3131_f9b2_c23e_76a9, - ]), - pallas::Base::from_raw([ - 0x6377_bc0b_418d_17d1, - 0xbdc7_c62f_a1a8_205e, - 0xb808_e58c_dc75_27e1, - 0x3ce3_9a6a_42ea_0aa0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x919c_3661_1b95_aae0, - 0x21c0_adf5_8570_1f29, - 0x15d8_a824_0a43_7e95, - 0x2487_0e7f_975b_e250, - ]), - pallas::Base::from_raw([ - 0x2b8a_f942_d325_4f8f, - 0xb8bf_f293_9d0e_2803, - 0x2b36_1401_fde5_3611, - 0x095f_973d_1e25_6fe0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x25b5_ca69_afd7_aff7, - 0x5731_761b_b667_965f, - 0xf0db_8000_e078_d5f6, - 0x105f_d651_9a6f_486c, - ]), - pallas::Base::from_raw([ - 0xf6ed_7c18_4edf_3a25, - 0xf716_d2fc_b54c_26c1, - 0x8303_3072_def8_c70a, - 0x3c72_43cc_c6f9_d8a8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd29a_f540_a1af_2913, - 0x86f8_1775_ed00_f09a, - 0xc978_728d_7996_fcb6, - 0x15aa_c4cf_5c52_2bcf, - ]), - pallas::Base::from_raw([ - 0xccad_8b65_5bf6_65a2, - 0x197e_4429_fe3d_8a0a, - 0xbc26_5a82_cbc8_f7ef, - 0x0963_7be9_0c33_cc7a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x75dc_37ce_9ca5_f163, - 0x3ce4_4f1c_f801_0d67, - 0x1933_916f_d304_ae70, - 0x09c9_2882_3da7_3ed0, - ]), - pallas::Base::from_raw([ - 0x141a_785b_eb35_8d29, - 0x10a1_7521_6bb8_ca36, - 0xcd51_d77e_9964_8226, - 0x1d96_15b1_2538_b56c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7c71_c1bd_6f57_54d3, - 0xc9a0_533d_95df_b16c, - 0xc945_1160_48eb_86c6, - 0x05a8_f8f3_8c44_0d2e, - ]), - pallas::Base::from_raw([ - 0x11d8_5995_cf88_f460, - 0x44eb_7f8a_f7bb_3f42, - 0xbe8c_bb43_79ee_ea5b, - 0x02dc_b98f_ed50_2f86, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4aa2_aebe_4d5d_a915, - 0x3425_6cb2_b933_62ec, - 0xd229_ad1e_6a44_6607, - 0x35fd_e2b2_e65f_cbf8, - ]), - pallas::Base::from_raw([ - 0x9a36_e5cc_e10a_7cc0, - 0x7d41_adbf_6442_8e9e, - 0xc64a_aab0_e77d_ddc3, - 0x28b6_ce44_dd17_b086, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1729_f03e_c757_de09, - 0x8714_d598_3cae_ddd6, - 0x46bc_981b_76f8_5cbe, - 0x1b7c_7a5d_98d4_34b6, - ]), - pallas::Base::from_raw([ - 0xfb61_8881_0f97_fafc, - 0x769e_1253_4744_7d00, - 0xe166_94e5_6b37_ac66, - 0x0e0d_592c_aaa4_40d6, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb477_691c_7b9a_4e74, - 0x1c61_eaa0_b273_998a, - 0x9295_2b04_a869_8738, - 0x18ae_d1c7_f94d_31cb, - ]), - pallas::Base::from_raw([ - 0x63b4_a102_91a0_3aa0, - 0x8456_6a59_cd00_e2e8, - 0xd9ac_8f76_f4fb_99ea, - 0x249a_c33c_1f19_006c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa611_c5c5_9dd9_c129, - 0xb449_431e_460c_3b9a, - 0x8aca_28de_50ac_6407, - 0x2be1_f2a6_a7a7_ef47, - ]), - pallas::Base::from_raw([ - 0xa14c_46c9_87ca_1f52, - 0x40fd_f4bb_a4f9_9362, - 0x99f2_8ce2_fff0_5d47, - 0x2339_e672_20fd_6223, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb07e_39ee_d553_19df, - 0x2e2e_a2b6_cd63_7b9e, - 0xb230_1c5c_5876_4d85, - 0x3101_8876_853f_6e11, - ]), - pallas::Base::from_raw([ - 0x6d1c_01bb_fd88_f740, - 0xac45_ec78_810e_f0f9, - 0x9178_89e7_5ed9_7c53, - 0x2e02_e772_12fb_a864, - ]), - ), - ( - pallas::Base::from_raw([ - 0x482b_ce95_a904_fbd8, - 0x099f_45ef_d9d4_df4e, - 0x6e70_1656_036c_32a5, - 0x0a38_cfd7_47d5_12df, - ]), - pallas::Base::from_raw([ - 0x570e_1101_ac76_4879, - 0x99d6_ff14_205e_e41a, - 0xc0cb_4ce1_8364_ca7d, - 0x3f21_3a0f_2127_88ab, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd491_d705_998e_3189, - 0x7bbe_badc_663c_142a, - 0x1d71_9890_63cb_18bf, - 0x24f8_a1c5_2bcc_e57b, - ]), - pallas::Base::from_raw([ - 0x1052_3fab_b946_6f52, - 0x4621_6150_6b1b_7617, - 0xe22b_b133_5f66_15bb, - 0x00f7_be2e_c34c_d4e3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9b7c_bac0_1918_11a9, - 0xe14a_1c33_bf27_13cd, - 0x9c34_676f_4ed5_0771, - 0x3bc3_b8f9_e4c7_cbdf, - ]), - pallas::Base::from_raw([ - 0xc0c3_e7a5_3a19_2bbe, - 0x9697_bec0_d8a8_605b, - 0xf832_dc8b_d08d_48b0, - 0x0ad3_7d64_7a36_db47, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1a49_dcca_d569_77a0, - 0x2769_7440_2b48_e461, - 0x7635_b7b2_f6c1_424a, - 0x2be6_10f4_a289_b89f, - ]), - pallas::Base::from_raw([ - 0x3e61_c167_3ef3_fc04, - 0x704f_268b_ce47_f0ed, - 0x1445_3f5f_d2de_d836, - 0x2cc9_d834_4ecd_1dd8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x11be_a2a7_7c43_e243, - 0xaecc_1a58_bb49_1e6a, - 0xad18_3b6c_844b_4f3e, - 0x3af2_29a8_1e78_8c01, - ]), - pallas::Base::from_raw([ - 0xe5c9_8811_3857_46dd, - 0x18a2_37a6_3f4b_065b, - 0x95eb_77a3_8a4f_506e, - 0x0f19_e7b4_bb81_9e9f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4289_8695_120d_ccc9, - 0x7c47_76b5_b28f_500d, - 0x7387_a0f6_6257_0e43, - 0x3e0a_1a75_0403_726f, - ]), - pallas::Base::from_raw([ - 0xa4b8_617f_f5a5_e2d0, - 0xbf01_7517_8dc0_be8f, - 0x3e12_8a0f_5763_aace, - 0x1019_05b6_1b1b_c5f2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6a1c_6336_c37a_69b0, - 0xab01_b8f5_4c9c_c938, - 0x4b70_77c2_8858_0ff1, - 0x219d_9462_2657_9313, - ]), - pallas::Base::from_raw([ - 0xf0ca_ec54_481d_b8b4, - 0x9caa_706e_8ced_f819, - 0x892e_4cf8_342d_d927, - 0x241c_1980_c2a8_9519, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2257_583e_eb36_4cc3, - 0x2729_3e7e_d528_5088, - 0x7eca_1457_60f9_6fcd, - 0x366d_41fd_d540_9bb6, - ]), - pallas::Base::from_raw([ - 0x8bfe_2959_1e82_19f9, - 0xbbcf_1722_efec_e216, - 0x9560_fd43_03ee_a5fe, - 0x01a2_ccf4_056f_faa8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf4b5_ad0b_5218_a94c, - 0x3a24_9090_dd6d_9354, - 0x98dc_0f69_de87_c57c, - 0x3dda_357c_5ff1_403e, - ]), - pallas::Base::from_raw([ - 0x5119_459b_c85d_b13a, - 0x2bfc_720c_90b0_7f40, - 0x8537_0f1d_f88b_d581, - 0x37db_226e_c00e_a298, - ]), - ), - ( - pallas::Base::from_raw([ - 0x63b3_23a9_39a1_77d2, - 0xe62f_9748_713d_01cc, - 0x2508_9050_a0a1_59bf, - 0x3d7c_7c78_e9b8_851d, - ]), - pallas::Base::from_raw([ - 0x3984_54cb_b4b2_6fce, - 0xc06e_f1b1_b11f_d4b9, - 0x4456_781c_e7d7_a297, - 0x04cd_8194_f1b8_f453, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1848_83cb_b617_7af4, - 0x2d57_546c_a4fe_c3d5, - 0x984d_e3a8_9232_dc0a, - 0x0fe5_7d7a_b313_f576, - ]), - pallas::Base::from_raw([ - 0x675f_4ab1_700e_2db7, - 0xb044_6bdd_3a0d_7127, - 0x8d66_c6a3_c174_8080, - 0x339e_ae89_0552_92fb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x28c6_46e7_5497_b6ce, - 0xa3fa_753a_0908_d101, - 0x1f09_d0f5_065d_2adc, - 0x178a_d1dd_216e_1573, - ]), - pallas::Base::from_raw([ - 0x030e_a306_b041_1e57, - 0x762a_03ec_df28_bda9, - 0xa2c1_f35a_ecc9_b51c, - 0x037f_7114_803f_e131, - ]), - ), - ( - pallas::Base::from_raw([ - 0x59ea_b5bb_9453_8366, - 0x5fd1_07f8_c2f0_3024, - 0x491f_9e0a_77a0_85f2, - 0x1948_5bba_5ad6_3346, - ]), - pallas::Base::from_raw([ - 0xe07d_8570_5ff6_f740, - 0xa7eb_9f4b_f78f_ebfb, - 0x4ec7_d8d5_ba74_87e2, - 0x152f_bf0c_1ad3_a448, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8951_a4b7_b88a_e304, - 0xfbba_f494_63d6_2de5, - 0x52dc_f4cf_46fb_b604, - 0x3867_61af_f0a2_8253, - ]), - pallas::Base::from_raw([ - 0xa79e_a333_0c3d_f255, - 0x98c0_1806_eff3_7bfa, - 0xce04_7c7b_36b8_bcd6, - 0x3c8b_a7f4_c363_edea, - ]), - ), - ( - pallas::Base::from_raw([ - 0xaf3d_f661_71ab_0aef, - 0xf42a_df27_feb7_ccb0, - 0xf652_096a_95e0_714e, - 0x12d2_2f2e_bb9f_dc00, - ]), - pallas::Base::from_raw([ - 0x2bd3_e13b_745c_7e1a, - 0x30d5_8bed_1c3b_4731, - 0x4fe9_de60_156d_0e6c, - 0x1e75_82ca_046c_a5e1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4b26_3b3a_2d30_be4e, - 0xa303_e1b5_ef9e_9c4e, - 0x1a0c_d3c7_1f78_d34d, - 0x0bc6_cbe2_2b93_1a09, - ]), - pallas::Base::from_raw([ - 0x5ef8_540a_c950_78e6, - 0x5d90_b70b_8565_5e85, - 0xed53_c717_36e6_4c78, - 0x1686_468a_3079_9166, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0d0d_dd14_b731_9e48, - 0x712e_bc82_5391_3fdc, - 0x5fcf_dda4_b51e_08ba, - 0x2f3d_06eb_2d44_fe78, - ]), - pallas::Base::from_raw([ - 0xa569_8634_a0b3_f32d, - 0xc8a6_e6d0_0d30_9550, - 0x89e7_8274_9620_9f58, - 0x05b3_f104_5b90_6405, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6556_9fab_c93f_5ef1, - 0x8c77_fb45_e5b0_3ff0, - 0x1462_4404_a661_0d5d, - 0x1431_fd82_8c12_8ca9, - ]), - pallas::Base::from_raw([ - 0xe0f4_ffe0_7a81_532a, - 0x6254_e069_7645_e573, - 0x3642_fa4b_19fd_822a, - 0x2485_d135_0391_bb52, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5768_e306_b266_4925, - 0xd2ef_fda1_e729_f652, - 0x21c6_d47c_319c_a9c0, - 0x2401_0c36_e54d_b3ee, - ]), - pallas::Base::from_raw([ - 0x4951_90fc_eb1b_0b80, - 0xf0c2_c315_ee04_91f2, - 0x61bc_9d08_1307_b3d6, - 0x024a_b73e_3607_a264, - ]), - ), - ( - pallas::Base::from_raw([ - 0x107f_387e_54f4_ef3f, - 0x290a_32da_0a43_f56b, - 0x8b9f_8656_4e83_0909, - 0x277f_0f45_b6ae_6203, - ]), - pallas::Base::from_raw([ - 0x546b_2865_f5cc_4c0e, - 0x8270_55d6_07bf_0010, - 0x3f7e_68bd_fe61_0371, - 0x1687_eb45_0f4d_7235, - ]), - ), - ( - pallas::Base::from_raw([ - 0x78a6_4eac_316d_2648, - 0x753e_2521_a67f_50aa, - 0x6e78_79a5_f11f_46fd, - 0x05d9_18ff_b1da_6eb7, - ]), - pallas::Base::from_raw([ - 0xbab9_5863_9bc9_3ae9, - 0xc37b_3f46_04cf_5755, - 0x7de4_ae79_9f29_d2df, - 0x047b_e1a6_060c_00a3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x49c8_71c2_61df_7cb6, - 0x5380_ca6c_e9ea_0b1a, - 0xd05a_4403_41b8_fe0e, - 0x080c_d18c_035f_3d1c, - ]), - pallas::Base::from_raw([ - 0x5274_e1b3_a894_244a, - 0xdedc_74af_a21e_7fb2, - 0xefb1_5f0d_99ee_54b4, - 0x164c_3262_4eb6_dbf6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x720a_ab53_d588_6877, - 0xceaa_5cf8_1671_dfae, - 0x6d4b_9e16_5405_52e7, - 0x1c6c_47fa_233f_06be, - ]), - pallas::Base::from_raw([ - 0x61f5_3c0a_f4a4_aa3f, - 0x5258_2334_b4f0_389a, - 0xc8a1_db30_50aa_f8fe, - 0x26dc_db34_c46c_475c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3208_2970_3840_3e89, - 0x90a1_593b_19f1_4fe3, - 0x09f3_ee71_e6d7_1be4, - 0x0e1f_8f25_134a_535e, - ]), - pallas::Base::from_raw([ - 0xd519_b8f9_b1ac_7612, - 0x91f7_850e_9074_5846, - 0x8846_3611_08cf_2b28, - 0x13ea_a62b_73e0_0d4c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4f39_a353_445a_c66f, - 0xb59d_a767_e1ba_84b7, - 0x3717_9c04_0954_afa8, - 0x2fcf_f236_d66a_b6d8, - ]), - pallas::Base::from_raw([ - 0x681a_f295_0d6a_597b, - 0x5642_9cae_6025_720a, - 0x8a44_998d_765c_574d, - 0x12ee_e67e_1017_6ed2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa310_66f1_af04_bfee, - 0x2537_ea36_fb79_6590, - 0xb3a7_25f6_64e1_75b9, - 0x0788_937e_9e35_d05e, - ]), - pallas::Base::from_raw([ - 0xb54e_df7e_8f9f_a0a2, - 0xe362_2000_9b73_a921, - 0xf8db_8c46_cd4f_aefb, - 0x2519_43ee_b590_deda, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa88e_2b82_de18_77cb, - 0x8b94_f5d7_e46c_d059, - 0x87a7_0381_3254_1fda, - 0x22b7_728f_f5f3_2e91, - ]), - pallas::Base::from_raw([ - 0x673d_7869_fa50_f997, - 0x9719_2499_f4d2_51a3, - 0x1c21_1da8_cfc7_b1d3, - 0x2bcb_9b60_77ac_9937, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa685_8e35_0e91_aeb6, - 0x97a5_6a16_423e_dae8, - 0xf9d3_8da2_28a0_0e54, - 0x1e9b_88fb_12aa_573a, - ]), - pallas::Base::from_raw([ - 0x9be1_63b7_2d0c_c322, - 0x6650_4cd4_3970_8ced, - 0xd3b1_ffca_c43e_ab37, - 0x1146_b28a_9f97_60fe, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdada_d29e_a8b1_8934, - 0x1250_940f_3606_539b, - 0xde2b_b139_6cf1_8876, - 0x11e8_cf63_9f28_6365, - ]), - pallas::Base::from_raw([ - 0x5015_5f8c_2102_5aa6, - 0xa1a1_d888_4567_1dfb, - 0x4927_0835_d236_0fb2, - 0x2753_5582_b996_b87b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8cc5_e492_e0b4_ca8f, - 0xb28f_29f7_b0c6_3c48, - 0x7e38_ef10_32a2_771e, - 0x3313_c543_e637_32ad, - ]), - pallas::Base::from_raw([ - 0x7669_4d57_eb2c_730c, - 0x0574_9ec0_b3f7_fe08, - 0x20a7_2453_e449_f1a4, - 0x2070_c656_4f60_8012, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7ec2_1a43_236a_004c, - 0xa075_0e43_5d13_56db, - 0xf3fe_38de_a0d9_767d, - 0x0337_f093_b562_0110, - ]), - pallas::Base::from_raw([ - 0x62ce_7184_7406_5d24, - 0x6bbb_c9a5_81d5_55af, - 0xfa2d_4ee6_6018_beea, - 0x280b_c654_e7e7_dca0, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb0e1_913d_b0c2_44fb, - 0xaaa4_d9c4_218e_5938, - 0x3546_9b6b_5fd6_28c6, - 0x2395_9107_43d3_b222, - ]), - pallas::Base::from_raw([ - 0x5caa_129b_4b4c_e99e, - 0xef45_ecaa_5313_85ec, - 0x9c0f_a2cc_c8c2_fb2b, - 0x189c_8131_f518_b80a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x032c_426c_b013_a4dd, - 0xe11b_5e5a_3317_d9a0, - 0x1492_b9fd_830d_3b80, - 0x05f1_9d94_cf5c_55d4, - ]), - pallas::Base::from_raw([ - 0x2c4c_4704_673d_d003, - 0xc48e_29af_97d8_8d07, - 0xd127_dd3d_91d8_53df, - 0x0d94_c052_f2d8_6405, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0281_7bc9_d4b9_3609, - 0xfd46_6a0d_2dd4_a592, - 0xd7bf_d5ad_053c_c494, - 0x3e23_096d_c906_06f6, - ]), - pallas::Base::from_raw([ - 0xca1b_a2ad_cf48_d0bb, - 0x4888_2a9e_e612_5ebd, - 0xa857_f300_33cd_faaa, - 0x0c0d_d8b5_2910_9f77, - ]), - ), - ( - pallas::Base::from_raw([ - 0x63aa_2c76_cd16_571b, - 0x6708_27ee_f35d_9eee, - 0xf732_370c_ed30_8f28, - 0x2ce7_690f_9c45_b228, - ]), - pallas::Base::from_raw([ - 0xcf08_8fe5_d2da_2200, - 0x6b75_35a5_3b79_5a4a, - 0x6cdd_78c6_35eb_3d58, - 0x088b_da57_e794_bed4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4f92_90f2_3582_04fa, - 0xbc25_9bd5_ce7a_6e0f, - 0xe944_7dba_fd99_596a, - 0x2151_a369_bbea_a627, - ]), - pallas::Base::from_raw([ - 0xc11e_3f08_4d99_83d1, - 0x3a2d_880e_3a7b_619b, - 0xa9ce_df46_75f2_11fc, - 0x153b_e140_8a41_79a8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x16b4_ed0b_32aa_4e15, - 0x5d02_9826_e003_163e, - 0xa674_90a0_12f9_fec2, - 0x13b1_0df3_13d4_e0de, - ]), - pallas::Base::from_raw([ - 0xfac3_5814_0dbf_6fc9, - 0x8d97_dbe3_f3dd_64d8, - 0xf604_80c5_b973_198e, - 0x0e44_6ba1_c4c7_30fe, - ]), - ), - ( - pallas::Base::from_raw([ - 0x53e5_02ce_d667_b3fc, - 0xbd6f_f292_2d35_b631, - 0x511e_7681_0c78_b289, - 0x35d9_b968_f2eb_c3a6, - ]), - pallas::Base::from_raw([ - 0x4b3b_f3a7_1759_3f8d, - 0x4820_7638_9976_7ebf, - 0x1549_6703_964e_4f60, - 0x153d_81a1_43f0_33f0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x31ba_52fc_3de5_ff01, - 0x376a_2b41_b9d1_ece2, - 0x62fc_8331_dce8_2da0, - 0x118f_5744_f6ac_a780, - ]), - pallas::Base::from_raw([ - 0xb1e6_df68_1ea7_f7a0, - 0x40ad_d363_1deb_f495, - 0x41bc_dabb_085f_cb8b, - 0x364f_f020_42c1_2247, - ]), - ), - ( - pallas::Base::from_raw([ - 0x36b4_1638_0c9e_d00e, - 0x51e0_bfdc_10a4_d1db, - 0x913c_5835_4ab5_aeab, - 0x0fab_7d64_6a29_1389, - ]), - pallas::Base::from_raw([ - 0x3321_18a5_c438_99ab, - 0xaf16_ef69_ec9a_ffa2, - 0xc1b2_59aa_af0b_d100, - 0x0575_6607_ef7c_7347, - ]), - ), - ( - pallas::Base::from_raw([ - 0x74e0_0818_faa1_9834, - 0xfb98_2b7c_6bed_60fd, - 0xdde3_235a_2ebd_4674, - 0x215a_5274_fda3_f4b6, - ]), - pallas::Base::from_raw([ - 0x106c_9783_c54d_cdce, - 0xe128_7246_1a71_5454, - 0xd4f3_6b85_c93a_1dc3, - 0x0c6e_92c5_d9f9_4b70, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1b65_d726_c0c0_4615, - 0xbf8b_e863_197b_7eda, - 0xaad7_e0b1_2452_bfd1, - 0x3511_415c_a5d8_9c89, - ]), - pallas::Base::from_raw([ - 0xd833_0a78_4996_6f63, - 0x30e1_6447_4b6b_f6d4, - 0xcaff_7c50_1359_107c, - 0x0952_ff5e_91f1_5c61, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0d03_79de_a34a_e974, - 0xcc94_561f_8673_d71a, - 0x131a_c0e3_d11b_fdbf, - 0x25f8_c019_6ac7_41d8, - ]), - pallas::Base::from_raw([ - 0xc14d_3404_894d_304e, - 0x1683_69a9_6ab3_16e9, - 0x3735_bc70_cd9c_eda8, - 0x37b4_443a_f523_48a5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9956_1c6e_192e_7568, - 0x65e7_be87_d79a_44a8, - 0xc477_1369_88f7_cfa5, - 0x2e08_d2d1_1f6a_f91f, - ]), - pallas::Base::from_raw([ - 0x8a16_6878_cf4d_afeb, - 0xabb3_04d6_e705_de6c, - 0x0859_c814_89dc_15a7, - 0x274d_0775_a079_b46f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdb3d_11a8_4fa8_eb13, - 0xea3a_7ea8_9ad3_d6af, - 0x9981_af35_3af1_4cae, - 0x2b38_c01e_7ae8_dfd9, - ]), - pallas::Base::from_raw([ - 0x830d_dec0_3c06_8077, - 0x422d_fa90_51e2_eb38, - 0xb8f7_0d0d_d10c_76bc, - 0x059f_5d67_0e51_88ac, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd910_97f8_e2bd_e10e, - 0x2f49_4c52_8f28_53a0, - 0x18ce_d481_b3ab_923b, - 0x25d9_e3db_a718_8482, - ]), - pallas::Base::from_raw([ - 0xd5a7_8005_ba95_0986, - 0xcaff_2367_d76d_2556, - 0xfd49_0e15_d2f5_1094, - 0x04ec_51a9_732e_c101, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9f75_b055_2d08_c237, - 0x8f7b_40f6_b94b_551f, - 0xff0a_1d65_6512_02d4, - 0x3259_3507_44ad_2a0e, - ]), - pallas::Base::from_raw([ - 0xc3b0_007b_5635_87fc, - 0x67fe_664c_1556_008b, - 0x3933_d14e_7c90_a14b, - 0x08dc_b066_37f5_9ef5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x66d6_5691_d7f4_6f1e, - 0x5774_25e4_a039_ed7a, - 0xfe27_c3f5_c7dd_098b, - 0x1daf_b77a_22f1_a231, - ]), - pallas::Base::from_raw([ - 0xa3bf_e610_9f9d_ac9b, - 0xa538_e6f2_5314_865c, - 0xd48c_5619_13f2_6135, - 0x267d_66bd_ebc3_5567, - ]), - ), - ( - pallas::Base::from_raw([ - 0x22c0_55b7_005a_fd9a, - 0xfbe9_5fb4_544d_dfc1, - 0x48d5_2641_43d1_c6cc, - 0x37c3_a72a_ea7a_3c08, - ]), - pallas::Base::from_raw([ - 0x77e1_afd5_eb2f_d2a4, - 0xbfcf_76bf_248c_529c, - 0x8589_07aa_9ffa_a44a, - 0x288a_b3ad_a23d_9811, - ]), - ), - ( - pallas::Base::from_raw([ - 0x847f_2f2e_b09a_a283, - 0x2874_cbee_5fec_a088, - 0x34d9_fc8d_9af2_8672, - 0x3e01_114f_d579_ff35, - ]), - pallas::Base::from_raw([ - 0x5504_d237_2254_c60b, - 0x8f8f_14cd_6ba7_b727, - 0x7539_9f3f_1180_d507, - 0x1977_5697_8320_c24b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x21d8_677d_a4ef_3754, - 0x970f_79ca_c4fe_71cc, - 0x9202_5638_93e7_a2f0, - 0x276c_3165_597d_8172, - ]), - pallas::Base::from_raw([ - 0xcddb_83d9_a9a1_4fee, - 0x05fa_2b1e_95df_ce2c, - 0xd58c_11ef_e1b6_7c84, - 0x01c7_cbc6_23e0_fde1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5dc4_11b7_be41_9bf8, - 0x6102_61de_71fd_509e, - 0x93df_5fe5_4b6f_15c1, - 0x2b17_a62a_ef55_fc8c, - ]), - pallas::Base::from_raw([ - 0x13e9_27e7_5428_fe43, - 0x3d07_6e3a_5358_d948, - 0x321d_9085_07a0_7394, - 0x2648_17bc_3f85_f5f9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xda55_668c_c5c9_544a, - 0x7dd5_42c2_06f1_4ae9, - 0xb88a_afeb_3d1c_ee22, - 0x1a12_25c2_42a6_d6dc, - ]), - pallas::Base::from_raw([ - 0xd8d8_02d6_7061_f4e7, - 0x1a21_e3e6_ed3e_e0e2, - 0xcbe5_9238_89e5_856b, - 0x0390_44ab_2e17_bd89, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3ae8_41df_e3b7_290b, - 0xf13f_ecde_fd80_6170, - 0xac39_a24e_4ce5_3f97, - 0x26ce_75c5_b2d5_e122, - ]), - pallas::Base::from_raw([ - 0xe473_f056_dc79_115d, - 0x76e3_15a5_ad62_0dae, - 0xa313_6c1e_483c_9721, - 0x3e6d_83ea_86d5_d926, - ]), - ), - ( - pallas::Base::from_raw([ - 0xae2f_741a_d983_16f1, - 0x382d_5858_cf9d_44bd, - 0x384e_98ab_f72d_0fbe, - 0x30f3_d34b_406d_3804, - ]), - pallas::Base::from_raw([ - 0xc245_5362_2247_8063, - 0x3e17_2608_60b4_bb4b, - 0xb86d_dafc_c500_27d6, - 0x2fe8_4841_5f29_2c18, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7b6a_1128_3c3c_80fa, - 0x9ca2_b9c2_dff3_f3b4, - 0x340f_f261_7ed1_3780, - 0x3e0c_e5ac_ec7d_2bec, - ]), - pallas::Base::from_raw([ - 0xd741_2e2b_3d37_fb89, - 0x6247_866a_c8b1_fed8, - 0x6f6b_0239_2805_590c, - 0x0ced_382c_9268_f3f4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf517_dcec_62e9_e3ab, - 0xef0f_7eeb_1b0c_6735, - 0x8b97_f27c_70f9_37cf, - 0x3b8f_7d37_f83c_eefc, - ]), - pallas::Base::from_raw([ - 0xc89c_a8e6_7126_cae0, - 0xbb34_8af9_7905_e208, - 0x454a_e56d_15e2_6ff5, - 0x1e45_8d1f_2c82_bdf4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8f21_d255_acaa_5b90, - 0xe729_e5a0_0840_e7fb, - 0x56c6_9b75_0b63_eb5d, - 0x1eaa_c9b9_4cc3_82f7, - ]), - pallas::Base::from_raw([ - 0xa370_d467_d4f0_adf4, - 0x5ec1_c5cf_197c_0be2, - 0xc1cf_51f4_f03f_6d42, - 0x09fb_0444_4edc_27ff, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb12c_0d2f_205c_31fe, - 0xeea6_f71c_6bfb_1591, - 0x67af_0a9c_f750_03b2, - 0x0398_bc66_1d37_47e7, - ]), - pallas::Base::from_raw([ - 0xcfcb_c59b_a71c_e886, - 0x13c5_dcea_abed_f8e3, - 0x94cc_f92b_e337_137f, - 0x0684_13f8_7199_260e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf82d_26f7_308d_982b, - 0xa463_f795_5164_d737, - 0x943b_0cdb_2a01_2793, - 0x36dc_43c7_d977_77d2, - ]), - pallas::Base::from_raw([ - 0x28d0_729c_c900_9cd4, - 0x95ce_751e_83b7_6438, - 0x7f75_8d0c_1ee4_d82f, - 0x0484_975c_8703_23b2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x573b_6407_c295_bc03, - 0x3d81_4362_3653_b276, - 0x715a_5538_1619_6299, - 0x1a2d_544c_2924_13dd, - ]), - pallas::Base::from_raw([ - 0x35eb_0d37_a82a_ebb9, - 0xc43b_bf74_7668_ff2b, - 0xb086_e27f_cabe_e36f, - 0x2aa3_498b_0d5e_e868, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbdc2_bfad_362e_4e45, - 0xe6a5_1dc4_a99d_9290, - 0x7a7b_06f1_60f6_7d5d, - 0x19cd_8877_65a7_d9d8, - ]), - pallas::Base::from_raw([ - 0x8d51_6305_64ff_936f, - 0xfadb_c64d_5013_97ef, - 0xc69f_7c0f_10e4_e5bc, - 0x2d2a_dbea_d1b6_989d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x583a_b4b1_cd55_7263, - 0xaae4_f810_312f_8c56, - 0x2f23_2a1d_07d9_df4d, - 0x2fba_b5a3_c4c6_773a, - ]), - pallas::Base::from_raw([ - 0x73e5_4412_d35d_bef2, - 0x3ece_87a1_67ec_e5a8, - 0x9223_f63f_59e9_6781, - 0x0ee5_e010_f598_055d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2969_6dcf_d0f2_45a4, - 0x8277_fcbf_73c3_66a0, - 0x6841_c274_1f99_74cf, - 0x3709_2e4c_18e6_289b, - ]), - pallas::Base::from_raw([ - 0x838f_2b53_2d37_f282, - 0x81dd_5e60_c4b0_6016, - 0xfc7c_b034_4511_4e5d, - 0x32ff_9c63_4da9_341f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9ff0_ae31_0044_5d6d, - 0x7cd8_e22c_968c_f64e, - 0x6ec7_7099_fd3f_bc2d, - 0x03ed_d409_4ace_757a, - ]), - pallas::Base::from_raw([ - 0xb949_d0f4_aa7d_daab, - 0x9579_75a6_e421_ce51, - 0xe387_f7c9_68d4_199a, - 0x1076_83d8_acc2_378c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7c36_ca16_0d02_f992, - 0xb3c4_7744_bd2a_cf1b, - 0xd4fa_877a_2a8e_237d, - 0x1394_a3da_f7c5_819a, - ]), - pallas::Base::from_raw([ - 0xb613_5e52_1b63_455a, - 0x4bf9_1fa0_ac38_e15a, - 0x81d9_9f64_1be8_55b6, - 0x2224_1b8b_d75d_1421, - ]), - ), - ( - pallas::Base::from_raw([ - 0xceb4_5f69_b989_fe1b, - 0xb7e7_93ed_c797_8d45, - 0x3b07_5a63_4103_0c39, - 0x2d76_b68f_6c00_d2e6, - ]), - pallas::Base::from_raw([ - 0x3ac8_1f11_ce1f_0c3e, - 0x5065_af29_2ab5_050c, - 0x8ac1_305a_a9ba_43f1, - 0x1697_81ba_e7d9_3067, - ]), - ), - ( - pallas::Base::from_raw([ - 0x20fe_f089_d835_a48f, - 0xcb23_7766_d607_2a64, - 0x18ef_0b57_dd7c_3b7c, - 0x1a3d_5f57_8f57_a4a0, - ]), - pallas::Base::from_raw([ - 0x2574_2597_3e32_c989, - 0xde95_cb1a_38b5_9aee, - 0x5e69_c45a_328e_ae08, - 0x12fa_3870_5145_9017, - ]), - ), - ( - pallas::Base::from_raw([ - 0x54cc_b71d_b115_00f3, - 0xeae2_7b08_c955_4e07, - 0xd7ac_a091_6e33_815d, - 0x0924_e273_11dd_a853, - ]), - pallas::Base::from_raw([ - 0x6d61_f93c_cce9_942a, - 0x2d9e_5dd1_7e83_e833, - 0x8410_7aea_6d67_f750, - 0x3cbe_6e62_757c_a1a5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7496_11d0_b797_7376, - 0x91ee_1646_4ccd_ec34, - 0xa71a_ee11_a82a_121a, - 0x0b9f_4bbf_d185_de95, - ]), - pallas::Base::from_raw([ - 0xd157_72cc_ea7e_a26d, - 0xd171_58db_8708_6d27, - 0x6093_1fae_1eea_2b4d, - 0x34dc_4613_b828_dd99, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1fbd_03d8_1ee5_f96f, - 0x371c_9782_b691_077a, - 0xf52d_f5a7_19bf_5ce5, - 0x02d6_cab2_451d_9d53, - ]), - pallas::Base::from_raw([ - 0x19b8_5371_5e90_f9c3, - 0x6e1e_109e_62b7_e02b, - 0x4302_b72c_1d4a_5b35, - 0x10b0_be6d_e221_46f8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x24cf_34c7_81aa_7322, - 0x3247_bd2e_b1c4_5ee3, - 0xf9ae_4378_0413_ea39, - 0x0d16_dcb8_7865_78a6, - ]), - pallas::Base::from_raw([ - 0x9d41_e502_3ba7_b1c8, - 0xfe5e_2c86_fc66_1a81, - 0xe729_c0d6_427e_0fc3, - 0x05f3_05ca_4971_05cb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1afa_a868_252f_7b9d, - 0x9e19_617b_52e9_b42c, - 0xd5f4_449d_e9e3_f183, - 0x322a_0e11_63ce_20e8, - ]), - pallas::Base::from_raw([ - 0xb391_cb0a_6351_bf73, - 0x610b_1f7b_4f5a_6acd, - 0x3a76_9f31_cd20_aa26, - 0x3ce3_28a2_561b_bf67, - ]), - ), - ( - pallas::Base::from_raw([ - 0x30c7_9e39_fd40_3fb2, - 0x1d82_1256_916f_f504, - 0xfe73_efde_65d6_2b6b, - 0x2994_4742_c6a3_4de2, - ]), - pallas::Base::from_raw([ - 0xaa6e_9941_b2a5_4d17, - 0x50e2_4496_1b34_d4ca, - 0x6b06_42c4_a199_cb45, - 0x01f3_609d_eefd_a00c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4bab_06a5_e077_4a9e, - 0xa330_3b42_52bd_5399, - 0x4bb4_1f7b_e729_9520, - 0x3e21_edef_d0eb_fab4, - ]), - pallas::Base::from_raw([ - 0x464c_145f_cb64_99e5, - 0xdf35_61b7_1aca_4810, - 0x04bc_58fc_3756_5635, - 0x1c58_279a_6bbf_5750, - ]), - ), - ( - pallas::Base::from_raw([ - 0x99f4_f0fe_9dc0_ca44, - 0x02fb_d682_b042_1702, - 0x2efe_f131_2968_d890, - 0x15e2_222e_6db1_4410, - ]), - pallas::Base::from_raw([ - 0x67a0_83e2_c99a_0667, - 0x23ab_d14a_6bd2_87fb, - 0xabdd_eb1e_2a5d_fdb0, - 0x0b60_960a_be90_667e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc740_684e_ba5a_4faf, - 0x4c22_ce95_137c_c36c, - 0x281a_a42b_c45a_2b1a, - 0x376b_146b_97e0_9a59, - ]), - pallas::Base::from_raw([ - 0xc4ef_bdb0_982a_e289, - 0xf554_a7b6_564c_83fc, - 0x8a67_d20f_be31_f8df, - 0x2c37_9f03_4178_6df6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2ab6_2fa8_4b1f_8e4f, - 0x5604_7652_51e0_d7d4, - 0x861d_2eb4_6261_0b9b, - 0x31c4_e0bd_450e_6e50, - ]), - pallas::Base::from_raw([ - 0xd8d3_3e9e_f72a_be1e, - 0xb803_ee7b_7f4a_6cef, - 0x9a3c_b438_0c39_4da6, - 0x1228_8e27_13b3_b5f0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1d8c_119e_1fea_0f3e, - 0xcf48_8423_afc0_a753, - 0x0b6e_dc85_421d_1af4, - 0x261f_f1dd_ff1f_5d8e, - ]), - pallas::Base::from_raw([ - 0x0199_5750_d19e_6caa, - 0xad1d_82df_b749_8ed4, - 0x247b_d709_b691_31b7, - 0x2539_b879_15a5_f780, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7589_fb80_f8e8_939a, - 0x9ebd_0810_d45a_bccd, - 0xfdba_79ca_0ccc_9b44, - 0x1aa0_1aea_8f5d_c980, - ]), - pallas::Base::from_raw([ - 0xa555_fa27_6b83_e30b, - 0x578f_1dd3_8ca4_8a1b, - 0x1df7_d102_f86b_370d, - 0x394a_4663_4e33_5391, - ]), - ), - ( - pallas::Base::from_raw([ - 0x20a6_ffb4_b2a0_6005, - 0x92eb_8f71_fb24_c4e2, - 0xaa8d_0967_96f7_84f8, - 0x16e3_1607_8d0e_330d, - ]), - pallas::Base::from_raw([ - 0xdd44_1a60_d432_5070, - 0x4b11_771a_1b21_7b5b, - 0xcd9b_504e_26da_2f48, - 0x300a_ebe3_2a72_477e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x744f_4c87_d1d4_508c, - 0xb3ec_6058_d948_a573, - 0xc4cc_b479_43b9_9fea, - 0x292e_928f_7ceb_3ff2, - ]), - pallas::Base::from_raw([ - 0x87ce_4476_03d0_27ad, - 0x9bb9_90ca_e688_0b20, - 0xc92d_41da_e465_745a, - 0x0223_81f5_2d29_279c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0762_3807_30d6_1de3, - 0x1edd_e3f3_3771_cc05, - 0x1b7f_051c_c2b6_4ab3, - 0x0453_ef02_8a0a_0e93, - ]), - pallas::Base::from_raw([ - 0x4af4_208c_5106_b83f, - 0xa12f_0bb8_1911_e9b2, - 0x8d23_55e3_13ca_6284, - 0x199a_c626_77dd_e42d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa5d5_078b_65a5_31cb, - 0xd6d4_d396_40a8_dead, - 0x7395_10a3_2e84_194a, - 0x0746_7e7f_2d24_b2da, - ]), - pallas::Base::from_raw([ - 0x2aca_d55d_1851_65e5, - 0x0fb2_146a_77c9_c7ad, - 0x4a21_f9c7_5a25_793d, - 0x051f_b653_7e5c_669a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5c77_2c3e_2739_e3fc, - 0xfef3_5127_c5dc_20fd, - 0x93d1_092b_43f0_b004, - 0x3610_1ab4_3a30_2e81, - ]), - pallas::Base::from_raw([ - 0xa206_2c8a_6927_2961, - 0x95ae_1eda_33fe_553c, - 0x0c55_8ed6_13c3_1d9f, - 0x2679_b3ad_0bb1_f518, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4c99_4a2d_9356_6587, - 0xdeeb_0d82_95d1_2d60, - 0xe1c2_2593_45ec_8dc4, - 0x2a35_d2f2_3772_88eb, - ]), - pallas::Base::from_raw([ - 0xdd98_203f_af9d_ee4d, - 0x5c66_2c8c_c521_19b8, - 0xa63e_cdcb_8480_514e, - 0x18da_f4d5_332a_1baa, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd84c_d0ad_ccfa_70c3, - 0x007c_d209_cc31_09a0, - 0x78ed_585e_3225_fa0f, - 0x039e_aa43_428a_bea0, - ]), - pallas::Base::from_raw([ - 0xb8f7_04f9_aa61_c65c, - 0xb502_1eee_d781_1fd1, - 0x5e3a_d1e1_0641_c3b6, - 0x286d_2d99_97fb_09c8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2f16_78b3_f543_9c73, - 0x9f1b_1cdd_d30a_111b, - 0x1601_479f_9b32_834d, - 0x17c1_c1b6_9420_721b, - ]), - pallas::Base::from_raw([ - 0x5b68_0b72_90c2_201a, - 0xf9f9_cb4d_b01a_bc23, - 0x1d4e_6bd4_f26a_e504, - 0x389d_e069_5988_822f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb1cc_a546_a26c_bd86, - 0xd581_36f0_8d48_7530, - 0xc022_5c61_93c4_2f07, - 0x3900_59d2_1cdc_6bd4, - ]), - pallas::Base::from_raw([ - 0x6b0c_72de_318e_22d4, - 0xc25b_9e3a_542f_b6b6, - 0xa7a8_06e6_da9f_7440, - 0x3c2a_71ce_4326_8d4d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x50e1_11a2_0489_f122, - 0x07db_1ada_fd5f_8ecb, - 0xf6a6_51ee_1f90_02b9, - 0x25dc_8f85_41ca_57ca, - ]), - pallas::Base::from_raw([ - 0x8241_e6e0_c4ed_eedc, - 0xe1db_5a05_57a0_5392, - 0x4b07_d4a1_6ee5_32a3, - 0x1d1a_0c97_70ed_f432, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb26b_68f6_0086_71f4, - 0x75db_a00b_0b9e_4307, - 0xd9a7_65b7_c82f_711f, - 0x2765_f4c0_27cb_e853, - ]), - pallas::Base::from_raw([ - 0xb2a7_d024_e97a_b65b, - 0x1df5_ee26_7727_2a6d, - 0x6c0e_4551_c789_273d, - 0x27a1_7d99_2875_639d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdb10_fcfe_4260_d68d, - 0x7154_7c95_a7be_2663, - 0x1258_286a_d0ce_a1a3, - 0x27df_52ac_88e9_47ea, - ]), - pallas::Base::from_raw([ - 0x3d4e_5b53_00c3_0fb7, - 0x93f6_bee4_3688_6e32, - 0xbce4_cf1c_bdd9_555d, - 0x2046_32cf_c355_10e2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8b7c_28f8_d7ec_c2a6, - 0x3484_bab7_04d2_2a17, - 0x68eb_5538_e6d8_bfcd, - 0x0408_8d25_0509_fd2f, - ]), - pallas::Base::from_raw([ - 0x57f8_018e_752e_b908, - 0xc709_94e2_3360_b3e9, - 0x31b5_e0c5_969a_1364, - 0x241d_3b9c_b64c_1c51, - ]), - ), - ( - pallas::Base::from_raw([ - 0x070f_a907_6332_8b37, - 0x80b7_7fc9_f7d1_454e, - 0xa851_ba95_b01c_9b9f, - 0x104f_1754_7220_df3c, - ]), - pallas::Base::from_raw([ - 0x7dc8_7e53_05e7_19fb, - 0x338f_f6d5_fbd5_8b87, - 0xf8c5_e720_14f7_325f, - 0x0309_fefc_0c51_fe88, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb33e_8147_9cf8_1580, - 0x3d43_f778_431a_39d8, - 0xca34_2567_f8af_16d1, - 0x3113_430a_214b_0cdb, - ]), - pallas::Base::from_raw([ - 0x13c9_5973_0b4f_4399, - 0xe534_1a6e_c65c_a2b0, - 0xcb52_a623_3314_e4d3, - 0x2ced_c552_f9fc_da21, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe2f2_d321_bc0b_2ca7, - 0xb252_6d8b_b9f2_415b, - 0xbf60_2a8f_52fe_1001, - 0x3d68_f289_95eb_8ebc, - ]), - pallas::Base::from_raw([ - 0x15bc_988c_f260_e0ae, - 0xd3fe_7253_a715_73b4, - 0x5d6e_a086_5a30_55b9, - 0x08ef_9afd_ec67_40fe, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4fa6_d6c3_91be_c514, - 0xb5a8_3229_b864_ecb8, - 0x3559_3f27_4198_2167, - 0x1402_abd3_64b4_91e4, - ]), - pallas::Base::from_raw([ - 0xad4f_91b5_5f82_9cbf, - 0x6078_24ce_bd17_46c1, - 0x8941_5aad_ad35_5caf, - 0x1e1d_54b1_8e31_aa02, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf268_ffe3_ff17_92f0, - 0xd30d_826d_c124_7ab7, - 0xd835_dea8_0451_546a, - 0x07f3_787f_5b1b_6728, - ]), - pallas::Base::from_raw([ - 0x06be_7c30_22da_5b48, - 0x6119_b0af_e57e_eece, - 0xffb2_ef93_3bd0_ebed, - 0x0169_f72c_db1b_2fcb, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe456_2834_294b_888d, - 0xbcfd_513b_64f2_5684, - 0xf08e_b8fb_c4ab_d423, - 0x0fb6_00e3_c86b_b49f, - ]), - pallas::Base::from_raw([ - 0xe7bc_fc0e_3b3f_f8de, - 0xbea6_5eea_f9ae_d71e, - 0x70df_ec85_cd8a_1b58, - 0x19f6_5367_896c_d8a6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x34fa_bfcf_3c22_1b33, - 0x044b_883c_d5c6_097b, - 0xbfb0_715a_00cc_0c7c, - 0x0679_54d0_2044_c9f5, - ]), - pallas::Base::from_raw([ - 0xd919_1bda_61df_8d07, - 0x6d2a_a446_a685_4475, - 0x92bc_bfbb_a58a_db13, - 0x065a_ecfb_ba1c_4f39, - ]), - ), - ( - pallas::Base::from_raw([ - 0x86c3_eb48_7c88_bd57, - 0xdb8b_d4d0_11d2_f88e, - 0xfad8_69ea_a7e4_4dcf, - 0x3022_30ed_6e9c_6e28, - ]), - pallas::Base::from_raw([ - 0x0fbe_eda5_bba2_91f6, - 0x92ea_6a64_ab91_359a, - 0x2e65_7270_4b8b_8373, - 0x30fd_7673_e584_02f4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xea84_2eab_a955_bf3a, - 0xa20d_8ca2_651d_19b9, - 0xab2e_3150_8ceb_fb7a, - 0x3aca_f491_8373_e853, - ]), - pallas::Base::from_raw([ - 0x44ca_a4f6_92ec_ca97, - 0x2b2e_4b9a_22ac_d3d3, - 0xbc30_279e_ff7b_e6aa, - 0x3b91_6c71_845b_1715, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1202_b03b_21d1_d047, - 0x03ae_5752_aa54_b5be, - 0xc925_4108_2eaf_2a3c, - 0x13ad_e51c_5d29_0b7a, - ]), - pallas::Base::from_raw([ - 0x8041_8cdc_5c36_974c, - 0xd604_0473_1a81_c29f, - 0x23a2_ba06_9389_1b6d, - 0x266f_9adc_4b16_36a1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9afd_aa5e_40ca_0c02, - 0xa358_984d_a414_8a51, - 0xacd4_cc7c_9942_0f78, - 0x2187_c185_232c_318b, - ]), - pallas::Base::from_raw([ - 0x8a81_3d5d_499f_4580, - 0xa513_113e_dfa2_d826, - 0xeb8d_fef7_f22d_f466, - 0x2031_fd3b_4359_99d0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x038e_6561_3318_309a, - 0xfbbc_cc98_6867_1618, - 0xc078_f45f_0b90_87ed, - 0x30f2_e8ef_849c_bdbb, - ]), - pallas::Base::from_raw([ - 0xa36b_5a01_49ef_da91, - 0x7a95_de96_1b20_9374, - 0xecca_06aa_0f3b_5ab8, - 0x31dd_63b8_64cb_de15, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4796_b297_f98e_93b3, - 0xf493_b341_1ed9_021e, - 0x1959_49f0_5a11_c922, - 0x35c5_a032_4cc5_8786, - ]), - pallas::Base::from_raw([ - 0xfe71_cea7_2663_1804, - 0x3b35_545d_e5bb_07ed, - 0x1e0c_8c02_6408_9be0, - 0x24b2_4b27_139e_827e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf33d_521e_4818_701b, - 0x0ed0_6b9b_4fb1_12eb, - 0xd38d_f6b1_d568_5738, - 0x2f83_54a3_e364_1f2d, - ]), - pallas::Base::from_raw([ - 0x2f57_b58b_8e5d_489c, - 0x88b1_ab17_4dc3_61c5, - 0xfffe_6160_1707_a091, - 0x0797_75d9_3fd9_4026, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7d09_4b08_9f06_34e0, - 0x3260_4273_2097_b4f3, - 0x2d95_5d56_8f05_4ae3, - 0x2094_83e1_a0b0_a837, - ]), - pallas::Base::from_raw([ - 0x7432_cb32_c68b_2165, - 0x7bd9_2165_7fb0_2d3f, - 0x0f8e_cd9e_6143_ed8a, - 0x1e80_5fa9_b94a_ec49, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5113_896c_8344_ca04, - 0x3ef8_8140_14dc_b062, - 0x4412_402a_64e3_8636, - 0x2ca2_c0ca_7fdf_3aab, - ]), - pallas::Base::from_raw([ - 0xaed4_11b6_dd39_334e, - 0xacbf_64e8_3c88_59f5, - 0xc68a_900f_bbf1_8b0f, - 0x35c2_a197_59b7_ad1c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3d3e_18af_68d8_62fa, - 0xe3d5_0649_7f05_6b13, - 0x4e45_faad_be7b_7fd3, - 0x1859_da3e_20cd_e957, - ]), - pallas::Base::from_raw([ - 0x645d_a090_f36a_e749, - 0xd41d_b3b2_a046_2af1, - 0xa96d_2c5e_6597_3c58, - 0x141e_1418_8f51_e0d0, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdabb_00be_7a67_fef0, - 0x5c7b_cf1c_6ad7_edda, - 0x936c_f456_316c_55a1, - 0x0d3a_6bba_e167_7f06, - ]), - pallas::Base::from_raw([ - 0xd39b_8075_0060_baa3, - 0xe8e3_40fa_3051_61af, - 0x195d_c44b_0585_652d, - 0x00d3_796b_0ba9_07d1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0f72_b95e_c033_1d81, - 0xc509_70b4_8e36_3af0, - 0x8d67_3023_a716_fcc4, - 0x012d_485d_fb24_6814, - ]), - pallas::Base::from_raw([ - 0xed91_6bb8_2624_17de, - 0x426d_028d_0170_49d3, - 0x398f_1550_b9e3_0d8c, - 0x0918_c246_acb5_fdee, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1293_b9c9_0725_4044, - 0x4088_0cdf_1a2f_acdc, - 0x4de3_cd80_f405_03be, - 0x21c9_dc8c_e021_5c1d, - ]), - pallas::Base::from_raw([ - 0x2a0b_32e0_23d9_a3bb, - 0x8dfd_3300_2c4d_a85d, - 0x90fa_fa54_eadc_032c, - 0x2b22_e6b4_d976_bb94, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7f67_fb22_3643_6df5, - 0x8cb7_a940_6905_bff4, - 0x0700_85c6_481f_f20a, - 0x2c67_6bf1_c4b8_6158, - ]), - pallas::Base::from_raw([ - 0x7cf1_8c00_4a9c_1a9e, - 0xf931_e68f_a15f_b06c, - 0x4b5a_0021_677e_9587, - 0x2fb0_f64a_a35e_6c60, - ]), - ), - ( - pallas::Base::from_raw([ - 0x980c_1135_0270_595f, - 0xda07_a0c2_5480_8a60, - 0xb0aa_67e1_dd15_8881, - 0x2075_e446_9ffc_c6fb, - ]), - pallas::Base::from_raw([ - 0x44d0_d6f6_aa0a_1932, - 0x862b_52b6_f304_e01b, - 0x690d_6e48_b517_135e, - 0x22e5_932c_6392_e33f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf261_d24d_d55e_fa46, - 0xe3a2_8ce1_2ece_2d1d, - 0xb6c3_ed0f_5de4_1a3c, - 0x1cb0_da91_1a87_cfa0, - ]), - pallas::Base::from_raw([ - 0x5442_5655_5336_1f42, - 0x089b_c245_a048_38f5, - 0x8dcc_4e66_7941_5a9e, - 0x34c6_80fb_1dd7_661b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2d65_9072_d56e_5b18, - 0x7987_24b4_22bd_dbf3, - 0xa346_5bd1_1778_6f23, - 0x3961_400e_4b13_e385, - ]), - pallas::Base::from_raw([ - 0xfd5e_6292_aed2_5d3c, - 0x4875_16bc_b3cb_783f, - 0x8e9f_fe18_293c_5856, - 0x257e_cda9_99c3_d0cf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8313_e47e_aa56_0f12, - 0xa288_d1ce_19d0_c1ce, - 0x0de7_47c8_24b5_d9ce, - 0x1ef9_17f6_6050_f9b8, - ]), - pallas::Base::from_raw([ - 0x51b3_c417_aae3_d512, - 0x308c_26cb_3ef9_b520, - 0x9e24_fee2_0510_c124, - 0x10c4_5920_4a45_09fa, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5354_70f6_26b1_1d0b, - 0x366e_2b98_c3f8_51b4, - 0xc02a_1aef_b019_705e, - 0x0ef2_f878_dec4_3a29, - ]), - pallas::Base::from_raw([ - 0xbbe1_eafd_c8f8_d6fb, - 0xba82_354a_c062_0fc1, - 0x4984_289a_d39b_917c, - 0x32b0_046e_bbd5_1e14, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe5af_e709_3216_cf73, - 0xce7c_ea62_2592_e580, - 0x073b_be3d_9d7b_463d, - 0x0205_976f_e9c1_b9d7, - ]), - pallas::Base::from_raw([ - 0x1eef_2946_b9ab_16dc, - 0x5513_ea0e_5cab_a5c4, - 0x0174_f38f_88f9_1425, - 0x16b7_f6c6_6548_4de9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x07cb_2e9c_7762_5c85, - 0x33f6_d324_7351_1aec, - 0xf7f0_ac0e_f1f1_e7ae, - 0x3e3f_c594_4e97_90ef, - ]), - pallas::Base::from_raw([ - 0xf286_21ff_e28c_23ad, - 0x44e4_45d2_2eb5_fae6, - 0xddc6_91ad_5bdf_57f0, - 0x36bf_156f_395d_dca9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd524_a165_4426_7d9a, - 0x1f66_2e96_84b2_aeab, - 0x2c89_6845_13b1_47ef, - 0x38c9_c6de_31d0_54f1, - ]), - pallas::Base::from_raw([ - 0x05ac_032b_5a68_e21d, - 0x13bb_ddc0_606c_20ab, - 0x3026_8ada_227c_8b3a, - 0x2d5b_3fbe_7b71_ff46, - ]), - ), - ( - pallas::Base::from_raw([ - 0x11b6_85e3_842e_c92b, - 0x9944_f4db_a624_498b, - 0x9fc0_d641_b040_6a97, - 0x1647_4f51_124c_377f, - ]), - pallas::Base::from_raw([ - 0x1168_60f3_af34_2dae, - 0x7805_c248_f3c3_fcc5, - 0x4813_d152_d1d3_098a, - 0x208f_c6df_823b_e5f9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc169_7a99_835e_be3e, - 0x5ef1_b7bb_3199_1aca, - 0x423b_d93b_fab8_c937, - 0x2967_35a3_0418_0bdd, - ]), - pallas::Base::from_raw([ - 0xbdb7_c009_07a2_d1da, - 0x368c_8c5b_b543_e0a1, - 0xc213_9520_868c_748e, - 0x0f8a_171f_46c2_fe7c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6adb_fb16_aac0_e0c1, - 0xe670_9f7f_a329_f25c, - 0x0345_3350_36cd_ada1, - 0x067c_220e_1a5d_efb7, - ]), - pallas::Base::from_raw([ - 0xeffb_7a08_1fd4_52ca, - 0x91c5_539e_3995_fa41, - 0x949f_e270_b209_2bc2, - 0x0c94_eb80_956c_63f5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x76ce_f08f_c4b9_3ce9, - 0xcd65_00bb_d889_d19b, - 0xcb76_bc91_e514_c0ba, - 0x2676_b3ed_f17f_cc35, - ]), - pallas::Base::from_raw([ - 0xa6ee_7cfc_440d_3bb1, - 0xf9f0_fa37_559f_b568, - 0x5c75_9922_987b_e0fd, - 0x18ba_9b25_9fb9_1ecc, - ]), - ), - ( - pallas::Base::from_raw([ - 0x88aa_9070_b7aa_f1e5, - 0xed19_124a_2b33_bb67, - 0xe56e_e569_c5d2_f813, - 0x3c6d_3d48_689c_6545, - ]), - pallas::Base::from_raw([ - 0x2dd3_3c98_6d92_2737, - 0x4a38_67c9_cc68_d3c5, - 0x0dd8_104b_2350_8489, - 0x1220_a703_5129_d555, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf34f_b7dc_c29e_e3f6, - 0x68ff_419f_787f_d6b4, - 0xe113_6044_b650_fd24, - 0x0f07_bb4e_3f0a_06bb, - ]), - pallas::Base::from_raw([ - 0xaf2f_3c9b_30d6_4868, - 0xb876_d0bd_eebc_8d41, - 0xd5e1_cfea_a531_971d, - 0x049f_733f_9545_e7b0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0730_f7ca_1dba_2634, - 0x229c_c86c_ac49_a95d, - 0x299f_5487_67f0_5bff, - 0x1ff0_6c6f_bbc9_7265, - ]), - pallas::Base::from_raw([ - 0x42d4_85b3_c343_fb9e, - 0xa6a0_b509_d7f4_32ed, - 0xea60_7525_3e54_c341, - 0x2c00_143d_8e9b_261e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8fda_58ae_2efc_f247, - 0xee35_0022_54f7_e10e, - 0x736e_f067_a1d8_6854, - 0x171b_73f6_f381_7bdb, - ]), - pallas::Base::from_raw([ - 0xc34f_b482_2878_1165, - 0xf1a5_16af_a161_fc8f, - 0x98c7_8cbd_6d9f_f721, - 0x3b38_7dd3_b99f_11c1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf52c_8ddc_ff5b_01c2, - 0x523d_70df_bd93_ca28, - 0x9c29_d3a5_c4c1_3774, - 0x31cd_fecb_38de_73c3, - ]), - pallas::Base::from_raw([ - 0xc68c_3f28_26b1_9cb8, - 0xfa8b_7593_0610_fe60, - 0xdef2_d495_2f51_9984, - 0x2221_6cb6_ddad_b185, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6bed_8edf_f3c0_d24e, - 0x99ef_37b9_cdba_a0d4, - 0xaf57_7449_65fd_54db, - 0x2704_ec4e_2419_ca44, - ]), - pallas::Base::from_raw([ - 0x8cdf_2bd0_b67e_b1c2, - 0x58f8_a33d_b426_e86b, - 0x653b_af62_fe66_967f, - 0x2326_7f58_4dce_4708, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6312_f284_adb7_2234, - 0x774f_0aa2_fa1c_ab96, - 0x7b2f_4ce7_137c_5695, - 0x0864_b203_83da_e0d2, - ]), - pallas::Base::from_raw([ - 0x731d_3ed1_53fe_b76c, - 0xcaf0_32bc_d5c9_4c3e, - 0xc4b6_0b28_83b2_aac6, - 0x2125_d63c_b9cf_c0b5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x53e9_3f17_a1d9_9759, - 0x5bbd_c73e_e01b_a020, - 0xacf7_bba6_f9d3_2f75, - 0x1952_c1c8_1635_6a75, - ]), - pallas::Base::from_raw([ - 0x66ec_f0b6_1af3_d4e0, - 0x571c_0924_ed6e_1a90, - 0x7705_b5de_1fc0_14c0, - 0x1fd7_5a22_f673_ea80, - ]), - ), - ( - pallas::Base::from_raw([ - 0x51e1_ea40_8c91_aad6, - 0x9db3_dc4a_6dd7_5da3, - 0x565d_5a06_e81f_9a96, - 0x0b2a_fb0f_ed99_5390, - ]), - pallas::Base::from_raw([ - 0xcb85_e6f7_24eb_eaa3, - 0x0ae7_3db8_9527_b9dc, - 0xcbe3_28e1_951c_7a68, - 0x2e2f_ae1a_239e_1571, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf958_eaa2_64c1_89d5, - 0xfd66_b7d1_121c_4ff7, - 0x34b3_6c0c_e96d_541b, - 0x0e73_8609_6c3b_0025, - ]), - pallas::Base::from_raw([ - 0x2cbd_19de_7f3b_b8ec, - 0x049d_9874_0dc9_177f, - 0xdc76_e494_dc8b_6c50, - 0x3c16_ea6c_a968_ab1a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x915a_adcc_89b7_daf3, - 0x2909_ff1c_0e1f_9785, - 0xd5bd_a128_019a_7ef2, - 0x3d37_fb8f_9eea_8d51, - ]), - pallas::Base::from_raw([ - 0x09be_e328_a080_f138, - 0xe673_5890_07fe_2120, - 0x2113_15e1_5d7c_9110, - 0x190f_69f4_eefd_5477, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9887_d028_c814_459b, - 0x0bfe_9714_c977_9a7d, - 0x09bc_a123_a070_2c37, - 0x2ab5_d63f_55f9_33ef, - ]), - pallas::Base::from_raw([ - 0x7704_3175_669a_cbaa, - 0xd2d9_3256_279c_aaaf, - 0x163b_f414_992e_0d03, - 0x2dd3_ad25_0723_378a, - ]), - ), - ( - pallas::Base::from_raw([ - 0xaa70_af4d_2c62_1ee1, - 0x82bf_76f9_a44f_e16a, - 0xd823_dfb3_28e9_1bf4, - 0x0e2e_86a7_8fef_50ce, - ]), - pallas::Base::from_raw([ - 0x96df_97dd_95e6_9e90, - 0xa340_7d75_e959_bcd6, - 0x8806_08c5_d89f_9255, - 0x2de3_b3e1_6dc1_2b33, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0c96_2934_58ec_b2cb, - 0x0d7d_864d_7d1e_560e, - 0xec28_d3a6_3cdd_c555, - 0x0de0_eb00_0263_741a, - ]), - pallas::Base::from_raw([ - 0x1cc8_207d_937b_6f0e, - 0x9797_e7ee_dc7e_c8c6, - 0x2286_088a_e441_e77a, - 0x242f_4811_c54f_c5a4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x02e6_08b8_b421_3091, - 0x04f9_d82c_26af_83fb, - 0x4d9c_e544_ba2f_2525, - 0x3f8e_e248_4851_a53b, - ]), - pallas::Base::from_raw([ - 0x9dac_0a3c_f93d_2ab4, - 0x7ed7_5569_f31b_ed67, - 0xb530_b73f_14e7_8731, - 0x320a_6858_c7ef_b1d8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf1c7_9c73_c18c_5bef, - 0xb4dc_fb27_be5d_af33, - 0x00fb_3437_a413_9ab8, - 0x27a9_6926_feb8_4658, - ]), - pallas::Base::from_raw([ - 0xf94f_9504_a805_5901, - 0xd816_70b5_5f8c_c186, - 0xd80a_41c9_3fca_d44c, - 0x35fb_6dfa_6996_faf9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbad4_1cc8_8afd_dd08, - 0x49d2_bda3_3181_eb27, - 0x6bd9_a42e_e764_f287, - 0x1bf9_7fbc_aad6_3dd3, - ]), - pallas::Base::from_raw([ - 0x9e70_14b6_b93f_3479, - 0x2ecd_3acc_85d9_0a8e, - 0x9adc_da24_387e_73bf, - 0x1e46_208e_ee13_e6a1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbefc_4b37_32e2_12e7, - 0x7994_0a4e_1943_82c7, - 0x31b5_2141_ba54_76cb, - 0x0dd7_b8d9_11c6_097e, - ]), - pallas::Base::from_raw([ - 0x878f_37be_45a6_24f7, - 0x9e03_f710_b58d_290e, - 0x9deb_aec0_79ca_08f8, - 0x00c9_3eac_1500_b8bd, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd808_eb89_0309_42fb, - 0xbcff_47e4_811f_e691, - 0x48a7_d2b6_7422_9156, - 0x228e_a752_e00e_fdbf, - ]), - pallas::Base::from_raw([ - 0xf199_ca0a_c24c_d4ca, - 0x6b0f_07a7_0752_8621, - 0x8d45_6536_032d_db36, - 0x0288_3b48_40b1_3378, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe693_43b4_9f9e_5b1b, - 0x89d5_ce6a_32fd_13c7, - 0x9ed7_6f5c_5aa1_9a97, - 0x2ec4_33c9_00e1_bbd1, - ]), - pallas::Base::from_raw([ - 0xeac3_ed86_403e_abe1, - 0xf6fe_9a5e_dfb8_8a4e, - 0x8f6a_6351_97b0_db20, - 0x1e2c_043d_0511_cfa2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9ab7_f215_baa3_94d4, - 0x1d8f_3e16_e38f_a26f, - 0x4159_fc19_7738_7456, - 0x00ab_08a1_f3c0_25db, - ]), - pallas::Base::from_raw([ - 0x7127_4247_2253_84aa, - 0xbb16_d239_fc1e_a68b, - 0x0e3b_b7c2_0be4_3570, - 0x100e_d9d7_3b76_9c8e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x42c3_aec9_48e9_24ff, - 0x9b63_1a8f_ca4b_f414, - 0x9ef2_f7fe_060e_a416, - 0x25b4_8d9f_f095_81d1, - ]), - pallas::Base::from_raw([ - 0x8ae4_2d3a_35a0_766e, - 0x104d_f6d8_e9cd_72d6, - 0x71df_5cb2_0423_2963, - 0x0899_58d7_7854_6236, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa5dc_0bad_a65b_67bf, - 0xf29f_e8a2_2244_b057, - 0x5511_3eee_8db8_b190, - 0x1210_c119_2f7b_d485, - ]), - pallas::Base::from_raw([ - 0x4b62_e8e5_60e9_df23, - 0xe625_32a0_2269_5edb, - 0x4afe_a317_bfa2_f9e4, - 0x0134_67f6_1d26_4b88, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd1d5_3c8c_9f78_209d, - 0x9713_2e54_9dc7_f6d1, - 0x9999_feb6_19e2_ce8f, - 0x1827_19c1_45b2_ad83, - ]), - pallas::Base::from_raw([ - 0x6440_07e8_0d1b_ebca, - 0xb59a_b45a_21c2_c8aa, - 0x37cd_166a_131b_bde9, - 0x3e88_79f1_0539_11ae, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2128_47a7_80b3_afd1, - 0xd62d_98a3_729d_147b, - 0xac76_cd5b_7780_e455, - 0x1371_d855_6493_7957, - ]), - pallas::Base::from_raw([ - 0x03c5_35ac_7821_d861, - 0x1897_7fb8_d4d3_21ff, - 0x57ec_5e9d_09d2_d94c, - 0x2933_8896_3d25_c33d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4c64_9009_4f5b_b733, - 0x2f25_149e_b638_123d, - 0x583b_d5e6_3c07_fe56, - 0x38d0_e3be_cf9a_d8fc, - ]), - pallas::Base::from_raw([ - 0x9482_7610_0282_f357, - 0x9035_4a5d_fd55_d474, - 0xdf90_065f_46d7_3461, - 0x1ee2_e8e9_a7f7_1162, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc2cf_20da_8325_f9f6, - 0x4158_322b_3ab5_e06c, - 0x55ea_0370_e75f_deaf, - 0x0491_5155_2307_b345, - ]), - pallas::Base::from_raw([ - 0x3a6c_b7c7_58d2_1156, - 0x3ee5_aca9_420a_c8d4, - 0x824e_78fc_93b0_042b, - 0x2300_ec5f_8679_d667, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4534_4de7_cd4a_1286, - 0x7000_9fbe_d545_bd95, - 0x56f3_45dc_329c_fe4d, - 0x1b11_0f10_4c22_8670, - ]), - pallas::Base::from_raw([ - 0x587e_67ee_4d03_0b13, - 0x26d6_4ee0_cfa1_e3fd, - 0x31a4_3dbc_e45b_3166, - 0x384c_1a74_cf99_7d87, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa739_b815_03af_5bde, - 0xfe73_4fc3_5916_3751, - 0x87ae_e2ab_a571_0f68, - 0x2880_7f09_fbdb_6069, - ]), - pallas::Base::from_raw([ - 0x959a_ef52_08c3_91fe, - 0x9283_4894_b296_c35c, - 0x4a5c_c47f_99f0_5f73, - 0x04a5_23d4_9550_e5f2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbbaa_a155_8473_a2f0, - 0x848d_48dd_594a_7097, - 0xe3dc_ec5c_faee_ddc1, - 0x3a8c_2c5a_d7c4_d92e, - ]), - pallas::Base::from_raw([ - 0x3bbc_7750_d4fe_2be1, - 0x70ba_0c48_e53b_baff, - 0xa804_5683_c10d_6804, - 0x1094_6631_c67f_0dfe, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3602_21c5_3677_ccd7, - 0x9de8_46d9_609e_11b3, - 0xc600_0f59_0fc5_e51e, - 0x12e5_6f18_ba2a_83f3, - ]), - pallas::Base::from_raw([ - 0xb472_c933_636e_7cfd, - 0x747b_505e_b1f1_252b, - 0x944f_8b8b_0fbe_9e69, - 0x081b_05b2_cc35_1fcd, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf69f_2736_a2e6_02cc, - 0x40b6_25b7_d5c4_621f, - 0x09ba_e2a7_4bc9_bc80, - 0x19b0_3942_3298_a1b4, - ]), - pallas::Base::from_raw([ - 0xab25_9c06_92dd_6ddd, - 0x8930_0e85_715a_2677, - 0x1518_4d35_6d96_7b91, - 0x1afc_017e_c025_f777, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbd9c_a11d_c9d1_47c4, - 0xa729_70e7_74ea_f665, - 0x4ab2_7f51_e350_8d9b, - 0x1b80_855f_52e2_65f1, - ]), - pallas::Base::from_raw([ - 0x47cd_3ef3_25be_4c31, - 0xe4c1_3895_f52a_ad9b, - 0x3533_9da3_9399_7f27, - 0x2388_7e28_f45a_cf6f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0863_f044_e1a6_11e2, - 0x79e4_5575_8e7a_78f8, - 0xc8fc_9c15_0f54_30d6, - 0x3a7a_8e36_84de_274d, - ]), - pallas::Base::from_raw([ - 0x03a3_2fb5_bab3_3a4d, - 0x0bd2_34a6_5c64_7867, - 0x972b_19ad_d013_d7c1, - 0x1612_2c94_e22e_f260, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdf78_184d_c553_f8fb, - 0x95e8_ea38_3755_2814, - 0x1603_092f_6d39_db38, - 0x2769_e6ea_c901_bb9f, - ]), - pallas::Base::from_raw([ - 0x6aae_1ad2_22b6_2d45, - 0x8341_704f_980d_1ea9, - 0x7317_b503_da60_23a6, - 0x16b1_5baa_a77c_92e6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x35ad_694f_d3f3_93e5, - 0xb977_6bab_ecc1_635d, - 0x673e_2552_a80f_847f, - 0x282a_562e_6ffd_6c2d, - ]), - pallas::Base::from_raw([ - 0xcd61_300f_af9b_7633, - 0x5f78_7bdd_6fb9_767a, - 0xf8e6_3e0b_a3cb_a82e, - 0x3c29_8b6c_70f6_5826, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf978_920b_4033_85f0, - 0x4741_dfed_87e7_f4ed, - 0x9af7_9a50_a097_b040, - 0x09f2_0401_7a7f_3d55, - ]), - pallas::Base::from_raw([ - 0x484c_a7c7_1e1d_cfde, - 0x435e_fe17_c8a5_cbc1, - 0xe981_12aa_7104_5057, - 0x1d2c_9905_b8c5_8026, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8a4e_ddc1_e2a4_e687, - 0x5bff_5ce2_018e_858f, - 0xc6e5_662f_83a1_e56a, - 0x02a2_000d_679b_2dba, - ]), - pallas::Base::from_raw([ - 0x2f6a_f6ea_7c76_b2a0, - 0xb8c7_4bfa_9b69_4056, - 0xfb79_16ad_496d_1e14, - 0x1df4_ca05_f14d_04e2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6088_f6ef_e336_ea5c, - 0x7497_110a_3ab5_54c8, - 0xbb4a_8a7e_90ab_1b70, - 0x16ca_05a8_a644_e307, - ]), - pallas::Base::from_raw([ - 0xbc6b_4bf6_eee0_03cf, - 0x9497_c239_5d17_314c, - 0xa528_8c4e_96df_57eb, - 0x05ec_2cd2_70b2_c32f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1d4b_5aba_2d51_6844, - 0x0ebb_e763_14ac_cff0, - 0xcae2_52c3_1950_5947, - 0x106f_7769_986b_58ec, - ]), - pallas::Base::from_raw([ - 0xec32_de24_bd53_2691, - 0xaf82_b179_9fba_b8aa, - 0xadf7_592d_33f3_4d51, - 0x1dd7_ab82_5380_22db, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7701_5dcc_356c_94f9, - 0xe75b_8f5f_f89f_73ab, - 0x934a_7c89_81e2_4737, - 0x0952_ea05_e704_9ee3, - ]), - pallas::Base::from_raw([ - 0x7bdb_c92d_9d50_75f7, - 0x9985_21f0_5f28_9ed4, - 0x920d_4ffe_7a28_6fb2, - 0x19b4_edf6_4b69_3292, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2d93_48b7_18f9_b3ac, - 0x1ee6_c3d8_07e9_cb72, - 0x27f7_47e3_bd7b_0b59, - 0x3344_264e_0e0f_39af, - ]), - pallas::Base::from_raw([ - 0x5392_14e5_9f27_7f85, - 0xbab5_f15c_75c7_fa84, - 0x5e92_a501_1bcb_a88a, - 0x39be_7bc4_6e98_ebef, - ]), - ), - ( - pallas::Base::from_raw([ - 0xeffc_5cb8_5798_7d36, - 0x4231_e383_e08a_1c06, - 0x83f4_c3e7_99b4_5fe5, - 0x1bc4_4ad9_628d_b324, - ]), - pallas::Base::from_raw([ - 0xb051_73ed_1a60_83bc, - 0x5d3f_b49d_377c_550f, - 0x9ec4_1f7e_c634_c956, - 0x2ea2_a4bd_7949_e352, - ]), - ), - ( - pallas::Base::from_raw([ - 0xce11_b86d_18ab_15c5, - 0xfdfd_58bb_e7cf_ebbd, - 0x011a_1665_1ade_a741, - 0x1867_7683_03fc_dcbe, - ]), - pallas::Base::from_raw([ - 0x8c65_a7b3_7436_63a6, - 0x0895_f62c_82b4_bcca, - 0x697f_2648_19e5_bf42, - 0x1c9e_8a89_693a_c155, - ]), - ), - ( - pallas::Base::from_raw([ - 0x20f1_50c1_b583_d962, - 0x5b7c_4fdd_6bf3_33a4, - 0x6616_f214_6b56_0695, - 0x3c09_152a_ae39_f9d7, - ]), - pallas::Base::from_raw([ - 0x8d4c_d15c_11e4_5f76, - 0x3ee6_fba2_a365_7a95, - 0x57df_944d_2990_ae68, - 0x3e40_9606_dd7f_fcfd, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0f1d_cbaa_c64e_207f, - 0x24ce_0096_04e8_74af, - 0x8206_a341_4f16_3b2b, - 0x1841_ffa5_9560_5383, - ]), - pallas::Base::from_raw([ - 0x7445_4a84_172d_dfb7, - 0x4e61_663d_e974_8c87, - 0x49ac_c46f_7652_ae10, - 0x35f9_eb31_2da0_3d40, - ]), - ), - ( - pallas::Base::from_raw([ - 0x71b2_cf29_e621_7cd2, - 0x85fb_6de4_0cdc_c772, - 0xfcb0_2d60_0a46_877a, - 0x0dcd_cba8_2583_6234, - ]), - pallas::Base::from_raw([ - 0xa5e7_e058_d611_327b, - 0x1f29_dadc_d446_02dd, - 0x50d2_0616_22aa_60e5, - 0x1bc1_4ad7_6911_5d28, - ]), - ), - ( - pallas::Base::from_raw([ - 0x76ad_98d4_ab3b_419f, - 0xffad_8c50_6e25_97ff, - 0x3a06_bbb6_43ea_1ebd, - 0x3da3_b0f3_6ffb_c5f7, - ]), - pallas::Base::from_raw([ - 0xf747_ed0e_6bf0_296d, - 0x08b5_9863_d358_93b0, - 0xfec9_a301_a77f_064e, - 0x18e9_b59e_d7dc_0386, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1965_7b9b_65a0_684f, - 0x2138_8c2d_19c4_1b69, - 0xae4f_210b_d783_87fa, - 0x2e4a_f156_17f9_aa1b, - ]), - pallas::Base::from_raw([ - 0x7e5a_da88_7dbb_23ac, - 0x076a_81da_aa1a_cea5, - 0x46f5_2c4a_4629_12c7, - 0x377c_3c47_a79a_cd00, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd9e6_9b4f_775a_8960, - 0x3cf8_686d_3a8c_2253, - 0x007c_16e7_38dd_f650, - 0x275c_d87f_d1a9_affb, - ]), - pallas::Base::from_raw([ - 0x2eac_fae8_83be_39dc, - 0xa147_cb90_545e_9792, - 0xb894_660b_0ca5_2156, - 0x102c_7bd5_54e6_2a1f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3d50_5225_818a_d743, - 0x7610_a4da_2296_4451, - 0x4ac1_dba3_15cd_e138, - 0x2a63_e9ea_93b4_8b68, - ]), - pallas::Base::from_raw([ - 0x602f_7b8a_987c_a0ae, - 0xf26d_d9ff_d12b_9ca2, - 0x7434_3696_6cde_5174, - 0x1d77_2b01_598d_98f6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9ee6_79fa_2503_f12d, - 0xe3a0_67a8_ab7c_c1a7, - 0x4a04_cfd6_a900_5d0d, - 0x20b6_e71f_03ce_350e, - ]), - pallas::Base::from_raw([ - 0xff99_352e_01d9_e9c0, - 0x1cff_eb28_f38b_918a, - 0x3f5a_211d_6b2f_6a4b, - 0x35fc_1ac5_b933_3f78, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfd29_ac30_0d2e_c13b, - 0x6d86_8828_a090_269d, - 0x617b_b4e3_df1d_6e3f, - 0x1062_44bd_2099_3d22, - ]), - pallas::Base::from_raw([ - 0xba4b_6207_7d83_b053, - 0x752b_22b3_0554_a5b4, - 0x9399_8320_f3a0_12c4, - 0x3e32_1295_f9a7_53f3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x21b0_2a13_67da_2df6, - 0xd95e_f536_2abb_71e5, - 0xc466_cf97_819a_bb8d, - 0x0ac1_d2f5_a9ef_d18d, - ]), - pallas::Base::from_raw([ - 0x652c_72da_e56f_053d, - 0x3e16_df3c_dd09_25f8, - 0x4486_dc64_f0ae_ae8e, - 0x1083_d1d6_afcc_3d28, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd66d_903f_1504_cb22, - 0x7d74_1d95_24fd_f1a2, - 0x0420_1142_5b05_701d, - 0x2581_a1db_a4a6_28f9, - ]), - pallas::Base::from_raw([ - 0x31f5_3161_9435_04e8, - 0x56b5_086a_e923_27ee, - 0x0470_dba6_f453_d40b, - 0x37b7_3cbb_6a46_8bc3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5a64_fae6_2a62_095a, - 0x1a5d_b99a_a3cc_09e1, - 0x5c87_bf4d_b4f1_d4cf, - 0x3554_e145_5ac7_ce25, - ]), - pallas::Base::from_raw([ - 0x62fb_29aa_b259_653c, - 0x1079_e028_f669_bf99, - 0xc7b5_e1a2_b66a_56d3, - 0x1da9_6c27_0679_663d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa38a_7597_05e4_c595, - 0x93b5_16bf_3679_9104, - 0xdcf3_617c_06b7_eca9, - 0x1c04_9649_6246_d90a, - ]), - pallas::Base::from_raw([ - 0xcb9b_62de_2098_b010, - 0x0b11_bddc_e6c4_3c5b, - 0x0e06_9619_2171_a4b5, - 0x0ca0_f9bd_545e_b563, - ]), - ), - ( - pallas::Base::from_raw([ - 0xabcc_ccbb_5ce1_d68c, - 0x6f7c_af47_e50d_a282, - 0xf36a_135e_abaa_806f, - 0x0c6e_bade_1095_aae8, - ]), - pallas::Base::from_raw([ - 0x759c_cc9e_69e6_b3e2, - 0xf9dd_54df_05a2_63bf, - 0x89da_d73c_cf47_946b, - 0x0312_d8af_2b83_bc52, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3d63_f419_3209_4084, - 0xa82e_0939_a10d_d3bd, - 0x09a4_2d48_e016_ca24, - 0x22d5_2560_48fb_a5d6, - ]), - pallas::Base::from_raw([ - 0x205f_917b_e385_f08e, - 0xe8ba_59ea_1582_96c5, - 0x07db_5f05_1202_61f4, - 0x1b27_fe10_cf0d_2d81, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc3c5_2026_c4c0_cdbc, - 0xe5c9_a075_9804_c4f1, - 0x333d_a34f_899b_6d01, - 0x0893_9b6f_69ee_9ff1, - ]), - pallas::Base::from_raw([ - 0x5738_5c90_a60b_6a29, - 0xcbfe_0af0_9889_9ee3, - 0xe56c_4f49_ed05_94c2, - 0x1a8c_87df_a7e4_fed0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9bcc_8617_524a_7052, - 0x9ed1_bc3e_a53b_8039, - 0xe83b_0a28_98c1_b3ae, - 0x2156_b879_f378_005f, - ]), - pallas::Base::from_raw([ - 0xe445_4fd6_1a4c_0c03, - 0xfd2d_77ee_9e45_d137, - 0x364c_d7d1_beca_462e, - 0x0454_61a0_6d06_0224, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa6dc_e40b_7742_c8df, - 0x77f6_fb9f_2f5e_4cbb, - 0x8971_a6f2_c8a1_01f6, - 0x06f6_891d_e68d_557e, - ]), - pallas::Base::from_raw([ - 0xe136_eb32_f32c_9360, - 0x43cc_807a_1583_94e3, - 0xb883_68d8_bd3f_0e85, - 0x39c7_f743_a3ff_d99b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4d92_8024_dec5_a188, - 0xc6fc_a92b_d386_353e, - 0x5812_c85d_f51b_7666, - 0x3622_96ae_b985_ad75, - ]), - pallas::Base::from_raw([ - 0xaf74_4347_0ebc_cc5b, - 0x8664_df03_bd4f_e04e, - 0xbb7c_dfe1_90ed_a6e1, - 0x04b7_49f0_6ac1_8d6d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x47cb_7e3a_61e6_5d64, - 0x2668_8f4b_611d_168b, - 0x851e_b1c6_f081_270a, - 0x0bcd_6577_07d9_c4d3, - ]), - pallas::Base::from_raw([ - 0xb8a7_9c1d_0164_6e59, - 0xaca0_0a81_3cbe_8d14, - 0x9be3_d622_a4d4_2261, - 0x228f_44ec_ff21_0aaf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x01e8_32eb_32fc_77d8, - 0xa37b_d49f_cf1e_6d1d, - 0x4ade_7626_003a_6902, - 0x2810_18ba_6873_285b, - ]), - pallas::Base::from_raw([ - 0x3b22_bd8c_3f6a_e0f7, - 0x647a_d4e9_cc9e_9df9, - 0x599f_264e_e5e2_861a, - 0x1bc7_4dbb_c711_e11b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xea31_502c_f1b8_0e15, - 0xc33d_5160_cd48_b428, - 0xcc23_c910_de17_adec, - 0x07de_f9ce_1aa5_9c47, - ]), - pallas::Base::from_raw([ - 0xa4ae_eeba_b464_5932, - 0xb123_1450_1087_4d65, - 0xd74f_2873_e2b3_fbd6, - 0x37f7_28e5_56e4_462f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7e30_9f95_bb4b_c5b4, - 0x6062_f47d_7261_c580, - 0x8e3d_4f2a_6d15_8590, - 0x01d5_e294_1638_a398, - ]), - pallas::Base::from_raw([ - 0x2d94_25e0_5176_6252, - 0x661f_3a26_6d6d_2f2b, - 0xe226_6037_2ff4_b8dd, - 0x1217_12c3_778e_e4a5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8089_bc3e_77ce_6f7c, - 0xa6b2_22eb_d80f_7fc0, - 0xe9b8_b790_943e_8250, - 0x1095_0660_66b4_15b1, - ]), - pallas::Base::from_raw([ - 0xecaf_5823_aa30_216c, - 0x1bd3_7176_ae8c_c867, - 0x6646_5d17_3a00_4c92, - 0x1708_b8da_bbac_5fa2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0f5a_b3f4_1ed5_0406, - 0x3ed6_b824_6b8e_8193, - 0xefc8_17a7_c166_72ef, - 0x03d9_e65c_55e0_6fed, - ]), - pallas::Base::from_raw([ - 0xd266_0a0a_3a15_efd9, - 0x3158_3160_0238_603a, - 0xd08a_576e_ef04_0407, - 0x12b5_fc79_3386_02ad, - ]), - ), - ( - pallas::Base::from_raw([ - 0xafb4_5038_861a_b261, - 0x3336_2512_0ea2_ddef, - 0xd0d2_1e8a_bde9_c3f0, - 0x3142_5607_0f44_6667, - ]), - pallas::Base::from_raw([ - 0xd47d_2bf6_b0cd_9526, - 0xdfb6_5162_03ea_5997, - 0x6bc8_e93a_d9f1_3d86, - 0x36e3_7b1e_879f_a3fe, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9641_b725_3871_63f8, - 0x2f14_e213_977d_fb89, - 0x872e_0f0f_818e_2401, - 0x2705_4742_9401_5255, - ]), - pallas::Base::from_raw([ - 0xe914_98e9_e277_bf3e, - 0xbc1c_1336_46cc_0de8, - 0x810d_265f_9dbb_24c2, - 0x073c_4fa7_0c22_d417, - ]), - ), - ( - pallas::Base::from_raw([ - 0x72e0_8476_4f57_cbdb, - 0xaade_43be_ed5a_ec74, - 0x6b7a_19e7_38aa_efa8, - 0x3fe1_03e4_b203_9c38, - ]), - pallas::Base::from_raw([ - 0xf7b0_a409_9047_5ffc, - 0xf227_8b45_596c_d47f, - 0x8e89_3c33_0061_9b20, - 0x1e9a_0a12_9951_b344, - ]), - ), - ( - pallas::Base::from_raw([ - 0x273e_1d1d_25f4_def7, - 0x2003_845a_3171_beb1, - 0x6d17_8165_5f29_f2d4, - 0x0870_5e7f_5d5b_29c0, - ]), - pallas::Base::from_raw([ - 0x5593_5829_fa5d_7cff, - 0xf32a_41cd_f789_5d7e, - 0x1bf2_ea43_d1a2_e73d, - 0x020f_bf08_0453_d654, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc7cc_99c7_2db8_9a13, - 0xe869_f872_1a3e_457f, - 0xf8d5_9b75_f9e9_5e27, - 0x2a3c_dfb9_b0ec_7221, - ]), - pallas::Base::from_raw([ - 0xda92_9b87_c8b3_43ae, - 0xb33c_22e3_1aca_23f0, - 0x7ef6_c020_43d5_029b, - 0x0f16_75e5_fb1b_6016, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdaa7_c49c_581e_a8f5, - 0x5e24_60df_0bf6_68a4, - 0x04e2_ec29_9caf_6146, - 0x2438_e7ee_c6b6_6289, - ]), - pallas::Base::from_raw([ - 0xd94c_c550_0990_5ce3, - 0x9149_39c9_7c98_acbb, - 0x90d6_a0d5_e69d_004f, - 0x0e30_9799_430a_005e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x16d2_ba71_df3d_ba37, - 0xf987_3a39_9072_46f3, - 0x7309_0fc7_2e2c_8978, - 0x3e6a_ca9f_7693_dbd8, - ]), - pallas::Base::from_raw([ - 0x14bb_c667_e12f_8242, - 0xb8ab_dadf_64c7_ce8e, - 0x1a94_5bc1_7bb2_ea2a, - 0x012d_bbf6_af71_3aec, - ]), - ), - ( - pallas::Base::from_raw([ - 0x240d_00da_c9d7_36ac, - 0x5e01_5424_1ed5_6054, - 0xb77b_8e76_3e42_9cfb, - 0x1443_95ec_38cd_baef, - ]), - pallas::Base::from_raw([ - 0xa1d5_463f_18ef_f4f8, - 0xac13_6a2b_6eec_e912, - 0x175b_2f1a_655b_abb6, - 0x11f8_e577_8862_dc12, - ]), - ), - ( - pallas::Base::from_raw([ - 0x917d_91a5_1b8e_9f26, - 0x96a7_d4b3_e2db_2ef9, - 0x6467_2893_ebec_80a5, - 0x0415_c72c_6add_a7ad, - ]), - pallas::Base::from_raw([ - 0x31fe_78e5_541c_b69d, - 0x6fd0_a42e_a164_a907, - 0x779b_fe38_59e7_a99d, - 0x1502_f313_f9ea_cc53, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6299_68d0_f509_962c, - 0x0fd8_546c_a5b9_a1e8, - 0x4f71_7137_88ee_864d, - 0x21be_39d7_bb78_98ff, - ]), - pallas::Base::from_raw([ - 0x2e30_597c_56a1_b4fa, - 0x1a02_ad53_8381_07e1, - 0x4d02_2a9e_1cfd_6d33, - 0x1f3c_e37d_51aa_b4c1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd2e8_277a_9787_ad9b, - 0x06b8_ef87_3d81_def3, - 0xcb3f_a058_0cdc_9294, - 0x3e0e_b866_b610_dad5, - ]), - pallas::Base::from_raw([ - 0x416f_988d_290b_fce1, - 0xe99d_9c46_9eea_a7fc, - 0xe826_d37c_968c_f31a, - 0x303a_5065_2996_bc3e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x970d_c43d_b7f9_6596, - 0x8bbe_a004_7bbe_b37a, - 0xffbf_c07c_4f86_ff20, - 0x2eb0_e870_2a5b_817b, - ]), - pallas::Base::from_raw([ - 0xcdec_df92_c73a_cf15, - 0xa349_b8f4_4bc1_1a4b, - 0x4ca2_5c82_1a35_0486, - 0x0c35_a8ee_8f63_ce4e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3330_feff_82c5_909d, - 0xa037_ccf5_1576_8f65, - 0x04b4_e5bf_d165_ab7e, - 0x3d8f_d30d_2e98_701f, - ]), - pallas::Base::from_raw([ - 0x76cf_354c_613f_6916, - 0xb3ac_8cfc_ef68_b8e4, - 0x121e_23ec_fb6d_3348, - 0x049c_4676_6965_007e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd28b_5af8_208a_ad16, - 0x85cc_0c01_2522_9ec1, - 0x0010_00b7_fcba_b744, - 0x2f16_3cb5_e159_50da, - ]), - pallas::Base::from_raw([ - 0x8204_a5a6_854c_8f0c, - 0xaec2_50ed_9f9c_1bf3, - 0xa678_973b_4ca8_cfba, - 0x2060_78c2_1062_adf6, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb572_bfa2_ae44_bae7, - 0x4739_7be5_ed58_65d9, - 0x12d8_2660_d7d5_cd9d, - 0x3802_91b0_d0fb_11f4, - ]), - pallas::Base::from_raw([ - 0xda9e_f004_e34f_00ed, - 0xd1c7_c9c5_f145_719e, - 0x5d07_b071_e032_9c77, - 0x111f_1bf3_5aca_cc6c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9d4e_fee9_dbec_f74b, - 0x54b6_6b98_6ed1_1c40, - 0xc69d_e967_1f2a_9277, - 0x381e_f7c2_0901_6f19, - ]), - pallas::Base::from_raw([ - 0x78cd_6291_4c3d_4870, - 0x969d_b03f_4366_a7c9, - 0xc63f_edfc_ad98_8cca, - 0x0871_c3f1_196c_ed39, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbf95_5ae0_cd25_88e4, - 0x1a5d_be45_5bc1_85c6, - 0x800f_fb1f_93e7_1b70, - 0x0499_6852_1fa4_93b8, - ]), - pallas::Base::from_raw([ - 0x0888_a02b_46a4_447f, - 0xbf4f_428f_9cb9_8c28, - 0x8137_0703_14ff_9de2, - 0x1387_9076_4310_b410, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd12e_b4c0_0f6b_07df, - 0x4867_9cb7_f377_39f4, - 0xd28d_9c85_b17d_4400, - 0x0bd9_47e1_a875_e349, - ]), - pallas::Base::from_raw([ - 0xda62_8d27_e56c_e1ba, - 0x3fb9_f8d5_96b8_9fd8, - 0x5de3_b929_f658_6237, - 0x1535_62a4_2638_2eb6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x36af_3b03_bde6_af5c, - 0x4fa4_3315_d7f6_0dc6, - 0x7067_a020_a491_9197, - 0x1c32_47f1_b306_ddee, - ]), - pallas::Base::from_raw([ - 0xc652_bb5a_650f_f696, - 0xf53e_890c_d2fe_64e1, - 0x9dbd_c120_670e_ac51, - 0x0786_cce0_4423_b08a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9b52_5a04_5c02_abe2, - 0xab88_03cd_3c69_fc10, - 0x4f5c_04e7_4967_f822, - 0x3d7c_ba8b_8d24_c973, - ]), - pallas::Base::from_raw([ - 0xc36f_6da9_c20e_8ca7, - 0x3ab8_0cd3_18c7_054d, - 0xea00_c48b_f1fb_88d8, - 0x2a85_cd4f_78e9_75d5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xac5b_f95e_d4b6_11a2, - 0x136d_4d81_80c7_2c43, - 0x1fb6_df88_d28c_8d4e, - 0x246a_fe1b_17d5_6011, - ]), - pallas::Base::from_raw([ - 0x3668_7b33_4756_4972, - 0x1467_dd2d_360d_bc64, - 0x410c_df5f_93a9_6258, - 0x3588_8b68_24c6_e8a0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5dc2_2a72_4a62_d492, - 0x2660_9b2b_a750_8d8c, - 0x5059_5ae6_1b53_8471, - 0x266a_34b1_9765_cdff, - ]), - pallas::Base::from_raw([ - 0x7fbe_5bdb_d358_a2cb, - 0x40a4_f7fd_1ca8_a76a, - 0x491d_3273_a50e_004a, - 0x3568_0e4a_dc4f_62ad, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbfdb_990c_f977_fd4e, - 0x6437_369d_ca6d_cc9e, - 0xc7b5_d048_b550_51ee, - 0x250b_73ec_71d5_4645, - ]), - pallas::Base::from_raw([ - 0x41ae_e46b_4412_b381, - 0x9e9e_e500_6ddc_61fb, - 0xec2f_6df5_bbce_cf94, - 0x1793_e215_0b16_603d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6f88_6d79_770c_6247, - 0x1500_0374_0fa1_e182, - 0xf376_03b2_1769_2f82, - 0x3d1f_7368_0af5_b7ec, - ]), - pallas::Base::from_raw([ - 0x81b6_a75a_e4f9_729e, - 0xe735_aeaa_341f_ae17, - 0x4eff_b7c5_e1aa_bb0a, - 0x0223_c1d4_4c5d_c34a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x419d_f14d_7945_7532, - 0xd780_283f_4e02_c512, - 0xf0fc_47a1_756c_c536, - 0x1ce3_0702_a06b_ed82, - ]), - pallas::Base::from_raw([ - 0xaa20_9753_1479_6860, - 0xb77b_9671_d950_53a0, - 0x804e_e63e_09dd_84ba, - 0x09e1_711b_96dd_a806, - ]), - ), - ( - pallas::Base::from_raw([ - 0x607f_ba34_a589_c019, - 0x79bd_bab6_5d82_5998, - 0xcaca_a4bd_7fbb_d938, - 0x3694_ca85_2cf8_e54d, - ]), - pallas::Base::from_raw([ - 0xf555_28c0_3fb3_7e54, - 0x4a49_b781_11bb_66e4, - 0x94e4_77e7_59c5_515b, - 0x369b_a0f2_0b09_fe48, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa903_4843_3c41_e761, - 0x334f_6c0e_07da_b2ae, - 0xfa76_35b1_0775_e8e1, - 0x1fdd_43d1_901d_1921, - ]), - pallas::Base::from_raw([ - 0xb042_af7e_11f5_e1a3, - 0x72dc_c343_0584_0ada, - 0xec1f_22f3_40a0_7a4a, - 0x3d4d_cd14_0c46_afa7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6516_53a1_ad5a_b863, - 0x3109_c5a4_3f3a_7299, - 0x4a26_89fe_ac51_8cd9, - 0x32cb_28e5_306f_4b25, - ]), - pallas::Base::from_raw([ - 0xce22_41f1_7770_0732, - 0xe9c2_68bf_1477_f81a, - 0xb643_c5f5_bed9_f57c, - 0x1ab3_8e0c_8fed_3eaf, - ]), - ), - ( - pallas::Base::from_raw([ - 0xad37_f47d_cf5b_c929, - 0xfec4_68cb_3ca6_b620, - 0x388c_5260_e2cd_625d, - 0x3e14_2094_bf47_b461, - ]), - pallas::Base::from_raw([ - 0xe191_3bcc_b9c4_dbd6, - 0xf56b_018e_cbd3_94fe, - 0x7a84_d88b_b2d8_d148, - 0x1095_d08b_31d1_571a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4c24_da73_a43b_18a4, - 0x192f_ad49_886d_4f1c, - 0xb9ca_2200_29b0_fd9e, - 0x23c3_cd8e_910e_3f61, - ]), - pallas::Base::from_raw([ - 0x446a_7b2c_0c53_995b, - 0xf640_9e82_f746_d6c6, - 0xd49a_f1a5_d660_f046, - 0x289f_6688_c8f7_a7da, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9322_2f89_f469_19ea, - 0x23ca_ce6d_d52f_41af, - 0x7b9f_0036_a0b5_b7ec, - 0x36a9_0ecc_3af7_1bf8, - ]), - pallas::Base::from_raw([ - 0xac78_4d5a_2fed_e96e, - 0x83c7_0ec2_e5cc_48a1, - 0x623c_7acd_dabe_6588, - 0x262e_4d3c_689f_55c2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc48b_b03e_d3dd_130e, - 0xc8da_668d_e3e8_c4c0, - 0x8496_8dfb_620e_4d78, - 0x21d2_8b83_ef14_3a07, - ]), - pallas::Base::from_raw([ - 0xa607_41ba_7c9f_512b, - 0xe9af_6b59_b23f_048f, - 0xb49b_ffe3_9a97_dd6b, - 0x073c_ef7a_eab5_e67c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbb8c_2ebd_02ef_5c02, - 0x9f3e_fb6b_a8a3_d5e7, - 0xdd5e_afd6_8224_7afd, - 0x0a4d_0696_34c2_1d49, - ]), - pallas::Base::from_raw([ - 0xde8b_2693_7445_2117, - 0x8827_3e13_9ac8_9175, - 0xaf4d_3f11_60fa_ce22, - 0x372e_f7de_420c_f5b0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x007a_3171_e694_ad4f, - 0x0b63_7d43_b499_6483, - 0x3f41_d9a4_71d9_e31e, - 0x2304_4159_f767_5fe2, - ]), - pallas::Base::from_raw([ - 0xc689_d9d9_98f0_22c3, - 0x3843_04a4_96ef_f3ea, - 0xcdf7_07fb_a786_9698, - 0x00ff_aa52_52f3_1075, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc7ed_5950_3bbd_ae0c, - 0x0771_0a4e_f363_a8cf, - 0xb854_a41d_2524_2222, - 0x361c_d998_8c71_f7d1, - ]), - pallas::Base::from_raw([ - 0xd1c3_f5a8_e31d_e85e, - 0x61f9_1fe1_a2ed_72f5, - 0xd02a_3047_b442_7a6b, - 0x28a9_2ac8_140a_7f61, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe69b_8ff5_68db_09ef, - 0xa955_a884_45b6_1b1d, - 0x0181_0ff8_0bc0_0a37, - 0x3f77_7487_2da1_b634, - ]), - pallas::Base::from_raw([ - 0xbafc_6197_5f58_119e, - 0x8ec8_6817_94cf_4a02, - 0xf79d_b4f7_ef61_586b, - 0x1ecb_0eff_dee9_b332, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2e7c_1b51_5d9a_6b02, - 0x6db8_5ed9_bc41_5b63, - 0x9e61_c761_f278_31e1, - 0x1d63_7f07_1de7_68c5, - ]), - pallas::Base::from_raw([ - 0xb695_013b_a88a_e8fc, - 0x6087_861a_5652_9bf5, - 0x37e4_54e2_449e_c3d0, - 0x32f1_ac34_a889_a6b1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x45c6_e979_95c8_8f9d, - 0x9177_13bd_364f_3511, - 0x18b5_d48a_f737_4cec, - 0x1acb_50aa_82bc_21f3, - ]), - pallas::Base::from_raw([ - 0xa0b5_ac1e_0e73_137c, - 0xe9cc_3b69_7c2a_33dd, - 0x3843_fbd6_837f_46b9, - 0x3af2_c307_dabd_f022, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf320_517d_b185_80af, - 0x4ee4_765d_dab8_aefa, - 0x6b87_9ec8_cb2c_34ec, - 0x1804_0e61_d02c_9aa7, - ]), - pallas::Base::from_raw([ - 0x7799_9a31_ca66_44d5, - 0x5c57_40bb_df52_8c37, - 0x3c6f_fa5b_9973_5cc2, - 0x2d42_7fcb_2de3_02b2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb702_1f4e_248b_d314, - 0x45a6_d47d_1e77_fc6f, - 0x71de_177e_9447_c0b3, - 0x2c36_6f8e_fc81_8295, - ]), - pallas::Base::from_raw([ - 0xd417_641c_3ef7_59be, - 0x46f0_a493_376d_27ea, - 0xcc58_89f3_a398_3e94, - 0x24ca_8204_9524_6a0c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4d41_08a1_fdf9_022d, - 0x445b_c1f6_ff38_ab2a, - 0x2c34_468f_08c5_67cd, - 0x27c9_224e_b005_f2fb, - ]), - pallas::Base::from_raw([ - 0xb67f_e386_3ad8_5858, - 0x35e7_89c1_3270_0ae0, - 0xaf43_ea8e_be9c_72c2, - 0x35ff_b97b_a593_0142, - ]), - ), - ( - pallas::Base::from_raw([ - 0x679c_9c77_fa3e_adea, - 0x050c_617e_c159_e9dd, - 0xe4d0_ad0b_279e_5d53, - 0x1c13_85a7_acca_d2d0, - ]), - pallas::Base::from_raw([ - 0xa605_758c_76d8_f99e, - 0x245c_09b6_233e_c109, - 0x9951_123f_fade_c94f, - 0x0e06_cb32_e11a_db9e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdda6_c646_97fa_e3a1, - 0x57f4_3e80_51b9_d2bc, - 0x05ac_1626_2bfa_455d, - 0x27e6_b214_c46d_b4ea, - ]), - pallas::Base::from_raw([ - 0xe0df_3924_7265_cae4, - 0x09c0_1eb2_c3d4_7a5b, - 0x4b07_d6dd_a718_dc3c, - 0x046e_e6b1_16a4_d680, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8827_884a_0d84_93fb, - 0xb641_d4be_17e5_2a25, - 0xd1bb_d65e_ca13_f1e5, - 0x14e6_8375_9dbd_f9b7, - ]), - pallas::Base::from_raw([ - 0xc5bc_27f2_043e_09d6, - 0x4383_1bd8_740d_18bc, - 0x4d28_b951_db51_646c, - 0x2ff2_925c_ae35_4106, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd2ab_b8ea_a809_c065, - 0xa526_4c4f_d558_42f7, - 0x36bd_6833_52ed_686a, - 0x3e03_a120_a2d9_028e, - ]), - pallas::Base::from_raw([ - 0xadcd_15a2_2b64_bcff, - 0x8b41_fbcf_fa41_1d4e, - 0x6275_e729_aac4_1718, - 0x05f4_d1dd_a528_76ca, - ]), - ), - ( - pallas::Base::from_raw([ - 0x259f_45df_db18_4292, - 0x85a3_9f21_bd27_88a2, - 0x7741_d050_9d2b_a469, - 0x3628_e48a_fad3_7caf, - ]), - pallas::Base::from_raw([ - 0xf38c_a509_52c2_edd4, - 0xdbc8_3dce_fa5d_964f, - 0x67e5_1358_704a_dc0d, - 0x2dd7_037f_7772_b72a, - ]), - ), - ( - pallas::Base::from_raw([ - 0xde93_38bd_92bb_3d57, - 0x944b_7238_c860_9441, - 0xe03d_5bc0_6ceb_4255, - 0x2889_0bf6_1603_be43, - ]), - pallas::Base::from_raw([ - 0x598d_dfbe_ff5b_91c4, - 0x9017_7d24_b040_66d8, - 0x29fe_24aa_ca62_9592, - 0x0e1b_b56d_d00f_ee5d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x80f2_b1d9_cd31_a2c3, - 0xfeca_8134_5364_e82b, - 0x667e_8405_4786_7826, - 0x196a_2aa5_dfcc_2404, - ]), - pallas::Base::from_raw([ - 0x44f2_ea4e_50cb_7b22, - 0xa203_aca9_842b_2587, - 0x9c3f_525e_e03f_487d, - 0x1dbb_0fc6_d624_36c8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd9f8_f81d_1726_2ea7, - 0x48c2_218d_3eba_8bbc, - 0x6a31_acc9_902a_abeb, - 0x1086_be57_c6c6_9382, - ]), - pallas::Base::from_raw([ - 0x9b21_c4ee_4438_3fb0, - 0xffbb_187c_d2c6_7113, - 0xbbdf_86a0_0d9c_9df9, - 0x1900_0dbd_6915_ef39, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb87e_e6a1_7150_f083, - 0x1dd3_172a_c7ca_bb4c, - 0x450d_6085_7553_2aa7, - 0x0e87_4af5_a4ea_bea9, - ]), - pallas::Base::from_raw([ - 0x27d9_3005_6a39_bdf0, - 0xaffc_ea8f_faac_2475, - 0x27ce_f92b_ac1e_26d1, - 0x1dce_ecf2_93f2_e855, - ]), - ), - ( - pallas::Base::from_raw([ - 0xec32_f124_f67c_b6a6, - 0xe76f_c0a9_bb04_6fc7, - 0x08c9_2fb9_a869_9d4b, - 0x0aa4_f0ca_3613_1f19, - ]), - pallas::Base::from_raw([ - 0xc77a_383a_f5f9_298c, - 0x6c2a_0c57_8f61_7a6a, - 0xa8fb_83f4_8769_5723, - 0x0dac_9338_2fb1_7d74, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa4ae_ed26_9bd7_f7af, - 0xcf45_5590_be79_8165, - 0xbb66_a5c2_ca07_ba02, - 0x2f71_97fb_33e0_2f3b, - ]), - pallas::Base::from_raw([ - 0xc6f5_fa79_26dc_55ff, - 0xb1d7_1d00_792c_b875, - 0x4300_1b82_b34b_fc81, - 0x2585_89f9_249d_35ff, - ]), - ), - ( - pallas::Base::from_raw([ - 0xca86_6954_84ea_c326, - 0x64d8_b454_7605_528f, - 0x47a1_1398_f1c8_6914, - 0x0626_f333_6694_8b96, - ]), - pallas::Base::from_raw([ - 0xcb9a_c695_8cdf_ac1a, - 0x51a2_395d_f28c_5a56, - 0x2982_997a_0143_8762, - 0x20a0_3634_e587_cdea, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4a22_3815_ad6a_af87, - 0xb23d_c239_fe51_f114, - 0xe744_6fbc_1d76_71f9, - 0x008f_b3c4_f277_6241, - ]), - pallas::Base::from_raw([ - 0xef35_ffbc_38cf_2be1, - 0x6406_1067_6e4b_152a, - 0xcd39_1b65_f743_55ca, - 0x33a9_ac54_8faa_2dc4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb43e_6160_16b7_ac1a, - 0x2d17_45fa_33dd_dbbe, - 0xfcf2_c7dc_158c_b996, - 0x222d_d6b4_22f5_41da, - ]), - pallas::Base::from_raw([ - 0xd15f_8eb6_6b9a_1971, - 0x735e_b437_8b76_de8c, - 0x7a9e_fd09_e21c_cb2f, - 0x2605_6891_36d0_47e3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa728_670e_b27d_0c27, - 0x0ffa_859b_d86e_09f4, - 0xfc12_1ddd_5bca_1d3e, - 0x3ed5_f5ac_9270_3915, - ]), - pallas::Base::from_raw([ - 0x2d66_ad9c_f3b0_9eb5, - 0x0f76_4a1b_3975_493f, - 0x311c_7d39_de6c_80e4, - 0x10c5_a910_538e_2161, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd8ef_2e55_08fe_449e, - 0x9795_f0b4_9b38_21dc, - 0x436d_3359_1956_ff92, - 0x2ef0_c2a1_ff67_562f, - ]), - pallas::Base::from_raw([ - 0xea61_5ac0_2396_252c, - 0xd3c3_e572_248f_f4ec, - 0x0891_5193_35ef_15f8, - 0x0e0b_7ddf_c509_d053, - ]), - ), - ( - pallas::Base::from_raw([ - 0x595f_7475_529b_3ad1, - 0xc202_93a2_e114_ef1a, - 0xa318_7931_4b87_03f2, - 0x25b5_defe_56df_8131, - ]), - pallas::Base::from_raw([ - 0x3207_683d_ce75_c89a, - 0x0aa3_95cc_ee66_6a3e, - 0x1d75_0d4b_db70_3a63, - 0x21a8_8c14_6d5d_50f2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf1a0_a157_fe44_54d0, - 0xe58f_ea83_b9a1_8e48, - 0xe75f_1ebe_b321_bd75, - 0x2ff0_cde1_263d_eb99, - ]), - pallas::Base::from_raw([ - 0x78ad_13cb_3871_d58b, - 0xd70b_f90a_dedf_4a15, - 0xce59_469b_4a86_1855, - 0x07d0_b9f2_d8b0_f8b3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1186_5fc8_3d94_8160, - 0xef33_cdf6_7d9d_f8ac, - 0x77fe_c81f_1b87_0816, - 0x33e4_5c8e_81bc_f208, - ]), - pallas::Base::from_raw([ - 0xa79c_f57d_5f8f_8039, - 0x46bd_dbab_182f_1e8d, - 0x121e_1e62_c3e6_2d1b, - 0x2aab_8626_7a08_126b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7309_5f4e_9257_4e26, - 0x800a_92c5_65c6_d0ab, - 0x959b_7396_8c33_df3e, - 0x1712_0abc_db9a_666e, - ]), - pallas::Base::from_raw([ - 0xa4ce_db71_dcbf_dda4, - 0x23a9_bb12_cc45_7125, - 0x4984_6598_5044_5012, - 0x15b9_a823_452d_151a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1881_58c9_d4f8_37b3, - 0x35e1_f53a_12ea_d4bf, - 0x43b0_1080_7105_9672, - 0x12a1_bb18_f6ae_aff4, - ]), - pallas::Base::from_raw([ - 0xd0c9_3a8c_6405_aeff, - 0x7c79_db4b_21ed_b868, - 0xfe64_ab4d_3285_580d, - 0x21f2_6e9b_4e96_4ad6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5ead_7427_d8bc_93be, - 0x1074_df9b_a240_dc10, - 0x5e02_f458_b883_e475, - 0x1658_9488_1a71_48ba, - ]), - pallas::Base::from_raw([ - 0xcf20_d6a3_30b6_e493, - 0xc050_fc5b_3e2a_b5ca, - 0xcad1_ca64_521c_4b4d, - 0x2d9b_99eb_4fa9_4da9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbf05_9e52_20ab_1fc0, - 0x8a7d_612b_8a1e_0e3a, - 0xeade_4244_f4cd_b38c, - 0x3331_7f8e_8124_54f2, - ]), - pallas::Base::from_raw([ - 0xc888_9b91_0593_4c5e, - 0xe569_c70e_0a7c_97f6, - 0x44d5_b9c8_f891_48f4, - 0x2312_5a5b_68f5_c72f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x94e4_bf9b_f2a6_1428, - 0xa590_5768_df89_f310, - 0x5f26_eac4_e6d7_bf48, - 0x1777_8461_3a31_42ef, - ]), - pallas::Base::from_raw([ - 0xd4c5_a93d_01a9_e944, - 0x00f3_0bb3_f382_1ab4, - 0x3e30_b05e_9001_115c, - 0x13aa_867d_0d62_d501, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0d77_6ee6_83d5_6884, - 0xc690_3133_0cb0_7fad, - 0x03f9_fa71_d83c_b6ac, - 0x385b_2c3f_69f2_2e4e, - ]), - pallas::Base::from_raw([ - 0xe52a_da77_f926_479c, - 0x4032_18dd_a3f9_f7d5, - 0x698a_ca67_0fe0_3b63, - 0x1be6_e46f_45a9_0d73, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb54f_2488_b34c_23f3, - 0x20f7_4d0f_dcf3_556c, - 0xb629_c46b_87ca_5183, - 0x3e05_1b07_97e5_4d7d, - ]), - pallas::Base::from_raw([ - 0x2845_df6b_a7f4_c4a9, - 0x01d8_7bb3_efc5_3212, - 0x7438_846f_f0c3_68eb, - 0x054c_4ccd_9568_783e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0e03_2b41_edf2_601e, - 0xca56_6380_2656_a1ab, - 0xa9c1_73f4_5b36_4aba, - 0x370b_f6a4_76fe_98c7, - ]), - pallas::Base::from_raw([ - 0xe83a_b9c8_7073_23c8, - 0x68cb_12fc_922c_e463, - 0x1d58_cba7_aae2_cd1d, - 0x1641_dcbe_d773_85ac, - ]), - ), - ( - pallas::Base::from_raw([ - 0x33d9_50b2_0786_8cb1, - 0x5546_4d24_79b0_1881, - 0xcef8_ae63_70b3_e7cf, - 0x1edd_0d6f_5654_df9f, - ]), - pallas::Base::from_raw([ - 0xca19_5fd2_3bf8_6d7d, - 0xd888_778b_481d_0c87, - 0x7718_4cb6_9a9c_a004, - 0x18cd_8422_c539_1785, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd3d0_061d_3c40_38a9, - 0x35d2_ba6f_b33a_337d, - 0x2b5a_ccd0_a048_8c8c, - 0x3177_51f9_70f0_55c8, - ]), - pallas::Base::from_raw([ - 0x7da0_2d46_e5dc_cf44, - 0x1948_7204_00fd_ac87, - 0xd35d_2f05_7952_09ed, - 0x067b_66e4_8fd4_40ae, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbe67_f5c1_c53b_6219, - 0x0c4d_d3eb_49dc_5141, - 0x1985_6e06_c83d_dc72, - 0x0580_4e34_6c60_f39d, - ]), - pallas::Base::from_raw([ - 0xd970_b5f8_e84e_2eca, - 0x8dee_bae7_6faa_0b0a, - 0xce36_460d_4c75_cfdd, - 0x0c0b_30a8_4eb6_c2ff, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd211_b3b4_85da_f337, - 0x7caf_c1c9_d176_8b9b, - 0x4f29_6d08_6aa0_6691, - 0x1469_1756_396e_e450, - ]), - pallas::Base::from_raw([ - 0x908c_5ebe_6cb7_9318, - 0x485e_123c_8a7a_1993, - 0xba9c_8297_dc30_544d, - 0x0b1b_b3c8_67ad_579f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfdbb_126a_9c89_8e38, - 0xeeb0_b9e3_24c7_e16a, - 0x2a63_649b_a4bd_3976, - 0x2cbe_8ae3_38cf_2e67, - ]), - pallas::Base::from_raw([ - 0x02c8_e297_4287_df10, - 0xfd4b_303a_ffcb_5e36, - 0xfe24_5d64_99c2_2680, - 0x2ad4_f003_ac6a_0942, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6366_45e4_5cf2_472e, - 0x581b_fa20_8c70_06f3, - 0x7f42_fc2f_a68c_53b6, - 0x3e5f_5c59_a596_3e85, - ]), - pallas::Base::from_raw([ - 0x3fae_7cd7_1795_7498, - 0x1897_f70d_330f_17cd, - 0x08bc_c4a8_93be_9624, - 0x16b6_5a70_880a_1196, - ]), - ), - ( - pallas::Base::from_raw([ - 0xecb8_a34e_6cfa_6400, - 0x872b_a68d_1737_b069, - 0x692b_8b56_4d30_00d6, - 0x1ac8_6b32_c2bd_28f7, - ]), - pallas::Base::from_raw([ - 0xcd15_73d7_4ab8_ecb6, - 0x10d8_d456_d06f_8959, - 0xc4d7_94db_40b8_a6a6, - 0x0fc4_1405_f622_01e8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb13c_4e21_fb86_cc29, - 0x6dd4_2256_220b_a841, - 0x485d_d357_9109_44f6, - 0x13e6_37f3_e85c_6236, - ]), - pallas::Base::from_raw([ - 0x393e_d2d6_d195_2520, - 0x8714_20e0_7d4d_41d9, - 0x4f97_e4c9_1b4d_d5a0, - 0x0ee1_6e26_9356_7999, - ]), - ), - ( - pallas::Base::from_raw([ - 0x18f0_e818_b67f_78c4, - 0xc78e_8276_5cfe_52d7, - 0x1029_108e_3372_5249, - 0x1ce7_779f_3e32_15bb, - ]), - pallas::Base::from_raw([ - 0x0a3c_2c79_69f4_7def, - 0x924a_5bd3_c10a_b277, - 0xa684_5102_3fda_00de, - 0x2848_c67f_8b86_351e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x785a_0070_6ef4_0a19, - 0xfc9e_e16d_1e79_450c, - 0x21b0_be13_8f13_ee31, - 0x205a_6e79_eb30_e515, - ]), - pallas::Base::from_raw([ - 0x109b_7b36_54cd_ff92, - 0xe219_fd76_bb44_d664, - 0x26dc_47f5_a4c6_cfd4, - 0x1396_0022_9638_8e73, - ]), - ), - ( - pallas::Base::from_raw([ - 0x284f_eee3_dedb_7e0a, - 0xeba3_d6d6_ab74_8634, - 0x206d_133e_7387_88b3, - 0x06e2_9444_0819_67d2, - ]), - pallas::Base::from_raw([ - 0x32f2_7745_dd5d_fa26, - 0x61b9_ff69_431d_6c7e, - 0x7b5e_c381_d868_ecdd, - 0x396d_b442_1b1f_998e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf09f_2925_09b3_435a, - 0x5dd8_7f72_700e_6289, - 0x428f_036b_3027_e4e7, - 0x3ba1_38ab_852a_c4c2, - ]), - pallas::Base::from_raw([ - 0x31eb_6ef7_e3a6_63c9, - 0x66fb_a519_222a_5eef, - 0xf056_ea85_d9a5_5f2d, - 0x0f9d_1a6e_42c7_af7b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2ed8_b60f_5a7d_5c4d, - 0x3c41_ec81_bb2b_0bd4, - 0x5162_51c1_cfd3_cc57, - 0x1628_f847_8492_257a, - ]), - pallas::Base::from_raw([ - 0x1028_dea0_df49_3ad2, - 0x9f64_8ee0_54ba_1f5d, - 0xa5c3_00a6_334b_5071, - 0x22ec_d647_4c9d_8dcb, - ]), - ), - ( - pallas::Base::from_raw([ - 0xba78_884f_a618_b4c9, - 0x2490_cfbd_ef1c_b8de, - 0x6262_4555_49b8_a7cf, - 0x22de_6c00_52d8_822e, - ]), - pallas::Base::from_raw([ - 0xb574_d8b6_4eb4_f13b, - 0x3ae5_7da8_c6fd_7491, - 0xd951_849a_c56a_d2eb, - 0x3d95_2743_8af5_bb67, - ]), - ), - ( - pallas::Base::from_raw([ - 0x423b_21c9_a9ae_e502, - 0xb560_584f_a159_372a, - 0xbde3_a652_e154_27f3, - 0x13e9_25ee_106a_6648, - ]), - pallas::Base::from_raw([ - 0x21c0_83c5_f051_3cd4, - 0x1aa4_9c06_bbfb_670f, - 0x003e_2620_a935_dec4, - 0x06d0_2c9b_fefc_d300, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1bac_349a_3968_df9d, - 0x4f7a_9588_dd94_8cf4, - 0x9c25_b2b9_425b_41da, - 0x34bc_c380_6706_0422, - ]), - pallas::Base::from_raw([ - 0x2e43_e508_767d_ab6a, - 0x8f2e_1357_30de_d522, - 0x1e5d_425e_7b9c_b97b, - 0x3b61_c068_3a4c_a1d1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2f22_1515_dc8d_33b3, - 0x8744_45d2_f4cf_5744, - 0xd439_9e9c_7a24_704b, - 0x0a48_d0cd_b7aa_cb6d, - ]), - pallas::Base::from_raw([ - 0x3265_a994_76ed_b4f8, - 0xad35_4f4c_83db_34fb, - 0x8c76_979a_0183_f56b, - 0x24c0_3c4a_383c_f34b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0264_48de_6bde_8f36, - 0x47df_c98c_065b_94cc, - 0x1bae_0086_8f7b_65d4, - 0x3725_ede4_49fa_fc27, - ]), - pallas::Base::from_raw([ - 0x0784_2c74_c2a0_abad, - 0x98b0_6931_a1fa_c65c, - 0xa0a2_f3f5_c5a0_d649, - 0x34e4_0ab4_f07a_f6aa, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc04a_82a5_985a_802d, - 0xf0dc_11c2_0ff2_f8e3, - 0xf99c_8842_c343_ab5b, - 0x1efe_d560_4943_bc1e, - ]), - pallas::Base::from_raw([ - 0x2b73_38af_72b1_7c87, - 0x7a76_3e90_131f_458a, - 0xf558_1a8c_ede7_797e, - 0x2160_887f_54e5_5248, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa806_7929_bd78_8219, - 0x4502_b7c2_0868_4ba6, - 0x1824_a713_12fa_8662, - 0x1d5f_eb68_ec9c_82c0, - ]), - pallas::Base::from_raw([ - 0xb50c_6fd8_a0ff_197e, - 0x1ecb_67c8_1a98_17ef, - 0x3802_668e_c3e2_e9ad, - 0x171f_bfe8_b8ea_bdc5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3804_32cb_1aa3_0b20, - 0x7206_9e76_128a_dbf5, - 0xfe30_6281_13f9_413e, - 0x3d95_faf6_a3c0_a23d, - ]), - pallas::Base::from_raw([ - 0x5c91_686d_7b70_5f0c, - 0xa432_25ab_ab76_f79a, - 0x1534_bae8_b052_0e10, - 0x1351_24f7_7d93_8a2d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd8a5_d43e_0733_a49a, - 0x59fc_166c_4df8_685b, - 0x6b2c_730b_481e_d580, - 0x0b74_b4c9_b3a5_8739, - ]), - pallas::Base::from_raw([ - 0xf7c3_af4c_034b_e968, - 0x280b_4dd1_da46_b742, - 0x817c_6343_92a5_2bf1, - 0x20c6_7219_0fa4_fd21, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9b9a_5d85_cc8c_cea9, - 0x8a3a_db6c_635f_69e0, - 0xd9e9_bb8c_1560_1184, - 0x1dcc_4260_292a_b5ee, - ]), - pallas::Base::from_raw([ - 0x1291_c646_f66d_6966, - 0xd0b2_d860_6baf_fadc, - 0x5fe4_42f8_21f2_398e, - 0x1b97_d042_35eb_620c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9111_47ed_8621_b0cb, - 0x15d9_a0c5_9075_13d4, - 0x55b6_8241_f6b5_5714, - 0x388f_21cd_bdba_18a8, - ]), - pallas::Base::from_raw([ - 0xd7f4_b6ed_57dd_0be9, - 0xc659_dca1_c72f_718f, - 0x673b_b001_0480_c230, - 0x089f_3734_b014_2b1d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3fef_e211_66f0_64d3, - 0xab1e_a692_2b23_fe74, - 0xabcc_16b8_5b13_edd3, - 0x2f1e_5892_5bfd_9702, - ]), - pallas::Base::from_raw([ - 0xe111_5ff5_cd6b_6e0c, - 0x3b8e_6060_6a62_c9d3, - 0x2a71_2c0a_2329_962a, - 0x398a_1f1d_e5c2_a3b5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb1f7_5faf_516c_5527, - 0x1834_e411_a954_5d74, - 0x5a3d_8f22_5192_48e5, - 0x0c9b_5c3b_99e5_e2e4, - ]), - pallas::Base::from_raw([ - 0xc519_1b97_cd4c_9178, - 0x3d1f_2cfd_ec1d_9f37, - 0x77ea_1ab5_a674_9b12, - 0x1c54_7537_1a50_9219, - ]), - ), - ( - pallas::Base::from_raw([ - 0xeb48_bb7c_bdf0_eca3, - 0x3818_af8f_3f8a_23f9, - 0x1225_2bc6_8251_52c2, - 0x20f2_231c_6b91_756b, - ]), - pallas::Base::from_raw([ - 0xe56c_b770_41bc_64df, - 0x6507_3efb_ec7c_88eb, - 0x4db8_fc10_e0e3_e9a3, - 0x25f5_aa8d_7ed0_e37a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x989d_1174_c5b5_1592, - 0xbc22_de23_d318_4f3d, - 0x0d74_e3e1_c30c_9216, - 0x3c9f_46e6_9974_ef0e, - ]), - pallas::Base::from_raw([ - 0xca71_bc9f_274e_a68f, - 0xda0a_f4d4_b787_77b0, - 0xe011_197f_5425_5452, - 0x02bc_1f24_5fad_07ce, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf66e_e106_a081_b017, - 0xbda0_9fb9_141a_ed66, - 0x8d9b_85d3_a5b2_218f, - 0x3368_44df_9aa0_5205, - ]), - pallas::Base::from_raw([ - 0x21cb_9ec2_7a50_283e, - 0x6526_eb8d_8a98_355e, - 0x4625_6651_5a5b_5bd2, - 0x0dcc_cfa2_eabb_31aa, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdf01_ebdc_d5d5_1078, - 0xdce7_4ffe_4597_40a9, - 0xec30_c721_88d4_926f, - 0x25f4_e3ba_66d0_0bd2, - ]), - pallas::Base::from_raw([ - 0x1aa4_cf28_305d_bd48, - 0xf1ac_ed41_29c5_2fce, - 0x6a79_ae99_419d_2023, - 0x287a_ccc2_aba7_dda2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf6c9_67b1_61e4_3701, - 0xba59_4171_cf75_314a, - 0x2366_fd0c_9845_d326, - 0x07ea_75ef_2e55_1043, - ]), - pallas::Base::from_raw([ - 0x5f6a_b363_1d50_02b3, - 0x42a7_f1d3_8df7_1886, - 0xb175_5fda_e244_41b1, - 0x06d8_b881_47e9_e884, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7760_0ee1_2469_f797, - 0x9d28_9411_63cf_2100, - 0x94f5_d9bc_1e38_d7ac, - 0x0d9d_a8ed_2348_f1d8, - ]), - pallas::Base::from_raw([ - 0x9dcb_1045_7ef9_4381, - 0xf26f_888e_41de_250d, - 0x4db4_569e_a5be_98ff, - 0x2c6e_26fe_e783_b1b6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8252_2117_8b68_e77e, - 0x62b6_4c04_daaf_0edb, - 0x56fc_ef6a_c5ce_9b21, - 0x0060_2183_26a9_b20f, - ]), - pallas::Base::from_raw([ - 0x9381_f756_c758_57be, - 0x2c64_8722_e9b2_aad0, - 0xd21d_fa97_22b7_899f, - 0x37b3_34ab_36d1_3b97, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1dca_d2a7_c9ac_257e, - 0xf481_bd41_dfde_561e, - 0x7fb9_5d59_e14f_9ba1, - 0x164f_e5ae_3a75_5ff1, - ]), - pallas::Base::from_raw([ - 0xd85d_2380_04ed_04b9, - 0xf0a2_f4ca_240b_67be, - 0x328d_6539_b137_e8c0, - 0x1f91_7ad2_3c72_2938, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7c1a_1f69_511d_ddc8, - 0xafef_22d0_8a93_c6bb, - 0x6b7d_de6e_5dfb_8e86, - 0x0418_14fb_9b1b_1fdf, - ]), - pallas::Base::from_raw([ - 0xc232_8d8d_5ade_ee19, - 0xfccd_233e_1faa_328c, - 0xb74a_eb62_bfd2_085d, - 0x349b_497a_e2da_b674, - ]), - ), - ( - pallas::Base::from_raw([ - 0xee76_492e_de05_8c40, - 0x9667_cea9_6321_0dfd, - 0x9ffb_dfe7_bbaf_4d78, - 0x024a_7f47_bbf2_edfb, - ]), - pallas::Base::from_raw([ - 0x2798_9453_54c0_b6a6, - 0x0258_04f1_e97c_9306, - 0xa589_745b_f70f_31f8, - 0x2980_753e_d2a0_1bd5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc217_79ea_fb8d_cf1f, - 0xc7d4_3d68_74e8_1a99, - 0xdf4e_e87a_3da7_0225, - 0x2674_6664_7ec0_66ec, - ]), - pallas::Base::from_raw([ - 0x9a08_438d_3e66_71ff, - 0x2597_f5fd_7ef0_e033, - 0x3490_d2b3_16e4_336b, - 0x0af1_68b8_2ce5_50d0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9ee7_3ace_ad81_d7b9, - 0x7f7d_4d51_c420_2287, - 0x7ea4_8cda_f72c_21d5, - 0x3ba5_ab89_7c05_9262, - ]), - pallas::Base::from_raw([ - 0x65a7_2df6_e7af_1f62, - 0x5018_7079_ed87_6e01, - 0xdd49_7bac_b2f8_f533, - 0x2305_b1e1_10ca_8348, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7bb8_856e_6f81_0866, - 0x2910_87a6_3558_342c, - 0x0197_f6a1_a5ec_2aee, - 0x2e3f_0e84_be82_a936, - ]), - pallas::Base::from_raw([ - 0x24d2_4f23_defe_d26e, - 0xa6a3_fdcb_e123_531f, - 0xf554_544f_9059_9b7a, - 0x1b2b_2c74_2c05_d788, - ]), - ), - ( - pallas::Base::from_raw([ - 0x77aa_8cc5_e75f_61b7, - 0x7ab0_d22c_2c7a_225d, - 0x261a_0bae_d904_6233, - 0x23ca_5427_dfe6_fe96, - ]), - pallas::Base::from_raw([ - 0x3965_f126_8be5_f4f1, - 0xfbbc_f05d_19e0_4468, - 0xcf20_7a1a_dda3_da90, - 0x2dc1_38b3_e758_ae9f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe4cd_d4bb_51f1_3a97, - 0x0ae0_b307_d947_f166, - 0x95c1_0d80_9554_61dd, - 0x2663_0dcd_f58c_a26b, - ]), - pallas::Base::from_raw([ - 0xec69_76ce_7f25_e7fb, - 0x21f1_ef67_603e_b2b9, - 0xb538_45ae_65dc_d7ef, - 0x006b_e5d2_3475_d4f0, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd937_daf5_c74d_37b5, - 0x7b6f_ad60_d7b0_78d4, - 0xeaa2_48f9_cc19_2e8e, - 0x1bff_9849_3f9c_61f3, - ]), - pallas::Base::from_raw([ - 0x1eb4_de71_6993_79b8, - 0x1631_ada7_84b0_c628, - 0x00af_5200_06fa_74cc, - 0x1497_0f48_9ac5_2a83, - ]), - ), - ( - pallas::Base::from_raw([ - 0x585d_8ca2_b07b_c36c, - 0x6a0e_125b_b3fb_3153, - 0x1656_99d8_a31c_48e5, - 0x0c90_2843_2d3d_2ecd, - ]), - pallas::Base::from_raw([ - 0x37b6_c3aa_0a9f_0553, - 0xe75f_7c83_3b31_0906, - 0x0b28_1359_fedd_80f0, - 0x2aea_f21d_78e4_2ae7, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf905_b492_f098_abbb, - 0x91e7_32ad_153d_fbb9, - 0x23b7_9b3d_c26f_956e, - 0x30a8_6999_b4de_0802, - ]), - pallas::Base::from_raw([ - 0xab98_1e4a_ef1a_ce80, - 0x3e6a_1ab7_cc7f_76f7, - 0xfcfc_ac90_b0a9_24bd, - 0x290c_7b1a_b364_d9f0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x89d2_5903_1495_2310, - 0xb8f6_4793_e3fe_9b02, - 0x1298_314c_1048_dded, - 0x35f6_6aef_3f87_5f47, - ]), - pallas::Base::from_raw([ - 0x7f09_c9ec_4e0b_9a00, - 0x02e5_58a8_8b63_c5e8, - 0xdff2_a2ab_eb34_d24d, - 0x182a_04c6_61a5_3ea5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7749_9a48_5a8d_c3c0, - 0x7301_8bb7_d60b_54a8, - 0xbd74_5aec_e134_f4d3, - 0x0ce6_4340_9896_9f25, - ]), - pallas::Base::from_raw([ - 0xb214_a94a_a5e8_5ac9, - 0x3a7b_00db_2c5b_71bf, - 0x1f1f_97e9_4a95_3ea7, - 0x0fdc_1f13_90f2_bdc3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfd7b_3712_3634_9249, - 0xb29c_31f6_a23e_e901, - 0x428c_09b7_ab6a_19b0, - 0x3edb_6eac_7f4a_7fc3, - ]), - pallas::Base::from_raw([ - 0x41ae_5f62_33d0_39fe, - 0x351b_2fad_6a83_3fae, - 0xb027_de87_dc3c_abd6, - 0x1c3c_6b89_8ff4_fbe6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8579_eab4_36d7_7379, - 0x6976_f60e_a7ad_6a4f, - 0x4d44_0486_bd7f_82e0, - 0x33df_087b_d169_6b33, - ]), - pallas::Base::from_raw([ - 0xd8ae_253e_7704_e1b1, - 0x6c80_3c98_5ca9_cb72, - 0x4f76_0a94_7173_e72a, - 0x1749_3c2a_a576_b53e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0d8d_9ce3_bee5_d2a8, - 0x3b11_1e32_1416_7ec7, - 0x866a_5644_f7bc_2429, - 0x2f53_e65c_d670_6b69, - ]), - pallas::Base::from_raw([ - 0xc9bc_a98d_5327_54b9, - 0x1c20_0a22_3360_ac52, - 0x8fd1_441f_3249_5f67, - 0x0891_e7a6_7b7a_a04c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x33ac_b0c2_3336_e65e, - 0xe9bd_f7b7_365f_b280, - 0x3fdb_301c_b124_359c, - 0x225c_f8a4_48fb_0bfc, - ]), - pallas::Base::from_raw([ - 0x7bd0_525c_7c01_37f5, - 0x25cc_2e9e_5ef5_3cac, - 0x0abf_86e7_33f6_5865, - 0x25ec_f837_9bd5_34fd, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1959_74df_433a_0d39, - 0xf92a_d555_fe66_45c1, - 0xde22_fe69_6b67_05a3, - 0x30c6_33cd_5289_cf7f, - ]), - pallas::Base::from_raw([ - 0x2de2_06ae_215b_cdb9, - 0x1dba_733a_5d1c_f06f, - 0x7795_0562_7c29_07b6, - 0x2e05_a443_58f8_295f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8c8d_3e5a_0e9e_27e2, - 0x33a7_ac34_3383_9ad5, - 0x813a_ef88_67ca_27f2, - 0x0351_82c5_aa57_93ea, - ]), - pallas::Base::from_raw([ - 0xe37a_d328_0519_9e75, - 0x9492_ecb8_7225_4d8f, - 0xe440_0d58_32d9_3b4f, - 0x23d7_f634_31de_0e04, - ]), - ), - ( - pallas::Base::from_raw([ - 0xed93_fc4d_8b7c_d2c7, - 0x2ff9_e82a_2813_1039, - 0x9b41_402f_8edd_7482, - 0x2de8_408a_e87c_5526, - ]), - pallas::Base::from_raw([ - 0x8482_7aee_9078_6f5b, - 0xfca5_1acc_7aa9_8a6f, - 0x3b26_c0d8_1fb1_7641, - 0x1e97_cfa5_3430_ce4f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x28d8_3f6f_dd30_2e4b, - 0x8b33_1616_df48_b162, - 0xeb66_7f0b_abbe_d5c6, - 0x1bb4_9f7d_2f00_992d, - ]), - pallas::Base::from_raw([ - 0x8f1b_2585_5975_5b8f, - 0x992a_5645_ac44_49a4, - 0xc7f8_a778_378a_878e, - 0x2388_d495_aa9a_2f14, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb3ee_832b_cca6_e15c, - 0x302e_0976_d09c_f5b0, - 0x3b73_c911_07ca_0590, - 0x1033_729d_e32a_20e5, - ]), - pallas::Base::from_raw([ - 0x824d_03c9_62ab_fb97, - 0x3376_05c3_fca4_da48, - 0xd938_5b92_c1b1_eb7b, - 0x04e9_d53b_9dd7_0353, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2a31_ceea_2bfe_1b89, - 0x459c_7864_3eed_fab2, - 0x8015_ebda_9a08_21f7, - 0x3176_5d48_ed2e_8f38, - ]), - pallas::Base::from_raw([ - 0xbbd2_e12e_2200_a567, - 0xee7e_8b8e_60c9_3161, - 0x4450_13a8_b51e_a17f, - 0x3fb3_ea3d_413f_600f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5792_e1bb_65af_5499, - 0xf38e_ecce_d9d1_90db, - 0x782e_777f_aef9_a1ed, - 0x3275_1af6_d47e_89f4, - ]), - pallas::Base::from_raw([ - 0x0558_8657_d79c_9fac, - 0x4cfc_fa59_c797_3faa, - 0x46ec_529c_3e3a_e025, - 0x2e88_9fc7_1cfe_b590, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4f36_5a89_27df_98cf, - 0xdc4d_ad2a_e1df_90d4, - 0xe8c7_f8c9_f534_a3a6, - 0x1f53_db72_546f_88b1, - ]), - pallas::Base::from_raw([ - 0xc521_f710_64f3_458e, - 0x55f4_b813_b4eb_ca44, - 0x1fbe_fca1_69c2_c1f7, - 0x3270_72d0_0569_db08, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe51c_bf5e_4534_c30a, - 0x9f11_38fe_5b82_ac9b, - 0x31e5_618e_64c9_6740, - 0x1626_a008_8065_ae1f, - ]), - pallas::Base::from_raw([ - 0x4e4f_35ca_0362_3b2b, - 0x589e_4ec7_4b43_ca66, - 0xadfc_a852_9739_1779, - 0x3ec9_c8c2_307f_b4fc, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe558_1772_2b26_fcc5, - 0x8cd2_78c7_57d7_bc6b, - 0x216f_0ed7_5683_8c13, - 0x2bad_b214_0ca1_67ef, - ]), - pallas::Base::from_raw([ - 0x7b8e_54ac_bde4_5d74, - 0xf12b_ee08_f085_ef2b, - 0x59be_cb38_9bb3_7cba, - 0x10c2_e53a_d289_3205, - ]), - ), - ( - pallas::Base::from_raw([ - 0x05bf_6073_a2cc_922b, - 0xaa40_a1b1_c161_a6f5, - 0xe7aa_a199_d7b3_f2be, - 0x2ec8_895a_ff5b_5376, - ]), - pallas::Base::from_raw([ - 0x21a9_2a6f_5c37_ad34, - 0x9ed0_8f7e_4c30_d354, - 0x0c92_ae6b_73d0_ddf0, - 0x02af_e3c9_f6d8_8524, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa364_1c63_2ef7_445f, - 0x1601_4441_ab17_06e9, - 0x5e0c_e5dd_d268_6d5c, - 0x2962_bd56_585a_49b2, - ]), - pallas::Base::from_raw([ - 0x8f33_3912_6908_c490, - 0xb337_01a1_f6fb_f2c6, - 0x5b5d_ed95_d5a1_587e, - 0x175a_30c9_9d0b_dcfa, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf982_0b5c_aa89_84ec, - 0x8cd5_6f8a_04f7_0000, - 0x45bf_1e43_42e6_c668, - 0x2b33_5ef2_cfc8_0c83, - ]), - pallas::Base::from_raw([ - 0xd28e_8c9a_a973_eb4c, - 0xfc8d_633c_c565_5eb8, - 0x49f8_808f_b1f8_2460, - 0x26df_2492_c732_e56c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xcc02_e14a_ed10_15df, - 0x7ab2_e6da_6148_1b32, - 0xf1b8_ccf5_7959_7c1f, - 0x1f39_1c76_d2a5_87d4, - ]), - pallas::Base::from_raw([ - 0x6161_8e3c_c900_c078, - 0x8051_d2da_5db8_ca06, - 0xf00c_bba6_4a81_7e59, - 0x0212_f279_9961_28a4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xba12_bea4_1ed1_352d, - 0xc72a_1238_3074_4e06, - 0x774b_4680_7bce_521e, - 0x1b55_f307_4483_1944, - ]), - pallas::Base::from_raw([ - 0x4339_05b5_7199_f756, - 0x5018_a2d2_8374_18cd, - 0xc369_3735_482c_e33f, - 0x06d1_33c4_e935_ed22, - ]), - ), - ( - pallas::Base::from_raw([ - 0x17d2_e055_42f8_9a6b, - 0x63c4_572c_834a_9911, - 0x7c98_197d_30e9_06b9, - 0x1bb8_0e9c_7b1c_a773, - ]), - pallas::Base::from_raw([ - 0x757f_5677_f5dd_82dd, - 0x6030_5392_57bb_182b, - 0x22e8_e711_493b_46f2, - 0x2462_9d6c_1107_6339, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc227_0007_0d48_67fa, - 0x5a14_a6ed_8e5a_164c, - 0xf31b_979b_e4fa_a4dc, - 0x2260_9c32_ae8a_2fe1, - ]), - pallas::Base::from_raw([ - 0xcbbe_cd59_36ba_6c7a, - 0x768f_7786_ddb9_39e0, - 0x8ee0_8603_e206_e123, - 0x14f1_bb3e_19ad_9852, - ]), - ), - ( - pallas::Base::from_raw([ - 0x36cc_d0fe_865e_1f8a, - 0xd12a_6df1_2f9b_0183, - 0x8fc1_7986_8075_3758, - 0x230a_a792_feb2_5fa6, - ]), - pallas::Base::from_raw([ - 0x2489_a5cd_0cc0_bae0, - 0x6f0d_c5d3_924f_4676, - 0xea2a_6502_9734_9b71, - 0x2596_75b5_6bcd_40ed, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc111_adf6_14ce_6cb0, - 0x4aba_0e21_bab9_0092, - 0x99e9_d9dc_1d39_ead0, - 0x1d84_4ec6_9215_ea84, - ]), - pallas::Base::from_raw([ - 0x665f_32ce_34d6_3a28, - 0x166d_7faf_b4f3_51da, - 0x71f2_1dc9_4a3a_0837, - 0x1cbd_dd75_d802_7a07, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbb16_0c4f_b407_3444, - 0x4f4f_3c61_ac00_a4f7, - 0x3c3a_271a_012b_988b, - 0x1b4d_4160_2bd3_ae10, - ]), - pallas::Base::from_raw([ - 0x61f2_9112_22f7_b25b, - 0xd2e6_eee7_d3df_2364, - 0x156e_24e6_a1ef_9b96, - 0x2cc4_b4f6_2b98_9419, - ]), - ), - ( - pallas::Base::from_raw([ - 0x90ad_379e_cf99_5052, - 0xfdd3_5b06_452e_f10f, - 0x3231_9fe1_ccd6_5847, - 0x37d6_0e5c_6f9b_157d, - ]), - pallas::Base::from_raw([ - 0xef5e_4b6d_8a11_3611, - 0xfff2_8aed_9719_e68f, - 0x0022_f704_2bc5_4b86, - 0x24d1_1739_87a0_150f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x67b6_a004_5b76_df29, - 0xd780_7758_5dd1_72c5, - 0xfd94_bada_1b47_6147, - 0x055a_ef12_3bb1_7975, - ]), - pallas::Base::from_raw([ - 0xc40d_7914_b6fd_0059, - 0xcd4b_03e5_9621_c0cf, - 0x5804_3959_aa1b_5cb4, - 0x399e_7d93_333c_9f5c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe987_36b6_6ff3_a8f3, - 0xb633_6b7c_e2d0_1c29, - 0x72b5_e138_e871_8594, - 0x39e3_1af0_f759_2d94, - ]), - pallas::Base::from_raw([ - 0x2584_aad2_a9e9_6991, - 0x4d67_c9b6_57a0_00f8, - 0x1fef_7c39_245d_f66b, - 0x39a5_61f5_b60e_13ce, - ]), - ), - ( - pallas::Base::from_raw([ - 0x12a8_2bb3_679d_2e7d, - 0x7923_949d_cf92_266e, - 0xb997_e0d1_8eda_a746, - 0x2722_d4bf_937a_919d, - ]), - pallas::Base::from_raw([ - 0xdcc8_3afd_5c79_7391, - 0x25a7_833d_a733_98ac, - 0xd82e_903f_c00f_3f8b, - 0x20b2_7ae6_263f_b41a, - ]), - ), - ( - pallas::Base::from_raw([ - 0xef97_ec2a_52ec_aaab, - 0x6456_0e73_b84c_0532, - 0xf42e_0f1e_2164_9dbc, - 0x362d_769b_3e3b_429b, - ]), - pallas::Base::from_raw([ - 0xa849_45d4_8229_07c7, - 0x8319_319a_9dfd_eb24, - 0x1b53_33bd_832f_9d47, - 0x1a8d_4605_440e_14eb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2cfe_f055_520e_c484, - 0xd39b_1ad9_5e10_8589, - 0x1aaf_3ba7_8102_4b08, - 0x39c3_c628_22fe_6009, - ]), - pallas::Base::from_raw([ - 0x45f8_894e_2232_67ac, - 0x4296_0ed4_94f2_d879, - 0x91c3_5975_0a2e_a628, - 0x0055_3f58_2ea2_b9d8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9dd7_97f4_738d_a24c, - 0x2759_7dca_3390_3158, - 0x2569_cf2d_55e1_3988, - 0x3a35_4403_855a_ecc7, - ]), - pallas::Base::from_raw([ - 0x8cd4_53df_2421_8d58, - 0x3eb8_606a_39df_7bba, - 0xe1b6_b3cd_016d_2c04, - 0x2ac0_1e01_122f_2859, - ]), - ), - ( - pallas::Base::from_raw([ - 0x05ee_bec3_ee74_bbef, - 0x9235_beb6_d261_7620, - 0xbe1b_e89b_c34f_92fd, - 0x3e52_f01c_752c_b88b, - ]), - pallas::Base::from_raw([ - 0xf3a9_51ca_cd8a_af53, - 0xc74a_97e4_097e_c343, - 0x092e_9e05_bffc_9a22, - 0x3d5a_5fc8_11e3_ba39, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0ce5_3d2c_d538_3a58, - 0x3ef1_eb32_6ca3_e72f, - 0x3c78_7688_7698_fc9b, - 0x3e74_cad7_49d2_c6c6, - ]), - pallas::Base::from_raw([ - 0x1f1c_faed_0c97_13d5, - 0x3c44_cdd9_d43b_1878, - 0xa99e_49e2_45a6_8dbe, - 0x3d13_8bac_6757_2e90, - ]), - ), - ( - pallas::Base::from_raw([ - 0x83f7_da35_d76e_c72f, - 0x5d1b_36e6_359e_06e5, - 0x4467_a198_0e08_1507, - 0x3416_e9d4_12cf_fc58, - ]), - pallas::Base::from_raw([ - 0x2730_0907_8ed4_7765, - 0xb022_0ab4_912b_7d90, - 0xb416_bc2b_6319_e9c9, - 0x10fa_d4cc_a19a_342c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa6ce_2794_9121_884f, - 0x92a8_a18f_02e8_8e44, - 0xcadf_04d1_3995_43e9, - 0x35f2_987c_a27e_1776, - ]), - pallas::Base::from_raw([ - 0x4f73_1ea3_e5d8_f863, - 0xbefa_b1c9_dacb_8028, - 0x91bd_d4ef_ab4e_02d4, - 0x39ea_3c5e_6cb8_47ec, - ]), - ), - ( - pallas::Base::from_raw([ - 0xba0e_d638_9040_a526, - 0xade3_6a2d_1046_ce2f, - 0x07c4_031f_7d63_bfda, - 0x3705_7fe5_eff1_6d4b, - ]), - pallas::Base::from_raw([ - 0xcb3d_da9a_230f_7d4f, - 0x3ec2_fac7_acc4_e22c, - 0x09bc_83c8_6022_52ca, - 0x01d7_c169_7b90_1850, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0316_2275_7062_aa8b, - 0x06e7_bf78_c301_eb68, - 0x5a45_ea8c_518d_e8fe, - 0x1a8b_f176_fdd8_5a16, - ]), - pallas::Base::from_raw([ - 0x1de4_ed97_6261_3da9, - 0x7c2d_265b_75a5_c58e, - 0xdecf_84e1_13a6_493c, - 0x1853_c9ac_fc18_1ad9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x18f8_f690_da5c_857a, - 0x8baf_5e54_f47a_4c66, - 0xc596_5adb_9056_e487, - 0x0b41_5e4f_c50b_4723, - ]), - pallas::Base::from_raw([ - 0xf758_8e8b_d1c1_5233, - 0x3bb8_512d_7b1e_a04e, - 0x3782_0e10_b3da_73da, - 0x2c2a_1026_015a_e0af, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc491_0da2_ab40_38fa, - 0x8919_0bf6_2117_4bb0, - 0x11b6_3346_fe70_1c31, - 0x01e3_fd81_583f_9350, - ]), - pallas::Base::from_raw([ - 0xdc61_17c0_98c1_601e, - 0x1ab5_a27b_e45e_f81e, - 0x52a2_3f16_f37e_1612, - 0x0b0a_7f80_97e2_e6cf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x520b_062f_e78a_e7a4, - 0x3cfd_2ac9_15c5_e15e, - 0x6f6f_0d82_41c1_d542, - 0x3d45_bbb4_6013_9f32, - ]), - pallas::Base::from_raw([ - 0xb1ac_5c97_c97a_3879, - 0xef0c_c0f2_56ab_5321, - 0x622a_376f_e184_60c6, - 0x0529_7efd_374c_32b5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc226_4973_4c5f_c60a, - 0xda93_2f28_b15a_50e6, - 0xcce7_e413_9c75_ced4, - 0x2a0a_7edf_84f3_ca0c, - ]), - pallas::Base::from_raw([ - 0x97e9_ae4d_cf51_e9c6, - 0x7763_6a76_34f8_eb62, - 0xc1db_731f_15d6_84d7, - 0x28ae_45a0_2811_2280, - ]), - ), - ( - pallas::Base::from_raw([ - 0x48e1_7904_526f_f906, - 0xd5fd_96af_3118_d25d, - 0x16f2_1379_295a_3e85, - 0x056e_6682_1209_f065, - ]), - pallas::Base::from_raw([ - 0x4d09_3b0c_18f0_4853, - 0xf28c_aecf_c757_36ed, - 0x0124_3cba_966f_a69b, - 0x2bf0_69d1_a8f4_e195, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa2ab_2ca3_3f7a_8c18, - 0x5fbf_9a9e_292c_3fee, - 0x42d2_fb9b_62d4_bf6f, - 0x1513_87c4_5019_b2a8, - ]), - pallas::Base::from_raw([ - 0x45de_0a99_709d_8f92, - 0x013b_c62b_f18c_2d51, - 0xdc17_e477_e451_a5b5, - 0x189b_e9b3_2748_ccfa, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb1d2_10c0_c338_3697, - 0xdde9_1ff0_0a98_9f1e, - 0x57b1_5511_fac4_ae0b, - 0x3415_5509_eda9_fb3a, - ]), - pallas::Base::from_raw([ - 0x0336_a0e4_4d04_f2a0, - 0x0c38_8030_f51d_1168, - 0xdb88_0218_359b_52b6, - 0x1669_7954_3729_1904, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf754_4d39_2e15_d646, - 0x042c_85b5_e75c_bffe, - 0xe38b_c7e1_c3a3_371e, - 0x1f78_4954_3955_3ffd, - ]), - pallas::Base::from_raw([ - 0xb3b0_03ef_ce95_fe55, - 0x3447_f020_3e43_a221, - 0xd3ec_5b00_f101_a4a7, - 0x1daf_fb55_fdca_e9bb, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd022_b2e4_3b43_5771, - 0x1f98_8073_0dae_5fa9, - 0xa19c_1dae_ee9d_2279, - 0x2d7c_10f1_1f8a_fbe2, - ]), - pallas::Base::from_raw([ - 0xe53e_4dc4_e5c6_9e51, - 0x2af4_1c7b_e73c_bfc3, - 0xf0e0_1136_6a8b_7018, - 0x0b77_44c8_8c77_fcbf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9ed7_be62_3b40_bcb9, - 0x3e31_f660_58df_eb96, - 0x0158_90c1_6331_430d, - 0x21ad_7eae_f186_64a9, - ]), - pallas::Base::from_raw([ - 0x4997_85d6_de57_f60b, - 0x3a83_9c1d_c46b_2861, - 0xaea4_ad0e_e1cd_df9a, - 0x2472_290e_1d0b_53b2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa73e_3284_1eb0_d3cf, - 0x5dd2_c1b8_16cb_cd57, - 0xac16_7859_a9c2_66b6, - 0x39d0_2f80_ee2f_5fdc, - ]), - pallas::Base::from_raw([ - 0xf33d_b523_81f4_08e5, - 0xa267_d464_ddb6_94ce, - 0xde0d_2c54_83af_3f7a, - 0x3105_d9d7_4eb0_8afc, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0f06_d3f2_ae51_741c, - 0xb747_9d5c_a4b9_5a80, - 0x7839_36ab_4715_89b0, - 0x17e1_7cf7_cf73_abce, - ]), - pallas::Base::from_raw([ - 0x228e_32f0_7e39_0ca6, - 0x92fe_35e7_744d_16a8, - 0x235f_5e1c_a1d9_dfa7, - 0x2adb_4c5b_3bd6_6726, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5819_6066_3266_3841, - 0x24da_b91e_6b28_9f04, - 0xb79a_cf49_63a4_4105, - 0x21da_e5c6_0cb6_7703, - ]), - pallas::Base::from_raw([ - 0xa223_487e_6406_576e, - 0x86b6_9d9e_7467_7eb2, - 0x7e2e_531d_048b_6ae2, - 0x1796_bb64_46b9_0567, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6b90_eb45_561d_04dc, - 0xe743_9460_131c_ae9a, - 0x2735_4e72_d3b1_3274, - 0x181b_8996_1ce6_dbf2, - ]), - pallas::Base::from_raw([ - 0x4393_a574_6e7d_ebcb, - 0x17b9_57b0_374b_7321, - 0xf48f_1499_0aeb_f4ff, - 0x2af0_a0cc_80d8_ad59, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8a86_d29c_9a81_c5a9, - 0x2393_6d2f_411a_1f97, - 0x50f6_242a_40fa_9525, - 0x05b0_faf1_c315_0a4b, - ]), - pallas::Base::from_raw([ - 0xc70c_9a93_ab83_1c95, - 0x6ed2_9ae9_ceea_efb1, - 0xc7fe_68b2_22e1_cf03, - 0x381d_cfd0_1918_44b4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7d5a_3127_5dbe_b7d9, - 0x79e0_3de5_25ce_dab6, - 0x935a_02dc_9fdc_eab4, - 0x2b4d_4719_7811_4448, - ]), - pallas::Base::from_raw([ - 0x7673_78df_e2fe_1eb2, - 0xbe91_9301_c9aa_5f18, - 0x60ee_48c0_4796_a28e, - 0x2f24_3e8c_7b7f_4693, - ]), - ), - ( - pallas::Base::from_raw([ - 0x58ac_fcec_3b6a_6302, - 0x778c_ceb2_8a49_ffb4, - 0x8c28_f55d_2771_8a04, - 0x3c4e_cb86_6f24_7db3, - ]), - pallas::Base::from_raw([ - 0x7fbe_d4df_7b3f_fc86, - 0x8540_6cc9_d470_f2ed, - 0x0bef_5e3d_830e_0220, - 0x2c60_c874_457a_d78e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2fb1_b9b7_f918_5676, - 0x3b9c_0985_f979_e385, - 0x3c64_e299_b19e_df3f, - 0x38c6_03c7_f4c2_e21a, - ]), - pallas::Base::from_raw([ - 0xb328_4e4b_3bc3_34f9, - 0x1a14_4a9d_9ca6_9b21, - 0x8d0c_c279_4992_b9b6, - 0x0ce6_19ca_d57c_1085, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9555_d1a8_a695_617a, - 0x9f38_43fe_8064_4c5e, - 0xa495_35cb_8d85_c2e7, - 0x2d01_2113_eb7c_976f, - ]), - pallas::Base::from_raw([ - 0xb4b7_72bd_6491_50b5, - 0x45dd_d92f_bdeb_1fd5, - 0xedaa_6443_41d8_1b41, - 0x2966_c1c6_12e0_0292, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6095_00b2_ffd5_9f23, - 0xc0c2_61ef_b258_de48, - 0xcbcd_b97b_51c2_00ac, - 0x0bef_2f3a_5b4a_70a6, - ]), - pallas::Base::from_raw([ - 0x69f9_ffcf_df73_c226, - 0x3c86_f51d_5b51_5ddf, - 0x0826_406c_ef5e_e020, - 0x05f0_31fe_225f_e8c9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x314d_d52e_0919_736c, - 0xf554_b5ea_55e9_39ff, - 0x7775_a5d8_d07f_9f27, - 0x18b9_43fb_57be_afd4, - ]), - pallas::Base::from_raw([ - 0xf563_1374_8745_63e7, - 0xbd1c_a9d6_622e_8cd2, - 0xd060_6006_611b_cc4e, - 0x360d_025e_38f6_02a0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x399e_2e74_4e2d_d3b9, - 0x43e3_74f8_8b83_0cba, - 0x4289_a1c4_48cd_f4e0, - 0x196d_f315_b594_9716, - ]), - pallas::Base::from_raw([ - 0xc288_6cd6_673f_4deb, - 0x21f2_2728_b89f_4ed3, - 0x3439_6d66_d9a9_48fe, - 0x1089_5fb4_40fe_bb75, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4316_a351_fc82_dd4a, - 0xc959_7950_4cfc_ed50, - 0x7273_943a_84cf_d15e, - 0x15aa_aa6c_c1b9_6ac1, - ]), - pallas::Base::from_raw([ - 0x1b99_d676_512b_796d, - 0xce39_dff1_cba5_dbbb, - 0x421d_4fa7_1462_6d44, - 0x34ad_9d2a_dfaf_5b69, - ]), - ), - ( - pallas::Base::from_raw([ - 0x49ad_a6d1_104a_6eef, - 0xcf8b_024f_cfb5_b7cf, - 0x840c_cc9d_3a3b_cc91, - 0x29b9_5744_64e1_ddfc, - ]), - pallas::Base::from_raw([ - 0x0b87_716a_708c_c280, - 0xf93d_800f_6f21_4435, - 0x1d51_3c67_2d6a_83ff, - 0x0ae6_d491_c1bd_f3bc, - ]), - ), - ( - pallas::Base::from_raw([ - 0x475e_41b0_f1fc_c172, - 0x09b7_1408_69c4_0bb0, - 0xc7ed_2eaa_6b58_0c14, - 0x1d5a_ddce_4556_7eae, - ]), - pallas::Base::from_raw([ - 0xb805_a989_ed0a_19a9, - 0x18f0_a092_4a48_ce6a, - 0x377c_c390_6667_48ba, - 0x0101_7bec_5e9b_8784, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc424_869d_df4a_4fd1, - 0xcb89_e9c6_1506_8e77, - 0x6573_5f9d_0d64_ad1e, - 0x1a16_1910_f3ef_d2a8, - ]), - pallas::Base::from_raw([ - 0x1c2a_ec44_2e96_e2b9, - 0xe5e2_6cbb_e793_3cd1, - 0x4152_f5a5_afcf_0b33, - 0x18bd_33f6_2cd7_afc2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6cef_2ed4_0f12_62a3, - 0x629f_be6a_9a08_13b6, - 0xe188_e97a_fd70_5e9a, - 0x1c81_abae_085e_bbdd, - ]), - pallas::Base::from_raw([ - 0x6b64_e32d_d83d_14cc, - 0x051c_e812_b7d3_8e72, - 0x7c9c_e5ff_9dab_955d, - 0x2c11_dcb2_7ed5_553a, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa486_1053_6543_7c5c, - 0xbaef_3528_5949_99b5, - 0x6ebc_2d21_8bd5_7856, - 0x1194_f3a8_8f8d_20d8, - ]), - pallas::Base::from_raw([ - 0xc583_16cf_02c6_0b44, - 0xbae8_db73_6695_4f2c, - 0x1321_fe4b_4bc8_ff74, - 0x1f90_ec5d_5cdb_66c9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3e78_8bbc_500b_061b, - 0xa39f_04d5_7d40_d1b4, - 0x1075_ff0a_e695_322e, - 0x29e8_f7f2_17eb_d76f, - ]), - pallas::Base::from_raw([ - 0xbf38_0b79_6b13_1fc9, - 0x6464_a70d_f53b_4597, - 0x7026_66e6_dd97_4644, - 0x12fe_b0d1_9689_e650, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfd13_2e00_4e5d_4971, - 0xc505_01d2_b5ea_6072, - 0x9202_b952_2e65_9ed7, - 0x3ab2_84aa_1043_7b11, - ]), - pallas::Base::from_raw([ - 0x4de0_8d20_70f7_f5e1, - 0x550f_b47d_5648_c508, - 0xf74a_5a30_6073_9c33, - 0x3b52_c98c_59db_48ec, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb565_72c3_4d9d_f266, - 0xd4cb_8d31_2f6e_e625, - 0xcd7e_2193_6f0a_a501, - 0x3173_b0b5_e1b9_bcb7, - ]), - pallas::Base::from_raw([ - 0x7bb7_0367_d936_382b, - 0x90d5_03e0_1a24_9fa0, - 0x1d1a_fceb_21eb_295a, - 0x2a42_5586_0ab7_f2de, - ]), - ), - ( - pallas::Base::from_raw([ - 0xea5b_ff65_c9da_428a, - 0xa4cb_a520_eadb_5354, - 0xd80d_5043_0b03_7bdb, - 0x30f5_493e_17bf_d471, - ]), - pallas::Base::from_raw([ - 0xa752_0e7f_dd99_dba5, - 0x5d12_6ed0_d9a3_2a25, - 0xf835_77c5_523e_9c66, - 0x3096_0d36_5f12_d42a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6698_5d13_ac44_6aa6, - 0xb773_2f26_9677_6e12, - 0x1fb7_b640_8501_50b1, - 0x335c_045c_e3ac_a829, - ]), - pallas::Base::from_raw([ - 0x1134_b8f8_bddf_ae01, - 0xfc14_9622_110b_9e4d, - 0x292a_9dfe_fed2_495a, - 0x2d23_4774_78d6_9f8c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe697_a384_bfe0_e7b9, - 0x9600_e548_7eec_8f61, - 0x5cf6_d911_d00d_4080, - 0x2f72_9fef_7fb4_9c3d, - ]), - pallas::Base::from_raw([ - 0x6f27_44cd_0eb3_ccea, - 0x20a3_f582_850f_75ee, - 0x0a5d_de13_44a9_f626, - 0x35ce_7274_5aba_1199, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7745_e733_21ad_a466, - 0x7e96_b0af_9e4e_eac1, - 0x9076_89d2_d2fe_4108, - 0x0ad7_74ec_279a_de59, - ]), - pallas::Base::from_raw([ - 0xeb87_26d2_fa30_f945, - 0xf59f_fb36_952a_758e, - 0xf46c_d397_277b_f15b, - 0x0e42_e600_a788_4e1e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x42d7_c6e8_1a54_7d39, - 0xb171_695f_50a8_bd62, - 0xfe87_5f93_5739_16ba, - 0x2b7b_81a1_9e1a_f147, - ]), - pallas::Base::from_raw([ - 0x5479_f6bc_eb58_7cf0, - 0x55a1_827c_f39e_06ab, - 0x2a9c_0fc4_d3e9_aaae, - 0x1934_b567_9c19_e682, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe18f_eb78_018f_21fb, - 0xcfa5_4075_0fa5_0007, - 0x05e3_f7d5_9d0f_5e8b, - 0x2cc9_4cc1_fe1a_3754, - ]), - pallas::Base::from_raw([ - 0xc2d2_f324_8b4c_ae1c, - 0x447f_7745_c5a9_dedd, - 0x3c21_26cb_32f6_9c68, - 0x08d2_cff6_fba5_5d5b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb5d8_5390_444c_c212, - 0xe08f_cf9d_bef6_3c10, - 0xe6cc_866a_fb3c_80e3, - 0x1973_ffe7_d02f_0fa4, - ]), - pallas::Base::from_raw([ - 0x433d_1974_b639_e380, - 0x10e3_a8f5_d79c_3bb2, - 0xc48b_7633_c798_f597, - 0x2b49_6a88_af43_e434, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6be3_5a9e_4646_9b0a, - 0x21fe_d657_d107_f630, - 0x99d3_0abd_ab7b_8d62, - 0x3509_1866_4a0e_e32f, - ]), - pallas::Base::from_raw([ - 0x0454_ba7b_2b38_8723, - 0x994c_fd44_0535_add3, - 0x5c3e_e7d5_a694_1082, - 0x3e6b_3a1f_16bb_57e2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xffb6_e87a_f4f9_273d, - 0xa3b4_9290_844f_d1f0, - 0xd9d9_9177_ac41_03a2, - 0x1ba6_f2f8_98ad_5de0, - ]), - pallas::Base::from_raw([ - 0x2199_f2d0_0e0a_20d2, - 0x47bf_5d92_1c69_7f48, - 0xb50d_409d_b342_4e95, - 0x0fc8_6805_b969_8fa4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x36ee_72e6_26d6_16f4, - 0xa85c_131e_8f2e_e5d1, - 0x544d_49b6_d5fe_bc77, - 0x0900_2d79_10df_23fd, - ]), - pallas::Base::from_raw([ - 0x768f_c641_47a7_920b, - 0xafed_4d26_3791_7ef3, - 0x25ef_bc62_b972_a83c, - 0x0a20_b646_a0fe_e655, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb83e_09de_6703_6a2c, - 0xc6e4_2d86_9a1c_8a6f, - 0x26cf_9928_a140_3757, - 0x2ea1_20a4_bb61_d62b, - ]), - pallas::Base::from_raw([ - 0xc7aa_5256_b121_eafd, - 0x37a9_d899_91a1_fb45, - 0x0c6b_29a8_5134_4bbd, - 0x0047_cc6a_f224_fb19, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9c0e_5b82_9469_8c2f, - 0x246a_ab8d_57f7_eb14, - 0x6acc_27f8_d28b_015c, - 0x14bc_c3c2_2e2e_b6bb, - ]), - pallas::Base::from_raw([ - 0xbcfd_9f65_9803_ac84, - 0x9065_8c67_7b1a_f1a8, - 0x779e_13d7_fbca_9d34, - 0x0cde_f9bd_324e_1df5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2fb5_5ddd_b490_61f1, - 0xe18d_c4f6_f48c_ff60, - 0x209e_1749_1f95_8e22, - 0x0651_e474_e0d8_11c6, - ]), - pallas::Base::from_raw([ - 0xadb6_45c2_ec3c_cbbb, - 0x35a0_eac6_b2d3_0210, - 0x4ad9_2ead_3d43_a194, - 0x2e39_0f7a_bc18_85b6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x23ca_ecf8_4a99_8786, - 0x48da_db27_2bd6_3318, - 0x9d89_40f9_b2d3_7799, - 0x17fa_61d6_05a5_8987, - ]), - pallas::Base::from_raw([ - 0xc88f_47e1_1d26_8daf, - 0xfb0d_a012_55ff_62bc, - 0xac10_cf88_df83_2cca, - 0x32f1_0c77_19eb_ab29, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3195_102f_c327_9b31, - 0xacfe_b6c5_89a5_d878, - 0x9367_2ab2_d8e8_a423, - 0x14ac_50c6_6669_ba07, - ]), - pallas::Base::from_raw([ - 0x8454_fc70_093a_e70e, - 0x83cf_e218_71ea_9716, - 0x8f87_513a_2560_8897, - 0x3042_845c_65f3_82fd, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe3bd_44e1_cf62_b948, - 0xaca4_8396_f097_f8f9, - 0xaae7_28f2_e533_dd59, - 0x205a_0002_d292_790e, - ]), - pallas::Base::from_raw([ - 0x3747_573a_6340_da58, - 0xc462_be08_e666_c34c, - 0x932b_a9bd_22ef_0dd1, - 0x3c05_7dd9_7523_55c2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x21bc_7af6_3b01_c7e9, - 0x6252_732a_b6ba_dc77, - 0x8936_7ad2_a6da_3eaf, - 0x3423_225a_a8b2_648c, - ]), - pallas::Base::from_raw([ - 0xbf9f_96b4_d37e_cdbd, - 0x9788_5731_a6b5_c21e, - 0x8e53_deb0_53bd_d03f, - 0x0267_f659_8e41_9d57, - ]), - ), - ( - pallas::Base::from_raw([ - 0x16ce_c525_99d8_4e32, - 0x0be9_87cf_f76b_791a, - 0x64e9_f724_3ded_90cb, - 0x3f4b_7c45_f7fd_0a5b, - ]), - pallas::Base::from_raw([ - 0x504d_f52d_0a5e_6f9b, - 0x0ffd_7f14_c471_c25e, - 0x05f5_f6a6_f4e4_3235, - 0x03ed_4df6_1b9b_8e2f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4d55_7ecd_d9bc_b076, - 0x5408_529b_d207_78e4, - 0x58de_ce33_83ef_9bd5, - 0x08e2_3b7f_80c4_f1ce, - ]), - pallas::Base::from_raw([ - 0x2439_550a_1d3f_5fe7, - 0x6f35_49ba_c229_e7de, - 0x4ff1_8163_5458_c34c, - 0x18b0_1033_f86c_5b2d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7932_981f_1490_acb6, - 0xae32_d1c6_69f1_ba87, - 0x487d_3e38_98de_ad2f, - 0x3360_9d96_1cb9_e4bb, - ]), - pallas::Base::from_raw([ - 0x2df5_c107_9de0_42d9, - 0x3a5e_e2d8_4f95_338e, - 0x0f61_1e54_8e5d_6071, - 0x314a_f599_b686_4f6a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x12ec_74da_fb34_4c9c, - 0x86e7_c394_398c_b2b0, - 0xb350_5e55_0f41_55b3, - 0x3882_c274_d10f_9604, - ]), - pallas::Base::from_raw([ - 0x0475_5416_a740_3cc8, - 0x7bc7_5c57_18be_8417, - 0x7225_cf87_5def_f0bb, - 0x354b_a5af_e4b7_8ab5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb928_8c66_ae60_cf6b, - 0x8a01_3bed_8367_6133, - 0xf9d3_d4e7_a269_61af, - 0x1590_bf3d_b717_8a0f, - ]), - pallas::Base::from_raw([ - 0x2988_6de5_e09d_b63b, - 0xffee_8de1_593f_5931, - 0x6c10_c99c_784a_4ab0, - 0x08b8_0c40_7a4e_c18f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x07ef_5d82_7684_6a64, - 0xf266_7542_3316_83e4, - 0x63e8_e5b2_b6e0_98a8, - 0x115d_36de_a116_3915, - ]), - pallas::Base::from_raw([ - 0xf5cb_ccd4_6981_b817, - 0x739c_6e08_5a3a_acc1, - 0x43c3_a2dc_0dc8_4a1b, - 0x3061_050b_bec9_728c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa784_97ba_84c4_9897, - 0x0bdf_4a54_6f11_477b, - 0x78d4_5bc7_61b4_4fc4, - 0x009c_265a_01e4_bd27, - ]), - pallas::Base::from_raw([ - 0x83d6_88e2_3124_442f, - 0xdaf5_4110_7337_7228, - 0x0476_e74e_a35f_a96c, - 0x1cbc_b10c_31c5_a6ce, - ]), - ), - ( - pallas::Base::from_raw([ - 0x815f_09ef_7425_c941, - 0xddea_5b91_af1f_b16e, - 0x44c4_8ec0_6e4c_4d5b, - 0x3eb2_6944_09dd_347a, - ]), - pallas::Base::from_raw([ - 0x5075_853b_087d_36e1, - 0xa637_4ced_4fb9_8cd2, - 0x8f41_0471_fa56_764d, - 0x2a49_2949_e50a_5431, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2a44_94c5_80ca_c7b1, - 0x5c80_bc62_be0c_4c20, - 0x3e9b_c8a6_76ee_a29d, - 0x31e9_f489_5373_0252, - ]), - pallas::Base::from_raw([ - 0x0cc5_99cc_2d44_795f, - 0x5f34_2d7a_6dbb_d769, - 0x1e03_83ac_5bb1_3b70, - 0x3576_b8fa_eecc_5390, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0d73_8802_f12c_9a24, - 0x574b_d31a_7a88_fc47, - 0xfc84_3f6a_5d93_3592, - 0x1386_f0fb_f8be_9c27, - ]), - pallas::Base::from_raw([ - 0x5a23_540a_296c_f044, - 0x6192_3af4_1508_7a98, - 0x5995_b4cf_15cc_2810, - 0x1706_3276_50a0_f036, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2653_f155_85de_a90b, - 0xd63d_94d0_8aa1_482f, - 0x6a82_4715_8027_d155, - 0x1df5_02c5_50b8_da4c, - ]), - pallas::Base::from_raw([ - 0x1c94_bebe_da62_eb37, - 0x0d7d_52bc_04b8_1267, - 0x8c2f_be33_eb00_04e4, - 0x0440_0a84_ea35_612f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5c1b_8f52_5659_4536, - 0x9b79_4d4d_2397_825f, - 0xbbde_a8df_0f7d_ba1c, - 0x3d29_b2f0_082a_5564, - ]), - pallas::Base::from_raw([ - 0x997a_e0be_a8e8_c381, - 0xd8fb_2e89_3946_7e27, - 0x23e9_4e6b_32ae_749c, - 0x37be_d4a7_96d3_6ef1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2b55_fd72_49a0_af15, - 0x84b6_ef86_00bf_2219, - 0xa742_27da_4188_25e1, - 0x2de3_dd50_d348_4b87, - ]), - pallas::Base::from_raw([ - 0x7c51_9935_0187_19af, - 0xe12b_c342_f5ad_3380, - 0x4771_3997_d6b6_6fdb, - 0x2781_cf1a_f080_88bd, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd6b5_8567_e42e_6228, - 0xba55_c9ee_caab_1684, - 0xb098_b03e_c0e2_bfa9, - 0x1658_92f6_2d6c_ab72, - ]), - pallas::Base::from_raw([ - 0x7cce_f3c2_7004_750a, - 0x6764_b8ec_87af_0fbd, - 0x954a_3e23_b88f_10da, - 0x016b_7c55_ed75_6eb4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1572_3792_f441_6a81, - 0xf995_d329_4d87_564f, - 0xb0d2_1f0e_cc5c_2ee8, - 0x27d0_c30b_d4bd_22ba, - ]), - pallas::Base::from_raw([ - 0xdb2c_fdc7_ab47_0473, - 0x6cf3_d13d_2256_03b9, - 0x2032_3b49_b053_23ca, - 0x3874_12f6_3a24_2a92, - ]), - ), - ( - pallas::Base::from_raw([ - 0x996a_0c38_d044_b83c, - 0xde09_0618_5b92_cda5, - 0x4643_0a67_d500_a255, - 0x27f5_9685_eb77_ac7e, - ]), - pallas::Base::from_raw([ - 0x059a_236e_dfd1_5edf, - 0xe561_315f_eae6_1f63, - 0xbb05_a594_85a4_b33a, - 0x3285_ddba_14ac_1ed8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe549_c0d0_0ceb_9dc3, - 0xd273_7cf6_b421_aa39, - 0x97d6_32a0_5a8f_3a2b, - 0x3c24_5f47_8e0c_a36c, - ]), - pallas::Base::from_raw([ - 0xf20b_8a37_aa4a_7d8b, - 0x8189_e00c_5620_23da, - 0x5aff_d154_2f27_8147, - 0x03a2_d69b_1690_1c15, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1db8_ec71_2a43_63b8, - 0x8920_3a49_6826_c060, - 0xab52_38e8_da30_0add, - 0x1fba_c064_05f9_fd83, - ]), - pallas::Base::from_raw([ - 0x35ca_286a_fd3e_c748, - 0x4d74_e271_dbd4_2a3a, - 0x1af7_48ff_e310_304b, - 0x38e5_4864_6bbe_709c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9c3f_6480_c417_46a5, - 0x7455_11cb_9655_ec10, - 0x0b30_d995_92df_c3ba, - 0x04b5_d208_aa2d_5695, - ]), - pallas::Base::from_raw([ - 0xe3fa_148a_db80_2f0b, - 0x692a_dedb_cc21_f27b, - 0xe5bd_3253_815e_0161, - 0x06ae_836a_74b7_d7b3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x23a6_7fe7_633a_8233, - 0xfb9a_4eca_7e71_4fac, - 0x950d_ef5f_a5bd_24cd, - 0x187a_4853_68dd_e36c, - ]), - pallas::Base::from_raw([ - 0x4ad9_6376_9666_3e54, - 0x935b_6072_4744_7eab, - 0x40d0_ef01_0cf4_ba17, - 0x2bd6_8f8f_e07b_ef4e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe269_82a7_147b_8c18, - 0x607b_e6c4_b9b9_be5d, - 0xe32d_307b_b3db_e0ef, - 0x3a76_010b_80d3_c8b0, - ]), - pallas::Base::from_raw([ - 0x06a9_146c_a674_8492, - 0xce4b_2d6b_49aa_731b, - 0x795b_873d_4a5a_95bb, - 0x19e5_778d_9876_7a46, - ]), - ), - ( - pallas::Base::from_raw([ - 0x02c9_e528_8369_fdca, - 0x546f_8eed_d946_62ec, - 0xa4c4_8b26_12bd_a088, - 0x3551_abbc_cb49_2c53, - ]), - pallas::Base::from_raw([ - 0xdfbe_b704_29a1_b4f7, - 0x6943_7350_0ca9_1961, - 0x4cf2_bc5d_2dd1_5705, - 0x2341_167f_494d_0476, - ]), - ), - ( - pallas::Base::from_raw([ - 0xaec8_67d5_8bab_356f, - 0x5a07_3489_e797_2666, - 0xe593_e00b_8588_5887, - 0x3298_8eb7_8bd8_1bcc, - ]), - pallas::Base::from_raw([ - 0xca3c_443b_d127_bdbe, - 0x53f6_db87_cbf9_232f, - 0x925e_3c81_1375_408d, - 0x362f_d3bb_da48_9c11, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6010_85d0_794c_e3ac, - 0x162b_7969_422e_ff0a, - 0xfa12_7c4b_9718_324d, - 0x05eb_74ba_ac18_6eb0, - ]), - pallas::Base::from_raw([ - 0xfa9c_6176_37ad_dbd4, - 0xd77b_985f_9626_c949, - 0x53e4_deb7_34a6_4e7a, - 0x1133_2731_91bb_93cf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x96c9_fb17_08b4_1634, - 0xa9a6_bc5e_2d24_cb92, - 0x834c_a22b_fd16_3870, - 0x3e56_ae12_1141_fc99, - ]), - pallas::Base::from_raw([ - 0x50bb_4dbc_163f_9f93, - 0x1e25_6f15_ff60_3b93, - 0x3e61_aa6f_b66c_8a6b, - 0x00e2_da21_06b8_e3c0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x42dd_8b79_23b6_b513, - 0xea85_bf04_b59a_779d, - 0xb0a9_fa50_a01a_72dd, - 0x08a0_0b38_4174_1ff4, - ]), - pallas::Base::from_raw([ - 0x64cb_e014_3f1e_ff9b, - 0xa145_12f2_67e7_15b9, - 0xd5fc_3acc_8d1b_3611, - 0x2717_cf1f_7f6d_ee6b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x11e3_925e_0cdb_c33d, - 0xbc8e_d434_51c3_4778, - 0x7304_853c_9743_9b31, - 0x1ada_7ad3_956c_621d, - ]), - pallas::Base::from_raw([ - 0x550f_ed05_7f72_917b, - 0x2345_cf15_73cd_6078, - 0xc00f_bede_8499_f921, - 0x3935_21fc_eb2e_3365, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0adc_cc3c_16a3_f235, - 0x2676_dcb3_8d85_ac03, - 0xb7c2_fa06_3232_3f54, - 0x1b00_c04e_8168_266c, - ]), - pallas::Base::from_raw([ - 0x22b8_f975_c6b2_6381, - 0x64a0_f521_877f_6589, - 0x0de4_3934_6246_b2b2, - 0x10ab_0d63_c867_c968, - ]), - ), - ( - pallas::Base::from_raw([ - 0x72ff_4d9f_054e_cb10, - 0x28cc_c6c5_1071_3c53, - 0x4144_3ca1_3640_7bcf, - 0x3ca1_8a54_8248_dce3, - ]), - pallas::Base::from_raw([ - 0x74b5_8607_c4f6_23a9, - 0x52cf_86ce_4024_b4e8, - 0x0c1f_22de_8fa9_9eb8, - 0x06d1_9d7c_2817_2812, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3429_9ecb_1a25_b41a, - 0x4c20_e2cd_430f_4f53, - 0xd3ac_8de7_5dfa_6385, - 0x315d_549f_290d_49aa, - ]), - pallas::Base::from_raw([ - 0x950a_7a7a_7391_01da, - 0xd06e_4417_2b59_15c5, - 0x8872_d56b_c32c_8a5b, - 0x1f28_a45d_64f9_644c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xec62_b82b_3f9c_dd5a, - 0x53e4_68e0_ba89_260f, - 0xbf71_b840_6644_8a63, - 0x1a7d_2578_300e_a6ca, - ]), - pallas::Base::from_raw([ - 0xdfd2_eae1_7952_3443, - 0xe753_284b_9058_3e43, - 0x3850_e370_e03e_b2ec, - 0x24f2_1e42_10b5_41ca, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3960_69f3_d739_056b, - 0x2f84_257d_240a_a99b, - 0xcbbc_6a3e_1d2e_3e47, - 0x32f2_11fd_60f5_6c88, - ]), - pallas::Base::from_raw([ - 0x8993_dc0a_f3e7_01d6, - 0x3c49_7f08_3d5f_1ffb, - 0x7c69_98c3_762e_4080, - 0x25ff_cd09_47d8_4962, - ]), - ), - ( - pallas::Base::from_raw([ - 0x00eb_df7a_a05e_0505, - 0x32d7_73fe_8a8d_769a, - 0xa0d7_4ae0_ba94_c75d, - 0x028f_6828_bf19_6ab8, - ]), - pallas::Base::from_raw([ - 0x1240_0761_dba1_cb3f, - 0xf439_7e09_5aee_c121, - 0x9a39_26be_cdaf_c085, - 0x11d1_6e6d_2222_d955, - ]), - ), - ( - pallas::Base::from_raw([ - 0xeb43_eac8_a45e_50fe, - 0x76e1_3155_9fb9_e4ca, - 0x8f66_7104_3f1b_0d78, - 0x0dc9_64a3_6226_3ba5, - ]), - pallas::Base::from_raw([ - 0x2443_a280_98f7_d9ea, - 0x7873_9d11_13fc_182d, - 0xd62c_6c84_30df_277e, - 0x3981_79f2_29f0_77ad, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3f3b_83e1_e18b_41a6, - 0xe879_b7d0_d499_1f0e, - 0x3a14_5291_dc57_a3a4, - 0x1106_64a3_a51b_428d, - ]), - pallas::Base::from_raw([ - 0x9acb_835d_d793_fc7e, - 0x695e_bbbc_7b1d_69ac, - 0x418d_bfef_2441_77eb, - 0x0e03_0d59_8861_c631, - ]), - ), - ( - pallas::Base::from_raw([ - 0x676c_1bbb_3d79_4a17, - 0x86f7_40b1_a30b_1824, - 0x0414_8138_2c6e_d6cd, - 0x2460_267a_aca9_b888, - ]), - pallas::Base::from_raw([ - 0x4b8e_28e4_c2de_91a3, - 0x0eb9_23e6_bb90_72e7, - 0x84a5_c9a1_9518_d64b, - 0x2028_854f_c7fe_f563, - ]), - ), - ( - pallas::Base::from_raw([ - 0xec55_0b1b_b4b3_5edc, - 0x9bd6_e713_a2a0_44f1, - 0x1bb7_d52f_e215_849b, - 0x2a3b_4a5a_60a8_e589, - ]), - pallas::Base::from_raw([ - 0x37db_8209_47f9_907b, - 0x9606_a95f_fed0_ec37, - 0xa4a5_f491_06db_2a91, - 0x2dc3_8e45_8a44_967b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xac40_3499_d9f9_eb6c, - 0x026d_a7c4_f3a1_2e88, - 0x7dfa_04ff_1867_a66b, - 0x0980_4e29_e424_13a9, - ]), - pallas::Base::from_raw([ - 0x51b5_218c_3a0a_055f, - 0x5ddc_c1fd_7461_34bb, - 0x3696_cdf0_cf53_c400, - 0x3594_1364_798f_0c20, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe6a7_7cfc_25cb_3242, - 0x2c31_d7f5_8837_2988, - 0x562e_9094_a407_ac85, - 0x3ab1_effb_2622_e180, - ]), - pallas::Base::from_raw([ - 0xb424_bdcf_597c_6557, - 0xeda3_48f9_ba67_2219, - 0x8c1a_e37b_63f2_d3cd, - 0x26f7_ed5a_5a2f_099a, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd297_863e_dded_7212, - 0xf91b_2b7e_3e36_bebc, - 0xaeff_d446_04bf_08b9, - 0x2467_95dd_ab7c_c74e, - ]), - pallas::Base::from_raw([ - 0xc713_53de_e975_f704, - 0xb276_043d_644d_0408, - 0x5878_7fed_3075_dead, - 0x2771_e939_209b_ae7a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x06dd_9ad7_373d_99f9, - 0x8a73_6054_b608_fa6a, - 0x3411_7ed3_2293_33b5, - 0x2e33_7d8a_2021_02de, - ]), - pallas::Base::from_raw([ - 0xc3ee_16d0_a73b_d633, - 0xd25f_08e9_2b65_b288, - 0xc26a_08ce_301a_28b9, - 0x3935_358f_146f_39be, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3f5b_b50c_f6ef_ce5b, - 0xb76d_32e4_5f67_4c5d, - 0xcaa1_7ff1_2bd7_bb4b, - 0x1b8d_cefd_b94d_06b2, - ]), - pallas::Base::from_raw([ - 0xa469_b014_2c83_2078, - 0x4d17_ae69_2a58_478f, - 0xcc08_c0ee_6947_386b, - 0x1428_6ba3_312d_4851, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2f3d_b3e9_a41a_0337, - 0x03a4_7f23_3f67_a26d, - 0x28c2_fecf_bfc3_355b, - 0x2bbc_960a_bd2e_f481, - ]), - pallas::Base::from_raw([ - 0xc311_0952_b121_2186, - 0x2e87_5201_48d5_fc53, - 0x875c_9ff6_a96a_da2c, - 0x0223_4935_d415_a5e5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x36f0_8415_22e2_56fe, - 0x6d55_4c96_1cb1_f126, - 0xefbe_e6c5_dceb_0fd6, - 0x3de2_b1ec_d97a_180c, - ]), - pallas::Base::from_raw([ - 0x5304_ab95_aae6_9b66, - 0x60ed_3893_0c80_7993, - 0xd9b4_3e8d_6ff5_4a3e, - 0x18fc_8e36_16ba_3090, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0822_d885_4dfe_69f0, - 0x505e_1f45_ccf1_dc38, - 0x628a_640a_7eec_8b84, - 0x0127_23d3_14c8_9c01, - ]), - pallas::Base::from_raw([ - 0x7e4e_f3cb_d5d4_7736, - 0x850b_2fbd_d6e5_5bac, - 0x6c2f_3bc2_18f3_9602, - 0x2535_1370_28dc_f11f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa134_90eb_3ad2_a6fe, - 0x0b67_1163_084d_310a, - 0x86df_15cb_08ca_1613, - 0x2186_0967_8d1c_6167, - ]), - pallas::Base::from_raw([ - 0x58de_954b_613d_9043, - 0x4cdf_a072_9d4a_5cde, - 0xd2a4_f058_b900_7509, - 0x2660_6d63_e85e_94fb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1bee_c383_512e_3059, - 0x75e4_6def_af35_b531, - 0x25cb_866c_89fa_7469, - 0x2300_a9c8_709c_c635, - ]), - pallas::Base::from_raw([ - 0x30fe_ba0a_d8b6_dd3a, - 0xfe7b_289a_3c6c_a17b, - 0x7a6a_763f_4f92_0595, - 0x0669_e3fe_787d_f81c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2317_af7e_2bc1_fb5a, - 0x4fa0_a83c_0f76_c57a, - 0xad4d_1850_e918_2af4, - 0x3095_294e_9909_a724, - ]), - pallas::Base::from_raw([ - 0xb04c_712b_c022_15ee, - 0xf118_0f20_c588_375d, - 0xaabd_ded2_9f7d_bf93, - 0x170b_a10e_7ff6_dc04, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4614_ca37_6411_165d, - 0xfe5e_19ff_1cf2_d2ea, - 0xfd57_702b_75b7_f29b, - 0x2d1b_3d96_4eb5_321a, - ]), - pallas::Base::from_raw([ - 0x03b0_6fb1_8c52_94d7, - 0xd282_d2a7_a658_83af, - 0x136d_b5bc_b3ef_254e, - 0x2e8c_5ef8_61fe_9aeb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x79cc_d5aa_18d7_fe0f, - 0x21fb_e42a_7f84_9fc5, - 0x6a28_f36b_52a4_f91c, - 0x011d_e672_2dda_0469, - ]), - pallas::Base::from_raw([ - 0x4f07_9730_2c53_dc9c, - 0x6c9d_a709_b02b_cf85, - 0x6bf0_cda1_2708_3753, - 0x02ad_a1fa_4596_eb60, - ]), - ), - ( - pallas::Base::from_raw([ - 0x74f1_d926_d45e_11b7, - 0x1c48_974b_0e37_87a2, - 0x574f_54b1_2560_ee08, - 0x1a17_a6cd_ff9b_fa8b, - ]), - pallas::Base::from_raw([ - 0x65bd_430a_18c2_6fdd, - 0x06a7_f226_5fff_44b4, - 0x600f_2717_320e_d4a6, - 0x0c3b_4e95_ac95_a06b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb18b_afc6_26e6_2669, - 0x34de_90c8_407d_290b, - 0x47c9_8071_fe58_680e, - 0x1274_01e0_c920_4b16, - ]), - pallas::Base::from_raw([ - 0x332d_e7a5_2f92_fc45, - 0xc917_cdc6_686b_1a9d, - 0xb86c_76fe_72e0_8b68, - 0x0b4f_39ca_545a_b70f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc417_3670_bcb9_cc4a, - 0xbd5c_f1b8_0b64_2192, - 0x1897_6a02_8e09_c2fb, - 0x187e_651a_79a4_8732, - ]), - pallas::Base::from_raw([ - 0xae69_5d7d_5294_c1af, - 0x1934_654c_e813_bf54, - 0x642c_b26f_293d_c2dd, - 0x092c_e031_517b_da63, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7662_8a07_ecc9_bc79, - 0x8cb2_1f86_aaa6_5bb3, - 0xbb09_cf23_8a56_d226, - 0x1c1a_5d7b_19a6_351a, - ]), - pallas::Base::from_raw([ - 0xfe9f_8731_fe5c_71af, - 0xdd8d_8082_7660_c6cf, - 0xa2fb_bb46_607d_b4f6, - 0x066c_dec4_29fa_02f4, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfeba_3899_4dcd_fab9, - 0x0185_bee0_53a8_b2e9, - 0x2d18_4ae3_6719_da6c, - 0x38de_de43_97fc_4e8c, - ]), - pallas::Base::from_raw([ - 0xaf8c_1a56_9749_5a96, - 0x1eaf_43ef_5661_3ff8, - 0xfe65_2cce_44c4_fced, - 0x24ca_f69b_2d91_f2f4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x050e_2315_3fe8_888a, - 0x5cd6_7594_d7fb_eada, - 0x5890_89ac_5ffa_169e, - 0x2c7a_db4e_0279_0a77, - ]), - pallas::Base::from_raw([ - 0xace5_6f4c_4889_310b, - 0x36cb_a3e6_49a8_2d97, - 0x0a3f_5f71_4d72_02ef, - 0x34e9_12c6_ec66_b3d8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8d2d_8ca6_933c_4438, - 0xd7f0_b609_54f3_3f61, - 0xe93b_e7cc_13ed_f94c, - 0x114a_be4c_6b55_af86, - ]), - pallas::Base::from_raw([ - 0x1837_62f1_7010_22b7, - 0x4811_6b3d_d2a2_a698, - 0xea41_857f_a3f3_188e, - 0x1fb5_1838_65ba_7743, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa082_8c60_d8a3_f578, - 0x0a25_684f_653f_6c8f, - 0x2b4d_9dc4_dc66_7726, - 0x36c8_2048_d681_651d, - ]), - pallas::Base::from_raw([ - 0xe26c_9196_230a_c29c, - 0x08fb_0378_bc18_071b, - 0x75a0_8f44_c578_a727, - 0x15ee_7196_24dc_9c10, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfeaa_76bf_d7f3_cc18, - 0x7d70_d0be_ff2b_e9a5, - 0xbfb7_ade3_819f_e899, - 0x0a80_597f_8201_89a2, - ]), - pallas::Base::from_raw([ - 0x7c0c_7cf8_5e73_abcb, - 0xefb0_3940_c106_04ee, - 0x85e4_c588_3d14_ef43, - 0x27fe_fbb2_9d0a_97b7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x47c6_a888_684f_bdbe, - 0x5427_2144_0e19_5279, - 0xf6b3_7923_849c_acea, - 0x34f3_4173_3333_34f1, - ]), - pallas::Base::from_raw([ - 0x0a04_1869_d2aa_dad4, - 0x34a7_9c4d_f7a6_b66f, - 0x7b7b_e1e9_121b_6d3a, - 0x2421_7f52_b1bb_09bc, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfe01_fde7_3ddc_40c0, - 0x6731_87df_9de0_27de, - 0x2150_0dc8_2124_84f9, - 0x1764_90fe_4fbf_05d1, - ]), - pallas::Base::from_raw([ - 0x3e96_ffcc_83de_2760, - 0xffd3_6ccc_6e69_1191, - 0xe3ce_955b_54a6_1af7, - 0x091d_70c1_c2a0_1886, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdf0c_1b18_d13e_6075, - 0x3660_d9cd_6d7c_a28c, - 0xc8db_742a_5e85_5a70, - 0x0856_63df_fcde_b718, - ]), - pallas::Base::from_raw([ - 0xdfc6_3b44_bfcb_4ba9, - 0xe1ab_077a_c6da_e5a3, - 0x2b4a_31f8_1d0a_106f, - 0x26e9_9d38_3c41_ba1a, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa55b_b719_22c8_8eb6, - 0x2ba9_93d9_f776_01fd, - 0xef9d_38c3_4590_b955, - 0x393c_90d8_8ab2_8885, - ]), - pallas::Base::from_raw([ - 0x2367_9c6c_8698_dc18, - 0xc375_1a89_e204_ed77, - 0xa2cc_f60a_2cc0_42c5, - 0x3b1a_7e64_31f5_efc9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x01aa_2003_93d8_1228, - 0xd565_deb4_6165_426a, - 0x1359_c8b2_23c3_a219, - 0x1741_223b_656d_fbea, - ]), - pallas::Base::from_raw([ - 0x68a2_aa8d_99d2_6617, - 0x3248_d5e3_8e95_e05c, - 0x4347_e264_3653_a95c, - 0x3b6a_ab30_009e_2a40, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc401_caf5_b80b_d7b7, - 0xd475_062f_bbbc_8de4, - 0xf888_a322_55a9_d44e, - 0x1a01_8bfb_3b21_464d, - ]), - pallas::Base::from_raw([ - 0x5d8f_724e_1cd2_4386, - 0x78a3_535f_8640_efd4, - 0x47ce_290a_4905_53a1, - 0x2a91_7aea_3b73_4a4c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x034e_89dd_99f2_6e09, - 0x45b5_bd00_e4da_62a9, - 0xebf3_dbff_ba88_271e, - 0x02c8_2b9c_ea98_af0f, - ]), - pallas::Base::from_raw([ - 0x3aca_a2de_6568_bd4f, - 0x5544_cffc_3aed_6643, - 0x52f8_d105_2659_131d, - 0x011f_4744_f248_a534, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe504_9c54_5183_a68e, - 0xb2d8_76d0_fd04_ddfd, - 0xe266_0cda_4417_fa06, - 0x2bc0_f5d1_292f_66ad, - ]), - pallas::Base::from_raw([ - 0x98fa_34c1_c7e4_4d04, - 0x86f0_df5a_c92c_6a54, - 0x458a_25bc_e1c6_6a86, - 0x36c6_ddb7_9a5f_7421, - ]), - ), - ( - pallas::Base::from_raw([ - 0x309b_b8ce_eaf9_5df5, - 0x0149_4b0f_a4ba_ea01, - 0xa124_4665_cce6_d172, - 0x3412_acee_8559_e4cd, - ]), - pallas::Base::from_raw([ - 0xa00c_8037_9921_039c, - 0x26ec_3ff0_2626_f929, - 0x7f42_5184_1ec7_6115, - 0x0d32_4da9_5111_de3f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0623_4914_8426_c348, - 0x923b_758a_75fb_c2ae, - 0x8563_479a_8a1c_3a18, - 0x0222_f189_6b30_9026, - ]), - pallas::Base::from_raw([ - 0x6383_b87a_3a58_9f66, - 0x5d68_22db_c04c_0804, - 0x3cd5_300d_b8c8_5e26, - 0x1ed6_87af_f5a9_7f81, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4976_a9d9_23f4_e05a, - 0x89a9_d356_80f3_5037, - 0xfcce_d80b_20ff_a679, - 0x2eaa_c96a_e572_8c2e, - ]), - pallas::Base::from_raw([ - 0xe326_9ec8_35b1_a894, - 0xe334_6c5d_38d5_f584, - 0x58d6_995b_9eb6_1568, - 0x3b13_1337_181e_2cab, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd626_3c8c_8fab_225e, - 0x6111_af8a_c249_0cd6, - 0xf2ef_6c29_147c_86d6, - 0x27f5_4f89_3962_c0ad, - ]), - pallas::Base::from_raw([ - 0xa842_3c35_185c_5986, - 0x70ae_f850_779c_bfa3, - 0xf628_f488_1fc8_b76e, - 0x0a9c_f292_fe41_9dfa, - ]), - ), - ( - pallas::Base::from_raw([ - 0x537c_08e1_3a1c_f53f, - 0x78df_4265_7b2b_fc61, - 0x2500_a58a_eac6_35c6, - 0x0fcf_c9c2_bc99_f123, - ]), - pallas::Base::from_raw([ - 0x3147_0e47_8fbe_1b4a, - 0x991e_e318_b485_e3b9, - 0x633d_47dd_3042_bb0e, - 0x3360_8103_99b0_a527, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd7a2_1d17_f989_6972, - 0x5e8b_6e6b_30d7_aa2b, - 0x8454_73ae_ee97_a305, - 0x3116_2156_7cc1_18e5, - ]), - pallas::Base::from_raw([ - 0xfccf_5d9f_b11e_df81, - 0x2e12_7758_c03e_b200, - 0x5f04_7db9_eeaa_1921, - 0x3a86_fc45_77b3_f524, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9e93_1cc8_c148_8493, - 0x900f_cf13_2569_e392, - 0x765e_58e9_48b5_d022, - 0x2ede_c32e_ef69_64c0, - ]), - pallas::Base::from_raw([ - 0x5695_ebac_bfeb_ebd4, - 0x98cc_74a8_fd64_21ff, - 0x27d8_5ecb_1931_3238, - 0x1053_65b5_5423_da3c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf222_9818_2d70_d3ed, - 0xdf8e_0ddb_b98b_fbeb, - 0x44ec_a0c2_57ef_550b, - 0x12e2_838e_4f99_a03a, - ]), - pallas::Base::from_raw([ - 0x6655_b07c_8d8e_d971, - 0x9d54_b9e8_f799_c635, - 0xd3ac_f7ab_31b0_0ae0, - 0x3db7_b034_049d_ceb4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x10ba_763a_c8c6_f730, - 0xae79_86b4_9150_c67a, - 0x82ed_80f2_e411_a974, - 0x04e0_22d6_0b2c_6589, - ]), - pallas::Base::from_raw([ - 0x088c_79a2_e8ad_c3e4, - 0xa2b1_bfb2_60e1_d64f, - 0x2153_eadf_50f5_03a8, - 0x0471_d795_1f45_c106, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa0af_6834_540a_1d2a, - 0xbc22_530b_a609_337d, - 0xb27e_7401_ff92_1206, - 0x0f66_0b47_5fce_7a48, - ]), - pallas::Base::from_raw([ - 0x0d2d_0ce4_5d34_1e91, - 0x5ed6_ed9b_6248_73e5, - 0xdb0d_b388_856f_04a8, - 0x3909_13e5_6b4d_ecad, - ]), - ), - ( - pallas::Base::from_raw([ - 0x931f_ebf4_3432_8d85, - 0xb4ac_dfb4_13f3_778f, - 0x2198_10f0_065a_4746, - 0x274b_25e6_d0ee_28ac, - ]), - pallas::Base::from_raw([ - 0x85ff_5dcf_2af8_0d1e, - 0x4fcf_da75_73d5_6aaa, - 0xfebf_10d6_f655_de17, - 0x0fc4_ed1e_e2fb_3daa, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2c88_682b_0807_fb47, - 0xe572_e261_762a_9833, - 0x92a5_94b7_dd97_e2d6, - 0x290c_0f08_ae67_92f1, - ]), - pallas::Base::from_raw([ - 0x9f3e_a22a_9fbd_e2f2, - 0x7828_c11a_b548_3f9d, - 0x889f_be4d_6071_fc49, - 0x2127_232a_a434_31ff, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdf50_276a_cd2f_7fd2, - 0x6221_308a_0532_4c09, - 0x1c28_3f54_3fb6_99e4, - 0x2691_bf94_093a_d903, - ]), - pallas::Base::from_raw([ - 0x6af0_82ff_ff8c_9733, - 0x5ff9_faf0_e36e_d8c0, - 0xce94_f44a_1788_600f, - 0x1318_d65d_1c35_c49b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9163_559a_be89_bb1c, - 0x5251_bfcf_7749_01a7, - 0x3efb_6de2_8193_cf1e, - 0x1942_18c3_fe5b_6949, - ]), - pallas::Base::from_raw([ - 0x7174_f4c0_cc3b_ede0, - 0x735b_e3c2_887f_4687, - 0x93ab_3df4_5697_0520, - 0x0d9d_d803_f612_8651, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7f74_e033_1fc3_eca4, - 0xd55f_7848_5f07_c856, - 0x4a3f_5542_4f34_fd79, - 0x0a48_7764_e6bb_64fc, - ]), - pallas::Base::from_raw([ - 0x7746_ae1b_b07c_53a9, - 0x0cd8_26a8_b54e_f182, - 0x64d2_d590_c7a7_2ef5, - 0x34e7_9a7c_db19_a72f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9ee7_822c_9974_c6fe, - 0x6d79_96e6_ecf8_df62, - 0x3263_2b2e_f5df_4af0, - 0x10f9_be27_b481_30e5, - ]), - pallas::Base::from_raw([ - 0x1272_0f17_8ab2_623a, - 0xa050_ea3b_6f25_0848, - 0x01f1_8495_9947_e6d4, - 0x3e25_d531_e842_b508, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1c20_5dac_8ff2_38cb, - 0x4c0e_7a71_7346_0cd7, - 0x5cb8_b1a1_4c49_19e7, - 0x1017_cc43_7f6c_a31c, - ]), - pallas::Base::from_raw([ - 0xc7a7_9329_b0d7_cfab, - 0xf910_054e_b22e_57ef, - 0xa27e_9be2_3ef3_e39a, - 0x221a_8fd3_dea3_471c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8da5_c8aa_c156_511d, - 0x3df5_2950_01ad_9519, - 0x654e_3cc1_fefe_95d2, - 0x1826_50e8_f7f3_c594, - ]), - pallas::Base::from_raw([ - 0x6a14_5790_4fe2_27cc, - 0xdbdc_600a_387f_90de, - 0xb47f_a736_8906_d3bd, - 0x2919_7af4_2853_5c8b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0e60_4790_c292_a15b, - 0x568d_bf3d_b502_70c0, - 0x54ae_c935_bb45_d7de, - 0x30eb_56d9_3c62_e58a, - ]), - pallas::Base::from_raw([ - 0x940f_2e00_ced7_14f4, - 0xf3d0_1a90_5dd8_c6bb, - 0x2188_66b3_369c_ec8f, - 0x16ad_3c60_929e_f022, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0c17_e5c3_6446_c41f, - 0xbc36_aeb7_6459_3101, - 0xe6b3_222b_f89f_1cbb, - 0x0a55_07f7_2694_65a6, - ]), - pallas::Base::from_raw([ - 0x5d8e_9202_13b0_c07c, - 0x0c75_2080_6653_ef25, - 0x0a8a_c99c_9e71_ec48, - 0x0cea_69fc_1248_9c7a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6bf7_aa25_2e67_bfe4, - 0xf638_dd62_3264_efb2, - 0xc5d9_d3dd_7ab8_95eb, - 0x19cc_6f41_d5ea_400f, - ]), - pallas::Base::from_raw([ - 0xb5f9_31ac_c93d_a424, - 0x0669_28e6_f068_ab0b, - 0xaa97_d1f0_2516_8563, - 0x12c9_2e45_f41a_027e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb5cd_03f6_546f_2d8c, - 0x008b_ed8d_5fb4_d8cc, - 0xfbcb_8613_de82_5e34, - 0x321d_9574_27a1_bf27, - ]), - pallas::Base::from_raw([ - 0xf46e_ef71_5d5a_f67e, - 0x0718_6aa5_d7df_a969, - 0xcdd8_6543_720a_6554, - 0x0109_0738_2d21_8149, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3b0a_d014_2f1d_6af2, - 0x99d7_56da_d234_fc14, - 0x45a8_b1c4_454c_5dfb, - 0x1ee7_4f77_ad27_f629, - ]), - pallas::Base::from_raw([ - 0xf38f_1264_df92_5a0f, - 0x198a_81c9_05ac_18d7, - 0xcc50_1caf_24f4_ed42, - 0x399e_531d_d4d1_3840, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb529_b39a_b8c8_6bbf, - 0x7d8f_ebda_e02d_678e, - 0x7fae_d795_ca8e_8302, - 0x31ed_a441_e002_ac2c, - ]), - pallas::Base::from_raw([ - 0x619d_1ef8_6855_6cbb, - 0xd88c_2fed_a381_abd6, - 0x6845_42a1_1e1f_ddd0, - 0x0771_38ca_a39c_2293, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8e3c_040a_f2be_9c63, - 0x0cfc_acc4_41b0_e1e2, - 0xf752_2875_1f06_363f, - 0x0032_71bd_2b81_e3cc, - ]), - pallas::Base::from_raw([ - 0xc3ad_aedb_26dc_6180, - 0x2ad6_7b13_2e77_7986, - 0x2dc6_e063_027b_de54, - 0x0af4_dae5_6e28_04a4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5075_53c9_94d0_dc2e, - 0x940f_4012_649a_26a7, - 0x9162_6f3d_cb07_7bdb, - 0x3c6c_9061_ba99_8e97, - ]), - pallas::Base::from_raw([ - 0x2178_ff4b_0732_3f45, - 0xc7bd_6c17_b4a7_3748, - 0x567e_30af_d336_1f3f, - 0x0fe0_0d2e_dc98_92d2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x923e_5ef9_fc71_838b, - 0x7d0f_0335_d240_a72f, - 0x1995_4895_1bc7_bb3e, - 0x21ab_30c3_8b38_7741, - ]), - pallas::Base::from_raw([ - 0x28a5_52b8_4d1c_2cb2, - 0x7879_b66b_db7d_c6f9, - 0x66cb_e4a2_b207_c3c3, - 0x1c5e_324e_ce7e_1fc2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0bea_8b37_7a6e_5de3, - 0xe8ad_fcbe_7b8f_c888, - 0x6443_7dff_eb54_1544, - 0x17e3_7101_e098_d708, - ]), - pallas::Base::from_raw([ - 0x5e3c_16ee_ea18_7549, - 0xcebc_d07b_5dda_4fdc, - 0xcaef_d061_c365_1317, - 0x08ba_afac_c8b0_f579, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0c45_64d3_dfdc_c360, - 0x3c34_d6db_627a_b743, - 0x19d6_66ef_aece_e57d, - 0x202c_137c_d1b6_7cb8, - ]), - pallas::Base::from_raw([ - 0x0dee_c67f_c432_1abc, - 0xc5cb_4568_bc4a_8783, - 0x86b1_1451_ecca_550c, - 0x0ff0_09f7_4820_2e77, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf299_ebe2_a905_3c8b, - 0x424d_1301_89df_a29d, - 0xea28_f364_490d_4a4b, - 0x2508_a2a0_337f_d881, - ]), - pallas::Base::from_raw([ - 0xd25c_bf8b_16a9_bc33, - 0x11a1_c1ed_a972_d5f0, - 0x9cef_8ada_9d7d_314e, - 0x00a8_b4df_bad1_2ed3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x23be_9beb_9a9d_1973, - 0x08cb_a79c_d6be_891a, - 0xfe6b_6d74_0d9e_ca76, - 0x1cf9_8a3d_7cad_c772, - ]), - pallas::Base::from_raw([ - 0x37b5_48a9_8ca6_1367, - 0x7717_856a_a9b5_f7e9, - 0xbbc3_ed77_a685_e338, - 0x3721_1cad_a67a_824f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xec8f_2eff_5163_90b6, - 0x502b_81eb_7035_b6aa, - 0xc6f2_0df9_5dfa_4d3e, - 0x0a19_842b_c197_5949, - ]), - pallas::Base::from_raw([ - 0x760b_a317_8fbe_610d, - 0x0370_d562_6abd_b305, - 0xb005_aebf_6e18_2d4c, - 0x0bfb_19da_eb56_6427, - ]), - ), - ( - pallas::Base::from_raw([ - 0x577e_5c79_60fc_0750, - 0xef55_42ac_ca0d_7327, - 0x1f01_e126_ce1b_85b2, - 0x2a4a_42d0_4ff1_a83e, - ]), - pallas::Base::from_raw([ - 0x89fb_594d_05da_15b6, - 0x409f_a8a7_c292_6e67, - 0xf51d_1898_aad8_d7bc, - 0x11a2_2949_d51d_cca1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa13a_ce54_6c54_ddfd, - 0x4f2f_05d0_3b6b_c624, - 0x24d8_342b_6f1b_bed6, - 0x10f6_dcfd_3058_49b0, - ]), - pallas::Base::from_raw([ - 0x45e4_776c_b11e_2c8b, - 0x21dd_7840_7331_9fb1, - 0x9b3d_9a29_2c94_f391, - 0x2476_66c1_6beb_0949, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6942_a75b_0f86_97d1, - 0x1e65_3555_73de_ffb9, - 0xcaa7_5277_14cc_174f, - 0x0bd5_3c52_fdd8_9e3f, - ]), - pallas::Base::from_raw([ - 0xefbd_85ab_0779_2a56, - 0x94ee_6dd3_5be0_b609, - 0xe2e2_ebf4_4c60_80ad, - 0x37e7_f6b5_6da4_f564, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa785_938c_daf0_a82c, - 0x0ff1_052c_6b0f_e01a, - 0xa3a3_4892_9645_d506, - 0x35fc_4d9f_25e4_ee0c, - ]), - pallas::Base::from_raw([ - 0x1bd8_1387_35d5_eed0, - 0x2031_6e2b_4402_2210, - 0x1de4_87e5_3382_18c8, - 0x2639_15ef_7bb7_ac86, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7270_5394_9d68_af25, - 0x31ec_3a68_bc55_8512, - 0x6224_b2b9_4190_4745, - 0x2bae_d2fb_bfa0_7f92, - ]), - pallas::Base::from_raw([ - 0x1585_ad6e_c39d_17e7, - 0xb3f4_5d31_7909_30e0, - 0x10f2_cf93_6dce_27ab, - 0x3ac7_25dc_a3cc_5a5b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x16d5_99fd_795e_e6d3, - 0xa832_7e0c_535a_268d, - 0x66f3_59f1_a2d0_c9a0, - 0x0b43_b8cf_c755_ef13, - ]), - pallas::Base::from_raw([ - 0x771e_bb8c_9993_734f, - 0xe22b_9efa_7f0e_8978, - 0xf847_286e_a0aa_95f5, - 0x3cab_00dc_f0cb_4e65, - ]), - ), - ( - pallas::Base::from_raw([ - 0x940e_5b99_9381_5ed6, - 0xe458_f932_4ac9_8472, - 0x7277_a9b2_a4c6_6b96, - 0x2a9b_1dbb_3571_6aff, - ]), - pallas::Base::from_raw([ - 0x1d1e_8561_7c5f_74fa, - 0x04e0_d957_2d5e_bdec, - 0x697f_9f0f_730e_36dd, - 0x3196_6863_7d6b_29ae, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf4ec_666a_be5d_ceba, - 0x4e55_7554_6220_3670, - 0xc2c0_90b4_a237_cb56, - 0x32ae_228d_d97a_e433, - ]), - pallas::Base::from_raw([ - 0xad96_69b3_e76e_a998, - 0x91e7_879f_ed57_7b7c, - 0x1e41_9d83_9e6c_94d7, - 0x048d_94ba_a0e3_0800, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6c90_7b9f_576a_7619, - 0x7bb1_599f_1d1c_9120, - 0x3b2f_e84d_d429_e90c, - 0x33d9_fbea_8acc_5ae9, - ]), - pallas::Base::from_raw([ - 0x549a_ec50_44ca_17ec, - 0x645d_16ee_dbae_2cd2, - 0x0ab1_6a27_9c8b_feef, - 0x3ce8_42b9_6fec_08f2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x66fe_abea_b49c_bc29, - 0x831b_43fd_4f80_1ad0, - 0x8963_b81f_a95b_9f77, - 0x3fff_5b9f_33a9_c8da, - ]), - pallas::Base::from_raw([ - 0xb846_fdb3_3ece_c0f6, - 0x028f_eede_2d86_2dc1, - 0xb6fe_b8a0_d783_8453, - 0x1ebf_fb3e_ea47_f184, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdbd3_28a6_187e_d102, - 0x4d92_bae1_fab1_c408, - 0x5036_8ca9_4dc4_3f5c, - 0x03e9_6590_9135_7f5e, - ]), - pallas::Base::from_raw([ - 0x6929_1025_5164_3cbe, - 0xa488_9bf3_bc56_9b53, - 0xf020_bfe6_2ccd_f413, - 0x0128_5e40_0aa2_8746, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8a24_35af_b4a2_12b6, - 0x5132_1588_3ffa_9384, - 0xba59_b535_c741_b302, - 0x024f_79e6_c546_5014, - ]), - pallas::Base::from_raw([ - 0x708d_0744_747d_b6bd, - 0x4ba0_0f9c_9956_4ab8, - 0xa6a1_8626_802b_0d85, - 0x1180_93b3_83be_9f5f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4e81_e880_ac86_3341, - 0xb199_dda5_ee5c_d052, - 0x4bfb_9edb_2b9e_40bf, - 0x31f3_ccf9_bc82_4e71, - ]), - pallas::Base::from_raw([ - 0xc77e_ac27_414c_a39a, - 0x75e7_9a0b_3e2d_8063, - 0x0622_1629_392c_7383, - 0x003f_f9a6_01db_549a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x19a3_fe6e_8919_9977, - 0xcaae_dcab_3a2a_1fdc, - 0x5d08_6ffb_b871_b05d, - 0x1009_d4da_10a2_540b, - ]), - pallas::Base::from_raw([ - 0x3e52_b60b_e56e_d8d2, - 0xa1d1_62c0_5220_5502, - 0xdf1e_4b5f_9eff_40e2, - 0x3983_0483_a475_7d5e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8a0e_979e_fd3e_fc28, - 0x4949_282d_94e0_8968, - 0xf2b2_9f4b_9c13_6beb, - 0x10ff_7bf3_f711_ca78, - ]), - pallas::Base::from_raw([ - 0xf3ac_a739_fe6f_9a2b, - 0x24a4_32dd_3b09_89e1, - 0x2f22_37ec_e69c_8858, - 0x2d7e_82a5_6448_019f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0dd9_25b4_b2b2_2f7c, - 0x5f56_b22a_a5b3_3623, - 0x57d5_9fe0_f291_a84c, - 0x0d09_972b_30f1_be14, - ]), - pallas::Base::from_raw([ - 0x3374_d4c2_52f8_d6b4, - 0xc076_3cb4_bdd1_d03b, - 0x0075_cad7_fa9b_c762, - 0x3231_c543_5a25_3b5f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd27e_395d_361b_5ec6, - 0xbf65_b40b_5fa3_aa57, - 0x6ebe_d47a_734c_d047, - 0x1c72_49cb_9959_520b, - ]), - pallas::Base::from_raw([ - 0xdaa7_b8e5_921f_ef38, - 0x96ef_2a6d_ad05_ee3f, - 0xc6f1_76e2_fc0b_18a4, - 0x389f_6781_7075_8a4d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb719_cae7_9e3e_eee7, - 0x7195_0578_1db1_15a0, - 0x4bf3_df1d_89d4_101a, - 0x1180_028a_0688_b2fe, - ]), - pallas::Base::from_raw([ - 0xead4_6a5b_c181_84fa, - 0x752e_4ef1_9ed1_d259, - 0x6987_464e_4442_6e0f, - 0x0e76_4f02_842d_9e51, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4fc8_561b_e0e3_7afb, - 0x4e22_7ecd_b7af_8143, - 0x18e5_adcc_3d30_4460, - 0x1c1d_1e61_5c90_5b8a, - ]), - pallas::Base::from_raw([ - 0xe84b_9fc9_fa1a_3202, - 0x64d2_8a73_dea5_979f, - 0xa1b7_2a78_52c4_ace3, - 0x3176_462e_9090_e088, - ]), - ), - ( - pallas::Base::from_raw([ - 0x073d_58c4_427d_406e, - 0xeaae_a64c_9da4_b973, - 0xdb2b_606a_ce9c_98fd, - 0x320d_ab61_0606_cff0, - ]), - pallas::Base::from_raw([ - 0xf6f5_6017_e567_b738, - 0xad8b_2fa4_c80d_6dcf, - 0xef76_6787_acc5_eec6, - 0x2046_af02_0cc2_8cfd, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdfe0_be8c_ea45_93e2, - 0xbf25_71e6_2c01_a757, - 0x5646_bd2a_721f_cde4, - 0x2e56_8465_0c5e_df5a, - ]), - pallas::Base::from_raw([ - 0xc367_119b_e723_3de0, - 0xa859_64d3_8319_d7e2, - 0xbf56_4106_7772_44b3, - 0x05a7_a0a3_f91c_3fe3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa157_1fb9_7ebd_b1cf, - 0xad70_58d4_9484_4afb, - 0x22ff_383e_fdf9_34da, - 0x03a8_f536_628d_a555, - ]), - pallas::Base::from_raw([ - 0x89a6_b560_8b35_83df, - 0x93d8_765b_4bb6_3abe, - 0x6607_c289_c75e_39ce, - 0x0846_7ac7_d613_3c93, - ]), - ), - ( - pallas::Base::from_raw([ - 0x09bb_0aa5_c0f7_596d, - 0xc0b7_9d5e_0a31_3f09, - 0x25c7_ae48_63c8_df2d, - 0x340f_7178_57c8_c4f5, - ]), - pallas::Base::from_raw([ - 0x58d6_0999_e9bd_175c, - 0x413c_51e3_6936_3dcc, - 0x44bf_08fb_a5bd_cc5f, - 0x09d9_43ab_4210_7233, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7660_e2b2_190b_69a3, - 0xa675_e6bd_1268_5aba, - 0x70c3_464c_345f_61a3, - 0x0c06_a269_203a_835c, - ]), - pallas::Base::from_raw([ - 0x5ea9_81b8_2f7f_4ab8, - 0x270c_896c_5e02_6b95, - 0x410a_6beb_1116_7954, - 0x25cc_f45d_51f9_413f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x83b6_8e9a_1a6a_c28f, - 0x252f_9079_e85e_8c2b, - 0x3dd5_a334_3f27_7d23, - 0x1f00_6677_bdfe_d386, - ]), - pallas::Base::from_raw([ - 0x21c2_597c_a01e_4b39, - 0x1195_b279_cab6_3aa8, - 0x5947_c45d_89d5_371c, - 0x0bfd_bc05_76f2_f69a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x56aa_cca5_f6d6_aeae, - 0x00de_b6ed_5b56_175d, - 0xe99e_0920_f6e3_ac48, - 0x1970_6df9_fa50_7068, - ]), - pallas::Base::from_raw([ - 0x68d1_0152_dcd8_93fb, - 0x05ce_c81d_e5b3_7f47, - 0x7f83_e062_2c1f_9c14, - 0x31cb_805d_ed05_7b35, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf740_8933_84f5_3c01, - 0xa65d_85ad_4b70_3a91, - 0xe988_f151_9c16_9eb4, - 0x39b7_6368_9c50_4537, - ]), - pallas::Base::from_raw([ - 0x8fcc_2881_8f89_9d3c, - 0x9a09_7667_344e_b7ed, - 0xc77a_ff9a_1099_b9ac, - 0x3c20_f228_e53f_9a40, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3e5f_02b6_0499_512f, - 0xc6aa_35d0_b5fc_7e3e, - 0x310d_1554_993b_9077, - 0x3b2e_af1c_97a7_e598, - ]), - pallas::Base::from_raw([ - 0xc7eb_cb64_9b4c_42bf, - 0x2bf3_2b91_10f2_ce19, - 0xd0eb_b868_6884_a28e, - 0x025e_43d6_95a4_e968, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe521_3aed_05e9_77a3, - 0xfe91_23c6_366e_6089, - 0xff9d_b1bf_4bbd_55c7, - 0x2806_f809_7feb_4387, - ]), - pallas::Base::from_raw([ - 0xf2cd_f9d7_d0fc_3fa3, - 0x277e_e79b_e9e8_6ab7, - 0x37c9_96f8_8238_9c4e, - 0x37d0_9ecf_faad_6231, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6d97_b12d_3d3a_a165, - 0x3ca0_bd33_97db_0743, - 0xc6eb_cdf5_27ec_2a4c, - 0x377f_7772_587b_c8e2, - ]), - pallas::Base::from_raw([ - 0x2563_f930_3ffd_2e65, - 0x54e7_472c_ef1a_9b21, - 0xfdf1_b209_a4ba_4952, - 0x285e_bf94_09ad_7630, - ]), - ), - ( - pallas::Base::from_raw([ - 0x300d_9e13_f84f_0abb, - 0xd16d_7740_9c8d_c8d6, - 0x88b4_6edb_02c4_9705, - 0x05c4_e9fb_bada_d36d, - ]), - pallas::Base::from_raw([ - 0xf151_5ce8_bead_7602, - 0x3928_bb28_9b22_02ae, - 0x11dd_8076_58b5_38d9, - 0x0bef_8f47_2c87_7974, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9182_5076_acdb_4b23, - 0x5e1d_aab6_2b52_5e01, - 0xd348_f694_cf00_7eab, - 0x0fcc_10bf_2527_b056, - ]), - pallas::Base::from_raw([ - 0x80f6_acc9_9258_cb51, - 0xc15d_6f31_1e48_7046, - 0x3042_b48e_8bab_078a, - 0x3cf4_7fcf_48ab_5d1b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6c13_9e12_49ce_58fd, - 0x04b0_81f9_23c7_d9e8, - 0x8f7a_9239_88e5_0d43, - 0x1fca_3b8d_b325_a3be, - ]), - pallas::Base::from_raw([ - 0x692f_f292_5bc7_efe1, - 0x375d_358d_b102_d895, - 0x7377_f146_2112_ee7e, - 0x22b9_ca2a_74d3_accf, - ]), - ), - ( - pallas::Base::from_raw([ - 0xda8d_d358_9491_7794, - 0xe067_e06d_8977_054b, - 0x68e7_65cf_e835_3e99, - 0x2c7b_ae76_7c60_05c6, - ]), - pallas::Base::from_raw([ - 0xbf71_5d06_4e5e_e34f, - 0x9c99_a7e1_8746_abeb, - 0x7615_e9eb_5e16_ccc4, - 0x328e_84b7_73ab_f7fa, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfe57_fcce_7fa3_b8ee, - 0xc9c2_448c_f7c2_687a, - 0x6fd2_be38_efd3_c2d4, - 0x0288_6502_ad64_3ca2, - ]), - pallas::Base::from_raw([ - 0x4bc1_9841_b03f_4d5c, - 0x460b_ea82_dcb0_7401, - 0x95b2_4a5e_6c57_84b4, - 0x2bfb_f8ee_7da6_9c92, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd39f_ac30_c415_232c, - 0x76dd_a79e_3bac_418d, - 0x146a_5061_cc03_a8bd, - 0x33d1_e61b_23b0_45c8, - ]), - pallas::Base::from_raw([ - 0x0a86_1d38_a0c1_6167, - 0x3403_d750_3625_fd76, - 0x5c14_43d8_4dfc_5111, - 0x11c4_166d_43ca_34b8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x59d0_4901_73f3_dc32, - 0xba05_8d5b_fec4_3964, - 0xe934_dd16_6639_b95a, - 0x2bbb_c6ea_bb03_cde0, - ]), - pallas::Base::from_raw([ - 0xee85_cf18_4523_3d07, - 0xee68_4cb6_e0a9_3cf3, - 0x256b_3bba_79ee_21d0, - 0x1922_24ec_0f7f_7bb9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5e0d_4224_2670_e7ae, - 0x1625_3e15_14a1_7a12, - 0xdc19_7727_5d06_feee, - 0x1945_e2c3_3e05_75dd, - ]), - pallas::Base::from_raw([ - 0xd13a_150f_7299_7634, - 0xfb54_5fc0_aeb3_d878, - 0x30f3_976d_4f5b_fab9, - 0x39e2_8dd6_964e_57c2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6338_94e3_1def_1331, - 0x178a_dcd2_9172_17f0, - 0x661d_3878_6be1_3883, - 0x3408_a710_6fc8_2ce2, - ]), - pallas::Base::from_raw([ - 0x342c_2e44_c71b_ed3f, - 0x96de_42e1_09ee_70d6, - 0x8589_6891_dd66_820f, - 0x0741_8793_5d70_7bcf, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc10b_7e08_f2dc_891d, - 0x5d68_913c_d9e6_d01e, - 0xdd5d_234c_090b_3903, - 0x15f0_5b8d_a216_b34d, - ]), - pallas::Base::from_raw([ - 0x7962_faa0_cf7a_f257, - 0xaeb0_181c_1252_a47d, - 0x1261_6f4b_f1ca_e2a5, - 0x2322_da04_1fbd_9122, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6a1f_d4d7_4910_b554, - 0xe38f_1107_a34e_2dfb, - 0x68c6_f5cb_806b_3ea4, - 0x2b4a_4711_8c56_07da, - ]), - pallas::Base::from_raw([ - 0xc783_e3cb_01aa_1026, - 0x5c61_2654_288f_5199, - 0x6308_5aa7_4c7a_1afd, - 0x2be0_c52c_6093_c62c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xcfd8_887f_b984_673a, - 0x7d45_4af5_572d_847a, - 0xb8cc_5e6b_e457_cafa, - 0x05f0_5b4a_1514_6b31, - ]), - pallas::Base::from_raw([ - 0x9b83_b107_3366_b9df, - 0x7e64_4e6e_6208_ad83, - 0xe7f1_ff6b_4f7f_ecbe, - 0x315c_4707_e207_5aa1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x937f_a439_75f4_9b60, - 0x302b_b808_40e5_8700, - 0xb139_c191_3f5d_2668, - 0x37d0_f747_3f38_8e55, - ]), - pallas::Base::from_raw([ - 0x85c8_de85_e1bb_51af, - 0x248e_5ca6_6754_a3fe, - 0xfcd6_2e4a_d4f9_c873, - 0x33ff_0368_6ba7_d5c7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5e5b_adbc_d5fb_0443, - 0x78c4_d68d_9535_6613, - 0xfc3a_f91d_e825_cef9, - 0x0da7_ce87_e12d_4f1c, - ]), - pallas::Base::from_raw([ - 0x7ef0_5e88_6074_d377, - 0x4a7f_af08_52b5_609c, - 0x0b09_33a2_2f81_8986, - 0x0d6f_bbc5_de55_8690, - ]), - ), - ( - pallas::Base::from_raw([ - 0xaa91_03bf_b5ec_e132, - 0x1104_aaeb_126c_9c14, - 0x03d5_39c6_576f_6608, - 0x2297_a2d2_c5b4_e323, - ]), - pallas::Base::from_raw([ - 0x60d6_c848_219c_e7be, - 0xb05a_10e1_00cd_63b0, - 0x429b_ea17_7b3f_4b88, - 0x0c1d_c916_f323_e7ba, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7e91_af55_41b0_8bf4, - 0x7eb7_87f3_ce5f_d6b1, - 0x716d_a388_45f1_2b56, - 0x0b63_6e98_ac64_6f4d, - ]), - pallas::Base::from_raw([ - 0x4ab7_12d1_a43e_13db, - 0xe60a_52eb_e24b_27bf, - 0x056c_fba5_2b55_7f09, - 0x1fac_62f4_32cd_f236, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2dfa_15b7_ebbd_e631, - 0xb320_f94d_a9c0_63af, - 0x1b77_601c_50e8_6a37, - 0x3d4c_2ff5_d00a_3876, - ]), - pallas::Base::from_raw([ - 0x272a_3417_43de_26bc, - 0xaea5_4b59_4992_3c71, - 0x0c4d_e807_c535_b183, - 0x2765_c806_aec7_71a7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x55ec_8f25_7b63_e13a, - 0xd5fc_34d5_66ec_9ee8, - 0x56c2_e320_91d0_8278, - 0x1691_2185_0e3d_dc23, - ]), - pallas::Base::from_raw([ - 0xa148_4983_bee5_638d, - 0x8a79_eb1b_c492_8b71, - 0xd6df_d4fc_d029_984b, - 0x2cbd_3698_162f_9ae9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7a1b_05bc_e3c4_7320, - 0x32a7_6039_297e_8409, - 0x732f_44e5_5380_a997, - 0x202a_a34a_e870_a44e, - ]), - pallas::Base::from_raw([ - 0x4868_6f6e_4f31_74e7, - 0x36ff_575c_ae12_a1e3, - 0xe09a_f42d_581b_50a7, - 0x2114_4937_0a1c_f825, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdb42_2a77_b183_1102, - 0x7bf8_c21d_1049_98b1, - 0xce43_b79c_9ad6_75f9, - 0x349d_78c6_a718_8921, - ]), - pallas::Base::from_raw([ - 0x3070_ba0f_699f_080f, - 0xd134_f6e0_36b8_c18a, - 0xda34_d0a7_2cd2_aa3f, - 0x2945_7a3e_37c3_b020, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6fa1_6666_d21b_774e, - 0xb91f_c4b1_0e6f_767c, - 0x12af_8401_416c_df0b, - 0x220f_43a3_4cc1_d1a0, - ]), - pallas::Base::from_raw([ - 0xab2b_060c_b26e_f892, - 0xe580_8ab1_a538_10e2, - 0xf36f_e472_3313_570c, - 0x36f1_3b73_3934_59b1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4e49_ebb2_947d_b488, - 0x242c_04d3_d97d_c253, - 0x9f41_d8d8_d7fd_b017, - 0x013c_52dc_adff_81e0, - ]), - pallas::Base::from_raw([ - 0x0a29_7aca_54ca_ebd9, - 0x63b0_abde_e434_9e09, - 0x51d0_948c_c749_f20b, - 0x069a_8db0_9a55_b0f4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x406f_b28a_71f7_8032, - 0x969e_b429_82fe_4929, - 0xb1af_24a1_53c8_2095, - 0x052a_3255_a165_23a7, - ]), - pallas::Base::from_raw([ - 0x98f1_82b9_5ac3_dcd2, - 0xb088_ed0c_bf43_f3a8, - 0xf950_fe2d_c059_db22, - 0x1440_06da_cd6f_d539, - ]), - ), - ( - pallas::Base::from_raw([ - 0xda59_fedf_ac9d_3f1e, - 0x226a_cb4a_3e98_29b1, - 0x3a73_3388_a504_88dc, - 0x3891_f70a_133b_a457, - ]), - pallas::Base::from_raw([ - 0x25c4_6ed8_4bf2_d71f, - 0xbff1_2fe2_1b00_e737, - 0xaedc_6377_1e3f_8787, - 0x0ed1_b27c_c7ef_d5ac, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc0d0_516d_40d3_cc81, - 0xa649_0816_1677_43c9, - 0xca42_f4c4_4243_c1d5, - 0x23b3_8f5b_b23d_8b5e, - ]), - pallas::Base::from_raw([ - 0xed2a_a32c_dcc3_fa23, - 0x8cda_3463_fef1_02c3, - 0x6b5a_f006_e433_ce3c, - 0x1225_df05_7f84_56b2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8291_0d73_56a0_e04c, - 0x64b6_73ac_c38f_66f0, - 0xdd23_f657_9d03_0932, - 0x2e91_cf8d_0328_73cd, - ]), - pallas::Base::from_raw([ - 0x6c94_8550_64c0_d6b3, - 0x7a29_80d2_5e0a_beb0, - 0xb651_e0fb_26b8_1656, - 0x3b5a_8440_9640_1532, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbadb_8627_9571_bbfb, - 0x124b_4809_a75e_8835, - 0xc9e7_00a7_4761_1c17, - 0x0920_b057_f207_5bcd, - ]), - pallas::Base::from_raw([ - 0xedf4_28d2_7f57_6e69, - 0x81db_b861_29e9_b438, - 0xfa8e_eed3_1e15_ec93, - 0x1126_9fbe_894e_0bed, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb1f4_fe1d_7c44_7f1f, - 0x83c4_259d_9758_51fc, - 0x117c_2cb5_bf1e_601b, - 0x22d9_4c09_d954_00dd, - ]), - pallas::Base::from_raw([ - 0xd683_7d9f_b5d2_4924, - 0x313b_2636_f504_0619, - 0x2b63_fc49_08e0_48d6, - 0x1144_ded2_0553_ac9c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x387c_b408_a242_5394, - 0xd079_369b_b24c_53d9, - 0x8f15_d008_d9e9_d4c3, - 0x3150_c6bf_e2c6_f49d, - ]), - pallas::Base::from_raw([ - 0x0404_728f_c1f7_729d, - 0x7867_a4bd_2454_fc8c, - 0x41ce_532d_3e8a_12e2, - 0x1ba3_02a9_468e_f35f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3db3_09bf_c9b3_4ec5, - 0x5033_0f96_20ca_8bcc, - 0xa8ba_c058_76aa_2be0, - 0x1448_b16c_5253_7aeb, - ]), - pallas::Base::from_raw([ - 0xc139_ae90_00d8_2a6f, - 0xe882_76a0_e243_47b5, - 0x3ddd_9c6e_1e82_af5b, - 0x36f6_2912_c020_70b8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1402_2b05_d861_fd8f, - 0x41d7_89f5_50b6_a9e6, - 0x87d2_6c5d_6fc8_2332, - 0x02f8_35e2_95b6_562e, - ]), - pallas::Base::from_raw([ - 0xbeb9_3c06_52f7_4ad8, - 0xe619_72c1_05e4_cd9d, - 0x884a_8d7f_678f_75dd, - 0x2874_6006_1cc8_886f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x69f1_75ca_c3b9_58f2, - 0x6747_f1ef_abb5_3998, - 0x46ec_4c53_0949_f44c, - 0x07ba_e7f2_46e1_1e0e, - ]), - pallas::Base::from_raw([ - 0x1021_d25b_0c19_dc41, - 0xea7a_36bd_9497_28f4, - 0xa859_e7cd_2cea_c8a7, - 0x0efc_9a8c_f825_3990, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5dea_1fb9_0da5_a77b, - 0xc0e1_3bb8_134a_bcc6, - 0x9938_d35c_c9ea_b2d4, - 0x2283_5512_a16b_cd1f, - ]), - pallas::Base::from_raw([ - 0x9be9_eaf3_1b0f_ad7e, - 0x3491_2b52_0ca1_71f9, - 0x0721_8f00_31b9_ac7e, - 0x0e74_f8e8_90c4_692f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6b4a_0ce4_26ac_5fb9, - 0x13cf_2331_e171_707e, - 0x8539_192e_4fcd_6ea1, - 0x128c_aa53_6e03_01ab, - ]), - pallas::Base::from_raw([ - 0x6e6b_8cb3_43a7_fcba, - 0xb4b2_353a_6472_323d, - 0x4867_0871_a8fd_61a2, - 0x11c8_bcf8_bdca_1c4d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8f8f_bb6f_6f0c_7693, - 0xa8cd_2c9f_9f6f_9eda, - 0xf8f7_1e1d_01ab_dafa, - 0x301a_41e0_0512_a1dc, - ]), - pallas::Base::from_raw([ - 0xcb70_6c7b_9d80_868f, - 0xf2a6_d279_5c03_64f4, - 0xbf2a_e148_ec6b_7343, - 0x303f_3b4b_74c4_59b8, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4c67_a5c8_e007_8e3b, - 0x5a11_f487_f259_6bcb, - 0x52d4_26c8_e498_b8aa, - 0x1bf9_81ee_4546_e1d6, - ]), - pallas::Base::from_raw([ - 0xb25b_9eda_f3c4_0ace, - 0x4cd8_57e5_5ff9_a68e, - 0x4c57_4295_a50b_e5aa, - 0x1457_bcd8_9f13_ef72, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6e49_8196_9af9_5023, - 0xa9f4_ad41_da85_fd4d, - 0xf643_d9f0_fcdb_da79, - 0x1077_61df_2dd6_6275, - ]), - pallas::Base::from_raw([ - 0xfa32_bd06_b1af_c76e, - 0xe61c_2fa4_1da2_cb0e, - 0x4c70_289c_043c_e9ed, - 0x2056_dd5d_ddfb_d391, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe6f7_b311_a5eb_8af4, - 0xbbcb_dea1_4f28_c13d, - 0x832a_fc2a_c06b_48c0, - 0x1884_c484_9a23_39d1, - ]), - pallas::Base::from_raw([ - 0xae85_ea27_cf05_147e, - 0xa661_d654_5ad7_8770, - 0x8cff_b5bd_23cd_1e02, - 0x0c4a_a17a_3d59_87b0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0903_2b71_20d2_c6d6, - 0x631f_355d_d06d_ccc6, - 0xf87c_c78c_ef4a_6b96, - 0x3ef8_d7d1_dc6f_9f9d, - ]), - pallas::Base::from_raw([ - 0x43ce_ad49_48dd_c9d2, - 0x2dc3_7407_7cca_9ffc, - 0xac61_ddbd_67db_3e8d, - 0x0297_f7b8_d03f_dedc, - ]), - ), - ( - pallas::Base::from_raw([ - 0x361c_0eb5_afba_a00d, - 0x8051_789c_48c8_8225, - 0x9887_1616_2649_2d22, - 0x3d51_6690_501f_18a2, - ]), - pallas::Base::from_raw([ - 0x3a63_1bfb_843d_d126, - 0x4a8c_64d0_c4eb_0522, - 0x9124_952e_3015_76f3, - 0x1a00_2583_79af_10c8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd1b3_d060_1eee_6e43, - 0xc4c5_f777_afcb_3d7c, - 0x5890_cf65_cdee_4f41, - 0x3bac_6dcd_6ca7_0869, - ]), - pallas::Base::from_raw([ - 0xddf9_20c5_9c7d_0fc6, - 0x0586_3a0c_6afe_2d3d, - 0x14d2_e276_9317_f416, - 0x1b0a_6eba_dac7_b097, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1396_4ab6_46aa_aa39, - 0x63ab_087a_ae54_f31b, - 0x6d98_908d_b903_5320, - 0x38d0_a593_6ed6_9ee0, - ]), - pallas::Base::from_raw([ - 0x63ad_df45_aee3_572a, - 0xce8b_2242_3aa8_96fe, - 0xddc1_4261_c724_5d07, - 0x3535_1cd4_d4f9_1ba2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb5ca_a06f_a744_e9dd, - 0x38e3_7f58_5670_d457, - 0xb4df_a467_546f_0bbb, - 0x01c3_1821_87e9_c394, - ]), - pallas::Base::from_raw([ - 0x735c_1df3_1c86_a46f, - 0xc35a_47e7_9530_8784, - 0x0b2d_cd84_17ad_d715, - 0x106c_dfe8_b63a_2baa, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1a6e_026d_0c07_0abb, - 0xaca9_b562_15b5_32b2, - 0xd41e_5c95_365c_f30a, - 0x288d_ca02_8dc0_36dc, - ]), - pallas::Base::from_raw([ - 0x662c_4ded_8523_98ed, - 0xb2d7_be0a_1d12_423d, - 0x3ec6_e3b5_de20_815c, - 0x291f_f461_d024_af8f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb09f_fa66_d16c_27ec, - 0xa1da_22b0_8593_d72a, - 0xe632_9240_dc54_eb20, - 0x1a76_7954_e044_678d, - ]), - pallas::Base::from_raw([ - 0xe6fa_cd09_85a5_0427, - 0xd348_8598_eddd_f7b2, - 0xd7a2_306f_08c8_bcc4, - 0x14f0_fcd5_0316_e459, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8f32_c8f3_5b64_6f4e, - 0x21aa_08fc_88eb_4def, - 0x2801_597f_de58_9a34, - 0x3a30_a417_2ad6_0466, - ]), - pallas::Base::from_raw([ - 0x7d06_9540_e011_19ee, - 0xc967_557c_731b_7356, - 0xda5a_4c02_83a4_2f1d, - 0x3d3a_57fb_c972_c1e0, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd3c1_f6cc_c3e0_2a53, - 0x0547_5fdc_7ec7_1268, - 0xf000_9637_f19f_5b9d, - 0x30ff_defd_ca48_bd81, - ]), - pallas::Base::from_raw([ - 0x91ae_9409_8215_c29a, - 0x6132_5ed0_20eb_03f6, - 0x7902_c795_04be_18dc, - 0x2fd2_0d09_cb6b_ffe2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1a31_a60b_d542_73dc, - 0xdb7f_1cc7_04b6_b150, - 0x1861_c054_0121_d013, - 0x206c_c173_9153_a5a3, - ]), - pallas::Base::from_raw([ - 0xe0e9_cb82_5775_fbd5, - 0x4376_49cc_7524_f7df, - 0x7bd2_080e_2134_cd15, - 0x31f0_de88_e2da_7e71, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfc72_8173_780b_d7a5, - 0x7aef_d664_bcbf_065b, - 0xb00b_a3b7_0b2c_e355, - 0x3699_84a7_28c9_f5db, - ]), - pallas::Base::from_raw([ - 0xce09_1005_839f_4217, - 0x3295_dcc5_fe7c_58a3, - 0x5aa3_0609_bda0_b60a, - 0x0241_cf89_cdbb_b0f2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1b00_1931_9eba_29b1, - 0x7216_7d55_26f9_8da3, - 0xe7cf_f705_a799_754f, - 0x2990_fd50_70f8_dc2b, - ]), - pallas::Base::from_raw([ - 0x1eed_c7c4_49c6_3e99, - 0xbbf4_2638_ef85_5544, - 0xf755_cb96_23f0_a42e, - 0x01ee_b0e0_5fe3_1d97, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe37e_1f9e_40b1_54a3, - 0x652d_23f0_cc13_026d, - 0x8e86_4190_1d49_7ee8, - 0x0664_9f66_0725_b3b9, - ]), - pallas::Base::from_raw([ - 0xf17e_dcbc_83c0_56f4, - 0xbb63_cec3_3dc1_383f, - 0x8e3f_6121_894f_a536, - 0x3c11_2d8a_1c60_b07c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1a3e_7d79_56bb_fe12, - 0xa7a9_ca39_4c1d_37be, - 0x9740_4aaf_c9c4_a82e, - 0x38aa_35a0_3d7c_378a, - ]), - pallas::Base::from_raw([ - 0xb631_7d5e_8de0_bb5d, - 0xdc67_9917_adbc_69d0, - 0x68b9_71fe_c7f3_8566, - 0x1989_cd89_9970_7a95, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb220_5013_ba92_96bb, - 0x2058_da75_36fa_a776, - 0x0436_5be3_f84a_c088, - 0x1af4_7a2f_3b0f_a032, - ]), - pallas::Base::from_raw([ - 0x2abf_4796_3d43_d58f, - 0xb235_0d75_403d_f0f1, - 0xa021_f706_77fe_3e5a, - 0x322f_cdad_4c07_7b90, - ]), - ), - ( - pallas::Base::from_raw([ - 0x06a9_ae6c_cbe5_d5d4, - 0xaa6b_45d7_03a5_e6f6, - 0x4614_a78b_bebe_0932, - 0x18cc_6bd2_2c90_ec21, - ]), - pallas::Base::from_raw([ - 0x967c_718d_fed8_a0b8, - 0x95a7_bc7f_31b3_4247, - 0x5a19_1faf_19e0_da2c, - 0x115b_c841_1338_488f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1d51_ca19_915e_a485, - 0x0b43_77f8_251d_b7af, - 0x0825_fb37_e0ea_5a48, - 0x1548_072e_3b8c_9cbf, - ]), - pallas::Base::from_raw([ - 0x48eb_6bb8_ab54_4b29, - 0xae66_f29c_ec75_ea3a, - 0x3195_4ba2_167a_b49c, - 0x3d57_aaaa_db93_5f7b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0c46_3390_d414_4397, - 0xb683_52dc_4bf0_80f6, - 0xa6a1_5861_0737_0e45, - 0x2400_81aa_ffbc_d341, - ]), - pallas::Base::from_raw([ - 0xbbef_dfca_46b3_a803, - 0xc3dd_0e85_0c04_6877, - 0x71e3_e8e2_2feb_ec64, - 0x08a9_eaf7_b5a5_39fc, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5e06_c2b1_b31b_93b4, - 0xc313_a37c_4320_dc75, - 0x7efc_a295_2612_6f7b, - 0x0aff_f83d_40bf_1741, - ]), - pallas::Base::from_raw([ - 0xc7cb_8f4c_fdc8_1d4b, - 0x5a50_fd94_f40c_8457, - 0x71d6_4791_1e74_f12b, - 0x1541_6661_ee80_7c70, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2802_c3f2_89e9_5d61, - 0xf33c_77fb_6c07_ea84, - 0xbbc9_320f_0df4_143a, - 0x356c_a3df_9cc0_4f80, - ]), - pallas::Base::from_raw([ - 0x4f45_fa2b_9fd8_1daa, - 0x7f47_5e59_7199_616e, - 0x7d3b_df29_ce4e_dfb5, - 0x1dae_8d6b_f927_1f87, - ]), - ), - ( - pallas::Base::from_raw([ - 0x473f_87de_7e94_192f, - 0xd393_9d88_1211_44b0, - 0x963b_e798_1010_c5ea, - 0x17ef_3597_df23_de2e, - ]), - pallas::Base::from_raw([ - 0x1e95_8dac_55e3_db76, - 0x12d2_c681_d82e_ed9c, - 0xd3d5_1684_1d5e_e0cf, - 0x0ac9_26dd_9cea_3447, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6858_89c4_1505_8b08, - 0x6db7_b0e4_db13_97af, - 0x5b80_1548_f65c_a777, - 0x0bc7_e844_145e_084b, - ]), - pallas::Base::from_raw([ - 0xe538_4d8c_3f79_208a, - 0x151f_22e1_29fd_3354, - 0x7a90_a95c_27ac_21db, - 0x19ed_e445_2202_a655, - ]), - ), - ( - pallas::Base::from_raw([ - 0xded8_57fc_ee32_3789, - 0x0bfe_aa0f_301d_6f33, - 0xf39c_96d3_5d9b_bf6d, - 0x2a9d_8309_fabf_976f, - ]), - pallas::Base::from_raw([ - 0x528c_0f45_53ee_3161, - 0x6dca_d2cc_ef93_aa93, - 0xe704_f08a_2ec9_996c, - 0x1bfd_16da_cc0d_2d3f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x188b_8471_e40c_3640, - 0xa201_8659_0697_76d0, - 0xd08d_57e0_209d_0571, - 0x1a90_63bb_e154_64ae, - ]), - pallas::Base::from_raw([ - 0x568d_9049_e597_c096, - 0xdd50_78d0_87aa_87c5, - 0x3c15_73d9_7187_5ef2, - 0x388e_691e_ea9e_23f4, - ]), - ), - ( - pallas::Base::from_raw([ - 0x40ab_3fc1_9370_1560, - 0x29ce_a290_2ec8_40f5, - 0xd75d_0b95_a9f7_f97b, - 0x0af0_7979_abd8_c613, - ]), - pallas::Base::from_raw([ - 0x5c15_cad2_0553_9ced, - 0xc602_0943_036b_091b, - 0x4c2c_78ce_e591_7f5e, - 0x1959_acff_f5a3_4bf9, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfa8d_876d_7cc0_0fb8, - 0x5a9c_4a97_786d_19a1, - 0x12be_8115_3b9b_aee9, - 0x1a0f_2978_8594_d43f, - ]), - pallas::Base::from_raw([ - 0xed97_14bc_d4e8_8df7, - 0xe734_c0d3_0dd8_9ea3, - 0xec5d_2259_c86d_e1f5, - 0x1322_03f3_5788_8faf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x93b5_3b69_0484_8f93, - 0x1339_8c0d_df8c_cf22, - 0xf46d_112e_a566_4f42, - 0x0041_e2f5_f2d6_8640, - ]), - pallas::Base::from_raw([ - 0xb605_0c79_bc10_7760, - 0xee50_15ea_4b49_adac, - 0x65e3_2182_22f4_2268, - 0x31cc_6994_41a9_c0ad, - ]), - ), - ( - pallas::Base::from_raw([ - 0x94ae_ab7c_eb62_81ab, - 0x5228_ca94_d8f1_56ab, - 0x475a_af93_16b9_884e, - 0x1986_0f4a_6c3e_b16d, - ]), - pallas::Base::from_raw([ - 0xebdc_e98f_ed8c_6d40, - 0x0540_8297_454e_307f, - 0xd024_3225_3f4a_6703, - 0x1af1_a0e4_f57d_5be3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfa36_a92e_b85b_e634, - 0xb44a_ed3d_eab7_8850, - 0xbe32_58d6_6770_c14b, - 0x35ff_5141_816d_634f, - ]), - pallas::Base::from_raw([ - 0x500c_0c1b_ceaa_bd2c, - 0xf0d6_669b_f68a_ef2e, - 0xbd8d_f904_9439_9c72, - 0x2db1_ef2c_35ad_69d3, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc0b4_8b5d_58ff_c10c, - 0xe5ca_70be_a28e_8cd2, - 0xf439_95af_87ab_fbbd, - 0x0730_82f6_d583_d377, - ]), - pallas::Base::from_raw([ - 0x1062_30a0_d505_0d13, - 0x4b6a_3c80_f34b_c350, - 0xc6fe_8327_3096_a319, - 0x2230_637f_0cc2_89f0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x25e8_9191_c18b_b009, - 0x82f9_29c5_b2a1_8aad, - 0x3f85_1520_6a2a_9706, - 0x25fe_4261_1ed7_737c, - ]), - pallas::Base::from_raw([ - 0x8337_c552_d63e_02f6, - 0x73cc_77a9_0b10_5fb4, - 0x94db_e561_3bad_7a8c, - 0x26e7_36b7_a39f_c440, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0946_b650_b1c0_8743, - 0x9db9_c020_11b8_8c65, - 0xfa3c_4dca_cbf8_ff13, - 0x06e5_c844_eb13_24bc, - ]), - pallas::Base::from_raw([ - 0x3c8f_57f9_a8a3_70a1, - 0x37c5_8b38_e0fc_1baf, - 0x6b33_3515_afc8_813b, - 0x1a82_f5f2_799f_573a, - ]), - ), - ( - pallas::Base::from_raw([ - 0xbea1_5e63_420a_279b, - 0x8e07_282b_8912_351d, - 0x408f_f799_d86a_fd7d, - 0x078f_7b8e_ce6e_22e4, - ]), - pallas::Base::from_raw([ - 0x88bc_d999_cef1_ecdf, - 0x333d_9c44_d4e7_0bec, - 0x8035_febd_691a_b18e, - 0x1407_a098_70a5_1148, - ]), - ), - ( - pallas::Base::from_raw([ - 0x454c_97de_2584_aa5f, - 0xeec7_9406_7a27_a899, - 0x0955_d427_80d3_4702, - 0x1d35_9759_c143_d6ff, - ]), - pallas::Base::from_raw([ - 0xa816_af30_15f6_605c, - 0x0710_71d6_689b_a943, - 0xdb02_148a_c73c_a8e1, - 0x05dd_3dec_b765_a777, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdb80_38eb_d76a_fb2f, - 0x0dc9_0a9f_1c88_325d, - 0xcf8c_c81e_1622_6cf5, - 0x2a99_7c7b_a771_a172, - ]), - pallas::Base::from_raw([ - 0xe8c2_d9bd_2155_e22f, - 0x8a70_25a0_bd8f_e9a9, - 0x5be9_c192_1d28_e841, - 0x12ea_8763_5c8a_9c3b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4e5c_2298_84b8_933c, - 0x4677_86a0_b2a8_994c, - 0x1325_900b_c323_5b30, - 0x2a1e_4623_a4ae_cc18, - ]), - pallas::Base::from_raw([ - 0x566c_512b_6e4b_d49b, - 0xa74e_0f1c_1e2f_0b5d, - 0xcb43_553c_5583_6e1d, - 0x13a4_a175_6930_a346, - ]), - ), - ( - pallas::Base::from_raw([ - 0x503c_48f0_8921_2210, - 0xed91_7232_785d_86d0, - 0xc0c2_ad95_b9fd_35fa, - 0x0b03_ca6a_1e38_17f6, - ]), - pallas::Base::from_raw([ - 0x4c85_4c2e_f43b_beb6, - 0x3325_8fe3_0797_c712, - 0x7b2b_65b2_71d7_d17f, - 0x2608_45d2_59cb_fed7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5143_9665_16ca_1642, - 0xfaa0_77c5_094f_ad4d, - 0xcbc1_d869_aa7d_14eb, - 0x2cf2_0f0a_34c2_1025, - ]), - pallas::Base::from_raw([ - 0xad36_eea9_9921_cdc6, - 0x2e1d_370d_297f_0a41, - 0xc957_086f_0915_9341, - 0x22cc_cf10_e21e_1daf, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfb44_e614_c314_ad4c, - 0x8b24_db0b_dfd8_617d, - 0xd17d_196f_3f6a_9e26, - 0x27c8_ffd6_32df_7764, - ]), - pallas::Base::from_raw([ - 0xa5ca_43b4_390c_42dc, - 0xd7a2_791f_6a1b_568b, - 0x98a7_1f22_9c63_b251, - 0x31a3_0d03_e7a9_779d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf4b4_4ce9_8722_550d, - 0xdd93_8b22_0139_0ac8, - 0xfe86_f423_5227_eeaa, - 0x31d2_8dfe_adb7_adcb, - ]), - pallas::Base::from_raw([ - 0x5adb_7f33_74bc_7bdc, - 0xc10f_d1b1_2bb8_8630, - 0xae28_7ce5_935b_f41c, - 0x2a20_9773_8054_a39f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3be7_413e_3d67_146b, - 0xad57_cda9_2e17_75bd, - 0x2c5f_f9c4_e371_aee9, - 0x1b81_7a0e_2f33_4e49, - ]), - pallas::Base::from_raw([ - 0xa15d_8dfb_cd6d_2737, - 0x2a49_ce19_5f43_8fcb, - 0x4d38_1b52_1b1a_cfd1, - 0x0e93_ce94_5828_a23c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1f51_ce5d_d476_cea2, - 0xdd2f_92cf_2184_73d4, - 0x666a_9231_c766_0b6b, - 0x2b1a_a9ae_9756_b3fb, - ]), - pallas::Base::from_raw([ - 0x46a9_9cce_8c15_cca3, - 0xbf85_bbce_c460_d9aa, - 0x4e8a_a7b8_4aa4_1021, - 0x1780_a81a_6a2a_e54c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe17a_6b50_9568_c08a, - 0x259f_ae60_9e4e_fd82, - 0xaf7f_d128_3ec4_4bdc, - 0x1c09_ded3_74a6_91ad, - ]), - pallas::Base::from_raw([ - 0x70df_b9a3_3551_a4d5, - 0xfe2e_eecc_1187_c582, - 0x8586_f426_db21_1456, - 0x26a6_2ba8_9350_0fca, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5ec3_cd23_5624_6658, - 0x0bab_696b_14fe_b07f, - 0xf70e_9a72_5b80_1b25, - 0x22ff_987b_a1c6_cd80, - ]), - pallas::Base::from_raw([ - 0x7808_0fb5_8b7c_ee41, - 0xce4d_d83d_b956_929b, - 0xeac8_39ce_a74d_ddc4, - 0x2317_33ea_2b06_a86d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xaec8_6746_685d_fe1f, - 0xc218_0c0a_b71e_5168, - 0x8d76_6976_1a70_70fa, - 0x0008_c8a2_7bfc_9cdb, - ]), - pallas::Base::from_raw([ - 0xaa4f_3a36_9871_ca77, - 0x7b4c_0ea1_c1ad_696f, - 0x4ed8_5210_fab0_f980, - 0x3e6c_bd12_b49c_1bdb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8f6a_0cea_47e1_7bc8, - 0x2864_1feb_0791_af26, - 0x60a3_c179_c72a_2b89, - 0x10ee_4430_7ce0_cbf3, - ]), - pallas::Base::from_raw([ - 0x66aa_db97_f4c0_a463, - 0xe302_d7db_78d5_576d, - 0x482d_9194_87cb_1e2f, - 0x0e9a_4a4a_36ad_1881, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4c34_5c29_f898_6470, - 0xdff4_47e0_e1f7_6080, - 0xf9db_c0ba_062c_1970, - 0x06cd_6193_ac7c_e277, - ]), - pallas::Base::from_raw([ - 0x6104_a761_347d_3597, - 0x8280_faa1_48a1_e104, - 0xa011_5d0a_2f37_3747, - 0x0c73_50b8_829e_b73b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7a98_41a0_1d18_03f0, - 0x9dcd_a639_ea9d_d030, - 0xd91c_8c1f_f2fc_d414, - 0x22b1_7e59_75fc_4d7f, - ]), - pallas::Base::from_raw([ - 0xcaea_f461_5474_dd21, - 0x973b_49e9_4e35_150e, - 0x1a20_3ee4_03cb_bc49, - 0x2012_40e4_943d_2c2c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x75f1_33d9_1456_5351, - 0x1896_214f_0087_2854, - 0x0cd4_7ce7_26fe_ea9d, - 0x2663_26f8_7005_286e, - ]), - pallas::Base::from_raw([ - 0x1737_3826_4271_f35f, - 0xc7d8_f940_6e0a_7c1f, - 0x5924_d283_767f_9d5c, - 0x0eb5_0f0e_3127_577d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x68e2_0f5e_bd39_c14c, - 0x477b_6956_a99f_77cb, - 0x313a_9885_a170_99ce, - 0x1a86_5d1d_04a2_df73, - ]), - pallas::Base::from_raw([ - 0x0623_0fc4_c152_65bb, - 0x52dd_72d4_2781_e376, - 0xa418_49f5_864e_6635, - 0x10fa_c29d_eb03_270d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa57d_3895_4a64_fb15, - 0xca09_c64e_7421_cae2, - 0xf017_5c2b_ec60_fe7f, - 0x0195_07a1_b05a_ac7e, - ]), - pallas::Base::from_raw([ - 0x6075_dd27_63ab_77ac, - 0x1aa0_6090_7bb7_8a07, - 0xef6a_bddb_8c68_635f, - 0x1b09_b5e0_1b7a_f882, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7849_72ec_1ae0_37c3, - 0x5a42_69be_4726_d8bd, - 0x56a7_19a2_e165_6dc7, - 0x1418_9c78_50da_d383, - ]), - pallas::Base::from_raw([ - 0x815b_cd2b_ca53_eb95, - 0x556c_78b4_7751_dbf6, - 0xf053_fd13_1a20_08c1, - 0x2881_c78c_feab_68d2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf306_1913_4ae0_7a9e, - 0xd306_6f26_bd6b_4a10, - 0xd230_d8ea_c29a_51fc, - 0x0e6c_d0f8_d1ea_c0f0, - ]), - pallas::Base::from_raw([ - 0x9fa4_27be_acec_9bb8, - 0x2a2b_c250_80aa_697f, - 0xdbf7_9c2f_db4d_bd95, - 0x0028_bb6a_8622_43f5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf013_8449_cc96_1899, - 0x379d_ac9d_9ebf_876a, - 0xeb7f_99d0_31cd_e93d, - 0x130b_5b85_19be_08fd, - ]), - pallas::Base::from_raw([ - 0xa4ed_7e43_422c_baeb, - 0x15bd_a565_cfd0_99f1, - 0x75e7_3fae_ef12_8208, - 0x1196_b027_3cf1_1fbc, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc311_f99e_5530_bae5, - 0x5e96_2191_2f98_67c0, - 0x0ec4_6179_0832_791f, - 0x3ab8_8c62_791f_cabc, - ]), - pallas::Base::from_raw([ - 0xe30c_dbb2_d1a3_46f3, - 0x300d_881b_2157_d573, - 0xe362_292b_af62_b032, - 0x02c4_23ea_26f4_a3a1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7244_fb82_f14a_5b15, - 0x1716_dbf8_c880_c5a0, - 0x134b_bb0d_fa04_d130, - 0x2c80_0943_ac16_971f, - ]), - pallas::Base::from_raw([ - 0x978a_d2ca_089a_5c31, - 0xe1e6_1bbd_0163_3f49, - 0x3330_aaf3_b642_cbd0, - 0x09a1_c6d2_ba6b_3d2c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x28a5_4ff3_bc33_d5be, - 0x3bf6_b12e_cf48_395c, - 0x222d_c71b_557c_9043, - 0x2440_8b65_1f74_a85b, - ]), - pallas::Base::from_raw([ - 0x9066_0895_04af_52c0, - 0x35e4_e8f7_66c0_15d1, - 0xa386_9229_659f_2484, - 0x207d_3198_11df_6bc7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x15d9_722b_d97c_c054, - 0xc0a4_0440_6239_45f9, - 0xb46b_37e5_73fd_989c, - 0x2b58_6ce7_ac3a_9166, - ]), - pallas::Base::from_raw([ - 0xb9d6_2d9d_3f31_dbef, - 0x7275_cd16_b7e6_a7a5, - 0x8d85_c044_6dd5_7a4d, - 0x0d86_a9fc_da53_0505, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6cc3_c1bc_2016_e727, - 0x617b_0dd8_180a_164b, - 0x4fd6_39de_9f61_971e, - 0x3d4a_6fd8_19ba_27f0, - ]), - pallas::Base::from_raw([ - 0x3413_e80e_aa57_8bd4, - 0x7b16_485e_63bb_769f, - 0x62bb_5921_8c4c_4aa2, - 0x1098_9857_f8af_586f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4d33_b7d2_2e3a_e53d, - 0xe888_af7e_b724_5aa1, - 0x78e6_f0f3_0b76_b896, - 0x15f9_f0ca_f850_8e61, - ]), - pallas::Base::from_raw([ - 0xbece_4f0d_e233_cb6a, - 0xeb3f_a9df_d0c3_9b89, - 0xb351_ff58_43cb_cac6, - 0x372a_a61b_e920_3f30, - ]), - ), - ( - pallas::Base::from_raw([ - 0x74f7_4a0c_a5d5_f226, - 0x3751_b852_e703_7cb6, - 0x9ad1_c8fa_759a_1891, - 0x10fd_b6b7_2434_8442, - ]), - pallas::Base::from_raw([ - 0xfcd7_aa2c_6716_e475, - 0x4f9c_2246_cede_c392, - 0x06aa_a436_01b9_97e3, - 0x0a26_804b_d57e_c010, - ]), - ), - ( - pallas::Base::from_raw([ - 0x539f_f781_f164_4836, - 0xd1dc_dc87_3d99_a0c6, - 0x2de4_7396_8ef1_0b89, - 0x0ff1_67a9_82ba_334c, - ]), - pallas::Base::from_raw([ - 0xb50d_ab91_5188_8e47, - 0xc1e0_55fa_97df_88cb, - 0x3547_e3a1_e0dd_755d, - 0x2d28_735e_9afb_ed0a, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa278_8a09_c089_d696, - 0xf529_cbd9_0600_711e, - 0xcb66_bb7a_1ef8_523e, - 0x29b9_17aa_34eb_2bac, - ]), - pallas::Base::from_raw([ - 0xed7f_a639_85a4_bf96, - 0xbc46_b5a4_cea4_8664, - 0x2c0b_8691_1652_3fde, - 0x3d30_43c2_7ddc_7417, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3c6e_e712_6545_c6fc, - 0x361e_60a3_9a64_72b5, - 0xa4fa_2bc5_6f5a_3772, - 0x206b_0968_ab5d_844a, - ]), - pallas::Base::from_raw([ - 0x7cc3_6e87_ba43_ad08, - 0xf915_23eb_eca6_b1dc, - 0x2fa9_d1da_381f_945a, - 0x25ff_57c6_8a6c_aa43, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7726_42a3_c1c2_2be0, - 0x5061_8408_7ab7_daae, - 0x67ee_d982_89e3_c3e4, - 0x1c40_7832_12e1_7379, - ]), - pallas::Base::from_raw([ - 0xaa43_becb_fcb9_ce01, - 0xe538_4afd_eab9_4a52, - 0x3e9c_4b32_8d24_33ff, - 0x0057_5aff_a2e5_24a2, - ]), - ), - ( - pallas::Base::from_raw([ - 0xea0e_ce17_54e1_854f, - 0x4459_6094_9fc0_86c4, - 0x835e_6759_c23d_e766, - 0x0be3_ab41_eeec_484d, - ]), - pallas::Base::from_raw([ - 0x48f9_a609_6201_6be1, - 0x1909_3863_efb7_d549, - 0x2b59_8ff2_accf_39ce, - 0x389d_847e_e5a1_b1e9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x936a_c037_696b_6537, - 0x3560_e5b4_a313_28a8, - 0x1f47_fea4_cfcb_2890, - 0x0c6b_bc4d_4957_3c28, - ]), - pallas::Base::from_raw([ - 0x2ac6_7e2f_fba6_8746, - 0x80e1_d8ee_95b1_e538, - 0x0ff9_37f0_4793_a319, - 0x1094_a38b_a671_2718, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8ec7_df2c_b2b8_fae3, - 0xeb40_cbe1_652c_ef89, - 0xa02d_a353_aadf_1885, - 0x2c64_885e_84cb_e485, - ]), - pallas::Base::from_raw([ - 0xccf9_06a7_d926_e277, - 0x5d7e_8f08_57f5_5c3e, - 0xdf71_1b47_1772_d5f2, - 0x0ca8_260c_f185_b333, - ]), - ), - ( - pallas::Base::from_raw([ - 0xefba_501d_d999_2307, - 0xcbce_e2bf_bc0a_86da, - 0x7ba9_c366_8cca_0e58, - 0x10e0_7bda_6733_fc28, - ]), - pallas::Base::from_raw([ - 0x0a72_e66f_df7d_ebc3, - 0xf16a_67d6_2aa2_75b9, - 0x03d2_5e00_aa84_2a6f, - 0x26c7_55bc_dfdb_ce70, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1853_7664_9aef_2dff, - 0x7f94_4c4f_10a4_9717, - 0xe235_80ff_b9f5_ac99, - 0x1d38_7fb6_5f7f_4a52, - ]), - pallas::Base::from_raw([ - 0xb59f_6906_b41f_c19e, - 0x6ae3_f226_ba4b_d26b, - 0x5171_2aca_d3e3_cb0c, - 0x3019_b3ab_9250_0e25, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7405_db8c_8d13_97ec, - 0x3a1f_5c63_44b8_b4b2, - 0x3b16_175b_df99_eacb, - 0x0e5c_3936_5a61_4966, - ]), - pallas::Base::from_raw([ - 0x3c2a_824f_2a3b_26ee, - 0x0cb5_c814_2e77_4dc9, - 0xe648_7df6_e45f_90f6, - 0x3a37_71c5_e20a_e479, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0f51_40a8_9629_08a9, - 0xab28_d099_4637_c6c5, - 0x8d40_0c2d_dfbb_597d, - 0x359a_fe63_b4f2_9823, - ]), - pallas::Base::from_raw([ - 0x1fc4_f014_db42_75cc, - 0x136d_5fd6_5404_503c, - 0x0844_9c43_ce86_523a, - 0x0677_006e_034e_098f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7cb5_4bb7_ecfc_0a93, - 0x64fc_3b54_53ba_a1af, - 0xc453_e619_2e6a_86d5, - 0x2838_035c_ac98_9917, - ]), - pallas::Base::from_raw([ - 0x0f6e_5839_dff8_8640, - 0x1290_4182_7ebc_73df, - 0x4735_3b6f_4a1f_7e8a, - 0x31aa_a1ad_ca93_7f4c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9f43_37c3_6d2b_534d, - 0x3bc4_bb39_ede7_0bc3, - 0x2f38_79ae_104b_8a55, - 0x13b0_c171_d97a_4fc8, - ]), - pallas::Base::from_raw([ - 0x0d46_d1fa_370c_5421, - 0x8397_7f28_65be_b753, - 0x63f4_7e7d_e49e_dfd8, - 0x118c_46bf_17f3_a19f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb4eb_a0ce_8969_48bf, - 0xad2a_98d9_656d_0cf3, - 0xc651_741d_4d5c_668a, - 0x039e_bf84_e942_4d6f, - ]), - pallas::Base::from_raw([ - 0xe095_c878_476c_81a2, - 0xedc7_bc68_679d_680e, - 0xf763_852b_4eed_2af1, - 0x15e9_98b1_e98e_6e1b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8566_9a18_2b28_8d21, - 0x9344_357f_0a1f_da13, - 0x3772_d744_a179_b8ed, - 0x1b03_8534_4ec0_b55a, - ]), - pallas::Base::from_raw([ - 0x4661_8dac_39b6_0421, - 0x4ef5_5d88_b13c_01b6, - 0x5315_7c47_50c6_9734, - 0x2a3a_6e07_2174_0395, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1e17_b775_4399_3b91, - 0x2837_ecac_c403_6f3d, - 0x56b4_0a0a_664d_8fb4, - 0x2f04_0f71_e7e4_d554, - ]), - pallas::Base::from_raw([ - 0xcbf0_51de_b98f_c269, - 0x5c6a_a704_7588_9496, - 0x42fa_c5f8_299f_bcfe, - 0x1247_eccd_7849_645b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x163e_3aad_4d5f_7140, - 0xb692_8158_7410_67a5, - 0x26b5_6868_509f_8ba2, - 0x05b1_5c3d_6a3f_a4ff, - ]), - pallas::Base::from_raw([ - 0x7cab_64a8_a8d0_1dc7, - 0x5b3b_f269_2d68_3607, - 0x2a15_8448_6787_3934, - 0x259a_0f62_1c04_39a1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5bda_eacf_bdfb_6df5, - 0xff6e_56d7_32b9_a43d, - 0x4557_5d7b_eff9_afc9, - 0x115f_3e25_b370_bb60, - ]), - pallas::Base::from_raw([ - 0xfa75_dfbd_dac8_8daa, - 0x2f30_93f7_6e39_fdb3, - 0xc8c1_e227_7dc5_95ff, - 0x3ea1_7ec5_148c_679d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2447_5f8c_9993_6ad1, - 0x51ee_6362_1f78_87c0, - 0x475e_d1d0_ab29_f628, - 0x0303_ffaa_2430_a0b7, - ]), - pallas::Base::from_raw([ - 0x1dd2_a952_d5a5_189d, - 0x22cc_a0bf_5041_4271, - 0x49b2_3458_622c_c627, - 0x0130_c236_40f8_7f89, - ]), - ), - ( - pallas::Base::from_raw([ - 0xaaf1_9c5a_cad7_1c28, - 0x8bb1_2918_8b7a_7858, - 0x23e7_ce2d_92dc_d66a, - 0x1942_3751_8e3a_2f23, - ]), - pallas::Base::from_raw([ - 0xa32c_eb66_4b3e_d4d9, - 0xeb2b_683e_f2b0_6773, - 0xa6f3_5519_396e_3a07, - 0x1d2b_b94d_b61e_c34c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4d21_de83_ed0b_0ed9, - 0xbddf_daab_a5f2_5e3b, - 0x0bbc_a486_495e_59d5, - 0x1685_4768_9da6_e3ad, - ]), - pallas::Base::from_raw([ - 0x8704_6afb_e059_6e25, - 0xbf4f_ef21_6f4a_5988, - 0x336a_e9d0_5d21_7097, - 0x0a21_13b0_758e_02e5, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1b2a_4f19_90f6_4ec2, - 0x56ab_849f_5d02_0569, - 0x2814_07aa_f7bf_a9ed, - 0x0601_c91a_2106_8b41, - ]), - pallas::Base::from_raw([ - 0xcb15_a0dd_808e_bc3d, - 0x07de_f385_c064_d556, - 0x2d6e_5a28_1e93_64d8, - 0x1039_dc0a_cb9e_a154, - ]), - ), - ( - pallas::Base::from_raw([ - 0xed0a_e905_2f8f_ec82, - 0xc113_bd2c_e530_54b2, - 0x0c7a_a4fc_f303_779b, - 0x0874_2829_cd8c_a708, - ]), - pallas::Base::from_raw([ - 0x6882_2f87_7899_c3f0, - 0x1896_a6ab_5b9e_67b3, - 0xcd49_5299_356c_6330, - 0x28a6_ee29_3adc_b613, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4b5e_4d5b_3583_5cb1, - 0x7c02_2a85_aaa9_48e4, - 0x8e1f_4a9b_8d4b_d320, - 0x3a17_94db_a7a9_3fc6, - ]), - pallas::Base::from_raw([ - 0xdd55_72e9_e0fe_59d3, - 0x7b10_d3c9_524a_5acb, - 0xfdfd_2d82_7b63_647c, - 0x0f9a_11b5_efe5_01ac, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8a46_db66_f88a_dfda, - 0x231a_f130_d914_9161, - 0x9afc_b0b8_a037_044d, - 0x2f80_ba78_43d6_0676, - ]), - pallas::Base::from_raw([ - 0x7b8b_4486_b3b0_f9ac, - 0xe9b8_0152_03ff_232a, - 0x3152_b63f_bf6b_2e27, - 0x2c41_0add_3b9a_25cd, - ]), - ), - ( - pallas::Base::from_raw([ - 0x346c_dbf0_be76_95e5, - 0x67e3_f66a_ed16_d76a, - 0x0461_f1a2_8763_60a3, - 0x0a18_29ce_9f91_a1d5, - ]), - pallas::Base::from_raw([ - 0xf17b_9a2b_6fc8_8392, - 0x2c4e_a7a2_bc5d_fd52, - 0xf512_092f_5365_a2ac, - 0x2c5f_2e6d_efce_5696, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa5c1_e1f8_460d_9bd0, - 0xb139_cee1_fbb6_2242, - 0xf5e6_14a0_2785_2538, - 0x133b_ce23_0971_df91, - ]), - pallas::Base::from_raw([ - 0x189c_cd97_00f7_da52, - 0x0ebf_79f0_cb47_65ce, - 0x749c_44ef_1e7d_1d11, - 0x312f_ad99_bbe7_c204, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe752_8bbc_917a_6be2, - 0x0bc2_ab1e_2504_cf52, - 0x3a48_1726_09ca_4031, - 0x2ce5_37e1_0a7c_529a, - ]), - pallas::Base::from_raw([ - 0x64f7_9aef_f4c4_2d79, - 0x9fd8_db65_8592_ed64, - 0xf842_04da_8886_9faf, - 0x377a_985c_3a1b_860c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5d3e_bfc6_25d2_05fa, - 0x10fa_dab3_20e6_ff3f, - 0x1784_f663_e29a_30ca, - 0x2a69_96bb_3ac5_9673, - ]), - pallas::Base::from_raw([ - 0x3fb6_a9c2_e6d6_0488, - 0x90b5_9221_a401_79bf, - 0xdc88_a94b_7528_facb, - 0x2c29_eed6_7fbd_9a89, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfea6_2c82_74a6_af4c, - 0x388c_7bcf_228c_73fe, - 0xc0c7_ea19_e955_ddd7, - 0x1e46_4602_7b2b_c1ca, - ]), - pallas::Base::from_raw([ - 0xca09_e0e1_e39c_3c01, - 0x701a_20ec_477e_affc, - 0x0fa5_db8e_79e9_4367, - 0x3cfc_3c48_e73a_04d1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd84c_ccf5_eb33_4179, - 0xce23_1898_15de_f8c7, - 0xe76c_8dea_7db5_8e1f, - 0x3aca_479f_f6b4_9d8a, - ]), - pallas::Base::from_raw([ - 0x17f1_246d_f123_7a60, - 0x2e17_9d8f_8d2f_2fa6, - 0x32d0_e613_423e_f64f, - 0x067c_293d_8b6e_c1ae, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8ecd_0c0a_17a7_8a19, - 0x7136_7ba6_7f60_b188, - 0xff5a_bf2c_d1aa_d63a, - 0x3656_099b_d15e_edb5, - ]), - pallas::Base::from_raw([ - 0xc0df_1063_d1e2_9ebc, - 0x9aec_45eb_3df3_5ab5, - 0x6e71_3f49_7b86_cba1, - 0x2e44_9f1d_b523_59ca, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa56e_440e_afba_0e69, - 0x10fb_4ac0_433e_be1a, - 0xd95f_392c_8d71_ee6d, - 0x34ef_089e_8af4_75db, - ]), - pallas::Base::from_raw([ - 0x9cde_8968_4faf_ee29, - 0xd390_7c2b_4645_4693, - 0xf858_c045_9eb2_6def, - 0x2a59_6136_fc96_199e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd341_83b8_68a0_094b, - 0x46c5_6330_1224_b24f, - 0x939f_ac11_dc0b_394b, - 0x1198_5ddc_b45f_ed85, - ]), - pallas::Base::from_raw([ - 0x4503_5252_8c23_bdac, - 0x818c_e278_0479_31a8, - 0x4d8b_05af_33be_0a68, - 0x2854_b240_01fe_2947, - ]), - ), - ( - pallas::Base::from_raw([ - 0x21ea_923b_9dba_2757, - 0x102d_32ee_7267_baa4, - 0xe07e_8d17_ff5b_d96d, - 0x0539_fe92_593b_cb44, - ]), - pallas::Base::from_raw([ - 0x89a6_e78c_a798_2cda, - 0x776a_98ae_c6c1_fc45, - 0xa4c1_cc4e_5efb_20c5, - 0x2f15_1e00_8953_fe2c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1023_5041_83b9_1d97, - 0x81fe_bc2a_8877_ca60, - 0x1924_5c49_fe3f_bb4c, - 0x0d38_a13f_e3f3_74f3, - ]), - pallas::Base::from_raw([ - 0xd643_1731_44a1_45de, - 0xcd95_d78b_7357_5f87, - 0x6ed2_6c3f_d329_09e3, - 0x0960_8380_e85f_342a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4291_8cdb_be2f_c05e, - 0x9acf_4a57_b166_d495, - 0xca99_c923_f45e_49ab, - 0x3fa1_33ab_04b7_a1e9, - ]), - pallas::Base::from_raw([ - 0xd731_a982_524d_4da0, - 0x55ec_878d_0321_1172, - 0x48d5_eaed_e324_92cd, - 0x0cff_b957_d167_7198, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf528_ad8a_c429_a4c2, - 0xd99b_85cd_8bcb_927e, - 0x853a_6c3f_3ecd_f11d, - 0x3fb4_d9e9_0d91_ecb0, - ]), - pallas::Base::from_raw([ - 0x9137_5cbd_7088_a770, - 0xbc73_46bd_4063_fc5d, - 0x52ee_b5a0_1934_a31c, - 0x3597_389b_0dc1_1334, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdb04_e2bd_c6a3_3802, - 0x4896_61c3_cebe_0978, - 0x21f9_61cc_a49e_f597, - 0x0fc8_c0b7_b394_2242, - ]), - pallas::Base::from_raw([ - 0x8f85_9b56_948a_bed6, - 0x72b1_52a1_bb7c_2347, - 0xfcda_82d5_34b4_88d3, - 0x3e4d_040b_c1bf_dcf7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x24a9_d7d9_f5f8_fb4c, - 0xa84b_e92f_da7a_6564, - 0x7c10_a2c0_1bac_9ff6, - 0x343d_ecbb_2e70_9ef9, - ]), - pallas::Base::from_raw([ - 0xf538_642e_d7fd_e654, - 0x6d30_faa6_432e_584b, - 0x18f2_02ad_2856_2bcc, - 0x1a0c_7166_2352_d21d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x08e8_9011_14d3_3f6a, - 0x0d82_62ea_f48c_28a2, - 0x89fe_087b_2750_6546, - 0x0895_2f7a_efaa_e8e6, - ]), - pallas::Base::from_raw([ - 0xca63_280f_9555_84ad, - 0xc7be_a103_e8a5_d522, - 0xb795_d913_5441_e491, - 0x3aa2_13ad_62ab_a032, - ]), - ), - ( - pallas::Base::from_raw([ - 0x154d_e3e2_a46d_afa1, - 0xef1b_cb7e_af7c_9641, - 0xc4cc_1e3f_0b9c_48b7, - 0x227b_14a3_1a99_2a2e, - ]), - pallas::Base::from_raw([ - 0xe7e2_e290_71fb_4a61, - 0x28f4_a7fe_9e2c_3b73, - 0x2fc8_8036_1925_c86a, - 0x2cde_373d_3d92_f96a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6c19_1842_a7d6_f4c8, - 0xa31d_ba99_3039_3d70, - 0x3514_6c26_3e06_7076, - 0x3803_9a47_4646_486b, - ]), - pallas::Base::from_raw([ - 0x27af_d249_5982_96c5, - 0xfcf6_b6aa_f5b2_d252, - 0x5c22_b91e_7495_dfec, - 0x2d57_9b70_dfa4_6507, - ]), - ), - ( - pallas::Base::from_raw([ - 0x50af_b111_4376_64df, - 0x1a85_72f4_fe6f_5325, - 0x1388_bf8b_eacf_630e, - 0x386b_3799_e109_7613, - ]), - pallas::Base::from_raw([ - 0x1d70_2f5b_9143_e12a, - 0xaac6_af7e_c5f3_428d, - 0x17dc_6b11_551f_52f2, - 0x0f7c_38b0_e835_e793, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc6e1_bd75_9bd4_3e46, - 0xb4a0_cc52_41e1_0baf, - 0x9b77_ed75_c46e_f6ab, - 0x0c02_f929_5248_ff03, - ]), - pallas::Base::from_raw([ - 0xc445_5024_0956_6825, - 0x0996_b65c_b2e1_7918, - 0xec22_9f0f_1eb1_49a6, - 0x0c64_8828_4462_5887, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc412_8bbd_2797_ba18, - 0xbd47_1f04_69d3_5b08, - 0x021a_0ae6_846c_2364, - 0x1e0d_3b1e_f4ea_6379, - ]), - pallas::Base::from_raw([ - 0xd0bd_8eb2_1cab_9f78, - 0x1bfb_e611_fe72_74e3, - 0xf844_8815_10e3_d7de, - 0x150b_00bb_a5ac_9396, - ]), - ), - ( - pallas::Base::from_raw([ - 0x752e_2b2b_9169_c0de, - 0xf2e4_7feb_5a2b_1656, - 0x61f7_7831_314b_7912, - 0x29d5_36bf_1530_146c, - ]), - pallas::Base::from_raw([ - 0xc890_bb54_9aff_0c72, - 0x197d_a4e0_76db_b42a, - 0x746f_0142_3821_5206, - 0x2512_c57e_4c5a_951e, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe7e6_6a45_c1aa_686c, - 0x8c98_b474_bd46_1267, - 0x8ae1_d414_4cc1_4cdf, - 0x1b9f_33fa_945c_8c67, - ]), - pallas::Base::from_raw([ - 0x9802_7495_ad6d_6b21, - 0xccc8_ed29_cecc_1b1b, - 0x74c8_0f51_6930_7044, - 0x334b_d2ec_3b06_2238, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe2e3_e34a_e48a_4542, - 0x77a7_9d9d_ee72_233a, - 0x9290_2fcd_5d97_3f99, - 0x0e28_df80_537b_d86b, - ]), - pallas::Base::from_raw([ - 0xb257_f5b7_a198_5b9a, - 0xaddd_7e70_cbc2_8f19, - 0xc35b_17df_11d3_bb77, - 0x28f4_8a76_e85b_984c, - ]), - ), - ( - pallas::Base::from_raw([ - 0xc1d2_64b9_7aa5_7f83, - 0xc8a7_697d_1031_d3ba, - 0x1e54_33c8_d6c1_c1ba, - 0x1a28_4362_7c85_7a95, - ]), - pallas::Base::from_raw([ - 0x5c00_7005_f638_803b, - 0x153c_6810_33d1_3436, - 0x39ca_84fa_65ec_c4cf, - 0x36a5_7369_ebe3_2da1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xcb3b_fab7_1ed6_88d1, - 0x959d_75b1_c3da_4470, - 0xff6b_cf88_212e_3d2b, - 0x1ab4_0ee5_990b_6b99, - ]), - pallas::Base::from_raw([ - 0x18fc_cc71_d6e5_8e43, - 0x52fa_e1cf_1c00_0d21, - 0xfe55_97c1_42a4_a225, - 0x0a8a_53ab_72a3_13ba, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf4ce_3a37_5416_8e4b, - 0x61c7_546a_ec52_434a, - 0x7d70_ac66_6893_57e8, - 0x1c12_4475_9a7d_efc8, - ]), - pallas::Base::from_raw([ - 0x3b5f_2cb6_a96e_db5a, - 0xef71_e886_2359_5d4f, - 0xe5a2_7436_5afd_c9e0, - 0x110a_f91f_2774_3efe, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6895_e22a_e677_de95, - 0x9fbb_9b3d_937b_3dc3, - 0x0bc1_f4d9_d4d5_bd66, - 0x27f2_b67f_1fec_e78a, - ]), - pallas::Base::from_raw([ - 0x7234_9411_50bc_efc4, - 0xac8e_5753_a8f5_0362, - 0xf7e3_8c41_e428_466c, - 0x315e_645b_5d4d_cf13, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5494_bb94_e808_6993, - 0x909a_795b_c421_efe8, - 0x038b_cb01_6b45_f433, - 0x2fc4_4636_cbb6_d6dd, - ]), - pallas::Base::from_raw([ - 0xa37f_6fe0_0cbd_bb87, - 0x0aae_cb06_be08_0506, - 0xdd80_a12f_e84d_f36f, - 0x1dc8_84e0_7af9_e250, - ]), - ), - ( - pallas::Base::from_raw([ - 0xdaa4_1d05_a56d_0e0b, - 0x6fed_5c75_13eb_443c, - 0x7a8b_0e4c_65b1_cd50, - 0x214f_7c8e_ed8b_b0ef, - ]), - pallas::Base::from_raw([ - 0xfe49_d9d5_1881_ea16, - 0x2353_dd64_ed34_1337, - 0x56b2_0c8e_d9f1_26d9, - 0x2c22_92b4_4c2b_0de8, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa74d_964e_9b7c_04bb, - 0x335c_bb5b_4ec0_2dec, - 0x8a84_7bec_6994_329f, - 0x1aa7_1c22_0de7_c5d4, - ]), - pallas::Base::from_raw([ - 0xc3b8_82a6_d6f9_f593, - 0x9ba7_9e1b_259f_8ae6, - 0x8ab6_b763_bd79_cc26, - 0x2183_61af_34fa_b740, - ]), - ), - ( - pallas::Base::from_raw([ - 0x97b6_5e79_5bd5_3661, - 0x560b_b24b_f4dc_8b38, - 0x16ce_dcc1_c055_12da, - 0x1571_6cae_b4f2_105b, - ]), - pallas::Base::from_raw([ - 0x3f1a_b4a4_ab91_7f25, - 0x4597_f16e_4e48_2ec7, - 0x43c4_b3e2_9f78_544b, - 0x0abf_eec2_26bf_1c59, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9beb_a739_41b6_91d7, - 0xcf15_e49b_9d08_eba3, - 0xd443_2465_4f9b_bb6e, - 0x2542_f10c_5975_b4f6, - ]), - pallas::Base::from_raw([ - 0x410d_c2a6_f3c7_221c, - 0x9e64_ef82_f138_821d, - 0x3607_68e2_df2a_cb50, - 0x2af0_280c_a2a1_a946, - ]), - ), - ( - pallas::Base::from_raw([ - 0x40aa_4da4_2525_32cc, - 0xa047_25f5_6850_6918, - 0xd096_8644_fefc_e14a, - 0x0591_ae22_96a9_a185, - ]), - pallas::Base::from_raw([ - 0xc59d_ea56_2de9_c223, - 0x1548_1b85_8a62_94f1, - 0x0aac_a08d_c1b6_25a2, - 0x0f05_cf9a_21ce_dda1, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd14b_b7d1_5076_72cc, - 0x6330_7f6f_52ce_3ad5, - 0x7ce5_1e25_ad24_3072, - 0x07dc_2bac_dd7c_6ea0, - ]), - pallas::Base::from_raw([ - 0x5836_c3d5_7c40_ffae, - 0x46f5_819e_44b7_ae09, - 0xb796_fb55_e09c_9785, - 0x2d95_737b_55d5_5dd1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x86dd_a9bf_0115_82af, - 0x40d9_e41e_3690_6b44, - 0x5787_20aa_8983_bfa2, - 0x2f1a_1706_18f1_8afb, - ]), - pallas::Base::from_raw([ - 0x09f8_9309_75e4_a8c6, - 0xef85_967d_be1c_9f79, - 0x4a38_18ba_32b7_bcd4, - 0x0a8f_1295_63b5_5cb7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x64e5_850f_a84e_2a38, - 0x67a1_f9d2_a1cb_2892, - 0x34b6_e8a9_6a3d_1adc, - 0x2e6f_30e3_86d6_a0c0, - ]), - pallas::Base::from_raw([ - 0xb9d1_3f17_8e65_ff6a, - 0x4ffb_0b20_e25a_7848, - 0x6c2f_dcd2_e668_e2d3, - 0x1e93_9c54_a6fa_239c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3316_8467_79ce_e7f6, - 0xfb6e_d07b_5560_c360, - 0x4a8f_2f59_55ff_6357, - 0x28fb_77fc_9375_6d8d, - ]), - pallas::Base::from_raw([ - 0xe3e2_1b78_b2cf_5612, - 0xc8d4_70e2_cb22_7688, - 0x731b_0c6e_e1d4_f24b, - 0x30cd_02ff_4619_55c2, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8e9c_4a02_e5ea_9126, - 0x6fb9_f18e_4e5e_96dd, - 0x494c_3274_6849_1131, - 0x18b5_fe24_35aa_0912, - ]), - pallas::Base::from_raw([ - 0x4956_0a92_8dfc_8d75, - 0xc948_7b69_3b11_267e, - 0x315e_da1d_1b42_789f, - 0x35d4_3503_9f73_bf9a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0010_6821_9f96_2f62, - 0x3931_2d4d_6b30_e2e7, - 0x94be_b29a_ad36_c2c6, - 0x36f4_5328_c007_73d2, - ]), - pallas::Base::from_raw([ - 0xe4f3_0b41_1e5d_d8b5, - 0x65e5_1f6f_4823_cbd8, - 0xf47f_3fd3_d0b6_f299, - 0x1427_8ff8_e951_56be, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe14f_d0ad_d91e_2015, - 0xa2bc_ccd9_60a9_fdab, - 0x715f_aab5_f71c_b572, - 0x1960_ed3b_e23f_8c8c, - ]), - pallas::Base::from_raw([ - 0x6d4d_e792_32d9_75b0, - 0xa0e0_d86f_f79c_4490, - 0x947e_ec8e_5f3c_08d9, - 0x162a_f9d0_f176_eeb6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x77be_2a89_644f_4e4f, - 0xdac2_fd2f_f979_19f8, - 0x482d_415e_0aa4_336e, - 0x12b4_8f67_c25d_ddea, - ]), - pallas::Base::from_raw([ - 0x1447_b356_5495_fdc2, - 0xfa86_152d_2046_a6bd, - 0x0e48_3cee_96b6_3430, - 0x310a_f969_9f04_356b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x49d9_568f_4b49_90b2, - 0xff1d_52e9_6c43_0eed, - 0x9dab_c67e_0ab6_7fbc, - 0x15b8_acf0_dafc_6bd0, - ]), - pallas::Base::from_raw([ - 0x04db_2abc_c8af_ebe1, - 0x858a_4302_b8ed_aede, - 0x857e_f9df_9683_371a, - 0x0ed5_6792_c5bc_56a9, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8fc8_c4bb_97be_29b8, - 0x723f_ec3a_c6fd_9388, - 0xcc18_5b44_14ce_3800, - 0x1903_31a9_ed7c_af8c, - ]), - pallas::Base::from_raw([ - 0x6e48_8eb0_820c_1768, - 0x7fcb_5d2c_98f1_ca49, - 0x32c6_8966_238e_4125, - 0x06ca_d05e_b165_eacc, - ]), - ), - ( - pallas::Base::from_raw([ - 0x05d6_73c0_9942_4c38, - 0x9b1c_e944_65d8_d36c, - 0x4192_c0f4_f365_0b99, - 0x3383_b385_084d_b871, - ]), - pallas::Base::from_raw([ - 0x41a3_b162_abb4_42dc, - 0x017f_86b0_2583_46ed, - 0x458e_9783_e3ed_a2b5, - 0x083e_e1cb_29d3_6b81, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe476_9543_7977_767d, - 0xed9c_7b2a_f66c_175f, - 0xb833_a588_5741_cd5e, - 0x363d_b7fb_cd58_d72c, - ]), - pallas::Base::from_raw([ - 0xf313_93cb_d9f8_02e3, - 0xe6eb_366c_2b43_078b, - 0xbca3_b4dc_3212_594e, - 0x08b1_1978_df11_1b34, - ]), - ), - ( - pallas::Base::from_raw([ - 0x77ce_a705_9e6f_006c, - 0xa35b_db7d_dc08_66ab, - 0x715a_f92e_56f1_97ea, - 0x3664_9345_05c4_d86e, - ]), - pallas::Base::from_raw([ - 0x9c53_e468_a11d_cffc, - 0x1c3e_0f67_68dd_602c, - 0x1ba5_77b8_d65c_4577, - 0x1d42_09b8_67f6_9ae6, - ]), - ), - ( - pallas::Base::from_raw([ - 0x260a_5380_a10f_5880, - 0x7a1b_b8cc_b65a_04e5, - 0x27a8_f9ff_d28b_2308, - 0x3a32_fb37_acbe_f3c3, - ]), - pallas::Base::from_raw([ - 0x914a_9b46_a374_9954, - 0xfed9_b9fc_0c61_8135, - 0xfe45_3ec9_a172_f21e, - 0x1c9f_90fd_5778_ec0f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9910_a461_c209_3108, - 0x2c2e_d023_b39e_9004, - 0x2c03_9b33_a27f_913b, - 0x0a0e_6954_9577_4dec, - ]), - pallas::Base::from_raw([ - 0xe6b9_b73d_4549_90d8, - 0x47ba_dd67_2352_1eed, - 0x40be_e046_81a5_cc00, - 0x36b5_ea1f_1eff_932d, - ]), - ), - ( - pallas::Base::from_raw([ - 0xd2e0_0398_4661_f7a3, - 0xca79_c17c_09e6_51e1, - 0x7836_47d3_410b_a538, - 0x217c_55a4_8acb_9a5d, - ]), - pallas::Base::from_raw([ - 0x1bd2_0b6c_04fd_e263, - 0x02c7_b694_dc6d_a359, - 0x3a71_9cfc_8a1b_9a1c, - 0x3fff_5323_5b48_9bbe, - ]), - ), - ( - pallas::Base::from_raw([ - 0xe25b_d2f6_66fc_16d2, - 0xf999_b1a1_db9c_75c2, - 0xd0f6_f6cf_794f_162d, - 0x3366_32de_5352_5f98, - ]), - pallas::Base::from_raw([ - 0x1c68_3a79_9230_e098, - 0x807c_7b25_a72c_04ed, - 0x534e_0c05_0c08_e762, - 0x2bc6_1d1f_88b2_bab0, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6ee1_ad02_6d11_3806, - 0xc402_cf86_0c69_c2f8, - 0x1b43_0a98_7ad4_7948, - 0x3123_cab0_04e7_4073, - ]), - pallas::Base::from_raw([ - 0x28ac_c01e_af74_1193, - 0x3d35_2c06_3e65_b2b5, - 0x5da6_8188_3d2a_52ab, - 0x38f2_4ab3_5569_517a, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6baf_341c_2702_9a80, - 0x31d7_cf3d_2326_22c1, - 0xb56b_e361_456f_7da3, - 0x22d9_07c2_5b47_0494, - ]), - pallas::Base::from_raw([ - 0x8110_08ea_9321_b2e1, - 0x9e15_c19c_8b04_0ec1, - 0xc7b4_860c_a4fd_0f1a, - 0x3fb3_5b5c_9ff2_ce92, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3eb4_cbe9_57c3_215d, - 0xe3bb_1c30_aa5a_2018, - 0x6829_f364_04df_ce6a, - 0x1e4c_9bb8_5e77_3502, - ]), - pallas::Base::from_raw([ - 0xf927_5406_c35a_b692, - 0xedb3_cacf_43f8_d2eb, - 0x5b04_6f41_e82f_fa8d, - 0x16c2_b490_1be1_772e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x91f2_5bb0_0df3_b325, - 0x9fa2_042e_bf14_310e, - 0x440d_8c06_8bb1_5a05, - 0x000a_e05a_1117_51b6, - ]), - pallas::Base::from_raw([ - 0x71a9_f252_e8dc_96fc, - 0x93e9_0e94_a948_47fc, - 0x35bd_756d_82e4_6522, - 0x0dd4_182d_0922_90ad, - ]), - ), - ( - pallas::Base::from_raw([ - 0xac7d_898a_152e_395a, - 0x893e_8851_1ab3_33da, - 0xf069_82b1_791e_1812, - 0x1fb6_f3c4_cf65_d002, - ]), - pallas::Base::from_raw([ - 0x65c5_e104_bca2_bc38, - 0xcd1b_883c_113f_a262, - 0x96bc_af49_58ae_d45e, - 0x3c4c_e7d2_6eb9_a372, - ]), - ), - ( - pallas::Base::from_raw([ - 0x867f_b40f_ed90_02ea, - 0x40a5_041b_7cba_a776, - 0xc206_37a4_c7c4_ac98, - 0x2570_9da2_0e46_8fbe, - ]), - pallas::Base::from_raw([ - 0x651a_689f_4ec0_fd53, - 0x4a1e_3008_41ea_e098, - 0x9e4d_ec05_ca83_49d2, - 0x2fcb_ed31_57c6_0795, - ]), - ), - ( - pallas::Base::from_raw([ - 0xa5b5_1c60_e817_6fd1, - 0x2e8f_21e3_bfb9_750f, - 0xf45c_e53c_8b74_a941, - 0x04fd_1a36_e04a_7b99, - ]), - pallas::Base::from_raw([ - 0x5ca7_72c9_9b5a_d4f9, - 0xea3c_aa3d_8393_caee, - 0x3508_ad20_2818_0ba6, - 0x1b7d_cd69_c52c_070f, - ]), - ), - ( - pallas::Base::from_raw([ - 0xf076_4e26_b3f1_d20e, - 0x18c7_142e_8625_e9c8, - 0x51f7_7d4f_7dde_dce2, - 0x2373_bf50_232b_3f22, - ]), - pallas::Base::from_raw([ - 0x47b8_d63d_328c_c660, - 0xdafe_f5c4_0e05_ae5d, - 0x98b5_a965_47c9_1289, - 0x01ad_0491_0905_0a6c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1144_a189_947f_94df, - 0xe428_df16_cd10_22ba, - 0x7565_d9ea_3476_c4a8, - 0x2070_a6e3_1265_c3dc, - ]), - pallas::Base::from_raw([ - 0x91df_7f7d_dec9_e146, - 0x9135_871c_349e_dbe7, - 0x7edb_dcb4_d0e8_bb0a, - 0x0c90_c909_0575_8d15, - ]), - ), - ( - pallas::Base::from_raw([ - 0x497e_9d18_b31f_1ea6, - 0x087a_5e39_1bec_b0e3, - 0xe8de_4d9c_6a44_8c64, - 0x141d_4aad_df85_22b8, - ]), - pallas::Base::from_raw([ - 0xff15_6277_b7ae_3c64, - 0x3455_b096_0f5b_a73c, - 0x2051_cfe3_04f9_e861, - 0x19f8_6f8b_52e2_d6d7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x9eb2_3cac_ee0c_46a4, - 0xe61a_c293_cba7_7cd6, - 0xc50e_6571_9c07_30af, - 0x2225_2c4f_0dc9_d926, - ]), - pallas::Base::from_raw([ - 0x99ee_8f10_2d20_4335, - 0x09d9_c154_3bf6_02d3, - 0x61d7_e3d0_9e64_c519, - 0x1b3f_b8bc_c227_b8f3, - ]), - ), - ( - pallas::Base::from_raw([ - 0x6b9e_a4ea_df65_cb3f, - 0xc1fe_f822_6717_eb27, - 0xfb69_b82e_a0f3_4f2c, - 0x2594_f3af_922c_6c4c, - ]), - pallas::Base::from_raw([ - 0xc431_a2b7_6a21_a9ae, - 0xba4f_fa4e_a749_4caa, - 0x354d_e308_ab36_c4f9, - 0x244b_96c7_5d78_711b, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4768_edc3_6542_5192, - 0x6635_8e8a_a347_fefe, - 0xb5f4_dfd5_e5b9_73ce, - 0x1a59_51c5_25bf_f454, - ]), - pallas::Base::from_raw([ - 0x7e01_049a_8df5_fd8a, - 0x6b01_2890_41d2_19dd, - 0x3844_3e89_e500_e012, - 0x2be0_f234_4af5_6d77, - ]), - ), - ( - pallas::Base::from_raw([ - 0xae1e_74fc_1860_213a, - 0x3fe4_3c3a_2886_f22c, - 0xdefa_9b1e_edbe_c1e1, - 0x31bc_5ab6_4e9f_5faf, - ]), - pallas::Base::from_raw([ - 0xbd19_b196_572a_8513, - 0x4272_e09b_f426_f2c9, - 0x9925_f875_ae11_ddf7, - 0x1fb9_5b9e_53fb_0d63, - ]), - ), - ( - pallas::Base::from_raw([ - 0xb236_a763_08e8_7326, - 0x8974_b02e_45e8_dca3, - 0x0575_b904_ff33_10d8, - 0x0347_ed41_4f04_efca, - ]), - pallas::Base::from_raw([ - 0x18eb_fd89_32b5_0ad8, - 0x82a2_5574_4ed0_515d, - 0xb135_d6bf_0377_152a, - 0x3419_a1db_bc9a_9880, - ]), - ), - ( - pallas::Base::from_raw([ - 0x8c84_0714_8c42_e400, - 0xee8a_bd72_6199_8367, - 0xfe4e_c3e9_5c51_4cd9, - 0x2b7d_7f9a_0bc8_cf07, - ]), - pallas::Base::from_raw([ - 0xe58f_7f61_3068_dfd4, - 0x31c9_d482_7192_7dd4, - 0xa09f_1e90_db5e_fe74, - 0x2e12_f957_7e54_b546, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3d25_c1f3_eb56_14c1, - 0x78b0_2ff0_db91_5adc, - 0x52e4_595a_4745_1abb, - 0x20c0_812b_5d28_2662, - ]), - pallas::Base::from_raw([ - 0xc166_e032_a3ff_9774, - 0xbf21_613f_887f_5cc1, - 0x6666_23cc_e45a_acb3, - 0x1f8a_670a_47ae_5415, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0e32_ea98_b294_1bb3, - 0x0040_f5f6_d5d0_174b, - 0x137c_87e7_3271_65a4, - 0x0614_8c65_f99b_da0a, - ]), - pallas::Base::from_raw([ - 0x6348_5e06_f44d_7edc, - 0x3b2b_37a4_b180_07ab, - 0xfe96_302e_4023_3b6d, - 0x0c86_9dda_efca_80d1, - ]), - ), - ( - pallas::Base::from_raw([ - 0x74e3_303e_17d4_1cf1, - 0xb9b5_5056_8945_d1c1, - 0xf5ca_f3d6_bab0_c8ee, - 0x20aa_c0ce_dcdc_1816, - ]), - pallas::Base::from_raw([ - 0x465b_2a4b_f80c_a876, - 0x7f65_deed_eb30_4907, - 0xcf39_c880_9f38_77e2, - 0x0286_a346_71e5_743b, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfb50_a168_127f_b04b, - 0x40f8_01e3_04f5_df03, - 0xb4e1_c034_c959_50eb, - 0x1126_9317_caf7_5d07, - ]), - pallas::Base::from_raw([ - 0x42c5_97bd_71be_93ad, - 0xe220_1b27_f87d_2e4b, - 0x11f2_a2f5_a81c_6934, - 0x25a7_0d53_1d5b_addf, - ]), - ), - ( - pallas::Base::from_raw([ - 0x86c3_b612_1d8d_3fa4, - 0x4914_c783_0ca4_f15f, - 0x04ea_4fe6_f986_a7ec, - 0x2026_f468_4a50_7b0c, - ]), - pallas::Base::from_raw([ - 0x435e_50f3_7974_66eb, - 0x8b5c_73b6_b70e_0033, - 0x7ed9_4ab6_144a_18bf, - 0x2b10_91f0_ffa9_d775, - ]), - ), - ( - pallas::Base::from_raw([ - 0x7335_a5d6_15f2_85a5, - 0x65e3_ce55_379a_4653, - 0xc59c_ed4a_cc76_2af0, - 0x0429_7a2c_6046_7f76, - ]), - pallas::Base::from_raw([ - 0x38f3_ec3f_0286_6257, - 0x1e13_f010_a49e_a5c0, - 0xdaf1_e8bb_06ca_2eec, - 0x329d_3ddb_9b5a_922d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x400a_e7f0_113b_1b88, - 0x6505_dd5a_729f_0ed9, - 0xf46d_81a6_8261_b4c8, - 0x2450_8490_e887_3820, - ]), - pallas::Base::from_raw([ - 0x35b8_1e5b_7fea_8621, - 0x9ab1_93bd_5e06_6a86, - 0x8692_12f1_d266_8fc3, - 0x15ea_d070_2b54_0d1e, - ]), - ), - ( - pallas::Base::from_raw([ - 0x958c_8b6a_f42e_66da, - 0xdfcd_951f_1c14_d6f5, - 0xb5bc_07dc_6f54_f30a, - 0x1d82_d649_7016_56da, - ]), - pallas::Base::from_raw([ - 0x05be_a7e3_a36e_01f9, - 0x77ab_d96c_4618_47be, - 0xa7b5_16d3_9767_5ff3, - 0x1785_5e76_cc3c_e4be, - ]), - ), - ( - pallas::Base::from_raw([ - 0xfd0a_310a_b4fb_5f5a, - 0xd05f_e1c2_4618_bb6f, - 0x5741_e067_013d_e384, - 0x2373_0ed6_879c_4bf1, - ]), - pallas::Base::from_raw([ - 0x7e9f_f7bc_b94c_5d16, - 0xd75e_56b3_9f76_fd96, - 0x5562_35b1_256d_ea0f, - 0x3ecd_11be_4f08_056d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x3d04_4438_d2b7_8ca6, - 0xa679_db14_51f3_dcb0, - 0x922b_166c_a2b2_bb15, - 0x1107_3835_6e3d_778a, - ]), - pallas::Base::from_raw([ - 0x95ce_a45d_d63e_b7e2, - 0x2af0_c617_e626_d526, - 0x9d55_3537_9131_d95d, - 0x0d84_161a_6b99_3a77, - ]), - ), - ( - pallas::Base::from_raw([ - 0x4df8_74c2_f161_5191, - 0xd297_0d9a_0843_1ff4, - 0x66c1_4b9b_525d_f889, - 0x3b83_8a77_8a22_ed9a, - ]), - pallas::Base::from_raw([ - 0x6786_9621_06cb_caae, - 0x83f2_0b98_433f_f62b, - 0xff05_c2a9_4d11_970e, - 0x32db_3f0c_596c_894c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x18d2_6b17_c5b7_95b4, - 0x5097_014c_31df_3d6b, - 0xc1bc_54b7_a9a3_6f47, - 0x003f_0149_4252_2ca4, - ]), - pallas::Base::from_raw([ - 0xe704_1773_6871_2b5d, - 0x012a_3a17_1425_6ed0, - 0x750f_6ae1_dac8_4dba, - 0x39fa_e6ac_0da9_dcec, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0022_fc4f_c196_3017, - 0x6e6d_a891_b75a_a6f2, - 0x8e65_aa60_d9c7_8441, - 0x2ff0_f181_181a_9fa8, - ]), - pallas::Base::from_raw([ - 0x08ea_646a_eaa0_74f3, - 0xe893_09ca_01bb_be00, - 0x0021_c936_55f7_2464, - 0x2e6f_5fdc_b38c_af4f, - ]), - ), - ( - pallas::Base::from_raw([ - 0x99bf_57d6_5784_c501, - 0x7017_bd72_7c8e_b52c, - 0xe919_d31c_2d32_8f5d, - 0x0bcd_43af_aaf5_2fb7, - ]), - pallas::Base::from_raw([ - 0x60d0_5ba3_c3d4_e2a8, - 0x03a1_39f0_df52_02d2, - 0xe5c8_8a6e_21e1_9481, - 0x384a_d0a4_1d52_9ba5, - ]), - ), - ( - pallas::Base::from_raw([ - 0xac1f_1153_693b_c3fb, - 0x95cb_3d54_26f8_0864, - 0xacc9_531f_91c2_17a7, - 0x37a0_65ab_2b62_bad6, - ]), - pallas::Base::from_raw([ - 0x2556_2833_d728_cc98, - 0x157a_5fe3_6bdc_7a86, - 0x45a9_fabe_1703_6e96, - 0x15a6_2e9a_3e84_6efb, - ]), - ), - ( - pallas::Base::from_raw([ - 0x84eb_0966_60b5_7d7e, - 0xbcb3_c183_689f_69b6, - 0xc179_6b0c_1aa2_7a8d, - 0x1f47_12b0_6b77_73e3, - ]), - pallas::Base::from_raw([ - 0x2e00_a10a_f3c4_6f66, - 0xd4d2_d9a4_4958_e31e, - 0xaae5_c9f9_9f8c_6e6a, - 0x0ffb_5c9c_6c4a_c3aa, - ]), - ), - ( - pallas::Base::from_raw([ - 0xebdf_427c_e6aa_6032, - 0x2284_d8b0_888f_cc3a, - 0x3f9c_8166_83f2_fe8d, - 0x3be0_c3d2_1862_d2b0, - ]), - pallas::Base::from_raw([ - 0xd068_4fe3_7825_0382, - 0x29a3_85cf_563b_538f, - 0xb401_2ac9_07b0_9161, - 0x3fe4_fabe_5f26_0616, - ]), - ), - ( - pallas::Base::from_raw([ - 0x0bc2_86a7_8d4d_c29a, - 0xa808_bac0_57cb_7c72, - 0x1e71_e213_e7ad_d6cd, - 0x3d6b_987c_9596_0b11, - ]), - pallas::Base::from_raw([ - 0xe4ac_cdd3_7e1d_475a, - 0xe6b1_afb2_8e9a_e97c, - 0xb43c_7942_dc38_771b, - 0x0a9f_622c_5b76_581d, - ]), - ), - ( - pallas::Base::from_raw([ - 0x346d_1c37_d315_d20d, - 0x2f90_33b6_9759_2232, - 0x19fa_9995_c446_fd03, - 0x0e97_a5fa_b367_fc42, - ]), - pallas::Base::from_raw([ - 0xa4f9_7858_7b47_3a80, - 0x5c3a_72cf_5848_9bcc, - 0x812b_72e4_2421_a299, - 0x2b11_99ab_416d_bef7, - ]), - ), - ( - pallas::Base::from_raw([ - 0x5e07_f1b3_b73a_4e48, - 0x19b0_925f_6f8f_6b83, - 0xcf98_c5cc_7f9a_9cb2, - 0x0f1a_0d41_9b39_1617, - ]), - pallas::Base::from_raw([ - 0x632f_c83e_f090_fdec, - 0x2f3c_0e5b_a18e_d660, - 0xce90_d880_46e7_cabf, - 0x0cad_fd0b_a42e_ea59, - ]), - ), - ( - pallas::Base::from_raw([ - 0x238c_cf74_76ab_5023, - 0x074a_888a_fb1b_0035, - 0x3763_56e8_efeb_ecee, - 0x203e_1e97_4451_db54, - ]), - pallas::Base::from_raw([ - 0x205f_a8cc_d857_d1b7, - 0xa271_379b_274f_7284, - 0x3d47_8f66_532f_d8fc, - 0x1366_88be_56b9_e771, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2b08_b53d_bb1c_746f, - 0xded6_6332_130e_59f9, - 0xec3e_7d70_890f_11b3, - 0x070b_8394_0557_a571, - ]), - pallas::Base::from_raw([ - 0x9320_2c85_006c_febc, - 0x679f_3693_3fc6_5b4d, - 0xea12_f030_0d2a_06e1, - 0x2e11_4723_802f_792c, - ]), - ), - ( - pallas::Base::from_raw([ - 0x356f_e85c_2e67_e247, - 0x1d0d_775e_a300_5f6d, - 0x80f8_64c6_bbd0_c16c, - 0x317a_eda0_114e_e9f0, - ]), - pallas::Base::from_raw([ - 0xcda6_4589_4bfc_0455, - 0xf9fc_3a76_ac88_3c1f, - 0x61f6_a208_798d_28ec, - 0x2c02_1be9_a8c2_9b49, - ]), - ), - ( - pallas::Base::from_raw([ - 0x717a_a137_f5c5_be89, - 0x9028_5359_3102_985b, - 0x4ffc_0b33_2c5a_0750, - 0x2494_2c9c_ed84_3a53, - ]), - pallas::Base::from_raw([ - 0xfbdb_198d_0cae_4fa7, - 0x301e_d666_339f_ae29, - 0xe8db_271b_351f_54c1, - 0x1ec6_b81d_e40c_48da, - ]), - ), - ( - pallas::Base::from_raw([ - 0x1fad_ffb9_7149_61e3, - 0xa176_3927_04e4_6feb, - 0x335d_89f8_2091_038d, - 0x0556_0da5_b68a_034a, - ]), - pallas::Base::from_raw([ - 0x7cbc_a061_15ef_3129, - 0x8e19_e08d_db9c_008d, - 0xa745_abb6_b7a1_36fb, - 0x2ccc_b707_6bde_5545, - ]), - ), - ( - pallas::Base::from_raw([ - 0x66ba_c59c_6f88_1b40, - 0xae9b_1f86_51c5_f96c, - 0x688e_7e00_9bdc_52e1, - 0x27e4_380e_842e_d733, - ]), - pallas::Base::from_raw([ - 0x1be8_47f3_618d_78db, - 0xcbf1_c63d_6c8b_f57f, - 0x62cb_3b48_a39f_91dc, - 0x0ced_7d2b_0b84_8552, - ]), - ), - ( - pallas::Base::from_raw([ - 0x2bc3_ed47_d3b1_9dae, - 0x7929_235c_2bdf_6880, - 0x4ec8_7166_4d23_deae, - 0x026a_bf29_d792_9647, - ]), - pallas::Base::from_raw([ - 0x8951_204b_5262_6b96, - 0x15ba_29c7_c672_fad2, - 0x0d49_9ba7_a480_134c, - 0x397c_dfb1_4d54_65ce, - ]), - ), -]; diff --git a/halo2_gadgets/src/utilities.rs b/halo2_gadgets/src/utilities.rs deleted file mode 100644 index fa50f7e8e8..0000000000 --- a/halo2_gadgets/src/utilities.rs +++ /dev/null @@ -1,496 +0,0 @@ -//! Utility gadgets. - -use ff::{Field, PrimeFieldBits}; -use halo2_proofs::{ - circuit::{AssignedCell, Cell, Layouter, Value}, - plonk::{Advice, Column, Error, Expression}, -}; -use halo2curves::FieldExt; -use std::marker::PhantomData; -use std::ops::Range; - -pub mod cond_swap; -pub mod decompose_running_sum; -pub mod lookup_range_check; - -/// A type that has a value at either keygen or proving time. -pub trait FieldValue { - /// Returns the value of this type. - fn value(&self) -> Value<&F>; -} - -impl FieldValue for Value { - fn value(&self) -> Value<&F> { - self.as_ref() - } -} - -impl FieldValue for AssignedCell { - fn value(&self) -> Value<&F> { - self.value() - } -} - -/// Trait for a variable in the circuit. -pub trait Var: Clone + std::fmt::Debug + From> { - /// The cell at which this variable was allocated. - fn cell(&self) -> Cell; - - /// The value allocated to this variable. - fn value(&self) -> Value; -} - -impl Var for AssignedCell { - fn cell(&self) -> Cell { - self.cell() - } - - fn value(&self) -> Value { - self.value().cloned() - } -} - -/// Trait for utilities used across circuits. -pub trait UtilitiesInstructions { - /// Variable in the circuit. - type Var: Var; - - /// Load a variable. - fn load_private( - &self, - mut layouter: impl Layouter, - column: Column, - value: Value, - ) -> Result { - layouter.assign_region( - || "load private", - |mut region| { - region - .assign_advice(|| "load private", column, 0, || value) - .map(Self::Var::from) - }, - ) - } -} - -/// A type representing a range-constrained field element. -#[derive(Clone, Copy, Debug)] -pub struct RangeConstrained> { - inner: T, - num_bits: usize, - _phantom: PhantomData, -} - -impl> RangeConstrained { - /// Returns the range-constrained inner type. - pub fn inner(&self) -> &T { - &self.inner - } - - /// Returns the number of bits to which this cell is constrained. - pub fn num_bits(&self) -> usize { - self.num_bits - } -} - -impl RangeConstrained> { - /// Constructs a `RangeConstrained>` as a bitrange of the given value. - pub fn bitrange_of(value: Value<&F>, bitrange: Range) -> Self { - let num_bits = bitrange.len(); - Self { - inner: value.map(|value| bitrange_subset(value, bitrange)), - num_bits, - _phantom: PhantomData::default(), - } - } -} - -impl RangeConstrained> { - /// Constructs a `RangeConstrained>` without verifying that the - /// cell is correctly range constrained. - /// - /// This API only exists to ease with integrating this type into existing circuits, - /// and will likely be removed in future. - pub fn unsound_unchecked(cell: AssignedCell, num_bits: usize) -> Self { - Self { - inner: cell, - num_bits, - _phantom: PhantomData::default(), - } - } - - /// Extracts the range-constrained value from this range-constrained cell. - pub fn value(&self) -> RangeConstrained> { - RangeConstrained { - inner: self.inner.value().copied(), - num_bits: self.num_bits, - _phantom: PhantomData::default(), - } - } -} - -/// Checks that an expression is either 1 or 0. -pub fn bool_check(value: Expression) -> Expression { - range_check(value, 2) -} - -/// If `a` then `b`, else `c`. Returns (a * b) + (1 - a) * c. -/// -/// `a` must be a boolean-constrained expression. -pub fn ternary(a: Expression, b: Expression, c: Expression) -> Expression { - let one_minus_a = Expression::Constant(F::one()) - a.clone(); - a * b + one_minus_a * c -} - -/// Takes a specified subsequence of the little-endian bit representation of a field element. -/// The bits are numbered from 0 for the LSB. -pub fn bitrange_subset(field_elem: &F, bitrange: Range) -> F { - // We can allow a subsequence of length NUM_BITS, because - // field_elem.to_le_bits() returns canonical bitstrings. - assert!(bitrange.end <= F::NUM_BITS as usize); - - field_elem - .to_le_bits() - .iter() - .by_vals() - .skip(bitrange.start) - .take(bitrange.end - bitrange.start) - .rev() - .fold(F::zero(), |acc, bit| { - if bit { - acc.double() + F::one() - } else { - acc.double() - } - }) -} - -/// Check that an expression is in the small range [0..range), -/// i.e. 0 ≤ word < range. -pub fn range_check(word: Expression, range: usize) -> Expression { - (1..range).fold(word.clone(), |acc, i| { - acc * (Expression::Constant(F::from(i as u64)) - word.clone()) - }) -} - -/// Decompose a word `alpha` into `window_num_bits` bits (little-endian) -/// For a window size of `w`, this returns [k_0, ..., k_n] where each `k_i` -/// is a `w`-bit value, and `scalar = k_0 + k_1 * w + k_n * w^n`. -/// -/// # Panics -/// -/// We are returning a `Vec` which means the window size is limited to -/// <= 8 bits. -pub fn decompose_word( - word: &F, - word_num_bits: usize, - window_num_bits: usize, -) -> Vec { - assert!(window_num_bits <= 8); - - // Pad bits to multiple of window_num_bits - let padding = (window_num_bits - (word_num_bits % window_num_bits)) % window_num_bits; - let bits: Vec = word - .to_le_bits() - .into_iter() - .take(word_num_bits) - .chain(std::iter::repeat(false).take(padding)) - .collect(); - assert_eq!(bits.len(), word_num_bits + padding); - - bits.chunks_exact(window_num_bits) - .map(|chunk| chunk.iter().rev().fold(0, |acc, b| (acc << 1) + (*b as u8))) - .collect() -} - -/// The u64 integer represented by an L-bit little-endian bitstring. -/// -/// # Panics -/// -/// Panics if the bitstring is longer than 64 bits. -pub fn lebs2ip(bits: &[bool; L]) -> u64 { - assert!(L <= 64); - bits.iter() - .enumerate() - .fold(0u64, |acc, (i, b)| acc + if *b { 1 << i } else { 0 }) -} - -/// The sequence of bits representing a u64 in little-endian order. -/// -/// # Panics -/// -/// Panics if the expected length of the sequence `NUM_BITS` exceeds -/// 64. -pub fn i2lebsp(int: u64) -> [bool; NUM_BITS] { - /// Takes in an FnMut closure and returns a constant-length array with elements of - /// type `Output`. - fn gen_const_array( - closure: impl FnMut(usize) -> Output, - ) -> [Output; LEN] { - let mut ret: [Output; LEN] = [Default::default(); LEN]; - for (bit, val) in ret.iter_mut().zip((0..LEN).map(closure)) { - *bit = val; - } - ret - } - assert!(NUM_BITS <= 64); - gen_const_array(|mask: usize| (int & (1 << mask)) != 0) -} - -#[cfg(test)] -mod tests { - use super::*; - use group::ff::{Field, PrimeField}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::{FailureLocation, MockProver, VerifyFailure}, - plonk::{Any, Circuit, ConstraintSystem, Constraints, Error, Selector}, - poly::Rotation, - }; - use halo2curves::{pasta::pallas, FieldExt}; - use proptest::prelude::*; - use rand::rngs::OsRng; - use std::convert::TryInto; - use std::iter; - use uint::construct_uint; - - #[test] - fn test_range_check() { - struct MyCircuit(u8); - - impl UtilitiesInstructions for MyCircuit { - type Var = AssignedCell; - } - - #[derive(Clone)] - struct Config { - selector: Selector, - advice: Column, - } - - impl Circuit for MyCircuit { - type Config = Config; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - MyCircuit(self.0) - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let selector = meta.selector(); - let advice = meta.advice_column(); - - meta.create_gate("range check", |meta| { - let selector = meta.query_selector(selector); - let advice = meta.query_advice(advice, Rotation::cur()); - - Constraints::with_selector(selector, Some(range_check(advice, RANGE))) - }); - - Config { selector, advice } - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - layouter.assign_region( - || "range constrain", - |mut region| { - config.selector.enable(&mut region, 0)?; - region.assign_advice( - || format!("witness {}", self.0), - config.advice, - 0, - || Value::known(pallas::Base::from(self.0 as u64)), - )?; - - Ok(()) - }, - ) - } - } - - for i in 0..8 { - let circuit: MyCircuit<8> = MyCircuit(i); - let prover = MockProver::::run(3, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - { - let circuit: MyCircuit<8> = MyCircuit(8); - let prover = MockProver::::run(3, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![VerifyFailure::ConstraintNotSatisfied { - constraint: ((0, "range check").into(), 0, "").into(), - location: FailureLocation::InRegion { - region: (0, "range constrain").into(), - offset: 0, - }, - cell_values: vec![(((Any::advice(), 0).into(), 0).into(), "0x8".to_string())], - }]) - ); - } - } - - #[allow(clippy::assign_op_pattern)] - #[allow(clippy::ptr_offset_with_cast)] - #[test] - fn test_bitrange_subset() { - let rng = OsRng; - - construct_uint! { - struct U256(4); - } - - // Subset full range. - { - let field_elem = pallas::Base::random(rng); - let bitrange = 0..(pallas::Base::NUM_BITS as usize); - let subset = bitrange_subset(&field_elem, bitrange); - assert_eq!(field_elem, subset); - } - - // Subset zero bits - { - let field_elem = pallas::Base::random(rng); - let bitrange = 0..0; - let subset = bitrange_subset(&field_elem, bitrange); - assert_eq!(pallas::Base::zero(), subset); - } - - // Closure to decompose field element into pieces using consecutive ranges, - // and check that we recover the original. - let decompose = |field_elem: pallas::Base, ranges: &[Range]| { - assert_eq!( - ranges.iter().map(|range| range.len()).sum::(), - pallas::Base::NUM_BITS as usize - ); - assert_eq!(ranges[0].start, 0); - assert_eq!(ranges.last().unwrap().end, pallas::Base::NUM_BITS as usize); - - // Check ranges are contiguous - #[allow(unused_assignments)] - { - let mut ranges = ranges.iter(); - let mut range = ranges.next().unwrap(); - if let Some(next_range) = ranges.next() { - assert_eq!(range.end, next_range.start); - range = next_range; - } - } - - let subsets = ranges - .iter() - .map(|range| bitrange_subset(&field_elem, range.clone())) - .collect::>(); - - let mut sum = subsets[0]; - let mut num_bits = 0; - for (idx, subset) in subsets.iter().skip(1).enumerate() { - // 2^num_bits - let range_shift: [u8; 32] = { - num_bits += ranges[idx].len(); - let mut range_shift = [0u8; 32]; - U256([2, 0, 0, 0]) - .pow(U256([num_bits as u64, 0, 0, 0])) - .to_little_endian(&mut range_shift); - range_shift - }; - sum += subset * pallas::Base::from_repr(range_shift).unwrap(); - } - assert_eq!(field_elem, sum); - }; - - decompose(pallas::Base::random(rng), &[0..255]); - decompose(pallas::Base::random(rng), &[0..1, 1..255]); - decompose(pallas::Base::random(rng), &[0..254, 254..255]); - decompose(pallas::Base::random(rng), &[0..127, 127..255]); - decompose(pallas::Base::random(rng), &[0..128, 128..255]); - decompose( - pallas::Base::random(rng), - &[0..50, 50..100, 100..150, 150..200, 200..255], - ); - } - - prop_compose! { - fn arb_scalar()(bytes in prop::array::uniform32(0u8..)) -> pallas::Scalar { - // Instead of rejecting out-of-range bytes, let's reduce them. - let mut buf = [0; 64]; - buf[..32].copy_from_slice(&bytes); - pallas::Scalar::from_bytes_wide(&buf) - } - } - - proptest! { - #[test] - fn test_decompose_word( - scalar in arb_scalar(), - window_num_bits in 1u8..9 - ) { - // Get decomposition into `window_num_bits` bits - let decomposed = decompose_word(&scalar, pallas::Scalar::NUM_BITS as usize, window_num_bits as usize); - - // Flatten bits - let bits = decomposed - .iter() - .flat_map(|window| (0..window_num_bits).map(move |mask| (window & (1 << mask)) != 0)); - - // Ensure this decomposition contains 256 or fewer set bits. - assert!(!bits.clone().skip(32*8).any(|b| b)); - - // Pad or truncate bits to 32 bytes - let bits: Vec = bits.chain(iter::repeat(false)).take(32*8).collect(); - - let bytes: Vec = bits.chunks_exact(8).map(|chunk| chunk.iter().rev().fold(0, |acc, b| (acc << 1) + (*b as u8))).collect(); - - // Check that original scalar is recovered from decomposition - assert_eq!(scalar, pallas::Scalar::from_repr(bytes.try_into().unwrap()).unwrap()); - } - } - - #[test] - fn lebs2ip_round_trip() { - use rand::rngs::OsRng; - - let mut rng = OsRng; - { - let int = rng.next_u64(); - assert_eq!(lebs2ip::<64>(&i2lebsp(int)), int); - } - - assert_eq!(lebs2ip::<64>(&i2lebsp(0)), 0); - assert_eq!( - lebs2ip::<64>(&i2lebsp(0xFFFFFFFFFFFFFFFF)), - 0xFFFFFFFFFFFFFFFF - ); - } - - #[test] - fn i2lebsp_round_trip() { - { - let bitstring = (0..64).map(|_| rand::random()).collect::>(); - assert_eq!( - i2lebsp::<64>(lebs2ip::<64>(&bitstring.clone().try_into().unwrap())).to_vec(), - bitstring - ); - } - - { - let bitstring = [false; 64]; - assert_eq!(i2lebsp(lebs2ip(&bitstring)), bitstring); - } - - { - let bitstring = [true; 64]; - assert_eq!(i2lebsp(lebs2ip(&bitstring)), bitstring); - } - - { - let bitstring = []; - assert_eq!(i2lebsp(lebs2ip(&bitstring)), bitstring); - } - } -} diff --git a/halo2_gadgets/src/utilities/cond_swap.rs b/halo2_gadgets/src/utilities/cond_swap.rs deleted file mode 100644 index 9dc1afa3ef..0000000000 --- a/halo2_gadgets/src/utilities/cond_swap.rs +++ /dev/null @@ -1,293 +0,0 @@ -//! Gadget and chip for a conditional swap utility. - -use super::{bool_check, ternary, UtilitiesInstructions}; -use halo2_proofs::{ - circuit::{AssignedCell, Chip, Layouter, Value}, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Selector}, - poly::Rotation, -}; -use halo2curves::FieldExt; -use std::marker::PhantomData; - -/// Instructions for a conditional swap gadget. -pub trait CondSwapInstructions: UtilitiesInstructions { - #[allow(clippy::type_complexity)] - /// Given an input pair (a,b) and a `swap` boolean flag, returns - /// (b,a) if `swap` is set, else (a,b) if `swap` is not set. - /// - /// The second element of the pair is required to be a witnessed - /// value, not a variable that already exists in the circuit. - fn swap( - &self, - layouter: impl Layouter, - pair: (Self::Var, Value), - swap: Value, - ) -> Result<(Self::Var, Self::Var), Error>; -} - -/// A chip implementing a conditional swap. -#[derive(Clone, Debug)] -pub struct CondSwapChip { - config: CondSwapConfig, - _marker: PhantomData, -} - -impl Chip for CondSwapChip { - type Config = CondSwapConfig; - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -/// Configuration for the [`CondSwapChip`]. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CondSwapConfig { - q_swap: Selector, - a: Column, - b: Column, - a_swapped: Column, - b_swapped: Column, - swap: Column, -} - -#[cfg(test)] -impl CondSwapConfig { - pub(crate) fn a(&self) -> Column { - self.a - } -} - -impl UtilitiesInstructions for CondSwapChip { - type Var = AssignedCell; -} - -impl CondSwapInstructions for CondSwapChip { - #[allow(clippy::type_complexity)] - fn swap( - &self, - mut layouter: impl Layouter, - pair: (Self::Var, Value), - swap: Value, - ) -> Result<(Self::Var, Self::Var), Error> { - let config = self.config(); - - layouter.assign_region( - || "swap", - |mut region| { - // Enable `q_swap` selector - config.q_swap.enable(&mut region, 0)?; - - // Copy in `a` value - let a = pair.0.copy_advice(|| "copy a", &mut region, config.a, 0)?; - - // Witness `b` value - let b = region.assign_advice(|| "witness b", config.b, 0, || pair.1)?; - - // Witness `swap` value - let swap_val = swap.map(|swap| F::from(swap as u64)); - region.assign_advice(|| "swap", config.swap, 0, || swap_val)?; - - // Conditionally swap a - let a_swapped = { - let a_swapped = a - .value() - .zip(b.value()) - .zip(swap) - .map(|((a, b), swap)| if swap { b } else { a }) - .cloned(); - region.assign_advice(|| "a_swapped", config.a_swapped, 0, || a_swapped)? - }; - - // Conditionally swap b - let b_swapped = { - let b_swapped = a - .value() - .zip(b.value()) - .zip(swap) - .map(|((a, b), swap)| if swap { a } else { b }) - .cloned(); - region.assign_advice(|| "b_swapped", config.b_swapped, 0, || b_swapped)? - }; - - // Return swapped pair - Ok((a_swapped, b_swapped)) - }, - ) - } -} - -impl CondSwapChip { - /// Configures this chip for use in a circuit. - /// - /// # Side-effects - /// - /// `advices[0]` will be equality-enabled. - pub fn configure( - meta: &mut ConstraintSystem, - advices: [Column; 5], - ) -> CondSwapConfig { - let a = advices[0]; - // Only column a is used in an equality constraint directly by this chip. - meta.enable_equality(a); - - let q_swap = meta.selector(); - - let config = CondSwapConfig { - q_swap, - a, - b: advices[1], - a_swapped: advices[2], - b_swapped: advices[3], - swap: advices[4], - }; - - // TODO: optimise shape of gate for Merkle path validation - - meta.create_gate("a' = b ⋅ swap + a ⋅ (1-swap)", |meta| { - let q_swap = meta.query_selector(q_swap); - - let a = meta.query_advice(config.a, Rotation::cur()); - let b = meta.query_advice(config.b, Rotation::cur()); - let a_swapped = meta.query_advice(config.a_swapped, Rotation::cur()); - let b_swapped = meta.query_advice(config.b_swapped, Rotation::cur()); - let swap = meta.query_advice(config.swap, Rotation::cur()); - - // This checks that `a_swapped` is equal to `b` when `swap` is set, - // but remains as `a` when `swap` is not set. - let a_check = a_swapped - ternary(swap.clone(), b.clone(), a.clone()); - - // This checks that `b_swapped` is equal to `a` when `swap` is set, - // but remains as `b` when `swap` is not set. - let b_check = b_swapped - ternary(swap.clone(), a, b); - - // Check `swap` is boolean. - let bool_check = bool_check(swap); - - Constraints::with_selector( - q_swap, - [ - ("a check", a_check), - ("b check", b_check), - ("swap is bool", bool_check), - ], - ) - }); - - config - } - - /// Constructs a [`CondSwapChip`] given a [`CondSwapConfig`]. - pub fn construct(config: CondSwapConfig) -> Self { - CondSwapChip { - config, - _marker: PhantomData, - } - } -} - -#[cfg(test)] -mod tests { - use super::super::UtilitiesInstructions; - use super::{CondSwapChip, CondSwapConfig, CondSwapInstructions}; - use group::ff::Field; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::MockProver, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use halo2curves::{pasta::pallas::Base, FieldExt}; - use rand::rngs::OsRng; - - #[test] - fn cond_swap() { - #[derive(Default)] - struct MyCircuit { - a: Value, - b: Value, - swap: Value, - } - - impl Circuit for MyCircuit { - type Config = CondSwapConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let advices = [ - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - meta.advice_column(), - ]; - - CondSwapChip::::configure(meta, advices) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let chip = CondSwapChip::::construct(config.clone()); - - // Load the pair and the swap flag into the circuit. - let a = chip.load_private(layouter.namespace(|| "a"), config.a, self.a)?; - // Return the swapped pair. - let swapped_pair = chip.swap( - layouter.namespace(|| "swap"), - (a.clone(), self.b), - self.swap, - )?; - - self.swap - .zip(a.value().zip(self.b.as_ref())) - .zip(swapped_pair.0.value().zip(swapped_pair.1.value())) - .assert_if_known(|((swap, (a, b)), (a_swapped, b_swapped))| { - if *swap { - // Check that `a` and `b` have been swapped - (a_swapped == b) && (b_swapped == a) - } else { - // Check that `a` and `b` have not been swapped - (a_swapped == a) && (b_swapped == b) - } - }); - - Ok(()) - } - } - - let rng = OsRng; - - // Test swap case - { - let circuit: MyCircuit = MyCircuit { - a: Value::known(Base::random(rng)), - b: Value::known(Base::random(rng)), - swap: Value::known(true), - }; - let prover = MockProver::::run(3, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // Test non-swap case - { - let circuit: MyCircuit = MyCircuit { - a: Value::known(Base::random(rng)), - b: Value::known(Base::random(rng)), - swap: Value::known(false), - }; - let prover = MockProver::::run(3, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - } -} diff --git a/halo2_gadgets/src/utilities/decompose_running_sum.rs b/halo2_gadgets/src/utilities/decompose_running_sum.rs deleted file mode 100644 index 89508f176c..0000000000 --- a/halo2_gadgets/src/utilities/decompose_running_sum.rs +++ /dev/null @@ -1,391 +0,0 @@ -//! Decomposes an $n$-bit field element $\alpha$ into $W$ windows, each window -//! being a $K$-bit word, using a running sum $z$. -//! We constrain $K \leq 3$ for this helper. -//! $$\alpha = k_0 + (2^K) k_1 + (2^{2K}) k_2 + ... + (2^{(W-1)K}) k_{W-1}$$ -//! -//! $z_0$ is initialized as $\alpha$. Each successive $z_{i+1}$ is computed as -//! $$z_{i+1} = (z_{i} - k_i) / (2^K).$$ -//! $z_W$ is constrained to be zero. -//! The difference between each interstitial running sum output is constrained -//! to be $K$ bits, i.e. -//! `range_check`($k_i$, $2^K$), -//! where -//! ```text -//! range_check(word, range) -//! = word * (1 - word) * (2 - word) * ... * ((range - 1) - word) -//! ``` -//! -//! Given that the `range_check` constraint will be toggled by a selector, in -//! practice we will have a `selector * range_check(word, range)` expression -//! of degree `range + 1`. -//! -//! This means that $2^K$ has to be at most `degree_bound - 1` in order for -//! the range check constraint to stay within the degree bound. - -use ff::PrimeFieldBits; -use halo2_proofs::{ - circuit::{AssignedCell, Region, Value}, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Selector}, - poly::Rotation, -}; - -use super::range_check; -use halo2curves::FieldExt; -use std::marker::PhantomData; - -/// The running sum $[z_0, ..., z_W]$. If created in strict mode, $z_W = 0$. -#[derive(Debug)] -pub struct RunningSum(Vec>); -impl std::ops::Deref for RunningSum { - type Target = Vec>; - - fn deref(&self) -> &Vec> { - &self.0 - } -} - -/// Configuration that provides methods for running sum decomposition. -#[derive(Debug, Clone, Copy, Eq, PartialEq)] -pub struct RunningSumConfig { - q_range_check: Selector, - z: Column, - _marker: PhantomData, -} - -impl - RunningSumConfig -{ - /// Returns the q_range_check selector of this [`RunningSumConfig`]. - pub(crate) fn q_range_check(&self) -> Selector { - self.q_range_check - } - - /// `perm` MUST include the advice column `z`. - /// - /// # Panics - /// - /// Panics if WINDOW_NUM_BITS > 3. - /// - /// # Side-effects - /// - /// `z` will be equality-enabled. - pub fn configure( - meta: &mut ConstraintSystem, - q_range_check: Selector, - z: Column, - ) -> Self { - assert!(WINDOW_NUM_BITS <= 3); - - meta.enable_equality(z); - - let config = Self { - q_range_check, - z, - _marker: PhantomData, - }; - - // https://p.z.cash/halo2-0.1:decompose-short-range - meta.create_gate("range check", |meta| { - let q_range_check = meta.query_selector(config.q_range_check); - let z_cur = meta.query_advice(config.z, Rotation::cur()); - let z_next = meta.query_advice(config.z, Rotation::next()); - // z_i = 2^{K}⋅z_{i + 1} + k_i - // => k_i = z_i - 2^{K}⋅z_{i + 1} - let word = z_cur - z_next * F::from(1 << WINDOW_NUM_BITS); - - Constraints::with_selector(q_range_check, Some(range_check(word, 1 << WINDOW_NUM_BITS))) - }); - - config - } - - /// Decompose a field element alpha that is witnessed in this helper. - /// - /// `strict` = true constrains the final running sum to be zero, i.e. - /// constrains alpha to be within WINDOW_NUM_BITS * num_windows bits. - pub fn witness_decompose( - &self, - region: &mut Region<'_, F>, - offset: usize, - alpha: Value, - strict: bool, - word_num_bits: usize, - num_windows: usize, - ) -> Result, Error> { - let z_0 = region.assign_advice(|| "z_0 = alpha", self.z, offset, || alpha)?; - self.decompose(region, offset, z_0, strict, word_num_bits, num_windows) - } - - /// Decompose an existing variable alpha that is copied into this helper. - /// - /// `strict` = true constrains the final running sum to be zero, i.e. - /// constrains alpha to be within WINDOW_NUM_BITS * num_windows bits. - pub fn copy_decompose( - &self, - region: &mut Region<'_, F>, - offset: usize, - alpha: AssignedCell, - strict: bool, - word_num_bits: usize, - num_windows: usize, - ) -> Result, Error> { - let z_0 = alpha.copy_advice(|| "copy z_0 = alpha", region, self.z, offset)?; - self.decompose(region, offset, z_0, strict, word_num_bits, num_windows) - } - - /// `z_0` must be the cell at `(self.z, offset)` in `region`. - /// - /// # Panics - /// - /// Panics if there are too many windows for the given word size. - fn decompose( - &self, - region: &mut Region<'_, F>, - offset: usize, - z_0: AssignedCell, - strict: bool, - word_num_bits: usize, - num_windows: usize, - ) -> Result, Error> { - // Make sure that we do not have more windows than required for the number - // of bits in the word. In other words, every window must contain at least - // one bit of the word (no empty windows). - // - // For example, let: - // - word_num_bits = 64 - // - WINDOW_NUM_BITS = 3 - // In this case, the maximum allowed num_windows is 22: - // 3 * 22 < 64 + 3 - // - assert!(WINDOW_NUM_BITS * num_windows < word_num_bits + WINDOW_NUM_BITS); - - // Enable selectors - for idx in 0..num_windows { - self.q_range_check.enable(region, offset + idx)?; - } - - // Decompose base field element into K-bit words. - let words = z_0 - .value() - .map(|word| super::decompose_word::(word, word_num_bits, WINDOW_NUM_BITS)) - .transpose_vec(num_windows); - - // Initialize empty vector to store running sum values [z_0, ..., z_W]. - let mut zs: Vec> = vec![z_0.clone()]; - let mut z = z_0; - - // Assign running sum `z_{i+1}` = (z_i - k_i) / (2^K) for i = 0..=n-1. - // Outside of this helper, z_0 = alpha must have already been loaded into the - // `z` column at `offset`. - let two_pow_k_inv = Value::known(F::from(1 << WINDOW_NUM_BITS as u64).invert().unwrap()); - for (i, word) in words.iter().enumerate() { - // z_next = (z_cur - word) / (2^K) - let z_next = { - let z_cur_val = z.value().copied(); - let word = word.map(|word| F::from(word as u64)); - let z_next_val = (z_cur_val - word) * two_pow_k_inv; - region.assign_advice( - || format!("z_{:?}", i + 1), - self.z, - offset + i + 1, - || z_next_val, - )? - }; - - // Update `z`. - z = z_next; - zs.push(z.clone()); - } - assert_eq!(zs.len(), num_windows + 1); - - if strict { - // Constrain the final running sum output to be zero. - region.constrain_constant(zs.last().unwrap().cell(), F::zero())?; - } - - Ok(RunningSum(zs)) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use group::ff::{Field, PrimeField}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - dev::{FailureLocation, MockProver, VerifyFailure}, - plonk::{Any, Circuit, ConstraintSystem, Error}, - }; - use halo2curves::{pasta::pallas, FieldExt}; - use rand::rngs::OsRng; - - use crate::ecc::chip::{ - FIXED_BASE_WINDOW_SIZE, L_SCALAR_SHORT as L_SHORT, NUM_WINDOWS, NUM_WINDOWS_SHORT, - }; - - const L_BASE: usize = pallas::Base::NUM_BITS as usize; - - #[test] - fn test_running_sum() { - struct MyCircuit< - F: FieldExt + PrimeFieldBits, - const WORD_NUM_BITS: usize, - const WINDOW_NUM_BITS: usize, - const NUM_WINDOWS: usize, - > { - alpha: Value, - strict: bool, - } - - impl< - F: FieldExt + PrimeFieldBits, - const WORD_NUM_BITS: usize, - const WINDOW_NUM_BITS: usize, - const NUM_WINDOWS: usize, - > Circuit for MyCircuit - { - type Config = RunningSumConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self { - alpha: Value::unknown(), - strict: self.strict, - } - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let z = meta.advice_column(); - let q_range_check = meta.selector(); - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - RunningSumConfig::::configure(meta, q_range_check, z) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - layouter.assign_region( - || "decompose", - |mut region| { - let offset = 0; - let zs = config.witness_decompose( - &mut region, - offset, - self.alpha, - self.strict, - WORD_NUM_BITS, - NUM_WINDOWS, - )?; - let alpha = zs[0].clone(); - - let offset = offset + NUM_WINDOWS + 1; - - config.copy_decompose( - &mut region, - offset, - alpha, - self.strict, - WORD_NUM_BITS, - NUM_WINDOWS, - )?; - - Ok(()) - }, - ) - } - } - - // Random base field element - { - let alpha = pallas::Base::random(OsRng); - - // Strict full decomposition should pass. - let circuit: MyCircuit = - MyCircuit { - alpha: Value::known(alpha), - strict: true, - }; - let prover = MockProver::::run(8, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // Random 64-bit word - { - let alpha = pallas::Base::from(rand::random::()); - - // Strict full decomposition should pass. - let circuit: MyCircuit< - pallas::Base, - L_SHORT, - FIXED_BASE_WINDOW_SIZE, - { NUM_WINDOWS_SHORT }, - > = MyCircuit { - alpha: Value::known(alpha), - strict: true, - }; - let prover = MockProver::::run(8, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // 2^66 - { - let alpha = pallas::Base::from_u128(1 << 66); - - // Strict partial decomposition should fail. - let circuit: MyCircuit< - pallas::Base, - L_SHORT, - FIXED_BASE_WINDOW_SIZE, - { NUM_WINDOWS_SHORT }, - > = MyCircuit { - alpha: Value::known(alpha), - strict: true, - }; - let prover = MockProver::::run(8, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::Permutation { - column: (Any::Fixed, 0).into(), - location: FailureLocation::OutsideRegion { row: 0 }, - }, - VerifyFailure::Permutation { - column: (Any::Fixed, 0).into(), - location: FailureLocation::OutsideRegion { row: 1 }, - }, - VerifyFailure::Permutation { - column: (Any::advice(), 0).into(), - location: FailureLocation::InRegion { - region: (0, "decompose").into(), - offset: 22, - }, - }, - VerifyFailure::Permutation { - column: (Any::advice(), 0).into(), - location: FailureLocation::InRegion { - region: (0, "decompose").into(), - offset: 45, - }, - }, - ]) - ); - - // Non-strict partial decomposition should pass. - let circuit: MyCircuit< - pallas::Base, - { L_SHORT }, - FIXED_BASE_WINDOW_SIZE, - { NUM_WINDOWS_SHORT }, - > = MyCircuit { - alpha: Value::known(alpha), - strict: false, - }; - let prover = MockProver::::run(8, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - } -} diff --git a/halo2_gadgets/src/utilities/lookup_range_check.rs b/halo2_gadgets/src/utilities/lookup_range_check.rs deleted file mode 100644 index f97654c38b..0000000000 --- a/halo2_gadgets/src/utilities/lookup_range_check.rs +++ /dev/null @@ -1,654 +0,0 @@ -//! Make use of a K-bit lookup table to decompose a field element into K-bit -//! words. - -use halo2_proofs::{ - circuit::{AssignedCell, Layouter, Region}, - plonk::{Advice, Column, ConstraintSystem, Constraints, Error, Selector, TableColumn}, - poly::Rotation, -}; -use std::{convert::TryInto, marker::PhantomData}; - -use ff::PrimeFieldBits; - -use super::*; - -/// The running sum $[z_0, ..., z_W]$. If created in strict mode, $z_W = 0$. -#[derive(Debug)] -pub struct RunningSum(Vec>); -impl std::ops::Deref for RunningSum { - type Target = Vec>; - - fn deref(&self) -> &Vec> { - &self.0 - } -} - -impl RangeConstrained> { - /// Witnesses a subset of the bits in `value` and constrains them to be the correct - /// number of bits. - /// - /// # Panics - /// - /// Panics if `bitrange.len() >= K`. - pub fn witness_short( - lookup_config: &LookupRangeCheckConfig, - layouter: impl Layouter, - value: Value<&F>, - bitrange: Range, - ) -> Result { - let num_bits = bitrange.len(); - assert!(num_bits < K); - - // Witness the subset and constrain it to be the correct number of bits. - lookup_config - .witness_short_check( - layouter, - value.map(|value| bitrange_subset(value, bitrange)), - num_bits, - ) - .map(|inner| Self { - inner, - num_bits, - _phantom: PhantomData::default(), - }) - } -} - -/// Configuration that provides methods for a lookup range check. -#[derive(Eq, PartialEq, Debug, Clone, Copy)] -pub struct LookupRangeCheckConfig { - q_lookup: Selector, - q_running: Selector, - q_bitshift: Selector, - running_sum: Column, - table_idx: TableColumn, - _marker: PhantomData, -} - -impl LookupRangeCheckConfig { - /// The `running_sum` advice column breaks the field element into `K`-bit - /// words. It is used to construct the input expression to the lookup - /// argument. - /// - /// The `table_idx` fixed column contains values from [0..2^K). Looking up - /// a value in `table_idx` constrains it to be within this range. The table - /// can be loaded outside this helper. - /// - /// # Side-effects - /// - /// Both the `running_sum` and `constants` columns will be equality-enabled. - pub fn configure( - meta: &mut ConstraintSystem, - running_sum: Column, - table_idx: TableColumn, - ) -> Self { - meta.enable_equality(running_sum); - - let q_lookup = meta.complex_selector(); - let q_running = meta.complex_selector(); - let q_bitshift = meta.selector(); - let config = LookupRangeCheckConfig { - q_lookup, - q_running, - q_bitshift, - running_sum, - table_idx, - _marker: PhantomData, - }; - - // https://p.z.cash/halo2-0.1:decompose-combined-lookup - meta.lookup("lookup", |meta| { - let q_lookup = meta.query_selector(config.q_lookup); - let q_running = meta.query_selector(config.q_running); - let z_cur = meta.query_advice(config.running_sum, Rotation::cur()); - - // In the case of a running sum decomposition, we recover the word from - // the difference of the running sums: - // z_i = 2^{K}⋅z_{i + 1} + a_i - // => a_i = z_i - 2^{K}⋅z_{i + 1} - let running_sum_lookup = { - let running_sum_word = { - let z_next = meta.query_advice(config.running_sum, Rotation::next()); - z_cur.clone() - z_next * F::from(1 << K) - }; - - q_running.clone() * running_sum_word - }; - - // In the short range check, the word is directly witnessed. - let short_lookup = { - let short_word = z_cur; - let q_short = Expression::Constant(F::one()) - q_running; - - q_short * short_word - }; - - // Combine the running sum and short lookups: - vec![( - q_lookup * (running_sum_lookup + short_lookup), - config.table_idx, - )] - }); - - // For short lookups, check that the word has been shifted by the correct number of bits. - // https://p.z.cash/halo2-0.1:decompose-short-lookup - meta.create_gate("Short lookup bitshift", |meta| { - let q_bitshift = meta.query_selector(config.q_bitshift); - let word = meta.query_advice(config.running_sum, Rotation::prev()); - let shifted_word = meta.query_advice(config.running_sum, Rotation::cur()); - let inv_two_pow_s = meta.query_advice(config.running_sum, Rotation::next()); - - let two_pow_k = F::from(1 << K); - - // shifted_word = word * 2^{K-s} - // = word * 2^K * inv_two_pow_s - Constraints::with_selector( - q_bitshift, - Some(word * two_pow_k * inv_two_pow_s - shifted_word), - ) - }); - - config - } - - #[cfg(test)] - // Loads the values [0..2^K) into `table_idx`. This is only used in testing - // for now, since the Sinsemilla chip provides a pre-loaded table in the - // Orchard context. - pub fn load(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_table( - || "table_idx", - |mut table| { - // We generate the row values lazily (we only need them during keygen). - for index in 0..(1 << K) { - table.assign_cell( - || "table_idx", - self.table_idx, - index, - || Value::known(F::from(index as u64)), - )?; - } - Ok(()) - }, - ) - } - - /// Range check on an existing cell that is copied into this helper. - /// - /// Returns an error if `element` is not in a column that was passed to - /// [`ConstraintSystem::enable_equality`] during circuit configuration. - pub fn copy_check( - &self, - mut layouter: impl Layouter, - element: AssignedCell, - num_words: usize, - strict: bool, - ) -> Result, Error> { - layouter.assign_region( - || format!("{:?} words range check", num_words), - |mut region| { - // Copy `element` and initialize running sum `z_0 = element` to decompose it. - let z_0 = element.copy_advice(|| "z_0", &mut region, self.running_sum, 0)?; - self.range_check(&mut region, z_0, num_words, strict) - }, - ) - } - - /// Range check on a value that is witnessed in this helper. - pub fn witness_check( - &self, - mut layouter: impl Layouter, - value: Value, - num_words: usize, - strict: bool, - ) -> Result, Error> { - layouter.assign_region( - || "Witness element", - |mut region| { - let z_0 = - region.assign_advice(|| "Witness element", self.running_sum, 0, || value)?; - self.range_check(&mut region, z_0, num_words, strict) - }, - ) - } - - /// If `strict` is set to "true", the field element must fit into - /// `num_words * K` bits. In other words, the the final cumulative sum `z_{num_words}` - /// must be zero. - /// - /// If `strict` is set to "false", the final `z_{num_words}` is not constrained. - /// - /// `element` must have been assigned to `self.running_sum` at offset 0. - fn range_check( - &self, - region: &mut Region<'_, F>, - element: AssignedCell, - num_words: usize, - strict: bool, - ) -> Result, Error> { - // `num_words` must fit into a single field element. - assert!(num_words * K <= F::CAPACITY as usize); - let num_bits = num_words * K; - - // Chunk the first num_bits bits into K-bit words. - let words = { - // Take first num_bits bits of `element`. - let bits = element.value().map(|element| { - element - .to_le_bits() - .into_iter() - .take(num_bits) - .collect::>() - }); - - bits.map(|bits| { - bits.chunks_exact(K) - .map(|word| F::from(lebs2ip::(&(word.try_into().unwrap())))) - .collect::>() - }) - .transpose_vec(num_words) - }; - - let mut zs = vec![element.clone()]; - - // Assign cumulative sum such that - // z_i = 2^{K}⋅z_{i + 1} + a_i - // => z_{i + 1} = (z_i - a_i) / (2^K) - // - // For `element` = a_0 + 2^10 a_1 + ... + 2^{120} a_{12}}, initialize z_0 = `element`. - // If `element` fits in 130 bits, we end up with z_{13} = 0. - let mut z = element; - let inv_two_pow_k = F::from(1u64 << K).invert().unwrap(); - for (idx, word) in words.iter().enumerate() { - // Enable q_lookup on this row - self.q_lookup.enable(region, idx)?; - // Enable q_running on this row - self.q_running.enable(region, idx)?; - - // z_next = (z_cur - m_cur) / 2^K - z = { - let z_val = z - .value() - .zip(*word) - .map(|(z, word)| (*z - word) * inv_two_pow_k); - - // Assign z_next - region.assign_advice( - || format!("z_{:?}", idx + 1), - self.running_sum, - idx + 1, - || z_val, - )? - }; - zs.push(z.clone()); - } - - if strict { - // Constrain the final `z` to be zero. - region.constrain_constant(zs.last().unwrap().cell(), F::zero())?; - } - - Ok(RunningSum(zs)) - } - - /// Short range check on an existing cell that is copied into this helper. - /// - /// # Panics - /// - /// Panics if NUM_BITS is equal to or larger than K. - pub fn copy_short_check( - &self, - mut layouter: impl Layouter, - element: AssignedCell, - num_bits: usize, - ) -> Result<(), Error> { - assert!(num_bits < K); - layouter.assign_region( - || format!("Range check {:?} bits", num_bits), - |mut region| { - // Copy `element` to use in the k-bit lookup. - let element = - element.copy_advice(|| "element", &mut region, self.running_sum, 0)?; - - self.short_range_check(&mut region, element, num_bits) - }, - ) - } - - /// Short range check on value that is witnessed in this helper. - /// - /// # Panics - /// - /// Panics if num_bits is larger than K. - pub fn witness_short_check( - &self, - mut layouter: impl Layouter, - element: Value, - num_bits: usize, - ) -> Result, Error> { - assert!(num_bits <= K); - layouter.assign_region( - || format!("Range check {:?} bits", num_bits), - |mut region| { - // Witness `element` to use in the k-bit lookup. - let element = - region.assign_advice(|| "Witness element", self.running_sum, 0, || element)?; - - self.short_range_check(&mut region, element.clone(), num_bits)?; - - Ok(element) - }, - ) - } - - /// Constrain `x` to be a NUM_BITS word. - /// - /// `element` must have been assigned to `self.running_sum` at offset 0. - fn short_range_check( - &self, - region: &mut Region<'_, F>, - element: AssignedCell, - num_bits: usize, - ) -> Result<(), Error> { - // Enable lookup for `element`, to constrain it to 10 bits. - self.q_lookup.enable(region, 0)?; - - // Enable lookup for shifted element, to constrain it to 10 bits. - self.q_lookup.enable(region, 1)?; - - // Check element has been shifted by the correct number of bits. - self.q_bitshift.enable(region, 1)?; - - // Assign shifted `element * 2^{K - num_bits}` - let shifted = element.value().into_field() * F::from(1 << (K - num_bits)); - - region.assign_advice( - || format!("element * 2^({}-{})", K, num_bits), - self.running_sum, - 1, - || shifted, - )?; - - // Assign 2^{-num_bits} from a fixed column. - let inv_two_pow_s = F::from(1 << num_bits).invert().unwrap(); - region.assign_advice_from_constant( - || format!("2^(-{})", num_bits), - self.running_sum, - 2, - inv_two_pow_s, - )?; - - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::LookupRangeCheckConfig; - - use super::super::lebs2ip; - use crate::sinsemilla::primitives::K; - - use ff::{Field, PrimeFieldBits}; - use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - dev::{FailureLocation, MockProver, VerifyFailure}, - plonk::{Circuit, ConstraintSystem, Error}, - }; - use halo2curves::{pasta::pallas, FieldExt}; - - use std::{convert::TryInto, marker::PhantomData}; - - #[test] - fn lookup_range_check() { - #[derive(Clone, Copy)] - struct MyCircuit { - num_words: usize, - _marker: PhantomData, - } - - impl Circuit for MyCircuit { - type Config = LookupRangeCheckConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - *self - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let running_sum = meta.advice_column(); - let table_idx = meta.lookup_table_column(); - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - LookupRangeCheckConfig::::configure(meta, running_sum, table_idx) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Load table_idx - config.load(&mut layouter)?; - - // Lookup constraining element to be no longer than num_words * K bits. - let elements_and_expected_final_zs = [ - (F::from((1 << (self.num_words * K)) - 1), F::zero(), true), // a word that is within self.num_words * K bits long - (F::from(1 << (self.num_words * K)), F::one(), false), // a word that is just over self.num_words * K bits long - ]; - - fn expected_zs( - element: F, - num_words: usize, - ) -> Vec { - let chunks = { - element - .to_le_bits() - .iter() - .by_vals() - .take(num_words * K) - .collect::>() - .chunks_exact(K) - .map(|chunk| F::from(lebs2ip::(chunk.try_into().unwrap()))) - .collect::>() - }; - let expected_zs = { - let inv_two_pow_k = F::from(1 << K).invert().unwrap(); - chunks.iter().fold(vec![element], |mut zs, a_i| { - // z_{i + 1} = (z_i - a_i) / 2^{K} - let z = (zs[zs.len() - 1] - a_i) * inv_two_pow_k; - zs.push(z); - zs - }) - }; - expected_zs - } - - for (element, expected_final_z, strict) in elements_and_expected_final_zs.iter() { - let expected_zs = expected_zs::(*element, self.num_words); - - let zs = config.witness_check( - layouter.namespace(|| format!("Lookup {:?}", self.num_words)), - Value::known(*element), - self.num_words, - *strict, - )?; - - assert_eq!(*expected_zs.last().unwrap(), *expected_final_z); - - for (expected_z, z) in expected_zs.into_iter().zip(zs.iter()) { - z.value().assert_if_known(|z| &&expected_z == z); - } - } - Ok(()) - } - } - - { - let circuit: MyCircuit = MyCircuit { - num_words: 6, - _marker: PhantomData, - }; - - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - } - - #[test] - fn short_range_check() { - struct MyCircuit { - element: Value, - num_bits: usize, - } - - impl Circuit for MyCircuit { - type Config = LookupRangeCheckConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - MyCircuit { - element: Value::unknown(), - num_bits: self.num_bits, - } - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let running_sum = meta.advice_column(); - let table_idx = meta.lookup_table_column(); - let constants = meta.fixed_column(); - meta.enable_constant(constants); - - LookupRangeCheckConfig::::configure(meta, running_sum, table_idx) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - // Load table_idx - config.load(&mut layouter)?; - - // Lookup constraining element to be no longer than num_bits. - config.witness_short_check( - layouter.namespace(|| format!("Lookup {:?} bits", self.num_bits)), - self.element, - self.num_bits, - )?; - - Ok(()) - } - } - - // Edge case: zero bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::zero()), - num_bits: 0, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // Edge case: K bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from((1 << K) - 1)), - num_bits: K, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // Element within `num_bits` - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from((1 << 6) - 1)), - num_bits: 6, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!(prover.verify(), Ok(())); - } - - // Element larger than `num_bits` but within K bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from(1 << 6)), - num_bits: 6, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![VerifyFailure::Lookup { - name: "lookup", - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 1, - }, - }]) - ); - } - - // Element larger than K bits - { - let circuit: MyCircuit = MyCircuit { - element: Value::known(pallas::Base::from(1 << K)), - num_bits: 6, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![ - VerifyFailure::Lookup { - name: "lookup", - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 0, - }, - }, - VerifyFailure::Lookup { - name: "lookup", - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 1, - }, - }, - ]) - ); - } - - // Element which is not within `num_bits`, but which has a shifted value within - // num_bits - { - let num_bits = 6; - let shifted = pallas::Base::from((1 << num_bits) - 1); - // Recall that shifted = element * 2^{K-s} - // => element = shifted * 2^{s-K} - let element = shifted - * pallas::Base::from(1 << (K as u64 - num_bits)) - .invert() - .unwrap(); - let circuit: MyCircuit = MyCircuit { - element: Value::known(element), - num_bits: num_bits as usize, - }; - let prover = MockProver::::run(11, &circuit, vec![]).unwrap(); - assert_eq!( - prover.verify(), - Err(vec![VerifyFailure::Lookup { - name: "lookup", - lookup_index: 0, - location: FailureLocation::InRegion { - region: (1, "Range check 6 bits").into(), - offset: 0, - }, - }]) - ); - } - } -} diff --git a/halo2_proofs/Cargo.toml b/halo2_proofs/Cargo.toml index abf200061a..9d4535d4d5 100644 --- a/halo2_proofs/Cargo.toml +++ b/halo2_proofs/Cargo.toml @@ -23,35 +23,36 @@ keywords = ["halo", "proofs", "zkp", "zkSNARKs"] all-features = true rustdoc-args = ["--cfg", "docsrs", "--html-in-header", "katex-header.html"] -[[bench]] -name = "arithmetic" -harness = false - -[[bench]] -name = "hashtocurve" -harness = false - -[[bench]] -name = "plonk" -harness = false - -[[bench]] -name = "dev_lookup" -harness = false - -[[bench]] -name = "fft" -harness = false +# [[bench]] +# name = "arithmetic" +# harness = false +# +# [[bench]] +# name = "hashtocurve" +# harness = false +# +# [[bench]] +# name = "plonk" +# harness = false +# +# [[bench]] +# name = "dev_lookup" +# harness = false +# +# [[bench]] +# name = "fft" +# harness = false [dependencies] backtrace = { version = "0.3", optional = true } rayon = "1.5.1" ff = "0.12" group = "0.12" -halo2curves = { git = 'https://github.com/privacy-scaling-explorations/halo2curves', tag = '0.3.0' } +halo2curves = { path = "../arithmetic/curves" } rand_core = { version = "0.6", default-features = false } tracing = "0.1" blake2b_simd = "1" +rustc-hash = "1.1.0" # Developer tooling dependencies plotters = { version = "0.3.0", optional = true } @@ -73,6 +74,7 @@ dev-graph = ["plotters", "tabbycat"] gadget-traces = ["backtrace"] sanity-checks = [] batch = ["rand_core/getrandom"] +profile = [] [lib] bench = false diff --git a/halo2_proofs/benches/dev_lookup.rs b/halo2_proofs/benches/dev_lookup.rs index bb6cfdadbf..2c86fc6766 100644 --- a/halo2_proofs/benches/dev_lookup.rs +++ b/halo2_proofs/benches/dev_lookup.rs @@ -77,10 +77,10 @@ fn criterion_benchmark(c: &mut Criterion) { for offset in 0u64..(1 << 10) { config.selector.enable(&mut region, offset as usize)?; region.assign_advice( - || format!("offset {}", offset), + // || format!("offset {}", offset), config.advice, offset as usize, - || Value::known(F::from((offset % 256) + 1)), + Value::known(F::from((offset % 256) + 1)), )?; } diff --git a/halo2_proofs/examples/serialization.rs b/halo2_proofs/examples/serialization.rs index fbd19a89b4..49474f924e 100644 --- a/halo2_proofs/examples/serialization.rs +++ b/halo2_proofs/examples/serialization.rs @@ -21,6 +21,7 @@ use halo2_proofs::{ transcript::{ Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, }, + SerdeFormat, }; use halo2curves::bn256::{Bn256, Fr, G1Affine}; use rand_core::OsRng; @@ -102,10 +103,10 @@ impl Circuit for StandardPlonk { layouter.assign_region( || "", |mut region| { - region.assign_advice(|| "", config.a, 0, || Value::known(self.0))?; - region.assign_fixed(|| "", config.q_a, 0, || Value::known(-Fr::one()))?; + region.assign_advice(config.a, 0, Value::known(self.0))?; + region.assign_fixed(config.q_a, 0, -Fr::one()); - region.assign_advice(|| "", config.a, 1, || Value::known(-Fr::from(5u64)))?; + region.assign_advice(config.a, 1, Value::known(-Fr::from(5u64)))?; for (idx, column) in (1..).zip([ config.q_a, config.q_b, @@ -113,12 +114,12 @@ impl Circuit for StandardPlonk { config.q_ab, config.constant, ]) { - region.assign_fixed(|| "", column, 1, || Value::known(Fr::from(idx as u64)))?; + region.assign_fixed(column, 1, Fr::from(idx as u64)); } - let a = region.assign_advice(|| "", config.a, 2, || Value::known(Fr::one()))?; - a.copy_advice(|| "", &mut region, config.b, 3)?; - a.copy_advice(|| "", &mut region, config.c, 4)?; + let a = region.assign_advice(config.a, 2, Value::known(Fr::one()))?; + a.copy_advice(&mut region, config.b, 3); + a.copy_advice(&mut region, config.c, 4); Ok(()) }, ) @@ -134,12 +135,13 @@ fn main() { let f = File::create("serialization-test.pk").unwrap(); let mut writer = BufWriter::new(f); - pk.write(&mut writer).unwrap(); + pk.write(&mut writer, SerdeFormat::RawBytes).unwrap(); writer.flush().unwrap(); let f = File::open("serialization-test.pk").unwrap(); let mut reader = BufReader::new(f); - let pk = ProvingKey::::read::<_, StandardPlonk>(&mut reader, ¶ms).unwrap(); + let pk = ProvingKey::::read::<_, StandardPlonk>(&mut reader, SerdeFormat::RawBytes) + .unwrap(); std::fs::remove_file("serialization-test.pk").unwrap(); diff --git a/halo2_proofs/examples/shuffle.rs b/halo2_proofs/examples/shuffle.rs index 1926074371..71ba001848 100644 --- a/halo2_proofs/examples/shuffle.rs +++ b/halo2_proofs/examples/shuffle.rs @@ -1,7 +1,7 @@ use ff::BatchInvert; use halo2_proofs::{ arithmetic::{CurveAffine, FieldExt}, - circuit::{floor_planner::V1, Layouter, Value}, + circuit::{Layouter, SimpleFloorPlanner, Value}, dev::{metadata, FailureLocation, MockProver, VerifyFailure}, halo2curves::pasta::EqAffine, plonk::*, @@ -137,7 +137,7 @@ impl MyCircuit { impl Circuit for MyCircuit { type Config = MyConfig; - type FloorPlanner = V1; + type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { Self::default() @@ -152,9 +152,7 @@ impl Circuit for MyCircuit, ) -> Result<(), Error> { - let theta = layouter.get_challenge(config.theta); - let gamma = layouter.get_challenge(config.gamma); - + println!("Calling synthesize function"); layouter.assign_region( || "Shuffle original into shuffled", |mut region| { @@ -174,10 +172,8 @@ impl Circuit for MyCircuit Circuit for MyCircuit Circuit for MyCircuit( let proof = { let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); + println!("Begin create proof"); create_proof::, ProverIPA, _, _, _, _>( ¶ms, &pk, @@ -301,6 +298,7 @@ fn test_prover( &mut transcript, ) .expect("proof generation should not fail"); + println!("End create proof"); transcript.finalize() }; diff --git a/halo2_proofs/examples/simple-example.rs b/halo2_proofs/examples/simple-example.rs index c5e7a9f282..3531511f8f 100644 --- a/halo2_proofs/examples/simple-example.rs +++ b/halo2_proofs/examples/simple-example.rs @@ -226,7 +226,8 @@ impl NumericInstructions for FieldChip { ) -> Result<(), Error> { let config = self.config(); - layouter.constrain_instance(num.0.cell(), config.instance, row) + layouter.constrain_instance(num.0.cell(), config.instance, row); + Ok(()) } } // ANCHOR_END: instructions-impl diff --git a/halo2_proofs/src/circuit.rs b/halo2_proofs/src/circuit.rs index 0f0646fa85..294a636940 100644 --- a/halo2_proofs/src/circuit.rs +++ b/halo2_proofs/src/circuit.rs @@ -90,13 +90,24 @@ impl std::ops::Deref for RegionStart { #[derive(Clone, Copy, Debug)] pub struct Cell { /// Identifies the region in which this cell resides. - region_index: RegionIndex, + // region_index: RegionIndex, /// The relative offset of this cell within its region. row_offset: usize, /// The column of this cell. column: Column, } +impl Cell { + /// Returns row offset + pub fn row_offset(&self) -> usize { + self.row_offset + } + /// Returns reference to column + pub fn column(&self) -> &Column { + &self.column + } +} + /// An assigned cell. #[derive(Clone, Debug)] pub struct AssignedCell { @@ -112,8 +123,16 @@ impl AssignedCell { } /// Returns the cell. - pub fn cell(&self) -> Cell { - self.cell + pub fn cell(&self) -> &Cell { + &self.cell + } + + pub fn row_offset(&self) -> usize { + self.cell.row_offset + } + + pub fn column(&self) -> &Column { + &self.cell.column } } @@ -141,30 +160,22 @@ impl AssignedCell, F> { } } -impl AssignedCell -where - for<'v> Assigned: From<&'v V>, -{ +impl<'v, F: Field> AssignedCell<&'v Assigned, F> { /// Copies the value to a given advice cell and constrains them to be equal. /// /// Returns an error if either this cell or the given cell are in columns /// where equality has not been enabled. - pub fn copy_advice( + pub fn copy_advice( &self, - annotation: A, region: &mut Region<'_, F>, column: Column, offset: usize, - ) -> Result - where - A: Fn() -> AR, - AR: Into, - { - let assigned_cell = - region.assign_advice(annotation, column, offset, || self.value.clone())?; - region.constrain_equal(assigned_cell.cell(), self.cell())?; - - Ok(assigned_cell) + ) -> AssignedCell<&'_ Assigned, F> { + let assigned_cell = region + .assign_advice(column, offset, self.value.map(|v| *v)) + .unwrap_or_else(|err| panic!("{err:?}")); + region.constrain_equal(&assigned_cell.cell, &self.cell); + assigned_cell } } @@ -209,34 +220,30 @@ impl<'r, F: Field> Region<'r, F> { /// Assign an advice column value (witness). /// /// Even though `to` has `FnMut` bounds, it is guaranteed to be called at most once. - pub fn assign_advice<'v, V, VR, A, AR>( - &'v mut self, - annotation: A, + // The returned &'v Assigned lives longer than the mutable borrow of &mut self + pub fn assign_advice<'v>( + //, V, VR, A, AR>( + &mut self, + //annotation: A, column: Column, offset: usize, - mut to: V, - ) -> Result, Error> - where - V: FnMut() -> Value + 'v, - for<'vr> Assigned: From<&'vr VR>, - A: Fn() -> AR, - AR: Into, - { - let mut value = Value::unknown(); - let cell = - self.region - .assign_advice(&|| annotation().into(), column, offset, &mut || { - let v = to(); - let value_f = v.to_field(); - value = v; - value_f - })?; + to: Value>>, // For now only accept Value, later might change to Value> for batch inversion + ) -> Result, F>, Error> { + //let mut value = Value::unknown(); + self.region.assign_advice( + //&|| annotation().into(), + column, + offset, + to.map(|v| v.into()), + ) + /* Ok(AssignedCell { value, cell, _marker: PhantomData, }) + */ } /// Assigns a constant value to the column `advice` at `offset` within this region. @@ -305,34 +312,21 @@ impl<'r, F: Field> Region<'r, F> { /// Assign a fixed value. /// /// Even though `to` has `FnMut` bounds, it is guaranteed to be called at most once. - pub fn assign_fixed<'v, V, VR, A, AR>( - &'v mut self, - annotation: A, + pub fn assign_fixed( + &mut self, + // annotation: A, column: Column, offset: usize, - mut to: V, - ) -> Result, Error> - where - V: FnMut() -> Value + 'v, - for<'vr> Assigned: From<&'vr VR>, - A: Fn() -> AR, - AR: Into, - { - let mut value = Value::unknown(); - let cell = - self.region - .assign_fixed(&|| annotation().into(), column, offset, &mut || { - let v = to(); - let value_f = v.to_field(); - value = v; - value_f - })?; - + to: impl Into>, + ) -> Cell { + self.region.assign_fixed(column, offset, to.into()) + /* Ok(AssignedCell { value, cell, _marker: PhantomData, }) + */ } /// Constrains a cell to have a constant value. @@ -349,8 +343,21 @@ impl<'r, F: Field> Region<'r, F> { /// /// Returns an error if either of the cells are in columns where equality /// has not been enabled. - pub fn constrain_equal(&mut self, left: Cell, right: Cell) -> Result<(), Error> { - self.region.constrain_equal(left, right) + pub fn constrain_equal(&mut self, left: &Cell, right: &Cell) { + self.region.constrain_equal(left, right); + } + + /// Queries the value of the given challenge. + /// + /// Returns `Value::unknown()` if the current synthesis phase is before the challenge can be queried. + pub fn get_challenge(&self, challenge: Challenge) -> Value { + self.region.get_challenge(challenge) + } + + /// Commit advice columns in current phase and squeeze challenges. + /// This can be called DURING synthesize. + pub fn next_phase(&mut self) { + self.region.next_phase(); } } @@ -416,7 +423,7 @@ pub trait Layouter { /// ``` fn assign_region(&mut self, name: N, assignment: A) -> Result where - A: FnMut(Region<'_, F>) -> Result, + A: FnOnce(Region<'_, F>) -> Result, N: Fn() -> NR, NR: Into; @@ -436,12 +443,7 @@ pub trait Layouter { /// Constrains a [`Cell`] to equal an instance column's row value at an /// absolute position. - fn constrain_instance( - &mut self, - cell: Cell, - column: Column, - row: usize, - ) -> Result<(), Error>; + fn constrain_instance(&mut self, cell: Cell, column: Column, row: usize); /// Queries the value of the given challenge. /// @@ -488,7 +490,7 @@ impl<'a, F: Field, L: Layouter + 'a> Layouter for NamespacedLayouter<'a, F fn assign_region(&mut self, name: N, assignment: A) -> Result where - A: FnMut(Region<'_, F>) -> Result, + A: FnOnce(Region<'_, F>) -> Result, N: Fn() -> NR, NR: Into, { @@ -504,13 +506,8 @@ impl<'a, F: Field, L: Layouter + 'a> Layouter for NamespacedLayouter<'a, F self.0.assign_table(name, assignment) } - fn constrain_instance( - &mut self, - cell: Cell, - column: Column, - row: usize, - ) -> Result<(), Error> { - self.0.constrain_instance(cell, column, row) + fn constrain_instance(&mut self, cell: Cell, column: Column, row: usize) { + self.0.constrain_instance(cell, column, row); } fn get_challenge(&self, challenge: Challenge) -> Value { diff --git a/halo2_proofs/src/circuit/floor_planner.rs b/halo2_proofs/src/circuit/floor_planner.rs index 1b629034e6..01c5415a30 100644 --- a/halo2_proofs/src/circuit/floor_planner.rs +++ b/halo2_proofs/src/circuit/floor_planner.rs @@ -2,5 +2,5 @@ pub(super) mod single_pass; -mod v1; -pub use v1::{V1Pass, V1}; +// mod v1; +//pub use v1::{V1Pass, V1}; diff --git a/halo2_proofs/src/circuit/floor_planner/single_pass.rs b/halo2_proofs/src/circuit/floor_planner/single_pass.rs index 3798efbe54..fc2aecdbcf 100644 --- a/halo2_proofs/src/circuit/floor_planner/single_pass.rs +++ b/halo2_proofs/src/circuit/floor_planner/single_pass.rs @@ -1,14 +1,14 @@ use std::cmp; -use std::collections::HashMap; use std::fmt; use std::marker::PhantomData; use ff::Field; +use rustc_hash::FxHashMap; use crate::{ circuit::{ layouter::{RegionColumn, RegionLayouter, RegionShape, TableLayouter}, - Cell, Layouter, Region, RegionIndex, RegionStart, Table, Value, + AssignedCell, Cell, Layouter, Region, RegionIndex, RegionStart, Table, Value, }, plonk::{ Advice, Any, Assigned, Assignment, Challenge, Circuit, Column, Error, Fixed, FloorPlanner, @@ -40,10 +40,11 @@ impl FloorPlanner for SimpleFloorPlanner { pub struct SingleChipLayouter<'a, F: Field, CS: Assignment + 'a> { cs: &'a mut CS, constants: Vec>, - /// Stores the starting row for each region. - regions: Vec, + // Stores the starting row for each region. + // Edit: modify to just one region with RegionStart(0) + // regions: Vec, /// Stores the first empty row for each column. - columns: HashMap, + columns: FxHashMap, /// Stores the table fixed columns. table_columns: Vec, _marker: PhantomData, @@ -52,7 +53,7 @@ pub struct SingleChipLayouter<'a, F: Field, CS: Assignment + 'a> { impl<'a, F: Field, CS: Assignment + 'a> fmt::Debug for SingleChipLayouter<'a, F, CS> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("SingleChipLayouter") - .field("regions", &self.regions) + //.field("regions", &self.regions) .field("columns", &self.columns) .finish() } @@ -64,8 +65,8 @@ impl<'a, F: Field, CS: Assignment> SingleChipLayouter<'a, F, CS> { let ret = SingleChipLayouter { cs, constants, - regions: vec![], - columns: HashMap::default(), + // regions: vec![], + columns: FxHashMap::default(), table_columns: vec![], _marker: PhantomData, }; @@ -76,12 +77,13 @@ impl<'a, F: Field, CS: Assignment> SingleChipLayouter<'a, F, CS> { impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a, F, CS> { type Root = Self; - fn assign_region(&mut self, name: N, mut assignment: A) -> Result + fn assign_region(&mut self, name: N, assignment: A) -> Result where - A: FnMut(Region<'_, F>) -> Result, + A: FnOnce(Region<'_, F>) -> Result, N: Fn() -> NR, NR: Into, { + /* let region_index = self.regions.len(); // Get shape of the region. @@ -93,20 +95,20 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a // Lay out this region. We implement the simplest approach here: position the // region starting at the earliest row for which none of the columns are in use. - let mut region_start = 0; + let region_start = 0; for column in &shape.columns { region_start = cmp::max(region_start, self.columns.get(column).cloned().unwrap_or(0)); } - self.regions.push(region_start.into()); + // self.regions.push(region_start.into()); // Update column usage information. for column in shape.columns { self.columns.insert(column, region_start + shape.row_count); - } + }*/ // Assign region cells. self.cs.enter_region(name); - let mut region = SingleChipLayouterRegion::new(self, region_index.into()); + let mut region = SingleChipLayouterRegion::new(self, 0.into()); //region_index.into()); let result = { let region: &mut dyn RegionLayouter = &mut region; assignment(region.into()) @@ -128,17 +130,17 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a .or_default(); for (constant, advice) in constants_to_assign { self.cs.assign_fixed( - || format!("Constant({:?})", constant.evaluate()), + //|| format!("Constant({:?})", constant.evaluate()), constants_column, *next_constant_row, - || Value::known(constant), - )?; + constant, + ); self.cs.copy( constants_column.into(), *next_constant_row, advice.column, - *self.regions[*advice.region_index] + advice.row_offset, - )?; + advice.row_offset, // *self.regions[*advice.region_index] + advice.row_offset, + ); *next_constant_row += 1; } } @@ -200,18 +202,13 @@ impl<'a, F: Field, CS: Assignment + 'a> Layouter for SingleChipLayouter<'a Ok(()) } - fn constrain_instance( - &mut self, - cell: Cell, - instance: Column, - row: usize, - ) -> Result<(), Error> { + fn constrain_instance(&mut self, cell: Cell, instance: Column, row: usize) { self.cs.copy( cell.column, - *self.regions[*cell.region_index] + cell.row_offset, + cell.row_offset, // *self.regions[*cell.region_index] + cell.row_offset, instance.into(), row, - ) + ); } fn get_challenge(&self, challenge: Challenge) -> Value { @@ -273,42 +270,45 @@ impl<'r, 'a, F: Field, CS: Assignment + 'a> RegionLayouter offset: usize, ) -> Result<(), Error> { self.layouter.cs.enable_selector( - annotation, - selector, - *self.layouter.regions[*self.region_index] + offset, + annotation, selector, + offset, // *self.layouter.regions[*self.region_index] + offset, ) } - fn assign_advice<'v>( - &'v mut self, - annotation: &'v (dyn Fn() -> String + 'v), + fn assign_advice<'b, 'v>( + &'b mut self, + // annotation: &'v (dyn Fn() -> String + 'v), column: Column, offset: usize, - to: &'v mut (dyn FnMut() -> Value> + 'v), - ) -> Result { - self.layouter.cs.assign_advice( - annotation, - column, - *self.layouter.regions[*self.region_index] + offset, + to: Value>, // &'v mut (dyn FnMut() -> Value> + 'v), + ) -> Result, F>, Error> { + let value = self.layouter.cs.assign_advice( + // annotation, + column, offset, //*self.layouter.regions[*self.region_index] + offset, to, )?; - Ok(Cell { - region_index: self.region_index, - row_offset: offset, - column: column.into(), + Ok(AssignedCell { + value, + cell: Cell { + // region_index: self.region_index, + row_offset: offset, + column: column.into(), + }, + _marker: PhantomData, }) } fn assign_advice_from_constant<'v>( &'v mut self, - annotation: &'v (dyn Fn() -> String + 'v), + _annotation: &'v (dyn Fn() -> String + 'v), column: Column, offset: usize, constant: Assigned, ) -> Result { - let advice = - self.assign_advice(annotation, column, offset, &mut || Value::known(constant))?; + let advice = self + .assign_advice(column, offset, Value::known(constant))? + .cell; self.constrain_constant(advice, constant)?; Ok(advice) @@ -316,7 +316,7 @@ impl<'r, 'a, F: Field, CS: Assignment + 'a> RegionLayouter fn assign_advice_from_instance<'v>( &mut self, - annotation: &'v (dyn Fn() -> String + 'v), + _annotation: &'v (dyn Fn() -> String + 'v), instance: Column, row: usize, advice: Column, @@ -324,37 +324,37 @@ impl<'r, 'a, F: Field, CS: Assignment + 'a> RegionLayouter ) -> Result<(Cell, Value), Error> { let value = self.layouter.cs.query_instance(instance, row)?; - let cell = self.assign_advice(annotation, advice, offset, &mut || value.to_field())?; + let cell = self + .assign_advice(advice, offset, value.map(|v| Assigned::Trivial(v)))? + .cell; self.layouter.cs.copy( cell.column, - *self.layouter.regions[*cell.region_index] + cell.row_offset, + cell.row_offset, // *self.layouter.regions[*cell.region_index] + cell.row_offset, instance.into(), row, - )?; + ); Ok((cell, value)) } - fn assign_fixed<'v>( - &'v mut self, - annotation: &'v (dyn Fn() -> String + 'v), + fn assign_fixed( + &mut self, + // annotation: &'v (dyn Fn() -> String + 'v), column: Column, offset: usize, - to: &'v mut (dyn FnMut() -> Value> + 'v), - ) -> Result { + to: Assigned, + ) -> Cell { self.layouter.cs.assign_fixed( - annotation, - column, - *self.layouter.regions[*self.region_index] + offset, + column, offset, // *self.layouter.regions[*self.region_index] + offset, to, - )?; + ); - Ok(Cell { - region_index: self.region_index, + Cell { + // region_index: self.region_index, row_offset: offset, column: column.into(), - }) + } } fn constrain_constant(&mut self, cell: Cell, constant: Assigned) -> Result<(), Error> { @@ -362,15 +362,21 @@ impl<'r, 'a, F: Field, CS: Assignment + 'a> RegionLayouter Ok(()) } - fn constrain_equal(&mut self, left: Cell, right: Cell) -> Result<(), Error> { + fn constrain_equal(&mut self, left: &Cell, right: &Cell) { self.layouter.cs.copy( left.column, - *self.layouter.regions[*left.region_index] + left.row_offset, + left.row_offset, // *self.layouter.regions[*left.region_index] + left.row_offset, right.column, - *self.layouter.regions[*right.region_index] + right.row_offset, - )?; + right.row_offset, // *self.layouter.regions[*right.region_index] + right.row_offset, + ); + } - Ok(()) + fn get_challenge(&self, challenge: Challenge) -> Value { + self.layouter.cs.get_challenge(challenge) + } + + fn next_phase(&mut self) { + self.layouter.cs.next_phase(); } } @@ -387,7 +393,7 @@ pub(crate) struct SimpleTableLayouter<'r, 'a, F: Field, CS: Assignment + 'a> cs: &'a mut CS, used_columns: &'r [TableColumn], // maps from a fixed column to a pair (default value, vector saying which rows are assigned) - pub(crate) default_and_assigned: HashMap, Vec)>, + pub(crate) default_and_assigned: FxHashMap, Vec)>, } impl<'r, 'a, F: Field, CS: Assignment + 'a> fmt::Debug for SimpleTableLayouter<'r, 'a, F, CS> { @@ -404,7 +410,7 @@ impl<'r, 'a, F: Field, CS: Assignment + 'a> SimpleTableLayouter<'r, 'a, F, CS SimpleTableLayouter { cs, used_columns, - default_and_assigned: HashMap::default(), + default_and_assigned: FxHashMap::default(), } } } @@ -414,7 +420,7 @@ impl<'r, 'a, F: Field, CS: Assignment + 'a> TableLayouter { fn assign_cell<'v>( &'v mut self, - annotation: &'v (dyn Fn() -> String + 'v), + _: &'v (dyn Fn() -> String + 'v), column: TableColumn, offset: usize, to: &'v mut (dyn FnMut() -> Value> + 'v), @@ -425,17 +431,17 @@ impl<'r, 'a, F: Field, CS: Assignment + 'a> TableLayouter let entry = self.default_and_assigned.entry(column).or_default(); - let mut value = Value::unknown(); + let value; self.cs.assign_fixed( - annotation, + // annotation, column.inner(), offset, // tables are always assigned starting at row 0 - || { + { let res = to(); value = res; - res + res.assign()? }, - )?; + ); match (entry.0.is_none(), offset) { // Use the value at offset 0 as the default value for this table column. diff --git a/halo2_proofs/src/circuit/floor_planner/v1.rs b/halo2_proofs/src/circuit/floor_planner/v1.rs index 62207a91a7..657b7f2636 100644 --- a/halo2_proofs/src/circuit/floor_planner/v1.rs +++ b/halo2_proofs/src/circuit/floor_planner/v1.rs @@ -66,6 +66,7 @@ impl FloorPlanner for V1 { let mut plan = V1Plan::new(cs)?; // First pass: measure the regions within the circuit. + println!("First pass: measure the regions within the circuit"); let mut measure = MeasurementPass::new(); { let pass = &mut measure; @@ -109,6 +110,7 @@ impl FloorPlanner for V1 { // Second pass: // - Assign the regions. + println!("Second pass: assign the regions"); let mut assign = AssignmentPass::new(&mut plan); { let pass = &mut assign; @@ -491,6 +493,14 @@ impl<'r, 'a, F: Field, CS: Assignment + 'a> RegionLayouter for V1Region<'r Ok(()) } + + fn get_challenge(&self, challenge: Challenge) -> Value { + self.plan.cs.get_challenge(challenge) + } + + fn next_phase(&mut self) -> Result<(), Error> { + self.plan.cs.next_phase() + } } #[cfg(test)] diff --git a/halo2_proofs/src/circuit/layouter.rs b/halo2_proofs/src/circuit/layouter.rs index 9436011fdc..ba4e585432 100644 --- a/halo2_proofs/src/circuit/layouter.rs +++ b/halo2_proofs/src/circuit/layouter.rs @@ -6,8 +6,10 @@ use std::fmt; use ff::Field; -use super::{Cell, RegionIndex, Value}; -use crate::plonk::{Advice, Any, Assigned, Column, Error, Fixed, Instance, Selector, TableColumn}; +use super::{AssignedCell, Cell, RegionIndex, Value}; +use crate::plonk::{ + Advice, Any, Assigned, Challenge, Column, Error, Fixed, Instance, Selector, TableColumn, +}; /// Helper trait for implementing a custom [`Layouter`]. /// @@ -49,13 +51,13 @@ pub trait RegionLayouter: fmt::Debug { ) -> Result<(), Error>; /// Assign an advice column value (witness) - fn assign_advice<'v>( - &'v mut self, - annotation: &'v (dyn Fn() -> String + 'v), + fn assign_advice<'b, 'v>( + &'b mut self, + // annotation: &'v (dyn Fn() -> String + 'v), column: Column, offset: usize, - to: &'v mut (dyn FnMut() -> Value> + 'v), - ) -> Result; + to: Value>, // &'v mut (dyn FnMut() -> Value> + 'v), + ) -> Result, F>, Error>; /// Assigns a constant value to the column `advice` at `offset` within this region. /// @@ -85,13 +87,13 @@ pub trait RegionLayouter: fmt::Debug { ) -> Result<(Cell, Value), Error>; /// Assign a fixed value - fn assign_fixed<'v>( - &'v mut self, - annotation: &'v (dyn Fn() -> String + 'v), + fn assign_fixed( + &mut self, + // annotation: &'v (dyn Fn() -> String + 'v), column: Column, offset: usize, - to: &'v mut (dyn FnMut() -> Value> + 'v), - ) -> Result; + to: Assigned, + ) -> Cell; /// Constrains a cell to have a constant value. /// @@ -101,7 +103,16 @@ pub trait RegionLayouter: fmt::Debug { /// Constraint two cells to have the same value. /// /// Returns an error if either of the cells is not within the given permutation. - fn constrain_equal(&mut self, left: Cell, right: Cell) -> Result<(), Error>; + fn constrain_equal(&mut self, left: &Cell, right: &Cell); + + /// Queries the value of the given challenge. + /// + /// Returns `Value::unknown()` if the current synthesis phase is before the challenge can be queried. + fn get_challenge(&self, challenge: Challenge) -> Value; + + /// Commit advice columns in current phase and squeeze challenges. + /// This can be called DURING synthesize. + fn next_phase(&mut self); } /// Helper trait for implementing a custom [`Layouter`]. @@ -125,6 +136,7 @@ pub trait TableLayouter: fmt::Debug { /// The shape of a region. For a region at a certain index, we track /// the set of columns it uses as well as the number of rows it uses. #[derive(Clone, Debug)] +#[allow(dead_code)] pub struct RegionShape { pub(super) region_index: RegionIndex, pub(super) columns: HashSet, @@ -170,6 +182,7 @@ impl PartialOrd for RegionColumn { } } +/* impl RegionShape { /// Create a new `RegionShape` for a region at `region_index`. pub fn new(region_index: RegionIndex) -> Self { @@ -211,11 +224,11 @@ impl RegionLayouter for RegionShape { fn assign_advice<'v>( &'v mut self, - _: &'v (dyn Fn() -> String + 'v), + //_: &'v (dyn Fn() -> String + 'v), column: Column, offset: usize, - _to: &'v mut (dyn FnMut() -> Value> + 'v), - ) -> Result { + _to: Value>, // &'v mut (dyn FnMut() -> Value> + 'v), + ) -> Result, F>, Error> { self.columns.insert(Column::::from(column).into()); self.row_count = cmp::max(self.row_count, offset + 1); @@ -223,7 +236,8 @@ impl RegionLayouter for RegionShape { region_index: self.region_index, row_offset: offset, column: column.into(), - }) + }); + todo!() } fn assign_advice_from_constant<'v>( @@ -234,7 +248,7 @@ impl RegionLayouter for RegionShape { constant: Assigned, ) -> Result { // The rest is identical to witnessing an advice cell. - self.assign_advice(annotation, column, offset, &mut || Value::known(constant)) + self.assign_advice(column, offset, Value::known(constant)) } fn assign_advice_from_instance<'v>( @@ -284,4 +298,14 @@ impl RegionLayouter for RegionShape { // Equality constraints don't affect the region shape. Ok(()) } + + fn get_challenge(&self, _: Challenge) -> Value { + Value::unknown() + } + + fn next_phase(&mut self) -> Result<(), Error> { + // Region shapes don't care about phases. + Ok(()) + } } +*/ diff --git a/halo2_proofs/src/dev.rs b/halo2_proofs/src/dev.rs index b5b92d390f..76f997d543 100644 --- a/halo2_proofs/src/dev.rs +++ b/halo2_proofs/src/dev.rs @@ -5,6 +5,7 @@ use std::collections::HashSet; use std::fmt; use std::iter; use std::ops::{Add, Mul, Neg, Range}; +use std::sync::Arc; use std::time::{Duration, Instant}; use blake2b_simd::blake2b; @@ -33,8 +34,8 @@ mod util; mod failure; pub use failure::{FailureLocation, VerifyFailure}; -pub mod cost; -pub use cost::CircuitCost; +//pub mod cost; +//pub use cost::CircuitCost; mod gates; pub use gates::CircuitGates; @@ -91,6 +92,15 @@ enum CellValue { Poison(usize), } +/// The value of a particular cell within the circuit. +#[derive(Clone, Debug, PartialEq, Eq)] +enum AdviceCellValue { + // A cell that has been assigned a value. + Assigned(Arc>), + // A unique poisoned cell. + Poison(usize), +} + /// A value within an expression. #[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd)] enum Value { @@ -291,7 +301,7 @@ pub struct MockProver { // The fixed cells in the circuit, arranged as [column][row]. fixed: Vec>>, // The advice cells in the circuit, arranged as [column][row]. - advice: Vec>>, + advice: Vec>>, // The instance cells in the circuit, arranged as [column][row]. instance: Vec>, @@ -365,19 +375,14 @@ impl Assignment for MockProver { .ok_or(Error::BoundsFailure) } - fn assign_advice( - &mut self, - _: A, + fn assign_advice<'r, 'v>( + //( + &'r mut self, + //_: A, column: Column, row: usize, - to: V, - ) -> Result<(), Error> - where - V: FnOnce() -> circuit::Value, - VR: Into>, - A: FnOnce() -> AR, - AR: Into, - { + to: circuit::Value>, + ) -> Result>, Error> { if !self.usable_rows.contains(&row) { return Err(Error::not_enough_rows_available(self.k)); } @@ -391,31 +396,22 @@ impl Assignment for MockProver { .or_default(); } - *self + let advice_get_mut = self .advice .get_mut(column.index()) .and_then(|v| v.get_mut(row)) - .ok_or(Error::BoundsFailure)? = - CellValue::Assigned(to().into_field().evaluate().assign()?); + .ok_or(Error::BoundsFailure)?; - Ok(()) + let val = Arc::new(to.assign()?); + let val_ref = Arc::downgrade(&val); + *advice_get_mut = AdviceCellValue::Assigned(val); + + Ok(circuit::Value::known(unsafe { &*val_ref.as_ptr() })) } - fn assign_fixed( - &mut self, - _: A, - column: Column, - row: usize, - to: V, - ) -> Result<(), Error> - where - V: FnOnce() -> circuit::Value, - VR: Into>, - A: FnOnce() -> AR, - AR: Into, - { + fn assign_fixed(&mut self, column: Column, row: usize, to: Assigned) { if !self.usable_rows.contains(&row) { - return Err(Error::not_enough_rows_available(self.k)); + panic!("{:?}", Error::not_enough_rows_available(self.k)); } if let Some(region) = self.current_region.as_mut() { @@ -431,10 +427,8 @@ impl Assignment for MockProver { .fixed .get_mut(column.index()) .and_then(|v| v.get_mut(row)) - .ok_or(Error::BoundsFailure)? = - CellValue::Assigned(to().into_field().evaluate().assign()?); - - Ok(()) + .unwrap_or_else(|| panic!("{:?}", Error::BoundsFailure)) = + CellValue::Assigned(to.evaluate()); } fn copy( @@ -443,13 +437,14 @@ impl Assignment for MockProver { left_row: usize, right_column: Column, right_row: usize, - ) -> Result<(), crate::plonk::Error> { + ) { if !self.usable_rows.contains(&left_row) || !self.usable_rows.contains(&right_row) { - return Err(Error::not_enough_rows_available(self.k)); + panic!("{:?}", Error::not_enough_rows_available(self.k)); } self.permutation .copy(left_column, left_row, right_column, right_row) + .unwrap_or_else(|err| panic!("{err:?}")) } fn fill_from_row( @@ -463,7 +458,7 @@ impl Assignment for MockProver { } for row in self.usable_rows.clone().skip(from_row) { - self.assign_fixed(|| "", col, row, || to)?; + self.assign_fixed(col, row, to.assign()?); } Ok(()) @@ -528,10 +523,13 @@ impl MockProver { let usable_rows = n - (blinding_factors + 1); let advice = vec![ { - let mut column = vec![CellValue::Unassigned; n]; + // let mut column = vec![AdviceCellValue::Unassigned; n]; + // Assign advice to 0 by default so we can have gates that query unassigned rotations to minimize number of distinct rotation sets, for SHPLONK optimization + let mut column = + vec![AdviceCellValue::Assigned(Arc::new(Assigned::Trivial(F::zero()))); n]; // Poison unusable rows. for (i, cell) in column.iter_mut().enumerate().skip(usable_rows) { - *cell = CellValue::Poison(i); + *cell = AdviceCellValue::Poison(i); } column }; @@ -612,6 +610,9 @@ impl MockProver { // Check that within each region, all cells used in instantiated gates have been // assigned to. + + // Turn off this check because we might query unassigned cells to increase the rotation set size of a gate (for SHPLONK optimization) + /* let selector_errors = self.regions.iter().enumerate().flat_map(|(r_i, r)| { r.enabled_selectors.iter().flat_map(move |(selector, at)| { // Find the gates enabled by this selector @@ -653,7 +654,26 @@ impl MockProver { }) }) }); + */ + let advice = self + .advice + .iter() + .map(|advice| { + advice + .iter() + .map(|rc| match *rc { + AdviceCellValue::Assigned(ref a) => CellValue::Assigned(match a.as_ref() { + Assigned::Trivial(a) => *a, + Assigned::Rational(a, b) => *a * b.invert().unwrap(), + _ => F::zero(), + }), + AdviceCellValue::Poison(i) => CellValue::Poison(i), + }) + .collect::>() + }) + .collect::>(); + let advice = &advice; // Check that all gates are satisfied for all rows. let gate_errors = self.cs @@ -674,7 +694,7 @@ impl MockProver { &|scalar| Value::Real(scalar), &|_| panic!("virtual selectors are removed during optimization"), &util::load(n, row, &self.cs.fixed_queries, &self.fixed), - &util::load(n, row, &self.cs.advice_queries, &self.advice), + &util::load(n, row, &self.cs.advice_queries, advice), &util::load_instance( n, row, @@ -706,7 +726,7 @@ impl MockProver { gate, poly, &util::load(n, row, &self.cs.fixed_queries, &self.fixed), - &util::load(n, row, &self.cs.advice_queries, &self.advice), + &util::load(n, row, &self.cs.advice_queries, advice), &util::load_instance( n, row, @@ -753,7 +773,7 @@ impl MockProver { let query = self.cs.advice_queries[query.index]; let column_index = query.0.index(); let rotation = query.1 .0; - self.advice[column_index] + advice[column_index] [(row as i32 + n + rotation) as usize % n as usize] .into() }, @@ -877,7 +897,7 @@ impl MockProver { .get_columns() .get(column) .map(|c: &Column| match c.column_type() { - Any::Advice(_) => self.advice[c.index()][row], + Any::Advice(_) => advice[c.index()][row], Any::Fixed => self.fixed[c.index()][row], Any::Instance => CellValue::Assigned(self.instance[c.index()][row]), }) @@ -914,7 +934,7 @@ impl MockProver { }; let mut errors: Vec<_> = iter::empty() - .chain(selector_errors) + //.chain(selector_errors) .chain(gate_errors) .chain(lookup_errors) .chain(perm_errors) @@ -1020,6 +1040,24 @@ impl MockProver { }) }); + let advice = self + .advice + .iter() + .map(|advice| { + advice + .iter() + .map(|rc| match *rc { + AdviceCellValue::Assigned(ref a) => CellValue::Assigned(match a.as_ref() { + Assigned::Trivial(a) => *a, + Assigned::Rational(a, b) => *a * b.invert().unwrap(), + _ => F::zero(), + }), + AdviceCellValue::Poison(i) => CellValue::Poison(i), + }) + .collect::>() + }) + .collect::>(); + let advice = &advice; // Check that all gates are satisfied for all rows. let gate_errors = self .cs @@ -1043,7 +1081,7 @@ impl MockProver { &|scalar| Value::Real(scalar), &|_| panic!("virtual selectors are removed during optimization"), &util::load(n, row, &self.cs.fixed_queries, &self.fixed), - &util::load(n, row, &self.cs.advice_queries, &self.advice), + &util::load(n, row, &self.cs.advice_queries, &advice), &util::load_instance( n, row, @@ -1075,7 +1113,7 @@ impl MockProver { gate, poly, &util::load(n, row, &self.cs.fixed_queries, &self.fixed), - &util::load(n, row, &self.cs.advice_queries, &self.advice), + &util::load(n, row, &self.cs.advice_queries, &advice), &util::load_instance( n, row, @@ -1118,7 +1156,7 @@ impl MockProver { .into() }, &|query| { - self.advice[query.column_index] + advice[query.column_index] [(row as i32 + n + query.rotation.0) as usize % n as usize] .into() }, @@ -1234,7 +1272,7 @@ impl MockProver { .get_columns() .get(column) .map(|c: &Column| match c.column_type() { - Any::Advice(_) => self.advice[c.index()][row], + Any::Advice(_) => advice[c.index()][row], Any::Fixed => self.fixed[c.index()][row], Any::Instance => CellValue::Assigned(self.instance[c.index()][row]), }) @@ -1315,6 +1353,27 @@ impl MockProver { panic!("circuit was not satisfied"); } } + + /// Panics if the circuit being checked by this `MockProver` is not satisfied. + /// + /// Any verification failures will be pretty-printed to stderr before the function + /// panics. + /// + /// Internally, this function uses a parallel aproach in order to verify the `MockProver` contents. + /// + /// Apart from the stderr output, this method is equivalent to: + /// ```ignore + /// assert_eq!(prover.verify_par(), Ok(())); + /// ``` + pub fn assert_satisfied_par(&self) { + if let Err(errs) = self.verify_par() { + for err in errs { + err.emit(self); + eprintln!(); + } + panic!("circuit was not satisfied"); + } + } } #[cfg(test)] @@ -1325,7 +1384,7 @@ mod tests { use crate::{ circuit::{Layouter, SimpleFloorPlanner, Value}, plonk::{ - Advice, Any, Circuit, Column, ConstraintSystem, Error, Expression, Selector, + Advice, Any, Assigned, Circuit, Column, ConstraintSystem, Error, Expression, Selector, TableColumn, }, poly::Rotation, @@ -1380,7 +1439,11 @@ mod tests { config.q.enable(&mut region, 1)?; // Assign a = 0. - region.assign_advice(|| "a", config.a, 0, || Value::known(Fp::zero()))?; + region.assign_advice( + /*|| "a",*/ config.a, + 0, + Value::known(Assigned::Trivial(Fp::zero())), + )?; // BUG: Forget to assign b = 0! This could go unnoticed during // development, because cell values default to zero, which in this @@ -1474,16 +1537,16 @@ mod tests { // Assign a = 2 and a = 6. region.assign_advice( - || "a = 2", + // || "a = 2", config.a, 0, - || Value::known(Fp::from(2)), + Value::known(Assigned::Trivial(Fp::from(2))), )?; region.assign_advice( - || "a = 6", + // || "a = 6", config.a, 1, - || Value::known(Fp::from(6)), + Value::known(Assigned::Trivial(Fp::from(6))), )?; Ok(()) @@ -1499,18 +1562,18 @@ mod tests { // Assign a = 4. region.assign_advice( - || "a = 4", + // || "a = 4", config.a, 0, - || Value::known(Fp::from(4)), + Value::known(Assigned::Trivial(Fp::from(4))), )?; // BUG: Assign a = 5, which doesn't exist in the table! region.assign_advice( - || "a = 5", + // || "a = 5", config.a, 1, - || Value::known(Fp::from(5)), + Value::known(Assigned::Trivial(Fp::from(5))), )?; Ok(()) diff --git a/halo2_proofs/src/dev/cost.rs b/halo2_proofs/src/dev/cost.rs index ad6f8b1eec..a47bdfe0fb 100644 --- a/halo2_proofs/src/dev/cost.rs +++ b/halo2_proofs/src/dev/cost.rs @@ -73,20 +73,20 @@ impl Assignment for Assembly { Ok(Value::unknown()) } - fn assign_advice( + fn assign_advice( + //( &mut self, - _: A, + //_: A, _: Column, _: usize, - _: V, - ) -> Result<(), Error> - where + to: Value>, + ) -> Result>, Error> +/*where V: FnOnce() -> Value, VR: Into>, A: FnOnce() -> AR, - AR: Into, - { - Ok(()) + AR: Into,*/ { + Ok(to.as_ref()) } fn assign_fixed( diff --git a/halo2_proofs/src/dev/failure.rs b/halo2_proofs/src/dev/failure.rs index c3c7ab93a9..89c0c05d95 100644 --- a/halo2_proofs/src/dev/failure.rs +++ b/halo2_proofs/src/dev/failure.rs @@ -10,6 +10,8 @@ use super::{ util::{self, AnyQuery}, MockProver, Region, }; +use crate::dev::{AdviceCellValue, CellValue}; +use crate::plonk::Assigned; use crate::{ dev::Value, plonk::{Any, Column, ConstraintSystem, Expression, Gate}, @@ -90,6 +92,9 @@ impl FailureLocation { .iter() .enumerate() .find(|(_, r)| { + if r.rows.is_none() { + return false; + } let (start, end) = r.rows.unwrap(); // We match the region if any input columns overlap, rather than all of // them, because matching complex selector columns is hard. As long as @@ -398,18 +403,18 @@ fn render_lookup( // Recover the fixed columns from the table expressions. We don't allow composite // expressions for the table side of lookups. - let table_columns = lookup.table_expressions.iter().map(|expr| { + let lookup_columns = lookup.table_expressions.iter().map(|expr| { expr.evaluate( &|_| panic!("no constants in table expressions"), &|_| panic!("no selectors in table expressions"), &|query| format!("F{}", query.column_index), - &|_| panic!("no advice columns in table expressions"), - &|_| panic!("no instance columns in table expressions"), - &|_| panic!("no challenges in table expressions"), - &|_| panic!("no negations in table expressions"), - &|_, _| panic!("no sums in table expressions"), - &|_, _| panic!("no products in table expressions"), - &|_, _| panic!("no scaling in table expressions"), + &|query| format! {"A{}", query.column_index}, + &|query| format! {"I{}", query.column_index}, + &|challenge| format! {"C{}", challenge.index()}, + &|query| format! {"-{}", query}, + &|a, b| format! {"{} + {}", a,b}, + &|a, b| format! {"{} * {}", a,b}, + &|a, b| format! {"{} * {:?}", a, b}, ) }); @@ -441,20 +446,36 @@ fn render_lookup( eprint!("{}L{}", if i == 0 { "" } else { ", " }, i); } eprint!(") ∉ ("); - for (i, column) in table_columns.enumerate() { + for (i, column) in lookup_columns.enumerate() { eprint!("{}{}", if i == 0 { "" } else { ", " }, column); } eprintln!(")"); eprintln!(); eprintln!(" Lookup '{}' inputs:", name); + let advice = prover + .advice + .iter() + .map(|advice| { + advice + .iter() + .map(|rc| match rc { + AdviceCellValue::Assigned(a) => CellValue::Assigned(match a.as_ref() { + Assigned::Trivial(a) => *a, + _ => unreachable!(), + }), + AdviceCellValue::Poison(i) => CellValue::Poison(*i), + }) + .collect::>() + }) + .collect::>(); for (i, input) in lookup.input_expressions.iter().enumerate() { // Fetch the cell values (since we don't store them in VerifyFailure::Lookup). let cell_values = input.evaluate( &|_| BTreeMap::default(), &|_| panic!("virtual selectors are removed during optimization"), &cell_value(&util::load(n, row, &cs.fixed_queries, &prover.fixed)), - &cell_value(&util::load(n, row, &cs.advice_queries, &prover.advice)), + &cell_value(&util::load(n, row, &cs.advice_queries, &advice)), &cell_value(&util::load_instance( n, row, diff --git a/halo2_proofs/src/dev/failure/emitter.rs b/halo2_proofs/src/dev/failure/emitter.rs index 0e792367c7..91525a20aa 100644 --- a/halo2_proofs/src/dev/failure/emitter.rs +++ b/halo2_proofs/src/dev/failure/emitter.rs @@ -120,16 +120,17 @@ pub(super) fn expression_to_string( &|query| { layout .get(&query.rotation.0) - .unwrap() - .get( - &( - Any::Advice(Advice { phase: query.phase }), - query.column_index, + .and_then(|map| { + map.get( + &( + Any::Advice(Advice { phase: query.phase }), + query.column_index, + ) + .into(), ) - .into(), - ) - .unwrap() - .clone() + }) + .cloned() + .unwrap_or_default() }, &|query| { layout diff --git a/halo2_proofs/src/helpers.rs b/halo2_proofs/src/helpers.rs index f601eab984..8eba57359b 100644 --- a/halo2_proofs/src/helpers.rs +++ b/halo2_proofs/src/helpers.rs @@ -1,8 +1,25 @@ use crate::poly::Polynomial; use ff::PrimeField; -use halo2curves::CurveAffine; +use halo2curves::{pairing::Engine, serde::SerdeObject, CurveAffine}; use std::io; +/// This enum specifies how various types are serialized and deserialized. +#[derive(Clone, Copy, Debug)] +pub enum SerdeFormat { + /// Curve elements are serialized in compressed form. + /// Field elements are serialized in standard form, with endianness specified by the + /// `PrimeField` implementation. + Processed, + /// Curve elements are serialized in uncompressed form. Field elements are serialized + /// in their internal Montgomery representation. + /// When deserializing, checks are performed to ensure curve elements indeed lie on the curve and field elements + /// are less than modulus. + RawBytes, + /// Serialization is the same as `RawBytes`, but no checks are performed. + RawBytesUnchecked, +} + +// Keep this trait for compatibility with IPA serialization pub(crate) trait CurveRead: CurveAffine { /// Reads a compressed element from the buffer and attempts to parse it /// using `from_bytes`. @@ -13,28 +30,67 @@ pub(crate) trait CurveRead: CurveAffine { .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Invalid point encoding in proof")) } } - impl CurveRead for C {} -pub(crate) trait SerdePrimeField: PrimeField { - /// Reads a field element as bytes from the buffer using `from_repr`. - /// Endianness is specified by `PrimeField` implementation. - fn read(reader: &mut R) -> io::Result { - let mut compressed = Self::Repr::default(); - reader.read_exact(compressed.as_mut())?; - Option::from(Self::from_repr(compressed)).ok_or_else(|| { - io::Error::new(io::ErrorKind::Other, "Invalid prime field point encoding") - }) +pub trait SerdeCurveAffine: CurveAffine + SerdeObject { + /// Reads an element from the buffer and parses it according to the `format`: + /// - `Processed`: Reads a compressed curve element and decompress it + /// - `RawBytes`: Reads an uncompressed curve element with coordinates in Montgomery form. + /// Checks that field elements are less than modulus, and then checks that the point is on the curve. + /// - `RawBytesUnchecked`: Reads an uncompressed curve element with coordinates in Montgomery form; + /// does not perform any checks + fn read(reader: &mut R, format: SerdeFormat) -> Self { + match format { + SerdeFormat::Processed => ::read(reader).unwrap(), + SerdeFormat::RawBytes => ::read_raw(reader).unwrap(), + SerdeFormat::RawBytesUnchecked => ::read_raw_unchecked(reader), + } } - - /// Writes a field element as bytes to the buffer using `to_repr`. - /// Endianness is specified by `PrimeField` implementation. - fn write(&self, writer: &mut W) -> io::Result<()> { - writer.write_all(self.to_repr().as_ref()) + /// Writes a curve element according to `format`: + /// - `Processed`: Writes a compressed curve element + /// - Otherwise: Writes an uncompressed curve element with coordinates in Montgomery form + fn write(&self, writer: &mut W, format: SerdeFormat) { + match format { + SerdeFormat::Processed => writer.write_all(self.to_bytes().as_ref()).unwrap(), + _ => self.write_raw(writer).unwrap(), + } } } +impl SerdeCurveAffine for C {} + +pub trait SerdePrimeField: PrimeField + SerdeObject { + /// Reads a field element as bytes from the buffer according to the `format`: + /// - `Processed`: Reads a field element in standard form, with endianness specified by the + /// `PrimeField` implementation, and checks that the element is less than the modulus. + /// - `RawBytes`: Reads a field element from raw bytes in its internal Montgomery representations, + /// and checks that the element is less than the modulus. + /// - `RawBytesUnchecked`: Reads a field element in Montgomery form and performs no checks. + fn read(reader: &mut R, format: SerdeFormat) -> Self { + match format { + SerdeFormat::Processed => { + let mut compressed = Self::Repr::default(); + reader.read_exact(compressed.as_mut()).unwrap(); + Option::from(Self::from_repr(compressed)) + .unwrap_or_else(|| panic!("Invalid prime field point encoding")) + } + SerdeFormat::RawBytes => ::read_raw(reader).unwrap(), + SerdeFormat::RawBytesUnchecked => ::read_raw_unchecked(reader), + } + } -impl SerdePrimeField for F {} + /// Writes a field element as bytes to the buffer according to the `format`: + /// - `Processed`: Writes a field element in standard form, with endianness specified by the + /// `PrimeField` implementation. + /// - Otherwise: Writes a field element into raw bytes in its internal Montgomery representation, + /// WITHOUT performing the expensive Montgomery reduction. + fn write(&self, writer: &mut W, format: SerdeFormat) { + match format { + SerdeFormat::Processed => writer.write_all(self.to_repr().as_ref()).unwrap(), + _ => self.write_raw(writer).unwrap(), + } + } +} +impl SerdePrimeField for F {} /// Convert a slice of `bool` into a `u8`. /// @@ -56,28 +112,31 @@ pub fn unpack(byte: u8, bits: &mut [bool]) { } /// Reads a vector of polynomials from buffer -pub(crate) fn read_polynomial_vec( +pub(crate) fn read_polynomial_vec( reader: &mut R, -) -> io::Result>> { - let mut len_be_bytes = [0u8; 4]; - reader.read_exact(&mut len_be_bytes)?; - let len = u32::from_be_bytes(len_be_bytes); + format: SerdeFormat, +) -> Vec> { + let mut len = [0u8; 4]; + reader.read_exact(&mut len).unwrap(); + let len = u32::from_be_bytes(len); (0..len) - .map(|_| Polynomial::::read(reader)) - .collect::>>() + .map(|_| Polynomial::::read(reader, format)) + .collect() } /// Writes a slice of polynomials to buffer -pub(crate) fn write_polynomial_slice( +pub(crate) fn write_polynomial_slice( slice: &[Polynomial], writer: &mut W, -) -> io::Result<()> { - writer.write_all(&(slice.len() as u32).to_be_bytes())?; + format: SerdeFormat, +) { + writer + .write_all(&(slice.len() as u32).to_be_bytes()) + .unwrap(); for poly in slice.iter() { - poly.write(writer)?; + poly.write(writer, format); } - Ok(()) } /// Gets the total number of bytes of a slice of polynomials, assuming all polynomials are the same length diff --git a/halo2_proofs/src/lib.rs b/halo2_proofs/src/lib.rs index c84e482675..c4ff31da1a 100644 --- a/halo2_proofs/src/lib.rs +++ b/halo2_proofs/src/lib.rs @@ -19,8 +19,8 @@ )] #![deny(broken_intra_doc_links)] #![deny(missing_debug_implementations)] -#![deny(missing_docs)] -#![deny(unsafe_code)] +// #![deny(missing_docs)] +// #![deny(unsafe_code)] // Remove this once we update pasta_curves #![allow(unused_imports)] #![allow(clippy::derive_partial_eq_without_eq)] @@ -35,3 +35,4 @@ pub mod transcript; pub mod dev; mod helpers; +pub use helpers::SerdeFormat; diff --git a/halo2_proofs/src/plonk.rs b/halo2_proofs/src/plonk.rs index 70ae557eed..e40d3deca2 100644 --- a/halo2_proofs/src/plonk.rs +++ b/halo2_proofs/src/plonk.rs @@ -11,7 +11,7 @@ use group::ff::Field; use crate::arithmetic::{CurveAffine, FieldExt}; use crate::helpers::{ - polynomial_slice_byte_length, read_polynomial_vec, write_polynomial_slice, CurveRead, + polynomial_slice_byte_length, read_polynomial_vec, write_polynomial_slice, SerdeCurveAffine, SerdePrimeField, }; use crate::poly::{ @@ -19,6 +19,7 @@ use crate::poly::{ PinnedEvaluationDomain, Polynomial, }; use crate::transcript::{ChallengeScalar, EncodedChallenge, Transcript}; +use crate::SerdeFormat; mod assigned; mod circuit; @@ -57,54 +58,79 @@ pub struct VerifyingKey { selectors: Vec>, } -impl VerifyingKey { +impl VerifyingKey +where + C::Scalar: SerdePrimeField, +{ /// Writes a verifying key to a buffer. - pub fn write(&self, writer: &mut W) -> io::Result<()> { - writer.write_all(&(self.fixed_commitments.len() as u32).to_be_bytes())?; + /// + /// Writes a curve element according to `format`: + /// - `Processed`: Writes a compressed curve element with coordinates in standard form. + /// Writes a field element in standard form, with endianness specified by the + /// `PrimeField` implementation. + /// - Otherwise: Writes an uncompressed curve element with coordinates in Montgomery form + /// Writes a field element into raw bytes in its internal Montgomery representation, + /// WITHOUT performing the expensive Montgomery reduction. + pub fn write(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> { + writer.write_all(&self.domain.k().to_be_bytes()).unwrap(); + writer + .write_all(&(self.fixed_commitments.len() as u32).to_be_bytes()) + .unwrap(); for commitment in &self.fixed_commitments { - writer.write_all(commitment.to_bytes().as_ref())?; + commitment.write(writer, format); } - self.permutation.write(writer)?; + self.permutation.write(writer, format); // write self.selectors for selector in &self.selectors { // since `selector` is filled with `bool`, we pack them 8 at a time into bytes and then write for bits in selector.chunks(8) { - writer.write_all(&[crate::helpers::pack(bits)])?; + writer.write_all(&[crate::helpers::pack(bits)]).unwrap(); } } Ok(()) } /// Reads a verification key from a buffer. - pub fn read<'params, R: io::Read, ConcreteCircuit: Circuit>( + /// + /// Reads a curve element from the buffer and parses it according to the `format`: + /// - `Processed`: Reads a compressed curve element and decompresses it. + /// Reads a field element in standard form, with endianness specified by the + /// `PrimeField` implementation, and checks that the element is less than the modulus. + /// - `RawBytes`: Reads an uncompressed curve element with coordinates in Montgomery form. + /// Checks that field elements are less than modulus, and then checks that the point is on the curve. + /// - `RawBytesUnchecked`: Reads an uncompressed curve element with coordinates in Montgomery form; + /// does not perform any checks + pub fn read>( reader: &mut R, - params: &impl Params<'params, C>, + format: SerdeFormat, ) -> io::Result { - let (domain, cs, _) = keygen::create_domain::(params.k()); - let mut num_fixed_columns_be_bytes = [0u8; 4]; - reader.read_exact(&mut num_fixed_columns_be_bytes)?; - let num_fixed_columns = u32::from_be_bytes(num_fixed_columns_be_bytes); + let mut k = [0u8; 4]; + reader.read_exact(&mut k)?; + let k = u32::from_be_bytes(k); + let (domain, cs, _) = keygen::create_domain::(k); + let mut num_fixed_columns = [0u8; 4]; + reader.read_exact(&mut num_fixed_columns).unwrap(); + let num_fixed_columns = u32::from_be_bytes(num_fixed_columns); let fixed_commitments: Vec<_> = (0..num_fixed_columns) - .map(|_| C::read(reader)) - .collect::>()?; + .map(|_| C::read(reader, format)) + .collect(); - let permutation = permutation::VerifyingKey::read(reader, &cs.permutation)?; + let permutation = permutation::VerifyingKey::read(reader, &cs.permutation, format); // read selectors - let selectors: Vec> = vec![vec![false; params.n() as usize]; cs.num_selectors] + let selectors: Vec> = vec![vec![false; 1 << k]; cs.num_selectors] .into_iter() .map(|mut selector| { let mut selector_bytes = vec![0u8; (selector.len() + 7) / 8]; - reader.read_exact(&mut selector_bytes)?; + reader.read_exact(&mut selector_bytes).unwrap(); for (bits, byte) in selector.chunks_mut(8).into_iter().zip(selector_bytes) { crate::helpers::unpack(byte, bits); } - Ok(selector) + selector }) - .collect::>>>() - .unwrap(); + .collect(); let (cs, _) = cs.compress_selectors(selectors.clone()); Ok(Self::from_parts( @@ -116,23 +142,25 @@ impl VerifyingKey { )) } - /// Writes a verifying key to a vector of bytes. - pub fn to_bytes(&self) -> Vec { + /// Writes a verifying key to a vector of bytes using [`Self::write`]. + pub fn to_bytes(&self, format: SerdeFormat) -> Vec { let mut bytes = Vec::::with_capacity(self.bytes_length()); - Self::write(self, &mut bytes).expect("Writing to vector should not fail"); + Self::write(self, &mut bytes, format).expect("Writing to vector should not fail"); bytes } - /// Reads a verification key from a slice of bytes. - pub fn from_bytes<'params, ConcreteCircuit: Circuit>( + /// Reads a verification key from a slice of bytes using [`Self::read`]. + pub fn from_bytes>( mut bytes: &[u8], - params: &impl Params<'params, C>, + format: SerdeFormat, ) -> io::Result { - Self::read::<_, ConcreteCircuit>(&mut bytes, params) + Self::read::<_, ConcreteCircuit>(&mut bytes, format) } +} +impl VerifyingKey { fn bytes_length(&self) -> usize { - 4 + (self.fixed_commitments.len() * C::default().to_bytes().as_ref().len()) + 8 + (self.fixed_commitments.len() * C::default().to_bytes().as_ref().len()) + self.permutation.bytes_length() + self.selectors.len() * (self @@ -251,34 +279,68 @@ impl ProvingKey { &self.vk } + /// Gets the total number of bytes in the serialization of `self` + fn bytes_length(&self) -> usize { + let scalar_len = C::Scalar::default().to_repr().as_ref().len(); + self.vk.bytes_length() + + 12 + + scalar_len * (self.l0.len() + self.l_last.len() + self.l_active_row.len()) + + polynomial_slice_byte_length(&self.fixed_values) + + polynomial_slice_byte_length(&self.fixed_polys) + + polynomial_slice_byte_length(&self.fixed_cosets) + + self.permutation.bytes_length() + } +} + +impl ProvingKey +where + C::Scalar: SerdePrimeField, +{ /// Writes a proving key to a buffer. + /// + /// Writes a curve element according to `format`: + /// - `Processed`: Writes a compressed curve element with coordinates in standard form. + /// Writes a field element in standard form, with endianness specified by the + /// `PrimeField` implementation. + /// - Otherwise: Writes an uncompressed curve element with coordinates in Montgomery form + /// Writes a field element into raw bytes in its internal Montgomery representation, + /// WITHOUT performing the expensive Montgomery reduction. /// Does so by first writing the verifying key and then serializing the rest of the data (in the form of field polynomials) - pub fn write(&self, writer: &mut W) -> io::Result<()> { - self.vk.write(writer)?; - self.l0.write(writer)?; - self.l_last.write(writer)?; - self.l_active_row.write(writer)?; - write_polynomial_slice(&self.fixed_values, writer)?; - write_polynomial_slice(&self.fixed_polys, writer)?; - write_polynomial_slice(&self.fixed_cosets, writer)?; - self.permutation.write(writer)?; + pub fn write(&self, writer: &mut W, format: SerdeFormat) -> io::Result<()> { + self.vk.write(writer, format).unwrap(); + self.l0.write(writer, format); + self.l_last.write(writer, format); + self.l_active_row.write(writer, format); + write_polynomial_slice(&self.fixed_values, writer, format); + write_polynomial_slice(&self.fixed_polys, writer, format); + write_polynomial_slice(&self.fixed_cosets, writer, format); + self.permutation.write(writer, format); Ok(()) } /// Reads a proving key from a buffer. /// Does so by reading verification key first, and then deserializing the rest of the file into the remaining proving key data. - pub fn read<'params, R: io::Read, ConcreteCircuit: Circuit>( + /// + /// Reads a curve element from the buffer and parses it according to the `format`: + /// - `Processed`: Reads a compressed curve element and decompresses it. + /// Reads a field element in standard form, with endianness specified by the + /// `PrimeField` implementation, and checks that the element is less than the modulus. + /// - `RawBytes`: Reads an uncompressed curve element with coordinates in Montgomery form. + /// Checks that field elements are less than modulus, and then checks that the point is on the curve. + /// - `RawBytesUnchecked`: Reads an uncompressed curve element with coordinates in Montgomery form; + /// does not perform any checks + pub fn read>( reader: &mut R, - params: &impl Params<'params, C>, + format: SerdeFormat, ) -> io::Result { - let vk = VerifyingKey::::read::(reader, params)?; - let l0 = Polynomial::read(reader)?; - let l_last = Polynomial::read(reader)?; - let l_active_row = Polynomial::read(reader)?; - let fixed_values = read_polynomial_vec(reader)?; - let fixed_polys = read_polynomial_vec(reader)?; - let fixed_cosets = read_polynomial_vec(reader)?; - let permutation = permutation::ProvingKey::read(reader)?; + let vk = VerifyingKey::::read::(reader, format).unwrap(); + let l0 = Polynomial::read(reader, format); + let l_last = Polynomial::read(reader, format); + let l_active_row = Polynomial::read(reader, format); + let fixed_values = read_polynomial_vec(reader, format); + let fixed_polys = read_polynomial_vec(reader, format); + let fixed_cosets = read_polynomial_vec(reader, format); + let permutation = permutation::ProvingKey::read(reader, format); let ev = Evaluator::new(vk.cs()); Ok(Self { vk, @@ -293,31 +355,19 @@ impl ProvingKey { }) } - /// Writes a proving key to a vector of bytes. - pub fn to_bytes(&self) -> Vec { + /// Writes a proving key to a vector of bytes using [`Self::write`]. + pub fn to_bytes(&self, format: SerdeFormat) -> Vec { let mut bytes = Vec::::with_capacity(self.bytes_length()); - Self::write(self, &mut bytes).expect("Writing to vector should not fail"); + Self::write(self, &mut bytes, format).expect("Writing to vector should not fail"); bytes } - /// Reads a proving key from a slice of bytes. - pub fn from_bytes<'params, ConcreteCircuit: Circuit>( + /// Reads a proving key from a slice of bytes using [`Self::read`]. + pub fn from_bytes>( mut bytes: &[u8], - params: &impl Params<'params, C>, + format: SerdeFormat, ) -> io::Result { - Self::read::<_, ConcreteCircuit>(&mut bytes, params) - } - - /// Gets the total number of bytes in the serialization of `self` - fn bytes_length(&self) -> usize { - let scalar_len = C::Scalar::default().to_repr().as_ref().len(); - self.vk.bytes_length() - + 12 - + scalar_len * (self.l0.len() + self.l_last.len() + self.l_active_row.len()) - + polynomial_slice_byte_length(&self.fixed_values) - + polynomial_slice_byte_length(&self.fixed_polys) - + polynomial_slice_byte_length(&self.fixed_cosets) - + self.permutation.bytes_length() + Self::read::<_, ConcreteCircuit>(&mut bytes, format) } } diff --git a/halo2_proofs/src/plonk/circuit.rs b/halo2_proofs/src/plonk/circuit.rs index 7ad8d8b8e1..4090b1c523 100644 --- a/halo2_proofs/src/plonk/circuit.rs +++ b/halo2_proofs/src/plonk/circuit.rs @@ -64,6 +64,8 @@ impl PartialOrd for Column { } pub(crate) mod sealed { + use std::ops::Add; + /// Phase of advice column #[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct Phase(pub(super) u8); @@ -72,6 +74,13 @@ pub(crate) mod sealed { pub fn prev(&self) -> Option { self.0.checked_sub(1).map(Phase) } + pub fn next(&self) -> Phase { + assert!(self.0 < 2, "The API only supports three phases"); + Phase(self.0 + 1) + } + pub fn to_u8(&self) -> u8 { + self.0 + } } /// Sealed trait to help keep `Phase` private. @@ -550,32 +559,22 @@ pub trait Assignment { fn query_instance(&self, column: Column, row: usize) -> Result, Error>; /// Assign an advice column value (witness) - fn assign_advice( - &mut self, - annotation: A, + fn assign_advice<'r, 'v>( + //( + &'r mut self, + // annotation: A, column: Column, row: usize, - to: V, - ) -> Result<(), Error> - where - V: FnOnce() -> Value, - VR: Into>, - A: FnOnce() -> AR, - AR: Into; + to: Value>, // V, + ) -> Result>, Error>; + // where + // V: FnOnce() -> Value, + // VR: Into>, + // A: FnOnce() -> AR, + // AR: Into; /// Assign a fixed value - fn assign_fixed( - &mut self, - annotation: A, - column: Column, - row: usize, - to: V, - ) -> Result<(), Error> - where - V: FnOnce() -> Value, - VR: Into>, - A: FnOnce() -> AR, - AR: Into; + fn assign_fixed(&mut self, column: Column, row: usize, to: Assigned); /// Assign two cells to have the same value fn copy( @@ -584,7 +583,7 @@ pub trait Assignment { left_row: usize, right_column: Column, right_row: usize, - ) -> Result<(), Error>; + ); /// Fills a fixed `column` starting from the given `row` with value `to`. fn fill_from_row( @@ -615,6 +614,10 @@ pub trait Assignment { /// /// [`Layouter::namespace`]: crate::circuit::Layouter#method.namespace fn pop_namespace(&mut self, gadget_name: Option); + + /// Commit advice columns in current phase and squeeze challenges. This can be + /// called DURING synthesize. + fn next_phase(&mut self) {} } /// A floor planning strategy for a circuit. @@ -925,40 +928,69 @@ impl Expression { } } - /// Identifier for this expression. Expressions with identical identifiers - /// do the same calculation (but the expressions don't need to be exactly equal - /// in how they are composed e.g. `1 + 2` and `2 + 1` can have the same identifier). - pub fn identifier(&self) -> String { + fn write_identifier(&self, writer: &mut W) -> std::io::Result<()> { match self { - Expression::Constant(scalar) => format!("{:?}", scalar), - Expression::Selector(selector) => format!("selector[{}]", selector.0), + Expression::Constant(scalar) => write!(writer, "{:?}", scalar), + Expression::Selector(selector) => write!(writer, "selector[{}]", selector.0), Expression::Fixed(query) => { - format!("fixed[{}][{}]", query.column_index, query.rotation.0) + write!( + writer, + "fixed[{}][{}]", + query.column_index, query.rotation.0 + ) } Expression::Advice(query) => { - format!("advice[{}][{}]", query.column_index, query.rotation.0) + write!( + writer, + "advice[{}][{}]", + query.column_index, query.rotation.0 + ) } Expression::Instance(query) => { - format!("instance[{}][{}]", query.column_index, query.rotation.0) + write!( + writer, + "instance[{}][{}]", + query.column_index, query.rotation.0 + ) } Expression::Challenge(challenge) => { - format!("challenge[{}]", challenge.index()) + write!(writer, "challenge[{}]", challenge.index()) } Expression::Negated(a) => { - format!("(-{})", a.identifier()) + writer.write_all(b"(-")?; + a.write_identifier(writer)?; + writer.write_all(b")") } Expression::Sum(a, b) => { - format!("({}+{})", a.identifier(), b.identifier()) + writer.write_all(b"(")?; + a.write_identifier(writer)?; + writer.write_all(b"+")?; + b.write_identifier(writer)?; + writer.write_all(b")") } Expression::Product(a, b) => { - format!("({}*{})", a.identifier(), b.identifier()) + writer.write_all(b"(")?; + a.write_identifier(writer)?; + writer.write_all(b"*")?; + b.write_identifier(writer)?; + writer.write_all(b")") } Expression::Scaled(a, f) => { - format!("{}*{:?}", a.identifier(), f) + a.write_identifier(writer)?; + write!(writer, "*{:?}", f) } } } + /// Identifier for this expression. Expressions with identical identifiers + /// do the same calculation (but the expressions don't need to be exactly equal + /// in how they are composed e.g. `1 + 2` and `2 + 1` can have the same identifier). + pub fn identifier(&self) -> String { + let mut cursor = std::io::Cursor::new(Vec::new()); + self.write_identifier(&mut cursor).unwrap(); + String::from_utf8(cursor.into_inner()).unwrap() + } + /// Compute the degree of this polynomial pub fn degree(&self) -> usize { match self { diff --git a/halo2_proofs/src/plonk/keygen.rs b/halo2_proofs/src/plonk/keygen.rs index a3fe3dc3d7..2001f5cc32 100644 --- a/halo2_proofs/src/plonk/keygen.rs +++ b/halo2_proofs/src/plonk/keygen.rs @@ -93,47 +93,30 @@ impl Assignment for Assembly { Ok(Value::unknown()) } - fn assign_advice( - &mut self, - _: A, + fn assign_advice<'r, 'v>( + //( + &'r mut self, + //_: A, _: Column, _: usize, - _: V, - ) -> Result<(), Error> - where - V: FnOnce() -> Value, - VR: Into>, - A: FnOnce() -> AR, - AR: Into, - { - // We only care about fixed columns here - Ok(()) + _: Value>, + ) -> Result>, Error> { + Ok(Value::unknown()) } - fn assign_fixed( - &mut self, - _: A, - column: Column, - row: usize, - to: V, - ) -> Result<(), Error> - where - V: FnOnce() -> Value, - VR: Into>, - A: FnOnce() -> AR, - AR: Into, - { + fn assign_fixed(&mut self, column: Column, row: usize, to: Assigned) { if !self.usable_rows.contains(&row) { - return Err(Error::not_enough_rows_available(self.k)); + panic!( + "Assign Fixed {:?}", + Error::not_enough_rows_available(self.k) + ); } *self .fixed .get_mut(column.index()) .and_then(|v| v.get_mut(row)) - .ok_or(Error::BoundsFailure)? = to().into_field().assign()?; - - Ok(()) + .unwrap_or_else(|| panic!("{:?}", Error::BoundsFailure)) = to; } fn copy( @@ -142,13 +125,14 @@ impl Assignment for Assembly { left_row: usize, right_column: Column, right_row: usize, - ) -> Result<(), Error> { + ) { if !self.usable_rows.contains(&left_row) || !self.usable_rows.contains(&right_row) { - return Err(Error::not_enough_rows_available(self.k)); + panic!("{:?}", Error::not_enough_rows_available(self.k)); } self.permutation .copy(left_column, left_row, right_column, right_row) + .unwrap_or_else(|err| panic!("{err:?}")) } fn fill_from_row( diff --git a/halo2_proofs/src/plonk/permutation.rs b/halo2_proofs/src/plonk/permutation.rs index 7d0d8cc774..99d7a75622 100644 --- a/halo2_proofs/src/plonk/permutation.rs +++ b/halo2_proofs/src/plonk/permutation.rs @@ -2,9 +2,11 @@ use super::circuit::{Any, Column}; use crate::{ arithmetic::CurveAffine, helpers::{ - polynomial_slice_byte_length, read_polynomial_vec, write_polynomial_slice, CurveRead, + polynomial_slice_byte_length, read_polynomial_vec, write_polynomial_slice, + SerdeCurveAffine, SerdePrimeField, }, poly::{Coeff, ExtendedLagrangeCoeff, LagrangeCoeff, Polynomial}, + SerdeFormat, }; use ff::PrimeField; @@ -87,19 +89,27 @@ impl VerifyingKey { &self.commitments } - pub(crate) fn write(&self, writer: &mut W) -> io::Result<()> { + pub(crate) fn write(&self, writer: &mut W, format: SerdeFormat) + where + C: SerdeCurveAffine, + { for commitment in &self.commitments { - writer.write_all(commitment.to_bytes().as_ref())?; + commitment.write(writer, format); } - - Ok(()) } - pub(crate) fn read(reader: &mut R, argument: &Argument) -> io::Result { + pub(crate) fn read( + reader: &mut R, + argument: &Argument, + format: SerdeFormat, + ) -> Self + where + C: SerdeCurveAffine, + { let commitments = (0..argument.columns.len()) - .map(|_| C::read(reader)) - .collect::, _>>()?; - Ok(VerifyingKey { commitments }) + .map(|_| C::read(reader, format)) + .collect(); + VerifyingKey { commitments } } pub(crate) fn bytes_length(&self) -> usize { @@ -115,27 +125,31 @@ pub(crate) struct ProvingKey { pub(super) cosets: Vec>, } -impl ProvingKey { +impl ProvingKey +where + C::Scalar: SerdePrimeField, +{ /// Reads proving key for a single permutation argument from buffer using `Polynomial::read`. - pub(super) fn read(reader: &mut R) -> io::Result { - let permutations = read_polynomial_vec(reader)?; - let polys = read_polynomial_vec(reader)?; - let cosets = read_polynomial_vec(reader)?; - Ok(ProvingKey { + pub(super) fn read(reader: &mut R, format: SerdeFormat) -> Self { + let permutations = read_polynomial_vec(reader, format); + let polys = read_polynomial_vec(reader, format); + let cosets = read_polynomial_vec(reader, format); + ProvingKey { permutations, polys, cosets, - }) + } } /// Writes proving key for a single permutation argument to buffer using `Polynomial::write`. - pub(super) fn write(&self, writer: &mut W) -> io::Result<()> { - write_polynomial_slice(&self.permutations, writer)?; - write_polynomial_slice(&self.polys, writer)?; - write_polynomial_slice(&self.cosets, writer)?; - Ok(()) + pub(super) fn write(&self, writer: &mut W, format: SerdeFormat) { + write_polynomial_slice(&self.permutations, writer, format); + write_polynomial_slice(&self.polys, writer, format); + write_polynomial_slice(&self.cosets, writer, format); } +} +impl ProvingKey { /// Gets the total number of bytes in the serialization of `self` pub(super) fn bytes_length(&self) -> usize { polynomial_slice_byte_length(&self.permutations) diff --git a/halo2_proofs/src/plonk/prover.rs b/halo2_proofs/src/plonk/prover.rs index 65a01873d2..efd4305a01 100644 --- a/halo2_proofs/src/plonk/prover.rs +++ b/halo2_proofs/src/plonk/prover.rs @@ -4,7 +4,9 @@ use halo2curves::CurveExt; use rand_core::RngCore; use std::collections::BTreeSet; use std::env::var; +use std::marker::PhantomData; use std::ops::RangeTo; +use std::rc::Rc; use std::sync::atomic::AtomicUsize; use std::time::Instant; use std::{collections::HashMap, iter, mem, sync::atomic::Ordering}; @@ -18,6 +20,9 @@ use super::{ lookup, permutation, vanishing, ChallengeBeta, ChallengeGamma, ChallengeTheta, ChallengeX, ChallengeY, Error, Expression, ProvingKey, }; +use crate::poly::batch_invert_assigned_ref; +use crate::poly::commitment::ParamsProver; +use crate::transcript::Transcript; use crate::{ arithmetic::{eval_polynomial, CurveAffine, FieldExt}, circuit::Value, @@ -40,19 +45,20 @@ use group::prime::PrimeCurveAffine; /// are zero-padded internally. pub fn create_proof< 'params, + 'a, Scheme: CommitmentScheme, P: Prover<'params, Scheme>, E: EncodedChallenge, - R: RngCore, + R: RngCore + 'a, T: TranscriptWrite, ConcreteCircuit: Circuit, >( params: &'params Scheme::ParamsProver, pk: &ProvingKey, circuits: &[ConcreteCircuit], - instances: &[&[&[Scheme::Scalar]]], + instances: &[&[&'a [Scheme::Scalar]]], mut rng: R, - transcript: &mut T, + mut transcript: &'a mut T, ) -> Result<(), Error> { for instance in instances.iter() { if instance.len() != pk.vk.cs.num_instance_columns { @@ -85,36 +91,14 @@ pub fn create_proof< let mut poly = domain.empty_lagrange(); assert_eq!(poly.len(), params.n() as usize); if values.len() > (poly.len() - (meta.blinding_factors() + 1)) { - return Err(Error::InstanceTooLarge); + panic!("Error::InstanceTooLarge"); } for (poly, value) in poly.iter_mut().zip(values.iter()) { - if !P::QUERY_INSTANCE { - transcript.common_scalar(*value)?; - } *poly = *value; } - Ok(poly) + poly }) - .collect::, _>>()?; - - if P::QUERY_INSTANCE { - let instance_commitments_projective: Vec<_> = instance_values - .iter() - .map(|poly| params.commit_lagrange(poly, Blind::default())) - .collect(); - let mut instance_commitments = - vec![Scheme::Curve::identity(); instance_commitments_projective.len()]; - ::CurveExt::batch_normalize( - &instance_commitments_projective, - &mut instance_commitments, - ); - let instance_commitments = instance_commitments; - drop(instance_commitments_projective); - - for commitment in &instance_commitments { - transcript.common_point(*commitment)?; - } - } + .collect::>(); let instance_polys: Vec<_> = instance_values .iter() @@ -137,17 +121,42 @@ pub fn create_proof< pub advice_blinds: Vec>, } - struct WitnessCollection<'a, F: Field> { - k: u32, + struct WitnessCollection<'params, 'a, 'b, Scheme, P, C, E, R, T> + where + Scheme: CommitmentScheme, + P: Prover<'params, Scheme>, + C: CurveAffine, + E: EncodedChallenge, + R: RngCore + 'a, + T: TranscriptWrite, + { + params: &'params Scheme::ParamsProver, current_phase: sealed::Phase, - advice: Vec, LagrangeCoeff>>, - challenges: &'a HashMap, - instances: &'a [&'a [F]], + advice: Vec, LagrangeCoeff>>, + challenges: &'b mut HashMap, + instances: &'b [&'a [C::Scalar]], usable_rows: RangeTo, - _marker: std::marker::PhantomData, + advice_single: AdviceSingle, + instance_single: &'b InstanceSingle, + rng: &'b mut R, + transcript: &'b mut &'a mut T, + column_indices: [Vec; 3], + challenge_indices: [Vec; 3], + unusable_rows_start: usize, + _marker: PhantomData<(P, E)>, } - impl<'a, F: Field> Assignment for WitnessCollection<'a, F> { + impl<'params, 'a, 'b, F, Scheme, P, C, E, R, T> Assignment + for WitnessCollection<'params, 'a, 'b, Scheme, P, C, E, R, T> + where + F: FieldExt, + Scheme: CommitmentScheme, + P: Prover<'params, Scheme>, + C: CurveAffine, + E: EncodedChallenge, + R: RngCore, + T: TranscriptWrite, + { fn enter_region(&mut self, _: N) where NR: Into, @@ -172,7 +181,7 @@ pub fn create_proof< fn query_instance(&self, column: Column, row: usize) -> Result, Error> { if !self.usable_rows.contains(&row) { - return Err(Error::not_enough_rows_available(self.k)); + return Err(Error::not_enough_rows_available(self.params.k())); } self.instances @@ -182,65 +191,51 @@ pub fn create_proof< .ok_or(Error::BoundsFailure) } - fn assign_advice( - &mut self, - _: A, + fn assign_advice<'r, 'v>( + //( + &'r mut self, + //_: A, column: Column, row: usize, - to: V, - ) -> Result<(), Error> - where - V: FnOnce() -> Value, - VR: Into>, - A: FnOnce() -> AR, - AR: Into, - { + to: Value>, + ) -> Result>, Error> { + // TODO: better to assign all at once, deal with phases later // Ignore assignment of advice column in different phase than current one. if self.current_phase != column.column_type().phase { - return Ok(()); + return Ok(Value::unknown()); } if !self.usable_rows.contains(&row) { - return Err(Error::not_enough_rows_available(self.k)); + return Err(Error::not_enough_rows_available(self.params.k())); } - *self + let advice_get_mut = self .advice .get_mut(column.index()) - .and_then(|v| v.get_mut(row)) - .ok_or(Error::BoundsFailure)? = to().into_field().assign()?; - - Ok(()) + .expect("Not enough advice columns") + .get_mut(row) + .expect("Not enough rows"); + // We can get another 3-4% decrease in witness gen time by using the following unsafe code, but this skips all array bound checks so we should use it only if the performance gain is really necessary: + /* + let advice_get_mut = unsafe { + self.advice + .get_unchecked_mut(column.index()) + .get_unchecked_mut(row) + }; + */ + *advice_get_mut = to + .assign() + .expect("No Value::unknown() in advice column allowed during create_proof"); + let immutable_raw_ptr = advice_get_mut as *const Assigned; + Ok(Value::known(unsafe { &*immutable_raw_ptr })) } - fn assign_fixed( - &mut self, - _: A, - _: Column, - _: usize, - _: V, - ) -> Result<(), Error> - where - V: FnOnce() -> Value, - VR: Into>, - A: FnOnce() -> AR, - AR: Into, - { + fn assign_fixed(&mut self, _: Column, _: usize, _: Assigned) { // We only care about advice columns here - - Ok(()) } - fn copy( - &mut self, - _: Column, - _: usize, - _: Column, - _: usize, - ) -> Result<(), Error> { + fn copy(&mut self, _: Column, _: usize, _: Column, _: usize) { // We only care about advice columns here - - Ok(()) } fn fill_from_row( @@ -271,117 +266,165 @@ pub fn create_proof< fn pop_namespace(&mut self, _: Option) { // Do nothing; we don't care about namespaces in this context. } + + fn next_phase(&mut self) { + let phase = self.current_phase.to_u8() as usize; + if phase == 0 { + // Absorb instances into transcript. + // Do this here and not earlier in case we want to be able to mutate + // the instances during synthesize in FirstPhase in the future + if !P::QUERY_INSTANCE { + for values in self.instances.iter() { + for value in values.iter() { + self.transcript + .common_scalar(*value) + .expect("Absorbing instance value to transcript failed"); + } + } + } else { + let instance_commitments_projective: Vec<_> = self + .instance_single + .instance_values + .iter() + .map(|poly| self.params.commit_lagrange(poly, Blind::default())) + .collect(); + let mut instance_commitments = + vec![C::identity(); instance_commitments_projective.len()]; + C::CurveExt::batch_normalize( + &instance_commitments_projective, + &mut instance_commitments, + ); + let instance_commitments = instance_commitments; + drop(instance_commitments_projective); + + for commitment in &instance_commitments { + self.transcript + .common_point(*commitment) + .expect("Absorbing instance commitment to transcript failed"); + } + } + } + // Commit the advice columns in the current phase + let mut advice_values = batch_invert_assigned_ref::( + self.column_indices + .get(phase) + .expect("The API only supports 3 phases right now") + .iter() + .map(|column_index| &self.advice[*column_index]) + .collect(), + ); + // Add blinding factors to advice columns + for advice_values in &mut advice_values { + for cell in &mut advice_values[self.unusable_rows_start..] { + *cell = F::random(&mut self.rng); + } + } + // Compute commitments to advice column polynomials + let blinds: Vec<_> = advice_values + .iter() + .map(|_| Blind(F::random(&mut self.rng))) + .collect(); + let advice_commitments_projective: Vec<_> = advice_values + .iter() + .zip(blinds.iter()) + .map(|(poly, blind)| self.params.commit_lagrange(poly, *blind)) + .collect(); + let mut advice_commitments = vec![C::identity(); advice_commitments_projective.len()]; + C::CurveExt::batch_normalize(&advice_commitments_projective, &mut advice_commitments); + let advice_commitments = advice_commitments; + drop(advice_commitments_projective); + + for commitment in &advice_commitments { + self.transcript + .write_point(*commitment) + .expect("Absorbing advice commitment to transcript failed"); + } + for ((column_index, advice_poly), blind) in self.column_indices[phase] + .iter() + .zip(advice_values) + .zip(blinds) + { + self.advice_single.advice_polys[*column_index] = advice_poly; + self.advice_single.advice_blinds[*column_index] = blind; + } + for challenge_index in self.challenge_indices[phase].iter() { + let existing = self.challenges.insert( + *challenge_index, + *self.transcript.squeeze_challenge_scalar::<()>(), + ); + assert!(existing.is_none()); + } + self.current_phase = self.current_phase.next(); + } + } + + let mut column_indices = [(); 3].map(|_| vec![]); + for (index, phase) in meta.advice_column_phase.iter().enumerate() { + column_indices[phase.to_u8() as usize].push(index); + } + let mut challenge_indices = [(); 3].map(|_| vec![]); + for (index, phase) in meta.challenge_phase.iter().enumerate() { + challenge_indices[phase.to_u8() as usize].push(index); } let (advice, challenges) = { - let mut advice = vec![ - AdviceSingle:: { - advice_polys: vec![domain.empty_lagrange(); meta.num_advice_columns], - advice_blinds: vec![Blind::default(); meta.num_advice_columns], - }; - instances.len() - ]; + let mut advice = Vec::with_capacity(instances.len()); let mut challenges = HashMap::::with_capacity(meta.num_challenges); let unusable_rows_start = params.n() as usize - (meta.blinding_factors() + 1); - for current_phase in pk.vk.cs.phases() { - let column_indices = meta - .advice_column_phase - .iter() - .enumerate() - .filter_map(|(column_index, phase)| { - if current_phase == *phase { - Some(column_index) - } else { - None - } - }) - .collect::>(); - - for ((circuit, advice), instances) in - circuits.iter().zip(advice.iter_mut()).zip(instances) - { - let mut witness = WitnessCollection { - k: params.k(), - current_phase, - advice: vec![domain.empty_lagrange_assigned(); meta.num_advice_columns], - instances, - challenges: &challenges, - // The prover will not be allowed to assign values to advice - // cells that exist within inactive rows, which include some - // number of blinding factors and an extra row for use in the - // permutation argument. - usable_rows: ..unusable_rows_start, - _marker: std::marker::PhantomData, - }; + let phases = pk.vk.cs.phases().collect::>(); + let num_phases = phases.len(); + // WARNING: this will currently not work if `circuits` has more than 1 circuit + // because the original API squeezes the challenges for a phase after running all circuits + // once in that phase. + assert_eq!( + circuits.len(), + 1, + "New challenge API doesn't work with multiple circuits yet" + ); + for ((circuit, instances), instance_single) in + circuits.iter().zip(instances).zip(instance.iter()) + { + let mut witness: WitnessCollection = WitnessCollection { + params, + current_phase: phases[0], + advice: vec![domain.empty_lagrange_assigned(); meta.num_advice_columns], + instances, + challenges: &mut challenges, + // The prover will not be allowed to assign values to advice + // cells that exist within inactive rows, which include some + // number of blinding factors and an extra row for use in the + // permutation argument. + usable_rows: ..unusable_rows_start, + advice_single: AdviceSingle:: { + advice_polys: vec![domain.empty_lagrange(); meta.num_advice_columns], + advice_blinds: vec![Blind::default(); meta.num_advice_columns], + }, + instance_single, + rng: &mut rng, + transcript: &mut transcript, + column_indices: column_indices.clone(), + challenge_indices: challenge_indices.clone(), + unusable_rows_start, + _marker: PhantomData, + }; + // while loop is for compatibility with circuits that do not use the new `next_phase` API to manage phases + // If the circuit uses the new API, then the while loop will only execute once + while witness.current_phase.to_u8() < num_phases as u8 { // Synthesize the circuit to obtain the witness and other information. ConcreteCircuit::FloorPlanner::synthesize( &mut witness, circuit, config.clone(), meta.constants.clone(), - )?; - - let mut advice_values = batch_invert_assigned::( - witness - .advice - .into_iter() - .enumerate() - .filter_map(|(column_index, advice)| { - if column_indices.contains(&column_index) { - Some(advice) - } else { - None - } - }) - .collect(), - ); - - // Add blinding factors to advice columns - for advice_values in &mut advice_values { - for cell in &mut advice_values[unusable_rows_start..] { - *cell = Scheme::Scalar::random(&mut rng); - } - } - - // Compute commitments to advice column polynomials - let blinds: Vec<_> = advice_values - .iter() - .map(|_| Blind(Scheme::Scalar::random(&mut rng))) - .collect(); - let advice_commitments_projective: Vec<_> = advice_values - .iter() - .zip(blinds.iter()) - .map(|(poly, blind)| params.commit_lagrange(poly, *blind)) - .collect(); - let mut advice_commitments = - vec![Scheme::Curve::identity(); advice_commitments_projective.len()]; - ::CurveExt::batch_normalize( - &advice_commitments_projective, - &mut advice_commitments, - ); - let advice_commitments = advice_commitments; - drop(advice_commitments_projective); - - for commitment in &advice_commitments { - transcript.write_point(*commitment)?; - } - for ((column_index, advice_values), blind) in - column_indices.iter().zip(advice_values).zip(blinds) - { - advice.advice_polys[*column_index] = advice_values; - advice.advice_blinds[*column_index] = blind; - } - } - - for (index, phase) in meta.challenge_phase.iter().enumerate() { - if current_phase == *phase { - let existing = - challenges.insert(index, *transcript.squeeze_challenge_scalar::<()>()); - assert!(existing.is_none()); + ) + .unwrap(); + if witness.current_phase.to_u8() < num_phases as u8 { + witness.next_phase(); } } + advice.push(witness.advice_single); } assert_eq!(challenges.len(), meta.num_challenges); @@ -508,7 +551,7 @@ pub fn create_proof< let vanishing = vanishing.construct(params, domain, h_poly, &mut rng, transcript)?; let x: ChallengeX<_> = transcript.squeeze_challenge_scalar(); - let xn = x.pow(&[params.n() as u64, 0, 0, 0]); + let xn = x.pow(&[params.n(), 0, 0, 0]); if P::QUERY_INSTANCE { // Compute and hash instance evals for each circuit instance @@ -638,6 +681,6 @@ pub fn create_proof< let prover = P::new(params); prover - .create_proof(rng, transcript, instances) + .create_proof(&mut rng, transcript, instances) .map_err(|_| Error::ConstraintSystemFailure) } diff --git a/halo2_proofs/src/poly.rs b/halo2_proofs/src/poly.rs index 1e2ac6366c..219afebb77 100644 --- a/halo2_proofs/src/poly.rs +++ b/halo2_proofs/src/poly.rs @@ -5,6 +5,7 @@ use crate::arithmetic::parallelize; use crate::helpers::SerdePrimeField; use crate::plonk::Assigned; +use crate::SerdeFormat; use ff::PrimeField; use group::ff::{BatchInvert, Field}; @@ -146,32 +147,68 @@ impl Polynomial { } } -impl Polynomial { +impl Polynomial { /// Reads polynomial from buffer using `SerdePrimeField::read`. - pub(crate) fn read(reader: &mut R) -> io::Result { - let mut poly_len_be_bytes = [0u8; 4]; - reader.read_exact(&mut poly_len_be_bytes)?; - let poly_len = u32::from_be_bytes(poly_len_be_bytes); - - (0..poly_len) - .map(|_| F::read(reader)) - .collect::>>() - .map(|values| Self { - values, - _marker: PhantomData, - }) + pub(crate) fn read(reader: &mut R, format: SerdeFormat) -> Self { + let mut poly_len = [0u8; 4]; + reader.read_exact(&mut poly_len).unwrap(); + let poly_len = u32::from_be_bytes(poly_len); + Self { + values: (0..poly_len).map(|_| F::read(reader, format)).collect(), + _marker: PhantomData, + } } /// Writes polynomial to buffer using `SerdePrimeField::write`. - pub(crate) fn write(&self, writer: &mut W) -> io::Result<()> { - writer.write_all(&(self.values.len() as u32).to_be_bytes())?; + pub(crate) fn write(&self, writer: &mut W, format: SerdeFormat) { + writer + .write_all(&(self.values.len() as u32).to_be_bytes()) + .unwrap(); for value in self.values.iter() { - value.write(writer)?; + value.write(writer, format); } - Ok(()) } } +/// Invert each polynomial in place for memory efficiency +pub(crate) fn batch_invert_assigned_ref( + assigned: Vec<&Polynomial, LagrangeCoeff>>, +) -> Vec> { + if assigned.is_empty() { + return vec![]; + } + let n = assigned[0].num_coeffs(); + // 1d vector better for memory allocation + let mut assigned_denominators: Vec<_> = assigned + .iter() + .flat_map(|f| f.iter().map(|value| value.denominator())) + .collect(); + + assigned_denominators + .iter_mut() + // If the denominator is trivial, we can skip it, reducing the + // size of the batch inversion. + .filter_map(|d| d.as_mut()) + .batch_invert(); + + assigned + .iter() + .zip(assigned_denominators.chunks(n)) + .map(|(poly, inv_denoms)| { + debug_assert_eq!(inv_denoms.len(), poly.values.len()); + Polynomial { + values: poly + .values + .iter() + .zip(inv_denoms.iter()) + .map(|(a, inv_den)| a.numerator() * inv_den.unwrap_or(F::one())) + .collect(), + _marker: poly._marker, + } + }) + .collect() +} + pub(crate) fn batch_invert_assigned( assigned: Vec, LagrangeCoeff>>, ) -> Vec> { diff --git a/halo2_proofs/src/poly/commitment.rs b/halo2_proofs/src/poly/commitment.rs index 91fa244280..e82515cfff 100644 --- a/halo2_proofs/src/poly/commitment.rs +++ b/halo2_proofs/src/poly/commitment.rs @@ -99,7 +99,7 @@ pub trait ParamsProver<'params, C: CurveAffine>: Params<'params, C> { pub trait ParamsVerifier<'params, C: CurveAffine>: Params<'params, C> {} /// Multi scalar multiplication engine -pub trait MSM: Clone + Debug { +pub trait MSM: Clone + Debug + Send + Sync { /// Add arbitrary term (the scalar and the point) fn append_term(&mut self, scalar: C::Scalar, point: C::CurveExt); diff --git a/halo2_proofs/src/poly/domain.rs b/halo2_proofs/src/poly/domain.rs index a753cb859d..54c6b5ed18 100644 --- a/halo2_proofs/src/poly/domain.rs +++ b/halo2_proofs/src/poly/domain.rs @@ -85,8 +85,8 @@ impl EvaluationDomain { { // Compute the evaluations of t(X) = X^n - 1 in the coset evaluation domain. // We don't have to compute all of them, because it will repeat. - let orig = G::Scalar::ZETA.pow_vartime(&[n as u64, 0, 0, 0]); - let step = extended_omega.pow_vartime(&[n as u64, 0, 0, 0]); + let orig = G::Scalar::ZETA.pow_vartime([n]); + let step = extended_omega.pow_vartime([n]); let mut cur = orig; loop { t_evaluations.push(cur); @@ -153,6 +153,18 @@ impl EvaluationDomain { } } + pub fn lagrange_assigned_from_vec( + &self, + values: Vec>, + ) -> Polynomial, LagrangeCoeff> { + assert_eq!(values.len(), self.n as usize); + + Polynomial { + values, + _marker: PhantomData, + } + } + /// Obtains a polynomial in coefficient form when given a vector of /// coefficients of size `n`; panics if the provided vector is the wrong /// length. diff --git a/halo2_proofs/src/poly/kzg/commitment.rs b/halo2_proofs/src/poly/kzg/commitment.rs index 3e8cce6d09..fbc1812e6b 100644 --- a/halo2_proofs/src/poly/kzg/commitment.rs +++ b/halo2_proofs/src/poly/kzg/commitment.rs @@ -1,9 +1,10 @@ use crate::arithmetic::{ best_fft, best_multiexp, g_to_lagrange, parallelize, CurveAffine, CurveExt, FieldExt, Group, }; -use crate::helpers::CurveRead; +use crate::helpers::SerdeCurveAffine; use crate::poly::commitment::{Blind, CommitmentScheme, Params, ParamsProver, ParamsVerifier, MSM}; use crate::poly::{Coeff, LagrangeCoeff, Polynomial}; +use crate::SerdeFormat; use ff::{Field, PrimeField}; use group::{prime::PrimeCurveAffine, Curve, Group as _}; @@ -34,7 +35,11 @@ pub struct KZGCommitmentScheme { _marker: PhantomData, } -impl CommitmentScheme for KZGCommitmentScheme { +impl CommitmentScheme for KZGCommitmentScheme +where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, +{ type Scalar = E::Scalar; type Curve = E::G1Affine; @@ -132,6 +137,102 @@ impl ParamsKZG { pub fn s_g2(&self) -> E::G2Affine { self.s_g2 } + + /// Writes parameters to buffer + pub fn write_custom(&self, writer: &mut W, format: SerdeFormat) + where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, + { + writer.write_all(&self.k.to_le_bytes()).unwrap(); + for el in self.g.iter() { + el.write(writer, format); + } + for el in self.g_lagrange.iter() { + el.write(writer, format); + } + self.g2.write(writer, format); + self.s_g2.write(writer, format); + } + + /// Reads params from a buffer. + pub fn read_custom(reader: &mut R, format: SerdeFormat) -> Self + where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, + { + let mut k = [0u8; 4]; + reader.read_exact(&mut k[..]).unwrap(); + let k = u32::from_le_bytes(k); + let n = 1 << k; + + let (g, g_lagrange) = match format { + SerdeFormat::Processed => { + use group::GroupEncoding; + let load_points_from_file_parallelly = + |reader: &mut R| -> Vec> { + let mut points_compressed = + vec![<::G1Affine as GroupEncoding>::Repr::default(); n]; + for points_compressed in points_compressed.iter_mut() { + reader.read_exact((*points_compressed).as_mut()).unwrap(); + } + + let mut points = vec![Option::::None; n]; + parallelize(&mut points, |points, chunks| { + for (i, point) in points.iter_mut().enumerate() { + *point = Option::from(E::G1Affine::from_bytes( + &points_compressed[chunks + i], + )); + } + }); + points + }; + + let g = load_points_from_file_parallelly(reader); + let g: Vec<::G1Affine> = g + .iter() + .map(|point| point.unwrap_or_else(|| panic!("invalid point encoding"))) + .collect(); + let g_lagrange = load_points_from_file_parallelly(reader); + let g_lagrange: Vec<::G1Affine> = g_lagrange + .iter() + .map(|point| point.unwrap_or_else(|| panic!("invalid point encoding"))) + .collect(); + (g, g_lagrange) + } + SerdeFormat::RawBytes => { + let g = (0..n) + .map(|_| ::read(reader, format)) + .collect(); + let g_lagrange = (0..n) + .map(|_| ::read(reader, format)) + .collect(); + (g, g_lagrange) + } + SerdeFormat::RawBytesUnchecked => { + // avoid try branching for performance + let g = (0..n) + .map(|_| ::read(reader, format)) + .collect::>(); + let g_lagrange = (0..n) + .map(|_| ::read(reader, format)) + .collect::>(); + (g, g_lagrange) + } + }; + + let g2 = E::G2Affine::read(reader, format); + let s_g2 = E::G2Affine::read(reader, format); + + Self { + k, + n: n as u64, + g, + g_lagrange, + g2, + s_g2, + } + } } // TODO: see the issue at https://github.com/appliedzkp/halo2/issues/45 @@ -139,7 +240,11 @@ impl ParamsKZG { /// KZG multi-open verification parameters pub type ParamsVerifierKZG = ParamsKZG; -impl<'params, E: Engine + Debug> Params<'params, E::G1Affine> for ParamsKZG { +impl<'params, E: Engine + Debug> Params<'params, E::G1Affine> for ParamsKZG +where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, +{ type MSM = MSMKZG; fn k(&self) -> u32 { @@ -169,89 +274,34 @@ impl<'params, E: Engine + Debug> Params<'params, E::G1Affine> for ParamsKZG { poly: &Polynomial, _: Blind, ) -> E::G1 { - let mut scalars = Vec::with_capacity(poly.len()); - scalars.extend(poly.iter()); - let bases = &self.g_lagrange; - let size = scalars.len(); - assert!(bases.len() >= size); - best_multiexp(&scalars, &bases[0..size]) + let size = poly.len(); + assert!(self.n() >= size as u64); + best_multiexp(poly, &self.g_lagrange[0..size]) } /// Writes params to a buffer. fn write(&self, writer: &mut W) -> io::Result<()> { - use group::GroupEncoding; - writer.write_all(&self.k.to_le_bytes())?; - for el in self.g.iter() { - writer.write_all(el.to_bytes().as_ref())?; - } - for el in self.g_lagrange.iter() { - writer.write_all(el.to_bytes().as_ref())?; - } - writer.write_all(self.g2.to_bytes().as_ref())?; - writer.write_all(self.s_g2.to_bytes().as_ref())?; - Ok(()) + Ok(self.write_custom(writer, SerdeFormat::RawBytesUnchecked)) } /// Reads params from a buffer. fn read(reader: &mut R) -> io::Result { - use group::GroupEncoding; - - let mut k = [0u8; 4]; - reader.read_exact(&mut k[..])?; - let k = u32::from_le_bytes(k); - let n = 1 << k; - - let load_points_from_file_parallelly = - |reader: &mut R| -> io::Result>> { - let mut points_compressed = - vec![<::G1Affine as GroupEncoding>::Repr::default(); n]; - for points_compressed in points_compressed.iter_mut() { - reader.read_exact((*points_compressed).as_mut())?; - } - - let mut points = vec![Option::::None; n]; - parallelize(&mut points, |points, chunks| { - for (i, point) in points.iter_mut().enumerate() { - *point = - Option::from(E::G1Affine::from_bytes(&points_compressed[chunks + i])); - } - }); - Ok(points) - }; - - let g = load_points_from_file_parallelly(reader)?; - let g: Vec<::G1Affine> = g - .iter() - .map(|point| { - point.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point encoding")) - }) - .collect::>()?; - - let g_lagrange = load_points_from_file_parallelly(reader)?; - let g_lagrange: Vec<::G1Affine> = g_lagrange - .iter() - .map(|point| { - point.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "invalid point encoding")) - }) - .collect::>()?; - - let g2 = E::G2Affine::read(reader)?; - let s_g2 = E::G2Affine::read(reader)?; - - Ok(Self { - k, - n: n as u64, - g, - g_lagrange, - g2, - s_g2, - }) + Ok(Self::read_custom(reader, SerdeFormat::RawBytesUnchecked)) } } -impl<'params, E: Engine + Debug> ParamsVerifier<'params, E::G1Affine> for ParamsKZG {} +impl<'params, E: Engine + Debug> ParamsVerifier<'params, E::G1Affine> for ParamsKZG +where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, +{ +} -impl<'params, E: Engine + Debug> ParamsProver<'params, E::G1Affine> for ParamsKZG { +impl<'params, E: Engine + Debug> ParamsProver<'params, E::G1Affine> for ParamsKZG +where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, +{ type ParamsVerifier = ParamsVerifierKZG; fn verifier_params(&'params self) -> &'params Self::ParamsVerifier { @@ -263,12 +313,9 @@ impl<'params, E: Engine + Debug> ParamsProver<'params, E::G1Affine> for ParamsKZ } fn commit(&self, poly: &Polynomial, _: Blind) -> E::G1 { - let mut scalars = Vec::with_capacity(poly.len()); - scalars.extend(poly.iter()); - let bases = &self.g; - let size = scalars.len(); - assert!(bases.len() >= size); - best_multiexp(&scalars, &bases[0..size]) + let size = poly.len(); + assert!(self.n() >= size as u64); + best_multiexp(poly, &self.g[0..size]) } fn get_g(&self) -> &[E::G1Affine] { @@ -278,11 +325,9 @@ impl<'params, E: Engine + Debug> ParamsProver<'params, E::G1Affine> for ParamsKZ #[cfg(test)] mod test { - use crate::arithmetic::{ best_fft, best_multiexp, parallelize, CurveAffine, CurveExt, FieldExt, Group, }; - use crate::helpers::CurveRead; use crate::poly::commitment::ParamsProver; use crate::poly::commitment::{Blind, CommitmentScheme, Params, MSM}; use crate::poly::kzg::commitment::{ParamsKZG, ParamsVerifierKZG}; diff --git a/halo2_proofs/src/poly/kzg/multiopen/gwc/prover.rs b/halo2_proofs/src/poly/kzg/multiopen/gwc/prover.rs index e5077b1b58..e7bff84ade 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/gwc/prover.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/gwc/prover.rs @@ -1,6 +1,6 @@ use super::{construct_intermediate_sets, ChallengeV, Query}; use crate::arithmetic::{eval_polynomial, kate_division, powers, CurveAffine, FieldExt}; - +use crate::helpers::SerdeCurveAffine; use crate::poly::commitment::ParamsProver; use crate::poly::commitment::Prover; use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; @@ -27,7 +27,11 @@ pub struct ProverGWC<'params, E: Engine> { } /// Create a multi-opening proof -impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> for ProverGWC<'params, E> { +impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> for ProverGWC<'params, E> +where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, +{ const QUERY_INSTANCE: bool = false; fn new(params: &'params ParamsKZG) -> Self { diff --git a/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs b/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs index 8f9d348942..1ec003d638 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/gwc/verifier.rs @@ -4,7 +4,7 @@ use std::marker::PhantomData; use super::{construct_intermediate_sets, ChallengeU, ChallengeV}; use crate::arithmetic::{eval_polynomial, lagrange_interpolate, powers, CurveAffine, FieldExt}; - +use crate::helpers::SerdeCurveAffine; use crate::poly::commitment::Verifier; use crate::poly::commitment::MSM; use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; @@ -30,8 +30,11 @@ pub struct VerifierGWC<'params, E: Engine> { params: &'params ParamsKZG, } -impl<'params, E: MultiMillerLoop + Debug> Verifier<'params, KZGCommitmentScheme> - for VerifierGWC<'params, E> +impl<'params, E> Verifier<'params, KZGCommitmentScheme> for VerifierGWC<'params, E> +where + E: MultiMillerLoop + Debug, + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, { type Guard = GuardKZG<'params, E>; type MSMAccumulator = DualMSM<'params, E>; diff --git a/halo2_proofs/src/poly/kzg/multiopen/shplonk.rs b/halo2_proofs/src/poly/kzg/multiopen/shplonk.rs index 125936229e..43d3687da3 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/shplonk.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/shplonk.rs @@ -2,6 +2,8 @@ mod prover; mod verifier; pub use prover::ProverSHPLONK; +use rayon::prelude::*; +use rustc_hash::FxHashSet; pub use verifier::VerifierSHPLONK; use crate::{ @@ -9,10 +11,12 @@ use crate::{ poly::{query::Query, Coeff, Polynomial}, transcript::ChallengeScalar, }; - +use rayon::prelude::*; use std::{ - collections::{btree_map::Entry, BTreeMap, BTreeSet}, + collections::{btree_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet}, + hash::Hash, marker::PhantomData, + sync::Arc, }; #[derive(Clone, Copy, Debug)] @@ -47,12 +51,12 @@ struct RotationSet { } #[derive(Debug, PartialEq)] -struct IntermediateSets> { +struct IntermediateSets> { rotation_sets: Vec>, - super_point_set: Vec, + super_point_set: FxHashSet, } -fn construct_intermediate_sets>( +fn construct_intermediate_sets>( queries: I, ) -> IntermediateSets where @@ -69,18 +73,8 @@ where .get_eval() }; - // Order points according to their rotation - let mut rotation_point_map = BTreeMap::new(); - for query in queries.clone() { - let point = rotation_point_map - .entry(query.get_point()) - .or_insert_with(|| query.get_point()); - - // Assert rotation point matching consistency - assert_eq!(*point, query.get_point()); - } - // All points appear in queries - let super_point_set: Vec = rotation_point_map.values().cloned().collect(); + // All points that appear in queries + let mut super_point_set = FxHashSet::default(); // Collect rotation sets for each commitment // Example elements in the vector: @@ -89,19 +83,21 @@ where // (C_2, {r_2, r_3, r_4}), // (C_3, {r_2, r_3, r_4}), // ... - let mut commitment_rotation_set_map: Vec<(Q::Commitment, Vec)> = vec![]; - for query in queries.clone() { + let mut commitment_rotation_set_map: Vec<(Q::Commitment, FxHashSet)> = vec![]; + for query in queries.iter() { let rotation = query.get_point(); - if let Some(pos) = commitment_rotation_set_map - .iter() - .position(|(commitment, _)| *commitment == query.get_commitment()) + super_point_set.insert(rotation); + if let Some(commitment_rotation_set) = commitment_rotation_set_map + .iter_mut() + .find(|(commitment, _)| *commitment == query.get_commitment()) { - let (_, rotation_set) = &mut commitment_rotation_set_map[pos]; - if !rotation_set.contains(&rotation) { - rotation_set.push(rotation); - } + let (_, rotation_set) = commitment_rotation_set; + rotation_set.insert(rotation); } else { - commitment_rotation_set_map.push((query.get_commitment(), vec![rotation])); + commitment_rotation_set_map.push(( + query.get_commitment(), + FxHashSet::from_iter(core::iter::once(rotation)), + )); }; } @@ -111,41 +107,37 @@ where // {r_1, r_2, r_3} : [C_1] // {r_2, r_3, r_4} : [C_2, C_3], // ... - let mut rotation_set_commitment_map = Vec::<(Vec<_>, Vec)>::new(); - for (commitment, rotation_set) in commitment_rotation_set_map.iter() { - if let Some(pos) = rotation_set_commitment_map.iter().position(|(set, _)| { - BTreeSet::::from_iter(set.iter().cloned()) - == BTreeSet::::from_iter(rotation_set.iter().cloned()) - }) { - let (_, commitments) = &mut rotation_set_commitment_map[pos]; - if !commitments.contains(commitment) { - commitments.push(*commitment); - } + let mut rotation_set_commitment_map: Vec<(FxHashSet, Vec)> = vec![]; + for (commitment, rotation_set) in commitment_rotation_set_map.into_iter() { + if let Some(rotation_set_commitment) = rotation_set_commitment_map + .iter_mut() + .find(|(set, _)| set == &rotation_set) + { + let (_, commitments) = rotation_set_commitment; + commitments.push(commitment); } else { - rotation_set_commitment_map.push((rotation_set.clone(), vec![*commitment])) - } + rotation_set_commitment_map.push((rotation_set, vec![commitment])); + }; } let rotation_sets = rotation_set_commitment_map - .into_iter() + .into_par_iter() .map(|(rotations, commitments)| { + let rotations_vec = rotations.iter().collect::>(); let commitments: Vec> = commitments - .iter() + .into_par_iter() .map(|commitment| { - let evals: Vec = rotations - .iter() - .map(|rotation| get_eval(*commitment, *rotation)) + let evals: Vec = rotations_vec + .par_iter() + .map(|&&rotation| get_eval(commitment, rotation)) .collect(); - Commitment((*commitment, evals)) + Commitment((commitment, evals)) }) .collect(); RotationSet { commitments, - points: rotations - .iter() - .map(|rotation| *rotation_point_map.get(rotation).unwrap()) - .collect(), + points: rotations.into_iter().collect(), } }) .collect::>>(); @@ -167,7 +159,7 @@ mod proptests { use super::{construct_intermediate_sets, Commitment, IntermediateSets}; use crate::poly::Rotation; - use halo2curves::{pasta::Fp, FieldExt}; + use halo2curves::{bn256::Fr, FieldExt}; use std::collections::BTreeMap; use std::convert::TryFrom; @@ -179,11 +171,11 @@ mod proptests { commitment: usize, } - impl super::Query for MyQuery { + impl super::Query for MyQuery { type Commitment = usize; - type Eval = Fp; + type Eval = Fr; - fn get_point(&self) -> Fp { + fn get_point(&self) -> Fr { self.point } @@ -199,15 +191,15 @@ mod proptests { prop_compose! { fn arb_point()( bytes in vec(any::(), 64) - ) -> Fp { - Fp::from_bytes_wide(&<[u8; 64]>::try_from(bytes).unwrap()) + ) -> Fr { + Fr::from_bytes_wide(&<[u8; 64]>::try_from(bytes).unwrap()) } } prop_compose! { - fn arb_query(commitment: usize, point: Fp)( + fn arb_query(commitment: usize, point: Fr)( eval in arb_point() - ) -> MyQuery { + ) -> MyQuery { MyQuery { point, eval, @@ -239,8 +231,8 @@ mod proptests { queries_1 in mapping.iter().map(|(commitment, point_idx)| arb_query(*commitment, points_1[*point_idx])).collect::>(), queries_2 in mapping.iter().map(|(commitment, point_idx)| arb_query(*commitment, points_2[*point_idx])).collect::>(), ) -> ( - Vec>, - Vec> + Vec>, + Vec> ) { ( queries_1, diff --git a/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs b/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs index 2585d9ab69..155ef9debb 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/shplonk/prover.rs @@ -5,7 +5,7 @@ use crate::arithmetic::{ eval_polynomial, evaluate_vanishing_polynomial, kate_division, lagrange_interpolate, parallelize, powers, CurveAffine, FieldExt, }; - +use crate::helpers::SerdeCurveAffine; use crate::poly::commitment::{Blind, ParamsProver, Prover}; use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; use crate::poly::query::{PolynomialPointer, ProverQuery}; @@ -17,7 +17,10 @@ use ff::Field; use group::Curve; use halo2curves::pairing::Engine; use rand_core::RngCore; +use rayon::prelude::*; +use rustc_hash::FxHashSet; use std::fmt::Debug; +use std::hash::Hash; use std::io::{self, Write}; use std::marker::PhantomData; use std::ops::MulAssign; @@ -36,8 +39,8 @@ struct CommitmentExtension<'a, C: CurveAffine> { } impl<'a, C: CurveAffine> Commitment> { - fn extend(&self, points: Vec) -> CommitmentExtension<'a, C> { - let poly = lagrange_interpolate(&points[..], &self.evals()[..]); + fn extend(&self, points: &[C::Scalar]) -> CommitmentExtension<'a, C> { + let poly = lagrange_interpolate(points, &self.evals()[..]); let low_degree_equivalent = Polynomial { values: poly, @@ -79,10 +82,10 @@ struct RotationSetExtension<'a, C: CurveAffine> { } impl<'a, C: CurveAffine> RotationSet> { - fn extend(&self, commitments: Vec>) -> RotationSetExtension<'a, C> { + fn extend(self, commitments: Vec>) -> RotationSetExtension<'a, C> { RotationSetExtension { commitments, - points: self.points.clone(), + points: self.points, } } } @@ -103,6 +106,10 @@ impl<'a, E: Engine> ProverSHPLONK<'a, E> { /// Create a multi-opening proof impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> for ProverSHPLONK<'params, E> +where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, + E::Scalar: Hash, { const QUERY_INSTANCE: bool = false; @@ -136,8 +143,9 @@ impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> // [P_i_0(X) - R_i_0(X), P_i_1(X) - R_i_1(X), ... ] let numerators = rotation_set .commitments - .iter() - .map(|commitment| commitment.quotient_contribution()); + .par_iter() + .map(|commitment| commitment.quotient_contribution()) + .collect::>(); // define numerator polynomial as // N_i_j(X) = (P_i_j(X) - R_i_j(X)) @@ -145,6 +153,7 @@ impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> // N_i(X) = linear_combinination(y, N_i_j(X)) // where y is random scalar to combine numerator polynomials let n_x = numerators + .into_iter() .zip(powers(*y)) .map(|(numerator, power_of_y)| numerator * power_of_y) .reduce(|acc, numerator| acc + &numerator) @@ -171,12 +180,12 @@ impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> ); let rotation_sets: Vec> = rotation_sets - .iter() + .into_par_iter() .map(|rotation_set| { let commitments: Vec> = rotation_set .commitments - .iter() - .map(|commitment_data| commitment_data.extend(rotation_set.points.clone())) + .par_iter() + .map(|commitment_data| commitment_data.extend(&rotation_set.points)) .collect(); rotation_set.extend(commitments) }) @@ -184,9 +193,13 @@ impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> let v: ChallengeV<_> = transcript.squeeze_challenge_scalar(); - let quotient_polynomials = rotation_sets.iter().map(quotient_contribution); + let quotient_polynomials = rotation_sets + .par_iter() + .map(quotient_contribution) + .collect::>(); let h_x: Polynomial = quotient_polynomials + .into_iter() .zip(powers(*v)) .map(|(poly, power_of_v)| poly * power_of_v) .reduce(|acc, poly| acc + &poly) @@ -196,18 +209,15 @@ impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> transcript.write_point(h)?; let u: ChallengeU<_> = transcript.squeeze_challenge_scalar(); - let zt_eval = evaluate_vanishing_polynomial(&super_point_set[..], *u); - let linearisation_contribution = |rotation_set: RotationSetExtension| -> (Polynomial, E::Scalar) { - let diffs: Vec = super_point_set - .iter() - .filter(|point| !rotation_set.points.contains(point)) - .copied() - .collect(); + let mut diffs = super_point_set.clone(); + for point in rotation_set.points.iter() { + diffs.remove(point); + } + let diffs = diffs.into_iter().collect::>(); // calculate difference vanishing polynomial evaluation - let z_i = evaluate_vanishing_polynomial(&diffs[..], *u); // inner linearisation contibutions are @@ -216,15 +226,15 @@ impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> // where u is random evaluation point let inner_contributions = rotation_set .commitments - .iter() - .map(|commitment| commitment.linearisation_contribution(*u)); + .par_iter() + .map(|commitment| commitment.linearisation_contribution(*u)).collect::>(); // define inner contributor polynomial as // L_i_j(X) = (P_i_j(X) - r_i_j) // and combine polynomials with same evaluation point set // L_i(X) = linear_combinination(y, L_i_j(X)) // where y is random scalar to combine inner contibutors - let l_x: Polynomial = inner_contributions.zip(powers(*y)).map(|(poly, power_of_y)| poly * power_of_y).reduce(|acc, poly| acc + &poly).unwrap(); + let l_x: Polynomial = inner_contributions.into_iter().zip(powers(*y)).map(|(poly, power_of_y)| poly * power_of_y).reduce(|acc, poly| acc + &poly).unwrap(); // finally scale l_x by difference vanishing polynomial evaluation z_i (l_x * z_i, z_i) @@ -235,7 +245,7 @@ impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> Vec>, Vec, ) = rotation_sets - .into_iter() + .into_par_iter() .map(linearisation_contribution) .unzip(); @@ -246,9 +256,12 @@ impl<'params, E: Engine + Debug> Prover<'params, KZGCommitmentScheme> .reduce(|acc, poly| acc + &poly) .unwrap(); + let super_point_set = super_point_set.into_iter().collect::>(); + let zt_eval = evaluate_vanishing_polynomial(&super_point_set[..], *u); let l_x = l_x - &(h_x * zt_eval); // sanity check + #[cfg(debug_assertions)] { let must_be_zero = eval_polynomial(&l_x.values[..], *u); assert_eq!(must_be_zero, E::Scalar::zero()); diff --git a/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs b/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs index 75626d74c6..77861867bc 100644 --- a/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs +++ b/halo2_proofs/src/poly/kzg/multiopen/shplonk/verifier.rs @@ -1,4 +1,5 @@ use std::fmt::Debug; +use std::hash::Hash; use std::io::Read; use super::ChallengeY; @@ -7,6 +8,7 @@ use crate::arithmetic::{ eval_polynomial, evaluate_vanishing_polynomial, lagrange_interpolate, powers, CurveAffine, FieldExt, }; +use crate::helpers::SerdeCurveAffine; use crate::poly::commitment::Verifier; use crate::poly::commitment::MSM; use crate::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; @@ -33,8 +35,12 @@ pub struct VerifierSHPLONK<'params, E: Engine> { params: &'params ParamsKZG, } -impl<'params, E: MultiMillerLoop + Debug> Verifier<'params, KZGCommitmentScheme> - for VerifierSHPLONK<'params, E> +impl<'params, E> Verifier<'params, KZGCommitmentScheme> for VerifierSHPLONK<'params, E> +where + E: MultiMillerLoop + Debug, + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, + E::Scalar: Hash, { type Guard = GuardKZG<'params, E>; type MSMAccumulator = DualMSM<'params, E>; diff --git a/halo2_proofs/src/poly/kzg/strategy.rs b/halo2_proofs/src/poly/kzg/strategy.rs index 896760067d..ca4b4fb18a 100644 --- a/halo2_proofs/src/poly/kzg/strategy.rs +++ b/halo2_proofs/src/poly/kzg/strategy.rs @@ -6,6 +6,7 @@ use super::{ multiopen::VerifierGWC, }; use crate::{ + helpers::SerdeCurveAffine, plonk::Error, poly::{ commitment::{Verifier, MSM}, @@ -29,7 +30,12 @@ pub struct GuardKZG<'params, E: MultiMillerLoop + Debug> { } /// Define accumulator type as `DualMSM` -impl<'params, E: MultiMillerLoop + Debug> Guard> for GuardKZG<'params, E> { +impl<'params, E> Guard> for GuardKZG<'params, E> +where + E: MultiMillerLoop + Debug, + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, +{ type MSMAccumulator = DualMSM<'params, E>; } @@ -85,6 +91,9 @@ impl< Guard = GuardKZG<'params, E>, >, > VerificationStrategy<'params, KZGCommitmentScheme, V> for AccumulatorStrategy<'params, E> +where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, { type Output = Self; @@ -120,6 +129,9 @@ impl< Guard = GuardKZG<'params, E>, >, > VerificationStrategy<'params, KZGCommitmentScheme, V> for SingleStrategy<'params, E> +where + E::G1Affine: SerdeCurveAffine, + E::G2Affine: SerdeCurveAffine, { type Output = (); diff --git a/halo2_proofs/src/poly/query.rs b/halo2_proofs/src/poly/query.rs index f13cc25a89..c596e6a71c 100644 --- a/halo2_proofs/src/poly/query.rs +++ b/halo2_proofs/src/poly/query.rs @@ -8,8 +8,8 @@ use crate::{ use ff::Field; use halo2curves::CurveAffine; -pub trait Query: Sized + Clone { - type Commitment: PartialEq + Copy; +pub trait Query: Sized + Clone + Send + Sync { + type Commitment: PartialEq + Copy + Send + Sync; type Eval: Clone + Default + Debug; fn get_point(&self) -> F; diff --git a/primitives/poseidon/.gitignore b/primitives/poseidon/.gitignore new file mode 100644 index 0000000000..869df07dae --- /dev/null +++ b/primitives/poseidon/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock \ No newline at end of file diff --git a/primitives/poseidon/.rustfmt.toml b/primitives/poseidon/.rustfmt.toml new file mode 100644 index 0000000000..606e29234d --- /dev/null +++ b/primitives/poseidon/.rustfmt.toml @@ -0,0 +1 @@ +wrap_comments = true \ No newline at end of file diff --git a/primitives/poseidon/Cargo.toml b/primitives/poseidon/Cargo.toml new file mode 100644 index 0000000000..afd41baec9 --- /dev/null +++ b/primitives/poseidon/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "poseidon" +version = "0.2.0" +authors = ["kilic "] +edition = "2021" +license = "MIT OR Apache-2.0" + +[dependencies] +halo2curves = { path = "../../arithmetic/curves" } +group = "0.12" +subtle = { version = "2.3", default-features = false } + +[dev-dependencies] +rand_core = { version = "0.6", default-features = false } diff --git a/primitives/poseidon/LICENSE-APACHE b/primitives/poseidon/LICENSE-APACHE new file mode 100644 index 0000000000..8e50fa5fe0 --- /dev/null +++ b/primitives/poseidon/LICENSE-APACHE @@ -0,0 +1,64 @@ +APACHE LICENSE +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +Definitions. + +“License” shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of this License; and +You must cause any modified files to carry prominent notices stating that You changed the files; and +(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + +You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[ ]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright 2022 Ethereum Foundation + +Licensed under the Apache License, Version 2.0 (the "License"); +You may not use this file except in compliance with the License. +You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. \ No newline at end of file diff --git a/primitives/poseidon/LICENSE-MIT b/primitives/poseidon/LICENSE-MIT new file mode 100644 index 0000000000..f29698d015 --- /dev/null +++ b/primitives/poseidon/LICENSE-MIT @@ -0,0 +1,9 @@ +MIT LICENSE + +Copyright 2022 Ethereum Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/primitives/poseidon/README.md b/primitives/poseidon/README.md new file mode 100644 index 0000000000..09e40fe852 --- /dev/null +++ b/primitives/poseidon/README.md @@ -0,0 +1,38 @@ +# `poseidon` + +`poseidon` is built to be used in SNARK and non native recursion friendly transcript for [appliedzkp/halo2](https://github.com/appliedzkp/halo2/). + +[Poseidon hash function](https://eprint.iacr.org/2019/458.pdf) implmenetation is in line with the reference and the [test vectors](https://extgit.iaik.tugraz.at/krypto/hadeshash/-/tree/master/code). It also uses optimized constants and sparse MDS matrices to reduce number of multiplications. For now constants are calculated in construction time they are planned to be hardcoded once transcript design matures. Currently only supports variable length hashing with $\alpha = 5$ sbox. Some parts of Poseidon implementation are adapted or ported from: + +* [filecoin-project/neptune](https://github.com/filecoin-project/neptune/tree/master/spec) +* [matter-labs/rescue-poseidon](https://github.com/matter-labs/rescue-poseidon) +* [zcash/halo2/halo2_gadgets](https://github.com/zcash/halo2/tree/main/halo2_gadgets) +* [dusk-network/Poseidon252](https://github.com/dusk-network/Poseidon252) + +## Example usage + +```rust +// Initialize a mutable hasher with constant capacity parameters +// and number of rounds arguments. This will also generate matrices +// and constants according to the specification +let mut hasher = Poseidon::::new(number_of_full_rounds, number_of_half_rounds); + +// In sake of the example we generate some dummy scalar inputs +let inputs = (0..number_of_inputs_0) + .map(|_| Fr::random(&mut rng)) + .collect::>(); + +// Feed inputs to the Absorption line +hasher.update(&inputs[..]); + +// Yield your challange with squeeze function +let challenge_alpha = hasher.squeeze(); + +// Then again ... +let inputs = (0..number_of_inputs_1) + .map(|_| Fr::random(&mut rng)) + .collect::>(); +hasher.update(&inputs[..]); +let challenge_beta = hasher.squeeze(); + +``` diff --git a/primitives/poseidon/src/grain.rs b/primitives/poseidon/src/grain.rs new file mode 100644 index 0000000000..0a5b1fd701 --- /dev/null +++ b/primitives/poseidon/src/grain.rs @@ -0,0 +1,161 @@ +use crate::spec::MDSMatrix; +use halo2curves::FieldExt; +use std::marker::PhantomData; + +/// Grain initializes round constants and MDS matrix at given sponge parameters +pub(super) struct Grain { + bit_sequence: Vec, + _field: PhantomData, +} + +impl Grain { + pub(crate) fn generate(r_f: usize, r_p: usize) -> (Vec<[F; T]>, MDSMatrix) { + debug_assert!(T > 1 && T == RATE + 1); + + // Support only prime field construction + const FIELD_TYPE: u8 = 1u8; + // Support only \alpha s-box + const SBOX_TYPE: u8 = 0; + + let field_size = F::NUM_BITS; + let n_bytes = F::Repr::default().as_ref().len(); + assert_eq!((field_size as f32 / 8.0).ceil() as usize, n_bytes); + assert_eq!(r_f % 2, 0); + + // Pseudo random number generation. See: + // Initialization of the Grain LFSR Used for Parameter Generation + // Supplementary Material Section F + // https://eprint.iacr.org/2019/458.pdf + let mut bit_sequence: Vec = Vec::new(); + append_bits(&mut bit_sequence, 2, FIELD_TYPE); + append_bits(&mut bit_sequence, 4, SBOX_TYPE); + append_bits(&mut bit_sequence, 12, field_size); + append_bits(&mut bit_sequence, 12, T as u32); + append_bits(&mut bit_sequence, 10, r_f as u16); + append_bits(&mut bit_sequence, 10, r_p as u16); + append_bits(&mut bit_sequence, 30, 0b111111111111111111111111111111u128); + debug_assert_eq!(bit_sequence.len(), 80); + + let mut grain: Grain = Grain { + bit_sequence, + _field: PhantomData, + }; + + for _ in 0..160 { + grain.new_bit(); + } + assert_eq!(grain.bit_sequence.len(), 80); + + let number_of_rounds = r_p as usize + r_f as usize; + let constants = (0..number_of_rounds) + .map(|_| { + let mut round_constants = [F::zero(); T]; + for c in round_constants.iter_mut() { + *c = grain.next_field_element(); + } + round_constants + }) + .collect::>(); + + let (mut xs, mut ys) = ([F::zero(); T], [F::zero(); T]); + for x in xs.iter_mut() { + *x = grain.next_field_element_without_rejection(); + } + for y in ys.iter_mut() { + *y = grain.next_field_element_without_rejection(); + } + + (constants, MDSMatrix::cauchy(&xs, &ys)) + } + + /// Credit: https://github.com/zcash/halo2/tree/main/halo2_gadgets/src/primitives/poseidon + /// Returns the next field element from this Grain instantiation. + pub(super) fn next_field_element(&mut self) -> F { + // Loop until we get an element in the field. + loop { + let mut bytes = F::Repr::default(); + + // Poseidon reference impl interprets the bits as a repr in MSB order, because + // it's easy to do that in Python. Meanwhile, our field elements all use LSB + // order. There's little motivation to diverge from the reference impl; these + // are all constants, so we aren't introducing big-endianness into the rest of + // the circuit (assuming unkeyed Poseidon, but we probably wouldn't want to + // implement Grain inside a circuit, so we'd use a different round constant + // derivation function there). + let view = bytes.as_mut(); + for (i, bit) in self.take(F::NUM_BITS as usize).enumerate() { + // If we diverged from the reference impl and interpreted the bits in LSB + // order, we would remove this line. + let i = F::NUM_BITS as usize - 1 - i; + + view[i / 8] |= if bit { 1 << (i % 8) } else { 0 }; + } + + if let Some(f) = F::from_repr_vartime(bytes) { + break f; + } + } + } + + /// Credit: https://github.com/zcash/halo2/tree/main/halo2_gadgets/src/primitives/poseidon + /// Returns the next field element from this Grain instantiation, without + /// using rejection sampling. + pub(super) fn next_field_element_without_rejection(&mut self) -> F { + let mut bytes = [0u8; 64]; + + // Poseidon reference impl interprets the bits as a repr in MSB order, because + // it's easy to do that in Python. Additionally, it does not use rejection + // sampling in cases where the constants don't specifically need to be uniformly + // random for security. We do not provide APIs that take a field-element-sized + // array and reduce it modulo the field order, because those are unsafe APIs to + // offer generally (accidentally using them can lead to divergence in consensus + // systems due to not rejecting canonical forms). + // + // Given that we don't want to diverge from the reference implementation, we + // hack around this restriction by serializing the bits into a 64-byte + // array and then calling F::from_bytes_wide. PLEASE DO NOT COPY THIS + // INTO YOUR OWN CODE! + let view = bytes.as_mut(); + for (i, bit) in self.take(F::NUM_BITS as usize).enumerate() { + // If we diverged from the reference impl and interpreted the bits in LSB + // order, we would remove this line. + let i = F::NUM_BITS as usize - 1 - i; + + view[i / 8] |= if bit { 1 << (i % 8) } else { 0 }; + } + + F::from_bytes_wide(&bytes) + } + + fn new_bit(&mut self) -> bool { + // See supplementary material Section F. Step 2. + // https://eprint.iacr.org/2019/458.pdf + let new_bit = vec![62, 51, 38, 23, 13usize] + .iter() + .fold(self.bit_sequence[0], |acc, pos| { + acc ^ self.bit_sequence[*pos] + }); + assert_eq!(self.bit_sequence.len(), 80); + self.bit_sequence.remove(0); + self.bit_sequence.push(new_bit); + new_bit + } +} + +impl Iterator for Grain { + type Item = bool; + + fn next(&mut self) -> Option { + while !self.new_bit() { + self.new_bit(); + } + Some(self.new_bit()) + } +} + +fn append_bits>(vec: &mut Vec, n: usize, from: T) { + let val = from.into() as u128; + for i in (0..n).rev() { + vec.push((val >> i) & 1 != 0); + } +} diff --git a/primitives/poseidon/src/lib.rs b/primitives/poseidon/src/lib.rs new file mode 100644 index 0000000000..492a77b1ad --- /dev/null +++ b/primitives/poseidon/src/lib.rs @@ -0,0 +1,14 @@ +//! Poseidon hashing implemention with variable lenght input setting. This crate +//! also exposes constant parameters for circuit implementations + +#![deny(missing_debug_implementations)] +#![deny(missing_docs)] + +mod grain; +mod matrix; +mod permutation; +mod poseidon; +mod spec; + +pub use crate::poseidon::Poseidon; +pub use crate::spec::{MDSMatrices, MDSMatrix, SparseMDSMatrix, Spec, State}; diff --git a/primitives/poseidon/src/matrix.rs b/primitives/poseidon/src/matrix.rs new file mode 100644 index 0000000000..d29770b90f --- /dev/null +++ b/primitives/poseidon/src/matrix.rs @@ -0,0 +1,145 @@ +//! Most of these operations here are not suitable for general purpose matrix +//! operations. Besides vector multiplication other operations are presented +//! with the intention of construction of parameters and are not used in the +//! actual permutation process. + +use halo2curves::FieldExt; + +#[derive(PartialEq, Debug, Clone)] +pub(crate) struct Matrix(pub(crate) [[F; T]; T]); + +impl Default for Matrix { + fn default() -> Self { + Matrix([[F::zero(); T]; T]) + } +} + +impl Matrix { + #[inline] + pub(crate) fn zero_matrix() -> Self { + Self([[F::zero(); T]; T]) + } + + #[inline] + pub(crate) fn identity() -> Self { + let mut m = Self::zero_matrix(); + for i in 0..T { + m.set(i, i, F::one()) + } + m + } + + pub(crate) fn set(&mut self, row: usize, col: usize, value: F) { + self.0[row][col] = value; + } + + pub(crate) fn from_vec(vec: Vec>) -> Self { + let n = vec.len(); + // Expect square and well formed matrix + for row in vec.iter() { + assert_eq!(row.len(), n); + } + + let mut result = Self::default(); + for (row_result, row_inverted) in result.0.iter_mut().zip(vec.iter()) { + for (result_cell, cell) in row_result.iter_mut().zip(row_inverted.iter()) { + *result_cell = *cell + } + } + result + } + + pub(crate) fn transpose(&self) -> Self { + let mut result = Self::default(); + for (i, row) in self.0.iter().enumerate() { + for (j, e) in row.iter().enumerate() { + result.0[j][i] = *e + } + } + result + } + + pub(crate) fn mul(&self, other: &Self) -> Self { + let mut result = Self::default(); + for i in 0..T { + for j in 0..T { + for k in 0..T { + result.0[i][j] += self.0[i][k] * other.0[k][j]; + } + } + } + result + } + + pub(crate) fn mul_vector(&self, v: &[F; T]) -> [F; T] { + let mut result = [F::zero(); T]; + for (row, cell) in self.0.iter().zip(result.iter_mut()) { + for (a_i, v_i) in row.iter().zip(v.iter()) { + *cell += *v_i * *a_i; + } + } + result + } + + // This is very pesky implementation of matrix inversion, + // It won't even alarm when a matrix is not invertable. + pub(crate) fn invert(&self) -> Self { + let identity = Self::identity(); + + let mut m: Vec> = identity + .0 + .iter() + .zip(self.0.iter()) + .map(|(u_row, v_row)| { + let mut row = v_row.to_vec(); + row.extend(u_row.to_vec()); + row + }) + .collect(); + + for i in 0..T { + for j in 0..T { + if i != j { + let r = m[j][i] * m[i][i].invert().unwrap(); + for k in 0..2 * T { + let e = m[i][k]; + m[j][k] -= r * e; + } + } + } + } + + let mut res = Self::default(); + for (i, row) in m.iter_mut().enumerate().take(T) { + for j in T..2 * T { + let e = row[i]; + row[j] *= e.invert().unwrap() + } + } + + for (i, row) in m.iter().enumerate().take(T) { + for j in 0..T { + res.set(i, j, row[j + T]); + } + } + res + } + + #[inline] + pub(crate) fn w(&self) -> [F; RATE] { + assert_eq!(RATE + 1, T); + self.0 + .iter() + .skip(1) + .map(|row| row[0]) + .collect::>() + .try_into() + .unwrap() + } + + #[inline] + pub(crate) fn sub(&self) -> Matrix { + assert_eq!(RATE + 1, T); + Matrix::::from_vec(self.0.iter().skip(1).map(|row| row[1..].to_vec()).collect()) + } +} diff --git a/primitives/poseidon/src/permutation.rs b/primitives/poseidon/src/permutation.rs new file mode 100644 index 0000000000..2f7baf213a --- /dev/null +++ b/primitives/poseidon/src/permutation.rs @@ -0,0 +1,207 @@ +use crate::spec::{Spec, State}; +use halo2curves::FieldExt; + +impl Spec { + /// Applies the Poseidon permutation to the given state + pub fn permute(&self, state: &mut State) { + let r_f = self.r_f / 2; + + // First half of the full rounds + { + state.add_constants(&self.constants.start[0]); + for round_constants in self.constants.start.iter().skip(1).take(r_f - 1) { + state.sbox_full(); + state.add_constants(round_constants); + self.mds_matrices.mds.apply(state); + } + state.sbox_full(); + state.add_constants(self.constants.start.last().unwrap()); + self.mds_matrices.pre_sparse_mds.apply(state) + } + + // Partial rounds + { + for (round_constant, sparse_mds) in self + .constants + .partial + .iter() + .zip(self.mds_matrices.sparse_matrices.iter()) + { + state.sbox_part(); + state.add_constant(round_constant); + sparse_mds.apply(state); + } + } + + // Second half of the full rounds + { + for round_constants in self.constants.end.iter() { + state.sbox_full(); + state.add_constants(round_constants); + self.mds_matrices.mds.apply(state); + } + state.sbox_full(); + self.mds_matrices.mds.apply(state); + } + } +} + +#[cfg(test)] +mod tests { + use super::State; + use crate::spec::{tests::SpecRef, Spec}; + use group::ff::PrimeField; + use halo2curves::bn256::Fr; + use halo2curves::FieldExt; + + /// We want to keep unoptimized poseidion construction and permutation to + /// cross test with optimized one + impl SpecRef { + fn permute(&self, state: &mut State) { + let (r_f, r_p) = (self.r_f / 2, self.r_p); + + for constants in self.constants.iter().take(r_f) { + state.add_constants(constants); + state.sbox_full(); + self.mds.apply(state); + } + + for constants in self.constants.iter().skip(r_f).take(r_p) { + state.add_constants(constants); + state.sbox_part(); + self.mds.apply(state); + } + + for constants in self.constants.iter().skip(r_f + r_p) { + state.add_constants(constants); + state.sbox_full(); + self.mds.apply(state); + } + } + } + + #[test] + fn cross_test() { + use halo2curves::group::ff::Field; + use rand_core::OsRng; + use std::time::Instant; + + macro_rules! run_test { + ( + $([$RF:expr, $RP:expr, $T:expr, $RATE:expr]),* + ) => { + $( + { + const R_F: usize = $RF; + const R_P: usize = $RP; + const T: usize = $T; + const RATE: usize = $RATE; + let mut state = State( + (0..T) + .map(|_| Fr::random(OsRng)) + .collect::>() + .try_into().unwrap(), + ); + let spec = SpecRef::::new(R_F, R_P); + let mut state_expected = state.clone(); + spec.permute(&mut state_expected); + + let spec = Spec::::new(R_F, R_P); + let now = Instant::now(); + { + spec.permute(&mut state); + } + let elapsed = now.elapsed(); + println!("Elapsed: {:.2?}", elapsed); + assert_eq!(state_expected, state); + } + )* + }; + } + run_test!([8, 57, 3, 2]); + run_test!([8, 57, 4, 3]); + run_test!([8, 57, 5, 4]); + run_test!([8, 57, 6, 5]); + run_test!([8, 57, 7, 6]); + run_test!([8, 57, 8, 7]); + run_test!([8, 57, 9, 8]); + run_test!([8, 57, 10, 9]); + } + + #[test] + fn test_against_test_vectors() { + // https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/test_vectors.txt + // poseidonperm_x5_254_3 + { + const R_F: usize = 8; + const R_P: usize = 57; + const T: usize = 3; + const RATE: usize = 2; + + let state = State( + vec![0u64, 1, 2] + .into_iter() + .map(Fr::from) + .collect::>() + .try_into() + .unwrap(), + ); + + let spec_ref = SpecRef::::new(R_F, R_P); + let mut state_0 = state.clone(); + + spec_ref.permute(&mut state_0); + let expected = vec![ + "7853200120776062878684798364095072458815029376092732009249414926327459813530", + "7142104613055408817911962100316808866448378443474503659992478482890339429929", + "6549537674122432311777789598043107870002137484850126429160507761192163713804", + ]; + for (word, expected) in state_0.words().into_iter().zip(expected.iter()) { + assert_eq!(word, Fr::from_str_vartime(expected).unwrap()); + } + + let spec = Spec::::new(R_F, R_P); + let mut state_1 = state; + spec.permute(&mut state_1); + assert_eq!(state_0, state_1); + } + + // https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/test_vectors.txt + // poseidonperm_x5_254_5 + { + const R_F: usize = 8; + const R_P: usize = 60; + const T: usize = 5; + const RATE: usize = 4; + + let state = State( + vec![0u64, 1, 2, 3, 4] + .into_iter() + .map(Fr::from) + .collect::>() + .try_into() + .unwrap(), + ); + + let spec_ref = SpecRef::::new(R_F, R_P); + let mut state_0 = state.clone(); + + spec_ref.permute(&mut state_0); + let expected = vec![ + "18821383157269793795438455681495246036402687001665670618754263018637548127333", + "7817711165059374331357136443537800893307845083525445872661165200086166013245", + "16733335996448830230979566039396561240864200624113062088822991822580465420551", + "6644334865470350789317807668685953492649391266180911382577082600917830417726", + "3372108894677221197912083238087960099443657816445944159266857514496320565191", + ]; + for (word, expected) in state_0.words().into_iter().zip(expected.iter()) { + assert_eq!(word, Fr::from_str_vartime(expected).unwrap()); + } + + let spec = Spec::::new(R_F, R_P); + let mut state_1 = state; + spec.permute(&mut state_1); + assert_eq!(state_0, state_1); + } + } +} diff --git a/primitives/poseidon/src/poseidon.rs b/primitives/poseidon/src/poseidon.rs new file mode 100644 index 0000000000..90023e3da6 --- /dev/null +++ b/primitives/poseidon/src/poseidon.rs @@ -0,0 +1,187 @@ +use crate::{Spec, State}; +use halo2curves::FieldExt; + +/// Poseidon hasher that maintains state and inputs and yields single element +/// output when desired +#[derive(Debug, Clone)] +pub struct Poseidon { + state: State, + spec: Spec, + absorbing: Vec, +} + +impl Poseidon { + /// Constructs a clear state poseidon instance + pub fn new(r_f: usize, r_p: usize) -> Self { + Self { + spec: Spec::new(r_f, r_p), + state: State::default(), + absorbing: Vec::new(), + } + } + + /// Appends elements to the absorption line updates state while `RATE` is + /// full + pub fn update(&mut self, elements: &[F]) { + let mut input_elements = self.absorbing.clone(); + input_elements.extend_from_slice(elements); + + for chunk in input_elements.chunks(RATE) { + if chunk.len() < RATE { + // Must be the last iteration of this update. Feed unpermutaed inputs to the + // absorbation line + self.absorbing = chunk.to_vec(); + } else { + // Add new chunk of inputs for the next permutation cycle. + for (input_element, state) in chunk.iter().zip(self.state.0.iter_mut().skip(1)) { + state.add_assign(input_element); + } + // Perform intermediate permutation + self.spec.permute(&mut self.state); + // Flush the absorption line + self.absorbing.clear(); + } + } + } + + /// Results a single element by absorbing already added inputs + pub fn squeeze(&mut self) -> F { + let mut last_chunk = self.absorbing.clone(); + { + // Expect padding offset to be in [0, RATE) + debug_assert!(last_chunk.len() < RATE); + } + // Add the finishing sign of the variable length hashing. Note that this mut + // also apply when absorbing line is empty + last_chunk.push(F::one()); + // Add the last chunk of inputs to the state for the final permutation cycle + + for (input_element, state) in last_chunk.iter().zip(self.state.0.iter_mut().skip(1)) { + state.add_assign(input_element); + } + + // Perform final permutation + self.spec.permute(&mut self.state); + // Flush the absorption line + self.absorbing.clear(); + // Returns the challenge while preserving internal state + self.state.result() + } +} + +#[test] +fn test_padding() { + use group::ff::Field; + use halo2curves::bn256::Fr; + + const R_F: usize = 8; + const R_P: usize = 57; + const T: usize = 5; + const RATE: usize = 4; + + use rand_core::OsRng; + + // w/o extra permutation + { + let mut poseidon = Poseidon::::new(R_F, R_P); + let number_of_permutation = 5; + let number_of_inputs = RATE * number_of_permutation - 1; + let inputs = (0..number_of_inputs) + .map(|_| Fr::random(OsRng)) + .collect::>(); + poseidon.update(&inputs[..]); + let result_0 = poseidon.squeeze(); + + let spec = poseidon.spec.clone(); + let mut inputs = inputs.clone(); + inputs.push(Fr::one()); + assert!(inputs.len() % RATE == 0); + let mut state = State::::default(); + for chunk in inputs.chunks(RATE) { + let mut inputs = vec![Fr::zero()]; + inputs.extend_from_slice(chunk); + state.add_constants(&inputs.try_into().unwrap()); + spec.permute(&mut state) + } + let result_1 = state.result(); + + assert_eq!(result_0, result_1); + } + + // w/ extra permutation + { + let mut poseidon = Poseidon::::new(R_F, R_P); + let number_of_permutation = 5; + let number_of_inputs = RATE * number_of_permutation; + let inputs = (0..number_of_inputs) + .map(|_| Fr::random(OsRng)) + .collect::>(); + poseidon.update(&inputs[..]); + let result_0 = poseidon.squeeze(); + + let spec = poseidon.spec.clone(); + let mut inputs = inputs.clone(); + let mut extra_padding = vec![Fr::zero(); RATE]; + extra_padding[0] = Fr::one(); + inputs.extend(extra_padding); + + assert!(inputs.len() % RATE == 0); + let mut state = State::::default(); + for chunk in inputs.chunks(RATE) { + let mut inputs = vec![Fr::zero()]; + inputs.extend_from_slice(chunk); + state.add_constants(&inputs.try_into().unwrap()); + spec.permute(&mut state) + } + let result_1 = state.result(); + + assert_eq!(result_0, result_1); + } + + // Much generic comparision + fn run() { + for number_of_iters in 1..25 { + let mut poseidon = Poseidon::::new(R_F, R_P); + + let mut inputs = vec![]; + for number_of_inputs in 0..=number_of_iters { + let chunk = (0..number_of_inputs) + .map(|_| Fr::random(OsRng)) + .collect::>(); + poseidon.update(&chunk[..]); + inputs.extend(chunk); + } + let result_0 = poseidon.squeeze(); + + // Accept below as reference and check consistency + inputs.push(Fr::one()); + let offset = inputs.len() % RATE; + if offset != 0 { + inputs.extend(vec![Fr::zero(); RATE - offset]); + } + + let spec = poseidon.spec.clone(); + let mut state = State::::default(); + for chunk in inputs.chunks(RATE) { + // First element is zero + let mut round_inputs = vec![Fr::zero()]; + // Round inputs must be T sized now + round_inputs.extend_from_slice(chunk); + + state.add_constants(&round_inputs.try_into().unwrap()); + spec.permute(&mut state) + } + let result_1 = state.result(); + assert_eq!(result_0, result_1); + } + } + + run::<3, 2>(); + run::<4, 3>(); + run::<5, 4>(); + run::<6, 5>(); + run::<7, 6>(); + run::<8, 7>(); + run::<9, 8>(); + run::<10, 9>(); +} diff --git a/primitives/poseidon/src/spec.rs b/primitives/poseidon/src/spec.rs new file mode 100644 index 0000000000..71992d334e --- /dev/null +++ b/primitives/poseidon/src/spec.rs @@ -0,0 +1,424 @@ +use std::ops::Index; + +use crate::{grain::Grain, matrix::Matrix}; +use halo2curves::FieldExt; + +/// `State` is structure `T` sized field elements that are subjected to +/// permutation +#[derive(Clone, Debug, PartialEq)] +pub struct State(pub(crate) [F; T]); + +impl Default for State { + /// The capacity value is 2**64 + (o − 1) where o the output length. + fn default() -> Self { + let mut state = [F::zero(); T]; + state[0] = F::from_u128(1 << 64); + State(state) + } +} + +impl State { + /// Applies sbox for all elements of the state. + /// Only supports `alpha = 5` sbox case. + pub(crate) fn sbox_full(&mut self) { + for e in self.0.iter_mut() { + let tmp = e.mul(*e); + e.mul_assign(tmp); + e.mul_assign(tmp); + } + } + + /// Partial round sbox applies sbox to the first element of the state. + /// Only supports `alpha = 5` sbox case + pub(crate) fn sbox_part(&mut self) { + let tmp = self.0[0].mul(self.0[0]); + self.0[0].mul_assign(tmp); + self.0[0].mul_assign(tmp); + } + + /// Adds constants to all elements of the state + pub(crate) fn add_constants(&mut self, constants: &[F; T]) { + for (e, constant) in self.0.iter_mut().zip(constants.iter()) { + e.add_assign(constant) + } + } + + /// Only adds a constant to the first element of the state.It is used with + /// optimized rounds constants where only single element is added in + /// each partial round + pub(crate) fn add_constant(&mut self, constant: &F) { + self.0[0].add_assign(constant) + } + + /// Copies elements of the state + pub fn words(&self) -> [F; T] { + self.0 + } + + /// Second element of the state is the result + pub(crate) fn result(&self) -> F { + self.0[1] + } +} + +/// `Spec` holds construction parameters as well as constants that are used in +/// permutation step. Constants are planned to be hardcoded once transcript +/// design matures. Number of partial rounds can be deriven from number of +/// constants. +#[derive(Debug, Clone)] +pub struct Spec { + pub(crate) r_f: usize, + pub(crate) mds_matrices: MDSMatrices, + pub(crate) constants: OptimizedConstants, +} + +impl Spec { + /// Number of full rounds + pub fn r_f(&self) -> usize { + self.r_f.clone() + } + /// Set of MDS Matrices used in permutation line + pub fn mds_matrices(&self) -> &MDSMatrices { + &self.mds_matrices + } + /// Optimised round constants + pub fn constants(&self) -> &OptimizedConstants { + &self.constants + } +} + +/// `OptimizedConstants` has round constants that are added each round. While +/// full rounds has T sized constants there is a single constant for each +/// partial round +#[derive(Debug, Clone)] +pub struct OptimizedConstants { + pub(crate) start: Vec<[F; T]>, + pub(crate) partial: Vec, + pub(crate) end: Vec<[F; T]>, +} + +impl OptimizedConstants { + /// Returns rounds constants for first part of full rounds + pub fn start(&self) -> &Vec<[F; T]> { + &self.start + } + + /// Returns rounds constants for partial rounds + pub fn partial(&self) -> &Vec { + &self.partial + } + + /// Returns rounds constants for second part of full rounds + pub fn end(&self) -> &Vec<[F; T]> { + &self.end + } +} + +/// `MDSMatrices` holds the MDS matrix as well as transition matrix which is +/// also called `pre_sparse_mds` and sparse matrices that enables us to reduce +/// number of multiplications in apply MDS step +#[derive(Debug, Clone)] +pub struct MDSMatrices { + pub(crate) mds: MDSMatrix, + pub(crate) pre_sparse_mds: MDSMatrix, + pub(crate) sparse_matrices: Vec>, +} + +impl MDSMatrices { + /// Returns original MDS matrix + pub fn mds(&self) -> &MDSMatrix { + &self.mds + } + + /// Returns transition matrix for sparse trick + pub fn pre_sparse_mds(&self) -> &MDSMatrix { + &self.pre_sparse_mds + } + + /// Returns sparse matrices for partial rounds + pub fn sparse_matrices(&self) -> &Vec> { + &self.sparse_matrices + } +} + +/// `MDSMatrix` is applied to `State` to achive linear layer of Poseidon +#[derive(Clone, Debug)] +pub struct MDSMatrix(pub(crate) Matrix); + +impl Index for MDSMatrix { + type Output = [F; T]; + + fn index(&self, idx: usize) -> &Self::Output { + &self.0 .0[idx] + } +} + +impl MDSMatrix { + /// Applies `MDSMatrix` to the state + pub(crate) fn apply(&self, state: &mut State) { + state.0 = self.0.mul_vector(&state.0); + } + + /// Given two `T` sized vector constructs the `t * t` Cauchy matrix + pub(super) fn cauchy(xs: &[F; T], ys: &[F; T]) -> Self { + let mut m = Matrix::default(); + for (i, x) in xs.iter().enumerate() { + for (j, y) in ys.iter().enumerate() { + let sum = *x + *y; + debug_assert!(!sum.is_zero_vartime()); + m.set(i, j, sum.invert().unwrap()); + } + } + MDSMatrix(m) + } + + /// Inverts the MDS matrix + fn invert(&self) -> Self { + Self(self.0.invert()) + } + + /// Used in calculation of optimized round constants. Calculates `v' = M * + /// v` where vectors are `T` sized + fn mul_constants(&self, v: &[F; T]) -> [F; T] { + self.0.mul_vector(v) + } + + /// Multiplies two MDS matrices. Used in sparse matrix calculations + fn mul(&self, other: &Self) -> Self { + Self(self.0.mul(&other.0)) + } + + fn transpose(&self) -> Self { + Self(self.0.transpose()) + } + + /// See Section B in Supplementary Material https://eprint.iacr.org/2019/458.pdf + /// Factorises an MDS matrix `M` into `M'` and `M''` where `M = M' * M''`. + /// Resulted `M''` matrices are the sparse ones while `M'` will contribute + /// to the accumulator of the process + fn factorise(&self) -> (Self, SparseMDSMatrix) { + // Given `(t-1 * t-1)` MDS matrix called `hat` constructs the matrix in + // form `[[1 | 0], [0 | m]]` + let prime = |hat: Matrix| -> MDSMatrix { + let mut prime = Matrix::identity(); + for (prime_row, hat_row) in prime.0.iter_mut().skip(1).zip(hat.0.iter()) { + for (el_prime, el_hat) in prime_row.iter_mut().skip(1).zip(hat_row.iter()) { + *el_prime = *el_hat; + } + } + Self(prime) + }; + + // Given `(t-1)` sized `w_hat` vector constructs the matrix in form + // `[[m_0_0 | m_0_i], [w_hat | identity]]` + let prime_prime = |w_hat: [F; RATE]| -> Self { + let mut prime_prime = Matrix::identity(); + prime_prime.0[0] = self.0 .0[0]; + for (row, w) in prime_prime.0.iter_mut().skip(1).zip(w_hat.iter()) { + row[0] = *w + } + Self(prime_prime) + }; + + let w = self.0.w(); + let m_hat = self.0.sub::(); + let m_hat_inverse = m_hat.invert(); + let w_hat = m_hat_inverse.mul_vector(&w); + (prime(m_hat), prime_prime(w_hat).transpose().into()) + } + + /// Returns rows of the MDS matrix + pub fn rows(&self) -> [[F; T]; T] { + self.0 .0 + } +} + +/// `SparseMDSMatrix` are in `[row], [hat | identity]` form and used in linear +/// layer of partial rounds instead of the original MDS +#[derive(Debug, Clone)] +pub struct SparseMDSMatrix { + pub(crate) row: [F; T], + pub(crate) col_hat: [F; RATE], +} + +impl SparseMDSMatrix { + /// Returns the first row + pub fn row(&self) -> &[F; T] { + &self.row + } + + /// Returns the first column without first element in the first row + pub fn col_hat(&self) -> &[F; RATE] { + &self.col_hat + } + + /// Applies the sparse MDS matrix to the state + pub(crate) fn apply(&self, state: &mut State) { + let words = state.words(); + state.0[0] = self + .row + .iter() + .zip(words.iter()) + .fold(F::zero(), |acc, (e, cell)| acc + (*e * *cell)); + + for ((new_word, col_el), word) in (state.0) + .iter_mut() + .skip(1) + .zip(self.col_hat.iter()) + .zip(words.iter().skip(1)) + { + *new_word = *col_el * words[0] + word; + } + } +} + +impl From> + for SparseMDSMatrix +{ + /// Assert the form and represent an MDS matrix as a sparse MDS matrix + fn from(mds: MDSMatrix) -> Self { + let mds = mds.0; + for (i, row) in mds.0.iter().enumerate().skip(1) { + for (j, _) in row.iter().enumerate().skip(1) { + assert_eq!(row[j], if i != j { F::zero() } else { F::one() }); + } + } + + let (mut row, mut col_hat) = ([F::zero(); T], [F::zero(); RATE]); + for (row_el, el) in row.iter_mut().zip(mds.0[0].iter()) { + *row_el = *el + } + for (col_el, row) in col_hat.iter_mut().zip(mds.0.iter().skip(1)) { + *col_el = row[0] + } + + SparseMDSMatrix { row, col_hat } + } +} + +impl Spec { + /// Given number of round parameters constructs new Posedion instance + /// calculating unoptimized round constants with reference `Grain` then + /// calculates optimized constants and sparse matrices + pub fn new(r_f: usize, r_p: usize) -> Self { + let (unoptimized_constants, mds) = Grain::generate(r_f, r_p); + let constants = Self::calculate_optimized_constants(r_f, r_p, unoptimized_constants, &mds); + let (sparse_matrices, pre_sparse_mds) = Self::calculate_sparse_matrices(r_p, &mds); + + Self { + r_f, + constants, + mds_matrices: MDSMatrices { + mds, + sparse_matrices, + pre_sparse_mds, + }, + } + } + + fn calculate_optimized_constants( + r_f: usize, + r_p: usize, + constants: Vec<[F; T]>, + mds: &MDSMatrix, + ) -> OptimizedConstants { + let inverse_mds = mds.invert(); + let (number_of_rounds, r_f_half) = (r_f + r_p, r_f / 2); + assert_eq!(constants.len(), number_of_rounds); + + // Calculate optimized constants for first half of the full rounds + let mut constants_start: Vec<[F; T]> = vec![[F::zero(); T]; r_f_half]; + constants_start[0] = constants[0].clone(); + for (optimized, constants) in constants_start + .iter_mut() + .skip(1) + .zip(constants.iter().skip(1)) + { + *optimized = inverse_mds.mul_constants(constants); + } + + // Calculate constants for partial rounds + let mut acc = constants[r_f_half + r_p].clone(); + let mut constants_partial = vec![F::zero(); r_p]; + for (optimized, constants) in constants_partial + .iter_mut() + .rev() + .zip(constants.iter().skip(r_f_half).rev().skip(r_f_half)) + { + let mut tmp = inverse_mds.mul_constants(&acc); + *optimized = tmp[0]; + + tmp[0] = F::zero(); + for ((acc, tmp), constant) in acc + .iter_mut() + .zip(tmp.into_iter()) + .zip(constants.into_iter()) + { + *acc = tmp + constant + } + } + constants_start.push(inverse_mds.mul_constants(&acc)); + + // Calculate optimized constants for ending half of the full rounds + let mut constants_end: Vec<[F; T]> = vec![[F::zero(); T]; r_f_half - 1]; + for (optimized, constants) in constants_end + .iter_mut() + .zip(constants.iter().skip(r_f_half + r_p + 1)) + { + *optimized = inverse_mds.mul_constants(constants); + } + + OptimizedConstants { + start: constants_start, + partial: constants_partial, + end: constants_end, + } + } + + fn calculate_sparse_matrices( + r_p: usize, + mds: &MDSMatrix, + ) -> (Vec>, MDSMatrix) { + let mds = mds.transpose(); + let mut acc = mds.clone(); + let mut sparse_matrices = (0..r_p) + .map(|_| { + let (m_prime, m_prime_prime) = acc.factorise(); + acc = mds.mul(&m_prime); + m_prime_prime + }) + .collect::>>(); + + sparse_matrices.reverse(); + (sparse_matrices, acc.transpose()) + } +} + +#[cfg(test)] +pub(super) mod tests { + use halo2curves::FieldExt; + + use super::MDSMatrix; + use crate::grain::Grain; + + /// We want to keep unoptimized parameters to cross test with optimized one + pub(crate) struct SpecRef { + pub(crate) r_f: usize, + pub(crate) r_p: usize, + pub(crate) mds: MDSMatrix, + pub(crate) constants: Vec<[F; T]>, + } + + impl SpecRef { + pub(crate) fn new(r_f: usize, r_p: usize) -> Self { + let (constants, mds) = Grain::generate(r_f, r_p); + + SpecRef { + r_f, + r_p, + mds, + constants, + } + } + } +} diff --git a/rust-toolchain b/rust-toolchain index af92bdd9f5..51ab475956 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.63.0 +nightly-2022-10-28 \ No newline at end of file