Add new poly1305 stage

I highly doubt this will pass timing... need to make a test harness to synthesize
This commit is contained in:
2026-07-12 22:13:53 -07:00
parent 9b40c88673
commit cedec1ed1f
9 changed files with 1008 additions and 1 deletions

View File

@@ -0,0 +1,26 @@
# Requirements
* 2 Gbps operation
* Handles both encrypt and decrypt
At reasonable FPGA speed of 250MHz, 2 Gbps requires a minimum width of 8 bits.
32 bits is a reasonable data width that would be common to see, and lets us
have more breathing room while still maintaining line rate.
Module inputs and outputs
* clk
* rst
* data_in [31:0]
* data_valid
* data_ready
* data_last
* r [127:0]
* s [127:0]
* mac [127:0]
* mac_valid
There is no output backpressure. since the result is just a single 128 bit number,
we don't need to have a ready signal. if you want to add backpressure, add a register
slice on the output outside of this module.

View File

@@ -0,0 +1,102 @@
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/29.3.0 Chrome/140.0.7339.249 Electron/38.7.2 Safari/537.36" version="29.3.0">
<diagram name="Page-1" id="k3McRs0H2XJFCpbK3g7K">
<mxGraphModel dx="1008" dy="674" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="850" pageHeight="1100" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="EpKCKhKhuYmIKFkPyJMO-6" edge="1" parent="1" source="EpKCKhKhuYmIKFkPyJMO-1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="EpKCKhKhuYmIKFkPyJMO-5">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-24" edge="1" parent="1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" target="EpKCKhKhuYmIKFkPyJMO-1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="79.99999999999989" y="260.0000000000001" as="sourcePoint" />
</mxGeometry>
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-25" connectable="0" parent="EpKCKhKhuYmIKFkPyJMO-24" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="din[31:0]" vertex="1">
<mxGeometry relative="1" x="-0.8485" as="geometry">
<mxPoint x="-33" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-1" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="32 -&amp;gt; 128&amp;nbsp;&lt;div&gt;width convert&lt;/div&gt;" vertex="1">
<mxGeometry height="40" width="120" x="120" y="240" as="geometry" />
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-3" parent="1" style="rounded=0;whiteSpace=wrap;html=1;" value="h [129:0]" vertex="1">
<mxGeometry height="40" width="80" x="360" y="240" as="geometry" />
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-11" edge="1" parent="1" source="EpKCKhKhuYmIKFkPyJMO-5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" target="EpKCKhKhuYmIKFkPyJMO-8">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-5" parent="1" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" value="+" vertex="1">
<mxGeometry height="40" width="40" x="280" y="240" as="geometry" />
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-7" edge="1" parent="1" source="EpKCKhKhuYmIKFkPyJMO-3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1.046;entryY=0.5;entryDx=0;entryDy=0;entryPerimeter=0;" target="EpKCKhKhuYmIKFkPyJMO-5">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-14" edge="1" parent="1" source="EpKCKhKhuYmIKFkPyJMO-8" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="EpKCKhKhuYmIKFkPyJMO-13">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-8" parent="1" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" value="*" vertex="1">
<mxGeometry height="40" width="40" x="280" y="320" as="geometry" />
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-10" edge="1" parent="1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="EpKCKhKhuYmIKFkPyJMO-8">
<mxGeometry relative="1" as="geometry">
<mxPoint x="80" y="340" as="sourcePoint" />
</mxGeometry>
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-22" connectable="0" parent="EpKCKhKhuYmIKFkPyJMO-10" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="r [127:0]" vertex="1">
<mxGeometry relative="1" x="-0.8764" y="-1" as="geometry">
<mxPoint x="-42" y="-1" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-15" edge="1" parent="1" source="EpKCKhKhuYmIKFkPyJMO-13" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" target="EpKCKhKhuYmIKFkPyJMO-3">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="460" y="340" />
<mxPoint x="460" y="260" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-19" edge="1" parent="1" source="EpKCKhKhuYmIKFkPyJMO-13" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="EpKCKhKhuYmIKFkPyJMO-16">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="460" y="340" />
<mxPoint x="460" y="260" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-13" parent="1" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" value="%" vertex="1">
<mxGeometry height="40" width="40" x="380" y="320" as="geometry" />
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-21" edge="1" parent="1" source="EpKCKhKhuYmIKFkPyJMO-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="EpKCKhKhuYmIKFkPyJMO-20">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-16" parent="1" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" value="+" vertex="1">
<mxGeometry height="40" width="40" x="480" y="240" as="geometry" />
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-18" edge="1" parent="1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" target="EpKCKhKhuYmIKFkPyJMO-16">
<mxGeometry relative="1" as="geometry">
<mxPoint x="80" y="420" as="sourcePoint" />
</mxGeometry>
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-23" connectable="0" parent="EpKCKhKhuYmIKFkPyJMO-18" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="s [127:0]" vertex="1">
<mxGeometry relative="1" x="-0.975" y="1" as="geometry">
<mxPoint x="-37" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-26" edge="1" parent="1" source="EpKCKhKhuYmIKFkPyJMO-20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;">
<mxGeometry relative="1" as="geometry">
<mxPoint x="640" y="260" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-27" connectable="0" parent="EpKCKhKhuYmIKFkPyJMO-26" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="mac [127:0]" vertex="1">
<mxGeometry relative="1" x="0.7484" y="1" as="geometry">
<mxPoint x="35" y="1" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="EpKCKhKhuYmIKFkPyJMO-20" parent="1" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" value="%" vertex="1">
<mxGeometry height="40" width="40" x="560" y="240" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@@ -22,4 +22,16 @@ tests:
modules:
- "poly1305_stage"
sources: sources.list
waves: True
- name: "poly1305_width_convert"
toplevel: "poly1305_width_convert"
modules:
- "poly1305_width_convert"
sources: sources.list
waves: True
- name: "poly1305_ll_stage"
toplevel: "poly1305_ll_stage"
modules:
- "poly1305_ll_stage"
sources: sources.list
waves: True

