Compare commits

...

10 Commits

Author SHA1 Message Date
f5e7b843b1 Reduce number of flops in chacha from 8 to 2 2026-07-27 20:19:21 -07:00
89a8087003 Add timing test 2026-07-27 19:38:54 -07:00
885e1307f5 Fix some length issues 2026-07-27 09:47:26 -07:00
4f7ade81d0 braindump 2026-07-26 17:35:24 -07:00
cedec1ed1f Add new poly1305 stage
I highly doubt this will pass timing... need to make a test harness to synthesize
2026-07-12 22:13:53 -07:00
9b40c88673 Whatever I was working on 2026-01-18 21:58:56 -08:00
Byron Lathi
d5035c6c81 Add poly1305 stage 2025-11-01 20:53:02 -07:00
Byron Lathi
2102cb41f4 Fix bug where top 2 bits were getting lost in the modulo 2025-10-30 22:34:52 -07:00
Byron Lathi
d6a062baa0 Make modular mult work 2025-10-28 21:59:28 -07:00
Byron Lathi
ad257f4220 Add mult, but it doesn't quite work 2025-10-28 08:27:36 -07:00
41 changed files with 3767 additions and 172 deletions

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "common/sim/sub/taxi"]
path = common/sim/sub/taxi
url = https://github.com/fpganinja/taxi.git
[submodule "common/sim/sub/fifo"]
path = common/sim/sub/fifo
url = https://github.com/olofk/fifo.git

View File

@@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<efxpt:design_db name="chacha20poly1305_timing_test" device_def="Ti375C529" version="2025.1.110" db_version="20251999" last_change_date="Mon Jul 27 19:31:51 2026" xmlns:efxpt="http://www.efinixinc.com/peri_design_db" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.efinixinc.com/peri_design_db peri_design_db.xsd ">
<efxpt:device_info>
<efxpt:iobank_info>
<efxpt:iobank name="2A" iostd="1.8 V LVCMOS" is_dyn_voltage="false" mode_sel_name="2A_MODE_SEL"/>
<efxpt:iobank name="2B" iostd="1.8 V LVCMOS" is_dyn_voltage="false" mode_sel_name="2B_MODE_SEL"/>
<efxpt:iobank name="2C" iostd="1.8 V LVCMOS" is_dyn_voltage="false" mode_sel_name="2C_MODE_SEL"/>
<efxpt:iobank name="2D" iostd="1.8 V LVCMOS" is_dyn_voltage="false" mode_sel_name="2D_MODE_SEL"/>
<efxpt:iobank name="2E" iostd="1.8 V LVCMOS" is_dyn_voltage="false" mode_sel_name="2E_MODE_SEL"/>
<efxpt:iobank name="4A_4B" iostd="1.8 V LVCMOS" is_dyn_voltage="false" mode_sel_name="4A_4B_MODE_SEL"/>
<efxpt:iobank name="4C" iostd="1.8 V LVCMOS" is_dyn_voltage="false" mode_sel_name="4C_MODE_SEL"/>
<efxpt:iobank name="4D" iostd="1.8 V LVCMOS" is_dyn_voltage="false" mode_sel_name="4D_MODE_SEL"/>
<efxpt:iobank name="BL2_BL3" iostd="3.3 V LVCMOS" is_dyn_voltage="false">
<efxpt:mode_sel_name>
<efxpt:pin_name bank_name="BL2" value="BL2_MODE_SEL"/>
<efxpt:pin_name bank_name="BL3" value="BL3_MODE_SEL"/>
</efxpt:mode_sel_name>
</efxpt:iobank>
<efxpt:iobank name="BR0" iostd="3.3 V LVCMOS" is_dyn_voltage="false" mode_sel_name="BR0_MODE_SEL"/>
<efxpt:iobank name="BR3_BR4" iostd="3.3 V LVCMOS" is_dyn_voltage="false">
<efxpt:mode_sel_name>
<efxpt:pin_name bank_name="BR3" value="BR3_MODE_SEL"/>
<efxpt:pin_name bank_name="BR4" value="BR4_MODE_SEL"/>
</efxpt:mode_sel_name>
</efxpt:iobank>
<efxpt:iobank name="TL1_TL5" iostd="3.3 V LVCMOS" is_dyn_voltage="false">
<efxpt:mode_sel_name>
<efxpt:pin_name bank_name="TL1" value="TL1_MODE_SEL"/>
<efxpt:pin_name bank_name="TL5" value="TL5_MODE_SEL"/>
</efxpt:mode_sel_name>
</efxpt:iobank>
<efxpt:iobank name="TR0" iostd="3.3 V LVCMOS" is_dyn_voltage="false" mode_sel_name="TR0_MODE_SEL"/>
<efxpt:iobank name="TR1" iostd="3.3 V LVCMOS" is_dyn_voltage="false" mode_sel_name="TR1_MODE_SEL"/>
<efxpt:iobank name="TR2" iostd="3.3 V LVCMOS" is_dyn_voltage="false" mode_sel_name="TR2_MODE_SEL"/>
</efxpt:iobank_info>
<efxpt:ctrl_info>
<efxpt:ctrl name="cfg" ctrl_def="CONFIG_CTRL0" clock_name="" is_clk_invert="false" cbsel_bus_name="cfg_CBSEL" config_ctrl_name="cfg_CONFIG" ena_capture_name="cfg_ENA" error_status_name="cfg_ERROR" um_signal_status_name="cfg_USR_STATUS" is_remote_update_enable="false" is_user_mode_enable="false">
<efxpt:gen_param>
<efxpt:param name="remote_update_retries" value="0" value_type="int"/>
</efxpt:gen_param>
</efxpt:ctrl>
</efxpt:ctrl_info>
<efxpt:seu_info>
<efxpt:seu name="seu" block_def="CONFIG_SEU0" mode="auto" ena_detect="false" wait_interval="16500000">
<efxpt:gen_pin>
<efxpt:pin name="seu_START" type_name="START" is_bus="false"/>
<efxpt:pin name="seu_INJECT_ERROR" type_name="INJECT_ERROR" is_bus="false"/>
<efxpt:pin name="seu_RST" type_name="RST" is_bus="false"/>
<efxpt:pin name="seu_CONFIG" type_name="CONFIG" is_bus="false"/>
<efxpt:pin name="seu_ERROR" type_name="ERROR" is_bus="false"/>
<efxpt:pin name="seu_DONE" type_name="DONE" is_bus="false"/>
</efxpt:gen_pin>
</efxpt:seu>
</efxpt:seu_info>
<efxpt:clkmux_info>
<efxpt:clkmux name="GCLKMUX_B" block_def="GCLKMUX_B" is_mux_bot0_dyn="false" is_mux_bot7_dyn="false">
<efxpt:gen_pin>
<efxpt:pin name="" type_name="ROUTE0" is_bus="false" is_clk="true" is_clk_invert="false"/>
<efxpt:pin name="" type_name="ROUTE1" is_bus="false" is_clk="true" is_clk_invert="false"/>
<efxpt:pin name="" type_name="ROUTE2" is_bus="false" is_clk="true" is_clk_invert="false"/>
<efxpt:pin name="" type_name="ROUTE3" is_bus="false" is_clk="true" is_clk_invert="false"/>
<efxpt:pin name="" type_name="DYN_MUX_OUT_0" is_bus="false"/>
<efxpt:pin name="" type_name="DYN_MUX_OUT_7" is_bus="false"/>
<efxpt:pin name="" type_name="DYN_MUX_SEL_0" is_bus="true"/>
<efxpt:pin name="" type_name="DYN_MUX_SEL_7" is_bus="true"/>
</efxpt:gen_pin>
</efxpt:clkmux>
<efxpt:clkmux name="GCLKMUX_L" block_def="GCLKMUX_L" is_mux_bot0_dyn="false" is_mux_bot7_dyn="false">
<efxpt:gen_pin>
<efxpt:pin name="" type_name="ROUTE0" is_bus="false" is_clk="true" is_clk_invert="false"/>
<efxpt:pin name="" type_name="ROUTE1" is_bus="false" is_clk="true" is_clk_invert="false"/>
<efxpt:pin name="" type_name="ROUTE2" is_bus="false" is_clk="true" is_clk_invert="false"/>
<efxpt:pin name="" type_name="ROUTE3" is_bus="false" is_clk="true" is_clk_invert="false"/>
<efxpt:pin name="" type_name="DYN_MUX_OUT_0" is_bus="false"/>
<efxpt:pin name="" type_name="DYN_MUX_OUT_7" is_bus="false"/>
<efxpt:pin name="" type_name="DYN_MUX_SEL_0" is_bus="true"/>
<efxpt:pin name="" type_name="DYN_MUX_SEL_7" is_bus="true"/>
</efxpt:gen_pin>
</efxpt:clkmux>
<efxpt:clkmux name="GCLKMUX_R" block_def="GCLKMUX_R" is_mux_bot0_dyn="false" is_mux_bot7_dyn="false">
<efxpt:gen_pin>
<efxpt:pin name="" type_name="ROUTE0" is_bus="false" is_clk="true" is_clk_invert="false"/>
<efxpt:pin name="" type_name="ROUTE1" is_bus="false" is_clk="true" is_clk_invert="false"/>
<efxpt:pin name="" type_name="ROUTE2" is_bus="false" is_clk="true" is_clk_invert="false"/>
<efxpt:pin name="" type_name="ROUTE3" is_bus="false" is_clk="true" is_clk_invert="false"/>
<efxpt:pin name="" type_name="DYN_MUX_OUT_0" is_bus="false"/>
<efxpt:pin name="" type_name="DYN_MUX_OUT_7" is_bus="false"/>
<efxpt:pin name="" type_name="DYN_MUX_SEL_0" is_bus="true"/>
<efxpt:pin name="" type_name="DYN_MUX_SEL_7" is_bus="true"/>
</efxpt:gen_pin>
</efxpt:clkmux>
<efxpt:clkmux name="GCLKMUX_T" block_def="GCLKMUX_T" is_mux_bot0_dyn="false" is_mux_bot7_dyn="false">
<efxpt:gen_pin>
<efxpt:pin name="" type_name="ROUTE0" is_bus="false" is_clk="true" is_clk_invert="false"/>
<efxpt:pin name="" type_name="ROUTE1" is_bus="false" is_clk="true" is_clk_invert="false"/>
<efxpt:pin name="" type_name="ROUTE2" is_bus="false" is_clk="true" is_clk_invert="false"/>
<efxpt:pin name="" type_name="ROUTE3" is_bus="false" is_clk="true" is_clk_invert="false"/>
<efxpt:pin name="" type_name="DYN_MUX_OUT_0" is_bus="false"/>
<efxpt:pin name="" type_name="DYN_MUX_OUT_7" is_bus="false"/>
<efxpt:pin name="" type_name="DYN_MUX_SEL_0" is_bus="true"/>
<efxpt:pin name="" type_name="DYN_MUX_SEL_7" is_bus="true"/>
</efxpt:gen_pin>
</efxpt:clkmux>
</efxpt:clkmux_info>
</efxpt:device_info>
<efxpt:gpio_info>
<efxpt:global_unused_config state="input with weak pullup"/>
</efxpt:gpio_info>
<efxpt:pll_info/>
<efxpt:osc_info/>
<efxpt:lvds_info/>
<efxpt:jtag_info/>
<efxpt:ddr_info/>
<efxpt:mipi_dphy_info/>
<efxpt:soc_info/>
</efxpt:design_db>

View File

@@ -0,0 +1,48 @@
module chacha20poly1305_timing_test(
input logic i_clk,
input logic i_rst,
input logic [255:0] i_key,
input logic [95:0] i_nonce,
input logic i_encrypt,
input logic [31:0] i_data,
input logic [1:0] i_countm1,
input logic i_last,
input logic i_valid,
output logic o_ready,
output logic [31:0] o_data,
output logic [1:0] o_data_countm1,
output logic o_data_last,
output logic o_data_valid,
input logic i_data_ready,
// no backpressure for the poly1305 output
output logic [127:0] o_mac,
output logic o_mac_valid
);
chacha20_poly1305_32_ll_core u_dut (
.i_clk (i_clk),
.i_rst (i_rst),
.i_key (i_key),
.i_nonce (i_nonce),
.i_encrypt (i_encrypt),
.i_data (i_data),
.i_countm1 (i_countm1),
.i_last (i_last),
.i_valid (i_valid),
.o_ready (o_ready),
.o_data (o_data),
.o_data_countm1 (o_data_countm1),
.o_data_last (o_data_last),
.o_data_valid (o_data_valid),
.i_data_ready (i_data_ready),
.o_mac (o_mac),
.o_mac_valid (o_mac_valid)
);
endmodule

View File

@@ -0,0 +1,129 @@
<?xml version="1.0" encoding="UTF-8"?>
<efx:project name="chacha20poly1305_timing_test" description="" last_change="1785208404" sw_version="2025.1.110" last_run_state="pass" last_run_flow="bitstream" config_result_in_sync="true" design_ood="sync" place_ood="sync" route_ood="sync" xmlns:efx="http://www.efinixinc.com/enf_proj" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.efinixinc.com/enf_proj enf_proj.xsd">
<efx:device_info>
<efx:family name="Titanium"/>
<efx:device name="Ti375C529"/>
<efx:timing_model name="C4"/>
</efx:device_info>
<efx:design_info def_veri_version="verilog_2k" def_vhdl_version="vhdl_2008" unified_flow="false">
<efx:top_module name="chacha20poly1305_timing_test"/>
<efx:design_file name="../src/poly1305_friendly_modulo.sv" version="default" library="default"/>
<efx:design_file name="../src/chacha20_block.sv" version="default" library="default"/>
<efx:design_file name="../src/chacha20_pipelined_block.sv" version="default" library="default"/>
<efx:design_file name="../src/poly1305_width_convert_2.sv" version="default" library="default"/>
<efx:design_file name="../src/chacha20_poly1305_32_ll_core.sv" version="default" library="default"/>
<efx:design_file name="../src/poly1305_stage.sv" version="default" library="default"/>
<efx:design_file name="../src/poly1305_friendly_modular_mult.sv" version="default" library="default"/>
<efx:design_file name="../src/poly1305_ll_stage.sv" version="default" library="default"/>
<efx:design_file name="../src/poly1305_width_convert_3.sv" version="default" library="default"/>
<efx:design_file name="../src/skidbuffer.sv" version="default" library="default"/>
<efx:design_file name="../src/poly1305_width_convert.sv" version="default" library="default"/>
<efx:design_file name="../src/chacha20_qr.sv" version="default" library="default"/>
<efx:design_file name="../src/poly1305_core.sv" version="default" library="default"/>
<efx:design_file name="../src/chacha20_pipelined_round.sv" version="default" library="default"/>
<efx:design_file name="../src/chacha20_poly1305_64.sv" version="default" library="default"/>
<efx:design_file name="../src/chacha20_poly1305_mid_fsm.sv" version="default" library="default"/>
<efx:design_file name="../src/chacha20_poly1305_input_fsm.sv" version="default" library="default"/>
<efx:design_file name="chacha20poly1305_timing_test.sv" version="default" library="default"/>
<efx:design_file name="../../common/sim/sub/fifo/rtl/verilog/fifo_fwft.v" version="default" library="default"/>
<efx:design_file name="../../common/sim/sub/fifo/rtl/verilog/xilinx_fifoe1.v" version="default" library="default"/>
<efx:design_file name="../../common/sim/sub/fifo/rtl/verilog/fifo.v" version="default" library="default"/>
<efx:design_file name="../../common/sim/sub/fifo/rtl/verilog/dual_clock_fifo.v" version="default" library="default"/>
<efx:design_file name="../../common/sim/sub/fifo/rtl/verilog/simple_dpram_sclk.v" version="default" library="default"/>
<efx:design_file name="../../common/sim/sub/fifo/rtl/verilog/fifo_fwft_adapter.v" version="default" library="default"/>
<efx:top_vhdl_arch name=""/>
</efx:design_info>
<efx:constraint_info>
<efx:sdc_file name="constraints.sdc"/>
<efx:inter_file name=""/>
</efx:constraint_info>
<efx:sim_info/>
<efx:misc_info/>
<efx:ip_info/>
<efx:synthesis tool_name="efx_map">
<efx:param name="work_dir" value="work_syn" value_type="e_string"/>
<efx:param name="write_efx_verilog" value="on" value_type="e_bool"/>
<efx:param name="allow-const-ram-index" value="0" value_type="e_option"/>
<efx:param name="blackbox-error" value="1" value_type="e_option"/>
<efx:param name="blast_const_operand_adders" value="1" value_type="e_option"/>
<efx:param name="bram_output_regs_packing" value="1" value_type="e_option"/>
<efx:param name="bram-push-tco-outreg" value="0" value_type="e_option"/>
<efx:param name="create-onehot-fsms" value="0" value_type="e_option"/>
<efx:param name="fanout-limit" value="0" value_type="e_integer"/>
<efx:param name="hdl-compile-unit" value="1" value_type="e_option"/>
<efx:param name="hdl-loop-limit" value="20000" value_type="e_integer"/>
<efx:param name="infer-clk-enable" value="3" value_type="e_option"/>
<efx:param name="infer-sync-set-reset" value="1" value_type="e_option"/>
<efx:param name="enable-mark-debug" value="1" value_type="e_option"/>
<efx:param name="max_ram" value="-1" value_type="e_integer"/>
<efx:param name="max_mult" value="-1" value_type="e_integer"/>
<efx:param name="max-bit-blast-mem-size" value="10240" value_type="e_integer"/>
<efx:param name="min-sr-fanout" value="0" value_type="e_integer"/>
<efx:param name="min-ce-fanout" value="0" value_type="e_integer"/>
<efx:param name="mode" value="speed" value_type="e_option"/>
<efx:param name="mult-auto-pipeline" value="0" value_type="e_integer"/>
<efx:param name="mult-decomp-retime" value="0" value_type="e_option"/>
<efx:param name="operator-sharing" value="0" value_type="e_option"/>
<efx:param name="optimize-adder-tree" value="0" value_type="e_option"/>
<efx:param name="optimize-zero-init-rom" value="1" value_type="e_option"/>
<efx:param name="peri-syn-instantiation" value="0" value_type="e_option"/>
<efx:param name="peri-syn-inference" value="0" value_type="e_option"/>
<efx:param name="ram-decomp-mode" value="0" value_type="e_option"/>
<efx:param name="retiming" value="1" value_type="e_option"/>
<efx:param name="seq_opt" value="1" value_type="e_option"/>
<efx:param name="seq-opt-sync-only" value="0" value_type="e_option"/>
<efx:param name="use-logic-for-small-mem" value="64" value_type="e_integer"/>
<efx:param name="use-logic-for-small-rom" value="64" value_type="e_integer"/>
<efx:param name="max_threads" value="-1" value_type="e_integer"/>
<efx:param name="dsp-input-regs-packing" value="1" value_type="e_option"/>
<efx:param name="dsp-output-regs-packing" value="1" value_type="e_option"/>
<efx:param name="dsp-mac-packing" value="1" value_type="e_option"/>
<efx:param name="insert-carry-skip" value="0" value_type="e_option"/>
<efx:param name="pack-luts-to-comb4" value="0" value_type="e_option"/>
</efx:synthesis>
<efx:place_and_route tool_name="efx_pnr">
<efx:param name="work_dir" value="work_pnr" value_type="e_string"/>
<efx:param name="verbose" value="off" value_type="e_bool"/>
<efx:param name="load_delaym" value="on" value_type="e_bool"/>
<efx:param name="optimization_level" value="NULL" value_type="e_option"/>
<efx:param name="seed" value="1" value_type="e_integer"/>
<efx:param name="placer_effort_level" value="2" value_type="e_option"/>
<efx:param name="max_threads" value="-1" value_type="e_integer"/>
<efx:param name="print_critical_path" value="10" value_type="e_integer"/>
<efx:param name="classic_flow" value="off" value_type="e_noarg"/>
<efx:param name="beneficial_skew" value="on" value_type="e_option"/>
</efx:place_and_route>
<efx:bitstream_generation tool_name="efx_pgm">
<efx:param name="mode" value="active" value_type="e_option"/>
<efx:param name="width" value="1" value_type="e_option"/>
<efx:param name="enable_roms" value="smart" value_type="e_option"/>
<efx:param name="spi_low_power_mode" value="on" value_type="e_bool"/>
<efx:param name="io_weak_pullup" value="on" value_type="e_bool"/>
<efx:param name="oscillator_clock_divider" value="DIV8" value_type="e_option"/>
<efx:param name="bitstream_compression" value="on" value_type="e_bool"/>
<efx:param name="enable_external_master_clock" value="off" value_type="e_bool"/>
<efx:param name="active_capture_clk_edge" value="negedge" value_type="e_option"/>
<efx:param name="jtag_usercode" value="0xFFFFFFFF" value_type="e_string"/>
<efx:param name="release_tri_then_reset" value="on" value_type="e_bool"/>
<efx:param name="four_byte_addressing" value="off" value_type="e_bool"/>
<efx:param name="generate_bit" value="on" value_type="e_bool"/>
<efx:param name="generate_bitbin" value="off" value_type="e_bool"/>
<efx:param name="generate_hex" value="on" value_type="e_bool"/>
<efx:param name="generate_hexbin" value="off" value_type="e_bool"/>
<efx:param name="cold_boot" value="off" value_type="e_bool"/>
<efx:param name="cascade" value="off" value_type="e_option"/>
</efx:bitstream_generation>
<efx:debugger>
<efx:param name="work_dir" value="work_dbg" value_type="e_string"/>
<efx:param name="auto_instantiation" value="off" value_type="e_bool"/>
<efx:param name="profile" value="NONE" value_type="e_string"/>
</efx:debugger>
<efx:security>
<efx:param name="randomize_iv_value" value="on" value_type="e_bool"/>
<efx:param name="iv_value" value="" value_type="e_string"/>
<efx:param name="enable_bitstream_encrypt" value="off" value_type="e_bool"/>
<efx:param name="enable_bitstream_auth" value="off" value_type="e_bool"/>
<efx:param name="encryption_key_file" value="NONE" value_type="e_string"/>
<efx:param name="auth_key_file" value="NONE" value_type="e_string"/>
</efx:security>
</efx:project>

