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