diff --git a/Cargo.lock b/Cargo.lock index 380bb0cdd..63bc6bd81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1782,6 +1782,7 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" name = "p3" version = "0.1.0" dependencies = [ + "p3-baby-bear", "p3-challenger", "p3-field", "p3-goldilocks", @@ -1792,6 +1793,20 @@ dependencies = [ "p3-symmetric", ] +[[package]] +name = "p3-baby-bear" +version = "0.1.0" +source = "git+https://github.com/scroll-tech/plonky3?rev=8d2be81#8d2be81c9827c1284ecb2d226b0ca0e08136679d" +dependencies = [ + "p3-field", + "p3-mds", + "p3-monty-31", + "p3-poseidon2", + "p3-symmetric", + "rand", + "serde", +] + [[package]] name = "p3-challenger" version = "0.1.0" @@ -1891,6 +1906,28 @@ dependencies = [ "rand", ] +[[package]] +name = "p3-monty-31" +version = "0.1.0" +source = "git+https://github.com/scroll-tech/plonky3?rev=8d2be81#8d2be81c9827c1284ecb2d226b0ca0e08136679d" +dependencies = [ + "itertools 0.14.0", + "num-bigint", + "p3-dft", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-mds", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "paste", + "rand", + "serde", + "tracing", + "transpose", +] + [[package]] name = "p3-poseidon" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 689ad0609..c22c3d166 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ itertools = "0.13" num-bigint = { version = "0.4.6" } num-derive = "0.4" num-traits = "0.2" +p3-baby-bear = { git = "https://github.com/scroll-tech/plonky3", rev = "8d2be81" } p3-challenger = { git = "https://github.com/scroll-tech/plonky3", rev = "8d2be81" } p3-field = { git = "https://github.com/scroll-tech/plonky3", rev = "8d2be81" } p3-goldilocks = { git = "https://github.com/scroll-tech/plonky3", rev = "8d2be81" } diff --git a/ceno_rt/Cargo.toml b/ceno_rt/Cargo.toml index a309688bc..9f289495d 100644 --- a/ceno_rt/Cargo.toml +++ b/ceno_rt/Cargo.toml @@ -10,5 +10,5 @@ repository = "https://github.com/scroll-tech/ceno" version = "0.1.0" [dependencies] -getrandom = { version = "*", features = ["custom"], default-features = false } +getrandom = { version = "0.2.15", features = ["custom"], default-features = false } rkyv = { version = "0.8", features = ["pointer_width_32"] } diff --git a/ceno_zkvm/src/scheme/mock_prover.rs b/ceno_zkvm/src/scheme/mock_prover.rs index 9a6a1edb3..c4aaceb19 100644 --- a/ceno_zkvm/src/scheme/mock_prover.rs +++ b/ceno_zkvm/src/scheme/mock_prover.rs @@ -18,7 +18,7 @@ use crate::{ use ark_std::test_rng; use base64::{Engine, engine::general_purpose::URL_SAFE_NO_PAD}; use ceno_emul::{ByteAddr, CENO_PLATFORM, Platform, Program}; -use ff_ext::{ExtensionField, GoldilocksExt2, SmallField}; +use ff_ext::{BabyBearExt4, ExtensionField, GoldilocksExt2, SmallField}; use generic_static::StaticTypeMap; use itertools::{Itertools, chain, enumerate, izip}; use multilinear_extensions::{mle::IntoMLEs, virtual_poly::ArcMultilinearExtension}; @@ -72,6 +72,12 @@ impl LkMultiplicityKey for GoldilocksExt2 { } } +impl LkMultiplicityKey for BabyBearExt4 { + fn to_u64(&self) -> Option { + None + } +} + #[allow(clippy::enum_variant_names)] #[derive(Debug, Clone)] pub enum MockProverError { diff --git a/ff_ext/src/babybear.rs b/ff_ext/src/babybear.rs new file mode 100644 index 000000000..3f81fbe90 --- /dev/null +++ b/ff_ext/src/babybear.rs @@ -0,0 +1,184 @@ +pub mod impl_babybear { + use crate::array_try_from_uniform_bytes; + use p3::{ + self, + babybear::{BabyBear, Poseidon2BabyBear}, + challenger::DuplexChallenger, + field::{ + BasedVectorSpace, Field, PackedValue, PrimeCharacteristicRing, PrimeField32, + TwoAdicField, + extension::{BinomialExtensionField, BinomiallyExtendable}, + }, + poseidon2::ExternalLayerConstants, + }; + + use crate::{ + ExtensionField, FieldFrom, FieldInto, FromUniformBytes, PoseidonField, SmallField, + impl_from_uniform_bytes_for_binomial_extension, + }; + + pub type BabyBearExt4 = BinomialExtensionField; + + pub const POSEIDON2_BABYBEAR_WIDTH: usize = 16; + pub const POSEIDON2_BABYBEAR_RATE: usize = 8; + + pub const BABYBEAR_RC16_EXTERNAL_INITIAL: [[BabyBear; 16]; 4] = BabyBear::new_2d_array([ + [ + 0x69cbb6af, 0x46ad93f9, 0x60a00f4e, 0x6b1297cd, 0x23189afe, 0x732e7bef, 0x72c246de, + 0x2c941900, 0x0557eede, 0x1580496f, 0x3a3ea77b, 0x54f3f271, 0x0f49b029, 0x47872fe1, + 0x221e2e36, 0x1ab7202e, + ], + [ + 0x487779a6, 0x3851c9d8, 0x38dc17c0, 0x209f8849, 0x268dcee8, 0x350c48da, 0x5b9ad32e, + 0x0523272b, 0x3f89055b, 0x01e894b2, 0x13ddedde, 0x1b2ef334, 0x7507d8b4, 0x6ceeb94e, + 0x52eb6ba2, 0x50642905, + ], + [ + 0x05453f3f, 0x06349efc, 0x6922787c, 0x04bfff9c, 0x768c714a, 0x3e9ff21a, 0x15737c9c, + 0x2229c807, 0x0d47f88c, 0x097e0ecc, 0x27eadba0, 0x2d7d29e4, 0x3502aaa0, 0x0f475fd7, + 0x29fbda49, 0x018afffd, + ], + [ + 0x0315b618, 0x6d4497d1, 0x1b171d9e, 0x52861abd, 0x2e5d0501, 0x3ec8646c, 0x6e5f250a, + 0x148ae8e6, 0x17f5fa4a, 0x3e66d284, 0x0051aa3b, 0x483f7913, 0x2cfe5f15, 0x023427ca, + 0x2cc78315, 0x1e36ea47, + ], + ]); + + pub const BABYBEAR_RC16_EXTERNAL_FINAL: [[BabyBear; 16]; 4] = BabyBear::new_2d_array([ + [ + 0x7290a80d, 0x6f7e5329, 0x598ec8a8, 0x76a859a0, 0x6559e868, 0x657b83af, 0x13271d3f, + 0x1f876063, 0x0aeeae37, 0x706e9ca6, 0x46400cee, 0x72a05c26, 0x2c589c9e, 0x20bd37a7, + 0x6a2d3d10, 0x20523767, + ], + [ + 0x5b8fe9c4, 0x2aa501d6, 0x1e01ac3e, 0x1448bc54, 0x5ce5ad1c, 0x4918a14d, 0x2c46a83f, + 0x4fcf6876, 0x61d8d5c8, 0x6ddf4ff9, 0x11fda4d3, 0x02933a8f, 0x170eaf81, 0x5a9c314f, + 0x49a12590, 0x35ec52a1, + ], + [ + 0x58eb1611, 0x5e481e65, 0x367125c9, 0x0eba33ba, 0x1fc28ded, 0x066399ad, 0x0cbec0ea, + 0x75fd1af0, 0x50f5bf4e, 0x643d5f41, 0x6f4fe718, 0x5b3cbbde, 0x1e3afb3e, 0x296fb027, + 0x45e1547b, 0x4a8db2ab, + ], + [ + 0x59986d19, 0x30bcdfa3, 0x1db63932, 0x1d7c2824, 0x53b33681, 0x0673b747, 0x038a98a3, + 0x2c5bce60, 0x351979cd, 0x5008fb73, 0x547bca78, 0x711af481, 0x3f93bf64, 0x644d987b, + 0x3c8bcd87, 0x608758b8, + ], + ]); + + pub const BABYBEAR_RC16_INTERNAL: [BabyBear; 13] = BabyBear::new_array([ + 0x5a8053c0, 0x693be639, 0x3858867d, 0x19334f6b, 0x128f0fd8, 0x4e2b1ccb, 0x61210ce0, + 0x3c318939, 0x0b5b2f22, 0x2edb11d5, 0x213effdf, 0x0cac4606, 0x241af16d, + ]); + + impl FieldFrom for BabyBear { + fn from_v(v: u64) -> Self { + Self::from_u64(v) + } + } + + impl FieldFrom for BabyBearExt4 { + fn from_v(v: u64) -> Self { + Self::from_u64(v) + } + } + + impl FieldInto for BabyBear { + fn into_f(self) -> BabyBear { + self + } + } + + impl PoseidonField for BabyBear { + type P = Poseidon2BabyBear; + type T = DuplexChallenger; + fn get_default_challenger() -> Self::T { + let p = Poseidon2BabyBear::new( + ExternalLayerConstants::new( + BABYBEAR_RC16_EXTERNAL_INITIAL.to_vec(), + BABYBEAR_RC16_EXTERNAL_FINAL.to_vec(), + ), + BABYBEAR_RC16_INTERNAL.to_vec(), + ); + DuplexChallenger::< + Self, + Self::P, + POSEIDON2_BABYBEAR_WIDTH, + POSEIDON2_BABYBEAR_RATE, + >::new(p) + } + } + + impl FromUniformBytes for BabyBear { + type Bytes = [u8; 8]; + + fn try_from_uniform_bytes(bytes: [u8; 8]) -> Option { + let value = u32::from_le_bytes(bytes[..4].try_into().unwrap()); + let is_canonical = value < Self::ORDER_U32; + is_canonical.then(|| Self::from_u32(value)) + } + } + + impl SmallField for BabyBear { + const MODULUS_U64: u64 = Self::ORDER_U32 as u64; + + /// Convert a byte string into a list of field elements + fn bytes_to_field_elements(bytes: &[u8]) -> Vec { + bytes + .chunks(8) + .map(|chunk| { + let mut array = [0u8; 8]; + array[..chunk.len()].copy_from_slice(chunk); + unsafe { std::ptr::read_unaligned(array.as_ptr() as *const u64) } + }) + .map(Self::from_u64) + .collect::>() + } + + /// Convert a field elements to a u64. + fn to_canonical_u64(&self) -> u64 { + self.as_canonical_u32() as u64 + } + } + + impl_from_uniform_bytes_for_binomial_extension!(p3::babybear::BabyBear, 4); + + impl ExtensionField for BabyBearExt4 { + const DEGREE: usize = 4; + const MULTIPLICATIVE_GENERATOR: Self = ::GENERATOR; + const TWO_ADICITY: usize = BabyBear::TWO_ADICITY; + // Passing two-adacity itself to this function will get the root of unity + // with the largest order, i.e., order = 2^two-adacity. + const BASE_TWO_ADIC_ROOT_OF_UNITY: Self::BaseField = BabyBear::new(0x78000000); + const TWO_ADIC_ROOT_OF_UNITY: Self = + BinomialExtensionField::new_unchecked([BabyBear::new(0x78000000); 4]); + // non-residue is the value w such that the extension field is + // F[X]/(X^2 - w) + const NONRESIDUE: Self::BaseField = >::W; + + type BaseField = BabyBear; + + fn from_bases(bases: &[BabyBear]) -> Self { + debug_assert_eq!(bases.len(), 2); + Self::from_basis_coefficients_slice(bases) + } + + fn as_bases(&self) -> &[BabyBear] { + self.as_basis_coefficients_slice() + } + + /// Convert limbs into self + fn from_limbs(limbs: &[Self::BaseField]) -> Self { + Self::from_bases(&limbs[0..4]) + } + + fn to_canonical_u64_vec(&self) -> Vec { + self.as_basis_coefficients_slice() + .iter() + .map(|v: &Self::BaseField| v.as_canonical_u32() as u64) + .collect() + } + } +} diff --git a/ff_ext/src/goldilock.rs b/ff_ext/src/goldilock.rs new file mode 100644 index 000000000..eae5c2fd1 --- /dev/null +++ b/ff_ext/src/goldilock.rs @@ -0,0 +1,135 @@ +pub mod impl_goldilocks { + + use crate::{ + ExtensionField, FieldFrom, FieldInto, FromUniformBytes, SmallField, + array_try_from_uniform_bytes, impl_from_uniform_bytes_for_binomial_extension, + poseidon::{PoseidonField, new_array}, + }; + use p3::{ + challenger::DuplexChallenger, + field::{ + BasedVectorSpace, Field, PackedValue, PrimeCharacteristicRing, PrimeField64, + TwoAdicField, + extension::{BinomialExtensionField, BinomiallyExtendable}, + }, + goldilocks::{ + Goldilocks, HL_GOLDILOCKS_8_EXTERNAL_ROUND_CONSTANTS, + HL_GOLDILOCKS_8_INTERNAL_ROUND_CONSTANTS, Poseidon2GoldilocksHL, + }, + poseidon2::ExternalLayerConstants, + }; + + pub type GoldilocksExt2 = BinomialExtensionField; + + impl FieldFrom for Goldilocks { + fn from_v(v: u64) -> Self { + Self::from_u64(v) + } + } + + impl FieldFrom for GoldilocksExt2 { + fn from_v(v: u64) -> Self { + Self::from_u64(v) + } + } + + impl FieldInto for Goldilocks { + fn into_f(self) -> Goldilocks { + self + } + } + + pub const POSEIDON2_GOLDILICK_WIDTH: usize = 8; + pub const POSEIDON2_GOLDILICK_RATE: usize = 4; + + impl PoseidonField for Goldilocks { + type P = Poseidon2GoldilocksHL; + type T = + DuplexChallenger; + fn get_default_challenger() -> Self::T { + let perm = Poseidon2GoldilocksHL::new( + ExternalLayerConstants::::new_from_saved_array( + HL_GOLDILOCKS_8_EXTERNAL_ROUND_CONSTANTS, + new_array, + ), + new_array(HL_GOLDILOCKS_8_INTERNAL_ROUND_CONSTANTS).to_vec(), + ); + DuplexChallenger::::new( + perm, + ) + } + } + + impl_from_uniform_bytes_for_binomial_extension!(p3::goldilocks::Goldilocks, 2); + + impl FromUniformBytes for Goldilocks { + type Bytes = [u8; 8]; + + fn try_from_uniform_bytes(bytes: [u8; 8]) -> Option { + let value = u64::from_le_bytes(bytes); + let is_canonical = value < Self::ORDER_U64; + is_canonical.then(|| Self::from_u64(value)) + } + } + + impl SmallField for Goldilocks { + const MODULUS_U64: u64 = Self::ORDER_U64; + + /// Convert a byte string into a list of field elements + fn bytes_to_field_elements(bytes: &[u8]) -> Vec { + bytes + .chunks(8) + .map(|chunk| { + let mut array = [0u8; 8]; + array[..chunk.len()].copy_from_slice(chunk); + unsafe { std::ptr::read_unaligned(array.as_ptr() as *const u64) } + }) + .map(Self::from_u64) + .collect::>() + } + + /// Convert a field elements to a u64. + fn to_canonical_u64(&self) -> u64 { + self.as_canonical_u64() + } + } + + impl ExtensionField for GoldilocksExt2 { + const DEGREE: usize = 2; + const MULTIPLICATIVE_GENERATOR: Self = ::GENERATOR; + const TWO_ADICITY: usize = Goldilocks::TWO_ADICITY; + // Passing two-adacity itself to this function will get the root of unity + // with the largest order, i.e., order = 2^two-adacity. + const BASE_TWO_ADIC_ROOT_OF_UNITY: Self::BaseField = + Goldilocks::two_adic_generator_const(Goldilocks::TWO_ADICITY); + const TWO_ADIC_ROOT_OF_UNITY: Self = BinomialExtensionField::new_unchecked( + Goldilocks::ext_two_adic_generator_const(Goldilocks::TWO_ADICITY), + ); + // non-residue is the value w such that the extension field is + // F[X]/(X^2 - w) + const NONRESIDUE: Self::BaseField = >::W; + + type BaseField = Goldilocks; + + fn from_bases(bases: &[Goldilocks]) -> Self { + debug_assert_eq!(bases.len(), 2); + Self::from_basis_coefficients_slice(bases) + } + + fn as_bases(&self) -> &[Goldilocks] { + self.as_basis_coefficients_slice() + } + + /// Convert limbs into self + fn from_limbs(limbs: &[Self::BaseField]) -> Self { + Self::from_bases(&limbs[0..2]) + } + + fn to_canonical_u64_vec(&self) -> Vec { + self.as_basis_coefficients_slice() + .iter() + .map(|v: &Self::BaseField| v.as_canonical_u64()) + .collect() + } + } +} diff --git a/ff_ext/src/lib.rs b/ff_ext/src/lib.rs index a207e026b..8287b0381 100644 --- a/ff_ext/src/lib.rs +++ b/ff_ext/src/lib.rs @@ -1,20 +1,17 @@ #![deny(clippy::cargo)] -use p3::{ - field::{ - ExtensionField as P3ExtensionField, Field as P3Field, PackedValue, PrimeField, - TwoAdicField, extension::BinomialExtensionField, - }, - goldilocks::Goldilocks, -}; +use p3::field::{ExtensionField as P3ExtensionField, Field as P3Field, PrimeField, TwoAdicField}; use rand_core::RngCore; use serde::Serialize; use std::{array::from_fn, iter::repeat_with}; +mod babybear; +pub use babybear::impl_babybear::*; +mod goldilock; +pub use goldilock::impl_goldilocks::*; mod poseidon; -pub use poseidon::PoseidonField; -pub type GoldilocksExt2 = BinomialExtensionField; +pub use poseidon::{FieldChallengerExt, PoseidonField}; -fn array_try_from_uniform_bytes< +pub(crate) fn array_try_from_uniform_bytes< F: Copy + Default + FromUniformBytes, const W: usize, const N: usize, @@ -52,6 +49,7 @@ pub trait FromUniformBytes: Sized { } } +#[macro_export] macro_rules! impl_from_uniform_bytes_for_binomial_extension { ($base:ty, $degree:literal) => { impl FromUniformBytes for p3::field::extension::BinomialExtensionField<$base, $degree> { @@ -70,8 +68,6 @@ macro_rules! impl_from_uniform_bytes_for_binomial_extension { }; } -impl_from_uniform_bytes_for_binomial_extension!(p3::goldilocks::Goldilocks, 2); - /// define a custom conversion trait like `From` /// an util to simulate general from function pub trait FieldFrom { @@ -84,22 +80,25 @@ pub trait FieldInto { fn into_f(self) -> T; } +impl FieldInto for T +where + U: FieldFrom, +{ + fn into_f(self) -> U { + U::from_v(self) + } +} + // TODO remove SmallField pub trait SmallField: Serialize + P3Field + FieldFrom + FieldInto { /// MODULUS as u64 const MODULUS_U64: u64; - /// Identifier string - const NAME: &'static str; - /// Convert a byte string into a list of field elements fn bytes_to_field_elements(bytes: &[u8]) -> Vec; /// Convert a field elements to a u64. fn to_canonical_u64(&self) -> u64; - - /// Convert a field elements to a u64. Do not normalize it. - fn to_noncanonical_u64(&self) -> u64; } pub trait ExtensionField: P3ExtensionField + FromUniformBytes + Ord { @@ -122,139 +121,3 @@ pub trait ExtensionField: P3ExtensionField + FromUniformBytes + /// Convert a field elements to a u64 vector fn to_canonical_u64_vec(&self) -> Vec; } - -mod impl_goldilocks { - use crate::{ - ExtensionField, FieldFrom, FieldInto, FromUniformBytes, GoldilocksExt2, SmallField, - poseidon::{PoseidonField, new_array}, - }; - use p3::{ - field::{ - BasedVectorSpace, Field, PrimeCharacteristicRing, PrimeField64, TwoAdicField, - extension::{BinomialExtensionField, BinomiallyExtendable}, - }, - goldilocks::{ - Goldilocks, HL_GOLDILOCKS_8_EXTERNAL_ROUND_CONSTANTS, - HL_GOLDILOCKS_8_INTERNAL_ROUND_CONSTANTS, Poseidon2GoldilocksHL, - }, - poseidon2::ExternalLayerConstants, - }; - - impl FieldFrom for Goldilocks { - fn from_v(v: u64) -> Self { - Self::from_u64(v) - } - } - - impl FieldFrom for GoldilocksExt2 { - fn from_v(v: u64) -> Self { - Self::from_u64(v) - } - } - - impl FieldInto for T - where - U: FieldFrom, - { - fn into_f(self) -> U { - U::from_v(self) - } - } - - impl FieldInto for Goldilocks { - fn into_f(self) -> Goldilocks { - self - } - } - - impl PoseidonField for Goldilocks { - type T = Poseidon2GoldilocksHL<8>; - fn get_perm() -> Self::T { - Poseidon2GoldilocksHL::new( - ExternalLayerConstants::::new_from_saved_array( - HL_GOLDILOCKS_8_EXTERNAL_ROUND_CONSTANTS, - new_array, - ), - new_array(HL_GOLDILOCKS_8_INTERNAL_ROUND_CONSTANTS).to_vec(), - ) - } - } - - impl FromUniformBytes for Goldilocks { - type Bytes = [u8; 8]; - - fn try_from_uniform_bytes(bytes: [u8; 8]) -> Option { - let value = u64::from_le_bytes(bytes); - let is_canonical = value < Self::ORDER_U64; - is_canonical.then(|| Self::from_u64(value)) - } - } - - impl SmallField for Goldilocks { - /// Identifier string - const NAME: &'static str = "Goldilocks"; - const MODULUS_U64: u64 = Self::ORDER_U64; - - /// Convert a byte string into a list of field elements - fn bytes_to_field_elements(bytes: &[u8]) -> Vec { - bytes - .chunks(8) - .map(|chunk| { - let mut array = [0u8; 8]; - array[..chunk.len()].copy_from_slice(chunk); - unsafe { std::ptr::read_unaligned(array.as_ptr() as *const u64) } - }) - .map(Self::from_u64) - .collect::>() - } - - /// Convert a field elements to a u64. - fn to_canonical_u64(&self) -> u64 { - self.as_canonical_u64() - } - - /// Convert a field elements to a u64. Do not normalize it. - fn to_noncanonical_u64(&self) -> u64 { - self.as_canonical_u64() - } - } - - impl ExtensionField for GoldilocksExt2 { - const DEGREE: usize = 2; - const MULTIPLICATIVE_GENERATOR: Self = ::GENERATOR; - const TWO_ADICITY: usize = Goldilocks::TWO_ADICITY; - // Passing two-adacity itself to this function will get the root of unity - // with the largest order, i.e., order = 2^two-adacity. - const BASE_TWO_ADIC_ROOT_OF_UNITY: Self::BaseField = - Goldilocks::two_adic_generator_const(Goldilocks::TWO_ADICITY); - const TWO_ADIC_ROOT_OF_UNITY: Self = BinomialExtensionField::new_unchecked( - Goldilocks::ext_two_adic_generator_const(Goldilocks::TWO_ADICITY), - ); - // non-residue is the value w such that the extension field is - // F[X]/(X^2 - w) - const NONRESIDUE: Self::BaseField = >::W; - - type BaseField = Goldilocks; - - fn from_bases(bases: &[Goldilocks]) -> Self { - debug_assert_eq!(bases.len(), 2); - Self::from_basis_coefficients_slice(bases) - } - - fn as_bases(&self) -> &[Goldilocks] { - self.as_basis_coefficients_slice() - } - - /// Convert limbs into self - fn from_limbs(limbs: &[Self::BaseField]) -> Self { - Self::from_bases(&limbs[0..2]) - } - - fn to_canonical_u64_vec(&self) -> Vec { - self.as_basis_coefficients_slice() - .iter() - .map(|v: &Self::BaseField| v.as_canonical_u64()) - .collect() - } - } -} diff --git a/ff_ext/src/poseidon.rs b/ff_ext/src/poseidon.rs index b4a40d6db..883829991 100644 --- a/ff_ext/src/poseidon.rs +++ b/ff_ext/src/poseidon.rs @@ -1,10 +1,22 @@ -use p3::{field::PrimeField, symmetric::CryptographicPermutation}; +use p3::{challenger::FieldChallenger, field::PrimeField}; -use crate::SmallField; +use crate::{ExtensionField, SmallField}; + +pub trait FieldChallengerExt: FieldChallenger { + fn observe_ext_slice>(&mut self, exts: &[E]) { + exts.iter() + .for_each(|ext| self.observe_slice(ext.as_basis_coefficients_slice())); + } + + fn sample_ext_vec>(&mut self, n: usize) -> Vec { + (0..n).map(|_| self.sample_algebra_element()).collect() + } +} pub trait PoseidonField: PrimeField + SmallField { - type T: CryptographicPermutation<[Self; 8]>; - fn get_perm() -> Self::T; + type P: Clone; + type T: FieldChallenger + Clone; + fn get_default_challenger() -> Self::T; } pub(crate) fn new_array(input: [u64; N]) -> [F; N] { diff --git a/p3/Cargo.toml b/p3/Cargo.toml index e41d9c1dc..ce89dccb0 100644 --- a/p3/Cargo.toml +++ b/p3/Cargo.toml @@ -10,6 +10,7 @@ repository.workspace = true version.workspace = true [dependencies] +p3-baby-bear.workspace = true p3-challenger.workspace = true p3-field.workspace = true p3-goldilocks.workspace = true diff --git a/p3/src/lib.rs b/p3/src/lib.rs index 74f50b061..53d9384aa 100644 --- a/p3/src/lib.rs +++ b/p3/src/lib.rs @@ -1,3 +1,4 @@ +pub use p3_baby_bear as babybear; pub use p3_challenger as challenger; pub use p3_field as field; pub use p3_goldilocks as goldilocks; diff --git a/poseidon/benches/hashing.rs b/poseidon/benches/hashing.rs index 64ca47b75..dce45b4a0 100644 --- a/poseidon/benches/hashing.rs +++ b/poseidon/benches/hashing.rs @@ -113,7 +113,7 @@ use p3::symmetric::Permutation; // bench permutation pub fn permutation_benchmark(c: &mut Criterion) { let mut plonky_permutation = PoseidonPermutation::new(core::iter::repeat(GoldilocksField(0))); - let ceno_challenger = DefaultChallenger::::new_poseidon_default(); + let ceno_challenger = DefaultChallenger::::new_poseidon_default(); c.bench_function("plonky permute", |bencher| { bencher.iter(|| plonky_permutation.permute()) diff --git a/poseidon/src/challenger.rs b/poseidon/src/challenger.rs index f13a90811..26bd646fc 100644 --- a/poseidon/src/challenger.rs +++ b/poseidon/src/challenger.rs @@ -1,119 +1,75 @@ use core::fmt::Debug; -use ff_ext::ExtensionField; -use p3::{field::PrimeField, symmetric::CryptographicPermutation}; +use ff_ext::{FieldChallengerExt, PoseidonField}; use std::ops::{Deref, DerefMut}; pub use p3::challenger::*; -use ff_ext::PoseidonField; - /// this wrap a DuplexChallenger as inner field, /// while expose some factory method to create default permutation object with defined constant #[derive(Clone, Debug)] -pub struct DefaultChallenger +pub struct DefaultChallenger where - F: PrimeField, - P: CryptographicPermutation<[F; 8]>, + F: PoseidonField, { - inner: DuplexChallenger, + inner: F::T, } -impl DefaultChallenger +impl DefaultChallenger where - F: PrimeField, - P: CryptographicPermutation<[F; 8]>, + F: PoseidonField, { - pub fn new(perm: P) -> Self { - Self { - inner: DuplexChallenger::::new(perm), - } + pub fn new(inner: F::T) -> Self { + Self { inner } } } -impl DefaultChallenger -where - F::T: CryptographicPermutation<[F; 8]>, -{ +impl DefaultChallenger { pub fn new_poseidon_default() -> Self { - Self { - inner: DuplexChallenger::::new(F::get_perm()), - } + DefaultChallenger::new(F::get_default_challenger()) } } -impl Deref for DefaultChallenger -where - F: PrimeField, - P: CryptographicPermutation<[F; 8]>, -{ - type Target = DuplexChallenger; +impl Deref for DefaultChallenger { + type Target = F::T; fn deref(&self) -> &Self::Target { &self.inner } } -impl DerefMut for DefaultChallenger -where - F: PrimeField, - P: CryptographicPermutation<[F; 8]>, -{ +impl DerefMut for DefaultChallenger { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.inner } } -pub trait FieldChallengerExt: FieldChallenger { - fn observe_ext_slice>(&mut self, exts: &[E]) { - exts.iter() - .for_each(|ext| self.observe_slice(ext.as_basis_coefficients_slice())); - } - - fn sample_ext_vec>(&mut self, n: usize) -> Vec { - (0..n).map(|_| self.sample_algebra_element()).collect() - } -} - -impl CanObserve for DefaultChallenger +impl CanObserve for DefaultChallenger where F: PoseidonField, - P: CryptographicPermutation<[F; 8]>, { fn observe(&mut self, value: F) { self.inner.observe(value); } } -impl CanSampleBits for DefaultChallenger +impl CanSampleBits for DefaultChallenger where F: PoseidonField, - P: CryptographicPermutation<[F; 8]>, { fn sample_bits(&mut self, _bits: usize) -> usize { todo!() } } -impl CanSample for DefaultChallenger +impl CanSample for DefaultChallenger where F: PoseidonField, - P: CryptographicPermutation<[F; 8]>, { fn sample(&mut self) -> F { self.inner.sample() } } -impl FieldChallenger for DefaultChallenger -where - F: PoseidonField, - P: CryptographicPermutation<[F; 8]>, -{ -} +impl FieldChallenger for DefaultChallenger where F: PoseidonField {} -impl FieldChallengerExt for DefaultChallenger -where - F: PoseidonField, - P: CryptographicPermutation<[F; 8]>, -{ -} +impl FieldChallengerExt for DefaultChallenger where F: PoseidonField {} diff --git a/poseidon/src/poseidon_hash.rs b/poseidon/src/poseidon_hash.rs index 13349c24b..cdc0b91d5 100644 --- a/poseidon/src/poseidon_hash.rs +++ b/poseidon/src/poseidon_hash.rs @@ -1,11 +1,7 @@ use std::marker::PhantomData; -use crate::{ - challenger::{DefaultChallenger, FieldChallengerExt}, - constants::DIGEST_WIDTH, - digest::Digest, -}; -use ff_ext::{ExtensionField, PoseidonField}; +use crate::{challenger::DefaultChallenger, constants::DIGEST_WIDTH, digest::Digest}; +use ff_ext::{ExtensionField, FieldChallengerExt, PoseidonField}; use p3::challenger::{CanObserve, CanSample}; pub struct PoseidonHash { @@ -37,7 +33,7 @@ impl PoseidonHash { } pub fn hash_n_to_m_no_pad(inputs: &[F], num_outputs: usize) -> Vec { - let mut challenger = DefaultChallenger::::new_poseidon_default(); + let mut challenger = DefaultChallenger::::new_poseidon_default(); challenger.observe_slice(inputs); challenger.sample_vec(num_outputs) } @@ -46,7 +42,7 @@ pub fn hash_n_to_m_no_pad_ext inputs: &[E], num_outputs: usize, ) -> Vec { - let mut challenger = DefaultChallenger::::new_poseidon_default(); + let mut challenger = DefaultChallenger::::new_poseidon_default(); challenger.observe_ext_slice(inputs); challenger.sample_vec(num_outputs) } @@ -64,7 +60,7 @@ pub fn hash_n_to_hash_no_pad_ext(x: &Digest, y: &Digest) -> Digest { - let mut challenger = DefaultChallenger::::new_poseidon_default(); + let mut challenger = DefaultChallenger::::new_poseidon_default(); challenger.observe_slice(x.elements()); challenger.observe_slice(y.elements()); Digest(challenger.sample_array::()) diff --git a/sumcheck/src/test.rs b/sumcheck/src/test.rs index 4e6cbfac1..ceb387a94 100644 --- a/sumcheck/src/test.rs +++ b/sumcheck/src/test.rs @@ -3,7 +3,7 @@ use crate::{ util::interpolate_uni_poly, }; use ark_std::{rand::RngCore, test_rng}; -use ff_ext::{ExtensionField, FromUniformBytes, GoldilocksExt2}; +use ff_ext::{BabyBearExt4, ExtensionField, FromUniformBytes, GoldilocksExt2}; use multilinear_extensions::{ util::max_usable_threads, virtual_poly::{VPAuxInfo, VirtualPolynomial}, @@ -163,6 +163,7 @@ fn test_sumcheck_internal( #[test] fn test_trivial_polynomial() { test_trivial_polynomial_helper::(); + test_trivial_polynomial_helper::(); } fn test_trivial_polynomial_helper() { @@ -177,6 +178,7 @@ fn test_trivial_polynomial_helper() { #[test] fn test_normal_polynomial() { test_normal_polynomial_helper::(); + test_normal_polynomial_helper::(); } fn test_normal_polynomial_helper() { @@ -191,6 +193,7 @@ fn test_normal_polynomial_helper() { #[test] fn test_extract_sum() { test_extract_sum_helper::(); + test_extract_sum_helper::(); } fn test_extract_sum_helper() { diff --git a/transcript/src/basic.rs b/transcript/src/basic.rs index 9a9f0710d..d333c334f 100644 --- a/transcript/src/basic.rs +++ b/transcript/src/basic.rs @@ -1,18 +1,18 @@ -use ff_ext::{ExtensionField, PoseidonField}; -use poseidon::challenger::{CanObserve, DefaultChallenger, FieldChallenger, FieldChallengerExt}; +use ff_ext::{ExtensionField, FieldChallengerExt}; +use poseidon::challenger::{CanObserve, DefaultChallenger, FieldChallenger}; use crate::{Challenge, ForkableTranscript, Transcript}; use ff_ext::SmallField; #[derive(Clone)] pub struct BasicTranscript { - challenger: DefaultChallenger::T>, + challenger: DefaultChallenger, } impl BasicTranscript { /// Create a new IOP transcript. pub fn new(label: &'static [u8]) -> Self { - let mut challenger = DefaultChallenger::::T>::new_poseidon_default(); + let mut challenger = DefaultChallenger::::new_poseidon_default(); let label_f = E::BaseField::bytes_to_field_elements(label); challenger.observe_slice(label_f.as_slice()); Self { challenger }