Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
238 changes: 120 additions & 118 deletions README.md

Large diffs are not rendered by default.

91 changes: 91 additions & 0 deletions verilog/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# ---------------------------------------------------------------------------
# Makefile configuration — edit these for your run
# ---------------------------------------------------------------------------

TOOL ?= verilator
TB ?= top
GUI ?= 0

# ---------------------------------------------------------------------------
# Constant variables
# ---------------------------------------------------------------------------

RTL_VC := rtl/design.vc
TB_DIR := tb
TB_FILE := $(TB_DIR)/tb_$(TB).sv
BUILD_DIR := build
TOP_MODULE := tb

# ---------------------------------------------------------------------------
# Simulation
# ---------------------------------------------------------------------------

VFLAGS := -cc --exe --build -j --timing
ifeq ($(GUI),1)
# using FST instead of VCD as the ECDSA simulation dump is in GBs range
# FST is 5-20x smaller in general
VFLAGS += --trace-fst
endif

.PHONY: sim
sim:
ifeq ($(TOOL),verilator)
@echo "-- VERILATE & BUILD --------"
verilator $(VFLAGS) -F $(RTL_VC) +incdir+$(TB_DIR) $(TB_FILE) --top-module $(TOP_MODULE) tb/sim_main.cpp --Mdir $(BUILD_DIR)
@echo "-- RUN ---------------------"
$(BUILD_DIR)/V$(TOP_MODULE)
@echo "-- DONE --------------------"
ifeq ($(GUI),1)
@echo "-- OPENING GUI -------------"
gtkwave dump.fst
endif
else
$(error Unknown sim tool '$(TOOL)'. See 'make help' for valid options)
endif

# ---------------------------------------------------------------------------
# Lint
# ---------------------------------------------------------------------------
# ALL_CAPS | CamelCase
VERIBLE_RULES_FLAG := --rules="parameter-name-style=localparam_style_regex:([A-Z][A-Z0-9]*(_[A-Z0-9]+)*|([A-Z][a-z0-9]*)+(_[0-9]+)?)"

.PHONY: lint
lint:
ifeq ($(GUI),1)
$(error Lint GUI '$(GUI)' not supported. See 'make help' for valid options)
endif
ifeq ($(TOOL),verilator)
@echo "-- RUN VERILATOR LINT -------"
verilator --lint-only -Wall -F $(RTL_VC)
@echo "-- DONE --------------------"
else ifeq ($(TOOL),verible)
@echo "-- RUN VERIBLE LINT --------"
cd $(dir $(RTL_VC)) && \
verible-verilog-lint $(VERIBLE_RULES_FLAG) $(shell cat $(RTL_VC)) && \
cd -
@echo "-- DONE --------------------"
else
$(error Unknown lint tool '$(TOOL)'. See 'make help' for valid options)
endif



# ---------------------------------------------------------------------------
# Housekeeping
# ---------------------------------------------------------------------------

.PHONY: clean
clean:
rm -rf $(BUILD_DIR) *.vcd *.fst *.vpd *.wlf *.log simv csrc

.PHONY: help
help:
@echo ""
@echo "RTL Makefile — available targets"
@echo "────────────────────────────────────────────────────────"
@echo " sim Run simulation (TOOL=verilator TB=top|ecdsa|arith GUI=0|1)"
@echo " lint Run linter (TOOL=verilator|verible GUI=0)"
@echo " clean Remove all generated build artefacts"
@echo " help Print this message"

.DEFAULT_GOAL := help
199 changes: 199 additions & 0 deletions verilog/rtl/arith.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
// Arith - Modular arithmetic unit for secp256k1 field operations
//
// Performs add, sub, mul, inv modulo either field prime p or curve order n.
// Operands are read from and results written to an external register file.
//
// Operations (op input):
// 0 = add: f <- a + b mod m
// 1 = sub: f <- a - b mod m
// 2 = mul: f <- a * b mod m
// 3 = inv: f <- a^(-1) mod m (b ignored)
//
// Protocol:
// 1. Set a, b, modulus, op; pulse valid high and hold until ready
// 2. ready pulses high for one cycle when the result is available

module arith
import arith_pkg::*; // import in module header to be used in port list
(
input logic clk,
input logic rst_n,
input logic valid,
input op_e op,
input logic [WIDTH-1:0] a,
input logic [WIDTH-1:0] b,
input logic [WIDTH-1:0] modulus,

output logic ready,
output logic [WIDTH-1:0] result
);

// ---------------------------------------------------------------------------
// Shared mod_add — instance
// ---------------------------------------------------------------------------

// Inputs shared across multiple blocks, assigned after each block declared
logic mod_add_valid;
logic [WIDTH-1:0] mod_add_a;
logic [WIDTH-1:0] mod_add_b;
logic mod_add_subtract;

logic mod_add_ready;
logic [WIDTH-1:0] mod_add_result;
logic mod_add_adjust;

mod_add u_mod_add (
.clk (clk),
.rst_n (rst_n),
.valid (mod_add_valid),
.a (mod_add_a),
.b (mod_add_b),
.modulus (modulus),
.subtract (mod_add_subtract),
.ready (mod_add_ready),
.result (mod_add_result),
.adjust (mod_add_adjust)
);

// ---------------------------------------------------------------------------
// mod_mul instance
// ---------------------------------------------------------------------------

// Input glue logic
wire mod_mul_valid = valid && (op == OP_MUL);

// Output nets
logic mod_mul_ready;
logic [WIDTH-1:0] mod_mul_result;

// mod_add interface
logic mod_mul_add_valid;
logic [WIDTH-1:0] mod_mul_add_a;
logic [WIDTH-1:0] mod_mul_add_b;
logic mod_mul_add_subtract;