View File

@@ -0,0 +1 @@
create_clock -period 20 -name clk [get_ports i_clk]

View File

@@ -0,0 +1,132 @@
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/26.2.2 Chrome/134.0.6998.178 Electron/35.1.2 Safari/537.36" version="26.2.2">
<diagram name="Page-1" id="b4c9RxKzofB-lxyaVzG6">
<mxGraphModel dx="289" dy="195" 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="yBq3zbYGeky0_LNz2CMc-4" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="yBq3zbYGeky0_LNz2CMc-1" target="yBq3zbYGeky0_LNz2CMc-2">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="680" y="100" />
<mxPoint x="580" y="100" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-28" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="yBq3zbYGeky0_LNz2CMc-1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="760" y="140" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-29" value="result" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="yBq3zbYGeky0_LNz2CMc-28">
<mxGeometry x="0.7628" y="1" relative="1" as="geometry">
<mxPoint x="25" y="1" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-1" value="accumulator w/ wrap" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="640" y="120" width="80" height="40" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="yBq3zbYGeky0_LNz2CMc-2" target="yBq3zbYGeky0_LNz2CMc-1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-2" value="+" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="560" y="120" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="yBq3zbYGeky0_LNz2CMc-5" target="yBq3zbYGeky0_LNz2CMc-2">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-5" value="Friendly Modulo" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="360" y="80" width="160" height="120" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-14" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="yBq3zbYGeky0_LNz2CMc-7" target="yBq3zbYGeky0_LNz2CMc-13">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-7" value="X" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="200" y="120" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="yBq3zbYGeky0_LNz2CMc-8" target="yBq3zbYGeky0_LNz2CMc-7">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-8" value="Data (128 bit)" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="40" y="80" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="yBq3zbYGeky0_LNz2CMc-10" target="yBq3zbYGeky0_LNz2CMc-7">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-10" value="h (26x5 bit)" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="40" y="160" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="yBq3zbYGeky0_LNz2CMc-13" target="yBq3zbYGeky0_LNz2CMc-5">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-13" value="pipe reg" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="280" y="120" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-25" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="yBq3zbYGeky0_LNz2CMc-16" target="yBq3zbYGeky0_LNz2CMc-22">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-16" value="pipe reg" style="whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="280" y="160" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-19" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="yBq3zbYGeky0_LNz2CMc-18" target="yBq3zbYGeky0_LNz2CMc-10">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-20" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="yBq3zbYGeky0_LNz2CMc-18" target="yBq3zbYGeky0_LNz2CMc-16">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="100" y="220" />
<mxPoint x="260" y="220" />
<mxPoint x="260" y="180" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-18" value="state counter" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="40" y="240" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-21" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.833;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="yBq3zbYGeky0_LNz2CMc-16" target="yBq3zbYGeky0_LNz2CMc-5">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-22" value="pipe reg" style="whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="360" y="240" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-23" value="pipe reg" style="whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="400" y="240" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-26" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="yBq3zbYGeky0_LNz2CMc-24" target="yBq3zbYGeky0_LNz2CMc-1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-27" value="reset" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="yBq3zbYGeky0_LNz2CMc-26">
<mxGeometry x="-0.2" y="1" relative="1" as="geometry">
<mxPoint x="-10" y="-9" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-31" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="yBq3zbYGeky0_LNz2CMc-24" target="yBq3zbYGeky0_LNz2CMc-30">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="680" y="260" />
<mxPoint x="680" y="200" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-24" value="pipe reg" style="whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="440" y="240" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-32" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="yBq3zbYGeky0_LNz2CMc-30">
<mxGeometry relative="1" as="geometry">
<mxPoint x="800" y="200" as="targetPoint" />
<Array as="points">
<mxPoint x="800" y="200" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-33" value="done flag" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="yBq3zbYGeky0_LNz2CMc-32">
<mxGeometry x="0.1299" y="1" relative="1" as="geometry">
<mxPoint x="7" y="-19" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="yBq3zbYGeky0_LNz2CMc-30" value="==4?" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="700" y="180" width="60" height="40" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@@ -33,4 +33,86 @@ we need
r\*r = r^2
r\*r^2 = r^3 r^2\*r^2 = r^4
r^4\*r = r^5 r^2\*r^4 = r^6 r^3\*r^4 = r^7 r^4\*r^4 = r^8
r^4\*r = r^5 r^2\*r^4 = r^6 r^3\*r^4 = r^7 r^4\*r^4 = r^8
we can do all of these in parallel, so we 4 (n/2) multiply blocks that feed back
on themselves, with some kind of FSM to control it. This can be done while another
block is being hashed, but there will be a delay between when the key is ready from
the chacha block and when the powers are ready, so there needs to be a fifo in between.
Basically we have to wait until we see that the accumulator was written with our index.
At reset though, the acumulator is unwritten? So we need to pretend that it was written
Lets just write out what we want to happen:
1. The index starts at 0. We accept new data, and send it through the pipeline
2. We increment the index to 1.
3. We accept new data and send it through the pipeline
4. We increment the index to 2
5. We need to wait until the index 0 is written before we can say we are ready
6. If the index 1 is written then we still need to say we are ready though
7. We can just use the 1 to indicate that is a valid write then?
So in the shift register we just need to say whether it is a valid write or not,
so always 1?
But if we send in 0, then send in 1, then the current index will be 0
and eventually the final index will always be 0. We need to store what
the last written one is.
We can just say the last written one was 2 I guess
We also need an input that tells it to reset the accumulator
What if instead of calculating all the way up to R^16 I just calculated up to r^8
and then just had 2 parallel blocks?
Lets think about the worst case throughput. The theoretical layout would have
8 of these in parallel. A minimum size packet of 64 bytes for example, is 512
bits. This is less than 128*8, so it would only take one round. Therefore, we
take 16 cycles to do 64 bytes, or 32 bits per cycle. This is only 1/4 of our
target throughput. In order to reach our target throughput of 128 bits per cycle,
If the packet is enough to fit into the second phase of the multiplier, then it
can run in parallel and give up to 256 bits per 16 cycles. In order for this to
happen, the packet size must be greater than 128*16, or 256 bytes. I would really
like to be able to reach our target throughput with 64 byte packets, so we may
need to have more smaller multipliers that can run in parallle, at the cost of
latency for larger packets.
a 64 byte packet is 512 bytes, which takes up 4 128 bit lanes. If we have a group
of 2 multipliers, they can do 128\*2\*2 bits per 16 cycles, or 512 bits per 16
cycles, which is 32 bits per cycle as we said earlier. To hit our target of 128
bits per cycle we just instantiate 4 of them. This results in the same number of
multipliers (8), but configured differently to prioritize throughput over latency.
We need to have a demux or whatever go between the groups.
If we only do 4 effective lanes in parallel, then we only need to do the multiply
loop twice
r->r^2
This will take 26 cycles, which is not ideal. Could we figure out a way to do all
of these powers in one step, taking only 13 cycles?
Alternatively, we could only do a single parallel step and just calculate R^2. This
would mean we have 8 different hashes going on at the same time, and would drastically
increase latency, but I think that is a fair tradeoff
So basically we need to store incoming data as 128 bit words. We will first get
r and s as 128 bit words. We store both and start work on squaring r. We will
also be recieving data this whole time at 128 bits per cycle which we store in
a FIFO. Once R^2 is calculated, we start running it through the multiplier, with
a counter that tells us when we should be using R and when we should be using
r^2. We only have 1 value to worry about, when we get the last value we only
use R instead of R^2. we also need to remember to store the outputs on both
last cycles. Since we are storing the data in a FIFO, we will know which is the
last. There is also a possibility that the data will not be a full 128 bits, so
we need to handle adding the leading 1 as well.
We can use 1 multiplier, 2 data fifos, 2 constant buffers.
The utilization of the multiplier is kinda low though since its only used
once per packet instaead of every 16 bytes

View File

@@ -0,0 +1,58 @@
# 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.
the real requirement was to get something that works...
we can pipeline chacha20 as much as we want since it is trivially pipelined
since poly1305 takes in a 32 bit stream, we can redo chacha20 to work on 32 bits
at a time instead of 256 bits. We could also reuse stages, so instead of needing
all 20 stages we can just have 2 or something.
BUT since the number 1 requirement is to get it to work, lets just use what we already have.
okay they 512 bit chacha implementation is a bit crazy. the latency is too high. we need
to come up with a way to do it 32 bits at a time.
each quarter round generates 128 bits, so we could do 1 quarter round at a time and get 128
bits per clock cycle, which is plenty fast.
if we do 1 quarter round per clock cycle, There are 20 rounds, each of which is 4 quarter
rounds, so it would take 80 cycles.
Compared to the current implementation which has 20 rounds, but each round takes 7 cycles,
this has almost half the latency. We still need to store the full state between each round,
which is 512 bits.
OHHH there is a big different here with encrypt vs decrypt. basically, it is always
the encrypted packet that goes through poly1305. If the packet is being encrypted then
it needs to get xored before going into poly1305. If the packet is being decrypted, then it
needs to go through poly1305 in parallel with being xored.

View File

