diff --git a/.clusterfuzzlite/Dockerfile b/.clusterfuzzlite/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..e42a5556b8c312958087871ccbd388ca33df57af
--- /dev/null
+++ b/.clusterfuzzlite/Dockerfile
@@ -0,0 +1,11 @@
+# Base image with clang toolchain
+FROM gcr.io/oss-fuzz-base/base-builder:v1@sha256:f161edec0c10ad31ced9fcec3d4d0d1dd8a36a22de9ebef136a41dcfac34d1ba
+# install required packages to build your project
+RUN apt-get update && apt-get install -y python3-pip ninja-build
+RUN pip install -U --pre meson
+# Copy your project's source code
+COPY . $SRC/cmp_tool
+# Working directory for build.sh.
+WORKDIR $SRC/cmp_tool
+# Copy build.sh into $SRC dir.
+COPY .clusterfuzzlite/build.sh $SRC/
diff --git a/.clusterfuzzlite/build.sh b/.clusterfuzzlite/build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..43f11d8cc178b896353db3c43bc3daa6f67c9d2d
--- /dev/null
+++ b/.clusterfuzzlite/build.sh
@@ -0,0 +1,22 @@
+#!/bin/bash -eu
+
+BUILD=$WORK/build
+
+# cleanup
+rm -rf "$BUILD"
+mkdir -p "$BUILD"
+
+# setup project
+meson setup "$BUILD" \
+  --buildtype=plain \
+  -Dfuzzer=enabled \
+  -Dfuzzer_ldflags="$LIB_FUZZING_ENGINE" \
+  -Ddebug_level=0 \
+  -Ddefault_library=static \
+  -Db_lundef=false 
+
+# build fuzzers
+ninja -v -C "$BUILD" test/fuzz/fuzz_{round_trip,compression}
+find "$BUILD/test/fuzz" -maxdepth 1 -executable -type f -exec cp "{}" "$OUT" \;
+
+#TODO prepare corps
diff --git a/.clusterfuzzlite/project.yaml b/.clusterfuzzlite/project.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..4ec8305f971c2babb3a8eef2586d5c6b2dba4c82
--- /dev/null
+++ b/.clusterfuzzlite/project.yaml
@@ -0,0 +1,11 @@
+homepage: "https://gitlab.phaidra.org/loidoltd15/cmp_tool"
+language: c
+primary_contact: "dominik.loidolt@univie.ac.at"
+auto_ccs: "dominik.loidolt@univie.ac.at"
+sanitizers:
+- address
+- undefined
+- memory
+
+main_repo: 'https://gitlab.phaidra.org/loidoltd15/cmp_tool.git'
+
diff --git a/.github/workflows/cflite_batch.yml b/.github/workflows/cflite_batch.yml
new file mode 100644
index 0000000000000000000000000000000000000000..30a6b53ee9147d229db1e1c13b269b8634bdb603
--- /dev/null
+++ b/.github/workflows/cflite_batch.yml
@@ -0,0 +1,37 @@
+name: ClusterFuzzLite batch fuzzing
+on:
+  schedule:
+    - cron: '0 0/6 * * *'  # Every 6th hour. Change this to whatever is suitable.
+  push:
+    branches: test_batch_fuzzing
+
+permissions: read-all
+jobs:
+  BatchFuzzing:
+    runs-on: ubuntu-latest
+    strategy:
+      fail-fast: false
+      matrix:
+        sanitizer:
+        - address
+        - undefined
+        - memory
+    steps:
+    - name: Build Fuzzers (${{ matrix.sanitizer }})
+      id: build
+      uses: google/clusterfuzzlite/actions/build_fuzzers@v1
+      with:
+        language: c
+        sanitizer: ${{ matrix.sanitizer }}
+    - name: Run Fuzzers (${{ matrix.sanitizer }})
+      id: run
+      uses: google/clusterfuzzlite/actions/run_fuzzers@v1
+      with:
+        github-token: ${{ secrets.GITHUB_TOKEN }}
+        fuzz-seconds: 3600
+        mode: 'batch'
+        sanitizer: ${{ matrix.sanitizer }}
+        output-sarif: true
+        storage-repo: https://gh-action:${{ secrets.ACCESS_TOKEN_GITLAB_UNI }}@gitlab.phaidra.org/loidoltd15/cmp_tool_storage.git
+        storage-repo-branch: main
+        storage-repo-branch-coverage: gh-pages
diff --git a/.github/workflows/cflite_build.yml b/.github/workflows/cflite_build.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5827f052d431be152b111d9f6c061f2cf732a8bd
--- /dev/null
+++ b/.github/workflows/cflite_build.yml
@@ -0,0 +1,28 @@
+name: ClusterFuzzLite continuous builds
+on:
+  push:
+    branches:
+      - master
+permissions: read-all
+jobs:
+  Build:
+   runs-on: ubuntu-latest
+   concurrency:
+     group: ${{ github.workflow }}-${{ matrix.sanitizer }}-${{ github.ref }}
+     cancel-in-progress: true
+   strategy:
+     fail-fast: false
+     matrix:
+        sanitizer:
+        - address
+        - undefined
+        - memory
+   steps:
+   - name: Build Fuzzers (${{ matrix.sanitizer }})
+     id: build
+     uses: google/clusterfuzzlite/actions/build_fuzzers@v1
+     with:
+        language: c
+        sanitizer: ${{ matrix.sanitizer }}
+        upload-build: true
+
diff --git a/.github/workflows/cflite_cron.yml b/.github/workflows/cflite_cron.yml
new file mode 100644
index 0000000000000000000000000000000000000000..9cbf6f09647c63dceaffe2eb2a6d2c7290fba94d
--- /dev/null
+++ b/.github/workflows/cflite_cron.yml
@@ -0,0 +1,45 @@
+name: ClusterFuzzLite cron tasks
+on:
+  schedule:
+    - cron: '0 0 * * *'  # Once a day at midnight.
+permissions: read-all
+jobs:
+  Pruning:
+    runs-on: ubuntu-latest
+    steps:
+    - name: Build Fuzzers
+      id: build
+      uses: google/clusterfuzzlite/actions/build_fuzzers@v1
+      with:
+        language: c
+    - name: Run Fuzzers
+      id: run
+      uses: google/clusterfuzzlite/actions/run_fuzzers@v1
+      with:
+        github-token: ${{ secrets.GITHUB_TOKEN }}
+        fuzz-seconds: 600
+        mode: 'prune'
+        output-sarif: true
+        storage-repo: https://gh-action:${{ secrets.ACCESS_TOKEN_GITLAB_UNI }}@gitlab.phaidra.org/loidoltd15/cmp_tool_storage.git
+        storage-repo-branch: main  
+        storage-repo-branch-coverage: gh-pages 
+  Coverage:
+    runs-on: ubuntu-latest
+    steps:
+    - name: Build Fuzzers
+      id: build
+      uses: google/clusterfuzzlite/actions/build_fuzzers@v1
+      with:
+        language: c
+        sanitizer: coverage
+    - name: Run Fuzzers
+      id: run
+      uses: google/clusterfuzzlite/actions/run_fuzzers@v1
+      with:
+        github-token: ${{ secrets.GITHUB_TOKEN }}
+        fuzz-seconds: 600
+        mode: 'coverage'
+        sanitizer: 'coverage'
+        storage-repo: https://gh-action:${{ secrets.ACCESS_TOKEN_GITLAB_UNI }}@gitlab.phaidra.org/loidoltd15/cmp_tool_storage.git
+        storage-repo-branch: main  
+        storage-repo-branch-coverage: gh-pages 
diff --git a/.github/workflows/cflite_pr.yml b/.github/workflows/cflite_pr.yml
new file mode 100644
index 0000000000000000000000000000000000000000..a82e85fab4c6eb40a6d9ce66469e814d22a64833
--- /dev/null
+++ b/.github/workflows/cflite_pr.yml
@@ -0,0 +1,42 @@
+name: ClusterFuzzLite PR fuzzing
+on:
+  pull_request:
+    paths:
+      - '**'
+permissions: read-all
+jobs:
+  PR:
+    runs-on: ubuntu-latest
+    concurrency:
+      group: ${{ github.workflow }}-${{ matrix.sanitizer }}-${{ github.ref }}
+      cancel-in-progress: true
+    strategy:
+      fail-fast: false
+      matrix:
+        sanitizer:
+        - address
+        - undefined
+        - memory
+    steps:
+    - name: Build Fuzzers (${{ matrix.sanitizer }})
+      id: build
+      uses: google/clusterfuzzlite/actions/build_fuzzers@v1
+      with:
+        language: c
+        github-token: ${{ secrets.GITHUB_TOKEN }}
+        sanitizer: ${{ matrix.sanitizer }}
+        storage-repo: https://gh-action:${{ secrets.ACCESS_TOKEN_GITLAB_UNI }}@gitlab.phaidra.org/loidoltd15/cmp_tool_storage.git
+        storage-repo-branch: main   
+        storage-repo-branch-coverage: gh-pages  
+    - name: Run Fuzzers (${{ matrix.sanitizer }})
+      id: run
+      uses: google/clusterfuzzlite/actions/run_fuzzers@v1
+      with:
+        github-token: ${{ secrets.GITHUB_TOKEN }}
+        fuzz-seconds: 600
+        mode: 'code-change'
+        sanitizer: ${{ matrix.sanitizer }}
+        output-sarif: true
+        storage-repo: https://gh-action:${{ secrets.ACCESS_TOKEN_GITLAB_UNI }}@gitlab.phaidra.org/loidoltd15/cmp_tool_storage.git
+        storage-repo-branch: main   
+        storage-repo-branch-coverage: gh-pages  
diff --git a/INSTALL.md b/INSTALL.md
index 70a4e0c93824557bbba73313085c476c6502d8c7..98ba3ce9f426a210bbaf28108ce05d5b58f6a2f2 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -8,7 +8,7 @@ If you're on Linux, you probably already have these. On macOS and Windows, you c
 
 ### Install meson and ninja
 
