feat: add four 90-ring entropy generators with spatial and temporal XOR (FPGA v3)

This commit is contained in:
randogoth 2026-10-25 13:23:27 +02:00
parent 504b00752a
commit 585e755c66
9 changed files with 389 additions and 217 deletions

View file

@ -0,0 +1,92 @@
// One entropy generator: RINGS ring oscillators whose enhanced outputs are each sampled
// every clock and XORed together (spatial XOR, pipelined), then XORed over `temporal`
// consecutive clocks. The output bit is held for `temporal` clocks, so capturing it with
// decimation = temporal yields every output bit exactly once.
//
// XOR combining multiplies the relative predictabilities (2P-1) of independent inputs, so
// the ring count and temporal factor set the residual bias and correlation of the output.
//
// A selected ring's sampled outputs and its raw tap are exposed for characterization.
module entropy_generator #(
parameter RINGS = 90 // at most 256 (four 4:1 XOR stages)
) (
input wire clk,
input wire enable, // low stops all rings
input wire [3:0] temporal, // consecutive bits XORed per output bit, 1-8
input wire [7:0] ring_select, // ring exposed on the characterization outputs
output reg out_bit, // processed output, held for `temporal` clocks
output wire spatial_bit, // XOR of all rings, one per clock
output reg ring_enhanced,
output reg ring_tap,
output wire ring_raw_tap // unsynchronized, for frequency counting
);
wire [RINGS-1:0] raw_enhanced, raw_tap;
genvar i;
generate
for (i = 0; i < RINGS; i = i + 1) begin : ring
ring_osc #(.LENGTH(9 + 3 * (i % 3))) osc (
.enable(enable), .first_tap(raw_tap[i]), .enhanced(raw_enhanced[i])
);
end
endgenerate
// sample_raw catches the asynchronous ring signals and may go metastable;
// sample_sync resolves it. The SDC file cuts timing into sample_raw.
reg [RINGS-1:0] sample_raw, sample_sync, tap_raw, tap_sync;
always @(posedge clk) begin
sample_raw <= raw_enhanced;
sample_sync <= sample_raw;
tap_raw <= raw_tap;
tap_sync <= tap_raw;
end
// Spatial XOR: four registered stages of 4-input XORs (256 -> 64 -> 16 -> 4 -> 1).
reg [255:0] level0;
reg [63:0] level1;
reg [15:0] level2;
reg [3:0] level3;
reg level4;
integer j;
always @(*) begin
level0 = 256'd0;
level0[RINGS-1:0] = sample_sync;
end
always @(posedge clk) begin
for (j = 0; j < 64; j = j + 1) level1[j] <= ^level0[4*j +: 4];
for (j = 0; j < 16; j = j + 1) level2[j] <= ^level1[4*j +: 4];
for (j = 0; j < 4; j = j + 1) level3[j] <= ^level2[4*j +: 4];
level4 <= ^level3;
end
assign spatial_bit = level4;
// Temporal XOR over `temporal` consecutive spatial bits.
reg [3:0] phase = 4'd0;
reg accumulator = 1'b0;
wire last = (phase >= temporal - 4'd1) || (temporal == 4'd0);
always @(posedge clk) begin
if (last) begin
out_bit <= accumulator ^ spatial_bit;
accumulator <= 1'b0;
phase <= 4'd0;
end else begin
accumulator <= accumulator ^ spatial_bit;
phase <= phase + 4'd1;
end
end
// Characterization taps
always @(posedge clk) begin
ring_enhanced <= sample_sync[ring_select];
ring_tap <= tap_sync[ring_select];
end
assign ring_raw_tap = raw_tap[ring_select];
endmodule