@@ -0,0 +1,217 @@
# Data from wireshark
Ok lets work this out by hand. The encyrpted packet matches exaactly, so we
know that the chacha20 part is correct, and this must include the first block
which is used for the keys.
84 bytes rounded to nearest multiple of 16 is 96 bytes. plus 16 for tag is 112.
so we do know that wireguard is including the tag.
the first output of chacha20, which becomes the keys, is
118b9bfd676a3bd991483cb1746252272e032bfbf2597dafec72576a54d9263ae32c815b30dbd75e7000d9ec14aac879075ada63f40d22180741336f9132e14a
The bottm 256 bits of that is
e32c815b30dbd75e7000d9ec14aac879075ada63f40d22180741336f9132e14a
splitting that into 128 bit sections, we get
0xe32c815b30dbd75e7000d9ec14aac879
0x075ada63f40d22180741336f9132e14a
r_mask is 0x0ffffffc0ffffffc0ffffffc0fffffff
so out final values of r and s are
r = 0x075ada60040d22180741336c0132e14a
s = 0xe32c815b30dbd75e7000d9ec14aac879
oh and p = 2**130-5
These values line up with what what we see in the hardware.
according to the spec, the algorithm for poly1305 is as follows:
```text
a = 0 /* a is the accumulator */
p = (1<<130)-5
for i=1 upto ceil(msg length in bytes / 16)
n = le_bytes_to_num(msg[((i-1)*16)..(i*16)] | [0x01])
a += n
a = (r * a) % p
end
a += s
return num_to_16_le_bytes(a)
end
```
Here is the cipher, which is msg in this case
b"\xa4\xeb\xc1.\xe3\xf9\x90\xda\x18\x03:\x07\x89\xc0N'\x00\xf6\xf5\xc2q\xd4*\xc4\xb4\xd6&.feI\xb4E\xa7Cn\x82\x9b\xff\xb6\xace\xf0VH\xbc\x0c9\x1f\xe7\xc5\x88Ht7a'\x16I@\x18\x8f\x03\xdb\xa6z\xf88\x8e\xaa\xb7lY6(\xbf\x9d\xc7\xbe\x034m\x91.\x91m\xad\x86%EEG\x016O-"
here it is split up into 16 byte chunks
b"\xa4\xeb\xc1.\xe3\xf9\x90\xda\x18\x03:\x07\x89\xc0N'"
b'\x00\xf6\xf5\xc2q\xd4*\xc4\xb4\xd6&.feI\xb4'
b'E\xa7Cn\x82\x9b\xff\xb6\xace\xf0VH\xbc\x0c9'
b"\x1f\xe7\xc5\x88Ht7a'\x16I@\x18\x8f\x03\xdb"
b'\xa6z\xf88\x8e\xaa\xb7lY6(\xbf\x9d\xc7\xbe\x03'
b'4m\x91.\x91m\xad\x86%EEG\x016O-'
The length of the message is 96 bytes, so we have our 6 16 byte chunks.
the next step is to interpret these as little endian integers, then add a leading 1.
0x1274ec089073a0318da90f9e32ec1eba4
0x1b44965662e26d6b4c42ad471c2f5f600
0x1390cbc4856f065acb6ff9b826e43a745
0x1db038f18404916276137744888c5e71f
0x103bec79dbf2836596cb7aa8e38f87aa6
0x12d4f36014745452586ad6d912e916d34
DON'T FORGET ABOUT THE LENGTHS!
The length of AAD is 0, and the length of the ciphertext is 96,
that becomes
this is aad length, data_length
be careful of the order, since aad length comes first, it is on the
right side of this hex number, since its little endian.
0x100000000000000600000000000000000
And these also match the hardware, so we are doing good so far.
so after the first round, a = (r * n) % p, since a started at 0, a+=n is just n
so a = 0xcfd86a9543d3377baf5be686c46d8491
ok looks good so far.
next is 0x312e451b2a526811c5bd976ce3c27d5e7, looks good as well. the next values in a row are
0x22097b74ef42792da5e02cf9dd8249776
0x2586a4ee24499da642fb6392be59137b2
0xff1ba4984e72db7199c786a00de9de1e
0x2850e6cbbf9869bf410976e82e2ee9b04
0x38878751382017086bc63eee8ba2cbdab
which all match still. So the final step is to add s,
0x46ba4f66eb2dd47e52c64c8d4ced78624
and truncate to 128 bits
6ba4f66eb2dd47e52c64c8d4ced78624
SO basically we need to appaned the length to the data when it is going through poly1305.
poly1305 should be able to look at the input fifo and know when it is outputting the last
valid beat. After this, we need to output the lengths.
## Keepalive Packets
These packets have zero data. They will need to be handled separately.
After We can look at the UDP length to figure out if it is a keepalive packet,
this only serves to tell software if the connection has failed. We will
need to support sending and receiving these at some point, most likely in
hardware since they need to be authenticated, but they have no data.
perhaps some tuser flag can be passed in to bypass the crypto. We can
send in 16 bytes of zeroes but the user flag says to not actually send
this to poly1305, and the result can just be dropped after resetting some kind
of counter, or we can drop the data and just encapsulate the poly1305 tag.
## Padding is not always 16 bytes
The packets are 16 byte aligned UNLESS this would bring the packet over the MTU.
What this means in practice is that we might receive packets which are not 16
byte aligned. If we are decrypting a packet, the length must be what the packet
actually is and not rounded up. We also need to be careful when we are sending
out packets that we can't always go up to 1500 bytes.
(Might have to tell end users to set their MTU to 1300 or something).
If we are decrypting then, the width convert should not round up.
Or... we can just put that in a different module and not have random rules in the
crypto block itself.
This also breaks the poly1305, because it is expecting exactly 128 bits every time,
so it has a specific cycle for the lengths. BUT if the incoming data is not 16 byte
aligned, then the lengths will be added at the wrong time. So, based on the length
of the packet, we need to be adding the lengths at a varying position at the end
of the packet. It might be split over 2 cycles, depending on what the length is.
we can figure this out easily by simply taking the length of the packet (which
we have counted already) modulo 16, aka & 0xf. In this case, the length of the packet
is 1420, so the counter is 12. What this means is that the last packet is only
12 bytes, so we need to shift 4 bytes of the counter into the last data beat.
How do we know its the last data beat? the upconvert module gives us last. Technically
we calulate the total length based on this output. whatever.
So in the sum state, we set the last flag based on upconvert_last. If this is true,
we also need to check if upconvert_countm1 is 0xf, or if its smaller than that. if
its 15, then we do what we normally do, just 1 extend the existing data. If it is not,
then we need to do 15 - countm1 bytes of the length packet.
* padding2 -- the padding is up to 15 zero bytes, and it brings
the total length so far to an integral multiple of 16. If the
length of the ciphertext was already an integral multiple of 16
bytes, this field is zero-length.
wait... we should still be adding this padding ourselves...
this is actually an embarassingly easy fix.
1420 bytes of inner ip
16 bytes of wireguard header
16 bytes of wireguard signature
8 bytes of udp
20 bytes of ipv4
14 bytes of ethernet
so if you are just looking at wireguard itself, its max is 1420 + 32?
or, is it that we set the MTU to 1420 which is the max sized of the
encrypted packet, so we can't add any padding?
OK in the width expander we expand to 1420 max.
we could have a check at the begining that checks the
total length. If it is larger than 1420 then we can
send the packet to the CPU to fragment or do something with
But really all computers that are on the network should
have the MTU set to 1420 so that we can avoid this.
One thing we still need to support is keepalive packets. These have
no payload, but still need to be decrypted. The input FSM will take
in just the encrypted wireguard packet, without the wireguard header.
It will then strip off the tag and put it in a fifo for the output fsm
to read. If it does this to a keepalive packet, there will be no data.
If this happens, the input FSM will send in 64 bytes of dummy data,
all zeroes, along with a keepalive signal. this signal will be stored
along with the packet and when it is output to the output fsm, it will
know to ignore the actual data.
I think this can be done entirely outside of the crypto block.
OK so that tells us what we need to do next, the pre and postformat FSM.
preformat FSM removes the tag, postformat FSM adds the tag back for encyrpt,
or compares the tag with the expected tag for decrypt.
We need a metadata FIFO which tells us whether to encyrpt or decrypt.
ohhhh right. what I really wanted to do today was synthesize this block
and see what the timing looks like.
We pass timing at 67 MHz. Lets try to reduce the number of flop stages in
chacha to see if we can reduce the number of flops we use.

View File

@@ -1,144 +1,128 @@
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/26.2.2 Chrome/134.0.6998.178 Electron/35.1.2 Safari/537.36" version="26.2.2">
<diagram name="Page-1" id="gIy_vrPza4QP03Kn0wfk">
<mxGraphModel dx="655" dy="442" 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">
<diagram name="Page-1" id="b4c9RxKzofB-lxyaVzG6">
<mxGraphModel dx="794" dy="536" 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="GA09nmFLpfHeItamLD5O-24" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="GA09nmFLpfHeItamLD5O-1" target="GA09nmFLpfHeItamLD5O-21">
<mxCell id="FEGHAENOx_VuAQpIDQKO-19" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="FEGHAENOx_VuAQpIDQKO-1" target="FEGHAENOx_VuAQpIDQKO-15">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-25" value="r" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="GA09nmFLpfHeItamLD5O-24">
<mxGeometry x="0.5579" y="-1" relative="1" as="geometry">
<mxPoint x="9" y="5" as="offset" />
<mxCell id="FEGHAENOx_VuAQpIDQKO-20" value="last" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FEGHAENOx_VuAQpIDQKO-19">
<mxGeometry x="-0.5549" y="-1" relative="1" as="geometry">
<mxPoint y="9" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-35" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="GA09nmFLpfHeItamLD5O-1" target="GA09nmFLpfHeItamLD5O-34">
<mxCell id="FEGHAENOx_VuAQpIDQKO-1" value="data fifo" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="120" y="120" width="280" height="40" as="geometry" />
</mxCell>
<mxCell id="FEGHAENOx_VuAQpIDQKO-3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.75;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="FEGHAENOx_VuAQpIDQKO-2" target="FEGHAENOx_VuAQpIDQKO-1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-38" value="s" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="GA09nmFLpfHeItamLD5O-35">
<mxGeometry x="-0.6624" y="1" relative="1" as="geometry">
<mxPoint x="-9" y="-9" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-1" value="r/s" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="360" y="200" width="80" height="40" as="geometry" />
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-2" value="" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="1" target="GA09nmFLpfHeItamLD5O-1">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="320" y="210" as="sourcePoint" />
<mxPoint x="410" y="270" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-3" value="otk" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="GA09nmFLpfHeItamLD5O-2">
<mxGeometry x="-0.3946" y="1" relative="1" as="geometry">
<mxPoint x="-22" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-10" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="GA09nmFLpfHeItamLD5O-4" target="GA09nmFLpfHeItamLD5O-6">
<mxCell id="FEGHAENOx_VuAQpIDQKO-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="FEGHAENOx_VuAQpIDQKO-2" target="FEGHAENOx_VuAQpIDQKO-6">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-4" value="64-&amp;gt;128" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="175" y="130" width="50" height="20" as="geometry" />
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-5" value="" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" target="GA09nmFLpfHeItamLD5O-4">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="120" y="140" as="sourcePoint" />
<mxPoint x="290" y="110" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="GA09nmFLpfHeItamLD5O-6" target="GA09nmFLpfHeItamLD5O-14">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-40" value="data_one_extended" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="GA09nmFLpfHeItamLD5O-15">
<mxGeometry x="-0.3532" y="-1" relative="1" as="geometry">
<mxPoint x="7" y="29" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-6" value="bit add" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="240" y="120" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-8" value="" style="endArrow=classic;html=1;rounded=0;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" target="GA09nmFLpfHeItamLD5O-6">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="260" y="80" as="sourcePoint" />
<mxPoint x="290" y="70" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-9" value="tkeep" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="GA09nmFLpfHeItamLD5O-8">
<mxGeometry x="-0.699" relative="1" as="geometry">
<mxPoint y="-16" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-11" value="P" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="540" y="180" width="80" height="20" as="geometry" />
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-18" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="GA09nmFLpfHeItamLD5O-12" target="GA09nmFLpfHeItamLD5O-14">
<mxCell id="FEGHAENOx_VuAQpIDQKO-14" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="FEGHAENOx_VuAQpIDQKO-2" target="FEGHAENOx_VuAQpIDQKO-8">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="340" y="100" />
<mxPoint x="100" y="210" />
<mxPoint x="100" y="250" />
<mxPoint x="260" y="250" />
<mxPoint x="260" y="220" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-36" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="GA09nmFLpfHeItamLD5O-12" target="GA09nmFLpfHeItamLD5O-34">
<mxCell id="FEGHAENOx_VuAQpIDQKO-2" value="" style="shape=trapezoid;perimeter=trapezoidPerimeter;whiteSpace=wrap;html=1;fixedSize=1;rotation=-90;" vertex="1" parent="1">
<mxGeometry y="160" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="FEGHAENOx_VuAQpIDQKO-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="FEGHAENOx_VuAQpIDQKO-4" target="FEGHAENOx_VuAQpIDQKO-27">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="400" y="60" />
<mxPoint x="660" y="60" />
<mxPoint x="420" y="260" />
<mxPoint x="420" y="300" />
<mxPoint x="780" y="300" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-12" value="acc" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="360" y="80" width="80" height="40" as="geometry" />
<mxCell id="FEGHAENOx_VuAQpIDQKO-4" value="s" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="280" y="240" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-14" value="+" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="320" y="120" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-32" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="GA09nmFLpfHeItamLD5O-21" target="GA09nmFLpfHeItamLD5O-31">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-21" value="*" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="440" y="120" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-22" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="GA09nmFLpfHeItamLD5O-14" target="GA09nmFLpfHeItamLD5O-21">
<mxGeometry relative="1" as="geometry">
<mxPoint x="460" y="140" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-41" value="data_post_add" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="GA09nmFLpfHeItamLD5O-22">
<mxGeometry x="-0.1925" y="-1" relative="1" as="geometry">
<mxPoint x="8" y="19" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-26" value="%" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="560" y="120" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.51;entryY=1.007;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="GA09nmFLpfHeItamLD5O-11" target="GA09nmFLpfHeItamLD5O-26">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-30" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1.022;entryY=0.482;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="GA09nmFLpfHeItamLD5O-26" target="GA09nmFLpfHeItamLD5O-12">
<mxCell id="FEGHAENOx_VuAQpIDQKO-5" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.25;exitY=1;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="FEGHAENOx_VuAQpIDQKO-2" target="FEGHAENOx_VuAQpIDQKO-4">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="580" y="99" />
<mxPoint x="100" y="210" />
<mxPoint x="100" y="260" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-33" value="" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="GA09nmFLpfHeItamLD5O-31" target="GA09nmFLpfHeItamLD5O-26">
<mxCell id="FEGHAENOx_VuAQpIDQKO-9" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="FEGHAENOx_VuAQpIDQKO-6" target="FEGHAENOx_VuAQpIDQKO-8">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-31" value="reg" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="500" y="130" width="40" height="20" as="geometry" />
<mxCell id="FEGHAENOx_VuAQpIDQKO-6" value="multiplier" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="120" y="200" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-37" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="GA09nmFLpfHeItamLD5O-34">
<mxCell id="FEGHAENOx_VuAQpIDQKO-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0.25;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="FEGHAENOx_VuAQpIDQKO-8" target="FEGHAENOx_VuAQpIDQKO-15">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FEGHAENOx_VuAQpIDQKO-22" value="r&lt;sup&gt;2&lt;/sup&gt;" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FEGHAENOx_VuAQpIDQKO-16">
<mxGeometry x="-0.2366" y="1" relative="1" as="geometry">
<mxPoint x="2" y="-9" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="FEGHAENOx_VuAQpIDQKO-17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0.75;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="FEGHAENOx_VuAQpIDQKO-8" target="FEGHAENOx_VuAQpIDQKO-15">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FEGHAENOx_VuAQpIDQKO-23" value="r" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FEGHAENOx_VuAQpIDQKO-17">
<mxGeometry x="-0.2762" y="1" relative="1" as="geometry">
<mxPoint x="3" y="11" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="FEGHAENOx_VuAQpIDQKO-8" value="r&lt;sup&gt;2&lt;/sup&gt;/r" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="280" y="200" width="120" height="40" as="geometry" />
</mxCell>
<mxCell id="FEGHAENOx_VuAQpIDQKO-28" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="FEGHAENOx_VuAQpIDQKO-11" target="FEGHAENOx_VuAQpIDQKO-27">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FEGHAENOx_VuAQpIDQKO-11" value="Poly1305 Stage" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="480" y="120" width="240" height="160" as="geometry" />
</mxCell>
<mxCell id="FEGHAENOx_VuAQpIDQKO-12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.125;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="FEGHAENOx_VuAQpIDQKO-1" target="FEGHAENOx_VuAQpIDQKO-11">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FEGHAENOx_VuAQpIDQKO-21" value="data" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FEGHAENOx_VuAQpIDQKO-12">
<mxGeometry x="-0.1705" relative="1" as="geometry">
<mxPoint y="-10" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="FEGHAENOx_VuAQpIDQKO-15" value="" style="shape=trapezoid;perimeter=trapezoidPerimeter;whiteSpace=wrap;html=1;fixedSize=1;rotation=90;size=10;" vertex="1" parent="1">
<mxGeometry x="410" y="210" width="40" height="20" as="geometry" />
</mxCell>
<mxCell id="FEGHAENOx_VuAQpIDQKO-18" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.625;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="FEGHAENOx_VuAQpIDQKO-15" target="FEGHAENOx_VuAQpIDQKO-11">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="FEGHAENOx_VuAQpIDQKO-25" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.25;exitDx=0;exitDy=0;entryX=0.125;entryY=0;entryDx=0;entryDy=0;entryPerimeter=0;" edge="1" parent="1" source="FEGHAENOx_VuAQpIDQKO-1" target="FEGHAENOx_VuAQpIDQKO-11">
<mxGeometry relative="1" as="geometry">
<mxPoint x="720" y="140" as="targetPoint" />
<Array as="points">
<mxPoint x="410" y="130" />
<mxPoint x="410" y="100" />
<mxPoint x="510" y="100" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-39" value="tag" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="GA09nmFLpfHeItamLD5O-37">
<mxGeometry x="0.6531" y="2" relative="1" as="geometry">
<mxPoint x="17" y="2" as="offset" />
<mxCell id="FEGHAENOx_VuAQpIDQKO-26" value="sop" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="FEGHAENOx_VuAQpIDQKO-25">
<mxGeometry x="-0.0418" relative="1" as="geometry">
<mxPoint x="13" y="-10" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="GA09nmFLpfHeItamLD5O-34" value="+" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="640" y="120" width="40" height="40" as="geometry" />
<mxCell id="FEGHAENOx_VuAQpIDQKO-30" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="FEGHAENOx_VuAQpIDQKO-27">
<mxGeometry relative="1" as="geometry">
<mxPoint x="840" y="200" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="FEGHAENOx_VuAQpIDQKO-27" value="+" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="760" y="180" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="FEGHAENOx_VuAQpIDQKO-31" value="&lt;h1 style=&quot;margin-top: 0px;&quot;&gt;Poly1305&lt;/h1&gt;&lt;p&gt;Axi Stream&amp;nbsp;&lt;/p&gt;" style="text;html=1;whiteSpace=wrap;overflow=hidden;rounded=0;" vertex="1" parent="1">
<mxGeometry x="80" y="320" width="360" height="160" as="geometry" />
</mxCell>
</root>
</mxGraphModel>

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

@@ -0,0 +1,59 @@
<mxfile host="Electron" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/26.2.2 Chrome/134.0.6998.178 Electron/35.1.2 Safari/537.36" version="26.2.2">
<diagram name="Page-1" id="b4c9RxKzofB-lxyaVzG6">
<mxGraphModel dx="616" dy="416" 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="3x5Ie6wAwAZYy6GZGmB0-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=1;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" source="3x5Ie6wAwAZYy6GZGmB0-1" target="3x5Ie6wAwAZYy6GZGmB0-6">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="500" y="160" />
<mxPoint x="500" y="230" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="3x5Ie6wAwAZYy6GZGmB0-17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="3x5Ie6wAwAZYy6GZGmB0-1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="560" y="160" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="3x5Ie6wAwAZYy6GZGmB0-1" value="Modular Multiplier (10 cycle latency)" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="280" y="120" width="200" height="80" as="geometry" />
</mxCell>
<mxCell id="3x5Ie6wAwAZYy6GZGmB0-11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=1;entryDx=0;entryDy=0;" edge="1" parent="1" source="3x5Ie6wAwAZYy6GZGmB0-6" target="3x5Ie6wAwAZYy6GZGmB0-10">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="3x5Ie6wAwAZYy6GZGmB0-6" value="H temp" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="345" y="210" width="80" height="40" as="geometry" />
</mxCell>
<mxCell id="3x5Ie6wAwAZYy6GZGmB0-12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.75;entryDx=0;entryDy=0;" edge="1" parent="1" source="3x5Ie6wAwAZYy6GZGmB0-10" target="3x5Ie6wAwAZYy6GZGmB0-1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="3x5Ie6wAwAZYy6GZGmB0-10" value="+" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" vertex="1" parent="1">
<mxGeometry x="200" y="160" width="40" height="40" as="geometry" />
</mxCell>
<mxCell id="3x5Ie6wAwAZYy6GZGmB0-13" value="" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" edge="1" parent="1" target="3x5Ie6wAwAZYy6GZGmB0-10">
<mxGeometry width="50" height="50" relative="1" as="geometry">
<mxPoint x="160" y="180" as="sourcePoint" />
<mxPoint x="170" y="140" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="3x5Ie6wAwAZYy6GZGmB0-14" value="message" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="3x5Ie6wAwAZYy6GZGmB0-13">
<mxGeometry x="-0.1731" y="1" relative="1" as="geometry">
<mxPoint x="-46" y="1" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="3x5Ie6wAwAZYy6GZGmB0-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="1" source="3x5Ie6wAwAZYy6GZGmB0-15" target="3x5Ie6wAwAZYy6GZGmB0-1">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="220" y="140" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="3x5Ie6wAwAZYy6GZGmB0-15" value="r" style="shape=trapezoid;perimeter=trapezoidPerimeter;whiteSpace=wrap;html=1;fixedSize=1;rotation=0;flipV=1;size=10;" vertex="1" parent="1">
<mxGeometry x="190" y="90" width="60" height="30" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>

