├── .gitattributes ├── doc ├── SHA-1_core_description.odt └── SHA-1_core_description.pdf ├── data └── sky130.tcl ├── .gitignore ├── sha1.core ├── LICENSE ├── .github └── workflows │ ├── openlane_runner.py │ └── ci.yml ├── toolruns └── Makefile ├── README.md └── src ├── rtl ├── sha1.v ├── sha1_w_mem.v └── sha1_core.v ├── tb ├── tb_sha1_w_mem.v ├── tb_sha1_core.v └── tb_sha1.v └── model └── python └── sha1.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Helping linguist detect files as Verilog, not Coq. 2 | *.v linguist-language=Verilog 3 | -------------------------------------------------------------------------------- /doc/SHA-1_core_description.odt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/secworks/sha1/HEAD/doc/SHA-1_core_description.odt -------------------------------------------------------------------------------- /doc/SHA-1_core_description.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/secworks/sha1/HEAD/doc/SHA-1_core_description.pdf -------------------------------------------------------------------------------- /data/sky130.tcl: -------------------------------------------------------------------------------- 1 | 2 | # Design 3 | set ::env(CLOCK_PORT) "clk" 4 | set ::env(CLOCK_NET) $::env(CLOCK_PORT) 5 | set ::env(FP_CORE_UTIL) 20 6 | set ::env(SYNTH_MAX_FANOUT) 8 7 | set ::env(PL_TARGET_DENSITY) 0.25 8 | set ::env(CLOCK_PERIOD) "25.9" -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /sha1.core: -------------------------------------------------------------------------------- 1 | CAPI=2: 2 | 3 | name : secworks:crypto:sha1:0 4 | 5 | filesets: 6 | rtl: 7 | files: 8 | - src/rtl/sha1.v 9 | - src/rtl/sha1_core.v 10 | - src/rtl/sha1_w_mem.v 11 | file_type : verilogSource 12 | 13 | tb: 14 | files: 15 | - src/tb/tb_sha1.v 16 | - src/tb/tb_sha1_core.v 17 | - src/tb/tb_sha1_w_mem.v 18 | file_type : verilogSource 19 | 20 | openlane: {files : [data/sky130.tcl : {file_type : tclSource}]} 21 | 22 | targets: 23 | default: 24 | filesets: [rtl] 25 | 26 | lint: 27 | default_tool : verilator 28 | filesets : [rtl] 29 | tools: 30 | verilator: 31 | mode : lint-only 32 | toplevel : sha1 33 | 34 | sky130: 35 | default_tool: openlane 36 | filesets: [rtl, openlane] 37 | toplevel: sha1 38 | 39 | tb_sha1: &tb 40 | default_tool: icarus 41 | filesets: [rtl, tb] 42 | toplevel : tb_sha1 43 | 44 | tb_sha1_core: 45 | <<: *tb 46 | toplevel : tb_sha1_core 47 | 48 | tb_sha1_w_mem: 49 | <<: *tb 50 | toplevel : tb_sha1_w_mem 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, 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. -------------------------------------------------------------------------------- /.github/workflows/openlane_runner.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | #This script is a launcher script for Edalize 4 | #Normally Edalize will launch the EDA tools directly, but if the 5 | #EDALIZE_LAUNCHER environmnet variable is set and points to an executable file, 6 | #this file will be called with the command-line that Edalize would otherwise 7 | #have launched. 8 | # 9 | #This allows us to define a custom launcher, as in this case where we intercept 10 | #the call to flow.tcl (the entry point to the openlane flow) and start up a 11 | #container. If Edalize wants to execute other applications, we just start them 12 | #the normal way 13 | 14 | import os 15 | import subprocess 16 | import sys 17 | 18 | def enverr(e): 19 | print(f"Error: Openlane backend needs environment variable '{e}' to be set") 20 | exit(1) 21 | 22 | if 'flow.tcl' in sys.argv[1]: 23 | pdk_root = os.environ.get('PDK_ROOT') or enverr('PDK_ROOT') 24 | (build_root, work) = os.path.split(os.getcwd()) 25 | 26 | image = "efabless/openlane:v0.12" 27 | 28 | prefix = ["docker", "run", 29 | "-v", f"{pdk_root}:{pdk_root}", 30 | "-v", f"{build_root}:/project", 31 | "-e", f"PDK_ROOT={pdk_root}", 32 | "-u", f"{os.getuid()}:{os.getgid()}", 33 | "-w", f"/project/{work}", 34 | image] 35 | sys.exit(subprocess.call(prefix+sys.argv[1:])) 36 | else: 37 | sys.exit(subprocess.call(sys.argv[1:])) 38 | 39 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: build-openlane-sky130 2 | on: [push] 3 | 4 | jobs: 5 | build-sha1: 6 | runs-on: ubuntu-latest 7 | env: 8 | REPO : sha1 9 | VLNV : secworks:crypto:sha1 10 | steps: 11 | - name: Checkout repo 12 | uses: actions/checkout@v2 13 | with: 14 | path: sha1 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}/$REPO/.github/workflows/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: fusesoc library add $REPO $GITHUB_WORKSPACE/$REPO 26 | - run: fusesoc run --target=sky130 $VLNV 27 | 28 | sim-icarus: 29 | runs-on: ubuntu-latest 30 | env: 31 | REPO : sha1 32 | VLNV : secworks:crypto:sha1 33 | steps: 34 | - name: Checkout repo 35 | uses: actions/checkout@v2 36 | with: 37 | path: sha1 38 | - run: sudo apt install iverilog 39 | - run: pip3 install fusesoc 40 | - run: fusesoc library add $REPO $GITHUB_WORKSPACE/$REPO 41 | - run: fusesoc run --target=tb_sha1 $VLNV 42 | - run: fusesoc run --target=tb_sha1_core $VLNV 43 | - run: fusesoc run --target=tb_sha1_w_mem $VLNV 44 | 45 | lint-verilator: 46 | runs-on: ubuntu-latest 47 | env: 48 | REPO : sha1 49 | VLNV : secworks:crypto:sha1 50 | steps: 51 | - name: Checkout repo 52 | uses: actions/checkout@v2 53 | with: 54 | path: sha1 55 | - run: sudo apt install verilator 56 | - run: pip3 install fusesoc 57 | - run: fusesoc library add $REPO $GITHUB_WORKSPACE/$REPO 58 | - run: fusesoc run --target=lint $VLNV 59 | -------------------------------------------------------------------------------- /toolruns/Makefile: -------------------------------------------------------------------------------- 1 | #=================================================================== 2 | # 3 | # Makefile 4 | # -------- 5 | # Makefile for building sha1 core and top simulation. 6 | # 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 | WMEM_SRC=../src/rtl/sha1_w_mem.v 41 | WMEM_TB_SRC=../src/tb/tb_sha1_w_mem.v 42 | 43 | CORE_SRC=../src/rtl/sha1_core.v ../src/rtl/sha1_w_mem.v 44 | CORE_TB_SRC=../src/tb/tb_sha1_core.v 45 | 46 | TOP_SRC=../src/rtl/sha1.v $(CORE_SRC) 47 | TOP_TB_SRC=../src/tb/tb_sha1.v 48 | 49 | CC = iverilog 50 | CC_FLAGS = -Wall 51 | 52 | LINT = verilator 53 | LINT_FLAGS = +1364-2001ext+ --lint-only -Wall -Wno-fatal -Wno-DECLFILENAME 54 | 55 | 56 | all: top.sim core.sim wmem.sim 57 | 58 | 59 | top.sim: $(TOP_TB_SRC) $(TOP_SRC) 60 | $(CC) $(CC_FLAGS) -o top.sim $(TOP_TB_SRC) $(TOP_SRC) 61 | 62 | 63 | core.sim: $(CORE_TB_SRC) $(CORE_SRC) 64 | $(CC) $(CC_FLAGS) -o core.sim $(CORE_SRC) $(CORE_TB_SRC) 65 | 66 | 67 | wmem.sim: $(WMEM_SRC) $(WMEM_TB_SRC) 68 | $(CC) $(CC_FLAGS) -o wmem.sim $(WMEM_SRC) $(WMEM_TB_SRC) 69 | 70 | 71 | lint: $(TOP_SRC) 72 | $(LINT) $(LINT_FLAGS) $(TOP_SRC) 73 | 74 | 75 | sim-top: top.sim 76 | ./top.sim 77 | 78 | 79 | sim-core: core.sim 80 | ./core.sim 81 | 82 | 83 | sim-wmem: wmem.sim 84 | ./wmem.sim 85 | 86 | 87 | clean: 88 | rm -f single_shot_top.sim 89 | rm -f top.sim 90 | rm -f core.sim 91 | rm -f wmem.sim 92 | 93 | 94 | help: 95 | @echo "Supported targets:" 96 | @echo "------------------" 97 | @echo "all: Build all simulation targets." 98 | @echo "single_shot_top: Build the top simulation target." 99 | @echo "top: Build the top simulation target." 100 | @echo "core: Build the core simulation target." 101 | @echo "wmem: Build the wmem simulation target." 102 | @echo "sim-single_shot: Run single shot top level simulation." 103 | @echo "sim-top: Run top level simulation." 104 | @echo "sim-core: Run core level simulation." 105 | @echo "sim-wmem: Run wmem level simulation." 106 | @echo "clean: Delete all built files." 107 | 108 | #=================================================================== 109 | # EOF Makefile 110 | #=================================================================== 111 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | sha1 2 | ==== 3 | Verilog implementation of the SHA-1 cryptgraphic hash function. 4 | 5 | ## Implementation status ## 6 | The core has been completed and been used in several designs. It is 7 | considered mature and ready to use.. Minor changes are non-functional 8 | cleanups of code. 9 | 10 | 11 | ## Introduction ## 12 | Verilog implementation of the SHA-1 cryptgraphic hash function. The 13 | functionality follows the specification in NIST FIPS 180-4. 14 | 15 | The implementation is iterative with one cycle/round. The initialization 16 | takes one cycle. The W memory is based around a sliding window of 16 17 | 32-bit registers that are updated in sync with the round processing. The 18 | total latency/message block is 82 cycles. 19 | 20 | There are top level wrappers that provides interface for easy 21 | integration into a System on Chip (SoC). This interface contains mesage 22 | block and digest registers to allow a host to load the next block while 23 | the current block is being processed. 24 | 25 | The implementation also includes a functional model written in Python. 26 | 27 | 28 | ### Contact information ## 29 | Assured provides customer support including customization, integration 30 | and system development related to the core. For more information, 31 | please contact [Assured Security 32 | Consultants](https://www.assured.se/contact). 33 | 34 | 35 | ## Implementation details ## 36 | 37 | The sha1 design is divided into the following sections. 38 | - src/rtl - RTL source files 39 | - src/tb - Testbenches for the RTL files 40 | - src/model/python - Functional model written in python 41 | - doc - documentation (currently not done.) 42 | - toolruns - Where tools are supposed to be run. Includes a Makefile for 43 | building and simulating the design using [Icarus Verilog](http://iverilog.icarus.com/) 44 | 45 | The actual core consists of the following files: 46 | - sha1_core.v - The core itself with wide interfaces. 47 | - sha1_w_mem.v - W message block memort and expansion logic. 48 | 49 | The top level entity is called sha1_core. This entity has wide 50 | interfaces (512 bit block input, 160 bit digest). In order to make it 51 | usable you probably want to wrap the core with a bus interface. 52 | 53 | Unless you want to provide your own interface you therefore also need to 54 | use a top level wrapper. There is one wrapper provided: 55 | - sha1.v - A wrapper with a 32-bit memory like interface. 56 | 57 | The core (sha1_core) will sample all data inputs when given the init 58 | or next signal. the wrappers provided contains additional data 59 | registers. This allows you to load a new block while the core is 60 | processing the previous block. 61 | 62 | 63 | ## FuseSoC 64 | This core is supported by the 65 | [FuseSoC](https://github.com/olofk/fusesoc) core package manager and 66 | build system. Some quick FuseSoC instructions: 67 | 68 | Install FuseSoC 69 | ~~~ 70 | pip install fusesoc 71 | ~~~ 72 | 73 | Create and enter a new workspace 74 | ~~~ 75 | mkdir workspace && cd workspace 76 | ~~~ 77 | 78 | Register sha1 as a library in the workspace 79 | ~~~ 80 | fusesoc library add sha1 /path/to/sha1 81 | ~~~ 82 | ...if repo is available locally or... 83 | ...to get the upstream repo 84 | ~~~ 85 | fusesoc library add sha1 https://github.com/secworks/sha1 86 | ~~~ 87 | 88 | Run tb_sha1 testbench 89 | ~~~ 90 | fusesoc run --target=tb_sha1 secworks:crypto:sha1 91 | ~~~ 92 | 93 | Run with modelsim instead of default tool (icarus) 94 | ~~~ 95 | fusesoc run --target=tb_sha1 --tool=modelsim secworks:crypto:sha1 96 | ~~~ 97 | 98 | ## FPGA-results ## 99 | 100 | ### Altera Cyclone FPGAs ### 101 | Implementation results using Altera Quartus-II 13.1. 102 | 103 | **Altera Cyclone IV E** 104 | - EP4CE6F17C6 105 | - 2913 LEs 106 | - 1527 regs 107 | - 107 MHz 108 | 109 | **Altera Cyclone IV GX** 110 | - EP4CGX22CF19C6 111 | - 2814 LEs 112 | - 1527 regs 113 | - 105 MHz 114 | 115 | **Altera Cyclone V** 116 | - 5CGXFC7C7F23C8 117 | - 1124 ALMs 118 | - 1527 regs 119 | - 104 MHz 120 | 121 | 122 | ### Xilinx FPGAs ### 123 | Implementation results using ISE 14.7. 124 | 125 | **Xilinx Spartan-6** 126 | - xc6slx45-3csg324 127 | - 1589 LUTs 128 | - 564 Slices 129 | - 1592 regs 130 | - 100 MHz 131 | -------------------------------------------------------------------------------- /src/rtl/sha1.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // sha1.v 4 | // ------ 5 | // Top level wrapper for the SHA-1 hash function providing 6 | // a simple memory like interface with 32 bit data access. 7 | // 8 | // 9 | // Author: Joachim Strombergson 10 | // Copyright (c) 2013 Secworks Sweden AB 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 sha1( 42 | // Clock and reset. 43 | input wire clk, 44 | input wire reset_n, 45 | 46 | // Control. 47 | input wire cs, 48 | input wire we, 49 | 50 | // Data ports. 51 | input wire [7 : 0] address, 52 | input wire [31 : 0] write_data, 53 | output wire [31 : 0] read_data, 54 | output wire error 55 | ); 56 | 57 | //---------------------------------------------------------------- 58 | // Internal constant and parameter definitions. 59 | //---------------------------------------------------------------- 60 | localparam ADDR_NAME0 = 8'h00; 61 | localparam ADDR_NAME1 = 8'h01; 62 | localparam ADDR_VERSION = 8'h02; 63 | 64 | localparam ADDR_CTRL = 8'h08; 65 | localparam CTRL_INIT_BIT = 0; 66 | localparam CTRL_NEXT_BIT = 1; 67 | 68 | localparam ADDR_STATUS = 8'h09; 69 | localparam STATUS_READY_BIT = 0; 70 | localparam STATUS_VALID_BIT = 1; 71 | 72 | localparam ADDR_BLOCK0 = 8'h10; 73 | localparam ADDR_BLOCK15 = 8'h1f; 74 | 75 | localparam ADDR_DIGEST0 = 8'h20; 76 | localparam ADDR_DIGEST4 = 8'h24; 77 | 78 | localparam CORE_NAME0 = 32'h73686131; // "sha1" 79 | localparam CORE_NAME1 = 32'h20202020; // " " 80 | localparam CORE_VERSION = 32'h302e3630; // "0.60" 81 | 82 | 83 | //---------------------------------------------------------------- 84 | // Registers including update variables and write enable. 85 | //---------------------------------------------------------------- 86 | reg init_reg; 87 | reg init_new; 88 | 89 | reg next_reg; 90 | reg next_new; 91 | 92 | reg ready_reg; 93 | 94 | reg [31 : 0] block_reg [0 : 15]; 95 | reg block_we; 96 | 97 | reg [159 : 0] digest_reg; 98 | 99 | reg digest_valid_reg; 100 | 101 | 102 | //---------------------------------------------------------------- 103 | // Wires. 104 | //---------------------------------------------------------------- 105 | wire core_ready; 106 | wire [511 : 0] core_block; 107 | wire [159 : 0] core_digest; 108 | wire core_digest_valid; 109 | 110 | reg [31 : 0] tmp_read_data; 111 | reg tmp_error; 112 | 113 | 114 | //---------------------------------------------------------------- 115 | // Concurrent connectivity for ports etc. 116 | //---------------------------------------------------------------- 117 | assign core_block = {block_reg[00], block_reg[01], block_reg[02], block_reg[03], 118 | block_reg[04], block_reg[05], block_reg[06], block_reg[07], 119 | block_reg[08], block_reg[09], block_reg[10], block_reg[11], 120 | block_reg[12], block_reg[13], block_reg[14], block_reg[15]}; 121 | 122 | assign read_data = tmp_read_data; 123 | assign error = tmp_error; 124 | 125 | 126 | //---------------------------------------------------------------- 127 | // core instantiation. 128 | //---------------------------------------------------------------- 129 | sha1_core core( 130 | .clk(clk), 131 | .reset_n(reset_n), 132 | 133 | .init(init_reg), 134 | .next(next_reg), 135 | 136 | .block(core_block), 137 | 138 | .ready(core_ready), 139 | 140 | .digest(core_digest), 141 | .digest_valid(core_digest_valid) 142 | ); 143 | 144 | 145 | //---------------------------------------------------------------- 146 | // reg_update 147 | // Update functionality for all registers in the core. 148 | // All registers are positive edge triggered with 149 | // asynchronous active low reset. 150 | //---------------------------------------------------------------- 151 | always @ (posedge clk or negedge reset_n) 152 | begin : reg_update 153 | integer i; 154 | 155 | if (!reset_n) 156 | begin 157 | init_reg <= 1'h0; 158 | next_reg <= 1'h0; 159 | ready_reg <= 1'h0; 160 | digest_reg <= 160'h0; 161 | digest_valid_reg <= 1'h0; 162 | 163 | for (i = 0 ; i < 16 ; i = i + 1) 164 | block_reg[i] <= 32'h0; 165 | end 166 | else 167 | begin 168 | ready_reg <= core_ready; 169 | digest_valid_reg <= core_digest_valid; 170 | init_reg <= init_new; 171 | next_reg <= next_new; 172 | 173 | if (block_we) 174 | block_reg[address[3 : 0]] <= write_data; 175 | 176 | if (core_digest_valid) 177 | digest_reg <= core_digest; 178 | end 179 | end // reg_update 180 | 181 | //---------------------------------------------------------------- 182 | // api 183 | // 184 | // The interface command decoding logic. 185 | //---------------------------------------------------------------- 186 | always @* 187 | begin : api 188 | init_new = 1'h0; 189 | next_new = 1'h0; 190 | block_we = 1'h0; 191 | tmp_read_data = 32'h0; 192 | tmp_error = 1'h0; 193 | 194 | if (cs) 195 | begin 196 | if (we) 197 | begin 198 | if ((address >= ADDR_BLOCK0) && (address <= ADDR_BLOCK15)) 199 | block_we = 1'h1; 200 | 201 | if (address == ADDR_CTRL) 202 | begin 203 | init_new = write_data[CTRL_INIT_BIT]; 204 | next_new = write_data[CTRL_NEXT_BIT]; 205 | end 206 | end // if (write_read) 207 | else 208 | begin 209 | if ((address >= ADDR_BLOCK0) && (address <= ADDR_BLOCK15)) 210 | tmp_read_data = block_reg[address[3 : 0]]; 211 | 212 | if ((address >= ADDR_DIGEST0) && (address <= ADDR_DIGEST4)) 213 | tmp_read_data = digest_reg[(4 - (address - ADDR_DIGEST0)) * 32 +: 32]; 214 | 215 | case (address) 216 | // Read operations. 217 | ADDR_NAME0: 218 | tmp_read_data = CORE_NAME0; 219 | 220 | ADDR_NAME1: 221 | tmp_read_data = CORE_NAME1; 222 | 223 | ADDR_VERSION: 224 | tmp_read_data = CORE_VERSION; 225 | 226 | ADDR_CTRL: 227 | tmp_read_data = {30'h0, next_reg, init_reg}; 228 | 229 | ADDR_STATUS: 230 | tmp_read_data = {30'h0, digest_valid_reg, ready_reg}; 231 | 232 | default: 233 | begin 234 | tmp_error = 1'h1; 235 | end 236 | endcase // case (addr) 237 | end 238 | end 239 | end // addr_decoder 240 | endmodule // sha1 241 | 242 | //====================================================================== 243 | // EOF sha1.v 244 | //====================================================================== 245 | -------------------------------------------------------------------------------- /src/rtl/sha1_w_mem.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // sha1_w_mem_reg.v 4 | // ----------------- 5 | // The SHA-1 W memory. This memory includes functionality to 6 | // expand the block into 80 words. 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 sha1_w_mem( 42 | input wire clk, 43 | input wire reset_n, 44 | 45 | input wire [511 : 0] block, 46 | 47 | input wire init, 48 | input wire next, 49 | 50 | output wire [31 : 0] w 51 | ); 52 | 53 | 54 | //---------------------------------------------------------------- 55 | // Registers including update variables and write enable. 56 | //---------------------------------------------------------------- 57 | reg [31 : 0] w_mem [0 : 15]; 58 | reg [31 : 0] w_mem00_new; 59 | reg [31 : 0] w_mem01_new; 60 | reg [31 : 0] w_mem02_new; 61 | reg [31 : 0] w_mem03_new; 62 | reg [31 : 0] w_mem04_new; 63 | reg [31 : 0] w_mem05_new; 64 | reg [31 : 0] w_mem06_new; 65 | reg [31 : 0] w_mem07_new; 66 | reg [31 : 0] w_mem08_new; 67 | reg [31 : 0] w_mem09_new; 68 | reg [31 : 0] w_mem10_new; 69 | reg [31 : 0] w_mem11_new; 70 | reg [31 : 0] w_mem12_new; 71 | reg [31 : 0] w_mem13_new; 72 | reg [31 : 0] w_mem14_new; 73 | reg [31 : 0] w_mem15_new; 74 | reg w_mem_we; 75 | 76 | reg [6 : 0] w_ctr_reg; 77 | reg [6 : 0] w_ctr_new; 78 | reg w_ctr_we; 79 | 80 | 81 | //---------------------------------------------------------------- 82 | // Wires. 83 | //---------------------------------------------------------------- 84 | reg [31 : 0] w_tmp; 85 | reg [31 : 0] w_new; 86 | 87 | 88 | //---------------------------------------------------------------- 89 | // Concurrent connectivity for ports etc. 90 | //---------------------------------------------------------------- 91 | assign w = w_tmp; 92 | 93 | 94 | //---------------------------------------------------------------- 95 | // reg_update 96 | // 97 | // Update functionality for all registers in the core. 98 | // All registers are positive edge triggered with 99 | // asynchronous active low reset. 100 | //---------------------------------------------------------------- 101 | always @ (posedge clk or negedge reset_n) 102 | begin : reg_update 103 | integer i; 104 | 105 | if (!reset_n) 106 | begin 107 | for (i = 0 ; i < 16 ; i = i + 1) 108 | w_mem[i] <= 32'h0; 109 | 110 | w_ctr_reg <= 7'h0; 111 | end 112 | else 113 | begin 114 | if (w_mem_we) 115 | begin 116 | w_mem[00] <= w_mem00_new; 117 | w_mem[01] <= w_mem01_new; 118 | w_mem[02] <= w_mem02_new; 119 | w_mem[03] <= w_mem03_new; 120 | w_mem[04] <= w_mem04_new; 121 | w_mem[05] <= w_mem05_new; 122 | w_mem[06] <= w_mem06_new; 123 | w_mem[07] <= w_mem07_new; 124 | w_mem[08] <= w_mem08_new; 125 | w_mem[09] <= w_mem09_new; 126 | w_mem[10] <= w_mem10_new; 127 | w_mem[11] <= w_mem11_new; 128 | w_mem[12] <= w_mem12_new; 129 | w_mem[13] <= w_mem13_new; 130 | w_mem[14] <= w_mem14_new; 131 | w_mem[15] <= w_mem15_new; 132 | end 133 | 134 | if (w_ctr_we) 135 | w_ctr_reg <= w_ctr_new; 136 | end 137 | end // reg_update 138 | 139 | 140 | //---------------------------------------------------------------- 141 | // select_w 142 | // 143 | // W word selection logic. Returns either directly from the 144 | // memory or the next w value calculated. 145 | //---------------------------------------------------------------- 146 | always @* 147 | begin : select_w 148 | if (w_ctr_reg < 16) 149 | w_tmp = w_mem[w_ctr_reg[3 : 0]]; 150 | else 151 | w_tmp = w_new; 152 | end // select_w 153 | 154 | 155 | //---------------------------------------------------------------- 156 | // w_mem_update_logic 157 | // 158 | // Update logic for the W memory. This is where the scheduling 159 | // based on a sliding window is implemented. 160 | //---------------------------------------------------------------- 161 | always @* 162 | begin : w_mem_update_logic 163 | reg [31 : 0] w_0; 164 | reg [31 : 0] w_2; 165 | reg [31 : 0] w_8; 166 | reg [31 : 0] w_13; 167 | reg [31 : 0] w_16; 168 | 169 | w_mem00_new = 32'h0; 170 | w_mem01_new = 32'h0; 171 | w_mem02_new = 32'h0; 172 | w_mem03_new = 32'h0; 173 | w_mem04_new = 32'h0; 174 | w_mem05_new = 32'h0; 175 | w_mem06_new = 32'h0; 176 | w_mem07_new = 32'h0; 177 | w_mem08_new = 32'h0; 178 | w_mem09_new = 32'h0; 179 | w_mem10_new = 32'h0; 180 | w_mem11_new = 32'h0; 181 | w_mem12_new = 32'h0; 182 | w_mem13_new = 32'h0; 183 | w_mem14_new = 32'h0; 184 | w_mem15_new = 32'h0; 185 | w_mem_we = 1'h0; 186 | 187 | w_0 = w_mem[0]; 188 | w_2 = w_mem[2]; 189 | w_8 = w_mem[8]; 190 | w_13 = w_mem[13]; 191 | w_16 = w_13 ^ w_8 ^ w_2 ^ w_0; 192 | w_new = {w_16[30 : 0], w_16[31]}; 193 | 194 | if (init) 195 | begin 196 | w_mem00_new = block[511 : 480]; 197 | w_mem01_new = block[479 : 448]; 198 | w_mem02_new = block[447 : 416]; 199 | w_mem03_new = block[415 : 384]; 200 | w_mem04_new = block[383 : 352]; 201 | w_mem05_new = block[351 : 320]; 202 | w_mem06_new = block[319 : 288]; 203 | w_mem07_new = block[287 : 256]; 204 | w_mem08_new = block[255 : 224]; 205 | w_mem09_new = block[223 : 192]; 206 | w_mem10_new = block[191 : 160]; 207 | w_mem11_new = block[159 : 128]; 208 | w_mem12_new = block[127 : 96]; 209 | w_mem13_new = block[95 : 64]; 210 | w_mem14_new = block[63 : 32]; 211 | w_mem15_new = block[31 : 0]; 212 | w_mem_we = 1'h1; 213 | end 214 | 215 | if (next && (w_ctr_reg > 15)) 216 | begin 217 | w_mem00_new = w_mem[01]; 218 | w_mem01_new = w_mem[02]; 219 | w_mem02_new = w_mem[03]; 220 | w_mem03_new = w_mem[04]; 221 | w_mem04_new = w_mem[05]; 222 | w_mem05_new = w_mem[06]; 223 | w_mem06_new = w_mem[07]; 224 | w_mem07_new = w_mem[08]; 225 | w_mem08_new = w_mem[09]; 226 | w_mem09_new = w_mem[10]; 227 | w_mem10_new = w_mem[11]; 228 | w_mem11_new = w_mem[12]; 229 | w_mem12_new = w_mem[13]; 230 | w_mem13_new = w_mem[14]; 231 | w_mem14_new = w_mem[15]; 232 | w_mem15_new = w_new; 233 | w_mem_we = 1'h1; 234 | end 235 | end // w_mem_update_logic 236 | 237 | 238 | //---------------------------------------------------------------- 239 | // w_ctr 240 | // 241 | // W schedule adress counter. Counts from 0x10 to 0x3f and 242 | // is used to expand the block into words. 243 | //---------------------------------------------------------------- 244 | always @* 245 | begin : w_ctr 246 | w_ctr_new = 7'h0; 247 | w_ctr_we = 1'h0; 248 | 249 | if (init) 250 | begin 251 | w_ctr_new = 7'h0; 252 | w_ctr_we = 1'h1; 253 | end 254 | 255 | if (next) 256 | begin 257 | w_ctr_new = w_ctr_reg + 7'h01; 258 | w_ctr_we = 1'h1; 259 | end 260 | end // w_ctr 261 | endmodule // sha1_w_mem 262 | 263 | //====================================================================== 264 | // sha1_w_mem.v 265 | //====================================================================== 266 | -------------------------------------------------------------------------------- /src/tb/tb_sha1_w_mem.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // Tb_sha1_w_mem.v 4 | // --------------- 5 | // Testbench for the SHA-1 W memory module. 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 | module tb_sha1_w_mem(); 39 | 40 | 41 | //---------------------------------------------------------------- 42 | // Internal constant and parameter definitions. 43 | //---------------------------------------------------------------- 44 | parameter DEBUG = 1; 45 | parameter DISPLAY_CYCLES = 0; 46 | 47 | parameter CLK_HALF_PERIOD = 2; 48 | 49 | 50 | //---------------------------------------------------------------- 51 | // Registers including update variables and write enable. 52 | //---------------------------------------------------------------- 53 | 54 | 55 | //---------------------------------------------------------------- 56 | // Wires. 57 | //---------------------------------------------------------------- 58 | reg tb_clk; 59 | reg tb_reset_n; 60 | reg tb_init; 61 | reg tb_next; 62 | reg [511 : 0] tb_block; 63 | wire [31 : 0] tb_w; 64 | 65 | reg [63 : 0] cycle_ctr; 66 | reg [31 : 0] error_ctr; 67 | reg [31 : 0] tc_ctr; 68 | 69 | 70 | //---------------------------------------------------------------- 71 | // Device Under Test. 72 | //---------------------------------------------------------------- 73 | sha1_w_mem dut( 74 | .clk(tb_clk), 75 | .reset_n(tb_reset_n), 76 | 77 | .block(tb_block), 78 | 79 | .init(tb_init), 80 | .next(tb_next), 81 | 82 | .w(tb_w) 83 | ); 84 | 85 | 86 | //---------------------------------------------------------------- 87 | // clk_gen 88 | // 89 | // Clock generator process. 90 | //---------------------------------------------------------------- 91 | always 92 | begin : clk_gen 93 | #CLK_HALF_PERIOD tb_clk = !tb_clk; 94 | end // clk_gen 95 | 96 | 97 | //-------------------------------------------------------------------- 98 | // dut_monitor 99 | // 100 | // Monitor displaying information every cycle. 101 | // Includes the cycle counter. 102 | //-------------------------------------------------------------------- 103 | always @ (posedge tb_clk) 104 | begin : dut_monitor 105 | cycle_ctr = cycle_ctr + 1; 106 | 107 | if (DISPLAY_CYCLES) 108 | begin 109 | $display("cycle = %016x:", cycle_ctr); 110 | end 111 | 112 | if (DEBUG) 113 | begin 114 | dump_w_state(); 115 | end 116 | end // dut_monitor 117 | 118 | 119 | //---------------------------------------------------------------- 120 | // dump_w_state() 121 | // 122 | // Dump the current state of all W registers. 123 | //---------------------------------------------------------------- 124 | task dump_w_state; 125 | begin 126 | $display("W state:"); 127 | 128 | 129 | $display("w_ctr_reg = %02x, init = %01x, next = %01x", 130 | dut.w_ctr_reg, dut.init, dut.next); 131 | 132 | $display("w_tmp = %08x, w_new = %08x", dut.w_tmp, dut.w_new); 133 | 134 | $display("w0_reg = %08x, w1_reg = %08x, w2_reg = %08x, w3_reg = %08x", 135 | dut.w_mem[00], dut.w_mem[01], dut.w_mem[02], dut.w_mem[03]); 136 | 137 | $display("w4_reg = %08x, w5_reg = %08x, w6_reg = %08x, w7_reg = %08x", 138 | dut.w_mem[04], dut.w_mem[05], dut.w_mem[06], dut.w_mem[07]); 139 | 140 | $display("w8_reg = %08x, w9_reg = %08x, w10_reg = %08x, w11_reg = %08x", 141 | dut.w_mem[08], dut.w_mem[09], dut.w_mem[10], dut.w_mem[11]); 142 | 143 | $display("w12_reg = %08x, w13_reg = %08x, w14_reg = %08x, w15_reg = %08x", 144 | dut.w_mem[12], dut.w_mem[13], dut.w_mem[14], dut.w_mem[15]); 145 | 146 | $display(""); 147 | end 148 | endtask // dump_state 149 | 150 | 151 | //---------------------------------------------------------------- 152 | // reset_dut 153 | //---------------------------------------------------------------- 154 | task reset_dut; 155 | begin 156 | $display("*** Toggle reset."); 157 | tb_reset_n = 0; 158 | #(4 * CLK_HALF_PERIOD); 159 | tb_reset_n = 1; 160 | end 161 | endtask // reset_dut 162 | 163 | 164 | //---------------------------------------------------------------- 165 | // init_sim 166 | //---------------------------------------------------------------- 167 | task init_sim; 168 | begin 169 | $display("*** Simulation init."); 170 | tb_clk = 0; 171 | tb_reset_n = 1; 172 | cycle_ctr = 0; 173 | tb_init = 0; 174 | tb_next = 0; 175 | tb_block = 512'h00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; 176 | end 177 | endtask // reset_dut 178 | 179 | 180 | //---------------------------------------------------------------- 181 | // dump_mem() 182 | // 183 | // Dump the contents of the memory by directly reading from 184 | // the registers in the dut, not via the read port. 185 | //---------------------------------------------------------------- 186 | task dump_mem; 187 | begin 188 | $display("*** Dumping memory:"); 189 | $display("W[00] = 0x%08x", dut.w_mem[00]); 190 | $display("W[01] = 0x%08x", dut.w_mem[01]); 191 | $display("W[02] = 0x%08x", dut.w_mem[02]); 192 | $display("W[03] = 0x%08x", dut.w_mem[03]); 193 | $display("W[04] = 0x%08x", dut.w_mem[04]); 194 | $display("W[05] = 0x%08x", dut.w_mem[05]); 195 | $display("W[06] = 0x%08x", dut.w_mem[06]); 196 | $display("W[07] = 0x%08x", dut.w_mem[07]); 197 | $display("W[08] = 0x%08x", dut.w_mem[08]); 198 | $display("W[09] = 0x%08x", dut.w_mem[09]); 199 | $display("W[10] = 0x%08x", dut.w_mem[10]); 200 | $display("W[11] = 0x%08x", dut.w_mem[11]); 201 | $display("W[12] = 0x%08x", dut.w_mem[12]); 202 | $display("W[13] = 0x%08x", dut.w_mem[13]); 203 | $display("W[14] = 0x%08x", dut.w_mem[14]); 204 | $display("W[15] = 0x%08x", dut.w_mem[15]); 205 | $display(""); 206 | end 207 | endtask // dump_mem 208 | 209 | 210 | //---------------------------------------------------------------- 211 | // test_w_schedule() 212 | // 213 | // Test that W scheduling happens and work correctly. 214 | // Note: Currently not a self checking test case. 215 | //---------------------------------------------------------------- 216 | task test_w_schedule; 217 | begin 218 | $display("*** Test of W schedule processing. --"); 219 | tb_block = 512'h61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018; 220 | tb_init = 1; 221 | #(4 * CLK_HALF_PERIOD); 222 | tb_init = 0; 223 | 224 | tb_next = 1; 225 | #(200 * CLK_HALF_PERIOD); 226 | 227 | dump_w_state(); 228 | end 229 | endtask // test_w_schedule 230 | 231 | 232 | //---------------------------------------------------------------- 233 | // test_read_w/( 234 | // 235 | // Test that we can read data from all W registers. 236 | // Note: Currently not a self checking test case. 237 | //---------------------------------------------------------------- 238 | task test_read_w; 239 | reg [7 : 0] i; 240 | begin 241 | $display("*** Test of W read operations. --"); 242 | i = 0; 243 | tb_init = 1; 244 | #(2 * CLK_HALF_PERIOD); 245 | tb_init = 0; 246 | 247 | while (i < 80) 248 | begin 249 | tb_next = i; 250 | $display("API: w%02x = 0x%02x", i, dut.w_tmp); 251 | i = i + 1; 252 | #(2 * CLK_HALF_PERIOD); 253 | end 254 | end 255 | endtask // read_w 256 | 257 | 258 | //---------------------------------------------------------------- 259 | // The main test functionality. 260 | //---------------------------------------------------------------- 261 | initial 262 | begin : w_mem_test 263 | $display(" -- Testbench for sha1 w memory started --"); 264 | init_sim(); 265 | 266 | dump_mem(); 267 | reset_dut(); 268 | dump_mem(); 269 | 270 | test_w_schedule(); 271 | 272 | test_read_w(); 273 | 274 | $display("*** Simulation done."); 275 | $finish; 276 | end 277 | 278 | endmodule // w_mem_test 279 | 280 | //====================================================================== 281 | // EOF tb_sha1_w_mem.v 282 | //====================================================================== 283 | -------------------------------------------------------------------------------- /src/model/python/sha1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #======================================================================= 4 | # 5 | # sha1.py 6 | # --------- 7 | # Simple, pure Python model of the SHA-1 function. Used as a 8 | # reference for the HW implementation. The code follows the structure 9 | # of the HW implementation as much as possible. 10 | # 11 | # 12 | # Author: Joachim Strömbergson 13 | # (c) 2014 Secworks Sweden AB 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 | 52 | 53 | #------------------------------------------------------------------- 54 | # SHA1() 55 | #------------------------------------------------------------------- 56 | class SHA1(): 57 | def __init__(self, verbose = 0): 58 | self.verbose = verbose 59 | self.H = [0] * 5 60 | self.T = 0 61 | self.a = 0 62 | self.b = 0 63 | self.c = 0 64 | self.d = 0 65 | self.e = 0 66 | self.W = [0] * 80 67 | self.k = 0 68 | 69 | 70 | def init(self): 71 | self.H = [0x67452301, 0xefcdab89, 0x98badcfe, 72 | 0x10325476, 0xc3d2e1f0] 73 | 74 | 75 | def next(self, block): 76 | self._W_schedule(block) 77 | self._copy_digest() 78 | for i in range(80): 79 | self._sha1_round(i) 80 | self._update_digest() 81 | 82 | 83 | def get_digest(self): 84 | return self.H 85 | 86 | 87 | def _copy_digest(self): 88 | self.a = self.H[0] 89 | self.b = self.H[1] 90 | self.c = self.H[2] 91 | self.d = self.H[3] 92 | self.e = self.H[4] 93 | 94 | 95 | def _update_digest(self): 96 | self.H[0] = (self.H[0] + self.a) & 0xffffffff 97 | self.H[1] = (self.H[1] + self.b) & 0xffffffff 98 | self.H[2] = (self.H[2] + self.c) & 0xffffffff 99 | self.H[3] = (self.H[3] + self.d) & 0xffffffff 100 | self.H[4] = (self.H[4] + self.e) & 0xffffffff 101 | 102 | 103 | def _sha1_round(self, round): 104 | if round <= 19: 105 | self.k = 0x5a827999 106 | self.f = self._Ch(self.b, self.c, self.d) 107 | 108 | elif 20 <= round <= 39: 109 | self.k = 0x6ed9eba1 110 | self.f = self._Parity(self.b, self.c, self.d) 111 | 112 | elif 40 <= round <= 59: 113 | self.k = 0x8f1bbcdc 114 | self.f = self._Maj(self.b, self.c, self.d) 115 | 116 | elif 60 <= round <= 79: 117 | self.k = 0xca62c1d6 118 | self.f = self._Parity(self.b, self.c, self.d) 119 | 120 | if self.verbose: 121 | print("Round %0d" % round) 122 | print("Round input values:") 123 | print("a = 0x%08x, b = 0x%08x, c = 0x%08x" % (self.a, self.b, self.c)) 124 | print("d = 0x%08x, e = 0x%08x" % (self.d, self.e)) 125 | print("f = 0x%08x, k = 0x%08x, w = 0x%08x" % (self.f, self.k, self.W[round])) 126 | 127 | 128 | self.T = (self._rotl32(self.a, 5) + self.f + self.e + self.k + self.W[round]) & 0xffffffff 129 | self.e = self.d 130 | self.d = self.c 131 | self.c = self._rotl32(self.b, 30) 132 | self.b = self.a 133 | self.a = self.T 134 | 135 | if self.verbose: 136 | print("Round output values:") 137 | print("a = 0x%08x, b = 0x%08x, c = 0x%08x" % (self.a, self.b, self.c)) 138 | print("d = 0x%08x, e = 0x%08x" % (self.d, self.e)) 139 | print("") 140 | 141 | 142 | def _W_schedule(self, block): 143 | # Expand the block into 80 words before round operations. 144 | for i in range(80): 145 | if (i < 16): 146 | self.W[i] = block[i] 147 | else: 148 | self.W[i] = self._rotl32((self.W[(i - 3)] ^ self.W[(i - 8)] ^ 149 | self.W[(i - 14)] ^ self.W[(i - 16)]), 1) 150 | if (self.verbose): 151 | print("W after schedule:") 152 | for i in range(80): 153 | print("W[%02d] = 0x%08x" % (i, self.W[i])) 154 | print("") 155 | 156 | 157 | def _Ch(self, x, y, z): 158 | return (x & y) ^ (~x & z) 159 | 160 | 161 | def _Maj(self, x, y, z): 162 | return (x & y) ^ (x & z) ^ (y & z) 163 | 164 | 165 | def _Parity(self, x, y, z): 166 | return (x ^ y ^ z) 167 | 168 | def _rotl32(self, n, r): 169 | return ((n << r) | (n >> (32 - r))) & 0xffffffff 170 | 171 | 172 | def compare_digests(digest, expected): 173 | if (digest != expected): 174 | print("Error:") 175 | print("Got:") 176 | print(digest) 177 | print("Expected:") 178 | print(expected) 179 | else: 180 | print("Test case ok.") 181 | 182 | 183 | #------------------------------------------------------------------- 184 | # main() 185 | # 186 | # If executed tests the SHA1 class using known test vectors. 187 | # 188 | # Test cases taken from: 189 | # http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf 190 | #------------------------------------------------------------------- 191 | def main(): 192 | print("Testing the SHA-1 Python model.") 193 | print("-------------------------------") 194 | print 195 | 196 | my_sha1 = SHA1(verbose=0); 197 | 198 | # TC1: NIST testcase with message "abc" 199 | print("TC1: Single block NIST test case.") 200 | TC1_block = [0x61626380, 0x00000000, 0x00000000, 0x00000000, 201 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 202 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 203 | 0x00000000, 0x00000000, 0x00000000, 0x00000018] 204 | 205 | TC1_expected = [0xa9993e36, 0x4706816a, 0xba3e2571, 206 | 0x7850c26c, 0x9cd0d89d] 207 | my_sha1.init() 208 | my_sha1.next(TC1_block) 209 | my_digest = my_sha1.get_digest() 210 | compare_digests(my_digest, TC1_expected) 211 | print("") 212 | 213 | 214 | # TC2: NIST testcase with message two block message. 215 | print("TC2: Dual block NIST test case.") 216 | TC2_1_block = [0x61626364, 0x62636465, 0x63646566, 0x64656667, 217 | 0x65666768, 0x66676869, 0x6768696A, 0x68696A6B, 218 | 0x696A6B6C, 0x6A6B6C6D, 0x6B6C6D6E, 0x6C6D6E6F, 219 | 0x6D6E6F70, 0x6E6F7071, 0x80000000, 0x00000000] 220 | 221 | 222 | TC2_2_block = [0x00000000, 0x00000000, 0x00000000, 0x00000000, 223 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 224 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 225 | 0x00000000, 0x00000000, 0x00000000, 0x000001C0] 226 | 227 | TC2_1_expected = [0xF4286818, 0xC37B27AE, 0x0408F581, 228 | 0x84677148, 0x4A566572] 229 | 230 | TC2_2_expected = [0x84983E44, 0x1C3BD26E, 0xBAAE4AA1, 231 | 0xF95129E5, 0xE54670F1] 232 | 233 | my_sha1.init() 234 | my_sha1.next(TC2_1_block) 235 | my_digest = my_sha1.get_digest() 236 | compare_digests(my_digest, TC2_1_expected) 237 | my_sha1.next(TC2_2_block) 238 | my_digest = my_sha1.get_digest() 239 | compare_digests(my_digest, TC2_2_expected) 240 | print("") 241 | 242 | 243 | # TC3: Huge message with n blocks 244 | n = 10000 245 | print("TC3: Huge message with %d blocks test case." % n) 246 | TC3_block = [0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f, 247 | 0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f, 248 | 0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f, 249 | 0xaa55aa55, 0xdeadbeef, 0x55aa55aa, 0xf00ff00f] 250 | 251 | TC3_expected = [0xea2ebc79, 0x35516705, 0xde1e1467, 252 | 0x31e55587, 0xa0038725] 253 | 254 | my_sha1.init() 255 | for i in range(n): 256 | my_sha1.next(TC3_block) 257 | my_digest = my_sha1.get_digest() 258 | compare_digests(my_digest, TC3_expected) 259 | 260 | 261 | #------------------------------------------------------------------- 262 | # __name__ 263 | # Python thingy which allows the file to be run standalone as 264 | # well as parsed from within a Python interpreter. 265 | #------------------------------------------------------------------- 266 | if __name__=="__main__": 267 | # Run the main function. 268 | sys.exit(main()) 269 | 270 | #======================================================================= 271 | # EOF sha1.py 272 | #======================================================================= 273 | -------------------------------------------------------------------------------- /src/tb/tb_sha1_core.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // tb_sha1_core.v 4 | // ---------------- 5 | // Testbench for the SHA-1 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 | module tb_sha1_core(); 39 | 40 | //---------------------------------------------------------------- 41 | // Internal constant and parameter definitions. 42 | //---------------------------------------------------------------- 43 | parameter DEBUG = 0; 44 | 45 | parameter CLK_HALF_PERIOD = 1; 46 | parameter CLK_PERIOD = CLK_HALF_PERIOD * 2; 47 | 48 | 49 | //---------------------------------------------------------------- 50 | // Register and Wire declarations. 51 | //---------------------------------------------------------------- 52 | reg [31 : 0] cycle_ctr; 53 | reg [31 : 0] error_ctr; 54 | reg [31 : 0] tc_ctr; 55 | 56 | reg tb_clk; 57 | reg tb_reset_n; 58 | reg tb_init; 59 | reg tb_next; 60 | reg [511 : 0] tb_block; 61 | wire tb_ready; 62 | wire [159 : 0] tb_digest; 63 | wire tb_digest_valid; 64 | 65 | 66 | 67 | //---------------------------------------------------------------- 68 | // Device Under Test. 69 | //---------------------------------------------------------------- 70 | sha1_core dut( 71 | .clk(tb_clk), 72 | .reset_n(tb_reset_n), 73 | 74 | .init(tb_init), 75 | .next(tb_next), 76 | 77 | .block(tb_block), 78 | 79 | .ready(tb_ready), 80 | 81 | .digest(tb_digest), 82 | .digest_valid(tb_digest_valid) 83 | ); 84 | 85 | 86 | //---------------------------------------------------------------- 87 | // clk_gen 88 | // 89 | // Clock generator process. 90 | //---------------------------------------------------------------- 91 | always 92 | begin : clk_gen 93 | #CLK_HALF_PERIOD tb_clk = !tb_clk; 94 | end // clk_gen 95 | 96 | 97 | //---------------------------------------------------------------- 98 | // sys_monitor 99 | //---------------------------------------------------------------- 100 | always 101 | begin : sys_monitor 102 | #(CLK_PERIOD); 103 | if (DEBUG) 104 | begin 105 | dump_dut_state(); 106 | end 107 | end 108 | 109 | 110 | //---------------------------------------------------------------- 111 | // dump_dut_state() 112 | // 113 | // Dump the state of the dump when needed. 114 | //---------------------------------------------------------------- 115 | task dump_dut_state; 116 | begin 117 | $display("State of DUT"); 118 | $display("------------"); 119 | $display("Inputs and outputs:"); 120 | $display("init = 0x%01x, next = 0x%01x", 121 | dut.init, dut.next); 122 | $display("block = 0x%0128x", dut.block); 123 | 124 | $display("ready = 0x%01x, valid = 0x%01x", 125 | dut.ready, dut.digest_valid); 126 | $display("digest = 0x%040x", dut.digest); 127 | $display("H0_reg = 0x%08x, H1_reg = 0x%08x, H2_reg = 0x%08x, H3_reg = 0x%08x, H4_reg = 0x%08x", 128 | dut.H0_reg, dut.H1_reg, dut.H2_reg, dut.H3_reg, dut.H4_reg); 129 | $display(""); 130 | 131 | $display("Control signals and counter:"); 132 | $display("sha1_ctrl_reg = 0x%01x", dut.sha1_ctrl_reg); 133 | $display("digest_init = 0x%01x, digest_update = 0x%01x", 134 | dut.digest_init, dut.digest_update); 135 | $display("state_init = 0x%01x, state_update = 0x%01x", 136 | dut.state_init, dut.state_update); 137 | $display("first_block = 0x%01x, ready_flag = 0x%01x, w_init = 0x%01x", 138 | dut.first_block, dut.ready_flag, dut.w_init); 139 | $display("round_ctr_inc = 0x%01x, round_ctr_rst = 0x%01x, round_ctr_reg = 0x%02x", 140 | dut.round_ctr_inc, dut.round_ctr_rst, dut.round_ctr_reg); 141 | $display(""); 142 | 143 | $display("State registers:"); 144 | $display("a_reg = 0x%08x, b_reg = 0x%08x, c_reg = 0x%08x, d_reg = 0x%08x, e_reg = 0x%08x", 145 | dut.a_reg, dut.b_reg, dut.c_reg, dut.d_reg, dut.e_reg); 146 | $display("a_new = 0x%08x, b_new = 0x%08x, c_new = 0x%08x, d_new = 0x%08x, e_new = 0x%08x", 147 | dut.a_new, dut.b_new, dut.c_new, dut.d_new, dut.e_new); 148 | $display(""); 149 | 150 | $display("State update values:"); 151 | $display("f = 0x%08x, k = 0x%08x, t = 0x%08x, w = 0x%08x,", 152 | dut.state_logic.f, dut.state_logic.k, dut.state_logic.t, dut.w); 153 | $display(""); 154 | end 155 | endtask // dump_dut_state 156 | 157 | 158 | //---------------------------------------------------------------- 159 | // reset_dut() 160 | //---------------------------------------------------------------- 161 | task reset_dut; 162 | begin 163 | $display("*** Toggle reset."); 164 | tb_reset_n = 0; 165 | #(4 * CLK_HALF_PERIOD); 166 | tb_reset_n = 1; 167 | end 168 | endtask // reset_dut 169 | 170 | 171 | //---------------------------------------------------------------- 172 | // init_sim() 173 | // 174 | // Initialize all counters and testbed functionality as well 175 | // as setting the DUT inputs to defined values. 176 | //---------------------------------------------------------------- 177 | task init_sim; 178 | begin 179 | error_ctr = 0; 180 | tc_ctr = 0; 181 | 182 | tb_clk = 0; 183 | tb_reset_n = 1; 184 | 185 | tb_init = 0; 186 | tb_next = 0; 187 | tb_block = 512'h00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000; 188 | end 189 | endtask // init_dut 190 | 191 | 192 | //---------------------------------------------------------------- 193 | // display_test_result() 194 | // 195 | // Display the accumulated test results. 196 | //---------------------------------------------------------------- 197 | task display_test_result; 198 | begin 199 | if (error_ctr == 0) 200 | begin 201 | $display("*** All %02d test cases completed successfully", tc_ctr); 202 | end 203 | else 204 | begin 205 | $display("*** %02d test cases did not complete successfully.", error_ctr); 206 | end 207 | end 208 | endtask // display_test_result 209 | 210 | 211 | //---------------------------------------------------------------- 212 | // wait_ready() 213 | // 214 | // Wait for the ready flag in the dut to be set. 215 | // 216 | // Note: It is the callers responsibility to call the function 217 | // when the dut is actively processing and will in fact at some 218 | // point set the flag. 219 | //---------------------------------------------------------------- 220 | task wait_ready; 221 | begin 222 | while (!tb_ready) 223 | begin 224 | #(CLK_PERIOD); 225 | 226 | end 227 | end 228 | endtask // wait_ready 229 | 230 | 231 | //---------------------------------------------------------------- 232 | // single_block_test 233 | // 234 | // Test a message of at most one block. 235 | //---------------------------------------------------------------- 236 | task single_block_test(input [7 : 0] tc_number, 237 | input [511 : 0] block, 238 | input [159 : 0] expected); 239 | begin 240 | $display("*** TC %0d single block test case started.", tc_number); 241 | tc_ctr = tc_ctr + 1; 242 | 243 | tb_block = block; 244 | tb_init = 1; 245 | #(CLK_PERIOD); 246 | tb_init = 0; 247 | wait_ready(); 248 | 249 | 250 | if (tb_digest == expected) 251 | begin 252 | $display("*** TC %0d successful.", tc_number); 253 | $display(""); 254 | end 255 | else 256 | begin 257 | $display("*** ERROR: TC %0d NOT successful.", tc_number); 258 | $display("Expected: 0x%040x", expected); 259 | $display("Got: 0x%040x", tb_digest); 260 | $display(""); 261 | 262 | error_ctr = error_ctr + 1; 263 | end 264 | end 265 | endtask // single_block_test 266 | 267 | 268 | //---------------------------------------------------------------- 269 | // double_block_test 270 | // 271 | // Test message consisting of two blocks. 272 | //---------------------------------------------------------------- 273 | task double_block_test(input [7 : 0] tc_number, 274 | input [511 : 0] block1, 275 | input [159 : 0] expected1, 276 | input [511 : 0] block2, 277 | input [159 : 0] expected2); 278 | 279 | reg [159 : 0] db_digest1; 280 | reg db_error; 281 | begin 282 | $display("*** TC %0d double block test case started.", tc_number); 283 | db_error = 0; 284 | tc_ctr = tc_ctr + 1; 285 | 286 | $display("*** TC %0d first block started.", tc_number); 287 | tb_block = block1; 288 | tb_init = 1; 289 | #(CLK_PERIOD); 290 | tb_init = 0; 291 | wait_ready(); 292 | db_digest1 = tb_digest; 293 | $display("*** TC %0d first block done.", tc_number); 294 | 295 | $display("*** TC %0d second block started.", tc_number); 296 | tb_block = block2; 297 | tb_next = 1; 298 | #(CLK_PERIOD); 299 | tb_next = 0; 300 | wait_ready(); 301 | $display("*** TC %0d second block done.", tc_number); 302 | 303 | if (db_digest1 == expected1) 304 | begin 305 | $display("*** TC %0d first block successful", tc_number); 306 | $display(""); 307 | end 308 | else 309 | begin 310 | $display("*** ERROR: TC %0d first block NOT successful", tc_number); 311 | $display("Expected: 0x%040x", expected1); 312 | $display("Got: 0x%040x", db_digest1); 313 | $display(""); 314 | db_error = 1; 315 | end 316 | 317 | if (db_digest1 == expected1) 318 | begin 319 | $display("*** TC %0d second block successful", tc_number); 320 | $display(""); 321 | end 322 | else 323 | begin 324 | $display("*** ERROR: TC %0d second block NOT successful", tc_number); 325 | $display("Expected: 0x%040x", expected2); 326 | $display("Got: 0x%040x", tb_digest); 327 | $display(""); 328 | db_error = 1; 329 | end 330 | 331 | if (db_error) 332 | begin 333 | error_ctr = error_ctr + 1; 334 | end 335 | end 336 | endtask // double_block_test 337 | 338 | 339 | //---------------------------------------------------------------- 340 | // sha1_core_test 341 | // The main test functionality. 342 | // 343 | // Test cases taken from: 344 | // http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf 345 | //---------------------------------------------------------------- 346 | initial 347 | begin : sha1_core_test 348 | reg [511 : 0] tc1; 349 | reg [159 : 0] res1; 350 | 351 | reg [511 : 0] tc2_1; 352 | reg [159 : 0] res2_1; 353 | reg [511 : 0] tc2_2; 354 | reg [159 : 0] res2_2; 355 | 356 | $display(" -- Testbench for sha1 core started --"); 357 | 358 | init_sim(); 359 | dump_dut_state(); 360 | reset_dut(); 361 | dump_dut_state(); 362 | 363 | // TC1: Single block message: "abc". 364 | tc1 = 512'h61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018; 365 | res1 = 160'ha9993e364706816aba3e25717850c26c9cd0d89d; 366 | single_block_test(1, tc1, res1); 367 | 368 | // TC2: Double block message. 369 | // "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 370 | tc2_1 = 512'h6162636462636465636465666465666765666768666768696768696A68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F70718000000000000000; 371 | res2_1 = 160'hf4286818c37b27ae0408f581846771484a566572; 372 | 373 | tc2_2 = 512'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001C0; 374 | res2_2 = 160'h84983e441c3bd26ebaae4aa1f95129e5e54670f1; 375 | double_block_test(2, tc2_1, res2_1, tc2_2, res2_2); 376 | 377 | display_test_result(); 378 | $display("*** Simulation done."); 379 | $finish; 380 | end // sha1_core_test 381 | endmodule // tb_sha1_core 382 | 383 | //====================================================================== 384 | // EOF tb_sha1_core.v 385 | //====================================================================== 386 | -------------------------------------------------------------------------------- /src/rtl/sha1_core.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // sha1_core.v 4 | // ----------- 5 | // Verilog 2001 implementation of the SHA-1 hash function. 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 sha1_core( 42 | input wire clk, 43 | input wire reset_n, 44 | 45 | input wire init, 46 | input wire next, 47 | 48 | input wire [511 : 0] block, 49 | 50 | output wire ready, 51 | 52 | output wire [159 : 0] digest, 53 | output wire digest_valid 54 | ); 55 | 56 | 57 | //---------------------------------------------------------------- 58 | // Internal constant and parameter definitions. 59 | //---------------------------------------------------------------- 60 | parameter H0_0 = 32'h67452301; 61 | parameter H0_1 = 32'hefcdab89; 62 | parameter H0_2 = 32'h98badcfe; 63 | parameter H0_3 = 32'h10325476; 64 | parameter H0_4 = 32'hc3d2e1f0; 65 | 66 | parameter SHA1_ROUNDS = 79; 67 | 68 | parameter CTRL_IDLE = 0; 69 | parameter CTRL_ROUNDS = 1; 70 | parameter CTRL_DONE = 2; 71 | 72 | 73 | //---------------------------------------------------------------- 74 | // Registers including update variables and write enable. 75 | //---------------------------------------------------------------- 76 | reg [31 : 0] a_reg; 77 | reg [31 : 0] a_new; 78 | reg [31 : 0] b_reg; 79 | reg [31 : 0] b_new; 80 | reg [31 : 0] c_reg; 81 | reg [31 : 0] c_new; 82 | reg [31 : 0] d_reg; 83 | reg [31 : 0] d_new; 84 | reg [31 : 0] e_reg; 85 | reg [31 : 0] e_new; 86 | reg a_e_we; 87 | 88 | reg [31 : 0] H0_reg; 89 | reg [31 : 0] H0_new; 90 | reg [31 : 0] H1_reg; 91 | reg [31 : 0] H1_new; 92 | reg [31 : 0] H2_reg; 93 | reg [31 : 0] H2_new; 94 | reg [31 : 0] H3_reg; 95 | reg [31 : 0] H3_new; 96 | reg [31 : 0] H4_reg; 97 | reg [31 : 0] H4_new; 98 | reg H_we; 99 | 100 | reg [6 : 0] round_ctr_reg; 101 | reg [6 : 0] round_ctr_new; 102 | reg round_ctr_we; 103 | reg round_ctr_inc; 104 | reg round_ctr_rst; 105 | 106 | reg digest_valid_reg; 107 | reg digest_valid_new; 108 | reg digest_valid_we; 109 | 110 | reg [1 : 0] sha1_ctrl_reg; 111 | reg [1 : 0] sha1_ctrl_new; 112 | reg sha1_ctrl_we; 113 | 114 | 115 | //---------------------------------------------------------------- 116 | // Wires. 117 | //---------------------------------------------------------------- 118 | reg digest_init; 119 | reg digest_update; 120 | reg state_init; 121 | reg state_update; 122 | reg first_block; 123 | reg ready_flag; 124 | reg w_init; 125 | reg w_next; 126 | wire [31 : 0] w; 127 | 128 | 129 | //---------------------------------------------------------------- 130 | // Module instantiantions. 131 | //---------------------------------------------------------------- 132 | sha1_w_mem w_mem_inst( 133 | .clk(clk), 134 | .reset_n(reset_n), 135 | 136 | .block(block), 137 | 138 | .init(w_init), 139 | .next(w_next), 140 | 141 | .w(w) 142 | ); 143 | 144 | 145 | //---------------------------------------------------------------- 146 | // Concurrent connectivity for ports etc. 147 | //---------------------------------------------------------------- 148 | assign ready = ready_flag; 149 | assign digest = {H0_reg, H1_reg, H2_reg, H3_reg, H4_reg}; 150 | assign digest_valid = digest_valid_reg; 151 | 152 | 153 | //---------------------------------------------------------------- 154 | // reg_update 155 | // Update functionality for all registers in the core. 156 | // All registers are positive edge triggered with 157 | // asynchronous active low reset. 158 | //---------------------------------------------------------------- 159 | always @ (posedge clk or negedge reset_n) 160 | begin : reg_update 161 | if (!reset_n) 162 | begin 163 | a_reg <= 32'h0; 164 | b_reg <= 32'h0; 165 | c_reg <= 32'h0; 166 | d_reg <= 32'h0; 167 | e_reg <= 32'h0; 168 | H0_reg <= 32'h0; 169 | H1_reg <= 32'h0; 170 | H2_reg <= 32'h0; 171 | H3_reg <= 32'h0; 172 | H4_reg <= 32'h0; 173 | digest_valid_reg <= 1'h0; 174 | round_ctr_reg <= 7'h0; 175 | sha1_ctrl_reg <= CTRL_IDLE; 176 | end 177 | else 178 | begin 179 | if (a_e_we) 180 | begin 181 | a_reg <= a_new; 182 | b_reg <= b_new; 183 | c_reg <= c_new; 184 | d_reg <= d_new; 185 | e_reg <= e_new; 186 | end 187 | 188 | if (H_we) 189 | begin 190 | H0_reg <= H0_new; 191 | H1_reg <= H1_new; 192 | H2_reg <= H2_new; 193 | H3_reg <= H3_new; 194 | H4_reg <= H4_new; 195 | end 196 | 197 | if (round_ctr_we) 198 | round_ctr_reg <= round_ctr_new; 199 | 200 | if (digest_valid_we) 201 | digest_valid_reg <= digest_valid_new; 202 | 203 | if (sha1_ctrl_we) 204 | sha1_ctrl_reg <= sha1_ctrl_new; 205 | end 206 | end // reg_update 207 | 208 | 209 | //---------------------------------------------------------------- 210 | // digest_logic 211 | // 212 | // The logic needed to init as well as update the digest. 213 | //---------------------------------------------------------------- 214 | always @* 215 | begin : digest_logic 216 | H0_new = 32'h0; 217 | H1_new = 32'h0; 218 | H2_new = 32'h0; 219 | H3_new = 32'h0; 220 | H4_new = 32'h0; 221 | H_we = 0; 222 | 223 | if (digest_init) 224 | begin 225 | H0_new = H0_0; 226 | H1_new = H0_1; 227 | H2_new = H0_2; 228 | H3_new = H0_3; 229 | H4_new = H0_4; 230 | H_we = 1; 231 | end 232 | 233 | if (digest_update) 234 | begin 235 | H0_new = H0_reg + a_reg; 236 | H1_new = H1_reg + b_reg; 237 | H2_new = H2_reg + c_reg; 238 | H3_new = H3_reg + d_reg; 239 | H4_new = H4_reg + e_reg; 240 | H_we = 1; 241 | end 242 | end // digest_logic 243 | 244 | 245 | //---------------------------------------------------------------- 246 | // state_logic 247 | // 248 | // The logic needed to init as well as update the state during 249 | // round processing. 250 | //---------------------------------------------------------------- 251 | always @* 252 | begin : state_logic 253 | reg [31 : 0] a5; 254 | reg [31 : 0] f; 255 | reg [31 : 0] k; 256 | reg [31 : 0] t; 257 | 258 | a5 = 32'h0; 259 | f = 32'h0; 260 | k = 32'h0; 261 | t = 32'h0; 262 | a_new = 32'h0; 263 | b_new = 32'h0; 264 | c_new = 32'h0; 265 | d_new = 32'h0; 266 | e_new = 32'h0; 267 | a_e_we = 1'h0; 268 | 269 | if (state_init) 270 | begin 271 | if (first_block) 272 | begin 273 | a_new = H0_0; 274 | b_new = H0_1; 275 | c_new = H0_2; 276 | d_new = H0_3; 277 | e_new = H0_4; 278 | a_e_we = 1; 279 | end 280 | else 281 | begin 282 | a_new = H0_reg; 283 | b_new = H1_reg; 284 | c_new = H2_reg; 285 | d_new = H3_reg; 286 | e_new = H4_reg; 287 | a_e_we = 1; 288 | end 289 | end 290 | 291 | if (state_update) 292 | begin 293 | if (round_ctr_reg <= 19) 294 | begin 295 | k = 32'h5a827999; 296 | f = ((b_reg & c_reg) ^ (~b_reg & d_reg)); 297 | end 298 | else if ((round_ctr_reg >= 20) && (round_ctr_reg <= 39)) 299 | begin 300 | k = 32'h6ed9eba1; 301 | f = b_reg ^ c_reg ^ d_reg; 302 | end 303 | else if ((round_ctr_reg >= 40) && (round_ctr_reg <= 59)) 304 | begin 305 | k = 32'h8f1bbcdc; 306 | f = ((b_reg | c_reg) ^ (b_reg | d_reg) ^ (c_reg | d_reg)); 307 | end 308 | else if (round_ctr_reg >= 60) 309 | begin 310 | k = 32'hca62c1d6; 311 | f = b_reg ^ c_reg ^ d_reg; 312 | end 313 | 314 | a5 = {a_reg[26 : 0], a_reg[31 : 27]}; 315 | t = a5 + e_reg + f + k + w; 316 | 317 | a_new = t; 318 | b_new = a_reg; 319 | c_new = {b_reg[1 : 0], b_reg[31 : 2]}; 320 | d_new = c_reg; 321 | e_new = d_reg; 322 | a_e_we = 1; 323 | end 324 | end // state_logic 325 | 326 | 327 | //---------------------------------------------------------------- 328 | // round_ctr 329 | // 330 | // Update logic for the round counter, a monotonically 331 | // increasing counter with reset. 332 | //---------------------------------------------------------------- 333 | always @* 334 | begin : round_ctr 335 | round_ctr_new = 7'h0; 336 | round_ctr_we = 1'h0; 337 | 338 | if (round_ctr_rst) 339 | begin 340 | round_ctr_new = 7'h0; 341 | round_ctr_we = 1'h1; 342 | end 343 | 344 | if (round_ctr_inc) 345 | begin 346 | round_ctr_new = round_ctr_reg + 1'h1; 347 | round_ctr_we = 1; 348 | end 349 | end // round_ctr 350 | 351 | 352 | //---------------------------------------------------------------- 353 | // sha1_ctrl_fsm 354 | // Logic for the state machine controlling the core behaviour. 355 | //---------------------------------------------------------------- 356 | always @* 357 | begin : sha1_ctrl_fsm 358 | digest_init = 1'h0; 359 | digest_update = 1'h0; 360 | state_init = 1'h0; 361 | state_update = 1'h0; 362 | first_block = 1'h0; 363 | ready_flag = 1'h0; 364 | w_init = 1'h0; 365 | w_next = 1'h0; 366 | round_ctr_inc = 1'h0; 367 | round_ctr_rst = 1'h0; 368 | digest_valid_new = 1'h0; 369 | digest_valid_we = 1'h0; 370 | sha1_ctrl_new = CTRL_IDLE; 371 | sha1_ctrl_we = 1'h0; 372 | 373 | case (sha1_ctrl_reg) 374 | CTRL_IDLE: 375 | begin 376 | ready_flag = 1; 377 | 378 | if (init) 379 | begin 380 | digest_init = 1'h1; 381 | w_init = 1'h1; 382 | state_init = 1'h1; 383 | first_block = 1'h1; 384 | round_ctr_rst = 1'h1; 385 | digest_valid_new = 1'h0; 386 | digest_valid_we = 1'h1; 387 | sha1_ctrl_new = CTRL_ROUNDS; 388 | sha1_ctrl_we = 1'h1; 389 | end 390 | 391 | if (next) 392 | begin 393 | w_init = 1'h1; 394 | state_init = 1'h1; 395 | round_ctr_rst = 1'h1; 396 | digest_valid_new = 1'h0; 397 | digest_valid_we = 1'h1; 398 | sha1_ctrl_new = CTRL_ROUNDS; 399 | sha1_ctrl_we = 1'h1; 400 | end 401 | end 402 | 403 | 404 | CTRL_ROUNDS: 405 | begin 406 | state_update = 1'h1; 407 | round_ctr_inc = 1'h1; 408 | w_next = 1'h1; 409 | 410 | if (round_ctr_reg == SHA1_ROUNDS) 411 | begin 412 | sha1_ctrl_new = CTRL_DONE; 413 | sha1_ctrl_we = 1'h1; 414 | end 415 | end 416 | 417 | 418 | CTRL_DONE: 419 | begin 420 | digest_update = 1'h1; 421 | digest_valid_new = 1'h1; 422 | digest_valid_we = 1'h1; 423 | sha1_ctrl_new = CTRL_IDLE; 424 | sha1_ctrl_we = 1'h1; 425 | end 426 | endcase // case (sha1_ctrl_reg) 427 | end // sha1_ctrl_fsm 428 | 429 | endmodule // sha1_core 430 | 431 | //====================================================================== 432 | // EOF sha1_core.v 433 | //====================================================================== 434 | -------------------------------------------------------------------------------- /src/tb/tb_sha1.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // tb_sha1.v 4 | // --------- 5 | // Testbench for the SHA-1 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_sha1(); 41 | 42 | //---------------------------------------------------------------- 43 | // Internal constant and parameter definitions. 44 | //---------------------------------------------------------------- 45 | parameter DEBUG_CORE = 0; 46 | parameter DEBUG_TOP = 0; 47 | 48 | parameter CLK_HALF_PERIOD = 1; 49 | parameter CLK_PERIOD = CLK_HALF_PERIOD * 2; 50 | 51 | parameter ADDR_NAME0 = 8'h00; 52 | parameter ADDR_NAME1 = 8'h01; 53 | parameter ADDR_VERSION = 8'h02; 54 | 55 | parameter ADDR_CTRL = 8'h08; 56 | parameter CTRL_INIT_BIT = 0; 57 | parameter CTRL_NEXT_BIT = 1; 58 | parameter CTRL_INIT_VALUE = 8'h01; 59 | parameter CTRL_NEXT_VALUE = 8'h02; 60 | 61 | parameter ADDR_STATUS = 8'h09; 62 | parameter STATUS_READY_BIT = 0; 63 | parameter STATUS_VALID_BIT = 1; 64 | 65 | parameter ADDR_BLOCK0 = 8'h10; 66 | parameter ADDR_BLOCK1 = 8'h11; 67 | parameter ADDR_BLOCK2 = 8'h12; 68 | parameter ADDR_BLOCK3 = 8'h13; 69 | parameter ADDR_BLOCK4 = 8'h14; 70 | parameter ADDR_BLOCK5 = 8'h15; 71 | parameter ADDR_BLOCK6 = 8'h16; 72 | parameter ADDR_BLOCK7 = 8'h17; 73 | parameter ADDR_BLOCK8 = 8'h18; 74 | parameter ADDR_BLOCK9 = 8'h19; 75 | parameter ADDR_BLOCK10 = 8'h1a; 76 | parameter ADDR_BLOCK11 = 8'h1b; 77 | parameter ADDR_BLOCK12 = 8'h1c; 78 | parameter ADDR_BLOCK13 = 8'h1d; 79 | parameter ADDR_BLOCK14 = 8'h1e; 80 | parameter ADDR_BLOCK15 = 8'h1f; 81 | 82 | parameter ADDR_DIGEST0 = 8'h20; 83 | parameter ADDR_DIGEST1 = 8'h21; 84 | parameter ADDR_DIGEST2 = 8'h22; 85 | parameter ADDR_DIGEST3 = 8'h23; 86 | parameter ADDR_DIGEST4 = 8'h24; 87 | 88 | 89 | //---------------------------------------------------------------- 90 | // Register and Wire declarations. 91 | //---------------------------------------------------------------- 92 | reg [31 : 0] cycle_ctr; 93 | reg [31 : 0] error_ctr; 94 | reg [31 : 0] tc_ctr; 95 | 96 | reg tb_clk; 97 | reg tb_reset_n; 98 | reg tb_cs; 99 | reg tb_write_read; 100 | reg [7 : 0] tb_address; 101 | reg [31 : 0] tb_data_in; 102 | wire [31 : 0] tb_data_out; 103 | wire tb_error; 104 | 105 | reg [31 : 0] read_data; 106 | reg [159 : 0] digest_data; 107 | 108 | 109 | //---------------------------------------------------------------- 110 | // Device Under Test. 111 | //---------------------------------------------------------------- 112 | sha1 dut( 113 | .clk(tb_clk), 114 | .reset_n(tb_reset_n), 115 | 116 | .cs(tb_cs), 117 | .we(tb_write_read), 118 | 119 | .address(tb_address), 120 | .write_data(tb_data_in), 121 | .read_data(tb_data_out), 122 | .error(tb_error) 123 | ); 124 | 125 | 126 | //---------------------------------------------------------------- 127 | // clk_gen 128 | // 129 | // Clock generator process. 130 | //---------------------------------------------------------------- 131 | always 132 | begin : clk_gen 133 | #CLK_HALF_PERIOD tb_clk = !tb_clk; 134 | end // clk_gen 135 | 136 | 137 | //---------------------------------------------------------------- 138 | // sys_monitor 139 | //---------------------------------------------------------------- 140 | always 141 | begin : sys_monitor 142 | if (DEBUG_CORE) 143 | begin 144 | dump_core_state(); 145 | end 146 | 147 | if (DEBUG_TOP) 148 | begin 149 | dump_top_state(); 150 | end 151 | 152 | #(CLK_PERIOD); 153 | cycle_ctr = cycle_ctr + 1; 154 | end 155 | 156 | 157 | //---------------------------------------------------------------- 158 | // dump_top_state() 159 | // 160 | // Dump state of the the top of the dut. 161 | //---------------------------------------------------------------- 162 | task dump_top_state; 163 | begin 164 | $display("State of top"); 165 | $display("-------------"); 166 | $display("Inputs and outputs:"); 167 | $display("cs = 0x%01x, we = 0x%01x", dut.cs, dut.we); 168 | $display("address = 0x%02x, write_data = 0x%08x", dut.address, dut.write_data); 169 | $display("error = 0x%01x, read_data = 0x%08x", dut.error, dut.read_data); 170 | $display(""); 171 | 172 | $display("Control and status flags:"); 173 | $display("init = 0x%01x, next = 0x%01x, ready = 0x%01x", 174 | dut.init_reg, dut.next_reg, dut.ready_reg); 175 | $display(""); 176 | 177 | $display("block registers:"); 178 | $display("block0 = 0x%08x, block1 = 0x%08x, block2 = 0x%08x, block3 = 0x%08x", 179 | dut.block_reg[00], dut.block_reg[01], dut.block_reg[02], dut.block_reg[03]); 180 | $display("block4 = 0x%08x, block5 = 0x%08x, block6 = 0x%08x, block7 = 0x%08x", 181 | dut.block_reg[04], dut.block_reg[05], dut.block_reg[06], dut.block_reg[07]); 182 | $display("block8 = 0x%08x, block9 = 0x%08x, block10 = 0x%08x, block11 = 0x%08x", 183 | dut.block_reg[08], dut.block_reg[09], dut.block_reg[10], dut.block_reg[11]); 184 | $display("block12 = 0x%08x, block13 = 0x%08x, block14 = 0x%08x, block15 = 0x%08x", 185 | dut.block_reg[12], dut.block_reg[13], dut.block_reg[14], dut.block_reg[15]); 186 | $display(""); 187 | 188 | $display("Digest registers:"); 189 | $display("digest_reg = 0x%040x", dut.digest_reg); 190 | $display(""); 191 | end 192 | endtask // dump_top_state 193 | 194 | 195 | //---------------------------------------------------------------- 196 | // dump_core_state() 197 | // 198 | // Dump the state of the core inside the dut. 199 | //---------------------------------------------------------------- 200 | task dump_core_state; 201 | begin 202 | $display("State of core"); 203 | $display("-------------"); 204 | $display("Inputs and outputs:"); 205 | $display("init = 0x%01x, next = 0x%01x", 206 | dut.core.init, dut.core.next); 207 | $display("block = 0x%0128x", dut.core.block); 208 | 209 | $display("ready = 0x%01x, valid = 0x%01x", 210 | dut.core.ready, dut.core.digest_valid); 211 | $display("digest = 0x%040x", dut.core.digest); 212 | $display("H0_reg = 0x%08x, H1_reg = 0x%08x, H2_reg = 0x%08x, H3_reg = 0x%08x, H4_reg = 0x%08x", 213 | dut.core.H0_reg, dut.core.H1_reg, dut.core.H2_reg, dut.core.H3_reg, dut.core.H4_reg); 214 | $display(""); 215 | 216 | $display("Control signals and counter:"); 217 | $display("sha1_ctrl_reg = 0x%01x", dut.core.sha1_ctrl_reg); 218 | $display("digest_init = 0x%01x, digest_update = 0x%01x", 219 | dut.core.digest_init, dut.core.digest_update); 220 | $display("state_init = 0x%01x, state_update = 0x%01x", 221 | dut.core.state_init, dut.core.state_update); 222 | $display("first_block = 0x%01x, ready_flag = 0x%01x, w_init = 0x%01x", 223 | dut.core.first_block, dut.core.ready_flag, dut.core.w_init); 224 | $display("round_ctr_inc = 0x%01x, round_ctr_rst = 0x%01x, round_ctr_reg = 0x%02x", 225 | dut.core.round_ctr_inc, dut.core.round_ctr_rst, dut.core.round_ctr_reg); 226 | $display(""); 227 | 228 | $display("State registers:"); 229 | $display("a_reg = 0x%08x, b_reg = 0x%08x, c_reg = 0x%08x, d_reg = 0x%08x, e_reg = 0x%08x", 230 | dut.core.a_reg, dut.core.b_reg, dut.core.c_reg, dut.core.d_reg, dut.core.e_reg); 231 | $display("a_new = 0x%08x, b_new = 0x%08x, c_new = 0x%08x, d_new = 0x%08x, e_new = 0x%08x", 232 | dut.core.a_new, dut.core.b_new, dut.core.c_new, dut.core.d_new, dut.core.e_new); 233 | $display(""); 234 | 235 | $display("State update values:"); 236 | $display("f = 0x%08x, k = 0x%08x, t = 0x%08x, w = 0x%08x,", 237 | dut.core.state_logic.f, dut.core.state_logic.k, dut.core.state_logic.t, dut.core.w); 238 | $display(""); 239 | end 240 | endtask // dump_core_state 241 | 242 | 243 | //---------------------------------------------------------------- 244 | // reset_dut() 245 | //---------------------------------------------------------------- 246 | task reset_dut; 247 | begin 248 | $display("*** Toggle reset."); 249 | tb_reset_n = 0; 250 | #(4 * CLK_HALF_PERIOD); 251 | tb_reset_n = 1; 252 | end 253 | endtask // reset_dut 254 | 255 | 256 | //---------------------------------------------------------------- 257 | // init_sim() 258 | // 259 | // Initialize all counters and testbed functionality as well 260 | // as setting the DUT inputs to defined values. 261 | //---------------------------------------------------------------- 262 | task init_sim; 263 | begin 264 | cycle_ctr = 32'h00000000; 265 | error_ctr = 32'h00000000; 266 | tc_ctr = 32'h00000000; 267 | 268 | tb_clk = 0; 269 | tb_reset_n = 0; 270 | tb_cs = 0; 271 | tb_write_read = 0; 272 | tb_address = 6'h00; 273 | tb_data_in = 32'h00000000; 274 | end 275 | endtask // init_dut 276 | 277 | 278 | //---------------------------------------------------------------- 279 | // display_test_result() 280 | // 281 | // Display the accumulated test results. 282 | //---------------------------------------------------------------- 283 | task display_test_result; 284 | begin 285 | if (error_ctr == 0) 286 | begin 287 | $display("*** All %02d test cases completed successfully.", tc_ctr); 288 | end 289 | else 290 | begin 291 | $display("*** %02d test cases completed.", tc_ctr); 292 | $display("*** %02d errors detected during testing.", error_ctr); 293 | end 294 | end 295 | endtask // display_test_result 296 | 297 | 298 | //---------------------------------------------------------------- 299 | // wait_ready() 300 | // 301 | // Wait for the ready flag in the dut to be set. 302 | // (Actually we wait for either ready or valid to be set.) 303 | // 304 | // Note: It is the callers responsibility to call the function 305 | // when the dut is actively processing and will in fact at some 306 | // point set the flag. 307 | //---------------------------------------------------------------- 308 | task wait_ready; 309 | begin 310 | read_data = 0; 311 | 312 | while (read_data == 0) 313 | begin 314 | read_word(ADDR_STATUS); 315 | end 316 | end 317 | endtask // wait_ready 318 | 319 | 320 | //---------------------------------------------------------------- 321 | // read_word() 322 | // 323 | // Read a data word from the given address in the DUT. 324 | // the word read will be available in the global variable 325 | // read_data. 326 | //---------------------------------------------------------------- 327 | task read_word(input [7 : 0] address); 328 | begin 329 | tb_address = address; 330 | tb_cs = 1; 331 | tb_write_read = 0; 332 | #(CLK_PERIOD); 333 | read_data = tb_data_out; 334 | tb_cs = 0; 335 | 336 | if (DEBUG_TOP) 337 | begin 338 | $display("*** Reading 0x%08x from 0x%02x.", read_data, address); 339 | $display(""); 340 | end 341 | end 342 | endtask // read_word 343 | 344 | 345 | //---------------------------------------------------------------- 346 | // write_word() 347 | // 348 | // Write the given word to the DUT using the DUT interface. 349 | //---------------------------------------------------------------- 350 | task write_word(input [7 : 0] address, 351 | input [31 : 0] word); 352 | begin 353 | if (DEBUG_TOP) 354 | begin 355 | $display("*** Writing 0x%08x to 0x%02x.", word, address); 356 | $display(""); 357 | end 358 | 359 | tb_address = address; 360 | tb_data_in = word; 361 | tb_cs = 1; 362 | tb_write_read = 1; 363 | #(CLK_PERIOD); 364 | tb_cs = 0; 365 | tb_write_read = 0; 366 | end 367 | endtask // write_word 368 | 369 | 370 | //---------------------------------------------------------------- 371 | // write_block() 372 | // 373 | // Write the given block to the dut. 374 | //---------------------------------------------------------------- 375 | task write_block(input [511 : 0] block); 376 | begin 377 | write_word(ADDR_BLOCK0, block[511 : 480]); 378 | write_word(ADDR_BLOCK1, block[479 : 448]); 379 | write_word(ADDR_BLOCK2, block[447 : 416]); 380 | write_word(ADDR_BLOCK3, block[415 : 384]); 381 | write_word(ADDR_BLOCK4, block[383 : 352]); 382 | write_word(ADDR_BLOCK5, block[351 : 320]); 383 | write_word(ADDR_BLOCK6, block[319 : 288]); 384 | write_word(ADDR_BLOCK7, block[287 : 256]); 385 | write_word(ADDR_BLOCK8, block[255 : 224]); 386 | write_word(ADDR_BLOCK9, block[223 : 192]); 387 | write_word(ADDR_BLOCK10, block[191 : 160]); 388 | write_word(ADDR_BLOCK11, block[159 : 128]); 389 | write_word(ADDR_BLOCK12, block[127 : 96]); 390 | write_word(ADDR_BLOCK13, block[95 : 64]); 391 | write_word(ADDR_BLOCK14, block[63 : 32]); 392 | write_word(ADDR_BLOCK15, block[31 : 0]); 393 | end 394 | endtask // write_block 395 | 396 | 397 | //---------------------------------------------------------------- 398 | // check_name_version() 399 | // 400 | // Read the name and version from the DUT. 401 | //---------------------------------------------------------------- 402 | task check_name_version; 403 | reg [31 : 0] name0; 404 | reg [31 : 0] name1; 405 | reg [31 : 0] version; 406 | begin 407 | 408 | read_word(ADDR_NAME0); 409 | name0 = read_data; 410 | read_word(ADDR_NAME1); 411 | name1 = read_data; 412 | read_word(ADDR_VERSION); 413 | version = read_data; 414 | 415 | $display("DUT name: %c%c%c%c%c%c%c%c", 416 | name0[31 : 24], name0[23 : 16], name0[15 : 8], name0[7 : 0], 417 | name1[31 : 24], name1[23 : 16], name1[15 : 8], name1[7 : 0]); 418 | $display("DUT version: %c%c%c%c", 419 | version[31 : 24], version[23 : 16], version[15 : 8], version[7 : 0]); 420 | end 421 | endtask // check_name_version 422 | 423 | 424 | //---------------------------------------------------------------- 425 | // read_digest() 426 | // 427 | // Read the digest in the dut. The resulting digest will be 428 | // available in the global variable digest_data. 429 | //---------------------------------------------------------------- 430 | task read_digest; 431 | begin 432 | read_word(ADDR_DIGEST0); 433 | digest_data[159 : 128] = read_data; 434 | read_word(ADDR_DIGEST1); 435 | digest_data[127 : 96] = read_data; 436 | read_word(ADDR_DIGEST2); 437 | digest_data[95 : 64] = read_data; 438 | read_word(ADDR_DIGEST3); 439 | digest_data[63 : 32] = read_data; 440 | read_word(ADDR_DIGEST4); 441 | digest_data[31 : 0] = read_data; 442 | end 443 | endtask // read_digest 444 | 445 | 446 | //---------------------------------------------------------------- 447 | // single_block_test() 448 | // 449 | // 450 | // Perform test of a single block digest. 451 | //---------------------------------------------------------------- 452 | task single_block_test(input [511 : 0] block, 453 | input [159 : 0] expected 454 | ); 455 | begin 456 | $display("*** TC%01d - Single block test started.", tc_ctr); 457 | 458 | write_block(block); 459 | write_word(ADDR_CTRL, CTRL_INIT_VALUE); 460 | #(CLK_PERIOD); 461 | wait_ready(); 462 | read_digest(); 463 | 464 | if (digest_data == expected) 465 | begin 466 | $display("TC%01d: OK.", tc_ctr); 467 | end 468 | else 469 | begin 470 | $display("TC%01d: ERROR.", tc_ctr); 471 | $display("TC%01d: Expected: 0x%040x", tc_ctr, expected); 472 | $display("TC%01d: Got: 0x%040x", tc_ctr, digest_data); 473 | error_ctr = error_ctr + 1; 474 | end 475 | $display("*** TC%01d - Single block test done.", tc_ctr); 476 | tc_ctr = tc_ctr + 1; 477 | end 478 | endtask // single_block_test 479 | 480 | 481 | //---------------------------------------------------------------- 482 | // double_block_test() 483 | // 484 | // 485 | // Perform test of a double block digest. Note that we check 486 | // the digests for both the first and final block. 487 | //---------------------------------------------------------------- 488 | task double_block_test(input [511 : 0] block0, 489 | input [159 : 0] expected0, 490 | input [511 : 0] block1, 491 | input [159 : 0] expected1 492 | ); 493 | begin 494 | $display("*** TC%01d - Double block test started.", tc_ctr); 495 | 496 | // First block 497 | write_block(block0); 498 | write_word(ADDR_CTRL, CTRL_INIT_VALUE); 499 | #(CLK_PERIOD); 500 | wait_ready(); 501 | read_digest(); 502 | 503 | if (digest_data == expected0) 504 | begin 505 | $display("TC%01d first block: OK.", tc_ctr); 506 | end 507 | else 508 | begin 509 | $display("TC%01d: ERROR in first digest", tc_ctr); 510 | $display("TC%01d: Expected: 0x%040x", tc_ctr, expected0); 511 | $display("TC%01d: Got: 0x%040x", tc_ctr, digest_data); 512 | error_ctr = error_ctr + 1; 513 | end 514 | 515 | // Final block 516 | write_block(block1); 517 | write_word(ADDR_CTRL, CTRL_NEXT_VALUE); 518 | #(CLK_PERIOD); 519 | wait_ready(); 520 | read_digest(); 521 | 522 | if (digest_data == expected1) 523 | begin 524 | $display("TC%01d final block: OK.", tc_ctr); 525 | end 526 | else 527 | begin 528 | $display("TC%01d: ERROR in final digest", tc_ctr); 529 | $display("TC%01d: Expected: 0x%040x", tc_ctr, expected1); 530 | $display("TC%01d: Got: 0x%040x", tc_ctr, digest_data); 531 | error_ctr = error_ctr + 1; 532 | end 533 | 534 | $display("*** TC%01d - Double block test done.", tc_ctr); 535 | tc_ctr = tc_ctr + 1; 536 | end 537 | endtask // double_block_test 538 | 539 | 540 | //---------------------------------------------------------------- 541 | // sha1_test 542 | // The main test functionality. 543 | // 544 | // Test cases taken from: 545 | // http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf 546 | //---------------------------------------------------------------- 547 | initial 548 | begin : sha1_test 549 | reg [511 : 0] tc1; 550 | reg [159 : 0] res1; 551 | 552 | reg [511 : 0] tc2_1; 553 | reg [159 : 0] res2_1; 554 | reg [511 : 0] tc2_2; 555 | reg [159 : 0] res2_2; 556 | 557 | $display(" -- Testbench for sha1 started --"); 558 | 559 | init_sim(); 560 | reset_dut(); 561 | check_name_version(); 562 | 563 | // TC1: Single block message: "abc". 564 | tc1 = 512'h61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018; 565 | res1 = 160'ha9993e364706816aba3e25717850c26c9cd0d89d; 566 | single_block_test(tc1, res1); 567 | 568 | // TC2: Double block message. 569 | // "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 570 | tc2_1 = 512'h6162636462636465636465666465666765666768666768696768696A68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F70718000000000000000; 571 | res2_1 = 160'hf4286818c37b27ae0408f581846771484a566572; 572 | 573 | tc2_2 = 512'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001C0; 574 | res2_2 = 160'h84983e441c3bd26ebaae4aa1f95129e5e54670f1; 575 | double_block_test(tc2_1, res2_1, tc2_2, res2_2); 576 | 577 | display_test_result(); 578 | $display("*** Simulation done. ***"); 579 | $finish; 580 | end // sha1_test 581 | endmodule // tb_sha1 582 | 583 | //====================================================================== 584 | // EOF tb_sha1.v 585 | //====================================================================== 586 | --------------------------------------------------------------------------------