summaryrefslogtreecommitdiffstats
path: root/src/verify-worker.js
blob: 1f5203f5cb2613bde1bb935c9758b9cb1bfd5614 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
// Off-main-thread nostr crypto. Schnorr signature checks (real secp256k1) on
// a relay backlog blocked the UI on boot / when a community opens — the
// carousel-stutter cause a CPU profile pinned to verifyEvent. This worker
// does that work on another thread; the main thread posts events and gets
// back a boolean per event, so the page never freezes on a burst.
//
// It also carries the other boot secp256k1 the profiler kept pinning:
//  - 'openWraps': community (Concord) wraps — nip44 decrypt under the
//    symmetric stream key + the seal's schnorr verify + hash checks. No
//    secret crosses the thread boundary: the stream conversation key is
//    group material every member derives.
//  - 'unwrapDMs': NIP-17 gift wraps when the wallet holds the raw identity
//    key (seed-derived / pasted nsec) — two ECDH ops + a seal verify each.
//    Remote signers (bunker/extension) can't export their key, so their
//    wraps never come here; the main thread keeps that path.
//
// Bundled to dist/verify-worker.js (see build.js). Same openWrap/unwrapDM/
// verifyEvent the main thread uses, so semantics are identical — this only
// moves WHERE they run.
import { verifyEvent } from 'nostr-tools/pure';
import { hexToBytes } from '@noble/hashes/utils';
import { openWrap } from './concord.js';
import { unwrapDM } from './dm.js';

self.onmessage = async (e) => {
  const { reqId, events, op, wraps, convKey, sk } = e.data || {};
  if (reqId == null) return;
  if (Array.isArray(events)) {
    const results = events.map((ev) => {
      try { return verifyEvent(ev); } catch { return false; }
    });
    self.postMessage({ reqId, results });
    return;
  }
  if (op === 'openWraps' && Array.isArray(wraps)) {
    let stream = null;
    try { stream = { convKey: hexToBytes(convKey) }; } catch {}
    const results = wraps.map((w) => {
      try { return stream ? openWrap(w, stream) : null; } catch { return null; }
    });
    self.postMessage({ reqId, results });
    return;
  }
  if (op === 'unwrapDMs' && Array.isArray(wraps)) {
    let key = null;
    try { key = hexToBytes(sk); } catch {}
    const results = [];
    for (const w of wraps) {
      results.push(key ? await unwrapDM(w, key).catch(() => null) : null);
    }
    self.postMessage({ reqId, results });
    return;
  }
  self.postMessage({ reqId, results: null });
};