blob: b45d1cc96bb6dcd486428b584a318e588ab11f54 [file] [log] [blame] [edit]
//======================================================================
//
// chacha.v
// --------
// Top level wrapper for the ChaCha stream, cipher core providing
// a simple memory like interface with 32 bit data access.
//
//
// Copyright (c) 2013 Secworks Sweden AB
//
// 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 chacha(
input wire clk,
input wire reset_n,
input wire cs,
input wire we,
input wire [7 : 0] addr,
input wire [31 : 0] write_data,
output wire [31 : 0] read_data
);
//----------------------------------------------------------------
// Internal constant and parameter definitions.
//----------------------------------------------------------------
localparam ADDR_NAME0 = 8'h00;
localparam ADDR_NAME1 = 8'h01;
localparam ADDR_VERSION = 8'h02;
localparam ADDR_CTRL = 8'h08;
localparam CTRL_INIT_BIT = 0;
localparam CTRL_NEXT_BIT = 1;
localparam ADDR_STATUS = 8'h09;
localparam STATUS_READY_BIT = 0;
localparam ADDR_KEYLEN = 8'h0a;
localparam KEYLEN_BIT = 0;
localparam ADDR_ROUNDS = 8'h0b;
localparam ROUNDS_HIGH_BIT = 4;
localparam ROUNDS_LOW_BIT = 0;
localparam ADDR_KEY0 = 8'h10;
localparam ADDR_KEY7 = 8'h17;
localparam ADDR_IV0 = 8'h20;
localparam ADDR_IV1 = 8'h21;
localparam ADDR_DATA_IN0 = 8'h40;
localparam ADDR_DATA_IN15 = 8'h4f;
localparam ADDR_DATA_OUT0 = 8'h80;
localparam ADDR_DATA_OUT15 = 8'h8f;
localparam CORE_NAME0 = 32'h63686163; // "chac"
localparam CORE_NAME1 = 32'h68612020; // "ha "
localparam CORE_VERSION = 32'h302e3830; // "0.80"
localparam DEFAULT_CTR_INIT = 64'h0;
//----------------------------------------------------------------
// Registers including update variables and write enable.
//----------------------------------------------------------------
reg init_reg;
reg init_new;
reg next_reg;
reg next_new;
reg keylen_reg;
reg keylen_we;
reg [4 : 0] rounds_reg;
reg rounds_we;
reg [31 : 0] key_reg [0 : 7];
reg key_we;
reg [31 : 0] iv_reg[0 : 1];
reg iv_we;
reg [31 : 0] data_in_reg [0 : 15];
reg data_in_we;
//----------------------------------------------------------------
// Wires.
//----------------------------------------------------------------
wire [255 : 0] core_key;
wire [63 : 0] core_iv;
wire core_ready;
wire [511 : 0] core_data_in;
wire [511 : 0] core_data_out;
wire core_data_out_valid;
reg [31 : 0] tmp_read_data;
//----------------------------------------------------------------
// Concurrent connectivity for ports etc.
//----------------------------------------------------------------
assign core_key = {key_reg[0], key_reg[1], key_reg[2], key_reg[3],
key_reg[4], key_reg[5], key_reg[6], key_reg[7]};
assign core_iv = {iv_reg[0], iv_reg[1]};
assign core_data_in = {data_in_reg[00], data_in_reg[01], data_in_reg[02], data_in_reg[03],
data_in_reg[04], data_in_reg[05], data_in_reg[06], data_in_reg[07],
data_in_reg[08], data_in_reg[09], data_in_reg[10], data_in_reg[11],
data_in_reg[12], data_in_reg[13], data_in_reg[14], data_in_reg[15]};
assign read_data = tmp_read_data;
//----------------------------------------------------------------
// core instantiation.
//----------------------------------------------------------------
chacha_core core (
.clk(clk),
.reset_n(reset_n),
.init(init_reg),
.next(next_reg),
.key(core_key),
.keylen(keylen_reg),
.iv(core_iv),
.ctr(DEFAULT_CTR_INIT),
.rounds(rounds_reg),
.data_in(core_data_in),
.ready(core_ready),
.data_out(core_data_out),
.data_out_valid(core_data_out_valid)
);
//----------------------------------------------------------------
// reg_update
//
// Update functionality for all registers in the core.
// All registers are positive edge triggered with asynchronous
// active low reset. All registers have write enable.
//----------------------------------------------------------------
always @ (posedge clk)
begin : reg_update
integer i;
if (!reset_n)
begin
init_reg <= 0;
next_reg <= 0;
keylen_reg <= 0;
rounds_reg <= 5'h0;
iv_reg[0] <= 32'h0;
iv_reg[1] <= 32'h0;
for (i = 0 ; i < 8 ; i = i + 1)
key_reg[i] <= 32'h0;
for (i = 0 ; i < 16 ; i = i + 1)
data_in_reg[i] <= 32'h0;
end
else
begin
init_reg <= init_new;
next_reg <= next_new;
if (keylen_we)
keylen_reg <= write_data[KEYLEN_BIT];
if (rounds_we)
rounds_reg <= write_data[ROUNDS_HIGH_BIT : ROUNDS_LOW_BIT];
if (key_we)
key_reg[addr[2 : 0]] <= write_data;
if (iv_we)
iv_reg[addr[0]] <= write_data;
if (data_in_we)
data_in_reg[addr[3 : 0]] <= write_data;
end
end // reg_update
//----------------------------------------------------------------
// Address decoder logic.
//----------------------------------------------------------------
always @*
begin : addr_decoder
keylen_we = 1'h0;
rounds_we = 1'h0;
key_we = 1'h0;
iv_we = 1'h0;
data_in_we = 1'h0;
init_new = 1'h0;
next_new = 1'h0;
tmp_read_data = 32'h0;
if (cs)
begin
if (we)
begin
if (addr == ADDR_CTRL)
begin
init_new = write_data[CTRL_INIT_BIT];
next_new = write_data[CTRL_NEXT_BIT];
end
if (addr == ADDR_KEYLEN)
keylen_we = 1;
if (addr == ADDR_ROUNDS)
rounds_we = 1;
if ((addr >= ADDR_KEY0) && (addr <= ADDR_KEY7))
key_we = 1;
if ((addr >= ADDR_IV0) && (addr <= ADDR_IV1))
iv_we = 1;
if ((addr >= ADDR_DATA_IN0) && (addr <= ADDR_DATA_IN15))
data_in_we = 1;
end // if (we)
else
begin
if ((addr >= ADDR_KEY0) && (addr <= ADDR_KEY7))
tmp_read_data = key_reg[addr[2 : 0]];
if ((addr >= ADDR_DATA_OUT0) && (addr <= ADDR_DATA_OUT15))
tmp_read_data = core_data_out[(15 - (addr - ADDR_DATA_OUT0)) * 32 +: 32];
case (addr)
ADDR_NAME0: tmp_read_data = CORE_NAME0;
ADDR_NAME1: tmp_read_data = CORE_NAME1;
ADDR_VERSION: tmp_read_data = CORE_VERSION;
ADDR_CTRL: tmp_read_data = {30'h0, next_reg, init_reg};
ADDR_STATUS: tmp_read_data = {30'h0, core_data_out_valid, core_ready};
ADDR_KEYLEN: tmp_read_data = {31'h0, keylen_reg};
ADDR_ROUNDS: tmp_read_data = {27'h0, rounds_reg};
ADDR_IV0: tmp_read_data = iv_reg[0];
ADDR_IV1: tmp_read_data = iv_reg[1];
default:
begin
end
endcase // case (address)
end
end
end // addr_decoder
endmodule // chacha
module chacha_core(
input wire clk,
input wire reset_n,
input wire init,
input wire next,
input wire [255 : 0] key,
input wire keylen,
input wire [63 : 0] iv,
input wire [63 : 0] ctr,
input wire [4 : 0] rounds,
input wire [511 : 0] data_in,
output wire ready,
output wire [511 : 0] data_out,
output wire data_out_valid
);
//----------------------------------------------------------------
// Internal constant and parameter definitions.
//----------------------------------------------------------------
// Datapath quartterround states names.
localparam QR0 = 0;
localparam QR1 = 1;
localparam NUM_ROUNDS = 4'h8;
localparam TAU0 = 32'h61707865;
localparam TAU1 = 32'h3120646e;
localparam TAU2 = 32'h79622d36;
localparam TAU3 = 32'h6b206574;
localparam SIGMA0 = 32'h61707865;
localparam SIGMA1 = 32'h3320646e;
localparam SIGMA2 = 32'h79622d32;
localparam SIGMA3 = 32'h6b206574;
localparam CTRL_IDLE = 3'h0;
localparam CTRL_INIT = 3'h1;
localparam CTRL_ROUNDS = 3'h2;
localparam CTRL_FINALIZE = 3'h3;
localparam CTRL_DONE = 3'h4;
//----------------------------------------------------------------
// l2b()
//
// Swap bytes from little to big endian byte order.
//----------------------------------------------------------------
function [31 : 0] l2b(input [31 : 0] op);
begin
l2b = {op[7 : 0], op[15 : 8], op[23 : 16], op[31 : 24]};
end
endfunction // b2l
//----------------------------------------------------------------
// Registers including update variables and write enable.
//----------------------------------------------------------------
reg [31 : 0] state_reg [0 : 15];
reg [31 : 0] state_new [0 : 15];
reg state_we;
reg [511 : 0] data_out_reg;
reg [511 : 0] data_out_new;
reg data_out_valid_reg;
reg data_out_valid_new;
reg data_out_valid_we;
reg qr_ctr_reg;
reg qr_ctr_new;
reg qr_ctr_we;
reg qr_ctr_inc;
reg qr_ctr_rst;
reg [3 : 0] dr_ctr_reg;
reg [3 : 0] dr_ctr_new;
reg dr_ctr_we;
reg dr_ctr_inc;
reg dr_ctr_rst;
reg [31 : 0] block0_ctr_reg;
reg [31 : 0] block0_ctr_new;
reg block0_ctr_we;
reg [31 : 0] block1_ctr_reg;
reg [31 : 0] block1_ctr_new;
reg block1_ctr_we;
reg block_ctr_inc;
reg block_ctr_set;
reg ready_reg;
reg ready_new;
reg ready_we;
reg [2 : 0] chacha_ctrl_reg;
reg [2 : 0] chacha_ctrl_new;
reg chacha_ctrl_we;
// Test
reg [31 : 0] msb_block_state [0 : 15];
reg [31 : 0] lsb_block_state [0 : 15];
reg [511 : 0] block_state;
//----------------------------------------------------------------
// Wires.
//----------------------------------------------------------------
reg [31 : 0] init_state_word [0 : 15];
reg init_state;
reg update_state;
reg update_output;
reg [31 : 0] qr0_a;
reg [31 : 0] qr0_b;
reg [31 : 0] qr0_c;
reg [31 : 0] qr0_d;
wire [31 : 0] qr0_a_prim;
wire [31 : 0] qr0_b_prim;
wire [31 : 0] qr0_c_prim;
wire [31 : 0] qr0_d_prim;
reg [31 : 0] qr1_a;
reg [31 : 0] qr1_b;
reg [31 : 0] qr1_c;
reg [31 : 0] qr1_d;
wire [31 : 0] qr1_a_prim;
wire [31 : 0] qr1_b_prim;
wire [31 : 0] qr1_c_prim;
wire [31 : 0] qr1_d_prim;
reg [31 : 0] qr2_a;
reg [31 : 0] qr2_b;
reg [31 : 0] qr2_c;
reg [31 : 0] qr2_d;
wire [31 : 0] qr2_a_prim;
wire [31 : 0] qr2_b_prim;
wire [31 : 0] qr2_c_prim;
wire [31 : 0] qr2_d_prim;
reg [31 : 0] qr3_a;
reg [31 : 0] qr3_b;
reg [31 : 0] qr3_c;
reg [31 : 0] qr3_d;
wire [31 : 0] qr3_a_prim;
wire [31 : 0] qr3_b_prim;
wire [31 : 0] qr3_c_prim;
wire [31 : 0] qr3_d_prim;
//----------------------------------------------------------------
// Instantiation of the qr modules.
//----------------------------------------------------------------
chacha_qr qr0(
.a(qr0_a),
.b(qr0_b),
.c(qr0_c),
.d(qr0_d),
.a_prim(qr0_a_prim),
.b_prim(qr0_b_prim),
.c_prim(qr0_c_prim),
.d_prim(qr0_d_prim)
);
chacha_qr qr1(
.a(qr1_a),
.b(qr1_b),
.c(qr1_c),
.d(qr1_d),
.a_prim(qr1_a_prim),
.b_prim(qr1_b_prim),
.c_prim(qr1_c_prim),
.d_prim(qr1_d_prim)
);
chacha_qr qr2(
.a(qr2_a),
.b(qr2_b),
.c(qr2_c),
.d(qr2_d),
.a_prim(qr2_a_prim),
.b_prim(qr2_b_prim),
.c_prim(qr2_c_prim),
.d_prim(qr2_d_prim)
);
chacha_qr qr3(
.a(qr3_a),
.b(qr3_b),
.c(qr3_c),
.d(qr3_d),
.a_prim(qr3_a_prim),
.b_prim(qr3_b_prim),
.c_prim(qr3_c_prim),
.d_prim(qr3_d_prim)
);
//----------------------------------------------------------------
// Concurrent connectivity for ports etc.
//----------------------------------------------------------------
assign data_out = data_out_reg;
assign data_out_valid = data_out_valid_reg;
assign ready = ready_reg;
//----------------------------------------------------------------
// 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
integer i;
if (!reset_n)
begin
for (i = 0 ; i < 16 ; i = i + 1)
state_reg[i] <= 32'h0;
data_out_reg <= 512'h0;
data_out_valid_reg <= 0;
qr_ctr_reg <= QR0;
dr_ctr_reg <= 0;
block0_ctr_reg <= 32'h0;
block1_ctr_reg <= 32'h0;
chacha_ctrl_reg <= CTRL_IDLE;
ready_reg <= 1;
end
else
begin
if (state_we)
begin
for (i = 0 ; i < 16 ; i = i + 1)
state_reg[i] <= state_new[i];
end
if (update_output)
data_out_reg <= data_out_new;
if (data_out_valid_we)
data_out_valid_reg <= data_out_valid_new;
if (qr_ctr_we)
qr_ctr_reg <= qr_ctr_new;
if (dr_ctr_we)
dr_ctr_reg <= dr_ctr_new;
if (block0_ctr_we)
block0_ctr_reg <= block0_ctr_new;
if (block1_ctr_we)
block1_ctr_reg <= block1_ctr_new;
if (ready_we)
ready_reg <= ready_new;
if (chacha_ctrl_we)
chacha_ctrl_reg <= chacha_ctrl_new;
end
end // reg_update
//----------------------------------------------------------------
// init_state_logic
//
// Calculates the initial state for a given block.
//----------------------------------------------------------------
always @*
begin : init_state_logic
reg [31 : 0] key0;
reg [31 : 0] key1;
reg [31 : 0] key2;
reg [31 : 0] key3;
reg [31 : 0] key4;
reg [31 : 0] key5;
reg [31 : 0] key6;
reg [31 : 0] key7;
key0 = l2b(key[255 : 224]);
key1 = l2b(key[223 : 192]);
key2 = l2b(key[191 : 160]);
key3 = l2b(key[159 : 128]);
key4 = l2b(key[127 : 96]);
key5 = l2b(key[95 : 64]);
key6 = l2b(key[63 : 32]);
key7 = l2b(key[31 : 0]);
init_state_word[04] = key0;
init_state_word[05] = key1;
init_state_word[06] = key2;
init_state_word[07] = key3;
init_state_word[12] = block0_ctr_reg;
init_state_word[13] = block1_ctr_reg;
init_state_word[14] = l2b(iv[63 : 32]);
init_state_word[15] = l2b(iv[31 : 0]);
if (keylen)
begin
// 256 bit key.
init_state_word[00] = SIGMA0;
init_state_word[01] = SIGMA1;
init_state_word[02] = SIGMA2;
init_state_word[03] = SIGMA3;
init_state_word[08] = key4;
init_state_word[09] = key5;
init_state_word[10] = key6;
init_state_word[11] = key7;
end
else
begin
// 128 bit key.
init_state_word[00] = TAU0;
init_state_word[01] = TAU1;
init_state_word[02] = TAU2;
init_state_word[03] = TAU3;
init_state_word[08] = key0;
init_state_word[09] = key1;
init_state_word[10] = key2;
init_state_word[11] = key3;
end
end
//----------------------------------------------------------------
// state_logic
// Logic to init and update the internal state.
//----------------------------------------------------------------
always @*
begin : state_logic
integer i;
for (i = 0 ; i < 16 ; i = i + 1)
state_new[i] = 32'h0;
state_we = 0;
qr0_a = 32'h0;
qr0_b = 32'h0;
qr0_c = 32'h0;
qr0_d = 32'h0;
qr1_a = 32'h0;
qr1_b = 32'h0;
qr1_c = 32'h0;
qr1_d = 32'h0;
qr2_a = 32'h0;
qr2_b = 32'h0;
qr2_c = 32'h0;
qr2_d = 32'h0;
qr3_a = 32'h0;
qr3_b = 32'h0;
qr3_c = 32'h0;
qr3_d = 32'h0;
if (init_state)
begin
for (i = 0 ; i < 16 ; i = i + 1)
state_new[i] = init_state_word[i];
state_we = 1;
end // if (init_state)
if (update_state)
begin
state_we = 1;
case (qr_ctr_reg)
QR0:
begin
qr0_a = state_reg[00];
qr0_b = state_reg[04];
qr0_c = state_reg[08];
qr0_d = state_reg[12];
qr1_a = state_reg[01];
qr1_b = state_reg[05];
qr1_c = state_reg[09];
qr1_d = state_reg[13];
qr2_a = state_reg[02];
qr2_b = state_reg[06];
qr2_c = state_reg[10];
qr2_d = state_reg[14];
qr3_a = state_reg[03];
qr3_b = state_reg[07];
qr3_c = state_reg[11];
qr3_d = state_reg[15];
state_new[00] = qr0_a_prim;
state_new[04] = qr0_b_prim;
state_new[08] = qr0_c_prim;
state_new[12] = qr0_d_prim;
state_new[01] = qr1_a_prim;
state_new[05] = qr1_b_prim;
state_new[09] = qr1_c_prim;
state_new[13] = qr1_d_prim;
state_new[02] = qr2_a_prim;
state_new[06] = qr2_b_prim;
state_new[10] = qr2_c_prim;
state_new[14] = qr2_d_prim;
state_new[03] = qr3_a_prim;
state_new[07] = qr3_b_prim;
state_new[11] = qr3_c_prim;
state_new[15] = qr3_d_prim;
end
QR1:
begin
qr0_a = state_reg[00];
qr0_b = state_reg[05];
qr0_c = state_reg[10];
qr0_d = state_reg[15];
qr1_a = state_reg[01];
qr1_b = state_reg[06];
qr1_c = state_reg[11];
qr1_d = state_reg[12];
qr2_a = state_reg[02];
qr2_b = state_reg[07];
qr2_c = state_reg[08];
qr2_d = state_reg[13];
qr3_a = state_reg[03];
qr3_b = state_reg[04];
qr3_c = state_reg[09];
qr3_d = state_reg[14];
state_new[00] = qr0_a_prim;
state_new[05] = qr0_b_prim;
state_new[10] = qr0_c_prim;
state_new[15] = qr0_d_prim;
state_new[01] = qr1_a_prim;
state_new[06] = qr1_b_prim;
state_new[11] = qr1_c_prim;
state_new[12] = qr1_d_prim;
state_new[02] = qr2_a_prim;
state_new[07] = qr2_b_prim;
state_new[08] = qr2_c_prim;
state_new[13] = qr2_d_prim;
state_new[03] = qr3_a_prim;
state_new[04] = qr3_b_prim;
state_new[09] = qr3_c_prim;
state_new[14] = qr3_d_prim;
end
endcase // case (quarterround_select)
end // if (update_state)
end // state_logic
//----------------------------------------------------------------
// data_out_logic
// Final output logic that combines the result from state
// update with the input block. This adds a 16 rounds and
// a final layer of XOR gates.
//
// Note that we also remap all the words into LSB format.
//----------------------------------------------------------------
always @*
begin : data_out_logic
integer i;
reg [31 : 0] msb_block_state [0 : 15];
reg [31 : 0] lsb_block_state [0 : 15];
reg [511 : 0] block_state;
for (i = 0 ; i < 16 ; i = i + 1)
begin
msb_block_state[i] = init_state_word[i] + state_reg[i];
lsb_block_state[i] = l2b(msb_block_state[i][31 : 0]);
end
block_state = {lsb_block_state[00], lsb_block_state[01],
lsb_block_state[02], lsb_block_state[03],
lsb_block_state[04], lsb_block_state[05],
lsb_block_state[06], lsb_block_state[07],
lsb_block_state[08], lsb_block_state[09],
lsb_block_state[10], lsb_block_state[11],
lsb_block_state[12], lsb_block_state[13],
lsb_block_state[14], lsb_block_state[15]};
data_out_new = data_in ^ block_state;
end // data_out_logic
//----------------------------------------------------------------
// qr_ctr
// Update logic for the quarterround counter, a monotonically
// increasing counter with reset.
//----------------------------------------------------------------
always @*
begin : qr_ctr
qr_ctr_new = 0;
qr_ctr_we = 0;
if (qr_ctr_rst)
begin
qr_ctr_new = 0;
qr_ctr_we = 1;
end
if (qr_ctr_inc)
begin
qr_ctr_new = qr_ctr_reg + 1'b1;
qr_ctr_we = 1;
end
end // qr_ctr
//----------------------------------------------------------------
// dr_ctr
// Update logic for the round counter, a monotonically
// increasing counter with reset.
//----------------------------------------------------------------
always @*
begin : dr_ctr
dr_ctr_new = 0;
dr_ctr_we = 0;
if (dr_ctr_rst)
begin
dr_ctr_new = 0;
dr_ctr_we = 1;
end
if (dr_ctr_inc)
begin
dr_ctr_new = dr_ctr_reg + 1'b1;
dr_ctr_we = 1;
end
end // dr_ctr
//----------------------------------------------------------------
// block_ctr
// Update logic for the 64-bit block counter, a monotonically
// increasing counter with reset.
//----------------------------------------------------------------
always @*
begin : block_ctr
block0_ctr_new = 32'h0;
block1_ctr_new = 32'h0;
block0_ctr_we = 0;
block1_ctr_we = 0;
if (block_ctr_set)
begin
block0_ctr_new = ctr[31 : 00];
block1_ctr_new = ctr[63 : 32];
block0_ctr_we = 1;
block1_ctr_we = 1;
end
if (block_ctr_inc)
begin
block0_ctr_new = block0_ctr_reg + 1;
block0_ctr_we = 1;
// Avoid chaining the 32-bit adders.
if (block0_ctr_reg == 32'hffffffff)
begin
block1_ctr_new = block1_ctr_reg + 1;
block1_ctr_we = 1;
end
end
end // block_ctr
//----------------------------------------------------------------
// chacha_ctrl_fsm
// Logic for the state machine controlling the core behaviour.
//----------------------------------------------------------------
always @*
begin : chacha_ctrl_fsm
init_state = 0;
update_state = 0;
update_output = 0;
qr_ctr_inc = 0;
qr_ctr_rst = 0;
dr_ctr_inc = 0;
dr_ctr_rst = 0;
block_ctr_inc = 0;
block_ctr_set = 0;
ready_new = 0;
ready_we = 0;
data_out_valid_new = 0;
data_out_valid_we = 0;
chacha_ctrl_new = CTRL_IDLE;
chacha_ctrl_we = 0;
case (chacha_ctrl_reg)
CTRL_IDLE:
begin
if (init)
begin
block_ctr_set = 1;
ready_new = 0;
ready_we = 1;
chacha_ctrl_new = CTRL_INIT;
chacha_ctrl_we = 1;
end
end
CTRL_INIT:
begin
init_state = 1;
qr_ctr_rst = 1;
dr_ctr_rst = 1;
chacha_ctrl_new = CTRL_ROUNDS;
chacha_ctrl_we = 1;
end
CTRL_ROUNDS:
begin
update_state = 1;
qr_ctr_inc = 1;
if (qr_ctr_reg == QR1)
begin
dr_ctr_inc = 1;
if (dr_ctr_reg == (rounds[4 : 1] - 1))
begin
chacha_ctrl_new = CTRL_FINALIZE;
chacha_ctrl_we = 1;
end
end
end
CTRL_FINALIZE:
begin
ready_new = 1;
ready_we = 1;
update_output = 1;
data_out_valid_new = 1;
data_out_valid_we = 1;
chacha_ctrl_new = CTRL_DONE;
chacha_ctrl_we = 1;
end
CTRL_DONE:
begin
if (init)
begin
ready_new = 0;
ready_we = 1;
data_out_valid_new = 0;
data_out_valid_we = 1;
block_ctr_set = 1;
chacha_ctrl_new = CTRL_INIT;
chacha_ctrl_we = 1;
end
else if (next)
begin
ready_new = 0;
ready_we = 1;
data_out_valid_new = 0;
data_out_valid_we = 1;
block_ctr_inc = 1;
chacha_ctrl_new = CTRL_INIT;
chacha_ctrl_we = 1;
end
end
default:
begin
end
endcase // case (chacha_ctrl_reg)
end // chacha_ctrl_fsm
endmodule // chacha_core
module chacha_qr(
input wire [31 : 0] a,
input wire [31 : 0] b,
input wire [31 : 0] c,
input wire [31 : 0] d,
output wire [31 : 0] a_prim,
output wire [31 : 0] b_prim,
output wire [31 : 0] c_prim,
output wire [31 : 0] d_prim
);
//----------------------------------------------------------------
// Wires.
//----------------------------------------------------------------
reg [31 : 0] internal_a_prim;
reg [31 : 0] internal_b_prim;
reg [31 : 0] internal_c_prim;
reg [31 : 0] internal_d_prim;
//----------------------------------------------------------------
// Concurrent connectivity for ports.
//----------------------------------------------------------------
assign a_prim = internal_a_prim;
assign b_prim = internal_b_prim;
assign c_prim = internal_c_prim;
assign d_prim = internal_d_prim;
//----------------------------------------------------------------
// qr
//
// The actual quarterround function.
//----------------------------------------------------------------
always @*
begin : qr
reg [31 : 0] a0;
reg [31 : 0] a1;
reg [31 : 0] b0;
reg [31 : 0] b1;
reg [31 : 0] b2;
reg [31 : 0] b3;
reg [31 : 0] c0;
reg [31 : 0] c1;
reg [31 : 0] d0;
reg [31 : 0] d1;
reg [31 : 0] d2;
reg [31 : 0] d3;
a0 = a + b;
d0 = d ^ a0;
d1 = {d0[15 : 0], d0[31 : 16]};
c0 = c + d1;
b0 = b ^ c0;
b1 = {b0[19 : 0], b0[31 : 20]};
a1 = a0 + b1;
d2 = d1 ^ a1;
d3 = {d2[23 : 0], d2[31 : 24]};
c1 = c0 + d3;
b2 = b1 ^ c1;
b3 = {b2[24 : 0], b2[31 : 25]};
internal_a_prim = a1;
internal_b_prim = b3;
internal_c_prim = c1;
internal_d_prim = d3;
end // qr
endmodule // chacha_qr