Feat/roman/poseidon2 (#507)

This PR adds support for poseidon2 permutation function as described in
https://eprint.iacr.org/2023/323.pdf

Reference implementations used (and compared against):
https://github.com/HorizenLabs/poseidon2/tree/main
https://github.com/Plonky3/Plonky3/tree/main

Tasks:

- [x] Remove commented code and prints
- [ ] Add doc-comments to functions and structs
- [x] Fix possible issue with Plonky3 imports
- [x] Update NTT/Plonky3 test
- [x] Add Plonky3-bn254 test (impossible)
This commit is contained in:
ChickenLover
2024-05-09 15:13:43 +07:00
committed by GitHub
parent c30e333819
commit 094683d291
27 changed files with 6070 additions and 13 deletions

View File

@@ -11,14 +11,13 @@ repository.workspace = true
[dependencies]
icicle-cuda-runtime = { workspace = true }
ark-ff = { version = "0.4.0", optional = true }
ark-ec = { version = "0.4.0", optional = true, features = ["parallel"] }
ark-poly = { version = "0.4.0", optional = true }
ark-std = { version = "0.4.0", optional = true }
rayon = "1.8.1"
hex = "0.4"
criterion = "0.3"
[dev-dependencies]

View File

@@ -3,6 +3,7 @@ use crate::traits::ArkConvertible;
use crate::traits::{FieldConfig, FieldImpl, MontgomeryConvertible};
#[cfg(feature = "arkworks")]
use ark_ff::{BigInteger, Field as ArkField, PrimeField};
use hex::FromHex;
use icicle_cuda_runtime::device_context::DeviceContext;
use icicle_cuda_runtime::error::CudaError;
use icicle_cuda_runtime::memory::DeviceSlice;
@@ -82,6 +83,12 @@ impl<const NUM_LIMBS: usize, F: FieldConfig> FieldImpl for Field<NUM_LIMBS, F> {
Self::from(limbs)
}
fn from_hex(s: &str) -> Self {
let mut bytes = Vec::from_hex(if s.starts_with("0x") { &s[2..] } else { s }).expect("Invalid hex string");
bytes.reverse();
Self::from_bytes_le(&bytes)
}
fn zero() -> Self {
FieldImpl::from_u32(0)
}

View File

@@ -6,6 +6,7 @@ pub mod msm;
pub mod ntt;
pub mod polynomials;
pub mod poseidon;
pub mod poseidon2;
#[doc(hidden)]
pub mod tests;
pub mod traits;

View File

@@ -56,10 +56,11 @@ pub fn check_poseidon_hash_many<F: FieldImpl>()
where
<F as FieldImpl>::Config: Poseidon<F>,
{
let arity = 2u32;
let constants = init_poseidon::<F>(arity as u32);
for arity in [2, 4] {
let constants = init_poseidon::<F>(arity as u32);
_check_poseidon_hash_many(constants);
_check_poseidon_hash_many(constants);
}
}
pub fn check_poseidon_custom_config<F: FieldImpl>(field_bytes: usize, field_prefix: &str, partial_rounds: u32)

View File

@@ -0,0 +1,384 @@
#[doc(hidden)]
pub mod tests;
use icicle_cuda_runtime::{
device::check_device,
device_context::{DeviceContext, DEFAULT_DEVICE_ID},
memory::{DeviceSlice, HostOrDeviceSlice},
};
use crate::{error::IcicleResult, traits::FieldImpl};
#[repr(C)]
#[derive(Debug, Clone)]
pub enum DiffusionStrategy {
Default,
Montgomery,
}
#[repr(C)]
#[derive(Debug, Clone)]
pub enum MdsType {
Default,
Plonky,
}
#[repr(C)]
#[derive(Debug, Clone)]
pub enum PoseidonMode {
Compression,
Permutation,
}
#[repr(C)]
pub struct Poseidon2Constants<'a, F: FieldImpl> {
width: u32,
alpha: u32,
internal_rounds: u32,
external_rounds: u32,
round_constants: &'a DeviceSlice<F>,
inernal_matrix_diag: &'a DeviceSlice<F>,
pub mds_type: MdsType,
pub diffusion: DiffusionStrategy,
}
impl<F: FieldImpl> std::fmt::Debug for Poseidon2Constants<'_, F> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}, {}, {}, {}",
self.width, self.alpha, self.internal_rounds, self.external_rounds
)
}
}
/// Struct that encodes Poseidon parameters to be passed into the [poseidon_hash_many](poseidon_hash_many) function.
#[repr(C)]
#[derive(Debug, Clone)]
pub struct Poseidon2Config<'a> {
/// Details related to the device such as its id and stream id. See [DeviceContext](@ref device_context::DeviceContext).
pub ctx: DeviceContext<'a>,
are_states_on_device: bool,
are_outputs_on_device: bool,
pub mode: PoseidonMode,
pub output_index: u32,
/// If true, hash results will also be copied in the input pointer in aligned format
pub loop_state: bool,
/// Whether to run Poseidon asynchronously. If set to `true`, Poseidon will be non-blocking
/// and you'd need to synchronize it explicitly by running `cudaStreamSynchronize` or `cudaDeviceSynchronize`.
/// If set to `false`, Poseidon will block the current CPU thread.
pub is_async: bool,
}
impl<'a> Default for Poseidon2Config<'a> {
fn default() -> Self {
Self::default_for_device(DEFAULT_DEVICE_ID)
}
}
impl<'a> Poseidon2Config<'a> {
pub fn default_for_device(device_id: usize) -> Self {
Self {
ctx: DeviceContext::default_for_device(device_id),
are_states_on_device: false,
are_outputs_on_device: false,
mode: PoseidonMode::Compression,
output_index: 1,
loop_state: false,
is_async: false,
}
}
}
pub trait Poseidon2<F: FieldImpl> {
fn create_optimized_constants<'a>(
width: u32,
alpha: u32,
internal_rounds: u32,
external_rounds: u32,
round_constants: &mut [F],
internal_matrix_diag: &mut [F],
mds_type: MdsType,
diffusion: DiffusionStrategy,
ctx: &DeviceContext,
) -> IcicleResult<Poseidon2Constants<'a, F>>;
fn load_optimized_constants<'a>(
width: u32,
mds_type: MdsType,
diffusion: DiffusionStrategy,
ctx: &DeviceContext,
) -> IcicleResult<Poseidon2Constants<'a, F>>;
fn poseidon_unchecked(
states: &mut (impl HostOrDeviceSlice<F> + ?Sized),
output: &mut (impl HostOrDeviceSlice<F> + ?Sized),
number_of_states: u32,
width: u32,
constants: &Poseidon2Constants<F>,
config: &Poseidon2Config,
) -> IcicleResult<()>;
}
/// Loads pre-calculated poseidon constants on the GPU.
pub fn load_optimized_poseidon2_constants<'a, F>(
width: u32,
mds_type: MdsType,
diffusion: DiffusionStrategy,
ctx: &DeviceContext,
) -> IcicleResult<Poseidon2Constants<'a, F>>
where
F: FieldImpl,
<F as FieldImpl>::Config: Poseidon2<F>,
{
<<F as FieldImpl>::Config as Poseidon2<F>>::load_optimized_constants(width, mds_type, diffusion, ctx)
}
/// Creates new instance of poseidon constants on the GPU.
pub fn create_optimized_poseidon2_constants<'a, F>(
width: u32,
alpha: u32,
ctx: &DeviceContext,
internal_rounds: u32,
external_rounds: u32,
round_constants: &mut [F],
internal_matrix_diag: &mut [F],
mds_type: MdsType,
diffusion: DiffusionStrategy,
) -> IcicleResult<Poseidon2Constants<'a, F>>
where
F: FieldImpl,
<F as FieldImpl>::Config: Poseidon2<F>,
{
<<F as FieldImpl>::Config as Poseidon2<F>>::create_optimized_constants(
width,
alpha,
internal_rounds,
external_rounds,
round_constants,
internal_matrix_diag,
mds_type,
diffusion,
ctx,
)
}
/// Computes the poseidon hashes for multiple preimages.
///
/// # Arguments
///
/// * `input` - a pointer to the input data. May point to a vector of preimages or a vector of states filled with preimages.
///
/// * `output` - a pointer to the output data. Must be at least of size [number_of_states](number_of_states)
///
/// * `number_of_states` - number of input blocks of size `arity`
///
/// * `arity` - the arity of the hash function (the size of 1 preimage)
///
/// * `constants` - Poseidon constants.
///
/// * `config` - config used to specify extra arguments of the Poseidon.
pub fn poseidon_hash_many<F>(
states: &mut (impl HostOrDeviceSlice<F> + ?Sized),
output: &mut (impl HostOrDeviceSlice<F> + ?Sized),
number_of_states: u32,
width: u32,
constants: &Poseidon2Constants<F>,
config: &Poseidon2Config,
) -> IcicleResult<()>
where
F: FieldImpl,
<F as FieldImpl>::Config: Poseidon2<F>,
{
if states.len() < (number_of_states * width) as usize {
panic!(
"input len is {}; but needs to be at least {}",
states.len(),
number_of_states * width
);
}
if output.len() < number_of_states as usize {
panic!(
"output len is {}; but needs to be at least {}",
output.len(),
number_of_states
);
}
let ctx_device_id = config
.ctx
.device_id;
if let Some(device_id) = states.device_id() {
assert_eq!(
device_id, ctx_device_id,
"Device ids in input and context are different"
);
}
if let Some(device_id) = output.device_id() {
assert_eq!(
device_id, ctx_device_id,
"Device ids in output and context are different"
);
}
check_device(ctx_device_id);
let mut local_cfg = config.clone();
local_cfg.are_states_on_device = states.is_on_device();
local_cfg.are_outputs_on_device = output.is_on_device();
<<F as FieldImpl>::Config as Poseidon2<F>>::poseidon_unchecked(
states,
output,
number_of_states,
width,
constants,
&local_cfg,
)
}
#[macro_export]
macro_rules! impl_poseidon2 {
(
$field_prefix:literal,
$field_prefix_ident:ident,
$field:ident,
$field_config:ident
) => {
mod $field_prefix_ident {
use crate::poseidon2::{
$field, $field_config, CudaError, DeviceContext, DiffusionStrategy, MdsType, Poseidon2Config,
Poseidon2Constants,
};
extern "C" {
#[link_name = concat!($field_prefix, "_create_optimized_poseidon2_constants_cuda")]
pub(crate) fn _create_optimized_constants(
width: u32,
alpha: u32,
internal_rounds: u32,
external_rounds: u32,
constants: *mut $field,
internal_matrix_diag: *mut $field,
mds_type: MdsType,
diffusion: DiffusionStrategy,
ctx: &DeviceContext,
poseidon_constants: *mut Poseidon2Constants<$field>,
) -> CudaError;
#[link_name = concat!($field_prefix, "_init_optimized_poseidon2_constants_cuda")]
pub(crate) fn _load_optimized_constants(
width: u32,
mds_type: MdsType,
diffusion: DiffusionStrategy,
ctx: &DeviceContext,
constants: *mut Poseidon2Constants<$field>,
) -> CudaError;
#[link_name = concat!($field_prefix, "_poseidon2_hash_cuda")]
pub(crate) fn hash_many(
states: *mut $field,
output: *mut $field,
number_of_states: u32,
width: u32,
constants: &Poseidon2Constants<$field>,
config: &Poseidon2Config,
) -> CudaError;
}
}
impl Poseidon2<$field> for $field_config {
fn create_optimized_constants<'a>(
width: u32,
alpha: u32,
internal_rounds: u32,
external_rounds: u32,
round_constants: &mut [$field],
internal_matrix_diag: &mut [$field],
mds_type: MdsType,
diffusion: DiffusionStrategy,
ctx: &DeviceContext,
) -> IcicleResult<Poseidon2Constants<'a, $field>> {
unsafe {
let mut poseidon_constants = MaybeUninit::<Poseidon2Constants<'a, $field>>::uninit();
let err = $field_prefix_ident::_create_optimized_constants(
width,
alpha,
internal_rounds,
external_rounds,
round_constants as *mut _ as *mut $field,
internal_matrix_diag as *mut _ as *mut $field,
mds_type,
diffusion,
ctx,
poseidon_constants.as_mut_ptr(),
)
.wrap();
err.and(Ok(poseidon_constants.assume_init()))
}
}
fn load_optimized_constants<'a>(
width: u32,
mds_type: MdsType,
diffusion: DiffusionStrategy,
ctx: &DeviceContext,
) -> IcicleResult<Poseidon2Constants<'a, $field>> {
unsafe {
let mut constants = MaybeUninit::<Poseidon2Constants<'a, $field>>::uninit();
let err = $field_prefix_ident::_load_optimized_constants(
width,
mds_type,
diffusion,
ctx,
constants.as_mut_ptr(),
)
.wrap();
err.and(Ok(constants.assume_init()))
}
}
fn poseidon_unchecked(
states: &mut (impl HostOrDeviceSlice<$field> + ?Sized),
output: &mut (impl HostOrDeviceSlice<$field> + ?Sized),
number_of_states: u32,
width: u32,
constants: &Poseidon2Constants<$field>,
config: &Poseidon2Config,
) -> IcicleResult<()> {
unsafe {
$field_prefix_ident::hash_many(
states.as_mut_ptr(),
output.as_mut_ptr(),
number_of_states,
width,
constants,
config,
)
.wrap()
}
}
}
};
}
#[macro_export]
macro_rules! impl_poseidon2_tests {
(
$field:ident
) => {
#[test]
fn test_poseidon2_hash_many() {
check_poseidon_hash_many::<$field>()
}
};
}

