tinyrelaycommit

Commit 80f76c966179

browse files at this commit | history

1diff --git a/internal/webui/tiny.js b/internal/webui/tiny.js
2index 6716f3e..748e838 100644
3--- a/internal/webui/tiny.js
4+++ b/internal/webui/tiny.js
5@@ -56,7 +56,37 @@
6 const text = value.replace(/-/g, "+").replace(/_/g, "/") + "===".slice((value.length + 3) % 4);
7 return Uint8Array.from(atob(text), char => char.charCodeAt(0));
8 };
9- tiny.util = Object.freeze({...tiny.util, bytes, hex, sha256, fromHex, element, relayURL, b64url, fromB64url});
10+ // bech32Encode renders bytes as a NIP-19 bare string such as an nsec or
11+ // npub. The browser bundle decodes these but has no plain encoder.
12+ const bech32Charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
13+ const bech32Polymod = values => {
14+ const generators = [0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3];
15+ let checksum = 1;
16+ for (const value of values) {
17+ const top = checksum >>> 25;
18+ checksum = (((checksum & 0x1ffffff) << 5) ^ value) >>> 0;
19+ generators.forEach((generator, index) => { if ((top >>> index) & 1) checksum = (checksum ^ generator) >>> 0; });
20+ }
21+ return checksum;
22+ };
23+ const bech32Encode = (prefix, value) => {
24+ const words = [];
25+ let accumulator = 0, bits = 0;
26+ for (const byte of bytes(value)) {
27+ accumulator = ((accumulator << 8) | byte) >>> 0;
28+ bits += 8;
29+ while (bits >= 5) {
30+ bits -= 5;
31+ words.push((accumulator >>> bits) & 31);
32+ }
33+ }
34+ if (bits > 0) words.push((accumulator << (5 - bits)) & 31);
35+ const expanded = [...prefix].map(char => char.charCodeAt(0) >>> 5).concat(0, [...prefix].map(char => char.charCodeAt(0) & 31));
36+ const polymod = bech32Polymod(expanded.concat(words, [0, 0, 0, 0, 0, 0])) ^ 1;
37+ const checksum = Array.from({length: 6}, (_, index) => (polymod >>> (5 * (5 - index))) & 31);
38+ return prefix + "1" + words.concat(checksum).map(word => bech32Charset[word]).join("");
39+ };
40+ tiny.util = Object.freeze({...tiny.util, bytes, hex, sha256, fromHex, element, relayURL, b64url, fromB64url, bech32Encode});
41 // signer returns the active signer: a resumed remote signer first, then a
42 // NIP-07 extension.
43 tiny.signer = () => globalThis.tinySigner || globalThis.nostr;
44diff --git a/scripts/tiny-namespace.test.mjs b/scripts/tiny-namespace.test.mjs
45index 7b0346d..7f49e6b 100644
46--- a/scripts/tiny-namespace.test.mjs
47+++ b/scripts/tiny-namespace.test.mjs
48@@ -3,6 +3,7 @@ import {webcrypto} from "node:crypto";
49 import {readFile} from "node:fs/promises";
50 import test from "node:test";
51 import vm from "node:vm";
52+import {generateSecretKey, getPublicKey, nip19} from "nostr-tools";
53
54 const read = name => readFile(new URL(`../internal/webui/${name}`, import.meta.url), "utf8");
55 const [tiny, encryption, manifests, upload] = await Promise.all([
56@@ -23,3 +24,19 @@ test("feature modules bootstrap through the shared tiny namespace", () => {
57 vm.runInNewContext(tiny + encryption + manifests + upload, sandbox);
58 assert.equal(typeof sandbox.tiny.blossom.manifests.decodeManifest, "function");
59 });
60+
61+test("bech32Encode matches the reference nsec and npub encodings", () => {
62+ const sandbox = {crypto: webcrypto, TextEncoder, TextDecoder, URL, URLSearchParams, Uint8Array, ArrayBuffer};
63+ sandbox.globalThis = sandbox;
64+ vm.runInNewContext(tiny, sandbox);
65+ const {bech32Encode} = sandbox.tiny.util;
66+ for (let i = 0; i < 8; i++) {
67+ const secret = generateSecretKey();
68+ assert.equal(bech32Encode("nsec", secret), nip19.nsecEncode(secret));
69+ const pubkey = getPublicKey(secret);
70+ assert.equal(bech32Encode("npub", Uint8Array.from(Buffer.from(pubkey, "hex"))), nip19.npubEncode(pubkey));
71+ }
72+ // The NIP-19 example key.
73+ const example = "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d";
74+ assert.equal(bech32Encode("npub", Uint8Array.from(Buffer.from(example, "hex"))), "npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6");
75+});

About

ownerc01503e8035f
visibilitypublic
head80f76c966179

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs