Browse Source

Almost ready for 0.5.0

c_build
Jordi Baylina 4 years ago
parent
commit
eb8cb0af74
No known key found for this signature in database GPG Key ID: 7480C80C1BE43112
62 changed files with 1251 additions and 15155 deletions
  1. +1
    -5
      .eslintrc.js
  2. +1
    -1
      COPYING
  3. +25
    -18
      TUTORIAL.md
  4. +4
    -4
      cli.js
  5. +303
    -332
      doc/r1cs_bin_format.md
  6. BIN
      doc/r1cs_bin_format.monopic
  7. BIN
      doc/r1cs_example.monopic
  8. +528
    -581
      package-lock.json
  9. +9
    -10
      package.json
  10. +0
    -245
      ports/c/buildasm/add.asm.ejs
  11. +0
    -240
      ports/c/buildasm/binops.asm.ejs
  12. +0
    -72
      ports/c/buildasm/buildzqfield.js
  13. +0
    -75
      ports/c/buildasm/buildzqfieldtester.js
  14. +0
    -439
      ports/c/buildasm/cmpops.asm.ejs
  15. +0
    -108
      ports/c/buildasm/cmpops_old.asm.ejs
  16. +0
    -139
      ports/c/buildasm/copy.asm.ejs
  17. +0
    -7607
      ports/c/buildasm/fr.asm
  18. +0
    -53
      ports/c/buildasm/fr.asm.ejs
  19. +0
    -201
      ports/c/buildasm/fr.c
  20. +0
    -201
      ports/c/buildasm/fr.c.ejs
  21. +0
    -67
      ports/c/buildasm/fr.h
  22. +0
    -67
      ports/c/buildasm/fr.h.ejs
  23. BIN
      ports/c/buildasm/fr.o
  24. +0
    -97
      ports/c/buildasm/logicalops.asm.ejs
  25. +0
    -64
      ports/c/buildasm/main.c
  26. +0
    -350
      ports/c/buildasm/montgomery.asm.ejs
  27. +0
    -275
      ports/c/buildasm/mul.asm.ejs
  28. +0
    -78
      ports/c/buildasm/neg.asm.ejs
  29. +0
    -33
      ports/c/buildasm/old/buildfieldasm.js
  30. +0
    -209
      ports/c/buildasm/old/buildzqfield.js
  31. +0
    -68
      ports/c/buildasm/old/buildzqfieldtester.js
  32. +0
    -302
      ports/c/buildasm/old/fr.asm.ejs.old
  33. +0
    -251
      ports/c/buildasm/old/mul.asm.ejs
  34. +0
    -317
      ports/c/buildasm/sub.asm.ejs
  35. BIN
      ports/c/buildasm/tester
  36. +0
    -220
      ports/c/buildasm/tester.cpp
  37. +0
    -72
      ports/c/buildasm/utils.asm.ejs
  38. +0
    -234
      ports/c/calcwit.cpp
  39. +0
    -73
      ports/c/calcwit.h
  40. +0
    -58
      ports/c/circom.h
  41. +0
    -1
      ports/c/fr.c
  42. +0
    -1
      ports/c/fr.h
  43. +0
    -1
      ports/c/fr.o
  44. +0
    -202
      ports/c/main.cpp
  45. +0
    -47
      ports/c/mainjson.cpp
  46. +42
    -25
      ports/c/tester.js
  47. +0
    -25
      ports/c/utils.cpp
  48. +0
    -10
      ports/c/utils.h
  49. +0
    -199
      ports/c/zqfield.cpp
  50. +0
    -49
      ports/c/zqfield.h
  51. +254
    -143
      ports/wasm/build_runtime.js
  52. +18
    -6
      ports/wasm/builder.js
  53. +18
    -21
      ports/wasm/tester.js
  54. +0
    -209
      ports/wasm/witness_calculator.js
  55. +9
    -7
      src/buildsyms.js
  56. +6
    -6
      src/compiler.js
  57. +3
    -1
      src/construction_phase.js
  58. +29
    -171
      src/r1csfile.js
  59. +1
    -2
      test/basiccases.js
  60. +0
    -343
      test/basiccases.js.old
  61. +0
    -67
      test/cases.js
  62. +0
    -453
      test/fieldasm.js

+ 1
- 5
.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"
]
}
};

+ 1
- 1
COPYING

@ -1,7 +1,7 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Copyright (C) 2020 0Kims Association <https://0kims.org>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

+ 25
- 18
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 <circuit JSON file name>`
> By default `snarkjs` will look for and use `circuit.r1cs`. You can always specify a different circuit file by adding `-r <circuit R1CS file name>`
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.

+ 4
- 4
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);
}

+ 303
- 332
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
````

BIN
doc/r1cs_bin_format.monopic


BIN
doc/r1cs_example.monopic


+ 528
- 581
package-lock.json
File diff suppressed because it is too large
View File


+ 9
- 10
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"
}
}

+ 0
- 245
ports/c/buildasm/add.asm.ejs

@ -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<n64; 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<n64; 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<n64; 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<n64; 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<n64; 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<n64; i++) { %>
mov rax, [q + <%=i*8%>]
<%= i==0 ? "sub" : "sbb" %> [rdi + <%=i*8%>], rax
<% } %>
rawAddLS_done:
ret

+ 0
- 240
ports/c/buildasm/binops.asm.ejs

@ -1,240 +0,0 @@
<% function binOpSubQIfBigger() { %>
<% const subQ = global.tmpLabel() %>
<% const done = global.tmpLabel() %>
; Compare with q
<% for (let i=0; i<n64; 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<n64; 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<n64; 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<n64; 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<n64; 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<n64; i++) { %>
mov rax, [rsi + <%= i*8 + 8 %>]
not rax
<% if (i== n64-1) { %>
and rax, [lboMask]
<% } %>
mov [rdi + <%= i*8 + 8 %>], rax
<% } %>
<% binOpSubQIfBigger() %>
ret

+ 0
- 72
ports/c/buildasm/buildzqfield.js

@ -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; i<this.n64; i++) {
if (i>0) 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;
}

+ 0
- 75
ports/c/buildasm/buildzqfieldtester.js

@ -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<test.length; i++) {
for (let j=0; j<test[i][0].length; j++) {
inLines.push(test[i][0][j]);
}
}
inLines.push("");
await fs.promises.writeFile(path.join(dir.path, "in.tst"), inLines.join("\n"), "utf8");
await exec(`${path.join(dir.path, "tester")}` +
` <${path.join(dir.path, "in.tst")}` +
` >${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<test.length; i++) {
const expected = test[i][1].toString();
const calculated = resLines[i];
if (calculated != expected) {
console.log("FAILED");
for (let j=0; j<test[i][0].length; j++) {
console.log(test[i][0][j]);
}
console.log("Should Return: " + expected);
console.log("But Returns: " + calculated);
}
assert.equal(calculated, expected);
}
}

