├── src
├── tests
│ ├── poseidon_python
│ │ ├── __init__.py
│ │ ├── poseidon.py
│ │ ├── constants.py
│ │ ├── basic.py
│ │ └── finite_field.py
│ ├── ModAdderTester.py
│ ├── Makefile
│ ├── MultiplierFlowTester.py
│ ├── MultiplierStreamTester.py
│ ├── ModularAdderFlowTester.py
│ ├── AdderTreeTester.py
│ ├── ModMultiplierTester.py
│ ├── MontgomeryMultFlowTester.py
│ ├── MontMultiplierPipedTester.py
│ ├── AXI4StreamTransmitterTester.py
│ ├── PoseidonSerializerTester.py
│ ├── MDSMatrixAddersTester.py
│ ├── AXI4StreamReceiverTester.py
│ └── MDSMatrixMultiplierTester.py
├── reference_model
│ └── poseidon_python
│ │ ├── __init__.py
│ │ ├── poseidon.py
│ │ ├── constants.py
│ │ ├── basic.py
│ │ └── finite_field.py
└── main
│ ├── verilog
│ ├── ModAdder.v
│ ├── PoseidonTopLevel_wrapper.v
│ ├── RoundConstantsTestbench.v
│ ├── ModMultiplier.v
│ └── MontMultiplierBasics.v
│ └── scala
│ └── poseidon
│ ├── ArithmeticOperator.scala
│ ├── PoseidonSerializer.scala
│ ├── BundleFifo.scala
│ ├── MontgomeryMult.scala
│ ├── MDSMatrixMultiplier.scala
│ ├── PoseidonThread.scala
│ ├── ModularAdder.scala
│ ├── AXI4StreamInterface.scala
│ └── AdderTree.scala
├── images
├── modadd.jpg
├── mul_sep.jpg
├── modadder.jpg
├── modadder2.jpg
├── mul_comb.JPG
├── toplevel.png
├── opt_poseidon.png
├── mod_multiplier.png
├── regular_adder.png
└── src
│ ├── AdderBasedModAdder.drawio
│ ├── TopLevel.drawio
│ ├── MDSMatrixAdder.drawio
│ ├── ModMultiplier.drawio
│ └── MDSMatrixMultiplier.drawio
├── poseidon_constants
├── compressed_round_constants_ff
│ ├── pre_round_constants_ff_3.txt
│ ├── pre_round_constants_ff_5.txt
│ ├── pre_round_constants_ff_9.txt
│ ├── pre_round_constants_ff_12.txt
│ ├── full_round_constants_ff_3.txt
│ ├── full_round_constants_ff_5.txt
│ ├── partial_round_constants_ff_3.txt
│ ├── partial_round_constants_ff_5.txt
│ ├── partial_round_constants_ff_9.txt
│ ├── partial_round_constants_ff_12.txt
│ └── full_round_constants_ff_9.txt
├── mds_matrixs
│ ├── mds_matrix_3.txt
│ ├── mds_matrix_5.txt
│ └── mds_matrix_9.txt
├── mds_matrixs_ff
│ ├── mds_matrix_ff_3.txt
│ ├── mds_matrix_ff_5.txt
│ └── mds_matrix_ff_9.txt
├── pre_sparse_matrix_ff
│ ├── pre_sparse_matrix_ff_3.txt
│ ├── pre_sparse_matrix_ff_5.txt
│ └── pre_sparse_matrix_ff_9.txt
├── pre_sparse_matrix
│ ├── pre_sparse_matrix_3.txt
│ ├── pre_sparse_matrix_5.txt
│ └── pre_sparse_matrix_9.txt
└── compressed_round_constants
│ └── compressed_round_constants_3.txt
├── .gitignore
├── .github
└── workflows
│ └── ci.yml
├── LICENSE
├── .scalafix.conf
└── run.sh
/src/tests/poseidon_python/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/reference_model/poseidon_python/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/images/modadd.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/datenlord/poseidon-spinal/HEAD/images/modadd.jpg
--------------------------------------------------------------------------------
/images/mul_sep.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/datenlord/poseidon-spinal/HEAD/images/mul_sep.jpg
--------------------------------------------------------------------------------
/images/modadder.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/datenlord/poseidon-spinal/HEAD/images/modadder.jpg
--------------------------------------------------------------------------------
/images/modadder2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/datenlord/poseidon-spinal/HEAD/images/modadder2.jpg
--------------------------------------------------------------------------------
/images/mul_comb.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/datenlord/poseidon-spinal/HEAD/images/mul_comb.JPG
--------------------------------------------------------------------------------
/images/toplevel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/datenlord/poseidon-spinal/HEAD/images/toplevel.png
--------------------------------------------------------------------------------
/images/opt_poseidon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/datenlord/poseidon-spinal/HEAD/images/opt_poseidon.png
--------------------------------------------------------------------------------
/images/mod_multiplier.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/datenlord/poseidon-spinal/HEAD/images/mod_multiplier.png
--------------------------------------------------------------------------------
/images/regular_adder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/datenlord/poseidon-spinal/HEAD/images/regular_adder.png
--------------------------------------------------------------------------------
/poseidon_constants/compressed_round_constants_ff/pre_round_constants_ff_3.txt:
--------------------------------------------------------------------------------
1 | 2a175464246e8941586440d29d17a3e801c1bdf20d09026b23e366d1c822c12d
2 | 600fd1b8363956cbdbfb4087da06af8ec28b6be869a2cf82dd35fb45585c6aed
3 | 69212d4e6495f3683deb63f13fe00e4249df84165dccb57f3fa379d7e2b8bfbe
4 |
--------------------------------------------------------------------------------
/poseidon_constants/compressed_round_constants_ff/pre_round_constants_ff_5.txt:
--------------------------------------------------------------------------------
1 | 33ff809e7dbdebbf8f644337a0008dcf305605b2cb53223d3d0a4729368cfb9f
2 | 4998feed41b4cddf2572ea256be885d0503170b7205090679e52ce58a4182072
3 | 27ae16683e3a7acc2302dadf7a5fa9c5034410574ac64bd6578b2978864d447c
4 | 5ec0e948c78bc2c24fbe333d330cfb35307db01f23092d8c6d3a7acd0bbd8dd7
5 | 73b33c1d097fe58c0b7c1572fafa5f3067d901cf30252eee2cb4d18b3637e7e5
6 |
--------------------------------------------------------------------------------
/poseidon_constants/mds_matrixs/mds_matrix_3.txt:
--------------------------------------------------------------------------------
1 | 4d491a377113a8daccd13ab0066be558e27e6d5755543d54aaaaaaaa00000001
2 | 56f23d7e5f361df6266b620607396203fece3b023ffec4ff3fffffff40000001
3 | 458e97984c2b4b2b51ef819e6c2de803323e959b66656a65cccccccc33333334
4 | 56f23d7e5f361df6266b620607396203fece3b023ffec4ff3fffffff40000001
5 | 458e97984c2b4b2b51ef819e6c2de803323e959b66656a65cccccccc33333334
6 | 609b60c54d5893118005895c0806deaf1b1e08ad2aa94ca9d555555480000001
7 | 458e97984c2b4b2b51ef819e6c2de803323e959b66656a65cccccccc33333334
8 | 609b60c54d5893118005895c0806deaf1b1e08ad2aa94ca9d555555480000001
9 | 211f5460e751918257c7624b7077624aaa362edc49241a48db6db6db24924925
10 |
--------------------------------------------------------------------------------
/poseidon_constants/mds_matrixs_ff/mds_matrix_ff_3.txt:
--------------------------------------------------------------------------------
1 | 2eb0c8399ccb80e7eeecb7fd521f62a8e4161ea9aaab36ab0000000055555555
2 | 4000000000000000000000000000000000000000000000000000000000000000
3 | 4d4237855c1011651e8dcc995bf433111b424cb999a419a0000000066666666
4 | 4000000000000000000000000000000000000000000000000000000000000000
5 | 4d4237855c1011651e8dcc995bf433111b424cb999a419a0000000066666666
6 | 514f37c663347f1811134802ade09d571be9e1565554c954ffffffffaaaaaaab
7 | 4d4237855c1011651e8dcc995bf433111b424cb999a419a0000000066666666
8 | 514f37c663347f1811134802ade09d571be9e1565554c954ffffffffaaaaaaab
9 | 66d0f1e660ec4796f8b356e005810db9e6b5824adb6cc6dadb6db6dadb6db6dc
10 |
--------------------------------------------------------------------------------
/poseidon_constants/pre_sparse_matrix_ff/pre_sparse_matrix_ff_3.txt:
--------------------------------------------------------------------------------
1 | 2eb0c8399ccb80e7eeecb7fd521f62a8e4161ea9aaab36ab0000000055555555
2 | 516cfbe5a0499eb26e0db7e149cb1614f2159006be9dd597e7ad644f2cc8fcce
3 | 2b5d8fedce156062b41e31b3e4051fb39def47675840ccfd40b77fb2a5c1dcc6
4 | 4000000000000000000000000000000000000000000000000000000000000000
5 | 717f183d735a42a911080d993a296f1bdc192f9a7c8a38d8a4e176e6b856e237
6 | 65483579139538bf910625005ee03a4d92a041b4572547b064d724c2907def5a
7 | 4d4237855c1011651e8dcc995bf433111b424cb999a419a0000000066666666
8 | 65483579139538bf910625005ee03a4d92a041b4572547b064d724c2907def5a
9 | 1326a139a061135832adaf114f318cefe528f09cf0f3500a650cbac1c8a0bc09
--------------------------------------------------------------------------------
/poseidon_constants/pre_sparse_matrix/pre_sparse_matrix_3.txt:
--------------------------------------------------------------------------------
1 | 0x4d491a377113a8daccd13ab0066be558e27e6d5755543d54aaaaaaaa00000001
2 | 0x69321c24c1cca37406c6aa610cf3eae4365bec86202785510ef2a763f5e42c3e
3 | 0x0d90801cabee4bb8d1fc3ae4f4fefac93b1105ad4e18f2907e485df9b0d18295
4 | 0x56f23d7e5f361df6266b620607396203fece3b023ffec4ff3fffffff40000001
5 | 0x5ea78f2da2d8388ecc02c49a4620a6b27d41d1e5effd39812af98a8d97d6d2a5
6 | 0x5520a6c1fa10647c5d2b726508ae4d861f26108eb53e8c91ed21b32cf61b91c2
7 | 0x458e97984c2b4b2b51ef819e6c2de803323e959b66656a65cccccccc33333334
8 | 0x5520a6c1fa10647c5d2b726508ae4d861f26108eb53e8c91ed21b32cf61b91c2
9 | 0x52077538d6b5e62ca4c19efc7069b99b3565cdb57004cd4efe3e71b13c252454
--------------------------------------------------------------------------------
/poseidon_constants/compressed_round_constants_ff/pre_round_constants_ff_9.txt:
--------------------------------------------------------------------------------
1 | 61164ad53d961f8c5d71b17b8762cfe5b80a09c3770458818eb749221c5777b2
2 | 629457753f89131cd47ba9d8cd6946fe4d9710737560c27a773d3406a8f372e5
3 | 7107e746a7f5d03edf182e037acdc21dc049822362518bf52fcfc516572100c6
4 | 6d682d57c2f77a87982f101aa874cc41716286f9625d3d92a968983a5ef53811
5 | 5af7e3d8f26afd924b8d17a25ff21fe5e1d792d5f295095fb676e1da058ed62f
6 | 1df39ecbc80f8cd77fe8ecebd38a68bd8e96c48fda8e055c41b143e41b03fa28
7 | 130c8a1cdc46a1feaf252450edd7afc1810f5fe59bc15438855be06daacb38ca
8 | 1caed2dbef24448b570ba85bacd8d8a59674e1b0da119872e2a4a3fb359dcf90
9 | 5d2a5445b34a8c40f1642337f13047a2767d87551c943519380312717f01c615
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 | *.log
3 | *.bak
4 | *.xml
5 | *.bin
6 |
7 | # python
8 | __pycache__
9 | sim_build
10 |
11 | # sbt specific
12 | .cache/
13 | .history/
14 | .lib/
15 | dist/*
16 | target
17 | lib_managed/
18 | src_managed/
19 | project
20 | project/boot/
21 | project/plugins/project/
22 |
23 | # Scala-IDE specific
24 | .scala_dependencies
25 | .worksheet
26 |
27 | .idea
28 | out
29 |
30 | # Metals
31 | .metals
32 |
33 | # Eclipse
34 | bin/
35 | .classpath
36 | .project
37 | .settings
38 | .cache-main
39 | .vscode
40 |
41 | #User
42 | /*.vhd
43 | /*.v
44 | *.cf
45 | *.json
46 | *.vcd
47 | !tester/src/test/resources/*.vhd
48 |
49 |
50 | simWorkspace/
51 | tmp/
52 | null
53 |
54 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 | on:
3 | pull_request:
4 | branches: [master]
5 | push:
6 | branches: [master]
7 | schedule: [cron: "12 */24 * * *"]
8 |
9 | # Allows you to run this workflow manually from the Actions tab
10 | workflow_dispatch:
11 |
12 |
13 | jobs:
14 | build-and-simulate:
15 | name: Build and Simulate
16 | runs-on: ubuntu-latest
17 |
18 | steps:
19 | - uses: actions/checkout@v2
20 | - name: build and simulate
21 | run : |
22 | docker pull datenlord/spinal-cocotb:1.6.1
23 | pip install black
24 |
25 | ./run.sh -c -e PoseidonTopLevel
26 | - name: Setup tmate session
27 | if: ${{ failure() }}
28 | uses: mxschmitt/action-tmate@v3
29 |
--------------------------------------------------------------------------------
/src/main/verilog/ModAdder.v:
--------------------------------------------------------------------------------
1 |
2 | module ModAdder #(
3 | // width of modulus
4 | parameter DATA_WIDTH = 255,
5 | // the modulus of ModAdder
6 | parameter MODULUS = 255'h73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001,
7 | // R = exp(2, DATA_WIDTH) MOD_COMPENSATION = R - MODULUS
8 | parameter MOD_COMPENSATION = 255'hc1258acd66282b7ccc627f7f65e27faac425bfd0001a40100000000ffffffff
9 | )(
10 | input wire [DATA_WIDTH-1:0] op1_i,
11 | input wire [DATA_WIDTH-1:0] op2_i,
12 |
13 | output wire [DATA_WIDTH-1:0] res_o
14 | );
15 |
16 | wire carry1,carry2;
17 | wire [DATA_WIDTH-1:0] res1, res2;
18 | assign {carry1, res1} = op1_i + op2_i;
19 | assign {carry2, res2} = res1 + MOD_COMPENSATION;
20 | assign res_o = (carry1 | carry2) ? res2 : res1;
21 |
22 | endmodule
--------------------------------------------------------------------------------
/poseidon_constants/compressed_round_constants_ff/pre_round_constants_ff_12.txt:
--------------------------------------------------------------------------------
1 | 17fa0c9a759f5b22f592e9170b46d35bec219c80c7f1f34d70bd48a2f2f6061f
2 | 1e380507358adb0dd4c8ff7007bd1f1f7fdf2350c0a4989b04f0d4cf72dc5c77
3 | 55baa6a9addd6703ae3a88059aeaf8176f3453533910eee7002dc13c81bfb07
4 | 59afa6e185c556f0c46834f185695aef105089c669bcebe48ffe7e848165e138
5 | 18e3e88a35ed841034d08f4c86633376a5404c484cf7e63bc4690dc8f2a12121
6 | 50f9329aad27d133c367c805dd6c5829ec24a9bd6d7a3cd9e7c46b528078d4d7
7 | 69a4eef12806819f181f6ba6aefe9cbe9c663618e7e8ba4c5a96cdeb798f7579
8 | 168c18dde57a2e4654bb324ccb241209c79ceb9b63830f21741b569b35071986
9 | 49f8d58a75a960d871dfd1ba40e985c10e39911645f5d35fadbffe3695ebab04
10 | 6163c52a1a4a5b5a4aad9cce14d6ffe6695d01abb6db317b877af0af830e804c
11 | 591b0c6bed72f4e6fdff7700591f2435b85c0361c6b226e2774779cdb0fc6d2e
12 | 586d4eacccd4167cf1538c8690df076bd88d48a64ea86aaecd6cda86c44450e0
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 datenlord
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 |
--------------------------------------------------------------------------------
/src/main/verilog/PoseidonTopLevel_wrapper.v:
--------------------------------------------------------------------------------
1 | module PoseidonTopLevel_wrapper (
2 | input io_input_valid,
3 | output io_input_ready,
4 | input io_input_last,
5 | input [255:0] io_input_payload,
6 | output io_output_valid,
7 | input io_output_ready,
8 | output io_output_last,
9 | output [255:0] io_output_payload,
10 | input clk,
11 | input reset
12 | );
13 | wire input_last = io_input_payload[255];
14 | wire [254:0] input_payload = io_input_payload[254:0];
15 | wire output_last;
16 | wire [254:0] output_payload;
17 | assign io_output_payload = {output_last, output_payload};
18 | PoseidonTopLevel poseidonInst(
19 | .io_input_valid (io_input_valid ),
20 | .io_input_ready (io_input_ready ),
21 | .io_input_last (input_last ),
22 | .io_input_payload (input_payload ),
23 |
24 | .io_output_valid (io_output_valid ),
25 | .io_output_ready (io_output_ready ),
26 | .io_output_last (output_last ),
27 | .io_output_payload (output_payload ),
28 | .clk (clk ),
29 | .reset (reset )
30 | );
31 |
32 | // bypass last
33 | reg last_reg;
34 | assign io_output_last = last_reg;
35 | always @(posedge clk) begin
36 | last_reg <= io_input_last;
37 | end
38 |
39 | endmodule
--------------------------------------------------------------------------------
/src/tests/poseidon_python/poseidon.py:
--------------------------------------------------------------------------------
1 | import basic
2 | import constants
3 |
4 | # poseidon hash function
5 |
6 |
7 | def poseidon_hash(preimage):
8 |
9 | t = len(preimage) + 1
10 | if t not in basic.T_RANGE:
11 | print("error: the length of preimage is incorrect")
12 | exit()
13 |
14 | roundf = basic.ROUNDFULL
15 | roundp = basic.ROUNDPARTIAL[t]
16 |
17 | round_constants = constants.generate_constants(t, roundf, roundp)
18 |
19 | state = basic.PrimeFieldOps.init_state(preimage)
20 | for i in range(int(roundf / 2)):
21 | state = basic.PrimeFieldOps.add_round_constants(
22 | state, round_constants[i * t : (i + 1) * t]
23 | )
24 | state = basic.PrimeFieldOps.s_boxes(state)
25 | state = basic.PrimeFieldOps.mds_mixing(state)
26 |
27 | for i in range(int(roundf / 2), int(roundf / 2 + roundp)):
28 |
29 | state = basic.PrimeFieldOps.add_round_constants(
30 | state, round_constants[i * t : (i + 1) * t]
31 | )
32 | state[0] = basic.PrimeFieldOps.s_box(state[0])
33 | state = basic.PrimeFieldOps.mds_mixing(state)
34 |
35 | for i in range(int(roundf / 2 + roundp), int(roundf + roundp)):
36 | state = basic.PrimeFieldOps.add_round_constants(
37 | state, round_constants[i * t : (i + 1) * t]
38 | )
39 | state = basic.PrimeFieldOps.s_boxes(state)
40 | state = basic.PrimeFieldOps.mds_mixing(state)
41 |
42 | return state[1]
43 |
--------------------------------------------------------------------------------
/src/reference_model/poseidon_python/poseidon.py:
--------------------------------------------------------------------------------
1 | import basic
2 | import constants
3 |
4 | # poseidon hash function
5 |
6 |
7 | def poseidon_hash(preimage):
8 |
9 | t = len(preimage) + 1
10 | if t not in basic.T_RANGE:
11 | print("error: the length of preimage is incorrect")
12 | exit()
13 |
14 | roundf = basic.ROUNDFULL
15 | roundp = basic.ROUNDPARTIAL[t]
16 |
17 | round_constants = constants.generate_constants(t, roundf, roundp)
18 |
19 | state = basic.PrimeFieldOps.init_state(preimage)
20 | for i in range(int(roundf / 2)):
21 | state = basic.PrimeFieldOps.add_round_constants(
22 | state, round_constants[i * t : (i + 1) * t]
23 | )
24 | state = basic.PrimeFieldOps.s_boxes(state)
25 | state = basic.PrimeFieldOps.mds_mixing(state)
26 |
27 | for i in range(int(roundf / 2), int(roundf / 2 + roundp)):
28 |
29 | state = basic.PrimeFieldOps.add_round_constants(
30 | state, round_constants[i * t : (i + 1) * t]
31 | )
32 | state[0] = basic.PrimeFieldOps.s_box(state[0])
33 | state = basic.PrimeFieldOps.mds_mixing(state)
34 |
35 | for i in range(int(roundf / 2 + roundp), int(roundf + roundp)):
36 | state = basic.PrimeFieldOps.add_round_constants(
37 | state, round_constants[i * t : (i + 1) * t]
38 | )
39 | state = basic.PrimeFieldOps.s_boxes(state)
40 | state = basic.PrimeFieldOps.mds_mixing(state)
41 |
42 | return state[1]
43 |
--------------------------------------------------------------------------------
/.scalafix.conf:
--------------------------------------------------------------------------------
1 | rules = [
2 | DisableSyntax
3 | LeakingImplicitClassVal
4 | NoValInForComprehension
5 | ProcedureSyntax
6 | // ExplicitResultTypes
7 | // NoAutoTupling
8 | // OrganizeImports
9 | // RemoveUnused
10 | ]
11 |
12 | Disable {
13 | ifSynthetic = [
14 | "scala/Option.option2Iterable"
15 | "scala/Predef.any2stringadd"
16 | ]
17 | }
18 |
19 | DisableSyntax {
20 | noAsInstanceOf = true
21 | noContravariantTypes = true
22 | noCovariantTypes = true
23 | noDefaultArgs = true
24 | noFinalVal = true
25 | noFinalize = true
26 | noImplicitConversion = true
27 | noImplicitObject = true // https://stackoverflow.com/questions/20380800/scala-implicits-resolution-mechanism-is-declaration-order-dependent#comment31809401_20381535
28 | noIsInstanceOf = true
29 | noNulls = true
30 | noReturns = true
31 | noSemicolons = true
32 | noTabs = true
33 | noThrows = true
34 | //noUniversalEquality = true
35 | noValInAbstract = true
36 | noValPatterns = true
37 | noVars = true
38 | noWhileLoops = true
39 | noXml = true
40 | }
41 |
42 | ExplicitResultTypes {
43 | unsafeShortenNames = true
44 |
45 | fatalWarnings = true
46 |
47 | # these apply to non-implicits
48 | memberKind = [Def, Val]
49 | memberVisibility = [Public, Protected]
50 |
51 | # turn to the max...
52 | skipSimpleDefinitions = false
53 | skipLocalImplicits = false
54 | }
55 |
56 | OrganizeImports {
57 | # Allign with IntelliJ IDEA so that they don't fight each other
58 | groupedImports = Merge
59 | }
60 |
61 | RemoveUnused {
62 | imports = false // handled by OrganizeImports
63 | }
--------------------------------------------------------------------------------
/poseidon_constants/compressed_round_constants_ff/full_round_constants_ff_3.txt:
--------------------------------------------------------------------------------
1 | 4517ba4b7c09e98c9f5655bc5716a24850897887d3a35419f94ac1947de7dfbf
2 | 2924588522082c34139f0c1aa9387186f70629ecb6bc61c8634c4c5d1e922f65
3 | 2176e2a8e17b0334d1a9afd2c536e7c1f53c66223285900202e3da796b2588e7
4 | 59007dc06b70d92913d9f5410992584bd22848ff29a3a26a3357a3e5fb0e2c83
5 | 49855421a67d44da22ca7e6753629da1de5f847ccbb3bcecba279ba13e25d236
6 | 4cc12f94e93b10143c09313a651e91f1e8e91b06e0f3c15a36bc60adb18fb495
7 | 36cd8b4d3835fc3d14da6d2cb573ee6b78f297c66af464f8ae4508d9adf8c1c
8 | 72a2a116737f0d1b362f024b68a823d31070dabe5f80fcd95b7c05b57a4a9bbd
9 | 577c0b4f62187b7d212d7faafaba0cd3bde34183bbdcc676307734828b5f8720
10 | 1cb041121f1c945cc101ff983bc06262946b768466e29527b7c615ac86a51179
11 | 2799270041b61254b3e55fc6376c34c22babe8e7aefca45941bbd60571403aa8
12 | 548c7c2ab82f5dc355c98968cb3faddc2ce697691ec4afd772191dd45f75f510
13 | 56c50a0987544b0ae2cebf0f4ffc771e378a357925dbe02f121a624ff2fa6515
14 | 1c9b4c2f0347c4380a9ce5dbdff12dea75796d32e375f949eef3d92cdb1a75de
15 | 3ae634d0aee1b659a7a5fe04ba22cfe642118279e686b956a43fce9c67ff43e2
16 | 4e3f7b301f96c62eae42227521870e8676c24cf7ff4dc0a2f6250e0e77939021
17 | 32027f4b29ba5dfa718a63356b649250792599b022051241e04b4510e65a7396
18 | 24487f8a7ac6a8c44795688b5d429175192d25e5d172fcda75865a2e698aa5e0
19 | 2698a559226880614d3fe274a97b265f43f6e6aae098b314b6548061f3d6d4a2
20 | 697c358044a0ea98cdc5e04faf0acbc8deb7495a7c56cc6ffeb966f1ad59f50e
21 | 5a9296c00ddd3f06b34412fe6a6cbea2fcb8abcd549d64cbae9ae8329d3ba5e5
22 | 0000000000000000000000000000000000000000000000000000000000000000
23 | 0000000000000000000000000000000000000000000000000000000000000000
24 | 0000000000000000000000000000000000000000000000000000000000000000
25 |
--------------------------------------------------------------------------------
/poseidon_constants/mds_matrixs/mds_matrix_5.txt:
--------------------------------------------------------------------------------
1 | 458e97984c2b4b2b51ef819e6c2de803323e959b66656a65cccccccc33333334
2 | 609b60c54d5893118005895c0806deaf1b1e08ad2aa94ca9d555555480000001
3 | 211f5460e751918257c7624b7077624aaa362edc49241a48db6db6db24924925
4 | 656ff268c469cd9f2cd29d07086d9d04a945ef829ffe907f1fffffff20000001
5 | 19c308bd25b13848eef068e557794c72f62a247271c6bf1c38e38e38aaaaaaab
6 | 609b60c54d5893118005895c0806deaf1b1e08ad2aa94ca9d555555480000001
7 | 211f5460e751918257c7624b7077624aaa362edc49241a48db6db6db24924925
8 | 656ff268c469cd9f2cd29d07086d9d04a945ef829ffe907f1fffffff20000001
9 | 19c308bd25b13848eef068e557794c72f62a247271c6bf1c38e38e38aaaaaaab
10 | 22c74bcc2615a595a8f7c0cf3616f401991f4acdb332b532e66666661999999a
11 | 211f5460e751918257c7624b7077624aaa362edc49241a48db6db6db24924925
12 | 656ff268c469cd9f2cd29d07086d9d04a945ef829ffe907f1fffffff20000001
13 | 19c308bd25b13848eef068e557794c72f62a247271c6bf1c38e38e38aaaaaaab
14 | 22c74bcc2615a595a8f7c0cf3616f401991f4acdb332b532e66666661999999a
15 | 6963af62e003892a5d1d50074e93217934daf23145cff68aba2e8ba200000001
16 | 656ff268c469cd9f2cd29d07086d9d04a945ef829ffe907f1fffffff20000001
17 | 19c308bd25b13848eef068e557794c72f62a247271c6bf1c38e38e38aaaaaaab
18 | 22c74bcc2615a595a8f7c0cf3616f401991f4acdb332b532e66666661999999a
19 | 6963af62e003892a5d1d50074e93217934daf23145cff68aba2e8ba200000001
20 | 6a44840c3b7b082cd99fb0b208d45b5a376dd6581553d4546aaaaaa9c0000001
21 | 19c308bd25b13848eef068e557794c72f62a247271c6bf1c38e38e38aaaaaaab
22 | 22c74bcc2615a595a8f7c0cf3616f401991f4acdb332b532e66666661999999a
23 | 6963af62e003892a5d1d50074e93217934daf23145cff68aba2e8ba200000001
24 | 6a44840c3b7b082cd99fb0b208d45b5a376dd6581553d4546aaaaaa9c0000001
25 | 6217dc5a0f85429f8dce7bb808267bb5bd02ed3d9d88753a3b13b13a3b13b13c
26 |
--------------------------------------------------------------------------------
/poseidon_constants/mds_matrixs_ff/mds_matrix_ff_5.txt:
--------------------------------------------------------------------------------
1 | 4d4237855c1011651e8dcc995bf433111b424cb999a419a0000000066666666
2 | 514f37c663347f1811134802ade09d571be9e1565554c954ffffffffaaaaaaab
3 | 66d0f1e660ec4796f8b356e005810db9e6b5824adb6cc6dadb6db6dadb6db6dc
4 | 2000000000000000000000000000000000000000000000000000000000000000
5 | 5cd95cf5500229281c7578047721063bd930778fe38d4f8daaaaaaaa1c71c71d
6 | 514f37c663347f1811134802ade09d571be9e1565554c954ffffffffaaaaaaab
7 | 66d0f1e660ec4796f8b356e005810db9e6b5824adb6cc6dadb6db6dadb6db6dc
8 | 2000000000000000000000000000000000000000000000000000000000000000
9 | 5cd95cf5500229281c7578047721063bd930778fe38d4f8daaaaaaaa1c71c71d
10 | 26a11bc2ae0808b28f46e64cadfa19888da1265cccd20cd0000000033333333
11 | 66d0f1e660ec4796f8b356e005810db9e6b5824adb6cc6dadb6db6dadb6db6dc
12 | 2000000000000000000000000000000000000000000000000000000000000000
13 | 5cd95cf5500229281c7578047721063bd930778fe38d4f8daaaaaaaa1c71c71d
14 | 26a11bc2ae0808b28f46e64cadfa19888da1265cccd20cd0000000033333333
15 | 2c59c154f04b2e0d209627474791ca2f8396d8008ba29c5ce8ba2e8b745d1746
16 | 2000000000000000000000000000000000000000000000000000000000000000
17 | 5cd95cf5500229281c7578047721063bd930778fe38d4f8daaaaaaaa1c71c71d
18 | 26a11bc2ae0808b28f46e64cadfa19888da1265cccd20cd0000000033333333
19 | 2c59c154f04b2e0d209627474791ca2f8396d8008ba29c5ce8ba2e8b745d1746
20 | 629e6f8cc668fe30222690055bc13aae37d3c2acaaa992a9ffffffff55555556
21 | 5cd95cf5500229281c7578047721063bd930778fe38d4f8daaaaaaaa1c71c71d
22 | 26a11bc2ae0808b28f46e64cadfa19888da1265cccd20cd0000000033333333
23 | 2c59c154f04b2e0d209627474791ca2f8396d8008ba29c5ce8ba2e8b745d1746
24 | 629e6f8cc668fe30222690055bc13aae37d3c2acaaa992a9ffffffff55555556
25 | 521d817b8c8fe0ff7e0b745318e0fe2a40c8936413b058ebc4ec4ec462762763
26 |
--------------------------------------------------------------------------------
/src/tests/ModAdderTester.py:
--------------------------------------------------------------------------------
1 | import cocotb
2 | from poseidon_python import basic
3 | from cocotb.triggers import Timer
4 | import random
5 | from cocotb_test import simulator
6 |
7 |
8 | @cocotb.test()
9 | async def ModAdderTest(dut):
10 | """test ModAdder"""
11 |
12 | for i in range(100):
13 | res = random.randint(1, basic.P - 1)
14 | op1 = random.randint(0, res)
15 | op2 = res - op1
16 | dut.op1_i.value = op1
17 | dut.op2_i.value = op2
18 | await Timer(5, units="ns")
19 | assert dut.res_o == res % basic.P, "the result of {} + {} is wrong".format(
20 | op1, op2
21 | )
22 |
23 | for i in range(100):
24 | res = random.randint(basic.P, pow(2, 255) - 1)
25 | op1 = random.randint(0, res)
26 | op2 = res - op1
27 | dut.op1_i.value = op1
28 | dut.op2_i.value = op2
29 | await Timer(5, units="ns")
30 | assert dut.res_o == res % basic.P, "the result of {} + {} is wrong".format(
31 | op1, op2
32 | )
33 |
34 | for i in range(100):
35 | res = random.randint(pow(2, 255), (2 * basic.P - 2))
36 | op1 = random.randint((res - pow(2, 255) + 1), (pow(2, 255) - 1))
37 | op2 = res - op1
38 | dut.op1_i.value = op1
39 | dut.op2_i.value = op2
40 | await Timer(5, units="ns")
41 | assert dut.res_o == res % basic.P, "the result of {} + {} is wrong".format(
42 | op1, op2
43 | )
44 |
45 |
46 | # pytest
47 | def test_ModAdder():
48 | simulator.run(
49 | verilog_sources=["../main/verilog/ModAdder.v"],
50 | toplevel="ModAdder",
51 | module="ModAdderTester",
52 | python_search="./src/reference_model/",
53 | )
54 |
--------------------------------------------------------------------------------
/poseidon_constants/pre_sparse_matrix_ff/pre_sparse_matrix_ff_5.txt:
--------------------------------------------------------------------------------
1 | 4d4237855c1011651e8dcc995bf433111b424cb999a419a0000000066666666
2 | 5301f64426b3ebca1f6651d78d256903f80141c43c2e8f2d5c42429d2da832c9
3 | 3d7e2fe8a9cf4c482ad7e335060ee024ab7c02cdee8d79c488bc776a7277500d
4 | 5fb37b8083eeb410ed792f28064ab12da369d8c6ea8f3b11bdf953ecf125f70c
5 | 57fabbc58de3cee7b6c5f61d7399f980b41ff9e0c1fc4099ae0f225c901e444d
6 | 514f37c663347f1811134802ade09d571be9e1565554c954ffffffffaaaaaaab
7 | 3b13122516ea9c45f99cec6182cd8f49d4ecba0ec0fa58c132342950ee316a69
8 | 48b3669cc94450051fbb37f9a37576dcf43f7419c9e80d8d1b55c267d36851b4
9 | 29386bc84ccab5b73cd7f602762aed1b2db36d3d0ef1f77134c8e7f44874c4d3
10 | 1b1a2fb021ae315d87c4202ad51ea54ed8429784720de9ac59ed11f884f9c9c7
11 | 66d0f1e660ec4796f8b356e005810db9e6b5824adb6cc6dadb6db6dadb6db6dc
12 | 48b3669cc94450051fbb37f9a37576dcf43f7419c9e80d8d1b55c267d36851b4
13 | c3f3140031a893bbfdc443c2786c6518ca6690d226ef7d333d42512ff3720cc
14 | 1f0c1edd5e10ea8b940df709c813ff880e4fac115efe0113554907b997612380
15 | 5e35a96c7dfa83af31d6ea2882e74655589a02c86410f5b0e58fd0c8599858a6
16 | 2000000000000000000000000000000000000000000000000000000000000000
17 | 29386bc84ccab5b73cd7f602762aed1b2db36d3d0ef1f77134c8e7f44874c4d3
18 | 1f0c1edd5e10ea8b940df709c813ff880e4fac115efe0113554907b997612380
19 | 2e3e6a432b5b0226ce6f0e65b1d20e5434b4072d7e4733208d7b739051aab926
20 | 14769e2082dd9a34a211d4fe8e8e097a66d1c33bd4e22affbb6133ddfc5fcf30
21 | 5cd95cf5500229281c7578047721063bd930778fe38d4f8daaaaaaaa1c71c71d
22 | 1b1a2fb021ae315d87c4202ad51ea54ed8429784720de9ac59ed11f884f9c9c7
23 | 5e35a96c7dfa83af31d6ea2882e74655589a02c86410f5b0e58fd0c8599858a6
24 | 14769e2082dd9a34a211d4fe8e8e097a66d1c33bd4e22affbb6133ddfc5fcf30
25 | 1d11e38f8014a70be5c6e4c025773b9ef6649d8ceb30ddb2492c459085fc174
26 |
--------------------------------------------------------------------------------
/poseidon_constants/pre_sparse_matrix/pre_sparse_matrix_5.txt:
--------------------------------------------------------------------------------
1 | 0x458e97984c2b4b2b51ef819e6c2de803323e959b66656a65cccccccc33333334
2 | 0x4f7a568d2f136a4330a0d0d95259681cb2197768a7cc4759c100462671a04e88
3 | 0x3e5edae6fd1fa70acaf56b85e4621300ba0ef6ced28e26cead2a6b0acb7eafb9
4 | 0x6b69bed9dd98b19b536db1ba89bb622f01efe9b804ce2b5b50418e5d3ae91972
5 | 0x5925b1536e05188717225c857b7c7a55b4fb8ce62b397c16494581213a4f4675
6 | 0x609b60c54d5893118005895c0806deaf1b1e08ad2aa94ca9d555555480000001
7 | 0x3d045c2704892e213ab77bc1a9296aa37e6b7e311b9c090a11adbd5c34e2e626
8 | 0x5782f4cda3a41ea9adc8d2809b1cbdc60397727f2da93005e737c67325956a97
9 | 0x20d393b21f4e1f820bf5f2629b11e468608325f17049c9d576ecc6117cc1967c
10 | 0x0bcb5d2aacef80f658938433e0bdf530ee618a4db0a0322ad982a27f5fe53c85
11 | 0x211f5460e751918257c7624b7077624aaa362edc49241a48db6db6db24924925
12 | 0x5782f4cda3a41ea9adc8d2809b1cbdc60397727f2da93005e737c67325956a97
13 | 0x06b54b14b70e35d4ac36330db80e734cfb9b34764d92ed9f481a5bdcbda6f6f9
14 | 0x03da17e2ca7d85a7d1515c882873d13e9f39ab5c0f4d649b1f3f890fa5e6996a
15 | 0x2bb32b216e0ca36b42d90b922f74194d63624682319ccecfd2b230006f84268a
16 | 0x656ff268c469cd9f2cd29d07086d9d04a945ef829ffe907f1fffffff20000001
17 | 0x20d393b21f4e1f820bf5f2629b11e468608325f17049c9d576ecc6117cc1967c
18 | 0x03da17e2ca7d85a7d1515c882873d13e9f39ab5c0f4d649b1f3f890fa5e6996a
19 | 0x4b9dad480da5c0592df350ce863ae17511dfc32dcd2047ab2dc24d487b629069
20 | 0x4271e0c1b796577eab8dc181740992bf8ae7eccdd57d934c066d93b2352ded3d
21 | 0x19c308bd25b13848eef068e557794c72f62a247271c6bf1c38e38e38aaaaaaab
22 | 0x0bcb5d2aacef80f658938433e0bdf530ee618a4db0a0322ad982a27f5fe53c85
23 | 0x2bb32b216e0ca36b42d90b922f74194d63624682319ccecfd2b230006f84268a
24 | 0x4271e0c1b796577eab8dc181740992bf8ae7eccdd57d934c066d93b2352ded3d
25 | 0x6adaf570e3ae54731aae329e3e32fca188117cb697027faa7bcba54fa5543d20
--------------------------------------------------------------------------------
/images/src/AdderBasedModAdder.drawio:
--------------------------------------------------------------------------------
1 | 7VpNd5s4FP01XibHEgbsZWxnPIu242nO6bSz6VGMDGoAUSHHOL9+BEiAAH+kMf6YdJOgpychdN997wrcMyZBMmMo8j5SB/s92HeSnjHtQWhbQ/E3NWxyw2AIc4PLiJObQGl4IC9YGvvSuiIOjjVHTqnPSaQbFzQM8YJrNsQYXetuS+rrd42QixuGhwXym9Z/iMO93DqEdmn/ExPXU3cG1ijvCZBylk8Se8ih64rJuO8ZE0Ypz6+CZIL9dO/UvuTj/tjSWyyM4ZAfMsCd/fj0t/UEn16Wn+zly4ySn3/dSHRivlEPjB3x/LJJGfeoS0Pk35fWMaOr0MHprH3RKn0+UBoJIxDGH5jzjQQTrTgVJo8HvuzFCeFf0+G3pmx9q/RMEzlz1tioRsjZJh8ETdX+Vu0sx2UtNbC5TXLnYrpiC7xjb1S4IeZivsNPhkK6cZUbSBBmmAZYrEc4MOwjTp71wEIyPt3Cr4RQXEgUX4GoIs6ZIK0AWsK7D1INz1vb3ANp1ppjRsSOYXYynEcXhTOEV0hdW6MuODt1wdG5mw29YwxtKg4RJSGPKzPPU4NwkFUSWpK0skhCo5bK6/4A7vIXF/kKyugqHuUNiSW/5TPyV3IbetDyxe6OlzRbXBmJ1s8VVR03cRZLd8JBYJmUneLKzf+P1URiXflcqqcW4Hr4rj3C8UOEskhYC/Whh+rW6HnGjONkJ9xqn/s6LkDhtC6lAFD13avIgEG/I9YPrpD0p6rX8FDSX1Yeb6FVDWKhHKMM3uVyLvTmJJe6lJ2GAwK+KgfsYZMCLQyAXTHAOgsDtpWw7qLZvMpoNi89moeXFc0ANPbnytQ6PLFatw/kxYWpdePqC3d3av1QSI+v1t+Eqf0OBbFRO6icXRDDsypi0HtFAhWNehosyAZ6WlLdl1N/nWujs3Htl07GwNJPuoas352edEf7RUxKGbIQEYMesT+nMeGEhqLrkXJOA4FQ8bY3hctBsVeEG/KJm7ouBHZpIFTjSk17J314Go9jpZiCxE3fsd9iXwgmlvrd+tQli+8u4jiuXKdBHWGG5KIybcUoV+3RzhA6PBuAgZ4NDNDMBgOzRU2ZXamp93I4AMaBNL6siqmWXWFWUTPjVaTK3FOl/FXMN0EDXRGoXAeDYVFe0WPmkLFNwJUX3Ky7Qb464wLiOFlYyMwkbmOOe+Y0Ld7E9yfUT9k0DWmYOsWc0SdcM+oBdQSeGbXXULCNZ6c8taivX5egZos621p030Cxbgpg812uoVe4gVVDLee4HFUD7hivddtk7JYjOxflB7/QdL5xVJEyhb2ib/ap0SVJsPreC/T6dAOGx6pQo5p8sJvMGbYwx+iMOW0vSF53aACDtkND/9Ajw/tImeJstRf4tnNKdynT6gh48Bt4Dfi6Jj0h8JPpdwf8O/4MouWXrxN7BsF0foTPZsBsw51G/z/kGzC3BMN25IGOvHk6kdQKPOwMePgbeA14+1TAi2b5e61cgJU/ejPu/wM=
--------------------------------------------------------------------------------
/src/main/verilog/RoundConstantsTestbench.v:
--------------------------------------------------------------------------------
1 | `timescale 1ns / 1ps
2 | //////////////////////////////////////////////////////////////////////////////////
3 | // Company:
4 | // Engineer:
5 | //
6 | // Create Date: 03/11/2022 04:54:40 PM
7 | // Design Name:
8 | // Module Name: bram_sim
9 | // Project Name:
10 | // Target Devices:
11 | // Tool Versions:
12 | // Description:
13 | //
14 | // Dependencies:
15 | //
16 | // Revision:
17 | // Revision 0.01 - File Created
18 | // Additional Comments:
19 | //
20 | //////////////////////////////////////////////////////////////////////////////////
21 |
22 |
23 | module RoundConstantsTester(
24 |
25 | );
26 | localparam Period = 10;
27 |
28 | // generate reset and clk signals
29 | reg clk;
30 | initial begin
31 | clk = 0;
32 | forever #(Period/2) clk = ~clk;
33 | end
34 |
35 | reg reset;
36 | initial begin
37 | reset = 1;
38 | #(2*Period) reset = 0;
39 | end
40 |
41 |
42 | // address generation
43 | reg [1:0] tIndex_reg;
44 | reg [5:0] rIndex_reg;
45 | always @(posedge clk) begin
46 | if(reset) begin
47 | tIndex_reg <= 0;
48 | rIndex_reg <= 0;
49 | end
50 | else begin
51 | tIndex_reg <= tIndex_reg + 1;
52 | rIndex_reg <= rIndex_reg + 1;
53 | end
54 |
55 | if(rIndex_reg == 60) $finish();
56 | end
57 |
58 |
59 | // reg ena;
60 | // initial begin
61 | // ena = 1;
62 | // forever #(2*Period) ena = ~ena;
63 | // end
64 |
65 | wire [254:0] readData;
66 |
67 | RoundConstants roundConstantsInst(
68 | .io_readPorts_0_data ( readData ),
69 | .io_readPorts_0_tIndex ( 0 ),
70 | .io_readPorts_0_roundIndex( rIndex_reg ),
71 | .clk ( clk ),
72 | .reset ( reset )
73 | );
74 |
75 |
76 | initial begin
77 | $dumpfile("dump.vcd");
78 | $dumpvars(1, RoundConstantsTester);
79 | end
80 |
81 |
82 | endmodule
--------------------------------------------------------------------------------
/images/src/TopLevel.drawio:
--------------------------------------------------------------------------------
1 | 7Vtbd+I2EP41PGYPsnzjkYQku204zSndbrYvPYqtgBtjubIcYH99JVvC14C52MA2L4k1Ghv5m28uGkEP3syX9xSFszFxsd/T+u6yB0c9TbNsjf8VglUq0AdWKphSz01FIBNMvB9YCvtSGnsujgqKjBCfeWFR6JAgwA4ryBClZFFUeyF+8VNDNMUVwcRBflX6zXPZLJXampXJP2NvOlOfDMxBOjNHSlm+STRDLlnkRPC2B28oISy9mi9vsC+wU7ik9929M7teGMUBa3LDHf7T/vuBknkIr76O49AB6PFKl+Z5Q34s31iulq0UBJTEgYvFU/o9eL2YeQxPQuSI2QW3OZfN2NznI8AvXRTNEl0xqC5RrvoNU4aXOZFc8j0mc8zoiqvIWU2X8En+aFCOF5k1YF/KZjlLrBWRZMB0/ewMJH4hcdoBM2BVIMIuJ40cEspmZEoC5N9m0usiiJnOAyGhROsfzNhKegCKGSkCyyGkqydx/ydDDb/LxyWD0bIwWsnRuzaISEwdvOk9pbshOsVsg56R6gkMNlqUYh8x763oWMe3jn0S6yw9ljMOH61tw68z04jBKm+ns7SoeV4WHXxY9FCLWudl0e1Jh2fLUFwynmHwDyIedx1i6vEFYJqXP2bCbbnpxVtiVWKAhCOMvywJ+JCHjY2GaJ6wICglrH41YQGrLmG1la/qUrzpMwEI4a+Zh938NyZq4ipKkBpyBWCEy2ySX03l/+Qpz0owQgyN46WS88U+l3W5LP1QJS6ZnYPMikajmK8DPScKwkTCU6PMhsj3psKADrdYwgFhKY/Xb0M5MfdcN4kIIfEClmBrXPeMUcIH378hPhF8CkgglCJGySsuCYux5BgcMYytHLE7pYhxPiFWzWwNsVYhxq5rpKPHWKNhjNX0YwfZ5NYhpWiVU5A8zp78KAQ5cmlFcumgtC8o6xvmJn1+ka4gY9f6VfYnnHF4TIKNYhKbUYzc/iExaaf9zzGiQ7+UQcxqdDBqogPQWwsP5knCwzvVVHuebp7M0w8yj9mtM4GLcibr7Jzp1O0DrSNvsi4rb+rmbnlTh3r3edPq1tW1S3J1vdwqPLmrg9OU1d2XyAA29HVwVolTLbt9dxo+fdEnjLvU/HfsYP5i9JI8S7OsgmetPSbf06hzLc1uK4nu0EKKvGDq46E4DOJwuB7Fjuz6cF6L5XdRhqiDFoUgqCKo1QGotwXgduqrszhFbrCR59tdhUNY4ypfgjBmHy2jrQTSigSyq/wxO+0Y6c0d8AJ7uNanUjFYc+wIVBevE8DhabYN6xad1bxHt38dofLF1joCHv2Iar89A4QFmhj9LXuGQX+T/sF7hofvX3+5+/x6/+vKGgd/fXsyzDegaq5TEUfbq7nb0flZc8KdxyYVGvZOhCv3Eo9NuI2gtl9WixOnET7wzKmLNHWUCqBoSt1qWoS3lpL6FSx/yi/CaIOGQUIR/0y2t2rd7fvheDQZI0a95dB1D9va/k+qedigvKzdD7bmy3X1fMutkD8oCqK5x9iFdUNKgdgAoGq8us0YHLRlvNN85637IwXY9ITu6H3G/bYH5XLf2lytGfZh+sDedmRhb9JvpxqEnR1PimpQsPcZOa/X8cvLZYUVHTQIK3X1XXthpa5+OOMmq1Z2N2NQQbA2qbYFoGqTn7zJ+lvMPrqsTRhklhg0qNZlnX4xT+++TQ/0OgaJ2PpIiYOj6Cen0dF/wVKu9esOz2p/wbI7qfgw+0FRmsCzX2XB2/8A
--------------------------------------------------------------------------------
/src/main/scala/poseidon/ArithmeticOperator.scala:
--------------------------------------------------------------------------------
1 | package poseidon
2 |
3 | import spinal.core._
4 | import spinal.lib._
5 |
6 | case class ModAdder() extends BlackBox {
7 | val io = new Bundle {
8 | val op1_i = in UInt (255 bits)
9 | val op2_i = in UInt (255 bits)
10 | val res_o = out UInt (255 bits)
11 | }
12 | noIoPrefix()
13 | }
14 |
15 | // standard io interface used in arithmetic operation Component
16 | object operands {
17 | def apply(dataWidth: Int, op1: UInt, op2: UInt): operands = {
18 | val inst = operands(dataWidth)
19 | inst.op1 := op1
20 | inst.op2 := op2
21 | inst
22 | }
23 |
24 | def apply(op1: UInt, op2: UInt): operands = {
25 | val inst = operands(widthOf(op1))
26 | inst.op1 := op1
27 | inst.op2 := op2
28 | inst
29 | }
30 | }
31 | case class operands(dataWidth: Int) extends Bundle {
32 | val op1 = UInt(dataWidth bits)
33 | val op2 = UInt(dataWidth bits)
34 | }
35 |
36 | object results {
37 | def apply(dataWidth: Int, res: UInt): results = {
38 | val inst = results(dataWidth)
39 | inst.res := res
40 | inst
41 | }
42 |
43 | def apply(res: UInt): results = {
44 | val inst = results(widthOf(res))
45 | inst.res := res
46 | inst
47 | }
48 | }
49 |
50 | case class results(dataWidth: Int) extends Bundle {
51 | val res = UInt(dataWidth bits)
52 | }
53 |
54 | case class ModMultiplier() extends BlackBox {
55 | val io = new Bundle {
56 | val clk = in Bool ()
57 | val rst = in Bool ()
58 | val cmd = slave Stream (operands(255))
59 | val rsp = master Stream (results(255))
60 | }
61 | noIoPrefix()
62 | // Function used to rename all signals of the blackbox
63 | private def renameIO(): Unit = {
64 | io.cmd.valid.setName("op_valid_i")
65 | io.cmd.ready.setName("op_ready_o")
66 | io.cmd.op1.setName("op1_i")
67 | io.cmd.op2.setName("op2_i")
68 | io.rsp.valid.setName("res_valid_o")
69 | io.rsp.ready.setName("res_ready_i")
70 | io.rsp.res.setName("res_o")
71 | }
72 |
73 | // Execute the function renameIO after the creation of the component
74 | addPrePopTask(() => renameIO())
75 |
76 | mapCurrentClockDomain(clock = io.clk, reset = io.rst)
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/images/src/MDSMatrixAdder.drawio:
--------------------------------------------------------------------------------
1 | 7Vtbc+I2FP41PMJYki2Zx9yadrqdyUxm0u3Tjhcr4NYgV4gA+fWVsWRbyIDZ4AvZvhB8JGzpO7fvHDkDdDffPPIgmf3BQhoPoBNuBuh+ACHBvvxMBdtM4PowE0x5FGYiUAieo3eqhI6SrqKQLo2JgrFYRIkpnLDFgk6EIQs4Z2tz2iuLzacmwZRagudJENvSP6NQzDKpD0kh/5VG05l+MsDjbGQe6MlqJ8tZELJ1SYQeBuiOMyayb/PNHY1T7DQu2e9+OTCaL4zThajzg9/c4PeXJA7mm9sl9l/W7/Hj16HaxlJs9YZpKPevLhkXMzZliyB+KKS3nK0WIU3v6sirYs4XxhIpBFL4NxViq5QZrASTopmYx2pULphvv6a/HxFPX/9VHrzfqLtnV1t1ZW9ZobBkKz6hR/aJlOkEfErFkXluNi8FofQABegjZXMq1yMncBoHInozjSRQtjbN5xXqkF+URs7Qjlr1WxCv1JMsdUmrStKvy2gxjelNavESqDDi0hkitkhH2Cq1xNv1LBL0OQl2OK2ls5pKOYjtG+WCbo6ioUbhWK1vq68VnOvCc7Q3zEpO4zoN4YdP4zeV1pzU33seaILv+g7OcUyIY2CCyNjCBKAKUIDfEChufaMS0kroO0tvd5tQHskFUF6WPxXCU/b1Gm2oju9gF0VEoCx0CPxq7z6q1NNm2RnEXgXEOBYpCkzurYw1/nfF9MBwuYPnRk4AINkUg/LbNP0rs+tNGFL+Qif6hnJ92T2zGZYqJUbCVASn8jHKfFPY0/i8LPQSxNE0VcpEamGn1xToSCbEGzUwj8JwlwcSFi3EDjrvduDd73Qcx3csZqmNLNginbQUnP1D94RmBrm43rXreYbnDZ2R40DHI8CF/u7TdSCynNGvMBTYVIACoMJSOo5QHrSjNqgK22A8Go9JAWdTWRDAK49YoH4mLWMO2gxZwK0iG1mMWSbB4tJBK7vnpw9aZ6hej7rSq/AYIofsPj1UEcWUx8nPsQMwwt1GMdJ1FQFbqiJ0pLyyMkIv+1rqCOT5hs13XkcAZAPWroUbBu40Z+C6xXLKwHM+3RcTr0Gk+mTirmuSrs5NnNgkaynpDv32RieOBeVVJujz+xmYmEoitpJIq4nW5mi5ksBPqiSEUM+UZDdYciXZQennUJKra7i+KAnoQqrTytvHBiqu3m65CnRgBSyNldpgfBoW0zrOzpUn9FHbpoagAixnhD3ij12CsO9CXX21Y1KwBs0WPApS9tEJcLoFPaogG3hEgONBjIDCz7OhA2ik/bgB9JAF1qek2Ar60wxbu2JPGDaANQ4Omo6YyDUrQ9eviJiItOr1Vc3+A5VHP7uTuWLPPFGpgLm59iSsOsv7vz1Zn7N9WPc5aRm55f4kqTplKfqT0kx8y0XbPWOBfseZpa2XHPKUcTq56KjVm+RSg3c2nVxcx+zJ9ICOoxqUshE6nuvjvJzQKf9GNXqAl+ffZyDVa/6NuubfbR3i5E51fVHStTuxn1RHmu7V0NGlVbT76Q3nwbY0QfGy4s5PqaDc4DJbOR7Yexlzbz7y4LH58ku2gsJY8q18wH70Kclnr7GBV5sI4X4d1eYrP5bEdPXwJfhO4ydZaKi6L68iDpYXJa1crCZVdY4MDigtdfhEF6WpDl/jKHlRT4z3lptXQ1Z5VJ/kHe4UkD0Hw56VczXWRo5tLMHiGm/zNt4/8VIfLOOCHRuXlkkurtFYaoTk5hq5IpKLa7SbLk9yz0Cq1yRX/3NGT1oBDWbA+gRKR8G+ZEDSL5LbpI66U9EPkVy090a1550guT45Nr8pktt1Idtauw/XPkvqSZHkAJN7uMftR5KTD80/VYTBMTk2vyH79K/sVbV9L8Y6GpVfVas4C/Ia40B+xx5upIeipj3g4LurUhHVntdrS+tLZvcPvBllafMqD9h+wLH2izEC7BMH9zJnZfKy+FfjLJYV/6+NHv4D
--------------------------------------------------------------------------------
/images/src/ModMultiplier.drawio:
--------------------------------------------------------------------------------
1 | 7Vxbc5s4FP41ftmZeJCEuDzGSZpOt91JJ7Pb7r50iFEwW2xRLCdOf33FReYijLGNwG6SmSRwOAihc/t0jsQIXc3Xt5ETzj5RlwQjqLnrEboeQWgaFv8bE15Sgm7BlOBFvpuSQE6493+SjKhl1JXvkmWJkVEaMD8sE6d0sSBTVqI5UUSfy2yPNCg/NXQ8IhHup04gU7/4LpulVAuaOf098b2ZeDIw7PTK3BHM2ZssZ45LnwskdDNCVxGlLD2ar69IEI+dGJf0vndbrm46FpEFa3PD4qPxI7z6ji5uv3757Mzu7h/u8UXWypK9iBcmLn//7JRGbEY9unCCm5w6iehq4ZK4VY2f5TwfKQ05EXDi/4Sxl0yYzopRTpqxeZBd5R2OXr7G94+xOP03ay45uV6Xzl6yM/mNRffpKppm/Z9E/z39Cefv9cfbx88fZtfujReI12RO5BHWwAcz5YwHofCEbEBvCZ0T3iHOEJHAYf5TWUmcTNe8DV8uDn6QSaReOk3dfnKCVfakETQC/gKTR8qHoCg348eKigsXy2TkLzkDAOE6v8iPvOx/0sqDIHxaxRYV+CTi90CM/+C/gon3/KF6I6elPRDkihKVVeR55jNyHzqJiJ65myirw1axPpGIkXWjHLKrEOD0lszLAD2zwufcZoEwxFnBXpGmSHTQGNiyYMm0gDLTQi1NC1gnZVqoxrQq8iqM68Z3x2PlOsvZRkhO4HsLfjzlA8etB01ipfV5/LjMLsx9102Ey9sI45bnay+OlOM0OsH0f9yskEUSO0F8tKBsOsuoEWV8WGjcpN0osfZWA0y9ZDWmNjaxbDfmGMuGA1QZDjB3S0YMJeMDSX7SuL1JSCKf9yCWQU6/y4m7vNCjvyYCf3TklYCm7fRKWJkDsgZxQGufFSI7P9sEdn6cO5/4ROh77rRKYCDHBt3DAaut0zopnyW6PbRpFFwR71NXzghVjAXKxmLWRHBljgjJg9urAcGiBYFGCzrcEoQG7UbGqGtTSG69jCLnpcAQUn/BloWW72JCAejhMtCDemXSU+EHdiM/P0h7kKvJ5lWO0Bw8rOaY7TWn/6lYa41D+mloXLMGSfxIH0DjxKAOHRk6iAMQVcZPM6U4YNXEAagqDtj26QCp1sYM+7LmttM/3Hlm5SBrluKB3WzNEKMm/qOteX3/NfL/ubO+3YVf/Ju/3/34MH1/ISDNYLkDs6fcQWvt6T55cKD2GHtpzybldCA/0Oxmft1q4lcUa+pSJ3tmJbW6rGREvBGeYP4O6FIb4etTTTYCA5SlamhShKqbqSiLUGKm1CARUVcRYw5aJIW5MCDWZWHsnQ3m48rKUogI75HzkDAkWTTujZY5jGifVMsslj8GT+JexpAkCK5oQGNIs6CLJPPGIvqdVIhlrelALcxKCtqWtQL3qRVomNrOMQmgTaRRnQASuYYzSwCJbg8N85UkgBA+sQTQJn17ChakKgGkaJYtT4sruXBUFVtqitldueT2hWjS9HsH5Kr2qxeA/2pqg3pLNysc28D4fl/l0fF++L7Kvwvf6xps4leUvdR3osnfG99vXNOp4HsdDRmHQCEK5TFpC5LjJwVcUc1K9ZVX0FvnmDv3O8cJukUa97dflYCwXTI/E57AqgRdlVOkIXibRpcXpZS9r0hxFWSPenW+WJnk4ZvkmyaAuHY5kirh1wJ12f0OuDxWYbw0zjReGm/xEiLTPMF4WbdUKXV2y9BZHO41/yqGy7Sp1+00C4s2B/GbteK3hslwnEfNXJTCd3pbq/Pc3HFCPaEVpa2F2teUs7VQTdi1UA9b1mRV8rHGjoUQyGziV5OKsofBX0Lj9kl8bFnDbO6qYSVn1ZRJD2pon1ZlS/S781mWVNW+dN1klxOOsc8k+XtG+5xgOdQjAGSkB2oivbJ9TkAbNDm5T5n5cKtS5LPrVpuNUfGn7HMxsMd28afc/pYKWlfO2Kwz0Yrkz7b4DCsrr3TDkAxLkHpB0KayNT1pASZeSP+2qucAj6vLHtfodWp1/suR1aFwq23BuXuPftwa82GDaAdAF/YMdFtL+sSArqWqkLQV6CZbpibntqEfw3HF8VpyRO4X6tqD5j86K8ODPQ33cBsVpncuORGp9Gj2sNxGDFITrBZA6aPzQII7jqky/PtAGaPz0V6VjYJqVfEXi1VSqnCQgExZFPONA+r502+ew8iycBzrNQf5ApTHcEzJ1woqWz91OHBlGGiypIbcp6MuYy02TZ1bxtqWa/ebaLtchSLafS+WlHLyxVwS7+uY8yCwe86j91mGH2bKo7IMX/uarb9KMdindJq6/aqL8ACXdwb2/Smd+n2k278fdmQR/q0G34hM5I0rdd8eU+YuQV2m9m0/YM9aoWu9bQjkp/l3JNOJSf4xTnTzCw==
--------------------------------------------------------------------------------
/images/src/MDSMatrixMultiplier.drawio:
--------------------------------------------------------------------------------
1 | 7Vxbc5s6EP41fgyDBAh4zKXtmTOnnc4kM22fMsSoNqcYubKc2P31RxjETXLAxxhB2rzELEKg3e9b7a4QM+t2tftAg/XyIwlxPINmuJtZdzMIgQ9N/i+V7HMJNJ1MsqBRmMtKwX30C+fC/MLFNgrxptaQERKzaF0XzkmS4DmryQJKyUu92XcS1++6DhZYEtzPg1iWfolCtsykHnRL+V84WizFnQHyszOrQDTOR7JZBiF5qYisdzPrlhLCsl+r3S2OU+0JvWTXvT9ytngwihPW5YKX1af5wxVBP28+gE82stf+w/0V8MXTsb0YMg65BvJDQtmSLEgSxO9K6Q0l2yTEab8mPyrb/EPImgsBF/6LGdvn5gy2jHDRkq3i/Cx/ZLr/ml5vAE8cf0tPGsD2heBul98hO9pXjz5jGq0wwzQXytrIFbQhWzrHr6jAylEV0AVmr6nKs7OWqX4qt8i1/QET/jx0zxtQHAcseq4jKMiBuCjalbbiP3JznWC6/Lmfg3ib34nT7+M2pUYcYSrbtW61l2XE8P06OOjmhbO3bqGj+nzGlOHdq+PPz9qCCjn3bTt/ppeSSMDMZcsKiSzzQioDnqcZ7U4N7C1A//+YRhPFNHod00Cynm5MO0A7pn1ZK8Ni2h0I1N5EQe21gHp8qEa+dlSbuuOSGqjNi4Ha7whqwfKRYNqXMC2Zq6LWIvRNdRUGm2VhoyCOFgn/PeeKS2O5mxS0EQ+/r/MTqygMD7blfazTnle7RZpqGFlwD7P/abfCFofkA6S/EsLmy1xKCeNqIUmbwbqTRnBEzASebViuRBvLMaAjEwfYhbh32xRDqRoHxfzON0/8x4Idxp8JvhM+/qrZ0M8tESeuNgeeXPMGFlrvypOiF0N0w58z66neOxdX7tjAB1czq7OPYn7D4OnQ4AAOzs/sEQ6nu2NlTaKEHdTq3Mycu3Q4URzfkpik6UJCkgOgGCU/cENY9yB9uFa/ETAgz0CWDJMhnSuUU4c/ABkNQBRZ0qDoQH/QMWJ0+PrdBzD1ZBy7iFUTDn74rXKqjMzSg1qt6Gv14Fs9uus/oBNVyraIzuo7oDtcek1psK80yLFc9vw5FVQABhoAc9wqQFrb247TAFT2BCW8iqGcgzg5vBw0GxgdeNCosgEA9Nin8AjwTXgEb1RG9VVpRMPIIiljPCXDv0ja3826Upkv5JVyfVs943u0w2IhCNQztyu/p2nVgg2v5wFpTgW2YlK9HIVMpJdCVQaZHRk0VJEE2rrm1DPdoiqUbhh5wW247g7pYqUzD3Rn1cVEFdSB5RlODexQUd2DYlqvFSnAxUoU9jh8SxhRrsrMuXAUptporxS12LqzEyqWwmtOZ0gzAFPLetipKm33D07fvFcHv9Cs1/yahsn8U35RwzY9hMFimBXWMOtxFW4eVwGj0e5xTuLtKjlz5Xcw/IP6FCxzwVVNwBfLaoGWFYf+ueDq4YJrDcsFV+aCP0EuiBU3uaYzNPy1FHX6h3/vSVTHqcAceC6QV5UZgNMlgK/d/5v+2yCAr4cA9sD+X16BZs504W9p9/+K4FLS3cVzVbuJKe2ZKoDyO2mSXiaWqhamnlKqKgK+cbpnodJW9wy0BSjDxidAFaAoktUzX34bjAEjS1bhqIOV7mwQDv6NZ6vFOFvS1dGzYTTpqjXqdPUEAkBN08HA+Wox0LaEdSoU0J+wipxh8hTo/XX9UWasxThbUtapEEB/ymo5kqre5B6BIged2mtBjpwDSBYbuqaAFDu2hq4pOB22T0ysplCYeko1BTTqJT+h0nb/gHrfHDTOmoIYZ1tNQc8UejoFRlZUQLIXmiYdLvNq9eiKCoqdGsqiwujpMJqqArLfCAN0vRA1dFUBKV6JUlYVpsIB/WUFpOVF5AtwQNOLUEOXFZDiTShVWWEqDNBfV3C1xEEa6goiD53YzhTg/tmiOt4tqgiOYIuqJ6+3nY0QricFQt4T+uONg+QiO7Dc+qzpeMCwfQk1aFDH78GjqNmsg6QLSIDSjUjY23CN4kcc4xU+4EWBk0KW3Xq68OnDx5RfUSm+o6HYsQeHRctINjFV6NkXOx3LNmxUVziAhpybQIAMEUXUtI6Mi1VtfS3rnsPvGwae0zE8A+64vnhWPPnlp9+/uZP6fabfvviNOJndJr+d9MMaQ03A1tOn2IRRQMP1r7tr/4v/8PDz6viHqy4y/T7j+W8x9SoWUSX0HIWKa9o1nNi+Eif+kDhRhWkN41SWlTuvIZ+iFuQ1qj62qVKLKuspqhkXSIxVIclpblbNIIoXR73sOVUlWe2vGrzdwWnUfYcNFIxGQbI4ULx7ue1YznWmpgS/DQT9yp9Tj7OBAw3Lk3AN7ALtNfX6hlhE7J30J0TbmyhV8nX+ZchOEDzPR8JGMqueS51+fCQ/LL8an5WRy4/vW+/+Aw==
--------------------------------------------------------------------------------
/src/tests/Makefile:
--------------------------------------------------------------------------------
1 | # Makefile
2 | # defaults
3 | DUT ?= AXI4StreamReceiver
4 | SIM ?= icarus
5 | TOPLEVEL_LANG ?= verilog
6 |
7 | PWD = $(shell pwd)
8 | export PYTHONPATH := $(PWD)/../reference_model:$(PYTHONPATH)
9 | export PYTHONPATH := $(PWD)/../reference_model/poseidon_python:$(PYTHONPATH)
10 |
11 | # add verilog sources
12 | VERILOG_SOURCES += ../main/verilog/$(DUT).v
13 |
14 | #PLUSARGS += -fst
15 | ifeq ($(WAVES), 1)
16 | VERILOG_SOURCES += iverilog_dump.v
17 | COMPILE_ARGS += -s iverilog_dump
18 | endif
19 |
20 | ifeq ($(DUT),MDSMatrixAdders)
21 | VERILOG_SOURCES += ../main/verilog/ModAdder.v
22 | endif
23 |
24 | ifeq ($(DUT), MDSMatrixMultiplier)
25 | VERILOG_SOURCES += ../main/verilog/MontMultiplierBasics.v
26 | VERILOG_SOURCES += ../main/verilog/ModMultiplier.v
27 | endif
28 |
29 | ifeq ($(DUT), MontMultiplierPiped)
30 | VERILOG_SOURCES += ../main/verilog/MontMultiplierBasics.v
31 | endif
32 |
33 | ifeq ($(DUT), MontMultiplierPipedSim)
34 | VERILOG_SOURCES += ../main/verilog/MontMultiplierBasics.v
35 | endif
36 |
37 | ifeq ($(DUT), PoseidonThread)
38 | VERILOG_SOURCES += ../main/verilog/ModAdder.v
39 | VERILOG_SOURCES += ../main/verilog/MontMultiplierBasics.v
40 | VERILOG_SOURCES += ../main/verilog/ModMultiplier.v
41 | endif
42 |
43 | ifeq ($(DUT), PoseidonTopLevel)
44 | VERILOG_SOURCES += ../main/verilog/ModAdder.v
45 | VERILOG_SOURCES += ../main/verilog/MontMultiplierBasics.v
46 | VERILOG_SOURCES += ../main/verilog/ModMultiplier.v
47 | endif
48 |
49 | # TOPLEVEL is the name of the toplevel module in your Verilog or VHDL file
50 | TOPLEVEL = $(DUT)
51 |
52 |
53 | # MODULE is the basename of the Python test file
54 | MODULE = $(DUT)Tester
55 | ifeq ($(DUT), MontMultiplierPipedSim2)
56 | MODULE = MontMultiplierPipedTester
57 | endif
58 |
59 | ifeq ($(DUT), MontMultiplierPipedSim)
60 | MODULE = MontMultiplierPipedTester
61 | endif
62 |
63 | ifeq ($(DUT), MontgomeryMultStream)
64 | MODULE = MontMultiplierPipedTester
65 | endif
66 |
67 |
68 | ifeq ($(DUT), MultiplierIPStream)
69 | MODULE = MultiplierStreamTester
70 | endif
71 |
72 | ifeq ($(DUT), MultiplierIPFlow)
73 | MODULE = MultiplierFlowTester
74 | endif
75 |
76 | ifeq ($(DUT), ModAdderPiped)
77 | MODULE = ModularAdderFlowTester
78 | endif
79 |
80 | # include cocotb's make rules to take care of the simulator setup
81 | include $(shell cocotb-config --makefiles)/Makefile.sim
82 |
83 |
84 | iverilog_dump.v:
85 | echo 'module iverilog_dump();' > $@
86 | echo 'initial begin' >> $@
87 | echo ' $$dumpfile("$(TOPLEVEL).vcd");' >> $@
88 | echo ' $$dumpvars(0, $(TOPLEVEL));' >> $@
89 | echo 'end' >> $@
90 | echo 'endmodule' >> $@
91 |
92 | # clean
93 | clean::
94 | @rm -rf __pycache__
95 | @rm -rf sim_build
96 | @rm -rf results.xml
97 | @rm -rf dump.vcd
--------------------------------------------------------------------------------
/poseidon_constants/compressed_round_constants_ff/full_round_constants_ff_5.txt:
--------------------------------------------------------------------------------
1 | 3e90d6cd6c7833beea8072690272c364efb62462b729ba3562df178936cee858
2 | 5b15a4cbaf84cb6230e39b5b4a7430dc05d6d9b02812267bb2bfa42f73df7ae2
3 | 58ca12da49ef4ab21f950964eae842a1970bf09ebf6d1b94d4933b1b4e728ee9
4 | 7290a0e823d4fdc123c122b2e0abddf01ec1af883fe512210beaa100831b5c1c
5 | 49356536fd1d9842465dabd0935b9703d5c3d9009dc1c9b30cc2836ed64f4ad0
6 | 6253f8445181947e7ce6886a71222e22c791d2fe42433fad63f21b32a6d4c501
7 | b0a1c20e1a89b10db06e7c3d5536dfe9cf13e57c92ee940943c1f285ac1c66f
8 | 2d70f909d350eb69e1ae4db73c91d81bf2327b62f54b6a11a57147d9c209055
9 | 2a8b5c7582103c71bc617b5161fc3ff2d686f36f8b4115c9725bbf69e3f6bd6a
10 | 717b04c11072646d75a9ea620113af3a34b44f37ded6f065effeb9206e4114ed
11 | 39102cfe4976829c17350bef3ce413f7090a1d1f8dd915bf0029823895b6df77
12 | 268f30e1d558361ef8e6a425541a6d224870ba6e333f13efbe3d9f908da0aa79
13 | 41878a1395ae763c0db29b1a3fd1a0b8632a6665db7298bc7d09b9ec9134abe2
14 | 30c09edc44a3b6fc25dc04c842aea1849f39a71449a1549c3508eed65cb2af91
15 | dd2e613dfddf86a22c821832a867d87eedd40f4aca1a1ff463c03b14fda248e
16 | 34f0bc9689c7a8bfdcfd4a28bb3591b062b9fb610571b4e77183603603c824f3
17 | 637ba50bbf8f4cbc618ae65d2ee1314dce4528feb68cf0e96f258cec4753f58f
18 | 52188f75db41ed39d3d8775d2cf76ecea4657029d1b18211075c49ae16f0b559
19 | 6eef08529ac5126c3c0456985fadaee5dd169a00fd55409a0051f1fad894717e
20 | 2be380692474498fb20d6c8ed7eb94a693faf8b6f80cbd0cb82526c6857c31af
21 | 56d28c7bdc6b5c23534e8c14987ebeb834add7427ded651c69dc23e27120456
22 | cb487276eced6a6e144ac2b4a17a00bbae913c586008f1a3c762c83fc588e6e
23 | 35a019c05a9ed06b228da72f5305348809401a868b0089f32c7718717c7a50a8
24 | 711af051b3f23397c815a0554d315eae13fbddbfb38a14704201eccfb2506a6a
25 | 692fbd6f78cc46ad074223fe12c2e188d6270453a760e7b2210701ae5cb0a954
26 | 54fff081f436a8125535858ccbee9f056fcfc9c27345b28680ee08141584ac15
27 | 307faf11551f916c049b8b283d6d0f5dd0576d3c2d22b95c7e68dbc5056c2ca0
28 | 618a5d16dd4c250c185682b1dc0177c19a8dc18fd5d55bf001c674dfefa067a4
29 | 240cbef05002149467cd0286e8b919db13f7abeb261359957170dc3e83a591b0
30 | 5b5e10efc9f91a8b417bc7de959d984f5906efe76291c3d11c52c684668fce23
31 | 1e02df65cba9f57559f54e595e8e1b929538b86c1f93f66fabb318eb21854b3b
32 | 4ef39debb5bcc97c9a3e4453ec20d7e83df165527d82d032fc161bb46f046958
33 | 6ca2cb9e63ceab96e58eb55a293080b16e037935448d7f83d65ce0841fb1f453
34 | 5d466700cccb3c5415d47a795b146ce17634043fffecedc55952e9ec80c4d3ac
35 | 65e2e8377190483bc6c095638c9fcce83369f3454fba50fbc37cab22808060ce
36 | 0000000000000000000000000000000000000000000000000000000000000000
37 | 0000000000000000000000000000000000000000000000000000000000000000
38 | 0000000000000000000000000000000000000000000000000000000000000000
39 | 0000000000000000000000000000000000000000000000000000000000000000
40 | 0000000000000000000000000000000000000000000000000000000000000000
41 |
--------------------------------------------------------------------------------
/src/tests/poseidon_python/constants.py:
--------------------------------------------------------------------------------
1 | from asyncio import constants
2 | import basic
3 | import os
4 |
5 |
6 | def int_to_bin(num_int, length):
7 | """convert int to binary string of given length"""
8 | num_str = bin(num_int)[2:]
9 | str_len = len(num_str)
10 | if length <= str_len:
11 | return num_str[str_len - length : str_len]
12 | else:
13 | return num_str.zfill(length)
14 |
15 |
16 | def xor_bit(bit1, bit2):
17 | """xor operation on char"""
18 | if bit1 == bit2:
19 | return "0"
20 | else:
21 | return "1"
22 |
23 |
24 | def shift_and_add(grainstate, bit):
25 | return (grainstate + bit)[1:]
26 |
27 |
28 | def get_new_bit(grainstate):
29 | tmp = xor_bit(grainstate[0], grainstate[13])
30 | tmp = xor_bit(tmp, grainstate[23])
31 | tmp = xor_bit(tmp, grainstate[38])
32 | tmp = xor_bit(tmp, grainstate[51])
33 | tmp = xor_bit(tmp, grainstate[62])
34 | return tmp
35 |
36 |
37 | def generate_constants(t, r_f, r_p):
38 | """generate roundconstants for Filecoin's poseidon"""
39 | num_contants = (r_f + r_p) * t
40 |
41 | FieldBits = int_to_bin(num_int=1, length=2)
42 | SboxBits = int_to_bin(num_int=1, length=4)
43 | FieldSizeBits = int_to_bin(num_int=255, length=12)
44 | tBits = int_to_bin(t, 12)
45 | RfBits = int_to_bin(r_f, 10)
46 | RpBits = int_to_bin(r_p, 10)
47 | padBits = 30 * "1"
48 |
49 | GrainState = (
50 | FieldBits + SboxBits + FieldSizeBits + tBits + RfBits + RpBits + padBits
51 | )
52 |
53 | for i in range(160):
54 | tmp_bit = get_new_bit(GrainState)
55 | GrainState = shift_and_add(GrainState, tmp_bit)
56 |
57 | RoundConstants = []
58 |
59 | while len(RoundConstants) < num_contants:
60 | tmp_bits = str()
61 | while len(tmp_bits) < 255:
62 | bit1 = get_new_bit(GrainState)
63 | GrainState = shift_and_add(GrainState, bit1)
64 | bit2 = get_new_bit(GrainState)
65 | GrainState = shift_and_add(GrainState, bit2)
66 | if bit1 == "1":
67 | tmp_bits = tmp_bits + bit2
68 | c = int(tmp_bits, 2)
69 | if c < basic.P:
70 | RoundConstants.append(c)
71 |
72 | return RoundConstants
73 |
74 |
75 | def output_round_constants():
76 | """generate round constants and write to files"""
77 |
78 | os.mkdir("round_constants")
79 | os.chdir("round_constants")
80 | for t in basic.T_RANGE:
81 | fileobject = open("round_constants_{}.txt".format(t), "w")
82 | round_constants = generate_constants(t, basic.ROUNDFULL, basic.ROUNDPARTIAL[t])
83 | for element in round_constants:
84 | output_str = hex(element)
85 | fileobject.write(output_str[2:] + "\n")
86 | fileobject.close()
87 |
--------------------------------------------------------------------------------
/src/reference_model/poseidon_python/constants.py:
--------------------------------------------------------------------------------
1 | from asyncio import constants
2 | import basic
3 | import os
4 |
5 |
6 | def int_to_bin(num_int, length):
7 | """convert int to binary string of given length"""
8 | num_str = bin(num_int)[2:]
9 | str_len = len(num_str)
10 | if length <= str_len:
11 | return num_str[str_len - length : str_len]
12 | else:
13 | return num_str.zfill(length)
14 |
15 |
16 | def xor_bit(bit1, bit2):
17 | """xor operation on char"""
18 | if bit1 == bit2:
19 | return "0"
20 | else:
21 | return "1"
22 |
23 |
24 | def shift_and_add(grainstate, bit):
25 | return (grainstate + bit)[1:]
26 |
27 |
28 | def get_new_bit(grainstate):
29 | tmp = xor_bit(grainstate[0], grainstate[13])
30 | tmp = xor_bit(tmp, grainstate[23])
31 | tmp = xor_bit(tmp, grainstate[38])
32 | tmp = xor_bit(tmp, grainstate[51])
33 | tmp = xor_bit(tmp, grainstate[62])
34 | return tmp
35 |
36 |
37 | def generate_constants(t, r_f, r_p):
38 | """generate roundconstants for Filecoin's poseidon"""
39 | num_contants = (r_f + r_p) * t
40 |
41 | FieldBits = int_to_bin(num_int=1, length=2)
42 | SboxBits = int_to_bin(num_int=1, length=4)
43 | FieldSizeBits = int_to_bin(num_int=255, length=12)
44 | tBits = int_to_bin(t, 12)
45 | RfBits = int_to_bin(r_f, 10)
46 | RpBits = int_to_bin(r_p, 10)
47 | padBits = 30 * "1"
48 |
49 | GrainState = (
50 | FieldBits + SboxBits + FieldSizeBits + tBits + RfBits + RpBits + padBits
51 | )
52 |
53 | for i in range(160):
54 | tmp_bit = get_new_bit(GrainState)
55 | GrainState = shift_and_add(GrainState, tmp_bit)
56 |
57 | RoundConstants = []
58 |
59 | while len(RoundConstants) < num_contants:
60 | tmp_bits = str()
61 | while len(tmp_bits) < 255:
62 | bit1 = get_new_bit(GrainState)
63 | GrainState = shift_and_add(GrainState, bit1)
64 | bit2 = get_new_bit(GrainState)
65 | GrainState = shift_and_add(GrainState, bit2)
66 | if bit1 == "1":
67 | tmp_bits = tmp_bits + bit2
68 | c = int(tmp_bits, 2)
69 | if c < basic.P:
70 | RoundConstants.append(c)
71 |
72 | return RoundConstants
73 |
74 |
75 | def output_round_constants():
76 | """generate round constants and write to files"""
77 |
78 | os.mkdir("round_constants")
79 | os.chdir("round_constants")
80 | for t in basic.T_RANGE:
81 | fileobject = open("round_constants_{}.txt".format(t), "w")
82 | round_constants = generate_constants(t, basic.ROUNDFULL, basic.ROUNDPARTIAL[t])
83 | for element in round_constants:
84 | output_str = hex(element)
85 | fileobject.write(output_str[2:] + "\n")
86 | fileobject.close()
87 |
--------------------------------------------------------------------------------
/src/tests/MultiplierFlowTester.py:
--------------------------------------------------------------------------------
1 | from operator import truediv
2 | import cocotb
3 | import random
4 | from cocotb.clock import Clock
5 | from cocotb.result import TestSuccess
6 | from cocotb.triggers import RisingEdge
7 | from queue import Queue
8 |
9 | CASES_NUM = 3000 # the number of test cases
10 |
11 |
12 | class MultiplierTester:
13 | def __init__(self, target, mul_width, stages_num):
14 |
15 | self.width = mul_width
16 | self.dut = target
17 | self.ref_outputs = Queue(maxsize=stages_num + 5) # store reference results
18 |
19 | async def reset_dut(self):
20 | dut = self.dut
21 | dut.reset.value = 0
22 | await RisingEdge(dut.clk)
23 | dut.reset.value = 1
24 | for i in range(3):
25 | await RisingEdge(dut.clk)
26 |
27 | dut.reset.value = 0
28 |
29 | def get_random_values(self):
30 | rand_valid = True # random.random() > 0.1
31 | rand_op1 = random.randint(0, pow(2, self.width) - 1)
32 | rand_op2 = random.randint(0, pow(2, self.width) - 1)
33 | return rand_valid, rand_op1, rand_op2
34 |
35 | async def generate_input(self):
36 | """generate input signals"""
37 | dut = self.dut
38 | cases_count = 0
39 | while cases_count < CASES_NUM:
40 | valid, op1, op2 = self.get_random_values()
41 |
42 | # assign random values to dut io port
43 | dut.io_input_valid.value = valid
44 | dut.io_input_payload_op1.value = op1
45 | dut.io_input_payload_op2.value = op2
46 |
47 | await RisingEdge(dut.clk)
48 | if dut.io_input_valid.value:
49 | cases_count += 1
50 | self.ref_outputs.put([op1, op2, op1 * op2])
51 |
52 | dut.io_input_valid.value = False
53 |
54 | async def check_output(self):
55 | """check output signals"""
56 | dut = self.dut
57 | cases_count = 0
58 | while cases_count < CASES_NUM:
59 | await RisingEdge(dut.clk)
60 | if dut.io_output_valid.value == True:
61 | cases_count += 1
62 | op1, op2, ref_res = self.ref_outputs.get()
63 | dut_res = int(dut.io_output_payload_res.value)
64 |
65 | assert (
66 | dut_res == ref_res
67 | ), " testcase{}: the result of {} * {} is wrong \n ref:{} \n dut:{}".format(
68 | cases_count, hex(op1), hex(op2), hex(ref_res), hex(dut_res)
69 | )
70 |
71 | raise TestSuccess(" pass {} test cases".format(CASES_NUM))
72 |
73 |
74 | @cocotb.test(timeout_time=300000, timeout_unit="ns")
75 | async def MultiplierTest(dut):
76 | await cocotb.start(Clock(dut.clk, 10, "ns").start())
77 |
78 | dut.io_input_valid.value = False
79 | dut.io_input_payload_op1.value = 0
80 | dut.io_input_payload_op2.value = 0
81 |
82 | tester = MultiplierTester(dut, 255, 60)
83 | await tester.reset_dut()
84 | await cocotb.start(tester.generate_input())
85 | await cocotb.start(tester.check_output())
86 |
87 | while True:
88 | await RisingEdge(dut.clk)
89 |
--------------------------------------------------------------------------------
/src/tests/MultiplierStreamTester.py:
--------------------------------------------------------------------------------
1 | from operator import truediv
2 | import cocotb
3 | import random
4 | from cocotb.clock import Clock
5 | from cocotb.result import TestSuccess
6 | from cocotb.triggers import RisingEdge
7 | from queue import Queue
8 |
9 | CASES_NUM = 3000 # the number of test cases
10 |
11 |
12 | class MultiplierTester:
13 | def __init__(self, target, mul_width, stages_num):
14 |
15 | self.width = mul_width
16 | self.dut = target
17 | self.ref_outputs = Queue(maxsize=stages_num + 5) # store reference results
18 |
19 | async def reset_dut(self):
20 | dut = self.dut
21 | dut.reset.value = 0
22 | await RisingEdge(dut.clk)
23 | dut.reset.value = 1
24 | for i in range(3):
25 | await RisingEdge(dut.clk)
26 |
27 | dut.reset.value = 0
28 |
29 | def get_random_values(self):
30 | rand_valid = random.random() > 0.1
31 | rand_op1 = random.randint(0, pow(2, self.width) - 1)
32 | rand_op2 = random.randint(0, pow(2, self.width) - 1)
33 | return rand_valid, rand_op1, rand_op2
34 |
35 | async def generate_input(self):
36 | """generate input signals"""
37 | dut = self.dut
38 | cases_count = 0
39 | while cases_count < CASES_NUM:
40 | valid, op1, op2 = self.get_random_values()
41 |
42 | # assign random values to dut io port
43 | dut.io_input_valid.value = valid
44 | dut.io_input_payload_op1.value = op1
45 | dut.io_input_payload_op2.value = op2
46 |
47 | await RisingEdge(dut.clk)
48 | if dut.io_input_valid.value & dut.io_input_ready.value:
49 | cases_count += 1
50 | self.ref_outputs.put([op1, op2, op1 * op2])
51 |
52 | dut.io_input_valid.value = False
53 |
54 | async def check_output(self):
55 | """check output signals"""
56 | dut = self.dut
57 | cases_count = 0
58 | while cases_count < CASES_NUM:
59 | dut.io_output_ready.value = random.random() > 0.4
60 | await RisingEdge(dut.clk)
61 | if dut.io_output_ready.value & dut.io_output_valid.value == True:
62 | cases_count += 1
63 | op1, op2, ref_res = self.ref_outputs.get()
64 | dut_res = int(dut.io_output_payload_res.value)
65 |
66 | assert (
67 | dut_res == ref_res
68 | ), "the result of {} * {} is wrong \n ref:{} \n dut:{}".format(
69 | hex(op1), hex(op2), hex(ref_res), hex(dut_res)
70 | )
71 |
72 | raise TestSuccess(" pass {} test cases".format(CASES_NUM))
73 |
74 |
75 | @cocotb.test(timeout_time=300000, timeout_unit="ns")
76 | async def MultiplierTest(dut):
77 | await cocotb.start(Clock(dut.clk, 10, "ns").start())
78 |
79 | dut.io_input_valid.value = False
80 | dut.io_input_payload_op1.value = 0
81 | dut.io_input_payload_op2.value = 0
82 | dut.io_output_ready.value = False
83 |
84 | tester = MultiplierTester(dut, 255, 50)
85 | await tester.reset_dut()
86 | await cocotb.start(tester.generate_input())
87 | await cocotb.start(tester.check_output())
88 |
89 | while True:
90 | await RisingEdge(dut.clk)
91 |
--------------------------------------------------------------------------------
/src/tests/poseidon_python/basic.py:
--------------------------------------------------------------------------------
1 | import math
2 | import os
3 |
4 | # Poseidon Constants Parameters
5 |
6 | P = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001
7 | M = 128
8 | T_RANGE = {3, 5, 9, 12}
9 | S_BOX_EXP = 5
10 |
11 | ROUNDFULL = 8
12 | ROUNDPARTIAL = {3: 55, 5: 56, 9: 57, 12: 57}
13 |
14 |
15 | # prime field element arithmetic operation
16 | class PrimeFieldOps:
17 | def add(op1, op2):
18 | return (op1 + op2) % P
19 |
20 | def mul(op1, op2):
21 | return (op1 * op2) % P
22 |
23 | def s_box(op1):
24 | tmp = 1
25 | for i in range(S_BOX_EXP):
26 | tmp = PrimeFieldOps.mul(tmp, op1)
27 | return tmp
28 |
29 | def s_boxes(op1_list):
30 | tmp = []
31 | for i in op1_list:
32 | tmp.append(PrimeFieldOps.s_box(i))
33 | return tmp
34 |
35 | def add_round_constants(state, constant):
36 | tmp = []
37 | for i in range(len(state)):
38 | tmp.append(PrimeFieldOps.add(state[i], constant[i]))
39 | return tmp
40 |
41 | def get_inverse(x):
42 | """get the modular inverse of x (mod p )"""
43 | """ the inverse of x equals to pow(x,p-2) mod p """
44 | p_bin = bin(P - 2)[2:]
45 | inverse = 1
46 | tmp = x % P
47 | for i in range(len(p_bin)):
48 | if p_bin[len(p_bin) - i - 1] == "1":
49 | inverse = (inverse * tmp) % P
50 | tmp = (tmp * tmp) % P
51 |
52 | return inverse
53 |
54 | def mds_mixing(state):
55 | t = len(state)
56 | new_state = []
57 | mds_matrix = PrimeFieldOps.get_mds_matrix(t)
58 | for i in range(t):
59 | tmp = 0
60 | for j in range(t):
61 | tmp = PrimeFieldOps.add(
62 | PrimeFieldOps.mul(state[j], mds_matrix[j][i]), tmp
63 | )
64 | new_state.append(tmp)
65 |
66 | return new_state
67 |
68 | def init_state(preimage):
69 | """get initial state from preimage"""
70 | domain_tag = [pow(2, len(preimage)) - 1]
71 | return domain_tag + preimage
72 |
73 | def get_mds_matrix(t):
74 |
75 | mds_x = range(0, t)
76 | mds_y = range(t, 2 * t)
77 | mds_matrix = []
78 |
79 | for x in mds_x:
80 | mds_vec = []
81 | for y in mds_y:
82 | mds_vec.append(PrimeFieldOps.get_inverse(x + y))
83 | mds_matrix.append(mds_vec)
84 |
85 | return mds_matrix
86 |
87 | def output_mds_matrixs():
88 | """generate mds_matrixs and write to files"""
89 |
90 | os.mkdir("mds_matrixs")
91 | os.chdir("mds_matrixs")
92 | for t in T_RANGE:
93 | mds_matrix = PrimeFieldOps.get_mds_matrix(t)
94 | fileobject = open("mds_matrix_{}.txt".format(t), "w")
95 | for mds_vec in mds_matrix:
96 | for element in mds_vec:
97 | output_str = hex(element)
98 | fileobject.write(output_str[2:] + "\n")
99 |
100 | fileobject.close()
101 |
--------------------------------------------------------------------------------
/src/reference_model/poseidon_python/basic.py:
--------------------------------------------------------------------------------
1 | import math
2 | import os
3 |
4 | # Poseidon Constants Parameters
5 |
6 | P = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001
7 | M = 128
8 | T_RANGE = {3, 5, 9, 12}
9 | S_BOX_EXP = 5
10 |
11 | ROUNDFULL = 8
12 | ROUNDPARTIAL = {3: 55, 5: 56, 9: 57, 12: 57}
13 |
14 |
15 | # prime field element arithmetic operation
16 | class PrimeFieldOps:
17 | def add(op1, op2):
18 | return (op1 + op2) % P
19 |
20 | def mul(op1, op2):
21 | return (op1 * op2) % P
22 |
23 | def s_box(op1):
24 | tmp = 1
25 | for i in range(S_BOX_EXP):
26 | tmp = PrimeFieldOps.mul(tmp, op1)
27 | return tmp
28 |
29 | def s_boxes(op1_list):
30 | tmp = []
31 | for i in op1_list:
32 | tmp.append(PrimeFieldOps.s_box(i))
33 | return tmp
34 |
35 | def add_round_constants(state, constant):
36 | tmp = []
37 | for i in range(len(state)):
38 | tmp.append(PrimeFieldOps.add(state[i], constant[i]))
39 | return tmp
40 |
41 | def get_inverse(x):
42 | """get the modular inverse of x (mod p )"""
43 | """ the inverse of x equals to pow(x,p-2) mod p """
44 | p_bin = bin(P - 2)[2:]
45 | inverse = 1
46 | tmp = x % P
47 | for i in range(len(p_bin)):
48 | if p_bin[len(p_bin) - i - 1] == "1":
49 | inverse = (inverse * tmp) % P
50 | tmp = (tmp * tmp) % P
51 |
52 | return inverse
53 |
54 | def mds_mixing(state):
55 | t = len(state)
56 | new_state = []
57 | mds_matrix = PrimeFieldOps.get_mds_matrix(t)
58 | for i in range(t):
59 | tmp = 0
60 | for j in range(t):
61 | tmp = PrimeFieldOps.add(
62 | PrimeFieldOps.mul(state[j], mds_matrix[j][i]), tmp
63 | )
64 | new_state.append(tmp)
65 |
66 | return new_state
67 |
68 | def init_state(preimage):
69 | """get initial state from preimage"""
70 | domain_tag = [pow(2, len(preimage)) - 1]
71 | return domain_tag + preimage
72 |
73 | def get_mds_matrix(t):
74 |
75 | mds_x = range(0, t)
76 | mds_y = range(t, 2 * t)
77 | mds_matrix = []
78 |
79 | for x in mds_x:
80 | mds_vec = []
81 | for y in mds_y:
82 | mds_vec.append(PrimeFieldOps.get_inverse(x + y))
83 | mds_matrix.append(mds_vec)
84 |
85 | return mds_matrix
86 |
87 | def output_mds_matrixs():
88 | """generate mds_matrixs and write to files"""
89 |
90 | os.mkdir("mds_matrixs")
91 | os.chdir("mds_matrixs")
92 | for t in T_RANGE:
93 | mds_matrix = PrimeFieldOps.get_mds_matrix(t)
94 | fileobject = open("mds_matrix_{}.txt".format(t), "w")
95 | for mds_vec in mds_matrix:
96 | for element in mds_vec:
97 | output_str = hex(element)
98 | fileobject.write(output_str[2:] + "\n")
99 |
100 | fileobject.close()
101 |
--------------------------------------------------------------------------------
/src/tests/ModularAdderFlowTester.py:
--------------------------------------------------------------------------------
1 | import cocotb
2 | import random
3 | from cocotb.clock import Clock
4 | from cocotb.result import TestSuccess
5 | from cocotb.result import TestFailure
6 | from cocotb.triggers import RisingEdge
7 | from queue import Queue
8 | from poseidon_python import finite_field as ff
9 | from cocotb_test import simulator
10 |
11 | CASES_NUM = 3000 # the number of test cases
12 |
13 |
14 | class ModularAdderFlowTester:
15 | def __init__(self, target):
16 | self.dut = target
17 | self.ref_outputs = Queue(maxsize=50) # store reference results
18 |
19 | async def reset_dut(self):
20 | dut = self.dut
21 | dut.reset.value = 0
22 | await RisingEdge(dut.clk)
23 | dut.reset.value = 1
24 | for i in range(3):
25 | await RisingEdge(dut.clk)
26 |
27 | dut.reset.value = 0
28 |
29 | def get_random_values(self):
30 | rand_valid = random.random() > 0.3
31 | rand_op1 = ff.PrimeField(random.randint(0, ff.P - 1))
32 | rand_op2 = ff.PrimeField(random.randint(0, ff.P - 1))
33 | return rand_valid, rand_op1, rand_op2
34 |
35 | async def drive_input_ports(self):
36 | """generate input signals"""
37 | dut = self.dut
38 | cases_count = 0
39 | while cases_count < CASES_NUM:
40 | valid, op1, op2 = self.get_random_values()
41 |
42 | # assign random values to dut io port
43 | dut.io_input_valid.value = valid
44 | dut.io_input_payload_op1.value = op1.value
45 | dut.io_input_payload_op2.value = op2.value
46 |
47 | await RisingEdge(dut.clk)
48 | if dut.io_input_valid.value == True:
49 | cases_count += 1
50 | self.ref_outputs.put(
51 | [op1.value, op2.value, op1.ModAdd(op1.value, op2.value)]
52 | )
53 |
54 | dut.io_input_valid.value = False
55 |
56 | async def monitor_output_ports(self):
57 | """check output signals"""
58 | dut = self.dut
59 | cases_count = 0
60 | while cases_count < CASES_NUM:
61 | await RisingEdge(dut.clk)
62 | if dut.io_output_valid.value == True:
63 | cases_count += 1
64 | op1, op2, ref_res = self.ref_outputs.get()
65 | dut_res = int(dut.io_output_payload_res.value)
66 |
67 | if dut_res != ref_res:
68 | print("INPUT:")
69 | print(hex(op1))
70 | print(hex(op2))
71 | print("REF:\n" + hex(ref_res))
72 | print("DUT:\n" + hex(dut_res))
73 | raise TestFailure(f"test case {cases_count} failed!!!")
74 |
75 | raise TestSuccess(" pass {} test cases".format(CASES_NUM))
76 |
77 |
78 | @cocotb.test(timeout_time=300000, timeout_unit="ns")
79 | async def ModularAdderFlowTest(dut):
80 | await cocotb.start(Clock(dut.clk, 10, "ns").start())
81 |
82 | dut.io_input_valid.value = False
83 | dut.io_input_payload_op1.value = 0
84 | dut.io_input_payload_op2.value = 0
85 |
86 | tester = ModularAdderFlowTester(dut)
87 | await tester.reset_dut()
88 | await cocotb.start(tester.drive_input_ports())
89 | await cocotb.start(tester.monitor_output_ports())
90 |
91 | while True:
92 | await RisingEdge(dut.clk)
93 |
--------------------------------------------------------------------------------
/src/tests/AdderTreeTester.py:
--------------------------------------------------------------------------------
1 | import cocotb
2 | import random
3 | from cocotb.clock import Clock
4 | from cocotb.result import TestSuccess
5 | from cocotb.result import TestFailure
6 | from cocotb.triggers import RisingEdge
7 | from queue import Queue
8 | from poseidon_python import finite_field as ff
9 | from cocotb_test import simulator
10 |
11 | CASES_NUM = 3000 # the number of test cases
12 |
13 |
14 | class ModularAdderFlowTester:
15 | def __init__(self, target, opNum=12):
16 | self.opNum = opNum
17 | self.dut = target
18 | self.ref_outputs = Queue(maxsize=100) # store reference results
19 |
20 | async def reset_dut(self):
21 | dut = self.dut
22 | dut.reset.value = 0
23 | await RisingEdge(dut.clk)
24 | dut.reset.value = 1
25 | for i in range(3):
26 | await RisingEdge(dut.clk)
27 |
28 | dut.reset.value = 0
29 |
30 | def get_random_values(self):
31 | rand_valid = random.random() > 0.3
32 | rand_values = []
33 | for i in range(self.opNum):
34 | rand_values.append(ff.PrimeField(random.randint(0, ff.P - 1)))
35 |
36 | return rand_valid, rand_values
37 |
38 | async def drive_input_ports(self):
39 | """generate input signals"""
40 | dut = self.dut
41 | cases_count = 0
42 | while cases_count < CASES_NUM:
43 | valid, operands = self.get_random_values()
44 |
45 | # assign random values to dut io port
46 | dut.io_input_valid.value = valid
47 | for i in range(self.opNum):
48 | exec(f"dut.io_input_payload_{i}.value = operands[{i}].value")
49 |
50 | await RisingEdge(dut.clk)
51 | if dut.io_input_valid.value == True:
52 | cases_count += 1
53 | result = ff.PrimeField(0)
54 | for i in range(self.opNum):
55 | result.addassign(operands[i])
56 | self.ref_outputs.put([operands, result])
57 |
58 | dut.io_input_valid.value = False
59 |
60 | async def monitor_output_ports(self):
61 | """check output signals"""
62 | dut = self.dut
63 | cases_count = 0
64 | while cases_count < CASES_NUM:
65 | await RisingEdge(dut.clk)
66 | if dut.io_output_valid.value == True:
67 | cases_count += 1
68 | ref_input, ref_res = self.ref_outputs.get()
69 | dut_res = int(dut.io_output_payload.value)
70 |
71 | if dut_res != ref_res.value:
72 | print("INPUT:")
73 | for i in range(self.opNum):
74 | print(hex(ref_input[i].value))
75 | print("REF:\n" + hex(ref_res.value))
76 | print("DUT:\n" + hex(dut_res))
77 | raise TestFailure(f"test case {cases_count} failed!!!")
78 |
79 | raise TestSuccess(" pass {} test cases".format(CASES_NUM))
80 |
81 |
82 | @cocotb.test(timeout_time=300000, timeout_unit="ns")
83 | async def ModularAdderFlowTest(dut):
84 | await cocotb.start(Clock(dut.clk, 10, "ns").start())
85 |
86 | tester = ModularAdderFlowTester(dut)
87 | dut.io_input_valid.value = False
88 | for i in range(tester.opNum):
89 | exec(f"dut.io_input_payload_{i}.value = 0")
90 |
91 | await tester.reset_dut()
92 | await cocotb.start(tester.drive_input_ports())
93 | await cocotb.start(tester.monitor_output_ports())
94 |
95 | while True:
96 | await RisingEdge(dut.clk)
97 |
--------------------------------------------------------------------------------
/src/tests/ModMultiplierTester.py:
--------------------------------------------------------------------------------
1 | import cocotb
2 | import random
3 | from cocotb.clock import Clock
4 | from cocotb.result import TestSuccess
5 | from cocotb.triggers import RisingEdge
6 | from queue import Queue
7 | from poseidon_python import finite_field as ff
8 | from cocotb_test import simulator
9 |
10 | CASES_NUM = 3000 # the number of test cases
11 |
12 |
13 | class ModMultiplierTester:
14 | def __init__(self, target):
15 | self.dut = target
16 | self.ref_outputs = Queue(maxsize=5) # store reference results
17 |
18 | async def reset_dut(self):
19 | dut = self.dut
20 | dut.rst.value = 0
21 | await RisingEdge(dut.clk)
22 | dut.rst.value = 1
23 | for i in range(3):
24 | await RisingEdge(dut.clk)
25 |
26 | dut.rst.value = 0
27 |
28 | def get_random_values(self):
29 | rand_valid = random.random() > 0.3
30 | rand_op1 = ff.PrimeField(random.randint(0, ff.P - 1))
31 | rand_op2 = ff.PrimeField(random.randint(0, ff.P - 1))
32 | return rand_valid, rand_op1, rand_op2
33 |
34 | async def generate_input(self):
35 | """generate input signals"""
36 | dut = self.dut
37 | cases_count = 0
38 | while cases_count < CASES_NUM:
39 | valid, op1, op2 = self.get_random_values()
40 |
41 | # assign random values to dut io port
42 | dut.op_valid_i.value = valid
43 | dut.op1_i.value = op1.value
44 | dut.op2_i.value = op2.value
45 |
46 | await RisingEdge(dut.clk)
47 | if dut.op_valid_i.value & dut.op_ready_o.value:
48 | cases_count += 1
49 | self.ref_outputs.put(
50 | [op1.value, op2.value, op1.MonPro(op1.value, op2.value)]
51 | )
52 |
53 | dut.op_valid_i.value = False
54 |
55 | async def check_output(self):
56 | """check output signals"""
57 | dut = self.dut
58 | cases_count = 0
59 | while cases_count < CASES_NUM:
60 |
61 | ready = random.random() > 0.3
62 | dut.res_ready_i.value = ready
63 | await RisingEdge(dut.clk)
64 | if dut.res_ready_i.value & dut.res_valid_o.value == True:
65 | cases_count += 1
66 | op1, op2, ref_res = self.ref_outputs.get()
67 | dut_res = int(dut.res_o.value)
68 |
69 | assert (
70 | dut_res == ref_res
71 | ), "the result of {} MonPro {} is wrong \n ref:{} \n dut:{}".format(
72 | hex(op1), hex(op2), hex(ref_res), hex(dut_res)
73 | )
74 |
75 | raise TestSuccess(" pass {} test cases".format(CASES_NUM))
76 |
77 |
78 | @cocotb.test(timeout_time=300000, timeout_unit="ns")
79 | async def ModMultiplierTest(dut):
80 | await cocotb.start(Clock(dut.clk, 10, "ns").start())
81 |
82 | dut.op_valid_i.value = False
83 | dut.op1_i.value = 0
84 | dut.op2_i.value = 0
85 | dut.res_ready_i.value = False
86 |
87 | tester = ModMultiplierTester(dut)
88 | await tester.reset_dut()
89 | await cocotb.start(tester.generate_input())
90 | await cocotb.start(tester.check_output())
91 |
92 | while True:
93 | await RisingEdge(dut.clk)
94 |
95 |
96 | # pytest
97 | def test_ModMultiplier():
98 | simulator.run(
99 | verilog_sources=["../main/verilog/ModMultiplier.v"],
100 | toplevel="ModMultiplier",
101 | module="ModMultiplierTester",
102 | python_search="./src/reference_model/",
103 | )
104 |
--------------------------------------------------------------------------------
/run.sh:
--------------------------------------------------------------------------------
1 | #/bin/bash
2 |
3 | set -o errexit
4 | set -o nounset
5 | #set -o xtrace
6 |
7 | Components=("ModAdder" "ModMultiplier" "SBox5" "MDSMatrixMultiplier" "PoseidonThread" "MDSMatrixAdders" "AXI4StreamReceiver" "AXI4StreamTransmitter" "DataLoopbackBuffer" "PoseidonTopLevel" "PoseidonSerializer")
8 |
9 | # print help info
10 | function help()
11 | {
12 | echo "Usage of this shell script: "
13 | echo "run.sh [-a] [-h] [-l] [-e component]"
14 | echo "-a: Build and test all components in this project."
15 | echo "-e: Specify a component in the project to be built and tested."
16 | echo "-h: Show the usage info of this shell script."
17 | echo "-l: Show all components in this project."
18 | echo "-c: check format "
19 | echo "-f: fix format "
20 | }
21 |
22 | #show all components
23 | function show_all_components()
24 | {
25 | echo "All components in this project: "
26 | for i in ${Components[*]}
27 | do
28 | echo $i
29 | done
30 | }
31 |
32 |
33 | function build_and_test()
34 | {
35 | component=$1
36 | testbench="${component}Test"
37 | object="${component}Verilog"
38 |
39 | # build
40 | if [[ $component != ${Components[0]} && $component != ${Components[1]} ]]
41 | then
42 | echo -e "Building ${component} ... \n"
43 |
44 | docker run --rm -v $(pwd):$(pwd) -w $(pwd) -u root datenlord/spinal-cocotb:1.6.1 mill poseidon.runMain poseidon.${object}
45 | #docker exec -w /spinalworkspace/poseidon-spinal/ spinalhdl02 mill poseidon.runMain poseidon.${object}
46 | fi
47 |
48 | echo -e "Compile And Build ${component} successfully !!!\n"
49 | echo "Testing ${component} ... "
50 |
51 | # copy rom files to testbench file
52 | if [[ $component = ${Components[3]} || $component = ${Components[4]} || $component = ${Components[9]} ]]
53 | then
54 | mv ./src/main/verilog/*.bin ./src/tests/
55 | fi
56 |
57 | docker run --rm -v $(pwd):$(pwd) -w $(pwd)/src/tests/ -u root datenlord/spinal-cocotb:1.6.1 make DUT=${component}
58 | #docker exec -w /spinalworkspace/poseidon-spinal/src/tests/ spinalhdl02 make DUT=${component}
59 |
60 | rm -f ./src/tests/*.bin
61 | if [[ $component != ${Components[0]} && $component != ${Components[1]} ]]
62 | then
63 | rm -f ./src/main/verilog/"${component}.v"
64 | fi
65 | }
66 |
67 |
68 | # Check parameters
69 | while getopts "cfhlae:" opt
70 | do
71 | case $opt in
72 | c)
73 | docker run --rm -v $(pwd):$(pwd) -w $(pwd) -u root datenlord/spinal-cocotb:1.6.1 sh -c "mill poseidon.checkFormat && mill poseidon.fix --check"
74 | #docker exec -w /spinalworkspace/poseidon-spinal/ spinalhdl02 sh -c "mill poseidon.checkFormat && mill poseidon.fix --check"
75 | black --check $(find ./src -name "*.py")
76 | ;;
77 |
78 | f)
79 | docker run --rm -v $(pwd):$(pwd) -w $(pwd) -u root datenlord/spinal-cocotb:1.6.1 sh -c "mill mill.scalalib.scalafmt.ScalafmtModule/reformatAll __.sources && mill poseidon.fix"
80 | #docker exec -w /spinalworkspace/poseidon-spinal/ spinalhdl02 sh -c "mill mill.scalalib.scalafmt.ScalafmtModule/reformatAll __.sources && mill poseidon.fix"
81 | black $(find ./src -name "*.py")
82 | ;;
83 |
84 | h) help
85 | ;;
86 |
87 | l) show_all_components
88 | ;;
89 |
90 | e) build_and_test $OPTARG
91 | ;;
92 |
93 | a)
94 | for i in ${Components[*]};do
95 | build_and_test $i
96 | done
97 | ;;
98 |
99 | ?)
100 | echo "wrong option"
101 | exit 1
102 | ;;
103 | esac
104 |
105 | done
106 |
--------------------------------------------------------------------------------
/src/tests/MontgomeryMultFlowTester.py:
--------------------------------------------------------------------------------
1 | import cocotb
2 | import random
3 | from cocotb.clock import Clock
4 | from cocotb.result import TestSuccess
5 | from cocotb.triggers import RisingEdge
6 | from queue import Queue
7 | from poseidon_python import finite_field as ff
8 | from cocotb_test import simulator
9 |
10 | CASES_NUM = 2000 # the number of test cases
11 |
12 |
13 | class MontgomeryMultFlowTester:
14 | def __init__(self, target):
15 | self.dut = target
16 | self.ref_outputs = Queue(maxsize=150) # store reference results
17 |
18 | async def reset_dut(self):
19 | dut = self.dut
20 | dut.reset.value = 0
21 | await RisingEdge(dut.clk)
22 | dut.reset.value = 1
23 | for i in range(3):
24 | await RisingEdge(dut.clk)
25 |
26 | dut.reset.value = 0
27 |
28 | def get_random_values(self):
29 | rand_valid = True # random.random() > 0.3
30 | rand_op1 = ff.PrimeField(random.randint(0, ff.P - 1))
31 | rand_op2 = ff.PrimeField(random.randint(0, ff.P - 1))
32 | return rand_valid, rand_op1, rand_op2
33 |
34 | async def generate_input(self):
35 | """generate input signals"""
36 | dut = self.dut
37 | cases_count = 0
38 | while cases_count < CASES_NUM:
39 | valid, op1, op2 = self.get_random_values()
40 |
41 | # assign random values to dut io port
42 | dut.io_input_valid.value = valid
43 | dut.io_input_payload_op1.value = op1.value
44 | dut.io_input_payload_op2.value = op2.value
45 |
46 | await RisingEdge(dut.clk)
47 | if dut.io_input_valid.value:
48 | cases_count += 1
49 | self.ref_outputs.put(
50 | [op1.value, op2.value, op1.MonPro(op1.value, op2.value)]
51 | )
52 |
53 | dut.io_input_valid.value = False
54 |
55 | async def check_output(self):
56 | """check output signals"""
57 | dut = self.dut
58 | cases_count = 0
59 | while cases_count < CASES_NUM:
60 |
61 | ready = True # random.random() > 0.3
62 | await RisingEdge(dut.clk)
63 | if dut.io_output_valid.value == True:
64 | cases_count += 1
65 | op1, op2, ref_res = self.ref_outputs.get()
66 | dut_res = int(dut.io_output_payload_res.value)
67 |
68 | assert (
69 | dut_res == ref_res
70 | ), "the result of {} MonPro {} is wrong \n ref:{} \n dut:{}".format(
71 | hex(op1), hex(op2), hex(ref_res), hex(dut_res)
72 | )
73 |
74 | raise TestSuccess(" pass {} test cases".format(CASES_NUM))
75 |
76 |
77 | @cocotb.test(timeout_time=300000, timeout_unit="ns")
78 | async def MontMultiplierTest(dut):
79 | await cocotb.start(Clock(dut.clk, 10, "ns").start())
80 |
81 | dut.io_input_valid.value = False
82 | dut.io_input_payload_op1.value = 0
83 | dut.io_input_payload_op2.value = 0
84 |
85 | tester = MontgomeryMultFlowTester(dut)
86 | await tester.reset_dut()
87 | await cocotb.start(tester.generate_input())
88 | await cocotb.start(tester.check_output())
89 |
90 | while True:
91 | await RisingEdge(dut.clk)
92 |
93 |
94 | # pytest
95 | def test_MontMultiplierPiped():
96 | simulator.run(
97 | verilog_sources=[
98 | "../main/verilog/MontMultiplierPiped.v",
99 | "../main/verilog/MontMultiplierBasics.v",
100 | ],
101 | toplevel="MontMultiplierPiped",
102 | module="MontMultiplierPipedTester",
103 | python_search="./src/reference_model/",
104 | )
105 |
--------------------------------------------------------------------------------
/poseidon_constants/compressed_round_constants_ff/partial_round_constants_ff_3.txt:
--------------------------------------------------------------------------------
1 | 955a904fbfcb90fbc5defc5c7e2c54155cd6d72beae79db3270aeb7b2d94f2c
2 | 48f5beee5b2bdab502cc5b8c2ed81366933e432e83f45112b3c600d678069561
3 | 5e4d218e2cbf432276a71b1172e3e870bc72581a32e4cb320fbab29868befe
4 | 40786413d77419f01c1f4b55932d717d6dd60a3567f47a00f192f40a6de7145b
5 | 21053c08db804c9ed0850bbd5200bc4cb4e51b9ccf99a93b97568646c2f5a9f2
6 | 696dcdc86c83f99b7ab110a0363b3e3be6ba21155fba71a5e33c6a07000694da
7 | 79e5780173271b97ad33f244e58cf742033f30121bb07a768eb1660c943a8cb
8 | 2ae60b92394ee0af5bcf1b75334c09b42b141c597f98f6ccee459235b5e7089d
9 | 6ca1fe4acfb19a5bc717c9dba926361ae42dc45ce97502696bd4c7dc43dd73e2
10 | 3213b3fa85b5ecda7f7a545e795072a3ccb959e291cedf0a44b4c0f3c3b3e539
11 | 1ae21be5ce235400a519d058a42cba01dbcfa358bd9f184609798ec6a14d217a
12 | 2e0d7726f80fb61131c55f1c9716450bc693731219d48bfc23c750fa2d8d28a1
13 | 181b74f358c9e32cfd1f921edd308e6a7fdb7c134231a08a820560707ea741ad
14 | 60719327c018006c11add949b16ac05bdda8bbd024ca707d8f3dbd3561c84ee9
15 | 2a278c8df95f69d8a3e968c60b5272cc0618b2b67efc17f938c3b7c49c9d2a8
16 | b4820817e915168634f8adaf951f93cfd2d51996c9090050c3e1c16537432e2
17 | 463dfbe202dd6fe926bd3e67dc0e0819ce260112368084f23447e04fb812d49a
18 | 8e354ca57e78ee68ab9521c305d8a0c34ccdbded694b9e1f87ee0d9e01aca4e
19 | 5f0fe54b3ba4666e107322d50c08af509f062c46cf86264edb4ba5221412ae94
20 | 6414ea3cce47f294c4ef7587a070b7fd577faf359c64f44190e5c7c5d11c0582
21 | 17f8d17b6f8a1a89bd02f67dc8be4f78356d12a3769c6d277127a0c3bb978d48
22 | 1b64219f9c0bbcda51ca7f66c7ce4359dc57157a2831146ca3ca2266320004b6
23 | 10c0b3db7560da95d001063291d42a2715ea388788faf42d2832105acaaf128c
24 | 197aaac31652ed74fb001ff6203bb5eae7ca7c5069b7fb11514dd01cda3bcfba
25 | 38db32f5eea5fa8059d6e14534b4a7d7c06a3c6b4b93b7ba0519c9abb7a6fa36
26 | 34486da53591db38d19727c8ed2d7d4ea3077f27b533b7e629f26572656a8b08
27 | 24a138017e08c10f603a428b172054211ea417fea26618521c0aa85514af00e3
28 | 4d307087ecc872c0d08c5e961a8fa958cb35bb1067242fb2a91687266d874347
29 | dcf58841afa7f5546ba57793eb05ac1e6b6de63628554a45f1bb36c5e2a1827
30 | 55fa9a0dba68e0a58207cddb42ff6a5d85a05677fe2b8bc2a12f1024bf6c96e5
31 | 7326ff2dcf3c878ecfd6d20491fa3d963cfe5e7bcd013806ec6556cef7c925e1
32 | 5e60fe3c2bea6ca8efadc4b05e47876297e63a714f2e13f62937f7282c3a87dd
33 | 5c5f684f78c673743fcdfbef6a307d255de584513584aa761430fdc74d7b0ea3
34 | 21639f6b8a8979ed5f546bb8cd0f7b9bbaf33d3e65fd6a3518ddae6fb61d4dd5
35 | 681903730747e00f2cc1958eddb0ebb0bd9a38a8468890a40e91f250640324b4
36 | 4fd7686552c2706f5b6007b1155fc62ae6c0664cc9630d2c81e3c47f0fdb7918
37 | c36c60cf0bb29cd26509015a7e00681e698b79349aba3ff5e49924ff37d1138
38 | 487a6367936f46b7a017c850f166c30b6841bd1e96446da4d6dda0af276a82ad
39 | 36fb0be312dd473fc81b749586ecc089a940ce532efb5c1f92ed3f92ffdfee95
40 | 37963b1d7716c1fdde3829102d8f7a93ea75b4747573c9cee5a8514792db59ef
41 | 82045aa3c764242d6201cd77ddb4c9c03a217bba94eaa40a051faf3ebfe3cca
42 | 118af6e575fa8a991e7cbbd42ce8d65132d0d4ec3ee48d7ec6e45434ce32ee3f
43 | 5d08bf87451c7afff5ea4367a7fef5fc820d9f82c14c1f7045e734f865d9619e
44 | 214218ce6c8049edea3ee22f6aaf01892cb586efdd0591f73c3f44281fe9bf6b
45 | 4b29ac56af22e18d40926457dab5aee6f5f9598ea7f0db53bc4e4a94e04f09a8
46 | 4d713a79af265adb3877b938b0ae7fd4ad76a6960e8c6f42155106254ed8516c
47 | 4e1c057b8dfb64842ba0de58a05289e0b20780457c1a34ec9652b6dbce0d83dd
48 | 36f88372c009fc993286d7f40257fc161b060b4a1ca4983b69036e305f87d5bc
49 | 50561122dcb9a342cdbc32fb0298da4a6d2923203522169f7b6a3c46293d54ac
50 | 73b7860fa6379af73e718277865a3e8d5111532cfb347b625ba5e04b92ad38d7
51 | 20056b9fb801dc442db53edcb050696499c7da58d2a653874788912123895022
52 | 268ec8894792136915e0adc539329abf24c767ee2295f5df55571a426453b6c5
53 | 4e2bd85efc52310851b742c56db7de3ef4cf316a37b54721eb72acc533ecf1a2
54 | 4175e26538109ede0800400ba6624b219a042735d6353edae1c7d5464ad1bbd7
55 | 23e1291393686042f4dd157fb3c49cdf24c7307f66437989d0ec7a3fb1a49462
56 |
--------------------------------------------------------------------------------
/poseidon_constants/compressed_round_constants_ff/partial_round_constants_ff_5.txt:
--------------------------------------------------------------------------------
1 | 4597c2d5e03e62d3de6b94c51cc6e2f7f0363b0e12f1786681f928e3db1913af
2 | 5d71428fdf05feb52ab1608cd6f5e16328c4077d48b60874a816abe2988b5914
3 | 3862339cef3f4db32ce67758e7377cb7c8d27ef2fc538e7007655c5d6fe32425
4 | b81fb35752a40ad12234eba5807eaecfb79d76992c0e628186bc66979454c85
5 | 5d30719d092fa3418884208726c62aca9ae9775ca05941aca20500230a89c43d
6 | 4fed9ae55f5cc41e3b53663bf560a30e1f573245dbcc8e60fcd1afe1e4b1a7be
7 | 1e5b8b83b9a542b6e410381ff5ce8c263b86b1e9645f63807a1a23a4c10f420b
8 | 2ff1c36c1fb11479f5fde194d0ff0330f88c2a9824f96238b7673ec6bc4274e0
9 | 16ba36d8d69190005c7d0a7fd56d1296a798cb33fbb7546d9d55ebc6811294da
10 | 459fb246e293148529adc6af0e7437222411036404d1738abd6c77b04ed85d7
11 | 41b0fb1940ec289c59250f061931bce62b6693bf2781bf67bd65620996c91ac0
12 | 5360e84beeb42d5f3c9aa86d70d68392aaaa5879ac7fa63dc4ad7ef4708ed9f2
13 | 2afd930d397906bb10c5d03c28ca848e83ae636bada15d5e613298b917a429ec
14 | 5874df8d5d1fd55cc73bb91037fb5b9763045c8ebebceec0a222b6acb4563dde
15 | 5931eb7da15904697c167ae1b7cd4286399976ffee6a2ea8a71b99e3dc735807
16 | c7dceaff1904c70a941d4d2de10863f8c3a2544be24d6f2119edaea9f361974
17 | 263c9da675c9422120f722f46951846ec1f02e9aef10697fdc032cbd56dc83b3
18 | 242b82b2e7bf7b9b76ffecb1ff97eea1d3f3678ae85358b5fe94aa89932497ac
19 | 64eb9e39284964db76e4e17a787358f089e5e1a2fa6579183237cb0d93c86e22
20 | 1d1262ce8246e4bcc1aefa1c6bfca1d0ec43082a46fb3ea78f188b2b206a06a1
21 | 4765cccc0995c0b682504648d135107fc1785acccc713c5dbccb53a92ed15f33
22 | 466c13d260fd8b9930e655554cc29c2ee7bcf3116902a8429a1d2b461e11b9c
23 | f70d9d2e33b41375d443de27337e5e7c6472a74301e2d9d7963de1b71686d6f
24 | 685899a3f56f1a5e5cf0135f77909d7c40ef768d288438b69ca6e00347ada9da
25 | 1b7f5e8164db7831fa3ce721522931db555d746891b9a7a4ef88308625da0fe1
26 | 5c150bb6c1b1796b49980974d67028230be283db4c6631b6bb132518dc794737
27 | 16a801e2ca1bec16b089498c9992d3cb4c7d8bb9a0f8956165ffe9de4ef05eac
28 | 440d74e3d73be2a9c2a5721680b983fc52df6c9b486053feb3d3016ec90be2c
29 | 506893e963ef99fa7cd8187e4568c91a044fb5287f397151df461353a29ba615
30 | 6161a3b78b558aa7c77a19bd48d17a29ac67099939c436a88a1686e33068254b
31 | 5781b50088d9b37a391f7f46e6b6174dce8659ac792dc79e205b27abc74be705
32 | 1b8bf1984ecf01afd18b0bbf0413ceba2f396c82495b4957503182bc6489d9c5
33 | 2a0391b30c3cc24ee2e39a25b4b620d9a5f7941db46b864c992fe097694d4d0a
34 | 2dc377e3d7ad99380aca44d812385100fe78ff324ba6d7fc0e67a921303d2f28
35 | 6b0971e4d13b1b2ae338c539d9acc17ff46cf9fd2b677b4390ff1a6fc2d66e2e
36 | 716a10a5be411170fddffcd38ead5a31da5749b7a87e86573e240f325c9b7b58
37 | 775c3d9313c3ebc5f7f952f92fab7b6edc9aa6625498311b2c1fa6a82657ea2
38 | 5b6af24ab6887233a3efc2e60691056acf03c93b79ec1804f60e2d293357b0aa
39 | 854dc9133532560238a22c7baaa7f1ed55a5aedc5c12dc08c1efe571f35ea34
40 | 23d5a01086d25d2575956bee3c94b4a8d064aa6da247cb15f2b3f8bb4cb742c7
41 | 2994ae1dcfbb7e488146247f0f7952482a1b84458b14a4e2c88dcd78ef8e8a41
42 | 6d46cd37f4f25ca74c96e50bb05f76369feb42b972d577e751b9c6a29d07c17a
43 | 3db6370ce200cdb3200475d68b91c405548eca1fe47ef8195c399e3f8dafd570
44 | 232a6740632f35ec289f560fb28dc6eeb5b47171bf4a0bde512bbe501beb9633
45 | 4394d1b3ca5be52f54d39bb6bc2bda6819cb350346960f7f79c97d7bcd149c7f
46 | 2bd3af22c1fdfe91cac8a70bbf722793c3d6e7c253952325d7936bedb1186278
47 | 315acb8b0bdbe947f0ceed16b7290dcefdd615eca041fa08327489483312c484
48 | 6c4d05497adf2263a2a1bee5e72979d171597c6a7799350a947da2fed08d50f0
49 | 10c01c28a57da7a9cadc9c4786d1bf6fb77a76ed693920b9919c890a4a6a077d
50 | bf150f7e34b02ad721a13430fa914fab956cf66adbf94b035f4d040699820f8
51 | 6000793141b303a6d7947994fcb43c19487456a795716dece4fda88fcbbfc202
52 | 104f6a328d08fd372b3eff88d3cecb804ca4226adde0d8d57bf9157c0d5d38c7
53 | 6327fa5e0e5291fac88e8a9f9a4abfdbb2518580227e8094e47a0158baf2b790
54 | 56cd2a9097b7a8fcd426bfe372ae3a783ad42da2ddc5abc1f9c8b1a7e777029a
55 | e36dd3da1e795fd26da550df4238007d905a43b02659321fa1be93d86e68a4
56 | 6b212c40afd2dedc10d055d9c48275aa7ad9a5220a964d48074a093c6375d3bc
57 |
--------------------------------------------------------------------------------
/src/main/verilog/ModMultiplier.v:
--------------------------------------------------------------------------------
1 |
2 | module ModMultiplier #(
3 | // the width of modulus
4 | parameter DATA_WIDTH = 255,
5 | // the modulus of ModMultiplier
6 | parameter MODULUS = 255'h73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001,
7 | // the inverse of modulus (mod R) R = exp(2,DATA_WIDTH)
8 | parameter M_INVERSE = 255'h3d443ab0d7bf2839181b2c170004ec0653ba5bfffffe5bfdfffffffeffffffff,
9 | // R = exp(2, DATA_WIDTH) MOD_COMPENSATION = R - MODULUS
10 | parameter MOD_COMPENSATION = 255'hc1258acd66282b7ccc627f7f65e27faac425bfd0001a40100000000ffffffff
11 |
12 | )(
13 | input wire clk,
14 | input wire rst,
15 |
16 | input wire op_valid_i,
17 | output wire op_ready_o,
18 |
19 | input wire [DATA_WIDTH-1:0] op1_i,
20 | input wire [DATA_WIDTH-1:0] op2_i,
21 |
22 | output wire res_valid_o,
23 | input wire res_ready_i,
24 | output wire [DATA_WIDTH-1:0] res_o
25 | );
26 |
27 | parameter IDLE = 2'b00, MUL_T = 2'b01, MUL_M = 2'b10, MUL_U = 2'b11;
28 | reg [1:0] state, next_state;
29 |
30 | // generate next state
31 | wire op_handshake = op_valid_i && op_ready_o;
32 | wire res_handshake = res_valid_o && res_ready_i;
33 | always @(*) begin
34 | case (state)
35 | IDLE : next_state = op_handshake ? MUL_T : IDLE;
36 | MUL_T: next_state = MUL_M;
37 | MUL_M: next_state = MUL_U;
38 | MUL_U: next_state = !res_handshake ? MUL_U :
39 | op_handshake ? MUL_T :
40 | IDLE ;
41 | endcase
42 | end
43 |
44 | // state transistion
45 | always @(posedge clk) begin
46 | if(rst) begin
47 | state <= IDLE;
48 | end
49 | else begin
50 | state <= next_state;
51 | end
52 | end
53 |
54 | // generate output signals
55 | assign op_ready_o = (state == IDLE) || ((state == MUL_U) && res_handshake);
56 | assign res_valid_o = state == MUL_U;
57 |
58 |
59 | // DATA_WIDTH bits * DATA_WIDTH bits multiplier
60 | wire [DATA_WIDTH-1 :0] mul_operand1, mul_operand2;
61 | wire [2*DATA_WIDTH-1:0] mul_res = mul_operand1 * mul_operand2;
62 | reg [2*DATA_WIDTH-1:0] op1_mul_op2 , mul_res_tmp;
63 |
64 | assign mul_operand1 = (state == MUL_T) ? op1_mul_op2[DATA_WIDTH-1:0] :
65 | (state == MUL_M) ? mul_res_tmp[DATA_WIDTH-1:0] :
66 | op1_i ;
67 | assign mul_operand2 = (state == MUL_T) ? M_INVERSE :
68 | (state == MUL_M) ? MODULUS :
69 | op2_i ;
70 |
71 | always @(posedge clk) begin
72 | if(rst) begin
73 | op1_mul_op2 <= 0;
74 | end
75 | else if(op_handshake)begin
76 | op1_mul_op2 <= mul_res;
77 | end
78 | end
79 |
80 | always @(posedge clk) begin
81 | if(rst) begin
82 | mul_res_tmp <= 0;
83 | end
84 | else if(state == MUL_T || state == MUL_M) begin
85 | mul_res_tmp <= mul_res;
86 | end
87 | end
88 |
89 | // (op1_mul_op2 + t_mul_inverse ) >> DATA_WIDTH mod MODULUS
90 | wire [2*DATA_WIDTH-1:0] res1;
91 | wire [ DATA_WIDTH-1:0] res2;
92 | wire carry1,carry2;
93 | assign {carry1 , res1} = op1_mul_op2 + mul_res_tmp;
94 | assign {carry2 , res2} = res1[2*DATA_WIDTH-1: DATA_WIDTH] + MOD_COMPENSATION;
95 | assign res_o = (carry1 || carry2) ? res2 : res1[2*DATA_WIDTH-1: DATA_WIDTH];
96 |
97 | wire [2*DATA_WIDTH:0] mediate_res = {carry1,res1};
98 |
99 | // Dump waves
100 | initial begin
101 | $dumpfile("dump.vcd");
102 | $dumpvars(1, ModMultiplier);
103 | end
104 |
105 |
106 | endmodule
--------------------------------------------------------------------------------
/src/tests/MontMultiplierPipedTester.py:
--------------------------------------------------------------------------------
1 | import cocotb
2 | import random
3 | from cocotb.clock import Clock
4 | from cocotb.result import TestSuccess
5 | from cocotb.triggers import RisingEdge
6 | from queue import Queue
7 | from poseidon_python import finite_field as ff
8 | from cocotb_test import simulator
9 |
10 | CASES_NUM = 2000 # the number of test cases
11 |
12 |
13 | class MontMultiplierPipedTester:
14 | def __init__(self, target):
15 | self.dut = target
16 | self.ref_outputs = Queue(maxsize=150) # store reference results
17 |
18 | async def reset_dut(self):
19 | dut = self.dut
20 | dut.reset.value = 0
21 | await RisingEdge(dut.clk)
22 | dut.reset.value = 1
23 | for i in range(3):
24 | await RisingEdge(dut.clk)
25 |
26 | dut.reset.value = 0
27 |
28 | def get_random_values(self):
29 | rand_valid = True # random.random() > 0.3
30 | rand_op1 = ff.PrimeField(random.randint(0, ff.P - 1))
31 | rand_op2 = ff.PrimeField(random.randint(0, ff.P - 1))
32 | return rand_valid, rand_op1, rand_op2
33 |
34 | async def generate_input(self):
35 | """generate input signals"""
36 | dut = self.dut
37 | cases_count = 0
38 | while cases_count < CASES_NUM:
39 | valid, op1, op2 = self.get_random_values()
40 |
41 | # assign random values to dut io port
42 | dut.io_input_valid.value = valid
43 | dut.io_input_payload_op1.value = op1.value
44 | dut.io_input_payload_op2.value = op2.value
45 |
46 | await RisingEdge(dut.clk)
47 | if dut.io_input_valid.value & dut.io_input_ready.value:
48 | cases_count += 1
49 | self.ref_outputs.put(
50 | [op1.value, op2.value, op1.MonPro(op1.value, op2.value)]
51 | )
52 |
53 | dut.io_input_valid.value = False
54 |
55 | async def check_output(self):
56 | """check output signals"""
57 | dut = self.dut
58 | cases_count = 0
59 | while cases_count < CASES_NUM:
60 |
61 | ready = True # random.random() > 0.3
62 | dut.io_output_ready.value = ready
63 | await RisingEdge(dut.clk)
64 | if dut.io_output_ready.value & dut.io_output_valid.value == True:
65 | cases_count += 1
66 | op1, op2, ref_res = self.ref_outputs.get()
67 | dut_res = int(dut.io_output_payload_res.value)
68 |
69 | assert (
70 | dut_res == ref_res
71 | ), "the result of {} MonPro {} is wrong \n ref:{} \n dut:{}".format(
72 | hex(op1), hex(op2), hex(ref_res), hex(dut_res)
73 | )
74 |
75 | raise TestSuccess(" pass {} test cases".format(CASES_NUM))
76 |
77 |
78 | @cocotb.test(timeout_time=300000, timeout_unit="ns")
79 | async def MontMultiplierTest(dut):
80 | await cocotb.start(Clock(dut.clk, 10, "ns").start())
81 |
82 | dut.io_input_valid.value = False
83 | dut.io_input_payload_op1.value = 0
84 | dut.io_input_payload_op2.value = 0
85 | dut.io_output_ready.value = False
86 |
87 | tester = MontMultiplierPipedTester(dut)
88 | await tester.reset_dut()
89 | await cocotb.start(tester.generate_input())
90 | await cocotb.start(tester.check_output())
91 |
92 | while True:
93 | await RisingEdge(dut.clk)
94 |
95 |
96 | # pytest
97 | def test_MontMultiplierPiped():
98 | simulator.run(
99 | verilog_sources=[
100 | "../main/verilog/MontMultiplierPiped.v",
101 | "../main/verilog/MontMultiplierBasics.v",
102 | ],
103 | toplevel="MontMultiplierPiped",
104 | module="MontMultiplierPipedTester",
105 | python_search="./src/reference_model/",
106 | )
107 |
--------------------------------------------------------------------------------
/poseidon_constants/compressed_round_constants_ff/partial_round_constants_ff_9.txt:
--------------------------------------------------------------------------------
1 | 719c547de433d29c2aa6ad9d6e80a0fb16f32ef0f3197d50442ed24d7d035b70
2 | 5364827a40445fd4cf9d227c5898b763978e94be3b319525893f6a6bb0bd38de
3 | 4a64656d98a5d828986a903f37061bd238245a89ebc33130b91bffc36c4e9743
4 | 5c91def5f9e7061af94d64da1cba47135262cb105422e7bf1e3964ff5b21f10a
5 | 32380af6895cd3c5dc99af8da929f40d5f876296c1ec8bc96c8d608416fd1cdd
6 | 54f630a63e7adad91b63c8c5f588c12d4bb232874c7546f5cf447dd7578e38a1
7 | 9836e5deed44fe15ff8b65bee710dd4840e211e32eea5edcaa9f55b167d0d90
8 | 726652dd154ccfe23dd206f78b2daae991ac284007c172f4d4b89b9b1adb4098
9 | 7343f3b646888d89671fe764a77b6799b99359307ee583be10b4bf4c1646bab0
10 | 3c992dfe1c2cb83856467ebf83426286b7ae65e6336ae3c91ff1d398ae0de67
11 | 1c0eb0a1eb09022e5882d04f17b58d665fcca167bf926683eb8b0200d51d1d61
12 | 5b78b552b150025bf4dc5f74f7187bb95f1c625216408aac36b25f93aac824ad
13 | 409d072638627609c116075527e3021e35e2f7a45a72c89ccfdb0f3ce8ac1dd0
14 | f58b72cdef8c4f7da9b732e6e67fe6991e3b248e5114b8d7c3a48b87215230d
15 | 18d6ed4cb9bd646d0f01fdaa90e044ad44122c4d33cdca2f355397a386deda10
16 | 28327d51f6723b41923a154f3647362ce549ace26c29ba658dc00c22c7265e5a
17 | 278d6a97675fd062938bd33df3c17f2eac780af52e14e068c7f906adc777da1c
18 | 6853c380081f1de555ddd016eb9449723578397bc342a5a1ab50deeff2e6666f
19 | 43901fad86a42bbdfc03a5380496b1ae2dbcc848218c9df3e9a89c86ffcfd706
20 | 2fdf2d02ba2614843da21bc7d15751e1e14c7e8939f060e8a77544898a964787
21 | 4919468964d0adfe78b0b03874005c682514a271964005477ffe51cddae33fe1
22 | bed0481c1d3a1cfa93a234548d236f07eb9974f4fc118a427a4906e15bff10b
23 | b1f43ebce8274c63b498e9afb08d7db5d6c461dec6ef7c430bd8a70325e1a5b
24 | 166bc3586286bc195d562323ccb3f2767464fd4adf17b145428d56d1a3ebcdbd
25 | 682c01c08691ca5398e21766de998908d97cd2693488b2dc77dd98fa93ded68d
26 | 55e3675cbde7b7f54a8542889e7e08c69b73f929833e99d2f8eafec229aef400
27 | 6c0cf0f6608d9dec58faaa544dae05cb9e4e8b551757e37b060be016f4e04f28
28 | 44db06be530ddf5fd0c7617d941532b0e18760fc527c80bb7b35c8bcba79f102
29 | 64228dc41a1daa01d70310233b00fe449382f29f034efe1dd1d270b8dd5d4e2c
30 | 3e23f72361d9564ee642fa245bacd1ad5c2fec3353bda0126d39eb87848b7693
31 | 5113fbb31d3a7b50ad7563dfd9180253982d04b77ba0d270368de730f1c2d142
32 | 2ca9282e5e798ccc5c46aa9a27c5c63d1c82adcec28afa87c2def9debbfb0423
33 | e816050f009975e9b5c5a761b66f6897952690276fd05815dadbe91113b3f2f
34 | 40e1ed7492a10495b5f3443153887f2f1e920196016bd50415fe657fbd445090
35 | 4ec0186bf9baba76703ea27f4fc06ad1c08b181bc62a49ca0b7bbf151df66de
36 | 23c5d71ec7f1f19638fce402907c5643e29cb5098f0fa87b58850675fb6d7bd8
37 | 50f7d37aeee78a630aecc3cc5017a812943e903205209696107599496e3bff23
38 | 21e421bc6c570eb53a56a45c4ada293fefe3ed0f115263bf502981cf8d6a64fd
39 | 368ae1626461f6d9a5a35888060d38e61498d047da74b55f3134f65363989975
40 | 412c09ebef9a00dde8facc0fdcc2f89fec4a877001a22d35cabf975136c304de
41 | 1cf89973996e33a5432b15595ee19cf2f50ba4facc15b5a49162285784517a31
42 | 1be13383c54535d3431242bc2d4cee22b109d9d8d80df846b891604de2a69f0f
43 | 275c1332218c4221e3cd1382f4580c3740c4d64fc475e51dd533eb828c711955
44 | 44cbb1b0e2d216081aa33593d10ea35a89091e201cef6b243dffe9a3a9cc6d2a
45 | 6d87561e194eb0aa03d8c86b2b3638ea099216e25dac662209ea098177a1f012
46 | 5548a2cb6494202dc9ccd53c28a646e380f33a77bb27acdd409a2a608c0bcf31
47 | afd0c8d17c218fa0f606909a6f6b9ae50b097acbfa9e3ad981b87b7df5d50cc
48 | 57222e019a99df6e8b86c1b64388ce068d0e01d9cce358f678da35dfe86639a1
49 | 3f8bec0774d7dd76f945e363e04bac528631708c620c374821924216112283cc
50 | 4aa90213015df3c5a3de82935129270a95c3cc0abf37d81501e98db745d7cf27
51 | 3839dfcfc80a2d9c3ffd971c75c52ff2fda7ce7b03b7d105d9ca5ffdec654241
52 | f2b3adfb545911a3f459506fb4cd03607d6082726e8fe24e521e3836f02f4b1
53 | 2d9efdd3811a9cb5d04c7e2fca02988e5021d03fa91bb6ded940caae7955e54b
54 | 5f259c25fb57b0cb9f13c32e3c5010d6d36d69c14dfe7f9fbeb04b1d9504884f
55 | 5acafa8f5c9e614f236eb89ea6682ffd819bbe5cc61430dc5140afbcb91cf4ad
56 | 3d12c6e84485a1f8019ffa5efacc5f2bf90b775697c443b8396f6c2862b13941
57 | 581f16e55cdfa35319dd21a68aeb6c0ea3b2423e6dfbdfda00e331dad3285027
58 |
--------------------------------------------------------------------------------
/poseidon_constants/compressed_round_constants_ff/partial_round_constants_ff_12.txt:
--------------------------------------------------------------------------------
1 | 61ddbd21aa3cdf60f8db05bdee3a2270738e9b1f8233d80246ab0d8ff64b9ae6
2 | 3d28bbbe6a5d5f27d1036aa42a4f08bee0107d3d714d9c299419bbbd33e913db
3 | 39899330c9a40e0b903eaa430bf4941e82ee5aa3a0ea91f07952fcce3bd19d34
4 | 366b123e3d009276b1d843f4e7c56bc8868326c2d705ab0dc7fa011f0beaa92f
5 | 3bc0dfe7e55ddb0d5c59e4e91394e9ed01ea7126a450fbdc5ed09de7e3999523
6 | 1a01537b2edec1b6866842e5aca0fd6036611a188c4b234bb25a66589d1aacd9
7 | 5bdbedf19519efc31383e5b7bdc2b2e43a8c9319943132f71c0704b5f20b5333
8 | 49c4a7264eff8c8a35b5566a432f3c878aea939774d5331beb19873433ff5958
9 | 6e76c43ce3e34074519ecc717f44cfa4b9904d9336af969d622f45ef3b6c7ea8
10 | 6c089cf205db963adeda7f87439955a53cfa2e1d04ca2a76f175565217e90264
11 | 53dcab90596ec843142185dda9bca22d9560df65d6d25cceb7fc30347c8f5c73
12 | 37ec57a1b4a47f75f2116dd47b888c13542168dc9ebdf3a4f328b9bcb287e4d
13 | 1186f410ffdfa0d4976ebc0a580107be377ab9ecc210a85d9881c3f64974d0a6
14 | 5d07a354e5ca8788127994b6201c9a2456b5bbbcd04f1fc37dfeee072a67d887
15 | f68a6d19696c4d1c9f0b4149dab96b18e061f651ba3f30554d31f32671ac438
16 | 1f8a70d0a5ac286cdbe0f4df7cd134ac27d17873dcfad2753c9087852b396e4
17 | 6dab0c6c36dabb98b0d0843e25023ab59469dd99d413f13d19286a7126394e97
18 | 3426f66a0ded8fbeaa176c5720b13e79c06a8520ad9c4f144c2e39e82f2a3776
19 | 2a5002dd7dd294a70c840e4ac359acf9ca296f0c3c5ba1b65077e17b955b9205
20 | 1897c311109acfc300dbb0eeccb7c4c571d84e8c989161a3ed94442deb1fcbd7
21 | bee4ca4bfa1aa02c474d7ae19ea04f5b89aaa7f42c184ea96f2131d35afa360
22 | 4fc8c2b7c94170a43056b066c48c70a15da307c534f8bcefcbc9a8e8ce7adce4
23 | 69878703e3ad4df912cae7ebbb8e04a7d37a8cf90ad4a7fbc05019aebea7f4b7
24 | 50650c96e3514d7bca9b9ca6d0ef92de44bd3e564edae4c2da2caabac6f930aa
25 | 343e7206996630a936aed8295150695c9fa21e2ae48e2489e350bed59aeed90a
26 | 71fd75fe89872cdb69151a1f5d26537e6105162c0dd84abf75136495cf25912b
27 | 41fd9f218d0061418d17b1762d562465284070d8add6e161f0e54549d4981d35
28 | 5afef959754485e1953640ef55945748e2539aa33a368aad26ffd9786af9394c
29 | 2c1a2004be2e92bb3a334ab7479fdf77aeae26aad699d6d3cf767eaeecc91fd9
30 | 5732893412d50959c8f56d731f00bbf313c18c693f87f3a513ef9311faaf5c96
31 | 337de782119e1928eb44f40de52c719c9723d939d4e0c91dc74cf253b3b2b9eb
32 | 4cd303643ea2530f2fc0f00a660654daaad9386bca098e75759fd121eb003922
33 | 21e75a288129097d11568099d4d75bcbbca53a1e2c8fe8ad6121b82deed4475e
34 | 350580ff40b1a560057c876f70cbb5b4cee6169429af76ba32b201ed9034ff41
35 | 5ba3bfca86781caea27395021aff7619922741afeadd381908382dc1cf3a201b
36 | 224f10dc5a9e59329be2fe0e57ba3dba53e8148fb143511b8e45e18553dcff80
37 | 108f95df62fc095442bc17c8eefd2dab965c85e314309b212d7dfe1aa7d58f47
38 | 44ef434d0ee752fc6eb1e3ee1d35415272b8547fda5d1b11ec816b8d179e8f23
39 | 5ecbce3cfa879f1e3463ae780f577aa6f7ef8406777af2af4fc83ba504d3fa91
40 | 6181c724431ea1591283191d96d0bfc409f008def9ee5dac77e362d27d50dc96
41 | 6cdee21312112696fb9815b2af5196a578424707e3fd622449ef24c8e269b1d3
42 | 33f75fbee6faaec4c017e01666e82c41d14caf3c13eb047cea2afa40f65cacd5
43 | 6f7e6ac9be53cc01f4a27c47418029d2356f0f0b1dd49a231577594af1cd914d
44 | 1637226aee56fcb110a7c56a5c08d94a1e509483900129d7af581cb99fb690ad
45 | 52c17e35ef264a191039b4adcda8b6ae71127d135428906cc0cadceae2010e24
46 | 1951f367c0d8425fbf2e1223608a9647725919f5423a0256f0cfc274f94c2b22
47 | 21c39ab35355280b42d7c04613362cb2e8e174cd04e442c05158106cb86d5372
48 | 2a72d3b6a083d157ea501dc797f5a2eb3353845aa722dc4c5c251cef0186550
49 | 6e45cbb08375c1377dc4fcde17aa183f7fb33851ba6b660b07d7aee44934415c
50 | 21f57fbe766addd5fbcb66e39b3ba311da4b03a35219030033a9b419f8445b96
51 | 2318c472d8c802c15d668d800f43cfc479a6830c6b2d82c7732ca497f209a11e
52 | 596972f4da5a229801a42837661ab63c0485bef98312a90570df72d902190584
53 | 2b4bc4cfc6e1b9d4910482c0de050cf42806d3b9d83940e8d93f0b27abb2c1a
54 | 2a9a3184aa49ba84200bfff22bce8bd0336eaba598c61fc5e050565e6718f390
55 | 64d8caebd3302ee45d49f2a7dbdc40c5d70105649d6714216d862ccf90ff5e4a
56 | 1cbdf93c411d6a4aea04b0fc1eb2b1c7b0aa3cf0335430a34614fbff8a5bd71b
57 | f6bf8b42ad4f9f22cd37279f26c5f8852f650a34dda16facea181c8db9bd59d
58 |
--------------------------------------------------------------------------------
/src/main/scala/poseidon/PoseidonSerializer.scala:
--------------------------------------------------------------------------------
1 | package poseidon
2 |
3 | import spinal.core._
4 | import spinal.lib._
5 | import spinal.lib.fsm._
6 |
7 | object PoseidonSerializer {
8 | def apply(g: PoseidonGenerics, input: Stream[MDSContext]): Stream[Context] = {
9 | val serializerInst = PoseidonSerializer(g)
10 | serializerInst.io.input << input
11 | serializerInst.io.output
12 | }
13 | }
14 |
15 | case class PoseidonSerializer(g: PoseidonGenerics) extends Component {
16 |
17 | val io = new Bundle {
18 | val input = slave Stream (MDSContext(g))
19 | val output = master Stream (new Context(g))
20 | }
21 |
22 | val buffer = Reg(MDSContext(g))
23 | buffer.isFull init (False)
24 | buffer.fullRound init (0)
25 | buffer.partialRound init (0)
26 | buffer.stateSize init (0)
27 | buffer.stateID init (0)
28 | buffer.stateElements.foreach(_ init (0))
29 |
30 | val fsm = new StateMachine {
31 | val counter = Reg(UInt(log2Up(g.sizeMax) bits)) init (0)
32 |
33 | val IDLE = new State with EntryPoint
34 | val FULL = new State
35 | val PARTIAL = new State
36 | val LAST = new State
37 |
38 | // set default value
39 | io.input.ready := False
40 |
41 | io.output.valid := False
42 | io.output.isFull := buffer.isFull
43 | io.output.fullRound := buffer.fullRound
44 | io.output.partialRound := buffer.partialRound
45 | io.output.stateIndex := counter
46 | io.output.stateSize := buffer.stateSize
47 | io.output.stateID := buffer.stateID
48 | io.output.stateElement := buffer.stateElements(counter)
49 | io.output.stateElements.foreach(_ := 0)
50 |
51 | IDLE
52 | .whenIsActive {
53 | io.input.ready := True
54 | when(io.input.fire) {
55 | buffer := io.input.payload
56 | when(io.input.isFull) {
57 | goto(FULL)
58 | } otherwise {
59 | when(io.input.stateSize < 9) {
60 | goto(LAST)
61 | } otherwise {
62 | goto(PARTIAL)
63 | }
64 | }
65 | }
66 | }
67 |
68 | FULL
69 | .whenIsActive {
70 | io.output.valid := True
71 | when(io.output.fire) {
72 | counter := counter + 1
73 | when(counter === buffer.stateSize - 2) { goto(LAST) }
74 | }
75 | }
76 |
77 | PARTIAL
78 | .whenIsActive {
79 | io.output.valid := True
80 | for (i <- 0 until g.sizeMax - 1)
81 | io.output.stateElements(i) := buffer.stateElements(i + 1)
82 | when(io.output.fire) {
83 | counter := counter + 1
84 | goto(LAST)
85 | }
86 | }
87 |
88 | LAST
89 | .whenIsActive {
90 | io.output.valid := True
91 |
92 | when(!buffer.isFull) {
93 | io.output.stateElement := buffer.stateElements(0)
94 | for (i <- 0 until g.sizeMax - 1)
95 | io.output.stateElements(i) := buffer.stateElements(i + 1)
96 | }
97 |
98 | when(io.output.fire) {
99 | io.input.ready := True
100 |
101 | when(io.input.fire) {
102 | buffer := io.input.payload
103 | when(io.input.isFull) {
104 | goto(FULL)
105 | } otherwise {
106 | when(io.input.stateSize > 5)(goto(PARTIAL))
107 | }
108 | } otherwise (goto(IDLE))
109 | }
110 | }
111 | .onExit(counter := 0)
112 | }
113 | }
114 |
115 | object PoseidonSerializerVerilog {
116 | def main(args: Array[String]): Unit = {
117 |
118 | val config = PoseidonGenerics(
119 | sizeMax = 12,
120 | roundp = 57,
121 | roundf = 8,
122 | dataWidth = 255,
123 | idWidth = 8,
124 | isSim = true
125 | )
126 |
127 | SpinalConfig(
128 | mode = Verilog,
129 | targetDirectory = "./src/main/verilog"
130 | ).generate(PoseidonSerializer(config))
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/src/tests/AXI4StreamTransmitterTester.py:
--------------------------------------------------------------------------------
1 | from math import ceil
2 | import cocotb
3 | import random
4 | from cocotb.clock import Clock
5 | from cocotb.result import TestSuccess, TestFailure
6 | from cocotb.triggers import RisingEdge
7 | from queue import Queue
8 | from poseidon_python import basic
9 |
10 | from cocotb_test import simulator
11 |
12 | CASES_NUM = 1 # the number of test cases
13 | BUFFER_SIZE = 9 # the size of buffer in transmitter
14 |
15 |
16 | class AXI4StreamTransmitter:
17 | def __init__(self, target) -> None:
18 | self.ref_outputs = Queue(maxsize=80) # store reference results
19 | self.dut = target
20 |
21 | async def reset_dut(self):
22 | dut = self.dut
23 | dut.reset.value = 0
24 | await RisingEdge(dut.clk)
25 | dut.reset.value = 1
26 | for i in range(2):
27 | await RisingEdge(dut.clk)
28 |
29 | dut.reset.value = 0
30 |
31 | async def generate_input(self):
32 | """generate input signals"""
33 | dut = self.dut
34 | cases_count = 0
35 | while cases_count < CASES_NUM:
36 | # get random values
37 | inputs = []
38 | for i in range(BUFFER_SIZE):
39 | rand_value = random.randint(0, basic.P - 1)
40 | inputs.append([cases_count % pow(2, 5), rand_value])
41 | self.ref_outputs.put(rand_value)
42 | cases_count += 1
43 |
44 | # assign random values to dut io port
45 | tag = []
46 | while len(tag) < BUFFER_SIZE:
47 | valid = random.random() > 0.2
48 | index = random.randint(0, 4)
49 | while index in tag:
50 | index = random.randint(0, 4)
51 | dut.io_input_valid.value = valid
52 | dut.io_input_payload_state_id.value = inputs[index][0]
53 | dut.io_input_payload_state_element.value = inputs[index][1]
54 | await RisingEdge(dut.clk)
55 | if (dut.io_input_valid.value & dut.io_input_ready.value) == True:
56 | tag.append(index)
57 |
58 | async def check_output(self):
59 | """check output signals"""
60 | cases_count = 0
61 | dut = self.dut
62 | while True:
63 | # get random ready signals
64 | ready = random.random() > 0.3
65 | dut.io_output_ready.value = ready
66 | await RisingEdge(dut.clk)
67 | if (dut.io_output_ready.value & dut.io_output_valid.value) == True:
68 | ref_res = self.ref_outputs.get()
69 | dut_res = int(dut.io_output_payload.value)
70 | assert ref_res == dut_res, "test case {} failed".format(cases_count)
71 | cases_count += 1
72 |
73 | if cases_count == CASES_NUM:
74 | raise TestSuccess(" pass {} test cases".format(CASES_NUM))
75 |
76 |
77 | @cocotb.test(timeout_time=100000, timeout_unit="ns")
78 | async def AXI4StreamTransmitterTest(dut):
79 | await cocotb.start(Clock(dut.clk, 10, "ns").start())
80 |
81 | # set default values to all dut input ports
82 | dut.io_input_valid.value = False
83 | dut.io_input_payload_state_id.value = 0
84 | dut.io_input_payload_state_element.value = 0
85 |
86 | dut.io_output_ready.value = False
87 |
88 | # start testing
89 | tester = AXI4StreamTransmitter(dut)
90 | await tester.reset_dut()
91 | await cocotb.start(tester.generate_input())
92 | await cocotb.start(tester.check_output())
93 |
94 | while True:
95 | await RisingEdge(dut.clk)
96 |
97 |
98 | # pytest
99 | def test_AXI4StreamTransmitter():
100 | simulator.run(
101 | verilog_sources=["../main/verilog/AXI4StreamTransmitter.v"],
102 | toplevel="AXI4StreamTransmitter",
103 | module="AXI4StreamTransmitterTester",
104 | python_search="./src/reference_model/",
105 | )
106 |
--------------------------------------------------------------------------------
/src/main/scala/poseidon/BundleFifo.scala:
--------------------------------------------------------------------------------
1 | package poseidon
2 | import spinal.core._
3 | import spinal.lib._
4 |
5 | case class FifoIPConfig(
6 | byteWidth: Int,
7 | depth: Int,
8 | isSim: Boolean,
9 | name: String
10 | ) {
11 | val width = byteWidth * 8
12 | }
13 |
14 | object AXISDataFifoIP {
15 | def apply(g: FifoIPConfig, input: Stream[Bits]): Stream[Bits] = {
16 | val fifoInst = AXISDataFifoIP(g).setDefinitionName(g.name)
17 | fifoInst.io.input << input
18 | fifoInst.io.output
19 | }
20 | }
21 |
22 | case class AXISDataFifoIP(g: FifoIPConfig) extends BlackBox {
23 | val io = new Bundle {
24 | val input = slave Stream (Bits(g.width bits))
25 | val output = master Stream (Bits(g.width bits))
26 | val clk = in Bool ()
27 | val resetn = in Bool ()
28 | }
29 |
30 | mapCurrentClockDomain(
31 | clock = io.clk,
32 | reset = io.resetn,
33 | resetActiveLevel = LOW
34 | )
35 |
36 | // Remove io_ prefix
37 | noIoPrefix()
38 |
39 | // Function used to rename all signals of the blackbox
40 | private def renameIO(): Unit = {
41 | io.input.valid.setName("s_axis_tvalid")
42 | io.input.ready.setName("s_axis_tready")
43 | io.input.payload.setName("s_axis_tdata")
44 |
45 | io.output.valid.setName("m_axis_tvalid")
46 | io.output.ready.setName("m_axis_tready")
47 | io.output.payload.setName("m_axis_tdata")
48 |
49 | io.clk.setName("s_axis_aclk")
50 | io.resetn.setName("s_axis_aresetn")
51 | }
52 |
53 | // Execute the function renameIO after the creation of the component
54 | addPrePopTask(() => renameIO())
55 | }
56 |
57 | object BundleFifo {
58 | def apply[T <: Bundle](
59 | input: Stream[T],
60 | ipConfig: FifoIPConfig
61 | ): Stream[T] = {
62 | val fifoInst = BundleFifo(cloneOf(input.payload), ipConfig)
63 | fifoInst.io.push << input
64 | fifoInst.io.pop
65 | }
66 | }
67 |
68 | case class BundleFifo[T <: Bundle](dataType: HardType[T], ip: FifoIPConfig)
69 | extends Component {
70 | val io = new Bundle {
71 | val push = slave Stream (dataType())
72 | val pop = master Stream (dataType())
73 | }
74 | val inputWidth = dataType.getBitsWidth
75 | val fifoWidth = ip.width
76 | println(fifoWidth)
77 | println(inputWidth)
78 |
79 | if (ip.isSim) {
80 | io.pop << io.push.queue(ip.depth)
81 | } else {
82 | val slicesCount =
83 | inputWidth / fifoWidth + (if (inputWidth % fifoWidth == 0) 0 else 1)
84 | val slicesVec =
85 | for (i <- 0 until slicesCount)
86 | yield io.push.payload
87 | .asBits((inputWidth - 1 min (i + 1) * fifoWidth) downto i * fifoWidth)
88 | .resize(fifoWidth)
89 |
90 | val inputForked = StreamFork(io.push.toEvent(), slicesCount)
91 | val fifoInputs = Vec(Stream(Bits(fifoWidth bits)), slicesCount)
92 | for (i <- 0 until slicesCount) {
93 | fifoInputs(i).arbitrationFrom(inputForked(i))
94 | fifoInputs(i).payload := slicesVec(i)
95 | }
96 |
97 | val fifoOutputs = fifoInputs.map(AXISDataFifoIP(ip, _))
98 | io.pop.arbitrationFrom(StreamJoin(fifoOutputs))
99 | io.pop.payload.assignFromBits(fifoOutputs.map(_.payload).asBits().resized)
100 | }
101 | }
102 |
103 | object BundleFifoVerilog {
104 | def main(args: Array[String]): Unit = {
105 | val poseidonConfig = PoseidonGenerics(
106 | sizeMax = 12,
107 | roundp = 57,
108 | roundf = 8,
109 | dataWidth = 255,
110 | idWidth = 8,
111 | isSim = false
112 | )
113 |
114 | val ipConfig = FifoIPConfig(
115 | byteWidth = 193,
116 | depth = 256,
117 | isSim = false,
118 | name = "axis_data_fifo_0"
119 | )
120 | val clockDomainConfig = ClockDomainConfig(
121 | resetKind = SYNC,
122 | resetActiveLevel = LOW
123 | )
124 |
125 | SpinalConfig(
126 | mode = Verilog,
127 | targetDirectory = "./src/main/verilog",
128 | defaultConfigForClockDomains = clockDomainConfig
129 | ).generate(BundleFifo(MDSContext(poseidonConfig), ipConfig))
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/src/main/scala/poseidon/MontgomeryMult.scala:
--------------------------------------------------------------------------------
1 | package poseidon
2 |
3 | import spinal.core._
4 | import spinal.lib._
5 |
6 | // implement Montgomery Multiplier based on normal multipliers
7 |
8 | case class MontMultConfig(
9 | dataWidth: Int, // the width of data
10 | rWidth: Int, // width of R, R=pow(2,rWidth)
11 | modulus: BigInt,
12 | modInverse: BigInt,
13 | compensation: BigInt,
14 | isSim: Boolean
15 | )
16 |
17 | object MontgomeryMultFlow {
18 | def apply(
19 | g: MontMultConfig,
20 | ipConfig: MulIPConfig,
21 | input: Flow[operands]
22 | ): (Flow[results], Int) = {
23 | val multInst = MontgomeryMultFlow(g, ipConfig)
24 | multInst.io.input << input
25 | (multInst.io.output, multInst.totalLatency)
26 | }
27 | }
28 |
29 | case class MontgomeryMultFlow(g: MontMultConfig, ipConfig: MulIPConfig)
30 | extends Component {
31 |
32 | val io = new Bundle {
33 | val input = slave Flow (operands(g.dataWidth))
34 | val output = master Flow (results(g.dataWidth))
35 | }
36 |
37 | val (mulRes0, latency0) =
38 | MultiplierFlow(g.dataWidth, g.isSim, ipConfig, io.input)
39 |
40 | val mulInput1 = mulRes0.translateWith {
41 | val payload = operands(g.rWidth)
42 | payload.op1 := mulRes0.res(g.rWidth - 1 downto 0)
43 | payload.op2 := U(g.modInverse, g.rWidth bits)
44 | payload
45 | }
46 | val (mulRes1, latency1) =
47 | MultiplierFlow(g.rWidth, g.isSim, ipConfig, mulInput1)
48 |
49 | val mulInput2 = mulRes1.translateWith {
50 | val payload = operands(g.rWidth)
51 | payload.op1 := mulRes1.res(g.rWidth - 1 downto 0)
52 | payload.op2 := U(g.modulus, g.rWidth bits)
53 | payload
54 | }
55 | val (mulRes2, latency2) =
56 | MultiplierFlow(g.rWidth, g.isSim, ipConfig, mulInput2)
57 |
58 | val mulRes0Delayed = Delay(mulRes0.res, latency1 + latency2)
59 |
60 | val halfAddRes = new Bundle {
61 | val carry = Bool
62 | val op1 = UInt(g.rWidth bits)
63 | val op2 = UInt(2 * g.dataWidth - g.rWidth bits)
64 | }
65 |
66 | halfAddRes.carry := (mulRes2.res(g.rWidth - 1 downto 0) +^ mulRes0Delayed(
67 | g.rWidth - 1 downto 0
68 | )).msb
69 | halfAddRes.op1 := mulRes2.res(2 * g.rWidth - 1 downto g.rWidth)
70 | halfAddRes.op2 := mulRes0Delayed(2 * g.dataWidth - 1 downto g.rWidth)
71 |
72 | val halfAdderOutput = mulRes2.translateWith(halfAddRes).stage()
73 |
74 | val adderOutput = halfAdderOutput
75 | .translateWith {
76 | val payload = results(g.dataWidth + 1)
77 | payload.res := halfAdderOutput.op1 + halfAdderOutput.op2 + halfAdderOutput.carry.asUInt
78 | payload
79 | }
80 | .stage()
81 |
82 | // TODO: cut critical path
83 | val tempOutput = adderOutput
84 | .translateWith {
85 | val payload = operands(g.dataWidth + 1)
86 | payload.op1 := adderOutput.res
87 | payload.op2 := adderOutput
88 | .res(g.dataWidth - 1 downto 0) +^ U(g.compensation, g.dataWidth bits)
89 | payload
90 | }
91 | .stage()
92 |
93 | io.output << tempOutput
94 | .translateWith {
95 | val payload = results(g.dataWidth)
96 | payload.res := Mux(
97 | tempOutput.op1.msb | tempOutput.op2.msb,
98 | tempOutput.op2,
99 | tempOutput.op1
100 | ).resized
101 | payload
102 | }
103 | .stage()
104 |
105 | val totalLatency = latency0 + latency1 + latency2 + 2 + 2
106 | }
107 |
108 | object MontgomeryMultFlowVerilog {
109 | def main(args: Array[String]): Unit = {
110 |
111 | val montConfig =
112 | MontMultConfig(
113 | 255,
114 | 256,
115 | PoseidonParam.modulus,
116 | PoseidonParam.modInverse,
117 | PoseidonParam.compensation,
118 | false
119 | )
120 |
121 | val ipConfig = MulIPConfig(
122 | inputWidth = 34,
123 | outputWidth = 68,
124 | pipeStages = 6,
125 | moduleName = "mult_gen_0"
126 | )
127 |
128 | SpinalConfig(
129 | mode = Verilog,
130 | targetDirectory = "./src/main/verilog"
131 | ).generate(MontgomeryMultFlow(montConfig, ipConfig))
132 | }
133 | }
134 |
--------------------------------------------------------------------------------
/src/main/verilog/MontMultiplierBasics.v:
--------------------------------------------------------------------------------
1 | module OneBitFullAdderVec #(
2 | parameter DATA_WIDTH = 256
3 | )(
4 | input [DATA_WIDTH-1:0] op1_i,
5 | input [DATA_WIDTH-1:0] op2_i,
6 | input [DATA_WIDTH-1:0] op3_i,
7 |
8 | output[DATA_WIDTH-1:0] sum_o,
9 | output[DATA_WIDTH-1:0] carry_o
10 | );
11 |
12 | genvar i;
13 | generate
14 | for(i=0; i= 9:
48 | context_vec.append(Context(isFull, roundf, roundp, 1, size, id))
49 | context_vec[1].copy_state_elements(context_vec[0])
50 |
51 | return context_vec
52 |
53 | async def reset_dut(self):
54 | self.dut.reset.value = 0
55 | await RisingEdge(self.dut.clk)
56 | self.dut.reset.value = 1
57 | for i in range(2):
58 | await RisingEdge(self.dut.clk)
59 |
60 | self.dut.reset.value = 0
61 |
62 | async def drive_input_ports(self):
63 | dut = self.dut
64 | """generate input signals"""
65 | cases_count = 0
66 | while cases_count < self.input_cases:
67 | dut_input = MDSContext()
68 | dut_input.rand_mds_context(
69 | isFull=self.isFull, size=self.size, id=cases_count
70 | )
71 |
72 | # assign random values to dut input port
73 | dut.io_input_valid.value = True # random.random() > 0.2
74 | dut_input.set_dut_ports(dut)
75 |
76 | await RisingEdge(dut.clk)
77 | if (dut.io_input_valid.value & dut.io_input_ready.value) == True:
78 | cases_count += 1
79 | ref_outputs = self.reference_model(dut_input)
80 | for element in ref_outputs:
81 | self.ref_outputs.put(element)
82 |
83 | dut.io_input_valid.value = False
84 |
85 | async def monitor_output_ports(self):
86 | """check output signals"""
87 | dut = self.dut
88 | cases_count = 0
89 | while cases_count < self.output_cases:
90 | dut.io_output_ready.value = True # random.random() > 0.2
91 | await RisingEdge(dut.clk)
92 |
93 | if (dut.io_output_ready.value & dut.io_output_valid.value) == True:
94 | ref_output = self.ref_outputs.get()
95 | dut_output = Context()
96 | dut_output.get_dut_ports(dut)
97 |
98 | if not dut_output.check_context_equal(ref_output):
99 | print("REF: ")
100 | ref_output.print_context_info()
101 | print("DUT: ")
102 | dut_output.print_context_info()
103 | raise TestFailure(f"test case {cases_count} failed!!!")
104 | cases_count = cases_count + 1
105 |
106 | raise TestSuccess(" pass {} test cases".format(self.input_cases))
107 |
108 |
109 | @cocotb.test(timeout_time=500000, timeout_unit="ns")
110 | async def PoseidonSerializerTest(dut):
111 |
112 | await cocotb.start(Clock(dut.clk, 10, "ns").start())
113 | tester = PoseidonSerializerTester(dut, 500, 12, isFull=True)
114 |
115 | # set default value to input ports of dut
116 | dut.io_input_valid.value = False
117 | dut.io_output_ready.value = False
118 | init_context = MDSContext()
119 | init_context.set_dut_ports(dut)
120 |
121 | await tester.reset_dut()
122 | # start testing
123 | await cocotb.start(tester.drive_input_ports())
124 | await cocotb.start(tester.monitor_output_ports())
125 |
126 | while True:
127 | await RisingEdge(dut.clk)
128 |
--------------------------------------------------------------------------------
/src/tests/MDSMatrixAddersTester.py:
--------------------------------------------------------------------------------
1 | from math import ceil
2 | from typing import List
3 | import cocotb
4 | import random
5 | from cocotb.clock import Clock
6 | from cocotb.result import TestSuccess, TestFailure
7 | from cocotb.triggers import RisingEdge
8 | from queue import Queue
9 |
10 | from poseidon_python import basic
11 |
12 | from cocotb_test import simulator
13 |
14 | from BasicElements import MDSContext
15 |
16 | CASES_NUM = 1000 # the number of test cases
17 |
18 |
19 | class MDSMatrixAddersTester:
20 | def __init__(self, target, isFull=None, size=None):
21 | self.dut = target
22 | self.id_width = 8 # the width of state_id used in MDSMatrixAdders
23 | self.ref_outputs = Queue(maxsize=100) # store reference results
24 | self.isFull = isFull
25 | self.size = size
26 |
27 | def reference_model(self, context_vec: List[MDSContext]):
28 | context = context_vec[0]
29 | res = MDSContext(
30 | context.isFull,
31 | context.full_round,
32 | context.partial_round,
33 | context.state_size,
34 | context.state_id,
35 | )
36 | if context.isFull:
37 | for i in range(context.state_size):
38 | for j in range(MDSContext.elements_num):
39 | res.state_elements[j].addassign(context_vec[i].state_elements[j])
40 | else:
41 | if context.state_size < 9:
42 | res.state_elements[0].value = context.state_elements[0].value
43 | for i in range(1, 2 * context.state_size - 1):
44 | res.state_elements[i].value = context.state_elements[i].value
45 | for i in range(context.state_size, 2 * context.state_size - 1):
46 | res.state_elements[0].addassign(context.state_elements[i])
47 |
48 | else:
49 | for i in range(MDSContext.elements_num):
50 | res.state_elements[0].addassign(context_vec[1].state_elements[i])
51 | for i in range(1, MDSContext.elements_num):
52 | res.state_elements[i].value = context.state_elements[i].value
53 | return res
54 |
55 | async def reset_dut(self):
56 | dut = self.dut
57 | dut.reset.value = 1
58 | for i in range(3):
59 | await RisingEdge(dut.clk)
60 |
61 | dut.reset.value = 0
62 |
63 | async def drive_input_ports(self):
64 | """drive input ports"""
65 | dut = self.dut
66 | await RisingEdge(dut.clk)
67 |
68 | cases_count = 0
69 | while cases_count < CASES_NUM:
70 | # get random input
71 | context_vec = MDSContext.get_context_vec(
72 | isFull=self.isFull, size=self.size, id=cases_count
73 | )
74 |
75 | for element in context_vec:
76 | dut.io_input_valid.value = True # random.random() > 0.3
77 | element.set_dut_ports(dut)
78 |
79 | await RisingEdge(dut.clk)
80 | while (dut.io_input_valid.value) == False:
81 | dut.io_input_valid.value = random.random() > 0.2
82 | await RisingEdge(dut.clk)
83 |
84 | self.ref_outputs.put(self.reference_model(context_vec))
85 |
86 | cases_count += 1
87 |
88 | dut.io_input_valid.value = False
89 |
90 | async def monitor_output_ports(self):
91 | """check output signals"""
92 | dut = self.dut
93 | cases_count = 0
94 |
95 | while cases_count < CASES_NUM:
96 | await RisingEdge(dut.clk)
97 |
98 | if (dut.io_output_valid.value) == True:
99 | # get reference output
100 | ref_context = self.ref_outputs.get()
101 |
102 | # get dut outputs
103 | dut_context = MDSContext()
104 | dut_context.get_dut_ports(dut)
105 | if not dut_context.check_context_equal(ref_context):
106 | print("REF:")
107 | ref_context.print_context_info()
108 | print("DUT:")
109 | dut_context.print_context_info()
110 | raise TestFailure(f"test case {cases_count} failed: ")
111 |
112 | cases_count += 1
113 |
114 | raise TestSuccess(f" pass {CASES_NUM} test cases")
115 |
116 |
117 | @cocotb.test(timeout_time=5000000, timeout_unit="ns")
118 | async def MDSMatrixAddersTest(dut):
119 | await cocotb.start(Clock(dut.clk, 10, "ns").start())
120 |
121 | tester = MDSMatrixAddersTester(dut, size=3)
122 |
123 | # set default values to all dut input ports
124 | initial_context = MDSContext()
125 | initial_context.set_dut_ports(dut)
126 |
127 | # start testing
128 | await tester.reset_dut()
129 | await cocotb.start(tester.drive_input_ports())
130 | await cocotb.start(tester.monitor_output_ports())
131 |
132 | while True:
133 | await RisingEdge(dut.clk)
134 |
--------------------------------------------------------------------------------
/src/tests/poseidon_python/finite_field.py:
--------------------------------------------------------------------------------
1 | import math
2 | import logging
3 |
4 | P = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001
5 | RWIDTH = 256
6 |
7 | logging.basicConfig(
8 | level=logging.DEBUG,
9 | format="%(asctime)s %(name)s %(levelname)s %(message)s",
10 | datefmt="%Y-%m-%d %H:%M:%S %a",
11 | )
12 |
13 |
14 | def get_gcd(a, b):
15 | """get the greatest common divisor of a and b"""
16 | if a == 0:
17 | return b
18 | if b == 0:
19 | return a
20 |
21 | if a < b:
22 | return get_gcd(a, b % a)
23 | else:
24 | return get_gcd(b, a % b)
25 |
26 |
27 | def getxy(a, b):
28 | """x*a + y*b = gcd(a,b)"""
29 | """ input requirement: a > b """
30 | """ get x for a and y for b"""
31 | remainder = a % b
32 | k = a // b
33 |
34 | if b % remainder == 0:
35 | return 1, -k
36 | else:
37 | x1, y1 = getxy(b, remainder)
38 | return y1, y1 * (-k) + x1
39 |
40 |
41 | def get_modular_inverse(x, modulus):
42 | """get the inverse of x mod modulus"""
43 | """ if the inverse don't exit return 0"""
44 | if get_gcd(x, modulus) != 1:
45 | return 0
46 | else:
47 | x, y = getxy(x, modulus)
48 | return (x + modulus) % modulus
49 |
50 |
51 | class PrimeField:
52 | N = 0
53 | R_WIDTH = 0
54 | R = 0
55 | N1 = 0
56 |
57 | def toMont(self, x):
58 | """transform x to montgomery format"""
59 | return (x << self.R_WIDTH) % self.N
60 |
61 | def __init__(self, value, n=P):
62 | self.N = n
63 | self.R_WIDTH = RWIDTH
64 | self.R = pow(2, self.R_WIDTH)
65 | x, y = getxy(self.R, self.N)
66 | self.N1 = -y
67 | self.value = self.toMont(value)
68 |
69 | def MonPro(self, op1, op2):
70 | """Montgomery product"""
71 | t = op1 * op2 % self.R
72 | m = t * self.N1 % self.R
73 | u = (op1 * op2 + m * self.N) >> self.R_WIDTH
74 |
75 | while u >= self.N:
76 | u -= self.N
77 | return u
78 |
79 | def ModAdd(self, op1, op2):
80 | tmp = op1 + op2
81 | while tmp > self.N:
82 | tmp -= self.N
83 | return tmp
84 |
85 | def ModExp(self, x, exp):
86 | """compute pow(x,exp) mod N in Montgomery pattern"""
87 | exp_bin = bin(exp)[2:]
88 | tmp = (1 * self.R) % self.N
89 | for i in exp_bin:
90 | tmp = self.MonPro(tmp, tmp)
91 | if i == "1":
92 | tmp = self.MonPro(x, tmp)
93 | return tmp
94 |
95 | def expassign(self, exp):
96 | """self = pow(self,exp)"""
97 | self.value = self.ModExp(self.value, exp)
98 |
99 | def addassign(self, op1):
100 | """self = self + op1"""
101 | assert self.N == op1.N
102 | self.value = self.ModAdd(self.value, op1.value)
103 |
104 | def mulassign(self, op1):
105 | """self = self * op1"""
106 | assert self.N == op1.N
107 | self.value = self.MonPro(self.value, op1.value)
108 |
109 | def fromMont(self):
110 | """transform Montgomery pattern into regular pattern"""
111 | return self.MonPro(self.value, 1)
112 |
113 | def add(self, op1):
114 | """return op1 + self"""
115 | assert self.N == op1.N
116 | tmp = PrimeField(0, self.N)
117 | tmp.value = self.ModAdd(self.value, op1.value)
118 | return tmp
119 |
120 | def mul(self, op1):
121 | """return self * op1"""
122 | assert self.N == op1.N
123 | tmp = PrimeField(0, self.N)
124 | tmp.value = self.MonPro(self.value, op1.value)
125 | return tmp
126 |
127 |
128 | # test
129 | def test_mul():
130 | p1 = PrimeField(100)
131 | p2 = PrimeField(999)
132 | p3 = PrimeField(1234567890)
133 |
134 | print(hex(p1.value))
135 | print(hex(p1.N1))
136 | print(hex(p1.R))
137 |
138 | p1.mulassign(p2)
139 | assert (
140 | p1.fromMont() == (100 * 999) % p1.N
141 | ), "the result of p1.mulassign(p2) is wrong."
142 | p2.mulassign(p3)
143 | assert (
144 | p2.fromMont() == (999 * 1234567890) % p2.N
145 | ), "the result of p2.mulassign(p3) is wrong."
146 |
147 | logging.info("pass mul test!!")
148 |
149 |
150 | def test_add():
151 | a = 9870765432
152 | b = 4567432198765430
153 | c = 3421987654320
154 | p1 = PrimeField(a)
155 | p2 = PrimeField(b)
156 | p3 = PrimeField(c)
157 |
158 | p1.addassign(p2)
159 | p2.addassign(p3)
160 | assert p1.fromMont() == (a + b) % p1.N, "the result of p1.addassign(p2) is wrong."
161 | assert p2.fromMont() == (b + c) % p1.N, "the result of p2.addassign(p3) is wrong."
162 |
163 | logging.info("pass add test")
164 |
165 |
166 | def test_exp():
167 | a = 65439870654
168 | p1 = PrimeField(a)
169 | p1.expassign(8)
170 | assert p1.fromMont() == pow(a, 8) % p1.N, "the result of p1.expassign(8) is wrong."
171 |
172 | logging.info("pass exp test!!")
173 |
--------------------------------------------------------------------------------
/src/reference_model/poseidon_python/finite_field.py:
--------------------------------------------------------------------------------
1 | import math
2 | import logging
3 |
4 | P = 0x73EDA753299D7D483339D80809A1D80553BDA402FFFE5BFEFFFFFFFF00000001
5 | RWIDTH = 256
6 |
7 | logging.basicConfig(
8 | level=logging.DEBUG,
9 | format="%(asctime)s %(name)s %(levelname)s %(message)s",
10 | datefmt="%Y-%m-%d %H:%M:%S %a",
11 | )
12 |
13 |
14 | def get_gcd(a, b):
15 | """get the greatest common divisor of a and b"""
16 | if a == 0:
17 | return b
18 | if b == 0:
19 | return a
20 |
21 | if a < b:
22 | return get_gcd(a, b % a)
23 | else:
24 | return get_gcd(b, a % b)
25 |
26 |
27 | def getxy(a, b):
28 | """x*a + y*b = gcd(a,b)"""
29 | """ input requirement: a > b """
30 | """ get x for a and y for b"""
31 | remainder = a % b
32 | k = a // b
33 |
34 | if b % remainder == 0:
35 | return 1, -k
36 | else:
37 | x1, y1 = getxy(b, remainder)
38 | return y1, y1 * (-k) + x1
39 |
40 |
41 | def get_modular_inverse(x, modulus):
42 | """get the inverse of x mod modulus"""
43 | """ if the inverse don't exit return 0"""
44 | if get_gcd(x, modulus) != 1:
45 | return 0
46 | else:
47 | x, y = getxy(x, modulus)
48 | return (x + modulus) % modulus
49 |
50 |
51 | class PrimeField:
52 | N = 0
53 | R_WIDTH = 0
54 | R = 0
55 | N1 = 0
56 |
57 | def toMont(self, x):
58 | """transform x to montgomery format"""
59 | return (x << self.R_WIDTH) % self.N
60 |
61 | def __init__(self, value, n=P):
62 | self.N = n
63 | self.R_WIDTH = RWIDTH
64 | self.R = pow(2, self.R_WIDTH)
65 | x, y = getxy(self.R, self.N)
66 | self.N1 = -y
67 | self.value = self.toMont(value)
68 |
69 | def MonPro(self, op1, op2):
70 | """Montgomery product"""
71 | t = op1 * op2 % self.R
72 | m = t * self.N1 % self.R
73 | u = (op1 * op2 + m * self.N) >> self.R_WIDTH
74 |
75 | while u >= self.N:
76 | u -= self.N
77 | return u
78 |
79 | def ModAdd(self, op1, op2):
80 | tmp = op1 + op2
81 | while tmp > self.N:
82 | tmp -= self.N
83 | return tmp
84 |
85 | def ModExp(self, x, exp):
86 | """compute pow(x,exp) mod N in Montgomery pattern"""
87 | exp_bin = bin(exp)[2:]
88 | tmp = (1 * self.R) % self.N
89 | for i in exp_bin:
90 | tmp = self.MonPro(tmp, tmp)
91 | if i == "1":
92 | tmp = self.MonPro(x, tmp)
93 | return tmp
94 |
95 | def expassign(self, exp):
96 | """self = pow(self,exp)"""
97 | self.value = self.ModExp(self.value, exp)
98 |
99 | def addassign(self, op1):
100 | """self = self + op1"""
101 | assert self.N == op1.N
102 | self.value = self.ModAdd(self.value, op1.value)
103 |
104 | def mulassign(self, op1):
105 | """self = self * op1"""
106 | assert self.N == op1.N
107 | self.value = self.MonPro(self.value, op1.value)
108 |
109 | def fromMont(self):
110 | """transform Montgomery pattern into regular pattern"""
111 | return self.MonPro(self.value, 1)
112 |
113 | def add(self, op1):
114 | """return op1 + self"""
115 | assert self.N == op1.N
116 | tmp = PrimeField(0, self.N)
117 | tmp.value = self.ModAdd(self.value, op1.value)
118 | return tmp
119 |
120 | def mul(self, op1):
121 | """return self * op1"""
122 | assert self.N == op1.N
123 | tmp = PrimeField(0, self.N)
124 | tmp.value = self.MonPro(self.value, op1.value)
125 | return tmp
126 |
127 |
128 | # test
129 | def test_mul():
130 | p1 = PrimeField(100)
131 | p2 = PrimeField(999)
132 | p3 = PrimeField(1234567890)
133 |
134 | print(hex(p1.value))
135 | print(hex(p1.N1))
136 | print(hex(p1.R))
137 |
138 | p1.mulassign(p2)
139 | assert (
140 | p1.fromMont() == (100 * 999) % p1.N
141 | ), "the result of p1.mulassign(p2) is wrong."
142 | p2.mulassign(p3)
143 | assert (
144 | p2.fromMont() == (999 * 1234567890) % p2.N
145 | ), "the result of p2.mulassign(p3) is wrong."
146 |
147 | logging.info("pass mul test!!")
148 |
149 |
150 | def test_add():
151 | a = 9870765432
152 | b = 4567432198765430
153 | c = 3421987654320
154 | p1 = PrimeField(a)
155 | p2 = PrimeField(b)
156 | p3 = PrimeField(c)
157 |
158 | p1.addassign(p2)
159 | p2.addassign(p3)
160 | assert p1.fromMont() == (a + b) % p1.N, "the result of p1.addassign(p2) is wrong."
161 | assert p2.fromMont() == (b + c) % p1.N, "the result of p2.addassign(p3) is wrong."
162 |
163 | logging.info("pass add test")
164 |
165 |
166 | def test_exp():
167 | a = 65439870654
168 | p1 = PrimeField(a)
169 | p1.expassign(8)
170 | assert p1.fromMont() == pow(a, 8) % p1.N, "the result of p1.expassign(8) is wrong."
171 |
172 | logging.info("pass exp test!!")
173 |
--------------------------------------------------------------------------------
/src/main/scala/poseidon/MDSMatrixMultiplier.scala:
--------------------------------------------------------------------------------
1 | package poseidon
2 |
3 | import spinal.core._
4 | import spinal.lib._
5 |
6 | case class MDSContext(g: PoseidonGenerics) extends Bundle {
7 | val isFull = Bool()
8 | val fullRound = UInt(log2Up(g.roundf) bits)
9 | val partialRound = UInt(log2Up(g.roundp) bits)
10 | val stateSize = UInt(log2Up(g.sizeMax) bits)
11 | val stateID = UInt(g.idWidth bits)
12 | val stateElements = Vec(UInt(g.dataWidth bits), g.sizeMax)
13 | }
14 |
15 | case class MDSMulContext(g: PoseidonGenerics) extends Bundle {
16 | val isFull = Bool()
17 | val fullRound = UInt(log2Up(g.roundf) bits)
18 | val partialRound = UInt(log2Up(g.roundp) bits)
19 | val stateSize = UInt(log2Up(g.sizeMax) bits)
20 | val stateID = UInt(g.idWidth bits)
21 | val stateElements = Vec(UInt(g.dataWidth bits), g.sizeMax - 1)
22 | }
23 |
24 | object MDSMatrixMultiplier {
25 | def apply(
26 | g: PoseidonGenerics,
27 | mulConfig: MontMultConfig,
28 | ipConfig: MulIPConfig,
29 | input: Flow[ContextCase]
30 | ): Flow[MDSContext] = {
31 | val MDSMultiplierInst = MDSMatrixMultiplier(g, mulConfig, ipConfig)
32 | MDSMultiplierInst.io.input << input
33 | MDSMultiplierInst.io.output
34 | }
35 | }
36 |
37 | case class MDSMatrixMultiplier( // 49 stages
38 | g: PoseidonGenerics,
39 | mulConfig: MontMultConfig,
40 | ipConfig: MulIPConfig
41 | ) extends Component {
42 |
43 | val io = new Bundle {
44 | val input = slave Flow (ContextCase(g))
45 | val output = master Flow (MDSContext(g))
46 | }
47 |
48 | val adderIPConfig = AdderIPConfig(
49 | inputWidth = 255,
50 | outputWidth = 256,
51 | latency = 8,
52 | moduleName = "c_addsub_1"
53 | )
54 |
55 | // set configuration parameters of ModularAdderFlow implemented through Xilinx Adder IP
56 | val modAdderConfig = ModAdderConfig(
57 | dataWidth = g.dataWidth,
58 | modulus = PoseidonParam.modulus,
59 | compensation = PoseidonParam.compensation,
60 | isSim = g.isSim
61 | )
62 |
63 | val constants = MDSConstantMem(g)
64 | constants.io.addr.assignSomeByName(io.input.payload)
65 |
66 | val inputDelayed = io.input.stage().stage().stage().stage().stage()
67 | val mulInputs = for (i <- 0 until g.sizeMax) yield {
68 | inputDelayed.translateWith(
69 | operands(inputDelayed.stateElement, constants.io.data(i))
70 | )
71 | }
72 |
73 | when(!inputDelayed.isFull) {
74 | when(inputDelayed.stateSize === 3) {
75 | for (i <- 3 until 5) mulInputs(i).op1 := inputDelayed.stateElements(i - 3)
76 | } elsewhen (inputDelayed.stateSize === 5) {
77 | for (i <- 5 until 9) mulInputs(i).op1 := inputDelayed.stateElements(i - 5)
78 | } elsewhen (inputDelayed.stateIndex === 1) {
79 | for (i <- 1 until g.sizeMax)
80 | mulInputs(i).op1 := inputDelayed.stateElements(i - 1)
81 | }
82 |
83 | }
84 |
85 | // TODO: cut the critical path
86 | // modular multipliers: 47 stages
87 | val mulInputsTemp = mulInputs.map(_.stage())
88 | val mulOutputs = mulInputsTemp.map(MontgomeryMultFlow(mulConfig, ipConfig, _))
89 |
90 | val mulContext = MDSMulContext(g)
91 | mulContext.assignSomeByName(inputDelayed.payload)
92 | when(
93 | !inputDelayed.isFull && inputDelayed.stateSize > 5 && inputDelayed.stateIndex === 1
94 | ) {
95 | mulContext.stateElements.assignFromBits(
96 | B(0, (g.sizeMax - 1) * g.dataWidth bits)
97 | )
98 | }
99 | val mulContextDelayed = Delay(mulContext, mulOutputs(0)._2 + 1)
100 |
101 | // modular adders: 2 stages
102 | val adderOutputs =
103 | for (i <- 1 until g.sizeMax)
104 | yield ModAdderPiped(
105 | modAdderConfig,
106 | adderIPConfig,
107 | mulOutputs(i)._1.res,
108 | mulContextDelayed.stateElements(i - 1)
109 | )
110 |
111 | val validDelayed = Delay(
112 | mulOutputs.map(_._1.valid).asBits().andR,
113 | adderOutputs(0)._2,
114 | init = False
115 | )
116 | val mulOutput0Delayed = Delay(mulOutputs(0)._1.res, adderOutputs(0)._2)
117 | val addContext = MDSAddContext(g)
118 | addContext.assignSomeByName(mulContextDelayed)
119 | val addContextDelayed = Delay(addContext, adderOutputs(0)._2)
120 |
121 | io.output.valid := validDelayed
122 | io.output.payload.assignSomeByName(addContextDelayed)
123 | io.output.stateElements.assignFromBits(
124 | adderOutputs.map(_._1).asBits() ## mulOutput0Delayed
125 | )
126 |
127 | }
128 |
129 | object MDSMatrixMultiplierVerilog {
130 | def main(args: Array[String]): Unit = {
131 | val poseidonConfig = PoseidonGenerics(
132 | sizeMax = 12,
133 | roundp = 57,
134 | roundf = 8,
135 | dataWidth = 255,
136 | idWidth = 8,
137 | isSim = true
138 | )
139 |
140 | val montMultConfig = MontMultConfig(
141 | 255,
142 | 256,
143 | PoseidonParam.modulus,
144 | PoseidonParam.modInverse,
145 | PoseidonParam.compensation,
146 | true
147 | )
148 |
149 | val mulIPConfig = MulIPConfig(
150 | inputWidth = 34,
151 | outputWidth = 68,
152 | pipeStages = 6,
153 | moduleName = "mult_gen_0"
154 | )
155 |
156 | SpinalConfig(
157 | mode = Verilog,
158 | targetDirectory = "./src/main/verilog/"
159 | ).generate(MDSMatrixMultiplier(poseidonConfig, montMultConfig, mulIPConfig))
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/poseidon_constants/mds_matrixs/mds_matrix_9.txt:
--------------------------------------------------------------------------------
1 | 19c308bd25b13848eef068e557794c72f62a247271c6bf1c38e38e38aaaaaaab
2 | 22c74bcc2615a595a8f7c0cf3616f401991f4acdb332b532e66666661999999a
3 | 6963af62e003892a5d1d50074e93217934daf23145cff68aba2e8ba200000001
4 | 6a44840c3b7b082cd99fb0b208d45b5a376dd6581553d4546aaaaaa9c0000001
5 | 6217dc5a0f85429f8dce7bb808267bb5bd02ed3d9d88753a3b13b13a3b13b13c
6 | 4a867dda0877876545809d29bd0c9d27fef9e96fa4913b23edb6db6d12492493
7 | 3dd414f92742ed7bd70dc88cd1efeaad81febddf77769776eeeeeeee66666667
8 | 6caeccddf703a573b0063a878907ba84fe81c9c2cffe763f0fffffff10000001
9 | 1b46fa31af7059b6a2a432d4b6f8e788c868db4bffff9d2cf0f0f0f0b4b4b4b5
10 | 22c74bcc2615a595a8f7c0cf3616f401991f4acdb332b532e66666661999999a
11 | 6963af62e003892a5d1d50074e93217934daf23145cff68aba2e8ba200000001
12 | 6a44840c3b7b082cd99fb0b208d45b5a376dd6581553d4546aaaaaa9c0000001
13 | 6217dc5a0f85429f8dce7bb808267bb5bd02ed3d9d88753a3b13b13a3b13b13c
14 | 4a867dda0877876545809d29bd0c9d27fef9e96fa4913b23edb6db6d12492493
15 | 3dd414f92742ed7bd70dc88cd1efeaad81febddf77769776eeeeeeee66666667
16 | 6caeccddf703a573b0063a878907ba84fe81c9c2cffe763f0fffffff10000001
17 | 1b46fa31af7059b6a2a432d4b6f8e788c868db4bffff9d2cf0f0f0f0b4b4b4b5
18 | 46d8580827a75ac891152076b08d923c24f3e43ab8e28d8d9c71c71bd5555556
19 | 6963af62e003892a5d1d50074e93217934daf23145cff68aba2e8ba200000001
20 | 6a44840c3b7b082cd99fb0b208d45b5a376dd6581553d4546aaaaaa9c0000001
21 | 6217dc5a0f85429f8dce7bb808267bb5bd02ed3d9d88753a3b13b13a3b13b13c
22 | 4a867dda0877876545809d29bd0c9d27fef9e96fa4913b23edb6db6d12492493
23 | 3dd414f92742ed7bd70dc88cd1efeaad81febddf77769776eeeeeeee66666667
24 | 6caeccddf703a573b0063a878907ba84fe81c9c2cffe763f0fffffff10000001
25 | 1b46fa31af7059b6a2a432d4b6f8e788c868db4bffff9d2cf0f0f0f0b4b4b4b5
26 | 46d8580827a75ac891152076b08d923c24f3e43ab8e28d8d9c71c71bd5555556
27 | 6dd3abfdf187ba0e815f38736770e79941dc14a486bb13c9286bca1a00000001
28 | 6a44840c3b7b082cd99fb0b208d45b5a376dd6581553d4546aaaaaa9c0000001
29 | 6217dc5a0f85429f8dce7bb808267bb5bd02ed3d9d88753a3b13b13a3b13b13c
30 | 4a867dda0877876545809d29bd0c9d27fef9e96fa4913b23edb6db6d12492493
31 | 3dd414f92742ed7bd70dc88cd1efeaad81febddf77769776eeeeeeee66666667
32 | 6caeccddf703a573b0063a878907ba84fe81c9c2cffe763f0fffffff10000001
33 | 1b46fa31af7059b6a2a432d4b6f8e788c868db4bffff9d2cf0f0f0f0b4b4b4b5
34 | 46d8580827a75ac891152076b08d923c24f3e43ab8e28d8d9c71c71bd5555556
35 | 6dd3abfdf187ba0e815f38736770e79941dc14a486bb13c9286bca1a00000001
36 | 1163a5e6130ad2cad47be0679b0b7a00cc8fa566d9995a99733333330ccccccd
37 | 6217dc5a0f85429f8dce7bb808267bb5bd02ed3d9d88753a3b13b13a3b13b13c
38 | 4a867dda0877876545809d29bd0c9d27fef9e96fa4913b23edb6db6d12492493
39 | 3dd414f92742ed7bd70dc88cd1efeaad81febddf77769776eeeeeeee66666667
40 | 6caeccddf703a573b0063a878907ba84fe81c9c2cffe763f0fffffff10000001
41 | 1b46fa31af7059b6a2a432d4b6f8e788c868db4bffff9d2cf0f0f0f0b4b4b4b5
42 | 46d8580827a75ac891152076b08d923c24f3e43ab8e28d8d9c71c71bd5555556
43 | 6dd3abfdf187ba0e815f38736770e79941dc14a486bb13c9286bca1a00000001
44 | 1163a5e6130ad2cad47be0679b0b7a00cc8fa566d9995a99733333330ccccccd
45 | b0a7175a27085d61d427619257d20c38e120f9ec30c08c2f3cf3cf3b6db6db7
46 | 4a867dda0877876545809d29bd0c9d27fef9e96fa4913b23edb6db6d12492493
47 | 3dd414f92742ed7bd70dc88cd1efeaad81febddf77769776eeeeeeee66666667
48 | 6caeccddf703a573b0063a878907ba84fe81c9c2cffe763f0fffffff10000001
49 | 1b46fa31af7059b6a2a432d4b6f8e788c868db4bffff9d2cf0f0f0f0b4b4b4b5
50 | 46d8580827a75ac891152076b08d923c24f3e43ab8e28d8d9c71c71bd5555556
51 | 6dd3abfdf187ba0e815f38736770e79941dc14a486bb13c9286bca1a00000001
52 | 1163a5e6130ad2cad47be0679b0b7a00cc8fa566d9995a99733333330ccccccd
53 | b0a7175a27085d61d427619257d20c38e120f9ec30c08c2f3cf3cf3b6db6db7
54 | 6ea8ab5b04d08339482b9407ac1a7cbf444c4b1a22e72944dd1745d080000001
55 | 3dd414f92742ed7bd70dc88cd1efeaad81febddf77769776eeeeeeee66666667
56 | 6caeccddf703a573b0063a878907ba84fe81c9c2cffe763f0fffffff10000001
57 | 1b46fa31af7059b6a2a432d4b6f8e788c868db4bffff9d2cf0f0f0f0b4b4b4b5
58 | 46d8580827a75ac891152076b08d923c24f3e43ab8e28d8d9c71c71bd5555556
59 | 6dd3abfdf187ba0e815f38736770e79941dc14a486bb13c9286bca1a00000001
60 | 1163a5e6130ad2cad47be0679b0b7a00cc8fa566d9995a99733333330ccccccd
61 | b0a7175a27085d61d427619257d20c38e120f9ec30c08c2f3cf3cf3b6db6db7
62 | 6ea8ab5b04d08339482b9407ac1a7cbf444c4b1a22e72944dd1745d080000001
63 | 64cea7c2c00361cf7a7514e599124c8a328ea4e137a587a61642c8582c8590b3
64 | 6caeccddf703a573b0063a878907ba84fe81c9c2cffe763f0fffffff10000001
65 | 1b46fa31af7059b6a2a432d4b6f8e788c868db4bffff9d2cf0f0f0f0b4b4b4b5
66 | 46d8580827a75ac891152076b08d923c24f3e43ab8e28d8d9c71c71bd5555556
67 | 6dd3abfdf187ba0e815f38736770e79941dc14a486bb13c9286bca1a00000001
68 | 1163a5e6130ad2cad47be0679b0b7a00cc8fa566d9995a99733333330ccccccd
69 | b0a7175a27085d61d427619257d20c38e120f9ec30c08c2f3cf3cf3b6db6db7
70 | 6ea8ab5b04d08339482b9407ac1a7cbf444c4b1a22e72944dd1745d080000001
71 | 64cea7c2c00361cf7a7514e599124c8a328ea4e137a587a61642c8582c8590b3
72 | 6f1915afb28c42ba866cc45d093b19afc595bd2d8aa91829b555555460000001
73 | 1b46fa31af7059b6a2a432d4b6f8e788c868db4bffff9d2cf0f0f0f0b4b4b4b5
74 | 46d8580827a75ac891152076b08d923c24f3e43ab8e28d8d9c71c71bd5555556
75 | 6dd3abfdf187ba0e815f38736770e79941dc14a486bb13c9286bca1a00000001
76 | 1163a5e6130ad2cad47be0679b0b7a00cc8fa566d9995a99733333330ccccccd
77 | b0a7175a27085d61d427619257d20c38e120f9ec30c08c2f3cf3cf3b6db6db7
78 | 6ea8ab5b04d08339482b9407ac1a7cbf444c4b1a22e72944dd1745d080000001
79 | 64cea7c2c00361cf7a7514e599124c8a328ea4e137a587a61642c8582c8590b3
80 | 6f1915afb28c42ba866cc45d093b19afc595bd2d8aa91829b555555460000001
81 | 6aa770fa96ed0cdc062af9f2ea24419e803dd454ae12f879f5c28f5b3d70a3d8
82 |
--------------------------------------------------------------------------------
/poseidon_constants/mds_matrixs_ff/mds_matrix_ff_9.txt:
--------------------------------------------------------------------------------
1 | 5cd95cf5500229281c7578047721063bd930778fe38d4f8daaaaaaaa1c71c71d
2 | 26a11bc2ae0808b28f46e64cadfa19888da1265cccd20cd0000000033333333
3 | 2c59c154f04b2e0d209627474791ca2f8396d8008ba29c5ce8ba2e8b745d1746
4 | 629e6f8cc668fe30222690055bc13aae37d3c2acaaa992a9ffffffff55555556
5 | 521d817b8c8fe0ff7e0b745318e0fe2a40c8936413b058ebc4ec4ec462762763
6 | 336878f3307623cb7c59ab7002c086dcf35ac1256db6636d6db6db6d6db6db6e
7 | 4ee5260a3853fe8ce81ed99de300fbbe930fcef08887a887ffffffff77777778
8 | 1000000000000000000000000000000000000000000000000000000000000000
9 | 2a560940be7f68c5b1b341e3c607f697d777ea5b0f0eac3bffffffffc3c3c3c4
10 | 26a11bc2ae0808b28f46e64cadfa19888da1265cccd20cd0000000033333333
11 | 2c59c154f04b2e0d209627474791ca2f8396d8008ba29c5ce8ba2e8b745d1746
12 | 629e6f8cc668fe30222690055bc13aae37d3c2acaaa992a9ffffffff55555556
13 | 521d817b8c8fe0ff7e0b745318e0fe2a40c8936413b058ebc4ec4ec462762763
14 | 336878f3307623cb7c59ab7002c086dcf35ac1256db6636d6db6db6d6db6db6e
15 | 4ee5260a3853fe8ce81ed99de300fbbe930fcef08887a887ffffffff77777778
16 | 1000000000000000000000000000000000000000000000000000000000000000
17 | 2a560940be7f68c5b1b341e3c607f697d777ea5b0f0eac3bffffffffc3c3c3c4
18 | 686382243ccfd33827d7a80640616f2096770dc971c5d5c6555555548e38e38f
19 | 2c59c154f04b2e0d209627474791ca2f8396d8008ba29c5ce8ba2e8b745d1746
20 | 629e6f8cc668fe30222690055bc13aae37d3c2acaaa992a9ffffffff55555556
21 | 521d817b8c8fe0ff7e0b745318e0fe2a40c8936413b058ebc4ec4ec462762763
22 | 336878f3307623cb7c59ab7002c086dcf35ac1256db6636d6db6db6d6db6db6e
23 | 4ee5260a3853fe8ce81ed99de300fbbe930fcef08887a887ffffffff77777778
24 | 1000000000000000000000000000000000000000000000000000000000000000
25 | 2a560940be7f68c5b1b341e3c607f697d777ea5b0f0eac3bffffffffc3c3c3c4
26 | 686382243ccfd33827d7a80640616f2096770dc971c5d5c6555555548e38e38f
27 | 1fc7355df918dde2fa9d580144e3a8d86b89bb94af2829791af286bc79435e51
28 | 629e6f8cc668fe30222690055bc13aae37d3c2acaaa992a9ffffffff55555556
29 | 521d817b8c8fe0ff7e0b745318e0fe2a40c8936413b058ebc4ec4ec462762763
30 | 336878f3307623cb7c59ab7002c086dcf35ac1256db6636d6db6db6d6db6db6e
31 | 4ee5260a3853fe8ce81ed99de300fbbe930fcef08887a887ffffffff77777778
32 | 1000000000000000000000000000000000000000000000000000000000000000
33 | 2a560940be7f68c5b1b341e3c607f697d777ea5b0f0eac3bffffffffc3c3c3c4
34 | 686382243ccfd33827d7a80640616f2096770dc971c5d5c6555555548e38e38f
35 | 1fc7355df918dde2fa9d580144e3a8d86b89bb94af2829791af286bc79435e51
36 | 3b2bdc87aa3efee9ae1723366a40bcceee4bdb346665be65ffffffff9999999a
37 | 521d817b8c8fe0ff7e0b745318e0fe2a40c8936413b058ebc4ec4ec462762763
38 | 336878f3307623cb7c59ab7002c086dcf35ac1256db6636d6db6db6d6db6db6e
39 | 4ee5260a3853fe8ce81ed99de300fbbe930fcef08887a887ffffffff77777778
40 | 1000000000000000000000000000000000000000000000000000000000000000
41 | 2a560940be7f68c5b1b341e3c607f697d777ea5b0f0eac3bffffffffc3c3c3c4
42 | 686382243ccfd33827d7a80640616f2096770dc971c5d5c6555555548e38e38f
43 | 1fc7355df918dde2fa9d580144e3a8d86b89bb94af2829791af286bc79435e51
44 | 3b2bdc87aa3efee9ae1723366a40bcceee4bdb346665be65ffffffff9999999a
45 | 48ea33132e2dec4a63f9ba4d5a60f73fbe266219f3ce60f3492492489e79e79f
46 | 336878f3307623cb7c59ab7002c086dcf35ac1256db6636d6db6db6d6db6db6e
47 | 4ee5260a3853fe8ce81ed99de300fbbe930fcef08887a887ffffffff77777778
48 | 1000000000000000000000000000000000000000000000000000000000000000
49 | 2a560940be7f68c5b1b341e3c607f697d777ea5b0f0eac3bffffffffc3c3c3c4
50 | 686382243ccfd33827d7a80640616f2096770dc971c5d5c6555555548e38e38f
51 | 1fc7355df918dde2fa9d580144e3a8d86b89bb94af2829791af286bc79435e51
52 | 3b2bdc87aa3efee9ae1723366a40bcceee4bdb346665be65ffffffff9999999a
53 | 48ea33132e2dec4a63f9ba4d5a60f73fbe266219f3ce60f3492492489e79e79f
54 | 162ce0aa78259706904b13a3a3c8e517c1cb6c0045d14e2e745d1745ba2e8ba3
55 | 4ee5260a3853fe8ce81ed99de300fbbe930fcef08887a887ffffffff77777778
56 | 1000000000000000000000000000000000000000000000000000000000000000
57 | 2a560940be7f68c5b1b341e3c607f697d777ea5b0f0eac3bffffffffc3c3c3c4
58 | 686382243ccfd33827d7a80640616f2096770dc971c5d5c6555555548e38e38f
59 | 1fc7355df918dde2fa9d580144e3a8d86b89bb94af2829791af286bc79435e51
60 | 3b2bdc87aa3efee9ae1723366a40bcceee4bdb346665be65ffffffff9999999a
61 | 48ea33132e2dec4a63f9ba4d5a60f73fbe266219f3ce60f3492492489e79e79f
62 | 162ce0aa78259706904b13a3a3c8e517c1cb6c0045d14e2e745d1745ba2e8ba3
63 | 6170efc625d5398afdc17ffa689a8b1daf7c1378590c4591642c8591642c859
64 | 1000000000000000000000000000000000000000000000000000000000000000
65 | 2a560940be7f68c5b1b341e3c607f697d777ea5b0f0eac3bffffffffc3c3c3c4
66 | 686382243ccfd33827d7a80640616f2096770dc971c5d5c6555555548e38e38f
67 | 1fc7355df918dde2fa9d580144e3a8d86b89bb94af2829791af286bc79435e51
68 | 3b2bdc87aa3efee9ae1723366a40bcceee4bdb346665be65ffffffff9999999a
69 | 48ea33132e2dec4a63f9ba4d5a60f73fbe266219f3ce60f3492492489e79e79f
70 | 162ce0aa78259706904b13a3a3c8e517c1cb6c0045d14e2e745d1745ba2e8ba3
71 | 6170efc625d5398afdc17ffa689a8b1daf7c1378590c4591642c8591642c859
72 | 314f37c663347f1811134802ade09d571be9e1565554c954ffffffffaaaaaaab
73 | 2a560940be7f68c5b1b341e3c607f697d777ea5b0f0eac3bffffffffc3c3c3c4
74 | 686382243ccfd33827d7a80640616f2096770dc971c5d5c6555555548e38e38f
75 | 1fc7355df918dde2fa9d580144e3a8d86b89bb94af2829791af286bc79435e51
76 | 3b2bdc87aa3efee9ae1723366a40bcceee4bdb346665be65ffffffff9999999a
77 | 48ea33132e2dec4a63f9ba4d5a60f73fbe266219f3ce60f3492492489e79e79f
78 | 162ce0aa78259706904b13a3a3c8e517c1cb6c0045d14e2e745d1745ba2e8ba3
79 | 6170efc625d5398afdc17ffa689a8b1daf7c1378590c4591642c8591642c859
80 | 314f37c663347f1811134802ade09d571be9e1565554c954ffffffffaaaaaaab
81 | 1826c228b312e612e76d575d1fe038a47ab05b5c851e85eb6666666647ae147b
82 |
--------------------------------------------------------------------------------
/poseidon_constants/pre_sparse_matrix_ff/pre_sparse_matrix_ff_9.txt:
--------------------------------------------------------------------------------
1 | 5cd95cf5500229281c7578047721063bd930778fe38d4f8daaaaaaaa1c71c71d
2 | 5af7310f714af42f8111b0e51ccdecca129f01a21285bf4c0cf9b5092a09fadc
3 | 2fcd74e4d241c2b43473b32b6d2b38713447261d83bec97c032c5dbcf589b4dc
4 | 1377447987b7b82747f59b52e801efc237d95c4235013276442f4218edb98b25
5 | 6ed258c11dd3e92f38525ad1e537213cc851dbe89595bf269415edce6f01ed3e
6 | 6f32f1479a578cc93ed9cf1913cb21d5183aeafd6f47febde74a5597d8c01b72
7 | 1330c90fbf4c108a82a9557731aacb7f5e0a46cded0f8eca84467ab8f8fede24
8 | 5ec1004ffeeb5b19a368e25ceeb5d588ed7461e55a3afedf71e79cc72a958c54
9 | 300a8b11d8240ad5a127153837de64677cb6ba792501065692fcbac4086dd7bc
10 | 26a11bc2ae0808b28f46e64cadfa19888da1265cccd20cd0000000033333333
11 | c9e4b2f2574895016314e8e51e4dc0be2ce83ca40ba46fe9f48ec09eca2cbf
12 | 6ca356aba3c6d3051810e5675865f34d344091d7e5f7130d1448e2da7c088254
13 | 6bddeed58ed330235de0f187d5cd9ff4f55d249b8c68bad0111b052d2595f9cf
14 | 38dcb36cb689adbfceab6bd2c66db3a312ac5c76920dfacf6489b8a6e57abf0d
15 | 560c6b7a2173171bea8e4b372b9708591baf0793401516d6de46f093693e017d
16 | 460fabe95f08dc6f86155fa415c298be3902451e7851890329f0e824951e4a40
17 | 2329be65a7f8d6840673d3eef76939b4d69c99813404ba4588cac586ff1874f2
18 | 62dcf8a2a99b248cf9eb57ece491381ca98d5a0f8bfaeef4544d0aa63d57a813
19 | 2c59c154f04b2e0d209627474791ca2f8396d8008ba29c5ce8ba2e8b745d1746
20 | 6ca356aba3c6d3051810e5675865f34d344091d7e5f7130d1448e2da7c088254
21 | 4d8562d6924c0c936ba4ba7bf95520672783739c78cf1889302e81f3ce88277d
22 | 6a5e9315e047b48bc8ad553d093fe5c4d07b15b468949f9ef169d01a7ab4ae15
23 | 61c325e7484a00d30881b9495b7566790b14c9a85d2fb9499743cff01906e9f0
24 | 13d974b3478565de14e3c8fb872bee0aed3b0aa662806d6d04bfe109db0365a0
25 | 4aa47b9b992774232f36d89c24bb29bdf1a99654fc880181281dba2c3c4deba1
26 | 2fae6443cfd4019977789b19c6041d7cada6d1b9683421b8e0ed05650ca875e5
27 | 417490236aa5398ccabd839a416f1bd0895476ac32e8265fb2f8663445f55cba
28 | 629e6f8cc668fe30222690055bc13aae37d3c2acaaa992a9ffffffff55555556
29 | 6bddeed58ed330235de0f187d5cd9ff4f55d249b8c68bad0111b052d2595f9cf
30 | 6a5e9315e047b48bc8ad553d093fe5c4d07b15b468949f9ef169d01a7ab4ae15
31 | 2c0bb77f030681e2867784a47cf698d97cbd73926dbf559d684fa66c48b6be4d
32 | 56e0a9dff4e51ed01d2cbd39ab79a3ff2d800d0769807df87ae9d548a0b5c8db
33 | 6d4b6fd9d7068dd8e3ce1a6b949e01a7f9ecbb6954d486c23ea79d928d31e1fb
34 | 5d2f26a4e1e33d1353a7ae11a8312d4f7ba200af6bf977294df96acb19ff58ca
35 | 289624559156d71b826b0f7df6aaf8e60e19845025682c0aba6d60b50022fdbd
36 | 21653a9d03325193ffa49f4edd43af78fcbcd8677909e3147dc945c62762584f
37 | 521d817b8c8fe0ff7e0b745318e0fe2a40c8936413b058ebc4ec4ec462762763
38 | 38dcb36cb689adbfceab6bd2c66db3a312ac5c76920dfacf6489b8a6e57abf0d
39 | 61c325e7484a00d30881b9495b7566790b14c9a85d2fb9499743cff01906e9f0
40 | 56e0a9dff4e51ed01d2cbd39ab79a3ff2d800d0769807df87ae9d548a0b5c8db
41 | 3120e3b83a6f9e0c88e2210563d071ed564b3c2371f6ae12942da15cb4584fcc
42 | 3d3fe7512e8c130a6183b760325dc21e6986c90556bcc099cda7ca87854186f5
43 | 686e7728d8e7277f6871414c76d35956fbe54ed21cb5b6ba7843befddf7037c8
44 | 4c63a6241edba92d3993229290be12b8a3ce8c593d10c3d6853f58fb207f58e3
45 | 477c32cf4ff8ee74f62a432e68c0942216caff6c11bb17c081bb7f83856af896
46 | 336878f3307623cb7c59ab7002c086dcf35ac1256db6636d6db6db6d6db6db6e
47 | 560c6b7a2173171bea8e4b372b9708591baf0793401516d6de46f093693e017d
48 | 13d974b3478565de14e3c8fb872bee0aed3b0aa662806d6d04bfe109db0365a0
49 | 6d4b6fd9d7068dd8e3ce1a6b949e01a7f9ecbb6954d486c23ea79d928d31e1fb
50 | 3d3fe7512e8c130a6183b760325dc21e6986c90556bcc099cda7ca87854186f5
51 | 2c271357a5bae475ea78679e98664012d84220ed2c5126fc6bd5770bf50915b1
52 | 56f7569326d01da5966de3363569ea52a410477175bea44ef7b9d409e1c689c0
53 | 3509f6a3a4ad7f83a9cca2e8c8232135d1d322f9233dff8cc089940843776d1c
54 | 3cd8760ee40660f5934f465243213d0145de7d1874b7909f44e48785b2726dfa
55 | 4ee5260a3853fe8ce81ed99de300fbbe930fcef08887a887ffffffff77777778
56 | 460fabe95f08dc6f86155fa415c298be3902451e7851890329f0e824951e4a40
57 | 4aa47b9b992774232f36d89c24bb29bdf1a99654fc880181281dba2c3c4deba1
58 | 5d2f26a4e1e33d1353a7ae11a8312d4f7ba200af6bf977294df96acb19ff58ca
59 | 686e7728d8e7277f6871414c76d35956fbe54ed21cb5b6ba7843befddf7037c8
60 | 56f7569326d01da5966de3363569ea52a410477175bea44ef7b9d409e1c689c0
61 | 2897360218689ec9034dc0ca210c2c2e6cc480dd175d11f826f345abc8397257
62 | 4cea8683dd9997312f53cc1d1e3dd066d2928df838c54e1c323fbbe605e484b6
63 | 25424bca582695dad0cf15af89d6fff61cd3dedc995905886c2193acdad14ae7
64 | 1000000000000000000000000000000000000000000000000000000000000000
65 | 2329be65a7f8d6840673d3eef76939b4d69c99813404ba4588cac586ff1874f2
66 | 2fae6443cfd4019977789b19c6041d7cada6d1b9683421b8e0ed05650ca875e5
67 | 289624559156d71b826b0f7df6aaf8e60e19845025682c0aba6d60b50022fdbd
68 | 4c63a6241edba92d3993229290be12b8a3ce8c593d10c3d6853f58fb207f58e3
69 | 3509f6a3a4ad7f83a9cca2e8c8232135d1d322f9233dff8cc089940843776d1c
70 | 4cea8683dd9997312f53cc1d1e3dd066d2928df838c54e1c323fbbe605e484b6
71 | 5b0ea47c49e54a8949b5ac44bc4d03e7d6b3bdac7c5914a6cec40a74ae51a542
72 | 3a5f57a8bf594bfc6e63cb3c9c4f4bea16c2790c3a678b58870ee149a5d1ac57
73 | 2a560940be7f68c5b1b341e3c607f697d777ea5b0f0eac3bffffffffc3c3c3c4
74 | 62dcf8a2a99b248cf9eb57ece491381ca98d5a0f8bfaeef4544d0aa63d57a813
75 | 417490236aa5398ccabd839a416f1bd0895476ac32e8265fb2f8663445f55cba
76 | 21653a9d03325193ffa49f4edd43af78fcbcd8677909e3147dc945c62762584f
77 | 477c32cf4ff8ee74f62a432e68c0942216caff6c11bb17c081bb7f83856af896
78 | 3cd8760ee40660f5934f465243213d0145de7d1874b7909f44e48785b2726dfa
79 | 25424bca582695dad0cf15af89d6fff61cd3dedc995905886c2193acdad14ae7
80 | 3a5f57a8bf594bfc6e63cb3c9c4f4bea16c2790c3a678b58870ee149a5d1ac57
81 | 36b3f71122dfee4322d02f20994fa1328e9146d146bf9569a2e945a460c82ee6
82 |
--------------------------------------------------------------------------------
/poseidon_constants/compressed_round_constants/compressed_round_constants_3.txt:
--------------------------------------------------------------------------------
1 | 0x669f064bfa3ae17a23bd51861dbb4a24501eac92a2758b36a7320a009d6ed3d8
2 | 0x0a61a8defbacca36e4537ff2c84fa66ceee67c9645ac27346e72ab842b9d3f15
3 | 0x21e9cefa24b89d09f91b1e8a45df275b17292b4e1aaa49301e234771128165d5
4 | 0x0bfc421d38531805382624c9d2d2d02b1f2f5590316c401b2f5f56ca2f12a0d1
5 | 0x13b0ae4a89035df0c3d3fcf4686942e8beccf44e15ef3bf5ffca19f35a8bc5c8
6 | 0x4b9addf98d64d0b4c1417481e426d040f1aac43c1fd12d20f83841b245aa3943
7 | 0x2c24c3856581c7149b2eda9cefa1cf3cc6bf1a2c3fba2b2472256501cc024538
8 | 0x61f92179479718029d91289f1a323cf6b8af610e3c2f8f42d5d1c1d33a51c665
9 | 0x1236dfa5abb3bf324a52476a08f456b4eff0f0f1132af1379fca6ec5a9165c40
10 | 0x59cd6edc11a8caf8cd6011fb967561525e971dc7e93debfd0ca417f4c22e5f63
11 | 0x65aac0a0a09c16817a58ca73edd20ee4322e57a2f551c1a8e574b361d64137f3
12 | 0x19f871c9bc44940f268b267e80579859c00ab3180e60f6618435b003b7433fe0
13 | 0x713fcab884bfd08e8f9c136139ae3a792622591b5de7509b2641c09aea0a3b9a
14 | 0x2137e69e882dfba1e84193a1c3d9dcfbaab690321163cb1ac50d630388357041
15 | 0x5590950aa71d8ce93cf3b553914cbdbc785f875e08e4f236bc87371864fcbeb2
16 | 0x15ea0de59c6ae7c8b21fd309ef84aba77c2d8e8139c9c08f5cca2138d161fdfd
17 | 0x490d03d2b54da88afebf20b082dd1df2ef57d1f5c22cfedc36ad01257e55df0f
18 | 0x61a362de5f6e86f0328206c43037b4fa6d998f568584756e626b6495ac4aaf43
19 | 0x5788188851bfb10f844ca386350a39716bbe93447677a2f16a789bc85c3717dc
20 | 0x578bf19b7ef10c031b56c4c599b92ea26411f5ca29277bafaaffe629df559709
21 | 0x2834bdb4bd049ae9aa231b154488643acb2ef2fb55e4ee823c677884054a4cc7
22 | 0x558f4008f1ae728e9ebe42ca584ca233e75f1828951daf3b1c43bd2c13553484
23 | 0x0be5a1a175c83f94c92e693dd48dd7f3f2643f05404a684438e775ff2ea36861
24 | 0x450980a0e66035f3916ef2d342f511ea818baf56a04b0f2bc94b6729e936ec26
25 | 0x0d2129697397018ae174869cf75268138cfabfb4f7d364fc276e7696de4c29fe
26 | 0x4e5e676b2b3555e54e6fb9e0a846775395ca50fdc17cf2ef8d938bf283a7cfae
27 | 0x2a15f60edc1f825ec66a676e13644c34dddfe849e5b47c945c4c3d19f3855124
28 | 0x5865e57d47e0a5933dc5e6e82c72deb4a2cae7592f25a189d5bf207d5c3add6f
29 | 0x362d9d5f6fb361f885729095808b3870fbba5ca0b3e74512fb2169c57962ec59
30 | 0x6a63ba9f7b9a5d26d51d529ca0f4f6e63a5252247fa778265a33cdd2c2ebe09f
31 | 0x6f7db3e777ac0728e89b6284937f5bc57360c71e3ea01dcf76248b37ecedb9da
32 | 0x72e049a299b4c01d755cd67a374c75e8d8302e752d1e31c5e7eb174df3c79151
33 | 0x66e141ead35048c7cc590ccfee0a980ae01f7115ee773679077ea78bed30b3e2
34 | 0x2e032e691b04eae635db7f594377d1d035585311c2068e51ec164c63e9243bd4
35 | 0x32bc02497721afe6df383cdf31578a5dcbc48ea4a3e88c1d5eef5224c767a95e
36 | 0x5bef039a2fb68a94e2c320d0b68c1270932f76090beadc843b949f956a9f1ede
37 | 0x25c6f8bd945ce03a59d6c06550fa5d6581d110ef102ec9ac13e690a7d0bf47c0
38 | 0x71e71d955f7f79f448e258b1898e84f3304b34611f3b04a8e17e0d5ca52f6185
39 | 0x40467b587ddb35d1c7df0ba3e71d0b3cfb0cf74f2a12119e87e67bd469435d47
40 | 0x097becd4af55811f7d23233c9d2dfbf5da6aebefc5283fd9d0139922b6c1f63e
41 | 0x2c913a8c0b779b2eec8a3b33d1b74f74fa8872635c704e2b139affe3de90e179
42 | 0x31c043e2807a8563ab9bd62fab9d853e7954108d993b0acc4c83781e40033c63
43 | 0x5d49a43f01fce19be18a2b56369bc6168fe05cff11b7ed65fb8dcbf6129a77a9
44 | 0x503140a019bdde3f9ca8518853fea9745bd30fa41926f7a7a1e54917bebd1959
45 | 0x0d2c48b5009cda788905bb25aa02f8b7d74a009288aed5ddb0c71cb297928b1f
46 | 0x23ef01c0d6f624c092d06e3def7535439c4ab2880116b59274963d6f4efcfaf3
47 | 0x6dd6e28ee3fce2175a38df3a62373c32ba5d132c4709bc690f8ca15e21276eb0
48 | 0x3514b140f2a8f9f1c5abe7275e49639095d477a23b0185900a669d4bccd11b50
49 | 0x601a7bf5efaa64320da7a34c4074681a40b58814bef4347050109b3b514c694d
50 | 0x11c2d475d07dcbc241b18f96187a5d3580ac1ebdbf98e7532839c650f233fc1d
51 | 0x5d10f0e3d327f06546668d53366f6ef9980b13420f37c1ac72591c5398a1d878
52 | 0x57ecbaef596d4e0967205fe1d5d0456acad0fe4b6055befafc40e6ec498dae1b
53 | 0x0d4a937c99b8b057e46fa0357fe7a043d10107a6c94891d14674a4541c62fa41
54 | 0x6d3bda46d1c6b862674d902d96002b93708ab217cc3c5b2ea8d127b224d60a4b
55 | 0x4d70a4c89d59f8315f5fe0005b1dde4202dd24d2b1f0d5506c89a201f203d6df
56 | 0x5ad28fab208f6abd693bb1e73bf428910f9c0ffd2b43ba02032e58bc94c35449
57 | 0x5e97039e8a5254e8afffcda9f51b7bcf570ca4da75fd0e313796d545cd9200f4
58 | 0x2d96e4a68760097d7fe53dff337da724b24d679a3885337afc7d61546d093f62
59 | 0x6989852e8353d2143f9d85bc3967f00794a5d8b384a94562b3cd492e3da41a3d
60 | 0x4b65945c8832d7832b8f7b912e7032889c9380870378c89553401d3ebf88e7c7
61 | 0x021638c05edaef75580ed73429657ad2f5bb36cd81337c91fd6e032516e1311a
62 | 0x6932a3d49d0516c006e9f214e6d64c0f4eaaae5f2cc0e183896117c5ad1a42ff
63 | 0x006595c8b8d5748e53f1652317e17ef9241fffe86cc279798b66fe238c518fa8
64 | 0x5e33d95d9120d62f822160030a5471a6b93b8b224a85eeace5718f7799885ff3
65 | 0x31c1333d03d8d48bae9c2e0a912c60ae4519897d184ad60e89efd16bfbf74854
66 | 0x0b60dc9a923984ec480b4dc5cb32332df1faef605d5cc6646513a8e3a8ed7e68
67 | 0x60b019ee1b13c73d145ba1b8b29b44d1c0b86cc6824071ebe4845304aad9660a
68 | 0x589e16c1fa152213cb343eaf0e51a30454030d38ba496f3c752e0c7f40c60ac5
69 | 0x16058f7f5678c48a0efce2f0404576c25545708d64780dee10f4cd06ad9c4778
70 | 0x583c8dc2fc9dc59369ad9eea83e71500a2724395a6d8533c89aabbfed742d331
71 | 0x24edc9984eeb8a91eeafadbdeb685dbea22f906abf027e839ec05365cbd770d8
72 | 0x47345bcfcb497bfbc8901d63845acc630661090cd1a43859108ef616df8d0d0d
73 | 0x163f682ea8cf8906483703f9bcc01d13f24198b89dd7dd30181fd56613b14e96
74 | 0x305ead1ea4dc91ce08e43af0c70b95b359ee2284f90f565c29b22d11fc2241f3
75 | 0x6a2d44c577afde17c71a41e9685c029469aba392e19c8f3157971381b2e30e9a
76 | 0x494e57dbcba7ecbd2bd69b8782b14d390a3ff51370e6aad0015774404116d02f
77 | 0x4926608d2cc060a348e2bccfbbc3bd4ea9a80723397f4a798b7ce683bea48aa5
78 | 0x089e407086a906aa3193e5083ce789186dfb0323c89c0827020e9499db789207
79 | 0x1c84e3e9450113a4b5489decd8dcc8b25f057797f37899354931a0eea88d7d5d
--------------------------------------------------------------------------------
/src/main/scala/poseidon/PoseidonThread.scala:
--------------------------------------------------------------------------------
1 | package poseidon
2 |
3 | import spinal.core._
4 | import spinal.lib._
5 |
6 | case class BasicContextCase(g: PoseidonGenerics) extends BasicContext(g) {}
7 | case class ContextCase(g: PoseidonGenerics) extends Context(g) {}
8 |
9 | object PoseidonThread {
10 | def apply(g: PoseidonGenerics, input: Flow[Context]): Flow[MDSContext] = {
11 | val threadInst = new PoseidonThread(g)
12 | threadInst.io.input << input
13 | threadInst.io.output
14 | }
15 | }
16 |
17 | class PoseidonThread(g: PoseidonGenerics) extends Component {
18 |
19 | val io = new Bundle {
20 | val input = slave Flow (new Context(g))
21 | val output = master Flow (MDSContext(g))
22 | }
23 |
24 | // set configuration parameters of Xilinx Multiplier IP implemented through LUTs
25 | val mulIPConfig1 = MulIPConfig(
26 | inputWidth = 34,
27 | outputWidth = 68,
28 | pipeStages = 6,
29 | moduleName = "mult_gen_0"
30 | )
31 |
32 | // set configuration parameters of Xilinx Multiplier IP implemented through DSP slices
33 | val mulIPConfig2 = MulIPConfig(
34 | inputWidth = 34,
35 | outputWidth = 68,
36 | pipeStages = 6,
37 | moduleName = "mult_gen_1"
38 | )
39 |
40 | // set configuration parameters of MontgomeryMult implemented through Xilinx Multiplier IP
41 | val montMultConfig = MontMultConfig(
42 | dataWidth = g.dataWidth,
43 | rWidth = g.dataWidth + 1,
44 | modulus = PoseidonParam.modulus,
45 | modInverse = PoseidonParam.modInverse,
46 | compensation = PoseidonParam.compensation,
47 | isSim = g.isSim
48 | )
49 |
50 | // set configuration parameters of Xilinx Adder IP implemented through LUT
51 | val adderIPConfig0 = AdderIPConfig(
52 | inputWidth = 255,
53 | outputWidth = 256,
54 | latency = 16,
55 | moduleName = "c_addsub_0"
56 | )
57 |
58 | // set configuration parameters of ModularAdderFlow implemented through Xilinx Adder IP
59 | val modAdderConfig = ModAdderConfig(
60 | dataWidth = g.dataWidth,
61 | modulus = PoseidonParam.modulus,
62 | compensation = PoseidonParam.compensation,
63 | isSim = g.isSim
64 | )
65 |
66 | // SBox5 Stage // 47 * 3 = 141 stages
67 | val SBox5Stage = new Area {
68 | val input = io.input
69 |
70 | // the first Montgomery Multiplier
71 | val mulInput0 =
72 | input.translateWith(operands(input.stateElement, input.stateElement))
73 | val montMultiplier0 = MontgomeryMultFlow(montMultConfig, mulIPConfig1)
74 | montMultiplier0.io.input << mulInput0
75 | val mulRes0 = montMultiplier0.io.output
76 |
77 | // the second Montgomery Multiplier
78 | val mulInput1 = mulRes0.translateWith(operands(mulRes0.res, mulRes0.res))
79 | val montMultiplier1 = MontgomeryMultFlow(montMultConfig, mulIPConfig1)
80 | montMultiplier1.io.input << mulInput1
81 | val mulRes1 = montMultiplier1.io.output
82 | val tempContext1 = Delay(
83 | input.payload,
84 | montMultiplier0.totalLatency + montMultiplier1.totalLatency
85 | )
86 |
87 | // the third Montgomery Multiplier
88 | val mulInput2 = mulRes1.translateWith {
89 | operands(mulRes1.res, tempContext1.stateElement)
90 | }
91 | val montMultiplier2 = MontgomeryMultFlow(montMultConfig, mulIPConfig2)
92 | montMultiplier2.io.input << mulInput2
93 | val mulRes2 = montMultiplier2.io.output
94 |
95 | val mul2Context = BasicContextCase(g)
96 | mul2Context.assignSomeByName(tempContext1)
97 | val tempContext2 = Delay(mul2Context, montMultiplier2.totalLatency)
98 |
99 | val output = mulRes2.translateWith {
100 | val payload = new ContextCase(g)
101 | payload.assignSomeByName(tempContext2)
102 | payload.stateElement := mulRes2.res
103 | payload
104 | }
105 | }
106 |
107 | val AddRoundConstantStage = new Area { // 33 stages
108 | val input = SBox5Stage.output
109 |
110 | //TODO: Synchronous memory read
111 |
112 | // get adder operands
113 | val adderOperands = operands(g.dataWidth)
114 | adderOperands.op1 := input.stateElement
115 | val constantMemory = RoundConstantMem(g)
116 | constantMemory.io.addr.assignSomeByName(input.payload)
117 | adderOperands.op2 := constantMemory.io.data
118 |
119 | val modAdder = ModularAdderFlow(modAdderConfig, adderIPConfig0)
120 | modAdder.io.input << input.translateWith(adderOperands)
121 | val adderContext = BasicContextCase(g)
122 | adderContext.assignSomeByName(input.payload)
123 | val adderContextDelayed = Delay(adderContext, modAdder.totalLatency)
124 |
125 | val output = modAdder.io.output.translateWith {
126 | val payload = ContextCase(g)
127 | payload.assignSomeByName(adderContextDelayed)
128 | payload.stateElement := modAdder.io.output.res
129 | payload
130 | }
131 | }
132 |
133 | // MDS Mixing
134 | val mdsMulOutput = // 49 stages
135 | MDSMatrixMultiplier(
136 | g,
137 | montMultConfig,
138 | mulIPConfig2,
139 | AddRoundConstantStage.output.stage()
140 | )
141 | // MDS Addition
142 | io.output << MDSMatrixAdders(g, mdsMulOutput) //partial_3 9 stages
143 |
144 | }
145 |
146 | object PoseidonThreadVerilog {
147 | def main(args: Array[String]): Unit = {
148 | val config = PoseidonGenerics(
149 | sizeMax = 12,
150 | roundp = 57,
151 | roundf = 8,
152 | dataWidth = 255,
153 | idWidth = 8,
154 | isSim = true
155 | )
156 |
157 | SpinalConfig(
158 | mode = Verilog,
159 | targetDirectory = "./src/main/verilog/"
160 | ).generate(new PoseidonThread(config))
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/src/tests/AXI4StreamReceiverTester.py:
--------------------------------------------------------------------------------
1 | from math import ceil
2 | import cocotb
3 | import random
4 | from cocotb.clock import Clock
5 | from cocotb.result import TestSuccess, TestFailure
6 | from cocotb.triggers import RisingEdge
7 | from queue import Queue
8 | from poseidon_python import basic
9 |
10 | from cocotb_test import simulator
11 |
12 | CASES_NUM = 1000 # the number of test cases
13 |
14 |
15 | class AXI4StreamReceiverTester:
16 | def __init__(self, target) -> None:
17 | self.dut = target
18 | self.ref_outputs = Queue(maxsize=80) # store reference results
19 | self.cases_count = 0
20 |
21 | async def reset_dut(self):
22 | dut = self.dut
23 | dut.reset.value = 0
24 | await RisingEdge(dut.clk)
25 | dut.reset.value = 1
26 | for i in range(2):
27 | await RisingEdge(dut.clk)
28 |
29 | dut.reset.value = 0
30 |
31 | def get_random_input(self):
32 | size_range = [3, 5, 9, 12]
33 | rand_size = size_range[random.randint(0, 3)]
34 | rand_vec = []
35 |
36 | for i in range(12):
37 | if i < rand_size:
38 | rand_vec.append(random.randint(0, basic.P - 1))
39 | else:
40 | rand_vec.append(0)
41 | return rand_size, rand_vec
42 |
43 | def check_state_elements(self, ref_res):
44 | dut = self.dut
45 | dut_res = []
46 | for i in range(12):
47 | exec(
48 | f"dut_res.append(dut.io_output_payload_state_elements_{i}.value.integer)"
49 | )
50 | for i in range(12):
51 | if dut_res[i] != ref_res[i]:
52 | return False, dut_res
53 |
54 | return True, dut_res
55 |
56 | async def drive_input_ports(self):
57 | """generate input signals"""
58 | dut = self.dut
59 | while self.cases_count < CASES_NUM:
60 | # get random values
61 | state_size, state_elements = self.get_random_input()
62 | # assign random values to dut io port
63 | for state_index in range(state_size):
64 |
65 | dut.io_input_valid.value = random.random() > 0.3
66 | dut.io_input_payload.value = state_elements[state_index]
67 | dut.io_input_last.value = state_index == (state_size - 1)
68 | await RisingEdge(dut.clk)
69 |
70 | while (dut.io_input_valid.value & dut.io_input_ready.value) == False:
71 | dut.io_input_valid.value = random.random() > 0.3
72 | await RisingEdge(dut.clk)
73 |
74 | dut.io_input_valid.value = False
75 |
76 | state_id = self.cases_count % pow(2, 5)
77 | self.ref_outputs.put([state_id, state_size, state_elements])
78 |
79 | self.cases_count += 1
80 |
81 | async def check_output_ports(self):
82 | """check output signals"""
83 | dut = self.dut
84 |
85 | while True:
86 | # get random ready signals
87 | dut.io_output_ready.value = random.random() > 0.3
88 | await RisingEdge(dut.clk)
89 | if (dut.io_output_ready.value & dut.io_output_valid.value) == True:
90 | id, size, elements = self.ref_outputs.get()
91 | dut_id = int(dut.io_output_payload_state_id.value)
92 | dut_size = int(dut.io_output_payload_state_size.value)
93 |
94 | elements_equal, dut_elements = self.check_state_elements(elements)
95 | if (dut_size != size) | (not elements_equal) | (dut_id != id):
96 | print(
97 | "reference output: \nstate_size:{}\nstate_id:{}".format(
98 | size, id
99 | )
100 | )
101 | print("state_elements:")
102 | for i in range(12):
103 | print(hex(elements[i]))
104 |
105 | print(
106 | "dut output: \nstate_size:{}\nstate_id:{}".format(
107 | dut_size, dut_id
108 | )
109 | )
110 | print("state_elements:")
111 | for i in range(12):
112 | print(hex(dut_elements[i]))
113 |
114 | raise TestFailure("test case {} failed".format(self.cases_count))
115 |
116 | if (self.cases_count == CASES_NUM) & self.ref_outputs.empty():
117 | raise TestSuccess(" pass {} test cases".format(CASES_NUM))
118 |
119 |
120 | @cocotb.test(timeout_time=200000, timeout_unit="ns")
121 | async def AXI4StreamReceiverTest(dut):
122 | await cocotb.start(Clock(dut.clk, 10, "ns").start())
123 |
124 | # set default values to all dut input ports
125 | dut.io_input_valid.value = False
126 | dut.io_input_last.value = False
127 | dut.io_input_payload.value = 0
128 | dut.io_output_ready.value = False
129 |
130 | # start testing
131 | tester = AXI4StreamReceiverTester(dut)
132 | await tester.reset_dut()
133 | await cocotb.start(tester.drive_input_ports())
134 | await cocotb.start(tester.check_output_ports())
135 |
136 | while True:
137 | await RisingEdge(dut.clk)
138 |
139 |
140 | # pytest
141 | def test_AXI4StreamReceiver():
142 | simulator.run(
143 | verilog_sources=["../main/verilog/AXI4StreamReceiver.v"],
144 | toplevel="AXI4StreamReceiver",
145 | module="AXI4StreamReceiverTester",
146 | python_search="./src/reference_model/",
147 | )
148 |
--------------------------------------------------------------------------------
/poseidon_constants/pre_sparse_matrix/pre_sparse_matrix_9.txt:
--------------------------------------------------------------------------------
1 | 0x19c308bd25b13848eef068e557794c72f62a247271c6bf1c38e38e38aaaaaaab
2 | 0x48a2a8dd9fda9644ef97501c5a819cddf743c3aab06762eea537d5a901dc24b8
3 | 0x4ce387bba3a50855092b1272b73be67fc49352a40f54a3c65c52445ab538f803
4 | 0x2544149503581962104e388809f131f61fa720ca7cec9b2e983a5ce41e931107
5 | 0x633b9a53ed76d8da91f4e310080d87337ff57ee2468de82f3d6cc39134266a35
6 | 0x678431ee3f69c9eae672f73c33d0b00997154c63c5bbb0f4bc088a20df238f57
7 | 0x410f7f912a450fd161b6e43a5202bf493298734540549fc6e5f6b0e636f70edb
8 | 0x64cdcddc566a664a8f80ecac9fd58160e1ec1edf74b9202f5d00308cc07dd78f
9 | 0x41fb1f210b312d0fefbf8c378fea543afe2d83c673d226662e93675cef30c8cd
10 | 0x22c74bcc2615a595a8f7c0cf3616f401991f4acdb332b532e66666661999999a
11 | 0x2ab02e414e808d28d3a456fa378b04e88e8628a1b076fa0826b555717b1007e8
12 | 0x2863d8f95cc187704a6629f0fe6499250fe09a7d59fddb38afa823abe2811e1c
13 | 0x0b17b58bcd93401ed9bd37d678f159db5342e330f3154bf1ca3c24ddbffe164e
14 | 0x3837893aecd67dabbffffd28ff2fe17d978636775309bbc500acf229fb62a4ef
15 | 0x732d1c1e4fa66d40286ac706a3894d357840d9820f3bc9aaa693e900ba66f526
16 | 0x12f7eb0363c274581c76508594eb17fbbf5ca9b08879462d5f04c73f761d1c7e
17 | 0x37d951955a8edae35deaf213fc8fcbf5fbd91264a50a5b736b9976dec44cfe66
18 | 0x18eb1302cb712fface0870bdc2b364daf1141d407f95f22b02b174986be5f1a4
19 | 0x6963af62e003892a5d1d50074e93217934daf23145cff68aba2e8ba200000001
20 | 0x2863d8f95cc187704a6629f0fe6499250fe09a7d59fddb38afa823abe2811e1c
21 | 0x1c17afe5dc48593597a1fa9ffdbacab7a4f291ce84dd3b1dd7028d474274f620
22 | 0x14fb86aa7bd1af6f441a21c79b5aaeaa819e8deb3d275440fd1cab16f5f1238f
23 | 0x095b066179f6ff886935b751f8492a2ff681aa5bf669386d5ff6c6762ae641a1
24 | 0x41f3b17f30da60fbe1569cfecbcdc98c5a12e0c1de339030314b548fec1dcccb
25 | 0x240a7994607ee28b58150d4f67a8baf86848af01d20008b8efa9eb235536eafd
26 | 0x48cec1298f793cc2fd97e2f08d5d4eacaa15fb69df206511e30e61a08d28a250
27 | 0x3504121a213d215e65c942bfe34b298b46cd9260b48ccaee3ac5518a6a2b727f
28 | 0x6a44840c3b7b082cd99fb0b208d45b5a376dd6581553d4546aaaaaa9c0000001
29 | 0x0b17b58bcd93401ed9bd37d678f159db5342e330f3154bf1ca3c24ddbffe164e
30 | 0x14fb86aa7bd1af6f441a21c79b5aaeaa819e8deb3d275440fd1cab16f5f1238f
31 | 0x62c72f07cd1cb4f0e00a5338db9dcf0cf4554e9102484f45f95961ea50d090df
32 | 0x2bd355c7a0ac26db9b1a8a9d0f268472502d19b6af85bdfc24cd585beee19640
33 | 0x62b8df58ed6eafe1be93d3e04253ab90c2342c5e9c7cd78429e93ad03110d8e5
34 | 0x4ce3e7e8598b4ba8f00a865f7df4852c8be55daa83908c7b3bc26d768c4077d9
35 | 0x3e5e168d02e3be9bcae8f0b3038c3973a2ff8e269186000e5aba42e350a0681a
36 | 0x1adc4bdc7123904ed735af348fd9a950bbb2204b309cc23f6a93152f9bc907d6
37 | 0x6217dc5a0f85429f8dce7bb808267bb5bd02ed3d9d88753a3b13b13a3b13b13c
38 | 0x3837893aecd67dabbffffd28ff2fe17d978636775309bbc500acf229fb62a4ef
39 | 0x095b066179f6ff886935b751f8492a2ff681aa5bf669386d5ff6c6762ae641a1
40 | 0x2bd355c7a0ac26db9b1a8a9d0f268472502d19b6af85bdfc24cd585beee19640
41 | 0x2c29ffcfed7bc2716d41133ac1c1603d469e22ba2d2f56867cd469f4c637b7d2
42 | 0x58df0a2a5c9eaa4e36f14b07dc8c1a449fb1a6ead2db7a3d264d3534b777ba71
43 | 0x6451000335ef325155d6970fa8c21672682ab80f217d58e55b5c387f4e7392d2
44 | 0x6201e7be4e6a1c508b3f04b36722da4efd39d87c4a2231206e5e292cab3337b8
45 | 0x3b6b40bdc68d1946cc65a60a135b55cdf9b9e917e6c6bfbcc26e86af83482a63
46 | 0x4a867dda0877876545809d29bd0c9d27fef9e96fa4913b23edb6db6d12492493
47 | 0x732d1c1e4fa66d40286ac706a3894d357840d9820f3bc9aaa693e900ba66f526
48 | 0x41f3b17f30da60fbe1569cfecbcdc98c5a12e0c1de339030314b548fec1dcccb
49 | 0x62b8df58ed6eafe1be93d3e04253ab90c2342c5e9c7cd78429e93ad03110d8e5
50 | 0x58df0a2a5c9eaa4e36f14b07dc8c1a449fb1a6ead2db7a3d264d3534b777ba71
51 | 0x11d321a0f81b72d066669200238fea4f662d669620bfead2855211f9c71cb2c4
52 | 0x32cc6c3b0617144d5f461893313b38a6ffc70118b55a15780679372e77b97ba6
53 | 0x194501111a85dcdbff1f17a0b071c6235dd57a33854209b0812f16e2d3d58405
54 | 0x0b3f27325ff47f6b1f90638aaf9fe37b629ee000c18a5814f03e233b7973cb84
55 | 0x3dd414f92742ed7bd70dc88cd1efeaad81febddf77769776eeeeeeee66666667
56 | 0x12f7eb0363c274581c76508594eb17fbbf5ca9b08879462d5f04c73f761d1c7e
57 | 0x240a7994607ee28b58150d4f67a8baf86848af01d20008b8efa9eb235536eafd
58 | 0x4ce3e7e8598b4ba8f00a865f7df4852c8be55daa83908c7b3bc26d768c4077d9
59 | 0x6451000335ef325155d6970fa8c21672682ab80f217d58e55b5c387f4e7392d2
60 | 0x32cc6c3b0617144d5f461893313b38a6ffc70118b55a15780679372e77b97ba6
61 | 0x29a7aa5e4090f82137307c73321f2589bd478478f5865a706a8b276db71f5693
62 | 0x07ebb7a69fade28941a85ae0047362d3d0eae68a5bfb6e656f0fc12ad12e9b67
63 | 0x407ac7761d3e323aac20d4c4b5c8e35907454e24c212a732a5dc1eeb68c19928
64 | 0x6caeccddf703a573b0063a878907ba84fe81c9c2cffe763f0fffffff10000001
65 | 0x37d951955a8edae35deaf213fc8fcbf5fbd91264a50a5b736b9976dec44cfe66
66 | 0x48cec1298f793cc2fd97e2f08d5d4eacaa15fb69df206511e30e61a08d28a250
67 | 0x3e5e168d02e3be9bcae8f0b3038c3973a2ff8e269186000e5aba42e350a0681a
68 | 0x6201e7be4e6a1c508b3f04b36722da4efd39d87c4a2231206e5e292cab3337b8
69 | 0x194501111a85dcdbff1f17a0b071c6235dd57a33854209b0812f16e2d3d58405
70 | 0x07ebb7a69fade28941a85ae0047362d3d0eae68a5bfb6e656f0fc12ad12e9b67
71 | 0x5fd1e4ccc94879482505a7eaa080e44325b85894f94ff504243b4f911e488375
72 | 0x093ffadeed9f6225f59595b6b92b26dd8f1da8fcd4d559ef3bdb430b6538e061
73 | 0x1b46fa31af7059b6a2a432d4b6f8e788c868db4bffff9d2cf0f0f0f0b4b4b4b5
74 | 0x18eb1302cb712fface0870bdc2b364daf1141d407f95f22b02b174986be5f1a4
75 | 0x3504121a213d215e65c942bfe34b298b46cd9260b48ccaee3ac5518a6a2b727f
76 | 0x1adc4bdc7123904ed735af348fd9a950bbb2204b309cc23f6a93152f9bc907d6
77 | 0x3b6b40bdc68d1946cc65a60a135b55cdf9b9e917e6c6bfbcc26e86af83482a63
78 | 0x0b3f27325ff47f6b1f90638aaf9fe37b629ee000c18a5814f03e233b7973cb84
79 | 0x407ac7761d3e323aac20d4c4b5c8e35907454e24c212a732a5dc1eeb68c19928
80 | 0x093ffadeed9f6225f59595b6b92b26dd8f1da8fcd4d559ef3bdb430b6538e061
81 | 0x12e485eb966a327be7830fef891172aaa3b231925a87ba700853b32f6da82524
--------------------------------------------------------------------------------
/src/main/scala/poseidon/ModularAdder.scala:
--------------------------------------------------------------------------------
1 | package poseidon
2 | import spinal.core._
3 | import spinal.lib._
4 |
5 | case class AdderIPConfig(
6 | inputWidth: Int,
7 | outputWidth: Int,
8 | latency: Int,
9 | moduleName: String
10 | )
11 |
12 | object AdderIP {
13 | def apply(
14 | g: AdderIPConfig,
15 | inputA: UInt,
16 | inputB: UInt
17 | ): UInt = {
18 | val multiplierInst = AdderIP(g).setDefinitionName(g.moduleName)
19 | multiplierInst.io.inputA := inputA
20 | multiplierInst.io.inputB := inputB
21 | multiplierInst.io.outputS
22 | }
23 | }
24 |
25 | case class AdderIP(g: AdderIPConfig) extends BlackBox {
26 | val io = new Bundle {
27 | val clk = in Bool ()
28 | val inputA, inputB = in UInt (g.inputWidth bits)
29 | val outputS = out UInt (g.outputWidth bits)
30 | }
31 |
32 | // map clock and reset signal
33 | mapClockDomain(clock = io.clk)
34 |
35 | //Remove io_ prefix
36 | noIoPrefix()
37 |
38 | //Function used to rename all signals of the blackbox
39 | private def renameIO(): Unit = {
40 | io.clk.setName("CLK")
41 | io.inputA.setName("A")
42 | io.inputB.setName("B")
43 | io.outputS.setName("S")
44 | }
45 |
46 | //Execute the function renameIO after the creation of the component
47 | addPrePopTask(() => renameIO())
48 | }
49 |
50 | // SimAdderIP with same behavior as Xilinx Adder IP used For Simulation
51 | object SimAdderIP {
52 | def apply(
53 | g: AdderIPConfig,
54 | inputA: UInt,
55 | inputB: UInt
56 | ): UInt = {
57 | val adderInst = SimAdderIP(g)
58 | adderInst.io.inputA := inputA
59 | adderInst.io.inputB := inputB
60 | adderInst.io.outputS
61 | }
62 | }
63 |
64 | case class SimAdderIP(g: AdderIPConfig) extends Component {
65 | val io = new Bundle {
66 | val inputA, inputB = in UInt (g.inputWidth bits)
67 | val outputS = out UInt (g.outputWidth bits)
68 | }
69 |
70 | val adderRes = io.inputA +^ io.inputB
71 | val stages = History(adderRes, g.latency + 1)
72 | io.outputS := stages.last.resize(g.outputWidth)
73 | }
74 |
75 | // wrap Xilinx Adder IP with Flow interface
76 | object AdderIPFlow {
77 | def apply(
78 | g: AdderIPConfig,
79 | isSim: Boolean,
80 | input: Flow[operands]
81 | ): Flow[results] = {
82 | val multiplierInst = AdderIPFlow(g, isSim)
83 | multiplierInst.io.input << input
84 | multiplierInst.io.output
85 | }
86 | }
87 |
88 | case class AdderIPFlow(g: AdderIPConfig, isSim: Boolean) extends Component {
89 |
90 | val io = new Bundle {
91 | val input = slave Flow (operands(g.inputWidth))
92 | val output = master Flow (results(g.outputWidth))
93 | }
94 |
95 | val validDelayed = Delay(io.input.valid, g.latency, init = False)
96 | io.output.valid := validDelayed
97 |
98 | val adderRes = if (isSim) {
99 | SimAdderIP(g, io.input.op1, io.input.op2)
100 | } else {
101 | AdderIP(g, io.input.op1, io.input.op2)
102 | }
103 |
104 | io.output.res := adderRes
105 | }
106 |
107 | case class ModAdderConfig(
108 | dataWidth: Int,
109 | modulus: BigInt,
110 | compensation: BigInt,
111 | isSim: Boolean
112 | )
113 |
114 | object ModularAdderFlow {
115 | def apply(
116 | config: ModAdderConfig,
117 | ipConfig: AdderIPConfig,
118 | input: Flow[operands]
119 | ): Flow[results] = {
120 | val modAdderInst = ModularAdderFlow(config, ipConfig)
121 | modAdderInst.io.input << input
122 | modAdderInst.io.output
123 | }
124 | }
125 |
126 | case class ModularAdderFlow(config: ModAdderConfig, ipConfig: AdderIPConfig)
127 | extends Component {
128 |
129 | val io = new Bundle {
130 | val input = slave Flow (operands(config.dataWidth))
131 | val output = master Flow (results(config.dataWidth))
132 | }
133 |
134 | require(config.dataWidth == ipConfig.inputWidth)
135 | require(config.dataWidth + 1 == ipConfig.outputWidth)
136 |
137 | val adderRes1 = AdderIPFlow(ipConfig, config.isSim, io.input)
138 |
139 | val adderInput2 = adderRes1.translateWith {
140 | operands(
141 | ipConfig.inputWidth,
142 | adderRes1.res.resized,
143 | U(config.compensation, ipConfig.inputWidth bits)
144 | )
145 | }
146 |
147 | val adderRes2 = AdderIPFlow(ipConfig, config.isSim, adderInput2)
148 | val res1Delayed = Delay(adderRes1.res, ipConfig.latency)
149 |
150 | io.output << adderRes2
151 | .translateWith {
152 | val payload = results(config.dataWidth)
153 | payload.res := Mux(
154 | adderRes2.res.msb | res1Delayed.msb,
155 | adderRes2.res,
156 | res1Delayed
157 | ).resized
158 | payload
159 | }
160 | .stage()
161 |
162 | val totalLatency = ipConfig.latency * 2 + 1
163 | }
164 |
165 | object AdderIPFlowVerilog {
166 | def main(args: Array[String]): Unit = {
167 | val config = AdderIPConfig(
168 | inputWidth = 255,
169 | outputWidth = 256,
170 | latency = 5,
171 | moduleName = "adder0"
172 | )
173 | SpinalConfig(
174 | mode = Verilog,
175 | targetDirectory = "./src/main/verilog"
176 | ).generate(AdderIPFlow(config, false))
177 | }
178 | }
179 |
180 | object ModularAdderFlowVerilog {
181 | def main(args: Array[String]): Unit = {
182 | val ipConfig = AdderIPConfig(
183 | inputWidth = 255,
184 | outputWidth = 256,
185 | latency = 6,
186 | moduleName = "adder0"
187 | )
188 | val config = ModAdderConfig(
189 | 255,
190 | PoseidonParam.modulus,
191 | PoseidonParam.compensation,
192 | true
193 | )
194 | SpinalConfig(
195 | mode = Verilog,
196 | targetDirectory = "./src/main/verilog"
197 | ).generate(ModularAdderFlow(config, ipConfig))
198 | }
199 | }
200 |
--------------------------------------------------------------------------------
/src/tests/MDSMatrixMultiplierTester.py:
--------------------------------------------------------------------------------
1 | import cocotb
2 | import random
3 | from cocotb.clock import Clock
4 | from cocotb.result import TestSuccess, TestFailure
5 | from cocotb.triggers import RisingEdge
6 | from queue import Queue
7 |
8 |
9 | from poseidon_python import finite_field as ff
10 | from poseidon_python import basic
11 | from poseidon_python.poseidon_ff import *
12 |
13 | from BasicElements import Context, MDSContext
14 |
15 | CASES_NUM = 2000
16 |
17 |
18 | class MDSMatrixMultiplierTester:
19 | def __init__(self, target, isFull=None, size=None, id=None):
20 | self.dut = target
21 | self.ref_outputs = Queue(maxsize=100)
22 | self.ref_inputs = Queue(maxsize=100)
23 | self.isFull = isFull
24 | self.size = size
25 | self.id = id
26 |
27 | def reference_model(self, context: Context):
28 | size = context.state_size
29 | ref_output = MDSContext(
30 | context.isFull,
31 | context.full_round,
32 | context.partial_round,
33 | context.state_size,
34 | context.state_id,
35 | )
36 | if context.isFull:
37 | mds_input_ff = (
38 | [ff.PrimeField(0)] * context.state_index
39 | + [context.state_element]
40 | + [ff.PrimeField(0)] * (context.state_size - context.state_index - 1)
41 | )
42 | if context.full_round == (Context.roundf / 2 - 1):
43 | matrix = transform_matrix(
44 | read_pre_sparse_matrix(size, "../../poseidon_constants")
45 | )
46 | else:
47 | matrix = transform_matrix(basic.PrimeFieldOps.get_mds_matrix(size))
48 | ref_output.copy_state_elements(mds_mixing_ff(mds_input_ff, matrix))
49 | else:
50 | w_hat, v_rest = read_sparse_matrix(size, "../../poseidon_constants")
51 | sparse_w_ff = transform_matrix(w_hat)[context.partial_round]
52 | sparse_v_ff = transform_matrix(v_rest)[context.partial_round]
53 | res = []
54 | if size < 9:
55 | res.append(context.state_element.mul(sparse_w_ff[0]))
56 | for i in range(1, size):
57 | res.append(context.state_element.mul(sparse_v_ff[i - 1]))
58 | res[i].addassign(context.state_elements[i - 1])
59 | for i in range(size - 1):
60 | res.append(context.state_elements[i].mul(sparse_w_ff[i + 1]))
61 | else:
62 | res.append(context.state_element.mul(sparse_w_ff[0]))
63 | if context.state_index == 0:
64 | for i in range(1, size):
65 | res.append(context.state_element.mul(sparse_v_ff[i - 1]))
66 | res[i].addassign(context.state_elements[i - 1])
67 | else:
68 | for i in range(size - 1):
69 | res.append(context.state_elements[i].mul(sparse_w_ff[i + 1]))
70 | ref_output.copy_state_elements(res)
71 | return ref_output
72 |
73 | async def reset_dut(self):
74 | self.dut.reset.value = 1
75 | for i in range(3):
76 | await RisingEdge(self.dut.clk)
77 |
78 | self.dut.reset.value = 0
79 |
80 | async def drive_input_ports(self):
81 | """generate input signals"""
82 | cases_count = 0
83 | while cases_count < CASES_NUM:
84 | # get random dut inputs
85 | context = Context()
86 | context.set_rand_values(isFull=self.isFull, size=self.size, id=self.id)
87 |
88 | # assign dut io port
89 | self.dut.io_input_valid.value = True # random.random()>0.2
90 | context.set_dut_ports(self.dut)
91 | await RisingEdge(self.dut.clk)
92 |
93 | if self.dut.io_input_valid.value == True:
94 | cases_count += 1
95 | # get reference output
96 | ref_output = self.reference_model(context)
97 |
98 | self.ref_outputs.put(ref_output)
99 | self.ref_inputs.put(context)
100 |
101 | self.dut.io_input_valid.value = False
102 |
103 | async def monitor_output_ports(self):
104 | """check output signals"""
105 | count_cases = 0
106 |
107 | while count_cases < CASES_NUM:
108 | await RisingEdge(self.dut.clk)
109 |
110 | if self.dut.io_output_valid.value == True:
111 | count_cases += 1
112 | ref_output = self.ref_outputs.get()
113 | ref_input = self.ref_inputs.get()
114 | dut_output = MDSContext()
115 | dut_output.get_dut_ports(self.dut)
116 |
117 | if not dut_output.check_context_equal(ref_output):
118 | print("INPUT: ")
119 | ref_input.print_context_info()
120 | print("REF:")
121 | ref_output.print_context_info()
122 | print("DUT:")
123 | dut_output.print_context_info()
124 | raise TestFailure("test case {} failed: ".format(count_cases))
125 |
126 | raise TestSuccess(" pass {} test cases".format(CASES_NUM))
127 |
128 |
129 | @cocotb.test(timeout_time=4000000, timeout_unit="ns")
130 | async def MDSMatrixMultiplierTest(dut):
131 | await cocotb.start(Clock(dut.clk, 10, "ns").start())
132 |
133 | dut.io_input_valid.value = False
134 | initial_input = Context()
135 | initial_input.set_dut_ports(dut)
136 |
137 | tester = MDSMatrixMultiplierTester(dut)
138 |
139 | await tester.reset_dut()
140 | await cocotb.start(tester.drive_input_ports())
141 | await cocotb.start(tester.monitor_output_ports())
142 |
143 | while True:
144 | await RisingEdge(dut.clk)
145 |
--------------------------------------------------------------------------------
/src/main/scala/poseidon/AXI4StreamInterface.scala:
--------------------------------------------------------------------------------
1 | package poseidon
2 |
3 | import spinal.core._
4 | import spinal.lib._
5 | import spinal.lib.fsm._
6 |
7 | object AXI4StreamReceiver {
8 | def apply(g: PoseidonGenerics, input: AXI4Stream): Stream[MDSContext] = {
9 | val receiver = new AXI4StreamReceiver(g)
10 | receiver.io.input.connectFrom(input)
11 | receiver.io.output
12 | }
13 | }
14 |
15 | class AXI4StreamReceiver(g: PoseidonGenerics) extends Component {
16 |
17 | val io = new Bundle {
18 | val input = slave(AXI4Stream(g.dataWidth))
19 | val output = master Stream (MDSContext(g))
20 | }
21 |
22 | // deserialize the serial input from AXIStream Bus to get stateSize
23 | val receiver = new Area {
24 | val output = Stream(MDSContext(g))
25 |
26 | val sizeCounter = Reg(UInt(log2Up(g.sizeMax) bits)) init (0)
27 | val idCounter = Reg(UInt(g.idWidth bits)) init (0)
28 | val buffer = Vec(Reg(UInt(g.dataWidth bits)), g.sizeMax)
29 | buffer.foreach(_ init (0))
30 |
31 | val receiverFSM = new StateMachine {
32 | io.input.ready := False
33 | output.valid := False
34 | output.isFull := True
35 | output.fullRound := 0
36 | output.partialRound.setAll()
37 | output.stateSize := 0
38 | output.stateID := 0
39 | output.stateElements.foreach(_ := 0)
40 |
41 | val BUSY = new State with EntryPoint
42 | val DONE = new State
43 |
44 | BUSY
45 | .whenIsActive {
46 | io.input.ready := True
47 | when(io.input.fire()) {
48 | buffer(sizeCounter) := io.input.payload
49 | sizeCounter := sizeCounter + 1
50 | when(io.input.last) { goto(DONE) }
51 | }
52 | }
53 |
54 | DONE
55 | .whenIsActive {
56 | output.valid := True
57 | output.stateSize := sizeCounter
58 | output.stateID := idCounter
59 | (output.stateElements lazyZip buffer).foreach(_ := _)
60 |
61 | when(output.fire) {
62 | io.input.ready := True
63 | buffer.foreach(_ := 0)
64 | idCounter := idCounter + 1
65 | sizeCounter := 0
66 | goto(BUSY)
67 | when(io.input.fire()) {
68 | buffer(0) := io.input.payload
69 | sizeCounter := 1
70 | }
71 | }
72 | }
73 | }
74 | }
75 |
76 | io.output << receiver.output.stage()
77 | }
78 |
79 | case class TransmitterContext(g: PoseidonGenerics) extends Bundle {
80 | val stateID = UInt(g.idWidth bits)
81 | val stateElement = UInt(g.dataWidth bits)
82 | }
83 |
84 | object AXI4StreamTransmitter {
85 | def apply(
86 | g: PoseidonGenerics,
87 | input: Stream[TransmitterContext]
88 | ): AXI4Stream = {
89 | val transmitterInst = new AXI4StreamTransmitter(g)
90 | transmitterInst.io.input << input
91 | transmitterInst.io.output
92 | }
93 | }
94 |
95 | class AXI4StreamTransmitter(g: PoseidonGenerics) extends Component {
96 |
97 | val io = new Bundle {
98 | val input = slave Stream (TransmitterContext(g))
99 | val output = master(AXI4Stream(g.dataWidth))
100 | }
101 |
102 | val idCounter = Reg(UInt(g.idWidth bits)) init (0)
103 | when(io.output.fire()) {
104 | idCounter := idCounter + 1
105 | }
106 |
107 | val loopback = Stream(TransmitterContext(g))
108 | val temp = StreamArbiterFactory.lowerFirst.onArgs(io.input, loopback).stage()
109 | val demuxOutputs = StreamDemux(temp, (temp.stateID === idCounter).asUInt, 2)
110 | io.output.last := True
111 | io.output.valid := demuxOutputs(1).valid
112 | demuxOutputs(1).ready := io.output.ready
113 | io.output.payload := demuxOutputs(1).stateElement
114 | loopback << demuxOutputs(0).queue(g.transmitterQueue).s2mPipe()
115 |
116 | // val inputTemp = io.input.s2mPipe().m2sPipe()
117 | // val outputTemp = inputTemp.queue(bufferDepth)
118 | // io.output.valid := outputTemp.valid
119 | // io.output.payload := outputTemp.state_element
120 | // io.output.last := True
121 | // outputTemp.ready := io.output.ready
122 |
123 | // val idCounter = Reg(UInt(g.id_width bits)) init (0)
124 | // when(io.output.fire()) {
125 | // idCounter := idCounter + 1
126 | // }
127 | // val input_demux = Vec(Stream(TransmitterContext(g)), bufferDepth)
128 | // val demux_select = OHToUInt(OHMasking.first(input_demux.map(_.ready)))
129 |
130 | // input_demux
131 | // .lazyZip(StreamDemux(io.input, demux_select, bufferDepth))
132 | // .foreach(_ << _)
133 |
134 | // val buffer = input_demux.map(_.stage())
135 | // val select = OHToUInt(
136 | // buffer
137 | // .map(_.valid)
138 | // .lazyZip(buffer.map(_.state_id))
139 | // .map(_ & _ === idCounter)
140 | // )
141 | // val buffer_out = StreamMux(select, buffer)
142 |
143 | // io.output.valid := buffer_out.valid && buffer_out.state_id === idCounter
144 | // io.output.last := True
145 | // io.output.payload := buffer_out.state_element
146 | // buffer_out.ready := io.output.ready && buffer_out.state_id === idCounter
147 | }
148 |
149 | object AXI4StreamReceiverVerilog {
150 |
151 | def main(args: Array[String]): Unit = {
152 | val config = PoseidonGenerics(
153 | sizeMax = 12,
154 | roundp = 57,
155 | roundf = 8,
156 | dataWidth = 255,
157 | idWidth = 8,
158 | isSim = true
159 | )
160 | SpinalConfig(
161 | mode = Verilog,
162 | targetDirectory = "./src/main/verilog"
163 | ).generate(new AXI4StreamReceiver(config))
164 | }
165 | }
166 |
167 | object AXI4StreamTransmitterVerilog {
168 |
169 | def main(args: Array[String]): Unit = {
170 |
171 | val config = PoseidonGenerics(
172 | sizeMax = 12,
173 | roundp = 57,
174 | roundf = 8,
175 | dataWidth = 255,
176 | idWidth = 8,
177 | isSim = true
178 | )
179 |
180 | SpinalConfig(
181 | mode = Verilog,
182 | targetDirectory = "./src/main/verilog"
183 | ).generate(new AXI4StreamTransmitter(config))
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/src/main/scala/poseidon/AdderTree.scala:
--------------------------------------------------------------------------------
1 | package poseidon
2 |
3 | import spinal.core._
4 | import spinal.lib._
5 |
6 | object ModAdderPipedFlow {
7 | val latency = 2
8 | def apply(width: Int, input: Flow[operands]): Flow[results] = {
9 | val adderInst = ModAdderPipedFlow(width, PoseidonParam.compensation)
10 | adderInst.io.input << input
11 | adderInst.io.output
12 | }
13 | }
14 |
15 | case class ModAdderPipedFlow(dataWidth: Int, compensation: BigInt)
16 | extends Component {
17 |
18 | val io = new Bundle {
19 | val input = slave Flow (operands(dataWidth))
20 | val output = master Flow (results(dataWidth))
21 | }
22 |
23 | val temp = io.input
24 | .translateWith(
25 | results(io.input.op1 +^ io.input.op2)
26 | )
27 | .stage()
28 |
29 | io.output << temp
30 | .translateWith {
31 | val tempRes =
32 | temp.res.resize(dataWidth) +^ U(compensation, dataWidth bits)
33 | val res =
34 | Mux(tempRes.msb | temp.res.msb, tempRes, temp.res).resize(dataWidth)
35 | results(res)
36 | }
37 | .stage()
38 | }
39 |
40 | object ModAdderPiped {
41 | def apply(
42 | g: ModAdderConfig,
43 | ip: AdderIPConfig,
44 | op1: UInt,
45 | op2: UInt
46 | ): (UInt, Int) = {
47 | val adderInst = ModAdderPiped(g, ip)
48 | adderInst.io.op1 := op1
49 | adderInst.io.op2 := op2
50 | (adderInst.io.res, adderInst.latency)
51 | }
52 | }
53 |
54 | case class ModAdderPiped(g: ModAdderConfig, ipConfig: AdderIPConfig)
55 | extends Component {
56 |
57 | val io = new Bundle {
58 | val op1, op2 = in UInt (g.dataWidth bits)
59 | val res = out UInt (g.dataWidth bits)
60 | }
61 |
62 | require(g.dataWidth.equals(ipConfig.inputWidth))
63 | require(ipConfig.outputWidth.equals(g.dataWidth + 1))
64 |
65 | val adderRes1 = if (g.isSim) {
66 | SimAdderIP(ipConfig, io.op1, io.op2)
67 | } else {
68 | AdderIP(ipConfig, io.op1, io.op2)
69 | }
70 |
71 | val adderRes2 = if (g.isSim) {
72 | SimAdderIP(
73 | ipConfig,
74 | adderRes1.resize(g.dataWidth),
75 | U(g.compensation, g.dataWidth bits)
76 | )
77 | } else {
78 | AdderIP(
79 | ipConfig,
80 | adderRes1.resize(g.dataWidth),
81 | U(g.compensation, g.dataWidth bits)
82 | )
83 | }
84 | val adderRes1Delayed = Delay(adderRes1, ipConfig.latency)
85 |
86 | io.res := Mux(
87 | adderRes1Delayed.msb | adderRes2.msb,
88 | adderRes2,
89 | adderRes1Delayed
90 | ).resize(g.dataWidth)
91 | val latency = 2 * ipConfig.latency
92 | }
93 |
94 | // SpinalHDL provide reduceBalanceTree that can implement adder tree
95 | // def reduceBalancedTree(op: (T, T) => T): T
96 | // operands.reduceBalancedTree(_+_)
97 |
98 | // adderTree implemented through recursion of scala
99 | object AdderTreeGenerator {
100 | def apply(
101 | g: ModAdderConfig,
102 | ip: AdderIPConfig,
103 | input: Vec[UInt]
104 | ): (UInt, Int) = {
105 | val opNum: Int = input.length
106 | if (opNum == 2) {
107 | val output = ModAdderPiped(g, ip, input(0), input(1))
108 | (output._1, output._2)
109 | } else {
110 | val adderOutputs =
111 | for (i <- 0 until opNum / 2)
112 | yield ModAdderPiped(g, ip, input(2 * i), input(2 * i + 1))
113 | if ((opNum % 2) == 0) {
114 | val next = Vec(UInt(g.dataWidth bits), opNum / 2)
115 | next.assignFromBits(adderOutputs.map(_._1).asBits())
116 | val (nextOutput, latency) = AdderTreeGenerator(g, ip, next)
117 | (nextOutput, latency + adderOutputs(0)._2)
118 |
119 | } else {
120 | val next = Vec(UInt(g.dataWidth bits), opNum / 2 + 1)
121 | val temp = Delay(input(opNum - 1), adderOutputs(0)._2)
122 | next.assignFromBits(temp.asBits ## adderOutputs.map(_._1).asBits())
123 | val (nextOutput, latency) = AdderTreeGenerator(g, ip, next)
124 | (nextOutput, latency + adderOutputs(0)._2)
125 | }
126 | }
127 | }
128 | }
129 |
130 | case class AdderTree(g: ModAdderConfig, ip: AdderIPConfig, opNum: Int)
131 | extends Component {
132 | val io = new Bundle {
133 | val input = slave Flow (Vec(UInt(g.dataWidth bits), opNum))
134 | val output = master Flow (UInt(g.dataWidth bits))
135 | }
136 |
137 | val (res, latency) = AdderTreeGenerator(g, ip, io.input.payload)
138 | println(latency)
139 | io.output.valid := Delay(io.input.valid, latency, init = False)
140 | io.output.payload := res
141 | }
142 |
143 | object ModAdderPipedFlowVerilog {
144 | def main(args: Array[String]): Unit = {
145 | SpinalConfig(
146 | mode = Verilog,
147 | targetDirectory = "./src/main/verilog/"
148 | ).generate(ModAdderPipedFlow(255, PoseidonParam.compensation))
149 | }
150 | }
151 |
152 | object ModAdderPipedVerilog {
153 | def main(args: Array[String]): Unit = {
154 | val adderIPConfig = AdderIPConfig(
155 | inputWidth = 255,
156 | outputWidth = 256,
157 | latency = 8,
158 | moduleName = "c_addsub_1"
159 | )
160 |
161 | val modAdderConfig = ModAdderConfig(
162 | dataWidth = 255,
163 | modulus = PoseidonParam.modulus,
164 | compensation = PoseidonParam.compensation,
165 | isSim = true
166 | )
167 |
168 | SpinalConfig(
169 | mode = Verilog,
170 | targetDirectory = "./src/main/verilog/"
171 | ).generate(ModAdderPiped(modAdderConfig, adderIPConfig))
172 | }
173 | }
174 |
175 | object AdderTreeVerilog {
176 | def main(args: Array[String]): Unit = {
177 |
178 | val adderIPConfig = AdderIPConfig(
179 | inputWidth = 255,
180 | outputWidth = 256,
181 | latency = 8,
182 | moduleName = "c_addsub_1"
183 | )
184 |
185 | // set configuration parameters of ModularAdderFlow implemented through Xilinx Adder IP
186 | val modAdderConfig = ModAdderConfig(
187 | dataWidth = 255,
188 | modulus = PoseidonParam.modulus,
189 | compensation = PoseidonParam.compensation,
190 | isSim = true
191 | )
192 |
193 | SpinalConfig(
194 | mode = Verilog,
195 | targetDirectory = "./src/main/verilog/"
196 | ).generate(AdderTree(modAdderConfig, adderIPConfig, 12))
197 | }
198 | }
199 |
--------------------------------------------------------------------------------