diff --git a/src/main/scala/uk/ac/soton/ecs/can/core/BlockInitializer.scala b/src/main/scala/uk/ac/soton/ecs/can/core/BlockInitializer.scala
new file mode 100644
index 0000000000000000000000000000000000000000..255f000a5a5f48fad367b3fa79701b46e80f3028
--- /dev/null
+++ b/src/main/scala/uk/ac/soton/ecs/can/core/BlockInitializer.scala
@@ -0,0 +1,41 @@
+package uk.ac.soton.ecs.can.core
+
+import chisel3._
+import chisel3.util.random.GaloisLFSR
+
+class BlockInitializer extends MultiIOModule {
+  val fillConstants = IO(Input(Bool()))
+  val generateKey = IO(Input(Bool()))
+  val incrementBlockCount = IO(Input(Bool()))
+  val generateNonce = IO(Input(Bool()))
+  val in = IO(Input(Vec(16, UInt(32.W))))
+  val out = IO(Output(Vec(16, UInt(32.W))))
+
+  private val constants = VecInit(
+    "h61707865".U(32.W),
+    "h3320646e".U(32.W),
+    "h79622d32".U(32.W),
+    "h6b206574".U(32.W)
+  )
+  private val randomKey = (0 until 16).map(_ => GaloisLFSR.maxPeriod(32))
+  private val incrementedBlockCount = in(12) + 1.U(32.W)
+  private val randomNonce = (0 until 3).map(_ => GaloisLFSR.maxPeriod(32))
+
+  private val io = in.zip(out)
+
+  io.take(4).zip(constants).foreach { case ((i, o), c) =>
+    o := Mux(fillConstants, c, i)
+  }
+
+  io.slice(4, 12).zip(randomKey).foreach { case ((i, o), k) =>
+    o := Mux(generateKey, k, i)
+  }
+
+  io(12) match {
+    case (i, o) => o := Mux(incrementBlockCount, incrementedBlockCount, i)
+  }
+
+  io.takeRight(3).zip(randomNonce).foreach { case ((i, o), n) =>
+    o := Mux(generateNonce, n, i)
+  }
+}
diff --git a/src/test/scala/uk/ac/soton/ecs/can/core/BlockInitializerTest.scala b/src/test/scala/uk/ac/soton/ecs/can/core/BlockInitializerTest.scala
new file mode 100644
index 0000000000000000000000000000000000000000..d83bf991e403182c85fbebc2b5486c755c70bde0
--- /dev/null
+++ b/src/test/scala/uk/ac/soton/ecs/can/core/BlockInitializerTest.scala
@@ -0,0 +1,78 @@
+package uk.ac.soton.ecs.can.core
+
+import org.scalatest._
+import chiseltest._
+import chisel3._
+
+class BlockInitializerTest extends FlatSpec with ChiselScalatestTester {
+  private val input = Seq.fill(16)(0.U(32.W))
+
+  behavior of "The Block Initializer"
+
+  it should "fill the ChaCha constant when requested" in {
+    test(new BlockInitializer) { c =>
+      c.in.zip(input).foreach { case (p, n) => p.poke(n) }
+
+      c.fillConstants.poke(true.B)
+      c.out(0).expect("h61707865".U(32.W))
+      c.out(1).expect("h3320646e".U(32.W))
+      c.out(2).expect("h79622d32".U(32.W))
+      c.out(3).expect("h6b206574".U(32.W))
+      c.out.takeRight(12).foreach(_.expect(0.U(32.W)))
+
+      c.fillConstants.poke(false.B)
+      c.out.foreach(_.expect(0.U(32.W)))
+    }
+  }
+
+  it should "randomly generate some keys when requested" in {
+    test(new BlockInitializer) { c =>
+      c.in.zip(input).foreach { case (p, n) => p.poke(n) }
+
+      c.generateKey.poke(true.B)
+      (0 until 10).foreach { _ =>
+        c.out.take(4).foreach(_.expect(0.U(32.W)))
+        c.out.slice(4, 12).foreach(o => assert(o.peek().litValue() != 0))
+        c.out.takeRight(4).foreach(_.expect(0.U(32.W)))
+        c.clock.step()
+      }
+
+      c.generateKey.poke(false.B)
+      c.out.foreach(_.expect(0.U(32.W)))
+    }
+  }
+
+  it should "increment the block count when requested" in {
+    test(new BlockInitializer) { c =>
+      c.in.zip(input).foreach { case (p, n) => p.poke(n) }
+
+      c.incrementBlockCount.poke(true.B)
+      (0 until 10).foreach { i =>
+        c.in(12).poke(i.U(32.W))
+        c.out(12).expect((i + 1).U(32.W))
+      }
+
+      c.in(12).poke(0.U(32.W))
+
+      c.incrementBlockCount.poke(false.B)
+      c.out.foreach(_.expect(0.U(32.W)))
+    }
+  }
+
+  it should "randomly generate some nonce when requested" in {
+    test(new BlockInitializer) { c =>
+      c.in.zip(input).foreach { case (p, n) => p.poke(n) }
+
+      c.generateNonce.poke(true.B)
+      (0 until 10).foreach { _ =>
+        c.out.take(9).foreach(_.expect(0.U(32.W)))
+        c.out.takeRight(3).foreach(o => assert(o.peek().litValue() != 0))
+        c.clock.step()
+      }
+
+      c.generateNonce.poke(false.B)
+      c.out.foreach(_.expect(0.U(32.W)))
+    }
+  }
+
+}