nappup 1.0.6 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,15 +8,15 @@ import { fileTypeFromFile } from 'file-type'
8
8
  export function parseArgs (args) {
9
9
  let dir = null
10
10
  let sk = null
11
- let appId = null
11
+ let dTag = null
12
12
  let channel = null
13
13
 
14
14
  for (let i = 0; i < args.length; i++) {
15
15
  if (args[i] === '-s' && args[i + 1]) {
16
16
  sk = args[i + 1]
17
17
  i++ // Skip the next argument as it's part of -k
18
- } else if (args[i] === '-i' && args[i + 1]) {
19
- appId = args[i + 1]
18
+ } else if (args[i] === '-d' && args[i + 1]) {
19
+ dTag = args[i + 1]
20
20
  i++
21
21
  } else if (args[i] === '--main' && channel === null) {
22
22
  channel = 'main'
@@ -32,7 +32,7 @@ export function parseArgs (args) {
32
32
  return {
33
33
  dir: path.resolve(dir ?? '.'),
34
34
  sk,
35
- appId,
35
+ dTag,
36
36
  channel: channel || 'main'
37
37
  }
38
38
  }
@@ -11,7 +11,7 @@ import toApp from '#index.js'
11
11
  const args = parseArgs(process.argv.slice(2))
12
12
  await confirmArgs(args)
13
13
 
14
- const { dir, sk, appId, channel } = args
14
+ const { dir, sk, dTag, channel } = args
15
15
  const fileList = await toFileList(getFiles(dir), dir)
16
16
 
17
- await toApp(fileList, await NostrSigner.create(sk), { log: console.log.bind(console), appId, channel })
17
+ await toApp(fileList, await NostrSigner.create(sk), { log: console.log.bind(console), dTag, channel })
package/package.json CHANGED
@@ -6,11 +6,12 @@
6
6
  "url": "git+https://github.com/44billion/nappup.git"
7
7
  },
8
8
  "license": "GPL-3.0-or-later",
9
- "version": "1.0.6",
9
+ "version": "1.0.8",
10
10
  "description": "Nostr App Uploader",
11
11
  "type": "module",
12
12
  "scripts": {
13
- "test": "node --test 'test/**/*.test.js'"
13
+ "test": "node --test 'tests/**/*.test.js'",
14
+ "test:only": "node --test --test-only 'tests/**/*.test.js'"
14
15
  },
15
16
  "bin": {
16
17
  "nappup": "bin/nappup/index.js"
@@ -1,23 +1,26 @@
1
- import { bytesToBase62 } from '#helpers/base62.js'
1
+ import { bytesToBase36 } from '#helpers/base36.js'
2
2
 
3
- export const NOSTR_APP_ID_MAX_LENGTH = 19
3
+ // 63 - (1<channel> + 5<b36loggeduserpkslug> 50<b36pk>)
4
+ // <b36loggeduserpkslug> pk chars at positions [7][17][27][37][47]
5
+ // to avoid vanity or pow colisions
6
+ export const NOSTR_APP_D_TAG_MAX_LENGTH = 7
4
7
 
5
- export function isNostrAppIdSafe (string) {
6
- return isSubdomainSafe(string) && string.length <= NOSTR_APP_ID_MAX_LENGTH
8
+ export function isNostrAppDTagSafe (string) {
9
+ return isSubdomainSafe(string) && string.length <= NOSTR_APP_D_TAG_MAX_LENGTH
7
10
  }
8
11
 
9
12
  function isSubdomainSafe (string) {
10
- return /(?:^[A-Za-z0-9]$)|(?:^(?!.*--)[A-Za-z0-9][A-Za-z0-9-]{0,63}[A-Za-z0-9]$)/.test(string)
13
+ return /(?:^[a-z0-9]$)|(?:^(?!.*--)[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$)/.test(string)
11
14
  }
12
15
 
13
- export function deriveNostrAppId (string) {
14
- return toSubdomainSafe(string, NOSTR_APP_ID_MAX_LENGTH)
16
+ export function deriveNostrAppDTag (string) {
17
+ return toSubdomainSafe(string, NOSTR_APP_D_TAG_MAX_LENGTH)
15
18
  }
16
19
 
17
20
  async function toSubdomainSafe (string, maxStringLength) {
18
- const byteLength = base62MaxLengthToMaxSourceByteLength(maxStringLength)
21
+ const byteLength = baseMaxLengthToMaxSourceByteLength(maxStringLength, 36)
19
22
  const bytes = (await toSha1(string)).slice(0, byteLength)
20
- return bytesToBase62(bytes, maxStringLength)
23
+ return bytesToBase36(bytes, maxStringLength)
21
24
  }
22
25
 
23
26
  async function toSha1 (string) {
@@ -25,12 +28,14 @@ async function toSha1 (string) {
25
28
  return new Uint8Array(await crypto.subtle.digest('SHA-1', bytes))
26
29
  }
27
30
 
28
- // base62MaxLengthToMaxSourceByteLength(19) === 14 byte length
29
- function base62MaxLengthToMaxSourceByteLength (maxStringLength) {
30
- const log62 = Math.log(62)
31
+ // baseMaxLengthToMaxSourceByteLength(19, 62) === 14 byte length
32
+ // baseMaxLengthToMaxSourceByteLength(7, 36) === 4 byte length
33
+ function baseMaxLengthToMaxSourceByteLength (maxStringLength, base) {
34
+ if (!base) throw new Error('Which base?')
35
+ const baseLog = Math.log(base)
31
36
  const log256 = Math.log(256)
32
37
 
33
- const maxByteLength = (maxStringLength * log62) / log256
38
+ const maxByteLength = (maxStringLength * baseLog) / log256
34
39
 
35
40
  return Math.floor(maxByteLength)
36
41
  }
@@ -1,12 +1,13 @@
1
- export function bytesToHex (uint8aBytes) {
1
+ export function bytesToBase16 (uint8aBytes) {
2
2
  return Array.from(uint8aBytes).map(b => b.toString(16).padStart(2, '0')).join('')
3
3
  }
4
4
 
5
- export function hexToBytes (hexString) {
6
- const arr = new Uint8Array(hexString.length / 2) // create result array
5
+ export function base16ToBytes (base16String) {
6
+ if (base16String.length % 2 !== 0) throw new Error('invalid hex: odd length')
7
+ const arr = new Uint8Array(base16String.length / 2) // create result array
7
8
  for (let i = 0; i < arr.length; i++) {
8
9
  const j = i * 2
9
- const h = hexString.slice(j, j + 2)
10
+ const h = base16String.slice(j, j + 2)
10
11
  const b = Number.parseInt(h, 16) // byte, created from string part
11
12
  if (Number.isNaN(b) || b < 0) throw new Error('invalid hex')
12
13
  arr[i] = b
@@ -0,0 +1,68 @@
1
+ import { base16ToBytes, bytesToBase16 } from '#helpers/base16.js'
2
+ import { base62ToBytes, bytesToBase62 } from '#helpers/base62.js'
3
+
4
+ export const BASE36_ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'
5
+ const BASE = BigInt(BASE36_ALPHABET.length)
6
+ const LEADER = BASE36_ALPHABET[0]
7
+ const CHAR_MAP = new Map([...BASE36_ALPHABET].map((char, index) => [char, BigInt(index)]))
8
+
9
+ export function bytesToBase36 (bytes, padLength = 0) {
10
+ return base16ToBase36(bytesToBase16(bytes), padLength)
11
+ }
12
+
13
+ export function base16ToBase36 (hex, padLength = 0) {
14
+ return bigIntToBase36(base16ToBigInt(hex), padLength)
15
+ }
16
+
17
+ export function base62ToBase36 (base62str, padLength = 0) {
18
+ return bytesToBase36(base62ToBytes(base62str), padLength)
19
+ }
20
+
21
+ export function base36ToBytes (base36str) {
22
+ return base16ToBytes(base36ToBase16(base36str))
23
+ }
24
+
25
+ export function base36ToBase16 (base36str) {
26
+ return bigIntToBase16(base36ToBigInt(base36str))
27
+ }
28
+
29
+ export function base36ToBase62 (base36str, padLength = 0) {
30
+ return bytesToBase62(base36ToBytes(base36str), padLength)
31
+ }
32
+
33
+ function base36ToBigInt (base36str) {
34
+ if (typeof base36str !== 'string') {
35
+ throw new Error('Input must be a string.')
36
+ }
37
+
38
+ let result = 0n
39
+ for (const char of base36str) {
40
+ const value = CHAR_MAP.get(char)
41
+ if (value === undefined) {
42
+ throw new Error(`Invalid character in Base36 string: ${char}`)
43
+ }
44
+ result = result * BASE + value
45
+ }
46
+ return result
47
+ }
48
+
49
+ function bigIntToBase36 (num, padLength) {
50
+ if (typeof num !== 'bigint') throw new Error('Input must be a BigInt.')
51
+ if (num < 0n) throw new Error('Can\'t be signed BigInt')
52
+
53
+ return num.toString(36).padStart(padLength, LEADER)
54
+ }
55
+
56
+ function bigIntToBase16 (num) {
57
+ if (typeof num !== 'bigint') throw new Error('Input must be a BigInt.')
58
+ if (num < 0n) throw new Error('Can\'t be signed BigInt')
59
+
60
+ let hexString = num.toString(16)
61
+ if (hexString.length % 2 !== 0) hexString = `0${hexString}`
62
+ return hexString
63
+ }
64
+
65
+ function base16ToBigInt (hex) {
66
+ if (typeof hex !== 'string') throw new Error('Input must be a string.')
67
+ return BigInt(`0x${hex}`)
68
+ }
@@ -1,56 +1,59 @@
1
- import { bytesToHex, hexToBytes } from '#helpers/byte.js'
1
+ export const ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
2
+ const BASE = BigInt(ALPHABET.length)
3
+ const LEADER = ALPHABET[0]
4
+ const CHAR_MAP = new Map([...ALPHABET].map((char, index) => [char, BigInt(index)]))
2
5
 
3
- export function bytesToBase62 (bytes, padLength) {
4
- const hex = bytesToHex(bytes)
5
- return hexToBase62(hex, padLength)
6
- }
7
-
8
- export function hexToBase62 (hex, padLength) {
9
- return bigIntToBase62(BigInt('0x' + hex), padLength)
10
- }
6
+ export function bytesToBase62 (bytes, padLength = 0) {
7
+ if (bytes.length === 0) return ''.padStart(padLength, LEADER)
11
8
 
12
- function bigIntToBase62 (num, padLength = 0) {
13
- const alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
14
- const base = BigInt(alphabet.length)
15
- if (num === 0n) return alphabet[0].padStart(padLength, alphabet[0])
9
+ let num = 0n
10
+ for (const byte of bytes) {
11
+ num = (num << 8n) + BigInt(byte)
12
+ }
16
13
 
17
14
  let result = ''
18
- let currentNum = num
15
+ if (num === 0n) return LEADER.padStart(padLength, LEADER)
16
+
17
+ while (num > 0n) {
18
+ const remainder = num % BASE
19
+ result = ALPHABET[Number(remainder)] + result
20
+ num = num / BASE
21
+ }
22
+
23
+ for (const byte of bytes) {
24
+ if (byte !== 0) break
19
25
 
20
- while (currentNum > 0n) {
21
- const remainder = currentNum % base
22
- result = alphabet[Number(remainder)] + result
23
- currentNum = currentNum / base
26
+ result = LEADER + result
24
27
  }
25
- return result.padStart(padLength, alphabet[0])
28
+
29
+ return result.padStart(padLength, LEADER)
26
30
  }
27
31
 
28
32
  export function base62ToBytes (base62Str) {
29
- const hexString = base62ToHex(base62Str)
30
- return hexToBytes(hexString)
31
- }
33
+ if (typeof base62Str !== 'string') { throw new Error('base62ToBytes requires a string argument') }
34
+ if (base62Str.length === 0) return new Uint8Array()
32
35
 
33
- export function base62ToHex (base62Str, padLength = 64 /* nostr hex key */) {
34
- const bigIntValue = base62ToBigInt(base62Str)
35
- return bigIntValue.toString(16).padStart(padLength, '0')
36
- }
36
+ let leadingZeros = 0
37
+ for (let i = 0; i < base62Str.length; i++) {
38
+ if (base62Str[i] !== LEADER) break
37
39
 
38
- function base62ToBigInt (base62Str) {
39
- const alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
40
- const base = BigInt(alphabet.length)
41
- // Create a lookup map for faster character value retrieval
42
- const charMap = new Map(
43
- [...alphabet].map((char, index) => [char, BigInt(index)])
44
- )
40
+ leadingZeros++
41
+ }
45
42
 
46
- let result = 0n
43
+ let num = 0n
47
44
  for (const char of base62Str) {
48
- const value = charMap.get(char)
49
- if (value === undefined) {
50
- throw new Error(`Invalid character in Base62 string: ${char}`)
51
- }
52
- result = result * base + value
45
+ const value = CHAR_MAP.get(char)
46
+ if (value === undefined) { throw new Error(`Invalid character in Base62 string: ${char}`) }
47
+ num = num * BASE + value
48
+ }
49
+
50
+ const bytes = []
51
+ while (num > 0n) {
52
+ bytes.unshift(Number(num & 0xffn))
53
+ num = num >> 8n
53
54
  }
54
55
 
56
+ const result = new Uint8Array(leadingZeros + bytes.length)
57
+ result.set(bytes, leadingZeros)
55
58
  return result
56
59
  }
@@ -0,0 +1,90 @@
1
+ import { bytesToBase16, base16ToBytes } from '#helpers/base16.js'
2
+ import { bytesToBase62, base62ToBytes, ALPHABET as base62Alphabet } from '#helpers/base62.js'
3
+ import { isNostrAppDTagSafe } from '#helpers/app.js'
4
+
5
+ const MAX_SIZE = 5000
6
+ export const BASE62_ENTITY_REGEX = new RegExp(`^app-[${base62Alphabet}]{,${MAX_SIZE}}$`)
7
+ export const kindByChannel = {
8
+ main: 37448,
9
+ next: 37449,
10
+ draft: 37450
11
+ }
12
+ const channelEnum = Object.keys(kindByChannel)
13
+ const textEncoder = new TextEncoder()
14
+ const textDecoder = new TextDecoder()
15
+
16
+ export function appEncode (ref) {
17
+ if (!isNostrAppDTagSafe(ref.dTag)) { throw new Error('Invalid deduplication tag') }
18
+ const channelIndex = Object.entries(kindByChannel)
19
+ .findIndex(([k, v]) => ref.channel ? k === ref.channel : v === ref.kind)
20
+ if (channelIndex === -1) throw new Error('Wrong channel')
21
+ const tlv = toTlv([
22
+ [textEncoder.encode(ref.dTag)], // type 0 (the array index)
23
+ (ref.relays || []).map(url => textEncoder.encode(url)), // type 1
24
+ [base16ToBytes(ref.pubkey)], // type 2
25
+ [uintToBytes(channelIndex)] // type 3
26
+ ])
27
+ const base62 = bytesToBase62(tlv)
28
+ return `app-${base62}`
29
+ }
30
+
31
+ export function appDecode (entity) {
32
+ const [, base62] = entity.split('-')
33
+ const tlv = tlvToObj(base62ToBytes(base62))
34
+ if (!tlv[0]?.[0]) throw new Error('Missing deduplication tag')
35
+ if (!tlv[2]?.[0]) throw new Error('Missing author pubkey')
36
+ if (tlv[2][0].length !== 32) throw new Error('Author pubkey should be 32 bytes')
37
+ if (!tlv[3]?.[0]) throw new Error('Missing channel enum')
38
+ if (tlv[3][0].length !== 1) throw new Error('Channel enum should be 1 byte')
39
+
40
+ const channel = channelEnum[parseInt(tlv[3][0])]
41
+ return {
42
+ dTag: textDecoder.decode(tlv[0][0]),
43
+ pubkey: bytesToBase16(tlv[2][0]),
44
+ kind: kindByChannel[channel],
45
+ channel,
46
+ relays: tlv[1] ? tlv[1].map(url => textDecoder.decode(url)) : []
47
+ }
48
+ }
49
+
50
+ // Return shortest uint8Array size (not fixed size)
51
+ function uintToBytes (n, bytes = []) {
52
+ do { bytes.unshift(n & 255) } while ((n >>= 8) > 0)
53
+ return new Uint8Array(bytes)
54
+ }
55
+
56
+ function toTlv (tlvConfig) {
57
+ const arrays = []
58
+ tlvConfig
59
+ .map((v, i) => [i, v])
60
+ .reverse() // if the first type is 0, entity always starts with the '0' char
61
+ .forEach(([type, values]) => {
62
+ // just non-empty values will be included
63
+ values.forEach(v => {
64
+ if (v.length > 255) throw new Error('Value is too big')
65
+ const array = new Uint8Array(v.length + 2)
66
+ array.set([type], 0) // t
67
+ array.set([v.length], 1) // l
68
+ array.set(v, 2) // v
69
+ arrays.push(array)
70
+ })
71
+ })
72
+ return new Uint8Array(arrays.reduce((r, v) => [...r, ...v]))
73
+ }
74
+
75
+ // { 0: [t0v0], 1: [t1v0, t1v2], 3: [t3v0] }
76
+ function tlvToObj (tlv) {
77
+ const ret = {}
78
+ let rest = tlv
79
+ let t, l, v
80
+ while (rest.length > 0) {
81
+ t = rest[0]
82
+ l = rest[1]
83
+ v = rest.slice(2, 2 + l)
84
+ rest = rest.slice(2 + l)
85
+ if (v.length < l) throw new Error(`not enough data to read on TLV ${t}`)
86
+ ret[t] ??= []
87
+ ret[t].push(v)
88
+ }
89
+ return ret
90
+ }
package/src/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import NMMR from 'nmmr'
2
- import { naddrEncode } from 'nostr-tools/nip19'
2
+ import { appEncode } from '#helpers/nip19.js'
3
3
  import Base122Encoder from '#services/base122-encoder.js'
4
4
  import nostrRelays from '#services/nostr-relays.js'
5
5
  import NostrSigner from '#services/nostr-signer.js'
6
6
  import { streamToChunks } from '#helpers/stream.js'
7
- import { isNostrAppIdSafe, deriveNostrAppId } from '#helpers/app.js'
7
+ import { isNostrAppDTagSafe, deriveNostrAppDTag } from '#helpers/app.js'
8
8
 
9
9
  export default async function (...args) {
10
10
  try {
@@ -14,18 +14,18 @@ export default async function (...args) {
14
14
  }
15
15
  }
16
16
 
17
- export async function toApp (fileList, nostrSigner, { log = () => {}, appId, channel = 'main' } = {}) {
17
+ export async function toApp (fileList, nostrSigner, { log = () => {}, dTag, channel = 'main' } = {}) {
18
18
  if (!nostrSigner && typeof window !== 'undefined') nostrSigner = window.nostr
19
19
  if (!nostrSigner) throw new Error('No Nostr signer found')
20
20
  if (typeof window !== 'undefined' && nostrSigner === window.nostr) {
21
21
  nostrSigner.getRelays = NostrSigner.prototype.getRelays
22
22
  }
23
23
 
24
- if (typeof appId === 'string') {
25
- if (!isNostrAppIdSafe(appId)) throw new Error('appId should be [A-Za-z0-9] with length ranging from 1 to 19')
24
+ if (typeof dTag === 'string') {
25
+ if (!isNostrAppDTagSafe(dTag)) throw new Error('dTag should be [A-Za-z0-9] with length ranging from 1 to 19')
26
26
  } else {
27
- appId = fileList[0].webkitRelativePath.split('/')[0].trim()
28
- if (!isNostrAppIdSafe(appId)) appId = deriveNostrAppId(appId || Math.random().toString(36))
27
+ dTag = fileList[0].webkitRelativePath.split('/')[0].trim()
28
+ if (!isNostrAppDTagSafe(dTag)) dTag = deriveNostrAppDTag(dTag || Math.random().toString(36))
29
29
  }
30
30
  let nmmr
31
31
  const fileMetadata = []
@@ -53,16 +53,16 @@ export async function toApp (fileList, nostrSigner, { log = () => {}, appId, cha
53
53
  }
54
54
  }
55
55
 
56
- log(`Uploading bundle #${appId}`)
57
- const bundle = await uploadBundle(appId, channel, fileMetadata, nostrSigner)
56
+ log(`Uploading bundle #${dTag}`)
57
+ const bundle = await uploadBundle(dTag, channel, fileMetadata, nostrSigner)
58
58
 
59
- const naddr = naddrEncode({
60
- identifier: bundle.tags.find(v => v[0] === 'd')[1],
59
+ const appEntity = appEncode({
60
+ dTag: bundle.tags.find(v => v[0] === 'd')[1],
61
61
  pubkey: bundle.pubkey,
62
62
  relays: [],
63
63
  kind: bundle.kind
64
64
  })
65
- log(`Visit at https://44billion.net/${naddr}`)
65
+ log(`Visit at https://44billion.net/${appEntity}`)
66
66
  }
67
67
 
68
68
  async function uploadBinaryDataChunks (nmmr, signer, { mimeType } = {}) {
@@ -116,7 +116,7 @@ async function getPreviousCtags (dTagValue, currentCtagValue, writeRelays, signe
116
116
  })
117
117
  }
118
118
 
119
- async function uploadBundle (appId, channel, fileMetadata, signer) {
119
+ async function uploadBundle (dTag, channel, fileMetadata, signer) {
120
120
  const kind = {
121
121
  main: 37448, // stable
122
122
  next: 37449, // insider
@@ -125,7 +125,7 @@ async function uploadBundle (appId, channel, fileMetadata, signer) {
125
125
  const appBundle = {
126
126
  kind,
127
127
  tags: [
128
- ['d', appId],
128
+ ['d', dTag],
129
129
  ...fileMetadata.map(v => ['file', v.rootHash, v.filename, v.mimeType])
130
130
  ],
131
131
  content: '',
@@ -43,7 +43,8 @@ export class NostrRelays {
43
43
  // Disconnect from a relay.
44
44
  async disconnect (url) {
45
45
  if (this.#relays.has(url)) {
46
- await this.#relays.get(url).close()
46
+ const relay = this.#relays.get(url)
47
+ if (relay.ws.readyState < 2) await relay.close().catch(console.log)
47
48
  this.#relays.delete(url)
48
49
  clearTimeout(this.#relayTimeouts.get(url))
49
50
  this.#relayTimeouts.delete(url)
@@ -5,7 +5,7 @@ import * as dotenv from 'dotenv'
5
5
  import { getPublicKey, finalizeEvent } from 'nostr-tools/pure'
6
6
  import { getConversationKey, encrypt, decrypt } from 'nostr-tools/nip44'
7
7
  import nostrRelays, { seedRelays, freeRelays } from '#services/nostr-relays.js'
8
- import { bytesToHex, hexToBytes } from '#helpers/byte.js'
8
+ import { bytesToBase16, base16ToBytes } from '#helpers/base16.js'
9
9
  const __dirname = fileURLToPath(new URL('.', import.meta.url))
10
10
 
11
11
  const dotenvPath = process.env.DOTENV_CONFIG_PATH ?? `${__dirname}/../../.env`
@@ -34,17 +34,17 @@ export default class NostrSigner {
34
34
  }
35
35
 
36
36
  static async create (skHex) {
37
- if (skHex) return new this(createToken, hexToBytes(skHex))
37
+ if (skHex) return new this(createToken, base16ToBytes(skHex))
38
38
 
39
39
  let skBytes
40
40
  let isNewSk = false
41
41
  if (process.env.NOSTR_SECRET_KEY) {
42
- skBytes = hexToBytes(process.env.NOSTR_SECRET_KEY)
42
+ skBytes = base16ToBytes(process.env.NOSTR_SECRET_KEY)
43
43
  } else {
44
44
  isNewSk = true
45
45
  skHex = generateSecretKey()
46
46
  fs.appendFileSync(path.resolve(dotenvPath), `NOSTR_SECRET_KEY=${skHex}\n`)
47
- skBytes = hexToBytes(skHex)
47
+ skBytes = base16ToBytes(skHex)
48
48
  }
49
49
  const ret = new this(createToken, skBytes)
50
50
  if (isNewSk) await ret.#initSk(skHex)
@@ -137,7 +137,7 @@ function generateSecretKey () {
137
137
  const randomBytes = crypto.getRandomValues(new Uint8Array(40))
138
138
  const B256 = 2n ** 256n // secp256k1 is short weierstrass curve
139
139
  const N = B256 - 0x14551231950b75fc4402da1732fc9bebfn // curve (group) order
140
- const bytesToNumber = b => BigInt('0x' + (bytesToHex(b) || '0'))
140
+ const bytesToNumber = b => BigInt('0x' + (bytesToBase16(b) || '0'))
141
141
  const mod = (a, b) => { const r = a % b; return r >= 0n ? r : b + r } // mod division
142
142
  const num = mod(bytesToNumber(randomBytes), N - 1n) + 1n // takes at least n+8 bytes
143
143
  return num.toString(16).padStart(64, '0')
File without changes
File without changes