diff --git a/packages/app/src/Element/NoteCreator.tsx b/packages/app/src/Element/NoteCreator.tsx index 139b61ae..03029ae0 100644 --- a/packages/app/src/Element/NoteCreator.tsx +++ b/packages/app/src/Element/NoteCreator.tsx @@ -21,7 +21,7 @@ import Note from "Element/Note"; import { ClipboardEventHandler } from "react"; import useLogin from "Hooks/useLogin"; -import { System } from "index"; +import { System, WasmPowWorker } from "index"; import AsyncButton from "Element/AsyncButton"; import { AsyncIcon } from "Element/AsyncIcon"; import { fetchNip05Pubkey } from "@snort/shared"; @@ -30,9 +30,9 @@ import { useNoteCreator } from "State/NoteCreator"; export function NoteCreator() { const { formatMessage } = useIntl(); - const publisher = useEventPublisher(); const uploader = useFileUpload(); - const login = useLogin(s => ({ relays: s.relays, publicKey: s.publicKey })); + const login = useLogin(s => ({ relays: s.relays, publicKey: s.publicKey, pow: s.preferences.pow })); + const publisher = login.pow ? useEventPublisher()?.pow(login.pow, new WasmPowWorker()) : useEventPublisher(); const note = useNoteCreator(); const relays = login.relays; diff --git a/packages/app/src/Element/PinPrompt.tsx b/packages/app/src/Element/PinPrompt.tsx index 7c995622..87b1f372 100644 --- a/packages/app/src/Element/PinPrompt.tsx +++ b/packages/app/src/Element/PinPrompt.tsx @@ -2,13 +2,14 @@ import useLogin from "Hooks/useLogin"; import "./PinPrompt.css"; import { ReactNode, useState } from "react"; import { FormattedMessage, useIntl } from "react-intl"; -import useEventPublisher from "Hooks/useEventPublisher"; -import { LoginStore, createPublisher, sessionNeedsPin } from "Login"; import { unwrap } from "@snort/shared"; import { EventPublisher, InvalidPinError, PinEncrypted, PinEncryptedPayload } from "@snort/system"; -import { DefaultPowWorker } from "index"; + +import useEventPublisher from "Hooks/useEventPublisher"; +import { LoginStore, createPublisher, sessionNeedsPin } from "Login"; import Modal from "./Modal"; import AsyncButton from "./AsyncButton"; +import { WasmPowWorker } from "index"; export function PinPrompt({ onResult, @@ -91,7 +92,7 @@ export function LoginUnlock() { const pub = EventPublisher.privateKey(k); if (login.preferences.pow) { - pub.pow(login.preferences.pow, DefaultPowWorker); + pub.pow(login.preferences.pow, new WasmPowWorker()); } LoginStore.setPublisher(login.id, pub); LoginStore.updateSession({ @@ -108,7 +109,7 @@ export function LoginUnlock() { const pub = createPublisher(login, key); if (pub) { if (login.preferences.pow) { - pub.pow(login.preferences.pow, DefaultPowWorker); + pub.pow(login.preferences.pow, new WasmPowWorker()); } LoginStore.setPublisher(login.id, pub); LoginStore.updateSession({ diff --git a/packages/app/src/Hooks/useEventPublisher.tsx b/packages/app/src/Hooks/useEventPublisher.tsx index 84bf8fd1..b686b0c8 100644 --- a/packages/app/src/Hooks/useEventPublisher.tsx +++ b/packages/app/src/Hooks/useEventPublisher.tsx @@ -1,6 +1,5 @@ import useLogin from "Hooks/useLogin"; import { LoginStore, createPublisher, sessionNeedsPin } from "Login"; -import { DefaultPowWorker } from "index"; export default function useEventPublisher() { const login = useLogin(); @@ -10,12 +9,8 @@ export default function useEventPublisher() { if (login.publicKey && !existing && !sessionNeedsPin(login)) { existing = createPublisher(login); if (existing) { - if (login.preferences.pow) { - existing.pow(login.preferences.pow, DefaultPowWorker); - } LoginStore.setPublisher(login.id, existing); } } - return existing; } diff --git a/packages/app/src/benchmarks.ts b/packages/app/src/benchmarks.ts index 7754d8a8..735863a1 100644 --- a/packages/app/src/benchmarks.ts +++ b/packages/app/src/benchmarks.ts @@ -1,6 +1,6 @@ import { bytesToHex } from "@noble/hashes/utils"; -import { DefaultQueryOptimizer, FlatReqFilter, QueryOptimizer, ReqFilter } from "@snort/system"; -import { compress, expand_filter, flat_merge, get_diff, default as wasmInit } from "@snort/system-wasm"; +import { DefaultQueryOptimizer, EventExt, FlatReqFilter, PowMiner, QueryOptimizer, ReqFilter } from "@snort/system"; +import { compress, expand_filter, flat_merge, get_diff, pow, default as wasmInit } from "@snort/system-wasm"; import WasmPath from "@snort/system-wasm/pkg/system_wasm_bg.wasm"; import { Bench } from "tinybench"; @@ -90,15 +90,35 @@ const testCompress = (q: QueryOptimizer) => { const wasmSuite = new Bench({ time: 1_000 }); const suite = new Bench({ time: 1_000 }); -const addTests = (s: Bench, q: QueryOptimizer) => { +const addTests = (s: Bench, q: QueryOptimizer, p: PowMiner) => { s.add("expand", () => testExpand(q)); s.add("get_diff", () => testGetDiff(q)); s.add("flat_merge", () => testFlatMerge(q)); s.add("compress", () => testCompress(q)); + s.add("pow", () => { + const ev = { + id: "", + kind: 1, + created_at: 1234567, + pubkey: "63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed", + content: "test", + sig: "", + tags: [], + }; + p.minePow(ev, 12); + }); }; -addTests(suite, DefaultQueryOptimizer); -addTests(wasmSuite, WasmQueryOptimizer); +addTests(suite, DefaultQueryOptimizer, { + minePow(ev, target) { + return Promise.resolve(EventExt.minePow(ev, target)); + }, +}); +addTests(wasmSuite, WasmQueryOptimizer, { + minePow(ev, target) { + return Promise.resolve(pow(ev, target)); + }, +}); const runAll = async () => { await wasmInit(WasmPath); @@ -106,9 +126,15 @@ const runAll = async () => { console.log("DefaultQueryOptimizer"); await suite.run(); console.table(suite.table()); + const p0 = document.createElement("pre"); + p0.innerText = JSON.stringify(suite.table(), undefined, " "); + document.body.appendChild(p0); console.log("WasmQueryOptimizer"); await wasmSuite.run(); console.table(wasmSuite.table()); + const p1 = document.createElement("pre"); + p1.innerText = JSON.stringify(wasmSuite.table(), undefined, " "); + document.body.appendChild(p1); }; runAll().catch(console.error); diff --git a/packages/app/src/chat/nip24.ts b/packages/app/src/chat/nip24.ts index 6281a6b7..9f32adf4 100644 --- a/packages/app/src/chat/nip24.ts +++ b/packages/app/src/chat/nip24.ts @@ -3,7 +3,7 @@ import { EventKind, NostrPrefix, encodeTLVEntries, TLVEntryType, TLVEntry, decod import { GiftWrapCache } from "Cache/GiftWrapCache"; import { UnwrappedGift } from "Db"; import { Chat, ChatSystem, ChatType, lastReadInChat } from "chat"; -import { DefaultPowWorker } from "index"; +import { WasmPowWorker } from "index"; export class Nip24ChatSystem extends ExternalStore> implements ChatSystem { #cache: GiftWrapCache; @@ -105,7 +105,9 @@ export class Nip24ChatSystem extends ExternalStore> implements ChatS const recvSealedN = pub.giftWrap(await pub.sealRumor(gossip, pt.id), pt.id, powTarget); messages.push(recvSealedN); } - messages.push(pub.giftWrap(await pub.sealRumor(gossip, pub.pubKey), pub.pubKey, powTarget, DefaultPowWorker)); + messages.push( + pub.giftWrap(await pub.sealRumor(gossip, pub.pubKey), pub.pubKey, powTarget, new WasmPowWorker()), + ); return await Promise.all(messages); }, sendMessage: (ev, system) => { diff --git a/packages/app/src/index.tsx b/packages/app/src/index.tsx index c47ca3a7..76f88d5c 100644 --- a/packages/app/src/index.tsx +++ b/packages/app/src/index.tsx @@ -2,13 +2,21 @@ import "./index.css"; import "@szhsin/react-menu/dist/index.css"; import "./fonts/inter.css"; -import { compress, expand_filter, flat_merge, get_diff, default as wasmInit } from "@snort/system-wasm"; +import { compress, expand_filter, flat_merge, get_diff, pow, default as wasmInit } from "@snort/system-wasm"; import WasmPath from "@snort/system-wasm/pkg/system_wasm_bg.wasm"; import { StrictMode } from "react"; import * as ReactDOM from "react-dom/client"; import { createBrowserRouter, RouterProvider } from "react-router-dom"; -import { NostrSystem, ProfileLoaderService, PowWorker, QueryOptimizer, FlatReqFilter, ReqFilter } from "@snort/system"; +import { + NostrSystem, + ProfileLoaderService, + QueryOptimizer, + FlatReqFilter, + ReqFilter, + PowMiner, + NostrEvent, +} from "@snort/system"; import { SnortContext } from "@snort/system-react"; import * as serviceWorkerRegistration from "serviceWorkerRegistration"; @@ -53,6 +61,13 @@ const WasmQueryOptimizer = { }, } as QueryOptimizer; +export class WasmPowWorker implements PowMiner { + minePow(ev: NostrEvent, target: number): Promise { + const res = pow(ev, target); + return Promise.resolve(res); + } +} + /** * Singleton nostr system */ @@ -75,11 +90,6 @@ export const System = new NostrSystem({ */ export const ProfileLoader = new ProfileLoaderService(System, UserCache); -/** - * Singleton POW worker - */ -export const DefaultPowWorker = new PowWorker("/pow.js"); - serviceWorkerRegistration.register(); async function initSite() { diff --git a/packages/system-wasm/Cargo.lock b/packages/system-wasm/Cargo.lock index ce049505..cc9ae096 100644 --- a/packages/system-wasm/Cargo.lock +++ b/packages/system-wasm/Cargo.lock @@ -23,24 +23,77 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46" +[[package]] +name = "argon2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ba4cac0a46bc1d2912652a751c47f2a9f3a7fe89bcae2275d418f5270402f9" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + +[[package]] +name = "async-trait" +version = "0.1.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bitflags" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bumpalo" version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + [[package]] name = "cast" version = "0.3.0" @@ -124,6 +177,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + [[package]] name = "criterion" version = "0.5.1" @@ -203,6 +265,27 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", + "subtle", +] + [[package]] name = "either" version = "1.9.0" @@ -230,6 +313,16 @@ dependencies = [ "libc", ] +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getrandom" version = "0.2.10" @@ -253,6 +346,12 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "is-terminal" version = "0.4.9" @@ -361,6 +460,17 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + [[package]] name = "plotters" version = "0.3.5" @@ -576,6 +686,35 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha256" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7895c8ae88588ccead14ff438b939b0c569cd619116f14b4d13fdff7b8333386" +dependencies = [ + "async-trait", + "bytes", + "hex", + "sha2", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + [[package]] name = "syn" version = "2.0.31" @@ -591,12 +730,16 @@ dependencies = [ name = "system-wasm" version = "0.1.0" dependencies = [ + "argon2", + "console_error_panic_hook", "criterion", + "hex", "itertools 0.11.0", "rand", "serde", "serde-wasm-bindgen", "serde_json", + "sha256", "wasm-bindgen", "wasm-bindgen-test", ] @@ -611,12 +754,24 @@ dependencies = [ "serde_json", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-ident" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "walkdir" version = "2.4.0" diff --git a/packages/system-wasm/Cargo.toml b/packages/system-wasm/Cargo.toml index 81a968a6..14e657d1 100644 --- a/packages/system-wasm/Cargo.toml +++ b/packages/system-wasm/Cargo.toml @@ -8,9 +8,13 @@ edition = "2021" crate-type = ["cdylib", "rlib"] [dependencies] +argon2 = "0.5.2" +console_error_panic_hook = "0.1.7" +hex = { version = "0.4.3", features = [], default-features = false } itertools = "0.11.0" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.188", features = ["derive"], default-features = false } serde-wasm-bindgen = "0.5.0" +sha256 = { version = "1.4.0", features = [], default-features = false } wasm-bindgen = "0.2.87" [dev-dependencies] @@ -21,4 +25,11 @@ criterion = { version = "0.5" } [[bench]] name = "basic" -harness = false \ No newline at end of file +harness = false + +[profile.release] +opt-level = 3 +lto = true + +[package.metadata.wasm-pack.profile.release] +wasm-opt = ["-O3"] diff --git a/packages/system-wasm/benches/basic.rs b/packages/system-wasm/benches/basic.rs index 5bdef41a..bdefcbf8 100644 --- a/packages/system-wasm/benches/basic.rs +++ b/packages/system-wasm/benches/basic.rs @@ -1,8 +1,9 @@ use criterion::{criterion_group, criterion_main, Criterion}; use rand::prelude::*; use std::collections::HashSet; -use system_query::diff::diff_filter; -use system_query::filter::{FlatReqFilter, ReqFilter}; +use system_wasm::diff::diff_filter; +use system_wasm::filter::{FlatReqFilter, ReqFilter}; +use system_wasm::{Event, pow}; fn random_pubkey(rng: &mut ThreadRng) -> String { let mut bytes = [0u8; 32]; @@ -63,6 +64,20 @@ fn criterion_benchmark(c: &mut Criterion) { let _ = diff_filter(&prev, &next); }) }); + c.bench_function("pow", |b| { + b.iter(|| { + let mut ev = Event { + id: None, + kind: 1, + created_at: 1234567, + pubkey: "63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed".to_string(), + content: "test".to_owned(), + sig: None, + tags: vec![], + }; + pow::pow(&mut ev, 12); + }) + }); } criterion_group!(benches, criterion_benchmark); diff --git a/packages/system-wasm/package.json b/packages/system-wasm/package.json index 8b9009d7..2d268998 100644 --- a/packages/system-wasm/package.json +++ b/packages/system-wasm/package.json @@ -5,7 +5,7 @@ "author": "Kieran", "license": "MIT", "scripts": { - "build": "wasm-pack build -t web -s snort && rm -f pkg/.gitignore" + "build": "wasm-pack build --release -t web -s snort && rm -f pkg/.gitignore" }, "files": [ "pkg/system_wasm_bg.wasm", diff --git a/packages/system-wasm/pkg/system_wasm.d.ts b/packages/system-wasm/pkg/system_wasm.d.ts index b1781e0d..1ebca4b4 100644 --- a/packages/system-wasm/pkg/system_wasm.d.ts +++ b/packages/system-wasm/pkg/system_wasm.d.ts @@ -27,6 +27,18 @@ export function flat_merge(val: any): any; * @returns {any} */ export function compress(val: any): any; +/** + * @param {any} val + * @param {any} target + * @returns {any} + */ +export function pow(val: any, target: any): any; +/** + * @param {any} password + * @param {any} salt + * @returns {any} + */ +export function argon2(password: any, salt: any): any; export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module; @@ -37,10 +49,13 @@ export interface InitOutput { readonly get_diff: (a: number, b: number, c: number) => void; readonly flat_merge: (a: number, b: number) => void; readonly compress: (a: number, b: number) => void; + readonly pow: (a: number, b: number, c: number) => void; + readonly argon2: (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_exn_store: (a: number) => void; + readonly __wbindgen_free: (a: number, b: number, c: number) => void; } export type SyncInitInput = BufferSource | WebAssembly.Module; diff --git a/packages/system-wasm/pkg/system_wasm.js b/packages/system-wasm/pkg/system_wasm.js index 7b930b35..7f7ae5af 100644 --- a/packages/system-wasm/pkg/system_wasm.js +++ b/packages/system-wasm/pkg/system_wasm.js @@ -108,6 +108,15 @@ function getInt32Memory0() { return cachedInt32Memory0; } +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; +} + const cachedTextDecoder = typeof TextDecoder !== "undefined" ? new TextDecoder("utf-8", { ignoreBOM: true, fatal: true }) @@ -126,15 +135,6 @@ function getStringFromWasm0(ptr, len) { return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); } -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; -} - let cachedFloat64Memory0 = null; function getFloat64Memory0() { @@ -144,6 +144,15 @@ function getFloat64Memory0() { return cachedFloat64Memory0; } +let cachedBigInt64Memory0 = null; + +function getBigInt64Memory0() { + if (cachedBigInt64Memory0 === null || cachedBigInt64Memory0.byteLength === 0) { + cachedBigInt64Memory0 = new BigInt64Array(wasm.memory.buffer); + } + return cachedBigInt64Memory0; +} + function debugString(val) { // primitive types const type = typeof val; @@ -310,6 +319,48 @@ export function compress(val) { } } +/** + * @param {any} val + * @param {any} target + * @returns {any} + */ +export function pow(val, target) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + wasm.pow(retptr, addHeapObject(val), addHeapObject(target)); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r2 = getInt32Memory0()[retptr / 4 + 2]; + if (r2) { + throw takeObject(r1); + } + return takeObject(r0); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +} + +/** + * @param {any} password + * @param {any} salt + * @returns {any} + */ +export function argon2(password, salt) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + wasm.argon2(retptr, addHeapObject(password), addHeapObject(salt)); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r2 = getInt32Memory0()[retptr / 4 + 2]; + if (r2) { + throw takeObject(r1); + } + return takeObject(r0); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +} + function handleError(f, args) { try { return f.apply(this, args); @@ -375,6 +426,18 @@ function __wbg_get_imports() { const ret = getObject(arg0) in getObject(arg1); return ret; }; + imports.wbg.__wbindgen_is_bigint = function (arg0) { + const ret = typeof getObject(arg0) === "bigint"; + return ret; + }; + imports.wbg.__wbindgen_bigint_from_u64 = function (arg0) { + const ret = BigInt.asUintN(64, arg0); + return addHeapObject(ret); + }; + imports.wbg.__wbindgen_jsval_eq = function (arg0, arg1) { + const ret = getObject(arg0) === getObject(arg1); + return ret; + }; imports.wbg.__wbindgen_error_new = function (arg0, arg1) { const ret = new Error(getStringFromWasm0(arg0, arg1)); return addHeapObject(ret); @@ -513,6 +576,34 @@ function __wbg_get_imports() { const ret = result; return ret; }; + imports.wbg.__wbg_new_abda76e883ba8a5f = function () { + const ret = new Error(); + return addHeapObject(ret); + }; + imports.wbg.__wbg_stack_658279fe44541cf6 = function (arg0, arg1) { + const ret = getObject(arg1).stack; + 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.__wbg_error_f851667af71bcfc6 = function (arg0, arg1) { + let deferred0_0; + let deferred0_1; + try { + deferred0_0 = arg0; + deferred0_1 = arg1; + console.error(getStringFromWasm0(arg0, arg1)); + } finally { + wasm.__wbindgen_free(deferred0_0, deferred0_1, 1); + } + }; + imports.wbg.__wbindgen_bigint_get_as_i64 = function (arg0, arg1) { + const v = getObject(arg1); + const ret = typeof v === "bigint" ? v : undefined; + getBigInt64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? BigInt(0) : ret; + getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); + }; imports.wbg.__wbindgen_debug_string = function (arg0, arg1) { const ret = debugString(getObject(arg1)); const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); @@ -536,6 +627,7 @@ function __wbg_init_memory(imports, maybe_memory) {} function __wbg_finalize_init(instance, module) { wasm = instance.exports; __wbg_init.__wbindgen_wasm_module = module; + cachedBigInt64Memory0 = null; cachedFloat64Memory0 = null; cachedInt32Memory0 = null; cachedUint8Memory0 = null; diff --git a/packages/system-wasm/pkg/system_wasm_bg.js b/packages/system-wasm/pkg/system_wasm_bg.js new file mode 100644 index 00000000..876c8507 --- /dev/null +++ b/packages/system-wasm/pkg/system_wasm_bg.js @@ -0,0 +1,622 @@ +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; +} + +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; +} + +function isLikeNone(x) { + return x === undefined || x === null; +} + +let cachedInt32Memory0 = null; + +function getInt32Memory0() { + if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) { + cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); + } + return cachedInt32Memory0; +} + +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; +} + +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)); +} + +let cachedFloat64Memory0 = null; + +function getFloat64Memory0() { + if (cachedFloat64Memory0 === null || cachedFloat64Memory0.byteLength === 0) { + cachedFloat64Memory0 = new Float64Array(wasm.memory.buffer); + } + return cachedFloat64Memory0; +} + +let cachedBigInt64Memory0 = null; + +function getBigInt64Memory0() { + if (cachedBigInt64Memory0 === null || cachedBigInt64Memory0.byteLength === 0) { + cachedBigInt64Memory0 = new BigInt64Array(wasm.memory.buffer); + } + return cachedBigInt64Memory0; +} + +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; +} +/** + * @param {any} prev + * @param {any} next + * @returns {any} + */ +export function diff_filters(prev, next) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + wasm.diff_filters(retptr, addHeapObject(prev), addHeapObject(next)); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r2 = getInt32Memory0()[retptr / 4 + 2]; + if (r2) { + throw takeObject(r1); + } + return takeObject(r0); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +} + +/** + * @param {any} val + * @returns {any} + */ +export function expand_filter(val) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + wasm.expand_filter(retptr, addHeapObject(val)); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r2 = getInt32Memory0()[retptr / 4 + 2]; + if (r2) { + throw takeObject(r1); + } + return takeObject(r0); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +} + +/** + * @param {any} prev + * @param {any} next + * @returns {any} + */ +export function get_diff(prev, next) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + wasm.get_diff(retptr, addHeapObject(prev), addHeapObject(next)); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r2 = getInt32Memory0()[retptr / 4 + 2]; + if (r2) { + throw takeObject(r1); + } + return takeObject(r0); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +} + +/** + * @param {any} val + * @returns {any} + */ +export function flat_merge(val) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + wasm.flat_merge(retptr, addHeapObject(val)); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r2 = getInt32Memory0()[retptr / 4 + 2]; + if (r2) { + throw takeObject(r1); + } + return takeObject(r0); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +} + +/** + * @param {any} val + * @returns {any} + */ +export function compress(val) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + wasm.compress(retptr, addHeapObject(val)); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r2 = getInt32Memory0()[retptr / 4 + 2]; + if (r2) { + throw takeObject(r1); + } + return takeObject(r0); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +} + +/** + * @param {any} val + * @param {any} target + * @returns {any} + */ +export function pow(val, target) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + wasm.pow(retptr, addHeapObject(val), addHeapObject(target)); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r2 = getInt32Memory0()[retptr / 4 + 2]; + if (r2) { + throw takeObject(r1); + } + return takeObject(r0); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + } +} + +/** + * @param {any} password + * @param {any} salt + * @returns {any} + */ +export function argon2(password, salt) { + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + wasm.argon2(retptr, addHeapObject(password), addHeapObject(salt)); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r2 = getInt32Memory0()[retptr / 4 + 2]; + if (r2) { + throw takeObject(r1); + } + return takeObject(r0); + } 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_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_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_is_bigint(arg0) { + const ret = typeof getObject(arg0) === "bigint"; + return ret; +} + +export function __wbindgen_bigint_from_u64(arg0) { + const ret = BigInt.asUintN(64, arg0); + return addHeapObject(ret); +} + +export function __wbindgen_jsval_eq(arg0, arg1) { + const ret = getObject(arg0) === getObject(arg1); + return ret; +} + +export function __wbindgen_error_new(arg0, arg1) { + const ret = new Error(getStringFromWasm0(arg0, arg1)); + return addHeapObject(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_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_5e6d9547403deab8(arg0, arg1) { + const ret = getObject(arg0)[getObject(arg1)]; + return addHeapObject(ret); +} + +export function __wbg_set_841ac57cff3d672b(arg0, arg1, arg2) { + getObject(arg0)[takeObject(arg1)] = takeObject(arg2); +} + +export function __wbg_get_44be0491f933a435(arg0, arg1) { + const ret = getObject(arg0)[arg1 >>> 0]; + return addHeapObject(ret); +} + +export function __wbg_length_fff51ee6522a1a18(arg0) { + const ret = getObject(arg0).length; + return ret; +} + +export function __wbg_new_898a68150f225f2e() { + const ret = new Array(); + return addHeapObject(ret); +} + +export function __wbindgen_is_function(arg0) { + const ret = typeof getObject(arg0) === "function"; + return ret; +} + +export function __wbg_next_526fc47e980da008(arg0) { + const ret = getObject(arg0).next; + return addHeapObject(ret); +} + +export function __wbg_next_ddb3312ca1c4e32a() { + return handleError(function (arg0) { + const ret = getObject(arg0).next(); + return addHeapObject(ret); + }, arguments); +} + +export function __wbg_done_5c1f01fb660d73b5(arg0) { + const ret = getObject(arg0).done; + return ret; +} + +export function __wbg_value_1695675138684bd5(arg0) { + const ret = getObject(arg0).value; + return addHeapObject(ret); +} + +export function __wbg_iterator_97f0c81209c6c35a() { + const ret = Symbol.iterator; + return addHeapObject(ret); +} + +export function __wbg_get_97b561fb56f034b5() { + return handleError(function (arg0, arg1) { + const ret = Reflect.get(getObject(arg0), getObject(arg1)); + return addHeapObject(ret); + }, arguments); +} + +export function __wbg_call_cb65541d95d71282() { + return handleError(function (arg0, arg1) { + const ret = getObject(arg0).call(getObject(arg1)); + return addHeapObject(ret); + }, arguments); +} + +export function __wbg_new_b51585de1b234aff() { + const ret = new Object(); + return addHeapObject(ret); +} + +export function __wbg_set_502d29070ea18557(arg0, arg1, arg2) { + getObject(arg0)[arg1 >>> 0] = takeObject(arg2); +} + +export function __wbg_isArray_4c24b343cb13cfb1(arg0) { + const ret = Array.isArray(getObject(arg0)); + return ret; +} + +export function __wbg_instanceof_ArrayBuffer_39ac22089b74fddb(arg0) { + let result; + try { + result = getObject(arg0) instanceof ArrayBuffer; + } catch { + result = false; + } + const ret = result; + return ret; +} + +export function __wbg_isSafeInteger_bb8e18dd21c97288(arg0) { + const ret = Number.isSafeInteger(getObject(arg0)); + return ret; +} + +export function __wbg_buffer_085ec1f694018c4f(arg0) { + const ret = getObject(arg0).buffer; + return addHeapObject(ret); +} + +export function __wbg_new_8125e318e6245eed(arg0) { + const ret = new Uint8Array(getObject(arg0)); + return addHeapObject(ret); +} + +export function __wbg_set_5cf90238115182c3(arg0, arg1, arg2) { + getObject(arg0).set(getObject(arg1), arg2 >>> 0); +} + +export function __wbg_length_72e2208bbc0efc61(arg0) { + const ret = getObject(arg0).length; + return ret; +} + +export function __wbg_instanceof_Uint8Array_d8d9cb2b8e8ac1d4(arg0) { + let result; + try { + result = getObject(arg0) instanceof Uint8Array; + } catch { + result = false; + } + const ret = result; + return ret; +} + +export function __wbg_new_abda76e883ba8a5f() { + const ret = new Error(); + return addHeapObject(ret); +} + +export function __wbg_stack_658279fe44541cf6(arg0, arg1) { + const ret = getObject(arg1).stack; + 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 __wbg_error_f851667af71bcfc6(arg0, arg1) { + let deferred0_0; + let deferred0_1; + try { + deferred0_0 = arg0; + deferred0_1 = arg1; + console.error(getStringFromWasm0(arg0, arg1)); + } finally { + wasm.__wbindgen_free(deferred0_0, deferred0_1, 1); + } +} + +export function __wbindgen_bigint_get_as_i64(arg0, arg1) { + const v = getObject(arg1); + const ret = typeof v === "bigint" ? v : undefined; + getBigInt64Memory0()[arg0 / 8 + 1] = isLikeNone(ret) ? BigInt(0) : ret; + getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(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); +} diff --git a/packages/system-wasm/pkg/system_wasm_bg.wasm b/packages/system-wasm/pkg/system_wasm_bg.wasm index a5b7b228..ce33b120 100644 Binary files a/packages/system-wasm/pkg/system_wasm_bg.wasm and b/packages/system-wasm/pkg/system_wasm_bg.wasm differ diff --git a/packages/system-wasm/pkg/system_wasm_bg.wasm.d.ts b/packages/system-wasm/pkg/system_wasm_bg.wasm.d.ts index 3071e5fd..b83a0ee8 100644 --- a/packages/system-wasm/pkg/system_wasm_bg.wasm.d.ts +++ b/packages/system-wasm/pkg/system_wasm_bg.wasm.d.ts @@ -6,7 +6,10 @@ export function expand_filter(a: number, b: number): void; export function get_diff(a: number, b: number, c: number): void; export function flat_merge(a: number, b: number): void; export function compress(a: number, b: number): void; +export function pow(a: number, b: number, c: number): void; +export function argon2(a: number, b: number, c: number): void; export function __wbindgen_malloc(a: number, b: number): number; export function __wbindgen_realloc(a: number, b: number, c: number, d: number): number; export function __wbindgen_add_to_stack_pointer(a: number): number; export function __wbindgen_exn_store(a: number): void; +export function __wbindgen_free(a: number, b: number, c: number): void; diff --git a/packages/system-wasm/src/lib.rs b/packages/system-wasm/src/lib.rs index ad46a46a..1343ddbb 100644 --- a/packages/system-wasm/src/lib.rs +++ b/packages/system-wasm/src/lib.rs @@ -1,12 +1,31 @@ +extern crate console_error_panic_hook; + +use argon2::{Argon2}; +use serde::{Deserialize, Serialize}; use crate::filter::{FlatReqFilter, ReqFilter}; use wasm_bindgen::prelude::*; pub mod diff; pub mod filter; pub mod merge; +pub mod pow; + +#[derive(PartialEq, Clone, Serialize, Deserialize)] +pub struct Event { + #[serde(rename = "id", skip_serializing_if = "Option::is_none")] + pub id: Option, + pub kind: i32, + pub created_at: u64, + pub pubkey: String, + pub content: String, + #[serde(rename = "sig", skip_serializing_if = "Option::is_none")] + pub sig: Option, + pub tags: Vec>, +} #[wasm_bindgen] pub fn diff_filters(prev: JsValue, next: JsValue) -> Result { + console_error_panic_hook::set_once(); let prev_parsed: Vec = serde_wasm_bindgen::from_value(prev)?; let next_parsed: Vec = serde_wasm_bindgen::from_value(next)?; let result = diff::diff_filter(&prev_parsed, &next_parsed); @@ -15,6 +34,7 @@ pub fn diff_filters(prev: JsValue, next: JsValue) -> Result { #[wasm_bindgen] pub fn expand_filter(val: JsValue) -> Result { + console_error_panic_hook::set_once(); let parsed: ReqFilter = serde_wasm_bindgen::from_value(val)?; let result: Vec = (&parsed).into(); Ok(serde_wasm_bindgen::to_value(&result)?) @@ -22,6 +42,7 @@ pub fn expand_filter(val: JsValue) -> Result { #[wasm_bindgen] pub fn get_diff(prev: JsValue, next: JsValue) -> Result { + console_error_panic_hook::set_once(); let prev_parsed: Vec = serde_wasm_bindgen::from_value(prev)?; let next_parsed: Vec = serde_wasm_bindgen::from_value(next)?; let expanded_prev: Vec = prev_parsed @@ -44,6 +65,7 @@ pub fn get_diff(prev: JsValue, next: JsValue) -> Result { #[wasm_bindgen] pub fn flat_merge(val: JsValue) -> Result { + console_error_panic_hook::set_once(); let val_parsed: Vec = serde_wasm_bindgen::from_value(val)?; let result = merge::merge::(val_parsed.iter().collect()); Ok(serde_wasm_bindgen::to_value(&result)?) @@ -51,11 +73,31 @@ pub fn flat_merge(val: JsValue) -> Result { #[wasm_bindgen] pub fn compress(val: JsValue) -> Result { + console_error_panic_hook::set_once(); let val_parsed: Vec = serde_wasm_bindgen::from_value(val)?; let result = merge::merge::(val_parsed.iter().collect()); Ok(serde_wasm_bindgen::to_value(&result)?) } +#[wasm_bindgen] +pub fn pow(val: JsValue, target: JsValue) -> Result { + console_error_panic_hook::set_once(); + let mut val_parsed: Event = serde_wasm_bindgen::from_value(val)?; + let target_parsed: u8 = serde_wasm_bindgen::from_value(target)?; + pow::pow(&mut val_parsed, target_parsed); + Ok(serde_wasm_bindgen::to_value(&val_parsed)?) +} + +#[wasm_bindgen] +pub fn argon2(password: JsValue, salt: JsValue) -> Result { + console_error_panic_hook::set_once(); + let password_parsed: String = serde_wasm_bindgen::from_value(password)?; + let salt_parsed: String = serde_wasm_bindgen::from_value(salt)?; + let mut key = [0u8; 32]; + Argon2::default().hash_password_into(password_parsed.as_bytes(), salt_parsed.as_bytes(), &mut key).expect("Failed to generate key"); + Ok(serde_wasm_bindgen::to_value(&hex::encode(key))?) +} + #[cfg(test)] mod tests { use super::*; diff --git a/packages/system-wasm/src/pow.rs b/packages/system-wasm/src/pow.rs new file mode 100644 index 00000000..73b70743 --- /dev/null +++ b/packages/system-wasm/src/pow.rs @@ -0,0 +1,111 @@ +use crate::Event; + +pub fn pow(ev: &mut Event, target: u8) { + let mut ctr = 0u32; + let mut nonce_tag_idx = ev.tags.iter().position(|x| x[0] == "nonce"); + if nonce_tag_idx.is_none() { + nonce_tag_idx = Some(ev.tags.len()); + ev.tags.push(vec!["nonce".to_owned(), ctr.to_string(), target.to_string()]); + } + loop { + ev.tags[nonce_tag_idx.unwrap()][1] = ctr.to_string(); + + let new_id = make_id(ev); + if count_leading_zeros(&new_id) >= target { + ev.id = Some(new_id); + break; + } + + ctr += 1; + } +} + +fn count_leading_zeros(str: &String) -> u8 { + let mut count = 0; + + for x in hex::decode(str).unwrap() { + if x == 0u8 { + count += 8; + } else { + count += x.leading_zeros(); + break; + } + } + + count as u8 +} + +fn make_id(ev: &Event) -> String { + let mut v = "[0,\"".to_owned(); + v.push_str(&ev.pubkey); + v.push_str("\","); + v.push_str(&ev.created_at.to_string()); + v.push(','); + v.push_str(&ev.kind.to_string()); + v.push_str(",["); + v.push_str(ev.tags.iter().map(|x| { + let mut y = "[".to_owned(); + y.push_str(x.iter().map(|z| ["\"", z, "\""].join("")).collect::>().join(",").as_str()); + y.push(']'); + y + }).collect::>().join(",").as_str()); + v.push_str("],\""); + v.push_str(&ev.content); + v.push_str("\"]"); + sha256::digest(v) +} + +#[cfg(test)] +mod tests { + use serde::Deserialize; + use serde_json::json; + use crate::Event; + + #[test] + fn make_id() { + let ev = Event::deserialize(json!({ + "content": "Oh i think it doesnt work until you reload", + "created_at": 1695568849, + "id": "0000051bca8ee62220b34827358dca69284734a2e7420f3c4b814901a531c767", + "kind": 1, + "pubkey": "63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed", + "sig": "0c18bfcde49fd42c7faf93b3ecd7caf10f0414c9ee3234fca96ea0bbb1a805cb2767fc067dc1a743420c499b34c232e19b73beb2f1fe47c18a2856c67bdef983", + "tags": [ + [ + "e", + "ad17146f086345a12583b537daabdf49ccc5cd09e2c0b4816c835f397b693e6b", + "wss://nos.lol/", + "root" + ], + [ + "e", + "72759bf1f525e9715f4e6d22381f53dc4d2ab47d7aaac11340e7fced13e10b11", + "wss://nos.lol/", + "reply" + ], + [ + "p", + "63fe6318dc58583cfe16810f86dd09e18bfd76aabc24a0081ce2856f330504ed" + ], + [ + "p", + "1bc70a0148b3f316da33fe3c89f23e3e71ac4ff998027ec712b905cd24f6a411" + ], + [ + "nonce", + "7403", + "18" + ] + ] + })).ok().unwrap(); + + assert_eq!(super::make_id(&ev), ev.id.unwrap()) + } + + #[test] + fn count_zeros() { + assert_eq!(10u8.leading_zeros(), 4); + assert_eq!(super::count_leading_zeros(&"00".to_owned()), 8); + assert_eq!(super::count_leading_zeros(&"0000051bca8ee62220b34827358dca69284734a2e7420f3c4b814901a531c767".to_owned()), 21) + } +} \ No newline at end of file diff --git a/packages/system/src/event-publisher.ts b/packages/system/src/event-publisher.ts index d4bbb1fa..b2bd0ad4 100644 --- a/packages/system/src/event-publisher.ts +++ b/packages/system/src/event-publisher.ts @@ -71,11 +71,13 @@ export class EventPublisher { } /** - * Apply POW to every event + * Create a copy of this publisher with PoW */ pow(target: number, miner?: PowMiner) { - this.#pow = target; - this.#miner = miner; + const ret = new EventPublisher(this.#signer, this.#pubKey); + ret.#pow = target; + ret.#miner = miner; + return ret; } #eb(k: EventKind) { diff --git a/packages/system/src/pow-util.ts b/packages/system/src/pow-util.ts index aab35f5d..52536e67 100644 --- a/packages/system/src/pow-util.ts +++ b/packages/system/src/pow-util.ts @@ -20,15 +20,7 @@ export function minePow(e: NostrPowEvent, target: number) { e.tags.push(["nonce", ctr.toString(), target.toString()]); } do { - //roll ctr and compute id - const now = Math.floor(new Date().getTime() / 1000); - // reset ctr if timestamp changed, this is not really needed but makes the ctr value smaller - if (now !== e.created_at) { - ctr = 0; - e.created_at = now; - } e.tags[nonceTagIdx][1] = (++ctr).toString(); - e.id = createId(e); } while (countLeadingZeros(e.id) < target);