-Meson 0.56 or newer is required.  
+Meson 0.63 or newer is required.  
 You can get meson through your package manager or using:
 
 ```
@@ -130,6 +130,47 @@ ninja coverage-html
 ```
 
 The coverage report can be found in the `meson-logs/coveragereport` subdirectory.
+### Benchmarking
+
+To run the compression speed test bench, follow these steps:
+
+```
+cd <name of the build directory>
+meson test --benchmark
+```
+
+
+### Fuzzing
+If you’re unfamiliar with fuzzing and libFuzzer, you can find a tutorial [here](https://github.com/google/fuzzing/blob/master/tutorial/libFuzzerTutorial.md). 
+To perform fuzzing with libFuzzer, AddressSanitizer, and UndefinedBehaviorSanitizer, follow these steps:
+
+Set up your build directory with the necessary configurations. Note that you’ll need a clang version that has libFuzzer support. Use the following command:
+
+```
+CC=clang CXX=clang++ \
+meson setup builddir_fuzzing \
+  --buildtype=plain \
+  -Dfuzzer=enabled \
+  -Dfuzzer_ldflags=-fsanitize=fuzzer \
+  -Dc_args="-O1 -gline-tables-only -fsanitize-address-use-after-scope -fsanitize=fuzzer-no-link" \
+  -Db_sanitize=address,undefined \
+  -Ddebug_level=0 \
+  -Ddefault_library=static \
+  -Db_lundef=false
+```
+
+The `builddir_fuzzing` directory is now configured for fuzzing. Execute different fuzz targets using the meson test command. For example:
+
+```
+cd builddir_fuzzing
+# List available tests
+meson test --list
+
+# Run a specific fuzz target (e.g., fuzz_round_trip for 10 minutes)
+meson test fuzz_round_trip\ 10\ min --verbose
+```
+
+Happy fuzzing! 🚀
 
 ## Documentation 
 ### External dependencies
diff --git a/lib/common/cmp_debug.c b/lib/common/cmp_debug.c
index 7d45515154fcd15a6e86d2d641159dfc30f94915..08486ab0af9a2dbf0a9cc3ecd668221202cdff82 100644
--- a/lib/common/cmp_debug.c
+++ b/lib/common/cmp_debug.c
@@ -87,4 +87,7 @@ void cmp_debug_print_impl(const char *fmt, ...)
 	cmp_debug_puts(print_buffer);
 }
 
+#else
+/* prevent warning: ISO C requires a translation unit to contain at least one declaration [-Wempty-translation-unit] */
+extern int make_iso_compilers_happy;
 #endif /* (DEBUGLEVEL > 0) */
diff --git a/lib/common/cmp_error.c b/lib/common/cmp_error.c
index 1579151a028294c9498e1f077aa41ec2f297529e..30da8f5abc665e1dca60a9f63d4767e3e6cf48e0 100644
--- a/lib/common/cmp_error.c
+++ b/lib/common/cmp_error.c
@@ -88,6 +88,8 @@ const char* cmp_get_error_string(enum cmp_error code)
 		return "Buffer related parameter is not valid";
 	case CMP_ERROR_PAR_MAX_USED_BITS:
 		return "Maximum used bits parameters are not valid";