View File

@@ -0,0 +1,72 @@
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import Timer, RisingEdge, FallingEdge
from cocotb.handle import Immediate
import random
from array import array
CLK_PERIOD = 5
@cocotb.test
async def test_sanity(dut):
data_bytes = b"Cryptographic Forum Research Group"
countm1 = [3 for _ in range(len(data_bytes)//4)]
if len(data_bytes) % 4:
countm1 += [len(data_bytes) % 4 -1]
print(len(data_bytes) % 4)
print(len(data_bytes))
print(countm1)
data_bytes += (len(data_bytes) - (len(data_bytes) //4 ) * 4) * b'\x00'
data_in = array("I", data_bytes).tolist()
print(data_in)
async def input_data():
for count, word in zip(countm1, data_in[:-1]):
dut.i_data.value = word
dut.i_countm1.value = count
dut.i_valid.value = 1
dut.i_last.value = 0
await RisingEdge(dut.i_clk)
while (not dut.o_ready.value):
await RisingEdge(dut.i_clk)
dut.i_data.value = data_in[-1]
dut.i_countm1.value = countm1[-1]
dut.i_valid.value = 1
dut.i_last.value = 1
await RisingEdge(dut.i_clk)
while (not dut.o_ready.value):
await RisingEdge(dut.i_clk)
dut.i_valid.value = 0
dut.i_last.value = 0
cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start())
dut.i_rst.value = Immediate(0)
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_rst.value = 1
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_rst.value = 0
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_r.value = 0x806d5400e52447c036d555408bed685
dut.i_s.value = 0x1bf54941aff6bf4afdb20dfb8a800301
cocotb.start_soon(input_data())
await Timer(1, "us")

View File

@@ -0,0 +1,480 @@
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import Timer, RisingEdge, FallingEdge
from cocotb.handle import Immediate
import math
import random
CLK_PERIOD = 5
@cocotb.test
async def test_sanity(dut):
data_in = [random.randint(0, 2**32-1) for _ in range(32)]
async def input_data():
for word in data_in[:-1]:
dut.i_data.value = word
dut.i_valid.value = 1
dut.i_last.value = 0
await RisingEdge(dut.i_clk)
while (not dut.o_ready.value):
await RisingEdge(dut.i_clk)
dut.i_data.value = data_in[-1]
dut.i_valid.value = 1
dut.i_last.value = 1
await RisingEdge(dut.i_clk)
while (not dut.o_ready.value):
await RisingEdge(dut.i_clk)
dut.i_valid.value = 0
dut.i_last.value = 0
data_out = []
async def output_data():
while True:
if (dut.o_valid.value):
data_out.append(int(dut.o_data.value))
await RisingEdge(dut.i_clk)
cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start())
dut.i_rst.value = Immediate(0)
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_rst.value = 1
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_rst.value = 0
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_ready.value = 1
cocotb.start_soon(input_data())
cocotb.start_soon(output_data())
await RisingEdge(dut.o_last)
await RisingEdge(dut.i_clk)
expected_data_out = []
for i in range(math.ceil(len(data_in)/4)):
vals = data_in[i*4:(i+1)*4]
converted = 0
for i, val in enumerate(vals):
converted |= val << (32*i)
expected_data_out.append(converted)
assert data_out == expected_data_out
@cocotb.test
async def test_incomplete_last(dut):
data_in = [random.randint(0, 2**32-1) for _ in range(30)]
async def input_data():
for word in data_in[:-1]:
dut.i_data.value = word
dut.i_valid.value = 1
dut.i_last.value = 0
await RisingEdge(dut.i_clk)
while (not dut.o_ready.value):
await RisingEdge(dut.i_clk)
dut.i_data.value = data_in[-1]
dut.i_valid.value = 1
dut.i_last.value = 1
await RisingEdge(dut.i_clk)
while (not dut.o_ready.value):
await RisingEdge(dut.i_clk)
dut.i_valid.value = 0
dut.i_last.value = 0
data_out = []
async def output_data():
while True:
if (dut.o_valid.value):
data_out.append(int(dut.o_data.value))
await RisingEdge(dut.i_clk)
cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start())
dut.i_rst.value = Immediate(0)
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_rst.value = 1
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_rst.value = 0
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_ready.value = 1
cocotb.start_soon(input_data())
cocotb.start_soon(output_data())
await RisingEdge(dut.o_last)
await RisingEdge(dut.i_clk)
expected_data_out = []
for i in range(math.ceil(len(data_in)/4)):
vals = data_in[i*4:(i+1)*4]
converted = 0
for i, val in enumerate(vals):
converted |= val << (32*i)
expected_data_out.append(converted)
assert data_out == expected_data_out
@cocotb.test
async def test_output_backpressure(dut):
data_in = [random.randint(0, 2**32-1) for _ in range(32)]
async def input_data():
for word in data_in[:-1]:
dut.i_data.value = word
dut.i_valid.value = 1
dut.i_last.value = 0
await RisingEdge(dut.i_clk)
while (not dut.o_ready.value):
await RisingEdge(dut.i_clk)
dut.i_data.value = data_in[-1]
dut.i_valid.value = 1
dut.i_last.value = 1
await RisingEdge(dut.i_clk)
while (not dut.o_ready.value):
await RisingEdge(dut.i_clk)
dut.i_valid.value = 0
dut.i_last.value = 0
data_out = []
async def output_data():
while True:
if (dut.o_valid.value and dut.i_ready.value):
data_out.append(int(dut.o_data.value))
await RisingEdge(dut.i_clk)
cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start())
dut.i_rst.value = Immediate(0)
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_rst.value = 1
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_rst.value = 0
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
async def output_backpressure():
while True:
await RisingEdge(dut.i_clk)
dut.i_ready.value = random.randint(0, 100) < 75
cocotb.start_soon(output_backpressure())
cocotb.start_soon(input_data())
cocotb.start_soon(output_data())
while True:
await RisingEdge(dut.i_clk)
if dut.o_last.value and dut.i_ready.value:
break
await RisingEdge(dut.i_clk)
expected_data_out = []
for i in range(math.ceil(len(data_in)/4)):
vals = data_in[i*4:(i+1)*4]
converted = 0
for i, val in enumerate(vals):
converted |= val << (32*i)
expected_data_out.append(converted)
if not data_out == expected_data_out:
print(data_out)
print(expected_data_out)
assert data_out == expected_data_out
@cocotb.test
async def test_output_backpressure_nonfull(dut):
data_in = [random.randint(0, 2**32-1) for _ in range(30)]
async def input_data():
for word in data_in[:-1]:
dut.i_data.value = word
dut.i_valid.value = 1
dut.i_last.value = 0
await RisingEdge(dut.i_clk)
while (not dut.o_ready.value):
await RisingEdge(dut.i_clk)
dut.i_data.value = data_in[-1]
dut.i_valid.value = 1
dut.i_last.value = 1
await RisingEdge(dut.i_clk)
while (not dut.o_ready.value):
await RisingEdge(dut.i_clk)
dut.i_valid.value = 0
dut.i_last.value = 0
data_out = []
async def output_data():
while True:
if (dut.o_valid.value and dut.i_ready.value):
data_out.append(int(dut.o_data.value))
await RisingEdge(dut.i_clk)
cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start())
dut.i_rst.value = Immediate(0)
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_rst.value = 1
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_rst.value = 0
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
async def output_backpressure():
while True:
await RisingEdge(dut.i_clk)
dut.i_ready.value = random.randint(0, 100) < 75
cocotb.start_soon(output_backpressure())
cocotb.start_soon(input_data())
cocotb.start_soon(output_data())
while True:
await RisingEdge(dut.i_clk)
if dut.o_last.value and dut.i_ready.value:
break
await RisingEdge(dut.i_clk)
expected_data_out = []
for i in range(math.ceil(len(data_in)/4)):
vals = data_in[i*4:(i+1)*4]
converted = 0
for i, val in enumerate(vals):
converted |= val << (32*i)
expected_data_out.append(converted)
if not data_out == expected_data_out:
print(data_out)
print(expected_data_out)
assert data_out == expected_data_out
@cocotb.test
async def test_input_nonvalid(dut):
data_in = [random.randint(0, 2**32-1) for _ in range(32)]
async def input_data():
for word in data_in[:-1]:
dut.i_data.value = word
dut.i_valid.value = 1
dut.i_last.value = 0
await RisingEdge(dut.i_clk)
while (not dut.o_ready.value):
await RisingEdge(dut.i_clk)
if random.randint(0, 10) > 7:
dut.i_valid.value = 0
await RisingEdge(dut.i_clk)
dut.i_data.value = data_in[-1]
dut.i_valid.value = 1
dut.i_last.value = 1
await RisingEdge(dut.i_clk)
while (not dut.o_ready.value):
await RisingEdge(dut.i_clk)
dut.i_valid.value = 0
dut.i_last.value = 0
data_out = []
async def output_data():
while True:
if (dut.o_valid.value and dut.i_ready.value):
data_out.append(int(dut.o_data.value))
await RisingEdge(dut.i_clk)
cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start())
dut.i_rst.value = Immediate(0)
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_rst.value = 1
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_rst.value = 0
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_ready.value = 1
cocotb.start_soon(input_data())
cocotb.start_soon(output_data())
while True:
await RisingEdge(dut.i_clk)
if dut.o_last.value and dut.i_ready.value:
break
await RisingEdge(dut.i_clk)
expected_data_out = []
for i in range(math.ceil(len(data_in)/4)):
vals = data_in[i*4:(i+1)*4]
converted = 0
for i, val in enumerate(vals):
converted |= val << (32*i)
expected_data_out.append(converted)
if not data_out == expected_data_out:
print(data_out)
print(expected_data_out)
assert data_out == expected_data_out
@cocotb.test
async def test_input_nonvalid_output_nonready(dut):
data_in = [random.randint(0, 2**32-1) for _ in range(30)]
async def input_data():
for word in data_in[:-1]:
dut.i_data.value = word
dut.i_valid.value = 1
dut.i_last.value = 0
await RisingEdge(dut.i_clk)
while (not dut.o_ready.value):
await RisingEdge(dut.i_clk)
if random.randint(0, 10) > 7:
dut.i_valid.value = 0
await RisingEdge(dut.i_clk)
dut.i_data.value = data_in[-1]
dut.i_valid.value = 1
dut.i_last.value = 1
await RisingEdge(dut.i_clk)
while (not dut.o_ready.value):
await RisingEdge(dut.i_clk)
dut.i_valid.value = 0
dut.i_last.value = 0
data_out = []
async def output_data():
while True:
if (dut.o_valid.value and dut.i_ready.value):
data_out.append(int(dut.o_data.value))
await RisingEdge(dut.i_clk)
cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start())
dut.i_rst.value = Immediate(0)
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_rst.value = 1
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
dut.i_rst.value = 0
await RisingEdge(dut.i_clk)
await RisingEdge(dut.i_clk)
async def output_backpressure():
while True:
await RisingEdge(dut.i_clk)
dut.i_ready.value = random.randint(0, 100) < 75
cocotb.start_soon(output_backpressure())
cocotb.start_soon(input_data())
cocotb.start_soon(output_data())
while True:
await RisingEdge(dut.i_clk)
if dut.o_last.value and dut.i_ready.value:
break
await RisingEdge(dut.i_clk)
expected_data_out = []
for i in range(math.ceil(len(data_in)/4)):
vals = data_in[i*4:(i+1)*4]
converted = 0
for i, val in enumerate(vals):
converted |= val << (32*i)
expected_data_out.append(converted)
if not data_out == expected_data_out:
print(data_out)
print(expected_data_out)
assert data_out == expected_data_out