View File

@@ -0,0 +1,29 @@
import base64
data = base64.decodebytes(b"BAAAALme3iYDAAAAAAAAAK0SmHnTT056FRHPMd66WYNlCDTwvJhkJx79R5psrl+fL/89gBZYHL2mjT9C+55tJuUVjHXYKMYdEVgn2he8p65W7BheKppBmq3mKfRezs8pRpgGVO4yI03t5BponGYn8xC71VtMPWxpBYdy9HsHNiZj4jGT30O+WPrdQTL10beu6ao+qEXUUD1hVHSKcpgOGp/xll7AjPYs1OEt64exAfO8pFeZtQTp16cLuiPNqMld3EYh2p7lF/Ry9GO3lB9sp/PB6cfSOOvLViZ3wsiCF/Q7awYqFuCrcMjU1RQs7RPGW4fhiFazl9NsvSuBvWMII48keUCtkLnbqv9dBZM7BPCVePAwFW5iPZOa7vkxaPF6pqWDSgTwRiLICiix5wQL0a0cBpgMxryNCxmvyRKUyRdo1RFMayfXFOp+6DqmUrNbBr3dnDGE87XuAkOnx9m/DR/yBI/iiePSCnsxeyJVwtBVJeDdzwZAyrVR9vYFfyVRH4MirZYuw33VkTA98OEXcqrdTSOvsTn04JL/1DmKTjdj8HHjtuBism6vOofdrFRmVSREAiE5tI4HecIkZV/iu2345JIe8FTWZZVfvIVG9VamkHPLe0gBQR4eeLfUWIlRQrU+aiWQBaZKMxooyYwZPZGTlUtKmU/Q1/cJ9GeBKuD6Txge+/okOlqvPXgCHeyiAiSHVJ/2lWHTK7BPyPwcIik3q+dIUpIwL5/7doYDcezpnscB5o/KjAvBw3YwqAuNLyVuqFrMGti1eCTi1ll016slCEbDGRvHYielCtdzkw7vYhIPE+k37FxXByoJ3jg5NlOrbRoVvO25Hy2rP4SYMmQ3dEQNRDVkCy8yvQRSAI1UOknXnpDo+SU50FKcmdB94htpRM+ddADNUmJPD7JJAI8AFgkMN7Zujgq7v2ZSXNhpDX1MD+7zdYUwu8GsldMKTYtz+BaShoJtcSSmXYdAup8i12lGBtJJf7FxANSweg5bHgr3OE9VLJZq5JIKhY+0cIKRF8ymI5of9vXETGT7JQe26QVn8zekevI183yiqS5qbxqdt96eT1/W8mF/2TNCYBgiP135gKwVoS3ZY/0kWrx5oN0TXSGjMkRnhucEjsw5W18CFJo+labHkmuZUJ+rdVfEviady27EwgIcU2sGWPWn7jw+WPOG+709CBGtfw7/Ld6MDmNsvT9m7mvTKOVIHxJyaiA997y9P4FD4mjjlHbtncJRtUeqrW4GXrQouF9ur2+OIMAkmo1jz51j6UbyT2RUwr+ABWfwfHUxDzwxRuhj0rodw3a3ZiFtGqIXYeDavMOE3Okn/zSGETIHOnfTufGBddxSRaOUGGMv6xBXzzq+qja6JMLx/M15yhTQE2NpVrNevbrMBBE7TdOVyZP4AdvQOByO1AcTjKtOgKaPfUQeHjn21/43VO9VhnNqozlU5n1ud+xxE+CKwt7kQ9TOn4UVF/x4poIJdV851jIehBZNR+ntWFPr4wc6WMggOJ3//UWKiAvKXrsKk3YsJLdVKIqBnXD3tewpb324LVkizIaUNH1ZWWAxZa/B1Rn3K8fwKl73G+d6I6uNcz0RiiAEYKoEkN7Web3KmIQYIyT4UN2I4HfjRy0i0rXEuEevDarBbfww+fgefYf9lu3hgre4/XMuuuBnjKK4+3BNkT9ipmOzm0gH3LT470OWEDFqm+SaIVW//VdijHsWJkFiSdD8QFYQtjgII1+d1XWXmZdocWm2iDje+4CX/14b+ZQgpWWgHJ+RiYOjEWnNzRtNyy9FrkQxzzlCIgz6hu+E8eDQExP7qunniB6UBPTkmutaaNXhrG4/oWT4yBx0HAmI/VrA/M/AmsDlRpp8MO0zwFQuLbb6aXm1CO88TIeCkXbCsYiy13edfJbf0FsLhIp4P9ZqX07Ug6SKcT8ZjHkc")[16:-16]
r = 0xb92cdec04e0255000c2c598066eeefa
s = 0xef4af5c5bed427d0e93cf8da2ffa5c6
p = 2**130 - 5
chunked_data = []
while len(data) > 0:
chunk_bytes = data[:16]
chunk = int.from_bytes(chunk_bytes, "little")
chunk |= 1 << (8*len(chunk_bytes))
chunked_data.append(chunk)
data = data[16:]
a = 0
for chunk in chunked_data:
a += chunk
a = (r * a) % p
print(hex(a))
a += s
print(hex(a))

View File

@@ -1 +1 @@
create_clock -period 2.5 -name clk [get_ports i_clk]
create_clock -period 20 -name clk [get_ports i_clk]

View File

@@ -1,16 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<efx:project name="poly1305_timing_test" description="" last_change="1752448578" sw_version="2025.1.110" last_run_state="pass" last_run_flow="bitstream" config_result_in_sync="true" design_ood="sync" place_ood="sync" route_ood="sync" xmlns:efx="http://www.efinixinc.com/enf_proj" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.efinixinc.com/enf_proj enf_proj.xsd">
<efx:project name="poly1305_timing_test" description="" last_change="1784047128" sw_version="2025.1.110" last_run_state="pass" last_run_flow="bitstream" config_result_in_sync="true" design_ood="sync" place_ood="sync" route_ood="sync" xmlns:efx="http://www.efinixinc.com/enf_proj" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.efinixinc.com/enf_proj enf_proj.xsd">
<efx:device_info>
<efx:family name="Titanium"/>
<efx:device name="Ti375N1156"/>
<efx:timing_model name="C4"/>
</efx:device_info>
<efx:design_info def_veri_version="sv_09" def_vhdl_version="vhdl_2008" unified_flow="false">
<efx:top_module name="mult_timing_test"/>
<efx:design_file name="../src/poly1305_core.sv" version="default" library="default"/>
<efx:design_file name="../../common/sim/sub/taxi/src/axis/rtl/taxi_axis_if.sv" version="default" library="default"/>
<efx:design_file name="../sim/poly1305_core_wrapper.sv" version="default" library="default"/>
<efx:design_file name="mult_timing_test.sv" version="default" library="default"/>
<efx:top_module name="chacha20_flat_qr"/>
<efx:design_file name="../src/poly1305_ll_stage.sv" version="default" library="default"/>
<efx:design_file name="../src/poly1305_width_convert.sv" version="default" library="default"/>
<efx:design_file name="../src/chacha20_flat_qr.sv" version="default" library="default"/>
<efx:top_vhdl_arch name=""/>
</efx:design_info>
<efx:constraint_info>
@@ -41,7 +40,7 @@
<efx:param name="min-sr-fanout" value="0" value_type="e_integer"/>
<efx:param name="min-ce-fanout" value="0" value_type="e_integer"/>
<efx:param name="mode" value="speed" value_type="e_option"/>
<efx:param name="mult-auto-pipeline" value="1" value_type="e_integer"/>
<efx:param name="mult-auto-pipeline" value="0" value_type="e_integer"/>
<efx:param name="mult-decomp-retime" value="1" value_type="e_option"/>
<efx:param name="operator-sharing" value="1" value_type="e_option"/>
<efx:param name="optimize-adder-tree" value="1" value_type="e_option"/>

View File

