mirror of https://github.com/vacp2p/zerokit.git
feat: wasm (#38)
This commit is contained in:
parent
4f08818d7a
commit
c401c0b21d
|
@ -22,7 +22,7 @@ jobs:
|
||||||
run: git submodule update --init --recursive
|
run: git submodule update --init --recursive
|
||||||
- name: cargo test
|
- name: cargo test
|
||||||
run: |
|
run: |
|
||||||
cargo test
|
cargo test --release --workspace --exclude rln-wasm
|
||||||
lint:
|
lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
@ -40,6 +40,9 @@ jobs:
|
||||||
- name: cargo fmt
|
- name: cargo fmt
|
||||||
run: cargo fmt --all -- --check
|
run: cargo fmt --all -- --check
|
||||||
- name: cargo clippy
|
- name: cargo clippy
|
||||||
run: cargo clippy
|
run: |
|
||||||
|
(cd multiplier && cargo clippy)
|
||||||
|
(cd rln && cargo clippy)
|
||||||
|
(cd semaphore && cargo clippy)
|
||||||
# Currently not treating warnings as error, too noisy
|
# Currently not treating warnings as error, too noisy
|
||||||
# -- -D warnings
|
# -- -D warnings
|
||||||
|
|
|
@ -3,4 +3,5 @@ members = [
|
||||||
"multiplier",
|
"multiplier",
|
||||||
"semaphore",
|
"semaphore",
|
||||||
"rln",
|
"rln",
|
||||||
|
"rln-wasm",
|
||||||
]
|
]
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
[package]
|
||||||
|
name = "rln-wasm"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rln = { path = "../rln", default-features = false, features = ["wasm"] }
|
||||||
|
num-bigint = { version = "0.4", default-features = false, features = ["rand", "serde"] }
|
||||||
|
wasmer = { version = "2.3", default-features = false, features = ["js", "std"] }
|
||||||
|
web-sys = {version = "0.3", features=["console"]}
|
||||||
|
getrandom = { version = "0.2.7", default-features = false, features = ["js"] }
|
||||||
|
wasm-bindgen = "0.2.63"
|
||||||
|
serde-wasm-bindgen = "0.4"
|
||||||
|
js-sys = "0.3.59"
|
||||||
|
console_error_panic_hook = "0.1.7"
|
||||||
|
serde_json = "1.0.85"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
wasm-bindgen-test = "0.3.0"
|
||||||
|
wasm-bindgen-futures = "0.4.33"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
debug = true
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
# RLN for WASM
|
||||||
|
This library is used in [waku-org/js-rln](https://github.com/waku-org/js-rln/)
|
||||||
|
|
||||||
|
## Building the library
|
||||||
|
1. Make sure you have nodejs installed and the `build-essential` package if using ubuntu.
|
||||||
|
2. Install wasm-pack
|
||||||
|
```
|
||||||
|
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
|
||||||
|
```
|
||||||
|
3. Compile zerokit for `wasm32-unknown-unknown`:
|
||||||
|
```
|
||||||
|
cd rln-wasm
|
||||||
|
wasm-pack build --release
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running tests
|
||||||
|
```
|
||||||
|
cd rln-wasm
|
||||||
|
wasm-pack test --node --release
|
||||||
|
```
|
|
@ -0,0 +1,331 @@
|
||||||
|
module.exports = async function builder(code, options) {
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
let wasmModule;
|
||||||
|
try {
|
||||||
|
wasmModule = await WebAssembly.compile(code);
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
|
console.log("\nTry to run circom --c in order to generate c++ code instead\n");
|
||||||
|
throw new Error(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
let wc;
|
||||||
|
|
||||||
|
let errStr = "";
|
||||||
|
let msgStr = "";
|
||||||
|
|
||||||
|
const instance = await WebAssembly.instantiate(wasmModule, {
|
||||||
|
runtime: {
|
||||||
|
exceptionHandler : function(code) {
|
||||||
|
let err;
|
||||||
|
if (code == 1) {
|
||||||
|
err = "Signal not found.\n";
|
||||||
|
} else if (code == 2) {
|
||||||
|
err = "Too many signals set.\n";
|
||||||
|
} else if (code == 3) {
|
||||||
|
err = "Signal already set.\n";
|
||||||
|
} else if (code == 4) {
|
||||||
|
err = "Assert Failed.\n";
|
||||||
|
} else if (code == 5) {
|
||||||
|
err = "Not enough memory.\n";
|
||||||
|
} else if (code == 6) {
|
||||||
|
err = "Input signal array access exceeds the size.\n";
|
||||||
|
} else {
|
||||||
|
err = "Unknown error.\n";
|
||||||
|
}
|
||||||
|
throw new Error(err + errStr);
|
||||||
|
},
|
||||||
|
printErrorMessage : function() {
|
||||||
|
errStr += getMessage() + "\n";
|
||||||
|
// console.error(getMessage());
|
||||||
|
},
|
||||||
|
writeBufferMessage : function() {
|
||||||
|
const msg = getMessage();
|
||||||
|
// Any calls to `log()` will always end with a `\n`, so that's when we print and reset
|
||||||
|
if (msg === "\n") {
|
||||||
|
console.log(msgStr);
|
||||||
|
msgStr = "";
|
||||||
|
} else {
|
||||||
|
// If we've buffered other content, put a space in between the items
|
||||||
|
if (msgStr !== "") {
|
||||||
|
msgStr += " "
|
||||||
|
}
|
||||||
|
// Then append the message to the message we are creating
|
||||||
|
msgStr += msg;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showSharedRWMemory : function() {
|
||||||
|
printSharedRWMemory ();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const sanityCheck =
|
||||||
|
options
|
||||||
|
// options &&
|
||||||
|
// (
|
||||||
|
// options.sanityCheck ||
|
||||||
|
// options.logGetSignal ||
|
||||||
|
// options.logSetSignal ||
|
||||||
|
// options.logStartComponent ||
|
||||||
|
// options.logFinishComponent
|
||||||
|
// );
|
||||||
|
|
||||||
|
|
||||||
|
wc = new WitnessCalculator(instance, sanityCheck);
|
||||||
|
return wc;
|
||||||
|
|
||||||
|
function getMessage() {
|
||||||
|
var message = "";
|
||||||
|
var c = instance.exports.getMessageChar();
|
||||||
|
while ( c != 0 ) {
|
||||||
|
message += String.fromCharCode(c);
|
||||||
|
c = instance.exports.getMessageChar();
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
function printSharedRWMemory () {
|
||||||
|
const shared_rw_memory_size = instance.exports.getFieldNumLen32();
|
||||||
|
const arr = new Uint32Array(shared_rw_memory_size);
|
||||||
|
for (let j=0; j<shared_rw_memory_size; j++) {
|
||||||
|
arr[shared_rw_memory_size-1-j] = instance.exports.readSharedRWMemory(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've buffered other content, put a space in between the items
|
||||||
|
if (msgStr !== "") {
|
||||||
|
msgStr += " "
|
||||||
|
}
|
||||||
|
// Then append the value to the message we are creating
|
||||||
|
msgStr += (fromArray32(arr).toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class WitnessCalculator {
|
||||||
|
constructor(instance, sanityCheck) {
|
||||||
|
this.instance = instance;
|
||||||
|
|
||||||
|
this.version = this.instance.exports.getVersion();
|
||||||
|
this.n32 = this.instance.exports.getFieldNumLen32();
|
||||||
|
|
||||||
|
this.instance.exports.getRawPrime();
|
||||||
|
const arr = new Uint32Array(this.n32);
|
||||||
|
for (let i=0; i<this.n32; i++) {
|
||||||
|
arr[this.n32-1-i] = this.instance.exports.readSharedRWMemory(i);
|
||||||
|
}
|
||||||
|
this.prime = fromArray32(arr);
|
||||||
|
|
||||||
|
this.witnessSize = this.instance.exports.getWitnessSize();
|
||||||
|
|
||||||
|
this.sanityCheck = sanityCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
circom_version() {
|
||||||
|
return this.instance.exports.getVersion();
|
||||||
|
}
|
||||||
|
|
||||||
|
async _doCalculateWitness(input, sanityCheck) {
|
||||||
|
//input is assumed to be a map from signals to arrays of bigints
|
||||||
|
this.instance.exports.init((this.sanityCheck || sanityCheck) ? 1 : 0);
|
||||||
|
const keys = Object.keys(input);
|
||||||
|
var input_counter = 0;
|
||||||
|
keys.forEach( (k) => {
|
||||||
|
const h = fnvHash(k);
|
||||||
|
const hMSB = parseInt(h.slice(0,8), 16);
|
||||||
|
const hLSB = parseInt(h.slice(8,16), 16);
|
||||||
|
const fArr = flatArray(input[k]);
|
||||||
|
let signalSize = this.instance.exports.getInputSignalSize(hMSB, hLSB);
|
||||||
|
if (signalSize < 0){
|
||||||
|
throw new Error(`Signal ${k} not found\n`);
|
||||||
|
}
|
||||||
|
if (fArr.length < signalSize) {
|
||||||
|
throw new Error(`Not enough values for input signal ${k}\n`);
|
||||||
|
}
|
||||||
|
if (fArr.length > signalSize) {
|
||||||
|
throw new Error(`Too many values for input signal ${k}\n`);
|
||||||
|
}
|
||||||
|
for (let i=0; i<fArr.length; i++) {
|
||||||
|
const arrFr = toArray32(BigInt(fArr[i])%this.prime,this.n32)
|
||||||
|
for (let j=0; j<this.n32; j++) {
|
||||||
|
this.instance.exports.writeSharedRWMemory(j,arrFr[this.n32-1-j]);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
this.instance.exports.setInputSignal(hMSB, hLSB,i);
|
||||||
|
input_counter++;
|
||||||
|
} catch (err) {
|
||||||
|
// console.log(`After adding signal ${i} of ${k}`)
|
||||||
|
throw new Error(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
if (input_counter < this.instance.exports.getInputSize()) {
|
||||||
|
throw new Error(`Not all inputs have been set. Only ${input_counter} out of ${this.instance.exports.getInputSize()}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async calculateWitness(input, sanityCheck) {
|
||||||
|
|
||||||
|
const w = [];
|
||||||
|
|
||||||
|
await this._doCalculateWitness(input, sanityCheck);
|
||||||
|
|
||||||
|
for (let i=0; i<this.witnessSize; i++) {
|
||||||
|
this.instance.exports.getWitness(i);
|
||||||
|
const arr = new Uint32Array(this.n32);
|
||||||
|
for (let j=0; j<this.n32; j++) {
|
||||||
|
arr[this.n32-1-j] = this.instance.exports.readSharedRWMemory(j);
|
||||||
|
}
|
||||||
|
w.push(fromArray32(arr));
|
||||||
|
}
|
||||||
|
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async calculateBinWitness(input, sanityCheck) {
|
||||||
|
|
||||||
|
const buff32 = new Uint32Array(this.witnessSize*this.n32);
|
||||||
|
const buff = new Uint8Array( buff32.buffer);
|
||||||
|
await this._doCalculateWitness(input, sanityCheck);
|
||||||
|
|
||||||
|
for (let i=0; i<this.witnessSize; i++) {
|
||||||
|
this.instance.exports.getWitness(i);
|
||||||
|
const pos = i*this.n32;
|
||||||
|
for (let j=0; j<this.n32; j++) {
|
||||||
|
buff32[pos+j] = this.instance.exports.readSharedRWMemory(j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async calculateWTNSBin(input, sanityCheck) {
|
||||||
|
|
||||||
|
const buff32 = new Uint32Array(this.witnessSize*this.n32+this.n32+11);
|
||||||
|
const buff = new Uint8Array( buff32.buffer);
|
||||||
|
await this._doCalculateWitness(input, sanityCheck);
|
||||||
|
|
||||||
|
//"wtns"
|
||||||
|
buff[0] = "w".charCodeAt(0)
|
||||||
|
buff[1] = "t".charCodeAt(0)
|
||||||
|
buff[2] = "n".charCodeAt(0)
|
||||||
|
buff[3] = "s".charCodeAt(0)
|
||||||
|
|
||||||
|
//version 2
|
||||||
|
buff32[1] = 2;
|
||||||
|
|
||||||
|
//number of sections: 2
|
||||||
|
buff32[2] = 2;
|
||||||
|
|
||||||
|
//id section 1
|
||||||
|
buff32[3] = 1;
|
||||||
|
|
||||||
|
const n8 = this.n32*4;
|
||||||
|
//id section 1 length in 64bytes
|
||||||
|
const idSection1length = 8 + n8;
|
||||||
|
const idSection1lengthHex = idSection1length.toString(16);
|
||||||
|
buff32[4] = parseInt(idSection1lengthHex.slice(0,8), 16);
|
||||||
|
buff32[5] = parseInt(idSection1lengthHex.slice(8,16), 16);
|
||||||
|
|
||||||
|
//this.n32
|
||||||
|
buff32[6] = n8;
|
||||||
|
|
||||||
|
//prime number
|
||||||
|
this.instance.exports.getRawPrime();
|
||||||
|
|
||||||
|
var pos = 7;
|
||||||
|
for (let j=0; j<this.n32; j++) {
|
||||||
|
buff32[pos+j] = this.instance.exports.readSharedRWMemory(j);
|
||||||
|
}
|
||||||
|
pos += this.n32;
|
||||||
|
|
||||||
|
// witness size
|
||||||
|
buff32[pos] = this.witnessSize;
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
//id section 2
|
||||||
|
buff32[pos] = 2;
|
||||||
|
pos++;
|
||||||
|
|
||||||
|
// section 2 length
|
||||||
|
const idSection2length = n8*this.witnessSize;
|
||||||
|
const idSection2lengthHex = idSection2length.toString(16);
|
||||||
|
buff32[pos] = parseInt(idSection2lengthHex.slice(0,8), 16);
|
||||||
|
buff32[pos+1] = parseInt(idSection2lengthHex.slice(8,16), 16);
|
||||||
|
|
||||||
|
pos += 2;
|
||||||
|
for (let i=0; i<this.witnessSize; i++) {
|
||||||
|
this.instance.exports.getWitness(i);
|
||||||
|
for (let j=0; j<this.n32; j++) {
|
||||||
|
buff32[pos+j] = this.instance.exports.readSharedRWMemory(j);
|
||||||
|
}
|
||||||
|
pos += this.n32;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function toArray32(rem,size) {
|
||||||
|
const res = []; //new Uint32Array(size); //has no unshift
|
||||||
|
const radix = BigInt(0x100000000);
|
||||||
|
while (rem) {
|
||||||
|
res.unshift( Number(rem % radix));
|
||||||
|
rem = rem / radix;
|
||||||
|
}
|
||||||
|
if (size) {
|
||||||
|
var i = size - res.length;
|
||||||
|
while (i>0) {
|
||||||
|
res.unshift(0);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fromArray32(arr) { //returns a BigInt
|
||||||
|
var res = BigInt(0);
|
||||||
|
const radix = BigInt(0x100000000);
|
||||||
|
for (let i = 0; i<arr.length; i++) {
|
||||||
|
res = res*radix + BigInt(arr[i]);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
function flatArray(a) {
|
||||||
|
var res = [];
|
||||||
|
fillArray(res, a);
|
||||||
|
return res;
|
||||||
|
|
||||||
|
function fillArray(res, a) {
|
||||||
|
if (Array.isArray(a)) {
|
||||||
|
for (let i=0; i<a.length; i++) {
|
||||||
|
fillArray(res, a[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
res.push(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function fnvHash(str) {
|
||||||
|
const uint64_max = BigInt(2) ** BigInt(64);
|
||||||
|
let hash = BigInt("0xCBF29CE484222325");
|
||||||
|
for (var i = 0; i < str.length; i++) {
|
||||||
|
hash ^= BigInt(str[i].charCodeAt());
|
||||||
|
hash *= BigInt(0x100000001B3);
|
||||||
|
hash %= uint64_max;
|
||||||
|
}
|
||||||
|
let shash = hash.toString(16);
|
||||||
|
let n = 16 - shash.length;
|
||||||
|
shash = '0'.repeat(n).concat(shash);
|
||||||
|
return shash;
|
||||||
|
}
|
|
@ -0,0 +1,222 @@
|
||||||
|
extern crate wasm_bindgen;
|
||||||
|
extern crate web_sys;
|
||||||
|
|
||||||
|
use js_sys::{BigInt as JsBigInt, Object, Uint8Array};
|
||||||
|
use num_bigint::BigInt;
|
||||||
|
use rln::public::RLN;
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn init_panic_hook() {
|
||||||
|
console_error_panic_hook::set_once();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen(js_name = RLN)]
|
||||||
|
pub struct RLNWrapper {
|
||||||
|
// The purpose of this wrapper is to hold a RLN instance with the 'static lifetime
|
||||||
|
// because wasm_bindgen does not allow returning elements with lifetimes
|
||||||
|
instance: RLN<'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||||
|
#[wasm_bindgen(js_name = newRLN)]
|
||||||
|
pub fn wasm_new(tree_height: usize, zkey: Uint8Array, vk: Uint8Array) -> *mut RLNWrapper {
|
||||||
|
let instance = RLN::new_with_params(tree_height, zkey.to_vec(), vk.to_vec());
|
||||||
|
let wrapper = RLNWrapper { instance };
|
||||||
|
Box::into_raw(Box::new(wrapper))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||||
|
#[wasm_bindgen(js_name = getSerializedRLNWitness)]
|
||||||
|
pub fn wasm_get_serialized_rln_witness(ctx: *mut RLNWrapper, input: Uint8Array) -> Uint8Array {
|
||||||
|
let wrapper = unsafe { &mut *ctx };
|
||||||
|
let rln_witness = wrapper
|
||||||
|
.instance
|
||||||
|
.get_serialized_rln_witness(&input.to_vec()[..]);
|
||||||
|
|
||||||
|
Uint8Array::from(&rln_witness[..])
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||||
|
#[wasm_bindgen(js_name = insertMember)]
|
||||||
|
pub fn wasm_set_next_leaf(ctx: *mut RLNWrapper, input: Uint8Array) -> Result<(), String> {
|
||||||
|
let wrapper = unsafe { &mut *ctx };
|
||||||
|
if wrapper.instance.set_next_leaf(&input.to_vec()[..]).is_ok() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err("could not insert member into merkle tree".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||||
|
#[wasm_bindgen(js_name = RLNWitnessToJson)]
|
||||||
|
pub fn rln_witness_to_json(ctx: *mut RLNWrapper, serialized_witness: Uint8Array) -> Object {
|
||||||
|
let wrapper = unsafe { &mut *ctx };
|
||||||
|
let inputs = wrapper
|
||||||
|
.instance
|
||||||
|
.get_rln_witness_json(&serialized_witness.to_vec()[..])
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let js_value = serde_wasm_bindgen::to_value(&inputs).unwrap();
|
||||||
|
let obj = Object::from_entries(&js_value);
|
||||||
|
obj.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn generate_rln_proof_with_witness(
|
||||||
|
ctx: *mut RLNWrapper,
|
||||||
|
calculated_witness: Vec<JsBigInt>,
|
||||||
|
serialized_witness: Uint8Array,
|
||||||
|
) -> Result<Uint8Array, String> {
|
||||||
|
let wrapper = unsafe { &mut *ctx };
|
||||||
|
|
||||||
|
let witness_vec: Vec<BigInt> = calculated_witness
|
||||||
|
.iter()
|
||||||
|
.map(|v| {
|
||||||
|
v.to_string(10)
|
||||||
|
.unwrap()
|
||||||
|
.as_string()
|
||||||
|
.unwrap()
|
||||||
|
.parse::<BigInt>()
|
||||||
|
.unwrap()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut output_data: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
|
if wrapper
|
||||||
|
.instance
|
||||||
|
.generate_rln_proof_with_witness(witness_vec, serialized_witness.to_vec(), &mut output_data)
|
||||||
|
.is_ok()
|
||||||
|
{
|
||||||
|
let result = Uint8Array::from(&output_data[..]);
|
||||||
|
std::mem::forget(output_data);
|
||||||
|
Ok(result)
|
||||||
|
} else {
|
||||||
|
std::mem::forget(output_data);
|
||||||
|
Err("could not generate proof".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||||
|
#[wasm_bindgen(js_name = generateMembershipKey)]
|
||||||
|
pub fn wasm_key_gen(ctx: *const RLNWrapper) -> Result<Uint8Array, String> {
|
||||||
|
let wrapper = unsafe { &*ctx };
|
||||||
|
let mut output_data: Vec<u8> = Vec::new();
|
||||||
|
if wrapper.instance.key_gen(&mut output_data).is_ok() {
|
||||||
|
let result = Uint8Array::from(&output_data[..]);
|
||||||
|
std::mem::forget(output_data);
|
||||||
|
Ok(result)
|
||||||
|
} else {
|
||||||
|
std::mem::forget(output_data);
|
||||||
|
Err("could not generate membership keys".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
||||||
|
#[wasm_bindgen(js_name = verifyProof)]
|
||||||
|
pub fn wasm_verify(ctx: *const RLNWrapper, proof: Uint8Array) -> bool {
|
||||||
|
let wrapper = unsafe { &*ctx };
|
||||||
|
if match wrapper.instance.verify(&proof.to_vec()[..]) {
|
||||||
|
Ok(verified) => verified,
|
||||||
|
Err(_) => return false,
|
||||||
|
} {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use rln::circuit::TEST_TREE_HEIGHT;
|
||||||
|
use wasm_bindgen_test::wasm_bindgen_test;
|
||||||
|
|
||||||
|
#[wasm_bindgen(module = "/src/utils.js")]
|
||||||
|
extern "C" {
|
||||||
|
#[wasm_bindgen(catch)]
|
||||||
|
fn read_file(path: &str) -> Result<Uint8Array, JsValue>;
|
||||||
|
|
||||||
|
#[wasm_bindgen(catch)]
|
||||||
|
async fn calculateWitness(circom_path: &str, input: Object) -> Result<JsValue, JsValue>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen_test]
|
||||||
|
pub async fn test_basic_flow() {
|
||||||
|
let tree_height = TEST_TREE_HEIGHT;
|
||||||
|
let circom_path = format!("../rln/resources/tree_height_{TEST_TREE_HEIGHT}/rln.wasm");
|
||||||
|
let zkey_path = format!("../rln/resources/tree_height_{TEST_TREE_HEIGHT}/rln_final.zkey");
|
||||||
|
let vk_path =
|
||||||
|
format!("../rln/resources/tree_height_{TEST_TREE_HEIGHT}/verification_key.json");
|
||||||
|
let zkey = read_file(&zkey_path).unwrap();
|
||||||
|
let vk = read_file(&vk_path).unwrap();
|
||||||
|
|
||||||
|
// Creating an instance of RLN
|
||||||
|
let rln_instance = wasm_new(tree_height, zkey, vk);
|
||||||
|
|
||||||
|
// Creating membership key
|
||||||
|
let mem_keys = wasm_key_gen(rln_instance).unwrap();
|
||||||
|
let idkey = mem_keys.subarray(0, 32);
|
||||||
|
let idcommitment = mem_keys.subarray(32, 64);
|
||||||
|
|
||||||
|
// Insert PK
|
||||||
|
wasm_set_next_leaf(rln_instance, idcommitment).unwrap();
|
||||||
|
|
||||||
|
// Prepare the message
|
||||||
|
let mut signal = "Hello World".as_bytes().to_vec();
|
||||||
|
let signal_len: u64 = signal.len() as u64;
|
||||||
|
|
||||||
|
// Setting up the epoch (With 0s for the test)
|
||||||
|
let epoch = Uint8Array::new_with_length(32);
|
||||||
|
epoch.fill(0, 0, 32);
|
||||||
|
|
||||||
|
let identity_index: u64 = 0;
|
||||||
|
|
||||||
|
// Serializing the message
|
||||||
|
let mut serialized_vec: Vec<u8> = Vec::new();
|
||||||
|
serialized_vec.append(&mut idkey.to_vec());
|
||||||
|
serialized_vec.append(&mut identity_index.to_le_bytes().to_vec());
|
||||||
|
serialized_vec.append(&mut epoch.to_vec());
|
||||||
|
serialized_vec.append(&mut signal_len.to_le_bytes().to_vec());
|
||||||
|
serialized_vec.append(&mut signal);
|
||||||
|
let serialized_message = Uint8Array::from(&serialized_vec[..]);
|
||||||
|
|
||||||
|
let serialized_rln_witness =
|
||||||
|
wasm_get_serialized_rln_witness(rln_instance, serialized_message);
|
||||||
|
|
||||||
|
// Obtaining inputs that should be sent to circom witness calculator
|
||||||
|
let json_inputs = rln_witness_to_json(rln_instance, serialized_rln_witness.clone());
|
||||||
|
|
||||||
|
// Calculating witness with JS
|
||||||
|
// (Using a JSON since wasm_bindgen does not like Result<Vec<JsBigInt>,JsValue>)
|
||||||
|
let calculated_witness_json = calculateWitness(&circom_path, json_inputs)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.as_string()
|
||||||
|
.unwrap();
|
||||||
|
let calculated_witness_vec_str: Vec<String> =
|
||||||
|
serde_json::from_str(&calculated_witness_json).unwrap();
|
||||||
|
let calculated_witness: Vec<JsBigInt> = calculated_witness_vec_str
|
||||||
|
.iter()
|
||||||
|
.map(|x| JsBigInt::new(&x.into()).unwrap())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Generating proof
|
||||||
|
let proof = generate_rln_proof_with_witness(
|
||||||
|
rln_instance,
|
||||||
|
calculated_witness.into(),
|
||||||
|
serialized_rln_witness,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Validate Proof
|
||||||
|
let is_proof_valid = wasm_verify(rln_instance, proof);
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
is_proof_valid,
|
||||||
|
"validating proof generated with wasm failed"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
const fs = require("fs");
|
||||||
|
|
||||||
|
// Utils functions for loading circom witness calculator and reading files from test
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
read_file: function (path) {
|
||||||
|
return fs.readFileSync(path);
|
||||||
|
},
|
||||||
|
|
||||||
|
calculateWitness: async function(circom_path, inputs){
|
||||||
|
const wc = require("resources/witness_calculator.js");
|
||||||
|
const wasmFile = fs.readFileSync(circom_path);
|
||||||
|
const wasmFileBuffer = wasmFile.slice(wasmFile.byteOffset, wasmFile.byteOffset + wasmFile.byteLength);
|
||||||
|
const witnessCalculator = await wc(wasmFileBuffer);
|
||||||
|
const calculatedWitness = await witnessCalculator.calculateWitness(inputs, false);
|
||||||
|
return JSON.stringify(calculatedWitness, (key, value) => typeof value === "bigint" ? value.toString() : value);
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,18 +6,22 @@ edition = "2021"
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib", "rlib", "staticlib"]
|
crate-type = ["cdylib", "rlib", "staticlib"]
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
||||||
# ZKP Generation
|
# ZKP Generation
|
||||||
ark-ff = { version = "0.3.0", default-features = false, features = ["parallel", "asm"] }
|
ark-ec = { version = "0.3.0", default-features = false }
|
||||||
ark-std = { version = "0.3.0", default-features = false, features = ["parallel"] }
|
ark-ff = { version = "0.3.0", default-features = false, features = [ "asm"] }
|
||||||
|
ark-std = { version = "0.3.0", default-features = false }
|
||||||
ark-bn254 = { version = "0.3.0" }
|
ark-bn254 = { version = "0.3.0" }
|
||||||
ark-groth16 = { git = "https://github.com/arkworks-rs/groth16", rev = "765817f", features = ["parallel"] }
|
ark-groth16 = { git = "https://github.com/arkworks-rs/groth16", rev = "765817f", default-features = false }
|
||||||
ark-relations = { version = "0.3.0", default-features = false, features = [ "std" ] }
|
ark-relations = { version = "0.3.0", default-features = false, features = [ "std" ] }
|
||||||
ark-serialize = { version = "0.3.0", default-features = false }
|
ark-serialize = { version = "0.3.0", default-features = false }
|
||||||
ark-circom = { git = "https://github.com/gakonst/ark-circom", rev = "06eb075", features = ["circom-2"] }
|
ark-circom = { git = "https://github.com/vacp2p/ark-circom", branch = "wasm", default-features = false, features = ["circom-2"] }
|
||||||
#ark-circom = { git = "https://github.com/vacp2p/ark-circom", branch = "no-ethers-core", features = ["circom-2"] }
|
#ark-circom = { git = "https://github.com/vacp2p/ark-circom", branch = "no-ethers-core", features = ["circom-2"] }
|
||||||
wasmer = "2.3.0"
|
|
||||||
|
# WASM
|
||||||
|
wasmer = { version = "2.3.0", default-features = false }
|
||||||
|
|
||||||
# error handling
|
# error handling
|
||||||
color-eyre = "0.5.11"
|
color-eyre = "0.5.11"
|
||||||
|
@ -39,4 +43,7 @@ serde_json = "1.0.48"
|
||||||
hex-literal = "0.3.4"
|
hex-literal = "0.3.4"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
default = ["parallel", "wasmer/sys-default"]
|
||||||
fullmerkletree = []
|
fullmerkletree = []
|
||||||
|
parallel = ["ark-ec/parallel", "ark-ff/parallel", "ark-std/parallel", "ark-groth16/parallel"]
|
||||||
|
wasm = ["wasmer/js", "wasmer/std"]
|
||||||
|
|
|
@ -4,18 +4,25 @@ use ark_bn254::{
|
||||||
Bn254, Fq as ArkFq, Fq2 as ArkFq2, Fr as ArkFr, G1Affine as ArkG1Affine,
|
Bn254, Fq as ArkFq, Fq2 as ArkFq2, Fr as ArkFr, G1Affine as ArkG1Affine,
|
||||||
G1Projective as ArkG1Projective, G2Affine as ArkG2Affine, G2Projective as ArkG2Projective,
|
G1Projective as ArkG1Projective, G2Affine as ArkG2Affine, G2Projective as ArkG2Projective,
|
||||||
};
|
};
|
||||||
use ark_circom::{read_zkey, WitnessCalculator};
|
use ark_circom::read_zkey;
|
||||||
use ark_groth16::{ProvingKey, VerifyingKey};
|
use ark_groth16::{ProvingKey, VerifyingKey};
|
||||||
use ark_relations::r1cs::ConstraintMatrices;
|
use ark_relations::r1cs::ConstraintMatrices;
|
||||||
|
use cfg_if::cfg_if;
|
||||||
use num_bigint::BigUint;
|
use num_bigint::BigUint;
|
||||||
use once_cell::sync::OnceCell;
|
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Cursor, Error, ErrorKind, Result};
|
use std::io::{Cursor, Error, ErrorKind, Result};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::Mutex;
|
|
||||||
use wasmer::{Module, Store};
|
cfg_if! {
|
||||||
|
if #[cfg(not(target_arch = "wasm32"))] {
|
||||||
|
use ark_circom::{WitnessCalculator};
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use wasmer::{Module, Store};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const ZKEY_FILENAME: &str = "rln_final.zkey";
|
const ZKEY_FILENAME: &str = "rln_final.zkey";
|
||||||
const VK_FILENAME: &str = "verifying_key.json";
|
const VK_FILENAME: &str = "verifying_key.json";
|
||||||
|
@ -109,9 +116,11 @@ pub fn vk_from_folder(resources_folder: &str) -> Result<VerifyingKey<Curve>> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
static WITNESS_CALCULATOR: OnceCell<Mutex<WitnessCalculator>> = OnceCell::new();
|
static WITNESS_CALCULATOR: OnceCell<Mutex<WitnessCalculator>> = OnceCell::new();
|
||||||
|
|
||||||
// Initializes the witness calculator using a bytes vector
|
// Initializes the witness calculator using a bytes vector
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub fn circom_from_raw(wasm_buffer: Vec<u8>) -> &'static Mutex<WitnessCalculator> {
|
pub fn circom_from_raw(wasm_buffer: Vec<u8>) -> &'static Mutex<WitnessCalculator> {
|
||||||
WITNESS_CALCULATOR.get_or_init(|| {
|
WITNESS_CALCULATOR.get_or_init(|| {
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
|
@ -123,6 +132,7 @@ pub fn circom_from_raw(wasm_buffer: Vec<u8>) -> &'static Mutex<WitnessCalculator
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes the witness calculator
|
// Initializes the witness calculator
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub fn circom_from_folder(resources_folder: &str) -> &'static Mutex<WitnessCalculator> {
|
pub fn circom_from_folder(resources_folder: &str) -> &'static Mutex<WitnessCalculator> {
|
||||||
// We read the wasm file
|
// We read the wasm file
|
||||||
let wasm_path = format!("{resources_folder}{WASM_FILENAME}");
|
let wasm_path = format!("{resources_folder}{WASM_FILENAME}");
|
||||||
|
|
|
@ -59,7 +59,12 @@ pub extern "C" fn new_with_params(
|
||||||
let circom_data = <&[u8]>::from(unsafe { &*circom_buffer });
|
let circom_data = <&[u8]>::from(unsafe { &*circom_buffer });
|
||||||
let zkey_data = <&[u8]>::from(unsafe { &*zkey_buffer });
|
let zkey_data = <&[u8]>::from(unsafe { &*zkey_buffer });
|
||||||
let vk_data = <&[u8]>::from(unsafe { &*vk_buffer });
|
let vk_data = <&[u8]>::from(unsafe { &*vk_buffer });
|
||||||
let rln = RLN::new_with_params(tree_height, circom_data, zkey_data, vk_data);
|
let rln = RLN::new_with_params(
|
||||||
|
tree_height,
|
||||||
|
circom_data.to_vec(),
|
||||||
|
zkey_data.to_vec(),
|
||||||
|
vk_data.to_vec(),
|
||||||
|
);
|
||||||
unsafe { *ctx = Box::into_raw(Box::new(rln)) };
|
unsafe { *ctx = Box::into_raw(Box::new(rln)) };
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
|
|
||||||
pub mod circuit;
|
pub mod circuit;
|
||||||
pub mod ffi;
|
|
||||||
pub mod merkle_tree;
|
pub mod merkle_tree;
|
||||||
pub mod poseidon_constants;
|
pub mod poseidon_constants;
|
||||||
pub mod poseidon_hash;
|
pub mod poseidon_hash;
|
||||||
|
@ -10,6 +9,9 @@ pub mod protocol;
|
||||||
pub mod public;
|
pub mod public;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
pub mod ffi;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ use ark_std::{rand::thread_rng, UniformRand};
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use num_bigint::BigInt;
|
use num_bigint::BigInt;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
@ -22,6 +23,7 @@ use crate::poseidon_hash::poseidon_hash;
|
||||||
use crate::poseidon_tree::*;
|
use crate::poseidon_tree::*;
|
||||||
use crate::public::RLN_IDENTIFIER;
|
use crate::public::RLN_IDENTIFIER;
|
||||||
use crate::utils::*;
|
use crate::utils::*;
|
||||||
|
use cfg_if::cfg_if;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////
|
||||||
// RLN Witness data structure and utility functions
|
// RLN Witness data structure and utility functions
|
||||||
|
@ -121,12 +123,9 @@ pub fn proof_inputs_to_rln_witness(
|
||||||
let signal_len = u64::from_le_bytes(serialized[all_read..all_read + 8].try_into().unwrap());
|
let signal_len = u64::from_le_bytes(serialized[all_read..all_read + 8].try_into().unwrap());
|
||||||
all_read += 8;
|
all_read += 8;
|
||||||
|
|
||||||
let signal: Vec<u8> =
|
let signal: Vec<u8> = serialized[all_read..all_read + (signal_len as usize)].to_vec();
|
||||||
serialized[all_read..all_read + usize::try_from(signal_len).unwrap()].to_vec();
|
|
||||||
|
|
||||||
let merkle_proof = tree
|
let merkle_proof = tree.proof(id_index as usize).expect("proof should exist");
|
||||||
.proof(usize::try_from(id_index).unwrap())
|
|
||||||
.expect("proof should exist");
|
|
||||||
let path_elements = merkle_proof.get_path_elements();
|
let path_elements = merkle_proof.get_path_elements();
|
||||||
let identity_path_index = merkle_proof.get_path_index();
|
let identity_path_index = merkle_proof.get_path_index();
|
||||||
|
|
||||||
|
@ -374,16 +373,70 @@ pub enum ProofError {
|
||||||
SynthesisError(#[from] SynthesisError),
|
SynthesisError(#[from] SynthesisError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a RLN proof
|
fn calculate_witness_element<E: ark_ec::PairingEngine>(witness: Vec<BigInt>) -> Result<Vec<E::Fr>> {
|
||||||
///
|
use ark_ff::{FpParameters, PrimeField};
|
||||||
/// # Errors
|
let modulus = <<E::Fr as PrimeField>::Params as FpParameters>::MODULUS;
|
||||||
///
|
|
||||||
/// Returns a [`ProofError`] if proving fails.
|
// convert it to field elements
|
||||||
pub fn generate_proof(
|
use num_traits::Signed;
|
||||||
witness_calculator: &Mutex<WitnessCalculator>,
|
let witness = witness
|
||||||
|
.into_iter()
|
||||||
|
.map(|w| {
|
||||||
|
let w = if w.sign() == num_bigint::Sign::Minus {
|
||||||
|
// Need to negate the witness element if negative
|
||||||
|
modulus.into() - w.abs().to_biguint().unwrap()
|
||||||
|
} else {
|
||||||
|
w.to_biguint().unwrap()
|
||||||
|
};
|
||||||
|
E::Fr::from(w)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
Ok(witness)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_proof_with_witness(
|
||||||
|
witness: Vec<BigInt>,
|
||||||
proving_key: &(ProvingKey<Curve>, ConstraintMatrices<Fr>),
|
proving_key: &(ProvingKey<Curve>, ConstraintMatrices<Fr>),
|
||||||
rln_witness: &RLNWitnessInput,
|
|
||||||
) -> Result<ArkProof<Curve>, ProofError> {
|
) -> Result<ArkProof<Curve>, ProofError> {
|
||||||
|
// If in debug mode, we measure and later print time take to compute witness
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
let now = Instant::now();
|
||||||
|
|
||||||
|
let full_assignment = calculate_witness_element::<Curve>(witness)
|
||||||
|
.map_err(ProofError::WitnessError)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
println!("witness generation took: {:.2?}", now.elapsed());
|
||||||
|
|
||||||
|
// Random Values
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
let r = Fr::rand(&mut rng);
|
||||||
|
let s = Fr::rand(&mut rng);
|
||||||
|
|
||||||
|
// If in debug mode, we measure and later print time take to compute proof
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
let now = Instant::now();
|
||||||
|
|
||||||
|
let proof = create_proof_with_reduction_and_matrices::<_, CircomReduction>(
|
||||||
|
&proving_key.0,
|
||||||
|
r,
|
||||||
|
s,
|
||||||
|
&proving_key.1,
|
||||||
|
proving_key.1.num_instance_variables,
|
||||||
|
proving_key.1.num_constraints,
|
||||||
|
full_assignment.as_slice(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
println!("proof generation took: {:.2?}", now.elapsed());
|
||||||
|
|
||||||
|
Ok(proof)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn inputs_for_witness_calculation(rln_witness: &RLNWitnessInput) -> [(&str, Vec<BigInt>); 6] {
|
||||||
// We confert the path indexes to field elements
|
// We confert the path indexes to field elements
|
||||||
// TODO: check if necessary
|
// TODO: check if necessary
|
||||||
let mut path_elements = Vec::new();
|
let mut path_elements = Vec::new();
|
||||||
|
@ -398,7 +451,7 @@ pub fn generate_proof(
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|v| identity_path_index.push(BigInt::from(*v)));
|
.for_each(|v| identity_path_index.push(BigInt::from(*v)));
|
||||||
|
|
||||||
let inputs = [
|
[
|
||||||
(
|
(
|
||||||
"identity_secret",
|
"identity_secret",
|
||||||
vec![to_bigint(&rln_witness.identity_secret)],
|
vec![to_bigint(&rln_witness.identity_secret)],
|
||||||
|
@ -411,8 +464,21 @@ pub fn generate_proof(
|
||||||
"rln_identifier",
|
"rln_identifier",
|
||||||
vec![to_bigint(&rln_witness.rln_identifier)],
|
vec![to_bigint(&rln_witness.rln_identifier)],
|
||||||
),
|
),
|
||||||
];
|
]
|
||||||
let inputs = inputs
|
}
|
||||||
|
|
||||||
|
/// Generates a RLN proof
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// Returns a [`ProofError`] if proving fails.
|
||||||
|
pub fn generate_proof(
|
||||||
|
#[cfg(not(target_arch = "wasm32"))] witness_calculator: &Mutex<WitnessCalculator>,
|
||||||
|
#[cfg(target_arch = "wasm32")] witness_calculator: &mut WitnessCalculator,
|
||||||
|
proving_key: &(ProvingKey<Curve>, ConstraintMatrices<Fr>),
|
||||||
|
rln_witness: &RLNWitnessInput,
|
||||||
|
) -> Result<ArkProof<Curve>, ProofError> {
|
||||||
|
let inputs = inputs_for_witness_calculation(rln_witness)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(name, values)| (name.to_string(), values));
|
.map(|(name, values)| (name.to_string(), values));
|
||||||
|
|
||||||
|
@ -420,11 +486,19 @@ pub fn generate_proof(
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
|
||||||
let full_assignment = witness_calculator
|
cfg_if! {
|
||||||
.lock()
|
if #[cfg(target_arch = "wasm32")] {
|
||||||
.expect("witness_calculator mutex should not get poisoned")
|
let full_assignment = witness_calculator
|
||||||
.calculate_witness_element::<Curve, _>(inputs, false)
|
.calculate_witness_element::<Curve, _>(inputs, false)
|
||||||
.map_err(ProofError::WitnessError)?;
|
.map_err(ProofError::WitnessError)?;
|
||||||
|
} else {
|
||||||
|
let full_assignment = witness_calculator
|
||||||
|
.lock()
|
||||||
|
.expect("witness_calculator mutex should not get poisoned")
|
||||||
|
.calculate_witness_element::<Curve, _>(inputs, false)
|
||||||
|
.map_err(ProofError::WitnessError)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
println!("witness generation took: {:.2?}", now.elapsed());
|
println!("witness generation took: {:.2?}", now.elapsed());
|
||||||
|
@ -490,3 +564,32 @@ pub fn verify_proof(
|
||||||
|
|
||||||
Ok(verified)
|
Ok(verified)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get CIRCOM JSON inputs
|
||||||
|
///
|
||||||
|
/// Returns a JSON object containing the inputs necessary to calculate
|
||||||
|
/// the witness with CIRCOM on javascript
|
||||||
|
pub fn get_json_inputs(rln_witness: &RLNWitnessInput) -> serde_json::Value {
|
||||||
|
let mut path_elements = Vec::new();
|
||||||
|
rln_witness
|
||||||
|
.path_elements
|
||||||
|
.iter()
|
||||||
|
.for_each(|v| path_elements.push(to_bigint(v).to_str_radix(10)));
|
||||||
|
|
||||||
|
let mut identity_path_index = Vec::new();
|
||||||
|
rln_witness
|
||||||
|
.identity_path_index
|
||||||
|
.iter()
|
||||||
|
.for_each(|v| identity_path_index.push(BigInt::from(*v).to_str_radix(10)));
|
||||||
|
|
||||||
|
let inputs = serde_json::json!({
|
||||||
|
"identity_secret": to_bigint(&rln_witness.identity_secret).to_str_radix(10),
|
||||||
|
"path_elements": path_elements,
|
||||||
|
"identity_path_index": identity_path_index,
|
||||||
|
"x": to_bigint(&rln_witness.x).to_str_radix(10),
|
||||||
|
"epoch": format!("0x{:064x}", to_bigint(&rln_witness.epoch)),
|
||||||
|
"rln_identifier": to_bigint(&rln_witness.rln_identifier).to_str_radix(10),
|
||||||
|
});
|
||||||
|
|
||||||
|
inputs
|
||||||
|
}
|
||||||
|
|
|
@ -1,21 +1,28 @@
|
||||||
/// This is the main public API for RLN module. It is used by the FFI, and should be
|
use crate::circuit::{vk_from_raw, zkey_from_raw, Curve, Fr};
|
||||||
/// used by tests etc as well
|
|
||||||
use ark_circom::WitnessCalculator;
|
|
||||||
use ark_groth16::Proof as ArkProof;
|
|
||||||
use ark_groth16::{ProvingKey, VerifyingKey};
|
|
||||||
use ark_relations::r1cs::ConstraintMatrices;
|
|
||||||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
|
||||||
use std::default::Default;
|
|
||||||
use std::io::{self, Cursor, Read, Result, Write};
|
|
||||||
use std::sync::Mutex;
|
|
||||||
|
|
||||||
use crate::circuit::{
|
|
||||||
circom_from_folder, circom_from_raw, vk_from_folder, vk_from_raw, zkey_from_folder,
|
|
||||||
zkey_from_raw, Curve, Fr, TEST_RESOURCES_FOLDER, TEST_TREE_HEIGHT,
|
|
||||||
};
|
|
||||||
use crate::poseidon_tree::PoseidonTree;
|
use crate::poseidon_tree::PoseidonTree;
|
||||||
use crate::protocol::*;
|
use crate::protocol::*;
|
||||||
use crate::utils::*;
|
use crate::utils::*;
|
||||||
|
/// This is the main public API for RLN module. It is used by the FFI, and should be
|
||||||
|
/// used by tests etc as well
|
||||||
|
use ark_groth16::Proof as ArkProof;
|
||||||
|
use ark_groth16::{ProvingKey, VerifyingKey};
|
||||||
|
use ark_relations::r1cs::ConstraintMatrices;
|
||||||
|
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, Write};
|
||||||
|
use cfg_if::cfg_if;
|
||||||
|
use num_bigint::BigInt;
|
||||||
|
use std::io::Cursor;
|
||||||
|
use std::io::{self, Result};
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(not(target_arch = "wasm32"))] {
|
||||||
|
use std::default::Default;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
use crate::circuit::{circom_from_folder, vk_from_folder, circom_from_raw, zkey_from_folder, TEST_RESOURCES_FOLDER, TEST_TREE_HEIGHT};
|
||||||
|
use ark_circom::WitnessCalculator;
|
||||||
|
} else {
|
||||||
|
use std::marker::*;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Application specific RLN identifier
|
// Application specific RLN identifier
|
||||||
pub const RLN_IDENTIFIER: &[u8] = b"zerokit/rln/010203040506070809";
|
pub const RLN_IDENTIFIER: &[u8] = b"zerokit/rln/010203040506070809";
|
||||||
|
@ -23,13 +30,21 @@ pub const RLN_IDENTIFIER: &[u8] = b"zerokit/rln/010203040506070809";
|
||||||
// TODO Add Engine here? i.e. <E: Engine> not <Curve>
|
// TODO Add Engine here? i.e. <E: Engine> not <Curve>
|
||||||
// TODO Assuming we want to use IncrementalMerkleTree, figure out type/trait conversions
|
// TODO Assuming we want to use IncrementalMerkleTree, figure out type/trait conversions
|
||||||
pub struct RLN<'a> {
|
pub struct RLN<'a> {
|
||||||
witness_calculator: &'a Mutex<WitnessCalculator>,
|
|
||||||
proving_key: Result<(ProvingKey<Curve>, ConstraintMatrices<Fr>)>,
|
proving_key: Result<(ProvingKey<Curve>, ConstraintMatrices<Fr>)>,
|
||||||
verification_key: Result<VerifyingKey<Curve>>,
|
verification_key: Result<VerifyingKey<Curve>>,
|
||||||
tree: PoseidonTree,
|
tree: PoseidonTree,
|
||||||
|
|
||||||
|
// The witness calculator can't be loaded in zerokit. Since this struct
|
||||||
|
// contains a lifetime, a PhantomData is necessary to avoid a compiler
|
||||||
|
// error since the lifetime is not being used
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
witness_calculator: &'a Mutex<WitnessCalculator>,
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
_marker: PhantomData<&'a ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RLN<'_> {
|
impl RLN<'_> {
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub fn new<R: Read>(tree_height: usize, mut input_data: R) -> RLN<'static> {
|
pub fn new<R: Read>(tree_height: usize, mut input_data: R) -> RLN<'static> {
|
||||||
// We read input
|
// We read input
|
||||||
let mut input: Vec<u8> = Vec::new();
|
let mut input: Vec<u8> = Vec::new();
|
||||||
|
@ -50,23 +65,18 @@ impl RLN<'_> {
|
||||||
proving_key,
|
proving_key,
|
||||||
verification_key,
|
verification_key,
|
||||||
tree,
|
tree,
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_params<R: Read>(
|
pub fn new_with_params(
|
||||||
tree_height: usize,
|
tree_height: usize,
|
||||||
mut circom_data: R,
|
#[cfg(not(target_arch = "wasm32"))] circom_vec: Vec<u8>,
|
||||||
mut zkey_data: R,
|
zkey_vec: Vec<u8>,
|
||||||
mut vk_data: R,
|
vk_vec: Vec<u8>,
|
||||||
) -> RLN<'static> {
|
) -> RLN<'static> {
|
||||||
// We read input
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
let mut circom_vec: Vec<u8> = Vec::new();
|
|
||||||
circom_data.read_to_end(&mut circom_vec).unwrap();
|
|
||||||
let mut zkey_vec: Vec<u8> = Vec::new();
|
|
||||||
zkey_data.read_to_end(&mut zkey_vec).unwrap();
|
|
||||||
let mut vk_vec: Vec<u8> = Vec::new();
|
|
||||||
vk_data.read_to_end(&mut vk_vec).unwrap();
|
|
||||||
|
|
||||||
let witness_calculator = circom_from_raw(circom_vec);
|
let witness_calculator = circom_from_raw(circom_vec);
|
||||||
|
|
||||||
let proving_key = zkey_from_raw(&zkey_vec);
|
let proving_key = zkey_from_raw(&zkey_vec);
|
||||||
|
@ -76,10 +86,13 @@ impl RLN<'_> {
|
||||||
let tree = PoseidonTree::default(tree_height);
|
let tree = PoseidonTree::default(tree_height);
|
||||||
|
|
||||||
RLN {
|
RLN {
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
witness_calculator,
|
witness_calculator,
|
||||||
proving_key,
|
proving_key,
|
||||||
verification_key,
|
verification_key,
|
||||||
tree,
|
tree,
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
_marker: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,6 +178,7 @@ impl RLN<'_> {
|
||||||
////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
// zkSNARK APIs
|
// zkSNARK APIs
|
||||||
////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub fn prove<R: Read, W: Write>(
|
pub fn prove<R: Read, W: Write>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut input_data: R,
|
mut input_data: R,
|
||||||
|
@ -182,7 +196,7 @@ impl RLN<'_> {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
let proof = generate_proof(
|
let proof = generate_proof(
|
||||||
self.witness_calculator,
|
&mut self.witness_calculator,
|
||||||
self.proving_key.as_ref().unwrap(),
|
self.proving_key.as_ref().unwrap(),
|
||||||
&rln_witness,
|
&rln_witness,
|
||||||
)
|
)
|
||||||
|
@ -213,9 +227,29 @@ impl RLN<'_> {
|
||||||
Ok(verified)
|
Ok(verified)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the serialized rln_witness for some input
|
||||||
|
pub fn get_serialized_rln_witness<R: Read>(&mut self, mut input_data: R) -> Vec<u8> {
|
||||||
|
// We read input RLN witness and we deserialize it
|
||||||
|
let mut witness_byte: Vec<u8> = Vec::new();
|
||||||
|
input_data.read_to_end(&mut witness_byte).unwrap();
|
||||||
|
let (rln_witness, _) = proof_inputs_to_rln_witness(&mut self.tree, &witness_byte);
|
||||||
|
|
||||||
|
serialize_witness(&rln_witness)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get JSON inputs for serialized RLN witness
|
||||||
|
pub fn get_rln_witness_json(
|
||||||
|
&mut self,
|
||||||
|
serialized_witness: &[u8],
|
||||||
|
) -> io::Result<serde_json::Value> {
|
||||||
|
let (rln_witness, _) = deserialize_witness(serialized_witness);
|
||||||
|
Ok(get_json_inputs(&rln_witness))
|
||||||
|
}
|
||||||
|
|
||||||
// This API keeps partial compatibility with kilic's rln public API https://github.com/kilic/rln/blob/7ac74183f8b69b399e3bc96c1ae8ab61c026dc43/src/public.rs#L148
|
// This API keeps partial compatibility with kilic's rln public API https://github.com/kilic/rln/blob/7ac74183f8b69b399e3bc96c1ae8ab61c026dc43/src/public.rs#L148
|
||||||
// input_data is [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
// input_data is [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||||
// output_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> ]
|
// output_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> ]
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
pub fn generate_rln_proof<R: Read, W: Write>(
|
pub fn generate_rln_proof<R: Read, W: Write>(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut input_data: R,
|
mut input_data: R,
|
||||||
|
@ -242,6 +276,29 @@ impl RLN<'_> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generate RLN Proof using a witness calculated from outside zerokit
|
||||||
|
///
|
||||||
|
/// output_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> ]
|
||||||
|
pub fn generate_rln_proof_with_witness<W: Write>(
|
||||||
|
&mut self,
|
||||||
|
calculated_witness: Vec<BigInt>,
|
||||||
|
rln_witness_vec: Vec<u8>,
|
||||||
|
mut output_data: W,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
let (rln_witness, _) = deserialize_witness(&rln_witness_vec[..]);
|
||||||
|
let proof_values = proof_values_from_witness(&rln_witness);
|
||||||
|
|
||||||
|
let proof =
|
||||||
|
generate_proof_with_witness(calculated_witness, self.proving_key.as_ref().unwrap())
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Note: we export a serialization of ark-groth16::Proof not semaphore::Proof
|
||||||
|
// This proof is compressed, i.e. 128 bytes long
|
||||||
|
proof.serialize(&mut output_data).unwrap();
|
||||||
|
output_data.write_all(&serialize_proof_values(&proof_values))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// Input data is serialized for Curve as:
|
// Input data is serialized for Curve as:
|
||||||
// [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> | signal_len<8> | signal<var> ]
|
// [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> | signal_len<8> | signal<var> ]
|
||||||
pub fn verify_rln_proof<R: Read>(&self, mut input_data: R) -> io::Result<bool> {
|
pub fn verify_rln_proof<R: Read>(&self, mut input_data: R) -> io::Result<bool> {
|
||||||
|
@ -253,10 +310,8 @@ impl RLN<'_> {
|
||||||
let (proof_values, read) = deserialize_proof_values(&serialized[all_read..].to_vec());
|
let (proof_values, read) = deserialize_proof_values(&serialized[all_read..].to_vec());
|
||||||
all_read += read;
|
all_read += read;
|
||||||
|
|
||||||
let signal_len = usize::try_from(u64::from_le_bytes(
|
let signal_len =
|
||||||
serialized[all_read..all_read + 8].try_into().unwrap(),
|
u64::from_le_bytes(serialized[all_read..all_read + 8].try_into().unwrap()) as usize;
|
||||||
))
|
|
||||||
.unwrap();
|
|
||||||
all_read += 8;
|
all_read += 8;
|
||||||
|
|
||||||
let signal: Vec<u8> = serialized[all_read..all_read + signal_len].to_vec();
|
let signal: Vec<u8> = serialized[all_read..all_read + signal_len].to_vec();
|
||||||
|
@ -299,6 +354,7 @@ impl RLN<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
impl Default for RLN<'_> {
|
impl Default for RLN<'_> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let tree_height = TEST_TREE_HEIGHT;
|
let tree_height = TEST_TREE_HEIGHT;
|
||||||
|
@ -673,6 +729,101 @@ mod test {
|
||||||
assert!(verified);
|
assert!(verified);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rln_with_witness() {
|
||||||
|
let tree_height = TEST_TREE_HEIGHT;
|
||||||
|
let no_of_leaves = 256;
|
||||||
|
|
||||||
|
// We generate a vector of random leaves
|
||||||
|
let mut leaves: Vec<Fr> = Vec::new();
|
||||||
|
let mut rng = thread_rng();
|
||||||
|
for _ in 0..no_of_leaves {
|
||||||
|
leaves.push(Fr::rand(&mut rng));
|
||||||
|
}
|
||||||
|
|
||||||
|
// We create a new RLN instance
|
||||||
|
let input_buffer = Cursor::new(TEST_RESOURCES_FOLDER);
|
||||||
|
let mut rln = RLN::new(tree_height, input_buffer);
|
||||||
|
|
||||||
|
// We add leaves in a batch into the tree
|
||||||
|
let mut buffer = Cursor::new(vec_fr_to_bytes_le(&leaves));
|
||||||
|
rln.set_leaves(&mut buffer).unwrap();
|
||||||
|
|
||||||
|
// Generate identity pair
|
||||||
|
let (identity_secret, id_commitment) = keygen();
|
||||||
|
|
||||||
|
// We set as leaf id_commitment after storing its index
|
||||||
|
let identity_index = u64::try_from(rln.tree.leaves_set()).unwrap();
|
||||||
|
let mut buffer = Cursor::new(fr_to_bytes_le(&id_commitment));
|
||||||
|
rln.set_next_leaf(&mut buffer).unwrap();
|
||||||
|
|
||||||
|
// We generate a random signal
|
||||||
|
let mut rng = rand::thread_rng();
|
||||||
|
let signal: [u8; 32] = rng.gen();
|
||||||
|
let signal_len = u64::try_from(signal.len()).unwrap();
|
||||||
|
|
||||||
|
// We generate a random epoch
|
||||||
|
let epoch = hash_to_field(b"test-epoch");
|
||||||
|
|
||||||
|
// We prepare input for generate_rln_proof API
|
||||||
|
// input_data is [ id_key<32> | id_index<8> | epoch<32> | signal_len<8> | signal<var> ]
|
||||||
|
let mut serialized: Vec<u8> = Vec::new();
|
||||||
|
serialized.append(&mut fr_to_bytes_le(&identity_secret));
|
||||||
|
serialized.append(&mut identity_index.to_le_bytes().to_vec());
|
||||||
|
serialized.append(&mut fr_to_bytes_le(&epoch));
|
||||||
|
serialized.append(&mut signal_len.to_le_bytes().to_vec());
|
||||||
|
serialized.append(&mut signal.to_vec());
|
||||||
|
|
||||||
|
let mut input_buffer = Cursor::new(serialized);
|
||||||
|
|
||||||
|
// We read input RLN witness and we deserialize it
|
||||||
|
let mut witness_byte: Vec<u8> = Vec::new();
|
||||||
|
input_buffer.read_to_end(&mut witness_byte).unwrap();
|
||||||
|
let (rln_witness, _) = proof_inputs_to_rln_witness(&mut rln.tree, &witness_byte);
|
||||||
|
|
||||||
|
let serialized_witness = serialize_witness(&rln_witness);
|
||||||
|
|
||||||
|
// Calculate witness outside zerokit (simulating what JS is doing)
|
||||||
|
let inputs = inputs_for_witness_calculation(&rln_witness)
|
||||||
|
.into_iter()
|
||||||
|
.map(|(name, values)| (name.to_string(), values));
|
||||||
|
let calculated_witness = rln
|
||||||
|
.witness_calculator
|
||||||
|
.lock()
|
||||||
|
.expect("witness_calculator mutex should not get poisoned")
|
||||||
|
.calculate_witness_element::<Curve, _>(inputs, false)
|
||||||
|
.map_err(ProofError::WitnessError)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let calculated_witness_vec: Vec<BigInt> = calculated_witness
|
||||||
|
.into_iter()
|
||||||
|
.map(|v| to_bigint(&v))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
// Generating the proof
|
||||||
|
let mut output_buffer = Cursor::new(Vec::<u8>::new());
|
||||||
|
rln.generate_rln_proof_with_witness(
|
||||||
|
calculated_witness_vec,
|
||||||
|
serialized_witness,
|
||||||
|
&mut output_buffer,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// output_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> ]
|
||||||
|
let mut proof_data = output_buffer.into_inner();
|
||||||
|
|
||||||
|
// We prepare input for verify_rln_proof API
|
||||||
|
// input_data is [ proof<128> | share_y<32> | nullifier<32> | root<32> | epoch<32> | share_x<32> | rln_identifier<32> | signal_len<8> | signal<var> ]
|
||||||
|
// that is [ proof_data || signal_len<8> | signal<var> ]
|
||||||
|
proof_data.append(&mut signal_len.to_le_bytes().to_vec());
|
||||||
|
proof_data.append(&mut signal.to_vec());
|
||||||
|
|
||||||
|
let mut input_buffer = Cursor::new(proof_data);
|
||||||
|
let verified = rln.verify_rln_proof(&mut input_buffer).unwrap();
|
||||||
|
|
||||||
|
assert!(verified);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hash_to_field() {
|
fn test_hash_to_field() {
|
||||||
let rln = RLN::default();
|
let rln = RLN::default();
|
||||||
|
|
|
@ -85,7 +85,7 @@ pub fn fr_to_bytes_be(input: &Fr) -> Vec<u8> {
|
||||||
pub fn vec_fr_to_bytes_le(input: &[Fr]) -> Vec<u8> {
|
pub fn vec_fr_to_bytes_le(input: &[Fr]) -> Vec<u8> {
|
||||||
let mut bytes: Vec<u8> = Vec::new();
|
let mut bytes: Vec<u8> = Vec::new();
|
||||||
//We store the vector length
|
//We store the vector length
|
||||||
bytes.extend(input.len().to_le_bytes().to_vec());
|
bytes.extend(u64::try_from(input.len()).unwrap().to_le_bytes().to_vec());
|
||||||
// We store each element
|
// We store each element
|
||||||
input.iter().for_each(|el| bytes.extend(fr_to_bytes_le(el)));
|
input.iter().for_each(|el| bytes.extend(fr_to_bytes_le(el)));
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ pub fn vec_fr_to_bytes_le(input: &[Fr]) -> Vec<u8> {
|
||||||
pub fn vec_fr_to_bytes_be(input: &[Fr]) -> Vec<u8> {
|
pub fn vec_fr_to_bytes_be(input: &[Fr]) -> Vec<u8> {
|
||||||
let mut bytes: Vec<u8> = Vec::new();
|
let mut bytes: Vec<u8> = Vec::new();
|
||||||
//We store the vector length
|
//We store the vector length
|
||||||
bytes.extend(input.len().to_be_bytes().to_vec());
|
bytes.extend(u64::try_from(input.len()).unwrap().to_be_bytes().to_vec());
|
||||||
// We store each element
|
// We store each element
|
||||||
input.iter().for_each(|el| bytes.extend(fr_to_bytes_be(el)));
|
input.iter().for_each(|el| bytes.extend(fr_to_bytes_be(el)));
|
||||||
|
|
||||||
|
@ -121,7 +121,7 @@ pub fn vec_u8_to_bytes_be(input: Vec<u8>) -> Vec<u8> {
|
||||||
pub fn bytes_le_to_vec_u8(input: &[u8]) -> (Vec<u8>, usize) {
|
pub fn bytes_le_to_vec_u8(input: &[u8]) -> (Vec<u8>, usize) {
|
||||||
let mut read: usize = 0;
|
let mut read: usize = 0;
|
||||||
|
|
||||||
let len = usize::try_from(u64::from_le_bytes(input[0..8].try_into().unwrap())).unwrap();
|
let len = u64::from_le_bytes(input[0..8].try_into().unwrap()) as usize;
|
||||||
read += 8;
|
read += 8;
|
||||||
|
|
||||||
let res = input[8..8 + len].to_vec();
|
let res = input[8..8 + len].to_vec();
|
||||||
|
@ -133,7 +133,7 @@ pub fn bytes_le_to_vec_u8(input: &[u8]) -> (Vec<u8>, usize) {
|
||||||
pub fn bytes_be_to_vec_u8(input: &[u8]) -> (Vec<u8>, usize) {
|
pub fn bytes_be_to_vec_u8(input: &[u8]) -> (Vec<u8>, usize) {
|
||||||
let mut read: usize = 0;
|
let mut read: usize = 0;
|
||||||
|
|
||||||
let len = usize::try_from(u64::from_be_bytes(input[0..8].try_into().unwrap())).unwrap();
|
let len = u64::from_be_bytes(input[0..8].try_into().unwrap()) as usize;
|
||||||
read += 8;
|
read += 8;
|
||||||
|
|
||||||
let res = input[8..8 + len].to_vec();
|
let res = input[8..8 + len].to_vec();
|
||||||
|
@ -147,7 +147,7 @@ pub fn bytes_le_to_vec_fr(input: &[u8]) -> (Vec<Fr>, usize) {
|
||||||
let mut read: usize = 0;
|
let mut read: usize = 0;
|
||||||
let mut res: Vec<Fr> = Vec::new();
|
let mut res: Vec<Fr> = Vec::new();
|
||||||
|
|
||||||
let len = usize::try_from(u64::from_le_bytes(input[0..8].try_into().unwrap())).unwrap();
|
let len = u64::from_le_bytes(input[0..8].try_into().unwrap()) as usize;
|
||||||
read += 8;
|
read += 8;
|
||||||
|
|
||||||
let el_size = fr_byte_size();
|
let el_size = fr_byte_size();
|
||||||
|
@ -164,7 +164,7 @@ pub fn bytes_be_to_vec_fr(input: &[u8]) -> (Vec<Fr>, usize) {
|
||||||
let mut read: usize = 0;
|
let mut read: usize = 0;
|
||||||
let mut res: Vec<Fr> = Vec::new();
|
let mut res: Vec<Fr> = Vec::new();
|
||||||
|
|
||||||
let len = usize::try_from(u64::from_be_bytes(input[0..8].try_into().unwrap())).unwrap();
|
let len = u64::from_be_bytes(input[0..8].try_into().unwrap()) as usize;
|
||||||
read += 8;
|
read += 8;
|
||||||
|
|
||||||
let el_size = fr_byte_size();
|
let el_size = fr_byte_size();
|
||||||
|
|
Loading…
Reference in New Issue