diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
new file mode 100644
index 0000000..ebec289
--- /dev/null
+++ b/.github/workflows/continuous-integration.yml
@@ -0,0 +1,18 @@
+name: Continuous Integration
+
+on:
+ push:
+ branches: ["main"]
+ pull_request:
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: aiken-lang/setup-aiken@v1
+ with:
+ version: v1.1.9
+ - run: aiken fmt --check
+ - run: aiken check -D
+ - run: aiken build
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ff7811b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+# Aiken compilation artifacts
+artifacts/
+# Aiken's project working directory
+build/
+# Aiken's default documentation export
+docs/
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..589721d
--- /dev/null
+++ b/README.md
@@ -0,0 +1,36 @@
+
+
+
aiken/bench
+
+[](https://github.com/aiken-lang/bench/blob/main/LICENSE)
+[](https://github.com/aiken-lang/bench/actions/workflows/continuous-integration.yml)
+
+
+
+The official library for writing _samplers_ (a.k.a Scaled Fuzzers) for the [Aiken](https://aiken-lang.org) Cardano smart-contract language.
+
+> ### ⚠️ WARNING
+>
+> **IMPORTANT:** This is a work in progress and the API is not stable yet; additionally Samplers are not yet supported in the current version of Aiken (v1.1.9).
+
+## Installation
+
+```
+aiken add aiken-lang/bench --version v0.0.0
+```
+
+## Getting started
+
+First, make sure you have the [Aiken's user manual about tests](https://aiken-lang.org/language-tour/tests#property-based-test); in particular the section about benchmarking functions.
+
+In many situations, you can use primitives from this library out-of-the-box, composing them inline when necessary. For example, if you need a growing non-empty list of values, you can simply write:
+
+```
+use aiken/bench
+
+bench my_bench(xs via bench.list(bench.int(Linear(1)), Linear(1))) {
+ // some function
+}
+```
+
+You can also write your own more complex sampler. Note that writing good samplers can be complicated, so here are a few guiding principles you should follow.. TODO
\ No newline at end of file
diff --git a/lib/aiken/sample.ak b/lib/aiken/sample.ak
new file mode 100644
index 0000000..92ea18e
--- /dev/null
+++ b/lib/aiken/sample.ak
@@ -0,0 +1,212 @@
+use aiken/builtin
+use cardano/assets.{Value}
+use aiken/interval.{Interval}
+use cardano/script_context.{ScriptContext}
+use cardano/transaction.{Input, Output, ScriptPurpose, Transaction}
+use aiken/crypto.{Blake2b_224, Hash}
+use cardano/address.{Address, Credential, Inline, VerificationKey}
+use aiken/collection/dict
+
+/// A growth pattern determines how complexity scales with input size
+pub type Growth {
+ /// Constant growth: f(n) = c
+ Constant
+ /// Linear growth: f(n) = n
+ Linear(Int)
+ /// Exponential growth: f(n) = 2^n
+ Exponential(Int)
+ /// Logarithmic growth: f(n) = log(n)
+ Logarithmic(Int)
+}
+
+/// Core random number generator that produces a byte (0-255)
+fn rand(prng: PRNG) -> Option<(PRNG, Int)> {
+ when prng is {
+ Seeded { seed, choices } -> {
+ let choice = builtin.index_bytearray(seed, 0)
+ Some((
+ Seeded {
+ seed: crypto.blake2b_256(seed),
+ choices: builtin.cons_bytearray(choice, choices),
+ },
+ choice,
+ ))
+ }
+ Replayed { cursor, choices } -> {
+ if cursor >= 1 {
+ let cursor = cursor - 1
+ Some((
+ Replayed { cursor, choices },
+ builtin.index_bytearray(choices, cursor),
+ ))
+ } else {
+ None
+ }
+ }
+ }
+}
+
+/// Apply a growth pattern to scale an input size
+pub fn apply_growth(pattern: Growth, n: Int) -> Int {
+ when pattern is {
+ Constant -> 1
+ Linear(base) -> base * n
+ Exponential(base) ->
+ if n <= 0 {
+ 0
+ } else {
+ exp_int_helper(base, n, 1)
+ }
+ Logarithmic(base) ->
+ if n <= 1 {
+ 0
+ } else {
+ count_divisions(base, n, 0)
+ }
+ }
+}
+
+// TODO: Probably need to use a builtin in the future.
+fn exp_int_helper(base: Int, n: Int, acc: Int) -> Int {
+ if base <= 0 {
+ acc
+ } else {
+ exp_int_helper(base - 1, n, acc * n)
+ }
+}
+
+// TODO: Probably need to use a builtin in the future.
+fn count_divisions(base: Int, n: Int, acc: Int) -> Int {
+ if n <= 1 {
+ acc
+ } else {
+ count_divisions(base, n / base, acc + 1)
+ }
+}
+
+// SAMPLERS:
+
+/// Create a constant sampler that always returns the same value
+pub fn constant(x: a) -> Sampler