├── project ├── build.properties ├── plugins.sbt └── Version.scala ├── tester └── src │ └── main │ └── scala │ ├── ref │ ├── checksum │ │ └── crc │ │ │ ├── CrcHelper.java │ │ │ ├── Crc64.java │ │ │ ├── Main.java │ │ │ ├── Crc8.java │ │ │ ├── Crc32.java │ │ │ ├── CrcCalculator.java │ │ │ ├── AlgoParams.java │ │ │ └── Crc16.java │ ├── hash │ │ ├── SHA3.scala │ │ ├── SHA2.scala │ │ └── MD5.scala │ ├── padding │ │ └── Pad_xB_1_Ref.scala │ ├── mac │ │ └── HMAC.scala │ ├── constructor │ └── symmetric │ │ ├── Symmetric.scala │ │ └── AES.scala │ ├── cryptotest │ ├── PolynomialTester.scala │ ├── SpinalSimDESCoreTester.scala │ ├── SpinalSimTripleDESCoreTester.scala │ ├── SpinalSimMD5CoreStdTester.scala │ ├── SpinalSimSHA3CoreStdTester.scala │ ├── SpinalSimPad_xB_1_StdTester.scala │ ├── SpinalSimCRCTester.scala │ ├── SpinalSimHMACCoreStdTester.scala │ ├── SpinalSimLFSRTester.scala │ ├── SpinalSimSpongeStdTester.scala │ ├── SpinalSimKeccakFStdTester.scala │ ├── SpinalSimTwoFishCoreStdTester.scala │ ├── SpinalSimAESCoreTester.scala │ └── SpinalSimSHA2CoreStdTester.scala │ └── play │ └── Play_1.scala ├── .github └── workflows │ └── tests.yaml ├── .gitignore ├── README.md ├── LICENSE ├── crypto └── src │ └── main │ └── scala │ └── spinal │ ├── crypto │ ├── hash │ │ ├── sim │ │ │ ├── HashEngineIOsim.scala │ │ │ └── HashIOsim.scala │ │ ├── sha3 │ │ │ ├── SHA3.scala │ │ │ └── SHA3Core_Std.scala │ │ ├── md5 │ │ │ └── MD5.scala │ │ └── Hash.scala │ ├── checksum │ │ ├── sim │ │ │ └── CRCCombinationalsim.scala │ │ ├── CRCPolynomial.scala │ │ └── CRCCombinational.scala │ ├── symmetric │ │ ├── twofish │ │ │ └── Twofish.scala │ │ ├── sim │ │ │ └── SymmetricIOsim.scala │ │ ├── Symmetric.scala │ │ ├── des │ │ │ ├── TripleDESCore_Std.scala │ │ │ └── DES.scala │ │ └── aes │ │ │ └── AES.scala │ ├── padding │ │ ├── Padding.scala │ │ ├── Pad_xB_1_Std.scala │ │ └── HashPadding_Std.scala │ ├── Utils.scala │ ├── primitive │ │ └── keccak │ │ │ └── Keccak.scala │ ├── devtype │ │ └── GaloisField.scala │ └── construtor │ │ └── SpongeCore_Std.scala │ └── crypto.scala └── todo.md /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=1.6.0 2 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | addSbtPlugin("org.xerial.sbt" % "sbt-sonatype" % "2.3") 2 | -------------------------------------------------------------------------------- /project/Version.scala: -------------------------------------------------------------------------------- 1 | object CryptoVersion { 2 | 3 | val scalaCompilers = Seq("2.12.18", "2.11.12", "2.13.6") 4 | val spinal = "1.10.2a" 5 | 6 | private val version = "1.2.0" 7 | val tester = s"$version" 8 | val crypto = s"$version" 9 | } 10 | -------------------------------------------------------------------------------- /tester/src/main/scala/ref/checksum/crc/CrcHelper.java: -------------------------------------------------------------------------------- 1 | package ref.checksum.crc; 2 | 3 | 4 | public class CrcHelper { 5 | 6 | static long ReverseBits(long ul, int valueLength) 7 | { 8 | long newValue = 0; 9 | 10 | for (int i = valueLength - 1; i >= 0; i--) 11 | { 12 | newValue |= (ul & 1) << i; 13 | ul >>= 1; 14 | } 15 | 16 | return newValue; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /tester/src/main/scala/ref/hash/SHA3.scala: -------------------------------------------------------------------------------- 1 | package ref.hash 2 | 3 | import org.bouncycastle.jcajce.provider.digest.SHA3.DigestSHA3 4 | 5 | 6 | object SHA3 { 7 | def digest(sizeSha: Int)(inputString: String): Array[Byte] = { 8 | 9 | val sha3 = new DigestSHA3(sizeSha) 10 | sha3.update(inputString.getBytes("UTF-8")) 11 | 12 | return sha3.digest() 13 | } 14 | } 15 | 16 | object PlayWithSHA3 extends App { 17 | 18 | def bigIntToHex(value: Array[Byte]): String = s"0x${value.map(b => f"${b}%02X").mkString("")}" 19 | 20 | println(bigIntToHex(SHA3.digest(512)("A"))) 21 | } -------------------------------------------------------------------------------- /tester/src/main/scala/ref/hash/SHA2.scala: -------------------------------------------------------------------------------- 1 | package ref.hash 2 | 3 | 4 | import java.security.MessageDigest 5 | 6 | 7 | object SHA2 { 8 | def digest(sha: String)(inputString: String): Array[Byte] = { 9 | 10 | val md = MessageDigest.getInstance(sha) 11 | md.update(inputString.getBytes()) 12 | 13 | val digest = md.digest() 14 | 15 | return digest 16 | } 17 | } 18 | 19 | 20 | object PlayWithSHA2 extends App { 21 | 22 | def bigIntToHex(value: Array[Byte]): String = s"0x${value.map(b => f"${b}%02X").mkString("")}" 23 | 24 | println(bigIntToHex(SHA2.digest("SHA-256")("abc"))) 25 | 26 | } 27 | 28 | -------------------------------------------------------------------------------- /.github/workflows/tests.yaml: -------------------------------------------------------------------------------- 1 | # This workflow compiles the project and runs all tests. 2 | 3 | name: SpinalCrypto Tests 4 | 5 | on: 6 | push: 7 | branches: 8 | - 'master' 9 | pull_request: 10 | branches: 11 | - 'master' 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v2 20 | 21 | - name: Compile 22 | run: | 23 | sbt compile 24 | 25 | - name: Install verilator 26 | run: | 27 | sudo apt install -y verilator 28 | 29 | - name: Run tests 30 | run: | 31 | sbt test 32 | -------------------------------------------------------------------------------- /tester/src/main/scala/ref/hash/MD5.scala: -------------------------------------------------------------------------------- 1 | package ref.hash 2 | 3 | import java.security.MessageDigest 4 | 5 | 6 | object MD5 { 7 | def digest( inputString: String): Array[Byte] = { 8 | 9 | val md = MessageDigest.getInstance("MD5") 10 | md.update(inputString.getBytes()) 11 | 12 | val digest = md.digest() 13 | 14 | return digest 15 | } 16 | } 17 | 18 | 19 | object PlayWithMD5 extends App { 20 | 21 | def bigIntToHex(value: Array[Byte]): String = s"0x${value.map(b => f"${b}%02X").mkString("")}" 22 | 23 | println(bigIntToHex(MD5.digest("krayxcnxewqbnmjlwnyrgnejmwamalqqttcosijqxhsvxuusllllgcpzrygybspmpunptfdeihzbnuyseglbkuoxbzfnqgqxfea"))) 24 | } 25 | 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | *.log 3 | *.bak 4 | *.gtkw 5 | *.yaml 6 | !.github/workflows/*.yaml 7 | *.bin 8 | .DS_Store 9 | 10 | # sbt specific 11 | .cache/ 12 | .history/ 13 | .lib/ 14 | dist/* 15 | target 16 | lib_managed/ 17 | src_managed/ 18 | project/boot/ 19 | project/plugins/project/ 20 | 21 | # Scala-IDE specific 22 | .scala_dependencies 23 | .worksheet 24 | 25 | .idea 26 | out 27 | 28 | # Eclipse 29 | bin/ 30 | .classpath 31 | .project 32 | .settings 33 | .cache-main 34 | 35 | #User 36 | /*.vhd 37 | /*.v 38 | *.cf 39 | *.json 40 | *.vcd 41 | !tester/src/test/resources/*.vhd 42 | 43 | #Test 44 | *.pyc 45 | *.xml 46 | *.vcd 47 | *.vvp 48 | 49 | #Simu 50 | simWorkspace 51 | tmp 52 | -------------------------------------------------------------------------------- /tester/src/main/scala/ref/checksum/crc/Crc64.java: -------------------------------------------------------------------------------- 1 | package ref.checksum.crc; 2 | 3 | public class Crc64 { 4 | public static AlgoParams Crc64 = new AlgoParams("CRC-64",64, 0x42F0E1EBA9EA3693L, 0x00000000L, false, false, 0x00000000L, 0x6C40DF5F0B497347L); 5 | public static AlgoParams Crc64We = new AlgoParams("CRC-64/WE", 64, 0x42F0E1EBA9EA3693L, 0xFFFFFFFFFFFFFFFFL, false, false, 0xFFFFFFFFFFFFFFFFL,0x62EC59E3F1A4F00AL); 6 | public static AlgoParams Crc64Xz = new AlgoParams("CRC-64/XZ", 64, 0x42F0E1EBA9EA3693L, 0xFFFFFFFFFFFFFFFFL, true, true, 0xFFFFFFFFFFFFFFFFL,0x995DC9BBDF1939FAL); 7 | 8 | 9 | public static final AlgoParams[] Params = new AlgoParams[]{ 10 | Crc64, Crc64We, Crc64Xz 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SpinalCrypto 2 | 3 | This repository contains cryptographic Spinal IPs. This work is currently in progress. 4 | 5 | 6 | ## IP available 7 | 8 | 9 | ### Symmetric 10 | 11 | - Block Cipher Mode of Operation (BCMO) (ECB, CBC, CFB, OFB) 12 | - AESCore_Std (128/192/256-bit) 13 | - DESCore_Std 14 | - TripleDESCore_Std 15 | - TwofishCore_Std (128/192/256-bit) 16 | 17 | 18 | ### Hash 19 | 20 | - MD5Core_Std 21 | - SHA2Core_Std 22 | - SHA3Core_Std 23 | 24 | 25 | ### MAC 26 | 27 | - HMACCore_Std (tested with MD5) 28 | 29 | 30 | ### Checksum 31 | 32 | - CRC (CRC8, CRC16, CRC32) 33 | 34 | 35 | ### Misc 36 | 37 | - LFSR (Galois & Fibonacci) 38 | - Keccak 39 | 40 | 41 | 42 | ## Documentation 43 | 44 | Documentation is available on the [wiki](https://github.com/SpinalHDL/SpinalCrypto/wiki) page. 45 | 46 | -------------------------------------------------------------------------------- /tester/src/main/scala/cryptotest/PolynomialTester.scala: -------------------------------------------------------------------------------- 1 | package cryptotest 2 | 3 | import org.scalatest.funsuite.AnyFunSuite 4 | import spinal.crypto._ 5 | 6 | 7 | class PolynomialTester extends AnyFunSuite { 8 | 9 | test("Polynomial creation") { 10 | 11 | val p1 = p"x^3 + x^2 + x + 1" 12 | assert(p1.coefficient == List(3,2,1,0), s"String polynomial Error $p1") 13 | 14 | val p2 = p"b1111" 15 | assert(p2.coefficient == List(3,2,1,0), s"String polynomial Error $p2") 16 | 17 | val p3 = p"32'x04C11DB7" 18 | assert(p3.coefficient == List(32, 26, 23, 22, 16, 12, 11, 10, 8, 7, 5, 4, 2, 1, 0), s"String polynomial Error $p3") 19 | 20 | val p4 = p"16'x8BB7" 21 | val p5 = p"x^16+x^15+x^11+x^9+x^8+x^7+x^5+x^4+x^2+x+1 " 22 | assert(p4 == p5, s"String polynomial Error $p4 is not equal to $p5") 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tester/src/main/scala/ref/padding/Pad_xB_1_Ref.scala: -------------------------------------------------------------------------------- 1 | package ref.padding 2 | 3 | object Pad_xB_1_Ref { 4 | 5 | /** 6 | * Software model 7 | * @param dIn string message 8 | * @param dataInWidth symbol width 9 | * @param outWidth Size of the output of the padding 10 | * @return Hexadecimal string 11 | */ 12 | def apply(dIn: String, dataInWidth: Int, outWidth: Int): List[String]= { 13 | 14 | var data: Array[Byte] = dIn.map(_.toByte).toArray :+ 0x06.toByte 15 | 16 | var nbr = scala.math.ceil(dIn.length / (outWidth / 8).toDouble).toInt 17 | if(dIn.length % (outWidth / 8) == 0) nbr += 1 18 | val endSize = nbr * outWidth / 8 19 | 20 | data = data ++ List.fill(endSize - data.length)(0x00.toByte) 21 | 22 | data(data.size - 1) = (data.last | 0x80).toByte 23 | 24 | data.sliding(outWidth / 8, outWidth / 8).map(_.map(x => f"$x%02X").mkString("")).toList 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tester/src/main/scala/ref/checksum/crc/Main.java: -------------------------------------------------------------------------------- 1 | package ref.checksum.crc; 2 | 3 | 4 | import static java.lang.System.out; 5 | 6 | public class Main { 7 | 8 | public static void main(String[] args) { 9 | Check(Crc8.Params); 10 | 11 | Check(Crc16.Params); 12 | 13 | Check(Crc32.Params); 14 | 15 | Check(Crc64.Params); 16 | } 17 | 18 | private static void Check(AlgoParams[] params) 19 | { 20 | for (int i = 0; i < params.length; i++) { 21 | CrcCalculator calculator = new CrcCalculator(params[i]); 22 | long result = calculator.Calc(CrcCalculator.TestBytes, 0, CrcCalculator.TestBytes.length); 23 | if (result != calculator.Parameters.Check) 24 | out.println(calculator.Parameters.Name + " - BAD ALGO!!! " + Long.toHexString(result).toUpperCase()); 25 | else 26 | out.println(calculator.Parameters.Name + " - OK!!! " + Long.toHexString(result).toUpperCase()); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Spinal HDL contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tester/src/main/scala/cryptotest/SpinalSimDESCoreTester.scala: -------------------------------------------------------------------------------- 1 | package cryptotest 2 | 3 | import org.scalatest.funsuite.AnyFunSuite 4 | import ref.symmetric.DES 5 | import spinal.core._ 6 | import spinal.crypto.symmetric.sim.SymmetricCryptoBlockIOSim 7 | import spinal.core.sim._ 8 | import spinal.crypto.symmetric.des.DESCore_Std 9 | 10 | import scala.util.Random 11 | 12 | 13 | 14 | class SpinalSimDESCoreTester extends AnyFunSuite { 15 | 16 | val NBR_ITERATION = 20 17 | 18 | /** 19 | * Test - DESCore_STD 20 | */ 21 | test("DESCore_Std"){ 22 | 23 | SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new DESCore_Std()).doSim{ dut => 24 | 25 | dut.clockDomain.forkStimulus(2) 26 | 27 | // initialize value 28 | SymmetricCryptoBlockIOSim.initializeIO(dut.io) 29 | 30 | dut.clockDomain.waitActiveEdge() 31 | 32 | for(_ <- 0 to NBR_ITERATION){ 33 | 34 | SymmetricCryptoBlockIOSim.doSim(dut.io, dut.clockDomain, enc = Random.nextBoolean())(DES.block(verbose = false)) 35 | } 36 | 37 | // Release the valid signal at the end of the simulation 38 | dut.io.cmd.valid #= false 39 | 40 | dut.clockDomain.waitActiveEdge() 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tester/src/main/scala/cryptotest/SpinalSimTripleDESCoreTester.scala: -------------------------------------------------------------------------------- 1 | package cryptotest 2 | 3 | import org.scalatest.funsuite.AnyFunSuite 4 | import ref.symmetric.TripleDES 5 | import spinal.core._ 6 | import spinal.crypto.symmetric.sim.SymmetricCryptoBlockIOSim 7 | import spinal.core.sim._ 8 | import spinal.crypto.symmetric.des.TripleDESCore_Std 9 | 10 | import scala.util.Random 11 | 12 | 13 | 14 | class SpinalSimTripleDESCoreTester extends AnyFunSuite { 15 | 16 | 17 | /** 18 | * Test - TripleDESCore_Std 19 | */ 20 | test("TripleDESCore_Std"){ 21 | 22 | val NBR_ITERATION = 20 23 | 24 | SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new TripleDESCore_Std()).doSim{ dut => 25 | 26 | dut.clockDomain.forkStimulus(2) 27 | 28 | // initialize value 29 | SymmetricCryptoBlockIOSim.initializeIO(dut.io) 30 | 31 | dut.clockDomain.waitActiveEdge() 32 | 33 | for(_ <- 0 to NBR_ITERATION){ 34 | SymmetricCryptoBlockIOSim.doSim(dut.io, dut.clockDomain, enc = Random.nextBoolean())(TripleDES.block(verbose = false)) 35 | } 36 | 37 | // Release the valid signal at the end of the simulation 38 | dut.io.cmd.valid #= false 39 | 40 | dut.clockDomain.waitActiveEdge() 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /tester/src/main/scala/ref/mac/HMAC.scala: -------------------------------------------------------------------------------- 1 | package ref.mac 2 | 3 | 4 | import javax.crypto.Mac 5 | import javax.crypto.spec.SecretKeySpec 6 | 7 | import spinal.crypto.BigIntToHexString 8 | 9 | 10 | object HMAC { 11 | 12 | def digest(msg: String, keyString: String, algo: String): BigInt = { 13 | 14 | val key = new SecretKeySpec((keyString).getBytes("UTF-8"), algo) 15 | val mac = Mac.getInstance(algo) 16 | mac.init(key) 17 | val bytes = mac.doFinal(msg.getBytes("ASCII")) 18 | 19 | return BigInt(bytes) 20 | } 21 | } 22 | 23 | object PlayWithHMacRef extends App{ 24 | 25 | // ('key : ', 'ghbkapojbkibfotjloeyqwzjtxvipc') 26 | // ('key : ', '6768626b61706f6a626b6962666f746a6c6f657971777a6a747876697063') 27 | // ('msg : ', 'wwekmebfdwkarbxwbjjfbjwunfbovhguihldbmyfpwxqhtgbszzyjuewylwpnuzswhunxogzgvnxjvatoimzyieyhqgktsfvszz') 28 | // ('msg : ', '7777656b6d65626664776b6172627877626a6a66626a77756e66626f7668677569686c64626d79667077787168746762737a7a796a756577796c77706e757a737768756e786f677a67766e786a7661746f696d7a796965796871676b74736676737a7a') 29 | // ('hmac : ', '5812b025c7b64aacc7fd97b68d518430') 30 | 31 | 32 | // println(HMAC.digest("The quick brown fox jumps over the lazy dog", "key", "HmacMD5")) 33 | 34 | println(HMAC.digest("wwekmebfdwkarbxwbjjfbjwunfbovhguihldbmyfpwxqhtgbszzyjuewylwpnuzswhunxogzgvnxjvatoimzyieyhqgktsfvszz", "ghbkapojbkibfotjloeyqwzjtxvipc", "HmacMD5")) 35 | 36 | 37 | } -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/hash/sim/HashEngineIOsim.scala: -------------------------------------------------------------------------------- 1 | package spinal.crypto.hash.sim 2 | 3 | 4 | import spinal.core._ 5 | import spinal.core.sim._ 6 | import spinal.crypto._ 7 | import spinal.crypto.hash._ 8 | 9 | import scala.util.Random 10 | 11 | 12 | object HashEngineIOsim { 13 | 14 | def initializeIO(dut: HashEngineIO): Unit ={ 15 | dut.init #= false 16 | dut.cmd.valid #= false 17 | dut.cmd.message.randomize() 18 | } 19 | 20 | 21 | def doSim(dut: HashEngineIO, clockDomain: ClockDomain, message: List[BigInt], refHash: BigInt): Unit = { 22 | 23 | 24 | dut.init #= true 25 | clockDomain.waitActiveEdge() 26 | dut.init #= false 27 | clockDomain.waitActiveEdge() 28 | 29 | var indexBlock = 0 30 | var rtlDigest = BigInt(0) 31 | 32 | while (indexBlock != message.length) { 33 | 34 | dut.cmd.valid #= true 35 | dut.cmd.message #= message(indexBlock) 36 | 37 | waitUntil(dut.rsp.valid.toBoolean == true) 38 | 39 | rtlDigest = dut.rsp.digest.toBigInt 40 | 41 | clockDomain.waitActiveEdge() 42 | 43 | dut.cmd.valid #= false 44 | 45 | clockDomain.waitActiveEdge() 46 | 47 | indexBlock += 1 48 | } 49 | 50 | assert(CastByteArray(rtlDigest.toByteArray, dut.rsp.digest.getWidth).sameElements(CastByteArray(refHash.toByteArray, dut.rsp.digest.getWidth)), s"RTL != REF ${BigIntToHexString(rtlDigest)} != ${BigIntToHexString(refHash)}") 51 | 52 | 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /tester/src/main/scala/ref/checksum/crc/Crc8.java: -------------------------------------------------------------------------------- 1 | package ref.checksum.crc; 2 | 3 | /** 4 | * Created by anthony on 15.05.2017. 5 | */ 6 | public class Crc8 { 7 | public static AlgoParams Crc8 = new AlgoParams("CRC-8", 8, 0x7, 0x0, false, false, 0x0, 0xF4); 8 | public static AlgoParams Crc8Cdma2000 = new AlgoParams("CRC-8/CDMA2000", 8, 0x9B, 0xFF, false, false, 0x0, 0xDA); 9 | public static AlgoParams Crc8Darc = new AlgoParams("CRC-8/DARC", 8, 0x39, 0x0, true, true, 0x0, 0x15); 10 | public static AlgoParams Crc8DvbS2 = new AlgoParams("CRC-8/DVB-S2", 8, 0xD5, 0x0, false, false, 0x0, 0xBC); 11 | public static AlgoParams Crc8Ebu = new AlgoParams("CRC-8/EBU", 8, 0x1D, 0xFF, true, true, 0x0, 0x97); 12 | public static AlgoParams Crc8ICode = new AlgoParams("CRC-8/I-CODE", 8, 0x1D, 0xFD, false, false, 0x0, 0x7E); 13 | public static AlgoParams Crc8Itu = new AlgoParams("CRC-8/ITU", 8, 0x7, 0x0, false, false, 0x55, 0xA1); 14 | public static AlgoParams Crc8Maxim = new AlgoParams("CRC-8/MAXIM", 8, 0x31, 0x0, true, true, 0x0, 0xA1); 15 | public static AlgoParams Crc8Rohc = new AlgoParams("CRC-8/ROHC", 8, 0x7, 0xFF, true, true, 0x0, 0xD0); 16 | public static AlgoParams Crc8Wcdma = new AlgoParams("CRC-8/WCDMA", 8, 0x9B, 0x0, true, true, 0x0, 0x25); 17 | 18 | public static final AlgoParams[] Params = new AlgoParams[]{ 19 | Crc8, Crc8Cdma2000, Crc8Darc, Crc8DvbS2, Crc8Ebu, Crc8ICode, Crc8Itu, Crc8Maxim, Crc8Rohc, Crc8Wcdma 20 | }; 21 | } -------------------------------------------------------------------------------- /tester/src/main/scala/ref/checksum/crc/Crc32.java: -------------------------------------------------------------------------------- 1 | package ref.checksum.crc; 2 | 3 | 4 | public class Crc32 { 5 | public static AlgoParams Crc32 = new AlgoParams("CRC-32", 32, 0x04C11DB7L, 0xFFFFFFFFL, true, true, 0xFFFFFFFFL, 0xCBF43926L); 6 | public static AlgoParams Crc32Bzip2 = new AlgoParams("CRC-32/BZIP2", 32, 0x04C11DB7L, 0xFFFFFFFFL, false, false, 0xFFFFFFFFL, 0xFC891918L); 7 | public static AlgoParams Crc32C = new AlgoParams("CRC-32C", 32, 0x1EDC6F41L, 0xFFFFFFFFL, true, true, 0xFFFFFFFFL, 0xE3069283L); 8 | public static AlgoParams Crc32D = new AlgoParams("CRC-32D", 32, 0xA833982BL, 0xFFFFFFFFL, true, true, 0xFFFFFFFFL, 0x87315576L); 9 | public static AlgoParams Crc32Jamcrc = new AlgoParams("CRC-32/JAMCRC", 32, 0x04C11DB7L, 0xFFFFFFFFL, true, true, 0x00000000L, 0x340BC6D9L); 10 | public static AlgoParams Crc32Mpeg2 = new AlgoParams("CRC-32/MPEG-2", 32, 0x04C11DB7L, 0xFFFFFFFFL, false, false, 0x00000000L, 0x0376E6E7L); 11 | public static AlgoParams Crc32Posix = new AlgoParams("CRC-32/POSIX", 32, 0x04C11DB7L, 0x00000000L, false, false, 0xFFFFFFFFL, 0x765E7680L); 12 | public static AlgoParams Crc32Q = new AlgoParams("CRC-32Q", 32, 0x814141ABL, 0x00000000L, false, false, 0x00000000L, 0x3010BF7FL); 13 | public static AlgoParams Crc32Xfer = new AlgoParams("CRC-32/XFER", 32, 0x000000AFL, 0x00000000L, false, false, 0x00000000L, 0xBD0BE338L); 14 | 15 | public static final AlgoParams[] Params = new AlgoParams[]{ 16 | Crc32, Crc32Bzip2, Crc32C, Crc32D, Crc32Jamcrc, Crc32Mpeg2, Crc32Posix, Crc32Q, Crc32Xfer 17 | }; 18 | } -------------------------------------------------------------------------------- /tester/src/main/scala/ref/constructor/Sponge.scala: -------------------------------------------------------------------------------- 1 | package ref.constructor 2 | 3 | 4 | 5 | object Sponge { 6 | 7 | def apply(msg: Array[Byte], c: Int, r: Int, d: Int): Array[Byte] ={ 8 | 9 | val msgCut = msg.sliding(r / 8, r / 8) 10 | val rReg = Array.fill(r / 8)(0x00.toByte) 11 | val cReg = Array.fill(c / 8)(0x00.toByte) 12 | 13 | /** 14 | * Absorbing 15 | */ 16 | for(m <- msgCut){ 17 | 18 | //println("msg", msg.length, m.map(x => f"$x%02X").mkString(",")) 19 | 20 | // XOR 21 | val xored = rReg.zip(m).map{case(a,b) => (a ^ b).toByte} 22 | //println("xor", xored.length, xored.map(x => f"$x%02X").mkString(",")) 23 | 24 | // SHIFT 25 | val shift = (xored ++ cReg).slice(1, xored.length + cReg.length) :+ 0x00.toByte 26 | //println("shift", shift.length, shift.map(x => f"$x%02X").mkString(",")) 27 | 28 | //println(rReg.length, cReg.length, shift.length) 29 | 30 | // COPY 31 | for(i <- 0 until rReg.length) rReg(i) = shift(i) 32 | for(i <- 0 until cReg.length) cReg(i) = shift(i + rReg.length - 1) 33 | } 34 | 35 | 36 | //println("rReg", rReg.length, rReg.map(x => f"$x%02X").mkString(",")) 37 | //println("cReg", cReg.length, cReg.map(x => f"$x%02X").mkString(",")) 38 | 39 | /** 40 | * Squeezing 41 | */ 42 | val nbrSqueeze = scala.math.floor(d / r.toDouble).toInt 43 | val zReg = Array.fill((nbrSqueeze + 1) * (r / 8))(0x00.toByte) 44 | 45 | if(d > r){ 46 | 47 | for(x <- 0 until nbrSqueeze){ 48 | for(i <- 0 until rReg.length) zReg(i + x * (r/8)) = rReg(i) 49 | 50 | // SHIFT 51 | val shift = (rReg ++ cReg).slice(1, rReg.length + cReg.length) :+ 0x00.toByte 52 | //println("shift", shift.length, shift.map(x => f"$x%02X").mkString(",")) 53 | 54 | // COPY 55 | for(i <- 0 until rReg.length) rReg(i) = shift(i) 56 | for(i <- 0 until cReg.length) cReg(i) = shift(i + rReg.length - 1) 57 | } 58 | 59 | for(i <- 0 until rReg.length) zReg(i + nbrSqueeze * (r/8)) = rReg(i) 60 | } 61 | 62 | 63 | 64 | return if(d > r) zReg.slice(0, d / 8) else rReg.slice(0, d / 8) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tester/src/main/scala/ref/checksum/crc/CrcCalculator.java: -------------------------------------------------------------------------------- 1 | package ref.checksum.crc; 2 | 3 | 4 | public class CrcCalculator { 5 | 6 | public AlgoParams Parameters; 7 | public byte HashSize = 8; 8 | private long _mask = 0xFFFFFFFFFFFFFFFFL; 9 | private long[] _table = new long[256]; 10 | 11 | public static final byte[] TestBytes = new byte[]{49,50,51,52,53,54,55,56,57}; 12 | 13 | public CrcCalculator(AlgoParams params) 14 | { 15 | Parameters = params; 16 | 17 | HashSize = (byte) params.HashSize; 18 | if (HashSize < 64) 19 | { 20 | _mask = (1L << HashSize) - 1; 21 | } 22 | 23 | CreateTable(); 24 | } 25 | 26 | public long Calc(byte[] data, int offset, int length) 27 | { 28 | long init = Parameters.RefOut ? CrcHelper.ReverseBits(Parameters.Init, HashSize) : Parameters.Init; 29 | long hash = ComputeCrc(init, data, offset, length); 30 | return (hash ^ Parameters.XorOut) & _mask; 31 | } 32 | 33 | private long ComputeCrc(long init, byte[] data, int offset, int length) 34 | { 35 | long crc = init; 36 | 37 | if (Parameters.RefOut) 38 | { 39 | for (int i = offset; i < offset + length; i++) 40 | { 41 | crc = (_table[(int)((crc ^ data[i]) & 0xFF)] ^ (crc >>> 8)); 42 | crc &= _mask; 43 | } 44 | } 45 | else 46 | { 47 | int toRight = (HashSize - 8); 48 | toRight = toRight < 0 ? 0 : toRight; 49 | for (int i = offset; i < offset + length; i++) 50 | { 51 | crc = (_table[(int)(((crc >> toRight) ^ data[i]) & 0xFF)] ^ (crc << 8)); 52 | crc &= _mask; 53 | } 54 | } 55 | 56 | return crc; 57 | } 58 | 59 | private void CreateTable() 60 | { 61 | for (int i = 0; i < _table.length; i++) 62 | _table[i] = CreateTableEntry(i); 63 | } 64 | 65 | private long CreateTableEntry(int index) 66 | { 67 | long r = (long)index; 68 | 69 | if (Parameters.RefIn) 70 | r = CrcHelper.ReverseBits(r, HashSize); 71 | else if (HashSize > 8) 72 | r <<= (HashSize - 8); 73 | 74 | long lastBit = (1L << (HashSize - 1)); 75 | 76 | for (int i = 0; i < 8; i++) 77 | { 78 | if ((r & lastBit) != 0) 79 | r = ((r << 1) ^ Parameters.Poly); 80 | else 81 | r <<= 1; 82 | } 83 | 84 | if (Parameters.RefOut) 85 | r = CrcHelper.ReverseBits(r, HashSize); 86 | 87 | return r & _mask; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /tester/src/main/scala/cryptotest/SpinalSimMD5CoreStdTester.scala: -------------------------------------------------------------------------------- 1 | package cryptotest 2 | 3 | 4 | import org.scalatest.funsuite.AnyFunSuite 5 | import ref.hash.MD5 6 | 7 | import spinal.core._ 8 | import spinal.core.sim._ 9 | 10 | import spinal.crypto.hash.LITTLE_endian 11 | import spinal.crypto.hash.md5.{MD5Core_Std, MD5Engine_Std} 12 | import spinal.crypto.hash.sim.{HashEngineIOsim, HashIOsim} 13 | 14 | 15 | 16 | 17 | /** 18 | * Test MD5Core_Std 19 | */ 20 | class SpinalSimMD5CoreStdTester extends AnyFunSuite { 21 | 22 | // RTL to simulate 23 | val compiledRTL = SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new MD5Core_Std()) 24 | 25 | val NBR_ITERATION = 100 26 | 27 | /** 28 | * Test 1 29 | */ 30 | test("MD5CoreStd") { 31 | 32 | compiledRTL.doSim{ dut => 33 | 34 | dut.clockDomain.forkStimulus(2) 35 | 36 | HashIOsim.initializeIO(dut.io) 37 | 38 | dut.clockDomain.waitActiveEdge() 39 | 40 | for(i <- 0 to NBR_ITERATION){ 41 | HashIOsim.doSim(dut.io, dut.clockDomain, i, LITTLE_endian)(MD5.digest) 42 | } 43 | } 44 | } 45 | } 46 | 47 | 48 | /** 49 | * Test MD5Engine_Std 50 | */ 51 | class SpinalSimMD5EngineStdTester extends AnyFunSuite { 52 | 53 | // RTL to simulate 54 | val compiledRTL = SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new MD5Engine_Std()) 55 | 56 | 57 | /** 58 | * Test 1 59 | */ 60 | test("MD5EngineStd") { 61 | 62 | compiledRTL.doSim{ dut => 63 | 64 | dut.clockDomain.forkStimulus(2) 65 | 66 | dut.io.cmd.valid #= false 67 | dut.io.cmd.message.randomize() 68 | dut.io.init #= false 69 | 70 | dut.clockDomain.waitActiveEdge() 71 | 72 | val messages = List( 73 | List(BigInt("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 16)), 74 | List(BigInt("00000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 16)), 75 | List(BigInt("80636261000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001800000000", 16)), 76 | List(BigInt("34333231383736353231303936353433303938373433323138373635323130393635343330393837343332313837363532313039363534333039383734333231", 16), 77 | BigInt("38373635323130393635343330393837000000800000000000000000000000000000000000000000000000000000000000000000000000000000028000000000", 16)) 78 | ) 79 | 80 | val refDigest = List( 81 | BigInt("031F1DAC6EA58ED01FAB67B774317791", 16), 82 | BigInt("D98C1DD404B2008F980980E97E42F8EC", 16), 83 | BigInt("98500190B04FD23C7D3F96D6727FE128", 16), 84 | BigInt("A2F4ED5755C9E32B2EDA49AC7AB60721", 16) 85 | ) 86 | 87 | for((ref, msg) <- refDigest.zip(messages)){ 88 | HashEngineIOsim.doSim(dut.io, dut.clockDomain, msg, ref) 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/checksum/sim/CRCCombinationalsim.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ ** 7 | ** ** 8 | ** This library is free software; you can redistribute it and/or ** 9 | ** modify it under the terms of the GNU Lesser General Public ** 10 | ** License as published by the Free Software Foundation; either ** 11 | ** version 3.0 of the License, or (at your option) any later version. ** 12 | ** ** 13 | ** This library is distributed in the hope that it will be useful, ** 14 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 15 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** 16 | ** Lesser General Public License for more details. ** 17 | ** ** 18 | ** You should have received a copy of the GNU Lesser General Public ** 19 | ** License along with this library. ** 20 | \* */ 21 | package spinal.crypto.checksum.sim 22 | 23 | import spinal.core._ 24 | import spinal.core.sim._ 25 | import spinal.crypto.checksum.{CRCCombinationalCmdMode, CRCCombinationalIO} 26 | 27 | 28 | object CRCCombinationalsim { 29 | 30 | def doSim(dut: CRCCombinationalIO, clockDomain: ClockDomain, data: List[BigInt], verbose: Boolean = false)(result: BigInt): Unit = { 31 | 32 | require(data.length > 0) 33 | 34 | var index = 0 35 | 36 | // initialize value 37 | dut.cmd.valid #= false 38 | dut.cmd.mode #= CRCCombinationalCmdMode.INIT 39 | dut.cmd.data #= 0 40 | 41 | // Wait end reset 42 | clockDomain.waitActiveEdge() 43 | 44 | // init CRC 45 | dut.cmd.valid #= true 46 | clockDomain.waitActiveEdge() 47 | dut.cmd.valid #= false 48 | clockDomain.waitActiveEdge() 49 | 50 | // Send all data 51 | for(_ <- 0 until data.length){ 52 | dut.cmd.mode #= CRCCombinationalCmdMode.UPDATE 53 | dut.cmd.valid #= true 54 | dut.cmd.data #= data(index) 55 | 56 | clockDomain.waitActiveEdge() 57 | 58 | dut.cmd.valid #= false 59 | 60 | clockDomain.waitActiveEdge() 61 | 62 | index += 1 63 | } 64 | 65 | // check crc 66 | val crcRTL = dut.crc.toBigInt 67 | 68 | if(verbose){ 69 | println(s"0x${crcRTL.toString(16).toUpperCase}") 70 | } 71 | 72 | assert(crcRTL == result, "CRC error") 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /tester/src/main/scala/cryptotest/SpinalSimSHA3CoreStdTester.scala: -------------------------------------------------------------------------------- 1 | package cryptotest 2 | 3 | 4 | import org.scalatest.funsuite.AnyFunSuite 5 | import ref.hash.SHA3 6 | import spinal.core._ 7 | import spinal.crypto.hash.BIG_endian 8 | import spinal.crypto.hash.sim.HashIOsim 9 | import spinal.core.sim._ 10 | import spinal.crypto.hash.sha3._ 11 | 12 | 13 | 14 | /** 15 | * Test SHA3Core_Std 16 | * 17 | * Pattern : https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines/example-values 18 | * 19 | */ 20 | class SpinalSimSHA3CoreStdTester extends AnyFunSuite { 21 | 22 | val NBR_ITERATION = 100 23 | 24 | /** 25 | * SHA3CoreStd_512 26 | */ 27 | test("SHA3CoreStd_512") { 28 | 29 | val compiledRTL = SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new SHA3Core_Std(SHA3_512)) 30 | 31 | compiledRTL.doSim{ dut => 32 | 33 | dut.clockDomain.forkStimulus(2) 34 | 35 | HashIOsim.initializeIO(dut.io) 36 | 37 | dut.clockDomain.waitActiveEdge() 38 | 39 | for(i <- 0 to NBR_ITERATION){ 40 | HashIOsim.doSim(dut.io, dut.clockDomain, i, BIG_endian)(SHA3.digest(512)) 41 | } 42 | 43 | dut.clockDomain.waitActiveEdge(5) 44 | } 45 | } 46 | 47 | /** 48 | * SHA3CoreStd_384 49 | */ 50 | test("SHA3CoreStd_384") { 51 | 52 | val compiledRTL = SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new SHA3Core_Std(SHA3_384)) 53 | 54 | compiledRTL.doSim{ dut => 55 | 56 | dut.clockDomain.forkStimulus(2) 57 | 58 | HashIOsim.initializeIO(dut.io) 59 | 60 | dut.clockDomain.waitActiveEdge() 61 | 62 | 63 | for(i <- 0 to NBR_ITERATION){ 64 | HashIOsim.doSim(dut.io, dut.clockDomain, i, BIG_endian)(SHA3.digest(384)) 65 | } 66 | 67 | dut.clockDomain.waitActiveEdge(5) 68 | } 69 | } 70 | 71 | /** 72 | * SHA3CoreStd_256 73 | */ 74 | test("SHA3CoreStd_256") { 75 | 76 | val compiledRTL = SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new SHA3Core_Std(SHA3_256)) 77 | 78 | compiledRTL.doSim{ dut => 79 | 80 | dut.clockDomain.forkStimulus(2) 81 | 82 | HashIOsim.initializeIO(dut.io) 83 | 84 | dut.clockDomain.waitActiveEdge() 85 | 86 | 87 | for(i <- 0 to NBR_ITERATION){ 88 | HashIOsim.doSim(dut.io, dut.clockDomain, i, BIG_endian)(SHA3.digest(256)) 89 | } 90 | 91 | dut.clockDomain.waitActiveEdge(5) 92 | } 93 | } 94 | 95 | /** 96 | * SHA3CoreStd_224 97 | */ 98 | test("SHA3CoreStd_224") { 99 | 100 | val compiledRTL = SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new SHA3Core_Std(SHA3_224)) 101 | 102 | compiledRTL.doSim{ dut => 103 | 104 | 105 | dut.clockDomain.forkStimulus(2) 106 | 107 | HashIOsim.initializeIO(dut.io) 108 | 109 | dut.clockDomain.waitActiveEdge() 110 | 111 | 112 | for(i <- 0 to NBR_ITERATION){ 113 | HashIOsim.doSim(dut.io, dut.clockDomain, i, BIG_endian)(SHA3.digest(224)) 114 | } 115 | 116 | dut.clockDomain.waitActiveEdge(5) 117 | } 118 | } 119 | } 120 | 121 | -------------------------------------------------------------------------------- /todo.md: -------------------------------------------------------------------------------- 1 | 2 | # spinal.crypto 3 | 4 | 5 | :ok: Implemented / 6 | :arrows_counterclockwise: In process / 7 | :no_entry_sign: Not implemented 8 | 9 | ### Symmetric 10 | 11 | | Algo | Status | Remark | 12 | |:-------------------------------------------------- |:--------------------------:|:------------------- | 13 | | DESCore_Std | :ok: | Not tested on FPGA | 14 | | TripleDESCore_Std | :ok: | Not tested on FPGA | 15 | | AESCore_Std (128/192/256-bit) | :ok: | Not tested on FPGA | 16 | | Block Cipher mode operation (CBC,ECB,CTR,OFB,CFB) | :ok: | CTR not implemented| 17 | | Twofish | :ok: | Not tested on FPGA | 18 | | RC6 | :no_entry_sign: | - | 19 | 20 | 21 | ### Asymmetric 22 | 23 | | Algo | Status | Remark | 24 | |:-------------------------------------------------- |:--------------------------:|:------------------- | 25 | | RSA | :no_entry_sign: | - | 26 | | Elliptic curve cryptography | :no_entry_sign: | - | 27 | 28 | 29 | 30 | ### Hash 31 | 32 | | Algo | Status | Remark | 33 | |:-------------------------------------------------- |:--------------------------:|:------------------- | 34 | | MD5Core_Std | :ok: | Not tested on FPGA | 35 | | SHA2Core_Std | :ok: | Not tested on FPGA | 36 | | SHA3Core_Std | :ok: | Not tested on FPGA | 37 | | MD6 | :no_entry_sign: | - | 38 | 39 | ### MAC 40 | 41 | | Algo | Status | Remark | 42 | |:-------------------------------------------------- |:--------------------------:|:------------------- | 43 | | HMACCore_Std | :ok: | Not tested on FPGA | 44 | 45 | 46 | ### Misc 47 | 48 | | Algo | Status | Remark | 49 | |:-------------------------------------------------- |:--------------------------:|:------------------- | 50 | | LFSR (Fibonacci/Galois) | :ok: | Not tested on FPGA | 51 | | TRNG with PLL | :no_entry_sign: | - | 52 | | CRC | :ok: | Test only CRC 8, 16, 32 | 53 | | Keccak | :ok: | Not tested on FPGA | 54 | 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/symmetric/twofish/Twofish.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.symmetric.twofish 27 | 28 | import spinal.core._ 29 | 30 | object Twofish { 31 | 32 | def blockWidth = 128 bits 33 | 34 | def getWidthOfS(keySize: Int) = keySize match{ 35 | case 128 => 2 36 | case 192 => 3 37 | case 256 => 4 38 | } 39 | 40 | def qxT0 = List( 41 | List(0x8, 0x1, 0x7, 0xD, 0x6, 0xF, 0x3, 0x2, 0x0, 0xB, 0x5, 0x9, 0xE, 0xC, 0xA, 0x4), 42 | List(0x2, 0x8, 0xB, 0xD, 0xF, 0x7, 0x6, 0xE, 0x3, 0x1, 0x9, 0x4, 0x0, 0xA, 0xC, 0x5) 43 | ) 44 | def qxT1 = List( 45 | List(0xE, 0xC, 0xB, 0x8, 0x1, 0x2, 0x3, 0x5, 0xF, 0x4, 0xA, 0x6, 0x7, 0x0, 0x9, 0xD), 46 | List(0x1, 0xE, 0x2, 0xB, 0x4, 0xC, 0x3, 0x7, 0x6, 0xD, 0xA, 0x5, 0xF, 0x9, 0x0, 0x8) 47 | ) 48 | def qxT2 = List( 49 | List(0xB, 0xA, 0x5, 0xE, 0x6, 0xD, 0x9, 0x0, 0xC, 0x8, 0xF, 0x3, 0x2, 0x4, 0x7, 0x1), 50 | List(0x4, 0xC, 0x7, 0x5, 0x1, 0x6, 0x9, 0xA, 0x0, 0xE, 0xD, 0x8, 0x2, 0xB, 0x3, 0xF) 51 | 52 | ) 53 | def qxT3 = List( 54 | List(0xD, 0x7, 0xF, 0x4, 0x1, 0x2, 0x6, 0xE, 0x9, 0xB, 0x3, 0x0, 0x8, 0x5, 0xC, 0xA), 55 | List(0xb, 0x9, 0x5, 0x1, 0xC, 0x3, 0xD, 0xE, 0x6, 0x4, 0x7, 0xF, 0x2, 0x0, 0x8, 0xA) 56 | ) 57 | 58 | } -------------------------------------------------------------------------------- /tester/src/main/scala/cryptotest/SpinalSimPad_xB_1_StdTester.scala: -------------------------------------------------------------------------------- 1 | package cryptotest 2 | 3 | import spinal.core._ 4 | import spinal.core.sim._ 5 | import org.scalatest.funsuite.AnyFunSuite 6 | import ref.padding.Pad_xB_1_Ref 7 | import spinal.crypto.{BigIntToHexString, CastByteArray} 8 | import spinal.crypto.padding.{Pad_xB_1_Std, Padding_xB_1_Config} 9 | 10 | 11 | import scala.util.Random 12 | 13 | 14 | 15 | class SpinalSimPad_xB_1_StdTester extends AnyFunSuite { 16 | 17 | 18 | /** 19 | * Pad_06_1_576_32 20 | */ 21 | test("Pad_06_1_576_32"){ 22 | 23 | SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new Pad_xB_1_Std(Padding_xB_1_Config(32 bits, 576 bits, 0x06, 8 bits))).doSim{ dut => 24 | 25 | dut.clockDomain.forkStimulus(2) 26 | 27 | var iteration = 100 28 | 29 | while(iteration != 0){ 30 | 31 | // pattern 32 | val pIn = List.fill(iteration)(Random.nextPrintableChar()).mkString("") 33 | 34 | val byteSizeMsg = 4 35 | 36 | // initialize value 37 | dut.io.init #= true 38 | dut.io.cmd.last #= false 39 | dut.io.cmd.valid #= false 40 | dut.io.cmd.data.randomize() 41 | 42 | dut.io.rsp.ready #= true 43 | 44 | dut.clockDomain.waitActiveEdge() 45 | 46 | dut.io.init #= false 47 | 48 | var indexPin = scala.math.ceil(pIn.length / byteSizeMsg.toDouble).toInt 49 | 50 | var msgStr = pIn 51 | val refOut = Pad_xB_1_Ref(pIn, 32, 576) 52 | 53 | /** 54 | * Manage the response and check the result 55 | */ 56 | fork{ 57 | 58 | var index = 0 59 | 60 | while(index != refOut.length) { 61 | 62 | dut.clockDomain.waitActiveEdgeWhere(dut.io.rsp.valid.toBoolean) 63 | 64 | val rtlOut = CastByteArray(dut.io.rsp.data.toBigInt.toByteArray, dut.io.rsp.data.getWidth / 8) 65 | 66 | assert(BigIntToHexString(BigInt(rtlOut)) == s"0x${refOut(index)}", s"REF != RTL ${refOut(index)} != ${BigIntToHexString(BigInt(rtlOut))}") 67 | 68 | dut.clockDomain.waitActiveEdge() 69 | 70 | index += 1 71 | } 72 | } 73 | 74 | /** 75 | * Send all block in the sponge 76 | */ 77 | while(indexPin != 0){ 78 | 79 | val (msg, isLast) = if (msgStr.length > byteSizeMsg) (msgStr.substring(0, byteSizeMsg) -> false) else (msgStr + 0.toChar.toString * (byteSizeMsg - msgStr.length) -> true) 80 | 81 | dut.clockDomain.waitActiveEdge() 82 | 83 | dut.io.cmd.last #= isLast 84 | dut.io.cmd.valid #= true 85 | dut.io.cmd.data #= BigInt(0x00.toByte +: (msg.map(_.toByte).toArray) )// Add 00 in front in order to get a positif number 86 | dut.io.cmd.size #= BigInt(if (isLast) msgStr.length - 1 else 0) 87 | 88 | // Wait the response 89 | dut.clockDomain.waitActiveEdgeWhere(dut.io.cmd.ready.toBoolean) 90 | 91 | dut.io.cmd.valid #= false 92 | 93 | indexPin -= 1 94 | msgStr = msgStr.drop(byteSizeMsg) 95 | } 96 | 97 | dut.clockDomain.waitActiveEdge(5) 98 | 99 | iteration -= 1 100 | } 101 | } 102 | } 103 | } 104 | 105 | 106 | -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/hash/sha3/SHA3.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.hash.sha3 27 | 28 | 29 | /** 30 | * SHA3 families 31 | * 32 | * The SHA-3 family consists of four cryptographic hash functions and two extendable-output 33 | * functions (XOFs). The cryptographic hash functions are called SHA3-224, SHA3-256, SHA3- 34 | * 384, and SHA3-512; and the XOFs are called SHAKE128 and SHAKE256. 35 | */ 36 | trait SHA3_Type{ def hashWidth: Int; def r: Int ; def c: Int ; def hashComputationWidth: Int } 37 | object SHA3_224 extends SHA3_Type { def hashWidth = 224 ; def r = 1152 ; def c = 448 ; def hashComputationWidth = 256 } 38 | object SHA3_256 extends SHA3_Type { def hashWidth = 256 ; def r = 1088 ; def c = 512 ; def hashComputationWidth = 256 } 39 | object SHA3_384 extends SHA3_Type { def hashWidth = 384 ; def r = 832 ; def c = 768 ; def hashComputationWidth = 384 } 40 | object SHA3_512 extends SHA3_Type { def hashWidth = 512 ; def r = 576 ; def c = 1024 ; def hashComputationWidth = 512 } 41 | //object SHAKE128 extends SHA3_Type { def hashWidth = 128 ; def r = 1344 ; def c = 256 ; def hashComputationWidth = 128 } 42 | //object SHAKE256 extends SHA3_Type { def hashWidth = 256 ; def r = 1088 ; def c = 512 ; def hashComputationWidth = 256 } -------------------------------------------------------------------------------- /tester/src/main/scala/cryptotest/SpinalSimCRCTester.scala: -------------------------------------------------------------------------------- 1 | package cryptotest 2 | 3 | import spinal.core._ 4 | import spinal.core.sim._ 5 | import spinal.crypto.checksum._ 6 | import org.scalatest.funsuite.AnyFunSuite 7 | import ref.checksum.crc._ 8 | import spinal.crypto.checksum.sim.CRCCombinationalsim 9 | 10 | import scala.util.Random 11 | 12 | 13 | class SpinalSimCRCTester extends AnyFunSuite { 14 | 15 | 16 | /** 17 | * Compute the CRC reference 18 | */ 19 | def computeCRC(data: List[BigInt], mode: AlgoParams, dataWidth: Int, verbose: Boolean = false): BigInt = { 20 | val calculator = new CrcCalculator(mode) 21 | 22 | val din = data.map(_.toByteArray.takeRight(dataWidth / 8)).flatten.toArray 23 | val result = calculator.Calc(din, 0, din.length) 24 | 25 | if (verbose) { 26 | println(BigInt(result).toString(16)) 27 | } 28 | 29 | return BigInt(result) 30 | } 31 | 32 | 33 | /** 34 | * Simulate a CRC 35 | */ 36 | def crcSimulation(crcMode: List[(CRCPolynomial, AlgoParams)], dataWidth: Int){ 37 | 38 | for (mode <- crcMode) { 39 | 40 | val config = CRCCombinationalConfig( 41 | crcConfig = mode._1, 42 | dataWidth = dataWidth bits 43 | ) 44 | 45 | SimConfig.compile(new CRCCombinational(config)).doSim { dut => 46 | 47 | val data = List.fill[BigInt](Random.nextInt(10) + 1)(BigInt(dataWidth, Random)) 48 | 49 | dut.clockDomain.forkStimulus(2) 50 | 51 | CRCCombinationalsim.doSim(dut.io, dut.clockDomain, data)(computeCRC(data, mode._2, dataWidth)) 52 | 53 | dut.clockDomain.waitActiveEdge() 54 | } 55 | } 56 | } 57 | 58 | 59 | /** 60 | * CRC32 with 8-bit data 61 | */ 62 | test("CRC32_8_combinational"){ 63 | 64 | val configurations = List( 65 | CRC32.Standard -> Crc32.Crc32, 66 | CRC32.XFER -> Crc32.Crc32Xfer 67 | ) 68 | 69 | crcSimulation(configurations, 8) 70 | } 71 | 72 | 73 | /** 74 | * CRC32 with 16-bit data 75 | */ 76 | test("CRC32_16_combinational"){ 77 | 78 | val configurations = List( 79 | CRC32.Standard -> Crc32.Crc32, 80 | CRC32.XFER -> Crc32.Crc32Xfer 81 | ) 82 | 83 | crcSimulation(configurations, 16) 84 | } 85 | 86 | 87 | /** 88 | * CRC32 with 32-bit data 89 | */ 90 | test("CRC32_32_combinational"){ 91 | 92 | val configurations = List( 93 | CRC32.Standard -> Crc32.Crc32, 94 | CRC32.XFER -> Crc32.Crc32Xfer 95 | ) 96 | 97 | crcSimulation(configurations, 32) 98 | } 99 | 100 | 101 | /** 102 | * CRC16 with 16-bit data 103 | */ 104 | test("CRC16_16_combinational"){ 105 | 106 | val configurations = List( 107 | CRC16.XModem -> Crc16.Crc16Xmodem 108 | ) 109 | 110 | crcSimulation(configurations, 16) 111 | } 112 | 113 | 114 | /** 115 | * CRC16 with 8-bit data 116 | */ 117 | test("CRC16_8_combinational"){ 118 | 119 | val configurations = List( 120 | CRC16.XModem -> Crc16.Crc16Xmodem 121 | ) 122 | 123 | crcSimulation(configurations, 8) 124 | } 125 | 126 | 127 | /** 128 | * CRC8 with 8-bit data 129 | */ 130 | test("CRC8_8_combinational") { 131 | 132 | val configurations = List( 133 | CRC8.Standard -> Crc8.Crc8, 134 | CRC8.DARC -> Crc8.Crc8Darc 135 | ) 136 | 137 | crcSimulation(configurations, 8) 138 | } 139 | } 140 | 141 | -------------------------------------------------------------------------------- /tester/src/main/scala/ref/checksum/crc/AlgoParams.java: -------------------------------------------------------------------------------- 1 | package ref.checksum.crc; 2 | 3 | 4 | public class AlgoParams 5 | { 6 | 7 | public AlgoParams(String name, int hashSize, long poly, long init, boolean refIn, boolean refOut, long xorOut, long check) 8 | { 9 | Name = name; 10 | Check = check; 11 | Init = init; 12 | Poly = poly; 13 | RefIn = refIn; 14 | RefOut = refOut; 15 | XorOut = xorOut; 16 | HashSize = hashSize; 17 | } 18 | 19 | /// 20 | /// This field is not strictly part of the definition, and, in 21 | /// the event of an inconsistency between this field and the other 22 | /// field, the other fields take precedence.This field is a check 23 | /// value that can be used as a weak validator of implementations of 24 | /// the algorithm.The field contains the checksum obtained when the 25 | /// ASCII string "123456789" is fed through the specified algorithm 26 | /// (i.e. 313233... (hexadecimal)). 27 | /// 28 | public long Check; 29 | 30 | /// 31 | /// This is hash size. 32 | /// 33 | public int HashSize; 34 | 35 | /// 36 | /// This parameter specifies the initial value of the register 37 | /// when the algorithm starts.This is the value that is to be assigned 38 | /// to the register in the direct table algorithm. In the table 39 | /// algorithm, we may think of the register always commencing with the 40 | /// value zero, and this value being XORed into the register after the 41 | /// N'th bit iteration. This parameter should be specified as a 42 | /// hexadecimal number. 43 | /// 44 | public long Init; 45 | 46 | /// 47 | /// This is a name given to the algorithm. A string value. 48 | /// 49 | public String Name; 50 | 51 | /// 52 | /// This parameter is the poly. This is a binary value that 53 | /// should be specified as a hexadecimal number.The top bit of the 54 | /// poly should be omitted.For example, if the poly is 10110, you 55 | /// should specify 06. An important aspect of this parameter is that it 56 | /// represents the unreflected poly; the bottom bit of this parameter 57 | /// is always the LSB of the divisor during the division regardless of 58 | /// whether the algorithm being modelled is reflected. 59 | /// 60 | public long Poly; 61 | 62 | /// 63 | /// This is a boolean parameter. If it is FALSE, input bytes are 64 | /// processed with bit 7 being treated as the most significant bit 65 | /// (MSB) and bit 0 being treated as the least significant bit.If this 66 | /// parameter is FALSE, each byte is reflected before being processed. 67 | /// 68 | public boolean RefIn; 69 | 70 | /// 71 | /// This is a boolean parameter. If it is set to FALSE, the 72 | /// final value in the register is fed into the XOROUT stage directly, 73 | /// otherwise, if this parameter is TRUE, the final register value is 74 | /// reflected first. 75 | /// 76 | public boolean RefOut; 77 | 78 | /// 79 | /// This is an W-bit value that should be specified as a 80 | /// hexadecimal number.It is XORed to the final register value (after 81 | /// the REFOUT) stage before the value is returned as the official 82 | /// checksum. 83 | /// 84 | public long XorOut; 85 | } -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/checksum/CRCPolynomial.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ ** 7 | ** ** 8 | ** This library is free software; you can redistribute it and/or ** 9 | ** modify it under the terms of the GNU Lesser General Public ** 10 | ** License as published by the Free Software Foundation; either ** 11 | ** version 3.0 of the License, or (at your option) any later version. ** 12 | ** ** 13 | ** This library is distributed in the hope that it will be useful, ** 14 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 15 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** 16 | ** Lesser General Public License for more details. ** 17 | ** ** 18 | ** You should have received a copy of the GNU Lesser General Public ** 19 | ** License along with this library. ** 20 | \* */ 21 | package spinal.crypto.checksum 22 | 23 | 24 | import spinal.crypto._ 25 | import spinal.crypto.PolynomialGF2 26 | 27 | 28 | /** 29 | * Class used to define the configuration of a CRC 30 | * @param polynomial : CRC polynomial 31 | * @param initValue : init value of the CRC 32 | * @param inputReflected : if true the input is reflected (inverse) 33 | * @param outputReflected : if true the output is reflected (inverse) 34 | * @param finalXor : this value is xor with the ouptut result 35 | */ 36 | class CRCPolynomial( 37 | val polynomial : PolynomialGF2, 38 | val initValue : BigInt, 39 | val inputReflected : Boolean, 40 | val outputReflected : Boolean, 41 | val finalXor : BigInt 42 | ) 43 | 44 | 45 | /** 46 | * Define all CRC 32 47 | */ 48 | object CRC32 { 49 | def Standard = new CRCPolynomial(polynomial = p"32'x04C11DB7", initValue = BigInt("FFFFFFFF", 16), inputReflected = true, outputReflected = true, finalXor = BigInt("FFFFFFFF", 16)) 50 | def XFER = new CRCPolynomial(polynomial = p"32'x000000AF", initValue = BigInt("00000000", 16), inputReflected = false, outputReflected = false, finalXor = BigInt("00000000", 16)) 51 | } 52 | 53 | 54 | /** 55 | * Define all CRC 16 56 | */ 57 | object CRC16 { 58 | def XModem = new CRCPolynomial(polynomial = p"16'x1021", initValue = BigInt("0000", 16), inputReflected = false, outputReflected = false, finalXor = BigInt("0000", 16)) 59 | } 60 | 61 | 62 | /** 63 | * Define all CRC 8 64 | */ 65 | object CRC8 { 66 | def Standard = new CRCPolynomial(polynomial = p"8'x07", initValue = BigInt("00", 16), inputReflected = false, outputReflected = false, finalXor = BigInt("00", 16)) 67 | def DARC = new CRCPolynomial(polynomial = p"8'x39", initValue = BigInt("00", 16), inputReflected = true, outputReflected = true, finalXor = BigInt("00", 16)) 68 | } 69 | 70 | -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/padding/Padding.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.padding 27 | 28 | import spinal.core._ 29 | import spinal.lib._ 30 | 31 | 32 | /** 33 | * Base class for the padding configuration 34 | * @param dataInWidth width of the data from the command 35 | * @param dataOutWidth width of the data from the response 36 | * @param symbolInWidth symbol width of the command data 37 | */ 38 | class PaddingConfig( 39 | dataInWidth : BitCount, 40 | dataOutWidth : BitCount, 41 | symbolInWidth : BitCount 42 | ){ 43 | def getPaddingIOConfig = PaddingIOConfig( 44 | dataCmdWidth = dataInWidth, 45 | dataRspWidth = dataOutWidth, 46 | symbolWidth = symbolInWidth 47 | ) 48 | } 49 | 50 | 51 | case class PaddingIOConfig ( 52 | dataCmdWidth : BitCount, 53 | dataRspWidth : BitCount, 54 | symbolWidth : BitCount = 8 bits 55 | ) 56 | 57 | case class PaddingIO_Cmd(dataWidth: BitCount, symbolWidth: BitCount) extends Bundle{ 58 | val data = Bits(dataWidth) 59 | val size = UInt(log2Up(dataWidth.value / symbolWidth.value) bits) 60 | } 61 | 62 | case class PaddingIO_Rsp(dataWidth: BitCount) extends Bundle{ 63 | val data = Bits(dataWidth) 64 | } 65 | 66 | 67 | case class PaddingIO(config: PaddingIOConfig) extends Bundle with IMasterSlave{ 68 | 69 | val init = Bool 70 | val cmd = Stream(Fragment(PaddingIO_Cmd(config.dataCmdWidth, config.symbolWidth))) 71 | val rsp = Stream(Fragment(PaddingIO_Rsp(config.dataRspWidth))) 72 | 73 | override def asMaster(): Unit = { 74 | out(init) 75 | master(cmd) 76 | slave(rsp) 77 | } 78 | } -------------------------------------------------------------------------------- /tester/src/main/scala/ref/checksum/crc/Crc16.java: -------------------------------------------------------------------------------- 1 | package ref.checksum.crc; 2 | 3 | /** 4 | * Created by anthony on 15.05.2017. 5 | */ 6 | public class Crc16 { 7 | public static AlgoParams Crc16CcittFalse = new AlgoParams("CRC-16/CCITT-FALSE", 16, 0x1021, 0xFFFF, false, false, 0x0, 0x29B1); 8 | public static AlgoParams Crc16Arc = new AlgoParams("CRC-16/ARC", 16, 0x8005, 0x0, true, true, 0x0, 0xBB3D); 9 | public static AlgoParams Crc16AugCcitt = new AlgoParams("CRC-16/AUG-CCITT", 16, 0x1021, 0x1D0F, false, false, 0x0, 0xE5CC); 10 | public static AlgoParams Crc16Buypass = new AlgoParams("CRC-16/BUYPASS", 16, 0x8005, 0x0, false, false, 0x0, 0xFEE8); 11 | public static AlgoParams Crc16Cdma2000 = new AlgoParams("CRC-16/CDMA2000", 16, 0xC867, 0xFFFF, false, false, 0x0, 0x4C06); 12 | public static AlgoParams Crc16Dds110 = new AlgoParams("CRC-16/DDS-110", 16, 0x8005, 0x800D, false, false, 0x0, 0x9ECF); 13 | public static AlgoParams Crc16DectR = new AlgoParams("CRC-16/DECT-R", 16, 0x589, 0x0, false, false, 0x1, 0x7E); 14 | public static AlgoParams Crc16DectX = new AlgoParams("CRC-16/DECT-X", 16, 0x589, 0x0, false, false, 0x0, 0x7F); 15 | public static AlgoParams Crc16Dnp = new AlgoParams("CRC-16/DNP", 16, 0x3D65, 0x0, true, true, 0xFFFF, 0xEA82); 16 | public static AlgoParams Crc16En13757 = new AlgoParams("CRC-16/EN-13757", 16, 0x3D65, 0x0, false, false, 0xFFFF, 0xC2B7); 17 | public static AlgoParams Crc16Genibus = new AlgoParams("CRC-16/GENIBUS", 16, 0x1021, 0xFFFF, false, false, 0xFFFF, 0xD64E); 18 | public static AlgoParams Crc16Maxim = new AlgoParams("CRC-16/MAXIM", 16, 0x8005, 0x0, true, true, 0xFFFF, 0x44C2); 19 | public static AlgoParams Crc16Mcrf4Xx = new AlgoParams("CRC-16/MCRF4XX", 16, 0x1021, 0xFFFF, true, true, 0x0, 0x6F91); 20 | public static AlgoParams Crc16Riello = new AlgoParams("CRC-16/RIELLO", 16, 0x1021, 0xB2AA, true, true, 0x0, 0x63D0); 21 | public static AlgoParams Crc16T10Dif = new AlgoParams("CRC-16/T10-DIF", 16, 0x8BB7, 0x0, false, false, 0x0, 0xD0DB); 22 | public static AlgoParams Crc16Teledisk = new AlgoParams("CRC-16/TELEDISK", 16, 0xA097, 0x0, false, false, 0x0, 0xFB3); 23 | public static AlgoParams Crc16Tms37157 = new AlgoParams("CRC-16/TMS37157", 16, 0x1021, 0x89EC, true, true, 0x0, 0x26B1); 24 | public static AlgoParams Crc16Usb = new AlgoParams("CRC-16/USB", 16, 0x8005, 0xFFFF, true, true, 0xFFFF, 0xB4C8); 25 | public static AlgoParams CrcA = new AlgoParams("CRC-A", 16, 0x1021, 0xc6c6, true, true, 0x0, 0xBF05); 26 | public static AlgoParams Crc16Kermit = new AlgoParams("CRC-16/KERMIT", 16, 0x1021, 0x0, true, true, 0x0, 0x2189); 27 | public static AlgoParams Crc16Modbus = new AlgoParams("CRC-16/MODBUS", 16, 0x8005, 0xFFFF, true, true, 0x0, 0x4B37); 28 | public static AlgoParams Crc16X25 = new AlgoParams("CRC-16/X-25", 16, 0x1021, 0xFFFF, true, true, 0xFFFF, 0x906E); 29 | public static AlgoParams Crc16Xmodem = new AlgoParams("CRC-16/XMODEM", 16, 0x1021, 0x0, false, false, 0x0, 0x31C3); 30 | 31 | public static final AlgoParams[] Params = new AlgoParams[] 32 | { 33 | Crc16CcittFalse, 34 | Crc16Arc, 35 | Crc16AugCcitt, 36 | Crc16Buypass, 37 | Crc16Cdma2000, 38 | Crc16Dds110, 39 | Crc16DectR, 40 | Crc16DectX, 41 | Crc16Dnp, 42 | Crc16En13757, 43 | Crc16Genibus, 44 | Crc16Maxim, 45 | Crc16Mcrf4Xx, 46 | Crc16Riello, 47 | Crc16T10Dif, 48 | Crc16Teledisk, 49 | Crc16Tms37157, 50 | Crc16Usb, 51 | CrcA, 52 | Crc16Kermit, 53 | Crc16Modbus, 54 | Crc16X25, 55 | Crc16Xmodem, 56 | }; 57 | } -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/symmetric/sim/SymmetricIOsim.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.symmetric.sim 27 | 28 | import spinal.crypto._ 29 | 30 | import spinal.core._ 31 | import spinal.core.sim._ 32 | import spinal.crypto.symmetric._ 33 | 34 | import scala.util.Random 35 | 36 | 37 | 38 | object SymmetricCryptoBlockIOSim { 39 | 40 | /** 41 | * Initialize the IO with random value 42 | */ 43 | def initializeIO(dut: SymmetricCryptoBlockIO): Unit ={ 44 | dut.cmd.valid #= false 45 | dut.cmd.block.randomize() 46 | dut.cmd.key.randomize() 47 | if(dut.config.useEncDec) dut.cmd.enc.randomize() 48 | } 49 | 50 | 51 | /** 52 | * Symmetric Crypto Block IO simulation 53 | */ 54 | def doSim(dut: SymmetricCryptoBlockIO, clockDomain: ClockDomain, enc: Boolean, blockIn: BigInt = null, keyIn: BigInt = null)(refCrypto: (BigInt, BigInt, Boolean) => BigInt ): Unit ={ 55 | 56 | // Generate random input 57 | val block_in = if(blockIn == null) BigInt(dut.cmd.block.getWidth, Random) else blockIn 58 | val key = if(keyIn == null) BigInt(dut.cmd.key.getWidth, Random) else keyIn 59 | 60 | // Send command 61 | dut.cmd.valid #= true 62 | dut.cmd.block #= block_in 63 | dut.cmd.key #= key 64 | if(dut.config.useEncDec) dut.cmd.enc #= enc 65 | 66 | clockDomain.waitActiveEdge() 67 | 68 | // Wait response 69 | waitUntil(dut.rsp.valid.toBoolean == true) 70 | 71 | val rtlBlock_out = dut.rsp.block.toBigInt 72 | val refBlock_out = refCrypto(key, block_in, enc) 73 | 74 | // Check result 75 | assert(BigInt(rtlBlock_out.toByteArray.takeRight(dut.cmd.block.getWidth / 8)) == BigInt(refBlock_out.toByteArray.takeRight(dut.cmd.block.getWidth / 8)) , s"Wrong result RTL ${BigIntToHexString(rtlBlock_out)} != REF ${BigIntToHexString(refBlock_out)}") 76 | 77 | 78 | // release the command valid between each transaction randomly 79 | clockDomain.waitActiveEdge() 80 | 81 | if(Random.nextBoolean()){ 82 | initializeIO(dut) 83 | 84 | clockDomain.waitActiveEdge() 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/hash/sha3/SHA3Core_Std.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.hash.sha3 27 | 28 | import spinal.core._ 29 | import spinal.crypto.construtor.{SpongeCore_Std} 30 | import spinal.crypto.hash.{HashCoreConfig, HashCoreIO} 31 | import spinal.crypto.padding.{Pad_xB_1_Std, Padding_xB_1_Config} 32 | import spinal.crypto.primitive.keccak.KeccakF_Std 33 | import spinal.lib._ 34 | 35 | /** 36 | * SHA-3 Core STD 37 | * 38 | * @param sha3Type SHA3 type 39 | * @param dataWidth Input data width 40 | */ 41 | class SHA3Core_Std(sha3Type: SHA3_Type, dataWidth: BitCount = 32 bits) extends Component { 42 | 43 | val configCore = HashCoreConfig( 44 | dataWidth = dataWidth, 45 | hashWidth = sha3Type.hashWidth bits, 46 | hashBlockWidth = 0 bits 47 | ) 48 | 49 | /** IO */ 50 | val io = slave(HashCoreIO(configCore)) 51 | 52 | val padding = new Pad_xB_1_Std(Padding_xB_1_Config(dataInWidth = dataWidth, dataOutWidth = sha3Type.r bits, pad_xB = 0x06)) 53 | val sponge = new SpongeCore_Std(capacity = sha3Type.c, rate = sha3Type.r, d = sha3Type.hashComputationWidth) 54 | val func = new KeccakF_Std(sha3Type.c + sha3Type.r) 55 | 56 | 57 | // io <-> padding 58 | padding.io.cmd.valid := io.cmd.valid 59 | padding.io.cmd.data := io.cmd.msg 60 | padding.io.cmd.last := io.cmd.last 61 | padding.io.cmd.size := io.cmd.size 62 | io.cmd.ready := padding.io.cmd.ready 63 | 64 | padding.io.init := io.init 65 | 66 | // padding <-> sponge 67 | sponge.io.cmd.valid := padding.io.rsp.valid 68 | sponge.io.cmd.last := padding.io.rsp.last 69 | sponge.io.cmd.n := Cat(padding.io.rsp.data.subdivideIn(64 bits).map(EndiannessSwap(_))) 70 | padding.io.rsp.ready := sponge.io.cmd.ready 71 | 72 | sponge.io.init := io.init 73 | 74 | // sponge <-> func 75 | sponge.io.func <> func.io 76 | 77 | // sponge <-> io 78 | io.rsp.valid := padding.io.cmd.ready & sponge.io.cmd.last 79 | io.rsp.digest := Cat(sponge.io.rsp.z.subdivideIn(64 bits).map(EndiannessSwap(_))).asBits.resizeLeft(sha3Type.hashWidth) 80 | } 81 | 82 | 83 | -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/Utils.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto 27 | 28 | import scala.collection.mutable.ListBuffer 29 | 30 | 31 | /** 32 | * Polynomial in Galois Field 2 33 | */ 34 | class PolynomialGF2(val coefficient: List[Int]) { 35 | 36 | def ==(that: PolynomialGF2): Boolean = this.coefficient.sorted == that.coefficient.sorted 37 | def !=(that: PolynomialGF2): Boolean = !(this == that) 38 | 39 | def order: Int = coefficient.max 40 | 41 | 42 | override def toString: String = { 43 | (for(coef <- coefficient) yield coef match{ 44 | case 0 => "1" 45 | case 1 => "x" 46 | case _ => s"x^$coef" 47 | }).mkString(" + ") 48 | } 49 | 50 | /** 51 | * Return a list of boolean representing the polynomial 52 | */ 53 | def toBooleanList(): List[Boolean] = { 54 | 55 | val listBuffer = ListBuffer[Boolean]() 56 | 57 | for(i <- 0 to coefficient.max){ 58 | listBuffer.append(coefficient.contains(i)) 59 | } 60 | 61 | return listBuffer.toList.reverse 62 | } 63 | } 64 | 65 | 66 | /** 67 | * Transform a BigInt value into a hexadecimal string 68 | */ 69 | object BigIntToHexString { 70 | def apply(value: BigInt): String = s"0x${value.toByteArray.map(b => f"${b}%02X").mkString("")}" 71 | } 72 | 73 | 74 | /** 75 | * Change endianness on Array[Byte] 76 | */ 77 | object Endianness { 78 | def apply(input: Array[Byte]): Array[Byte] = { 79 | assert(input.length % 4 == 0, s"Endianess input is not a multiple of 4 (current length ${input.length}) ") 80 | return input.grouped(4).flatMap(_.reverse.toList).toArray 81 | } 82 | } 83 | 84 | /** 85 | * Cast a Byte Array 86 | */ 87 | object CastByteArray { 88 | def apply(input: Array[Byte], castSize: Int): Array[Byte] = { 89 | if (input.length == castSize) { 90 | input 91 | } else if (input.length > castSize) { 92 | input.takeRight(castSize) 93 | } else { 94 | Array.fill[Byte](castSize - input.length)(0x00) ++ input 95 | } 96 | } 97 | } 98 | 99 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/primitive/keccak/Keccak.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.primitive.keccak 27 | 28 | import scala.collection.mutable 29 | 30 | object Keccak { 31 | 32 | /** 33 | * The rotation offsets r[x,y] 34 | */ 35 | private var pRawOffset : mutable.LinkedHashMap[(Int, Int), Int] = mutable.LinkedHashMap((0,0) -> 0) 36 | 37 | 38 | /** 39 | * Precompute the map pRawOffset 40 | * 41 | * 1. For all z such that 0≤z ((t + 1) * (t + 2)) / 2) 54 | 55 | val tmpX = x 56 | x = y 57 | y = (2 * tmpX + 3 * y) % 5 58 | } 59 | } 60 | 61 | initRawOffset() 62 | 63 | 64 | def pOffset(x: Int, y: Int, modulo: Int): Int = { 65 | return pRawOffset.get((x, y)).get % modulo 66 | } 67 | 68 | 69 | /** 70 | * The round constants RC[i] are given in the table below for the maximum lane size 64. 71 | * For smaller sizes, they are simply truncated. 72 | */ 73 | def RC : List[BigInt] = List( 74 | BigInt("0000000000000001", 16), BigInt("0000000000008082", 16), 75 | BigInt("800000000000808A", 16), BigInt("8000000080008000", 16), 76 | BigInt("000000000000808B", 16), BigInt("0000000080000001", 16), 77 | BigInt("8000000080008081", 16), BigInt("8000000000008009", 16), 78 | BigInt("000000000000008A", 16), BigInt("0000000000000088", 16), 79 | BigInt("0000000080008009", 16), BigInt("000000008000000A", 16), 80 | BigInt("000000008000808B", 16), BigInt("800000000000008B", 16), 81 | BigInt("8000000000008089", 16), BigInt("8000000000008003", 16), 82 | BigInt("8000000000008002", 16), BigInt("8000000000000080", 16), 83 | BigInt("000000000000800A", 16), BigInt("800000008000000A", 16), 84 | BigInt("8000000080008081", 16), BigInt("8000000000008080", 16), 85 | BigInt("0000000080000001", 16), BigInt("8000000080008008", 16) 86 | ) 87 | 88 | 89 | 90 | } 91 | -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/hash/md5/MD5.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.hash.md5 27 | 28 | import spinal.core._ 29 | import scala.math.{pow, sin} 30 | 31 | 32 | /** 33 | * MD5Core Specification 34 | */ 35 | object MD5 { 36 | 37 | /** Size of a message block */ 38 | def blockWidth = 512 bits 39 | /** Size of the A B C D block */ 40 | def subBlockWidth = 32 bits 41 | /** Digest message */ 42 | def hashWidth = 128 bits 43 | /** Total number of iterations */ 44 | def nbrIteration = 4 * 16 45 | /** Width of the counter of bit */ 46 | def cntBitWidth = 64 bits 47 | 48 | 49 | def initBlock = Vec(B"x67452301", B"xEFCDAB89", B"x98BADCFE", B"x10325476") 50 | 51 | 52 | def funcF(b: Bits, c: Bits, d: Bits): Bits = (b & c) | (~b & d) 53 | def funcG(b: Bits, c: Bits, d: Bits): Bits = (b & d) | (~d & c) 54 | def funcH(b: Bits, c: Bits, d: Bits): Bits = b ^ c ^ d 55 | def funcI(b: Bits, c: Bits, d: Bits): Bits = c ^ (b | ~d) 56 | 57 | 58 | /** T[i] := floor(2^32 × abs(sin(i + 1))) */ 59 | def constantT: List[BigInt] = for(i <- List.range(0,64)) yield BigDecimal((pow(2,32) * sin(i + 1.0).abs)).toBigInt 60 | 61 | 62 | /** 63 | * ShiftValue is used to know how much left rotation must be done 64 | * Original array : 65 | * 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 66 | * 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 67 | * 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 68 | * 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21) 69 | */ 70 | def shiftCstS: List[Int] = List(7, 12, 17, 22, 5, 9, 14, 20, 4, 11, 16, 23, 6, 10, 15, 21) 71 | 72 | 73 | /** 74 | * Index K is used to select a word in the 512-bit of the message block 75 | * 0 .. 15 : index = i 76 | * 16 .. 31 : index = 5 * i + 1 mod 16 77 | * 32 .. 47 : index = 3 * i + 5 mod 16 78 | * 63 .. 34 : index = 7 * i mod 16 79 | */ 80 | def indexK: List[Int] = for(i <- List.range(0, 64)) yield if (i < 16) i 81 | else if (i < 32) (5 * i + 1) % 16 82 | else if (i < 48) (3 * i + 5) % 16 83 | else (7 * i) % 16 84 | } 85 | -------------------------------------------------------------------------------- /tester/src/main/scala/cryptotest/SpinalSimHMACCoreStdTester.scala: -------------------------------------------------------------------------------- 1 | package cryptotest 2 | 3 | 4 | import org.scalatest.funsuite.AnyFunSuite 5 | import ref.mac.HMAC 6 | import spinal.core._ 7 | import spinal.crypto.{BigIntToHexString, CastByteArray, Endianness} 8 | import spinal.crypto.hash.md5.MD5Core_Std 9 | import spinal.crypto.mac.hmac.{HMACCoreStdConfig, HMACCoreStdIO, HMACCore_Std} 10 | import spinal.lib.slave 11 | import spinal.sim._ 12 | import spinal.core.sim._ 13 | 14 | import scala.util.Random 15 | 16 | 17 | class HMACCoreStd_MD5_Tester() extends Component { 18 | 19 | val md5 = new MD5Core_Std() 20 | val hmac = new HMACCore_Std(HMACCoreStdConfig(md5.configCore.hashBlockWidth, md5.configCore)) 21 | 22 | val io = slave(HMACCoreStdIO(hmac.config)) 23 | 24 | hmac.io.hmacCore <> io 25 | hmac.io.hashCore <> md5.io 26 | } 27 | 28 | 29 | 30 | class SpinalSimHMACCoreStdTester extends AnyFunSuite { 31 | 32 | // RTL to simulate 33 | val compiledRTL = SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new HMACCoreStd_MD5_Tester()) 34 | 35 | val NBR_ITERATION = 200 36 | 37 | /** 38 | * Test 39 | */ 40 | test("HMACCoreStd_MD5"){ 41 | 42 | compiledRTL.doSim{ dut => 43 | 44 | val byteSizeMsg = dut.io.cmd.msg.getWidth / 8 45 | 46 | dut.clockDomain.forkStimulus(2) 47 | 48 | // initialize value 49 | dut.io.init #= false 50 | dut.io.cmd.valid #= false 51 | 52 | dut.clockDomain.waitActiveEdge() 53 | 54 | var lenMsg = 1 55 | 56 | for(_ <- 0 to NBR_ITERATION){ 57 | 58 | var msgStr = (List.fill(lenMsg)(Random.nextPrintableChar()).mkString("")) 59 | val keyStr = (List.fill(64)(Random.nextPrintableChar()).mkString("")) 60 | 61 | // var msgStr = """RYWc/tA]1iG""" 62 | // val keyStr = """0,m,U/s_^}<.|?<&DnTk#0q_R5-:,L*""" 63 | 64 | val msgStrOrginal = msgStr 65 | 66 | 67 | val refHmac = HMAC.digest(msgStr, keyStr, "HmacMD5") 68 | 69 | val keyByte = Endianness((keyStr.map(_.toByte).toList ::: List.fill(((dut.io.cmd.key.getWidth / 4) - keyStr.length * 2) / 2 )(0.toByte)).toArray) 70 | 71 | // init HMAC 72 | dut.clockDomain.waitActiveEdge() 73 | dut.io.init #= true 74 | dut.clockDomain.waitActiveEdge() 75 | dut.io.init #= false 76 | dut.clockDomain.waitActiveEdge() 77 | 78 | // number of iteration 79 | var index = math.ceil(msgStr.length / byteSizeMsg.toDouble).toInt 80 | 81 | // Send all block of message 82 | while(index != 0) { 83 | 84 | val (msg, isLast) = if (msgStr.length > byteSizeMsg) (msgStr.substring(0, byteSizeMsg) -> false) else (msgStr + 0.toChar.toString * (byteSizeMsg - msgStr.length) -> true) 85 | 86 | val msgByte = Endianness(msg.map(_.toByte).toArray) 87 | 88 | dut.io.cmd.valid #= true 89 | dut.io.cmd.msg #= BigInt(0x00.toByte +: msgByte) 90 | dut.io.cmd.size #= BigInt(if (isLast) msgStr.length - 1 else 0) 91 | dut.io.cmd.last #= isLast 92 | dut.io.cmd.key #= BigInt(0x00.toByte +: keyByte) 93 | 94 | 95 | // Wait the response 96 | if (isLast){ 97 | waitUntil(dut.io.rsp.valid.toBoolean == true) 98 | 99 | val rtlHmac = CastByteArray(dut.io.rsp.hmac.toBigInt.toByteArray, dut.io.rsp.hmac.getWidth / 8) 100 | 101 | assert( 102 | refHmac == BigInt(Endianness(rtlHmac)), 103 | s""" 104 | | REF != RTL : ${BigIntToHexString(refHmac)} != ${BigIntToHexString(BigInt(0x00.toByte +: Endianness(rtlHmac)))}" 105 | | Input message : ${msgStrOrginal} 106 | | Key : ${keyStr} 107 | """.stripMargin 108 | ) 109 | 110 | dut.clockDomain.waitActiveEdge() 111 | }else { 112 | waitUntil(dut.io.cmd.ready.toBoolean == true) 113 | 114 | dut.clockDomain.waitActiveEdge() 115 | } 116 | 117 | // randomize the release of teh cmd.valid 118 | dut.io.cmd.valid #= false 119 | dut.clockDomain.waitActiveEdge() 120 | 121 | 122 | index -= 1 123 | msgStr = msgStr.drop(byteSizeMsg) 124 | } 125 | 126 | lenMsg += 1 127 | } 128 | } 129 | } 130 | } -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/symmetric/Symmetric.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.symmetric 27 | 28 | import spinal.core._ 29 | import spinal.lib._ 30 | import spinal.lib.bus.misc.BusSlaveFactory 31 | 32 | 33 | /** 34 | * Symmetric Crypto block generiics 35 | * @param keyWidth Key width 36 | * @param blockWidth Block width 37 | * @param useEncDec Create a signal for the encryption/decryption 38 | */ 39 | case class SymmetricCryptoBlockConfig( 40 | keyWidth : BitCount, 41 | blockWidth : BitCount, 42 | useEncDec : Boolean = true 43 | ) 44 | 45 | 46 | /** 47 | * Command interface for a symmetric block algo 48 | */ 49 | case class SymmetricCryptoBlockCmd(config: SymmetricCryptoBlockConfig) extends Bundle { 50 | val key = Bits(config.keyWidth) 51 | val block = Bits(config.blockWidth) 52 | val enc = if(config.useEncDec) Bool else null 53 | } 54 | 55 | 56 | /** 57 | * Response interface for a symmetric block algo 58 | */ 59 | case class SymmetricCryptoBlockRsp(config: SymmetricCryptoBlockConfig) extends Bundle { 60 | val block = Bits(config.blockWidth) 61 | } 62 | 63 | 64 | /** 65 | * Interface used by a symmetric block algo 66 | */ 67 | case class SymmetricCryptoBlockIO(config: SymmetricCryptoBlockConfig) extends Bundle with IMasterSlave { 68 | 69 | val cmd = Stream(SymmetricCryptoBlockCmd(config)) 70 | val rsp = Flow(SymmetricCryptoBlockRsp(config)) 71 | 72 | override def asMaster() = { 73 | master(cmd) 74 | slave(rsp) 75 | } 76 | 77 | /** Drive IO from a bus */ 78 | def driveFrom(busCtrl: BusSlaveFactory, baseAddress: Int = 0) = new Area { 79 | 80 | var addr = baseAddress 81 | 82 | /* Write operation */ 83 | 84 | busCtrl.driveMultiWord(cmd.key, addr) 85 | addr += (widthOf(cmd.key)/32)*4 86 | 87 | busCtrl.driveMultiWord(cmd.block, addr) 88 | addr += (widthOf(cmd.block)/32)*4 89 | 90 | if(config.useEncDec) busCtrl.drive(cmd.enc, addr) 91 | addr += 4 92 | 93 | val validReg = busCtrl.drive(cmd.valid, addr) init(False) 94 | validReg.clearWhen(cmd.ready) 95 | addr += 4 96 | 97 | /* Read operation */ 98 | 99 | val block = Reg(cloneOf(rsp.block)) 100 | val rspValid = Reg(Bool) init(False) setWhen(rsp.valid) 101 | 102 | when(rsp.valid){ 103 | block := rsp.block 104 | } 105 | 106 | busCtrl.onRead(addr){ 107 | when(rspValid){ 108 | rspValid := False 109 | } 110 | } 111 | 112 | busCtrl.read(rspValid, addr) 113 | addr += 4 114 | 115 | busCtrl.readMultiWord(block, addr) 116 | addr += (widthOf(block)/32)*4 117 | 118 | 119 | //manage interrupts 120 | val interruptCtrl = new Area { 121 | val doneIntEnable = busCtrl.createReadAndWrite(Bool, address = addr, 0) init(False) 122 | val doneInt = doneIntEnable & !rsp.valid 123 | val interrupt = doneInt 124 | } 125 | } 126 | } -------------------------------------------------------------------------------- /tester/src/main/scala/cryptotest/SpinalSimLFSRTester.scala: -------------------------------------------------------------------------------- 1 | package cryptotest 2 | 3 | 4 | import org.scalatest.funsuite.AnyFunSuite 5 | import spinal.core._ 6 | import spinal.core.sim._ 7 | import spinal.crypto.misc.LFSR 8 | 9 | import scala.collection.mutable.ListBuffer 10 | 11 | 12 | case class LFSR_IO_TEST() extends Bundle{ 13 | val init = in Bool() 14 | val seed = in Bits(8 bits) 15 | val inc = in Bool() 16 | val value = out Bits(8 bits) 17 | } 18 | 19 | object LFSR_IO_SIM{ 20 | 21 | def initializeIO(dut: LFSR_IO_TEST): Unit ={ 22 | dut.init #= false 23 | dut.seed.randomize() 24 | dut.inc #= false 25 | } 26 | 27 | def doSim(dut: LFSR_IO_TEST, clockDomain: ClockDomain, order_poly: Int, extended: Boolean): Unit = { 28 | 29 | val lfsr_buf = new ListBuffer[BigInt]() 30 | 31 | // init 32 | dut.init #= true 33 | dut.seed #= 1 34 | 35 | clockDomain.waitActiveEdge() 36 | dut.init #= false 37 | 38 | clockDomain.waitActiveEdge() 39 | dut.inc #= true 40 | 41 | // iteration 42 | val iteration = if(extended) math.pow(2, order_poly).toInt else math.pow(2, order_poly).toInt - 1 43 | 44 | for(_ <- 0 until iteration){ 45 | clockDomain.waitActiveEdge() 46 | 47 | val value = dut.value.toBigInt 48 | 49 | assert(!lfsr_buf.contains(value), s"Duplicate value found ${lfsr_buf.length} -> ${lfsr_buf}") 50 | 51 | lfsr_buf.append(value) 52 | } 53 | 54 | 55 | assert(lfsr_buf.length == iteration , "Not enough or too many number generated") 56 | } 57 | } 58 | 59 | 60 | /** 61 | * LFSR Fibonacci and Galois 62 | */ 63 | class LFSRTester(lfsr: (Bits) => (Bits)) extends Component { 64 | 65 | val io = LFSR_IO_TEST() 66 | 67 | val lfsr_reg = Reg(cloneOf(io.value)) 68 | 69 | when(io.init) { 70 | lfsr_reg := io.seed 71 | } 72 | 73 | when(io.inc) { 74 | lfsr_reg := lfsr(lfsr_reg) 75 | } 76 | 77 | io.value := lfsr_reg 78 | } 79 | 80 | 81 | 82 | class SpinalSimLFSRTester extends AnyFunSuite { 83 | 84 | // RTL to simulate 85 | val compiledRTL_galois = SimConfig.compile(new LFSRTester((reg: Bits) => LFSR.Galois(reg, LFSR.polynomial_8bits))) 86 | val compiledRTL_galois_ext = SimConfig.compile(new LFSRTester((reg: Bits) => LFSR.Galois(reg, LFSR.polynomial_8bits, LFSR.XOR, true))) 87 | val compiledRTL_galois_xnor = SimConfig.compile(new LFSRTester((reg: Bits) => LFSR.Galois(reg, LFSR.polynomial_8bits, LFSR.XNOR, false))) 88 | 89 | val compiledRTL_fibonacci = SimConfig.compile(new LFSRTester((reg: Bits) => LFSR.Fibonacci(reg, LFSR.polynomial_8bits))) 90 | val compiledRTL_fibonacci_ext = SimConfig.compile(new LFSRTester((reg: Bits) => LFSR.Fibonacci(reg, LFSR.polynomial_8bits, LFSR.XOR, true))) 91 | 92 | 93 | /** 94 | * Test - Galois 95 | */ 96 | test("LFSR_Galois"){ 97 | 98 | compiledRTL_galois.doSim{ dut => 99 | 100 | dut.clockDomain.forkStimulus(2) 101 | 102 | // initialize value 103 | LFSR_IO_SIM.initializeIO(dut.io) 104 | 105 | dut.clockDomain.waitActiveEdge() 106 | 107 | LFSR_IO_SIM.doSim(dut.io, dut.clockDomain, order_poly = 8, extended = false) 108 | 109 | } 110 | } 111 | 112 | 113 | /** 114 | * Test - Galois 115 | */ 116 | test("LFSR_Galois_ext"){ 117 | 118 | compiledRTL_galois_ext.doSim{ dut => 119 | 120 | dut.clockDomain.forkStimulus(2) 121 | 122 | // initialize value 123 | LFSR_IO_SIM.initializeIO(dut.io) 124 | 125 | dut.clockDomain.waitActiveEdge() 126 | 127 | LFSR_IO_SIM.doSim(dut.io, dut.clockDomain, order_poly = 8, extended = true) 128 | 129 | } 130 | } 131 | 132 | /** 133 | * Test - Galois 134 | */ 135 | test("LFSR_Galois_xnor"){ 136 | 137 | compiledRTL_galois_xnor.doSim{ dut => 138 | 139 | dut.clockDomain.forkStimulus(2) 140 | 141 | // initialize value 142 | LFSR_IO_SIM.initializeIO(dut.io) 143 | 144 | dut.clockDomain.waitActiveEdge() 145 | 146 | LFSR_IO_SIM.doSim(dut.io, dut.clockDomain, order_poly = 8, extended = false) 147 | 148 | } 149 | } 150 | 151 | 152 | /** 153 | * Test - Fibonacci 154 | */ 155 | test("LFSR_fibonacci"){ 156 | 157 | compiledRTL_fibonacci.doSim{ dut => 158 | 159 | dut.clockDomain.forkStimulus(2) 160 | 161 | // initialize value 162 | LFSR_IO_SIM.initializeIO(dut.io) 163 | 164 | dut.clockDomain.waitActiveEdge() 165 | 166 | LFSR_IO_SIM.doSim(dut.io, dut.clockDomain, order_poly = 8, extended = false) 167 | 168 | } 169 | } 170 | 171 | 172 | /** 173 | * Test - Fibonacci 174 | */ 175 | test("LFSR_fibonacci_ext"){ 176 | 177 | compiledRTL_fibonacci_ext.doSim{ dut => 178 | 179 | dut.clockDomain.forkStimulus(2) 180 | 181 | // initialize value 182 | LFSR_IO_SIM.initializeIO(dut.io) 183 | 184 | dut.clockDomain.waitActiveEdge() 185 | 186 | LFSR_IO_SIM.doSim(dut.io, dut.clockDomain, order_poly = 8, extended = true) 187 | 188 | } 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/hash/sim/HashIOsim.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.hash.sim 27 | 28 | 29 | import spinal.core._ 30 | import spinal.core.sim._ 31 | import spinal.crypto._ 32 | import spinal.crypto.hash.{LITTLE_endian, EndiannessMode, HashCoreIO} 33 | 34 | import scala.util.Random 35 | 36 | 37 | object HashIOsim { 38 | 39 | def initializeIO(dut: HashCoreIO): Unit ={ 40 | dut.init #= false 41 | dut.cmd.valid #= false 42 | dut.cmd.msg.randomize() 43 | dut.cmd.size.randomize() 44 | dut.cmd.last.randomize() 45 | } 46 | 47 | 48 | def doSim(dut: HashCoreIO, clockDomain: ClockDomain, lengthString: Int, endianess: EndiannessMode, msg: String = null)(refCrypto: (String) => Array[Byte]): Unit = { 49 | 50 | val byteSizeMsg = dut.cmd.msg.getWidth / 8 51 | 52 | // init Hash 53 | clockDomain.waitActiveEdge() 54 | dut.init #= true 55 | clockDomain.waitActiveEdge() 56 | dut.init #= false 57 | clockDomain.waitActiveEdge() 58 | 59 | // Generate a random message + compute the reference hash 60 | var msgHex = if(msg == null) List.fill(lengthString)(Random.nextPrintableChar()).mkString("") else msg 61 | val refDigest = refCrypto(msgHex) 62 | 63 | // number of iteration 64 | var index = math.ceil(msgHex.length / byteSizeMsg.toDouble).toInt 65 | 66 | // Send all block of message 67 | while(index != 0) { 68 | 69 | val (msg, isLast) = if (msgHex.length > byteSizeMsg) (msgHex.substring(0, byteSizeMsg) -> false) else (msgHex + 0.toChar.toString * (byteSizeMsg - msgHex.length) -> true) 70 | 71 | dut.cmd.valid #= true 72 | dut.cmd.msg #= BigInt(0x00.toByte +: (if(endianess == LITTLE_endian) (msg.map(_.toByte).reverse.toArray) else (msg.map(_.toByte).toArray)) )// Add 00 in front in order to get a positif number 73 | dut.cmd.size #= BigInt(if (isLast) msgHex.length - 1 else 0) 74 | dut.cmd.last #= isLast 75 | 76 | clockDomain.waitActiveEdge() 77 | 78 | // Wait the response 79 | if (isLast){ 80 | waitUntil(dut.rsp.valid.toBoolean == true) 81 | 82 | val rtlDigest = CastByteArray(dut.rsp.digest.toBigInt.toByteArray, dut.rsp.digest.getWidth) 83 | 84 | if(endianess == LITTLE_endian){ 85 | assert(CastByteArray(refDigest, dut.rsp.digest.getWidth).sameElements(Endianness(rtlDigest)), s"REF != RTL ${BigIntToHexString(BigInt(refDigest))} != ${BigIntToHexString(BigInt(Endianness(rtlDigest)))}") 86 | }else{ 87 | assert(CastByteArray(refDigest, dut.rsp.digest.getWidth).sameElements(rtlDigest), s"REF != RTL ${BigIntToHexString(BigInt(refDigest))} != ${BigIntToHexString(BigInt(rtlDigest))}") 88 | } 89 | 90 | 91 | clockDomain.waitActiveEdge() 92 | }else { 93 | waitUntil(dut.cmd.ready.toBoolean == true) 94 | } 95 | 96 | initializeIO(dut) 97 | 98 | clockDomain.waitActiveEdge() 99 | 100 | index -= 1 101 | msgHex = msgHex.drop(byteSizeMsg) 102 | } 103 | } 104 | } 105 | 106 | -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/devtype/GaloisField.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.devtype 27 | 28 | import spinal.core._ 29 | import spinal.crypto._ 30 | 31 | 32 | object GaloisField{ 33 | 34 | /** 35 | * XTimes function (used for the multiplication) 36 | * 37 | * e.g: GF4 with polynomial x^4 + x + 1 38 | * Input 39 | * _______________|_________________ 40 | * |_b3_|_b2______________________b0_| 41 | * ____/_______/_______/________/___ 42 | * |_b2_|_____________________b0_|_0_| 43 | * | 44 | * poly: 00b3b3 --->XOR 45 | * | 46 | * Output 47 | */ 48 | private def xtimes(data: DBits, polynomial: List[Boolean]): DBits = { 49 | (data |<< 1) ^ DBits(polynomial.reverse.init, data.msb) 50 | } 51 | 52 | 53 | /** 54 | * Multiplication between two Galois field number 55 | */ 56 | def multiplication(operand1: DBits, operand2: DBits, poly: PolynomialGF2): DBits = { 57 | 58 | val polynomial = poly.toBooleanList() 59 | 60 | assert(polynomial.length == operand1.getWidth + 1, "Polynomial must be of the same order than operands") 61 | assert(operand1.getWidth == operand2.getWidth, "The size of the operands are different") 62 | 63 | var tmp = operand1 64 | var result = DBits("Bits", operand1.getWidth bits) 65 | 66 | for(i <- 0 until operand1.getWidth){ 67 | 68 | val andOperand = DBits(List.fill(operand1.getWidth)(true), operand2(i)) 69 | 70 | if(i==0){ 71 | result = andOperand & tmp 72 | }else{ 73 | tmp = xtimes(tmp, polynomial) 74 | result = (andOperand & tmp) ^ result 75 | } 76 | } 77 | 78 | result 79 | } 80 | } 81 | 82 | /** 83 | * Galois field base class 84 | */ 85 | abstract class GaloisField(val value: Bits, val poly: PolynomialGF2) extends Bundle { 86 | 87 | val field: Int = poly.coefficient.max 88 | 89 | assert(value.getWidth == field, s"GF$field support only Bits on $field bits ") 90 | 91 | type T <: GaloisField 92 | 93 | def newGF(v: Bits): T 94 | 95 | def *(that: T): T = { 96 | assert(this.poly == that.poly, "Irreducible polynomial is not the same") 97 | newGF(GaloisField.multiplication(DBits("a", this.value), DBits("b", that.value), poly).toBits) 98 | } 99 | 100 | def *(that: BigInt): T = { 101 | assert(log2Up(that) <= this.field, s"that is bigger than $field bits") 102 | newGF(GaloisField.multiplication(DBits("a", this.value), DBitsLiteral(that, this.field bits), poly).toBits) 103 | } 104 | 105 | 106 | def +(that: T): T = newGF(this.value ^ that.value) 107 | def -(that: T): T = this + that 108 | 109 | def ^(that: T): T = this + that 110 | 111 | 112 | def toBits(): Bits = this.value 113 | } 114 | 115 | 116 | case class GF4(v: Bits)(implicit poly: PolynomialGF2) extends GaloisField(v, poly){ 117 | 118 | override type T = GF4 119 | 120 | def newGF(v: Bits): GF4 = new GF4(v) 121 | } 122 | 123 | 124 | case class GF8(v: Bits)(implicit poly: PolynomialGF2) extends GaloisField(v, poly){ 125 | 126 | override type T = GF8 127 | 128 | def newGF(v: Bits): GF8 = new GF8(v) 129 | } -------------------------------------------------------------------------------- /tester/src/main/scala/ref/symmetric/Symmetric.scala: -------------------------------------------------------------------------------- 1 | package ref.symmetric 2 | 3 | import java.security.SecureRandom 4 | import javax.crypto.{Cipher, KeyGenerator} 5 | import javax.crypto.spec.{IvParameterSpec, SecretKeySpec} 6 | 7 | import spinal.crypto.{BigIntToHexString, CastByteArray} 8 | 9 | import scala.util.Random 10 | 11 | 12 | 13 | 14 | 15 | /** 16 | * DES 17 | */ 18 | object DES { 19 | 20 | def block(verbose: Boolean)(key: BigInt, block: BigInt, enc: Boolean) = { 21 | if(enc) { 22 | Symmetric.block( 23 | key = key, 24 | block = block, 25 | blockSize = 8, 26 | keySize = 8, 27 | algoName = "DES", 28 | chainning = "ECB", 29 | padding = "NoPadding", 30 | enc = true, 31 | verbose = verbose) 32 | } else { 33 | Symmetric.block( 34 | key = key, 35 | block = block, 36 | blockSize = 8, 37 | keySize = 8, 38 | algoName = "DES", 39 | chainning = "ECB", 40 | padding = "NoPadding", 41 | enc = false, 42 | verbose = verbose) 43 | } 44 | } 45 | 46 | def blockRaw(verbose: Boolean)(key: Array[Byte], block: Array[Byte], iv: Array[Byte], enc: Boolean, algoName: String, chainning: String, padding: String): Array[Byte] = { 47 | 48 | // Cast the input key 49 | val keyAlgo = new SecretKeySpec(key, algoName) 50 | 51 | // iv 52 | val dpIV = new IvParameterSpec(iv) 53 | 54 | // Create the cipher 55 | val algorithm = Cipher.getInstance(s"$algoName/$chainning/$padding") 56 | 57 | // Initialize the cipher for encryption 58 | algorithm.init(if(enc) Cipher.ENCRYPT_MODE else Cipher.DECRYPT_MODE, keyAlgo, dpIV) 59 | 60 | // cast input block 61 | val block_in = block 62 | 63 | // Encrypt the text 64 | val block_out = algorithm.doFinal(block_in) 65 | 66 | if(verbose){ 67 | println(s"Block_in : 0x${block_in.map(b => "%02X".format(b)).mkString("")}") 68 | println(s"Key : 0x${keyAlgo.getEncoded().map(b => "%02X".format(b)).mkString("")}") 69 | println(s"Block_out : 0x${block_out.map(b => "%02X".format(b)).mkString("")}") 70 | println("") 71 | } 72 | 73 | return block_out 74 | } 75 | } 76 | 77 | 78 | /** 79 | * Triple DES 80 | */ 81 | object TripleDES { 82 | 83 | def block(verbose: Boolean)(key: BigInt, block: BigInt, enc: Boolean) = { 84 | if(enc) { 85 | Symmetric.block( 86 | key = key, 87 | block = block, 88 | blockSize = 8, 89 | keySize = 3 * 8, 90 | algoName = "DESede", 91 | chainning = "ECB", 92 | padding = "NoPadding", 93 | enc = true, 94 | verbose = verbose) 95 | } else { 96 | Symmetric.block( 97 | key = key, 98 | block = block, 99 | blockSize = 8, 100 | keySize = 3 * 8, 101 | algoName = "DESede", 102 | chainning = "ECB", 103 | padding = "NoPadding", 104 | enc = false, 105 | verbose = verbose) 106 | } 107 | } 108 | } 109 | 110 | 111 | 112 | 113 | object Symmetric { 114 | 115 | 116 | /** 117 | * Block Encryption 118 | */ 119 | def block(key: BigInt, block: BigInt, blockSize:Int, keySize:Int, algoName: String, chainning: String, padding: String, enc: Boolean, verbose: Boolean = false ): BigInt = { 120 | 121 | // Cast the input key 122 | val keyAlgo = new SecretKeySpec(CastByteArray(key.toByteArray, keySize), algoName) 123 | 124 | 125 | // Create the cipher 126 | val algorithm = Cipher.getInstance(s"$algoName/$chainning/$padding") 127 | 128 | // Initialize the cipher for encryption 129 | algorithm.init(if(enc) Cipher.ENCRYPT_MODE else Cipher.DECRYPT_MODE, keyAlgo) 130 | 131 | // cast input block 132 | val block_in = CastByteArray(block.toByteArray, blockSize) 133 | 134 | 135 | // Encrypt the text 136 | val block_out = algorithm.doFinal(block_in) 137 | 138 | if(verbose){ 139 | println(s"Block_in : 0x${block_in.map(b => "%02X".format(b)).mkString("")}") 140 | println(s"Key : 0x${keyAlgo.getEncoded().map(b => "%02X".format(b)).mkString("")}") 141 | println(s"Block_out : 0x${block_out.map(b => "%02X".format(b)).mkString("")}") 142 | println("") 143 | } 144 | 145 | return BigInt(block_out.take(blockSize)) 146 | } 147 | 148 | } 149 | 150 | 151 | object PlayWithSymmetricRef extends App { 152 | 153 | val c = Cipher.getInstance("DES/CTR/NoPadding") 154 | 155 | val key = new SecretKeySpec(CastByteArray(BigInt(0x111).toByteArray, 8), "DES") 156 | 157 | val iv = CastByteArray(BigInt(0x111).toByteArray, 8) 158 | val dps = new IvParameterSpec(iv) 159 | 160 | c.init(Cipher.ENCRYPT_MODE, key, dps) 161 | val input = "Stand and unfold".getBytes() 162 | val encrypted = c.doFinal(input) 163 | println(BigIntToHexString(BigInt(encrypted))) 164 | 165 | 166 | c.init(Cipher.DECRYPT_MODE, key, dps) 167 | val output = c.doFinal(encrypted) 168 | println(BigIntToHexString(BigInt(output))) 169 | 170 | //// 171 | //// val key_ = BigInt(64, Random) 172 | //// val blockIn_ = BigInt(64 * 3, Random) 173 | //// val enc_ = Random.nextBoolean() 174 | //// val ref_blockOut_ = DES.blockWithChaining(true)(key_, blockIn_, (64 * 3) / 8, enc_, "CBC") 175 | 176 | 177 | } 178 | -------------------------------------------------------------------------------- /tester/src/main/scala/cryptotest/SpinalSimSpongeStdTester.scala: -------------------------------------------------------------------------------- 1 | package cryptotest 2 | 3 | import spinal.core._ 4 | import spinal.core.sim._ 5 | import org.scalatest.funsuite.AnyFunSuite 6 | import ref.constructor.Sponge 7 | import spinal.crypto.{BigIntToHexString, CastByteArray} 8 | import spinal.crypto.construtor.{SpongeCoreCmd_Std, SpongeCoreRsp_Std, SpongeCore_Std} 9 | import spinal.lib._ 10 | 11 | import scala.util.Random 12 | 13 | 14 | class SpinalSimSpongeStdTester extends AnyFunSuite { 15 | 16 | val NBR_ITERATION = 10 17 | 18 | 19 | class FakeSponge(d: Int) extends Component { 20 | 21 | val io = new Bundle{ 22 | val init = in Bool() 23 | val cmd = slave(Stream(Fragment(SpongeCoreCmd_Std(576)))) 24 | val rsp = master(Flow(SpongeCoreRsp_Std(d))) 25 | } 26 | 27 | val sponge = new SpongeCore_Std(1024, 576, d) 28 | val rTmp = Reg(cloneOf(sponge.io.func.cmd.payload)) 29 | val start = RegInit(False) 30 | 31 | sponge.io.func.cmd.ready := False 32 | sponge.io.func.rsp.payload := rTmp 33 | sponge.io.func.rsp.valid := False 34 | 35 | 36 | val timeout = Timeout(3 cycles) 37 | 38 | when(sponge.io.func.cmd.valid & !start){ 39 | start := True 40 | rTmp := B(sponge.io.func.cmd.payload |<< 8) 41 | timeout.clear() 42 | } 43 | 44 | when(timeout & start){ 45 | sponge.io.func.cmd.ready := True 46 | sponge.io.func.rsp.valid := True 47 | timeout.clear() 48 | start := False 49 | } 50 | 51 | sponge.io.cmd <> io.cmd 52 | sponge.io.rsp <> io.rsp 53 | sponge.io.init <> io.init 54 | } 55 | 56 | 57 | /** 58 | * Sponge without squeezing 59 | */ 60 | test("Sponge_noSqueezing"){ 61 | 62 | SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new FakeSponge(512)).doSim{ dut => 63 | 64 | dut.clockDomain.forkStimulus(2) 65 | 66 | 67 | // send differnt pattern 68 | for(_ <- 0 to NBR_ITERATION){ 69 | 70 | val nbrBlock = Random.nextInt(5) + 1 71 | 72 | val pIn = List.fill(nbrBlock)(BigInt(Array.fill(72)(Random.nextInt(256).toByte).map(x => f"$x%02X").mkString(""), 16)) 73 | 74 | val refState_out = Sponge(pIn.map(x => CastByteArray(x.toByteArray, 72)).reduce(_ ++ _), 1024, 576, 512) 75 | 76 | var indexBlock = 0 77 | 78 | // initialize value 79 | dut.io.init #= true 80 | dut.io.cmd.last #= false 81 | dut.io.cmd.valid #= false 82 | dut.io.cmd.n.randomize() 83 | 84 | dut.clockDomain.waitActiveEdge() 85 | 86 | dut.io.init #= false 87 | 88 | // Send all block in the sponge 89 | while(indexBlock != pIn.length){ 90 | 91 | dut.clockDomain.waitActiveEdge() 92 | 93 | dut.io.cmd.last #= (indexBlock == pIn.length - 1) 94 | dut.io.cmd.valid #= true 95 | dut.io.cmd.n #= pIn(indexBlock) 96 | 97 | dut.clockDomain.waitActiveEdgeWhere(dut.io.cmd.ready.toBoolean) 98 | dut.io.cmd.valid #= false 99 | 100 | if(indexBlock == pIn.length - 1){ 101 | 102 | val rtlState_out = BigInt(dut.io.rsp.z.toBigInt.toByteArray.takeRight(dut.io.rsp.z.getWidth / 8)) 103 | 104 | assert(CastByteArray(rtlState_out.toByteArray, 512 / 8).sameElements(refState_out), s"Wrong result RTL ${BigIntToHexString(rtlState_out)} != REF ${refState_out.map(x => f"$x%02X").mkString("")}") 105 | } 106 | indexBlock += 1 107 | } 108 | 109 | dut.clockDomain.waitActiveEdge(5) 110 | 111 | } 112 | } 113 | } 114 | 115 | 116 | /** 117 | * Sponge with Squeezing 118 | */ 119 | test("Sponge_withSqueezing"){ 120 | 121 | SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new FakeSponge(1024)).doSim{ dut => 122 | 123 | dut.clockDomain.forkStimulus(2) 124 | 125 | 126 | // send differnt pattern 127 | for(_ <- 0 to NBR_ITERATION){ 128 | 129 | val nbrBlock = Random.nextInt(5) + 1 130 | 131 | val pIn = List.fill(nbrBlock)(BigInt(Array.fill(72)(Random.nextInt(256).toByte).map(x => f"$x%02X").mkString(""), 16)) 132 | 133 | val refState_out = Sponge(pIn.map(x => CastByteArray(x.toByteArray, 72)).reduce(_ ++ _), 1024, 576, 1024) 134 | 135 | var indexBlock = 0 136 | 137 | // initialize value 138 | dut.io.init #= true 139 | dut.io.cmd.last #= false 140 | dut.io.cmd.valid #= false 141 | dut.io.cmd.n.randomize() 142 | 143 | dut.clockDomain.waitActiveEdge() 144 | 145 | dut.io.init #= false 146 | 147 | // Send all block in the sponge 148 | while(indexBlock != pIn.length){ 149 | 150 | dut.clockDomain.waitActiveEdge() 151 | 152 | dut.io.cmd.last #= (indexBlock == pIn.length - 1) 153 | dut.io.cmd.valid #= true 154 | dut.io.cmd.n #= pIn(indexBlock) 155 | 156 | dut.clockDomain.waitActiveEdgeWhere(dut.io.cmd.ready.toBoolean) 157 | dut.io.cmd.valid #= false 158 | 159 | if(indexBlock == pIn.length - 1){ 160 | 161 | val rtlState_out = BigInt(dut.io.rsp.z.toBigInt.toByteArray.takeRight(dut.io.rsp.z.getWidth / 8)) 162 | 163 | assert(CastByteArray(rtlState_out.toByteArray, 1024 / 8).sameElements(refState_out), s"Wrong result RTL ${BigIntToHexString(rtlState_out)} != REF ${refState_out.map(x => f"$x%02X").mkString("")}") 164 | } 165 | indexBlock += 1 166 | } 167 | 168 | dut.clockDomain.waitActiveEdge(5) 169 | 170 | } 171 | } 172 | } 173 | } 174 | 175 | -------------------------------------------------------------------------------- /tester/src/main/scala/cryptotest/SpinalSimKeccakFStdTester.scala: -------------------------------------------------------------------------------- 1 | package cryptotest 2 | 3 | import spinal.core._ 4 | import spinal.core.sim._ 5 | import org.scalatest.funsuite.AnyFunSuite 6 | import spinal.crypto.BigIntToHexString 7 | import spinal.crypto.primitive.keccak.KeccakF_Std 8 | 9 | 10 | 11 | class SpinalSimKeccakFStdTester extends AnyFunSuite { 12 | 13 | test("KeccakF_1600"){ 14 | 15 | SimConfig.withWave(3).withConfig(SpinalConfig(inlineRom = true)).compile(new KeccakF_Std(1600)).doSim{ dut => 16 | 17 | dut.clockDomain.forkStimulus(2) 18 | 19 | // pattern 20 | val pIn = List( 21 | BigInt("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", 16), 22 | BigInt("2D5C954DF96ECB3C6A332CD07057B56D093D8D1270D76B6C8A20D9B25569D0944F9C4F99E5E7F156F957B9A2DA65FB3885773DAE1275AF0DFAF4F247C3D810F71F1B9EE6F79A8759E4FECC0FEE98B42568CE61B6B9CE68A1DEEA66C4BA8F974F33C43D836EAFB1F5E00654042719DBD97CF8A9F009831265FD5449A6BF17474397DDAD33D8994B4048EAD5FC5D0BE774E3B8C8EE55B7B03C91A0226E649E42E9900E3129E7BADD7B202A9EC5FAA3CCE85B3402464E1C3DB6609F4E62A44C105920D06CD26A8FBF5C", 16), 23 | BigInt("3A7C2A5F40A6EB2E6D65A12941DC4578421FDC535744C454D7D362577104BE802760D9DB642351F4EE3E72527BEE47BDCD3828BB52A2C82C77C6E8A0A1F7DD0DB20410D9920D330609FAF1CBD8AAEE346908B5414252574F4DC4B495E348785257C8B308E597ABC8CFD1CA17D26E64FFE0952BC6B5ECC88841C66D9E7A092BA08E0C70F08AF986235F07630B6DF1ADA7F312E32DDF61343B5D1093D26FCE27EEDB0F640215B2AAE0400EEA2CC76F8716CF6DE6E9838329953BA0E9CD540AEEC472011C1D6BF77DAC", 16), 24 | BigInt("971CECC10266B10E6ADAE29CE71EAE385B331D9109F32D8947F889804480CDCEFECD01EAF3FD184BFF02D96272A0F9FA7305A59462631C8CADE70BA47BBB82B2DDBB6C2E22C7C2A916C92997F043DCD4287E1DC935D7A9972800BC77799B1CE47CCC56C5A551A5B55F7EBC347B2216D974C621FCD15148895D2B628A78B8B87DC52FF58E3A695D87A811456522C06885AEB698C6CE808B73962FFCD5A04C204F24297C7912E1BD9F02BCFEDFF5953DF1FE0A74D3A3676EC6A2F3B516FD29D10E80FC705B68E01610", 16), 25 | BigInt("E409BECC15D4110ABE07B597F646971BA20860D19A3176333D00CCDE8328DE56ED02F1DFA7ECF90B33EB764F744CC239C9FB8C0916C5443DBAAFC63179C24F4FD1B8CD19229301D0C025BFF35A6DE35BC324DCF0129AE69C7948559948D8E9251D3E08195A76A2BFC55247327076D2F7A3E4F405E6235A3B6A985AA8BC1CB5C55B719D0BF123A1E491FB8DB83291DF4C5296F8B6F90985006428D0CBC5A701F0258EE8110E5F6AAC687E1B35262CAD37DE2D00C16CFE6760D61A2EB46F9050CB7FE279B794440AB5", 16) 26 | ) 27 | 28 | 29 | val pOut = List( 30 | BigInt("F1258F7940E1DDE784D5CCF933C0478AD598261EA65AA9EEBD1547306F80494D8B284E056253D057FF97A42D7F8E6FD490FEE5A0A44647C48C5BDA0CD6192E76AD30A6F71B19059C30935AB7D08FFC64EB5AA93F2317D635A9A6E6260D71210381A57C16DBCF555F43B831CD0347C82601F22F1A11A5569F05E5635A21D9AE6164BEFEF28CC970F2613670957BC46611B87C5A554FD00ECB8C3EE88A1CCF32C8940C7922AE3A26141841F924A2C509E416F53526E70465C275F644E97F30A13BEAF1FF7B5CECA249", 16), 31 | BigInt("55EABB80767D364686C354C8D01CBACE9452D254B0979B3DDE59422BE2C66F16C660E4F2D4D8212E78414F691B639BB3CBB20F9F1B22E381CF16DA5FAC2DA63F83C0B76552D95F7C44EFC84EAF017E1548D380FF3E532C9592436EC5C5E02F05BDE57CA1EE8DE7E9240970468A1FD1B012A978439CBB7686D26B59FCCEFF8B4DD2AA0F472110FFF87BD44ABF53F72551E15AD2B722D00BB7C56095932C792C459E02D1766AD3A79C312F2DA72ADA4EC368B9F274A8D7D6B92B7239F7E51EEA1EB6947F6894D77AEB", 16), 32 | BigInt("C9F309FF271C66319281C8B3825841B42219CB1928CA14C4F50D1D2AE140281AF0A33A68985B6934D8A79767500429F6BE55A8FFF0767FAFBC2A9530CCA9D7A87E7947DEBC81B851772429B40AA052A858F891E79CE863653110152CADF8860F7F6F0628BDA22D08A89FB4DB4293CC0A390BCA6688AB09BEFADCBB8BBBEDCE4B2D78A388460C4A73E692F192C06EA9AE909DE0D99F0083F076773FCDC7E9D261344D00AE9D02C8539D85CB92EF2A61550A1A8ECF6537E0B3A6DA3FB1F1688E95CFE9307B7DB8BED0", 16), 33 | BigInt("96FD5DCE98F24747BC17F718A5EE2C326C35A669C2803013B609BCA1CB4290D79ACB9589DFE9E24D23CD87D2100A09C81D045BFEC0E027B456C35E5CA9BBA89FFE57C5CEA57A60C2E7EE16B2641E669B68985ABFA550BB66F6923F628221835B6FFA61F3003DA12AEC8239484A92E877C0B246BCCD3FC38578C896C5470D48A7861A0C89AD6C9AC44721476CB83EA905C0B5307B7F640E2C1F273DC75696478A22D54D8F7705A150BD92ECCC819E4ABE58137F2452C9686A0F61A7F4CA21445709683D0401018460", 16), 34 | BigInt("D1AED9E3149CF176FA5784FB1CD05D62410AD4C334AC5843FD5D711A3619C022EF3C5A52A19521C388CA427AD4093D4030CAE0756CCB675DF1BC6D1003600450551E54846019C2740F0E2C4EED72C02E7FA05C108E09CA188A77C0D124F5E5B35BFCB30FC8DE496DEADC837994534B200B81F95E44D6BB58DAD404401A489506D60AB885FE20EBF52EB0F3A94432ABCF0186261253FAA874691B683FD0CEB84A26DE0E2E35F2AD7A5F559030137AD5FEB372861AA4A3C6AF1AA9D09D3BA9A957FA7EAA90728CA360", 16) 35 | ) 36 | 37 | // initialize value 38 | dut.io.cmd.valid #= false 39 | dut.io.cmd.payload.randomize() 40 | 41 | for((dIn, dOut) <- pIn.zip(pOut)){ 42 | 43 | dut.clockDomain.waitActiveEdge() 44 | 45 | dut.io.cmd.valid #= true 46 | dut.io.cmd.payload #= dIn 47 | 48 | dut.clockDomain.waitActiveEdgeWhere(dut.io.rsp.valid.toBoolean) 49 | dut.io.cmd.valid #= false 50 | 51 | val rtlState_out = BigInt(dut.io.rsp.payload.toBigInt.toByteArray.takeRight(dut.io.rsp.payload.getWidth / 8)) 52 | val refState_out = BigInt(dOut.toByteArray.takeRight(dut.io.rsp.payload.getWidth / 8)) 53 | 54 | assert(rtlState_out == refState_out , s"Wrong result RTL ${BigIntToHexString(rtlState_out)} != REF ${BigIntToHexString(refState_out)}") 55 | 56 | dut.clockDomain.waitActiveEdge(5) 57 | 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/hash/Hash.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.hash 27 | 28 | import spinal.core._ 29 | import spinal.crypto.padding.PaddingIOConfig 30 | import spinal.lib._ 31 | import spinal.lib.bus.misc.BusSlaveFactory 32 | import spinal.lib.fsm._ 33 | 34 | trait EndiannessMode 35 | object BIG_endian extends EndiannessMode 36 | object LITTLE_endian extends EndiannessMode 37 | 38 | /** 39 | * Hash Core configuration 40 | */ 41 | case class HashCoreConfig ( 42 | dataWidth : BitCount, 43 | hashWidth : BitCount, 44 | hashBlockWidth : BitCount 45 | ){ 46 | def getPaddingIOConfig = PaddingIOConfig( 47 | dataCmdWidth = dataWidth, 48 | dataRspWidth = hashBlockWidth, 49 | symbolWidth = 8 bits 50 | ) 51 | } 52 | 53 | 54 | /** 55 | * Hash Core command 56 | */ 57 | case class HashCoreCmd(config: HashCoreConfig) extends Bundle { 58 | val msg = Bits(config.dataWidth) 59 | val size = UInt(log2Up(config.dataWidth.value / 8) bits) 60 | } 61 | 62 | 63 | /** 64 | * Hash Core response 65 | */ 66 | case class HashCoreRsp(config: HashCoreConfig) extends Bundle { 67 | val digest = Bits(config.hashWidth) 68 | } 69 | 70 | 71 | /** 72 | * Hash Core IO 73 | */ 74 | case class HashCoreIO(config: HashCoreConfig) extends Bundle with IMasterSlave { 75 | 76 | val init = in Bool() 77 | val cmd = Stream(Fragment(HashCoreCmd(config))) 78 | val rsp = Flow(HashCoreRsp(config)) 79 | 80 | override def asMaster() = { 81 | out(init) 82 | master(cmd) 83 | slave(rsp) 84 | } 85 | 86 | /** Drive IO from a bus */ 87 | def driveFrom(busCtrl: BusSlaveFactory, baseAddress: Int = 0) = new Area { 88 | 89 | var addr = baseAddress 90 | 91 | /* Write operation */ 92 | 93 | busCtrl.driveMultiWord(cmd.msg, addr) 94 | addr += (widthOf(cmd.msg) / 32) * 4 95 | 96 | busCtrl.drive(cmd.size, addr) 97 | addr += 4 98 | 99 | busCtrl.drive(cmd.last, addr) 100 | addr += 4 101 | 102 | val initReg = busCtrl.drive(init, addr) init(False) 103 | initReg.clearWhen(initReg) 104 | addr += 4 105 | 106 | val validReg = busCtrl.drive(cmd.valid, addr) init(False) 107 | validReg.clearWhen(cmd.ready) 108 | addr += 4 109 | 110 | /* Read operation */ 111 | 112 | val digest = Reg(cloneOf(rsp.digest)) 113 | val rspValid = Reg(Bool) init(False) setWhen(rsp.valid) 114 | 115 | when(rsp.valid){ 116 | digest := rsp.digest 117 | } 118 | 119 | busCtrl.onRead(addr){ 120 | when(rspValid){ 121 | rspValid := False 122 | } 123 | } 124 | 125 | busCtrl.read(rspValid, addr) 126 | addr += 4 127 | 128 | busCtrl.readMultiWord(digest, addr) 129 | addr += (widthOf(digest) / 32) * 4 130 | 131 | 132 | //manage interrupts 133 | val interruptCtrl = new Area { 134 | val doneIntEnable = busCtrl.createReadAndWrite(Bool, address = addr, 0) init(False) 135 | val doneInt = doneIntEnable & !rsp.valid 136 | val interrupt = doneInt 137 | } 138 | } 139 | } 140 | 141 | 142 | /** 143 | * Hash Engine command 144 | */ 145 | case class HashEngineCmd(blockSize: BitCount) extends Bundle { 146 | val message = Bits(blockSize) 147 | } 148 | 149 | 150 | /** 151 | * Hash Engine response 152 | */ 153 | case class HashEngineRsp(digestSize: BitCount) extends Bundle { 154 | val digest = Bits(digestSize) 155 | } 156 | 157 | 158 | /** 159 | * Hash Engine IO 160 | */ 161 | case class HashEngineIO(blockSize: BitCount, digestSize: BitCount) extends Bundle with IMasterSlave { 162 | 163 | val init = Bool 164 | val cmd = Stream(HashEngineCmd(blockSize)) 165 | val rsp = Flow(HashEngineRsp(digestSize)) 166 | 167 | override def asMaster() = { 168 | out(init) 169 | master(cmd) 170 | slave(rsp) 171 | } 172 | } 173 | 174 | -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal 27 | 28 | import scala.collection.mutable.ListBuffer 29 | import spinal.lib.tools._ 30 | import spinal.core._ 31 | 32 | 33 | package object crypto{ 34 | 35 | /** 36 | * Used to create polynomial as follow p"x^2 + x + 1" 37 | */ 38 | implicit class LiteralBuilderCrypto(private val sc: StringContext) { 39 | def p(args: Any*): PolynomialGF2 = str2PolynomialGF2(getString(args)) 40 | 41 | private def getString(args: Any*): String = { 42 | val pi = sc.parts.iterator 43 | val ai = args.iterator 44 | val bldr = new StringBuilder(pi.next().toString) 45 | 46 | while (ai.hasNext) { 47 | if (ai.hasNext && !ai.next.isInstanceOf[List[_]]) bldr append ai.next 48 | if (pi.hasNext && !pi.next.isInstanceOf[List[_]]) bldr append pi.next 49 | } 50 | 51 | bldr.result.replace("_", "") 52 | } 53 | } 54 | 55 | 56 | /** 57 | * Convert a string into a polynomial 58 | */ 59 | private[crypto] def str2PolynomialGF2(polyStr: String): PolynomialGF2 = { 60 | 61 | assert(polyStr.length > 0, "Empty polynomial") 62 | 63 | /** 64 | * Polynomial str into list of coefficient 65 | */ 66 | def polynomialStrDecoder(p: String): List[Int] = { 67 | 68 | // Get all coefficient 69 | var duplicate0 = 0 70 | val pp = """x\^([0-9]+)""".r 71 | def getCoef(str: List[String]) : List[Int] = str match{ 72 | case "x" :: tail => 1 :: getCoef(tail) 73 | case "1" :: tail => duplicate0 += 1 ; 0 :: getCoef(tail) 74 | case "0" :: tail => duplicate0 += 1 ; getCoef(tail) 75 | case pp(value) :: tail => value.toInt :: getCoef(tail) 76 | case Nil => Nil 77 | case _ => throw new Exception(s"The polynomial $p is not valid. ") 78 | } 79 | 80 | val coefficientList = getCoef(p.split('+').toList) 81 | 82 | // Check if there some duplicate coefficient 83 | val duplicateCoef = coefficientList.diff(coefficientList.distinct) 84 | assert(duplicateCoef.length == 0 && duplicate0 <= 1, s"Polynomial $p has duplicate coefficient ${duplicateCoef.mkString(",")}") 85 | 86 | 87 | return coefficientList 88 | } 89 | 90 | 91 | /** 92 | * Polynomial bin/hex into list of coefficient 93 | */ 94 | def polynomialNumberDecoder(radix: Int, p: String): List[Int] = { 95 | 96 | assert(List(2,16).contains(radix), "The following radix for polynomial is forbidden") 97 | 98 | // remove all _ 99 | var strPoly = p.replace("_", "").toLowerCase 100 | 101 | // convert hexadecimal str into binary string 102 | var bitCount = -1 103 | if (radix == 16) { 104 | val split = strPoly.split('\'') 105 | bitCount = split(0).toInt 106 | strPoly = split(1).substring(1) 107 | strPoly = BigIntToListBoolean(BigInt(strPoly, 16), bitCount bits).map(b => if(b) "1" else "0").reverse.mkString("") 108 | } else { 109 | strPoly = strPoly.substring(1) 110 | } 111 | 112 | // Convert the binary string into list of coefficient 113 | val listBuffer = new ListBuffer[Int]() 114 | for((b,i) <- strPoly.reverse.zipWithIndex){ 115 | if(b == '1') listBuffer.append(i) 116 | } 117 | 118 | // append for hexadecimal polynomial the higher coefficient 119 | if(bitCount != -1){ 120 | listBuffer.append(bitCount) 121 | } 122 | 123 | return listBuffer.toList 124 | } 125 | 126 | // remove all spaces 127 | val poly = polyStr.replace(" ", "") 128 | 129 | // detect the format of the string 130 | val rhex = """[0-9]+\'x[0-9a-fA-F_]+""".r 131 | val rbin = """b[0-1_]+""".r 132 | val rstr = """[0-9x\^\+]+""".r 133 | 134 | val polynomial = poly match{ 135 | case rhex() => polynomialNumberDecoder(16, poly) 136 | case rbin() => polynomialNumberDecoder(2, poly) 137 | case rstr() => polynomialStrDecoder(poly) 138 | case _ => throw new Exception("Polynomial format issue") 139 | } 140 | 141 | return new PolynomialGF2(polynomial.sortWith(_ > _)) 142 | } 143 | 144 | 145 | } 146 | -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/symmetric/des/TripleDESCore_Std.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.symmetric.des 27 | 28 | import spinal.core._ 29 | import spinal.lib._ 30 | import spinal.lib.fsm._ 31 | import spinal.crypto.symmetric.{SymmetricCryptoBlockConfig, SymmetricCryptoBlockIO} 32 | 33 | 34 | /** 35 | * Triple DES (3DES) 36 | * 37 | * Encrpytion : Decrytpion : 38 | * 39 | * plaintext plaintext (64 bits) 40 | * | | 41 | * ----------------- ---------------- 42 | * | DES encrypt |<-- K1 -->| DES decrypt | 43 | * ----------------- ---------------- 44 | * | | 45 | * ----------------- ---------------- 46 | * | DES decrypt |<-- K2 -->| DES encrypt | 47 | * ----------------- ---------------- 48 | * | | 49 | * ----------------- ---------------- 50 | * | DES encrypt |<-- K3 -->| DES decrypt | 51 | * ----------------- ---------------- 52 | * | | 53 | * ciphertext ciphertext (64 bits) 54 | * 55 | * 56 | * key = Concatenation(k1 , k2 , k3) = 3*64 bits = 192 bits 57 | * 58 | */ 59 | class TripleDESCore_Std() extends Component { 60 | 61 | val gIO = SymmetricCryptoBlockConfig( 62 | keyWidth = ((DES.keyWidth.value + DES.keyWidthParity.value) * 3) bits, 63 | blockWidth = DES.blockWidth, 64 | useEncDec = true 65 | ) 66 | 67 | val io = slave(new SymmetricCryptoBlockIO(gIO)) 68 | 69 | val block = Reg(Bits(DES.blockWidth)) 70 | 71 | val coreDES = new DESCore_Std() 72 | 73 | /** 74 | * Triple DES state machine 75 | */ 76 | val sm3DES = new StateMachine { 77 | 78 | val desCmdValid = False 79 | val desEncDec = False 80 | val desKey = B(0, DES.keyWidthParity + DES.keyWidth) 81 | val inSel = False 82 | val cmdReady = False 83 | 84 | val sIdle: State = new State with EntryPoint { 85 | whenIsActive{ 86 | when(io.cmd.valid && !io.cmd.ready){ 87 | goto(sStage1) 88 | } 89 | } 90 | } 91 | 92 | val sStage1: State = new State { 93 | whenIsActive{ 94 | desEncDec := io.cmd.enc 95 | desCmdValid := True 96 | desKey := io.cmd.enc ? io.cmd.key(191 downto 128) | io.cmd.key(63 downto 0) 97 | 98 | when(coreDES.io.rsp.valid){ 99 | desCmdValid := False 100 | block := coreDES.io.rsp.block 101 | goto(sStage2) 102 | } 103 | } 104 | } 105 | 106 | val sStage2: State = new State { 107 | whenIsActive{ 108 | inSel := True 109 | desEncDec := !io.cmd.enc 110 | desKey := io.cmd.key(127 downto 64) 111 | desCmdValid := True 112 | 113 | when(coreDES.io.rsp.valid){ 114 | desCmdValid := False 115 | block := coreDES.io.rsp.block 116 | goto(sStage3) 117 | } 118 | } 119 | } 120 | 121 | val sStage3: State = new State { 122 | whenIsActive{ 123 | inSel := True 124 | desEncDec := io.cmd.enc 125 | desKey := io.cmd.enc ? io.cmd.key(63 downto 0) | io.cmd.key(191 downto 128) 126 | desCmdValid := True 127 | 128 | when(coreDES.io.rsp.valid){ 129 | desCmdValid := False 130 | cmdReady := True 131 | block := coreDES.io.rsp.block 132 | goto(sIdle) 133 | } 134 | } 135 | } 136 | } 137 | 138 | 139 | /* 140 | * DES block connection 141 | */ 142 | coreDES.io.cmd.valid <> sm3DES.desCmdValid 143 | coreDES.io.cmd.key <> sm3DES.desKey 144 | coreDES.io.cmd.enc <> sm3DES.desEncDec 145 | coreDES.io.cmd.block <> (sm3DES.inSel ? block | io.cmd.block) 146 | 147 | 148 | /* 149 | * Output 150 | */ 151 | val cmdReady = RegNext(sm3DES.cmdReady, False) 152 | io.rsp.block := block 153 | io.rsp.valid := cmdReady 154 | io.cmd.ready := cmdReady 155 | } 156 | 157 | -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/symmetric/aes/AES.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.symmetric.aes 27 | 28 | import spinal.core._ 29 | 30 | 31 | 32 | 33 | object AES { 34 | 35 | def blockWidth = 128 bits 36 | 37 | def nbrRound(keySize: BitCount): Int = keySize.value match { 38 | case 128 => 10 39 | case 192 => 12 40 | case 256 => 14 41 | case _ => SpinalError(s"AES doesn't support the following key size $keySize") 42 | } 43 | 44 | 45 | def sBox = List( 46 | 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 47 | 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 48 | 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 49 | 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 50 | 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 51 | 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 52 | 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 53 | 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 54 | 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 55 | 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 56 | 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 57 | 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 58 | 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 59 | 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 60 | 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 61 | 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 62 | ) 63 | 64 | 65 | def sBoxInverse = List( 66 | 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 67 | 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 68 | 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 69 | 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 70 | 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 71 | 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 72 | 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 73 | 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 74 | 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 75 | 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 76 | 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 77 | 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 78 | 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 79 | 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 80 | 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 81 | 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d 82 | ) 83 | 84 | 85 | def rcon(keyWidth: BitCount): List[Int] = { 86 | val rconValue = List( 87 | 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 88 | 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 89 | 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a 90 | ) 91 | return rconValue.take(AES.nbrRound(keyWidth) + 1) 92 | } 93 | 94 | 95 | def shiftRowIndex = List( 96 | 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, 1, 6, 11 97 | ) 98 | 99 | def invShiftRowIndex = List( 100 | 0, 13, 10, 7, 4, 1, 14, 11, 8, 5, 2, 15, 12, 9, 6, 3 101 | ) 102 | 103 | } -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/padding/Pad_xB_1_Std.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.padding 27 | 28 | import spinal.core._ 29 | import spinal.lib._ 30 | import spinal.lib.fsm._ 31 | 32 | case class Padding_xB_1_Config( 33 | dataInWidth : BitCount, 34 | dataOutWidth : BitCount , 35 | pad_xB : Byte, 36 | symbolWidth : BitCount = 8 bits 37 | ) extends PaddingConfig(dataInWidth, dataOutWidth, symbolWidth) 38 | 39 | 40 | 41 | /** 42 | * Padding xB* 1 (message is byte-aligned) 43 | * 44 | * e.g. with xPad = 0x06 45 | * 46 | * +--------------------------------+ 47 | * | Padded message | 48 | * ---------------------------------+ 49 | * | M || 0x86 | 50 | * | M || 0x0680 | 51 | * | M || 0x06 || 0x00... || 0x80 | 52 | * +--------------------------------+ 53 | * 54 | */ 55 | class Pad_xB_1_Std(config: Padding_xB_1_Config) extends Component { 56 | 57 | assert(config.dataInWidth.value == 32, "Currently padding supports only 32 bits") 58 | assert(config.symbolWidth.value == 8, "Padding works in byte") 59 | 60 | val io = slave(PaddingIO(config.getPaddingIOConfig)) 61 | 62 | val nbrElementInBlock = config.dataOutWidth.value / config.dataInWidth.value 63 | val buffer = Reg(Vec(Bits(config.dataInWidth), nbrElementInBlock)) 64 | val indexBuffer = Reg(UInt(log2Up(nbrElementInBlock) bits)) 65 | 66 | io.cmd.ready := False 67 | io.rsp.valid := False 68 | io.rsp.data := Cat(buffer.reverse) 69 | io.rsp.last := io.cmd.valid & io.cmd.last 70 | 71 | 72 | val mask_1 = io.cmd.size.mux( 73 | U"00" -> B("x00" + f"${config.pad_xB}%02X0000"), 74 | U"01" -> B("x0000" + f"${config.pad_xB}%02X00"), 75 | U"10" -> B("x000000" + f"${config.pad_xB}%02X"), 76 | U"11" -> B("x" + f"${config.pad_xB}%02X000000") 77 | ) 78 | 79 | /** 80 | * Padding state machine 81 | */ 82 | val sm = new StateMachine { 83 | 84 | val add_1_nextElement = Reg(Bool) 85 | val fillNewBlock = Reg(Bool) 86 | 87 | always{ 88 | when(io.init){ 89 | indexBuffer := 0 90 | add_1_nextElement := False 91 | fillNewBlock := False 92 | buffer.map(_ := 0) 93 | goto(sLoad) 94 | } 95 | } 96 | 97 | val sLoad: State = new State with EntryPoint{ 98 | whenIsActive{ 99 | 100 | when(io.cmd.valid){ 101 | 102 | buffer(indexBuffer) := io.cmd.data 103 | 104 | when(io.cmd.last){ 105 | goto(sPadding_1) 106 | }otherwise{ 107 | indexBuffer := indexBuffer + 1 108 | 109 | when(indexBuffer === nbrElementInBlock - 1){ 110 | goto(sProcessing) 111 | }otherwise{ 112 | io.cmd.ready := True 113 | } 114 | } 115 | } 116 | } 117 | 118 | val sPadding_1: State = new State{ 119 | whenIsActive{ 120 | 121 | when(io.cmd.size === 3){ 122 | add_1_nextElement := True 123 | }otherwise{ 124 | buffer(indexBuffer) := buffer(indexBuffer) | mask_1 125 | } 126 | goto(sPadding) 127 | } 128 | } 129 | 130 | val sPadding: State = new State { 131 | whenIsActive{ 132 | when(fillNewBlock){ 133 | buffer(0) := mask_1 134 | buffer.last := B"x00000080" 135 | fillNewBlock := False 136 | add_1_nextElement := False 137 | goto(sProcessing) 138 | }elsewhen(add_1_nextElement){ 139 | when(indexBuffer === nbrElementInBlock - 1){ 140 | fillNewBlock := True 141 | goto(sProcessing) 142 | }otherwise{ 143 | buffer(indexBuffer + 1) := mask_1 144 | add_1_nextElement := False 145 | } 146 | }otherwise{ 147 | buffer.last := buffer.last | B"x00000080" 148 | goto(sProcessing) 149 | } 150 | } 151 | } 152 | 153 | val sProcessing: State = new State { /* Run Algorithm */ 154 | whenIsActive{ 155 | io.rsp.valid := True 156 | 157 | when(io.rsp.ready){ 158 | buffer.map(_ := 0) 159 | indexBuffer := 0 160 | when(fillNewBlock){ 161 | goto(sPadding_1) 162 | }otherwise{ 163 | io.cmd.ready := True 164 | goto(sLoad) 165 | } 166 | } 167 | } 168 | } 169 | } 170 | } 171 | } -------------------------------------------------------------------------------- /tester/src/main/scala/play/Play_1.scala: -------------------------------------------------------------------------------- 1 | package play 2 | 3 | import spinal.core._ 4 | import spinal.lib._ 5 | 6 | import spinal.crypto._ 7 | import spinal.crypto.hash._ 8 | import spinal.crypto.hash.md5._ 9 | import spinal.crypto.mac.hmac.{HMACCoreStdConfig, HMACCoreStdIO, HMACCore_Std} 10 | import spinal.crypto.symmetric.SymmetricCryptoBlockIO 11 | import spinal.crypto.symmetric.des.{DESCore_Std, TripleDESCore_Std} 12 | import spinal.crypto.symmetric.aes._ 13 | import spinal.crypto.misc.LFSR 14 | 15 | 16 | 17 | object PlayWithDesCore_Std{ 18 | 19 | class DESCoreStdTester extends Component { 20 | 21 | val des = new DESCore_Std() 22 | 23 | val io = slave(new SymmetricCryptoBlockIO(des.gIO)) 24 | 25 | des.io <> io 26 | } 27 | 28 | def main(args: Array[String]): Unit = { 29 | SpinalConfig( 30 | mode = Verilog, 31 | dumpWave = DumpWaveConfig(depth = 0), 32 | defaultConfigForClockDomains = ClockDomainConfig(clockEdge = RISING, resetKind = ASYNC, resetActiveLevel = LOW), 33 | defaultClockDomainFrequency = FixedFrequency(50 MHz) 34 | ).generate(new DESCoreStdTester).printPruned 35 | } 36 | } 37 | 38 | 39 | object PlayWith3DesCore_Std{ 40 | 41 | class TripleDESCoreStdTester extends Component { 42 | 43 | val des3 = new TripleDESCore_Std() 44 | 45 | val io = slave(new SymmetricCryptoBlockIO(des3.gIO)) 46 | 47 | des3.io <> io 48 | } 49 | 50 | def main(args: Array[String]): Unit = { 51 | SpinalConfig( 52 | mode = Verilog, 53 | dumpWave = DumpWaveConfig(depth = 0), 54 | defaultConfigForClockDomains = ClockDomainConfig(clockEdge = RISING, resetKind = ASYNC, resetActiveLevel = LOW), 55 | defaultClockDomainFrequency = FixedFrequency(50 MHz) 56 | ).generate(new TripleDESCoreStdTester).printPruned 57 | } 58 | } 59 | 60 | 61 | object PlayWithMD5Core_Std{ 62 | 63 | class MD5CoreStdTester extends Component{ 64 | 65 | val md5 = new MD5Core_Std() 66 | 67 | val io = slave(HashCoreIO(md5.configCore)) 68 | 69 | md5.io <> io 70 | } 71 | 72 | def main(args: Array[String]): Unit = { 73 | SpinalConfig( 74 | mode = Verilog, 75 | dumpWave = DumpWaveConfig(depth = 0), 76 | defaultConfigForClockDomains = ClockDomainConfig(clockEdge = RISING, resetKind = ASYNC, resetActiveLevel = LOW), 77 | defaultClockDomainFrequency = FixedFrequency(50 MHz) 78 | ).generate(new MD5CoreStdTester).printUnused() 79 | } 80 | } 81 | 82 | object PlayWithHMACCore_Std_MD5Core_Std{ 83 | 84 | class HMACCoreStdTester() extends Component{ 85 | 86 | val md5 = new MD5Core_Std() 87 | val hmac = new HMACCore_Std(HMACCoreStdConfig(md5.configCore.hashBlockWidth, md5.configCore)) 88 | 89 | val io = slave(HMACCoreStdIO(hmac.config)) 90 | 91 | hmac.io.hmacCore <> io 92 | hmac.io.hashCore <> md5.io 93 | } 94 | 95 | def main(args: Array[String]): Unit = { 96 | SpinalConfig( 97 | mode = Verilog, 98 | dumpWave = DumpWaveConfig(depth = 0), 99 | defaultConfigForClockDomains = ClockDomainConfig(clockEdge = RISING, resetKind = ASYNC, resetActiveLevel = LOW), 100 | defaultClockDomainFrequency = FixedFrequency(50 MHz), 101 | mergeAsyncProcess = false 102 | ).generate(new HMACCoreStdTester).printPruned 103 | } 104 | } 105 | 106 | 107 | object PlayWithAESCore_Std{ 108 | class AESCoreStdTester() extends Component{ 109 | 110 | val aes128 = new AESCore_Std(128 bits) 111 | val aes192 = new AESCore_Std(192 bits) 112 | val aes256 = new AESCore_Std(256 bits) 113 | 114 | val io = new Bundle{ 115 | val aes_128 = slave(SymmetricCryptoBlockIO(aes128.gIO)) 116 | val aes_192 = slave(SymmetricCryptoBlockIO(aes192.gIO)) 117 | val aes_256 = slave(SymmetricCryptoBlockIO(aes256.gIO)) 118 | } 119 | 120 | aes128.io <> io.aes_128 121 | aes192.io <> io.aes_192 122 | aes256.io <> io.aes_256 123 | } 124 | 125 | def main(args: Array[String]): Unit = { 126 | SpinalConfig( 127 | mode = VHDL, 128 | dumpWave = DumpWaveConfig(depth = 0), 129 | defaultConfigForClockDomains = ClockDomainConfig(clockEdge = RISING, resetKind = ASYNC, resetActiveLevel = LOW), 130 | defaultClockDomainFrequency = FixedFrequency(50 MHz) 131 | ).generate(new AESCoreStdTester).printPruned 132 | } 133 | } 134 | 135 | 136 | object PlayWithLFSR{ 137 | 138 | case class LFSR_CMD() extends Bundle{ 139 | val init = in Bool() 140 | val seed = in Bits(8 bits) 141 | val inc = in Bool() 142 | val value = out Bits(8 bits) 143 | } 144 | 145 | class LFSRTester() extends Component{ 146 | 147 | val io = new Bundle{ 148 | val fib = LFSR_CMD() 149 | val gal = LFSR_CMD() 150 | val fib_ext = LFSR_CMD() 151 | val gal_ext = LFSR_CMD() 152 | 153 | } 154 | 155 | val fib = new Area { 156 | val lfsr_reg = Reg(cloneOf(io.fib.value)) 157 | when(io.fib.init){ 158 | lfsr_reg := io.fib.seed 159 | } 160 | when(io.fib.inc){ 161 | lfsr_reg := LFSR.Fibonacci(lfsr_reg, LFSR.polynomial_8bits) 162 | } 163 | io.fib.value := lfsr_reg 164 | } 165 | 166 | val fib_ext = new Area { 167 | val lfsr_reg = Reg(cloneOf(io.fib_ext.value)) 168 | when(io.fib_ext.init){ 169 | lfsr_reg := io.fib_ext.seed 170 | } 171 | when(io.fib_ext.inc){ 172 | lfsr_reg := LFSR.Fibonacci(lfsr_reg, LFSR.polynomial_8bits, LFSR.XOR, true) 173 | } 174 | io.fib_ext.value := lfsr_reg 175 | } 176 | 177 | val gal = new Area { 178 | val lfsr_reg = Reg(cloneOf(io.gal.value)) 179 | when(io.gal.init){ 180 | lfsr_reg := io.gal.seed 181 | } 182 | when(io.gal.inc){ 183 | lfsr_reg := LFSR.Galois(lfsr_reg, LFSR.polynomial_8bits) 184 | } 185 | io.gal.value := lfsr_reg 186 | } 187 | 188 | val gal_ext = new Area { 189 | val lfsr_reg = Reg(cloneOf(io.gal_ext.value)) 190 | when(io.gal_ext.init){ 191 | lfsr_reg := io.gal_ext.seed 192 | } 193 | when(io.gal_ext.inc){ 194 | lfsr_reg := LFSR.Galois(lfsr_reg, LFSR.polynomial_8bits, LFSR.XOR, true) 195 | } 196 | io.gal_ext.value := lfsr_reg 197 | } 198 | 199 | } 200 | 201 | def main(args: Array[String]): Unit = { 202 | SpinalConfig( 203 | mode = Verilog, 204 | dumpWave = DumpWaveConfig(depth = 0), 205 | defaultConfigForClockDomains = ClockDomainConfig(clockEdge = RISING, resetKind = ASYNC, resetActiveLevel = LOW), 206 | defaultClockDomainFrequency = FixedFrequency(50 MHz) 207 | ).generate(new LFSRTester).printPruned 208 | } 209 | } -------------------------------------------------------------------------------- /tester/src/main/scala/cryptotest/SpinalSimTwoFishCoreStdTester.scala: -------------------------------------------------------------------------------- 1 | package cryptotest 2 | 3 | import spinal.core.SpinalConfig 4 | import spinal.core.sim.SimConfig 5 | import org.scalatest.funsuite.AnyFunSuite 6 | import spinal.core._ 7 | import spinal.crypto.symmetric.sim.SymmetricCryptoBlockIOSim 8 | import spinal.core.sim._ 9 | import spinal.crypto.symmetric.twofish._ 10 | 11 | 12 | 13 | 14 | class SpinalSimTwoFishCoreStdTester extends AnyFunSuite { 15 | 16 | val ref_key_128 = List( 17 | BigInt("00000000000000000000000000000000", 16), 18 | BigInt("00000000000000000000000000000000", 16), 19 | BigInt("9F589F5CF6122C32B6BFEC2F2AE8C35A", 16) 20 | ) 21 | 22 | val ref_plain_128 = List( 23 | BigInt("00000000000000000000000000000000", 16), 24 | BigInt("9F589F5CF6122C32B6BFEC2F2AE8C35A", 16), 25 | BigInt("D491DB16E7B1C39E86CB086B789F5419", 16) 26 | ) 27 | 28 | val ref_cipher_128 = List( 29 | BigInt("9F589F5CF6122C32B6BFEC2F2AE8C35A", 16), 30 | BigInt("D491DB16E7B1C39E86CB086B789F5419", 16), 31 | BigInt("019F9809DE1711858FAAC3A3BA20FBC3", 16) 32 | ) 33 | 34 | 35 | val ref_key_192 = List( 36 | BigInt("000000000000000000000000000000000000000000000000", 16), 37 | BigInt("88B2B2706B105E36B446BB6D731A1E88EFA71F788965BD44", 16), 38 | BigInt("39DA69D6BA4997D585B6DC073CA341B288B2B2706B105E36", 16) 39 | ) 40 | 41 | val ref_plain_192 = List( 42 | BigInt("00000000000000000000000000000000", 16), 43 | BigInt("39DA69D6BA4997D585B6DC073CA341B2", 16), 44 | BigInt("182B02D81497EA45F9DAACDC29193A65", 16) 45 | ) 46 | 47 | val ref_cipher_192 = List( 48 | BigInt("EFA71F788965BD4453F860178FC19101", 16), 49 | BigInt("182B02D81497EA45F9DAACDC29193A65", 16), 50 | BigInt("7AFF7A70CA2FF28AC31DD8AE5DAAAB63", 16) 51 | ) 52 | 53 | 54 | val ref_key_256 = List( 55 | BigInt("0000000000000000000000000000000000000000000000000000000000000000", 16), 56 | BigInt("D43BB7556EA32E46F2A282B7D45B4E0D57FF739D4DC92C1BD7FC01700CC8216F", 16) 57 | ) 58 | 59 | val ref_plain_256 = List( 60 | BigInt("00000000000000000000000000000000", 16), 61 | BigInt("90AFE91BB288544F2C32DC239B2635E6", 16) 62 | ) 63 | 64 | val ref_cipher_256 = List( 65 | BigInt("57FF739D4DC92C1BD7FC01700CC8216F", 16), 66 | BigInt("6CB4561C40BF0A9705931CB6D408E7FA", 16) 67 | ) 68 | 69 | /** 70 | * Test - TwoFish (128-bit) 71 | */ 72 | test("TwoFishCoreStd_128"){ 73 | SimConfig.withConfig(SpinalConfig(inlineRom = true)).withWave(6).compile(new TwofishCore_Std(128 bits)).doSim { dut => 74 | 75 | dut.clockDomain.forkStimulus(2) 76 | 77 | // initialize value 78 | dut.io.cmd.valid #= false 79 | dut.io.cmd.block.randomize() 80 | dut.io.cmd.key.randomize() 81 | if (dut.io.config.useEncDec) dut.io.cmd.enc.randomize() 82 | 83 | dut.clockDomain.waitActiveEdge() 84 | 85 | for ((key, plain, cipher) <- (ref_key_128, ref_plain_128, ref_cipher_128).zipped) { 86 | 87 | 88 | SymmetricCryptoBlockIOSim.doSim( 89 | dut = dut.io, 90 | clockDomain = dut.clockDomain, 91 | enc = true, 92 | blockIn = plain, 93 | keyIn = key)((a: BigInt, b: BigInt, c: Boolean) => cipher) 94 | 95 | SymmetricCryptoBlockIOSim.doSim( 96 | dut = dut.io, 97 | clockDomain = dut.clockDomain, 98 | enc = false, 99 | blockIn = cipher, 100 | keyIn = key)((a: BigInt, b: BigInt, c: Boolean) => plain) 101 | 102 | } 103 | 104 | // Release the valid signal at the end of the simulation 105 | dut.io.cmd.valid #= false 106 | 107 | dut.clockDomain.waitActiveEdge(40) 108 | } 109 | } 110 | 111 | 112 | /** 113 | * Test - TwoFish (192-bit) 114 | */ 115 | test("TwoFishCoreStd_192"){ 116 | 117 | SimConfig.withConfig(SpinalConfig(inlineRom = true)).withWave(6).compile(new TwofishCore_Std(192 bits)).doSim { dut => 118 | 119 | dut.clockDomain.forkStimulus(2) 120 | 121 | // initialize value 122 | dut.io.cmd.valid #= false 123 | dut.io.cmd.block.randomize() 124 | dut.io.cmd.key.randomize() 125 | if (dut.io.config.useEncDec) dut.io.cmd.enc.randomize() 126 | 127 | dut.clockDomain.waitActiveEdge() 128 | 129 | for ((key, plain, cipher) <- (ref_key_192, ref_plain_192, ref_cipher_192).zipped) { 130 | 131 | 132 | SymmetricCryptoBlockIOSim.doSim( 133 | dut = dut.io, 134 | clockDomain = dut.clockDomain, 135 | enc = true, 136 | blockIn = plain, 137 | keyIn = key)((a: BigInt, b: BigInt, c: Boolean) => cipher) 138 | 139 | SymmetricCryptoBlockIOSim.doSim( 140 | dut = dut.io, 141 | clockDomain = dut.clockDomain, 142 | enc = false, 143 | blockIn = cipher, 144 | keyIn = key)((a: BigInt, b: BigInt, c: Boolean) => plain) 145 | 146 | } 147 | 148 | // Release the valid signal at the end of the simulation 149 | dut.io.cmd.valid #= false 150 | 151 | dut.clockDomain.waitActiveEdge(40) 152 | } 153 | } 154 | 155 | 156 | /** 157 | * Test - TwoFish (256-bit) 158 | */ 159 | test("TwoFishCoreStd_256"){ 160 | 161 | SimConfig.withConfig(SpinalConfig(inlineRom = true)).withWave(6).compile(new TwofishCore_Std(256 bits)).doSim { dut => 162 | 163 | dut.clockDomain.forkStimulus(2) 164 | 165 | // initialize value 166 | dut.io.cmd.valid #= false 167 | dut.io.cmd.block.randomize() 168 | dut.io.cmd.key.randomize() 169 | if (dut.io.config.useEncDec) dut.io.cmd.enc.randomize() 170 | 171 | dut.clockDomain.waitActiveEdge() 172 | 173 | for ((key, plain, cipher) <- (ref_key_256, ref_plain_256, ref_cipher_256).zipped) { 174 | 175 | 176 | SymmetricCryptoBlockIOSim.doSim( 177 | dut = dut.io, 178 | clockDomain = dut.clockDomain, 179 | enc = true, 180 | blockIn = plain, 181 | keyIn = key)((a: BigInt, b: BigInt, c: Boolean) => cipher) 182 | 183 | SymmetricCryptoBlockIOSim.doSim( 184 | dut = dut.io, 185 | clockDomain = dut.clockDomain, 186 | enc = false, 187 | blockIn = cipher, 188 | keyIn = key)((a: BigInt, b: BigInt, c: Boolean) => plain) 189 | 190 | } 191 | 192 | // Release the valid signal at the end of the simulation 193 | dut.io.cmd.valid #= false 194 | 195 | dut.clockDomain.waitActiveEdge(40) 196 | } 197 | } 198 | 199 | 200 | 201 | } 202 | -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/construtor/SpongeCore_Std.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.construtor 27 | 28 | import spinal.core._ 29 | import spinal.crypto.primitive.keccak.{FuncIO_Std} 30 | import spinal.lib._ 31 | 32 | 33 | 34 | case class SpongeCoreCmd_Std(width: Int) extends Bundle { 35 | val n = Bits(width bits) 36 | } 37 | 38 | case class SpongeCoreRsp_Std(width: Int) extends Bundle { 39 | val z = Bits(width bits) 40 | } 41 | 42 | 43 | /** 44 | * SPONGE[f, pad, r](N,d). 45 | * where f = function on fixed-length string 46 | * pad = padding rule 47 | * r = rate 48 | * N = bit string 49 | * d = bit length of the output string 50 | * 51 | * 52 | * The rate r is a positive integer that is strictly less than the width b. The capacity, denoted by c, is 53 | * the positive integer b+r. Thus, r + c = b. 54 | * 55 | * N Absorbing | Squeezing Z 56 | * | | | 57 | * PAD(*)------------ ... ----\ | /------- ... ------------------> TRUNC 58 | * __ | ___ | ___ | | ___ | ___ | 59 | * | | | | | | | | | | | | | | | | 60 | * (r) | | - XOR ->| | - XOR ->| |--|---->| | ---->| |----> 61 | * |__| | f | .... | f | | | f | ... | f | 62 | * | | | | | | | | | | | 63 | * (c) | | ------->| | ------->| |--|---->| | ---->| |----> 64 | * |__| |___| |___| | |___| |___| 65 | * 66 | * (*) the padding is done outside of this component 67 | */ 68 | class SpongeCore_Std(capacity: Int, rate: Int, d: Int) extends Component { 69 | 70 | val b = capacity + rate 71 | val nbrSqueeze = scala.math.floor(d / rate.toDouble).toInt 72 | 73 | /** 74 | * IO 75 | */ 76 | val io = new Bundle { 77 | val init = in Bool() 78 | val cmd = slave(Stream(Fragment(SpongeCoreCmd_Std(rate)))) 79 | val rsp = master(Flow(SpongeCoreRsp_Std(d))) 80 | val func = master(FuncIO_Std(b, b)) 81 | } 82 | 83 | val rReg = Reg(Bits(rate bits)) 84 | val cReg = Reg(Bits(capacity bits)) 85 | val zReg = if(nbrSqueeze != 0) Reg(Bits(rate * (nbrSqueeze + 1) bits)) else null 86 | 87 | val isProcessing = RegInit(False) 88 | val isSqueezing = RegInit(False) 89 | val cntSqueeze = if(nbrSqueeze != 0) Reg(UInt(log2Up(nbrSqueeze + 1) bits)) else null 90 | val saveInR = if(nbrSqueeze != 0) False else null 91 | 92 | // Cmd func component 93 | io.func.cmd.valid := isProcessing 94 | io.func.cmd.payload := (isSqueezing ? rReg | (io.cmd.n ^ rReg)) ## cReg 95 | 96 | // Rsp sponge 97 | val spg_rspValid = False 98 | val spg_cmdReady = False 99 | 100 | io.rsp.valid := RegNext(spg_rspValid, False) 101 | io.cmd.ready := RegNext(spg_cmdReady, False) 102 | io.rsp.z := (if(nbrSqueeze != 0) zReg else rReg).resizeLeft(d) 103 | 104 | 105 | /** 106 | * Save func.rsp.data in rReg 107 | */ 108 | if(nbrSqueeze != 0){ 109 | when(saveInR){ 110 | zReg.subdivideIn(rate bits).reverse(cntSqueeze.resized) := io.func.rsp.payload.resizeLeft(rate) 111 | } 112 | } 113 | 114 | 115 | /** 116 | * init 117 | */ 118 | when(io.init){ 119 | rReg := 0 120 | cReg := 0 121 | isSqueezing := False 122 | isProcessing := False 123 | if(nbrSqueeze != 0) cntSqueeze := 0 124 | } 125 | 126 | 127 | /** 128 | * Start processing 129 | */ 130 | when(io.cmd.valid && !io.cmd.ready && !isProcessing){ 131 | isProcessing := True 132 | } 133 | 134 | 135 | /** 136 | * Wait response of the function 137 | */ 138 | when(io.func.rsp.valid){ 139 | 140 | // Store the response 141 | rReg := io.func.rsp.payload(b - 1 downto capacity) 142 | cReg := io.func.rsp.payload(capacity - 1 downto 0) 143 | 144 | /** 145 | * Squeezing 146 | */ 147 | if(nbrSqueeze != 0){ 148 | 149 | when(isSqueezing){ 150 | 151 | cntSqueeze := cntSqueeze + 1 152 | saveInR := True 153 | 154 | when(cntSqueeze === nbrSqueeze ){ 155 | isSqueezing := False 156 | isProcessing := False 157 | spg_rspValid := True 158 | spg_cmdReady := True 159 | } 160 | } 161 | } 162 | 163 | /** 164 | * Absorbing 165 | */ 166 | when(!isSqueezing){ 167 | 168 | if(nbrSqueeze == 0){ 169 | spg_rspValid := io.cmd.last 170 | spg_cmdReady := True 171 | isProcessing := False 172 | }else{ 173 | spg_cmdReady := !io.cmd.last 174 | isProcessing := io.cmd.last 175 | isSqueezing := io.cmd.last 176 | saveInR := io.cmd.last 177 | when(io.cmd.last){ 178 | cntSqueeze := cntSqueeze + 1 179 | } 180 | } 181 | } 182 | } 183 | } 184 | 185 | 186 | -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/symmetric/des/DES.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.symmetric.des 27 | 28 | import spinal.core._ 29 | 30 | 31 | /** 32 | * Constants for the DES Core 33 | */ 34 | object DES { 35 | 36 | def initialPermutation = Seq( 37 | 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 38 | 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 39 | 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 40 | 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 41 | ) 42 | 43 | def finalPermutation = Seq( 44 | 40, 8, 48, 16, 56, 24, 64, 32, 39, 7, 47, 15, 55, 23, 63, 31, 45 | 38, 6, 46, 14, 54, 22, 62, 30, 37, 5, 45, 13, 53, 21, 61, 29, 46 | 36, 4, 44, 12, 52, 20, 60, 28, 35, 3, 43, 11, 51, 19, 59, 27, 47 | 34, 2, 42, 10, 50, 18, 58, 26, 33, 1, 41, 9, 49, 17, 57, 25 48 | ) 49 | 50 | def expansion = List( 51 | 32, 1, 2, 3, 4, 5, 4, 5, 6, 7, 8, 9, 52 | 8, 9, 10, 11, 12, 13, 12, 13, 14, 15, 16, 17, 53 | 16, 17, 18, 19, 20, 21, 20, 21, 22, 23, 24, 25, 54 | 24, 25, 26, 27, 28, 29, 28, 29, 30, 31, 32, 1 55 | ) 56 | 57 | def fixedPermutation = List( 58 | 16, 7 , 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 59 | 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 60 | ) 61 | 62 | def pc_1 = Seq( 63 | 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 64 | 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 65 | 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 66 | 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 67 | ) 68 | 69 | def pc_2 = Seq( 70 | 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 71 | 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 72 | 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 73 | 44, 49, 39, 56, 34, 53, 46, 42, 50, 36, 29, 32 74 | ) 75 | 76 | /* SBox definition */ 77 | def sBox_1 = List( 78 | 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7, 79 | 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8, 80 | 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0, 81 | 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 82 | ) 83 | 84 | def sBox_2 = List( 85 | 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10, 86 | 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5, 87 | 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15, 88 | 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 89 | ) 90 | 91 | def sBox_3 = List( 92 | 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8, 93 | 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1, 94 | 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7, 95 | 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 96 | ) 97 | 98 | def sBox_4 = List( 99 | 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15, 100 | 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9, 101 | 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4, 102 | 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 103 | ) 104 | 105 | def sBox_5 = List( 106 | 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9, 107 | 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6, 108 | 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14, 109 | 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 110 | ) 111 | 112 | def sBox_6 = List( 113 | 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11, 114 | 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8, 115 | 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6, 116 | 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 117 | ) 118 | 119 | def sBox_7 = List( 120 | 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1, 121 | 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6, 122 | 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2, 123 | 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 124 | ) 125 | 126 | def sBox_8 = List( 127 | 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7, 128 | 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2, 129 | 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8, 130 | 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 131 | ) 132 | 133 | /* Data width */ 134 | def blockWidth = 64 bits 135 | def keyWidth = 56 bits 136 | def keyWidthParity = 8 bits 137 | 138 | /** Number of Round used by DES */ 139 | def nbrRound = 16 140 | 141 | /** Used by the key scheduling */ 142 | def oneShiftRound = List(1,2,9,16) // 1 left rotation for round 1,2,9,16 and others 2 left shift rotation 143 | 144 | 145 | /** 146 | * Permutation, Compression and expansion 147 | * These functions permute a vector thanks to the table (!! The table is given for a software application !!) 148 | */ 149 | def permutation(table: Seq[Int], vector: Bits): Bits = expansion(table.toList, vector) 150 | 151 | def compression(table: Seq[Int], vector: Bits): Bits = expansion(table.toList,vector) 152 | 153 | def expansion(table: List[Int], vector: Bits): Bits = Cat(table.reverse.map(index => vector(vector.getWidth - index))) 154 | } 155 | -------------------------------------------------------------------------------- /tester/src/main/scala/ref/symmetric/AES.scala: -------------------------------------------------------------------------------- 1 | package ref.symmetric 2 | 3 | import java.security.MessageDigest 4 | import java.security.spec.KeySpec 5 | import java.util 6 | import javax.crypto.spec.{PBEKeySpec, SecretKeySpec} 7 | import javax.crypto.{SecretKey, SecretKeyFactory, Cipher} 8 | 9 | 10 | 11 | object AES { 12 | 13 | 14 | /** 15 | * Encrypt/Decrypt a block 16 | */ 17 | def block(keyLenght:Int, verbose: Boolean)(key: BigInt, block: BigInt, enc: Boolean) = if(enc) encryptBlock(key, block, keyLenght, verbose) else decryptBlock(key, block, keyLenght, verbose) 18 | 19 | 20 | /** 21 | * Block Encryption 22 | */ 23 | def encryptBlock(key: BigInt, block: BigInt, keyLenght:Int, verbose: Boolean = false): BigInt = { 24 | 25 | // Cast the input key 26 | val keyModified = castByteArray(key.toByteArray, keyLenght / 8) 27 | val myKey = new SecretKeySpec(keyModified, "AES") 28 | 29 | // Create the cipher 30 | val desCipher = Cipher.getInstance("AES/ECB/NoPadding") 31 | 32 | // Initialize the cipher for encryption 33 | desCipher.init(Cipher.ENCRYPT_MODE, myKey) 34 | 35 | // cast input block 36 | val blockPlain = castByteArray(block.toByteArray, 16) 37 | 38 | // Encrypt the text 39 | val blockCipher = desCipher.doFinal(blockPlain) 40 | 41 | if(verbose){ 42 | println(s"Plain : 0x${blockPlain.map(b => "%02X".format(b)).mkString("")}") 43 | println(s"KEY : 0x${myKey.getEncoded().map(b => "%02X".format(b)).mkString("")}") 44 | println(s"Cipher : 0x${blockCipher.map(b => "%02X".format(b)).mkString("")}") 45 | println("") 46 | } 47 | 48 | return BigInt(blockCipher.take(16)) 49 | } 50 | 51 | 52 | /** 53 | * Block Decryption 54 | */ 55 | def decryptBlock(key: BigInt, block: BigInt, keyLenght:Int, verbose: Boolean = false): BigInt = { 56 | 57 | // cast input key 58 | val keyModified = castByteArray(key.toByteArray, keyLenght / 8) 59 | 60 | val myKey = new SecretKeySpec(keyModified, "AES") 61 | 62 | // Create the cipher 63 | val desCipher = Cipher.getInstance("AES/ECB/NoPadding") 64 | 65 | // Initialize the cipher for encryption 66 | desCipher.init(Cipher.DECRYPT_MODE, myKey) 67 | 68 | // cast input block 69 | val blockCipher = castByteArray(block.toByteArray, 16) 70 | 71 | // Encrypt the text 72 | 73 | val blockPlain = desCipher.doFinal(blockCipher) 74 | 75 | if(verbose){ 76 | println(s"Cipher : 0x${blockCipher.map(b => "%02X".format(b)).mkString("")}") 77 | println(s"KEY : 0x${myKey.getEncoded().map(b => "%02X".format(b)).mkString("")}") 78 | println(s"Plain : 0x${blockPlain.map(b => "%02X".format(b)).mkString("")}") 79 | println("") 80 | } 81 | 82 | return BigInt(blockPlain.take(16)) 83 | } 84 | 85 | 86 | /** 87 | * Cast the input array to x byte 88 | */ 89 | private def castByteArray(input: Array[Byte], castSize: Int): Array[Byte] = { 90 | if(input.length == castSize){ 91 | input 92 | }else if(input.length > castSize){ 93 | input.takeRight(castSize) 94 | }else{ 95 | Array.fill[Byte](castSize - input.length)(0x00) ++ input 96 | } 97 | } 98 | } 99 | 100 | 101 | 102 | // 128 => 16 103 | // 192 => 24 104 | // 256 => 32 105 | object PlayWithRefAES extends App{ 106 | 107 | // val cipher = AES.encryptBlock(BigInt("11223344", 16), BigInt("eca93cda1c63a01feca93cda1c63a01f", 16), 192, true) 108 | // 109 | // def bigIntToHex(value: BigInt): String = s"0x${value.toByteArray.map(b => f"${b}%02X").mkString("")}" 110 | // 111 | // println(bigIntToHex(cipher) + "\n") 112 | // 113 | // val plain = AES.decryptBlock(BigInt("000000e454454f7e000000e454454f7e54454f7e54454f7e", 16), cipher, 192, true) 114 | // 115 | // println(bigIntToHex(plain)) 116 | def getSecretKeySpec( 117 | passphrase: String, 118 | algorithm: String, 119 | kgenbit: Int 120 | ): SecretKeySpec = { 121 | val salt: Array[Byte] = Array( 122 | 0xA9.asInstanceOf[Byte], 123 | 0x87.asInstanceOf[Byte], 124 | 0xC8.asInstanceOf[Byte], 125 | 0x32.asInstanceOf[Byte], 126 | 0x56.asInstanceOf[Byte], 127 | 0xA5.asInstanceOf[Byte], 128 | 0xE3.asInstanceOf[Byte], 129 | 0xB2.asInstanceOf[Byte] 130 | ) 131 | val iterationCount = 1024 132 | val keySpec: KeySpec = new PBEKeySpec( 133 | passphrase.toCharArray, 134 | salt, 135 | iterationCount 136 | ) 137 | val secretKey: SecretKey = SecretKeyFactory.getInstance( 138 | "PBEWithMD5AndDES" 139 | ).generateSecret(keySpec) 140 | val md: MessageDigest = MessageDigest.getInstance("MD5") 141 | md.update(secretKey.getEncoded) 142 | md.update(salt) 143 | for (i <- 1 until iterationCount) { 144 | md.update(md.digest()) 145 | } 146 | val keyBytes: Array[Byte] = md.digest 147 | val skeyspec: SecretKeySpec = new SecretKeySpec(keyBytes, algorithm) 148 | skeyspec 149 | } 150 | 151 | 152 | def encrypt( 153 | message: Array[Byte], 154 | secret: String, 155 | scheme: String = "AES", 156 | bits: Int = 192 157 | ): Array[Byte] = { 158 | /* 159 | byte[] keyBytes = "ThisIs128bitSize".getBytes(); 160 | Key key = new SecretKeySpec(keyBytes, "AES"); 161 | Cipher c = Cipher.getInstance("AES"); 162 | c.init(Cipher.DECRYPT_MODE, key); 163 | byte[] decValue = c.doFinal(encryptedText); 164 | String decryptedValue = new String(decValue); 165 | return decryptedValue; 166 | */ 167 | val skeySpec: SecretKeySpec = getSecretKeySpec(secret, scheme, bits) 168 | //val skeySpec: SecretKeySpec = new SecretKeySpec(secret.toByte, "AES") 169 | println(skeySpec) 170 | val cipher: Cipher = Cipher.getInstance("AES/ECB/NoPadding") 171 | println(skeySpec.getAlgorithm) 172 | cipher.init(Cipher.ENCRYPT_MODE, skeySpec) 173 | val encrypted: Array[Byte] = cipher.doFinal(message) 174 | encrypted 175 | } 176 | 177 | /** 178 | * Decrypt a byte array given the same secret key spec used to encrypt the 179 | * message. 180 | 181 | */ 182 | def decrypt( 183 | message: Array[Byte], 184 | secret: String, 185 | scheme: String = "AES", 186 | bits: Int = 192 187 | ): Array[Byte] = { 188 | val skeySpec: SecretKeySpec = getSecretKeySpec(secret, scheme, bits) 189 | val cipher: Cipher = Cipher.getInstance("AES/ECB/NoPadding") 190 | 191 | cipher.init(Cipher.DECRYPT_MODE, skeySpec) 192 | val decrypted: Array[Byte] = cipher.doFinal(message) 193 | decrypted 194 | } 195 | 196 | def asHexStr(buf: Array[Byte]): String = { 197 | import java.lang.{Long => JLong} 198 | val strbuf: StringBuffer = new StringBuffer(buf.length * 2) 199 | for (i <- 0 until buf.length) { 200 | if ((buf(i).asInstanceOf[Int] & 0xff) < 0x10) { 201 | strbuf.append("0") 202 | } 203 | strbuf.append(JLong.toString(buf(i).asInstanceOf[Int] & 0xff, 16)) 204 | } 205 | strbuf.toString 206 | } 207 | 208 | 209 | 210 | var message: String = "This is just an " 211 | System.out.println("(HEX) Original : " + asHexStr(message.getBytes)) 212 | var encrypted: Array[Byte] = encrypt(message.getBytes, "1111111122222222333333334444444411111111222222223333333344444444", "AES", 256) 213 | System.out.println("(HEX) Encrypted : " + asHexStr(encrypted)) 214 | var decrypted: Array[Byte] = decrypt(encrypted, "mypassword", "AES", 128) 215 | System.out.println("(HEX) Decrypted : " + asHexStr(decrypted)) 216 | if (util.Arrays.equals(decrypted, message.getBytes)) { 217 | System.out.println("THE ONE AND THE SAME") 218 | } 219 | 220 | 221 | 222 | 223 | } -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/checksum/CRCCombinational.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ ** 7 | ** ** 8 | ** This library is free software; you can redistribute it and/or ** 9 | ** modify it under the terms of the GNU Lesser General Public ** 10 | ** License as published by the Free Software Foundation; either ** 11 | ** version 3.0 of the License, or (at your option) any later version. ** 12 | ** ** 13 | ** This library is distributed in the hope that it will be useful, ** 14 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** 15 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ** 16 | ** Lesser General Public License for more details. ** 17 | ** ** 18 | ** You should have received a copy of the GNU Lesser General Public ** 19 | ** License along with this library. ** 20 | \* */ 21 | package spinal.crypto.checksum 22 | 23 | import spinal.core._ 24 | import spinal.lib._ 25 | import spinal.crypto._ 26 | import spinal.lib.bus.misc.BusSlaveFactory 27 | 28 | import scala.collection.mutable.ListBuffer 29 | 30 | /** 31 | * CRC combinational 32 | * 33 | * Doc : 34 | * - http://www.sigmatone.com/utilities/crc_generator/crc_generator.htm 35 | * - http://www.sunshine2k.de/articles/coding/crc/understanding_crc.html 36 | * - http://crccalc.com/ 37 | */ 38 | 39 | 40 | /** 41 | * CRC Configuration 42 | * 43 | * @param crcConfig : String representing the equation 44 | * @param dataWidth : Bus data width 45 | */ 46 | case class CRCCombinationalConfig( 47 | crcConfig : CRCPolynomial, 48 | dataWidth : BitCount 49 | ){ 50 | val crcWidth = crcConfig.polynomial.order bits 51 | } 52 | 53 | 54 | object CRCCombinationalCmdMode extends SpinalEnum{ 55 | val INIT, UPDATE = newElement() 56 | } 57 | 58 | 59 | case class CRCCombinationalCmd(g: CRCCombinationalConfig) extends Bundle{ 60 | val mode = CRCCombinationalCmdMode() 61 | val data = Bits(g.dataWidth) 62 | } 63 | 64 | 65 | case class CRCCombinationalIO(g: CRCCombinationalConfig) extends Bundle{ 66 | 67 | val cmd = slave Flow(CRCCombinationalCmd(g)) 68 | val crc = out Bits(g.crcWidth) 69 | 70 | /** Drive IO from a bus */ 71 | def driveFrom(busCtrl: BusSlaveFactory, baseAddress: Int = 0) = new Area { 72 | 73 | busCtrl.driveFlow(cmd, baseAddress + 0x00) 74 | 75 | busCtrl.read(crc, baseAddress + 0x08) 76 | } 77 | } 78 | 79 | 80 | /** 81 | * CRC Combinational component 82 | */ 83 | class CRCCombinational(g: CRCCombinationalConfig) extends Component{ 84 | 85 | assert(g.dataWidth.value % 8 == 0, "Currently support only datawidth multiple of 8") 86 | assert(g.crcConfig.polynomial.order % 8 == 0, "Currently support only polynomial degree multiple of 8") 87 | 88 | import CRCCombinationalCmdMode._ 89 | 90 | val io = CRCCombinationalIO(g) 91 | 92 | // Input operation 93 | val crc_reg = Reg(cloneOf(io.crc)) 94 | val dataIn = if(g.crcConfig.inputReflected) EndiannessSwap(Reverse(io.cmd.data)) else io.cmd.data 95 | 96 | // Compute the CRC 97 | val next_crc = CRCCombinationalCore(dataIn, crc_reg, g.crcConfig.polynomial) 98 | 99 | // Init 100 | when(io.cmd.valid && io.cmd.mode === INIT){ 101 | crc_reg := B(g.crcConfig.initValue, io.crc.getWidth bits) 102 | } 103 | 104 | // Update 105 | when(io.cmd.valid && io.cmd.mode === UPDATE){ 106 | crc_reg := next_crc 107 | } 108 | 109 | // Output operation 110 | val result_reflected = if(g.crcConfig.outputReflected) Reverse(crc_reg) else crc_reg 111 | 112 | io.crc := result_reflected ^ B(g.crcConfig.finalXor, crc_reg.getWidth bits) 113 | } 114 | 115 | 116 | /** 117 | * CRC combinational core 118 | */ 119 | object CRCCombinationalCore { 120 | 121 | 122 | case class Register(name: String, index: Int){ 123 | def ==(that: Register): Boolean = { 124 | return this.name == that.name && this.index == that.index 125 | } 126 | 127 | override def toString: String = s"${name}(${index})" 128 | } 129 | 130 | /** 131 | * Creaete a CRC combinational core 132 | * @param data : data input of the crc 133 | * @param crc : current crc value 134 | * @param polynomial : CRC polynomial 135 | * @return newCRC 136 | */ 137 | def apply(data: Bits, crc: Bits, polynomial: PolynomialGF2) : Bits ={ 138 | 139 | val newCRC = cloneOf(crc) 140 | 141 | val listXor = lfsrCRCGenerator(polynomial, data.getWidth) 142 | 143 | for(i <- 0 until crc.getWidth){ 144 | newCRC(i) := listXor(i).map(t => if (t.name == "D") data(t.index) else crc(t.index)).reduce(_ ^ _) 145 | } 146 | 147 | newCRC 148 | } 149 | 150 | /** 151 | * Use a LFSR to compute the xor combination for each index in order to perform the CRC in one clock 152 | * 153 | * Rule : Build a LFSR from a polynomial : 154 | * 1 * x^0 = 1 => feedback 155 | * 1 * x^n => x^n xor x^(n-1) 156 | * 0 * x^0 => do noting 157 | * 158 | * e.g : x^3+x+1 159 | * 160 | * /-------------------------------------------XOR<-- D2,D1,D0 161 | * | ____ | ____ ____ | 162 | * \->|_C0_|---XOR--->|_C1_|------------|_C2_|--/ 163 | * 0: c0 c1 c2 D2,D1,D0 164 | * 1: c2^d2 c0^c2^d2 c1 D1,D0 165 | * 2: c1^d1 c2^d2^c1^d1 c0^c2^d2 D0 166 | * 3: c0^c2^d2^d0 c1^d1^c0^c2^d2^d0 c2^d2^c1^d1 - 167 | * 168 | * crc(0) = c0^c2^d2^d0 169 | * crc(1) = c1^d1^c0^c2^d2^d0 170 | * crc(2) = c2^d2^c1^d1 171 | */ 172 | def lfsrCRCGenerator(polynomial: PolynomialGF2, dataWidth: Int):List[List[Register]]={ 173 | 174 | assert(dataWidth <= polynomial.order, "dataWidth can't be bigger than the polynomial length") 175 | 176 | val listPolynomial = polynomial.toBooleanList() 177 | val lenLFSR = polynomial.order // nbr of register used by the LFSR 178 | 179 | // initialize the LFSR register 180 | var lfsr = (for(i <- 0 until lenLFSR) yield List(Register("C", i))).toList 181 | 182 | // execute the LFSR dataWidth number of time 183 | for(j <- 0 until dataWidth) { 184 | 185 | val result = new ListBuffer[List[Register]]() 186 | result += lfsr(lenLFSR - 1) ::: List(Register("D", dataWidth - 1 - j)) 187 | 188 | for (i <- 1 until lenLFSR) { 189 | if (listPolynomial(lenLFSR - i) == false) { 190 | result += lfsr(i - 1) 191 | } else { 192 | result += lfsr(i - 1) ::: lfsr(lenLFSR - 1) ::: List(Register("D", dataWidth - 1 - j)) 193 | } 194 | } 195 | 196 | lfsr = result.toList 197 | } 198 | 199 | // Simplify (odd number => replace by one occurrence, even number => remove all occurrence) 200 | val finalRes = new ListBuffer[List[Register]]() 201 | for(lt <- lfsr){ 202 | val listD = (for(i <- 0 until lenLFSR if (lt.count(_ == Register("D", i)) % 2 == 1)) yield Register("D", i)).toList 203 | val listC = (for(i <- 0 until lenLFSR if (lt.count(_ == Register("C", i)) % 2 == 1)) yield Register("C", i)).toList 204 | finalRes += (listD ++ listC) 205 | } 206 | 207 | finalRes.toList 208 | } 209 | } -------------------------------------------------------------------------------- /crypto/src/main/scala/spinal/crypto/padding/HashPadding_Std.scala: -------------------------------------------------------------------------------- 1 | /* *\ 2 | ** _____ ____ _____ _____ __ ** 3 | ** / ___// __ \/ _/ | / / | / / Crypto ** 4 | ** \__ \/ /_/ // // |/ / /| | / / (c) Dolu, All rights reserved ** 5 | ** ___/ / ____// // /| / ___ |/ /___ ** 6 | ** /____/_/ /___/_/ |_/_/ |_/_____/ MIT Licence ** 7 | ** ** 8 | ** Permission is hereby granted, free of charge, to any person obtaining a ** 9 | ** copy of this software and associated documentation files (the "Software"),** 10 | ** to deal in the Software without restriction, including without limitation ** 11 | ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** 12 | ** and/or sell copies of the Software, and to permit persons to whom the ** 13 | ** Software is furnished to do so, subject to the following conditions: ** 14 | ** ** 15 | ** The above copyright notice and this permission notice shall be included ** 16 | ** in all copies or substantial portions of the Software. ** 17 | ** ** 18 | ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS ** 19 | ** OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF ** 20 | ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. ** 21 | ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY ** 22 | ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT ** 23 | ** OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR ** 24 | ** THE USE OR OTHER DEALINGS IN THE SOFTWARE. ** 25 | \* */ 26 | package spinal.crypto.padding 27 | 28 | import spinal.core._ 29 | import spinal.crypto.hash._ 30 | import spinal.lib.fsm._ 31 | import spinal.lib._ 32 | 33 | 34 | /** 35 | * Configuration of the Hash Padding core 36 | */ 37 | case class HashPadding_Config( 38 | dataInWidth : BitCount, 39 | dataOutWidth : BitCount , 40 | endianess : EndiannessMode, 41 | symbolWidth : BitCount = 8 bits 42 | ) extends PaddingConfig(dataInWidth, dataOutWidth, symbolWidth) 43 | 44 | 45 | /** 46 | * Hash Padding 47 | * 48 | * The message to hash must be padded as following: 49 | * - Add a one bit a the end of the message 50 | * - Add a sequence of 0 until to get a block of 448-bits 51 | * - Write the size in bits of the message on 64 bits (l0 l1) e.g : 24 bits => 00000018 00000000 52 | * 53 | */ 54 | class HashPadding_Std(config: HashPadding_Config) extends Component { 55 | 56 | assert(config.dataInWidth.value == 32, "Currently Hash padding supports only 32 bits") 57 | 58 | val io = slave(PaddingIO(config.getPaddingIOConfig)) 59 | 60 | val nbrWordInBlock = config.dataOutWidth.value / config.dataInWidth.value 61 | val nbrByteInWord = config.dataInWidth.value / 8 62 | 63 | val cntBit = Reg(UInt(64 bits)) 64 | val block = Reg(Vec(Bits(config.dataInWidth), nbrWordInBlock)) 65 | val indexWord = Reg(UInt(log2Up(nbrWordInBlock) bits)) 66 | 67 | // default value 68 | io.rsp.data := block.asBits 69 | io.rsp.valid := False // default value 70 | io.cmd.ready := False // default value 71 | 72 | val maskMsg = io.cmd.size.mux( 73 | U"00" -> (if(config.endianess == LITTLE_endian) B"x000000FF" else B"xFF000000"), 74 | U"01" -> (if(config.endianess == LITTLE_endian) B"x0000FFFF" else B"xFFFF0000"), 75 | U"10" -> (if(config.endianess == LITTLE_endian) B"x00FFFFFF" else B"xFFFFFF00"), 76 | U"11" -> B"xFFFFFFFF" 77 | ) 78 | 79 | val maskSet1 = io.cmd.size.mux( 80 | U"00" -> (if(config.endianess == LITTLE_endian) B"x00008000" else B"x00800000"), 81 | U"01" -> (if(config.endianess == LITTLE_endian) B"x00800000" else B"x00008000"), 82 | U"10" -> (if(config.endianess == LITTLE_endian) B"x80000000" else B"x00000080"), 83 | U"11" -> B"x00000000" 84 | ) 85 | 86 | /** 87 | * Padding state machine 88 | */ 89 | val sm = new StateMachine { 90 | 91 | val addPaddingNextWord = Reg(Bool) 92 | val isBiggerThan448 = Reg(Bool) 93 | val fillNewBlock = Reg(Bool) 94 | 95 | val isLastFullWordInBlock = indexWord === 0 && io.cmd.size === (nbrByteInWord - 1) 96 | 97 | always{ 98 | when(io.init){ 99 | cntBit := 0 100 | indexWord := nbrWordInBlock - 1 101 | block.map(_ := 0) 102 | goto(sLoad) 103 | } 104 | } 105 | 106 | val sLoad: State = new State with EntryPoint{ /* Load the block register of 512-bit */ 107 | whenIsActive{ 108 | 109 | addPaddingNextWord := True 110 | isBiggerThan448 := False 111 | fillNewBlock := False 112 | 113 | when(io.cmd.valid){ 114 | 115 | block(indexWord) := io.cmd.data 116 | 117 | when(io.cmd.last){ 118 | 119 | cntBit := cntBit + io.cmd.size.mux( 120 | U"00" -> 8, 121 | U"01" -> 16, 122 | U"10" -> 24, 123 | U"11" -> 32 124 | ) 125 | when(isLastFullWordInBlock){ 126 | goto(sProcessing) 127 | }otherwise{ 128 | isBiggerThan448 := indexWord < 2 || (indexWord === 2 && io.cmd.size === (nbrByteInWord - 1)) 129 | goto(sPadding) 130 | } 131 | }otherwise{ 132 | 133 | cntBit := cntBit + config.dataInWidth.value 134 | indexWord := indexWord - 1 135 | 136 | when(indexWord === 0){ 137 | goto(sProcessing) 138 | }otherwise{ 139 | io.cmd.ready := True 140 | } 141 | } 142 | } 143 | } 144 | 145 | val sPadding: State = new State { /* Do padding */ 146 | onEntry{ 147 | 148 | when(isLastFullWordInBlock || fillNewBlock){ 149 | indexWord := nbrWordInBlock - 1 150 | fillNewBlock := False 151 | }otherwise{ 152 | block(indexWord) := (io.cmd.data & maskMsg) | maskSet1 153 | when(indexWord =/= 0) { indexWord := indexWord - 1 } 154 | when(io.cmd.size =/= (nbrByteInWord - 1)){ addPaddingNextWord := False } 155 | } 156 | } 157 | 158 | whenIsActive{ 159 | 160 | when(indexWord > 1 || isBiggerThan448){ 161 | 162 | indexWord := indexWord - 1 163 | 164 | when(addPaddingNextWord){ 165 | block(indexWord) := (if(config.endianess == LITTLE_endian) B"x00000080" else B"x80000000") 166 | addPaddingNextWord := False 167 | }otherwise{ 168 | when(indexWord =/= 0){ 169 | block(indexWord) := B(0).resized 170 | } 171 | } 172 | 173 | when(indexWord === 0){ 174 | fillNewBlock := True 175 | goto(sProcessing) 176 | } 177 | 178 | }otherwise{ 179 | 180 | if(config.endianess == LITTLE_endian){ 181 | block(1) := cntBit(31 downto 0).asBits 182 | block(0) := cntBit(63 downto 32).asBits 183 | }else{ 184 | block(0) := cntBit(31 downto 0).asBits 185 | block(1) := cntBit(63 downto 32).asBits 186 | } 187 | 188 | goto(sProcessing) 189 | } 190 | } 191 | } 192 | 193 | val sProcessing: State = new State { /* Run Hash Engine */ 194 | whenIsActive{ 195 | io.rsp.valid := True 196 | 197 | when(io.rsp.ready){ 198 | 199 | block.map(_ := 0) 200 | 201 | when(isBiggerThan448 || isLastFullWordInBlock) { 202 | isBiggerThan448 := False 203 | goto(sPadding) 204 | } otherwise { 205 | io.cmd.ready := True 206 | goto(sLoad) 207 | } 208 | } 209 | } 210 | } 211 | } 212 | } 213 | } -------------------------------------------------------------------------------- /tester/src/main/scala/cryptotest/SpinalSimAESCoreTester.scala: -------------------------------------------------------------------------------- 1 | package cryptotest 2 | 3 | import org.scalatest.funsuite.AnyFunSuite 4 | import ref.symmetric.AES 5 | import spinal.crypto.symmetric.aes.AESCore_Std 6 | import spinal.crypto.symmetric.sim.SymmetricCryptoBlockIOSim 7 | import spinal.core._ 8 | import spinal.core.sim._ 9 | 10 | import scala.util.Random 11 | 12 | 13 | class SpinalSimAESCoreTester extends AnyFunSuite { 14 | 15 | val NBR_ITERATION = 20 16 | 17 | val ref_key_192 = List( 18 | BigInt("6ABBBC50D08AFC199FBC016526C4283B8FEC6D2B885FC561", 16), 19 | BigInt("A2ED76AFC3F9D4E7681E713F93B61BD155D1A2D7DE357BDD", 16), 20 | BigInt("53F68E3E567773D3F3547CDBACC6A30E088351E6452A53C3", 16), 21 | BigInt("B1899353221201AE06BC2727B7C9C7BE68E32E5CAB155729", 16), 22 | BigInt("EE0009BB08CCC77C279D7B38DC3758C9F299B26BE3BF9F66", 16), 23 | BigInt("00480C389D551E03EB87031102C6661A8DB7CDDBC30BB827", 16), 24 | BigInt("76A9A31C04226A885BD42FDFAA1C04DDC2E1488B15C961A9", 16), 25 | BigInt("21F3EB61A808BA8F4C35F56A9F105258959C9054CD4DDF8C", 16), 26 | BigInt("22E73418B0C00D26E196A808E5DF6B746CC50944A2359B4F", 16), 27 | BigInt("26328555A340EBAE7F0656A1B418493DA49C2C83D4705705", 16), 28 | BigInt("EA24B53818A6CBCC209CD36321D14B3A688A43F2122B071E", 16), 29 | BigInt("8652D785134E52DF8E5EC717A4344DEA3BF700CF319294A2", 16) 30 | ) 31 | 32 | val ref_plain_192 = List( 33 | BigInt("A7B8FAAF3AE1242BBC78855109D277EA", 16), 34 | BigInt("2D234D2A0A3657DBD18A9527EBE33594", 16), 35 | BigInt("46205D6E3C11C5A7601040848512CE06", 16), 36 | BigInt("1D3AC9C4FB2967EA212A60045442FECE", 16), 37 | BigInt("6A7C9EFFB8346D4A0B4BB4C986648BD2", 16), 38 | BigInt("D4F16E958EE55AED23293F87E64CF63E", 16), 39 | BigInt("50F4895D300A1EB0912D011511281540", 16), 40 | BigInt("7C96258BC956A8F95062E4499F0FF4D5", 16), 41 | BigInt("7A0C2875BF800219E89D10E9A28342AC", 16), 42 | BigInt("949E1A9E0C678AFFFDD21EEE3C04F0D4", 16), 43 | BigInt("1E3D029ACD08E4DB74B3B17D4BEB4927", 16), 44 | BigInt("EF55D405140C2ADBC8590114126CEEC9", 16) 45 | ) 46 | 47 | val ref_cipher_192 = List( 48 | BigInt("c93d735113fede10a9101a0344dae6a9", 16), 49 | BigInt("0c278804e7fe30ebcc75e93316532e50", 16), 50 | BigInt("ba92d96c42cd8e515406b64c88de8a0c", 16), 51 | BigInt("eed933e8631e53527bc6e239654bb4c6", 16), 52 | BigInt("8988e76d9c23f1b55177907745e3c1c6", 16), 53 | BigInt("06b23321b8e220b38fbf7e6b636043e5", 16), 54 | BigInt("68c276caa8afb0c85d85e460948c26b1", 16), 55 | BigInt("8f802592668cf79f19444f5b192e89fa", 16), 56 | BigInt("6eaa516f86846fb4e5b839263d432272", 16), 57 | BigInt("76489285003f71f2f3a6bffe3ae3d54a", 16), 58 | BigInt("581515f2787c8d7d33f41c241b137f78", 16), 59 | BigInt("34b6c26d50cdb79ae5f89d7ca134789c", 16) 60 | ) 61 | 62 | 63 | val ref_key_256 = List( 64 | BigInt("B00DACFFF50660170A43C7277D2745902C8E0854AEAF451096A96A96EB1F010E", 16), 65 | BigInt("563DA55F0825E3450F886BD32CF18DC772214D008E095877AD2189393EEC955D", 16), 66 | BigInt("743B0025E35CD475636372864876A04EA0500FBA8F785855E3A415EA5E178374", 16), 67 | BigInt("3EC201A67054161C9746126B501E6F1CA800A9B20C59AC232511362F8824E7FE", 16), 68 | BigInt("8787FE585483C5148AA58D5F6D74A814D99955763C9916EB74E6006A954845DE", 16), 69 | BigInt("1C59544605D493742D79F9D8CD60486D568D46E10CFFE26ECFBF84DB480C7CF5", 16), 70 | BigInt("D9101783D3D7E5C23569C524219DAD6B32B67D8A117A01FCA2B4A515E47888F8", 16), 71 | BigInt("290B038DAECCA6270927DC15CD463AF1FC9DA03A0967B1EC724B28F53EB4AE2C", 16), 72 | BigInt("BFA53A8D373227B872A4D99BD328819A19148300ED046CD6761453502CE0A454", 16), 73 | BigInt("86F5EF344BDC69D03C07D76E0CC7F21D8FB4E6EE776CB08B539DB6627DF9CA89", 16), 74 | BigInt("03B27F93CFE0F97D77BE7229EE84EAE6853601927D769AFCF4AFD8CD9C6D8618", 16), 75 | BigInt("7CC66BB6216FB1D91E0B1E7D67AF02C1DB3FBF211A1B5865FABF5EE08042DFE2", 16) 76 | ) 77 | 78 | val ref_plain_256 = List( 79 | BigInt("D857791DCB86A5B163F117B343C2C25E", 16), 80 | BigInt("593A2DA60CB845F3862681631A3EF178", 16), 81 | BigInt("4F605AE3419C74758DB0BD9B01652C17", 16), 82 | BigInt("7176658B0088A3CA6BE280C0C945EED4", 16), 83 | BigInt("96B21E268D0FE312DC8CC2423105C0F3", 16), 84 | BigInt("B152BA5F12AB00EC3036DD4DC6CA796F", 16), 85 | BigInt("97AD799973D0DFEF7321CF86C9E09A67", 16), 86 | BigInt("A0E0CCC34731335D9B982A5F1B21CBD2", 16), 87 | BigInt("7E72264880BC6517FD72CC1AA5017AE3", 16), 88 | BigInt("5419D35470B981318FC5C92FF4368FD8", 16), 89 | BigInt("9E60D4D38027A9801297AF60ED0C08B4", 16), 90 | BigInt("2B7DECE3A2715117C3EC4996CA0080D0", 16) 91 | ) 92 | 93 | val ref_cipher_256 = List( 94 | BigInt("5249276be694b468c33f2bc156cd0721", 16), 95 | BigInt("caff9811b10b8e91464eb4e0fb4ad178", 16), 96 | BigInt("2c7dfc8da3163976428f43be86714b83", 16), 97 | BigInt("8abb828e86a1bd9fca91f1e1beb846da", 16), 98 | BigInt("07ba4270db20881f1b6a6aa6d0a7b22c", 16), 99 | BigInt("5ac2812dd41af19628b40a7aff39a3b9", 16), 100 | BigInt("cca8b6888e6e9c8bd31a4d3129f3b1a8", 16), 101 | BigInt("430c45c9b2810021016e258ee585552e", 16), 102 | BigInt("460ba7300a0665554f6c7cab2bf81f82", 16), 103 | BigInt("8ef41279949290f2b87fed3436d0310c", 16), 104 | BigInt("3ef1e08388c54406a143ff888e4da248", 16), 105 | BigInt("aeb6ccd3c3e1bb91b4620bd72e2faca2", 16) 106 | ) 107 | 108 | /** 109 | * Test - AESCore_Std (128-bit) 110 | */ 111 | test("AESCoreStd_128"){ 112 | 113 | SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new AESCore_Std(128 bits)).doSim{ dut => 114 | 115 | dut.clockDomain.forkStimulus(2) 116 | 117 | // initialize value 118 | SymmetricCryptoBlockIOSim.initializeIO(dut.io) 119 | 120 | dut.clockDomain.waitActiveEdge() 121 | 122 | for(_ <- 0 to NBR_ITERATION){ 123 | 124 | SymmetricCryptoBlockIOSim.doSim(dut.io, dut.clockDomain, enc = Random.nextBoolean() )(AES.block(128, verbose = false)) 125 | } 126 | 127 | // Release the valid signal at the end of the simulation 128 | dut.io.cmd.valid #= false 129 | 130 | dut.clockDomain.waitActiveEdge() 131 | } 132 | } 133 | 134 | 135 | 136 | /** 137 | * Test - AESCore_Std (192-bit) 138 | */ 139 | test("AESCoreStd_192"){ 140 | 141 | SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new AESCore_Std(192 bits)).doSim{ dut => 142 | 143 | dut.clockDomain.forkStimulus(2) 144 | 145 | // initialize value 146 | SymmetricCryptoBlockIOSim.initializeIO(dut.io) 147 | 148 | dut.clockDomain.waitActiveEdge() 149 | 150 | 151 | for((key, plain, cipher) <- (ref_key_192, ref_plain_192, ref_cipher_192).zipped){ 152 | 153 | SymmetricCryptoBlockIOSim.doSim( 154 | dut = dut.io, 155 | clockDomain = dut.clockDomain, 156 | enc = true, 157 | blockIn = plain, 158 | keyIn = key)((a: BigInt, b: BigInt, c:Boolean) => cipher) 159 | 160 | SymmetricCryptoBlockIOSim.doSim( 161 | dut = dut.io, 162 | clockDomain = dut.clockDomain, 163 | enc = false, 164 | blockIn = cipher, 165 | keyIn = key)((a: BigInt, b: BigInt, c:Boolean) => plain) 166 | 167 | } 168 | 169 | 170 | // Release the valid signal at the end of the simulation 171 | dut.io.cmd.valid #= false 172 | 173 | dut.clockDomain.waitActiveEdge() 174 | } 175 | } 176 | 177 | 178 | 179 | 180 | /** 181 | * Test - AESCore_Std (256-bit) 182 | */ 183 | test("AESCoreStd_256"){ 184 | 185 | SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new AESCore_Std(256 bits)).doSim{ dut => 186 | 187 | dut.clockDomain.forkStimulus(2) 188 | 189 | // initialize value 190 | SymmetricCryptoBlockIOSim.initializeIO(dut.io) 191 | 192 | dut.clockDomain.waitActiveEdge() 193 | 194 | for((key, plain, cipher) <- (ref_key_256, ref_plain_256, ref_cipher_256).zipped){ 195 | 196 | 197 | SymmetricCryptoBlockIOSim.doSim( 198 | dut = dut.io, 199 | clockDomain = dut.clockDomain, 200 | enc = true, 201 | blockIn = plain, 202 | keyIn = key)((a: BigInt, b: BigInt, c:Boolean) => cipher) 203 | 204 | SymmetricCryptoBlockIOSim.doSim( 205 | dut = dut.io, 206 | clockDomain = dut.clockDomain, 207 | enc = false, 208 | blockIn = cipher, 209 | keyIn = key)((a: BigInt, b: BigInt, c:Boolean) => plain) 210 | 211 | } 212 | 213 | // Release the valid signal at the end of the simulation 214 | dut.io.cmd.valid #= false 215 | 216 | dut.clockDomain.waitActiveEdge() 217 | } 218 | } 219 | } 220 | 221 | 222 | -------------------------------------------------------------------------------- /tester/src/main/scala/cryptotest/SpinalSimSHA2CoreStdTester.scala: -------------------------------------------------------------------------------- 1 | package cryptotest 2 | 3 | 4 | 5 | import org.scalatest.funsuite.AnyFunSuite 6 | import ref.hash.SHA2 7 | import spinal.core.SpinalConfig 8 | import spinal.crypto.hash.BIG_endian 9 | import spinal.crypto.hash.sim.{HashEngineIOsim, HashIOsim} 10 | 11 | import spinal.core.sim._ 12 | import spinal.crypto.hash.sha2._ 13 | 14 | /** 15 | * Test SHA2Core_Std 16 | */ 17 | class SpinalSimSHA2CoreStdTester extends AnyFunSuite { 18 | 19 | val NBR_ITERATION = 100 20 | 21 | /** 22 | * SHA2CoreStd_256 23 | */ 24 | test("SHA2CoreStd_256") { 25 | 26 | val compiledRTL = SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new SHA2Core_Std(SHA2_256)) 27 | 28 | compiledRTL.doSim{ dut => 29 | 30 | dut.clockDomain.forkStimulus(2) 31 | 32 | HashIOsim.initializeIO(dut.io) 33 | 34 | dut.clockDomain.waitActiveEdge() 35 | 36 | for(i <- 0 to NBR_ITERATION){ 37 | HashIOsim.doSim(dut.io, dut.clockDomain, i, BIG_endian )(SHA2.digest("SHA-256")) 38 | } 39 | } 40 | } 41 | 42 | /** 43 | * SHA2CoreStd_512 44 | */ 45 | test("SHA2CoreStd_512") { 46 | 47 | val compiledRTL = SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new SHA2Core_Std(SHA2_512)) 48 | 49 | compiledRTL.doSim{ dut => 50 | 51 | dut.clockDomain.forkStimulus(2) 52 | 53 | HashIOsim.initializeIO(dut.io) 54 | 55 | dut.clockDomain.waitActiveEdge() 56 | 57 | for(i <- 0 to NBR_ITERATION){ 58 | HashIOsim.doSim(dut.io, dut.clockDomain, i, BIG_endian )(SHA2.digest("SHA-512")) 59 | } 60 | } 61 | } 62 | } 63 | 64 | 65 | /** 66 | * Test Sha2Engine_Std 67 | * 68 | */ 69 | class SpinalSimSHA2EngineStdTester extends AnyFunSuite { 70 | 71 | /** 72 | * SHA2Engine_Std_224 73 | */ 74 | test("SHA2Engine_Std_224") { 75 | 76 | val compiledRTL = SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new SHA2Engine_Std(SHA2_224)) 77 | 78 | compiledRTL.doSim { dut => 79 | 80 | dut.clockDomain.forkStimulus(2) 81 | 82 | dut.io.cmd.valid #= false 83 | dut.io.cmd.message.randomize() 84 | dut.io.init #= false 85 | 86 | dut.clockDomain.waitActiveEdge() 87 | 88 | val messages = List( 89 | List(BigInt("61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018", 16)) 90 | ) 91 | 92 | val refDigest = List( 93 | BigInt("23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", 16) 94 | ) 95 | 96 | for((ref, msg) <- refDigest.zip(messages)){ 97 | 98 | HashEngineIOsim.doSim(dut.io, dut.clockDomain, msg, ref) 99 | } 100 | } 101 | } 102 | 103 | 104 | /** 105 | * SHA2Engine_Std_256 106 | */ 107 | test("SHA2Engine_Std_256") { 108 | 109 | val compiledRTL = SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new SHA2Engine_Std(SHA2_256)) 110 | 111 | compiledRTL.doSim { dut => 112 | 113 | dut.clockDomain.forkStimulus(2) 114 | 115 | dut.io.cmd.valid #= false 116 | dut.io.cmd.message.randomize() 117 | dut.io.init #= false 118 | 119 | dut.clockDomain.waitActiveEdge() 120 | 121 | val messages = List( 122 | List(BigInt("61626380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018", 16)), 123 | List(BigInt("6162636462636465636465666465666765666768666768696768696a68696a6b696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f70718000000000000000", 16), 124 | BigInt("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c0", 16)) 125 | ) 126 | 127 | val refDigest = List( 128 | BigInt("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", 16), 129 | BigInt("248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1", 16) 130 | ) 131 | 132 | for((ref, msg) <- refDigest.zip(messages)){ 133 | HashEngineIOsim.doSim(dut.io, dut.clockDomain, msg, ref) 134 | } 135 | 136 | } 137 | } 138 | 139 | /** 140 | * SHA2Engine_Std_384 141 | */ 142 | test("SHA2Engine_Std_384") { 143 | 144 | val compiledRTL = SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new SHA2Engine_Std(SHA2_384)) 145 | 146 | compiledRTL.doSim { dut => 147 | 148 | dut.clockDomain.forkStimulus(2) 149 | 150 | dut.io.cmd.valid #= false 151 | dut.io.cmd.message.randomize() 152 | dut.io.init #= false 153 | 154 | dut.clockDomain.waitActiveEdge() 155 | 156 | val messages = List( 157 | List(BigInt("6162638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018", 16)) 158 | ) 159 | 160 | val refDigest = List( 161 | BigInt("cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", 16) 162 | ) 163 | 164 | for((ref, msg) <- refDigest.zip(messages)){ 165 | HashEngineIOsim.doSim(dut.io, dut.clockDomain, msg, ref) 166 | } 167 | } 168 | } 169 | 170 | /** 171 | * SHA2Engine_Std_512 172 | */ 173 | test("SHA2Engine_Std_512") { 174 | 175 | val compiledRTL = SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new SHA2Engine_Std(SHA2_512)) 176 | 177 | compiledRTL.doSim { dut => 178 | 179 | dut.clockDomain.forkStimulus(2) 180 | 181 | dut.io.cmd.valid #= false 182 | dut.io.cmd.message.randomize() 183 | dut.io.init #= false 184 | 185 | dut.clockDomain.waitActiveEdge() 186 | 187 | val messages = List( 188 | List(BigInt("6162638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018", 16)), 189 | List(BigInt("61626364656667686263646566676869636465666768696a6465666768696a6b65666768696a6b6c666768696a6b6c6d6768696a6b6c6d6e68696a6b6c6d6e6f696a6b6c6d6e6f706a6b6c6d6e6f70716b6c6d6e6f7071726c6d6e6f707172736d6e6f70717273746e6f70717273747580000000000000000000000000000000", 16), 190 | BigInt("0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000380", 16)) 191 | ) 192 | 193 | val refDigest = List( 194 | BigInt("ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", 16), 195 | BigInt("8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909", 16) 196 | 197 | ) 198 | 199 | for((ref, msg) <- refDigest.zip(messages)){ 200 | HashEngineIOsim.doSim(dut.io, dut.clockDomain, msg, ref) 201 | } 202 | } 203 | } 204 | 205 | /** 206 | * SHA2Engine_Std_512_224 207 | */ 208 | test("SHA2Engine_Std_512_224") { 209 | 210 | val compiledRTL = SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new SHA2Engine_Std(SHA2_512_224)) 211 | 212 | compiledRTL.doSim { dut => 213 | 214 | dut.clockDomain.forkStimulus(2) 215 | 216 | dut.io.cmd.valid #= false 217 | dut.io.cmd.message.randomize() 218 | dut.io.init #= false 219 | 220 | dut.clockDomain.waitActiveEdge() 221 | 222 | val messages = List( 223 | List(BigInt("6162638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018", 16)) 224 | ) 225 | 226 | val refDigest = List( 227 | BigInt("4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa", 16) 228 | ) 229 | 230 | for((ref, msg) <- refDigest.zip(messages)){ 231 | HashEngineIOsim.doSim(dut.io, dut.clockDomain, msg, ref) 232 | } 233 | } 234 | } 235 | 236 | /** 237 | * SHA2Engine_Std_512_256 238 | */ 239 | test("SHA2Engine_Std_512_256") { 240 | 241 | val compiledRTL = SimConfig.withConfig(SpinalConfig(inlineRom = true)).compile(new SHA2Engine_Std(SHA2_512_256)) 242 | 243 | compiledRTL.doSim { dut => 244 | 245 | dut.clockDomain.forkStimulus(2) 246 | 247 | dut.io.cmd.valid #= false 248 | dut.io.cmd.message.randomize() 249 | dut.io.init #= false 250 | 251 | dut.clockDomain.waitActiveEdge() 252 | 253 | val messages = List( 254 | List(BigInt("6162638000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000018", 16)) 255 | ) 256 | 257 | val refDigest = List( 258 | BigInt("53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23", 16) 259 | ) 260 | 261 | 262 | for((ref, msg) <- refDigest.zip(messages)){ 263 | 264 | HashEngineIOsim.doSim(dut.io, dut.clockDomain, msg, ref) 265 | 266 | } 267 | } 268 | } 269 | } 270 | 271 | --------------------------------------------------------------------------------