├── 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 |
--------------------------------------------------------------------------------