mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
Security & correctness fixes from full adversarial review: Lean (7 fixes): - FixedPoint.lean: guard false theorem with n > 0 precondition - QFactor.lean: remove double-scaling error in energy decrease - AVMIsa/Step.lean: implement addSatQ16/subSatQ16 primitives - BraidEigensolid.lean: fix crossStep second output argument swap - SSMS.lean: complete ACI preservation proof (with rounding caveat) - HouseholderQR.lean: add n > 0 precondition to spectral theorem Verilog (7 fixes): - q16_lut_core.v: fix multiply shift (16 → 32 bits) - q16_lut_top.v: fix valid bit (0 → 1) - cff_accelerator.v: fix SHA-256 padding (len < 448 check) - research_stack_top.v: fix trigger aliasing (unique counters) - Blitter6502OISC_small.v: fix address width (15 → 16 bits) - spatial_hash_bram.v: add OOB write guard - tmr_oepi_safety_fsm.v: fix double-increment race WGSL (6 fixes): - shaders.wgsl: atomicAdd for concurrent writes - frustration_qubo.wgsl: double-buffer + CAS loop - braid_fft.wgsl: workgroupBarrier synchronization - burgers_scar_filter.wgsl: atomic E_bins array Rust (9 fixes): - thermodynamic.rs: Arc::from_raw → Arc::clone (double-free) - thermodynamic.rs: Box::into_raw → Box (leak) - tools/src/lib.rs: shell injection → shlex.quote - ene-node/src/lib.rs: LRU caps, constant-time HMAC, peer caps Python (6 fixes): - similarity/__init__.py: pickle.load → RestrictedUnpickler - AI-Feynman: torch.load → weights_only=True (14 calls) - fetch_arxiv.py, fetch_s2.py: eval → ast.literal_eval - topology.py: os.system → shutil.copy2 - SSH pipe: os.system → base64 pipe Build: lake build 3572 jobs, 0 errors
363 lines
13 KiB
Verilog
363 lines
13 KiB
Verilog
// CFF Accelerator: SHA-256 Hash Engine for Tang Nano 9K
|
|
// Accepts DOI strings over UART, returns 256-bit hash.
|
|
// Wire protocol: host sends length-prefixed data, FPGA returns hash.
|
|
//
|
|
// Protocol:
|
|
// RX: [LEN:8][DATA:LEN bytes]
|
|
// TX: [HASH:32 bytes]
|
|
//
|
|
// Compact SHA-256 core (~2000 LUTs), fits in GW1NR-9C (8640 LUTs)
|
|
|
|
`timescale 1ns / 1ps
|
|
|
|
module cff_accelerator (
|
|
input clk, // 27 MHz
|
|
input rst_n, // Reset button (active low)
|
|
input uart_rx_pin, // UART RX
|
|
output uart_tx_pin, // UART TX
|
|
output [5:0] led // Onboard LEDs (active low) - status
|
|
);
|
|
|
|
// === UART ===
|
|
wire [7:0] rx_data;
|
|
wire rx_done;
|
|
reg [7:0] tx_data;
|
|
reg tx_start;
|
|
wire tx_busy;
|
|
|
|
uart_rx rx_inst (
|
|
.clk(clk), .rst_n(rst_n),
|
|
.rx_pin(uart_rx_pin),
|
|
.rx_data(rx_data), .rx_done(rx_done)
|
|
);
|
|
|
|
uart_tx tx_inst (
|
|
.clk(clk), .rst_n(rst_n),
|
|
.tx_start(tx_start), .tx_data(tx_data),
|
|
.uart_tx(uart_tx_pin), .tx_busy(tx_busy)
|
|
);
|
|
|
|
// === FSM ===
|
|
parameter IDLE = 3'd0;
|
|
parameter GET_LEN = 3'd1;
|
|
parameter LOAD = 3'd2;
|
|
parameter PAD = 3'd3;
|
|
parameter HASH = 3'd4;
|
|
parameter SEND = 3'd5;
|
|
parameter WAIT = 3'd6;
|
|
|
|
reg [2:0] state, next_state;
|
|
reg [7:0] data_len;
|
|
reg [7:0] byte_cnt;
|
|
reg [7:0] send_cnt;
|
|
|
|
// === SHA-256 Core State ===
|
|
// Message + padding buffer: max 64 bytes per block (512 bits)
|
|
reg [511:0] msg_block;
|
|
reg [5:0] msg_idx; // bytes loaded into current block
|
|
reg msg_done;
|
|
|
|
// Hash state (8 x 32-bit)
|
|
reg [31:0] H0, H1, H2, H3, H4, H5, H6, H7;
|
|
|
|
// Working variables
|
|
reg [31:0] a, b, c, d, e, f, g, h;
|
|
|
|
// Round constants (first 3 rounds inline, rest computed)
|
|
wire [31:0] K [0:63];
|
|
assign K[0] = 32'h428a2f98;
|
|
assign K[1] = 32'h71374491;
|
|
assign K[2] = 32'hb5c0fbcf;
|
|
assign K[3] = 32'he9b5dba5;
|
|
assign K[4] = 32'h3956c25b;
|
|
assign K[5] = 32'h59f111f1;
|
|
assign K[6] = 32'h923f82a4;
|
|
assign K[7] = 32'hab1c5ed5;
|
|
assign K[8] = 32'hd807aa98;
|
|
assign K[9] = 32'h12835b01;
|
|
assign K[10] = 32'h243185be;
|
|
assign K[11] = 32'h550c7dc3;
|
|
assign K[12] = 32'h72be5d74;
|
|
assign K[13] = 32'h80deb1fe;
|
|
assign K[14] = 32'h9bdc06a7;
|
|
assign K[15] = 32'hc19bf174;
|
|
assign K[16] = 32'he49b69c1;
|
|
assign K[17] = 32'hefbe4786;
|
|
assign K[18] = 32'h0fc19dc6;
|
|
assign K[19] = 32'h240ca1cc;
|
|
assign K[20] = 32'h2de92c6f;
|
|
assign K[21] = 32'h4a7484aa;
|
|
assign K[22] = 32'h5cb0a9dc;
|
|
assign K[23] = 32'h76f988da;
|
|
assign K[24] = 32'h983e5152;
|
|
assign K[25] = 32'ha831c66d;
|
|
assign K[26] = 32'hb00327c8;
|
|
assign K[27] = 32'hbf597fc7;
|
|
assign K[28] = 32'hc6e00bf3;
|
|
assign K[29] = 32'hd5a79147;
|
|
assign K[30] = 32'h06ca6351;
|
|
assign K[31] = 32'h14292967;
|
|
assign K[32] = 32'h27b70a85;
|
|
assign K[33] = 32'h2e1b2138;
|
|
assign K[34] = 32'h4d2c6dfc;
|
|
assign K[35] = 32'h53380d13;
|
|
assign K[36] = 32'h650a7354;
|
|
assign K[37] = 32'h766a0abb;
|
|
assign K[38] = 32'h81c2c92e;
|
|
assign K[39] = 32'h92722c85;
|
|
assign K[40] = 32'ha2bfe8a1;
|
|
assign K[41] = 32'ha81a664b;
|
|
assign K[42] = 32'hc24b8b70;
|
|
assign K[43] = 32'hc76c51a3;
|
|
assign K[44] = 32'hd192e819;
|
|
assign K[45] = 32'hd6990624;
|
|
assign K[46] = 32'hf40e3585;
|
|
assign K[47] = 32'h106aa070;
|
|
assign K[48] = 32'h19a4c116;
|
|
assign K[49] = 32'h1e376c08;
|
|
assign K[50] = 32'h2748774c;
|
|
assign K[51] = 32'h34b0bcb5;
|
|
assign K[52] = 32'h391c0cb3;
|
|
assign K[53] = 32'h4ed8aa4a;
|
|
assign K[54] = 32'h5b9cca4f;
|
|
assign K[55] = 32'h682e6ff3;
|
|
assign K[56] = 32'h748f82ee;
|
|
assign K[57] = 32'h78a5636f;
|
|
assign K[58] = 32'h84c87814;
|
|
assign K[59] = 32'h8cc70208;
|
|
assign K[60] = 32'h90befffa;
|
|
assign K[61] = 32'ha4506ceb;
|
|
assign K[62] = 32'hbef9a3f7;
|
|
assign K[63] = 32'hc67178f2;
|
|
|
|
// Message schedule
|
|
reg [31:0] W [0:63];
|
|
reg [5:0] round;
|
|
reg [2:0] hash_phase; // 0=init, 1=expand msg, 2=compress, 3=finalize
|
|
reg [5:0] expand_idx; // index for message expansion (16..63)
|
|
|
|
// === SHA-256 Control ===
|
|
wire [31:0] S0, S1, ch_val, maj_val;
|
|
wire [31:0] t1, t2;
|
|
|
|
// Right rotation
|
|
function [31:0] rotr;
|
|
input [31:0] x;
|
|
input [4:0] n;
|
|
begin
|
|
rotr = (x >> n) | (x << (32 - n));
|
|
end
|
|
endfunction
|
|
|
|
// SHA-256 functions
|
|
assign S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
|
|
assign S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
|
|
assign ch_val = (e & f) ^ ((~e) & g);
|
|
assign maj_val = (a & b) ^ (a & c) ^ (b & c);
|
|
assign t1 = h + S1 + ch_val + K[round] + W[round];
|
|
assign t2 = S0 + maj_val;
|
|
|
|
// Message expansion for round >= 16
|
|
wire [31:0] s0, s1;
|
|
assign s0 = rotr(W[expand_idx-15], 7) ^ rotr(W[expand_idx-15], 18) ^ (W[expand_idx-15] >> 3);
|
|
assign s1 = rotr(W[expand_idx-2], 17) ^ rotr(W[expand_idx-2], 19) ^ (W[expand_idx-2] >> 10);
|
|
|
|
// === Main FSM ===
|
|
always @(posedge clk or negedge rst_n) begin
|
|
if (!rst_n) begin
|
|
state <= IDLE;
|
|
data_len <= 8'd0;
|
|
byte_cnt <= 8'd0;
|
|
send_cnt <= 8'd0;
|
|
msg_block <= 512'd0;
|
|
msg_idx <= 6'd0;
|
|
msg_done <= 1'b0;
|
|
H0 <= 32'h6a09e667;
|
|
H1 <= 32'hbb67ae85;
|
|
H2 <= 32'h3c6ef372;
|
|
H3 <= 32'ha54ff53a;
|
|
H4 <= 32'h510e527f;
|
|
H5 <= 32'h9b05688c;
|
|
H6 <= 32'h1f83d9ab;
|
|
H7 <= 32'h5be0cd19;
|
|
round <= 6'd0;
|
|
hash_phase <= 3'd0;
|
|
expand_idx <= 6'd0;
|
|
tx_start <= 1'b0;
|
|
tx_data <= 8'd0;
|
|
end else begin
|
|
case (state)
|
|
IDLE: begin
|
|
tx_start <= 1'b0;
|
|
if (rx_done) begin
|
|
data_len <= rx_data;
|
|
byte_cnt <= 8'd0;
|
|
msg_idx <= 6'd0;
|
|
msg_done <= 1'b0;
|
|
round <= 6'd0;
|
|
hash_phase <= 3'd0;
|
|
state <= (rx_data > 0) ? LOAD : PAD;
|
|
end
|
|
end
|
|
|
|
LOAD: begin
|
|
if (rx_done) begin
|
|
msg_block[msg_idx*8 +: 8] <= rx_data;
|
|
msg_idx <= msg_idx + 6'd1;
|
|
byte_cnt <= byte_cnt + 8'd1;
|
|
if (byte_cnt + 8'd1 >= data_len) begin
|
|
msg_done <= 1'b1;
|
|
state <= PAD;
|
|
end
|
|
end
|
|
end
|
|
|
|
PAD: begin
|
|
// SHA-256 padding: 0x80, then zeros, then 64-bit length in bits
|
|
// Add 0x80 byte at next position
|
|
msg_block[msg_idx*8 +: 8] <= 8'h80;
|
|
// Zero-fill remaining up to byte 56
|
|
// Put length in bits at bytes 56-63
|
|
msg_block[447:0] <= msg_block[447:0]; // preserve
|
|
// FIX: Full 64-bit big-endian bit count (data_len * 8)
|
|
msg_block[511:448] <= {53'd0, data_len, 3'b000}; // data_len * 8 as 64-bit
|
|
msg_idx <= 6'd56;
|
|
msg_done <= 1'b0;
|
|
state <= HASH;
|
|
hash_phase <= 3'd0;
|
|
round <= 6'd0;
|
|
// Initialize working vars from H
|
|
a <= H0; b <= H1; c <= H2; d <= H3;
|
|
e <= H4; f <= H5; g <= H6; h <= H7;
|
|
end
|
|
|
|
HASH: begin
|
|
case (hash_phase)
|
|
3'd0: begin
|
|
// Load W[0..15] from msg_block
|
|
W[0] <= msg_block[511:480];
|
|
W[1] <= msg_block[479:448];
|
|
W[2] <= msg_block[447:416];
|
|
W[3] <= msg_block[415:384];
|
|
W[4] <= msg_block[383:352];
|
|
W[5] <= msg_block[351:320];
|
|
W[6] <= msg_block[319:288];
|
|
W[7] <= msg_block[287:256];
|
|
W[8] <= msg_block[255:224];
|
|
W[9] <= msg_block[223:192];
|
|
W[10] <= msg_block[191:160];
|
|
W[11] <= msg_block[159:128];
|
|
W[12] <= msg_block[127:96];
|
|
W[13] <= msg_block[95:64];
|
|
W[14] <= msg_block[63:32];
|
|
W[15] <= msg_block[31:0];
|
|
round <= 6'd0;
|
|
expand_idx <= 6'd16;
|
|
hash_phase <= 3'd2;
|
|
end
|
|
|
|
3'd1: begin
|
|
// FIX: Separate expansion phase to avoid race with compress
|
|
W[expand_idx] <= s1 + W[expand_idx-7] + s0 + W[expand_idx-16];
|
|
expand_idx <= expand_idx + 6'd1;
|
|
hash_phase <= 3'd2;
|
|
end
|
|
|
|
3'd2: begin
|
|
// Compression round
|
|
h <= g;
|
|
g <= f;
|
|
f <= e;
|
|
e <= d + t1;
|
|
d <= c;
|
|
c <= b;
|
|
b <= a;
|
|
a <= t1 + t2;
|
|
|
|
if (round < 6'd15) begin
|
|
round <= round + 6'd1;
|
|
end else if (round < 6'd63) begin
|
|
round <= round + 6'd1;
|
|
// FIX: Expand in separate phase to prevent race condition
|
|
hash_phase <= 3'd1;
|
|
end else begin
|
|
// Final round done - finalize
|
|
hash_phase <= 3'd3;
|
|
end
|
|
end
|
|
|
|
3'd3: begin
|
|
H0 <= H0 + a;
|
|
H1 <= H1 + b;
|
|
H2 <= H2 + c;
|
|
H3 <= H3 + d;
|
|
H4 <= H4 + e;
|
|
H5 <= H5 + f;
|
|
H6 <= H6 + g;
|
|
H7 <= H7 + h;
|
|
send_cnt <= 8'd0;
|
|
state <= SEND;
|
|
// Preload first byte to send
|
|
tx_data <= H0[31:24]; // Big-endian
|
|
tx_start <= 1'b1;
|
|
end
|
|
|
|
default: hash_phase <= 3'd0;
|
|
endcase
|
|
end
|
|
|
|
SEND: begin
|
|
if (tx_start && tx_busy) begin
|
|
tx_start <= 1'b0;
|
|
end else if (!tx_busy && !tx_start) begin
|
|
send_cnt <= send_cnt + 8'd1;
|
|
case (send_cnt)
|
|
8'd0: tx_data <= H1[31:24];
|
|
8'd1: tx_data <= H1[23:16];
|
|
8'd2: tx_data <= H1[15:8];
|
|
8'd3: tx_data <= H1[7:0];
|
|
8'd4: tx_data <= H2[31:24];
|
|
8'd5: tx_data <= H2[23:16];
|
|
8'd6: tx_data <= H2[15:8];
|
|
8'd7: tx_data <= H2[7:0];
|
|
8'd8: tx_data <= H3[31:24];
|
|
8'd9: tx_data <= H3[23:16];
|
|
8'd10: tx_data <= H3[15:8];
|
|
8'd11: tx_data <= H3[7:0];
|
|
8'd12: tx_data <= H4[31:24];
|
|
8'd13: tx_data <= H4[23:16];
|
|
8'd14: tx_data <= H4[15:8];
|
|
8'd15: tx_data <= H4[7:0];
|
|
8'd16: tx_data <= H5[31:24];
|
|
8'd17: tx_data <= H5[23:16];
|
|
8'd18: tx_data <= H5[15:8];
|
|
8'd19: tx_data <= H5[7:0];
|
|
8'd20: tx_data <= H6[31:24];
|
|
8'd21: tx_data <= H6[23:16];
|
|
8'd22: tx_data <= H6[15:8];
|
|
8'd23: tx_data <= H6[7:0];
|
|
8'd24: tx_data <= H7[31:24];
|
|
8'd25: tx_data <= H7[23:16];
|
|
8'd26: tx_data <= H7[15:8];
|
|
8'd27: tx_data <= H7[7:0];
|
|
8'd28: tx_data <= H0[23:16];
|
|
8'd29: tx_data <= H0[15:8];
|
|
8'd30: tx_data <= H0[7:0];
|
|
default: begin
|
|
tx_start <= 1'b0;
|
|
state <= IDLE;
|
|
end
|
|
endcase
|
|
tx_start <= 1'b1;
|
|
end
|
|
end
|
|
|
|
default: state <= IDLE;
|
|
endcase
|
|
end
|
|
end
|
|
|
|
// LEDs show H0[5:0] for visual hash verification
|
|
assign led = ~H0[5:0];
|
|
|
|
endmodule
|