+ 0
- 439
ports/c/buildasm/cmpops.asm.ejs

@ -1,439 +0,0 @@
<% function signL(reg, label_pos, label_neg) { %>
<% 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<rax => 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<rdx => 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<rdx => 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<n64; i++) { %>
mov rax, [rsi + <%= 8+(i*8) %>]
cmp [rdx + <%= 8+(i*8) %>], rax
jne req_ret0 ; rsi<rdi => 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

+ 0
- 108
ports/c/buildasm/cmpops_old.asm.ejs

@ -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<rax => 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") %>

+ 0
- 139
ports/c/buildasm/copy.asm.ejs

@ -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<n64; 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<n64; 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<n64; 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

+ 0
- 7607
ports/c/buildasm/fr.asm
File diff suppressed because it is too large
View File


+ 0
- 53
ports/c/buildasm/fr.asm.ejs

@ -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) %>

+ 0
- 201
ports/c/buildasm/fr.c

@ -1,201 +0,0 @@
#include "fr.h"
#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>
#include <assert.h>
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; i<Fr_N64; i++) pE->longVal[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);
}

+ 0
- 201
ports/c/buildasm/fr.c.ejs

@ -1,201 +0,0 @@
#include "<%=name.toLowerCase()+".h"%>"
#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>
#include <assert.h>
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);
}

+ 0
- 67
ports/c/buildasm/fr.h

@ -1,67 +0,0 @@
#ifndef __FR_H
#define __FR_H
#include <stdint.h>
#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

+ 0
- 67
ports/c/buildasm/fr.h.ejs

@ -1,67 +0,0 @@
#ifndef __<%=name.toUpperCase()%>_H
#define __<%=name.toUpperCase()%>_H
#include <stdint.h>
#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

BIN
ports/c/buildasm/fr.o


+ 0
- 97
ports/c/buildasm/logicalops.asm.ejs

@ -1,97 +0,0 @@
<% function isTrue(resReg, srcPtrReg) { %>
<% 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<n64; 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

+ 0
- 64
ports/c/buildasm/main.c

@ -1,64 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#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<Fr_N64; j++) {
a2[i].longVal[j] = i;
}
}
Fr_copyn(a2, a1, 10);
for (int i=0; i<10; i++) {
char *c1 = Fr_element2str(&a1[i]);
char *c2 = Fr_element2str(&a2[i]);
printf("%s\n%s\n\n", c1, c2);
free(c1);
free(c2);
}
*/
int tests[7] = { 0, 1, 2, -1, -2, 0x7FFFFFFF, (int)0x80000000};
for (int i=0; i<7;i++) {
FrElement a = { tests[i], Fr_SHORT, {0,0,0,0}};
Fr_toLongNormal(&a);
int b = Fr_toInt(&a);
int c = Fr_isTrue(&a);
printf("%d, %d, %d\n", tests[i], b, c);
}
FrElement err = { 0, Fr_LONGMONTGOMERY, {1,1,1,1}};
Fr_toInt(&err);
// printf("%llu, %llu, %llu, %llu\n", c.longVal[0], c.longVal[1], c.longVal[2], c.longVal[3]);
}

+ 0
- 350
ports/c/buildasm/montgomery.asm.ejs

@ -1,350 +0,0 @@
<%
//////////////////////
// montgomeryTemplate
//////////////////////
// This function creates functions with the montgomery transformation
// applied
// the round hook allows to add diferent code in the iteration
//
// All the montgomery functions modifies:
// r8, r9, 10, r11, rax, rcx
//////////////////////
function montgomeryTemplate(fnName, round) {
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));
%>
<%=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<n64*2; i++) {
setR(i);
round(i, r0, r1, r2);
%>
<%
for (let j=i-1; j>=0; j--) { // All ms
if (((i-j)<n64)&&(j<n64)) {
%>
mov rax, [rsp + <%= j*8 %>]
mul qword [q + <%= (i-j)*8 %>]
add <%= r0 %>, rax
adc <%= r1 %>, rdx
adc <%= r2 %>, 0x0
<%
}
} // ms
%>
<%
if (i<n64) {
%>
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<n64; 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<n64; 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<n64); o1++) {
const o2= 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<n64); o1++) {
const o2= i-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<n64) {
%>
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<n64) {
%>
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

+ 0
- 275
ports/c/buildasm/mul.asm.ejs

@ -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

+ 0
- 78
ports/c/buildasm/neg.asm.ejs

@ -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<n64; i++) { %>
cmp [rsi + <%=i*8%>], rax
jnz doNegate
<% } %>
; it's zero so just set to zero
<% for (let i=0; i<n64; i++) { %>
mov [rdi + <%=i*8%>], rax
<% } %>
ret
doNegate:
<% for (let i=0; i<n64; i++) { %>
mov rax, [q + <%=i*8%>]
<%= i==0 ? "sub" : "sbb" %> rax, [rsi + <%=i*8%>]
mov [rdi + <%=i*8%>], rax
<% } %>
ret

