module poly1305_friendly_modulo #( parameter WIDTH = 130, parameter MDIFF = 5, // modulo difference parameter SHIFT_SIZE = 26 ) ( input logic i_clk, input logic i_rst, input logic i_valid, input logic [2*WIDTH-1:0] i_val, input logic [2:0] i_shift_amount, output logic o_valid, output logic [WIDTH-1:0] o_result ); localparam WIDE_WIDTH = WIDTH + $clog2(MDIFF); localparam [WIDTH-1:0] PRIME = (1 << WIDTH) - MDIFF; logic [WIDE_WIDTH-1:0] high_part_1, high_part_2; logic [WIDTH-1:0] low_part_1, low_part_2; logic [WIDE_WIDTH-1:0] intermediate_val; logic [WIDTH-1:0] final_val; logic [2:0] unused_final; logic [2:0] valid_sr; assign intermediate_val = high_part_1 + WIDE_WIDTH'(low_part_1); assign o_result = (final_val >= PRIME) ? final_val - PRIME : final_val; assign o_valid = valid_sr[2]; always_ff @(posedge i_clk) begin valid_sr <= {valid_sr[1:0], i_valid}; high_part_1 <= WIDTH'({3'b0, i_val} >> (130 - (i_shift_amount*SHIFT_SIZE))) * MDIFF; low_part_1 <= WIDTH'(i_val << (i_shift_amount*SHIFT_SIZE)); high_part_2 <= (intermediate_val >> WIDTH) * 5; low_part_2 <= intermediate_val[WIDTH-1:0]; {unused_final, final_val} <= high_part_2 + WIDE_WIDTH'(low_part_2); end endmodule