mirror of
https://github.com/arnaucube/circom.git
synced 2026-02-06 18:56:40 +01:00
Almost ready for 0.5.0
This commit is contained in:
@@ -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"
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
2
COPYING
2
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.
|
||||
|
||||
|
||||
23
TUTORIAL.md
23
TUTORIAL.md
@@ -16,6 +16,7 @@ Run:
|
||||
|
||||
```sh
|
||||
npm install -g circom
|
||||
npm install -g circom_runtime
|
||||
npm install -g snarkjs
|
||||
```
|
||||
|
||||
@@ -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*
|
||||
@@ -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
|
||||
```
|
||||
|
||||
|
||||
@@ -101,7 +104,7 @@ Ok, let's run a setup for our circuit:
|
||||
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.
|
||||
|
||||
> 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
|
||||
|
||||
8
cli.js
8
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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||
┃ 32 │ 01 00 00 00 ┃ nWires
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||
┃ 4 │ is ┃ Id size ( Normally 4 (32bits))
|
||||
┃ 32 │ 01 00 00 00 ┃ nPubOut
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||
┃ is │ 01 00 00 00 ┃ nWires
|
||||
┃ 32 │ 01 00 00 00 ┃ nPubIn
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||
┃ is │ 01 00 00 00 ┃ nPubOut
|
||||
┃ 32 │ 01 00 00 00 ┃ nPrvIn
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 64 │ 01 00 00 00 00 00 00 00 ┃ nLabels
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||
┃ is │ 01 00 00 00 ┃ nPubIn
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┛
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓
|
||||
┃ 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
|
||||
#### Prime
|
||||
|
||||
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
|
||||
|
||||
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} ┃ ╱
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱
|
||||
╱
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
|
||||
┃ 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} ┃ ╱
|
||||
┗━━━━┻━━━━━━━━━━━━━━━━━┻━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━┛ ╱
|
||||
╱
|
||||
|
||||
|
||||
┏━━━━┳━━━━━━━━━━━━━━━━━┓ ╲
|
||||
┃ 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_{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 ┃
|
||||
┗━━━━━━━━━━━━━━┻━━━━━━━━┛
|
||||
┏━━━━━━━━━━┓
|
||||
┃ 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
|
||||
┃ 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 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
|
||||
┃ 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 ┃
|
||||
┗━━━━━━━━━━━━━━┻━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━┓ 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 ┃
|
||||
┗━━━━━━━━━━┻━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
|
||||
|
||||
┏━━━━━━━━━━━━━━┳━━━━━━━━━━━━━┓
|
||||
┃ 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 ┃
|
||||
┗━━━━━━━━━━━━━━┛
|
||||
┏━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┓
|
||||
┃ 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
|
||||
|
||||
````
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
1119
package-lock.json
generated
1119
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
19
package.json
19
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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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") %>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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) %>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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"],
|
||||
]);
|
||||
});
|
||||
});
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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)) %>
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
Binary file not shown.
@@ -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;
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -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`);
|
||||
} %>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -1 +0,0 @@
|
||||
buildasm/fr.c
|
||||
@@ -1 +0,0 @@
|
||||
buildasm/fr.h
|
||||
@@ -1 +0,0 @@
|
||||
buildasm/fr.o
|
||||
202
ports/c/main.cpp
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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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))),
|
||||
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))),
|
||||
|
||||
// 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)
|
||||
),
|
||||
|
||||
// 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");
|
||||
function buildGetWitnessBuffer() {
|
||||
const f = module.addFunction("getWitnessBuffer");
|
||||
f.setReturnType("i32");
|
||||
f.addLocal("i", "i32");
|
||||
f.addLocal("pSrc", "i32");
|
||||
f.addLocal("pDst", "i32");
|
||||
|
||||
const fErr1 = module.addIimportFunction("err1", "runtime");
|
||||
fErr1.addParam("code", "i32");
|
||||
fErr1.addParam("pStr", "i32");
|
||||
fErr1.addParam("param1", "i32");
|
||||
const c = f.getCodeBuilder();
|
||||
|
||||
const fErr2 = module.addIimportFunction("err2", "runtime");
|
||||
fErr2.addParam("code", "i32");
|
||||
fErr2.addParam("pStr", "i32");
|
||||
fErr2.addParam("param1", "i32");
|
||||
fErr2.addParam("param2", "i32");
|
||||
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))),
|
||||
|
||||
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");
|
||||
c.setLocal(
|
||||
"pSrc",
|
||||
c.i32_add(
|
||||
c.i32_const(builder.pSignals),
|
||||
c.i32_mul(
|
||||
c.getLocal("i"),
|
||||
c.i32_const(builder.sizeFr)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
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");
|
||||
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");
|
||||
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
200
src/r1csfile.js
200
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 bytes = bigInt(n).toArray(256).value.reverse();
|
||||
const dwords = bigInt(n).toArray(0x100000000).value;
|
||||
|
||||
await fd.write(Buffer.from([bytes.length, ...bytes ]));
|
||||
for (let i=0; i<dwords.length; i++) {
|
||||
b.writeUInt32LE(dwords[dwords.length-1-i], i*4, 4 );
|
||||
}
|
||||
b.fill(0, dwords.length*4);
|
||||
|
||||
p += bytes.length+1;
|
||||
await fd.write(b, 0, fs, pos);
|
||||
|
||||
if (typeof(pos) == "undefined") p += n8;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
});
|
||||
|
||||
@@ -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}],
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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);
|
||||
});
|
||||
});
|
||||
453
test/fieldasm.js
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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user