├── .gitattributes ├── .gitignore ├── LICENSE ├── README.md ├── src ├── model │ ├── c │ │ ├── .gitignore │ │ ├── Debug │ │ │ ├── makefile │ │ │ ├── objects.mk │ │ │ ├── sources.mk │ │ │ └── src │ │ │ │ └── subdir.mk │ │ └── src │ │ │ ├── ModExpTestBench.c │ │ │ ├── autogenerated_tests.c │ │ │ ├── autogenerated_tests.h │ │ │ ├── bignum_uint32_t.c │ │ │ ├── bignum_uint32_t.h │ │ │ ├── montgomery_array.c │ │ │ ├── montgomery_array.h │ │ │ ├── montgomery_array_test.c │ │ │ ├── montgomery_array_test.h │ │ │ ├── simple_tests.c │ │ │ └── simple_tests.h │ ├── java │ │ ├── bin │ │ │ └── NOTE.txt │ │ ├── lib │ │ │ ├── README.txt │ │ │ ├── hamcrest-core-1.3.jar │ │ │ └── junit-4.12.jar │ │ ├── src │ │ │ └── rsa │ │ │ │ ├── BigNum.java │ │ │ │ ├── BigNumTest.java │ │ │ │ ├── Montgomery.java │ │ │ │ ├── MontgomeryArray.java │ │ │ │ └── PerformanceClock.java │ │ └── test │ │ │ └── rsa │ │ │ └── MontgomeryArrayTest.java │ └── python │ │ └── modexp.py ├── rtl │ ├── adder32.v │ ├── blockmem1r1w.v │ ├── blockmem2r1w.v │ ├── blockmem2r1wptr.v │ ├── blockmem2rptr1w.v │ ├── blockmem_rw32_r128.v │ ├── blockmem_rw32_r256.v │ ├── blockmem_rw32_r64.v │ ├── modexp.v │ ├── modexp_core.v │ ├── montprod.v │ ├── residue.v │ ├── shl32.v │ └── shr32.v ├── tb │ ├── tb_modexp.v │ ├── tb_modexp_autogenerated.v │ ├── tb_modexp_autogenerated_template.v │ ├── tb_montprod.v │ └── tb_residue.v └── testgenerator │ ├── .classpath │ ├── .gitignore │ ├── .project │ ├── .settings │ └── org.eclipse.jdt.core.prefs │ └── src │ └── org │ └── crypttech │ └── modexp │ └── testgenerator │ ├── TestGenerator.java │ ├── TestGenerator65537.java │ ├── TestGeneratorBasic.java │ ├── TestGeneratorRSA.java │ ├── TestVector.java │ ├── Util.java │ └── format │ ├── GeneratorC.java │ ├── GeneratorVerilog.java │ └── ModExpTestFormater.java └── toolruns └── Makefile /.gitattributes: -------------------------------------------------------------------------------- 1 | # Helping linguist detect files as Verilog, not Coq. 2 | *.v linguist-language=Verilog 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #======================================================================= 2 | # 3 | # .gitignore 4 | # ---------- 5 | # Gitignore for core projects. 6 | #======================================================================= 7 | 8 | ## Generated files 9 | test* 10 | *.sim 11 | 12 | ## Log files 13 | *.log 14 | 15 | 16 | ## Subdirs in toolruns for vendor tools 17 | /toolruns/quartus 18 | /toolruns/ise/ 19 | /toolruns/vivado 20 | /toolruns/modelsim 21 | /toolruns/libero 22 | /toolruns/icestorm 23 | 24 | #======================================================================= 25 | # EOF .gitignore 26 | #======================================================================= 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Author: Joachim Strömbergson 2 | Copyright (c) 2014, Secworks Sweden AB 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this 9 | list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright notice, 12 | this list of conditions and the following disclaimer in the documentation 13 | and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | modexp 2 | ====== 3 | 4 | Modular exponentiation core for implementing public key algorithms such 5 | as RSA, DH, ElGamal etc. 6 | 7 | The core calculates the following function: 8 | 9 | C = M ** e mod N 10 | 11 | M is a message with a length of n bits 12 | e is the exponent with a length of m bits 13 | N is the modulus with a length of n bits 14 | 15 | The size n be one and up to and including 8192 bits in steps of 32 16 | bits. 17 | 18 | The size m be one and up to and including 8192 bits in steps of 32 19 | bits. 20 | 21 | The core has a 32-bit memory like interface, but provides status signals 22 | to inform the system that a given operation has is done. Additionally, 23 | any errors will also be asserted. 24 | 25 | The core is written in Verilog 2001 and suitable for implementation in 26 | FPGA and ASIC devices. No vendor specific macros are used in the code. 27 | 28 | 29 | ## Status ## 30 | 31 | Really broken. Does **NOT** work. 32 | 33 | 34 | ## Implementation details ## 35 | 36 | The core is iterative with 32-bit operands and not the fastest core on 37 | the planet. 38 | 39 | 40 | ## Future developments ## 41 | 42 | - The core will perform blinding to protect against side channel 43 | attacks. 44 | 45 | - Increased operands to 64-, 128-, or possibly even 256 bits for 46 | increased performance. 47 | 48 | 49 | ## FPGA-results ## 50 | 51 | ## Altera Cyclone-V ### 52 | 53 | - 203 registers 54 | - 387 ALMs 55 | - 106496 block memory bits 56 | - 107 MHz 57 | 58 | 59 | ### Xilinx Artix-7 100T ### 60 | 61 | - 160 registers 62 | - 565 LUTs 63 | - 13 RAMB18E1 block memories 64 | - 160 MHz 65 | 66 | ### Xilinx Spartan-6 LX45 ### 67 | 68 | - 169 registers 69 | - 589 LUTs 70 | - 13 RAMB8BWER block memories 71 | - 136 MHz 72 | 73 | 74 | ## Status ## 75 | 76 | ***(2015-04-27)*** 77 | 78 | Modexp simulation with exponent and modolus with up to 1280 bits 79 | simulates. The auto test generation system works. Implementation in 80 | different FPGA types and vendors works. 81 | 82 | 83 | ***(2015-04-23)*** 84 | 85 | The Montgomery multiplication module works. The Residue calculation 86 | module works. Top level integration and debugging is onging. The core 87 | does not yet work and there are dragons to be found. 88 | 89 | 90 | ***(2014-12-07)*** 91 | 92 | Renamed the core tom modexp from rsa to make it more clear that it 93 | provides generic modular exponentiation, not RSA. 94 | 95 | 96 | ***(2014-10-01)*** 97 | 98 | Very early phase. Started to collect information and drawing some rough 99 | ideas on paper. 100 | -------------------------------------------------------------------------------- /src/model/c/.gitignore: -------------------------------------------------------------------------------- 1 | /Release/ 2 | -------------------------------------------------------------------------------- /src/model/c/Debug/makefile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Automatically-generated file. Do not edit! 3 | ################################################################################ 4 | 5 | -include ../makefile.init 6 | 7 | RM := rm -rf 8 | CC = clang 9 | 10 | # All of the sources participating in the build are defined here 11 | -include sources.mk 12 | -include src/subdir.mk 13 | -include subdir.mk 14 | -include objects.mk 15 | 16 | ifneq ($(MAKECMDGOALS),clean) 17 | ifneq ($(strip $(C_DEPS)),) 18 | -include $(C_DEPS) 19 | endif 20 | endif 21 | 22 | -include ../makefile.defs 23 | 24 | # Add inputs and outputs from these tool invocations to the build variables 25 | 26 | # All Target 27 | all: modexp 28 | 29 | # Tool invocations 30 | modexp: $(OBJS) $(USER_OBJS) 31 | @echo 'Building target: $@' 32 | @echo 'Invoking: MacOS X C Linker' 33 | $(CC) -o "modexp" $(OBJS) $(USER_OBJS) $(LIBS) 34 | @echo 'Finished building target: $@' 35 | @echo ' ' 36 | 37 | # Other Targets 38 | clean: 39 | -$(RM) $(EXECUTABLES)$(OBJS)$(C_DEPS) modexp 40 | -@echo ' ' 41 | 42 | .PHONY: all clean dependents 43 | .SECONDARY: 44 | 45 | -include ../makefile.targets 46 | -------------------------------------------------------------------------------- /src/model/c/Debug/objects.mk: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Automatically-generated file. Do not edit! 3 | ################################################################################ 4 | 5 | USER_OBJS := 6 | 7 | LIBS := 8 | 9 | -------------------------------------------------------------------------------- /src/model/c/Debug/sources.mk: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Automatically-generated file. Do not edit! 3 | ################################################################################ 4 | 5 | OBJ_SRCS := 6 | ASM_SRCS := 7 | C_SRCS := 8 | O_SRCS := 9 | S_UPPER_SRCS := 10 | EXECUTABLES := 11 | OBJS := 12 | C_DEPS := 13 | 14 | # Every subdirectory with source files must be described here 15 | SUBDIRS := \ 16 | src \ 17 | 18 | -------------------------------------------------------------------------------- /src/model/c/Debug/src/subdir.mk: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # Automatically-generated file. Do not edit! 3 | ################################################################################ 4 | 5 | CC = clang 6 | CC_OPT = -O2 7 | CC_FLAGS = -g3 -pedantic -pedantic-errors -Wall -Wextra -Werror -Wconversion -c -fmessage-length=0 -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" 8 | 9 | # Add inputs and outputs from these tool invocations to the build variables 10 | C_SRCS += \ 11 | ../src/ModExpTestBench.c \ 12 | ../src/simple_tests.c \ 13 | ../src/autogenerated_tests.c \ 14 | ../src/bignum_uint32_t.c \ 15 | ../src/montgomery_array.c \ 16 | ../src/montgomery_array_test.c 17 | 18 | OBJS += \ 19 | ./src/ModExpTestBench.o \ 20 | ./src/simple_tests.o \ 21 | ./src/autogenerated_tests.o \ 22 | ./src/bignum_uint32_t.o \ 23 | ./src/montgomery_array.o \ 24 | ./src/montgomery_array_test.o 25 | 26 | C_DEPS += \ 27 | ./src/ModExpTestBench.d \ 28 | ./src/simple_tests.d \ 29 | ./src/autogenerated_tests.d \ 30 | ./src/bignum_uint32_t.d \ 31 | ./src/montgomery_array.d \ 32 | ./src/montgomery_array_test.d 33 | 34 | 35 | # Each subdirectory must supply rules for building sources it contributes 36 | src/%.o: ../src/%.c 37 | @echo 'Building file: $<' 38 | @echo 'Invoking: clang C Compiler' 39 | $(CC) $(CC_OPT) $(CC_FLAGS) -o "$@" "$<" 40 | @echo 'Finished building: $<' 41 | @echo ' ' 42 | -------------------------------------------------------------------------------- /src/model/c/src/ModExpTestBench.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "simple_tests.h" 4 | #include "autogenerated_tests.h" 5 | #include "montgomery_array_test.h" 6 | #include "bignum_uint32_t.h" 7 | 8 | int main(void) { 9 | simple_tests(); 10 | // autogenerated_tests(); 11 | // montgomery_array_tests(0); 12 | 13 | print_assert_array_stats(); 14 | 15 | return EXIT_SUCCESS; 16 | } 17 | -------------------------------------------------------------------------------- /src/model/c/src/autogenerated_tests.h: -------------------------------------------------------------------------------- 1 | #ifndef AUTOGENERATED_TESTS_H_ 2 | #define AUTOGENERATED_TESTS_H_ 3 | 4 | void autogenerated_tests(void); 5 | 6 | #endif /* AUTOGENERATED_TESTS_H_ */ 7 | -------------------------------------------------------------------------------- /src/model/c/src/bignum_uint32_t.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "bignum_uint32_t.h" 4 | 5 | int assert_array_total = 0; 6 | int assert_array_error = 0; 7 | void assertArrayEquals(uint32_t length, uint32_t *expected, uint32_t *actual) { //needed in tests 8 | int equals = 1; 9 | for (uint32_t i = 0; i < length; i++) 10 | equals &= expected[i] == actual[i]; 11 | printf("%s expected: \n[", equals ? "PASS" : "FAIL"); 12 | for (uint32_t i = 0; i < length - 1; i++) { 13 | if ((i > 0) && (!(i % 4))) 14 | printf("\n "); 15 | printf("0x%08x, ", expected[i]); 16 | } 17 | printf("0x%08x]", expected[length - 1]); 18 | 19 | printf("\n\n"); 20 | printf("actual:\n["); 21 | for (uint32_t i = 0; i < length - 1; i++) { 22 | if ((i > 0) && (!(i % 4))) 23 | printf("\n "); 24 | printf("0x%08x, ", actual[i]); 25 | } 26 | printf("0x%08x]\n", actual[length - 1]); 27 | 28 | printf("\n"); 29 | assert_array_total++; 30 | if (!equals) 31 | assert_array_error++; 32 | } 33 | 34 | void print_assert_array_stats(void) { 35 | printf("%d tests, failed: %d\n", assert_array_total, assert_array_error); 36 | } 37 | 38 | void copy_array(uint32_t length, uint32_t *src, uint32_t *dst) { 39 | for (uint32_t i = 0; i < length; i++) 40 | dst[i] = src[i]; 41 | } 42 | 43 | void add_array(uint32_t length, uint32_t *a, uint32_t *b, uint32_t *result) { 44 | uint64_t carry = 0; 45 | for (int32_t i = ((int32_t) length) - 1; i >= 0; i--) { 46 | uint64_t r = carry; 47 | uint32_t aa = a[i]; 48 | uint32_t bb = b[i]; 49 | r += aa & 0xFFFFFFFFul; 50 | r += bb & 0xFFFFFFFFul; 51 | carry = r >> 32; 52 | result[i] = (uint32_t) r; 53 | } 54 | } 55 | 56 | void sub_array(uint32_t length, uint32_t *a, uint32_t *b, uint32_t *result) { 57 | uint64_t carry = 1; 58 | for (int32_t wordIndex = ((int32_t) length) - 1; wordIndex >= 0; wordIndex--) { 59 | uint64_t r = carry; 60 | uint32_t aa = a[wordIndex]; 61 | uint32_t bb = ~b[wordIndex]; 62 | r += aa & 0xFFFFFFFFul; 63 | r += bb & 0xFFFFFFFFul; 64 | carry = r >> 32; 65 | result[wordIndex] = (uint32_t) r; 66 | } 67 | } 68 | 69 | void shift_right_1_array(uint32_t length, uint32_t *a, uint32_t *result) { 70 | uint32_t prev = 0; // MSB will be zero extended 71 | for (uint32_t wordIndex = 0; wordIndex < length; wordIndex++) { 72 | uint32_t aa = a[wordIndex]; 73 | result[wordIndex] = (aa >> 1) | (prev << 31); 74 | prev = aa & 1; // Lower word will be extended with LSB of this word 75 | } 76 | } 77 | 78 | void shift_left_1_array(uint32_t length, uint32_t *a, uint32_t *result) { 79 | uint32_t prev = 0; // LSB will be zero extended 80 | for (int32_t wordIndex = ((int32_t) length) - 1; wordIndex >= 0; wordIndex--) { 81 | uint32_t aa = a[wordIndex]; 82 | result[wordIndex] = (aa << 1) | prev; 83 | 84 | // Higher word will be extended with MSB of this word 85 | prev = aa >> 31; 86 | } 87 | } 88 | 89 | void debugArray(char *msg, uint32_t length, uint32_t *array) { 90 | printf("%s ", msg); 91 | for (uint32_t i = 0; i < length; i++) { 92 | printf("%8x ", array[i]); 93 | } 94 | printf("\n"); 95 | } 96 | 97 | void modulus_array(uint32_t length, uint32_t *a, uint32_t *modulus, uint32_t *temp, 98 | uint32_t *reminder) { 99 | copy_array(length, a, reminder); 100 | 101 | while (!greater_than_array(length, modulus, reminder)) { 102 | 103 | copy_array(length, modulus, temp); 104 | 105 | while (((temp[0] & 0x80000000) == 0) 106 | && (!greater_than_array(length, temp, reminder))) { 107 | sub_array(length, reminder, temp, reminder); 108 | shift_left_1_array(length, temp, temp); 109 | } 110 | } 111 | } 112 | 113 | void zero_array(uint32_t length, uint32_t *a) { 114 | for (uint32_t i = 0; i < length; i++) 115 | a[i] = 0; 116 | } 117 | 118 | int greater_than_array(uint32_t length, uint32_t *a, uint32_t *b) { 119 | for (uint32_t i = 0; i < length; i++) { 120 | if (a[i] > b[i]) 121 | return 1; 122 | if (a[i] < b[i]) 123 | return 0; 124 | } 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /src/model/c/src/bignum_uint32_t.h: -------------------------------------------------------------------------------- 1 | /* 2 | * bignum_uint32_t.h 3 | * 4 | * Created on: Mar 5, 2015 5 | * Author: psjm 6 | */ 7 | 8 | #ifndef BIGNUM_UINT32_T_H_ 9 | #define BIGNUM_UINT32_T_H_ 10 | 11 | void modulus_array(uint32_t length, uint32_t *a, uint32_t *modulus, uint32_t *temp, 12 | uint32_t *reminder); 13 | int greater_than_array(uint32_t length, uint32_t *a, uint32_t *b); 14 | void add_array(uint32_t length, uint32_t *a, uint32_t *b, uint32_t *result); 15 | void sub_array(uint32_t length, uint32_t *a, uint32_t *b, uint32_t *result); 16 | void shift_right_1_array(uint32_t length, uint32_t *a, uint32_t *result); 17 | void shift_left_1_array(uint32_t length, uint32_t *a, uint32_t *result); 18 | void zero_array(uint32_t length, uint32_t *a); 19 | void copy_array(uint32_t length, uint32_t *src, uint32_t *dst); 20 | void debugArray(char *msg, uint32_t length, uint32_t *array); 21 | void assertArrayEquals(uint32_t length, uint32_t *expected, uint32_t *actual); 22 | void print_assert_array_stats(void); 23 | 24 | #endif /* BIGNUM_UINT32_T_H_ */ 25 | -------------------------------------------------------------------------------- /src/model/c/src/montgomery_array.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "bignum_uint32_t.h" 4 | #include "montgomery_array.h" 5 | 6 | void mont_prod_array(uint32_t length, uint32_t *A, uint32_t *B, uint32_t *M, uint32_t *s) { 7 | zero_array(length, s); 8 | for (int32_t wordIndex = ((int32_t) length) - 1; wordIndex >= 0; wordIndex--) { 9 | for (int i = 0; i < 32; i++) { 10 | 11 | uint32_t b = (B[wordIndex] >> i) & 1; 12 | 13 | //q = (s - b * A) & 1; 14 | uint32_t q = (s[length-1] ^ (A[length-1] & b)) & 1; // int q = (s - b * A) & 1; 15 | 16 | // s = (s + q*M + b*A) >>> 1; 17 | if (q == 1) { 18 | add_array(length, s, M, s); 19 | } else { 20 | //TODO possibly do some sub operation to temporary here just to force constant execution time. 21 | } 22 | 23 | if (b == 1) { 24 | add_array(length, s, A, s); 25 | } else { 26 | //TODO possibly do some sub operation to temporary here just to force constant execution time. 27 | } 28 | 29 | shift_right_1_array(length, s, s); 30 | } 31 | } 32 | } 33 | 34 | void m_residue_2_2N_array(uint32_t length, uint32_t N, uint32_t *M, uint32_t *temp, 35 | uint32_t *Nr) { 36 | zero_array(length, Nr); 37 | Nr[length - 1] = 1; // Nr = 1 == 2**(2N-2N) 38 | for (uint32_t i = 0; i < 2 * N; i++) { 39 | shift_left_1_array(length, Nr, Nr); 40 | modulus_array(length, Nr, M, temp, Nr); 41 | // debugArray(length, Nr); 42 | } 43 | // Nr = (2 ** 2N) mod M 44 | } 45 | 46 | uint32_t findN(uint32_t length, uint32_t *E) { 47 | uint32_t n = 0; 48 | for (uint32_t i = 0; i < 32 * length; i++) { 49 | uint32_t ei_ = E[length - 1 - (i / 32)]; 50 | uint32_t ei = (ei_ >> (i % 32)) & 1; 51 | if (ei == 1) { 52 | n = i+1; 53 | } 54 | } 55 | return n; 56 | } 57 | 58 | void mont_exp_array(uint32_t length, uint32_t *X, uint32_t *E, uint32_t *M, 59 | uint32_t *Nr, uint32_t *P, uint32_t *ONE, uint32_t *temp, 60 | uint32_t *temp2, uint32_t *Z) { 61 | //debugArray("X ", length, X); 62 | //debugArray("E ", length, E); 63 | //debugArray("M ", length, M); 64 | 65 | // 1. Nr := 2 ** 2N mod M 66 | const uint32_t N = 32 * length; 67 | m_residue_2_2N_array(length, N, M, temp, Nr); 68 | //debugArray("Nr", length, Nr); 69 | 70 | // 2. Z0 := MontProd( 1, Nr, M ) 71 | zero_array(length, ONE); 72 | ONE[length - 1] = 1; 73 | mont_prod_array(length, ONE, Nr, M, Z); 74 | //debugArray("Z0", length, Z); 75 | 76 | // 3. P0 := MontProd( X, Nr, M ); 77 | mont_prod_array(length, X, Nr, M, P); 78 | //debugArray("P0", length, P); 79 | 80 | // 4. for i = 0 to n-1 loop 81 | const uint32_t n = findN(length, E); //loop optimization for low values of E. Not necessary. 82 | for (uint32_t i = 0; i < n; i++) { 83 | uint32_t ei_ = E[length - 1 - (i / 32)]; 84 | uint32_t ei = (ei_ >> (i % 32)) & 1; 85 | // 6. if (ei = 1) then Zi+1 := MontProd ( Zi, Pi, M) else Zi+1 := Zi 86 | if (ei == 1) { 87 | mont_prod_array(length, Z, P, M, temp2); 88 | copy_array(length, temp2, Z); 89 | //debugArray("Z ", length, Z); 90 | } 91 | // 5. Pi+1 := MontProd( Pi, Pi, M ); 92 | mont_prod_array(length, P, P, M, temp2); 93 | copy_array(length, temp2, P); 94 | //debugArray("P ", length, P); 95 | // 7. end for 96 | } 97 | // 8. Zn := MontProd( 1, Zn, M ); 98 | mont_prod_array(length, ONE, Z, M, temp2); 99 | copy_array(length, temp2, Z); 100 | //debugArray("Z ", length, Z); 101 | // 9. RETURN Zn 102 | 103 | } 104 | 105 | // Experimental version where we add explicit lengths. 106 | void mont_exp_array2(uint32_t explength, uint32_t modlength, uint32_t *X, uint32_t *E, uint32_t *M, 107 | uint32_t *Nr, uint32_t *P, uint32_t *ONE, uint32_t *temp, 108 | uint32_t *temp2, uint32_t *Z) { 109 | //debugArray("X ", length, X); 110 | //debugArray("E ", length, E); 111 | //debugArray("M ", length, M); 112 | 113 | // 1. Nr := 2 ** 2N mod M 114 | const uint32_t N = 32 * modlength; 115 | m_residue_2_2N_array(modlength, N, M, temp, Nr); 116 | //debugArray("Nr", length, Nr); 117 | 118 | // 2. Z0 := MontProd( 1, Nr, M ) 119 | zero_array(modlength, ONE); 120 | ONE[modlength - 1] = 1; 121 | mont_prod_array(modlength, ONE, Nr, M, Z); 122 | //debugArray("Z0", length, Z); 123 | 124 | // 3. P0 := MontProd( X, Nr, M ); 125 | mont_prod_array(modlength, X, Nr, M, P); 126 | //debugArray("P0", length, P); 127 | 128 | // 4. for i = 0 to explength - 1 loop 129 | for (uint32_t i = 0; i < (explength * 32); i++) { 130 | uint32_t ei_ = E[explength - 1 - (i / 32)]; 131 | uint32_t ei = (ei_ >> (i % 32)) & 1; 132 | // 6. if (ei = 1) then Zi+1 := MontProd ( Zi, Pi, M) else Zi+1 := Zi 133 | if (ei == 1) { 134 | mont_prod_array(modlength, Z, P, M, temp2); 135 | copy_array(modlength, temp2, Z); 136 | //debugArray("Z ", length, Z); 137 | } 138 | // 5. Pi+1 := MontProd( Pi, Pi, M ); 139 | mont_prod_array(modlength, P, P, M, temp2); 140 | copy_array(modlength, temp2, P); 141 | //debugArray("P ", length, P); 142 | // 7. end for 143 | } 144 | // 8. Zn := MontProd( 1, Zn, M ); 145 | mont_prod_array(modlength, ONE, Z, M, temp2); 146 | copy_array(modlength, temp2, Z); 147 | //debugArray("Z ", length, Z); 148 | // 9. RETURN Zn 149 | 150 | } 151 | 152 | void die(const char *c) { 153 | printf("Fatal error: %s\n", c); 154 | exit(1); 155 | } 156 | 157 | void mod_exp_array(uint32_t length, uint32_t *X, uint32_t *E, uint32_t *M, uint32_t *Z) { 158 | uint32_t *Nr = calloc(length, sizeof(uint32_t)); 159 | uint32_t *P = calloc(length, sizeof(uint32_t)); 160 | uint32_t *ONE = calloc(length, sizeof(uint32_t)); 161 | uint32_t *temp = calloc(length, sizeof(uint32_t)); 162 | uint32_t *temp2 = calloc(length, sizeof(uint32_t)); 163 | if (Nr == NULL) die("calloc"); 164 | if (P == NULL) die("calloc"); 165 | if (ONE == NULL) die("calloc"); 166 | if (temp == NULL) die("calloc"); 167 | if (temp2 == NULL) die("calloc"); 168 | mont_exp_array(length, X, E, M, Nr, P, ONE, temp, temp2, Z); 169 | free(Nr); 170 | free(P); 171 | free(ONE); 172 | free(temp); 173 | free(temp2); 174 | } 175 | 176 | // Experimental version with explicit explength separate from modlength. 177 | void mod_exp_array2(uint32_t explength, uint32_t modlength, uint32_t *X, uint32_t *E, uint32_t *M, uint32_t *Z) { 178 | uint32_t *Nr = calloc(modlength, sizeof(uint32_t)); 179 | uint32_t *P = calloc(modlength, sizeof(uint32_t)); 180 | uint32_t *ONE = calloc(modlength, sizeof(uint32_t)); 181 | uint32_t *temp = calloc(modlength, sizeof(uint32_t)); 182 | uint32_t *temp2 = calloc(modlength, sizeof(uint32_t)); 183 | if (Nr == NULL) die("calloc"); 184 | if (P == NULL) die("calloc"); 185 | if (ONE == NULL) die("calloc"); 186 | if (temp == NULL) die("calloc"); 187 | if (temp2 == NULL) die("calloc"); 188 | mont_exp_array2(explength, modlength, X, E, M, Nr, P, ONE, temp, temp2, Z); 189 | free(Nr); 190 | free(P); 191 | free(ONE); 192 | free(temp); 193 | free(temp2); 194 | } 195 | -------------------------------------------------------------------------------- /src/model/c/src/montgomery_array.h: -------------------------------------------------------------------------------- 1 | /* 2 | * montgomery_array.h 3 | * 4 | * Created on: Mar 3, 2015 5 | * Author: psjm 6 | */ 7 | 8 | #ifndef MONTGOMERY_ARRAY_H_ 9 | #define MONTGOMERY_ARRAY_H_ 10 | 11 | void mont_prod_array(uint32_t length, uint32_t *A, uint32_t *B, uint32_t *M, 12 | uint32_t *s); 13 | void mod_exp_array(uint32_t length, uint32_t *X, uint32_t *E, uint32_t *M, uint32_t *Z); 14 | 15 | 16 | void mont_prod_array2(uint32_t explength, uint32_t modlength, uint32_t *A, uint32_t *B, uint32_t *M, 17 | uint32_t *s); 18 | 19 | void mod_exp_array2(uint32_t explength, uint32_t modlength, uint32_t *X, uint32_t *E, uint32_t *M, uint32_t *Z); 20 | 21 | #endif /* MONTGOMERY_ARRAY_H_ */ 22 | -------------------------------------------------------------------------------- /src/model/c/src/montgomery_array_test.h: -------------------------------------------------------------------------------- 1 | /* 2 | * montgomery_array_test.h 3 | * 4 | * Created on: Mar 4, 2015 5 | * Author: psjm 6 | */ 7 | 8 | #ifndef MONTGOMERY_ARRAY_TEST_H_ 9 | #define MONTGOMERY_ARRAY_TEST_H_ 10 | 11 | void montgomery_array_tests(int bigtests); 12 | 13 | #endif /* MONTGOMERY_ARRAY_TEST_H_ */ 14 | -------------------------------------------------------------------------------- /src/model/c/src/simple_tests.c: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // simple_tests.h 4 | // -------------- 5 | // Header fil to export the simple tests of the modexp C model. 6 | // 7 | // 8 | // Author: Joachim Strombergson 9 | // Copyright (c) 2015, Assured AB 10 | // All rights reserved. 11 | // 12 | // Redistribution and use in source and binary forms, with or 13 | // without modification, are permitted provided that the following 14 | // conditions are met: 15 | // 16 | // 1. Redistributions of source code must retain the above copyright 17 | // notice, this list of conditions and the following disclaimer. 18 | // 19 | // 2. Redistributions in binary form must reproduce the above copyright 20 | // notice, this list of conditions and the following disclaimer in 21 | // the documentation and/or other materials provided with the 22 | // distribution. 23 | // 24 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 33 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 35 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | //====================================================================== 37 | 38 | #include 39 | #include 40 | #include "montgomery_array.h" 41 | #include "bignum_uint32_t.h" 42 | 43 | void simple_3_7_11(void) { 44 | printf("=== Simple test with X = 3, E = 7 and M = 11 ===\n"); 45 | uint32_t X[] = { 0x3 }; 46 | uint32_t E[] = { 0x7 }; 47 | uint32_t M[] = { 0xb }; 48 | uint32_t expected[] = { 0x9 }; 49 | uint32_t Z[] = { 0x00000000 }; 50 | mod_exp_array(1, X, E, M, Z); 51 | assertArrayEquals(1, expected, Z); 52 | } 53 | 54 | void simple_251_251_257(void) { 55 | printf("=== Simple test with X = 251, E = 251 and M = 257 ===\n"); 56 | uint32_t X[] = { 0xfb }; 57 | uint32_t E[] = { 0xfb }; 58 | uint32_t M[] = { 0x101 }; 59 | uint32_t expected[] = { 0xb7 }; 60 | uint32_t Z[] = { 0x00000000 }; 61 | mod_exp_array(1, X, E, M, Z); 62 | assertArrayEquals(1, expected, Z); 63 | } 64 | 65 | 66 | void bigger_test(void) 67 | { 68 | printf("=== Bigger test with 128 bit operands.\n"); 69 | uint32_t exponent[] = {0x3285c343, 0x2acbcb0f, 0x4d023228, 0x2ecc73db}; 70 | uint32_t modulus[] = {0x267d2f2e, 0x51c216a7, 0xda752ead, 0x48d22d89}; 71 | uint32_t message[] = {0x29462882, 0x12caa2d5, 0xb80e1c66, 0x1006807f}; 72 | uint32_t expected[] = {0x0ddc404d, 0x91600596, 0x7425a8d8, 0xa066ca56}; 73 | uint32_t result[] = {0x00000000, 0x00000000, 0x00000000, 0x00000000}; 74 | 75 | mod_exp_array(4, message, exponent, modulus, result); 76 | assertArrayEquals(4, expected, result); 77 | } 78 | 79 | 80 | void small_e_64_mod(void) 81 | { 82 | printf("=== Simple test with small e and 64 bit modulus ===\n"); 83 | uint32_t X[] = { 0x00000000, 0xdb5a7e09, 0x86b98bfb }; 84 | uint32_t E[] = { 0x00000000, 0x00000000, 0x00010001 }; 85 | uint32_t M[] = { 0x00000000, 0xb3164743, 0xe1de267d }; 86 | uint32_t expected[] = { 0x00000000, 0x9fc7f328, 0x3ba0ae18 }; 87 | uint32_t Z[] = { 0x00000000, 0x00000000, 0x00000000 }; 88 | mod_exp_array(3, X, E, M, Z); 89 | assertArrayEquals(3, expected, Z); 90 | } 91 | 92 | void small_e_256_mod(void) { 93 | printf("=== Simple test with small e and 256 bit modulus ===\n"); 94 | uint32_t X[] = {0x00000000, 0xbd589a51, 0x2ba97013, 95 | 0xc4736649, 0xe233fd5c, 0x39fcc5e5, 96 | 0x2d60b324, 0x1112f2d0, 0x1177c62b}; 97 | uint32_t E[] = {0x00000000, 0x00000000, 0x00000000, 98 | 0x00000000, 0x00000000, 0x00000000, 99 | 0x00000000, 0x00000000, 0x00010001}; 100 | 101 | uint32_t M[] = {0x00000000, 0xf169d36e, 0xbe2ce61d, 102 | 0xc2e87809, 0x4fed15c3, 0x7c70eac5, 103 | 0xa123e643, 0x299b36d2, 0x788e583b }; 104 | 105 | uint32_t expected[] = {0x00000000, 0x7c5f0fee, 0x73028fc5, 106 | 0xc4fe57c4, 0x91a6f5be, 0x33a5c174, 107 | 0x2d2c2bcd, 0xda80e7d6, 0xfb4c889f}; 108 | 109 | uint32_t Z[] = {0x00000000, 0x00000000, 0x00000000, 110 | 0x00000000, 0x00000000, 0x00000000, 111 | 0x00000000, 0x00000000, 0x00000000}; 112 | 113 | mod_exp_array(9, X, E, M, Z); 114 | assertArrayEquals(9, expected, Z); 115 | } 116 | 117 | void rob_dec_1024(void) 118 | { 119 | uint32_t exponent[] = {0x00000000, 0x3ff26c9e, 0x32685b93, 0x66570228, 0xf0603c4e, 120 | 0x04a717c1, 0x8038b116, 0xeb48325e, 0xcada992a, 121 | 0x920bb241, 0x5aee4afe, 0xe2a37e87, 0xb35b9519, 122 | 0xb335775d, 0x989553e9, 0x1326f46e, 0x2cdf6b7b, 123 | 0x84aabfa9, 0xef24c600, 0xb56872ad, 0x5edb9041, 124 | 0xe8ecd7f8, 0x535133fb, 0xdefc92c7, 0x42384226, 125 | 0x7d40e5f5, 0xc91bd745, 0x9578e460, 0xfc858374, 126 | 0x3172bed3, 0x73b6957c, 0xc0d6a68e, 0x33156a61}; 127 | 128 | 129 | uint32_t modulus[] = {0x00000000, 0xd075ec0a, 0x95048ef8, 0xcaa69073, 0x8d9d58e9, 130 | 0x1764b437, 0x50b58cad, 0x8a6e3199, 0x135f80ee, 131 | 0x84eb2bde, 0x58d38ee3, 0x5825e91e, 0xafdeb1ba, 132 | 0xa15a160b, 0x0057c47c, 0xc7765e31, 0x868a3e15, 133 | 0x5ee57cef, 0xb008c4dd, 0x6a0a89ee, 0x98a4ee9c, 134 | 0x971a07de, 0x61e5b0d3, 0xcf70e1cd, 0xc6a0de5b, 135 | 0x451f2fb9, 0xdb995196, 0x9f2f884b, 0x4b09749a, 136 | 0xe6c4ddbe, 0x7ee61f79, 0x265c6adf, 0xb16b3015}; 137 | 138 | 139 | uint32_t message[] = {0x00000000, 0x0001ffff, 0xffffffff, 0xffffffff, 0xffffffff, 140 | 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 141 | 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 142 | 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 143 | 0xffffffff, 0xffffffff, 0xffffffff, 0x00303130, 144 | 0x0d060960, 0x86480165, 0x03040201, 0x05000420, 145 | 0x8e36fc9a, 0xa31724c3, 0x2416263c, 0x0366a175, 146 | 0xfabbb92b, 0x741ca649, 0x6107074d, 0x0343b597}; 147 | 148 | 149 | uint32_t expected[] = {0x00000000, 0x06339a64, 0x367db02a, 0xf41158cc, 0x95e76049, 150 | 0x4519c165, 0x111184be, 0xe41d8ee2, 0x2ae5f5d1, 151 | 0x1da7f962, 0xac93ac88, 0x915eee13, 0xa3350c22, 152 | 0xf0dfa62e, 0xfdfc2b62, 0x29f26e27, 0xbebdc84e, 153 | 0x4746df79, 0x7b387ad2, 0x13423c9f, 0x98e8a146, 154 | 0xff486b6c, 0x1a85414e, 0x73117121, 0xb700e547, 155 | 0xab4e07b2, 0x21b988b8, 0x24dd77c2, 0x046b0a20, 156 | 0xcddb986a, 0xac75c2f2, 0xb044ed59, 0xea565879}; 157 | 158 | 159 | uint32_t target[] = {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 160 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 161 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 162 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 163 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 164 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 165 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 166 | 0x00000000, 0x00000000, 0x00000000, 0x00000000}; 167 | 168 | printf("=== 1024 bit decipher/sign test from Robs RSA code. ===\n"); 169 | 170 | mod_exp_array(33, message, exponent, modulus, target); 171 | assertArrayEquals(33, expected, target); 172 | } 173 | 174 | 175 | void rob_enc_1024(void) 176 | { 177 | uint32_t exponent[] = {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 178 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 179 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 180 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 181 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 182 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 183 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 184 | 0x00000000, 0x00000000, 0x00000000, 0x00010001}; 185 | 186 | 187 | uint32_t modulus[] = {0x00000000, 0xd075ec0a, 0x95048ef8, 0xcaa69073, 0x8d9d58e9, 188 | 0x1764b437, 0x50b58cad, 0x8a6e3199, 0x135f80ee, 189 | 0x84eb2bde, 0x58d38ee3, 0x5825e91e, 0xafdeb1ba, 190 | 0xa15a160b, 0x0057c47c, 0xc7765e31, 0x868a3e15, 191 | 0x5ee57cef, 0xb008c4dd, 0x6a0a89ee, 0x98a4ee9c, 192 | 0x971a07de, 0x61e5b0d3, 0xcf70e1cd, 0xc6a0de5b, 193 | 0x451f2fb9, 0xdb995196, 0x9f2f884b, 0x4b09749a, 194 | 0xe6c4ddbe, 0x7ee61f79, 0x265c6adf, 0xb16b3015}; 195 | 196 | 197 | uint32_t message[] = {0x00000000, 0x0001ffff, 0xffffffff, 0xffffffff, 0xffffffff, 198 | 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 199 | 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 200 | 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 201 | 0xffffffff, 0xffffffff, 0xffffffff, 0x00303130, 202 | 0x0d060960, 0x86480165, 0x03040201, 0x05000420, 203 | 0x8e36fc9a, 0xa31724c3, 0x2416263c, 0x0366a175, 204 | 0xfabbb92b, 0x741ca649, 0x6107074d, 0x0343b597}; 205 | 206 | 207 | uint32_t expected[] = {0x00000000, 0x06339a64, 0x367db02a, 0xf41158cc, 0x95e76049, 208 | 0x4519c165, 0x111184be, 0xe41d8ee2, 0x2ae5f5d1, 209 | 0x1da7f962, 0xac93ac88, 0x915eee13, 0xa3350c22, 210 | 0xf0dfa62e, 0xfdfc2b62, 0x29f26e27, 0xbebdc84e, 211 | 0x4746df79, 0x7b387ad2, 0x13423c9f, 0x98e8a146, 212 | 0xff486b6c, 0x1a85414e, 0x73117121, 0xb700e547, 213 | 0xab4e07b2, 0x21b988b8, 0x24dd77c2, 0x046b0a20, 214 | 0xcddb986a, 0xac75c2f2, 0xb044ed59, 0xea565879}; 215 | 216 | 217 | uint32_t target[] = {0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 218 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 219 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 220 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 221 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 222 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 223 | 0x00000000, 0x00000000, 0x00000000, 0x00000000, 224 | 0x00000000, 0x00000000, 0x00000000, 0x00000000}; 225 | 226 | printf("=== 1024 bit encipher/verify test from Robs RSA code. ===\n"); 227 | 228 | mod_exp_array(33, expected, exponent, modulus, target); 229 | assertArrayEquals(33, message, target); 230 | } 231 | 232 | 233 | void simple_tests(void) { 234 | // simple_3_7_11(); 235 | // simple_251_251_257(); 236 | // bigger_test(); 237 | // small_e_256_mod(); 238 | // small_e_64_mod(); 239 | rob_enc_1024(); 240 | rob_dec_1024(); 241 | // small_e_256_mod2(); 242 | } 243 | 244 | //====================================================================== 245 | // EOF simple_tests.c 246 | //====================================================================== 247 | -------------------------------------------------------------------------------- /src/model/c/src/simple_tests.h: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // simple_tests.h 4 | // -------------- 5 | // Header fil to export the simple tests of the modexp C model. 6 | // 7 | // 8 | // Author: Joachim Strombergson 9 | // Copyright (c) 2015, Assured AB 10 | // All rights reserved. 11 | // 12 | // Redistribution and use in source and binary forms, with or 13 | // without modification, are permitted provided that the following 14 | // conditions are met: 15 | // 16 | // 1. Redistributions of source code must retain the above copyright 17 | // notice, this list of conditions and the following disclaimer. 18 | // 19 | // 2. Redistributions in binary form must reproduce the above copyright 20 | // notice, this list of conditions and the following disclaimer in 21 | // the documentation and/or other materials provided with the 22 | // distribution. 23 | // 24 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 33 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 35 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | //====================================================================== 37 | 38 | #ifndef SIMPLE_TESTS_H_ 39 | #define SIMPLE_TESTS_H_ 40 | 41 | void simple_tests(void); 42 | 43 | #endif // SIMPLE_TESTS_H_ 44 | 45 | //====================================================================== 46 | // EOF simple_tests.h 47 | //====================================================================== 48 | -------------------------------------------------------------------------------- /src/model/java/bin/NOTE.txt: -------------------------------------------------------------------------------- 1 | This is the destination directory for the java compiler. Must be present. 2 | -------------------------------------------------------------------------------- /src/model/java/lib/README.txt: -------------------------------------------------------------------------------- 1 | This library contains the junit.jar and hamcrest-core.jar from the JUnit 2 | project: 3 | 4 | http://junit.org/ 5 | For license, see: http://junit.org/license.html 6 | 7 | The Java model has been tested and is known to work with the following 8 | versions: 9 | 10 | - hamcrest-core-1.3.jar 11 | - junit-4.12.jar 12 | -------------------------------------------------------------------------------- /src/model/java/lib/hamcrest-core-1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/secworks/modexp/7a3211e0008c7b77c295640079bf014bc57ac6d6/src/model/java/lib/hamcrest-core-1.3.jar -------------------------------------------------------------------------------- /src/model/java/lib/junit-4.12.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/secworks/modexp/7a3211e0008c7b77c295640079bf014bc57ac6d6/src/model/java/lib/junit-4.12.jar -------------------------------------------------------------------------------- /src/model/java/src/rsa/BigNum.java: -------------------------------------------------------------------------------- 1 | package rsa; 2 | 3 | public class BigNum { 4 | static void debugArray(int length, int[] array) { 5 | System.out.println(" debug => "); 6 | for (int a : array) { 7 | System.out.printf("%8x ", a); 8 | } 9 | System.out.println(); 10 | } 11 | 12 | static void debugArray(String s, int length, int[] array) { 13 | System.out.printf(" debug %s => ", s); 14 | for (int a : array) { 15 | System.out.printf("%8x ", a); 16 | } 17 | System.out.println(); 18 | } 19 | 20 | static void copy_array(int length, int[] src, int[] dst) { 21 | for (int i = 0; i < length; i++) 22 | dst[i] = src[i]; 23 | } 24 | 25 | static void add_array(int length, int[] a, int b[], int result[]) { 26 | long carry = 0; 27 | for (int i = length - 1; i >= 0; i--) { 28 | long r = carry; 29 | int aa = a[i]; 30 | int bb = b[i]; 31 | r += aa & 0xFFFFFFFFL; 32 | r += bb & 0xFFFFFFFFL; 33 | carry = ((int) (r >> 32l)) & 1; 34 | result[i] = (int) r; 35 | } 36 | } 37 | 38 | static void sub_array(int length, int[] a, int[] b, int result[]) { 39 | long carry = 1; 40 | for (int wordIndex = length - 1; wordIndex >= 0; wordIndex--) { 41 | long r = carry; 42 | int aa = a[wordIndex]; 43 | int bb = ~b[wordIndex]; 44 | r += aa & 0xFFFFFFFFL; 45 | r += bb & 0xFFFFFFFFL; 46 | carry = (r >> 32l) & 1; 47 | result[wordIndex] = (int) r; 48 | } 49 | } 50 | 51 | static void shift_right_1_array(int length, int[] a, int result[]) { 52 | int prev = 0; // MSB will be zero extended 53 | for (int wordIndex = 0; wordIndex < length; wordIndex++) { 54 | int aa = a[wordIndex]; 55 | result[wordIndex] = (aa >>> 1) | (prev << 31); 56 | prev = aa & 1; // Lower word will be extended with LSB of this word 57 | } 58 | } 59 | 60 | static void shift_left_1_array(int length, int[] a, int result[]) { 61 | int prev = 0; // LSB will be zero extended 62 | for (int wordIndex = length - 1; wordIndex >= 0; wordIndex--) { 63 | int aa = a[wordIndex]; 64 | result[wordIndex] = (aa << 1) | prev; 65 | prev = aa >>> 31; // Lower word will be extended with LSB of this 66 | // word 67 | } 68 | } 69 | 70 | static void zero_array(int length, int[] a) { 71 | for (int i = 0; i < length; i++) 72 | a[i] = 0; 73 | } 74 | 75 | static boolean greater_than_array(int length, int[] a, int[] b) { 76 | for (int i = 0; i < length; i++) { 77 | long aa = a[i] & 0xFFFF_FFFFL; 78 | long bb = b[i] & 0xFFFF_FFFFL; 79 | if (aa > bb) 80 | return true; 81 | if (aa < bb) 82 | return false; 83 | 84 | } 85 | return false; 86 | } 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/model/java/src/rsa/BigNumTest.java: -------------------------------------------------------------------------------- 1 | package rsa; 2 | 3 | import static org.junit.Assert.*; 4 | 5 | import org.junit.Test; 6 | 7 | public class BigNumTest { 8 | 9 | @Test 10 | public void testShiftRight() { 11 | int[] a = { 0x01234567, 0x89abcdef }; 12 | BigNum.shift_right_1_array(2, a, a); 13 | BigNum.shift_right_1_array(2, a, a); 14 | BigNum.shift_right_1_array(2, a, a); 15 | BigNum.shift_right_1_array(2, a, a); 16 | int[] expected = { 0x00123456, 0x789abcde }; 17 | assertArrayEquals(expected, a); 18 | } 19 | 20 | @Test 21 | public void testAdd() { 22 | int[] a = { 0x01234567, 0x89abcdef }; 23 | int[] b = { 0x12000002, 0x77000001 }; 24 | int[] c = new int[2]; 25 | BigNum.add_array(2, a, b, c); 26 | int[] expected = { 0x1323456a, 0x00abcdf0 }; 27 | System.out.printf("%x %x %x\n", c[0], c[1], 0x0123456789abcdefL + 0x1200000277000001L); 28 | assertArrayEquals(expected, c); 29 | } 30 | 31 | @Test 32 | public void testSub() { 33 | int[] a = { 0x01234567, 0x89abcdef }; 34 | int[] b = { 0x00200000, 0x8a001001 }; 35 | int[] c = new int[2]; 36 | BigNum.sub_array(2, a, b, c); 37 | int[] expected = { 0x1034566, 0xffabbdee }; 38 | System.out.printf("%8x %8x %x\n", c[0], c[1], 0x0123456789abcdefL - 0x002000008a001001L); 39 | assertArrayEquals(expected, c); 40 | } 41 | 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/model/java/src/rsa/Montgomery.java: -------------------------------------------------------------------------------- 1 | package rsa; 2 | 3 | import org.junit.Test; 4 | 5 | public class Montgomery { 6 | static final int TEST_CONSTANT_PRIME_15_1 = 65537; 7 | static final int TEST_CONSTANT_PRIME_31_1 = 2147483647; // eighth Mersenne prime 8 | 9 | 10 | 11 | int mont_prod(int A, int B, int M) { 12 | int s = 0; 13 | for(int i = 0; i < 32; i++) { 14 | int b = (B >>> i) & 1; 15 | int q = (s - b * A) & 1; 16 | s = (s + q*M + b*A) >>> 1; 17 | } 18 | return s; 19 | } 20 | 21 | int m_residue(int A, int M) { 22 | long x = A & 0xFFFFFFFFFL; 23 | long m = M & 0xFFFFFFFFFL; 24 | x <<= 32; 25 | x %= m; 26 | return (int) x; 27 | } 28 | 29 | boolean test_montgomery_a_b_m(int A, int B, int M) { 30 | //int prodMod = (A * B) % M; 31 | int prodMod = A % M; 32 | prodMod *= B % M; 33 | prodMod %= M; 34 | int Ar = m_residue(A, M); 35 | int Br = m_residue(B, M); 36 | int monProdMod = mont_prod(Ar, Br, M); 37 | int monProdMod_ = mont_prod(1, monProdMod, M); 38 | boolean success = prodMod == monProdMod_; 39 | System.out.printf("%c A=%3x B=%3x M=%3x A*B=%3x Ar=%3x Br=%3x Ar*Br=%3x A*B=%3x\n", 40 | success ? '*' : ' ', A, B, M, prodMod, Ar, Br, 41 | monProdMod, monProdMod_); 42 | return success; 43 | } 44 | 45 | @Test 46 | public void test_montgomery() { 47 | test_montgomery_a_b_m(11, 17, 19); 48 | test_montgomery_a_b_m(11, 19, 17); 49 | test_montgomery_a_b_m(17, 11, 19); 50 | test_montgomery_a_b_m(17, 19, 11); 51 | test_montgomery_a_b_m(19, 11, 17); 52 | test_montgomery_a_b_m(19, 17, 11); 53 | 54 | test_montgomery_a_b_m(TEST_CONSTANT_PRIME_15_1, 17, 19); 55 | test_montgomery_a_b_m(TEST_CONSTANT_PRIME_15_1, 19, 17); 56 | test_montgomery_a_b_m(17, TEST_CONSTANT_PRIME_15_1, 19); 57 | test_montgomery_a_b_m(17, 19, TEST_CONSTANT_PRIME_15_1); 58 | test_montgomery_a_b_m(19, TEST_CONSTANT_PRIME_15_1, 17); 59 | test_montgomery_a_b_m(19, 17, TEST_CONSTANT_PRIME_15_1); 60 | 61 | test_montgomery_a_b_m(TEST_CONSTANT_PRIME_15_1, 17, 62 | TEST_CONSTANT_PRIME_31_1); 63 | test_montgomery_a_b_m(TEST_CONSTANT_PRIME_15_1, TEST_CONSTANT_PRIME_31_1, 64 | 17); 65 | test_montgomery_a_b_m(17, TEST_CONSTANT_PRIME_15_1, 66 | TEST_CONSTANT_PRIME_31_1); 67 | test_montgomery_a_b_m(17, TEST_CONSTANT_PRIME_31_1, 68 | TEST_CONSTANT_PRIME_15_1); 69 | test_montgomery_a_b_m(TEST_CONSTANT_PRIME_31_1, TEST_CONSTANT_PRIME_15_1, 70 | 17); 71 | test_montgomery_a_b_m(TEST_CONSTANT_PRIME_31_1, 17, 72 | TEST_CONSTANT_PRIME_15_1); 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /src/model/java/src/rsa/MontgomeryArray.java: -------------------------------------------------------------------------------- 1 | package rsa; 2 | import static rsa.BigNum.*; 3 | 4 | import java.util.Arrays; 5 | 6 | public class MontgomeryArray { 7 | static void mont_prod_array(int length, int[] A, int B[], int M[], int[] s) { 8 | if (A == s || B == s) 9 | throw new IllegalArgumentException(); 10 | zero_array(length, s); 11 | int[] qSub = new int[length]; 12 | int[] sMA = new int[length]; 13 | int[] sM = new int[length]; 14 | int[] sA = new int[length]; 15 | for (int wordIndex = length - 1; wordIndex >= 0; wordIndex--) { 16 | for (int i = 0; i < 32; i++) { 17 | sub_array(length, s, A, qSub); // int q = (s - b * A) & 1; 18 | add_array(length, s, M, sM); 19 | add_array(length, s, A, sA); 20 | add_array(length, sM, A, sMA); 21 | 22 | int b = (B[wordIndex] >>> i) & 1; 23 | int[] qSelect = (b == 1) ? qSub : s; 24 | int q = qSelect[length - 1] & 1; // int q = (s - b * A) & 1; 25 | 26 | // s = (s + q*M + b*A) >>> 1; 27 | if (q == 1 && b == 1) { 28 | copy_array(length, sMA, s); 29 | } else if (q == 1) { 30 | copy_array(length, sM, s); 31 | } else if (b == 1) { 32 | copy_array(length, sA, s); 33 | } 34 | shift_right_1_array(length, s, s); 35 | } 36 | } 37 | } 38 | 39 | 40 | public static void m_residue(int length, int[] a, int[] modulus, 41 | int[] residue) { 42 | modulus_array(length, a, modulus, residue); 43 | for (int i = 0; i < 32; i++) { 44 | shift_left_1_array(length, residue, residue); 45 | modulus_array(length, residue, modulus, residue); 46 | } 47 | } 48 | 49 | static void modulus_array(int length, int[] a, int[] modulus, int[] reminder) { 50 | // int[] tmp = new int[length]; 51 | // copy_array(length, a, reminder); 52 | // copy_array(length, a, tmp); 53 | // 54 | // while((tmp[0] & 0x8000_0000) == 0) { 55 | // System.out.printf("tmp: %s\n", Arrays.toString(tmp)); 56 | // System.out.printf("reminder: %s\n", Arrays.toString(reminder)); 57 | // copy_array(length, tmp, reminder); 58 | // sub_array(length, tmp, modulus, tmp); 59 | // } 60 | 61 | int[] tmp = new int[length]; 62 | int[] tmp2 = new int[length]; 63 | copy_array(length, a, reminder); 64 | 65 | while (!greater_than_array(length, modulus, reminder)) { 66 | sub_array(length, reminder, tmp2, reminder); 67 | copy_array(length, modulus, tmp); 68 | zero_array(length, tmp2); 69 | 70 | while (!greater_than_array(length, tmp, reminder)) { 71 | copy_array(length, tmp, tmp2); 72 | shift_left_1_array(length, tmp, tmp); 73 | } 74 | 75 | sub_array(length, reminder, tmp2, reminder); 76 | 77 | } 78 | } 79 | 80 | public static void m_residue_2_2N_array(int length, int N, int[] M, 81 | int[] temp, int[] Nr) { 82 | zero_array(length, Nr); 83 | Nr[length - 1] = 1; // Nr = 1 == 2**(2N-2N) 84 | for (int i = 0; i < 2 * N ; i++) { 85 | shift_left_1_array(length, Nr, Nr); 86 | modulus_array(length, Nr, M, Nr); 87 | } 88 | } 89 | 90 | static int findN(int length, int[] E) { 91 | int n = -1; 92 | for (int i = 0; i < 32 * length; i++) { 93 | int ei_ = E[length - 1 - (i / 32)]; 94 | int ei = (ei_ >> (i % 32)) & 1; 95 | if (ei == 1) { 96 | n = i; 97 | } 98 | } 99 | return n + 1; 100 | } 101 | 102 | public static void mont_exp_array(int length, int[] X, int[] E, int[] M, 103 | int[] Nr, int[] P, int[] ONE, int[] temp, int[] Z) { 104 | //debugArray("X ", length, X); 105 | //debugArray("E ", length, E); 106 | //debugArray("M ", length, M); 107 | 108 | int n = 32 * length; 109 | //System.out.println("N: " + n); 110 | 111 | PerformanceClock.updateThen(); 112 | 113 | // 1. Nr := 2 ** 2N mod M 114 | m_residue_2_2N_array(length, n, M, temp, Nr); 115 | //debugArray("Nr", length, Nr); 116 | 117 | PerformanceClock.debug("m_residue_2_2N_array"); 118 | 119 | // 2. Z0 := MontProd( 1, Nr, M ) 120 | zero_array(length, ONE); 121 | ONE[length - 1] = 1; 122 | mont_prod_array(length, ONE, Nr, M, Z); 123 | //debugArray("Z0", length, Z); 124 | 125 | PerformanceClock.debug("1*Nr mod M"); 126 | 127 | // 3. P0 := MontProd( X, Nr, M ); 128 | mont_prod_array(length, X, Nr, M, P); 129 | //debugArray("P0", length, P); 130 | 131 | PerformanceClock.debug("X*Nr mod M"); 132 | 133 | // 4. for i = 0 to n-1 loop 134 | n = findN(length, E); //loop optimization 135 | for (int i = 0; i < n; i++) { 136 | int ei_ = E[length - 1 - (i / 32)]; 137 | int ei = (ei_ >> (i % 32)) & 1; 138 | // 6. if (ei = 1) then Zi+1 := MontProd ( Zi, Pi, M) else Zi+1 := Zi 139 | if (ei == 1) { 140 | mont_prod_array(length, Z, P, M, temp); 141 | copy_array(length, temp, Z); 142 | //debugArray("Z ", length, Z); 143 | } 144 | // 5. Pi+1 := MontProd( Pi, Pi, M ); 145 | mont_prod_array(length, P, P, M, temp); 146 | copy_array(length, temp, P); 147 | //debugArray("P ", length, P); 148 | 149 | } // 7. end for 150 | PerformanceClock.debug("loop"); 151 | 152 | // 8. Zn := MontProd( 1, Zn, M ); 153 | mont_prod_array(length, ONE, Z, M, temp); 154 | copy_array(length, temp, Z); 155 | //debugArray("Z ", length, Z); 156 | // 9. RETURN Zn 157 | PerformanceClock.debug("1*Z mod M"); 158 | } 159 | 160 | } 161 | -------------------------------------------------------------------------------- /src/model/java/src/rsa/PerformanceClock.java: -------------------------------------------------------------------------------- 1 | package rsa; 2 | 3 | public class PerformanceClock { 4 | static long then; 5 | static void updateThen() { 6 | then = System.currentTimeMillis(); 7 | } 8 | static void debug(String s) { 9 | long time = System.currentTimeMillis() - then; 10 | System.out.printf(" %5d ms %s\n", time, s); 11 | updateThen(); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/model/python/modexp.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | #======================================================================= 4 | # 5 | # modexp.py 6 | # --------- 7 | # A python model for doing modular exponention. 8 | # 9 | # 10 | # Author: Joachim Strömbergson 11 | # Copyright (c) 2014, Secworks Sweden AB 12 | # 13 | # Redistribution and use in source and binary forms, with or 14 | # without modification, are permitted provided that the following 15 | # conditions are met: 16 | # 17 | # 1. Redistributions of source code must retain the above copyright 18 | # notice, this list of conditions and the following disclaimer. 19 | # 20 | # 2. Redistributions in binary form must reproduce the above copyright 21 | # notice, this list of conditions and the following disclaimer in 22 | # the documentation and/or other materials provided with the 23 | # distribution. 24 | # 25 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 28 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 29 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 30 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 31 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 34 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 36 | # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | # 38 | #======================================================================= 39 | 40 | #------------------------------------------------------------------- 41 | # Python module imports. 42 | #------------------------------------------------------------------- 43 | import sys 44 | 45 | 46 | #------------------------------------------------------------------- 47 | # Defines. 48 | #------------------------------------------------------------------- 49 | VERBOSE = False 50 | 51 | 52 | #------------------------------------------------------------------- 53 | # iter_mult() 54 | # 55 | # Iterative multiplier (i*j) with operands that are bitlen 56 | # number of bits. 57 | #------------------------------------------------------------------- 58 | def iter_mult(i, j, bitlen): 59 | print("Mult of 0x%08x and 0x%08x of max 0x%08x bits" % 60 | (i, j, bitlen)) 61 | 62 | r = 0 63 | max = 2**bitlen - 1 64 | 65 | for bit in range(bitlen): 66 | mask = ((j & (1 << bit))) 67 | r = (r + (i * mask)) & max 68 | print("bit: 0x%08x, mask = 0x%01x, r = 0x%08x" % 69 | (bit, mask, r)) 70 | return r 71 | 72 | 73 | #------------------------------------------------------------------- 74 | # iter_exp() 75 | # 76 | # Iterative exponentiator (i ** j) with operands that are 77 | # bitlen number of bits. 78 | #------------------------------------------------------------------- 79 | def iter_exp(i, j, bitlen): 80 | print("Exp of 0x%08x and 0x%08x of max 0x%08x bits" % 81 | (i, j, bitlen)) 82 | 83 | n = i 84 | for bit in range(j): 85 | n = iter_mult(n, n, bitlen) 86 | return n 87 | 88 | 89 | #------------------------------------------------------------------- 90 | # gen_keypair() 91 | # 92 | # Generate a keypair (and exponent) with n bits in length. 93 | #------------------------------------------------------------------- 94 | def gen_keypair(bitlen): 95 | print("Generating keys with %d bits" % (bitlen)) 96 | print("") 97 | 98 | e = 3 99 | pub = 2**bitlen - 1 100 | priv = pub - 2 101 | 102 | return (pub, priv, e) 103 | 104 | 105 | #------------------------------------------------------------------- 106 | # keytest() 107 | #------------------------------------------------------------------- 108 | def keytest(): 109 | print("key encryption and decryption") 110 | print("-----------------------------") 111 | 112 | p = 11 113 | q = 13 114 | n = p * q 115 | tiotent = (p - 1) * (q - 1) 116 | 117 | print("p = %d, q = %d, n = %d, tiotent = %d" % (p, q, n, tiotent)) 118 | 119 | e = 7 120 | d = 103 121 | 122 | print("e = %d, d = %d" % (e, d)) 123 | 124 | print("Public key: e, n = %d, %d" % (e, n)) 125 | print("private key: d = %d" % (d)) 126 | 127 | m = 9 128 | cm = modexp(m, e, n) 129 | m2 = modexp(cm, d, n) 130 | print("Encryption of message m = %d -> cm = %d" % (m, cm)) 131 | print("Decryption of message cm = %d -> m = %d" % (cm, m2)) 132 | 133 | 134 | #------------------------------------------------------------------- 135 | # modtest() 136 | #------------------------------------------------------------------- 137 | def modtest(): 138 | print("modular exponentition") 139 | print("---------------------") 140 | 141 | M = 12345 142 | e = 3 143 | N = 12347 144 | 145 | print("M = %d, e = %d, N = %d" % (M, e, N)) 146 | print(modexp(M, e, N)) 147 | print("") 148 | 149 | M = 2**8192 - 37 150 | e = 3 151 | N = 2**8192 - 1 152 | 153 | print("M = %d, e = %d, N = %d" % (M, e, N)) 154 | print(modexp(M, e, N)) 155 | print("") 156 | 157 | 158 | #------------------------------------------------------------------- 159 | # modexp() 160 | # 161 | # Perform generic modular exponention of the given message M 162 | # using the exponent e and modulus N. 163 | #------------------------------------------------------------------- 164 | def modexp(M, e, N): 165 | return (M ** e) % N 166 | 167 | 168 | #------------------------------------------------------------------- 169 | # main() 170 | # 171 | # Parse any arguments and run the tests. 172 | #------------------------------------------------------------------- 173 | def main(): 174 | # my_keypair = gen_keypair(12) 175 | # print(my_keypair) 176 | # modtest() 177 | # keytest() 178 | 179 | # test of iterative multiply. 180 | print(iter_mult(2, 3, 4)) 181 | print(iter_mult(2, 3, 5)) 182 | print(iter_mult(2543, 1201, 12)) 183 | print(iter_mult(2543, 1201, 16)) 184 | print(iter_mult(2543, 1201, 23)) 185 | 186 | # test of iterative exponentiation. 187 | print(iter_exp(2, 3, 12)) 188 | print(iter_exp(8, 8, 4)) 189 | 190 | 191 | #------------------------------------------------------------------- 192 | # __name__ 193 | # Python thingy which allows the file to be run standalone as 194 | # well as parsed from within a Python interpreter. 195 | #------------------------------------------------------------------- 196 | if __name__=="__main__": 197 | # Run the main function. 198 | sys.exit(main()) 199 | 200 | 201 | #======================================================================= 202 | # EOF modexp.py 203 | #======================================================================= 204 | -------------------------------------------------------------------------------- /src/rtl/adder32.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // adder32.v 4 | // --------- 5 | // 32bit adder with carry in / carry out 6 | // 7 | // 8 | // Author: Peter Magnusson 9 | // Copyright (c) 2015, NORDUnet A/S All rights reserved. 10 | // 11 | // Redistribution and use in source and binary forms, with or without 12 | // modification, are permitted provided that the following conditions are 13 | // met: 14 | // - Redistributions of source code must retain the above copyright notice, 15 | // this list of conditions and the following disclaimer. 16 | // 17 | // - Redistributions in binary form must reproduce the above copyright 18 | // notice, this list of conditions and the following disclaimer in the 19 | // documentation and/or other materials provided with the distribution. 20 | // 21 | // - Neither the name of the NORDUnet nor the names of its contributors may 22 | // be used to endorse or promote products derived from this software 23 | // without specific prior written permission. 24 | // 25 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 26 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 28 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 31 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 32 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | // 37 | //====================================================================== 38 | 39 | 40 | module adder32( 41 | input [31 : 0] a, 42 | input [31 : 0] b, 43 | input carry_in, 44 | output wire [31 : 0] sum, 45 | output wire carry_out); 46 | 47 | reg [32 : 0] adder_result; 48 | 49 | assign sum = adder_result[31:0]; 50 | assign carry_out = adder_result[32]; 51 | 52 | always @(a, b, carry_in) 53 | adder_result = {1'b0, a} + {1'b0, b} + {32'b0, carry_in}; 54 | endmodule 55 | -------------------------------------------------------------------------------- /src/rtl/blockmem1r1w.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // blockmem1rw1.v 4 | // -------------- 5 | // Synchronous block memory with one read and one write port. 6 | // The data size is the same for both read and write operations. 7 | // 8 | // The memory is used in the modexp core. 9 | // 10 | // 11 | // Author: Joachim Strombergson 12 | // Copyright (c) 2015, NORDUnet A/S All rights reserved. 13 | // 14 | // Redistribution and use in source and binary forms, with or without 15 | // modification, are permitted provided that the following conditions are 16 | // met: 17 | // - Redistributions of source code must retain the above copyright notice, 18 | // this list of conditions and the following disclaimer. 19 | // 20 | // - Redistributions in binary form must reproduce the above copyright 21 | // notice, this list of conditions and the following disclaimer in the 22 | // documentation and/or other materials provided with the distribution. 23 | // 24 | // - Neither the name of the NORDUnet nor the names of its contributors may 25 | // be used to endorse or promote products derived from this software 26 | // without specific prior written permission. 27 | // 28 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 29 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 31 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 34 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 35 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 36 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | // 40 | //====================================================================== 41 | 42 | module blockmem1r1w( 43 | input wire clk, 44 | 45 | input wire [07 : 0] read_addr, 46 | output wire [31 : 0] read_data, 47 | 48 | input wire wr, 49 | input wire [07 : 0] write_addr, 50 | input wire [31 : 0] write_data 51 | ); 52 | 53 | reg [31 : 0] mem [0 : 255]; 54 | reg [31 : 0] tmp_read_data; 55 | 56 | assign read_data = tmp_read_data; 57 | 58 | always @ (posedge clk) 59 | begin : reg_mem 60 | if (wr) 61 | mem[write_addr] <= write_data; 62 | 63 | tmp_read_data <= mem[read_addr]; 64 | end 65 | 66 | endmodule // blockmem1r1w 67 | 68 | //====================================================================== 69 | // EOF blockmem1r1w.v 70 | //====================================================================== 71 | -------------------------------------------------------------------------------- /src/rtl/blockmem2r1w.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // blockmem2r1w.v 4 | // -------------- 5 | // Synchronous block memory with two read ports and one write port. 6 | // The data size is the same for both read and write operations. 7 | // 8 | // The memory is used in the modexp core. 9 | // 10 | // 11 | // Author: Joachim Strombergson 12 | // Copyright (c) 2015, NORDUnet A/S All rights reserved. 13 | // 14 | // Redistribution and use in source and binary forms, with or without 15 | // modification, are permitted provided that the following conditions are 16 | // met: 17 | // - Redistributions of source code must retain the above copyright notice, 18 | // this list of conditions and the following disclaimer. 19 | // 20 | // - Redistributions in binary form must reproduce the above copyright 21 | // notice, this list of conditions and the following disclaimer in the 22 | // documentation and/or other materials provided with the distribution. 23 | // 24 | // - Neither the name of the NORDUnet nor the names of its contributors may 25 | // be used to endorse or promote products derived from this software 26 | // without specific prior written permission. 27 | // 28 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 29 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 31 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 34 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 35 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 36 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | // 40 | //====================================================================== 41 | 42 | module blockmem2r1w( 43 | input wire clk, 44 | 45 | input wire [07 : 0] read_addr0, 46 | output wire [31 : 0] read_data0, 47 | 48 | input wire [07 : 0] read_addr1, 49 | output wire [31 : 0] read_data1, 50 | 51 | input wire wr, 52 | input wire [07 : 0] write_addr, 53 | input wire [31 : 0] write_data 54 | ); 55 | 56 | reg [31 : 0] mem [0 : 255]; 57 | reg [31 : 0] tmp_read_data0; 58 | reg [31 : 0] tmp_read_data1; 59 | 60 | assign read_data0 = tmp_read_data0; 61 | assign read_data1 = tmp_read_data1; 62 | 63 | always @ (posedge clk) 64 | begin : reg_mem 65 | if (wr) 66 | mem[write_addr] <= write_data; 67 | 68 | tmp_read_data0 <= mem[read_addr0]; 69 | tmp_read_data1 <= mem[read_addr1]; 70 | end 71 | 72 | endmodule // blockmem2r1w 73 | 74 | //====================================================================== 75 | // EOF blockmem2r1w.v 76 | //====================================================================== 77 | -------------------------------------------------------------------------------- /src/rtl/blockmem2r1wptr.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // blockmem2r1wptr.v 4 | // ----------------- 5 | // Synchronous block memory with two read ports and one write port. 6 | // For port 1 the address is implicit and instead given by the 7 | // internal pointer. The pointer is automatically increased 8 | // when the cs signal is set. The pointer is reset to zero when 9 | // the rst signal is asserted. 10 | // 11 | // The memory is used in the modexp core. 12 | // 13 | // 14 | // Author: Joachim Strombergson 15 | // Copyright (c) 2015, NORDUnet A/S All rights reserved. 16 | // 17 | // Redistribution and use in source and binary forms, with or without 18 | // modification, are permitted provided that the following conditions are 19 | // met: 20 | // - Redistributions of source code must retain the above copyright notice, 21 | // this list of conditions and the following disclaimer. 22 | // 23 | // - Redistributions in binary form must reproduce the above copyright 24 | // notice, this list of conditions and the following disclaimer in the 25 | // documentation and/or other materials provided with the distribution. 26 | // 27 | // - Neither the name of the NORDUnet nor the names of its contributors may 28 | // be used to endorse or promote products derived from this software 29 | // without specific prior written permission. 30 | // 31 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 32 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 33 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 34 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 36 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 37 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 38 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 39 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 40 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 41 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 | // 43 | //====================================================================== 44 | 45 | module blockmem2r1wptr( 46 | input wire clk, 47 | input wire reset_n, 48 | 49 | input wire [07 : 0] read_addr0, 50 | output wire [31 : 0] read_data0, 51 | 52 | output wire [31 : 0] read_data1, 53 | 54 | input wire rst, 55 | input wire cs, 56 | input wire wr, 57 | input wire [31 : 0] write_data 58 | ); 59 | 60 | 61 | //---------------------------------------------------------------- 62 | // Memories and regs including update variables and write enable. 63 | //---------------------------------------------------------------- 64 | reg [31 : 0] mem [0 : 255]; 65 | reg [31 : 0] tmp_read_data0; 66 | reg [31 : 0] tmp_read_data1; 67 | 68 | reg [7 : 0] ptr_reg; 69 | reg [7 : 0] ptr_new; 70 | reg ptr_we; 71 | 72 | 73 | //---------------------------------------------------------------- 74 | // Concurrent connectivity for ports etc. 75 | //---------------------------------------------------------------- 76 | assign read_data0 = tmp_read_data0; 77 | assign read_data1 = tmp_read_data1; 78 | 79 | 80 | //---------------------------------------------------------------- 81 | // mem_update 82 | // 83 | // Clocked update of memory This should cause 84 | // the memory to be implemented as a block memory. 85 | //---------------------------------------------------------------- 86 | always @ (posedge clk) 87 | begin : mem_update 88 | if (wr) 89 | mem[ptr_reg] <= write_data; 90 | 91 | tmp_read_data0 <= mem[read_addr0]; 92 | tmp_read_data1 <= mem[ptr_reg]; 93 | end 94 | 95 | 96 | //---------------------------------------------------------------- 97 | // reg_update 98 | //---------------------------------------------------------------- 99 | always @ (posedge clk or negedge reset_n) 100 | begin : reg_mem_update 101 | if (!reset_n) 102 | ptr_reg <= 8'h00; 103 | 104 | else 105 | if (ptr_we) 106 | ptr_reg <= ptr_new; 107 | end 108 | 109 | 110 | //---------------------------------------------------------------- 111 | // ptr_logic 112 | //---------------------------------------------------------------- 113 | always @* 114 | begin : ptr_logic 115 | ptr_new = 8'h00; 116 | ptr_we = 1'b0; 117 | 118 | if (rst) 119 | begin 120 | ptr_new = 8'h00; 121 | ptr_we = 1'b1; 122 | end 123 | 124 | if (cs) 125 | begin 126 | ptr_new = ptr_reg + 1'b1; 127 | ptr_we = 1'b1; 128 | end 129 | end 130 | 131 | endmodule // blockmem2r1wptr 132 | 133 | //====================================================================== 134 | // EOF blockmem2r1wptr.v 135 | //====================================================================== 136 | -------------------------------------------------------------------------------- /src/rtl/blockmem2rptr1w.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // blockmem2r1wptr.v 4 | // ----------------- 5 | // Synchronous block memory with two read ports and one write port. 6 | // For port 1 the address is implicit and instead given by the 7 | // internal pointer. But write address is explicitly given. 8 | // 9 | // The memory is used in the modexp core. 10 | // 11 | // 12 | // Author: Joachim Strombergson 13 | // Copyright (c) 2015, NORDUnet A/S All rights reserved. 14 | // 15 | // Redistribution and use in source and binary forms, with or without 16 | // modification, are permitted provided that the following conditions are 17 | // met: 18 | // - Redistributions of source code must retain the above copyright notice, 19 | // this list of conditions and the following disclaimer. 20 | // 21 | // - Redistributions in binary form must reproduce the above copyright 22 | // notice, this list of conditions and the following disclaimer in the 23 | // documentation and/or other materials provided with the distribution. 24 | // 25 | // - Neither the name of the NORDUnet nor the names of its contributors may 26 | // be used to endorse or promote products derived from this software 27 | // without specific prior written permission. 28 | // 29 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 30 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 31 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 32 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 35 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 36 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 37 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 38 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 39 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | // 41 | //====================================================================== 42 | 43 | module blockmem2rptr1w( 44 | input wire clk, 45 | input wire reset_n, 46 | 47 | input wire [07 : 0] read_addr0, 48 | output wire [31 : 0] read_data0, 49 | 50 | output wire [31 : 0] read_data1, 51 | 52 | input wire rst, 53 | input wire cs, 54 | input wire wr, 55 | input wire [07 : 0] write_addr, 56 | input wire [31 : 0] write_data 57 | ); 58 | 59 | 60 | //---------------------------------------------------------------- 61 | // Memories and regs including update variables and write enable. 62 | //---------------------------------------------------------------- 63 | reg [31 : 0] mem [0 : 255]; 64 | reg [31 : 0] tmp_read_data0; 65 | reg [31 : 0] tmp_read_data1; 66 | 67 | reg [7 : 0] ptr_reg; 68 | reg [7 : 0] ptr_new; 69 | reg ptr_we; 70 | 71 | 72 | //---------------------------------------------------------------- 73 | // Concurrent connectivity for ports etc. 74 | //---------------------------------------------------------------- 75 | assign read_data0 = tmp_read_data0; 76 | assign read_data1 = tmp_read_data1; 77 | 78 | 79 | //---------------------------------------------------------------- 80 | // mem_update 81 | // 82 | // Clocked update of memory This should cause 83 | // the memory to be implemented as a block memory. 84 | //---------------------------------------------------------------- 85 | always @ (posedge clk) 86 | begin : mem_update 87 | if (wr) 88 | mem[write_addr] <= write_data; 89 | 90 | tmp_read_data0 <= mem[read_addr0]; 91 | tmp_read_data1 <= mem[ptr_reg]; 92 | end 93 | 94 | 95 | //---------------------------------------------------------------- 96 | // reg_update 97 | //---------------------------------------------------------------- 98 | always @ (posedge clk or negedge reset_n) 99 | begin : reg_mem_update 100 | if (!reset_n) 101 | ptr_reg <= 8'h00; 102 | 103 | else 104 | if (ptr_we) 105 | ptr_reg <= ptr_new; 106 | end 107 | 108 | 109 | //---------------------------------------------------------------- 110 | // ptr_logic 111 | //---------------------------------------------------------------- 112 | always @* 113 | begin : ptr_logic 114 | ptr_new = 8'h00; 115 | ptr_we = 1'b0; 116 | 117 | if (rst) 118 | begin 119 | ptr_new = 8'h00; 120 | ptr_we = 1'b1; 121 | end 122 | 123 | if (cs) 124 | begin 125 | ptr_new = ptr_reg + 1'b1; 126 | ptr_we = 1'b1; 127 | end 128 | end 129 | 130 | endmodule // blockmem2r1wptr 131 | 132 | //====================================================================== 133 | // EOF blockmem2r1wptr.v 134 | //====================================================================== 135 | -------------------------------------------------------------------------------- /src/rtl/blockmem_rw32_r128.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // blockmem_rw32_r128.v 4 | // -------------------- 5 | // Test implementation of a block memory that has different data 6 | // widths on external (api) and internal ports. 7 | // Author: Joachim Strombergson, Peter Magnusson 8 | // Copyright (c) 2015, Assured AB 9 | // All rights reserved. 10 | // 11 | // Redistribution and use in source and binary forms, with or 12 | // without modification, are permitted provided that the following 13 | // conditions are met: 14 | // 15 | // 1. Redistributions of source code must retain the above copyright 16 | // notice, this list of conditions and the following disclaimer. 17 | // 18 | // 2. Redistributions in binary form must reproduce the above copyright 19 | // notice, this list of conditions and the following disclaimer in 20 | // the documentation and/or other materials provided with the 21 | // distribution. 22 | // 23 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 34 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | // 36 | //====================================================================== 37 | 38 | module blockmem_rw32_r128( 39 | input wire clk, 40 | 41 | input wire api_we, 42 | input wire [07 : 0] api_addr, 43 | input wire [31 : 0] api_wr_data, 44 | output wire [31 : 0] api_rd_data, 45 | 46 | input wire [05 : 0] internal_addr, 47 | output wire [127 : 0] internal_rd_data 48 | ); 49 | 50 | 51 | //---------------------------------------------------------------- 52 | // Regs and memories. 53 | //---------------------------------------------------------------- 54 | reg [31 : 0] mem0 [0 : 63]; 55 | reg [31 : 0] mem1 [0 : 63]; 56 | reg [31 : 0] mem2 [0 : 63]; 57 | reg [31 : 0] mem3 [0 : 63]; 58 | 59 | 60 | //---------------------------------------------------------------- 61 | // Wires. 62 | //---------------------------------------------------------------- 63 | reg [31 : 0] muxed_api_rd_data; 64 | reg [31 : 0] mem0_api_rd_data; 65 | reg [31 : 0] mem1_api_rd_data; 66 | reg [31 : 0] mem2_api_rd_data; 67 | reg [31 : 0] mem3_api_rd_data; 68 | 69 | reg [31 : 0] mem0_int_rd_data; 70 | reg [31 : 0] mem1_int_rd_data; 71 | reg [31 : 0] mem2_int_rd_data; 72 | reg [31 : 0] mem3_int_rd_data; 73 | 74 | reg mem0_we; 75 | reg mem1_we; 76 | reg mem2_we; 77 | reg mem3_we; 78 | 79 | 80 | //---------------------------------------------------------------- 81 | // Assignmets. 82 | //---------------------------------------------------------------- 83 | assign api_rd_data = muxed_api_rd_data; 84 | 85 | assign internal_rd_data = {mem3_int_rd_data, mem2_int_rd_data, 86 | mem1_int_rd_data, mem0_int_rd_data}; 87 | 88 | 89 | //---------------------------------------------------------------- 90 | // Reg updates. 91 | //---------------------------------------------------------------- 92 | always @ (posedge clk) 93 | begin : reg_update_mem0 94 | if (mem0_we) 95 | mem0[api_addr[7 : 2]] <= api_wr_data; 96 | 97 | mem0_api_rd_data <= mem0[api_addr[7 : 2]]; 98 | mem0_int_rd_data <= mem0[internal_addr]; 99 | end 100 | 101 | always @ (posedge clk) 102 | begin : reg_update_mem1 103 | if (mem1_we) 104 | mem1[api_addr[7 : 2]] <= api_wr_data; 105 | 106 | mem1_api_rd_data <= mem1[api_addr[7 : 2]]; 107 | mem1_int_rd_data <= mem1[internal_addr]; 108 | end 109 | 110 | always @ (posedge clk) 111 | begin : reg_update_mem2 112 | if (mem2_we) 113 | mem2[api_addr[7 : 2]] <= api_wr_data; 114 | 115 | mem2_api_rd_data <= mem2[api_addr[7 : 2]]; 116 | mem2_int_rd_data <= mem2[internal_addr]; 117 | end 118 | 119 | always @ (posedge clk) 120 | begin : reg_update_mem3 121 | if (mem3_we) 122 | mem3[api_addr[7 : 2]] <= api_wr_data; 123 | 124 | mem3_api_rd_data <= mem3[api_addr[7 : 2]]; 125 | mem3_int_rd_data <= mem3[internal_addr]; 126 | end 127 | 128 | //---------------------------------------------------------------- 129 | // api_mux 130 | //---------------------------------------------------------------- 131 | always @* 132 | begin : api_mux 133 | mem0_we = 1'b0; 134 | mem1_we = 1'b0; 135 | mem2_we = 1'b0; 136 | mem3_we = 1'b0; 137 | 138 | case (api_addr[1 : 0]) 139 | 0: 140 | begin 141 | muxed_api_rd_data = mem0_api_rd_data; 142 | mem0_we = api_we; 143 | end 144 | 145 | 1: 146 | begin 147 | muxed_api_rd_data = mem1_api_rd_data; 148 | mem1_we = api_we; 149 | end 150 | 151 | 2: 152 | begin 153 | muxed_api_rd_data = mem2_api_rd_data; 154 | mem2_we = api_we; 155 | end 156 | 157 | 3: 158 | begin 159 | muxed_api_rd_data = mem3_api_rd_data; 160 | mem3_we = api_we; 161 | end 162 | 163 | default: 164 | begin 165 | end 166 | endcase // case (api_addr[1 : 0]) 167 | end // api_mux 168 | 169 | endmodule // blockmem_rw32_r128 170 | 171 | //====================================================================== 172 | // eof blockmem_rw32_r128.v 173 | //====================================================================== 174 | -------------------------------------------------------------------------------- /src/rtl/blockmem_rw32_r256.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // blockmem_rw32_r256.v 4 | // -------------------- 5 | // Test implementation of a block memory that has different data 6 | // widths on external (api) and internal ports. 7 | // Author: Joachim Strombergson, Peter Magnusson 8 | // Copyright (c) 2015, Assured AB 9 | // All rights reserved. 10 | // 11 | // Redistribution and use in source and binary forms, with or 12 | // without modification, are permitted provided that the following 13 | // conditions are met: 14 | // 15 | // 1. Redistributions of source code must retain the above copyright 16 | // notice, this list of conditions and the following disclaimer. 17 | // 18 | // 2. Redistributions in binary form must reproduce the above copyright 19 | // notice, this list of conditions and the following disclaimer in 20 | // the documentation and/or other materials provided with the 21 | // distribution. 22 | // 23 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 34 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | // 36 | //====================================================================== 37 | 38 | module blockmem_rw32_r128( 39 | input wire clk, 40 | 41 | input wire api_we, 42 | input wire [07 : 0] api_addr, 43 | input wire [31 : 0] api_wr_data, 44 | output wire [31 : 0] api_rd_data, 45 | 46 | input wire [04 : 0] internal_addr, 47 | output wire [255 : 0] internal_rd_data 48 | ); 49 | 50 | 51 | //---------------------------------------------------------------- 52 | // Regs and memories. 53 | //---------------------------------------------------------------- 54 | reg [31 : 0] mem0 [0 : 31]; 55 | reg [31 : 0] mem1 [0 : 31]; 56 | reg [31 : 0] mem2 [0 : 31]; 57 | reg [31 : 0] mem3 [0 : 31]; 58 | reg [31 : 0] mem4 [0 : 31]; 59 | reg [31 : 0] mem5 [0 : 31]; 60 | reg [31 : 0] mem6 [0 : 31]; 61 | reg [31 : 0] mem7 [0 : 31]; 62 | 63 | 64 | //---------------------------------------------------------------- 65 | // Wires. 66 | //---------------------------------------------------------------- 67 | reg [31 : 0] muxed_api_rd_data; 68 | 69 | reg [31 : 0] mem0_api_rd_data; 70 | reg [31 : 0] mem1_api_rd_data; 71 | reg [31 : 0] mem2_api_rd_data; 72 | reg [31 : 0] mem3_api_rd_data; 73 | reg [31 : 0] mem4_api_rd_data; 74 | reg [31 : 0] mem5_api_rd_data; 75 | reg [31 : 0] mem6_api_rd_data; 76 | reg [31 : 0] mem7_api_rd_data; 77 | 78 | reg [31 : 0] mem0_int_rd_data; 79 | reg [31 : 0] mem1_int_rd_data; 80 | reg [31 : 0] mem2_int_rd_data; 81 | reg [31 : 0] mem3_int_rd_data; 82 | reg [31 : 0] mem4_int_rd_data; 83 | reg [31 : 0] mem5_int_rd_data; 84 | reg [31 : 0] mem6_int_rd_data; 85 | reg [31 : 0] mem7_int_rd_data; 86 | 87 | reg mem0_we; 88 | reg mem1_we; 89 | reg mem2_we; 90 | reg mem3_we; 91 | reg mem4_we; 92 | reg mem5_we; 93 | reg mem6_we; 94 | reg mem7_we; 95 | 96 | 97 | //---------------------------------------------------------------- 98 | // Assignmets. 99 | //---------------------------------------------------------------- 100 | assign api_rd_data = muxed_api_rd_data; 101 | 102 | assign internal_rd_data = {mem7_int_rd_data, mem6_int_rd_data, 103 | mem5_int_rd_data, mem4_int_rd_data, 104 | mem3_int_rd_data, mem2_int_rd_data, 105 | mem1_int_rd_data, mem0_int_rd_data}; 106 | 107 | 108 | //---------------------------------------------------------------- 109 | // Reg updates. 110 | //---------------------------------------------------------------- 111 | always @ (posedge clk) 112 | begin : reg_update_mem0 113 | if (mem0_we) 114 | mem0[api_addr[7 : 3]] <= api_wr_data; 115 | 116 | mem0_api_rd_data <= mem0[api_addr[7 : 3]]; 117 | mem0_int_rd_data <= mem0[internal_addr]; 118 | end 119 | 120 | always @ (posedge clk) 121 | begin : reg_update_mem1 122 | if (mem1_we) 123 | mem1[api_addr[7 : 3]] <= api_wr_data; 124 | 125 | mem1_api_rd_data <= mem1[api_addr[7 : 3]]; 126 | mem1_int_rd_data <= mem1[internal_addr]; 127 | end 128 | 129 | always @ (posedge clk) 130 | begin : reg_update_mem2 131 | if (mem2_we) 132 | mem2[api_addr[7 : 3]] <= api_wr_data; 133 | 134 | mem2_api_rd_data <= mem2[api_addr[7 : 3]]; 135 | mem2_int_rd_data <= mem2[internal_addr]; 136 | end 137 | 138 | always @ (posedge clk) 139 | begin : reg_update_mem3 140 | if (mem3_we) 141 | mem3[api_addr[7 : 3]] <= api_wr_data; 142 | 143 | mem3_api_rd_data <= mem3[api_addr[7 : 3]]; 144 | mem3_int_rd_data <= mem3[internal_addr]; 145 | end 146 | 147 | always @ (posedge clk) 148 | begin : reg_update_mem4 149 | if (mem4_we) 150 | mem4[api_addr[7 : 3]] <= api_wr_data; 151 | 152 | mem4_api_rd_data <= mem4[api_addr[7 : 3]]; 153 | mem4_int_rd_data <= mem4[internal_addr]; 154 | end 155 | 156 | always @ (posedge clk) 157 | begin : reg_update_mem5 158 | if (mem5_we) 159 | mem5[api_addr[7 : 3]] <= api_wr_data; 160 | 161 | mem5_api_rd_data <= mem5[api_addr[7 : 3]]; 162 | mem5_int_rd_data <= mem5[internal_addr]; 163 | end 164 | 165 | always @ (posedge clk) 166 | begin : reg_update_mem6 167 | if (mem6_we) 168 | mem6[api_addr[7 : 3]] <= api_wr_data; 169 | 170 | mem6_api_rd_data <= mem6[api_addr[7 : 3]]; 171 | mem6_int_rd_data <= mem6[internal_addr]; 172 | end 173 | 174 | always @ (posedge clk) 175 | begin : reg_update_mem7 176 | if (mem7_we) 177 | mem7[api_addr[7 : 3]] <= api_wr_data; 178 | 179 | mem7_api_rd_data <= mem7[api_addr[7 : 3]]; 180 | mem7_int_rd_data <= mem7[internal_addr]; 181 | end 182 | 183 | 184 | //---------------------------------------------------------------- 185 | // api_mux 186 | //---------------------------------------------------------------- 187 | always @* 188 | begin : api_mux 189 | mem0_we = 1'b0; 190 | mem1_we = 1'b0; 191 | mem2_we = 1'b0; 192 | mem3_we = 1'b0; 193 | mem4_we = 1'b0; 194 | mem5_we = 1'b0; 195 | mem6_we = 1'b0; 196 | mem7_we = 1'b0; 197 | 198 | case (api_addr[2 : 0]) 199 | 0: 200 | begin 201 | muxed_api_rd_data = mem0_api_rd_data; 202 | mem0_we = api_we; 203 | end 204 | 205 | 1: 206 | begin 207 | muxed_api_rd_data = mem1_api_rd_data; 208 | mem1_we = api_we; 209 | end 210 | 211 | 2: 212 | begin 213 | muxed_api_rd_data = mem2_api_rd_data; 214 | mem2_we = api_we; 215 | end 216 | 217 | 3: 218 | begin 219 | muxed_api_rd_data = mem3_api_rd_data; 220 | mem3_we = api_we; 221 | end 222 | 223 | 4: 224 | begin 225 | muxed_api_rd_data = mem4_api_rd_data; 226 | mem4_we = api_we; 227 | end 228 | 229 | 5: 230 | begin 231 | muxed_api_rd_data = mem5_api_rd_data; 232 | mem5_we = api_we; 233 | end 234 | 235 | 6: 236 | begin 237 | muxed_api_rd_data = mem6_api_rd_data; 238 | mem6_we = api_we; 239 | end 240 | 241 | 7: 242 | begin 243 | muxed_api_rd_data = mem7_api_rd_data; 244 | mem7_we = api_we; 245 | end 246 | 247 | default: 248 | begin 249 | end 250 | endcase // case (api_addr[1 : 0]) 251 | end // api_mux 252 | 253 | endmodule // blockmem_rw32_r128 254 | 255 | //====================================================================== 256 | // eof blockmem_rw32_r128.v 257 | //====================================================================== 258 | -------------------------------------------------------------------------------- /src/rtl/blockmem_rw32_r64.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // blockmem_rw32_r64.v 4 | // ------------------- 5 | // Test implementation of a block memory that has different data 6 | // widths on external (api) and internal ports. 7 | // Author: Joachim Strombergson, Peter Magnusson 8 | // Copyright (c) 2015, Assured AB 9 | // All rights reserved. 10 | // 11 | // Redistribution and use in source and binary forms, with or 12 | // without modification, are permitted provided that the following 13 | // conditions are met: 14 | // 15 | // 1. Redistributions of source code must retain the above copyright 16 | // notice, this list of conditions and the following disclaimer. 17 | // 18 | // 2. Redistributions in binary form must reproduce the above copyright 19 | // notice, this list of conditions and the following disclaimer in 20 | // the documentation and/or other materials provided with the 21 | // distribution. 22 | // 23 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 26 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 27 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 28 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 29 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 30 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 31 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 32 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 34 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | // 36 | //====================================================================== 37 | 38 | module blockmem_rw32_r64( 39 | input wire clk, 40 | 41 | input wire api_wr, 42 | input wire [07 : 0] api_addr, 43 | input wire [31 : 0] api_wr_data, 44 | output wire [31 : 0] api_rd_data, 45 | 46 | input wire [06 : 0] internal_addr, 47 | output wire [63 : 0] internal_rd_data 48 | ); 49 | 50 | 51 | //---------------------------------------------------------------- 52 | // Regs and memories. 53 | //---------------------------------------------------------------- 54 | reg [31 : 0] mem0 [0 : 127]; 55 | reg [31 : 0] mem1 [0 : 127]; 56 | 57 | wire mem0_we; 58 | wire mem1_we; 59 | 60 | 61 | //---------------------------------------------------------------- 62 | // Wires. 63 | //---------------------------------------------------------------- 64 | reg [31 : 0] tmp0_api_rd_data; 65 | reg [31 : 0] tmp1_api_rd_data; 66 | reg [31 : 0] tmp0_int_rd_data; 67 | reg [31 : 0] tmp1_int_rd_data; 68 | 69 | 70 | //---------------------------------------------------------------- 71 | // Assignmets. 72 | //---------------------------------------------------------------- 73 | assign api_rd_data = api_addr[0] ? tmp1_api_rd_data : tmp0_api_rd_data; 74 | assign internal_rd_data = {tmp1_int_rd_data, tmp0_int_rd_data}; 75 | 76 | assign mem0_we = api_wr & ~api_addr[0]; 77 | assign mem1_we = api_wr & api_addr[0]; 78 | 79 | 80 | //---------------------------------------------------------------- 81 | // Reg updates. 82 | //---------------------------------------------------------------- 83 | always @ (posedge clk) 84 | begin : reg_update_mem0 85 | if (mem0_we) 86 | mem0[api_addr[7 : 1]] <= api_wr_data; 87 | 88 | tmp0_api_rd_data <= mem0[api_addr[7 : 1]]; 89 | tmp0_int_rd_data <= mem0[internal_addr]; 90 | end 91 | 92 | always @ (posedge clk) 93 | begin : reg_update_mem1 94 | if (mem1_we) 95 | mem1[api_addr[7 : 1]] <= api_wr_data; 96 | 97 | tmp1_api_rd_data <= mem1[api_addr[7 : 1]]; 98 | tmp1_int_rd_data <= mem1[internal_addr]; 99 | end 100 | 101 | endmodule // blockmem_rw32_r64 102 | 103 | //====================================================================== 104 | // eof blockmem_rw32_r64.v 105 | //====================================================================== 106 | -------------------------------------------------------------------------------- /src/rtl/modexp.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // modexp.v 4 | // -------- 5 | // Top level wrapper for the modula exponentiation core. The core 6 | // is used to implement public key algorithms such as RSA, 7 | // DH, ElGamal etc. 8 | // 9 | // The core calculates the following function: 10 | // 11 | // C = M ** e mod N 12 | // 13 | // M is a message with a length of n bits 14 | // e is the exponent with a length of m bits 15 | // N is the modulus with a length of n bits 16 | // 17 | // n can be 32 and up to and including 8192 bits in steps 18 | // of 32 bits. 19 | // m can be one and up to and including 8192 bits in steps 20 | // of 32 bits. 21 | // 22 | // The core has a 32-bit memory like interface, but provides 23 | // status signals to inform the system that a given operation 24 | // has is done. Additionally, any errors will also be asserted. 25 | // 26 | // 27 | // Author: Joachim Strombergson, Peter Magnusson 28 | // Copyright (c) 2015, Assured AB 29 | // All rights reserved. 30 | // 31 | // Redistribution and use in source and binary forms, with or 32 | // without modification, are permitted provided that the following 33 | // conditions are met: 34 | // 35 | // 1. Redistributions of source code must retain the above copyright 36 | // notice, this list of conditions and the following disclaimer. 37 | // 38 | // 2. Redistributions in binary form must reproduce the above copyright 39 | // notice, this list of conditions and the following disclaimer in 40 | // the documentation and/or other materials provided with the 41 | // distribution. 42 | // 43 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 44 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 45 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 46 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 47 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 48 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 49 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 50 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 51 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 52 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 53 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 54 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 | // 56 | // 57 | //====================================================================== 58 | 59 | module modexp( 60 | input wire clk, 61 | input wire reset_n, 62 | 63 | input wire cs, 64 | input wire we, 65 | 66 | input wire [11 : 0] address, 67 | input wire [31 : 0] write_data, 68 | output wire [31 : 0] read_data 69 | ); 70 | 71 | 72 | //---------------------------------------------------------------- 73 | // Internal constant and parameter definitions. 74 | //---------------------------------------------------------------- 75 | localparam GENERAL_PREFIX = 4'h0; 76 | localparam ADDR_NAME0 = 8'h00; 77 | localparam ADDR_NAME1 = 8'h01; 78 | localparam ADDR_VERSION = 8'h02; 79 | 80 | localparam ADDR_CTRL = 8'h08; 81 | localparam CTRL_INIT_BIT = 0; 82 | localparam CTRL_NEXT_BIT = 1; 83 | 84 | localparam ADDR_STATUS = 8'h09; 85 | localparam STATUS_READY_BIT = 0; 86 | 87 | localparam ADDR_CYCLES_HIGH = 8'h10; 88 | localparam ADDR_CYCLES_LOW = 8'h11; 89 | 90 | localparam ADDR_MODULUS_LENGTH = 8'h20; 91 | localparam ADDR_EXPONENT_LENGTH = 8'h21; 92 | 93 | localparam ADDR_MODULUS_PTR_RST = 8'h30; 94 | localparam ADDR_MODULUS_DATA = 8'h31; 95 | 96 | localparam ADDR_EXPONENT_PTR_RST = 8'h40; 97 | localparam ADDR_EXPONENT_DATA = 8'h41; 98 | 99 | localparam ADDR_MESSAGE_PTR_RST = 8'h50; 100 | localparam ADDR_MESSAGE_DATA = 8'h51; 101 | 102 | localparam ADDR_RESULT_PTR_RST = 8'h60; 103 | localparam ADDR_RESULT_DATA = 8'h61; 104 | 105 | localparam DEFAULT_MODLENGTH = 8'h80; // 2048 bits. 106 | localparam DEFAULT_EXPLENGTH = 8'h80; 107 | 108 | localparam CORE_NAME0 = 32'h6d6f6465; // "mode" 109 | localparam CORE_NAME1 = 32'h78702020; // "xp " 110 | localparam CORE_VERSION = 32'h302e3532; // "0.52" 111 | 112 | 113 | //---------------------------------------------------------------- 114 | // Registers including update variables and write enable. 115 | //---------------------------------------------------------------- 116 | reg [07 : 0] exponent_length_reg; 117 | reg [07 : 0] exponent_length_new; 118 | reg exponent_length_we; 119 | 120 | reg [07 : 0] modulus_length_reg; 121 | reg [07 : 0] modulus_length_new; 122 | reg modulus_length_we; 123 | 124 | reg start_reg; 125 | reg start_new; 126 | 127 | 128 | //---------------------------------------------------------------- 129 | // Wires. 130 | //---------------------------------------------------------------- 131 | reg exponent_mem_api_rst; 132 | reg exponent_mem_api_cs; 133 | reg exponent_mem_api_wr; 134 | wire [31 : 0] exponent_mem_api_read_data; 135 | 136 | reg modulus_mem_api_rst; 137 | reg modulus_mem_api_cs; 138 | reg modulus_mem_api_wr; 139 | wire [31 : 0] modulus_mem_api_read_data; 140 | 141 | reg message_mem_api_rst; 142 | reg message_mem_api_cs; 143 | reg message_mem_api_wr; 144 | wire [31 : 0] message_mem_api_read_data; 145 | 146 | reg result_mem_api_rst; 147 | reg result_mem_api_cs; 148 | wire [31 : 0] result_mem_api_read_data; 149 | 150 | wire ready; 151 | wire [63 : 0] cycles; 152 | 153 | reg [31 : 0] tmp_read_data; 154 | 155 | 156 | //---------------------------------------------------------------- 157 | // Concurrent connectivity for ports etc. 158 | //---------------------------------------------------------------- 159 | assign read_data = tmp_read_data; 160 | 161 | 162 | //---------------------------------------------------------------- 163 | // core instantiations. 164 | //---------------------------------------------------------------- 165 | modexp_core core_inst( 166 | .clk(clk), 167 | .reset_n(reset_n), 168 | 169 | .start(start_reg), 170 | .ready(ready), 171 | 172 | .exponent_length(exponent_length_reg), 173 | .modulus_length(modulus_length_reg), 174 | 175 | .cycles(cycles), 176 | 177 | .exponent_mem_api_cs(exponent_mem_api_cs), 178 | .exponent_mem_api_wr(exponent_mem_api_wr), 179 | .exponent_mem_api_rst(exponent_mem_api_rst), 180 | .exponent_mem_api_write_data(write_data), 181 | .exponent_mem_api_read_data(exponent_mem_api_read_data), 182 | 183 | .modulus_mem_api_cs(modulus_mem_api_cs), 184 | .modulus_mem_api_wr(modulus_mem_api_wr), 185 | .modulus_mem_api_rst(modulus_mem_api_rst), 186 | .modulus_mem_api_write_data(write_data), 187 | .modulus_mem_api_read_data(modulus_mem_api_read_data), 188 | 189 | .message_mem_api_cs(message_mem_api_cs), 190 | .message_mem_api_wr(message_mem_api_wr), 191 | .message_mem_api_rst(message_mem_api_rst), 192 | .message_mem_api_write_data(write_data), 193 | .message_mem_api_read_data(message_mem_api_read_data), 194 | 195 | .result_mem_api_cs(result_mem_api_cs), 196 | .result_mem_api_rst(result_mem_api_rst), 197 | .result_mem_api_read_data(result_mem_api_read_data) 198 | ); 199 | 200 | 201 | //---------------------------------------------------------------- 202 | // reg_update 203 | // 204 | // Update functionality for all registers in the core. 205 | // All registers are positive edge triggered with asynchronous 206 | // active low reset. All registers have write enable. 207 | //---------------------------------------------------------------- 208 | always @ (posedge clk or negedge reset_n) 209 | begin 210 | if (!reset_n) 211 | begin 212 | start_reg <= 1'b0; 213 | exponent_length_reg <= DEFAULT_EXPLENGTH; 214 | modulus_length_reg <= DEFAULT_MODLENGTH; 215 | end 216 | else 217 | begin 218 | start_reg <= start_new; 219 | 220 | if (exponent_length_we) 221 | begin 222 | exponent_length_reg <= write_data[7 : 0]; 223 | end 224 | 225 | if (modulus_length_we) 226 | begin 227 | modulus_length_reg <= write_data[7 : 0]; 228 | end 229 | end 230 | end // reg_update 231 | 232 | 233 | //---------------------------------------------------------------- 234 | // api 235 | // 236 | // The interface command decoding logic. 237 | //---------------------------------------------------------------- 238 | always @* 239 | begin : api 240 | modulus_length_we = 1'b0; 241 | exponent_length_we = 1'b0; 242 | start_new = 1'b0; 243 | 244 | modulus_mem_api_rst = 1'b0; 245 | modulus_mem_api_cs = 1'b0; 246 | modulus_mem_api_wr = 1'b0; 247 | 248 | exponent_mem_api_rst = 1'b0; 249 | exponent_mem_api_cs = 1'b0; 250 | exponent_mem_api_wr = 1'b0; 251 | 252 | message_mem_api_rst = 1'b0; 253 | message_mem_api_cs = 1'b0; 254 | message_mem_api_wr = 1'b0; 255 | 256 | result_mem_api_rst = 1'b0; 257 | result_mem_api_cs = 1'b0; 258 | 259 | tmp_read_data = 32'h00000000; 260 | 261 | if (cs) 262 | begin 263 | case (address[11 : 8]) 264 | GENERAL_PREFIX: 265 | begin 266 | if (we) 267 | begin 268 | case (address[7 : 0]) 269 | ADDR_CTRL: 270 | begin 271 | start_new = write_data[0]; 272 | end 273 | 274 | ADDR_MODULUS_LENGTH: 275 | begin 276 | modulus_length_we = 1'b1; 277 | end 278 | 279 | ADDR_EXPONENT_LENGTH: 280 | begin 281 | exponent_length_we = 1'b1; 282 | end 283 | 284 | ADDR_MODULUS_PTR_RST: 285 | begin 286 | modulus_mem_api_rst = 1'b1; 287 | end 288 | 289 | ADDR_MODULUS_DATA: 290 | begin 291 | modulus_mem_api_cs = 1'b1; 292 | modulus_mem_api_wr = 1'b1; 293 | end 294 | 295 | ADDR_EXPONENT_PTR_RST: 296 | begin 297 | exponent_mem_api_rst = 1'b1; 298 | end 299 | 300 | ADDR_EXPONENT_DATA: 301 | begin 302 | exponent_mem_api_cs = 1'b1; 303 | exponent_mem_api_wr = 1'b1; 304 | end 305 | 306 | ADDR_MESSAGE_PTR_RST: 307 | begin 308 | message_mem_api_rst = 1'b1; 309 | end 310 | 311 | ADDR_MESSAGE_DATA: 312 | begin 313 | message_mem_api_cs = 1'b1; 314 | message_mem_api_wr = 1'b1; 315 | end 316 | 317 | ADDR_RESULT_PTR_RST: 318 | begin 319 | result_mem_api_rst = 1'b1; 320 | end 321 | 322 | default: 323 | begin 324 | end 325 | endcase // case (address[7 : 0]) 326 | end 327 | else 328 | begin 329 | case (address[7 : 0]) 330 | ADDR_NAME0: 331 | tmp_read_data = CORE_NAME0; 332 | 333 | ADDR_NAME1: 334 | tmp_read_data = CORE_NAME1; 335 | 336 | ADDR_VERSION: 337 | tmp_read_data = CORE_VERSION; 338 | 339 | ADDR_CTRL: 340 | tmp_read_data = {31'h00000000, start_reg}; 341 | 342 | ADDR_STATUS: 343 | tmp_read_data = {31'h00000000, ready}; 344 | 345 | ADDR_CYCLES_HIGH: 346 | tmp_read_data = cycles[63 : 32]; 347 | 348 | ADDR_CYCLES_LOW: 349 | tmp_read_data = cycles[31 : 0]; 350 | 351 | ADDR_MODULUS_LENGTH: 352 | tmp_read_data = {24'h000000, modulus_length_reg}; 353 | 354 | ADDR_EXPONENT_LENGTH: 355 | tmp_read_data = {24'h000000, exponent_length_reg}; 356 | 357 | ADDR_MODULUS_DATA: 358 | begin 359 | modulus_mem_api_cs = 1'b1; 360 | tmp_read_data = modulus_mem_api_read_data; 361 | end 362 | 363 | ADDR_EXPONENT_DATA: 364 | begin 365 | exponent_mem_api_cs = 1'b1; 366 | tmp_read_data = exponent_mem_api_read_data; 367 | end 368 | 369 | ADDR_MESSAGE_DATA: 370 | begin 371 | message_mem_api_cs = 1'b1; 372 | tmp_read_data = message_mem_api_read_data; 373 | end 374 | 375 | ADDR_RESULT_DATA: 376 | begin 377 | result_mem_api_cs = 1'b1; 378 | tmp_read_data = result_mem_api_read_data; 379 | end 380 | 381 | default: 382 | begin 383 | end 384 | endcase // case (address[7 : 0]) 385 | end 386 | end 387 | 388 | default: 389 | begin 390 | 391 | end 392 | endcase // case (address[11 : 8]) 393 | end // if (cs) 394 | end // api 395 | 396 | endmodule // modexp 397 | 398 | //====================================================================== 399 | // EOF modexp.v 400 | //====================================================================== 401 | -------------------------------------------------------------------------------- /src/rtl/montprod.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // montprod.v 4 | // --------- 5 | // Montgomery product calculator for the modular exponentiantion core. 6 | // 7 | // 8 | // Author: Peter Magnusson, Joachim Strombergson 9 | // Copyright (c) 2015, NORDUnet A/S All rights reserved. 10 | // 11 | // Redistribution and use in source and binary forms, with or without 12 | // modification, are permitted provided that the following conditions are 13 | // met: 14 | // - Redistributions of source code must retain the above copyright notice, 15 | // this list of conditions and the following disclaimer. 16 | // 17 | // - Redistributions in binary form must reproduce the above copyright 18 | // notice, this list of conditions and the following disclaimer in the 19 | // documentation and/or other materials provided with the distribution. 20 | // 21 | // - Neither the name of the NORDUnet nor the names of its contributors may 22 | // be used to endorse or promote products derived from this software 23 | // without specific prior written permission. 24 | // 25 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 26 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 28 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 31 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 32 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | // 37 | //====================================================================== 38 | 39 | module montprod( 40 | input wire clk, 41 | input wire reset_n, 42 | 43 | input wire calculate, 44 | output wire ready, 45 | 46 | input [7 : 0] length, 47 | 48 | output wire [7 : 0] opa_addr, 49 | input wire [31 : 0] opa_data, 50 | 51 | output wire [7 : 0] opb_addr, 52 | input wire [31 : 0] opb_data, 53 | 54 | output wire [7 : 0] opm_addr, 55 | input wire [31 : 0] opm_data, 56 | 57 | output wire [7 : 0] result_addr, 58 | output wire [31 : 0] result_data, 59 | output wire result_we 60 | ); 61 | 62 | 63 | //---------------------------------------------------------------- 64 | // Internal constant and parameter definitions. 65 | //---------------------------------------------------------------- 66 | localparam DEBUG = 0; 67 | 68 | localparam CTRL_IDLE = 4'h0; 69 | localparam CTRL_INIT_S = 4'h1; 70 | localparam CTRL_LOOP_INIT = 4'h2; 71 | localparam CTRL_LOOP_ITER = 4'h3; 72 | localparam CTRL_LOOP_BQ = 4'h4; 73 | localparam CTRL_L_CALC_SM = 4'h5; 74 | localparam CTRL_L_STALLPIPE_SM = 4'h6; 75 | localparam CTRL_L_CALC_SA = 4'h7; 76 | localparam CTRL_L_STALLPIPE_SA = 4'h8; 77 | localparam CTRL_L_CALC_SDIV2 = 4'h9; 78 | localparam CTRL_L_STALLPIPE_D2 = 4'hA; 79 | localparam CTRL_L_STALLPIPE_ES = 4'hB; 80 | localparam CTRL_EMIT_S = 4'hC; 81 | localparam CTRL_DONE = 4'hD; 82 | 83 | localparam SMUX_0 = 2'h0; 84 | localparam SMUX_ADD_SM = 2'h1; 85 | localparam SMUX_ADD_SA = 2'h2; 86 | localparam SMUX_SHR = 2'h3; 87 | 88 | //---------------------------------------------------------------- 89 | // Registers including update variables and write enable. 90 | //---------------------------------------------------------------- 91 | 92 | reg [07 : 0] opa_addr_reg; 93 | reg [07 : 0] opb_addr_reg; 94 | reg [07 : 0] opm_addr_reg; 95 | 96 | reg [07 : 0] result_addr_reg; 97 | reg [31 : 0] result_data_reg; 98 | 99 | reg ready_reg; 100 | reg ready_new; 101 | reg ready_we; 102 | 103 | reg [3 : 0] montprod_ctrl_reg; 104 | reg [3 : 0] montprod_ctrl_new; 105 | reg montprod_ctrl_we; 106 | 107 | reg [1 : 0] s_mux_new; 108 | reg [1 : 0] s_mux_reg; 109 | 110 | reg [31 : 0] s_mem_new; 111 | reg s_mem_we; 112 | reg s_mem_we_new; 113 | reg [07 : 0] s_mem_addr; 114 | reg [07 : 0] s_mem_wr_addr; 115 | wire [31 : 0] s_mem_read_data; 116 | 117 | reg q; //q = (s - b * A) & 1 118 | reg q_reg; 119 | reg b; //b: bit of B 120 | reg b_reg; 121 | 122 | reg [12 : 0] loop_counter; 123 | reg [12 : 0] loop_counter_new; 124 | reg [12 : 0] loop_counter_dec; 125 | reg [07 : 0] B_word_index; //loop counter as a word index 126 | reg [04 : 0] B_bit_index; //loop counter as a bit index 127 | reg [04 : 0] B_bit_index_reg; //loop counter as a bit index 128 | 129 | reg [07 : 0] word_index; //register of what word is being read 130 | reg [07 : 0] word_index_new; //calculation of what word to be read 131 | reg [07 : 0] word_index_prev; //register of what word was read previously (result address to emit) 132 | reg [07 : 0] length_m1; 133 | 134 | reg add_carry_in_sa; 135 | reg add_carry_new_sa; 136 | reg add_carry_in_sm; 137 | reg add_carry_new_sm; 138 | 139 | reg shr_carry_in; 140 | reg shr_carry_new; 141 | 142 | reg reset_word_index_LSW; 143 | reg reset_word_index_MSW; 144 | 145 | 146 | //---------------------------------------------------------------- 147 | // Wires. 148 | //---------------------------------------------------------------- 149 | reg tmp_result_we; 150 | wire [31 : 0] add_result_sa; 151 | wire add_carry_out_sa; 152 | wire [31 : 0] add_result_sm; 153 | wire add_carry_out_sm; 154 | 155 | wire shr_carry_out; 156 | wire [31 : 0] shr_adiv2; 157 | 158 | 159 | //---------------------------------------------------------------- 160 | // Concurrent connectivity for ports etc. 161 | //---------------------------------------------------------------- 162 | assign opa_addr = opa_addr_reg; 163 | assign opb_addr = opb_addr_reg; 164 | assign opm_addr = opm_addr_reg; 165 | 166 | assign result_addr = result_addr_reg; 167 | assign result_data = result_data_reg; 168 | assign result_we = tmp_result_we; 169 | 170 | assign ready = ready_reg; 171 | 172 | 173 | //---------------------------------------------------------------- 174 | // Instantions 175 | //---------------------------------------------------------------- 176 | 177 | blockmem1r1w s_mem( 178 | .clk(clk), 179 | .read_addr(s_mem_addr), 180 | .read_data(s_mem_read_data), 181 | .wr(s_mem_we), 182 | .write_addr(s_mem_wr_addr), 183 | .write_data(s_mem_new) 184 | ); 185 | 186 | 187 | adder32 s_adder_sa( 188 | .a(s_mem_read_data), 189 | .b(opa_data), 190 | .carry_in(add_carry_in_sa), 191 | .sum(add_result_sa), 192 | .carry_out(add_carry_out_sa) 193 | ); 194 | 195 | adder32 s_adder_sm( 196 | .a(s_mem_read_data), 197 | .b(opm_data), 198 | .carry_in(add_carry_in_sm), 199 | .sum(add_result_sm), 200 | .carry_out(add_carry_out_sm) 201 | ); 202 | 203 | shr32 shifter( 204 | .a( s_mem_read_data ), 205 | .carry_in( shr_carry_in ), 206 | .adiv2( shr_adiv2 ), 207 | .carry_out( shr_carry_out ) 208 | ); 209 | 210 | always @* 211 | begin : s_mux 212 | case (s_mux_reg) 213 | SMUX_0: 214 | s_mem_new = 32'b0; 215 | SMUX_ADD_SA: 216 | s_mem_new = add_result_sa; 217 | SMUX_ADD_SM: 218 | s_mem_new = add_result_sm; 219 | SMUX_SHR: 220 | s_mem_new = shr_adiv2; 221 | endcase 222 | if (DEBUG) 223 | $display("SMUX%x: %x", s_mux_reg, s_mem_new); 224 | end 225 | 226 | 227 | //---------------------------------------------------------------- 228 | // reg_update 229 | // 230 | // Update functionality for all registers in the core. 231 | // All registers are positive edge triggered with asynchronous 232 | // active low reset. All registers have write enable. 233 | //---------------------------------------------------------------- 234 | always @ (posedge clk or negedge reset_n) 235 | begin : reg_update 236 | if (!reset_n) 237 | begin 238 | ready_reg <= 1'b0; 239 | loop_counter <= 13'h0; 240 | word_index <= 8'h0; 241 | word_index_prev <= 8'h0; 242 | add_carry_in_sa <= 1'b0; 243 | add_carry_in_sm <= 1'b0; 244 | shr_carry_in <= 1'b0; 245 | montprod_ctrl_reg <= CTRL_IDLE; 246 | b_reg <= 1'b0; 247 | q_reg <= 1'b0; 248 | s_mux_reg <= SMUX_0; 249 | s_mem_we <= 1'b0; 250 | s_mem_wr_addr <= 8'h0; 251 | B_bit_index_reg <= 5'h0; 252 | end 253 | else 254 | begin 255 | if (ready_we) 256 | ready_reg <= ready_new; 257 | 258 | if (montprod_ctrl_we) 259 | begin 260 | montprod_ctrl_reg <= montprod_ctrl_new; 261 | end 262 | 263 | s_mem_wr_addr <= s_mem_addr; 264 | 265 | s_mem_we <= s_mem_we_new; 266 | 267 | word_index <= word_index_new; 268 | word_index_prev <= word_index; 269 | 270 | loop_counter <= loop_counter_new; 271 | shr_carry_in <= shr_carry_new; 272 | add_carry_in_sa <= add_carry_new_sa; 273 | add_carry_in_sm <= add_carry_new_sm; 274 | 275 | B_bit_index_reg <= B_bit_index; 276 | q_reg <= q; 277 | b_reg <= b; 278 | 279 | s_mux_reg <= s_mux_new; 280 | end 281 | end // reg_update 282 | 283 | always @* 284 | begin : bq_process 285 | b = b_reg; 286 | q = q_reg; 287 | if (montprod_ctrl_reg == CTRL_LOOP_BQ) 288 | begin 289 | b = opb_data[ B_bit_index_reg ]; 290 | //opa_addr will point to length-1 to get A LSB. 291 | //s_read_addr will point to length-1 292 | q = s_mem_read_data[0] ^ (opa_data[0] & b); 293 | if (DEBUG) 294 | $display("s_mem_read_data: %x opa_data %x b %x q %x B_bit_index_reg %x", s_mem_read_data, opa_data, b, q, B_bit_index_reg); 295 | end 296 | end 297 | 298 | 299 | //---------------------------------------------------------------- 300 | // Process for iterating the loop counter and setting related B indexes 301 | //---------------------------------------------------------------- 302 | always @* 303 | begin : loop_counter_process 304 | loop_counter_new = loop_counter; 305 | length_m1 = length - 1'b1; 306 | loop_counter_dec = loop_counter - 1'b1; 307 | B_word_index = loop_counter[12:5]; 308 | B_bit_index = B_bit_index_reg; 309 | 310 | case (montprod_ctrl_reg) 311 | CTRL_LOOP_INIT: 312 | loop_counter_new = {length, 5'b00000} - 1'b1; 313 | 314 | CTRL_LOOP_ITER: 315 | begin 316 | B_word_index = loop_counter[12:5]; 317 | B_bit_index = 5'h1f - loop_counter[4:0]; 318 | end 319 | 320 | CTRL_L_STALLPIPE_D2: 321 | loop_counter_new = loop_counter_dec; 322 | 323 | default: 324 | loop_counter_new = loop_counter; 325 | endcase 326 | end 327 | 328 | 329 | //---------------------------------------------------------------- 330 | // prodcalc 331 | //---------------------------------------------------------------- 332 | always @* 333 | begin : prodcalc 334 | 335 | case (montprod_ctrl_reg) 336 | CTRL_LOOP_ITER: 337 | //q = (s[length-1] ^ A[length-1]) & 1; 338 | opa_addr_reg = length_m1; 339 | 340 | default: 341 | opa_addr_reg = word_index; 342 | endcase 343 | 344 | opb_addr_reg = B_word_index; 345 | opm_addr_reg = word_index; 346 | 347 | case (montprod_ctrl_reg) 348 | CTRL_LOOP_ITER: 349 | s_mem_addr = length_m1; 350 | default: 351 | s_mem_addr = word_index; 352 | endcase 353 | 354 | 355 | 356 | 357 | result_addr_reg = word_index_prev; 358 | result_data_reg = s_mem_read_data; 359 | 360 | case (montprod_ctrl_reg) 361 | CTRL_EMIT_S: 362 | tmp_result_we = 1'b1; 363 | default: 364 | tmp_result_we = 1'b0; 365 | endcase 366 | 367 | 368 | if (reset_word_index_LSW == 1'b1) 369 | word_index_new = length_m1; 370 | else if (reset_word_index_MSW == 1'b1) 371 | word_index_new = 8'h0; 372 | else if (montprod_ctrl_reg == CTRL_L_CALC_SDIV2) 373 | word_index_new = word_index + 1'b1; 374 | else 375 | word_index_new = word_index - 1'b1; 376 | end // prodcalc 377 | 378 | 379 | always @* 380 | begin : s_writer_process 381 | shr_carry_new = 1'b0; 382 | s_mux_new = SMUX_0; 383 | 384 | s_mem_we_new = 1'b0; 385 | case (montprod_ctrl_reg) 386 | CTRL_INIT_S: 387 | begin 388 | s_mem_we_new = 1'b1; 389 | s_mux_new = SMUX_0; // write 0 390 | end 391 | 392 | CTRL_L_CALC_SM: 393 | begin 394 | //s = (s + q*M + b*A) >>> 1;, if(q==1) S+= M. Takes (1..length) cycles. 395 | s_mem_we_new = q_reg; 396 | s_mux_new = SMUX_ADD_SM; 397 | end 398 | 399 | CTRL_L_CALC_SA: 400 | begin 401 | //s = (s + q*M + b*A) >>> 1;, if(b==1) S+= A. Takes (1..length) cycles. 402 | s_mem_we_new = b_reg; 403 | s_mux_new = SMUX_ADD_SA; 404 | end 405 | 406 | CTRL_L_CALC_SDIV2: 407 | begin 408 | //s = (s + q*M + b*A) >>> 1; s>>=1. Takes (1..length) cycles. 409 | s_mux_new = SMUX_SHR; 410 | s_mem_we_new = 1'b1; 411 | end 412 | 413 | default: 414 | begin 415 | end 416 | endcase 417 | 418 | add_carry_new_sa = 1'b0; 419 | add_carry_new_sm = 1'b0; 420 | 421 | case (s_mux_reg) 422 | SMUX_ADD_SM: 423 | add_carry_new_sm = add_carry_out_sm; 424 | 425 | SMUX_ADD_SA: 426 | add_carry_new_sa = add_carry_out_sa; 427 | 428 | SMUX_SHR: 429 | shr_carry_new = shr_carry_out; 430 | 431 | default: 432 | begin 433 | end 434 | endcase 435 | 436 | end // prodcalc 437 | 438 | 439 | //---------------------------------------------------------------- 440 | // montprod_ctrl 441 | // 442 | // Control FSM for the montgomery product calculator. 443 | //---------------------------------------------------------------- 444 | always @* 445 | begin : montprod_ctrl 446 | ready_new = 1'b0; 447 | ready_we = 1'b0; 448 | montprod_ctrl_new = CTRL_IDLE; 449 | montprod_ctrl_we = 1'b0; 450 | 451 | reset_word_index_LSW = 1'b0; 452 | reset_word_index_MSW = 1'b0; 453 | 454 | case (montprod_ctrl_reg) 455 | CTRL_IDLE: 456 | begin 457 | if (calculate) 458 | begin 459 | ready_new = 1'b0; 460 | ready_we = 1'b1; 461 | montprod_ctrl_new = CTRL_INIT_S; 462 | montprod_ctrl_we = 1'b1; 463 | reset_word_index_LSW = 1'b1; 464 | end 465 | else 466 | begin 467 | ready_new = 1'b1; 468 | ready_we = 1'b1; 469 | end 470 | end 471 | 472 | CTRL_INIT_S: 473 | begin 474 | if (word_index == 8'h0) 475 | begin 476 | montprod_ctrl_new = CTRL_LOOP_INIT; 477 | montprod_ctrl_we = 1'b1; 478 | end 479 | end 480 | 481 | 482 | CTRL_LOOP_INIT: 483 | begin 484 | montprod_ctrl_new = CTRL_LOOP_ITER; 485 | montprod_ctrl_we = 1'b1; 486 | end 487 | 488 | //calculate q = (s - b * A) & 1;. 489 | // Also abort loop if done. 490 | CTRL_LOOP_ITER: 491 | begin 492 | reset_word_index_LSW = 1'b1; 493 | montprod_ctrl_new = CTRL_LOOP_BQ; 494 | montprod_ctrl_we = 1'b1; 495 | end 496 | 497 | CTRL_LOOP_BQ: 498 | begin 499 | reset_word_index_LSW = 1'b1; 500 | montprod_ctrl_new = CTRL_L_CALC_SM; 501 | montprod_ctrl_we = 1'b1; 502 | end 503 | 504 | CTRL_L_CALC_SM: 505 | begin 506 | if (word_index == 8'h0) 507 | begin 508 | reset_word_index_LSW = 1'b1; 509 | montprod_ctrl_we = 1'b1; 510 | montprod_ctrl_new = CTRL_L_STALLPIPE_SM; 511 | end 512 | end 513 | 514 | CTRL_L_STALLPIPE_SM: 515 | begin 516 | montprod_ctrl_new = CTRL_L_CALC_SA; 517 | montprod_ctrl_we = 1'b1; 518 | reset_word_index_LSW = 1'b1; 519 | end 520 | 521 | CTRL_L_CALC_SA: 522 | begin 523 | if (word_index == 8'h0) 524 | begin 525 | reset_word_index_LSW = 1'b1; 526 | montprod_ctrl_new = CTRL_L_STALLPIPE_SA; 527 | montprod_ctrl_we = 1'b1; 528 | end 529 | end 530 | 531 | CTRL_L_STALLPIPE_SA: 532 | begin 533 | montprod_ctrl_new = CTRL_L_CALC_SDIV2; 534 | montprod_ctrl_we = 1'b1; 535 | reset_word_index_MSW = 1'b1; 536 | end 537 | 538 | CTRL_L_CALC_SDIV2: 539 | begin 540 | if (word_index == length_m1) 541 | begin 542 | montprod_ctrl_new = CTRL_L_STALLPIPE_D2; 543 | montprod_ctrl_we = 1'b1; 544 | //reset_word_index = 1'b1; 545 | end 546 | end 547 | 548 | CTRL_L_STALLPIPE_D2: 549 | begin 550 | montprod_ctrl_new = CTRL_LOOP_ITER; //loop 551 | montprod_ctrl_we = 1'b1; 552 | reset_word_index_LSW = 1'b1; 553 | if (loop_counter == 0) 554 | begin 555 | montprod_ctrl_new = CTRL_L_STALLPIPE_ES; 556 | montprod_ctrl_we = 1'b1; 557 | end 558 | end 559 | 560 | CTRL_L_STALLPIPE_ES: 561 | begin 562 | montprod_ctrl_new = CTRL_EMIT_S; 563 | montprod_ctrl_we = 1'b1; 564 | //reset_word_index_LSW = 1'b1; 565 | end 566 | 567 | CTRL_EMIT_S: 568 | begin 569 | if (DEBUG) 570 | $display("EMIT_S word_index: %d", word_index); 571 | if (word_index_prev == 8'h0) 572 | begin 573 | montprod_ctrl_new = CTRL_DONE; 574 | montprod_ctrl_we = 1'b1; 575 | end 576 | end 577 | 578 | CTRL_DONE: 579 | begin 580 | ready_new = 1'b1; 581 | ready_we = 1'b1; 582 | montprod_ctrl_new = CTRL_IDLE; 583 | montprod_ctrl_we = 1'b1; 584 | end 585 | 586 | default: 587 | begin 588 | end 589 | 590 | endcase // case (montprod_ctrl_reg) 591 | end // montprod_ctrl 592 | 593 | endmodule // montprod 594 | 595 | //====================================================================== 596 | // EOF montprod.v 597 | //====================================================================== 598 | -------------------------------------------------------------------------------- /src/rtl/residue.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // residue.v 4 | // --------- 5 | // Modulus 2**2N residue calculator for montgomery calculations. 6 | // 7 | // m_residue_2_2N_array( N, M, Nr) 8 | // Nr = 00...01 ; Nr = 1 == 2**(2N-2N) 9 | // for (int i = 0; i < 2 * N; i++) 10 | // Nr = Nr shift left 1 11 | // if (Nr less than M) continue; 12 | // Nr = Nr - M 13 | // return Nr 14 | // 15 | // 16 | // 17 | // Author: Peter Magnusson 18 | // Copyright (c) 2015, NORDUnet A/S All rights reserved. 19 | // 20 | // Redistribution and use in source and binary forms, with or without 21 | // modification, are permitted provided that the following conditions are 22 | // met: 23 | // - Redistributions of source code must retain the above copyright notice, 24 | // this list of conditions and the following disclaimer. 25 | // 26 | // - Redistributions in binary form must reproduce the above copyright 27 | // notice, this list of conditions and the following disclaimer in the 28 | // documentation and/or other materials provided with the distribution. 29 | // 30 | // - Neither the name of the NORDUnet nor the names of its contributors may 31 | // be used to endorse or promote products derived from this software 32 | // without specific prior written permission. 33 | // 34 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 35 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 36 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 37 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 38 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 39 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 40 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 41 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 42 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 43 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 44 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 45 | // 46 | //====================================================================== 47 | 48 | module residue( 49 | input wire clk, 50 | input wire reset_n, 51 | 52 | input wire calculate, 53 | output wire ready, 54 | 55 | input wire [14 : 0] nn, //MAX(2*N)=8192*2 (14 bit) 56 | input wire [07 : 0] length, 57 | 58 | output wire [07 : 0] opa_rd_addr, 59 | input wire [31 : 0] opa_rd_data, 60 | output wire [07 : 0] opa_wr_addr, 61 | output wire [31 : 0] opa_wr_data, 62 | output wire opa_wr_we, 63 | 64 | output wire [07 : 0] opm_addr, 65 | input wire [31 : 0] opm_data 66 | 67 | ); 68 | 69 | //---------------------------------------------------------------- 70 | // Internal constant and parameter definitions. 71 | //---------------------------------------------------------------- 72 | 73 | 74 | // m_residue_2_2N_array( N, M, Nr) 75 | // Nr = 00...01 ; Nr = 1 == 2**(2N-2N) 76 | // for (int i = 0; i < 2 * N; i++) 77 | // Nr = Nr shift left 1 78 | // if (Nr less than M) continue; 79 | // Nr = Nr - M 80 | // return Nr 81 | // 82 | localparam CTRL_IDLE = 4'h0; 83 | localparam CTRL_INIT = 4'h1; // Nr = 00...01 ; Nr = 1 == 2**(2N-2N) 84 | localparam CTRL_INIT_STALL = 4'h2; 85 | localparam CTRL_SHL = 4'h3; // Nr = Nr shift left 1 86 | localparam CTRL_SHL_STALL = 4'h4; 87 | localparam CTRL_COMPARE = 4'h5; //if (Nr less than M) continue; 88 | localparam CTRL_COMPARE_STALL = 4'h6; 89 | localparam CTRL_SUB = 4'h7; //Nr = Nr - M 90 | localparam CTRL_SUB_STALL = 4'h8; 91 | localparam CTRL_LOOP = 4'h9; //for (int i = 0; i < 2 * N; i++) 92 | 93 | //---------------------------------------------------------------- 94 | // Registers including update variables and write enable. 95 | //---------------------------------------------------------------- 96 | 97 | reg [07 : 0] opa_rd_addr_reg; 98 | reg [07 : 0] opa_wr_addr_reg; 99 | reg [31 : 0] opa_wr_data_reg; 100 | reg opa_wr_we_reg; 101 | reg [07 : 0] opm_addr_reg; 102 | reg ready_reg; 103 | reg ready_new; 104 | reg ready_we; 105 | reg [03 : 0] residue_ctrl_reg; 106 | reg [03 : 0] residue_ctrl_new; 107 | reg residue_ctrl_we; 108 | reg reset_word_index; 109 | reg reset_n_counter; 110 | reg [14 : 0] loop_counter_1_to_nn_reg; //for i = 1 to nn (2*N) 111 | reg [14 : 0] loop_counter_1_to_nn_new; 112 | reg loop_counter_1_to_nn_we; 113 | reg [14 : 0] nn_reg; 114 | reg nn_we; 115 | reg [07 : 0] length_m1_reg; 116 | reg [07 : 0] length_m1_new; 117 | reg length_m1_we; 118 | reg [07 : 0] word_index_reg; 119 | reg [07 : 0] word_index_new; 120 | reg word_index_we; 121 | 122 | reg [31 : 0] one_data; 123 | wire [31 : 0] sub_data; 124 | wire [31 : 0] shl_data; 125 | reg sub_carry_in_new; 126 | reg sub_carry_in_reg; 127 | wire sub_carry_out; 128 | reg shl_carry_in_new; 129 | reg shl_carry_in_reg; 130 | wire shl_carry_out; 131 | 132 | //---------------------------------------------------------------- 133 | // Concurrent connectivity for ports etc. 134 | //---------------------------------------------------------------- 135 | assign opa_rd_addr = opa_rd_addr_reg; 136 | assign opa_wr_addr = opa_wr_addr_reg; 137 | assign opa_wr_data = opa_wr_data_reg; 138 | assign opa_wr_we = opa_wr_we_reg; 139 | assign opm_addr = opm_addr_reg; 140 | assign ready = ready_reg; 141 | 142 | 143 | //---------------------------------------------------------------- 144 | // Instantions 145 | //---------------------------------------------------------------- 146 | adder32 subcmp( 147 | .a(opa_rd_data), 148 | .b( ~ opm_data), 149 | .carry_in(sub_carry_in_reg), 150 | .sum(sub_data), 151 | .carry_out(sub_carry_out) 152 | ); 153 | 154 | shl32 shl( 155 | .a(opa_rd_data), 156 | .carry_in(shl_carry_in_reg), 157 | .amul2(shl_data), 158 | .carry_out(shl_carry_out) 159 | ); 160 | 161 | 162 | 163 | //---------------------------------------------------------------- 164 | // reg_update 165 | //---------------------------------------------------------------- 166 | always @ (posedge clk or negedge reset_n) 167 | begin 168 | if (!reset_n) 169 | begin 170 | residue_ctrl_reg <= CTRL_IDLE; 171 | word_index_reg <= 8'h0; 172 | length_m1_reg <= 8'h0; 173 | nn_reg <= 15'h0; 174 | loop_counter_1_to_nn_reg <= 15'h0; 175 | ready_reg <= 1'b1; 176 | sub_carry_in_reg <= 1'b0; 177 | shl_carry_in_reg <= 1'b0; 178 | end 179 | else 180 | begin 181 | if (residue_ctrl_we) 182 | residue_ctrl_reg <= residue_ctrl_new; 183 | 184 | if (word_index_we) 185 | word_index_reg <= word_index_new; 186 | 187 | if (length_m1_we) 188 | length_m1_reg <= length_m1_new; 189 | 190 | if (nn_we) 191 | nn_reg <= nn; 192 | 193 | if (loop_counter_1_to_nn_we) 194 | loop_counter_1_to_nn_reg <= loop_counter_1_to_nn_new; 195 | 196 | if (ready_we) 197 | ready_reg <= ready_new; 198 | 199 | sub_carry_in_reg <= sub_carry_in_new; 200 | shl_carry_in_reg <= shl_carry_in_new; 201 | end 202 | end // reg_update 203 | 204 | 205 | //---------------------------------------------------------------- 206 | // loop counter process. implements for (int i = 0; i < 2 * N; i++) 207 | // 208 | // m_residue_2_2N_array( N, M, Nr) 209 | // Nr = 00...01 ; Nr = 1 == 2**(2N-2N) 210 | // for (int i = 0; i < 2 * N; i++) 211 | // Nr = Nr shift left 1 212 | // if (Nr less than M) continue; 213 | // Nr = Nr - M 214 | // return Nr 215 | // 216 | //---------------------------------------------------------------- 217 | always @* 218 | begin : process_1_to_2n 219 | loop_counter_1_to_nn_new = loop_counter_1_to_nn_reg + 15'h1; 220 | loop_counter_1_to_nn_we = 1'b0; 221 | 222 | if (reset_n_counter) 223 | begin 224 | loop_counter_1_to_nn_new = 15'h1; 225 | loop_counter_1_to_nn_we = 1'b1; 226 | end 227 | 228 | if (residue_ctrl_reg == CTRL_LOOP) 229 | loop_counter_1_to_nn_we = 1'b1; 230 | end 231 | 232 | //---------------------------------------------------------------- 233 | // implements looping over words in a multiword operation 234 | //---------------------------------------------------------------- 235 | always @* 236 | begin : word_index_process 237 | word_index_new = word_index_reg - 8'h1; 238 | word_index_we = 1'b1; 239 | 240 | if (reset_word_index) 241 | word_index_new = length_m1_reg; 242 | 243 | if (residue_ctrl_reg == CTRL_IDLE) 244 | word_index_new = length_m1_new; //reduce a pipeline stage with early read 245 | 246 | end 247 | 248 | //---------------------------------------------------------------- 249 | // writer process. implements: 250 | // Nr = 00...01 ; Nr = 1 == 2**(2N-2N) 251 | // Nr = Nr shift left 1 252 | // Nr = Nr - M 253 | // 254 | // m_residue_2_2N_array( N, M, Nr) 255 | // Nr = 00...01 ; Nr = 1 == 2**(2N-2N) 256 | // for (int i = 0; i < 2 * N; i++) 257 | // Nr = Nr shift left 1 258 | // if (Nr less than M) continue; 259 | // Nr = Nr - M 260 | // return Nr 261 | //---------------------------------------------------------------- 262 | always @* 263 | begin : writer_process 264 | opa_wr_addr_reg = word_index_reg; 265 | case (residue_ctrl_reg) 266 | CTRL_INIT: 267 | begin 268 | opa_wr_data_reg = one_data; 269 | opa_wr_we_reg = 1'b1; 270 | end 271 | 272 | CTRL_SUB: 273 | begin 274 | opa_wr_data_reg = sub_data; 275 | opa_wr_we_reg = 1'b1; 276 | end 277 | 278 | CTRL_SHL: 279 | begin 280 | opa_wr_data_reg = shl_data; 281 | opa_wr_we_reg = 1'b1; 282 | end 283 | 284 | default: 285 | begin 286 | opa_wr_data_reg = 32'h0; 287 | opa_wr_we_reg = 1'b0; 288 | end 289 | endcase 290 | end 291 | 292 | //---------------------------------------------------------------- 293 | // reader process. reads from new value because it occurs one 294 | // cycle earlier than the writer. 295 | //---------------------------------------------------------------- 296 | always @* 297 | begin : reader_process 298 | opa_rd_addr_reg = word_index_new; 299 | opm_addr_reg = word_index_new; 300 | end 301 | 302 | //---------------------------------------------------------------- 303 | // carry process. "Ripple carry awesomeness!" 304 | //---------------------------------------------------------------- 305 | always @* 306 | begin : carry_process 307 | case (residue_ctrl_reg) 308 | CTRL_COMPARE: 309 | sub_carry_in_new = sub_carry_out; 310 | CTRL_SUB: 311 | sub_carry_in_new = sub_carry_out; 312 | default: 313 | sub_carry_in_new = 1'b1; 314 | endcase 315 | 316 | case (residue_ctrl_reg) 317 | CTRL_SHL: 318 | shl_carry_in_new = shl_carry_out; 319 | default: 320 | shl_carry_in_new = 1'b0; 321 | endcase 322 | end 323 | 324 | //---------------------------------------------------------------- 325 | // Nr = 00...01 ; Nr = 1 == 2**(2N-2N) 326 | //---------------------------------------------------------------- 327 | always @* 328 | begin : one_process 329 | one_data = 32'h0; 330 | if (residue_ctrl_reg == CTRL_INIT) 331 | if (word_index_reg == length_m1_reg) 332 | one_data = 32'h1; 333 | end 334 | 335 | //---------------------------------------------------------------- 336 | // residue_ctrl 337 | // 338 | // Control FSM for residue 339 | //---------------------------------------------------------------- 340 | always @* 341 | begin : residue_ctrl 342 | ready_new = 1'b0; 343 | ready_we = 1'b0; 344 | 345 | residue_ctrl_new = CTRL_IDLE; 346 | residue_ctrl_we = 1'b0; 347 | 348 | reset_word_index = 1'b0; 349 | reset_n_counter = 1'b0; 350 | 351 | length_m1_new = length - 8'h1; 352 | length_m1_we = 1'b0; 353 | 354 | nn_we = 1'b0; 355 | 356 | case (residue_ctrl_reg) 357 | CTRL_IDLE: 358 | if (calculate) 359 | begin 360 | ready_new = 1'b0; 361 | ready_we = 1'b1; 362 | residue_ctrl_new = CTRL_INIT; 363 | residue_ctrl_we = 1'b1; 364 | reset_word_index = 1'b1; 365 | length_m1_we = 1'b1; 366 | nn_we = 1'b1; 367 | end 368 | 369 | CTRL_INIT: 370 | if (word_index_reg == 8'h0) 371 | begin 372 | residue_ctrl_new = CTRL_INIT_STALL; 373 | residue_ctrl_we = 1'b1; 374 | end 375 | 376 | CTRL_INIT_STALL: 377 | begin 378 | reset_word_index = 1'b1; 379 | reset_n_counter = 1'b1; 380 | residue_ctrl_new = CTRL_SHL; 381 | residue_ctrl_we = 1'b1; 382 | end 383 | 384 | CTRL_SHL: 385 | begin 386 | if (word_index_reg == 8'h0) 387 | begin 388 | residue_ctrl_new = CTRL_SHL_STALL; 389 | residue_ctrl_we = 1'b1; 390 | end 391 | end 392 | 393 | CTRL_SHL_STALL: 394 | begin 395 | reset_word_index = 1'b1; 396 | residue_ctrl_new = CTRL_COMPARE; 397 | residue_ctrl_we = 1'b1; 398 | end 399 | 400 | CTRL_COMPARE: 401 | if (word_index_reg == 8'h0) 402 | begin 403 | residue_ctrl_new = CTRL_COMPARE_STALL; 404 | residue_ctrl_we = 1'b1; 405 | end 406 | 407 | CTRL_COMPARE_STALL: 408 | begin 409 | reset_word_index = 1'b1; 410 | residue_ctrl_we = 1'b1; 411 | if (sub_carry_in_reg == 1'b1) 412 | //TODO: Bug! detect CF to detect less than, but no detect ZF to detect equal to. 413 | residue_ctrl_new = CTRL_SUB; 414 | else 415 | residue_ctrl_new = CTRL_LOOP; 416 | end 417 | 418 | CTRL_SUB: 419 | if (word_index_reg == 8'h0) 420 | begin 421 | residue_ctrl_new = CTRL_SUB_STALL; 422 | residue_ctrl_we = 1'b1; 423 | end 424 | 425 | CTRL_SUB_STALL: 426 | begin 427 | residue_ctrl_new = CTRL_LOOP; 428 | residue_ctrl_we = 1'b1; 429 | end 430 | 431 | CTRL_LOOP: 432 | begin 433 | if (loop_counter_1_to_nn_reg == nn_reg) 434 | begin 435 | ready_new = 1'b1; 436 | ready_we = 1'b1; 437 | residue_ctrl_new = CTRL_IDLE; 438 | residue_ctrl_we = 1'b1; 439 | end 440 | else 441 | begin 442 | reset_word_index = 1'b1; 443 | residue_ctrl_new = CTRL_SHL; 444 | residue_ctrl_we = 1'b1; 445 | end 446 | end 447 | 448 | default: 449 | begin 450 | end 451 | 452 | endcase 453 | end 454 | 455 | endmodule // residue 456 | 457 | //====================================================================== 458 | // EOF residue.v 459 | //====================================================================== 460 | -------------------------------------------------------------------------------- /src/rtl/shl32.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // shl32.v 4 | // ------- 5 | // 32bit left shift with carry in / carry out 6 | // 7 | // 8 | // Author: Peter Magnusson 9 | // Copyright (c) 2015, NORDUnet A/S All rights reserved. 10 | // 11 | // Redistribution and use in source and binary forms, with or without 12 | // modification, are permitted provided that the following conditions are 13 | // met: 14 | // - Redistributions of source code must retain the above copyright notice, 15 | // this list of conditions and the following disclaimer. 16 | // 17 | // - Redistributions in binary form must reproduce the above copyright 18 | // notice, this list of conditions and the following disclaimer in the 19 | // documentation and/or other materials provided with the distribution. 20 | // 21 | // - Neither the name of the NORDUnet nor the names of its contributors may 22 | // be used to endorse or promote products derived from this software 23 | // without specific prior written permission. 24 | // 25 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 26 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 28 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 31 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 32 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | // 37 | //====================================================================== 38 | 39 | module shl32( 40 | input wire [31 : 0] a, 41 | input wire carry_in, 42 | output wire [31 : 0] amul2, 43 | output wire carry_out 44 | ); 45 | 46 | assign amul2 = {a[30 : 0], carry_in}; 47 | assign carry_out = a[31]; 48 | 49 | endmodule // shl32 50 | 51 | //====================================================================== 52 | // EOF shl32.v 53 | //====================================================================== 54 | -------------------------------------------------------------------------------- /src/rtl/shr32.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // shr32.v 4 | // ------- 5 | // 32bit right shift with carry in / carry out. 6 | // 7 | // 8 | // Author: Peter Magnusson 9 | // Copyright (c) 2015, NORDUnet A/S All rights reserved. 10 | // 11 | // Redistribution and use in source and binary forms, with or without 12 | // modification, are permitted provided that the following conditions are 13 | // met: 14 | // - Redistributions of source code must retain the above copyright notice, 15 | // this list of conditions and the following disclaimer. 16 | // 17 | // - Redistributions in binary form must reproduce the above copyright 18 | // notice, this list of conditions and the following disclaimer in the 19 | // documentation and/or other materials provided with the distribution. 20 | // 21 | // - Neither the name of the NORDUnet nor the names of its contributors may 22 | // be used to endorse or promote products derived from this software 23 | // without specific prior written permission. 24 | // 25 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 26 | // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 | // TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 28 | // PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 | // HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 31 | // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 32 | // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 33 | // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 34 | // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 35 | // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | // 37 | //====================================================================== 38 | 39 | module shr32( 40 | input wire [31 : 0] a, 41 | input wire carry_in, 42 | output wire [31 : 0] adiv2, 43 | output wire carry_out 44 | ); 45 | 46 | assign adiv2 = {carry_in, a[31 : 1]}; 47 | assign carry_out = a[0]; 48 | 49 | endmodule // shr32 50 | 51 | //====================================================================== 52 | // EOF shr32.v 53 | //====================================================================== 54 | -------------------------------------------------------------------------------- /src/tb/tb_modexp_autogenerated_template.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // tb_modexp_autogenerated.v 4 | // ----------- 5 | // Testbench modular exponentiation core. 6 | // 7 | // 8 | // Author: Joachim Strombergson, Peter Magnusson 9 | // Copyright (c) 2015, Assured AB 10 | // All rights reserved. 11 | // 12 | // Redistribution and use in source and binary forms, with or 13 | // without modification, are permitted provided that the following 14 | // conditions are met: 15 | // 16 | // 1. Redistributions of source code must retain the above copyright 17 | // notice, this list of conditions and the following disclaimer. 18 | // 19 | // 2. Redistributions in binary form must reproduce the above copyright 20 | // notice, this list of conditions and the following disclaimer in 21 | // the documentation and/or other materials provided with the 22 | // distribution. 23 | // 24 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 33 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 35 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | // 37 | //====================================================================== 38 | 39 | //------------------------------------------------------------------ 40 | // Simulator directives. 41 | //------------------------------------------------------------------ 42 | `timescale 1ns/100ps 43 | 44 | 45 | //------------------------------------------------------------------ 46 | // Test module. 47 | //------------------------------------------------------------------ 48 | module tb_modexp_autogenerated(); 49 | 50 | //---------------------------------------------------------------- 51 | // Internal constant and parameter definitions. 52 | //---------------------------------------------------------------- 53 | // Debug output control. 54 | parameter DEBUG = 0; 55 | parameter DEBUG_EI = 0; 56 | parameter DISPLAY_TEST_CYCLES = 1; 57 | 58 | // Clock defines. 59 | localparam CLK_HALF_PERIOD = 1; 60 | localparam CLK_PERIOD = 2 * CLK_HALF_PERIOD; 61 | 62 | // The DUT address map. 63 | localparam GENERAL_PREFIX = 4'h0; 64 | localparam ADDR_NAME0 = 8'h00; 65 | localparam ADDR_NAME1 = 8'h01; 66 | localparam ADDR_VERSION = 8'h02; 67 | 68 | localparam ADDR_CTRL = 8'h08; 69 | localparam CTRL_START_BIT = 0; 70 | 71 | localparam ADDR_STATUS = 8'h09; 72 | localparam STATUS_READY_BIT = 0; 73 | 74 | localparam ADDR_MODULUS_LENGTH = 8'h20; 75 | localparam ADDR_EXPONENT_LENGTH = 8'h21; 76 | localparam ADDR_LENGTH = 8'h22; 77 | 78 | localparam MODULUS_PREFIX = 4'h1; 79 | localparam ADDR_MODULUS_START = 8'h00; 80 | localparam ADDR_MODULUS_END = 8'hff; 81 | 82 | localparam EXPONENT_PREFIX = 4'h2; 83 | localparam ADDR_EXPONENT_START = 8'h00; 84 | localparam ADDR_EXPONENT_END = 8'hff; 85 | 86 | localparam MESSAGE_PREFIX = 4'h3; 87 | localparam MESSAGE_START = 8'h00; 88 | localparam MESSAGE_END = 8'hff; 89 | 90 | localparam RESULT_PREFIX = 4'h4; 91 | localparam RESULT_START = 8'h00; 92 | localparam RESULT_END = 8'hff; 93 | 94 | 95 | //---------------------------------------------------------------- 96 | // Register and Wire declarations. 97 | //---------------------------------------------------------------- 98 | reg [31 : 0] test_cycle_ctr; 99 | reg test_cycle_ctr_rst; 100 | reg test_cycle_ctr_inc; 101 | 102 | reg [31 : 0] cycle_ctr; 103 | reg [31 : 0] error_ctr; 104 | reg [31 : 0] tc_ctr; 105 | 106 | reg [31 : 0] read_data; 107 | reg [127 : 0] result_data; 108 | 109 | reg tb_clk; 110 | reg tb_reset_n; 111 | reg tb_cs; 112 | reg tb_we; 113 | reg [11 : 0] tb_address; 114 | reg [31 : 0] tb_write_data; 115 | wire [31 : 0] tb_read_data; 116 | wire tb_error; 117 | 118 | 119 | //---------------------------------------------------------------- 120 | // Device Under Test. 121 | //---------------------------------------------------------------- 122 | modexp dut( 123 | .clk(tb_clk), 124 | .reset_n(tb_reset_n), 125 | .cs(tb_cs), 126 | .we(tb_we), 127 | .address(tb_address), 128 | .write_data(tb_write_data), 129 | .read_data(tb_read_data) 130 | ); 131 | 132 | 133 | //---------------------------------------------------------------- 134 | // clk_gen 135 | // 136 | // Always running clock generator process. 137 | //---------------------------------------------------------------- 138 | always 139 | begin : clk_gen 140 | #CLK_HALF_PERIOD; 141 | tb_clk = !tb_clk; 142 | end // clk_gen 143 | 144 | 145 | //---------------------------------------------------------------- 146 | // sys_monitor() 147 | // 148 | // An always running process that creates a cycle counter and 149 | // conditionally displays information about the DUT. 150 | //---------------------------------------------------------------- 151 | always 152 | begin : sys_monitor 153 | cycle_ctr = cycle_ctr + 1; 154 | 155 | #(CLK_PERIOD); 156 | 157 | if (DEBUG) 158 | begin 159 | dump_dut_state(); 160 | end 161 | end 162 | 163 | 164 | //---------------------------------------------------------------- 165 | // test_cycle_counter 166 | // 167 | // Used to measure the number of cycles it takes to perform 168 | // a given test case. 169 | //---------------------------------------------------------------- 170 | always @ (posedge tb_clk) 171 | begin 172 | if (test_cycle_ctr_rst) 173 | test_cycle_ctr = 64'h0000000000000000; 174 | 175 | if (test_cycle_ctr_inc) 176 | test_cycle_ctr = test_cycle_ctr + 1; 177 | end 178 | 179 | 180 | //---------------------------------------------------------------- 181 | // start_test_cycle_ctr 182 | // 183 | // Reset and start the test cycle counter. 184 | //---------------------------------------------------------------- 185 | task start_test_cycle_ctr(); 186 | begin 187 | test_cycle_ctr_rst = 1; 188 | #(CLK_PERIOD); 189 | test_cycle_ctr_rst = 0; 190 | 191 | test_cycle_ctr_inc = 1; 192 | end 193 | endtask // start_test_cycle_ctr() 194 | 195 | 196 | //---------------------------------------------------------------- 197 | // stop_test_cycle_ctr() 198 | // 199 | // Stop the test cycle counter and optionally display the 200 | // result. 201 | //---------------------------------------------------------------- 202 | task stop_test_cycle_ctr(); 203 | begin 204 | test_cycle_ctr_inc = 0; 205 | #(CLK_PERIOD); 206 | 207 | if (DISPLAY_TEST_CYCLES) 208 | $display("*** Number of cycles performed during test: 0x%016x", test_cycle_ctr); 209 | end 210 | endtask // stop_test_cycle_ctr() 211 | 212 | 213 | //---------------------------------------------------------------- 214 | // dump_dut_state() 215 | // 216 | // Dump the state of the dump when needed. 217 | //---------------------------------------------------------------- 218 | task dump_dut_state(); 219 | begin 220 | $display("cycle: 0x%016x", cycle_ctr); 221 | $display("State of DUT"); 222 | $display("------------"); 223 | $display("Inputs and outputs:"); 224 | $display("cs = 0x%01x, we = 0x%01x", tb_cs, tb_we); 225 | $display("addr = 0x%08x, read_data = 0x%08x, write_data = 0x%08x", 226 | tb_address, tb_read_data, tb_write_data); 227 | $display(""); 228 | 229 | $display("State:"); 230 | $display("ready_reg = 0x%01x, start_reg = 0x%01x, start_new = 0x%01x, start_we = 0x%01x", 231 | dut.ready_reg, dut.start_reg, dut.start_new, dut.start_we); 232 | $display("residue_valid = 0x%01x", dut.residue_valid_reg); 233 | $display("loop_counter_reg = 0x%08x", dut.loop_counter_reg); 234 | $display("exponent_length_reg = 0x%02x, modulus_length_reg = 0x%02x", 235 | dut.exponent_length_reg, dut.modulus_length_reg); 236 | $display("length_reg = 0x%02x, length_m1_reg = 0x%02x", 237 | dut.length_reg, dut.length_m1_reg); 238 | $display("ctrl_reg = 0x%04x", dut.modexp_ctrl_reg); 239 | $display(""); 240 | end 241 | endtask // dump_dut_state 242 | 243 | 244 | //---------------------------------------------------------------- 245 | // reset_dut() 246 | // 247 | // Toggle reset to put the DUT into a well known state. 248 | //---------------------------------------------------------------- 249 | task reset_dut(); 250 | begin 251 | $display("*** Toggle reset."); 252 | tb_reset_n = 0; 253 | 254 | #(2 * CLK_PERIOD); 255 | tb_reset_n = 1; 256 | $display(""); 257 | end 258 | endtask // reset_dut 259 | 260 | 261 | //---------------------------------------------------------------- 262 | // display_test_results() 263 | // 264 | // Display the accumulated test results. 265 | //---------------------------------------------------------------- 266 | task display_test_results(); 267 | begin 268 | if (error_ctr == 0) 269 | begin 270 | $display("*** All %02d test cases completed successfully", tc_ctr); 271 | end 272 | else 273 | begin 274 | $display("*** %02d tests completed - %02d test cases did not complete successfully.", 275 | tc_ctr, error_ctr); 276 | end 277 | end 278 | endtask // display_test_results 279 | 280 | 281 | //---------------------------------------------------------------- 282 | // init_sim() 283 | // 284 | // Initialize all counters and testbed functionality as well 285 | // as setting the DUT inputs to defined values. 286 | //---------------------------------------------------------------- 287 | task init_sim(); 288 | begin 289 | cycle_ctr = 0; 290 | error_ctr = 0; 291 | tc_ctr = 0; 292 | 293 | tb_clk = 0; 294 | tb_reset_n = 1; 295 | 296 | tb_cs = 0; 297 | tb_we = 0; 298 | tb_address = 8'h00; 299 | tb_write_data = 32'h00000000; 300 | end 301 | endtask // init_sim 302 | 303 | 304 | //---------------------------------------------------------------- 305 | // read_word() 306 | // 307 | // Read a data word from the given address in the DUT. 308 | // the word read will be available in the global variable 309 | // read_data. 310 | //---------------------------------------------------------------- 311 | task read_word(input [11 : 0] address); 312 | begin 313 | tb_address = address; 314 | tb_cs = 1; 315 | tb_we = 0; 316 | #(CLK_PERIOD); 317 | read_data = tb_read_data; 318 | tb_cs = 0; 319 | 320 | if (DEBUG) 321 | begin 322 | $display("*** (read_word) Reading 0x%08x from 0x%02x.", read_data, address); 323 | $display(""); 324 | end 325 | end 326 | endtask // read_word 327 | 328 | 329 | //---------------------------------------------------------------- 330 | // write_word() 331 | // 332 | // Write the given word to the DUT using the DUT interface. 333 | //---------------------------------------------------------------- 334 | task write_word(input [11 : 0] address, 335 | input [31 : 0] word); 336 | begin 337 | if (DEBUG) 338 | begin 339 | $display("*** (write_word) Writing 0x%08x to 0x%02x.", word, address); 340 | $display(""); 341 | end 342 | 343 | tb_address = address; 344 | tb_write_data = word; 345 | tb_cs = 1; 346 | tb_we = 1; 347 | #(2 * CLK_PERIOD); 348 | tb_cs = 0; 349 | tb_we = 0; 350 | end 351 | endtask // write_word 352 | 353 | 354 | //---------------------------------------------------------------- 355 | // wait_ready() 356 | // 357 | // Wait until the ready flag in the core is set. 358 | //---------------------------------------------------------------- 359 | task wait_ready(); 360 | begin 361 | while (tb_read_data != 32'h00000001) 362 | read_word({GENERAL_PREFIX, ADDR_STATUS}); 363 | 364 | if (DEBUG) 365 | $display("*** (wait_ready) Ready flag has been set."); 366 | end 367 | endtask // wait_ready 368 | 369 | 370 | //---------------------------------------------------------------- 371 | // dump_message_mem() 372 | // 373 | // Dump the contents of the message memory. 374 | //---------------------------------------------------------------- 375 | task dump_message_mem(); 376 | reg [8 : 0] i; 377 | begin 378 | $display("Contents of the message memory:"); 379 | for (i = 0 ; i < 256 ; i = i + 8) 380 | begin 381 | $display("message_mem[0x%02x .. 0x%02x] = 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", 382 | i[7 : 0], (i[7 : 0] + 8'h07), 383 | dut.message_mem.mem[(i[7 : 0] + 0)], dut.message_mem.mem[(i[7 : 0] + 1)], 384 | dut.message_mem.mem[(i[7 : 0] + 2)], dut.message_mem.mem[(i[7 : 0] + 3)], 385 | dut.message_mem.mem[(i[7 : 0] + 4)], dut.message_mem.mem[(i[7 : 0] + 5)], 386 | dut.message_mem.mem[(i[7 : 0] + 6)], dut.message_mem.mem[(i[7 : 0] + 7)], 387 | ); 388 | end 389 | $display(""); 390 | end 391 | endtask // dump_message_mem 392 | 393 | 394 | //---------------------------------------------------------------- 395 | // dump_exponent_mem() 396 | // 397 | // Dump the contents of the exponent memory. 398 | //---------------------------------------------------------------- 399 | task dump_exponent_mem(); 400 | reg [8 : 0] i; 401 | begin 402 | $display("Contents of the exponent memory:"); 403 | for (i = 0 ; i < 256 ; i = i + 8) 404 | begin 405 | $display("exponent_mem[0x%02x .. 0x%02x] = 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", 406 | i[7 : 0], (i[7 : 0] + 8'h07), 407 | dut.exponent_mem.mem[(i[7 : 0] + 0)], dut.exponent_mem.mem[(i[7 : 0] + 1)], 408 | dut.exponent_mem.mem[(i[7 : 0] + 2)], dut.exponent_mem.mem[(i[7 : 0] + 3)], 409 | dut.exponent_mem.mem[(i[7 : 0] + 4)], dut.exponent_mem.mem[(i[7 : 0] + 5)], 410 | dut.exponent_mem.mem[(i[7 : 0] + 6)], dut.exponent_mem.mem[(i[7 : 0] + 7)], 411 | ); 412 | end 413 | $display(""); 414 | end 415 | endtask // dump_exponent_mem 416 | 417 | 418 | //---------------------------------------------------------------- 419 | // dump_modulus_mem() 420 | // 421 | // Dump the contents of the modulus memory. 422 | //---------------------------------------------------------------- 423 | task dump_modulus_mem(); 424 | reg [8 : 0] i; 425 | begin 426 | $display("Contents of the modulus memory:"); 427 | for (i = 0 ; i < 256 ; i = i + 8) 428 | begin 429 | $display("modulus_mem[0x%02x .. 0x%02x] = 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", 430 | i[7 : 0], (i[7 : 0] + 8'h07), 431 | dut.modulus_mem.mem[(i[7 : 0] + 0)], dut.modulus_mem.mem[(i[7 : 0] + 1)], 432 | dut.modulus_mem.mem[(i[7 : 0] + 2)], dut.modulus_mem.mem[(i[7 : 0] + 3)], 433 | dut.modulus_mem.mem[(i[7 : 0] + 4)], dut.modulus_mem.mem[(i[7 : 0] + 5)], 434 | dut.modulus_mem.mem[(i[7 : 0] + 6)], dut.modulus_mem.mem[(i[7 : 0] + 7)], 435 | ); 436 | end 437 | $display(""); 438 | end 439 | endtask // dump_modulus_mem 440 | 441 | 442 | //---------------------------------------------------------------- 443 | // dump_residue_mem() 444 | // 445 | // Dump the contents of the residue memory. 446 | //---------------------------------------------------------------- 447 | task dump_residue_mem(); 448 | reg [8 : 0] i; 449 | begin 450 | $display("Contents of the residue memory:"); 451 | for (i = 0 ; i < 256 ; i = i + 8) 452 | begin 453 | $display("residue_mem[0x%02x .. 0x%02x] = 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", 454 | i[7 : 0], (i[7 : 0] + 8'h07), 455 | dut.residue_mem.mem[(i[7 : 0] + 0)], dut.residue_mem.mem[(i[7 : 0] + 1)], 456 | dut.residue_mem.mem[(i[7 : 0] + 2)], dut.residue_mem.mem[(i[7 : 0] + 3)], 457 | dut.residue_mem.mem[(i[7 : 0] + 4)], dut.residue_mem.mem[(i[7 : 0] + 5)], 458 | dut.residue_mem.mem[(i[7 : 0] + 6)], dut.residue_mem.mem[(i[7 : 0] + 7)], 459 | ); 460 | end 461 | $display(""); 462 | end 463 | endtask // dump_residue_mem 464 | 465 | 466 | //---------------------------------------------------------------- 467 | // dump_result_mem() 468 | // 469 | // Dump the contents of the result memory. 470 | //---------------------------------------------------------------- 471 | task dump_result_mem(); 472 | reg [8 : 0] i; 473 | begin 474 | $display("Contents of the result memory:"); 475 | for (i = 0 ; i < 256 ; i = i + 8) 476 | begin 477 | $display("result_mem[0x%02x .. 0x%02x] = 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x", 478 | i[7 : 0], (i[7 : 0] + 8'h07), 479 | dut.result_mem.mem[(i[7 : 0] + 0)], dut.result_mem.mem[(i[7 : 0] + 1)], 480 | dut.result_mem.mem[(i[7 : 0] + 2)], dut.result_mem.mem[(i[7 : 0] + 3)], 481 | dut.result_mem.mem[(i[7 : 0] + 4)], dut.result_mem.mem[(i[7 : 0] + 5)], 482 | dut.result_mem.mem[(i[7 : 0] + 6)], dut.result_mem.mem[(i[7 : 0] + 7)], 483 | ); 484 | end 485 | $display(""); 486 | end 487 | endtask // dump_result_mem 488 | 489 | 490 | //---------------------------------------------------------------- 491 | // dump_memories() 492 | // 493 | // Dump the contents of the memories in the dut. 494 | //---------------------------------------------------------------- 495 | task dump_memories(); 496 | begin 497 | dump_message_mem(); 498 | dump_exponent_mem(); 499 | dump_modulus_mem(); 500 | dump_residue_mem(); 501 | dump_result_mem(); 502 | end 503 | endtask // dump_memories 504 | 505 | function assertEquals( 506 | input [31:0] expected, 507 | input [31:0] actual 508 | ); 509 | begin 510 | if (expected === actual) 511 | begin 512 | assertEquals = 1; // success 513 | end 514 | else 515 | begin 516 | $display("Expected: 0x%08x, got 0x%08x", expected, actual); 517 | assertEquals = 0; // failure 518 | end 519 | end 520 | endfunction // assertEquals 521 | 522 | integer success; 523 | 524 | // ===TEMPLATE_HEADER_END=== 525 | 526 | task TEMPLATE_TASK_NAME(); 527 | reg [31 : 0] read_data; 528 | begin 529 | success = 32'h1; 530 | tc_ctr = tc_ctr + 1; 531 | $display("TEMPLATE_TASK_NAME"); 532 | 533 | write_word({MESSAGE_PREFIX, 8'h#TI#}, 32'h#TD#); //TEMPLATE_MESSAGE_VALUES 534 | write_word({EXPONENT_PREFIX, 8'h#TI#}, 32'h#TD#); //TEMPLATE_EXPONENT_VALUES 535 | write_word({MODULUS_PREFIX, 8'h#TI#}, 32'h#TD#); //TEMPLATE_MODULUS_VALUES 536 | 537 | write_word({GENERAL_PREFIX, ADDR_EXPONENT_LENGTH}, 32'h#TL#); //TEMPLATE_MESSAGE_LENGTH 538 | write_word({GENERAL_PREFIX, ADDR_MODULUS_LENGTH}, 32'h#TL#); //TEMPLATE_MODULUS_LENGTH 539 | write_word({GENERAL_PREFIX, ADDR_LENGTH}, 32'h#TL#); //TEMPLATE_MODULUS_LENGTH 540 | 541 | start_test_cycle_ctr(); 542 | 543 | stop_test_cycle_ctr(); 544 | 545 | // Start processing and wait for ready. 546 | write_word({GENERAL_PREFIX, ADDR_CTRL}, 32'h00000001); 547 | wait_ready(); 548 | 549 | read_word({RESULT_PREFIX, 8'h#TI#}); read_data = tb_read_data; success = success & assertEquals(32'h#TD#, read_data); //TEMPLATE_EXPECTED_VALUES 550 | 551 | if (success !== 1) 552 | begin 553 | $display("*** ERROR: TEMPLATE_TASK_NAME was NOT successful."); 554 | error_ctr = error_ctr + 1; 555 | end 556 | else 557 | $display("*** TEMPLATE_TASK_NAME success."); 558 | end 559 | endtask // TEMPLATE_TASK_NAME 560 | 561 | 562 | // ===TEMPLATE_TEST_DEFINITION_END=== 563 | 564 | //---------------------------------------------------------------- 565 | // main 566 | // 567 | // The main test functionality. 568 | //---------------------------------------------------------------- 569 | initial 570 | begin : main 571 | 572 | $display(" -= Testbench for modexp started =-"); 573 | $display(" ================================="); 574 | $display(""); 575 | 576 | init_sim(); 577 | dump_dut_state(); 578 | reset_dut(); 579 | dump_dut_state(); 580 | 581 | // ===TEMPLATE_CALL_TASKS=== 582 | 583 | display_test_results(); 584 | 585 | $display(""); 586 | $display("*** modexp simulation done. ***"); 587 | $finish; 588 | end // main 589 | endmodule // tb_modexp 590 | 591 | //====================================================================== 592 | // EOF tb_modexp.v 593 | //====================================================================== 594 | -------------------------------------------------------------------------------- /src/tb/tb_montprod.v: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // tb_montprod.v 4 | // ------------- 5 | // Testbench for the montgomery product module. 6 | // 7 | // 8 | // Author: Peter Magnusson, Joachim Strombergson 9 | // Copyright (c) 2014, Assured AB 10 | // All rights reserved. 11 | // 12 | // Redistribution and use in source and binary forms, with or 13 | // without modification, are permitted provided that the following 14 | // conditions are met: 15 | // 16 | // 1. Redistributions of source code must retain the above copyright 17 | // notice, this list of conditions and the following disclaimer. 18 | // 19 | // 2. Redistributions in binary form must reproduce the above copyright 20 | // notice, this list of conditions and the following disclaimer in 21 | // the documentation and/or other materials provided with the 22 | // distribution. 23 | // 24 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 33 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 35 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | // 37 | //====================================================================== 38 | 39 | //------------------------------------------------------------------ 40 | // Simulator directives. 41 | //------------------------------------------------------------------ 42 | `timescale 1ns/100ps 43 | 44 | //------------------------------------------------------------------ 45 | // Test module. 46 | //------------------------------------------------------------------ 47 | 48 | module tb_montprod(); 49 | 50 | //---------------------------------------------------------------- 51 | // Internal constant and parameter definitions. 52 | //---------------------------------------------------------------- 53 | parameter SHOW_INIT = 0; 54 | 55 | parameter DUMP_MEM = 0; 56 | parameter DEBUG = 0; 57 | parameter CLK_HALF_PERIOD = 2; 58 | parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD; 59 | 60 | 61 | //---------------------------------------------------------------- 62 | // Register and Wire declarations. 63 | //---------------------------------------------------------------- 64 | 65 | reg tb_clk; 66 | reg tb_reset_n; 67 | reg tb_calculate; 68 | wire tb_ready; 69 | reg [ 7 : 0] tb_length; 70 | wire [ 7 : 0] tb_opa_addr; 71 | reg [31 : 0] tb_opa_data; 72 | wire [ 7 : 0] tb_opb_addr; 73 | reg [31 : 0] tb_opb_data; 74 | wire [ 7 : 0] tb_opm_addr; 75 | reg [31 : 0] tb_opm_data; 76 | wire [ 7 : 0] tb_result_addr; 77 | wire [31 : 0] tb_result_data; 78 | wire tb_result_we; 79 | 80 | reg [31 : 0] tb_a [0 : 255]; //tb_opa_data 81 | reg [31 : 0] tb_b [0 : 255]; //tb_opb_data reads here 82 | reg [31 : 0] tb_m [0 : 255]; //tb_opm_data reads here 83 | reg [31 : 0] tb_r [0 : 255]; //tb_result_data writes here 84 | 85 | reg monitor_s; 86 | 87 | integer test_mont_prod_success; 88 | integer test_mont_prod_fail; 89 | 90 | //---------------------------------------------------------------- 91 | // Device Under Test. 92 | //---------------------------------------------------------------- 93 | 94 | montprod dut( 95 | .clk(tb_clk), 96 | .reset_n(tb_reset_n), 97 | .length(tb_length), 98 | .calculate(tb_calculate), 99 | .ready(tb_ready), 100 | .opa_addr(tb_opa_addr), 101 | .opa_data(tb_opa_data), 102 | .opb_addr(tb_opb_addr), 103 | .opb_data(tb_opb_data), 104 | .opm_addr(tb_opm_addr), 105 | .opm_data(tb_opm_data), 106 | .result_addr(tb_result_addr), 107 | .result_data(tb_result_data), 108 | .result_we(tb_result_we) 109 | ); 110 | 111 | always @(posedge tb_clk) 112 | begin : read_test_memory 113 | tb_opa_data <= tb_a[tb_opa_addr]; 114 | tb_opb_data <= tb_b[tb_opb_addr]; 115 | tb_opm_data <= tb_m[tb_opm_addr]; 116 | 117 | if (DUMP_MEM) 118 | $display("a %x %x b %x %x m %x %x", tb_opa_addr, tb_a[tb_opa_addr], tb_opb_addr, tb_b[tb_opb_addr], tb_opm_addr, tb_m[tb_opm_addr]); 119 | end 120 | 121 | always @* 122 | begin : write_test_memory 123 | if (tb_result_we == 1'b1) 124 | begin 125 | $display("write %d: %x", tb_result_addr, tb_result_data); 126 | tb_r[tb_result_addr] = tb_result_data; 127 | end 128 | end 129 | 130 | 131 | //---------------------------------------------------------------- 132 | // clk_gen 133 | // 134 | // Clock generator process. 135 | //---------------------------------------------------------------- 136 | always 137 | begin : clk_gen 138 | #CLK_HALF_PERIOD tb_clk = !tb_clk; 139 | end // clk_gen 140 | 141 | 142 | //---------------------------------------------------------------- 143 | // S monitor 144 | //---------------------------------------------------------------- 145 | always @ (posedge tb_clk) 146 | begin : s_monitor 147 | if (monitor_s) 148 | $display("S[ 0 ]: %x", dut.s_mem.mem[0] ); 149 | end 150 | 151 | 152 | 153 | //---------------------------------------------------------------- 154 | // S monitor 155 | //---------------------------------------------------------------- 156 | always @ (posedge tb_clk) 157 | begin : s_write_minitor 158 | if (monitor_s) 159 | if (dut.s_mem_we) 160 | $display("Write to S[0x%02x]: 0x%08x", dut.s_mem_wr_addr, dut.s_mem_new); 161 | end 162 | 163 | 164 | 165 | //---------------------------------------------------------------- 166 | //---------------------------------------------------------------- 167 | always @ (posedge tb_clk) 168 | begin : bq_debug 169 | if (dut.montprod_ctrl_reg == dut.CTRL_L_CALC_SM) 170 | $display("====================> B: %x Q: %x B_bit_index_reg: %x <=====================", dut.b_reg, dut.q_reg, dut.B_bit_index_reg); 171 | end 172 | 173 | //case (montprod_ctrl_reg) 174 | // CTRL_LOOP_BQ: 175 | // $display("DEBUG: b: %d q: %d opa_data %x opb_data %x s_mem_read_data %x", b, q, opa_addr_reg, opa_data, opb_data, s_mem_read_data); 176 | // default: 177 | // begin end 178 | //endcase 179 | 180 | //---------------------------------------------------------------- 181 | //---------------------------------------------------------------- 182 | always @ (posedge tb_clk) 183 | begin : fsm_debug 184 | if (dut.montprod_ctrl_we) 185 | case (dut.montprod_ctrl_new) 186 | dut.CTRL_IDLE: 187 | $display("FSM: IDLE"); 188 | dut.CTRL_INIT_S: 189 | $display("FSM: INIT_S"); 190 | dut.CTRL_LOOP_INIT: 191 | $display("FSM: LOOP_INIT"); 192 | dut.CTRL_LOOP_ITER: 193 | $display("FSM: LOOP_ITER"); 194 | dut.CTRL_LOOP_BQ: 195 | $display("FSM: LOOP_BQ"); 196 | dut.CTRL_L_CALC_SM: 197 | $display("FSM: LOOP_CALC_SM"); 198 | dut.CTRL_L_CALC_SA: 199 | $display("FSM: LOOP_CALC_SA"); 200 | dut.CTRL_L_STALLPIPE_SA: 201 | $display("FSM: STALL_PIPE"); 202 | dut.CTRL_L_CALC_SDIV2: 203 | $display("FSM: LOOP_CALC_SDIV2"); 204 | dut.CTRL_EMIT_S: 205 | $display("FSM: LOOP_EMIT_S"); 206 | dut.CTRL_DONE: 207 | $display("FSM: DONE"); 208 | default: 209 | $display("FSM: %x", dut.montprod_ctrl_new); 210 | endcase 211 | end 212 | 213 | 214 | //---------------------------------------------------------------- 215 | // reset_dut() 216 | // 217 | // Toggles reset to force the DUT into a well defined state. 218 | //---------------------------------------------------------------- 219 | task reset_dut(); 220 | begin 221 | $display("*** Toggle reset."); 222 | tb_reset_n = 0; 223 | #(2 * CLK_PERIOD); 224 | tb_reset_n = 1; 225 | end 226 | endtask // reset_dut 227 | 228 | //---------------------------------------------------------------- 229 | // init_sim() 230 | // 231 | // Initialize all counters and testbed functionality as well 232 | // as setting the DUT inputs to defined values. 233 | //---------------------------------------------------------------- 234 | task init_sim(); 235 | begin 236 | $display("*** init_sim"); 237 | tb_clk = 0; 238 | tb_reset_n = 0; 239 | tb_length = 0; 240 | tb_calculate = 0; 241 | monitor_s = 1; 242 | test_mont_prod_success = 0; 243 | test_mont_prod_fail = 0; 244 | end 245 | endtask // init_dut 246 | 247 | //---------------------------------------------------------------- 248 | // wait_ready() 249 | // 250 | // Wait for the ready flag in the dut to be set. 251 | // 252 | // Note: It is the callers responsibility to call the function 253 | // when the dut is actively processing and will in fact at some 254 | // point set the flag. 255 | //---------------------------------------------------------------- 256 | task wait_ready(); 257 | begin 258 | $display("*** wait_ready"); 259 | begin: wait_loop 260 | integer i; 261 | for (i=0; i<1000000; i=i+1) 262 | if (tb_ready == 0) 263 | #(CLK_PERIOD); 264 | end 265 | if (tb_ready == 0) 266 | begin 267 | $display("*** wait_ready failed, never became ready!"); 268 | $finish; 269 | end 270 | end 271 | endtask // wait_ready 272 | 273 | //---------------------------------------------------------------- 274 | //---------------------------------------------------------------- 275 | task signal_calculate(); 276 | begin 277 | $display("*** signal_calculate"); 278 | tb_calculate = 1; 279 | #(CLK_PERIOD); 280 | tb_calculate = 0; 281 | end 282 | endtask // signal_calculate 283 | 284 | 285 | //---------------------------------------------------------------- 286 | // Tests the montgomery multiplications 287 | //---------------------------------------------------------------- 288 | task test_mont_prod( 289 | input [7 : 0] length, 290 | input [0 : 8192-1] a, 291 | input [0 : 8192-1] b, 292 | input [0 : 8192-1] m, 293 | input [0 : 8192-1] expected 294 | ); 295 | begin 296 | $display("*** test started"); 297 | begin: copy_test_vectors 298 | integer i; 299 | integer j; 300 | 301 | $display("*** Initializing..."); 302 | for (i=32'h0; i<256; i=i+1) 303 | begin 304 | j = {i, 5'h0}; 305 | tb_a[i] = a[j +: 32]; 306 | tb_b[i] = b[j +: 32]; 307 | tb_m[i] = m[j +: 32]; 308 | tb_r[i] = 32'h0; 309 | if (SHOW_INIT) 310 | $display("*** init %0x: a: %x b: %x m: %x r: %x", i, tb_a[i], tb_b[i], tb_m[i], tb_r[i]); 311 | end 312 | end 313 | 314 | $display("*** Test vector copied"); 315 | wait_ready(); 316 | tb_length = length; 317 | signal_calculate(); 318 | wait_ready(); 319 | begin: verify_test_vectors 320 | integer i; 321 | integer j; 322 | integer success; 323 | integer fail; 324 | success = 1; 325 | fail = 0; 326 | for (i=0; i 0 0 1 385 | //debug B => 0 0 4000 386 | //debug M => 1ffffff ffffffff ffffffff 387 | //debug s => 0 0 80 388 | test_mont_prod( 3, {96'h1, 8096'h0}, {96'h4000, 8096'h0}, {96'h1ffffffffffffffffffffff,8096'h0}, {96'h80,8096'h0} ); 389 | 390 | //debug A => 00000000 098b0437 ae647838 09d930b9 a1d269d5 03579a63 9c4e3ac5 fd070836 413389c2 321cfe8b a6a5732e bc7cbcf8 a2f1df87 19f7a767 43ef9b5d 6bd33597 23bfc574 8ec046da 5419d7ff 31811123 740b227b 709f3ace e53ba5cc 38cbc161 a0c15c88 64f26a18 423692ef a5e52a20 80d9f244 717aa2d5 e1a6680a b29eed64 57c6b005 391 | //debug B => 00000000 098b0437 ae647838 09d930b9 a1d269d5 03579a63 9c4e3ac5 fd070836 413389c2 321cfe8b a6a5732e bc7cbcf8 a2f1df87 19f7a767 43ef9b5d 6bd33597 23bfc574 8ec046da 5419d7ff 31811123 740b227b 709f3ace e53ba5cc 38cbc161 a0c15c88 64f26a18 423692ef a5e52a20 80d9f244 717aa2d5 e1a6680a b29eed64 57c6b005 392 | //debug M => 00000000 f14b5a0a 122ff247 85813db2 02c0d3af bd0a4615 2889ff7d 8f655e9e c866e586 f21003a0 e969769b 127ec8a5 67f07708 217775f7 7654cabc 3a624f9b 4074bdf1 55fa84c0 0354fe59 0ad04cfd 14e666c0 ce6cea72 788c31f4 edcf3dd7 3a5a59c1 b9b3ef41 565df033 69a82de8 f18c2793 0abd5502 f3730ec0 d1943dc4 a660a267 393 | //debug s => 00000000 0a8a4a44 40e5c3b0 a05383c2 4ad92fc9 0af7b72e d22fa180 f3a99e64 38ffbe72 3854bc5e 93fffa55 ce49b2cf f809c9eb 81176d8b 4f8b942c 3de18f9c 6393a70a 89924a58 5684cb90 acfd1bde b408b2c0 a8d862c1 74b5a10d 90532d4e 79fe2f50 430decda 0ed75e0a ac354c46 69ce0bd8 eb36e857 b55623d1 527b9711 86cd4d75 394 | 395 | test_mont_prod( 396 | 33, 397 | { 1056'h098b0437ae64783809d930b9a1d269d503579a639c4e3ac5fd070836413389c2321cfe8ba6a5732ebc7cbcf8a2f1df8719f7a76743ef9b5d6bd3359723bfc5748ec046da5419d7ff31811123740b227b709f3acee53ba5cc38cbc161a0c15c8864f26a18423692efa5e52a2080d9f244717aa2d5e1a6680ab29eed6457c6b005 398 | , 7136'h0 }, 399 | { 1056'h098b0437ae64783809d930b9a1d269d503579a639c4e3ac5fd070836413389c2321cfe8ba6a5732ebc7cbcf8a2f1df8719f7a76743ef9b5d6bd3359723bfc5748ec046da5419d7ff31811123740b227b709f3acee53ba5cc38cbc161a0c15c8864f26a18423692efa5e52a2080d9f244717aa2d5e1a6680ab29eed6457c6b005 400 | , 7136'h0 }, 401 | {1056'hf14b5a0a122ff24785813db202c0d3afbd0a46152889ff7d8f655e9ec866e586f21003a0e969769b127ec8a567f07708217775f77654cabc3a624f9b4074bdf155fa84c00354fe590ad04cfd14e666c0ce6cea72788c31f4edcf3dd73a5a59c1b9b3ef41565df03369a82de8f18c27930abd5502f3730ec0d1943dc4a660a267 402 | , 7136'h0 }, 403 | {1056'h0a8a4a4440e5c3b0a05383c24ad92fc90af7b72ed22fa180f3a99e6438ffbe723854bc5e93fffa55ce49b2cff809c9eb81176d8b4f8b942c3de18f9c6393a70a89924a585684cb90acfd1bdeb408b2c0a8d862c174b5a10d90532d4e79fe2f50430decda0ed75e0aac354c4669ce0bd8eb36e857b55623d1527b971186cd4d75 404 | , 7136'h0 }); 405 | 406 | $display(" -- Testbench for montprod done. --"); 407 | $display(" tests success: %d", test_mont_prod_success); 408 | $display(" tests failed: %d", test_mont_prod_fail); 409 | $finish; 410 | end // montprod 411 | endmodule // tb_montprod 412 | 413 | //====================================================================== 414 | // EOF tb_montprod.v 415 | //====================================================================== 416 | -------------------------------------------------------------------------------- /src/testgenerator/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/testgenerator/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | -------------------------------------------------------------------------------- /src/testgenerator/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | TestGenerator 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.jdt.core.javanature 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/testgenerator/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=1.7 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 11 | org.eclipse.jdt.core.compiler.source=1.7 12 | -------------------------------------------------------------------------------- /src/testgenerator/src/org/crypttech/modexp/testgenerator/TestGenerator.java: -------------------------------------------------------------------------------- 1 | package org.crypttech.modexp.testgenerator; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | import org.crypttech.modexp.testgenerator.format.GeneratorC; 7 | import org.crypttech.modexp.testgenerator.format.GeneratorVerilog; 8 | import org.crypttech.modexp.testgenerator.format.ModExpTestFormater; 9 | 10 | public class TestGenerator { 11 | public static void main(String[] argv) throws Exception { 12 | String basePath; 13 | if (argv.length == 1) 14 | basePath = argv[0]; 15 | else 16 | basePath = ".."; 17 | 18 | System.out.println("Generating modexp test values."); 19 | 20 | List vectors = new ArrayList(); 21 | vectors.addAll(TestGeneratorRSA.getTestVectors()); 22 | vectors.addAll(TestGenerator65537.getTestVectors()); 23 | vectors.addAll(TestGeneratorBasic.getTestVectors()); 24 | try (GeneratorC genC = new GeneratorC( 25 | basePath + "/model/c/src/autogenerated_tests.c")) { 26 | try (GeneratorVerilog genVerilog = new GeneratorVerilog( 27 | basePath + "/tb/tb_modexp_autogenerated_template.v", 28 | basePath + "/tb/tb_modexp_autogenerated.v")) { 29 | 30 | emitTests(vectors, genC, genVerilog); 31 | } 32 | } 33 | 34 | } 35 | 36 | private static void emitTests(List vectors, 37 | ModExpTestFormater... generators) { 38 | for (ModExpTestFormater generator : generators) 39 | for (TestVector vector : vectors) 40 | generator.format(vector); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/testgenerator/src/org/crypttech/modexp/testgenerator/TestGenerator65537.java: -------------------------------------------------------------------------------- 1 | package org.crypttech.modexp.testgenerator; 2 | 3 | import java.math.BigInteger; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.Random; 7 | 8 | 9 | public class TestGenerator65537 { 10 | 11 | public static final List getTestVectors() { 12 | Random rng = new Random(0); //any static seed 13 | ArrayList list = new ArrayList(); 14 | int[] sizes = { 64, 128, 256, 512, 1024, 2048 }; 15 | for (int size : sizes) 16 | generateTestVectors(rng, list, size, (size/32)+1, 3); //+1 because model requires leading zeros currently 17 | return list; 18 | } 19 | 20 | private static void generateTestVectors(Random rng, 21 | ArrayList list, int bitLength, int wordLength, int max) { 22 | for(int i = 0; i < max; i++) { 23 | final long seed = rng.nextLong(); 24 | rng.setSeed(seed); 25 | BigInteger m = BigInteger.probablePrime(bitLength, rng); 26 | BigInteger x = BigInteger.probablePrime(bitLength, rng); 27 | BigInteger e = new BigInteger("65537"); 28 | BigInteger z = x.modPow(e, m); 29 | TestVector tv = Util.generateTestVector("65537_"+bitLength, Long.toString(seed), wordLength, m, x, e, z); 30 | list.add(tv); 31 | System.out.printf("%s Generated test: bits: %d seed: %d\n", TestGenerator65537.class.getName(), bitLength, seed); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/testgenerator/src/org/crypttech/modexp/testgenerator/TestGeneratorBasic.java: -------------------------------------------------------------------------------- 1 | package org.crypttech.modexp.testgenerator; 2 | 3 | import java.math.BigInteger; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.Random; 7 | 8 | public class TestGeneratorBasic { 9 | public static final List getTestVectors() { 10 | Random rng = new Random(0); //any static seed 11 | ArrayList list = new ArrayList(); 12 | 13 | generateTestVectors(rng, list, 33, 2); 14 | generateTestVectors(rng, list, 30, 1); 15 | //generateTestVectors(rng, list, 32, 1); //will generate failing tests in C model 16 | //generateTestVectors(rng, list, 31, 1); //will generate failing tests in C model 17 | generateTestVectors(rng, list, 126, 4); 18 | generateTestVectors(rng, list, 510, 16, 2); 19 | generateTestVectors(rng, list, 1022, 32, 1); 20 | generateTestVectors(rng, list, 2046, 64, 1); 21 | return list; 22 | } 23 | 24 | private static void generateTestVectors(Random rng, 25 | ArrayList list, int bitLength, int wordLength) { 26 | int max = 10; 27 | generateTestVectors(rng, list, bitLength, wordLength, max); 28 | } 29 | 30 | private static void generateTestVectors(Random rng, 31 | ArrayList list, int bitLength, int wordLength, int max) { 32 | for(int i = 0; i < max; i++) { 33 | final long seed = rng.nextLong(); 34 | rng.setSeed(seed); 35 | BigInteger m = BigInteger.probablePrime(bitLength, rng); 36 | BigInteger x = BigInteger.probablePrime(bitLength, rng); 37 | BigInteger e = BigInteger.probablePrime(bitLength, rng); 38 | BigInteger z = x.modPow(e, m); 39 | TestVector tv = Util.generateTestVector("BASIC_"+bitLength, Long.toString(seed), wordLength, m, x, e, z); 40 | list.add(tv); 41 | System.out.printf("%s Generated test: bits: %d seed: %d\n", TestGeneratorBasic.class.getName(), bitLength, seed); 42 | } 43 | } 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/testgenerator/src/org/crypttech/modexp/testgenerator/TestGeneratorRSA.java: -------------------------------------------------------------------------------- 1 | package org.crypttech.modexp.testgenerator; 2 | 3 | import java.math.BigInteger; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import java.util.Random; 7 | 8 | public class TestGeneratorRSA { 9 | 10 | private static final BigInteger ONE = new BigInteger("1"); 11 | 12 | public static final List getTestVectors() { 13 | Random rng = new Random(0); // any static seed 14 | ArrayList list = new ArrayList(); 15 | int[] sizes = { 64, 128, 256, 512, 1024 }; 16 | for (int size : sizes) 17 | generateTestVectors(rng, list, size, ((size*2) / 32) + 1, 1); 18 | return list; 19 | } 20 | 21 | private static void generateTestVectors(Random rng, 22 | ArrayList list, int bitLength, int wordLength, int max) { 23 | for (int i = 0; i < max; i++) { 24 | final long seed = rng.nextLong(); 25 | rng.setSeed(seed); 26 | // Choose two distinct prime numbers p and q. 27 | BigInteger p = BigInteger.probablePrime(bitLength, rng); 28 | BigInteger q = BigInteger.probablePrime(bitLength, rng); 29 | // Compute n = pq. 30 | BigInteger n = p.multiply(q); 31 | // Compute φ(n) = φ(p)φ(q) = (p − 1)(q − 1) = n - (p + q -1) 32 | BigInteger φ = n.subtract(p.add(q).subtract(ONE)); 33 | // Choose an integer e such that 1 < e < φ(n) and gcd(e, φ(n)) = 1; 34 | // i.e., e and φ(n) are coprime. 35 | BigInteger e = new BigInteger("65537"); 36 | if (! ONE.equals(e.gcd(φ))) { 37 | throw new RuntimeException("Warning: The world is on fire! Invalid RSA non-coprime e,φ detected by GCD. Continuing would generate an illegal secret key."); 38 | } 39 | // Determine d as d ≡ e−1 (mod φ(n)); i.e., d is the modular 40 | // multiplicative inverse of e (modulo φ(n)). 41 | BigInteger d = e.modInverse(φ); 42 | 43 | BigInteger x = BigInteger.probablePrime(bitLength*2-4, rng); 44 | BigInteger z = x.modPow(e, n); 45 | TestVector tv = Util.generateTestVector("RSA_ENCRYPT_2x" 46 | + bitLength, Long.toString(seed), wordLength, n, x, e, z); 47 | list.add(tv); 48 | System.out.printf( 49 | "%s Generated rsa encrypt test: bits: %d seed: %d\n", 50 | TestGeneratorRSA.class.getName(), bitLength, seed); 51 | 52 | TestVector tv2 = Util.generateTestVector("RSA_DECRYPT_2x" 53 | + bitLength, Long.toString(seed), wordLength, n, z, d, x); 54 | list.add(tv2); 55 | System.out.printf( 56 | "%s Generated rsa decrypt test: bits: %d seed: %d\n", 57 | TestGeneratorRSA.class.getName(), bitLength, seed); 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/testgenerator/src/org/crypttech/modexp/testgenerator/TestVector.java: -------------------------------------------------------------------------------- 1 | package org.crypttech.modexp.testgenerator; 2 | 3 | public class TestVector { 4 | public final String generator; 5 | public final String seed; 6 | public final int length; 7 | public final int[] X; 8 | public final int[] E; 9 | public final int[] M; 10 | public final int[] expected; 11 | 12 | public TestVector(String generator, String seed, int length, int[] x, 13 | int[] e, int[] m, int[] expected) { 14 | super(); 15 | this.generator = generator; 16 | this.seed = seed; 17 | this.length = length; 18 | X = x; 19 | E = e; 20 | M = m; 21 | this.expected = expected; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/testgenerator/src/org/crypttech/modexp/testgenerator/Util.java: -------------------------------------------------------------------------------- 1 | package org.crypttech.modexp.testgenerator; 2 | 3 | import java.math.BigInteger; 4 | 5 | public class Util { 6 | public static TestVector generateTestVector(String generator, String seed, int length, 7 | BigInteger m, BigInteger x, BigInteger e, BigInteger z) { 8 | //System.out.printf("%s %s %s %s\n", m.toString(16), x.toString(16), e.toString(16), z.toString(16)); 9 | int[] mi = toInt(length, m); 10 | int[] xi = toInt(length, x); 11 | int[] ei = toInt(length, e); 12 | int[] zi = toInt(length, z); 13 | return new TestVector(generator, seed, length, xi, ei, mi, zi); 14 | } 15 | 16 | 17 | public static int[] toInt(int length, BigInteger bi) { 18 | byte[] ba = bi.toByteArray(); 19 | int[] ia = new int[length]; 20 | for (int j = ba.length-1; j >= 0; j--) { 21 | int changeByte = ((ba.length-1-j)%4); 22 | int jj = length -1 - (ba.length-1-j)/4; 23 | ia[jj] |= (ba[j] & 0xff) << (changeByte*8); 24 | } 25 | return ia; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/testgenerator/src/org/crypttech/modexp/testgenerator/format/GeneratorC.java: -------------------------------------------------------------------------------- 1 | package org.crypttech.modexp.testgenerator.format; 2 | 3 | import java.io.FileNotFoundException; 4 | import java.io.PrintWriter; 5 | 6 | import org.crypttech.modexp.testgenerator.TestVector; 7 | 8 | public class GeneratorC extends ModExpTestFormater { 9 | public GeneratorC(String file) throws FileNotFoundException { 10 | super(new PrintWriter(file), true); 11 | out("#include "); 12 | out("#include "); 13 | out("#include \"montgomery_array.h\""); 14 | out("#include \"bignum_uint32_t.h\""); 15 | } 16 | 17 | StringBuilder footer = new StringBuilder(); 18 | 19 | @Override 20 | public void format(TestVector testVector) { 21 | String testname = ("autogenerated_" + testVector.generator + "_" + testVector.seed) 22 | .replace("-", "M"); 23 | footer.append(" ").append(testname).append("();").append((char) 10); 24 | 25 | out("void %s(void) {", testname); 26 | out(" printf(\"=== %s ===\\n\");", testname); 27 | appendCArray("X", testVector.X); 28 | appendCArray("E", testVector.E); 29 | appendCArray("M", testVector.M); 30 | appendCArray("expected", testVector.expected); 31 | int[] Z = new int[testVector.length]; 32 | appendCArray("Z", Z); 33 | out(" mod_exp_array(%s, X, E, M, Z);", testVector.length); 34 | out(" assertArrayEquals(%d, expected, Z);", testVector.length); 35 | out("}"); 36 | } 37 | 38 | private void appendCArray(String arrayName, int[] array) { 39 | StringBuilder sb = new StringBuilder(); 40 | sb.append(" uint32_t ").append(arrayName).append("[] = "); 41 | sb.append("{ "); 42 | for (int m : array) 43 | sb.append(String.format("0x%08x, ", m)); 44 | sb.replace(sb.length() - 2, sb.length(), " };"); 45 | out(sb.toString()); 46 | } 47 | 48 | @Override 49 | public void close() throws Exception { 50 | out("void autogenerated_tests(void) {"); 51 | out(footer.toString()); 52 | out("}"); 53 | super.close(); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/testgenerator/src/org/crypttech/modexp/testgenerator/format/GeneratorVerilog.java: -------------------------------------------------------------------------------- 1 | package org.crypttech.modexp.testgenerator.format; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.IOException; 7 | import java.io.InputStreamReader; 8 | import java.io.PrintWriter; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import org.crypttech.modexp.testgenerator.TestVector; 13 | 14 | public class GeneratorVerilog extends ModExpTestFormater { 15 | private BufferedReader br; 16 | private List taskCalls = new ArrayList(); 17 | private boolean initilized = false; 18 | private List taskTemplate = new ArrayList(); 19 | 20 | public GeneratorVerilog(String templateFile, String destinationFile) 21 | throws FileNotFoundException { 22 | super(new PrintWriter(destinationFile), true); 23 | this.br = new BufferedReader(new InputStreamReader(new FileInputStream( 24 | templateFile))); 25 | 26 | } 27 | 28 | @Override 29 | public void format(TestVector testVector) { 30 | init(); 31 | 32 | String testname = ("autogenerated_" + testVector.generator + "_" + testVector.seed) 33 | .replace("-", "M"); 34 | taskCalls.add(testname + "();"); 35 | 36 | for (String line : taskTemplate) { 37 | line = line.replace("TEMPLATE_TASK_NAME", testname); 38 | if (line.contains("TEMPLATE_EXPECTED_VALUES")) 39 | emitArray(line, testVector.expected); 40 | else if (line.contains("TEMPLATE_MESSAGE_VALES")) 41 | emitArray(line, testVector.X); 42 | else if (line.contains("TEMPLATE_EXPONENT_VALES")) 43 | emitArray(line, testVector.E); 44 | else if (line.contains("TEMPLATE_MODULUS_VALUES")) 45 | emitArray(line, testVector.M); 46 | else if (line.contains("TEMPLATE_EXPECTED_LENGTH")) 47 | emitLength(line, testVector.expected); 48 | else if (line.contains("TEMPLATE_MESSAGE_LENGTH")) 49 | emitLength(line, testVector.X); 50 | else if (line.contains("TEMPLATE_EXPONENT_LENGTH")) 51 | emitLength(line, testVector.E); 52 | else if (line.contains("TEMPLATE_MODULUS_LENGTH")) 53 | emitLength(line, testVector.M); 54 | else 55 | out(line); 56 | } 57 | } 58 | 59 | private void emitLength(String pattern, int[] array) { 60 | String lengthHexString = hex32(array.length); 61 | String line = pattern.replace("#TL#", lengthHexString); 62 | out(line); 63 | } 64 | 65 | private void emitArray(String pattern, int[] array) { 66 | for (int i = 0; i < array.length; i++) { 67 | String indexHexString = hex8(i); 68 | String arrayHexString = hex32(array[i]); 69 | String line = pattern.replace("#TI#", indexHexString).replace( 70 | "#TD#", arrayHexString); 71 | out(line); 72 | } 73 | } 74 | 75 | private String hex8(int data) { 76 | return String.format("%02x", data); 77 | } 78 | 79 | private String hex32(int data) { 80 | return String.format("%08x", data); 81 | } 82 | 83 | @Override 84 | public void close() throws Exception { 85 | emitMiddle(); 86 | for (String taskCall : taskCalls) 87 | out(taskCall); 88 | emitFinal(); 89 | if (br != null) 90 | br.close(); 91 | super.close(); 92 | } 93 | 94 | private void init() { 95 | if (initilized == true) 96 | return; 97 | initilized = true; 98 | emitHeader(); 99 | taskTemplate.addAll(consumeTemplate("TEMPLATE_TEST_DEFINITION_END")); 100 | } 101 | 102 | private void emitHeader() { 103 | String terminatingLine = "===TEMPLATE_HEADER_END==="; 104 | emitTemplateSection(terminatingLine); 105 | } 106 | 107 | private void emitMiddle() { 108 | String terminatingLine = "===TEMPLATE_CALL_TASKS==="; 109 | emitTemplateSection(terminatingLine); 110 | } 111 | 112 | private void emitFinal() { 113 | String terminatingLine = "Never gonna give you up, never gonna let you down"; 114 | emitTemplateSection(terminatingLine); 115 | } 116 | 117 | private void emitTemplateSection(String terminatingLine) { 118 | List lines = consumeTemplate(terminatingLine); 119 | for (String line : lines) 120 | out(line); 121 | } 122 | 123 | private List consumeTemplate(String terminatingLine) { 124 | List lines = new ArrayList(); 125 | String line; 126 | try { 127 | while ((line = br.readLine()) != null) { 128 | if (line.contains(terminatingLine)) 129 | break; 130 | lines.add(line); 131 | } 132 | } catch (IOException e) { 133 | throw new RuntimeException(e); 134 | } 135 | return lines; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/testgenerator/src/org/crypttech/modexp/testgenerator/format/ModExpTestFormater.java: -------------------------------------------------------------------------------- 1 | package org.crypttech.modexp.testgenerator.format; 2 | 3 | import java.io.PrintWriter; 4 | 5 | import org.crypttech.modexp.testgenerator.TestVector; 6 | 7 | public abstract class ModExpTestFormater implements AutoCloseable { 8 | private static final char LF = (char) 10; 9 | private final boolean alwaysLF; 10 | private final PrintWriter pw; 11 | 12 | public ModExpTestFormater(PrintWriter pw, boolean alwaysLF) { 13 | this.pw = pw; 14 | this.alwaysLF = alwaysLF; 15 | } 16 | 17 | public ModExpTestFormater(PrintWriter pw) { 18 | this(pw, false); 19 | } 20 | 21 | public abstract void format(TestVector testVector); 22 | 23 | protected final void out(String s) { 24 | pw.print(s); 25 | if (alwaysLF) 26 | pw.print(LF); 27 | } 28 | 29 | protected final void out(String frmt, Object... args) { 30 | out(String.format(frmt, args)); 31 | } 32 | 33 | @Override 34 | public void close() throws Exception { 35 | pw.close(); 36 | System.out.printf("%s closing...\n", this.getClass().getName()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /toolruns/Makefile: -------------------------------------------------------------------------------- 1 | #=================================================================== 2 | # 3 | # Makefile 4 | # -------- 5 | # Makefile for building the modular exponentiation submodules, core 6 | # and top simulations. 7 | # 8 | # 9 | # Author: Joachim Strombergson 10 | # Copyright (c) 2014, Secworks Sweden AB 11 | # All rights reserved. 12 | # 13 | # Redistribution and use in source and binary forms, with or 14 | # without modification, are permitted provided that the following 15 | # conditions are met: 16 | # 17 | # 1. Redistributions of source code must retain the above copyright 18 | # notice, this list of conditions and the following disclaimer. 19 | # 20 | # 2. Redistributions in binary form must reproduce the above copyright 21 | # notice, this list of conditions and the following disclaimer in 22 | # the documentation and/or other materials provided with the 23 | # distribution. 24 | # 25 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 28 | # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 29 | # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 30 | # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 31 | # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 32 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 34 | # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 36 | # ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | # 38 | #=================================================================== 39 | 40 | # Tools. 41 | CC = iverilog 42 | CCFLAGS = -Wall 43 | LINT = verilator 44 | LINTFLAGS = --lint-only -Wall 45 | 46 | # Sources. 47 | COMMON_SRC = ../src/rtl/adder32.v ../src/rtl/shl32.v ../src/rtl/shr32.v \ 48 | ../src/rtl/blockmem1r1w.v ../src/rtl/blockmem2r1w.v \ 49 | ../src/rtl/blockmem2r1wptr.v ../src/rtl/blockmem2rptr1w.v 50 | 51 | RESIDUE_TB = ../src/tb/tb_residue.v 52 | RESIDUE_SRC = ../src/rtl/residue.v 53 | 54 | MONTPROD_TB = ../src/tb/tb_montprod.v 55 | MONTPROD_SRC = ../src/rtl/montprod.v 56 | 57 | MODEXP_SRC=../src/rtl/modexp.v ../src/rtl/modexp_core.v $(MONTPROD_SRC) $(RESIDUE_SRC) $(COMMON_SRC) 58 | MODEXP_TB=../src/tb/tb_modexp.v 59 | MODEXP_AUTOGENERATED_TB = ../src/tb/tb_modexp_autogenerated.v 60 | 61 | 62 | # Rules. 63 | all: modexp.sim modexp.autogenerated.sim montprod.sim residue.sim 64 | 65 | 66 | modexp.sim: $(MODEXP_TB) $(MODEXP_SRC) 67 | $(CC) $(CCFLAGS) -o modexp.sim $(MODEXP_TB) $(MODEXP_SRC) 68 | 69 | modexp.autogenerated.sim: $(MODEXP_AUTOGENERATED_TB) $(MODEXP_SRC) 70 | $(CC) $(CCFLAGS) -o modexp.autogenerated.sim $(MODEXP_AUTOGENERATED_TB) $(MODEXP_SRC) 71 | 72 | montprod.sim: $(MONTPROD_TB) $(MONTPROD_SRC) $(COMMON_SRC) 73 | $(CC) $(CCFLAGS) -o montprod.sim $(MONTPROD_TB) $(MONTPROD_SRC) $(COMMON_SRC) 74 | 75 | residue.sim: $(RESIDUE_TB) $(RESIDUE_SRC) $(COMMON_SRC) 76 | $(CC) $(CCFLAGS) -o residue.sim $(RESIDUE_TB) $(RESIDUE_SRC) $(COMMON_SRC) 77 | 78 | 79 | sim-modexp: modexp.sim 80 | ./modexp.sim 81 | 82 | # run autogenerate-tests manually to renew ../src/tb/tb_montprod_autogenerated.v 83 | sim-modexp-autogenerated: modexp.autogenerated.sim 84 | ./modexp.autogenerated.sim 85 | 86 | sim-montprod: montprod.sim 87 | ./montprod.sim 88 | 89 | 90 | sim-residue: residue.sim 91 | ./residue.sim 92 | 93 | 94 | lint: 95 | @echo "Linting of montprod:" 96 | $(LINT) $(LINTFLAGS) --top-module montprod $(MONTPROD_SRC) $(COMMON_SRC) 97 | @echo "" 98 | 99 | @echo "Linting of residue:" 100 | $(LINT) $(LINTFLAGS) --top-module residue $(RESIDUE_SRC) $(COMMON_SRC) 101 | @echo "" 102 | 103 | @echo "Linting of modexp:" 104 | $(LINT) $(LINTFLAGS) --top-module modexp $(MODEXP_SRC) 105 | @echo "" 106 | 107 | 108 | autogenerate-tests: 109 | javac -cp ../src/testgenerator/src/ -d ../src/testgenerator/bin/ ../src/testgenerator/src/org/crypttech/modexp/testgenerator/TestGenerator.java 110 | java -cp ../src/testgenerator/bin/ org.crypttech.modexp.testgenerator.TestGenerator ../src 111 | 112 | run-java-model-test: 113 | javac -cp ../src/model/java/lib/junit-4.12.jar:../src/model/java/src:../src/model/java/tests -d ../src/model/java/bin -d ../src/model/java/bin ../src/model/java/test/rsa/MontgomeryArrayTest.java 114 | java -cp ../src/model/java/bin:../src/model/java/lib/junit-4.12.jar:../src/model/java/lib/hamcrest-core-1.3.jar org.junit.runner.JUnitCore rsa.MontgomeryArrayTest 115 | 116 | clean: 117 | rm -f modexp.sim 118 | rm -f modexp.autogenerated.sim 119 | rm -f montprod.sim 120 | rm -f residue.sim 121 | 122 | 123 | help: 124 | @echo "Build system for simulation of modular exponentation core" 125 | @echo "" 126 | @echo "Supported targets:" 127 | @echo "------------------" 128 | @echo "all: Build all simulation targets." 129 | @echo "lint: Lint all modules and hierarchies." 130 | @echo "modexp.sim: Build modexp simulation target." 131 | @echo "montprod.sim: Build Montgomery product simulation target." 132 | @echo "residue.sim: Build Residue calculation simulation target." 133 | @echo "sim-top: Run top level simulation." 134 | @echo "sim-montprod: Run montprod simulation." 135 | @echo "sim-residue: Run residue simulation." 136 | @echo "clean: Delete all built files." 137 | @echo "" 138 | @echo "Supported autogeneration targets:" 139 | @echo "autogenerate-tests - rebuild autogenerated tests source code" 140 | @echo "modexp.autogenerated.sim - run autogenerated test bench" 141 | @echo "sim-modexp-autogenerated - simulate autogenerated tests" 142 | 143 | #=================================================================== 144 | # EOF Makefile 145 | #=================================================================== 146 | --------------------------------------------------------------------------------