View File

@@ -1,3 +1,5 @@
// FPGA Friendly modular multiplication. takes ~6 cycles
module poly1305_friendly_modular_mult #(
parameter DATA_WIDTH = 130,
parameter ACC_WIDTH = 130

View File

@@ -0,0 +1,231 @@
// Low latency poly1305 core
//
// Target 2 cycles per 128 bit block
module poly1305_ll_stage (
input logic i_clk,
input logic i_rst,
input logic i_valid,
input logic [1:0] i_countm1,
output logic o_ready,
input logic [31:0] i_data,
input logic i_last,
input logic [127:0] i_r,
input logic [127:0] i_s,
output logic o_valid,
output logic [127:0] o_result
);
localparam [129:0] PRIME = (1 << 130) - 5;
logic upconvert_ready;
logic upconvert_valid;
logic upconvert_last;
logic [127:0] upconvert_data;
logic [3:0] upconvert_countm1;
poly1305_width_convert u_width_convert(
.i_clk (i_clk),
.i_rst (i_rst),
.i_valid (i_valid),
.i_countm1 (i_countm1),
.o_ready (o_ready),
.i_data (i_data),
.i_last (i_last),
.o_valid (upconvert_valid),
.o_countm1 (upconvert_countm1),
.i_ready (upconvert_ready),
.o_data (upconvert_data),
.o_last (upconvert_last)
);
logic [127:0] r_reg, s_reg, s_reg_2;
logic [127:0] r_reg_next, s_reg_next, s_reg_2_next;;
enum logic [2:0] {IDLE, SUM, MULT, MODULO_1, MODULO_2} state, state_next;
enum logic [1:0] {OUTPUT_IDLE, OUTPUT_ADD, OUTPUT_OUT} output_state, output_state_next;
logic [129:0] h, h_next;
logic [130:0] data_1extend;
logic [130:0] sum, sum_next;
logic [258:0] product, product_next;
logic [131:0] mod1;
logic [131:0] mod2_upper, mod2_upper_next;
logic [129:0] mod2_lower, mod2_lower_next;
logic [131:0] mod2;
logic [131:0] mod3;
logic [130:0] final_sum, final_sum_next;
logic [130:0] final_mod;
logic start_output;
logic last_flag, last_flag_next;
always_ff @(posedge i_clk) begin
if (i_rst) begin
r_reg <= '0;
s_reg <= '0;
s_reg_2 <= '0;
last_flag <= '0;
state <= IDLE;
output_state <= OUTPUT_IDLE;
end else begin
r_reg <= r_reg_next;
s_reg <= s_reg_next;
s_reg_2 <= s_reg_2_next;
mod2_upper <= mod2_upper_next;
mod2_lower <= mod2_lower_next;
h <= h_next;
sum <= sum_next;
product <= product_next;
last_flag <= last_flag_next;
state <= state_next;
output_state <= output_state_next;
final_sum <= final_sum_next;
end
end
always_comb begin
h_next = h;
sum_next = '0;
product_next = '0;
r_reg_next = r_reg;
s_reg_next = s_reg;
upconvert_ready = '0;
last_flag_next = last_flag;
state_next = state;
mod1 = '0;
mod2 = '0;
mod2_upper_next = '0;
mod2_lower_next = '0;
mod3 = '0;
data_1extend = '0;
start_output = '0;
case (state)
IDLE: begin
upconvert_ready = '1;
if (upconvert_valid) begin
data_1extend = {3'b0, upconvert_data} | (131'b1 << (8*(1+upconvert_countm1)));
sum_next = data_1extend;
state_next = MULT;
r_reg_next = i_r;
s_reg_next = i_s;
end
end
SUM: begin
last_flag_next = upconvert_last;
upconvert_ready = '1;
data_1extend = {3'b0, upconvert_data} | (131'b1 << (8*(1+upconvert_countm1)));
sum_next = h + data_1extend;
state_next = MULT;
end
MULT: begin
product_next = sum * r_reg;
state_next = MODULO_1;
end
MODULO_1: begin
mod1 = (product[258:130] * 5) + {2'b0, product[129:0]};
mod2_upper_next = mod1[131:130] * 5;
mod2_lower_next = mod1[129:0];
state_next = MODULO_2;
end
MODULO_2: begin
mod2 = mod2_upper + {2'b0, mod2_lower};
mod3 = (mod2[131:130] * 5) + {2'b0, mod2[129:0]};
if (mod3[129:0] > PRIME) begin
h_next = mod3[129:0] - PRIME;
end else begin
h_next = mod3[129:0];
end
if (last_flag) begin
state_next = IDLE;
last_flag_next = '0;
s_reg_2_next = s_reg;
start_output = '1;
end else begin
state_next = SUM;
end
end
default: begin
end
endcase
output_state_next = output_state;
case (output_state)
OUTPUT_IDLE: begin
if (start_output) begin
output_state_next = OUTPUT_ADD;
end
end
OUTPUT_ADD: begin
final_sum_next = h + {3'b0, s_reg_2};
output_state_next = OUTPUT_OUT;
end
OUTPUT_OUT: begin
if (final_sum > {1'b0, PRIME}) begin
final_mod = final_sum - PRIME;
end else begin
final_mod = final_sum;
end
o_valid = '1;
o_result = final_mod[127:0];
output_state_next = OUTPUT_IDLE;
end
default: begin
end
endcase
end
endmodule

View File

@@ -0,0 +1,79 @@
module poly1305_width_convert(
input logic i_clk,
input logic i_rst,
input logic i_valid,
input logic [1:0] i_countm1,
output logic o_ready,
input logic [31:0] i_data,
input logic i_last,
output logic o_valid,
output logic [3:0] o_countm1,
input logic i_ready,
output logic [127:0] o_data,
output logic o_last
);
logic [95:0] width_convert_save, width_convert_save_next;
logic [1:0] width_convert_count, width_convert_count_next;
always_ff @(posedge i_clk) begin
if (i_rst) begin
width_convert_save <= '0;
width_convert_count <= '0;
end else begin
width_convert_count <= width_convert_count_next;
width_convert_save <= width_convert_save_next;
end
end
always_comb begin
width_convert_save_next = width_convert_save;
width_convert_count_next = width_convert_count;
o_valid = '0;
o_ready = '0;
o_last = '0;
o_countm1 = '1;
if (width_convert_count < 3) begin
o_data = {32'b0, width_convert_save};
o_data[32*width_convert_count +: 32] = i_data;
if (i_last && i_valid) begin
o_ready = i_ready;
o_valid = '1;
o_last = '1;
o_countm1 = width_convert_count*4 + {2'b0, i_countm1};
if (i_ready) begin
width_convert_count_next = '0;
width_convert_save_next = '0;
end
end else begin
width_convert_save_next[32*width_convert_count +: 32] = i_data;
if (i_valid) begin
o_ready = '1;
width_convert_count_next = width_convert_count + 2'd1;
end
end
end else begin
o_ready = i_ready;
o_valid = i_valid;
o_data = {i_data, width_convert_save};
o_last = i_last;
o_countm1 = 4'd12 + {2'b0, i_countm1};
if (i_valid && o_ready) begin
width_convert_count_next = '0;
width_convert_save_next = '0;
end
end
end
endmodule

View File

@@ -6,4 +6,7 @@ chacha20_pipelined_block.sv
poly1305_core.sv
poly1305_friendly_modulo.sv
poly1305_friendly_modular_mult.sv
poly1305_stage.sv
poly1305_stage.sv
poly1305_width_convert.sv
poly1305_ll_stage.sv