From eb8cb0af7437e3322ed2bc37a1b4142a10f0e92c Mon Sep 17 00:00:00 2001 From: Jordi Baylina Date: Thu, 26 Mar 2020 17:42:25 +0100 Subject: [PATCH] Almost ready for 0.5.0 --- .eslintrc.js | 6 +- COPYING | 2 +- TUTORIAL.md | 43 +- cli.js | 8 +- doc/r1cs_bin_format.md | 635 +- doc/r1cs_bin_format.monopic | Bin 28845 -> 0 bytes doc/r1cs_example.monopic | Bin 5950 -> 0 bytes package-lock.json | 1109 ++- package.json | 19 +- ports/c/buildasm/add.asm.ejs | 245 - ports/c/buildasm/binops.asm.ejs | 240 - ports/c/buildasm/buildzqfield.js | 72 - ports/c/buildasm/buildzqfieldtester.js | 75 - ports/c/buildasm/cmpops.asm.ejs | 439 -- ports/c/buildasm/cmpops_old.asm.ejs | 108 - ports/c/buildasm/copy.asm.ejs | 139 - ports/c/buildasm/fr.asm | 7607 -------------------- ports/c/buildasm/fr.asm.ejs | 53 - ports/c/buildasm/fr.c | 201 - ports/c/buildasm/fr.c.ejs | 201 - ports/c/buildasm/fr.h | 67 - ports/c/buildasm/fr.h.ejs | 67 - ports/c/buildasm/fr.o | Bin 30956 -> 0 bytes ports/c/buildasm/logicalops.asm.ejs | 97 - ports/c/buildasm/main.c | 64 - ports/c/buildasm/montgomery.asm.ejs | 350 - ports/c/buildasm/mul.asm.ejs | 275 - ports/c/buildasm/neg.asm.ejs | 78 - ports/c/buildasm/old/buildfieldasm.js | 33 - ports/c/buildasm/old/buildzqfield.js | 209 - ports/c/buildasm/old/buildzqfieldtester.js | 68 - ports/c/buildasm/old/fr.asm.ejs.old | 302 - ports/c/buildasm/old/mul.asm.ejs | 251 - ports/c/buildasm/sub.asm.ejs | 317 - ports/c/buildasm/tester | Bin 1518884 -> 0 bytes ports/c/buildasm/tester.cpp | 220 - ports/c/buildasm/utils.asm.ejs | 72 - ports/c/calcwit.cpp | 234 - ports/c/calcwit.h | 73 - ports/c/circom.h | 58 - ports/c/fr.c | 1 - ports/c/fr.h | 1 - ports/c/fr.o | 1 - ports/c/main.cpp | 202 - ports/c/mainjson.cpp | 47 - ports/c/tester.js | 67 +- ports/c/utils.cpp | 25 - ports/c/utils.h | 10 - ports/c/zqfield.cpp | 199 - ports/c/zqfield.h | 49 - ports/wasm/build_runtime.js | 397 +- ports/wasm/builder.js | 24 +- ports/wasm/tester.js | 39 +- ports/wasm/witness_calculator.js | 209 - src/buildsyms.js | 16 +- src/compiler.js | 12 +- src/construction_phase.js | 4 +- src/r1csfile.js | 200 +- test/basiccases.js | 3 +- test/basiccases.js.old | 343 - test/cases.js | 67 - test/fieldasm.js | 453 -- 62 files changed, 1251 insertions(+), 15155 deletions(-) delete mode 100644 doc/r1cs_bin_format.monopic delete mode 100644 doc/r1cs_example.monopic delete mode 100644 ports/c/buildasm/add.asm.ejs delete mode 100644 ports/c/buildasm/binops.asm.ejs delete mode 100644 ports/c/buildasm/buildzqfield.js delete mode 100644 ports/c/buildasm/buildzqfieldtester.js delete mode 100644 ports/c/buildasm/cmpops.asm.ejs delete mode 100644 ports/c/buildasm/cmpops_old.asm.ejs delete mode 100644 ports/c/buildasm/copy.asm.ejs delete mode 100644 ports/c/buildasm/fr.asm delete mode 100644 ports/c/buildasm/fr.asm.ejs delete mode 100644 ports/c/buildasm/fr.c delete mode 100644 ports/c/buildasm/fr.c.ejs delete mode 100644 ports/c/buildasm/fr.h delete mode 100644 ports/c/buildasm/fr.h.ejs delete mode 100644 ports/c/buildasm/fr.o delete mode 100644 ports/c/buildasm/logicalops.asm.ejs delete mode 100644 ports/c/buildasm/main.c delete mode 100644 ports/c/buildasm/montgomery.asm.ejs delete mode 100644 ports/c/buildasm/mul.asm.ejs delete mode 100644 ports/c/buildasm/neg.asm.ejs delete mode 100644 ports/c/buildasm/old/buildfieldasm.js delete mode 100644 ports/c/buildasm/old/buildzqfield.js delete mode 100644 ports/c/buildasm/old/buildzqfieldtester.js delete mode 100644 ports/c/buildasm/old/fr.asm.ejs.old delete mode 100644 ports/c/buildasm/old/mul.asm.ejs delete mode 100644 ports/c/buildasm/sub.asm.ejs delete mode 100755 ports/c/buildasm/tester delete mode 100644 ports/c/buildasm/tester.cpp delete mode 100644 ports/c/buildasm/utils.asm.ejs delete mode 100644 ports/c/calcwit.cpp delete mode 100644 ports/c/calcwit.h delete mode 100644 ports/c/circom.h delete mode 120000 ports/c/fr.c delete mode 120000 ports/c/fr.h delete mode 120000 ports/c/fr.o delete mode 100644 ports/c/main.cpp delete mode 100644 ports/c/mainjson.cpp delete mode 100644 ports/c/utils.cpp delete mode 100644 ports/c/utils.h delete mode 100644 ports/c/zqfield.cpp delete mode 100644 ports/c/zqfield.h delete mode 100644 ports/wasm/witness_calculator.js delete mode 100644 test/basiccases.js.old delete mode 100644 test/cases.js delete mode 100644 test/fieldasm.js diff --git a/.eslintrc.js b/.eslintrc.js index 2f45ad9..ce75c5c 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,7 +1,4 @@ module.exports = { - "plugins": [ - "mocha" - ], "env": { "es6": true, "node": true, @@ -27,7 +24,6 @@ module.exports = { "semi": [ "error", "always" - ], - "mocha/no-exclusive-tests": "error" + ] } }; diff --git a/COPYING b/COPYING index 9cecc1d..9dc9bca 100644 --- a/COPYING +++ b/COPYING @@ -1,7 +1,7 @@ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2020 0Kims Association Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. diff --git a/TUTORIAL.md b/TUTORIAL.md index 72fe63a..ab20464 100644 --- a/TUTORIAL.md +++ b/TUTORIAL.md @@ -6,7 +6,7 @@ This tutorial will guide you in creating your first Zero Knowledge zkSnark circu ### 1.1 Pre-requisites -If you don't have it installed yet, you need to install `Node.js`. +If you don't have it installed yet, you need to install `Node.js`. The last stable version of `Node.js` (or 8.12.0) works just fine, but if you install the latest current version `Node.js` (10.12.0) you will see a significant increase in performance. This is because last versions of node includes Big Integer Libraries nativelly. The `snarkjs` library makes use of this feature if available, and this improves the performance x10 (!). @@ -16,6 +16,7 @@ Run: ```sh npm install -g circom +npm install -g circom_runtime npm install -g snarkjs ``` @@ -42,7 +43,7 @@ template Multiplier() { signal private input a; signal private input b; signal output c; - + c <== a*b; } @@ -62,10 +63,12 @@ Note: When compiling a circuit, a component named `main` must always exist. We are now ready to compile the circuit. Run the following command: ```sh -circom circuit.circom -o circuit.json +circom circuit.circom --r1cs --wasm --sym ``` -to compile the circuit to a file named `circuit.json` +The -r optin will generate `circuit.r1cs` ( The r1cs constraint system of the circuit in binary format) +The -w will generate `circuit.wasm` (The wasm code to generate the witness) +The -s will generate `circuit.sym` (This is the symbols file, required for debugging or if you want to print the constraint system in an annotated mode) ## 3. Taking the compiled circuit to *snarkjs* @@ -74,7 +77,7 @@ Now that the circuit is compiled, we will continue with `snarkjs`. Please note that you can always access the help of `snarkjs` by typing: ```sh -snarkjs --help +snarkjs --help ``` ### 3.1 View information and stats regarding a circuit @@ -82,13 +85,13 @@ snarkjs --help To show general statistics of this circuit, you can run: ```sh -snarkjs info -c circuit.json +snarkjs info -r circuit.r1cs ``` You can also print the constraints of the circuit by running: ```sh -snarkjs printconstraints -c circuit.json +snarkjs printconstraints -r circuit.r1cs -s circuit.sym ``` @@ -98,10 +101,10 @@ snarkjs printconstraints -c circuit.json Ok, let's run a setup for our circuit: ```sh -snarkjs setup +snarkjs setup ``` -> By default `snarkjs` will look for and use `circuit.json`. You can always specify a different circuit file by adding `-c ` +> By default `snarkjs` will look for and use `circuit.r1cs`. You can always specify a different circuit file by adding `-r ` The output of the setup will in the form of 2 files: `proving_key.json` and `verification_key.json` @@ -109,13 +112,13 @@ The output of the setup will in the form of 2 files: `proving_key.json` and `ver Before creating any proof, we need to calculate all the signals of the circuit that match (all) the constrains of the circuit. -`snarkjs` calculates those for you. You need to provide a file with the inputs and it will execute the circuit and calculate all the intermediate signals and the output. This set of signals is the *witness*. +`circom` generates a wasm module that calculates those for you. You need to provide a file with the inputs and it will execute the circuit and calculate all the intermediate signals and the output. This set of signals is the *witness*. The zero knowledge proofs prove that you know a set of signals (witness) that match all the constraints, without revealing any of the signals except the public inputs plus the outputs. -For example, imagine you want to prove you are able to factor 33. It means that you know two numbers `a` and `b` and when you multiply them, it results in 33. +For example, imagine you want to prove you are able to factor 33. It means that you know two numbers `a` and `b` and when you multiply them, it results in 33. -> Of course you can always use one and the same number as `a` and `b`. We will deal with this problem later. +> Of course you can always use one and the same number as `a` or `b`. We will deal with this problem later. So you want to prove that you know 3 and 11. @@ -128,9 +131,13 @@ Let's create a file named `input.json` Now let's calculate the witness: ```sh -snarkjs calculatewitness +snarkjs --wasm circuit.wasm --input input.json --witness witness.json ``` +`calcwit` is part of the circom_runtime package and it's just a wrapper in JS to call the wasm module. + +You can use `circom_runtime` from your own project to calulate the witness. + You may want to take a look at `witness.json` file with all the signals. ### Create the proof @@ -214,20 +221,20 @@ template Multiplier() { signal output c; signal inva; signal invb; - + inva <-- 1/(a-1); (a-1)*inva === 1; - + invb <-- 1/(b-1); - (b-1)*invb === 1; - + (b-1)*invb === 1; + c <== a*b; } component main = Multiplier(); ``` -A nice thing of the circom language is that you can split a <== into two independent actions: <-- and === +A nice thing of the circom language is that you can split a <== into two independent actions: <-- and === The <-- and --> operators assign a value to a signal without creating any constraints. diff --git a/cli.js b/cli.js index 17651fe..11be768 100755 --- a/cli.js +++ b/cli.js @@ -23,6 +23,7 @@ const fs = require("fs"); const path = require("path"); +const bigInt = require("big-integer"); const compiler = require("./src/compiler"); @@ -37,6 +38,7 @@ const argv = require("yargs") .alias("t", "wat") .alias("s", "sym") .alias("r", "r1cs") + .alias("p", "prime") .alias("n", "newThreadTemplates") .help("h") .alias("h", "help") @@ -50,10 +52,6 @@ const argv = require("yargs") type: "boolean", description: "Do not optimize constraints" }) - .option("sanityCheck", { - type: "boolean", - description: "Add sanity check code" - }) .epilogue(`Copyright (C) 2018 0kims association This program comes with ABSOLUTELY NO WARRANTY; This is free software, and you are welcome to redistribute it @@ -84,6 +82,8 @@ const options = {}; options.reduceConstraints = !argv.fast; options.verbose = argv.verbose || false; options.sanityCheck = argv.sanitycheck; +options.prime = argv.prime || bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); + if (argv.csource) { options.cSourceWriteStream = fs.createWriteStream(cSourceName); } diff --git a/doc/r1cs_bin_format.md b/doc/r1cs_bin_format.md index fbe3ab0..813af4b 100644 --- a/doc/r1cs_bin_format.md +++ b/doc/r1cs_bin_format.md @@ -152,114 +152,93 @@ Size in bytes of the section Section Type: 0x01 ```` - ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ 4 │ FieldDefSize ┃ FieldDef ┃ field Id - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┏━━━━┳━━━━━━━━━━━━━━━━━┓ - ┃ 4 │ 00 00 00 00 ┃ bigInt Format + ┃ 4 │ 20 00 00 00 ┃ Field Size in bytes (fs) ┗━━━━┻━━━━━━━━━━━━━━━━━┛ + ┏━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ fs │ 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430 ┃ Prime size + ┗━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┏━━━━┳━━━━━━━━━━━━━━━━━┓ - ┃ 4 │ is ┃ Id size ( Normally 4 (32bits)) + ┃ 32 │ 01 00 00 00 ┃ nWires ┗━━━━┻━━━━━━━━━━━━━━━━━┛ ┏━━━━┳━━━━━━━━━━━━━━━━━┓ - ┃ is │ 01 00 00 00 ┃ nWires + ┃ 32 │ 01 00 00 00 ┃ nPubOut ┗━━━━┻━━━━━━━━━━━━━━━━━┛ ┏━━━━┳━━━━━━━━━━━━━━━━━┓ - ┃ is │ 01 00 00 00 ┃ nPubOut + ┃ 32 │ 01 00 00 00 ┃ nPubIn ┗━━━━┻━━━━━━━━━━━━━━━━━┛ ┏━━━━┳━━━━━━━━━━━━━━━━━┓ - ┃ is │ 01 00 00 00 ┃ nPubIn + ┃ 32 │ 01 00 00 00 ┃ nPrvIn ┗━━━━┻━━━━━━━━━━━━━━━━━┛ + ┏━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ 64 │ 01 00 00 00 00 00 00 00 ┃ nLabels + ┗━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ┏━━━━┳━━━━━━━━━━━━━━━━━┓ - ┃ is │ 01 00 00 00 ┃ nPrvIn - ┗━━━━┻━━━━━━━━━━━━━━━━━┛ - ┏━━━━┳━━━━━━━━━━━━━━━━━┓ - ┃ is │ 01 00 00 00 ┃ nLabels - ┗━━━━┻━━━━━━━━━━━━━━━━━┛ - ┏━━━━┳━━━━━━━━━━━━━━━━━┓ - ┃ is │ 01 00 00 00 ┃ mConstraints + ┃ 32 │ 01 00 00 00 ┃ mConstraints ┗━━━━┻━━━━━━━━━━━━━━━━━┛ ```` -#### fieldDefSize +#### field Size (fs) Size: 4 bytes Format: Little-Endian -Size of the field Definition +Size in bytes of a field element. Mast be a multiple of 8. Example: ``` 0x00 0x0 0x00 0x00 ``` -#### fieldDef - -Field dfinition the first 4 bytes are the type in LE. 0x0000001 Ar prime fields. - -For the prime fields, the next bytes are the prime in variable length LE base 256 format. - -NOTE: This number is independent of the bigInt Format defined next - -#### bigInt Format +#### Prime -Size: 4 bytes -Format: Little-Endian - -0 Means that the Big Int are variable size LE. -That is the First byte indicates the size and the remaining bytes are the number in little enfian (LSB first) base 256. - -Numbers from 1 to 16383 are fixed size Litle endian format base 256. +Prime Number of the field Example: ``` -0x00 0x00 0x00 0x00 +0x010000f0_93f5e143_9170b979_48e83328_5d588181_b64550b8_29a031e1_724e6430 ``` -#### Id Size (is) - -Size: 4 bytes -Format: Little-Endian - -Size of the identifiers for wires, labels and constraints. In small circuits this is going to be 4 (32 bits) -but can be increaset to 8 for bigger circiuits. - -The only possible numbers are 4 or 8 - - #### Number of wires -Size: `is` bytes +Size: 4 bytes Format: Little-Endian Total Number of wires including ONE signal (Index 0). #### Number of public outputs -Size: `is` bytes +Size: 4 bytes Format: Little-Endian Total Number of wires public output wires. They should be starting at idx 1 #### Number of public inputs -Size: `is` bytes +Size: 4 bytes Format: Little-Endian Total Number of wires public input wires. They should be starting just after the public output #### Number of private inputs -Size: `is` bytes +Size: 4 bytes +Format: Little-Endian + +Total Number of wires private input wires. They should be starting just after the public inputs + +#### Number of Labels + +Size: 8 bytes Format: Little-Endian Total Number of wires private input wires. They should be starting just after the public inputs #### Number of constraints (m) -Size: `ìs` bytes +Size: 4 bytes Format: Little-Endian Total Number of constraints @@ -269,115 +248,115 @@ Total Number of constraints Section Type: 0x02 ```` - ┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲ - ┃ is │ nA ┃ ╲ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲ - ┃ is │ wireId_1 ┃ V │ a_{0,wireId_1} ┃ │ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ - ┃ is │ wireId_2 ┃ V │ a_{0,wireId_2} ┃ │ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ - ... ... │ - ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ wireId_nA ┃ V │ a_{0,wireId_nA} ┃ │ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ - ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ nB ┃ │ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ wireId_1 ┃ V │ b_{0,wireId_1} ┃ │ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲ - ┃ is │ wireId_2 ┃ V │ b_{0,wireId_2} ┃ ╲ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ Constraint_0 - ... ... ╱ - ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ wireId_nB ┃ V │ b_{0,wireId_nB} ┃ │ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ - ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ nC ┃ │ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ wireId_1 ┃ V │ c_{0,wireId_1} ┃ │ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ - ┃ is │ wireId_2 ┃ V │ c_{0,wireId_2} ┃ │ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ - ... ... │ - ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ wireId_nC ┃ V │ c_{0,wireId_nC} ┃ ╱ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ - ╱ - - - ┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲ - ┃ is │ nA ┃ ╲ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲ - ┃ is │ wireId_1 ┃ V │ a_{1,wireId_1} ┃ │ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ - ┃ is │ wireId_2 ┃ V │ a_{1,wireId_2} ┃ │ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ - ... ... │ - ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ wireId_nA ┃ V │ a_{1,wireId_nA} ┃ │ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ - ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ nB ┃ │ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ wireId_1 ┃ V │ b_{1,wireId_1} ┃ │ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲ - ┃ is │ wireId_2 ┃ V │ b_{1,wireId_2} ┃ ╲ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ Constraint_1 - ... ... ╱ - ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ wireId_nB ┃ V │ b_{1,wireId_nB} ┃ │ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ - ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ nC ┃ │ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ wireId_1 ┃ V │ c_{1,wireId_1} ┃ │ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ - ┃ is │ wireId_2 ┃ V │ c_{1,wireId_2} ┃ │ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ - ... ... │ - ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ wireId_nC ┃ V │ c_{1,wireId_nC} ┃ ╱ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ - ╱ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲ + ┃ 32 │ nA ┃ ╲ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲ + ┃ 32 │ wireId_1 ┃ fs │ a_{0,wireId_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ + ┃ 32 │ wireId_2 ┃ fs │ a_{0,wireId_2} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ... ... │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ wireId_nA ┃ fs │ a_{0,wireId_nA} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ nB ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ wireId_1 ┃ fs │ b_{0,wireId_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲ + ┃ 32 │ wireId_2 ┃ fs │ b_{0,wireId_2} ┃ ╲ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ Constraint_0 + ... ... ╱ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ wireId_nB ┃ fs │ b_{0,wireId_nB} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ nC ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ wireId_1 ┃ fs │ c_{0,wireId_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ + ┃ 32 │ wireId_2 ┃ fs │ c_{0,wireId_2} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ... ... │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ wireId_nC ┃ fs │ c_{0,wireId_nC} ┃ ╱ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ + ╱ + + + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲ + ┃ 32 │ nA ┃ ╲ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲ + ┃ 32 │ wireId_1 ┃ fs │ a_{1,wireId_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ + ┃ 32 │ wireId_2 ┃ fs │ a_{1,wireId_2} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ... ... │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ wireId_nA ┃ fs │ a_{1,wireId_nA} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ nB ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ wireId_1 ┃ fs │ b_{1,wireId_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲ + ┃ 32 │ wireId_2 ┃ fs │ b_{1,wireId_2} ┃ ╲ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ Constraint_1 + ... ... ╱ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ wireId_nB ┃ fs │ b_{1,wireId_nB} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ nC ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ wireId_1 ┃ fs │ c_{1,wireId_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ + ┃ 32 │ wireId_2 ┃ fs │ c_{1,wireId_2} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ... ... │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ wireId_nC ┃ fs │ c_{1,wireId_nC} ┃ ╱ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ + ╱ ... ... ... - ┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲ - ┃ is │ nA ┃ ╲ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲ - ┃ is │ wireId_1 ┃ V │ a_{m-1,wireId_1} ┃ │ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ - ┃ is │ wireId_2 ┃ V │ a_{m-1,wireId_2} ┃ │ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ - ... ... │ - ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ wireId_nA ┃ V │ a_{m-1,wireId_nA} ┃ │ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ - ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ nB ┃ │ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ wireId_1 ┃ V │ b_{m-1,wireId_1} ┃ │ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲ - ┃ is │ wireId_2 ┃ V │ b_{m-1,wireId_2} ┃ ╲ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ Constraint_{m-1} - ... ... ╱ - ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ wireId_nB ┃ V │ b_{m-1,wireId_nB} ┃ │ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ - ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ nC ┃ │ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ wireId_1 ┃ V │ c_{m-1,wireId_1} ┃ │ - ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ - ┃ is │ wireId_2 ┃ V │ c_{m-1,wireId_2} ┃ │ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ - ... ... │ - ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ - ┃ is │ wireId_nC ┃ V │ c_{m-1,wireId_nC} ┃ ╱ - ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ - ╱ ╱ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲ + ┃ 32 │ nA ┃ ╲ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ ╲ + ┃ 32 │ wireId_1 ┃ fs │ a_{m-1,wireId_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ + ┃ 32 │ wireId_2 ┃ fs │ a_{m-1,wireId_2} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ... ... │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ wireId_nA ┃ fs │ a_{m-1,wireId_nA} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ nB ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ wireId_1 ┃ fs │ b_{m-1,wireId_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ ╲ + ┃ 32 │ wireId_2 ┃ fs │ b_{m-1,wireId_2} ┃ ╲ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ Constraint_{m-1} + ... ... ╱ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ wireId_nB ┃ fs │ b_{m-1,wireId_nB} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ nC ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ wireId_1 ┃ fs │ c_{m-1,wireId_1} ┃ │ + ┣━━━━╋━━━━━━━━━━━━━━━━━╋━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━┫ │ + ┃ 32 │ wireId_2 ┃ fs │ c_{m-1,wireId_2} ┃ │ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ │ + ... ... │ + ┏━━━━┳━━━━━━━━━━━━━━━━━┳━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓ │ + ┃ 32 │ wireId_nC ┃ fs │ c_{m-1,wireId_nC} ┃ ╱ + ┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱ + ╱ ```` @@ -401,7 +380,7 @@ $$ #### Number of nonZero Factors -Size: `ìs` bytes +Size: 4 bytes Format: Little-Endian Total number of non Zero factors in the linear compination. @@ -414,16 +393,14 @@ For each factor we have the index of the factor and the value of the factor. #### WireId of the factor -Size: `is` bytes +Size: 4 bytes Format: Little-Endian WireId of the nonZero Factor #### Value of the factor -The first byte indicate the length N in bytes of the number in the upcoming bytes. - -The next N bytes represent the value in Little Endian format. +This is the factor that multiplies the associated wire in the linear convination. For example, to represent the linear combination: @@ -436,13 +413,13 @@ The linear combination would be represented as: ```` ┏━━━━━━━━━━━━━━━━━┓ ┃ 03 00 00 00 ┃ - ┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┓ - ┃ 04 00 00 00 ┃ 01 05 ┃ - ┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫ - ┃ 05 00 00 00 ┃ 01 08 ┃ - ┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━┫ - ┃ 76 03 00 00 ┃ 02 04 01 ┃ - ┗━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━┛ + ┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ 04 00 00 00 ┃ 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ + ┃ 05 00 00 00 ┃ 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┣━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ + ┃ 76 03 00 00 ┃ 04010000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┗━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ ```` @@ -452,7 +429,7 @@ Section Type: 0x03 ```` ┏━━┳━━━━━━━━━━━━━━━━━━━┳━━┳━━━━━━━━━━━━━━━━━━━┓ ┏━━┳━━━━━━━━━━━━━━━━━━━┓ -┃is│ labelId of Wire_0 ┃is│ labelId of Wire_1 ┃ ... ┃is│ labelId of Wire_n ┃ +┃64│ labelId of Wire_0 ┃64│ labelId of Wire_1 ┃ ... ┃64│ labelId of Wire_n ┃ ┗━━┻━━━━━━━━━━━━━━━━━━━┻━━┻━━━━━━━━━━━━━━━━━━━┛ ┗━━┻━━━━━━━━━━━━━━━━━━━┛ ```` @@ -500,176 +477,170 @@ $$ The format will be: ```` - ┏━━━━━━━━━━━━━━┓ - ┃ 72 31 63 77 ┃ Magic - ┣━━━━━━━━━━━━━━┫ - ┃ 01 00 00 00 ┃ Version - ┣━━━━━━━━━━━━━━┫ - ┃ 03 00 00 00 ┃ nSections - ┗━━━━━━━━━━━━━━┛ - ┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓ - ┃ 01 00 00 00 ┃ 49 00 00 00 ┃ SectionType: Header - ┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛ - ┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓ - ┃ 25 00 00 00 ┃ 10 00 00 00 ┃ FieldDefSize FieldDef - ┣━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ - ┃ 20 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430┃ - ┣━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ - ┃ 00 00 00 00 ┃ Big Int format - ┣━━━━━━━━━━━━━━┫ - ┃ 04 00 00 00 ┃ Id Size - ┣━━━━━━━━━━━━━━┫ - ┃ 07 00 00 00 ┃ # of wires - ┣━━━━━━━━━━━━━━┫ - ┃ 01 00 00 00 ┃ # Public Outs - ┣━━━━━━━━━━━━━━┫ - ┃ 02 00 00 00 ┃ # Public Ins - ┣━━━━━━━━━━━━━━┫ - ┃ 03 00 00 00 ┃ # Private Ins - ┣━━━━━━━━━━━━━━┫ - ┃ e8 03 00 00 ┃ # Labels - ┣━━━━━━━━━━━━━━┫ - ┃ 03 00 00 00 ┃ # Constraints - ┗━━━━━━━━━━━━━━┛ - ┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓ - ┃ 02 00 00 00 ┃ 8b 00 00 00 ┃ SectionType: Constraints - ┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛ - ┏━━━━━━━━━━━━━━┓ Constraint 0: (3w_5 + 8w_6) * (2w_0 + 20w_2 + 12w_3) - (5w_0 + 7w_2) = 0 - ┃ 02 00 00 00 ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━┓ - ┃ 05 00 00 00 ┃ 01 03 ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━┫ - ┃ 06 00 00 00 ┃ 01 08 ┃ - ┗━━━━━━━━━━━━━━┻━━━━━━━━┛ - ┏━━━━━━━━━━━━━━┓ - ┃ 03 00 00 00 ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━┓ - ┃ 00 00 00 00 ┃ 01 02 ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━┫ - ┃ 02 00 00 00 ┃ 01 14 ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━┫ - ┃ 03 00 00 00 ┃ 01 0C ┃ - ┗━━━━━━━━━━━━━━┻━━━━━━━━┛ - ┏━━━━━━━━━━━━━━┓ - ┃ 02 00 00 00 ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━┓ - ┃ 00 00 00 00 ┃ 01 05 ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━┫ - ┃ 02 00 00 00 ┃ 01 07 ┃ - ┗━━━━━━━━━━━━━━┻━━━━━━━━┛ - - ┏━━━━━━━━━━━━━━┓ Constraint 1: (4w_1 + 8w_4 + 3w_5) * (6w_6 + 44w_3) = 0 - ┃ 03 00 00 00 ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━━┓ - ┃ 01 00 00 00 ┃ 01 04 ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━━┫ - ┃ 04 00 00 00 ┃ 01 08 ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━━┫ - ┃ 05 00 00 00 ┃ 01 03 ┃ - ┗━━━━━━━━━━━━━━┻━━━━━━━━━┛ - ┏━━━━━━━━━━━━━━┓ - ┃ 02 00 00 00 ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━━┓ - ┃ 03 00 00 00 ┃ 01 2C ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━━┫ - ┃ 06 00 00 00 ┃ 01 06 ┃ - ┗━━━━━━━━━━━━━━┻━━━━━━━━━┛ - ┏━━━━━━━━━━━━━━┓ - ┃ 00 00 00 00 ┃ - ┗━━━━━━━━━━━━━━┛ - - ┏━━━━━━━━━━━━━━┓ Constraint 2: (4w_6) * (6w_0 + 5w_3 + 11w_2) - (600w_6) = 0 - ┃ 01 00 00 00 ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━━┓ - ┃ 06 00 00 00 ┃ 01 04 ┃ - ┗━━━━━━━━━━━━━━┻━━━━━━━━━┛ - ┏━━━━━━━━━━━━━━┓ - ┃ 03 00 00 00 ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━━┓ - ┃ 00 00 00 00 ┃ 01 06 ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━━┫ - ┃ 02 00 00 00 ┃ 01 0B ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━━┫ - ┃ 03 00 00 00 ┃ 01 05 ┃ - ┗━━━━━━━━━━━━━━┻━━━━━━━━━┛ - ┏━━━━━━━━━━━━━━┓ - ┃ 01 00 00 00 ┃ - ┣━━━━━━━━━━━━━━╋━━━━━━━━━━━━━┓ - ┃ 06 00 00 00 ┃ 02 58 02 ┃ - ┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛ - - ┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓ - ┃ 03 00 00 00 ┃ 1c 00 00 00 ┃ Wire to Label Map - ┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛ - ┏━━━━━━━━━━━━━━┓ - ┃ 00 00 00 00 ┃ - ┣━━━━━━━━━━━━━━┫ - ┃ 03 00 00 00 ┃ - ┣━━━━━━━━━━━━━━┫ - ┃ 0a 00 00 00 ┃ - ┣━━━━━━━━━━━━━━┫ - ┃ 0b 00 00 00 ┃ - ┣━━━━━━━━━━━━━━┫ - ┃ 0c 00 00 00 ┃ - ┣━━━━━━━━━━━━━━┫ - ┃ 0f 00 00 00 ┃ - ┣━━━━━━━━━━━━━━┫ - ┃ 44 01 00 00 ┃ - ┗━━━━━━━━━━━━━━┛ + ┏━━━━━━━━━━┓ + ┃ 72316377 ┃ Magic + ┣━━━━━━━━━━┫ + ┃ 01000000 ┃ Version + ┣━━━━━━━━━━┫ + ┃ 03000000 ┃ nSections + ┗━━━━━━━━━━┛ + ┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ 01000000 ┃ 40000000 00000000 ┃ SectionType: Header + ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━┛ + ┏━━━━━━━━━━┓ + ┃ 20000000 ┃ Field Size + ┣━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430 ┃ + ┣━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + ┃ 07000000 ┃ # of wires + ┣━━━━━━━━━━┫ + ┃ 01000000 ┃ # Public Outs + ┣━━━━━━━━━━┫ + ┃ 02000000 ┃ # Public Ins + ┣━━━━━━━━━━┫ + ┃ 03000000 ┃ # Private Ins + ┣━━━━━━━━━━┻━━━━━━━━┓ + ┃ e8030000 00000000 ┃ # Labels + ┣━━━━━━━━━━┳━━━━━━━━┛ + ┃ 03000000 ┃ # Constraints + ┗━━━━━━━━━━┛ + ┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ 02000000 ┃ 88200000 00000000 ┃ SectionType: Constraints + ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━┛ + ┏━━━━━━━━━━┓ Constraint 0: (3w_5 + 8w_6) * (2w_0 + 20w_2 + 12w_3) - (5w_0 + 7w_2) = 0 + ┃ 02000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ 05000000 ┃ 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ + ┃ 06000000 ┃ 01000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + ┏━━━━━━━━━━┓ + ┃ 03000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ 00000000 ┃ 02000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ + ┃ 02000000 ┃ 01140000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ + ┃ 03000000 ┃ 0C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + ┏━━━━━━━━━━┓ + ┃ 02000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ 00000000 ┃ 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ + ┃ 02000000 ┃ 07000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + + ┏━━━━━━━━━━┓ Constraint 1: (4w_1 + 8w_4 + 3w_5) * (6w_6 + 44w_3) = 0 + ┃ 03000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ 01000000 ┃ 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ + ┃ 04000000 ┃ 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ + ┃ 05000000 ┃ 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + ┏━━━━━━━━━━┓ + ┃ 02000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ 03000000 ┃ 2C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ + ┃ 06000000 ┃ 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + ┏━━━━━━━━━━┓ + ┃ 00000000 ┃ + ┗━━━━━━━━━━┛ + + ┏━━━━━━━━━━┓ Constraint 2: (4w_6) * (6w_0 + 5w_3 + 11w_2) - (600w_6) = 0 + ┃ 01000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ 06000000 ┃ 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + ┏━━━━━━━━━━┓ + ┃ 03000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ 00000000 ┃ 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ + ┃ 02000000 ┃ 0B000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┫ + ┃ 03000000 ┃ 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + ┏━━━━━━━━━━┓ + ┃ 01000000 ┃ + ┣━━━━━━━━━━╋━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓ + ┃ 06000000 ┃ 58020000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 ┃ + ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ + + ┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓ + ┃ 03000000 ┃ 38000000 00000000 ┃ Wire to Label Map + ┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━┛ + ┏━━━━━━━━━━━━━━━━━━━┓ + ┃ 00000000 00000000 ┃ + ┣━━━━━━━━━━━━━━━━━━━┫ + ┃ 03000000 00000000 ┃ + ┣━━━━━━━━━━━━━━━━━━━┫ + ┃ 0a000000 00000000 ┃ + ┣━━━━━━━━━━━━━━━━━━━┫ + ┃ 0b000000 00000000 ┃ + ┣━━━━━━━━━━━━━━━━━━━┫ + ┃ 0c000000 00000000 ┃ + ┣━━━━━━━━━━━━━━━━━━━┫ + ┃ 0f000000 00000000 ┃ + ┣━━━━━━━━━━━━━━━━━━━┫ + ┃ 44010000 00000000 ┃ + ┗━━━━━━━━━━━━━━━━━━━┛ ```` And the binary representation in Hex: ```` -72 31 63 77 -01 00 00 00 -03 00 00 00 -01 00 00 00 49 00 00 00 -25 00 00 00 10 00 00 00 -20 010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430 -00 00 00 00 -04 00 00 00 -07 00 00 00 -01 00 00 00 -02 00 00 00 -03 00 00 00 -e8 03 00 00 -03 00 00 00 -02 00 00 00 8b 00 00 00 -02 00 00 00 -05 00 00 00 01 03 -06 00 00 00 01 08 -03 00 00 00 -00 00 00 00 01 02 -02 00 00 00 01 14 -03 00 00 00 01 0C -02 00 00 00 -00 00 00 00 01 05 -02 00 00 00 01 07 -03 00 00 00 -01 00 00 00 01 04 -04 00 00 00 01 08 -05 00 00 00 01 03 -02 00 00 00 -03 00 00 00 01 2C -06 00 00 00 01 06 -00 00 00 00 -01 00 00 00 -06 00 00 00 01 04 -03 00 00 00 -00 00 00 00 01 06 -02 00 00 00 01 0B -03 00 00 00 01 05 -01 00 00 00 -06 00 00 00 02 58 02 -03 00 00 00 1c 00 00 00 -00 00 00 00 -03 00 00 00 -0a 00 00 00 -0b 00 00 00 -0c 00 00 00 -0f 00 00 00 -44 01 00 00 +72316377 +01000000 +03000000 +01000000 40000000 00000000 +20000000 +010000f0 93f5e143 9170b979 48e83328 5d588181 b64550b8 29a031e1 724e6430 +07000000 +01000000 +02000000 +03000000 +e8030000 00000000 +03000000 +02000000 88200000 00000000 +02000000 +05000000 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +06000000 01000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +03000000 +00000000 02000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +02000000 01140000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +03000000 0C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +02000000 +00000000 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +02000000 07000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +03000000 +01000000 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +04000000 08000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +05000000 03000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +02000000 +03000000 2C000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +06000000 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +00000000 +01000000 +06000000 04000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +03000000 +00000000 06000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +02000000 0B000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +03000000 05000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +01000000 +06000000 58020000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 +03000000 38000000 00000000 +00000000 00000000 +03000000 00000000 +0a000000 00000000 +0b000000 00000000 +0c000000 00000000 +0f000000 00000000 +44010000 00000000 ```` diff --git a/doc/r1cs_bin_format.monopic b/doc/r1cs_bin_format.monopic deleted file mode 100644 index b49bf3a54878d46be8c89ade509bf6b5acb6d4b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28845 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 diff --git a/doc/r1cs_example.monopic b/doc/r1cs_example.monopic deleted file mode 100644 index e4aa83ba6c882927080c12ba4edc6362d9316de8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5950 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 VJ?yWMbkK9q+4= 1.5.x" } }, - "keccak": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/keccak/-/keccak-2.0.0.tgz", - "integrity": "sha512-rKe/lRr0KGhjoz97cwg+oeT1Rj/Y4cjae6glArioUC8JBF9ROGZctwIaaruM7d7naovME4Q8WcQSO908A8qcyQ==", - "dev": true, - "requires": { - "bindings": "^1.2.1", - "inherits": "^2.0.3", - "nan": "^2.2.1", - "safe-buffer": "^5.1.0" - } - }, - "lcid": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", - "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", - "requires": { - "invert-kv": "^2.0.0" - } - }, "levn": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", @@ -880,12 +950,11 @@ "dev": true }, "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "p-locate": "^4.1.0" } }, "lodash": { @@ -894,35 +963,10 @@ "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", "dev": true }, - "map-age-cleaner": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz", - "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==", - "requires": { - "p-defer": "^1.0.0" - } - }, - "mem": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", - "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==", - "requires": { - "map-age-cleaner": "^0.1.1", - "mimic-fn": "^2.0.0", - "p-is-promise": "^2.0.0" - }, - "dependencies": { - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" - } - } - }, "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, "minimatch": { @@ -934,43 +978,30 @@ } }, "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true }, "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", + "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", "dev": true, "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", - "dev": true - } + "minimist": "^1.2.5" } }, "ms": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", - "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", - "dev": true - }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, "natural-compare": { @@ -980,9 +1011,10 @@ "dev": true }, "nice-try": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.4.tgz", - "integrity": "sha512-2NpiFHqC87y/zFke0fC0spBXL3bBsoh/p5H1EFhshxjCR5+0g2d6BiXbUFz9v1sAcxsk2htp2eQnNIci2dIYcA==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true }, "nomnom": { "version": "1.5.2", @@ -994,19 +1026,6 @@ "underscore": "1.1.x" } }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "requires": { - "path-key": "^2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -1016,53 +1035,26 @@ } }, "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.0.tgz", + "integrity": "sha512-5NcSkPHhwTVFIQN+TUqXoS5+dlElHXdpAWu9I0HP20YOtIi+aZ0Ct82jdlILDxjLEAWwvm+qj1m6aEtsDVmm6Q==", "dev": true, "requires": { - "mimic-fn": "^1.0.0" - } - }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" + "mimic-fn": "^2.1.0" } }, "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "dev": true, "requires": { "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", + "fast-levenshtein": "~2.0.6", "levn": "~0.3.0", "prelude-ls": "~1.1.2", "type-check": "~0.3.2", - "wordwrap": "~1.0.0" - }, - "dependencies": { - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - } - } - }, - "os-locale": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz", - "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==", - "requires": { - "execa": "^1.0.0", - "lcid": "^2.0.0", - "mem": "^4.0.0" + "word-wrap": "~1.2.3" } }, "os-tmpdir": { @@ -1071,35 +1063,20 @@ "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", "dev": true }, - "p-defer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", - "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=" - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "p-is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz", - "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==" - }, "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", "requires": { "p-try": "^2.0.0" } }, "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "requires": { - "p-limit": "^2.0.0" + "p-limit": "^2.2.0" } }, "p-try": { @@ -1117,31 +1094,25 @@ } }, "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", - "dev": true - }, "path-key": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true }, "pathval": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.0.tgz", - "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=", - "dev": true + "integrity": "sha1-uULm1L3mUwBe9rcTYd74cn0GReA=" }, "prelude-ls": { "version": "1.1.2", @@ -1155,26 +1126,19 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, - "ramda": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.26.1.tgz", - "integrity": "sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==", - "dev": true + "r1csfile": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/r1csfile/-/r1csfile-0.0.2.tgz", + "integrity": "sha512-H1aR5NYRJ/RUrHWR/PNEivFEDkLV4R0+4SlKo2eq/fyiWxwgZNapOkjnJXsy5TZn40uFVrud0uOxGyVWgm9rDg==", + "requires": { + "big-integer": "^1.6.48" + } }, "regexpp": { "version": "2.0.1", @@ -1188,9 +1152,9 @@ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" }, "resolve-from": { "version": "4.0.0", @@ -1199,55 +1163,41 @@ "dev": true }, "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, "requires": { - "onetime": "^2.0.0", + "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "requires": { "glob": "^7.1.3" } }, - "rimraf-promise": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/rimraf-promise/-/rimraf-promise-2.0.0.tgz", - "integrity": "sha1-PdvkN4wa3slmvDZt37yYUUPHaVI=", - "requires": { - "rimraf": "^2.4.3" - } - }, "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.0.tgz", + "integrity": "sha512-xJTbh/d7Lm7SBhc1tNvTpeCHaEzoyxPrqNlvSdMfBTYwaY++UJFyXUOxAtsRUXjlqOfj8luNaR9vjCh4KeV+pg==", "dev": true, "requires": { "is-promise": "^2.1.0" } }, "rxjs": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.4.0.tgz", - "integrity": "sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw==", + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.4.tgz", + "integrity": "sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==", "dev": true, "requires": { "tslib": "^1.9.0" } }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -1255,9 +1205,10 @@ "dev": true }, "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true }, "set-blocking": { "version": "2.0.0", @@ -1268,6 +1219,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, "requires": { "shebang-regex": "^1.0.0" } @@ -1275,12 +1227,14 @@ "shebang-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true }, "signal-exit": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true }, "slice-ansi": { "version": "2.1.0", @@ -1291,20 +1245,38 @@ "ansi-styles": "^3.2.0", "astral-regex": "^1.0.0", "is-fullwidth-code-point": "^2.0.0" - } - }, - "snarkjs": { - "version": "0.1.14", - "resolved": "https://registry.npmjs.org/snarkjs/-/snarkjs-0.1.14.tgz", - "integrity": "sha512-mNsWx5K0ojz73689ZARwqyY62ENvW43movC+WMEHVYsFdcX9lpG+ZjiJGvnQh7LkYg2WY2lFzsXTUZI35TxqeA==", - "dev": true, - "requires": { - "big-integer": "^1.6.43", - "chai": "^4.2.0", - "escape-string-regexp": "^1.0.5", - "eslint": "^5.16.0", - "keccak": "^2.0.0", - "yargs": "^12.0.5" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + } } }, "source-map": { @@ -1324,38 +1296,27 @@ "dev": true }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "requires": { - "ansi-regex": "^3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - } + "ansi-regex": "^5.0.0" } }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" - }, "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.0.1.tgz", + "integrity": "sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw==", "dev": true }, "supports-color": { @@ -1368,13 +1329,13 @@ } }, "table": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/table/-/table-5.2.3.tgz", - "integrity": "sha512-N2RsDAMvDLvYwFcwbPyF3VmVSSkuF+G1e+8inhBLtHpvwXGw4QRPEZhihQNeEN0i1up6/f6ObCJXNdlRG3YVyQ==", + "version": "5.4.6", + "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", + "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", "dev": true, "requires": { - "ajv": "^6.9.1", - "lodash": "^4.17.11", + "ajv": "^6.10.2", + "lodash": "^4.17.14", "slice-ansi": "^2.1.0", "string-width": "^3.0.0" }, @@ -1385,6 +1346,18 @@ "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", "dev": true }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, "string-width": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", @@ -1420,12 +1393,11 @@ "dev": true }, "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.1.0.tgz", + "integrity": "sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw==", "requires": { - "os-tmpdir": "~1.0.2" + "rimraf": "^2.6.3" } }, "tmp-promise": { @@ -1434,22 +1406,12 @@ "integrity": "sha512-zl71nFWjPKW2KXs+73gEk8RmqvtAeXPxhWDkTUoa3MSMkjq3I+9OeknjF178MQoMYsdqL730hfzvNfEkePxq9Q==", "requires": { "tmp": "0.1.0" - }, - "dependencies": { - "tmp": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.1.0.tgz", - "integrity": "sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw==", - "requires": { - "rimraf": "^2.6.3" - } - } } }, "tslib": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", - "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==", "dev": true }, "type-check": { @@ -1464,7 +1426,12 @@ "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", "dev": true }, "underscore": { @@ -1482,18 +1449,25 @@ "punycode": "^2.1.0" } }, + "v8-compile-cache": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz", + "integrity": "sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g==", + "dev": true + }, "wasmbuilder": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/wasmbuilder/-/wasmbuilder-0.0.8.tgz", - "integrity": "sha512-d63cIsDmHnybA5hTlRRLadgys5r3Tl4W8SbcBRh13FauEPOo48dqjgzdL1xefpZkpKKybDRlFqgm+9cX04B3+w==", + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/wasmbuilder/-/wasmbuilder-0.0.9.tgz", + "integrity": "sha512-QJ550VwQvN6P4oW0d+/tCfo3i+1GBuuFX906r8QpDRryYXmXvdRZWJM0qkHgOfhg8G47SfgJVYNl3fyLfkxaPw==", "requires": { - "big-integer": "^1.6.43" + "big-integer": "^1.6.48" } }, "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, "requires": { "isexe": "^2.0.0" } @@ -1503,46 +1477,20 @@ "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true }, "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "^2.0.0" - } - } + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } }, "wrappy": { @@ -1565,28 +1513,27 @@ "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" }, "yargs": { - "version": "12.0.5", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz", - "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==", + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", + "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", "requires": { - "cliui": "^4.0.0", + "cliui": "^6.0.0", "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^1.0.1", - "os-locale": "^3.0.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", + "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", - "string-width": "^2.0.0", + "string-width": "^4.2.0", "which-module": "^2.0.0", - "y18n": "^3.2.1 || ^4.0.0", - "yargs-parser": "^11.1.1" + "y18n": "^4.0.0", + "yargs-parser": "^18.1.1" } }, "yargs-parser": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz", - "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==", + "version": "18.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.1.tgz", + "integrity": "sha512-KRHEsOM16IX7XuLnMOqImcPNbLVXMNHYAoFc3BKR8Ortl5gzDbtXvvEoGx9imk5E+X1VeNKNlcHr8B8vi+7ipA==", "requires": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" diff --git a/package.json b/package.json index 65df8bf..32b8914 100644 --- a/package.json +++ b/package.json @@ -30,20 +30,19 @@ }, "dependencies": { "big-integer": "^1.6.32", - "ejs": "^3.0.1", - "fflib": "0.0.2", + "chai": "^4.2.0", + "circom_runtime": "0.0.2", + "ffiasm": "0.0.2", + "ffjavascript": "0.0.3", + "ffwasm": "0.0.5", "fnv-plus": "^1.3.1", - "optimist": "^0.6.1", - "rimraf-promise": "^2.0.0", + "r1csfile": "0.0.2", "tmp-promise": "^2.0.2", - "wasmbuilder": "0.0.8", - "yargs": "^12.0.2" + "wasmbuilder": "0.0.9" }, "devDependencies": { - "chai": "^4.2.0", - "eslint": "^5.16.0", - "eslint-plugin-mocha": "^5.3.0", + "eslint": "^6.8.0", "jison": "^0.4.18", - "snarkjs": "0.1.14" + "yargs": "^15.3.1" } } diff --git a/ports/c/buildasm/add.asm.ejs b/ports/c/buildasm/add.asm.ejs deleted file mode 100644 index 70cfd73..0000000 --- a/ports/c/buildasm/add.asm.ejs +++ /dev/null @@ -1,245 +0,0 @@ -<% function addS1S2() { %> - xor rdx, rdx - mov edx, eax - add edx, ecx - jo add_manageOverflow ; rsi already is the 64bits result - - mov [rdi], rdx ; not necessary to adjust so just save and return - ret - -add_manageOverflow: ; Do the operation in 64 bits - push rsi - movsx rsi, eax - movsx rdx, ecx - add rsi, rdx - call rawCopyS2L - pop rsi - ret -<% } %> - - - -<% function addL1S2() { %> - add rsi, 8 - movsx rdx, ecx - add rdi, 8 - cmp rdx, 0 - <% const rawAddLabel = global.tmpLabel() %> - jns <%= rawAddLabel %> - neg rdx - call rawSubLS - sub rdi, 8 - sub rsi, 8 - ret -<%= rawAddLabel %>: - call rawAddLS - sub rdi, 8 - sub rsi, 8 - ret - -<% } %> - -<% function addS1L2() { %> - lea rsi, [rdx + 8] - movsx rdx, eax - add rdi, 8 - cmp rdx, 0 - <% const rawAddLabel = global.tmpLabel() %> - jns <%= rawAddLabel %> - neg rdx - call rawSubLS - sub rdi, 8 - sub rsi, 8 - ret -<%= rawAddLabel %>: - call rawAddLS - sub rdi, 8 - sub rsi, 8 - ret -<% } %> - -<% function addL1L2() { %> - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawAddLL - sub rdi, 8 - sub rsi, 8 - ret -<% } %> - -;;;;;;;;;;;;;;;;;;;;;; -; add -;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result -; Modified Registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_add: - mov rax, [rsi] - mov rcx, [rdx] - bt rax, 63 ; Check if is short first operand - jc add_l1 - bt rcx, 63 ; Check if is short second operand - jc add_s1l2 - -add_s1s2: ; Both operands are short -<%= addS1S2() %> -add_l1: - bt rcx, 63 ; Check if is short second operand - jc add_l1l2 - -;;;;;;;; -add_l1s2: - bt rax, 62 ; check if montgomery first - jc add_l1ms2 -add_l1ns2: -<%= global.setTypeDest("0x80"); %> -<%= addL1S2(); %> - -add_l1ms2: - bt rcx, 62 ; check if montgomery second - jc add_l1ms2m -add_l1ms2n: -<%= global.setTypeDest("0xC0"); %> -<%= global.toMont_b() %> -<%= addL1L2() %> - -add_l1ms2m: -<%= global.setTypeDest("0xC0"); %> -<%= addL1L2() %> - - -;;;;;;;; -add_s1l2: - bt rcx, 62 ; check if montgomery second - jc add_s1l2m -add_s1l2n: -<%= global.setTypeDest("0x80"); %> -<%= addS1L2(); %> - -add_s1l2m: - bt rax, 62 ; check if montgomery first - jc add_s1ml2m -add_s1nl2m: -<%= global.setTypeDest("0xC0"); %> -<%= global.toMont_a() %> -<%= addL1L2() %> - -add_s1ml2m: -<%= global.setTypeDest("0xC0"); %> -<%= addL1L2() %> - -;;;; -add_l1l2: - bt rax, 62 ; check if montgomery first - jc add_l1ml2 -add_l1nl2: - bt rcx, 62 ; check if montgomery second - jc add_l1nl2m -add_l1nl2n: -<%= global.setTypeDest("0x80"); %> -<%= addL1L2() %> - -add_l1nl2m: -<%= global.setTypeDest("0xC0"); %> -<%= global.toMont_a(); %> -<%= addL1L2() %> - -add_l1ml2: - bt rcx, 62 ; check if montgomery seconf - jc add_l1ml2m -add_l1ml2n: -<%= global.setTypeDest("0xC0"); %> -<%= global.toMont_b(); %> -<%= addL1L2() %> - -add_l1ml2m: -<%= global.setTypeDest("0xC0"); %> -<%= addL1L2() %> - - - -;;;;;;;;;;;;;;;;;;;;;; -; rawAddLL -;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of type long -; Params: -; rsi <= Pointer to the long data of element 1 -; rdx <= Pointer to the long data of element 2 -; rdi <= Pointer to the long data of result -; Modified Registers: -; rax -;;;;;;;;;;;;;;;;;;;;;; -rawAddLL: - ; Add component by component with carry -<% for (let i=0; i - mov rax, [rsi + <%=i*8%>] - <%= i==0 ? "add" : "adc" %> rax, [rdx + <%=i*8%>] - mov [rdi + <%=i*8%>], rax -<% } %> - jc rawAddLL_sq ; if overflow, substract q - - ; Compare with q -<% for (let i=0; i -<% if (i>0) { %> - mov rax, [rdi + <%= (n64-i-1)*8 %>] -<% } %> - cmp rax, [q + <%= (n64-i-1)*8 %>] - jc rawAddLL_done ; q is bigget so done. - jnz rawAddLL_sq ; q is lower -<% } %> - ; If equal substract q -rawAddLL_sq: -<% for (let i=0; i - mov rax, [q + <%=i*8%>] - <%= i==0 ? "sub" : "sbb" %> [rdi + <%=i*8%>], rax -<% } %> -rawAddLL_done: - ret - - -;;;;;;;;;;;;;;;;;;;;;; -; rawAddLS -;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of type long -; Params: -; rdi <= Pointer to the long data of result -; rsi <= Pointer to the long data of element 1 -; rdx <= Value to be added -;;;;;;;;;;;;;;;;;;;;;; -rawAddLS: - ; Add component by component with carry - - add rdx, [rsi] - mov [rdi] ,rdx -<% for (let i=1; i - mov rdx, 0 - adc rdx, [rsi + <%=i*8%>] - mov [rdi + <%=i*8%>], rdx -<% } %> - jc rawAddLS_sq ; if overflow, substract q - - ; Compare with q -<% for (let i=0; i - mov rax, [rdi + <%= (n64-i-1)*8 %>] - cmp rax, [q + <%= (n64-i-1)*8 %>] - jc rawAddLS_done ; q is bigget so done. - jnz rawAddLS_sq ; q is lower -<% } %> - ; If equal substract q -rawAddLS_sq: -<% for (let i=0; i - mov rax, [q + <%=i*8%>] - <%= i==0 ? "sub" : "sbb" %> [rdi + <%=i*8%>], rax -<% } %> -rawAddLS_done: - ret - - - - diff --git a/ports/c/buildasm/binops.asm.ejs b/ports/c/buildasm/binops.asm.ejs deleted file mode 100644 index 4001893..0000000 --- a/ports/c/buildasm/binops.asm.ejs +++ /dev/null @@ -1,240 +0,0 @@ -<% function binOpSubQIfBigger() { %> - <% const subQ = global.tmpLabel() %> - <% const done = global.tmpLabel() %> - - ; Compare with q -<% for (let i=0; i - mov rax, [rdi + <%= (n64-i)*8 %>] - cmp rax, [q + <%= (n64-i-1)*8 %>] - jc <%=done%> ; q is bigget so done. - jnz <%=subQ%> ; q is lower -<% } %> - ; If equal substract q -<%=subQ%>: -<% for (let i=0; i - mov rax, [q + <%=i*8%>] - <%= i==0 ? "sub" : "sbb" %> [rdi + <%=i*8 + 8 %>], rax -<% } %> -<%=done%>: -<% } %> - - -<% function binOpS1S2(op) { %> - cmp r8d, 0 - <% const s1s2_solveNeg = global.tmpLabel() %> - js <%=s1s2_solveNeg%> - - cmp r9d, 0 - js <%=s1s2_solveNeg%> - xor rdx, rdx ; both ops are positive so do the op and return - mov edx, r8d - <%=op%> edx, r9d - mov [rdi], rdx ; not necessary to adjust so just save and return - ret - -<%=s1s2_solveNeg%>: -<%= global.setTypeDest("0x80"); %> -<%= global.toLong_b() %> -<%= global.toLong_a() %> -<%= binOpL1L2(op) %> - - -<% } %> - -<% function binOpS1L2(op) { %> - cmp r8d, 0 - <% const s1l2_solveNeg = global.tmpLabel() %> - js <%=s1l2_solveNeg%> - movsx rax, r8d - <%=op%> rax, [rdx +8] - mov [rdi+8], rax -<% for (let i=1; i - xor rax, rax - <%=op%> rax, [rdx + <%= (i*8)+8 %>] -<% if (i== n64-1) { %> - and rax, [lboMask] -<% } %> - mov [rdi + <%= (i*8)+8 %> ], rax -<% } %> -<% binOpSubQIfBigger() %> - ret - -<%=s1l2_solveNeg%>: -<%= global.toLong_a() %> -<%= global.setTypeDest("0x80"); %> -<%= binOpL1L2(op) %> - -<% } %> - -<% function binOpL1S2(op) { %> - cmp r9d, 0 - <% const l1s2_solveNeg = global.tmpLabel() %> - js <%=l1s2_solveNeg%> - movsx rax, r9d - <%=op%> rax, [rsi +8] - mov [rdi+8], rax -<% for (let i=1; i - xor rax, rax - <%=op%> rax, [rsi + <%= (i*8)+8 %>]; -<% if (i== n64-1) { %> - and rax, [lboMask] ; -<% } %> - mov [rdi + <%= (i*8)+8 %> ], rax; -<% } %> -<% binOpSubQIfBigger() %> - ret - -<%=l1s2_solveNeg%>: -<%= global.toLong_b() %> -<%= global.setTypeDest("0x80"); %> -<%= binOpL1L2(op) %> - -<% } %> - -<% function binOpL1L2(op) { %> -<% for (let i=0; i - mov rax, [rsi + <%= (i*8)+8 %>] - <%=op%> rax, [rdx + <%= (i*8)+8 %>] -<% if (i== n64-1) { %> - and rax, [lboMask] -<% } %> - mov [rdi + <%= (i*8)+8 %> ], rax -<% } %> -<% binOpSubQIfBigger() %> - ret -<% } %> - - -<% function binOp(op) { %> -;;;;;;;;;;;;;;;;;;;;;; -; b<%= op %> -;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result -; Modified Registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_b<%=op%>: - mov r8, [rsi] - mov r9, [rdx] - bt r8, 63 ; Check if is short first operand - jc <%=op%>_l1 - bt r9, 63 ; Check if is short second operand - jc <%=op%>_s1l2 - -<%=op%>_s1s2: -<%= binOpS1S2(op) %> - - -<%=op%>_l1: - bt r9, 63 ; Check if is short second operand - jc <%=op%>_l1l2 - - -<%=op%>_l1s2: - bt r8, 62 ; check if montgomery first - jc <%=op%>_l1ms2 -<%=op%>_l1ns2: -<%= global.setTypeDest("0x80"); %> -<%= binOpL1S2(op) %> - -<%=op%>_l1ms2: -<%= global.setTypeDest("0x80"); %> - push r9 ; r9 is used in montgomery so we need to save it -<%= global.fromMont_a() %> - pop r9 -<%= binOpL1S2(op) %> - - -<%=op%>_s1l2: - bt r9, 62 ; check if montgomery first - jc <%=op%>_s1l2m -<%=op%>_s1l2n: -<%= global.setTypeDest("0x80"); %> -<%= binOpS1L2(op) %> - -<%=op%>_s1l2m: -<%= global.setTypeDest("0x80"); %> - push r8 ; r8 is used in montgomery so we need to save it -<%= global.fromMont_b() %> - pop r8 -<%= binOpS1L2(op) %> - - -<%=op%>_l1l2: - bt r8, 62 ; check if montgomery first - jc <%=op%>_l1ml2 - bt r9, 62 ; check if montgomery first - jc <%=op%>_l1nl2m -<%=op%>_l1nl2n: -<%= global.setTypeDest("0x80"); %> -<%= binOpL1L2(op) %> - -<%=op%>_l1nl2m: -<%= global.setTypeDest("0x80"); %> -<%= global.fromMont_b() %> -<%= binOpL1L2(op) %> - -<%=op%>_l1ml2: - bt r9, 62 ; check if montgomery first - jc <%=op%>_l1ml2m -<%=op%>_l1ml2n: -<%= global.setTypeDest("0x80"); %> -<%= global.fromMont_a() %> -<%= binOpL1L2(op) %> - -<%=op%>_l1ml2m: -<%= global.setTypeDest("0x80"); %> -<%= global.fromMont_a() %> -<%= global.fromMont_b() %> -<%= binOpL1L2(op) %> -<% } %> - -<%= binOp("and") %> -<%= binOp("or") %> -<%= binOp("xor") %> - - -;;;;;;;;;;;;;;;;;;;;;; -; bnot -;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdi <= Pointer to result -; Modified Registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_bnot: - <%= global.setTypeDest("0x80"); %> - - mov r8, [rsi] - bt r8, 63 ; Check if is long operand - jc bnot_l1 -bnot_s: - <%= global.toLong_a() %> - jmp bnot_l1n - -bnot_l1: - bt r8, 62 ; check if montgomery first - jnc bnot_l1n - -bnot_l1m: -<%= global.fromMont_a() %> - -bnot_l1n: -<% for (let i=0; i - mov rax, [rsi + <%= i*8 + 8 %>] - not rax -<% if (i== n64-1) { %> - and rax, [lboMask] -<% } %> - mov [rdi + <%= i*8 + 8 %>], rax -<% } %> -<% binOpSubQIfBigger() %> - ret - - diff --git a/ports/c/buildasm/buildzqfield.js b/ports/c/buildasm/buildzqfield.js deleted file mode 100644 index e223bac..0000000 --- a/ports/c/buildasm/buildzqfield.js +++ /dev/null @@ -1,72 +0,0 @@ -const bigInt=require("big-integer"); -const path = require("path"); -const util = require("util"); -const renderFile = util.promisify(require("ejs").renderFile); - -const runningAsScript = !module.parent; - - -class ZqBuilder { - constructor(q, name) { - const self = this; - this.q=bigInt(q); - this.n64 = Math.floor((this.q.bitLength() - 1) / 64)+1; - this.name = name; - this.bigInt = bigInt; - this.lastTmp=0; - this.global = {}; - this.global.tmpLabel = function(label) { - self.lastTmp++; - label = label || "tmp"; - return label+"_"+self.lastTmp; - }; - } - - constantElement(v) { - let S = ""; - const mask = bigInt("FFFFFFFFFFFFFFFF", 16); - for (let i=0; i0) S = S+","; - let shex = v.shiftRight(i*64).and(mask).toString(16); - while (shex.length <16) shex = "0" + shex; - S = S + "0x" + shex; - } - return S; - } - -} - -async function buildField(q, name) { - const builder = new ZqBuilder(q, name); - - const asm = await renderFile(path.join(__dirname, "fr.asm.ejs"), builder); - const c = await renderFile(path.join(__dirname, "fr.c.ejs"), builder); - const h = await renderFile(path.join(__dirname, "fr.h.ejs"), builder); - - return {asm: asm, h: h, c: c}; -} - -if (runningAsScript) { - const fs = require("fs"); - var argv = require("yargs") - .usage("Usage: $0 -q [primeNum] -n [name] -oc [out .c file] -oh [out .h file]") - .demandOption(["q","n"]) - .alias("q", "prime") - .alias("n", "name") - .argv; - - const q = bigInt(argv.q); - - const asmFileName = (argv.oc) ? argv.oc : argv.name.toLowerCase() + ".asm"; - const hFileName = (argv.oc) ? argv.oc : argv.name.toLowerCase() + ".h"; - const cFileName = (argv.oc) ? argv.oc : argv.name.toLowerCase() + ".c"; - - buildField(q, argv.name).then( (res) => { - fs.writeFileSync(asmFileName, res.asm, "utf8"); - fs.writeFileSync(hFileName, res.h, "utf8"); - fs.writeFileSync(cFileName, res.c, "utf8"); - }); - -} else { - module.exports = buildField; -} diff --git a/ports/c/buildasm/buildzqfieldtester.js b/ports/c/buildasm/buildzqfieldtester.js deleted file mode 100644 index eff7d2a..0000000 --- a/ports/c/buildasm/buildzqfieldtester.js +++ /dev/null @@ -1,75 +0,0 @@ -const chai = require("chai"); -const assert = chai.assert; - -const fs = require("fs"); -var tmp = require("tmp-promise"); -const path = require("path"); -const util = require("util"); -const exec = util.promisify(require("child_process").exec); - -const BuildZqField = require("./buildzqfield"); - -module.exports = testField; - -async function testField(prime, test) { - tmp.setGracefulCleanup(); - - const dir = await tmp.dir({prefix: "circom_", unsafeCleanup: true }); - - const source = await BuildZqField(prime, "Fr"); - - // console.log(dir.path); - - await fs.promises.writeFile(path.join(dir.path, "fr.asm"), source.asm, "utf8"); - await fs.promises.writeFile(path.join(dir.path, "fr.h"), source.h, "utf8"); - await fs.promises.writeFile(path.join(dir.path, "fr.c"), source.c, "utf8"); - - await exec(`cp ${path.join(__dirname, "tester.cpp")} ${dir.path}`); - - await exec("nasm -fmacho64 --prefix _ " + - ` ${path.join(dir.path, "fr.asm")}` - ); - - await exec("g++" + - ` ${path.join(dir.path, "tester.cpp")}` + - ` ${path.join(dir.path, "fr.o")}` + - ` ${path.join(dir.path, "fr.c")}` + - ` -o ${path.join(dir.path, "tester")}` + - " -lgmp -g" - ); - - const inLines = []; - for (let i=0; i${path.join(dir.path, "out.tst")}`); - - const res = await fs.promises.readFile(path.join(dir.path, "out.tst"), "utf8"); - const resLines = res.split("\n"); - - for (let i=0; i -<% for (let i=n64-1; i>=0; i--) { %> - mov rax, [<%=reg%> + <%= 8+(i*8) %>] - cmp [half + <%= (i*8) %>], rax ; comare with (q-1)/2 - jc <%=label_neg%> ; half e1-e2 is neg => e1 < e2 -<% if (i>0) { %> - jnz <%=label_pos%> ; half>rax => e1 -e2 is pos => e1 > e2 -<% } else { %> - jmp <%=label_pos%> -<% } %> -<% } %> -<% } %> - - -;;;;;;;;;;;;;;;;;;;;;; -; rgt - Raw Greater Than -;;;;;;;;;;;;;;;;;;;;;; -; returns in ax 1 id *rsi > *rdx -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rax <= Return 1 or 0 -; Modified Registers: -; r8, r9, rax -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_rgt: - mov r8, [rsi] - mov r9, [rdx] - bt r8, 63 ; Check if is short first operand - jc rgt_l1 - bt r9, 63 ; Check if is short second operand - jc rgt_s1l2 - -rgt_s1s2: ; Both operands are short - cmp r8d, r9d - jg rgt_ret1 - jmp rgt_ret0 - - -rgt_l1: - bt r9, 63 ; Check if is short second operand - jc rgt_l1l2 - -;;;;;;;; -rgt_l1s2: - bt r8, 62 ; check if montgomery first - jc rgt_l1ms2 -rgt_l1ns2: -<%= global.toLong_b() %> - jmp rgtL1L2 - -rgt_l1ms2: -<%= global.toLong_b() %> -<%= global.fromMont_a() %> - jmp rgtL1L2 - - -;;;;;;;; -rgt_s1l2: - bt r9, 62 ; check if montgomery second - jc rgt_s1l2m -rgt_s1l2n: -<%= global.toLong_a() %> - jmp rgtL1L2 - -rgt_s1l2m: -<%= global.toLong_a() %> -<%= global.fromMont_b() %> - jmp rgtL1L2 - -;;;; -rgt_l1l2: - bt r8, 62 ; check if montgomery first - jc rgt_l1ml2 -rgt_l1nl2: - bt r9, 62 ; check if montgomery second - jc rgt_l1nl2m -rgt_l1nl2n: - jmp rgtL1L2 - -rgt_l1nl2m: -<%= global.fromMont_b() %> - jmp rgtL1L2 - -rgt_l1ml2: - bt r9, 62 ; check if montgomery second - jc rgt_l1ml2m -rgt_l1ml2n: -<%= global.fromMont_a() %> - jmp rgtL1L2 - -rgt_l1ml2m: -<%= global.fromMont_a() %> -<%= global.fromMont_b() %> - jmp rgtL1L2 - - -;;;;;; -; rgtL1L2 -;;;;;; - -rgtL1L2: -<%= signL("rsi", "rgtl1l2_p1", "rgtl1l2_n1") %> -rgtl1l2_p1: -<%= signL("rdx", "rgtRawL1L2", "rgt_ret1") %> - -rgtl1l2_n1: -<%= signL("rdx", "rgt_ret0", "rgtRawL1L2") %> - - -rgtRawL1L2: -<% for (let i=n64-1; i>=0; i--) { %> - mov rax, [rsi + <%= 8+(i*8) %>] - cmp [rdx + <%= 8+(i*8) %>], rax ; comare with (q-1)/2 - jc rgt_ret1 ; rsi 1st > 2nd -<% if (i>0) { %> - jnz rgt_ret0 -<% } %> -<% } %> - -rgt_ret0: - xor rax, rax - ret -rgt_ret1: - mov rax, 1 - ret - - - -;;;;;;;;;;;;;;;;;;;;;; -; rlt - Raw Less Than -;;;;;;;;;;;;;;;;;;;;;; -; returns in ax 1 id *rsi > *rdx -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rax <= Return 1 or 0 -; Modified Registers: -; r8, r9, rax -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_rlt: - mov r8, [rsi] - mov r9, [rdx] - bt r8, 63 ; Check if is short first operand - jc rlt_l1 - bt r9, 63 ; Check if is short second operand - jc rlt_s1l2 - -rlt_s1s2: ; Both operands are short - cmp r8d, r9d - jl rlt_ret1 - jmp rlt_ret0 - - -rlt_l1: - bt r9, 63 ; Check if is short second operand - jc rlt_l1l2 - -;;;;;;;; -rlt_l1s2: - bt r8, 62 ; check if montgomery first - jc rlt_l1ms2 -rlt_l1ns2: -<%= global.toLong_b() %> - jmp rltL1L2 - -rlt_l1ms2: -<%= global.toLong_b() %> -<%= global.fromMont_a() %> - jmp rltL1L2 - - -;;;;;;;; -rlt_s1l2: - bt r9, 62 ; check if montgomery second - jc rlt_s1l2m -rlt_s1l2n: -<%= global.toLong_a() %> - jmp rltL1L2 - -rlt_s1l2m: -<%= global.toLong_a() %> -<%= global.fromMont_b() %> - jmp rltL1L2 - -;;;; -rlt_l1l2: - bt r8, 62 ; check if montgomery first - jc rlt_l1ml2 -rlt_l1nl2: - bt r9, 62 ; check if montgomery second - jc rlt_l1nl2m -rlt_l1nl2n: - jmp rltL1L2 - -rlt_l1nl2m: -<%= global.fromMont_b() %> - jmp rltL1L2 - -rlt_l1ml2: - bt r9, 62 ; check if montgomery second - jc rlt_l1ml2m -rlt_l1ml2n: -<%= global.fromMont_a() %> - jmp rltL1L2 - -rlt_l1ml2m: -<%= global.fromMont_a() %> -<%= global.fromMont_b() %> - jmp rltL1L2 - - -;;;;;; -; rltL1L2 -;;;;;; - -rltL1L2: -<%= signL("rsi", "rltl1l2_p1", "rltl1l2_n1") %> -rltl1l2_p1: -<%= signL("rdx", "rltRawL1L2", "rlt_ret0") %> - -rltl1l2_n1: -<%= signL("rdx", "rlt_ret1", "rltRawL1L2") %> - - -rltRawL1L2: -<% for (let i=n64-1; i>=0; i--) { %> - mov rax, [rsi + <%= 8+(i*8) %>] - cmp [rdx + <%= 8+(i*8) %>], rax ; comare with (q-1)/2 - jc rlt_ret0 ; rsi 1st > 2nd - jnz rlt_ret1 -<% } %> - -rlt_ret0: - xor rax, rax - ret -rlt_ret1: - mov rax, 1 - ret - - - -;;;;;;;;;;;;;;;;;;;;;; -; req - Raw Eq -;;;;;;;;;;;;;;;;;;;;;; -; returns in ax 1 id *rsi == *rdx -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rax <= Return 1 or 0 -; Modified Registers: -; r8, r9, rax -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_req: - mov r8, [rsi] - mov r9, [rdx] - bt r8, 63 ; Check if is short first operand - jc req_l1 - bt r9, 63 ; Check if is short second operand - jc req_s1l2 - -req_s1s2: ; Both operands are short - cmp r8d, r9d - je req_ret1 - jmp req_ret0 - - -req_l1: - bt r9, 63 ; Check if is short second operand - jc req_l1l2 - -;;;;;;;; -req_l1s2: - bt r8, 62 ; check if montgomery first - jc req_l1ms2 -req_l1ns2: -<%= global.toLong_b() %> - jmp reqL1L2 - -req_l1ms2: -<%= global.toMont_b() %> - jmp reqL1L2 - - -;;;;;;;; -req_s1l2: - bt r9, 62 ; check if montgomery second - jc req_s1l2m -req_s1l2n: -<%= global.toLong_a() %> - jmp reqL1L2 - -req_s1l2m: -<%= global.toMont_a() %> - jmp reqL1L2 - -;;;; -req_l1l2: - bt r8, 62 ; check if montgomery first - jc req_l1ml2 -req_l1nl2: - bt r9, 62 ; check if montgomery second - jc req_l1nl2m -req_l1nl2n: - jmp reqL1L2 - -req_l1nl2m: -<%= global.toMont_a() %> - jmp reqL1L2 - -req_l1ml2: - bt r9, 62 ; check if montgomery second - jc req_l1ml2m -req_l1ml2n: -<%= global.toMont_b() %> - jmp reqL1L2 - -req_l1ml2m: - jmp reqL1L2 - - -;;;;;; -; eqL1L2 -;;;;;; - -reqL1L2: -<% for (let i=0; i - mov rax, [rsi + <%= 8+(i*8) %>] - cmp [rdx + <%= 8+(i*8) %>], rax - jne req_ret0 ; rsi 1st > 2nd -<% } %> - -req_ret1: - mov rax, 1 - ret - -req_ret0: - xor rax, rax - ret - - -;;;;;;;;;;;;;;;;;;;;;; -; gt -;;;;;;;;;;;;;;;;;;;;;; -; Compares two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result can be zero or one. -; Modified Registers: -; rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_gt: - call <%=name%>_rgt - mov [rdi], rax - ret - -;;;;;;;;;;;;;;;;;;;;;; -; lt -;;;;;;;;;;;;;;;;;;;;;; -; Compares two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result can be zero or one. -; Modified Registers: -; rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_lt: - call <%=name%>_rlt - mov [rdi], rax - ret - -;;;;;;;;;;;;;;;;;;;;;; -; eq -;;;;;;;;;;;;;;;;;;;;;; -; Compares two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result can be zero or one. -; Modified Registers: -; rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_eq: - call <%=name%>_req - mov [rdi], rax - ret - -;;;;;;;;;;;;;;;;;;;;;; -; neq -;;;;;;;;;;;;;;;;;;;;;; -; Compares two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result can be zero or one. -; Modified Registers: -; rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_neq: - call <%=name%>_req - xor rax, 1 - mov [rdi], rax - ret - -;;;;;;;;;;;;;;;;;;;;;; -; geq -;;;;;;;;;;;;;;;;;;;;;; -; Compares two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result can be zero or one. -; Modified Registers: -; rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_geq: - call <%=name%>_rlt - xor rax, 1 - mov [rdi], rax - ret - -;;;;;;;;;;;;;;;;;;;;;; -; leq -;;;;;;;;;;;;;;;;;;;;;; -; Compares two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result can be zero or one. -; Modified Registers: -; rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_leq: - call <%=name%>_rgt - xor rax, 1 - mov [rdi], rax - ret diff --git a/ports/c/buildasm/cmpops_old.asm.ejs b/ports/c/buildasm/cmpops_old.asm.ejs deleted file mode 100644 index 420bdce..0000000 --- a/ports/c/buildasm/cmpops_old.asm.ejs +++ /dev/null @@ -1,108 +0,0 @@ - -<% function retOne() { %> - mov qword [rdi], 1 - add rsp, <%= (n64+1)*8 %> - ret -<% } %> - -<% function retZero() { %> - mov qword [rdi], 0 - add rsp, <%= (n64+1)*8 %> - ret -<% } %> - -<% function cmpLong(op, eq) { %> - -<% - if (eq==true) { - if (["leq","geq"].indexOf(op) >= 0) retOne(); - if (["lt","gt"].indexOf(op) >= 0) retZero(); - } -%> - - -<% const label_gt = global.tmpLabel() %> -<% const label_lt = global.tmpLabel() %> -<% for (let i=n64-1; i>=0; i--) { %> - mov rax, [rsp + <%= 8+(i*8) %>] - cmp [half + <%= (i*8) %>], rax ; comare with (q-1)/2 - jc <%=label_lt%> ; half e1-e2 is neg => e1 < e2 - jnz <%=label_gt%> ; half>rax => e1 -e2 is pos => e1 > e2 -<% } %> - ; half == rax => e1-e2 is pos => e1 > e2 -<%=label_gt%>: -<% if (["geq","gt"].indexOf(op) >= 0) retOne(); else retZero(); %> -<%=label_lt%>: -<% if (["leq","lt"].indexOf(op) >= 0) retOne(); else retZero(); %> -<% } // cmpLong%> - -<% function cmpOp(op) { %> -;;;;;;;;;;;;;;;;;;;;;; -; <%= op %> -;;;;;;;;;;;;;;;;;;;;;; -; Compares two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result can be zero or one. -; Modified Registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_<%=op%>: - sub rsp, <%= (n64+1)*8 %> ; Save space for the result of the substraction - push rdi ; Save rdi - lea rdi, [rsp+8] ; We pushed rdi so we need to add 8 - call <%=name%>_sub ; Do a substraction - call <%=name%>_toNormal ; Convert it to normal - pop rdi - - mov rax, [rsp] ; We already poped do no need to add 8 - bt rax, 63 ; check is result is long - jc <%=op%>_longCmp - -<%=op%>_shortCmp: - cmp eax, 0 - je <%=op%>_s_eq - js <%=op%>_s_lt -<%=op%>_s_gt: -<% if (["geq","gt", "neq"].indexOf(op) >= 0) retOne(); else retZero(); %> -<%=op%>_s_lt: -<% if (["leq","lt", "neq"].indexOf(op) >= 0) retOne(); else retZero(); %> -<%=op%>_s_eq: -<% if (["eq","geq", "leq"].indexOf(op) >= 0) retOne(); else retZero(); %> - -<%=op%>_longCmp: - -<% for (let i=n64-1; i>=0; i--) { %> - cmp qword [rsp + <%= 8+(i*8) %>], 0 - jnz <%=op%>_neq -<% } %> -<%=op%>_eq: -<% if (op == "eq") { - retOne(); - } else if (op == "neq") { - retZero(); - } else { - cmpLong(op, true); - } -%> -<%=op%>_neq: -<% if (op == "neq") { - retOne(); - } else if (op == "eq") { - retZero(); - } else { - cmpLong(op, false); - } -%> - - -<% } %> - -<%= cmpOp("eq") %> -<%= cmpOp("neq") %> -<%= cmpOp("lt") %> -<%= cmpOp("gt") %> -<%= cmpOp("leq") %> -<%= cmpOp("geq") %> - diff --git a/ports/c/buildasm/copy.asm.ejs b/ports/c/buildasm/copy.asm.ejs deleted file mode 100644 index a9623ed..0000000 --- a/ports/c/buildasm/copy.asm.ejs +++ /dev/null @@ -1,139 +0,0 @@ -;;;;;;;;;;;;;;;;;;;;;; -; copy -;;;;;;;;;;;;;;;;;;;;;; -; Copies -; Params: -; rsi <= the src -; rdi <= the dest -; -; Nidified registers: -; rax -;;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_copy: -<% for (let i=0; i<=n64; i++) { %> - mov rax, [rsi + <%= i*8 %>] - mov [rdi + <%= i*8 %>], rax -<% } %> - ret - -;;;;;;;;;;;;;;;;;;;;;; -; copy an array of integers -;;;;;;;;;;;;;;;;;;;;;; -; Copies -; Params: -; rsi <= the src -; rdi <= the dest -; rdx <= number of integers to copy -; -; Nidified registers: -; rax -;;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_copyn: -<%=name%>_copyn_loop: - mov r8, rsi - mov r9, rdi - mov rax, <%= n64+1 %> - mul rdx - mov rcx, rax - cld - rep movsq - mov rsi, r8 - mov rdi, r9 - ret - -;;;;;;;;;;;;;;;;;;;;;; -; rawCopyS2L -;;;;;;;;;;;;;;;;;;;;;; -; Convert a 64 bit integer to a long format field element -; Params: -; rsi <= the integer -; rdi <= Pointer to the overwritted element -; -; Nidified registers: -; rax -;;;;;;;;;;;;;;;;;;;;;;; - -rawCopyS2L: - mov al, 0x80 - shl rax, 56 - mov [rdi], rax ; set the result to LONG normal - - cmp rsi, 0 - js u64toLong_adjust_neg - - mov [rdi + 8], rsi - xor rax, rax -<% for (let i=1; i - mov [rdi + <%= 8+i*8 %>], rax -<% } %> - ret - -u64toLong_adjust_neg: - add rsi, [q] ; Set the first digit - mov [rdi + 8], rsi ; - - mov rsi, -1 ; all ones -<% for (let i=1; i - mov rax, rsi ; Add to q - adc rax, [q + <%= i*8 %> ] - mov [rdi + <%= (i+1)*8 %>], rax -<% } %> - ret - -;;;;;;;;;;;;;;;;;;;;;; -; toInt -;;;;;;;;;;;;;;;;;;;;;; -; Convert a 64 bit integer to a long format field element -; Params: -; rsi <= Pointer to the element -; Returs: -; rax <= The value -;;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_toInt: - mov rax, [rdi] - bt rax, 63 - jc <%=name%>_long - movsx rax, eax - ret - -<%=name%>_long: - bt rax, 62 - jnc <%=name%>_longNormal -<%=name%>_longMontgomery: - call <%=name%>_toLongNormal - -<%=name%>_longNormal: - mov rax, [rdi + 8] - mov rcx, rax - shr rcx, 31 - jnz <%=name%>_longNeg -<% for (let i=1; i< n64; i++) { %> - mov rcx, [rdi + <%= i*8+8 %>] - test rcx, rcx - jnz <%=name%>_longNeg -<% } %> - ret - -<%=name%>_longNeg: - mov rax, [rdi + 8] - sub rax, [q] - jnc <%=name%>_longErr -<% for (let i=1; i - mov rcx, [rdi + <%= i*8+8 %>] - sbb rcx, [q + <%= i*8 %>] - jnc <%=name%>_longErr -<% } %> - mov rcx, rax - sar rcx, 31 - add rcx, 1 - jnz <%=name%>_longErr - ret - -<%=name%>_longErr: - push rdi - mov rdi, 0 - call <%=name%>_fail - pop rdi - - - diff --git a/ports/c/buildasm/fr.asm b/ports/c/buildasm/fr.asm deleted file mode 100644 index 180cd8d..0000000 --- a/ports/c/buildasm/fr.asm +++ /dev/null @@ -1,7607 +0,0 @@ - - - global Fr_copy - global Fr_copyn - global Fr_add - global Fr_sub - global Fr_neg - global Fr_mul - global Fr_square - global Fr_band - global Fr_bor - global Fr_bxor - global Fr_bnot - global Fr_eq - global Fr_neq - global Fr_lt - global Fr_gt - global Fr_leq - global Fr_geq - global Fr_land - global Fr_lor - global Fr_lnot - global Fr_toNormal - global Fr_toLongNormal - global Fr_toMontgomery - global Fr_toInt - global Fr_isTrue - global Fr_q - extern Fr_fail - DEFAULT REL - - section .text - - - - - - - - - - - - - - - - -;;;;;;;;;;;;;;;;;;;;;; -; copy -;;;;;;;;;;;;;;;;;;;;;; -; Copies -; Params: -; rsi <= the src -; rdi <= the dest -; -; Nidified registers: -; rax -;;;;;;;;;;;;;;;;;;;;;;; -Fr_copy: - - mov rax, [rsi + 0] - mov [rdi + 0], rax - - mov rax, [rsi + 8] - mov [rdi + 8], rax - - mov rax, [rsi + 16] - mov [rdi + 16], rax - - mov rax, [rsi + 24] - mov [rdi + 24], rax - - mov rax, [rsi + 32] - mov [rdi + 32], rax - - ret - -;;;;;;;;;;;;;;;;;;;;;; -; copy an array of integers -;;;;;;;;;;;;;;;;;;;;;; -; Copies -; Params: -; rsi <= the src -; rdi <= the dest -; rdx <= number of integers to copy -; -; Nidified registers: -; rax -;;;;;;;;;;;;;;;;;;;;;;; -Fr_copyn: -Fr_copyn_loop: - mov r8, rsi - mov r9, rdi - mov rax, 5 - mul rdx - mov rcx, rax - cld - rep movsq - mov rsi, r8 - mov rdi, r9 - ret - -;;;;;;;;;;;;;;;;;;;;;; -; rawCopyS2L -;;;;;;;;;;;;;;;;;;;;;; -; Convert a 64 bit integer to a long format field element -; Params: -; rsi <= the integer -; rdi <= Pointer to the overwritted element -; -; Nidified registers: -; rax -;;;;;;;;;;;;;;;;;;;;;;; - -rawCopyS2L: - mov al, 0x80 - shl rax, 56 - mov [rdi], rax ; set the result to LONG normal - - cmp rsi, 0 - js u64toLong_adjust_neg - - mov [rdi + 8], rsi - xor rax, rax - - mov [rdi + 16], rax - - mov [rdi + 24], rax - - mov [rdi + 32], rax - - ret - -u64toLong_adjust_neg: - add rsi, [q] ; Set the first digit - mov [rdi + 8], rsi ; - - mov rsi, -1 ; all ones - - mov rax, rsi ; Add to q - adc rax, [q + 8 ] - mov [rdi + 16], rax - - mov rax, rsi ; Add to q - adc rax, [q + 16 ] - mov [rdi + 24], rax - - mov rax, rsi ; Add to q - adc rax, [q + 24 ] - mov [rdi + 32], rax - - ret - -;;;;;;;;;;;;;;;;;;;;;; -; toInt -;;;;;;;;;;;;;;;;;;;;;; -; Convert a 64 bit integer to a long format field element -; Params: -; rsi <= Pointer to the element -; Returs: -; rax <= The value -;;;;;;;;;;;;;;;;;;;;;;; -Fr_toInt: - mov rax, [rdi] - bt rax, 63 - jc Fr_long - movsx rax, eax - ret - -Fr_long: - bt rax, 62 - jnc Fr_longNormal -Fr_longMontgomery: - call Fr_toLongNormal - -Fr_longNormal: - mov rax, [rdi + 8] - mov rcx, rax - shr rcx, 31 - jnz Fr_longNeg - - mov rcx, [rdi + 16] - test rcx, rcx - jnz Fr_longNeg - - mov rcx, [rdi + 24] - test rcx, rcx - jnz Fr_longNeg - - mov rcx, [rdi + 32] - test rcx, rcx - jnz Fr_longNeg - - ret - -Fr_longNeg: - mov rax, [rdi + 8] - sub rax, [q] - jnc Fr_longErr - - mov rcx, [rdi + 16] - sbb rcx, [q + 8] - jnc Fr_longErr - - mov rcx, [rdi + 24] - sbb rcx, [q + 16] - jnc Fr_longErr - - mov rcx, [rdi + 32] - sbb rcx, [q + 24] - jnc Fr_longErr - - mov rcx, rax - sar rcx, 31 - add rcx, 1 - jnz Fr_longErr - ret - -Fr_longErr: - push rdi - mov rdi, 0 - call Fr_fail - pop rdi - - - - - - - - - -;;;;;;;;;;;;;;;;;;;;;; -; rawMontgomeryMul -;;;;;;;;;;;;;;;;;;;;;; -; Multiply two elements in montgomery form -; Params: -; rsi <= Pointer to the long data of element 1 -; rdx <= Pointer to the long data of element 2 -; rdi <= Pointer to the long data of result -; Modified registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; - -rawMontgomeryMul: - sub rsp, 32 ; Reserve space for ms - mov rcx, rdx ; rdx is needed for multiplications so keep it in cx - mov r11, 0xc2e1f593efffffff ; np - xor r8,r8 - xor r9,r9 - xor r10,r10 - - mov rax, [rsi + 0] - mul qword [rcx + 0] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - - - mov rax, r8 - mul r11 - mov [rsp + 0], rax - mul qword [q] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - mov rax, [rsi + 0] - mul qword [rcx + 8] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - mov rax, [rsi + 8] - mul qword [rcx + 0] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - mov rax, [rsp + 0] - mul qword [q + 8] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - mov rax, r9 - mul r11 - mov [rsp + 8], rax - mul qword [q] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - mov rax, [rsi + 0] - mul qword [rcx + 16] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - mov rax, [rsi + 8] - mul qword [rcx + 8] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - mov rax, [rsi + 16] - mul qword [rcx + 0] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - mov rax, [rsp + 8] - mul qword [q + 8] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - mov rax, [rsp + 0] - mul qword [q + 16] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - mov rax, r10 - mul r11 - mov [rsp + 16], rax - mul qword [q] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - mov rax, [rsi + 0] - mul qword [rcx + 24] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - mov rax, [rsi + 8] - mul qword [rcx + 16] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - mov rax, [rsi + 16] - mul qword [rcx + 8] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - mov rax, [rsi + 24] - mul qword [rcx + 0] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - mov rax, [rsp + 16] - mul qword [q + 8] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - mov rax, [rsp + 8] - mul qword [q + 16] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - mov rax, [rsp + 0] - mul qword [q + 24] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - mov rax, r8 - mul r11 - mov [rsp + 24], rax - mul qword [q] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - mov rax, [rsi + 8] - mul qword [rcx + 24] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - mov rax, [rsi + 16] - mul qword [rcx + 16] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - mov rax, [rsi + 24] - mul qword [rcx + 8] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - mov rax, [rsp + 24] - mul qword [q + 8] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - mov rax, [rsp + 16] - mul qword [q + 16] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - mov rax, [rsp + 8] - mul qword [q + 24] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - mov [rdi + 0 ], r9 - xor r9,r9 - - - - mov rax, [rsi + 16] - mul qword [rcx + 24] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - mov rax, [rsi + 24] - mul qword [rcx + 16] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - mov rax, [rsp + 24] - mul qword [q + 16] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - mov rax, [rsp + 16] - mul qword [q + 24] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - mov [rdi + 8 ], r10 - xor r10,r10 - - - - mov rax, [rsi + 24] - mul qword [rcx + 24] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - mov rax, [rsp + 24] - mul qword [q + 24] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - mov [rdi + 16 ], r8 - xor r8,r8 - - - - - - - - mov [rdi + 24 ], r9 - xor r9,r9 - - - - test r10, r10 - jnz rawMontgomeryMul_mulM_sq - ; Compare with q - - mov rax, [rdi + 24] - cmp rax, [q + 24] - jc rawMontgomeryMul_mulM_done ; q is bigget so done. - jnz rawMontgomeryMul_mulM_sq ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 16] - jc rawMontgomeryMul_mulM_done ; q is bigget so done. - jnz rawMontgomeryMul_mulM_sq ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 8] - jc rawMontgomeryMul_mulM_done ; q is bigget so done. - jnz rawMontgomeryMul_mulM_sq ; q is lower - - mov rax, [rdi + 0] - cmp rax, [q + 0] - jc rawMontgomeryMul_mulM_done ; q is bigget so done. - jnz rawMontgomeryMul_mulM_sq ; q is lower - - ; If equal substract q - -rawMontgomeryMul_mulM_sq: - - mov rax, [q + 0] - sub [rdi + 0], rax - - mov rax, [q + 8] - sbb [rdi + 8], rax - - mov rax, [q + 16] - sbb [rdi + 16], rax - - mov rax, [q + 24] - sbb [rdi + 24], rax - - -rawMontgomeryMul_mulM_done: - mov rdx, rcx ; recover rdx to its original place. - add rsp, 32 ; recover rsp - ret - - - -;;;;;;;;;;;;;;;;;;;;;; -; rawMontgomerySquare -;;;;;;;;;;;;;;;;;;;;;; -; Square an element -; Params: -; rsi <= Pointer to the long data of element 1 -; rdi <= Pointer to the long data of result -; Modified registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; - -rawMontgomerySquare: - sub rsp, 32 ; Reserve space for ms - mov rcx, rdx ; rdx is needed for multiplications so keep it in cx - mov r11, 0xc2e1f593efffffff ; np - xor r8,r8 - xor r9,r9 - xor r10,r10 - - - - mov rax, [rsi + 0] - mul rax - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - - - - - mov rax, r8 - mul r11 - mov [rsp + 0], rax - mul qword [q] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - mov rax, [rsi + 0] - mul qword [rsi + 8] - add r9, rax - adc r10, rdx - adc r8, 0x0 - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - - - - - mov rax, [rsp + 0] - mul qword [q + 8] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - mov rax, r9 - mul r11 - mov [rsp + 8], rax - mul qword [q] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - mov rax, [rsi + 0] - mul qword [rsi + 16] - add r10, rax - adc r8, rdx - adc r9, 0x0 - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - mov rax, [rsi + 8] - mul rax - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - - - mov rax, [rsp + 8] - mul qword [q + 8] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - mov rax, [rsp + 0] - mul qword [q + 16] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - mov rax, r10 - mul r11 - mov [rsp + 16], rax - mul qword [q] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - mov rax, [rsi + 0] - mul qword [rsi + 24] - add r8, rax - adc r9, rdx - adc r10, 0x0 - add r8, rax - adc r9, rdx - adc r10, 0x0 - - mov rax, [rsi + 8] - mul qword [rsi + 16] - add r8, rax - adc r9, rdx - adc r10, 0x0 - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - - - - - mov rax, [rsp + 16] - mul qword [q + 8] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - mov rax, [rsp + 8] - mul qword [q + 16] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - mov rax, [rsp + 0] - mul qword [q + 24] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - mov rax, r8 - mul r11 - mov [rsp + 24], rax - mul qword [q] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - mov rax, [rsi + 8] - mul qword [rsi + 24] - add r9, rax - adc r10, rdx - adc r8, 0x0 - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - mov rax, [rsi + 16] - mul rax - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - - - mov rax, [rsp + 24] - mul qword [q + 8] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - mov rax, [rsp + 16] - mul qword [q + 16] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - mov rax, [rsp + 8] - mul qword [q + 24] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - mov [rdi + 0 ], r9 - xor r9,r9 - - - - mov rax, [rsi + 16] - mul qword [rsi + 24] - add r10, rax - adc r8, rdx - adc r9, 0x0 - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - - - - - mov rax, [rsp + 24] - mul qword [q + 16] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - mov rax, [rsp + 16] - mul qword [q + 24] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - mov [rdi + 8 ], r10 - xor r10,r10 - - - - - - mov rax, [rsi + 24] - mul rax - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - - - mov rax, [rsp + 24] - mul qword [q + 24] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - mov [rdi + 16 ], r8 - xor r8,r8 - - - - - - - - - - - - mov [rdi + 24 ], r9 - xor r9,r9 - - - - test r10, r10 - jnz rawMontgomerySquare_mulM_sq - ; Compare with q - - mov rax, [rdi + 24] - cmp rax, [q + 24] - jc rawMontgomerySquare_mulM_done ; q is bigget so done. - jnz rawMontgomerySquare_mulM_sq ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 16] - jc rawMontgomerySquare_mulM_done ; q is bigget so done. - jnz rawMontgomerySquare_mulM_sq ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 8] - jc rawMontgomerySquare_mulM_done ; q is bigget so done. - jnz rawMontgomerySquare_mulM_sq ; q is lower - - mov rax, [rdi + 0] - cmp rax, [q + 0] - jc rawMontgomerySquare_mulM_done ; q is bigget so done. - jnz rawMontgomerySquare_mulM_sq ; q is lower - - ; If equal substract q - -rawMontgomerySquare_mulM_sq: - - mov rax, [q + 0] - sub [rdi + 0], rax - - mov rax, [q + 8] - sbb [rdi + 8], rax - - mov rax, [q + 16] - sbb [rdi + 16], rax - - mov rax, [q + 24] - sbb [rdi + 24], rax - - -rawMontgomerySquare_mulM_done: - mov rdx, rcx ; recover rdx to its original place. - add rsp, 32 ; recover rsp - ret - - - - -;;;;;;;;;;;;;;;;;;;;;; -; rawMontgomeryMul1 -;;;;;;;;;;;;;;;;;;;;;; -; Multiply two elements in montgomery form -; Params: -; rsi <= Pointer to the long data of element 1 -; rdx <= second operand -; rdi <= Pointer to the long data of result -; Modified registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; - -rawMontgomeryMul1: - sub rsp, 32 ; Reserve space for ms - mov rcx, rdx ; rdx is needed for multiplications so keep it in cx - mov r11, 0xc2e1f593efffffff ; np - xor r8,r8 - xor r9,r9 - xor r10,r10 - - mov rax, [rsi + 0] - mul rcx - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - - - mov rax, r8 - mul r11 - mov [rsp + 0], rax - mul qword [q] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - mov rax, [rsi + 8] - mul rcx - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - mov rax, [rsp + 0] - mul qword [q + 8] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - mov rax, r9 - mul r11 - mov [rsp + 8], rax - mul qword [q] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - mov rax, [rsi + 16] - mul rcx - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - mov rax, [rsp + 8] - mul qword [q + 8] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - mov rax, [rsp + 0] - mul qword [q + 16] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - mov rax, r10 - mul r11 - mov [rsp + 16], rax - mul qword [q] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - mov rax, [rsi + 24] - mul rcx - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - mov rax, [rsp + 16] - mul qword [q + 8] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - mov rax, [rsp + 8] - mul qword [q + 16] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - mov rax, [rsp + 0] - mul qword [q + 24] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - mov rax, r8 - mul r11 - mov [rsp + 24], rax - mul qword [q] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - - - mov rax, [rsp + 24] - mul qword [q + 8] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - mov rax, [rsp + 16] - mul qword [q + 16] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - mov rax, [rsp + 8] - mul qword [q + 24] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - mov [rdi + 0 ], r9 - xor r9,r9 - - - - - - mov rax, [rsp + 24] - mul qword [q + 16] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - mov rax, [rsp + 16] - mul qword [q + 24] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - mov [rdi + 8 ], r10 - xor r10,r10 - - - - - - mov rax, [rsp + 24] - mul qword [q + 24] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - mov [rdi + 16 ], r8 - xor r8,r8 - - - - - - - - mov [rdi + 24 ], r9 - xor r9,r9 - - - - test r10, r10 - jnz rawMontgomeryMul1_mulM_sq - ; Compare with q - - mov rax, [rdi + 24] - cmp rax, [q + 24] - jc rawMontgomeryMul1_mulM_done ; q is bigget so done. - jnz rawMontgomeryMul1_mulM_sq ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 16] - jc rawMontgomeryMul1_mulM_done ; q is bigget so done. - jnz rawMontgomeryMul1_mulM_sq ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 8] - jc rawMontgomeryMul1_mulM_done ; q is bigget so done. - jnz rawMontgomeryMul1_mulM_sq ; q is lower - - mov rax, [rdi + 0] - cmp rax, [q + 0] - jc rawMontgomeryMul1_mulM_done ; q is bigget so done. - jnz rawMontgomeryMul1_mulM_sq ; q is lower - - ; If equal substract q - -rawMontgomeryMul1_mulM_sq: - - mov rax, [q + 0] - sub [rdi + 0], rax - - mov rax, [q + 8] - sbb [rdi + 8], rax - - mov rax, [q + 16] - sbb [rdi + 16], rax - - mov rax, [q + 24] - sbb [rdi + 24], rax - - -rawMontgomeryMul1_mulM_done: - mov rdx, rcx ; recover rdx to its original place. - add rsp, 32 ; recover rsp - ret - - - - -;;;;;;;;;;;;;;;;;;;;;; -; rawFromMontgomery -;;;;;;;;;;;;;;;;;;;;;; -; Multiply two elements in montgomery form -; Params: -; rsi <= Pointer to the long data of element 1 -; rdi <= Pointer to the long data of result -; Modified registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; - -rawFromMontgomery: - sub rsp, 32 ; Reserve space for ms - mov rcx, rdx ; rdx is needed for multiplications so keep it in cx - mov r11, 0xc2e1f593efffffff ; np - xor r8,r8 - xor r9,r9 - xor r10,r10 - - add r8, [rdi + 0] - adc r9, 0x0 - adc r10, 0x0 - - - - - - mov rax, r8 - mul r11 - mov [rsp + 0], rax - mul qword [q] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - add r9, [rdi + 8] - adc r10, 0x0 - adc r8, 0x0 - - - - mov rax, [rsp + 0] - mul qword [q + 8] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - mov rax, r9 - mul r11 - mov [rsp + 8], rax - mul qword [q] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - add r10, [rdi + 16] - adc r8, 0x0 - adc r9, 0x0 - - - - mov rax, [rsp + 8] - mul qword [q + 8] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - mov rax, [rsp + 0] - mul qword [q + 16] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - mov rax, r10 - mul r11 - mov [rsp + 16], rax - mul qword [q] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - add r8, [rdi + 24] - adc r9, 0x0 - adc r10, 0x0 - - - - mov rax, [rsp + 16] - mul qword [q + 8] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - mov rax, [rsp + 8] - mul qword [q + 16] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - mov rax, [rsp + 0] - mul qword [q + 24] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - mov rax, r8 - mul r11 - mov [rsp + 24], rax - mul qword [q] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - - - mov rax, [rsp + 24] - mul qword [q + 8] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - mov rax, [rsp + 16] - mul qword [q + 16] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - mov rax, [rsp + 8] - mul qword [q + 24] - add r9, rax - adc r10, rdx - adc r8, 0x0 - - - - mov [rdi + 0 ], r9 - xor r9,r9 - - - - - - mov rax, [rsp + 24] - mul qword [q + 16] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - mov rax, [rsp + 16] - mul qword [q + 24] - add r10, rax - adc r8, rdx - adc r9, 0x0 - - - - mov [rdi + 8 ], r10 - xor r10,r10 - - - - - - mov rax, [rsp + 24] - mul qword [q + 24] - add r8, rax - adc r9, rdx - adc r10, 0x0 - - - - mov [rdi + 16 ], r8 - xor r8,r8 - - - - - - - - mov [rdi + 24 ], r9 - xor r9,r9 - - - - test r10, r10 - jnz rawFromMontgomery_mulM_sq - ; Compare with q - - mov rax, [rdi + 24] - cmp rax, [q + 24] - jc rawFromMontgomery_mulM_done ; q is bigget so done. - jnz rawFromMontgomery_mulM_sq ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 16] - jc rawFromMontgomery_mulM_done ; q is bigget so done. - jnz rawFromMontgomery_mulM_sq ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 8] - jc rawFromMontgomery_mulM_done ; q is bigget so done. - jnz rawFromMontgomery_mulM_sq ; q is lower - - mov rax, [rdi + 0] - cmp rax, [q + 0] - jc rawFromMontgomery_mulM_done ; q is bigget so done. - jnz rawFromMontgomery_mulM_sq ; q is lower - - ; If equal substract q - -rawFromMontgomery_mulM_sq: - - mov rax, [q + 0] - sub [rdi + 0], rax - - mov rax, [q + 8] - sbb [rdi + 8], rax - - mov rax, [q + 16] - sbb [rdi + 16], rax - - mov rax, [q + 24] - sbb [rdi + 24], rax - - -rawFromMontgomery_mulM_done: - mov rdx, rcx ; recover rdx to its original place. - add rsp, 32 ; recover rsp - ret - - - -;;;;;;;;;;;;;;;;;;;;;; -; toMontgomery -;;;;;;;;;;;;;;;;;;;;;; -; Convert a number to Montgomery -; rdi <= Pointer element to convert -; Modified registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;; -Fr_toMontgomery: - mov rax, [rdi] - bt rax, 62 ; check if montgomery - jc toMontgomery_doNothing - bt rax, 63 - jc toMontgomeryLong - -toMontgomeryShort: - add rdi, 8 - push rsi - push rdx - lea rsi, [R2] - movsx rdx, eax - cmp rdx, 0 - js negMontgomeryShort -posMontgomeryShort: - call rawMontgomeryMul1 - pop rdx - pop rsi - sub rdi, 8 - mov r11b, 0x40 - shl r11d, 24 - mov [rdi+4], r11d - ret - -negMontgomeryShort: - neg rdx ; Do the multiplication positive and then negate the result. - call rawMontgomeryMul1 - mov rsi, rdi - call rawNegL - pop rdx - pop rsi - sub rdi, 8 - mov r11b, 0x40 - shl r11d, 24 - mov [rdi+4], r11d - ret - - -toMontgomeryLong: - mov [rdi], rax - add rdi, 8 - push rsi - mov rdx, rdi - lea rsi, [R2] - call rawMontgomeryMul - pop rsi - sub rdi, 8 - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - - -toMontgomery_doNothing: - ret - -;;;;;;;;;;;;;;;;;;;;;; -; toNormal -;;;;;;;;;;;;;;;;;;;;;; -; Convert a number from Montgomery -; rdi <= Pointer element to convert -; Modified registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;; -Fr_toNormal: - mov rax, [rdi] - bt rax, 62 ; check if montgomery - jnc toNormal_doNothing - bt rax, 63 ; if short, it means it's converted - jnc toNormal_doNothing - -toNormalLong: - add rdi, 8 - call rawFromMontgomery - sub rdi, 8 - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - -toNormal_doNothing: - ret - -;;;;;;;;;;;;;;;;;;;;;; -; toLongNormal -;;;;;;;;;;;;;;;;;;;;;; -; Convert a number to long normal -; rdi <= Pointer element to convert -; Modified registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;; -Fr_toLongNormal: - mov rax, [rdi] - bt rax, 62 ; check if montgomery - jc toLongNormal_fromMontgomery - bt rax, 63 ; check if long - jnc toLongNormal_fromShort - ret ; It is already long - -toLongNormal_fromMontgomery: - add rdi, 8 - call rawFromMontgomery - sub rdi, 8 - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - ret - -toLongNormal_fromShort: - mov r8, rsi ; save rsi - movsx rsi, eax - call rawCopyS2L - mov rsi, r8 ; recover rsi - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - ret - - - - - - - - - - - - -;;;;;;;;;;;;;;;;;;;;;; -; add -;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result -; Modified Registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -Fr_add: - mov rax, [rsi] - mov rcx, [rdx] - bt rax, 63 ; Check if is short first operand - jc add_l1 - bt rcx, 63 ; Check if is short second operand - jc add_s1l2 - -add_s1s2: ; Both operands are short - - xor rdx, rdx - mov edx, eax - add edx, ecx - jo add_manageOverflow ; rsi already is the 64bits result - - mov [rdi], rdx ; not necessary to adjust so just save and return - ret - -add_manageOverflow: ; Do the operation in 64 bits - push rsi - movsx rsi, eax - movsx rdx, ecx - add rsi, rdx - call rawCopyS2L - pop rsi - ret - -add_l1: - bt rcx, 63 ; Check if is short second operand - jc add_l1l2 - -;;;;;;;; -add_l1s2: - bt rax, 62 ; check if montgomery first - jc add_l1ms2 -add_l1ns2: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - add rsi, 8 - movsx rdx, ecx - add rdi, 8 - cmp rdx, 0 - - jns tmp_1 - neg rdx - call rawSubLS - sub rdi, 8 - sub rsi, 8 - ret -tmp_1: - call rawAddLS - sub rdi, 8 - sub rsi, 8 - ret - - - -add_l1ms2: - bt rcx, 62 ; check if montgomery second - jc add_l1ms2m -add_l1ms2n: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rdx - call Fr_toMontgomery - mov rdx, rdi - pop rdi - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawAddLL - sub rdi, 8 - sub rsi, 8 - ret - - -add_l1ms2m: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawAddLL - sub rdi, 8 - sub rsi, 8 - ret - - - -;;;;;;;; -add_s1l2: - bt rcx, 62 ; check if montgomery second - jc add_s1l2m -add_s1l2n: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - lea rsi, [rdx + 8] - movsx rdx, eax - add rdi, 8 - cmp rdx, 0 - - jns tmp_2 - neg rdx - call rawSubLS - sub rdi, 8 - sub rsi, 8 - ret -tmp_2: - call rawAddLS - sub rdi, 8 - sub rsi, 8 - ret - - -add_s1l2m: - bt rax, 62 ; check if montgomery first - jc add_s1ml2m -add_s1nl2m: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toMontgomery - mov rdx, rsi - mov rsi, rdi - pop rdi - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawAddLL - sub rdi, 8 - sub rsi, 8 - ret - - -add_s1ml2m: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawAddLL - sub rdi, 8 - sub rsi, 8 - ret - - -;;;; -add_l1l2: - bt rax, 62 ; check if montgomery first - jc add_l1ml2 -add_l1nl2: - bt rcx, 62 ; check if montgomery second - jc add_l1nl2m -add_l1nl2n: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawAddLL - sub rdi, 8 - sub rsi, 8 - ret - - -add_l1nl2m: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toMontgomery - mov rdx, rsi - mov rsi, rdi - pop rdi - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawAddLL - sub rdi, 8 - sub rsi, 8 - ret - - -add_l1ml2: - bt rcx, 62 ; check if montgomery seconf - jc add_l1ml2m -add_l1ml2n: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rdx - call Fr_toMontgomery - mov rdx, rdi - pop rdi - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawAddLL - sub rdi, 8 - sub rsi, 8 - ret - - -add_l1ml2m: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawAddLL - sub rdi, 8 - sub rsi, 8 - ret - - - - -;;;;;;;;;;;;;;;;;;;;;; -; rawAddLL -;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of type long -; Params: -; rsi <= Pointer to the long data of element 1 -; rdx <= Pointer to the long data of element 2 -; rdi <= Pointer to the long data of result -; Modified Registers: -; rax -;;;;;;;;;;;;;;;;;;;;;; -rawAddLL: - ; Add component by component with carry - - mov rax, [rsi + 0] - add rax, [rdx + 0] - mov [rdi + 0], rax - - mov rax, [rsi + 8] - adc rax, [rdx + 8] - mov [rdi + 8], rax - - mov rax, [rsi + 16] - adc rax, [rdx + 16] - mov [rdi + 16], rax - - mov rax, [rsi + 24] - adc rax, [rdx + 24] - mov [rdi + 24], rax - - jc rawAddLL_sq ; if overflow, substract q - - ; Compare with q - - - cmp rax, [q + 24] - jc rawAddLL_done ; q is bigget so done. - jnz rawAddLL_sq ; q is lower - - - mov rax, [rdi + 16] - - cmp rax, [q + 16] - jc rawAddLL_done ; q is bigget so done. - jnz rawAddLL_sq ; q is lower - - - mov rax, [rdi + 8] - - cmp rax, [q + 8] - jc rawAddLL_done ; q is bigget so done. - jnz rawAddLL_sq ; q is lower - - - mov rax, [rdi + 0] - - cmp rax, [q + 0] - jc rawAddLL_done ; q is bigget so done. - jnz rawAddLL_sq ; q is lower - - ; If equal substract q -rawAddLL_sq: - - mov rax, [q + 0] - sub [rdi + 0], rax - - mov rax, [q + 8] - sbb [rdi + 8], rax - - mov rax, [q + 16] - sbb [rdi + 16], rax - - mov rax, [q + 24] - sbb [rdi + 24], rax - -rawAddLL_done: - ret - - -;;;;;;;;;;;;;;;;;;;;;; -; rawAddLS -;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of type long -; Params: -; rdi <= Pointer to the long data of result -; rsi <= Pointer to the long data of element 1 -; rdx <= Value to be added -;;;;;;;;;;;;;;;;;;;;;; -rawAddLS: - ; Add component by component with carry - - add rdx, [rsi] - mov [rdi] ,rdx - - mov rdx, 0 - adc rdx, [rsi + 8] - mov [rdi + 8], rdx - - mov rdx, 0 - adc rdx, [rsi + 16] - mov [rdi + 16], rdx - - mov rdx, 0 - adc rdx, [rsi + 24] - mov [rdi + 24], rdx - - jc rawAddLS_sq ; if overflow, substract q - - ; Compare with q - - mov rax, [rdi + 24] - cmp rax, [q + 24] - jc rawAddLS_done ; q is bigget so done. - jnz rawAddLS_sq ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 16] - jc rawAddLS_done ; q is bigget so done. - jnz rawAddLS_sq ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 8] - jc rawAddLS_done ; q is bigget so done. - jnz rawAddLS_sq ; q is lower - - mov rax, [rdi + 0] - cmp rax, [q + 0] - jc rawAddLS_done ; q is bigget so done. - jnz rawAddLS_sq ; q is lower - - ; If equal substract q -rawAddLS_sq: - - mov rax, [q + 0] - sub [rdi + 0], rax - - mov rax, [q + 8] - sbb [rdi + 8], rax - - mov rax, [q + 16] - sbb [rdi + 16], rax - - mov rax, [q + 24] - sbb [rdi + 24], rax - -rawAddLS_done: - ret - - - - - - - - - - - - - - - -;;;;;;;;;;;;;;;;;;;;;; -; sub -;;;;;;;;;;;;;;;;;;;;;; -; Substracts two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result -; Modified Registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -Fr_sub: - mov rax, [rsi] - mov rcx, [rdx] - bt rax, 63 ; Check if is long first operand - jc sub_l1 - bt rcx, 63 ; Check if is long second operand - jc sub_s1l2 - -sub_s1s2: ; Both operands are short - - xor rdx, rdx - mov edx, eax - sub edx, ecx - jo sub_manageOverflow ; rsi already is the 64bits result - - mov [rdi], rdx ; not necessary to adjust so just save and return - ret - -sub_manageOverflow: ; Do the operation in 64 bits - push rsi - movsx rsi, eax - movsx rdx, ecx - sub rsi, rdx - call rawCopyS2L - pop rsi - ret - -sub_l1: - bt rcx, 63 ; Check if is short second operand - jc sub_l1l2 - -;;;;;;;; -sub_l1s2: - bt rax, 62 ; check if montgomery first - jc sub_l1ms2 -sub_l1ns2: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - add rsi, 8 - movsx rdx, ecx - add rdi, 8 - cmp rdx, 0 - - jns tmp_3 - neg rdx - call rawAddLS - sub rdi, 8 - sub rsi, 8 - ret -tmp_3: - call rawSubLS - sub rdi, 8 - sub rsi, 8 - ret - - -sub_l1ms2: - bt rcx, 62 ; check if montgomery second - jc sub_l1ms2m -sub_l1ms2n: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rdx - call Fr_toMontgomery - mov rdx, rdi - pop rdi - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawSubLL - sub rdi, 8 - sub rsi, 8 - ret - - -sub_l1ms2m: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawSubLL - sub rdi, 8 - sub rsi, 8 - ret - - - -;;;;;;;; -sub_s1l2: - bt rcx, 62 ; check if montgomery first - jc sub_s1l2m -sub_s1l2n: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - cmp eax, 0 - - js tmp_4 - - ; First Operand is positive - push rsi - add rdi, 8 - movsx rsi, eax - add rdx, 8 - call rawSubSL - sub rdi, 8 - pop rsi - ret - -tmp_4: ; First operand is negative - push rsi - lea rsi, [rdx + 8] - movsx rdx, eax - add rdi, 8 - neg rdx - call rawNegLS - sub rdi, 8 - pop rsi - ret - - -sub_s1l2m: - bt rax, 62 ; check if montgomery second - jc sub_s1ml2m -sub_s1nl2m: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toMontgomery - mov rdx, rsi - mov rsi, rdi - pop rdi - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawSubLL - sub rdi, 8 - sub rsi, 8 - ret - - -sub_s1ml2m: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawSubLL - sub rdi, 8 - sub rsi, 8 - ret - - -;;;; -sub_l1l2: - bt rax, 62 ; check if montgomery first - jc sub_l1ml2 -sub_l1nl2: - bt rcx, 62 ; check if montgomery second - jc sub_l1nl2m -sub_l1nl2n: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawSubLL - sub rdi, 8 - sub rsi, 8 - ret - - -sub_l1nl2m: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toMontgomery - mov rdx, rsi - mov rsi, rdi - pop rdi - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawSubLL - sub rdi, 8 - sub rsi, 8 - ret - - -sub_l1ml2: - bt rcx, 62 ; check if montgomery seconf - jc sub_l1ml2m -sub_l1ml2n: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rdx - call Fr_toMontgomery - mov rdx, rdi - pop rdi - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawSubLL - sub rdi, 8 - sub rsi, 8 - ret - - -sub_l1ml2m: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawSubLL - sub rdi, 8 - sub rsi, 8 - ret - - - -;;;;;;;;;;;;;;;;;;;;;; -; rawSubLS -;;;;;;;;;;;;;;;;;;;;;; -; Substracts a short element from the long element -; Params: -; rdi <= Pointer to the long data of result -; rsi <= Pointer to the long data of element 1 where will be substracted -; rdx <= Value to be substracted -; [rdi] = [rsi] - rdx -; Modified Registers: -; rax -;;;;;;;;;;;;;;;;;;;;;; -rawSubLS: - ; Substract first digit - - mov rax, [rsi] - sub rax, rdx - mov [rdi] ,rax - mov rdx, 0 - - mov rax, [rsi + 8] - sbb rax, rdx - mov [rdi + 8], rax - - mov rax, [rsi + 16] - sbb rax, rdx - mov [rdi + 16], rax - - mov rax, [rsi + 24] - sbb rax, rdx - mov [rdi + 24], rax - - jnc rawSubLS_done ; if overflow, add q - - ; Add q -rawSubLS_aq: - - mov rax, [q + 0] - add [rdi + 0], rax - - mov rax, [q + 8] - adc [rdi + 8], rax - - mov rax, [q + 16] - adc [rdi + 16], rax - - mov rax, [q + 24] - adc [rdi + 24], rax - -rawSubLS_done: - ret - - -;;;;;;;;;;;;;;;;;;;;;; -; rawSubSL -;;;;;;;;;;;;;;;;;;;;;; -; Substracts a long element from a short element -; Params: -; rdi <= Pointer to the long data of result -; rsi <= Value from where will bo substracted -; rdx <= Pointer to long of the value to be substracted -; -; [rdi] = rsi - [rdx] -; Modified Registers: -; rax -;;;;;;;;;;;;;;;;;;;;;; -rawSubSL: - ; Substract first digit - sub rsi, [rdx] - mov [rdi] ,rsi - - - mov rax, 0 - sbb rax, [rdx + 8] - mov [rdi + 8], rax - - mov rax, 0 - sbb rax, [rdx + 16] - mov [rdi + 16], rax - - mov rax, 0 - sbb rax, [rdx + 24] - mov [rdi + 24], rax - - jnc rawSubSL_done ; if overflow, add q - - ; Add q -rawSubSL_aq: - - mov rax, [q + 0] - add [rdi + 0], rax - - mov rax, [q + 8] - adc [rdi + 8], rax - - mov rax, [q + 16] - adc [rdi + 16], rax - - mov rax, [q + 24] - adc [rdi + 24], rax - -rawSubSL_done: - ret - -;;;;;;;;;;;;;;;;;;;;;; -; rawSubLL -;;;;;;;;;;;;;;;;;;;;;; -; Substracts a long element from a short element -; Params: -; rdi <= Pointer to the long data of result -; rsi <= Pointer to long from where substracted -; rdx <= Pointer to long of the value to be substracted -; -; [rdi] = [rsi] - [rdx] -; Modified Registers: -; rax -;;;;;;;;;;;;;;;;;;;;;; -rawSubLL: - ; Substract first digit - - mov rax, [rsi + 0] - sub rax, [rdx + 0] - mov [rdi + 0], rax - - mov rax, [rsi + 8] - sbb rax, [rdx + 8] - mov [rdi + 8], rax - - mov rax, [rsi + 16] - sbb rax, [rdx + 16] - mov [rdi + 16], rax - - mov rax, [rsi + 24] - sbb rax, [rdx + 24] - mov [rdi + 24], rax - - jnc rawSubLL_done ; if overflow, add q - - ; Add q -rawSubLL_aq: - - mov rax, [q + 0] - add [rdi + 0], rax - - mov rax, [q + 8] - adc [rdi + 8], rax - - mov rax, [q + 16] - adc [rdi + 16], rax - - mov rax, [q + 24] - adc [rdi + 24], rax - -rawSubLL_done: - ret - -;;;;;;;;;;;;;;;;;;;;;; -; rawNegLS -;;;;;;;;;;;;;;;;;;;;;; -; Substracts a long element and a short element form 0 -; Params: -; rdi <= Pointer to the long data of result -; rsi <= Pointer to long from where substracted -; rdx <= short value to be substracted too -; -; [rdi] = -[rsi] - rdx -; Modified Registers: -; rax -;;;;;;;;;;;;;;;;;;;;;; -rawNegLS: - mov rax, [q] - sub rax, rdx - mov [rdi], rax - - mov rax, [q + 8 ] - sbb rax, 0 - mov [rdi + 8], rax - - mov rax, [q + 16 ] - sbb rax, 0 - mov [rdi + 16], rax - - mov rax, [q + 24 ] - sbb rax, 0 - mov [rdi + 24], rax - - setc dl - - - mov rax, [rdi + 0 ] - sub rax, [rsi + 0] - mov [rdi + 0], rax - - mov rax, [rdi + 8 ] - sbb rax, [rsi + 8] - mov [rdi + 8], rax - - mov rax, [rdi + 16 ] - sbb rax, [rsi + 16] - mov [rdi + 16], rax - - mov rax, [rdi + 24 ] - sbb rax, [rsi + 24] - mov [rdi + 24], rax - - - setc dh - or dl, dh - jz rawNegSL_done - - ; it is a negative value, so add q - - mov rax, [q + 0] - add [rdi + 0], rax - - mov rax, [q + 8] - adc [rdi + 8], rax - - mov rax, [q + 16] - adc [rdi + 16], rax - - mov rax, [q + 24] - adc [rdi + 24], rax - - -rawNegSL_done: - ret - - - - - - - -;;;;;;;;;;;;;;;;;;;;;; -; neg -;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of any kind -; Params: -; rsi <= Pointer to element to be negated -; rdi <= Pointer to result -; [rdi] = -[rsi] -;;;;;;;;;;;;;;;;;;;;;; -Fr_neg: - mov rax, [rsi] - bt rax, 63 ; Check if is short first operand - jc neg_l - -neg_s: ; Operand is short - - neg eax - jo neg_manageOverflow ; Check if overflow. (0x80000000 is the only case) - - mov [rdi], rax ; not necessary to adjust so just save and return - ret - -neg_manageOverflow: ; Do the operation in 64 bits - push rsi - movsx rsi, eax - neg rsi - call rawCopyS2L - pop rsi - ret - - - -neg_l: - mov [rdi], rax ; Copy the type - - add rdi, 8 - add rsi, 8 - call rawNegL - sub rdi, 8 - sub rsi, 8 - ret - - - -;;;;;;;;;;;;;;;;;;;;;; -; rawNeg -;;;;;;;;;;;;;;;;;;;;;; -; Negates a value -; Params: -; rdi <= Pointer to the long data of result -; rsi <= Pointer to the long data of element 1 -; -; [rdi] = - [rsi] -;;;;;;;;;;;;;;;;;;;;;; -rawNegL: - ; Compare is zero - - xor rax, rax - - cmp [rsi + 0], rax - jnz doNegate - - cmp [rsi + 8], rax - jnz doNegate - - cmp [rsi + 16], rax - jnz doNegate - - cmp [rsi + 24], rax - jnz doNegate - - ; it's zero so just set to zero - - mov [rdi + 0], rax - - mov [rdi + 8], rax - - mov [rdi + 16], rax - - mov [rdi + 24], rax - - ret -doNegate: - - mov rax, [q + 0] - sub rax, [rsi + 0] - mov [rdi + 0], rax - - mov rax, [q + 8] - sbb rax, [rsi + 8] - mov [rdi + 8], rax - - mov rax, [q + 16] - sbb rax, [rsi + 16] - mov [rdi + 16], rax - - mov rax, [q + 24] - sbb rax, [rsi + 24] - mov [rdi + 24], rax - - ret - - - - - - - - - - - - - - - - - - - -;;;;;;;;;;;;;;;;;;;;;; -; square -;;;;;;;;;;;;;;;;;;;;;; -; Squares a field element -; Params: -; rsi <= Pointer to element 1 -; rdi <= Pointer to result -; [rdi] = [rsi] * [rsi] -; Modified Registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -Fr_square: - mov r8, [rsi] - bt r8, 63 ; Check if is short first operand - jc square_l1 - -square_s1: ; Both operands are short - - xor rax, rax - mov eax, r8d - imul eax - jo square_manageOverflow ; rsi already is the 64bits result - - mov [rdi], rax ; not necessary to adjust so just save and return - -square_manageOverflow: ; Do the operation in 64 bits - push rsi - movsx rax, r8d - imul rax - mov rsi, rax - call rawCopyS2L - pop rsi - - ret - -square_l1: - bt r8, 62 ; check if montgomery first - jc square_l1m -square_l1n: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - call rawMontgomerySquare - sub rdi, 8 - sub rsi, 8 - - - push rsi - add rdi, 8 - mov rsi, rdi - lea rdx, [R3] - call rawMontgomeryMul - sub rdi, 8 - pop rsi - - ret - -square_l1m: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - call rawMontgomerySquare - sub rdi, 8 - sub rsi, 8 - - ret - - - -;;;;;;;;;;;;;;;;;;;;;; -; mul -;;;;;;;;;;;;;;;;;;;;;; -; Multiplies two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result -; [rdi] = [rsi] * [rdi] -; Modified Registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -Fr_mul: - mov r8, [rsi] - mov r9, [rdx] - bt r8, 63 ; Check if is short first operand - jc mul_l1 - bt r9, 63 ; Check if is short second operand - jc mul_s1l2 - -mul_s1s2: ; Both operands are short - - xor rax, rax - mov eax, r8d - imul r9d - jo mul_manageOverflow ; rsi already is the 64bits result - - mov [rdi], rax ; not necessary to adjust so just save and return - -mul_manageOverflow: ; Do the operation in 64 bits - push rsi - movsx rax, r8d - movsx rcx, r9d - imul rcx - mov rsi, rax - call rawCopyS2L - pop rsi - - ret - -mul_l1: - bt r9, 63 ; Check if is short second operand - jc mul_l1l2 - -;;;;;;;; -mul_l1s2: - bt r8, 62 ; check if montgomery first - jc mul_l1ms2 -mul_l1ns2: - bt r9, 62 ; check if montgomery first - jc mul_l1ns2m -mul_l1ns2n: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - - push rsi - add rsi, 8 - movsx rdx, r9d - add rdi, 8 - cmp rdx, 0 - - jns tmp_5 - neg rdx - call rawMontgomeryMul1 - mov rsi, rdi - call rawNegL - sub rdi, 8 - pop rsi - - jmp tmp_6 -tmp_5: - call rawMontgomeryMul1 - sub rdi, 8 - pop rsi -tmp_6: - - - - push rsi - add rdi, 8 - mov rsi, rdi - lea rdx, [R3] - call rawMontgomeryMul - sub rdi, 8 - pop rsi - - ret - - -mul_l1ns2m: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawMontgomeryMul - sub rdi, 8 - sub rsi, 8 - - ret - - -mul_l1ms2: - bt r9, 62 ; check if montgomery second - jc mul_l1ms2m -mul_l1ms2n: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - push rsi - add rsi, 8 - movsx rdx, r9d - add rdi, 8 - cmp rdx, 0 - - jns tmp_7 - neg rdx - call rawMontgomeryMul1 - mov rsi, rdi - call rawNegL - sub rdi, 8 - pop rsi - - jmp tmp_8 -tmp_7: - call rawMontgomeryMul1 - sub rdi, 8 - pop rsi -tmp_8: - - - ret - -mul_l1ms2m: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawMontgomeryMul - sub rdi, 8 - sub rsi, 8 - - ret - - -;;;;;;;; -mul_s1l2: - bt r8, 62 ; check if montgomery first - jc mul_s1ml2 -mul_s1nl2: - bt r9, 62 ; check if montgomery first - jc mul_s1nl2m -mul_s1nl2n: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - - push rsi - lea rsi, [rdx + 8] - movsx rdx, r8d - add rdi, 8 - cmp rdx, 0 - - jns tmp_9 - neg rdx - call rawMontgomeryMul1 - mov rsi, rdi - call rawNegL - sub rdi, 8 - pop rsi - - jmp tmp_10 -tmp_9: - call rawMontgomeryMul1 - sub rdi, 8 - pop rsi -tmp_10: - - - - push rsi - add rdi, 8 - mov rsi, rdi - lea rdx, [R3] - call rawMontgomeryMul - sub rdi, 8 - pop rsi - - ret - -mul_s1nl2m: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - push rsi - lea rsi, [rdx + 8] - movsx rdx, r8d - add rdi, 8 - cmp rdx, 0 - - jns tmp_11 - neg rdx - call rawMontgomeryMul1 - mov rsi, rdi - call rawNegL - sub rdi, 8 - pop rsi - - jmp tmp_12 -tmp_11: - call rawMontgomeryMul1 - sub rdi, 8 - pop rsi -tmp_12: - - - ret - -mul_s1ml2: - bt r9, 62 ; check if montgomery first - jc mul_s1ml2m -mul_s1ml2n: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawMontgomeryMul - sub rdi, 8 - sub rsi, 8 - - ret - -mul_s1ml2m: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawMontgomeryMul - sub rdi, 8 - sub rsi, 8 - - ret - -;;;; -mul_l1l2: - bt r8, 62 ; check if montgomery first - jc mul_l1ml2 -mul_l1nl2: - bt r9, 62 ; check if montgomery second - jc mul_l1nl2m -mul_l1nl2n: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawMontgomeryMul - sub rdi, 8 - sub rsi, 8 - - - push rsi - add rdi, 8 - mov rsi, rdi - lea rdx, [R3] - call rawMontgomeryMul - sub rdi, 8 - pop rsi - - ret - -mul_l1nl2m: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawMontgomeryMul - sub rdi, 8 - sub rsi, 8 - - ret - -mul_l1ml2: - bt r9, 62 ; check if montgomery seconf - jc mul_l1ml2m -mul_l1ml2n: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawMontgomeryMul - sub rdi, 8 - sub rsi, 8 - - ret - -mul_l1ml2m: - mov r11b, 0xC0 - shl r11d, 24 - mov [rdi+4], r11d - - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawMontgomeryMul - sub rdi, 8 - sub rsi, 8 - - ret - - - - - - - - - - - - - - - - - - -;;;;;;;;;;;;;;;;;;;;;; -; band -;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result -; Modified Registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -Fr_band: - mov r8, [rsi] - mov r9, [rdx] - bt r8, 63 ; Check if is short first operand - jc and_l1 - bt r9, 63 ; Check if is short second operand - jc and_s1l2 - -and_s1s2: - - cmp r8d, 0 - - js tmp_13 - - cmp r9d, 0 - js tmp_13 - xor rdx, rdx ; both ops are positive so do the op and return - mov edx, r8d - and edx, r9d - mov [rdi], rdx ; not necessary to adjust so just save and return - ret - -tmp_13: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - push rsi - mov rdi, rdx - movsx rsi, r9d - call rawCopyS2L - mov rdx, rdi - pop rsi - pop rdi - push rdi - push rdx - mov rdi, rsi - movsx rsi, r8d - call rawCopyS2L - mov rsi, rdi - pop rdx - pop rdi - - - mov rax, [rsi + 8] - and rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - and rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - and rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - and rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_15 ; q is bigget so done. - jnz tmp_14 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_15 ; q is bigget so done. - jnz tmp_14 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_15 ; q is bigget so done. - jnz tmp_14 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_15 ; q is bigget so done. - jnz tmp_14 ; q is lower - - ; If equal substract q -tmp_14: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_15: - - ret - - - - - - -and_l1: - bt r9, 63 ; Check if is short second operand - jc and_l1l2 - - -and_l1s2: - bt r8, 62 ; check if montgomery first - jc and_l1ms2 -and_l1ns2: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - cmp r9d, 0 - - js tmp_16 - movsx rax, r9d - and rax, [rsi +8] - mov [rdi+8], rax - - xor rax, rax - and rax, [rsi + 16]; - - mov [rdi + 16 ], rax; - - xor rax, rax - and rax, [rsi + 24]; - - mov [rdi + 24 ], rax; - - xor rax, rax - and rax, [rsi + 32]; - - and rax, [lboMask] ; - - mov [rdi + 32 ], rax; - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_18 ; q is bigget so done. - jnz tmp_17 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_18 ; q is bigget so done. - jnz tmp_17 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_18 ; q is bigget so done. - jnz tmp_17 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_18 ; q is bigget so done. - jnz tmp_17 ; q is lower - - ; If equal substract q -tmp_17: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_18: - - ret - -tmp_16: - push rdi - push rsi - mov rdi, rdx - movsx rsi, r9d - call rawCopyS2L - mov rdx, rdi - pop rsi - pop rdi - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - - mov rax, [rsi + 8] - and rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - and rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - and rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - and rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_20 ; q is bigget so done. - jnz tmp_19 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_20 ; q is bigget so done. - jnz tmp_19 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_20 ; q is bigget so done. - jnz tmp_19 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_20 ; q is bigget so done. - jnz tmp_19 ; q is lower - - ; If equal substract q -tmp_19: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_20: - - ret - - - - -and_l1ms2: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push r9 ; r9 is used in montgomery so we need to save it - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi - pop r9 - - cmp r9d, 0 - - js tmp_21 - movsx rax, r9d - and rax, [rsi +8] - mov [rdi+8], rax - - xor rax, rax - and rax, [rsi + 16]; - - mov [rdi + 16 ], rax; - - xor rax, rax - and rax, [rsi + 24]; - - mov [rdi + 24 ], rax; - - xor rax, rax - and rax, [rsi + 32]; - - and rax, [lboMask] ; - - mov [rdi + 32 ], rax; - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_23 ; q is bigget so done. - jnz tmp_22 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_23 ; q is bigget so done. - jnz tmp_22 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_23 ; q is bigget so done. - jnz tmp_22 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_23 ; q is bigget so done. - jnz tmp_22 ; q is lower - - ; If equal substract q -tmp_22: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_23: - - ret - -tmp_21: - push rdi - push rsi - mov rdi, rdx - movsx rsi, r9d - call rawCopyS2L - mov rdx, rdi - pop rsi - pop rdi - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - - mov rax, [rsi + 8] - and rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - and rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - and rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - and rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_25 ; q is bigget so done. - jnz tmp_24 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_25 ; q is bigget so done. - jnz tmp_24 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_25 ; q is bigget so done. - jnz tmp_24 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_25 ; q is bigget so done. - jnz tmp_24 ; q is lower - - ; If equal substract q -tmp_24: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_25: - - ret - - - - - -and_s1l2: - bt r9, 62 ; check if montgomery first - jc and_s1l2m -and_s1l2n: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - cmp r8d, 0 - - js tmp_26 - movsx rax, r8d - and rax, [rdx +8] - mov [rdi+8], rax - - xor rax, rax - and rax, [rdx + 16] - - mov [rdi + 16 ], rax - - xor rax, rax - and rax, [rdx + 24] - - mov [rdi + 24 ], rax - - xor rax, rax - and rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_28 ; q is bigget so done. - jnz tmp_27 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_28 ; q is bigget so done. - jnz tmp_27 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_28 ; q is bigget so done. - jnz tmp_27 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_28 ; q is bigget so done. - jnz tmp_27 ; q is lower - - ; If equal substract q -tmp_27: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_28: - - ret - -tmp_26: - push rdi - push rdx - mov rdi, rsi - movsx rsi, r8d - call rawCopyS2L - mov rsi, rdi - pop rdx - pop rdi - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - - mov rax, [rsi + 8] - and rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - and rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - and rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - and rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_30 ; q is bigget so done. - jnz tmp_29 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_30 ; q is bigget so done. - jnz tmp_29 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_30 ; q is bigget so done. - jnz tmp_29 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_30 ; q is bigget so done. - jnz tmp_29 ; q is lower - - ; If equal substract q -tmp_29: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_30: - - ret - - - - -and_s1l2m: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push r8 ; r8 is used in montgomery so we need to save it - push rdi - mov rdi, rdx - call Fr_toNormal - mov rdx, rdi - pop rdi - pop r8 - - cmp r8d, 0 - - js tmp_31 - movsx rax, r8d - and rax, [rdx +8] - mov [rdi+8], rax - - xor rax, rax - and rax, [rdx + 16] - - mov [rdi + 16 ], rax - - xor rax, rax - and rax, [rdx + 24] - - mov [rdi + 24 ], rax - - xor rax, rax - and rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_33 ; q is bigget so done. - jnz tmp_32 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_33 ; q is bigget so done. - jnz tmp_32 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_33 ; q is bigget so done. - jnz tmp_32 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_33 ; q is bigget so done. - jnz tmp_32 ; q is lower - - ; If equal substract q -tmp_32: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_33: - - ret - -tmp_31: - push rdi - push rdx - mov rdi, rsi - movsx rsi, r8d - call rawCopyS2L - mov rsi, rdi - pop rdx - pop rdi - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - - mov rax, [rsi + 8] - and rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - and rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - and rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - and rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_35 ; q is bigget so done. - jnz tmp_34 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_35 ; q is bigget so done. - jnz tmp_34 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_35 ; q is bigget so done. - jnz tmp_34 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_35 ; q is bigget so done. - jnz tmp_34 ; q is lower - - ; If equal substract q -tmp_34: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_35: - - ret - - - - - -and_l1l2: - bt r8, 62 ; check if montgomery first - jc and_l1ml2 - bt r9, 62 ; check if montgomery first - jc and_l1nl2m -and_l1nl2n: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - - mov rax, [rsi + 8] - and rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - and rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - and rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - and rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_37 ; q is bigget so done. - jnz tmp_36 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_37 ; q is bigget so done. - jnz tmp_36 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_37 ; q is bigget so done. - jnz tmp_36 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_37 ; q is bigget so done. - jnz tmp_36 ; q is lower - - ; If equal substract q -tmp_36: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_37: - - ret - - -and_l1nl2m: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rdx - call Fr_toNormal - mov rdx, rdi - pop rdi - - - mov rax, [rsi + 8] - and rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - and rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - and rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - and rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_39 ; q is bigget so done. - jnz tmp_38 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_39 ; q is bigget so done. - jnz tmp_38 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_39 ; q is bigget so done. - jnz tmp_38 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_39 ; q is bigget so done. - jnz tmp_38 ; q is lower - - ; If equal substract q -tmp_38: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_39: - - ret - - -and_l1ml2: - bt r9, 62 ; check if montgomery first - jc and_l1ml2m -and_l1ml2n: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi - - - mov rax, [rsi + 8] - and rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - and rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - and rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - and rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_41 ; q is bigget so done. - jnz tmp_40 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_41 ; q is bigget so done. - jnz tmp_40 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_41 ; q is bigget so done. - jnz tmp_40 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_41 ; q is bigget so done. - jnz tmp_40 ; q is lower - - ; If equal substract q -tmp_40: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_41: - - ret - - -and_l1ml2m: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi - push rdi - mov rdi, rdx - call Fr_toNormal - mov rdx, rdi - pop rdi - - - mov rax, [rsi + 8] - and rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - and rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - and rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - and rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_43 ; q is bigget so done. - jnz tmp_42 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_43 ; q is bigget so done. - jnz tmp_42 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_43 ; q is bigget so done. - jnz tmp_42 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_43 ; q is bigget so done. - jnz tmp_42 ; q is lower - - ; If equal substract q -tmp_42: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_43: - - ret - - - -;;;;;;;;;;;;;;;;;;;;;; -; bor -;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result -; Modified Registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -Fr_bor: - mov r8, [rsi] - mov r9, [rdx] - bt r8, 63 ; Check if is short first operand - jc or_l1 - bt r9, 63 ; Check if is short second operand - jc or_s1l2 - -or_s1s2: - - cmp r8d, 0 - - js tmp_44 - - cmp r9d, 0 - js tmp_44 - xor rdx, rdx ; both ops are positive so do the op and return - mov edx, r8d - or edx, r9d - mov [rdi], rdx ; not necessary to adjust so just save and return - ret - -tmp_44: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - push rsi - mov rdi, rdx - movsx rsi, r9d - call rawCopyS2L - mov rdx, rdi - pop rsi - pop rdi - push rdi - push rdx - mov rdi, rsi - movsx rsi, r8d - call rawCopyS2L - mov rsi, rdi - pop rdx - pop rdi - - - mov rax, [rsi + 8] - or rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - or rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - or rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - or rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_46 ; q is bigget so done. - jnz tmp_45 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_46 ; q is bigget so done. - jnz tmp_45 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_46 ; q is bigget so done. - jnz tmp_45 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_46 ; q is bigget so done. - jnz tmp_45 ; q is lower - - ; If equal substract q -tmp_45: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_46: - - ret - - - - - - -or_l1: - bt r9, 63 ; Check if is short second operand - jc or_l1l2 - - -or_l1s2: - bt r8, 62 ; check if montgomery first - jc or_l1ms2 -or_l1ns2: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - cmp r9d, 0 - - js tmp_47 - movsx rax, r9d - or rax, [rsi +8] - mov [rdi+8], rax - - xor rax, rax - or rax, [rsi + 16]; - - mov [rdi + 16 ], rax; - - xor rax, rax - or rax, [rsi + 24]; - - mov [rdi + 24 ], rax; - - xor rax, rax - or rax, [rsi + 32]; - - and rax, [lboMask] ; - - mov [rdi + 32 ], rax; - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_49 ; q is bigget so done. - jnz tmp_48 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_49 ; q is bigget so done. - jnz tmp_48 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_49 ; q is bigget so done. - jnz tmp_48 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_49 ; q is bigget so done. - jnz tmp_48 ; q is lower - - ; If equal substract q -tmp_48: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_49: - - ret - -tmp_47: - push rdi - push rsi - mov rdi, rdx - movsx rsi, r9d - call rawCopyS2L - mov rdx, rdi - pop rsi - pop rdi - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - - mov rax, [rsi + 8] - or rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - or rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - or rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - or rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_51 ; q is bigget so done. - jnz tmp_50 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_51 ; q is bigget so done. - jnz tmp_50 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_51 ; q is bigget so done. - jnz tmp_50 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_51 ; q is bigget so done. - jnz tmp_50 ; q is lower - - ; If equal substract q -tmp_50: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_51: - - ret - - - - -or_l1ms2: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push r9 ; r9 is used in montgomery so we need to save it - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi - pop r9 - - cmp r9d, 0 - - js tmp_52 - movsx rax, r9d - or rax, [rsi +8] - mov [rdi+8], rax - - xor rax, rax - or rax, [rsi + 16]; - - mov [rdi + 16 ], rax; - - xor rax, rax - or rax, [rsi + 24]; - - mov [rdi + 24 ], rax; - - xor rax, rax - or rax, [rsi + 32]; - - and rax, [lboMask] ; - - mov [rdi + 32 ], rax; - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_54 ; q is bigget so done. - jnz tmp_53 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_54 ; q is bigget so done. - jnz tmp_53 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_54 ; q is bigget so done. - jnz tmp_53 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_54 ; q is bigget so done. - jnz tmp_53 ; q is lower - - ; If equal substract q -tmp_53: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_54: - - ret - -tmp_52: - push rdi - push rsi - mov rdi, rdx - movsx rsi, r9d - call rawCopyS2L - mov rdx, rdi - pop rsi - pop rdi - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - - mov rax, [rsi + 8] - or rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - or rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - or rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - or rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_56 ; q is bigget so done. - jnz tmp_55 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_56 ; q is bigget so done. - jnz tmp_55 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_56 ; q is bigget so done. - jnz tmp_55 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_56 ; q is bigget so done. - jnz tmp_55 ; q is lower - - ; If equal substract q -tmp_55: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_56: - - ret - - - - - -or_s1l2: - bt r9, 62 ; check if montgomery first - jc or_s1l2m -or_s1l2n: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - cmp r8d, 0 - - js tmp_57 - movsx rax, r8d - or rax, [rdx +8] - mov [rdi+8], rax - - xor rax, rax - or rax, [rdx + 16] - - mov [rdi + 16 ], rax - - xor rax, rax - or rax, [rdx + 24] - - mov [rdi + 24 ], rax - - xor rax, rax - or rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_59 ; q is bigget so done. - jnz tmp_58 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_59 ; q is bigget so done. - jnz tmp_58 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_59 ; q is bigget so done. - jnz tmp_58 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_59 ; q is bigget so done. - jnz tmp_58 ; q is lower - - ; If equal substract q -tmp_58: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_59: - - ret - -tmp_57: - push rdi - push rdx - mov rdi, rsi - movsx rsi, r8d - call rawCopyS2L - mov rsi, rdi - pop rdx - pop rdi - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - - mov rax, [rsi + 8] - or rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - or rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - or rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - or rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_61 ; q is bigget so done. - jnz tmp_60 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_61 ; q is bigget so done. - jnz tmp_60 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_61 ; q is bigget so done. - jnz tmp_60 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_61 ; q is bigget so done. - jnz tmp_60 ; q is lower - - ; If equal substract q -tmp_60: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_61: - - ret - - - - -or_s1l2m: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push r8 ; r8 is used in montgomery so we need to save it - push rdi - mov rdi, rdx - call Fr_toNormal - mov rdx, rdi - pop rdi - pop r8 - - cmp r8d, 0 - - js tmp_62 - movsx rax, r8d - or rax, [rdx +8] - mov [rdi+8], rax - - xor rax, rax - or rax, [rdx + 16] - - mov [rdi + 16 ], rax - - xor rax, rax - or rax, [rdx + 24] - - mov [rdi + 24 ], rax - - xor rax, rax - or rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_64 ; q is bigget so done. - jnz tmp_63 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_64 ; q is bigget so done. - jnz tmp_63 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_64 ; q is bigget so done. - jnz tmp_63 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_64 ; q is bigget so done. - jnz tmp_63 ; q is lower - - ; If equal substract q -tmp_63: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_64: - - ret - -tmp_62: - push rdi - push rdx - mov rdi, rsi - movsx rsi, r8d - call rawCopyS2L - mov rsi, rdi - pop rdx - pop rdi - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - - mov rax, [rsi + 8] - or rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - or rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - or rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - or rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_66 ; q is bigget so done. - jnz tmp_65 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_66 ; q is bigget so done. - jnz tmp_65 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_66 ; q is bigget so done. - jnz tmp_65 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_66 ; q is bigget so done. - jnz tmp_65 ; q is lower - - ; If equal substract q -tmp_65: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_66: - - ret - - - - - -or_l1l2: - bt r8, 62 ; check if montgomery first - jc or_l1ml2 - bt r9, 62 ; check if montgomery first - jc or_l1nl2m -or_l1nl2n: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - - mov rax, [rsi + 8] - or rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - or rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - or rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - or rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_68 ; q is bigget so done. - jnz tmp_67 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_68 ; q is bigget so done. - jnz tmp_67 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_68 ; q is bigget so done. - jnz tmp_67 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_68 ; q is bigget so done. - jnz tmp_67 ; q is lower - - ; If equal substract q -tmp_67: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_68: - - ret - - -or_l1nl2m: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rdx - call Fr_toNormal - mov rdx, rdi - pop rdi - - - mov rax, [rsi + 8] - or rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - or rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - or rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - or rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_70 ; q is bigget so done. - jnz tmp_69 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_70 ; q is bigget so done. - jnz tmp_69 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_70 ; q is bigget so done. - jnz tmp_69 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_70 ; q is bigget so done. - jnz tmp_69 ; q is lower - - ; If equal substract q -tmp_69: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_70: - - ret - - -or_l1ml2: - bt r9, 62 ; check if montgomery first - jc or_l1ml2m -or_l1ml2n: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi - - - mov rax, [rsi + 8] - or rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - or rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - or rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - or rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_72 ; q is bigget so done. - jnz tmp_71 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_72 ; q is bigget so done. - jnz tmp_71 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_72 ; q is bigget so done. - jnz tmp_71 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_72 ; q is bigget so done. - jnz tmp_71 ; q is lower - - ; If equal substract q -tmp_71: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_72: - - ret - - -or_l1ml2m: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi - push rdi - mov rdi, rdx - call Fr_toNormal - mov rdx, rdi - pop rdi - - - mov rax, [rsi + 8] - or rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - or rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - or rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - or rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_74 ; q is bigget so done. - jnz tmp_73 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_74 ; q is bigget so done. - jnz tmp_73 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_74 ; q is bigget so done. - jnz tmp_73 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_74 ; q is bigget so done. - jnz tmp_73 ; q is lower - - ; If equal substract q -tmp_73: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_74: - - ret - - - -;;;;;;;;;;;;;;;;;;;;;; -; bxor -;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result -; Modified Registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -Fr_bxor: - mov r8, [rsi] - mov r9, [rdx] - bt r8, 63 ; Check if is short first operand - jc xor_l1 - bt r9, 63 ; Check if is short second operand - jc xor_s1l2 - -xor_s1s2: - - cmp r8d, 0 - - js tmp_75 - - cmp r9d, 0 - js tmp_75 - xor rdx, rdx ; both ops are positive so do the op and return - mov edx, r8d - xor edx, r9d - mov [rdi], rdx ; not necessary to adjust so just save and return - ret - -tmp_75: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - push rsi - mov rdi, rdx - movsx rsi, r9d - call rawCopyS2L - mov rdx, rdi - pop rsi - pop rdi - push rdi - push rdx - mov rdi, rsi - movsx rsi, r8d - call rawCopyS2L - mov rsi, rdi - pop rdx - pop rdi - - - mov rax, [rsi + 8] - xor rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - xor rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - xor rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - xor rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_77 ; q is bigget so done. - jnz tmp_76 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_77 ; q is bigget so done. - jnz tmp_76 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_77 ; q is bigget so done. - jnz tmp_76 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_77 ; q is bigget so done. - jnz tmp_76 ; q is lower - - ; If equal substract q -tmp_76: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_77: - - ret - - - - - - -xor_l1: - bt r9, 63 ; Check if is short second operand - jc xor_l1l2 - - -xor_l1s2: - bt r8, 62 ; check if montgomery first - jc xor_l1ms2 -xor_l1ns2: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - cmp r9d, 0 - - js tmp_78 - movsx rax, r9d - xor rax, [rsi +8] - mov [rdi+8], rax - - xor rax, rax - xor rax, [rsi + 16]; - - mov [rdi + 16 ], rax; - - xor rax, rax - xor rax, [rsi + 24]; - - mov [rdi + 24 ], rax; - - xor rax, rax - xor rax, [rsi + 32]; - - and rax, [lboMask] ; - - mov [rdi + 32 ], rax; - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_80 ; q is bigget so done. - jnz tmp_79 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_80 ; q is bigget so done. - jnz tmp_79 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_80 ; q is bigget so done. - jnz tmp_79 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_80 ; q is bigget so done. - jnz tmp_79 ; q is lower - - ; If equal substract q -tmp_79: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_80: - - ret - -tmp_78: - push rdi - push rsi - mov rdi, rdx - movsx rsi, r9d - call rawCopyS2L - mov rdx, rdi - pop rsi - pop rdi - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - - mov rax, [rsi + 8] - xor rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - xor rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - xor rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - xor rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_82 ; q is bigget so done. - jnz tmp_81 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_82 ; q is bigget so done. - jnz tmp_81 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_82 ; q is bigget so done. - jnz tmp_81 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_82 ; q is bigget so done. - jnz tmp_81 ; q is lower - - ; If equal substract q -tmp_81: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_82: - - ret - - - - -xor_l1ms2: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push r9 ; r9 is used in montgomery so we need to save it - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi - pop r9 - - cmp r9d, 0 - - js tmp_83 - movsx rax, r9d - xor rax, [rsi +8] - mov [rdi+8], rax - - xor rax, rax - xor rax, [rsi + 16]; - - mov [rdi + 16 ], rax; - - xor rax, rax - xor rax, [rsi + 24]; - - mov [rdi + 24 ], rax; - - xor rax, rax - xor rax, [rsi + 32]; - - and rax, [lboMask] ; - - mov [rdi + 32 ], rax; - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_85 ; q is bigget so done. - jnz tmp_84 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_85 ; q is bigget so done. - jnz tmp_84 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_85 ; q is bigget so done. - jnz tmp_84 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_85 ; q is bigget so done. - jnz tmp_84 ; q is lower - - ; If equal substract q -tmp_84: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_85: - - ret - -tmp_83: - push rdi - push rsi - mov rdi, rdx - movsx rsi, r9d - call rawCopyS2L - mov rdx, rdi - pop rsi - pop rdi - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - - mov rax, [rsi + 8] - xor rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - xor rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - xor rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - xor rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_87 ; q is bigget so done. - jnz tmp_86 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_87 ; q is bigget so done. - jnz tmp_86 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_87 ; q is bigget so done. - jnz tmp_86 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_87 ; q is bigget so done. - jnz tmp_86 ; q is lower - - ; If equal substract q -tmp_86: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_87: - - ret - - - - - -xor_s1l2: - bt r9, 62 ; check if montgomery first - jc xor_s1l2m -xor_s1l2n: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - cmp r8d, 0 - - js tmp_88 - movsx rax, r8d - xor rax, [rdx +8] - mov [rdi+8], rax - - xor rax, rax - xor rax, [rdx + 16] - - mov [rdi + 16 ], rax - - xor rax, rax - xor rax, [rdx + 24] - - mov [rdi + 24 ], rax - - xor rax, rax - xor rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_90 ; q is bigget so done. - jnz tmp_89 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_90 ; q is bigget so done. - jnz tmp_89 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_90 ; q is bigget so done. - jnz tmp_89 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_90 ; q is bigget so done. - jnz tmp_89 ; q is lower - - ; If equal substract q -tmp_89: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_90: - - ret - -tmp_88: - push rdi - push rdx - mov rdi, rsi - movsx rsi, r8d - call rawCopyS2L - mov rsi, rdi - pop rdx - pop rdi - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - - mov rax, [rsi + 8] - xor rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - xor rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - xor rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - xor rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_92 ; q is bigget so done. - jnz tmp_91 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_92 ; q is bigget so done. - jnz tmp_91 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_92 ; q is bigget so done. - jnz tmp_91 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_92 ; q is bigget so done. - jnz tmp_91 ; q is lower - - ; If equal substract q -tmp_91: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_92: - - ret - - - - -xor_s1l2m: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push r8 ; r8 is used in montgomery so we need to save it - push rdi - mov rdi, rdx - call Fr_toNormal - mov rdx, rdi - pop rdi - pop r8 - - cmp r8d, 0 - - js tmp_93 - movsx rax, r8d - xor rax, [rdx +8] - mov [rdi+8], rax - - xor rax, rax - xor rax, [rdx + 16] - - mov [rdi + 16 ], rax - - xor rax, rax - xor rax, [rdx + 24] - - mov [rdi + 24 ], rax - - xor rax, rax - xor rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_95 ; q is bigget so done. - jnz tmp_94 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_95 ; q is bigget so done. - jnz tmp_94 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_95 ; q is bigget so done. - jnz tmp_94 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_95 ; q is bigget so done. - jnz tmp_94 ; q is lower - - ; If equal substract q -tmp_94: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_95: - - ret - -tmp_93: - push rdi - push rdx - mov rdi, rsi - movsx rsi, r8d - call rawCopyS2L - mov rsi, rdi - pop rdx - pop rdi - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - - mov rax, [rsi + 8] - xor rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - xor rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - xor rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - xor rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_97 ; q is bigget so done. - jnz tmp_96 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_97 ; q is bigget so done. - jnz tmp_96 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_97 ; q is bigget so done. - jnz tmp_96 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_97 ; q is bigget so done. - jnz tmp_96 ; q is lower - - ; If equal substract q -tmp_96: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_97: - - ret - - - - - -xor_l1l2: - bt r8, 62 ; check if montgomery first - jc xor_l1ml2 - bt r9, 62 ; check if montgomery first - jc xor_l1nl2m -xor_l1nl2n: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - - mov rax, [rsi + 8] - xor rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - xor rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - xor rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - xor rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_99 ; q is bigget so done. - jnz tmp_98 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_99 ; q is bigget so done. - jnz tmp_98 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_99 ; q is bigget so done. - jnz tmp_98 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_99 ; q is bigget so done. - jnz tmp_98 ; q is lower - - ; If equal substract q -tmp_98: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_99: - - ret - - -xor_l1nl2m: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rdx - call Fr_toNormal - mov rdx, rdi - pop rdi - - - mov rax, [rsi + 8] - xor rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - xor rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - xor rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - xor rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_101 ; q is bigget so done. - jnz tmp_100 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_101 ; q is bigget so done. - jnz tmp_100 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_101 ; q is bigget so done. - jnz tmp_100 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_101 ; q is bigget so done. - jnz tmp_100 ; q is lower - - ; If equal substract q -tmp_100: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_101: - - ret - - -xor_l1ml2: - bt r9, 62 ; check if montgomery first - jc xor_l1ml2m -xor_l1ml2n: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi - - - mov rax, [rsi + 8] - xor rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - xor rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - xor rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - xor rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_103 ; q is bigget so done. - jnz tmp_102 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_103 ; q is bigget so done. - jnz tmp_102 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_103 ; q is bigget so done. - jnz tmp_102 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_103 ; q is bigget so done. - jnz tmp_102 ; q is lower - - ; If equal substract q -tmp_102: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_103: - - ret - - -xor_l1ml2m: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi - push rdi - mov rdi, rdx - call Fr_toNormal - mov rdx, rdi - pop rdi - - - mov rax, [rsi + 8] - xor rax, [rdx + 8] - - mov [rdi + 8 ], rax - - mov rax, [rsi + 16] - xor rax, [rdx + 16] - - mov [rdi + 16 ], rax - - mov rax, [rsi + 24] - xor rax, [rdx + 24] - - mov [rdi + 24 ], rax - - mov rax, [rsi + 32] - xor rax, [rdx + 32] - - and rax, [lboMask] - - mov [rdi + 32 ], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_105 ; q is bigget so done. - jnz tmp_104 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_105 ; q is bigget so done. - jnz tmp_104 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_105 ; q is bigget so done. - jnz tmp_104 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_105 ; q is bigget so done. - jnz tmp_104 ; q is lower - - ; If equal substract q -tmp_104: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_105: - - ret - - - - -;;;;;;;;;;;;;;;;;;;;;; -; bnot -;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdi <= Pointer to result -; Modified Registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -Fr_bnot: - mov r11b, 0x80 - shl r11d, 24 - mov [rdi+4], r11d - - mov r8, [rsi] - bt r8, 63 ; Check if is long operand - jc bnot_l1 -bnot_s: - push rdi - push rdx - mov rdi, rsi - movsx rsi, r8d - call rawCopyS2L - mov rsi, rdi - pop rdx - pop rdi - jmp bnot_l1n - -bnot_l1: - bt r8, 62 ; check if montgomery first - jnc bnot_l1n - -bnot_l1m: - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi - -bnot_l1n: - - mov rax, [rsi + 8] - not rax - - mov [rdi + 8], rax - - mov rax, [rsi + 16] - not rax - - mov [rdi + 16], rax - - mov rax, [rsi + 24] - not rax - - mov [rdi + 24], rax - - mov rax, [rsi + 32] - not rax - - and rax, [lboMask] - - mov [rdi + 32], rax - - - - - - ; Compare with q - - mov rax, [rdi + 32] - cmp rax, [q + 24] - jc tmp_107 ; q is bigget so done. - jnz tmp_106 ; q is lower - - mov rax, [rdi + 24] - cmp rax, [q + 16] - jc tmp_107 ; q is bigget so done. - jnz tmp_106 ; q is lower - - mov rax, [rdi + 16] - cmp rax, [q + 8] - jc tmp_107 ; q is bigget so done. - jnz tmp_106 ; q is lower - - mov rax, [rdi + 8] - cmp rax, [q + 0] - jc tmp_107 ; q is bigget so done. - jnz tmp_106 ; q is lower - - ; If equal substract q -tmp_106: - - mov rax, [q + 0] - sub [rdi + 8], rax - - mov rax, [q + 8] - sbb [rdi + 16], rax - - mov rax, [q + 16] - sbb [rdi + 24], rax - - mov rax, [q + 24] - sbb [rdi + 32], rax - -tmp_107: - - ret - - - - - - -;;;;;;;;;;;;;;;;;;;;;; -; rgt - Raw Greater Than -;;;;;;;;;;;;;;;;;;;;;; -; returns in ax 1 id *rsi > *rdx -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rax <= Return 1 or 0 -; Modified Registers: -; r8, r9, rax -;;;;;;;;;;;;;;;;;;;;;; -Fr_rgt: - mov r8, [rsi] - mov r9, [rdx] - bt r8, 63 ; Check if is short first operand - jc rgt_l1 - bt r9, 63 ; Check if is short second operand - jc rgt_s1l2 - -rgt_s1s2: ; Both operands are short - cmp r8d, r9d - jg rgt_ret1 - jmp rgt_ret0 - - -rgt_l1: - bt r9, 63 ; Check if is short second operand - jc rgt_l1l2 - -;;;;;;;; -rgt_l1s2: - bt r8, 62 ; check if montgomery first - jc rgt_l1ms2 -rgt_l1ns2: - push rdi - push rsi - mov rdi, rdx - movsx rsi, r9d - call rawCopyS2L - mov rdx, rdi - pop rsi - pop rdi - jmp rgtL1L2 - -rgt_l1ms2: - push rdi - push rsi - mov rdi, rdx - movsx rsi, r9d - call rawCopyS2L - mov rdx, rdi - pop rsi - pop rdi - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi - jmp rgtL1L2 - - -;;;;;;;; -rgt_s1l2: - bt r9, 62 ; check if montgomery second - jc rgt_s1l2m -rgt_s1l2n: - push rdi - push rdx - mov rdi, rsi - movsx rsi, r8d - call rawCopyS2L - mov rsi, rdi - pop rdx - pop rdi - jmp rgtL1L2 - -rgt_s1l2m: - push rdi - push rdx - mov rdi, rsi - movsx rsi, r8d - call rawCopyS2L - mov rsi, rdi - pop rdx - pop rdi - push rdi - mov rdi, rdx - call Fr_toNormal - mov rdx, rdi - pop rdi - jmp rgtL1L2 - -;;;; -rgt_l1l2: - bt r8, 62 ; check if montgomery first - jc rgt_l1ml2 -rgt_l1nl2: - bt r9, 62 ; check if montgomery second - jc rgt_l1nl2m -rgt_l1nl2n: - jmp rgtL1L2 - -rgt_l1nl2m: - push rdi - mov rdi, rdx - call Fr_toNormal - mov rdx, rdi - pop rdi - jmp rgtL1L2 - -rgt_l1ml2: - bt r9, 62 ; check if montgomery second - jc rgt_l1ml2m -rgt_l1ml2n: - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi - jmp rgtL1L2 - -rgt_l1ml2m: - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi - push rdi - mov rdi, rdx - call Fr_toNormal - mov rdx, rdi - pop rdi - jmp rgtL1L2 - - -;;;;;; -; rgtL1L2 -;;;;;; - -rgtL1L2: - - - mov rax, [rsi + 32] - cmp [half + 24], rax ; comare with (q-1)/2 - jc rgtl1l2_n1 ; half e1-e2 is neg => e1 < e2 - - jnz rgtl1l2_p1 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rsi + 24] - cmp [half + 16], rax ; comare with (q-1)/2 - jc rgtl1l2_n1 ; half e1-e2 is neg => e1 < e2 - - jnz rgtl1l2_p1 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rsi + 16] - cmp [half + 8], rax ; comare with (q-1)/2 - jc rgtl1l2_n1 ; half e1-e2 is neg => e1 < e2 - - jnz rgtl1l2_p1 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rsi + 8] - cmp [half + 0], rax ; comare with (q-1)/2 - jc rgtl1l2_n1 ; half e1-e2 is neg => e1 < e2 - - jmp rgtl1l2_p1 - - - -rgtl1l2_p1: - - - mov rax, [rdx + 32] - cmp [half + 24], rax ; comare with (q-1)/2 - jc rgt_ret1 ; half e1-e2 is neg => e1 < e2 - - jnz rgtRawL1L2 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rdx + 24] - cmp [half + 16], rax ; comare with (q-1)/2 - jc rgt_ret1 ; half e1-e2 is neg => e1 < e2 - - jnz rgtRawL1L2 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rdx + 16] - cmp [half + 8], rax ; comare with (q-1)/2 - jc rgt_ret1 ; half e1-e2 is neg => e1 < e2 - - jnz rgtRawL1L2 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rdx + 8] - cmp [half + 0], rax ; comare with (q-1)/2 - jc rgt_ret1 ; half e1-e2 is neg => e1 < e2 - - jmp rgtRawL1L2 - - - - -rgtl1l2_n1: - - - mov rax, [rdx + 32] - cmp [half + 24], rax ; comare with (q-1)/2 - jc rgtRawL1L2 ; half e1-e2 is neg => e1 < e2 - - jnz rgt_ret0 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rdx + 24] - cmp [half + 16], rax ; comare with (q-1)/2 - jc rgtRawL1L2 ; half e1-e2 is neg => e1 < e2 - - jnz rgt_ret0 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rdx + 16] - cmp [half + 8], rax ; comare with (q-1)/2 - jc rgtRawL1L2 ; half e1-e2 is neg => e1 < e2 - - jnz rgt_ret0 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rdx + 8] - cmp [half + 0], rax ; comare with (q-1)/2 - jc rgtRawL1L2 ; half e1-e2 is neg => e1 < e2 - - jmp rgt_ret0 - - - - - -rgtRawL1L2: - - mov rax, [rsi + 32] - cmp [rdx + 32], rax ; comare with (q-1)/2 - jc rgt_ret1 ; rsi 1st > 2nd - - jnz rgt_ret0 - - - mov rax, [rsi + 24] - cmp [rdx + 24], rax ; comare with (q-1)/2 - jc rgt_ret1 ; rsi 1st > 2nd - - jnz rgt_ret0 - - - mov rax, [rsi + 16] - cmp [rdx + 16], rax ; comare with (q-1)/2 - jc rgt_ret1 ; rsi 1st > 2nd - - jnz rgt_ret0 - - - mov rax, [rsi + 8] - cmp [rdx + 8], rax ; comare with (q-1)/2 - jc rgt_ret1 ; rsi 1st > 2nd - - - -rgt_ret0: - xor rax, rax - ret -rgt_ret1: - mov rax, 1 - ret - - - -;;;;;;;;;;;;;;;;;;;;;; -; rlt - Raw Less Than -;;;;;;;;;;;;;;;;;;;;;; -; returns in ax 1 id *rsi > *rdx -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rax <= Return 1 or 0 -; Modified Registers: -; r8, r9, rax -;;;;;;;;;;;;;;;;;;;;;; -Fr_rlt: - mov r8, [rsi] - mov r9, [rdx] - bt r8, 63 ; Check if is short first operand - jc rlt_l1 - bt r9, 63 ; Check if is short second operand - jc rlt_s1l2 - -rlt_s1s2: ; Both operands are short - cmp r8d, r9d - jl rlt_ret1 - jmp rlt_ret0 - - -rlt_l1: - bt r9, 63 ; Check if is short second operand - jc rlt_l1l2 - -;;;;;;;; -rlt_l1s2: - bt r8, 62 ; check if montgomery first - jc rlt_l1ms2 -rlt_l1ns2: - push rdi - push rsi - mov rdi, rdx - movsx rsi, r9d - call rawCopyS2L - mov rdx, rdi - pop rsi - pop rdi - jmp rltL1L2 - -rlt_l1ms2: - push rdi - push rsi - mov rdi, rdx - movsx rsi, r9d - call rawCopyS2L - mov rdx, rdi - pop rsi - pop rdi - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi - jmp rltL1L2 - - -;;;;;;;; -rlt_s1l2: - bt r9, 62 ; check if montgomery second - jc rlt_s1l2m -rlt_s1l2n: - push rdi - push rdx - mov rdi, rsi - movsx rsi, r8d - call rawCopyS2L - mov rsi, rdi - pop rdx - pop rdi - jmp rltL1L2 - -rlt_s1l2m: - push rdi - push rdx - mov rdi, rsi - movsx rsi, r8d - call rawCopyS2L - mov rsi, rdi - pop rdx - pop rdi - push rdi - mov rdi, rdx - call Fr_toNormal - mov rdx, rdi - pop rdi - jmp rltL1L2 - -;;;; -rlt_l1l2: - bt r8, 62 ; check if montgomery first - jc rlt_l1ml2 -rlt_l1nl2: - bt r9, 62 ; check if montgomery second - jc rlt_l1nl2m -rlt_l1nl2n: - jmp rltL1L2 - -rlt_l1nl2m: - push rdi - mov rdi, rdx - call Fr_toNormal - mov rdx, rdi - pop rdi - jmp rltL1L2 - -rlt_l1ml2: - bt r9, 62 ; check if montgomery second - jc rlt_l1ml2m -rlt_l1ml2n: - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi - jmp rltL1L2 - -rlt_l1ml2m: - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi - push rdi - mov rdi, rdx - call Fr_toNormal - mov rdx, rdi - pop rdi - jmp rltL1L2 - - -;;;;;; -; rltL1L2 -;;;;;; - -rltL1L2: - - - mov rax, [rsi + 32] - cmp [half + 24], rax ; comare with (q-1)/2 - jc rltl1l2_n1 ; half e1-e2 is neg => e1 < e2 - - jnz rltl1l2_p1 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rsi + 24] - cmp [half + 16], rax ; comare with (q-1)/2 - jc rltl1l2_n1 ; half e1-e2 is neg => e1 < e2 - - jnz rltl1l2_p1 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rsi + 16] - cmp [half + 8], rax ; comare with (q-1)/2 - jc rltl1l2_n1 ; half e1-e2 is neg => e1 < e2 - - jnz rltl1l2_p1 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rsi + 8] - cmp [half + 0], rax ; comare with (q-1)/2 - jc rltl1l2_n1 ; half e1-e2 is neg => e1 < e2 - - jmp rltl1l2_p1 - - - -rltl1l2_p1: - - - mov rax, [rdx + 32] - cmp [half + 24], rax ; comare with (q-1)/2 - jc rlt_ret0 ; half e1-e2 is neg => e1 < e2 - - jnz rltRawL1L2 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rdx + 24] - cmp [half + 16], rax ; comare with (q-1)/2 - jc rlt_ret0 ; half e1-e2 is neg => e1 < e2 - - jnz rltRawL1L2 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rdx + 16] - cmp [half + 8], rax ; comare with (q-1)/2 - jc rlt_ret0 ; half e1-e2 is neg => e1 < e2 - - jnz rltRawL1L2 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rdx + 8] - cmp [half + 0], rax ; comare with (q-1)/2 - jc rlt_ret0 ; half e1-e2 is neg => e1 < e2 - - jmp rltRawL1L2 - - - - -rltl1l2_n1: - - - mov rax, [rdx + 32] - cmp [half + 24], rax ; comare with (q-1)/2 - jc rltRawL1L2 ; half e1-e2 is neg => e1 < e2 - - jnz rlt_ret1 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rdx + 24] - cmp [half + 16], rax ; comare with (q-1)/2 - jc rltRawL1L2 ; half e1-e2 is neg => e1 < e2 - - jnz rlt_ret1 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rdx + 16] - cmp [half + 8], rax ; comare with (q-1)/2 - jc rltRawL1L2 ; half e1-e2 is neg => e1 < e2 - - jnz rlt_ret1 ; half>rax => e1 -e2 is pos => e1 > e2 - - - mov rax, [rdx + 8] - cmp [half + 0], rax ; comare with (q-1)/2 - jc rltRawL1L2 ; half e1-e2 is neg => e1 < e2 - - jmp rlt_ret1 - - - - - -rltRawL1L2: - - mov rax, [rsi + 32] - cmp [rdx + 32], rax ; comare with (q-1)/2 - jc rlt_ret0 ; rsi 1st > 2nd - jnz rlt_ret1 - - mov rax, [rsi + 24] - cmp [rdx + 24], rax ; comare with (q-1)/2 - jc rlt_ret0 ; rsi 1st > 2nd - jnz rlt_ret1 - - mov rax, [rsi + 16] - cmp [rdx + 16], rax ; comare with (q-1)/2 - jc rlt_ret0 ; rsi 1st > 2nd - jnz rlt_ret1 - - mov rax, [rsi + 8] - cmp [rdx + 8], rax ; comare with (q-1)/2 - jc rlt_ret0 ; rsi 1st > 2nd - jnz rlt_ret1 - - -rlt_ret0: - xor rax, rax - ret -rlt_ret1: - mov rax, 1 - ret - - - -;;;;;;;;;;;;;;;;;;;;;; -; req - Raw Eq -;;;;;;;;;;;;;;;;;;;;;; -; returns in ax 1 id *rsi == *rdx -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rax <= Return 1 or 0 -; Modified Registers: -; r8, r9, rax -;;;;;;;;;;;;;;;;;;;;;; -Fr_req: - mov r8, [rsi] - mov r9, [rdx] - bt r8, 63 ; Check if is short first operand - jc req_l1 - bt r9, 63 ; Check if is short second operand - jc req_s1l2 - -req_s1s2: ; Both operands are short - cmp r8d, r9d - je req_ret1 - jmp req_ret0 - - -req_l1: - bt r9, 63 ; Check if is short second operand - jc req_l1l2 - -;;;;;;;; -req_l1s2: - bt r8, 62 ; check if montgomery first - jc req_l1ms2 -req_l1ns2: - push rdi - push rsi - mov rdi, rdx - movsx rsi, r9d - call rawCopyS2L - mov rdx, rdi - pop rsi - pop rdi - jmp reqL1L2 - -req_l1ms2: - push rdi - mov rdi, rdx - call Fr_toMontgomery - mov rdx, rdi - pop rdi - jmp reqL1L2 - - -;;;;;;;; -req_s1l2: - bt r9, 62 ; check if montgomery second - jc req_s1l2m -req_s1l2n: - push rdi - push rdx - mov rdi, rsi - movsx rsi, r8d - call rawCopyS2L - mov rsi, rdi - pop rdx - pop rdi - jmp reqL1L2 - -req_s1l2m: - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toMontgomery - mov rdx, rsi - mov rsi, rdi - pop rdi - jmp reqL1L2 - -;;;; -req_l1l2: - bt r8, 62 ; check if montgomery first - jc req_l1ml2 -req_l1nl2: - bt r9, 62 ; check if montgomery second - jc req_l1nl2m -req_l1nl2n: - jmp reqL1L2 - -req_l1nl2m: - push rdi - mov rdi, rsi - mov rsi, rdx - call Fr_toMontgomery - mov rdx, rsi - mov rsi, rdi - pop rdi - jmp reqL1L2 - -req_l1ml2: - bt r9, 62 ; check if montgomery second - jc req_l1ml2m -req_l1ml2n: - push rdi - mov rdi, rdx - call Fr_toMontgomery - mov rdx, rdi - pop rdi - jmp reqL1L2 - -req_l1ml2m: - jmp reqL1L2 - - -;;;;;; -; eqL1L2 -;;;;;; - -reqL1L2: - - mov rax, [rsi + 8] - cmp [rdx + 8], rax - jne req_ret0 ; rsi 1st > 2nd - - mov rax, [rsi + 16] - cmp [rdx + 16], rax - jne req_ret0 ; rsi 1st > 2nd - - mov rax, [rsi + 24] - cmp [rdx + 24], rax - jne req_ret0 ; rsi 1st > 2nd - - mov rax, [rsi + 32] - cmp [rdx + 32], rax - jne req_ret0 ; rsi 1st > 2nd - - -req_ret1: - mov rax, 1 - ret - -req_ret0: - xor rax, rax - ret - - -;;;;;;;;;;;;;;;;;;;;;; -; gt -;;;;;;;;;;;;;;;;;;;;;; -; Compares two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result can be zero or one. -; Modified Registers: -; rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -Fr_gt: - call Fr_rgt - mov [rdi], rax - ret - -;;;;;;;;;;;;;;;;;;;;;; -; lt -;;;;;;;;;;;;;;;;;;;;;; -; Compares two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result can be zero or one. -; Modified Registers: -; rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -Fr_lt: - call Fr_rlt - mov [rdi], rax - ret - -;;;;;;;;;;;;;;;;;;;;;; -; eq -;;;;;;;;;;;;;;;;;;;;;; -; Compares two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result can be zero or one. -; Modified Registers: -; rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -Fr_eq: - call Fr_req - mov [rdi], rax - ret - -;;;;;;;;;;;;;;;;;;;;;; -; neq -;;;;;;;;;;;;;;;;;;;;;; -; Compares two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result can be zero or one. -; Modified Registers: -; rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -Fr_neq: - call Fr_req - xor rax, 1 - mov [rdi], rax - ret - -;;;;;;;;;;;;;;;;;;;;;; -; geq -;;;;;;;;;;;;;;;;;;;;;; -; Compares two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result can be zero or one. -; Modified Registers: -; rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -Fr_geq: - call Fr_rlt - xor rax, 1 - mov [rdi], rax - ret - -;;;;;;;;;;;;;;;;;;;;;; -; leq -;;;;;;;;;;;;;;;;;;;;;; -; Compares two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result can be zero or one. -; Modified Registers: -; rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -Fr_leq: - call Fr_rgt - xor rax, 1 - mov [rdi], rax - ret - - - - - - - - - - - -;;;;;;;;;;;;;;;;;;;;;; -; land -;;;;;;;;;;;;;;;;;;;;;; -; Logical and between two elements -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result zero or one -; Modified Registers: -; rax, rcx, r8 -;;;;;;;;;;;;;;;;;;;;;; -Fr_land: - - - - - - - mov rax, [rsi] - bt rax, 63 - jc tmp_108 - - test eax, eax - jz retZero_110 - jmp retOne_109 - -tmp_108: - - mov rax, [rsi + 8] - test rax, rax - jnz retOne_109 - - mov rax, [rsi + 16] - test rax, rax - jnz retOne_109 - - mov rax, [rsi + 24] - test rax, rax - jnz retOne_109 - - mov rax, [rsi + 32] - test rax, rax - jnz retOne_109 - - -retZero_110: - mov qword r8, 0 - jmp done_111 - -retOne_109: - mov qword r8, 1 - -done_111: - - - - - - - - mov rax, [rdx] - bt rax, 63 - jc tmp_112 - - test eax, eax - jz retZero_114 - jmp retOne_113 - -tmp_112: - - mov rax, [rdx + 8] - test rax, rax - jnz retOne_113 - - mov rax, [rdx + 16] - test rax, rax - jnz retOne_113 - - mov rax, [rdx + 24] - test rax, rax - jnz retOne_113 - - mov rax, [rdx + 32] - test rax, rax - jnz retOne_113 - - -retZero_114: - mov qword rcx, 0 - jmp done_115 - -retOne_113: - mov qword rcx, 1 - -done_115: - - and rcx, r8 - mov [rdi], rcx - ret - - -;;;;;;;;;;;;;;;;;;;;;; -; lor -;;;;;;;;;;;;;;;;;;;;;; -; Logical or between two elements -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result zero or one -; Modified Registers: -; rax, rcx, r8 -;;;;;;;;;;;;;;;;;;;;;; -Fr_lor: - - - - - - - mov rax, [rsi] - bt rax, 63 - jc tmp_116 - - test eax, eax - jz retZero_118 - jmp retOne_117 - -tmp_116: - - mov rax, [rsi + 8] - test rax, rax - jnz retOne_117 - - mov rax, [rsi + 16] - test rax, rax - jnz retOne_117 - - mov rax, [rsi + 24] - test rax, rax - jnz retOne_117 - - mov rax, [rsi + 32] - test rax, rax - jnz retOne_117 - - -retZero_118: - mov qword r8, 0 - jmp done_119 - -retOne_117: - mov qword r8, 1 - -done_119: - - - - - - - - mov rax, [rdx] - bt rax, 63 - jc tmp_120 - - test eax, eax - jz retZero_122 - jmp retOne_121 - -tmp_120: - - mov rax, [rdx + 8] - test rax, rax - jnz retOne_121 - - mov rax, [rdx + 16] - test rax, rax - jnz retOne_121 - - mov rax, [rdx + 24] - test rax, rax - jnz retOne_121 - - mov rax, [rdx + 32] - test rax, rax - jnz retOne_121 - - -retZero_122: - mov qword rcx, 0 - jmp done_123 - -retOne_121: - mov qword rcx, 1 - -done_123: - - or rcx, r8 - mov [rdi], rcx - ret - - -;;;;;;;;;;;;;;;;;;;;;; -; lnot -;;;;;;;;;;;;;;;;;;;;;; -; Do the logical not of an element -; Params: -; rsi <= Pointer to element to be tested -; rdi <= Pointer to result one if element1 is zero and zero otherwise -; Modified Registers: -; rax, rax, r8 -;;;;;;;;;;;;;;;;;;;;;; -Fr_lnot: - - - - - - - mov rax, [rsi] - bt rax, 63 - jc tmp_124 - - test eax, eax - jz retZero_126 - jmp retOne_125 - -tmp_124: - - mov rax, [rsi + 8] - test rax, rax - jnz retOne_125 - - mov rax, [rsi + 16] - test rax, rax - jnz retOne_125 - - mov rax, [rsi + 24] - test rax, rax - jnz retOne_125 - - mov rax, [rsi + 32] - test rax, rax - jnz retOne_125 - - -retZero_126: - mov qword rcx, 0 - jmp done_127 - -retOne_125: - mov qword rcx, 1 - -done_127: - - test rcx, rcx - - jz lnot_retOne -lnot_retZero: - mov qword [rdi], 0 - ret -lnot_retOne: - mov qword [rdi], 1 - ret - - -;;;;;;;;;;;;;;;;;;;;;; -; isTrue -;;;;;;;;;;;;;;;;;;;;;; -; Convert a 64 bit integer to a long format field element -; Params: -; rsi <= Pointer to the element -; Returs: -; rax <= 1 if true 0 if false -;;;;;;;;;;;;;;;;;;;;;;; -Fr_isTrue: - - - - - - - mov rax, [rdi] - bt rax, 63 - jc tmp_128 - - test eax, eax - jz retZero_130 - jmp retOne_129 - -tmp_128: - - mov rax, [rdi + 8] - test rax, rax - jnz retOne_129 - - mov rax, [rdi + 16] - test rax, rax - jnz retOne_129 - - mov rax, [rdi + 24] - test rax, rax - jnz retOne_129 - - mov rax, [rdi + 32] - test rax, rax - jnz retOne_129 - - -retZero_130: - mov qword rax, 0 - jmp done_131 - -retOne_129: - mov qword rax, 1 - -done_131: - - ret - - - - - - section .data -Fr_q: - dd 0 - dd 0x80000000 -q dq 0x43e1f593f0000001,0x2833e84879b97091,0xb85045b68181585d,0x30644e72e131a029 -half dq 0xa1f0fac9f8000000,0x9419f4243cdcb848,0xdc2822db40c0ac2e,0x183227397098d014 -R2 dq 0x1bb8e645ae216da7,0x53fe3ab1e35c59e3,0x8c49833d53bb8085,0x0216d0b17f4e44a5 -R3 dq 0x5e94d8e1b4bf0040,0x2a489cbe1cfbb6b8,0x893cc664a19fcfed,0x0cf8594b7fcc657c -lboMask dq 0x3fffffffffffffff - diff --git a/ports/c/buildasm/fr.asm.ejs b/ports/c/buildasm/fr.asm.ejs deleted file mode 100644 index fa5f339..0000000 --- a/ports/c/buildasm/fr.asm.ejs +++ /dev/null @@ -1,53 +0,0 @@ - - - global <%=name%>_copy - global <%=name%>_copyn - global <%=name%>_add - global <%=name%>_sub - global <%=name%>_neg - global <%=name%>_mul - global <%=name%>_square - global <%=name%>_band - global <%=name%>_bor - global <%=name%>_bxor - global <%=name%>_bnot - global <%=name%>_eq - global <%=name%>_neq - global <%=name%>_lt - global <%=name%>_gt - global <%=name%>_leq - global <%=name%>_geq - global <%=name%>_land - global <%=name%>_lor - global <%=name%>_lnot - global <%=name%>_toNormal - global <%=name%>_toLongNormal - global <%=name%>_toMontgomery - global <%=name%>_toInt - global <%=name%>_isTrue - global <%=name%>_q - extern <%=name%>_fail - DEFAULT REL - - section .text -<%- include('utils.asm.ejs'); %> -<%- include('copy.asm.ejs'); %> -<%- include('montgomery.asm.ejs'); %> -<%- include('add.asm.ejs'); %> -<%- include('sub.asm.ejs'); %> -<%- include('neg.asm.ejs'); %> -<%- include('mul.asm.ejs'); %> -<%- include('binops.asm.ejs'); %> -<%- include('cmpops.asm.ejs'); %> -<%- include('logicalops.asm.ejs'); %> - - section .data -<%=name%>_q: - dd 0 - dd 0x80000000 -q dq <%= constantElement(q) %> -half dq <%= constantElement(q.shiftRight(1)) %> -R2 dq <%= constantElement(bigInt.one.shiftLeft(n64*64*2).mod(q)) %> -R3 dq <%= constantElement(bigInt.one.shiftLeft(n64*64*3).mod(q)) %> -lboMask dq 0x<%= bigInt("10000000000000000",16).shiftRight(n64*64 - q.bitLength()).minus(bigInt.one).toString(16) %> - diff --git a/ports/c/buildasm/fr.c b/ports/c/buildasm/fr.c deleted file mode 100644 index 8e4aec0..0000000 --- a/ports/c/buildasm/fr.c +++ /dev/null @@ -1,201 +0,0 @@ -#include "fr.h" -#include -#include -#include -#include - -mpz_t q; -mpz_t zero; -mpz_t one; -mpz_t mask; -size_t nBits; - - -void Fr_toMpz(mpz_t r, PFrElement pE) { - Fr_toNormal(pE); - if (!(pE->type & Fr_LONG)) { - mpz_set_si(r, pE->shortVal); - if (pE->shortVal<0) { - mpz_add(r, r, q); - } - } else { - Fr_toNormal(pE); - mpz_import(r, Fr_N64, -1, 8, -1, 0, (const void *)pE->longVal); - } -} - -void Fr_fromMpz(PFrElement pE, mpz_t v) { - if (mpz_fits_sint_p(v)) { - pE->type = Fr_SHORT; - pE->shortVal = mpz_get_si(v); - } else { - pE->type = Fr_LONG; - for (int i=0; ilongVal[i] = 0; - mpz_export((void *)(pE->longVal), NULL, -1, 8, -1, 0, v); - } -} - - -void Fr_init() { - mpz_init(q); - mpz_import(q, Fr_N64, -1, 8, -1, 0, (const void *)Fr_q.longVal); - mpz_init_set_ui(zero, 0); - mpz_init_set_ui(one, 1); - nBits = mpz_sizeinbase (q, 2); - mpz_init(mask); - mpz_mul_2exp(mask, one, nBits); - mpz_sub(mask, mask, one); - -} - -void Fr_str2element(PFrElement pE, char const *s) { - mpz_t mr; - mpz_init_set_str(mr, s, 10); - Fr_fromMpz(pE, mr); -} - -char *Fr_element2str(PFrElement pE) { - mpz_t r; - if (!(pE->type & Fr_LONG)) { - if (pE->shortVal>=0) { - char *r = new char[32]; - sprintf(r, "%d", pE->shortVal); - return r; - } else { - mpz_init_set_si(r, pE->shortVal); - mpz_add(r, r, q); - } - } else { - Fr_toNormal(pE); - mpz_init(r); - mpz_import(r, Fr_N64, -1, 8, -1, 0, (const void *)pE->longVal); - } - char *res = mpz_get_str (0, 10, r); - mpz_clear(r); - return res; -} - -void Fr_idiv(PFrElement r, PFrElement a, PFrElement b) { - mpz_t ma; - mpz_t mb; - mpz_t mr; - mpz_init(ma); - mpz_init(mb); - mpz_init(mr); - - Fr_toMpz(ma, a); - // char *s1 = mpz_get_str (0, 10, ma); - // printf("s1 %s\n", s1); - Fr_toMpz(mb, b); - // char *s2 = mpz_get_str (0, 10, mb); - // printf("s2 %s\n", s2); - mpz_fdiv_q(mr, ma, mb); - // char *sr = mpz_get_str (0, 10, mr); - // printf("r %s\n", sr); - Fr_fromMpz(r, mr); -} - -void Fr_mod(PFrElement r, PFrElement a, PFrElement b) { - mpz_t ma; - mpz_t mb; - mpz_t mr; - mpz_init(ma); - mpz_init(mb); - mpz_init(mr); - - Fr_toMpz(ma, a); - Fr_toMpz(mb, b); - mpz_fdiv_r(mr, ma, mb); - Fr_fromMpz(r, mr); -} - -void Fr_shl(PFrElement r, PFrElement a, PFrElement b) { - mpz_t ma; - mpz_t mb; - mpz_t mr; - mpz_init(ma); - mpz_init(mb); - mpz_init(mr); - - Fr_toMpz(ma, a); - Fr_toMpz(mb, b); - if (mpz_cmp_ui(mb, nBits) < 0) { - mpz_mul_2exp(mr, ma, mpz_get_ui(mb)); - mpz_and(mr, mr, mask); - if (mpz_cmp(mr, q) >= 0) { - mpz_sub(mr, mr, q); - } - } else { - mpz_sub(mb, q, mb); - if (mpz_cmp_ui(mb, nBits) < 0) { - mpz_tdiv_q_2exp(mr, ma, mpz_get_ui(mb)); - } else { - mpz_set(mr, zero); - } - } - Fr_fromMpz(r, mr); -} - -void Fr_shr(PFrElement r, PFrElement a, PFrElement b) { - mpz_t ma; - mpz_t mb; - mpz_t mr; - mpz_init(ma); - mpz_init(mb); - mpz_init(mr); - - Fr_toMpz(ma, a); - Fr_toMpz(mb, b); - if (mpz_cmp_ui(mb, nBits) < 0) { - mpz_tdiv_q_2exp(mr, ma, mpz_get_ui(mb)); - } else { - mpz_sub(mb, q, mb); - if (mpz_cmp_ui(mb, nBits) < 0) { - mpz_mul_2exp(mr, ma, mpz_get_ui(mb)); - mpz_and(mr, mr, mask); - if (mpz_cmp(mr, q) >= 0) { - mpz_sub(mr, mr, q); - } - } else { - mpz_set(mr, zero); - } - } - Fr_fromMpz(r, mr); -} - - -void Fr_pow(PFrElement r, PFrElement a, PFrElement b) { - mpz_t ma; - mpz_t mb; - mpz_t mr; - mpz_init(ma); - mpz_init(mb); - mpz_init(mr); - - Fr_toMpz(ma, a); - Fr_toMpz(mb, b); - mpz_powm(mr, ma, mb, q); - Fr_fromMpz(r, mr); -} - -void Fr_inv(PFrElement r, PFrElement a) { - mpz_t ma; - mpz_t mr; - mpz_init(ma); - mpz_init(mr); - - Fr_toMpz(ma, a); - mpz_invert(mr, ma, q); - Fr_fromMpz(r, mr); -} - -void Fr_div(PFrElement r, PFrElement a, PFrElement b) { - FrElement tmp; - Fr_inv(&tmp, b); - Fr_mul(r, a, &tmp); -} - -void Fr_fail() { - assert(false); -} - diff --git a/ports/c/buildasm/fr.c.ejs b/ports/c/buildasm/fr.c.ejs deleted file mode 100644 index 962b6c1..0000000 --- a/ports/c/buildasm/fr.c.ejs +++ /dev/null @@ -1,201 +0,0 @@ -#include "<%=name.toLowerCase()+".h"%>" -#include -#include -#include -#include - -mpz_t q; -mpz_t zero; -mpz_t one; -mpz_t mask; -size_t nBits; - - -void <%=name%>_toMpz(mpz_t r, P<%=name%>Element pE) { - <%=name%>_toNormal(pE); - if (!(pE->type & <%=name%>_LONG)) { - mpz_set_si(r, pE->shortVal); - if (pE->shortVal<0) { - mpz_add(r, r, q); - } - } else { - <%=name%>_toNormal(pE); - mpz_import(r, <%=name%>_N64, -1, 8, -1, 0, (const void *)pE->longVal); - } -} - -void <%=name%>_fromMpz(P<%=name%>Element pE, mpz_t v) { - if (mpz_fits_sint_p(v)) { - pE->type = <%=name%>_SHORT; - pE->shortVal = mpz_get_si(v); - } else { - pE->type = <%=name%>_LONG; - for (int i=0; i<<%=name%>_N64; i++) pE->longVal[i] = 0; - mpz_export((void *)(pE->longVal), NULL, -1, 8, -1, 0, v); - } -} - - -void <%=name%>_init() { - mpz_init(q); - mpz_import(q, <%=name%>_N64, -1, 8, -1, 0, (const void *)Fr_q.longVal); - mpz_init_set_ui(zero, 0); - mpz_init_set_ui(one, 1); - nBits = mpz_sizeinbase (q, 2); - mpz_init(mask); - mpz_mul_2exp(mask, one, nBits); - mpz_sub(mask, mask, one); - -} - -void <%=name%>_str2element(P<%=name%>Element pE, char const *s) { - mpz_t mr; - mpz_init_set_str(mr, s, 10); - <%=name%>_fromMpz(pE, mr); -} - -char *<%=name%>_element2str(P<%=name%>Element pE) { - mpz_t r; - if (!(pE->type & <%=name%>_LONG)) { - if (pE->shortVal>=0) { - char *r = new char[32]; - sprintf(r, "%d", pE->shortVal); - return r; - } else { - mpz_init_set_si(r, pE->shortVal); - mpz_add(r, r, q); - } - } else { - <%=name%>_toNormal(pE); - mpz_init(r); - mpz_import(r, <%=name%>_N64, -1, 8, -1, 0, (const void *)pE->longVal); - } - char *res = mpz_get_str (0, 10, r); - mpz_clear(r); - return res; -} - -void <%=name%>_idiv(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) { - mpz_t ma; - mpz_t mb; - mpz_t mr; - mpz_init(ma); - mpz_init(mb); - mpz_init(mr); - - <%=name%>_toMpz(ma, a); - // char *s1 = mpz_get_str (0, 10, ma); - // printf("s1 %s\n", s1); - <%=name%>_toMpz(mb, b); - // char *s2 = mpz_get_str (0, 10, mb); - // printf("s2 %s\n", s2); - mpz_fdiv_q(mr, ma, mb); - // char *sr = mpz_get_str (0, 10, mr); - // printf("r %s\n", sr); - <%=name%>_fromMpz(r, mr); -} - -void <%=name%>_mod(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) { - mpz_t ma; - mpz_t mb; - mpz_t mr; - mpz_init(ma); - mpz_init(mb); - mpz_init(mr); - - <%=name%>_toMpz(ma, a); - <%=name%>_toMpz(mb, b); - mpz_fdiv_r(mr, ma, mb); - <%=name%>_fromMpz(r, mr); -} - -void <%=name%>_shl(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) { - mpz_t ma; - mpz_t mb; - mpz_t mr; - mpz_init(ma); - mpz_init(mb); - mpz_init(mr); - - <%=name%>_toMpz(ma, a); - <%=name%>_toMpz(mb, b); - if (mpz_cmp_ui(mb, nBits) < 0) { - mpz_mul_2exp(mr, ma, mpz_get_ui(mb)); - mpz_and(mr, mr, mask); - if (mpz_cmp(mr, q) >= 0) { - mpz_sub(mr, mr, q); - } - } else { - mpz_sub(mb, q, mb); - if (mpz_cmp_ui(mb, nBits) < 0) { - mpz_tdiv_q_2exp(mr, ma, mpz_get_ui(mb)); - } else { - mpz_set(mr, zero); - } - } - <%=name%>_fromMpz(r, mr); -} - -void <%=name%>_shr(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) { - mpz_t ma; - mpz_t mb; - mpz_t mr; - mpz_init(ma); - mpz_init(mb); - mpz_init(mr); - - <%=name%>_toMpz(ma, a); - <%=name%>_toMpz(mb, b); - if (mpz_cmp_ui(mb, nBits) < 0) { - mpz_tdiv_q_2exp(mr, ma, mpz_get_ui(mb)); - } else { - mpz_sub(mb, q, mb); - if (mpz_cmp_ui(mb, nBits) < 0) { - mpz_mul_2exp(mr, ma, mpz_get_ui(mb)); - mpz_and(mr, mr, mask); - if (mpz_cmp(mr, q) >= 0) { - mpz_sub(mr, mr, q); - } - } else { - mpz_set(mr, zero); - } - } - <%=name%>_fromMpz(r, mr); -} - - -void <%=name%>_pow(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) { - mpz_t ma; - mpz_t mb; - mpz_t mr; - mpz_init(ma); - mpz_init(mb); - mpz_init(mr); - - <%=name%>_toMpz(ma, a); - <%=name%>_toMpz(mb, b); - mpz_powm(mr, ma, mb, q); - <%=name%>_fromMpz(r, mr); -} - -void <%=name%>_inv(P<%=name%>Element r, P<%=name%>Element a) { - mpz_t ma; - mpz_t mr; - mpz_init(ma); - mpz_init(mr); - - <%=name%>_toMpz(ma, a); - mpz_invert(mr, ma, q); - <%=name%>_fromMpz(r, mr); -} - -void <%=name%>_div(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b) { - <%=name%>Element tmp; - <%=name%>_inv(&tmp, b); - <%=name%>_mul(r, a, &tmp); -} - -void <%=name%>_fail() { - assert(false); -} - diff --git a/ports/c/buildasm/fr.h b/ports/c/buildasm/fr.h deleted file mode 100644 index 9cc2378..0000000 --- a/ports/c/buildasm/fr.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef __FR_H -#define __FR_H - -#include -#define Fr_N64 4 -#define Fr_SHORT 0x00000000 -#define Fr_LONG 0x80000000 -#define Fr_LONGMONTGOMERY 0xC0000000 -typedef struct __attribute__((__packed__)) { - int32_t shortVal; - uint32_t type; - uint64_t longVal[Fr_N64]; -} FrElement; -typedef FrElement *PFrElement; -extern FrElement Fr_q; -extern "C" void Fr_copy(PFrElement r, PFrElement a); -extern "C" void Fr_copyn(PFrElement r, PFrElement a, int n); -extern "C" void Fr_add(PFrElement r, PFrElement a, PFrElement b); -extern "C" void Fr_sub(PFrElement r, PFrElement a, PFrElement b); -extern "C" void Fr_neg(PFrElement r, PFrElement a); -extern "C" void Fr_mul(PFrElement r, PFrElement a, PFrElement b); -extern "C" void Fr_square(PFrElement r, PFrElement a); -extern "C" void Fr_band(PFrElement r, PFrElement a, PFrElement b); -extern "C" void Fr_bor(PFrElement r, PFrElement a, PFrElement b); -extern "C" void Fr_bxor(PFrElement r, PFrElement a, PFrElement b); -extern "C" void Fr_bnot(PFrElement r, PFrElement a); -extern "C" void Fr_eq(PFrElement r, PFrElement a, PFrElement b); -extern "C" void Fr_neq(PFrElement r, PFrElement a, PFrElement b); -extern "C" void Fr_lt(PFrElement r, PFrElement a, PFrElement b); -extern "C" void Fr_gt(PFrElement r, PFrElement a, PFrElement b); -extern "C" void Fr_leq(PFrElement r, PFrElement a, PFrElement b); -extern "C" void Fr_geq(PFrElement r, PFrElement a, PFrElement b); -extern "C" void Fr_land(PFrElement r, PFrElement a, PFrElement b); -extern "C" void Fr_lor(PFrElement r, PFrElement a, PFrElement b); -extern "C" void Fr_lnot(PFrElement r, PFrElement a); -extern "C" void Fr_toNormal(PFrElement pE); -extern "C" void Fr_toLongNormal(PFrElement pE); -extern "C" void Fr_toMontgomery(PFrElement pE); - -extern "C" int Fr_isTrue(PFrElement pE); -extern "C" int Fr_toInt(PFrElement pE); - -extern "C" void Fr_fail(); - -extern FrElement Fr_q; - -// Pending functions to convert - -void Fr_str2element(PFrElement pE, char const*s); -char *Fr_element2str(PFrElement pE); -void Fr_idiv(PFrElement r, PFrElement a, PFrElement b); -void Fr_mod(PFrElement r, PFrElement a, PFrElement b); -void Fr_inv(PFrElement r, PFrElement a); -void Fr_div(PFrElement r, PFrElement a, PFrElement b); -void Fr_shl(PFrElement r, PFrElement a, PFrElement b); -void Fr_shr(PFrElement r, PFrElement a, PFrElement b); -void Fr_pow(PFrElement r, PFrElement a, PFrElement b); - - -void Fr_init(); - - - -#endif // __FR_H - - - diff --git a/ports/c/buildasm/fr.h.ejs b/ports/c/buildasm/fr.h.ejs deleted file mode 100644 index 3359223..0000000 --- a/ports/c/buildasm/fr.h.ejs +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef __<%=name.toUpperCase()%>_H -#define __<%=name.toUpperCase()%>_H - -#include -#define <%=name%>_N64 <%= n64 %> -#define <%=name%>_SHORT 0x00000000 -#define <%=name%>_LONG 0x80000000 -#define <%=name%>_LONGMONTGOMERY 0xC0000000 -typedef struct __attribute__((__packed__)) { - int32_t shortVal; - uint32_t type; - uint64_t longVal[<%=name%>_N64]; -} <%=name%>Element; -typedef <%=name%>Element *P<%=name%>Element; -extern <%=name%>Element <%=name%>_q; -extern "C" void <%=name%>_copy(P<%=name%>Element r, P<%=name%>Element a); -extern "C" void <%=name%>_copyn(P<%=name%>Element r, P<%=name%>Element a, int n); -extern "C" void <%=name%>_add(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -extern "C" void <%=name%>_sub(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -extern "C" void <%=name%>_neg(P<%=name%>Element r, P<%=name%>Element a); -extern "C" void <%=name%>_mul(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -extern "C" void <%=name%>_square(P<%=name%>Element r, P<%=name%>Element a); -extern "C" void <%=name%>_band(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -extern "C" void <%=name%>_bor(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -extern "C" void <%=name%>_bxor(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -extern "C" void <%=name%>_bnot(P<%=name%>Element r, P<%=name%>Element a); -extern "C" void <%=name%>_eq(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -extern "C" void <%=name%>_neq(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -extern "C" void <%=name%>_lt(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -extern "C" void <%=name%>_gt(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -extern "C" void <%=name%>_leq(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -extern "C" void <%=name%>_geq(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -extern "C" void <%=name%>_land(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -extern "C" void <%=name%>_lor(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -extern "C" void <%=name%>_lnot(P<%=name%>Element r, P<%=name%>Element a); -extern "C" void <%=name%>_toNormal(P<%=name%>Element pE); -extern "C" void <%=name%>_toLongNormal(P<%=name%>Element pE); -extern "C" void <%=name%>_toMontgomery(P<%=name%>Element pE); - -extern "C" int <%=name%>_isTrue(P<%=name%>Element pE); -extern "C" int <%=name%>_toInt(P<%=name%>Element pE); - -extern "C" void <%=name%>_fail(); - -extern <%=name%>Element <%=name%>_q; - -// Pending functions to convert - -void <%=name%>_str2element(P<%=name%>Element pE, char const*s); -char *<%=name%>_element2str(P<%=name%>Element pE); -void <%=name%>_idiv(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -void <%=name%>_mod(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -void <%=name%>_inv(P<%=name%>Element r, P<%=name%>Element a); -void <%=name%>_div(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -void <%=name%>_shl(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -void <%=name%>_shr(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); -void <%=name%>_pow(P<%=name%>Element r, P<%=name%>Element a, P<%=name%>Element b); - - -void <%=name%>_init(); - - - -#endif // __<%=name.toUpperCase()%>_H - - - diff --git a/ports/c/buildasm/fr.o b/ports/c/buildasm/fr.o deleted file mode 100644 index 7bf2b66c4b2156211413b14de5dd0f040b59f0e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30956 zcmeI533OG})yE$o5XOWu1rPy2nFRAPM-U7GzG%?OAPztb5I_tGyd(vuibTUb(fA_tc5d8F8w!&K9T`T<0@7{Cv*=L{O zo_pVW`s%(f_SX*tYSjtIKk`>w{#-&;jyCdF;ZimK6Y6j0J8EG$JQkY){d4w2b8?FF zW)w?;BPVD0pmT?N6xHYZS=zHV>6AdAwHm1(m}yt+-<+KBxy8BBGdVc}GlyqJ*|T#q zr{2QPXpX8Wts-9jI-VT}TrX`YzbFtmAy(Qmr(US6erV3%m{8eiF`{vzaiZ~}@uD3? zJFdzq+mThacS&8b5UTtrRJP*#uR{-Hm#xk&dv(=QGeavrNLMSR`vWstgvzGJgo5SH zjGEBmp*kt*j=QvG^#M6TWjjL6>&Cc~QlFzZBPpWS)LSb&r+z5*uOIXe9~Bx`zDkq* zit1LxHdg1w<+2r_727(L937f-R$SgF=HYob*bwQ~j9HPM=jnmWUKJA_JC)DjCLm&-{TDLJ9i&m}4wvtE#Pe0A$LAFdn{ zEFThFHzc@8qgmN0t5$hdvyEA$n*!Nosg?N7#JNhMC(M%7 z5WuG9e3fv8<_zqjw#}JnHgnOu ziJo;XYF|Yydhs6EMGPMlaOaWu7>$>VcITt-j1;WeD`u-|FL;icOVQHisQKib%`S_T z!9nY#_Grjtj#cX}tE+0*y}Hb*S30|FWQ-ed&PbKOn~~~)IW0~`X?EFJ@j6nk*;LX; z=0tp`kDF%U^GZ$-j1$zl!>55H-g{P>*t;NU(y)SQ{%n=}5t{J%_=3BJivrDtU9ic4Ow zwF`8*{SuR8g0HWljkd|J?s(%nn(_v~e{fc)Q{H%urfkeg9K1{FiB7CvW-@4{UWB75 zua2KR34BAyvvFk2fe)iy?yX}r&H-J!16V4LTEds24$hCF zcr8^C`-9kabv)`c|MDf8tWHM%zQQygpr}LH!CLY*KqEW#}Bn5 zCQDbwRQy3}^vw85RLL~MpUJFO@o%m~O#9RC-^!zWhAY-qvmh-@_thr;RfftoSG=gb zQnpJvy{ea$8o>X}%T4}F7RB-A>~U3s>1+K0e~}veNj`)>6aD255$-)YY^sO5x4)pT z!Ybiz;LoJbd39=sc*br%Ao`r$d_eSByZHcpP>v6${pWY&@-W^?#_(Uo$v~+2IpWXA z7!Smuk#Qb~Myc|`w_dDp$#yz9QXV)j?Qd6)gu=iPptMcz=Xc(>ZPu4&$V zwXcSOaDjiq9%>+@`ZL)u%k&N9(mk?%p5um&EGIgfAH|(9vcmW#r7RbNG3Az;L(IOx z&e4Ns-;@4E9?DmJDHMszPn&%s{Y89sz13jx-kMi~4*qh7n0=SJviqtoBcJ#umaoDp zvu}kzla8wH8)Wv`pw?F`Z3IuVH(f4iFS}eazNn}7Xj?1tXxmIP+oNr>=%a13)8bc! zdM1X-(w4Z1)XpZh2X1D2;HLJ^G%bGjjI0_Mch6((e5*z~TQz>JX&&A+EYdQ4mSMkpaskGa@ z>uXi{mfmXX+pV_p{faxbyZLUL2EF}NR9$A}jblc=l4C;|gJa}fV8-CMl2-C>e2Mf# zednaU)|4ey78+|m&9L@IT4Eg?X^g$cpgpUy=hVw`-W?+^I0u%MS5{1|Bj(S^8dn~w ztO%8@uGsOJda0TEg-@zsgjVeSGP?ZO)Gyl~n%h#xP{p65i8=+xtg5NxUwtLjlk7PS z&6!>zy7}m;)5`gkS-CCZSk}08p~`LQ+i=e}&AeMOJ2zuzT`hI1iGJa8ef5fSt7Ec! zyO!3vYsuKDQ+j{JTvpLB+Z$FKr{~n|>g{=5D)ibD*cbFMWOlSA%*!qns9=j*&GK_24I^@gV$`i+%S>twA4E$6hzi&*=$f2@*&63A~M0aNY`8n=&TxZ{2t+Q{{ z?QE;A8wrp?>8gT6-)n3SNNK6xc7n2)y%WKEzenQeRNx}%=3=0PDuXO zk=F@s9jjsV?}?0l8Qjcc9p_AAmyC}7UuP0WmYo+q(!k5I;~P>((&+!KjQ%$(hU@;M zY+p|1xw;B_i_Z}d{=Od`dExi1`b>exWUW6k$B!F5tvNuM=3H4|*Q*Z%Mo{q~kogBlKpmJNxTA z4|xxwkG!RUuVF{%d9F7U&vm__c)sg1>94c``A5I)2nW~$#X&nluMvlB_x&vt}|vEM(wBRs*iBDy0yj2q&cz}}9qV6#qy=#FrVuk>|l}@9|J5F9@&IkA&UVQ(8wpeeJVW+bEmdZL8&K zycP&b000cFO9U0MDgo2L~+~i)y_~pRe#qz?Iv+AXJlW__R;1>yn5R& zTzmTvce$x|xu2bH=~e!X+jqNxxBXb}!UdA3JNFo*E;kJR7mI zuGCX!$f<~(soVSd?1WD&xxi;5+_5CvS3caVEu9_F9!Js!VMKV5VrpKKuDCIX4Wte+IgqFuwS(4 z#|Oe^|EO^wyyl&DebvPoIpjd7>s_us5I%R$0o4Y=o6(cb_!@gy_$3FzqJsy*%?A$z z{l0wFflyF=AmmmZ2t%t5gj1^ygyhITIKHG?WFWNFpS$W1mVwYzzT)N$gxV!PJ{0=v znsD{Y;^Vegsy}V5K`ZBQq#JZ|Vy{c-vDeQ)KNf)oJC2hS3xHiiq9ni6)o(+7R z0u|r5Z@|`# zR%?396mvV|C)lUnGIi-Cp^Bt#qtCtSs>OqTyQKU5!4Jb{j!%$0d)DpSu`smc-M(FR zx4EtNpUY2q=h$xVw%9O#YDU+@_=l!+dScKgOWJ*W-l&hCK5753Yi7PM?Bvp{8y*;V z=9N!xXjS`^!1BL*_||P>mMs46=wFCp>*zXk8Tu^xC-io7HacBY?X-X! zp!?-lN9y0#Xa)K<`V#sA`e#wKa|V10nu7K~JD_oBEp%71)%UTe+PM|J4!r^mqZ83{ z(Jb^Nw5O=r*_32<*PwqxpGF@jMaXA6@3w1iavoZ zKyOB`Lc^kJr#<`|v_AU%iDrK%`VsmX`Xc(AsM;9;pN{rNlhN*ITeK1Sz5G&0+wp~{ z+L;f}MQ5SY(R_3?dM4T*O%PQ(8+)1E)#wZ8Q|JTe9q6^_4D=#VwX^;Nv$GO?9{n@A z5S@pXqQz*QsM@IwSN1e}pQ9h5o6$As67&)DZc(+90ry5bqw#1Hbbk-4=PUFBbfc)+ zxeERrdNFz-IszSxrlH-?Hlk{$yt~!&9Qr7_0KE;p2K^m65j|H_?bLzybTfNjpdX=c zqHEEm=%eU8qG~4-PDOj79nqF(J+!i`)mMSOEvj~|hA%-2&~fOwXcl@B+7mrmRPC%i z-t7M!eFl99y%(K}{vItvFBDZfjo<+K&2eV;GjuDu0bPMUgDw(PJEy|wXfO0wv^5%o z?(IT7=sTinXEuBpIu*@B&qvQd`=Y(jV?@=?^3G=eFX$uaedw*|)o2Mi0Uar-c3wEv z>^y}&fZmPXgw8~#p<~fuqH1SHC$sZ!bPM__`Xc%q`XG8IdY!1+=?Wi>Hbd*7-*vQl zK1bg}|A{UaRXc_7c=SBvGIT0B0qux3Lu;eoG`I5G z(D%{T&~@mIXel}aEkKjdZfJY7IXW}W>M21dqZgth(9_U#v^)A)td-x2zK*_xE=Qk6 z|A^j-Ue`Df$d~vfqxD2Jp5HYx-GP3BzJsnum!VIh*P@fr;b=N~EZP|TwxQLt1^oy5 zBsv$JhK@o{LXSazXkd0;K%YV%K<`0sMrWZ#=ypy#4P&;e*V+6(P~#-X*)x9gbQN738R;b=d!8~Sc-%U_N@hTe{5 zpzYBZbXhGc_eWITF}QJmqG(yIK(7|CzE{!turFZx1$sAn1NwXPBJ_LFrc$=6s2&X^ zt$eCspd~y3?g2jyC&EkMf$-nqq3|d0Xt4@J2lOa}o67p5#~ipP{0BG_ehNMp zUIkwYzYZ^ix5LlEd*GMhMlzn%|M%gpa3!qcPOo=wV*Z^5r^4sMr@^`KP!*|2G;6?CW_;L97rsnUna5DUNxDUJ*E`nc!=fm&93*b-S2Vwn{ zsK)1I_y$I1Ox<39p!3y*@2gYSS7;8)=c_&qoq-U$zbzlTS`^<}@T#{{@3JPjTI zPlvPNE8q$6b?_W`9y|~J1H2ku1aE*Jfj7c`fxm_S4%d=>z8-7f7*c+O9)sY;a5nrrJOW-1>woJ_ z{Xe6lD;}5#PlpTO8So`=olcg2CVV1%Et~+~0{4OMgj z!K>g8;FrDf@Fw`4&Q|_ycn$mkycYfhehvN-ejl!c$96G$`{5hmy0Q<|c-{mzhC3W* z`J2OMz-{4dxHJ4I+yicYyp<2aE#P$cPjG*D13Vbs2%ibR3y*{^>}vMMz&F5o@LV__ zZr{!F>vOKQHw(TLJ{>NFx5C%Mjk;U;Tj0j9?(@~&z3>8fE&L$74t@gO3NL|2_b~g* z;WBtNd_BAYZrRiFzX@l;@52M&PvIf(PWXLz58Utsvv&Y)1UG1C?Rx}{gWrH#!@J;) zaHC#kuPgjG+#7xyPJy?;ec^w@gWw(TS#WW0vwseJKRg;<2#<$@CtCiC;n8py9s^$v z?}ba@;}Wd=_3-iVE%0J^KKv290R9+$82%D|1`Y?!{!;ipxEx*puYpfYwEX{sFM!{G zN5Na+o$x1c`y?y>1$+#=8-4=*4&DOSZe-)(9k>y^6K(|;CY$~C@I7!B_+I!#xNC~# zPlJcS{o&zo7Mug?do`VZJK$09(Wz!{Jlq~GgkONC!=J)e!au;X;bv)O??yNtz7y^V z-w)pnKMb#ipMuxG&%^J)fq#>3{{0K?3x5Hh3RlAC!?hY){4RqV z!n5EOa2ebIo&)!Q?}qjLsrJW0xIerYJ{^7w9tyX}F#kuxqu@#Ke7Fc+4POqw1YZMh zfNy~R1>X+ug71ZYfFFR5I?4Qb5^e`Cg$Kba;cWO7cpSVLz8c;N&w;nW^Wfd^ZSVnj z5!|4O#rILT1-u;Y0DlN~h1>VB_9Vi2@X7E(I0SEm&xYTC&xhZEbK$Sx$?y;GH2A2# zR{y1NBlv2#1AHUg8@>}xffvGA@MG{8_%CoCybR8V*TDtw>u@RjK72jA4ZaKB4c`NQ z53hpj%6lIj|LfqUaEFtv{jK0r;bY-5;9l_Aa4MV&_k*v2Pls=SN5HqhW8jD33Ggd$ z7=9hT0^S18hChREgq!xW_S_A(gdc$0!cV|KcriQzUI~wa*TcE+W_SYpF zCf;G-9=L-0%k}V!?EmM%n@_O(a{G1VjRJw@Fx%U}Gw@c%+Y0y__)qY9csu+%+OrXk zrGMAKwc(H8PUPPL&*%DM@Mi2^0zcnU5^_wCKW+a_ydPQ$SCIc(Wr@G{{~IdcdN0b4 zfy?3~AxC@pQ+taX$@3$u>#iOe7rovJ*4vEoA7M!b^e=Mc3=Zc^$h{~(powvXQ!j}m z3S6qVFsq=L)R4l0;)#V*^1_y>xbV!v@RVFDT3nc2STNCdB6s|FSFEUHtkZ(LiN@1P za>IEpIiZM^8$0~O0T+OEZ*ABKOE(NRF*E2O+ieB;T z3=S7gi8fE|R6XOjQ_~e^r?@a`V%Vg@aB*O2VNvx{(i7EB`OE1T4ERsvjF&-LJn15L z+IomQ234*{M{v%Bsx9)5ZgXm#i zOMb9GG8a#on&VxVLgDI+UT*|8< zQby{HT$hx0-5HW@%p5;HJ6rqHB^aKT_WE9Fn3rXkFUv5AtqfY3{}v-nREv?Gk{Fpt zBrM^@C<)dW*%cR~NOFoh>tdwmqA^O2T=25E_F5*_G_xTsw}i$hk}8NMt+>U=uDcjT zl2f$Z!%D_l09+y`*G*wddodCk=ECR_(JaHVEk;=JvSepRvq;*ra%SE{t4I=FNtq8h zMFIV{T4?o@TV*73c0gu9-o)Hu=?%APNUXe6wPIY?PO+RaY@*320a>N2H#JeMte%pB zCemk?(B6!sYz(Kkk(?SmZFb!p;H2wmohWH8Z+i5!=Yw>ank{kzJd&~sGHi||L~~5B zGeHxtsPraTT)&zXH$co|F54usQ!-QvaK;TPJL?&8L&dx949Ts?0_J9YlGUGVk`mCX zx=1*YKv}|@06}YfFx|4Jnpoo!6UeNyLv719%AHshiPq9Yt0~cHvgO1%6j@HJibSg- z(W*$aDw3=UEoI?LvMQ3SiX^Kd$*M^58Y3~I6^*MhEi z4}%Fw(Mw)=b10aQ5*RBRQ(3>ANJP;oUcy$hV1hXtOi0t+XIS>a@@M^{2`OkIBis_& z6_(OCYsv-DOB6&-$qmdIkOo*n?}U+*<#Vf_mrZ(h) zMtLdA=QYZmb&c{;-gP -<% const longIsZero = global.tmpLabel() %> -<% const retOne = global.tmpLabel("retOne") %> -<% const retZero = global.tmpLabel("retZero") %> -<% const done = global.tmpLabel("done") %> - - mov rax, [<%=srcPtrReg%>] - bt rax, 63 - jc <%= longIsZero %> - - test eax, eax - jz <%= retZero %> - jmp <%= retOne %> - -<%= longIsZero %>: -<% for (let i=0; i - mov rax, [<%= srcPtrReg + " + " +(i*8+8) %>] - test rax, rax - jnz <%= retOne %> -<% } %> - -<%= retZero %>: - mov qword <%=resReg%>, 0 - jmp <%= done %> - -<%= retOne %>: - mov qword <%=resReg%>, 1 - -<%= done %>: -<% } %> - - - - -<% function logicalOp(op) { %> -;;;;;;;;;;;;;;;;;;;;;; -; l<%= op %> -;;;;;;;;;;;;;;;;;;;;;; -; Logical <%= op %> between two elements -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result zero or one -; Modified Registers: -; rax, rcx, r8 -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_l<%=op%>: -<%= isTrue("r8", "rsi") %> -<%= isTrue("rcx", "rdx") %> - <%=op%> rcx, r8 - mov [rdi], rcx - ret -<% } %> - -<% logicalOp("and"); %> -<% logicalOp("or"); %> - -;;;;;;;;;;;;;;;;;;;;;; -; lnot -;;;;;;;;;;;;;;;;;;;;;; -; Do the logical not of an element -; Params: -; rsi <= Pointer to element to be tested -; rdi <= Pointer to result one if element1 is zero and zero otherwise -; Modified Registers: -; rax, rax, r8 -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_lnot: -<%= isTrue("rcx", "rsi") %> - test rcx, rcx - - jz lnot_retOne -lnot_retZero: - mov qword [rdi], 0 - ret -lnot_retOne: - mov qword [rdi], 1 - ret - - -;;;;;;;;;;;;;;;;;;;;;; -; isTrue -;;;;;;;;;;;;;;;;;;;;;; -; Convert a 64 bit integer to a long format field element -; Params: -; rsi <= Pointer to the element -; Returs: -; rax <= 1 if true 0 if false -;;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_isTrue: - <%= isTrue("rax", "rdi") %> - ret - - - diff --git a/ports/c/buildasm/main.c b/ports/c/buildasm/main.c deleted file mode 100644 index d33cefb..0000000 --- a/ports/c/buildasm/main.c +++ /dev/null @@ -1,64 +0,0 @@ -#include -#include -#include -#include "fr.h" - -int main() { - Fr_init(); -/* - FrElement a = { 0, Fr_LONGMONTGOMERY, {1,1,1,1}}; - FrElement b = { 0, Fr_LONGMONTGOMERY, {2,2,2,2}}; - - - FrElement a={0x43e1f593f0000000ULL,0x2833e84879b97091ULL,0xb85045b68181585dULL,0x30644e72e131a029ULL}; - FrElement b = {3,0,0,0}; - - FrElement c; -*/ -// Fr_add(&(c[0]), a, a); -// Fr_add(&(c[0]), c, b); - -/* - for (int i=0; i<1000000000; i++) { - Fr_mul(&c, &a, &b); - } - - Fr_mul(&c,&a, &b); -*/ - -/* - FrElement a1[10]; - FrElement a2[10]; - for (int i=0; i<10; i++) { - a1[i].type = Fr_LONGMONTGOMERY; - a1[i].shortVal =0; - for (int j=0; j -<%=fnName%>: - sub rsp, <%= n64*8 %> ; Reserve space for ms - mov rcx, rdx ; rdx is needed for multiplications so keep it in cx - mov r11, 0x<%= np64.toString(16) %> ; np - xor r8,r8 - xor r9,r9 - xor r10,r10 -<% - // Main loop - for (let i=0; i - -<% - for (let j=i-1; j>=0; j--) { // All ms - if (((i-j) - mov rax, [rsp + <%= j*8 %>] - mul qword [q + <%= (i-j)*8 %>] - add <%= r0 %>, rax - adc <%= r1 %>, rdx - adc <%= r2 %>, 0x0 -<% - } - } // ms -%> - -<% - if (i - mov rax, <%= r0 %> - mul r11 - mov [rsp + <%= i*8 %>], rax - mul qword [q] - add <%= r0 %>, rax - adc <%= r1 %>, rdx - adc <%= r2 %>, 0x0 -<% - } else { -%> - mov [rdi + <%= (i-n64)*8 %> ], <%= r0 %> - xor <%= r0 %>,<%= r0 %> -<% - } -%> - -<% - } // Main Loop -%> - test <%= r1 %>, <%= r1 %> - jnz <%=fnName%>_mulM_sq - ; Compare with q -<% - for (let i=0; i - mov rax, [rdi + <%= (n64-i-1)*8 %>] - cmp rax, [q + <%= (n64-i-1)*8 %>] - jc <%=fnName%>_mulM_done ; q is bigget so done. - jnz <%=fnName%>_mulM_sq ; q is lower -<% - } -%> - ; If equal substract q - -<%=fnName%>_mulM_sq: -<% - for (let i=0; i - mov rax, [q + <%= i*8 %>] - <%= i==0 ? "sub" : "sbb" %> [rdi + <%= i*8 %>], rax -<% - } -%> - -<%=fnName%>_mulM_done: - mov rdx, rcx ; recover rdx to its original place. - add rsp, <%= n64*8 %> ; recover rsp - ret - -<% -} // Template -%> - -;;;;;;;;;;;;;;;;;;;;;; -; rawMontgomeryMul -;;;;;;;;;;;;;;;;;;;;;; -; Multiply two elements in montgomery form -; Params: -; rsi <= Pointer to the long data of element 1 -; rdx <= Pointer to the long data of element 2 -; rdi <= Pointer to the long data of result -; Modified registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<% -montgomeryTemplate("rawMontgomeryMul", function(i, r0, r1, r2) { - // Same Digit - for (let o1=Math.max(0, i-n64+1); (o1<=i)&&(o1 - mov rax, [rsi + <%= 8*o1 %>] - mul qword [rcx + <%= 8*o2 %>] - add <%= r0 %>, rax - adc <%= r1 %>, rdx - adc <%= r2 %>, 0x0 -<% - } // Same digit -}) -%> - -;;;;;;;;;;;;;;;;;;;;;; -; rawMontgomerySquare -;;;;;;;;;;;;;;;;;;;;;; -; Square an element -; Params: -; rsi <= Pointer to the long data of element 1 -; rdi <= Pointer to the long data of result -; Modified registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<% -montgomeryTemplate("rawMontgomerySquare", function(i, r0, r1, r2) { - // Same Digit - for (let o1=Math.max(0, i-n64+1); (o1<((i+1)>>1) )&&(o1 - mov rax, [rsi + <%= 8*o1 %>] - mul qword [rsi + <%= 8*o2 %>] - add <%= r0 %>, rax - adc <%= r1 %>, rdx - adc <%= r2 %>, 0x0 - add <%= r0 %>, rax - adc <%= r1 %>, rdx - adc <%= r2 %>, 0x0 -<% - } // Same digit -%> - -<% if (i%2 == 0) { %> - mov rax, [rsi + <%= 8*(i/2) %>] - mul rax - add <%= r0 %>, rax - adc <%= r1 %>, rdx - adc <%= r2 %>, 0x0 -<% } %> - -<% -}) -%> - - -;;;;;;;;;;;;;;;;;;;;;; -; rawMontgomeryMul1 -;;;;;;;;;;;;;;;;;;;;;; -; Multiply two elements in montgomery form -; Params: -; rsi <= Pointer to the long data of element 1 -; rdx <= second operand -; rdi <= Pointer to the long data of result -; Modified registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<% -montgomeryTemplate("rawMontgomeryMul1", function(i, r0, r1, r2) { - // Same Digit - if (i - mov rax, [rsi + <%= 8*i %>] - mul rcx - add <%= r0 %>, rax - adc <%= r1 %>, rdx - adc <%= r2 %>, 0x0 -<% - } // Same digit -}) -%> - - -;;;;;;;;;;;;;;;;;;;;;; -; rawFromMontgomery -;;;;;;;;;;;;;;;;;;;;;; -; Multiply two elements in montgomery form -; Params: -; rsi <= Pointer to the long data of element 1 -; rdi <= Pointer to the long data of result -; Modified registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<% -montgomeryTemplate("rawFromMontgomery", function(i, r0, r1, r2) { - // Same Digit - if (i - add <%= r0 %>, [rdi + <%= 8*i %>] - adc <%= r1 %>, 0x0 - adc <%= r2 %>, 0x0 -<% - } // Same digit -}) -%> - -;;;;;;;;;;;;;;;;;;;;;; -; toMontgomery -;;;;;;;;;;;;;;;;;;;;;; -; Convert a number to Montgomery -; rdi <= Pointer element to convert -; Modified registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;; -<%=name%>_toMontgomery: - mov rax, [rdi] - bt rax, 62 ; check if montgomery - jc toMontgomery_doNothing - bt rax, 63 - jc toMontgomeryLong - -toMontgomeryShort: - add rdi, 8 - push rsi - push rdx - lea rsi, [R2] - movsx rdx, eax - cmp rdx, 0 - js negMontgomeryShort -posMontgomeryShort: - call rawMontgomeryMul1 - pop rdx - pop rsi - sub rdi, 8 - <%= global.setTypeDest("0x40"); %> - ret - -negMontgomeryShort: - neg rdx ; Do the multiplication positive and then negate the result. - call rawMontgomeryMul1 - mov rsi, rdi - call rawNegL - pop rdx - pop rsi - sub rdi, 8 - <%= global.setTypeDest("0x40"); %> - ret - - -toMontgomeryLong: - mov [rdi], rax - add rdi, 8 - push rsi - mov rdx, rdi - lea rsi, [R2] - call rawMontgomeryMul - pop rsi - sub rdi, 8 - <%= global.setTypeDest("0xC0"); %> - - -toMontgomery_doNothing: - ret - -;;;;;;;;;;;;;;;;;;;;;; -; toNormal -;;;;;;;;;;;;;;;;;;;;;; -; Convert a number from Montgomery -; rdi <= Pointer element to convert -; Modified registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;; -<%=name%>_toNormal: - mov rax, [rdi] - bt rax, 62 ; check if montgomery - jnc toNormal_doNothing - bt rax, 63 ; if short, it means it's converted - jnc toNormal_doNothing - -toNormalLong: - add rdi, 8 - call rawFromMontgomery - sub rdi, 8 - <%= global.setTypeDest("0x80"); %> - -toNormal_doNothing: - ret - -;;;;;;;;;;;;;;;;;;;;;; -; toLongNormal -;;;;;;;;;;;;;;;;;;;;;; -; Convert a number to long normal -; rdi <= Pointer element to convert -; Modified registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;; -<%=name%>_toLongNormal: - mov rax, [rdi] - bt rax, 62 ; check if montgomery - jc toLongNormal_fromMontgomery - bt rax, 63 ; check if long - jnc toLongNormal_fromShort - ret ; It is already long - -toLongNormal_fromMontgomery: - add rdi, 8 - call rawFromMontgomery - sub rdi, 8 - <%= global.setTypeDest("0x80"); %> - ret - -toLongNormal_fromShort: - mov r8, rsi ; save rsi - movsx rsi, eax - call rawCopyS2L - mov rsi, r8 ; recover rsi - <%= global.setTypeDest("0x80"); %> - ret - diff --git a/ports/c/buildasm/mul.asm.ejs b/ports/c/buildasm/mul.asm.ejs deleted file mode 100644 index fca655d..0000000 --- a/ports/c/buildasm/mul.asm.ejs +++ /dev/null @@ -1,275 +0,0 @@ -<% function mulS1S2() { %> - xor rax, rax - mov eax, r8d - imul r9d - jo mul_manageOverflow ; rsi already is the 64bits result - - mov [rdi], rax ; not necessary to adjust so just save and return - -mul_manageOverflow: ; Do the operation in 64 bits - push rsi - movsx rax, r8d - movsx rcx, r9d - imul rcx - mov rsi, rax - call rawCopyS2L - pop rsi -<% } %> - -<% function squareS1() { %> - xor rax, rax - mov eax, r8d - imul eax - jo square_manageOverflow ; rsi already is the 64bits result - - mov [rdi], rax ; not necessary to adjust so just save and return - -square_manageOverflow: ; Do the operation in 64 bits - push rsi - movsx rax, r8d - imul rax - mov rsi, rax - call rawCopyS2L - pop rsi -<% } %> - - -<% function mulL1S2(t) { %> - push rsi - add rsi, 8 - movsx rdx, r9d - add rdi, 8 - cmp rdx, 0 - <% const rawPositiveLabel = global.tmpLabel() %> - jns <%= rawPositiveLabel %> - neg rdx - call rawMontgomeryMul1 - mov rsi, rdi - call rawNegL - sub rdi, 8 - pop rsi - <% const done = global.tmpLabel() %> - jmp <%= done %> -<%= rawPositiveLabel %>: - call rawMontgomeryMul1 - sub rdi, 8 - pop rsi -<%= done %>: - -<% } %> - -<% function mulS1L2() { %> - push rsi - lea rsi, [rdx + 8] - movsx rdx, r8d - add rdi, 8 - cmp rdx, 0 - <% const rawPositiveLabel = global.tmpLabel() %> - jns <%= rawPositiveLabel %> - neg rdx - call rawMontgomeryMul1 - mov rsi, rdi - call rawNegL - sub rdi, 8 - pop rsi - <% const done = global.tmpLabel() %> - jmp <%= done %> -<%= rawPositiveLabel %>: - call rawMontgomeryMul1 - sub rdi, 8 - pop rsi -<%= done %>: - -<% } %> - -<% function mulL1L2() { %> - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawMontgomeryMul - sub rdi, 8 - sub rsi, 8 -<% } %> - - -<% function squareL1() { %> - add rdi, 8 - add rsi, 8 - call rawMontgomerySquare - sub rdi, 8 - sub rsi, 8 -<% } %> - -<% function mulR3() { %> - push rsi - add rdi, 8 - mov rsi, rdi - lea rdx, [R3] - call rawMontgomeryMul - sub rdi, 8 - pop rsi -<% } %> - - - -;;;;;;;;;;;;;;;;;;;;;; -; square -;;;;;;;;;;;;;;;;;;;;;; -; Squares a field element -; Params: -; rsi <= Pointer to element 1 -; rdi <= Pointer to result -; [rdi] = [rsi] * [rsi] -; Modified Registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_square: - mov r8, [rsi] - bt r8, 63 ; Check if is short first operand - jc square_l1 - -square_s1: ; Both operands are short -<%= squareS1() %> - ret - -square_l1: - bt r8, 62 ; check if montgomery first - jc square_l1m -square_l1n: -<%= global.setTypeDest("0xC0"); %> -<%= squareL1() %> -<%= mulR3() %> - ret - -square_l1m: -<%= global.setTypeDest("0xC0"); %> -<%= squareL1() %> - ret - - - -;;;;;;;;;;;;;;;;;;;;;; -; mul -;;;;;;;;;;;;;;;;;;;;;; -; Multiplies two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result -; [rdi] = [rsi] * [rdi] -; Modified Registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_mul: - mov r8, [rsi] - mov r9, [rdx] - bt r8, 63 ; Check if is short first operand - jc mul_l1 - bt r9, 63 ; Check if is short second operand - jc mul_s1l2 - -mul_s1s2: ; Both operands are short -<%= mulS1S2() %> - ret - -mul_l1: - bt r9, 63 ; Check if is short second operand - jc mul_l1l2 - -;;;;;;;; -mul_l1s2: - bt r8, 62 ; check if montgomery first - jc mul_l1ms2 -mul_l1ns2: - bt r9, 62 ; check if montgomery first - jc mul_l1ns2m -mul_l1ns2n: -<%= global.setTypeDest("0xC0"); %> -<%= mulL1S2() %> -<%= mulR3() %> - ret - - -mul_l1ns2m: -<%= global.setTypeDest("0x80"); %> -<%= mulL1L2() %> - ret - - -mul_l1ms2: - bt r9, 62 ; check if montgomery second - jc mul_l1ms2m -mul_l1ms2n: -<%= global.setTypeDest("0x80"); %> -<%= mulL1S2() %> - ret - -mul_l1ms2m: -<%= global.setTypeDest("0xC0"); %> -<%= mulL1L2() %> - ret - - -;;;;;;;; -mul_s1l2: - bt r8, 62 ; check if montgomery first - jc mul_s1ml2 -mul_s1nl2: - bt r9, 62 ; check if montgomery first - jc mul_s1nl2m -mul_s1nl2n: -<%= global.setTypeDest("0xC0"); %> -<%= mulS1L2() %> -<%= mulR3() %> - ret - -mul_s1nl2m: -<%= global.setTypeDest("0x80"); %> -<%= mulS1L2(); %> - ret - -mul_s1ml2: - bt r9, 62 ; check if montgomery first - jc mul_s1ml2m -mul_s1ml2n: -<%= global.setTypeDest("0x80"); %> -<%= mulL1L2() %> - ret - -mul_s1ml2m: -<%= global.setTypeDest("0xC0"); %> -<%= mulL1L2() %> - ret - -;;;; -mul_l1l2: - bt r8, 62 ; check if montgomery first - jc mul_l1ml2 -mul_l1nl2: - bt r9, 62 ; check if montgomery second - jc mul_l1nl2m -mul_l1nl2n: -<%= global.setTypeDest("0xC0"); %> -<%= mulL1L2() %> -<%= mulR3() %> - ret - -mul_l1nl2m: -<%= global.setTypeDest("0x80"); %> -<%= mulL1L2() %> - ret - -mul_l1ml2: - bt r9, 62 ; check if montgomery seconf - jc mul_l1ml2m -mul_l1ml2n: -<%= global.setTypeDest("0x80"); %> -<%= mulL1L2() %> - ret - -mul_l1ml2m: -<%= global.setTypeDest("0xC0"); %> -<%= mulL1L2() %> - ret - - diff --git a/ports/c/buildasm/neg.asm.ejs b/ports/c/buildasm/neg.asm.ejs deleted file mode 100644 index d0796dc..0000000 --- a/ports/c/buildasm/neg.asm.ejs +++ /dev/null @@ -1,78 +0,0 @@ -<% function negS() { %> - neg eax - jo neg_manageOverflow ; Check if overflow. (0x80000000 is the only case) - - mov [rdi], rax ; not necessary to adjust so just save and return - ret - -neg_manageOverflow: ; Do the operation in 64 bits - push rsi - movsx rsi, eax - neg rsi - call rawCopyS2L - pop rsi - ret -<% } %> - -<% function negL() { %> - add rdi, 8 - add rsi, 8 - call rawNegL - sub rdi, 8 - sub rsi, 8 - ret -<% } %> - -;;;;;;;;;;;;;;;;;;;;;; -; neg -;;;;;;;;;;;;;;;;;;;;;; -; Adds two elements of any kind -; Params: -; rsi <= Pointer to element to be negated -; rdi <= Pointer to result -; [rdi] = -[rsi] -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_neg: - mov rax, [rsi] - bt rax, 63 ; Check if is short first operand - jc neg_l - -neg_s: ; Operand is short -<%= negS() %> - - -neg_l: - mov [rdi], rax ; Copy the type -<%= negL() %> - - -;;;;;;;;;;;;;;;;;;;;;; -; rawNeg -;;;;;;;;;;;;;;;;;;;;;; -; Negates a value -; Params: -; rdi <= Pointer to the long data of result -; rsi <= Pointer to the long data of element 1 -; -; [rdi] = - [rsi] -;;;;;;;;;;;;;;;;;;;;;; -rawNegL: - ; Compare is zero - - xor rax, rax -<% for (let i=0; i - cmp [rsi + <%=i*8%>], rax - jnz doNegate -<% } %> - ; it's zero so just set to zero -<% for (let i=0; i - mov [rdi + <%=i*8%>], rax -<% } %> - ret -doNegate: -<% for (let i=0; i - mov rax, [q + <%=i*8%>] - <%= i==0 ? "sub" : "sbb" %> rax, [rsi + <%=i*8%>] - mov [rdi + <%=i*8%>], rax -<% } %> - ret diff --git a/ports/c/buildasm/old/buildfieldasm.js b/ports/c/buildasm/old/buildfieldasm.js deleted file mode 100644 index fc48e4c..0000000 --- a/ports/c/buildasm/old/buildfieldasm.js +++ /dev/null @@ -1,33 +0,0 @@ -const tester = require("../c/buildasm/buildzqfieldtester2.js"); - -const bigInt = require("big-integer"); - -const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); - - -describe("basic cases", function () { - this.timeout(100000); - it("should do basic tests", async () => { - await tester(__P__, [ - ["add", 0, 0], - ["add", 0, 1], - ["add", 1, 0], - ["add", 1, 1], - ["add", 2, 1], - ["add", 2, 10], - ["add", -1, -1], - ["add", -20, -10], - ["add", "10604728079509999371218483608188593244163417117449316147628604036713980815027", "10604728079509999371218483608188593244163417117449316147628604036713980815027"], - - ["mul", 0, 0], - ["mul", 0, 1], - ["mul", 1, 0], - ["mul", 1, 1], - ["mul", 2, 1], - ["mul", 2, 10], - ["mul", -1, -1], - ["mul", -20, -10], - ["mul", "10604728079509999371218483608188593244163417117449316147628604036713980815027", "10604728079509999371218483608188593244163417117449316147628604036713980815027"], - ]); - }); -}); diff --git a/ports/c/buildasm/old/buildzqfield.js b/ports/c/buildasm/old/buildzqfield.js deleted file mode 100644 index 72e5284..0000000 --- a/ports/c/buildasm/old/buildzqfield.js +++ /dev/null @@ -1,209 +0,0 @@ -const bigInt=require("big-integer"); - - - - - -class ZqBuilder { - constructor(q, name) { - this.q=bigInt(q); - this.h = []; - this.c = []; - this.name = name; - } - - build() { - this._buildHeaders(); - this._buildAdd(); - this._buildMul(); - - this.c.push(""); this.h.push(""); - return [this.h.join("\n"), this.c.join("\n")]; - } - - _buildHeaders() { - this.n64 = Math.floor((this.q.bitLength() - 1) / 64)+1; - this.h.push("typedef unsigned long long u64;"); - this.h.push(`typedef u64 ${this.name}Element[${this.n64}];`); - this.h.push(`typedef u64 *P${this.name}Element;`); - this.h.push(`extern ${this.name}Element ${this.name}_q;`); - this.h.push(`#define ${this.name}_N64 ${this.n64}`); - this.c.push(`#include "${this.name.toLowerCase()}.h"`); - this._defineConstant(`${this.name}_q`, this.q); - this.c.push(""); this.h.push(""); - } - - _defineConstant(n, v) { - let S = `${this.name}Element ${n}={`; - const mask = bigInt("FFFFFFFFFFFFFFFF", 16); - for (let i=0; i0) S = S+","; - let shex = v.shiftRight(i*64).and(mask).toString(16); - while (shex <16) shex = "0" + shex; - S = S + "0x" + shex + "ULL"; - } - S += "};"; - this.c.push(S); - } - - _buildAdd() { - this.h.push(`void ${this.name}_add(P${this.name}Element r, P${this.name}Element a, P${this.name}Element b);`); - this.c.push(`void ${this.name}_add(P${this.name}Element r, P${this.name}Element a, P${this.name}Element b) {`); - this.c.push(" __asm__ __volatile__ ("); - for (let i=0; i0) { - this.c.push(` "movq ${(this.n64 - i-1)*8}(%0), %%rax;"`); - } - this.c.push(` "cmp ${(this.n64 - i-1)*8}(%3), %%rax;"`); - this.c.push(" \"jg SQ;\""); - this.c.push(" \"jl DONE;\""); - } - this.c.push(" \"SQ:\""); - for (let i=0; i=0; j--) { - if (((i-j)_add - global <%=name%>_mul - global <%=name%>_q - DEFAULT REL - - section .text - -;;;;;;;;;;;;;;;;;;;;;; -; add -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_add: - ; Add component by component with carry -<% for (let i=0; i - mov rax, [rsi + <%=i*8%>] - <%= i==0 ? "add" : "adc" %> rax, [rdx + <%=i*8%>] - mov [rdi + <%=i*8%>], rax -<% } %> - jc add_sq ; if overflow, substract q - - ; Compare with q -<% for (let i=0; i -<% if (i>0) { %> - mov rax, [rdi + <%= (n64-i-1)*8 %>] -<% } %> - cmp rax, [q + <%= (n64-i-1)*8 %>] - jg add_sq - jl add_done -<% } %> - ; If equal substract q -add_sq: -<% for (let i=0; i - mov rax, [q + <%=i*8%>] - <%= i==0 ? "sub" : "sbb" %> [rdi + <%=i*8%>], rax - mov [rdx + <%=i*8%>], rax -<% } %> - -add_done: - ret - - -;;;;;;;;;;;;;;;;;;;;;; -; mul Montgomery -;;;;;;;;;;;;;;;;;;;;;; -mulM: -<% -let r0, r1, r2; -function setR(step) { - if ((step % 3) == 0) { - r0 = "r8"; - r1 = "r9"; - r2 = "r10"; - } else if ((step % 3) == 1) { - r0 = "r9"; - r1 = "r10"; - r2 = "r8"; - } else { - r0 = "r10"; - r1 = "r8"; - r2 = "r9"; - } -} - -const base = bigInt.one.shiftLeft(64); -const np64 = base.minus(q.modInv(base)); -%> - sub rsp, <%= n64*8 %> ; Reserve space for ms - mov rcx, rdx ; rdx is needed for multiplications so keep it in cx - mov r11, 0x<%= np64.toString(16) %> ; np - xor r8,r8 - xor r9,r9 - xor r10,r10 -<% -// Main loop -for (let i=0; i -<% - // Same Digit - for (let o1=Math.max(0, i-n64+1); (o1<=i)&&(o1 - mov rax, [rsi + <%= 8*o1 %>] - mul qword [rcx + <%= 8*o2 %>] - add <%= r0 %>, rax - adc <%= r1 %>, rdx - adc <%= r2 %>, 0x0 -<% - } // Same digit -%> - - -<% - for (let j=i-1; j>=0; j--) { // All ms - if (((i-j) - mov rax, [rsp + <%= j*8 %>] - mul qword [q + <%= (i-j)*8 %>] - add <%= r0 %>, rax - adc <%= r1 %>, rdx - adc <%= r2 %>, 0x0 -<% - } - } // ms -%> - -<% - if (i - mov rax, <%= r0 %> - mul r11 - mov [rsp + <%= i*8 %>], rax - mul qword [q] - add <%= r0 %>, rax - adc <%= r1 %>, rdx - adc <%= r2 %>, 0x0 -<% - } else { -%> - mov [rdi + <%= (i-n64)*8 %> ], <%= r0 %> - xor <%= r0 %>,<%= r0 %> -<% - } -%> - -<% -} // Main Loop -%> - cmp <%= r1 %>, 0x0 - jne mulM_sq - ; Compare with q -<% -for (let i=0; i - mov rax, [rdi + <%= (n64-i-1)*8 %>] - cmp rax, [q + <%= (n64-i-1)*8 %>] - jg mulM_sq - jl mulM_done -<% -} -%> - ; If equal substract q - -mulM_sq: -<% -for (let i=0; i - mov rax, [q + <%= i*8 %>] - <%= i==0 ? "sub" : "sbb" %> [rdi + <%= i*8 %>], rax - mov [rdx + <%= i*8 %>], rax -<% -} -%> - -mulM_done: - add rsp, <%= n64*8 %> ; recover rsp - ret - -;;;;;;;;;;;;;;;;;;;;;; -; mul MontgomeryShort -;;;;;;;;;;;;;;;;;;;;;; -mulSM: - -;;;;;;;;;;;;;;;;;;;;;; -; mul -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_mul: - mov rax, [rsi] - bt rax, 63 - jc l1 - mov rcx, [rdx] - bt rcx, 63 - jc s1l2 -s1s2: ; short first and second - mul ecx - jc rs2l ; If if doesn't feed in 32 bits convert the result to long - - ; The shorts multiplication is done. copy the val to destination and return - mov [rdi], rax - ret - -rs2l: ; The result in the multiplication doen't feed - ; we have the result in edx:eax we need to convert it to long - shl rdx, 32 - mov edx, eax ; pack edx:eax to rdx - - xor rax, rax ; Set the format to long - bts rax, 63 - mov [rdi], rax ; move the first digit - - cmp rdx, 0 ; check if redx is negative. - jl rs2ln - - ; edx is positive. - mov [rdi + 8], rdx ; Set the firs digit - - xor rax, rax ; Set the remaining digits to 0 -<% for (let i=1; i - mov [rdi + <%= (i+1)*8 %>], rax -<% } %> - ret - - ; edx is negative. -rs2ln: - - add rdx, [q] ; Set the firs digit - mov [rdi + 8], rdx ; - - mov rdx, -1 ; all ones -<% for (let i=1; i - mov rax, rdx ; Add to q - adc rax, [q + <%= i*8 %> ] - mov [rdi + <%= (i+1)*8 %>], rax -<% } %> - ret - -l1: - mov rcx, [rdx] - bt rcx, 63 - jc ll - -l1s2: - xor rdx, rdx - mov edx, ecx - bt rax, 62 - jc lsM - jmp lsN - -s1l2: - mov rsi, rdx - xor rdx, rdx - mov edx, eax - bt rcx, 62 - jc lsM - jmp lsN - - -lsN: - mov byte [rdi + 3], 0xC0 ; set the result to montgomery - add rsi, 8 - add rdi, 8 - call mulSM - mov rdx, R3 - call mulM - ret - -lsM: - mov byte [rdi + 3], 0x80 ; set the result to long normal - add rsi, 8 - add rdi, 8 - call mulSM - ret - - -ll: - - bt rax, 62 - jc lml - bt rcx, 62 - jc lnlm - -lnln: - mov byte [rdi + 3], 0xC0 ; set the result to long montgomery - add rsi, 8 - add rdi, 8 - add rdx, 8 - call mulM - mov rdi, rsi - mov rdx, R3 - call mulM - ret - -lml: - bt rcx, 62 - jc lmlm - -lnlm: - mov byte [rdi + 3], 0x80 ; set the result to long normal - add rsi, 8 - add rdi, 8 - add rdx, 8 - call mulM - ret - -lmlm: - mov byte [rdi + 3], 0xC0 ; set the result to long montgomery - add rsi, 8 - add rdi, 8 - add rdx, 8 - call mulM - ret - - - section .data -<%=name%>_q: - dd 0 - dd 0x80000000 -q dq <%= constantElement(q) %> -R3 dq <%= constantElement(bigInt.one.shiftLeft(n64*64*3).mod(q)) %> - - diff --git a/ports/c/buildasm/old/mul.asm.ejs b/ports/c/buildasm/old/mul.asm.ejs deleted file mode 100644 index f6b537e..0000000 --- a/ports/c/buildasm/old/mul.asm.ejs +++ /dev/null @@ -1,251 +0,0 @@ - -;;;;;;;;;;;;;;;;;;;;;; -; mul Montgomery -;;;;;;;;;;;;;;;;;;;;;; -mulM: -<% -let r0, r1, r2; -function setR(step) { - if ((step % 3) == 0) { - r0 = "r8"; - r1 = "r9"; - r2 = "r10"; - } else if ((step % 3) == 1) { - r0 = "r9"; - r1 = "r10"; - r2 = "r8"; - } else { - r0 = "r10"; - r1 = "r8"; - r2 = "r9"; - } -} - -const base = bigInt.one.shiftLeft(64); -const np64 = base.minus(q.modInv(base)); -%> - sub rsp, <%= n64*8 %> ; Reserve space for ms - mov rcx, rdx ; rdx is needed for multiplications so keep it in cx - mov r11, 0x<%= np64.toString(16) %> ; np - xor r8,r8 - xor r9,r9 - xor r10,r10 -<% -// Main loop -for (let i=0; i -<% - // Same Digit - for (let o1=Math.max(0, i-n64+1); (o1<=i)&&(o1 - mov rax, [rsi + <%= 8*o1 %>] - mul qword [rcx + <%= 8*o2 %>] - add <%= r0 %>, rax - adc <%= r1 %>, rdx - adc <%= r2 %>, 0x0 -<% - } // Same digit -%> - - -<% - for (let j=i-1; j>=0; j--) { // All ms - if (((i-j) - mov rax, [rsp + <%= j*8 %>] - mul qword [q + <%= (i-j)*8 %>] - add <%= r0 %>, rax - adc <%= r1 %>, rdx - adc <%= r2 %>, 0x0 -<% - } - } // ms -%> - -<% - if (i - mov rax, <%= r0 %> - mul r11 - mov [rsp + <%= i*8 %>], rax - mul qword [q] - add <%= r0 %>, rax - adc <%= r1 %>, rdx - adc <%= r2 %>, 0x0 -<% - } else { -%> - mov [rdi + <%= (i-n64)*8 %> ], <%= r0 %> - xor <%= r0 %>,<%= r0 %> -<% - } -%> - -<% -} // Main Loop -%> - cmp <%= r1 %>, 0x0 - jne mulM_sq - ; Compare with q -<% -for (let i=0; i - mov rax, [rdi + <%= (n64-i-1)*8 %>] - cmp rax, [q + <%= (n64-i-1)*8 %>] - jg mulM_sq - jl mulM_done -<% -} -%> - ; If equal substract q - -mulM_sq: -<% -for (let i=0; i - mov rax, [q + <%= i*8 %>] - <%= i==0 ? "sub" : "sbb" %> [rdi + <%= i*8 %>], rax -<% -} -%> - -mulM_done: - add rsp, <%= n64*8 %> ; recover rsp - ret - -;;;;;;;;;;;;;;;;;;;;;; -; mul MontgomeryShort -;;;;;;;;;;;;;;;;;;;;;; -mulSM: - -;;;;;;;;;;;;;;;;;;;;;; -; mul -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_mul: - mov rax, [rsi] - bt rax, 63 - jc l1 - mov rcx, [rdx] - bt rcx, 63 - jc s1l2 -s1s2: ; short first and second - mul ecx - jc rs2l ; If if doesn't feed in 32 bits convert the result to long - - ; The shorts multiplication is done. copy the val to destination and return - mov [rdi], rax - ret - -rs2l: ; The result in the multiplication doen't feed - ; we have the result in edx:eax we need to convert it to long - shl rdx, 32 - mov edx, eax ; pack edx:eax to rdx - - xor rax, rax ; Set the format to long - bts rax, 63 - mov [rdi], rax ; move the first digit - - cmp rdx, 0 ; check if redx is negative. - jl rs2ln - - ; edx is positive. - mov [rdi + 8], rdx ; Set the firs digit - - xor rax, rax ; Set the remaining digits to 0 -<% for (let i=1; i - mov [rdi + <%= (i+1)*8 %>], rax -<% } %> - ret - - ; edx is negative. -rs2ln: - - add rdx, [q] ; Set the firs digit - mov [rdi + 8], rdx ; - - mov rdx, -1 ; all ones -<% for (let i=1; i - mov rax, rdx ; Add to q - adc rax, [q + <%= i*8 %> ] - mov [rdi + <%= (i+1)*8 %>], rax -<% } %> - ret - -l1: - mov rcx, [rdx] - bt rcx, 63 - jc ll - -l1s2: - xor rdx, rdx - mov edx, ecx - bt rax, 62 - jc lsM - jmp lsN - -s1l2: - mov rsi, rdx - xor rdx, rdx - mov edx, eax - bt rcx, 62 - jc lsM - jmp lsN - - -lsN: - mov byte [rdi + 7], 0xC0 ; set the result to montgomery - add rsi, 8 - add rdi, 8 - call mulSM - mov rsi, rdi - lea rdx, [R3] - call mulM - ret - -lsM: - mov byte [rdi + 7], 0x80 ; set the result to long normal - add rsi, 8 - add rdi, 8 - call mulSM - ret - - -ll: - - bt rax, 62 - jc lml - bt rcx, 62 - jc lnlm - -lnln: - mov byte [rdi + 7], 0xC0 ; set the result to long montgomery - add rsi, 8 - add rdi, 8 - add rdx, 8 - call mulM - mov rsi, rdi - lea rdx, [R3] - call mulM - ret - -lml: - bt rcx, 62 - jc lmlm - -lnlm: - mov byte [rdi + 7], 0x80 ; set the result to long normal - add rsi, 8 - add rdi, 8 - add rdx, 8 - call mulM - ret - -lmlm: - mov byte [rdi + 7], 0xC0 ; set the result to long montgomery - add rsi, 8 - add rdi, 8 - add rdx, 8 - call mulM - ret diff --git a/ports/c/buildasm/sub.asm.ejs b/ports/c/buildasm/sub.asm.ejs deleted file mode 100644 index 5a8d199..0000000 --- a/ports/c/buildasm/sub.asm.ejs +++ /dev/null @@ -1,317 +0,0 @@ -<% function subS1S2() { %> - xor rdx, rdx - mov edx, eax - sub edx, ecx - jo sub_manageOverflow ; rsi already is the 64bits result - - mov [rdi], rdx ; not necessary to adjust so just save and return - ret - -sub_manageOverflow: ; Do the operation in 64 bits - push rsi - movsx rsi, eax - movsx rdx, ecx - sub rsi, rdx - call rawCopyS2L - pop rsi - ret -<% } %> - -<% function subL1S2(t) { %> - add rsi, 8 - movsx rdx, ecx - add rdi, 8 - cmp rdx, 0 - <% const rawSubLabel = global.tmpLabel() %> - jns <%= rawSubLabel %> - neg rdx - call rawAddLS - sub rdi, 8 - sub rsi, 8 - ret -<%= rawSubLabel %>: - call rawSubLS - sub rdi, 8 - sub rsi, 8 - ret -<% } %> - - -<% function subS1L2(t) { %> - cmp eax, 0 - <% const s1NegLabel = global.tmpLabel() %> - js <%= s1NegLabel %> - - ; First Operand is positive - push rsi - add rdi, 8 - movsx rsi, eax - add rdx, 8 - call rawSubSL - sub rdi, 8 - pop rsi - ret - -<%= s1NegLabel %>: ; First operand is negative - push rsi - lea rsi, [rdx + 8] - movsx rdx, eax - add rdi, 8 - neg rdx - call rawNegLS - sub rdi, 8 - pop rsi - ret -<% } %> - - -<% function subL1L2(t) { %> - add rdi, 8 - add rsi, 8 - add rdx, 8 - call rawSubLL - sub rdi, 8 - sub rsi, 8 - ret -<% } %> - -;;;;;;;;;;;;;;;;;;;;;; -; sub -;;;;;;;;;;;;;;;;;;;;;; -; Substracts two elements of any kind -; Params: -; rsi <= Pointer to element 1 -; rdx <= Pointer to element 2 -; rdi <= Pointer to result -; Modified Registers: -; r8, r9, 10, r11, rax, rcx -;;;;;;;;;;;;;;;;;;;;;; -<%=name%>_sub: - mov rax, [rsi] - mov rcx, [rdx] - bt rax, 63 ; Check if is long first operand - jc sub_l1 - bt rcx, 63 ; Check if is long second operand - jc sub_s1l2 - -sub_s1s2: ; Both operands are short -<%= subS1S2() %> -sub_l1: - bt rcx, 63 ; Check if is short second operand - jc sub_l1l2 - -;;;;;;;; -sub_l1s2: - bt rax, 62 ; check if montgomery first - jc sub_l1ms2 -sub_l1ns2: -<%= global.setTypeDest("0x80"); %> -<%= subL1S2(); %> - -sub_l1ms2: - bt rcx, 62 ; check if montgomery second - jc sub_l1ms2m -sub_l1ms2n: -<%= global.setTypeDest("0xC0"); %> -<%= global.toMont_b() %> -<%= subL1L2() %> - -sub_l1ms2m: -<%= global.setTypeDest("0xC0"); %> -<%= subL1L2() %> - - -;;;;;;;; -sub_s1l2: - bt rcx, 62 ; check if montgomery first - jc sub_s1l2m -sub_s1l2n: -<%= global.setTypeDest("0x80"); %> -<%= subS1L2(); %> - -sub_s1l2m: - bt rax, 62 ; check if montgomery second - jc sub_s1ml2m -sub_s1nl2m: -<%= global.setTypeDest("0xC0"); %> -<%= global.toMont_a() %> -<%= subL1L2() %> - -sub_s1ml2m: -<%= global.setTypeDest("0xC0"); %> -<%= subL1L2() %> - -;;;; -sub_l1l2: - bt rax, 62 ; check if montgomery first - jc sub_l1ml2 -sub_l1nl2: - bt rcx, 62 ; check if montgomery second - jc sub_l1nl2m -sub_l1nl2n: -<%= global.setTypeDest("0x80"); %> -<%= subL1L2() %> - -sub_l1nl2m: -<%= global.setTypeDest("0xC0"); %> -<%= global.toMont_a(); %> -<%= subL1L2() %> - -sub_l1ml2: - bt rcx, 62 ; check if montgomery seconf - jc sub_l1ml2m -sub_l1ml2n: -<%= global.setTypeDest("0xC0"); %> -<%= global.toMont_b(); %> -<%= subL1L2() %> - -sub_l1ml2m: -<%= global.setTypeDest("0xC0"); %> -<%= subL1L2() %> - - -;;;;;;;;;;;;;;;;;;;;;; -; rawSubLS -;;;;;;;;;;;;;;;;;;;;;; -; Substracts a short element from the long element -; Params: -; rdi <= Pointer to the long data of result -; rsi <= Pointer to the long data of element 1 where will be substracted -; rdx <= Value to be substracted -; [rdi] = [rsi] - rdx -; Modified Registers: -; rax -;;;;;;;;;;;;;;;;;;;;;; -rawSubLS: - ; Substract first digit - - mov rax, [rsi] - sub rax, rdx - mov [rdi] ,rax - mov rdx, 0 -<% for (let i=1; i - mov rax, [rsi + <%=i*8%>] - sbb rax, rdx - mov [rdi + <%=i*8%>], rax -<% } %> - jnc rawSubLS_done ; if overflow, add q - - ; Add q -rawSubLS_aq: -<% for (let i=0; i - mov rax, [q + <%=i*8%>] - <%= i==0 ? "add" : "adc" %> [rdi + <%=i*8%>], rax -<% } %> -rawSubLS_done: - ret - - -;;;;;;;;;;;;;;;;;;;;;; -; rawSubSL -;;;;;;;;;;;;;;;;;;;;;; -; Substracts a long element from a short element -; Params: -; rdi <= Pointer to the long data of result -; rsi <= Value from where will bo substracted -; rdx <= Pointer to long of the value to be substracted -; -; [rdi] = rsi - [rdx] -; Modified Registers: -; rax -;;;;;;;;;;;;;;;;;;;;;; -rawSubSL: - ; Substract first digit - sub rsi, [rdx] - mov [rdi] ,rsi - -<% for (let i=1; i - mov rax, 0 - sbb rax, [rdx + <%=i*8%>] - mov [rdi + <%=i*8%>], rax -<% } %> - jnc rawSubSL_done ; if overflow, add q - - ; Add q -rawSubSL_aq: -<% for (let i=0; i - mov rax, [q + <%=i*8%>] - <%= i==0 ? "add" : "adc" %> [rdi + <%=i*8%>], rax -<% } %> -rawSubSL_done: - ret - -;;;;;;;;;;;;;;;;;;;;;; -; rawSubLL -;;;;;;;;;;;;;;;;;;;;;; -; Substracts a long element from a short element -; Params: -; rdi <= Pointer to the long data of result -; rsi <= Pointer to long from where substracted -; rdx <= Pointer to long of the value to be substracted -; -; [rdi] = [rsi] - [rdx] -; Modified Registers: -; rax -;;;;;;;;;;;;;;;;;;;;;; -rawSubLL: - ; Substract first digit -<% for (let i=0; i - mov rax, [rsi + <%=i*8%>] - <%= i==0 ? "sub" : "sbb" %> rax, [rdx + <%=i*8%>] - mov [rdi + <%=i*8%>], rax -<% } %> - jnc rawSubLL_done ; if overflow, add q - - ; Add q -rawSubLL_aq: -<% for (let i=0; i - mov rax, [q + <%=i*8%>] - <%= i==0 ? "add" : "adc" %> [rdi + <%=i*8%>], rax -<% } %> -rawSubLL_done: - ret - -;;;;;;;;;;;;;;;;;;;;;; -; rawNegLS -;;;;;;;;;;;;;;;;;;;;;; -; Substracts a long element and a short element form 0 -; Params: -; rdi <= Pointer to the long data of result -; rsi <= Pointer to long from where substracted -; rdx <= short value to be substracted too -; -; [rdi] = -[rsi] - rdx -; Modified Registers: -; rax -;;;;;;;;;;;;;;;;;;;;;; -rawNegLS: - mov rax, [q] - sub rax, rdx - mov [rdi], rax -<% for (let i=1; i - mov rax, [q + <%=i*8%> ] - sbb rax, 0 - mov [rdi + <%=i*8%>], rax -<% } %> - setc dl - -<% for (let i=0; i - mov rax, [rdi + <%=i*8%> ] - <%= i==0 ? "sub" : "sbb" %> rax, [rsi + <%=i*8%>] - mov [rdi + <%=i*8%>], rax -<% } %> - - setc dh - or dl, dh - jz rawNegSL_done - - ; it is a negative value, so add q -<% for (let i=0; i - mov rax, [q + <%=i*8%>] - <%= i==0 ? "add" : "adc" %> [rdi + <%=i*8%>], rax -<% } %> - -rawNegSL_done: - ret - - diff --git a/ports/c/buildasm/tester b/ports/c/buildasm/tester deleted file mode 100755 index 1a99905f3ee062a3d1923ce66db7d2825cdaab7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1518884 zcmeFad3==B^*=rdMp8u+*GB6S_aIi{f(8{0$g~3zjY=%8K|w|9f{-Y-qM;!z<2V(o zQPiqv7gK93T9*_RB2Xq;Epe%)E;w4+K5?iUxA&F9T_RoVC+89hYsy>g^>v1JQTYVi5|5ntns z^Dmis{w%>C9`AxH6kn%disixin|AqSv;6^Q^HPZbIu(5Ic*vVrXk3Z?eQzuI+^g;Bb-1N2jV#>s6|5(-7c;V%~)C%M4umb|VAYYu% z6TfC?3BF4&pWb-UWfwIyUeJ8mv>g6AUQ+(BbmSk)L3{yJ(vEq^n%D4ny9~aVLBjH2 z^GdnR!B|vo%7gr$Hgan*btua}Q?@cQ>I3*o&TX81^`+-seo5oZrdb8?&7A1t3yza` zeij%k*VnmC7foxNes0sbXv^kr=7C$vyvp37o#ny)VP2wDV^+H8!1lUN*it z2H&a!6bs8i{<3j5TElV#`S7@*$DZL$->{fO5^O*(%bp zzDR6l1^RVX4~zW!kVxeDJIf+dZW@Y?N9{rJv9 zQCEpS8DklYDgO9fWx0Lvf%tADgKzMS7(elRHd>1AKhmwmAKS!K6_cZF4KJ5ZJNJ^2 zm(Oe(dEuoqg)?x6uLmDeeK2^u=se|{{@cNS144`p&4HgbP2jP(MvmsU*-g`@jTmw8 z5kWjPK|GNnsBMui6TqB$_3WneFFkmig+X_bTWuH)B?~9~19GIJ%hf&m;6ogW{n49p zs@QK>WHBapxG8hqzxwx;1iq5MR}%P20$)ksD+zohfv+U+l?1+$!2f#^Xo$uCcJ@mC zAB)c&Sg2of|7T+?5gmw?J>3;+?LThmaS+w;74e?fBJCWX`*|Yzd270*t*h*ouCm9w z4AR#1xyBC@e7B=yJGu9`(r@S zP86A4Vu=RA#p165^sO@qs!h)-%dP7xg)^X!#T&d>>s&9=JhYS3n5h7;7faOj3*YfS z#em|MK(Wxk+7YFm*@Sf7vtT@gCRW#hcfm+Dk;@kQ=|0C!*_$R`6>aUqAQfg#!W}?=B2q|G0WI1f8ZveYX*3MPi&^h< zM5ZpM^BLdC+nEYQA;ufhK;k88D@^twH zyF@<^vqJ`#G7q?n*&<5h`V+`cHrsx`TGQ{my#3<+3!);8SRw-M%43PrvSqA+G*&~Y zH@z69pVhx|kp7g2sG=+}aHu4zCV^7U5*xdz=h^U@ag@p)udRWK?O67BbOTm5S&J1U5E)iaokx+a!B7@NHvx9jQPFhME)GeZ7n|0@>IL(+BL#j9 zb0yM>16mhFqP7|~t!Y0QWTL(r0PD%;GwC6*q8@VKtX}5pU;$7KuxGS+-`UgHJe@sS zj22xaomhz1nZ=wa`SgjBh$(Qg=FJ`01kSE1?_}a@DWD>;Pnri{a%g!>M{Cm{`V@PJ z_Hh!PJ3_3a%9-dmIjLGnYs#$2WYt5*FoXKN!t|*m9+<2UY=ANJ4wryeQh5$0z!fZK zIR&=|kxybFQ6~hKG7}gRla5KU=E!oYQ1C)Z$yt-Z?aTj`4SHi#*sKJ#mFCu8MDR{( zL+(42ASG`-2Gf}2C?QrgVKi*@jR{{hkXg$^T zZSTWx3c4Tuj+PeYs$@D5YuhL2KOw$~-Ts8Hlj3Pk_}_NJgxeUv8cL7`D?0PgwM}k@ zjGPmZ)`6m?o!Nz7i<`E#Ux$W0oYjWl%z|j=h=7)5wY^zgxNU8oHp4T=^5Gbc9z0QW zA+`eRXYhPB4(Dt<2KTL~T{L#*_li&rB(nY|2}G(hwK~aL_QYfL;i5obnzH zRE{gM`fA2(cwZekhYY4_x7gY7SGuoO4g0#QDwj|rRlB19+rB>ITX6Ss!d`{V0+fO&2 zXN=VHndbAXv$TA+`8?-bEjJF;vra}B@e8Gff3ey1CL&o}&DVEDbz@H@lsdy(Py zV#Duu4ZoKdJ};HeSaPSYoyBEZKa=GB;v7>flGcSSW)@N{3-FEq*iJoOc!McWnGW4= z2%Va+2GIG0u8Kj7T)5Q)ldw>f>chr88k zw|`>k!5*7#EiI_ch-eauji)qR1JbSeWMSX5zzw10L2VHoHZVkjmY?K7{dEbDGv%>l zN#=|pk<3th>Bko{&c%QviPbF~_{ODdZJ5WHL&D%#qD90JhuqN>D-)vI-F&Tyu4}ep zEXoXvwMGYuGrdAIkIgdt(p!PwcSkzMY%RQmnae1H<(25>2d{p7KDMuG>`{BNY+bR&66{5GRwwbL`HA86nsCdJh7#Cbj z6uY=Lbq>(5I+h$0Ieg2AcNiTXb_cRsqSGsi#ZN8;5h6M@HgEkD9LL6zZEHT`1})_s zf+5F}?NUs(EoN1bX=Uffw6jJ09>$H< zO@_|1Qf!xEvaLty{J_wuS5VekIuG|dI-mYW=m-qx)M;mn_y)bRVK>mtwN5TInpswuGW+ zQBc;}@eKL5qcdFT2n;&U)y@|2BZ9c?MnmT&r6a{;+f=160Dq?l}5sC52)nvQ1)qF2l%YwdVmE@PAE!RbmzU_j?L+Sww0 zcW;6Hz|eU{itSQNwsk3;pBOqZ1!b)r&!4t;bUu{M3IjS(?Q9W$PwDJQX3%=N(vf1a ztzYRJZ0MvJP-?9m&x<~txY7|AV0ueCTg2Ndos$fm5BDOfb}1&?Dn%5do@*e}DQ}K~ zvewdh&)0*!l#allbF+4~h#wHdZPyt(ait^0WLv$`xzNxlS5VekItOfY`u2NSYzhN9 z+h}Ktc%0Jtt)a7*(vf1atwre!F?2c(7rC+4(wY7rN9SavBQT)z3+-$Xzg{V@ZyP$l zmtwmVlWj|s&f>``w^{{dt<{5ji`gXl*0)jgT3|qDjCQt&XDOXBE;6*9taPN9Y)dPh zF@{d>VZsw@?RZi{9i4efM__>I&)V4{-b(2lXXx}{R|!3kVzRAVmiVY%><7riOa*1F zr8C2)vy0LZ7<9f=J6pu}3F5ZP4V`&PM~ca|TBXxu=#(lbYb~Akw{+uq_*0Raz<^GP zcD9I*Qabk-I=d(xDJI)yDxESzXEB|O)>=AqeL54Aj=+GpQy>Rl5}7f5b(OdiP`<&kO}+t)=rLpU!ql zM__>IeC=!z-yw+G8V#MRm5vnQe^{Fwb)BITQBc-eIvqZpUwtBS6By9>0%0NsFPKm~ zR1imReQ_)qT~73m$@hlk zC@%!}&(*7x#%cG3mi245V!ceo`yZ2a^agZPy9uVbiuD85H!9W-(60+v=NPQ(5&N;q zVja4*!@5YZb`kmm?IxHG0H!{PmyixH!4bMVk1m-ZOcD5D)aTzIwq9b$4C7Ze+KA=O z0Dui!{^$cNbpR211faM$05HNk;jSp~u z1F&BGwS)aZTh~6+2l!Z|$w7-t#~6MY0I)v#)m@#G{@?(tpKT5R>`6NfB){+hZgBvW zrg3}#zx&)^09c3g z&Mt1yJ)+5!l65LA0e~`Ns+RZw_c(xZ(|A$<;5buvoeyxC1F&X(j{v~s2H->=V2lHp zX&V1|kU!{qOx^B2z%U134ewI{0Be2MSGYmH@in&|47Nl7z?#t~eSilXK!ipI6L&@c zz}my>eSoVSfVFAE0|3^ro$dp~9Dp@Z10&p^)lQA@d+%y{tKE4a&~-Vvi}+nXC^ch^ ziZQt_&{ZtTpTF+JvWi{jt)h83Q}bU;Mb==S*BwhlyEVa_9QE`Ggn(7q9-lZ;x}^)d z?eQ>VJ+VY{cT7*()TW`AM6qaF$}ROW{0Zzozy>T5Y%HMAYiqK#t5CsBP`}@D+b`aW zW|}bV|HgrY7vr`qxo%xmV_4SwX+4 zV4{t5kfCnA0>oDA17iQ+t}#)LY;B92&BhxR;FINr_^iMuBv4z4Y{g=L+(?iv0WqB8 z6cdn~3`yH>deIlqdF*^UI`{34t-7UMT-LUVGDwaY$My>?{q}l_fXBn}_9^-mT(ryb z7Dn1_us6DBCBB8%tRy~j*mg{FO%_%8iVg(WGp_s^N!}s{9zeYpYw7Q%60MenIT41E0-czL;vxOe?-mEYufmk8f81 z585u+sc>71wlPVin%;waQ!M^;6+JQbp;%pF(_jD&`Zibrx(kJ+HtB)lo3aqwI=Bv# z?fRkn2|W=i=7uZby8lkQcWQV2Xj>wSSnd_P%q5s?C*fG)X>oOl$D|#3128rA_mFsG zY$sF+F6zZtd?R^k+@DZwQ%(GEnigwKag1)YZILH3V$<5Cf3mI1Ctog*?W6>JqTD)+ zPsn#NDP3*D>n1urOn1WCJLRpFt_Ew$6B~#vqhV(J)~b_A;?Xn~GybA*6e7Y{391tfy{@O!?ugEPO|k+VFP)4jtaIDy zNlLbFE&j`9tyBonN9?#K*3r@2p2XW~L`Y+bShcrQ(ZIv*Cbdbq*d(dQ#*0?QQS4o$;9{X}Qh1o^x(@hO&>nE#Z{s(O)L& zD`5qz;4a`ayo0dae^RrLP5{HP+iv}=sA;H-JyT-aMKK`Z9pEVPwTphB{a;w#`PxN& z(Ow6OgZ4f-^x#;GN~OHt1JZ`Ls(*;OS+|3+H5-v;n-u@6?PJyFD&6*424@A(Sf1N*7ydg_H%t%mqVi};am zWF7-PsP(;ySYmsg{sZDa!$fPhw-|ng+*E6HeNkq)^Uk<(0M#6`aW|;Vo}4D@=8xqO z<06ek-jr5Rs+9K^@FjXK3HX%vG&7Lq`|bGN8uf}YzmzGobQfd1el#V6N%|t_V)9I* zsnCgs_gm!XFeDhTVFJ7^xZE#kL7T1-PoCEUzm>8xr-wbGxo$rFp%US&*B)5%g?4w z5!O>l*X|;7M8|+kYwIb0`3g4!8$OttS7R@PPyBbIAmJlAcyJqag1zpMFB+wHg^0F!2%AQck@*r{8BsSYrC}!DhKZ?Uf>B=Us+e0D zR!7`@N?&VB?CN13y*>%8rgHb=c2x=NtGlhCy5{=0yP4&@zj+8C0BALrx35J1$8#eq zO}N9Etgn*q@%qxt-uf-&-9Synn0RAL)J5PfMy=DVLHL(d7t#pFZzZPM14_s;^D!LP2`qM6ej@y5K~f8XvEN4o7UyM) zDq0Fs%p5I|o07T)I5Io1LJ`#xQHo29WqiNFPwnmhiTDzK#bn8O4ks^eEREH1)QGBH z&OC}SbeE!IzPSXs!w17LB7kFfVH_SUd?7xL4&ZnZ9SiXBF2fqKYjolzTQ>Iy*_NuU zP%%rlN=j=_Oiuxf6^Q(;uJC@HXulCig))-YL+@X(ZMB3jOPR!o#Xo_f{44frE8<6W z3VENh)-jo?jRn5fyYIM|O6H%VHPU|M9R3z++p$nv9WDqWj*{_h!+*#!hX2+A2iZ2#`2?DMai`ntVDO4nKcymun}pfY3_>B2XYdC~3Q!6F4i-kzL|VAT z$uhG$=w>e_($f*5bp`kp%2!~j4JFzwP}Z9?fZ}k{rrUX{5qRJM8p7(<6}6`6CWK0^ zcVgm{SUff*mY6sdpHpLrQ)Ym*8E8*~wVBdSuchJgv}g^mc?*6({n18PFVM=2R7<1; zp^{@jMR!@oL%mB^uY0B2KEe`hT~*;S#q-wB&;&_`Z08?aEFbNQ_>pLrk~tk#A#_RD zV9wdwYyCt+JHv%UyPz?rd7Qz`EN77^v2E~eYzC`Yy3gjz(OJCT_y1iMY7vIDsn3x(^}A zd8;TrBTQ$YME#&TvXDh}evC*|HdnrWSLRs-Z}HAe!Bv12kn;ARKgsJytAMaq{HXCl zPuN|iW>er_g_jz+IHJA_2vgf~NYG#j4G~+WysnQyBTk~FuWUOX+2U}WgKP#R1aldP>m#E=Aj^U9dvDZetAEK z%Z53<|9_PC!hCT{?ppZ^0&ufde2-#O>pKI*NcaS7b)FS*dy#`jYxX=+#i0NqxMn22 zvR7p;Kks}lVzPQBIw78t4iZ8yxAW>B*L9;)7uHoL*42_pab#R@T*mqRHa7Fj{F&U& zv9jBz)j`jc_bhJ(Asd7P%1QBeVsT`iVR0D*&=eUF><{sXiqv(nqtWG$v=>$@*C$LA za?dz}WC42!JRqcfQ{Fx3m}%6N;I`S9NT4A*@3fK4b{g)aGlvP^kW>~-4Pd-eSs!2N zeN#Sr*>z$@mb`zumOBY*W1f($G;}@mz~e}O`)jLG{Q(Uz;uAkII_`ZCf%N@toc9ot zj9N6049U8t2F(BxNWXb8gtG`x9oWxbhpd|0mtOrZU}J`zZLqj;$WOl3mf}0ar;~RM z)0lBgRT2}MWd2OF=o9jysSH57i02k~H&k)*0yJE>< z#Y*ubGq*E~LDwW!y(h87M1JE6?SdyXg$xgq!B5J&j|MkU4eTV03Hb|azsG$kc|Z=e z%0g}zhMXag0H(R)zEdD;4P@qW3-{1|Brm~M+3RHyTpWfJxk1`tf)fm+_YxGa zwZ8~s-P@9G6a>^5&Itx5{zuL!WV(=UO`K958$o~eV(ghuhs2f!a#t?`&cb|+m=p$+ zQ*OR`8U=F-^G%FAlL|$uFYik-+=O69a>cgt8QyOeo=^)X+Hz9_>(7lSDbWZ=MEw9O zGNOy*@SVB{R=CmE>dENry(6n;rT3(KVmv9Y_a7Kc>#AU8w$eFwS`B7Ma|ZQEZ>$I! z2n&|PMRv)^2!re16VdbsViIwk*$?66#&a{khxI31cQs%F3{saGy5n`LKm-y_d9NU3 z!FLc(d1+=L5)~+-7j9Tcu{zP9ofC6=$7%*H{<`-Lm!Cm#8&KFw6oT`I#Hlgpvws(H z*h>^(q#TS4K)(2sL%A~h9TfYJg0c1{I|fj=T#xVs9GRkESfINtmIw1C|FazzQe`~d z0_Sp)EEBXH!j=FvN_tMn!o}+rB3pC=`cQ)w`}(~|^;@bJQjggs(Qt$A?mCo4%KJG5 z&6b%JiX)~AL|FmOTIkcbtGNrX6kBj>V~$3Y3rx}l5DR2iPXAzHjE`hB z!C#s3n_9-E6E{zi^kXux+r47?qC>SR}>K=3$dT21ao$IM(We?D2>&Kke1m@ z3T)2s;F(qDuOHBV1(4!%j`d3g>uHbBgvWZ zE?6&}g^l;H!gI%aH&6t|dnbya@y=&&~9SJ2_Rg4R`2vV)D>IQS9chc$xc#nKstv&n6e=>=cMFs!34M% zlE5bVhId16QZJG1v2&Sy!T}b>$~vPROp~KSr3jzDl1urSffA^-Jz0Q4SBke|+Er+h zzqC2|&qMwlN8V*Ks(=8-61ytd0^`Y3i4cJWdnlLE*q&T4qSG|DXKen;wGy#0DgqAN zxnkm6)`}1M+S{!2!&PLz*LbtU+b}PJ;6GVU?tuU~8Gh>7Jj$XlFLPBh*7ftgT**0n zf9DIOZCIHqMdn4!$Z+dZ5@7#A{tZJhB=Ll$bd;fCc&Jyh3t?|@Rb+ppvB43m@$7(f z#rB$!H*CY(UOAiq!oqEZZ}jK_^2`>}U)i-Mr^yjN_msDp^-#h z^LeCBRXE|Ajmi*{(=x?jQlw5%d$0(sPTd0*g6k4Pa^fsBlD}a|J>%`^W;W0dLiFeA zNqAx_ZX>F&;PRC;cU+C}^vc>cw?4o%$|>)6dTNE4jdroT36@%ek8Tz}w!TBNDD#XR z#|0)LsN*|xB%Ajr(NGYrtE%NzsLTO9R0Zzn;6nI-99=%vFCXomoKCiB3AfMR0(88s zLiUe$=|`JFq`Wv$lFPFB7f_N3l~TN|oWv8^!g^26E1kTW zCIyD_Cu5Q=Gb!&WslhEY^H_&<*T*ni)Tbjb0zN&`*UUh}$QaK_%gB)<=B5hUP_X{K z!DU&uG9G}+*cIlH$%99`V#kTrU*Rs-5{;m6H{Jbbi10-9Tb|IQlXYT zHy7}n7s4{S+;mi6ZYG*D;8b*x3ZZUMEE#Pv+Vx8jGm6MX^kqbl%3!ihNJ0E53A1G; zrrYymqwS(ZSHM(5)h_`}t8A0m&rZQXI0ulti4!Jngh`%6B)_k6uoxV4WG+D;p_@$V z2Tg}`8=~F1(5*WY&8z)C#SR)TxihB@h$7$z&AidZ2%06jCxp9(SDUwrCd3BEuzTSb zw^fRzHfH($UJMD#TQ>Ew*h)}id`}@u*gCf-(tJGa8TEKq@P~WS-Mk1X{$A{0IcfuY zvd@q^nG}E5xc;5~l50j5;O-hRCS!OJCcn##x-Jm74yTCHl)$3}$$I9GK$sUQakAn^ z9q(zjJRP>EzAv<%fdQyHL4?!Ql8uYtnGg_4fS|*>llNS?8Hl2K_3|nxllKeBi{XY{ zc`R{isRm!C!U-{rdujzfEAUx~&q^jm{VXAUP{DYZ9MpuojuG$`GDqY9!^XXJ78%mM zjvCxhU!f1aF;gazpR9Wx>02EJ-AjrXh+gf*fMm*-%Em1cD*_BWlA*KVHJMj$7Pn%8 z%`-Jux|r=%)JV)mKgKk_jX^MYWRjRUO1iLSr!Af#UDL%W%Wj}RE!}Xu(^6DL*z`~36PD)NK#oUU< z{Zcfp0>vHz-6q9q!G+tn(YWUyp^riIoY_Oy6D|*QVe#PB6j5s$=CXX8CAcwhz=y3nn?ln`JUXtq8u3--9s34TNi$W+U9fuD= z1Imh2^}`o_ye^INoHrA5@op*}7C^rf$oT@y-2A-}<5T?>-=JC&JOv+nnw^PC%ml=T z+X)o*(b4X*`8WxWcnkid{{J0Xn#)np^Bi6?mpOTa%Sa582>&$+1?67U1yF`O(OEMf zrE5&5up4~iZz6`v&+TKwp?i49)|}G@a^k3eRXc4Ji`z5sV@Qw~-Tf4Nb@zezUG4)} zc87%7t@7EuPD5ZB)H^S8P*6U@>R(wN9qlc{}SoSg(Q%_ks>yh%?4P) z>l69}UysH2FhW8uFrwG1`uIeRc+UqaD#Hq9?`o}!$9ynl1H&tK?!^TjLf2-l;Gap|5#8g}3c0+0Aexc69EQi} zGDyF8{htVXuwcG-x9B~fPn!tB)9Duy#iAb#X|RkgQZ*D+p(DokAV6aYlPP>1%nyjE z@_Gb3L4ZA$FB2(uH!MZ)F}Ye!w3U#K&lQ zVN~J#%ohgvApZWe7l@3y2Z`ZMmJ}iUm3S}}gQshEvuKBytfvxUSX^RRei$OK5caGo zHz_;@`Ujhu%@(J{-fQO7Xq}?{dw7uAIJNR{3NK%XKM&*(_$Pu3FwSdka1XJEt}_E<`9Kg%RqATwc^* zSGX^;Qj;)4kZ4-KGBtXk?Bw;xE*T1g$hP=PMHzFVv|2$Oa$sB=gN(HUTKiv(^{RXT zUpCgq``uVWI)POomPF?8SL=iov-c8n;ReE_V~l}F{ONAVHa^xRAMJcu#Omk=7(=_% zB+WAlg7G_ov0WhS0hBZxs|^H3qC$_o%mI}|Teaf;vTkTE|iyddrEaIH%5C%FH zHzFadZhKB8XtBco$`!Awcvcs_&RfNi1aco@6`^lt&ZrG)Hy|BxAn+r>Sb;LjGrwWa z_UDx#g^t-S#GWOAv7JS2E6^)VOEgr9Vb4aD%C{T^;B{;{HO>>q!5yfc1oi4ZktacG zne_=RJ~gPhHvO9A0o!U<1ol!oQZi8kod9YCMmFEgEKk!ElhZ*po?j7RGuG%5CNQ0E zdlO(|b%(+iEukL*GWkRVBK@O1ncwBq+>1rqjpz!46Q%hkGD7HN(+D~HK2Yz(B?)IW zbfBW&c>nV=ftG4nlP(0~Mm}_{>p~>Jtr`Au(|$gb%I~dIbH%%cyH?Q$8)a3>5@Sz# zWZqH720_vEEw4J(JN+e$tubH*!AMCEqE~cWS42PcFD}wGE9Lx z9^D4~*nFeg8&_v*BW~_@f?y9*aD2wm+Z#NhqLU-N1{N@|37RcMy%dAi{~)2Q8z?~I z*<3Y0fQ7p28F5`ay!mLM!;{PQuYW`;Hbo6P+qw;=F%&_5%Hm-?EX8+)THa71Kq{MzXQ6-1wJW#-B8Q?90FYgNh~yyI26(rz{x-;jIBVN3dTARI^fTB z9F2L!&Ui0W1HNuCnwFRy{LfXIOMtpFGgo1-qn7lc@C{GM}|74N@m-uw#b9{JfYm z_ZyZuYwTMD>wkkhf$={r=S<^`B@kdBUb9wA==F1uc@2(5Cfzmu(>J>5tX$OTkY*ct zi5hL>h~-34f{ok$mIZ+!hf>(DI76S;e&!EG55qO5EXO4r!$b;Qu?Jnbz0IA26UGXKB#x@(MM9o#(vuJ<{vxDH?3nYp@xUk0dV^jgPk-!xG+w$Bz+h+65$A z=MF@gwnKx~;Km|?0+Z5*#ehJKQ1PmXrxk}_lq@YGNuV={+WE8vI1(iRZ4guTns+l3 zl(r`2ohSX;*e_e!!b~88TcT8CId~jrO_oCe`bQd0pu}m9JP|e zSd1bMIQ^PCP=hDG{|BhohEYG8gL)-u=upe%PvAmRiFV<$i>!>1s1lCWln>By3nYp^ zI$*I!2SQSqd-QRP_fAM& zH3d&gQ#mE7b5%drswF^*V9#h!IZA1#d@nG1gOeA>Hx4TfJ(XUkVZ8AP?Xh5781iO? z1ahVsiUEnQLB^LDL`w{!ofXj%AnJRNeqVWatn{lLOk)r|z=l`=&rtPnP;GPMI)hfF zv`X$%B-`~vJE)+afnXr$x>(ZGBDYA&x{vA>?PZcX#4EN=B4kv{>mz*FNsmF!xAFu% zbChnMshH%g3Le93l@EECU%9uojW_y@JF+qFKH3~<<=Pt?7l`I`s^7FAz<_Wj%63D!WypvrCc^s+&k#9xwZ zzT5Jxbjf`fKb{VA1NR_3Lg3sXltZIh_?wK;A*!b1fWLtVMIe*0TgQy3htNx+7(6B} zz~788f2Zf;uiED?paVYD{6SJN{HzO-Dn&M(Jm|&0Ju!y^syZoe1>z)>`(sHk?~n8g z?k*BO291Yu!>r#gaf5VmbZ)PkH>=mzp4K_##2pXyFv1%I@27Bj&_2k5_6K94i9$)% zvMKiKTOzo-VvBpbVcrmyiX2LOPJ{4moDzt>9i;-fuI&5+(AM(j6Pp>{q-|jkHVnTV?w##%ieufSk_ zQr>HHY`lCUrC+0D(W>5e7zxLJ8 z40iK@Z~9F>V72zjMcDG&arx&j-@%H=y9zLRzt)CU2}ghQ?@^HSA`HA9qn)W zhL!g|uR@@hh2Jtv$8WGzX5PpP7qWDFAhsa_XKxBwizgl^z(xq&O`Fy0F$pJB4R(KO zbMQX)B-t!%ElO3Ufdl%O-Yp2(4J%#dAg#R#B<8AvZfJFM6EZ(JDbsbx?tH1NJ}~36 z+W)^m_fbce_9+HVyP+suP?Sz^*@Y=YS)z$s;OMaO&(kVABS*&vk0~h{>G4z6BsE`n z1Ms?5Bt>8Inpk75FTKiRYtwTE>rI$2AG_wvk5KBgkGuC!^X_MNjRju6A7AzDlg`{g z&D6N)Wy;E+xPhyeC}ts&)C^^s#c2#I5uHh}gxgUl`WGW+NsLVI08kw}yXzH*?2Lh~ zP^>IGe*reJGTdqg0>fBt_TL1vjnHcd729n@vbdiVHmqpjb%-4^h>O;670P8I#=OE+ zzk~)7d%@rjlwCOnGNrldH7OcNMj!qxhZ-EsZmf|2%?+@PF5igiZFpum2jNW}5)(8J zOAkr3TdCZDs?0$g`Oa{O7W{D3dc#?PC~k;+$_!Ng5>>fT+(5Qn`Z2avzI~~5lPL!o z$RBZXIBkq|RSrA9n6q|_tC$2^ZB`Z6ikpu?;)gfDW|(|{!<<;){!s67Fsr>y#1KrC zEkIZ0#lQ3Gx!@1C7?FRcz_H%&)DO}IbFiYRaFWf4<~$PuFOpLjTs>_Eu+ zxI^v&G42h*lhC39`T~AMnaY?Zgn+F6X2(M2d}Sg@I~yl>z;11@Hh<<4z25wlm4M@; z^DzB~Tc`A2;0pa_z;x${Kj+HK7n;vXC;PZ4DaM6eUI#EC7LY4$O(ou9Zp6h)hTnLi zxxV1+5M5|?z?{f_6SiIfL(-38z>vHnMO-=Mx_L%Tink2;H_U%HDjw9jIEkFQ8XZ;;$9=zc^WP-kB181JoXrz+58g7%m4ISvwVG^JT91iHNaqSD7Q#ROK>C{!W z#^zJkL0kb~F!>U65y5i3)W#RKXch-J@!NcAX(6*8EYNC86peQf4xf`B;wK$Qpz$hc z#G@-bG_jZWo}%*#bvw=AIEW@SP7jLiB9!ZGUr?ZRCET)aK<*?t4;301Z?(Jxb>0fZ z;s8cw1fo#{n+TMYYj+lBwZ-W&$FFvfE`C)D$I4;)Tjlh9!1NuT(|7H&fDVo8TGO{0 zeKSxyUhTtlBYsCTYW(-Ei}}^a%}&n=X!l=z;^uJ)a|vMz$OQNuO&b0XB_Ch#8#{0ni8mpAT3bm->bUD|{=z4CyWx`oszF~GjvF1g~!5^#on zqIva!JK`#L=1wr+7Ykwfp&iC3*nN>{Tmj&X1z2a7NHr z=Er|d9xK3Rn$o;qimPMMkwd>nw)3xO}-1ilrpD&lYuuHk*xIR8jQAGJpNg-0dtK5{wI z@DcBiDB*{jVB8|!a(;(7e^ku*FIZX&Y(K>p8gWRhp%;b_T|@7`{`&)H54`_6Miw^7 zZb~J5IlpVnzW-106^q1w2GeRGhBZLI_r;p(YH)9P2e_R4w$aR)jxVC4ADxLN+om7O z(k_7G`~Z%txJKPNsT3VI`hAD&X{eW?n>?Lo`rRXsrJRnq!H;jUsX6jzhBxz?7e9Im z@z#w!4uW};+@UZ@At65`Z+-89pp6ILnh=s2m{8=A`)IyM5t}Q!bv76q7m83&uRPU$$!EJfPrGFstU@cbW2kw`z{Pk6>TE zYObU|k(KAKnr~6y*{fzA`7%qb&I09GHD3d8)~dMy3&~$K%w`8x&231XK?TgJX-CPf znmE6^RdYE@Ts0Tqi@$2d&CKkt&PLYr@9sClLC2Gs9?{iNdON-jx;nN6SHAYNTJ5Qw zX;tR~7{DymnQD|^rc<0Z(Mc+E73W6GW47WP!bNLVT@pD}v}Y-f^RN}VgwFQRUzW;M zw5F|IvAMZ&4bv8ZTiCv93A}^%c!j|)%!~bsWx;?1ECn)HvNB7dKK-%aa}#*GpE?d7 zdElntpF~kB0G#F;S}w(We#_n^vapHTQv8GrURj|(z>@VcE385}pym&D$iN?h4OSZg zS;(9GK~IcW#~;zcUb1cVw@7AKHhQ;Sk0Z_deBCk_FSm64OoPorxSg3r7}^dDk{_84 z+Ys2+?1`d=X)>;I6#e|j-mB~=drjQ%J$ASGk&ycq#xPf+Nn)iA#xk(xcXPSx!U_m* z_b`e9?(Rd;=k8Wvol&*rZUeh#aaS!mYmQzDhGUb0Gk8vL z292yXhnsIXZt|*l1}p_avp1zEDt=3sS$tnIF|WaW$dlLk$9xoH>p;8DMPL=r<;wC` z{tZ&}pTEcpGeKdH0+5wIB?~4yR@fiyFh<5jGBkr>z}xr?7VCk{yhyV=;FQN+*cq#I z)avg~MPYnE9ooBwo$ zjD547#o)ZuKnPedCT5mA6wHh3{-o?UJJKqE%ab)P_q~--7_|*~#B&{&?wIMR9AAvva-CfULq9>lr+tcxu@|rmY zD+@5B?|%>u%JhdSAj1*Bp+d%;Dgtm-na}C`%ySdyGDBoFUt;Nle@b%(@RXP}Wt#Ug z$4v=zdc}0QFW3nVJU(u!WnEr&W+glaw-NkDA3lBrBuvqcOytoQXaEbZu$Z_jq(mw2 z2du^O6j2HIoa)?<>de=*&OV88GwWdOC}Jy~;}x7k9QZLX&09s4&AQ`icE;8YBx>hm z?Ui#a&xZ^yVIj>5^6jq+a9mKd6xZ;L34ZoLf#OQddGcQ}#>j)+!Y;mhtj_YMXv{g| zdIfutEZ<@|#<-b>6q`95n_;A9@hY)6y*RA9#tooopeX?cUU**6Nubg(U=9kJXn|bB zB`E%dsM|*o5T~-yk5JFu2qg`BJK{P=MeUDqIpy%k&RPc}H zSq$?wNFVga+bDj5kp!~XuRm!dMKRf*yV!y~FBW5&>*pav-y3}jV*--wWuKFu0@gag z+7htVfqcng}eg4_l@}}VA z#@xw50oZD%FT8tWUm`IA?#agbftRU6BTcM-Z51RrAPQt86=$(MRLe;w;;jM6CAa z1h&i_=wZ)W1>`ny>!1UTx?Uz9TmIlXw6f!tInYoYlZ_-Wqd1&`XybLSn1d}Z(eR2c z<#wiO+|pdQM0d2@8-eCR`Yg0|ll++FB1mBSL6`02?q|=jW(pmjLW}{IvyY

EykT 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%0D?LzZ93wzay{dzg6J- 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а{CbvVL#)X7mTIi}P2@XT5%GPhXQ>E$`3Q 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

6qQXd|<9KpU)e$KNV9?=|mWOL*Z&Jj#8r9M33 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 J*zcY_`!6z4-#h>S diff --git a/ports/c/buildasm/tester.cpp b/ports/c/buildasm/tester.cpp deleted file mode 100644 index b74a983..0000000 --- a/ports/c/buildasm/tester.cpp +++ /dev/null @@ -1,220 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include - -#include /* printf, NULL */ -#include -#include - - -#include "fr.h" - - -typedef void (*Func1)(PFrElement, PFrElement); -typedef void (*Func2)(PFrElement, PFrElement, PFrElement); -typedef void *FuncAny; - -typedef struct { - FuncAny fn; - int nOps; -} FunctionSpec; - -std::map functions; -std::vector stack; - -void addFunction(std::string name, FuncAny f, int nOps) { - FunctionSpec fs; - fs.fn = f; - fs.nOps = nOps; - functions[name] = fs; -} - -void fillMap() { - addFunction("add", (FuncAny)Fr_add, 2); - addFunction("sub", (FuncAny)Fr_sub, 2); - addFunction("neg", (FuncAny)Fr_neg, 1); - addFunction("mul", (FuncAny)Fr_mul, 2); - addFunction("square", (FuncAny)Fr_square, 1); - addFunction("idiv", (FuncAny)Fr_idiv, 2); - addFunction("inv", (FuncAny)Fr_inv, 1); - addFunction("div", (FuncAny)Fr_div, 2); - addFunction("band", (FuncAny)Fr_band, 2); - addFunction("bor", (FuncAny)Fr_bor, 2); - addFunction("bxor", (FuncAny)Fr_bxor, 2); - addFunction("bnot", (FuncAny)Fr_bnot, 1); - addFunction("eq", (FuncAny)Fr_eq, 2); - addFunction("neq", (FuncAny)Fr_neq, 2); - addFunction("lt", (FuncAny)Fr_lt, 2); - addFunction("gt", (FuncAny)Fr_gt, 2); - addFunction("leq", (FuncAny)Fr_leq, 2); - addFunction("geq", (FuncAny)Fr_geq, 2); - addFunction("land", (FuncAny)Fr_land, 2); - addFunction("lor", (FuncAny)Fr_lor, 2); - addFunction("lnot", (FuncAny)Fr_lnot, 1); - addFunction("shl", (FuncAny)Fr_shl, 2); - addFunction("shr", (FuncAny)Fr_shr, 2); -} - -u_int64_t readInt(std::string &s) { - if (s.rfind("0x", 0) == 0) { - return std::stoull(s.substr(2), 0, 16); - } else { - return std::stoull(s, 0, 10); - } -} - -void pushNumber(std::vector &v) { - u_int64_t a; - if ((v.size()<1) || (v.size() > (Fr_N64+1))) { - printf("Invalid Size: %d - %d \n", v.size(), Fr_N64); - throw std::runtime_error("Invalid number of parameters for number"); - } - FrElement e; - a = readInt(v[0]); - *(u_int64_t *)(&e) = a; - for (int i=0; i tokens; - - std::copy(begin, end, std::back_inserter(tokens)); - - // Remove initial empty tokens - while ((tokens.size() > 0)&&(tokens[0] == "")) { - tokens.erase(tokens.begin()); - } - - // Empty lines are valid but are not processed - if (tokens.size() == 0) return; - - auto search = functions.find(tokens[0]); - if (search == functions.end()) { - pushNumber(tokens); - } else { - if (tokens.size() != 1) { - throw std::runtime_error("Functions does not accept parameters"); - } - callFunction(search->second); - } -} - -int main(void) -{ - Fr_init(); - fillMap(); - std::string line; - int i=0; - while (std::getline(std::cin, line)) { - processLine(line); - // if (i%1000 == 0) printf("%d\n", i); - // printf("%d\n", i); - i++; - } - // Print the elements in the stack - // - for (int i=0; i -#include -#include "fr.h" - -typedef void (*Func2)(PFrElement, PFrElement, PFrElement); - -typedef struct { - const char *fnName; - Func2 fn; -} FN; - - -#define NFN 2 -FN fns[NFN] = { - {"add", Fr_add}, - {"mul", Fr_mul}, -}; - -int main(int argc, char **argv) { - - if (argc <= 1) { - fprintf( stderr, "invalid number of parameters"); - return 1; - } - - for (int i=0; i< NFN;i++) { - if (strcmp(argv[1], fns[i].fnName) == 0) { - if (argc != 4) { - fprintf( stderr, "invalid number of parameters"); - return 1; - } - FrElement a; - FrElement b; - - Fr_str2element(&a, argv[2]); - Fr_str2element(&b, argv[3]); - FrElement c; - fns[i].fn(&c, &a, &b); - - char *s; - s = Fr_element2str(&c); - printf("%s", s); - free(s); - return 0; - } - } - fprintf( stderr, "invalid operation %s", argv[1]); - return 1; -} - -*/ diff --git a/ports/c/buildasm/utils.asm.ejs b/ports/c/buildasm/utils.asm.ejs deleted file mode 100644 index a8852bf..0000000 --- a/ports/c/buildasm/utils.asm.ejs +++ /dev/null @@ -1,72 +0,0 @@ -<% global.setTypeDest = function (t) { -return ( -` mov r11b, ${t} - shl r11d, 24 - mov [rdi+4], r11d`); -} %> - - -<% global.toMont_a = function () { -return ( -` push rdi - mov rdi, rsi - mov rsi, rdx - call ${name}_toMontgomery - mov rdx, rsi - mov rsi, rdi - pop rdi`); -} %> - -<% global.toMont_b = function() { -return ( -` push rdi - mov rdi, rdx - call ${name}_toMontgomery - mov rdx, rdi - pop rdi`); -} %> - -<% global.fromMont_a = function () { -return ( -` push rdi - mov rdi, rsi - mov rsi, rdx - call ${name}_toNormal - mov rdx, rsi - mov rsi, rdi - pop rdi`); -} %> - -<% global.fromMont_b = function() { -return ( -` push rdi - mov rdi, rdx - call ${name}_toNormal - mov rdx, rdi - pop rdi`); -} %> - -<% global.toLong_a = function () { -return ( -` push rdi - push rdx - mov rdi, rsi - movsx rsi, r8d - call rawCopyS2L - mov rsi, rdi - pop rdx - pop rdi`); -} %> - -<% global.toLong_b = function() { -return ( -` push rdi - push rsi - mov rdi, rdx - movsx rsi, r9d - call rawCopyS2L - mov rdx, rdi - pop rsi - pop rdi`); -} %> - diff --git a/ports/c/calcwit.cpp b/ports/c/calcwit.cpp deleted file mode 100644 index fc3bcda..0000000 --- a/ports/c/calcwit.cpp +++ /dev/null @@ -1,234 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "calcwit.h" -#include "utils.h" - -Circom_CalcWit::Circom_CalcWit(Circom_Circuit *aCircuit) { - circuit = aCircuit; - -#ifdef SANITY_CHECK - signalAssigned = new bool[circuit->NSignals]; - signalAssigned[0] = true; -#endif - - mutexes = new std::mutex[NMUTEXES]; - cvs = new std::condition_variable[NMUTEXES]; - inputSignalsToTrigger = new int[circuit->NComponents]; - signalValues = new FrElement[circuit->NSignals]; - - // Set one signal - Fr_copy(&signalValues[0], circuit->constants + 1); - - reset(); -} - - -Circom_CalcWit::~Circom_CalcWit() { - -#ifdef SANITY_CHECK - delete signalAssigned; -#endif - - delete[] cvs; - delete[] mutexes; - - delete[] signalValues; - delete[] inputSignalsToTrigger; - -} - -void Circom_CalcWit::syncPrintf(const char *format, ...) { - va_list args; - va_start(args, format); - - printf_mutex.lock(); - vprintf(format, args); - printf_mutex.unlock(); - - va_end(args); -} - -void Circom_CalcWit::reset() { - -#ifdef SANITY_CHECK - for (int i=1; iNComponents; i++) signalAssigned[i] = false; -#endif - - for (int i=0; iNComponents; i++) { - inputSignalsToTrigger[i] = circuit->components[i].inputSignals; - } - for (int i=0; iNComponents; i++) { - if (inputSignalsToTrigger[i] == 0) triggerComponent(i); - } -} - - -int Circom_CalcWit::getSubComponentOffset(int cIdx, u64 hash) { - int hIdx; - for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) { - if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash)); - } - int entryPos = circuit->components[cIdx].hashTable[hIdx].pos; - if (circuit->components[cIdx].entries[entryPos].type != _typeComponent) { - throw std::runtime_error("invalid type"); - } - return circuit->components[cIdx].entries[entryPos].offset; -} - - -Circom_Sizes Circom_CalcWit::getSubComponentSizes(int cIdx, u64 hash) { - int hIdx; - for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) { - if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash)); - } - int entryPos = circuit->components[cIdx].hashTable[hIdx].pos; - if (circuit->components[cIdx].entries[entryPos].type != _typeComponent) { - throw std::runtime_error("invalid type"); - } - return circuit->components[cIdx].entries[entryPos].sizes; -} - -int Circom_CalcWit::getSignalOffset(int cIdx, u64 hash) { - int hIdx; - for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) { - if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash)); - } - int entryPos = circuit->components[cIdx].hashTable[hIdx].pos; - if (circuit->components[cIdx].entries[entryPos].type != _typeSignal) { - throw std::runtime_error("invalid type"); - } - return circuit->components[cIdx].entries[entryPos].offset; -} - -Circom_Sizes Circom_CalcWit::getSignalSizes(int cIdx, u64 hash) { - int hIdx; - for(hIdx = int(hash & 0xFF); hash!=circuit->components[cIdx].hashTable[hIdx].hash; hIdx++) { - if (!circuit->components[cIdx].hashTable[hIdx].hash) throw std::runtime_error("hash not found: " + int_to_hex(hash)); - } - int entryPos = circuit->components[cIdx].hashTable[hIdx].pos; - if (circuit->components[cIdx].entries[entryPos].type != _typeSignal) { - throw std::runtime_error("invalid type"); - } - return circuit->components[cIdx].entries[entryPos].sizes; -} - -void Circom_CalcWit::getSignal(int currentComponentIdx, int cIdx, int sIdx, PFrElement value) { - // syncPrintf("getSignal: %d\n", sIdx); - if ((circuit->components[cIdx].newThread)&&(currentComponentIdx != cIdx)) { - std::unique_lock lk(mutexes[cIdx % NMUTEXES]); - while (inputSignalsToTrigger[cIdx] != -1) { - cvs[cIdx % NMUTEXES].wait(lk); - } - // cvs[cIdx % NMUTEXES].wait(lk, [&]{return inputSignalsToTrigger[cIdx] == -1;}); - lk.unlock(); - } -#ifdef SANITY_CHECK - if (signalAssigned[sIdx] == false) { - fprintf(stderr, "Accessing a not assigned signal: %d\n", sIdx); - assert(false); - } -#endif - Fr_copy(value, signalValues + sIdx); - /* - char *valueStr = mpz_get_str(0, 10, *value); - syncPrintf("%d, Get %d --> %s\n", currentComponentIdx, sIdx, valueStr); - free(valueStr); - */ -} - -void Circom_CalcWit::finished(int cIdx) { - { - std::lock_guard lk(mutexes[cIdx % NMUTEXES]); - inputSignalsToTrigger[cIdx] = -1; - } - // syncPrintf("Finished: %d\n", cIdx); - cvs[cIdx % NMUTEXES].notify_all(); -} - -void Circom_CalcWit::setSignal(int currentComponentIdx, int cIdx, int sIdx, PFrElement value) { - // syncPrintf("setSignal: %d\n", sIdx); - -#ifdef SANITY_CHECK - if (signalAssigned[sIdx] == true) { - fprintf(stderr, "Signal assigned twice: %d\n", sIdx); - assert(false); - } - signalAssigned[sIdx] = true; -#endif - // Log assignement - /* - char *valueStr = mpz_get_str(0, 10, *value); - syncPrintf("%d, Set %d --> %s\n", currentComponentIdx, sIdx, valueStr); - free(valueStr); - */ - Fr_copy(signalValues + sIdx, value); - if ( BITMAP_ISSET(circuit->mapIsInput, sIdx) ) { - if (inputSignalsToTrigger[cIdx]>0) { - inputSignalsToTrigger[cIdx]--; - if (inputSignalsToTrigger[cIdx] == 0) triggerComponent(cIdx); - } else { - fprintf(stderr, "Input signals does not match with map: %d\n", sIdx); - assert(false); - } - } - -} - -void Circom_CalcWit::checkConstraint(int currentComponentIdx, PFrElement value1, PFrElement value2, char const *err) { -#ifdef SANITY_CHECK - FrElement tmp; - Fr_eq(&tmp, value1, value2); - if (!Fr_isTrue(&tmp)) { - char *pcV1 = Fr_element2str(value1); - char *pcV2 = Fr_element2str(value2); - // throw std::runtime_error(std::to_string(currentComponentIdx) + std::string(", Constraint doesn't match, ") + err + ". " + sV1 + " != " + sV2 ); - fprintf(stderr, "Constraint doesn't match, %s: %s != %s", err, pcV1, pcV2); - free(pcV1); - free(pcV2); - assert(false); - } -#endif -} - - -void Circom_CalcWit::triggerComponent(int newCIdx) { - //int oldCIdx = cIdx; - // cIdx = newCIdx; - if (circuit->components[newCIdx].newThread) { - // syncPrintf("Triggered: %d\n", newCIdx); - std::thread t(circuit->components[newCIdx].fn, this, newCIdx); - // t.join(); - t.detach(); - } else { - (*(circuit->components[newCIdx].fn))(this, newCIdx); - } - // cIdx = oldCIdx; -} - -void Circom_CalcWit::log(PFrElement value) { - char *pcV = Fr_element2str(value); - syncPrintf("Log: %s\n", pcV); - free(pcV); -} - -void Circom_CalcWit::join() { - for (int i=0; iNComponents; i++) { - std::unique_lock lk(mutexes[i % NMUTEXES]); - while (inputSignalsToTrigger[i] != -1) { - cvs[i % NMUTEXES].wait(lk); - } - // cvs[i % NMUTEXES].wait(lk, [&]{return inputSignalsToTrigger[i] == -1;}); - lk.unlock(); - // syncPrintf("Joined: %d\n", i); - } - -} - - diff --git a/ports/c/calcwit.h b/ports/c/calcwit.h deleted file mode 100644 index 00f0445..0000000 --- a/ports/c/calcwit.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef CIRCOM_CALCWIT_H -#define CIRCOM_CALCWIT_H - -#include "circom.h" -#include "fr.h" -#include -#include - -#define NMUTEXES 128 - -class Circom_CalcWit { - -#ifdef SANITY_CHECK - bool *signalAssigned; -#endif - - // componentStatus -> For each component - // >0 Signals required to trigger - // == 0 Component triggered - // == -1 Component finished - int *inputSignalsToTrigger; - std::mutex *mutexes; - std::condition_variable *cvs; - - std::mutex printf_mutex; - - FrElement *signalValues; - - - void triggerComponent(int newCIdx); - void calculateWitness(void *input, void *output); - - void syncPrintf(const char *format, ...); - - -public: - Circom_Circuit *circuit; - -// Functions called by the circuit - Circom_CalcWit(Circom_Circuit *aCircuit); - ~Circom_CalcWit(); - - int getSubComponentOffset(int cIdx, u64 hash); - Circom_Sizes getSubComponentSizes(int cIdx, u64 hash); - int getSignalOffset(int cIdx, u64 hash); - Circom_Sizes getSignalSizes(int cIdx, u64 hash); - - void getSignal(int currentComponentIdx, int cIdx, int sIdx, PFrElement value); - void setSignal(int currentComponentIdx, int cIdx, int sIdx, PFrElement value); - - void checkConstraint(int currentComponentIdx, PFrElement value1, PFrElement value2, char const *err); - - void log(PFrElement value); - - void finished(int cIdx); - void join(); - - -// Public functions - inline void setInput(int idx, PFrElement val) { - setSignal(0, 0, circuit->wit2sig[idx], val); - } - inline void getWitness(int idx, PFrElement val) { - Fr_copy(val, &signalValues[circuit->wit2sig[idx]]); - } - - void reset(); - -}; - - - -#endif // CIRCOM_CALCWIT_H diff --git a/ports/c/circom.h b/ports/c/circom.h deleted file mode 100644 index 258c02e..0000000 --- a/ports/c/circom.h +++ /dev/null @@ -1,58 +0,0 @@ -#ifndef __CIRCOM_H -#define __CIRCOM_H - -#include -#include -#include "fr.h" - -class Circom_CalcWit; -typedef unsigned long long u64; -typedef uint32_t u32; -typedef uint8_t u8; - -typedef int Circom_Size; -typedef Circom_Size *Circom_Sizes; - -struct Circom_HashEntry { - u64 hash; - int pos; -}; -typedef Circom_HashEntry *Circom_HashTable; - -typedef enum { _typeSignal, _typeComponent} Circom_EntryType; - -struct Circom_ComponentEntry { - int offset; - Circom_Sizes sizes; - Circom_EntryType type; -}; -typedef Circom_ComponentEntry *Circom_ComponentEntries; - -typedef void (*Circom_ComponentFunction)(Circom_CalcWit *ctx, int __cIdx); - -struct Circom_Component { - Circom_HashTable hashTable; - Circom_ComponentEntries entries; - Circom_ComponentFunction fn; - int inputSignals; - bool newThread; -}; - -class Circom_Circuit { -public: - int NSignals; - int NComponents; - int NInputs; - int NOutputs; - int NVars; - int *wit2sig; - Circom_Component *components; - u32 *mapIsInput; - PFrElement constants; - const char *P; -}; - -#define BITMAP_ISSET(m, b) (m[b>>5] & (1 << (b&0x1F))) -extern struct Circom_Circuit _circuit; - -#endif diff --git a/ports/c/fr.c b/ports/c/fr.c deleted file mode 120000 index b3a3f61..0000000 --- a/ports/c/fr.c +++ /dev/null @@ -1 +0,0 @@ -buildasm/fr.c \ No newline at end of file diff --git a/ports/c/fr.h b/ports/c/fr.h deleted file mode 120000 index f682bb8..0000000 --- a/ports/c/fr.h +++ /dev/null @@ -1 +0,0 @@ -buildasm/fr.h \ No newline at end of file diff --git a/ports/c/fr.o b/ports/c/fr.o deleted file mode 120000 index 14a80cb..0000000 --- a/ports/c/fr.o +++ /dev/null @@ -1 +0,0 @@ -buildasm/fr.o \ No newline at end of file diff --git a/ports/c/main.cpp b/ports/c/main.cpp deleted file mode 100644 index 3a8b2ea..0000000 --- a/ports/c/main.cpp +++ /dev/null @@ -1,202 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -using json = nlohmann::json; - -#include "calcwit.h" -#include "circom.h" -#include "utils.h" - -#define handle_error(msg) \ - do { perror(msg); exit(EXIT_FAILURE); } while (0) - -void loadBin(Circom_CalcWit *ctx, std::string filename) { - int fd; - struct stat sb; - - // map input - fd = open(filename.c_str(), O_RDONLY); - if (fd == -1) - handle_error("open"); - - if (fstat(fd, &sb) == -1) /* To obtain file size */ - handle_error("fstat"); - - - u8 *in; - - in = (u8 *)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (in == MAP_FAILED) - handle_error("mmap"); - - close(fd); - - FrElement v; - u8 *p = in; - for (int i=0; i<_circuit.NInputs; i++) { - v.type = Fr_LONG; - for (int j=0; jsetSignal(0, 0, _circuit.wit2sig[1 + _circuit.NOutputs + i], &v); - } -} - - -typedef void (*ItFunc)(Circom_CalcWit *ctx, int idx, json val); - -void iterateArr(Circom_CalcWit *ctx, int o, Circom_Sizes sizes, json jarr, ItFunc f) { - if (!jarr.is_array()) { - assert((sizes[0] == 1)&&(sizes[1] == 0)); - f(ctx, o, jarr); - } else { - int n = sizes[0] / sizes[1]; - for (int i=0; i(); - } else if (val.is_number()) { - - double vd = val.get(); - std::stringstream stream; - stream << std::fixed << std::setprecision(0) << vd; - s = stream.str(); - } else { - handle_error("Invalid JSON type"); - } - - Fr_str2element (&v, s.c_str()); - - ctx->setSignal(0, 0, o, &v); -} - - -void loadJson(Circom_CalcWit *ctx, std::string filename) { - std::ifstream inStream(filename); - json j; - inStream >> j; - - for (json::iterator it = j.begin(); it != j.end(); ++it) { -// std::cout << it.key() << " => " << it.value() << '\n'; - u64 h = fnv1a(it.key()); - int o; - try { - o = ctx->getSignalOffset(0, h); - } catch (std::runtime_error e) { - std::ostringstream errStrStream; - errStrStream << "Error loadin variable: " << it.key() << "\n" << e.what(); - throw std::runtime_error(errStrStream.str() ); - } - Circom_Sizes sizes = ctx->getSignalSizes(0, h); - iterateArr(ctx, o, sizes, it.value(), itFunc); - } - -} - - -void writeOutBin(Circom_CalcWit *ctx, std::string filename) { - FILE *write_ptr; - - write_ptr = fopen(filename.c_str(),"wb"); - - FrElement v; - - u8 buffOut[256]; - for (int i=0;i<_circuit.NVars;i++) { - size_t size=256; - ctx->getWitness(i, &v); - Fr_toLongNormal(&v); - fwrite(v.longVal, Fr_N64*8, 1, write_ptr); - } - fclose(write_ptr); - -} - - -void writeOutJson(Circom_CalcWit *ctx, std::string filename) { - - std::ofstream outFile; - outFile.open (filename); - - outFile << "[\n"; - - FrElement v; - - for (int i=0;i<_circuit.NVars;i++) { - ctx->getWitness(i, &v); - char *pcV = Fr_element2str(&v); - std::string sV = std::string(pcV); - outFile << (i ? "," : " ") << "\"" << sV << "\"\n"; - free(pcV); - } - - outFile << "]\n"; - outFile.close(); -} - -bool hasEnding (std::string const &fullString, std::string const &ending) { - if (fullString.length() >= ending.length()) { - return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending)); - } else { - return false; - } -} - -int main(int argc, char *argv[]) { - Fr_init(); - if (argc!=3) { - std::string cl = argv[0]; - std::string base_filename = cl.substr(cl.find_last_of("/\\") + 1); - std::cout << "Usage: " << base_filename << " > >\n"; - } else { - - // open output - Circom_CalcWit *ctx = new Circom_CalcWit(&_circuit); - - std::string infilename = argv[1]; - - if (hasEnding(infilename, std::string(".bin"))) { - loadBin(ctx, infilename); - } else if (hasEnding(infilename, std::string(".json"))) { - loadJson(ctx, infilename); - } else { - handle_error("Invalid input extension (.bin / .json)"); - } - - ctx->join(); - - // printf("Finished!\n"); - - std::string outfilename = argv[2]; - - if (hasEnding(outfilename, std::string(".bin"))) { - writeOutBin(ctx, outfilename); - } else if (hasEnding(outfilename, std::string(".json"))) { - writeOutJson(ctx, outfilename); - } else { - handle_error("Invalid output extension (.bin / .json)"); - } - - delete ctx; - exit(EXIT_SUCCESS); - } -} diff --git a/ports/c/mainjson.cpp b/ports/c/mainjson.cpp deleted file mode 100644 index b711e1a..0000000 --- a/ports/c/mainjson.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include -using json = nlohmann::json; - - -#include "utils.h" -#include "circom.h" -#include "calcwit.h" - -auto j = R"( - { - "in": "314" - } -)"_json; - -typedef void (*ItFunc)(int idx, json val); - -void iterateArr(int o, Circom_Sizes sizes, json jarr, ItFunc f) { - if (!jarr.is_array()) { - assert((sizes[0] == 1)&&(sizes[1] == 0)); - f(o, jarr); - } else { - int n = sizes[0] / sizes[1]; - for (int i=0; i " << it.value() << '\n'; - u64 h = fnv1a(it.key()); - int o = ctx->getSignalOffset(0, h); - Circom_Sizes sizes = ctx->getSignalSizes(0, h); - iterateArr(o, sizes, it.value(), itFunc); - } -} - diff --git a/ports/c/tester.js b/ports/c/tester.js index 84c1dc0..1edd55c 100644 --- a/ports/c/tester.js +++ b/ports/c/tester.js @@ -8,12 +8,11 @@ const compiler = require("../../src/compiler"); const util = require("util"); const exec = util.promisify(require("child_process").exec); -const stringifyBigInts = require("../../src/utils").stringifyBigInts; -const unstringifyBigInts = require("../../src/utils").unstringifyBigInts; const bigInt = require("big-integer"); const utils = require("../../src/utils"); -const loadR1cs = require("../../src/r1csfile").loadR1cs; -const ZqField = require("fflib").ZqField; +const loadR1cs = require("r1csfile").load; +const ZqField = require("ffjavascript").ZqField; +const buildZqField = require("ffiasm").buildZqField; module.exports = c_tester; @@ -31,22 +30,39 @@ async function c_tester(circomFile, _options) { options.cSourceWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".cpp")); options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym")); options.r1csFileName = path.join(dir.path, baseName + ".r1cs"); + + options.p = options.p || bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); await compiler(circomFile, options); - const cdir = path.join(__dirname, "..", "c"); - await exec("cp" + - ` ${path.join(dir.path, baseName + ".cpp")}` + - " /tmp/circuit.cpp" - ); + const source = await buildZqField(options.p, "Fr"); + + // console.log(dir.path); + + await fs.promises.writeFile(path.join(dir.path, "fr.asm"), source.asm, "utf8"); + await fs.promises.writeFile(path.join(dir.path, "fr.h"), source.h, "utf8"); + await fs.promises.writeFile(path.join(dir.path, "fr.c"), source.c, "utf8"); + + if (process.platform === "darwin") { + await exec("nasm -fmacho64 --prefix _ " + + ` ${path.join(dir.path, "fr.asm")}` + ); + } else if (process.platform === "linux") { + await exec("nasm -felf64 " + + ` ${path.join(dir.path, "fr.asm")}` + ); + } else throw("Unsupported platform"); + + const cdir = path.join(__dirname, "..", "..", "node_modules", "circom_runtime", "c"); + await exec("g++" + ` ${path.join(cdir, "main.cpp")}` + ` ${path.join(cdir, "calcwit.cpp")}` + ` ${path.join(cdir, "utils.cpp")}` + - ` ${path.join(cdir, "fr.c")}` + - ` ${path.join(cdir, "fr.o")}` + + ` ${path.join(dir.path, "fr.c")}` + + ` ${path.join(dir.path, "fr.o")}` + ` ${path.join(dir.path, baseName + ".cpp")} ` + ` -o ${path.join(dir.path, baseName)}` + - ` -I ${cdir}` + + ` -I ${dir.path} -I${cdir}` + " -lgmp -std=c++11 -DSANITY_CHECK -g" ); @@ -68,7 +84,7 @@ class CTester { async calculateWitness(input) { await fs.promises.writeFile( path.join(this.dir.path, "in.json"), - JSON.stringify(stringifyBigInts(input), null, 1) + JSON.stringify(utils.stringifyBigInts(input), null, 1) ); const r = await exec(`${path.join(this.dir.path, this.baseName)}` + ` ${path.join(this.dir.path, "in.json")}` + @@ -81,7 +97,7 @@ class CTester { path.join(this.dir.path, "out.json") ); - const res = unstringifyBigInts(JSON.parse(resStr)); + const res = utils.unstringifyBigInts(JSON.parse(resStr)); return res; } @@ -95,10 +111,11 @@ class CTester { const lines = symsStr.split("\n"); for (let i=0; i -#include -#include -#include -#include - -#include "utils.h" - -std::string int_to_hex( u64 i ) -{ - std::stringstream stream; - stream << "0x" - << std::setfill ('0') << std::setw(16) - << std::hex << i; - return stream.str(); -} - -u64 fnv1a(std::string s) { - u64 hash = 0xCBF29CE484222325LL; - for(char& c : s) { - hash ^= u64(c); - hash *= 0x100000001B3LL; - } - return hash; -} diff --git a/ports/c/utils.h b/ports/c/utils.h deleted file mode 100644 index e2d72bf..0000000 --- a/ports/c/utils.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef __UTILS_H -#define __UTILS_H - -#include "circom.h" - -std::string int_to_hex( u64 i ); -u64 fnv1a(std::string s); - - -#endif // __UTILS_H diff --git a/ports/c/zqfield.cpp b/ports/c/zqfield.cpp deleted file mode 100644 index 84605f6..0000000 --- a/ports/c/zqfield.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include "zqfield.h" - -ZqField::ZqField(PBigInt ap) { - mpz_init_set(p, *ap); - mpz_init_set_ui(zero, 0); - mpz_init_set_ui(one, 1); - nBits = mpz_sizeinbase (p, 2); - mpz_init(mask); - mpz_mul_2exp(mask, one, nBits-1); - mpz_sub(mask, mask, one); -} - -ZqField::~ZqField() { - mpz_clear(p); - mpz_clear(zero); - mpz_clear(one); -} - -void ZqField::add(PBigInt r, PBigInt a, PBigInt b) { - mpz_add(*r,*a,*b); - if (mpz_cmp(*r, p) >= 0) { - mpz_sub(*r, *r, p); - } -} - -void ZqField::sub(PBigInt r, PBigInt a, PBigInt b) { - if (mpz_cmp(*a, *b) >= 0) { - mpz_sub(*r, *a, *b); - } else { - mpz_sub(*r, *b, *a); - mpz_sub(*r, p, *r); - } -} - -void ZqField::neg(PBigInt r, PBigInt a) { - if (mpz_sgn(*a) > 0) { - mpz_sub(*r, p, *a); - } else { - mpz_set(*r, *a); - } -} - -void ZqField::mul(PBigInt r, PBigInt a, PBigInt b) { - mpz_t tmp; - mpz_init(tmp); - mpz_mul(tmp,*a,*b); - mpz_fdiv_r(*r, tmp, p); - mpz_clear(tmp); -} - -void ZqField::div(PBigInt r, PBigInt a, PBigInt b) { - mpz_t tmp; - mpz_init(tmp); - mpz_invert(tmp, *b, p); - mpz_mul(tmp,*a,tmp); - mpz_fdiv_r(*r, tmp, p); - mpz_clear(tmp); -} - -void ZqField::idiv(PBigInt r, PBigInt a, PBigInt b) { - mpz_fdiv_q(*r, *a, *b); -} - -void ZqField::mod(PBigInt r, PBigInt a, PBigInt b) { - mpz_fdiv_r(*r, *a, *b); -} - -void ZqField::pow(PBigInt r, PBigInt a, PBigInt b) { - mpz_powm(*r, *a, *b, p); -} - -void ZqField::lt(PBigInt r, PBigInt a, PBigInt b) { - int c = mpz_cmp(*a, *b); - if (c<0) { - mpz_set(*r, one); - } else { - mpz_set(*r, zero); - } -} - -void ZqField::eq(PBigInt r, PBigInt a, PBigInt b) { - int c = mpz_cmp(*a, *b); - if (c==0) { - mpz_set(*r, one); - } else { - mpz_set(*r, zero); - } -} - -void ZqField::gt(PBigInt r, PBigInt a, PBigInt b) { - int c = mpz_cmp(*a, *b); - if (c>0) { - mpz_set(*r, one); - } else { - mpz_set(*r, zero); - } -} - -void ZqField::leq(PBigInt r, PBigInt a, PBigInt b) { - int c = mpz_cmp(*a, *b); - if (c<=0) { - mpz_set(*r, one); - } else { - mpz_set(*r, zero); - } -} - -void ZqField::geq(PBigInt r, PBigInt a, PBigInt b) { - int c = mpz_cmp(*a, *b); - if (c>=0) { - mpz_set(*r, one); - } else { - mpz_set(*r, zero); - } -} - -void ZqField::neq(PBigInt r, PBigInt a, PBigInt b) { - int c = mpz_cmp(*a, *b); - if (c!=0) { - mpz_set(*r, one); - } else { - mpz_set(*r, zero); - } -} - -void ZqField::land(PBigInt r, PBigInt a, PBigInt b) { - if (mpz_sgn(*a) && mpz_sgn(*b)) { - mpz_set(*r, one); - } else { - mpz_set(*r, zero); - } -} - -void ZqField::lor(PBigInt r, PBigInt a, PBigInt b) { - if (mpz_sgn(*a) || mpz_sgn(*b)) { - mpz_set(*r, one); - } else { - mpz_set(*r, zero); - } -} - -void ZqField::lnot(PBigInt r, PBigInt a) { - if (mpz_sgn(*a)) { - mpz_set(*r, zero); - } else { - mpz_set(*r, one); - } -} - -int ZqField::isTrue(PBigInt a) { - return mpz_sgn(*a); -} - -void ZqField::copyn(PBigInt a, PBigInt b, int n) { - for (int i=0;i= 0) { - mpz_set(*r, zero); - } else { - mpz_mul_2exp(*r, *a, mpz_get_ui(*b)); - mpz_and(*r, *r, mask); - } -} - -void ZqField::shr(PBigInt r, PBigInt a, PBigInt b) { - if (mpz_cmp_ui(*b, nBits) >= 0) { - mpz_set(*r, zero); - } else { - mpz_tdiv_q_2exp(*r, *a, mpz_get_ui(*b)); - mpz_and(*r, *r, mask); - } -} - -int ZqField::toInt(PBigInt a) { - return mpz_get_si (*a); -} - diff --git a/ports/c/zqfield.h b/ports/c/zqfield.h deleted file mode 100644 index 1080387..0000000 --- a/ports/c/zqfield.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef ZQFIELD_H -#define ZQFIELD_H - -#include "circom.h" - -class ZqField { -public: - BigInt p; - BigInt one; - BigInt zero; - size_t nBits; - BigInt mask; - ZqField(PBigInt ap); - ~ZqField(); - - void copyn(PBigInt a, PBigInt b, int n); - - void add(PBigInt r,PBigInt a, PBigInt b); - void sub(PBigInt r,PBigInt a, PBigInt b); - void neg(PBigInt r,PBigInt a); - void mul(PBigInt r,PBigInt a, PBigInt b); - void div(PBigInt r,PBigInt a, PBigInt b); - void idiv(PBigInt r,PBigInt a, PBigInt b); - void mod(PBigInt r,PBigInt a, PBigInt b); - void pow(PBigInt r,PBigInt a, PBigInt b); - - void lt(PBigInt r, PBigInt a, PBigInt b); - void eq(PBigInt r, PBigInt a, PBigInt b); - void gt(PBigInt r, PBigInt a, PBigInt b); - void leq(PBigInt r, PBigInt a, PBigInt b); - void geq(PBigInt r, PBigInt a, PBigInt b); - void neq(PBigInt r, PBigInt a, PBigInt b); - - void land(PBigInt r, PBigInt a, PBigInt b); - void lor(PBigInt r, PBigInt a, PBigInt b); - void lnot(PBigInt r, PBigInt a); - - void band(PBigInt r, PBigInt a, PBigInt b); - void bor(PBigInt r, PBigInt a, PBigInt b); - void bxor(PBigInt r, PBigInt a, PBigInt b); - void bnot(PBigInt r, PBigInt a); - void shl(PBigInt r, PBigInt a, PBigInt b); - void shr(PBigInt r, PBigInt a, PBigInt b); - - int isTrue(PBigInt a); - int toInt(PBigInt a); -}; - -#endif // ZQFIELD_H diff --git a/ports/wasm/build_runtime.js b/ports/wasm/build_runtime.js index f568e7d..2c74cce 100644 --- a/ports/wasm/build_runtime.js +++ b/ports/wasm/build_runtime.js @@ -1,13 +1,16 @@ const errs = require("./errs"); -const buildWasmFf = require("fflib").buildWasmFf; +const buildWasmFf = require("ffwasm").buildWasmFf; module.exports = function buildRuntime(module, builder) { + const pSanityCheck = module.alloc(4); + function buildInit() { const f = module.addFunction("init"); + f.addParam("sanityCheck", "i32"); f.addLocal("i", "i32"); const c = f.getCodeBuilder(); @@ -26,6 +29,14 @@ module.exports = function buildRuntime(module, builder) { ) ); + // Save Sanity check flag + f.addCode( + c.i32_store( + c.i32_const(pSanityCheck), + c.getLocal("sanityCheck") + ) + ); + f.addCode( // i=0 c.setLocal("i", c.i32_const(0)), @@ -66,38 +77,36 @@ module.exports = function buildRuntime(module, builder) { )) ); - if (builder.sanityCheck) { - f.addCode( - // i=0 - c.setLocal("i", c.i32_const(0)), - c.block(c.loop( - // if (i==NSignals) break - c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NSignals))), - - // signalsAssigned[i] = false - c.i32_store( - c.i32_add( - c.i32_const(builder.pSignalsAssigned), - c.i32_mul( - c.getLocal("i"), - c.i32_const(4) - ) - ), - c.i32_const(0) - ), + f.addCode(ifSanityCheck(c, + // i=0 + c.setLocal("i", c.i32_const(0)), + c.block(c.loop( + // if (i==NSignals) break + c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NSignals))), - // i=i+1 - c.setLocal( - "i", - c.i32_add( + // signalsAssigned[i] = false + c.i32_store( + c.i32_add( + c.i32_const(builder.pSignalsAssigned), + c.i32_mul( c.getLocal("i"), - c.i32_const(1) + c.i32_const(4) ) ), - c.br(0) - )) - ); - } + c.i32_const(0) + ), + + // i=i+1 + c.setLocal( + "i", + c.i32_add( + c.getLocal("i"), + c.i32_const(1) + ) + ), + c.br(0) + )) + )); f.addCode( c.call( @@ -109,14 +118,12 @@ module.exports = function buildRuntime(module, builder) { ) ) ); - if (builder.sanityCheck) { - f.addCode( - c.i32_store( - c.i32_const(builder.pSignalsAssigned), - c.i32_const(1) - ) - ); - } + f.addCode(ifSanityCheck(c, + c.i32_store( + c.i32_const(builder.pSignalsAssigned), + c.i32_const(1) + ) + )); f.addCode( // i=0 @@ -158,6 +165,13 @@ module.exports = function buildRuntime(module, builder) { } + function ifSanityCheck(c, ...args) { + return c.if( + c.i32_load(c.i32_const(pSanityCheck)), + [].concat(...[...args]) + ); + } + function buildTriggerComponent() { const f = module.addFunction("triggerComponent"); @@ -227,9 +241,13 @@ module.exports = function buildRuntime(module, builder) { c.if( c.i64_eqz(c.getLocal("h")), c.call( - "err", + "error", c.i32_const(errs.HASH_NOT_FOUND.code), - c.i32_const(errs.HASH_NOT_FOUND.pointer) + c.i32_const(errs.HASH_NOT_FOUND.pointer), + c.i32_const(0), + c.i32_const(0), + c.i32_const(0), + c.i32_const(0) ) ), c.setLocal( @@ -296,9 +314,13 @@ module.exports = function buildRuntime(module, builder) { c.i32_const(type) ), c.call( - "err", + "error", c.i32_const(errs.INVALID_TYPE.code), - c.i32_const(errs.INVALID_TYPE.pointer) + c.i32_const(errs.INVALID_TYPE.pointer), + c.i32_const(0), + c.i32_const(0), + c.i32_const(0), + c.i32_const(0) ) ), c.i32_store( @@ -345,28 +367,30 @@ module.exports = function buildRuntime(module, builder) { const c = f.getCodeBuilder(); - if (builder.sanityCheck) { - f.addCode( - c.if( - c.i32_eqz( - c.i32_load( - c.i32_add( - c.i32_const(builder.pSignalsAssigned), - c.i32_mul( - c.getLocal("signal"), - c.i32_const(4) - ) - ), - ) - ), - c.call( - "err", - c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code), - c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer) + f.addCode(ifSanityCheck(c, + c.if( + c.i32_eqz( + c.i32_load( + c.i32_add( + c.i32_const(builder.pSignalsAssigned), + c.i32_mul( + c.getLocal("signal"), + c.i32_const(4) + ) + ), ) + ), + c.call( + "error", + c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code), + c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer), + c.i32_const(0), + c.i32_const(0), + c.i32_const(0), + c.i32_const(0) ) - ); - } + ) + )); f.addCode( c.call( @@ -381,6 +405,11 @@ module.exports = function buildRuntime(module, builder) { ) ) ); + + f.addCode(ifSanityCheck(c, + c.call("logGetSignal", c.getLocal("signal"), c.getLocal("pR") ) + )); + } @@ -395,25 +424,10 @@ module.exports = function buildRuntime(module, builder) { const c = f.getCodeBuilder(); - if (builder.sanityCheck) { - f.addCode( - c.if( - c.i32_load( - c.i32_add( - c.i32_const(builder.pSignalsAssigned), - c.i32_mul( - c.getLocal("signal"), - c.i32_const(4) - ) - ), - ), - c.call( - "err", - c.i32_const(errs.SIGNAL_ASSIGNED_TWICE.code), - c.i32_const(errs.SIGNAL_ASSIGNED_TWICE.pointer) - ) - ), - c.i32_store( + f.addCode(ifSanityCheck(c, + c.call("logSetSignal", c.getLocal("signal"), c.getLocal("pVal") ), + c.if( + c.i32_load( c.i32_add( c.i32_const(builder.pSignalsAssigned), c.i32_mul( @@ -421,10 +435,28 @@ module.exports = function buildRuntime(module, builder) { c.i32_const(4) ) ), - c.i32_const(1) ), - ); - } + c.call( + "error", + c.i32_const(errs.SIGNAL_ASSIGNED_TWICE.code), + c.i32_const(errs.SIGNAL_ASSIGNED_TWICE.pointer), + c.i32_const(0), + c.i32_const(0), + c.i32_const(0), + c.i32_const(0) + ) + ), + c.i32_store( + c.i32_add( + c.i32_const(builder.pSignalsAssigned), + c.i32_mul( + c.getLocal("signal"), + c.i32_const(4) + ) + ), + c.i32_const(1) + ), + )); f.addCode( c.call( @@ -510,11 +542,13 @@ module.exports = function buildRuntime(module, builder) { ) ], c.call( - "err2", + "error", c.i32_const(errs.MAPISINPUT_DONT_MATCH.code), c.i32_const(errs.MAPISINPUT_DONT_MATCH.pointer), c.getLocal("component"), - c.getLocal("signal") + c.getLocal("signal"), + c.i32_const(0), + c.i32_const(0) ) ) ] @@ -528,6 +562,23 @@ module.exports = function buildRuntime(module, builder) { const c = f.getCodeBuilder(); + f.addCode(ifSanityCheck(c, + c.call("logFinishComponent", c.getLocal("cIdx")) + )); + + f.addCode(c.ret([])); + } + + function buildComponentStarted() { + const f = module.addFunction("componentStarted"); + f.addParam("cIdx", "i32"); + + const c = f.getCodeBuilder(); + + f.addCode(ifSanityCheck(c, + c.call("logStartComponent", c.getLocal("cIdx")) + )); + f.addCode(c.ret([])); } @@ -541,33 +592,31 @@ module.exports = function buildRuntime(module, builder) { const c = f.getCodeBuilder(); - if (builder.sanityCheck) { - f.addCode( - c.call( - "Fr_eq", - c.i32_const(pTmp), - c.getLocal("pA"), - c.getLocal("pB") - ), - c.if ( - c.i32_eqz( - c.call( - "Fr_isTrue", - c.i32_const(pTmp), - ) - ), + f.addCode(ifSanityCheck(c, + c.call( + "Fr_eq", + c.i32_const(pTmp), + c.getLocal("pA"), + c.getLocal("pB") + ), + c.if ( + c.i32_eqz( c.call( - "err4", - c.i32_const(errs.CONSTRAIN_DOES_NOT_MATCH.code), - c.i32_const(errs.CONSTRAIN_DOES_NOT_MATCH.pointer), - c.getLocal("cIdx"), - c.getLocal("pA"), - c.getLocal("pB"), - c.getLocal("pStr"), + "Fr_isTrue", + c.i32_const(pTmp), ) + ), + c.call( + "error", + c.i32_const(errs.CONSTRAIN_DOES_NOT_MATCH.code), + c.i32_const(errs.CONSTRAIN_DOES_NOT_MATCH.pointer), + c.getLocal("cIdx"), + c.getLocal("pA"), + c.getLocal("pB"), + c.getLocal("pStr"), ) - ); - } + ) + )); } function buildGetNVars() { @@ -638,9 +687,13 @@ module.exports = function buildRuntime(module, builder) { ) ), c.call( - "err", + "error", c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.code), - c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer) + c.i32_const(errs.ACCESSING_NOT_ASSIGNED_SIGNAL.pointer), + c.i32_const(0), + c.i32_const(0), + c.i32_const(0), + c.i32_const(0) ) ) ); @@ -658,35 +711,92 @@ module.exports = function buildRuntime(module, builder) { ); } - const fErr = module.addIimportFunction("err", "runtime"); - fErr.addParam("code", "i32"); - fErr.addParam("pStr", "i32"); - - const fErr1 = module.addIimportFunction("err1", "runtime"); - fErr1.addParam("code", "i32"); - fErr1.addParam("pStr", "i32"); - fErr1.addParam("param1", "i32"); - - const fErr2 = module.addIimportFunction("err2", "runtime"); - fErr2.addParam("code", "i32"); - fErr2.addParam("pStr", "i32"); - fErr2.addParam("param1", "i32"); - fErr2.addParam("param2", "i32"); - - const fErr3 = module.addIimportFunction("err3", "runtime"); - fErr3.addParam("code", "i32"); - fErr3.addParam("pStr", "i32"); - fErr3.addParam("param1", "i32"); - fErr3.addParam("param2", "i32"); - fErr3.addParam("param3", "i32"); - - const fErr4 = module.addIimportFunction("err4", "runtime"); - fErr4.addParam("code", "i32"); - fErr4.addParam("pStr", "i32"); - fErr4.addParam("param1", "i32"); - fErr4.addParam("param2", "i32"); - fErr4.addParam("param3", "i32"); - fErr4.addParam("param4", "i32"); + function buildGetWitnessBuffer() { + const f = module.addFunction("getWitnessBuffer"); + f.setReturnType("i32"); + f.addLocal("i", "i32"); + f.addLocal("pSrc", "i32"); + f.addLocal("pDst", "i32"); + + const c = f.getCodeBuilder(); + + f.addCode( + c.setLocal("i", c.i32_const(0)), + c.block(c.loop( + // if (i==NComponents) break + c.br_if(1, c.i32_eq(c.getLocal("i"), c.i32_const(builder.header.NVars))), + + c.setLocal( + "pSrc", + c.i32_add( + c.i32_const(builder.pSignals), + c.i32_mul( + c.getLocal("i"), + c.i32_const(builder.sizeFr) + ) + ) + ), + + c.call( + "Fr_toLongNormal", + c.getLocal("pSrc") + ), + + c.setLocal( + "pDst", + c.i32_add( + c.i32_const(builder.pSignals), + c.i32_mul( + c.getLocal("i"), + c.i32_const(builder.sizeFr-8) + ) + ) + ), + + c.call( + "Fr_F1m_copy", + c.i32_add(c.getLocal("pSrc"), c.i32_const(8)), + c.getLocal("pDst") + ), + + // i=i+1 + c.setLocal( + "i", + c.i32_add( + c.getLocal("i"), + c.i32_const(1) + ) + ), + c.br(0) + )), + + c.i32_const(builder.pSignals) + ); + + } + + + const fError = module.addIimportFunction("error", "runtime"); + fError.addParam("code", "i32"); + fError.addParam("pStr", "i32"); + fError.addParam("param1", "i32"); + fError.addParam("param2", "i32"); + fError.addParam("param3", "i32"); + fError.addParam("param4", "i32"); + + const fLogSetSignal = module.addIimportFunction("logSetSignal", "runtime"); + fLogSetSignal.addParam("signal", "i32"); + fLogSetSignal.addParam("val", "i32"); + + const fLogGetSignal = module.addIimportFunction("logGetSignal", "runtime"); + fLogGetSignal.addParam("signal", "i32"); + fLogGetSignal.addParam("val", "i32"); + + const fLogFinishComponent = module.addIimportFunction("logFinishComponent", "runtime"); + fLogFinishComponent.addParam("cIdx", "i32"); + + const fLogStartComponent = module.addIimportFunction("logStartComponent", "runtime"); + fLogStartComponent.addParam("cIdx", "i32"); const fLog = module.addIimportFunction("log", "runtime"); fLog.addParam("code", "i32"); @@ -695,9 +805,7 @@ module.exports = function buildRuntime(module, builder) { builder.pSignals=module.alloc(builder.header.NSignals*builder.sizeFr); builder.pInputSignalsToTrigger=module.alloc(builder.header.NComponents*4); - if (builder.sanityCheck) { - builder.pSignalsAssigned=module.alloc(builder.header.NSignals*4); - } + builder.pSignalsAssigned=module.alloc(builder.header.NSignals*4); buildHash2ComponentEntry(); @@ -713,6 +821,7 @@ module.exports = function buildRuntime(module, builder) { buildGetSignal(); buildSetSignal(); + buildComponentStarted(); buildComponentFinished(); buildCheckConstraint(); @@ -721,6 +830,7 @@ module.exports = function buildRuntime(module, builder) { buildGetFrLen(); buildGetPWitness(); buildGetPRawPrime(); + buildGetWitnessBuffer(); // buildFrToInt(); @@ -732,5 +842,6 @@ module.exports = function buildRuntime(module, builder) { module.exportFunction("getPWitness"); module.exportFunction("Fr_toInt"); module.exportFunction("getPRawPrime"); + module.exportFunction("getWitnessBuffer"); }; diff --git a/ports/wasm/builder.js b/ports/wasm/builder.js index 6b5c429..f96bd10 100644 --- a/ports/wasm/builder.js +++ b/ports/wasm/builder.js @@ -528,9 +528,13 @@ class FunctionBuilderWasm { c.getLocal("sp") ), c.call( - "err", + "error", c.i32_const(errs.STACK_OUT_OF_MEM.code), - c.i32_const(errs.STACK_OUT_OF_MEM.pointer) + c.i32_const(errs.STACK_OUT_OF_MEM.pointer), + c.i32_const(0), + c.i32_const(0), + c.i32_const(0), + c.i32_const(0) ) ), @@ -550,9 +554,13 @@ class FunctionBuilderWasm { c.getLocal("sp") ), c.call( - "err", + "error", c.i32_const(errs.STACK_TOO_SMALL.code), - c.i32_const(errs.STACK_TOO_SMALL.pointer) + c.i32_const(errs.STACK_TOO_SMALL.pointer), + c.i32_const(0), + c.i32_const(0), + c.i32_const(0), + c.i32_const(0) ) ), @@ -650,7 +658,12 @@ class FunctionBuilderWasm { const c = f.getCodeBuilder(); + const code = []; + if (this.type=="COMPONENT") { + code.push(c.call("componentStarted", c.getLocal("cIdx"))); + } + code.push(this._buildHeader(c)); code.push(this.body.build(c)); if (this.type=="COMPONENT") { @@ -676,7 +689,7 @@ class FunctionBuilderWasm { } class BuilderWasm { - constructor(sanityCheck) { + constructor() { this.hashMaps={}; this.componentEntriesTables={}; this.sizes ={}; @@ -684,7 +697,6 @@ class BuilderWasm { this.usedConstants = {}; this.functions = []; this.components = []; - this.sanityCheck = sanityCheck; this.TYPE_SIGNAL = 1; this.TYPE_COMPONENT = 2; diff --git a/ports/wasm/tester.js b/ports/wasm/tester.js index 1a36bba..8da1644 100644 --- a/ports/wasm/tester.js +++ b/ports/wasm/tester.js @@ -5,21 +5,16 @@ const fs = require("fs"); var tmp = require("tmp-promise"); const path = require("path"); const compiler = require("../../src/compiler"); -const util = require("util"); -const exec = util.promisify(require("child_process").exec); -const stringifyBigInts = require("../../src/utils").stringifyBigInts; -const unstringifyBigInts = require("../../src/utils").unstringifyBigInts; const bigInt = require("big-integer"); const utils = require("../../src/utils"); -const loadR1cs = require("../../src/r1csfile").loadR1cs; -const ZqField = require("fflib").ZqField; +const loadR1cs = require("r1csfile").load; +const ZqField = require("ffjavascript").ZqField; -const WitnessCalculator = require("./witness_calculator"); +const WitnessCalculatorBuilder = require("circom_runtime").WitnessCalculatorBuilder; module.exports = wasm_tester; - async function wasm_tester(circomFile, _options) { tmp.setGracefulCleanup(); @@ -33,7 +28,6 @@ async function wasm_tester(circomFile, _options) { options.wasmWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".wasm")); options.symWriteStream = fs.createWriteStream(path.join(dir.path, baseName + ".sym")); options.r1csFileName = path.join(dir.path, baseName + ".r1cs"); - options.sanityCheck = true; const promisesArr = []; promisesArr.push(new Promise(fulfill => options.wasmWriteStream.on("finish", fulfill))); @@ -42,7 +36,9 @@ async function wasm_tester(circomFile, _options) { await Promise.all(promisesArr); - const wc = await WitnessCalculator.fromFile(path.join(dir.path, baseName + ".wasm")); + const wasm = await fs.promises.readFile(path.join(dir.path, baseName + ".wasm")); + + const wc = await WitnessCalculatorBuilder(wasm); return new WasmTester(dir, baseName, wc); } @@ -74,10 +70,11 @@ class WasmTester { const lines = symsStr.split("\n"); for (let i=0; i0; i++) bytes.push(i8[p+i]); - - return String.fromCharCode.apply(null, bytes); - } -}; - -class WitnessCalculator { - constructor(memory, instance) { - this.memory = memory; - this.i32 = new Uint32Array(memory.buffer); - this.instance = instance; - - this.n32 = (this.instance.exports.getFrLen() >> 2) - 2; - const pRawPrime = this.instance.exports.getPRawPrime(); - - this.prime = bigInt(0); - for (let i=this.n32-1; i>=0; i--) { - this.prime = this.prime.shiftLeft(32); - this.prime = this.prime.add(bigInt(this.i32[(pRawPrime >> 2) + i])); - } - - this.mask32 = bigInt("FFFFFFFF", 16); - this.NVars = this.instance.exports.getNVars(); - this.n64 = Math.floor((this.prime.bitLength() - 1) / 64)+1; - this.R = bigInt.one.shiftLeft(this.n64*64); - this.RInv = this.R.modInv(this.prime); - - } - - async calculateWitness(input) { - const w = []; - const old0 = this.i32[0]; - this.instance.exports.init(); - const pSigOffset = this.allocInt(); - const pFr = this.allocFr(); - for (let k in input) { - const h = utils.fnvHash(k); - const hMSB = parseInt(h.slice(0,8), 16); - const hLSB = parseInt(h.slice(8,16), 16); - this.instance.exports.getSignalOffset32(pSigOffset, 0, hMSB, hLSB); - const sigOffset = this.getInt(pSigOffset); - const fArr = utils.flatArray(input[k]); - for (let i=0; i>2]; - } - - setInt(p, v) { - this.i32[p>>2] = v; - } - - getFr(p) { - const self = this; - const idx = (p>>2); - - if (self.i32[idx + 1] & 0x80000000) { - let res= bigInt(0); - for (let i=self.n32-1; i>=0; i--) { - res = res.shiftLeft(32); - res = res.add(bigInt(self.i32[idx+2+i])); - } - if (self.i32[idx + 1] & 0x40000000) { - return fromMontgomery(res); - } else { - return res; - } - - } else { - if (self.i32[idx] & 0x80000000) { - return self.prime.add( bigInt(self.i32[idx]).minus(bigInt(0x100000000)) ); - } else { - return bigInt(self.i32[idx]); - } - } - - function fromMontgomery(n) { - return n.times(self.RInv).mod(self.prime); - } - - } - - - setFr(p, v) { - const self = this; - v = bigInt(v); - - if (v.lt(bigInt("80000000", 16)) ) { - return setShortPositive(v); - } - if (v.geq(self.prime.minus(bigInt("80000000", 16))) ) { - return setShortNegative(v); - } - return setLongNormal(v); - - function setShortPositive(a) { - self.i32[(p >> 2)] = parseInt(a); - self.i32[(p >> 2) + 1] = 0; - } - - function setShortNegative(a) { - const b = bigInt("80000000", 16 ).add(a.minus( self.prime.minus(bigInt("80000000", 16 )))); - self.i32[(p >> 2)] = parseInt(b); - self.i32[(p >> 2) + 1] = 0; - } - - function setLongNormal(a) { - self.i32[(p >> 2)] = 0; - self.i32[(p >> 2) + 1] = 0x80000000; - for (let i=0; i> 2) + 2 + i] = a.shiftRight(i*32).and(self.mask32); - } - } - } -} - - - diff --git a/src/buildsyms.js b/src/buildsyms.js index 688f1b2..f99bc70 100644 --- a/src/buildsyms.js +++ b/src/buildsyms.js @@ -19,7 +19,7 @@ module.exports = function buildSyms(ctx) { while (ctx.signals[s].e >= 0) s = ctx.signals[s].e; let wId = ctx.signals[s].id; if (typeof(wId) == "undefined") wId=-1; - rs.push(`${actual.offset},${wId},${actual.name}\n`); + rs.push(`${actual.offset},${wId},${actual.cIdx},${actual.name}\n`); it.next(); counter ++; @@ -32,11 +32,12 @@ module.exports = function buildSyms(ctx) { class SignalIt { - constructor (ctx, offset, prefix) { + constructor (ctx, offset, prefix, cIdx) { this.ctx = ctx; this.offset = offset; this.prefix = prefix; this.cur = 0; + this.cIdx = cIdx; } next() { @@ -47,16 +48,16 @@ class SignalIt { current() { if (this.cur == 0) { - return {offset: this.offset, name: this.prefix}; + return {offset: this.offset, name: this.prefix, cIdx: this.cIdx}; } } } class ArrayIt { - constructor (ctx, type, sizes, offset, prefix) { + constructor (ctx, type, sizes, offset, prefix, cIdx) { if (sizes.length == 0) { if (type == "S") { - return new SignalIt(ctx, offset, prefix); + return new SignalIt(ctx, offset, prefix, cIdx); } else { return new ComponentIt(ctx, offset, prefix); } @@ -67,6 +68,7 @@ class ArrayIt { this.sizes = sizes; this.offset = offset; this.prefix = prefix; + this.cIdx = cIdx; @@ -86,7 +88,7 @@ class ArrayIt { _loadSubIt() { if (this.cur < this.sizes[0]) { - this.subIt = new ArrayIt(this.ctx, this.type, this.sizes.slice(1), this.offset + this.cur*this.subArrSize, this.prefix + "[" + this.cur + "]"); + this.subIt = new ArrayIt(this.ctx, this.type, this.sizes.slice(1), this.offset + this.cur*this.subArrSize, this.prefix + "[" + this.cur + "]", this.cIdx); } } @@ -129,7 +131,7 @@ class ComponentIt { _loadSubIt() { if (this.cur < this.names.length) { const entrie = this.ctx.components[this.idxComponent].names.o[this.names[this.cur]]; - this.subIt = new ArrayIt(this.ctx, entrie.type, entrie.sizes, entrie.offset, this.prefix + "." + this.names[this.cur]); + this.subIt = new ArrayIt(this.ctx, entrie.type, entrie.sizes, entrie.offset, this.prefix + "." + this.names[this.cur], this.idxComponent); } } diff --git a/src/compiler.js b/src/compiler.js index 4016c3d..005fdd1 100644 --- a/src/compiler.js +++ b/src/compiler.js @@ -18,14 +18,14 @@ */ const bigInt = require("big-integer"); -const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); +const __P__ = bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); const sONE = 0; const build = require("./build"); const BuilderC = require("../ports/c/builder.js"); const BuilderWasm = require("../ports/wasm/builder.js"); const constructionPhase = require("./construction_phase"); const Ctx = require("./ctx"); -const ZqField = require("fflib").ZqField; +const ZqField = require("ffjavascript").ZqField; const utils = require("./utils"); const buildR1cs = require("./r1csfile").buildR1cs; const BigArray = require("./bigarray"); @@ -49,7 +49,7 @@ async function compile(srcFile, options) { constructionPhase(ctx, srcFile); - console.log("NConstraints Before: "+ctx.constraints.length); + if (ctx.verbose) console.log("NConstraints Before: "+ctx.constraints.length); if (ctx.error) { throw(ctx.error); @@ -70,13 +70,13 @@ async function compile(srcFile, options) { // Repeat while reductions are performed let oldNConstrains = -1; while (ctx.constraints.length != oldNConstrains) { - console.log("Reducing constraints: "+ctx.constraints.length); + if (ctx.verbose) console.log("Reducing constraints: "+ctx.constraints.length); oldNConstrains = ctx.constraints.length; reduceConstrains(ctx); } } - console.log("NConstraints After: "+ctx.constraints.length); + if (ctx.verbose) console.log("NConstraints After: "+ctx.constraints.length); generateWitnessNames(ctx); @@ -94,7 +94,7 @@ async function compile(srcFile, options) { } if ((options.wasmWriteStream)||(options.watWriteStream)) { - ctx.builder = new BuilderWasm(options.sanityCheck); + ctx.builder = new BuilderWasm(); build(ctx); if (options.wasmWriteStream) { const rdStream = ctx.builder.build("wasm"); diff --git a/src/construction_phase.js b/src/construction_phase.js index 3f3262c..2736e86 100644 --- a/src/construction_phase.js +++ b/src/construction_phase.js @@ -924,7 +924,9 @@ function execConstrain(ctx, ast) { if (!ctx.lc.isZero(res)) { ctx.constraints.push(ctx.lc.toQEX(res)); - if ((ctx.constraints.length % 10000 == 0)&&(ctx.constraints.length>0)) console.log("Constraints: " + ctx.constraints.length); + if (ctx.verbose) { + if ((ctx.constraints.length % 10000 == 0)&&(ctx.constraints.length>0)) console.log("Constraints: " + ctx.constraints.length); + } } return a; diff --git a/src/r1csfile.js b/src/r1csfile.js index 8ea335d..f141f9a 100644 --- a/src/r1csfile.js +++ b/src/r1csfile.js @@ -4,157 +4,6 @@ const assert = require("assert"); const bigInt = require("big-integer"); module.exports.buildR1cs = buildR1cs; -module.exports.loadR1cs = loadR1cs; - -async function loadR1cs(fileName, loadConstraints, loadMap) { - const res = {}; - const fd = await fs.promises.open(fileName, "r"); - - const b = Buffer.allocUnsafe(4); - await fd.read(b, 0, 4, 0); - - if (b.toString() != "r1cs") assert(false, "Invalid File format"); - - let p=4; - - let v = await readU32(); - - if (v>1) assert(false, "Version not supported"); - - const nSections = await readU32(); - - let pHeader; - let pConstraints; - let headerSize; - let constraintsSize; - let pMap; - let mapSize; - for (let i=0; i { await doTest(wasm_tester, basicCases[i].circuit, basicCases[i].tv); }); } -*/ + }); diff --git a/test/basiccases.js.old b/test/basiccases.js.old deleted file mode 100644 index f7351ec..0000000 --- a/test/basiccases.js.old +++ /dev/null @@ -1,343 +0,0 @@ -const path = require("path"); - -const bigInt = require("big-integer"); -const c_tester = require("../index.js").c_tester; - -const __P__ = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); - - -function normalize(o) { - if ((typeof(o) == "bigint") || o.isZero !== undefined) { - const res = bigInt(o); - return norm(res); - } else if (Array.isArray(o)) { - return o.map(normalize); - } else if (typeof o == "object") { - const res = {}; - for (let k in o) { - res[k] = normalize(o[k]); - } - return res; - } else { - const res = bigInt(o); - return norm(res); - } - - function norm(n) { - let res = n.mod(__P__); - if (res.isNegative()) res = __P__.add(res); - return res; - } -} - - -async function doTest(circuit, testVectors) { - const cir = await c_tester(path.join(__dirname, "circuits", circuit)); - - for (let i=0; i { - await doTest( - "inout.circom", - [ - [{in1: 1, in2: [2,3], in3:[[4,5], [6,7], [8,9]]}, {out1: 1, out2: [2,3], out3: [[4,5], [6,7],[8,9]]}], - ] - ); - }); - it("add", async () => { - await doTest( - "add.circom", - [ - [{in: [0,0]}, {out: 0}], - [{in: [0,1]}, {out: 1}], - [{in: [1,2]}, {out: 3}], - [{in: [__P__.minus(1),1]}, {out: 0}], - ] - ); - }); - it("add constant", async () => { - await doTest( - "addconst1.circom", - [ - [{in: 0}, {out: 15}], - [{in: 10}, {out: 25}], - [{in: __P__.minus(2)}, {out: 13}], - ] - ); - }); - it("for unrolled", async () => { - await doTest( - "forunrolled.circom", - [ - [{in: 0}, {out: [0,1,2]}], - [{in: 10}, {out: [10, 11, 12]}], - [{in: __P__.minus(2)}, {out: [__P__.minus(2), __P__.minus(1), 0]}], - ] - ); - }); - it("for rolled", async () => { - await doTest( - "forrolled.circom", - [ - [{in: 0}, {out: 0}], - [{in: 10}, {out: 10}], - ] - ); - }); - it("while unrolled", async () => { - await doTest( - "whileunrolled.circom", - [ - [{in: 0}, {out: [0,1,2]}], - [{in: 10}, {out: [10, 11, 12]}], - [{in: __P__.minus(2)}, {out: [__P__.minus(2), __P__.minus(1), 0]}], - ] - ); - }); - it("while rolled", async () => { - await doTest( - "whilerolled.circom", - [ - [{in: 0}, {out: 0}], - [{in: 10}, {out: 10}], - ] - ); - }); - it("function1", async () => { - await doTest( - "function1.circom", - [ - [{in: 0}, {out: 3}], - [{in: 10}, {out: 13}], - [{in: __P__.minus(2)}, {out: 1}], - ] - ); - }); - it("function2", async () => { - await doTest( - "function2.circom", - [ - [{in: 0}, {out: 3}], - [{in: 10}, {out: 13}], - [{in: __P__.minus(2)}, {out: 1}], - ] - ); - }); - it("constants1", async () => { - await doTest( - "constants1.circom", - [ - [{in: 0}, {out: 42}], - [{in: 10}, {out: 52}], - [{in: __P__.minus(2)}, {out: 40}], - ] - ); - }); - it("arrays", async () => { - await doTest( - "arrays.circom", - [ - [{in: 0}, {out: [1, 8, 51]}], - [{in: 10}, {out: [11, 28, 111]}], - [{in: __P__.minus(2)}, {out: [__P__.minus(1), 4, 39]}], - ] - ); - }); - it("if unrolled", async () => { - await doTest( - "ifunrolled.circom", - [ - [{in: 0}, {out: [1, 3, 6]}], - [{in: 10}, {out: [11, 13, 16]}], - [{in: __P__.minus(2)}, {out: [__P__.minus(1), 1, 4]}], - ] - ); - }); - it("if rolled", async () => { - await doTest( - "ifrolled.circom", - [ - [{in: 0}, {out: [1, 0, 0]}], - [{in: 1}, {out: [0, 1, 0]}], - [{in: 2}, {out: [0, 0, 1]}], - [{in: 3}, {out: [0, 0, 0]}], - [{in: __P__.minus(2)}, {out: [0,0,0]}], - ] - ); - }); - it("inc", async () => { - await doTest( - "inc.circom", - [ - [{in: 0}, {out: [5, 2]}], - [{in: 1}, {out: [6, 4]}], - [{in: 2}, {out: [7, 6]}], - [{in: 3}, {out: [8, 8]}], - [{in: __P__.minus(2)}, {out: [3,__P__.minus(2)]}], - ] - ); - }); - it("dec", async () => { - await doTest( - "dec.circom", - [ - [{in: 0}, {out: [1, __P__.minus(2)]}], - [{in: 1}, {out: [2, 0]}], - [{in: 2}, {out: [3, 2]}], - [{in: 3}, {out: [4, 4]}], - [{in: __P__.minus(2)}, {out: [__P__.minus(1),__P__.minus(6)]}], - ] - ); - }); - it("ops", async () => { - await doTest( - "ops.circom", - [ - [{in: [-2, 2]}, {add: 0, sub: -4, mul: -4}], - [{in: [-1, 1]}, {add: 0, sub: -2, mul: -1}], - [{in: [ 0, 0]}, {add: 0, sub: 0, mul: 0}], - [{in: [ 1,-1]}, {add: 0, sub: 2, mul: -1}], - [{in: [ 2,-2]}, {add: 0, sub: 4, mul: -4}], - [{in: [-2,-3]}, {add: -5, sub: 1, mul: 6}], - [{in: [ 2, 3]}, {add: 5, sub: -1, mul: 6}], - ] - ); - }); - it("ops2", async () => { - await doTest( - "ops2.circom", - [ - [{in: [-2, 2]}, {div: -1, idiv: bigInt("10944121435919637611123202872628637544274182200208017171849102093287904247807"), mod: 1}], - [{in: [-1, 1]}, {div: -1, idiv: -1, mod: 0}], - [{in: [ 1,-1]}, {div: -1, idiv: 0, mod: 1}], - ] - ); - }); - it("ops3", async () => { - await doTest( - "ops3.circom", - [ - [{in: [-2, 2]}, {neg1: 2,neg2: -2, pow: 4}], - [{in: [0, 1]}, {neg1: 0, neg2: -1, pow: 0}], - [{in: [ 1,-1]}, {neg1: -1, neg2: 1, pow: 1}], - ] - ); - }); - it("Comparation ops", async () => { - await doTest( - "opscmp.circom", - [ - [{in: [ 8, 9]}, {lt: 1, leq: 1, eq:0, neq:1, geq: 0, gt:0}], - [{in: [-2,-2]}, {lt: 0, leq: 1, eq:1, neq:0, geq: 1, gt:0}], - [{in: [-1,-2]}, {lt: 0, leq: 0, eq:0, neq:1, geq: 1, gt:1}], - [{in: [ 1,-1]}, {lt: 0, leq: 0, eq:0, neq:1, geq: 1, gt:1}], // In mod, negative values are higher than positive. - ] - ); - }); - it("Bit ops", async () => { - const mask = bigInt("14474011154664524427946373126085988481658748083205070504932198000989141204991"); - const m1m = bigInt("7414231717174750794300032619171286606889616317210963838766006185586667290624"); - await doTest( - "opsbit.circom", - [ - [{in: [ 5, 3]}, {and: 1, or: 7, xor:6, not1:mask.minus(5), shl: 40, shr:0}], - [{in: [ 0, 0]}, {and: 0, or: 0, xor:0, not1:mask, shl: 0, shr:0}], - [{in: [-1, 1]}, {and: 0, or: m1m.add(bigInt.one), xor:m1m.add(bigInt.one), not1:mask.minus(m1m), shl: m1m.shiftLeft(1).and(mask), shr:__P__.shiftRight(1).and(mask)}], - ] - ); - }); - it("Logical ops", async () => { - await doTest( - "opslog.circom", - [ - [{in: [ 5, 0]}, {and: 0, or: 1, not1:0}], - [{in: [ 0, 1]}, {and: 0, or: 1, not1:1}], - [{in: [-1, 9]}, {and: 1, or: 1, not1:0}], - [{in: [ 0, 0]}, {and: 0, or: 0, not1:1}], - ] - ); - }); - - it("Conditional Ternary operator", async () => { - await doTest( - "condternary.circom", - [ - [{in: 0}, {out: 21}], - [{in: 1}, {out: 1}], - [{in: 2}, {out: 23}], - [{in:-1}, {out: 20}], - ] - ); - }); - - it("Compute block", async () => { - await doTest( - "compute.circom", - [ - [{x: 1}, {y: 7}], - [{x: 2}, {y: 7}], - [{x: 3}, {y: 11}], - [{x:-1}, {y: -5}], - ] - ); - }); - it("Component array ", async () => { - await doTest( - "componentarray.circom", - [ - [{in: 1}, {out: 1}], - [{in: 2}, {out: 256}], - [{in: 3}, {out: 6561}], - [{in:-1}, {out: 1}], - ] - ); - }); - it("Component array 2d", async () => { - await doTest( - "componentarray2.circom", - [ - [{in: [1,2]}, {out: [1, 256]}], - [{in: [0,3]}, {out: [0, 6561]}], - ] - ); - }); - it("Constant circuit", async () => { - await doTest( - "constantcircuit.circom", - [ - // 0xbb67ae85 - [{}, {out: [1,0,1,0, 0,0,0,1, 0,1,1,1, 0,1,0,1, 1,1,1,0, 0,1,1,0, 1,1,0,1, 1,1,0,1]}], - ] - ); - }); - it("Constant internal circuit", async () => { - await doTest( - "constantinternalcircuit.circom", - [ - [{in: 1}, {out: 5}], - [{in: 0}, {out: 4}], - [{in: -2}, {out: 2}], - [{in: 10}, {out: 14}] - ] - ); - }); - it("include", async () => { - await doTest( - "include.circom", - [ - [{in: 3}, {out: 6}], - [{in: 6}, {out: 15}], - ] - ); - }); - -}); diff --git a/test/cases.js b/test/cases.js deleted file mode 100644 index 7b98d83..0000000 --- a/test/cases.js +++ /dev/null @@ -1,67 +0,0 @@ -const chai = require("chai"); -const path = require("path"); -const snarkjs = require("snarkjs"); - -const bigInt = snarkjs.bigInt; - -const compiler = require("../index.js"); - -const assert = chai.assert; - -async function assertThrowsAsync(fn, regExp) { - let f = () => {}; - try { - await fn(); - } catch(e) { - f = () => { throw e; }; - } finally { - assert.throws(f, regExp); - } -} - -describe("Sum test", () => { - it("Should compile a code with an undefined if", async () => { - await compiler(path.join(__dirname, "circuits", "undefinedif.circom")); - }); - it("Should compile a code with vars inside a for", async () => { - const cirDef = await compiler(path.join(__dirname, "circuits", "forvariables.circom")); - - const circuit = new snarkjs.Circuit(cirDef); - - const witness = circuit.calculateWitness({ "in": 111}); - assert(witness[0].equals(bigInt(1))); - assert(witness[1].equals(bigInt(114))); - assert(witness[2].equals(bigInt(111))); - - }); - it("Should compile a code with an undefined if", async () => { - const cirDef = await compiler(path.join(__dirname, "circuits", "mixvarsignal.circom")); - - const circuit = new snarkjs.Circuit(cirDef); - - const witness = circuit.calculateWitness({ "i": 111}); - assert(witness[0].equals(bigInt(1))); - assert(witness[1].equals(bigInt(111*111))); - assert(witness[2].equals(bigInt(111))); - }); -// it("Should assign signal ERROR", async () => { -// await assertThrowsAsync(async () => { -// await compiler(path.join(__dirname, "circuits", "assignsignal.circom")); -// }, /Cannot assign to a signal .*/); -// }); - it("Should compile a code with compute", async () => { - const cirDef = await compiler(path.join(__dirname, "circuits", "compute.circom")); - - const circuit = new snarkjs.Circuit(cirDef); - - const witness = circuit.calculateWitness({ "x": 6}); - assert(witness[0].equals(bigInt(1))); - assert(witness[1].equals(bigInt(37))); - assert(witness[2].equals(bigInt(6))); - }); - it("Should compile a code with compute", async () => { - const cirDef = await compiler(path.join(__dirname, "circuits", "inout.circom")); - - assert.equal(cirDef.constraints.length, 1); - }); -}); diff --git a/test/fieldasm.js b/test/fieldasm.js deleted file mode 100644 index 205fc8c..0000000 --- a/test/fieldasm.js +++ /dev/null @@ -1,453 +0,0 @@ -const tester = require("../ports/c/buildasm/buildzqfieldtester.js"); - -const ZqField = require("fflib").ZqField; - -const bigInt = require("big-integer"); - -const bn128q = new bigInt("21888242871839275222246405745257275088696311157297823662689037894645226208583"); -const bn128r = new bigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617"); -const secp256k1q = new bigInt("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16); -const secp256k1r = new bigInt("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16); -const mnt6753q = new bigInt("41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888458477323173057491593855069696241854796396165721416325350064441470418137846398469611935719059908164220784476160001"); -const mnt6753r = new bigInt("41898490967918953402344214791240637128170709919953949071783502921025352812571106773058893763790338921418070971888253786114353726529584385201591605722013126468931404347949840543007986327743462853720628051692141265303114721689601"); - -describe("field asm test", function () { - this.timeout(1000000000); - it("bn128r add", async () => { - const tv = buildTestVector2(bn128r, "add"); - await tester(bn128r, tv); - }); -/* - it("secp256k1q add", async () => { - const tv = buildTestVector2(secp256k1q, "add"); - await tester(secp256k1q, tv); - }); - it("mnt6753q add", async () => { - const tv = buildTestVector2(mnt6753q, "add"); - await tester(mnt6753q, tv); - }); - it("bn128r sub", async () => { - const tv = buildTestVector2(bn128r, "sub"); - await tester(bn128r, tv); - }); - it("secp256k1q sub", async () => { - const tv = buildTestVector2(secp256k1q, "sub"); - await tester(secp256k1q, tv); - }); - it("mnt6753q sub", async () => { - const tv = buildTestVector2(mnt6753q, "sub"); - await tester(mnt6753q, tv); - }); - it("bn128r neg", async () => { - const tv = buildTestVector1(bn128r, "neg"); - await tester(bn128r, tv); - }); - it("secp256k1q neg", async () => { - const tv = buildTestVector1(secp256k1q, "neg"); - await tester(secp256k1q, tv); - }); - it("mnt6753q neg", async () => { - const tv = buildTestVector1(mnt6753q, "neg"); - await tester(mnt6753q, tv); - }); - it("bn128r mul", async () => { - const tv = buildTestVector2(bn128r, "mul"); - await tester(bn128r, tv); - }); - it("secp256k1q mul", async () => { - const tv = buildTestVector2(secp256k1q, "mul"); - await tester(secp256k1q, tv); - }); - it("mnt6753q mul", async () => { - const tv = buildTestVector2(mnt6753q, "mul"); - await tester(mnt6753q, tv); - }); - it("bn128r binary and", async () => { - const tv = buildTestVector2(bn128r, "band"); - await tester(bn128r, tv); - }); - it("secp256k1q binary and", async () => { - const tv = buildTestVector2(secp256k1q, "band"); - await tester(secp256k1q, tv); - }); - it("mnt6753q binary and", async () => { - const tv = buildTestVector2(mnt6753q, "band"); - await tester(mnt6753q, tv); - }); - it("bn128r binary or", async () => { - const tv = buildTestVector2(bn128r, "bor"); - await tester(bn128r, tv); - }); - it("secp256k1q binary or", async () => { - const tv = buildTestVector2(secp256k1q, "bor"); - await tester(secp256k1q, tv); - }); - it("mnt6753q binary or", async () => { - const tv = buildTestVector2(mnt6753q, "bor"); - await tester(mnt6753q, tv); - }); - it("bn128r binary xor", async () => { - const tv = buildTestVector2(bn128r, "bxor"); - await tester(bn128r, tv); - }); - it("secp256k1q binary xor", async () => { - const tv = buildTestVector2(secp256k1q, "bxor"); - await tester(secp256k1q, tv); - }); - it("mnt6753q binary xor", async () => { - const tv = buildTestVector2(mnt6753q, "bxor"); - await tester(mnt6753q, tv); - }); - it("bn128r binary not", async () => { - const tv = buildTestVector1(bn128r, "bnot"); - await tester(bn128r, tv); - }); - it("secp256k1q binary not", async () => { - const tv = buildTestVector1(secp256k1q, "bnot"); - await tester(secp256k1q, tv); - }); - it("mnt6753q binary not", async () => { - const tv = buildTestVector1(mnt6753q, "bnot"); - await tester(mnt6753q, tv); - }); - it("bn128r eq", async () => { - const tv = buildTestVector2(bn128r, "eq"); - await tester(bn128r, tv); - }); - it("secp256k1q eq", async () => { - const tv = buildTestVector2(secp256k1q, "eq"); - await tester(secp256k1q, tv); - }); - it("mnt6753q eq", async () => { - const tv = buildTestVector2(mnt6753q, "eq"); - await tester(mnt6753q, tv); - }); - it("bn128r neq", async () => { - const tv = buildTestVector2(bn128r, "neq"); - await tester(bn128r, tv); - }); - it("secp256k1q neq", async () => { - const tv = buildTestVector2(secp256k1q, "neq"); - await tester(secp256k1q, tv); - }); - it("mnt6753q neq", async () => { - const tv = buildTestVector2(mnt6753q, "neq"); - await tester(mnt6753q, tv); - }); - it("bn128r lt", async () => { - const tv = buildTestVector2(bn128r, "lt"); - await tester(bn128r, tv); - }); - it("secp256k1q lt", async () => { - const tv = buildTestVector2(secp256k1q, "lt"); - await tester(secp256k1q, tv); - }); - it("mnt6753q lt", async () => { - const tv = buildTestVector2(mnt6753q, "lt"); - await tester(mnt6753q, tv); - }); - it("bn128r gt", async () => { - const tv = buildTestVector2(bn128r, "gt"); - await tester(bn128r, tv); - }); - it("secp256k1q gt", async () => { - const tv = buildTestVector2(secp256k1q, "gt"); - await tester(secp256k1q, tv); - }); - it("mnt6753q gt", async () => { - const tv = buildTestVector2(mnt6753q, "gt"); - await tester(mnt6753q, tv); - }); - it("bn128r leq", async () => { - const tv = buildTestVector2(bn128r, "leq"); - await tester(bn128r, tv); - }); - it("secp256k1q leq", async () => { - const tv = buildTestVector2(secp256k1q, "leq"); - await tester(secp256k1q, tv); - }); - it("mnt6753q leq", async () => { - const tv = buildTestVector2(mnt6753q, "leq"); - await tester(mnt6753q, tv); - }); - it("bn128r geq", async () => { - const tv = buildTestVector2(bn128r, "geq"); - await tester(bn128r, tv); - }); - it("secp256k1q geq", async () => { - const tv = buildTestVector2(secp256k1q, "geq"); - await tester(secp256k1q, tv); - }); - it("mnt6753q geq", async () => { - const tv = buildTestVector2(mnt6753q, "geq"); - await tester(mnt6753q, tv); - }); - it("bn128r logical and", async () => { - const tv = buildTestVector2(bn128r, "land"); - await tester(bn128r, tv); - }); - it("secp256k1q logical and", async () => { - const tv = buildTestVector2(secp256k1q, "land"); - await tester(secp256k1q, tv); - }); - it("mnt6753q logical and", async () => { - const tv = buildTestVector2(mnt6753q, "land"); - await tester(mnt6753q, tv); - }); - it("bn128r logical or", async () => { - const tv = buildTestVector2(bn128r, "lor"); - await tester(bn128r, tv); - }); - it("secp256k1q logical or", async () => { - const tv = buildTestVector2(secp256k1q, "lor"); - await tester(secp256k1q, tv); - }); - it("mnt6753q logical or", async () => { - const tv = buildTestVector2(mnt6753q, "lor"); - await tester(mnt6753q, tv); - }); - it("bn128r logical not", async () => { - const tv = buildTestVector1(bn128r, "lnot"); - await tester(bn128r, tv); - }); - it("secp256k1q logical not", async () => { - const tv = buildTestVector1(secp256k1q, "lnot"); - await tester(secp256k1q, tv); - }); - it("mnt6753q logical not", async () => { - const tv = buildTestVector1(mnt6753q, "lnot"); - await tester(mnt6753q, tv); - }); - it("bn128r idiv", async () => { - const tv = buildTestVector2(bn128r, "idiv"); - await tester(bn128r, tv); - }); - it("secp256k1q idiv", async () => { - const tv = buildTestVector2(secp256k1q, "idiv"); - await tester(secp256k1q, tv); - }); - it("mnt6753q idiv", async () => { - const tv = buildTestVector2(mnt6753q, "idiv"); - await tester(mnt6753q, tv); - }); - it("bn128r inv", async () => { - const tv = buildTestVector1(bn128r, "inv"); - await tester(bn128r, tv); - }); - it("secp256k1q inv", async () => { - const tv = buildTestVector1(secp256k1q, "inv"); - await tester(secp256k1q, tv); - }); - it("mnt6753q inv", async () => { - const tv = buildTestVector1(mnt6753q, "inv"); - await tester(mnt6753q, tv); - }); - it("bn128r div", async () => { - const tv = buildTestVector2(bn128r, "div"); - await tester(bn128r, tv); - }); - it("secp256k1q div", async () => { - const tv = buildTestVector2(secp256k1q, "div"); - await tester(secp256k1q, tv); - }); - it("mnt6753q div", async () => { - const tv = buildTestVector2(mnt6753q, "div"); - await tester(mnt6753q, tv); - }); - it("bn128r square", async () => { - const tv = buildTestVector1(bn128r, "square"); - await tester(bn128r, tv); - }); - it("secp256k1q square", async () => { - const tv = buildTestVector1(secp256k1q, "square"); - await tester(secp256k1q, tv); - }); - it("mnt6753q square", async () => { - const tv = buildTestVector1(mnt6753q, "square"); - await tester(mnt6753q, tv); - }); -*/ - it("bn128r shl", async () => { - const tv = buildTestVector2(bn128r, "shl"); - await tester(bn128r, tv); - }); -/* - it("secp256k1q shl", async () => { - const tv = buildTestVector2(secp256k1q, "shl"); - await tester(secp256k1q, tv); - }); - it("mnt6753q shl", async () => { - const tv = buildTestVector2(mnt6753q, "shl"); - await tester(mnt6753q, tv); - }); -*/ - it("bn128r shr", async () => { - const tv = buildTestVector2(bn128r, "shr"); - await tester(bn128r, tv); - }); -/* - it("secp256k1q shr", async () => { - const tv = buildTestVector2(secp256k1q, "shr"); - await tester(secp256k1q, tv); - }); - it("mnt6753q shr", async () => { - const tv = buildTestVector2(mnt6753q, "shr"); - await tester(mnt6753q, tv); - }); - it("mnt6753q band", async () => { - const tv = buildTestVector2(mnt6753q, "band"); - await tester(mnt6753q, tv); - }); - it("mnt6753q bor", async () => { - const tv = buildTestVector2(mnt6753q, "bor"); - await tester(mnt6753q, tv); - }); - it("mnt6753q bxor", async () => { - const tv = buildTestVector2(mnt6753q, "bxor"); - await tester(mnt6753q, tv); - }); - it("mnt6753q bnot", async () => { - const tv = buildTestVector1(mnt6753q, "bnot"); - await tester(mnt6753q, tv); - }); -*/ -}); - -function buildTestVector2(p, op) { - const F = new ZqField(p); - const tv = []; - const nums = getCriticalNumbers(p, 2); - - const excludeZero = ["div", "mod", "idiv"].indexOf(op) >= 0; - - for (let i=0; i= 0; - - for (let i=0; i