use alloc::vec::Vec;
use p3_field::{Algebra, InjectiveMonomial, PrimeCharacteristicRing};
#[cfg(not(target_arch = "aarch64"))]
use p3_poseidon2::Poseidon2;
use p3_poseidon2::{
ExternalLayer, ExternalLayerConstants, ExternalLayerConstructor, GenericPoseidon2LinearLayers,
InternalLayer, InternalLayerConstructor, MDSMat4, add_rc_and_sbox_generic,
external_initial_permute_state, external_terminal_permute_state, internal_permute_state,
matmul_internal,
};
use crate::Goldilocks;
use crate::poseidon1::GOLDILOCKS_S_BOX_DEGREE;
pub const GOLDILOCKS_POSEIDON2_HALF_FULL_ROUNDS: usize = 4;
pub const GOLDILOCKS_POSEIDON2_PARTIAL_ROUNDS_8: usize = 22;
pub const GOLDILOCKS_POSEIDON2_PARTIAL_ROUNDS_12: usize = 22;
pub const GOLDILOCKS_POSEIDON2_PARTIAL_ROUNDS_16: usize = 22;
#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
pub type Poseidon2Goldilocks<const WIDTH: usize> = crate::Poseidon2GoldilocksFused<WIDTH>;
#[cfg(not(target_arch = "aarch64"))]
pub type Poseidon2Goldilocks<const WIDTH: usize> = Poseidon2<
Goldilocks,
Poseidon2ExternalLayerGoldilocks<WIDTH>,
Poseidon2InternalLayerGoldilocks,
WIDTH,
GOLDILOCKS_S_BOX_DEGREE,
>;
pub const GOLDILOCKS_POSEIDON2_RC_8_EXTERNAL_INITIAL: [[Goldilocks; 8]; 4] = [
Goldilocks::new_array([
0xdd5743e7f2a5a5d9,
0xcb3a864e58ada44b,
0xffa2449ed32f8cdc,
0x42025f65d6bd13ee,
0x7889175e25506323,
0x34b98bb03d24b737,
0xbdcc535ecc4faa2a,
0x5b20ad869fc0d033,
]),
Goldilocks::new_array([
0xf1dda5b9259dfcb4,
0x27515210be112d59,
0x4227d1718c766c3f,
0x26d333161a5bd794,
0x49b938957bf4b026,
0x4a56b5938b213669,
0x1120426b48c8353d,
0x6b323c3f10a56cad,
]),
Goldilocks::new_array([
0xce57d6245ddca6b2,
0xb1fc8d402bba1eb1,
0xb5c5096ca959bd04,
0x6db55cd306d31f7f,
0xc49d293a81cb9641,
0x1ce55a4fe979719f,
0xa92e60a9d178a4d1,
0x002cc64973bcfd8c,
]),
Goldilocks::new_array([
0xcea721cce82fb11b,
0xe5b55eb8098ece81,
0x4e30525c6f1ddd66,
0x43c6702827070987,
0xaca68430a7b5762a,
0x3674238634df9c93,
0x88cee1c825e33433,
0xde99ae8d74b57176,
]),
];
pub const GOLDILOCKS_POSEIDON2_RC_8_EXTERNAL_FINAL: [[Goldilocks; 8]; 4] = [
Goldilocks::new_array([
0x014ef1197d341346,
0x9725e20825d07394,
0xfdb25aef2c5bae3b,
0xbe5402dc598c971e,
0x93a5711f04cdca3d,
0xc45a9a5b2f8fb97b,
0xfe8946a924933545,
0x2af997a27369091c,
]),
Goldilocks::new_array([
0xaa62c88e0b294011,
0x058eb9d810ce9f74,
0xb3cb23eced349ae4,
0xa3648177a77b4a84,
0x43153d905992d95d,
0xf4e2a97cda44aa4b,
0x5baa2702b908682f,
0x082923bdf4f750d1,
]),
Goldilocks::new_array([
0x98ae09a325893803,
0xf8a6475077968838,
0xceb0735bf00b2c5f,
0x0a1a5d953888e072,
0x2fcb190489f94475,
0xb5be06270dec69fc,
0x739cb934b09acf8b,
0x537750b75ec7f25b,
]),
Goldilocks::new_array([
0xe9dd318bae1f3961,
0xf7462137299efe1a,
0xb1f6b8eee9adb940,
0xbdebcc8a809dfe6b,
0x40fc1f791b178113,
0x3ac1c3362d014864,
0x9a016184bdb8aeba,
0x95f2394459fbc25e,
]),
];
pub const GOLDILOCKS_POSEIDON2_RC_8_INTERNAL: [Goldilocks; 22] = Goldilocks::new_array([
0x488897d85ff51f56,
0x1140737ccb162218,
0xa7eeb9215866ed35,
0x9bd2976fee49fcc9,
0xc0c8f0de580a3fcc,
0x4fb2dae6ee8fc793,
0x343a89f35f37395b,
0x223b525a77ca72c8,
0x56ccb62574aaa918,
0xc4d507d8027af9ed,
0xa080673cf0b7e95c,
0xf0184884eb70dcf8,
0x044f10b0cb3d5c69,
0xe9e3f7993938f186,
0x1b761c80e772f459,
0x606cec607a1b5fac,
0x14a0c2e1d45f03cd,
0x4eace8855398574f,
0xf905ca7103eff3e6,
0xf8c8f8d20862c059,
0xb524fe8bdd678e5a,
0xfbb7865901a1ec41,
]);
pub const GOLDILOCKS_POSEIDON2_RC_12_EXTERNAL_INITIAL: [[Goldilocks; 12]; 4] = [
Goldilocks::new_array([
0x13dcf33aba214f46,
0x30b3b654a1da6d83,
0x1fc634ada6159b56,
0x937459964dc03466,
0xedd2ef2ca7949924,
0xede9affde0e22f68,
0x8515b9d6bac9282d,
0x6b5c07b4e9e900d8,
0x1ec66368838c8a08,
0x9042367d80d1fbab,
0x400283564a3c3799,
0x4a00be0466bca75e,
]),
Goldilocks::new_array([
0x7913beee58e3817f,
0xf545e88532237d90,
0x22f8cb8736042005,
0x6f04990e247a2623,
0xfe22e87ba37c38cd,
0xd20e32c85ffe2815,
0x117227674048fe73,
0x4e9fb7ea98a6b145,
0xe0866c232b8af08b,
0x00bbc77916884964,
0x7031c0fb990d7116,
0x240a9e87cf35108f,
]),
Goldilocks::new_array([
0x2e6363a5a12244b3,
0x5e1c3787d1b5011c,
0x4132660e2a196e8b,
0x3a013b648d3d4327,
0xf79839f49888ea43,
0xfe85658ebafe1439,
0xb6889825a14240bd,
0x578453605541382b,
0x4508cda8f6b63ce9,
0x9c3ef35848684c91,
0x0812bde23c87178c,
0xfe49638f7f722c14,
]),
Goldilocks::new_array([
0x8e3f688ce885cbf5,
0xb8e110acf746a87d,
0xb4b2e8973a6dabef,
0x9e714c5da3d462ec,
0x6438f9033d3d0c15,
0x24312f7cf1a27199,
0x23f843bb47acbf71,
0x9183f11a34be9f01,
0x839062fbb9d45dbf,
0x24b56e7e6c2e43fa,
0xe1683da61c962a72,
0xa95c63971a19bfa7,
]),
];
pub const GOLDILOCKS_POSEIDON2_RC_12_EXTERNAL_FINAL: [[Goldilocks; 12]; 4] = [
Goldilocks::new_array([
0xc68be7c94882a24d,
0xaf996d5d5cdaedd9,
0x9717f025e7daf6a5,
0x6436679e6e7216f4,
0x8a223d99047af267,
0xbb512e35a133ba9a,
0xfbbf44097671aa03,
0xf04058ebf6811e61,
0x5cca84703fac7ffb,
0x9b55c7945de6469f,
0x8e05bf09808e934f,
0x2ea900de876307d7,
]),
Goldilocks::new_array([
0x7748fff2b38dfb89,
0x6b99a676dd3b5d81,
0xac4bb7c627cf7c13,
0xadb6ebe5e9e2f5ba,
0x2d33378cafa24ae3,
0x1e5b73807543f8c2,
0x09208814bfebb10f,
0x782e64b6bb5b93dd,
0xadd5a48eac90b50f,
0xadd4c54c736ea4b1,
0xd58dbb86ed817fd8,
0x6d5ed1a533f34ddd,
]),
Goldilocks::new_array([
0x28686aa3e36b7cb9,
0x591abd3476689f36,
0x047d766678f13875,
0xa2a11112625f5b49,
0x21fd10a3f8304958,
0xf9b40711443b0280,
0xd2697eb8b2bde88e,
0x3493790b51731b3f,
0x11caf9dd73764023,
0x7acfb8f72878164e,
0x744ec4db23cefc26,
0x1e00e58f422c6340,
]),
Goldilocks::new_array([
0x21dd28d906a62dda,
0xf32a46ab5f465b5f,
0xbfce13201f3f7e6b,
0xf30d2e7adb5304e2,
0xecdf4ee4abad48e9,
0xf94e82182d395019,
0x4ee52e3744d887c5,
0xa1341c7cac0083b2,
0x2302fb26c30c834a,
0xaea3c587273bf7d3,
0xf798e24961823ec7,
0x962deba3e9a2cd94,
]),
];
pub const GOLDILOCKS_POSEIDON2_RC_12_INTERNAL: [Goldilocks; 22] = Goldilocks::new_array([
0x4adf842aa75d4316,
0xf8fbb871aa4ab4eb,
0x68e85b6eb2dd6aeb,
0x07a0b06b2d270380,
0xd94e0228bd282de4,
0x8bdd91d3250c5278,
0x209c68b88bba778f,
0xb5e18cdab77f3877,
0xb296a3e808da93fa,
0x8370ecbda11a327e,
0x3f9075283775dad8,
0xb78095bb23c6aa84,
0x3f36b9fe72ad4e5f,
0x69bc96780b10b553,
0x3f1d341f2eb7b881,
0x4e939e9815838818,
0xda366b3ae2a31604,
0xbc89db1e7287d509,
0x6102f411f9ef5659,
0x58725c5e7ac1f0ab,
0x0df5856c798883e7,
0xf7bb62a8da4c961b,
]);
pub const GOLDILOCKS_POSEIDON2_RC_16_EXTERNAL_INITIAL: [[Goldilocks; 16]; 4] = [
Goldilocks::new_array([
0x15ebea3fc73397c3,
0xd73cd9fbfe8e275c,
0x8c096bfce77f6c26,
0x4e128f68b53d8fea,
0x29b779a36b2763f6,
0xfe2adc6fb65acd08,
0x8d2520e725ad0955,
0x1c2392b214624d2a,
0x37482118206dcc6e,
0x2f829bed19be019a,
0x2fe298cb6f8159b0,
0x2bbad982deccdbbf,
0xbad568b8cc60a81e,
0xb86a814265baad10,
0xbec2005513b3acb3,
0x6bf89b59a07c2a94,
]),
Goldilocks::new_array([
0xa25deeb835e230f5,
0x3c5bad8512b8b12a,
0x7230f73c3cb7a4f2,
0xa70c87f095c74d0f,
0x6b7606b830bb2e80,
0x6cd467cfc4f24274,
0xfeed794df42a9b0a,
0x8cf7cf6163b7dbd3,
0x9a6e9dda597175a0,
0xaa52295a684faf7b,
0x017b811cc3589d8d,
0x55bfb699b6181648,
0xc2ccaf71501c2421,
0x1707950327596402,
0xdd2fcdcd42a8229f,
0x8b9d7d5b27778a21,
]),
Goldilocks::new_array([
0xac9a05525f9cf512,
0x2ba125c58627b5e8,
0xc74e91250a8147a5,
0xa3e64b640d5bb384,
0xf53047d18d1f9292,
0xbaaeddacae3a6374,
0xf2d0914a808b3db1,
0x18af1a3742bfa3b0,
0x9a621ef50c55bdb8,
0xc615f4d1cc5466f3,
0xb7fbac19a35cf793,
0xd2b1a15ba517e46d,
0x4a290c4d7fd26f6f,
0x4f0cf1bb1770c4c4,
0x548345386cd377f5,
0x33978d2789fddd42,
]),
Goldilocks::new_array([
0xab78c59deb77e211,
0xc485b2a933d2be7f,
0xbde3792c00c03c53,
0xab4cefe8f893d247,
0xc5c0e752eab7f85f,
0xdbf5a76f893bafea,
0xa91f6003e3d984de,
0x099539077f311e87,
0x097ec52232f9559e,
0x53641bdf8991e48c,
0x2afe9711d5ed9d7c,
0xa7b13d3661b5d117,
0x5a0e243fe7af6556,
0x1076fae8932d5f00,
0x9b53a83d434934e3,
0xed3fd595a3c0344a,
]),
];
pub const GOLDILOCKS_POSEIDON2_RC_16_EXTERNAL_FINAL: [[Goldilocks; 16]; 4] = [
Goldilocks::new_array([
0xdacf46dc1c31a045,
0x5d2e3c121eb387f2,
0x51f8b0658b124499,
0x1e7dbd1daa72167d,
0x8275015a25c55b88,
0xe8521c24ac7a70b3,
0x6521d121c40b3f67,
0xac12de797de135b0,
0xafa28ead79f6ed6a,
0x685174a7a8d26f0b,
0xeff92a08d35d9874,
0x3058734b76dd123a,
0xfa55dcfba429f79c,
0x559294d4324c7728,
0x7a770f53012dc178,
0xedd8f7c408f3883b,
]),
Goldilocks::new_array([
0x39b533cf8d795fa5,
0x160ef9de243a8c0a,
0x431d52da6215fe3f,
0x54c51a2a2ef6d528,
0x9b13892b46ff9d16,
0x263c46fcee210289,
0xb738c96d25aabdc4,
0x5c33a5203996d38f,
0x2626496e7c98d8dd,
0xc669e0a52785903a,
0xaecde726c8ae1f47,
0x039343ef3a81e999,
0x2615ceaf044a54f9,
0x7e41e834662b66e1,
0x4ca5fd4895335783,
0x64b334d02916f2b0,
]),
Goldilocks::new_array([
0x87268837389a6981,
0x034b75bcb20a6274,
0x58e658296cc2cd6e,
0xe2d0f759acc31df4,
0x81a652e435093e20,
0x0b72b6e0172eaf47,
0x4aec43cec577d66d,
0xde78365b028a84e6,
0x444e19569adc0ee4,
0x942b2451fa40d1da,
0xe24506623ea5bd6c,
0x082854bf2ef7c743,
0x69dbbc566f59d62e,
0x248c38d02a7b5cb2,
0x4f4e8f8c09d15edb,
0xd96682f188d310cf,
]),
Goldilocks::new_array([
0x6f9a25d56818b54c,
0xb6cefed606546cd9,
0x5bc07523da38a67b,
0x7df5a3c35b8111cf,
0xaaa2cc5d4db34bb0,
0x9e673ff22a4653f8,
0xbd8b278d60739c62,
0xe10d20f6925b8815,
0xf6c87b91dd4da2bf,
0xfed623e2f71b6f1a,
0xa0f02fa52a94d0d3,
0xbb5794711b39fa16,
0xd3b94fba9d005c7f,
0x15a26e89fad946c9,
0xf3cb87db8a67cf49,
0x400d2bf56aa2a577,
]),
];
pub const GOLDILOCKS_POSEIDON2_RC_16_INTERNAL: [Goldilocks; 22] = Goldilocks::new_array([
0x28eff4b01103d100,
0x60400ca3e2685a45,
0x1c8636beb3389b84,
0xac1332b60e13eff0,
0x2adafcc364e20f87,
0x79ffc2b14054ea0b,
0x3f98e4c0908f0a05,
0xcdb230bc4e8a06c4,
0x1bcaf7705b152a74,
0xd9bca249a82a7470,
0x91e24af19bf82551,
0xa62b43ba5cb78858,
0xb4898117472e797f,
0xb3228bca606cdaa0,
0x844461051bca39c9,
0xf3411581f6617d68,
0xf7fd50646782b533,
0x6ca664253c18fb48,
0x2d2fcdec0886a08f,
0x29da00dd799b575e,
0x47d966cc3b6e1e93,
0xde884e9a17ced59e,
]);
#[cfg(not(target_arch = "aarch64"))]
pub fn default_goldilocks_poseidon2_8() -> Poseidon2Goldilocks<8> {
Poseidon2::new(
ExternalLayerConstants::new(
GOLDILOCKS_POSEIDON2_RC_8_EXTERNAL_INITIAL.to_vec(),
GOLDILOCKS_POSEIDON2_RC_8_EXTERNAL_FINAL.to_vec(),
),
GOLDILOCKS_POSEIDON2_RC_8_INTERNAL.to_vec(),
)
}
#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
pub fn default_goldilocks_poseidon2_8() -> Poseidon2Goldilocks<8> {
crate::Poseidon2GoldilocksFused::new(
&ExternalLayerConstants::new(
GOLDILOCKS_POSEIDON2_RC_8_EXTERNAL_INITIAL.to_vec(),
GOLDILOCKS_POSEIDON2_RC_8_EXTERNAL_FINAL.to_vec(),
),
&GOLDILOCKS_POSEIDON2_RC_8_INTERNAL,
)
}
#[cfg(not(target_arch = "aarch64"))]
pub fn default_goldilocks_poseidon2_12() -> Poseidon2Goldilocks<12> {
Poseidon2::new(
ExternalLayerConstants::new(
GOLDILOCKS_POSEIDON2_RC_12_EXTERNAL_INITIAL.to_vec(),
GOLDILOCKS_POSEIDON2_RC_12_EXTERNAL_FINAL.to_vec(),
),
GOLDILOCKS_POSEIDON2_RC_12_INTERNAL.to_vec(),
)
}
#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
pub fn default_goldilocks_poseidon2_12() -> Poseidon2Goldilocks<12> {
crate::Poseidon2GoldilocksFused::new(
&ExternalLayerConstants::new(
GOLDILOCKS_POSEIDON2_RC_12_EXTERNAL_INITIAL.to_vec(),
GOLDILOCKS_POSEIDON2_RC_12_EXTERNAL_FINAL.to_vec(),
),
&GOLDILOCKS_POSEIDON2_RC_12_INTERNAL,
)
}
#[cfg(not(target_arch = "aarch64"))]
pub fn default_goldilocks_poseidon2_16() -> Poseidon2Goldilocks<16> {
Poseidon2::new(
ExternalLayerConstants::new(
GOLDILOCKS_POSEIDON2_RC_16_EXTERNAL_INITIAL.to_vec(),
GOLDILOCKS_POSEIDON2_RC_16_EXTERNAL_FINAL.to_vec(),
),
GOLDILOCKS_POSEIDON2_RC_16_INTERNAL.to_vec(),
)
}
#[cfg(all(target_arch = "aarch64", target_feature = "neon"))]
pub fn default_goldilocks_poseidon2_16() -> Poseidon2Goldilocks<16> {
crate::Poseidon2GoldilocksFused::new(
&ExternalLayerConstants::new(
GOLDILOCKS_POSEIDON2_RC_16_EXTERNAL_INITIAL.to_vec(),
GOLDILOCKS_POSEIDON2_RC_16_EXTERNAL_FINAL.to_vec(),
),
&GOLDILOCKS_POSEIDON2_RC_16_INTERNAL,
)
}
pub const MATRIX_DIAG_8_GOLDILOCKS: [Goldilocks; 8] = Goldilocks::new_array([
0xfffffffeffffffff, 0x0000000000000001, 0x0000000000000002, 0x7fffffff80000001, 0x0000000000000003, 0x7fffffff80000000, 0xfffffffefffffffe, 0xfffffffefffffffd, ]);
pub const MATRIX_DIAG_12_GOLDILOCKS: [Goldilocks; 12] = Goldilocks::new_array([
0xfffffffeffffffff, 0x0000000000000001, 0x0000000000000002, 0x7fffffff80000001, 0x0000000000000003, 0x0000000000000004, 0x7fffffff80000000, 0xfffffffefffffffe, 0xfffffffefffffffd, 0xbfffffff40000001, 0x3fffffffc0000000, 0xdfffffff20000001, ]);
pub const MATRIX_DIAG_16_GOLDILOCKS: [Goldilocks; 16] = Goldilocks::new_array([
0xfffffffeffffffff, 0x0000000000000001, 0x0000000000000002, 0x7fffffff80000001, 0x0000000000000003, 0x0000000000000004, 0x7fffffff80000000, 0xfffffffefffffffe, 0xfffffffefffffffd, 0xdfffffff20000001, 0xefffffff10000001, 0xf7ffffff08000001, 0x1fffffffe0000000, 0x0ffffffff0000000, 0x07fffffff8000000, 0xfffffffe00000002, ]);
pub const MATRIX_DIAG_20_GOLDILOCKS: [Goldilocks; 20] = Goldilocks::new_array([
0x95c381fda3b1fa57,
0xf36fe9eb1288f42c,
0x89f5dcdfef277944,
0x106f22eadeb3e2d2,
0x684e31a2530e5111,
0x27435c5d89fd148e,
0x3ebed31c414dbf17,
0xfd45b0b2d294e3cc,
0x48c904473a7f6dbf,
0xe0d1b67809295b4d,
0xddd1941e9d199dcb,
0x8cfe534eeb742219,
0xa6e5261d9e3b8524,
0x6897ee5ed0f82c1b,
0x0e7dcd0739ee5f78,
0x493253f3d0d32363,
0xbb2737f5845f05c0,
0xa187e810b06ad903,
0xb635b995936c4918,
0x0b3694a940bd2394,
]);
fn internal_layer_mat_mul_goldilocks_8<A: Algebra<Goldilocks>>(state: &mut [A; 8]) {
let sum: A = state.iter().map(|r| r.dup()).sum();
let s0 = state[0].dup();
let s1 = state[1].dup();
let s2 = state[2].dup();
let s3 = state[3].dup();
let s4 = state[4].dup();
let s5 = state[5].dup();
let s6 = state[6].dup();
let s7 = state[7].dup();
let two_s0 = s0.dup() + s0;
state[0] = sum.dup() - two_s0;
state[1] = sum.dup() + s1;
let two_s2 = s2.dup() + s2;
state[2] = sum.dup() + two_s2;
state[3] = sum.dup() + s3.halve();
let two_s4 = s4.dup() + s4.dup();
let three_s4 = two_s4 + s4;
state[4] = sum.dup() + three_s4;
state[5] = sum.dup() - s5.halve();
let two_s6 = s6.dup() + s6.dup();
let three_s6 = two_s6 + s6;
state[6] = sum.dup() - three_s6;
let two_s7 = s7.dup() + s7;
let four_s7 = two_s7.dup() + two_s7;
state[7] = sum - four_s7;
}
fn internal_layer_mat_mul_goldilocks_12<A: Algebra<Goldilocks>>(state: &mut [A; 12]) {
let sum: A = state.iter().map(|r| r.dup()).sum();
let s0 = state[0].dup();
let s1 = state[1].dup();
let s2 = state[2].dup();
let s3 = state[3].dup();
let s4 = state[4].dup();
let s5 = state[5].dup();
let s6 = state[6].dup();
let s7 = state[7].dup();
let s8 = state[8].dup();
let s9 = state[9].dup();
let s10 = state[10].dup();
let s11 = state[11].dup();
let two_s0 = s0.dup() + s0;
state[0] = sum.dup() - two_s0;
state[1] = sum.dup() + s1;
let two_s2 = s2.dup() + s2;
state[2] = sum.dup() + two_s2;
state[3] = sum.dup() + s3.halve();
let two_s4 = s4.dup() + s4.dup();
let three_s4 = two_s4 + s4;
state[4] = sum.dup() + three_s4;
let two_s5 = s5.dup() + s5;
let four_s5 = two_s5.dup() + two_s5;
state[5] = sum.dup() + four_s5;
state[6] = sum.dup() - s6.halve();
let two_s7 = s7.dup() + s7.dup();
let three_s7 = two_s7 + s7;
state[7] = sum.dup() - three_s7;
let two_s8 = s8.dup() + s8;
let four_s8 = two_s8.dup() + two_s8;
state[8] = sum.dup() - four_s8;
state[9] = sum.dup() + s9.halve().halve();
state[10] = sum.dup() - s10.halve().halve();
state[11] = sum + s11.halve().halve().halve();
}
fn internal_layer_mat_mul_goldilocks_16<A: Algebra<Goldilocks>>(state: &mut [A; 16]) {
let sum: A = state.iter().map(|r| r.dup()).sum();
let s0 = state[0].dup();
let s1 = state[1].dup();
let s2 = state[2].dup();
let s3 = state[3].dup();
let s4 = state[4].dup();
let s5 = state[5].dup();
let s6 = state[6].dup();
let s7 = state[7].dup();
let s8 = state[8].dup();
let s9 = state[9].dup();
let s10 = state[10].dup();
let s11 = state[11].dup();
let s12 = state[12].dup();
let s13 = state[13].dup();
let s14 = state[14].dup();
let s15 = state[15].dup();
let two_s0 = s0.dup() + s0;
state[0] = sum.dup() - two_s0;
state[1] = sum.dup() + s1;
let two_s2 = s2.dup() + s2;
state[2] = sum.dup() + two_s2;
state[3] = sum.dup() + s3.halve();
let two_s4 = s4.dup() + s4.dup();
let three_s4 = two_s4 + s4;
state[4] = sum.dup() + three_s4;
let two_s5 = s5.dup() + s5;
let four_s5 = two_s5.dup() + two_s5;
state[5] = sum.dup() + four_s5;
state[6] = sum.dup() - s6.halve();
let two_s7 = s7.dup() + s7.dup();
let three_s7 = two_s7 + s7;
state[7] = sum.dup() - three_s7;
let two_s8 = s8.dup() + s8;
let four_s8 = two_s8.dup() + two_s8;
state[8] = sum.dup() - four_s8;
state[9] = sum.dup() + s9.halve().halve().halve();
state[10] = sum.dup() + s10.halve().halve().halve().halve();
state[11] = sum.dup() + s11.halve().halve().halve().halve().halve();
state[12] = sum.dup() - s12.halve().halve().halve();
state[13] = sum.dup() - s13.halve().halve().halve().halve();
state[14] = sum.dup() - s14.halve().halve().halve().halve().halve();
let inv_2_32 = MATRIX_DIAG_16_GOLDILOCKS[15];
let v15 = s15 * inv_2_32;
state[15] = sum + v15;
}
#[derive(Debug, Clone, Default)]
pub struct Poseidon2InternalLayerGoldilocks {
internal_constants: Vec<Goldilocks>,
}
impl InternalLayerConstructor<Goldilocks> for Poseidon2InternalLayerGoldilocks {
fn new_from_constants(internal_constants: Vec<Goldilocks>) -> Self {
Self { internal_constants }
}
}
impl<A: Algebra<Goldilocks> + InjectiveMonomial<GOLDILOCKS_S_BOX_DEGREE>>
InternalLayer<A, 8, GOLDILOCKS_S_BOX_DEGREE> for Poseidon2InternalLayerGoldilocks
{
fn permute_state(&self, state: &mut [A; 8]) {
internal_permute_state(
state,
internal_layer_mat_mul_goldilocks_8,
&self.internal_constants,
);
}
}
impl<A: Algebra<Goldilocks> + InjectiveMonomial<GOLDILOCKS_S_BOX_DEGREE>>
InternalLayer<A, 12, GOLDILOCKS_S_BOX_DEGREE> for Poseidon2InternalLayerGoldilocks
{
fn permute_state(&self, state: &mut [A; 12]) {
internal_permute_state(
state,
internal_layer_mat_mul_goldilocks_12,
&self.internal_constants,
);
}
}
impl<A: Algebra<Goldilocks> + InjectiveMonomial<GOLDILOCKS_S_BOX_DEGREE>>
InternalLayer<A, 16, GOLDILOCKS_S_BOX_DEGREE> for Poseidon2InternalLayerGoldilocks
{
fn permute_state(&self, state: &mut [A; 16]) {
internal_permute_state(
state,
internal_layer_mat_mul_goldilocks_16,
&self.internal_constants,
);
}
}
impl<A: Algebra<Goldilocks> + InjectiveMonomial<GOLDILOCKS_S_BOX_DEGREE>>
InternalLayer<A, 20, GOLDILOCKS_S_BOX_DEGREE> for Poseidon2InternalLayerGoldilocks
{
fn permute_state(&self, state: &mut [A; 20]) {
internal_permute_state(
state,
|x| matmul_internal(x, MATRIX_DIAG_20_GOLDILOCKS),
&self.internal_constants,
);
}
}
#[derive(Clone)]
pub struct Poseidon2ExternalLayerGoldilocks<const WIDTH: usize> {
pub(crate) external_constants: ExternalLayerConstants<Goldilocks, WIDTH>,
}
impl<const WIDTH: usize> ExternalLayerConstructor<Goldilocks, WIDTH>
for Poseidon2ExternalLayerGoldilocks<WIDTH>
{
fn new_from_constants(external_constants: ExternalLayerConstants<Goldilocks, WIDTH>) -> Self {
Self { external_constants }
}
}
impl<A: Algebra<Goldilocks> + InjectiveMonomial<GOLDILOCKS_S_BOX_DEGREE>, const WIDTH: usize>
ExternalLayer<A, WIDTH, GOLDILOCKS_S_BOX_DEGREE> for Poseidon2ExternalLayerGoldilocks<WIDTH>
{
fn permute_state_initial(&self, state: &mut [A; WIDTH]) {
external_initial_permute_state(
state,
self.external_constants.get_initial_constants(),
add_rc_and_sbox_generic,
&MDSMat4,
);
}
fn permute_state_terminal(&self, state: &mut [A; WIDTH]) {
external_terminal_permute_state(
state,
self.external_constants.get_terminal_constants(),
add_rc_and_sbox_generic,
&MDSMat4,
);
}
}
#[derive(Clone, Debug, Default)]
pub struct GenericPoseidon2LinearLayersGoldilocks;
impl GenericPoseidon2LinearLayers<8> for GenericPoseidon2LinearLayersGoldilocks {
fn internal_linear_layer<R: PrimeCharacteristicRing>(state: &mut [R; 8]) {
let sum: R = state.iter().map(|r| r.dup()).sum();
for i in 0..8 {
let d = R::from_u64(MATRIX_DIAG_8_GOLDILOCKS[i].value);
state[i] *= d;
state[i] += sum.dup();
}
}
}
impl GenericPoseidon2LinearLayers<12> for GenericPoseidon2LinearLayersGoldilocks {
fn internal_linear_layer<R: PrimeCharacteristicRing>(state: &mut [R; 12]) {
let sum: R = state.iter().map(|r| r.dup()).sum();
for i in 0..12 {
let d = R::from_u64(MATRIX_DIAG_12_GOLDILOCKS[i].value);
state[i] *= d;
state[i] += sum.dup();
}
}
}
impl GenericPoseidon2LinearLayers<16> for GenericPoseidon2LinearLayersGoldilocks {
fn internal_linear_layer<R: PrimeCharacteristicRing>(state: &mut [R; 16]) {
let sum: R = state.iter().map(|r| r.dup()).sum();
for i in 0..16 {
let d = R::from_u64(MATRIX_DIAG_16_GOLDILOCKS[i].value);
state[i] *= d;
state[i] += sum.dup();
}
}
}
impl GenericPoseidon2LinearLayers<20> for GenericPoseidon2LinearLayersGoldilocks {
fn internal_linear_layer<R: PrimeCharacteristicRing>(state: &mut [R; 20]) {
let sum: R = state.iter().map(|r| r.dup()).sum();
for i in 0..20 {
let d = R::from_u64(MATRIX_DIAG_20_GOLDILOCKS[i].value);
state[i] *= d;
state[i] += sum.dup();
}
}
}
#[cfg(test)]
mod tests {
use p3_field::PrimeCharacteristicRing;
use p3_symmetric::Permutation;
use super::*;
type F = Goldilocks;
#[test]
fn test_generic_internal_linear_layer_8_matches_matmul_internal() {
let mut state_generic = [
F::from_u64(1),
F::from_u64(2),
F::from_u64(3),
F::from_u64(4),
F::from_u64(5),
F::from_u64(6),
F::from_u64(7),
F::from_u64(8),
];
let mut state_existing = state_generic;
GenericPoseidon2LinearLayersGoldilocks::internal_linear_layer(&mut state_generic);
matmul_internal(&mut state_existing, MATRIX_DIAG_8_GOLDILOCKS);
assert_eq!(state_generic, state_existing);
}
#[test]
fn test_generic_internal_linear_layer_12_matches_matmul_internal() {
let mut state_generic = [
F::from_u64(1),
F::from_u64(2),
F::from_u64(3),
F::from_u64(4),
F::from_u64(5),
F::from_u64(6),
F::from_u64(7),
F::from_u64(8),
F::from_u64(9),
F::from_u64(10),
F::from_u64(11),
F::from_u64(12),
];
let mut state_existing = state_generic;
GenericPoseidon2LinearLayersGoldilocks::internal_linear_layer(&mut state_generic);
matmul_internal(&mut state_existing, MATRIX_DIAG_12_GOLDILOCKS);
assert_eq!(state_generic, state_existing);
}
#[test]
fn test_generic_internal_linear_layer_16_matches_matmul_internal() {
let mut state_generic = [
F::from_u64(1),
F::from_u64(2),
F::from_u64(3),
F::from_u64(4),
F::from_u64(5),
F::from_u64(6),
F::from_u64(7),
F::from_u64(8),
F::from_u64(9),
F::from_u64(10),
F::from_u64(11),
F::from_u64(12),
F::from_u64(13),
F::from_u64(14),
F::from_u64(15),
F::from_u64(16),
];
let mut state_existing = state_generic;
GenericPoseidon2LinearLayersGoldilocks::internal_linear_layer(&mut state_generic);
matmul_internal(&mut state_existing, MATRIX_DIAG_16_GOLDILOCKS);
assert_eq!(state_generic, state_existing);
}
#[test]
fn test_generic_internal_linear_layer_20_matches_matmul_internal() {
let mut state_generic = [
F::from_u64(1),
F::from_u64(2),
F::from_u64(3),
F::from_u64(4),
F::from_u64(5),
F::from_u64(6),
F::from_u64(7),
F::from_u64(8),
F::from_u64(9),
F::from_u64(10),
F::from_u64(11),
F::from_u64(12),
F::from_u64(13),
F::from_u64(14),
F::from_u64(15),
F::from_u64(16),
F::from_u64(17),
F::from_u64(18),
F::from_u64(19),
F::from_u64(20),
];
let mut state_existing = state_generic;
GenericPoseidon2LinearLayersGoldilocks::internal_linear_layer(&mut state_generic);
matmul_internal(&mut state_existing, MATRIX_DIAG_20_GOLDILOCKS);
assert_eq!(state_generic, state_existing);
}
#[test]
fn test_default_goldilocks_poseidon2_width_8() {
let mut input: [F; 8] = Goldilocks::new_array([0, 1, 2, 3, 4, 5, 6, 7]);
let expected: [F; 8] = Goldilocks::new_array([
0x020cf04a1b214d14,
0x84e14aaaeacaed25,
0x1ae0f640e81c7457,
0xa4d204cbaeb0d8a5,
0x0cf637b627b3a7ff,
0x788d304d948b486b,
0x7327133ea1949af4,
0xf415abb924da395b,
]);
let perm = default_goldilocks_poseidon2_8();
perm.permute_mut(&mut input);
assert_eq!(input, expected);
}
#[test]
fn test_default_goldilocks_poseidon2_width_12() {
let mut input: [F; 12] = Goldilocks::new_array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
let expected: [F; 12] = Goldilocks::new_array([
0xf292ab67c0f14b03,
0x0a32f1b37656544c,
0x053c61ab895498de,
0x02ff92e55b196ffb,
0x58176e8f6f58cab2,
0xb0aa1206e7aec0f8,
0xe90c13f3dce83ca4,
0xf4da15333edf39c2,
0x23b701c053c2ca6c,
0xd233d593dcdfbf58,
0x4effa5f9516fb52e,
0x0aaf4489f1f40166,
]);
let perm = default_goldilocks_poseidon2_12();
perm.permute_mut(&mut input);
assert_eq!(input, expected);
}
#[test]
fn test_default_goldilocks_poseidon2_width_16() {
let mut input: [F; 16] = Goldilocks::new_array([
0x4d3f967fab9d4979,
0x57e1fba55677697e,
0x57429a86e75a3774,
0x31d379f3a592b5eb,
0x497232e1b648e3f1,
0x325a7db57173c39e,
0xa802252d78bee916,
0x8920f55e154adef8,
0xa1225bc9c7913658,
0xd687be5097ffd038,
0x89f514ef0c913e48,
0x21fd4a9cf548cd84,
0x570a1586ada436ff,
0x46bfbf38ccd740ae,
0x23651b3f3ab26484,
0xe90f3b02127fa552,
]);
let expected: [F; 16] = Goldilocks::new_array([
0xf0f7717837c7032a,
0xf12fbcc838feb15b,
0xd8661f6fa4165ad8,
0x351cdc546760d1a9,
0x99474334bf02445f,
0x46fc4e9ceb376d6a,
0x4601808321fcd920,
0xc58bfd0342dc60df,
0xb7f3acd43f3c029c,
0x5c7afa6a6997dfc5,
0xecbef8b82906c887,
0xd490e3b4e945d87c,
0x31866766b83ebe0b,
0xb32d52f6e7a5bea2,
0x9522431667b3c5f9,
0xeaf5638a69518f65,
]);
let perm = default_goldilocks_poseidon2_16();
perm.permute_mut(&mut input);
assert_eq!(input, expected);
}
}