mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-01-09 01:03:08 +00:00
Merge branch 'main' into jacqui/witness-generation
This commit is contained in:
commit
206f527338
@ -6,6 +6,9 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- "**"
|
||||
workflow_dispatch:
|
||||
branches:
|
||||
- "**"
|
||||
|
||||
jobs:
|
||||
test:
|
||||
@ -21,7 +24,7 @@ jobs:
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
toolchain: nightly-2022-11-23
|
||||
override: true
|
||||
|
||||
- name: rust-cache
|
||||
@ -57,7 +60,7 @@ jobs:
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: nightly
|
||||
toolchain: nightly-2022-11-23
|
||||
override: true
|
||||
components: rustfmt, clippy
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
[workspace]
|
||||
members = ["field", "insertion", "plonky2", "starky", "system_zero", "util", "waksman", "ecdsa", "u32", "evm", "maybe_rayon"]
|
||||
members = ["ecdsa", "evm", "field", "insertion", "maybe_rayon", "plonky2", "starky", "system_zero", "u32", "util", "waksman"]
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
|
||||
@ -47,7 +47,11 @@ Jemalloc is known to cause crashes when a binary compiled for x86 is run on an A
|
||||
As this is a monorepo, see the individual crates within for license information.
|
||||
|
||||
|
||||
## Disclaimer
|
||||
## Security
|
||||
|
||||
This code has not yet been audited, and should not be used in any production systems.
|
||||
|
||||
While Plonky2 is configurable, its defaults generally target 100 bits of security. The default FRI configuration targets 100 bits of *conjectured* security based on the conjecture in [ethSTARK](https://eprint.iacr.org/2021/582).
|
||||
|
||||
Plonky2's default hash function is Poseidon, configured with 8 full rounds, 22 partial rounds, a width of 12 field elements (each ~64 bits), and an S-box of `x^7`. [BBLP22](https://tosc.iacr.org/index.php/ToSC/article/view/9850) suggests that this configuration may have around 95 bits of security, falling a bit short of our 100 bit target.
|
||||
|
||||
|
||||
@ -3,16 +3,17 @@ name = "plonky2_ecdsa"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[features]
|
||||
parallel = ["maybe_rayon/parallel", "plonky2/parallel"]
|
||||
|
||||
[dependencies]
|
||||
plonky2 = { path = "../plonky2" }
|
||||
plonky2_util = { path = "../util" }
|
||||
plonky2_field = { path = "../field" }
|
||||
plonky2_u32 = { path = "../u32" }
|
||||
num = "0.4.0"
|
||||
itertools = "0.10.0"
|
||||
rayon = "1.5.1"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
anyhow = "1.0.40"
|
||||
rand = "0.8.4"
|
||||
anyhow = { version = "1.0.40", default-features = false }
|
||||
itertools = { version = "0.10.0", default-features = false }
|
||||
maybe_rayon = { path = "../maybe_rayon", default-features = false }
|
||||
num = { version = "0.4.0", default-features = false }
|
||||
plonky2 = { path = "../plonky2", default-features = false }
|
||||
plonky2_u32 = { path = "../u32", default-features = false }
|
||||
serde = { version = "1.0", default-features = false, features = ["derive"] }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { version = "0.8.4", default-features = false, features = ["getrandom"] }
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use std::ops::Add;
|
||||
use core::ops::Add;
|
||||
|
||||
use plonky2_field::ops::Square;
|
||||
use plonky2_field::types::Field;
|
||||
use plonky2::field::ops::Square;
|
||||
use plonky2::field::types::Field;
|
||||
|
||||
use crate::curve::curve_types::{AffinePoint, Curve, ProjectivePoint};
|
||||
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use itertools::Itertools;
|
||||
use plonky2_field::types::Field;
|
||||
use plonky2_field::types::PrimeField;
|
||||
use rayon::prelude::*;
|
||||
use maybe_rayon::*;
|
||||
use plonky2::field::types::{Field, PrimeField};
|
||||
|
||||
use crate::curve::curve_summation::affine_multisummation_best;
|
||||
use crate::curve::curve_types::{AffinePoint, Curve, ProjectivePoint};
|
||||
@ -186,13 +187,12 @@ pub(crate) fn to_digits<C: Curve>(x: &C::ScalarField, w: usize) -> Vec<usize> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use num::BigUint;
|
||||
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2_field::types::Field;
|
||||
use plonky2_field::types::PrimeField;
|
||||
use alloc::vec;
|
||||
|
||||
use crate::curve::curve_msm::{msm_execute, msm_precompute, to_digits};
|
||||
use crate::curve::curve_types::Curve;
|
||||
use num::BigUint;
|
||||
use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
|
||||
|
||||
use super::*;
|
||||
use crate::curve::secp256k1::Secp256K1;
|
||||
|
||||
#[test]
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use std::ops::Mul;
|
||||
use alloc::vec::Vec;
|
||||
use core::ops::Mul;
|
||||
|
||||
use plonky2_field::types::Field;
|
||||
use plonky2_field::types::PrimeField;
|
||||
use plonky2::field::types::{Field, PrimeField};
|
||||
|
||||
use crate::curve::curve_types::{Curve, CurveScalar, ProjectivePoint};
|
||||
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
use std::iter::Sum;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::iter::Sum;
|
||||
|
||||
use plonky2_field::ops::Square;
|
||||
use plonky2_field::types::Field;
|
||||
use plonky2::field::ops::Square;
|
||||
use plonky2::field::types::Field;
|
||||
|
||||
use crate::curve::curve_types::{AffinePoint, Curve, ProjectivePoint};
|
||||
|
||||
@ -188,10 +190,7 @@ pub fn affine_multisummation_batch_inversion<C: Curve>(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::curve::curve_summation::{
|
||||
affine_summation_batch_inversion, affine_summation_pairwise,
|
||||
};
|
||||
use crate::curve::curve_types::{Curve, ProjectivePoint};
|
||||
use super::*;
|
||||
use crate::curve::secp256k1::Secp256K1;
|
||||
|
||||
#[test]
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use std::ops::Neg;
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::Debug;
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::ops::Neg;
|
||||
|
||||
use plonky2_field::ops::Square;
|
||||
use plonky2_field::types::{Field, PrimeField};
|
||||
use plonky2::field::ops::Square;
|
||||
use plonky2::field::types::{Field, PrimeField};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// To avoid implementation conflicts from associated types,
|
||||
@ -123,7 +124,7 @@ impl<C: Curve> PartialEq for AffinePoint<C> {
|
||||
impl<C: Curve> Eq for AffinePoint<C> {}
|
||||
|
||||
impl<C: Curve> Hash for AffinePoint<C> {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
if self.zero {
|
||||
self.zero.hash(state);
|
||||
} else {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use plonky2_field::types::Field;
|
||||
use plonky2::field::types::{Field, Sample};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::curve::curve_msm::msm_parallel;
|
||||
@ -63,8 +63,8 @@ pub fn verify_message<C: Curve>(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2_field::types::Field;
|
||||
use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2::field::types::Sample;
|
||||
|
||||
use crate::curve::ecdsa::{sign_message, verify_message, ECDSASecretKey};
|
||||
use crate::curve::secp256k1::Secp256K1;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
use num::rational::Ratio;
|
||||
use num::BigUint;
|
||||
use plonky2_field::secp256k1_base::Secp256K1Base;
|
||||
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2_field::types::{Field, PrimeField};
|
||||
use plonky2::field::secp256k1_base::Secp256K1Base;
|
||||
use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2::field::types::{Field, PrimeField};
|
||||
|
||||
use crate::curve::curve_msm::msm_parallel;
|
||||
use crate::curve::curve_types::{AffinePoint, ProjectivePoint};
|
||||
@ -102,8 +102,8 @@ pub fn glv_mul(p: ProjectivePoint<Secp256K1>, k: Secp256K1Scalar) -> ProjectiveP
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2_field::types::Field;
|
||||
use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2::field::types::{Field, Sample};
|
||||
|
||||
use crate::curve::curve_types::{Curve, CurveScalar};
|
||||
use crate::curve::glv::{decompose_secp256k1_scalar, glv_mul, GLV_S};
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use plonky2_field::secp256k1_base::Secp256K1Base;
|
||||
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2_field::types::Field;
|
||||
use plonky2::field::secp256k1_base::Secp256K1Base;
|
||||
use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2::field::types::Field;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::curve::curve_types::{AffinePoint, Curve};
|
||||
@ -40,9 +40,8 @@ const SECP256K1_GENERATOR_Y: Secp256K1Base = Secp256K1Base([
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use num::BigUint;
|
||||
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2_field::types::Field;
|
||||
use plonky2_field::types::PrimeField;
|
||||
use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2::field::types::{Field, PrimeField};
|
||||
|
||||
use crate::curve::curve_types::{AffinePoint, Curve, ProjectivePoint};
|
||||
use crate::curve::secp256k1::Secp256K1;
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
use std::marker::PhantomData;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use num::{BigUint, Integer, Zero};
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::field::types::{PrimeField, PrimeField64};
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::generator::{GeneratedValues, SimpleGenerator};
|
||||
use plonky2::iop::target::{BoolTarget, Target};
|
||||
use plonky2::iop::witness::{PartitionWitness, Witness};
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_field::types::{PrimeField, PrimeField64};
|
||||
use plonky2_u32::gadgets::arithmetic_u32::{CircuitBuilderU32, U32Target};
|
||||
use plonky2_u32::gadgets::multiple_comparison::list_le_u32_circuit;
|
||||
use plonky2_u32::witness::{GeneratedValuesU32, WitnessU32};
|
||||
@ -346,11 +348,11 @@ impl<F: RichField + Extendable<D>, const D: usize> SimpleGenerator<F>
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
use num::{BigUint, FromPrimitive, Integer};
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
use plonky2::{
|
||||
iop::witness::PartialWitness,
|
||||
plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitConfig},
|
||||
};
|
||||
use rand::rngs::OsRng;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::gadgets::biguint::{CircuitBuilderBiguint, WitnessBigUint};
|
||||
@ -360,7 +362,7 @@ mod tests {
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = OsRng;
|
||||
|
||||
let x_value = BigUint::from_u128(rng.gen()).unwrap();
|
||||
let y_value = BigUint::from_u128(rng.gen()).unwrap();
|
||||
@ -390,7 +392,7 @@ mod tests {
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = OsRng;
|
||||
|
||||
let mut x_value = BigUint::from_u128(rng.gen()).unwrap();
|
||||
let mut y_value = BigUint::from_u128(rng.gen()).unwrap();
|
||||
@ -420,7 +422,7 @@ mod tests {
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = OsRng;
|
||||
|
||||
let x_value = BigUint::from_u128(rng.gen()).unwrap();
|
||||
let y_value = BigUint::from_u128(rng.gen()).unwrap();
|
||||
@ -450,7 +452,7 @@ mod tests {
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = OsRng;
|
||||
|
||||
let x_value = BigUint::from_u128(rng.gen()).unwrap();
|
||||
let y_value = BigUint::from_u128(rng.gen()).unwrap();
|
||||
@ -476,7 +478,7 @@ mod tests {
|
||||
const D: usize = 2;
|
||||
type C = PoseidonGoldilocksConfig;
|
||||
type F = <C as GenericConfig<D>>::F;
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = OsRng;
|
||||
|
||||
let mut x_value = BigUint::from_u128(rng.gen()).unwrap();
|
||||
let mut y_value = BigUint::from_u128(rng.gen()).unwrap();
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::field::types::Sample;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::target::BoolTarget;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_field::types::Field;
|
||||
|
||||
use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar};
|
||||
use crate::gadgets::nonnative::{CircuitBuilderNonNative, NonNativeTarget};
|
||||
@ -254,16 +257,16 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilderCurve<F, D>
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::ops::Neg;
|
||||
use core::ops::Neg;
|
||||
|
||||
use anyhow::Result;
|
||||
use plonky2::field::secp256k1_base::Secp256K1Base;
|
||||
use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2::field::types::{Field, Sample};
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
use plonky2_field::secp256k1_base::Secp256K1Base;
|
||||
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2_field::types::Field;
|
||||
|
||||
use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar};
|
||||
use crate::curve::secp256k1::Secp256K1;
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use num::BigUint;
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::hash::keccak::KeccakHash;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::config::{GenericHashOut, Hasher};
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_field::types::Field;
|
||||
|
||||
use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar};
|
||||
use crate::gadgets::curve::{AffinePointTarget, CircuitBuilderCurve};
|
||||
@ -66,13 +68,12 @@ pub fn fixed_base_curve_mul_circuit<C: Curve, F: RichField + Extendable<D>, cons
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2::field::types::{PrimeField, Sample};
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2_field::types::Field;
|
||||
use plonky2_field::types::PrimeField;
|
||||
|
||||
use crate::curve::curve_types::{Curve, CurveScalar};
|
||||
use crate::curve::secp256k1::Secp256K1;
|
||||
|
||||
@ -1,10 +1,12 @@
|
||||
use alloc::vec;
|
||||
|
||||
use num::BigUint;
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::hash::keccak::KeccakHash;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::config::{GenericHashOut, Hasher};
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_field::types::Field;
|
||||
|
||||
use crate::curve::curve_types::{Curve, CurveScalar};
|
||||
use crate::gadgets::curve::{AffinePointTarget, CircuitBuilderCurve};
|
||||
@ -79,12 +81,12 @@ pub fn curve_msm_circuit<C: Curve, F: RichField + Extendable<D>, const D: usize>
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2::field::types::Sample;
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2_field::types::Field;
|
||||
|
||||
use crate::curve::curve_types::{Curve, CurveScalar};
|
||||
use crate::curve::secp256k1::Secp256K1;
|
||||
|
||||
@ -1,13 +1,15 @@
|
||||
use std::marker::PhantomData;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use num::BigUint;
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::field::types::{Field, Sample};
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::hash::keccak::KeccakHash;
|
||||
use plonky2::iop::target::{BoolTarget, Target};
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::config::{GenericHashOut, Hasher};
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_field::types::Field;
|
||||
use plonky2_u32::gadgets::arithmetic_u32::{CircuitBuilderU32, U32Target};
|
||||
|
||||
use crate::curve::curve_types::{Curve, CurveScalar};
|
||||
@ -169,22 +171,18 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilderWindowedMul<F,
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::ops::Neg;
|
||||
use core::ops::Neg;
|
||||
|
||||
use anyhow::Result;
|
||||
use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2_field::types::Field;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::curve::curve_types::{Curve, CurveScalar};
|
||||
use super::*;
|
||||
use crate::curve::secp256k1::Secp256K1;
|
||||
use crate::gadgets::curve::CircuitBuilderCurve;
|
||||
use crate::gadgets::curve_windowed_mul::CircuitBuilderWindowedMul;
|
||||
use crate::gadgets::nonnative::CircuitBuilderNonNative;
|
||||
|
||||
#[test]
|
||||
fn test_random_access_curve_points() -> Result<()> {
|
||||
@ -206,7 +204,7 @@ mod tests {
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = OsRng;
|
||||
let access_index = rng.gen::<usize>() % num_points;
|
||||
|
||||
let access_index_target = builder.constant(F::from_canonical_usize(access_index));
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
use std::marker::PhantomData;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
||||
|
||||
use crate::curve::curve_types::Curve;
|
||||
use crate::curve::secp256k1::Secp256K1;
|
||||
@ -52,20 +52,14 @@ pub fn verify_message_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
use plonky2::field::types::Sample;
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2_field::types::Field;
|
||||
|
||||
use super::{ECDSAPublicKeyTarget, ECDSASignatureTarget};
|
||||
use crate::curve::curve_types::{Curve, CurveScalar};
|
||||
use super::*;
|
||||
use crate::curve::curve_types::CurveScalar;
|
||||
use crate::curve::ecdsa::{sign_message, ECDSAPublicKey, ECDSASecretKey, ECDSASignature};
|
||||
use crate::curve::secp256k1::Secp256K1;
|
||||
use crate::gadgets::curve::CircuitBuilderCurve;
|
||||
use crate::gadgets::ecdsa::verify_message_circuit;
|
||||
use crate::gadgets::nonnative::CircuitBuilderNonNative;
|
||||
|
||||
fn test_ecdsa_circuit_with_config(config: CircuitConfig) -> Result<()> {
|
||||
const D: usize = 2;
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
use std::marker::PhantomData;
|
||||
use alloc::vec::Vec;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::field::secp256k1_base::Secp256K1Base;
|
||||
use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2::field::types::{Field, PrimeField};
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::generator::{GeneratedValues, SimpleGenerator};
|
||||
use plonky2::iop::target::{BoolTarget, Target};
|
||||
use plonky2::iop::witness::PartitionWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_field::secp256k1_base::Secp256K1Base;
|
||||
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2_field::types::{Field, PrimeField};
|
||||
|
||||
use crate::curve::glv::{decompose_secp256k1_scalar, GLV_BETA, GLV_S};
|
||||
use crate::curve::secp256k1::Secp256K1;
|
||||
@ -132,12 +133,12 @@ impl<F: RichField + Extendable<D>, const D: usize> SimpleGenerator<F>
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2::field::types::Sample;
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2_field::types::Field;
|
||||
|
||||
use crate::curve::curve_types::{Curve, CurveScalar};
|
||||
use crate::curve::glv::glv_mul;
|
||||
|
||||
@ -1,17 +1,19 @@
|
||||
use std::marker::PhantomData;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use num::{BigUint, Integer, One, Zero};
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::field::types::{Field, PrimeField};
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::generator::{GeneratedValues, SimpleGenerator};
|
||||
use plonky2::iop::target::{BoolTarget, Target};
|
||||
use plonky2::iop::witness::PartitionWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2_field::types::PrimeField;
|
||||
use plonky2_field::{extension::Extendable, types::Field};
|
||||
use plonky2::util::ceil_div_usize;
|
||||
use plonky2_u32::gadgets::arithmetic_u32::{CircuitBuilderU32, U32Target};
|
||||
use plonky2_u32::gadgets::range_check::range_check_u32_circuit;
|
||||
use plonky2_u32::witness::GeneratedValuesU32;
|
||||
use plonky2_util::ceil_div_usize;
|
||||
|
||||
use crate::gadgets::biguint::{
|
||||
BigUintTarget, CircuitBuilderBiguint, GeneratedValuesBigUint, WitnessBigUint,
|
||||
@ -642,12 +644,12 @@ impl<F: RichField + Extendable<D>, const D: usize, FF: PrimeField> SimpleGenerat
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
use plonky2::field::secp256k1_base::Secp256K1Base;
|
||||
use plonky2::field::types::{Field, PrimeField, Sample};
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
use plonky2_field::secp256k1_base::Secp256K1Base;
|
||||
use plonky2_field::types::{Field, PrimeField};
|
||||
|
||||
use crate::gadgets::nonnative::CircuitBuilderNonNative;
|
||||
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
use std::marker::PhantomData;
|
||||
use alloc::vec::Vec;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use itertools::Itertools;
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::target::Target;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_field::types::Field;
|
||||
use plonky2_u32::gadgets::arithmetic_u32::{CircuitBuilderU32, U32Target};
|
||||
|
||||
use crate::gadgets::biguint::BigUintTarget;
|
||||
@ -96,15 +97,14 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilderSplit<F, D>
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
use plonky2::field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2::field::types::Sample;
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
|
||||
use plonky2_field::types::Field;
|
||||
|
||||
use super::*;
|
||||
use crate::gadgets::nonnative::{CircuitBuilderNonNative, NonNativeTarget};
|
||||
use crate::gadgets::split_nonnative::CircuitBuilderSplit;
|
||||
|
||||
#[test]
|
||||
fn test_split_nonnative() -> Result<()> {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#![allow(clippy::needless_range_loop)]
|
||||
// Below lint is currently broken and produces false positives.
|
||||
// TODO: Remove this override when Clippy is patched.
|
||||
#![allow(clippy::derive_partial_eq_without_eq)]
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub mod curve;
|
||||
pub mod gadgets;
|
||||
|
||||
@ -5,22 +5,22 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
plonky2 = { path = "../plonky2", default-features = false, features = ["rand", "timing"] }
|
||||
plonky2_util = { path = "../util" }
|
||||
eth_trie_utils = "0.4.0"
|
||||
anyhow = "1.0.40"
|
||||
env_logger = "0.9.0"
|
||||
eth_trie_utils = "0.4.0"
|
||||
ethereum-types = "0.14.0"
|
||||
hex = { version = "0.4.3", optional = true }
|
||||
hex-literal = "0.3.4"
|
||||
itertools = "0.10.3"
|
||||
keccak-hash = "0.10.0"
|
||||
log = "0.4.14"
|
||||
num = "0.4.0"
|
||||
maybe_rayon = { path = "../maybe_rayon" }
|
||||
num = "0.4.0"
|
||||
once_cell = "1.13.0"
|
||||
pest = "2.1.3"
|
||||
pest_derive = "2.1.0"
|
||||
plonky2 = { path = "../plonky2", default-features = false, features = ["timing"] }
|
||||
plonky2_util = { path = "../util" }
|
||||
rand = "0.8.5"
|
||||
rand_chacha = "0.3.1"
|
||||
ripemd = "0.1.3"
|
||||
|
||||
@ -161,7 +161,7 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::field::types::{Field, Sample};
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
@ -177,7 +177,7 @@ mod tests {
|
||||
type F = GoldilocksField;
|
||||
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25);
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::rand_from_rng(&mut rng));
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::sample(&mut rng));
|
||||
|
||||
// if `IS_ADD == 0`, then the constraints should be met even
|
||||
// if all values are garbage.
|
||||
@ -200,7 +200,7 @@ mod tests {
|
||||
type F = GoldilocksField;
|
||||
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25);
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::rand_from_rng(&mut rng));
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::sample(&mut rng));
|
||||
|
||||
// set `IS_ADD == 1` and ensure all constraints are satisfied.
|
||||
lv[IS_ADD] = F::ONE;
|
||||
|
||||
@ -6,12 +6,7 @@ use plonky2::field::extension::{Extendable, FieldExtension};
|
||||
use plonky2::field::packed::PackedField;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
|
||||
use crate::arithmetic::add;
|
||||
use crate::arithmetic::columns;
|
||||
use crate::arithmetic::compare;
|
||||
use crate::arithmetic::modular;
|
||||
use crate::arithmetic::mul;
|
||||
use crate::arithmetic::sub;
|
||||
use crate::arithmetic::{add, columns, compare, modular, mul, sub};
|
||||
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
|
||||
use crate::stark::Stark;
|
||||
use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars};
|
||||
|
||||
@ -22,25 +22,20 @@ pub const IS_ADD: usize = 0;
|
||||
pub const IS_MUL: usize = IS_ADD + 1;
|
||||
pub const IS_SUB: usize = IS_MUL + 1;
|
||||
pub const IS_DIV: usize = IS_SUB + 1;
|
||||
pub const IS_SDIV: usize = IS_DIV + 1;
|
||||
pub const IS_MOD: usize = IS_SDIV + 1;
|
||||
pub const IS_SMOD: usize = IS_MOD + 1;
|
||||
pub const IS_ADDMOD: usize = IS_SMOD + 1;
|
||||
pub const IS_MOD: usize = IS_DIV + 1;
|
||||
pub const IS_ADDMOD: usize = IS_MOD + 1;
|
||||
pub const IS_SUBMOD: usize = IS_ADDMOD + 1;
|
||||
pub const IS_MULMOD: usize = IS_SUBMOD + 1;
|
||||
pub const IS_LT: usize = IS_MULMOD + 1;
|
||||
pub const IS_GT: usize = IS_LT + 1;
|
||||
pub const IS_SLT: usize = IS_GT + 1;
|
||||
pub const IS_SGT: usize = IS_SLT + 1;
|
||||
pub const IS_SHL: usize = IS_SGT + 1;
|
||||
pub const IS_SHL: usize = IS_GT + 1;
|
||||
pub const IS_SHR: usize = IS_SHL + 1;
|
||||
pub const IS_SAR: usize = IS_SHR + 1;
|
||||
|
||||
const START_SHARED_COLS: usize = IS_SAR + 1;
|
||||
const START_SHARED_COLS: usize = IS_SHR + 1;
|
||||
|
||||
pub(crate) const ALL_OPERATIONS: [usize; 17] = [
|
||||
IS_ADD, IS_MUL, IS_SUB, IS_DIV, IS_SDIV, IS_MOD, IS_SMOD, IS_ADDMOD, IS_SUBMOD, IS_MULMOD,
|
||||
IS_LT, IS_GT, IS_SLT, IS_SGT, IS_SHL, IS_SHR, IS_SAR,
|
||||
pub(crate) const ALL_OPERATIONS: [usize; 12] = [
|
||||
IS_ADD, IS_MUL, IS_SUB, IS_DIV, IS_MOD, IS_ADDMOD, IS_SUBMOD, IS_MULMOD, IS_LT, IS_GT, IS_SHL,
|
||||
IS_SHR,
|
||||
];
|
||||
|
||||
/// Within the Arithmetic Unit, there are shared columns which can be
|
||||
|
||||
@ -35,8 +35,6 @@ pub(crate) fn generate<F: RichField>(lv: &mut [F; NUM_ARITH_COLUMNS], op: usize)
|
||||
IS_LT => u256_sub_br(input0, input1),
|
||||
// input1 - input0 == diff + br*2^256
|
||||
IS_GT => u256_sub_br(input1, input0),
|
||||
IS_SLT => todo!(),
|
||||
IS_SGT => todo!(),
|
||||
_ => panic!("op code not a comparison"),
|
||||
};
|
||||
|
||||
@ -162,7 +160,7 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::field::types::{Field, Sample};
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
@ -176,7 +174,7 @@ mod tests {
|
||||
type F = GoldilocksField;
|
||||
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25);
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::rand_from_rng(&mut rng));
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::sample(&mut rng));
|
||||
|
||||
// if `IS_LT == 0`, then the constraints should be met even if
|
||||
// all values are garbage. `eval_packed_generic` handles IS_GT
|
||||
@ -201,7 +199,7 @@ mod tests {
|
||||
type F = GoldilocksField;
|
||||
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25);
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::rand_from_rng(&mut rng));
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::sample(&mut rng));
|
||||
const N_ITERS: usize = 1000;
|
||||
|
||||
for _ in 0..N_ITERS {
|
||||
|
||||
@ -87,7 +87,8 @@
|
||||
//! In the case of DIV, we do something similar, except that we "replace"
|
||||
//! the modulus with "2^256" to force the quotient to be zero.
|
||||
|
||||
use num::{bigint::Sign, BigInt, One, Zero};
|
||||
use num::bigint::Sign;
|
||||
use num::{BigInt, One, Zero};
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::field::packed::PackedField;
|
||||
use plonky2::field::types::Field;
|
||||
@ -500,7 +501,7 @@ pub(crate) fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
mod tests {
|
||||
use itertools::izip;
|
||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::field::types::{Field, Sample};
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
@ -516,7 +517,7 @@ mod tests {
|
||||
type F = GoldilocksField;
|
||||
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25);
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::rand_from_rng(&mut rng));
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::sample(&mut rng));
|
||||
|
||||
// if `IS_ADDMOD == 0`, then the constraints should be met even
|
||||
// if all values are garbage.
|
||||
@ -543,7 +544,7 @@ mod tests {
|
||||
type F = GoldilocksField;
|
||||
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25);
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::rand_from_rng(&mut rng));
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::sample(&mut rng));
|
||||
|
||||
for op_filter in [IS_ADDMOD, IS_DIV, IS_SUBMOD, IS_MOD, IS_MULMOD] {
|
||||
// Reset operation columns, then select one
|
||||
@ -594,7 +595,7 @@ mod tests {
|
||||
type F = GoldilocksField;
|
||||
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25);
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::rand_from_rng(&mut rng));
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::sample(&mut rng));
|
||||
|
||||
for op_filter in [IS_ADDMOD, IS_SUBMOD, IS_DIV, IS_MOD, IS_MULMOD] {
|
||||
// Reset operation columns, then select one
|
||||
|
||||
@ -172,7 +172,7 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::field::types::{Field, Sample};
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
@ -188,7 +188,7 @@ mod tests {
|
||||
type F = GoldilocksField;
|
||||
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25);
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::rand_from_rng(&mut rng));
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::sample(&mut rng));
|
||||
|
||||
// if `IS_MUL == 0`, then the constraints should be met even
|
||||
// if all values are garbage.
|
||||
@ -211,7 +211,7 @@ mod tests {
|
||||
type F = GoldilocksField;
|
||||
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25);
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::rand_from_rng(&mut rng));
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::sample(&mut rng));
|
||||
|
||||
// set `IS_MUL == 1` and ensure all constraints are satisfied.
|
||||
lv[IS_MUL] = F::ONE;
|
||||
|
||||
@ -93,7 +93,7 @@ pub fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::field::types::{Field, Sample};
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
@ -109,7 +109,7 @@ mod tests {
|
||||
type F = GoldilocksField;
|
||||
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25);
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::rand_from_rng(&mut rng));
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::sample(&mut rng));
|
||||
|
||||
// if `IS_SUB == 0`, then the constraints should be met even
|
||||
// if all values are garbage.
|
||||
@ -132,7 +132,7 @@ mod tests {
|
||||
type F = GoldilocksField;
|
||||
|
||||
let mut rng = ChaCha8Rng::seed_from_u64(0x6feb51b7ec230f25);
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::rand_from_rng(&mut rng));
|
||||
let mut lv = [F::default(); NUM_ARITH_COLUMNS].map(|_| F::sample(&mut rng));
|
||||
|
||||
// set `IS_SUB == 1` and ensure all constraints are satisfied.
|
||||
lv[IS_SUB] = F::ONE;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
use std::ops::{Add, AddAssign, Mul, Neg, Range, Shr, Sub, SubAssign};
|
||||
|
||||
use log::error;
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::ext_target::ExtensionTarget;
|
||||
@ -11,21 +10,24 @@ use crate::arithmetic::columns::{NUM_ARITH_COLUMNS, N_LIMBS};
|
||||
/// Emit an error message regarding unchecked range assumptions.
|
||||
/// Assumes the values in `cols` are `[cols[0], cols[0] + 1, ...,
|
||||
/// cols[0] + cols.len() - 1]`.
|
||||
///
|
||||
/// TODO: Hamish to delete this when he has implemented and integrated
|
||||
/// range checks.
|
||||
pub(crate) fn _range_check_error<const RC_BITS: u32>(
|
||||
file: &str,
|
||||
line: u32,
|
||||
cols: Range<usize>,
|
||||
signedness: &str,
|
||||
_file: &str,
|
||||
_line: u32,
|
||||
_cols: Range<usize>,
|
||||
_signedness: &str,
|
||||
) {
|
||||
error!(
|
||||
"{}:{}: arithmetic unit skipped {}-bit {} range-checks on columns {}--{}: not yet implemented",
|
||||
line,
|
||||
file,
|
||||
RC_BITS,
|
||||
signedness,
|
||||
cols.start,
|
||||
cols.end - 1,
|
||||
);
|
||||
// error!(
|
||||
// "{}:{}: arithmetic unit skipped {}-bit {} range-checks on columns {}--{}: not yet implemented",
|
||||
// line,
|
||||
// file,
|
||||
// RC_BITS,
|
||||
// signedness,
|
||||
// cols.start,
|
||||
// cols.end - 1,
|
||||
// );
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::{env, fs};
|
||||
|
||||
use hex::encode;
|
||||
use plonky2_evm::cpu::kernel::assemble_to_bytes;
|
||||
|
||||
@ -10,6 +10,7 @@ pub(crate) union CpuGeneralColumnsView<T: Copy> {
|
||||
arithmetic: CpuArithmeticView<T>,
|
||||
logic: CpuLogicView<T>,
|
||||
jumps: CpuJumpsView<T>,
|
||||
shift: CpuShiftView<T>,
|
||||
}
|
||||
|
||||
impl<T: Copy> CpuGeneralColumnsView<T> {
|
||||
@ -52,6 +53,16 @@ impl<T: Copy> CpuGeneralColumnsView<T> {
|
||||
pub(crate) fn jumps_mut(&mut self) -> &mut CpuJumpsView<T> {
|
||||
unsafe { &mut self.jumps }
|
||||
}
|
||||
|
||||
// SAFETY: Each view is a valid interpretation of the underlying array.
|
||||
pub(crate) fn shift(&self) -> &CpuShiftView<T> {
|
||||
unsafe { &self.shift }
|
||||
}
|
||||
|
||||
// SAFETY: Each view is a valid interpretation of the underlying array.
|
||||
pub(crate) fn shift_mut(&mut self) -> &mut CpuShiftView<T> {
|
||||
unsafe { &mut self.shift }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Copy + PartialEq> PartialEq<Self> for CpuGeneralColumnsView<T> {
|
||||
@ -145,5 +156,12 @@ pub(crate) struct CpuJumpsView<T: Copy> {
|
||||
pub(crate) should_trap: T,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) struct CpuShiftView<T: Copy> {
|
||||
// For a shift amount of displacement: [T], this is the inverse of
|
||||
// sum(displacement[1..]) or zero if the sum is zero.
|
||||
pub(crate) high_limb_sum_inv: T,
|
||||
}
|
||||
|
||||
// `u8` is guaranteed to have a `size_of` of 1.
|
||||
pub const NUM_SHARED_COLUMNS: usize = size_of::<CpuGeneralColumnsView<u8>>();
|
||||
|
||||
@ -11,8 +11,8 @@ use plonky2::hash::hash_types::RichField;
|
||||
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
|
||||
use crate::cpu::columns::{CpuColumnsView, COL_MAP, NUM_CPU_COLUMNS};
|
||||
use crate::cpu::{
|
||||
bootstrap_kernel, control_flow, decode, dup_swap, jumps, membus, modfp254, simple_logic, stack,
|
||||
stack_bounds, syscalls,
|
||||
bootstrap_kernel, control_flow, decode, dup_swap, jumps, membus, modfp254, shift, simple_logic,
|
||||
stack, stack_bounds, syscalls,
|
||||
};
|
||||
use crate::cross_table_lookup::Column;
|
||||
use crate::memory::segments::Segment;
|
||||
@ -150,6 +150,7 @@ impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for CpuStark<F, D
|
||||
jumps::eval_packed(local_values, next_values, yield_constr);
|
||||
membus::eval_packed(local_values, yield_constr);
|
||||
modfp254::eval_packed(local_values, yield_constr);
|
||||
shift::eval_packed(local_values, yield_constr);
|
||||
simple_logic::eval_packed(local_values, yield_constr);
|
||||
stack::eval_packed(local_values, yield_constr);
|
||||
stack_bounds::eval_packed(local_values, yield_constr);
|
||||
@ -171,6 +172,7 @@ impl<F: RichField + Extendable<D>, const D: usize> Stark<F, D> for CpuStark<F, D
|
||||
jumps::eval_ext_circuit(builder, local_values, next_values, yield_constr);
|
||||
membus::eval_ext_circuit(builder, local_values, yield_constr);
|
||||
modfp254::eval_ext_circuit(builder, local_values, yield_constr);
|
||||
shift::eval_ext_circuit(builder, local_values, yield_constr);
|
||||
simple_logic::eval_ext_circuit(builder, local_values, yield_constr);
|
||||
stack::eval_ext_circuit(builder, local_values, yield_constr);
|
||||
stack_bounds::eval_ext_circuit(builder, local_values, yield_constr);
|
||||
|
||||
@ -16,6 +16,7 @@ pub(crate) fn combined_kernel() -> Kernel {
|
||||
include_str!("asm/core/create_addresses.asm"),
|
||||
include_str!("asm/core/intrinsic_gas.asm"),
|
||||
include_str!("asm/core/invalid.asm"),
|
||||
include_str!("asm/core/jumpdest_analysis.asm"),
|
||||
include_str!("asm/core/nonce.asm"),
|
||||
include_str!("asm/core/process_txn.asm"),
|
||||
include_str!("asm/core/syscall.asm"),
|
||||
@ -77,6 +78,7 @@ pub(crate) fn combined_kernel() -> Kernel {
|
||||
include_str!("asm/sha2/store_pad.asm"),
|
||||
include_str!("asm/sha2/temp_words.asm"),
|
||||
include_str!("asm/sha2/write_length.asm"),
|
||||
include_str!("asm/shift.asm"),
|
||||
include_str!("asm/transactions/router.asm"),
|
||||
include_str!("asm/transactions/type_0.asm"),
|
||||
include_str!("asm/transactions/type_1.asm"),
|
||||
|
||||
@ -21,7 +21,7 @@ global extcodehash:
|
||||
%endmacro
|
||||
|
||||
%macro extcodesize
|
||||
%stack (address) -> (address, %%after)
|
||||
%stack (address) -> (address, 0, @SEGMENT_KERNEL_ACCOUNT_CODE, %%after)
|
||||
%jump(load_code)
|
||||
%%after:
|
||||
%endmacro
|
||||
@ -44,7 +44,8 @@ global extcodesize:
|
||||
// Post stack: (empty)
|
||||
global extcodecopy:
|
||||
// stack: address, dest_offset, offset, size, retdest
|
||||
%stack (address, dest_offset, offset, size, retdest) -> (address, extcodecopy_contd, size, offset, dest_offset, retdest)
|
||||
%stack (address, dest_offset, offset, size, retdest)
|
||||
-> (address, 0, @SEGMENT_KERNEL_ACCOUNT_CODE, extcodecopy_contd, size, offset, dest_offset, retdest)
|
||||
%jump(load_code)
|
||||
|
||||
extcodecopy_contd:
|
||||
@ -55,19 +56,22 @@ extcodecopy_contd:
|
||||
|
||||
// Loop copying the `code[offset]` to `memory[dest_offset]` until `i==size`.
|
||||
// Each iteration increments `offset, dest_offset, i`.
|
||||
// TODO: Consider implementing this with memcpy.
|
||||
extcodecopy_loop:
|
||||
// stack: i, size, code_length, offset, dest_offset, retdest
|
||||
DUP2 DUP2 EQ
|
||||
// stack: i == size, i, size, code_length, offset, dest_offset, retdest
|
||||
%jumpi(extcodecopy_end)
|
||||
%stack (i, size, code_length, offset, dest_offset, retdest) -> (offset, code_length, offset, code_length, dest_offset, i, size, retdest)
|
||||
%stack (i, size, code_length, offset, dest_offset, retdest)
|
||||
-> (offset, code_length, offset, code_length, dest_offset, i, size, retdest)
|
||||
LT
|
||||
// stack: offset < code_length, offset, code_length, dest_offset, i, size, retdest
|
||||
DUP2
|
||||
// stack: offset, offset < code_length, offset, code_length, dest_offset, i, size, retdest
|
||||
%mload_current(@SEGMENT_KERNEL_ACCOUNT_CODE)
|
||||
// stack: opcode, offset < code_length, offset, code_length, dest_offset, i, size, retdest
|
||||
%stack (opcode, offset_lt_code_length, offset, code_length, dest_offset, i, size, retdest) -> (offset_lt_code_length, 0, opcode, offset, code_length, dest_offset, i, size, retdest)
|
||||
%stack (opcode, offset_lt_code_length, offset, code_length, dest_offset, i, size, retdest)
|
||||
-> (offset_lt_code_length, 0, opcode, offset, code_length, dest_offset, i, size, retdest)
|
||||
// If `offset >= code_length`, use `opcode=0`. Necessary since `SEGMENT_KERNEL_ACCOUNT_CODE` might be clobbered from previous calls.
|
||||
%select_bool
|
||||
// stack: opcode, offset, code_length, dest_offset, i, size, retdest
|
||||
@ -93,41 +97,42 @@ extcodecopy_end:
|
||||
JUMP
|
||||
|
||||
|
||||
// Loads the code at `address` in the `SEGMENT_KERNEL_ACCOUNT_CODE` at the current context and starting at offset 0.
|
||||
// Loads the code at `address` into memory, at the given context and segment, starting at offset 0.
|
||||
// Checks that the hash of the loaded code corresponds to the `codehash` in the state trie.
|
||||
// Pre stack: address, retdest
|
||||
// Post stack: extcodesize(address)
|
||||
load_code:
|
||||
%stack (address, retdest) -> (extcodehash, address, load_code_ctd, retdest)
|
||||
// Pre stack: address, ctx, segment, retdest
|
||||
// Post stack: code_len
|
||||
global load_code:
|
||||
%stack (address, ctx, segment, retdest) -> (extcodehash, address, load_code_ctd, ctx, segment, retdest)
|
||||
JUMP
|
||||
load_code_ctd:
|
||||
// stack: codehash, retdest
|
||||
// stack: codehash, ctx, segment, retdest
|
||||
PROVER_INPUT(account_code::length)
|
||||
// stack: code_length, codehash, retdest
|
||||
// stack: code_length, codehash, ctx, segment, retdest
|
||||
PUSH 0
|
||||
|
||||
// Loop non-deterministically querying `code[i]` and storing it in `SEGMENT_KERNEL_ACCOUNT_CODE` at offset `i`, until `i==code_length`.
|
||||
load_code_loop:
|
||||
// stack: i, code_length, codehash, retdest
|
||||
// stack: i, code_length, codehash, ctx, segment, retdest
|
||||
DUP2 DUP2 EQ
|
||||
// stack: i == code_length, i, code_length, codehash, retdest
|
||||
// stack: i == code_length, i, code_length, codehash, ctx, segment, retdest
|
||||
%jumpi(load_code_check)
|
||||
PROVER_INPUT(account_code::get)
|
||||
// stack: opcode, i, code_length, codehash, retdest
|
||||
// stack: opcode, i, code_length, codehash, ctx, segment, retdest
|
||||
DUP2
|
||||
// stack: i, opcode, i, code_length, codehash, retdest
|
||||
%mstore_current(@SEGMENT_KERNEL_ACCOUNT_CODE)
|
||||
// stack: i, code_length, codehash, retdest
|
||||
// stack: i, opcode, i, code_length, codehash, ctx, segment, retdest
|
||||
DUP7 // segment
|
||||
DUP7 // context
|
||||
MSTORE_GENERAL
|
||||
// stack: i, code_length, codehash, ctx, segment, retdest
|
||||
%increment
|
||||
// stack: i+1, code_length, codehash, retdest
|
||||
// stack: i+1, code_length, codehash, ctx, segment, retdest
|
||||
%jump(load_code_loop)
|
||||
|
||||
// Check that the hash of the loaded code equals `codehash`.
|
||||
load_code_check:
|
||||
// stack: i, code_length, codehash, retdest
|
||||
POP
|
||||
// stack: code_length, codehash, retdest
|
||||
%stack (code_length, codehash, retdest) -> (0, @SEGMENT_KERNEL_ACCOUNT_CODE, 0, code_length, codehash, retdest, code_length)
|
||||
// stack: i, code_length, codehash, ctx, segment, retdest
|
||||
%stack (i, code_length, codehash, ctx, segment, retdest)
|
||||
-> (ctx, segment, 0, code_length, codehash, retdest, code_length)
|
||||
KECCAK_GENERAL
|
||||
// stack: shouldbecodehash, codehash, retdest, code_length
|
||||
%assert_eq
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
// Loads some prover-provided contract code into the code segment of memory,
|
||||
// then hashes the code and returns the hash.
|
||||
|
||||
global bootload_contract:
|
||||
// stack: retdest
|
||||
// stack: address, retdest
|
||||
// %stack (address, retdest) -> (address, after_load_code, retdest)
|
||||
// %jump(load_code)
|
||||
PANIC // TODO
|
||||
|
||||
// TODO
|
||||
global bootload_code:
|
||||
// stack: code_len, retdest
|
||||
PANIC // TODO
|
||||
|
||||
// stack: code_hash, retdest
|
||||
SWAP1
|
||||
|
||||
64
evm/src/cpu/kernel/asm/core/jumpdest_analysis.asm
Normal file
64
evm/src/cpu/kernel/asm/core/jumpdest_analysis.asm
Normal file
@ -0,0 +1,64 @@
|
||||
// Populates @SEGMENT_JUMPDEST_BITS for the given context's code.
|
||||
// Pre stack: ctx, code_len, retdest
|
||||
// Post stack: (empty)
|
||||
global jumpdest_analysis:
|
||||
// stack: ctx, code_len, retdest
|
||||
PUSH 0 // i = 0
|
||||
|
||||
loop:
|
||||
// stack: i, ctx, code_len, retdest
|
||||
// Ideally we would break if i >= code_len, but checking i > code_len is
|
||||
// cheaper. It doesn't hurt to over-read by 1, since we'll read 0 which is
|
||||
// a no-op.
|
||||
DUP3 DUP2 GT // i > code_len
|
||||
%jumpi(return)
|
||||
|
||||
// stack: i, ctx, code_len, retdest
|
||||
%stack (i, ctx) -> (ctx, @SEGMENT_CODE, i, i, ctx)
|
||||
MLOAD_GENERAL
|
||||
// stack: opcode, i, ctx, code_len, retdest
|
||||
|
||||
DUP1 %eq_const(0x5b)
|
||||
// stack: opcode == JUMPDEST, opcode, i, ctx, code_len, retdest
|
||||
%jumpi(encountered_jumpdest)
|
||||
|
||||
// stack: opcode, i, ctx, code_len, retdest
|
||||
%code_bytes_to_skip
|
||||
// stack: bytes_to_skip, i, ctx, code_len, retdest
|
||||
ADD
|
||||
%jump(continue)
|
||||
|
||||
encountered_jumpdest:
|
||||
// stack: opcode, i, ctx, code_len, retdest
|
||||
POP
|
||||
// stack: i, ctx, code_len, retdest
|
||||
%stack (i, ctx) -> (ctx, @SEGMENT_JUMPDEST_BITS, i, 1, i, ctx)
|
||||
MSTORE_GENERAL
|
||||
|
||||
continue:
|
||||
// stack: i, ctx, code_len, retdest
|
||||
%increment
|
||||
%jump(loop)
|
||||
|
||||
return:
|
||||
// stack: i, ctx, code_len, retdest
|
||||
%pop3
|
||||
JUMP
|
||||
|
||||
// Determines how many bytes to skip, if any, based on the opcode we read.
|
||||
// If we read a PUSH<n> opcode, we skip over n bytes, otherwise we skip 0.
|
||||
//
|
||||
// Note that the range of PUSH opcodes is [0x60, 0x80). I.e. PUSH1 is 0x60
|
||||
// and PUSH32 is 0x7f.
|
||||
%macro code_bytes_to_skip
|
||||
// stack: opcode
|
||||
%sub_const(0x60)
|
||||
// stack: opcode - 0x60
|
||||
DUP1 %lt_const(0x20)
|
||||
// stack: is_push_opcode, opcode - 0x60
|
||||
SWAP1
|
||||
%increment // n = opcode - 0x60 + 1
|
||||
// stack: n, is_push_opcode
|
||||
MUL
|
||||
// stack: bytes_to_skip
|
||||
%endmacro
|
||||
@ -1,5 +1,7 @@
|
||||
global main:
|
||||
// First, load all MPT data from the prover.
|
||||
// First, initialise the shift table
|
||||
%shift_table_init
|
||||
// Second, load all MPT data from the prover.
|
||||
PUSH txn_loop
|
||||
%jump(load_all_mpts)
|
||||
|
||||
|
||||
25
evm/src/cpu/kernel/asm/shift.asm
Normal file
25
evm/src/cpu/kernel/asm/shift.asm
Normal file
@ -0,0 +1,25 @@
|
||||
/// Initialise the lookup table of binary powers for doing left/right shifts
|
||||
///
|
||||
/// Specifically, set SHIFT_TABLE_SEGMENT[i] = 2^i for i = 0..255.
|
||||
%macro shift_table_init
|
||||
push 1 // 2^0
|
||||
push 0 // initial offset is zero
|
||||
push @SEGMENT_SHIFT_TABLE // segment
|
||||
dup2 // kernel context is 0
|
||||
%rep 255
|
||||
// stack: context, segment, ost_i, 2^i
|
||||
dup4
|
||||
dup1
|
||||
add
|
||||
// stack: 2^(i+1), context, segment, ost_i, 2^i
|
||||
dup4
|
||||
%increment
|
||||
// stack: ost_(i+1), 2^(i+1), context, segment, ost_i, 2^i
|
||||
dup4
|
||||
dup4
|
||||
// stack: context, segment, ost_(i+1), 2^(i+1), context, segment, ost_i, 2^i
|
||||
%endrep
|
||||
%rep 256
|
||||
mstore_general
|
||||
%endrep
|
||||
%endmacro
|
||||
@ -7,15 +7,12 @@ use plonky2_util::ceil_div_usize;
|
||||
|
||||
use super::ast::PushTarget;
|
||||
use crate::cpu::kernel::ast::Item::LocalLabelDeclaration;
|
||||
use crate::cpu::kernel::ast::StackReplacement;
|
||||
use crate::cpu::kernel::ast::{File, Item, StackReplacement};
|
||||
use crate::cpu::kernel::keccak_util::hash_kernel;
|
||||
use crate::cpu::kernel::opcodes::{get_opcode, get_push_opcode};
|
||||
use crate::cpu::kernel::optimizer::optimize_asm;
|
||||
use crate::cpu::kernel::stack::stack_manipulation::expand_stack_manipulation;
|
||||
use crate::cpu::kernel::utils::u256_to_trimmed_be_bytes;
|
||||
use crate::cpu::kernel::{
|
||||
ast::{File, Item},
|
||||
opcodes::{get_opcode, get_push_opcode},
|
||||
};
|
||||
use crate::generation::prover_input::ProverInputFn;
|
||||
use crate::keccak_sponge::columns::KECCAK_RATE_BYTES;
|
||||
|
||||
@ -387,8 +384,9 @@ mod tests {
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::cpu::kernel::assembler::*;
|
||||
use crate::cpu::kernel::ast::*;
|
||||
use crate::cpu::kernel::parser::parse;
|
||||
use crate::cpu::kernel::{assembler::*, ast::*};
|
||||
|
||||
#[test]
|
||||
fn two_files() {
|
||||
|
||||
@ -202,6 +202,25 @@ impl<'a> Interpreter<'a> {
|
||||
rlp.into_iter().map(U256::from).collect();
|
||||
}
|
||||
|
||||
pub(crate) fn set_code(&mut self, context: usize, code: Vec<u8>) {
|
||||
assert_ne!(context, 0, "Can't modify kernel code.");
|
||||
while self.memory.context_memory.len() <= context {
|
||||
self.memory
|
||||
.context_memory
|
||||
.push(MemoryContextState::default());
|
||||
}
|
||||
self.memory.context_memory[context].segments[Segment::Code as usize].content =
|
||||
code.into_iter().map(U256::from).collect();
|
||||
}
|
||||
|
||||
pub(crate) fn get_jumpdest_bits(&self, context: usize) -> Vec<bool> {
|
||||
self.memory.context_memory[context].segments[Segment::JumpdestBits as usize]
|
||||
.content
|
||||
.iter()
|
||||
.map(|x| x.bit(0))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn incr(&mut self, n: usize) {
|
||||
self.offset += n;
|
||||
}
|
||||
@ -266,10 +285,10 @@ impl<'a> Interpreter<'a> {
|
||||
0x31 => todo!(), // "BALANCE",
|
||||
0x32 => todo!(), // "ORIGIN",
|
||||
0x33 => todo!(), // "CALLER",
|
||||
0x34 => todo!(), // "CALLVALUE",
|
||||
0x35 => todo!(), // "CALLDATALOAD",
|
||||
0x36 => todo!(), // "CALLDATASIZE",
|
||||
0x37 => todo!(), // "CALLDATACOPY",
|
||||
0x34 => self.run_callvalue(), // "CALLVALUE",
|
||||
0x35 => self.run_calldataload(), // "CALLDATALOAD",
|
||||
0x36 => self.run_calldatasize(), // "CALLDATASIZE",
|
||||
0x37 => self.run_calldatacopy(), // "CALLDATACOPY",
|
||||
0x38 => todo!(), // "CODESIZE",
|
||||
0x39 => todo!(), // "CODECOPY",
|
||||
0x3a => todo!(), // "GASPRICE",
|
||||
@ -537,6 +556,51 @@ impl<'a> Interpreter<'a> {
|
||||
self.push(U256::from_big_endian(hash.as_bytes()));
|
||||
}
|
||||
|
||||
fn run_callvalue(&mut self) {
|
||||
self.push(
|
||||
self.memory.context_memory[self.context].segments[Segment::ContextMetadata as usize]
|
||||
.get(ContextMetadata::CallValue as usize),
|
||||
)
|
||||
}
|
||||
|
||||
fn run_calldataload(&mut self) {
|
||||
let offset = self.pop().as_usize();
|
||||
let value = U256::from_big_endian(
|
||||
&(0..32)
|
||||
.map(|i| {
|
||||
self.memory
|
||||
.mload_general(self.context, Segment::Calldata, offset + i)
|
||||
.byte(0)
|
||||
})
|
||||
.collect::<Vec<_>>(),
|
||||
);
|
||||
self.push(value);
|
||||
}
|
||||
|
||||
fn run_calldatasize(&mut self) {
|
||||
self.push(
|
||||
self.memory.context_memory[self.context].segments[Segment::ContextMetadata as usize]
|
||||
.get(ContextMetadata::CalldataSize as usize),
|
||||
)
|
||||
}
|
||||
|
||||
fn run_calldatacopy(&mut self) {
|
||||
let dest_offset = self.pop().as_usize();
|
||||
let offset = self.pop().as_usize();
|
||||
let size = self.pop().as_usize();
|
||||
for i in 0..size {
|
||||
let calldata_byte =
|
||||
self.memory
|
||||
.mload_general(self.context, Segment::Calldata, offset + i);
|
||||
self.memory.mstore_general(
|
||||
self.context,
|
||||
Segment::MainMemory,
|
||||
dest_offset + i,
|
||||
calldata_byte,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn run_prover_input(&mut self) -> anyhow::Result<()> {
|
||||
let prover_input_fn = self
|
||||
.prover_inputs_map
|
||||
|
||||
42
evm/src/cpu/kernel/tests/core/jumpdest_analysis.rs
Normal file
42
evm/src/cpu/kernel/tests/core/jumpdest_analysis.rs
Normal file
@ -0,0 +1,42 @@
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::cpu::kernel::aggregator::KERNEL;
|
||||
use crate::cpu::kernel::interpreter::Interpreter;
|
||||
use crate::cpu::kernel::opcodes::{get_opcode, get_push_opcode};
|
||||
|
||||
#[test]
|
||||
fn test_jumpdest_analysis() -> Result<()> {
|
||||
let jumpdest_analysis = KERNEL.global_labels["jumpdest_analysis"];
|
||||
const CONTEXT: usize = 3; // arbitrary
|
||||
|
||||
let add = get_opcode("ADD");
|
||||
let push2 = get_push_opcode(2);
|
||||
let jumpdest = get_opcode("JUMPDEST");
|
||||
|
||||
#[rustfmt::skip]
|
||||
let code: Vec<u8> = vec![
|
||||
add,
|
||||
jumpdest,
|
||||
push2,
|
||||
jumpdest, // part of PUSH2
|
||||
jumpdest, // part of PUSH2
|
||||
jumpdest,
|
||||
add,
|
||||
jumpdest,
|
||||
];
|
||||
|
||||
let expected_jumpdest_bits = vec![false, true, false, false, false, true, false, true];
|
||||
|
||||
// Contract creation transaction.
|
||||
let initial_stack = vec![0xDEADBEEFu32.into(), code.len().into(), CONTEXT.into()];
|
||||
let mut interpreter = Interpreter::new_with_kernel(jumpdest_analysis, initial_stack);
|
||||
interpreter.set_code(CONTEXT, code);
|
||||
interpreter.run()?;
|
||||
assert_eq!(interpreter.stack(), vec![]);
|
||||
assert_eq!(
|
||||
interpreter.get_jumpdest_bits(CONTEXT),
|
||||
expected_jumpdest_bits
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -1,2 +1,3 @@
|
||||
mod create_addresses;
|
||||
mod intrinsic_gas;
|
||||
mod jumpdest_analysis;
|
||||
|
||||
@ -8,6 +8,7 @@ mod jumps;
|
||||
pub mod kernel;
|
||||
pub(crate) mod membus;
|
||||
mod modfp254;
|
||||
mod shift;
|
||||
pub(crate) mod simple_logic;
|
||||
mod stack;
|
||||
mod stack_bounds;
|
||||
|
||||
108
evm/src/cpu/shift.rs
Normal file
108
evm/src/cpu/shift.rs
Normal file
@ -0,0 +1,108 @@
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::field::packed::PackedField;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::ext_target::ExtensionTarget;
|
||||
|
||||
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
|
||||
use crate::cpu::columns::CpuColumnsView;
|
||||
use crate::cpu::membus::NUM_GP_CHANNELS;
|
||||
use crate::memory::segments::Segment;
|
||||
|
||||
pub(crate) fn eval_packed<P: PackedField>(
|
||||
lv: &CpuColumnsView<P>,
|
||||
yield_constr: &mut ConstraintConsumer<P>,
|
||||
) {
|
||||
let is_shift = lv.op.shl + lv.op.shr;
|
||||
let displacement = lv.mem_channels[1]; // holds the shift displacement d
|
||||
let two_exp = lv.mem_channels[2]; // holds 2^d
|
||||
|
||||
// Not needed here; val is the input and we're verifying that output is
|
||||
// val * 2^d (mod 2^256)
|
||||
//let val = lv.mem_channels[0];
|
||||
//let output = lv.mem_channels[NUM_GP_CHANNELS - 1];
|
||||
|
||||
let shift_table_segment = P::Scalar::from_canonical_u64(Segment::ShiftTable as u64);
|
||||
|
||||
// Only lookup the shifting factor when displacement is < 2^32.
|
||||
// two_exp.used is true (1) if the high limbs of the displacement are
|
||||
// zero and false (0) otherwise.
|
||||
let high_limbs_are_zero = two_exp.used;
|
||||
yield_constr.constraint(is_shift * (two_exp.is_read - P::ONES));
|
||||
|
||||
let high_limbs_sum: P = displacement.value[1..].iter().copied().sum();
|
||||
let high_limbs_sum_inv = lv.general.shift().high_limb_sum_inv;
|
||||
// Verify that high_limbs_are_zero = 0 implies high_limbs_sum != 0 and
|
||||
// high_limbs_are_zero = 1 implies high_limbs_sum = 0.
|
||||
let t = high_limbs_sum * high_limbs_sum_inv - (P::ONES - high_limbs_are_zero);
|
||||
yield_constr.constraint(is_shift * t);
|
||||
yield_constr.constraint(is_shift * high_limbs_sum * high_limbs_are_zero);
|
||||
|
||||
// When the shift displacement is < 2^32, constrain the two_exp
|
||||
// mem_channel to be the entry corresponding to `displacement` in
|
||||
// the shift table lookup (will be zero if displacement >= 256).
|
||||
yield_constr.constraint(is_shift * two_exp.addr_context); // read from kernel memory
|
||||
yield_constr.constraint(is_shift * (two_exp.addr_segment - shift_table_segment));
|
||||
yield_constr.constraint(is_shift * (two_exp.addr_virtual - displacement.value[0]));
|
||||
|
||||
// Other channels must be unused
|
||||
for chan in &lv.mem_channels[3..NUM_GP_CHANNELS - 1] {
|
||||
yield_constr.constraint(is_shift * chan.used); // channel is not used
|
||||
}
|
||||
|
||||
// Cross-table lookup must connect the memory channels here to MUL
|
||||
// (in the case of left shift) or DIV (in the case of right shift)
|
||||
// in the arithmetic table. Specifically, the mapping is
|
||||
//
|
||||
// 0 -> 0 (value to be shifted is the same)
|
||||
// 2 -> 1 (two_exp becomes the multiplicand (resp. divisor))
|
||||
// last -> last (output is the same)
|
||||
}
|
||||
|
||||
pub(crate) fn eval_ext_circuit<F: RichField + Extendable<D>, const D: usize>(
|
||||
builder: &mut plonky2::plonk::circuit_builder::CircuitBuilder<F, D>,
|
||||
lv: &CpuColumnsView<ExtensionTarget<D>>,
|
||||
yield_constr: &mut RecursiveConstraintConsumer<F, D>,
|
||||
) {
|
||||
let is_shift = builder.add_extension(lv.op.shl, lv.op.shr);
|
||||
let displacement = lv.mem_channels[1];
|
||||
let two_exp = lv.mem_channels[2];
|
||||
|
||||
let shift_table_segment = F::from_canonical_u64(Segment::ShiftTable as u64);
|
||||
|
||||
let high_limbs_are_zero = two_exp.used;
|
||||
let one = builder.one_extension();
|
||||
let t = builder.sub_extension(two_exp.is_read, one);
|
||||
let t = builder.mul_extension(is_shift, t);
|
||||
yield_constr.constraint(builder, t);
|
||||
|
||||
let high_limbs_sum = builder.add_many_extension(&displacement.value[1..]);
|
||||
let high_limbs_sum_inv = lv.general.shift().high_limb_sum_inv;
|
||||
let t = builder.one_extension();
|
||||
let t = builder.sub_extension(t, high_limbs_are_zero);
|
||||
let t = builder.mul_sub_extension(high_limbs_sum, high_limbs_sum_inv, t);
|
||||
let t = builder.mul_extension(is_shift, t);
|
||||
yield_constr.constraint(builder, t);
|
||||
|
||||
let t = builder.mul_many_extension([is_shift, high_limbs_sum, high_limbs_are_zero]);
|
||||
yield_constr.constraint(builder, t);
|
||||
|
||||
let t = builder.mul_extension(is_shift, two_exp.addr_context);
|
||||
yield_constr.constraint(builder, t);
|
||||
let t = builder.arithmetic_extension(
|
||||
F::ONE,
|
||||
-shift_table_segment,
|
||||
is_shift,
|
||||
two_exp.addr_segment,
|
||||
is_shift,
|
||||
);
|
||||
yield_constr.constraint(builder, t);
|
||||
let t = builder.sub_extension(two_exp.addr_virtual, displacement.value[0]);
|
||||
let t = builder.mul_extension(is_shift, t);
|
||||
yield_constr.constraint(builder, t);
|
||||
|
||||
for chan in &lv.mem_channels[3..NUM_GP_CHANNELS - 1] {
|
||||
let t = builder.mul_extension(is_shift, chan.used);
|
||||
yield_constr.constraint(builder, t);
|
||||
}
|
||||
}
|
||||
@ -70,7 +70,7 @@ impl<F: Field> GenerationState<F> {
|
||||
match input_fn.0[1].as_str() {
|
||||
"length" => {
|
||||
// Return length of code.
|
||||
// stack: codehash
|
||||
// stack: codehash, ...
|
||||
let codehash = stack.last().expect("Empty stack");
|
||||
self.inputs.contract_code[&H256::from_uint(codehash)]
|
||||
.len()
|
||||
@ -78,7 +78,7 @@ impl<F: Field> GenerationState<F> {
|
||||
}
|
||||
"get" => {
|
||||
// Return `code[i]`.
|
||||
// stack: i, code_length, codehash
|
||||
// stack: i, code_length, codehash, ...
|
||||
let stacklen = stack.len();
|
||||
let i = stack[stacklen - 1].as_usize();
|
||||
let codehash = stack[stacklen - 3];
|
||||
|
||||
@ -5,11 +5,9 @@ use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
|
||||
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
|
||||
use crate::keccak::columns::reg_step;
|
||||
use crate::keccak::columns::NUM_COLUMNS;
|
||||
use crate::keccak::columns::{reg_step, NUM_COLUMNS};
|
||||
use crate::keccak::keccak_stark::NUM_ROUNDS;
|
||||
use crate::vars::StarkEvaluationTargets;
|
||||
use crate::vars::StarkEvaluationVars;
|
||||
use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars};
|
||||
|
||||
pub(crate) fn eval_round_flags<F: Field, P: PackedField<Scalar = F>>(
|
||||
vars: StarkEvaluationVars<F, P, NUM_COLUMNS>,
|
||||
|
||||
@ -15,8 +15,7 @@ use crate::keccak_memory::columns::*;
|
||||
use crate::memory::segments::Segment;
|
||||
use crate::stark::Stark;
|
||||
use crate::util::trace_rows_to_poly_values;
|
||||
use crate::vars::StarkEvaluationTargets;
|
||||
use crate::vars::StarkEvaluationVars;
|
||||
use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars};
|
||||
|
||||
pub(crate) fn ctl_looked_data<F: Field>() -> Vec<Column<F>> {
|
||||
Column::singles([COL_CONTEXT, COL_SEGMENT, COL_VIRTUAL, COL_READ_TIMESTAMP]).collect()
|
||||
|
||||
@ -21,8 +21,7 @@ use crate::keccak_sponge::columns::*;
|
||||
use crate::memory::segments::Segment;
|
||||
use crate::stark::Stark;
|
||||
use crate::util::trace_rows_to_poly_values;
|
||||
use crate::vars::StarkEvaluationTargets;
|
||||
use crate::vars::StarkEvaluationVars;
|
||||
use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars};
|
||||
|
||||
#[allow(unused)] // TODO: Should be used soon.
|
||||
pub(crate) fn ctl_looked_data<F: Field>() -> Vec<Column<F>> {
|
||||
|
||||
@ -35,10 +35,14 @@ pub(crate) enum Segment {
|
||||
TrieEncodedChild = 14,
|
||||
/// A buffer used to store the lengths of the encodings of a branch node's children.
|
||||
TrieEncodedChildLen = 15,
|
||||
/// A table of values 2^i for i=0..255 for use with shift
|
||||
/// instructions; initialised by `kernel/asm/shift.asm::init_shift_table()`.
|
||||
ShiftTable = 16,
|
||||
JumpdestBits = 17,
|
||||
}
|
||||
|
||||
impl Segment {
|
||||
pub(crate) const COUNT: usize = 16;
|
||||
pub(crate) const COUNT: usize = 18;
|
||||
|
||||
pub(crate) fn all() -> [Self; Self::COUNT] {
|
||||
[
|
||||
@ -58,6 +62,8 @@ impl Segment {
|
||||
Self::TrieData,
|
||||
Self::TrieEncodedChild,
|
||||
Self::TrieEncodedChildLen,
|
||||
Self::ShiftTable,
|
||||
Self::JumpdestBits,
|
||||
]
|
||||
}
|
||||
|
||||
@ -80,6 +86,8 @@ impl Segment {
|
||||
Segment::TrieData => "SEGMENT_TRIE_DATA",
|
||||
Segment::TrieEncodedChild => "SEGMENT_TRIE_ENCODED_CHILD",
|
||||
Segment::TrieEncodedChildLen => "SEGMENT_TRIE_ENCODED_CHILD_LEN",
|
||||
Segment::ShiftTable => "SEGMENT_SHIFT_TABLE",
|
||||
Segment::JumpdestBits => "SEGMENT_JUMPDEST_BITS",
|
||||
}
|
||||
}
|
||||
|
||||
@ -102,6 +110,8 @@ impl Segment {
|
||||
Segment::TrieData => 256,
|
||||
Segment::TrieEncodedChild => 256,
|
||||
Segment::TrieEncodedChildLen => 6,
|
||||
Segment::ShiftTable => 256,
|
||||
Segment::JumpdestBits => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,9 +27,9 @@ use crate::keccak::keccak_stark::KeccakStark;
|
||||
use crate::keccak_memory::keccak_memory_stark::KeccakMemoryStark;
|
||||
use crate::logic::LogicStark;
|
||||
use crate::memory::memory_stark::MemoryStark;
|
||||
use crate::permutation::PermutationCheckVars;
|
||||
use crate::permutation::{
|
||||
compute_permutation_z_polys, get_n_grand_product_challenge_sets, GrandProductChallengeSet,
|
||||
PermutationCheckVars,
|
||||
};
|
||||
use crate::proof::{AllProof, PublicValues, StarkOpeningSet, StarkProof};
|
||||
use crate::stark::Stark;
|
||||
|
||||
@ -13,13 +13,12 @@ use plonky2::iop::target::Target;
|
||||
use plonky2::iop::witness::Witness;
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::{CircuitConfig, VerifierCircuitData, VerifierCircuitTarget};
|
||||
use plonky2::plonk::config::Hasher;
|
||||
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig};
|
||||
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, Hasher};
|
||||
use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget};
|
||||
use plonky2::util::reducing::ReducingFactorTarget;
|
||||
use plonky2::with_context;
|
||||
|
||||
use crate::all_stark::NUM_TABLES;
|
||||
use crate::all_stark::{AllStark, Table, NUM_TABLES};
|
||||
use crate::config::StarkConfig;
|
||||
use crate::constraint_consumer::RecursiveConstraintConsumer;
|
||||
use crate::cpu::cpu_stark::CpuStark;
|
||||
@ -41,13 +40,9 @@ use crate::proof::{
|
||||
TrieRootsTarget,
|
||||
};
|
||||
use crate::stark::Stark;
|
||||
use crate::util::h160_limbs;
|
||||
use crate::util::{h160_limbs, h256_limbs};
|
||||
use crate::vanishing_poly::eval_vanishing_poly_circuit;
|
||||
use crate::vars::StarkEvaluationTargets;
|
||||
use crate::{
|
||||
all_stark::{AllStark, Table},
|
||||
util::h256_limbs,
|
||||
};
|
||||
|
||||
/// Table-wise recursive proofs of an `AllProof`.
|
||||
pub struct RecursiveAllProof<
|
||||
@ -236,7 +231,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
.enumerate()
|
||||
{
|
||||
builder.verify_proof::<C>(
|
||||
recursive_proof,
|
||||
&recursive_proof,
|
||||
&verifier_data_target,
|
||||
&verifier_data[i].common,
|
||||
);
|
||||
@ -850,8 +845,7 @@ pub(crate) mod tests {
|
||||
use plonky2::iop::witness::{PartialWitness, Witness};
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::{CircuitConfig, VerifierCircuitData};
|
||||
use plonky2::plonk::config::Hasher;
|
||||
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig};
|
||||
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, Hasher};
|
||||
use plonky2::plonk::proof::ProofWithPublicInputs;
|
||||
|
||||
use crate::all_stark::{AllStark, Table};
|
||||
|
||||
@ -13,8 +13,7 @@ use plonky2_util::ceil_div_usize;
|
||||
use crate::config::StarkConfig;
|
||||
use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer};
|
||||
use crate::permutation::PermutationPair;
|
||||
use crate::vars::StarkEvaluationTargets;
|
||||
use crate::vars::StarkEvaluationVars;
|
||||
use crate::vars::{StarkEvaluationTargets, StarkEvaluationVars};
|
||||
|
||||
const TRACE_ORACLE_INDEX: usize = 0;
|
||||
const PERMUTATION_CTL_ORACLE_INDEX: usize = 1;
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
use anyhow::{ensure, Result};
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::field::extension::FieldExtension;
|
||||
use plonky2::field::extension::{Extendable, FieldExtension};
|
||||
use plonky2::field::polynomial::{PolynomialCoeffs, PolynomialValues};
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::field::types::{Field, Sample};
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::iop::witness::Witness;
|
||||
use plonky2::iop::witness::{PartialWitness, Witness};
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::GenericConfig;
|
||||
use plonky2::plonk::config::Hasher;
|
||||
use plonky2::plonk::config::{GenericConfig, Hasher};
|
||||
use plonky2::util::transpose;
|
||||
use plonky2_util::{log2_ceil, log2_strict};
|
||||
|
||||
@ -93,8 +90,8 @@ where
|
||||
{
|
||||
// Compute native constraint evaluation on random values.
|
||||
let vars = StarkEvaluationVars {
|
||||
local_values: &F::Extension::rand_arr::<{ S::COLUMNS }>(),
|
||||
next_values: &F::Extension::rand_arr::<{ S::COLUMNS }>(),
|
||||
local_values: &F::Extension::rand_array::<{ S::COLUMNS }>(),
|
||||
next_values: &F::Extension::rand_array::<{ S::COLUMNS }>(),
|
||||
};
|
||||
let alphas = F::rand_vec(1);
|
||||
let z_last = F::Extension::rand();
|
||||
|
||||
@ -275,7 +275,7 @@ fn eval_l_0_and_l_last<F: Field>(log_n: usize, x: F) -> (F, F) {
|
||||
mod tests {
|
||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||
use plonky2::field::polynomial::PolynomialValues;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::field::types::Sample;
|
||||
|
||||
use crate::verifier::eval_l_0_and_l_last;
|
||||
|
||||
|
||||
@ -4,16 +4,12 @@ description = "Finite field arithmetic"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[features]
|
||||
default = ["rand"]
|
||||
rand = ["dep:rand"]
|
||||
|
||||
[dependencies]
|
||||
plonky2_util = { path = "../util" }
|
||||
anyhow = "1.0.40"
|
||||
itertools = "0.10.0"
|
||||
num = { version = "0.4", features = [ "rand" ] }
|
||||
rand = { optional = true, version = "0.8.4" }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
unroll = "0.1.5"
|
||||
static_assertions = "1.1.0"
|
||||
anyhow = { version = "1.0.40", default-features = false }
|
||||
itertools = { version = "0.10.0", default-features = false, features = ["use_alloc"] }
|
||||
num = { version = "0.4", default-features = false, features = ["alloc", "rand"] }
|
||||
plonky2_util = { path = "../util", default-features = false }
|
||||
rand = { version = "0.8.5", default-features = false, features = ["getrandom"] }
|
||||
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] }
|
||||
static_assertions = { version = "1.1.0", default-features = false }
|
||||
unroll = { version = "0.1.5", default-features = false }
|
||||
|
||||
@ -1,20 +1,22 @@
|
||||
use core::arch::x86_64::*;
|
||||
use std::fmt;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::iter::{Product, Sum};
|
||||
use std::mem::transmute;
|
||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
use core::fmt;
|
||||
use core::fmt::{Debug, Formatter};
|
||||
use core::iter::{Product, Sum};
|
||||
use core::mem::transmute;
|
||||
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
|
||||
use crate::goldilocks_field::GoldilocksField;
|
||||
use crate::ops::Square;
|
||||
use crate::packed::PackedField;
|
||||
use crate::types::{Field, Field64};
|
||||
|
||||
// Ideally `Avx2GoldilocksField` would wrap `__m256i`. Unfortunately, `__m256i` has an alignment of
|
||||
// 32B, which would preclude us from casting `[GoldilocksField; 4]` (alignment 8B) to
|
||||
// `Avx2GoldilocksField`. We need to ensure that `Avx2GoldilocksField` has the same alignment as
|
||||
// `GoldilocksField`. Thus we wrap `[GoldilocksField; 4]` and use the `new` and `get` methods to
|
||||
// convert to and from `__m256i`.
|
||||
/// AVX2 Goldilocks Field
|
||||
///
|
||||
/// Ideally `Avx2GoldilocksField` would wrap `__m256i`. Unfortunately, `__m256i` has an alignment of
|
||||
/// 32B, which would preclude us from casting `[GoldilocksField; 4]` (alignment 8B) to
|
||||
/// `Avx2GoldilocksField`. We need to ensure that `Avx2GoldilocksField` has the same alignment as
|
||||
/// `GoldilocksField`. Thus we wrap `[GoldilocksField; 4]` and use the `new` and `get` methods to
|
||||
/// convert to and from `__m256i`.
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(transparent)]
|
||||
pub struct Avx2GoldilocksField(pub [GoldilocksField; 4]);
|
||||
|
||||
@ -1,20 +1,22 @@
|
||||
use core::arch::x86_64::*;
|
||||
use std::fmt;
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::iter::{Product, Sum};
|
||||
use std::mem::transmute;
|
||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
use core::fmt;
|
||||
use core::fmt::{Debug, Formatter};
|
||||
use core::iter::{Product, Sum};
|
||||
use core::mem::transmute;
|
||||
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
|
||||
use crate::goldilocks_field::GoldilocksField;
|
||||
use crate::ops::Square;
|
||||
use crate::packed::PackedField;
|
||||
use crate::types::{Field, Field64};
|
||||
|
||||
// Ideally `Avx512GoldilocksField` would wrap `__m512i`. Unfortunately, `__m512i` has an alignment
|
||||
// of 64B, which would preclude us from casting `[GoldilocksField; 8]` (alignment 8B) to
|
||||
// `Avx512GoldilocksField`. We need to ensure that `Avx512GoldilocksField` has the same alignment as
|
||||
// `GoldilocksField`. Thus we wrap `[GoldilocksField; 8]` and use the `new` and `get` methods to
|
||||
// convert to and from `__m512i`.
|
||||
/// AVX512 Goldilocks Field
|
||||
///
|
||||
/// Ideally `Avx512GoldilocksField` would wrap `__m512i`. Unfortunately, `__m512i` has an alignment
|
||||
/// of 64B, which would preclude us from casting `[GoldilocksField; 8]` (alignment 8B) to
|
||||
/// `Avx512GoldilocksField`. We need to ensure that `Avx512GoldilocksField` has the same alignment as
|
||||
/// `GoldilocksField`. Thus we wrap `[GoldilocksField; 8]` and use the `new` and `get` methods to
|
||||
/// convert to and from `__m512i`.
|
||||
#[derive(Copy, Clone)]
|
||||
#[repr(transparent)]
|
||||
pub struct Avx512GoldilocksField(pub [GoldilocksField; 8]);
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use num::bigint::BigUint;
|
||||
|
||||
use crate::types::Field;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::iter::{Product, Sum};
|
||||
use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::{self, Debug, Display, Formatter};
|
||||
use core::iter::{Product, Sum};
|
||||
use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
|
||||
use crate::extension::OEF;
|
||||
|
||||
@ -42,7 +43,7 @@ impl<F: OEF<D>, const D: usize> From<F> for ExtensionAlgebra<F, D> {
|
||||
}
|
||||
|
||||
impl<F: OEF<D>, const D: usize> Display for ExtensionAlgebra<F, D> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "({})", self.0[0])?;
|
||||
for i in 1..D {
|
||||
write!(f, " + ({})*b^{i}", self.0[i])?;
|
||||
@ -52,7 +53,7 @@ impl<F: OEF<D>, const D: usize> Display for ExtensionAlgebra<F, D> {
|
||||
}
|
||||
|
||||
impl<F: OEF<D>, const D: usize> Debug for ExtensionAlgebra<F, D> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
@ -190,12 +191,14 @@ impl<F: OEF<D>, const D: usize> PolynomialCoeffsAlgebra<F, D> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
use crate::extension::algebra::ExtensionAlgebra;
|
||||
use crate::extension::{Extendable, FieldExtension};
|
||||
use crate::goldilocks_field::GoldilocksField;
|
||||
use crate::types::Field;
|
||||
use crate::types::{Field, Sample};
|
||||
|
||||
/// Tests that the multiplication on the extension algebra lifts that of the field extension.
|
||||
fn test_extension_algebra<F: Extendable<D>, const D: usize>() {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use std::convert::TryInto;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::types::Field;
|
||||
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::iter::{Product, Sum};
|
||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
use core::fmt::{self, Debug, Display, Formatter};
|
||||
use core::iter::{Product, Sum};
|
||||
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
|
||||
use num::bigint::BigUint;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::extension::{Extendable, FieldExtension, Frobenius, OEF};
|
||||
use crate::ops::Square;
|
||||
use crate::types::Field;
|
||||
use crate::types::{Field, Sample};
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
#[serde(bound = "")]
|
||||
@ -48,6 +48,16 @@ impl<F: Extendable<2>> From<F> for QuadraticExtension<F> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Extendable<2>> Sample for QuadraticExtension<F> {
|
||||
#[inline]
|
||||
fn sample<R>(rng: &mut R) -> Self
|
||||
where
|
||||
R: rand::RngCore + ?Sized,
|
||||
{
|
||||
Self([F::sample(rng), F::sample(rng)])
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Extendable<2>> Field for QuadraticExtension<F> {
|
||||
const ZERO: Self = Self([F::ZERO; 2]);
|
||||
const ONE: Self = Self([F::ONE, F::ZERO]);
|
||||
@ -99,21 +109,16 @@ impl<F: Extendable<2>> Field for QuadraticExtension<F> {
|
||||
fn from_noncanonical_u128(n: u128) -> Self {
|
||||
F::from_noncanonical_u128(n).into()
|
||||
}
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
fn rand_from_rng<R: rand::Rng>(rng: &mut R) -> Self {
|
||||
Self([F::rand_from_rng(rng), F::rand_from_rng(rng)])
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Extendable<2>> Display for QuadraticExtension<F> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{} + {}*a", self.0[0], self.0[1])
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Extendable<2>> Debug for QuadraticExtension<F> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::iter::{Product, Sum};
|
||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
use core::fmt::{self, Debug, Display, Formatter};
|
||||
use core::iter::{Product, Sum};
|
||||
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
|
||||
use num::bigint::BigUint;
|
||||
use num::traits::Pow;
|
||||
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::extension::{Extendable, FieldExtension, Frobenius, OEF};
|
||||
use crate::ops::Square;
|
||||
use crate::types::Field;
|
||||
use crate::types::{Field, Sample};
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
#[serde(bound = "")]
|
||||
@ -49,6 +49,21 @@ impl<F: Extendable<4>> From<F> for QuarticExtension<F> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Extendable<4>> Sample for QuarticExtension<F> {
|
||||
#[inline]
|
||||
fn sample<R>(rng: &mut R) -> Self
|
||||
where
|
||||
R: rand::RngCore + ?Sized,
|
||||
{
|
||||
Self::from_basefield_array([
|
||||
F::sample(rng),
|
||||
F::sample(rng),
|
||||
F::sample(rng),
|
||||
F::sample(rng),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Extendable<4>> Field for QuarticExtension<F> {
|
||||
const ZERO: Self = Self([F::ZERO; 4]);
|
||||
const ONE: Self = Self([F::ONE, F::ZERO, F::ZERO, F::ZERO]);
|
||||
@ -104,20 +119,10 @@ impl<F: Extendable<4>> Field for QuarticExtension<F> {
|
||||
fn from_noncanonical_u128(n: u128) -> Self {
|
||||
F::from_noncanonical_u128(n).into()
|
||||
}
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
fn rand_from_rng<R: rand::Rng>(rng: &mut R) -> Self {
|
||||
Self::from_basefield_array([
|
||||
F::rand_from_rng(rng),
|
||||
F::rand_from_rng(rng),
|
||||
F::rand_from_rng(rng),
|
||||
F::rand_from_rng(rng),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Extendable<4>> Display for QuarticExtension<F> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{} + {}*a + {}*a^2 + {}*a^3",
|
||||
@ -127,7 +132,7 @@ impl<F: Extendable<4>> Display for QuarticExtension<F> {
|
||||
}
|
||||
|
||||
impl<F: Extendable<4>> Debug for QuarticExtension<F> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::iter::{Product, Sum};
|
||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
use core::fmt::{self, Debug, Display, Formatter};
|
||||
use core::iter::{Product, Sum};
|
||||
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
|
||||
use num::bigint::BigUint;
|
||||
use num::traits::Pow;
|
||||
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::extension::{Extendable, FieldExtension, Frobenius, OEF};
|
||||
use crate::ops::Square;
|
||||
use crate::types::Field;
|
||||
use crate::types::{Field, Sample};
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
#[serde(bound = "")]
|
||||
@ -49,6 +49,22 @@ impl<F: Extendable<5>> From<F> for QuinticExtension<F> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Extendable<5>> Sample for QuinticExtension<F> {
|
||||
#[inline]
|
||||
fn sample<R>(rng: &mut R) -> Self
|
||||
where
|
||||
R: rand::RngCore + ?Sized,
|
||||
{
|
||||
Self::from_basefield_array([
|
||||
F::sample(rng),
|
||||
F::sample(rng),
|
||||
F::sample(rng),
|
||||
F::sample(rng),
|
||||
F::sample(rng),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Extendable<5>> Field for QuinticExtension<F> {
|
||||
const ZERO: Self = Self([F::ZERO; 5]);
|
||||
const ONE: Self = Self([F::ONE, F::ZERO, F::ZERO, F::ZERO, F::ZERO]);
|
||||
@ -110,21 +126,10 @@ impl<F: Extendable<5>> Field for QuinticExtension<F> {
|
||||
fn from_noncanonical_u128(n: u128) -> Self {
|
||||
F::from_noncanonical_u128(n).into()
|
||||
}
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
fn rand_from_rng<R: rand::Rng>(rng: &mut R) -> Self {
|
||||
Self::from_basefield_array([
|
||||
F::rand_from_rng(rng),
|
||||
F::rand_from_rng(rng),
|
||||
F::rand_from_rng(rng),
|
||||
F::rand_from_rng(rng),
|
||||
F::rand_from_rng(rng),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
impl<F: Extendable<5>> Display for QuinticExtension<F> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{} + {}*a + {}*a^2 + {}*a^3 + {}*a^4",
|
||||
@ -134,7 +139,7 @@ impl<F: Extendable<5>> Display for QuinticExtension<F> {
|
||||
}
|
||||
|
||||
impl<F: Extendable<5>> Debug for QuinticExtension<F> {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
Display::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use std::cmp::{max, min};
|
||||
use std::option::Option;
|
||||
use alloc::vec::Vec;
|
||||
use core::cmp::{max, min};
|
||||
|
||||
use plonky2_util::{log2_strict, reverse_index_bits_in_place};
|
||||
use unroll::unroll_for_loops;
|
||||
@ -207,6 +207,8 @@ pub(crate) fn fft_classic<F: Field>(values: &mut [F], r: usize, root_table: &Fft
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use plonky2_util::{log2_ceil, log2_strict};
|
||||
|
||||
use crate::fft::{fft, fft_with_options, ifft};
|
||||
@ -224,7 +226,7 @@ mod tests {
|
||||
// "random", the last degree_padded-degree of them are zero.
|
||||
let coeffs = (0..degree)
|
||||
.map(|i| F::from_canonical_usize(i * 1337 % 100))
|
||||
.chain(std::iter::repeat(F::ZERO).take(degree_padded - degree))
|
||||
.chain(core::iter::repeat(F::ZERO).take(degree_padded - degree))
|
||||
.collect::<Vec<_>>();
|
||||
assert_eq!(coeffs.len(), degree_padded);
|
||||
let coefficients = PolynomialCoeffs { coeffs };
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
use crate::extension::Extendable;
|
||||
use crate::extension::Frobenius;
|
||||
use crate::extension::{Extendable, Frobenius};
|
||||
use crate::ops::Square;
|
||||
use crate::types::Field;
|
||||
use crate::types::{Field, Sample};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! test_field_arithmetic {
|
||||
($field:ty) => {
|
||||
mod field_arithmetic {
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use num::bigint::BigUint;
|
||||
use rand::rngs::OsRng;
|
||||
use rand::Rng;
|
||||
use $crate::types::Field;
|
||||
use $crate::types::{Field, Sample};
|
||||
|
||||
#[test]
|
||||
fn batch_inversion() {
|
||||
@ -72,7 +74,7 @@ macro_rules! test_field_arithmetic {
|
||||
fn exponentiation_large() {
|
||||
type F = $field;
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rng = OsRng;
|
||||
|
||||
let base = F::rand();
|
||||
let pow = BigUint::from(rng.gen::<u64>());
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use std::ops::Mul;
|
||||
use core::ops::Mul;
|
||||
|
||||
use static_assertions::const_assert;
|
||||
|
||||
|
||||
@ -1,15 +1,14 @@
|
||||
use std::fmt;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::iter::{Product, Sum};
|
||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
use core::fmt::{self, Debug, Display, Formatter};
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::iter::{Product, Sum};
|
||||
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
|
||||
use num::{BigUint, Integer};
|
||||
use plonky2_util::{assume, branch_hint};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::inversion::try_inverse_u64;
|
||||
use crate::types::{Field, Field64, PrimeField, PrimeField64};
|
||||
use crate::types::{Field, Field64, PrimeField, PrimeField64, Sample};
|
||||
|
||||
const EPSILON: u64 = (1 << 32) - 1;
|
||||
|
||||
@ -57,6 +56,17 @@ impl Debug for GoldilocksField {
|
||||
}
|
||||
}
|
||||
|
||||
impl Sample for GoldilocksField {
|
||||
#[inline]
|
||||
fn sample<R>(rng: &mut R) -> Self
|
||||
where
|
||||
R: rand::RngCore + ?Sized,
|
||||
{
|
||||
use rand::Rng;
|
||||
Self::from_canonical_u64(rng.gen_range(0..Self::ORDER))
|
||||
}
|
||||
}
|
||||
|
||||
impl Field for GoldilocksField {
|
||||
const ZERO: Self = Self(0);
|
||||
const ONE: Self = Self(1);
|
||||
@ -104,11 +114,6 @@ impl Field for GoldilocksField {
|
||||
reduce128(n)
|
||||
}
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
fn rand_from_rng<R: rand::Rng>(rng: &mut R) -> Self {
|
||||
Self::from_canonical_u64(rng.gen_range(0..Self::ORDER))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn multiply_accumulate(&self, x: Self, y: Self) -> Self {
|
||||
// u64 + u64 * u64 cannot overflow.
|
||||
@ -300,10 +305,9 @@ impl DivAssign for GoldilocksField {
|
||||
#[inline(always)]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
unsafe fn add_no_canonicalize_trashing_input(x: u64, y: u64) -> u64 {
|
||||
use std::arch::asm;
|
||||
let res_wrapped: u64;
|
||||
let adjustment: u64;
|
||||
asm!(
|
||||
core::arch::asm!(
|
||||
"add {0}, {1}",
|
||||
// Trick. The carry flag is set iff the addition overflowed.
|
||||
// sbb x, y does x := x - y - CF. In our case, x and y are both {1:e}, so it simply does
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use plonky2_util::log2_ceil;
|
||||
|
||||
use crate::fft::ifft;
|
||||
@ -79,7 +81,7 @@ mod tests {
|
||||
use crate::extension::quartic::QuarticExtension;
|
||||
use crate::goldilocks_field::GoldilocksField;
|
||||
use crate::polynomial::PolynomialCoeffs;
|
||||
use crate::types::Field;
|
||||
use crate::types::{Field, Sample};
|
||||
|
||||
#[test]
|
||||
fn interpolant_random() {
|
||||
|
||||
@ -6,8 +6,8 @@ use crate::types::PrimeField64;
|
||||
#[inline(always)]
|
||||
fn safe_iteration(f: &mut u64, g: &mut u64, c: &mut i128, d: &mut i128, k: &mut u32) {
|
||||
if f < g {
|
||||
std::mem::swap(f, g);
|
||||
std::mem::swap(c, d);
|
||||
core::mem::swap(f, g);
|
||||
core::mem::swap(c, d);
|
||||
}
|
||||
if *f & 3 == *g & 3 {
|
||||
// f - g = 0 (mod 4)
|
||||
@ -36,8 +36,8 @@ fn safe_iteration(f: &mut u64, g: &mut u64, c: &mut i128, d: &mut i128, k: &mut
|
||||
#[inline(always)]
|
||||
unsafe fn unsafe_iteration(f: &mut u64, g: &mut u64, c: &mut i128, d: &mut i128, k: &mut u32) {
|
||||
if *f < *g {
|
||||
std::mem::swap(f, g);
|
||||
std::mem::swap(c, d);
|
||||
core::mem::swap(f, g);
|
||||
core::mem::swap(c, d);
|
||||
}
|
||||
if *f & 3 == *g & 3 {
|
||||
// f - g = 0 (mod 4)
|
||||
|
||||
@ -6,10 +6,16 @@
|
||||
#![allow(clippy::needless_range_loop)]
|
||||
#![allow(clippy::return_self_not_must_use)]
|
||||
#![feature(generic_const_exprs)]
|
||||
#![feature(specialization)]
|
||||
#![feature(stdsimd)]
|
||||
#![feature(specialization)]
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
mod inversion;
|
||||
|
||||
pub(crate) mod arch;
|
||||
|
||||
pub mod batch_util;
|
||||
pub mod cosets;
|
||||
pub mod extension;
|
||||
@ -17,7 +23,6 @@ pub mod fft;
|
||||
pub mod goldilocks_extensions;
|
||||
pub mod goldilocks_field;
|
||||
pub mod interpolation;
|
||||
mod inversion;
|
||||
pub mod ops;
|
||||
pub mod packable;
|
||||
pub mod packed;
|
||||
@ -29,5 +34,6 @@ pub mod zero_poly_coset;
|
||||
|
||||
#[cfg(test)]
|
||||
mod field_testing;
|
||||
|
||||
#[cfg(test)]
|
||||
mod prime_field_testing;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use std::ops::Mul;
|
||||
use core::ops::Mul;
|
||||
|
||||
pub trait Square {
|
||||
fn square(&self) -> Self;
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use std::fmt::Debug;
|
||||
use std::iter::{Product, Sum};
|
||||
use std::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
use std::slice;
|
||||
use core::fmt::Debug;
|
||||
use core::iter::{Product, Sum};
|
||||
use core::ops::{Add, AddAssign, Div, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
use core::slice;
|
||||
|
||||
use crate::ops::Square;
|
||||
use crate::types::Field;
|
||||
@ -82,7 +82,7 @@ where
|
||||
);
|
||||
let buf_ptr = buf.as_ptr().cast::<Self>();
|
||||
let n = buf.len() / Self::WIDTH;
|
||||
unsafe { std::slice::from_raw_parts(buf_ptr, n) }
|
||||
unsafe { slice::from_raw_parts(buf_ptr, n) }
|
||||
}
|
||||
fn pack_slice_mut(buf: &mut [Self::Scalar]) -> &mut [Self] {
|
||||
assert!(
|
||||
@ -93,7 +93,7 @@ where
|
||||
);
|
||||
let buf_ptr = buf.as_mut_ptr().cast::<Self>();
|
||||
let n = buf.len() / Self::WIDTH;
|
||||
unsafe { std::slice::from_raw_parts_mut(buf_ptr, n) }
|
||||
unsafe { slice::from_raw_parts_mut(buf_ptr, n) }
|
||||
}
|
||||
|
||||
fn doubles(&self) -> Self {
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use plonky2_util::log2_ceil;
|
||||
|
||||
use crate::polynomial::PolynomialCoeffs;
|
||||
@ -68,7 +71,7 @@ impl<F: Field> PolynomialCoeffs<F> {
|
||||
}
|
||||
|
||||
/// Let `self=p(X)`, this returns `(p(X)-p(z))/(X-z)`.
|
||||
/// See https://en.wikipedia.org/wiki/Horner%27s_method
|
||||
/// See <https://en.wikipedia.org/wiki/Horner%27s_method>
|
||||
pub fn divide_by_linear(&self, z: F) -> PolynomialCoeffs<F> {
|
||||
let mut bs = self
|
||||
.coeffs
|
||||
@ -131,17 +134,18 @@ impl<F: Field> PolynomialCoeffs<F> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use rand::{thread_rng, Rng};
|
||||
use rand::rngs::OsRng;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::extension::quartic::QuarticExtension;
|
||||
use crate::goldilocks_field::GoldilocksField;
|
||||
use crate::polynomial::PolynomialCoeffs;
|
||||
use crate::types::Field;
|
||||
use crate::types::{Field, Sample};
|
||||
|
||||
#[test]
|
||||
fn test_division_by_linear() {
|
||||
type F = QuarticExtension<GoldilocksField>;
|
||||
let n = thread_rng().gen_range(1..1000);
|
||||
let n = OsRng.gen_range(1..1000);
|
||||
let poly = PolynomialCoeffs::new(F::rand_vec(n));
|
||||
let z = F::rand();
|
||||
let ev = poly.eval(z);
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
pub(crate) mod division;
|
||||
|
||||
use std::cmp::max;
|
||||
use std::iter::Sum;
|
||||
use std::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::cmp::max;
|
||||
use core::iter::Sum;
|
||||
use core::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
|
||||
|
||||
use anyhow::{ensure, Result};
|
||||
use itertools::Itertools;
|
||||
@ -440,10 +442,12 @@ impl<F: Field> Mul for &PolynomialCoeffs<F> {
|
||||
mod tests {
|
||||
use std::time::Instant;
|
||||
|
||||
use rand::{thread_rng, Rng};
|
||||
use rand::rngs::OsRng;
|
||||
use rand::Rng;
|
||||
|
||||
use super::*;
|
||||
use crate::goldilocks_field::GoldilocksField;
|
||||
use crate::types::Sample;
|
||||
|
||||
#[test]
|
||||
fn test_trimmed() {
|
||||
@ -516,7 +520,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_polynomial_multiplication() {
|
||||
type F = GoldilocksField;
|
||||
let mut rng = thread_rng();
|
||||
let mut rng = OsRng;
|
||||
let (a_deg, b_deg) = (rng.gen_range(1..10_000), rng.gen_range(1..10_000));
|
||||
let a = PolynomialCoeffs::new(F::rand_vec(a_deg));
|
||||
let b = PolynomialCoeffs::new(F::rand_vec(b_deg));
|
||||
@ -532,7 +536,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_inv_mod_xn() {
|
||||
type F = GoldilocksField;
|
||||
let mut rng = thread_rng();
|
||||
let mut rng = OsRng;
|
||||
let a_deg = rng.gen_range(0..1_000);
|
||||
let n = rng.gen_range(1..1_000);
|
||||
let mut a = PolynomialCoeffs::new(F::rand_vec(a_deg + 1));
|
||||
@ -557,7 +561,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_polynomial_long_division() {
|
||||
type F = GoldilocksField;
|
||||
let mut rng = thread_rng();
|
||||
let mut rng = OsRng;
|
||||
let (a_deg, b_deg) = (rng.gen_range(1..10_000), rng.gen_range(1..10_000));
|
||||
let a = PolynomialCoeffs::new(F::rand_vec(a_deg));
|
||||
let b = PolynomialCoeffs::new(F::rand_vec(b_deg));
|
||||
@ -571,7 +575,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_polynomial_division() {
|
||||
type F = GoldilocksField;
|
||||
let mut rng = thread_rng();
|
||||
let mut rng = OsRng;
|
||||
let (a_deg, b_deg) = (rng.gen_range(1..10_000), rng.gen_range(1..10_000));
|
||||
let a = PolynomialCoeffs::new(F::rand_vec(a_deg));
|
||||
let b = PolynomialCoeffs::new(F::rand_vec(b_deg));
|
||||
@ -585,7 +589,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_polynomial_division_by_constant() {
|
||||
type F = GoldilocksField;
|
||||
let mut rng = thread_rng();
|
||||
let mut rng = OsRng;
|
||||
let a_deg = rng.gen_range(1..10_000);
|
||||
let a = PolynomialCoeffs::new(F::rand_vec(a_deg));
|
||||
let b = PolynomialCoeffs::from(vec![F::rand()]);
|
||||
@ -601,7 +605,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_division_linear() {
|
||||
type F = GoldilocksField;
|
||||
let mut rng = thread_rng();
|
||||
let mut rng = OsRng;
|
||||
let l = 14;
|
||||
let n = 1 << l;
|
||||
let g = F::primitive_root_of_unity(l);
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::types::PrimeField64;
|
||||
|
||||
/// Generates a series of non-negative integers less than `modulus` which cover a range of
|
||||
@ -68,7 +70,7 @@ where
|
||||
macro_rules! test_prime_field_arithmetic {
|
||||
($field:ty) => {
|
||||
mod prime_field_arithmetic {
|
||||
use std::ops::{Add, Mul, Neg, Sub};
|
||||
use core::ops::{Add, Mul, Neg, Sub};
|
||||
|
||||
use $crate::ops::Square;
|
||||
use $crate::types::{Field, Field64};
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
use std::fmt;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::iter::{Product, Sum};
|
||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::{self, Debug, Display, Formatter};
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::iter::{Product, Sum};
|
||||
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
|
||||
use itertools::Itertools;
|
||||
use num::bigint::BigUint;
|
||||
use num::{Integer, One};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::types::{Field, PrimeField};
|
||||
use crate::types::{Field, PrimeField, Sample};
|
||||
|
||||
/// The base field of the secp256k1 elliptic curve.
|
||||
///
|
||||
@ -65,6 +65,17 @@ impl Debug for Secp256K1Base {
|
||||
}
|
||||
}
|
||||
|
||||
impl Sample for Secp256K1Base {
|
||||
#[inline]
|
||||
fn sample<R>(rng: &mut R) -> Self
|
||||
where
|
||||
R: rand::RngCore + ?Sized,
|
||||
{
|
||||
use num::bigint::RandBigInt;
|
||||
Self::from_noncanonical_biguint(rng.gen_biguint_below(&Self::order()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Field for Secp256K1Base {
|
||||
const ZERO: Self = Self([0; 4]);
|
||||
const ONE: Self = Self([1, 0, 0, 0]);
|
||||
@ -131,12 +142,6 @@ impl Field for Secp256K1Base {
|
||||
fn from_noncanonical_u96(n: (u64, u32)) -> Self {
|
||||
Self([n.0, n.1 as u64, 0, 0])
|
||||
}
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
fn rand_from_rng<R: rand::Rng>(rng: &mut R) -> Self {
|
||||
use num::bigint::RandBigInt;
|
||||
Self::from_noncanonical_biguint(rng.gen_biguint_below(&Self::order()))
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimeField for Secp256K1Base {
|
||||
|
||||
@ -1,16 +1,15 @@
|
||||
use std::convert::TryInto;
|
||||
use std::fmt;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::iter::{Product, Sum};
|
||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::{self, Debug, Display, Formatter};
|
||||
use core::hash::{Hash, Hasher};
|
||||
use core::iter::{Product, Sum};
|
||||
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
|
||||
use itertools::Itertools;
|
||||
use num::bigint::BigUint;
|
||||
use num::{Integer, One};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::types::{Field, PrimeField};
|
||||
use crate::types::{Field, PrimeField, Sample};
|
||||
|
||||
/// The base field of the secp256k1 elliptic curve.
|
||||
///
|
||||
@ -68,6 +67,17 @@ impl Debug for Secp256K1Scalar {
|
||||
}
|
||||
}
|
||||
|
||||
impl Sample for Secp256K1Scalar {
|
||||
#[inline]
|
||||
fn sample<R>(rng: &mut R) -> Self
|
||||
where
|
||||
R: rand::RngCore + ?Sized,
|
||||
{
|
||||
use num::bigint::RandBigInt;
|
||||
Self::from_noncanonical_biguint(rng.gen_biguint_below(&Self::order()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Field for Secp256K1Scalar {
|
||||
const ZERO: Self = Self([0; 4]);
|
||||
const ONE: Self = Self([1, 0, 0, 0]);
|
||||
@ -140,12 +150,6 @@ impl Field for Secp256K1Scalar {
|
||||
fn from_noncanonical_u96(n: (u64, u32)) -> Self {
|
||||
Self([n.0, n.1 as u64, 0, 0])
|
||||
}
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
fn rand_from_rng<R: rand::Rng>(rng: &mut R) -> Self {
|
||||
use num::bigint::RandBigInt;
|
||||
Self::from_noncanonical_biguint(rng.gen_biguint_below(&Self::order()))
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimeField for Secp256K1Scalar {
|
||||
|
||||
@ -1,17 +1,49 @@
|
||||
use std::fmt::{Debug, Display};
|
||||
use std::hash::Hash;
|
||||
use std::iter::{Product, Sum};
|
||||
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
use core::fmt::{Debug, Display};
|
||||
use core::hash::Hash;
|
||||
use core::iter::{Product, Sum};
|
||||
use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
|
||||
|
||||
use num::bigint::BigUint;
|
||||
use num::{Integer, One, ToPrimitive, Zero};
|
||||
use plonky2_util::bits_u64;
|
||||
use rand::rngs::OsRng;
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::extension::Frobenius;
|
||||
use crate::ops::Square;
|
||||
|
||||
/// Sampling
|
||||
pub trait Sample: Sized {
|
||||
/// Samples a single value using `rng`.
|
||||
fn sample<R>(rng: &mut R) -> Self
|
||||
where
|
||||
R: rand::RngCore + ?Sized;
|
||||
|
||||
/// Samples a single value using the [`OsRng`].
|
||||
#[inline]
|
||||
fn rand() -> Self {
|
||||
Self::sample(&mut OsRng)
|
||||
}
|
||||
|
||||
/// Samples a [`Vec`] of values of length `n` using [`OsRng`].
|
||||
#[inline]
|
||||
fn rand_vec(n: usize) -> Vec<Self> {
|
||||
(0..n).map(|_| Self::rand()).collect()
|
||||
}
|
||||
|
||||
/// Samples an array of values of length `N` using [`OsRng`].
|
||||
#[inline]
|
||||
fn rand_array<const N: usize>() -> [Self; N] {
|
||||
Self::rand_vec(N)
|
||||
.try_into()
|
||||
.ok()
|
||||
.expect("This conversion can never fail.")
|
||||
}
|
||||
}
|
||||
|
||||
/// A finite field.
|
||||
pub trait Field:
|
||||
'static
|
||||
@ -33,6 +65,7 @@ pub trait Field:
|
||||
+ Debug
|
||||
+ Default
|
||||
+ Display
|
||||
+ Sample
|
||||
+ Send
|
||||
+ Sync
|
||||
+ Serialize
|
||||
@ -317,9 +350,6 @@ pub trait Field:
|
||||
Self::from_noncanonical_u128(n)
|
||||
}
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
fn rand_from_rng<R: rand::Rng>(rng: &mut R) -> Self;
|
||||
|
||||
fn exp_power_of_2(&self, power_log: usize) -> Self {
|
||||
let mut res = *self;
|
||||
for _ in 0..power_log {
|
||||
@ -397,21 +427,6 @@ pub trait Field:
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
fn rand() -> Self {
|
||||
Self::rand_from_rng(&mut rand::thread_rng())
|
||||
}
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
fn rand_arr<const N: usize>() -> [Self; N] {
|
||||
Self::rand_vec(N).try_into().unwrap()
|
||||
}
|
||||
|
||||
#[cfg(feature = "rand")]
|
||||
fn rand_vec(n: usize) -> Vec<Self> {
|
||||
(0..n).map(|_| Self::rand()).collect()
|
||||
}
|
||||
|
||||
/// Representative `g` of the coset used in FRI, so that LDEs in FRI are done over `gH`.
|
||||
fn coset_shift() -> Self {
|
||||
Self::MULTIPLICATIVE_GROUP_GENERATOR
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::packed::PackedField;
|
||||
use crate::types::Field;
|
||||
|
||||
|
||||
@ -5,5 +5,9 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = { version = "1.0.40", default-features = false }
|
||||
plonky2 = { path = "../plonky2", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
plonky2 = { path = "../plonky2" }
|
||||
anyhow = "1.0.40"
|
||||
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use plonky2::field::extension::Extendable;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::ext_target::ExtensionTarget;
|
||||
@ -50,7 +53,7 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilderInsert<F, D>
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use anyhow::Result;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::field::types::{Field, Sample};
|
||||
use plonky2::iop::witness::PartialWitness;
|
||||
use plonky2::plonk::circuit_data::CircuitConfig;
|
||||
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Range;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use alloc::{format, vec};
|
||||
use core::marker::PhantomData;
|
||||
use core::ops::Range;
|
||||
|
||||
use plonky2::field::extension::{Extendable, FieldExtension};
|
||||
use plonky2::field::types::Field;
|
||||
@ -317,18 +321,14 @@ impl<F: RichField + Extendable<D>, const D: usize> SimpleGenerator<F> for Insert
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use anyhow::Result;
|
||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::gates::gate::Gate;
|
||||
use plonky2::field::types::Sample;
|
||||
use plonky2::gates::gate_testing::{test_eval_fns, test_low_degree};
|
||||
use plonky2::hash::hash_types::HashOut;
|
||||
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
|
||||
use plonky2::plonk::vars::EvaluationVars;
|
||||
|
||||
use crate::insertion_gate::InsertionGate;
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn wire_indices() {
|
||||
|
||||
@ -4,6 +4,9 @@
|
||||
#![allow(clippy::len_without_is_empty)]
|
||||
#![allow(clippy::needless_range_loop)]
|
||||
#![allow(clippy::return_self_not_must_use)]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub mod insert_gadget;
|
||||
pub mod insertion_gate;
|
||||
|
||||
@ -3,7 +3,6 @@ name = "maybe_rayon"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[features]
|
||||
parallel = ["rayon"]
|
||||
|
||||
|
||||
@ -1,13 +1,16 @@
|
||||
#[cfg(not(feature = "parallel"))]
|
||||
use std::{
|
||||
use core::{
|
||||
iter::{FlatMap, IntoIterator, Iterator},
|
||||
slice::{Chunks, ChunksExact, ChunksExactMut, ChunksMut},
|
||||
};
|
||||
|
||||
#[cfg(feature = "parallel")]
|
||||
pub use rayon::prelude::{
|
||||
IndexedParallelIterator, ParallelDrainFull, ParallelDrainRange, ParallelExtend,
|
||||
ParallelIterator,
|
||||
pub use rayon::{
|
||||
self,
|
||||
prelude::{
|
||||
IndexedParallelIterator, ParallelDrainFull, ParallelDrainRange, ParallelExtend,
|
||||
ParallelIterator,
|
||||
},
|
||||
};
|
||||
#[cfg(feature = "parallel")]
|
||||
use rayon::{
|
||||
|
||||
@ -11,45 +11,46 @@ edition = "2021"
|
||||
default-run = "generate_constants"
|
||||
|
||||
[features]
|
||||
default = ["parallel", "rand", "rand_chacha", "timing", "gate_testing"]
|
||||
parallel = ["maybe_rayon/parallel"]
|
||||
rand = ["dep:rand", "plonky2_field/rand"]
|
||||
gate_testing = ["rand"]
|
||||
rand_chacha = ["dep:rand_chacha"]
|
||||
timing = []
|
||||
default = ["gate_testing", "parallel", "rand_chacha", "std", "timing"]
|
||||
gate_testing = []
|
||||
parallel = ["hashbrown/rayon", "maybe_rayon/parallel"]
|
||||
std = ["anyhow/std", "rand/std"]
|
||||
timing = ["std"]
|
||||
|
||||
[dependencies]
|
||||
plonky2_field = { path = "../field" }
|
||||
plonky2_util = { path = "../util" }
|
||||
log = "0.4.14"
|
||||
itertools = "0.10.0"
|
||||
num = { version = "0.4", features = [ "rand" ] }
|
||||
rand = { version = "0.8.4", optional = true }
|
||||
rand_chacha = { version = "0.3.1", optional = true }
|
||||
maybe_rayon = { path = "../maybe_rayon" }
|
||||
unroll = "0.1.5"
|
||||
anyhow = "1.0.40"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_cbor = "0.11.1"
|
||||
keccak-hash = "0.8.0"
|
||||
static_assertions = "1.1.0"
|
||||
ahash = { version = "0.7.6", default-features = false, features = ["compile-time-rng"] } # NOTE: Be sure to keep this version the same as the dependency in `hashbrown`.
|
||||
anyhow = { version = "1.0.40", default-features = false }
|
||||
hashbrown = { version = "0.12.3", default-features = false, features = ["ahash", "serde"] } # NOTE: When upgrading, see `ahash` dependency.
|
||||
itertools = { version = "0.10.0", default-features = false }
|
||||
keccak-hash = { version = "0.8.0", default-features = false }
|
||||
log = { version = "0.4.14", default-features = false }
|
||||
maybe_rayon = { path = "../maybe_rayon", default-features = false }
|
||||
num = { version = "0.4", default-features = false, features = ["rand"] }
|
||||
plonky2_field = { path = "../field", default-features = false }
|
||||
plonky2_util = { path = "../util", default-features = false }
|
||||
rand = { version = "0.8.4", default-features = false }
|
||||
rand_chacha = { version = "0.3.1", optional = true, default-features = false }
|
||||
serde = { version = "1.0", default-features = false, features = ["derive"] }
|
||||
static_assertions = { version = "1.1.0", default-features = false }
|
||||
unroll = { version = "0.1.5", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.8.4"
|
||||
rand_chacha = "0.3.1"
|
||||
criterion = "0.4.0"
|
||||
env_logger = "0.9.0"
|
||||
tynm = "0.1.6"
|
||||
structopt = "0.3.26"
|
||||
num_cpus = "1.13.1"
|
||||
rayon = "1.5.1"
|
||||
criterion = { version = "0.4.0", default-features = false }
|
||||
env_logger = { version = "0.9.0", default-features = false }
|
||||
num_cpus = { version = "1.14.0", default-features = false }
|
||||
plonky2 = { path = "." }
|
||||
rand = { version = "0.8.4", default-features = false, features = ["getrandom"] }
|
||||
rand_chacha = { version = "0.3.1", default-features = false }
|
||||
serde_cbor = { version = "0.11.2" }
|
||||
structopt = { version = "0.3.26", default-features = false }
|
||||
tynm = { version = "0.1.6", default-features = false }
|
||||
|
||||
[target.'cfg(not(target_env = "msvc"))'.dev-dependencies]
|
||||
jemallocator = "0.3.2"
|
||||
|
||||
[[bin]]
|
||||
name = "generate_constants"
|
||||
required-features = ["rand", "rand_chacha"]
|
||||
required-features = ["rand_chacha"]
|
||||
|
||||
[[bench]]
|
||||
name = "field_arithmetic"
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(generic_const_exprs)]
|
||||
|
||||
mod allocator;
|
||||
|
||||
use criterion::{criterion_group, criterion_main, BatchSize, Criterion};
|
||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||
use plonky2::field::types::Sample;
|
||||
use plonky2::hash::hash_types::{BytesHash, RichField};
|
||||
use plonky2::hash::hashing::SPONGE_WIDTH;
|
||||
use plonky2::hash::keccak::KeccakHash;
|
||||
@ -27,7 +25,7 @@ pub(crate) fn bench_poseidon<F: Poseidon>(c: &mut Criterion) {
|
||||
&format!("poseidon<{}, {SPONGE_WIDTH}>", type_name::<F>()),
|
||||
|b| {
|
||||
b.iter_batched(
|
||||
|| F::rand_arr::<SPONGE_WIDTH>(),
|
||||
|| F::rand_array::<SPONGE_WIDTH>(),
|
||||
|state| F::poseidon(state),
|
||||
BatchSize::SmallInput,
|
||||
)
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
#![feature(generic_const_exprs)]
|
||||
|
||||
mod allocator;
|
||||
|
||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
@ -13,10 +11,7 @@ use tynm::type_name;
|
||||
|
||||
const ELEMS_PER_LEAF: usize = 135;
|
||||
|
||||
pub(crate) fn bench_merkle_tree<F: RichField, H: Hasher<F>>(c: &mut Criterion)
|
||||
where
|
||||
[(); H::HASH_SIZE]:,
|
||||
{
|
||||
pub(crate) fn bench_merkle_tree<F: RichField, H: Hasher<F>>(c: &mut Criterion) {
|
||||
let mut group = c.benchmark_group(&format!(
|
||||
"merkle-tree<{}, {}>",
|
||||
type_name::<F>(),
|
||||
|
||||
@ -2,7 +2,7 @@ mod allocator;
|
||||
|
||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::field::types::Sample;
|
||||
use plonky2_util::{reverse_index_bits, reverse_index_bits_in_place};
|
||||
|
||||
type F = GoldilocksField;
|
||||
|
||||
@ -2,7 +2,7 @@ mod allocator;
|
||||
|
||||
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
|
||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||
use plonky2::field::types::Field;
|
||||
use plonky2::field::types::Sample;
|
||||
use plonky2::util::transpose;
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
|
||||
@ -2,30 +2,28 @@
|
||||
// custom CLI argument parsing (even with harness disabled). We could also have
|
||||
// put it in `src/bin/`, but then we wouldn't have access to
|
||||
// `[dev-dependencies]`.
|
||||
#![allow(incomplete_features)]
|
||||
#![feature(generic_const_exprs)]
|
||||
|
||||
use std::{num::ParseIntError, ops::RangeInclusive, str::FromStr};
|
||||
use core::num::ParseIntError;
|
||||
use core::ops::RangeInclusive;
|
||||
use core::str::FromStr;
|
||||
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use log::{info, Level, LevelFilter};
|
||||
use plonky2::{
|
||||
gates::noop::NoopGate,
|
||||
hash::hash_types::RichField,
|
||||
iop::witness::{PartialWitness, Witness},
|
||||
plonk::{
|
||||
circuit_builder::CircuitBuilder,
|
||||
circuit_data::{
|
||||
CircuitConfig, CommonCircuitData, VerifierCircuitTarget, VerifierOnlyCircuitData,
|
||||
},
|
||||
config::{AlgebraicHasher, GenericConfig, Hasher, PoseidonGoldilocksConfig},
|
||||
proof::{CompressedProofWithPublicInputs, ProofWithPublicInputs},
|
||||
prover::prove,
|
||||
},
|
||||
util::timing::TimingTree,
|
||||
use maybe_rayon::rayon;
|
||||
use plonky2::gates::noop::NoopGate;
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::witness::{PartialWitness, Witness};
|
||||
use plonky2::plonk::circuit_builder::CircuitBuilder;
|
||||
use plonky2::plonk::circuit_data::{
|
||||
CircuitConfig, CommonCircuitData, VerifierCircuitTarget, VerifierOnlyCircuitData,
|
||||
};
|
||||
use plonky2::plonk::config::{AlgebraicHasher, GenericConfig, PoseidonGoldilocksConfig};
|
||||
use plonky2::plonk::proof::{CompressedProofWithPublicInputs, ProofWithPublicInputs};
|
||||
use plonky2::plonk::prover::prove;
|
||||
use plonky2::util::timing::TimingTree;
|
||||
use plonky2_field::extension::Extendable;
|
||||
use rand::{rngs::OsRng, RngCore, SeedableRng};
|
||||
use rand::rngs::OsRng;
|
||||
use rand::{RngCore, SeedableRng};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
use structopt::StructOpt;
|
||||
|
||||
@ -66,10 +64,7 @@ struct Options {
|
||||
fn dummy_proof<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>(
|
||||
config: &CircuitConfig,
|
||||
log2_size: usize,
|
||||
) -> Result<ProofTuple<F, C, D>>
|
||||
where
|
||||
[(); C::Hasher::HASH_SIZE]:,
|
||||
{
|
||||
) -> Result<ProofTuple<F, C, D>> {
|
||||
// 'size' is in degree, but we want number of noop gates. A non-zero amount of padding will be added and size will be rounded to the next power of two. To hit our target size, we go just under the previous power of two and hope padding is less than half the proof.
|
||||
let num_dummy_gates = match log2_size {
|
||||
0 => return Err(anyhow!("size must be at least 1")),
|
||||
@ -107,21 +102,17 @@ fn recursive_proof<
|
||||
) -> Result<ProofTuple<F, C, D>>
|
||||
where
|
||||
InnerC::Hasher: AlgebraicHasher<F>,
|
||||
[(); C::Hasher::HASH_SIZE]:,
|
||||
{
|
||||
let (inner_proof, inner_vd, inner_cd) = inner;
|
||||
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
|
||||
let mut pw = PartialWitness::new();
|
||||
let pt = builder.add_virtual_proof_with_pis::<InnerC>(inner_cd);
|
||||
pw.set_proof_with_pis_target(&pt, inner_proof);
|
||||
|
||||
let inner_data = VerifierCircuitTarget {
|
||||
constants_sigmas_cap: builder.add_virtual_cap(inner_cd.config.fri_config.cap_height),
|
||||
circuit_digest: builder.add_virtual_hash(),
|
||||
};
|
||||
pw.set_verifier_data_target(&inner_data, inner_vd);
|
||||
|
||||
builder.verify_proof::<InnerC>(pt, &inner_data, inner_cd);
|
||||
builder.verify_proof::<InnerC>(&pt, &inner_data, inner_cd);
|
||||
builder.print_gate_counts(0);
|
||||
|
||||
if let Some(min_degree_bits) = min_degree_bits {
|
||||
@ -137,6 +128,10 @@ where
|
||||
|
||||
let data = builder.build::<C>();
|
||||
|
||||
let mut pw = PartialWitness::new();
|
||||
pw.set_proof_with_pis_target(&pt, inner_proof);
|
||||
pw.set_verifier_data_target(&inner_data, inner_vd);
|
||||
|
||||
let mut timing = TimingTree::new("prove", Level::Debug);
|
||||
let proof = prove(&data.prover_only, &data.common, pw, &mut timing)?;
|
||||
timing.print();
|
||||
@ -151,11 +146,8 @@ fn test_serialization<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>,
|
||||
proof: &ProofWithPublicInputs<F, C, D>,
|
||||
vd: &VerifierOnlyCircuitData<C, D>,
|
||||
cd: &CommonCircuitData<F, D>,
|
||||
) -> Result<()>
|
||||
where
|
||||
[(); C::Hasher::HASH_SIZE]:,
|
||||
{
|
||||
let proof_bytes = proof.to_bytes()?;
|
||||
) -> Result<()> {
|
||||
let proof_bytes = proof.to_bytes();
|
||||
info!("Proof length: {} bytes", proof_bytes.len());
|
||||
let proof_from_bytes = ProofWithPublicInputs::from_bytes(proof_bytes, cd)?;
|
||||
assert_eq!(proof, &proof_from_bytes);
|
||||
@ -168,7 +160,7 @@ where
|
||||
info!("{:.4}s to compress proof", now.elapsed().as_secs_f64());
|
||||
assert_eq!(proof, &decompressed_compressed_proof);
|
||||
|
||||
let compressed_proof_bytes = compressed_proof.to_bytes()?;
|
||||
let compressed_proof_bytes = compressed_proof.to_bytes();
|
||||
info!(
|
||||
"Compressed proof length: {} bytes",
|
||||
compressed_proof_bytes.len()
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
use std::marker::PhantomData;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use anyhow::Result;
|
||||
use plonky2::field::types::{Field, PrimeField};
|
||||
use plonky2::field::types::{PrimeField, Sample};
|
||||
use plonky2::hash::hash_types::RichField;
|
||||
use plonky2::iop::generator::{GeneratedValues, SimpleGenerator};
|
||||
use plonky2::iop::target::Target;
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
|
||||
#![allow(clippy::needless_range_loop)]
|
||||
|
||||
use plonky2_field::goldilocks_field::GoldilocksField;
|
||||
use plonky2_field::types::Field64;
|
||||
use plonky2::field::goldilocks_field::GoldilocksField;
|
||||
use plonky2::field::types::Field64;
|
||||
use rand::{Rng, SeedableRng};
|
||||
use rand_chacha::ChaCha8Rng;
|
||||
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_field::polynomial::PolynomialCoeffs;
|
||||
|
||||
use crate::field::extension::Extendable;
|
||||
use crate::field::polynomial::PolynomialCoeffs;
|
||||
use crate::fri::proof::{FriChallenges, FriChallengesTarget};
|
||||
use crate::fri::structure::{FriOpenings, FriOpeningsTarget};
|
||||
use crate::fri::FriConfig;
|
||||
@ -49,16 +48,8 @@ impl<F: RichField, H: Hasher<F>> Challenger<F, H> {
|
||||
|
||||
self.observe_extension_elements(&final_poly.coeffs);
|
||||
|
||||
let fri_pow_response = C::InnerHasher::hash_no_pad(
|
||||
&self
|
||||
.get_hash()
|
||||
.elements
|
||||
.iter()
|
||||
.copied()
|
||||
.chain(Some(pow_witness))
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.elements[0];
|
||||
self.observe_element(pow_witness);
|
||||
let fri_pow_response = self.get_challenge();
|
||||
|
||||
let fri_query_indices = (0..num_fri_queries)
|
||||
.map(|_| self.get_challenge().to_canonical_u64() as usize % lde_size)
|
||||
@ -105,16 +96,8 @@ impl<F: RichField + Extendable<D>, H: AlgebraicHasher<F>, const D: usize>
|
||||
|
||||
self.observe_extension_elements(&final_poly.0);
|
||||
|
||||
let pow_inputs = self
|
||||
.get_hash(builder)
|
||||
.elements
|
||||
.iter()
|
||||
.copied()
|
||||
.chain(Some(pow_witness))
|
||||
.collect();
|
||||
let fri_pow_response = builder
|
||||
.hash_n_to_hash_no_pad::<C::InnerHasher>(pow_inputs)
|
||||
.elements[0];
|
||||
self.observe_element(pow_witness);
|
||||
let fri_pow_response = self.get_challenge(builder);
|
||||
|
||||
let fri_query_indices = (0..num_fri_queries)
|
||||
.map(|_| self.get_challenge(builder))
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use crate::fri::reduction_strategies::FriReductionStrategy;
|
||||
|
||||
mod challenges;
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
use alloc::format;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use itertools::Itertools;
|
||||
use maybe_rayon::*;
|
||||
use plonky2_field::extension::Extendable;
|
||||
use plonky2_field::fft::FftRootTable;
|
||||
use plonky2_field::packed::PackedField;
|
||||
use plonky2_field::polynomial::{PolynomialCoeffs, PolynomialValues};
|
||||
use plonky2_field::types::Field;
|
||||
use plonky2_util::{log2_strict, reverse_index_bits_in_place};
|
||||
|
||||
use crate::field::extension::Extendable;
|
||||
use crate::field::fft::FftRootTable;
|
||||
use crate::field::packed::PackedField;
|
||||
use crate::field::polynomial::{PolynomialCoeffs, PolynomialValues};
|
||||
use crate::field::types::Field;
|
||||
use crate::fri::proof::FriProof;
|
||||
use crate::fri::prover::fri_proof;
|
||||
use crate::fri::structure::{FriBatchInfo, FriInstanceInfo};
|
||||
@ -14,12 +16,11 @@ use crate::fri::FriParams;
|
||||
use crate::hash::hash_types::RichField;
|
||||
use crate::hash::merkle_tree::MerkleTree;
|
||||
use crate::iop::challenger::Challenger;
|
||||
use crate::plonk::config::{GenericConfig, Hasher};
|
||||
use crate::plonk::config::GenericConfig;
|
||||
use crate::timed;
|
||||
use crate::util::reducing::ReducingFactor;
|
||||
use crate::util::reverse_bits;
|
||||
use crate::util::timing::TimingTree;
|
||||
use crate::util::transpose;
|
||||
use crate::util::{log2_strict, reverse_bits, reverse_index_bits_in_place, transpose};
|
||||
|
||||
/// Four (~64 bit) field elements gives ~128 bit security.
|
||||
pub const SALT_SIZE: usize = 4;
|
||||
@ -45,10 +46,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
cap_height: usize,
|
||||
timing: &mut TimingTree,
|
||||
fft_root_table: Option<&FftRootTable<F>>,
|
||||
) -> Self
|
||||
where
|
||||
[(); C::Hasher::HASH_SIZE]:,
|
||||
{
|
||||
) -> Self {
|
||||
let coeffs = timed!(
|
||||
timing,
|
||||
"IFFT",
|
||||
@ -73,10 +71,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
cap_height: usize,
|
||||
timing: &mut TimingTree,
|
||||
fft_root_table: Option<&FftRootTable<F>>,
|
||||
) -> Self
|
||||
where
|
||||
[(); C::Hasher::HASH_SIZE]:,
|
||||
{
|
||||
) -> Self {
|
||||
let degree = polynomials[0].len();
|
||||
let lde_values = timed!(
|
||||
timing,
|
||||
@ -169,10 +164,7 @@ impl<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>
|
||||
challenger: &mut Challenger<F, C::Hasher>,
|
||||
fri_params: &FriParams,
|
||||
timing: &mut TimingTree,
|
||||
) -> FriProof<F, C::Hasher, D>
|
||||
where
|
||||
[(); C::Hasher::HASH_SIZE]:,
|
||||
{
|
||||
) -> FriProof<F, C::Hasher, D> {
|
||||
assert!(D > 1, "Not implemented for D=1.");
|
||||
let alpha = challenger.get_extension_challenge::<D>();
|
||||
let mut alpha = ReducingFactor::new(alpha);
|
||||
|
||||
@ -1,14 +1,15 @@
|
||||
use std::collections::HashMap;
|
||||
use alloc::vec;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use itertools::izip;
|
||||
use plonky2_field::extension::{flatten, unflatten, Extendable};
|
||||
use plonky2_field::polynomial::PolynomialCoeffs;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::field::extension::{flatten, unflatten, Extendable};
|
||||
use crate::field::polynomial::PolynomialCoeffs;
|
||||
use crate::fri::FriParams;
|
||||
use crate::gadgets::polynomial::PolynomialCoeffsExtTarget;
|
||||
use crate::hash::hash_types::MerkleCapTarget;
|
||||
use crate::hash::hash_types::RichField;
|
||||
use crate::hash::hash_types::{MerkleCapTarget, RichField};
|
||||
use crate::hash::merkle_proofs::{MerkleProof, MerkleProofTarget};
|
||||
use crate::hash::merkle_tree::MerkleCap;
|
||||
use crate::hash::path_compression::{compress_merkle_proofs, decompress_merkle_proofs};
|
||||
@ -111,7 +112,7 @@ pub struct FriProof<F: RichField + Extendable<D>, H: Hasher<F>, const D: usize>
|
||||
pub pow_witness: F,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FriProofTarget<const D: usize> {
|
||||
pub commit_phase_merkle_caps: Vec<MerkleCapTarget>,
|
||||
pub query_round_proofs: Vec<FriQueryRoundTarget<D>>,
|
||||
@ -245,10 +246,7 @@ impl<F: RichField + Extendable<D>, H: Hasher<F>, const D: usize> CompressedFriPr
|
||||
challenges: &ProofChallenges<F, D>,
|
||||
fri_inferred_elements: FriInferredElements<F, D>,
|
||||
params: &FriParams,
|
||||
) -> FriProof<F, H, D>
|
||||
where
|
||||
[(); H::HASH_SIZE]:,
|
||||
{
|
||||
) -> FriProof<F, H, D> {
|
||||
let CompressedFriProof {
|
||||
commit_phase_merkle_caps,
|
||||
query_round_proofs,
|
||||
|
||||
@ -1,17 +1,19 @@
|
||||
use itertools::Itertools;
|
||||
use maybe_rayon::*;
|
||||
use plonky2_field::extension::{flatten, unflatten, Extendable};
|
||||
use plonky2_field::polynomial::{PolynomialCoeffs, PolynomialValues};
|
||||
use plonky2_util::reverse_index_bits_in_place;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use maybe_rayon::*;
|
||||
|
||||
use crate::field::extension::{flatten, unflatten, Extendable};
|
||||
use crate::field::polynomial::{PolynomialCoeffs, PolynomialValues};
|
||||
use crate::fri::proof::{FriInitialTreeProof, FriProof, FriQueryRound, FriQueryStep};
|
||||
use crate::fri::{FriConfig, FriParams};
|
||||
use crate::hash::hash_types::{HashOut, RichField};
|
||||
use crate::hash::hash_types::RichField;
|
||||
use crate::hash::hashing::{PlonkyPermutation, SPONGE_RATE};
|
||||
use crate::hash::merkle_tree::MerkleTree;
|
||||
use crate::iop::challenger::Challenger;
|
||||
use crate::plonk::config::{GenericConfig, Hasher};
|
||||
use crate::plonk::plonk_common::reduce_with_powers;
|
||||
use crate::timed;
|
||||
use crate::util::reverse_index_bits_in_place;
|
||||
use crate::util::timing::TimingTree;
|
||||
|
||||
/// Builds a FRI proof.
|
||||
@ -24,10 +26,7 @@ pub fn fri_proof<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const
|
||||
challenger: &mut Challenger<F, C::Hasher>,
|
||||
fri_params: &FriParams,
|
||||
timing: &mut TimingTree,
|
||||
) -> FriProof<F, C::Hasher, D>
|
||||
where
|
||||
[(); C::Hasher::HASH_SIZE]:,
|
||||
{
|
||||
) -> FriProof<F, C::Hasher, D> {
|
||||
let n = lde_polynomial_values.len();
|
||||
assert_eq!(lde_polynomial_coeffs.len(), n);
|
||||
|
||||
@ -44,11 +43,10 @@ where
|
||||
);
|
||||
|
||||
// PoW phase
|
||||
let current_hash = challenger.get_hash();
|
||||
let pow_witness = timed!(
|
||||
timing,
|
||||
"find proof-of-work witness",
|
||||
fri_proof_of_work::<F, C, D>(current_hash, &fri_params.config)
|
||||
fri_proof_of_work::<F, C, D>(challenger, &fri_params.config)
|
||||
);
|
||||
|
||||
// Query phase
|
||||
@ -63,18 +61,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
type FriCommitedTrees<F, C, const D: usize> = (
|
||||
Vec<MerkleTree<F, <C as GenericConfig<D>>::Hasher>>,
|
||||
PolynomialCoeffs<<F as Extendable<D>>::Extension>,
|
||||
);
|
||||
|
||||
fn fri_committed_trees<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>(
|
||||
mut coeffs: PolynomialCoeffs<F::Extension>,
|
||||
mut values: PolynomialValues<F::Extension>,
|
||||
challenger: &mut Challenger<F, C::Hasher>,
|
||||
fri_params: &FriParams,
|
||||
) -> (
|
||||
Vec<MerkleTree<F, C::Hasher>>,
|
||||
PolynomialCoeffs<F::Extension>,
|
||||
)
|
||||
where
|
||||
[(); C::Hasher::HASH_SIZE]:,
|
||||
{
|
||||
) -> FriCommitedTrees<F, C, D> {
|
||||
let mut trees = Vec::new();
|
||||
|
||||
let mut shift = F::MULTIPLICATIVE_GROUP_GENERATOR;
|
||||
@ -114,28 +111,55 @@ where
|
||||
(trees, coeffs)
|
||||
}
|
||||
|
||||
/// Performs the proof-of-work (a.k.a. grinding) step of the FRI protocol. Returns the PoW witness.
|
||||
fn fri_proof_of_work<F: RichField + Extendable<D>, C: GenericConfig<D, F = F>, const D: usize>(
|
||||
current_hash: HashOut<F>,
|
||||
challenger: &mut Challenger<F, C::Hasher>,
|
||||
config: &FriConfig,
|
||||
) -> F {
|
||||
(0..=F::NEG_ONE.to_canonical_u64())
|
||||
let min_leading_zeros = config.proof_of_work_bits + (64 - F::order().bits()) as u32;
|
||||
|
||||
// The easiest implementation would be repeatedly clone our Challenger. With each clone, we'd
|
||||
// observe an incrementing PoW witness, then get the PoW response. If it contained sufficient
|
||||
// leading zeros, we'd end the search, and store this clone as our new challenger.
|
||||
//
|
||||
// However, performance is critical here. We want to avoid cloning Challenger, particularly
|
||||
// since it stores vectors, which means allocations. We'd like a more compact state to clone.
|
||||
//
|
||||
// We know that a duplex will be performed right after we send the PoW witness, so we can ignore
|
||||
// any output_buffer, which will be invalidated. We also know input_buffer.len() < SPONGE_WIDTH,
|
||||
// an invariant of Challenger.
|
||||
//
|
||||
// We separate the duplex operation into two steps, one which can be performed now, and the
|
||||
// other which depends on the PoW witness candidate. The first step is the overwrite our sponge
|
||||
// state with any inputs (excluding the PoW witness candidate). The second step is to overwrite
|
||||
// one more element of our sponge state with the candidate, then apply the permutation,
|
||||
// obtaining our duplex's post-state which contains the PoW response.
|
||||
let mut duplex_intermediate_state = challenger.sponge_state;
|
||||
let witness_input_pos = challenger.input_buffer.len();
|
||||
for (i, input) in challenger.input_buffer.iter().enumerate() {
|
||||
duplex_intermediate_state[i] = *input;
|
||||
}
|
||||
|
||||
let pow_witness = (0..=F::NEG_ONE.to_canonical_u64())
|
||||
.into_par_iter()
|
||||
.find_any(|&i| {
|
||||
C::InnerHasher::hash_no_pad(
|
||||
¤t_hash
|
||||
.elements
|
||||
.iter()
|
||||
.copied()
|
||||
.chain(Some(F::from_canonical_u64(i)))
|
||||
.collect_vec(),
|
||||
)
|
||||
.elements[0]
|
||||
.to_canonical_u64()
|
||||
.leading_zeros()
|
||||
>= config.proof_of_work_bits + (64 - F::order().bits()) as u32
|
||||
.find_any(|&candidate| {
|
||||
let mut duplex_state = duplex_intermediate_state;
|
||||
duplex_state[witness_input_pos] = F::from_canonical_u64(candidate);
|
||||
duplex_state =
|
||||
<<C as GenericConfig<D>>::Hasher as Hasher<F>>::Permutation::permute(duplex_state);
|
||||
let pow_response = duplex_state[SPONGE_RATE - 1];
|
||||
let leading_zeros = pow_response.to_canonical_u64().leading_zeros();
|
||||
leading_zeros >= min_leading_zeros
|
||||
})
|
||||
.map(F::from_canonical_u64)
|
||||
.expect("Proof of work failed. This is highly unlikely!")
|
||||
.expect("Proof of work failed. This is highly unlikely!");
|
||||
|
||||
// Recompute pow_response using our normal Challenger code, and make sure it matches.
|
||||
challenger.observe_element(pow_witness);
|
||||
let pow_response = challenger.get_challenge();
|
||||
let leading_zeros = pow_response.to_canonical_u64().leading_zeros();
|
||||
assert!(leading_zeros >= min_leading_zeros);
|
||||
pow_witness
|
||||
}
|
||||
|
||||
fn fri_prover_query_rounds<
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user