+	case CMP_ERROR_PAR_NULL:
+		return "Pointer to the compression parameters structure is NULL.";
 
 	case CMP_ERROR_CHUNK_NULL:
 		return "Pointer to the chunk is NULL. No data, no compression";
diff --git a/lib/common/cmp_error_list.h b/lib/common/cmp_error_list.h
index e28eb940b90f468f942754f8dd8b54c9cab6ead9..93448571de835d50cd4e2eff94e135e3278102f4 100644
--- a/lib/common/cmp_error_list.h
+++ b/lib/common/cmp_error_list.h
@@ -35,6 +35,7 @@ enum cmp_error {
 	CMP_ERROR_PAR_SPECIFIC = 21,
 	CMP_ERROR_PAR_BUFFERS = 22,
 	CMP_ERROR_PAR_MAX_USED_BITS = 23,
+	CMP_ERROR_PAR_NULL = 24,
 	/* chunk errors */
 	CMP_ERROR_CHUNK_NULL = 40,
 	CMP_ERROR_CHUNK_TOO_LARGE = 41,
diff --git a/lib/common/vsnprintf.c b/lib/common/vsnprintf.c
index b1cefe0ed8f19c2d29d8f4ff3cb9e5cfdd36a1c4..87a75e1f7fd8fd1526ae7144a9c040c4a5620c95 100644
--- a/lib/common/vsnprintf.c
+++ b/lib/common/vsnprintf.c
@@ -884,4 +884,8 @@ int my_vsnprintf(char* buffer, size_t count, const char* format, va_list va)
 	return _vsnprintf(_out_buffer, buffer, count, format, va);
 }
 
+#else
+/* prevent warning: ISO C requires a translation unit to contain at least one declaration [-Wempty-translation-unit] */
+extern int make_iso_compilers_happy;
+
 #endif /* (DEBUGLEVEL > 0) */
