diff --git a/Cargo.toml b/Cargo.toml
index 6b2b45d09774ad847a395cd268218816a1fa4326..745d0bdd73411ed0c80e376148cc0266b7e46c4f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,3 +21,8 @@ tracing-subscriber = "0.3.17"
 
 [dev-dependencies]
 rand = "0.8.5"
+criterion = "0.3"
+
+[[bench]]
+name = "recoding"
+harness = false
diff --git a/benches/recoding.rs b/benches/recoding.rs
new file mode 100644
index 0000000000000000000000000000000000000000..01069027659b3b48a66ff4c01c5e6c23cacb0729
--- /dev/null
+++ b/benches/recoding.rs
@@ -0,0 +1,64 @@
+use ark_bls12_381::Bls12_381;
+use ark_ec::pairing::Pairing;
+use ark_ff::PrimeField;
+
+use rand::Rng;
+
+use komodo::{
+    fec::{combine, Shard},
+    field,
+};
+
+use criterion::{criterion_group, criterion_main, Criterion};
+
+fn to_curve<E: Pairing>(n: u128) -> E::ScalarField {
+    E::ScalarField::from_le_bytes_mod_order(&n.to_le_bytes())
+}
+
+fn create_fake_shard<E: Pairing>(nb_bytes: usize, k: usize) -> Shard<E> {
+    let mut rng = rand::thread_rng();
+    let bytes: Vec<u8> = (0..nb_bytes).map(|_| rng.gen::<u8>()).collect();
+
+    let linear_combination: Vec<E::ScalarField> =
+        (0..k).map(|_| to_curve::<E>(rng.gen::<u128>())).collect();
+
+    Shard {
+        k: k as u32,
+        linear_combination,
+        hash: vec![],
+        bytes: field::split_data_into_field_elements::<E>(&bytes, 1),
+        size: 0,
+    }
+}
+
+fn bench_template<E: Pairing>(c: &mut Criterion, nb_bytes: usize, k: usize, nb_shards: usize) {
+    let shards: Vec<Shard<E>> = (0..nb_shards)
+        .map(|_| create_fake_shard(nb_bytes, k))
+        .collect();
+
+    let mut rng = rand::thread_rng();
+    let coeffs: Vec<E::ScalarField> = (0..nb_shards)
+        .map(|_| to_curve::<E>(rng.gen::<u128>()))
+        .collect();
+
+    c.bench_function(
+        &format!(
+            "recoding {} bytes and {} shards with k = {}",
+            nb_bytes, nb_shards, k
+        ),
+        |b| b.iter(|| combine(&shards, &coeffs)),
+    );
+}
+
+fn criterion_benchmark(c: &mut Criterion) {
+    for nb_bytes in [1, 1_024, 1_024 * 1_024] {
+        for nb_shards in [2, 4, 8, 16] {
+            for k in [2, 4, 8, 16] {
+                bench_template::<Bls12_381>(c, nb_bytes, k, nb_shards);
+            }
+        }
+    }
+}
+
+criterion_group!(benches, criterion_benchmark);
+criterion_main!(benches);
diff --git a/src/fec.rs b/src/fec.rs
index 2c83471878ac5b377d5347658770932a77f67413..fadf5ecf8956572608d39c8ff58019944fe8cf5d 100644
--- a/src/fec.rs
+++ b/src/fec.rs
@@ -47,10 +47,7 @@ impl<E: Pairing> Shard<E> {
     }
 }
 
-pub(super) fn combine<E: Pairing>(
-    shards: &[Shard<E>],
-    coeffs: &[E::ScalarField],
-) -> Option<Shard<E>> {
+pub fn combine<E: Pairing>(shards: &[Shard<E>], coeffs: &[E::ScalarField]) -> Option<Shard<E>> {
     if shards.len() != coeffs.len() {
         return None;
     }
diff --git a/src/field.rs b/src/field.rs
index 1b92cdb7071178c1bbdb1737f61ba5bd7a5b8e48..e3e79115573373ff63fd2c66abe3fdcd936c2720 100644
--- a/src/field.rs
+++ b/src/field.rs
@@ -6,7 +6,7 @@ use ark_std::One;
 ///
 /// [`split_data_into_field_elements`] supports padding the output vector of
 /// elements by giving a number that needs to divide the length of the vector.
-pub(crate) fn split_data_into_field_elements<E: Pairing>(
+pub fn split_data_into_field_elements<E: Pairing>(
     bytes: &[u8],
     modulus: usize,
 ) -> Vec<E::ScalarField> {
diff --git a/src/lib.rs b/src/lib.rs
index d581ff9aa9e900d67b760a94d5507797678e2e2b..9d334b0efdf2f00eab3db34ab92aed62bd7306ff 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -11,7 +11,7 @@ use tracing::{debug, info};
 
 mod error;
 pub mod fec;
-mod field;
+pub mod field;
 pub mod linalg;
 pub mod setup;