feat(ntt): implement synchronous NTT core with Barrett modular reduction

Phase 2.1: Merged Path00+Path01 NTT engine.
- barrett_mul.v: Barrett modular multiplication (a·b mod 3329)
- butterfly_unit.v: Cooley-Tukey/Gentleman-Sande butterfly
- zeta_rom.v: 128-entry ROM with bit-reversed roots of unity
- ntt_core.v: 7-layer NTT FSM, 256×12-bit register file
- ntt_sync.v: valid/ready streaming wrapper

Verified: 13/13 vectors bit-exact vs Python NTT/NTTInverse
This commit is contained in:
2026-06-24 22:51:14 +08:00
parent 5941fee980
commit c4cd10c2c1
8 changed files with 765 additions and 0 deletions

View File

@@ -0,0 +1,67 @@
// butterfly_unit.v - Cooley-Tukey / Gentleman-Sande butterfly
//
// Computes one butterfly operation for NTT or inverse NTT.
//
// Parameters:
// Q = 3329 (prime modulus)
//
// Forward NTT (mode=0):
// t = zeta * b mod Q (via barrett_mul)
// a_out = (a + t) mod Q
// b_out = (a - t) mod Q
//
// Inverse NTT (mode=1):
// a_out = (a + b) mod Q
// diff = (b - a) mod Q (handled as: if b >= a: b-a; else: b-a+Q)
// b_out = zeta * diff mod Q (via barrett_mul)
//
// Pure combinational.
module butterfly_unit (
input [11:0] a,
input [11:0] b,
input [11:0] zeta,
input mode, // 0 = forward NTT, 1 = inverse NTT
output [11:0] a_out,
output [11:0] b_out
);
localparam Q = 3329;
// Barrett modular multiplication: zeta * mul_data mod Q
wire [11:0] mul_data; // what to multiply with zeta
wire [11:0] mul_result; // result of barrett_mul(zeta, mul_data)
// Forward: mul_data = b, t = zeta * b mod Q
// Inverse: mul_data = (b - a) mod Q positive
assign mul_data = (mode == 1'b0) ? b : ((b >= a) ? (b - a) : (b - a + Q));
barrett_mul u_barrett (
.a (zeta),
.b (mul_data),
.product (mul_result)
);
// ---- a_out computation ----
// Forward: a_out = (a + t) mod Q
// Inverse: a_out = (a + b) mod Q
wire [12:0] a_sum;
wire [11:0] add_val;
assign add_val = (mode == 1'b0) ? mul_result : b;
assign a_sum = {1'b0, a} + {1'b0, add_val};
// a_sum - Q produces 13-bit result; we only need lower 12 bits since
// a_sum >= Q guarantees the result < Q < 2^12
wire [11:0] a_sub_12;
assign a_sub_12 = a_sum[11:0] - Q[11:0];
wire [11:0] a_result = (a_sum >= Q) ? a_sub_12 : a_sum[11:0];
assign a_out = a_result;
// ---- b_out computation ----
// Forward: b_out = (a - t) mod Q if a >= t: a-t; else: a-t+Q
// Inverse: b_out = t (mul_result, which is zeta * (b-a) mod Q)
wire [11:0] sub_val;
assign sub_val = mul_result;
wire [11:0] sub_result;
assign sub_result = (a >= sub_val) ? (a - sub_val) : (a - sub_val + Q);
assign b_out = (mode == 1'b0) ? sub_result : mul_result;
endmodule