From f6a8c0cdacd78983dd7ce5b04f07cba7613cec52 Mon Sep 17 00:00:00 2001
From: Minyong Li <ml10g20@soton.ac.uk>
Date: Tue, 15 Jun 2021 19:55:54 +0100
Subject: [PATCH] core: impl ChaChaBlockFunction{Test}

---
 .../ecs/can/core/ChaChaBlockFunction.scala    | 23 ++++++
 .../ac/soton/ecs/can/core/ColumnRound.scala   | 23 ++++++
 .../ac/soton/ecs/can/core/DiagonalRound.scala | 23 ++++++
 .../ac/soton/ecs/can/core/DoubleRound.scala   | 24 ++++++
 .../can/core/ChaChaBlockFunctionTest.scala    | 75 +++++++++++++++++++
 5 files changed, 168 insertions(+)
 create mode 100644 src/main/scala/uk/ac/soton/ecs/can/core/ChaChaBlockFunction.scala
 create mode 100644 src/main/scala/uk/ac/soton/ecs/can/core/ColumnRound.scala
 create mode 100644 src/main/scala/uk/ac/soton/ecs/can/core/DiagonalRound.scala
 create mode 100644 src/main/scala/uk/ac/soton/ecs/can/core/DoubleRound.scala
 create mode 100644 src/test/scala/uk/ac/soton/ecs/can/core/ChaChaBlockFunctionTest.scala

