├── .gitattributes ├── src ├── data │ └── openlane_params.tcl ├── rtl │ ├── chacha_qr.v │ ├── chacha.v │ └── chacha_core.v ├── tb │ ├── tb_chacha_core.v │ └── tb_chacha.v └── model │ └── python │ └── chacha.py ├── .gitignore ├── LICENSE ├── chacha.core ├── .github └── workflows │ └── ci.yml ├── toolruns └── Makefile ├── README.md └── tools └── lsbgen.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Helping linguist detect files as Verilog, not Coq. 2 | *.v linguist-language=Verilog 3 | -------------------------------------------------------------------------------- /src/data/openlane_params.tcl: -------------------------------------------------------------------------------- 1 | # Variables for the Openlane flow, as taken from the example designs in the Openlane repository 2 | set ::env(CLOCK_PORT) "clk" 3 | set ::env(CLOCK_NET) $::env(CLOCK_PORT) 4 | set ::env(GLB_RT_ADJUSTMENT) 0.1 5 | set ::env(SYNTH_MAX_FANOUT) 6 6 | set ::env(CLOCK_PERIOD) "26.01" 7 | set ::env(FP_CORE_UTIL) 25 8 | set ::env(PL_TARGET_DENSITY) [ expr ($::env(FP_CORE_UTIL)+5) / 100.0 ] -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #======================================================================= 2 | # 3 | # .gitignore 4 | # ---------- 5 | # Gitignore for core projects. 6 | #======================================================================= 7 | 8 | ## Generated files 9 | test* 10 | *.sim 11 | 12 | ## Log files 13 | *.log 14 | 15 | 16 | ## Subdirs in toolruns for vendor tools 17 | /toolruns/quartus 18 | /toolruns/ise/ 19 | /toolruns/vivado 20 | /toolruns/modelsim 21 | /toolruns/libero 22 | /toolruns/icestorm 23 | 24 | #======================================================================= 25 | # EOF .gitignore 26 | #======================================================================= 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013, Joachim Strömbergson 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | Redistributions in binary form must reproduce the above copyright notice, this 11 | list of conditions and the following disclaimer in the documentation and/or 12 | other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /chacha.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | 3 | name : secworks:crypto:chacha:0 4 | description : Verilog 2001 implementation of the ChaCha stream cipher 5 | 6 | filesets: 7 | rtl: 8 | files: 9 | - src/rtl/chacha_qr.v 10 | - src/rtl/chacha_core.v 11 | - src/rtl/chacha.v 12 | file_type : verilogSource 13 | 14 | tb: 15 | files: 16 | - src/tb/tb_chacha_core.v 17 | - src/tb/tb_chacha.v 18 | file_type : verilogSource 19 | 20 | openlane: 21 | files: 22 | - src/data/openlane_params.tcl : {file_type : tclSource} 23 | 24 | targets: 25 | default: 26 | filesets: [rtl] 27 | 28 | lint: 29 | default_tool : verilator 30 | filesets : [rtl] 31 | tools: 32 | verilator: 33 | mode: lint-only 34 | toplevel: chacha 35 | 36 | tb_chacha: 37 | default_tool: icarus 38 | filesets: [rtl, tb] 39 | toplevel: tb_chacha 40 | parameters : [DEBUG] 41 | 42 | tb_chacha_core: 43 | default_tool: icarus 44 | filesets: [rtl, tb] 45 | toplevel: tb_chacha_core 46 | 47 | sky130: 48 | default_tool : openlane 49 | filesets : [rtl, openlane] 50 | toplevel : chacha 51 | 52 | parameters: 53 | DEBUG: 54 | datatype : int 55 | default : 0 56 | paramtype : vlogparam 57 | description : Enable debug printouts -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: build-openlane-sky130 2 | on: [push] 3 | 4 | jobs: 5 | build-chacha-sky130: 6 | runs-on: ubuntu-latest 7 | env: 8 | REPO : chacha 9 | VLNV : secworks:crypto:chacha 10 | steps: 11 | - name: Checkout repo 12 | uses: actions/checkout@v2 13 | with: 14 | path: chacha 15 | - name: Checkout pdk 16 | uses: actions/checkout@v2 17 | with: 18 | repository: olofk/pdklite 19 | path: pdklite 20 | - run: echo "PDK_ROOT=$GITHUB_WORKSPACE/pdklite" >> $GITHUB_ENV 21 | - run: echo "EDALIZE_LAUNCHER=${GITHUB_WORKSPACE}/openlane_runner.py" >> $GITHUB_ENV 22 | - run: pip3 install --user -e "git+https://github.com/olofk/edalize.git#egg=edalize" 23 | - run: pip3 install fusesoc 24 | - run: docker pull efabless/openlane:v0.12 25 | - run: wget https://raw.githubusercontent.com/olofk/subservient/main/openlane_runner.py 26 | - run: chmod +x openlane_runner.py 27 | - run: fusesoc library add $REPO $GITHUB_WORKSPACE/$REPO 28 | - run: fusesoc run --target=sky130 $VLNV 29 | 30 | sim-icarus: 31 | runs-on: ubuntu-latest 32 | env: 33 | REPO : chacha 34 | VLNV : secworks:crypto:chacha 35 | steps: 36 | - name: Checkout repo 37 | uses: actions/checkout@v2 38 | with: 39 | path: chacha 40 | - run: sudo apt install iverilog 41 | - run: pip3 install fusesoc 42 | - run: fusesoc library add $REPO $GITHUB_WORKSPACE/$REPO 43 | - run: fusesoc run --target=tb_chacha $VLNV 44 | - run: fusesoc run --target=tb_chacha_core $VLNV 45 | 46 | lint-verilator: 47 | runs-on: ubuntu-latest 48 | env: 49 | REPO : chacha 50 | VLNV : secworks:crypto:chacha 51 | steps: 52 | - name: Checkout repo 53 | uses: actions/checkout@v2 54 | with: 55 | path: chacha 56 | - run: sudo apt install verilator 57 | - run: pip3 install fusesoc 58 | - run: fusesoc library add $REPO $GITHUB_WORKSPACE/$REPO 59 | - run: fusesoc run --target=lint $VLNV -------------------------------------------------------------------------------- /toolruns/Makefile: -------------------------------------------------------------------------------- 1 | #=================================================================== 2 | # 3 | # Makefile 4 | # -------- 5 | # Makefile for building core and top simulation as well as 6 | # linting of the source code. 7 | # 8 | # 9 | # Author: Joachim Strombergson 10 | # Copyright (c) 2013, Secworks Sweden AB 11 | # All rights reserved. 12 | # 13 | # Redistribution and use in source and binary forms, with or 14 | # without modification, are permitted provided that the following 15 | # conditions are met: 16 | # 17 | # 1. Redistributions of source code must retain the above copyright 18 | # notice, this list of conditions and the following disclaimer. 19 | # 20 | # 2. Redistributions in binary form must reproduce the above copyright 21 | # notice, this list of conditions and the following disclaimer in 22 | # the documentation and/or other materials provided with the 23 | # distribution. 24 | # 25 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 28 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 29 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 30 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 31 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 34 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 36 | # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | # 38 | #=================================================================== 39 | 40 | CORE_SRC=../src/rtl/chacha_core.v ../src/rtl/chacha_qr.v 41 | CORE_TB_SRC=../src/tb/tb_chacha_core.v 42 | 43 | TOP_SRC=../src/rtl/chacha.v $(CORE_SRC) 44 | TOP_TB_SRC=../src/tb/tb_chacha.v 45 | 46 | CC = iverilog 47 | CC_FLAGS = -Wall 48 | 49 | LINT = verilator 50 | LINT_FLAGS = +1364-2001ext+ --lint-only -Wall -Wno-fatal -Wno-DECLFILENAME 51 | 52 | 53 | all: top.sim core.sim 54 | 55 | 56 | top.sim: $(TOP_TB_SRC) $(TOP_SRC) 57 | $(CC) $(CC_FLAGS) -o top.sim $(TOP_TB_SRC) $(TOP_SRC) 58 | 59 | 60 | core.sim: $(CORE_TB_SRC) $(CORE_SRC) 61 | $(CC) $(CC_FLAGS) -o core.sim $(CORE_SRC) $(CORE_TB_SRC) 62 | 63 | 64 | lint: $(TOP_SRC) 65 | $(LINT) $(LINT_FLAGS) $(TOP_SRC) 66 | 67 | 68 | sim-core: core.sim 69 | ./core.sim 70 | 71 | 72 | sim-top: top.sim 73 | ./top.sim 74 | 75 | 76 | clean: 77 | rm -f *.sim 78 | 79 | 80 | help: 81 | @echo "Supported targets:" 82 | @echo "------------------" 83 | @echo "all: Build all simulation targets." 84 | @echo "top.sim: Build the top simulation target." 85 | @echo "core.sim Build the top simulation target." 86 | @echo "lint: Run lint on the source." 87 | @echo "sim-top: Run top level simulation." 88 | @echo "sim-core: Run core level simulation." 89 | @echo "clean: Remove build targets." 90 | 91 | #=================================================================== 92 | # EOF Makefile 93 | #=================================================================== 94 | -------------------------------------------------------------------------------- /src/rtl/chacha_qr.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // chacha_qr.v 4 | // ----------- 5 | // Verilog 2001 implementation of the stream cipher ChaCha. 6 | // This is the combinational QR logic as a separade module to allow 7 | // us to build versions of the cipher with 1, 2, 4 and even 8 8 | // parallel qr functions. 9 | // 10 | // 11 | // Copyright (c) 2013 Secworks Sweden AB 12 | // All rights reserved. 13 | // 14 | // Redistribution and use in source and binary forms, with or 15 | // without modification, are permitted provided that the following 16 | // conditions are met: 17 | // 18 | // 1. Redistributions of source code must retain the above copyright 19 | // notice, this list of conditions and the following disclaimer. 20 | // 21 | // 2. Redistributions in binary form must reproduce the above copyright 22 | // notice, this list of conditions and the following disclaimer in 23 | // the documentation and/or other materials provided with the 24 | // distribution. 25 | // 26 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 27 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 28 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 29 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 30 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 31 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 32 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 33 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 35 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 37 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | // 39 | //====================================================================== 40 | 41 | `default_nettype none 42 | 43 | module chacha_qr( 44 | input wire [31 : 0] a, 45 | input wire [31 : 0] b, 46 | input wire [31 : 0] c, 47 | input wire [31 : 0] d, 48 | 49 | output wire [31 : 0] a_prim, 50 | output wire [31 : 0] b_prim, 51 | output wire [31 : 0] c_prim, 52 | output wire [31 : 0] d_prim 53 | ); 54 | 55 | //---------------------------------------------------------------- 56 | // Wires. 57 | //---------------------------------------------------------------- 58 | reg [31 : 0] internal_a_prim; 59 | reg [31 : 0] internal_b_prim; 60 | reg [31 : 0] internal_c_prim; 61 | reg [31 : 0] internal_d_prim; 62 | 63 | 64 | //---------------------------------------------------------------- 65 | // Concurrent connectivity for ports. 66 | //---------------------------------------------------------------- 67 | assign a_prim = internal_a_prim; 68 | assign b_prim = internal_b_prim; 69 | assign c_prim = internal_c_prim; 70 | assign d_prim = internal_d_prim; 71 | 72 | 73 | //---------------------------------------------------------------- 74 | // qr 75 | // 76 | // The actual quarterround function. 77 | //---------------------------------------------------------------- 78 | always @* 79 | begin : qr 80 | reg [31 : 0] a0; 81 | reg [31 : 0] a1; 82 | 83 | reg [31 : 0] b0; 84 | reg [31 : 0] b1; 85 | reg [31 : 0] b2; 86 | reg [31 : 0] b3; 87 | 88 | reg [31 : 0] c0; 89 | reg [31 : 0] c1; 90 | 91 | reg [31 : 0] d0; 92 | reg [31 : 0] d1; 93 | reg [31 : 0] d2; 94 | reg [31 : 0] d3; 95 | 96 | a0 = a + b; 97 | d0 = d ^ a0; 98 | d1 = {d0[15 : 0], d0[31 : 16]}; 99 | c0 = c + d1; 100 | b0 = b ^ c0; 101 | b1 = {b0[19 : 0], b0[31 : 20]}; 102 | a1 = a0 + b1; 103 | d2 = d1 ^ a1; 104 | d3 = {d2[23 : 0], d2[31 : 24]}; 105 | c1 = c0 + d3; 106 | b2 = b1 ^ c1; 107 | b3 = {b2[24 : 0], b2[31 : 25]}; 108 | 109 | internal_a_prim = a1; 110 | internal_b_prim = b3; 111 | internal_c_prim = c1; 112 | internal_d_prim = d3; 113 | end // qr 114 | endmodule // chacha_qr 115 | 116 | //====================================================================== 117 | // EOF chacha_qr.v 118 | //====================================================================== 119 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![build-openlane-sky130](https://github.com/secworks/chacha/actions/workflows/ci.yml/badge.svg?branch=master&event=push)](https://github.com/secworks/chacha/actions/workflows/ci.yml) 2 | 3 | chacha 4 | ======== 5 | 6 | Verilog 2001 implementation of the ChaCha stream cipher. 7 | 8 | ## Status ## 9 | The core is completed and has been implemented and used in several FPGA 10 | designs. The core is for example used as the CSPRNG/DRBG part of the 11 | random number generator (RNG) in the [Cryptech 12 | HSM](https://cryptech.is/). 13 | 14 | 15 | ## Introduction ## 16 | This core implements the [ChaCha stream cipher 17 | (pdf)](https://cr.yp.to/chacha/chacha-20080128.pdf) By Daniel 18 | J. Bernstein (DJB). 19 | 20 | 21 | ### Contact information ## 22 | 23 | Assured provides customer support including customization, integration 24 | and system development related to the core. For more information, 25 | please contact [Assured Security 26 | Consultants](https://www.assured.se/contact). 27 | 28 | 29 | ## Functionality ## 30 | This core implements ChaCha with support for 128 and 256 bit keys. The 31 | number of rounds can be set from two to 32 rounds in steps of two. The 32 | default number of rounds is eight. 33 | 34 | The core contains an internal 64-bit block counter that is automatically 35 | updated for each data block. 36 | 37 | There is a [reference model in a separate 38 | repository](https://github.com/secworks/chacha_testvectors) used to 39 | generate and document test vectors. There is also a functional model in 40 | this repo under src/model/python. 41 | 42 | 43 | ## Branch for VHDL interoperability ## 44 | There is a branch 45 | [*vhdl_interop*](https://github.com/secworks/chacha/tree/vhdl_interop) 46 | that changes the port name "next" in *chacha_core.v*. Next is a reserved 47 | word in VHDL. If you are instantiating the core in a mixed language 48 | environment use this branch. This branch will not be merged into 49 | *master*, but will track changes to the *master* branch. 50 | 51 | 52 | ## Performance ## 53 | The core has four separate quarterround modules, which means that 54 | one round takes one cycle. The overhead latency cost when using the top 55 | level wrapper is three, which means that with eight rounds the total 56 | latency is 11 cycles. For ChaCha20 the latency is 23 cycles. 57 | 58 | ## FuseSoC 59 | This core is supported by the 60 | [FuseSoC](https://github.com/olofk/fusesoc) core package manager and 61 | build system. Some quick FuseSoC instructions: 62 | 63 | Install FuseSoC 64 | ~~~ 65 | pip install fusesoc 66 | ~~~ 67 | 68 | Create and enter a new workspace 69 | ~~~ 70 | mkdir workspace && cd workspace 71 | ~~~ 72 | 73 | Register chacha as a library in the workspace 74 | ~~~ 75 | fusesoc library add chacha /path/to/chacha 76 | ~~~ 77 | ...if repo is available locally or... 78 | ...to get the upstream repo 79 | ~~~ 80 | fusesoc library add chacha https://github.com/secworks/chacha 81 | ~~~ 82 | 83 | Run tb_chacha testbench 84 | ~~~ 85 | fusesoc run --target=tb_chacha secworks:crypto:chacha 86 | ~~~ 87 | 88 | Run with modelsim instead of default tool (icarus) 89 | ~~~ 90 | fusesoc run --target=tb_chacha --tool=modelsim secworks:crypto:chacha 91 | ~~~ 92 | 93 | List all targets 94 | ~~~ 95 | fusesoc core show secworks:crypto:chacha 96 | ~~~ 97 | 98 | ## Implementation results## 99 | 100 | ### Intel Cyclone IV E ### 101 | - Tool: Altera Quartus Prime 15.1 102 | - LEs: 4748 103 | - Regs: 1940 104 | - RAM: 0 105 | - Fmax: 55 MHz 106 | 107 | 108 | ### Intel Cyclone V GX ### 109 | - Tool: Altera Quartus Prime 15.1 110 | - ALMs: 1939 111 | - Regs: 1940 112 | - Ram: 0 113 | - Fmax: 60 MHz 114 | 115 | 116 | ### Microchip IGLOO2 ### 117 | - Tool: Libero v 12.4 118 | - Device: M2GL150TS-FCV484 119 | - LUTs: 4190 120 | - SLEs: 2028 121 | - BRAMs: 2 122 | - Fmax: 88.4 MHz 123 | 124 | 125 | ### Microchip PolarFire ### 126 | - Tool: Libero v 12.4 127 | - Device: MPF500TS-FCG784I 128 | - LUTs: 4190 129 | - SLEs: 1992 130 | - BRAMs: 3 131 | - Fmax: 94.4 MHz 132 | 133 | 134 | ### Xilinx Spartan-6 ### 135 | - Tool: Xilinx ISE 14.7 136 | - Device: xc6slx75-3fgg676 137 | - LUTs: 3843 138 | - Slices: 1049 139 | - Regs: 1994 140 | - BRAM: 0 141 | - Fmax: 83 MHz 142 | 143 | 144 | ### Xilinx Artix-7 ### 145 | - Tool: Xilinx ISE 14.7 146 | - Device: xc7a200t-3fbg484 147 | - LUTs: 3837 148 | - Slices: 1076 149 | - Regs: 1949 150 | - BRAM: 0 151 | - Fmax: 100 MHz 152 | -------------------------------------------------------------------------------- /tools/lsbgen.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #======================================================================= 4 | # 5 | # lsbgen.py 6 | # --------- 7 | # Given the length of a vector will calculate and print Verilog 8 | # statements needed to extract a number of 32-bit words from 9 | # the vector. 10 | # 11 | # The vector is assumed to be in the format [(n-1)..0] where n 12 | # is the given number of bits. The vector is considered to 13 | # be a byte representation of a sequence of bytes from left to 14 | # right. This means that the first byte is in bits 15 | # [(n-1)..(n-8)]. 16 | # 17 | # Based on this 32-bit lsb words are extracted from left to 18 | # right in increasing order. this means that LSB for word0 19 | # is in bits [(n-1)..(n-8)] of the vector. 20 | # 21 | # Simple, isn't it? ;-) 22 | # 23 | # 24 | # Copyright (c) 2013 Secworks Sweden AB 25 | # Author: Joachim Strömbergson 26 | # 27 | # Redistribution and use in source and binary forms, with or 28 | # without modification, are permitted provided that the following 29 | # conditions are met: 30 | # 31 | # 1. Redistributions of source code must retain the above copyright 32 | # notice, this list of conditions and the following disclaimer. 33 | # 34 | # 2. Redistributions in binary form must reproduce the above copyright 35 | # notice, this list of conditions and the following disclaimer in 36 | # the documentation and/or other materials provided with the 37 | # distribution. 38 | # 39 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 40 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 41 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 42 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 43 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 44 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 45 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 46 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 47 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 48 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 49 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 50 | # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 51 | # 52 | #======================================================================= 53 | 54 | #------------------------------------------------------------------- 55 | # Python module imports. 56 | #------------------------------------------------------------------- 57 | import sys 58 | 59 | 60 | #------------------------------------------------------------------- 61 | # main() 62 | # 63 | # If executed tests the ChaCha class using known test vectors. 64 | #------------------------------------------------------------------- 65 | def main(): 66 | vector_name = "state_reg" 67 | vector_bits = 512 68 | word_bits = 32 69 | word_name = "x" 70 | 71 | # Check that the given size is ok. 72 | if (vector_bits % word_bits != 0): 73 | print("Error: Vector with %d bits can not be evenly divided into %d-bit words." % (vector_bits, word_bits)) 74 | return 75 | else: 76 | print("Creating %d words of size %d" ) 77 | 78 | for i in range(int(vector_bits / word_bits)): 79 | b0max = (vector_bits - 1) - i * word_bits 80 | b0min = (vector_bits - 8) - i * word_bits 81 | b1max = (vector_bits - 9) - i * word_bits 82 | b1min = (vector_bits - 16) - i * word_bits 83 | b2max = (vector_bits - 17) - i * word_bits 84 | b2min = (vector_bits - 24) - i * word_bits 85 | b3max = (vector_bits - 25) - i * word_bits 86 | b3min = (vector_bits - 32) - i * word_bits 87 | 88 | print("x%d_new = {%s[%d:%d], %s[%d:%d], %s[%d:%d], %s[%d:%d]}" %\ 89 | (i, vector_name, b3max, b3min, vector_name, b2max, b2min, 90 | vector_name, b1max, b1min, vector_name, b0max, b0min)) 91 | 92 | 93 | #------------------------------------------------------------------- 94 | # __name__ 95 | # Python thingy which allows the file to be run standalone as 96 | # well as parsed from within a Python interpreter. 97 | #------------------------------------------------------------------- 98 | if __name__=="__main__": 99 | # Run the main function. 100 | sys.exit(main()) 101 | 102 | #======================================================================= 103 | # EOF lsbgen.py 104 | #======================================================================= 105 | -------------------------------------------------------------------------------- /src/rtl/chacha.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // chacha.v 4 | // -------- 5 | // Top level wrapper for the ChaCha stream, cipher core providing 6 | // a simple memory like interface with 32 bit data access. 7 | // 8 | // 9 | // Copyright (c) 2013 Secworks Sweden AB 10 | // 11 | // Redistribution and use in source and binary forms, with or 12 | // without modification, are permitted provided that the following 13 | // conditions are met: 14 | // 15 | // 1. Redistributions of source code must retain the above copyright 16 | // notice, this list of conditions and the following disclaimer. 17 | // 18 | // 2. Redistributions in binary form must reproduce the above copyright 19 | // notice, this list of conditions and the following disclaimer in 20 | // the documentation and/or other materials provided with the 21 | // distribution. 22 | // 23 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 34 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | // 36 | //====================================================================== 37 | 38 | `default_nettype none 39 | 40 | module chacha( 41 | input wire clk, 42 | input wire reset_n, 43 | input wire cs, 44 | input wire we, 45 | input wire [7 : 0] addr, 46 | input wire [31 : 0] write_data, 47 | output wire [31 : 0] read_data 48 | ); 49 | 50 | //---------------------------------------------------------------- 51 | // Internal constant and parameter definitions. 52 | //---------------------------------------------------------------- 53 | localparam ADDR_NAME0 = 8'h00; 54 | localparam ADDR_NAME1 = 8'h01; 55 | localparam ADDR_VERSION = 8'h02; 56 | 57 | localparam ADDR_CTRL = 8'h08; 58 | localparam CTRL_INIT_BIT = 0; 59 | localparam CTRL_NEXT_BIT = 1; 60 | 61 | localparam ADDR_STATUS = 8'h09; 62 | localparam STATUS_READY_BIT = 0; 63 | 64 | localparam ADDR_KEYLEN = 8'h0a; 65 | localparam KEYLEN_BIT = 0; 66 | localparam ADDR_ROUNDS = 8'h0b; 67 | localparam ROUNDS_HIGH_BIT = 4; 68 | localparam ROUNDS_LOW_BIT = 0; 69 | 70 | localparam ADDR_KEY0 = 8'h10; 71 | localparam ADDR_KEY7 = 8'h17; 72 | 73 | localparam ADDR_IV0 = 8'h20; 74 | localparam ADDR_IV1 = 8'h21; 75 | 76 | localparam ADDR_DATA_IN0 = 8'h40; 77 | localparam ADDR_DATA_IN15 = 8'h4f; 78 | 79 | localparam ADDR_DATA_OUT0 = 8'h80; 80 | localparam ADDR_DATA_OUT15 = 8'h8f; 81 | 82 | localparam CORE_NAME0 = 32'h63686163; // "chac" 83 | localparam CORE_NAME1 = 32'h68612020; // "ha " 84 | localparam CORE_VERSION = 32'h302e3830; // "0.80" 85 | 86 | localparam DEFAULT_CTR_INIT = 64'h0; 87 | 88 | 89 | //---------------------------------------------------------------- 90 | // Registers including update variables and write enable. 91 | //---------------------------------------------------------------- 92 | reg init_reg; 93 | reg init_new; 94 | reg next_reg; 95 | reg next_new; 96 | 97 | reg keylen_reg; 98 | reg keylen_we; 99 | 100 | reg [4 : 0] rounds_reg; 101 | reg rounds_we; 102 | 103 | reg [31 : 0] key_reg [0 : 7]; 104 | reg key_we; 105 | 106 | reg [31 : 0] iv_reg[0 : 1]; 107 | reg iv_we; 108 | 109 | reg [31 : 0] data_in_reg [0 : 15]; 110 | reg data_in_we; 111 | 112 | 113 | //---------------------------------------------------------------- 114 | // Wires. 115 | //---------------------------------------------------------------- 116 | wire [255 : 0] core_key; 117 | wire [63 : 0] core_iv; 118 | wire core_ready; 119 | wire [511 : 0] core_data_in; 120 | wire [511 : 0] core_data_out; 121 | wire core_data_out_valid; 122 | 123 | reg [31 : 0] tmp_read_data; 124 | 125 | 126 | //---------------------------------------------------------------- 127 | // Concurrent connectivity for ports etc. 128 | //---------------------------------------------------------------- 129 | assign core_key = {key_reg[0], key_reg[1], key_reg[2], key_reg[3], 130 | key_reg[4], key_reg[5], key_reg[6], key_reg[7]}; 131 | 132 | assign core_iv = {iv_reg[0], iv_reg[1]}; 133 | 134 | assign core_data_in = {data_in_reg[00], data_in_reg[01], data_in_reg[02], data_in_reg[03], 135 | data_in_reg[04], data_in_reg[05], data_in_reg[06], data_in_reg[07], 136 | data_in_reg[08], data_in_reg[09], data_in_reg[10], data_in_reg[11], 137 | data_in_reg[12], data_in_reg[13], data_in_reg[14], data_in_reg[15]}; 138 | 139 | assign read_data = tmp_read_data; 140 | 141 | 142 | //---------------------------------------------------------------- 143 | // core instantiation. 144 | //---------------------------------------------------------------- 145 | chacha_core core ( 146 | .clk(clk), 147 | .reset_n(reset_n), 148 | .init(init_reg), 149 | .next(next_reg), 150 | .key(core_key), 151 | .keylen(keylen_reg), 152 | .iv(core_iv), 153 | .ctr(DEFAULT_CTR_INIT), 154 | .rounds(rounds_reg), 155 | .data_in(core_data_in), 156 | .ready(core_ready), 157 | .data_out(core_data_out), 158 | .data_out_valid(core_data_out_valid) 159 | ); 160 | 161 | 162 | //---------------------------------------------------------------- 163 | // reg_update 164 | // 165 | // Update functionality for all registers in the core. 166 | // All registers are positive edge triggered with asynchronous 167 | // active low reset. All registers have write enable. 168 | //---------------------------------------------------------------- 169 | always @ (posedge clk) 170 | begin : reg_update 171 | integer i; 172 | if (!reset_n) 173 | begin 174 | init_reg <= 0; 175 | next_reg <= 0; 176 | keylen_reg <= 0; 177 | rounds_reg <= 5'h0; 178 | iv_reg[0] <= 32'h0; 179 | iv_reg[1] <= 32'h0; 180 | 181 | for (i = 0 ; i < 8 ; i = i + 1) 182 | key_reg[i] <= 32'h0; 183 | 184 | for (i = 0 ; i < 16 ; i = i + 1) 185 | data_in_reg[i] <= 32'h0; 186 | end 187 | else 188 | begin 189 | init_reg <= init_new; 190 | next_reg <= next_new; 191 | 192 | if (keylen_we) 193 | keylen_reg <= write_data[KEYLEN_BIT]; 194 | 195 | if (rounds_we) 196 | rounds_reg <= write_data[ROUNDS_HIGH_BIT : ROUNDS_LOW_BIT]; 197 | 198 | if (key_we) 199 | key_reg[addr[2 : 0]] <= write_data; 200 | 201 | if (iv_we) 202 | iv_reg[addr[0]] <= write_data; 203 | 204 | if (data_in_we) 205 | data_in_reg[addr[3 : 0]] <= write_data; 206 | end 207 | end // reg_update 208 | 209 | 210 | //---------------------------------------------------------------- 211 | // Address decoder logic. 212 | //---------------------------------------------------------------- 213 | always @* 214 | begin : addr_decoder 215 | keylen_we = 1'h0; 216 | rounds_we = 1'h0; 217 | key_we = 1'h0; 218 | iv_we = 1'h0; 219 | data_in_we = 1'h0; 220 | init_new = 1'h0; 221 | next_new = 1'h0; 222 | tmp_read_data = 32'h0; 223 | 224 | if (cs) 225 | begin 226 | if (we) 227 | begin 228 | if (addr == ADDR_CTRL) 229 | begin 230 | init_new = write_data[CTRL_INIT_BIT]; 231 | next_new = write_data[CTRL_NEXT_BIT]; 232 | end 233 | 234 | if (addr == ADDR_KEYLEN) 235 | keylen_we = 1; 236 | 237 | if (addr == ADDR_ROUNDS) 238 | rounds_we = 1; 239 | 240 | if ((addr >= ADDR_KEY0) && (addr <= ADDR_KEY7)) 241 | key_we = 1; 242 | 243 | if ((addr >= ADDR_IV0) && (addr <= ADDR_IV1)) 244 | iv_we = 1; 245 | 246 | if ((addr >= ADDR_DATA_IN0) && (addr <= ADDR_DATA_IN15)) 247 | data_in_we = 1; 248 | 249 | end // if (we) 250 | 251 | else 252 | begin 253 | if ((addr >= ADDR_KEY0) && (addr <= ADDR_KEY7)) 254 | tmp_read_data = key_reg[addr[2 : 0]]; 255 | 256 | if ((addr >= ADDR_DATA_OUT0) && (addr <= ADDR_DATA_OUT15)) 257 | tmp_read_data = core_data_out[(15 - (addr - ADDR_DATA_OUT0)) * 32 +: 32]; 258 | 259 | case (addr) 260 | ADDR_NAME0: tmp_read_data = CORE_NAME0; 261 | ADDR_NAME1: tmp_read_data = CORE_NAME1; 262 | ADDR_VERSION: tmp_read_data = CORE_VERSION; 263 | ADDR_CTRL: tmp_read_data = {30'h0, next_reg, init_reg}; 264 | ADDR_STATUS: tmp_read_data = {30'h0, core_data_out_valid, core_ready}; 265 | ADDR_KEYLEN: tmp_read_data = {31'h0, keylen_reg}; 266 | ADDR_ROUNDS: tmp_read_data = {27'h0, rounds_reg}; 267 | ADDR_IV0: tmp_read_data = iv_reg[0]; 268 | ADDR_IV1: tmp_read_data = iv_reg[1]; 269 | 270 | default: 271 | begin 272 | end 273 | endcase // case (address) 274 | end 275 | end 276 | end // addr_decoder 277 | endmodule // chacha 278 | 279 | //====================================================================== 280 | // EOF chacha.v 281 | //====================================================================== 282 | -------------------------------------------------------------------------------- /src/rtl/chacha_core.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // chacha_core.v 4 | // -------------- 5 | // Verilog 2001 implementation of the stream cipher ChaCha. 6 | // This is the internal core with wide interfaces. 7 | // 8 | // 9 | // Copyright (c) 2013 Secworks Sweden AB 10 | // All rights reserved. 11 | // 12 | // Redistribution and use in source and binary forms, with or 13 | // without modification, are permitted provided that the following 14 | // conditions are met: 15 | // 16 | // 1. Redistributions of source code must retain the above copyright 17 | // notice, this list of conditions and the following disclaimer. 18 | // 19 | // 2. Redistributions in binary form must reproduce the above copyright 20 | // notice, this list of conditions and the following disclaimer in 21 | // the documentation and/or other materials provided with the 22 | // distribution. 23 | // 24 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 33 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 35 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | // 37 | //====================================================================== 38 | 39 | `default_nettype none 40 | 41 | module chacha_core( 42 | input wire clk, 43 | input wire reset_n, 44 | 45 | input wire init, 46 | input wire next, 47 | 48 | input wire [255 : 0] key, 49 | input wire keylen, 50 | input wire [63 : 0] iv, 51 | input wire [63 : 0] ctr, 52 | input wire [4 : 0] rounds, 53 | 54 | input wire [511 : 0] data_in, 55 | 56 | output wire ready, 57 | 58 | output wire [511 : 0] data_out, 59 | output wire data_out_valid 60 | ); 61 | 62 | 63 | //---------------------------------------------------------------- 64 | // Internal constant and parameter definitions. 65 | //---------------------------------------------------------------- 66 | // Datapath quartterround states names. 67 | localparam QR0 = 0; 68 | localparam QR1 = 1; 69 | 70 | localparam NUM_ROUNDS = 4'h8; 71 | 72 | localparam TAU0 = 32'h61707865; 73 | localparam TAU1 = 32'h3120646e; 74 | localparam TAU2 = 32'h79622d36; 75 | localparam TAU3 = 32'h6b206574; 76 | 77 | localparam SIGMA0 = 32'h61707865; 78 | localparam SIGMA1 = 32'h3320646e; 79 | localparam SIGMA2 = 32'h79622d32; 80 | localparam SIGMA3 = 32'h6b206574; 81 | 82 | localparam CTRL_IDLE = 3'h0; 83 | localparam CTRL_INIT = 3'h1; 84 | localparam CTRL_ROUNDS = 3'h2; 85 | localparam CTRL_FINALIZE = 3'h3; 86 | localparam CTRL_DONE = 3'h4; 87 | 88 | 89 | //---------------------------------------------------------------- 90 | // l2b() 91 | // 92 | // Swap bytes from little to big endian byte order. 93 | //---------------------------------------------------------------- 94 | function [31 : 0] l2b(input [31 : 0] op); 95 | begin 96 | l2b = {op[7 : 0], op[15 : 8], op[23 : 16], op[31 : 24]}; 97 | end 98 | endfunction // b2l 99 | 100 | 101 | //---------------------------------------------------------------- 102 | // Registers including update variables and write enable. 103 | //---------------------------------------------------------------- 104 | reg [31 : 0] state_reg [0 : 15]; 105 | reg [31 : 0] state_new [0 : 15]; 106 | reg state_we; 107 | 108 | reg [511 : 0] data_out_reg; 109 | reg [511 : 0] data_out_new; 110 | 111 | reg data_out_valid_reg; 112 | reg data_out_valid_new; 113 | reg data_out_valid_we; 114 | 115 | reg qr_ctr_reg; 116 | reg qr_ctr_new; 117 | reg qr_ctr_we; 118 | reg qr_ctr_inc; 119 | reg qr_ctr_rst; 120 | 121 | reg [3 : 0] dr_ctr_reg; 122 | reg [3 : 0] dr_ctr_new; 123 | reg dr_ctr_we; 124 | reg dr_ctr_inc; 125 | reg dr_ctr_rst; 126 | 127 | reg [31 : 0] block0_ctr_reg; 128 | reg [31 : 0] block0_ctr_new; 129 | reg block0_ctr_we; 130 | reg [31 : 0] block1_ctr_reg; 131 | reg [31 : 0] block1_ctr_new; 132 | reg block1_ctr_we; 133 | reg block_ctr_inc; 134 | reg block_ctr_set; 135 | 136 | reg ready_reg; 137 | reg ready_new; 138 | reg ready_we; 139 | 140 | reg [2 : 0] chacha_ctrl_reg; 141 | reg [2 : 0] chacha_ctrl_new; 142 | reg chacha_ctrl_we; 143 | 144 | 145 | //---------------------------------------------------------------- 146 | // Wires. 147 | //---------------------------------------------------------------- 148 | reg [31 : 0] init_state_word [0 : 15]; 149 | 150 | reg init_state; 151 | reg update_state; 152 | reg update_output; 153 | 154 | reg [31 : 0] qr0_a; 155 | reg [31 : 0] qr0_b; 156 | reg [31 : 0] qr0_c; 157 | reg [31 : 0] qr0_d; 158 | wire [31 : 0] qr0_a_prim; 159 | wire [31 : 0] qr0_b_prim; 160 | wire [31 : 0] qr0_c_prim; 161 | wire [31 : 0] qr0_d_prim; 162 | 163 | reg [31 : 0] qr1_a; 164 | reg [31 : 0] qr1_b; 165 | reg [31 : 0] qr1_c; 166 | reg [31 : 0] qr1_d; 167 | wire [31 : 0] qr1_a_prim; 168 | wire [31 : 0] qr1_b_prim; 169 | wire [31 : 0] qr1_c_prim; 170 | wire [31 : 0] qr1_d_prim; 171 | 172 | reg [31 : 0] qr2_a; 173 | reg [31 : 0] qr2_b; 174 | reg [31 : 0] qr2_c; 175 | reg [31 : 0] qr2_d; 176 | wire [31 : 0] qr2_a_prim; 177 | wire [31 : 0] qr2_b_prim; 178 | wire [31 : 0] qr2_c_prim; 179 | wire [31 : 0] qr2_d_prim; 180 | 181 | reg [31 : 0] qr3_a; 182 | reg [31 : 0] qr3_b; 183 | reg [31 : 0] qr3_c; 184 | reg [31 : 0] qr3_d; 185 | wire [31 : 0] qr3_a_prim; 186 | wire [31 : 0] qr3_b_prim; 187 | wire [31 : 0] qr3_c_prim; 188 | wire [31 : 0] qr3_d_prim; 189 | 190 | 191 | //---------------------------------------------------------------- 192 | // Instantiation of the qr modules. 193 | //---------------------------------------------------------------- 194 | chacha_qr qr0( 195 | .a(qr0_a), 196 | .b(qr0_b), 197 | .c(qr0_c), 198 | .d(qr0_d), 199 | 200 | .a_prim(qr0_a_prim), 201 | .b_prim(qr0_b_prim), 202 | .c_prim(qr0_c_prim), 203 | .d_prim(qr0_d_prim) 204 | ); 205 | 206 | chacha_qr qr1( 207 | .a(qr1_a), 208 | .b(qr1_b), 209 | .c(qr1_c), 210 | .d(qr1_d), 211 | 212 | .a_prim(qr1_a_prim), 213 | .b_prim(qr1_b_prim), 214 | .c_prim(qr1_c_prim), 215 | .d_prim(qr1_d_prim) 216 | ); 217 | 218 | chacha_qr qr2( 219 | .a(qr2_a), 220 | .b(qr2_b), 221 | .c(qr2_c), 222 | .d(qr2_d), 223 | 224 | .a_prim(qr2_a_prim), 225 | .b_prim(qr2_b_prim), 226 | .c_prim(qr2_c_prim), 227 | .d_prim(qr2_d_prim) 228 | ); 229 | 230 | chacha_qr qr3( 231 | .a(qr3_a), 232 | .b(qr3_b), 233 | .c(qr3_c), 234 | .d(qr3_d), 235 | 236 | .a_prim(qr3_a_prim), 237 | .b_prim(qr3_b_prim), 238 | .c_prim(qr3_c_prim), 239 | .d_prim(qr3_d_prim) 240 | ); 241 | 242 | 243 | //---------------------------------------------------------------- 244 | // Concurrent connectivity for ports etc. 245 | //---------------------------------------------------------------- 246 | assign data_out = data_out_reg; 247 | assign data_out_valid = data_out_valid_reg; 248 | assign ready = ready_reg; 249 | 250 | 251 | //---------------------------------------------------------------- 252 | // reg_update 253 | // 254 | // Update functionality for all registers in the core. 255 | // All registers are positive edge triggered with synchronous 256 | // active low reset. All registers have write enable. 257 | //---------------------------------------------------------------- 258 | always @ (posedge clk) 259 | begin : reg_update 260 | integer i; 261 | 262 | if (!reset_n) 263 | begin 264 | for (i = 0 ; i < 16 ; i = i + 1) 265 | state_reg[i] <= 32'h0; 266 | 267 | data_out_reg <= 512'h0; 268 | data_out_valid_reg <= 0; 269 | qr_ctr_reg <= QR0; 270 | dr_ctr_reg <= 0; 271 | block0_ctr_reg <= 32'h0; 272 | block1_ctr_reg <= 32'h0; 273 | chacha_ctrl_reg <= CTRL_IDLE; 274 | ready_reg <= 1; 275 | end 276 | else 277 | begin 278 | if (state_we) 279 | begin 280 | for (i = 0 ; i < 16 ; i = i + 1) 281 | state_reg[i] <= state_new[i]; 282 | end 283 | 284 | if (update_output) 285 | data_out_reg <= data_out_new; 286 | 287 | if (data_out_valid_we) 288 | data_out_valid_reg <= data_out_valid_new; 289 | 290 | if (qr_ctr_we) 291 | qr_ctr_reg <= qr_ctr_new; 292 | 293 | if (dr_ctr_we) 294 | dr_ctr_reg <= dr_ctr_new; 295 | 296 | if (block0_ctr_we) 297 | block0_ctr_reg <= block0_ctr_new; 298 | 299 | if (block1_ctr_we) 300 | block1_ctr_reg <= block1_ctr_new; 301 | 302 | if (ready_we) 303 | ready_reg <= ready_new; 304 | 305 | if (chacha_ctrl_we) 306 | chacha_ctrl_reg <= chacha_ctrl_new; 307 | end 308 | end // reg_update 309 | 310 | 311 | //---------------------------------------------------------------- 312 | // init_state_logic 313 | // 314 | // Calculates the initial state for a given block. 315 | //---------------------------------------------------------------- 316 | always @* 317 | begin : init_state_logic 318 | reg [31 : 0] key0; 319 | reg [31 : 0] key1; 320 | reg [31 : 0] key2; 321 | reg [31 : 0] key3; 322 | reg [31 : 0] key4; 323 | reg [31 : 0] key5; 324 | reg [31 : 0] key6; 325 | reg [31 : 0] key7; 326 | 327 | key0 = l2b(key[255 : 224]); 328 | key1 = l2b(key[223 : 192]); 329 | key2 = l2b(key[191 : 160]); 330 | key3 = l2b(key[159 : 128]); 331 | key4 = l2b(key[127 : 96]); 332 | key5 = l2b(key[95 : 64]); 333 | key6 = l2b(key[63 : 32]); 334 | key7 = l2b(key[31 : 0]); 335 | 336 | init_state_word[04] = key0; 337 | init_state_word[05] = key1; 338 | init_state_word[06] = key2; 339 | init_state_word[07] = key3; 340 | init_state_word[12] = block0_ctr_reg; 341 | init_state_word[13] = block1_ctr_reg; 342 | init_state_word[14] = l2b(iv[63 : 32]); 343 | init_state_word[15] = l2b(iv[31 : 0]); 344 | 345 | if (keylen) 346 | begin 347 | // 256 bit key. 348 | init_state_word[00] = SIGMA0; 349 | init_state_word[01] = SIGMA1; 350 | init_state_word[02] = SIGMA2; 351 | init_state_word[03] = SIGMA3; 352 | init_state_word[08] = key4; 353 | init_state_word[09] = key5; 354 | init_state_word[10] = key6; 355 | init_state_word[11] = key7; 356 | end 357 | else 358 | begin 359 | // 128 bit key. 360 | init_state_word[00] = TAU0; 361 | init_state_word[01] = TAU1; 362 | init_state_word[02] = TAU2; 363 | init_state_word[03] = TAU3; 364 | init_state_word[08] = key0; 365 | init_state_word[09] = key1; 366 | init_state_word[10] = key2; 367 | init_state_word[11] = key3; 368 | end 369 | end 370 | 371 | 372 | //---------------------------------------------------------------- 373 | // state_logic 374 | // Logic to init and update the internal state. 375 | //---------------------------------------------------------------- 376 | always @* 377 | begin : state_logic 378 | integer i; 379 | 380 | for (i = 0 ; i < 16 ; i = i + 1) 381 | state_new[i] = 32'h0; 382 | state_we = 0; 383 | 384 | qr0_a = 32'h0; 385 | qr0_b = 32'h0; 386 | qr0_c = 32'h0; 387 | qr0_d = 32'h0; 388 | qr1_a = 32'h0; 389 | qr1_b = 32'h0; 390 | qr1_c = 32'h0; 391 | qr1_d = 32'h0; 392 | qr2_a = 32'h0; 393 | qr2_b = 32'h0; 394 | qr2_c = 32'h0; 395 | qr2_d = 32'h0; 396 | qr3_a = 32'h0; 397 | qr3_b = 32'h0; 398 | qr3_c = 32'h0; 399 | qr3_d = 32'h0; 400 | 401 | if (init_state) 402 | begin 403 | for (i = 0 ; i < 16 ; i = i + 1) 404 | state_new[i] = init_state_word[i]; 405 | state_we = 1; 406 | end // if (init_state) 407 | 408 | if (update_state) 409 | begin 410 | state_we = 1; 411 | case (qr_ctr_reg) 412 | QR0: 413 | begin 414 | qr0_a = state_reg[00]; 415 | qr0_b = state_reg[04]; 416 | qr0_c = state_reg[08]; 417 | qr0_d = state_reg[12]; 418 | qr1_a = state_reg[01]; 419 | qr1_b = state_reg[05]; 420 | qr1_c = state_reg[09]; 421 | qr1_d = state_reg[13]; 422 | qr2_a = state_reg[02]; 423 | qr2_b = state_reg[06]; 424 | qr2_c = state_reg[10]; 425 | qr2_d = state_reg[14]; 426 | qr3_a = state_reg[03]; 427 | qr3_b = state_reg[07]; 428 | qr3_c = state_reg[11]; 429 | qr3_d = state_reg[15]; 430 | state_new[00] = qr0_a_prim; 431 | state_new[04] = qr0_b_prim; 432 | state_new[08] = qr0_c_prim; 433 | state_new[12] = qr0_d_prim; 434 | state_new[01] = qr1_a_prim; 435 | state_new[05] = qr1_b_prim; 436 | state_new[09] = qr1_c_prim; 437 | state_new[13] = qr1_d_prim; 438 | state_new[02] = qr2_a_prim; 439 | state_new[06] = qr2_b_prim; 440 | state_new[10] = qr2_c_prim; 441 | state_new[14] = qr2_d_prim; 442 | state_new[03] = qr3_a_prim; 443 | state_new[07] = qr3_b_prim; 444 | state_new[11] = qr3_c_prim; 445 | state_new[15] = qr3_d_prim; 446 | end 447 | 448 | QR1: 449 | begin 450 | qr0_a = state_reg[00]; 451 | qr0_b = state_reg[05]; 452 | qr0_c = state_reg[10]; 453 | qr0_d = state_reg[15]; 454 | qr1_a = state_reg[01]; 455 | qr1_b = state_reg[06]; 456 | qr1_c = state_reg[11]; 457 | qr1_d = state_reg[12]; 458 | qr2_a = state_reg[02]; 459 | qr2_b = state_reg[07]; 460 | qr2_c = state_reg[08]; 461 | qr2_d = state_reg[13]; 462 | qr3_a = state_reg[03]; 463 | qr3_b = state_reg[04]; 464 | qr3_c = state_reg[09]; 465 | qr3_d = state_reg[14]; 466 | state_new[00] = qr0_a_prim; 467 | state_new[05] = qr0_b_prim; 468 | state_new[10] = qr0_c_prim; 469 | state_new[15] = qr0_d_prim; 470 | state_new[01] = qr1_a_prim; 471 | state_new[06] = qr1_b_prim; 472 | state_new[11] = qr1_c_prim; 473 | state_new[12] = qr1_d_prim; 474 | state_new[02] = qr2_a_prim; 475 | state_new[07] = qr2_b_prim; 476 | state_new[08] = qr2_c_prim; 477 | state_new[13] = qr2_d_prim; 478 | state_new[03] = qr3_a_prim; 479 | state_new[04] = qr3_b_prim; 480 | state_new[09] = qr3_c_prim; 481 | state_new[14] = qr3_d_prim; 482 | end 483 | endcase // case (quarterround_select) 484 | end // if (update_state) 485 | end // state_logic 486 | 487 | 488 | //---------------------------------------------------------------- 489 | // data_out_logic 490 | // Final output logic that combines the result from state 491 | // update with the input block. This adds a 16 rounds and 492 | // a final layer of XOR gates. 493 | // 494 | // Note that we also remap all the words into LSB format. 495 | //---------------------------------------------------------------- 496 | always @* 497 | begin : data_out_logic 498 | integer i; 499 | reg [31 : 0] msb_block_state [0 : 15]; 500 | reg [31 : 0] lsb_block_state [0 : 15]; 501 | reg [511 : 0] block_state; 502 | 503 | for (i = 0 ; i < 16 ; i = i + 1) 504 | begin 505 | msb_block_state[i] = init_state_word[i] + state_reg[i]; 506 | lsb_block_state[i] = l2b(msb_block_state[i][31 : 0]); 507 | end 508 | 509 | block_state = {lsb_block_state[00], lsb_block_state[01], 510 | lsb_block_state[02], lsb_block_state[03], 511 | lsb_block_state[04], lsb_block_state[05], 512 | lsb_block_state[06], lsb_block_state[07], 513 | lsb_block_state[08], lsb_block_state[09], 514 | lsb_block_state[10], lsb_block_state[11], 515 | lsb_block_state[12], lsb_block_state[13], 516 | lsb_block_state[14], lsb_block_state[15]}; 517 | 518 | data_out_new = data_in ^ block_state; 519 | end // data_out_logic 520 | 521 | 522 | //---------------------------------------------------------------- 523 | // qr_ctr 524 | // Update logic for the quarterround counter, a monotonically 525 | // increasing counter with reset. 526 | //---------------------------------------------------------------- 527 | always @* 528 | begin : qr_ctr 529 | qr_ctr_new = 0; 530 | qr_ctr_we = 0; 531 | 532 | if (qr_ctr_rst) 533 | begin 534 | qr_ctr_new = 0; 535 | qr_ctr_we = 1; 536 | end 537 | 538 | if (qr_ctr_inc) 539 | begin 540 | qr_ctr_new = qr_ctr_reg + 1'b1; 541 | qr_ctr_we = 1; 542 | end 543 | end // qr_ctr 544 | 545 | 546 | //---------------------------------------------------------------- 547 | // dr_ctr 548 | // Update logic for the round counter, a monotonically 549 | // increasing counter with reset. 550 | //---------------------------------------------------------------- 551 | always @* 552 | begin : dr_ctr 553 | dr_ctr_new = 0; 554 | dr_ctr_we = 0; 555 | 556 | if (dr_ctr_rst) 557 | begin 558 | dr_ctr_new = 0; 559 | dr_ctr_we = 1; 560 | end 561 | 562 | if (dr_ctr_inc) 563 | begin 564 | dr_ctr_new = dr_ctr_reg + 1'b1; 565 | dr_ctr_we = 1; 566 | end 567 | end // dr_ctr 568 | 569 | 570 | //---------------------------------------------------------------- 571 | // block_ctr 572 | // Update logic for the 64-bit block counter, a monotonically 573 | // increasing counter with reset. 574 | //---------------------------------------------------------------- 575 | always @* 576 | begin : block_ctr 577 | block0_ctr_new = 32'h0; 578 | block1_ctr_new = 32'h0; 579 | block0_ctr_we = 0; 580 | block1_ctr_we = 0; 581 | 582 | if (block_ctr_set) 583 | begin 584 | block0_ctr_new = ctr[31 : 00]; 585 | block1_ctr_new = ctr[63 : 32]; 586 | block0_ctr_we = 1; 587 | block1_ctr_we = 1; 588 | end 589 | 590 | if (block_ctr_inc) 591 | begin 592 | block0_ctr_new = block0_ctr_reg + 1; 593 | block0_ctr_we = 1; 594 | 595 | // Avoid chaining the 32-bit adders. 596 | if (block0_ctr_reg == 32'hffffffff) 597 | begin 598 | block1_ctr_new = block1_ctr_reg + 1; 599 | block1_ctr_we = 1; 600 | end 601 | end 602 | end // block_ctr 603 | 604 | 605 | //---------------------------------------------------------------- 606 | // chacha_ctrl_fsm 607 | // Logic for the state machine controlling the core behaviour. 608 | //---------------------------------------------------------------- 609 | always @* 610 | begin : chacha_ctrl_fsm 611 | init_state = 0; 612 | update_state = 0; 613 | update_output = 0; 614 | qr_ctr_inc = 0; 615 | qr_ctr_rst = 0; 616 | dr_ctr_inc = 0; 617 | dr_ctr_rst = 0; 618 | block_ctr_inc = 0; 619 | block_ctr_set = 0; 620 | ready_new = 0; 621 | ready_we = 0; 622 | data_out_valid_new = 0; 623 | data_out_valid_we = 0; 624 | chacha_ctrl_new = CTRL_IDLE; 625 | chacha_ctrl_we = 0; 626 | 627 | case (chacha_ctrl_reg) 628 | CTRL_IDLE: 629 | begin 630 | if (init) 631 | begin 632 | block_ctr_set = 1; 633 | ready_new = 0; 634 | ready_we = 1; 635 | chacha_ctrl_new = CTRL_INIT; 636 | chacha_ctrl_we = 1; 637 | end 638 | end 639 | 640 | CTRL_INIT: 641 | begin 642 | init_state = 1; 643 | qr_ctr_rst = 1; 644 | dr_ctr_rst = 1; 645 | chacha_ctrl_new = CTRL_ROUNDS; 646 | chacha_ctrl_we = 1; 647 | end 648 | 649 | CTRL_ROUNDS: 650 | begin 651 | update_state = 1; 652 | qr_ctr_inc = 1; 653 | if (qr_ctr_reg == QR1) 654 | begin 655 | dr_ctr_inc = 1; 656 | if (dr_ctr_reg == (rounds[4 : 1] - 1)) 657 | begin 658 | chacha_ctrl_new = CTRL_FINALIZE; 659 | chacha_ctrl_we = 1; 660 | end 661 | end 662 | end 663 | 664 | CTRL_FINALIZE: 665 | begin 666 | ready_new = 1; 667 | ready_we = 1; 668 | update_output = 1; 669 | data_out_valid_new = 1; 670 | data_out_valid_we = 1; 671 | chacha_ctrl_new = CTRL_DONE; 672 | chacha_ctrl_we = 1; 673 | end 674 | 675 | CTRL_DONE: 676 | begin 677 | if (init) 678 | begin 679 | ready_new = 0; 680 | ready_we = 1; 681 | data_out_valid_new = 0; 682 | data_out_valid_we = 1; 683 | block_ctr_set = 1; 684 | chacha_ctrl_new = CTRL_INIT; 685 | chacha_ctrl_we = 1; 686 | end 687 | else if (next) 688 | begin 689 | ready_new = 0; 690 | ready_we = 1; 691 | data_out_valid_new = 0; 692 | data_out_valid_we = 1; 693 | block_ctr_inc = 1; 694 | chacha_ctrl_new = CTRL_INIT; 695 | chacha_ctrl_we = 1; 696 | end 697 | end 698 | 699 | default: 700 | begin 701 | 702 | end 703 | endcase // case (chacha_ctrl_reg) 704 | end // chacha_ctrl_fsm 705 | endmodule // chacha_core 706 | 707 | //====================================================================== 708 | // EOF chacha_core.v 709 | //====================================================================== 710 | -------------------------------------------------------------------------------- /src/tb/tb_chacha_core.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // tb_chacha_core.v 4 | // ----------------- 5 | // Testbench for the Chacha stream cipher core. 6 | // 7 | // 8 | // Copyright (c) 2013, Secworks Sweden AB 9 | // All rights reserved. 10 | // 11 | // Redistribution and use in source and binary forms, with or 12 | // without modification, are permitted provided that the following 13 | // conditions are met: 14 | // 15 | // 1. Redistributions of source code must retain the above copyright 16 | // notice, this list of conditions and the following disclaimer. 17 | // 18 | // 2. Redistributions in binary form must reproduce the above copyright 19 | // notice, this list of conditions and the following disclaimer in 20 | // the documentation and/or other materials provided with the 21 | // distribution. 22 | // 23 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 34 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | // 36 | //====================================================================== 37 | 38 | `default_nettype none 39 | 40 | module tb_chacha_core(); 41 | 42 | //---------------------------------------------------------------- 43 | // Internal constant and parameter definitions. 44 | //---------------------------------------------------------------- 45 | parameter CLK_HALF_PERIOD = 2; 46 | parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD; 47 | 48 | parameter TC1 = 1; 49 | parameter TC2 = 2; 50 | parameter TC3 = 3; 51 | parameter TC4 = 4; 52 | parameter TC5 = 5; 53 | parameter TC6 = 6; 54 | parameter TC7 = 7; 55 | parameter TC8 = 8; 56 | parameter TC9 = 9; 57 | parameter TC10 = 10; 58 | 59 | parameter ONE = 1; 60 | parameter TWO = 2; 61 | parameter THREE = 3; 62 | parameter FOUR = 4; 63 | parameter FIVE = 5; 64 | parameter SIX = 6; 65 | parameter SEVEN = 7; 66 | parameter EIGHT = 8; 67 | 68 | parameter KEY_128_BITS = 0; 69 | parameter KEY_256_BITS = 1; 70 | 71 | parameter EIGHT_ROUNDS = 8; 72 | parameter TWELWE_ROUNDS = 12; 73 | parameter TWENTY_ROUNDS = 20; 74 | 75 | parameter DISABLE = 0; 76 | parameter ENABLE = 1; 77 | 78 | localparam DEFAULT_CTR_INIT = 64'h0; 79 | 80 | 81 | //---------------------------------------------------------------- 82 | // Register and Wire declarations. 83 | //---------------------------------------------------------------- 84 | reg [31 : 0] cycle_ctr; 85 | reg [31 : 0] error_ctr; 86 | reg [31 : 0] tc_ctr; 87 | 88 | reg tb_clk; 89 | reg tb_reset_n; 90 | 91 | reg tb_core_init; 92 | reg tb_core_next; 93 | reg [255 : 0] tb_core_key; 94 | reg tb_core_keylen; 95 | reg [4 : 0] tb_core_rounds; 96 | reg [63 : 0] tb_core_iv; 97 | wire tb_core_ready; 98 | reg [0 : 511] tb_core_data_in; 99 | wire [0 : 511] tb_core_data_out; 100 | wire tb_core_data_out_valid; 101 | 102 | reg display_cycle_ctr; 103 | reg display_ctrl_and_ctrs; 104 | reg display_qround; 105 | reg display_state; 106 | 107 | 108 | //---------------------------------------------------------------- 109 | // chacha_core device under test. 110 | //---------------------------------------------------------------- 111 | chacha_core dut( 112 | // Clock and reset. 113 | .clk(tb_clk), 114 | .reset_n(tb_reset_n), 115 | 116 | // Control. 117 | .init(tb_core_init), 118 | .next(tb_core_next), 119 | 120 | // Parameters. 121 | .key(tb_core_key), 122 | .keylen(tb_core_keylen), 123 | .iv(tb_core_iv), 124 | .ctr(DEFAULT_CTR_INIT), 125 | .rounds(tb_core_rounds), 126 | 127 | // Data input. 128 | .data_in(tb_core_data_in), 129 | 130 | // Status output. 131 | .ready(tb_core_ready), 132 | 133 | // Data out with valid signal. 134 | .data_out(tb_core_data_out), 135 | .data_out_valid(tb_core_data_out_valid) 136 | ); 137 | 138 | 139 | //---------------------------------------------------------------- 140 | // clk_gen 141 | // 142 | // Clock generator process. 143 | //---------------------------------------------------------------- 144 | always 145 | begin : clk_gen 146 | #CLK_HALF_PERIOD tb_clk = !tb_clk; 147 | end // clk_gen 148 | 149 | 150 | //-------------------------------------------------------------------- 151 | // dut_monitor 152 | // 153 | // Monitor that displays different types of information 154 | // every cycle depending on what flags test cases enable. 155 | // 156 | // The monitor includes a cycle counter for the testbench. 157 | //-------------------------------------------------------------------- 158 | always @ (posedge tb_clk) 159 | begin : dut_monitor 160 | cycle_ctr = cycle_ctr + 1; 161 | 162 | // Display cycle counter. 163 | if (display_cycle_ctr) 164 | begin 165 | $display("cycle = %08x:", cycle_ctr); 166 | $display(""); 167 | end 168 | 169 | // Display FSM control state and QR, DR counters. 170 | if (display_ctrl_and_ctrs) 171 | begin 172 | $display("chacha_ctrl_reg = %01x", dut.chacha_ctrl_reg); 173 | $display("qr_ctr_reg = %01x, dr_ctr_reg = %01x", dut.qr_ctr_reg, dut.dr_ctr_reg); 174 | $display(""); 175 | end 176 | 177 | // Display the internal state register. 178 | if (display_state) 179 | begin 180 | $display("Round state:"); 181 | $display("state0_reg = 0x%08x, state0_new = 0x%08x", dut.state_reg[00], dut.state_new[00]); 182 | $display("state1_reg = 0x%08x, state1_new = 0x%08x", dut.state_reg[01], dut.state_new[01]); 183 | $display("state2_reg = 0x%08x, state2_new = 0x%08x", dut.state_reg[02], dut.state_new[02]); 184 | $display("state3_reg = 0x%08x, state3_new = 0x%08x", dut.state_reg[03], dut.state_new[03]); 185 | $display("state4_reg = 0x%08x, state4_new = 0x%08x", dut.state_reg[04], dut.state_new[04]); 186 | $display("state5_reg = 0x%08x, state5_new = 0x%08x", dut.state_reg[05], dut.state_new[05]); 187 | $display("state6_reg = 0x%08x, state6_new = 0x%08x", dut.state_reg[06], dut.state_new[06]); 188 | $display("state7_reg = 0x%08x, state7_new = 0x%08x", dut.state_reg[07], dut.state_new[07]); 189 | $display("state8_reg = 0x%08x, state8_new = 0x%08x", dut.state_reg[08], dut.state_new[08]); 190 | $display("state9_reg = 0x%08x, state9_new = 0x%08x", dut.state_reg[09], dut.state_new[09]); 191 | $display("state10_reg = 0x%08x, state10_new = 0x%08x", dut.state_reg[10], dut.state_new[10]); 192 | $display("state11_reg = 0x%08x, state11_new = 0x%08x", dut.state_reg[11], dut.state_new[11]); 193 | $display("state12_reg = 0x%08x, state12_new = 0x%08x", dut.state_reg[12], dut.state_new[12]); 194 | $display("state13_reg = 0x%08x, state13_new = 0x%08x", dut.state_reg[13], dut.state_new[13]); 195 | $display("state14_reg = 0x%08x, state14_new = 0x%08x", dut.state_reg[14], dut.state_new[14]); 196 | $display("state15_reg = 0x%08x, state15_new = 0x%08x", dut.state_reg[15], dut.state_new[15]); 197 | $display("state_we = 0x%01x", dut.state_we); 198 | $display(""); 199 | end 200 | 201 | // Display the qround input and outputs. 202 | if (display_qround) 203 | begin 204 | $display("a = %08x, b = %08x, c = %08x, d = %08x", dut.qr0_a, dut.qr0_b, dut.qr0_c, dut.qr0_d); 205 | $display("qr0_a_prim = %08x, qr0_b_prim = %08x, qr0_c_prim = %08x, qr0_d_prim = %08x", dut.qr0_a_prim, dut.qr0_b_prim, dut.qr0_c_prim, dut.qr0_d_prim); 206 | $display(""); 207 | end 208 | end // dut_monitor 209 | 210 | 211 | //---------------------------------------------------------------- 212 | // dump_state() 213 | // Dump the internal CHACHA state to std out. 214 | //---------------------------------------------------------------- 215 | task dump_state; 216 | begin 217 | $display(""); 218 | $display("Internal state:"); 219 | $display("---------------"); 220 | $display("Round state:"); 221 | $display("state0_reg = %08x, state1_reg = %08x, state2_reg = %08x, state3_reg = %08x", 222 | dut.state_reg[00], dut.state_reg[01], dut.state_reg[02], dut.state_reg[03]); 223 | $display("state4_reg = %08x, state5_reg = %08x, state6_reg = %08x, state7_reg = %08x", 224 | dut.state_reg[04], dut.state_reg[05], dut.state_reg[06], dut.state_reg[07]); 225 | $display("state8_reg = %08x, state9_reg = %08x, state10_reg = %08x, state11_reg = %08x", 226 | dut.state_reg[08], dut.state_reg[09], dut.state_reg[10], dut.state_reg[11]); 227 | $display("state12_reg = %08x, state13_reg = %08x, state14_reg = %08x, state15_reg = %08x", 228 | dut.state_reg[12], dut.state_reg[13], dut.state_reg[14], dut.state_reg[15]); 229 | $display(""); 230 | 231 | $display("rounds = %01x", dut.rounds); 232 | $display("qr_ctr_reg = %01x, dr_ctr_reg = %01x", dut.qr_ctr_reg, dut.dr_ctr_reg); 233 | $display("block0_ctr_reg = %08x, block1_ctr_reg = %08x", dut.block0_ctr_reg, dut.block1_ctr_reg); 234 | 235 | $display(""); 236 | 237 | $display("chacha_ctrl_reg = %02x", dut.chacha_ctrl_reg); 238 | $display(""); 239 | 240 | $display("data_in = %064x", dut.data_in); 241 | $display("data_out_valid_reg = %01x", dut.data_out_valid_reg); 242 | $display(""); 243 | 244 | $display("qr0_a_prim = %08x, qr0_b_prim = %08x", dut.qr0_a_prim, dut.qr0_b_prim); 245 | $display("qr0_c_prim = %08x, qr0_d_prim = %08x", dut.qr0_c_prim, dut.qr0_d_prim); 246 | $display(""); 247 | end 248 | endtask // dump_state 249 | 250 | 251 | //---------------------------------------------------------------- 252 | // dump_inout() 253 | // Dump the status for input and output ports. 254 | //---------------------------------------------------------------- 255 | task dump_inout; 256 | begin 257 | $display(""); 258 | $display("State for input and output ports:"); 259 | $display("---------------------------------"); 260 | 261 | $display("init = %01x", dut.init); 262 | $display("next = %01x", dut.next); 263 | $display("keylen = %01x", dut.keylen); 264 | $display(""); 265 | 266 | $display("key = %032x", dut.key); 267 | $display("iv = %016x", dut.iv); 268 | $display(""); 269 | 270 | $display("ready = %01x", dut.ready); 271 | $display("data_in = %064x", dut.data_in); 272 | $display("data_out = %064x", dut.data_out); 273 | $display("data_out_valid = %01x", dut.data_out_valid); 274 | $display(""); 275 | end 276 | endtask // dump_inout 277 | 278 | 279 | //---------------------------------------------------------------- 280 | // test_quarterround() 281 | // 282 | // Test the quarterround by forcing the inputs of the logic 283 | // to known given values and observing the result. 284 | //---------------------------------------------------------------- 285 | task test_quarterround(input [31 : 0] a, input [31 : 0] b, 286 | input [31 : 0] c, input [31 : 0] d); 287 | begin 288 | $display("Test of quarterround."); 289 | $display("a = 0x%08x, b = 0x%08x", a, b); 290 | $display("c = 0x%08x, d = 0x%08x", c, d); 291 | $display(""); 292 | 293 | dut.qr0_a = a; 294 | dut.qr0_b = b; 295 | dut.qr0_c = c; 296 | dut.qr0_d = d; 297 | #(CLK_PERIOD); 298 | 299 | $display("a0 = 0x%08x, a1 = 0x%08x", dut.qr0.qr.a0, dut.qr0.qr.a1); 300 | $display("b0 = 0x%08x, b1 = 0x%08x", dut.qr0.qr.b0, dut.qr0.qr.b1); 301 | $display("b2 = 0x%08x, b3 = 0x%08x", dut.qr0.qr.b2, dut.qr0.qr.b3); 302 | $display("c0 = 0x%08x, c1 = 0x%08x", dut.qr0.qr.c0, dut.qr0.qr.c1); 303 | $display("d0 = 0x%08x, d1 = 0x%08x", dut.qr0.qr.d0, dut.qr0.qr.d1); 304 | $display("d2 = 0x%08x, d3 = 0x%08x", dut.qr0.qr.d2, dut.qr0.qr.d3); 305 | $display(""); 306 | 307 | $display("a_prim = 0x%08x, b_prim = 0x%08x", dut.qr0_a_prim, dut.qr0_b_prim); 308 | $display("c_prim = 0x%08x, d_prim = 0x%08x", dut.qr0_c_prim, dut.qr0_d_prim); 309 | $display(""); 310 | end 311 | endtask // test_quarterround 312 | 313 | 314 | //---------------------------------------------------------------- 315 | // qr_tests() 316 | // 317 | // Run some simple test on the qr logic. 318 | // Note: Not self testing. No expected value used. 319 | //---------------------------------------------------------------- 320 | task qr_tests; 321 | begin 322 | $display("*** Test of Quarterround:"); 323 | $display(""); 324 | test_quarterround(32'h11223344, 32'h11223344, 32'h11223344, 32'h11223344); 325 | test_quarterround(32'h55555555, 32'h55555555, 32'h55555555, 32'h55555555); 326 | end 327 | endtask // qr_tests 328 | 329 | 330 | //---------------------------------------------------------------- 331 | // set_core_init() 332 | // 333 | // Set core init flag to given value. 334 | //---------------------------------------------------------------- 335 | task set_core_init(input value); 336 | begin 337 | tb_core_init = value; 338 | end 339 | endtask // set_core_init 340 | 341 | 342 | //---------------------------------------------------------------- 343 | // set_core_next() 344 | // 345 | // Set code next flag to given value. 346 | //---------------------------------------------------------------- 347 | task set_core_next(input value); 348 | begin 349 | tb_core_next = value; 350 | end 351 | endtask // set_core_next 352 | 353 | 354 | //---------------------------------------------------------------- 355 | // set_core_key_iv_rounds() 356 | // 357 | // Sets the core key, iv and rounds indata ports 358 | // to the given values. 359 | //---------------------------------------------------------------- 360 | task set_core_key_iv_rounds(input [255 : 0] key, 361 | input key_length, 362 | input [63 : 0] iv, 363 | input [4 : 0] rounds); 364 | begin 365 | tb_core_key = key; 366 | tb_core_keylen = key_length; 367 | tb_core_iv = iv; 368 | tb_core_rounds = rounds; 369 | end 370 | endtask // set_core_key_iv 371 | 372 | 373 | //---------------------------------------------------------------- 374 | // cycle_reset() 375 | // 376 | // Cycles the reset signal on the dut. 377 | //---------------------------------------------------------------- 378 | task cycle_reset; 379 | begin 380 | tb_reset_n = 0; 381 | #(CLK_PERIOD); 382 | 383 | @(negedge tb_clk) 384 | 385 | tb_reset_n = 1; 386 | #(CLK_PERIOD); 387 | end 388 | endtask // cycle_reset 389 | 390 | 391 | //---------------------------------------------------------------- 392 | // run_test_case 393 | // 394 | // Runs a test case based on the given key, keylenght, IV and 395 | // expected data out from the DUT. 396 | //---------------------------------------------------------------- 397 | task run_test_case(input [7 : 0] major, 398 | input [7 : 0] minor, 399 | input [255 : 0] key, 400 | input key_length, 401 | input [63 : 0] iv, 402 | input [4 : 0] rounds, 403 | input [511 : 0] expected); 404 | begin 405 | $display("*** TC %0d-%0d started.", major, minor); 406 | $display(""); 407 | 408 | tc_ctr = tc_ctr + 1; 409 | 410 | cycle_reset(); 411 | set_core_key_iv_rounds(key, key_length, iv, rounds); 412 | set_core_init(1); 413 | 414 | #(CLK_PERIOD); 415 | set_core_init(0); 416 | dump_state(); 417 | 418 | // Wait for valid flag and check results. 419 | @(posedge dut.data_out_valid); 420 | dump_state(); 421 | 422 | if (tb_core_data_out == expected) 423 | begin 424 | $display("*** TC %0d-%0d successful", major, minor); 425 | $display(""); 426 | end 427 | else 428 | begin 429 | $display("*** ERROR: TC %0d-%0d not successful", major, minor); 430 | $display("Expected: 0x%064x", expected); 431 | $display("Got: 0x%064x", tb_core_data_out); 432 | $display(""); 433 | 434 | error_ctr = error_ctr + 1; 435 | end 436 | end 437 | endtask // run_test_case 438 | 439 | 440 | //---------------------------------------------------------------- 441 | // display_test_result() 442 | // 443 | // Display the accumulated test results. 444 | //---------------------------------------------------------------- 445 | task display_test_result; 446 | begin 447 | if (error_ctr == 0) 448 | begin 449 | $display("*** All test cases completed successfully"); 450 | end 451 | else 452 | begin 453 | $display("*** %02d test cases did not complete successfully.", error_ctr); 454 | end 455 | end 456 | endtask // display_test_result 457 | 458 | 459 | //---------------------------------------------------------------- 460 | // init_dut() 461 | // 462 | // Set the input to the DUT to defined values. 463 | //---------------------------------------------------------------- 464 | task init_dut; 465 | begin 466 | cycle_ctr = 0; 467 | tb_clk = 0; 468 | tb_reset_n = 0; 469 | error_ctr = 0; 470 | tc_ctr = 0; 471 | set_core_key_iv_rounds(256'h0000000000000001000000000000000100000000000000010000000000000001, 472 | 1'b0, 473 | 64'h0000000000000001, 474 | 5'b01000); 475 | 476 | tb_core_init = 0; 477 | tb_core_next = 0; 478 | tb_core_data_in = 512'h0; 479 | end 480 | endtask // init_dut 481 | 482 | 483 | //---------------------------------------------------------------- 484 | // set_display_prefs() 485 | // 486 | // Set the different monitor displays we want to see during 487 | // simulation. 488 | //---------------------------------------------------------------- 489 | task set_display_prefs( 490 | input cycles, 491 | input ctrl_ctr, 492 | input state, 493 | input x_state, 494 | input qround); 495 | begin 496 | display_cycle_ctr = cycles; 497 | display_ctrl_and_ctrs = ctrl_ctr; 498 | display_state = state; 499 | display_qround = qround; 500 | end 501 | endtask // set_display_prefs 502 | 503 | 504 | //---------------------------------------------------------------- 505 | // chacha_core_test 506 | // 507 | // The main test functionality. 508 | //---------------------------------------------------------------- 509 | initial 510 | begin : chacha_core_test 511 | $display(" -- Testbench for chacha_core started --"); 512 | $display(""); 513 | 514 | set_display_prefs(0, 0, 1, 1, 0); 515 | qr_tests(); 516 | init_dut(); 517 | $display("*** State at init:"); 518 | $display(""); 519 | dump_state(); 520 | 521 | #(2 * CLK_PERIOD); 522 | @(negedge tb_clk) 523 | tb_reset_n = 1; 524 | #(CLK_PERIOD); 525 | $display("*** State after release of reset:"); 526 | $display(""); 527 | dump_state(); 528 | 529 | $display("TC1-1: All zero inputs. 128 bit key, 8 rounds."); 530 | run_test_case(TC1, ONE, 531 | 256'h0, 532 | KEY_128_BITS, 533 | 64'h0, 534 | EIGHT_ROUNDS, 535 | 512'he28a5fa4a67f8c5defed3e6fb7303486aa8427d31419a729572d777953491120b64ab8e72b8deb85cd6aea7cb6089a101824beeb08814a428aab1fa2c816081b); 536 | 537 | 538 | $display("TC1-2: All zero inputs. 128 bit key, 12 rounds."); 539 | run_test_case(TC1, TWO, 540 | 256'h0, 541 | KEY_128_BITS, 542 | 64'h0, 543 | TWELWE_ROUNDS, 544 | 512'he1047ba9476bf8ff312c01b4345a7d8ca5792b0ad467313f1dc412b5fdce32410dea8b68bd774c36a920f092a04d3f95274fbeff97bc8491fcef37f85970b450); 545 | 546 | 547 | $display("TC1-3: All zero inputs. 128 bit key, 20 rounds."); 548 | run_test_case(TC1, THREE, 549 | 256'h0, 550 | KEY_128_BITS, 551 | 64'h0, 552 | TWENTY_ROUNDS, 553 | 512'h89670952608364fd00b2f90936f031c8e756e15dba04b8493d00429259b20f46cc04f111246b6c2ce066be3bfb32d9aa0fddfbc12123d4b9e44f34dca05a103f); 554 | 555 | 556 | $display("TC1-4: All zero inputs. 256 bit key, 8 rounds."); 557 | run_test_case(TC1, FOUR, 558 | 256'h0, 559 | KEY_256_BITS, 560 | 64'h0, 561 | EIGHT_ROUNDS, 562 | 512'h3e00ef2f895f40d67f5bb8e81f09a5a12c840ec3ce9a7f3b181be188ef711a1e984ce172b9216f419f445367456d5619314a42a3da86b001387bfdb80e0cfe42); 563 | 564 | 565 | $display("TC1-5: All zero inputs. 256 bit key, 12 rounds."); 566 | run_test_case(TC1, FIVE, 567 | 256'h0, 568 | KEY_256_BITS, 569 | 64'h0, 570 | TWELWE_ROUNDS, 571 | 512'h9bf49a6a0755f953811fce125f2683d50429c3bb49e074147e0089a52eae155f0564f879d27ae3c02ce82834acfa8c793a629f2ca0de6919610be82f411326be); 572 | 573 | 574 | $display("TC1-6: All zero inputs. 256 bit key, 20 rounds."); 575 | run_test_case(TC1, SIX, 576 | 256'h0, 577 | KEY_256_BITS, 578 | 64'h0, 579 | TWENTY_ROUNDS, 580 | 512'h76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586); 581 | 582 | 583 | $display("TC2-1: One bit in key set, all zero IV. 128 bit key, 8 rounds."); 584 | run_test_case(TC2, ONE, 585 | 256'h0100000000000000000000000000000000000000000000000000000000000000, 586 | KEY_128_BITS, 587 | 64'h0, 588 | EIGHT_ROUNDS, 589 | 512'h03a7669888605a0765e8357475e58673f94fc8161da76c2a3aa2f3caf9fe5449e0fcf38eb882656af83d430d410927d55c972ac4c92ab9da3713e19f761eaa14); 590 | 591 | 592 | $display("TC2-2: One bit in key set, all zero IV. 256 bit key, 8 rounds."); 593 | run_test_case(TC2, ONE, 594 | 256'h0100000000000000000000000000000000000000000000000000000000000000, 595 | KEY_256_BITS, 596 | 64'h0, 597 | EIGHT_ROUNDS, 598 | 512'hcf5ee9a0494aa9613e05d5ed725b804b12f4a465ee635acc3a311de8740489ea289d04f43c7518db56eb4433e498a1238cd8464d3763ddbb9222ee3bd8fae3c8); 599 | 600 | 601 | $display("TC3-1: All zero key, one bit in IV set. 128 bit key, 8 rounds."); 602 | run_test_case(TC3, ONE, 603 | 256'h0, 604 | KEY_128_BITS, 605 | 64'h0100000000000000, 606 | EIGHT_ROUNDS, 607 | 512'h25f5bec6683916ff44bccd12d102e692176663f4cac53e719509ca74b6b2eec85da4236fb29902012adc8f0d86c8187d25cd1c486966930d0204c4ee88a6ab35); 608 | 609 | 610 | $display("TC4-1: All bits in key and IV are set. 128 bit key, 8 rounds."); 611 | run_test_case(TC4, ONE, 612 | 256'hffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, 613 | KEY_128_BITS, 614 | 64'hffffffffffffffff, 615 | EIGHT_ROUNDS, 616 | 512'h2204d5b81ce662193e00966034f91302f14a3fb047f58b6e6ef0d721132304163e0fb640d76ff9c3b9cd99996e6e38fad13f0e31c82244d33abbc1b11e8bf12d); 617 | 618 | 619 | $display("TC5-1: Even bits in key, IV are set. 128 bit key, 8 rounds."); 620 | run_test_case(TC5, ONE, 621 | 256'h5555555555555555555555555555555555555555555555555555555555555555, 622 | KEY_128_BITS, 623 | 64'h5555555555555555, 624 | EIGHT_ROUNDS, 625 | 512'hf0a23bc36270e18ed0691dc384374b9b2c5cb60110a03f56fa48a9fbbad961aa6bab4d892e96261b6f1a0919514ae56f86e066e17c71a4176ac684af1c931996); 626 | 627 | 628 | $display("TC6-1: Odd bits in key, IV are set. 128 bit key, 8 rounds."); 629 | run_test_case(TC6, ONE, 630 | 256'haaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, 631 | KEY_128_BITS, 632 | 64'haaaaaaaaaaaaaaaa, 633 | EIGHT_ROUNDS, 634 | 512'h312d95c0bc38eff4942db2d50bdc500a30641ef7132db1a8ae838b3bea3a7ab03815d7a4cc09dbf5882a3433d743aced48136ebab73299506855c0f5437a36c6); 635 | 636 | 637 | $display("TC7-1: Increasing, decreasing sequences in key and IV. 128 bit key, 8 rounds"); 638 | run_test_case(TC7, ONE, 639 | 256'h00112233445566778899aabbccddeeff00000000000000000000000000000000, 640 | KEY_128_BITS, 641 | 64'h0f1e2d3c4b596877, 642 | EIGHT_ROUNDS, 643 | 512'ha7a6c81bd8ac106e8f3a46a1bc8ec702e95d18c7e0f424519aeafb54471d83a2bf888861586b73d228eaaf82f9665a5a155e867f93731bfbe24fab495590b231); 644 | 645 | 646 | $display("TC7-2: Increasing, decreasing sequences in key and IV. 256 bit key, 8 rounds."); 647 | run_test_case(TC7, TWO, 648 | 256'h00112233445566778899aabbccddeeffffeeddccbbaa99887766554433221100, 649 | KEY_256_BITS, 650 | 64'h0f1e2d3c4b596877, 651 | EIGHT_ROUNDS, 652 | 512'h60fdedbd1a280cb741d0593b6ea0309010acf18e1471f68968f4c9e311dca149b8e027b47c81e0353db013891aa5f68ea3b13dd2f3b8dd0873bf3746e7d6c567); 653 | 654 | 655 | $display("TC8-128-8: Random inputs. 128 bit key, 8 rounds."); 656 | run_test_case(TC8, ONE, 657 | 256'hc46ec1b18ce8a878725a37e780dfb73500000000000000000000000000000000, 658 | KEY_128_BITS, 659 | 64'h1ada31d5cf688221, 660 | EIGHT_ROUNDS, 661 | 512'h6a870108859f679118f3e205e2a56a6826ef5a60a4102ac8d4770059fcb7c7bae02f5ce004a6bfbbea53014dd82107c0aa1c7ce11b7d78f2d50bd3602bbd2594); 662 | 663 | 664 | // Finish in style. 665 | $display("*** chacha_core simulation done ***"); 666 | display_test_result(); 667 | $finish; 668 | end // chacha_core_test 669 | 670 | endmodule // tb_chacha_core 671 | 672 | //====================================================================== 673 | // EOF tb_chacha_core.v 674 | //====================================================================== 675 | -------------------------------------------------------------------------------- /src/tb/tb_chacha.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // tb_chacha.v 4 | // ----------- 5 | // Testbench for the Chacha top level wrapper. 6 | // 7 | // 8 | // Copyright (c) 2013, Secworks Sweden AB 9 | // All rights reserved. 10 | // 11 | // Redistribution and use in source and binary forms, with or 12 | // without modification, are permitted provided that the following 13 | // conditions are met: 14 | // 15 | // 1. Redistributions of source code must retain the above copyright 16 | // notice, this list of conditions and the following disclaimer. 17 | // 18 | // 2. Redistributions in binary form must reproduce the above copyright 19 | // notice, this list of conditions and the following disclaimer in 20 | // the documentation and/or other materials provided with the 21 | // distribution. 22 | // 23 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 34 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | // 36 | //====================================================================== 37 | 38 | `default_nettype none 39 | 40 | module tb_chacha(); 41 | 42 | //---------------------------------------------------------------- 43 | // Internal constant and parameter definitions. 44 | //---------------------------------------------------------------- 45 | parameter DEBUG = 1; 46 | 47 | localparam CLK_HALF_PERIOD = 1; 48 | localparam CLK_PERIOD = 2 * CLK_HALF_PERIOD; 49 | 50 | localparam TC1 = 1; 51 | localparam TC2 = 2; 52 | localparam TC3 = 3; 53 | localparam TC4 = 4; 54 | localparam TC5 = 5; 55 | localparam TC6 = 6; 56 | localparam TC7 = 7; 57 | localparam TC8 = 8; 58 | localparam TC9 = 9; 59 | localparam TC10 = 10; 60 | 61 | localparam ONE = 1; 62 | localparam TWO = 2; 63 | localparam THREE = 3; 64 | localparam FOUR = 4; 65 | localparam FIVE = 5; 66 | localparam SIX = 6; 67 | localparam SEVEN = 7; 68 | localparam EIGHT = 8; 69 | 70 | localparam KEY_128_BITS = 0; 71 | localparam KEY_256_BITS = 1; 72 | 73 | localparam EIGHT_ROUNDS = 8; 74 | localparam TWELWE_ROUNDS = 12; 75 | localparam TWENTY_ROUNDS = 20; 76 | 77 | localparam DISABLE = 0; 78 | localparam ENABLE = 1; 79 | 80 | // API for the dut. 81 | localparam ADDR_NAME0 = 8'h00; 82 | localparam ADDR_NAME1 = 8'h01; 83 | localparam ADDR_VERSION = 8'h02; 84 | 85 | localparam ADDR_CTRL = 8'h08; 86 | localparam CTRL_INIT_BIT = 0; 87 | localparam CTRL_NEXT_BIT = 1; 88 | 89 | localparam ADDR_STATUS = 8'h09; 90 | localparam STATUS_READY_BIT = 0; 91 | 92 | localparam ADDR_KEYLEN = 8'h0a; 93 | localparam KEYLEN_BIT = 0; 94 | localparam ADDR_ROUNDS = 8'h0b; 95 | localparam ROUNDS_HIGH_BIT = 4; 96 | localparam ROUNDS_LOW_BIT = 0; 97 | 98 | localparam ADDR_KEY0 = 8'h10; 99 | localparam ADDR_KEY1 = 8'h11; 100 | localparam ADDR_KEY2 = 8'h12; 101 | localparam ADDR_KEY3 = 8'h13; 102 | localparam ADDR_KEY4 = 8'h14; 103 | localparam ADDR_KEY5 = 8'h15; 104 | localparam ADDR_KEY6 = 8'h16; 105 | localparam ADDR_KEY7 = 8'h17; 106 | 107 | localparam ADDR_IV0 = 8'h20; 108 | localparam ADDR_IV1 = 8'h21; 109 | 110 | localparam ADDR_DATA_IN0 = 8'h40; 111 | localparam ADDR_DATA_IN15 = 8'h4f; 112 | 113 | localparam ADDR_DATA_OUT0 = 8'h80; 114 | localparam ADDR_DATA_OUT1 = 8'h81; 115 | localparam ADDR_DATA_OUT2 = 8'h82; 116 | localparam ADDR_DATA_OUT3 = 8'h83; 117 | localparam ADDR_DATA_OUT4 = 8'h84; 118 | localparam ADDR_DATA_OUT5 = 8'h85; 119 | localparam ADDR_DATA_OUT6 = 8'h86; 120 | localparam ADDR_DATA_OUT7 = 8'h87; 121 | localparam ADDR_DATA_OUT8 = 8'h88; 122 | localparam ADDR_DATA_OUT9 = 8'h89; 123 | localparam ADDR_DATA_OUT10 = 8'h8a; 124 | localparam ADDR_DATA_OUT11 = 8'h8b; 125 | localparam ADDR_DATA_OUT12 = 8'h8c; 126 | localparam ADDR_DATA_OUT13 = 8'h8d; 127 | localparam ADDR_DATA_OUT14 = 8'h8e; 128 | localparam ADDR_DATA_OUT15 = 8'h8f; 129 | 130 | 131 | //---------------------------------------------------------------- 132 | // Register and Wire declarations. 133 | //---------------------------------------------------------------- 134 | reg tb_clk; 135 | reg tb_reset_n; 136 | 137 | reg tb_cs; 138 | reg tb_write_read; 139 | 140 | reg [7 : 0] tb_address; 141 | reg [31 : 0] tb_data_in; 142 | wire [31 : 0] tb_data_out; 143 | wire tb_error; 144 | 145 | reg [63 : 0] cycle_ctr; 146 | reg [31 : 0] error_ctr; 147 | reg [31 : 0] tc_ctr; 148 | 149 | reg [31 : 0] read_data; 150 | 151 | reg [511 : 0] extracted_data; 152 | 153 | reg display_cycle_ctr; 154 | reg display_read_write; 155 | reg display_core_state; 156 | 157 | 158 | //---------------------------------------------------------------- 159 | // Chacha device under test. 160 | //---------------------------------------------------------------- 161 | chacha dut( 162 | .clk(tb_clk), 163 | .reset_n(tb_reset_n), 164 | .cs(tb_cs), 165 | .we(tb_write_read), 166 | .addr(tb_address), 167 | .write_data(tb_data_in), 168 | .read_data(tb_data_out) 169 | ); 170 | 171 | 172 | //---------------------------------------------------------------- 173 | // clk_gen 174 | // 175 | // Clock generator process. 176 | //---------------------------------------------------------------- 177 | always 178 | begin : clk_gen 179 | #CLK_HALF_PERIOD tb_clk = !tb_clk; 180 | end // clk_gen 181 | 182 | 183 | //-------------------------------------------------------------------- 184 | // dut_monitor 185 | // 186 | // Monitor displaying information every cycle. 187 | // Includes the cycle counter. 188 | //-------------------------------------------------------------------- 189 | always @ (posedge tb_clk) 190 | begin : dut_monitor 191 | cycle_ctr = cycle_ctr + 1; 192 | 193 | if (display_cycle_ctr) 194 | begin 195 | $display("cycle = %016x:", cycle_ctr); 196 | end 197 | 198 | if (display_core_state) 199 | begin 200 | $display("core ctrl: 0x%02x, core_qr_ctr: 0x%02x, core_dr_ctr: 0x%02x, init: 0x%01x, next: 0x%01x, core_ready: 0x%02x", 201 | dut.core.chacha_ctrl_reg, dut.core.qr_ctr_reg, 202 | dut.core.dr_ctr_reg, dut.core.init, 203 | dut.core.next, dut.core.ready_reg); 204 | 205 | $display("state0_reg = 0x%08x, state1_reg = 0x%08x, state2_reg = 0x%08x, state3_reg = 0x%08x", 206 | dut.core.state_reg[00], dut.core.state_reg[01], dut.core.state_reg[02], dut.core.state_reg[03]); 207 | $display("state4_reg = 0x%08x, state5_reg = 0x%08x, state6_reg = 0x%08x, state7_reg = 0x%08x", 208 | dut.core.state_reg[04], dut.core.state_reg[05], dut.core.state_reg[06], dut.core.state_reg[07]); 209 | $display("state8_reg = 0x%08x, state9_reg = 0x%08x, state10_reg = 0x%08x, state11_reg = 0x%08x", 210 | dut.core.state_reg[08], dut.core.state_reg[09], dut.core.state_reg[10], dut.core.state_reg[11]); 211 | $display("state12_reg = 0x%08x, state13_reg = 0x%08x, state14_reg = 0x%08x, state15_reg = 0x%08x", 212 | dut.core.state_reg[12], dut.core.state_reg[13], dut.core.state_reg[14], dut.core.state_reg[15]); 213 | $display(""); 214 | end 215 | 216 | if (display_read_write) 217 | begin 218 | 219 | if (dut.cs) 220 | begin 221 | if (dut.we) 222 | begin 223 | $display("*** Write acess: addr 0x%02x = 0x%08x", dut.addr, dut.write_data); 224 | end 225 | else 226 | begin 227 | $display("*** Read acess: addr 0x%02x = 0x%08x", dut.addr, dut.read_data); 228 | end 229 | end 230 | end 231 | 232 | end // dut_monitor 233 | 234 | 235 | //---------------------------------------------------------------- 236 | // reset_dut 237 | //---------------------------------------------------------------- 238 | task reset_dut; 239 | begin 240 | tb_reset_n = 0; 241 | #(2 * CLK_PERIOD); 242 | tb_reset_n = 1; 243 | end 244 | endtask // reset_dut 245 | 246 | 247 | //---------------------------------------------------------------- 248 | // init_sim() 249 | // 250 | // Set the input to the DUT to defined values. 251 | //---------------------------------------------------------------- 252 | task init_sim; 253 | begin 254 | cycle_ctr = 0; 255 | error_ctr = 0; 256 | tc_ctr = 0; 257 | tb_clk = 0; 258 | tb_reset_n = 0; 259 | tb_cs = 0; 260 | tb_write_read = 0; 261 | tb_address = 8'h0; 262 | tb_data_in = 32'h0; 263 | 264 | display_cycle_ctr = 0; 265 | display_read_write = 0; 266 | display_core_state = 0; 267 | end 268 | endtask // init_sim 269 | 270 | 271 | //---------------------------------------------------------------- 272 | // read_reg 273 | // 274 | // Task that reads and display the value of 275 | // a register in the dut. 276 | //---------------------------------------------------------------- 277 | task read_reg(input [7 : 0] addr); 278 | begin 279 | tb_cs = 1; 280 | tb_write_read = 0; 281 | tb_address = addr; 282 | #(CLK_PERIOD); 283 | tb_cs = 0; 284 | tb_write_read = 0; 285 | tb_address = 8'h0; 286 | tb_data_in = 32'h0; 287 | end 288 | endtask // read_reg 289 | 290 | 291 | //---------------------------------------------------------------- 292 | // write_reg 293 | // 294 | // Task that writes to a register in the dut. 295 | //---------------------------------------------------------------- 296 | task write_reg(input [7 : 0] addr, input [31 : 0] data); 297 | begin 298 | tb_cs = 1; 299 | tb_write_read = 1; 300 | tb_address = addr; 301 | tb_data_in = data; 302 | #(CLK_PERIOD); 303 | tb_cs = 0; 304 | tb_write_read = 0; 305 | tb_address = 8'h0; 306 | tb_data_in = 32'h0; 307 | end 308 | endtask // write_reg 309 | 310 | 311 | //---------------------------------------------------------------- 312 | // dump_top_state 313 | // 314 | // Dump the internal state of the top to std out. 315 | //---------------------------------------------------------------- 316 | task dump_top_state; 317 | begin 318 | $display(""); 319 | $display("Top internal state"); 320 | $display("------------------"); 321 | $display("init_reg = %01x", dut.init_reg); 322 | $display("next_reg = %01x", dut.next_reg); 323 | $display("keylen_reg = %01x", dut.keylen_reg); 324 | $display("rounds_reg = %01x", dut.rounds_reg); 325 | $display(""); 326 | 327 | $display("key0_reg = %08x, key1_reg = %08x, key2_reg = %08x, key3_reg = %08x", 328 | dut.key_reg[0], dut.key_reg[1], dut.key_reg[2], dut.key_reg[3]); 329 | $display("key4_reg = %08x, key5_reg = %08x, key6_reg = %08x, key7_reg = %08x", 330 | dut.key_reg[4], dut.key_reg[5], dut.key_reg[6], dut.key_reg[7]); 331 | $display(""); 332 | 333 | $display("iv0_reg = %08x, iv1_reg = %08x", dut.iv_reg[0], dut.iv_reg[1]); 334 | $display(""); 335 | 336 | $display("data_in0_reg = %08x, data_in1_reg = %08x, data_in2_reg = %08x, data_in3_reg = %08x", 337 | dut.data_in_reg[00], dut.data_in_reg[01], dut.data_in_reg[02], dut.data_in_reg[03]); 338 | $display("data_in4_reg = %08x, data_in5_reg = %08x, data_in6_reg = %08x, data_in7_reg = %08x", 339 | dut.data_in_reg[04], dut.data_in_reg[05], dut.data_in_reg[06], dut.data_in_reg[07]); 340 | $display("data_in8_reg = %08x, data_in9_reg = %08x, data_in10_reg = %08x, data_in11_reg = %08x", 341 | dut.data_in_reg[08], dut.data_in_reg[09], dut.data_in_reg[10], dut.data_in_reg[11]); 342 | $display("data_in12_reg = %08x, data_in13_reg = %08x, data_in14_reg = %08x, data_in15_reg = %08x", 343 | dut.data_in_reg[12], dut.data_in_reg[13], dut.data_in_reg[14], dut.data_in_reg[15]); 344 | $display(""); 345 | 346 | $display("ready = 0x%01x, data_out_valid = %01x", dut.core_ready, dut.core_data_out_valid); 347 | $display("data_out00 = %08x, data_out01 = %08x, data_out02 = %08x, data_out03 = %08x", 348 | dut.core_data_out[511 : 480], dut.core_data_out[479 : 448], 349 | dut.core_data_out[447 : 416], dut.core_data_out[415 : 384]); 350 | $display("data_out04 = %08x, data_out05 = %08x, data_out06 = %08x, data_out07 = %08x", 351 | dut.core_data_out[383 : 352], dut.core_data_out[351 : 320], 352 | dut.core_data_out[319 : 288], dut.core_data_out[287 : 256]); 353 | $display("data_out08 = %08x, data_out09 = %08x, data_out10 = %08x, data_out11 = %08x", 354 | dut.core_data_out[255 : 224], dut.core_data_out[223 : 192], 355 | dut.core_data_out[191 : 160], dut.core_data_out[159 : 128]); 356 | $display("data_out12 = %08x, data_out13 = %08x, data_out14 = %08x, data_out15 = %08x", 357 | dut.core_data_out[127 : 96], dut.core_data_out[95 : 64], 358 | dut.core_data_out[63 : 32], dut.core_data_out[31 : 0]); 359 | $display(""); 360 | end 361 | endtask // dump_top_state 362 | 363 | 364 | //---------------------------------------------------------------- 365 | // dump_core_state 366 | // 367 | // Dump the internal state of the core to std out. 368 | //---------------------------------------------------------------- 369 | task dump_core_state; 370 | begin 371 | $display(""); 372 | $display("Core internal state"); 373 | $display("-------------------"); 374 | $display("Round state:"); 375 | $display("state0_reg = 0x%08x, state1_reg = 0x%08x, state2_reg = 0x%08x, state3_reg = 0x%08x", 376 | dut.core.state_reg[00], dut.core.state_reg[01], dut.core.state_reg[02], dut.core.state_reg[03]); 377 | $display("state4_reg = 0x%08x, state5_reg = 0x%08x, state6_reg = 0x%08x, state7_reg = 0x%08x", 378 | dut.core.state_reg[04], dut.core.state_reg[05], dut.core.state_reg[06], dut.core.state_reg[07]); 379 | $display("state8_reg = 0x%08x, state9_reg = 0x%08x, state10_reg = 0x%08x, state11_reg = 0x%08x", 380 | dut.core.state_reg[08], dut.core.state_reg[09], dut.core.state_reg[10], dut.core.state_reg[11]); 381 | $display("state12_reg = 0x%08x, state13_reg = 0x%08x, state14_reg = 0x%08x, state15_reg = 0x%08x", 382 | dut.core.state_reg[12], dut.core.state_reg[13], dut.core.state_reg[14], dut.core.state_reg[15]); 383 | $display(""); 384 | 385 | $display("rounds = %01x", dut.core.rounds); 386 | $display("qr_ctr_reg = %01x, dr_ctr_reg = %01x", dut.core.qr_ctr_reg, dut.core.dr_ctr_reg); 387 | $display("block0_ctr_reg = %08x, block1_ctr_reg = %08x", dut.core.block0_ctr_reg, dut.core.block1_ctr_reg); 388 | 389 | $display(""); 390 | 391 | $display("chacha_ctrl_reg = %02x", dut.core.chacha_ctrl_reg); 392 | $display(""); 393 | 394 | $display("data_in = %064x", dut.core.data_in); 395 | $display("data_out_valid_reg = %01x", dut.core.data_out_valid_reg); 396 | $display(""); 397 | 398 | $display("qr0_a_prim = %08x, qr0_b_prim = %08x", dut.core.qr0_a_prim, dut.core.qr0_b_prim); 399 | $display("qr0_c_prim = %08x, qr0_d_prim = %08x", dut.core.qr0_c_prim, dut.core.qr0_d_prim); 400 | $display(""); 401 | end 402 | endtask // dump_core_state 403 | 404 | 405 | //---------------------------------------------------------------- 406 | // display_test_result() 407 | // 408 | // Display the accumulated test results. 409 | //---------------------------------------------------------------- 410 | task display_test_result; 411 | begin 412 | if (error_ctr == 0) 413 | begin 414 | $display("*** All %02d test cases completed successfully", tc_ctr); 415 | end 416 | else 417 | begin 418 | $display("*** %02d test cases did not complete successfully.", error_ctr); 419 | end 420 | end 421 | endtask // display_test_result 422 | 423 | 424 | //---------------------------------------------------------------- 425 | // read_write_test() 426 | // 427 | // Simple test case that tries to read and write to the 428 | // registers in the dut. 429 | // 430 | // Note: Currently not self testing. No expected values. 431 | //---------------------------------------------------------------- 432 | task read_write_test; 433 | begin 434 | tc_ctr = tc_ctr + 1; 435 | 436 | write_reg(ADDR_KEY0, 32'h55555555); 437 | read_reg(ADDR_KEY0); 438 | write_reg(ADDR_KEY1, 32'haaaaaaaa); 439 | read_reg(ADDR_KEY1); 440 | read_reg(ADDR_CTRL); 441 | read_reg(ADDR_STATUS); 442 | read_reg(ADDR_KEYLEN); 443 | read_reg(ADDR_ROUNDS); 444 | 445 | read_reg(ADDR_KEY0); 446 | read_reg(ADDR_KEY1); 447 | read_reg(ADDR_KEY2); 448 | read_reg(ADDR_KEY3); 449 | read_reg(ADDR_KEY4); 450 | read_reg(ADDR_KEY5); 451 | read_reg(ADDR_KEY6); 452 | read_reg(ADDR_KEY7); 453 | end 454 | endtask // read_write_test 455 | 456 | 457 | //---------------------------------------------------------------- 458 | // write_localparams() 459 | // 460 | // Write key, iv and other parameters to the dut. 461 | //---------------------------------------------------------------- 462 | task write_parameters(input [256 : 0] key, 463 | input key_length, 464 | input [64 : 0] iv, 465 | input [4 : 0] rounds); 466 | begin 467 | write_reg(ADDR_KEY0, key[255 : 224]); 468 | write_reg(ADDR_KEY1, key[223 : 192]); 469 | write_reg(ADDR_KEY2, key[191 : 160]); 470 | write_reg(ADDR_KEY3, key[159 : 128]); 471 | write_reg(ADDR_KEY4, key[127 : 96]); 472 | write_reg(ADDR_KEY5, key[95 : 64]); 473 | write_reg(ADDR_KEY6, key[63 : 32]); 474 | write_reg(ADDR_KEY7, key[31 : 0]); 475 | write_reg(ADDR_IV0, iv[63 : 32]); 476 | write_reg(ADDR_IV1, iv[31 : 0]); 477 | write_reg(ADDR_KEYLEN, {{31'h0}, key_length}); 478 | write_reg(ADDR_ROUNDS, {{27'h0}, rounds}); 479 | end 480 | endtask // write_parameters 481 | 482 | 483 | //---------------------------------------------------------------- 484 | // start_init_block() 485 | // 486 | // Toggle the init signal in the dut to make it start processing 487 | // the first block available in the data in registers. 488 | // 489 | // Note: It is the callers responsibility to call the function 490 | // when the dut is ready to react on the init signal. 491 | //---------------------------------------------------------------- 492 | task start_init_block; 493 | begin 494 | write_reg(ADDR_CTRL, 32'h00000001); 495 | #(2 * CLK_PERIOD); 496 | write_reg(ADDR_CTRL, 32'h00000000); 497 | end 498 | endtask // start_init_block 499 | 500 | 501 | //---------------------------------------------------------------- 502 | // start_next_block() 503 | // 504 | // Toggle the next signal in the dut to make it start processing 505 | // the next block available in the data in registers. 506 | // 507 | // Note: It is the callers responsibility to call the function 508 | // when the dut is ready to react on the next signal. 509 | //---------------------------------------------------------------- 510 | task start_next_block; 511 | begin 512 | write_reg(ADDR_CTRL, 32'h00000002); 513 | #(2 * CLK_PERIOD); 514 | write_reg(ADDR_CTRL, 32'h00000000); 515 | 516 | if (DEBUG) 517 | begin 518 | $display("Debug of next state."); 519 | dump_core_state(); 520 | #(2 * CLK_PERIOD); 521 | dump_core_state(); 522 | end 523 | end 524 | endtask // start_next_block 525 | 526 | 527 | //---------------------------------------------------------------- 528 | // wait_ready() 529 | // 530 | // Wait for the ready flag in the dut to be set. 531 | // 532 | // Note: It is the callers responsibility to call the function 533 | // when the dut is actively processing and will in fact at some 534 | // point set the flag. 535 | //---------------------------------------------------------------- 536 | task wait_ready; 537 | begin 538 | while (!tb_data_out[STATUS_READY_BIT]) 539 | begin 540 | read_reg(ADDR_STATUS); 541 | end 542 | end 543 | endtask // wait_ready 544 | 545 | 546 | //---------------------------------------------------------------- 547 | // extract_data() 548 | // 549 | // Extracts all 16 data out words and combine them into the 550 | // global extracted_data. 551 | //---------------------------------------------------------------- 552 | task extract_data; 553 | begin 554 | read_reg(ADDR_DATA_OUT0); 555 | extracted_data[511 : 480] = tb_data_out; 556 | read_reg(ADDR_DATA_OUT1); 557 | extracted_data[479 : 448] = tb_data_out; 558 | read_reg(ADDR_DATA_OUT2); 559 | extracted_data[447 : 416] = tb_data_out; 560 | read_reg(ADDR_DATA_OUT3); 561 | extracted_data[415 : 384] = tb_data_out; 562 | read_reg(ADDR_DATA_OUT4); 563 | extracted_data[383 : 352] = tb_data_out; 564 | read_reg(ADDR_DATA_OUT5); 565 | extracted_data[351 : 320] = tb_data_out; 566 | read_reg(ADDR_DATA_OUT6); 567 | extracted_data[319 : 288] = tb_data_out; 568 | read_reg(ADDR_DATA_OUT7); 569 | extracted_data[287 : 256] = tb_data_out; 570 | read_reg(ADDR_DATA_OUT8); 571 | extracted_data[255 : 224] = tb_data_out; 572 | read_reg(ADDR_DATA_OUT9); 573 | extracted_data[223 : 192] = tb_data_out; 574 | read_reg(ADDR_DATA_OUT10); 575 | extracted_data[191 : 160] = tb_data_out; 576 | read_reg(ADDR_DATA_OUT11); 577 | extracted_data[159 : 128] = tb_data_out; 578 | read_reg(ADDR_DATA_OUT12); 579 | extracted_data[127 : 96] = tb_data_out; 580 | read_reg(ADDR_DATA_OUT13); 581 | extracted_data[95 : 64] = tb_data_out; 582 | read_reg(ADDR_DATA_OUT14); 583 | extracted_data[63 : 32] = tb_data_out; 584 | read_reg(ADDR_DATA_OUT15); 585 | extracted_data[31 : 0] = tb_data_out; 586 | end 587 | endtask // extract_data 588 | 589 | 590 | //---------------------------------------------------------------- 591 | // check_name_version() 592 | // 593 | // Read the name and version from the DUT. 594 | //---------------------------------------------------------------- 595 | task check_name_version; 596 | reg [31 : 0] name0; 597 | reg [31 : 0] name1; 598 | reg [31 : 0] version; 599 | begin 600 | $display("*** Trying to read name and version from core."); 601 | read_reg(ADDR_NAME0); 602 | name0 = tb_data_out; 603 | read_reg(ADDR_NAME1); 604 | name1 = tb_data_out; 605 | read_reg(ADDR_VERSION); 606 | version = tb_data_out; 607 | 608 | $display("DUT name: %c%c%c%c%c%c%c%c", 609 | name0[31 : 24], name0[23 : 16], name0[15 : 8], name0[7 : 0], 610 | name1[31 : 24], name1[23 : 16], name1[15 : 8], name1[7 : 0]); 611 | $display("DUT version: %c%c%c%c", 612 | version[31 : 24], version[23 : 16], version[15 : 8], version[7 : 0]); 613 | $display(""); 614 | end 615 | endtask // check_name_version 616 | 617 | 618 | //---------------------------------------------------------------- 619 | // run_two_blocks_test_vector() 620 | // 621 | // Runs a test case with two blocks based on the given 622 | // test vector. Only the final block is compared. 623 | //---------------------------------------------------------------- 624 | task run_two_blocks_test_vector(input [7 : 0] major, 625 | input [7 : 0] minor, 626 | input [256 : 0] key, 627 | input key_length, 628 | input [64 : 0] iv, 629 | input [4 : 0] rounds, 630 | input [511 : 0] expected); 631 | begin 632 | tc_ctr = tc_ctr + 1; 633 | 634 | $display("***TC%2d-%2d started", major, minor); 635 | $display("***-----------------"); 636 | write_parameters(key, key_length, iv, rounds); 637 | start_init_block(); 638 | wait_ready(); 639 | extract_data(); 640 | 641 | if (DEBUG) 642 | begin 643 | $display("State after first block:"); 644 | dump_core_state(); 645 | 646 | $display("First block:"); 647 | $display("0x%064x", extracted_data); 648 | end 649 | 650 | start_next_block(); 651 | 652 | if (DEBUG) 653 | begin 654 | $display("State after init of second block:"); 655 | dump_core_state(); 656 | end 657 | 658 | wait_ready(); 659 | extract_data(); 660 | 661 | if (DEBUG) 662 | begin 663 | $display("State after init of second block:"); 664 | dump_core_state(); 665 | 666 | $display("Second block:"); 667 | $display("0x%064x", extracted_data); 668 | end 669 | 670 | if (extracted_data != expected) 671 | begin 672 | error_ctr = error_ctr + 1; 673 | $display("***TC%2d-%2d - ERROR", major, minor); 674 | $display("***-----------------"); 675 | $display("Expected:"); 676 | $display("0x%064x", expected); 677 | $display("Got:"); 678 | $display("0x%064x", extracted_data); 679 | end 680 | else 681 | begin 682 | $display("***TC%2d-%2d - SUCCESS", major, minor); 683 | $display("***-------------------"); 684 | end 685 | $display(""); 686 | end 687 | endtask // run_two_blocks_test_vector 688 | 689 | 690 | //---------------------------------------------------------------- 691 | // run_test_vector() 692 | // 693 | // Runs a test case based on the given test vector. 694 | //---------------------------------------------------------------- 695 | task run_test_vector(input [7 : 0] major, 696 | input [7 : 0] minor, 697 | input [256 : 0] key, 698 | input key_length, 699 | input [64 : 0] iv, 700 | input [4 : 0] rounds, 701 | input [511 : 0] expected); 702 | begin 703 | tc_ctr = tc_ctr + 1; 704 | 705 | $display("***TC%2d-%2d started", major, minor); 706 | $display("***-----------------"); 707 | write_parameters(key, key_length, iv, rounds); 708 | 709 | start_init_block(); 710 | $display("*** Started."); 711 | wait_ready(); 712 | $display("*** Ready seen."); 713 | dump_top_state(); 714 | extract_data(); 715 | 716 | if (extracted_data != expected) 717 | begin 718 | error_ctr = error_ctr + 1; 719 | $display("***TC%2d-%2d - ERROR", major, minor); 720 | $display("***-----------------"); 721 | $display("Expected:"); 722 | $display("0x%064x", expected); 723 | $display("Got:"); 724 | $display("0x%064x", extracted_data); 725 | end 726 | else 727 | begin 728 | $display("***TC%2d-%2d - SUCCESS", major, minor); 729 | $display("***-------------------"); 730 | end 731 | $display(""); 732 | end 733 | endtask // run_test_vector 734 | 735 | 736 | //---------------------------------------------------------------- 737 | // chacha_test 738 | // The main test functionality. 739 | //---------------------------------------------------------------- 740 | initial 741 | begin : chacha_test 742 | $display(" -- Testbench for chacha started --"); 743 | init_sim(); 744 | reset_dut(); 745 | 746 | $display("State at init after reset:"); 747 | dump_top_state(); 748 | 749 | // Check name and version. 750 | check_name_version(); 751 | 752 | $display("TC1-1: All zero inputs. 128 bit key, 8 rounds."); 753 | run_test_vector(TC1, ONE, 754 | 256'h0, 755 | KEY_128_BITS, 756 | 64'h0, 757 | EIGHT_ROUNDS, 758 | 512'he28a5fa4a67f8c5defed3e6fb7303486aa8427d31419a729572d777953491120b64ab8e72b8deb85cd6aea7cb6089a101824beeb08814a428aab1fa2c816081b); 759 | 760 | $display("TC7-2: Increasing, decreasing sequences in key and IV. 256 bit key, 8 rounds."); 761 | run_test_vector(TC7, TWO, 762 | 256'h00112233445566778899aabbccddeeffffeeddccbbaa99887766554433221100, 763 | KEY_256_BITS, 764 | 64'h0f1e2d3c4b596877, 765 | EIGHT_ROUNDS, 766 | 512'h60fdedbd1a280cb741d0593b6ea0309010acf18e1471f68968f4c9e311dca149b8e027b47c81e0353db013891aa5f68ea3b13dd2f3b8dd0873bf3746e7d6c567); 767 | 768 | 769 | $display("TC7-3: Increasing, decreasing sequences in key and IV. 256 bit key, 8 rounds."); 770 | $display("TC7-3: Testing correct second block."); 771 | run_two_blocks_test_vector(TC7, THREE, 772 | 256'h00112233445566778899aabbccddeeffffeeddccbbaa99887766554433221100, 773 | KEY_256_BITS, 774 | 64'h0f1e2d3c4b596877, 775 | EIGHT_ROUNDS, 776 | 512'hfe882395601ce8aded444867fe62ed8741420002e5d28bb573113a418c1f4008e954c188f38ec4f26bb8555e2b7c92bf4380e2ea9e553187fdd42821794416de); 777 | 778 | 779 | display_test_result(); 780 | $display("*** chacha simulation done."); 781 | $finish; 782 | end // chacha_test 783 | endmodule // tb_chacha 784 | 785 | //====================================================================== 786 | // EOF tb_chacha.v 787 | //====================================================================== 788 | -------------------------------------------------------------------------------- /src/model/python/chacha.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #======================================================================= 4 | # 5 | # chacha.py 6 | # --------- 7 | # Simple model of the ChaCha stream cipher. Used as a reference for 8 | # the HW implementation. The code follows the structure of the 9 | # HW implementation as much as possible. 10 | # 11 | # 12 | # Copyright (c) 2013 Secworks Sweden AB 13 | # Author: Joachim Strömbergson 14 | # 15 | # Redistribution and use in source and binary forms, with or 16 | # without modification, are permitted provided that the following 17 | # conditions are met: 18 | # 19 | # 1. Redistributions of source code must retain the above copyright 20 | # notice, this list of conditions and the following disclaimer. 21 | # 22 | # 2. Redistributions in binary form must reproduce the above copyright 23 | # notice, this list of conditions and the following disclaimer in 24 | # the documentation and/or other materials provided with the 25 | # distribution. 26 | # 27 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 28 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 29 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 30 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 31 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 32 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 33 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 34 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 35 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 36 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 38 | # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | # 40 | #======================================================================= 41 | 42 | #------------------------------------------------------------------- 43 | # Python module imports. 44 | #------------------------------------------------------------------- 45 | import sys 46 | 47 | 48 | #------------------------------------------------------------------- 49 | # Constants. 50 | #------------------------------------------------------------------- 51 | TAU = [0x61707865, 0x3120646e, 0x79622d36, 0x6b206574] 52 | SIGMA = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574] 53 | 54 | 55 | #------------------------------------------------------------------- 56 | # ChaCha() 57 | #------------------------------------------------------------------- 58 | class ChaCha(): 59 | 60 | #--------------------------------------------------------------- 61 | # __init__() 62 | # 63 | # Given the key, iv initializes the state of the cipher. 64 | # The number of rounds used can be set. By default 8 rounds 65 | # are used. Accepts a list of either 16 or 32 bytes as key. 66 | # Accepts a list of 8 bytes as IV. 67 | #--------------------------------------------------------------- 68 | def __init__(self, key, iv, rounds = 8, verbose = 0): 69 | self.state = [0] * 16 70 | self.x = [0] * 16 71 | self.rounds = rounds 72 | self.verbose = verbose 73 | self.set_key_iv(key, iv) 74 | 75 | 76 | #--------------------------------------------------------------- 77 | # set_key_iv() 78 | # 79 | # Set key and iv. Basically reinitialize the cipher. 80 | # This also resets the block counter. 81 | #--------------------------------------------------------------- 82 | def set_key_iv(self, key, iv): 83 | keyword0 = self._b2w(key[0:4]) 84 | keyword1 = self._b2w(key[4:8]) 85 | keyword2 = self._b2w(key[8:12]) 86 | keyword3 = self._b2w(key[12:16]) 87 | 88 | if len(key) == 16: 89 | self.state[0] = TAU[0] 90 | self.state[1] = TAU[1] 91 | self.state[2] = TAU[2] 92 | self.state[3] = TAU[3] 93 | self.state[4] = keyword0 94 | self.state[5] = keyword1 95 | self.state[6] = keyword2 96 | self.state[7] = keyword3 97 | self.state[8] = keyword0 98 | self.state[9] = keyword1 99 | self.state[10] = keyword2 100 | self.state[11] = keyword3 101 | 102 | elif len(key) == 32: 103 | keyword4 = self._b2w(key[16:20]) 104 | keyword5 = self._b2w(key[20:24]) 105 | keyword6 = self._b2w(key[24:28]) 106 | keyword7 = self._b2w(key[28:32]) 107 | self.state[0] = SIGMA[0] 108 | self.state[1] = SIGMA[1] 109 | self.state[2] = SIGMA[2] 110 | self.state[3] = SIGMA[3] 111 | self.state[4] = keyword0 112 | self.state[5] = keyword1 113 | self.state[6] = keyword2 114 | self.state[7] = keyword3 115 | self.state[8] = keyword4 116 | self.state[9] = keyword5 117 | self.state[10] = keyword6 118 | self.state[11] = keyword7 119 | else: 120 | print("Key length of %d bits, is not supported." % (len(key) * 8)) 121 | 122 | # Common state init for both key lengths. 123 | self.block_counter = [0, 0] 124 | self.state[12] = self.block_counter[0] 125 | self.state[13] = self.block_counter[1] 126 | self.state[14] = self._b2w(iv[0:4]) 127 | self.state[15] = self._b2w(iv[4:8]) 128 | 129 | if self.verbose: 130 | print("State after init:") 131 | self._print_state() 132 | 133 | 134 | #--------------------------------------------------------------- 135 | # next() 136 | # 137 | # Encyp/decrypt the next block. This also updates the 138 | # internal state and increases the block counter. 139 | #--------------------------------------------------------------- 140 | def next(self, data_in): 141 | # Copy the current internal state to the temporary state x. 142 | self.x = self.state[:] 143 | 144 | if self.verbose: 145 | print("State before round processing.") 146 | self._print_state() 147 | 148 | if self.verbose: 149 | print("X before round processing:") 150 | self._print_x() 151 | 152 | # Update the internal state by performing 153 | # (rounds / 2) double rounds. 154 | for i in range(int(self.rounds / 2)): 155 | if (self.verbose > 1): 156 | print("Doubleround 0x%02x:" % i) 157 | self._doubleround() 158 | if (self.verbose > 1): 159 | print("") 160 | 161 | if self.verbose: 162 | print("X after round processing:") 163 | self._print_x() 164 | 165 | # Update the internal state by adding the elements 166 | # of the temporary state to the internal state. 167 | self.state = [((self.state[i] + self.x[i]) & 0xffffffff) for i in range(16)] 168 | 169 | if self.verbose: 170 | print("State after round processing.") 171 | self._print_state() 172 | 173 | bytestate = [] 174 | for i in self.state: 175 | bytestate += self._w2b(i) 176 | 177 | # Create the data out words. 178 | data_out = [data_in[i] ^ bytestate[i] for i in range(64)] 179 | 180 | # Update the block counter. 181 | self._inc_counter() 182 | 183 | return data_out 184 | 185 | 186 | #--------------------------------------------------------------- 187 | # _doubleround() 188 | # 189 | # Perform the two complete rounds that comprises the 190 | # double round. 191 | #--------------------------------------------------------------- 192 | def _doubleround(self): 193 | if (self.verbose > 0): 194 | print("Start of double round processing.") 195 | 196 | self._quarterround(0, 4, 8, 12) 197 | if (self.verbose > 1): 198 | print("X after QR 0") 199 | self._print_x() 200 | self._quarterround(1, 5, 9, 13) 201 | if (self.verbose > 1): 202 | print("X after QR 1") 203 | self._print_x() 204 | self._quarterround(2, 6, 10, 14) 205 | if (self.verbose > 1): 206 | print("X after QR 2") 207 | self._print_x() 208 | self._quarterround(3, 7, 11, 15) 209 | if (self.verbose > 1): 210 | print("X after QR 3") 211 | self._print_x() 212 | 213 | self._quarterround(0, 5, 10, 15) 214 | if (self.verbose > 1): 215 | print("X after QR 4") 216 | self._print_x() 217 | self._quarterround(1, 6, 11, 12) 218 | if (self.verbose > 1): 219 | print("X after QR 5") 220 | self._print_x() 221 | self._quarterround(2, 7, 8, 13) 222 | if (self.verbose > 1): 223 | print("X after QR 6") 224 | self._print_x() 225 | self._quarterround(3, 4, 9, 14) 226 | if (self.verbose > 1): 227 | print("X after QR 7") 228 | self._print_x() 229 | 230 | if (self.verbose > 0): 231 | print("End of double round processing.") 232 | 233 | 234 | #--------------------------------------------------------------- 235 | # _quarterround() 236 | # 237 | # Updates four elements in the state vector x given by 238 | # their indices. 239 | #--------------------------------------------------------------- 240 | def _quarterround(self, ai, bi, ci, di): 241 | # Extract four elemenst from x using the qi tuple. 242 | a, b, c, d = self.x[ai], self.x[bi], self.x[ci], self.x[di] 243 | 244 | if (self.verbose > 1): 245 | print("Indata to quarterround:") 246 | print("X state indices:", ai, bi, ci, di) 247 | print("a = 0x%08x, b = 0x%08x, c = 0x%08x, d = 0x%08x" %\ 248 | (a, b, c, d)) 249 | print("") 250 | 251 | a0 = (a + b) & 0xffffffff 252 | d0 = d ^ a0 253 | d1 = ((d0 << 16) + (d0 >> 16)) & 0xffffffff 254 | c0 = (c + d1) & 0xffffffff 255 | b0 = b ^ c0 256 | b1 = ((b0 << 12) + (b0 >> 20)) & 0xffffffff 257 | a1 = (a0 + b1) & 0xffffffff 258 | d2 = d1 ^ a1 259 | d3 = ((d2 << 8) + (d2 >> 24)) & 0xffffffff 260 | c1 = (c0 + d3) & 0xffffffff 261 | b2 = b1 ^ c1 262 | b3 = ((b2 << 7) + (b2 >> 25)) & 0xffffffff 263 | 264 | if (self.verbose > 2): 265 | print("Intermediate values:") 266 | print("a0 = 0x%08x, a1 = 0x%08x" % (a0, a1)) 267 | print("b0 = 0x%08x, b1 = 0x%08x, b2 = 0x%08x, b3 = 0x%08x" %\ 268 | (b0, b1, b2, b3)) 269 | print("c0 = 0x%08x, c1 = 0x%08x" % (c0, c1)) 270 | print("d0 = 0x%08x, d1 = 0x%08x, d2 = 0x%08x, d3 = 0x%08x" %\ 271 | (d0, d1, d2, d3)) 272 | print("") 273 | 274 | a_prim = a1 275 | b_prim = b3 276 | c_prim = c1 277 | d_prim = d3 278 | 279 | if (self.verbose > 1): 280 | print("Outdata from quarterround:") 281 | print("a_prim = 0x%08x, b_prim = 0x%08x, c_prim = 0x%08x, d_prim = 0x%08x" %\ 282 | (a_prim, b_prim, c_prim, d_prim)) 283 | print("") 284 | 285 | # Update the four elemenst in x using the qi tuple. 286 | self.x[ai], self.x[bi] = a_prim, b_prim 287 | self.x[ci], self.x[di] = c_prim, d_prim 288 | 289 | 290 | #--------------------------------------------------------------- 291 | # _inc_counter() 292 | # 293 | # Increase the 64 bit block counter. 294 | #--------------------------------------------------------------- 295 | def _inc_counter(self): 296 | self.block_counter[0] += 1 & 0xffffffff 297 | if not (self.block_counter[0] % 0xffffffff): 298 | self.block_counter[1] += 1 & 0xffffffff 299 | 300 | 301 | #--------------------------------------------------------------- 302 | # _b2w() 303 | # 304 | # Given a list of four bytes returns the little endian 305 | # 32 bit word representation of the bytes. 306 | #--------------------------------------------------------------- 307 | def _b2w(self, bytes): 308 | return (bytes[0] + (bytes[1] << 8) 309 | + (bytes[2] << 16) + (bytes[3] << 24)) & 0xffffffff 310 | 311 | 312 | #--------------------------------------------------------------- 313 | # _w2b() 314 | # 315 | # Given a 32-bit word returns a list of set of four bytes 316 | # that is the little endian byte representation of the word. 317 | #--------------------------------------------------------------- 318 | def _w2b(self, word): 319 | return [(word & 0x000000ff), ((word & 0x0000ff00) >> 8), 320 | ((word & 0x00ff0000) >> 16), ((word & 0xff000000) >> 24)] 321 | 322 | 323 | #--------------------------------------------------------------- 324 | # _print_state() 325 | # 326 | # Print the internal state. 327 | #--------------------------------------------------------------- 328 | def _print_state(self): 329 | print(" 0: 0x%08x, 1: 0x%08x, 2: 0x%08x, 3: 0x%08x" %\ 330 | (self.state[0], self.state[1], self.state[2], self.state[3])) 331 | print(" 4: 0x%08x, 5: 0x%08x, 6: 0x%08x, 7: 0x%08x" %\ 332 | (self.state[4], self.state[5], self.state[6], self.state[7])) 333 | print(" 8: 0x%08x, 9: 0x%08x, 10: 0x%08x, 11: 0x%08x" %\ 334 | (self.state[8], self.state[9], self.state[10], self.state[11])) 335 | print("12: 0x%08x, 13: 0x%08x, 14: 0x%08x, 15: 0x%08x" %\ 336 | (self.state[12], self.state[13], self.state[14], self.state[15])) 337 | print("") 338 | 339 | 340 | #--------------------------------------------------------------- 341 | # _print_x() 342 | # 343 | # Print the temporary state X. 344 | #--------------------------------------------------------------- 345 | def _print_x(self): 346 | print(" 0: 0x%08x, 1: 0x%08x, 2: 0x%08x, 3: 0x%08x" %\ 347 | (self.x[0], self.x[1], self.x[2], self.x[3])) 348 | print(" 4: 0x%08x, 5: 0x%08x, 6: 0x%08x, 7: 0x%08x" %\ 349 | (self.x[4], self.x[5], self.x[6], self.x[7])) 350 | print(" 8: 0x%08x, 9: 0x%08x, 10: 0x%08x, 11: 0x%08x" %\ 351 | (self.x[8], self.x[9], self.x[10], self.x[11])) 352 | print("12: 0x%08x, 13: 0x%08x, 14: 0x%08x, 15: 0x%08x" %\ 353 | (self.x[12], self.x[13], self.x[14], self.x[15])) 354 | print("") 355 | 356 | 357 | #------------------------------------------------------------------- 358 | # print_block() 359 | # 360 | # Print a given block (list) of bytes ordered in 361 | # rows of eight bytes. 362 | #------------------------------------------------------------------- 363 | def print_block(block): 364 | for i in range(0, len(block), 8): 365 | print("0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x" %\ 366 | (block[i], block[i+1], block[i+2], block[i+3], 367 | block[i+4], block[i+5], block[i+6], block[i+7])) 368 | 369 | 370 | #------------------------------------------------------------------- 371 | # check_block() 372 | # 373 | # Compare the result block with the expected block and print 374 | # if the result for the given test case was correct or not. 375 | #------------------------------------------------------------------- 376 | def check_block(result, expected, test_case): 377 | if result == expected: 378 | print("SUCCESS: %s was correct." % test_case) 379 | else: 380 | print("ERROR: %s was not correct." % test_case) 381 | print("Expected:") 382 | print_block(expected) 383 | print("") 384 | print("Result:") 385 | print_block(result) 386 | print("") 387 | 388 | 389 | #------------------------------------------------------------------- 390 | # main() 391 | # 392 | # If executed tests the ChaCha class using known test vectors. 393 | #------------------------------------------------------------------- 394 | def main(): 395 | print("Testing the ChaCha Python model.") 396 | print("--------------------------------") 397 | print 398 | 399 | # Testing with TC1-128-8. 400 | # All zero inputs. IV all zero. 128 bit key, 8 rounds. 401 | print("TC1-128-8: All zero inputs. 128 bit key, 8 rounds.") 402 | key1 = [0x00] * 16 403 | iv1 = [0x00] * 8 404 | expected1 = [0xe2, 0x8a, 0x5f, 0xa4, 0xa6, 0x7f, 0x8c, 0x5d, 405 | 0xef, 0xed, 0x3e, 0x6f, 0xb7, 0x30, 0x34, 0x86, 406 | 0xaa, 0x84, 0x27, 0xd3, 0x14, 0x19, 0xa7, 0x29, 407 | 0x57, 0x2d, 0x77, 0x79, 0x53, 0x49, 0x11, 0x20, 408 | 0xb6, 0x4a, 0xb8, 0xe7, 0x2b, 0x8d, 0xeb, 0x85, 409 | 0xcd, 0x6a, 0xea, 0x7c, 0xb6, 0x08, 0x9a, 0x10, 410 | 0x18, 0x24, 0xbe, 0xeb, 0x08, 0x81, 0x4a, 0x42, 411 | 0x8a, 0xab, 0x1f, 0xa2, 0xc8, 0x16, 0x08, 0x1b] 412 | block1 = [0x00] * 64 413 | cipher1 = ChaCha(key1, iv1, verbose=0) 414 | result1 = cipher1.next(block1) 415 | check_block(result1, expected1, "TC1-128-8") 416 | print 417 | 418 | 419 | # Testing with TC1-128-12. 420 | # All zero inputs. IV all zero. 128 bit key, 12 rounds. 421 | print("TC1-128-12: All zero inputs. 128 bit key, 12 rounds.") 422 | key1 = [0x00] * 16 423 | iv1 = [0x00] * 8 424 | expected1 = [0xe1, 0x04, 0x7b, 0xa9, 0x47, 0x6b, 0xf8, 0xff, 425 | 0x31, 0x2c, 0x01, 0xb4, 0x34, 0x5a, 0x7d, 0x8c, 426 | 0xa5, 0x79, 0x2b, 0x0a, 0xd4, 0x67, 0x31, 0x3f, 427 | 0x1d, 0xc4, 0x12, 0xb5, 0xfd, 0xce, 0x32, 0x41, 428 | 0x0d, 0xea, 0x8b, 0x68, 0xbd, 0x77, 0x4c, 0x36, 429 | 0xa9, 0x20, 0xf0, 0x92, 0xa0, 0x4d, 0x3f, 0x95, 430 | 0x27, 0x4f, 0xbe, 0xff, 0x97, 0xbc, 0x84, 0x91, 431 | 0xfc, 0xef, 0x37, 0xf8, 0x59, 0x70, 0xb4, 0x50] 432 | block1 = [0x00] * 64 433 | cipher1 = ChaCha(key1, iv1, rounds = 12, verbose=0) 434 | result1 = cipher1.next(block1) 435 | check_block(result1, expected1, "TC1-128-12") 436 | print 437 | 438 | 439 | # Testing with TC1-128-20. 440 | # All zero inputs. IV all zero. 128 bit key, 20 rounds. 441 | print("TC1-128-20: All zero inputs. 128 bit key, 20 rounds.") 442 | key1 = [0x00] * 16 443 | iv1 = [0x00] * 8 444 | expected1 = [0x89, 0x67, 0x09, 0x52, 0x60, 0x83, 0x64, 0xfd, 445 | 0x00, 0xb2, 0xf9, 0x09, 0x36, 0xf0, 0x31, 0xc8, 446 | 0xe7, 0x56, 0xe1, 0x5d, 0xba, 0x04, 0xb8, 0x49, 447 | 0x3d, 0x00, 0x42, 0x92, 0x59, 0xb2, 0x0f, 0x46, 448 | 0xcc, 0x04, 0xf1, 0x11, 0x24, 0x6b, 0x6c, 0x2c, 449 | 0xe0, 0x66, 0xbe, 0x3b, 0xfb, 0x32, 0xd9, 0xaa, 450 | 0x0f, 0xdd, 0xfb, 0xc1, 0x21, 0x23, 0xd4, 0xb9, 451 | 0xe4, 0x4f, 0x34, 0xdc, 0xa0, 0x5a, 0x10, 0x3f] 452 | block1 = [0x00] * 64 453 | cipher1 = ChaCha(key1, iv1, rounds = 20, verbose=0) 454 | result1 = cipher1.next(block1) 455 | check_block(result1, expected1, "TC1-128-20") 456 | print 457 | 458 | 459 | # Testing with TC1-256-8. 460 | # All zero inputs. IV all zero. 256 bit key, 8 rounds. 461 | print("TC1-256-8: All zero inputs. 256 bit key, 8 rounds.") 462 | key1 = [0x00] * 32 463 | iv1 = [0x00] * 8 464 | expected1 = [0x3e, 0x00, 0xef, 0x2f, 0x89, 0x5f, 0x40, 0xd6, 465 | 0x7f, 0x5b, 0xb8, 0xe8, 0x1f, 0x09, 0xa5, 0xa1, 466 | 0x2c, 0x84, 0x0e, 0xc3, 0xce, 0x9a, 0x7f, 0x3b, 467 | 0x18, 0x1b, 0xe1, 0x88, 0xef, 0x71, 0x1a, 0x1e, 468 | 0x98, 0x4c, 0xe1, 0x72, 0xb9, 0x21, 0x6f, 0x41, 469 | 0x9f, 0x44, 0x53, 0x67, 0x45, 0x6d, 0x56, 0x19, 470 | 0x31, 0x4a, 0x42, 0xa3, 0xda, 0x86, 0xb0, 0x01, 471 | 0x38, 0x7b, 0xfd, 0xb8, 0x0e, 0x0c, 0xfe, 0x42] 472 | block1 = [0x00] * 64 473 | cipher1 = ChaCha(key1, iv1, verbose=0) 474 | result1 = cipher1.next(block1) 475 | check_block(result1, expected1, "TC1-256-8") 476 | print 477 | 478 | 479 | # Testing with TC1-256-12. 480 | # All zero inputs. IV all zero. 256 bit key, 12 rounds. 481 | print("TC1-256-12: All zero inputs. 256 bit key, 12 rounds.") 482 | key1 = [0x00] * 32 483 | iv1 = [0x00] * 8 484 | expected1 = [0x9b, 0xf4, 0x9a, 0x6a, 0x07, 0x55, 0xf9, 0x53, 485 | 0x81, 0x1f, 0xce, 0x12, 0x5f, 0x26, 0x83, 0xd5, 486 | 0x04, 0x29, 0xc3, 0xbb, 0x49, 0xe0, 0x74, 0x14, 487 | 0x7e, 0x00, 0x89, 0xa5, 0x2e, 0xae, 0x15, 0x5f, 488 | 0x05, 0x64, 0xf8, 0x79, 0xd2, 0x7a, 0xe3, 0xc0, 489 | 0x2c, 0xe8, 0x28, 0x34, 0xac, 0xfa, 0x8c, 0x79, 490 | 0x3a, 0x62, 0x9f, 0x2c, 0xa0, 0xde, 0x69, 0x19, 491 | 0x61, 0x0b, 0xe8, 0x2f, 0x41, 0x13, 0x26, 0xbe] 492 | block1 = [0x00] * 64 493 | cipher1 = ChaCha(key1, iv1, rounds = 12, verbose=0) 494 | result1 = cipher1.next(block1) 495 | check_block(result1, expected1, "TC1-256-12") 496 | print 497 | 498 | 499 | # Testing with TC1-256-20. 500 | # All zero inputs. IV all zero. 256 bit key, 20 rounds. 501 | print("TC1-256-20: All zero inputs. 256 bit key, 20 rounds.") 502 | key1 = [0x00] * 32 503 | iv1 = [0x00] * 8 504 | expected1 = [0x76, 0xb8, 0xe0, 0xad, 0xa0, 0xf1, 0x3d, 0x90, 505 | 0x40, 0x5d, 0x6a, 0xe5, 0x53, 0x86, 0xbd, 0x28, 506 | 0xbd, 0xd2, 0x19, 0xb8, 0xa0, 0x8d, 0xed, 0x1a, 507 | 0xa8, 0x36, 0xef, 0xcc, 0x8b, 0x77, 0x0d, 0xc7, 508 | 0xda, 0x41, 0x59, 0x7c, 0x51, 0x57, 0x48, 0x8d, 509 | 0x77, 0x24, 0xe0, 0x3f, 0xb8, 0xd8, 0x4a, 0x37, 510 | 0x6a, 0x43, 0xb8, 0xf4, 0x15, 0x18, 0xa1, 0x1c, 511 | 0xc3, 0x87, 0xb6, 0x69, 0xb2, 0xee, 0x65, 0x86] 512 | block1 = [0x00] * 64 513 | cipher1 = ChaCha(key1, iv1, rounds = 20, verbose=0) 514 | result1 = cipher1.next(block1) 515 | check_block(result1, expected1, "TC1-256-20") 516 | print 517 | 518 | 519 | # Testing with TC2-128-8. 520 | # Single bit set in key. IV all zero. 128 bit key. 521 | print("TC2-128-8: One bit in key set. IV all zeros. 128 bit key, 8 rounds.") 522 | key2 = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 523 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 524 | iv2 = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 525 | expected2 = [0x03, 0xa7, 0x66, 0x98, 0x88, 0x60, 0x5a, 0x07, 526 | 0x65, 0xe8, 0x35, 0x74, 0x75, 0xe5, 0x86, 0x73, 527 | 0xf9, 0x4f, 0xc8, 0x16, 0x1d, 0xa7, 0x6c, 0x2a, 528 | 0x3a, 0xa2, 0xf3, 0xca, 0xf9, 0xfe, 0x54, 0x49, 529 | 0xe0, 0xfc, 0xf3, 0x8e, 0xb8, 0x82, 0x65, 0x6a, 530 | 0xf8, 0x3d, 0x43, 0x0d, 0x41, 0x09, 0x27, 0xd5, 531 | 0x5c, 0x97, 0x2a, 0xc4, 0xc9, 0x2a, 0xb9, 0xda, 532 | 0x37, 0x13, 0xe1, 0x9f, 0x76, 0x1e, 0xaa, 0x14] 533 | block2 = [0x00] * 64 534 | cipher2 = ChaCha(key2, iv2, verbose=0) 535 | result2 = cipher2.next(block2) 536 | check_block(result2, expected2, "TC2-128-8") 537 | print 538 | 539 | 540 | # Testing with TC2-256-8. 541 | # Single bit set in key. IV all zero. 256 bit key. 542 | print("TC2-256-8: One bit in key set. IV all zeros. 256 bit key, 8 rounds.") 543 | key2 = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 544 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 545 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 546 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 547 | iv2 = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 548 | expected2 = [0xcf, 0x5e, 0xe9, 0xa0, 0x49, 0x4a, 0xa9, 0x61, 549 | 0x3e, 0x05, 0xd5, 0xed, 0x72, 0x5b, 0x80, 0x4b, 550 | 0x12, 0xf4, 0xa4, 0x65, 0xee, 0x63, 0x5a, 0xcc, 551 | 0x3a, 0x31, 0x1d, 0xe8, 0x74, 0x04, 0x89, 0xea, 552 | 0x28, 0x9d, 0x04, 0xf4, 0x3c, 0x75, 0x18, 0xdb, 553 | 0x56, 0xeb, 0x44, 0x33, 0xe4, 0x98, 0xa1, 0x23, 554 | 0x8c, 0xd8, 0x46, 0x4d, 0x37, 0x63, 0xdd, 0xbb, 555 | 0x92, 0x22, 0xee, 0x3b, 0xd8, 0xfa, 0xe3, 0xc8] 556 | block2 = [0x00] * 64 557 | cipher2 = ChaCha(key2, iv2, verbose=0) 558 | result2 = cipher2.next(block2) 559 | check_block(result2, expected2, "TC2-256-8") 560 | print 561 | 562 | 563 | # Testing with TC3-128-8. 564 | # All zero key. Single bit in IV set. 128 bit key. 565 | print("TC3-128-8: All zero key. Single bit in IV set. 128 bit key, 8 rounds.") 566 | key3 = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 567 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 568 | iv3 = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 569 | 570 | expected3 = [0x25, 0xf5, 0xbe, 0xc6, 0x68, 0x39, 0x16, 0xff, 571 | 0x44, 0xbc, 0xcd, 0x12, 0xd1, 0x02, 0xe6, 0x92, 572 | 0x17, 0x66, 0x63, 0xf4, 0xca, 0xc5, 0x3e, 0x71, 573 | 0x95, 0x09, 0xca, 0x74, 0xb6, 0xb2, 0xee, 0xc8, 574 | 0x5d, 0xa4, 0x23, 0x6f, 0xb2, 0x99, 0x02, 0x01, 575 | 0x2a, 0xdc, 0x8f, 0x0d, 0x86, 0xc8, 0x18, 0x7d, 576 | 0x25, 0xcd, 0x1c, 0x48, 0x69, 0x66, 0x93, 0x0d, 577 | 0x02, 0x04, 0xc4, 0xee, 0x88, 0xa6, 0xab, 0x35] 578 | block3 = [0x00] * 64 579 | cipher3 = ChaCha(key3, iv3, verbose=0) 580 | result3 = cipher3.next(block3) 581 | check_block(result3, expected3, "TC3-128-8") 582 | print 583 | 584 | 585 | # Testing with TC4-128-8. 586 | # All bits in key IV are set. 128 bit key, 8 rounds. 587 | print("TC4-128-8: All bits in key IV are set. 128 bit key, 8 rounds.") 588 | key4 = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 589 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] 590 | iv4 = [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff] 591 | expected4 = [0x22, 0x04, 0xd5, 0xb8, 0x1c, 0xe6, 0x62, 0x19, 592 | 0x3e, 0x00, 0x96, 0x60, 0x34, 0xf9, 0x13, 0x02, 593 | 0xf1, 0x4a, 0x3f, 0xb0, 0x47, 0xf5, 0x8b, 0x6e, 594 | 0x6e, 0xf0, 0xd7, 0x21, 0x13, 0x23, 0x04, 0x16, 595 | 0x3e, 0x0f, 0xb6, 0x40, 0xd7, 0x6f, 0xf9, 0xc3, 596 | 0xb9, 0xcd, 0x99, 0x99, 0x6e, 0x6e, 0x38, 0xfa, 597 | 0xd1, 0x3f, 0x0e, 0x31, 0xc8, 0x22, 0x44, 0xd3, 598 | 0x3a, 0xbb, 0xc1, 0xb1, 0x1e, 0x8b, 0xf1, 0x2d] 599 | block4 = [0x00] * 64 600 | cipher4 = ChaCha(key4, iv4, verbose=0) 601 | result4 = cipher4.next(block4) 602 | check_block(result4, expected4, "TC4-128-8") 603 | print 604 | 605 | 606 | # Testing with TC5-128-8 607 | print("TC5-128-8: Even bits set. 128 bit key, 8 rounds.") 608 | key5 = [0x55] * 16 609 | iv5 = [0x55] * 8 610 | expected5 = [0xf0, 0xa2, 0x3b, 0xc3, 0x62, 0x70, 0xe1, 0x8e, 611 | 0xd0, 0x69, 0x1d, 0xc3, 0x84, 0x37, 0x4b, 0x9b, 612 | 0x2c, 0x5c, 0xb6, 0x01, 0x10, 0xa0, 0x3f, 0x56, 613 | 0xfa, 0x48, 0xa9, 0xfb, 0xba, 0xd9, 0x61, 0xaa, 614 | 0x6b, 0xab, 0x4d, 0x89, 0x2e, 0x96, 0x26, 0x1b, 615 | 0x6f, 0x1a, 0x09, 0x19, 0x51, 0x4a, 0xe5, 0x6f, 616 | 0x86, 0xe0, 0x66, 0xe1, 0x7c, 0x71, 0xa4, 0x17, 617 | 0x6a, 0xc6, 0x84, 0xaf, 0x1c, 0x93, 0x19, 0x96] 618 | block5 = [0x00] * 64 619 | cipher5 = ChaCha(key5, iv5, verbose=0) 620 | result5 = cipher5.next(block5) 621 | check_block(result5, expected5, "TC5-128-8") 622 | print 623 | 624 | 625 | # Testing with TC6-128-8 626 | print("TC6-128-8: Odd bits set. 128 bit key, 8 rounds.") 627 | key6 = [0xaa] * 16 628 | iv6 = [0xaa] * 8 629 | expected6 = [0x31, 0x2d, 0x95, 0xc0, 0xbc, 0x38, 0xef, 0xf4, 630 | 0x94, 0x2d, 0xb2, 0xd5, 0x0b, 0xdc, 0x50, 0x0a, 631 | 0x30, 0x64, 0x1e, 0xf7, 0x13, 0x2d, 0xb1, 0xa8, 632 | 0xae, 0x83, 0x8b, 0x3b, 0xea, 0x3a, 0x7a, 0xb0, 633 | 0x38, 0x15, 0xd7, 0xa4, 0xcc, 0x09, 0xdb, 0xf5, 634 | 0x88, 0x2a, 0x34, 0x33, 0xd7, 0x43, 0xac, 0xed, 635 | 0x48, 0x13, 0x6e, 0xba, 0xb7, 0x32, 0x99, 0x50, 636 | 0x68, 0x55, 0xc0, 0xf5, 0x43, 0x7a, 0x36, 0xc6] 637 | block6 = [0x00] * 64 638 | cipher6 = ChaCha(key6, iv6, verbose=0) 639 | result6 = cipher6.next(block6) 640 | check_block(result6, expected6, "TC6-128-8") 641 | print 642 | 643 | 644 | # Testing with TC7-128-8 645 | print("TC7-128-8: Key and IV are increasing, decreasing patterns. 128 bit key, 8 rounds.") 646 | key7 = [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 647 | 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff] 648 | iv7 = [0x0f, 0x1e, 0x2d, 0x3c, 0x4b, 0x59, 0x68, 0x77] 649 | expected7 = [0xa7, 0xa6, 0xc8, 0x1b, 0xd8, 0xac, 0x10, 0x6e, 650 | 0x8f, 0x3a, 0x46, 0xa1, 0xbc, 0x8e, 0xc7, 0x02, 651 | 0xe9, 0x5d, 0x18, 0xc7, 0xe0, 0xf4, 0x24, 0x51, 652 | 0x9a, 0xea, 0xfb, 0x54, 0x47, 0x1d, 0x83, 0xa2, 653 | 0xbf, 0x88, 0x88, 0x61, 0x58, 0x6b, 0x73, 0xd2, 654 | 0x28, 0xea, 0xaf, 0x82, 0xf9, 0x66, 0x5a, 0x5a, 655 | 0x15, 0x5e, 0x86, 0x7f, 0x93, 0x73, 0x1b, 0xfb, 656 | 0xe2, 0x4f, 0xab, 0x49, 0x55, 0x90, 0xb2, 0x31] 657 | block7 = [0x00] * 64 658 | cipher7 = ChaCha(key7, iv7, verbose=2) 659 | result7 = cipher7.next(block7) 660 | check_block(result7, expected7, "TC7-128-8") 661 | print 662 | 663 | 664 | # Testing with TC8-128-8 665 | print("TC8-128-8: Random inputs. 128 bit key, 8 rounds.") 666 | key8 = [0xc4, 0x6e, 0xc1, 0xb1, 0x8c, 0xe8, 0xa8, 0x78, 667 | 0x72, 0x5a, 0x37, 0xe7, 0x80, 0xdf, 0xb7, 0x35] 668 | iv8 = [0x1a, 0xda, 0x31, 0xd5, 0xcf, 0x68, 0x82, 0x21] 669 | expected8 = [0x6a, 0x87, 0x01, 0x08, 0x85, 0x9f, 0x67, 0x91, 670 | 0x18, 0xf3, 0xe2, 0x05, 0xe2, 0xa5, 0x6a, 0x68, 671 | 0x26, 0xef, 0x5a, 0x60, 0xa4, 0x10, 0x2a, 0xc8, 672 | 0xd4, 0x77, 0x00, 0x59, 0xfc, 0xb7, 0xc7, 0xba, 673 | 0xe0, 0x2f, 0x5c, 0xe0, 0x04, 0xa6, 0xbf, 0xbb, 674 | 0xea, 0x53, 0x01, 0x4d, 0xd8, 0x21, 0x07, 0xc0, 675 | 0xaa, 0x1c, 0x7c, 0xe1, 0x1b, 0x7d, 0x78, 0xf2, 676 | 0xd5, 0x0b, 0xd3, 0x60, 0x2b, 0xbd, 0x25, 0x94] 677 | block8 = [0x00] * 64 678 | cipher8 = ChaCha(key8, iv8, verbose=0) 679 | result8 = cipher8.next(block8) 680 | check_block(result8, expected8, "TC8-128-8") 681 | print 682 | 683 | 684 | #------------------------------------------------------------------- 685 | # __name__ 686 | # Python thingy which allows the file to be run standalone as 687 | # well as parsed from within a Python interpreter. 688 | #------------------------------------------------------------------- 689 | if __name__=="__main__": 690 | # Run the main function. 691 | sys.exit(main()) 692 | 693 | #======================================================================= 694 | # EOF chacha.py 695 | #======================================================================= 696 | --------------------------------------------------------------------------------