diff --git a/lib/icu_compress/cmp_icu.c b/lib/icu_compress/cmp_icu.c
index b0fd6cd2caba1588b1f88eac378b93217da3edf9..faa9d53d9f374aebd2647bee34519bef2cb40dbe 100644
--- a/lib/icu_compress/cmp_icu.c
+++ b/lib/icu_compress/cmp_icu.c
@@ -2688,6 +2688,7 @@ uint32_t compress_chunk(void *chunk, uint32_t chunk_size,
 	size_t read_bytes;
 
 	RETURN_ERROR_IF(chunk == NULL, CHUNK_NULL, "");
+	RETURN_ERROR_IF(cmp_par == NULL, PAR_NULL, "");
 	RETURN_ERROR_IF(chunk_size < COLLECTION_HDR_SIZE, CHUNK_SIZE_INCONSISTENT,
 			"chunk_size: %"PRIu32"", chunk_size);
 	RETURN_ERROR_IF(chunk_size > CMP_ENTITY_MAX_ORIGINAL_SIZE, CHUNK_TOO_LARGE,
diff --git a/meson_options.txt b/meson_options.txt
index fc27689bb4a6e18bc5c1c4beb04579af179ea3d2..d19ed29e42451cde424f1e635baf52a429c118b2 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -1,4 +1,4 @@
-option('debug_level', type: 'integer', min: 0, max: 9, value: 1,
-  description: 'Enable run-time debug. See lib/common/cmp_debug.h')
-option('argument_input_mode', type : 'boolean', value : false,
-  description : 'If set, the data file is set with the first argument and the model file with the second one')
+option('debug_level',         type : 'integer', min: 0, max: 9, value: 1,   description: 'Enable run-time debug. See lib/common/cmp_debug.h')
+option('argument_input_mode', type : 'boolean', value : false,              description : 'If set, the data file is set with the first argument and the model file with the second one')
+option('fuzzer',              type : 'feature', value : 'disabled',         description : 'Build for fuzzing')
+option('fuzzer_ldflags',      type : 'string', value : '-fsanitize=fuzzer', description : 'Extra LDFLAGS used during linking of fuzzing binaries')
diff --git a/test/cmp_tool/meson.build b/test/cmp_tool/meson.build
index 17b6ef1af62a64cf288809b7b3492dbc91dc7e2e..dfa0ce6d35ecffc3639fbe45c2b3a3a85b9d4198 100644
--- a/test/cmp_tool/meson.build
+++ b/test/cmp_tool/meson.build
@@ -5,6 +5,7 @@ if pytest.found()
   test('cmp_tool Interface Test',
     pytest,
     args : ['--color=yes', '-vvv', int_test_file],
+    env: test_env,
     depends : cmp_tool_exe,
     timeout : 100,
     workdir : meson.project_build_root())
diff --git a/test/fuzz/download_corpus.sh b/test/fuzz/download_corpus.sh
new file mode 100755
index 0000000000000000000000000000000000000000..5b11d2423b7e1c121b2fa513c4cd009fc03b933a
--- /dev/null
+++ b/test/fuzz/download_corpus.sh
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+bin_path=${1:-}
+if [[ -z "$bin_path" ]]; then
+    echo "usage: $0 <fuzz target>"
+    exit 1
+fi
+
+if [[ "$OSTYPE" == "darwin"* ]]; then
+    DOWNLOAD="curl --silent -L -o"
+else
+    DOWNLOAD="wget --quiet --output-document"
+fi
+
+ROOT_DIR=${MESON_BUILD_ROOT:-.}"/"
+CORPORA_URL=https://gitlab.phaidra.org/loidoltd15/cmp_tool_storage/-/archive/main/cmp_tool_storage-main.tar.bz2
+CORPUS_COMPRESSED=$ROOT_DIR"cmp_tool_storage.tar.bz2"
+CORPUS="cmp_tool_storage-main"
+
+CORPUS_ID=$(git ls-remote https://gitlab.phaidra.org/loidoltd15/cmp_tool_storage.git HEAD | head -c 8)
+CORPUS_DIR="$ROOT_DIR"corpus__"$CORPUS_ID"
+
+if [ ! -d "$CORPUS_DIR" ]; then
+    $DOWNLOAD "$CORPUS_COMPRESSED" "$CORPORA_URL"
+    mkdir "$CORPUS_DIR"
+    tar -xf "$CORPUS_COMPRESSED" -C "$CORPUS_DIR"
+fi
+rm -f "$CORPUS_COMPRESSED"
+
+for arg in "$@" 
+do
+    find "$CORPUS_DIR"/"$CORPUS"/corpus -name "$arg"
+done
diff --git a/test/fuzz/fuzz.h b/test/fuzz/fuzz.h
new file mode 100644
index 0000000000000000000000000000000000000000..ddb25f7c26641b4be55c461a695762e4e91ed7d4
--- /dev/null
+++ b/test/fuzz/fuzz.h
@@ -0,0 +1,21 @@
+/**
+ * Fuzz target interface.
+ */
+
+#ifndef FUZZ_H
+#define FUZZ_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/test/fuzz/fuzz_compression.c b/test/fuzz/fuzz_compression.c
new file mode 100644
index 0000000000000000000000000000000000000000..9962dee6fc181123f5a76c2ce36fcec06a5651fc
--- /dev/null
+++ b/test/fuzz/fuzz_compression.c
@@ -0,0 +1,142 @@
+/**
+ * @file fuzz_copression.c
+ * @date 2024
+ *
+ * @copyright GPLv2
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * @brief chunk compression fuzz target
+ *
+ * This fuzzer tests the compression functionality with random data/model and
+ * parameters. It uses a random portion of the input data for parameter
+ * generation, while the rest is used for compression.
+ */
+
+
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+
+#include "fuzz_helpers.h"
+#include "fuzz_data_producer.h"
+
+#include "../../lib/cmp_chunk.h"
+
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
+{
+	struct cmp_par cmp_par;
+	struct cmp_par *cmp_par_ptr = NULL;
+	const uint8_t *model = NULL;
+	void *up_model;
+	uint32_t *cmp_data;
+	uint32_t cmp_data_capacity;
+	int use_a_upmodel;
+	uint32_t cmp_size_bound;
+	uint32_t return_value;
+
+	/* Give a random portion of src data to the producer, to use for
+	   parameter generation. The rest will be used for data/model */
+	FUZZ_dataProducer_t *producer = (FUZZ_dataProducer_t *)FUZZ_dataProducer_create(src, size);
+	size = FUZZ_dataProducer_reserveDataPrefix(producer);
+
+	FUZZ_dataProducer_cmp_par(producer, &cmp_par);
+
+	/* 1/2 of the cases we use a model */
+	if (FUZZ_dataProducer_uint32Range(producer, 0, 1) && size > 2) {
+		model = src + size/2;
+		size /= 2;
+	}
+	FUZZ_ASSERT(size <= UINT32_MAX);
+
+	cmp_size_bound = compress_chunk_cmp_size_bound(src, size);
+	if (cmp_is_error(cmp_size_bound))
+		cmp_size_bound = 0;
+	cmp_data_capacity = FUZZ_dataProducer_uint32Range(producer, 0, cmp_size_bound+(uint32_t)size);
+	cmp_data = (uint32_t *)FUZZ_malloc(cmp_data_capacity);
+
+	FUZZ_dataProducer_cmp_par(producer, &cmp_par);
+	cmp_par.lossy_par = 0; /*TODO: implement lossy  */
+	if (FUZZ_dataProducer_uint32Range(producer, 0, 1))
+		cmp_par_ptr = &cmp_par;
+
+	use_a_upmodel = FUZZ_dataProducer_int32Range(producer, 0, 2);
+	switch (use_a_upmodel) {
+	case 0:
+		up_model = NULL;
+		break;
+	case 1:
+		up_model = FUZZ_malloc(size);
+		break;
+	case 2:
+		up_model = FUZZ_malloc(size);
+		if (model && up_model) {
+			memcpy(up_model, model, size);
+			model = up_model; /* in-place update */
+		}
+		break;
+	default:
+		FUZZ_ASSERT(0);
+	}
+
+
+	return_value = compress_chunk((void *)src, size, (void *)model, up_model,
+				      cmp_data, cmp_data_capacity, cmp_par_ptr);
+
+	switch (cmp_get_error_code(return_value)) {
+	case CMP_ERROR_NO_ERROR:
+	case CMP_ERROR_GENERIC:
+	case CMP_ERROR_SMALL_BUF_:
+	/* compression parameter errors */
+	case CMP_ERROR_PAR_GENERIC:
+	case CMP_ERROR_PAR_SPECIFIC:
+	case CMP_ERROR_PAR_BUFFERS:
+	case CMP_ERROR_PAR_MAX_USED_BITS:
+	case CMP_ERROR_PAR_NULL:
+	/* chunk errors */
+	case CMP_ERROR_CHUNK_NULL:
+	case CMP_ERROR_CHUNK_TOO_LARGE:
+	case CMP_ERROR_CHUNK_TOO_SMALL:
+	case CMP_ERROR_CHUNK_SIZE_INCONSISTENT:
+	case CMP_ERROR_CHUNK_SUBSERVICE_INCONSISTENT:
+	/* collection errors */
+	case CMP_ERROR_COL_SUBSERVICE_UNSUPPORTED:
+	case CMP_ERROR_COL_SIZE_INCONSISTENT:
+		break;
+	/* compression entity errors */
+	case CMP_ERROR_ENTITY_NULL:
+		FUZZ_ASSERT(0);
+	case CMP_ERROR_ENTITY_TOO_SMALL:
+		FUZZ_ASSERT(0);
+	case CMP_ERROR_ENTITY_HEADER:
+		break;
+	case CMP_ERROR_ENTITY_TIMESTAMP:
+		FUZZ_ASSERT(0);
+	/* internal compressor errors */
+	case CMP_ERROR_INT_DECODER:
+		FUZZ_ASSERT(0);
+	case CMP_ERROR_INT_DATA_TYPE_UNSUPPORTED:
+		FUZZ_ASSERT(0);
+	case CMP_ERROR_INT_CMP_COL_TOO_LARGE:
+		FUZZ_ASSERT(0);
+
+	case CMP_ERROR_DATA_VALUE_TOO_LARGE:
+		FUZZ_ASSERT(0);
+	default:
+		FUZZ_ASSERT(0);
+	}
+
+	free(cmp_data);
+	free(up_model);
+	FUZZ_dataProducer_free(producer);
+	return 0;
+}
+
diff --git a/test/fuzz/fuzz_data_producer.c b/test/fuzz/fuzz_data_producer.c
new file mode 100644
index 0000000000000000000000000000000000000000..1ee59944a44d2b2754d5ca343542c7493c47f1d1
--- /dev/null
+++ b/test/fuzz/fuzz_data_producer.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE.BSD-3.Zstandard file in the 3rdparty_licenses directory) and the GPLv2
+ * (found in the LICENSE.GPL-2 file in the 3rdparty_licenses directory).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/**
+ * Modifications made by
+ * @author Dominik Loidolt (dominik.loidolt@univie.ac.at)
+ * @date 2024
+ * @see https://github.com/facebook/zstd/issues/1723
+ *
+ * - Added function providing a cmp_par struct
+ *
+ * Modifications are also licensed under the same license for consistency
+ *
+ */
+
+
+#include "fuzz_helpers.h"
+#include "fuzz_data_producer.h"
+#include <cmp_chunk.h>
+
+struct FUZZ_dataProducer_s{
+  const uint8_t *data;
+  size_t size;
+};
+
+FUZZ_dataProducer_t *FUZZ_dataProducer_create(const uint8_t *data, size_t size) {
+    FUZZ_dataProducer_t *producer = FUZZ_malloc(sizeof(FUZZ_dataProducer_t));
+
+    producer->data = data;
+    producer->size = size;
+    return producer;
+}
+
+void FUZZ_dataProducer_free(FUZZ_dataProducer_t *producer) { free(producer); }
+
+uint32_t FUZZ_dataProducer_uint32Range(FUZZ_dataProducer_t *producer, uint32_t min,
+                                  uint32_t max) {
+    uint32_t range = max - min;
+    uint32_t rolling = range;
+    uint32_t result = 0;
+
+    FUZZ_ASSERT(min <= max);
+
+    while (rolling > 0 && producer->size > 0) {
+      uint8_t next = *(producer->data + producer->size - 1);
+      producer->size -= 1;
+      result = (result << 8) | next;
+      rolling >>= 8;
+    }
+
+    if (range == 0xffffffff) {
+      return result;
+    }
+
+    return min + result % (range + 1);
+}
+
+uint32_t FUZZ_dataProducer_uint32(FUZZ_dataProducer_t *producer) {
+    return FUZZ_dataProducer_uint32Range(producer, 0, 0xffffffff);
+}
+
+int32_t FUZZ_dataProducer_int32Range(FUZZ_dataProducer_t *producer,
+                                    int32_t min, int32_t max)
+{
+    FUZZ_ASSERT(min <= max);
+
+    if (min < 0)
+      return (int)FUZZ_dataProducer_uint32Range(producer, 0, max - min) + min;
+
+    return FUZZ_dataProducer_uint32Range(producer, min, max);
+}
+
+size_t FUZZ_dataProducer_remainingBytes(FUZZ_dataProducer_t *producer){
+    return producer->size;
+}
+
+void FUZZ_dataProducer_rollBack(FUZZ_dataProducer_t *producer, size_t remainingBytes)
+{
+    FUZZ_ASSERT(remainingBytes >= producer->size);
+    producer->size = remainingBytes;
+}
+
+int FUZZ_dataProducer_empty(FUZZ_dataProducer_t *producer) {
+    return producer->size == 0;
+}
+
+size_t FUZZ_dataProducer_contract(FUZZ_dataProducer_t *producer, size_t newSize)
+{
+    size_t remaining;
+
+    newSize = newSize > producer->size ? producer->size : newSize;
+    remaining = producer->size - newSize;
+    producer->data = producer->data + remaining;
+    producer->size = newSize;
+    return remaining;
+}
+
+size_t FUZZ_dataProducer_reserveDataPrefix(FUZZ_dataProducer_t *producer)
+{
+    size_t producerSliceSize = FUZZ_dataProducer_uint32Range(
+                                  producer, 0, producer->size);
+    return FUZZ_dataProducer_contract(producer, producerSliceSize);
+}
+
+void FUZZ_dataProducer_cmp_par(FUZZ_dataProducer_t *producer, struct cmp_par *cmp_par)
+{
+	cmp_par->cmp_mode = (enum cmp_mode)FUZZ_dataProducer_uint32(producer);
+	cmp_par->model_value = FUZZ_dataProducer_uint32(producer);
+	cmp_par->lossy_par = FUZZ_dataProducer_uint32(producer);
+
+	cmp_par->nc_imagette = FUZZ_dataProducer_uint32(producer);
+
+	cmp_par->s_exp_flags = FUZZ_dataProducer_uint32(producer);
+	cmp_par->s_fx = FUZZ_dataProducer_uint32(producer);
+	cmp_par->s_ncob = FUZZ_dataProducer_uint32(producer);
+	cmp_par->s_efx = FUZZ_dataProducer_uint32(producer);
+	cmp_par->s_ecob = FUZZ_dataProducer_uint32(producer);
+
+	cmp_par->l_exp_flags = FUZZ_dataProducer_uint32(producer);
+	cmp_par->l_fx = FUZZ_dataProducer_uint32(producer);
+	cmp_par->l_ncob = FUZZ_dataProducer_uint32(producer);
+	cmp_par->l_efx = FUZZ_dataProducer_uint32(producer);
+	cmp_par->l_ecob = FUZZ_dataProducer_uint32(producer);
+	cmp_par->l_fx_cob_variance = FUZZ_dataProducer_uint32(producer);
+
+	cmp_par->saturated_imagette = FUZZ_dataProducer_uint32(producer);
+
+	cmp_par->nc_offset_mean = FUZZ_dataProducer_uint32(producer);
+	cmp_par->nc_offset_variance = FUZZ_dataProducer_uint32(producer);
+	cmp_par->nc_background_mean = FUZZ_dataProducer_uint32(producer);
+	cmp_par->nc_background_variance = FUZZ_dataProducer_uint32(producer);
+	cmp_par->nc_background_outlier_pixels = FUZZ_dataProducer_uint32(producer);
+
+	cmp_par->smearing_mean = FUZZ_dataProducer_uint32(producer);
+	cmp_par->smearing_variance_mean = FUZZ_dataProducer_uint32(producer);
+	cmp_par->smearing_outlier_pixels = FUZZ_dataProducer_uint32(producer);
+
+	cmp_par->fc_imagette = FUZZ_dataProducer_uint32(producer);
+	cmp_par->fc_offset_mean = FUZZ_dataProducer_uint32(producer);
+	cmp_par->fc_offset_variance = FUZZ_dataProducer_uint32(producer);
+	cmp_par->fc_background_mean = FUZZ_dataProducer_uint32(producer);
+	cmp_par->fc_background_variance = FUZZ_dataProducer_uint32(producer);
+	cmp_par->fc_background_outlier_pixels = FUZZ_dataProducer_uint32(producer);
+}
diff --git a/test/fuzz/fuzz_data_producer.h b/test/fuzz/fuzz_data_producer.h
new file mode 100644
index 0000000000000000000000000000000000000000..cdccd16a5a916ec8d1326a0be0fb7e378ba846f5
--- /dev/null
+++ b/test/fuzz/fuzz_data_producer.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE.BSD-3.Zstandard file in the 3rdparty_licenses directory) and the GPLv2
+ * (found in the LICENSE.GPL-2 file in the 3rdparty_licenses directory).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/**
+ * Modifications made by
+ * @author Dominik Loidolt (dominik.loidolt@univie.ac.at)
+ * @date 2024
+ *
+ * - Added function providing a cmp_par struct
+ *
+ * Modifications are also licensed under the same license for consistency
+ */
+
+/**
+ * Helper APIs for generating random data from input data stream.
+ The producer reads bytes from the end of the input and appends them together
+ to generate  a random number in the requested range. If it runs out of input
+ data, it will keep returning the same value (min) over and over again.
+
+ */
+
+#ifndef FUZZ_DATA_PRODUCER_H
+#define FUZZ_DATA_PRODUCER_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <cmp_chunk.h>
+
+/* Struct used for maintaining the state of the data */
+typedef struct FUZZ_dataProducer_s FUZZ_dataProducer_t;
+
+/* Returns a data producer state struct. Use for producer initialization. */
+FUZZ_dataProducer_t *FUZZ_dataProducer_create(const uint8_t *data, size_t size);
+
+/* Frees the data producer */
+void FUZZ_dataProducer_free(FUZZ_dataProducer_t *producer);
+
+/* Returns value between [min, max] */
+uint32_t FUZZ_dataProducer_uint32Range(FUZZ_dataProducer_t *producer, uint32_t min,
+                                  uint32_t max);
+
+/* Returns a uint32 value */
+uint32_t FUZZ_dataProducer_uint32(FUZZ_dataProducer_t *producer);
+
+/* Returns a signed value between [min, max] */
+int32_t FUZZ_dataProducer_int32Range(FUZZ_dataProducer_t *producer,
+                                    int32_t min, int32_t max);
+
+/* Provides compression parameters */
+void FUZZ_dataProducer_cmp_par(FUZZ_dataProducer_t *producer, struct cmp_par *cmp_par);
+
+/* Returns the size of the remaining bytes of data in the producer */
+size_t FUZZ_dataProducer_remainingBytes(FUZZ_dataProducer_t *producer);
+
+/* Rolls back the data producer state to have remainingBytes remaining */
+void FUZZ_dataProducer_rollBack(FUZZ_dataProducer_t *producer, size_t remainingBytes);
+
+/* Returns true if the data producer is out of bytes */
+int FUZZ_dataProducer_empty(FUZZ_dataProducer_t *producer);
+
+/* Restricts the producer to only the last newSize bytes of data.
+If newSize > current data size, nothing happens. Returns the number of bytes
+the producer won't use anymore, after contracting. */
+size_t FUZZ_dataProducer_contract(FUZZ_dataProducer_t *producer, size_t newSize);
+
+/* Restricts the producer to use only the last X bytes of data, where X is
+ a random number in the interval [0, data_size]. Returns the size of the
+ remaining data the producer won't use anymore (the prefix). */
+size_t FUZZ_dataProducer_reserveDataPrefix(FUZZ_dataProducer_t *producer);
+#endif // FUZZ_DATA_PRODUCER_H
diff --git a/test/fuzz/fuzz_helpers.c b/test/fuzz/fuzz_helpers.c
new file mode 100644
index 0000000000000000000000000000000000000000..27f10768511dec42d4060a616206733adb358695
--- /dev/null
+++ b/test/fuzz/fuzz_helpers.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE.BSD-3.Zstandard file in the 3rdparty_licenses directory) and the GPLv2
+ * (found in the LICENSE.GPL-2 file in the 3rdparty_licenses directory).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+#include "fuzz_helpers.h"
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+void* FUZZ_malloc(size_t size)
+{
+    if (size > 0) {
+        void* const mem = malloc(size);
+        FUZZ_ASSERT(mem);
+        return mem;
+    }
+    return NULL;
+}
+
+void* FUZZ_malloc_rand(size_t size, FUZZ_dataProducer_t *producer)
+{
+    if (size > 0) {
+        void* const mem = malloc(size);
+        FUZZ_ASSERT(mem);
+        return mem;
+    } else {
+        uintptr_t ptr = 0;
+        /* Add +- 1M 50% of the time */
+        if (FUZZ_dataProducer_uint32Range(producer, 0, 1))
+            FUZZ_dataProducer_int32Range(producer, -1000000, 1000000);
+        return (void*)ptr;
+    }
+
+}
+
+int FUZZ_memcmp(void const* lhs, void const* rhs, int32_t size)
+{
+    if (size <= 0) {
+        return 0;
+    }
+    return memcmp(lhs, rhs, (size_t)size);
+}
diff --git a/test/fuzz/fuzz_helpers.h b/test/fuzz/fuzz_helpers.h
new file mode 100644
index 0000000000000000000000000000000000000000..70fb3fbb39b123797e340191514c48621260a366
--- /dev/null
+++ b/test/fuzz/fuzz_helpers.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
+ * All rights reserved.
+ *
+ * This source code is licensed under both the BSD-style license (found in the
+ * LICENSE.BSD-3.Zstandard file in the 3rdparty_licenses directory) and the GPLv2
+ * (found in the LICENSE.GPL-2 file in the 3rdparty_licenses directory).
+ * You may select, at your option, one of the above-listed licenses.
+ */
+
+/**
+ * Helper functions for fuzzing.
+ */
+
+#ifndef FUZZ_HELPERS_H
+#define FUZZ_HELPERS_H
+
+#include "fuzz.h"
+#include "fuzz_data_producer.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#define FUZZ_QUOTE_IMPL(str) #str
+#define FUZZ_QUOTE(str) FUZZ_QUOTE_IMPL(str)
+
+/**
+ * Asserts for fuzzing that are always enabled.
+ */
+#define FUZZ_ASSERT_MSG(cond, msg)                                             \
+  ((cond) ? (void)0                                                            \
+          : (fprintf(stderr, "%s: %u: Assertion: `%s' failed. %s\n", __FILE__, \
+                     __LINE__, FUZZ_QUOTE(cond), (msg)),                       \
+             abort()))
+#define FUZZ_ASSERT(cond) FUZZ_ASSERT_MSG((cond), "");
+#define FUZZ_ZASSERT(code)                                                     \
+  FUZZ_ASSERT_MSG(!ZSTD_isError(code), ZSTD_getErrorName(code))
+
+#if defined(__GNUC__)
+#define FUZZ_STATIC static __inline __attribute__((unused))
+#elif defined(__cplusplus) ||                                                  \
+    (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
+#define FUZZ_STATIC static inline
+#elif defined(_MSC_VER)
+#define FUZZ_STATIC static __inline
+#else
+#define FUZZ_STATIC static
+#endif
+
+/**
+ * malloc except return NULL for zero sized data and FUZZ_ASSERT
+ * that malloc doesn't fail.
+ */
+void* FUZZ_malloc(size_t size);
+
+/**
+ * malloc except returns random pointer for zero sized data and FUZZ_ASSERT
+ * that malloc doesn't fail.
+ */
+void* FUZZ_malloc_rand(size_t size,  FUZZ_dataProducer_t *producer);
+
+/**
+ * memcmp but accepts NULL. Ignore negative sizes
+ */
+int FUZZ_memcmp(void const* lhs, void const* rhs, int32_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/test/fuzz/fuzz_round_trip.c b/test/fuzz/fuzz_round_trip.c
new file mode 100644
index 0000000000000000000000000000000000000000..d87cb8112d8561e73bbe7c5c099ab9e9259ae4bb
--- /dev/null
+++ b/test/fuzz/fuzz_round_trip.c
@@ -0,0 +1,223 @@
+/**
+ * @file fuzz_round_trip.c
+ * @date 2024
+ *
+ * @copyright GPLv2
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * @brief chunk compression/decompression fuzz target
+ *
+ * This fuzzer tests the (de)compression functionality with random data/model
+ * and parameters. It uses a random portion of the input data for parameter
+ * generation, while the rest is used for compression. If the compression
+ * succeeds, the data are decompressed and checked to see whether they match the
+ * input data.
+ */
+
+#include <string.h>
+
+#include "fuzz_helpers.h"
+#include "fuzz_data_producer.h"
+
+#include "../../lib/cmp_chunk.h"
+#include "../../lib/decmp.h"
+
+
+#define TEST_malloc(size) FUZZ_malloc(size)
+#define TEST_ASSERT(cond) FUZZ_ASSERT(cond)
+
+
+static uint32_t chunk_round_trip(void *data, uint32_t data_size,
+				 void *model, void *up_model,
+				 uint32_t *cmp_data, uint32_t cmp_data_capacity,
+				 struct cmp_par *cmp_par, int use_decmp_buf,
+				 int use_decmp_up_model)
+{
+	uint32_t cmp_size;
+	void *model_cpy = NULL;
+
+	/* if in-place model update is used (up_model == model), the model
+	 * needed for decompression is destroyed; therefore we make a copy
+	 */
+	if (model) {
+		if (up_model == model) {
+			model_cpy = TEST_malloc(data_size);
+			memcpy(model_cpy, model, data_size);
+		} else {
+			model_cpy = model;
+		}
+	}
+
+	cmp_size = compress_chunk(data, data_size, model, up_model,
+				  cmp_data, cmp_data_capacity, cmp_par);
+
+#if 0
+	{ /* Compress a second time and check for determinism */
+		int32_t cSize2;
+		void *compressed2 = NULL;
+		void *up_model2 = NULL;
+
+		if (compressed)
+			compressed2 = FUZZ_malloc(compressedCapacity);
+
+		if (up_model)
+			up_model2 = FUZZ_malloc(srcSize);
+		cSize2 = compress_chunk((void *)src, srcSize, (void *)model, up_model2,
+					   compressed2, compressedCapacity, cmp_par);
+		FUZZ_ASSERT(cSize == cSize2);
+		FUZZ_ASSERT_MSG(!FUZZ_memcmp(compressed, compressed2, cSize), "Not deterministic!");
+		FUZZ_ASSERT_MSG(!FUZZ_memcmp(up_model, compressed2, cSize), "NO deterministic!");
+		free(compressed2);
+		free(up_model2);
+	}
+#endif
+	if (!cmp_is_error(cmp_size) && cmp_data) {
+		void *decmp_data = NULL;
+		void *up_model_decmp = NULL;
+		int decmp_size;
+
+		decmp_size = decompress_cmp_entiy((struct cmp_entity *)cmp_data, model_cpy, NULL, NULL);
+		TEST_ASSERT(decmp_size >= 0);
+		TEST_ASSERT((uint32_t)decmp_size == data_size);
+
+		if (use_decmp_buf)
+			decmp_data = TEST_malloc(data_size);
+		if (use_decmp_up_model) {
+			up_model_decmp = TEST_malloc(data_size);
+			if (!model_mode_is_used(cmp_par->cmp_mode))
+				memset(up_model_decmp, 0, data_size); /* up_model is not used */
+		}
+
+		decmp_size = decompress_cmp_entiy((struct cmp_entity *)cmp_data, model_cpy,
+						  up_model_decmp, decmp_data);
+		TEST_ASSERT(decmp_size >= 0);
+		TEST_ASSERT((uint32_t)decmp_size == data_size);
+
+		if (use_decmp_buf) {
+			TEST_ASSERT(!memcmp(data, decmp_data, data_size));
+
+			/*
+			 * the model is only updated when the decompressed_data
+			 * buffer is set
+			 */
+			if (up_model && up_model_decmp)
+				TEST_ASSERT(!memcmp(up_model, up_model_decmp, data_size));
+		}
+
+		free(decmp_data);
+		free(up_model_decmp);
+	}
+
+	if (up_model == model)
+		free(model_cpy);
+
+	return cmp_size;
+}
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size)
+{
+	struct cmp_par cmp_par;
+	struct cmp_par *cmp_par_ptr=NULL;
+	const uint8_t *model = NULL;
+	void *up_model = NULL;
+	uint32_t cmp_size_bound;
+	uint32_t *cmp_data;
+	uint32_t cmp_data_capacity;
+	uint32_t return_value;
+	int use_decmp_buf;
+	int use_decmp_up_model;
+
+	/* Give a random portion of src data to the producer, to use for
+	   parameter generation. The rest will be used for (de)compression */
+	FUZZ_dataProducer_t *producer = (FUZZ_dataProducer_t *)FUZZ_dataProducer_create(src, size);
+	size = FUZZ_dataProducer_reserveDataPrefix(producer);
+
+	/* 1/2 of the cases we use a model */
+	if (FUZZ_dataProducer_uint32Range(producer, 0, 1) && size > 2) {
+		model = src + size/2;
+		size /= 2;
+	}
+	FUZZ_ASSERT(size <= UINT32_MAX);
+
+	/* generate compression parameters */
+	FUZZ_dataProducer_cmp_par(producer, &cmp_par);
+	cmp_par.lossy_par = 0; /*TODO: implement lossy  */
+	if (FUZZ_dataProducer_uint32Range(producer, 0, 1))
+		cmp_par_ptr = &cmp_par;
+
+	/* 1/2 of the cases we use a updated model buffer */
+	if (FUZZ_dataProducer_uint32Range(producer, 0, 1)) {
+		up_model = FUZZ_malloc(size);
+		if (!model_mode_is_used(cmp_par.cmp_mode))
+			memset(up_model, 0, size); /* up_model is not used */
+	}
+
+	cmp_size_bound = compress_chunk_cmp_size_bound(src, size);
+	if (cmp_is_error(cmp_size_bound))
+		cmp_size_bound = 0;
+	cmp_data_capacity = FUZZ_dataProducer_uint32Range(producer, 0, cmp_size_bound+(uint32_t)size);
+	cmp_data = (uint32_t *)FUZZ_malloc(cmp_data_capacity);
+
+	use_decmp_buf = FUZZ_dataProducer_int32Range(producer, 0, 1);
+	use_decmp_up_model = FUZZ_dataProducer_int32Range(producer, 0, 1);
+
+	return_value = chunk_round_trip(src, size, model, up_model, cmp_data,
+				        cmp_data_capacity, cmp_par_ptr,
+				        use_decmp_buf, use_decmp_up_model);
+	switch (cmp_get_error_code(return_value)) {
+	case CMP_ERROR_NO_ERROR:
+	case CMP_ERROR_GENERIC:
+	case CMP_ERROR_SMALL_BUF_:
+	/* compression parameter errors */
+	case CMP_ERROR_PAR_GENERIC:
+	case CMP_ERROR_PAR_SPECIFIC:
+	case CMP_ERROR_PAR_BUFFERS:
+	case CMP_ERROR_PAR_MAX_USED_BITS:
+	case CMP_ERROR_PAR_NULL:
+	/* chunk errors */
+	case CMP_ERROR_CHUNK_NULL:
+	case CMP_ERROR_CHUNK_TOO_LARGE:
+	case CMP_ERROR_CHUNK_TOO_SMALL:
+	case CMP_ERROR_CHUNK_SIZE_INCONSISTENT:
+	case CMP_ERROR_CHUNK_SUBSERVICE_INCONSISTENT:
+	/* collection errors */
+	case CMP_ERROR_COL_SUBSERVICE_UNSUPPORTED:
+	case CMP_ERROR_COL_SIZE_INCONSISTENT:
+		break;
+	/* compression entity errors */
+	case CMP_ERROR_ENTITY_NULL:
+		FUZZ_ASSERT(0);
+	case CMP_ERROR_ENTITY_TOO_SMALL:
+		FUZZ_ASSERT(0);
+	case CMP_ERROR_ENTITY_HEADER:
+		break;
+	case CMP_ERROR_ENTITY_TIMESTAMP:
+		FUZZ_ASSERT(0);
+	/* internal compressor errors */
+	case CMP_ERROR_INT_DECODER:
+		FUZZ_ASSERT(0);
+	case CMP_ERROR_INT_DATA_TYPE_UNSUPPORTED:
+		FUZZ_ASSERT(0);
+	case CMP_ERROR_INT_CMP_COL_TOO_LARGE:
+		FUZZ_ASSERT(0);
+
+	case CMP_ERROR_DATA_VALUE_TOO_LARGE:
+		FUZZ_ASSERT(0);
+	default:
+		FUZZ_ASSERT(0);
+	}
+
+	free(up_model);
+	free(cmp_data);
+	FUZZ_dataProducer_free(producer);
+
+	return 0;
+}
diff --git a/test/fuzz/meson.build b/test/fuzz/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..f7da779e90bd6576d380c75db37a58c33c13d3c7
--- /dev/null
+++ b/test/fuzz/meson.build
@@ -0,0 +1,42 @@
+if get_option('fuzzer').disabled()
+  subdir_done()
+endif
+
+fuzz_common = files('fuzz_helpers.c', 'fuzz_data_producer.c')
+fuzz_targets = ['fuzz_compression.c', 'fuzz_round_trip.c']
+
+add_languages('cpp', native: false) # libFuzzingEngine needs c++
+
+foreach target : fuzz_targets
+  file_name = target
+  target_name = file_name.split('.').get(0)
+
+  fuzz_exe = executable(target_name,
+    fuzz_common, file_name,
+    include_directories : incdir,
+    link_with : cmp_lib,
+    link_args : get_option('fuzzer_ldflags'),
+    link_language : 'cpp' # libFuzzingEngine needs c++
+  )
+
+   corpus_path = run_command('./download_corpus.sh', target_name, check: true).stdout().split()
+
+  test(target_name + ' 10 min',
+    fuzz_exe,
+    args : ['-rss_limit_mb=2560', '-timeout=25', '-max_total_time=600', corpus_path],
+    env : test_env,
+    is_parallel : false,
+    # suite : 'fuzzing',
+    timeout : 605,
+  )
+
+  test(target_name + ' non stop',
+    fuzz_exe,
+    args : ['-rss_limit_mb=2560', '-timeout=25', corpus_path],
+    env : test_env,
+    is_parallel : false,
+    # suite : 'fuzzing',
+    timeout : 0,
+    verbose : true
+  )
+endforeach
diff --git a/test/meson.build b/test/meson.build
index 00d88c88a5299d4c347a0b3cb09f7c6cbd9a49ea..f145b5d16c3a0eb113a5cbe1f834eb5cff927303 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -28,12 +28,51 @@ if cppcheck.found()
   )
 endif
 