// mod_add resp glue logic
wire mod_mul_add_ready = mod_mul_add_valid && mod_add_ready;
wire [WIDTH-1:0] mod_mul_add_result = mod_add_result;

mod_mul u_mod_mul (
.clk (clk),
.rst_n (rst_n),
.valid (mod_mul_valid),
.a (a),
.b (b),
.mod_add_ready (mod_mul_add_ready),
.mod_add_result (mod_mul_add_result),
.ready (mod_mul_ready),
.result (mod_mul_result),
.mod_add_valid (mod_mul_add_valid),
.mod_add_a (mod_mul_add_a),
.mod_add_b (mod_mul_add_b),
.mod_add_subtract(mod_mul_add_subtract)
);

// ---------------------------------------------------------------------------
// mod_inv instance
// ---------------------------------------------------------------------------

// Input glue logic
wire mod_inv_valid = valid && (op == OP_INV);

// Output nets
logic mod_inv_ready;
logic mod_inv_exists_unused; // not used currently at arith level
logic [WIDTH-1:0] mod_inv_result;

// mod_add interface
logic mod_inv_add_valid;
logic [WIDTH-1:0] mod_inv_add_a;
logic [WIDTH-1:0] mod_inv_add_b;
logic mod_inv_add_subtract;

// mod_add resp glue logic
wire mod_inv_add_ready = mod_inv_add_valid && mod_add_ready;
wire [WIDTH-1:0] mod_inv_add_result = mod_add_result;
wire mod_inv_add_adjust = mod_add_adjust;

mod_inv u_mod_inv (
.clk (clk),
.rst_n (rst_n),
.valid (mod_inv_valid),
.a (a),
.modulus (modulus),
.mod_add_ready (mod_inv_add_ready),
.mod_add_result (mod_inv_add_result),
.mod_add_adjust (mod_inv_add_adjust),
.ready (mod_inv_ready),
.exists (mod_inv_exists_unused),
.result (mod_inv_result),
.mod_add_valid (mod_inv_add_valid),
.mod_add_a (mod_inv_add_a),
.mod_add_b (mod_inv_add_b),
.mod_add_subtract(mod_inv_add_subtract)
);

// ---------------------------------------------------------------------------
// mod_add input assignments
// ---------------------------------------------------------------------------

always_comb begin
mod_add_valid = 1'b0;
mod_add_a = '0;
mod_add_b = '0;
mod_add_subtract = 1'b0;

unique case(op)
OP_ADD: begin
mod_add_valid = valid;
mod_add_a = a;
mod_add_b = b;
mod_add_subtract = 1'b0;
end
OP_SUB: begin
mod_add_valid = valid;
mod_add_a = a;
mod_add_b = b;
mod_add_subtract = 1'b1;
end
OP_MUL: begin
mod_add_valid = mod_mul_add_valid;
mod_add_a = mod_mul_add_a;
mod_add_b = mod_mul_add_b;
mod_add_subtract = mod_mul_add_subtract;
end
OP_INV: begin
mod_add_valid = mod_inv_add_valid;
mod_add_a = mod_inv_add_a;
mod_add_b = mod_inv_add_b;
mod_add_subtract = mod_inv_add_subtract;
end
endcase
end

// ---------------------------------------------------------------------------
// Output assignments
// ---------------------------------------------------------------------------

always_comb begin
ready = 1'b0;
result = '0;

unique case(op)
OP_ADD,
OP_SUB: begin
ready = mod_add_ready;
result = mod_add_result;
end
OP_MUL: begin
ready = mod_mul_ready;
result = mod_mul_result;
end
OP_INV: begin
ready = mod_inv_ready;
result = mod_inv_result;
end
endcase
end

endmodule
12 changes: 12 additions & 0 deletions verilog/rtl/arith_pkg.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package arith_pkg;

parameter int unsigned WIDTH = 256;

typedef enum logic [1:0] {
OP_ADD, // modular addition: a + b mod p
OP_SUB, // modular subtraction: a - b mod p
OP_MUL, // modular multiplication: a * b mod p
OP_INV // modular inverse: a^-1 mod p (b ignored)
} op_e;

endpackage
26 changes: 26 additions & 0 deletions verilog/rtl/comb_add.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
module comb_add
import arith_pkg::*; // import in module header to be used in port list
(
input wire [WIDTH-1:0] a,
input wire [WIDTH-1:0] b,
input wire subtract,
output wire [WIDTH-1:0] result,
output wire carry_out
);

// Two's complement negation of b:
// Step 1: bitwise invert b (ones' complement)
// Step 2: add 1 via carry-in (subtract fed as cin below)
// Together these form -(b) in two's complement.
// When subtract=0 the uninverted b and cin=0 pass through unchanged.
wire [WIDTH:0] b_ext = {1'b0, b};
wire [WIDTH:0] b_eff = subtract ? ~b_ext : b_ext;

// Single (WIDTH+1)-bit full adder with carry-in.
// The third operand is a single bit (the carry-in),
// which synthesis tools map directly to the adder's carry-in port.
wire [WIDTH:0] sum = {1'b0, a} + b_eff + { {WIDTH{1'b0}}, subtract};

assign result = sum[WIDTH-1:0];
assign carry_out = sum[WIDTH];
endmodule
10 changes: 10 additions & 0 deletions verilog/rtl/design.vc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
./arith_pkg.sv
./comb_add.sv
./mod_add.sv
./mod_mul.sv
./mod_inv.sv
./arith.sv
./trng.sv
./secp256k1_pkg.sv
./ecdsa.sv
./security_block.sv
Loading
Loading