View File

@@ -0,0 +1,105 @@
use crate::poseidon2::{MdsType, PoseidonMode};
use crate::traits::FieldImpl;
use icicle_cuda_runtime::device_context::DeviceContext;
use icicle_cuda_runtime::memory::{HostOrDeviceSlice, HostSlice};
use super::{
load_optimized_poseidon2_constants, poseidon_hash_many, DiffusionStrategy, Poseidon2, Poseidon2Config,
Poseidon2Constants,
};
pub fn init_poseidon<'a, F: FieldImpl>(
width: u32,
mds_type: MdsType,
diffusion: DiffusionStrategy,
) -> Poseidon2Constants<'a, F>
where
<F as FieldImpl>::Config: Poseidon2<F>,
{
let ctx = DeviceContext::default();
load_optimized_poseidon2_constants::<F>(width, mds_type, diffusion, &ctx).unwrap()
}
fn _check_poseidon_hash_many<F: FieldImpl>(width: u32, constants: Poseidon2Constants<F>) -> (F, F)
where
<F as FieldImpl>::Config: Poseidon2<F>,
{
let test_size = 1 << 10;
let mut inputs = vec![F::one(); test_size * width as usize];
let mut outputs = vec![F::zero(); test_size];
let input_slice = HostSlice::from_mut_slice(&mut inputs);
let output_slice = HostSlice::from_mut_slice(&mut outputs);
let config = Poseidon2Config::default();
poseidon_hash_many::<F>(
input_slice,
output_slice,
test_size as u32,
width as u32,
&constants,
&config,
)
.unwrap();
let a1 = output_slice[0];
let a2 = output_slice[output_slice.len() - 2];
assert_eq!(a1, a2);
(a1, a2)
}
pub fn check_poseidon_hash_many<'a, F: FieldImpl + 'a>()
where
<F as FieldImpl>::Config: Poseidon2<F>,
{
let widths = [2, 3, 4, 8, 12, 16, 20, 24];
for width in widths {
let constants = init_poseidon::<'a, F>(width as u32, MdsType::Default, DiffusionStrategy::Default);
_check_poseidon_hash_many(width, constants);
}
}
pub fn check_poseidon_kats<'a, F: FieldImpl>(width: usize, kats: &[F], constants: &Poseidon2Constants<'a, F>)
where
<F as FieldImpl>::Config: Poseidon2<F>,
{
assert_eq!(width, kats.len());
let batch_size = 1024;
let mut input = vec![F::one(); width];
let mut outputs = vec![F::zero(); width * batch_size];
for i in 0..width {
input[i] = F::from_u32(i as u32);
}
let mut inputs: Vec<F> = std::iter::repeat(input.clone())
.take(batch_size)
.flatten()
.collect();
let input_slice = HostSlice::from_mut_slice(&mut inputs);
let output_slice = HostSlice::from_mut_slice(&mut outputs);
let mut config = Poseidon2Config::default();
config.mode = PoseidonMode::Permutation;
poseidon_hash_many::<F>(
input_slice,
output_slice,
batch_size as u32,
width as u32,
&constants,
&config,
)
.unwrap();
for (i, val) in output_slice
.iter()
.enumerate()
{
assert_eq!(*val, kats[i % width]);
}
}