+ 0
- 33
ports/c/buildasm/old/buildfieldasm.js

@ -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"],
]);
});
});

+ 0
- 209
ports/c/buildasm/old/buildzqfield.js

@ -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; i<this.n64; i++) {
if (i>0) 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; i<this.n64; i++) {
this.c.push(` "movq ${i*8}(%2), %%rax;"`);
this.c.push(` "${i==0 ? "addq" : "adcq"} ${i*8}(%1), %%rax;"`);
this.c.push(` "movq %%rax, ${i*8}(%0);"`);
}
this.c.push(" \"jc SQ;\"");
for (let i=0; i<this.n64; i++) {
if (i>0) {
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<this.n64; i++) {
this.c.push(` "movq ${i*8}(%3), %%rax;"`);
this.c.push(` "${i==0 ? "subq" : "sbbq"} %%rax, ${i*8}(%0);"`);
}
this.c.push(" \"DONE:\"");
this.c.push(` :: "r" (r), "r" (a), "r" (b), "r" (${this.name}_q) : "%rax", "memory");`);
this.c.push("}\n");
}
_buildMul() {
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(this.q.modInv(base));
this.h.push(`void ${this.name}_mul(P${this.name}Element r, P${this.name}Element a, P${this.name}Element b);`);
this.c.push(`void ${this.name}_mul(P${this.name}Element r, P${this.name}Element a, P${this.name}Element b) {`);
this.c.push(" __asm__ __volatile__ (");
this.c.push(` "subq $${this.n64*8}, %%rsp;"`);
this.c.push(` "movq $0x${np64.toString(16)}, %%r11;"`);
this.c.push(" \"movq $0x0, %%r8;\"");
this.c.push(" \"movq $0x0, %%r9;\"");
this.c.push(" \"movq $0x0, %%r10;\"");
for (let i=0; i<this.n64*2; i++) {
setR(i);
for (let o1=Math.max(0, i-this.n64+1); (o1<=i)&&(o1<this.n64); o1++) {
const o2= i-o1;
this.c.push(` "movq ${o1*8}(%1), %%rax;"`);
this.c.push(` "mulq ${o2*8}(%2);"`);
this.c.push(` "addq %%rax, ${r0};"`);
this.c.push(` "adcq %%rdx, ${r1};"`);
this.c.push(` "adcq $0x0, ${r2};"`);
}
for (let j=i-1; j>=0; j--) {
if (((i-j)<this.n64)&&(j<this.n64)) {
this.c.push(` "movq ${j*8}(%%rsp), %%rax;"`);
this.c.push(` "mulq ${(i-j)*8}(%3);"`);
this.c.push(` "addq %%rax, ${r0};"`);
this.c.push(` "adcq %%rdx, ${r1};"`);
this.c.push(` "adcq $0x0, ${r2};"`);
}
}
if (i<this.n64) {
this.c.push(` "movq ${r0}, %%rax;"`);
this.c.push(" \"mulq %%r11;\"");
this.c.push(` "movq %%rax, ${i*8}(%%rsp);"`);
this.c.push(" \"mulq (%3);\"");
this.c.push(` "addq %%rax, ${r0};"`);
this.c.push(` "adcq %%rdx, ${r1};"`);
this.c.push(` "adcq $0x0, ${r2};"`);
} else {
this.c.push(` "movq ${r0}, ${(i-this.n64)*8}(%0);"`);
this.c.push(` "movq $0, ${r0};"`);
}
}
this.c.push(` "cmp $0, ${r1};"`);
this.c.push(" \"jne SQ2;\"");
for (let i=0; i<this.n64; i++) {
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 SQ2;\"");
this.c.push(" \"jl DONE2;\"");
}
this.c.push(" \"SQ2:\"");
for (let i=0; i<this.n64; i++) {
this.c.push(` "movq ${i*8}(%3), %%rax;"`);
this.c.push(` "${i==0 ? "subq" : "sbbq"} %%rax, ${i*8}(%0);"`);
}
this.c.push(" \"DONE2:\"");
this.c.push(` "addq $${this.n64*8}, %%rsp;"`);
this.c.push(` :: "r" (r), "r" (a), "r" (b), "r" (${this.name}_q) : "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", "memory");`);
this.c.push("}\n");
}
_buildIDiv() {
this.h.push(`void ${this.name}_idiv(P${this.name}Element r, P${this.name}Element a, P${this.name}Element b);`);
this.c.push(`void ${this.name}_idiv(P${this.name}Element r, P${this.name}Element a, P${this.name}Element b) {`);
this.c.push(" __asm__ __volatile__ (");
this.c.push(" \"pxor %%xmm0, %%xmm0;\""); // Comparison Register
if (this.n64 == 1) {
this.c.push(` "mov %%rax, $${this.n64 - 8};"`);
} else {
this.c.push(` "mov %%rax, $${this.n64 -16};"`);
}
this.c.push(` :: "r" (r), "r" (a), "r" (b), "r" (${this.name}_q) : "%rax", "%rdx", "%r8", "%r9", "%r10", "%r11", "memory");`);
this.c.push("}\n");
}
}
var runningAsScript = !module.parent;
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 cFileName = (argv.oc) ? argv.oc : argv.name.toLowerCase() + ".c";
const hFileName = (argv.oh) ? argv.oh : argv.name.toLowerCase() + ".h";
const builder = new ZqBuilder(q, argv.name);
const res = builder.build();
fs.writeFileSync(hFileName, res[0], "utf8");
fs.writeFileSync(cFileName, res[1], "utf8");
} else {
module.exports = function(q, name) {
const builder = new ZqBuilder(q, name);
return builder.build();
};
}

