package KenSha2; /* A implementation of the SHA-256 cryptographic hash algorithm (part of the SHA-2 family of hash functions), one cycle per iteration. There are three interfaces. The highest-level interface, "bitSHA2", consumes bits terminated by EOF and returns a hash. "mkBlockProcess" consumes blocks and returns a hash. The user is expected to have properly padded the input. "mkSHA2" is "reentrant", consuming blocks. The user must thread the state between successive calls. Although there is bitSHA2, there is no byteSHA2 that consumes bytes, though it could probably be easily written. There are probably FIFOs that could by optimized with bypasses. */ import Vector::*; import ClientServer::*; import GetPut::*; import FIFO::*; import Connectable::*; import RegFile::*; /* Probably eventually want import FIFOF::*; import SpecialFIFOs::*; */ import StmtFSM::*; typedef 64 WidthWord; typedef Bit#(WidthWord) Word; typedef UInt#(7) CountRounds; typedef 80 NumRounds; typedef struct { Word a; Word b; Word c; Word d; Word e; Word f; Word g; Word h; } ShaState deriving (Bits); function ShaState stateAdd(ShaState x, ShaState y); return ShaState { a: x.a+y.a ,b: x.b+y.b ,c: x.c+y.c ,d: x.d+y.d ,e: x.e+y.e ,f: x.f+y.f ,g: x.g+y.g ,h: x.h+y.h }; endfunction //This is 16*32 = 512 or 16*64 = 1024 depending //on WidthWord, but always 16 words typedef 16 InputWords; typedef Vector#(InputWords,Word) InputChunk; typedef TMul#(InputWords,WidthWord) SizeInput; typedef UInt#(TAdd#(TLog#(SizeInput),1)) CountBlock; /* #! /bin/bash set -x set -o pipefail set -e ( cat <>7); Word two = w[i-2]; Word s1 =rightrotate(two,19'b0) ^ rightrotate(two,61'b0) ^ (two>>6); return w[i-16]+s0+w[i-7]+s1; endfunction function ShaState round_do(ShaState x, Word k, Word w); Word s1 = rightrotate(x.e,14'b0) ^ rightrotate(x.e,18'b0) ^ rightrotate(x.e,41'b0); Word ch = (x.e & x.f) ^ (~x.e & x.g); Word temp = x.h + s1 + ch + k + w; x.d = x.d + temp; Word s0 = rightrotate(x.a, 28'b0) ^ rightrotate(x.a, 34'b0) ^ rightrotate(x.a, 39'b0); Word maj = (x.a & (x.b ^ x.c)) ^ (x.b & x.c); temp = temp + s0 + maj; return ShaState { h: x.g ,g: x.f ,f: x.e ,e: x.d ,d: x.c ,c: x.b ,b: x.a ,a: temp }; endfunction function InputChunk mkInput3(Word x1, Word x2, Word length); InputChunk w=unpack(0); w[0]=x1; w[1]=x2; w[15]=8*length; return w; endfunction module mkInputExtend(Server#(InputChunk,Word)); Reg#(InputChunk) w<-mkRegU; interface Put request; method Action put(InputChunk inw); w<=inw; endmethod endinterface interface Get response; method ActionValue#(Word) get; Word ret=w[0]; InputChunk neww=rotate(w); neww[15]=initial_extend(w); w<=neww; return ret; endmethod endinterface endmodule module mkSHA2(Server#(Tuple2#(ShaState,InputChunk),ShaState)); Reg#(Maybe#(ShaState)) x<-mkReg(tagged Invalid); Reg#(CountRounds) i<-mkReg(0); FIFO#(Tuple2#(ShaState,InputChunk)) infifo <- mkFIFO; FIFO#(ShaState) outfifo <- mkFIFO; Server#(InputChunk,Word) input_w<-mkInputExtend; CountRounds cNumRounds=fromInteger(valueof(NumRounds)); //Use this vector instead of a giant lookup table, which would have //presumably implemented by a giant variable shifter. Reg#(Vector#(NumRounds,Word)) k <- mkReg(arrayToVector(k_round_constant)); rule initialize (x matches tagged Invalid); x <= tagged Valid (tpl_1(infifo.first)); input_w.request.put(tpl_2(infifo.first)); //Do not dequeue until "done" so "first" is available then //to add the last x. i <= 0; endrule rule oneround ( i input.hex module regfile(); Integer numtests=2306; Server#(DataOrEof#(bit),ShaState) sha <- bitSHA2; RegFile#(UInt#(48),Bit#(DataMax)) data_in<-mkRegFileLoad("input.hex",0,fromInteger(2*numtests-1)); Reg#(Bit#(DataMax)) text<-mkRegU; Reg#(UInt#(BitCounter)) i<-mkRegU; Reg#(UInt#(48)) test<-mkRegU; //UInt#(BitCounter) len = unpack(truncate(data_in.sub(2*test))); Reg#(UInt#(BitCounter)) len <- mkRegU; mkAutoStartFSM (seq for(test<=0;test