diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/rtl/coretest_hashes.v | 273 | ||||
-rw-r--r-- | src/rtl/i2c_core.v | 581 | ||||
-rw-r--r-- | src/rtl/novena_fpga.v | 147 | ||||
-rw-r--r-- | src/rtl/sha1.v | 421 | ||||
-rw-r--r-- | src/rtl/sha256.v | 433 | ||||
-rw-r--r-- | src/rtl/sha512.v | 497 | ||||
-rw-r--r-- | src/sw/hash.c | 310 | ||||
-rw-r--r-- | src/sw/hash_tester.c | 688 |
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; +} |