@@ -0,0 +1,344 @@
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import Timer, RisingEdge, FallingEdge
from cocotb.handle import Immediate
from cocotb.queue import Queue
from dataclasses import dataclass
from chacha_helpers import chacha_block
import random
import base64
import struct
CLK_PERIOD = 20
NONCE_BYTES = b"\x00\x00\x00\x00\x00\x00\x00\x4a\x00\x00\x00\x00"
KEY_BYTES = b"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
MSG_BYTES = b"Ladies and Gentlemen of the class of '99: If I could offer you only one tip for the future, sunscreen would be it."
NONCE = int.from_bytes(NONCE_BYTES, "little")
KEY = int.from_bytes(KEY_BYTES, "little")
CONSTANT = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574]
output_queue = Queue()
async def receieve_output(dut):
packet = bytearray()
while True:
if dut.o_data_valid.value:
packet.extend(int(dut.o_data.value).to_bytes(4, "little"))
if dut.o_data_last.value:
await output_queue.put(bytes(packet))
packet = bytearray()
await RisingEdge(dut.i_clk)
# @cocotb.test
async def test_sanity(dut):
cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start())
cocotb.start_soon(receieve_output(dut))
for counter in range(3):
data_in = CONSTANT[:]
data_in.extend(struct.unpack("8I", KEY_BYTES))
data_in.extend(struct.unpack("1I", counter.to_bytes(4, "little")))
data_in.extend(struct.unpack("3I", NONCE_BYTES))
data_out = chacha_block(data_in)
print([f"{data:x}" for data in data_out])
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_nonce.value = NONCE
dut.i_key.value = KEY
dut.i_data_ready.value = 1
N_PKTS = 100
for _ in range(N_PKTS):
dut.i_last.value = 0
dut.i_valid.value = 1
msg = MSG_BYTES
while len(msg) > 0:
part = msg[0:4]
dut.i_data.value = int.from_bytes(part, "little")
dut.i_countm1.value = len(part)-1
if len(msg) < 4:
dut.i_last.value = 1
msg = msg[4:]
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
for _ in range(N_PKTS):
packet = await output_queue.get()
print(packet)
@dataclass
class CipherContext():
key: int
counter: int
encrypt: int
tag: int
cipher: bytes
clear: bytes
MESSAGE_KEY_1_BYTES = base64.decodebytes(b"IA7buFUDsARj+YequW4OfQR3JsaE9M88dpXKrDjKzIs=")
MESSAGE_KEY_2_BYTES = base64.decodebytes(b"3sZ+QBcwflnvE8t4jv9qgIqIOVaXXwO1bxRo9qWB1fM=")
MESSAGE_KEY_1 = int.from_bytes(MESSAGE_KEY_1_BYTES, "little")
MESSAGE_KEY_2 = int.from_bytes(MESSAGE_KEY_2_BYTES, "little")
MESSAGE_KEY_3_BYTES = base64.decodebytes(b"LbEI5uiueAZ2LJEg41FbMw6l8ZM3ZtaTrKLOb3dT7QI=")
MESSAGE_KEY_4_BYTES = base64.decodebytes(b"H8xSW7vRDaYfl5RilWIwkdF0ehDo30tEJO/IzJMTezY=")
MESSAGE_KEY_3 = int.from_bytes(MESSAGE_KEY_3_BYTES, "little")
MESSAGE_KEY_4 = int.from_bytes(MESSAGE_KEY_4_BYTES, "little")
PACKETS = [
CipherContext(
key=MESSAGE_KEY_1,
counter=0,
encrypt=1,
tag=int.from_bytes(base64.decodebytes(b"BAAAAAb0fasAAAAAAAAAAKTrwS7j+ZDaGAM6B4nATicA9vXCcdQqxLTWJi5mZUm0RadDboKb/7asZfBWSLwMOR/nxYhIdDdhJxZJQBiPA9umevg4jqq3bFk2KL+dx74DNG2RLpFtrYYlRUVHATZPLSSG187UyGQs5Ufdsm72pGs=")[-16:], "little"),
cipher=base64.decodebytes(b"BAAAAAb0fasAAAAAAAAAAKTrwS7j+ZDaGAM6B4nATicA9vXCcdQqxLTWJi5mZUm0RadDboKb/7asZfBWSLwMOR/nxYhIdDdhJxZJQBiPA9umevg4jqq3bFk2KL+dx74DNG2RLpFtrYYlRUVHATZPLSSG187UyGQs5Ufdsm72pGs=")[16:-16],
clear=base64.decodebytes(b"RQAAVOVGQABAAUFMCgoAAgoKAAEIAPlcbAAAAG+tIvUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
),
CipherContext(
key=MESSAGE_KEY_2,
counter=0,
encrypt=0,
tag=int.from_bytes(base64.decodebytes(b"BAAAANg30DAAAAAAAAAAAG9PCA6fUmkbvpSFNfecE+1o8JFF1SPu2whyZfloCC9wc1cpJj7aYnx2g83AuAozVtlTbJ8OKHJ5e1yBcguguOpyM8bev58PvujxDsGJhbgkvzUPi4GA0Ipk5r6YEAiaw9E2PtXhKcoeBCXPfpSWVlk=")[-16:], "little"),
cipher=base64.decodebytes(b"BAAAANg30DAAAAAAAAAAAG9PCA6fUmkbvpSFNfecE+1o8JFF1SPu2whyZfloCC9wc1cpJj7aYnx2g83AuAozVtlTbJ8OKHJ5e1yBcguguOpyM8bev58PvujxDsGJhbgkvzUPi4GA0Ipk5r6YEAiaw9E2PtXhKcoeBCXPfpSWVlk=")[16:-16],
clear=base64.decodebytes(b"RQAAVKEdAABAAcV1CgoAAQoKAAIAAAFdbAAAAG+tIvUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
),
CipherContext(
key=MESSAGE_KEY_1,
counter=1,
encrypt=1,
tag=int.from_bytes(base64.decodebytes(b"BAAAAAb0fasBAAAAAAAAAHzNKCSiKfzNFoU7Hv+UasxWNazSNhCJwxaXBs4Pz2LNqySyHtibW+QDk8FpLPp6KYHljK6RU0il+fyDPap6kagbUeVbtzLq3DhtalfmJbCSy1upQ/apOsaaBwHpnmAipi8Gbzy2IjKAkdrVnfE/bjM=")[-16:], "little"),
cipher=base64.decodebytes(b"BAAAAAb0fasBAAAAAAAAAHzNKCSiKfzNFoU7Hv+UasxWNazSNhCJwxaXBs4Pz2LNqySyHtibW+QDk8FpLPp6KYHljK6RU0il+fyDPap6kagbUeVbtzLq3DhtalfmJbCSy1upQ/apOsaaBwHpnmAipi8Gbzy2IjKAkdrVnfE/bjM=")[16:-16],
clear=base64.decodebytes(b"RQAAVOYnQABAAUBrCgoAAgoKAAEIALT9bAAAAaQLMvUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
),
CipherContext(
key=MESSAGE_KEY_2,
counter=1,
encrypt=0,
tag=int.from_bytes(base64.decodebytes(b"BAAAANg30DABAAAAAAAAAEnLMkirrPEmhurVsmRHh5lF0OHX0qYLVBL6ud2/nel70Iv6tf/m/76DfaEOzFYj9Muj7omVUEI90wZsW0+5sBoKcaivdUZhWC6g9ARJI0fqt/R+aXE2Kci0l8p5cgFBcLLDnZnBQcGf4VNr6+uPvyk=")[-16:], "little"),
cipher=base64.decodebytes(b"BAAAANg30DABAAAAAAAAAEnLMkirrPEmhurVsmRHh5lF0OHX0qYLVBL6ud2/nel70Iv6tf/m/76DfaEOzFYj9Muj7omVUEI90wZsW0+5sBoKcaivdUZhWC6g9ARJI0fqt/R+aXE2Kci0l8p5cgFBcLLDnZnBQcGf4VNr6+uPvyk=")[16:-16],
clear=base64.decodebytes(b"RQAAVKH6AABAAcSYCgoAAQoKAAIAALz9bAAAAaQLMvUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
),
CipherContext(
key=MESSAGE_KEY_1,
counter=2,
encrypt=1,
tag=int.from_bytes(base64.decodebytes(b"BAAAAAb0fasCAAAAAAAAAAK8hjcszyCKObdjMno0cMU0Iz0tMNJT26kI3GZUjL0WHPVq8pyYw5H5Cv+19Ks8qy7VQoPlhe14MGYbqoxpaSxmKvU3pAhRgOPhtIMZa/FXV7H68rtwMXO+O0wAaub4tGBBfxAZM+O3E5bImRe2MFQ=")[-16:], "little"),
cipher=base64.decodebytes(b"BAAAAAb0fasCAAAAAAAAAAK8hjcszyCKObdjMno0cMU0Iz0tMNJT26kI3GZUjL0WHPVq8pyYw5H5Cv+19Ks8qy7VQoPlhe14MGYbqoxpaSxmKvU3pAhRgOPhtIMZa/FXV7H68rtwMXO+O0wAaub4tGBBfxAZM+O3E5bImRe2MFQ=")[16:-16],
clear=base64.decodebytes(b"RQAAVOZ4QABAAUAaCgoAAgoKAAEIAPSqbAAAAlVdQfUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
),
CipherContext(
key=MESSAGE_KEY_2,
counter=2,
encrypt=0,
tag=int.from_bytes(base64.decodebytes(b"BAAAANg30DACAAAAAAAAANVl/HO/AF3XLEDRkTrZ/V7iOIWpZXRUWt3Xaj5pZx+L05YcIMinZnsoR1gjA0KunMnQPjBLXRwx+zH541MWDl9kX2/iT6RisxvvhDdooyunZ+VWV/JIUS31WWE10cWyKk/j47mqdGGCj8ZDP/LlkvM=")[-16:], "little"),
cipher=base64.decodebytes(b"BAAAANg30DACAAAAAAAAANVl/HO/AF3XLEDRkTrZ/V7iOIWpZXRUWt3Xaj5pZx+L05YcIMinZnsoR1gjA0KunMnQPjBLXRwx+zH541MWDl9kX2/iT6RisxvvhDdooyunZ+VWV/JIUS31WWE10cWyKk/j47mqdGGCj8ZDP/LlkvM=")[16:-16],
clear=base64.decodebytes(b"RQAAVKKZAABAAcP5CgoAAQoKAAIAAPyqbAAAAlVdQfUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
),
CipherContext(
key=MESSAGE_KEY_2,
counter=3,
encrypt=0,
tag=int.from_bytes(base64.decodebytes(b"BAAAANg30DADAAAAAAAAAPIVoyyT8QyqQd4enxQqF7LuwF57P7ArJTu0jKnZ04yUzfm7M5REwfdusioMH0qQDVMU+VSacW3qKTnW8QuQCLStPz1FDEcyFZzx31jXPEcB")[-16:], "little"),
cipher=base64.decodebytes(b"BAAAANg30DADAAAAAAAAAPIVoyyT8QyqQd4enxQqF7LuwF57P7ArJTu0jKnZ04yUzfm7M5REwfdusioMH0qQDVMU+VSacW3qKTnW8QuQCLStPz1FDEcyFZzx31jXPEcB")[16:-16],
clear=base64.decodebytes(b"RQAAO7tHQABAEXNeCgoAAQEBAQHO1gA1ACeG3RAHAQAAAQAAAAAAAApsZWtlbnN0ZXluAm5sAAABAAE=")
),
CipherContext(
key=MESSAGE_KEY_2,
counter=4,
encrypt=0,
tag=int.from_bytes(base64.decodebytes(b"BAAAANg30DAEAAAAAAAAABF9QjZR6eDhFtX+gZMGK7RgtG9rxhmQ4PuWsusUcIYPVdpQvQHpvyIytVN8rghjlXFTjQPJwnS/u0azC5Y4ibNZtQc2MvPGw2CtNZvjdctJ")[-16:], "little"),
cipher=base64.decodebytes(b"BAAAANg30DAEAAAAAAAAABF9QjZR6eDhFtX+gZMGK7RgtG9rxhmQ4PuWsusUcIYPVdpQvQHpvyIytVN8rghjlXFTjQPJwnS/u0azC5Y4ibNZtQc2MvPGw2CtNZvjdctJ")[16:-16],
clear=base64.decodebytes(b"RQAAO7tIQABAEXNdCgoAAQEBAQHO1gA1ACfptZIuAQAAAQAAAAAAAApsZWtlbnN0ZXluAm5sAAAcAAE=")
),
CipherContext(
key=MESSAGE_KEY_1,
counter=4,
encrypt=1,
tag=int.from_bytes(base64.decodebytes(b"BAAAAAb0fasEAAAAAAAAABWYbKqqAh9E0OCEJSfZMrW0OjvWiMl6N1SSqbWOWlpzH/udELV5KSWtTc1/tc8zFwJLgxDy565wNIUvShAlls+Nj6KjHEZQU7rylH8u4iIOAlrs0XkD1ZIy/hxPxSjUuA==")[-16:], "little"),
cipher=base64.decodebytes(b"BAAAAAb0fasEAAAAAAAAABWYbKqqAh9E0OCEJSfZMrW0OjvWiMl6N1SSqbWOWlpzH/udELV5KSWtTc1/tc8zFwJLgxDy565wNIUvShAlls+Nj6KjHEZQU7rylH8u4iIOAlrs0XkD1ZIy/hxPxSjUuA==")[16:-16],
clear=base64.decodebytes(b"RQAASwAAAAA/EW+WAQEBAQoKAAEANc7WADcuQhAHgYAAAQABAAAAAApsZWtlbnN0ZXluAm5sAAABAAHADAABAAEAABa0AASyFXD7")
),
# # should be a keepalive packet here!
CipherContext(
key=MESSAGE_KEY_1,
counter=5,
encrypt=1,
tag=int.from_bytes(base64.decodebytes(b"BAAAAAb0fasFAAAAAAAAAHzSuzTFBRFN2GIycujWryZhjoTccbQKpugYmS8w5csSlEO35wpTpXn74TShqfQhNbHxTNwm45kLUL0pozLrNiiGz5U4G7m0lBYDj9b4eeZSfArymZOe0BfYt8w5dx0DUHs53v4xdEC2aBlsMBmv3k0=")[-16:], "little"),
cipher=base64.decodebytes(b"BAAAAAb0fasFAAAAAAAAAHzSuzTFBRFN2GIycujWryZhjoTccbQKpugYmS8w5csSlEO35wpTpXn74TShqfQhNbHxTNwm45kLUL0pozLrNiiGz5U4G7m0lBYDj9b4eeZSfArymZOe0BfYt8w5dx0DUHs53v4xdEC2aBlsMBmv3k0=")[16:-16],
clear=base64.decodebytes(b"RQAAVwABAAA/EW+JAQEBAQoKAAEANc7WAEMO1ZIugYAAAQABAAAAAApsZWtlbnN0ZXluAm5sAAAcAAHADAAcAAEAABa0ABAqAiMIAAAAAAAAA2AAAQAB")
),
# Another keepalive here
CipherContext(
key=MESSAGE_KEY_4,
counter=0,
encrypt=0,
tag=int.from_bytes(base64.decodebytes(b"BAAAAMVB/b8AAAAAAAAAAK/Th71y1FBFIYi8O6d3P0Dlyte5Dy3zQrD41/6Iiros3Rr6pibFKWWyujj0RpPWIvEWJtCUnKJP9dPZREqfmAuazNKRjiugpL4wSnjpHiz+=")[-16:], "little"),
cipher=base64.decodebytes(b"BAAAAMVB/b8AAAAAAAAAAK/Th71y1FBFIYi8O6d3P0Dlyte5Dy3zQrD41/6Iiros3Rr6pibFKWWyujj0RpPWIvEWJtCUnKJP9dPZREqfmAuazNKRjiugpL4wSnjpHiz+")[16:-16],
clear=base64.decodebytes(b"RQAAPJioQABABnT4CgoAAbIVcPvBQAG7ixsUqAAAAACgAmvQUbcAAAIEBWQEAggKP6q7QwAAAAABAwMH")
),
CipherContext(
key=MESSAGE_KEY_3,
counter=1,
encrypt=1,
tag=int.from_bytes(base64.decodebytes(b"BAAAALme3iYBAAAAAAAAAHmKtCxsplQ4V+bzmLxkrd9iIszgAclV26wj8hAtodPOi3wBBJXT5BZoBmhf76dAgwci+WAo8Neeizq/4Yu+pYQ=")[-16:], "little"),
cipher=base64.decodebytes(b"BAAAALme3iYBAAAAAAAAAHmKtCxsplQ4V+bzmLxkrd9iIszgAclV26wj8hAtodPOi3wBBJXT5BZoBmhf76dAgwci+WAo8Neeizq/4Yu+pYQ=")[16:-16],
clear=base64.decodebytes(b"RQAALAACAAA/Bk6vshVw+woKAAEBu8FAAAD6AYsbFKlgEiAA7jgAAAIEBbQ=")
),
CipherContext(
key=MESSAGE_KEY_4,
counter=1,
encrypt=0,
tag=int.from_bytes(base64.decodebytes(b"BAAAAMVB/b8BAAAAAAAAAHvtESOQTU9ahgXtzw/OK8TvEsrjCkFEAnAcitOFqhqbeqmDtelwklfvLbxyLP9aRPReulhCY3luOLwB57MU6aw=")[-16:], "little"),
cipher=base64.decodebytes(b"BAAAAMVB/b8BAAAAAAAAAHvtESOQTU9ahgXtzw/OK8TvEsrjCkFEAnAcitOFqhqbeqmDtelwklfvLbxyLP9aRPReulhCY3luOLwB57MU6aw=")[16:-16],
clear=base64.decodebytes(b"RQAAKJipQABABnULCgoAAbIVcPvBQAG7ixsUqQAA+gJQEGvQuiUAAA==")
),
CipherContext(
key=MESSAGE_KEY_3,
counter=2,
encrypt=1,
tag=int.from_bytes(base64.decodebytes(b"BAAAALme3iYCAAAAAAAAAMdVYbYHeBkuhSpOOkGEh/rIwcKv4a+17BEgv+T7DY4Ksivu3gNm0DXUh/hpgZ/lhqbgPT1+GUWUOQMypr/T1Nw=")[-16:], "little"),
cipher=base64.decodebytes(b"BAAAALme3iYCAAAAAAAAAMdVYbYHeBkuhSpOOkGEh/rIwcKv4a+17BEgv+T7DY4Ksivu3gNm0DXUh/hpgZ/lhqbgPT1+GUWUOQMypr/T1Nw=")[16:-16],
clear=base64.decodebytes(b"RQAAKAADAAA/Bk6yshVw+woKAAEBu8FAAAD6AosbFYFQECI4AuYAAA==")
),
CipherContext(
key=MESSAGE_KEY_3,
counter=3,
encrypt=1,
tag=int.from_bytes(base64.decodebytes(b"BAAAALme3iYDAAAAAAAAAK0SmHnTT056FRHPMd66WYNlCDTwvJhkJx79R5psrl+fL/89gBZYHL2mjT9C+55tJuUVjHXYKMYdEVgn2he8p65W7BheKppBmq3mKfRezs8pRpgGVO4yI03t5BponGYn8xC71VtMPWxpBYdy9HsHNiZj4jGT30O+WPrdQTL10beu6ao+qEXUUD1hVHSKcpgOGp/xll7AjPYs1OEt64exAfO8pFeZtQTp16cLuiPNqMld3EYh2p7lF/Ry9GO3lB9sp/PB6cfSOOvLViZ3wsiCF/Q7awYqFuCrcMjU1RQs7RPGW4fhiFazl9NsvSuBvWMII48keUCtkLnbqv9dBZM7BPCVePAwFW5iPZOa7vkxaPF6pqWDSgTwRiLICiix5wQL0a0cBpgMxryNCxmvyRKUyRdo1RFMayfXFOp+6DqmUrNbBr3dnDGE87XuAkOnx9m/DR/yBI/iiePSCnsxeyJVwtBVJeDdzwZAyrVR9vYFfyVRH4MirZYuw33VkTA98OEXcqrdTSOvsTn04JL/1DmKTjdj8HHjtuBism6vOofdrFRmVSREAiE5tI4HecIkZV/iu2345JIe8FTWZZVfvIVG9VamkHPLe0gBQR4eeLfUWIlRQrU+aiWQBaZKMxooyYwZPZGTlUtKmU/Q1/cJ9GeBKuD6Txge+/okOlqvPXgCHeyiAiSHVJ/2lWHTK7BPyPwcIik3q+dIUpIwL5/7doYDcezpnscB5o/KjAvBw3YwqAuNLyVuqFrMGti1eCTi1ll016slCEbDGRvHYielCtdzkw7vYhIPE+k37FxXByoJ3jg5NlOrbRoVvO25Hy2rP4SYMmQ3dEQNRDVkCy8yvQRSAI1UOknXnpDo+SU50FKcmdB94htpRM+ddADNUmJPD7JJAI8AFgkMN7Zujgq7v2ZSXNhpDX1MD+7zdYUwu8GsldMKTYtz+BaShoJtcSSmXYdAup8i12lGBtJJf7FxANSweg5bHgr3OE9VLJZq5JIKhY+0cIKRF8ymI5of9vXETGT7JQe26QVn8zekevI183yiqS5qbxqdt96eT1/W8mF/2TNCYBgiP135gKwVoS3ZY/0kWrx5oN0TXSGjMkRnhucEjsw5W18CFJo+labHkmuZUJ+rdVfEviady27EwgIcU2sGWPWn7jw+WPOG+709CBGtfw7/Ld6MDmNsvT9m7mvTKOVIHxJyaiA997y9P4FD4mjjlHbtncJRtUeqrW4GXrQouF9ur2+OIMAkmo1jz51j6UbyT2RUwr+ABWfwfHUxDzwxRuhj0rodw3a3ZiFtGqIXYeDavMOE3Okn/zSGETIHOnfTufGBddxSRaOUGGMv6xBXzzq+qja6JMLx/M15yhTQE2NpVrNevbrMBBE7TdOVyZP4AdvQOByO1AcTjKtOgKaPfUQeHjn21/43VO9VhnNqozlU5n1ud+xxE+CKwt7kQ9TOn4UVF/x4poIJdV851jIehBZNR+ntWFPr4wc6WMggOJ3//UWKiAvKXrsKk3YsJLdVKIqBnXD3tewpb324LVkizIaUNH1ZWWAxZa/B1Rn3K8fwKl73G+d6I6uNcz0RiiAEYKoEkN7Web3KmIQYIyT4UN2I4HfjRy0i0rXEuEevDarBbfww+fgefYf9lu3hgre4/XMuuuBnjKK4+3BNkT9ipmOzm0gH3LT470OWEDFqm+SaIVW//VdijHsWJkFiSdD8QFYQtjgII1+d1XWXmZdocWm2iDje+4CX/14b+ZQgpWWgHJ+RiYOjEWnNzRtNyy9FrkQxzzlCIgz6hu+E8eDQExP7qunniB6UBPTkmutaaNXhrG4/oWT4yBx0HAmI/VrA/M/AmsDlRpp8MO0zwFQuLbb6aXm1CO88TIeCkXbCsYiy13edfJbf0FsLhIp4P9ZqX07Ug6SKcT8ZjHkc")[-16:], "little"),
cipher=base64.decodebytes(b"BAAAALme3iYDAAAAAAAAAK0SmHnTT056FRHPMd66WYNlCDTwvJhkJx79R5psrl+fL/89gBZYHL2mjT9C+55tJuUVjHXYKMYdEVgn2he8p65W7BheKppBmq3mKfRezs8pRpgGVO4yI03t5BponGYn8xC71VtMPWxpBYdy9HsHNiZj4jGT30O+WPrdQTL10beu6ao+qEXUUD1hVHSKcpgOGp/xll7AjPYs1OEt64exAfO8pFeZtQTp16cLuiPNqMld3EYh2p7lF/Ry9GO3lB9sp/PB6cfSOOvLViZ3wsiCF/Q7awYqFuCrcMjU1RQs7RPGW4fhiFazl9NsvSuBvWMII48keUCtkLnbqv9dBZM7BPCVePAwFW5iPZOa7vkxaPF6pqWDSgTwRiLICiix5wQL0a0cBpgMxryNCxmvyRKUyRdo1RFMayfXFOp+6DqmUrNbBr3dnDGE87XuAkOnx9m/DR/yBI/iiePSCnsxeyJVwtBVJeDdzwZAyrVR9vYFfyVRH4MirZYuw33VkTA98OEXcqrdTSOvsTn04JL/1DmKTjdj8HHjtuBism6vOofdrFRmVSREAiE5tI4HecIkZV/iu2345JIe8FTWZZVfvIVG9VamkHPLe0gBQR4eeLfUWIlRQrU+aiWQBaZKMxooyYwZPZGTlUtKmU/Q1/cJ9GeBKuD6Txge+/okOlqvPXgCHeyiAiSHVJ/2lWHTK7BPyPwcIik3q+dIUpIwL5/7doYDcezpnscB5o/KjAvBw3YwqAuNLyVuqFrMGti1eCTi1ll016slCEbDGRvHYielCtdzkw7vYhIPE+k37FxXByoJ3jg5NlOrbRoVvO25Hy2rP4SYMmQ3dEQNRDVkCy8yvQRSAI1UOknXnpDo+SU50FKcmdB94htpRM+ddADNUmJPD7JJAI8AFgkMN7Zujgq7v2ZSXNhpDX1MD+7zdYUwu8GsldMKTYtz+BaShoJtcSSmXYdAup8i12lGBtJJf7FxANSweg5bHgr3OE9VLJZq5JIKhY+0cIKRF8ymI5of9vXETGT7JQe26QVn8zekevI183yiqS5qbxqdt96eT1/W8mF/2TNCYBgiP135gKwVoS3ZY/0kWrx5oN0TXSGjMkRnhucEjsw5W18CFJo+labHkmuZUJ+rdVfEviady27EwgIcU2sGWPWn7jw+WPOG+709CBGtfw7/Ld6MDmNsvT9m7mvTKOVIHxJyaiA997y9P4FD4mjjlHbtncJRtUeqrW4GXrQouF9ur2+OIMAkmo1jz51j6UbyT2RUwr+ABWfwfHUxDzwxRuhj0rodw3a3ZiFtGqIXYeDavMOE3Okn/zSGETIHOnfTufGBddxSRaOUGGMv6xBXzzq+qja6JMLx/M15yhTQE2NpVrNevbrMBBE7TdOVyZP4AdvQOByO1AcTjKtOgKaPfUQeHjn21/43VO9VhnNqozlU5n1ud+xxE+CKwt7kQ9TOn4UVF/x4poIJdV851jIehBZNR+ntWFPr4wc6WMggOJ3//UWKiAvKXrsKk3YsJLdVKIqBnXD3tewpb324LVkizIaUNH1ZWWAxZa/B1Rn3K8fwKl73G+d6I6uNcz0RiiAEYKoEkN7Web3KmIQYIyT4UN2I4HfjRy0i0rXEuEevDarBbfww+fgefYf9lu3hgre4/XMuuuBnjKK4+3BNkT9ipmOzm0gH3LT470OWEDFqm+SaIVW//VdijHsWJkFiSdD8QFYQtjgII1+d1XWXmZdocWm2iDje+4CX/14b+ZQgpWWgHJ+RiYOjEWnNzRtNyy9FrkQxzzlCIgz6hu+E8eDQExP7qunniB6UBPTkmutaaNXhrG4/oWT4yBx0HAmI/VrA/M/AmsDlRpp8MO0zwFQuLbb6aXm1CO88TIeCkXbCsYiy13edfJbf0FsLhIp4P9ZqX07Ug6SKcT8ZjHkc")[16:-16],
clear=base64.decodebytes(b"RQAFjAAEIAA/BilNshVw+woKAAEBu8FAAAD6AosbFYFQECI4yD0AABYDAwBqAgAAZgMDqpKMTdCadtmNVjGh3gODkvSKTc0qQdGxOZTbaOOBJMIgQMCBb2mtCP0D7maJrcd1gyat2SYsDc5UpGvLnuGuF3vALwAAHgAAAAD/AQABAAALAAQDAAECM3QACQhodHRwLzEuMRYDAwq+CwAKugAKtwAGGzCCBhcwggT/oAMCAQICEgNjl8IYWbinreQPsgP6+V5FoDANBgkqhkiG9w0BAQsFADBKMQswCQYDVQQGEwJVUzEWMBQGA1UEChMNTGV0J3MgRW5jcnlwdDEjMCEGA1UEAxMaTGV0J3MgRW5jcnlwdCBBdXRob3JpdHkgWDMwHhcNMTgwNzE1MjEwODM2WhcNMTgxMDEzMjEwODM2WjAYMRYwFAYDVQQDEw1sZWtlbnN0ZXluLm5sMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuVUnC61jiWQv+1/cA4RTj2AqZ5uVNlcpuWO+OEiuZyclfbXE+5w115ixULQhzI6nroJaF6T9SquuCrTxUcoKSlYpAkosCe5ne6BqY8jCJTiDhNhcIKjta/mbJzfCSJ0ZEo7sry3xOtnr50iOhmEJfXsfbDpHADCNZst/+G5YnXGEh5a0yuRo4v6CBHaNd0rO1+HxhhL//uFGy2EiP8J9xSQg8mmFIIBhKyYbw/0TvhiscsOozkoBT1E035IHeTXbdM8/EyWw60CEqgfucKbCW+Kd02hOIe3pduvVmsUKBq9ix5lgxfagWci48+Rw8LUfUlg3kxcbmM2oRpL1OZ5KmwIDAQABo4IDJzCCAyMwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTh2YXInDbV8qE3u7gB+8X5THYuNjAfBgNVHSMEGDAWgBSoSmpjBH3duubRObemRWXv86jsoTBvBggrBgEFBQcBAQRjMGEwLgYIKwYBBQUHMAGGImh0dHA6Ly9vY3NwLmludC14My5sZXRzZW5jcnlwdC5vcmcwLwYIKwYBBQUHMAKGI2h0dHA6Ly9jZXJ0LmludC14My5sZXRzZW5jcnlwdC5vcmcvMCsGA1UdEQQkMCKCDWxla2Vuc3RleW4ubmyCEXd3dy5sZWtlbnN0ZXluLm5sMIH+BgNVHSAEgfYwgfMwCAYGZ4EMAQIBMIHmBgsrBgEEAYLfEwEBATCB1jAmBggrBgEFBQcCARYaaHR0cDovL2Nwcy5sZXRzZW5jcnlwdC5vcmcwgasGCCsGAQUFBwICMIGeDIGbVGhpcyBDZXJ0aWZpY2F0ZSBtYXkgb25seSBiZSByZWxpZWQgdXBvbiBieSBSZWx5aW5nIFBhcnRpZXMgYW5kIG9ubHkgaW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBDZXJ0aWZpY2F0ZSBQb2xpY3kgZm91bmQgYXQgaHR0cHM6Ly9sZXRzZW5jcnlwdC5vcmcvcmVwb3NpdG9yeS8wggEDBgorBgEEAdZ5AgQCBIH0BIHxAO8AdgApPFGWVMg5ZbqqUPxYB9S3b79Yeily3KTDDPTlRUf0eAAAAWSf/QPTAAAEAwBHMEUCIQDu0y+NGbIdvkKji76RH7MrpOuDhRpCbhBgwqEsKUPZFAIgGOq0Lyi2seniX907uqGuMAXdERxs9/NKutzK6GX43TIAdQBVgdTCFpA2AUrqC5tXPFPwwOQ4eHAlCBcvo6odBxPTDAAAAWSf/QdnAAAEAwBGMEQCIHz8RGU2c48kG9uZJdxNfE4ppp7xHMuYT22MAp1gM5nUAg==")
),
]
tag_queue = Queue()
async def tag_output_process(dut):
while True:
if dut.o_mac_valid.value:
await tag_queue.put(int(dut.o_mac.value))
await RisingEdge(dut.i_clk)
@cocotb.test
async def test_real_packet(dut):
cocotb.start_soon(Clock(dut.i_clk, CLK_PERIOD, unit="ns").start())
cocotb.start_soon(receieve_output(dut))
cocotb.start_soon(tag_output_process(dut))
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)
for pkt in PACKETS:
dut.i_nonce.value = pkt.counter << 32
dut.i_key.value = pkt.key
dut.i_encrypt.value = pkt.encrypt
msg = pkt.clear if pkt.encrypt else pkt.cipher
dut.i_data_ready.value = 1
dut.i_last.value = 0
dut.i_valid.value = 1
while len(msg) > 0:
part = msg[0:4]
dut.i_data.value = int.from_bytes(part, "little")
dut.i_countm1.value = len(part)-1
if len(msg) <= 4:
dut.i_last.value = 1
msg = msg[4:]
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
dut.i_nonce.value = 0
dut.i_key.value = 0
for i, pkt in enumerate(PACKETS):
packet = await output_queue.get()
expected = pkt.cipher if pkt.encrypt else pkt.clear
# The packet is rounded up to 16 bytes before encryption, but based on the IP length we
# are supposed to truncate it. That would happen outside of this block though.
if expected not in packet:
print(f"{i}: Packets didn't match!")
print(f"expected={expected} actual={packet}")
tag = await tag_queue.get()
if tag != pkt.tag:
print(f"{i}: Tags did not match!")
print(f"expected={pkt.tag:x} actual={tag:x}")
await Timer(10, "us")

View File

@@ -1,4 +1,5 @@
from typing import List
import random
from modulo_theory import friendly_modular_mult, friendly_modulo
@@ -111,11 +112,19 @@ def test_on_long_string():
print(f"{regular_result:x}")
print(f"{parallel_result:x}")
def test_random():
r = mask_r(random.randint(0, 2**128-1))
s = random.randint(0, 2**128-1)
msg = random.randbytes(random.randint(16, 1500))
parallel_poly1305(msg, r, s, 8)
def main():
test_regular()
test_parallel()
test_on_long_string()
test_random()
if __name__ == "__main__":
main()

View File

@@ -57,7 +57,6 @@ def friendly_modular_mult(value_a: int, value_b: int) -> int:
mods = [friendly_modulo(prod, 26*i) for i, prod in enumerate(prods)]
mod_sum = friendly_modulo(sum(mods), 0)
return mod_sum

View File

@@ -5,9 +5,39 @@ tests:
- "poly1305_core"
sources: "sources.list"
waves: True
- name: "friendly_modulo"
- name: "poly1305_friendly_modulo"
toplevel: "poly1305_friendly_modulo"
modules:
- "poly1305_friendly_modulo"
sources: sources.list
waves: True
- name: "poly1305_friendly_modular_mult"
toplevel: "poly1305_friendly_modular_mult"
modules:
- "poly1305_friendly_modular_mult"
sources: sources.list
waves: True
- name: "poly1305_stage"
toplevel: "poly1305_stage"
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
- name: "chacha20_poly1305_32_ll_core"
toplevel: "chacha20_poly1305_32_ll_core"
modules:
- "chacha20_poly1305_32_ll_core"
sources: sources.list
waves: True

View File

@@ -0,0 +1,96 @@
import logging
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import Timer, RisingEdge, FallingEdge
from cocotb.queue import Queue
from cocotbext.axi import AxiStreamBus, AxiStreamSource
from modulo_theory import friendly_modular_mult
import random
PRIME = 2**130-5
CLK_PERIOD = 4
class TB:
def __init__(self, dut):
self.dut = dut
self.log = logging.getLogger("cocotb.tb")
self.log.setLevel(logging.INFO)
self.input_queue = Queue()
self.expected_queue = Queue()
self.output_queue = Queue()
cocotb.start_soon(Clock(self.dut.i_clk, CLK_PERIOD, units="ns").start())
cocotb.start_soon(self.run_input())
cocotb.start_soon(self.run_output())
async def cycle_reset(self):
await self._cycle_reset(self.dut.i_rst, self.dut.i_clk)
async def _cycle_reset(self, rst, clk):
rst.setimmediatevalue(0)
await RisingEdge(clk)
await RisingEdge(clk)
rst.value = 1
await RisingEdge(clk)
await RisingEdge(clk)
rst.value = 0
await RisingEdge(clk)
await RisingEdge(clk)
async def write_input(self, data: int, h: int):
await self.input_queue.put((data, h))
await self.expected_queue.put(friendly_modular_mult(h, data))
async def run_input(self):
while True:
data, h = await self.input_queue.get()
self.dut.i_valid.value = 1
self.dut.i_data.value = data
self.dut.i_accumulator.value = h
while True:
await RisingEdge(self.dut.i_clk)
if (self.dut.o_ready.value == 1):
break
self.dut.i_valid.value = 0
self.dut.i_data.value = 0
self.dut.i_accumulator.value = 0
async def run_output(self):
while True:
await RisingEdge(self.dut.i_clk)
if self.dut.o_valid.value:
await self.output_queue.put(self.dut.o_result.value.integer)
@cocotb.test
async def test_sanity(dut):
tb = TB(dut)
await tb.cycle_reset()
count = 1
for _ in range(count):
await tb.write_input(random.randint(1,2**128-1), random.randint(0, 2**130-6))
fail = False
for _ in range(count):
sim_val = await tb.expected_queue.get()
dut_val = await tb.output_queue.get()
if sim_val != dut_val:
tb.log.info(f"{sim_val:x} -> {dut_val:x}")
fail = True
assert not fail

View File

@@ -88,4 +88,23 @@ async def test_sanity(dut):
tb.log.info(f"{sim_val:x} -> {dut_val:x}")
fail = True
assert not fail
@cocotb.test
async def test_directed(dut):
tb = TB(dut)
await tb.cycle_reset()
await tb.write_input(0x14C0D69391E7116E057E7AD833B00B706AA2390C, 4)
fail = False
sim_val = await tb.expected_queue.get()
dut_val = await tb.output_queue.get()
if sim_val != dut_val:
tb.log.info(f"{sim_val:x} -> {dut_val:x}")
fail = True
assert not fail

View File

@@ -0,0 +1,73 @@
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 _ in range(2):
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,111 @@
import logging
import cocotb
from cocotb.clock import Clock
from cocotb.triggers import Timer, RisingEdge, FallingEdge
from cocotb.queue import Queue
from cocotb.handle import Immediate
from cocotbext.axi import AxiStreamBus, AxiStreamSource
from modulo_theory import friendly_modular_mult
import random
PRIME = 2**130-5
CLK_PERIOD = 4
class TB:
def __init__(self, dut):
self.dut = dut
self.log = logging.getLogger("cocotb.tb")
self.log.setLevel(logging.INFO)
self.input_queue = Queue()
self.expected_queue = Queue()
self.output_queue = Queue()
cocotb.start_soon(Clock(self.dut.i_clk, CLK_PERIOD, unit="ns").start())
cocotb.start_soon(self.run_input())
cocotb.start_soon(self.run_output())
self.index = 0
self.accumulators = [0, 0]
async def cycle_reset(self):
await self._cycle_reset(self.dut.i_rst, self.dut.i_clk)
async def _cycle_reset(self, rst, clk):
rst.value = Immediate(0)
await RisingEdge(clk)
await RisingEdge(clk)
rst.value = 1
await RisingEdge(clk)
await RisingEdge(clk)
rst.value = 0
await RisingEdge(clk)
await RisingEdge(clk)
async def write_input(self, msg: int, r_power: int, clear_acc: int):
await self.input_queue.put((msg, r_power, clear_acc))
if clear_acc:
expected_result = friendly_modular_mult((msg) % PRIME, r_power)
else:
expected_result = friendly_modular_mult((msg + self.accumulators[self.index]) % PRIME, r_power)
self.accumulators[self.index] = expected_result
await self.expected_queue.put(expected_result)
self.index = 1 if self.index == 0 else 0
async def run_input(self):
while True:
msg, r_power, clear_acc = await self.input_queue.get()
self.dut.i_valid.value = 1
self.dut.i_r_power.value = r_power
self.dut.i_message.value = msg
self.dut.i_clear_acc.value = clear_acc
while True:
await RisingEdge(self.dut.i_clk)
if (self.dut.o_ready.value == 1):
break
self.dut.i_valid.value = 0
self.dut.i_r_power.value = 0
self.dut.i_message.value = 0
self.dut.i_clear_acc.value = 0
async def run_output(self):
while True:
await RisingEdge(self.dut.i_clk)
if self.dut.o_valid.value:
await self.output_queue.put(self.dut.o_result.value.to_unsigned())
@cocotb.test
async def test_sanity(dut):
tb = TB(dut)
await tb.cycle_reset()
count = 1024
for _ in range(count):
clr = 1 if random.randint(0,10) == 0 else 0
await tb.write_input(random.randint(1,2**128-1), random.randint(0, 2**130-6), clr)
fail = False
for _ in range(count):
sim_val = await tb.expected_queue.get()
dut_val = await tb.output_queue.get()
if sim_val != dut_val:
tb.log.info(f"{_} {sim_val:x} -> {dut_val:x}")
fail = True
assert not fail

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

@@ -2,3 +2,8 @@ poly1305_core_wrapper.sv
../src/sources.list
../../common/sim/sub/taxi/src/axis/rtl/taxi_axis_if.sv
../../common/sim/sub/fifo/rtl/verilog/fifo_fwft_adapter.v
../../common/sim/sub/fifo/rtl/verilog/fifo.v
../../common/sim/sub/fifo/rtl/verilog/fifo_fwft.v
../../common/sim/sub/fifo/rtl/verilog/simple_dpram_sclk.v

View File

@@ -1,10 +1,10 @@
module chacha20_block #(
parameter KEY_SIZE = 256,
parameter COUNTER_SIZE = 64,
parameter NONCE_SIZE = 64,
parameter COUNTER_SIZE = 32,
parameter NONCE_SIZE = 96,
parameter STATE_SIZE = 512,
parameter ROUNDS = 20,
parameter CONSTANT = 128'h657870616e642033322d62797465206b
parameter CONSTANT = 128'h617078653320646e79622d326b206574
)(
input logic i_clk,
input logic i_rst,
@@ -68,7 +68,7 @@ always_ff @(posedge i_clk) begin
initial_state_rptr <= '0;
initial_state_wptr <= '0;
end else begin
if (i_valid) begin
if (i_valid & i_ready) begin
initial_states[initial_state_wptr] <= write_initial_state;
if (initial_state_wptr < PIPE_STAGES-1) begin
initial_state_wptr <= initial_state_wptr + 1;
@@ -77,9 +77,8 @@ always_ff @(posedge i_clk) begin
end
end
pre_add_valid <= valid[ROUNDS][0];
if (valid[ROUNDS][0]) begin
if (valid[ROUNDS][0] & i_ready) begin
read_initial_state <= initial_states[initial_state_rptr];
if (initial_state_rptr < PIPE_STAGES-1) begin
initial_state_rptr <= initial_state_rptr + 1;
@@ -92,13 +91,16 @@ always_ff @(posedge i_clk) begin
end
o_valid <= pre_add_valid;
if (i_ready) begin
pre_add_valid <= valid[ROUNDS][0];
o_valid <= pre_add_valid;
// We cannot just add state_pre_add and read_initial state
// because the addition needs to be done wordwise, with no
// carries between 32 bit groups.
for (int i = 0; i < 16; i++) begin
o_state[i*32 +: 32] <= state_pre_add[i*32 +: 32] + read_initial_state[i*32 +: 32];
// We cannot just add state_pre_add and read_initial state
// because the addition needs to be done wordwise, with no
// carries between 32 bit groups.
for (int i = 0; i < 16; i++) begin
o_state[i*32 +: 32] <= state_pre_add[i*32 +: 32] + read_initial_state[i*32 +: 32];
end
end
end
@@ -115,10 +117,10 @@ always_comb begin
end
state[0][12] = i_counter[0 +: 32];
state[0][13] = i_counter[32 +: 32];
state[0][14] = i_nonce[0 +: 32];
state[0][15] = i_nonce[32 +: 32];
state[0][13] = i_nonce[0 +: 32];
state[0][14] = i_nonce[32 +: 32];
state[0][15] = i_nonce[64 +: 32];
for (int i = 0; i < 4; i++) begin

View File

@@ -0,0 +1,324 @@
module chacha20_poly1305_32_ll_core (
input logic i_clk,
input logic i_rst,
input logic [255:0] i_key,
input logic [95:0] i_nonce,
input logic i_encrypt,
input logic [31:0] i_data,
input logic [1:0] i_countm1,
input logic i_last,
input logic i_valid,
output logic o_ready,
output logic [31:0] o_data,
output logic [1:0] o_data_countm1,
output logic o_data_last,
output logic o_data_valid,
input logic i_data_ready,
// no backpressure for the poly1305 output
output logic [127:0] o_mac,
output logic o_mac_valid
);
logic [255:0] chacha_key;
logic [31:0] chacha_counter;
logic [95:0] chacha_nonce;
logic chacha_i_valid;
logic chacha_i_ready;
logic [511:0] chacha_state;
logic chacha_o_valid;
logic chacha_o_ready;
logic poly1305_i_valid;
logic [1:0] poly1305_countm1;
logic poly1305_i_ready;
logic [31:0] poly1305_data;
logic poly1305_last;
logic [127:0] poly1305_r;
logic [127:0] poly1305_s;
logic downconvert_i_valid;
logic [1:0] downconvert_countm1;
logic downconvert_i_ready;
logic [31:0] downconvert_data;
logic downconvert_last;
logic poly1305_o_valid;
logic [127:0] poly1305_o_result;
logic [511:0] fifo_data;
logic [5:0] fifo_countm1;
logic fifo_last;
logic fifo_rd_en;
logic fifo_empty;
logic fifo_full;
logic fifo_valid;
logic upconvert_ready;
logic upconvert_valid;
logic upconvert_last;
logic [511:0] upconvert_data;
logic [5:0] upconvert_countm1;
logic ciphertext_ready;
logic ciphertext_valid;
logic ciphertext_last;
logic [511:0] ciphertext_data;
logic [5:0] ciphertext_countm1;
logic ciphertext_skid_ready;
logic ciphertext_skid_valid;
logic ciphertext_skid_last;
logic [511:0] ciphertext_skid_data;
logic [5:0] ciphertext_skid_countm1;
logic [511:0] post_data;
logic post_skid_ready;
logic post_skid_valid;
logic post_skid_last;
logic [511:0] post_skid_data;
logic [5:0] post_skid_countm1;
logic meta_fifo_encrypt;
logic meta_fifo_read;
logic meta_fifo_empty;
logic input_fsm_short_packet;
assign chacha_nonce = i_nonce;
assign chacha_key = i_key;
assign fifo_valid = ~fifo_empty;
assign o_mac_valid = poly1305_o_valid;
assign o_mac = poly1305_o_result;
poly1305_width_convert_2 u_chacha_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 & chacha_o_ready & ~input_fsm_short_packet),
.o_data (upconvert_data),
.o_last (upconvert_last)
);
assign upconvert_ready = ~fifo_full;
logic sop;
logic in_pkt;
always_ff @(posedge i_clk) begin
if (i_rst) begin
in_pkt <= '0;
end else begin
if (i_valid & o_ready) begin
if (i_last) begin
in_pkt <= '0;
end else begin
in_pkt <= '1;
end
end
end
end
assign sop = i_valid & o_ready & ~in_pkt;
fifo_fwft #(
.DATA_WIDTH(512+6+1),
.DEPTH_WIDTH(8)
) u_input_fifo (
.clk (i_clk),
.rst (i_rst),
.din ({upconvert_data, upconvert_countm1, upconvert_last}),
.wr_en (upconvert_valid & chacha_o_ready & ~input_fsm_short_packet),
.full (fifo_full), // probably wrong, think about this
.dout ({fifo_data, fifo_countm1, fifo_last}),
.rd_en (fifo_rd_en),
.empty (fifo_empty)
);
fifo_fwft #(
.DATA_WIDTH(1), // can increase when we have more metadata
.DEPTH_WIDTH(4)
) u_meta_fifo (
.clk (i_clk),
.rst (i_rst),
.din (i_encrypt),
.wr_en (sop),
.full (),
.dout (meta_fifo_encrypt),
.rd_en (meta_fifo_read),
.empty (meta_fifo_empty)
);
chacha20_poly1305_input_fsm u_chacha20_poly1305_input_fsm (
.i_clk (i_clk),
.i_rst (i_rst),
.i_valid (upconvert_valid),
.i_last (upconvert_last),
.o_short_packet (input_fsm_short_packet),
.o_counter (chacha_counter),
.chacha_valid (chacha_i_valid),
.chacha_ready (chacha_i_ready)
);
chacha20_block u_chacha20_block (
.i_clk (i_clk),
.i_rst (i_rst),
.i_key (chacha_key),
.i_counter (chacha_counter),
.i_nonce (chacha_nonce),
.i_valid (chacha_i_valid),
.o_ready (chacha_i_ready),
.o_state (chacha_state),
.o_valid (chacha_o_valid),
.i_ready (chacha_o_ready)
);
chacha20_poly1305_mid_fsm u_mid_fsm (
.i_clk (i_clk),
.i_rst (i_rst),
.i_chacha_state (chacha_state),
.i_chacha_valid (chacha_o_valid),
.o_chacha_ready (chacha_o_ready),
.i_metadata_din (meta_fifo_encrypt),
.o_metadata_read (meta_fifo_read),
.i_fifo_data (fifo_data),
.i_fifo_countm1 (fifo_countm1),
.i_fifo_valid (fifo_valid),
.i_fifo_last (fifo_last),
.o_fifo_rd_en (fifo_rd_en),
.o_ciphertext (ciphertext_data),
.o_post (post_data),
.o_ciphertext_countm1 (ciphertext_countm1),
.o_ciphertext_valid (ciphertext_valid),
.o_ciphertext_last (ciphertext_last),
.i_ciphertext_ready (ciphertext_ready),
// TODO this is most likely wrong.
.o_r (poly1305_r),
.o_s (poly1305_s)
);
logic rstn;
assign rstn = ~i_rst;
pipe_skid_buffer #(
.DWIDTH(512+512+6+1)
) u_ciphertext_skid_buffer (
.clk (i_clk),
.rstn (rstn),
.i_data ({post_data, ciphertext_data, ciphertext_countm1, ciphertext_last}),
.i_valid (ciphertext_valid),
.o_ready (ciphertext_ready),
.o_data ({post_skid_data, ciphertext_skid_data, ciphertext_skid_countm1, ciphertext_skid_last}),
.o_valid (ciphertext_skid_valid),
.i_ready (ciphertext_skid_ready)
);
poly1305_width_convert_3 u_pre_poly1305_width_convert (
.i_clk (i_clk),
.i_rst (i_rst),
.i_valid (ciphertext_skid_valid),
.i_countm1 (ciphertext_skid_countm1),
.o_ready (ciphertext_skid_ready),
.i_data (ciphertext_skid_data),
.i_last (ciphertext_skid_last),
.o_valid (poly1305_i_valid),
.o_countm1 (poly1305_countm1),
.i_ready (poly1305_i_ready & ~output_fifo_full),
.o_data (poly1305_data),
.o_last (poly1305_last)
);
poly1305_width_convert_3 u_output_width_convert (
.i_clk (i_clk),
.i_rst (i_rst),
.i_valid (ciphertext_skid_valid),
.i_countm1 (ciphertext_skid_countm1),
.o_ready (),
.i_data (post_skid_data),
.i_last (ciphertext_skid_last),
.o_valid (downconvert_i_valid),
.o_countm1 (downconvert_countm1),
.i_ready (poly1305_i_ready & ~output_fifo_full),
.o_data (downconvert_data),
.o_last (downconvert_last)
);
fifo_fwft #(
.DATA_WIDTH(32+1),
.DEPTH_WIDTH(4)
) u_output_fifo (
.clk (i_clk),
.rst (i_rst),
.din ({downconvert_data, downconvert_last}),
.wr_en (downconvert_i_valid & poly1305_i_ready & ~output_fifo_full),
.full (output_fifo_full),
.dout ({o_data, o_data_last}),
.rd_en (o_data_valid & i_data_ready),
.empty (output_fifo_empty)
);
assign o_data_valid = ~output_fifo_empty;
logic output_fifo_full;
logic output_fifo_empty;
// if output fifo is not ready, we need to backpressure poly1305
poly1305_ll_stage u_poly1305_ll_stage (
.i_clk (i_clk),
.i_rst (i_rst),
.i_valid (poly1305_i_valid & ~output_fifo_full),
.i_countm1 (poly1305_countm1),
.o_ready (poly1305_i_ready),
.i_data (poly1305_data),
.i_last (poly1305_last),
.i_r (poly1305_r),
.i_s (poly1305_s),
.o_valid (poly1305_o_valid),
.o_result (poly1305_o_result)
);
endmodule