+ 0
- 68
ports/c/buildasm/old/buildzqfieldtester.js

@ -1,68 +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 bigInt = require("big-integer");
const BuildZqField = require("./buildzqfield");
const ZqField = require("fflib").ZqField;
module.exports = testField;
function toMontgomeryStr(a, prime) {
const n64 = Math.floor((prime.bitLength() - 1) / 64)+1;
return a.shiftLeft(n64*64).mod(prime).toString(10);
}
function fromMontgomeryStr(a, prime) {
const n64 = Math.floor((prime.bitLength() - 1) / 64)+1;
const R = bigInt.one.shiftLeft(n64*64).mod(prime);
const RI = R.modInv(prime);
return bigInt(a).times(RI).mod(prime);
}
async function testField(prime, test) {
tmp.setGracefulCleanup();
const F = new ZqField(prime);
const dir = await tmp.dir({prefix: "circom_", unsafeCleanup: true });
const [hSource, cSource] = BuildZqField(prime, "Fr");
await fs.promises.writeFile(path.join(dir.path, "fr.h"), hSource, "utf8");
await fs.promises.writeFile(path.join(dir.path, "fr.c"), cSource, "utf8");
await exec("g++" +
` ${path.join(__dirname, "tester.c")}` +
` ${path.join(dir.path, "fr.c")}` +
` -o ${path.join(dir.path, "tester")}` +
" -lgmp"
);
for (let i=0; i<test.length; i++) {
let a = bigInt(test[i][1]).mod(prime);
if (a.isNegative()) a = prime.add(a);
let b = bigInt(test[i][2]).mod(prime);
if (b.isNegative()) b = prime.add(b);
const ec = F[test[i][0]](a,b);
// console.log(toMontgomeryStr(a, prime));
// console.log(toMontgomeryStr(b, prime));
const res = await exec(`${path.join(dir.path, "tester")}` +
` ${test[i][0]}` +
` ${toMontgomeryStr(a, prime)}` +
` ${toMontgomeryStr(b, prime)}`
);
// console.log(res.stdout);
const c=fromMontgomeryStr(res.stdout, prime);
assert.equal(ec.toString(), c.toString());
}
}

+ 0
- 302
ports/c/buildasm/old/fr.asm.ejs.old

@ -1,302 +0,0 @@
global <%=name%>_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<n64; 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<n64; 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<n64; 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<n64*2; i++) {
setR(i);
%>
<%
// Same Digit
for (let o1=Math.max(0, i-n64+1); (o1<=i)&&(o1<n64); o1++) {
const o2= 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)<n64)&&(j<n64)) {
%>
mov rax, [rsp + <%= j*8 %>]
mul qword [q + <%= (i-j)*8 %>]
add <%= r0 %>, rax
adc <%= r1 %>, rdx
adc <%= r2 %>, 0x0
<%
}
} // ms
%>
<%
if (i<n64) {
%>
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<n64; 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<n64; 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<n64; 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<n64; 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)) %>

+ 0
- 251
ports/c/buildasm/old/mul.asm.ejs

@ -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<n64*2; i++) {
setR(i);
%>
<%
// Same Digit
for (let o1=Math.max(0, i-n64+1); (o1<=i)&&(o1<n64); o1++) {
const o2= 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)<n64)&&(j<n64)) {
%>
mov rax, [rsp + <%= j*8 %>]
mul qword [q + <%= (i-j)*8 %>]
add <%= r0 %>, rax
adc <%= r1 %>, rdx
adc <%= r2 %>, 0x0
<%
}
} // ms
%>
<%
if (i<n64) {
%>
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<n64; 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<n64; 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<n64; 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<n64; 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

+ 0
- 317
ports/c/buildasm/sub.asm.ejs

@ -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<n64; 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<n64; 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<n64; 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<n64; 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<n64; 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<n64; 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<n64; i++) { %>
mov rax, [q + <%=i*8%> ]
sbb rax, 0
mov [rdi + <%=i*8%>], rax
<% } %>
setc dl
<% for (let i=0; i<n64; 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<n64; i++) { %>
mov rax, [q + <%=i*8%>]
<%= i==0 ? "add" : "adc" %> [rdi + <%=i*8%>], rax
<% } %>
rawNegSL_done:
ret

BIN
ports/c/buildasm/tester


+ 0
- 220
ports/c/buildasm/tester.cpp

@ -1,220 +0,0 @@
#include <string>
#include <iostream>
#include <regex>
#include <string>
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <stdio.h> /* printf, NULL */
#include <stdlib.h>
#include <cassert>
#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<std::string, FunctionSpec> functions;
std::vector<FrElement> 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<std::string> &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<Fr_N64; i++) {
if (i+1 < v.size()) {
a = readInt(v[i+1]);
} else {
a = 0;
}
e.longVal[i] = a;
}
stack.push_back(e);
}
void callFunction(FunctionSpec fs) {
if (stack.size() < fs.nOps) {
throw new std::runtime_error("Not enough elements in stack");
}
if (fs.nOps == 1) {
FrElement a = stack.back();
stack.pop_back();
FrElement c;
(*(Func1)fs.fn)(&c, &a);
stack.push_back(c);
} else if (fs.nOps == 2) {
FrElement b = stack.back();
stack.pop_back();
FrElement a = stack.back();
stack.pop_back();
FrElement c;
(*(Func2)fs.fn)(&c, &a, &b);
stack.push_back(c);
} else {
assert(false);
}
}
void processLine(std::string &line) {
std::regex re("(\\s*[,;]\\s*)|\\s+"); // whitespace
std::sregex_token_iterator begin( line.begin(), line.end(), re ,-1);
std::sregex_token_iterator end;
std::vector<std::string> 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<stack.size(); i++) {
char *s;
s = Fr_element2str(&stack[i]);
printf("%s\n", s);
free(s);
}
return EXIT_SUCCESS;
}
/*
#include <stdlib.h>
#include <string.h>
#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;
}
*/