diff --git a/src/main/scala/uk/ac/soton/ecs/can/core/ChaChaBlockFunction.scala b/src/main/scala/uk/ac/soton/ecs/can/core/ChaChaBlockFunction.scala
new file mode 100644
index 0000000..e8f2afc
--- /dev/null
+++ b/src/main/scala/uk/ac/soton/ecs/can/core/ChaChaBlockFunction.scala
@@ -0,0 +1,23 @@
+package uk.ac.soton.ecs.can.core
+
+import chisel3._
+
+class ChaChaBlockFunction extends Module {
+  val io = IO(new Bundle {
+    val muxIn = Input(Bool())
+    val in = Input(Vec(16, UInt(32.W)))
+    val out = Output(Vec(16, UInt(32.W)))
+  })
+
+  val initialState = Reg(Vec(16, UInt(32.W)))
+  val doubleRound = Module(new DoubleRound(regBetweenRounds = true))
+  val doubleRoundState = Reg(Vec(16, UInt(32.W)))
+
+  initialState := io.in
+  doubleRound.io.in := Mux(io.muxIn, initialState, doubleRoundState)
+  doubleRoundState := doubleRound.io.out
+
+  val addedState = doubleRoundState.zip(initialState).map(t => t._1 + t._2)
+
+  io.out := addedState
+}
diff --git a/src/main/scala/uk/ac/soton/ecs/can/core/ColumnRound.scala b/src/main/scala/uk/ac/soton/ecs/can/core/ColumnRound.scala
new file mode 100644
index 0000000..367d125
--- /dev/null
+++ b/src/main/scala/uk/ac/soton/ecs/can/core/ColumnRound.scala
@@ -0,0 +1,23 @@
+package uk.ac.soton.ecs.can.core
+
+import chisel3._
+
+class ColumnRound extends Module {
+  val io = IO(new Bundle {
+    val in = Input(Vec(16, UInt(32.W)))
+    val out = Output(Vec(16, UInt(32.W)))
+  })
+
+  Seq(
+    Seq(0, 4, 8, 12),
+    Seq(1, 5, 9, 13),
+    Seq(2, 6, 10, 14),
+    Seq(3, 7, 11, 15)
+  ).foreach { roundWires =>
+    val quarterRound = Module(new QuarterRound)
+    roundWires.zipWithIndex.foreach { roundWire =>
+      quarterRound.io.in(roundWire._2) := io.in(roundWire._1)
+      io.out(roundWire._1) := quarterRound.io.out(roundWire._2)
+    }
+  }
+}
diff --git a/src/main/scala/uk/ac/soton/ecs/can/core/DiagonalRound.scala b/src/main/scala/uk/ac/soton/ecs/can/core/DiagonalRound.scala
new file mode 100644
index 0000000..8e93499
--- /dev/null
+++ b/src/main/scala/uk/ac/soton/ecs/can/core/DiagonalRound.scala
@@ -0,0 +1,23 @@
+package uk.ac.soton.ecs.can.core
+
+import chisel3._
+
+class DiagonalRound extends Module {
+  val io = IO(new Bundle {
+    val in = Input(Vec(16, UInt(32.W)))
+    val out = Output(Vec(16, UInt(32.W)))
+  })
+
+  Seq(
+    Seq(0, 5, 10, 15),
+    Seq(1, 6, 11, 12),
+    Seq(2, 7, 8, 13),
+    Seq(3, 4, 9, 14)
+  ).foreach { roundWires =>
+    val quarterRound = Module(new QuarterRound)
+    roundWires.zipWithIndex.foreach { roundWire =>
+      quarterRound.io.in(roundWire._2) := io.in(roundWire._1)
+      io.out(roundWire._1) := quarterRound.io.out(roundWire._2)
+    }
+  }
+}
diff --git a/src/main/scala/uk/ac/soton/ecs/can/core/DoubleRound.scala b/src/main/scala/uk/ac/soton/ecs/can/core/DoubleRound.scala
new file mode 100644
index 0000000..1639139
--- /dev/null
+++ b/src/main/scala/uk/ac/soton/ecs/can/core/DoubleRound.scala
@@ -0,0 +1,24 @@
+package uk.ac.soton.ecs.can.core
+
+import chisel3._
+
+class DoubleRound(regBetweenRounds: Boolean) extends Module {
+  val io = IO(new Bundle {
+    val in = Input(Vec(16, UInt(32.W)))
+    val out = Output(Vec(16, UInt(32.W)))
+  })
+
+  val betweenRounds =
+    if (regBetweenRounds)
+      Reg(Vec(16, UInt(32.W)))
+    else
+      Wire(Vec(16, UInt(32.W)))
+
+  val columnRound = Module(new ColumnRound)
+  val diagonalRound = Module(new DiagonalRound)
+
+  columnRound.io.in := io.in
+  betweenRounds := columnRound.io.out
+  diagonalRound.io.in := betweenRounds
+  io.out := diagonalRound.io.out
+}
diff --git a/src/test/scala/uk/ac/soton/ecs/can/core/ChaChaBlockFunctionTest.scala b/src/test/scala/uk/ac/soton/ecs/can/core/ChaChaBlockFunctionTest.scala
new file mode 100644
index 0000000..9c7dc83
--- /dev/null
+++ b/src/test/scala/uk/ac/soton/ecs/can/core/ChaChaBlockFunctionTest.scala
@@ -0,0 +1,75 @@
+package uk.ac.soton.ecs.can.core
+
+import org.scalatest._
+import chiseltest._
+import chisel3._
+
+class ChaChaBlockFunctionTest extends FlatSpec with ChiselScalatestTester {
+
+  private val rfc8439232TestVectorIn = Seq(
+    "h61707865".U(32.W),
+    "h3320646e".U(32.W),
+    "h79622d32".U(32.W),
+    "h6b206574".U(32.W),
+    "h03020100".U(32.W),
+    "h07060504".U(32.W),
+    "h0b0a0908".U(32.W),
+    "h0f0e0d0c".U(32.W),
+    "h13121110".U(32.W),
+    "h17161514".U(32.W),
+    "h1b1a1918".U(32.W),
+    "h1f1e1d1c".U(32.W),
+    "h00000001".U(32.W),
+    "h09000000".U(32.W),
+    "h4a000000".U(32.W),
+    "h00000000".U(32.W)
+  )
+  private val rfc8439232TestVectorOut = Seq(
+    "he4e7f110".U(32.W),
+    "h15593bd1".U(32.W),
+    "h1fdd0f50".U(32.W),
+    "hc47120a3".U(32.W),
+    "hc7f4d1c7".U(32.W),
+    "h0368c033".U(32.W),
+    "h9aaa2204".U(32.W),
+    "h4e6cd4c3".U(32.W),
+    "h466482d2".U(32.W),
+    "h09aa9f07".U(32.W),
+    "h05d7c214".U(32.W),
+    "ha2028bd9".U(32.W),
+    "hd19c12b5".U(32.W),
+    "hb94e16de".U(32.W),
+    "he883d0cb".U(32.W),
+    "h4e3c50a2".U(32.W)
+  )
+
+  it should "compute RFC8439 2.3.2 test vector correctly" in {
+    test(new ChaChaBlockFunction) { c =>
+      c.io.in.zip(rfc8439232TestVectorIn).foreach { t =>
+        t._1.poke(t._2)
+      }
+
+      // Shift inputs into the initial state register
+      c.clock.step()
+
+      // Select the initial state register as the input to the 2-round circuit
+      c.io.muxIn.poke(true.B)
+
+      // Shift the 2-rounded state to the round register
+      c.clock.step(2)
+
+      // Select the round register as the input to the 2-round circuit
+      c.io.muxIn.poke(false.B)
+
+      // Depending on the ChaCha variant and the pipeline configuration, wait
+      // for the correct time for the correct result. Note that one 2-round has
+      // been processed in the above steps.
+      c.clock.step(19)
+
+      c.io.out.zip(rfc8439232TestVectorOut).foreach { t =>
+        t._1.expect(t._2)
+      }
+    }
+  }
+
+}
-- 
GitLab