@@ -1,18 +1,12 @@
// comp_decomp_sync . v - ML - KEM coefficient compression / decompression
// comp_decomp_sync . v - ML - KEM coefficient compression / decompression
//
//
// Streaming : one coefficient per cycle through pipeline_reg .
// Streaming : one coefficient per cycle through pipeline_reg .
// mode = 0 : compress - round ( ( 2 ^ d * x ) / Q ) mod 2 ^ d
// mode = 0 : compress — round ( ( 2 ^ d * x ) / Q ) mod 2 ^ d
// mode = 1 : decompress - round ( ( Q * x ) / 2 ^ d ) mod Q
// mode = 1 : decompress — round ( ( Q * x ) / 2 ^ d ) mod Q
// Uses round - half - up ( round ( 2 . 5 ) = 3 , round ( 3 . 5 ) = 4 ) .
// Uses round - half - up ( round ( 2 . 5 ) = 3 , round ( 3 . 5 ) = 4 ) .
// Integer arithmetic :
// Integer arithmetic :
// compress : ( x * 2 ^ d + Q / 2 ) / Q , lower d bits as result
// compress : ( x * 2 ^ d + Q / 2 ) / Q , lower d bits as result
// decompress : ( x * Q + 2 ^ ( d - 1 ) ) / 2 ^ d , result mod Q
// decompress : ( x * Q + 2 ^ ( d - 1 ) ) / 2 ^ d , result ( always < Q )
//
// Division by Q = 3329 replaced with Barrett multiplication + correction :
// floor ( x / Q ) ≈ ( x * 5039 ) > > 24 ( 5039 = floor ( 2 ^ 24 / 3329 ) )
// Correction : if x - q_approx * Q > = Q , add 1 to quotient .
// Q * 5039 = 16 , 774 , 831 < 2 ^ 24 , so Barrett may under - estimate by 1 .
// Q = 3329 = 2048 + 512 + 256 + 1 , so q * Q uses 3 shifts + add ( no 2nd multiplier ) .
` include " sync_rtl/common/defines.vh "
` include " sync_rtl/common/defines.vh "
@@ -30,58 +24,43 @@ module comp_decomp_sync (
input ready_i
input ready_i
) ;
) ;
wire [ 11 : 0 ] two_pow_d = 12'd1 < < d ;
// 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 ;
// p roduct: 12b * 12b = max 2048 * 3328 = 6 , 815 , 744 → 23b , pad to 24b
// P roduct: 12 - bit * 12- bit = max 2048 * 3328 = 6 , 815 , 744 → 23 bits ( use 24)
wire [ 23 : 0 ] product = mode ? { 12'b0 , coeff_in } * { 12'b0 , 12' ( ` Q ) }
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 } ;
: { 12'b0 , coeff_in } * { 12'b0 , two_pow_d } ;
wire [ 11 : 0 ] r ound_off = mode ? ( two_pow_d > > 1 ) : 12'd1664 ;
// R ounding offset : compress → Q / 2 = 1664 ; decompress → 2 ^ ( d - 1 )
wire [ 11 : 0 ] round_off ;
assign round_off = mode ? ( two_pow_d > > 1 ) : 12'd1664 ;
wire [ 23 : 0 ] d ividend = product + { 12'b0 , round_off } ;
// D ividend = 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
// Barrett : floor ( x / Q ) ≈ ( x * 5039 ) > > 24
wire [ 11 : 0 ] divisor ;
// M = floor ( 2 ^ 24 / Q ) = 5039
assign divisor = mode ? two_pow_d : 12' ( ` Q ) ;
// M * Q = 16 , 774 , 831 < 2 ^ 24 → floor ( x / Q ) may be 1 too low
// Correction : remainder = x - q_approx * Q ; if rem > = Q , q → q + 1
// Q * 5039 fails at : k * 2385 > = 2 ^ 24 → k > = 7033 ; max k ≈ 2047 → safe
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
wire [ 36 : 0 ] barrett_prod = dividend * 13'd5039 ; // 24 × 13 = 37b
wire [ 11 : 0 ] q_approx = barrett_prod [ 35 : 24 ] ; // quotient estimate
// q * Q = q * 2048 + q * 512 + q * 256 + q ( 3329 = 2048 + 512 + 256 + 1 )
wire [ 23 : 0 ] q_times_Q = ( { q_approx , 11'd0 } )
+ ( { q_approx , 9'd0 } )
+ ( { q_approx , 8'd0 } )
+ q_approx ;
wire [ 24 : 0 ] delta = { 1'b0 , dividend } - { 1'b0 , q_times_Q } ; // 25b
wire [ 11 : 0 ] comp_q = q_approx + ( delta > = { 13'b0 , 12' ( ` Q ) } ) ;
// lower d bits = compressed result
wire [ 11 : 0 ] comp_res = comp_q & ( { 12'b0 , two_pow_d } - 1'b1 ) ;
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Integer division ( both ops positive → floor )
// Decompress : dividend > > d ( free ) , then % Q via Barrett
// Quotient is computed as 24b ( widest operand ) but fits in 12b
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
/* verilator lint_off WIDTHTRUNC * /
wire [ 23 : 0 ] dec_sh = dividend > > d ;
wire [ 11 : 0 ] div_result ;
wire [ 36 : 0 ] dm_prod = dec_sh * 13'd5039 ;
assign div_result = dividend / { 12'b0 , divisor } ;
wire [ 11 : 0 ] dm_qe = dm_prod [ 35 : 24 ] ;
/* verilator lint_on WIDTHTRUNC * /
wire [ 23 : 0 ] dm_qQ = ( { dm_qe , 11'd0 } )
+ ( { dm_qe , 9'd0 } )
+ ( { dm_qe , 8'd0 } )
+ dm_qe ;
wire [ 24 : 0 ] dm_del = { 1'b0 , dec_sh } - { 1'b0 , dm_qQ } ;
// divide by Q , take remainder : r = x - q * Q
wire [ 12 : 0 ] dm_q = dm_qe + ( dm_del > = { 13'b0 , 12' ( ` Q ) } ) ; // corr quotient
// actual remainder = dec_sh - dm_q * Q
wire [ 23 : 0 ] dm_corrQ = ( { dm_q , 11'd0 } ) + ( { dm_q , 9'd0 } ) + ( { dm_q , 8'd0 } ) + dm_q ;
wire [ 24 : 0 ] dm_rem = { 1'b0 , dec_sh } - { 1'b0 , dm_corrQ } ;
// dm_rem < Q * 2 ( Barrett gives exact quotient after correction ) , one cond - sub
wire [ 11 : 0 ] dec_mod = ( dm_rem > = { 13'b0 , 12' ( ` Q ) } )
? ( dm_rem [ 11 : 0 ] - 12' ( ` Q ) )
: dm_rem [ 11 : 0 ] ;
wire [ 11 : 0 ] mod_result = mode ? dec_mod : comp_res ;
// 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 (
pipeline_reg # ( . DW ( 12 ) ) u_pipe (
. clk ( clk ) ,
. clk ( clk ) ,
. rst_n ( rst_n ) ,
. rst_n ( rst_n ) ,