View File

@@ -0,0 +1,104 @@
module chacha20_poly1305_input_fsm (
input logic i_clk,
input logic i_rst,
input logic i_valid,
input logic i_last,
output logic [31:0] o_counter,
output logic o_short_packet,
output logic chacha_valid,
input logic chacha_ready
);
enum logic [1:0] {IDLE, ACTIVE1, ACTIVE2, ACTIVE3} state, state_next;
logic [31:0] counter, counter_next;
// in case the first beat is also the last one.
logic last_flag, last_flag_next;
assign o_counter = counter;
always_ff @(posedge i_clk) begin
if (i_rst) begin
state <= IDLE;
counter <= '0;
last_flag <= '0;
end else begin
state <= state_next;
counter <= counter_next;
last_flag <= last_flag_next;
end
end
always_comb begin
state_next = state;
counter_next = counter;
last_flag_next = '0;
chacha_valid = '0;
o_short_packet = '0;
case (state)
IDLE: begin
counter_next = '0;
chacha_valid = '0;
if (i_valid) begin
chacha_valid = '1;
if (chacha_ready) begin
state_next = ACTIVE1;
counter_next = counter + 1;
last_flag_next = i_last;
// if the first beat is also the last, then lower ready so that
// we run chacha for 2 cycles instead of 1, and keep the key valid.
if (i_last) begin
o_short_packet = '1;
end
end
end
end
ACTIVE1: begin
chacha_valid = '1;
if (chacha_ready) begin
state_next = ACTIVE2;
counter_next = counter + 1;
end
if (i_last || last_flag) begin
state_next = IDLE;
counter_next = '0;
end
end
ACTIVE2: begin
if (i_valid) begin
chacha_valid = '1;
if (chacha_ready) begin
counter_next = counter + 1;
if (i_last || last_flag) begin
state_next = IDLE;
counter_next = '0;
end
end
end
end
default: begin
state_next = IDLE;
end
endcase
end
endmodule

