Make initial public release

This commit is contained in:
Joachim Strömbergson 2022-09-19 08:51:11 +02:00 committed by Daniel Lublin
commit 715de60f4a
251 changed files with 881225 additions and 0 deletions

View file

@ -0,0 +1,29 @@
# trng
Implementation of the FiGaRO TRNG for FPGAs
## Introduction
# figaro
## Status
First version completed. In testing. Use with caution.
## Introduction
This is a an implementation of the FiGaRO true random
number generator (TRNG) [1]. The main FPGA target is Lattice iCE40
UltraPlus, but adaption to other FPGAs should be easy to do.
## Implementation details
The implementation instantiates four FiRO and four GaRO modules. The
modules includes state sampling. The polynomials used for the
oscillators are given by equotions (9)..(16) in paper [1]. The eight
outputs are then XORed together to form a one bit random value.
The random bit value is sampled at a rate controlled by a 24 bit
divisor.
## References
[1] [True Random Number Generator Based on Fibonacci-Galois
Ring Oscillators for FPGA](https://www.mdpi.com/2076-3417/11/8/3330/pdf)

View file

@ -0,0 +1,129 @@
//======================================================================
//
// figaro.v
// --------
// Top level wrapper for the figaro core.
//
//
// Author: Joachim Strombergson
// Copyright (C) 2022 - Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
//
//======================================================================
`default_nettype none
module figaro(
input wire clk,
input wire reset_n,
input wire cs,
input wire we,
input wire [7 : 0] address,
input wire [31 : 0] write_data,
output wire [31 : 0] read_data,
output wire ready
);
//----------------------------------------------------------------
// Internal constant and parameter definitions.
//----------------------------------------------------------------
localparam ADDR_NAME0 = 8'h00;
localparam ADDR_NAME1 = 8'h01;
localparam ADDR_VERSION = 8'h02;
localparam ADDR_STATUS = 8'h09;
localparam STATUS_READY_BIT = 0;
localparam ADDR_SAMPLE_RATE = 8'h10;
localparam ADDR_ENTROPY = 8'h20;
localparam CORE_NAME0 = 32'h66696761; // "figa"
localparam CORE_NAME1 = 32'h726f2020; // "ro "
localparam CORE_VERSION = 32'h00000001;
//----------------------------------------------------------------
// Wires.
//----------------------------------------------------------------
reg core_read_entropy;
reg core_set_sample_rate;
wire [31 : 0] core_entropy;
wire core_ready;
reg [31 : 0] tmp_read_data;
reg tmp_ready;
//----------------------------------------------------------------
// Concurrent connectivity for ports etc.
//----------------------------------------------------------------
assign read_data = tmp_read_data;
assign ready = tmp_ready;
//----------------------------------------------------------------
// core instantiation.
//----------------------------------------------------------------
figaro_core core(
.clk(clk),
.reset_n(reset_n),
.read_entropy(core_read_entropy),
.set_sample_rate(core_set_sample_rate),
.sample_rate(write_data[23 : 0]),
.entropy(core_entropy),
.ready(core_ready)
);
//----------------------------------------------------------------
// api
//
// The interface command decoding logic.
//----------------------------------------------------------------
always @*
begin : api
core_read_entropy = 1'h0;
core_set_sample_rate = 1'h0;
tmp_read_data = 32'h0;
tmp_ready = 1'h0;
if (cs) begin
tmp_ready = 1'h1;
if (we) begin
if (address == ADDR_SAMPLE_RATE) begin
core_set_sample_rate = 1'h1;
end
end
else begin
if (address == ADDR_NAME0) begin
tmp_read_data = CORE_NAME0;
end
if (address == ADDR_NAME1) begin
tmp_read_data = CORE_NAME1;
end
if (address == ADDR_VERSION) begin
tmp_read_data = CORE_VERSION;
end
if (address == ADDR_STATUS) begin
tmp_read_data = {31'h0, core_ready};
end
if (address == ADDR_ENTROPY) begin
tmp_read_data = core_entropy;
core_read_entropy = 1'h1;
end
end
end
end // api
endmodule // figaro
//======================================================================
// EOF figaro.v
//======================================================================

View file

@ -0,0 +1,204 @@
//======================================================================
//
// figaro_core.v
// -----------
// FiGaRO based FIGARO for iCE40 device.
//
//
// Author: Joachim Strombergson
// Copyright (C) 2022 - Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
//
//======================================================================
module figaro_core(
input wire clk,
input wire reset_n,
input wire set_sample_rate,
input wire [23 : 0] sample_rate,
input wire read_entropy,
output wire [31 : 0] entropy,
output wire ready
);
//---------------------------------------------------------------
// Local parameters.
//---------------------------------------------------------------
localparam DEFAULT_SAMPLE_RATE = 24'h010000;
//---------------------------------------------------------------
// Registers.
//---------------------------------------------------------------
reg [23 : 0] sample_rate_ctr_reg;
reg [23 : 0] sample_rate_ctr_new;
reg [23 : 0] sample_rate_reg;
reg sample_rate_we;
reg [5 : 0] bit_ctr_reg;
reg [5 : 0] bit_ctr_new;
reg bit_ctr_rst;
reg bit_ctr_inc;
reg bit_ctr_we;
reg [31 : 0] entropy_reg;
reg [31 : 0] entropy_new;
reg entropy_we;
reg ready_reg;
reg ready_new;
reg ready_we;
//---------------------------------------------------------------
// Firo oscillator instances and XOR combined result.
//---------------------------------------------------------------
wire firo_ent[3 : 0];
wire firo_entropy;
firo #(.POLY(10'b1111110111)) firo0(.clk(clk), .entropy(firo_ent[0]));
firo #(.POLY(10'b1011111001)) firo1(.clk(clk), .entropy(firo_ent[1]));
firo #(.POLY(10'b1100000001)) firo2(.clk(clk), .entropy(firo_ent[2]));
firo #(.POLY(10'b1011111111)) firo3(.clk(clk), .entropy(firo_ent[3]));
assign firo_entropy = firo_ent[0] ^ firo_ent[1] ^
firo_ent[2] ^ firo_ent[3];
//---------------------------------------------------------------
// garo oscillator instances and XOR combined result.
//---------------------------------------------------------------
wire garo_ent[3 : 0];
wire garo_entropy;
garo #(.POLY(11'b11111101111)) garo0(.clk(clk), .entropy(garo_ent[0]));
garo #(.POLY(11'b10111110011)) garo1(.clk(clk), .entropy(garo_ent[1]));
garo #(.POLY(11'b11000000011)) garo2(.clk(clk), .entropy(garo_ent[2]));
garo #(.POLY(11'b10111111111)) garo3(.clk(clk), .entropy(garo_ent[3]));
assign garo_entropy = garo_ent[0] ^ garo_ent[1] ^
garo_ent[2] ^ garo_ent[3];
//---------------------------------------------------------------
// Assignments.
//---------------------------------------------------------------
assign ready = ready_reg;
assign entropy = entropy_reg;
//---------------------------------------------------------------
// reg_update
//---------------------------------------------------------------
always @(posedge clk)
begin : reg_update
if (!reset_n) begin
sample_rate_reg <= DEFAULT_SAMPLE_RATE;
sample_rate_ctr_reg <= 24'h0;
bit_ctr_reg <= 6'h0;
entropy_reg <= 32'h0;
ready_reg <= 1'h0;
end
else begin
sample_rate_ctr_reg <= sample_rate_ctr_new;
if (sample_rate_we) begin
sample_rate_reg <= sample_rate;
end
if (bit_ctr_we) begin
bit_ctr_reg <= bit_ctr_new;
end
if (entropy_we) begin
entropy_reg <= entropy_new;
end
if (ready_we) begin
ready_reg <= ready_new;
end
end
end
//---------------------------------------------------------------
// ready_logic
//
// After an entropy word has been read we wait 32 bits before
// setting ready again, indicating that a new word is ready.
//---------------------------------------------------------------
always @*
begin : ready_logic;
bit_ctr_new = 6'h0;
bit_ctr_we = 1'h0;
ready_new = 1'h0;
ready_we = 1'h0;
if (bit_ctr_reg >= 6'h20) begin
ready_new = 1'h1;
ready_we = 1'h1;
end
if (bit_ctr_rst) begin
bit_ctr_new = 6'h0;
bit_ctr_we = 1'h1;
ready_new = 1'h0;
ready_we = 1'h1;
end
else if (bit_ctr_inc) begin
if (bit_ctr_reg < 6'h24) begin
bit_ctr_new = bit_ctr_reg + 1'h1;
bit_ctr_we = 1'h1;
end
end
end
//---------------------------------------------------------------
// figaro_sample_logic
//
// Wait sample_rate_reg number of cycles between sampling a bit
// from the entropy source.
//---------------------------------------------------------------
always @*
begin : figaro_sample_logic
sample_rate_we = 1'h0;
bit_ctr_rst = 1'h0;
bit_ctr_inc = 1'h0;
entropy_we = 1'h0;
entropy_new = {entropy_reg[30 : 0], firo_entropy ^ garo_entropy};
if (read_entropy) begin
bit_ctr_rst = 1'h1;
sample_rate_ctr_new = 24'h0;
end
else if (set_sample_rate) begin
bit_ctr_rst = 1'h1;
sample_rate_we = 1'h1;
sample_rate_ctr_new = 24'h0;
end
else if (sample_rate_ctr_reg == sample_rate_reg) begin
sample_rate_ctr_new = 24'h0;
entropy_we = 1'h1;
bit_ctr_inc = 1'h1;
end
else begin
sample_rate_ctr_new = sample_rate_ctr_reg + 1'h1;
end
end
endmodule // figaro_core
//======================================================================
// EOF figaro_core.v
//======================================================================

View file

@ -0,0 +1,75 @@
//======================================================================
//
// firo.v
// ------
// Fibonacci Ring Oscillator with state sampling.
// The Fibonacci depth is 10 bits, and the bits are always sampled.
//
//
// Author: Joachim Strombergson
// Copyright (C) 2022 - Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
//
//======================================================================
`default_nettype none
module firo(
input wire clk,
output wire entropy
);
parameter POLY = 10'b1111111111;
//----------------------------------------------------------------
// Registers and wires.
//----------------------------------------------------------------
reg entropy_reg;
wire [10 : 0] f;
//---------------------------------------------------------------
// Combinational loop inverters.
//---------------------------------------------------------------
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv1 (.I0(f[0]), .O(f[1]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv2 (.I0(f[1]), .O(f[2]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv3 (.I0(f[2]), .O(f[3]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv4 (.I0(f[3]), .O(f[4]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv5 (.I0(f[4]), .O(f[5]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv6 (.I0(f[5]), .O(f[6]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv7 (.I0(f[6]), .O(f[7]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv8 (.I0(f[7]), .O(f[8]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv9 (.I0(f[8]), .O(f[9]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv10 (.I0(f[9]), .O(f[10]));
//---------------------------------------------------------------
// parameterized feedback logic.
//---------------------------------------------------------------
assign f[0] = (POLY[0] & f[1]) ^ (POLY[1] & f[2]) ^
(POLY[2] & f[3]) ^ (POLY[3] & f[4]) ^
(POLY[4] & f[5]) ^ (POLY[5] & f[6]) ^
(POLY[6] & f[7]) ^ (POLY[7] & f[8]) ^
(POLY[8] & f[9]) ^ (POLY[9] & f[10]);
//----------------------------------------------------------------
// Concurrent connectivity for ports etc.
//----------------------------------------------------------------
assign entropy = entropy_reg;
//---------------------------------------------------------------
// reg_update
//---------------------------------------------------------------
always @(posedge clk)
begin : reg_update
entropy_reg <= ^f;
end
endmodule // firo
//======================================================================
// EOF firo.v
//======================================================================

View file

@ -0,0 +1,85 @@
//======================================================================
//
// garo.v
// ------
// GaloisRing Oscillator with state sampling.
// The Galois depth is 11 bits, and the bits are always sampled.
//
//
// Author: Joachim Strombergson
// Copyright (C) 2022 - Tillitis AB
// SPDX-License-Identifier: GPL-2.0-only
//
//======================================================================
`default_nettype none
module garo(
input wire clk,
output wire entropy
);
parameter POLY = 11'b11111111111;
//----------------------------------------------------------------
// Registers and wires.
//----------------------------------------------------------------
reg entropy_reg;
wire [11 : 0] g;
wire [11 : 0] gp;
//---------------------------------------------------------------
// Combinational loop inverters.
//---------------------------------------------------------------
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv1 (.I0(g[0]), .O(gp[0]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv2 (.I0(g[1]), .O(gp[1]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv3 (.I0(g[2]), .O(gp[2]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv4 (.I0(g[3]), .O(gp[3]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv5 (.I0(g[4]), .O(gp[4]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv6 (.I0(g[5]), .O(gp[5]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv7 (.I0(g[6]), .O(gp[6]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv8 (.I0(g[7]), .O(gp[7]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv9 (.I0(g[8]), .O(gp[8]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv10 (.I0(g[9]), .O(gp[9]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv11 (.I0(g[10]), .O(gp[10]));
(* keep *) SB_LUT4 #(.LUT_INIT(1'b1)) osc_inv12 (.I0(g[11]), .O(gp[11]));
//---------------------------------------------------------------
// parameterized feedback logic.
//---------------------------------------------------------------
assign g[11] = gp[0];
assign g[10] = gp[11] ^ (POLY[10] & gp[0]);
assign g[9] = gp[10] ^ (POLY[9] & gp[0]);
assign g[8] = gp[9] ^ (POLY[8] & gp[0]);
assign g[7] = gp[8] ^ (POLY[7] & gp[0]);
assign g[6] = gp[7] ^ (POLY[6] & gp[0]);
assign g[5] = gp[6] ^ (POLY[5] & gp[0]);
assign g[4] = gp[5] ^ (POLY[4] & gp[0]);
assign g[3] = gp[4] ^ (POLY[3] & gp[0]);
assign g[2] = gp[3] ^ (POLY[2] & gp[0]);
assign g[1] = gp[2] ^ (POLY[1] & gp[0]);
assign g[0] = gp[1] ^ (POLY[0] & gp[0]);
//----------------------------------------------------------------
// Concurrent connectivity for ports etc.
//----------------------------------------------------------------
assign entropy = entropy_reg;
//---------------------------------------------------------------
// reg_update
//---------------------------------------------------------------
always @(posedge clk)
begin : reg_update
entropy_reg <= ^g;
end
endmodule // garo
//======================================================================
// EOF garo.v
//======================================================================