View File

@@ -27,6 +27,7 @@ pub trait FieldImpl:
fn to_bytes_le(&self) -> Vec<u8>;
fn from_bytes_le(bytes: &[u8]) -> Self;
fn from_hex(s: &str) -> Self;
fn zero() -> Self;
fn one() -> Self;
fn from_u32(val: u32) -> Self;

View File

@@ -1,9 +1,11 @@
pub mod curve;
pub mod ecntt;
pub mod msm;
pub mod ntt;
pub mod polynomials;
pub mod poseidon;
pub mod poseidon2;
pub mod tree;
pub mod vec_ops;

View File

@@ -0,0 +1,35 @@
use crate::curve::{ScalarCfg, ScalarField};
use icicle_core::error::IcicleResult;
use icicle_core::impl_poseidon2;
use icicle_core::poseidon2::{DiffusionStrategy, MdsType, Poseidon2, Poseidon2Config, Poseidon2Constants};
use icicle_core::traits::IcicleResultWrap;
use icicle_cuda_runtime::device_context::DeviceContext;
use icicle_cuda_runtime::error::CudaError;
use icicle_cuda_runtime::memory::HostOrDeviceSlice;
use core::mem::MaybeUninit;
impl_poseidon2!("bn254", bn254, ScalarField, ScalarCfg);
#[cfg(test)]
pub(crate) mod tests {
use crate::curve::ScalarField;
use icicle_core::impl_poseidon2_tests;
use icicle_core::ntt::FieldImpl;
use icicle_core::poseidon2::{tests::*, DiffusionStrategy, MdsType};
impl_poseidon2_tests!(ScalarField);
#[test]
fn test_poseidon2_kats() {
let kats = [
ScalarField::from_hex("0x0bb61d24daca55eebcb1929a82650f328134334da98ea4f847f760054f4a3033"),
ScalarField::from_hex("0x303b6f7c86d043bfcbcc80214f26a30277a15d3f74ca654992defe7ff8d03570"),
ScalarField::from_hex("0x1ed25194542b12eef8617361c3ba7c52e660b145994427cc86296242cf766ec8"),
];
let constants = init_poseidon::<ScalarField>(3, MdsType::Default, DiffusionStrategy::Default);
check_poseidon_kats(3, &kats, &constants);
}
}