View File

@@ -0,0 +1,114 @@
module chacha20_poly1305_mid_fsm (
input logic i_clk,
input logic i_rst,
input logic [511:0] i_chacha_state,
input logic i_chacha_valid,
output logic o_chacha_ready,
input logic [511:0] i_fifo_data,
input logic [5:0] i_fifo_countm1,
input logic i_fifo_valid,
input logic i_fifo_last,
output logic o_fifo_rd_en,
input logic [0:0] i_metadata_din,
output logic o_metadata_read,
output logic [511:0] o_ciphertext,
output logic [511:0] o_post,
output logic [5:0] o_ciphertext_countm1,
output logic o_ciphertext_valid,
output logic o_ciphertext_last,
input logic i_ciphertext_ready,
output logic [127:0] o_r,
output logic [127:0] o_s
);
localparam R_MASK = 128'h0ffffffc0ffffffc0ffffffc0fffffff;
logic encrypt;
assign encrypt = i_metadata_din[0];
enum logic {IDLE, DATA} state, state_next;
logic [127:0] r, r_next;
logic [127:0] s, s_next;
assign o_r = r;
assign o_s = s;
always_ff @(posedge i_clk) begin
if (i_rst) begin
state <= IDLE;
r <= '0;
s <= '0;
end else begin
state <= state_next;
r <= r_next;
s <= s_next;
end
end
always_comb begin
state_next = state;
r_next = r;
s_next = s;
o_fifo_rd_en = '0;
o_chacha_ready = i_ciphertext_ready;
o_ciphertext_valid = '0;
o_ciphertext_last = '0;
o_metadata_read = '0;
o_ciphertext = '0;
o_ciphertext_countm1 = '0;
o_post = '0;
case (state)
IDLE: begin
if (i_chacha_valid) begin
r_next = i_chacha_state[0 +: 128] & R_MASK;
s_next = i_chacha_state[128 +: 128];
state_next = DATA;
end
end
DATA: begin
if (encrypt) begin
o_ciphertext = i_fifo_data ^ i_chacha_state;
end else begin
o_ciphertext = i_fifo_data;
end
o_post = i_fifo_data ^ i_chacha_state;
o_ciphertext_countm1 = i_fifo_countm1;
o_ciphertext_last = i_fifo_last;
o_ciphertext_valid = i_fifo_valid & i_chacha_valid;
if (i_ciphertext_ready & i_chacha_valid) begin
o_chacha_ready = '1;
o_fifo_rd_en = i_fifo_valid;
if (i_fifo_last) begin
state_next = IDLE;
o_metadata_read = '1;
end
end
end
endcase
end
endmodule

View File

@@ -18,12 +18,40 @@ module chacha20_qr #(
output logic [31:0] a_o, b_o, c_o, d_o
);
logic [31:0] a_int_0;
logic [31:0] b_int_0;
logic [31:0] c_int_0;
logic [31:0] d_int_0;
logic [31:0] a_int_1;
logic [31:0] b_int_1;
logic [31:0] c_int_1;
logic [31:0] d_int_1;
logic [31:0] a_int [7];
logic [31:0] b_int [7];
logic [31:0] c_int [7];
logic [31:0] d_int [7];
logic [31:0] a_int_2;
logic [31:0] b_int_2;
logic [31:0] c_int_2;
logic [31:0] d_int_2;
logic [31:0] a_int_3;
logic [31:0] b_int_3;
logic [31:0] c_int_3;
logic [31:0] d_int_3;
logic [31:0] a_int_4;
logic [31:0] b_int_4;
logic [31:0] c_int_4;
logic [31:0] d_int_4;
logic [31:0] a_int_5;
logic [31:0] b_int_5;
logic [31:0] c_int_5;
logic [31:0] d_int_5;
logic [31:0] a_int_6;
logic [31:0] b_int_6;
logic [31:0] c_int_6;
logic [31:0] d_int_6;
logic [6:0] valid_sr;
@@ -33,62 +61,62 @@ logic [6:0] valid_sr;
assign o_ready = i_ready;
always_ff @(posedge i_clk) begin
always @(posedge i_clk) begin
if (i_rst) begin
valid_sr <= '0;
end else begin
if (i_ready) begin
// 1. Update A
a_int[0] <= a_i + b_i;
b_int[0] <= b_i;
c_int[0] <= c_i;
d_int[0] <= d_i;
a_int_0 <= a_i + b_i;
b_int_0 <= b_i;
c_int_0 <= c_i;
d_int_0 <= d_i;
// 2. Update D
a_int[1] <= a_int[0];
b_int[1] <= b_int[0];
c_int[1] <= c_int[0];
d_int[1] <= `ROTL(a_int[0], 16) ^ `ROTL(d_int[0], 16);
a_int_1 = a_int_0;
b_int_1 = b_int_0;
c_int_1 = c_int_0;
d_int_1 = `ROTL(a_int_0, 16) ^ `ROTL(d_int_0, 16);
// 3. Update C
a_int[2] <= a_int[1];
b_int[2] <= b_int[1];
c_int[2] <= c_int[1] + d_int[1];
d_int[2] <= d_int[1];
a_int_2 = a_int_1;
b_int_2 = b_int_1;
c_int_2 = c_int_1 + d_int_1;
d_int_2 = d_int_1;
// 4. Update B
a_int[3] <= a_int[2];
b_int[3] <= `ROTL(b_int[2], 12) ^ `ROTL(c_int[2], 12);
c_int[3] <= c_int[2];
d_int[3] <= d_int[2];
a_int_3 = a_int_2;
b_int_3 = `ROTL(b_int_2, 12) ^ `ROTL(c_int_2, 12);
c_int_3 = c_int_2;
d_int_3 = d_int_2;
// 5. Update A
a_int[4] <= a_int[3] + b_int[3];
b_int[4] <= b_int[3];
c_int[4] <= c_int[3];
d_int[4] <= d_int[3];
a_int_4 = a_int_3 + b_int_3;
b_int_4 = b_int_3;
c_int_4 = c_int_3;
d_int_4 = d_int_3;
// 6. Update D
a_int[5] <= a_int[4];
b_int[5] <= b_int[4];
c_int[5] <= c_int[4];
d_int[5] <= `ROTL(a_int[4], 8) ^ `ROTL(d_int[4], 8);
a_int_5 = a_int_4;
b_int_5 = b_int_4;
c_int_5 = c_int_4;
d_int_5 = `ROTL(a_int_4, 8) ^ `ROTL(d_int_4, 8);
// 7. Update C
a_int[6] <= a_int[5];
b_int[6] <= b_int[5];
c_int[6] <= c_int[5] + d_int[5];
d_int[6] <= d_int[5];
a_int_6 = a_int_5;
b_int_6 = b_int_5;
c_int_6 = c_int_5 + d_int_5;
d_int_6 = d_int_5;
// 8. Update B
a_o <= a_int[6];
b_o <= `ROTL(b_int[6], 7) ^ `ROTL(c_int[6], 7);
c_o <= c_int[6];
d_o <= d_int[6];
a_o <= a_int_6;
b_o <= `ROTL(b_int_6, 7) ^ `ROTL(c_int_6, 7);
c_o <= c_int_6;
d_o <= d_int_6;
// Simultaneously, update valid_sr;
valid_sr <= {valid_sr[5:0], i_valid};
o_valid <= valid_sr[6];
o_valid <= valid_sr[0];
end
end
end