+ 0
- 72
ports/c/buildasm/utils.asm.ejs

@ -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`);
} %>

+ 0
- 234
ports/c/calcwit.cpp

@ -1,234 +0,0 @@
#include <string>
#include <stdexcept>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <stdlib.h>
#include <assert.h>
#include <stdarg.h>
#include <thread>
#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; i<circuit->NComponents; i++) signalAssigned[i] = false;
#endif
for (int i=0; i<circuit->NComponents; i++) {
inputSignalsToTrigger[i] = circuit->components[i].inputSignals;
}
for (int i=0; i<circuit->NComponents; 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<std::mutex> 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<std::mutex> 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; i<circuit->NComponents; i++) {
std::unique_lock<std::mutex> 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);
}
}

+ 0
- 73
ports/c/calcwit.h

@ -1,73 +0,0 @@
#ifndef CIRCOM_CALCWIT_H
#define CIRCOM_CALCWIT_H
#include "circom.h"
#include "fr.h"
#include <mutex>
#include <condition_variable>
#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

+ 0
- 58
ports/c/circom.h

@ -1,58 +0,0 @@
#ifndef __CIRCOM_H
#define __CIRCOM_H
#include <gmp.h>
#include <stdint.h>
#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

+ 0
- 1
ports/c/fr.c

@ -1 +0,0 @@
buildasm/fr.c

+ 0
- 1
ports/c/fr.h

@ -1 +0,0 @@
buildasm/fr.h

+ 0
- 1
ports/c/fr.o

@ -1 +0,0 @@
buildasm/fr.o

+ 0
- 202
ports/c/main.cpp

@ -1,202 +0,0 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <iomanip>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <nlohmann/json.hpp>
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; j<Fr_N64; j++) {
v.longVal[j] = *(u64 *)p;
}
p += 8;
ctx->setSignal(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<n; i++) {
iterateArr(ctx, o + i*sizes[1], sizes+1, jarr[i], f);
}
}
}
void itFunc(Circom_CalcWit *ctx, int o, json val) {
FrElement v;
std::string s;
if (val.is_string()) {
s = val.get<std::string>();
} else if (val.is_number()) {
double vd = val.get<double>();
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 << " <input.<bin|json>> <output.<bin|json>>\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);
}
}

+ 0
- 47
ports/c/mainjson.cpp

@ -1,47 +0,0 @@
#include <iostream>
#include <nlohmann/json.hpp>
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<n; i++) {
iterateArr(o + i*sizes[1], sizes+1, jarr[i], f);
}
}
}
void itFunc(int o, json v) {
std::cout << o << " <-- " << v << '\n';
}
int main(int argc, char **argv) {
Circom_CalcWit *ctx = new Circom_CalcWit(&_circuit);
for (json::iterator it = j.begin(); it != j.end(); ++it) {
// std::cout << it.key() << " => " << 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);
}
}

+ 42
- 25
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<lines.length; i++) {
const arr = lines[i].split(",");
if (arr.length!=3) continue;
this.symbols[arr[2]] = {
idx: Number(arr[0]),
idxWit: Number(arr[1])
if (arr.length!=4) continue;
this.symbols[arr[3]] = {
labelIdx: Number(arr[0]),
varIdx: Number(arr[1]),
componentIdx: Number(arr[2]),
};
}
}
@ -108,7 +125,7 @@ class CTester {
if (this.constraints) return;
const r1cs = await loadR1cs(path.join(this.dir.path, this.baseName + ".r1cs"),true, false);
self.field = new ZqField(r1cs.prime);
self.nWires = r1cs.nWires;
self.nVars = r1cs.nVars;
self.constraints = r1cs.constraints;
}
@ -132,7 +149,7 @@ class CTester {
if (typeof self.symbols[prefix] == "undefined") {
assert(false, "Output variable not defined: "+ prefix);
}
const ba = bigInt(actualOut[self.symbols[prefix].idxWit]).toString();
const ba = bigInt(actualOut[self.symbols[prefix].varIdx]).toString();
const be = bigInt(eOut).toString();
assert.strictEqual(ba, be, prefix);
}
@ -145,8 +162,8 @@ class CTester {
if (!self.symbols) await self.loadSymbols();
for (let n in self.symbols) {
let v;
if (utils.isDefined(witness[self.symbols[n].idxWit])) {
v = witness[self.symbols[n].idxWit].toString();
if (utils.isDefined(witness[self.symbols[n].varIdx])) {
v = witness[self.symbols[n].varIdx].toString();
} else {
v = "undefined";
}
@ -164,9 +181,9 @@ class CTester {
function checkConstraint(constraint) {
const F = self.field;
const a = evalLC(constraint.a);
const b = evalLC(constraint.b);
const c = evalLC(constraint.c);
const a = evalLC(constraint[0]);
const b = evalLC(constraint[1]);
const c = evalLC(constraint[2]);
assert (F.sub(F.mul(a,b), c).isZero(), "Constraint doesn't match");
}

+ 0
- 25
ports/c/utils.cpp

@ -1,25 +0,0 @@
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <stdlib.h>
#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;
}

+ 0
- 10
ports/c/utils.h

@ -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

+ 0
- 199
ports/c/zqfield.cpp

@ -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<n; i++) mpz_set(a[i], b[i]);
}
void ZqField::band(PBigInt r, PBigInt a, PBigInt b) {
mpz_and(*r, *a, *b);
mpz_and(*r, *r, mask);
}
void ZqField::bor(PBigInt r, PBigInt a, PBigInt b) {
mpz_ior(*r, *a, *b);
mpz_and(*r, *r, mask);
}
void ZqField::bxor(PBigInt r, PBigInt a, PBigInt b) {
mpz_xor(*r, *a, *b);
mpz_and(*r, *r, mask);
}
void ZqField::bnot(PBigInt r, PBigInt a) {
mpz_xor(*r, *a, mask);
mpz_and(*r, *r, mask);
}
void ZqField::shl(PBigInt r, PBigInt a, PBigInt b) {
if (mpz_cmp_ui(*b, nBits) >= 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);
}

+ 0
- 49
ports/c/zqfield.h

@ -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

+ 254
- 143
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");
};

+ 18
- 6
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;

+ 18
- 21
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; i<lines.length; i++) {
const arr = lines[i].split(",");
if (arr.length!=3) continue;
this.symbols[arr[2]] = {
idx: Number(arr[0]),
idxWit: Number(arr[1])
if (arr.length!=4) continue;
this.symbols[arr[3]] = {
labelIdx: Number(arr[0]),
varIdx: Number(arr[1]),
componentIdx: Number(arr[2]),
};
}
}
@ -87,7 +84,7 @@ class WasmTester {
if (this.constraints) return;
const r1cs = await loadR1cs(path.join(this.dir.path, this.baseName + ".r1cs"),true, false);
self.field = new ZqField(r1cs.prime);
self.nWires = r1cs.nWires;
self.nVars = r1cs.nVars;
self.constraints = r1cs.constraints;
}
@ -111,7 +108,7 @@ class WasmTester {
if (typeof self.symbols[prefix] == "undefined") {
assert(false, "Output variable not defined: "+ prefix);
}
const ba = bigInt(actualOut[self.symbols[prefix].idxWit]).toString();
const ba = bigInt(actualOut[self.symbols[prefix].varIdx]).toString();
const be = bigInt(eOut).toString();
assert.strictEqual(ba, be, prefix);
}
@ -124,8 +121,8 @@ class WasmTester {
if (!self.symbols) await self.loadSymbols();
for (let n in self.symbols) {
let v;
if (utils.isDefined(witness[self.symbols[n].idxWit])) {
v = witness[self.symbols[n].idxWit].toString();
if (utils.isDefined(witness[self.symbols[n].varIdx])) {
v = witness[self.symbols[n].varIdx].toString();
} else {
v = "undefined";
}
@ -143,9 +140,9 @@ class WasmTester {
function checkConstraint(constraint) {
const F = self.field;
const a = evalLC(constraint.a);
const b = evalLC(constraint.b);
const c = evalLC(constraint.c);
const a = evalLC(constraint[0]);
const b = evalLC(constraint[1]);
const c = evalLC(constraint[2]);
assert (F.sub(F.mul(a,b), c).isZero(), "Constraint doesn't match");
}

+ 0
- 209
ports/wasm/witness_calculator.js

@ -1,209 +0,0 @@
/* globals WebAssembly */
const fs = require("fs");
const utils = require("../../src/utils");
const bigInt = require("big-integer");
module.exports.fromFile = async function(file) {
const code = await fs.promises.readFile(file);
return await module.exports.fromBuffer(code);
};
module.exports.fromBuffer = async function(code) {
const memory = new WebAssembly.Memory({initial:20000});
const wasmModule = await WebAssembly.compile(code);
let wc;
const instance = await WebAssembly.instantiate(wasmModule, {
env: {
"memory": memory
},
runtime: {
err: function(code, pstr) {
const errStr=p2str(pstr);
console.log("ERROR: ", code, errStr);
throw new Error(errStr);
},
err1: function(code, pstr, a) {
const errStr=p2str(pstr)+ " " + a;
console.log("ERROR: ", code, errStr);
throw new Error(errStr);
},
err2: function(code, pstr, a, b) {
const errStr=p2str(pstr)+ " " + a + " " + b;
console.log("ERROR: ", code, errStr);
throw new Error(errStr);
},
err3: function(code, pstr, a, b, c) {
const errStr=p2str(pstr)+ " " + a + " " + b + " " + c;
console.log("ERROR: ", code, errStr);
throw new Error(errStr);
},
err4: function(code, pstr, a,b,c,d) {
const errStr=p2str(pstr) + " " + wc.getFr(b).toString() + " != " + wc.getFr(c).toString() + " " +p2str(d);
console.log("ERROR: ", code, errStr);
throw new Error(errStr);
},
log: function(a) {
console.log(wc.getFr(a).toString());
},
}
});
wc = new WitnessCalculator(memory, instance);
return wc;
function p2str(p) {
const i8 = new Uint8Array(memory.buffer);
const bytes = [];
for (let i=0; i8[p+i]>0; 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<fArr.length; i++) {
this.setFr(pFr, fArr[i]);
this.instance.exports.setSignal(0, 0, sigOffset + i, pFr);
}
}
for (let i=0; i<this.NVars; i++) {
const pWitness = this.instance.exports.getPWitness(i);
w.push(this.getFr(pWitness));
}
this.i32[0] = old0;
return w;
}
allocInt() {
const p = this.i32[0];
this.i32[0] = p+8;
return p;
}
allocFr() {
const p = this.i32[0];
this.i32[0] = p+this.n32*4 + 8;
return p;
}
getInt(p) {
return this.i32[p>>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<self.n32; i++) {
self.i32[(p >> 2) + 2 + i] = a.shiftRight(i*32).and(self.mask32);
}
}
}
}

+ 9
- 7
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);
}
}

+ 6
- 6
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");

+ 3
- 1
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;

+ 29
- 171
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<nSections; i++) {
let ht = await readU32();
let hl = await readU32();
if (ht == 1) {
if (typeof pHeader != "undefined") assert(false, "File has two headder sections");
pHeader = p;
headerSize = hl;
} else if (ht==2) {
if (typeof pConstraints != "undefined") assert(false, "File has two constraints sections");
pConstraints = p;
constraintsSize = hl;
} else if (ht==3) {
pMap = p;
mapSize = hl;
}
p += hl;
}
if (typeof pHeader == "undefined") assert(false, "File has two header");
// Read Header
p = pHeader;
const fieldDefSize = await readU32();
const pFieldDef = p;
const defType = await readU32();
if (defType != 1) if (typeof pConstraints != "undefined") assert(false, "Field type not supported");
res.prime = await readBigInt();
if ( p != pFieldDef + fieldDefSize) assert("Invalid fieldDef size");
const bigIntFormat = await readU32();
if (bigIntFormat != 0) assert(false, "BigInt format not supported");
const idSize = await readU32();
if (idSize != 4) assert(false, "idSize not supported. Mus be 4");
res.nWires = await readU32();
res.nPubOuts = await readU32();
res.nPubIns = await readU32();
res.nPrvIns = await readU32();
res.nLabels = await readU32();
res.nConstraints = await readU32();
if (p != pHeader + headerSize) assert(false, "Invalid header section size");
if (loadConstraints) {
// Read Constraints
p = pConstraints;
res.constraints = [];
for (let i=0; i<res.nConstraints; i++) {
const c = await readConstraint();
res.constraints.push(c);
}
if (p != pConstraints + constraintsSize) assert(false, "Invalid constraints size");
}
// Read Labels
if (loadMap) {
p = pMap;
res.map = [];
for (let i=0; i<res.nLabels; i++) {
const idx = await readU32();
res.map.push(idx);
}
if (p != pMap + mapSize) assert(false, "Invalid Map size");
}
await fd.close();
return res;
async function readU32() {
const b = Buffer.allocUnsafe(4);
await fd.read(b, 0, 4, p);
p+=4;
return b.readInt32LE(0);
}
async function readBigInt() {
const bl = Buffer.allocUnsafe(1);
await fd.read(bl, 0, 1, p);
p++;
const l = bl[0];
const b = Buffer.allocUnsafe(l);
await fd.read(b, 0, l, p);
p += l;
const arr = Uint8Array.from(b);
const arrr = new Array(arr.length);
for (let i=0; i<arr.length; i++) {
arrr[i] = arr[arr.length-1-i];
}
const n = bigInt.fromArray(arrr, 256);
return n;
}
async function readConstraint() {
const c = {};
c.a = await readLC();
c.b = await readLC();
c.c = await readLC();
return c;
}
async function readLC() {
const lc= {};
const nIdx = await readU32();
for (let i=0; i<nIdx; i++) {
const idx = await readU32();
const val = await readBigInt();
lc[idx] = val;
}
return lc;
}
}
async function buildR1cs(ctx, fileName) {
@ -171,18 +20,13 @@ async function buildR1cs(ctx, fileName) {
///////////
await writeU32(1); // Header type
const pHeaderSize = p;
await writeU32(0); // Temporally set to 0 length
await writeU64(0); // Temporally set to 0 length
const n8 = (Math.floor( (ctx.field.p.bitLength() - 1) / 64) +1)*8;
// Field Def
const pFieldDefSize = p;
await writeU32(0); // Temporally set to 0 length
await writeU32(1);
await writeU32(n8); // Temporally set to 0 length
await writeBigInt(ctx.field.p);
const fieldDefSize = p - pFieldDefSize - 4;
await writeU32(0); // Variable bigInt format
await writeU32(4); // Id Size
const NWires =
ctx.totals[ctx.stONE] +
@ -195,16 +39,16 @@ async function buildR1cs(ctx, fileName) {
await writeU32(ctx.totals[ctx.stOUTPUT]);
await writeU32(ctx.totals[ctx.stPUBINPUT]);
await writeU32(ctx.totals[ctx.stPRVINPUT]);
await writeU32(ctx.signals.length);
await writeU64(ctx.signals.length);
await writeU32(ctx.constraints.length);
const headerSize = p - pHeaderSize - 4;
const headerSize = p - pHeaderSize - 8;
// Write constraints
///////////
await writeU32(2); // Constraints type
const pConstraintsSize = p;
await writeU32(0); // Temporally set to 0 length
await writeU64(0); // Temporally set to 0 length
for (let i=0; i<ctx.constraints.length; i++) {
if ((ctx.verbose)&&(i%10000 == 0)) {
@ -214,13 +58,13 @@ async function buildR1cs(ctx, fileName) {
await writeConstraint(ctx.constraints[i]);
}
const constraintsSize = p - pConstraintsSize - 4;
const constraintsSize = p - pConstraintsSize - 8;
// Write map
///////////
await writeU32(3); // wires2label type
const pMapSize = p;
await writeU32(0); // Temporally set to 0 length
await writeU64(0); // Temporally set to 0 length
const arr = new Array(NWires);
@ -234,15 +78,14 @@ async function buildR1cs(ctx, fileName) {
}
}
for (let i=0; i<arr.length; i++) {
await writeU32(arr[i]);
await writeU64(arr[i]);
if ((ctx.verbose)&&(i%100000)) console.log("writing wire2label map: ", i);
}
const mapSize = p - pMapSize -4;
const mapSize = p - pMapSize - 8;
// Write sizes
await writeU32(headerSize, pHeaderSize);
await writeU32(fieldDefSize, pFieldDefSize);
await writeU32(constraintsSize, pConstraintsSize);
await writeU32(mapSize, pMapSize);
@ -258,6 +101,15 @@ async function buildR1cs(ctx, fileName) {
if (typeof(pos) == "undefined") p += 4;
}
async function writeU64(v, pos) {
const b = Buffer.allocUnsafe(8);
b.writeBigUInt64LE(BigInt(v));
await fd.write(b, 0, 8, pos);
if (typeof(pos) == "undefined") p += 8;
}
async function writeConstraint(c) {
await writeLC(c.a);
await writeLC(c.b);
@ -277,12 +129,18 @@ async function buildR1cs(ctx, fileName) {
}
}
async function writeBigInt(n) {
async function writeBigInt(n, pos) {
const b = Buffer.allocUnsafe(n8);
const dwords = bigInt(n).toArray(0x100000000).value;
const bytes = bigInt(n).toArray(256).value.reverse();
for (let i=0; i<dwords.length; i++) {
b.writeUInt32LE(dwords[dwords.length-1-i], i*4, 4 );
}
b.fill(0, dwords.length*4);
await fd.write(Buffer.from([bytes.length, ...bytes ]));
await fd.write(b, 0, fs, pos);
p += bytes.length+1;
if (typeof(pos) == "undefined") p += n8;
}
}

+ 1
- 2
test/basiccases.js

@ -56,11 +56,10 @@ describe("basic cases", function () {
});
}
/*
for (let i=0; i<basicCases.length; i++) {
it("wasm " + basicCases[i].name, async () => {
await doTest(wasm_tester, basicCases[i].circuit, basicCases[i].tv);
});
}
*/
});

+ 0
- 343
test/basiccases.js.old

@ -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<testVectors.length; i++) {
const w = await cir.calculateWitness(normalize(testVectors[i][0]));
await cir.assertOut(w, normalize(testVectors[i][1]) );
}
await cir.release();
}
describe("basic cases", function () {
this.timeout(100000);
it("inout", async () => {
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}],
]
);
});
});

+ 0
- 67
test/cases.js

@ -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);
});
});

+ 0
- 453
test/fieldasm.js

@ -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<nums.length; i++) {
for (let j=0; j<nums.length; j++) {
if ((excludeZero)&&(nums[j][0].isZero())) continue;
tv.push([
[nums[i][1], nums[j][1], op],
F[op](nums[i][0], nums[j][0])
]);
}
}
return tv;
}
function buildTestVector1(p, op) {
const F = new ZqField(p);
const tv = [];
const nums = getCriticalNumbers(p, 2);
const excludeZero = ["inv"].indexOf(op) >= 0;
for (let i=0; i<nums.length; i++) {
if ((excludeZero)&&(nums[i][0].isZero())) continue;
tv.push([
[nums[i][1], op],
F[op](nums[i][0])
]);
}
return tv;
}
function getCriticalNumbers(p, lim) {
const numbers = [];
addFrontier(0);
addFrontier(bigInt(32));
addFrontier(bigInt(64));
addFrontier(bigInt(p.bitLength()));
addFrontier(bigInt.one.shiftLeft(31));
addFrontier(p.minus(bigInt.one.shiftLeft(31)));
addFrontier(bigInt.one.shiftLeft(32));
addFrontier(p.minus(bigInt.one.shiftLeft(32)));
addFrontier(bigInt.one.shiftLeft(63));
addFrontier(p.minus(bigInt.one.shiftLeft(63)));
addFrontier(bigInt.one.shiftLeft(64));
addFrontier(p.minus(bigInt.one.shiftLeft(64)));
addFrontier(bigInt.one.shiftLeft(p.bitLength()-1));
addFrontier(p.shiftRight(1));
function addFrontier(f) {
for (let i=-lim; i<=lim; i++) {
let n = bigInt(f).add(bigInt(i));
n = n.mod(p);
if (n.isNegative()) n = p.add(n);
addNumber(n);
}
}
return numbers;
function addNumber(n) {
if (n.lt(bigInt("80000000", 16)) ) {
addShortPositive(n);
addShortMontgomeryPositive(n);
}
if (n.geq(p.minus(bigInt("80000000", 16))) ) {
addShortNegative(n);
addShortMontgomeryNegative(n);
}
addLongNormal(n);
addLongMontgomery(n);
function addShortPositive(a) {
numbers.push([a, "0x"+a.toString(16)]);
}
function addShortMontgomeryPositive(a) {
let S = "0x" + bigInt("40", 16).shiftLeft(56).add(a).toString(16);
S = S + "," + getLongString(toMontgomery(a));
numbers.push([a, S]);
}
function addShortNegative(a) {
const b = bigInt("80000000", 16 ).add(a.minus( p.minus(bigInt("80000000", 16 ))));
numbers.push([a, "0x"+b.toString(16)]);
}
function addShortMontgomeryNegative(a) {
const b = bigInt("80000000", 16 ).add(a.minus( p.minus(bigInt("80000000", 16 ))));
let S = "0x" + bigInt("40", 16).shiftLeft(56).add(b).toString(16);
S = S + "," + getLongString(toMontgomery(a));
numbers.push([a, S]);
}
function addLongNormal(a) {
let S = "0x" + bigInt("80", 16).shiftLeft(56).toString(16);
S = S + "," + getLongString(a);
numbers.push([a, S]);
}
function addLongMontgomery(a) {
let S = "0x" + bigInt("C0", 16).shiftLeft(56).toString(16);
S = S + "," + getLongString(toMontgomery(a));
numbers.push([a, S]);
}
function getLongString(a) {
if (a.isZero()) {
return "0x0";
}
let r = a;
let S = "";
while (!r.isZero()) {
if (S!= "") S = S+",";
S += "0x" + r.and(bigInt("FFFFFFFFFFFFFFFF", 16)).toString(16);
r = r.shiftRight(64);
}
return S;
}
function toMontgomery(a) {
const n64 = Math.floor((p.bitLength() - 1) / 64)+1;
const R = bigInt.one.shiftLeft(n64*64);
return a.times(R).mod(p);
}
}
}

Loading…
Cancel
Save