mirror of
https://github.com/tlsnotary/tlsn-js.git
synced 2026-01-09 15:07:59 -05:00
v0.0.2
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,4 +7,4 @@ node_modules/
|
||||
.DS_Store
|
||||
pnpm-lock.yaml
|
||||
build/
|
||||
test-build/
|
||||
dev-build/
|
||||
|
||||
@@ -3,8 +3,8 @@ test-build
|
||||
node_modules
|
||||
wasm
|
||||
postcss.config.js
|
||||
webpack.config.js
|
||||
webpack.test.config.js
|
||||
webpack.build.config.js
|
||||
webpack.web.dev.config.js
|
||||
|
||||
*.json
|
||||
*.scss
|
||||
23313
package-lock.json
generated
Normal file
23313
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
22
package.json
22
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tlsn-js",
|
||||
"version": "0.0.1",
|
||||
"version": "0.0.2",
|
||||
"description": "",
|
||||
"repository": "https://github.com/tlsnotary/tlsn-js",
|
||||
"main": "build/index.js",
|
||||
@@ -8,17 +8,19 @@
|
||||
"files": [
|
||||
"build/",
|
||||
"src/",
|
||||
"wasm/prover/pkg",
|
||||
"readme.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build:src": "webpack --config webpack.config.js",
|
||||
"build:src": "webpack --config webpack.build.config.js",
|
||||
"build:types": "tsc --project tsconfig.compile.json",
|
||||
"build": "NODE_ENV=production concurrently npm:build:src npm:build:types",
|
||||
"update:wasm": "sh utils/check-wasm.sh -f",
|
||||
"build:wasm": "wasm-pack build --target web wasm/prover",
|
||||
"build:test": "webpack --config webpack.test.config.js",
|
||||
"watch:test": "webpack --config webpack.test.config.js --watch",
|
||||
"serve:test": "serve --config ../serve.json ./test-build -l 3001",
|
||||
"test": "concurrently npm:watch:test npm:serve:test",
|
||||
"watch:dev": "webpack --config webpack.web.dev.config.js --watch",
|
||||
"serve:dev": "serve --config ../../serve.json ./dev-build/web -l 3001",
|
||||
"predev": "sh utils/check-wasm.sh",
|
||||
"dev": "concurrently npm:watch:dev npm:serve:dev",
|
||||
"lint:eslint": "eslint . --fix",
|
||||
"lint:tsc": "tsc --noEmit",
|
||||
"lint": "concurrently npm:lint:tsc npm:lint:eslint"
|
||||
@@ -27,6 +29,7 @@
|
||||
"comlink": "^4.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^6.15.0",
|
||||
"browserify": "^17.0.0",
|
||||
"concurrently": "^5.1.0",
|
||||
"constants-browserify": "^1.0.0",
|
||||
@@ -35,12 +38,12 @@
|
||||
"eslint": "^8.47.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-plugin-prettier": "^5.0.0",
|
||||
"prettier": "^3.0.2",
|
||||
"file-loader": "^5.0.2",
|
||||
"html-webpack-plugin": "~5.3.2",
|
||||
"https-browserify": "^1.0.0",
|
||||
"image-webpack-loader": "^6.0.0",
|
||||
"node-loader": "^0.6.0",
|
||||
"prettier": "^3.0.2",
|
||||
"process": "^0.11.10",
|
||||
"serve": "14.2.1",
|
||||
"stream-browserify": "^3.0.0",
|
||||
@@ -52,5 +55,8 @@
|
||||
"webpack-node-externals": "^3.0.0"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC"
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">= 16.20.2"
|
||||
}
|
||||
}
|
||||
|
||||
11
readme.md
11
readme.md
@@ -1,6 +1,6 @@
|
||||
# tlsn-js
|
||||
|
||||
NPM Modules for proving and verifying using TLS Notary.
|
||||
NPM Modules for proving and verifying using TLS Notary in the browser.
|
||||
|
||||
The prover requires a [notary-server](https://github.com/tlsnotary/notary-server) and websockify proxy
|
||||
|
||||
@@ -43,12 +43,15 @@ npm install tlsn-js
|
||||
## Development
|
||||
|
||||
```
|
||||
# make sure you have rust install
|
||||
# https://www.rust-lang.org/tools/install
|
||||
npm install
|
||||
npm run lint
|
||||
npm test
|
||||
|
||||
# this serve a page that will execute the example code at http://localhost:3001
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Build
|
||||
## Build for NPM
|
||||
|
||||
```
|
||||
npm install
|
||||
|
||||
47
src/index.ts
47
src/index.ts
@@ -1,20 +1,20 @@
|
||||
import * as Comlink from 'comlink';
|
||||
import type TLSN from './worker';
|
||||
import { Proof } from './types';
|
||||
|
||||
const TLSN: any = Comlink.wrap(
|
||||
const T = Comlink.wrap<TLSN>(
|
||||
new Worker(new URL('./worker.ts', import.meta.url)),
|
||||
);
|
||||
|
||||
let _tlsn: any | null = null;
|
||||
let _tlsn: Comlink.Remote<TLSN>;
|
||||
|
||||
async function getTLSN(): Promise<any | null> {
|
||||
async function getTLSN(): Promise<Comlink.Remote<TLSN>> {
|
||||
if (_tlsn) return _tlsn;
|
||||
_tlsn = await new TLSN();
|
||||
// @ts-ignore
|
||||
_tlsn = await new T();
|
||||
return _tlsn;
|
||||
}
|
||||
|
||||
export const DEFAULT_LOCAL_SERVER_PUBKEY = `-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEBv36FI4ZFszJa0DQFJ3wWCXvVLFr\ncRzMG5kaTeHGoSzDu6cFqx3uEWYpFGo6C0EOUgf+mEgbktLrXocv5yHzKg==\n-----END PUBLIC KEY-----`;
|
||||
export const NOTARY_SERVER_PUBKEY = `-----BEGIN PUBLIC KEY-----\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAExpX/4R4z40gI6C/j9zAM39u58LJu\n3Cx5tXTuqhhu/tirnBi5GniMmspOTEsps4ANnPLpMmMSfhJ+IFHbc3qVOA==\n-----END PUBLIC KEY-----\n`;
|
||||
|
||||
export const prove = async (
|
||||
url: string,
|
||||
options: {
|
||||
@@ -27,7 +27,7 @@ export const prove = async (
|
||||
secretHeaders?: string[];
|
||||
secretResps?: string[];
|
||||
},
|
||||
) => {
|
||||
): Promise<Proof> => {
|
||||
const {
|
||||
method,
|
||||
headers = {},
|
||||
@@ -41,10 +41,10 @@ export const prove = async (
|
||||
|
||||
const tlsn = await getTLSN();
|
||||
|
||||
headers["Host"] = new URL(url).host;
|
||||
headers["Connection"] = "close";
|
||||
headers['Host'] = new URL(url).host;
|
||||
headers['Connection'] = 'close';
|
||||
|
||||
return tlsn.prover(url, {
|
||||
const proof = await tlsn.prove(url, {
|
||||
method,
|
||||
headers,
|
||||
body,
|
||||
@@ -54,13 +54,28 @@ export const prove = async (
|
||||
secretHeaders,
|
||||
secretResps,
|
||||
});
|
||||
|
||||
return {
|
||||
...proof,
|
||||
notaryUrl,
|
||||
};
|
||||
};
|
||||
|
||||
export const verify = async (
|
||||
proof: { session: any; substrings: any },
|
||||
pubkey = NOTARY_SERVER_PUBKEY,
|
||||
) => {
|
||||
proof: Proof,
|
||||
): Promise<{
|
||||
time: number;
|
||||
sent: string;
|
||||
recv: string;
|
||||
notaryUrl: string;
|
||||
}> => {
|
||||
const res = await fetch(proof.notaryUrl + '/info');
|
||||
const json: any = await res.json();
|
||||
const publicKey = json.publicKey as string;
|
||||
const tlsn = await getTLSN();
|
||||
const result = await tlsn.verify(proof, pubkey);
|
||||
return result;
|
||||
const result = await tlsn.verify(proof, publicKey);
|
||||
return {
|
||||
...result,
|
||||
notaryUrl: proof.notaryUrl,
|
||||
};
|
||||
};
|
||||
|
||||
82
src/tlsn.ts
Normal file
82
src/tlsn.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import init, { initThreadPool, prover, verify } from '../wasm/prover/pkg';
|
||||
|
||||
export default class TLSN {
|
||||
private startPromise: any;
|
||||
private resolveStart: any;
|
||||
|
||||
constructor() {
|
||||
console.log('worker module initiated.');
|
||||
this.startPromise = new Promise((resolve) => {
|
||||
this.resolveStart = resolve;
|
||||
});
|
||||
this.start();
|
||||
}
|
||||
|
||||
async start() {
|
||||
console.log('start');
|
||||
const numConcurrency = navigator.hardwareConcurrency;
|
||||
console.log('!@# navigator.hardwareConcurrency=', numConcurrency);
|
||||
const res = await init();
|
||||
console.log('!@# res.memory=', res.memory);
|
||||
// 6422528 ~= 6.12 mb
|
||||
console.log('!@# res.memory.buffer.length=', res.memory.buffer.byteLength);
|
||||
await initThreadPool(numConcurrency);
|
||||
this.resolveStart();
|
||||
}
|
||||
|
||||
async waitForStart() {
|
||||
return this.startPromise;
|
||||
}
|
||||
|
||||
async prove(
|
||||
url: string,
|
||||
options?: {
|
||||
method?: string;
|
||||
headers?: { [key: string]: string };
|
||||
body?: string;
|
||||
maxTranscriptSize?: number;
|
||||
notaryUrl?: string;
|
||||
websocketProxyUrl?: string;
|
||||
secretHeaders?: string[];
|
||||
secretResps?: string[];
|
||||
},
|
||||
) {
|
||||
try {
|
||||
await this.waitForStart();
|
||||
console.log('worker', url, {
|
||||
...options,
|
||||
notaryUrl: options?.notaryUrl,
|
||||
websocketProxyUrl: options?.websocketProxyUrl,
|
||||
});
|
||||
const resProver = await prover(
|
||||
url,
|
||||
{
|
||||
...options,
|
||||
notaryUrl: options?.notaryUrl,
|
||||
websocketProxyUrl: options?.websocketProxyUrl,
|
||||
},
|
||||
options?.secretHeaders || [],
|
||||
options?.secretResps || [],
|
||||
);
|
||||
const resJSON = JSON.parse(resProver);
|
||||
console.log('!@# resProver,resJSON=', { resProver, resJSON });
|
||||
console.log('!@# resAfter.memory=', resJSON.memory);
|
||||
// 1105920000 ~= 1.03 gb
|
||||
console.log(
|
||||
'!@# resAfter.memory.buffer.length=',
|
||||
resJSON.memory?.buffer?.byteLength,
|
||||
);
|
||||
|
||||
return resJSON;
|
||||
} catch (e: any) {
|
||||
console.log(e);
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
async verify(proof: any, pubkey: string) {
|
||||
await this.waitForStart();
|
||||
const raw = await verify(JSON.stringify(proof), pubkey);
|
||||
return JSON.parse(raw);
|
||||
}
|
||||
}
|
||||
94
src/types.ts
Normal file
94
src/types.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
export interface Proof {
|
||||
session: Session;
|
||||
substrings: Substrings;
|
||||
notaryUrl: string;
|
||||
}
|
||||
|
||||
export interface Session {
|
||||
header: Header;
|
||||
server_name: ServerName;
|
||||
signature: Signature;
|
||||
handshake_data_decommitment: HandshakeDataDecommitment;
|
||||
}
|
||||
|
||||
export interface HandshakeDataDecommitment {
|
||||
nonce: number[];
|
||||
data: Data;
|
||||
}
|
||||
|
||||
export interface Data {
|
||||
server_cert_details: ServerCERTDetails;
|
||||
server_kx_details: ServerKxDetails;
|
||||
client_random: number[];
|
||||
server_random: number[];
|
||||
}
|
||||
|
||||
export interface ServerCERTDetails {
|
||||
cert_chain: Array<number[]>;
|
||||
ocsp_response: any[];
|
||||
scts: null;
|
||||
}
|
||||
|
||||
export interface ServerKxDetails {
|
||||
kx_params: number[];
|
||||
kx_sig: KxSig;
|
||||
}
|
||||
|
||||
export interface KxSig {
|
||||
scheme: string;
|
||||
sig: number[];
|
||||
}
|
||||
|
||||
export interface Header {
|
||||
encoder_seed: number[];
|
||||
merkle_root: number[];
|
||||
sent_len: number;
|
||||
recv_len: number;
|
||||
handshake_summary: HandshakeSummary;
|
||||
}
|
||||
|
||||
export interface HandshakeSummary {
|
||||
time: number;
|
||||
server_public_key: ServerPublicKey;
|
||||
handshake_commitment: number[];
|
||||
}
|
||||
|
||||
export interface ServerPublicKey {
|
||||
group: string;
|
||||
key: number[];
|
||||
}
|
||||
|
||||
export interface ServerName {
|
||||
Dns: string;
|
||||
}
|
||||
|
||||
export interface Signature {
|
||||
P256: string;
|
||||
}
|
||||
|
||||
export interface Substrings {
|
||||
openings: { [key: string]: Opening[] };
|
||||
inclusion_proof: InclusionProof;
|
||||
}
|
||||
|
||||
export interface InclusionProof {
|
||||
proof: any[];
|
||||
total_leaves: number;
|
||||
}
|
||||
|
||||
export interface Opening {
|
||||
kind?: string;
|
||||
ranges?: Range[];
|
||||
direction?: string;
|
||||
Blake3?: Blake3;
|
||||
}
|
||||
|
||||
export interface Blake3 {
|
||||
data: number[];
|
||||
nonce: number[];
|
||||
}
|
||||
|
||||
export interface Range {
|
||||
start: number;
|
||||
end: number;
|
||||
}
|
||||
@@ -1,89 +1,6 @@
|
||||
import * as Comlink from 'comlink';
|
||||
import init, {
|
||||
initThreadPool,
|
||||
prover,
|
||||
verify,
|
||||
} from '../wasm/prover/pkg/tlsn_extension_rs';
|
||||
import TLSN from './tlsn';
|
||||
|
||||
export default class TLSN {
|
||||
private startPromise: any;
|
||||
private resolveStart: any;
|
||||
export default TLSN;
|
||||
|
||||
constructor() {
|
||||
console.log('worker module initiated.');
|
||||
this.startPromise = new Promise((resolve) => {
|
||||
this.resolveStart = resolve;
|
||||
});
|
||||
this.start();
|
||||
}
|
||||
|
||||
async start() {
|
||||
console.log('start');
|
||||
const numConcurrency = navigator.hardwareConcurrency;
|
||||
console.log('!@# navigator.hardwareConcurrency=', numConcurrency);
|
||||
const res = await init();
|
||||
console.log('!@# res.memory=', res.memory);
|
||||
// 6422528 ~= 6.12 mb
|
||||
console.log('!@# res.memory.buffer.length=', res.memory.buffer.byteLength);
|
||||
await initThreadPool(numConcurrency);
|
||||
this.resolveStart();
|
||||
}
|
||||
|
||||
async waitForStart() {
|
||||
return this.startPromise;
|
||||
}
|
||||
|
||||
async prover(
|
||||
url: string,
|
||||
options?: {
|
||||
method?: string;
|
||||
headers?: { [key: string]: string };
|
||||
body?: string;
|
||||
maxTranscriptSize?: number;
|
||||
notaryUrl?: string;
|
||||
websocketProxyUrl?: string;
|
||||
secretHeaders?: string[];
|
||||
secretResps?: string[];
|
||||
},
|
||||
) {
|
||||
try {
|
||||
await this.waitForStart();
|
||||
console.log('worker', url, {
|
||||
...options,
|
||||
notaryUrl: options?.notaryUrl,
|
||||
websocketProxyUrl: options?.websocketProxyUrl,
|
||||
});
|
||||
const resProver = await prover(
|
||||
url,
|
||||
{
|
||||
...options,
|
||||
notaryUrl: options?.notaryUrl,
|
||||
websocketProxyUrl: options?.websocketProxyUrl,
|
||||
},
|
||||
options?.secretHeaders || [],
|
||||
options?.secretResps || [],
|
||||
);
|
||||
const resJSON = JSON.parse(resProver);
|
||||
console.log('!@# resProver,resJSON=', { resProver, resJSON });
|
||||
console.log('!@# resAfter.memory=', resJSON.memory);
|
||||
// 1105920000 ~= 1.03 gb
|
||||
console.log(
|
||||
'!@# resAfter.memory.buffer.length=',
|
||||
resJSON.memory?.buffer?.byteLength,
|
||||
);
|
||||
|
||||
return resJSON;
|
||||
} catch (e: any) {
|
||||
console.log(e);
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
async verify(proof: any, pubkey: string) {
|
||||
await this.waitForStart();
|
||||
const raw = await verify(JSON.stringify(proof), pubkey);
|
||||
return JSON.parse(raw);
|
||||
}
|
||||
}
|
||||
|
||||
Comlink.expose(TLSN);
|
||||
Comlink.expose(TLSN);
|
||||
|
||||
32
utils/check-wasm.sh
Normal file
32
utils/check-wasm.sh
Normal file
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
DIRECTORY="./wasm/prover/target"
|
||||
FORCE_FLAG=0
|
||||
|
||||
# Check if --force or -f flag is passed
|
||||
for arg in "$@"
|
||||
do
|
||||
if [ "$arg" == "--force" ] || [ "$arg" == "-f" ]
|
||||
then
|
||||
FORCE_FLAG=1
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
# If force flag is set, remove the directories/files and run the npm command
|
||||
if [ $FORCE_FLAG -eq 1 ]
|
||||
then
|
||||
echo "Force flag detected, removing directories and files."
|
||||
rm -rf ./wasm/prover/pkg
|
||||
rm -rf ./wasm/prover/target
|
||||
rm -f ./wasm/prover/Cargo.lock
|
||||
echo "Running npm run build:wasm"
|
||||
npm run build:wasm
|
||||
# If the directory does not exist or is empty, run the npm command
|
||||
elif [ ! -d "$DIRECTORY" ] || [ -z "$(ls -A $DIRECTORY)" ]
|
||||
then
|
||||
echo "Running npm run build:wasm"
|
||||
npm run build:wasm
|
||||
else
|
||||
echo "$DIRECTORY exists and is not empty."
|
||||
fi
|
||||
@@ -1,17 +1,18 @@
|
||||
import { prove, verify, NOTARY_SERVER_PUBKEY } from '../src';
|
||||
import { prove, verify } from '../src';
|
||||
|
||||
(async function runTest() {
|
||||
console.time('prove');
|
||||
const proof = await prove('https://swapi.dev/api/people/1', {
|
||||
method: 'GET',
|
||||
maxTranscriptSize: 16384,
|
||||
notaryUrl: 'https://notary.efprivacyscaling.org',
|
||||
notaryUrl: 'http://localhost:7047',
|
||||
websocketProxyUrl: 'ws://notary.efprivacyscaling.org:55688?token=swapi.dev',
|
||||
});
|
||||
console.timeEnd('prove');
|
||||
|
||||
console.time('verify');
|
||||
const result = await verify(proof, NOTARY_SERVER_PUBKEY);
|
||||
const result = await verify(proof);
|
||||
console.timeEnd('verify');
|
||||
|
||||
console.log(result);
|
||||
})();
|
||||
})();
|
||||
@@ -158,6 +158,7 @@ pub async fn prover(
|
||||
let config = ProverConfig::builder()
|
||||
.id(notarization_response.session_id)
|
||||
.server_dns(target_host)
|
||||
.max_transcript_size(options.max_transcript_size)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
@@ -253,7 +254,6 @@ pub async fn prover(
|
||||
|
||||
log!("Got a response from the server");
|
||||
|
||||
log!("{}", response.status());
|
||||
assert!(response.status() == StatusCode::OK);
|
||||
|
||||
log!("Request OK");
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
const webpack = require('webpack');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
const path = require('path');
|
||||
const { compilerOptions } = require('./tsconfig.json');
|
||||
|
||||
@@ -36,10 +35,10 @@ module.exports = [
|
||||
target: 'web',
|
||||
mode: isProd ? 'production' : 'development',
|
||||
entry: {
|
||||
test: path.join(__dirname, 'utils', 'test.ts'),
|
||||
test: path.join(__dirname, 'utils', 'web.ts'),
|
||||
},
|
||||
output: {
|
||||
path: __dirname + '/test-build',
|
||||
path: __dirname + '/dev-build/web',
|
||||
publicPath: '/',
|
||||
filename: `[name].js`,
|
||||
},
|
||||
@@ -80,17 +79,12 @@ module.exports = [
|
||||
new HtmlWebpackPlugin({
|
||||
template: './static/index.template.ejs',
|
||||
filename: `index.html`,
|
||||
title: process.env.APP_TITLE || 'Zkitter',
|
||||
inject: true,
|
||||
}),
|
||||
new webpack.ContextReplacementPlugin(/gun/),
|
||||
],
|
||||
stats: 'minimal',
|
||||
devServer: {
|
||||
historyApiFallback: true,
|
||||
},
|
||||
// optimization: {
|
||||
// runtimeChunk: 'single'
|
||||
// },
|
||||
},
|
||||
];
|
||||
Reference in New Issue
Block a user