View File

@@ -0,0 +1,112 @@
// FPGA Friendly modular multiplication. takes ~6 cycles
module poly1305_friendly_modular_mult #(
parameter DATA_WIDTH = 130,
parameter ACC_WIDTH = 130
) (
input logic i_clk,
input logic i_rst,
input logic i_valid,
output logic o_ready,
input logic [DATA_WIDTH-1:0] i_data,
input logic [ACC_WIDTH-1:0] i_accumulator,
output logic o_valid,
output logic [ACC_WIDTH-1:0] o_result
);
localparam INT_ACC_WIDTH = ACC_WIDTH + 3; // $clog2(8)
localparam [129:0] PRIME = (1 << 130) - 5;
logic [2:0] state_counter, state_counter_next;
logic [2:0] state_counter_p [5];
logic [INT_ACC_WIDTH-1:0] accumulator, accumulator_next; // accumulator is outgoing
logic [INT_ACC_WIDTH+1:0] accumulator_intermediate;
logic [DATA_WIDTH-1:0] data, data_next;
logic [INT_ACC_WIDTH-1:0] h, h_next; // h is incoming
logic [DATA_WIDTH+26-1:0] mult_product, mult_product_next;
logic [ACC_WIDTH-1:0] modulo_result;
assign o_ready = state_counter >= 3'h4;
always_ff @(posedge i_clk) begin
if (i_rst) begin
state_counter <= 3'h5;
state_counter_p <= '{default: 3'h5};
end else begin
state_counter <= state_counter_next;
accumulator <= accumulator_next;
data <= data_next;
h <= h_next;
mult_product <= mult_product_next;
state_counter_p[0] <= state_counter;
for (int i = 1; i < 5; i++) begin
state_counter_p[i] <= state_counter_p[i-1];
end
end
end
always_comb begin
data_next = data; // If neccesary, we can remove this state?
h_next = h;
state_counter_next = state_counter;
accumulator_next = '0;
mult_product_next = '0;
accumulator_intermediate = '0;
if (state_counter < 3'h5) begin
mult_product_next = h[state_counter*26 +: 26] * data;
state_counter_next = state_counter + 1;
end
if (state_counter >= 3'h4 && i_valid) begin
data_next = i_data;
h_next = (INT_ACC_WIDTH)'(i_accumulator);
state_counter_next = '0;
end
if (state_counter_p[3] == '0) begin
accumulator_next = (INT_ACC_WIDTH)'(modulo_result);
end else begin
accumulator_next = accumulator + (INT_ACC_WIDTH)'(modulo_result);
end
end
poly1305_friendly_modulo u_mult_modulo (
.i_clk (i_clk),
.i_rst (i_rst),
.i_valid ('1),
.i_val ((2*ACC_WIDTH)'(mult_product)),
.i_shift_amount (state_counter_p[0]),
.o_valid (),
.o_result (modulo_result)
);
poly1305_friendly_modulo u_sum_modulo (
.i_clk (i_clk),
.i_rst (i_rst),
.i_valid (state_counter_p[4] == 3'h4),
.i_val ({127'b0, accumulator}),
.i_shift_amount ('0),
.o_valid (o_valid),
.o_result (o_result)
);
endmodule

View File

@@ -36,7 +36,7 @@ assign o_valid = valid_sr[2];
always_ff @(posedge i_clk) begin
valid_sr <= {valid_sr[1:0], i_valid};
high_part_1 <= WIDTH'({3'b0, i_val} >> (130 - (i_shift_amount*SHIFT_SIZE))) * MDIFF;
high_part_1 <= WIDE_WIDTH'({3'b0, i_val} >> (130 - (i_shift_amount*SHIFT_SIZE))) * MDIFF;
low_part_1 <= WIDTH'(i_val << (i_shift_amount*SHIFT_SIZE));
high_part_2 <= (intermediate_val >> WIDTH) * 5;

View File

@@ -0,0 +1,262 @@
// 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 = 130'h3fffffffffffffffffffffffffffffffb;
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, LENGTHS, 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;
logic length_flag, length_flag_next;
logic [63:0] data_len, data_len_next;
always_ff @(posedge i_clk) begin
if (i_rst) begin
r_reg <= '0;
s_reg <= '0;
s_reg_2 <= '0;
data_len <= '0;
last_flag <= '0;
length_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;
data_len <= data_len_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;
length_flag <= length_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;
final_sum_next = '0;
r_reg_next = r_reg;
s_reg_next = s_reg;
s_reg_2_next = s_reg_2;
data_len_next = data_len;
upconvert_ready = '0;
last_flag_next = last_flag;
length_flag_next = length_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;
data_len_next = {60'd0, upconvert_countm1} + 1;
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'b1, upconvert_data};
sum_next = h + data_1extend;
data_len_next = data_len + {60'd0, upconvert_countm1} + 1;
state_next = MULT;
end
LENGTHS: begin
length_flag_next = '1;
data_1extend = {3'b0, data_len, 64'b0} | (131'b1 << 128);
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 = LENGTHS;
last_flag_next = '0;
end else if (length_flag) begin
length_flag_next = '0;
s_reg_2_next = s_reg;
start_output = '1;
data_len_next = '0;
state_next = IDLE;
end else begin
state_next = SUM;
end
end
default: begin
end
endcase
output_state_next = output_state;
o_result = '0;
o_valid = '0;
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
o_valid = '1;
o_result = final_sum[127:0];
output_state_next = OUTPUT_IDLE;
end
default: begin
output_state_next = OUTPUT_IDLE;
end
endcase
end
endmodule

View File

@@ -0,0 +1,145 @@
module poly1305_stage #(
) (
input logic i_clk,
input logic i_rst,
input logic i_valid,
output logic o_ready,
input logic i_clear_acc,
input logic [129:0] i_r_power,
input logic [127:0] i_message,
output logic o_valid,
output logic [129:0] o_result
);
localparam [129:0] PRIME = (1 << 130) - 5;
logic mult_i_valid;
logic mult_o_ready;
logic [129:0] r_power, r_power_next;
logic [130:0] mult_accumulator, mult_accumulator_next;
logic mult_valid;
logic [129:0] mult_result;
logic [129:0] accumulators [2];
logic [129:0] accumulators_next [2];
logic [1:0] ops_in_flight, ops_in_flight_next;
logic [1:0] index, index_next;
logic [1:0] index_sr [16];
logic [1:0] index_sr_next;
enum logic [1:0] {SUM1, SUM2, MUL, STORE} state, state_next;
always_ff @(posedge i_clk) begin
if (i_rst) begin
state <= SUM1;
r_power <= '0;
mult_accumulator <= '0;
ops_in_flight <= 2'h0;
index <= 2'h2;
index_sr <= '{default: '0};
for (int i = 0; i < 2; i++) begin
accumulators[i] <= '0;
end
end else begin
state <= state_next;
r_power <= r_power_next;
mult_accumulator <= mult_accumulator_next;
index <= index_next;
ops_in_flight <= ops_in_flight_next;
for (int i = 0; i < 2; i++) begin
accumulators[i] <= accumulators_next[i];
end
index_sr[0] <= index;
for (int i = 1; i < 16; i++) begin
index_sr[i] <= index_sr[i-1];
end
end
end
logic [1:0] ops_in_flight_state;
assign ops_in_flight_state = {i_valid & o_ready, mult_valid};
always_comb begin
state_next = state;
o_ready = '0;
mult_accumulator_next = mult_accumulator;
mult_i_valid = '0;
index_next = index;
if (mult_valid) begin
accumulators_next[index_sr[12][0]] = mult_result;
end
case (ops_in_flight_state)
2'b00: ops_in_flight_next = ops_in_flight;
2'b01: ops_in_flight_next = ops_in_flight - 1;
2'b10: ops_in_flight_next = ops_in_flight + 1;
2'b11: ops_in_flight_next = ops_in_flight;
endcase
o_valid = mult_valid;
o_result = mult_result;
case (state)
SUM1: begin
o_ready = ops_in_flight < 2;
if (i_valid && o_ready) begin
r_power_next = i_r_power;
if (i_clear_acc) begin
mult_accumulator_next = {3'b0, i_message};
end else begin
mult_accumulator_next = accumulators[index[0]] + {3'b0, i_message};
end
state_next = SUM2;
end
end
SUM2: begin
mult_accumulator_next = mult_accumulator >= 131'(PRIME) ? 131'(mult_accumulator - PRIME) : mult_accumulator;
state_next = MUL;
end
MUL: begin
mult_i_valid = '1;
if (mult_o_ready) begin
index_next = index + 1;
state_next = SUM1;
end
end
default: begin
state_next = SUM1;
end
endcase
end
poly1305_friendly_modular_mult u_modular_mult (
.i_clk (i_clk),
.i_rst (i_rst),
.i_valid (mult_i_valid),
.o_ready (mult_o_ready),
.i_data (r_power),
.i_accumulator (mult_accumulator[129:0]),
.o_valid (mult_valid),
.o_result (mult_result)
);
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

@@ -0,0 +1,109 @@
module poly1305_width_convert_2(
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 [5:0] o_countm1,
input logic i_ready,
output logic [511:0] o_data,
output logic o_last
);
// this could definitely be parameterized,
// but that can be a future project for the intern
logic [11:0] pkt_len, pkt_len_next;
// make this an input
logic [11:0] pkt_len_max;
assign pkt_len_max = 12'd1420;
logic [479:0] width_convert_save, width_convert_save_next;
logic [3: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;
pkt_len <= '0;
end else begin
width_convert_count <= width_convert_count_next;
width_convert_save <= width_convert_save_next;
pkt_len <= pkt_len_next;
end
end
always_comb begin
width_convert_save_next = width_convert_save;
width_convert_count_next = width_convert_count;
pkt_len_next = pkt_len;
o_valid = '0;
o_ready = '0;
o_last = '0;
o_countm1 = '1;
if (width_convert_count < 15) 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;
pkt_len_next = '0;
// wireguard packets are rounded up to 16 bytes
o_countm1 = width_convert_count*4 + {4'b0, i_countm1};
if (o_countm1[3:0] != 0) begin
o_countm1 = {o_countm1[5:4], 4'hf};
end
if (pkt_len + 12'(o_countm1) + 1 > pkt_len_max) begin
o_countm1 = 6'(pkt_len_max - pkt_len - 12'd1);
end
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 & i_ready) begin
o_ready = '1;
width_convert_count_next = width_convert_count + 4'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 = 6'd63 + {4'b0, i_countm1};
o_countm1 = 6'd63;
if (i_valid && o_ready) begin
width_convert_count_next = '0;
width_convert_save_next = '0;
pkt_len_next = pkt_len + 12'(o_countm1) + 12'h1;
if (i_last) begin
pkt_len_next = '0;
end
end
end
end
endmodule

View File

@@ -0,0 +1,63 @@
// this one converts from 512 back to 32
module poly1305_width_convert_3(
input logic i_clk,
input logic i_rst,
input logic i_valid,
input logic [5:0] i_countm1,
output logic o_ready,
input logic [511:0] i_data,
input logic i_last,
output logic o_valid,
output logic [1:0] o_countm1,
input logic i_ready,
output logic [31:0] o_data,
output logic o_last
);
logic [3:0] width_convert_count, width_convert_count_next;
always_ff @(posedge i_clk) begin
if (i_rst) begin
width_convert_count <= '0;
end else begin
width_convert_count <= width_convert_count_next;
end
end
always_comb begin
width_convert_count_next = width_convert_count;
o_valid = '0;
o_last = '0;
o_ready = '0;
o_data = i_data[width_convert_count*32 +: 32];
o_countm1 = '0;
o_valid = i_valid;
if (i_valid && i_ready) begin
width_convert_count_next = width_convert_count + 1;
o_countm1 = '1;
if (width_convert_count == 15) begin
o_ready = '1;
end
end
if (i_last && 6'(width_convert_count+1)*4 > i_countm1) begin
o_last = '1;
o_countm1 = (2)'(i_countm1 - width_convert_count*4);
if (i_valid && i_ready) begin
o_ready = '1;
width_convert_count_next = '0;
end
end
end
endmodule

View File

@@ -0,0 +1,114 @@
/*===============================================================================================================================
Module : Pipeline Skid Buffer
Description : Pipeline Skid Buffer is used as buffer in pipeline between two modules.
- Smallest pipeline buffer; implemented with just two registers.
- Simple valid-ready handshaking.
- Latency = 1 cycle.
- Configurable data width.
Developer : Mitu Raj, chip@chipmunklogic.com at Chipmunk Logic ™, https://chipmunklogic.com
Notes : -
License : Open-source.
Date : Mar-26-2022
===============================================================================================================================*/
/*-------------------------------------------------------------------------------------------------------------------------------
P I P E S K I D B U F F E R
-------------------------------------------------------------------------------------------------------------------------------*/
module pipe_skid_buffer #(
// Global Parameters
parameter DWIDTH = 8 // Data width
)
(
input logic clk , // Clock
input logic rstn , // Active-low synchronous reset
// Input Interface
input logic [DWIDTH-1 : 0] i_data , // Data in
input logic i_valid , // Data in valid
output logic o_ready , // Ready out
// Output Interface
output logic [DWIDTH-1 : 0] o_data , // Data out
output logic o_valid , // Data out valid
input logic i_ready // Ready in
) ;
/*-------------------------------------------------------------------------------------------------------------------------------
Local Parameters
-------------------------------------------------------------------------------------------------------------------------------*/
// State encoding
localparam PIPE = 1'b0 ;
localparam SKID = 1'b1 ;
/*-------------------------------------------------------------------------------------------------------------------------------
Internal Registers/Signals
-------------------------------------------------------------------------------------------------------------------------------*/
logic state_rg ; // State register
logic [DWIDTH-1 : 0] data_rg, sparebuff_rg ; // Data buffer, Spare buffer
logic valid_rg, ready_rg ; // Valid and Ready signals
logic ready ; // Pipeline ready signal
/*-------------------------------------------------------------------------------------------------------------------------------
Synchronous logic
-------------------------------------------------------------------------------------------------------------------------------*/
always @(posedge clk) begin
// Reset
if (!rstn) begin
// Internal Registers
state_rg <= PIPE ;
data_rg <= '0 ;
sparebuff_rg <= '0 ;
valid_rg <= 1'b0 ;
ready_rg <= 1'b0 ;
end
// Out of reset
else begin
case (state_rg)
/* Stage where data is piped out or stored to spare buffer */
PIPE : begin
// Pipe data out
if (ready) begin
data_rg <= i_data ;
valid_rg <= i_valid ;
ready_rg <= 1'b1 ;
end
// Pipeline stall, store input data to spare buffer (skid happened)
else if (i_valid) begin
sparebuff_rg <= i_data ;
ready_rg <= 1'b0 ;
state_rg <= SKID ;
end
end
/* Stage to wait after data skid happened */
SKID : begin
// Copy data from spare buffer to data buffer when downstream is ready, resume pipeline
if (i_ready) begin
data_rg <= sparebuff_rg ;
valid_rg <= 1'b1 ;
ready_rg <= 1'b1 ;
state_rg <= PIPE ;
end
end
endcase
end
end
/*-------------------------------------------------------------------------------------------------------------------------------
Continuous Assignments
-------------------------------------------------------------------------------------------------------------------------------*/
assign ready = i_ready || ~valid_rg ;
assign o_ready = ready_rg ;
assign o_data = data_rg ;
assign o_valid = valid_rg ;
endmodule
/*-------------------------------------------------------------------------------------------------------------------------------
P I P E S K I D B U F F E R
-------------------------------------------------------------------------------------------------------------------------------*/

View File

@@ -4,4 +4,17 @@ chacha20_pipelined_round.sv
chacha20_pipelined_block.sv
poly1305_core.sv
poly1305_friendly_modulo.sv
poly1305_friendly_modulo.sv
poly1305_friendly_modular_mult.sv
poly1305_stage.sv
poly1305_width_convert.sv
poly1305_width_convert_2.sv
poly1305_width_convert_3.sv
poly1305_ll_stage.sv
skidbuffer.sv
chacha20_poly1305_32_ll_core.sv
chacha20_poly1305_input_fsm.sv
chacha20_poly1305_mid_fsm.sv

1
common/sim/sub/fifo Submodule

Submodule common/sim/sub/fifo added at 9f35e490dc

0
mod_test.py Normal file
View File