// comp_decomp_sync.v - ML-KEM coefficient compression/decompression // // Streaming: one coefficient per cycle through pipeline_reg. // mode=0: compress — round((2^d * x) / Q) mod 2^d // mode=1: decompress — round((Q * x) / 2^d) mod Q // Uses round-half-up (round(2.5)=3, round(3.5)=4). // Integer arithmetic: // compress: (x * 2^d + Q/2) / Q, lower d bits as result // decompress: (x * Q + 2^(d-1)) / 2^d, result (always < Q) `include "sync_rtl/common/defines.vh" (* use_dsp = "no" *) module comp_decomp_sync ( input clk, input rst_n, input [11:0] coeff_in, input [4:0] d, input mode, // 0=compress, 1=decompress input valid_i, output ready_o, output [11:0] coeff_out, output valid_o, input ready_i ); // 2^d for d in {4,5,10,11}; fits in 12 bits (max 2048) wire [11:0] two_pow_d; assign two_pow_d = 12'd1 << d; // Product: 12-bit * 12-bit = max 2048*3328 = 6,815,744 → 23 bits (use 24) wire [23:0] product; // compress: x * 2^d; decompress: x * Q assign product = mode ? {12'b0, coeff_in} * {12'b0, 12'(`Q)} : {12'b0, coeff_in} * {12'b0, two_pow_d}; // Rounding offset: compress→Q/2=1664; decompress→2^(d-1) wire [11:0] round_off; assign round_off = mode ? (two_pow_d >> 1) : 12'd1664; // Dividend = product + round_off (max ~ 6,817,408 fits in 24 bits) wire [23:0] dividend; assign dividend = product + {12'b0, round_off}; // Divisor: compress→Q=3329; decompress→2^d wire [11:0] divisor; assign divisor = mode ? two_pow_d : 12'(`Q); // Integer division (both ops positive → floor) // Quotient is computed as 24b (widest operand) but fits in 12b /* verilator lint_off WIDTHTRUNC */ wire [11:0] div_result; assign div_result = dividend / {12'b0, divisor}; /* verilator lint_on WIDTHTRUNC */ // Final modular reduction // compress: lower d bits (mask with 2^d - 1) // decompress: result < Q always, but apply mod Q for safety wire [11:0] mod_result; assign mod_result = mode ? (div_result % 12'(`Q)) : (div_result & (two_pow_d - 1'b1)); // Pipeline through valid/ready stage pipeline_reg #(.DW(12)) u_pipe ( .clk (clk), .rst_n (rst_n), .data_i (mod_result), .valid_i(valid_i), .ready_o(ready_o), .data_o (coeff_out), .valid_o(valid_o), .ready_i(ready_i) ); endmodule