fix mp-psi package (#4)

* fix BFV params

* unite convert functions

* add support for arbitrary bit vector size

* chore: `mp-psi` bump `0.1.7`

* chore: `mp-psi` bump `0.1.8`

update readme of the `pkg`

* chore: bump `0.1.9`

Minor readme fixes

* chore: add runtime performance benches

* chore: code polishing

* chore: update wasm bidnings

* feat: add `bandwidth_benches` (partial)

* chore: update benches

* fix: minor

* chore: minor fix

* chore: add API documentation

* chore: update benches

* chore: update readme

---------

Co-authored-by: Janmajaya Mall <janmajayamall@protonmail.com>
This commit is contained in:
enrico.eth
2024-01-23 17:56:44 +01:00
committed by GitHub
parent 19efa25c2a
commit e6e8dbab6f
12 changed files with 948 additions and 1045 deletions

4
Cargo.lock generated
View File

@@ -32,7 +32,7 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bfv"
version = "0.1.0"
source = "git+https://github.com/Janmajayamall/bfv.git?branch=wasm#55181279cf5701d9706a92cb87f345573e8f9af4"
source = "git+https://github.com/Janmajayamall/bfv.git?branch=wasm#0bc0446cfcd4902732f6b20e71dda12d15d7c9e8"
dependencies = [
"concrete-ntt",
"crypto-bigint",
@@ -757,7 +757,7 @@ dependencies = [
[[package]]
name = "traits"
version = "0.1.0"
source = "git+https://github.com/Janmajayamall/bfv.git?branch=wasm#55181279cf5701d9706a92cb87f345573e8f9af4"
source = "git+https://github.com/Janmajayamall/bfv.git?branch=wasm#0bc0446cfcd4902732f6b20e71dda12d15d7c9e8"
[[package]]
name = "typetag"

View File

@@ -7,10 +7,11 @@ The library contains the following components:
### Build
The rust library is used to build the JS-TS-WASM package using `wasm-pack` [guide](https://developer.mozilla.org/en-US/docs/WebAssembly/Rust_to_Wasm)
The rust library is used to build the JS-TS-WASM package using `wasm-pack` targeting `web` [guide](https://developer.mozilla.org/en-US/docs/WebAssembly/Rust_to_Wasm). When compiling to `web` the output can natively be included on a web page, and doesn't require any further postprocessing. The output is included as an ES module. For more information check [`wasm-bindgen` guide](https://rustwasm.github.io/docs/wasm-bindgen/reference/deployment.html)
```bash
wasm-pack build --target nodejs
wasm-pack build --target web
```
### Test
@@ -18,5 +19,5 @@ wasm-pack build --target nodejs
To test the rust library, run:
```bash
cargo test
cargo test --release
```

21
pkg/LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Gaussian
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,37 +1,146 @@
# MP-PSI
The package contains the APIs to build a multi party private set intersection application.
The package contains the APIs to build a multi party private set intersection (MP-PSI) web-app. Note that the APIs are compiled specifically for web browser environments and are not compatible with a node environment.
PSI stands for Private Set Intersection. It allows two parties to compute the intersection of their sets without revealing anything else about their sets.
[BFV](https://inferati.azureedge.net/docs/inferati-fhe-bfv.pdf) is a fully homomorphic encryption scheme. It allows to perform addition and multiplication on encrypted data. The PSI protocol made available in this library uses the BFV scheme to perform the encryption of the sets, compute the intersection and decrypt the result. In particular, the multiparty protocol is based on the paper [Mouchet, Christian, et al. "Multiparty homomorphic encryption from ring-learning-with-errors."](https://eprint.iacr.org/2020/304.pdf).
### Install
## Security Notice
Install the `mp-psi` package with npm:
This is a research project and is not meant to be used in production. The code has not been audited.
```bash
npm i mp-psi
```
or yarn:
```bash
yarn add mp-psi
```
### Usage
## Usage in web-app
```js
import { state0_bindgen, state1_bindgen, state2_bindgen, state3_bindgen, state4_bindgen } from "mp-psi";
import init, { state0_bindgen, state1_bindgen, state2_bindgen, state3_bindgen, state4_bindgen } from "./mp_psi.js";
const state0 = state0_bindgen();
const bit_vector_a = [1, 0, 1, 0, 1, 0, 1, 0, 1, 1];
const state1 = state1_bindgen(state0.message_a_to_b, bit_vector_a);
const bit_vector_b = [1, 1, 1, 1, 1, 0, 1, 0, 0, 0];
const state2 = state2_bindgen(state0.private_output_a, state0.public_output_a, state1.message_b_to_a, bit_vector_b);
const state3 = state3_bindgen(state1.private_output_b, state1.public_output_b, state2.message_a_to_b);
const psi_output_a = state4_bindgen(state2.public_output_a, state3.message_b_to_a);
const psi_output_b = state3.psi_output;
init().then(() => {
const state0 = state0_bindgen();
const bit_vector_b = [1, 0, 1, 0, 1, 0, 1, 0, 1, 1];
const state1 = state1_bindgen(state0.message_a_to_b, bit_vector_b);
const bit_vector_a = [1, 1, 1, 1, 1, 0, 1, 0, 0, 0];
const state2 = state2_bindgen(state0.private_output_a, state0.public_output_a, state1.message_b_to_a, bit_vector_a);
const state3 = state3_bindgen(state1.private_output_b, state1.public_output_b, state2.message_a_to_b);
const psi_output_a = state4_bindgen(state2.public_output_a, state3.message_b_to_a);
const psi_output_b = state3.psi_output;
});
```
The `mp_psi.js` can natively be included on a web page as an ES module. An example of the usage is include in the `index.html` file.
You can test it by:
- Cloning the repo
- Serving the `pkg` directory with a local web server, (e.g. `python3 -m http.server`)
- Visit `http://localhost:8000` in your browser
- Open the console. It will show you the result of the PSI protocol.
### `state0_bindgen()`
Called by party A. Generates the public key share of A starting from a newly generated secret key. Generates the round 1 relinearization key share of A starting from a newly generated ephermeral key.
Returns:
- `message_a_to_b`: message to be sent from A to B after round 0. Contains the public key share `share_pk_a` and the round 1 relinearization key share `share_rlk_a_round1`.
- `private_output_a`: private output of A after round 0. It has to be privately stored by A. Contains the secret key `s_pk_a` behind the public key share and the ephemeral key `s_rlk_a` behind the round 1 relinearization key share.
- `public_output_a`: public output of A after round 0. It has to be stored by A (not necessarily privately). Contains the public key share `share_pk_a` and the round 1 relinearization key share `share_rlk_a_round1`.
```js
const state0 = state0_bindgen();
const {message_a_to_b, private_output_a, public_output_a} = state0;
```
### `state1_bindgen(message_a_to_b, bit_vector_b)`
Called by party B after receiving `message_a_to_b` from A. Takes as input `message_a_to_b` and the plaintext bit vector of B. This is the bit vector that B wants to find the intersection with the bit vector of A. Generates the public key share of B starting from a newly generated secret key. Generates the round 1 relinearization key share of B starting from a newly generated ephermeral key. Aggregates the received round 1 relinearization key share of A, and their own round 1 relinearization key share to generate the round 2 relinearization key share of B. Aggregates the received public key share of A and their own generated public key share to generate the collective public key used for encryption. Encrypts the bit vector of B using the collective public key.
Returns:
- `message_b_to_a`: message to be sent from B to A after round 1. Contains the public key share `share_pk_b`, the round 1 relinearization key share `share_rlk_b_round1`, the round 2 relinearization key share `share_rlk_b_round2` and the encrypted bit vector `ciphertexts_b`.
- `private_output_b`: private output of B after round 1. It has to be privately stored by B. Contains the secret key `s_pk_b` behind the public key share.
- `public_output_b`: public output of B after round 1. It has to be stored by B (not necessarily privately). Contains the encrypted bit vector `ciphertexts_b`, the round 2 relinearization key share `share_rlk_b_round2` and the round 1 aggregate relinearization key share `rlk_agg_round1_h1s`.
```js
const state1 = state1_bindgen(state0.message_a_to_b, bit_vector_b);
const {message_b_to_a, private_output_b, public_output_b} = state1;
```
### `state2_bindgen(private_output_a_state0, public_output_a_state0, message_b_to_a, bit_vector_a)`
Called by party A after receiving `message_b_to_a` from B. Takes as input `private_output_a_state0` and `public_output_a_state0` stored by A from state 0, `message_b_to_a` from state 1 and the plaintext bit vector of A. This is the bit vector that A wants to find the intersection with the bit vector of B. Aggregates the received round 1 relinearization key share of B, and their own round 1 relinearization key share to generate the round 2 relinearization key share of A. Aggregates the received round 2 relinearization key share of B, and their own round 2 relinearization key share to generate the collective relinearization key. Aggregates the received public key share of B and their own generated public key share to generate the collective public key used for encryption. Encrypts the bit vector of A using the collective public key. Performs Private Set Intersection (PSI) on the encrypted bit vectors of A and B to get a new ciphertext. The collective relinearization key is used to reduce the size of the ciphertext. Perform partial decryption of the ciphertext (result of the PSI) using their own secret key.
Returns:
- `message_a_to_b`: message to be sent from A to B after round 2. Contains the partial decryption of the ciphertext (result of the PSI) `decryption_shares_a`, the encrypted bit vector `ciphertexts_a` and the round 2 relinearization key share `share_rlk_a_round2`.
- `public_output_a`: public output of A after round 2. It has to be stored by A (not necessarily privately). Contains the partial decryption of the ciphertext (result of the PSI) `decryption_shares_a` and the result of the PSI `ciphertexts_res`
```js
const state2 = state2_bindgen(state0.private_output_a, state0.public_output_a, state1.message_b_to_a, bit_vector_a);
const {message_a_to_b, public_output_a} = state2;
```
### `state3_bindgen(private_output_b_state1, public_output_b_state1, message_a_to_b)`
Called by party B after receiving `message_a_to_b` from A. Takes as input `private_output_b_state1` and `public_output_b_state1` stored by B from state 1 and `message_a_to_b` from state 2. Aggregates the received round 2 relinearization key share of A, and their own round 2 relinearization key share to generate the collective relinearization key. Performs Private Set Intersection (PSI) on the encrypted bit vectors of A and B to get a new ciphertext. The collective relinearization key is used to reduce the size of the ciphertext. Performs partial decryption of the ciphertext (result of the PSI) using their own secret key. Aggregates the partial decryption share of A and their own partial decryption share to fully decrypt the ciphertext and obtain the intersection of the two vectors.
Returns:
- `message_b_to_a`: message to be sent from B to A after round 3. Contains the partial decryption of the ciphertext (result of the PSI) `decryption_shares_b`.
- `psi_output`: the intersection of the bit vectors of A and B.
```js
const state3 = state3_bindgen(state1.private_output_b, state1.public_output_b, state2.message_a_to_b);
const {message_b_to_a, psi_output} = state3;
```
### `state4_bindgen(public_output_a_state2, message_b_to_a)`
Called by party A after receiving `message_b_to_a` from B. Takes as input `public_output_a_state2` stored by A from state 2 and `message_b_to_a` from state 3. Aggregates the partial decryption share of B and their own partial decryption share to fully decrypt the ciphertext and obtain the intersection of the two vectors.
Returns:
- `psi_output`: the intersection of the bit vectors of A and B.
```js
const state4 = state4_bindgen(state2.public_output_a, state3.message_b_to_a);
const psi_output = state4;
```
Note that the `psi_output` returned by `state3_bindgen` and `state4_bindgen` should be the same. It is the intersection of the bit vectors of A and B.
### Benchmarks in web-app
The benchmark relates to a PSI protocol are based on the following `bfv` parameters:
- `ciphertext_moduli`: `[1032193, 1073692673]`
- `extension_moduli` : `[995329, 1073668097]`
- `plaintext_modulus`: `40961`
- `ring_size`: `2048`
The bit vector size, which is the subject of the PSI protocol, is set to `ring_size * 3`
**Runtime**
The benchmarks are run on M2 Macbook Pro with 12 cores and 32GB of RAM. The browser used is Brave v1.61.116 Chromium:120.0.6099.217. The benchmark code is also part of `index.html`.
| Operation | Time (ms) |
| --- | --- |
| state0_bindgen | 13.86 |
| state1_bindgen | 33.25 |
| state2_bindgen | 53.91 |
| state3_bindgen | 38.12 |
| state4_bindgen | 11.44 |
**Communication Bandwidth**
The following benchmarks measure the size in terms of bytes of the output of each state. The benchmark code can be found inside `src/lib.rs` and reproduced by running `cargo test --release -- --nocapture`.
| State | Output | Size in Bytes |
| ------- | ------------------ | ------------- |
| State 0 | `private_output_a` | 1026 |
| State 0 | `public_output_a` | 84495 |
| State 0 | `message_a_to_b` | 84495 |
| State 1 | `private_output_b` | 513 |
| State 1 | `public_output_b` | 144408 |
| State 1 | `message_b_to_a` | 195105 |
| State 2 | `public_output_a` | 115218 |
| State 2 | `message_a_to_b` | 149016 |
| State 3 | `message_b_to_a` | 38406 |
| State 3 | `psi_output_b` | 768 |
| State 4 | `psi_output_a` | 768 |

70
pkg/index.html Normal file
View File

@@ -0,0 +1,70 @@
<!doctype html>
<html lang="en-US">
<head>
<meta charset="utf-8" />
<title>mp-psi example</title>
</head>
<body>
<script type="module">
import init, { state0_bindgen, state1_bindgen, state2_bindgen, state3_bindgen, state4_bindgen } from "./mp_psi.js";
function randomBitVector(hammingWeight, size) {
let bitVector = new Array(size).fill(0);
for (let i = 0; i < hammingWeight; i++) {
let sampleIndex;
do {
sampleIndex = Math.floor(Math.random() * size);
} while (bitVector[sampleIndex] === 1);
bitVector[sampleIndex] = 1;
}
return bitVector;
}
function plainPsi(bitVector0, bitVector1) {
if (bitVector0.length !== bitVector1.length) {
throw new Error("Both bit vectors must be of the same length");
}
return bitVector0.map((element, index) => element * bitVector1[index]);
}
init().then(() => {
console.time('state0 Time');
const state0 = state0_bindgen();
console.timeEnd('state0 Time');
const hammingWeight = 1000;
const size = 2048 * 3;
const bit_vector_b = randomBitVector(hammingWeight, size);
console.time('state1 Time');
const state1 = state1_bindgen(state0.message_a_to_b, bit_vector_b);
console.timeEnd('state1 Time');
const bit_vector_a = randomBitVector(hammingWeight, size);
console.time('state2 Time');
const state2 = state2_bindgen(state0.private_output_a, state0.public_output_a, state1.message_b_to_a, bit_vector_a);
console.timeEnd('state2 Time');
console.time('state3 Time');
const state3 = state3_bindgen(state1.private_output_b, state1.public_output_b, state2.message_a_to_b);
console.timeEnd('state3 Time');
console.time('state4 Time');
const psi_output_a = state4_bindgen(state2.public_output_a, state3.message_b_to_a);
console.timeEnd('state4 Time');
const psi_output_b = state3.psi_output;
console.log("psi_output_a", psi_output_a)
console.log("psi_output_b", psi_output_b)
const expected_psi_output = plainPsi(bit_vector_a, bit_vector_b);
console.log("expected_psi_output", expected_psi_output)
console.log("psi_output", psi_output_a)
});
</script>
</body>
</html>

37
pkg/mp_psi.d.ts vendored
View File

@@ -31,3 +31,40 @@ export function state3_bindgen(private_output_b_state1: any, public_output_b_sta
* @returns {Uint32Array}
*/
export function state4_bindgen(public_output_a_state2: any, message_b_to_a: any): Uint32Array;
export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
export interface InitOutput {
readonly memory: WebAssembly.Memory;
readonly state0_bindgen: () => number;
readonly state1_bindgen: (a: number, b: number, c: number) => number;
readonly state2_bindgen: (a: number, b: number, c: number, d: number, e: number) => number;
readonly state3_bindgen: (a: number, b: number, c: number) => number;
readonly state4_bindgen: (a: number, b: number, c: number) => void;
readonly __wbindgen_malloc: (a: number, b: number) => number;
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
readonly __wbindgen_add_to_stack_pointer: (a: number) => number;
readonly __wbindgen_free: (a: number, b: number, c: number) => void;
readonly __wbindgen_exn_store: (a: number) => void;
}
export type SyncInitInput = BufferSource | WebAssembly.Module;
/**
* Instantiates the given `module`, which can either be bytes or
* a precompiled `WebAssembly.Module`.
*
* @param {SyncInitInput} module
*
* @returns {InitOutput}
*/
export function initSync(module: SyncInitInput): InitOutput;
/**
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
* for everything else, calls `WebAssembly.instantiate` directly.
*
* @param {InitInput | Promise<InitInput>} module_or_path
*
* @returns {Promise<InitOutput>}
*/
export default function __wbg_init (module_or_path?: InitInput | Promise<InitInput>): Promise<InitOutput>;

View File

@@ -1,7 +1,4 @@
let imports = {};
imports['__wbindgen_placeholder__'] = module.exports;
let wasm;
const { TextEncoder, TextDecoder } = require(`util`);
const heap = new Array(128).fill(undefined);
@@ -65,7 +62,7 @@ function getUint8Memory0() {
return cachedUint8Memory0;
}
let cachedTextEncoder = new TextEncoder('utf-8');
const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } );
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
? function (arg, view) {
@@ -118,9 +115,9 @@ function passStringToWasm0(arg, malloc, realloc) {
return ptr;
}
let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } );
cachedTextDecoder.decode();
if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); };
function getStringFromWasm0(ptr, len) {
ptr = ptr >>> 0;
@@ -194,10 +191,10 @@ function debugString(val) {
/**
* @returns {any}
*/
module.exports.state0_bindgen = function() {
export function state0_bindgen() {
const ret = wasm.state0_bindgen();
return takeObject(ret);
};
}
let cachedUint32Memory0 = null;
@@ -219,12 +216,12 @@ function passArray32ToWasm0(arg, malloc) {
* @param {Uint32Array} bit_vector
* @returns {any}
*/
module.exports.state1_bindgen = function(message_a_to_b, bit_vector) {
export function state1_bindgen(message_a_to_b, bit_vector) {
const ptr0 = passArray32ToWasm0(bit_vector, wasm.__wbindgen_malloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.state1_bindgen(addHeapObject(message_a_to_b), ptr0, len0);
return takeObject(ret);
};
}
/**
* @param {any} private_output_a_state0
@@ -233,12 +230,12 @@ module.exports.state1_bindgen = function(message_a_to_b, bit_vector) {
* @param {Uint32Array} bit_vector
* @returns {any}
*/
module.exports.state2_bindgen = function(private_output_a_state0, public_output_a_state0, message_b_to_a, bit_vector) {
export function state2_bindgen(private_output_a_state0, public_output_a_state0, message_b_to_a, bit_vector) {
const ptr0 = passArray32ToWasm0(bit_vector, wasm.__wbindgen_malloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.state2_bindgen(addHeapObject(private_output_a_state0), addHeapObject(public_output_a_state0), addHeapObject(message_b_to_a), ptr0, len0);
return takeObject(ret);
};
}
/**
* @param {any} private_output_b_state1
@@ -246,10 +243,10 @@ module.exports.state2_bindgen = function(private_output_a_state0, public_output_
* @param {any} message_a_to_b
* @returns {any}
*/
module.exports.state3_bindgen = function(private_output_b_state1, public_output_b_state1, message_a_to_b) {
export function state3_bindgen(private_output_b_state1, public_output_b_state1, message_a_to_b) {
const ret = wasm.state3_bindgen(addHeapObject(private_output_b_state1), addHeapObject(public_output_b_state1), addHeapObject(message_a_to_b));
return takeObject(ret);
};
}
function getArrayU32FromWasm0(ptr, len) {
ptr = ptr >>> 0;
@@ -260,7 +257,7 @@ function getArrayU32FromWasm0(ptr, len) {
* @param {any} message_b_to_a
* @returns {Uint32Array}
*/
module.exports.state4_bindgen = function(public_output_a_state2, message_b_to_a) {
export function state4_bindgen(public_output_a_state2, message_b_to_a) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
wasm.state4_bindgen(retptr, addHeapObject(public_output_a_state2), addHeapObject(message_b_to_a));
@@ -272,7 +269,7 @@ module.exports.state4_bindgen = function(public_output_a_state2, message_b_to_a)
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
};
}
function handleError(f, args) {
try {
@@ -282,307 +279,334 @@ function handleError(f, args) {
}
}
module.exports.__wbindgen_object_drop_ref = function(arg0) {
takeObject(arg0);
};
async function __wbg_load(module, imports) {
if (typeof Response === 'function' && module instanceof Response) {
if (typeof WebAssembly.instantiateStreaming === 'function') {
try {
return await WebAssembly.instantiateStreaming(module, imports);
module.exports.__wbindgen_is_object = function(arg0) {
const val = getObject(arg0);
const ret = typeof(val) === 'object' && val !== null;
return ret;
};
} catch (e) {
if (module.headers.get('Content-Type') != 'application/wasm') {
console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e);
module.exports.__wbindgen_is_undefined = function(arg0) {
const ret = getObject(arg0) === undefined;
return ret;
};
} else {
throw e;
}
}
}
module.exports.__wbindgen_in = function(arg0, arg1) {
const ret = getObject(arg0) in getObject(arg1);
return ret;
};
const bytes = await module.arrayBuffer();
return await WebAssembly.instantiate(bytes, imports);
module.exports.__wbindgen_object_clone_ref = function(arg0) {
const ret = getObject(arg0);
return addHeapObject(ret);
};
} else {
const instance = await WebAssembly.instantiate(module, imports);
module.exports.__wbindgen_jsval_loose_eq = function(arg0, arg1) {
const ret = getObject(arg0) == getObject(arg1);
return ret;
};
if (instance instanceof WebAssembly.Instance) {
return { instance, module };
module.exports.__wbindgen_boolean_get = function(arg0) {
const v = getObject(arg0);
const ret = typeof(v) === 'boolean' ? (v ? 1 : 0) : 2;
return ret;
};
module.exports.__wbindgen_number_get = function(arg0, arg1) {
const obj = getObject(arg1);
const ret = typeof(obj) === 'number' ? obj : undefined;
getFloat64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? 0 : ret;
getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret);
};
module.exports.__wbindgen_string_get = function(arg0, arg1) {
const obj = getObject(arg1);
const ret = typeof(obj) === 'string' ? obj : undefined;
var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len1 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
};
module.exports.__wbindgen_error_new = function(arg0, arg1) {
const ret = new Error(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
module.exports.__wbindgen_number_new = function(arg0) {
const ret = arg0;
return addHeapObject(ret);
};
module.exports.__wbindgen_string_new = function(arg0, arg1) {
const ret = getStringFromWasm0(arg0, arg1);
return addHeapObject(ret);
};
module.exports.__wbg_getwithrefkey_15c62c2b8546208d = function(arg0, arg1) {
const ret = getObject(arg0)[getObject(arg1)];
return addHeapObject(ret);
};
module.exports.__wbg_set_20cbc34131e76824 = function(arg0, arg1, arg2) {
getObject(arg0)[takeObject(arg1)] = takeObject(arg2);
};
module.exports.__wbg_crypto_d05b68a3572bb8ca = function(arg0) {
const ret = getObject(arg0).crypto;
return addHeapObject(ret);
};
module.exports.__wbg_process_b02b3570280d0366 = function(arg0) {
const ret = getObject(arg0).process;
return addHeapObject(ret);
};
module.exports.__wbg_versions_c1cb42213cedf0f5 = function(arg0) {
const ret = getObject(arg0).versions;
return addHeapObject(ret);
};
module.exports.__wbg_node_43b1089f407e4ec2 = function(arg0) {
const ret = getObject(arg0).node;
return addHeapObject(ret);
};
module.exports.__wbindgen_is_string = function(arg0) {
const ret = typeof(getObject(arg0)) === 'string';
return ret;
};
module.exports.__wbg_require_9a7e0f667ead4995 = function() { return handleError(function () {
const ret = module.require;
return addHeapObject(ret);
}, arguments) };
module.exports.__wbg_msCrypto_10fc94afee92bd76 = function(arg0) {
const ret = getObject(arg0).msCrypto;
return addHeapObject(ret);
};
module.exports.__wbg_randomFillSync_b70ccbdf4926a99d = function() { return handleError(function (arg0, arg1) {
getObject(arg0).randomFillSync(takeObject(arg1));
}, arguments) };
module.exports.__wbg_getRandomValues_7e42b4fb8779dc6d = function() { return handleError(function (arg0, arg1) {
getObject(arg0).getRandomValues(getObject(arg1));
}, arguments) };
module.exports.__wbg_get_c43534c00f382c8a = function(arg0, arg1) {
const ret = getObject(arg0)[arg1 >>> 0];
return addHeapObject(ret);
};
module.exports.__wbg_length_d99b680fd68bf71b = function(arg0) {
const ret = getObject(arg0).length;
return ret;
};
module.exports.__wbg_new_34c624469fb1d4fd = function() {
const ret = new Array();
return addHeapObject(ret);
};
module.exports.__wbindgen_is_function = function(arg0) {
const ret = typeof(getObject(arg0)) === 'function';
return ret;
};
module.exports.__wbg_newnoargs_5859b6d41c6fe9f7 = function(arg0, arg1) {
const ret = new Function(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
module.exports.__wbg_next_1938cf110c9491d4 = function(arg0) {
const ret = getObject(arg0).next;
return addHeapObject(ret);
};
module.exports.__wbg_next_267398d0e0761bf9 = function() { return handleError(function (arg0) {
const ret = getObject(arg0).next();
return addHeapObject(ret);
}, arguments) };
module.exports.__wbg_done_506b44765ba84b9c = function(arg0) {
const ret = getObject(arg0).done;
return ret;
};
module.exports.__wbg_value_31485d8770eb06ab = function(arg0) {
const ret = getObject(arg0).value;
return addHeapObject(ret);
};
module.exports.__wbg_iterator_364187e1ee96b750 = function() {
const ret = Symbol.iterator;
return addHeapObject(ret);
};
module.exports.__wbg_get_5027b32da70f39b1 = function() { return handleError(function (arg0, arg1) {
const ret = Reflect.get(getObject(arg0), getObject(arg1));
return addHeapObject(ret);
}, arguments) };
module.exports.__wbg_call_a79f1973a4f07d5e = function() { return handleError(function (arg0, arg1) {
const ret = getObject(arg0).call(getObject(arg1));
return addHeapObject(ret);
}, arguments) };
module.exports.__wbg_new_87d841e70661f6e9 = function() {
const ret = new Object();
return addHeapObject(ret);
};
module.exports.__wbg_self_086b5302bcafb962 = function() { return handleError(function () {
const ret = self.self;
return addHeapObject(ret);
}, arguments) };
module.exports.__wbg_window_132fa5d7546f1de5 = function() { return handleError(function () {
const ret = window.window;
return addHeapObject(ret);
}, arguments) };
module.exports.__wbg_globalThis_e5f801a37ad7d07b = function() { return handleError(function () {
const ret = globalThis.globalThis;
return addHeapObject(ret);
}, arguments) };
module.exports.__wbg_global_f9a61fce4af6b7c1 = function() { return handleError(function () {
const ret = global.global;
return addHeapObject(ret);
}, arguments) };
module.exports.__wbg_set_379b27f1d5f1bf9c = function(arg0, arg1, arg2) {
getObject(arg0)[arg1 >>> 0] = takeObject(arg2);
};
module.exports.__wbg_isArray_fbd24d447869b527 = function(arg0) {
const ret = Array.isArray(getObject(arg0));
return ret;
};
module.exports.__wbg_instanceof_ArrayBuffer_f4521cec1b99ee35 = function(arg0) {
let result;
try {
result = getObject(arg0) instanceof ArrayBuffer;
} catch (_) {
result = false;
} else {
return instance;
}
}
const ret = result;
return ret;
};
}
module.exports.__wbg_call_f6a2bc58c19c53c6 = function() { return handleError(function (arg0, arg1, arg2) {
const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));
return addHeapObject(ret);
}, arguments) };
function __wbg_get_imports() {
const imports = {};
imports.wbg = {};
imports.wbg.__wbindgen_object_drop_ref = function(arg0) {
takeObject(arg0);
};
imports.wbg.__wbindgen_is_object = function(arg0) {
const val = getObject(arg0);
const ret = typeof(val) === 'object' && val !== null;
return ret;
};
imports.wbg.__wbindgen_is_undefined = function(arg0) {
const ret = getObject(arg0) === undefined;
return ret;
};
imports.wbg.__wbindgen_in = function(arg0, arg1) {
const ret = getObject(arg0) in getObject(arg1);
return ret;
};
imports.wbg.__wbindgen_object_clone_ref = function(arg0) {
const ret = getObject(arg0);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_jsval_loose_eq = function(arg0, arg1) {
const ret = getObject(arg0) == getObject(arg1);
return ret;
};
imports.wbg.__wbindgen_boolean_get = function(arg0) {
const v = getObject(arg0);
const ret = typeof(v) === 'boolean' ? (v ? 1 : 0) : 2;
return ret;
};
imports.wbg.__wbindgen_number_get = function(arg0, arg1) {
const obj = getObject(arg1);
const ret = typeof(obj) === 'number' ? obj : undefined;
getFloat64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? 0 : ret;
getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret);
};
imports.wbg.__wbindgen_string_get = function(arg0, arg1) {
const obj = getObject(arg1);
const ret = typeof(obj) === 'string' ? obj : undefined;
var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len1 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
};
imports.wbg.__wbindgen_error_new = function(arg0, arg1) {
const ret = new Error(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
imports.wbg.__wbindgen_number_new = function(arg0) {
const ret = arg0;
return addHeapObject(ret);
};
imports.wbg.__wbindgen_string_new = function(arg0, arg1) {
const ret = getStringFromWasm0(arg0, arg1);
return addHeapObject(ret);
};
imports.wbg.__wbg_getwithrefkey_15c62c2b8546208d = function(arg0, arg1) {
const ret = getObject(arg0)[getObject(arg1)];
return addHeapObject(ret);
};
imports.wbg.__wbg_set_20cbc34131e76824 = function(arg0, arg1, arg2) {
getObject(arg0)[takeObject(arg1)] = takeObject(arg2);
};
imports.wbg.__wbg_crypto_d05b68a3572bb8ca = function(arg0) {
const ret = getObject(arg0).crypto;
return addHeapObject(ret);
};
imports.wbg.__wbg_process_b02b3570280d0366 = function(arg0) {
const ret = getObject(arg0).process;
return addHeapObject(ret);
};
imports.wbg.__wbg_versions_c1cb42213cedf0f5 = function(arg0) {
const ret = getObject(arg0).versions;
return addHeapObject(ret);
};
imports.wbg.__wbg_node_43b1089f407e4ec2 = function(arg0) {
const ret = getObject(arg0).node;
return addHeapObject(ret);
};
imports.wbg.__wbindgen_is_string = function(arg0) {
const ret = typeof(getObject(arg0)) === 'string';
return ret;
};
imports.wbg.__wbg_require_9a7e0f667ead4995 = function() { return handleError(function () {
const ret = module.require;
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_msCrypto_10fc94afee92bd76 = function(arg0) {
const ret = getObject(arg0).msCrypto;
return addHeapObject(ret);
};
imports.wbg.__wbg_randomFillSync_b70ccbdf4926a99d = function() { return handleError(function (arg0, arg1) {
getObject(arg0).randomFillSync(takeObject(arg1));
}, arguments) };
imports.wbg.__wbg_getRandomValues_7e42b4fb8779dc6d = function() { return handleError(function (arg0, arg1) {
getObject(arg0).getRandomValues(getObject(arg1));
}, arguments) };
imports.wbg.__wbg_get_c43534c00f382c8a = function(arg0, arg1) {
const ret = getObject(arg0)[arg1 >>> 0];
return addHeapObject(ret);
};
imports.wbg.__wbg_length_d99b680fd68bf71b = function(arg0) {
const ret = getObject(arg0).length;
return ret;
};
imports.wbg.__wbg_new_34c624469fb1d4fd = function() {
const ret = new Array();
return addHeapObject(ret);
};
imports.wbg.__wbindgen_is_function = function(arg0) {
const ret = typeof(getObject(arg0)) === 'function';
return ret;
};
imports.wbg.__wbg_newnoargs_5859b6d41c6fe9f7 = function(arg0, arg1) {
const ret = new Function(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
imports.wbg.__wbg_next_1938cf110c9491d4 = function(arg0) {
const ret = getObject(arg0).next;
return addHeapObject(ret);
};
imports.wbg.__wbg_next_267398d0e0761bf9 = function() { return handleError(function (arg0) {
const ret = getObject(arg0).next();
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_done_506b44765ba84b9c = function(arg0) {
const ret = getObject(arg0).done;
return ret;
};
imports.wbg.__wbg_value_31485d8770eb06ab = function(arg0) {
const ret = getObject(arg0).value;
return addHeapObject(ret);
};
imports.wbg.__wbg_iterator_364187e1ee96b750 = function() {
const ret = Symbol.iterator;
return addHeapObject(ret);
};
imports.wbg.__wbg_get_5027b32da70f39b1 = function() { return handleError(function (arg0, arg1) {
const ret = Reflect.get(getObject(arg0), getObject(arg1));
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_call_a79f1973a4f07d5e = function() { return handleError(function (arg0, arg1) {
const ret = getObject(arg0).call(getObject(arg1));
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_new_87d841e70661f6e9 = function() {
const ret = new Object();
return addHeapObject(ret);
};
imports.wbg.__wbg_self_086b5302bcafb962 = function() { return handleError(function () {
const ret = self.self;
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_window_132fa5d7546f1de5 = function() { return handleError(function () {
const ret = window.window;
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_globalThis_e5f801a37ad7d07b = function() { return handleError(function () {
const ret = globalThis.globalThis;
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_global_f9a61fce4af6b7c1 = function() { return handleError(function () {
const ret = global.global;
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_set_379b27f1d5f1bf9c = function(arg0, arg1, arg2) {
getObject(arg0)[arg1 >>> 0] = takeObject(arg2);
};
imports.wbg.__wbg_isArray_fbd24d447869b527 = function(arg0) {
const ret = Array.isArray(getObject(arg0));
return ret;
};
imports.wbg.__wbg_instanceof_ArrayBuffer_f4521cec1b99ee35 = function(arg0) {
let result;
try {
result = getObject(arg0) instanceof ArrayBuffer;
} catch (_) {
result = false;
}
const ret = result;
return ret;
};
imports.wbg.__wbg_call_f6a2bc58c19c53c6 = function() { return handleError(function (arg0, arg1, arg2) {
const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));
return addHeapObject(ret);
}, arguments) };
imports.wbg.__wbg_isSafeInteger_d8c89788832a17bf = function(arg0) {
const ret = Number.isSafeInteger(getObject(arg0));
return ret;
};
imports.wbg.__wbg_buffer_5d1b598a01b41a42 = function(arg0) {
const ret = getObject(arg0).buffer;
return addHeapObject(ret);
};
imports.wbg.__wbg_newwithbyteoffsetandlength_d695c7957788f922 = function(arg0, arg1, arg2) {
const ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0);
return addHeapObject(ret);
};
imports.wbg.__wbg_new_ace717933ad7117f = function(arg0) {
const ret = new Uint8Array(getObject(arg0));
return addHeapObject(ret);
};
imports.wbg.__wbg_set_74906aa30864df5a = function(arg0, arg1, arg2) {
getObject(arg0).set(getObject(arg1), arg2 >>> 0);
};
imports.wbg.__wbg_length_f0764416ba5bb237 = function(arg0) {
const ret = getObject(arg0).length;
return ret;
};
imports.wbg.__wbg_instanceof_Uint8Array_4f5cffed7df34b2f = function(arg0) {
let result;
try {
result = getObject(arg0) instanceof Uint8Array;
} catch (_) {
result = false;
}
const ret = result;
return ret;
};
imports.wbg.__wbg_newwithlength_728575f3bba9959b = function(arg0) {
const ret = new Uint8Array(arg0 >>> 0);
return addHeapObject(ret);
};
imports.wbg.__wbg_subarray_7f7a652672800851 = function(arg0, arg1, arg2) {
const ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0);
return addHeapObject(ret);
};
imports.wbg.__wbindgen_debug_string = function(arg0, arg1) {
const ret = debugString(getObject(arg1));
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
};
imports.wbg.__wbindgen_throw = function(arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1));
};
imports.wbg.__wbindgen_memory = function() {
const ret = wasm.memory;
return addHeapObject(ret);
};
module.exports.__wbg_isSafeInteger_d8c89788832a17bf = function(arg0) {
const ret = Number.isSafeInteger(getObject(arg0));
return ret;
};
return imports;
}
module.exports.__wbg_buffer_5d1b598a01b41a42 = function(arg0) {
const ret = getObject(arg0).buffer;
return addHeapObject(ret);
};
function __wbg_init_memory(imports, maybe_memory) {
module.exports.__wbg_newwithbyteoffsetandlength_d695c7957788f922 = function(arg0, arg1, arg2) {
const ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0);
return addHeapObject(ret);
};
}
module.exports.__wbg_new_ace717933ad7117f = function(arg0) {
const ret = new Uint8Array(getObject(arg0));
return addHeapObject(ret);
};
function __wbg_finalize_init(instance, module) {
wasm = instance.exports;
__wbg_init.__wbindgen_wasm_module = module;
cachedFloat64Memory0 = null;
cachedInt32Memory0 = null;
cachedUint32Memory0 = null;
cachedUint8Memory0 = null;
module.exports.__wbg_set_74906aa30864df5a = function(arg0, arg1, arg2) {
getObject(arg0).set(getObject(arg1), arg2 >>> 0);
};
module.exports.__wbg_length_f0764416ba5bb237 = function(arg0) {
const ret = getObject(arg0).length;
return ret;
};
return wasm;
}
module.exports.__wbg_instanceof_Uint8Array_4f5cffed7df34b2f = function(arg0) {
let result;
try {
result = getObject(arg0) instanceof Uint8Array;
} catch (_) {
result = false;
function initSync(module) {
if (wasm !== undefined) return wasm;
const imports = __wbg_get_imports();
__wbg_init_memory(imports);
if (!(module instanceof WebAssembly.Module)) {
module = new WebAssembly.Module(module);
}
const ret = result;
return ret;
};
module.exports.__wbg_newwithlength_728575f3bba9959b = function(arg0) {
const ret = new Uint8Array(arg0 >>> 0);
return addHeapObject(ret);
};
const instance = new WebAssembly.Instance(module, imports);
module.exports.__wbg_subarray_7f7a652672800851 = function(arg0, arg1, arg2) {
const ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0);
return addHeapObject(ret);
};
return __wbg_finalize_init(instance, module);
}
module.exports.__wbindgen_debug_string = function(arg0, arg1) {
const ret = debugString(getObject(arg1));
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
};
async function __wbg_init(input) {
if (wasm !== undefined) return wasm;
module.exports.__wbindgen_throw = function(arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1));
};
if (typeof input === 'undefined') {
input = new URL('mp_psi_bg.wasm', import.meta.url);
}
const imports = __wbg_get_imports();
module.exports.__wbindgen_memory = function() {
const ret = wasm.memory;
return addHeapObject(ret);
};
if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) {
input = fetch(input);
}
const path = require('path').join(__dirname, 'mp_psi_bg.wasm');
const bytes = require('fs').readFileSync(path);
__wbg_init_memory(imports);
const wasmModule = new WebAssembly.Module(bytes);
const wasmInstance = new WebAssembly.Instance(wasmModule, imports);
wasm = wasmInstance.exports;
module.exports.__wasm = wasm;
const { instance, module } = await __wbg_load(await input, imports);
return __wbg_finalize_init(instance, module);
}
export { initSync }
export default __wbg_init;

View File

@@ -1,585 +0,0 @@
let wasm;
export function __wbg_set_wasm(val) {
wasm = val;
}
const heap = new Array(128).fill(undefined);
heap.push(undefined, null, true, false);
function getObject(idx) { return heap[idx]; }
let heap_next = heap.length;
function dropObject(idx) {
if (idx < 132) return;
heap[idx] = heap_next;
heap_next = idx;
}
function takeObject(idx) {
const ret = getObject(idx);
dropObject(idx);
return ret;
}
function addHeapObject(obj) {
if (heap_next === heap.length) heap.push(heap.length + 1);
const idx = heap_next;
heap_next = heap[idx];
heap[idx] = obj;
return idx;
}
function isLikeNone(x) {
return x === undefined || x === null;
}
let cachedFloat64Memory0 = null;
function getFloat64Memory0() {
if (cachedFloat64Memory0 === null || cachedFloat64Memory0.byteLength === 0) {
cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer);
}
return cachedFloat64Memory0;
}
let cachedInt32Memory0 = null;
function getInt32Memory0() {
if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) {
cachedInt32Memory0 = new Int32Array(wasm.memory.buffer);
}
return cachedInt32Memory0;
}
let WASM_VECTOR_LEN = 0;
let cachedUint8Memory0 = null;
function getUint8Memory0() {
if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) {
cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer);
}
return cachedUint8Memory0;
}
const lTextEncoder = typeof TextEncoder === 'undefined' ? (0, module.require)('util').TextEncoder : TextEncoder;
let cachedTextEncoder = new lTextEncoder('utf-8');
const encodeString = (typeof cachedTextEncoder.encodeInto === 'function'
? function (arg, view) {
return cachedTextEncoder.encodeInto(arg, view);
}
: function (arg, view) {
const buf = cachedTextEncoder.encode(arg);
view.set(buf);
return {
read: arg.length,
written: buf.length
};
});
function passStringToWasm0(arg, malloc, realloc) {
if (realloc === undefined) {
const buf = cachedTextEncoder.encode(arg);
const ptr = malloc(buf.length, 1) >>> 0;
getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf);
WASM_VECTOR_LEN = buf.length;
return ptr;
}
let len = arg.length;
let ptr = malloc(len, 1) >>> 0;
const mem = getUint8Memory0();
let offset = 0;
for (; offset < len; offset++) {
const code = arg.charCodeAt(offset);
if (code > 0x7F) break;
mem[ptr + offset] = code;
}
if (offset !== len) {
if (offset !== 0) {
arg = arg.slice(offset);
}
ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
const view = getUint8Memory0().subarray(ptr + offset, ptr + len);
const ret = encodeString(arg, view);
offset += ret.written;
}
WASM_VECTOR_LEN = offset;
return ptr;
}
const lTextDecoder = typeof TextDecoder === 'undefined' ? (0, module.require)('util').TextDecoder : TextDecoder;
let cachedTextDecoder = new lTextDecoder('utf-8', { ignoreBOM: true, fatal: true });
cachedTextDecoder.decode();
function getStringFromWasm0(ptr, len) {
ptr = ptr >>> 0;
return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len));
}
function debugString(val) {
// primitive types
const type = typeof val;
if (type == 'number' || type == 'boolean' || val == null) {
return `${val}`;
}
if (type == 'string') {
return `"${val}"`;
}
if (type == 'symbol') {
const description = val.description;
if (description == null) {
return 'Symbol';
} else {
return `Symbol(${description})`;
}
}
if (type == 'function') {
const name = val.name;
if (typeof name == 'string' && name.length > 0) {
return `Function(${name})`;
} else {
return 'Function';
}
}
// objects
if (Array.isArray(val)) {
const length = val.length;
let debug = '[';
if (length > 0) {
debug += debugString(val[0]);
}
for(let i = 1; i < length; i++) {
debug += ', ' + debugString(val[i]);
}
debug += ']';
return debug;
}
// Test for built-in
const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val));
let className;
if (builtInMatches.length > 1) {
className = builtInMatches[1];
} else {
// Failed to match the standard '[object ClassName]'
return toString.call(val);
}
if (className == 'Object') {
// we're a user defined class or Object
// JSON.stringify avoids problems with cycles, and is generally much
// easier than looping through ownProperties of `val`.
try {
return 'Object(' + JSON.stringify(val) + ')';
} catch (_) {
return 'Object';
}
}
// errors
if (val instanceof Error) {
return `${val.name}: ${val.message}\n${val.stack}`;
}
// TODO we could test for more things here, like `Set`s and `Map`s.
return className;
}
/**
* @returns {any}
*/
export function state0_bindgen() {
const ret = wasm.state0_bindgen();
return takeObject(ret);
}
let cachedUint32Memory0 = null;
function getUint32Memory0() {
if (cachedUint32Memory0 === null || cachedUint32Memory0.byteLength === 0) {
cachedUint32Memory0 = new Uint32Array(wasm.memory.buffer);
}
return cachedUint32Memory0;
}
function passArray32ToWasm0(arg, malloc) {
const ptr = malloc(arg.length * 4, 4) >>> 0;
getUint32Memory0().set(arg, ptr / 4);
WASM_VECTOR_LEN = arg.length;
return ptr;
}
/**
* @param {any} message_a_to_b
* @param {Uint32Array} bit_vector
* @returns {any}
*/
export function state1_bindgen(message_a_to_b, bit_vector) {
const ptr0 = passArray32ToWasm0(bit_vector, wasm.__wbindgen_malloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.state1_bindgen(addHeapObject(message_a_to_b), ptr0, len0);
return takeObject(ret);
}
/**
* @param {any} private_output_a_state0
* @param {any} public_output_a_state0
* @param {any} message_b_to_a
* @param {Uint32Array} bit_vector
* @returns {any}
*/
export function state2_bindgen(private_output_a_state0, public_output_a_state0, message_b_to_a, bit_vector) {
const ptr0 = passArray32ToWasm0(bit_vector, wasm.__wbindgen_malloc);
const len0 = WASM_VECTOR_LEN;
const ret = wasm.state2_bindgen(addHeapObject(private_output_a_state0), addHeapObject(public_output_a_state0), addHeapObject(message_b_to_a), ptr0, len0);
return takeObject(ret);
}
/**
* @param {any} private_output_b_state1
* @param {any} public_output_b_state1
* @param {any} message_a_to_b
* @returns {any}
*/
export function state3_bindgen(private_output_b_state1, public_output_b_state1, message_a_to_b) {
const ret = wasm.state3_bindgen(addHeapObject(private_output_b_state1), addHeapObject(public_output_b_state1), addHeapObject(message_a_to_b));
return takeObject(ret);
}
function getArrayU32FromWasm0(ptr, len) {
ptr = ptr >>> 0;
return getUint32Memory0().subarray(ptr / 4, ptr / 4 + len);
}
/**
* @param {any} public_output_a_state2
* @param {any} message_b_to_a
* @returns {Uint32Array}
*/
export function state4_bindgen(public_output_a_state2, message_b_to_a) {
try {
const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
wasm.state4_bindgen(retptr, addHeapObject(public_output_a_state2), addHeapObject(message_b_to_a));
var r0 = getInt32Memory0()[retptr / 4 + 0];
var r1 = getInt32Memory0()[retptr / 4 + 1];
var v1 = getArrayU32FromWasm0(r0, r1).slice();
wasm.__wbindgen_free(r0, r1 * 4, 4);
return v1;
} finally {
wasm.__wbindgen_add_to_stack_pointer(16);
}
}
function handleError(f, args) {
try {
return f.apply(this, args);
} catch (e) {
wasm.__wbindgen_exn_store(addHeapObject(e));
}
}
export function __wbindgen_object_drop_ref(arg0) {
takeObject(arg0);
};
export function __wbindgen_is_object(arg0) {
const val = getObject(arg0);
const ret = typeof(val) === 'object' && val !== null;
return ret;
};
export function __wbindgen_is_undefined(arg0) {
const ret = getObject(arg0) === undefined;
return ret;
};
export function __wbindgen_in(arg0, arg1) {
const ret = getObject(arg0) in getObject(arg1);
return ret;
};
export function __wbindgen_object_clone_ref(arg0) {
const ret = getObject(arg0);
return addHeapObject(ret);
};
export function __wbindgen_jsval_loose_eq(arg0, arg1) {
const ret = getObject(arg0) == getObject(arg1);
return ret;
};
export function __wbindgen_boolean_get(arg0) {
const v = getObject(arg0);
const ret = typeof(v) === 'boolean' ? (v ? 1 : 0) : 2;
return ret;
};
export function __wbindgen_number_get(arg0, arg1) {
const obj = getObject(arg1);
const ret = typeof(obj) === 'number' ? obj : undefined;
getFloat64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? 0 : ret;
getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret);
};
export function __wbindgen_string_get(arg0, arg1) {
const obj = getObject(arg1);
const ret = typeof(obj) === 'string' ? obj : undefined;
var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
var len1 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
};
export function __wbindgen_error_new(arg0, arg1) {
const ret = new Error(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
export function __wbindgen_number_new(arg0) {
const ret = arg0;
return addHeapObject(ret);
};
export function __wbindgen_string_new(arg0, arg1) {
const ret = getStringFromWasm0(arg0, arg1);
return addHeapObject(ret);
};
export function __wbg_getwithrefkey_15c62c2b8546208d(arg0, arg1) {
const ret = getObject(arg0)[getObject(arg1)];
return addHeapObject(ret);
};
export function __wbg_set_20cbc34131e76824(arg0, arg1, arg2) {
getObject(arg0)[takeObject(arg1)] = takeObject(arg2);
};
export function __wbg_crypto_d05b68a3572bb8ca(arg0) {
const ret = getObject(arg0).crypto;
return addHeapObject(ret);
};
export function __wbg_process_b02b3570280d0366(arg0) {
const ret = getObject(arg0).process;
return addHeapObject(ret);
};
export function __wbg_versions_c1cb42213cedf0f5(arg0) {
const ret = getObject(arg0).versions;
return addHeapObject(ret);
};
export function __wbg_node_43b1089f407e4ec2(arg0) {
const ret = getObject(arg0).node;
return addHeapObject(ret);
};
export function __wbindgen_is_string(arg0) {
const ret = typeof(getObject(arg0)) === 'string';
return ret;
};
export function __wbg_require_9a7e0f667ead4995() { return handleError(function () {
const ret = module.require;
return addHeapObject(ret);
}, arguments) };
export function __wbg_msCrypto_10fc94afee92bd76(arg0) {
const ret = getObject(arg0).msCrypto;
return addHeapObject(ret);
};
export function __wbg_randomFillSync_b70ccbdf4926a99d() { return handleError(function (arg0, arg1) {
getObject(arg0).randomFillSync(takeObject(arg1));
}, arguments) };
export function __wbg_getRandomValues_7e42b4fb8779dc6d() { return handleError(function (arg0, arg1) {
getObject(arg0).getRandomValues(getObject(arg1));
}, arguments) };
export function __wbg_get_c43534c00f382c8a(arg0, arg1) {
const ret = getObject(arg0)[arg1 >>> 0];
return addHeapObject(ret);
};
export function __wbg_length_d99b680fd68bf71b(arg0) {
const ret = getObject(arg0).length;
return ret;
};
export function __wbg_new_34c624469fb1d4fd() {
const ret = new Array();
return addHeapObject(ret);
};
export function __wbindgen_is_function(arg0) {
const ret = typeof(getObject(arg0)) === 'function';
return ret;
};
export function __wbg_newnoargs_5859b6d41c6fe9f7(arg0, arg1) {
const ret = new Function(getStringFromWasm0(arg0, arg1));
return addHeapObject(ret);
};
export function __wbg_next_1938cf110c9491d4(arg0) {
const ret = getObject(arg0).next;
return addHeapObject(ret);
};
export function __wbg_next_267398d0e0761bf9() { return handleError(function (arg0) {
const ret = getObject(arg0).next();
return addHeapObject(ret);
}, arguments) };
export function __wbg_done_506b44765ba84b9c(arg0) {
const ret = getObject(arg0).done;
return ret;
};
export function __wbg_value_31485d8770eb06ab(arg0) {
const ret = getObject(arg0).value;
return addHeapObject(ret);
};
export function __wbg_iterator_364187e1ee96b750() {
const ret = Symbol.iterator;
return addHeapObject(ret);
};
export function __wbg_get_5027b32da70f39b1() { return handleError(function (arg0, arg1) {
const ret = Reflect.get(getObject(arg0), getObject(arg1));
return addHeapObject(ret);
}, arguments) };
export function __wbg_call_a79f1973a4f07d5e() { return handleError(function (arg0, arg1) {
const ret = getObject(arg0).call(getObject(arg1));
return addHeapObject(ret);
}, arguments) };
export function __wbg_new_87d841e70661f6e9() {
const ret = new Object();
return addHeapObject(ret);
};
export function __wbg_self_086b5302bcafb962() { return handleError(function () {
const ret = self.self;
return addHeapObject(ret);
}, arguments) };
export function __wbg_window_132fa5d7546f1de5() { return handleError(function () {
const ret = window.window;
return addHeapObject(ret);
}, arguments) };
export function __wbg_globalThis_e5f801a37ad7d07b() { return handleError(function () {
const ret = globalThis.globalThis;
return addHeapObject(ret);
}, arguments) };
export function __wbg_global_f9a61fce4af6b7c1() { return handleError(function () {
const ret = global.global;
return addHeapObject(ret);
}, arguments) };
export function __wbg_set_379b27f1d5f1bf9c(arg0, arg1, arg2) {
getObject(arg0)[arg1 >>> 0] = takeObject(arg2);
};
export function __wbg_isArray_fbd24d447869b527(arg0) {
const ret = Array.isArray(getObject(arg0));
return ret;
};
export function __wbg_instanceof_ArrayBuffer_f4521cec1b99ee35(arg0) {
let result;
try {
result = getObject(arg0) instanceof ArrayBuffer;
} catch (_) {
result = false;
}
const ret = result;
return ret;
};
export function __wbg_call_f6a2bc58c19c53c6() { return handleError(function (arg0, arg1, arg2) {
const ret = getObject(arg0).call(getObject(arg1), getObject(arg2));
return addHeapObject(ret);
}, arguments) };
export function __wbg_isSafeInteger_d8c89788832a17bf(arg0) {
const ret = Number.isSafeInteger(getObject(arg0));
return ret;
};
export function __wbg_buffer_5d1b598a01b41a42(arg0) {
const ret = getObject(arg0).buffer;
return addHeapObject(ret);
};
export function __wbg_newwithbyteoffsetandlength_d695c7957788f922(arg0, arg1, arg2) {
const ret = new Uint8Array(getObject(arg0), arg1 >>> 0, arg2 >>> 0);
return addHeapObject(ret);
};
export function __wbg_new_ace717933ad7117f(arg0) {
const ret = new Uint8Array(getObject(arg0));
return addHeapObject(ret);
};
export function __wbg_set_74906aa30864df5a(arg0, arg1, arg2) {
getObject(arg0).set(getObject(arg1), arg2 >>> 0);
};
export function __wbg_length_f0764416ba5bb237(arg0) {
const ret = getObject(arg0).length;
return ret;
};
export function __wbg_instanceof_Uint8Array_4f5cffed7df34b2f(arg0) {
let result;
try {
result = getObject(arg0) instanceof Uint8Array;
} catch (_) {
result = false;
}
const ret = result;
return ret;
};
export function __wbg_newwithlength_728575f3bba9959b(arg0) {
const ret = new Uint8Array(arg0 >>> 0);
return addHeapObject(ret);
};
export function __wbg_subarray_7f7a652672800851(arg0, arg1, arg2) {
const ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0);
return addHeapObject(ret);
};
export function __wbindgen_debug_string(arg0, arg1) {
const ret = debugString(getObject(arg1));
const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
const len1 = WASM_VECTOR_LEN;
getInt32Memory0()[arg0 / 4 + 1] = len1;
getInt32Memory0()[arg0 / 4 + 0] = ptr1;
};
export function __wbindgen_throw(arg0, arg1) {
throw new Error(getStringFromWasm0(arg0, arg1));
};
export function __wbindgen_memory() {
const ret = wasm.memory;
return addHeapObject(ret);
};

Binary file not shown.

View File

@@ -1,11 +1,14 @@
{
"name": "mp-psi",
"version": "0.1.6",
"version": "0.1.9.1",
"files": [
"mp_psi_bg.wasm",
"mp_psi.js",
"mp_psi.d.ts"
],
"main": "mp_psi.js",
"types": "mp_psi.d.ts"
"module": "mp_psi.js",
"types": "mp_psi.d.ts",
"sideEffects": [
"./snippets/*"
]
}

65
src/bandwidth_benches.rs Normal file
View File

@@ -0,0 +1,65 @@
pub trait BandwidthBench {
fn get_byte_size(&self) -> usize;
}
impl BandwidthBench for bfv::SecretKeyProto {
fn get_byte_size(&self) -> usize {
self.coefficients.len()
}
}
impl BandwidthBench for bfv::CollectivePublicKeyShareProto {
fn get_byte_size(&self) -> usize {
self.clone()
.share
.unwrap()
.coefficients
.iter()
.fold(0, |acc, vec| acc + vec.len())
}
}
impl BandwidthBench for bfv::CollectiveRlkShare1Proto {
fn get_byte_size(&self) -> usize {
self.shares.iter().fold(0, |acc, poly| {
poly.coefficients
.iter()
.fold(acc, |acc, vec| acc + vec.len())
})
}
}
impl BandwidthBench for bfv::CollectiveRlkShare2Proto {
fn get_byte_size(&self) -> usize {
self.shares.iter().fold(0, |acc, poly| {
acc + poly.coefficients.iter().fold(0, |acc, vec| acc + vec.len())
})
}
}
impl BandwidthBench for bfv::CiphertextProto {
fn get_byte_size(&self) -> usize {
self.c.iter().fold(0, |acc, poly| {
acc + poly.coefficients.iter().fold(0, |acc, vec| acc + vec.len())
})
}
}
impl BandwidthBench for bfv::CollectiveRlkAggTrimmedShare1Proto {
fn get_byte_size(&self) -> usize {
self.shares.iter().fold(0, |acc, poly| {
acc + poly.coefficients.iter().fold(0, |acc, vec| acc + vec.len())
})
}
}
impl BandwidthBench for bfv::CollectiveDecryptionShareProto {
fn get_byte_size(&self) -> usize {
self.clone()
.share
.unwrap()
.coefficients
.iter()
.fold(0, |acc, vec| acc + vec.len())
}
}

View File

@@ -1,10 +1,11 @@
use bfv::{
BfvParameters, CiphertextProto, CollectiveDecryption, CollectiveDecryptionShare,
BfvParameters, Ciphertext, CiphertextProto, CollectiveDecryption, CollectiveDecryptionShare,
CollectiveDecryptionShareProto, CollectivePublicKeyGenerator, CollectivePublicKeyShareProto,
CollectiveRlkAggTrimmedShare1Proto, CollectiveRlkGenerator, CollectiveRlkShare1Proto,
CollectiveRlkShare2Proto, Encoding, EvaluationKey, Evaluator, Plaintext, SecretKey,
SecretKeyProto,
};
use itertools::{izip, Itertools};
use rand::thread_rng;
use serde::{Deserialize, Serialize};
use traits::{
@@ -13,32 +14,32 @@ use traits::{
};
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
static CRS_PK: [u8; 32] = [0u8; 32];
mod bandwidth_benches;
static CRS_PK: [u8; 32] = [11u8; 32];
static CRS_RLK: [u8; 32] = [0u8; 32];
static RING_SIZE: usize = 1 << 11;
fn params() -> BfvParameters {
let mut params = BfvParameters::new(&[30, 30], 65537, 1 << 11);
params.enable_hybrid_key_switching(&[30]);
let mut params = BfvParameters::new_with_primes(
vec![1032193, 1073692673],
vec![995329, 1073668097],
40961,
RING_SIZE,
);
params.enable_hybrid_key_switching_with_prime(vec![61441]);
params.enable_pke();
params
}
fn convert_to_proto<T, U>(value: &T, parameters: &T::Parameters) -> U
fn convert<T, U>(value: &T, parameters: &BfvParameters) -> U
where
T: TryFromWithParameters<Value = U, Parameters = BfvParameters>,
U: TryFromWithParameters<Value = T, Parameters = BfvParameters>,
{
U::try_from_with_parameters(value, parameters)
}
fn convert_from_proto<T, U>(proto: &U, parameters: &U::Parameters) -> T
where
U: TryFromWithParameters<Value = T, Parameters = BfvParameters>,
T: TryFromWithParameters<Value = U, Parameters = BfvParameters>,
{
T::try_from_with_parameters(proto, parameters)
}
#[derive(Serialize, Deserialize)]
struct PrivateOutputAPostState0 {
s_pk_a: SecretKeyProto,
@@ -71,7 +72,7 @@ struct PrivateOutputBPostState1 {
#[derive(Serialize, Deserialize)]
struct PublicOutputBPostState1 {
ciphertext_b: CiphertextProto,
ciphertexts_b: Vec<CiphertextProto>,
share_rlk_b_round2: CollectiveRlkShare2Proto,
rlk_agg_round1_h1s: CollectiveRlkAggTrimmedShare1Proto,
}
@@ -81,7 +82,7 @@ struct MessageBToAPostState1 {
share_pk_b: CollectivePublicKeyShareProto,
share_rlk_b_round1: CollectiveRlkShare1Proto,
share_rlk_b_round2: CollectiveRlkShare2Proto,
ciphertext_b: CiphertextProto,
ciphertexts_b: Vec<CiphertextProto>,
}
#[derive(Serialize, Deserialize)]
@@ -93,14 +94,14 @@ struct OutputState1 {
#[derive(Serialize, Deserialize)]
struct PublicOutputAPostState2 {
decryption_share_a: CollectiveDecryptionShareProto,
ciphertext_res: CiphertextProto,
decryption_shares_a: Vec<CollectiveDecryptionShareProto>,
ciphertexts_res: Vec<CiphertextProto>,
}
#[derive(Serialize, Deserialize)]
struct MessageAToBPostState2 {
decryption_share_a: CollectiveDecryptionShareProto,
ciphertext_a: CiphertextProto,
decryption_shares_a: Vec<CollectiveDecryptionShareProto>,
ciphertexts_a: Vec<CiphertextProto>,
share_rlk_a_round2: CollectiveRlkShare2Proto,
}
@@ -112,7 +113,7 @@ struct OutputState2 {
#[derive(Serialize, Deserialize)]
struct MessageBToAPostState3 {
decryption_share_b: CollectiveDecryptionShareProto,
decryption_shares_b: Vec<CollectiveDecryptionShareProto>,
}
#[derive(Serialize, Deserialize)]
@@ -151,18 +152,21 @@ fn state0() -> (
let share_rlk_a_round1 =
CollectiveRlkGenerator::generate_share_1(&params, &s_pk_a, &s_rlk_a, CRS_RLK, 0, &mut rng);
let share_rlk_a_round1_proto: CollectiveRlkShare1Proto = convert(&share_rlk_a_round1, &params);
let share_pk_a_proto: CollectivePublicKeyShareProto = convert(&share_pk_a, &params);
let message_a_to_b = MessageAToBPostState0 {
share_pk_a: convert_to_proto(&share_pk_a, &params),
share_rlk_a_round1: convert_to_proto(&share_rlk_a_round1, &params),
share_pk_a: share_pk_a_proto.clone(),
share_rlk_a_round1: share_rlk_a_round1_proto.clone(),
};
let private_output_a = PrivateOutputAPostState0 {
s_pk_a: convert_to_proto(&s_pk_a, &params),
s_rlk_a: convert_to_proto(&s_rlk_a, &params),
s_pk_a: convert(&s_pk_a, &params),
s_rlk_a: convert(&s_rlk_a, &params),
};
let public_output_a = PublicOutputAPostState0 {
share_pk_a: convert_to_proto(&share_pk_a, &params),
share_rlk_a_round1: convert_to_proto(&share_rlk_a_round1, &params),
share_pk_a: share_pk_a_proto,
share_rlk_a_round1: share_rlk_a_round1_proto,
};
(private_output_a, public_output_a, message_a_to_b)
@@ -203,9 +207,9 @@ fn state1(
let share_rlk_b_round1 =
CollectiveRlkGenerator::generate_share_1(&params, &s_pk_b, &s_rlk_b, CRS_RLK, 0, &mut rng);
let share_rlk_a_round1 = convert_from_proto(&message_a_to_b.share_rlk_a_round1, &params);
let share_rlk_a_round1 = convert(&message_a_to_b.share_rlk_a_round1, &params);
let share_pk_a = convert_from_proto(&message_a_to_b.share_pk_a, &params);
let share_pk_a = convert(&message_a_to_b.share_pk_a, &params);
// rlk key part 1
let rlk_shares_round1 = vec![share_rlk_a_round1, share_rlk_b_round1.clone()];
@@ -223,25 +227,36 @@ fn state1(
&collective_pk_shares,
CRS_PK,
);
let pt = Plaintext::try_encoding_with_parameters(bit_vector, &params, Encoding::default());
let ciphertext_b = collecitve_pk.encrypt(&params, &pt, &mut rng);
let ciphertexts_b = bit_vector
.chunks(RING_SIZE)
.map(|v| {
let pt = Plaintext::try_encoding_with_parameters(v, &params, Encoding::default());
collecitve_pk.encrypt(&params, &pt, &mut rng)
})
.collect_vec();
let ciphertexts_b_proto: Vec<CiphertextProto> = ciphertexts_b
.iter()
.map(|v| convert(v, &params))
.collect_vec();
let share_rlk_b_round2_proto: CollectiveRlkShare2Proto = convert(&share_rlk_b_round2, &params);
let message_b_to_a = MessageBToAPostState1 {
share_pk_b: convert_to_proto(&share_pk_b, &params),
share_rlk_b_round1: convert_to_proto(&share_rlk_b_round1, &params),
share_rlk_b_round2: convert_to_proto(&share_rlk_b_round2, &params),
ciphertext_b: convert_to_proto(&ciphertext_b, &params),
share_pk_b: convert(&share_pk_b, &params),
share_rlk_b_round1: convert(&share_rlk_b_round1, &params),
share_rlk_b_round2: share_rlk_b_round2_proto.clone(),
ciphertexts_b: ciphertexts_b_proto.clone(),
};
let private_output_b = PrivateOutputBPostState1 {
s_pk_b: convert_to_proto(&s_pk_b, &params),
s_pk_b: convert(&s_pk_b, &params),
};
let rlk_aggregated_shares1_trimmed = rlk_agg_1.trim();
let public_output_b = PublicOutputBPostState1 {
ciphertext_b: convert_to_proto(&ciphertext_b, &params),
share_rlk_b_round2: convert_to_proto(&share_rlk_b_round2, &params),
rlk_agg_round1_h1s: convert_to_proto(&rlk_aggregated_shares1_trimmed, &params),
ciphertexts_b: ciphertexts_b_proto,
share_rlk_b_round2: share_rlk_b_round2_proto,
rlk_agg_round1_h1s: convert(&rlk_aggregated_shares1_trimmed, &params),
};
(private_output_b, public_output_b, message_b_to_a)
@@ -291,13 +306,13 @@ fn state2(
// aggrgegate shares of rlk round 1
let rlk_shares_round1 = vec![
convert_from_proto(&public_output_a_state0.share_rlk_a_round1, &params),
convert_from_proto(&message_b_to_a.share_rlk_b_round1, &params),
convert(&public_output_a_state0.share_rlk_a_round1, &params),
convert(&message_b_to_a.share_rlk_b_round1, &params),
];
let rlk_agg_1 = CollectiveRlkGenerator::aggregate_shares_1(&params, &rlk_shares_round1, 0);
let s_pk_a = convert_from_proto(&private_output_a_state0.s_pk_a, &params);
let s_rlk_a = convert_from_proto(&private_output_a_state0.s_rlk_a, &params);
let s_pk_a = convert(&private_output_a_state0.s_pk_a, &params);
let s_rlk_a = convert(&private_output_a_state0.s_rlk_a, &params);
// generate share 2 for rlk round 2
let share_rlk_a_round2 = CollectiveRlkGenerator::generate_share_2(
@@ -308,7 +323,7 @@ fn state2(
// aggregate rlk round 2 shares and generate rlk
let rlk_shares_round2 = vec![
share_rlk_a_round2.clone(),
convert_from_proto(&message_b_to_a.share_rlk_b_round2, &params),
convert(&message_b_to_a.share_rlk_b_round2, &params),
];
let rlk = CollectiveRlkGenerator::aggregate_shares_2(
&params,
@@ -318,47 +333,70 @@ fn state2(
);
// create public key and encrypt A's bit vector'
let collective_pk_shares = vec![
convert_from_proto(&public_output_a_state0.share_pk_a, &params),
convert_from_proto(&message_b_to_a.share_pk_b, &params),
convert(&public_output_a_state0.share_pk_a, &params),
convert(&message_b_to_a.share_pk_b, &params),
];
let collective_pk = CollectivePublicKeyGenerator::aggregate_shares_and_finalise(
&params,
&collective_pk_shares,
CRS_PK,
);
let pt = Plaintext::try_encoding_with_parameters(bit_vector, &params, Encoding::default());
let ciphertext_a = collective_pk.encrypt(&params, &pt, &mut rng);
let ciphertexts_a = bit_vector
.chunks(RING_SIZE)
.map(|v| {
let pt = Plaintext::try_encoding_with_parameters(v, &params, Encoding::default());
collective_pk.encrypt(&params, &pt, &mut rng)
})
.collect_vec();
// perform PSI
let evaluator = Evaluator::new(params.clone());
let evaluation_key = EvaluationKey::new_raw(&[0], vec![rlk], &[], &[], vec![]);
let ciphertext_b = convert_from_proto(&message_b_to_a.ciphertext_b, &params);
let ciphertext_res = evaluator.mul(&ciphertext_a, &ciphertext_b);
let ciphertext_res = evaluator.relinearize(&ciphertext_res, &evaluation_key);
let ciphertexts_b: Vec<Ciphertext> = message_b_to_a
.ciphertexts_b
.iter()
.map(|v| convert(v, &params))
.collect_vec();
let ciphertexts_res = izip!(ciphertexts_a.iter(), ciphertexts_b.iter())
.map(|(a, b)| {
let ct = evaluator.mul(a, b);
evaluator.relinearize(&ct, &evaluation_key)
})
.collect_vec();
// generate decryption share of ciphertext_res
let decryption_share_a = CollectiveDecryption::generate_share(
evaluator.params(),
&ciphertext_res,
&convert_from_proto(&private_output_a_state0.s_pk_a, &params),
&mut rng,
);
let decryption_shares_a = ciphertexts_res
.iter()
.map(|ct| {
CollectiveDecryption::generate_share(
evaluator.params(),
ct,
&convert(&private_output_a_state0.s_pk_a, &params),
&mut rng,
)
})
.collect_vec();
let decryption_share_a = CollectiveDecryptionShareProto::try_from_with_levelled_parameters(
&decryption_share_a,
&params,
0,
);
let decryption_shares_a_proto: Vec<CollectiveDecryptionShareProto> = decryption_shares_a
.iter()
.map(|v| CollectiveDecryptionShareProto::try_from_with_levelled_parameters(v, &params, 0))
.collect_vec();
let public_output_a = PublicOutputAPostState2 {
decryption_share_a: decryption_share_a.clone(),
ciphertext_res: convert_to_proto(&ciphertext_res, &params),
decryption_shares_a: decryption_shares_a_proto.clone(),
ciphertexts_res: ciphertexts_res
.iter()
.map(|v| convert(v, &params))
.collect_vec(),
};
let message_a_to_b = MessageAToBPostState2 {
decryption_share_a,
ciphertext_a: convert_to_proto(&ciphertext_a, &params),
share_rlk_a_round2: convert_to_proto(&share_rlk_a_round2, &params),
decryption_shares_a: decryption_shares_a_proto,
ciphertexts_a: ciphertexts_a
.iter()
.map(|v| convert(v, &params))
.collect_vec(),
share_rlk_a_round2: convert(&share_rlk_a_round2, &params),
};
(public_output_a, message_a_to_b)
@@ -405,12 +443,11 @@ fn state3(
// create rlk
let rlk_shares_round2 = vec![
convert_from_proto(&message_a_to_b.share_rlk_a_round2, &params),
convert_from_proto(&public_output_b_state1.share_rlk_b_round2, &params),
convert(&message_a_to_b.share_rlk_a_round2, &params),
convert(&public_output_b_state1.share_rlk_b_round2, &params),
];
let rlk_agg_round1_h1s =
convert_from_proto(&public_output_b_state1.rlk_agg_round1_h1s, &params);
let rlk_agg_round1_h1s = convert(&public_output_b_state1.rlk_agg_round1_h1s, &params);
let rlk = CollectiveRlkGenerator::aggregate_shares_2(
&params,
@@ -423,49 +460,55 @@ fn state3(
let evaluator = Evaluator::new(params.clone());
let evaluation_key = EvaluationKey::new_raw(&[0], vec![rlk], &[], &[], vec![]);
let ciphertext_a = convert_from_proto(&message_a_to_b.ciphertext_a, &params);
let ciphertext_b = convert_from_proto(&public_output_b_state1.ciphertext_b, &params);
let ciphertexts_a: Vec<Ciphertext> = message_a_to_b
.ciphertexts_a
.iter()
.map(|v| convert(v, &params))
.collect_vec();
let ciphertexts_b: Vec<Ciphertext> = public_output_b_state1
.ciphertexts_b
.iter()
.map(|v| convert(v, &params))
.collect_vec();
let ciphertext_res = evaluator.mul(&ciphertext_a, &ciphertext_b);
let ciphertext_res = evaluator.relinearize(&ciphertext_res, &evaluation_key);
let ciphertexts_res = izip!(ciphertexts_a.iter(), ciphertexts_b.iter())
.map(|(a, b)| {
let ct = evaluator.mul(a, b);
evaluator.relinearize(&ct, &evaluation_key)
})
.collect_vec();
let s_pk_b = convert_from_proto(&private_output_b_state1.s_pk_b, &params);
let s_pk_b = convert(&private_output_b_state1.s_pk_b, &params);
// generate B's decryption share
let decryption_share_b = CollectiveDecryption::generate_share(
evaluator.params(),
&ciphertext_res,
&s_pk_b,
&mut rng,
);
let decryption_shares_b = ciphertexts_res
.iter()
.map(|ct| CollectiveDecryption::generate_share(evaluator.params(), ct, &s_pk_b, &mut rng))
.collect_vec();
// decrypt ciphertext res
let decryption_shares_vec = vec![
decryption_share_b.clone(),
CollectiveDecryptionShare::try_from_with_levelled_parameters(
&message_a_to_b.decryption_share_a,
&params,
0,
),
];
let psi_output = CollectiveDecryption::aggregate_share_and_decrypt(
evaluator.params(),
&ciphertext_res,
&decryption_shares_vec,
);
let psi_output = Vec::<u32>::try_decoding_with_parameters(
&psi_output,
evaluator.params(),
Encoding::default(),
);
let psi_output = izip!(
message_a_to_b.decryption_shares_a.iter(),
decryption_shares_b.iter(),
ciphertexts_res.iter()
)
.flat_map(|(a_proto, b, ct)| {
let shares_vec = vec![
b.clone(),
CollectiveDecryptionShare::try_from_with_levelled_parameters(a_proto, &params, 0),
];
let pt =
CollectiveDecryption::aggregate_share_and_decrypt(evaluator.params(), ct, &shares_vec);
Vec::<u32>::try_decoding_with_parameters(&pt, evaluator.params(), Encoding::default())
})
.collect_vec();
let message_b_to_a = MessageBToAPostState3 {
decryption_share_b: CollectiveDecryptionShareProto::try_from_with_levelled_parameters(
&decryption_share_b,
&params,
0,
),
decryption_shares_b: decryption_shares_b
.iter()
.map(|v| {
CollectiveDecryptionShareProto::try_from_with_levelled_parameters(v, &params, 0)
})
.collect_vec(),
};
(message_b_to_a, psi_output)
@@ -491,35 +534,29 @@ fn state4(
) -> Vec<u32> {
let params = params();
// decrypt ciphertext res
let decryption_shares_vec = vec![
CollectiveDecryptionShare::try_from_with_levelled_parameters(
&public_output_a_state2.decryption_share_a,
&params,
0,
),
CollectiveDecryptionShare::try_from_with_levelled_parameters(
&message_b_to_a.decryption_share_b,
&params,
0,
),
];
let ciphertext_res = convert_from_proto(&public_output_a_state2.ciphertext_res, &params);
let psi_output = CollectiveDecryption::aggregate_share_and_decrypt(
&params,
&ciphertext_res,
&decryption_shares_vec,
);
let psi_output =
Vec::<u32>::try_decoding_with_parameters(&psi_output, &params, Encoding::default());
let psi_output = izip!(
public_output_a_state2.decryption_shares_a.iter(),
message_b_to_a.decryption_shares_b.iter(),
public_output_a_state2.ciphertexts_res.iter()
)
.flat_map(|(a_proto, b_proto, ct_proto)| {
let shares_vec = vec![
CollectiveDecryptionShare::try_from_with_levelled_parameters(&b_proto, &params, 0),
CollectiveDecryptionShare::try_from_with_levelled_parameters(&a_proto, &params, 0),
];
let ct: Ciphertext = convert(ct_proto, &params);
let pt = CollectiveDecryption::aggregate_share_and_decrypt(&params, &ct, &shares_vec);
Vec::<u32>::try_decoding_with_parameters(&pt, &params, Encoding::default())
})
.collect_vec();
psi_output
}
#[cfg(test)]
mod tests {
use crate::bandwidth_benches::BandwidthBench;
use super::*;
use itertools::{izip, Itertools};
use rand::{distributions::Uniform, Rng};
@@ -544,17 +581,84 @@ mod tests {
#[test]
fn psi_works() {
let hamming_weight = 10;
let vector_size = 10;
let hamming_weight = 1000;
let vector_size = RING_SIZE * 3;
// A: state 0
let (private_output_a_state0, public_output_a_state0, message_a_to_b_state0) = state0();
// B: state 1
// Benchmark bandwidth size of output state 0
let mut byte_count_state0_private_output_a = 0;
byte_count_state0_private_output_a += private_output_a_state0.s_pk_a.get_byte_size();
byte_count_state0_private_output_a += private_output_a_state0.s_rlk_a.get_byte_size();
println!(
"byte_count_state0_private_output_a: {}",
byte_count_state0_private_output_a
);
let mut byte_count_state0_public_output_a = 0;
byte_count_state0_public_output_a += public_output_a_state0.share_pk_a.get_byte_size();
byte_count_state0_public_output_a +=
public_output_a_state0.share_rlk_a_round1.get_byte_size();
println!(
"byte_count_state0_public_output_a: {}",
byte_count_state0_public_output_a
);
let mut byte_count_state0_message_a_to_b = 0;
byte_count_state0_message_a_to_b += message_a_to_b_state0.share_pk_a.get_byte_size();
byte_count_state0_message_a_to_b +=
message_a_to_b_state0.share_rlk_a_round1.get_byte_size();
println!(
"byte_count_state0_message_a_to_b: {}",
byte_count_state0_message_a_to_b
);
// B: state 1
let bit_vector_b = random_bit_vector(hamming_weight, vector_size);
let (private_output_b_state1, public_output_b_state1, message_b_to_a_state1) =
state1(message_a_to_b_state0, &bit_vector_b);
let mut byte_count_state1_private_output_b = 0;
byte_count_state1_private_output_b += private_output_b_state1.s_pk_b.get_byte_size();
println!(
"byte_count_state1_private_output_b: {}",
byte_count_state1_private_output_b
);
let mut byte_count_state1_public_output_b = 0;
byte_count_state1_public_output_b += public_output_b_state1
.ciphertexts_b
.iter()
.fold(0, |acc, ct| acc + ct.get_byte_size());
byte_count_state1_public_output_b +=
public_output_b_state1.rlk_agg_round1_h1s.get_byte_size();
byte_count_state1_public_output_b +=
public_output_b_state1.share_rlk_b_round2.get_byte_size();
println!(
"byte_count_state1_public_output_b: {}",
byte_count_state1_public_output_b
);
let mut byte_count_state1_message_b_to_a = 0;
byte_count_state1_message_b_to_a += message_b_to_a_state1
.ciphertexts_b
.iter()
.fold(0, |acc, ct| acc + ct.get_byte_size());
byte_count_state1_message_b_to_a += message_b_to_a_state1.share_pk_b.get_byte_size();
byte_count_state1_message_b_to_a +=
message_b_to_a_state1.share_rlk_b_round1.get_byte_size();
byte_count_state1_message_b_to_a +=
message_b_to_a_state1.share_rlk_b_round2.get_byte_size();
println!(
"byte_count_state1_message_b_to_a: {}",
byte_count_state1_message_b_to_a
);
// A: state 2
let bit_vector_a = random_bit_vector(hamming_weight, vector_size);
let (public_output_a_state2, message_a_to_b_state2) = state2(
@@ -564,6 +668,37 @@ mod tests {
&bit_vector_a,
);
let mut byte_count_state2_public_output_a = 0;
byte_count_state2_public_output_a += public_output_a_state2
.decryption_shares_a
.iter()
.fold(0, |acc, share| acc + share.get_byte_size());
byte_count_state2_public_output_a += public_output_a_state2
.ciphertexts_res
.iter()
.fold(0, |acc, ct| acc + ct.get_byte_size());
println!(
"byte_count_state2_public_output_a: {}",
byte_count_state2_public_output_a
);
let mut byte_count_state2_message_a_to_b = 0;
byte_count_state2_message_a_to_b += message_a_to_b_state2
.decryption_shares_a
.iter()
.fold(0, |acc, share| acc + share.get_byte_size());
byte_count_state2_message_a_to_b += message_a_to_b_state2
.ciphertexts_a
.iter()
.fold(0, |acc, ct| acc + ct.get_byte_size());
byte_count_state2_message_a_to_b +=
message_a_to_b_state2.share_rlk_a_round2.get_byte_size();
println!(
"byte_count_state2_message_a_to_b: {}",
byte_count_state2_message_a_to_b
);
// B: state 3
let (message_b_to_a_state3, psi_output_b) = state3(
private_output_b_state1,
@@ -571,9 +706,32 @@ mod tests {
message_a_to_b_state2,
);
let byte_count_state3_message_b_to_a = message_b_to_a_state3
.decryption_shares_b
.iter()
.fold(0, |acc, share| acc + share.get_byte_size());
let byte_count_state3_psi_output_b = psi_output_b.len() / 8; // Divide by 8 to account for the fact that it is a bit vector
println!(
"byte_count_state3_message_b_to_a: {}",
byte_count_state3_message_b_to_a
);
println!(
"byte_count_state3_psi_output_b: {}",
byte_count_state3_psi_output_b
);
// A: state 4
let psi_output_a = state4(public_output_a_state2, message_b_to_a_state3);
let byte_count_state4_psi_output_a = psi_output_a.len() / 8; // Divide by 8 to account for the fact that it is a bit vector
println!(
"byte_count_state4_psi_output_a {}",
byte_count_state4_psi_output_a
);
let expected_psi_output = plain_psi(&bit_vector_a, &bit_vector_b);
assert_eq!(expected_psi_output, psi_output_a[..vector_size]);