+# Options were copied from oss-fuzz and adapted
+# see: https://github.com/google/sanitizers/wiki/SanitizerCommonFlags
+test_env = environment()
+test_env.set('ASAN_OPTIONS',
+  'abort_on_error=1',
+  'allocator_may_return_null=1',
+  'allocator_release_to_os_interval_ms=500',
+  'detect_container_overflow=1',
+  'detect_stack_use_after_return=1',
+  'fast_unwind_on_fatal=0','handle_abort=1',
+  'handle_segv=1',
+  'handle_sigill=1',
+  'max_uar_stack_size_log=16',
+  'print_scariness=1',
+  'quarantine_size_mb=10',
+  'strict_memcmp=1',
+  'symbolize=1',
+  'use_sigaltstack=1',
+  'dedup_token_length=3'
+)
+if cc.has_argument('-fsanitize=leak')
+  test_env.append('ASAN_OPTIONS', 'detect_leaks=1')
+endif
+
+test_env.set('UBSAN_OPTIONS',
+  'abort_on_error=1',
+  'print_stacktrace=1',
+  'print_summary=1',
+  'symbolize=1',
+  'dedup_token_length=3'
+)
+test_env.set('MSAN_OPTIONS',
+  'abort_on_error=1',
+  'print_stats=1',
+  'symbolize=1',
+  'dedup_token_length=3'
+)
+
 subdir('tools')
 
 subdir('cmp_tool')
 
 unity_dep = dependency('unity', fallback : ['unity', 'unity_dep'])
 subdir('test_common')
+subdir('fuzz')
 
 test_cases = []
 subdir('decmp')
@@ -70,8 +109,12 @@ if ruby.found()
       build_by_default : false
     )
 
-    test(test_description, test_exe)
+    test(test_description, test_exe,
+      env : test_env
+    )
   endforeach
+else
+   message('ruby not found! Install ruby to run unit tests.')
 endif
 
 subdir('bench')