aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Selkirk <paul@psgd.org>2014-09-25 22:09:34 -0400
committerPaul Selkirk <paul@psgd.org>2014-09-25 22:09:34 -0400
commit4817dd0cffa365bd58fc45e51f89157c36e0691f (patch)
tree0a01f16788952bfad1e5fa8ef1c57c7b606dbc8a /src
Initial commit
Diffstat (limited to 'src')
-rw-r--r--src/rtl/coretest_hashes.v273
-rw-r--r--src/rtl/i2c_core.v581
-rw-r--r--src/rtl/novena_fpga.v147
-rw-r--r--src/rtl/sha1.v421
-rw-r--r--src/rtl/sha256.v433
-rw-r--r--src/rtl/sha512.v497
-rw-r--r--src/sw/hash.c310
-rw-r--r--src/sw/hash_tester.c688
8 files changed, 3350 insertions, 0 deletions
diff --git a/src/rtl/coretest_hashes.v b/src/rtl/coretest_hashes.v
new file mode 100644
index 0000000..567d4f7
--- /dev/null
+++ b/src/rtl/coretest_hashes.v
@@ -0,0 +1,273 @@
+//======================================================================
+//
+// coretest_hashes.v
+// -----------------
+// Top level wrapper that creates the Cryptech coretest system.
+// The wrapper contains instances of the external interface and the
+// cores to be tested, as well as address and data muxes.
+//
+//
+// Authors: Joachim Strombergson, Paul Selkirk
+// Copyright (c) 2014, SUNET
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or
+// without modification, are permitted provided that the following
+// conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in
+// the documentation and/or other materials provided with the
+// distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module coretest_hashes(
+ input wire clk,
+ input wire reset_n,
+
+ // External interface.
+ input wire SCL,
+ input wire SDA,
+ output wire SDA_pd,
+
+ output wire [7 : 0] debug
+ );
+
+
+ //----------------------------------------------------------------
+ // Internal constant and parameter definitions.
+ //----------------------------------------------------------------
+ parameter I2C_SHA1_ADDR = 7'h1e;
+ parameter I2C_SHA256_ADDR = 7'h1f;
+ parameter I2C_SHA512_224_ADDR = 7'h20;
+ parameter I2C_SHA512_256_ADDR = 7'h21;
+ parameter I2C_SHA384_ADDR = 7'h22;
+ parameter I2C_SHA512_ADDR = 7'h23;
+
+ parameter MODE_SHA_512_224 = 2'h0;
+ parameter MODE_SHA_512_256 = 2'h1;
+ parameter MODE_SHA_384 = 2'h2;
+ parameter MODE_SHA_512 = 2'h3;
+
+
+ //----------------------------------------------------------------
+ // Wires.
+ //----------------------------------------------------------------
+ // i2c connections
+ wire i2c_rxd_syn;
+ wire [7 : 0] i2c_rxd_data;
+ reg i2c_rxd_ack;
+ reg i2c_txd_syn;
+ reg [7 : 0] i2c_txd_data;
+ wire i2c_txd_ack;
+ wire [6 : 0] i2c_device_addr;
+
+ // sha1 connections.
+ reg sha1_rxd_syn;
+ reg [7 : 0] sha1_rxd_data;
+ wire sha1_rxd_ack;
+ wire sha1_txd_syn;
+ wire [7 : 0] sha1_txd_data;
+ reg sha1_txd_ack;
+
+ // sha256 connections.
+ reg sha256_rxd_syn;
+ reg [7 : 0] sha256_rxd_data;
+ wire sha256_rxd_ack;
+ wire sha256_txd_syn;
+ wire [7 : 0] sha256_txd_data;
+ reg sha256_txd_ack;
+
+ // sha512 connections.
+ reg [1 : 0] sha512_mode;
+ reg sha512_rxd_syn;
+ reg [7 : 0] sha512_rxd_data;
+ wire sha512_rxd_ack;
+ wire sha512_txd_syn;
+ wire [7 : 0] sha512_txd_data;
+ reg sha512_txd_ack;
+
+
+ //----------------------------------------------------------------
+ // Core instantiations.
+ //----------------------------------------------------------------
+ i2c_core i2c(
+ .clk(clk),
+ .reset(!reset_n), // active high
+
+ .SCL(SCL),
+ .SDA(SDA),
+ .SDA_pd(SDA_pd),
+ .i2c_addr_low(I2C_SHA1_ADDR),
+ .i2c_addr_high(I2C_SHA512_ADDR),
+ .i2c_device_addr(i2c_device_addr),
+
+ .rxd_syn(i2c_rxd_syn),
+ .rxd_data(i2c_rxd_data),
+ .rxd_ack(i2c_rxd_ack),
+
+ .txd_syn(i2c_txd_syn),
+ .txd_data(i2c_txd_data),
+ .txd_ack(i2c_txd_ack)
+ );
+
+ sha1 sha1(
+ .clk(clk),
+ .reset_n(reset_n),
+
+ .rx_syn(sha1_rxd_syn),
+ .rx_data(sha1_rxd_data),
+ .rx_ack(sha1_rxd_ack),
+
+ .tx_syn(sha1_txd_syn),
+ .tx_data(sha1_txd_data),
+ .tx_ack(sha1_txd_ack)
+ );
+
+ sha256 sha256(
+ .clk(clk),
+ .reset_n(reset_n),
+
+ .rx_syn(sha256_rxd_syn),
+ .rx_data(sha256_rxd_data),
+ .rx_ack(sha256_rxd_ack),
+
+ .tx_syn(sha256_txd_syn),
+ .tx_data(sha256_txd_data),
+ .tx_ack(sha256_txd_ack)
+ );
+
+ sha512 sha512(
+ .clk(clk),
+ .reset_n(reset_n),
+
+ .mode(sha512_mode),
+
+ .rx_syn(sha512_rxd_syn),
+ .rx_data(sha512_rxd_data),
+ .rx_ack(sha512_rxd_ack),
+
+ .tx_syn(sha512_txd_syn),
+ .tx_data(sha512_txd_data),
+ .tx_ack(sha512_txd_ack)
+ );
+
+ //----------------------------------------------------------------
+ // address_mux
+ //
+ // Combinational data mux that handles addressing between
+ // cores using the I2C device address.
+ //----------------------------------------------------------------
+ always @*
+ begin : address_mux
+ // Default assignments.
+ i2c_rxd_ack = 0;
+ i2c_txd_syn = 0;
+ i2c_txd_data = 8'h00;
+
+ sha1_rxd_syn = 0;
+ sha1_rxd_data = 8'h00;
+ sha1_txd_ack = 0;
+
+ sha256_rxd_syn = 0;
+ sha256_rxd_data = 8'h00;
+ sha256_txd_ack = 0;
+
+ sha512_rxd_syn = 0;
+ sha512_rxd_data = 8'h00;
+ sha512_txd_ack = 0;
+ sha512_mode = 2'b00;
+
+ case (i2c_device_addr)
+ I2C_SHA1_ADDR:
+ begin
+ sha1_rxd_syn = i2c_rxd_syn;
+ sha1_rxd_data = i2c_rxd_data;
+ i2c_rxd_ack = sha1_rxd_ack;
+ i2c_txd_syn = sha1_txd_syn;
+ i2c_txd_data = sha1_txd_data;
+ sha1_txd_ack = i2c_txd_ack;
+ end
+
+ I2C_SHA256_ADDR:
+ begin
+ sha256_rxd_syn = i2c_rxd_syn;
+ sha256_rxd_data = i2c_rxd_data;
+ i2c_rxd_ack = sha256_rxd_ack;
+ i2c_txd_syn = sha256_txd_syn;
+ i2c_txd_data = sha256_txd_data;
+ sha256_txd_ack = i2c_txd_ack;
+ end
+
+ I2C_SHA512_224_ADDR:
+ begin
+ sha512_rxd_syn = i2c_rxd_syn;
+ sha512_rxd_data = i2c_rxd_data;
+ i2c_rxd_ack = sha512_rxd_ack;
+ i2c_txd_syn = sha512_txd_syn;
+ i2c_txd_data = sha512_txd_data;
+ sha512_txd_ack = i2c_txd_ack;
+ sha512_mode = MODE_SHA_512_224;
+ end
+
+ I2C_SHA512_256_ADDR:
+ begin
+ sha512_rxd_syn = i2c_rxd_syn;
+ sha512_rxd_data = i2c_rxd_data;
+ i2c_rxd_ack = sha512_rxd_ack;
+ i2c_txd_syn = sha512_txd_syn;
+ i2c_txd_data = sha512_txd_data;
+ sha512_txd_ack = i2c_txd_ack;
+ sha512_mode = MODE_SHA_512_256;
+ end
+
+ I2C_SHA384_ADDR:
+ begin
+ sha512_rxd_syn = i2c_rxd_syn;
+ sha512_rxd_data = i2c_rxd_data;
+ i2c_rxd_ack = sha512_rxd_ack;
+ i2c_txd_syn = sha512_txd_syn;
+ i2c_txd_data = sha512_txd_data;
+ sha512_txd_ack = i2c_txd_ack;
+ sha512_mode = MODE_SHA_384;
+ end
+
+ I2C_SHA512_ADDR:
+ begin
+ sha512_rxd_syn = i2c_rxd_syn;
+ sha512_rxd_data = i2c_rxd_data;
+ i2c_rxd_ack = sha512_rxd_ack;
+ i2c_txd_syn = sha512_txd_syn;
+ i2c_txd_data = sha512_txd_data;
+ sha512_txd_ack = i2c_txd_ack;
+ sha512_mode = MODE_SHA_512;
+ end
+
+ default:
+ begin
+ end
+ endcase // case (i2c_device_addr)
+ end // address_mux
+
+endmodule // coretest_hashes
+
+//======================================================================
+// EOF coretest_hashes.v
+//======================================================================
diff --git a/src/rtl/i2c_core.v b/src/rtl/i2c_core.v
new file mode 100644
index 0000000..cbf76c6
--- /dev/null
+++ b/src/rtl/i2c_core.v
@@ -0,0 +1,581 @@
+//////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2011, Andrew "bunnie" Huang
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without modification,
+// are permitted provided that the following conditions are met:
+//
+// * Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//////////////////////////////////////////////////////////////////////////////
+// A simple I2C slave implementation. Oversampled for robustness.
+// The slave is extended into the snoop & surpress version for the DDC bus;
+// this is just a starting point for basic testing and also simple comms
+// with the CPU.
+//
+// i2c slave module requires the top level module to implement the IOBs
+// This is just to keep the tri-state easy to implemen across the hierarchy
+//
+// The code required on the top level is:
+// IOBUF #(.DRIVE(12), .SLEW("SLOW")) IOBUF_sda (.IO(SDA), .I(1'b0), .T(!SDA_pd));
+//
+///////////
+`timescale 1 ns / 1 ps
+
+module i2c_core (
+ input wire clk,
+ input wire reset,
+
+ // External data interface
+ input wire SCL,
+ input wire SDA,
+ output reg SDA_pd,
+ input wire [6:0] i2c_addr_low,
+ input wire [6:0] i2c_addr_high,
+ output wire [6:0] i2c_device_addr,
+
+ // Internal receive interface.
+ output wire rxd_syn,
+ output [7 : 0] rxd_data,
+ input wire rxd_ack,
+
+ // Internal transmit interface.
+ input wire txd_syn,
+ input wire [7 : 0] txd_data,
+ output wire txd_ack
+ );
+
+ /////// I2C physical layer components
+ /// SDA is stable when SCL is high.
+ /// If SDA moves while SCL is high, this is considered a start or stop condition.
+ ///
+ /// Otherwise, SDA can move around when SCL is low (this is where we suppress bits or
+ /// overdrive as needed). SDA is a wired-AND bus, so you only "drive" zero.
+ ///
+ /// In an oversampled implementation, a rising and falling edge de-glitcher is needed
+ /// for SCL and SDA.
+ ///
+
+ // rise fall time cycles computation:
+ // At 400kHz operation, 2.5us is a cycle. "chatter" from transition should be about
+ // 5% of total cycle time max (just rule of thumb), so 0.125us should be the equiv
+ // number of cycles.
+ // For the demo board, a 25 MHz clock is provided, and 0.125us ~ 4 cycles
+ // At 100kHz operation, 10us is a cycle, so 0.5us ~ 12 cycles
+ parameter TRF_CYCLES = 5'd4; // number of cycles for rise/fall time
+
+ ////////////////
+ ///// protocol-level state machine
+ ////////////////
+ parameter I2C_START = 16'b1 << 0; // should only pass through this state for one cycle
+ parameter I2C_RESTART = 16'b1 << 1;
+ parameter I2C_DADDR = 16'b1 << 2;
+ parameter I2C_ACK_DADDR = 16'b1 << 3;
+ parameter I2C_WR_DATA = 16'b1 << 4;
+ parameter I2C_ACK_WR = 16'b1 << 5;
+ parameter I2C_END_WR = 16'b1 << 6;
+ parameter I2C_RD_DATA = 16'b1 << 7;
+ parameter I2C_ACK_RD = 16'b1 << 8;
+ parameter I2C_END_RD = 16'b1 << 9;
+ parameter I2C_END_RD2 = 16'b1 << 10;
+ parameter I2C_WAITSTOP = 16'b1 << 11;
+ parameter I2C_RXD_SYN = 16'b1 << 12;
+ parameter I2C_RXD_ACK = 16'b1 << 13;
+ parameter I2C_TXD_SYN = 16'b1 << 14;
+ parameter I2C_TXD_ACK = 16'b1 << 15;
+
+ parameter I2C_nSTATES = 16;
+
+ reg [(I2C_nSTATES-1):0] I2C_cstate = {{(I2C_nSTATES-1){1'b0}}, 1'b1}; //current and next states
+ reg [(I2C_nSTATES-1):0] I2C_nstate;
+
+//`define SIMULATION
+`ifdef SIMULATION
+ // synthesis translate_off
+ reg [8*20:1] I2C_state_ascii = "I2C_START ";
+ always @(I2C_cstate) begin
+ if (I2C_cstate == I2C_START) I2C_state_ascii <= "I2C_START ";
+ else if (I2C_cstate == I2C_RESTART) I2C_state_ascii <= "I2C_RESTART ";
+ else if (I2C_cstate == I2C_DADDR) I2C_state_ascii <= "I2C_DADDR ";
+ else if (I2C_cstate == I2C_ACK_DADDR) I2C_state_ascii <= "I2C_ACK_DADDR ";
+ else if (I2C_cstate == I2C_WR_DATA) I2C_state_ascii <= "I2C_WR_DATA ";
+ else if (I2C_cstate == I2C_ACK_WR) I2C_state_ascii <= "I2C_ACK_WR ";
+ else if (I2C_cstate == I2C_END_WR) I2C_state_ascii <= "I2C_END_WR ";
+ else if (I2C_cstate == I2C_RD_DATA) I2C_state_ascii <= "I2C_RD_DATA ";
+ else if (I2C_cstate == I2C_ACK_RD) I2C_state_ascii <= "I2C_ACK_RD ";
+ else if (I2C_cstate == I2C_END_RD) I2C_state_ascii <= "I2C_END_RD ";
+ else if (I2C_cstate == I2C_END_RD2) I2C_state_ascii <= "I2C_END_RD2 ";
+ else if (I2C_cstate == I2C_WAITSTOP) I2C_state_ascii <= "I2C_WAITSTOP ";
+ else if (I2C_cstate == I2C_RXD_SYN) I2C_state_ascii <= "I2C_RXD_SYN ";
+ else if (I2C_cstate == I2C_RXD_ACK) I2C_state_ascii <= "I2C_RXD_ACK ";
+ else if (I2C_cstate == I2C_TXD_SYN) I2C_state_ascii <= "I2C_TXD_SYN ";
+ else if (I2C_cstate == I2C_TXD_ACK) I2C_state_ascii <= "I2C_TXD_ACK ";
+ else I2C_state_ascii <= "WTF ";
+ end
+ // synthesis translate_on
+`endif
+
+ reg [3:0] I2C_bitcnt;
+ reg [7:0] I2C_daddr;
+ reg [7:0] I2C_wdata;
+ reg [7:0] I2C_rdata;
+
+ reg rxd_syn_reg;
+ reg txd_ack_reg;
+
+ assign rxd_data = I2C_wdata;
+ assign rxd_syn = rxd_syn_reg;
+ assign txd_ack = txd_ack_reg;
+
+ assign i2c_device_addr = I2C_daddr[7:1];
+
+
+ ////////// code begins here
+ always @ (posedge clk) begin
+ if (reset || ((SCL_cstate == SCL_HIGH) && (SDA_cstate == SDA_RISE))) // stop condition always resets
+ I2C_cstate <= I2C_START;
+ else
+ I2C_cstate <= I2C_nstate;
+ end
+
+ always @ (*) begin
+ case (I2C_cstate) //synthesis parallel_case full_case
+ I2C_START: begin // wait for the start condition
+ I2C_nstate = ((SDA_cstate == SDA_FALL) && (SCL_cstate == SCL_HIGH)) ? I2C_DADDR : I2C_START;
+ end
+ I2C_RESTART: begin // repeated start moves immediately to DADDR
+ I2C_nstate = I2C_DADDR;
+ end
+
+ // device address branch
+ I2C_DADDR: begin // 8 bits to get the address
+ I2C_nstate = ((I2C_bitcnt > 4'h7) && (SCL_cstate == SCL_FALL)) ? I2C_ACK_DADDR : I2C_DADDR;
+ end
+ I2C_ACK_DADDR: begin // depending upon W/R bit state, go to one of two branches
+ I2C_nstate = (SCL_cstate == SCL_FALL) ?
+ ((I2C_daddr[7:1] >= i2c_addr_low) &&
+ (I2C_daddr[7:1] <= i2c_addr_high)) ?
+ (I2C_daddr[0] == 1'b0 ? I2C_WR_DATA : I2C_TXD_SYN) :
+ I2C_WAITSTOP : // !I2C_daddr match
+ I2C_ACK_DADDR; // !SCL_FALL
+ end
+
+ // write branch
+ I2C_WR_DATA: begin // 8 bits to get the write data
+ I2C_nstate = ((SDA_cstate == SDA_FALL) && (SCL_cstate == SCL_HIGH)) ? I2C_RESTART : // repeated start
+ ((I2C_bitcnt > 4'h7) && (SCL_cstate == SCL_FALL)) ? I2C_RXD_SYN : I2C_WR_DATA;
+ end
+ I2C_RXD_SYN: begin // put data on the coretest bus
+ I2C_nstate = I2C_RXD_ACK;
+ end
+ I2C_RXD_ACK: begin // wait for coretest ack
+ I2C_nstate = rxd_ack ? I2C_ACK_WR : I2C_RXD_ACK;
+ end
+ I2C_ACK_WR: begin // trigger the ack response (pull SDA low until next falling edge)
+ // and stay in this state until the next falling edge of SCL
+ I2C_nstate = (SCL_cstate == SCL_FALL) ? I2C_END_WR : I2C_ACK_WR;
+ end
+ I2C_END_WR: begin // one-cycle state to update address+1, reset SDA pulldown
+ I2C_nstate = I2C_WR_DATA; // SCL is now low
+ end
+
+ // read branch
+ I2C_TXD_SYN: begin // get data from the coretest bus
+ // if data isn't available (txd_syn isn't asserted) by the time we
+ // get to this state, it probably never will be, so skip it
+ I2C_nstate = txd_syn ? I2C_TXD_ACK : I2C_RD_DATA;
+ end
+ I2C_TXD_ACK: begin // send coretest ack
+ // hold ack high until syn is lowered
+ I2C_nstate = txd_syn ? I2C_TXD_ACK : I2C_RD_DATA;
+ end
+ I2C_RD_DATA: begin // 8 bits to get the read data
+ I2C_nstate = ((SDA_cstate == SDA_FALL) && (SCL_cstate == SCL_HIGH)) ? I2C_RESTART : // repeated start
+ ((I2C_bitcnt > 4'h7) && (SCL_cstate == SCL_FALL)) ? I2C_ACK_RD : I2C_RD_DATA;
+ end
+ I2C_ACK_RD: begin // wait for an (n)ack response
+ // need to sample (n)ack on a rising edge
+ I2C_nstate = (SCL_cstate == SCL_RISE) ? I2C_END_RD : I2C_ACK_RD;
+ end
+ I2C_END_RD: begin // if nack, just go to start state (don't explicitly check stop event)
+ // single cycle state for adr+1 update
+ I2C_nstate = (SDA_cstate == SDA_LOW) ? I2C_END_RD2 : I2C_START;
+ end
+ I2C_END_RD2: begin // before entering I2C_RD_DATA, we need to have seen a falling edge.
+ I2C_nstate = (SCL_cstate == SCL_FALL) ? I2C_RD_DATA : I2C_END_RD2;
+ end
+
+ // we're not the addressed device, so we just idle until we see a stop
+ I2C_WAITSTOP: begin
+ I2C_nstate = (((SCL_cstate == SCL_HIGH) && (SDA_cstate == SDA_RISE))) ? // stop
+ I2C_START :
+ (((SCL_cstate == SCL_HIGH) && (SDA_cstate == SDA_FALL))) ? // or start
+ I2C_RESTART :
+ I2C_WAITSTOP;
+ end
+ endcase // case (cstate)
+ end
+
+ always @ (posedge clk) begin
+ if( reset ) begin
+ I2C_bitcnt <= 4'b0;
+ I2C_daddr <= 8'b0;
+ I2C_wdata <= 8'b0;
+ SDA_pd <= 1'b0;
+ I2C_rdata <= 8'b0;
+ end else begin
+ case (I2C_cstate) // synthesis parallel_case full_case
+ I2C_START: begin // everything in reset
+ I2C_bitcnt <= 4'b0;
+ I2C_daddr <= 8'b0;
+ I2C_wdata <= 8'b0;
+ I2C_rdata <= 8'b0;
+ SDA_pd <= 1'b0;
+ end
+
+ I2C_RESTART: begin
+ I2C_bitcnt <= 4'b0;
+ I2C_daddr <= 8'b0;
+ I2C_wdata <= 8'b0;
+ I2C_rdata <= 8'b0;
+ SDA_pd <= 1'b0;
+ end
+
+ // get my i2c device address (am I being talked to?)
+ I2C_DADDR: begin // shift in the address on rising edges of clock
+ if( SCL_cstate == SCL_RISE ) begin
+ I2C_bitcnt <= I2C_bitcnt + 4'b1;
+ I2C_daddr[7] <= I2C_daddr[6];
+ I2C_daddr[6] <= I2C_daddr[5];
+ I2C_daddr[5] <= I2C_daddr[4];
+ I2C_daddr[4] <= I2C_daddr[3];
+ I2C_daddr[3] <= I2C_daddr[2];
+ I2C_daddr[2] <= I2C_daddr[1];
+ I2C_daddr[1] <= I2C_daddr[0];
+ I2C_daddr[0] <= (SDA_cstate == SDA_HIGH) ? 1'b1 : 1'b0;
+ end else begin // we're oversampled so we need a hold-state gutter
+ I2C_bitcnt <= I2C_bitcnt;
+ I2C_daddr <= I2C_daddr;
+ end // else: !if( SCL_cstate == SCL_RISE )
+ SDA_pd <= 1'b0;
+ I2C_wdata <= 8'b0;
+ I2C_rdata <= 8'b0;
+ end // case: I2C_DADDR
+ I2C_ACK_DADDR: begin
+ SDA_pd <= 1'b1; // active pull down ACK
+ I2C_daddr <= I2C_daddr;
+ I2C_bitcnt <= 4'b0;
+ I2C_wdata <= 8'b0;
+ I2C_rdata <= 8'b0;
+ end
+
+ // write branch
+ I2C_WR_DATA: begin // shift in data on rising edges of clock
+ if( SCL_cstate == SCL_RISE ) begin
+ I2C_bitcnt <= I2C_bitcnt + 4'b1;
+ I2C_wdata[7] <= I2C_wdata[6];
+ I2C_wdata[6] <= I2C_wdata[5];
+ I2C_wdata[5] <= I2C_wdata[4];
+ I2C_wdata[4] <= I2C_wdata[3];
+ I2C_wdata[3] <= I2C_wdata[2];
+ I2C_wdata[2] <= I2C_wdata[1];
+ I2C_wdata[1] <= I2C_wdata[0];
+ I2C_wdata[0] <= (SDA_cstate == SDA_HIGH) ? 1'b1 : 1'b0;
+ end else begin
+ I2C_bitcnt <= I2C_bitcnt; // hold state gutter
+ I2C_wdata <= I2C_wdata;
+ end // else: !if( SCL_cstate == SCL_RISE )
+ SDA_pd <= 1'b0;
+ I2C_daddr <= I2C_daddr;
+ I2C_rdata <= I2C_rdata;
+ end // case: I2C_WR_DATA
+ I2C_RXD_SYN: begin // put data on the coretest bus and raise syn
+ rxd_syn_reg <= 1;
+ end
+ I2C_RXD_ACK: begin // wait for coretest ack
+ if (rxd_ack)
+ rxd_syn_reg <= 0;
+ end
+ I2C_ACK_WR: begin
+ SDA_pd <= 1'b1; // active pull down ACK
+ I2C_daddr <= I2C_daddr;
+ I2C_bitcnt <= 4'b0;
+ I2C_wdata <= I2C_wdata;
+ I2C_rdata <= I2C_rdata;
+ end
+ I2C_END_WR: begin
+ SDA_pd <= 1'b0; // let SDA rise (host may look for this to know ack is done
+ I2C_bitcnt <= 4'b0;
+ I2C_wdata <= 8'b0;
+ I2C_rdata <= I2C_rdata;
+ I2C_daddr <= I2C_daddr;
+ end
+
+ // read branch
+ I2C_TXD_SYN: begin // get data from the coretest bus
+ if (txd_syn) begin
+ I2C_rdata <= txd_data;
+ txd_ack_reg <= 1;
+ end
+ end
+ I2C_TXD_ACK: begin // send coretest ack
+ if (!txd_syn)
+ txd_ack_reg <= 0;
+ end
+ I2C_RD_DATA: begin // shift out data on falling edges of clock
+ SDA_pd <= I2C_rdata[7] ? 1'b0 : 1'b1;
+ if( SCL_cstate == SCL_RISE ) begin
+ I2C_bitcnt <= I2C_bitcnt + 4'b1;
+ end else begin
+ I2C_bitcnt <= I2C_bitcnt; // hold state gutter
+ end
+
+ if( SCL_cstate == SCL_FALL ) begin
+ I2C_rdata[7] <= I2C_rdata[6];
+ I2C_rdata[6] <= I2C_rdata[5];
+ I2C_rdata[5] <= I2C_rdata[4];
+ I2C_rdata[4] <= I2C_rdata[3];
+ I2C_rdata[3] <= I2C_rdata[2];
+ I2C_rdata[2] <= I2C_rdata[1];
+ I2C_rdata[1] <= I2C_rdata[0];
+ I2C_rdata[0] <= 1'b0;
+ end else begin
+ I2C_rdata <= I2C_rdata;
+ end // else: !if( SCL_cstate == SCL_RISE )
+ I2C_daddr <= I2C_daddr;
+ I2C_wdata <= I2C_wdata;
+ end // case: I2C_RD_DATA
+ I2C_ACK_RD: begin
+ SDA_pd <= 1'b0; // in ack state don't pull down, we are listening to host
+ I2C_daddr <= I2C_daddr;
+ I2C_bitcnt <= 4'b0;
+ I2C_rdata <= I2C_rdata;
+ I2C_wdata <= I2C_wdata;
+ end
+ I2C_END_RD: begin
+ SDA_pd <= 1'b0; // let SDA rise (host may look for this to know ack is done
+ I2C_daddr <= I2C_daddr;
+ I2C_bitcnt <= 4'b0;
+ I2C_rdata <= I2C_rdata;
+ I2C_wdata <= I2C_wdata;
+ end
+ I2C_END_RD2: begin
+ SDA_pd <= 1'b0;
+ I2C_daddr <= 8'b0;
+ I2C_bitcnt <= 4'b0;
+ I2C_rdata <= I2C_rdata;
+ I2C_wdata <= I2C_wdata;
+ end
+
+ I2C_WAITSTOP: begin
+ SDA_pd <= 1'b0;
+ I2C_daddr <= 8'b0;
+ I2C_bitcnt <= 4'b0;
+ I2C_rdata <= I2C_rdata;
+ I2C_wdata <= I2C_wdata;
+ end
+ endcase // case (cstate)
+ end // else: !if( reset )
+ end // always @ (posedge clk or posedge reset)
+
+
+ ///////////////////////////////////////////////////////////////
+ /////////// low level state machines //////////////////////////
+ ///////////////////////////////////////////////////////////////
+
+
+ ////////////////
+ ///// SCL low-level sampling state machine
+ ////////////////
+ parameter SCL_HIGH = 4'b1 << 0; // should only pass through this state for one cycle
+ parameter SCL_FALL = 4'b1 << 1;
+ parameter SCL_LOW = 4'b1 << 2;
+ parameter SCL_RISE = 4'b1 << 3;
+ parameter SCL_nSTATES = 4;
+
+ reg [(SCL_nSTATES-1):0] SCL_cstate = {{(SCL_nSTATES-1){1'b0}}, 1'b1}; //current and next states
+ reg [(SCL_nSTATES-1):0] SCL_nstate;
+
+//`define SIMULATION
+`ifdef SIMULATION
+ // synthesis translate_off
+ reg [8*20:1] SCL_state_ascii = "SCL_HIGH ";
+
+ always @(SCL_cstate) begin
+ if (SCL_cstate == SCL_HIGH) SCL_state_ascii <= "SCL_HIGH ";
+ else if (SCL_cstate == SCL_FALL) SCL_state_ascii <= "SCL_FALL ";
+ else if (SCL_cstate == SCL_LOW ) SCL_state_ascii <= "SCL_LOW ";
+ else if (SCL_cstate == SCL_RISE) SCL_state_ascii <= "SCL_RISE ";
+ else SCL_state_ascii <= "WTF ";
+ end
+ // synthesis translate_on
+`endif
+
+ reg [4:0] SCL_rfcnt;
+ reg SCL_s, SCL_sync;
+ reg SDA_s, SDA_sync;
+
+ always @ (posedge clk) begin
+ if (reset)
+ SCL_cstate <= SCL_HIGH; // always start here even if it's wrong -- easier to test
+ else
+ SCL_cstate <= SCL_nstate;
+ end
+
+ always @ (*) begin
+ case (SCL_cstate) //synthesis parallel_case full_case
+ SCL_HIGH: begin
+ SCL_nstate = ((SCL_rfcnt > TRF_CYCLES) && (SCL_sync == 1'b0)) ? SCL_FALL : SCL_HIGH;
+ end
+ SCL_FALL: begin
+ SCL_nstate = SCL_LOW;
+ end
+ SCL_LOW: begin
+ SCL_nstate = ((SCL_rfcnt > TRF_CYCLES) && (SCL_sync == 1'b1)) ? SCL_RISE : SCL_LOW;
+ end
+ SCL_RISE: begin
+ SCL_nstate = SCL_HIGH;
+ end
+ endcase // case (cstate)
+ end // always @ (*)
+
+ always @ (posedge clk) begin
+ if( reset ) begin
+ SCL_rfcnt <= 5'b0;
+ end else begin
+ case (SCL_cstate) // synthesis parallel_case full_case
+ SCL_HIGH: begin
+ if( SCL_sync == 1'b1 ) begin
+ SCL_rfcnt <= 5'b0;
+ end else begin
+ SCL_rfcnt <= SCL_rfcnt + 5'b1;
+ end
+ end
+ SCL_FALL: begin
+ SCL_rfcnt <= 5'b0;
+ end
+ SCL_LOW: begin
+ if( SCL_sync == 1'b0 ) begin
+ SCL_rfcnt <= 5'b0;
+ end else begin
+ SCL_rfcnt <= SCL_rfcnt + 5'b1;
+ end
+ end
+ SCL_RISE: begin
+ SCL_rfcnt <= 5'b0;
+ end
+ endcase // case (cstate)
+ end // else: !if( reset )
+ end // always @ (posedge clk or posedge reset)
+
+
+ ////////////////
+ ///// SDA low-level sampling state machine
+ ////////////////
+ parameter SDA_HIGH = 4'b1 << 0; // should only pass through this state for one cycle
+ parameter SDA_FALL = 4'b1 << 1;
+ parameter SDA_LOW = 4'b1 << 2;
+ parameter SDA_RISE = 4'b1 << 3;
+ parameter SDA_nSTATES = 4;
+
+ reg [(SDA_nSTATES-1):0] SDA_cstate = {{(SDA_nSTATES-1){1'b0}}, 1'b1}; //current and next states
+ reg [(SDA_nSTATES-1):0] SDA_nstate;
+
+//`define SIMULATION
+`ifdef SIMULATION
+ // synthesis translate_off
+ reg [8*20:1] SDA_state_ascii = "SDA_HIGH ";
+
+ always @(SDA_cstate) begin
+ if (SDA_cstate == SDA_HIGH) SDA_state_ascii <= "SDA_HIGH ";
+ else if (SDA_cstate == SDA_FALL) SDA_state_ascii <= "SDA_FALL ";
+ else if (SDA_cstate == SDA_LOW ) SDA_state_ascii <= "SDA_LOW ";
+ else if (SDA_cstate == SDA_RISE) SDA_state_ascii <= "SDA_RISE ";
+ else SDA_state_ascii <= "WTF ";
+ end
+ // synthesis translate_on
+`endif
+
+ reg [4:0] SDA_rfcnt;
+
+ always @ (posedge clk) begin
+ if (reset)
+ SDA_cstate <= SDA_HIGH; // always start here even if it's wrong -- easier to test
+ else
+ SDA_cstate <= SDA_nstate;
+ end
+
+ always @ (*) begin
+ case (SDA_cstate) //synthesis parallel_case full_case
+ SDA_HIGH: begin
+ SDA_nstate = ((SDA_rfcnt > TRF_CYCLES) && (SDA_sync == 1'b0)) ? SDA_FALL : SDA_HIGH;
+ end
+ SDA_FALL: begin
+ SDA_nstate = SDA_LOW;
+ end
+ SDA_LOW: begin
+ SDA_nstate = ((SDA_rfcnt > TRF_CYCLES) && (SDA_sync == 1'b1)) ? SDA_RISE : SDA_LOW;
+ end
+ SDA_RISE: begin
+ SDA_nstate = SDA_HIGH;
+ end
+ endcase // case (cstate)
+ end // always @ (*)
+
+ always @ (posedge clk) begin
+ if( reset ) begin
+ SDA_rfcnt <= 5'b0;
+ end else begin
+ case (SDA_cstate) // synthesis parallel_case full_case
+ SDA_HIGH: begin
+ if( SDA_sync == 1'b1 ) begin
+ SDA_rfcnt <= 5'b0;
+ end else begin
+ SDA_rfcnt <= SDA_rfcnt + 5'b1;
+ end
+ end
+ SDA_FALL: begin
+ SDA_rfcnt <= 5'b0;
+ end
+ SDA_LOW: begin
+ if( SDA_sync == 1'b0 ) begin
+ SDA_rfcnt <= 5'b0;
+ end else begin
+ SDA_rfcnt <= SDA_rfcnt + 5'b1;
+ end
+ end
+ SDA_RISE: begin
+ SDA_rfcnt <= 5'b0;
+ end
+ endcase // case (cstate)
+ end // else: !if( reset )
+ end // always @ (posedge clk or posedge reset)
+
+
+
+ /////////////////////
+ /////// synchronizers
+ /////////////////////
+ always @ (posedge clk) begin
+ SCL_s <= SCL;
+ SCL_sync <= SCL_s;
+ SDA_s <= SDA;
+ SDA_sync <= SDA_s;
+ end // always @ (posedge clk or posedge reset)
+
+endmodule // i2c_slave
diff --git a/src/rtl/novena_fpga.v b/src/rtl/novena_fpga.v
new file mode 100644
index 0000000..fd0f667
--- /dev/null
+++ b/src/rtl/novena_fpga.v
@@ -0,0 +1,147 @@
+//////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2013, Andrew "bunnie" Huang
+//
+// See the NOTICE file distributed with this work for additional
+// information regarding copyright ownership. The copyright holder
+// licenses this file to you under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// code distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//////////////////////////////////////////////////////////////////////////////
+
+/// note: must set "-g UnusedPin:Pullnone" to avoid conflicts with unused pins
+
+`timescale 1ns / 1ps
+
+module novena_fpga(
+ // CPU side mapping
+ input wire [15:0] EIM_DA,
+ output reg EIM_A16, // relay of the trigger output
+ output reg EIM_A17, // relay of the trigger data (read path)
+
+ // connector side mapping
+ //input wire F_LVDS_N3, // output of trigger
+ //input wire F_DX2, // output of trigger
+ //output wire F_LVDS_N5, // trigger reset
+ output wire F_LVDS_P4, // trigger reset
+ //inout wire F_LVDS_P5, // trigger data (bidir)
+ //input wire F_DX18, // trigger data in from sticker (DUT->CPU)
+ output wire F_LVDS_P11, // trigger data out to sticker (CPU->DUT)
+ //output wire F_LVDS_N8, // trigger clock
+ //output wire F_DX14, // trigger clock
+
+ output wire F_LVDS_N7, // drive TPI data line
+ output wire F_LVDS_P7, // drive TPI signal lines
+
+ output wire F_DX15, // 1 = drive 5V, 0 = drive 3V to DUT
+
+ output wire F_LVDS_CK1_N,
+ output wire F_LVDS_CK1_P,
+ output wire F_LVDS_N11,
+
+ output wire F_LVDS_N0,
+ output wire F_LVDS_P0,
+ output wire F_DX1,
+
+ output wire F_LVDS_N15,
+ output wire F_LVDS_P15,
+ output wire F_LVDS_NC,
+
+ //input wire F_DX11,
+ //input wire F_DX3,
+ //input wire F_DX0,
+
+ //input wire F_LVDS_CK0_P,
+ //input wire F_LVDS_CK0_N,
+ //input wire F_LVDS_P9,
+
+ //input wire [1:0] EIM_CS,
+ //input wire EIM_LBA,
+
+ input wire CLK2_N,
+ input wire CLK2_P,
+ output wire FPGA_LED2,
+
+ input wire I2C3_SCL,
+ inout wire I2C3_SDA,
+
+ input wire RESETBMCU,
+ output wire F_DX17, // dummy
+ output wire APOPTOSIS
+);
+ wire clk;
+
+ IBUFGDS clkibufgds(
+ .I(CLK2_P),
+ .IB(CLK2_N),
+ .O(clk)
+ );
+
+ assign FPGA_LED2 = 1'b1;
+
+ assign APOPTOSIS = 1'b0;
+ assign F_DX15 = 1'b1; //+5V P_DUT
+
+ // OE on bank to drive signals; signal not inverted in software
+ assign F_LVDS_P7 = !EIM_DA[3];
+ // OE on bank to drive the data; signal not inverted in software
+ assign F_LVDS_N7 = !EIM_DA[4];
+ assign F_LVDS_P4 = 1'b0;
+ assign F_LVDS_P11 = 1'b0;
+ assign F_LVDS_CK1_N = 1'b0;
+ assign F_LVDS_CK1_P = 1'b0;
+ assign F_LVDS_N11 = 1'b0;
+ assign F_LVDS_N0 = 1'b0;
+ assign F_LVDS_P0 = 1'b0;
+ assign F_DX1 = 1'b0;
+ assign F_LVDS_N15 = 1'b0;
+ assign F_LVDS_P15 = 1'b0;
+ assign F_LVDS_NC = 1'b0;
+
+ // reduction and of EIM_DA, dummy-map to keep compiler quiet
+ assign F_DX17 = &EIM_DA | RESETBMCU;
+
+ ////////////////////////////////////
+ ///// I2C register set
+ ////////////////////////////////////
+ wire SDA_pd;
+ wire SDA_int;
+ reg clk25;
+
+ initial begin
+ clk25 <= 1'b0;
+ end
+ always @ (posedge clk) begin
+ clk25 <= ~clk25;
+ EIM_A16 <= 1'b0;
+ EIM_A17 <= 1'b0;
+ end
+
+ IOBUF #(
+ .DRIVE(8),
+ .SLEW("SLOW")
+ ) IOBUF_sda (
+ .IO(I2C3_SDA),
+ .I(1'b0),
+ .T(!SDA_pd),
+ .O(SDA_int)
+ );
+
+ coretest_hashes top(
+ .clk(clk25),
+ .reset_n(1'b1),
+
+ .SCL(I2C3_SCL),
+ .SDA(SDA_int),
+ .SDA_pd(SDA_pd)
+ );
+
+endmodule
diff --git a/src/rtl/sha1.v b/src/rtl/sha1.v
new file mode 100644
index 0000000..2bf0de7
--- /dev/null
+++ b/src/rtl/sha1.v
@@ -0,0 +1,421 @@
+//======================================================================
+//
+// sha1.v
+// ------
+// Top level wrapper for the SHA-1 hash function providing
+// a simple write()/read() interface with 8 bit data access.
+//
+//
+// Authors: Joachim Strombergson, Paul Selkirk
+// Copyright (c) 2014, SUNET
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or
+// without modification, are permitted provided that the following
+// conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in
+// the documentation and/or other materials provided with the
+// distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module sha1(
+ // Clock and reset.
+ input wire clk,
+ input wire reset_n,
+
+ // Interface to communication core
+ input wire rx_syn,
+ input wire [7 : 0] rx_data,
+ output wire rx_ack,
+
+ output wire tx_syn,
+ output wire [7 : 0] tx_data,
+ input wire tx_ack
+ );
+
+ //----------------------------------------------------------------
+ // Internal constant and parameter definitions.
+ //----------------------------------------------------------------
+ parameter RX_INIT = 0;
+ parameter RX_SYN = 1;
+ parameter RX_ACK = 2;
+ parameter RX_WAIT = 3;
+
+ parameter TX_INIT = 0;
+ parameter TX_SYN = 1;
+ parameter TX_ACK = 2;
+
+ parameter BLOCK_BITS = 512;
+ parameter BLOCK_BYTES = BLOCK_BITS / 8;
+ parameter DIGEST_BITS = 160;
+ parameter DIGEST_BYTES = DIGEST_BITS / 8;
+
+ //----------------------------------------------------------------
+ // Registers including update variables and write enable.
+ //----------------------------------------------------------------
+ reg rx_ack_reg;
+ reg rx_ack_new;
+ reg rx_ack_we;
+
+ reg [6 : 0] rx_ptr_reg;
+ reg [7 : 0] rx_ptr_new;
+ reg rx_ptr_we;
+
+ reg [1 : 0] rx_ctrl_reg;
+ reg [1 : 0] rx_ctrl_new;
+ reg rx_ctrl_we;
+
+ reg [7 : 0] block_reg [0 : BLOCK_BYTES - 1];
+ reg [7 : 0] block_new;
+ reg block_we;
+
+ reg init_reg;
+ reg init_new;
+ reg init_we;
+
+ reg next_reg;
+ reg next_new;
+ reg next_we;
+
+ reg initnext_reg;
+ reg initnext_new;
+ reg initnext_we;
+
+ reg tx_syn_reg;
+ reg tx_syn_new;
+ reg tx_syn_we;
+
+ reg [6 : 0] tx_ptr_reg;
+ reg [7 : 0] tx_ptr_new;
+ reg tx_ptr_we;
+
+ reg [1 : 0] tx_ctrl_reg;
+ reg [1 : 0] tx_ctrl_new;
+ reg tx_ctrl_we;
+
+ reg tx_active_reg;
+ reg tx_active_new;
+ reg tx_active_we;
+
+ wire [7 : 0] digest_reg [0 : DIGEST_BYTES - 1];
+
+ //----------------------------------------------------------------
+ // Wires.
+ //----------------------------------------------------------------
+ wire core_init;
+ wire core_next;
+ wire core_ready;
+ wire [BLOCK_BITS - 1 : 0] core_block;
+ wire [DIGEST_BITS - 1 : 0] core_digest;
+ wire core_digest_valid;
+
+ //----------------------------------------------------------------
+ // Concurrent connectivity for ports etc.
+ //----------------------------------------------------------------
+ assign core_init = init_reg;
+ assign core_next = next_reg;
+ assign core_block = {block_reg[0], block_reg[1], block_reg[2], block_reg[3],
+ block_reg[4], block_reg[5], block_reg[6], block_reg[7],
+ block_reg[8], block_reg[9], block_reg[10], block_reg[11],
+ block_reg[12], block_reg[13], block_reg[14], block_reg[15],
+ block_reg[16], block_reg[17], block_reg[18], block_reg[19],
+ block_reg[20], block_reg[21], block_reg[22], block_reg[23],
+ block_reg[24], block_reg[25], block_reg[26], block_reg[27],
+ block_reg[28], block_reg[29], block_reg[30], block_reg[31],
+ block_reg[32], block_reg[33], block_reg[34], block_reg[35],
+ block_reg[36], block_reg[37], block_reg[38], block_reg[39],
+ block_reg[40], block_reg[41], block_reg[42], block_reg[43],
+ block_reg[44], block_reg[45], block_reg[46], block_reg[47],
+ block_reg[48], block_reg[49], block_reg[50], block_reg[51],
+ block_reg[52], block_reg[53], block_reg[54], block_reg[55],
+ block_reg[56], block_reg[57], block_reg[58], block_reg[59],
+ block_reg[60], block_reg[61], block_reg[62], block_reg[63]};
+
+ assign rx_ack = rx_ack_reg;
+ assign tx_syn = tx_syn_reg;
+ assign tx_data = digest_reg[tx_ptr_reg];
+
+ assign digest_reg[0] = core_digest[159 : 152];
+ assign digest_reg[1] = core_digest[151 : 144];
+ assign digest_reg[2] = core_digest[143 : 136];
+ assign digest_reg[3] = core_digest[135 : 128];
+ assign digest_reg[4] = core_digest[127 : 120];
+ assign digest_reg[5] = core_digest[119 : 112];
+ assign digest_reg[6] = core_digest[111 : 104];
+ assign digest_reg[7] = core_digest[103 : 96];
+ assign digest_reg[8] = core_digest[95 : 88];
+ assign digest_reg[9] = core_digest[87 : 80];
+ assign digest_reg[10] = core_digest[79 : 72];
+ assign digest_reg[11] = core_digest[71 : 64];
+ assign digest_reg[12] = core_digest[63 : 56];
+ assign digest_reg[13] = core_digest[55 : 48];
+ assign digest_reg[14] = core_digest[47 : 40];
+ assign digest_reg[15] = core_digest[39 : 32];
+ assign digest_reg[16] = core_digest[31 : 24];
+ assign digest_reg[17] = core_digest[23 : 16];
+ assign digest_reg[18] = core_digest[15 : 8];
+ assign digest_reg[19] = core_digest[7 : 0];
+
+ //----------------------------------------------------------------
+ // core instantiation.
+ //----------------------------------------------------------------
+ sha1_core core(
+ .clk(clk),
+ .reset_n(reset_n),
+
+ .init(core_init),
+ .next(core_next),
+
+ .block(core_block),
+
+ .ready(core_ready),
+
+ .digest(core_digest),
+ .digest_valid(core_digest_valid)
+ );
+
+ //----------------------------------------------------------------
+ // reg_update
+ // Update functionality for all registers in the core.
+ // All registers are positive edge triggered with synchronous
+ // active low reset. All registers have write enable.
+ //----------------------------------------------------------------
+
+ always @ (posedge clk)
+ begin: reg_update
+ if (!reset_n)
+ begin: reset_reg
+ reg[7:0] i;
+ for (i = 0; i < BLOCK_BYTES; i = i + 1)
+ block_reg[i] <= 0;
+ rx_ack_reg <= 0;
+ rx_ptr_reg <= 0;
+ rx_ctrl_reg <= RX_INIT;
+ tx_syn_reg <= 0;
+ tx_ptr_reg <= 0;
+ tx_ctrl_reg <= TX_INIT;
+ initnext_reg <= 0;
+ end
+ else
+ begin
+ if (rx_ack_we)
+ begin
+ rx_ack_reg <= rx_ack_new;
+ end
+
+ if (rx_ptr_we)
+ begin
+ rx_ptr_reg <= rx_ptr_new[6:0];
+ end
+
+ if (rx_ctrl_we)
+ begin
+ rx_ctrl_reg <= rx_ctrl_new;
+ end
+
+ if (block_we)
+ begin
+ block_reg[rx_ptr_reg] <= block_new;
+ end
+
+ if (init_we)
+ begin
+ init_reg <= init_new;
+ end
+
+ if (next_we)
+ begin
+ next_reg <= next_new;
+ end
+
+ if (initnext_we)
+ begin
+ initnext_reg <= initnext_new;
+ end
+
+ if (tx_syn_we)
+ begin
+ tx_syn_reg <= tx_syn_new;
+ end
+
+ if (tx_ptr_we)
+ begin
+ tx_ptr_reg <= tx_ptr_new[6:0];
+ end
+
+ if (tx_ctrl_we)
+ begin
+ tx_ctrl_reg <= tx_ctrl_new;
+ end
+
+ if (tx_active_we)
+ begin
+ tx_active_reg <= tx_active_new;
+ end
+ end
+ end // reg_update
+
+ //----------------------------------------------------------------
+ // rx_engine
+ //----------------------------------------------------------------
+ always @*
+ begin: rx_engine
+ rx_ack_new = 0;
+ rx_ack_we = 0;
+ rx_ptr_new = 0;
+ rx_ptr_we = 0;
+ rx_ctrl_new = 0;
+ rx_ctrl_we = 0;
+ block_new = 0;
+ block_we = 0;
+ init_new = 0;
+ init_we = 0;
+ next_new = 0;
+ next_we = 0;
+ initnext_new = 0;
+ initnext_we = 0;
+
+ if (tx_active_reg)
+ begin
+ initnext_we = 1;
+ end
+
+ case (rx_ctrl_reg)
+ RX_INIT:
+ if (core_ready)
+ begin
+ rx_ctrl_new = RX_SYN;
+ rx_ctrl_we = 1;
+ end
+ RX_SYN:
+ if (rx_syn)
+ begin
+ rx_ack_new = 1;
+ rx_ack_we = 1;
+ block_new = rx_data;
+ block_we = 1;
+ rx_ctrl_new = RX_ACK;
+ rx_ctrl_we = 1;
+ end
+ RX_ACK:
+ if (!rx_syn)
+ begin
+ rx_ack_new = 0;
+ rx_ack_we = 1;
+ rx_ptr_new = rx_ptr_reg + 1;
+ rx_ptr_we = 1;
+ rx_ctrl_new = RX_SYN;
+ rx_ctrl_we = 1;
+ if (rx_ptr_new == BLOCK_BYTES)
+ begin
+ rx_ptr_new = 0;
+ rx_ctrl_new = RX_WAIT;
+ if (initnext_reg == 0)
+ begin
+ init_new = 1;
+ init_we = 1;
+ initnext_new = 1;
+ initnext_we = 1;
+ end
+ else
+ begin
+ next_new = 1;
+ next_we = 1;
+ end
+ end
+ end
+ RX_WAIT:
+ if (!core_ready)
+ begin
+ init_new = 0;
+ init_we = 1;
+ next_new = 0;
+ next_we = 1;
+ rx_ctrl_new = RX_INIT;
+ rx_ctrl_we = 1;
+ end
+ endcase // case (rx_ctrl_reg)
+ end // rx_engine
+
+ //----------------------------------------------------------------
+ // tx_engine
+ //----------------------------------------------------------------
+ always @*
+ begin: tx_engine
+ tx_syn_new = 0;
+ tx_syn_we = 0;
+ tx_ptr_new = 0;
+ tx_ptr_we = 0;
+ tx_ctrl_new = 0;
+ tx_ctrl_we = 0;
+ tx_active_new = 0;
+ tx_active_we = 0;
+
+ case (tx_ctrl_reg)
+ TX_INIT:
+ if (core_digest_valid)
+ begin
+ tx_ctrl_new = TX_SYN;
+ tx_ctrl_we = 1;
+ end
+ TX_SYN:
+ begin
+ tx_syn_new = 1;
+ tx_syn_we = 1;
+ tx_ctrl_new = TX_ACK;
+ tx_ctrl_we = 1;
+ end
+ TX_ACK:
+ if (!core_digest_valid)
+ begin
+ tx_syn_new = 0;
+ tx_syn_we = 1;
+ tx_ptr_new = 0;
+ tx_ptr_we = 1;
+ tx_ctrl_new = TX_INIT;
+ tx_ctrl_we = 1;
+ end
+ else if (tx_ack)
+ begin
+ tx_active_new = 1;
+ tx_active_we = 1;
+ tx_syn_new = 0;
+ tx_syn_we = 1;
+ tx_ptr_new = tx_ptr_reg + 1;
+ tx_ptr_we = 1;
+ tx_ctrl_new = TX_SYN;
+ tx_ctrl_we = 1;
+ if (tx_ptr_new == DIGEST_BYTES)
+ begin
+ tx_active_new = 0;
+ tx_ptr_new = 0;
+ tx_ctrl_new = TX_INIT;
+ end
+ end
+ endcase // case (tx_ctrl_reg)
+ end // tx_engine
+
+endmodule // sha1
+
+//======================================================================
+// EOF sha1.v
+//======================================================================
diff --git a/src/rtl/sha256.v b/src/rtl/sha256.v
new file mode 100644
index 0000000..d28a914
--- /dev/null
+++ b/src/rtl/sha256.v
@@ -0,0 +1,433 @@
+//======================================================================
+//
+// sha256.v
+// --------
+// Top level wrapper for the SHA-256 hash function providing
+// a simple write()/read() interface with 8 bit data access.
+//
+//
+// Authors: Joachim Strombergson, Paul Selkirk
+// Copyright (c) 2014, SUNET
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or
+// without modification, are permitted provided that the following
+// conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in
+// the documentation and/or other materials provided with the
+// distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module sha256(
+ // Clock and reset.
+ input wire clk,
+ input wire reset_n,
+
+ // Interface to communication core
+ input wire rx_syn,
+ input wire [7 : 0] rx_data,
+ output wire rx_ack,
+
+ output wire tx_syn,
+ output wire [7 : 0] tx_data,
+ input wire tx_ack
+ );
+
+ //----------------------------------------------------------------
+ // Internal constant and parameter definitions.
+ //----------------------------------------------------------------
+ parameter RX_INIT = 0;
+ parameter RX_SYN = 1;
+ parameter RX_ACK = 2;
+ parameter RX_WAIT = 3;
+
+ parameter TX_INIT = 0;
+ parameter TX_SYN = 1;
+ parameter TX_ACK = 2;
+
+ parameter BLOCK_BITS = 512;
+ parameter BLOCK_BYTES = BLOCK_BITS / 8;
+ parameter DIGEST_BITS = 256;
+ parameter DIGEST_BYTES = DIGEST_BITS / 8;
+
+ //----------------------------------------------------------------
+ // Registers including update variables and write enable.
+ //----------------------------------------------------------------
+ reg rx_ack_reg;
+ reg rx_ack_new;
+ reg rx_ack_we;
+
+ reg [6 : 0] rx_ptr_reg;
+ reg [7 : 0] rx_ptr_new;
+ reg rx_ptr_we;
+
+ reg [1 : 0] rx_ctrl_reg;
+ reg [1 : 0] rx_ctrl_new;
+ reg rx_ctrl_we;
+
+ reg [7 : 0] block_reg [0 : BLOCK_BYTES - 1];
+ reg [7 : 0] block_new;
+ reg block_we;
+
+ reg init_reg;
+ reg init_new;
+ reg init_we;
+
+ reg next_reg;
+ reg next_new;
+ reg next_we;
+
+ reg initnext_reg;
+ reg initnext_new;
+ reg initnext_we;
+
+ reg tx_syn_reg;
+ reg tx_syn_new;
+ reg tx_syn_we;
+
+ reg [6 : 0] tx_ptr_reg;
+ reg [7 : 0] tx_ptr_new;
+ reg tx_ptr_we;
+
+ reg [1 : 0] tx_ctrl_reg;
+ reg [1 : 0] tx_ctrl_new;
+ reg tx_ctrl_we;
+
+ reg tx_active_reg;
+ reg tx_active_new;
+ reg tx_active_we;
+
+ wire [7 : 0] digest_reg [0 : DIGEST_BYTES - 1];
+
+ //----------------------------------------------------------------
+ // Wires.
+ //----------------------------------------------------------------
+ wire core_init;
+ wire core_next;
+ wire core_ready;
+ wire [BLOCK_BITS - 1 : 0] core_block;
+ wire [DIGEST_BITS - 1 : 0] core_digest;
+ wire core_digest_valid;
+
+ //----------------------------------------------------------------
+ // Concurrent connectivity for ports etc.
+ //----------------------------------------------------------------
+ assign core_init = init_reg;
+ assign core_next = next_reg;
+ assign core_block = {block_reg[0], block_reg[1], block_reg[2], block_reg[3],
+ block_reg[4], block_reg[5], block_reg[6], block_reg[7],
+ block_reg[8], block_reg[9], block_reg[10], block_reg[11],
+ block_reg[12], block_reg[13], block_reg[14], block_reg[15],
+ block_reg[16], block_reg[17], block_reg[18], block_reg[19],
+ block_reg[20], block_reg[21], block_reg[22], block_reg[23],
+ block_reg[24], block_reg[25], block_reg[26], block_reg[27],
+ block_reg[28], block_reg[29], block_reg[30], block_reg[31],
+ block_reg[32], block_reg[33], block_reg[34], block_reg[35],
+ block_reg[36], block_reg[37], block_reg[38], block_reg[39],
+ block_reg[40], block_reg[41], block_reg[42], block_reg[43],
+ block_reg[44], block_reg[45], block_reg[46], block_reg[47],
+ block_reg[48], block_reg[49], block_reg[50], block_reg[51],
+ block_reg[52], block_reg[53], block_reg[54], block_reg[55],
+ block_reg[56], block_reg[57], block_reg[58], block_reg[59],
+ block_reg[60], block_reg[61], block_reg[62], block_reg[63]};
+
+ assign rx_ack = rx_ack_reg;
+ assign tx_syn = tx_syn_reg;
+ assign tx_data = digest_reg[tx_ptr_reg];
+
+ assign digest_reg[0] = core_digest[255 : 248];
+ assign digest_reg[1] = core_digest[247 : 240];
+ assign digest_reg[2] = core_digest[239 : 232];
+ assign digest_reg[3] = core_digest[231 : 224];
+ assign digest_reg[4] = core_digest[223 : 216];
+ assign digest_reg[5] = core_digest[215 : 208];
+ assign digest_reg[6] = core_digest[207 : 200];
+ assign digest_reg[7] = core_digest[199 : 192];
+ assign digest_reg[8] = core_digest[191 : 184];
+ assign digest_reg[9] = core_digest[183 : 176];
+ assign digest_reg[10] = core_digest[175 : 168];
+ assign digest_reg[11] = core_digest[167 : 160];
+ assign digest_reg[12] = core_digest[159 : 152];
+ assign digest_reg[13] = core_digest[151 : 144];
+ assign digest_reg[14] = core_digest[143 : 136];
+ assign digest_reg[15] = core_digest[135 : 128];
+ assign digest_reg[16] = core_digest[127 : 120];
+ assign digest_reg[17] = core_digest[119 : 112];
+ assign digest_reg[18] = core_digest[111 : 104];
+ assign digest_reg[19] = core_digest[103 : 96];
+ assign digest_reg[20] = core_digest[95 : 88];
+ assign digest_reg[21] = core_digest[87 : 80];
+ assign digest_reg[22] = core_digest[79 : 72];
+ assign digest_reg[23] = core_digest[71 : 64];
+ assign digest_reg[24] = core_digest[63 : 56];
+ assign digest_reg[25] = core_digest[55 : 48];
+ assign digest_reg[26] = core_digest[47 : 40];
+ assign digest_reg[27] = core_digest[39 : 32];
+ assign digest_reg[28] = core_digest[31 : 24];
+ assign digest_reg[29] = core_digest[23 : 16];
+ assign digest_reg[30] = core_digest[15 : 8];
+ assign digest_reg[31] = core_digest[7 : 0];
+
+ //----------------------------------------------------------------
+ // core instantiation.
+ //----------------------------------------------------------------
+ sha256_core core(
+ .clk(clk),
+ .reset_n(reset_n),
+
+ .init(core_init),
+ .next(core_next),
+
+ .block(core_block),
+
+ .ready(core_ready),
+
+ .digest(core_digest),
+ .digest_valid(core_digest_valid)
+ );
+
+ //----------------------------------------------------------------
+ // reg_update
+ // Update functionality for all registers in the core.
+ // All registers are positive edge triggered with synchronous
+ // active low reset. All registers have write enable.
+ //----------------------------------------------------------------
+
+ always @ (posedge clk)
+ begin: reg_update
+ if (!reset_n)
+ begin: reset_reg
+ reg[7:0] i;
+ for (i = 0; i < BLOCK_BYTES; i = i + 1)
+ block_reg[i] <= 0;
+ rx_ack_reg <= 0;
+ rx_ptr_reg <= 0;
+ rx_ctrl_reg <= RX_INIT;
+ tx_syn_reg <= 0;
+ tx_ptr_reg <= 0;
+ tx_ctrl_reg <= TX_INIT;
+ initnext_reg <= 0;
+ end
+ else
+ begin
+ if (rx_ack_we)
+ begin
+ rx_ack_reg <= rx_ack_new;
+ end
+
+ if (rx_ptr_we)
+ begin
+ rx_ptr_reg <= rx_ptr_new[6:0];
+ end
+
+ if (rx_ctrl_we)
+ begin
+ rx_ctrl_reg <= rx_ctrl_new;
+ end
+
+ if (block_we)
+ begin
+ block_reg[rx_ptr_reg] <= block_new;
+ end
+
+ if (init_we)
+ begin
+ init_reg <= init_new;
+ end
+
+ if (next_we)
+ begin
+ next_reg <= next_new;
+ end
+
+ if (initnext_we)
+ begin
+ initnext_reg <= initnext_new;
+ end
+
+ if (tx_syn_we)
+ begin
+ tx_syn_reg <= tx_syn_new;
+ end
+
+ if (tx_ptr_we)
+ begin
+ tx_ptr_reg <= tx_ptr_new[6:0];
+ end
+
+ if (tx_ctrl_we)
+ begin
+ tx_ctrl_reg <= tx_ctrl_new;
+ end
+
+ if (tx_active_we)
+ begin
+ tx_active_reg <= tx_active_new;
+ end
+ end
+ end // reg_update
+
+ //----------------------------------------------------------------
+ // rx_engine
+ //----------------------------------------------------------------
+ always @*
+ begin: rx_engine
+ rx_ack_new = 0;
+ rx_ack_we = 0;
+ rx_ptr_new = 0;
+ rx_ptr_we = 0;
+ rx_ctrl_new = 0;
+ rx_ctrl_we = 0;
+ block_new = 0;
+ block_we = 0;
+ init_new = 0;
+ init_we = 0;
+ next_new = 0;
+ next_we = 0;
+ initnext_new = 0;
+ initnext_we = 0;
+
+ if (tx_active_reg)
+ begin
+ initnext_we = 1;
+ end
+
+ case (rx_ctrl_reg)
+ RX_INIT:
+ if (core_ready)
+ begin
+ rx_ctrl_new = RX_SYN;
+ rx_ctrl_we = 1;
+ end
+ RX_SYN:
+ if (rx_syn)
+ begin
+ rx_ack_new = 1;
+ rx_ack_we = 1;
+ block_new = rx_data;
+ block_we = 1;
+ rx_ctrl_new = RX_ACK;
+ rx_ctrl_we = 1;
+ end
+ RX_ACK:
+ if (!rx_syn)
+ begin
+ rx_ack_new = 0;
+ rx_ack_we = 1;
+ rx_ptr_new = rx_ptr_reg + 1;
+ rx_ptr_we = 1;
+ rx_ctrl_new = RX_SYN;
+ rx_ctrl_we = 1;
+ if (rx_ptr_new == BLOCK_BYTES)
+ begin
+ rx_ptr_new = 0;
+ rx_ctrl_new = RX_WAIT;
+ if (initnext_reg == 0)
+ begin
+ init_new = 1;
+ init_we = 1;
+ initnext_new = 1;
+ initnext_we = 1;
+ end
+ else
+ begin
+ next_new = 1;
+ next_we = 1;
+ end
+ end
+ end
+ RX_WAIT:
+ if (!core_ready)
+ begin
+ init_new = 0;
+ init_we = 1;
+ next_new = 0;
+ next_we = 1;
+ rx_ctrl_new = RX_INIT;
+ rx_ctrl_we = 1;
+ end
+ endcase // case (rx_ctrl_reg)
+ end // rx_engine
+
+ //----------------------------------------------------------------
+ // tx_engine
+ //----------------------------------------------------------------
+ always @*
+ begin: tx_engine
+ tx_syn_new = 0;
+ tx_syn_we = 0;
+ tx_ptr_new = 0;
+ tx_ptr_we = 0;
+ tx_ctrl_new = 0;
+ tx_ctrl_we = 0;
+ tx_active_new = 0;
+ tx_active_we = 0;
+
+ case (tx_ctrl_reg)
+ TX_INIT:
+ if (core_digest_valid)
+ begin
+ tx_ctrl_new = TX_SYN;
+ tx_ctrl_we = 1;
+ end
+ TX_SYN:
+ begin
+ tx_syn_new = 1;
+ tx_syn_we = 1;
+ tx_ctrl_new = TX_ACK;
+ tx_ctrl_we = 1;
+ end
+ TX_ACK:
+ if (!core_digest_valid)
+ begin
+ tx_syn_new = 0;
+ tx_syn_we = 1;
+ tx_ptr_new = 0;
+ tx_ptr_we = 1;
+ tx_ctrl_new = TX_INIT;
+ tx_ctrl_we = 1;
+ end
+ else if (tx_ack)
+ begin
+ tx_active_new = 1;
+ tx_active_we = 1;
+ tx_syn_new = 0;
+ tx_syn_we = 1;
+ tx_ptr_new = tx_ptr_reg + 1;
+ tx_ptr_we = 1;
+ tx_ctrl_new = TX_SYN;
+ tx_ctrl_we = 1;
+ if (tx_ptr_new == DIGEST_BYTES)
+ begin
+ tx_active_new = 0;
+ tx_ptr_new = 0;
+ tx_ctrl_new = TX_INIT;
+ end
+ end
+ endcase // case (tx_ctrl_reg)
+ end // tx_engine
+
+endmodule // sha256
+
+//======================================================================
+// EOF sha256.v
+//======================================================================
diff --git a/src/rtl/sha512.v b/src/rtl/sha512.v
new file mode 100644
index 0000000..9e9b3d5
--- /dev/null
+++ b/src/rtl/sha512.v
@@ -0,0 +1,497 @@
+//======================================================================
+//
+// sha512.v
+// --------
+// Top level wrapper for the SHA-512 hash function providing
+// a simple write()/read() interface with 8 bit data access.
+//
+//
+// Authors: Joachim Strombergson, Paul Selkirk
+// Copyright (c) 2014, SUNET
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or
+// without modification, are permitted provided that the following
+// conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in
+// the documentation and/or other materials provided with the
+// distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module sha512(
+ // Clock and reset.
+ input wire clk,
+ input wire reset_n,
+
+ // SHA-512 mode
+ input wire [1 : 0] mode,
+
+ // Interface to communication core
+ input wire rx_syn,
+ input wire [7 : 0] rx_data,
+ output wire rx_ack,
+
+ output wire tx_syn,
+ output wire [7 : 0] tx_data,
+ input wire tx_ack
+ );
+
+ //----------------------------------------------------------------
+ // Internal constant and parameter definitions.
+ //----------------------------------------------------------------
+ parameter RX_INIT = 0;
+ parameter RX_SYN = 1;
+ parameter RX_ACK = 2;
+ parameter RX_WAIT = 3;
+
+ parameter TX_INIT = 0;
+ parameter TX_SYN = 1;
+ parameter TX_ACK = 2;
+
+ parameter MODE_SHA_512_224 = 2'h0;
+ parameter MODE_SHA_512_256 = 2'h1;
+ parameter MODE_SHA_384 = 2'h2;
+ parameter MODE_SHA_512 = 2'h3;
+
+ parameter BLOCK_BITS = 1024;
+ parameter BLOCK_BYTES = BLOCK_BITS / 8;
+ parameter DIGEST_BITS = 512;
+ parameter DIGEST_BYTES = DIGEST_BITS / 8;
+ parameter DIGEST_BYTES_512_224 = 224 / 8;
+ parameter DIGEST_BYTES_512_256 = 256 / 8;
+ parameter DIGEST_BYTES_384 = 384 / 8;
+ parameter DIGEST_BYTES_512 = 512 / 8;
+
+ //----------------------------------------------------------------
+ // Registers including update variables and write enable.
+ //----------------------------------------------------------------
+ reg rx_ack_reg;
+ reg rx_ack_new;
+ reg rx_ack_we;
+
+ reg [6 : 0] rx_ptr_reg;
+ reg [7 : 0] rx_ptr_new;
+ reg rx_ptr_we;
+
+ reg [1 : 0] rx_ctrl_reg;
+ reg [1 : 0] rx_ctrl_new;
+ reg rx_ctrl_we;
+
+ reg [7 : 0] block_reg [0 : BLOCK_BYTES - 1];
+ reg [7 : 0] block_new;
+ reg block_we;
+
+ reg init_reg;
+ reg init_new;
+ reg init_we;
+
+ reg next_reg;
+ reg next_new;
+ reg next_we;
+
+ reg initnext_reg;
+ reg initnext_new;
+ reg initnext_we;
+
+ reg tx_syn_reg;
+ reg tx_syn_new;
+ reg tx_syn_we;
+
+ reg [6 : 0] tx_ptr_reg;
+ reg [7 : 0] tx_ptr_new;
+ reg tx_ptr_we;
+
+ reg [1 : 0] tx_ctrl_reg;
+ reg [1 : 0] tx_ctrl_new;
+ reg tx_ctrl_we;
+
+ reg tx_active_reg;
+ reg tx_active_new;
+ reg tx_active_we;
+
+ wire [7 : 0] digest_reg [0 : DIGEST_BYTES - 1];
+
+ //----------------------------------------------------------------
+ // Wires.
+ //----------------------------------------------------------------
+ wire core_init;
+ wire core_next;
+ wire core_ready;
+ wire [BLOCK_BITS - 1 : 0] core_block;
+ wire [DIGEST_BITS - 1 : 0] core_digest;
+ wire core_digest_valid;
+
+ //----------------------------------------------------------------
+ // Concurrent connectivity for ports etc.
+ //----------------------------------------------------------------
+ assign core_init = init_reg;
+ assign core_next = next_reg;
+ assign core_block = {block_reg[0], block_reg[1], block_reg[2], block_reg[3],
+ block_reg[4], block_reg[5], block_reg[6], block_reg[7],
+ block_reg[8], block_reg[9], block_reg[10], block_reg[11],
+ block_reg[12], block_reg[13], block_reg[14], block_reg[15],
+ block_reg[16], block_reg[17], block_reg[18], block_reg[19],
+ block_reg[20], block_reg[21], block_reg[22], block_reg[23],
+ block_reg[24], block_reg[25], block_reg[26], block_reg[27],
+ block_reg[28], block_reg[29], block_reg[30], block_reg[31],
+ block_reg[32], block_reg[33], block_reg[34], block_reg[35],
+ block_reg[36], block_reg[37], block_reg[38], block_reg[39],
+ block_reg[40], block_reg[41], block_reg[42], block_reg[43],
+ block_reg[44], block_reg[45], block_reg[46], block_reg[47],
+ block_reg[48], block_reg[49], block_reg[50], block_reg[51],
+ block_reg[52], block_reg[53], block_reg[54], block_reg[55],
+ block_reg[56], block_reg[57], block_reg[58], block_reg[59],
+ block_reg[60], block_reg[61], block_reg[62], block_reg[63],
+ block_reg[64], block_reg[65], block_reg[66], block_reg[67],
+ block_reg[68], block_reg[69], block_reg[70], block_reg[71],
+ block_reg[72], block_reg[73], block_reg[74], block_reg[75],
+ block_reg[76], block_reg[77], block_reg[78], block_reg[79],
+ block_reg[80], block_reg[81], block_reg[82], block_reg[83],
+ block_reg[84], block_reg[85], block_reg[86], block_reg[87],
+ block_reg[88], block_reg[89], block_reg[90], block_reg[91],
+ block_reg[92], block_reg[93], block_reg[94], block_reg[95],
+ block_reg[96], block_reg[97], block_reg[98], block_reg[99],
+ block_reg[100], block_reg[101], block_reg[102], block_reg[103],
+ block_reg[104], block_reg[105], block_reg[106], block_reg[107],
+ block_reg[108], block_reg[109], block_reg[110], block_reg[111],
+ block_reg[112], block_reg[113], block_reg[114], block_reg[115],
+ block_reg[116], block_reg[117], block_reg[118], block_reg[119],
+ block_reg[120], block_reg[121], block_reg[122], block_reg[123],
+ block_reg[124], block_reg[125], block_reg[126], block_reg[127]};
+
+ assign rx_ack = rx_ack_reg;
+ assign tx_syn = tx_syn_reg;
+ assign tx_data = digest_reg[tx_ptr_reg];
+
+ assign digest_reg[0] = core_digest[511 : 504];
+ assign digest_reg[1] = core_digest[503 : 496];
+ assign digest_reg[2] = core_digest[495 : 488];
+ assign digest_reg[3] = core_digest[487 : 480];
+ assign digest_reg[4] = core_digest[479 : 472];
+ assign digest_reg[5] = core_digest[471 : 464];
+ assign digest_reg[6] = core_digest[463 : 456];
+ assign digest_reg[7] = core_digest[455 : 448];
+ assign digest_reg[8] = core_digest[447 : 440];
+ assign digest_reg[9] = core_digest[439 : 432];
+ assign digest_reg[10] = core_digest[431 : 424];
+ assign digest_reg[11] = core_digest[423 : 416];
+ assign digest_reg[12] = core_digest[415 : 408];
+ assign digest_reg[13] = core_digest[407 : 400];
+ assign digest_reg[14] = core_digest[399 : 392];
+ assign digest_reg[15] = core_digest[391 : 384];
+ assign digest_reg[16] = core_digest[383 : 376];
+ assign digest_reg[17] = core_digest[375 : 368];
+ assign digest_reg[18] = core_digest[367 : 360];
+ assign digest_reg[19] = core_digest[359 : 352];
+ assign digest_reg[20] = core_digest[351 : 344];
+ assign digest_reg[21] = core_digest[343 : 336];
+ assign digest_reg[22] = core_digest[335 : 328];
+ assign digest_reg[23] = core_digest[327 : 320];
+ assign digest_reg[24] = core_digest[319 : 312];
+ assign digest_reg[25] = core_digest[311 : 304];
+ assign digest_reg[26] = core_digest[303 : 296];
+ assign digest_reg[27] = core_digest[295 : 288];
+ assign digest_reg[28] = core_digest[287 : 280];
+ assign digest_reg[29] = core_digest[279 : 272];
+ assign digest_reg[30] = core_digest[271 : 264];
+ assign digest_reg[31] = core_digest[263 : 256];
+ assign digest_reg[32] = core_digest[255 : 248];
+ assign digest_reg[33] = core_digest[247 : 240];
+ assign digest_reg[34] = core_digest[239 : 232];
+ assign digest_reg[35] = core_digest[231 : 224];
+ assign digest_reg[36] = core_digest[223 : 216];
+ assign digest_reg[37] = core_digest[215 : 208];
+ assign digest_reg[38] = core_digest[207 : 200];
+ assign digest_reg[39] = core_digest[199 : 192];
+ assign digest_reg[40] = core_digest[191 : 184];
+ assign digest_reg[41] = core_digest[183 : 176];
+ assign digest_reg[42] = core_digest[175 : 168];
+ assign digest_reg[43] = core_digest[167 : 160];
+ assign digest_reg[44] = core_digest[159 : 152];
+ assign digest_reg[45] = core_digest[151 : 144];
+ assign digest_reg[46] = core_digest[143 : 136];
+ assign digest_reg[47] = core_digest[135 : 128];
+ assign digest_reg[48] = core_digest[127 : 120];
+ assign digest_reg[49] = core_digest[119 : 112];
+ assign digest_reg[50] = core_digest[111 : 104];
+ assign digest_reg[51] = core_digest[103 : 96];
+ assign digest_reg[52] = core_digest[95 : 88];
+ assign digest_reg[53] = core_digest[87 : 80];
+ assign digest_reg[54] = core_digest[79 : 72];
+ assign digest_reg[55] = core_digest[71 : 64];
+ assign digest_reg[56] = core_digest[63 : 56];
+ assign digest_reg[57] = core_digest[55 : 48];
+ assign digest_reg[58] = core_digest[47 : 40];
+ assign digest_reg[59] = core_digest[39 : 32];
+ assign digest_reg[60] = core_digest[31 : 24];
+ assign digest_reg[61] = core_digest[23 : 16];
+ assign digest_reg[62] = core_digest[15 : 8];
+ assign digest_reg[63] = core_digest[7 : 0];
+
+ //----------------------------------------------------------------
+ // core instantiation.
+ //----------------------------------------------------------------
+ sha512_core core(
+ .clk(clk),
+ .reset_n(reset_n),
+
+ .init(core_init),
+ .next(core_next),
+ .mode(mode),
+
+ .block(core_block),
+
+ .ready(core_ready),
+
+ .digest(core_digest),
+ .digest_valid(core_digest_valid)
+ );
+
+ //----------------------------------------------------------------
+ // reg_update
+ // Update functionality for all registers in the core.
+ // All registers are positive edge triggered with synchronous
+ // active low reset. All registers have write enable.
+ //----------------------------------------------------------------
+
+ always @ (posedge clk)
+ begin: reg_update
+ if (!reset_n)
+ begin: reset_reg
+ reg[7:0] i;
+ for (i = 0; i < BLOCK_BYTES; i = i + 1)
+ block_reg[i] <= 0;
+ rx_ack_reg <= 0;
+ rx_ptr_reg <= 0;
+ rx_ctrl_reg <= RX_INIT;
+ tx_syn_reg <= 0;
+ tx_ptr_reg <= 0;
+ tx_ctrl_reg <= TX_INIT;
+ initnext_reg <= 0;
+ end
+ else
+ begin
+ if (rx_ack_we)
+ begin
+ rx_ack_reg <= rx_ack_new;
+ end
+
+ if (rx_ptr_we)
+ begin
+ rx_ptr_reg <= rx_ptr_new[6:0];
+ end
+
+ if (rx_ctrl_we)
+ begin
+ rx_ctrl_reg <= rx_ctrl_new;
+ end
+
+ if (block_we)
+ begin
+ block_reg[rx_ptr_reg] <= block_new;
+ end
+
+ if (init_we)
+ begin
+ init_reg <= init_new;
+ end
+
+ if (next_we)
+ begin
+ next_reg <= next_new;
+ end
+
+ if (initnext_we)
+ begin
+ initnext_reg <= initnext_new;
+ end
+
+ if (tx_syn_we)
+ begin
+ tx_syn_reg <= tx_syn_new;
+ end
+
+ if (tx_ptr_we)
+ begin
+ tx_ptr_reg <= tx_ptr_new[6:0];
+ end
+
+ if (tx_ctrl_we)
+ begin
+ tx_ctrl_reg <= tx_ctrl_new;
+ end
+
+ if (tx_active_we)
+ begin
+ tx_active_reg <= tx_active_new;
+ end
+ end
+ end // reg_update
+
+ //----------------------------------------------------------------
+ // rx_engine
+ //----------------------------------------------------------------
+ always @*
+ begin: rx_engine
+ rx_ack_new = 0;
+ rx_ack_we = 0;
+ rx_ptr_new = 0;
+ rx_ptr_we = 0;
+ rx_ctrl_new = 0;
+ rx_ctrl_we = 0;
+ block_new = 0;
+ block_we = 0;
+ init_new = 0;
+ init_we = 0;
+ next_new = 0;
+ next_we = 0;
+ initnext_new = 0;
+ initnext_we = 0;
+
+ if (tx_active_reg)
+ begin
+ initnext_we = 1;
+ end
+
+ case (rx_ctrl_reg)
+ RX_INIT:
+ if (core_ready)
+ begin
+ rx_ctrl_new = RX_SYN;
+ rx_ctrl_we = 1;
+ end
+ RX_SYN:
+ if (rx_syn)
+ begin
+ rx_ack_new = 1;
+ rx_ack_we = 1;
+ block_new = rx_data;
+ block_we = 1;
+ rx_ctrl_new = RX_ACK;
+ rx_ctrl_we = 1;
+ end
+ RX_ACK:
+ if (!rx_syn)
+ begin
+ rx_ack_new = 0;
+ rx_ack_we = 1;
+ rx_ptr_new = rx_ptr_reg + 1;
+ rx_ptr_we = 1;
+ rx_ctrl_new = RX_SYN;
+ rx_ctrl_we = 1;
+ if (rx_ptr_new == BLOCK_BYTES)
+ begin
+ rx_ptr_new = 0;
+ rx_ctrl_new = RX_WAIT;
+ if (initnext_reg == 0)
+ begin
+ init_new = 1;
+ init_we = 1;
+ initnext_new = 1;
+ initnext_we = 1;
+ end
+ else
+ begin
+ next_new = 1;
+ next_we = 1;
+ end
+ end
+ end
+ RX_WAIT:
+ if (!core_ready)
+ begin
+ init_new = 0;
+ init_we = 1;
+ next_new = 0;
+ next_we = 1;
+ rx_ctrl_new = RX_INIT;
+ rx_ctrl_we = 1;
+ end
+ endcase // case (rx_ctrl_reg)
+ end // rx_engine
+
+ //----------------------------------------------------------------
+ // tx_engine
+ //----------------------------------------------------------------
+ always @*
+ begin: tx_engine
+ tx_syn_new = 0;
+ tx_syn_we = 0;
+ tx_ptr_new = 0;
+ tx_ptr_we = 0;
+ tx_ctrl_new = 0;
+ tx_ctrl_we = 0;
+ tx_active_new = 0;
+ tx_active_we = 0;
+
+ case (tx_ctrl_reg)
+ TX_INIT:
+ if (core_digest_valid)
+ begin
+ tx_ctrl_new = TX_SYN;
+ tx_ctrl_we = 1;
+ end
+ TX_SYN:
+ begin
+ tx_syn_new = 1;
+ tx_syn_we = 1;
+ tx_ctrl_new = TX_ACK;
+ tx_ctrl_we = 1;
+ end
+ TX_ACK:
+ if (!core_digest_valid)
+ begin
+ tx_syn_new = 0;
+ tx_syn_we = 1;
+ tx_ptr_new = 0;
+ tx_ptr_we = 1;
+ tx_ctrl_new = TX_INIT;
+ tx_ctrl_we = 1;
+ end
+ else if (tx_ack)
+ begin
+ tx_active_new = 1;
+ tx_active_we = 1;
+ tx_syn_new = 0;
+ tx_syn_we = 1;
+ tx_ptr_new = tx_ptr_reg + 1;
+ tx_ptr_we = 1;
+ tx_ctrl_new = TX_SYN;
+ tx_ctrl_we = 1;
+ if (((mode == MODE_SHA_512_224) && (tx_ptr_new == DIGEST_BYTES_512_224)) ||
+ ((mode == MODE_SHA_512_256) && (tx_ptr_new == DIGEST_BYTES_512_256)) ||
+ ((mode == MODE_SHA_384) && (tx_ptr_new == DIGEST_BYTES_384)) ||
+ ((mode == MODE_SHA_512) && (tx_ptr_new == DIGEST_BYTES_512)))
+ begin
+ tx_active_new = 0;
+ tx_ptr_new = 0;
+ tx_ctrl_new = TX_INIT;
+ end
+ end
+ endcase // case (tx_ctrl_reg)
+ end // tx_engine
+
+endmodule // sha512
+
+//======================================================================
+// EOF sha512.v
+//======================================================================
diff --git a/src/sw/hash.c b/src/sw/hash.c
new file mode 100644
index 0000000..2314fe4
--- /dev/null
+++ b/src/sw/hash.c
@@ -0,0 +1,310 @@
+/*
+ * hash.c
+ * ------
+ * This program uses the coretest_hashes subsystem to produce a
+ * cryptographic hash of a file or input stream. It is a generalization
+ * of the hash_tester.c test program.
+ *
+ * Author: Paul Selkirk
+ * Copyright (c) 2014, SUNET
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <linux/i2c-dev.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+char *usage =
+"Usage: %s [-d] [-v] [-q] [-i I2C_device] [-a I2C_addr] [algorithm [file]]\n"
+"algorithms: sha-1, sha-256, sha-512/224, sha-512/256, sha-384, sha-512\n";
+
+/* I2C configuration */
+#define I2C_dev "/dev/i2c-2"
+
+int debug = 0;
+int verbose = 0;
+
+/* block and digest lengths are number of 32-bit words */
+#define SHA1_BLOCK_LEN 16
+#define SHA1_DIGEST_LEN 5
+#define SHA256_BLOCK_LEN 16
+#define SHA256_DIGEST_LEN 8
+#define SHA512_BLOCK_LEN 32
+#define SHA512_224_DIGEST_LEN 7
+#define SHA512_256_DIGEST_LEN 8
+#define SHA384_DIGEST_LEN 12
+#define SHA512_DIGEST_LEN 16
+
+/* ---------------- algorithm lookup code ---------------- */
+
+struct ctrl {
+ char *name;
+ int i2c_addr;
+ int block_len;
+ int digest_len;
+} ctrl[] = {
+ { "sha-1", 0x1e, SHA1_BLOCK_LEN, SHA1_DIGEST_LEN },
+ { "sha-256", 0x1f, SHA256_BLOCK_LEN, SHA256_DIGEST_LEN },
+ { "sha-512/224", 0x20, SHA512_BLOCK_LEN, SHA512_224_DIGEST_LEN },
+ { "sha-512/256", 0x21, SHA512_BLOCK_LEN, SHA512_256_DIGEST_LEN },
+ { "sha-384", 0x22, SHA512_BLOCK_LEN, SHA384_DIGEST_LEN },
+ { "sha-512", 0x23, SHA512_BLOCK_LEN, SHA512_DIGEST_LEN },
+ { NULL, 0, 0, 0 }
+};
+
+/* return the control structure for the given algorithm */
+struct ctrl *find_algo(char *algo)
+{
+ int i;
+
+ for (i = 0; ctrl[i].name != NULL; ++i)
+ if (strcmp(ctrl[i].name, algo) == 0)
+ return &ctrl[i];
+
+ fprintf(stderr, "algorithm \"%s\" not found\n", algo);
+ fprintf(stderr, usage, "hash");
+ return NULL;
+}
+
+/* ---------------- I2C low-level code ---------------- */
+
+/* return file descriptor for i2c device */
+int i2c_open(char *dev, int addr)
+{
+ int fd;
+
+ fd = open(dev, O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "Unable to open %s: ", dev);
+ perror("");
+ return -1;
+ }
+
+ if (ioctl(fd, I2C_SLAVE, addr) < 0) {
+ fprintf(stderr, "Unable to set I2C slave device 0x%02x: ", addr);
+ perror("");
+ close(fd);
+ return -1;
+ }
+
+ return fd;
+}
+
+void i2c_close(int ifd)
+{
+ close(ifd);
+}
+
+/* ---------------- hash ---------------- */
+
+/* return number of digest bytes read */
+int hash(char *dev, char *algo, char *file, uint8_t *digest)
+{
+ uint8_t block[SHA512_BLOCK_LEN * 4];
+ struct ctrl *ctrl;
+ int i2c_fd, in_fd = 0;
+ int addr, blen, dlen;
+ int nblk, nread;
+ int i, ret = -1;
+ struct timeval start, stop, difftime;
+
+ if (debug) printf("hash(dev=%s, algo=%s, file=%s, digest=%p)\n", dev, algo, file, digest);
+
+ ctrl = find_algo(algo);
+ if (ctrl == NULL)
+ return -1;
+ addr = ctrl->i2c_addr;
+ blen = ctrl->block_len * 4;
+ dlen = ctrl->digest_len * 4;
+
+ if (debug) printf("algorithm %s, device addr %02x\n", ctrl->name, ctrl->i2c_addr);
+
+ i2c_fd = i2c_open(dev, addr);
+ if (i2c_fd < 0)
+ return -1;
+
+ if (strcmp(file, "-") != 0) {
+ in_fd = open(file, O_RDONLY);
+ if (in_fd < 0) {
+ perror("open");
+ goto out2;
+ }
+ }
+
+ if (verbose) {
+ if (gettimeofday(&start, NULL) < 0) {
+ perror("gettimeofday");
+ goto out;
+ }
+ }
+
+ for (nblk = 0; ; ++nblk) {
+ nread = read(in_fd, block, blen);
+ if (nread != blen) {
+ if (nread < 0) {
+ /* read error */
+ perror("read");
+ goto out;
+ }
+ else if (nread == 0) {
+ /* EOF */
+ break;
+ }
+ else {
+ /* partial read - pad the block with 0 */
+ while (nread < blen) {
+ block[nread++] = 0;
+ }
+ }
+ }
+ if (debug) {
+ printf("write [");
+ for (i = 0; i < blen; ++i)
+ printf(" %02x", block[i]);
+ printf(" ]\n");
+ }
+ if (write(i2c_fd, block, blen) != blen) {
+ perror("i2c write failed");
+ goto out;
+ }
+ }
+
+ for (i = 0; i < dlen; ++i) {
+ /* read() on the i2c device only returns one byte at a time */
+ if (read(i2c_fd, &digest[i], 1) != 1) {
+ perror("i2c read failed");
+ goto out;
+ }
+ }
+
+ if (verbose) {
+ if (gettimeofday(&stop, NULL) < 0) {
+ perror("gettimeofday");
+ goto out;
+ }
+ timersub(&stop, &start, &difftime);
+ printf("%d blocks written in %d.%03d sec (%.3f blocks/sec)\n",
+ nblk, (int)difftime.tv_sec, (int)difftime.tv_usec/1000,
+ (float)nblk / ((float)difftime.tv_sec + ((float)difftime.tv_usec)/1000000));
+ }
+
+ ret = dlen;
+out:
+ if (in_fd != 0)
+ close(in_fd);
+out2:
+ i2c_close(i2c_fd);
+ return ret;
+}
+
+/* ---------------- main ---------------- */
+
+int main(int argc, char *argv[])
+{
+ char *dev = I2C_dev;
+ int addr = 0;
+ int i, opt, quiet = 0;
+ char *algo = "sha-1";
+ char *file = "-";
+ uint8_t digest[512/8];
+ int dlen;
+
+ while ((opt = getopt(argc, argv, "h?dvqi:a:")) != -1) {
+ switch (opt) {
+ case 'h':
+ case '?':
+ printf(usage, argv[0]);
+ return 0;
+ case 'd':
+ debug = 1;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ case 'q':
+ quiet = 1;
+ break;
+ case 'i':
+ dev = optarg;
+ break;
+ case 'a':
+ addr = (int)strtol(optarg, NULL, 0);
+ if ((addr < 0x03) || (addr > 0x77)) {
+ fprintf(stderr, "addr must be between 0x03 and 0x77\n");
+ return 1;
+ }
+ break;
+ default:
+ fprintf(stderr, usage, argv[0]);
+ return 1;
+ }
+ }
+
+ if (optind < argc) {
+ algo = argv[optind];
+ ++optind;
+ }
+ else {
+ if (!quiet)
+ printf("defaulting to algorithm \"%s\"\n", algo);
+ }
+
+ if (optind < argc) {
+ file = argv[optind];
+ ++optind;
+ }
+ else {
+ if (!quiet)
+ printf("reading from stdin\n");
+ }
+
+ dlen = hash(dev, algo, file, digest);
+ if (dlen < 0)
+ return 1;
+
+ for (i = 0; i < dlen; ++i) {
+ printf("%02x", digest[i]);
+ if (i % 16 == 15)
+ printf("\n");
+ else if (i % 4 == 3)
+ printf(" ");
+ }
+ if (dlen % 16 != 0)
+ printf("\n");
+
+ return 0;
+}
diff --git a/src/sw/hash_tester.c b/src/sw/hash_tester.c
new file mode 100644
index 0000000..994c305
--- /dev/null
+++ b/src/sw/hash_tester.c
@@ -0,0 +1,688 @@
+/*
+ * hash_tester.c
+ * --------------
+ * This program sends several commands to the coretest_hashes subsystem
+ * in order to verify the SHA-1, SHA-256 and SHA-512/x hash function
+ * cores.
+ *
+ * Note: This version of the program talks to the FPGA over an I2C bus.
+ *
+ * The single and dual block test cases are taken from the
+ * NIST KAT document:
+ * http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/SHA_All.pdf
+ *
+ *
+ * Authors: Joachim Strömbergson, Paul Selkirk
+ * Copyright (c) 2014, SUNET
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <time.h>
+#include <linux/i2c-dev.h>
+#include <sys/ioctl.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+
+/* I2C configuration */
+#define I2C_DEV "/dev/i2c-2"
+
+#define I2C_SHA1_ADDR 0x1e
+#define I2C_SHA256_ADDR 0x1f
+#define I2C_SHA512_ADDR 0x20
+
+#define MODE_SHA_512_224 0x00
+#define MODE_SHA_512_256 0x01
+#define MODE_SHA_384 0x02
+#define MODE_SHA_512 0x03
+
+int i2cfd;
+int debug = 0;
+
+#define SHA1_BLOCK_BITS 512
+#define SHA1_BLOCK_BYTES SHA1_BLOCK_BITS/8
+#define SHA1_DIGEST_BITS 160
+#define SHA1_DIGEST_BYTES SHA1_DIGEST_BITS/8
+
+#define SHA256_BLOCK_BITS 512
+#define SHA256_BLOCK_BYTES SHA256_BLOCK_BITS/8
+#define SHA256_DIGEST_BITS 256
+#define SHA256_DIGEST_BYTES SHA256_DIGEST_BITS/8
+
+#define SHA512_BLOCK_BITS 1024
+#define SHA512_BLOCK_BYTES SHA512_BLOCK_BITS/8
+#define SHA512_224_DIGEST_BITS 224
+#define SHA512_224_DIGEST_BYTES SHA512_224_DIGEST_BITS/8
+#define SHA512_256_DIGEST_BITS 256
+#define SHA512_256_DIGEST_BYTES SHA512_256_DIGEST_BITS/8
+#define SHA384_DIGEST_BITS 384
+#define SHA384_DIGEST_BYTES SHA384_DIGEST_BITS/8
+#define SHA512_DIGEST_BITS 512
+#define SHA512_DIGEST_BYTES SHA512_DIGEST_BITS/8
+
+/* SHA-1/SHA-256 One Block Message Sample
+ Input Message: "abc" */
+const uint8_t NIST_512_SINGLE[] =
+{ 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18 };
+
+const uint8_t SHA1_SINGLE_DIGEST[] =
+{ 0xa9, 0x99, 0x3e, 0x36, 0x47, 0x06, 0x81, 0x6a,
+ 0xba, 0x3e, 0x25, 0x71, 0x78, 0x50, 0xc2, 0x6c,
+ 0x9c, 0xd0, 0xd8, 0x9d };
+
+const uint8_t SHA256_SINGLE_DIGEST[] =
+{ 0xBA, 0x78, 0x16, 0xBF, 0x8F, 0x01, 0xCF, 0xEA,
+ 0x41, 0x41, 0x40, 0xDE, 0x5D, 0xAE, 0x22, 0x23,
+ 0xB0, 0x03, 0x61, 0xA3, 0x96, 0x17, 0x7A, 0x9C,
+ 0xB4, 0x10, 0xFF, 0x61, 0xF2, 0x00, 0x15, 0xAD };
+
+/* SHA-1/SHA-256 Two Block Message Sample
+ Input Message: "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" */
+const uint8_t NIST_512_DOUBLE0[] =
+{ 0x61, 0x62, 0x63, 0x64, 0x62, 0x63, 0x64, 0x65,
+ 0x63, 0x64, 0x65, 0x66, 0x64, 0x65, 0x66, 0x67,
+ 0x65, 0x66, 0x67, 0x68, 0x66, 0x67, 0x68, 0x69,
+ 0x67, 0x68, 0x69, 0x6A, 0x68, 0x69, 0x6A, 0x6B,
+ 0x69, 0x6A, 0x6B, 0x6C, 0x6A, 0x6B, 0x6C, 0x6D,
+ 0x6B, 0x6C, 0x6D, 0x6E, 0x6C, 0x6D, 0x6E, 0x6F,
+ 0x6D, 0x6E, 0x6F, 0x70, 0x6E, 0x6F, 0x70, 0x71,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+const uint8_t NIST_512_DOUBLE1[] =
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xC0 };
+
+const uint8_t SHA1_DOUBLE_DIGEST[] =
+{ 0x84, 0x98, 0x3E, 0x44, 0x1C, 0x3B, 0xD2, 0x6E,
+ 0xBA, 0xAE, 0x4A, 0xA1, 0xF9, 0x51, 0x29, 0xE5,
+ 0xE5, 0x46, 0x70, 0xF1 };
+
+const uint8_t SHA256_DOUBLE_DIGEST[] =
+{ 0x24, 0x8D, 0x6A, 0x61, 0xD2, 0x06, 0x38, 0xB8,
+ 0xE5, 0xC0, 0x26, 0x93, 0x0C, 0x3E, 0x60, 0x39,
+ 0xA3, 0x3C, 0xE4, 0x59, 0x64, 0xFF, 0x21, 0x67,
+ 0xF6, 0xEC, 0xED, 0xD4, 0x19, 0xDB, 0x06, 0xC1 };
+
+/* SHA-512 One Block Message Sample
+ Input Message: "abc" */
+const uint8_t NIST_1024_SINGLE[] =
+{ 0x61, 0x62, 0x63, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18 };
+
+const uint8_t SHA512_224_SINGLE_DIGEST[] =
+{ 0x46, 0x34, 0x27, 0x0f, 0x70, 0x7b, 0x6a, 0x54,
+ 0xda, 0xae, 0x75, 0x30, 0x46, 0x08, 0x42, 0xe2,
+ 0x0e, 0x37, 0xed, 0x26, 0x5c, 0xee, 0xe9, 0xa4,
+ 0x3e, 0x89, 0x24, 0xaa };
+const uint8_t SHA512_256_SINGLE_DIGEST[] =
+{ 0x53, 0x04, 0x8e, 0x26, 0x81, 0x94, 0x1e, 0xf9,
+ 0x9b, 0x2e, 0x29, 0xb7, 0x6b, 0x4c, 0x7d, 0xab,
+ 0xe4, 0xc2, 0xd0, 0xc6, 0x34, 0xfc, 0x6d, 0x46,
+ 0xe0, 0xe2, 0xf1, 0x31, 0x07, 0xe7, 0xaf, 0x23 };
+const uint8_t SHA384_SINGLE_DIGEST[] =
+{ 0xcb, 0x00, 0x75, 0x3f, 0x45, 0xa3, 0x5e, 0x8b,
+ 0xb5, 0xa0, 0x3d, 0x69, 0x9a, 0xc6, 0x50, 0x07,
+ 0x27, 0x2c, 0x32, 0xab, 0x0e, 0xde, 0xd1, 0x63,
+ 0x1a, 0x8b, 0x60, 0x5a, 0x43, 0xff, 0x5b, 0xed,
+ 0x80, 0x86, 0x07, 0x2b, 0xa1, 0xe7, 0xcc, 0x23,
+ 0x58, 0xba, 0xec, 0xa1, 0x34, 0xc8, 0x25, 0xa7 };
+const uint8_t SHA512_SINGLE_DIGEST[] =
+{ 0xdd, 0xaf, 0x35, 0xa1, 0x93, 0x61, 0x7a, 0xba,
+ 0xcc, 0x41, 0x73, 0x49, 0xae, 0x20, 0x41, 0x31,
+ 0x12, 0xe6, 0xfa, 0x4e, 0x89, 0xa9, 0x7e, 0xa2,
+ 0x0a, 0x9e, 0xee, 0xe6, 0x4b, 0x55, 0xd3, 0x9a,
+ 0x21, 0x92, 0x99, 0x2a, 0x27, 0x4f, 0xc1, 0xa8,
+ 0x36, 0xba, 0x3c, 0x23, 0xa3, 0xfe, 0xeb, 0xbd,
+ 0x45, 0x4d, 0x44, 0x23, 0x64, 0x3c, 0xe8, 0x0e,
+ 0x2a, 0x9a, 0xc9, 0x4f, 0xa5, 0x4c, 0xa4, 0x9f };
+
+/* SHA-512 Two Block Message Sample
+ Input Message: "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" */
+const uint8_t NIST_1024_DOUBLE0[] =
+{ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a,
+ 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
+ 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
+ 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
+ 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70,
+ 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71,
+ 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72,
+ 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
+ 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74,
+ 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75,
+ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+const uint8_t NIST_1024_DOUBLE1[] =
+{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x80 };
+
+const uint8_t SHA512_224_DOUBLE_DIGEST[] =
+{ 0x23, 0xfe, 0xc5, 0xbb, 0x94, 0xd6, 0x0b, 0x23,
+ 0x30, 0x81, 0x92, 0x64, 0x0b, 0x0c, 0x45, 0x33,
+ 0x35, 0xd6, 0x64, 0x73, 0x4f, 0xe4, 0x0e, 0x72,
+ 0x68, 0x67, 0x4a, 0xf9 };
+const uint8_t SHA512_256_DOUBLE_DIGEST[] =
+{ 0x39, 0x28, 0xe1, 0x84, 0xfb, 0x86, 0x90, 0xf8,
+ 0x40, 0xda, 0x39, 0x88, 0x12, 0x1d, 0x31, 0xbe,
+ 0x65, 0xcb, 0x9d, 0x3e, 0xf8, 0x3e, 0xe6, 0x14,
+ 0x6f, 0xea, 0xc8, 0x61, 0xe1, 0x9b, 0x56, 0x3a };
+const uint8_t SHA384_DOUBLE_DIGEST[] =
+{ 0x09, 0x33, 0x0c, 0x33, 0xf7, 0x11, 0x47, 0xe8,
+ 0x3d, 0x19, 0x2f, 0xc7, 0x82, 0xcd, 0x1b, 0x47,
+ 0x53, 0x11, 0x1b, 0x17, 0x3b, 0x3b, 0x05, 0xd2,
+ 0x2f, 0xa0, 0x80, 0x86, 0xe3, 0xb0, 0xf7, 0x12,
+ 0xfc, 0xc7, 0xc7, 0x1a, 0x55, 0x7e, 0x2d, 0xb9,
+ 0x66, 0xc3, 0xe9, 0xfa, 0x91, 0x74, 0x60, 0x39 };
+const uint8_t SHA512_DOUBLE_DIGEST[] =
+{ 0x8e, 0x95, 0x9b, 0x75, 0xda, 0xe3, 0x13, 0xda,
+ 0x8c, 0xf4, 0xf7, 0x28, 0x14, 0xfc, 0x14, 0x3f,
+ 0x8f, 0x77, 0x79, 0xc6, 0xeb, 0x9f, 0x7f, 0xa1,
+ 0x72, 0x99, 0xae, 0xad, 0xb6, 0x88, 0x90, 0x18,
+ 0x50, 0x1d, 0x28, 0x9e, 0x49, 0x00, 0xf7, 0xe4,
+ 0x33, 0x1b, 0x99, 0xde, 0xc4, 0xb5, 0x43, 0x3a,
+ 0xc7, 0xd3, 0x29, 0xee, 0xb6, 0xdd, 0x26, 0x54,
+ 0x5e, 0x96, 0xe5, 0x5b, 0x87, 0x4b, 0xe9, 0x09 };
+
+/* ---------------- I2C low-level code ---------------- */
+
+int i2c_open(char *dev)
+{
+ i2cfd = open(dev, O_RDWR);
+ if (i2cfd < 0) {
+ fprintf(stderr, "Unable to open %s: ", dev);
+ perror("");
+ i2cfd = 0;
+ return 1;
+ }
+
+ return 0;
+}
+
+int i2c_addr(int addr)
+{
+ static int cur_addr = 0;
+
+ if (addr != cur_addr) {
+ if (ioctl(i2cfd, I2C_SLAVE, addr) < 0) {
+ fprintf(stderr, "Unable to set I2C slave device 0x%02x: ", addr);
+ perror("");
+ return 1;
+ }
+ addr = cur_addr;
+ }
+
+ return 0;
+}
+
+int i2c_close(void)
+{
+ return close(i2cfd);
+}
+
+int i2c_write(const uint8_t *buf, int len)
+{
+ if (write(i2cfd, buf, len) != len) {
+ perror("i2c write failed");
+ return 1;
+ }
+
+ return 0;
+}
+
+int i2c_read(uint8_t *b)
+{
+ /* read() on the i2c device only returns one byte at a time,
+ * and tc_get_resp() needs to parse the response one byte at a time
+ */
+ if (read(i2cfd, b, 1) != 1) {
+ perror("i2c read failed");
+ return 1;
+ }
+
+ return 0;
+}
+
+/* ---------------- test-case low-level code ---------------- */
+
+int tc_write(int addr, const uint8_t *buf, int len)
+{
+ /* we only set the i2c device addr on tc_write, because test cases always
+ * write before reading, plus test cases never call tc_read directly
+ */
+ if (i2c_addr(addr) != 0)
+ return 1;
+
+ if (debug) {
+ int i;
+ printf("write [");
+ for (i = 0; i < len; ++i)
+ printf(" %02x", buf[i]);
+ printf(" ]\n");
+ }
+
+ return i2c_write(buf, len);
+}
+
+int tc_read(uint8_t *buf, int len)
+{
+ int i;
+
+ if (debug) printf("read [");
+
+ for (i = 0; i < len; ++i) {
+ if (i2c_read(&buf[i]) != 0) {
+ if (debug) printf(" ]\n");
+ return 1;
+ }
+ if (debug) printf(" %02x", buf[i]);
+ }
+
+ if (debug) printf(" ]\n");
+
+ return 0;
+}
+
+int tc_expected(const uint8_t *expected, int len)
+{
+ uint8_t *buf;
+ int i;
+
+ buf = malloc(len);
+ if (buf == NULL) {
+ perror("malloc");
+ return 1;
+ }
+
+ if (tc_read(buf, len) != 0)
+ goto errout;
+
+ for (i = 0; i < len; ++i)
+ if (buf[i] != expected[i]) {
+ fprintf(stderr, "response byte %d: expected 0x%02x, got 0x%02x\n",
+ i, expected[i], buf[i]);
+ goto errout;
+ }
+
+ free(buf);
+ return 0;
+errout:
+ free(buf);
+ return 1;
+}
+
+/* ---------------- SHA-1 test cases ---------------- */
+
+#define BLOCK_LEN SHA1_BLOCK_BYTES
+#define DIGEST_LEN SHA1_DIGEST_BYTES
+
+/* TC1: Read name and version from SHA-1 core. */
+int TC1(int addr)
+{
+ return 0;
+}
+
+/* TC2: SHA-1 Single block message test as specified by NIST. */
+int TC2(int addr)
+{
+ const uint8_t *block = NIST_512_SINGLE;
+ const uint8_t *expected = SHA1_SINGLE_DIGEST;
+
+ printf("TC2: Single block message test for SHA-1.\n");
+
+ if (addr == 0)
+ addr = I2C_SHA1_ADDR;
+
+ return
+ tc_write(addr, block, BLOCK_LEN) ||
+ tc_expected(expected, DIGEST_LEN);
+}
+
+/* TC3: SHA-1 Double block message test as specified by NIST. */
+int TC3(int addr)
+{
+ const uint8_t *block[2] = { NIST_512_DOUBLE0, NIST_512_DOUBLE1 };
+ const uint8_t *expected = SHA1_DOUBLE_DIGEST;
+
+ printf("TC3: Double block message test for SHA-1.\n");
+
+ if (addr == 0)
+ addr = I2C_SHA1_ADDR;
+
+ return
+ tc_write(addr, block[0], BLOCK_LEN) ||
+ tc_write(addr, block[1], BLOCK_LEN) ||
+ tc_expected(expected, DIGEST_LEN);
+}
+
+/* ---------------- SHA-256 test cases ---------------- */
+
+#undef BLOCK_LEN
+#define BLOCK_LEN SHA256_BLOCK_BYTES
+#undef DIGEST_LEN
+#define DIGEST_LEN SHA256_DIGEST_BYTES
+
+int TC4(int addr)
+{
+ return 0;
+}
+
+/* TC5: SHA-256 Single block message test as specified by NIST. */
+int TC5(int addr)
+{
+ const uint8_t *block = NIST_512_SINGLE;
+ const uint8_t *expected = SHA256_SINGLE_DIGEST;
+
+ printf("TC5: Single block message test for SHA-256.\n");
+
+ if (addr == 0)
+ addr = I2C_SHA256_ADDR;
+
+ return
+ tc_write(addr, block, BLOCK_LEN) ||
+ tc_expected(expected, DIGEST_LEN);
+}
+
+/* TC6: SHA-256 Double block message test as specified by NIST. */
+int TC6(int addr)
+{
+ const uint8_t *block[2] = { NIST_512_DOUBLE0, NIST_512_DOUBLE1 };
+ const uint8_t *expected = SHA256_DOUBLE_DIGEST;
+
+ printf("TC6: Double block message test for SHA-256.\n");
+
+ if (addr == 0)
+ addr = I2C_SHA256_ADDR;
+
+ return
+ tc_write(addr, block[0], BLOCK_LEN) ||
+ tc_write(addr, block[1], BLOCK_LEN) ||
+ tc_expected(expected, DIGEST_LEN);
+}
+
+/* TC7: SHA-256 Huge message test. */
+int TC7(int addr)
+{
+ static const uint8_t block[] =
+ { 0xaa, 0x55, 0xaa, 0x55, 0xde, 0xad, 0xbe, 0xef,
+ 0x55, 0xaa, 0x55, 0xaa, 0xf0, 0x0f, 0xf0, 0x0f,
+ 0xaa, 0x55, 0xaa, 0x55, 0xde, 0xad, 0xbe, 0xef,
+ 0x55, 0xaa, 0x55, 0xaa, 0xf0, 0x0f, 0xf0, 0x0f,
+ 0xaa, 0x55, 0xaa, 0x55, 0xde, 0xad, 0xbe, 0xef,
+ 0x55, 0xaa, 0x55, 0xaa, 0xf0, 0x0f, 0xf0, 0x0f,
+ 0xaa, 0x55, 0xaa, 0x55, 0xde, 0xad, 0xbe, 0xef,
+ 0x55, 0xaa, 0x55, 0xaa, 0xf0, 0x0f, 0xf0, 0x0f };
+
+ /* final digest after 1000 iterations */
+ static const uint8_t expected[] =
+ { 0x76, 0x38, 0xf3, 0xbc, 0x50, 0x0d, 0xd1, 0xa6,
+ 0x58, 0x6d, 0xd4, 0xd0, 0x1a, 0x15, 0x51, 0xaf,
+ 0xd8, 0x21, 0xd2, 0x35, 0x2f, 0x91, 0x9e, 0x28,
+ 0xd5, 0x84, 0x2f, 0xab, 0x03, 0xa4, 0x0f, 0x2a };
+
+ int i, n = 1000;
+
+ printf("TC7: Message with %d blocks test for SHA-256.\n", n);
+
+ if (addr == 0)
+ addr = I2C_SHA256_ADDR;
+
+ /* Write blocks to SHA-256. */
+ for (i = 0; i < n; ++i)
+ if (tc_write(addr, block, BLOCK_LEN) != 0)
+ return 1;
+
+ /* Extract the final digest. */
+ return tc_expected(expected, DIGEST_LEN);
+}
+
+/* ---------------- SHA-512 test cases ---------------- */
+
+#undef BLOCK_LEN
+#define BLOCK_LEN SHA512_BLOCK_BYTES
+
+/* TC8: Read name and version from SHA-512 core. */
+int TC8(int addr)
+{
+ return 0;
+}
+
+/* TC9: SHA-512 Single block message test as specified by NIST.
+ We do this for all modes. */
+int tc9(int addr, const uint8_t *expected, int digest_len)
+{
+ const uint8_t *block = NIST_1024_SINGLE;
+
+ return
+ tc_write(addr, block, BLOCK_LEN) ||
+ tc_expected(expected, digest_len);
+}
+
+int TC9(int addr)
+{
+ if (addr == 0)
+ addr = I2C_SHA512_ADDR;
+
+ printf("TC9-1: Single block message test for SHA-512/224.\n");
+ if (tc9(addr + MODE_SHA_512_224, SHA512_224_SINGLE_DIGEST,
+ sizeof(SHA512_224_SINGLE_DIGEST)) != 0)
+ return 1;
+
+ printf("TC9-2: Single block message test for SHA-512/256.\n");
+ if (tc9(addr + MODE_SHA_512_256, SHA512_256_SINGLE_DIGEST,
+ sizeof(SHA512_256_SINGLE_DIGEST)) != 0)
+ return 1;
+
+ printf("TC9-3: Single block message test for SHA-384.\n");
+ if (tc9(addr + MODE_SHA_384, SHA384_SINGLE_DIGEST,
+ sizeof(SHA384_SINGLE_DIGEST)) != 0)
+ return 1;
+
+ printf("TC9-4: Single block message test for SHA-512.\n");
+ if (tc9(addr + MODE_SHA_512, SHA512_SINGLE_DIGEST,
+ sizeof(SHA512_SINGLE_DIGEST)) != 0)
+ return 1;
+
+ return 0;
+}
+
+/* TC10: SHA-512 Double block message test as specified by NIST.
+ We do this for all modes. */
+int tc10(int addr, const uint8_t *expected, int digest_len)
+{
+ const uint8_t *block[2] = { NIST_1024_DOUBLE0, NIST_1024_DOUBLE1 };
+
+ return
+ tc_write(addr, block[0], BLOCK_LEN) ||
+ tc_write(addr, block[1], BLOCK_LEN) ||
+ tc_expected(expected, digest_len);
+}
+
+int TC10(int addr)
+{
+ if (addr == 0)
+ addr = I2C_SHA512_ADDR;
+
+ printf("TC10-1: Double block message test for SHA-512/224.\n");
+ if (tc10(addr + MODE_SHA_512_224, SHA512_224_DOUBLE_DIGEST,
+ sizeof(SHA512_224_DOUBLE_DIGEST)) != 0)
+ return 1;
+
+ printf("TC10-2: Double block message test for SHA-512/256.\n");
+ if (tc10(addr + MODE_SHA_512_256, SHA512_256_DOUBLE_DIGEST,
+ sizeof(SHA512_256_DOUBLE_DIGEST)) != 0)
+ return 1;
+
+ printf("TC10-3: Double block message test for SHA-384.\n");
+ if (tc10(addr + MODE_SHA_384, SHA384_DOUBLE_DIGEST,
+ sizeof(SHA384_DOUBLE_DIGEST)) != 0)
+ return 1;
+
+ printf("TC10-4: Double block message test for SHA-512.\n");
+ if (tc10(addr + MODE_SHA_512, SHA512_DOUBLE_DIGEST,
+ sizeof(SHA512_DOUBLE_DIGEST)) != 0)
+ return 1;
+
+ return 0;
+}
+
+/* ---------------- main ---------------- */
+
+int main(int argc, char *argv[])
+{
+ typedef int (*tcfp)(int);
+ tcfp all_tests[] = { TC1, TC2, TC3, TC4, TC5, TC6, TC7, TC9, TC10
+ };
+ tcfp sha1_tests[] = { TC1, TC2, TC3 };
+ tcfp sha256_tests[] = { TC4, TC5, TC6, TC7 };
+ tcfp sha512_tests[] = { TC9, TC10 };
+
+ char *usage = "Usage: %s [-h] [-d] [-i I2C_device] [-a I2C_addr] tc...\n";
+ char *dev = I2C_DEV;
+ int addr = 0;
+ int i, j, opt;
+
+ while ((opt = getopt(argc, argv, "h?di:a:")) != -1) {
+ switch (opt) {
+ case 'h':
+ case '?':
+ printf(usage, argv[0]);
+ return 0;
+ case 'd':
+ debug = 1;
+ break;
+ case 'i':
+ dev = optarg;
+ break;
+ case 'a':
+ addr = (int)strtol(optarg, NULL, 0);
+ if ((addr < 0x03) || (addr > 0x77)) {
+ fprintf(stderr, "addr must be between 0x03 and 0x77\n");
+ return 1;
+ }
+ break;
+ default:
+ fprintf(stderr, usage, argv[0]);
+ return 1;
+ }
+ }
+
+ if (i2c_open(dev) != 0)
+ return 1;
+
+ /* no args == run all tests */
+ if (optind >= argc) {
+ for (j = 0; j < sizeof(all_tests)/sizeof(all_tests[0]); ++j)
+ if (all_tests[j](addr) != 0)
+ return 1;
+ return 0;
+ }
+
+ for (i = optind; i < argc; ++i) {
+ if (strcmp(argv[i], "sha1") == 0) {
+ for (j = 0; j < sizeof(sha1_tests)/sizeof(sha1_tests[0]); ++j)
+ if (sha1_tests[j](addr) != 0)
+ return 1;
+ }
+ else if (strcmp(argv[i], "sha256") == 0) {
+ for (j = 0; j < sizeof(sha256_tests)/sizeof(sha256_tests[0]); ++j)
+ if (sha256_tests[j](addr) != 0)
+ return 1;
+ }
+ else if (strcmp(argv[i], "sha512") == 0) {
+ for (j = 0; j < sizeof(sha512_tests)/sizeof(sha512_tests[0]); ++j)
+ if (sha512_tests[j](addr) != 0)
+ return 1;
+ }
+ else if (strcmp(argv[i], "all") == 0) {
+ for (j = 0; j < sizeof(all_tests)/sizeof(all_tests[0]); ++j)
+ if (all_tests[j](addr) != 0)
+ return 1;
+ }
+ else if (isdigit(argv[i][0]) &&
+ (((j = atoi(argv[i])) > 0) &&
+ (j <= sizeof(all_tests)/sizeof(all_tests[0])))) {
+ if (all_tests[j - 1](addr) != 0)
+ return 1;
+ }
+ else {
+ fprintf(stderr, "unknown test case %s\n", argv[i]);
+ return 1;
+ }
+ }
+
+ return 0;
+}