View File

@@ -17,10 +17,13 @@ cmake = "0.1.50"
[dev-dependencies]
risc0-core = "0.21.0"
risc0-zkp = "0.21.0"
p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3", rev = "83590121c8c28011cffa7e73cb71cf9bf94b8477" }
p3-field = { git = "https://github.com/Plonky3/Plonky3", rev = "83590121c8c28011cffa7e73cb71cf9bf94b8477" }
p3-dft = { git = "https://github.com/Plonky3/Plonky3", rev = "83590121c8c28011cffa7e73cb71cf9bf94b8477" }
p3-matrix = { git = "https://github.com/Plonky3/Plonky3", rev = "83590121c8c28011cffa7e73cb71cf9bf94b8477" }
p3-baby-bear = { git = "https://github.com/Plonky3/Plonky3", rev = "1e87146ebfaedc2150b635b10a096b733795fdce" }
p3-symmetric = { git = "https://github.com/Plonky3/Plonky3", rev = "1e87146ebfaedc2150b635b10a096b733795fdce" }
p3-mds = { git = "https://github.com/Plonky3/Plonky3", rev = "1e87146ebfaedc2150b635b10a096b733795fdce" }
p3-poseidon2 = { git = "https://github.com/Plonky3/Plonky3", rev = "1e87146ebfaedc2150b635b10a096b733795fdce" }
p3-field = { git = "https://github.com/Plonky3/Plonky3", rev = "1e87146ebfaedc2150b635b10a096b733795fdce" }
p3-dft = { git = "https://github.com/Plonky3/Plonky3", rev = "1e87146ebfaedc2150b635b10a096b733795fdce" }
p3-matrix = { git = "https://github.com/Plonky3/Plonky3", rev = "1e87146ebfaedc2150b635b10a096b733795fdce" }
serial_test = "3.0.0"
[features]

