Skip to content

Commit 5f6c787

Browse files
authored
feat: add new permutation-related APIs (#13)
* impl Default for SwCurves * Self::P is an permutation of Ts * add get_default_perm_rc * revert defaults * clippy
1 parent 6ee7e8d commit 5f6c787

File tree

5 files changed

+94
-30
lines changed

5 files changed

+94
-30
lines changed

crates/ff_ext/src/babybear.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
pub mod impl_babybear {
2-
use crate::array_try_from_uniform_bytes;
2+
use crate::{array_try_from_uniform_bytes, wrapper::Wrapper};
33
use p3::{
44
self,
55
babybear::{BabyBear, Poseidon2BabyBear},
@@ -94,20 +94,14 @@ pub mod impl_babybear {
9494

9595
#[cfg(debug_assertions)]
9696
use crate::poseidon::impl_instruments::*;
97-
#[cfg(debug_assertions)]
98-
use p3::symmetric::CryptographicPermutation;
9997

100-
#[cfg(debug_assertions)]
101-
impl CryptographicPermutation<[BabyBear; POSEIDON2_BABYBEAR_WIDTH]>
102-
for Instrumented<Poseidon2BabyBear<POSEIDON2_BABYBEAR_WIDTH>>
103-
{
104-
}
98+
type WP = Wrapper<Poseidon2BabyBear<POSEIDON2_BABYBEAR_WIDTH>, POSEIDON2_BABYBEAR_WIDTH>;
10599

106100
impl PoseidonField for BabyBear {
107101
#[cfg(debug_assertions)]
108-
type P = Instrumented<Poseidon2BabyBear<POSEIDON2_BABYBEAR_WIDTH>>;
102+
type P = Instrumented<WP>;
109103
#[cfg(not(debug_assertions))]
110-
type P = Poseidon2BabyBear<POSEIDON2_BABYBEAR_WIDTH>;
104+
type P = WP;
111105

112106
type T = DuplexChallenger<Self, Self::P, POSEIDON2_BABYBEAR_WIDTH, POSEIDON2_BABYBEAR_RATE>;
113107
type S = PaddingFreeSponge<Self::P, POSEIDON2_BABYBEAR_WIDTH, POSEIDON2_BABYBEAR_RATE, 8>;
@@ -124,24 +118,34 @@ pub mod impl_babybear {
124118

125119
#[cfg(debug_assertions)]
126120
fn get_default_perm() -> Self::P {
127-
Instrumented::new(Poseidon2BabyBear::new(
121+
Instrumented::new(Wrapper::new(Poseidon2BabyBear::new(
128122
ExternalLayerConstants::new(
129123
BABYBEAR_RC16_EXTERNAL_INITIAL.to_vec(),
130124
BABYBEAR_RC16_EXTERNAL_FINAL.to_vec(),
131125
),
132126
BABYBEAR_RC16_INTERNAL.to_vec(),
133-
))
127+
)))
134128
}
135129

136130
#[cfg(not(debug_assertions))]
137131
fn get_default_perm() -> Self::P {
138-
Poseidon2BabyBear::new(
132+
Wrapper::new(Poseidon2BabyBear::new(
139133
ExternalLayerConstants::new(
140134
BABYBEAR_RC16_EXTERNAL_INITIAL.to_vec(),
141135
BABYBEAR_RC16_EXTERNAL_FINAL.to_vec(),
142136
),
143137
BABYBEAR_RC16_INTERNAL.to_vec(),
144-
)
138+
))
139+
}
140+
141+
fn get_default_perm_rc() -> Vec<Self> {
142+
BABYBEAR_RC16_EXTERNAL_INITIAL
143+
.iter()
144+
.flatten()
145+
.chain(BABYBEAR_RC16_INTERNAL.iter())
146+
.chain(BABYBEAR_RC16_EXTERNAL_FINAL.iter().flatten())
147+
.cloned()
148+
.collect()
145149
}
146150

147151
fn get_default_sponge() -> Self::S {

crates/ff_ext/src/goldilock.rs

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ pub mod impl_goldilocks {
33
ExtensionField, FieldFrom, FieldInto, FromUniformBytes, SmallField,
44
array_try_from_uniform_bytes, impl_from_uniform_bytes_for_binomial_extension,
55
poseidon::{PoseidonField, new_array},
6+
wrapper::Wrapper,
67
};
78
use p3::{
89
challenger::DuplexChallenger,
@@ -21,8 +22,6 @@ pub mod impl_goldilocks {
2122

2223
#[cfg(debug_assertions)]
2324
use crate::poseidon::impl_instruments::*;
24-
#[cfg(debug_assertions)]
25-
use p3::symmetric::CryptographicPermutation;
2625

2726
pub type GoldilocksExt2 = BinomialExtensionField<Goldilocks, 2>;
2827

@@ -47,17 +46,13 @@ pub mod impl_goldilocks {
4746
pub const POSEIDON2_GOLDILICK_WIDTH: usize = 8;
4847
pub const POSEIDON2_GOLDILICK_RATE: usize = 4;
4948

50-
#[cfg(debug_assertions)]
51-
impl CryptographicPermutation<[Goldilocks; POSEIDON2_GOLDILICK_WIDTH]>
52-
for Instrumented<Poseidon2GoldilocksHL<POSEIDON2_GOLDILICK_WIDTH>>
53-
{
54-
}
55-
49+
type WP = Wrapper<Poseidon2GoldilocksHL<POSEIDON2_GOLDILICK_WIDTH>, POSEIDON2_GOLDILICK_WIDTH>;
5650
impl PoseidonField for Goldilocks {
5751
#[cfg(debug_assertions)]
58-
type P = Instrumented<Poseidon2GoldilocksHL<POSEIDON2_GOLDILICK_WIDTH>>;
52+
type P = Instrumented<WP>;
5953
#[cfg(not(debug_assertions))]
60-
type P = Poseidon2GoldilocksHL<POSEIDON2_GOLDILICK_WIDTH>;
54+
type P = WP;
55+
6156
type T =
6257
DuplexChallenger<Self, Self::P, POSEIDON2_GOLDILICK_WIDTH, POSEIDON2_GOLDILICK_RATE>;
6358
type S = PaddingFreeSponge<Self::P, POSEIDON2_GOLDILICK_WIDTH, POSEIDON2_GOLDILICK_RATE, 4>;
@@ -71,24 +66,34 @@ pub mod impl_goldilocks {
7166

7267
#[cfg(debug_assertions)]
7368
fn get_default_perm() -> Self::P {
74-
Instrumented::new(Poseidon2GoldilocksHL::new(
69+
Instrumented::new(Wrapper::new(Poseidon2GoldilocksHL::new(
7570
ExternalLayerConstants::<Goldilocks, POSEIDON2_GOLDILICK_WIDTH>::new_from_saved_array(
7671
HL_GOLDILOCKS_8_EXTERNAL_ROUND_CONSTANTS,
7772
new_array,
7873
),
7974
new_array(HL_GOLDILOCKS_8_INTERNAL_ROUND_CONSTANTS).to_vec(),
80-
))
75+
)))
8176
}
8277

8378
#[cfg(not(debug_assertions))]
8479
fn get_default_perm() -> Self::P {
85-
Poseidon2GoldilocksHL::new(
80+
Wrapper::new(Poseidon2GoldilocksHL::new(
8681
ExternalLayerConstants::<Goldilocks, POSEIDON2_GOLDILICK_WIDTH>::new_from_saved_array(
8782
HL_GOLDILOCKS_8_EXTERNAL_ROUND_CONSTANTS,
8883
new_array,
8984
),
9085
new_array(HL_GOLDILOCKS_8_INTERNAL_ROUND_CONSTANTS).to_vec(),
91-
)
86+
))
87+
}
88+
89+
fn get_default_perm_rc() -> Vec<Self> {
90+
HL_GOLDILOCKS_8_EXTERNAL_ROUND_CONSTANTS[0]
91+
.iter()
92+
.flatten()
93+
.chain(HL_GOLDILOCKS_8_INTERNAL_ROUND_CONSTANTS.iter())
94+
.chain(HL_GOLDILOCKS_8_EXTERNAL_ROUND_CONSTANTS[1].iter().flatten())
95+
.map(|v| Self::from_canonical_u64(*v))
96+
.collect()
9297
}
9398

9499
fn get_default_sponge() -> Self::S {

crates/ff_ext/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use std::{
1010
iter::{self, repeat_with},
1111
};
1212
mod babybear;
13+
mod wrapper;
1314
pub use babybear::impl_babybear::*;
1415
mod goldilock;
1516
pub use goldilock::impl_goldilocks::*;

crates/ff_ext/src/poseidon.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use p3::{
22
challenger::{FieldChallenger, GrindingChallenger},
33
commit::Mmcs,
44
field::PrimeField,
5+
symmetric::Permutation,
56
};
67

78
use crate::{ExtensionField, SmallField};
@@ -19,7 +20,7 @@ pub trait FieldChallengerExt<F: PoseidonField>: FieldChallenger<F> {
1920

2021
pub trait PoseidonField: PrimeField + SmallField {
2122
// permutation
22-
type P: Clone;
23+
type P: Clone + Permutation<Vec<Self>> + Send + Sync;
2324
// sponge
2425
type S: Clone + Sync;
2526
// compression
@@ -28,6 +29,7 @@ pub trait PoseidonField: PrimeField + SmallField {
2829
type T: FieldChallenger<Self> + Clone + GrindingChallenger<Witness = Self>;
2930
fn get_default_challenger() -> Self::T;
3031
fn get_default_perm() -> Self::P;
32+
fn get_default_perm_rc() -> Vec<Self>;
3133
fn get_default_sponge() -> Self::S;
3234
fn get_default_compression() -> Self::C;
3335
fn get_default_mmcs() -> Self::MMCS;
@@ -51,7 +53,7 @@ pub mod impl_instruments {
5153
};
5254

5355
use once_cell::sync::Lazy;
54-
use p3::symmetric::Permutation;
56+
use p3::symmetric::{CryptographicPermutation, Permutation};
5557

5658
pub type PermCount = Arc<Mutex<usize>>;
5759
pub type LabelCounts = Arc<Mutex<HashMap<&'static str, usize>>>;
@@ -136,4 +138,6 @@ pub mod impl_instruments {
136138
self.inner_perm.permute(input)
137139
}
138140
}
141+
142+
impl<T: Clone, P: Permutation<T>> CryptographicPermutation<T> for Instrumented<P> {}
139143
}

crates/ff_ext/src/wrapper.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use p3::symmetric::{CryptographicPermutation, Permutation};
2+
use std::array::from_fn;
3+
#[derive(Clone)]
4+
pub struct Wrapper<P: Clone, const N: usize> {
5+
inner: P,
6+
}
7+
8+
impl<P: Clone, const N: usize> Wrapper<P, N> {
9+
pub fn new(inner: P) -> Self {
10+
Self { inner }
11+
}
12+
}
13+
14+
impl<const N: usize, T: Clone, P: Permutation<[T; N]> + Clone> Permutation<Vec<T>>
15+
for Wrapper<P, N>
16+
{
17+
fn permute(&self, input: Vec<T>) -> Vec<T> {
18+
assert_eq!(input.len(), N, "Input vector must be of length {}", N);
19+
20+
let mut array = from_fn(|i| input[i].clone());
21+
self.inner.permute_mut(&mut array);
22+
23+
array.to_vec()
24+
}
25+
26+
fn permute_mut(&self, input: &mut Vec<T>) {
27+
assert_eq!(input.len(), N, "Input vector must be of length {}", N);
28+
let mut array = from_fn(|i| input[i].clone());
29+
self.inner.permute_mut(&mut array);
30+
input.iter_mut().zip(array).for_each(|(i, a)| {
31+
*i = a;
32+
});
33+
}
34+
}
35+
impl<const N: usize, T: Clone, P: Permutation<[T; N]> + Clone> Permutation<[T; N]>
36+
for Wrapper<P, N>
37+
{
38+
fn permute(&self, input: [T; N]) -> [T; N] {
39+
self.inner.permute(input)
40+
}
41+
42+
fn permute_mut(&self, input: &mut [T; N]) {
43+
self.inner.permute_mut(input);
44+
}
45+
}
46+
47+
impl<const N: usize, T: Clone, P: Permutation<[T; N]> + Clone> CryptographicPermutation<[T; N]>
48+
for Wrapper<P, N>
49+
{
50+
}

0 commit comments

Comments
 (0)