[Cryptech-Commits] [core/lib] 01/01: Library for common Verilog modules.

git at cryptech.is git at cryptech.is
Fri Nov 9 15:55:54 UTC 2018


This is an automated email from the git hooks/post-receive script.

meisterpaul1 at yandex.ru pushed a commit to branch master
in repository core/lib.

commit 057c4c6fe15b2fb5ef08397eef832620c3e6dead
Author: Pavel V. Shatov (Meister) <meisterpaul1 at yandex.ru>
AuthorDate: Fri Nov 9 18:50:27 2018 +0300

    Library for common Verilog modules.
---
 README.md                                     |  18 ++
 lowlevel/artix7/adder32_artix7.v              |  96 +++++++++
 lowlevel/artix7/adder47_artix7.v              |  91 ++++++++
 lowlevel/artix7/dsp48e1_wrapper.v             | 159 ++++++++++++++
 lowlevel/artix7/dsp48e1_wrapper_modexp.v      | 159 ++++++++++++++
 lowlevel/artix7/mac16_artix7.v                |  90 ++++++++
 lowlevel/artix7/modexp_systolic_pe_artix7.v   | 126 +++++++++++
 lowlevel/artix7/subtractor32_artix7.v         |  94 ++++++++
 lowlevel/cryptech_primitive_switch.vh         |  94 ++++++++
 lowlevel/generic/adder32_generic.v            |  67 ++++++
 lowlevel/generic/adder47_generic.v            |  64 ++++++
 lowlevel/generic/mac16_generic.v              |  74 +++++++
 lowlevel/generic/modexp_systolic_pe_generic.v |  85 ++++++++
 lowlevel/generic/subtractor32_generic.v       |  67 ++++++
 memory/bram_1rw_1ro_readfirst.v               | 112 ++++++++++
 memory/bram_1rw_readfirst.v                   |  75 +++++++
 memory/bram_1wo_1ro_readfirst.v               | 107 +++++++++
 modular/modular_adder.v                       | 298 ++++++++++++++++++++++++++
 modular/modular_subtractor.v                  | 294 +++++++++++++++++++++++++
 multiword/multiword_comparator.v              | 232 ++++++++++++++++++++
 multiword/multiword_mover.v                   | 169 +++++++++++++++
 util/cryptech_clog2.vh                        |  48 +++++
 22 files changed, 2619 insertions(+)

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4c6408c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,18 @@
+# core/lib
+
+This repository contains common modules instantiated by other cores:
+
+* **lowlevel** contains modules for math operations (addition, subtraction, etc). Two sets of modules are provided: **generic** ones can be used during simulation and when porting to a different architecture, modules from **artix7** should be used when building a bitstream for the Alpha board. To use the modules first `` `include "cryptech_primitive_switch.vh"``, then instantiate them using `` `CRYPTECH_PRIMITIVE_*`` macro.
+
+* **memory** contains wrappers for block memories:
+    * ``bram_1rw_readfirst`` is single read-write port
+    * ``bram_1rw_1ro_readfirst`` is one read-write, one read-only port
+	* ``bram_1wo_1ro_readfirst`` is one write-only, one read-only port (useful for storing private keys)
+	
+* **modular** contains multiprecision modular adder and subtractor
+
+* **multiword** contains multiprecision integer comparator and mover/copier
+
+* **util** has the following:
+    * ``cryptech_clog2.vh`` replacement for Xilinx' notorious clog2()
+
diff --git a/lowlevel/artix7/adder32_artix7.v b/lowlevel/artix7/adder32_artix7.v
new file mode 100644
index 0000000..dad2340
--- /dev/null
+++ b/lowlevel/artix7/adder32_artix7.v
@@ -0,0 +1,96 @@
+//------------------------------------------------------------------------------
+//
+// adder32_artix7.v
+// -----------------------------------------------------------------------------
+// Hardware (Artix-7 DSP48E1) 32-bit adder.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2016, NORDUnet A/S
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//------------------------------------------------------------------------------
+
+module adder32_artix7
+  (
+   input 	  clk, // clock
+   input [31: 0]  a, // operand input
+   input [31: 0]  b, // operand input
+   output [31: 0] s, // sum output
+   input 	  c_in, // carry input
+   output 	  c_out		// carry output
+   );
+
+   //
+   // Lower and higher parts of operand
+   //
+   wire [17: 0]   bl = b[17: 0];
+   wire [13: 0]   bh = b[31:18];
+
+
+   //
+   // DSP48E1 Slice
+   //
+
+   /* Operation Mode */
+   wire [ 3: 0]   dsp48e1_alumode	= 4'b0000;
+   wire [ 6: 0]   dsp48e1_opmode		= 7'b0110011;
+
+   /* Internal Product */
+   wire [47: 0]   p_int;
+
+   dsp48e1_wrapper dsp_adder
+     (
+      .clk			(clk),
+
+      .ce			(1'b1),
+
+      .carry		(c_in),
+
+      .alumode		(dsp48e1_alumode),
+      .opmode		(dsp48e1_opmode),
+
+      .a				({{16{1'b0}}, bh}),
+      .b				(bl),
+      .c				({{16{1'b0}}, a}),
+
+      .p				(p_int)
+      );
+
+   //
+   // Output Mapping
+   //
+   assign s 		= p_int[31: 0];
+   assign c_out	= p_int[32];
+
+
+endmodule
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/lowlevel/artix7/adder47_artix7.v b/lowlevel/artix7/adder47_artix7.v
new file mode 100644
index 0000000..caafc85
--- /dev/null
+++ b/lowlevel/artix7/adder47_artix7.v
@@ -0,0 +1,91 @@
+//------------------------------------------------------------------------------
+//
+// adder47_artix7.v
+// -----------------------------------------------------------------------------
+// Hardware (Artix-7 DSP48E1) 47-bit adder.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2016, NORDUnet A/S
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//------------------------------------------------------------------------------
+
+module adder47_artix7
+  (
+   input 	  clk,	// clock
+   input [46: 0]  a,	// operand input
+   input [46: 0]  b,	// operand input
+   output [46: 0] s	// sum output
+   );
+
+   //
+   // Lower and higher parts of operand
+   //
+   wire [17: 0]   bl = b[17: 0];
+   wire [28: 0]   bh = b[46:18];
+
+   //
+   // DSP48E1 Slice
+   //
+
+   /* Operation Mode */
+   wire [ 3: 0]   dsp48e1_alumode	= 4'b0000;
+   wire [ 6: 0]   dsp48e1_opmode	= 7'b0110011;
+
+   /* Internal Product */
+   wire [47: 0]   p_int;
+
+   dsp48e1_wrapper dsp_adder
+     (
+      .clk			(clk),
+
+      .ce			(1'b1),
+
+      .carry		(1'b0),
+
+      .alumode		(dsp48e1_alumode),
+      .opmode		(dsp48e1_opmode),
+
+      .a				({1'b0, bh}),
+      .b				(bl),
+      .c				({1'b0, a}),
+
+      .p				(p_int)
+      );
+
+   //
+   // Output Mapping
+   //
+   assign s 		= p_int[46: 0];
+
+endmodule
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/lowlevel/artix7/dsp48e1_wrapper.v b/lowlevel/artix7/dsp48e1_wrapper.v
new file mode 100644
index 0000000..4c272f0
--- /dev/null
+++ b/lowlevel/artix7/dsp48e1_wrapper.v
@@ -0,0 +1,159 @@
+//------------------------------------------------------------------------------
+//
+// dsp48e1_wrapper.v
+// -----------------------------------------------------------------------------
+// Hardware (Artix-7 DSP48E1) tile wrapper.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2016, NORDUnet A/S
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//------------------------------------------------------------------------------
+
+module dsp48e1_wrapper
+  (
+   input 	  clk,
+
+   input 	  ce,
+
+   input [ 6: 0]  opmode,
+   input [ 3: 0]  alumode,
+
+   input 	  carry,
+
+   input [29: 0]  a,
+   input [17: 0]  b,
+   input [47: 0]  c,
+
+   output [47: 0] p
+   );
+
+
+   //
+   // Tile instantiation
+   //
+   DSP48E1 #
+     (
+      .AREG						(0),
+      .BREG						(0),
+      .CREG						(0),
+      .DREG						(0),
+      .MREG						(0),
+      .PREG						(1),
+      .ADREG					(0),
+
+      .ACASCREG				(0),
+      .BCASCREG				(0),
+      .ALUMODEREG				(0),
+      .INMODEREG				(0),
+      .OPMODEREG				(0),
+      .CARRYINREG				(0),
+      .CARRYINSELREG			(0),
+
+      .A_INPUT					("DIRECT"),
+      .B_INPUT					("DIRECT"),
+
+      .USE_DPORT				("FALSE"),
+      .USE_MULT				("DYNAMIC"),
+      .USE_SIMD				("ONE48"),
+
+      .USE_PATTERN_DETECT	("NO_PATDET"),
+      .SEL_PATTERN			("PATTERN"),
+      .SEL_MASK				("MASK"),
+      .PATTERN					(48'h000000000000),
+      .MASK						(48'h3fffffffffff),
+      .AUTORESET_PATDET		("NO_RESET")
+      )
+   DSP48E1_inst
+     (
+      .CLK					(clk),
+
+      .RSTA					(1'b0),
+      .RSTB					(1'b0),
+      .RSTC					(1'b0),
+      .RSTD					(1'b0),
+      .RSTM					(1'b0),
+      .RSTP					(1'b0),
+
+      .RSTCTRL				(1'b0),
+      .RSTINMODE			(1'b0),
+      .RSTALUMODE			(1'b0),
+      .RSTALLCARRYIN		(1'b0),
+
+      .CEA1					(1'b0),
+      .CEA2					(1'b0),
+      .CEB1					(1'b0),
+      .CEB2					(1'b0),
+      .CEC					(1'b0),
+      .CED					(1'b0),
+      .CEM					(1'b0),
+      .CEP					(ce),
+      .CEAD					(1'b0),
+      .CEALUMODE			(1'b0),
+      .CEINMODE			(1'b0),
+
+      .CECTRL				(1'b0),
+      .CECARRYIN			(1'b0),
+
+      .A						(a),
+      .B						(b),
+      .C						(c),
+      .D						({25{1'b1}}),
+      .P						(p),
+
+      .CARRYIN				(carry),
+      .CARRYOUT			(),
+      .CARRYINSEL			(3'b000),
+
+      .CARRYCASCIN		(1'b0),
+      .CARRYCASCOUT		(),
+
+      .PATTERNDETECT		(),
+      .PATTERNBDETECT	(),
+
+      .OPMODE				(opmode),
+      .ALUMODE				(alumode),
+      .INMODE				(5'b00000),
+
+      .MULTSIGNIN			(1'b0),
+      .MULTSIGNOUT		(),
+
+      .UNDERFLOW			(),
+      .OVERFLOW			(),
+
+      .ACIN					(30'd0),
+      .BCIN					(18'd0),
+      .PCIN					(48'd0),
+
+      .ACOUT				(),
+      .BCOUT				(),
+      .PCOUT				()
+      );
+
+endmodule
diff --git a/lowlevel/artix7/dsp48e1_wrapper_modexp.v b/lowlevel/artix7/dsp48e1_wrapper_modexp.v
new file mode 100644
index 0000000..17d8efe
--- /dev/null
+++ b/lowlevel/artix7/dsp48e1_wrapper_modexp.v
@@ -0,0 +1,159 @@
+//------------------------------------------------------------------------------
+//
+// dsp48e1_wrapper_modexp.v
+// -----------------------------------------------------------------------------
+// Extended hardware (Artix-7 DSP48E1) tile wrapper.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2016-2018, NORDUnet A/S
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//------------------------------------------------------------------------------
+
+module modexpa7_dsp48e1_wrapper_modexp #
+	(
+		parameter	AREG		= 1'b0,
+		parameter	PREG		= 1'b0,
+		
+		parameter	A_INPUT	= "DIRECT"
+	)
+	(
+		input					clk,
+		input		[ 6: 0]	opmode,
+		input		[29: 0]	a,
+		input		[17: 0]	b,
+		output	[47: 0]	p,
+		input		[29: 0]	acin,
+		input		[47: 0]	pcin,
+		output	[29: 0]	acout,
+		output	[47: 0]	pcout
+	);
+	
+		//
+		// Tile instantiation
+		//
+	DSP48E1 #
+	(
+		.AREG						(AREG),
+		.BREG						(1'b1),
+		.CREG						(0),
+		.DREG						(0),
+		.MREG						(0),
+		.PREG						(PREG),
+		.ADREG					(0),
+		
+		.ACASCREG				(AREG),
+		.BCASCREG				(1'b1),
+		.ALUMODEREG				(0),
+		.INMODEREG				(0),
+		.OPMODEREG				(0),
+		.CARRYINREG				(0),
+		.CARRYINSELREG			(0),
+
+		.A_INPUT					(A_INPUT),
+		.B_INPUT					("DIRECT"),
+		
+		.USE_DPORT				("FALSE"),
+		.USE_MULT				("MULTIPLY"),
+		.USE_SIMD				("ONE48"),
+
+		.USE_PATTERN_DETECT	("NO_PATDET"),
+		.SEL_PATTERN			("PATTERN"),
+		.SEL_MASK				("MASK"),
+		.PATTERN					(48'h000000000000),
+		.MASK						(48'h3fffffffffff),
+		.AUTORESET_PATDET		("NO_RESET")
+	)
+	DSP48E1_inst
+	(
+		.CLK					(clk),
+
+		.RSTA					(1'b0),
+		.RSTB					(1'b0),
+		.RSTC					(1'b0),
+		.RSTD					(1'b0),
+		.RSTM					(1'b0),
+		.RSTP					(1'b0),
+
+		.RSTCTRL				(1'b0),
+		.RSTINMODE			(1'b0),
+		.RSTALUMODE			(1'b0),
+		.RSTALLCARRYIN		(1'b0),
+
+		.CEA1					(1'b0),
+		.CEA2					(AREG),
+		.CEB1					(1'b0),
+		.CEB2					(1'b1),
+		.CEC					(1'b0),
+		.CED					(1'b0),
+		.CEM					(1'b0),
+		.CEP					(PREG),
+		.CEAD					(1'b0),
+		.CEALUMODE			(1'b0),
+		.CEINMODE			(1'b0),
+
+		.CECTRL				(1'b0),
+		.CECARRYIN			(1'b0),
+
+		.A						(a),
+		.B						(b),
+		.C						({48{1'b0}}),
+		.D						({25{1'b1}}),
+		.P						(p),
+
+		.CARRYIN				(1'b0),
+		.CARRYOUT			(),
+		.CARRYINSEL			(3'b000),
+
+		.CARRYCASCIN		(1'b0),
+		.CARRYCASCOUT		(),
+
+		.PATTERNDETECT		(),
+		.PATTERNBDETECT	(),
+
+		.OPMODE				(opmode),
+		.ALUMODE				(4'b0000),
+		.INMODE				(5'b00000),
+
+		.MULTSIGNIN			(1'b0),
+		.MULTSIGNOUT		(),
+
+		.UNDERFLOW			(),
+		.OVERFLOW			(),
+
+		.ACIN					(acin),
+		.BCIN					(18'd0),
+		.PCIN					(pcin),
+
+		.ACOUT				(acout),
+		.BCOUT				(),
+		.PCOUT				(pcout)
+  );
+
+endmodule
diff --git a/lowlevel/artix7/mac16_artix7.v b/lowlevel/artix7/mac16_artix7.v
new file mode 100644
index 0000000..421e7ba
--- /dev/null
+++ b/lowlevel/artix7/mac16_artix7.v
@@ -0,0 +1,90 @@
+//------------------------------------------------------------------------------
+//
+// mac16_artix7.v
+// -----------------------------------------------------------------------------
+// Hardware (Artix-7 DSP48E1) 16-bit multiplier and 47-bit accumulator.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2016, NORDUnet A/S
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//------------------------------------------------------------------------------
+
+module mac16_artix7
+  (
+   input 	  clk, // clock
+   input 	  clr, // clear accumulator (active-high)
+   input 	  ce, // enable clock (active-high)
+   input [15: 0]  a, // operand input
+   input [15: 0]  b, // operand input
+   output [46: 0] s			// sum output
+   );
+
+
+   //
+   // DSP48E1 Slice
+   //
+
+   /* Operation Mode */
+   wire [ 3: 0]   dsp48e1_alumode	= 4'b0000;
+   wire [ 6: 0]   dsp48e1_opmode		= {2'b01, clr, 4'b0101};
+
+   /* Internal Product */
+   wire [47: 0]   p_int;
+
+   dsp48e1_wrapper dsp_adder
+     (
+      .clk			(clk),
+
+      .ce			(ce),
+
+      .carry		(1'b0),
+
+      .alumode		(dsp48e1_alumode),
+      .opmode		(dsp48e1_opmode),
+
+      .a				({{14{1'b0}}, a}),
+      .b				({{ 2{1'b0}}, b}),
+      .c				({48{1'b0}}),
+
+      .p				(p_int)
+      );
+
+   //
+   // Output Mapping
+   //
+   assign s = p_int[46:0];
+
+
+endmodule
+
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/lowlevel/artix7/modexp_systolic_pe_artix7.v b/lowlevel/artix7/modexp_systolic_pe_artix7.v
new file mode 100644
index 0000000..08391f5
--- /dev/null
+++ b/lowlevel/artix7/modexp_systolic_pe_artix7.v
@@ -0,0 +1,126 @@
+//------------------------------------------------------------------------------
+//
+// modexp_systolic_pe_artix7.v
+// -----------------------------------------------------------------------------
+// Hardware (Artix-7 DSP48E1) low-level systolic array processing element.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2016-2017, NORDUnet A/S
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//------------------------------------------------------------------------------
+
+module modexp_systolic_pe_artix7
+	(
+		input					clk,
+		input		[31: 0]	a,
+		input		[31: 0]	b,
+		input		[31: 0]	t,
+		input		[31: 0]	c_in,
+		output	[31: 0]	p,
+		output	[31: 0]	c_out
+	);
+	
+	reg	[31: 0]	t_dly;
+	reg	[31: 0]	c_in_dly;
+	
+	always @(posedge clk) t_dly <= t;
+	always @(posedge clk) c_in_dly <= c_in;
+	
+	wire	[31: 0]	t_c_in_s;
+	wire				t_c_in_c_out;
+	
+	reg				t_c_in_c_out_dly;
+	
+	always @(posedge clk) t_c_in_c_out_dly <= t_c_in_c_out;
+	
+	modexpa7_adder32_artix7 add_t_c_in
+	(
+		.clk		(clk),
+		.ce		(1'b1),
+		.a			(t_dly),
+		.b			(c_in_dly),
+		.c_in		(1'b0),
+		.s			(t_c_in_s),
+		.c_out	(t_c_in_c_out)
+	);
+
+	wire	[63: 0]	a_b;
+	
+	wire	[31: 0]	a_b_lsb = a_b[31: 0];
+	wire	[31: 0]	a_b_msb = a_b[63:32];
+	
+	reg	[31: 0]	a_b_msb_dly;
+	
+	always @(posedge clk) a_b_msb_dly <= a_b_msb;
+	
+	modexpa7_multiplier32_artix7 mul_a_b
+	(
+		.clk	(clk),
+		.a		(a),
+		.b		(b),
+		.p		(a_b)
+	);
+	
+	wire	[31: 0]	add_p_s;
+	wire				add_p_c_out;
+	
+	reg	[31: 0]	add_p_s_dly;
+	
+	always @(posedge clk) add_p_s_dly <= add_p_s;
+	
+	assign p = add_p_s_dly;
+	
+	modexpa7_adder32_artix7 add_p
+	(
+		.clk		(clk),
+		.ce		(1'b1),
+		.a			(a_b_lsb),
+		.b			(t_c_in_s),
+		.c_in		(1'b0),
+		.s			(add_p_s),
+		.c_out	(add_p_c_out)
+	);
+
+	modexpa7_adder32_artix7 add_c_out
+	(
+		.clk		(clk),
+		.ce		(1'b1),
+		.a			(a_b_msb_dly),
+		.b			({{31{1'b0}}, t_c_in_c_out_dly}),
+		.c_in		(add_p_c_out),
+		.s			(c_out),
+		.c_out	()
+	);
+
+endmodule
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/lowlevel/artix7/subtractor32_artix7.v b/lowlevel/artix7/subtractor32_artix7.v
new file mode 100644
index 0000000..7377781
--- /dev/null
+++ b/lowlevel/artix7/subtractor32_artix7.v
@@ -0,0 +1,94 @@
+//------------------------------------------------------------------------------
+//
+// subtractor32_artix7.v
+// -----------------------------------------------------------------------------
+// Hardware (Artix-7 DSP48E1) 32-bit subtractor.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2016, NORDUnet A/S
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//------------------------------------------------------------------------------
+
+module subtractor32_artix7
+  (
+   input 	  clk,
+   input [31: 0]  a,
+   input [31: 0]  b,
+   output [31: 0] d,
+   input 	  b_in,
+   output 	  b_out
+   );
+
+   //
+   // Lower and higher parts of operand
+   //
+   wire [17: 0]   bl = b[17: 0];
+   wire [13: 0]   bh = b[31:18];
+
+   //
+   // DSP48E1 Slice
+   //
+
+   /* Operation Mode */
+   wire [ 3: 0]   dsp48e1_alumode	= 4'b0011;
+   wire [ 6: 0]   dsp48e1_opmode		= 7'b0110011;
+
+   /* Internal Product */
+   wire [47: 0]   p_int;
+
+   dsp48e1_wrapper dsp_subtractor
+     (
+      .clk			(clk),
+
+      .ce			(1'b1),
+
+      .carry		(b_in),
+
+      .alumode		(dsp48e1_alumode),
+      .opmode		(dsp48e1_opmode),
+
+      .a				({{16{1'b0}}, bh}),
+      .b				(bl),
+      .c				({{16{1'b0}}, a}),
+
+      .p				(p_int)
+      );
+
+   //
+   // Output Mapping
+   //
+   assign d 		= p_int[31: 0];
+   assign b_out	= p_int[32];
+
+endmodule
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/lowlevel/cryptech_primitive_switch.vh b/lowlevel/cryptech_primitive_switch.vh
new file mode 100644
index 0000000..a4aad45
--- /dev/null
+++ b/lowlevel/cryptech_primitive_switch.vh
@@ -0,0 +1,94 @@
+//======================================================================
+//
+// Copyright (c) 2018, NORDUnet A/S All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// - Redistributions of source code must retain the above copyright
+//   notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+//   notice, this list of conditions and the following disclaimer in the
+//   documentation and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may
+//   be used to endorse or promote products derived from this software
+//   without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+/* IMPORTANT: The scope of `define in Verilog is somewhat unevident (one
+              "compilation unit"), thus all `defines are prefixed with
+              CRYPTECH_ to prevent any potentical conflicts.
+              */
+              
+/* NOTE: You can comment the following line when simulating to use generic
+         primitives and get some speedup, otherwise un-comment it to take
+         advantage of vendor-specific hardware math slices when building the
+         bitstream.
+         */
+   
+
+    // generic/vendor switch
+`define CRYPTECH_USE_VENDOR_PRIMITIVES
+
+
+    //
+    // Generic Math Primitives
+    //
+`define CRYPTECH_PRIMITIVE_MAC16_GENERIC    mac16_generic
+`define CRYPTECH_PRIMITIVE_ADD32_GENERIC    adder32_generic
+`define CRYPTECH_PRIMITIVE_ADD47_GENERIC    adder47_generic
+`define CRYPTECH_PRIMITIVE_SUB32_GENERIC    subtractor32_generic
+    
+
+    //
+    // Xilinx Math Primitives for Artix-7 Family
+    //
+`define CRYPTECH_PRIMITIVE_MAC16_VENDOR     mac16_artix7
+`define CRYPTECH_PRIMITIVE_ADD32_VENDOR     adder32_artix7
+`define CRYPTECH_PRIMITIVE_ADD47_VENDOR     adder47_artix7
+`define CRYPTECH_PRIMITIVE_SUB32_VENDOR     subtractor32_artix7
+
+
+
+/* map CRYPTECH_PRIMITIVE_* to either CRYPTECH_PRIMITIVE_*_GENERIC or 
+   CRYPTECH_PRIMITIVE_*_VENDOR based on the value of the earlier generic/vendor
+   switch.
+   */
+   
+`ifndef CRYPTECH_USE_VENDOR_PRIMITIVES
+
+    // generic primitives
+`define CRYPTECH_PRIMITIVE_MAC16 `CRYPTECH_PRIMITIVE_MAC16_GENERIC
+`define CRYPTECH_PRIMITIVE_ADD32 `CRYPTECH_PRIMITIVE_ADD32_GENERIC
+`define CRYPTECH_PRIMITIVE_ADD47 `CRYPTECH_PRIMITIVE_ADD47_GENERIC
+`define CRYPTECH_PRIMITIVE_SUB32 `CRYPTECH_PRIMITIVE_SUB32_GENERIC
+
+`else
+
+    // vendor-specific primitives
+`define CRYPTECH_PRIMITIVE_MAC16 `CRYPTECH_PRIMITIVE_MAC16_VENDOR
+`define CRYPTECH_PRIMITIVE_ADD47 `CRYPTECH_PRIMITIVE_ADD47_VENDOR
+`define CRYPTECH_PRIMITIVE_ADD32 `CRYPTECH_PRIMITIVE_ADD32_VENDOR
+`define CRYPTECH_PRIMITIVE_SUB32 `CRYPTECH_PRIMITIVE_SUB32_VENDOR
+
+`endif
+
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/lowlevel/generic/adder32_generic.v b/lowlevel/generic/adder32_generic.v
new file mode 100644
index 0000000..eadfb6f
--- /dev/null
+++ b/lowlevel/generic/adder32_generic.v
@@ -0,0 +1,67 @@
+//------------------------------------------------------------------------------
+//
+// adder32_generic.v
+// -----------------------------------------------------------------------------
+// Generic 32-bit adder.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2016, NORDUnet A/S
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//------------------------------------------------------------------------------
+
+module adder32_generic
+  (
+   input 	  clk, // clock
+   input [31: 0]  a, // operand input
+   input [31: 0]  b, // operand input
+   output [31: 0] s, // sum output
+   input 	  c_in, // carry input
+   output 	  c_out		// carry output
+   );
+
+   //
+   // Sum
+   //
+   reg [32: 0] 	  s_int;
+
+   always @(posedge clk)
+     s_int <= {1'b0, a} + {1'b0, b} + {{32{1'b0}}, c_in};
+
+   //
+   // Output
+   //
+   assign s = s_int[31:0];
+   assign c_out = s_int[32];
+
+endmodule
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/lowlevel/generic/adder47_generic.v b/lowlevel/generic/adder47_generic.v
new file mode 100644
index 0000000..406c175
--- /dev/null
+++ b/lowlevel/generic/adder47_generic.v
@@ -0,0 +1,64 @@
+//------------------------------------------------------------------------------
+//
+// adder47_generic.v
+// -----------------------------------------------------------------------------
+// Generic 47-bit adder.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2016, NORDUnet A/S
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//------------------------------------------------------------------------------
+
+module adder47_generic
+  (
+   input 	  clk, // clock
+   input [46: 0]  a, // operand input
+   input [46: 0]  b, // operand input
+   output [46: 0] s			// sum output
+   );
+
+   //
+   // Sum
+   //
+   reg [46: 0] 	  s_int;
+
+   always @(posedge clk)
+     s_int <= a + b;
+
+   //
+   // Output
+   //
+   assign s = s_int;
+
+endmodule
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/lowlevel/generic/mac16_generic.v b/lowlevel/generic/mac16_generic.v
new file mode 100644
index 0000000..6d120a3
--- /dev/null
+++ b/lowlevel/generic/mac16_generic.v
@@ -0,0 +1,74 @@
+//------------------------------------------------------------------------------
+//
+// mac16_generic.v
+// -----------------------------------------------------------------------------
+// Generic 16-bit multiplier and 47-bit accumulator.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2016, NORDUnet A/S
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//------------------------------------------------------------------------------
+
+module mac16_generic
+  (
+   input 	  clk, // clock
+   input 	  clr, // clear accumulator (active-high)
+   input 	  ce, // enable clock (active-high)
+   input [15: 0]  a, // operand input
+   input [15: 0]  b, // operand input
+   output [46: 0] s			// sum output
+   );
+
+   //
+   // Multiplier
+   //
+   wire [31: 0]   p = {{16{1'b0}}, a} * {{16{1'b0}}, b};
+   wire [46: 0]   p_ext = {{15{1'b0}}, p};
+
+   //
+   // Accumulator
+   //
+   reg [46: 0] 	  s_int;
+
+   always @(posedge clk)
+     //
+     if (ce) s_int <= clr ? p_ext : p_ext + s_int;
+
+   //
+   // Output
+   //
+   assign s = s_int;
+
+endmodule
+
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/lowlevel/generic/modexp_systolic_pe_generic.v b/lowlevel/generic/modexp_systolic_pe_generic.v
new file mode 100644
index 0000000..0e338ff
--- /dev/null
+++ b/lowlevel/generic/modexp_systolic_pe_generic.v
@@ -0,0 +1,85 @@
+//======================================================================
+//
+// modexp_systolic_pe_generic.v
+// -----------------------------------------------------------------------------
+// Generic low-level systolic array processing element for ModExp core.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2017-2018, NORDUnet A/S All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// - Redistributions of source code must retain the above copyright
+//   notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+//   notice, this list of conditions and the following disclaimer in the
+//   documentation and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may
+//   be used to endorse or promote products derived from this software
+//   without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module modexp_systolic_pe_generic
+	(
+		input					clk,
+		input		[31: 0]	a,
+		input		[31: 0]	b,
+		input		[31: 0]	t,
+		input		[31: 0]	c_in,
+		output	[31: 0]	p,
+		output	[31: 0]	c_out
+	);
+
+		//
+		// Customizable Latency
+		//
+	parameter LATENCY = 4;
+		
+		//
+		// Delay Line
+		//
+	reg	[63: 0]	abct[1:LATENCY];
+	
+		//
+		// Outputs
+		//
+	assign p			= abct[LATENCY][31: 0];
+	assign c_out	= abct[LATENCY][63:32];
+
+		//
+		// Sub-products
+		//
+	wire	[63: 0]	ab = {{32{1'b0}}, a}    * {{32{1'b0}}, b};
+	wire	[63: 0]	ct = {{32{1'b0}}, c_in} + {{32{1'b0}}, t};
+
+		//
+		// Delay
+		//
+	integer i;
+	always @(posedge clk)
+		//
+		for (i=1; i<=LATENCY; i=i+1)
+			abct[i] <= (i == 1) ? ab + ct : abct[i-1];
+
+endmodule
+
+//======================================================================
+// End of file
+//======================================================================
diff --git a/lowlevel/generic/subtractor32_generic.v b/lowlevel/generic/subtractor32_generic.v
new file mode 100644
index 0000000..5137ace
--- /dev/null
+++ b/lowlevel/generic/subtractor32_generic.v
@@ -0,0 +1,67 @@
+//------------------------------------------------------------------------------
+//
+// subtractor32_generic.v
+// -----------------------------------------------------------------------------
+// Generic 32-bit subtractor.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2016, NORDUnet A/S
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//------------------------------------------------------------------------------
+
+module subtractor32_generic
+  (
+   input 	  clk,
+   input [31: 0]  a,
+   input [31: 0]  b,
+   output [31: 0] d,
+   input 	  b_in,
+   output 	  b_out
+   );
+
+   //
+   // Difference
+   //
+   reg [32: 0] 	  d_int;
+
+   always @(posedge clk)
+     d_int <= {1'b0, a} - {1'b0, b} - {{32{1'b0}}, b_in};
+
+   //
+   // Output
+   //
+   assign d = d_int[31:0];
+   assign b_out = d_int[32];
+
+endmodule
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/memory/bram_1rw_1ro_readfirst.v b/memory/bram_1rw_1ro_readfirst.v
new file mode 100644
index 0000000..29e0daa
--- /dev/null
+++ b/memory/bram_1rw_1ro_readfirst.v
@@ -0,0 +1,112 @@
+//======================================================================
+//
+// Copyright (c) 2015, 2018 NORDUnet A/S All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// - Redistributions of source code must retain the above copyright
+//   notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+//   notice, this list of conditions and the following disclaimer in the
+//   documentation and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may
+//   be used to endorse or promote products derived from this software
+//   without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module bram_1rw_1ro_readfirst #
+(
+    parameter MEM_WIDTH     = 32,
+    parameter MEM_ADDR_BITS =  8
+)
+(
+    input   clk,
+
+    input  [MEM_ADDR_BITS-1:0] a_addr,
+    input                      a_wr,
+    input  [MEM_WIDTH    -1:0] a_in,
+    output [MEM_WIDTH    -1:0] a_out,
+
+    input  [MEM_ADDR_BITS-1:0] b_addr,
+    output [MEM_WIDTH    -1:0] b_out
+);
+
+
+    //
+    // BRAM
+    //
+    (* RAM_STYLE="BLOCK" *)
+    reg [MEM_WIDTH-1:0] bram[0:(2**MEM_ADDR_BITS)-1];
+
+
+    //
+    // Initialization for Simulation
+    //
+    /*
+    integer c;
+    initial begin
+        for (c=0; c<(2**MEM_ADDR_BITS); c=c+1)
+        bram[c] = {MEM_WIDTH{1'b0}};
+    end
+    */
+
+
+
+    //
+    // Output Registers
+    //
+    reg [MEM_WIDTH-1:0] bram_reg_a;
+    reg [MEM_WIDTH-1:0] bram_reg_b;
+
+    assign a_out = bram_reg_a;
+    assign b_out = bram_reg_b;
+
+    
+    //
+    // Note, that when both ports are accessing the same location, conflict can
+    // potentionally arise. See Xilinx UG473 (pages 19-20, "Conflict
+    // Avoidance") for more information. In our configuration to avoid that the
+    // write port must be coded to operate in READ_FIRST mode. If the write
+    // port is overwriting the same address the read port is accessing, the 
+    // write port must read the previously stored data (not the data it is
+    // writing, as that would be WRITE_FIRST mode).
+    //
+
+
+    //
+    // Read-Write Port A
+    //
+    always @(posedge clk) begin
+        //
+        bram_reg_a <= bram[a_addr];
+        //
+        if (a_wr) bram[a_addr] <= a_in;
+        //
+    end
+
+
+    //
+    // Read-Only Port B
+    //
+    always @(posedge clk)
+        //
+        bram_reg_b <= bram[b_addr];
+
+
+endmodule
diff --git a/memory/bram_1rw_readfirst.v b/memory/bram_1rw_readfirst.v
new file mode 100644
index 0000000..9003e50
--- /dev/null
+++ b/memory/bram_1rw_readfirst.v
@@ -0,0 +1,75 @@
+//======================================================================
+//
+// Copyright (c) 2017, NORDUnet A/S All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// - Redistributions of source code must retain the above copyright
+//   notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+//   notice, this list of conditions and the following disclaimer in the
+//   documentation and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may
+//   be used to endorse or promote products derived from this software
+//   without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+`timescale 1ns / 1ps
+
+module bram_1rw_readfirst
+  #(parameter MEM_WIDTH            = 32,
+    parameter MEM_ADDR_BITS        = 8)
+   (
+    input wire                     clk,
+
+    input wire [MEM_ADDR_BITS-1:0] a_addr,
+    input wire                     a_wr,
+    input wire [MEM_WIDTH-1:0]     a_in,
+    output wire [MEM_WIDTH-1:0]    a_out
+    );
+
+
+   //
+   // BRAM
+   //
+   (* RAM_STYLE="BLOCK" *)
+   reg [MEM_WIDTH-1:0]             bram[0:(2**MEM_ADDR_BITS)-1];
+	
+	
+   //
+   // Output Register
+   //
+   reg [MEM_WIDTH-1:0]             bram_reg_a;
+
+   assign a_out = bram_reg_a;
+
+
+   //
+   // Read-Write Port A
+   //
+   always @(posedge clk) begin
+      //
+      bram_reg_a <= bram[a_addr];
+      //
+      if (a_wr) bram[a_addr] <= a_in;
+      //
+   end
+
+
+endmodule
diff --git a/memory/bram_1wo_1ro_readfirst.v b/memory/bram_1wo_1ro_readfirst.v
new file mode 100644
index 0000000..6991c87
--- /dev/null
+++ b/memory/bram_1wo_1ro_readfirst.v
@@ -0,0 +1,107 @@
+//======================================================================
+//
+// Copyright (c) 2015, 2018 NORDUnet A/S All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// - Redistributions of source code must retain the above copyright
+//   notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+//   notice, this list of conditions and the following disclaimer in the
+//   documentation and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may
+//   be used to endorse or promote products derived from this software
+//   without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+module bram_1wo_1ro_readfirst #
+(
+    parameter MEM_WIDTH     = 32,
+    parameter MEM_ADDR_BITS =  8
+)
+(
+    input   clk,
+
+    input  [MEM_ADDR_BITS-1:0] a_addr,
+    input                      a_wr,
+    input  [MEM_WIDTH    -1:0] a_in,
+    output [MEM_WIDTH    -1:0] a_out,
+
+    input  [MEM_ADDR_BITS-1:0] b_addr,
+    output [MEM_WIDTH    -1:0] b_out
+);
+
+
+    //
+    // BRAM
+    //
+    (* RAM_STYLE="BLOCK" *)
+    reg [MEM_WIDTH-1:0] bram[0:(2**MEM_ADDR_BITS)-1];
+
+
+    //
+    // Initialization for Simulation
+    //
+    /*
+    integer c;
+    initial begin
+        for (c=0; c<(2**MEM_ADDR_BITS); c=c+1)
+        bram[c] = {MEM_WIDTH{1'b0}};
+    end
+    */
+
+
+
+    //
+    // Output Registers
+    //
+    reg [MEM_WIDTH-1:0] bram_reg_b;
+
+    assign a_out = 32'hDEADCE11;
+    assign b_out = bram_reg_b;
+
+    
+    //
+    // Note, that when both ports are accessing the same location, conflict can
+    // potentionally arise. See Xilinx UG473 (pages 19-20, "Conflict
+    // Avoidance") for more information. In our configuration to avoid that the
+    // write port must be coded to operate in READ_FIRST mode. If the write
+    // port is overwriting the same address the read port is accessing, the 
+    // write port must read the previously stored data (not the data it is
+    // writing, as that would be WRITE_FIRST mode).
+    //
+
+
+    //
+    // Write-Only Port A
+    //
+    always @(posedge clk)
+        //
+        if (a_wr) bram[a_addr] <= a_in;
+
+
+    //
+    // Read-Only Port B
+    //
+    always @(posedge clk)
+        //
+        bram_reg_b <= bram[b_addr];
+
+
+endmodule
diff --git a/modular/modular_adder.v b/modular/modular_adder.v
new file mode 100644
index 0000000..c2f5a4e
--- /dev/null
+++ b/modular/modular_adder.v
@@ -0,0 +1,298 @@
+//------------------------------------------------------------------------------
+//
+// modular_adder.v
+// -----------------------------------------------------------------------------
+// Modular adder.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2016, 2018 NORDUnet A/S
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//------------------------------------------------------------------------------
+
+module modular_adder
+(
+    clk, rst_n,
+    ena, rdy,
+    ab_addr, n_addr, s_addr, s_wren,
+    a_din, b_din, n_din, s_dout
+);
+
+
+    //
+    // Settings
+    //
+    `include "cryptech_primitive_switch.vh"
+
+
+    //
+    // Parameters
+    //
+    parameter   OPERAND_NUM_WORDS   = 8;
+    parameter   WORD_COUNTER_WIDTH  = 3;
+
+
+    //
+    // Handy Numbers
+    //
+    localparam  [WORD_COUNTER_WIDTH-1:0]    WORD_INDEX_ZERO = 0;
+    localparam  [WORD_COUNTER_WIDTH-1:0]    WORD_INDEX_LAST = OPERAND_NUM_WORDS - 1;
+
+
+    //
+    // Handy Functions
+    //
+    function  [WORD_COUNTER_WIDTH-1:0]    WORD_INDEX_NEXT_OR_ZERO;
+        input [WORD_COUNTER_WIDTH-1:0]    WORD_INDEX_CURRENT;
+        begin
+            WORD_INDEX_NEXT_OR_ZERO = (WORD_INDEX_CURRENT < WORD_INDEX_LAST) ?
+            WORD_INDEX_CURRENT + 1'b1 : WORD_INDEX_ZERO;
+        end
+    endfunction
+
+
+    //
+    // Ports
+    //
+    input                               clk;        // system clock
+    input                               rst_n;      // active-low async reset
+
+    input                               ena;        // enable input
+    output                              rdy;        // ready output
+
+    output  [WORD_COUNTER_WIDTH-1:0]    ab_addr;    // index of current A and B words
+    output  [WORD_COUNTER_WIDTH-1:0]    n_addr;     // index of current N word
+    output  [WORD_COUNTER_WIDTH-1:0]    s_addr;     // index of current S word
+    output                              s_wren;     // store current S word now
+
+    input   [                32-1:0]    a_din;      // A
+    input   [                32-1:0]    b_din;      // B
+    input   [                32-1:0]    n_din;      // N
+    output  [                32-1:0]    s_dout;     // S = (A + B) mod N
+
+
+    //
+    // Word Indices
+    //
+    reg [WORD_COUNTER_WIDTH-1:0] index_ab;
+    reg [WORD_COUNTER_WIDTH-1:0] index_n;
+    reg [WORD_COUNTER_WIDTH-1:0] index_s;
+
+    // map registers to output ports
+    assign ab_addr  = index_ab;
+    assign n_addr   = index_n;
+    assign s_addr   = index_s;
+
+
+    //
+    // Adder
+    //
+    wire [31:0] add32_s;
+    wire        add32_c_in;
+    wire        add32_c_out;
+
+    `CRYPTECH_PRIMITIVE_ADD32 add32
+    (
+        .clk    (clk),
+        .a      (a_din),
+        .b      (b_din),
+        .s      (add32_s),
+        .c_in   (add32_c_in),
+        .c_out  (add32_c_out)
+    );
+
+
+    //
+    // Subtractor
+    //
+    wire [31:0] sub32_d;
+    wire        sub32_b_in;
+    wire        sub32_b_out;
+
+    `CRYPTECH_PRIMITIVE_SUB32 sub
+    (
+        .clk    (clk),
+        .a      (add32_s),
+        .b      (n_din),
+        .d      (sub32_d),
+        .b_in   (sub32_b_in),
+        .b_out  (sub32_b_out)
+    );
+
+
+    //
+    // FSM
+    //
+
+    localparam FSM_SHREG_WIDTH = 2 * OPERAND_NUM_WORDS + 5;
+
+    reg [FSM_SHREG_WIDTH-1:0] fsm_shreg;
+
+    assign rdy = fsm_shreg[0];
+
+    wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_inc_index_ab   = fsm_shreg[FSM_SHREG_WIDTH - (0 * OPERAND_NUM_WORDS + 1) : FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 0)];
+    wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_inc_index_n    = fsm_shreg[FSM_SHREG_WIDTH - (0 * OPERAND_NUM_WORDS + 2) : FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 1)];
+    wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_store_sum_ab   = fsm_shreg[FSM_SHREG_WIDTH - (0 * OPERAND_NUM_WORDS + 3) : FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 2)];
+    wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_store_sum_ab_n = fsm_shreg[FSM_SHREG_WIDTH - (0 * OPERAND_NUM_WORDS + 4) : FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 3)];
+    wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_store_data_s   = fsm_shreg[FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 4) : FSM_SHREG_WIDTH - (2 * OPERAND_NUM_WORDS + 3)];
+    wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_inc_index_s    = fsm_shreg[FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 5) : FSM_SHREG_WIDTH - (2 * OPERAND_NUM_WORDS + 4)];
+    wire                         fsm_latch_msb_carry      = fsm_shreg[FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 2)];
+    wire                         fsm_latch_msb_borrow     = fsm_shreg[FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 3)];
+
+    wire inc_index_ab   = |fsm_shreg_inc_index_ab;
+    wire inc_index_n    = |fsm_shreg_inc_index_n;
+    wire store_sum_ab   = |fsm_shreg_store_sum_ab;
+    wire store_sum_ab_n = |fsm_shreg_store_sum_ab_n;
+    wire store_data_s   = |fsm_shreg_store_data_s;
+    wire inc_index_s    = |fsm_shreg_inc_index_s;
+
+    always @(posedge clk or negedge rst_n)
+        //
+        if (rst_n == 1'b0)
+            //
+            fsm_shreg <= {{FSM_SHREG_WIDTH-1{1'b0}}, 1'b1};
+            //
+        else begin
+            //
+            if (rdy)    fsm_shreg <= {ena, {FSM_SHREG_WIDTH-2{1'b0}}, ~ena};
+            //
+            else        fsm_shreg <= {1'b0, fsm_shreg[FSM_SHREG_WIDTH-1:1]};
+            //
+        end
+
+
+    //
+    // Carry & Borrow Masking Logic
+    //
+    reg add32_c_mask;
+    reg sub32_b_mask;
+
+    always @(posedge clk) begin
+        //
+        add32_c_mask <= (index_ab == WORD_INDEX_ZERO) ? 1'b1 : 1'b0;
+        sub32_b_mask <= (index_n  == WORD_INDEX_ZERO) ? 1'b1 : 1'b0;
+        //
+    end
+
+    assign add32_c_in = add32_c_out & ~add32_c_mask;
+    assign sub32_b_in = sub32_b_out & ~sub32_b_mask;
+
+
+    //
+    // Carry & Borrow Latch Logic
+    //
+    reg add32_carry_latch;
+    reg sub32_borrow_latch;
+
+    always @(posedge clk) begin
+        //
+        if (fsm_latch_msb_carry) add32_carry_latch <= add32_c_out;
+        if (fsm_latch_msb_borrow) sub32_borrow_latch <= sub32_b_out;
+        //
+    end
+
+
+    //
+    // Intermediate Results
+    //
+    reg [32*OPERAND_NUM_WORDS-1:0] s_ab;
+    reg [32*OPERAND_NUM_WORDS-1:0] s_ab_n;
+
+    always @(posedge clk)
+        //
+        if (store_data_s) begin
+            //
+            s_ab   <= {{32{1'bX}}, s_ab[32*OPERAND_NUM_WORDS-1:32]};
+            s_ab_n <= {{32{1'bX}}, s_ab_n[32*OPERAND_NUM_WORDS-1:32]};
+            //
+        end else begin
+            //
+            if (store_sum_ab)   s_ab   <= {add32_s, s_ab[32*OPERAND_NUM_WORDS-1:32]};
+            if (store_sum_ab_n) s_ab_n <= {sub32_d, s_ab_n[32*OPERAND_NUM_WORDS-1:32]};
+            //
+        end
+
+
+    //
+    // Word Index Increment Logic
+    //
+    always @(posedge clk)
+        //
+        if (rdy) begin
+            //
+            index_ab <= WORD_INDEX_ZERO;
+            index_n  <= WORD_INDEX_ZERO;
+            index_s  <= WORD_INDEX_ZERO;
+            //
+        end else begin
+            //
+            if (inc_index_ab) index_ab <= WORD_INDEX_NEXT_OR_ZERO(index_ab);
+            if (inc_index_n)  index_n  <= WORD_INDEX_NEXT_OR_ZERO(index_n);
+            if (inc_index_s)  index_s  <= WORD_INDEX_NEXT_OR_ZERO(index_s);
+            //
+        end
+
+
+    //
+    // Output Sum Selector
+    //
+    wire mux_select_ab = sub32_borrow_latch && !add32_carry_latch;
+
+
+    //
+    // Output Data and Write Enable Logic
+    //
+    reg         s_wren_reg;
+    reg  [31:0] s_dout_reg;
+    wire [31:0] s_dout_mux = mux_select_ab ? s_ab[31:0] : s_ab_n[31:0];
+
+    assign s_wren = s_wren_reg;
+    assign s_dout = s_dout_reg;
+
+    always @(posedge clk)
+        //
+        if (rdy) begin
+            //
+            s_wren_reg <= 1'b0;
+            s_dout_reg <= {32{1'bX}};
+            //
+        end else begin
+            //
+            s_wren_reg <= store_data_s;
+            s_dout_reg <= store_data_s ? s_dout_mux : {32{1'bX}};
+            //
+        end
+
+
+endmodule
+
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/modular/modular_subtractor.v b/modular/modular_subtractor.v
new file mode 100644
index 0000000..4ac5e44
--- /dev/null
+++ b/modular/modular_subtractor.v
@@ -0,0 +1,294 @@
+//------------------------------------------------------------------------------
+//
+// modular_subtractor.v
+// -----------------------------------------------------------------------------
+// Modular subtractor.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2016, 2018 NORDUnet A/S
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//------------------------------------------------------------------------------
+
+module modular_subtractor
+(
+    clk, rst_n,
+    ena, rdy,
+    ab_addr, n_addr, d_addr, d_wren,
+    a_din, b_din, n_din, d_dout
+);
+
+
+    //
+    // Settings
+    //
+    `include "cryptech_primitive_switch.vh"
+
+
+    //
+    // Parameters
+    //
+    parameter   OPERAND_NUM_WORDS   = 8;
+    parameter   WORD_COUNTER_WIDTH  = 3;
+
+
+    //
+    // Handy Numbers
+    //
+    localparam  [WORD_COUNTER_WIDTH-1:0]    WORD_INDEX_ZERO = 0;
+    localparam  [WORD_COUNTER_WIDTH-1:0]    WORD_INDEX_LAST = OPERAND_NUM_WORDS - 1;
+
+
+    //
+    // Handy Functions
+    //
+    function  [WORD_COUNTER_WIDTH-1:0]    WORD_INDEX_NEXT_OR_ZERO;
+        input [WORD_COUNTER_WIDTH-1:0]    WORD_INDEX_CURRENT;
+        begin
+            WORD_INDEX_NEXT_OR_ZERO = (WORD_INDEX_CURRENT < WORD_INDEX_LAST) ?
+            WORD_INDEX_CURRENT + 1'b1 : WORD_INDEX_ZERO;
+        end
+    endfunction
+
+
+    //
+    // Ports
+    //
+    input                               clk;        // system clock
+    input                               rst_n;      // active-low async reset
+
+    input                               ena;        // enable input
+    output                              rdy;        // ready output
+
+    output  [WORD_COUNTER_WIDTH-1:0]    ab_addr;    // index of current A and B words
+    output  [WORD_COUNTER_WIDTH-1:0]    n_addr;     // index of current N word
+    output  [WORD_COUNTER_WIDTH-1:0]    d_addr;     // index of current D word
+    output                              d_wren;     // store current D word now
+
+    input   [                32-1:0]    a_din;      // A
+    input   [                32-1:0]    b_din;      // B
+    input   [                32-1:0]    n_din;      // N
+    output  [                32-1:0]    d_dout;     // D = (A - B) mod N
+
+
+    //
+    // Word Indices
+    //
+    reg [WORD_COUNTER_WIDTH-1:0] index_ab;
+    reg [WORD_COUNTER_WIDTH-1:0] index_n;
+    reg [WORD_COUNTER_WIDTH-1:0] index_d;
+
+    // map registers to output ports
+    assign ab_addr  = index_ab;
+    assign n_addr   = index_n;
+    assign d_addr   = index_d;
+
+
+    //
+    // Subtractor
+    //
+    wire [31:0] sub32_d;
+    wire        sub32_b_in;
+    wire        sub32_b_out;
+
+    `CRYPTECH_PRIMITIVE_SUB32 sub32
+    (
+        .clk    (clk),
+        .a      (a_din),
+        .b      (b_din),
+        .d      (sub32_d),
+        .b_in   (sub32_b_in),
+        .b_out  (sub32_b_out)
+    );
+
+
+    //
+    // Adder
+    //
+    wire [31:0] add32_s;
+    wire        add32_c_in;
+    wire        add32_c_out;
+
+    `CRYPTECH_PRIMITIVE_ADD32 add32
+    (
+        .clk    (clk),
+        .a      (sub32_d),
+        .b      (n_din),
+        .s      (add32_s),
+        .c_in   (add32_c_in),
+        .c_out  (add32_c_out)
+    );
+
+
+    //
+    // FSM
+    //
+
+    localparam FSM_SHREG_WIDTH = 2 * OPERAND_NUM_WORDS + 5;
+
+    reg [FSM_SHREG_WIDTH-1:0] fsm_shreg;
+
+    assign rdy = fsm_shreg[0];
+
+    wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_inc_index_ab   = fsm_shreg[FSM_SHREG_WIDTH - (0 * OPERAND_NUM_WORDS + 1) : FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 0)];
+    wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_inc_index_n    = fsm_shreg[FSM_SHREG_WIDTH - (0 * OPERAND_NUM_WORDS + 2) : FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 1)];
+    wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_store_dif_ab   = fsm_shreg[FSM_SHREG_WIDTH - (0 * OPERAND_NUM_WORDS + 3) : FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 2)];
+    wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_store_dif_ab_n = fsm_shreg[FSM_SHREG_WIDTH - (0 * OPERAND_NUM_WORDS + 4) : FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 3)];
+    wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_store_data_d   = fsm_shreg[FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 4) : FSM_SHREG_WIDTH - (2 * OPERAND_NUM_WORDS + 3)];
+    wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_inc_index_d    = fsm_shreg[FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 5) : FSM_SHREG_WIDTH - (2 * OPERAND_NUM_WORDS + 4)];
+    wire                         fsm_latch_msb_borrow     = fsm_shreg[FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 2)];
+
+wire inc_index_ab   = |fsm_shreg_inc_index_ab;
+wire inc_index_n    = |fsm_shreg_inc_index_n;
+wire store_dif_ab   = |fsm_shreg_store_dif_ab;
+wire store_dif_ab_n = |fsm_shreg_store_dif_ab_n;
+wire store_data_d   = |fsm_shreg_store_data_d;
+wire inc_index_d    = |fsm_shreg_inc_index_d;
+
+    always @(posedge clk or negedge rst_n)
+        //
+        if (rst_n == 1'b0)
+            //
+            fsm_shreg <= {{FSM_SHREG_WIDTH-1{1'b0}}, 1'b1};
+            //
+        else begin
+            //
+            if (rdy)    fsm_shreg <= {ena, {FSM_SHREG_WIDTH-2{1'b0}}, ~ena};
+            //
+            else        fsm_shreg <= {1'b0, fsm_shreg[FSM_SHREG_WIDTH-1:1]};
+            //
+        end
+
+
+    //
+    // Borrow & Carry Masking Logic
+    //
+    reg sub32_b_mask;
+    reg add32_c_mask;
+
+    always @(posedge clk) begin
+        //
+        sub32_b_mask <= (index_ab == WORD_INDEX_ZERO) ? 1'b1 : 1'b0;
+        add32_c_mask <= (index_n  == WORD_INDEX_ZERO) ? 1'b1 : 1'b0;
+        //
+    end
+
+    assign sub32_b_in = sub32_b_out & ~sub32_b_mask;
+    assign add32_c_in = add32_c_out & ~add32_c_mask;
+
+
+    //
+    // Borrow Latch Logic
+    //
+    reg sub32_borrow_latch;
+
+    always @(posedge clk) begin
+        //
+        if (fsm_latch_msb_borrow) sub32_borrow_latch <= sub32_b_out;
+        //
+    end
+
+
+    //
+    // Intermediate Results
+    //
+    reg [32*OPERAND_NUM_WORDS-1:0] d_ab;
+    reg [32*OPERAND_NUM_WORDS-1:0] d_ab_n;
+
+    always @(posedge clk)
+        //
+        if (store_data_d) begin
+            //
+            d_ab   <= {{32{1'bX}}, d_ab[32*OPERAND_NUM_WORDS-1:32]};
+            d_ab_n <= {{32{1'bX}}, d_ab_n[32*OPERAND_NUM_WORDS-1:32]};
+        end else begin
+            //
+            if (store_dif_ab)   d_ab   <= {sub32_d, d_ab[32*OPERAND_NUM_WORDS-1:32]};
+            if (store_dif_ab_n) d_ab_n <= {add32_s, d_ab_n[32*OPERAND_NUM_WORDS-1:32]};
+            //
+        end
+
+
+    //
+    // Word Index Increment Logic
+    //
+    always @(posedge clk)
+        //
+        if (rdy) begin
+            //
+            index_ab <= WORD_INDEX_ZERO;
+            index_n  <= WORD_INDEX_ZERO;
+            index_d  <= WORD_INDEX_ZERO;
+            //
+        end else begin
+            //
+            if (inc_index_ab) index_ab <= WORD_INDEX_NEXT_OR_ZERO(index_ab);
+            if (inc_index_n)  index_n  <= WORD_INDEX_NEXT_OR_ZERO(index_n);
+            if (inc_index_d)  index_d  <= WORD_INDEX_NEXT_OR_ZERO(index_d);
+            //
+        end
+
+
+    //
+    // Output Difference Selector
+    //
+    wire mux_select_ab_n = sub32_borrow_latch;
+
+
+    //
+    // Output Data and Write Enable Logic
+    //
+    reg         d_wren_reg;
+    reg  [31:0] d_dout_reg;
+    wire [31:0] d_dout_mux = mux_select_ab_n ? d_ab_n[31:0] : d_ab[31:0];
+
+    assign d_wren = d_wren_reg;
+    assign d_dout = d_dout_reg;
+
+    always @(posedge clk)
+        //
+        if (rdy) begin
+            //
+            d_wren_reg <= 1'b0;
+            d_dout_reg <= {32{1'bX}};
+            //
+        end else begin
+            //
+            d_wren_reg <= store_data_d;
+            d_dout_reg <= store_data_d ? d_dout_mux : {32{1'bX}};
+            //
+        end
+
+
+endmodule
+
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/multiword/multiword_comparator.v b/multiword/multiword_comparator.v
new file mode 100644
index 0000000..bbdb2a6
--- /dev/null
+++ b/multiword/multiword_comparator.v
@@ -0,0 +1,232 @@
+//------------------------------------------------------------------------------
+//
+// multiword_comparator.v
+// -----------------------------------------------------------------------------
+// Multi-word comparator.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2015-2016, NORDUnet A/S
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//------------------------------------------------------------------------------
+
+module multiword_comparator
+(
+    clk, rst_n,
+    ena, rdy,
+    xy_addr, x_din, y_din,
+    cmp_l, cmp_e, cmp_g
+);
+
+    //
+    // Settings
+    //
+    `include "cryptech_primitive_switch.vh"
+
+
+    //
+    // Parameters
+    //
+    parameter WORD_COUNTER_WIDTH = 3;
+    parameter OPERAND_NUM_WORDS  = 8;
+
+
+    //
+    // Handy Numbers
+    //
+    localparam [WORD_COUNTER_WIDTH-1:0] WORD_INDEX_ZERO = 0;
+    localparam [WORD_COUNTER_WIDTH-1:0] WORD_INDEX_LAST = OPERAND_NUM_WORDS - 1;
+
+
+    //
+    // Handy Functions
+    //
+    function  [WORD_COUNTER_WIDTH-1:0] WORD_INDEX_PREV_OR_LAST;
+        input [WORD_COUNTER_WIDTH-1:0] WORD_INDEX_CURRENT;
+        begin
+            WORD_INDEX_PREV_OR_LAST = (WORD_INDEX_CURRENT > WORD_INDEX_ZERO) ?
+            WORD_INDEX_CURRENT - 1'b1 : WORD_INDEX_LAST;
+        end
+    endfunction
+
+
+    //
+    // Ports
+    //
+    input                               clk;        // system clock
+    input                               rst_n;      // active-low async reset
+
+    input                               ena;        // enable input
+    output                              rdy;        // ready output
+
+    output  [WORD_COUNTER_WIDTH-1:0]    xy_addr;    // address of current X and Y words
+    input   [                32-1:0]    x_din;      // current X word
+    input   [                32-1:0]    y_din;      // current Y word
+
+    output                              cmp_l;      // X < Y ?
+    output                              cmp_e;      // X = Y ?
+    output                              cmp_g;      // X > Y ?
+
+
+    //
+    // Word Indices
+    //
+    reg [WORD_COUNTER_WIDTH-1:0] index_xy;
+
+    
+    //
+    // Comparison Result
+    //
+    reg reg_cmp_l;
+    reg reg_cmp_e;
+    reg reg_cmp_g;
+
+
+    //
+    // Output Mapping
+    //
+    assign xy_addr  = index_xy;
+
+    assign cmp_l = reg_cmp_l;
+    assign cmp_e = reg_cmp_e;
+    assign cmp_g = reg_cmp_g;
+
+
+    //
+    // FSM
+    //
+    localparam FSM_SHREG_WIDTH = 1 * OPERAND_NUM_WORDS + 3;
+    localparam [FSM_SHREG_WIDTH-1:0] FSM_SHREG_INIT = {{FSM_SHREG_WIDTH-1{1'b0}}, 1'b1};
+
+    
+    reg [FSM_SHREG_WIDTH-1:0] fsm_shreg = FSM_SHREG_INIT;
+
+    assign rdy = fsm_shreg[0];
+
+    wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_dec_index_xy  = fsm_shreg[FSM_SHREG_WIDTH - (0 * OPERAND_NUM_WORDS + 1) : FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 0)];
+    wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_calc_leg      = fsm_shreg[FSM_SHREG_WIDTH - (0 * OPERAND_NUM_WORDS + 3) : FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 2)];
+    wire                         fsm_shreg_calc_leg_last = fsm_shreg[FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 2)];
+
+    wire dec_index_xy  = |fsm_shreg_dec_index_xy;
+    wire calc_leg      = |fsm_shreg_calc_leg;
+    wire calc_leg_last =  fsm_shreg_calc_leg_last;
+
+
+    always @(posedge clk or negedge rst_n)
+        //
+        if (rst_n == 1'b0)
+            //
+            fsm_shreg <= FSM_SHREG_INIT;
+            //
+        else begin
+            //
+            if (rdy)    fsm_shreg <= {ena, {FSM_SHREG_WIDTH-2{1'b0}}, ~ena};
+            //
+            else        fsm_shreg <= {1'b0, fsm_shreg[FSM_SHREG_WIDTH-1:1]};
+            //
+        end
+
+
+    //
+    // Word Index Increment Logic
+    //
+    always @(posedge clk)
+        //
+        if (rdy)               index_xy <= WORD_INDEX_LAST;
+        else if (dec_index_xy) index_xy <= WORD_INDEX_PREV_OR_LAST(index_xy);
+
+
+    //
+    // 32-bit Subtractor
+    //
+    wire [31: 0] sub32_d_out;
+    wire         sub32_b_in;
+    wire         sub32_b_out;
+
+    `CRYPTECH_PRIMITIVE_SUB32 sub32_inst
+    (
+        .clk    (clk),
+
+        .a      (x_din),
+        .b      (y_din),
+
+        .d      (sub32_d_out),
+
+        .b_in   (sub32_b_in),
+        .b_out  (sub32_b_out)
+    );
+
+
+    //
+    // Borrow Masking Logic
+    //
+    reg         sub32_b_mask;
+
+    always @(posedge clk)
+        //
+        sub32_b_mask <= (index_xy  == WORD_INDEX_LAST) ? 1'b1 : 1'b0;
+
+    assign sub32_b_in = sub32_b_out & ~sub32_b_mask;
+
+    
+    //
+    // Output Logic
+    //
+    wire cmp_unresolved = !(cmp_l || cmp_g);
+
+    wire cmp_borrow_is_set         = (sub32_b_out ==  1'b1) ? 1'b1 : 1'b0;
+    wire cmp_difference_is_nonzero = (sub32_d_out != 32'd0) ? 1'b1 : 1'b0;
+
+    always @(posedge clk)
+        //
+        if (rdy) begin
+            //
+            if (ena) begin
+                //
+                reg_cmp_l   <= 1'b0;
+                reg_cmp_e   <= 1'b0;
+                reg_cmp_g   <= 1'b0;
+                //
+            end
+        //
+        end else if (cmp_unresolved && calc_leg) begin
+            //
+            if ( cmp_borrow_is_set)                                                reg_cmp_l <= 1'b1;
+            if (!cmp_borrow_is_set &&  cmp_difference_is_nonzero)                  reg_cmp_g <= 1'b1;
+            if (!cmp_borrow_is_set && !cmp_difference_is_nonzero && calc_leg_last) reg_cmp_e <= 1'b1;
+            //
+        end
+
+
+endmodule
+
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/multiword/multiword_mover.v b/multiword/multiword_mover.v
new file mode 100644
index 0000000..8a7a015
--- /dev/null
+++ b/multiword/multiword_mover.v
@@ -0,0 +1,169 @@
+//------------------------------------------------------------------------------
+//
+// multiword_mover.v
+// -----------------------------------------------------------------------------
+// Multi-word data mover.
+//
+// Authors: Pavel Shatov
+//
+// Copyright (c) 2015-2016, 2018 NORDUnet A/S
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// - Redistributions of source code must retain the above copyright notice,
+//   this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright notice,
+//   this list of conditions and the following disclaimer in the documentation
+//   and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may be
+//   used to endorse or promote products derived from this software without
+//   specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//------------------------------------------------------------------------------
+
+module multiword_mover
+(
+    clk, rst_n,
+    ena, rdy,
+    x_addr, y_addr, y_wren,
+    x_din, y_dout
+);
+
+
+    //
+    // Parameters
+    //
+    parameter WORD_COUNTER_WIDTH    = 3;
+    parameter OPERAND_NUM_WORDS     = 8;
+
+
+    //
+    // Handy Numbers
+    //
+    localparam  [WORD_COUNTER_WIDTH-1:0]    WORD_INDEX_ZERO = 0;
+    localparam  [WORD_COUNTER_WIDTH-1:0]    WORD_INDEX_LAST = OPERAND_NUM_WORDS - 1;
+
+
+    //
+    // Handy Functions
+    //
+    function [WORD_COUNTER_WIDTH-1:0] WORD_INDEX_NEXT_OR_ZERO;
+    input    [WORD_COUNTER_WIDTH-1:0] WORD_INDEX_CURRENT;
+    begin
+        WORD_INDEX_NEXT_OR_ZERO = (WORD_INDEX_CURRENT < WORD_INDEX_LAST) ?
+            WORD_INDEX_CURRENT + 1'b1 : WORD_INDEX_ZERO;
+    end
+    endfunction
+
+
+    //
+    // Ports
+    //
+    input                               clk;    // system clock
+    input                               rst_n;  // active-low async reset
+
+    input                               ena;    // enable input
+    output                              rdy;    // ready output
+
+    output  [WORD_COUNTER_WIDTH-1:0]    x_addr; // address of current X word
+    output  [WORD_COUNTER_WIDTH-1:0]    y_addr; // address of current Y word
+    output                              y_wren; // store current Y word
+
+    input   [                32-1:0]    x_din;  // current X word
+    output  [                32-1:0]    y_dout; // current Y word
+
+
+    //
+    // Word Indices
+    //
+    reg [WORD_COUNTER_WIDTH-1:0] index_x;
+    reg [WORD_COUNTER_WIDTH-1:0] index_y;
+
+
+    //
+    // Output Mapping
+    //
+    assign x_addr   = index_x;
+    assign y_addr   = index_y;
+
+
+    //
+    // FSM
+    //
+    localparam FSM_SHREG_WIDTH = 1 * OPERAND_NUM_WORDS + 2;
+    localparam [FSM_SHREG_WIDTH-1:0] FSM_SHREG_INIT = {{(FSM_SHREG_WIDTH-1){1'b0}}, 1'b1};
+    
+    reg [FSM_SHREG_WIDTH-1:0] fsm_shreg = FSM_SHREG_INIT;
+
+    assign rdy = fsm_shreg[0];
+
+    wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_inc_index_x = fsm_shreg[FSM_SHREG_WIDTH - (0 * OPERAND_NUM_WORDS + 1) : FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 0)];
+    wire [OPERAND_NUM_WORDS-1:0] fsm_shreg_inc_index_y = fsm_shreg[FSM_SHREG_WIDTH - (0 * OPERAND_NUM_WORDS + 2) : FSM_SHREG_WIDTH - (1 * OPERAND_NUM_WORDS + 1)];
+
+    wire inc_index_x    = |fsm_shreg_inc_index_x;
+    wire inc_index_y    = |fsm_shreg_inc_index_y;
+    wire store_word_y   = |fsm_shreg_inc_index_x;
+
+    always @(posedge clk or negedge rst_n)
+        //
+        if (rst_n == 1'b0)  fsm_shreg <= FSM_SHREG_INIT;
+        else begin
+            if (rdy)        fsm_shreg <= {ena, {FSM_SHREG_WIDTH-2{1'b0}}, ~ena};
+            else            fsm_shreg <= {1'b0, fsm_shreg[FSM_SHREG_WIDTH-1:1]};
+        end
+
+
+    //
+    // Word Index Increment Logic
+    //
+    always @(posedge clk)
+        //
+        if (rdy) begin
+            index_x <= WORD_INDEX_ZERO;
+            index_y <= WORD_INDEX_ZERO;
+        end else begin
+            if (inc_index_x) index_x <= WORD_INDEX_NEXT_OR_ZERO(index_x);
+            if (inc_index_y) index_y <= WORD_INDEX_NEXT_OR_ZERO(index_y);
+        end
+
+
+    //
+    // Write Enable Logic
+    //
+    reg y_wren_reg = 1'b0;
+
+    assign y_wren = y_wren_reg;
+
+    always @(posedge clk)
+        //
+        if (rdy) y_wren_reg  <= 1'b0;
+        else     y_wren_reg  <= store_word_y;
+
+
+    //
+    // Output Logic
+    //
+    assign y_dout = x_din;
+
+
+endmodule
+
+
+//------------------------------------------------------------------------------
+// End-of-File
+//------------------------------------------------------------------------------
diff --git a/util/cryptech_clog2.vh b/util/cryptech_clog2.vh
new file mode 100644
index 0000000..06120c4
--- /dev/null
+++ b/util/cryptech_clog2.vh
@@ -0,0 +1,48 @@
+//======================================================================
+//
+// Copyright (c) 2015, 2018 NORDUnet A/S All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+// - Redistributions of source code must retain the above copyright
+//   notice, this list of conditions and the following disclaimer.
+//
+// - Redistributions in binary form must reproduce the above copyright
+//   notice, this list of conditions and the following disclaimer in the
+//   documentation and/or other materials provided with the distribution.
+//
+// - Neither the name of the NORDUnet nor the names of its contributors may
+//   be used to endorse or promote products derived from this software
+//   without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+//======================================================================
+
+function    integer cryptech_clog2;
+    input   integer value;
+            integer result;
+    //
+    begin
+        value = value - 1;
+        for (result = 0; value > 0; result = result + 1)
+            value = value >> 1;
+        clog2 = result;
+    end
+    //
+endfunction
+
+//======================================================================
+// End of file
+//======================================================================



More information about the Commits mailing list