View File

@@ -1,4 +1,5 @@
pub mod field;
pub mod ntt;
pub mod polynomials;
pub mod poseidon2;
pub mod vec_ops;

View File

@@ -120,7 +120,7 @@ pub(crate) mod tests {
ntt_cfg.columns_batch = true;
ntt_inplace(HostSlice::from_mut_slice(&mut scalars[..]), NTTDir::kForward, &ntt_cfg).unwrap();
let result_p3 = Radix2Dit.dft_batch(matrix_p3);
let result_p3 = Radix2Dit::default().dft_batch(matrix_p3);
for i in 0..nrows {
for j in 0..ntt_size {
@@ -156,7 +156,7 @@ pub(crate) mod tests {
)
.unwrap();
let ext_result_p3 = Radix2Dit.dft_batch(ext_matrix_p3);
let ext_result_p3 = Radix2Dit::default().dft_batch(ext_matrix_p3);
for i in 0..nrows {
for j in 0..ntt_size {

View File

@@ -0,0 +1,633 @@
use crate::field::{ScalarCfg, ScalarField};
use icicle_core::error::IcicleResult;
use icicle_core::impl_poseidon2;
use icicle_core::poseidon2::{DiffusionStrategy, MdsType, Poseidon2, Poseidon2Config, Poseidon2Constants};
use icicle_core::traits::IcicleResultWrap;
use icicle_cuda_runtime::device_context::DeviceContext;
use icicle_cuda_runtime::error::CudaError;
use icicle_cuda_runtime::memory::HostOrDeviceSlice;
use core::mem::MaybeUninit;
impl_poseidon2!("babybear", babybear, ScalarField, ScalarCfg);
#[cfg(test)]
pub(crate) mod tests {
use crate::field::ScalarField;
use icicle_core::impl_poseidon2_tests;
use icicle_core::poseidon2::{create_optimized_poseidon2_constants, tests::*, DiffusionStrategy, MdsType};
use icicle_core::traits::FieldImpl;
use icicle_cuda_runtime::device_context::DeviceContext;
use p3_baby_bear::BabyBear;
use p3_baby_bear::DiffusionMatrixBabyBear;
use p3_field::{AbstractField, PrimeField32};
use p3_poseidon2::{Poseidon2, Poseidon2ExternalMatrixGeneral};
use p3_symmetric::Permutation;
impl_poseidon2_tests!(ScalarField);
#[test]
fn test_poseidon2_kats() {
let kats = [
ScalarField::from_hex("0x2ed3e23d"),
ScalarField::from_hex("0x12921fb0"),
ScalarField::from_hex("0x0e659e79"),
ScalarField::from_hex("0x61d81dc9"),
ScalarField::from_hex("0x32bae33b"),
ScalarField::from_hex("0x62486ae3"),
ScalarField::from_hex("0x1e681b60"),
ScalarField::from_hex("0x24b91325"),
ScalarField::from_hex("0x2a2ef5b9"),
ScalarField::from_hex("0x50e8593e"),
ScalarField::from_hex("0x5bc818ec"),
ScalarField::from_hex("0x10691997"),
ScalarField::from_hex("0x35a14520"),
ScalarField::from_hex("0x2ba6a3c5"),
ScalarField::from_hex("0x279d47ec"),
ScalarField::from_hex("0x55014e81"),
ScalarField::from_hex("0x5953a67f"),
ScalarField::from_hex("0x2f403111"),
ScalarField::from_hex("0x6b8828ff"),
ScalarField::from_hex("0x1801301f"),
ScalarField::from_hex("0x2749207a"),
ScalarField::from_hex("0x3dc9cf21"),
ScalarField::from_hex("0x3c985ba2"),
ScalarField::from_hex("0x57a99864"),
];
let constants = init_poseidon::<ScalarField>(24, MdsType::Default, DiffusionStrategy::Default);
check_poseidon_kats(24, &kats, &constants);
}
#[test]
fn test_poseidon2_plonky3_t16() {
let rounds_p = 13;
let rounds_f = 8;
const ALPHA: u64 = 7;
const WIDTH: usize = 16;
let cnv = BabyBear::from_canonical_u32;
let external_constants: Vec<[BabyBear; 16]> = vec![
[
cnv(1774958255),
cnv(1185780729),
cnv(1621102414),
cnv(1796380621),
cnv(588815102),
cnv(1932426223),
cnv(1925334750),
cnv(747903232),
cnv(89648862),
cnv(360728943),
cnv(977184635),
cnv(1425273457),
cnv(256487465),
cnv(1200041953),
cnv(572403254),
cnv(448208942),
],
[
cnv(1215789478),
cnv(944884184),
cnv(953948096),
cnv(547326025),
cnv(646827752),
cnv(889997530),
cnv(1536873262),
cnv(86189867),
cnv(1065944411),
cnv(32019634),
cnv(333311454),
cnv(456061748),
cnv(1963448500),
cnv(1827584334),
cnv(1391160226),
cnv(1348741381),
],
[
cnv(88424255),
cnv(104111868),
cnv(1763866748),
cnv(79691676),
cnv(1988915530),
cnv(1050669594),
cnv(359890076),
cnv(573163527),
cnv(222820492),
cnv(159256268),
cnv(669703072),
cnv(763177444),
cnv(889367200),
cnv(256335831),
cnv(704371273),
cnv(25886717),
],
[
cnv(51754520),
cnv(1833211857),
cnv(454499742),
cnv(1384520381),
cnv(777848065),
cnv(1053320300),
cnv(1851729162),
cnv(344647910),
cnv(401996362),
cnv(1046925956),
cnv(5351995),
cnv(1212119315),
cnv(754867989),
cnv(36972490),
cnv(751272725),
cnv(506915399),
],
[
cnv(1922082829),
cnv(1870549801),
cnv(1502529704),
cnv(1990744480),
cnv(1700391016),
cnv(1702593455),
cnv(321330495),
cnv(528965731),
cnv(183414327),
cnv(1886297254),
cnv(1178602734),
cnv(1923111974),
cnv(744004766),
cnv(549271463),
cnv(1781349648),
cnv(542259047),
],
[
cnv(1536158148),
cnv(715456982),
cnv(503426110),
cnv(340311124),
cnv(1558555932),
cnv(1226350925),
cnv(742828095),
cnv(1338992758),
cnv(1641600456),
cnv(1843351545),
cnv(301835475),
cnv(43203215),
cnv(386838401),
cnv(1520185679),
cnv(1235297680),
cnv(904680097),
],
[
cnv(1491801617),
cnv(1581784677),
cnv(913384905),
cnv(247083962),
cnv(532844013),
cnv(107190701),
cnv(213827818),
cnv(1979521776),
cnv(1358282574),
cnv(1681743681),
cnv(1867507480),
cnv(1530706910),
cnv(507181886),
cnv(695185447),
cnv(1172395131),
cnv(1250800299),
],
[
cnv(1503161625),
cnv(817684387),
cnv(498481458),
cnv(494676004),
cnv(1404253825),
cnv(108246855),
cnv(59414691),
cnv(744214112),
cnv(890862029),
cnv(1342765939),
cnv(1417398904),
cnv(1897591937),
cnv(1066647396),
cnv(1682806907),
cnv(1015795079),
cnv(1619482808),
],
];
let internal_constants: Vec<BabyBear> = vec![
cnv(1518359488),
cnv(1765533241),
cnv(945325693),
cnv(422793067),
cnv(311365592),
cnv(1311448267),
cnv(1629555936),
cnv(1009879353),
cnv(190525218),
cnv(786108885),
cnv(557776863),
cnv(212616710),
cnv(605745517),
];
let poseidon2: Poseidon2<BabyBear, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, WIDTH, ALPHA> =
Poseidon2::new(
rounds_f,
external_constants.clone(),
Poseidon2ExternalMatrixGeneral::default(),
rounds_p,
internal_constants.clone(),
DiffusionMatrixBabyBear::default(),
);
let mut input: [BabyBear; WIDTH] = [BabyBear::zero(); WIDTH];
for i in 0..WIDTH {
input[i] = BabyBear::from_canonical_u32(i as u32);
}
let output = poseidon2.permute(input);
let mut kats: [ScalarField; WIDTH] = [ScalarField::zero(); WIDTH];
for i in 0..WIDTH {
kats[i] = ScalarField::from_u32(output[i].as_canonical_u32());
}
let ctx = DeviceContext::default();
let mut round_constants = vec![ScalarField::zero(); rounds_f * WIDTH + rounds_p];
let external_constants_flattened: Vec<ScalarField> = external_constants
.into_iter()
.flatten()
.map(|c| ScalarField::from_u32(c.as_canonical_u32()))
.collect();
let internal_constants_icicle: Vec<ScalarField> = internal_constants
.iter()
.map(|&c| ScalarField::from_u32(c.as_canonical_u32()))
.collect();
(&mut round_constants[..rounds_f / 2 * WIDTH])
.copy_from_slice(&external_constants_flattened[..rounds_f / 2 * WIDTH]);
(&mut round_constants[rounds_f / 2 * WIDTH..rounds_f / 2 * WIDTH + rounds_p])
.copy_from_slice(&internal_constants_icicle[..]);
(&mut round_constants[rounds_p + rounds_f / 2 * WIDTH..])
.copy_from_slice(&external_constants_flattened[rounds_f / 2 * WIDTH..]);
let mut internal_matrix_diag = vec![
ScalarField::from_u32(0x78000001 - 2),
ScalarField::from_u32(1),
ScalarField::from_u32(1 << 1),
ScalarField::from_u32(1 << 2),
ScalarField::from_u32(1 << 3),
ScalarField::from_u32(1 << 4),
ScalarField::from_u32(1 << 5),
ScalarField::from_u32(1 << 6),
ScalarField::from_u32(1 << 7),
ScalarField::from_u32(1 << 8),
ScalarField::from_u32(1 << 9),
ScalarField::from_u32(1 << 10),
ScalarField::from_u32(1 << 11),
ScalarField::from_u32(1 << 12),
ScalarField::from_u32(1 << 13),
ScalarField::from_u32(1 << 15),
];
let mut constants = create_optimized_poseidon2_constants(
WIDTH as u32,
ALPHA as u32,
&ctx,
rounds_p as u32,
rounds_f as u32,
&mut round_constants,
&mut internal_matrix_diag,
MdsType::Plonky,
DiffusionStrategy::Montgomery,
)
.unwrap();
check_poseidon_kats(WIDTH, &kats, &constants);
}
#[test]
fn test_poseidon2_plonky3_t24() {
let rounds_p = 21;
let rounds_f = 8;
const ALPHA: u64 = 7;
const WIDTH: usize = 24;
let cnv = BabyBear::from_canonical_u32;
let external_constants: Vec<[BabyBear; 24]> = vec![
[
cnv(262278199),
cnv(127253399),
cnv(314968988),
cnv(246143118),
cnv(157582794),
cnv(118043943),
cnv(454905424),
cnv(815798990),
cnv(1004040026),
cnv(1773108264),
cnv(1066694495),
cnv(1930780904),
cnv(1180307149),
cnv(1464793095),
cnv(1660766320),
cnv(1389166148),
cnv(343354132),
cnv(1307439985),
cnv(638242172),
cnv(525458520),
cnv(1964135730),
cnv(1751797115),
cnv(1421525369),
cnv(831813382),
],
[
cnv(695835963),
cnv(1845603984),
cnv(540703332),
cnv(1333667262),
cnv(1917861751),
cnv(1170029417),
cnv(1989924532),
cnv(1518763784),
cnv(1339793538),
cnv(622609176),
cnv(686842369),
cnv(1737016378),
cnv(1282239129),
cnv(897025192),
cnv(716894289),
cnv(1997503974),
cnv(395622276),
cnv(1201063290),
cnv(1917549072),
cnv(1150912935),
cnv(1687379185),
cnv(1507936940),
cnv(241306552),
cnv(989176635),
],
[
cnv(1147522062),
cnv(27129487),
cnv(1257820264),
cnv(142102402),
cnv(217046702),
cnv(1664590951),
cnv(855276054),
cnv(1215259350),
cnv(946500736),
cnv(552696906),
cnv(1424297384),
cnv(538103555),
cnv(1608853840),
cnv(162510541),
cnv(623051854),
cnv(1549062383),
cnv(1908416316),
cnv(1622328571),
cnv(1079030649),
cnv(1584033957),
cnv(1099252725),
cnv(1910423126),
cnv(447555988),
cnv(862495875),
],
[
cnv(128479034),
cnv(1587822577),
cnv(608401422),
cnv(1290028279),
cnv(342857858),
cnv(825405577),
cnv(427731030),
cnv(1718628547),
cnv(588764636),
cnv(204228775),
cnv(1454563174),
cnv(1740472809),
cnv(1338899225),
cnv(1269493554),
cnv(53007114),
cnv(1647670797),
cnv(306391314),
cnv(172614232),
cnv(51256176),
cnv(1221257987),
cnv(1239734761),
cnv(273790406),
cnv(1781980094),
cnv(1291790245),
],
[
cnv(53041581),
cnv(723038058),
cnv(1439947916),
cnv(1136469704),
cnv(205609311),
cnv(1883820770),
cnv(14387587),
cnv(720724951),
cnv(1854174607),
cnv(1629316321),
cnv(530151394),
cnv(1679178250),
cnv(1549779579),
cnv(48375137),
cnv(976057819),
cnv(463976218),
cnv(875839332),
cnv(1946596189),
cnv(434078361),
cnv(1878280202),
cnv(1363837384),
cnv(1470845646),
cnv(1792450386),
cnv(1040977421),
],
[
cnv(1209164052),
cnv(714957516),
cnv(390340387),
cnv(1213686459),
cnv(790726260),
cnv(117294666),
cnv(140621810),
cnv(993455846),
cnv(1889603648),
cnv(78845751),
cnv(925018226),
cnv(708123747),
cnv(1647665372),
cnv(1649953458),
cnv(942439428),
cnv(1006235079),
cnv(238616145),
cnv(930036496),
cnv(1401020792),
cnv(989618631),
cnv(1545325389),
cnv(1715719711),
cnv(755691969),
cnv(150307788),
],
[
cnv(1567618575),
cnv(1663353317),
cnv(1950429111),
cnv(1891637550),
cnv(192082241),
cnv(1080533265),
cnv(1463323727),
cnv(890243564),
cnv(158646617),
cnv(1402624179),
cnv(59510015),
cnv(1198261138),
cnv(1065075039),
cnv(1150410028),
cnv(1293938517),
cnv(76770019),
cnv(1478577620),
cnv(1748789933),
cnv(457372011),
cnv(1841795381),
cnv(760115692),
cnv(1042892522),
cnv(1507649755),
cnv(1827572010),
],
[
cnv(1206940496),
cnv(1896271507),
cnv(1003792297),
cnv(738091882),
cnv(1124078057),
cnv(1889898),
cnv(813674331),
cnv(228520958),
cnv(1832911930),
cnv(781141772),
cnv(459826664),
cnv(202271745),
cnv(1296144415),
cnv(1111203133),
cnv(1090783436),
cnv(641665156),
cnv(1393671120),
cnv(1303271640),
cnv(809508074),
cnv(162506101),
cnv(1262312258),
cnv(1672219447),
cnv(1608891156),
cnv(1380248020),
],
];
let internal_constants: Vec<BabyBear> = vec![
cnv(497520322),
cnv(1930103076),
cnv(1052077299),
cnv(1540960371),
cnv(924863639),
cnv(1365519753),
cnv(1726563304),
cnv(440300254),
cnv(1891545577),
cnv(822033215),
cnv(1111544260),
cnv(308575117),
cnv(1708681573),
cnv(1240419708),
cnv(1199068823),
cnv(1186174623),
cnv(1551596046),
cnv(1886977120),
cnv(1327682690),
cnv(1210751726),
cnv(1810596765),
];
let poseidon2: Poseidon2<BabyBear, Poseidon2ExternalMatrixGeneral, DiffusionMatrixBabyBear, WIDTH, ALPHA> =
Poseidon2::new(
rounds_f,
external_constants.clone(),
Poseidon2ExternalMatrixGeneral::default(),
rounds_p,
internal_constants.clone(),
DiffusionMatrixBabyBear::default(),
);
let mut input: [BabyBear; WIDTH] = [BabyBear::zero(); WIDTH];
for i in 0..WIDTH {
input[i] = BabyBear::from_canonical_u32(i as u32);
}
let output = poseidon2.permute(input);
let mut kats: [ScalarField; WIDTH] = [ScalarField::zero(); WIDTH];
for i in 0..WIDTH {
kats[i] = ScalarField::from_u32(output[i].as_canonical_u32());
}
let ctx = DeviceContext::default();
let mut round_constants = vec![ScalarField::zero(); rounds_f * WIDTH + rounds_p];
let external_constants_flattened: Vec<ScalarField> = external_constants
.into_iter()
.flatten()
.map(|c| ScalarField::from_u32(c.as_canonical_u32()))
.collect();
let internal_constants_icicle: Vec<ScalarField> = internal_constants
.iter()
.map(|&c| ScalarField::from_u32(c.as_canonical_u32()))
.collect();
(&mut round_constants[..rounds_f / 2 * WIDTH])
.copy_from_slice(&external_constants_flattened[..rounds_f / 2 * WIDTH]);
(&mut round_constants[rounds_f / 2 * WIDTH..rounds_f / 2 * WIDTH + rounds_p])
.copy_from_slice(&internal_constants_icicle[..]);
(&mut round_constants[rounds_p + rounds_f / 2 * WIDTH..])
.copy_from_slice(&external_constants_flattened[rounds_f / 2 * WIDTH..]);
let mut internal_matrix_diag = vec![
ScalarField::from_u32(0x78000001 - 2),
ScalarField::from_u32(1),
ScalarField::from_u32(1 << 1),
ScalarField::from_u32(1 << 2),
ScalarField::from_u32(1 << 3),
ScalarField::from_u32(1 << 4),
ScalarField::from_u32(1 << 5),
ScalarField::from_u32(1 << 6),
ScalarField::from_u32(1 << 7),
ScalarField::from_u32(1 << 8),
ScalarField::from_u32(1 << 9),
ScalarField::from_u32(1 << 10),
ScalarField::from_u32(1 << 11),
ScalarField::from_u32(1 << 12),
ScalarField::from_u32(1 << 13),
ScalarField::from_u32(1 << 14),
ScalarField::from_u32(1 << 15),
ScalarField::from_u32(1 << 16),
ScalarField::from_u32(1 << 18),
ScalarField::from_u32(1 << 19),
ScalarField::from_u32(1 << 20),
ScalarField::from_u32(1 << 21),
ScalarField::from_u32(1 << 22),
ScalarField::from_u32(1 << 23),
];
let mut constants = create_optimized_poseidon2_constants(
WIDTH as u32,
ALPHA as u32,
&ctx,
rounds_p as u32,
rounds_f as u32,
&mut round_constants,
&mut internal_matrix_diag,
MdsType::Plonky,
DiffusionStrategy::Montgomery,
)
.unwrap();
check_poseidon_kats(WIDTH, &kats, &constants);
}
}