├── .eslintrc.cjs ├── .github ├── dependabot.yml └── workflows │ ├── ci.yml │ ├── integration-test.yml │ └── npm-publish.yml ├── .gitignore ├── COPYING ├── README.md ├── build └── main.cjs ├── c ├── calcwit.cpp ├── calcwit.hpp ├── circom.hpp ├── main.cpp ├── old │ ├── buildasm │ │ ├── add.asm.ejs │ │ ├── binops.asm.ejs │ │ ├── buildzqfield.js │ │ ├── buildzqfieldtester.js │ │ ├── cmpops.asm.ejs │ │ ├── cmpops_old.asm.ejs │ │ ├── copy.asm.ejs │ │ ├── fr.asm │ │ ├── fr.asm.ejs │ │ ├── fr.c │ │ ├── fr.c.ejs │ │ ├── fr.h │ │ ├── fr.h.ejs │ │ ├── fr.o │ │ ├── logicalops.asm.ejs │ │ ├── main.c │ │ ├── montgomery.asm.ejs │ │ ├── mul.asm.ejs │ │ ├── neg.asm.ejs │ │ ├── old │ │ │ ├── buildfieldasm.js │ │ │ ├── buildzqfield.js │ │ │ ├── buildzqfieldtester.js │ │ │ ├── fr.asm.ejs.old │ │ │ └── mul.asm.ejs │ │ ├── sub.asm.ejs │ │ ├── tester │ │ ├── tester.cpp │ │ ├── testet │ │ └── utils.asm.ejs │ ├── mainjson.cpp │ ├── zqfield.cpp │ └── zqfield.h ├── utils.cpp └── utils.hpp ├── calcwit.js ├── js ├── utils.js └── witness_calculator.js ├── main.js ├── package-lock.json ├── package.json ├── rollup.cjs.config.js └── test ├── circuit ├── circuit.circom ├── circuit.r1cs ├── circuit.zkey ├── circuit_js │ └── circuit.wasm ├── input.json └── verification_key.json └── witness_calc.test.js /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "env": { 3 | "es6": true, 4 | "node": true, 5 | "mocha": true 6 | }, 7 | "parserOptions": { 8 | "ecmaVersion": 2022, 9 | "sourceType": "module" 10 | }, 11 | "extends": "eslint:recommended", 12 | "rules": { 13 | "indent": [ 14 | "error", 15 | 4 16 | ], 17 | "linebreak-style": [ 18 | "error", 19 | "unix" 20 | ], 21 | "quotes": [ 22 | "error", 23 | "double" 24 | ], 25 | "semi": [ 26 | "error", 27 | "always" 28 | ] 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Enable version updates for npm 4 | - package-ecosystem: "npm" 5 | # Look for `package.json` and `lock` files in the `root` directory 6 | directory: "/" 7 | # Check the npm registry for updates every day (weekdays) 8 | schedule: 9 | interval: "daily" 10 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: JS Witness calc tests 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | 8 | jobs: 9 | test: 10 | name: Test 11 | runs-on: ${{ matrix.os }} 12 | 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | os: [ubuntu-latest] 17 | node-version: ["18", "20", "22"] 18 | 19 | steps: 20 | - name: Checkout project 21 | uses: actions/checkout@v4 22 | 23 | - name: Setup Node.js 24 | uses: actions/setup-node@v4 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | check-latest: true 28 | cache: 'npm' 29 | 30 | - name: Install dependencies 31 | run: npm ci 32 | 33 | - name: Run tests 34 | run: npm test 35 | -------------------------------------------------------------------------------- /.github/workflows/integration-test.yml: -------------------------------------------------------------------------------- 1 | name: Snarkjs Integration Test 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | 8 | jobs: 9 | test: 10 | name: Test 11 | runs-on: ${{ matrix.os }} 12 | 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | os: [ubuntu-latest] 17 | node-version: ["18", "20", "22"] 18 | 19 | steps: 20 | - name: Checkout project 21 | uses: actions/checkout@v4 22 | with: 23 | path: circom_runtime 24 | 25 | - name: Checkout project 26 | uses: actions/checkout@v4 27 | with: 28 | repository: iden3/snarkjs 29 | path: snarkjs 30 | 31 | - name: Setup Node.js 32 | uses: actions/setup-node@v4 33 | with: 34 | node-version: ${{ matrix.node-version }} 35 | check-latest: true 36 | cache: 'npm' 37 | cache-dependency-path: snarkjs/package-lock.json 38 | 39 | - name: Install circom_runtime dependencies 40 | run: npm ci 41 | working-directory: circom_runtime 42 | 43 | - name: Build circom_runtime 44 | run: npm run build 45 | working-directory: circom_runtime 46 | 47 | - name: Install circom_runtime to snarkjs as a link 48 | run: npm install ../circom_runtime 49 | working-directory: snarkjs 50 | 51 | - name: Install snarkjs dependencies 52 | run: npm ci 53 | working-directory: snarkjs 54 | 55 | - name: Build snarkjs 56 | run: npm run build 57 | working-directory: snarkjs 58 | 59 | - name: Run snarkjs tests 60 | run: npm test 61 | working-directory: snarkjs 62 | 63 | - name: Install smart_contract_tests dependencies 64 | working-directory: snarkjs/smart_contract_tests 65 | run: npm ci 66 | 67 | - name: Run smart_contract_tests 68 | working-directory: snarkjs/smart_contract_tests 69 | run: npm test 70 | 71 | - name: Install browser dependencies 72 | working-directory: snarkjs/browser_tests 73 | run: npm ci 74 | 75 | - name: Run browser tests 76 | working-directory: snarkjs/browser_tests 77 | run: npm test 78 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish package to NPM 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | publish-npm: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v4 12 | - uses: actions/setup-node@v4 13 | with: 14 | node-version: '20.x' 15 | registry-url: https://registry.npmjs.org/ 16 | cache: 'npm' 17 | - run: npm ci 18 | - run: npm run build 19 | - run: npm publish 20 | env: 21 | NODE_AUTH_TOKEN: ${{secrets.IDEN3_CIRCOM_NPM_PUBLISH_TOKEN}} 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | tmp 64 | 65 | .DS_Store 66 | 67 | # Workspace files are user-specific 68 | *.sublime-workspace 69 | 70 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2020 0Kinks Association 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # circom runtime 2 | 3 | This is the code needed to calculate the witness by a circuit compiled with [circom](https://github.com/iden3/circom). 4 | 5 | 6 | ## License 7 | 8 | Circom is part of the iden3 project copyright 2018 0KIMS association and published with Apache-2 license. Please check the COPYING file for more details. 9 | -------------------------------------------------------------------------------- /c/calcwit.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "calcwit.hpp" 12 | #include "utils.hpp" 13 | 14 | using namespace std::chrono_literals; 15 | 16 | Circom_CalcWit::Circom_CalcWit(Circom_Circuit *aCircuit) { 17 | circuit = aCircuit; 18 | 19 | signalAssigned = new bool[circuit->NSignals]; 20 | signalAssigned[0] = true; 21 | 22 | mutexes = new std::mutex[NMUTEXES]; 23 | cvs = new std::condition_variable[NMUTEXES]; 24 | inputSignalsToTrigger = new int[circuit->NComponents]; 25 | signalValues = new FrElement[circuit->NSignals]; 26 | 27 | // Set one signal 28 | Fr_copy(&signalValues[0], circuit->constants + 1); 29 | 30 | reset(); 31 | } 32 | 33 | 34 | Circom_CalcWit::~Circom_CalcWit() { 35 | 36 | delete[] signalAssigned; 37 | 38 | delete[] cvs; 39 | delete[] mutexes; 40 | 41 | delete[] signalValues; 42 | delete[] inputSignalsToTrigger; 43 | 44 | } 45 | 46 | void Circom_CalcWit::syncPrintf(const char *format, ...) { 47 | va_list args; 48 | va_start(args, format); 49 | 50 | printf_mutex.lock(); 51 | vprintf(format, args); 52 | printf_mutex.unlock(); 53 | 54 | va_end(args); 55 | } 56 | 57 | void Circom_CalcWit::reset() { 58 | 59 | #pragma omp parallel for 60 | for (int i=1; iNSignals; i++) { 61 | signalAssigned[i] = false; 62 | } 63 | 64 | #pragma omp parallel for 65 | for (int i=0; iNComponents; i++) { 66 | inputSignalsToTrigger[i] = circuit->components[i].inputSignals; 67 | } 68 | 69 | for (int i=circuit->NComponents-1; i>=0; i--) { 70 | if (inputSignalsToTrigger[i] == 0) triggerComponent(i); 71 | } 72 | } 73 | 74 | 75 | int Circom_CalcWit::getSubComponentOffset(int cIdx, u64 hash) { 76 | int hIdx; 77 | for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) { 78 | if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash)); 79 | } 80 | int entryPos = circuit->components[cIdx].hashTable[hIdx].pos; 81 | if (circuit->components[cIdx].entries[entryPos].type != _typeComponent) { 82 | throw std::runtime_error("invalid type"); 83 | } 84 | return circuit->components[cIdx].entries[entryPos].offset; 85 | } 86 | 87 | 88 | Circom_Sizes Circom_CalcWit::getSubComponentSizes(int cIdx, u64 hash) { 89 | int hIdx; 90 | for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) { 91 | if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash)); 92 | } 93 | int entryPos = circuit->components[cIdx].hashTable[hIdx].pos; 94 | if (circuit->components[cIdx].entries[entryPos].type != _typeComponent) { 95 | throw std::runtime_error("invalid type"); 96 | } 97 | return circuit->components[cIdx].entries[entryPos].sizes; 98 | } 99 | 100 | int Circom_CalcWit::getSignalOffset(int cIdx, u64 hash) { 101 | int hIdx; 102 | for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) { 103 | if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash)); 104 | } 105 | int entryPos = circuit->components[cIdx].hashTable[hIdx].pos; 106 | if (circuit->components[cIdx].entries[entryPos].type != _typeSignal) { 107 | throw std::runtime_error("invalid type"); 108 | } 109 | return circuit->components[cIdx].entries[entryPos].offset; 110 | } 111 | 112 | Circom_Sizes Circom_CalcWit::getSignalSizes(int cIdx, u64 hash) { 113 | int hIdx; 114 | for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) { 115 | if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash)); 116 | } 117 | int entryPos = circuit->components[cIdx].hashTable[hIdx].pos; 118 | if (circuit->components[cIdx].entries[entryPos].type != _typeSignal) { 119 | throw std::runtime_error("invalid type"); 120 | } 121 | return circuit->components[cIdx].entries[entryPos].sizes; 122 | } 123 | 124 | void Circom_CalcWit::getSignal(int currentComponentIdx, int cIdx, int sIdx, PFrElement value) { 125 | // char *s = Fr_element2str(value); 126 | // syncPrintf("getSignal: %d %s\n", sIdx, s); 127 | // delete s; 128 | if ((circuit->components[cIdx].newThread)&&(currentComponentIdx != cIdx)) { 129 | std::unique_lock lk(mutexes[cIdx % NMUTEXES]); 130 | while (!signalAssigned[sIdx]) { 131 | cvs[sIdx % NMUTEXES].wait_for(lk, 10ms); 132 | } 133 | lk.unlock(); 134 | } 135 | if (signalAssigned[sIdx] == false) { 136 | fprintf(stderr, "Accessing a not assigned signal: %d\n", sIdx); 137 | assert(false); 138 | } 139 | Fr_copy(value, signalValues + sIdx); 140 | /* 141 | char *valueStr = mpz_get_str(0, 10, *value); 142 | syncPrintf("%d, Get %d --> %s\n", currentComponentIdx, sIdx, valueStr); 143 | free(valueStr); 144 | */ 145 | } 146 | 147 | void Circom_CalcWit::multiGetSignal(int currentComponentIdx, int cIdx, int sIdx, PFrElement value, int n) { 148 | for (int i=0; i lk(mutexes[cIdx % NMUTEXES]); 156 | inputSignalsToTrigger[cIdx] = -1; 157 | } 158 | // syncPrintf("Finished: %d\n", cIdx); 159 | cvs[cIdx % NMUTEXES].notify_all(); 160 | } 161 | 162 | void Circom_CalcWit::setSignal(int currentComponentIdx, int cIdx, int sIdx, PFrElement value) { 163 | // syncPrintf("setSignal: %d\n", sIdx); 164 | 165 | if (signalAssigned[sIdx] == true) { 166 | fprintf(stderr, "Signal assigned twice: %d\n", sIdx); 167 | assert(false); 168 | } 169 | // Log assignement 170 | /* 171 | char *valueStr = mpz_get_str(0, 10, *value); 172 | syncPrintf("%d, Set %d --> %s\n", currentComponentIdx, sIdx, valueStr); 173 | free(valueStr); 174 | */ 175 | Fr_copy(signalValues + sIdx, value); 176 | signalAssigned[sIdx] = true; 177 | if ( BITMAP_ISSET(circuit->mapIsInput, sIdx) ) { 178 | if (inputSignalsToTrigger[cIdx]>0) { 179 | inputSignalsToTrigger[cIdx]--; 180 | if (inputSignalsToTrigger[cIdx] == 0) triggerComponent(cIdx); 181 | } else { 182 | fprintf(stderr, "Input signals does not match with map: %d\n", sIdx); 183 | assert(false); 184 | } 185 | } 186 | if ((circuit->components[currentComponentIdx].newThread)&&(currentComponentIdx == cIdx)) { 187 | // syncPrintf("Finished: %d\n", cIdx); 188 | cvs[sIdx % NMUTEXES].notify_all(); 189 | } 190 | 191 | } 192 | 193 | void Circom_CalcWit::checkConstraint(int currentComponentIdx, PFrElement value1, PFrElement value2, char const *err) { 194 | #ifdef SANITY_CHECK 195 | FrElement tmp; 196 | Fr_eq(&tmp, value1, value2); 197 | if (!Fr_isTrue(&tmp)) { 198 | char *pcV1 = Fr_element2str(value1); 199 | char *pcV2 = Fr_element2str(value2); 200 | // throw std::runtime_error(std::to_string(currentComponentIdx) + std::string(", Constraint doesn't match, ") + err + ". " + sV1 + " != " + sV2 ); 201 | fprintf(stderr, "Constraint doesn't match, %s: %s != %s", err, pcV1, pcV2); 202 | free(pcV1); 203 | free(pcV2); 204 | assert(false); 205 | } 206 | #endif 207 | } 208 | 209 | void Circom_CalcWit::checkAssert(int currentComponentIdx, PFrElement value1, char const *err) { 210 | #ifdef SANITY_CHECK 211 | FrElement tmp; 212 | if (!Fr_isTrue(value1)) { 213 | char *pcV1 = Fr_element2str(value1); 214 | // throw std::runtime_error(std::to_string(currentComponentIdx) + std::string(", Constraint doesn't match, ") + err + ". " + sV1 + " != " + sV2 ); 215 | fprintf(stderr, "Assert fail: %s", err); 216 | free(pcV1); 217 | assert(false); 218 | } 219 | #endif 220 | } 221 | 222 | void Circom_CalcWit::triggerComponent(int newCIdx) { 223 | //int oldCIdx = cIdx; 224 | // cIdx = newCIdx; 225 | if (circuit->components[newCIdx].newThread) { 226 | // syncPrintf("Triggered: %d\n", newCIdx); 227 | std::thread t(circuit->components[newCIdx].fn, this, newCIdx); 228 | // t.join(); 229 | t.detach(); 230 | } else { 231 | (*(circuit->components[newCIdx].fn))(this, newCIdx); 232 | } 233 | // cIdx = oldCIdx; 234 | } 235 | 236 | void Circom_CalcWit::log(PFrElement value) { 237 | char *pcV = Fr_element2str(value); 238 | syncPrintf("Log: %s\n", pcV); 239 | free(pcV); 240 | } 241 | 242 | void Circom_CalcWit::join() { 243 | for (int i=0; iNComponents; i++) { 244 | std::unique_lock lk(mutexes[i % NMUTEXES]); 245 | while (inputSignalsToTrigger[i] != -1) { 246 | cvs[i % NMUTEXES].wait_for(lk, 10ms); 247 | } 248 | // cvs[i % NMUTEXES].wait(lk, [&]{return inputSignalsToTrigger[i] == -1;}); 249 | lk.unlock(); 250 | // syncPrintf("Joined: %d\n", i); 251 | } 252 | 253 | } 254 | 255 | 256 | 257 | void Circom_CalcWit::iterateArr(int o, Circom_Sizes sizes, json jarr) { 258 | if (!jarr.is_array()) { 259 | assert((sizes[0] == 1)&&(sizes[1] == 0)); 260 | itFunc(o, jarr); 261 | } else { 262 | int n = sizes[0] / sizes[1]; 263 | for (int i=0; i(); 279 | } else if (val.is_number()) { 280 | 281 | double vd = val.get(); 282 | std::stringstream stream; 283 | stream << std::fixed << std::setprecision(0) << vd; 284 | s = stream.str(); 285 | } else { 286 | throw new std::runtime_error("Invalid JSON type"); 287 | } 288 | 289 | Fr_str2element (&v, s.c_str()); 290 | 291 | setSignal(0, 0, o, &v); 292 | } 293 | 294 | 295 | void Circom_CalcWit::calculateProve(void *wtns, json &input, std::function _isCanceledCB) { 296 | isCanceledCB = _isCanceledCB; 297 | reset(); 298 | for (json::iterator it = input.begin(); it != input.end(); ++it) { 299 | // std::cout << it.key() << " => " << it.value() << '\n'; 300 | u64 h = fnv1a(it.key()); 301 | int o; 302 | try { 303 | o = getSignalOffset(0, h); 304 | } catch (std::runtime_error e) { 305 | std::ostringstream errStrStream; 306 | errStrStream << "Error loading variable: " << it.key() << "\n" << e.what(); 307 | throw new std::runtime_error(errStrStream.str()); 308 | } 309 | Circom_Sizes sizes = getSignalSizes(0, h); 310 | iterateArr(o, sizes, it.value()); 311 | if (isCanceled()) break; 312 | } 313 | 314 | join(); 315 | 316 | if (!isCanceled()) { 317 | 318 | #pragma omp raw for 319 | for (unsigned int i=0;iNVars;i++) { 320 | FrElement v; 321 | getWitness(i, &v); 322 | Fr_toLongNormal(&v, &v); 323 | memcpy((uint8_t*)wtns + i*Fr_N64*8, v.longVal, Fr_N64*8); 324 | } 325 | } 326 | 327 | if (isCanceled()) throw new std::runtime_error("Aborted"); 328 | } 329 | 330 | void Circom_CalcWit::calculateProve(void *wtns, std::string &input, std::function _isCanceledCB) { 331 | 332 | json inputJson = json::parse(input, nullptr, false); 333 | if (inputJson.is_discarded()) throw new std::runtime_error("JSonParseError"); 334 | calculateProve(wtns, inputJson, _isCanceledCB); 335 | } 336 | 337 | 338 | 339 | -------------------------------------------------------------------------------- /c/calcwit.hpp: -------------------------------------------------------------------------------- 1 | #ifndef CIRCOM_CALCWIT_H 2 | #define CIRCOM_CALCWIT_H 3 | 4 | #include "circom.hpp" 5 | #include "fr.hpp" 6 | #include 7 | #include 8 | #include 9 | #include 10 | using json = nlohmann::json; 11 | 12 | #define NMUTEXES 128 13 | 14 | class Circom_CalcWit { 15 | 16 | bool *signalAssigned; 17 | 18 | // componentStatus -> For each component 19 | // >0 Signals required to trigger 20 | // == 0 Component triggered 21 | // == -1 Component finished 22 | int *inputSignalsToTrigger; 23 | std::mutex *mutexes; 24 | std::condition_variable *cvs; 25 | 26 | std::mutex printf_mutex; 27 | 28 | FrElement *signalValues; 29 | 30 | 31 | void triggerComponent(int newCIdx); 32 | void calculateWitness(void *input, void *output); 33 | 34 | void syncPrintf(const char *format, ...); 35 | bool isCanceled() { return isCanceledCB && isCanceledCB(); } 36 | 37 | void itFunc(int o, json val); 38 | void iterateArr(int o, Circom_Sizes sizes, json jarr); 39 | 40 | public: 41 | std::function isCanceledCB; 42 | Circom_Circuit *circuit; 43 | 44 | // Functions called by the circuit 45 | Circom_CalcWit(Circom_Circuit *aCircuit); 46 | ~Circom_CalcWit(); 47 | 48 | int getSubComponentOffset(int cIdx, u64 hash); 49 | Circom_Sizes getSubComponentSizes(int cIdx, u64 hash); 50 | int getSignalOffset(int cIdx, u64 hash); 51 | Circom_Sizes getSignalSizes(int cIdx, u64 hash); 52 | 53 | void getSignal(int currentComponentIdx, int cIdx, int sIdx, PFrElement value); 54 | void setSignal(int currentComponentIdx, int cIdx, int sIdx, PFrElement value); 55 | void multiGetSignal(int currentComponentIdx, int cIdx, int sIdx, PFrElement value, int n); 56 | 57 | void checkConstraint(int currentComponentIdx, PFrElement value1, PFrElement value2, char const *err); 58 | void checkAssert(int currentComponentIdx, PFrElement value1, char const *err); 59 | 60 | void log(PFrElement value); 61 | 62 | void finished(int cIdx); 63 | void join(); 64 | 65 | 66 | // Public functions 67 | inline void setInput(int idx, PFrElement val) { 68 | setSignal(0, 0, circuit->wit2sig[idx], val); 69 | } 70 | inline void getWitness(int idx, PFrElement val) { 71 | Fr_copy(val, &signalValues[circuit->wit2sig[idx]]); 72 | } 73 | 74 | void reset(); 75 | 76 | void calculateProve(void *wtns, json &input, std::function _isCanceledCB); 77 | void calculateProve(void *wtns, std::string &input, std::function _isCanceledCB); 78 | 79 | }; 80 | 81 | 82 | 83 | #endif // CIRCOM_CALCWIT_H 84 | -------------------------------------------------------------------------------- /c/circom.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __CIRCOM_H 2 | #define __CIRCOM_H 3 | 4 | #include 5 | #include 6 | #include "fr.hpp" 7 | 8 | class Circom_CalcWit; 9 | typedef unsigned long long u64; 10 | typedef uint32_t u32; 11 | typedef uint8_t u8; 12 | 13 | typedef int Circom_Size; 14 | typedef Circom_Size *Circom_Sizes; 15 | 16 | struct __attribute__((__packed__)) Circom_HashEntry { 17 | u64 hash; 18 | int pos; 19 | }; 20 | typedef Circom_HashEntry *Circom_HashTable; 21 | 22 | typedef enum { _typeSignal=0, _typeComponent=1} Circom_EntryType; 23 | 24 | struct __attribute__((__packed__)) Circom_ComponentEntry { 25 | Circom_Sizes sizes; 26 | uint32_t offset; 27 | Circom_EntryType type; 28 | }; 29 | typedef Circom_ComponentEntry *Circom_ComponentEntries; 30 | 31 | typedef void (*Circom_ComponentFunction)(Circom_CalcWit *ctx, int __cIdx); 32 | 33 | struct Circom_Component { 34 | Circom_HashTable hashTable; 35 | Circom_ComponentEntries entries; 36 | Circom_ComponentFunction fn; 37 | uint32_t inputSignals; 38 | uint32_t newThread; 39 | }; 40 | 41 | struct __attribute__((__packed__)) Circom_Circuit { 42 | unsigned int *wit2sig; 43 | Circom_Component *components; 44 | u32 *mapIsInput; 45 | PFrElement constants; 46 | const char *P; 47 | Circom_ComponentEntry *componentEntries; 48 | int NSignals; 49 | int NComponents; 50 | int NInputs; 51 | int NOutputs; 52 | int NVars; 53 | int NComponentEntries; 54 | int NPublic; 55 | }; 56 | 57 | #define BITMAP_ISSET(m, b) (m[b>>5] & (1 << (b&0x1F))) 58 | extern Circom_ComponentFunction _functionTable[]; 59 | #endif 60 | -------------------------------------------------------------------------------- /c/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | using json = nlohmann::json; 16 | 17 | #include "calcwit.hpp" 18 | #include "circom.hpp" 19 | #include "utils.hpp" 20 | 21 | Circom_Circuit *circuit; 22 | 23 | 24 | #define handle_error(msg) \ 25 | do { perror(msg); exit(EXIT_FAILURE); } while (0) 26 | 27 | #define SHMEM_WITNESS_KEY (123456) 28 | 29 | // assumptions 30 | // 1) There is only one key assigned for shared memory. This means 31 | // that only one witness can be computed and used at a time. If several witness 32 | // are computed before calling the prover, witness memory will be overwritten. 33 | // 2) Prover is responsible for releasing memory once is done with witness 34 | // 35 | // File format: 36 | // Type : 4B (wshm) 37 | // Version : 4B 38 | // N Section : 4B 39 | // HDR1 : 12B 40 | // N8 : 4B 41 | // Fr : N8 B 42 | // NVars : 4B 43 | // HDR2 : 12B 44 | // ShmemKey : 4B 45 | // Status : 4B (0:OK, 0xFFFF: KO) 46 | // ShmemID : 4B 47 | void writeOutShmem(Circom_CalcWit *ctx, std::string filename) { 48 | FILE *write_ptr; 49 | u64 *shbuf; 50 | int shmid, status = 0; 51 | 52 | write_ptr = fopen(filename.c_str(),"wb"); 53 | 54 | fwrite("wshm", 4, 1, write_ptr); 55 | 56 | u32 version = 2; 57 | fwrite(&version, 4, 1, write_ptr); 58 | 59 | u32 nSections = 2; 60 | fwrite(&nSections, 4, 1, write_ptr); 61 | 62 | // Header 63 | u32 idSection1 = 1; 64 | fwrite(&idSection1, 4, 1, write_ptr); 65 | 66 | u32 n8 = Fr_N64*8; 67 | 68 | u64 idSection1length = 8 + n8; 69 | fwrite(&idSection1length, 8, 1, write_ptr); 70 | 71 | fwrite(&n8, 4, 1, write_ptr); 72 | 73 | fwrite(Fr_q.longVal, Fr_N64*8, 1, write_ptr); 74 | 75 | u32 nVars = circuit->NVars; 76 | fwrite(&nVars, 4, 1, write_ptr); 77 | 78 | // Data 79 | u32 idSection2 = 2; 80 | fwrite(&idSection2, 4, 1, write_ptr); 81 | 82 | u64 idSection2length = n8*circuit->NVars; 83 | fwrite(&idSection2length, 8, 1, write_ptr); 84 | 85 | 86 | // generate key 87 | key_t key = SHMEM_WITNESS_KEY; 88 | fwrite(&key, sizeof(key_t), 1, write_ptr); 89 | 90 | // Setup shared memory 91 | if ((shmid = shmget(key, circuit->NVars * Fr_N64 * sizeof(u64), IPC_CREAT | 0666)) < 0) { 92 | // preallocated shared memory segment is too small => Retrieve id by accesing old segment 93 | // Delete old segment and create new with corret size 94 | shmid = shmget(key, 4, IPC_CREAT | 0666); 95 | shmctl(shmid, IPC_RMID, NULL); 96 | if ((shmid = shmget(key, circuit->NVars * Fr_N64 * sizeof(u64), IPC_CREAT | 0666)) < 0){ 97 | status = -1; 98 | fwrite(&status, sizeof(status), 1, write_ptr); 99 | fclose(write_ptr); 100 | return ; 101 | } 102 | } 103 | 104 | // Attach shared memory 105 | if ((shbuf = (u64 *)shmat(shmid, NULL, 0)) == (u64 *) -1) { 106 | status = -1; 107 | fwrite(&status, sizeof(status), 1, write_ptr); 108 | fclose(write_ptr); 109 | return; 110 | } 111 | fwrite(&status, sizeof(status), 1, write_ptr); 112 | 113 | fwrite(&shmid, sizeof(u32), 1, write_ptr); 114 | fclose(write_ptr); 115 | 116 | 117 | #pragma omp parallel for 118 | for (int i=0; iNVars;i++) { 119 | FrElement v; 120 | ctx->getWitness(i, &v); 121 | Fr_toLongNormal(&v, &v); 122 | memcpy(&shbuf[i*Fr_N64], v.longVal, Fr_N64*sizeof(u64)); 123 | } 124 | } 125 | 126 | 127 | void loadBin(Circom_CalcWit *ctx, std::string filename) { 128 | int fd; 129 | struct stat sb; 130 | 131 | // map input 132 | fd = open(filename.c_str(), O_RDONLY); 133 | if (fd == -1) 134 | handle_error("open"); 135 | 136 | if (fstat(fd, &sb) == -1) /* To obtain file size */ 137 | handle_error("fstat"); 138 | 139 | 140 | u8 *in; 141 | 142 | in = (u8 *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 143 | if (in == MAP_FAILED) 144 | handle_error("mmap"); 145 | 146 | close(fd); 147 | 148 | FrElement v; 149 | u8 *p = in; 150 | for (int i=0; iNInputs; i++) { 151 | v.type = Fr_LONG; 152 | for (int j=0; jsetSignal(0, 0, circuit->wit2sig[1 + circuit->NOutputs + i], &v); 157 | } 158 | } 159 | 160 | 161 | typedef void (*ItFunc)(Circom_CalcWit *ctx, int idx, json val); 162 | 163 | void iterateArr(Circom_CalcWit *ctx, int o, Circom_Sizes sizes, json jarr, ItFunc f) { 164 | if (!jarr.is_array()) { 165 | assert((sizes[0] == 1)&&(sizes[1] == 0)); 166 | f(ctx, o, jarr); 167 | } else { 168 | int n = sizes[0] / sizes[1]; 169 | for (int i=0; i(); 183 | } else if (val.is_number()) { 184 | 185 | double vd = val.get(); 186 | std::stringstream stream; 187 | stream << std::fixed << std::setprecision(0) << vd; 188 | s = stream.str(); 189 | } else { 190 | handle_error("Invalid JSON type"); 191 | } 192 | 193 | Fr_str2element (&v, s.c_str()); 194 | 195 | ctx->setSignal(0, 0, o, &v); 196 | } 197 | 198 | void loadJson(Circom_CalcWit *ctx, std::string filename) { 199 | std::ifstream inStream(filename); 200 | json j; 201 | inStream >> j; 202 | 203 | u64 nItems = j.size(); 204 | printf("Items : %llu\n",nItems); 205 | for (json::iterator it = j.begin(); it != j.end(); ++it) { 206 | // std::cout << it.key() << " => " << it.value() << '\n'; 207 | u64 h = fnv1a(it.key()); 208 | int o; 209 | try { 210 | o = ctx->getSignalOffset(0, h); 211 | } catch (std::runtime_error e) { 212 | std::ostringstream errStrStream; 213 | errStrStream << "Error loadin variable: " << it.key() << "\n" << e.what(); 214 | throw std::runtime_error(errStrStream.str() ); 215 | } 216 | Circom_Sizes sizes = ctx->getSignalSizes(0, h); 217 | iterateArr(ctx, o, sizes, it.value(), itFunc); 218 | } 219 | } 220 | 221 | 222 | void writeOutBin(Circom_CalcWit *ctx, std::string filename) { 223 | FILE *write_ptr; 224 | 225 | write_ptr = fopen(filename.c_str(),"wb"); 226 | 227 | fwrite("wtns", 4, 1, write_ptr); 228 | 229 | u32 version = 2; 230 | fwrite(&version, 4, 1, write_ptr); 231 | 232 | u32 nSections = 2; 233 | fwrite(&nSections, 4, 1, write_ptr); 234 | 235 | // Header 236 | u32 idSection1 = 1; 237 | fwrite(&idSection1, 4, 1, write_ptr); 238 | 239 | u32 n8 = Fr_N64*8; 240 | 241 | u64 idSection1length = 8 + n8; 242 | fwrite(&idSection1length, 8, 1, write_ptr); 243 | 244 | fwrite(&n8, 4, 1, write_ptr); 245 | 246 | fwrite(Fr_q.longVal, Fr_N64*8, 1, write_ptr); 247 | 248 | u32 nVars = circuit->NVars; 249 | fwrite(&nVars, 4, 1, write_ptr); 250 | 251 | 252 | // Data 253 | u32 idSection2 = 2; 254 | fwrite(&idSection2, 4, 1, write_ptr); 255 | 256 | u64 idSection2length = (u64)n8*(u64)circuit->NVars; 257 | fwrite(&idSection2length, 8, 1, write_ptr); 258 | 259 | FrElement v; 260 | 261 | for (int i=0;iNVars;i++) { 262 | ctx->getWitness(i, &v); 263 | Fr_toLongNormal(&v, &v); 264 | fwrite(v.longVal, Fr_N64*8, 1, write_ptr); 265 | } 266 | fclose(write_ptr); 267 | 268 | } 269 | 270 | 271 | void writeOutJson(Circom_CalcWit *ctx, std::string filename) { 272 | 273 | std::ofstream outFile; 274 | outFile.open (filename); 275 | 276 | outFile << "[\n"; 277 | 278 | FrElement v; 279 | 280 | for (int i=0;iNVars;i++) { 281 | ctx->getWitness(i, &v); 282 | char *pcV = Fr_element2str(&v); 283 | std::string sV = std::string(pcV); 284 | outFile << (i ? "," : " ") << "\"" << sV << "\"\n"; 285 | free(pcV); 286 | } 287 | 288 | outFile << "]\n"; 289 | outFile.close(); 290 | } 291 | 292 | bool hasEnding (std::string const &fullString, std::string const &ending) { 293 | if (fullString.length() >= ending.length()) { 294 | return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); 295 | } else { 296 | return false; 297 | } 298 | } 299 | 300 | #define ADJ_P(a) *((void **)&a) = (void *)(((char *)circuit)+ (uint64_t)(a)) 301 | 302 | Circom_Circuit *loadCircuit(std::string const &datFileName) { 303 | Circom_Circuit *circuitF; 304 | Circom_Circuit *circuit; 305 | 306 | int fd; 307 | struct stat sb; 308 | 309 | fd = open(datFileName.c_str(), O_RDONLY); 310 | if (fd == -1) { 311 | std::cout << ".dat file not found: " << datFileName << "\n"; 312 | throw std::system_error(errno, std::generic_category(), "open"); 313 | } 314 | 315 | if (fstat(fd, &sb) == -1) { /* To obtain file size */ 316 | throw std::system_error(errno, std::generic_category(), "fstat"); 317 | } 318 | 319 | circuitF = (Circom_Circuit *)mmap(NULL, sb.st_size, PROT_READ , MAP_PRIVATE, fd, 0); 320 | close(fd); 321 | 322 | circuit = (Circom_Circuit *)malloc(sb.st_size); 323 | memcpy((void *)circuit, (void *)circuitF, sb.st_size); 324 | 325 | munmap(circuitF, sb.st_size); 326 | 327 | ADJ_P(circuit->wit2sig); 328 | ADJ_P(circuit->components); 329 | ADJ_P(circuit->mapIsInput); 330 | ADJ_P(circuit->constants); 331 | ADJ_P(circuit->P); 332 | ADJ_P(circuit->componentEntries); 333 | 334 | for (int i=0; iNComponents; i++) { 335 | ADJ_P(circuit->components[i].hashTable); 336 | ADJ_P(circuit->components[i].entries); 337 | circuit->components[i].fn = _functionTable[ (uint64_t)circuit->components[i].fn]; 338 | } 339 | 340 | for (int i=0; iNComponentEntries; i++) { 341 | ADJ_P(circuit->componentEntries[i].sizes); 342 | } 343 | 344 | return circuit; 345 | } 346 | 347 | int main(int argc, char *argv[]) { 348 | if (argc!=3) { 349 | std::string cl = argv[0]; 350 | std::string base_filename = cl.substr(cl.find_last_of("/\\") + 1); 351 | std::cout << "Usage: " << base_filename << " > >\n"; 352 | } else { 353 | 354 | struct timeval begin, end; 355 | long seconds, microseconds; 356 | double elapsed; 357 | 358 | gettimeofday(&begin,0); 359 | 360 | std::string datFileName = argv[0]; 361 | datFileName += ".dat"; 362 | 363 | circuit = loadCircuit(datFileName); 364 | 365 | // open output 366 | Circom_CalcWit *ctx = new Circom_CalcWit(circuit); 367 | 368 | std::string infilename = argv[1]; 369 | gettimeofday(&end,0); 370 | seconds = end.tv_sec - begin.tv_sec; 371 | microseconds = end.tv_usec - begin.tv_usec; 372 | elapsed = seconds + microseconds*1e-6; 373 | 374 | printf("Up to loadJson %.20f\n", elapsed); 375 | 376 | if (hasEnding(infilename, std::string(".bin"))) { 377 | loadBin(ctx, infilename); 378 | } else if (hasEnding(infilename, std::string(".json"))) { 379 | loadJson(ctx, infilename); 380 | } else { 381 | handle_error("Invalid input extension (.bin / .json)"); 382 | } 383 | 384 | ctx->join(); 385 | 386 | // printf("Finished!\n"); 387 | 388 | std::string outfilename = argv[2]; 389 | 390 | if (hasEnding(outfilename, std::string(".wtns"))) { 391 | gettimeofday(&end,0); 392 | seconds = end.tv_sec - begin.tv_sec; 393 | microseconds = end.tv_usec - begin.tv_usec; 394 | elapsed = seconds + microseconds*1e-6; 395 | 396 | printf("Up to WriteWtns %.20f\n", elapsed); 397 | writeOutBin(ctx, outfilename); 398 | } else if (hasEnding(outfilename, std::string(".json"))) { 399 | writeOutJson(ctx, outfilename); 400 | } else if (hasEnding(outfilename, std::string(".wshm"))) { 401 | gettimeofday(&end,0); 402 | seconds = end.tv_sec - begin.tv_sec; 403 | microseconds = end.tv_usec - begin.tv_usec; 404 | elapsed = seconds + microseconds*1e-6; 405 | 406 | printf("Up to WriteShmem %.20f\n", elapsed); 407 | writeOutShmem(ctx, outfilename); 408 | } else { 409 | handle_error("Invalid output extension (.bin / .json)"); 410 | } 411 | 412 | delete ctx; 413 | gettimeofday(&end,0); 414 | seconds = end.tv_sec - begin.tv_sec; 415 | microseconds = end.tv_usec - begin.tv_usec; 416 | elapsed = seconds + microseconds*1e-6; 417 | 418 | printf("Total %.20f\n", elapsed); 419 | exit(EXIT_SUCCESS); 420 | } 421 | } 422 | -------------------------------------------------------------------------------- /c/old/buildasm/add.asm.ejs: -------------------------------------------------------------------------------- 1 | <% function addS1S2() { %> 2 | xor rdx, rdx 3 | mov edx, eax 4 | add edx, ecx 5 | jo add_manageOverflow ; rsi already is the 64bits result 6 | 7 | mov [rdi], rdx ; not necessary to adjust so just save and return 8 | ret 9 | 10 | add_manageOverflow: ; Do the operation in 64 bits 11 | push rsi 12 | movsx rsi, eax 13 | movsx rdx, ecx 14 | add rsi, rdx 15 | call rawCopyS2L 16 | pop rsi 17 | ret 18 | <% } %> 19 | 20 | 21 | 22 | <% function addL1S2() { %> 23 | add rsi, 8 24 | movsx rdx, ecx 25 | add rdi, 8 26 | cmp rdx, 0 27 | <% const rawAddLabel = global.tmpLabel() %> 28 | jns <%= rawAddLabel %> 29 | neg rdx 30 | call rawSubLS 31 | sub rdi, 8 32 | sub rsi, 8 33 | ret 34 | <%= rawAddLabel %>: 35 | call rawAddLS 36 | sub rdi, 8 37 | sub rsi, 8 38 | ret 39 | 40 | <% } %> 41 | 42 | <% function addS1L2() { %> 43 | lea rsi, [rdx + 8] 44 | movsx rdx, eax 45 | add rdi, 8 46 | cmp rdx, 0 47 | <% const rawAddLabel = global.tmpLabel() %> 48 | jns <%= rawAddLabel %> 49 | neg rdx 50 | call rawSubLS 51 | sub rdi, 8 52 | sub rsi, 8 53 | ret 54 | <%= rawAddLabel %>: 55 | call rawAddLS 56 | sub rdi, 8 57 | sub rsi, 8 58 | ret 59 | <% } %> 60 | 61 | <% function addL1L2() { %> 62 | add rdi, 8 63 | add rsi, 8 64 | add rdx, 8 65 | call rawAddLL 66 | sub rdi, 8 67 | sub rsi, 8 68 | ret 69 | <% } %> 70 | 71 | ;;;;;;;;;;;;;;;;;;;;;; 72 | ; add 73 | ;;;;;;;;;;;;;;;;;;;;;; 74 | ; Adds two elements of any kind 75 | ; Params: 76 | ; rsi <= Pointer to element 1 77 | ; rdx <= Pointer to element 2 78 | ; rdi <= Pointer to result 79 | ; Modified Registers: 80 | ; r8, r9, 10, r11, rax, rcx 81 | ;;;;;;;;;;;;;;;;;;;;;; 82 | <%=name%>_add: 83 | mov rax, [rsi] 84 | mov rcx, [rdx] 85 | bt rax, 63 ; Check if is short first operand 86 | jc add_l1 87 | bt rcx, 63 ; Check if is short second operand 88 | jc add_s1l2 89 | 90 | add_s1s2: ; Both operands are short 91 | <%= addS1S2() %> 92 | add_l1: 93 | bt rcx, 63 ; Check if is short second operand 94 | jc add_l1l2 95 | 96 | ;;;;;;;; 97 | add_l1s2: 98 | bt rax, 62 ; check if montgomery first 99 | jc add_l1ms2 100 | add_l1ns2: 101 | <%= global.setTypeDest("0x80"); %> 102 | <%= addL1S2(); %> 103 | 104 | add_l1ms2: 105 | bt rcx, 62 ; check if montgomery second 106 | jc add_l1ms2m 107 | add_l1ms2n: 108 | <%= global.setTypeDest("0xC0"); %> 109 | <%= global.toMont_b() %> 110 | <%= addL1L2() %> 111 | 112 | add_l1ms2m: 113 | <%= global.setTypeDest("0xC0"); %> 114 | <%= addL1L2() %> 115 | 116 | 117 | ;;;;;;;; 118 | add_s1l2: 119 | bt rcx, 62 ; check if montgomery second 120 | jc add_s1l2m 121 | add_s1l2n: 122 | <%= global.setTypeDest("0x80"); %> 123 | <%= addS1L2(); %> 124 | 125 | add_s1l2m: 126 | bt rax, 62 ; check if montgomery first 127 | jc add_s1ml2m 128 | add_s1nl2m: 129 | <%= global.setTypeDest("0xC0"); %> 130 | <%= global.toMont_a() %> 131 | <%= addL1L2() %> 132 | 133 | add_s1ml2m: 134 | <%= global.setTypeDest("0xC0"); %> 135 | <%= addL1L2() %> 136 | 137 | ;;;; 138 | add_l1l2: 139 | bt rax, 62 ; check if montgomery first 140 | jc add_l1ml2 141 | add_l1nl2: 142 | bt rcx, 62 ; check if montgomery second 143 | jc add_l1nl2m 144 | add_l1nl2n: 145 | <%= global.setTypeDest("0x80"); %> 146 | <%= addL1L2() %> 147 | 148 | add_l1nl2m: 149 | <%= global.setTypeDest("0xC0"); %> 150 | <%= global.toMont_a(); %> 151 | <%= addL1L2() %> 152 | 153 | add_l1ml2: 154 | bt rcx, 62 ; check if montgomery seconf 155 | jc add_l1ml2m 156 | add_l1ml2n: 157 | <%= global.setTypeDest("0xC0"); %> 158 | <%= global.toMont_b(); %> 159 | <%= addL1L2() %> 160 | 161 | add_l1ml2m: 162 | <%= global.setTypeDest("0xC0"); %> 163 | <%= addL1L2() %> 164 | 165 | 166 | 167 | ;;;;;;;;;;;;;;;;;;;;;; 168 | ; rawAddLL 169 | ;;;;;;;;;;;;;;;;;;;;;; 170 | ; Adds two elements of type long 171 | ; Params: 172 | ; rsi <= Pointer to the long data of element 1 173 | ; rdx <= Pointer to the long data of element 2 174 | ; rdi <= Pointer to the long data of result 175 | ; Modified Registers: 176 | ; rax 177 | ;;;;;;;;;;;;;;;;;;;;;; 178 | rawAddLL: 179 | ; Add component by component with carry 180 | <% for (let i=0; i 181 | mov rax, [rsi + <%=i*8%>] 182 | <%= i==0 ? "add" : "adc" %> rax, [rdx + <%=i*8%>] 183 | mov [rdi + <%=i*8%>], rax 184 | <% } %> 185 | jc rawAddLL_sq ; if overflow, substract q 186 | 187 | ; Compare with q 188 | <% for (let i=0; i 189 | <% if (i>0) { %> 190 | mov rax, [rdi + <%= (n64-i-1)*8 %>] 191 | <% } %> 192 | cmp rax, [q + <%= (n64-i-1)*8 %>] 193 | jc rawAddLL_done ; q is bigget so done. 194 | jnz rawAddLL_sq ; q is lower 195 | <% } %> 196 | ; If equal substract q 197 | rawAddLL_sq: 198 | <% for (let i=0; i 199 | mov rax, [q + <%=i*8%>] 200 | <%= i==0 ? "sub" : "sbb" %> [rdi + <%=i*8%>], rax 201 | <% } %> 202 | rawAddLL_done: 203 | ret 204 | 205 | 206 | ;;;;;;;;;;;;;;;;;;;;;; 207 | ; rawAddLS 208 | ;;;;;;;;;;;;;;;;;;;;;; 209 | ; Adds two elements of type long 210 | ; Params: 211 | ; rdi <= Pointer to the long data of result 212 | ; rsi <= Pointer to the long data of element 1 213 | ; rdx <= Value to be added 214 | ;;;;;;;;;;;;;;;;;;;;;; 215 | rawAddLS: 216 | ; Add component by component with carry 217 | 218 | add rdx, [rsi] 219 | mov [rdi] ,rdx 220 | <% for (let i=1; i 221 | mov rdx, 0 222 | adc rdx, [rsi + <%=i*8%>] 223 | mov [rdi + <%=i*8%>], rdx 224 | <% } %> 225 | jc rawAddLS_sq ; if overflow, substract q 226 | 227 | ; Compare with q 228 | <% for (let i=0; i 229 | mov rax, [rdi + <%= (n64-i-1)*8 %>] 230 | cmp rax, [q + <%= (n64-i-1)*8 %>] 231 | jc rawAddLS_done ; q is bigget so done. 232 | jnz rawAddLS_sq ; q is lower 233 | <% } %> 234 | ; If equal substract q 235 | rawAddLS_sq: 236 | <% for (let i=0; i 237 | mov rax, [q + <%=i*8%>] 238 | <%= i==0 ? "sub" : "sbb" %> [rdi + <%=i*8%>], rax 239 | <% } %> 240 | rawAddLS_done: 241 | ret 242 | 243 | 244 | 245 | 246 | -------------------------------------------------------------------------------- /c/old/buildasm/binops.asm.ejs: -------------------------------------------------------------------------------- 1 | <% function binOpSubQIfBigger() { %> 2 | <% const subQ = global.tmpLabel() %> 3 | <% const done = global.tmpLabel() %> 4 | 5 | ; Compare with q 6 | <% for (let i=0; i 7 | mov rax, [rdi + <%= (n64-i)*8 %>] 8 | cmp rax, [q + <%= (n64-i-1)*8 %>] 9 | jc <%=done%> ; q is bigget so done. 10 | jnz <%=subQ%> ; q is lower 11 | <% } %> 12 | ; If equal substract q 13 | <%=subQ%>: 14 | <% for (let i=0; i 15 | mov rax, [q + <%=i*8%>] 16 | <%= i==0 ? "sub" : "sbb" %> [rdi + <%=i*8 + 8 %>], rax 17 | <% } %> 18 | <%=done%>: 19 | <% } %> 20 | 21 | 22 | <% function binOpS1S2(op) { %> 23 | cmp r8d, 0 24 | <% const s1s2_solveNeg = global.tmpLabel() %> 25 | js <%=s1s2_solveNeg%> 26 | 27 | cmp r9d, 0 28 | js <%=s1s2_solveNeg%> 29 | xor rdx, rdx ; both ops are positive so do the op and return 30 | mov edx, r8d 31 | <%=op%> edx, r9d 32 | mov [rdi], rdx ; not necessary to adjust so just save and return 33 | ret 34 | 35 | <%=s1s2_solveNeg%>: 36 | <%= global.setTypeDest("0x80"); %> 37 | <%= global.toLong_b() %> 38 | <%= global.toLong_a() %> 39 | <%= binOpL1L2(op) %> 40 | 41 | 42 | <% } %> 43 | 44 | <% function binOpS1L2(op) { %> 45 | cmp r8d, 0 46 | <% const s1l2_solveNeg = global.tmpLabel() %> 47 | js <%=s1l2_solveNeg%> 48 | movsx rax, r8d 49 | <%=op%> rax, [rdx +8] 50 | mov [rdi+8], rax 51 | <% for (let i=1; i 52 | xor rax, rax 53 | <%=op%> rax, [rdx + <%= (i*8)+8 %>] 54 | <% if (i== n64-1) { %> 55 | and rax, [lboMask] 56 | <% } %> 57 | mov [rdi + <%= (i*8)+8 %> ], rax 58 | <% } %> 59 | <% binOpSubQIfBigger() %> 60 | ret 61 | 62 | <%=s1l2_solveNeg%>: 63 | <%= global.toLong_a() %> 64 | <%= global.setTypeDest("0x80"); %> 65 | <%= binOpL1L2(op) %> 66 | 67 | <% } %> 68 | 69 | <% function binOpL1S2(op) { %> 70 | cmp r9d, 0 71 | <% const l1s2_solveNeg = global.tmpLabel() %> 72 | js <%=l1s2_solveNeg%> 73 | movsx rax, r9d 74 | <%=op%> rax, [rsi +8] 75 | mov [rdi+8], rax 76 | <% for (let i=1; i 77 | xor rax, rax 78 | <%=op%> rax, [rsi + <%= (i*8)+8 %>]; 79 | <% if (i== n64-1) { %> 80 | and rax, [lboMask] ; 81 | <% } %> 82 | mov [rdi + <%= (i*8)+8 %> ], rax; 83 | <% } %> 84 | <% binOpSubQIfBigger() %> 85 | ret 86 | 87 | <%=l1s2_solveNeg%>: 88 | <%= global.toLong_b() %> 89 | <%= global.setTypeDest("0x80"); %> 90 | <%= binOpL1L2(op) %> 91 | 92 | <% } %> 93 | 94 | <% function binOpL1L2(op) { %> 95 | <% for (let i=0; i 96 | mov rax, [rsi + <%= (i*8)+8 %>] 97 | <%=op%> rax, [rdx + <%= (i*8)+8 %>] 98 | <% if (i== n64-1) { %> 99 | and rax, [lboMask] 100 | <% } %> 101 | mov [rdi + <%= (i*8)+8 %> ], rax 102 | <% } %> 103 | <% binOpSubQIfBigger() %> 104 | ret 105 | <% } %> 106 | 107 | 108 | <% function binOp(op) { %> 109 | ;;;;;;;;;;;;;;;;;;;;;; 110 | ; b<%= op %> 111 | ;;;;;;;;;;;;;;;;;;;;;; 112 | ; Adds two elements of any kind 113 | ; Params: 114 | ; rsi <= Pointer to element 1 115 | ; rdx <= Pointer to element 2 116 | ; rdi <= Pointer to result 117 | ; Modified Registers: 118 | ; r8, r9, 10, r11, rax, rcx 119 | ;;;;;;;;;;;;;;;;;;;;;; 120 | <%=name%>_b<%=op%>: 121 | mov r8, [rsi] 122 | mov r9, [rdx] 123 | bt r8, 63 ; Check if is short first operand 124 | jc <%=op%>_l1 125 | bt r9, 63 ; Check if is short second operand 126 | jc <%=op%>_s1l2 127 | 128 | <%=op%>_s1s2: 129 | <%= binOpS1S2(op) %> 130 | 131 | 132 | <%=op%>_l1: 133 | bt r9, 63 ; Check if is short second operand 134 | jc <%=op%>_l1l2 135 | 136 | 137 | <%=op%>_l1s2: 138 | bt r8, 62 ; check if montgomery first 139 | jc <%=op%>_l1ms2 140 | <%=op%>_l1ns2: 141 | <%= global.setTypeDest("0x80"); %> 142 | <%= binOpL1S2(op) %> 143 | 144 | <%=op%>_l1ms2: 145 | <%= global.setTypeDest("0x80"); %> 146 | push r9 ; r9 is used in montgomery so we need to save it 147 | <%= global.fromMont_a() %> 148 | pop r9 149 | <%= binOpL1S2(op) %> 150 | 151 | 152 | <%=op%>_s1l2: 153 | bt r9, 62 ; check if montgomery first 154 | jc <%=op%>_s1l2m 155 | <%=op%>_s1l2n: 156 | <%= global.setTypeDest("0x80"); %> 157 | <%= binOpS1L2(op) %> 158 | 159 | <%=op%>_s1l2m: 160 | <%= global.setTypeDest("0x80"); %> 161 | push r8 ; r8 is used in montgomery so we need to save it 162 | <%= global.fromMont_b() %> 163 | pop r8 164 | <%= binOpS1L2(op) %> 165 | 166 | 167 | <%=op%>_l1l2: 168 | bt r8, 62 ; check if montgomery first 169 | jc <%=op%>_l1ml2 170 | bt r9, 62 ; check if montgomery first 171 | jc <%=op%>_l1nl2m 172 | <%=op%>_l1nl2n: 173 | <%= global.setTypeDest("0x80"); %> 174 | <%= binOpL1L2(op) %> 175 | 176 | <%=op%>_l1nl2m: 177 | <%= global.setTypeDest("0x80"); %> 178 | <%= global.fromMont_b() %> 179 | <%= binOpL1L2(op) %> 180 | 181 | <%=op%>_l1ml2: 182 | bt r9, 62 ; check if montgomery first 183 | jc <%=op%>_l1ml2m 184 | <%=op%>_l1ml2n: 185 | <%= global.setTypeDest("0x80"); %> 186 | <%= global.fromMont_a() %> 187 | <%= binOpL1L2(op) %> 188 | 189 | <%=op%>_l1ml2m: 190 | <%= global.setTypeDest("0x80"); %> 191 | <%= global.fromMont_a() %> 192 | <%= global.fromMont_b() %> 193 | <%= binOpL1L2(op) %> 194 | <% } %> 195 | 196 | <%= binOp("and") %> 197 | <%= binOp("or") %> 198 | <%= binOp("xor") %> 199 | 200 | 201 | ;;;;;;;;;;;;;;;;;;;;;; 202 | ; bnot 203 | ;;;;;;;;;;;;;;;;;;;;;; 204 | ; Adds two elements of any kind 205 | ; Params: 206 | ; rsi <= Pointer to element 1 207 | ; rdi <= Pointer to result 208 | ; Modified Registers: 209 | ; r8, r9, 10, r11, rax, rcx 210 | ;;;;;;;;;;;;;;;;;;;;;; 211 | <%=name%>_bnot: 212 | <%= global.setTypeDest("0x80"); %> 213 | 214 | mov r8, [rsi] 215 | bt r8, 63 ; Check if is long operand 216 | jc bnot_l1 217 | bnot_s: 218 | <%= global.toLong_a() %> 219 | jmp bnot_l1n 220 | 221 | bnot_l1: 222 | bt r8, 62 ; check if montgomery first 223 | jnc bnot_l1n 224 | 225 | bnot_l1m: 226 | <%= global.fromMont_a() %> 227 | 228 | bnot_l1n: 229 | <% for (let i=0; i 230 | mov rax, [rsi + <%= i*8 + 8 %>] 231 | not rax 232 | <% if (i== n64-1) { %> 233 | and rax, [lboMask] 234 | <% } %> 235 | mov [rdi + <%= i*8 + 8 %>], rax 236 | <% } %> 237 | <% binOpSubQIfBigger() %> 238 | ret 239 | 240 | 241 | -------------------------------------------------------------------------------- /c/old/buildasm/buildzqfield.js: -------------------------------------------------------------------------------- 1 | const bigInt=require("big-integer"); 2 | const path = require("path"); 3 | const util = require("util"); 4 | const renderFile = util.promisify(require("ejs").renderFile); 5 | 6 | const runningAsScript = !module.parent; 7 | 8 | 9 | class ZqBuilder { 10 | constructor(q, name) { 11 | const self = this; 12 | this.q=bigInt(q); 13 | this.n64 = Math.floor((this.q.bitLength() - 1) / 64)+1; 14 | this.name = name; 15 | this.bigInt = bigInt; 16 | this.lastTmp=0; 17 | this.global = {}; 18 | this.global.tmpLabel = function(label) { 19 | self.lastTmp++; 20 | label = label || "tmp"; 21 | return label+"_"+self.lastTmp; 22 | }; 23 | } 24 | 25 | constantElement(v) { 26 | let S = ""; 27 | const mask = bigInt("FFFFFFFFFFFFFFFF", 16); 28 | for (let i=0; i0) S = S+","; 30 | let shex = v.shiftRight(i*64).and(mask).toString(16); 31 | while (shex.length <16) shex = "0" + shex; 32 | S = S + "0x" + shex; 33 | } 34 | return S; 35 | } 36 | 37 | } 38 | 39 | async function buildField(q, name) { 40 | const builder = new ZqBuilder(q, name); 41 | 42 | const asm = await renderFile(path.join(__dirname, "fr.asm.ejs"), builder); 43 | const c = await renderFile(path.join(__dirname, "fr.c.ejs"), builder); 44 | const h = await renderFile(path.join(__dirname, "fr.h.ejs"), builder); 45 | 46 | return {asm: asm, h: h, c: c}; 47 | } 48 | 49 | if (runningAsScript) { 50 | const fs = require("fs"); 51 | var argv = require("yargs") 52 | .usage("Usage: $0 -q [primeNum] -n [name] -oc [out .c file] -oh [out .h file]") 53 | .demandOption(["q","n"]) 54 | .alias("q", "prime") 55 | .alias("n", "name") 56 | .argv; 57 | 58 | const q = bigInt(argv.q); 59 | 60 | const asmFileName = (argv.oc) ? argv.oc : argv.name.toLowerCase() + ".asm"; 61 | const hFileName = (argv.oc) ? argv.oc : argv.name.toLowerCase() + ".h"; 62 | const cFileName = (argv.oc) ? argv.oc : argv.name.toLowerCase() + ".c"; 63 | 64 | buildField(q, argv.name).then( (res) => { 65 | fs.writeFileSync(asmFileName, res.asm, "utf8"); 66 | fs.writeFileSync(hFileName, res.h, "utf8"); 67 | fs.writeFileSync(cFileName, res.c, "utf8"); 68 | }); 69 | 70 | } else { 71 | module.exports = buildField; 72 | } 73 | -------------------------------------------------------------------------------- /c/old/buildasm/buildzqfieldtester.js: -------------------------------------------------------------------------------- 1 | const chai = require("chai"); 2 | const assert = chai.assert; 3 | 4 | const fs = require("fs"); 5 | var tmp = require("tmp-promise"); 6 | const path = require("path"); 7 | const util = require("util"); 8 | const exec = util.promisify(require("child_process").exec); 9 | 10 | const BuildZqField = require("./buildzqfield"); 11 | 12 | module.exports = testField; 13 | 14 | async function testField(prime, test) { 15 | tmp.setGracefulCleanup(); 16 | 17 | const dir = await tmp.dir({prefix: "circom_", unsafeCleanup: true }); 18 | 19 | const source = await BuildZqField(prime, "Fr"); 20 | 21 | // console.log(dir.path); 22 | 23 | await fs.promises.writeFile(path.join(dir.path, "fr.asm"), source.asm, "utf8"); 24 | await fs.promises.writeFile(path.join(dir.path, "fr.h"), source.h, "utf8"); 25 | await fs.promises.writeFile(path.join(dir.path, "fr.c"), source.c, "utf8"); 26 | 27 | await exec(`cp ${path.join(__dirname, "tester.cpp")} ${dir.path}`); 28 | 29 | await exec("nasm -fmacho64 --prefix _ " + 30 | ` ${path.join(dir.path, "fr.asm")}` 31 | ); 32 | 33 | await exec("g++" + 34 | ` ${path.join(dir.path, "tester.cpp")}` + 35 | ` ${path.join(dir.path, "fr.o")}` + 36 | ` ${path.join(dir.path, "fr.c")}` + 37 | ` -o ${path.join(dir.path, "tester")}` + 38 | " -lgmp -g" 39 | ); 40 | 41 | const inLines = []; 42 | for (let i=0; i${path.join(dir.path, "out.tst")}`); 54 | 55 | const res = await fs.promises.readFile(path.join(dir.path, "out.tst"), "utf8"); 56 | const resLines = res.split("\n"); 57 | 58 | for (let i=0; i 2 | <% for (let i=n64-1; i>=0; i--) { %> 3 | mov rax, [<%=reg%> + <%= 8+(i*8) %>] 4 | cmp [half + <%= (i*8) %>], rax ; comare with (q-1)/2 5 | jc <%=label_neg%> ; half e1-e2 is neg => e1 < e2 6 | <% if (i>0) { %> 7 | jnz <%=label_pos%> ; half>rax => e1 -e2 is pos => e1 > e2 8 | <% } else { %> 9 | jmp <%=label_pos%> 10 | <% } %> 11 | <% } %> 12 | <% } %> 13 | 14 | 15 | ;;;;;;;;;;;;;;;;;;;;;; 16 | ; rgt - Raw Greater Than 17 | ;;;;;;;;;;;;;;;;;;;;;; 18 | ; returns in ax 1 id *rsi > *rdx 19 | ; Params: 20 | ; rsi <= Pointer to element 1 21 | ; rdx <= Pointer to element 2 22 | ; rax <= Return 1 or 0 23 | ; Modified Registers: 24 | ; r8, r9, rax 25 | ;;;;;;;;;;;;;;;;;;;;;; 26 | <%=name%>_rgt: 27 | mov r8, [rsi] 28 | mov r9, [rdx] 29 | bt r8, 63 ; Check if is short first operand 30 | jc rgt_l1 31 | bt r9, 63 ; Check if is short second operand 32 | jc rgt_s1l2 33 | 34 | rgt_s1s2: ; Both operands are short 35 | cmp r8d, r9d 36 | jg rgt_ret1 37 | jmp rgt_ret0 38 | 39 | 40 | rgt_l1: 41 | bt r9, 63 ; Check if is short second operand 42 | jc rgt_l1l2 43 | 44 | ;;;;;;;; 45 | rgt_l1s2: 46 | bt r8, 62 ; check if montgomery first 47 | jc rgt_l1ms2 48 | rgt_l1ns2: 49 | <%= global.toLong_b() %> 50 | jmp rgtL1L2 51 | 52 | rgt_l1ms2: 53 | <%= global.toLong_b() %> 54 | <%= global.fromMont_a() %> 55 | jmp rgtL1L2 56 | 57 | 58 | ;;;;;;;; 59 | rgt_s1l2: 60 | bt r9, 62 ; check if montgomery second 61 | jc rgt_s1l2m 62 | rgt_s1l2n: 63 | <%= global.toLong_a() %> 64 | jmp rgtL1L2 65 | 66 | rgt_s1l2m: 67 | <%= global.toLong_a() %> 68 | <%= global.fromMont_b() %> 69 | jmp rgtL1L2 70 | 71 | ;;;; 72 | rgt_l1l2: 73 | bt r8, 62 ; check if montgomery first 74 | jc rgt_l1ml2 75 | rgt_l1nl2: 76 | bt r9, 62 ; check if montgomery second 77 | jc rgt_l1nl2m 78 | rgt_l1nl2n: 79 | jmp rgtL1L2 80 | 81 | rgt_l1nl2m: 82 | <%= global.fromMont_b() %> 83 | jmp rgtL1L2 84 | 85 | rgt_l1ml2: 86 | bt r9, 62 ; check if montgomery second 87 | jc rgt_l1ml2m 88 | rgt_l1ml2n: 89 | <%= global.fromMont_a() %> 90 | jmp rgtL1L2 91 | 92 | rgt_l1ml2m: 93 | <%= global.fromMont_a() %> 94 | <%= global.fromMont_b() %> 95 | jmp rgtL1L2 96 | 97 | 98 | ;;;;;; 99 | ; rgtL1L2 100 | ;;;;;; 101 | 102 | rgtL1L2: 103 | <%= signL("rsi", "rgtl1l2_p1", "rgtl1l2_n1") %> 104 | rgtl1l2_p1: 105 | <%= signL("rdx", "rgtRawL1L2", "rgt_ret1") %> 106 | 107 | rgtl1l2_n1: 108 | <%= signL("rdx", "rgt_ret0", "rgtRawL1L2") %> 109 | 110 | 111 | rgtRawL1L2: 112 | <% for (let i=n64-1; i>=0; i--) { %> 113 | mov rax, [rsi + <%= 8+(i*8) %>] 114 | cmp [rdx + <%= 8+(i*8) %>], rax ; comare with (q-1)/2 115 | jc rgt_ret1 ; rsi 1st > 2nd 116 | <% if (i>0) { %> 117 | jnz rgt_ret0 118 | <% } %> 119 | <% } %> 120 | 121 | rgt_ret0: 122 | xor rax, rax 123 | ret 124 | rgt_ret1: 125 | mov rax, 1 126 | ret 127 | 128 | 129 | 130 | ;;;;;;;;;;;;;;;;;;;;;; 131 | ; rlt - Raw Less Than 132 | ;;;;;;;;;;;;;;;;;;;;;; 133 | ; returns in ax 1 id *rsi > *rdx 134 | ; Params: 135 | ; rsi <= Pointer to element 1 136 | ; rdx <= Pointer to element 2 137 | ; rax <= Return 1 or 0 138 | ; Modified Registers: 139 | ; r8, r9, rax 140 | ;;;;;;;;;;;;;;;;;;;;;; 141 | <%=name%>_rlt: 142 | mov r8, [rsi] 143 | mov r9, [rdx] 144 | bt r8, 63 ; Check if is short first operand 145 | jc rlt_l1 146 | bt r9, 63 ; Check if is short second operand 147 | jc rlt_s1l2 148 | 149 | rlt_s1s2: ; Both operands are short 150 | cmp r8d, r9d 151 | jl rlt_ret1 152 | jmp rlt_ret0 153 | 154 | 155 | rlt_l1: 156 | bt r9, 63 ; Check if is short second operand 157 | jc rlt_l1l2 158 | 159 | ;;;;;;;; 160 | rlt_l1s2: 161 | bt r8, 62 ; check if montgomery first 162 | jc rlt_l1ms2 163 | rlt_l1ns2: 164 | <%= global.toLong_b() %> 165 | jmp rltL1L2 166 | 167 | rlt_l1ms2: 168 | <%= global.toLong_b() %> 169 | <%= global.fromMont_a() %> 170 | jmp rltL1L2 171 | 172 | 173 | ;;;;;;;; 174 | rlt_s1l2: 175 | bt r9, 62 ; check if montgomery second 176 | jc rlt_s1l2m 177 | rlt_s1l2n: 178 | <%= global.toLong_a() %> 179 | jmp rltL1L2 180 | 181 | rlt_s1l2m: 182 | <%= global.toLong_a() %> 183 | <%= global.fromMont_b() %> 184 | jmp rltL1L2 185 | 186 | ;;;; 187 | rlt_l1l2: 188 | bt r8, 62 ; check if montgomery first 189 | jc rlt_l1ml2 190 | rlt_l1nl2: 191 | bt r9, 62 ; check if montgomery second 192 | jc rlt_l1nl2m 193 | rlt_l1nl2n: 194 | jmp rltL1L2 195 | 196 | rlt_l1nl2m: 197 | <%= global.fromMont_b() %> 198 | jmp rltL1L2 199 | 200 | rlt_l1ml2: 201 | bt r9, 62 ; check if montgomery second 202 | jc rlt_l1ml2m 203 | rlt_l1ml2n: 204 | <%= global.fromMont_a() %> 205 | jmp rltL1L2 206 | 207 | rlt_l1ml2m: 208 | <%= global.fromMont_a() %> 209 | <%= global.fromMont_b() %> 210 | jmp rltL1L2 211 | 212 | 213 | ;;;;;; 214 | ; rltL1L2 215 | ;;;;;; 216 | 217 | rltL1L2: 218 | <%= signL("rsi", "rltl1l2_p1", "rltl1l2_n1") %> 219 | rltl1l2_p1: 220 | <%= signL("rdx", "rltRawL1L2", "rlt_ret0") %> 221 | 222 | rltl1l2_n1: 223 | <%= signL("rdx", "rlt_ret1", "rltRawL1L2") %> 224 | 225 | 226 | rltRawL1L2: 227 | <% for (let i=n64-1; i>=0; i--) { %> 228 | mov rax, [rsi + <%= 8+(i*8) %>] 229 | cmp [rdx + <%= 8+(i*8) %>], rax ; comare with (q-1)/2 230 | jc rlt_ret0 ; rsi 1st > 2nd 231 | jnz rlt_ret1 232 | <% } %> 233 | 234 | rlt_ret0: 235 | xor rax, rax 236 | ret 237 | rlt_ret1: 238 | mov rax, 1 239 | ret 240 | 241 | 242 | 243 | ;;;;;;;;;;;;;;;;;;;;;; 244 | ; req - Raw Eq 245 | ;;;;;;;;;;;;;;;;;;;;;; 246 | ; returns in ax 1 id *rsi == *rdx 247 | ; Params: 248 | ; rsi <= Pointer to element 1 249 | ; rdx <= Pointer to element 2 250 | ; rax <= Return 1 or 0 251 | ; Modified Registers: 252 | ; r8, r9, rax 253 | ;;;;;;;;;;;;;;;;;;;;;; 254 | <%=name%>_req: 255 | mov r8, [rsi] 256 | mov r9, [rdx] 257 | bt r8, 63 ; Check if is short first operand 258 | jc req_l1 259 | bt r9, 63 ; Check if is short second operand 260 | jc req_s1l2 261 | 262 | req_s1s2: ; Both operands are short 263 | cmp r8d, r9d 264 | je req_ret1 265 | jmp req_ret0 266 | 267 | 268 | req_l1: 269 | bt r9, 63 ; Check if is short second operand 270 | jc req_l1l2 271 | 272 | ;;;;;;;; 273 | req_l1s2: 274 | bt r8, 62 ; check if montgomery first 275 | jc req_l1ms2 276 | req_l1ns2: 277 | <%= global.toLong_b() %> 278 | jmp reqL1L2 279 | 280 | req_l1ms2: 281 | <%= global.toMont_b() %> 282 | jmp reqL1L2 283 | 284 | 285 | ;;;;;;;; 286 | req_s1l2: 287 | bt r9, 62 ; check if montgomery second 288 | jc req_s1l2m 289 | req_s1l2n: 290 | <%= global.toLong_a() %> 291 | jmp reqL1L2 292 | 293 | req_s1l2m: 294 | <%= global.toMont_a() %> 295 | jmp reqL1L2 296 | 297 | ;;;; 298 | req_l1l2: 299 | bt r8, 62 ; check if montgomery first 300 | jc req_l1ml2 301 | req_l1nl2: 302 | bt r9, 62 ; check if montgomery second 303 | jc req_l1nl2m 304 | req_l1nl2n: 305 | jmp reqL1L2 306 | 307 | req_l1nl2m: 308 | <%= global.toMont_a() %> 309 | jmp reqL1L2 310 | 311 | req_l1ml2: 312 | bt r9, 62 ; check if montgomery second 313 | jc req_l1ml2m 314 | req_l1ml2n: 315 | <%= global.toMont_b() %> 316 | jmp reqL1L2 317 | 318 | req_l1ml2m: 319 | jmp reqL1L2 320 | 321 | 322 | ;;;;;; 323 | ; eqL1L2 324 | ;;;;;; 325 | 326 | reqL1L2: 327 | <% for (let i=0; i 328 | mov rax, [rsi + <%= 8+(i*8) %>] 329 | cmp [rdx + <%= 8+(i*8) %>], rax 330 | jne req_ret0 ; rsi 1st > 2nd 331 | <% } %> 332 | 333 | req_ret1: 334 | mov rax, 1 335 | ret 336 | 337 | req_ret0: 338 | xor rax, rax 339 | ret 340 | 341 | 342 | ;;;;;;;;;;;;;;;;;;;;;; 343 | ; gt 344 | ;;;;;;;;;;;;;;;;;;;;;; 345 | ; Compares two elements of any kind 346 | ; Params: 347 | ; rsi <= Pointer to element 1 348 | ; rdx <= Pointer to element 2 349 | ; rdi <= Pointer to result can be zero or one. 350 | ; Modified Registers: 351 | ; rax, rcx 352 | ;;;;;;;;;;;;;;;;;;;;;; 353 | <%=name%>_gt: 354 | call <%=name%>_rgt 355 | mov [rdi], rax 356 | ret 357 | 358 | ;;;;;;;;;;;;;;;;;;;;;; 359 | ; lt 360 | ;;;;;;;;;;;;;;;;;;;;;; 361 | ; Compares two elements of any kind 362 | ; Params: 363 | ; rsi <= Pointer to element 1 364 | ; rdx <= Pointer to element 2 365 | ; rdi <= Pointer to result can be zero or one. 366 | ; Modified Registers: 367 | ; rax, rcx 368 | ;;;;;;;;;;;;;;;;;;;;;; 369 | <%=name%>_lt: 370 | call <%=name%>_rlt 371 | mov [rdi], rax 372 | ret 373 | 374 | ;;;;;;;;;;;;;;;;;;;;;; 375 | ; eq 376 | ;;;;;;;;;;;;;;;;;;;;;; 377 | ; Compares two elements of any kind 378 | ; Params: 379 | ; rsi <= Pointer to element 1 380 | ; rdx <= Pointer to element 2 381 | ; rdi <= Pointer to result can be zero or one. 382 | ; Modified Registers: 383 | ; rax, rcx 384 | ;;;;;;;;;;;;;;;;;;;;;; 385 | <%=name%>_eq: 386 | call <%=name%>_req 387 | mov [rdi], rax 388 | ret 389 | 390 | ;;;;;;;;;;;;;;;;;;;;;; 391 | ; neq 392 | ;;;;;;;;;;;;;;;;;;;;;; 393 | ; Compares two elements of any kind 394 | ; Params: 395 | ; rsi <= Pointer to element 1 396 | ; rdx <= Pointer to element 2 397 | ; rdi <= Pointer to result can be zero or one. 398 | ; Modified Registers: 399 | ; rax, rcx 400 | ;;;;;;;;;;;;;;;;;;;;;; 401 | <%=name%>_neq: 402 | call <%=name%>_req 403 | xor rax, 1 404 | mov [rdi], rax 405 | ret 406 | 407 | ;;;;;;;;;;;;;;;;;;;;;; 408 | ; geq 409 | ;;;;;;;;;;;;;;;;;;;;;; 410 | ; Compares two elements of any kind 411 | ; Params: 412 | ; rsi <= Pointer to element 1 413 | ; rdx <= Pointer to element 2 414 | ; rdi <= Pointer to result can be zero or one. 415 | ; Modified Registers: 416 | ; rax, rcx 417 | ;;;;;;;;;;;;;;;;;;;;;; 418 | <%=name%>_geq: 419 | call <%=name%>_rlt 420 | xor rax, 1 421 | mov [rdi], rax 422 | ret 423 | 424 | ;;;;;;;;;;;;;;;;;;;;;; 425 | ; leq 426 | ;;;;;;;;;;;;;;;;;;;;;; 427 | ; Compares two elements of any kind 428 | ; Params: 429 | ; rsi <= Pointer to element 1 430 | ; rdx <= Pointer to element 2 431 | ; rdi <= Pointer to result can be zero or one. 432 | ; Modified Registers: 433 | ; rax, rcx 434 | ;;;;;;;;;;;;;;;;;;;;;; 435 | <%=name%>_leq: 436 | call <%=name%>_rgt 437 | xor rax, 1 438 | mov [rdi], rax 439 | ret 440 | -------------------------------------------------------------------------------- /c/old/buildasm/cmpops_old.asm.ejs: -------------------------------------------------------------------------------- 1 | 2 | <% function retOne() { %> 3 | mov qword [rdi], 1 4 | add rsp, <%= (n64+1)*8 %> 5 | ret 6 | <% } %> 7 | 8 | <% function retZero() { %> 9 | mov qword [rdi], 0 10 | add rsp, <%= (n64+1)*8 %> 11 | ret 12 | <% } %> 13 | 14 | <% function cmpLong(op, eq) { %> 15 | 16 | <% 17 | if (eq==true) { 18 | if (["leq","geq"].indexOf(op) >= 0) retOne(); 19 | if (["lt","gt"].indexOf(op) >= 0) retZero(); 20 | } 21 | %> 22 | 23 | 24 | <% const label_gt = global.tmpLabel() %> 25 | <% const label_lt = global.tmpLabel() %> 26 | <% for (let i=n64-1; i>=0; i--) { %> 27 | mov rax, [rsp + <%= 8+(i*8) %>] 28 | cmp [half + <%= (i*8) %>], rax ; comare with (q-1)/2 29 | jc <%=label_lt%> ; half e1-e2 is neg => e1 < e2 30 | jnz <%=label_gt%> ; half>rax => e1 -e2 is pos => e1 > e2 31 | <% } %> 32 | ; half == rax => e1-e2 is pos => e1 > e2 33 | <%=label_gt%>: 34 | <% if (["geq","gt"].indexOf(op) >= 0) retOne(); else retZero(); %> 35 | <%=label_lt%>: 36 | <% if (["leq","lt"].indexOf(op) >= 0) retOne(); else retZero(); %> 37 | <% } // cmpLong%> 38 | 39 | <% function cmpOp(op) { %> 40 | ;;;;;;;;;;;;;;;;;;;;;; 41 | ; <%= op %> 42 | ;;;;;;;;;;;;;;;;;;;;;; 43 | ; Compares two elements of any kind 44 | ; Params: 45 | ; rsi <= Pointer to element 1 46 | ; rdx <= Pointer to element 2 47 | ; rdi <= Pointer to result can be zero or one. 48 | ; Modified Registers: 49 | ; r8, r9, 10, r11, rax, rcx 50 | ;;;;;;;;;;;;;;;;;;;;;; 51 | <%=name%>_<%=op%>: 52 | sub rsp, <%= (n64+1)*8 %> ; Save space for the result of the substraction 53 | push rdi ; Save rdi 54 | lea rdi, [rsp+8] ; We pushed rdi so we need to add 8 55 | call <%=name%>_sub ; Do a substraction 56 | call <%=name%>_toNormal ; Convert it to normal 57 | pop rdi 58 | 59 | mov rax, [rsp] ; We already poped do no need to add 8 60 | bt rax, 63 ; check is result is long 61 | jc <%=op%>_longCmp 62 | 63 | <%=op%>_shortCmp: 64 | cmp eax, 0 65 | je <%=op%>_s_eq 66 | js <%=op%>_s_lt 67 | <%=op%>_s_gt: 68 | <% if (["geq","gt", "neq"].indexOf(op) >= 0) retOne(); else retZero(); %> 69 | <%=op%>_s_lt: 70 | <% if (["leq","lt", "neq"].indexOf(op) >= 0) retOne(); else retZero(); %> 71 | <%=op%>_s_eq: 72 | <% if (["eq","geq", "leq"].indexOf(op) >= 0) retOne(); else retZero(); %> 73 | 74 | <%=op%>_longCmp: 75 | 76 | <% for (let i=n64-1; i>=0; i--) { %> 77 | cmp qword [rsp + <%= 8+(i*8) %>], 0 78 | jnz <%=op%>_neq 79 | <% } %> 80 | <%=op%>_eq: 81 | <% if (op == "eq") { 82 | retOne(); 83 | } else if (op == "neq") { 84 | retZero(); 85 | } else { 86 | cmpLong(op, true); 87 | } 88 | %> 89 | <%=op%>_neq: 90 | <% if (op == "neq") { 91 | retOne(); 92 | } else if (op == "eq") { 93 | retZero(); 94 | } else { 95 | cmpLong(op, false); 96 | } 97 | %> 98 | 99 | 100 | <% } %> 101 | 102 | <%= cmpOp("eq") %> 103 | <%= cmpOp("neq") %> 104 | <%= cmpOp("lt") %> 105 | <%= cmpOp("gt") %> 106 | <%= cmpOp("leq") %> 107 | <%= cmpOp("geq") %> 108 | 109 | -------------------------------------------------------------------------------- /c/old/buildasm/copy.asm.ejs: -------------------------------------------------------------------------------- 1 | ;;;;;;;;;;;;;;;;;;;;;; 2 | ; copy 3 | ;;;;;;;;;;;;;;;;;;;;;; 4 | ; Copies 5 | ; Params: 6 | ; rsi <= the src 7 | ; rdi <= the dest 8 | ; 9 | ; Nidified registers: 10 | ; rax 11 | ;;;;;;;;;;;;;;;;;;;;;;; 12 | <%=name%>_copy: 13 | <% for (let i=0; i<=n64; i++) { %> 14 | mov rax, [rsi + <%= i*8 %>] 15 | mov [rdi + <%= i*8 %>], rax 16 | <% } %> 17 | ret 18 | 19 | ;;;;;;;;;;;;;;;;;;;;;; 20 | ; copy an array of integers 21 | ;;;;;;;;;;;;;;;;;;;;;; 22 | ; Copies 23 | ; Params: 24 | ; rsi <= the src 25 | ; rdi <= the dest 26 | ; rdx <= number of integers to copy 27 | ; 28 | ; Nidified registers: 29 | ; rax 30 | ;;;;;;;;;;;;;;;;;;;;;;; 31 | <%=name%>_copyn: 32 | <%=name%>_copyn_loop: 33 | mov r8, rsi 34 | mov r9, rdi 35 | mov rax, <%= n64+1 %> 36 | mul rdx 37 | mov rcx, rax 38 | cld 39 | rep movsq 40 | mov rsi, r8 41 | mov rdi, r9 42 | ret 43 | 44 | ;;;;;;;;;;;;;;;;;;;;;; 45 | ; rawCopyS2L 46 | ;;;;;;;;;;;;;;;;;;;;;; 47 | ; Convert a 64 bit integer to a long format field element 48 | ; Params: 49 | ; rsi <= the integer 50 | ; rdi <= Pointer to the overwritted element 51 | ; 52 | ; Nidified registers: 53 | ; rax 54 | ;;;;;;;;;;;;;;;;;;;;;;; 55 | 56 | rawCopyS2L: 57 | mov al, 0x80 58 | shl rax, 56 59 | mov [rdi], rax ; set the result to LONG normal 60 | 61 | cmp rsi, 0 62 | js u64toLong_adjust_neg 63 | 64 | mov [rdi + 8], rsi 65 | xor rax, rax 66 | <% for (let i=1; i 67 | mov [rdi + <%= 8+i*8 %>], rax 68 | <% } %> 69 | ret 70 | 71 | u64toLong_adjust_neg: 72 | add rsi, [q] ; Set the first digit 73 | mov [rdi + 8], rsi ; 74 | 75 | mov rsi, -1 ; all ones 76 | <% for (let i=1; i 77 | mov rax, rsi ; Add to q 78 | adc rax, [q + <%= i*8 %> ] 79 | mov [rdi + <%= (i+1)*8 %>], rax 80 | <% } %> 81 | ret 82 | 83 | ;;;;;;;;;;;;;;;;;;;;;; 84 | ; toInt 85 | ;;;;;;;;;;;;;;;;;;;;;; 86 | ; Convert a 64 bit integer to a long format field element 87 | ; Params: 88 | ; rsi <= Pointer to the element 89 | ; Returs: 90 | ; rax <= The value 91 | ;;;;;;;;;;;;;;;;;;;;;;; 92 | <%=name%>_toInt: 93 | mov rax, [rdi] 94 | bt rax, 63 95 | jc <%=name%>_long 96 | movsx rax, eax 97 | ret 98 | 99 | <%=name%>_long: 100 | bt rax, 62 101 | jnc <%=name%>_longNormal 102 | <%=name%>_longMontgomery: 103 | call <%=name%>_toLongNormal 104 | 105 | <%=name%>_longNormal: 106 | mov rax, [rdi + 8] 107 | mov rcx, rax 108 | shr rcx, 31 109 | jnz <%=name%>_longNeg 110 | <% for (let i=1; i< n64; i++) { %> 111 | mov rcx, [rdi + <%= i*8+8 %>] 112 | test rcx, rcx 113 | jnz <%=name%>_longNeg 114 | <% } %> 115 | ret 116 | 117 | <%=name%>_longNeg: 118 | mov rax, [rdi + 8] 119 | sub rax, [q] 120 | jnc <%=name%>_longErr 121 | <% for (let i=1; i 122 | mov rcx, [rdi + <%= i*8+8 %>] 123 | sbb rcx, [q + <%= i*8 %>] 124 | jnc <%=name%>_longErr 125 | <% } %> 126 | mov rcx, rax 127 | sar rcx, 31 128 | add rcx, 1 129 | jnz <%=name%>_longErr 130 | ret 131 | 132 | <%=name%>_longErr: 133 | push rdi 134 | mov rdi, 0 135 | call <%=name%>_fail 136 | pop rdi 137 | 138 | 139 | 140 | -------------------------------------------------------------------------------- /c/old/buildasm/fr.asm.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | global <%=name%>_copy 4 | global <%=name%>_copyn 5 | global <%=name%>_add 6 | global <%=name%>_sub 7 | global <%=name%>_neg 8 | global <%=name%>_mul 9 | global <%=name%>_square 10 | global <%=name%>_band 11 | global <%=name%>_bor 12 | global <%=name%>_bxor 13 | global <%=name%>_bnot 14 | global <%=name%>_eq 15 | global <%=name%>_neq 16 | global <%=name%>_lt 17 | global <%=name%>_gt 18 | global <%=name%>_leq 19 | global <%=name%>_geq 20 | global <%=name%>_land 21 | global <%=name%>_lor 22 | global <%=name%>_lnot 23 | global <%=name%>_toNormal 24 | global <%=name%>_toLongNormal 25 | global <%=name%>_toMontgomery 26 | global <%=name%>_toInt 27 | global <%=name%>_isTrue 28 | global <%=name%>_q 29 | extern <%=name%>_fail 30 | DEFAULT REL 31 | 32 | section .text 33 | <%- include('utils.asm.ejs'); %> 34 | <%- include('copy.asm.ejs'); %> 35 | <%- include('montgomery.asm.ejs'); %> 36 | <%- include('add.asm.ejs'); %> 37 | <%- include('sub.asm.ejs'); %> 38 | <%- include('neg.asm.ejs'); %> 39 | <%- include('mul.asm.ejs'); %> 40 | <%- include('binops.asm.ejs'); %> 41 | <%- include('cmpops.asm.ejs'); %> 42 | <%- include('logicalops.asm.ejs'); %> 43 | 44 | section .data 45 | <%=name%>_q: 46 | dd 0 47 | dd 0x80000000 48 | q dq <%= constantElement(q) %> 49 | half dq <%= constantElement(q.shiftRight(1)) %> 50 | R2 dq <%= constantElement(bigInt.one.shiftLeft(n64*64*2).mod(q)) %> 51 | R3 dq <%= constantElement(bigInt.one.shiftLeft(n64*64*3).mod(q)) %> 52 | lboMask dq 0x<%= bigInt("10000000000000000",16).shiftRight(n64*64 - q.bitLength()).minus(bigInt.one).toString(16) %> 53 | 54 | -------------------------------------------------------------------------------- /c/old/buildasm/fr.c: -------------------------------------------------------------------------------- 1 | #include "fr.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | mpz_t q; 8 | mpz_t zero; 9 | mpz_t one; 10 | mpz_t mask; 11 | size_t nBits; 12 | 13 | 14 | void Fr_toMpz(mpz_t r, PFrElement pE) { 15 | Fr_toNormal(pE); 16 | if (!(pE->type & Fr_LONG)) { 17 | mpz_set_si(r, pE->shortVal); 18 | if (pE->shortVal<0) { 19 | mpz_add(r, r, q); 20 | } 21 | } else { 22 | Fr_toNormal(pE); 23 | mpz_import(r, Fr_N64, -1, 8, -1, 0, (const void *)pE->longVal); 24 | } 25 | } 26 | 27 | void Fr_fromMpz(PFrElement pE, mpz_t v) { 28 | if (mpz_fits_sint_p(v)) { 29 | pE->type = Fr_SHORT; 30 | pE->shortVal = mpz_get_si(v); 31 | } else { 32 | pE->type = Fr_LONG; 33 | for (int i=0; ilongVal[i] = 0; 34 | mpz_export((void *)(pE->longVal), NULL, -1, 8, -1, 0, v); 35 | } 36 | } 37 | 38 | 39 | void Fr_init() { 40 | mpz_init(q); 41 | mpz_import(q, Fr_N64, -1, 8, -1, 0, (const void *)Fr_q.longVal); 42 | mpz_init_set_ui(zero, 0); 43 | mpz_init_set_ui(one, 1); 44 | nBits = mpz_sizeinbase (q, 2); 45 | mpz_init(mask); 46 | mpz_mul_2exp(mask, one, nBits); 47 | mpz_sub(mask, mask, one); 48 | 49 | } 50 | 51 | void Fr_str2element(PFrElement pE, char const *s) { 52 | mpz_t mr; 53 | mpz_init_set_str(mr, s, 10); 54 | Fr_fromMpz(pE, mr); 55 | } 56 | 57 | char *Fr_element2str(PFrElement pE) { 58 | mpz_t r; 59 | if (!(pE->type & Fr_LONG)) { 60 | if (pE->shortVal>=0) { 61 | char *r = new char[32]; 62 | sprintf(r, "%d", pE->shortVal); 63 | return r; 64 | } else { 65 | mpz_init_set_si(r, pE->shortVal); 66 | mpz_add(r, r, q); 67 | } 68 | } else { 69 | Fr_toNormal(pE); 70 | mpz_init(r); 71 | mpz_import(r, Fr_N64, -1, 8, -1, 0, (const void *)pE->longVal); 72 | } 73 | char *res = mpz_get_str (0, 10, r); 74 | mpz_clear(r); 75 | return res; 76 | } 77 | 78 | void Fr_idiv(PFrElement r, PFrElement a, PFrElement b) { 79 | mpz_t ma; 80 | mpz_t mb; 81 | mpz_t mr; 82 | mpz_init(ma); 83 | mpz_init(mb); 84 | mpz_init(mr); 85 | 86 | Fr_toMpz(ma, a); 87 | // char *s1 = mpz_get_str (0, 10, ma); 88 | // printf("s1 %s\n", s1); 89 | Fr_toMpz(mb, b); 90 | // char *s2 = mpz_get_str (0, 10, mb); 91 | // printf("s2 %s\n", s2); 92 | mpz_fdiv_q(mr, ma, mb); 93 | // char *sr = mpz_get_str (0, 10, mr); 94 | // printf("r %s\n", sr); 95 | Fr_fromMpz(r, mr); 96 | } 97 | 98 | void Fr_mod(PFrElement r, PFrElement a, PFrElement b) { 99 | mpz_t ma; 100 | mpz_t mb; 101 | mpz_t mr; 102 | mpz_init(ma); 103 | mpz_init(mb); 104 | mpz_init(mr); 105 | 106 | Fr_toMpz(ma, a); 107 | Fr_toMpz(mb, b); 108 | mpz_fdiv_r(mr, ma, mb); 109 | Fr_fromMpz(r, mr); 110 | } 111 | 112 | void Fr_shl(PFrElement r, PFrElement a, PFrElement b) { 113 | mpz_t ma; 114 | mpz_t mb; 115 | mpz_t mr; 116 | mpz_init(ma); 117 | mpz_init(mb); 118 | mpz_init(mr); 119 | 120 | Fr_toMpz(ma, a); 121 | Fr_toMpz(mb, b); 122 | if (mpz_cmp_ui(mb, nBits) < 0) { 123 | mpz_mul_2exp(mr, ma, mpz_get_ui(mb)); 124 | mpz_and(mr, mr, mask); 125 | if (mpz_cmp(mr, q) >= 0) { 126 | mpz_sub(mr, mr, q); 127 | } 128 | } else { 129 | mpz_sub(mb, q, mb); 130 | if (mpz_cmp_ui(mb, nBits) < 0) { 131 | mpz_tdiv_q_2exp(mr, ma, mpz_get_ui(mb)); 132 | } else { 133 | mpz_set(mr, zero); 134 | } 135 | } 136 | Fr_fromMpz(r, mr); 137 | } 138 | 139 | void Fr_shr(PFrElement r, PFrElement a, PFrElement b) { 140 | mpz_t ma; 141 | mpz_t mb; 142 | mpz_t mr; 143 | mpz_init(ma); 144 | mpz_init(mb); 145 | mpz_init(mr); 146 | 147 | Fr_toMpz(ma, a); 148 | Fr_toMpz(mb, b); 149 | if (mpz_cmp_ui(mb, nBits) < 0) { 150 | mpz_tdiv_q_2exp(mr, ma, mpz_get_ui(mb)); 151 | } else { 152 | mpz_sub(mb, q, mb); 153 | if (mpz_cmp_ui(mb, nBits) < 0) { 154 | mpz_mul_2exp(mr, ma, mpz_get_ui(mb)); 155 | mpz_and(mr, mr, mask); 156 | if (mpz_cmp(mr, q) >= 0) { 157 | mpz_sub(mr, mr, q); 158 | } 159 | } else { 160 | mpz_set(mr, zero); 161 | } 162 | } 163 | Fr_fromMpz(r, mr); 164 | } 165 | 166 | 167 | void Fr_pow(PFrElement r, PFrElement a, PFrElement b) { 168 | mpz_t ma; 169 | mpz_t mb; 170 | mpz_t mr; 171 | mpz_init(ma); 172 | mpz_init(mb); 173 | mpz_init(mr); 174 | 175 | Fr_toMpz(ma, a); 176 | Fr_toMpz(mb, b); 177 | mpz_powm(mr, ma, mb, q); 178 | Fr_fromMpz(r, mr); 179 | } 180 | 181 | void Fr_inv(PFrElement r, PFrElement a) { 182 | mpz_t ma; 183 | mpz_t mr; 184 | mpz_init(ma); 185 | mpz_init(mr); 186 | 187 | Fr_toMpz(ma, a); 188 | mpz_invert(mr, ma, q); 189 | Fr_fromMpz(r, mr); 190 | } 191 | 192 | void Fr_div(PFrElement r, PFrElement a, PFrElement b) { 193 | FrElement tmp; 194 | Fr_inv(&tmp, b); 195 | Fr_mul(r, a, &tmp); 196 | } 197 | 198 | void Fr_fail() { 199 | assert(false); 200 | } 201 | 202 | -------------------------------------------------------------------------------- /c/old/buildasm/fr.c.ejs: -------------------------------------------------------------------------------- 1 | #include "<%=name.toLowerCase()+".h"%>" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | mpz_t q; 8 | mpz_t zero; 9 | mpz_t one; 10 | mpz_t mask; 11 | size_t nBits; 12 | 13 | 14 | void <%=name%>_toMpz(mpz_t r, P<%=name%>Element pE) { 15 | <%=name%>_toNormal(pE); 16 | if (!(pE->type & <%=name%>_LONG)) { 17 | mpz_set_si(r, pE->shortVal); 18 | if (pE->shortVal<0) { 19 | mpz_add(r, r, q); 20 | } 21 | } else { 22 | <%=name%>_toNormal(pE); 23 | mpz_import(r, <%=name%>_N64, -1, 8, -1, 0, (const void *)pE->longVal); 24 | } 25 | } 26 | 27 | void <%=name%>_fromMpz(P<%=name%>Element pE, mpz_t v) { 28 | if (mpz_fits_sint_p(v)) { 29 | pE->type = <%=name%>_SHORT; 30 | pE->shortVal = mpz_get_si(v); 31 | } else { 32 | pE->type = <%=name%>_LONG; 33 | for (int i=0; i<<%=name%>_N64; i++) pE->longVal[i] = 0; 34 | mpz_export((void *)(pE->longVal), NULL, -1, 8, -1, 0, v); 35 | } 36 | } 37 | 38 | 39 | void <%=name%>_init() { 40 | mpz_init(q); 41 | mpz_import(q, <%=name%>_N64, -1, 8, -1, 0, (const void *)Fr_q.longVal); 42 | mpz_init_set_ui(zero, 0); 43 | mpz_init_set_ui(one, 1); 44 | nBits = mpz_sizeinbase (q, 2); 45 | mpz_init(mask); 46 | mpz_mul_2exp(mask, one, nBits); 47 | mpz_sub(mask, mask, one); 48 | 49 | } 50 | 51 | void <%=name%>_str2element(P<%=name%>Element pE, char const *s) { 52 | mpz_t mr; 53 | mpz_init_set_str(mr, s, 10); 54 | <%=name%>_fromMpz(pE, mr); 55 | } 56 | 57 | char *<%=name%>_element2str(P<%=name%>Element pE) { 58 | mpz_t r; 59 | if (!(pE->type & <%=name%>_LONG)) { 60 | if (pE->shortVal>=0) { 61 | char *r = new char[32]; 62 | sprintf(r, "%d", pE->shortVal); 63 | return r; 64 | } else { 65 | mpz_init_set_si(r, pE->shortVal); 66 | mpz_add(r, r, q); 67 | } 68 | } else { 69 | <%=name%>_toNormal(pE); 70 | mpz_init(r); 71 | mpz_import(r, <%=name%>_N64, -1, 8, -1, 0, (const void *)pE->longVal); 72 | } 73 | char *res = mpz_get_str (0, 10, r); 74 | mpz_clear(r); 75 | return res; 76 | } 77 | 78 | void <%=name%>_idiv(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) { 79 | mpz_t ma; 80 | mpz_t mb; 81 | mpz_t mr; 82 | mpz_init(ma); 83 | mpz_init(mb); 84 | mpz_init(mr); 85 | 86 | <%=name%>_toMpz(ma, a); 87 | // char *s1 = mpz_get_str (0, 10, ma); 88 | // printf("s1 %s\n", s1); 89 | <%=name%>_toMpz(mb, b); 90 | // char *s2 = mpz_get_str (0, 10, mb); 91 | // printf("s2 %s\n", s2); 92 | mpz_fdiv_q(mr, ma, mb); 93 | // char *sr = mpz_get_str (0, 10, mr); 94 | // printf("r %s\n", sr); 95 | <%=name%>_fromMpz(r, mr); 96 | } 97 | 98 | void <%=name%>_mod(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) { 99 | mpz_t ma; 100 | mpz_t mb; 101 | mpz_t mr; 102 | mpz_init(ma); 103 | mpz_init(mb); 104 | mpz_init(mr); 105 | 106 | <%=name%>_toMpz(ma, a); 107 | <%=name%>_toMpz(mb, b); 108 | mpz_fdiv_r(mr, ma, mb); 109 | <%=name%>_fromMpz(r, mr); 110 | } 111 | 112 | void <%=name%>_shl(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) { 113 | mpz_t ma; 114 | mpz_t mb; 115 | mpz_t mr; 116 | mpz_init(ma); 117 | mpz_init(mb); 118 | mpz_init(mr); 119 | 120 | <%=name%>_toMpz(ma, a); 121 | <%=name%>_toMpz(mb, b); 122 | if (mpz_cmp_ui(mb, nBits) < 0) { 123 | mpz_mul_2exp(mr, ma, mpz_get_ui(mb)); 124 | mpz_and(mr, mr, mask); 125 | if (mpz_cmp(mr, q) >= 0) { 126 | mpz_sub(mr, mr, q); 127 | } 128 | } else { 129 | mpz_sub(mb, q, mb); 130 | if (mpz_cmp_ui(mb, nBits) < 0) { 131 | mpz_tdiv_q_2exp(mr, ma, mpz_get_ui(mb)); 132 | } else { 133 | mpz_set(mr, zero); 134 | } 135 | } 136 | <%=name%>_fromMpz(r, mr); 137 | } 138 | 139 | void <%=name%>_shr(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) { 140 | mpz_t ma; 141 | mpz_t mb; 142 | mpz_t mr; 143 | mpz_init(ma); 144 | mpz_init(mb); 145 | mpz_init(mr); 146 | 147 | <%=name%>_toMpz(ma, a); 148 | <%=name%>_toMpz(mb, b); 149 | if (mpz_cmp_ui(mb, nBits) < 0) { 150 | mpz_tdiv_q_2exp(mr, ma, mpz_get_ui(mb)); 151 | } else { 152 | mpz_sub(mb, q, mb); 153 | if (mpz_cmp_ui(mb, nBits) < 0) { 154 | mpz_mul_2exp(mr, ma, mpz_get_ui(mb)); 155 | mpz_and(mr, mr, mask); 156 | if (mpz_cmp(mr, q) >= 0) { 157 | mpz_sub(mr, mr, q); 158 | } 159 | } else { 160 | mpz_set(mr, zero); 161 | } 162 | } 163 | <%=name%>_fromMpz(r, mr); 164 | } 165 | 166 | 167 | void <%=name%>_pow(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) { 168 | mpz_t ma; 169 | mpz_t mb; 170 | mpz_t mr; 171 | mpz_init(ma); 172 | mpz_init(mb); 173 | mpz_init(mr); 174 | 175 | <%=name%>_toMpz(ma, a); 176 | <%=name%>_toMpz(mb, b); 177 | mpz_powm(mr, ma, mb, q); 178 | <%=name%>_fromMpz(r, mr); 179 | } 180 | 181 | void <%=name%>_inv(P<%=name%>Element r, P<%=name%>Element a) { 182 | mpz_t ma; 183 | mpz_t mr; 184 | mpz_init(ma); 185 | mpz_init(mr); 186 | 187 | <%=name%>_toMpz(ma, a); 188 | mpz_invert(mr, ma, q); 189 | <%=name%>_fromMpz(r, mr); 190 | } 191 | 192 | void <%=name%>_div(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) { 193 | <%=name%>Element tmp; 194 | <%=name%>_inv(&tmp, b); 195 | <%=name%>_mul(r, a, &tmp); 196 | } 197 | 198 | void <%=name%>_fail() { 199 | assert(false); 200 | } 201 | 202 | -------------------------------------------------------------------------------- /c/old/buildasm/fr.h: -------------------------------------------------------------------------------- 1 | #ifndef __FR_H 2 | #define __FR_H 3 | 4 | #include 5 | #define Fr_N64 4 6 | #define Fr_SHORT 0x00000000 7 | #define Fr_LONG 0x80000000 8 | #define Fr_LONGMONTGOMERY 0xC0000000 9 | typedef struct __attribute__((__packed__)) { 10 | int32_t shortVal; 11 | uint32_t type; 12 | uint64_t longVal[Fr_N64]; 13 | } FrElement; 14 | typedef FrElement *PFrElement; 15 | extern FrElement Fr_q; 16 | extern "C" void Fr_copy(PFrElement r, PFrElement a); 17 | extern "C" void Fr_copyn(PFrElement r, PFrElement a, int n); 18 | extern "C" void Fr_add(PFrElement r, PFrElement a, PFrElement b); 19 | extern "C" void Fr_sub(PFrElement r, PFrElement a, PFrElement b); 20 | extern "C" void Fr_neg(PFrElement r, PFrElement a); 21 | extern "C" void Fr_mul(PFrElement r, PFrElement a, PFrElement b); 22 | extern "C" void Fr_square(PFrElement r, PFrElement a); 23 | extern "C" void Fr_band(PFrElement r, PFrElement a, PFrElement b); 24 | extern "C" void Fr_bor(PFrElement r, PFrElement a, PFrElement b); 25 | extern "C" void Fr_bxor(PFrElement r, PFrElement a, PFrElement b); 26 | extern "C" void Fr_bnot(PFrElement r, PFrElement a); 27 | extern "C" void Fr_eq(PFrElement r, PFrElement a, PFrElement b); 28 | extern "C" void Fr_neq(PFrElement r, PFrElement a, PFrElement b); 29 | extern "C" void Fr_lt(PFrElement r, PFrElement a, PFrElement b); 30 | extern "C" void Fr_gt(PFrElement r, PFrElement a, PFrElement b); 31 | extern "C" void Fr_leq(PFrElement r, PFrElement a, PFrElement b); 32 | extern "C" void Fr_geq(PFrElement r, PFrElement a, PFrElement b); 33 | extern "C" void Fr_land(PFrElement r, PFrElement a, PFrElement b); 34 | extern "C" void Fr_lor(PFrElement r, PFrElement a, PFrElement b); 35 | extern "C" void Fr_lnot(PFrElement r, PFrElement a); 36 | extern "C" void Fr_toNormal(PFrElement pE); 37 | extern "C" void Fr_toLongNormal(PFrElement pE); 38 | extern "C" void Fr_toMontgomery(PFrElement pE); 39 | 40 | extern "C" int Fr_isTrue(PFrElement pE); 41 | extern "C" int Fr_toInt(PFrElement pE); 42 | 43 | extern "C" void Fr_fail(); 44 | 45 | extern FrElement Fr_q; 46 | 47 | // Pending functions to convert 48 | 49 | void Fr_str2element(PFrElement pE, char const*s); 50 | char *Fr_element2str(PFrElement pE); 51 | void Fr_idiv(PFrElement r, PFrElement a, PFrElement b); 52 | void Fr_mod(PFrElement r, PFrElement a, PFrElement b); 53 | void Fr_inv(PFrElement r, PFrElement a); 54 | void Fr_div(PFrElement r, PFrElement a, PFrElement b); 55 | void Fr_shl(PFrElement r, PFrElement a, PFrElement b); 56 | void Fr_shr(PFrElement r, PFrElement a, PFrElement b); 57 | void Fr_pow(PFrElement r, PFrElement a, PFrElement b); 58 | 59 | 60 | void Fr_init(); 61 | 62 | 63 | 64 | #endif // __FR_H 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /c/old/buildasm/fr.h.ejs: -------------------------------------------------------------------------------- 1 | #ifndef __<%=name.toUpperCase()%>_H 2 | #define __<%=name.toUpperCase()%>_H 3 | 4 | #include 5 | #define <%=name%>_N64 <%= n64 %> 6 | #define <%=name%>_SHORT 0x00000000 7 | #define <%=name%>_LONG 0x80000000 8 | #define <%=name%>_LONGMONTGOMERY 0xC0000000 9 | typedef struct __attribute__((__packed__)) { 10 | int32_t shortVal; 11 | uint32_t type; 12 | uint64_t longVal[<%=name%>_N64]; 13 | } <%=name%>Element; 14 | typedef <%=name%>Element *P<%=name%>Element; 15 | extern <%=name%>Element <%=name%>_q; 16 | extern "C" void <%=name%>_copy(P<%=name%>Element r, P<%=name%>Element a); 17 | extern "C" void <%=name%>_copyn(P<%=name%>Element r, P<%=name%>Element a, int n); 18 | extern "C" void <%=name%>_add(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 19 | extern "C" void <%=name%>_sub(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 20 | extern "C" void <%=name%>_neg(P<%=name%>Element r, P<%=name%>Element a); 21 | extern "C" void <%=name%>_mul(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 22 | extern "C" void <%=name%>_square(P<%=name%>Element r, P<%=name%>Element a); 23 | extern "C" void <%=name%>_band(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 24 | extern "C" void <%=name%>_bor(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 25 | extern "C" void <%=name%>_bxor(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 26 | extern "C" void <%=name%>_bnot(P<%=name%>Element r, P<%=name%>Element a); 27 | extern "C" void <%=name%>_eq(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 28 | extern "C" void <%=name%>_neq(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 29 | extern "C" void <%=name%>_lt(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 30 | extern "C" void <%=name%>_gt(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 31 | extern "C" void <%=name%>_leq(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 32 | extern "C" void <%=name%>_geq(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 33 | extern "C" void <%=name%>_land(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 34 | extern "C" void <%=name%>_lor(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 35 | extern "C" void <%=name%>_lnot(P<%=name%>Element r, P<%=name%>Element a); 36 | extern "C" void <%=name%>_toNormal(P<%=name%>Element pE); 37 | extern "C" void <%=name%>_toLongNormal(P<%=name%>Element pE); 38 | extern "C" void <%=name%>_toMontgomery(P<%=name%>Element pE); 39 | 40 | extern "C" int <%=name%>_isTrue(P<%=name%>Element pE); 41 | extern "C" int <%=name%>_toInt(P<%=name%>Element pE); 42 | 43 | extern "C" void <%=name%>_fail(); 44 | 45 | extern <%=name%>Element <%=name%>_q; 46 | 47 | // Pending functions to convert 48 | 49 | void <%=name%>_str2element(P<%=name%>Element pE, char const*s); 50 | char *<%=name%>_element2str(P<%=name%>Element pE); 51 | void <%=name%>_idiv(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 52 | void <%=name%>_mod(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 53 | void <%=name%>_inv(P<%=name%>Element r, P<%=name%>Element a); 54 | void <%=name%>_div(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 55 | void <%=name%>_shl(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 56 | void <%=name%>_shr(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 57 | void <%=name%>_pow(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); 58 | 59 | 60 | void <%=name%>_init(); 61 | 62 | 63 | 64 | #endif // __<%=name.toUpperCase()%>_H 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /c/old/buildasm/fr.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iden3/circom_runtime/3ad281088f78a4be5e6d7adda073823e60ca08fa/c/old/buildasm/fr.o -------------------------------------------------------------------------------- /c/old/buildasm/logicalops.asm.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | <% function isTrue(resReg, srcPtrReg) { %> 4 | <% const longIsZero = global.tmpLabel() %> 5 | <% const retOne = global.tmpLabel("retOne") %> 6 | <% const retZero = global.tmpLabel("retZero") %> 7 | <% const done = global.tmpLabel("done") %> 8 | 9 | mov rax, [<%=srcPtrReg%>] 10 | bt rax, 63 11 | jc <%= longIsZero %> 12 | 13 | test eax, eax 14 | jz <%= retZero %> 15 | jmp <%= retOne %> 16 | 17 | <%= longIsZero %>: 18 | <% for (let i=0; i 19 | mov rax, [<%= srcPtrReg + " + " +(i*8+8) %>] 20 | test rax, rax 21 | jnz <%= retOne %> 22 | <% } %> 23 | 24 | <%= retZero %>: 25 | mov qword <%=resReg%>, 0 26 | jmp <%= done %> 27 | 28 | <%= retOne %>: 29 | mov qword <%=resReg%>, 1 30 | 31 | <%= done %>: 32 | <% } %> 33 | 34 | 35 | 36 | 37 | <% function logicalOp(op) { %> 38 | ;;;;;;;;;;;;;;;;;;;;;; 39 | ; l<%= op %> 40 | ;;;;;;;;;;;;;;;;;;;;;; 41 | ; Logical <%= op %> between two elements 42 | ; Params: 43 | ; rsi <= Pointer to element 1 44 | ; rdx <= Pointer to element 2 45 | ; rdi <= Pointer to result zero or one 46 | ; Modified Registers: 47 | ; rax, rcx, r8 48 | ;;;;;;;;;;;;;;;;;;;;;; 49 | <%=name%>_l<%=op%>: 50 | <%= isTrue("r8", "rsi") %> 51 | <%= isTrue("rcx", "rdx") %> 52 | <%=op%> rcx, r8 53 | mov [rdi], rcx 54 | ret 55 | <% } %> 56 | 57 | <% logicalOp("and"); %> 58 | <% logicalOp("or"); %> 59 | 60 | ;;;;;;;;;;;;;;;;;;;;;; 61 | ; lnot 62 | ;;;;;;;;;;;;;;;;;;;;;; 63 | ; Do the logical not of an element 64 | ; Params: 65 | ; rsi <= Pointer to element to be tested 66 | ; rdi <= Pointer to result one if element1 is zero and zero otherwise 67 | ; Modified Registers: 68 | ; rax, rax, r8 69 | ;;;;;;;;;;;;;;;;;;;;;; 70 | <%=name%>_lnot: 71 | <%= isTrue("rcx", "rsi") %> 72 | test rcx, rcx 73 | 74 | jz lnot_retOne 75 | lnot_retZero: 76 | mov qword [rdi], 0 77 | ret 78 | lnot_retOne: 79 | mov qword [rdi], 1 80 | ret 81 | 82 | 83 | ;;;;;;;;;;;;;;;;;;;;;; 84 | ; isTrue 85 | ;;;;;;;;;;;;;;;;;;;;;; 86 | ; Convert a 64 bit integer to a long format field element 87 | ; Params: 88 | ; rsi <= Pointer to the element 89 | ; Returs: 90 | ; rax <= 1 if true 0 if false 91 | ;;;;;;;;;;;;;;;;;;;;;;; 92 | <%=name%>_isTrue: 93 | <%= isTrue("rax", "rdi") %> 94 | ret 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /c/old/buildasm/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "fr.h" 5 | 6 | int main() { 7 | Fr_init(); 8 | /* 9 | FrElement a = { 0, Fr_LONGMONTGOMERY, {1,1,1,1}}; 10 | FrElement b = { 0, Fr_LONGMONTGOMERY, {2,2,2,2}}; 11 | 12 | 13 | FrElement a={0x43e1f593f0000000ULL,0x2833e84879b97091ULL,0xb85045b68181585dULL,0x30644e72e131a029ULL}; 14 | FrElement b = {3,0,0,0}; 15 | 16 | FrElement c; 17 | */ 18 | // Fr_add(&(c[0]), a, a); 19 | // Fr_add(&(c[0]), c, b); 20 | 21 | /* 22 | for (int i=0; i<1000000000; i++) { 23 | Fr_mul(&c, &a, &b); 24 | } 25 | 26 | Fr_mul(&c,&a, &b); 27 | */ 28 | 29 | /* 30 | FrElement a1[10]; 31 | FrElement a2[10]; 32 | for (int i=0; i<10; i++) { 33 | a1[i].type = Fr_LONGMONTGOMERY; 34 | a1[i].shortVal =0; 35 | for (int j=0; j 36 | <%=fnName%>: 37 | sub rsp, <%= n64*8 %> ; Reserve space for ms 38 | mov rcx, rdx ; rdx is needed for multiplications so keep it in cx 39 | mov r11, 0x<%= np64.toString(16) %> ; np 40 | xor r8,r8 41 | xor r9,r9 42 | xor r10,r10 43 | <% 44 | // Main loop 45 | for (let i=0; i 49 | 50 | <% 51 | for (let j=i-1; j>=0; j--) { // All ms 52 | if (((i-j) 54 | mov rax, [rsp + <%= j*8 %>] 55 | mul qword [q + <%= (i-j)*8 %>] 56 | add <%= r0 %>, rax 57 | adc <%= r1 %>, rdx 58 | adc <%= r2 %>, 0x0 59 | <% 60 | } 61 | } // ms 62 | %> 63 | 64 | <% 65 | if (i 67 | mov rax, <%= r0 %> 68 | mul r11 69 | mov [rsp + <%= i*8 %>], rax 70 | mul qword [q] 71 | add <%= r0 %>, rax 72 | adc <%= r1 %>, rdx 73 | adc <%= r2 %>, 0x0 74 | <% 75 | } else { 76 | %> 77 | mov [rdi + <%= (i-n64)*8 %> ], <%= r0 %> 78 | xor <%= r0 %>,<%= r0 %> 79 | <% 80 | } 81 | %> 82 | 83 | <% 84 | } // Main Loop 85 | %> 86 | test <%= r1 %>, <%= r1 %> 87 | jnz <%=fnName%>_mulM_sq 88 | ; Compare with q 89 | <% 90 | for (let i=0; i 92 | mov rax, [rdi + <%= (n64-i-1)*8 %>] 93 | cmp rax, [q + <%= (n64-i-1)*8 %>] 94 | jc <%=fnName%>_mulM_done ; q is bigget so done. 95 | jnz <%=fnName%>_mulM_sq ; q is lower 96 | <% 97 | } 98 | %> 99 | ; If equal substract q 100 | 101 | <%=fnName%>_mulM_sq: 102 | <% 103 | for (let i=0; i 105 | mov rax, [q + <%= i*8 %>] 106 | <%= i==0 ? "sub" : "sbb" %> [rdi + <%= i*8 %>], rax 107 | <% 108 | } 109 | %> 110 | 111 | <%=fnName%>_mulM_done: 112 | mov rdx, rcx ; recover rdx to its original place. 113 | add rsp, <%= n64*8 %> ; recover rsp 114 | ret 115 | 116 | <% 117 | } // Template 118 | %> 119 | 120 | ;;;;;;;;;;;;;;;;;;;;;; 121 | ; rawMontgomeryMul 122 | ;;;;;;;;;;;;;;;;;;;;;; 123 | ; Multiply two elements in montgomery form 124 | ; Params: 125 | ; rsi <= Pointer to the long data of element 1 126 | ; rdx <= Pointer to the long data of element 2 127 | ; rdi <= Pointer to the long data of result 128 | ; Modified registers: 129 | ; r8, r9, 10, r11, rax, rcx 130 | ;;;;;;;;;;;;;;;;;;;;;; 131 | <% 132 | montgomeryTemplate("rawMontgomeryMul", function(i, r0, r1, r2) { 133 | // Same Digit 134 | for (let o1=Math.max(0, i-n64+1); (o1<=i)&&(o1 137 | mov rax, [rsi + <%= 8*o1 %>] 138 | mul qword [rcx + <%= 8*o2 %>] 139 | add <%= r0 %>, rax 140 | adc <%= r1 %>, rdx 141 | adc <%= r2 %>, 0x0 142 | <% 143 | } // Same digit 144 | }) 145 | %> 146 | 147 | ;;;;;;;;;;;;;;;;;;;;;; 148 | ; rawMontgomerySquare 149 | ;;;;;;;;;;;;;;;;;;;;;; 150 | ; Square an element 151 | ; Params: 152 | ; rsi <= Pointer to the long data of element 1 153 | ; rdi <= Pointer to the long data of result 154 | ; Modified registers: 155 | ; r8, r9, 10, r11, rax, rcx 156 | ;;;;;;;;;;;;;;;;;;;;;; 157 | <% 158 | montgomeryTemplate("rawMontgomerySquare", function(i, r0, r1, r2) { 159 | // Same Digit 160 | for (let o1=Math.max(0, i-n64+1); (o1<((i+1)>>1) )&&(o1 163 | mov rax, [rsi + <%= 8*o1 %>] 164 | mul qword [rsi + <%= 8*o2 %>] 165 | add <%= r0 %>, rax 166 | adc <%= r1 %>, rdx 167 | adc <%= r2 %>, 0x0 168 | add <%= r0 %>, rax 169 | adc <%= r1 %>, rdx 170 | adc <%= r2 %>, 0x0 171 | <% 172 | } // Same digit 173 | %> 174 | 175 | <% if (i%2 == 0) { %> 176 | mov rax, [rsi + <%= 8*(i/2) %>] 177 | mul rax 178 | add <%= r0 %>, rax 179 | adc <%= r1 %>, rdx 180 | adc <%= r2 %>, 0x0 181 | <% } %> 182 | 183 | <% 184 | }) 185 | %> 186 | 187 | 188 | ;;;;;;;;;;;;;;;;;;;;;; 189 | ; rawMontgomeryMul1 190 | ;;;;;;;;;;;;;;;;;;;;;; 191 | ; Multiply two elements in montgomery form 192 | ; Params: 193 | ; rsi <= Pointer to the long data of element 1 194 | ; rdx <= second operand 195 | ; rdi <= Pointer to the long data of result 196 | ; Modified registers: 197 | ; r8, r9, 10, r11, rax, rcx 198 | ;;;;;;;;;;;;;;;;;;;;;; 199 | <% 200 | montgomeryTemplate("rawMontgomeryMul1", function(i, r0, r1, r2) { 201 | // Same Digit 202 | if (i 204 | mov rax, [rsi + <%= 8*i %>] 205 | mul rcx 206 | add <%= r0 %>, rax 207 | adc <%= r1 %>, rdx 208 | adc <%= r2 %>, 0x0 209 | <% 210 | } // Same digit 211 | }) 212 | %> 213 | 214 | 215 | ;;;;;;;;;;;;;;;;;;;;;; 216 | ; rawFromMontgomery 217 | ;;;;;;;;;;;;;;;;;;;;;; 218 | ; Multiply two elements in montgomery form 219 | ; Params: 220 | ; rsi <= Pointer to the long data of element 1 221 | ; rdi <= Pointer to the long data of result 222 | ; Modified registers: 223 | ; r8, r9, 10, r11, rax, rcx 224 | ;;;;;;;;;;;;;;;;;;;;;; 225 | <% 226 | montgomeryTemplate("rawFromMontgomery", function(i, r0, r1, r2) { 227 | // Same Digit 228 | if (i 230 | add <%= r0 %>, [rdi + <%= 8*i %>] 231 | adc <%= r1 %>, 0x0 232 | adc <%= r2 %>, 0x0 233 | <% 234 | } // Same digit 235 | }) 236 | %> 237 | 238 | ;;;;;;;;;;;;;;;;;;;;;; 239 | ; toMontgomery 240 | ;;;;;;;;;;;;;;;;;;;;;; 241 | ; Convert a number to Montgomery 242 | ; rdi <= Pointer element to convert 243 | ; Modified registers: 244 | ; r8, r9, 10, r11, rax, rcx 245 | ;;;;;;;;;;;;;;;;;;;; 246 | <%=name%>_toMontgomery: 247 | mov rax, [rdi] 248 | bt rax, 62 ; check if montgomery 249 | jc toMontgomery_doNothing 250 | bt rax, 63 251 | jc toMontgomeryLong 252 | 253 | toMontgomeryShort: 254 | add rdi, 8 255 | push rsi 256 | push rdx 257 | lea rsi, [R2] 258 | movsx rdx, eax 259 | cmp rdx, 0 260 | js negMontgomeryShort 261 | posMontgomeryShort: 262 | call rawMontgomeryMul1 263 | pop rdx 264 | pop rsi 265 | sub rdi, 8 266 | <%= global.setTypeDest("0x40"); %> 267 | ret 268 | 269 | negMontgomeryShort: 270 | neg rdx ; Do the multiplication positive and then negate the result. 271 | call rawMontgomeryMul1 272 | mov rsi, rdi 273 | call rawNegL 274 | pop rdx 275 | pop rsi 276 | sub rdi, 8 277 | <%= global.setTypeDest("0x40"); %> 278 | ret 279 | 280 | 281 | toMontgomeryLong: 282 | mov [rdi], rax 283 | add rdi, 8 284 | push rsi 285 | mov rdx, rdi 286 | lea rsi, [R2] 287 | call rawMontgomeryMul 288 | pop rsi 289 | sub rdi, 8 290 | <%= global.setTypeDest("0xC0"); %> 291 | 292 | 293 | toMontgomery_doNothing: 294 | ret 295 | 296 | ;;;;;;;;;;;;;;;;;;;;;; 297 | ; toNormal 298 | ;;;;;;;;;;;;;;;;;;;;;; 299 | ; Convert a number from Montgomery 300 | ; rdi <= Pointer element to convert 301 | ; Modified registers: 302 | ; r8, r9, 10, r11, rax, rcx 303 | ;;;;;;;;;;;;;;;;;;;; 304 | <%=name%>_toNormal: 305 | mov rax, [rdi] 306 | bt rax, 62 ; check if montgomery 307 | jnc toNormal_doNothing 308 | bt rax, 63 ; if short, it means it's converted 309 | jnc toNormal_doNothing 310 | 311 | toNormalLong: 312 | add rdi, 8 313 | call rawFromMontgomery 314 | sub rdi, 8 315 | <%= global.setTypeDest("0x80"); %> 316 | 317 | toNormal_doNothing: 318 | ret 319 | 320 | ;;;;;;;;;;;;;;;;;;;;;; 321 | ; toLongNormal 322 | ;;;;;;;;;;;;;;;;;;;;;; 323 | ; Convert a number to long normal 324 | ; rdi <= Pointer element to convert 325 | ; Modified registers: 326 | ; r8, r9, 10, r11, rax, rcx 327 | ;;;;;;;;;;;;;;;;;;;; 328 | <%=name%>_toLongNormal: 329 | mov rax, [rdi] 330 | bt rax, 62 ; check if montgomery 331 | jc toLongNormal_fromMontgomery 332 | bt rax, 63 ; check if long 333 | jnc toLongNormal_fromShort 334 | ret ; It is already long 335 | 336 | toLongNormal_fromMontgomery: 337 | add rdi, 8 338 | call rawFromMontgomery 339 | sub rdi, 8 340 | <%= global.setTypeDest("0x80"); %> 341 | ret 342 | 343 | toLongNormal_fromShort: 344 | mov r8, rsi ; save rsi 345 | movsx rsi, eax 346 | call rawCopyS2L 347 | mov rsi, r8 ; recover rsi 348 | <%= global.setTypeDest("0x80"); %> 349 | ret 350 | 351 | -------------------------------------------------------------------------------- /c/old/buildasm/mul.asm.ejs: -------------------------------------------------------------------------------- 1 | <% function mulS1S2() { %> 2 | xor rax, rax 3 | mov eax, r8d 4 | imul r9d 5 | jo mul_manageOverflow ; rsi already is the 64bits result 6 | 7 | mov [rdi], rax ; not necessary to adjust so just save and return 8 | 9 | mul_manageOverflow: ; Do the operation in 64 bits 10 | push rsi 11 | movsx rax, r8d 12 | movsx rcx, r9d 13 | imul rcx 14 | mov rsi, rax 15 | call rawCopyS2L 16 | pop rsi 17 | <% } %> 18 | 19 | <% function squareS1() { %> 20 | xor rax, rax 21 | mov eax, r8d 22 | imul eax 23 | jo square_manageOverflow ; rsi already is the 64bits result 24 | 25 | mov [rdi], rax ; not necessary to adjust so just save and return 26 | 27 | square_manageOverflow: ; Do the operation in 64 bits 28 | push rsi 29 | movsx rax, r8d 30 | imul rax 31 | mov rsi, rax 32 | call rawCopyS2L 33 | pop rsi 34 | <% } %> 35 | 36 | 37 | <% function mulL1S2(t) { %> 38 | push rsi 39 | add rsi, 8 40 | movsx rdx, r9d 41 | add rdi, 8 42 | cmp rdx, 0 43 | <% const rawPositiveLabel = global.tmpLabel() %> 44 | jns <%= rawPositiveLabel %> 45 | neg rdx 46 | call rawMontgomeryMul1 47 | mov rsi, rdi 48 | call rawNegL 49 | sub rdi, 8 50 | pop rsi 51 | <% const done = global.tmpLabel() %> 52 | jmp <%= done %> 53 | <%= rawPositiveLabel %>: 54 | call rawMontgomeryMul1 55 | sub rdi, 8 56 | pop rsi 57 | <%= done %>: 58 | 59 | <% } %> 60 | 61 | <% function mulS1L2() { %> 62 | push rsi 63 | lea rsi, [rdx + 8] 64 | movsx rdx, r8d 65 | add rdi, 8 66 | cmp rdx, 0 67 | <% const rawPositiveLabel = global.tmpLabel() %> 68 | jns <%= rawPositiveLabel %> 69 | neg rdx 70 | call rawMontgomeryMul1 71 | mov rsi, rdi 72 | call rawNegL 73 | sub rdi, 8 74 | pop rsi 75 | <% const done = global.tmpLabel() %> 76 | jmp <%= done %> 77 | <%= rawPositiveLabel %>: 78 | call rawMontgomeryMul1 79 | sub rdi, 8 80 | pop rsi 81 | <%= done %>: 82 | 83 | <% } %> 84 | 85 | <% function mulL1L2() { %> 86 | add rdi, 8 87 | add rsi, 8 88 | add rdx, 8 89 | call rawMontgomeryMul 90 | sub rdi, 8 91 | sub rsi, 8 92 | <% } %> 93 | 94 | 95 | <% function squareL1() { %> 96 | add rdi, 8 97 | add rsi, 8 98 | call rawMontgomerySquare 99 | sub rdi, 8 100 | sub rsi, 8 101 | <% } %> 102 | 103 | <% function mulR3() { %> 104 | push rsi 105 | add rdi, 8 106 | mov rsi, rdi 107 | lea rdx, [R3] 108 | call rawMontgomeryMul 109 | sub rdi, 8 110 | pop rsi 111 | <% } %> 112 | 113 | 114 | 115 | ;;;;;;;;;;;;;;;;;;;;;; 116 | ; square 117 | ;;;;;;;;;;;;;;;;;;;;;; 118 | ; Squares a field element 119 | ; Params: 120 | ; rsi <= Pointer to element 1 121 | ; rdi <= Pointer to result 122 | ; [rdi] = [rsi] * [rsi] 123 | ; Modified Registers: 124 | ; r8, r9, 10, r11, rax, rcx 125 | ;;;;;;;;;;;;;;;;;;;;;; 126 | <%=name%>_square: 127 | mov r8, [rsi] 128 | bt r8, 63 ; Check if is short first operand 129 | jc square_l1 130 | 131 | square_s1: ; Both operands are short 132 | <%= squareS1() %> 133 | ret 134 | 135 | square_l1: 136 | bt r8, 62 ; check if montgomery first 137 | jc square_l1m 138 | square_l1n: 139 | <%= global.setTypeDest("0xC0"); %> 140 | <%= squareL1() %> 141 | <%= mulR3() %> 142 | ret 143 | 144 | square_l1m: 145 | <%= global.setTypeDest("0xC0"); %> 146 | <%= squareL1() %> 147 | ret 148 | 149 | 150 | 151 | ;;;;;;;;;;;;;;;;;;;;;; 152 | ; mul 153 | ;;;;;;;;;;;;;;;;;;;;;; 154 | ; Multiplies two elements of any kind 155 | ; Params: 156 | ; rsi <= Pointer to element 1 157 | ; rdx <= Pointer to element 2 158 | ; rdi <= Pointer to result 159 | ; [rdi] = [rsi] * [rdi] 160 | ; Modified Registers: 161 | ; r8, r9, 10, r11, rax, rcx 162 | ;;;;;;;;;;;;;;;;;;;;;; 163 | <%=name%>_mul: 164 | mov r8, [rsi] 165 | mov r9, [rdx] 166 | bt r8, 63 ; Check if is short first operand 167 | jc mul_l1 168 | bt r9, 63 ; Check if is short second operand 169 | jc mul_s1l2 170 | 171 | mul_s1s2: ; Both operands are short 172 | <%= mulS1S2() %> 173 | ret 174 | 175 | mul_l1: 176 | bt r9, 63 ; Check if is short second operand 177 | jc mul_l1l2 178 | 179 | ;;;;;;;; 180 | mul_l1s2: 181 | bt r8, 62 ; check if montgomery first 182 | jc mul_l1ms2 183 | mul_l1ns2: 184 | bt r9, 62 ; check if montgomery first 185 | jc mul_l1ns2m 186 | mul_l1ns2n: 187 | <%= global.setTypeDest("0xC0"); %> 188 | <%= mulL1S2() %> 189 | <%= mulR3() %> 190 | ret 191 | 192 | 193 | mul_l1ns2m: 194 | <%= global.setTypeDest("0x80"); %> 195 | <%= mulL1L2() %> 196 | ret 197 | 198 | 199 | mul_l1ms2: 200 | bt r9, 62 ; check if montgomery second 201 | jc mul_l1ms2m 202 | mul_l1ms2n: 203 | <%= global.setTypeDest("0x80"); %> 204 | <%= mulL1S2() %> 205 | ret 206 | 207 | mul_l1ms2m: 208 | <%= global.setTypeDest("0xC0"); %> 209 | <%= mulL1L2() %> 210 | ret 211 | 212 | 213 | ;;;;;;;; 214 | mul_s1l2: 215 | bt r8, 62 ; check if montgomery first 216 | jc mul_s1ml2 217 | mul_s1nl2: 218 | bt r9, 62 ; check if montgomery first 219 | jc mul_s1nl2m 220 | mul_s1nl2n: 221 | <%= global.setTypeDest("0xC0"); %> 222 | <%= mulS1L2() %> 223 | <%= mulR3() %> 224 | ret 225 | 226 | mul_s1nl2m: 227 | <%= global.setTypeDest("0x80"); %> 228 | <%= mulS1L2(); %> 229 | ret 230 | 231 | mul_s1ml2: 232 | bt r9, 62 ; check if montgomery first 233 | jc mul_s1ml2m 234 | mul_s1ml2n: 235 | <%= global.setTypeDest("0x80"); %> 236 | <%= mulL1L2() %> 237 | ret 238 | 239 | mul_s1ml2m: 240 | <%= global.setTypeDest("0xC0"); %> 241 | <%= mulL1L2() %> 242 | ret 243 | 244 | ;;;; 245 | mul_l1l2: 246 | bt r8, 62 ; check if montgomery first 247 | jc mul_l1ml2 248 | mul_l1nl2: 249 | bt r9, 62 ; check if montgomery second 250 | jc mul_l1nl2m 251 | mul_l1nl2n: 252 | <%= global.setTypeDest("0xC0"); %> 253 | <%= mulL1L2() %> 254 | <%= mulR3() %> 255 | ret 256 | 257 | mul_l1nl2m: 258 | <%= global.setTypeDest("0x80"); %> 259 | <%= mulL1L2() %> 260 | ret 261 | 262 | mul_l1ml2: 263 | bt r9, 62 ; check if montgomery seconf 264 | jc mul_l1ml2m 265 | mul_l1ml2n: 266 | <%= global.setTypeDest("0x80"); %> 267 | <%= mulL1L2() %> 268 | ret 269 | 270 | mul_l1ml2m: 271 | <%= global.setTypeDest("0xC0"); %> 272 | <%= mulL1L2() %> 273 | ret 274 | 275 | 276 | -------------------------------------------------------------------------------- /c/old/buildasm/neg.asm.ejs: -------------------------------------------------------------------------------- 1 | <% function negS() { %> 2 | neg eax 3 | jo neg_manageOverflow ; Check if overflow. (0x80000000 is the only case) 4 | 5 | mov [rdi], rax ; not necessary to adjust so just save and return 6 | ret 7 | 8 | neg_manageOverflow: ; Do the operation in 64 bits 9 | push rsi 10 | movsx rsi, eax 11 | neg rsi 12 | call rawCopyS2L 13 | pop rsi 14 | ret 15 | <% } %> 16 | 17 | <% function negL() { %> 18 | add rdi, 8 19 | add rsi, 8 20 | call rawNegL 21 | sub rdi, 8 22 | sub rsi, 8 23 | ret 24 | <% } %> 25 | 26 | ;;;;;;;;;;;;;;;;;;;;;; 27 | ; neg 28 | ;;;;;;;;;;;;;;;;;;;;;; 29 | ; Adds two elements of any kind 30 | ; Params: 31 | ; rsi <= Pointer to element to be negated 32 | ; rdi <= Pointer to result 33 | ; [rdi] = -[rsi] 34 | ;;;;;;;;;;;;;;;;;;;;;; 35 | <%=name%>_neg: 36 | mov rax, [rsi] 37 | bt rax, 63 ; Check if is short first operand 38 | jc neg_l 39 | 40 | neg_s: ; Operand is short 41 | <%= negS() %> 42 | 43 | 44 | neg_l: 45 | mov [rdi], rax ; Copy the type 46 | <%= negL() %> 47 | 48 | 49 | ;;;;;;;;;;;;;;;;;;;;;; 50 | ; rawNeg 51 | ;;;;;;;;;;;;;;;;;;;;;; 52 | ; Negates a value 53 | ; Params: 54 | ; rdi <= Pointer to the long data of result 55 | ; rsi <= Pointer to the long data of element 1 56 | ; 57 | ; [rdi] = - [rsi] 58 | ;;;;;;;;;;;;;;;;;;;;;; 59 | rawNegL: 60 | ; Compare is zero 61 | 62 | xor rax, rax 63 | <% for (let i=0; i 64 | cmp [rsi + <%=i*8%>], rax 65 | jnz doNegate 66 | <% } %> 67 | ; it's zero so just set to zero 68 | <% for (let i=0; i 69 | mov [rdi + <%=i*8%>], rax 70 | <% } %> 71 | ret 72 | doNegate: 73 | <% for (let i=0; i 74 | mov rax, [q + <%=i*8%>] 75 | <%= i==0 ? "sub" : "sbb" %> rax, [rsi + <%=i*8%>] 76 | mov [rdi + <%=i*8%>], rax 77 | <% } %> 78 | ret 79 | -------------------------------------------------------------------------------- /c/old/buildasm/old/buildfieldasm.js: -------------------------------------------------------------------------------- 1 | const tester = require("../c/buildasm/buildzqfieldtester2.js"); 2 | 3 | const bigInt = require("big-integer"); 4 | 5 | const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); 6 | 7 | 8 | describe("basic cases", function () { 9 | this.timeout(100000); 10 | it("should do basic tests", async () => { 11 | await tester(__P__, [ 12 | ["add", 0, 0], 13 | ["add", 0, 1], 14 | ["add", 1, 0], 15 | ["add", 1, 1], 16 | ["add", 2, 1], 17 | ["add", 2, 10], 18 | ["add", -1, -1], 19 | ["add", -20, -10], 20 | ["add", "10604728079509999371218483608188593244163417117449316147628604036713980815027", "10604728079509999371218483608188593244163417117449316147628604036713980815027"], 21 | 22 | ["mul", 0, 0], 23 | ["mul", 0, 1], 24 | ["mul", 1, 0], 25 | ["mul", 1, 1], 26 | ["mul", 2, 1], 27 | ["mul", 2, 10], 28 | ["mul", -1, -1], 29 | ["mul", -20, -10], 30 | ["mul", "10604728079509999371218483608188593244163417117449316147628604036713980815027", "10604728079509999371218483608188593244163417117449316147628604036713980815027"], 31 | ]); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /c/old/buildasm/old/buildzqfield.js: -------------------------------------------------------------------------------- 1 | const bigInt=require("big-integer"); 2 | 3 | 4 | 5 | 6 | 7 | class ZqBuilder { 8 | constructor(q, name) { 9 | this.q=bigInt(q); 10 | this.h = []; 11 | this.c = []; 12 | this.name = name; 13 | } 14 | 15 | build() { 16 | this._buildHeaders(); 17 | this._buildAdd(); 18 | this._buildMul(); 19 | 20 | this.c.push(""); this.h.push(""); 21 | return [this.h.join("\n"), this.c.join("\n")]; 22 | } 23 | 24 | _buildHeaders() { 25 | this.n64 = Math.floor((this.q.bitLength() - 1) / 64)+1; 26 | this.h.push("typedef unsigned long long u64;"); 27 | this.h.push(`typedef u64 ${this.name}Element[${this.n64}];`); 28 | this.h.push(`typedef u64 *P${this.name}Element;`); 29 | this.h.push(`extern ${this.name}Element ${this.name}_q;`); 30 | this.h.push(`#define ${this.name}_N64 ${this.n64}`); 31 | this.c.push(`#include "${this.name.toLowerCase()}.h"`); 32 | this._defineConstant(`${this.name}_q`, this.q); 33 | this.c.push(""); this.h.push(""); 34 | } 35 | 36 | _defineConstant(n, v) { 37 | let S = `${this.name}Element ${n}={`; 38 | const mask = bigInt("FFFFFFFFFFFFFFFF", 16); 39 | for (let i=0; i0) S = S+","; 41 | let shex = v.shiftRight(i*64).and(mask).toString(16); 42 | while (shex <16) shex = "0" + shex; 43 | S = S + "0x" + shex + "ULL"; 44 | } 45 | S += "};"; 46 | this.c.push(S); 47 | } 48 | 49 | _buildAdd() { 50 | this.h.push(`void ${this.name}_add(P${this.name}Element r, P${this.name}Element a, P${this.name}Element b);`); 51 | this.c.push(`void ${this.name}_add(P${this.name}Element r, P${this.name}Element a, P${this.name}Element b) {`); 52 | this.c.push(" __asm__ __volatile__ ("); 53 | for (let i=0; i0) { 61 | this.c.push(` "movq ${(this.n64 - i-1)*8}(%0), %%rax;"`); 62 | } 63 | this.c.push(` "cmp ${(this.n64 - i-1)*8}(%3), %%rax;"`); 64 | this.c.push(" \"jg SQ;\""); 65 | this.c.push(" \"jl DONE;\""); 66 | } 67 | this.c.push(" \"SQ:\""); 68 | for (let i=0; i=0; j--) { 121 | if (((i-j)_add 4 | global <%=name%>_mul 5 | global <%=name%>_q 6 | DEFAULT REL 7 | 8 | section .text 9 | 10 | ;;;;;;;;;;;;;;;;;;;;;; 11 | ; add 12 | ;;;;;;;;;;;;;;;;;;;;;; 13 | <%=name%>_add: 14 | ; Add component by component with carry 15 | <% for (let i=0; i 16 | mov rax, [rsi + <%=i*8%>] 17 | <%= i==0 ? "add" : "adc" %> rax, [rdx + <%=i*8%>] 18 | mov [rdi + <%=i*8%>], rax 19 | <% } %> 20 | jc add_sq ; if overflow, substract q 21 | 22 | ; Compare with q 23 | <% for (let i=0; i 24 | <% if (i>0) { %> 25 | mov rax, [rdi + <%= (n64-i-1)*8 %>] 26 | <% } %> 27 | cmp rax, [q + <%= (n64-i-1)*8 %>] 28 | jg add_sq 29 | jl add_done 30 | <% } %> 31 | ; If equal substract q 32 | add_sq: 33 | <% for (let i=0; i 34 | mov rax, [q + <%=i*8%>] 35 | <%= i==0 ? "sub" : "sbb" %> [rdi + <%=i*8%>], rax 36 | mov [rdx + <%=i*8%>], rax 37 | <% } %> 38 | 39 | add_done: 40 | ret 41 | 42 | 43 | ;;;;;;;;;;;;;;;;;;;;;; 44 | ; mul Montgomery 45 | ;;;;;;;;;;;;;;;;;;;;;; 46 | mulM: 47 | <% 48 | let r0, r1, r2; 49 | function setR(step) { 50 | if ((step % 3) == 0) { 51 | r0 = "r8"; 52 | r1 = "r9"; 53 | r2 = "r10"; 54 | } else if ((step % 3) == 1) { 55 | r0 = "r9"; 56 | r1 = "r10"; 57 | r2 = "r8"; 58 | } else { 59 | r0 = "r10"; 60 | r1 = "r8"; 61 | r2 = "r9"; 62 | } 63 | } 64 | 65 | const base = bigInt.one.shiftLeft(64); 66 | const np64 = base.minus(q.modInv(base)); 67 | %> 68 | sub rsp, <%= n64*8 %> ; Reserve space for ms 69 | mov rcx, rdx ; rdx is needed for multiplications so keep it in cx 70 | mov r11, 0x<%= np64.toString(16) %> ; np 71 | xor r8,r8 72 | xor r9,r9 73 | xor r10,r10 74 | <% 75 | // Main loop 76 | for (let i=0; i 79 | <% 80 | // Same Digit 81 | for (let o1=Math.max(0, i-n64+1); (o1<=i)&&(o1 84 | mov rax, [rsi + <%= 8*o1 %>] 85 | mul qword [rcx + <%= 8*o2 %>] 86 | add <%= r0 %>, rax 87 | adc <%= r1 %>, rdx 88 | adc <%= r2 %>, 0x0 89 | <% 90 | } // Same digit 91 | %> 92 | 93 | 94 | <% 95 | for (let j=i-1; j>=0; j--) { // All ms 96 | if (((i-j) 98 | mov rax, [rsp + <%= j*8 %>] 99 | mul qword [q + <%= (i-j)*8 %>] 100 | add <%= r0 %>, rax 101 | adc <%= r1 %>, rdx 102 | adc <%= r2 %>, 0x0 103 | <% 104 | } 105 | } // ms 106 | %> 107 | 108 | <% 109 | if (i 111 | mov rax, <%= r0 %> 112 | mul r11 113 | mov [rsp + <%= i*8 %>], rax 114 | mul qword [q] 115 | add <%= r0 %>, rax 116 | adc <%= r1 %>, rdx 117 | adc <%= r2 %>, 0x0 118 | <% 119 | } else { 120 | %> 121 | mov [rdi + <%= (i-n64)*8 %> ], <%= r0 %> 122 | xor <%= r0 %>,<%= r0 %> 123 | <% 124 | } 125 | %> 126 | 127 | <% 128 | } // Main Loop 129 | %> 130 | cmp <%= r1 %>, 0x0 131 | jne mulM_sq 132 | ; Compare with q 133 | <% 134 | for (let i=0; i 136 | mov rax, [rdi + <%= (n64-i-1)*8 %>] 137 | cmp rax, [q + <%= (n64-i-1)*8 %>] 138 | jg mulM_sq 139 | jl mulM_done 140 | <% 141 | } 142 | %> 143 | ; If equal substract q 144 | 145 | mulM_sq: 146 | <% 147 | for (let i=0; i 149 | mov rax, [q + <%= i*8 %>] 150 | <%= i==0 ? "sub" : "sbb" %> [rdi + <%= i*8 %>], rax 151 | mov [rdx + <%= i*8 %>], rax 152 | <% 153 | } 154 | %> 155 | 156 | mulM_done: 157 | add rsp, <%= n64*8 %> ; recover rsp 158 | ret 159 | 160 | ;;;;;;;;;;;;;;;;;;;;;; 161 | ; mul MontgomeryShort 162 | ;;;;;;;;;;;;;;;;;;;;;; 163 | mulSM: 164 | 165 | ;;;;;;;;;;;;;;;;;;;;;; 166 | ; mul 167 | ;;;;;;;;;;;;;;;;;;;;;; 168 | <%=name%>_mul: 169 | mov rax, [rsi] 170 | bt rax, 63 171 | jc l1 172 | mov rcx, [rdx] 173 | bt rcx, 63 174 | jc s1l2 175 | s1s2: ; short first and second 176 | mul ecx 177 | jc rs2l ; If if doesn't feed in 32 bits convert the result to long 178 | 179 | ; The shorts multiplication is done. copy the val to destination and return 180 | mov [rdi], rax 181 | ret 182 | 183 | rs2l: ; The result in the multiplication doen't feed 184 | ; we have the result in edx:eax we need to convert it to long 185 | shl rdx, 32 186 | mov edx, eax ; pack edx:eax to rdx 187 | 188 | xor rax, rax ; Set the format to long 189 | bts rax, 63 190 | mov [rdi], rax ; move the first digit 191 | 192 | cmp rdx, 0 ; check if redx is negative. 193 | jl rs2ln 194 | 195 | ; edx is positive. 196 | mov [rdi + 8], rdx ; Set the firs digit 197 | 198 | xor rax, rax ; Set the remaining digits to 0 199 | <% for (let i=1; i 200 | mov [rdi + <%= (i+1)*8 %>], rax 201 | <% } %> 202 | ret 203 | 204 | ; edx is negative. 205 | rs2ln: 206 | 207 | add rdx, [q] ; Set the firs digit 208 | mov [rdi + 8], rdx ; 209 | 210 | mov rdx, -1 ; all ones 211 | <% for (let i=1; i 212 | mov rax, rdx ; Add to q 213 | adc rax, [q + <%= i*8 %> ] 214 | mov [rdi + <%= (i+1)*8 %>], rax 215 | <% } %> 216 | ret 217 | 218 | l1: 219 | mov rcx, [rdx] 220 | bt rcx, 63 221 | jc ll 222 | 223 | l1s2: 224 | xor rdx, rdx 225 | mov edx, ecx 226 | bt rax, 62 227 | jc lsM 228 | jmp lsN 229 | 230 | s1l2: 231 | mov rsi, rdx 232 | xor rdx, rdx 233 | mov edx, eax 234 | bt rcx, 62 235 | jc lsM 236 | jmp lsN 237 | 238 | 239 | lsN: 240 | mov byte [rdi + 3], 0xC0 ; set the result to montgomery 241 | add rsi, 8 242 | add rdi, 8 243 | call mulSM 244 | mov rdx, R3 245 | call mulM 246 | ret 247 | 248 | lsM: 249 | mov byte [rdi + 3], 0x80 ; set the result to long normal 250 | add rsi, 8 251 | add rdi, 8 252 | call mulSM 253 | ret 254 | 255 | 256 | ll: 257 | 258 | bt rax, 62 259 | jc lml 260 | bt rcx, 62 261 | jc lnlm 262 | 263 | lnln: 264 | mov byte [rdi + 3], 0xC0 ; set the result to long montgomery 265 | add rsi, 8 266 | add rdi, 8 267 | add rdx, 8 268 | call mulM 269 | mov rdi, rsi 270 | mov rdx, R3 271 | call mulM 272 | ret 273 | 274 | lml: 275 | bt rcx, 62 276 | jc lmlm 277 | 278 | lnlm: 279 | mov byte [rdi + 3], 0x80 ; set the result to long normal 280 | add rsi, 8 281 | add rdi, 8 282 | add rdx, 8 283 | call mulM 284 | ret 285 | 286 | lmlm: 287 | mov byte [rdi + 3], 0xC0 ; set the result to long montgomery 288 | add rsi, 8 289 | add rdi, 8 290 | add rdx, 8 291 | call mulM 292 | ret 293 | 294 | 295 | section .data 296 | <%=name%>_q: 297 | dd 0 298 | dd 0x80000000 299 | q dq <%= constantElement(q) %> 300 | R3 dq <%= constantElement(bigInt.one.shiftLeft(n64*64*3).mod(q)) %> 301 | 302 | 303 | -------------------------------------------------------------------------------- /c/old/buildasm/old/mul.asm.ejs: -------------------------------------------------------------------------------- 1 | 2 | ;;;;;;;;;;;;;;;;;;;;;; 3 | ; mul Montgomery 4 | ;;;;;;;;;;;;;;;;;;;;;; 5 | mulM: 6 | <% 7 | let r0, r1, r2; 8 | function setR(step) { 9 | if ((step % 3) == 0) { 10 | r0 = "r8"; 11 | r1 = "r9"; 12 | r2 = "r10"; 13 | } else if ((step % 3) == 1) { 14 | r0 = "r9"; 15 | r1 = "r10"; 16 | r2 = "r8"; 17 | } else { 18 | r0 = "r10"; 19 | r1 = "r8"; 20 | r2 = "r9"; 21 | } 22 | } 23 | 24 | const base = bigInt.one.shiftLeft(64); 25 | const np64 = base.minus(q.modInv(base)); 26 | %> 27 | sub rsp, <%= n64*8 %> ; Reserve space for ms 28 | mov rcx, rdx ; rdx is needed for multiplications so keep it in cx 29 | mov r11, 0x<%= np64.toString(16) %> ; np 30 | xor r8,r8 31 | xor r9,r9 32 | xor r10,r10 33 | <% 34 | // Main loop 35 | for (let i=0; i 38 | <% 39 | // Same Digit 40 | for (let o1=Math.max(0, i-n64+1); (o1<=i)&&(o1 43 | mov rax, [rsi + <%= 8*o1 %>] 44 | mul qword [rcx + <%= 8*o2 %>] 45 | add <%= r0 %>, rax 46 | adc <%= r1 %>, rdx 47 | adc <%= r2 %>, 0x0 48 | <% 49 | } // Same digit 50 | %> 51 | 52 | 53 | <% 54 | for (let j=i-1; j>=0; j--) { // All ms 55 | if (((i-j) 57 | mov rax, [rsp + <%= j*8 %>] 58 | mul qword [q + <%= (i-j)*8 %>] 59 | add <%= r0 %>, rax 60 | adc <%= r1 %>, rdx 61 | adc <%= r2 %>, 0x0 62 | <% 63 | } 64 | } // ms 65 | %> 66 | 67 | <% 68 | if (i 70 | mov rax, <%= r0 %> 71 | mul r11 72 | mov [rsp + <%= i*8 %>], rax 73 | mul qword [q] 74 | add <%= r0 %>, rax 75 | adc <%= r1 %>, rdx 76 | adc <%= r2 %>, 0x0 77 | <% 78 | } else { 79 | %> 80 | mov [rdi + <%= (i-n64)*8 %> ], <%= r0 %> 81 | xor <%= r0 %>,<%= r0 %> 82 | <% 83 | } 84 | %> 85 | 86 | <% 87 | } // Main Loop 88 | %> 89 | cmp <%= r1 %>, 0x0 90 | jne mulM_sq 91 | ; Compare with q 92 | <% 93 | for (let i=0; i 95 | mov rax, [rdi + <%= (n64-i-1)*8 %>] 96 | cmp rax, [q + <%= (n64-i-1)*8 %>] 97 | jg mulM_sq 98 | jl mulM_done 99 | <% 100 | } 101 | %> 102 | ; If equal substract q 103 | 104 | mulM_sq: 105 | <% 106 | for (let i=0; i 108 | mov rax, [q + <%= i*8 %>] 109 | <%= i==0 ? "sub" : "sbb" %> [rdi + <%= i*8 %>], rax 110 | <% 111 | } 112 | %> 113 | 114 | mulM_done: 115 | add rsp, <%= n64*8 %> ; recover rsp 116 | ret 117 | 118 | ;;;;;;;;;;;;;;;;;;;;;; 119 | ; mul MontgomeryShort 120 | ;;;;;;;;;;;;;;;;;;;;;; 121 | mulSM: 122 | 123 | ;;;;;;;;;;;;;;;;;;;;;; 124 | ; mul 125 | ;;;;;;;;;;;;;;;;;;;;;; 126 | <%=name%>_mul: 127 | mov rax, [rsi] 128 | bt rax, 63 129 | jc l1 130 | mov rcx, [rdx] 131 | bt rcx, 63 132 | jc s1l2 133 | s1s2: ; short first and second 134 | mul ecx 135 | jc rs2l ; If if doesn't feed in 32 bits convert the result to long 136 | 137 | ; The shorts multiplication is done. copy the val to destination and return 138 | mov [rdi], rax 139 | ret 140 | 141 | rs2l: ; The result in the multiplication doen't feed 142 | ; we have the result in edx:eax we need to convert it to long 143 | shl rdx, 32 144 | mov edx, eax ; pack edx:eax to rdx 145 | 146 | xor rax, rax ; Set the format to long 147 | bts rax, 63 148 | mov [rdi], rax ; move the first digit 149 | 150 | cmp rdx, 0 ; check if redx is negative. 151 | jl rs2ln 152 | 153 | ; edx is positive. 154 | mov [rdi + 8], rdx ; Set the firs digit 155 | 156 | xor rax, rax ; Set the remaining digits to 0 157 | <% for (let i=1; i 158 | mov [rdi + <%= (i+1)*8 %>], rax 159 | <% } %> 160 | ret 161 | 162 | ; edx is negative. 163 | rs2ln: 164 | 165 | add rdx, [q] ; Set the firs digit 166 | mov [rdi + 8], rdx ; 167 | 168 | mov rdx, -1 ; all ones 169 | <% for (let i=1; i 170 | mov rax, rdx ; Add to q 171 | adc rax, [q + <%= i*8 %> ] 172 | mov [rdi + <%= (i+1)*8 %>], rax 173 | <% } %> 174 | ret 175 | 176 | l1: 177 | mov rcx, [rdx] 178 | bt rcx, 63 179 | jc ll 180 | 181 | l1s2: 182 | xor rdx, rdx 183 | mov edx, ecx 184 | bt rax, 62 185 | jc lsM 186 | jmp lsN 187 | 188 | s1l2: 189 | mov rsi, rdx 190 | xor rdx, rdx 191 | mov edx, eax 192 | bt rcx, 62 193 | jc lsM 194 | jmp lsN 195 | 196 | 197 | lsN: 198 | mov byte [rdi + 7], 0xC0 ; set the result to montgomery 199 | add rsi, 8 200 | add rdi, 8 201 | call mulSM 202 | mov rsi, rdi 203 | lea rdx, [R3] 204 | call mulM 205 | ret 206 | 207 | lsM: 208 | mov byte [rdi + 7], 0x80 ; set the result to long normal 209 | add rsi, 8 210 | add rdi, 8 211 | call mulSM 212 | ret 213 | 214 | 215 | ll: 216 | 217 | bt rax, 62 218 | jc lml 219 | bt rcx, 62 220 | jc lnlm 221 | 222 | lnln: 223 | mov byte [rdi + 7], 0xC0 ; set the result to long montgomery 224 | add rsi, 8 225 | add rdi, 8 226 | add rdx, 8 227 | call mulM 228 | mov rsi, rdi 229 | lea rdx, [R3] 230 | call mulM 231 | ret 232 | 233 | lml: 234 | bt rcx, 62 235 | jc lmlm 236 | 237 | lnlm: 238 | mov byte [rdi + 7], 0x80 ; set the result to long normal 239 | add rsi, 8 240 | add rdi, 8 241 | add rdx, 8 242 | call mulM 243 | ret 244 | 245 | lmlm: 246 | mov byte [rdi + 7], 0xC0 ; set the result to long montgomery 247 | add rsi, 8 248 | add rdi, 8 249 | add rdx, 8 250 | call mulM 251 | ret 252 | -------------------------------------------------------------------------------- /c/old/buildasm/sub.asm.ejs: -------------------------------------------------------------------------------- 1 | <% function subS1S2() { %> 2 | xor rdx, rdx 3 | mov edx, eax 4 | sub edx, ecx 5 | jo sub_manageOverflow ; rsi already is the 64bits result 6 | 7 | mov [rdi], rdx ; not necessary to adjust so just save and return 8 | ret 9 | 10 | sub_manageOverflow: ; Do the operation in 64 bits 11 | push rsi 12 | movsx rsi, eax 13 | movsx rdx, ecx 14 | sub rsi, rdx 15 | call rawCopyS2L 16 | pop rsi 17 | ret 18 | <% } %> 19 | 20 | <% function subL1S2(t) { %> 21 | add rsi, 8 22 | movsx rdx, ecx 23 | add rdi, 8 24 | cmp rdx, 0 25 | <% const rawSubLabel = global.tmpLabel() %> 26 | jns <%= rawSubLabel %> 27 | neg rdx 28 | call rawAddLS 29 | sub rdi, 8 30 | sub rsi, 8 31 | ret 32 | <%= rawSubLabel %>: 33 | call rawSubLS 34 | sub rdi, 8 35 | sub rsi, 8 36 | ret 37 | <% } %> 38 | 39 | 40 | <% function subS1L2(t) { %> 41 | cmp eax, 0 42 | <% const s1NegLabel = global.tmpLabel() %> 43 | js <%= s1NegLabel %> 44 | 45 | ; First Operand is positive 46 | push rsi 47 | add rdi, 8 48 | movsx rsi, eax 49 | add rdx, 8 50 | call rawSubSL 51 | sub rdi, 8 52 | pop rsi 53 | ret 54 | 55 | <%= s1NegLabel %>: ; First operand is negative 56 | push rsi 57 | lea rsi, [rdx + 8] 58 | movsx rdx, eax 59 | add rdi, 8 60 | neg rdx 61 | call rawNegLS 62 | sub rdi, 8 63 | pop rsi 64 | ret 65 | <% } %> 66 | 67 | 68 | <% function subL1L2(t) { %> 69 | add rdi, 8 70 | add rsi, 8 71 | add rdx, 8 72 | call rawSubLL 73 | sub rdi, 8 74 | sub rsi, 8 75 | ret 76 | <% } %> 77 | 78 | ;;;;;;;;;;;;;;;;;;;;;; 79 | ; sub 80 | ;;;;;;;;;;;;;;;;;;;;;; 81 | ; Substracts two elements of any kind 82 | ; Params: 83 | ; rsi <= Pointer to element 1 84 | ; rdx <= Pointer to element 2 85 | ; rdi <= Pointer to result 86 | ; Modified Registers: 87 | ; r8, r9, 10, r11, rax, rcx 88 | ;;;;;;;;;;;;;;;;;;;;;; 89 | <%=name%>_sub: 90 | mov rax, [rsi] 91 | mov rcx, [rdx] 92 | bt rax, 63 ; Check if is long first operand 93 | jc sub_l1 94 | bt rcx, 63 ; Check if is long second operand 95 | jc sub_s1l2 96 | 97 | sub_s1s2: ; Both operands are short 98 | <%= subS1S2() %> 99 | sub_l1: 100 | bt rcx, 63 ; Check if is short second operand 101 | jc sub_l1l2 102 | 103 | ;;;;;;;; 104 | sub_l1s2: 105 | bt rax, 62 ; check if montgomery first 106 | jc sub_l1ms2 107 | sub_l1ns2: 108 | <%= global.setTypeDest("0x80"); %> 109 | <%= subL1S2(); %> 110 | 111 | sub_l1ms2: 112 | bt rcx, 62 ; check if montgomery second 113 | jc sub_l1ms2m 114 | sub_l1ms2n: 115 | <%= global.setTypeDest("0xC0"); %> 116 | <%= global.toMont_b() %> 117 | <%= subL1L2() %> 118 | 119 | sub_l1ms2m: 120 | <%= global.setTypeDest("0xC0"); %> 121 | <%= subL1L2() %> 122 | 123 | 124 | ;;;;;;;; 125 | sub_s1l2: 126 | bt rcx, 62 ; check if montgomery first 127 | jc sub_s1l2m 128 | sub_s1l2n: 129 | <%= global.setTypeDest("0x80"); %> 130 | <%= subS1L2(); %> 131 | 132 | sub_s1l2m: 133 | bt rax, 62 ; check if montgomery second 134 | jc sub_s1ml2m 135 | sub_s1nl2m: 136 | <%= global.setTypeDest("0xC0"); %> 137 | <%= global.toMont_a() %> 138 | <%= subL1L2() %> 139 | 140 | sub_s1ml2m: 141 | <%= global.setTypeDest("0xC0"); %> 142 | <%= subL1L2() %> 143 | 144 | ;;;; 145 | sub_l1l2: 146 | bt rax, 62 ; check if montgomery first 147 | jc sub_l1ml2 148 | sub_l1nl2: 149 | bt rcx, 62 ; check if montgomery second 150 | jc sub_l1nl2m 151 | sub_l1nl2n: 152 | <%= global.setTypeDest("0x80"); %> 153 | <%= subL1L2() %> 154 | 155 | sub_l1nl2m: 156 | <%= global.setTypeDest("0xC0"); %> 157 | <%= global.toMont_a(); %> 158 | <%= subL1L2() %> 159 | 160 | sub_l1ml2: 161 | bt rcx, 62 ; check if montgomery seconf 162 | jc sub_l1ml2m 163 | sub_l1ml2n: 164 | <%= global.setTypeDest("0xC0"); %> 165 | <%= global.toMont_b(); %> 166 | <%= subL1L2() %> 167 | 168 | sub_l1ml2m: 169 | <%= global.setTypeDest("0xC0"); %> 170 | <%= subL1L2() %> 171 | 172 | 173 | ;;;;;;;;;;;;;;;;;;;;;; 174 | ; rawSubLS 175 | ;;;;;;;;;;;;;;;;;;;;;; 176 | ; Substracts a short element from the long element 177 | ; Params: 178 | ; rdi <= Pointer to the long data of result 179 | ; rsi <= Pointer to the long data of element 1 where will be substracted 180 | ; rdx <= Value to be substracted 181 | ; [rdi] = [rsi] - rdx 182 | ; Modified Registers: 183 | ; rax 184 | ;;;;;;;;;;;;;;;;;;;;;; 185 | rawSubLS: 186 | ; Substract first digit 187 | 188 | mov rax, [rsi] 189 | sub rax, rdx 190 | mov [rdi] ,rax 191 | mov rdx, 0 192 | <% for (let i=1; i 193 | mov rax, [rsi + <%=i*8%>] 194 | sbb rax, rdx 195 | mov [rdi + <%=i*8%>], rax 196 | <% } %> 197 | jnc rawSubLS_done ; if overflow, add q 198 | 199 | ; Add q 200 | rawSubLS_aq: 201 | <% for (let i=0; i 202 | mov rax, [q + <%=i*8%>] 203 | <%= i==0 ? "add" : "adc" %> [rdi + <%=i*8%>], rax 204 | <% } %> 205 | rawSubLS_done: 206 | ret 207 | 208 | 209 | ;;;;;;;;;;;;;;;;;;;;;; 210 | ; rawSubSL 211 | ;;;;;;;;;;;;;;;;;;;;;; 212 | ; Substracts a long element from a short element 213 | ; Params: 214 | ; rdi <= Pointer to the long data of result 215 | ; rsi <= Value from where will bo substracted 216 | ; rdx <= Pointer to long of the value to be substracted 217 | ; 218 | ; [rdi] = rsi - [rdx] 219 | ; Modified Registers: 220 | ; rax 221 | ;;;;;;;;;;;;;;;;;;;;;; 222 | rawSubSL: 223 | ; Substract first digit 224 | sub rsi, [rdx] 225 | mov [rdi] ,rsi 226 | 227 | <% for (let i=1; i 228 | mov rax, 0 229 | sbb rax, [rdx + <%=i*8%>] 230 | mov [rdi + <%=i*8%>], rax 231 | <% } %> 232 | jnc rawSubSL_done ; if overflow, add q 233 | 234 | ; Add q 235 | rawSubSL_aq: 236 | <% for (let i=0; i 237 | mov rax, [q + <%=i*8%>] 238 | <%= i==0 ? "add" : "adc" %> [rdi + <%=i*8%>], rax 239 | <% } %> 240 | rawSubSL_done: 241 | ret 242 | 243 | ;;;;;;;;;;;;;;;;;;;;;; 244 | ; rawSubLL 245 | ;;;;;;;;;;;;;;;;;;;;;; 246 | ; Substracts a long element from a short element 247 | ; Params: 248 | ; rdi <= Pointer to the long data of result 249 | ; rsi <= Pointer to long from where substracted 250 | ; rdx <= Pointer to long of the value to be substracted 251 | ; 252 | ; [rdi] = [rsi] - [rdx] 253 | ; Modified Registers: 254 | ; rax 255 | ;;;;;;;;;;;;;;;;;;;;;; 256 | rawSubLL: 257 | ; Substract first digit 258 | <% for (let i=0; i 259 | mov rax, [rsi + <%=i*8%>] 260 | <%= i==0 ? "sub" : "sbb" %> rax, [rdx + <%=i*8%>] 261 | mov [rdi + <%=i*8%>], rax 262 | <% } %> 263 | jnc rawSubLL_done ; if overflow, add q 264 | 265 | ; Add q 266 | rawSubLL_aq: 267 | <% for (let i=0; i 268 | mov rax, [q + <%=i*8%>] 269 | <%= i==0 ? "add" : "adc" %> [rdi + <%=i*8%>], rax 270 | <% } %> 271 | rawSubLL_done: 272 | ret 273 | 274 | ;;;;;;;;;;;;;;;;;;;;;; 275 | ; rawNegLS 276 | ;;;;;;;;;;;;;;;;;;;;;; 277 | ; Substracts a long element and a short element form 0 278 | ; Params: 279 | ; rdi <= Pointer to the long data of result 280 | ; rsi <= Pointer to long from where substracted 281 | ; rdx <= short value to be substracted too 282 | ; 283 | ; [rdi] = -[rsi] - rdx 284 | ; Modified Registers: 285 | ; rax 286 | ;;;;;;;;;;;;;;;;;;;;;; 287 | rawNegLS: 288 | mov rax, [q] 289 | sub rax, rdx 290 | mov [rdi], rax 291 | <% for (let i=1; i 292 | mov rax, [q + <%=i*8%> ] 293 | sbb rax, 0 294 | mov [rdi + <%=i*8%>], rax 295 | <% } %> 296 | setc dl 297 | 298 | <% for (let i=0; i 299 | mov rax, [rdi + <%=i*8%> ] 300 | <%= i==0 ? "sub" : "sbb" %> rax, [rsi + <%=i*8%>] 301 | mov [rdi + <%=i*8%>], rax 302 | <% } %> 303 | 304 | setc dh 305 | or dl, dh 306 | jz rawNegSL_done 307 | 308 | ; it is a negative value, so add q 309 | <% for (let i=0; i 310 | mov rax, [q + <%=i*8%>] 311 | <%= i==0 ? "add" : "adc" %> [rdi + <%=i*8%>], rax 312 | <% } %> 313 | 314 | rawNegSL_done: 315 | ret 316 | 317 | 318 | -------------------------------------------------------------------------------- /c/old/buildasm/tester: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iden3/circom_runtime/3ad281088f78a4be5e6d7adda073823e60ca08fa/c/old/buildasm/tester -------------------------------------------------------------------------------- /c/old/buildasm/tester.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include /* printf, NULL */ 11 | #include 12 | #include 13 | 14 | 15 | #include "fr.h" 16 | 17 | 18 | typedef void (*Func1)(PFrElement, PFrElement); 19 | typedef void (*Func2)(PFrElement, PFrElement, PFrElement); 20 | typedef void *FuncAny; 21 | 22 | typedef struct { 23 | FuncAny fn; 24 | int nOps; 25 | } FunctionSpec; 26 | 27 | std::map functions; 28 | std::vector stack; 29 | 30 | void addFunction(std::string name, FuncAny f, int nOps) { 31 | FunctionSpec fs; 32 | fs.fn = f; 33 | fs.nOps = nOps; 34 | functions[name] = fs; 35 | } 36 | 37 | void fillMap() { 38 | addFunction("add", (FuncAny)Fr_add, 2); 39 | addFunction("sub", (FuncAny)Fr_sub, 2); 40 | addFunction("neg", (FuncAny)Fr_neg, 1); 41 | addFunction("mul", (FuncAny)Fr_mul, 2); 42 | addFunction("square", (FuncAny)Fr_square, 1); 43 | addFunction("idiv", (FuncAny)Fr_idiv, 2); 44 | addFunction("inv", (FuncAny)Fr_inv, 1); 45 | addFunction("div", (FuncAny)Fr_div, 2); 46 | addFunction("band", (FuncAny)Fr_band, 2); 47 | addFunction("bor", (FuncAny)Fr_bor, 2); 48 | addFunction("bxor", (FuncAny)Fr_bxor, 2); 49 | addFunction("bnot", (FuncAny)Fr_bnot, 1); 50 | addFunction("eq", (FuncAny)Fr_eq, 2); 51 | addFunction("neq", (FuncAny)Fr_neq, 2); 52 | addFunction("lt", (FuncAny)Fr_lt, 2); 53 | addFunction("gt", (FuncAny)Fr_gt, 2); 54 | addFunction("leq", (FuncAny)Fr_leq, 2); 55 | addFunction("geq", (FuncAny)Fr_geq, 2); 56 | addFunction("land", (FuncAny)Fr_land, 2); 57 | addFunction("lor", (FuncAny)Fr_lor, 2); 58 | addFunction("lnot", (FuncAny)Fr_lnot, 1); 59 | addFunction("shl", (FuncAny)Fr_shl, 2); 60 | addFunction("shr", (FuncAny)Fr_shr, 2); 61 | } 62 | 63 | u_int64_t readInt(std::string &s) { 64 | if (s.rfind("0x", 0) == 0) { 65 | return std::stoull(s.substr(2), 0, 16); 66 | } else { 67 | return std::stoull(s, 0, 10); 68 | } 69 | } 70 | 71 | void pushNumber(std::vector &v) { 72 | u_int64_t a; 73 | if ((v.size()<1) || (v.size() > (Fr_N64+1))) { 74 | printf("Invalid Size: %d - %d \n", v.size(), Fr_N64); 75 | throw std::runtime_error("Invalid number of parameters for number"); 76 | } 77 | FrElement e; 78 | a = readInt(v[0]); 79 | *(u_int64_t *)(&e) = a; 80 | for (int i=0; i tokens; 120 | 121 | std::copy(begin, end, std::back_inserter(tokens)); 122 | 123 | // Remove initial empty tokens 124 | while ((tokens.size() > 0)&&(tokens[0] == "")) { 125 | tokens.erase(tokens.begin()); 126 | } 127 | 128 | // Empty lines are valid but are not processed 129 | if (tokens.size() == 0) return; 130 | 131 | auto search = functions.find(tokens[0]); 132 | if (search == functions.end()) { 133 | pushNumber(tokens); 134 | } else { 135 | if (tokens.size() != 1) { 136 | throw std::runtime_error("Functions does not accept parameters"); 137 | } 138 | callFunction(search->second); 139 | } 140 | } 141 | 142 | int main(void) 143 | { 144 | Fr_init(); 145 | fillMap(); 146 | std::string line; 147 | int i=0; 148 | while (std::getline(std::cin, line)) { 149 | processLine(line); 150 | // if (i%1000 == 0) printf("%d\n", i); 151 | // printf("%d\n", i); 152 | i++; 153 | } 154 | // Print the elements in the stack 155 | // 156 | for (int i=0; i 171 | #include 172 | #include "fr.h" 173 | 174 | typedef void (*Func2)(PFrElement, PFrElement, PFrElement); 175 | 176 | typedef struct { 177 | const char *fnName; 178 | Func2 fn; 179 | } FN; 180 | 181 | 182 | #define NFN 2 183 | FN fns[NFN] = { 184 | {"add", Fr_add}, 185 | {"mul", Fr_mul}, 186 | }; 187 | 188 | int main(int argc, char **argv) { 189 | 190 | if (argc <= 1) { 191 | fprintf( stderr, "invalid number of parameters"); 192 | return 1; 193 | } 194 | 195 | for (int i=0; i< NFN;i++) { 196 | if (strcmp(argv[1], fns[i].fnName) == 0) { 197 | if (argc != 4) { 198 | fprintf( stderr, "invalid number of parameters"); 199 | return 1; 200 | } 201 | FrElement a; 202 | FrElement b; 203 | 204 | Fr_str2element(&a, argv[2]); 205 | Fr_str2element(&b, argv[3]); 206 | FrElement c; 207 | fns[i].fn(&c, &a, &b); 208 | 209 | char *s; 210 | s = Fr_element2str(&c); 211 | printf("%s", s); 212 | free(s); 213 | return 0; 214 | } 215 | } 216 | fprintf( stderr, "invalid operation %s", argv[1]); 217 | return 1; 218 | } 219 | 220 | */ 221 | -------------------------------------------------------------------------------- /c/old/buildasm/testet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iden3/circom_runtime/3ad281088f78a4be5e6d7adda073823e60ca08fa/c/old/buildasm/testet -------------------------------------------------------------------------------- /c/old/buildasm/utils.asm.ejs: -------------------------------------------------------------------------------- 1 | <% global.setTypeDest = function (t) { 2 | return ( 3 | ` mov r11b, ${t} 4 | shl r11d, 24 5 | mov [rdi+4], r11d`); 6 | } %> 7 | 8 | 9 | <% global.toMont_a = function () { 10 | return ( 11 | ` push rdi 12 | mov rdi, rsi 13 | mov rsi, rdx 14 | call ${name}_toMontgomery 15 | mov rdx, rsi 16 | mov rsi, rdi 17 | pop rdi`); 18 | } %> 19 | 20 | <% global.toMont_b = function() { 21 | return ( 22 | ` push rdi 23 | mov rdi, rdx 24 | call ${name}_toMontgomery 25 | mov rdx, rdi 26 | pop rdi`); 27 | } %> 28 | 29 | <% global.fromMont_a = function () { 30 | return ( 31 | ` push rdi 32 | mov rdi, rsi 33 | mov rsi, rdx 34 | call ${name}_toNormal 35 | mov rdx, rsi 36 | mov rsi, rdi 37 | pop rdi`); 38 | } %> 39 | 40 | <% global.fromMont_b = function() { 41 | return ( 42 | ` push rdi 43 | mov rdi, rdx 44 | call ${name}_toNormal 45 | mov rdx, rdi 46 | pop rdi`); 47 | } %> 48 | 49 | <% global.toLong_a = function () { 50 | return ( 51 | ` push rdi 52 | push rdx 53 | mov rdi, rsi 54 | movsx rsi, r8d 55 | call rawCopyS2L 56 | mov rsi, rdi 57 | pop rdx 58 | pop rdi`); 59 | } %> 60 | 61 | <% global.toLong_b = function() { 62 | return ( 63 | ` push rdi 64 | push rsi 65 | mov rdi, rdx 66 | movsx rsi, r9d 67 | call rawCopyS2L 68 | mov rdx, rdi 69 | pop rsi 70 | pop rdi`); 71 | } %> 72 | 73 | -------------------------------------------------------------------------------- /c/old/mainjson.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | using json = nlohmann::json; 5 | 6 | 7 | #include "utils.h" 8 | #include "circom.h" 9 | #include "calcwit.h" 10 | 11 | auto j = R"( 12 | { 13 | "in": "314" 14 | } 15 | )"_json; 16 | 17 | typedef void (*ItFunc)(int idx, json val); 18 | 19 | void iterateArr(int o, Circom_Sizes sizes, json jarr, ItFunc f) { 20 | if (!jarr.is_array()) { 21 | assert((sizes[0] == 1)&&(sizes[1] == 0)); 22 | f(o, jarr); 23 | } else { 24 | int n = sizes[0] / sizes[1]; 25 | for (int i=0; i " << it.value() << '\n'; 42 | u64 h = fnv1a(it.key()); 43 | int o = ctx->getSignalOffset(0, h); 44 | Circom_Sizes sizes = ctx->getSignalSizes(0, h); 45 | iterateArr(o, sizes, it.value(), itFunc); 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /c/old/zqfield.cpp: -------------------------------------------------------------------------------- 1 | #include "zqfield.h" 2 | 3 | ZqField::ZqField(PBigInt ap) { 4 | mpz_init_set(p, *ap); 5 | mpz_init_set_ui(zero, 0); 6 | mpz_init_set_ui(one, 1); 7 | nBits = mpz_sizeinbase (p, 2); 8 | mpz_init(mask); 9 | mpz_mul_2exp(mask, one, nBits-1); 10 | mpz_sub(mask, mask, one); 11 | } 12 | 13 | ZqField::~ZqField() { 14 | mpz_clear(p); 15 | mpz_clear(zero); 16 | mpz_clear(one); 17 | } 18 | 19 | void ZqField::add(PBigInt r, PBigInt a, PBigInt b) { 20 | mpz_add(*r,*a,*b); 21 | if (mpz_cmp(*r, p) >= 0) { 22 | mpz_sub(*r, *r, p); 23 | } 24 | } 25 | 26 | void ZqField::sub(PBigInt r, PBigInt a, PBigInt b) { 27 | if (mpz_cmp(*a, *b) >= 0) { 28 | mpz_sub(*r, *a, *b); 29 | } else { 30 | mpz_sub(*r, *b, *a); 31 | mpz_sub(*r, p, *r); 32 | } 33 | } 34 | 35 | void ZqField::neg(PBigInt r, PBigInt a) { 36 | if (mpz_sgn(*a) > 0) { 37 | mpz_sub(*r, p, *a); 38 | } else { 39 | mpz_set(*r, *a); 40 | } 41 | } 42 | 43 | void ZqField::mul(PBigInt r, PBigInt a, PBigInt b) { 44 | mpz_t tmp; 45 | mpz_init(tmp); 46 | mpz_mul(tmp,*a,*b); 47 | mpz_fdiv_r(*r, tmp, p); 48 | mpz_clear(tmp); 49 | } 50 | 51 | void ZqField::div(PBigInt r, PBigInt a, PBigInt b) { 52 | mpz_t tmp; 53 | mpz_init(tmp); 54 | mpz_invert(tmp, *b, p); 55 | mpz_mul(tmp,*a,tmp); 56 | mpz_fdiv_r(*r, tmp, p); 57 | mpz_clear(tmp); 58 | } 59 | 60 | void ZqField::idiv(PBigInt r, PBigInt a, PBigInt b) { 61 | mpz_fdiv_q(*r, *a, *b); 62 | } 63 | 64 | void ZqField::mod(PBigInt r, PBigInt a, PBigInt b) { 65 | mpz_fdiv_r(*r, *a, *b); 66 | } 67 | 68 | void ZqField::pow(PBigInt r, PBigInt a, PBigInt b) { 69 | mpz_powm(*r, *a, *b, p); 70 | } 71 | 72 | void ZqField::lt(PBigInt r, PBigInt a, PBigInt b) { 73 | int c = mpz_cmp(*a, *b); 74 | if (c<0) { 75 | mpz_set(*r, one); 76 | } else { 77 | mpz_set(*r, zero); 78 | } 79 | } 80 | 81 | void ZqField::eq(PBigInt r, PBigInt a, PBigInt b) { 82 | int c = mpz_cmp(*a, *b); 83 | if (c==0) { 84 | mpz_set(*r, one); 85 | } else { 86 | mpz_set(*r, zero); 87 | } 88 | } 89 | 90 | void ZqField::gt(PBigInt r, PBigInt a, PBigInt b) { 91 | int c = mpz_cmp(*a, *b); 92 | if (c>0) { 93 | mpz_set(*r, one); 94 | } else { 95 | mpz_set(*r, zero); 96 | } 97 | } 98 | 99 | void ZqField::leq(PBigInt r, PBigInt a, PBigInt b) { 100 | int c = mpz_cmp(*a, *b); 101 | if (c<=0) { 102 | mpz_set(*r, one); 103 | } else { 104 | mpz_set(*r, zero); 105 | } 106 | } 107 | 108 | void ZqField::geq(PBigInt r, PBigInt a, PBigInt b) { 109 | int c = mpz_cmp(*a, *b); 110 | if (c>=0) { 111 | mpz_set(*r, one); 112 | } else { 113 | mpz_set(*r, zero); 114 | } 115 | } 116 | 117 | void ZqField::neq(PBigInt r, PBigInt a, PBigInt b) { 118 | int c = mpz_cmp(*a, *b); 119 | if (c!=0) { 120 | mpz_set(*r, one); 121 | } else { 122 | mpz_set(*r, zero); 123 | } 124 | } 125 | 126 | void ZqField::land(PBigInt r, PBigInt a, PBigInt b) { 127 | if (mpz_sgn(*a) && mpz_sgn(*b)) { 128 | mpz_set(*r, one); 129 | } else { 130 | mpz_set(*r, zero); 131 | } 132 | } 133 | 134 | void ZqField::lor(PBigInt r, PBigInt a, PBigInt b) { 135 | if (mpz_sgn(*a) || mpz_sgn(*b)) { 136 | mpz_set(*r, one); 137 | } else { 138 | mpz_set(*r, zero); 139 | } 140 | } 141 | 142 | void ZqField::lnot(PBigInt r, PBigInt a) { 143 | if (mpz_sgn(*a)) { 144 | mpz_set(*r, zero); 145 | } else { 146 | mpz_set(*r, one); 147 | } 148 | } 149 | 150 | int ZqField::isTrue(PBigInt a) { 151 | return mpz_sgn(*a); 152 | } 153 | 154 | void ZqField::copyn(PBigInt a, PBigInt b, int n) { 155 | for (int i=0;i= 0) { 180 | mpz_set(*r, zero); 181 | } else { 182 | mpz_mul_2exp(*r, *a, mpz_get_ui(*b)); 183 | mpz_and(*r, *r, mask); 184 | } 185 | } 186 | 187 | void ZqField::shr(PBigInt r, PBigInt a, PBigInt b) { 188 | if (mpz_cmp_ui(*b, nBits) >= 0) { 189 | mpz_set(*r, zero); 190 | } else { 191 | mpz_tdiv_q_2exp(*r, *a, mpz_get_ui(*b)); 192 | mpz_and(*r, *r, mask); 193 | } 194 | } 195 | 196 | int ZqField::toInt(PBigInt a) { 197 | return mpz_get_si (*a); 198 | } 199 | 200 | -------------------------------------------------------------------------------- /c/old/zqfield.h: -------------------------------------------------------------------------------- 1 | #ifndef ZQFIELD_H 2 | #define ZQFIELD_H 3 | 4 | #include "circom.h" 5 | 6 | class ZqField { 7 | public: 8 | BigInt p; 9 | BigInt one; 10 | BigInt zero; 11 | size_t nBits; 12 | BigInt mask; 13 | ZqField(PBigInt ap); 14 | ~ZqField(); 15 | 16 | void copyn(PBigInt a, PBigInt b, int n); 17 | 18 | void add(PBigInt r,PBigInt a, PBigInt b); 19 | void sub(PBigInt r,PBigInt a, PBigInt b); 20 | void neg(PBigInt r,PBigInt a); 21 | void mul(PBigInt r,PBigInt a, PBigInt b); 22 | void div(PBigInt r,PBigInt a, PBigInt b); 23 | void idiv(PBigInt r,PBigInt a, PBigInt b); 24 | void mod(PBigInt r,PBigInt a, PBigInt b); 25 | void pow(PBigInt r,PBigInt a, PBigInt b); 26 | 27 | void lt(PBigInt r, PBigInt a, PBigInt b); 28 | void eq(PBigInt r, PBigInt a, PBigInt b); 29 | void gt(PBigInt r, PBigInt a, PBigInt b); 30 | void leq(PBigInt r, PBigInt a, PBigInt b); 31 | void geq(PBigInt r, PBigInt a, PBigInt b); 32 | void neq(PBigInt r, PBigInt a, PBigInt b); 33 | 34 | void land(PBigInt r, PBigInt a, PBigInt b); 35 | void lor(PBigInt r, PBigInt a, PBigInt b); 36 | void lnot(PBigInt r, PBigInt a); 37 | 38 | void band(PBigInt r, PBigInt a, PBigInt b); 39 | void bor(PBigInt r, PBigInt a, PBigInt b); 40 | void bxor(PBigInt r, PBigInt a, PBigInt b); 41 | void bnot(PBigInt r, PBigInt a); 42 | void shl(PBigInt r, PBigInt a, PBigInt b); 43 | void shr(PBigInt r, PBigInt a, PBigInt b); 44 | 45 | int isTrue(PBigInt a); 46 | int toInt(PBigInt a); 47 | }; 48 | 49 | #endif // ZQFIELD_H 50 | -------------------------------------------------------------------------------- /c/utils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "utils.hpp" 8 | 9 | std::string int_to_hex( u64 i ) 10 | { 11 | std::stringstream stream; 12 | stream << "0x" 13 | << std::setfill ('0') << std::setw(16) 14 | << std::hex << i; 15 | return stream.str(); 16 | } 17 | 18 | u64 fnv1a(std::string s) { 19 | u64 hash = 0xCBF29CE484222325LL; 20 | for(char& c : s) { 21 | hash ^= u64(c); 22 | hash *= 0x100000001B3LL; 23 | } 24 | return hash; 25 | } 26 | -------------------------------------------------------------------------------- /c/utils.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __UTILS_H 2 | #define __UTILS_H 3 | 4 | #include "circom.hpp" 5 | 6 | std::string int_to_hex( u64 i ); 7 | u64 fnv1a(std::string s); 8 | 9 | 10 | #endif // __UTILS_H 11 | -------------------------------------------------------------------------------- /calcwit.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | /* 3 | 4 | Copyright 2020 0KIMS association. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | 18 | */ 19 | 20 | import fs from "fs"; 21 | const pkg = JSON.parse(fs.readFileSync("./package.json")); 22 | const version = pkg.version; 23 | 24 | import WitnessCalculatorBuilder from "./js/witness_calculator.js"; 25 | import { utils } from "ffjavascript"; 26 | import yargs from "yargs"; 27 | 28 | 29 | 30 | const argv = yargs 31 | .version(version) 32 | .usage("calcwit -w [wasm file] -i [input file JSON] -o [output ouput file file .json|.bin]") 33 | .alias("o", "output") 34 | .alias("i", "input") 35 | .alias("w", "wasm") 36 | .help("h") 37 | .alias("h", "help") 38 | .epilogue(`Copyright (C) 2018 0kims association 39 | This program comes with ABSOLUTELY NO WARRANTY; 40 | This is free software, and you are welcome to redistribute it 41 | under certain conditions; see the COPYING file in the official 42 | repo directory at https://github.com/iden3/circom `) 43 | .argv; 44 | 45 | const inputFileName = typeof(argv.input) === "string" ? argv.input : "input.json"; 46 | const outputFileName = typeof(argv.output) === "string" ? argv.output : "witness.bin"; 47 | const wasmFileName = typeof(argv.wasm) === "string" ? argv.wasm : "circuit.wasm"; 48 | 49 | 50 | async function run() { 51 | 52 | 53 | const input = utils.unstringifyBigInts(JSON.parse(await fs.promises.readFile(inputFileName, "utf8"))); 54 | const wasm = await fs.promises.readFile(wasmFileName); 55 | 56 | const wc = await WitnessCalculatorBuilder(wasm); 57 | 58 | const outputExtension = outputFileName.split(".").pop(); 59 | 60 | if (outputExtension === "json") { 61 | const w = await wc.calculateWitness(input); 62 | 63 | await fs.promises.writeFile(outputFileName, JSON.stringify(utils.stringifyBigInts(w), null, 1)); 64 | 65 | } else { 66 | const w = await wc.calculateBinWitness(input); 67 | 68 | var wstream = fs.createWriteStream(outputFileName); 69 | 70 | wstream.write(Buffer.from(w)); 71 | wstream.end(); 72 | await new Promise(fulfill => wstream.on("finish", fulfill)); 73 | } 74 | 75 | 76 | } 77 | 78 | 79 | run(); 80 | -------------------------------------------------------------------------------- /js/utils.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Copyright 2020 0KIMS association. 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | 17 | */ 18 | 19 | export function flatArray(a) { 20 | let res = []; 21 | fillArray(res, a); 22 | return res; 23 | 24 | function fillArray(res, a) { 25 | if (Array.isArray(a)) { 26 | for (let i = 0; i < a.length; i++) { 27 | fillArray(res, a[i]); 28 | } 29 | } else { 30 | res.push(a); 31 | } 32 | } 33 | } 34 | 35 | // Ref https://github.com/iden3/circom/commit/ec6388cf6eb62463539cb4c40cc3ceae9826de19 36 | export function normalize(n, prime) { 37 | let res = BigInt(n) % prime; 38 | if (res < 0) res += prime; 39 | return res; 40 | } 41 | 42 | export function fnvHash(str) { 43 | const uint64_max = BigInt(2) ** BigInt(64); 44 | let hash = BigInt("0xCBF29CE484222325"); 45 | for (let i = 0; i < str.length; i++) { 46 | hash ^= BigInt(str[i].charCodeAt(0)); 47 | hash *= BigInt(0x100000001B3); 48 | hash %= uint64_max; 49 | } 50 | let shash = hash.toString(16); 51 | let n = 16 - shash.length; 52 | shash = "0".repeat(n).concat(shash); 53 | return shash; 54 | } 55 | 56 | // Note that this pads zeros 57 | export function toArray32(s, size) { 58 | const res = []; //new Uint32Array(size); //has no unshift 59 | let rem = BigInt(s); 60 | const radix = BigInt(0x100000000); 61 | while (rem) { 62 | res.unshift(Number(rem % radix)); 63 | rem = rem / radix; 64 | } 65 | if (size) { 66 | let i = size - res.length; 67 | while (i > 0) { 68 | res.unshift(0); 69 | i--; 70 | } 71 | } 72 | return res; 73 | } 74 | -------------------------------------------------------------------------------- /js/witness_calculator.js: -------------------------------------------------------------------------------- 1 | /* globals WebAssembly */ 2 | /* 3 | 4 | Copyright 2020 0KIMS association. 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | 18 | */ 19 | 20 | import {flatArray, fnvHash, toArray32, normalize} from "./utils.js"; 21 | import {Scalar, F1Field} from "ffjavascript"; 22 | 23 | export default async function builder(code, options) { 24 | let instance; 25 | let wc; 26 | let memory; 27 | options = options || {}; 28 | 29 | // Only circom 2 implements version lookup through exports in the WASM 30 | // We default to `1` and update if we see the `getVersion` export (major version) 31 | // These are updated after the instance is instantiated, assuming the functions are available 32 | let majorVersion = 1; 33 | // After Circom 2.0.7, Blaine added exported functions for getting minor and patch versions 34 | let minorVersion = 0; 35 | // If we can't look up the patch version, assume the lowest 36 | let patchVersion = 0; 37 | 38 | let codeIsWebAssemblyInstance = false; 39 | 40 | // If code is already prepared WebAssembly.Instance, we use it directly 41 | if (code instanceof WebAssembly.Instance) { 42 | instance = code; 43 | codeIsWebAssemblyInstance = true; 44 | } else { 45 | let memorySize = 32767; 46 | 47 | if (options.memorySize) { 48 | // make sure we have int 49 | memorySize = parseInt(options.memorySize); 50 | if (memorySize < 0) { 51 | throw new Error("Invalid memory size"); 52 | } 53 | } 54 | 55 | let memoryAllocated = false; 56 | while (!memoryAllocated) { 57 | try { 58 | memory = new WebAssembly.Memory({initial: memorySize}); 59 | memoryAllocated = true; 60 | } catch (err) { 61 | if (memorySize <= 1) { 62 | throw err; 63 | } 64 | console.warn("Could not allocate " + memorySize * 1024 * 64 + " bytes. This may cause severe instability. Trying with " + memorySize * 1024 * 64 / 2 + " bytes"); 65 | memorySize = Math.floor(memorySize / 2); 66 | } 67 | } 68 | 69 | const wasmModule = await WebAssembly.compile(code); 70 | 71 | let errStr = ""; 72 | let msgStr = ""; 73 | 74 | instance = await WebAssembly.instantiate(wasmModule, { 75 | env: { 76 | "memory": memory 77 | }, 78 | runtime: { 79 | printDebug : function(value) { 80 | console.log("printDebug:", value); 81 | }, 82 | exceptionHandler: function (code) { 83 | let err; 84 | if (code === 1) { 85 | err = "Signal not found. "; 86 | } else if (code === 2) { 87 | err = "Too many signals set. "; 88 | } else if (code === 3) { 89 | err = "Signal already set. "; 90 | } else if (code === 4) { 91 | err = "Assert Failed. "; 92 | } else if (code === 5) { 93 | err = "Not enough memory. "; 94 | } else if (code === 6) { 95 | err = "Input signal array access exceeds the size. "; 96 | } else { 97 | err = "Unknown error. "; 98 | } 99 | console.error("ERROR: ", code, errStr); 100 | throw new Error(err + errStr); 101 | }, 102 | // A new way of logging messages was added in Circom 2.0.7 that requires 2 new imports 103 | // `printErrorMessage` and `writeBufferMessage`. 104 | printErrorMessage: function () { 105 | errStr += getMessage() + "\n"; 106 | }, 107 | writeBufferMessage: function () { 108 | const msg = getMessage(); 109 | // Any calls to `log()` will always end with a `\n`, so that's when we print and reset 110 | if (msg === "\n") { 111 | console.log(msgStr); 112 | msgStr = ""; 113 | } else { 114 | // If we've buffered other content, put a space in between the items 115 | if (msgStr !== "") { 116 | msgStr += " "; 117 | } 118 | // Then append the message to the message we are creating 119 | msgStr += msg; 120 | } 121 | }, 122 | showSharedRWMemory: function () { 123 | const shared_rw_memory_size = instance.exports.getFieldNumLen32(); 124 | const arr = new Uint32Array(shared_rw_memory_size); 125 | for (let j = 0; j < shared_rw_memory_size; j++) { 126 | arr[shared_rw_memory_size - 1 - j] = instance.exports.readSharedRWMemory(j); 127 | } 128 | 129 | // In circom 2.0.7, they changed the log() function to allow strings and changed the 130 | // output API. This smoothes over the breaking change. 131 | if (majorVersion >= 2 && (minorVersion >= 1 || patchVersion >= 7)) { 132 | // If we've buffered other content, put a space in between the items 133 | if (msgStr !== "") { 134 | msgStr += " "; 135 | } 136 | // Then append the value to the message we are creating 137 | const msg = (Scalar.fromArray(arr, 0x100000000).toString()); 138 | msgStr += msg; 139 | } else { 140 | console.log(Scalar.fromArray(arr, 0x100000000)); 141 | } 142 | }, 143 | error: function (code, pstr, a, b, c, d) { 144 | let errStr; 145 | if (code === 7) { 146 | errStr = p2str(pstr) + " " + wc.getFr(b).toString() + " != " + wc.getFr(c).toString() + " " + p2str(d); 147 | } else if (code === 9) { 148 | errStr = p2str(pstr) + " " + wc.getFr(b).toString() + " " + p2str(c); 149 | } else if ((code === 5) && (options.sym)) { 150 | errStr = p2str(pstr) + " " + options.sym.labelIdx2Name[c]; 151 | } else { 152 | errStr = p2str(pstr) + " " + a + " " + b + " " + c + " " + d; 153 | } 154 | console.log("ERROR: ", code, errStr); 155 | throw new Error(errStr); 156 | }, 157 | log: function (a) { 158 | console.log(wc.getFr(a).toString()); 159 | }, 160 | logGetSignal: function (signal, pVal) { 161 | if (options.logGetSignal) { 162 | options.logGetSignal(signal, wc.getFr(pVal)); 163 | } 164 | }, 165 | logSetSignal: function (signal, pVal) { 166 | if (options.logSetSignal) { 167 | options.logSetSignal(signal, wc.getFr(pVal)); 168 | } 169 | }, 170 | logStartComponent: function (cIdx) { 171 | if (options.logStartComponent) { 172 | options.logStartComponent(cIdx); 173 | } 174 | }, 175 | logFinishComponent: function (cIdx) { 176 | if (options.logFinishComponent) { 177 | options.logFinishComponent(cIdx); 178 | } 179 | } 180 | } 181 | }); 182 | } 183 | 184 | if (typeof instance.exports.getVersion == "function") { 185 | majorVersion = instance.exports.getVersion(); 186 | } 187 | if (typeof instance.exports.getMinorVersion == "function") { 188 | minorVersion = instance.exports.getMinorVersion(); 189 | } 190 | if (typeof instance.exports.getPatchVersion == "function") { 191 | patchVersion = instance.exports.getPatchVersion(); 192 | } 193 | 194 | const sanityCheck = 195 | options && 196 | ( 197 | options.sanityCheck || 198 | options.logGetSignal || 199 | options.logSetSignal || 200 | options.logStartComponent || 201 | options.logFinishComponent 202 | ); 203 | 204 | // We explicitly check for major version 2 in case there's a circom v3 in the future 205 | if (majorVersion === 2) { 206 | wc = new WitnessCalculatorCircom2(instance, sanityCheck); 207 | } else if (majorVersion === 1) { 208 | if (codeIsWebAssemblyInstance) { 209 | throw new Error('Loading code from WebAssembly instance is not supported for circom version 1'); 210 | } 211 | wc = new WitnessCalculatorCircom1(memory, instance, sanityCheck); 212 | } else { 213 | throw new Error(`Unsupported circom version: ${majorVersion}`); 214 | } 215 | return wc; 216 | 217 | function getMessage() { 218 | let message = ""; 219 | let c = instance.exports.getMessageChar(); 220 | while (c !== 0) { 221 | message += String.fromCharCode(c); 222 | c = instance.exports.getMessageChar(); 223 | } 224 | return message; 225 | } 226 | 227 | function p2str(p) { 228 | const i8 = new Uint8Array(memory.buffer); 229 | 230 | const bytes = []; 231 | 232 | for (let i = 0; i8[p + i] > 0; i++) bytes.push(i8[p + i]); 233 | 234 | return String.fromCharCode.apply(null, bytes); 235 | } 236 | } 237 | 238 | class WitnessCalculatorCircom1 { 239 | constructor(memory, instance, sanityCheck) { 240 | this.memory = memory; 241 | this.i32 = new Uint32Array(memory.buffer); 242 | this.instance = instance; 243 | 244 | this.n32 = (this.instance.exports.getFrLen() >> 2) - 2; 245 | const pRawPrime = this.instance.exports.getPRawPrime(); 246 | 247 | const arr = new Array(this.n32); 248 | for (let i = 0; i < this.n32; i++) { 249 | arr[this.n32 - 1 - i] = this.i32[(pRawPrime >> 2) + i]; 250 | } 251 | 252 | this.prime = Scalar.fromArray(arr, 0x100000000); 253 | 254 | this.Fr = new F1Field(this.prime); 255 | 256 | this.mask32 = Scalar.fromString("FFFFFFFF", 16); 257 | this.NVars = this.instance.exports.getNVars(); 258 | this.n64 = Math.floor((this.Fr.bitLength - 1) / 64) + 1; 259 | this.R = this.Fr.e(Scalar.shiftLeft(1, this.n64 * 64)); 260 | this.RInv = this.Fr.inv(this.R); 261 | this.sanityCheck = sanityCheck; 262 | } 263 | 264 | circom_version() { 265 | return 1; 266 | } 267 | 268 | async _doCalculateWitness(input, sanityCheck) { 269 | this.instance.exports.init((this.sanityCheck || sanityCheck) ? 1 : 0); 270 | const pSigOffset = this.allocInt(); 271 | const pFr = this.allocFr(); 272 | const keys = Object.keys(input); 273 | keys.forEach((k) => { 274 | const h = fnvHash(k); 275 | const hMSB = parseInt(h.slice(0, 8), 16); 276 | const hLSB = parseInt(h.slice(8, 16), 16); 277 | try { 278 | this.instance.exports.getSignalOffset32(pSigOffset, 0, hMSB, hLSB); 279 | } catch (err) { 280 | throw new Error(`Signal ${k} is not an input of the circuit.`); 281 | } 282 | const sigOffset = this.getInt(pSigOffset); 283 | const fArr = flatArray(input[k]); 284 | for (let i = 0; i < fArr.length; i++) { 285 | this.setFr(pFr, fArr[i]); 286 | this.instance.exports.setSignal(0, 0, sigOffset + i, pFr); 287 | } 288 | }); 289 | } 290 | 291 | async calculateWitness(input, sanityCheck) { 292 | const self = this; 293 | 294 | const old0 = self.i32[0]; 295 | const w = []; 296 | 297 | await self._doCalculateWitness(input, sanityCheck); 298 | 299 | for (let i = 0; i < self.NVars; i++) { 300 | const pWitness = self.instance.exports.getPWitness(i); 301 | w.push(self.getFr(pWitness)); 302 | } 303 | 304 | self.i32[0] = old0; 305 | return w; 306 | } 307 | 308 | async calculateBinWitness(input, sanityCheck) { 309 | const self = this; 310 | 311 | const old0 = self.i32[0]; 312 | 313 | await self._doCalculateWitness(input, sanityCheck); 314 | 315 | const pWitnessBuffer = self.instance.exports.getWitnessBuffer(); 316 | 317 | self.i32[0] = old0; 318 | 319 | const buff = self.memory.buffer.slice(pWitnessBuffer, pWitnessBuffer + (self.NVars * self.n64 * 8)); 320 | return new Uint8Array(buff); 321 | } 322 | 323 | allocInt() { 324 | const p = this.i32[0]; 325 | this.i32[0] = p + 8; 326 | return p; 327 | } 328 | 329 | allocFr() { 330 | const p = this.i32[0]; 331 | this.i32[0] = p + this.n32 * 4 + 8; 332 | return p; 333 | } 334 | 335 | getInt(p) { 336 | return this.i32[p >> 2]; 337 | } 338 | 339 | setInt(p, v) { 340 | this.i32[p >> 2] = v; 341 | } 342 | 343 | getFr(p) { 344 | const self = this; 345 | const idx = (p >> 2); 346 | 347 | if (self.i32[idx + 1] & 0x80000000) { 348 | const arr = new Array(self.n32); 349 | for (let i = 0; i < self.n32; i++) { 350 | arr[self.n32 - 1 - i] = self.i32[idx + 2 + i]; 351 | } 352 | const res = self.Fr.e(Scalar.fromArray(arr, 0x100000000)); 353 | if (self.i32[idx + 1] & 0x40000000) { 354 | return fromMontgomery(res); 355 | } else { 356 | return res; 357 | } 358 | 359 | } else { 360 | if (self.i32[idx] & 0x80000000) { 361 | return self.Fr.e(self.i32[idx] - 0x100000000); 362 | } else { 363 | return self.Fr.e(self.i32[idx]); 364 | } 365 | } 366 | 367 | function fromMontgomery(n) { 368 | return self.Fr.mul(self.RInv, n); 369 | } 370 | 371 | } 372 | 373 | 374 | setFr(p, v) { 375 | const self = this; 376 | 377 | v = self.Fr.e(v); 378 | 379 | const minShort = self.Fr.neg(self.Fr.e("80000000", 16)); 380 | const maxShort = self.Fr.e("7FFFFFFF", 16); 381 | 382 | if ((self.Fr.geq(v, minShort)) 383 | && (self.Fr.leq(v, maxShort))) { 384 | let a; 385 | if (self.Fr.geq(v, self.Fr.zero)) { 386 | a = Scalar.toNumber(v); 387 | } else { 388 | a = Scalar.toNumber(self.Fr.sub(v, minShort)); 389 | a = a - 0x80000000; 390 | a = 0x100000000 + a; 391 | } 392 | self.i32[(p >> 2)] = a; 393 | self.i32[(p >> 2) + 1] = 0; 394 | return; 395 | } 396 | 397 | self.i32[(p >> 2)] = 0; 398 | self.i32[(p >> 2) + 1] = 0x80000000; 399 | const arr = Scalar.toArray(v, 0x100000000); 400 | for (let i = 0; i < self.n32; i++) { 401 | const idx = arr.length - 1 - i; 402 | 403 | if (idx >= 0) { 404 | self.i32[(p >> 2) + 2 + i] = arr[idx]; 405 | } else { 406 | self.i32[(p >> 2) + 2 + i] = 0; 407 | } 408 | } 409 | } 410 | } 411 | 412 | class WitnessCalculatorCircom2 { 413 | constructor(instance, sanityCheck) { 414 | this.instance = instance; 415 | 416 | this.version = this.instance.exports.getVersion(); 417 | this.n32 = this.instance.exports.getFieldNumLen32(); 418 | 419 | this.instance.exports.getRawPrime(); 420 | const arr = new Uint32Array(this.n32); 421 | for (let i = 0; i < this.n32; i++) { 422 | arr[this.n32 - 1 - i] = this.instance.exports.readSharedRWMemory(i); 423 | } 424 | this.prime = Scalar.fromArray(arr, 0x100000000); 425 | 426 | this.witnessSize = this.instance.exports.getWitnessSize(); 427 | 428 | this.sanityCheck = sanityCheck; 429 | } 430 | 431 | circom_version() { 432 | return this.instance.exports.getVersion(); 433 | } 434 | 435 | async _doCalculateWitness(input, sanityCheck) { 436 | //input is assumed to be a map from signals to arrays of bigints 437 | this.instance.exports.init((this.sanityCheck || sanityCheck) ? 1 : 0); 438 | const keys = Object.keys(input); 439 | let input_counter = 0; 440 | keys.forEach((k) => { 441 | const h = fnvHash(k); 442 | const hMSB = parseInt(h.slice(0, 8), 16); 443 | const hLSB = parseInt(h.slice(8, 16), 16); 444 | const fArr = flatArray(input[k]); 445 | // Slight deviation from https://github.com/iden3/circom/blob/v2.1.6/code_producers/src/wasm_elements/common/witness_calculator.js 446 | // because I don't know when this exported function was added 447 | if (typeof this.instance.exports.getInputSignalSize === "function") { 448 | let signalSize = this.instance.exports.getInputSignalSize(hMSB, hLSB); 449 | if (signalSize < 0) { 450 | throw new Error(`Signal ${k} not found\n`); 451 | } 452 | if (fArr.length < signalSize) { 453 | throw new Error(`Not enough values for input signal ${k}\n`); 454 | } 455 | if (fArr.length > signalSize) { 456 | throw new Error(`Too many values for input signal ${k}\n`); 457 | } 458 | } 459 | for (let i = 0; i < fArr.length; i++) { 460 | const arrFr = toArray32(normalize(fArr[i], this.prime), this.n32); 461 | for (let j = 0; j < this.n32; j++) { 462 | this.instance.exports.writeSharedRWMemory(j, arrFr[this.n32 - 1 - j]); 463 | } 464 | try { 465 | this.instance.exports.setInputSignal(hMSB, hLSB, i); 466 | input_counter++; 467 | } catch (err) { 468 | // console.log(`After adding signal ${i} of ${k}`) 469 | throw new Error(err); 470 | } 471 | } 472 | 473 | }); 474 | if (input_counter < this.instance.exports.getInputSize()) { 475 | throw new Error(`Not all inputs have been set. Only ${input_counter} out of ${this.instance.exports.getInputSize()}`); 476 | } 477 | } 478 | 479 | async calculateWitness(input, sanityCheck) { 480 | const w = []; 481 | 482 | await this._doCalculateWitness(input, sanityCheck); 483 | 484 | for (let i = 0; i < this.witnessSize; i++) { 485 | this.instance.exports.getWitness(i); 486 | const arr = new Uint32Array(this.n32); 487 | for (let j = 0; j < this.n32; j++) { 488 | arr[this.n32 - 1 - j] = this.instance.exports.readSharedRWMemory(j); 489 | } 490 | w.push(Scalar.fromArray(arr, 0x100000000)); 491 | } 492 | 493 | return w; 494 | } 495 | 496 | async calculateWTNSBin(input, sanityCheck) { 497 | const buff32 = new Uint32Array(this.witnessSize * this.n32 + this.n32 + 11); 498 | const buff = new Uint8Array(buff32.buffer); 499 | await this._doCalculateWitness(input, sanityCheck); 500 | 501 | //"wtns" 502 | buff[0] = "w".charCodeAt(0); 503 | buff[1] = "t".charCodeAt(0); 504 | buff[2] = "n".charCodeAt(0); 505 | buff[3] = "s".charCodeAt(0); 506 | 507 | //version 2 508 | buff32[1] = 2; 509 | 510 | //number of sections: 2 511 | buff32[2] = 2; 512 | 513 | //id section 1 514 | buff32[3] = 1; 515 | 516 | const n8 = this.n32 * 4; 517 | //id section 1 length in 64bytes 518 | const idSection1length = 8 + n8; 519 | const idSection1lengthHex = idSection1length.toString(16); 520 | buff32[4] = parseInt(idSection1lengthHex.slice(0, 8), 16); 521 | buff32[5] = parseInt(idSection1lengthHex.slice(8, 16), 16); 522 | 523 | //this.n32 524 | buff32[6] = n8; 525 | 526 | //prime number 527 | this.instance.exports.getRawPrime(); 528 | 529 | let pos = 7; 530 | for (let j = 0; j < this.n32; j++) { 531 | buff32[pos + j] = this.instance.exports.readSharedRWMemory(j); 532 | } 533 | pos += this.n32; 534 | 535 | // witness size 536 | buff32[pos] = this.witnessSize; 537 | pos++; 538 | 539 | //id section 2 540 | buff32[pos] = 2; 541 | pos++; 542 | 543 | // section 2 length 544 | const idSection2length = n8 * this.witnessSize; 545 | const idSection2lengthHex = idSection2length.toString(16); 546 | buff32[pos] = parseInt(idSection2lengthHex.slice(0, 8), 16); 547 | buff32[pos + 1] = parseInt(idSection2lengthHex.slice(8, 16), 16); 548 | 549 | pos += 2; 550 | for (let i = 0; i < this.witnessSize; i++) { 551 | this.instance.exports.getWitness(i); 552 | for (let j = 0; j < this.n32; j++) { 553 | buff32[pos + j] = this.instance.exports.readSharedRWMemory(j); 554 | } 555 | pos += this.n32; 556 | } 557 | 558 | return buff; 559 | } 560 | 561 | } 562 | -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | export { default as WitnessCalculatorBuilder } from "./js/witness_calculator.js"; 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "circom_runtime", 3 | "version": "0.1.28", 4 | "description": "Circom runtime", 5 | "type": "module", 6 | "exports": { 7 | "import": "./main.js", 8 | "require": "./build/main.cjs" 9 | }, 10 | "main": "./build/main.cjs", 11 | "module": "./main.js", 12 | "scripts": { 13 | "test": "mocha --exit", 14 | "build": "rollup -c rollup.cjs.config.js" 15 | }, 16 | "bin": { 17 | "calcwit": "calcwit.js" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "git+https://github.com/iden3/circom_runtime.git" 22 | }, 23 | "keywords": [ 24 | "circom", 25 | "runtime", 26 | "zksnarks", 27 | "witness", 28 | "wasm" 29 | ], 30 | "author": "Jordi Baylina", 31 | "license": "Apache-2.0", 32 | "bugs": { 33 | "url": "https://github.com/iden3/circom_runtime/issues" 34 | }, 35 | "homepage": "https://github.com/iden3/circom_runtime#readme", 36 | "dependencies": { 37 | "ffjavascript": "0.3.1" 38 | }, 39 | "devDependencies": { 40 | "chai": "^5.1.1", 41 | "eslint": "^8.17.0", 42 | "fastfile": "^0.0.20", 43 | "mocha": "^10.7.3", 44 | "rollup": "^2.39.1", 45 | "snarkjs": "^0.7.4" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /rollup.cjs.config.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import { builtinModules as builtin } from "module"; 3 | 4 | const pkg = JSON.parse(fs.readFileSync("./package.json")); 5 | 6 | export default { 7 | input: "main.js", 8 | output: { 9 | file: "build/main.cjs", 10 | format: "cjs", 11 | }, 12 | external: [ 13 | ...Object.keys(pkg.dependencies), 14 | ...builtin, 15 | ] 16 | }; 17 | 18 | -------------------------------------------------------------------------------- /test/circuit/circuit.circom: -------------------------------------------------------------------------------- 1 | template Multiplier(n) { 2 | signal input a; 3 | signal input b; 4 | signal input c; 5 | signal output d; 6 | 7 | signal int[n]; 8 | 9 | int[0] <== a * a + b * 2 + c + 3; 10 | for (var i = 1; i < n; i++) { 11 | int[i] <== int[i-1] * int[i-1] + b + 4; 12 | } 13 | 14 | d <== int[n-1]; 15 | } 16 | 17 | component main {public [a, b, c]} = Multiplier(1000); 18 | -------------------------------------------------------------------------------- /test/circuit/circuit.r1cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iden3/circom_runtime/3ad281088f78a4be5e6d7adda073823e60ca08fa/test/circuit/circuit.r1cs -------------------------------------------------------------------------------- /test/circuit/circuit.zkey: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iden3/circom_runtime/3ad281088f78a4be5e6d7adda073823e60ca08fa/test/circuit/circuit.zkey -------------------------------------------------------------------------------- /test/circuit/circuit_js/circuit.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iden3/circom_runtime/3ad281088f78a4be5e6d7adda073823e60ca08fa/test/circuit/circuit_js/circuit.wasm -------------------------------------------------------------------------------- /test/circuit/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "a": 1, 3 | "b": 2, 4 | "c": 3 5 | } 6 | -------------------------------------------------------------------------------- /test/circuit/verification_key.json: -------------------------------------------------------------------------------- 1 | { 2 | "protocol": "groth16", 3 | "curve": "bn128", 4 | "nPublic": 4, 5 | "vk_alpha_1": [ 6 | "20491192805390485299153009773594534940189261866228447918068658471970481763042", 7 | "9383485363053290200918347156157836566562967994039712273449902621266178545958", 8 | "1" 9 | ], 10 | "vk_beta_2": [ 11 | [ 12 | "6375614351688725206403948262868962793625744043794305715222011528459656738731", 13 | "4252822878758300859123897981450591353533073413197771768651442665752259397132" 14 | ], 15 | [ 16 | "10505242626370262277552901082094356697409835680220590971873171140371331206856", 17 | "21847035105528745403288232691147584728191162732299865338377159692350059136679" 18 | ], 19 | [ 20 | "1", 21 | "0" 22 | ] 23 | ], 24 | "vk_gamma_2": [ 25 | [ 26 | "10857046999023057135944570762232829481370756359578518086990519993285655852781", 27 | "11559732032986387107991004021392285783925812861821192530917403151452391805634" 28 | ], 29 | [ 30 | "8495653923123431417604973247489272438418190587263600148770280649306958101930", 31 | "4082367875863433681332203403145435568316851327593401208105741076214120093531" 32 | ], 33 | [ 34 | "1", 35 | "0" 36 | ] 37 | ], 38 | "vk_delta_2": [ 39 | [ 40 | "3975790311893893341340161766879905936958661067882264032474266902345378689989", 41 | "644478862152636240062151223979355724911820071041473015124265160845680677640" 42 | ], 43 | [ 44 | "18653336180275048042902643932736430752334488465561901574241586300721370515350", 45 | "4439809646982105720900774322696795865391078961997895171991532846160287677573" 46 | ], 47 | [ 48 | "1", 49 | "0" 50 | ] 51 | ], 52 | "vk_alphabeta_12": [ 53 | [ 54 | [ 55 | "2029413683389138792403550203267699914886160938906632433982220835551125967885", 56 | "21072700047562757817161031222997517981543347628379360635925549008442030252106" 57 | ], 58 | [ 59 | "5940354580057074848093997050200682056184807770593307860589430076672439820312", 60 | "12156638873931618554171829126792193045421052652279363021382169897324752428276" 61 | ], 62 | [ 63 | "7898200236362823042373859371574133993780991612861777490112507062703164551277", 64 | "7074218545237549455313236346927434013100842096812539264420499035217050630853" 65 | ] 66 | ], 67 | [ 68 | [ 69 | "7077479683546002997211712695946002074877511277312570035766170199895071832130", 70 | "10093483419865920389913245021038182291233451549023025229112148274109565435465" 71 | ], 72 | [ 73 | "4595479056700221319381530156280926371456704509942304414423590385166031118820", 74 | "19831328484489333784475432780421641293929726139240675179672856274388269393268" 75 | ], 76 | [ 77 | "11934129596455521040620786944827826205713621633706285934057045369193958244500", 78 | "8037395052364110730298837004334506829870972346962140206007064471173334027475" 79 | ] 80 | ] 81 | ], 82 | "IC": [ 83 | [ 84 | "13301910515319440036781559521244314286896559228088406220286498587163275032898", 85 | "21752102455923956970297538199953311940955308225446086282237557428140916857247", 86 | "1" 87 | ], 88 | [ 89 | "17482596306642470706171849523416052476936601967698452358356767181693176975875", 90 | "16875289648181723199466955981261105815550134487513330320459939834929279218791", 91 | "1" 92 | ], 93 | [ 94 | "5772884469279940971460880086361780610840620334751263386570253375423022114824", 95 | "19701704231049813163687130014634352753198605671093169759803278572696433587644", 96 | "1" 97 | ], 98 | [ 99 | "20438355410214480154024250925177562386037016834261610289216986319964190521404", 100 | "15984525382738813974840145618800038332013248407344020798478497142205284007916", 101 | "1" 102 | ], 103 | [ 104 | "1311730469912073488579103303436905662163459373538656417086366898821493109364", 105 | "11969131862858876373690771619700437495976850333829176058509962039594565501218", 106 | "1" 107 | ] 108 | ] 109 | } -------------------------------------------------------------------------------- /test/witness_calc.test.js: -------------------------------------------------------------------------------- 1 | import path from "path"; 2 | import {WitnessCalculatorBuilder} from "../main.js"; 3 | import * as fastFile from "fastfile"; 4 | import * as snarkjs from "snarkjs"; 5 | import fs from "fs"; 6 | import {expect} from "chai"; 7 | 8 | describe("Witness Calc test", function () { 9 | const wasmFilename = path.join("test", "circuit", "circuit_js", "circuit.wasm"); 10 | const zkeyFilename = path.join("test", "circuit", "circuit.zkey"); 11 | const vkeyFilename = path.join("test", "circuit", "verification_key.json"); 12 | const input = { 13 | "a": 1, 14 | "b": 2, 15 | "c": 3 16 | }; 17 | 18 | this.timeout(15000); 19 | 20 | //let curve; 21 | 22 | before(async () => { 23 | // snarkjs.curves is not accessible yet, waiting for snarkjs release where it would be exported 24 | //curve = await snarkjs.curves.getCurveFromName("bn128"); 25 | }); 26 | 27 | after(async () => { 28 | // that would be a proper way to terminate background jobs instead of `mocha --exit` 29 | //await curve.terminate(); 30 | }); 31 | 32 | it("regular witness calc & prove", async () => { 33 | 34 | for (let i = 0; i < 10; i++) { 35 | 36 | const wtns = {type: "mem"}; 37 | 38 | const fdWasm = await fastFile.readExisting(wasmFilename); 39 | const wasm = await fdWasm.read(fdWasm.totalSize); 40 | await fdWasm.close(); 41 | 42 | const wc = await WitnessCalculatorBuilder(wasm); 43 | expect(wc.circom_version()).to.be.equal(2); 44 | 45 | const fdWtns = await fastFile.createOverride(wtns); 46 | 47 | const w = await wc.calculateWTNSBin(input); 48 | 49 | await fdWtns.write(w); 50 | await fdWtns.close(); 51 | 52 | 53 | // groth16 prove 54 | const {proof, publicSignals} = await snarkjs.groth16.prove(zkeyFilename, wtns); 55 | 56 | // Verify the proof 57 | const verificationKey = JSON.parse(fs.readFileSync(vkeyFilename, "utf8")); 58 | const isValid = await snarkjs.groth16.verify(verificationKey, publicSignals, proof); 59 | 60 | expect(isValid).to.be.true; 61 | } 62 | }); 63 | 64 | it("reuse witness calc instance & prove", async () => { 65 | const verificationKey = JSON.parse(fs.readFileSync(vkeyFilename, "utf8")); 66 | 67 | const wtns = {type: "mem"}; 68 | 69 | const fdWasm = await fastFile.readExisting(wasmFilename); 70 | const wasm = await fdWasm.read(fdWasm.totalSize); 71 | await fdWasm.close(); 72 | 73 | const wc = await WitnessCalculatorBuilder(wasm); 74 | expect(wc.circom_version()).to.be.equal(2); 75 | 76 | const fdWtns = await fastFile.createOverride(wtns); 77 | 78 | const w = await wc.calculateWTNSBin(input); 79 | 80 | await fdWtns.write(w); 81 | await fdWtns.close(); 82 | 83 | // groth16 prove 84 | const res = await snarkjs.groth16.prove(zkeyFilename, wtns); 85 | 86 | // Verify the proof 87 | const isValid = await snarkjs.groth16.verify(verificationKey, res.publicSignals, res.proof); 88 | 89 | expect(isValid).to.be.true; 90 | 91 | ///////////////////////////////////////////// 92 | // Witness Calculator from the same wasm instance 93 | ///////////////////////////////////////////// 94 | 95 | for (let i = 0; i < 9; i++) { 96 | 97 | const wtns2 = {type: "mem"}; 98 | 99 | const wc2 = await WitnessCalculatorBuilder(wc.instance); 100 | expect(wc2.circom_version()).to.be.equal(2); 101 | 102 | const fdWtns2 = await fastFile.createOverride(wtns2); 103 | 104 | const w2 = await wc2.calculateWTNSBin(input); 105 | 106 | await fdWtns2.write(w2); 107 | await fdWtns2.close(); 108 | 109 | // groth16 prove 110 | const res3 = await snarkjs.groth16.prove(zkeyFilename, wtns2); 111 | 112 | // Verify the proof 113 | const isValid2 = await snarkjs.groth16.verify(verificationKey, res3.publicSignals, res3.proof); 114 | 115 | expect(isValid2).to.be.true; 116 | } 117 | 118 | }); 119 | }); --------------------------------------------------------------------------------