@stll/stdnum 2.0.1 → 2.1.1
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.
- package/README.md +11 -9
- package/dist/_checksums/keccak.d.ts +5 -0
- package/dist/_checksums/keccak.js +118 -0
- package/dist/_checksums/keccak.js.map +1 -0
- package/dist/_checksums/mod112.js.map +1 -1
- package/dist/_checksums/sha256.d.ts +5 -0
- package/dist/_checksums/sha256.js +164 -0
- package/dist/_checksums/sha256.js.map +1 -0
- package/dist/_checksums/verhoeff.js.map +1 -1
- package/dist/_util/arabic.js.map +1 -1
- package/dist/_util/clean.d.ts +6 -1
- package/dist/_util/clean.js +7 -2
- package/dist/_util/clean.js.map +1 -1
- package/dist/_util/date.js.map +1 -1
- package/dist/ad/nrt.js.map +1 -1
- package/dist/ae/eid.js.map +1 -1
- package/dist/ai/tin.js.map +1 -1
- package/dist/al/nipt.js.map +1 -1
- package/dist/am/tin.js.map +1 -1
- package/dist/ar/cbu.js.map +1 -1
- package/dist/ar/cuit.js.map +1 -1
- package/dist/ar/dni.js.map +1 -1
- package/dist/at/businessid.js.map +1 -1
- package/dist/at/vnr.js.map +1 -1
- package/dist/au/abn.js.map +1 -1
- package/dist/au/tfn.js.map +1 -1
- package/dist/az/voen.js.map +1 -1
- package/dist/ba/jmbg.js.map +1 -1
- package/dist/be/bis.js.map +1 -1
- package/dist/be/nn.js.map +1 -1
- package/dist/be/vat.js.map +1 -1
- package/dist/bg/egn.js.map +1 -1
- package/dist/bg/vat.js.map +1 -1
- package/dist/bh/cpr.js.map +1 -1
- package/dist/bic.js.map +1 -1
- package/dist/br/cnpj.js.map +1 -1
- package/dist/br/cpf.js.map +1 -1
- package/dist/by/unp.js.map +1 -1
- package/dist/bz/tin.js.map +1 -1
- package/dist/ch/uid.js.map +1 -1
- package/dist/ch/vat.js.map +1 -1
- package/dist/cl/rut.js.map +1 -1
- package/dist/cn/ric.js.map +1 -1
- package/dist/cn/uscc.js.map +1 -1
- package/dist/cr/cpf.js.map +1 -1
- package/dist/crypto/btcbase58.d.ts +11 -0
- package/dist/crypto/btcbase58.js +76 -0
- package/dist/crypto/btcbase58.js.map +1 -0
- package/dist/crypto/btcbech32.d.ts +19 -0
- package/dist/crypto/btcbech32.js +145 -0
- package/dist/crypto/btcbech32.js.map +1 -0
- package/dist/crypto/eth.d.ts +11 -0
- package/dist/crypto/eth.js +63 -0
- package/dist/crypto/eth.js.map +1 -0
- package/dist/crypto/mod.d.ts +12 -0
- package/dist/crypto/mod.js +16 -0
- package/dist/crypto/mod.js.map +1 -0
- package/dist/crypto/wallet.d.ts +10 -0
- package/dist/crypto/wallet.js +55 -0
- package/dist/crypto/wallet.js.map +1 -0
- package/dist/cu/ni.js.map +1 -1
- package/dist/cz/rc.js.map +1 -1
- package/dist/de/handelsreg.js.map +1 -1
- package/dist/de/idnr.js.map +1 -1
- package/dist/de/stnr.js.map +1 -1
- package/dist/de/svnr.js.map +1 -1
- package/dist/dk/cpr.js.map +1 -1
- package/dist/dk/cvr.js.map +1 -1
- package/dist/dk/vat.js.map +1 -1
- package/dist/do/rnc.js.map +1 -1
- package/dist/ec/ruc.js.map +1 -1
- package/dist/ee/ik.js.map +1 -1
- package/dist/ee/vat.js.map +1 -1
- package/dist/eg/tn.js.map +1 -1
- package/dist/es/dni.js.map +1 -1
- package/dist/es/nie.js.map +1 -1
- package/dist/es/nss.js.map +1 -1
- package/dist/eu/vat.js.map +1 -1
- package/dist/fi/hetu.js.map +1 -1
- package/dist/fi/vat.js.map +1 -1
- package/dist/fi/ytunnus.js.map +1 -1
- package/dist/fr/nif.js.map +1 -1
- package/dist/fr/nir.js.map +1 -1
- package/dist/fr/tva.js.map +1 -1
- package/dist/gb/mod.d.ts +3 -2
- package/dist/gb/mod.js +3 -1
- package/dist/gb/mod.js.map +1 -1
- package/dist/gb/nhs.d.ts +11 -0
- package/dist/gb/nhs.js +51 -0
- package/dist/gb/nhs.js.map +1 -0
- package/dist/gb/nino.js.map +1 -1
- package/dist/gb/sedol.js.map +1 -1
- package/dist/gb/utr.js.map +1 -1
- package/dist/gb/vat.js.map +1 -1
- package/dist/ge/pin.js.map +1 -1
- package/dist/gh/tin.js.map +1 -1
- package/dist/gr/amka.js.map +1 -1
- package/dist/gt/nit.js.map +1 -1
- package/dist/hk/hkid.js.map +1 -1
- package/dist/hu/vat.js.map +1 -1
- package/dist/iban.js.map +1 -1
- package/dist/id/npwp.js.map +1 -1
- package/dist/ie/pps.js.map +1 -1
- package/dist/ie/vat.js.map +1 -1
- package/dist/il/idnr.js.map +1 -1
- package/dist/in/aadhaar.js.map +1 -1
- package/dist/in/gstin.js.map +1 -1
- package/dist/in/pan.js.map +1 -1
- package/dist/index.d.ts +76 -75
- package/dist/index.js +2 -1
- package/dist/ir/nid.js.map +1 -1
- package/dist/is/kennitala.js.map +1 -1
- package/dist/isin.js.map +1 -1
- package/dist/it/codicefiscale.js.map +1 -1
- package/dist/it/iva.js.map +1 -1
- package/dist/kr/rrn.js.map +1 -1
- package/dist/kw/civil.js.map +1 -1
- package/dist/kz/iin.js.map +1 -1
- package/dist/lei.js.map +1 -1
- package/dist/li/peid.js.map +1 -1
- package/dist/lk/nic.js.map +1 -1
- package/dist/lt/asmens.js.map +1 -1
- package/dist/lt/vat.js.map +1 -1
- package/dist/lu/vat.js.map +1 -1
- package/dist/lv/vat.js.map +1 -1
- package/dist/ma/ice.js.map +1 -1
- package/dist/mc/tva.js.map +1 -1
- package/dist/mt/vat.js.map +1 -1
- package/dist/mu/brn.js.map +1 -1
- package/dist/mx/clabe.js.map +1 -1
- package/dist/mx/curp.js.map +1 -1
- package/dist/mx/rfc.js.map +1 -1
- package/dist/my/nric.js.map +1 -1
- package/dist/ni/ruc.js.map +1 -1
- package/dist/nl/bsn.js.map +1 -1
- package/dist/nl/vat.js.map +1 -1
- package/dist/no/fodselsnummer.js.map +1 -1
- package/dist/no/mva.js.map +1 -1
- package/dist/no/orgnr.js.map +1 -1
- package/dist/nz/ird.js.map +1 -1
- package/dist/pa/ruc.js.map +1 -1
- package/dist/patterns.js.map +1 -1
- package/dist/pe/ruc.js.map +1 -1
- package/dist/pl/pesel.js.map +1 -1
- package/dist/pl/regon.js.map +1 -1
- package/dist/pt/cc.js.map +1 -1
- package/dist/ro/cnp.js.map +1 -1
- package/dist/ro/vat.js.map +1 -1
- package/dist/rs/pib.js.map +1 -1
- package/dist/ru/inn.js.map +1 -1
- package/dist/se/personnummer.js.map +1 -1
- package/dist/sg/uen.js.map +1 -1
- package/dist/si/emso.js.map +1 -1
- package/dist/si/vat.js.map +1 -1
- package/dist/sk/dic.js.map +1 -1
- package/dist/tw/ubn.js.map +1 -1
- package/dist/ua/edrpou.js.map +1 -1
- package/dist/us/itin.js.map +1 -1
- package/dist/us/rtn.js.map +1 -1
- package/dist/us/ssn.js.map +1 -1
- package/dist/uy/rut.js.map +1 -1
- package/dist/ve/rif.js.map +1 -1
- package/dist/vn/mst.js.map +1 -1
- package/dist/za/idnr.js.map +1 -1
- package/package.json +31 -6
- package/src/_checksums/keccak.ts +145 -0
- package/src/_checksums/sha256.ts +125 -0
- package/src/_util/clean.ts +7 -2
- package/src/crypto/btcbase58.ts +144 -0
- package/src/crypto/btcbech32.ts +210 -0
- package/src/crypto/eth.ts +114 -0
- package/src/crypto/mod.ts +4 -0
- package/src/crypto/wallet.ts +67 -0
- package/src/gb/mod.ts +1 -0
- package/src/gb/nhs.ts +92 -0
- package/src/index.ts +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stll/stdnum",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Validate, compact, and format standard identifiers for Node.js and Bun. Pure TypeScript, zero dependencies, tree-shakeable per identifier.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"credit-card",
|
|
@@ -247,6 +247,26 @@
|
|
|
247
247
|
"import": "./dist/creditcard.js",
|
|
248
248
|
"default": "./dist/creditcard.js"
|
|
249
249
|
},
|
|
250
|
+
"./crypto/btcbase58": {
|
|
251
|
+
"types": "./dist/crypto/btcbase58.d.ts",
|
|
252
|
+
"import": "./dist/crypto/btcbase58.js",
|
|
253
|
+
"default": "./dist/crypto/btcbase58.js"
|
|
254
|
+
},
|
|
255
|
+
"./crypto/btcbech32": {
|
|
256
|
+
"types": "./dist/crypto/btcbech32.d.ts",
|
|
257
|
+
"import": "./dist/crypto/btcbech32.js",
|
|
258
|
+
"default": "./dist/crypto/btcbech32.js"
|
|
259
|
+
},
|
|
260
|
+
"./crypto/eth": {
|
|
261
|
+
"types": "./dist/crypto/eth.d.ts",
|
|
262
|
+
"import": "./dist/crypto/eth.js",
|
|
263
|
+
"default": "./dist/crypto/eth.js"
|
|
264
|
+
},
|
|
265
|
+
"./crypto/wallet": {
|
|
266
|
+
"types": "./dist/crypto/wallet.d.ts",
|
|
267
|
+
"import": "./dist/crypto/wallet.js",
|
|
268
|
+
"default": "./dist/crypto/wallet.js"
|
|
269
|
+
},
|
|
250
270
|
"./cu/ni": {
|
|
251
271
|
"types": "./dist/cu/ni.d.ts",
|
|
252
272
|
"import": "./dist/cu/ni.js",
|
|
@@ -412,6 +432,11 @@
|
|
|
412
432
|
"import": "./dist/fr/tva.js",
|
|
413
433
|
"default": "./dist/fr/tva.js"
|
|
414
434
|
},
|
|
435
|
+
"./gb/nhs": {
|
|
436
|
+
"types": "./dist/gb/nhs.d.ts",
|
|
437
|
+
"import": "./dist/gb/nhs.js",
|
|
438
|
+
"default": "./dist/gb/nhs.js"
|
|
439
|
+
},
|
|
415
440
|
"./gb/nino": {
|
|
416
441
|
"types": "./dist/gb/nino.d.ts",
|
|
417
442
|
"import": "./dist/gb/nino.js",
|
|
@@ -925,7 +950,7 @@
|
|
|
925
950
|
"@brazilian-utils/brazilian-utils": "^2.3.0",
|
|
926
951
|
"@stll/oxlint-config": "^0.3.0",
|
|
927
952
|
"@stll/typescript-config": "^0.3.0",
|
|
928
|
-
"@types/node": "^25.9.
|
|
953
|
+
"@types/node": "^25.9.2",
|
|
929
954
|
"bun-types": "^1.3.14",
|
|
930
955
|
"fast-check": "^4.8.0",
|
|
931
956
|
"fast-luhn": "^2.0.2",
|
|
@@ -933,13 +958,13 @@
|
|
|
933
958
|
"ibantools": "^4.5.4",
|
|
934
959
|
"jsvat": "^2.5.4",
|
|
935
960
|
"luhn": "^2.4.1",
|
|
936
|
-
"oxfmt": "^0.
|
|
961
|
+
"oxfmt": "^0.53.0",
|
|
937
962
|
"oxlint": "^1.67.0",
|
|
938
963
|
"oxlint-tsgolint": "^0.23.0",
|
|
939
964
|
"rut.js": "^2.1.0",
|
|
940
|
-
"stdnum": "^1.
|
|
941
|
-
"tsdown": "0.22.
|
|
942
|
-
"typescript": "^
|
|
965
|
+
"stdnum": "^1.12.0",
|
|
966
|
+
"tsdown": "0.22.2",
|
|
967
|
+
"typescript": "^6.0.3",
|
|
943
968
|
"validate-polish": "^2.1.40"
|
|
944
969
|
},
|
|
945
970
|
"engines": {
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
const MASK_64 = (1n << 64n) - 1n;
|
|
2
|
+
|
|
3
|
+
const ROUND_CONSTANTS = [
|
|
4
|
+
0x0000000000000001n,
|
|
5
|
+
0x0000000000008082n,
|
|
6
|
+
0x800000000000808an,
|
|
7
|
+
0x8000000080008000n,
|
|
8
|
+
0x000000000000808bn,
|
|
9
|
+
0x0000000080000001n,
|
|
10
|
+
0x8000000080008081n,
|
|
11
|
+
0x8000000000008009n,
|
|
12
|
+
0x000000000000008an,
|
|
13
|
+
0x0000000000000088n,
|
|
14
|
+
0x0000000080008009n,
|
|
15
|
+
0x000000008000000an,
|
|
16
|
+
0x000000008000808bn,
|
|
17
|
+
0x800000000000008bn,
|
|
18
|
+
0x8000000000008089n,
|
|
19
|
+
0x8000000000008003n,
|
|
20
|
+
0x8000000000008002n,
|
|
21
|
+
0x8000000000000080n,
|
|
22
|
+
0x000000000000800an,
|
|
23
|
+
0x800000008000000an,
|
|
24
|
+
0x8000000080008081n,
|
|
25
|
+
0x8000000000008080n,
|
|
26
|
+
0x0000000080000001n,
|
|
27
|
+
0x8000000080008008n,
|
|
28
|
+
] as const;
|
|
29
|
+
|
|
30
|
+
const ROTATION_OFFSETS = [
|
|
31
|
+
0, 1, 62, 28, 27, 36, 44, 6, 55, 20, 3, 10, 43, 25, 39,
|
|
32
|
+
41, 45, 15, 21, 8, 18, 2, 61, 56, 14,
|
|
33
|
+
] as const;
|
|
34
|
+
|
|
35
|
+
const RATE_BYTES = 136;
|
|
36
|
+
|
|
37
|
+
const rotl64 = (value: bigint, shift: number): bigint => {
|
|
38
|
+
if (shift === 0) return value & MASK_64;
|
|
39
|
+
const bigShift = BigInt(shift);
|
|
40
|
+
return (
|
|
41
|
+
((value << bigShift) | (value >> (64n - bigShift))) &
|
|
42
|
+
MASK_64
|
|
43
|
+
);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const keccakF1600 = (state: bigint[]): void => {
|
|
47
|
+
const c = Array.from({ length: 5 }, () => 0n);
|
|
48
|
+
const d = Array.from({ length: 5 }, () => 0n);
|
|
49
|
+
const b = Array.from({ length: 25 }, () => 0n);
|
|
50
|
+
|
|
51
|
+
for (const roundConstant of ROUND_CONSTANTS) {
|
|
52
|
+
for (let x = 0; x < 5; x += 1) {
|
|
53
|
+
c[x] =
|
|
54
|
+
(state[x] ?? 0n) ^
|
|
55
|
+
(state[x + 5] ?? 0n) ^
|
|
56
|
+
(state[x + 10] ?? 0n) ^
|
|
57
|
+
(state[x + 15] ?? 0n) ^
|
|
58
|
+
(state[x + 20] ?? 0n);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
for (let x = 0; x < 5; x += 1) {
|
|
62
|
+
d[x] =
|
|
63
|
+
(c[(x + 4) % 5] ?? 0n) ^
|
|
64
|
+
rotl64(c[(x + 1) % 5] ?? 0n, 1);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
for (let y = 0; y < 5; y += 1) {
|
|
68
|
+
for (let x = 0; x < 5; x += 1) {
|
|
69
|
+
const index = x + 5 * y;
|
|
70
|
+
state[index] =
|
|
71
|
+
((state[index] ?? 0n) ^ (d[x] ?? 0n)) & MASK_64;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
for (let y = 0; y < 5; y += 1) {
|
|
76
|
+
for (let x = 0; x < 5; x += 1) {
|
|
77
|
+
const sourceIndex = x + 5 * y;
|
|
78
|
+
const targetIndex = y + 5 * ((2 * x + 3 * y) % 5);
|
|
79
|
+
b[targetIndex] = rotl64(
|
|
80
|
+
state[sourceIndex] ?? 0n,
|
|
81
|
+
ROTATION_OFFSETS[sourceIndex] ?? 0,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
for (let y = 0; y < 5; y += 1) {
|
|
87
|
+
for (let x = 0; x < 5; x += 1) {
|
|
88
|
+
const index = x + 5 * y;
|
|
89
|
+
state[index] =
|
|
90
|
+
((b[index] ?? 0n) ^
|
|
91
|
+
(~(b[((x + 1) % 5) + 5 * y] ?? 0n) &
|
|
92
|
+
(b[((x + 2) % 5) + 5 * y] ?? 0n))) &
|
|
93
|
+
MASK_64;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
state[0] = ((state[0] ?? 0n) ^ roundConstant) & MASK_64;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export const keccak256 = (
|
|
102
|
+
bytes: Uint8Array,
|
|
103
|
+
): Uint8Array => {
|
|
104
|
+
const state = Array.from({ length: 25 }, () => 0n);
|
|
105
|
+
let offset = 0;
|
|
106
|
+
|
|
107
|
+
while (offset + RATE_BYTES <= bytes.length) {
|
|
108
|
+
for (let i = 0; i < RATE_BYTES; i += 1) {
|
|
109
|
+
const lane = Math.floor(i / 8);
|
|
110
|
+
const shift = BigInt((i % 8) * 8);
|
|
111
|
+
state[lane] =
|
|
112
|
+
((state[lane] ?? 0n) ^
|
|
113
|
+
(BigInt(bytes[offset + i] ?? 0) << shift)) &
|
|
114
|
+
MASK_64;
|
|
115
|
+
}
|
|
116
|
+
keccakF1600(state);
|
|
117
|
+
offset += RATE_BYTES;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const block = new Uint8Array(RATE_BYTES);
|
|
121
|
+
block.set(bytes.slice(offset));
|
|
122
|
+
block[bytes.length - offset] = 0x01;
|
|
123
|
+
block[RATE_BYTES - 1] =
|
|
124
|
+
(block[RATE_BYTES - 1] ?? 0) ^ 0x80;
|
|
125
|
+
|
|
126
|
+
for (let i = 0; i < RATE_BYTES; i += 1) {
|
|
127
|
+
const lane = Math.floor(i / 8);
|
|
128
|
+
const shift = BigInt((i % 8) * 8);
|
|
129
|
+
state[lane] =
|
|
130
|
+
((state[lane] ?? 0n) ^
|
|
131
|
+
(BigInt(block[i] ?? 0) << shift)) &
|
|
132
|
+
MASK_64;
|
|
133
|
+
}
|
|
134
|
+
keccakF1600(state);
|
|
135
|
+
|
|
136
|
+
const digest = new Uint8Array(32);
|
|
137
|
+
for (let i = 0; i < digest.length; i += 1) {
|
|
138
|
+
const lane = Math.floor(i / 8);
|
|
139
|
+
const shift = BigInt((i % 8) * 8);
|
|
140
|
+
digest[i] = Number(
|
|
141
|
+
((state[lane] ?? 0n) >> shift) & 0xffn,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
return digest;
|
|
145
|
+
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
const K = new Uint32Array([
|
|
2
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
|
3
|
+
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
4
|
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
|
5
|
+
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
6
|
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
|
7
|
+
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
8
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
|
9
|
+
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
10
|
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
|
11
|
+
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
12
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
|
13
|
+
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
14
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
|
15
|
+
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
16
|
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
|
17
|
+
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
const rotr = (value: number, bits: number): number =>
|
|
21
|
+
(value >>> bits) | (value << (32 - bits));
|
|
22
|
+
|
|
23
|
+
export const sha256 = (bytes: Uint8Array): Uint8Array => {
|
|
24
|
+
const bitLength = bytes.length * 8;
|
|
25
|
+
const messageLength = bytes.length + 1;
|
|
26
|
+
const paddingLength =
|
|
27
|
+
(64 - ((messageLength + 8) % 64)) % 64;
|
|
28
|
+
const totalLength = messageLength + paddingLength + 8;
|
|
29
|
+
const message = new Uint8Array(totalLength);
|
|
30
|
+
message.set(bytes);
|
|
31
|
+
message[bytes.length] = 0x80;
|
|
32
|
+
|
|
33
|
+
const high = Math.floor(bitLength / 0x1_0000_0000);
|
|
34
|
+
const low = bitLength >>> 0;
|
|
35
|
+
message[totalLength - 8] = high >>> 24;
|
|
36
|
+
message[totalLength - 7] = high >>> 16;
|
|
37
|
+
message[totalLength - 6] = high >>> 8;
|
|
38
|
+
message[totalLength - 5] = high;
|
|
39
|
+
message[totalLength - 4] = low >>> 24;
|
|
40
|
+
message[totalLength - 3] = low >>> 16;
|
|
41
|
+
message[totalLength - 2] = low >>> 8;
|
|
42
|
+
message[totalLength - 1] = low;
|
|
43
|
+
|
|
44
|
+
let h0 = 0x6a09e667;
|
|
45
|
+
let h1 = 0xbb67ae85;
|
|
46
|
+
let h2 = 0x3c6ef372;
|
|
47
|
+
let h3 = 0xa54ff53a;
|
|
48
|
+
let h4 = 0x510e527f;
|
|
49
|
+
let h5 = 0x9b05688c;
|
|
50
|
+
let h6 = 0x1f83d9ab;
|
|
51
|
+
let h7 = 0x5be0cd19;
|
|
52
|
+
|
|
53
|
+
const words = new Uint32Array(64);
|
|
54
|
+
|
|
55
|
+
for (let offset = 0; offset < totalLength; offset += 64) {
|
|
56
|
+
for (let i = 0; i < 16; i += 1) {
|
|
57
|
+
const j = offset + i * 4;
|
|
58
|
+
words[i] =
|
|
59
|
+
((message[j] ?? 0) << 24) |
|
|
60
|
+
((message[j + 1] ?? 0) << 16) |
|
|
61
|
+
((message[j + 2] ?? 0) << 8) |
|
|
62
|
+
(message[j + 3] ?? 0);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
for (let i = 16; i < 64; i += 1) {
|
|
66
|
+
const w2 = words[i - 2] ?? 0;
|
|
67
|
+
const w7 = words[i - 7] ?? 0;
|
|
68
|
+
const w15 = words[i - 15] ?? 0;
|
|
69
|
+
const w16 = words[i - 16] ?? 0;
|
|
70
|
+
const s0 = rotr(w15, 7) ^ rotr(w15, 18) ^ (w15 >>> 3);
|
|
71
|
+
const s1 = rotr(w2, 17) ^ rotr(w2, 19) ^ (w2 >>> 10);
|
|
72
|
+
words[i] = (w16 + s0 + w7 + s1) >>> 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
let a = h0;
|
|
76
|
+
let b = h1;
|
|
77
|
+
let c = h2;
|
|
78
|
+
let d = h3;
|
|
79
|
+
let e = h4;
|
|
80
|
+
let f = h5;
|
|
81
|
+
let g = h6;
|
|
82
|
+
let h = h7;
|
|
83
|
+
|
|
84
|
+
for (let i = 0; i < 64; i += 1) {
|
|
85
|
+
const s1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
|
|
86
|
+
const ch = (e & f) ^ (~e & g);
|
|
87
|
+
const temp1 =
|
|
88
|
+
(h + s1 + ch + (K[i] ?? 0) + (words[i] ?? 0)) >>> 0;
|
|
89
|
+
const s0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
|
|
90
|
+
const maj = (a & b) ^ (a & c) ^ (b & c);
|
|
91
|
+
const temp2 = (s0 + maj) >>> 0;
|
|
92
|
+
|
|
93
|
+
h = g;
|
|
94
|
+
g = f;
|
|
95
|
+
f = e;
|
|
96
|
+
e = (d + temp1) >>> 0;
|
|
97
|
+
d = c;
|
|
98
|
+
c = b;
|
|
99
|
+
b = a;
|
|
100
|
+
a = (temp1 + temp2) >>> 0;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
h0 = (h0 + a) >>> 0;
|
|
104
|
+
h1 = (h1 + b) >>> 0;
|
|
105
|
+
h2 = (h2 + c) >>> 0;
|
|
106
|
+
h3 = (h3 + d) >>> 0;
|
|
107
|
+
h4 = (h4 + e) >>> 0;
|
|
108
|
+
h5 = (h5 + f) >>> 0;
|
|
109
|
+
h6 = (h6 + g) >>> 0;
|
|
110
|
+
h7 = (h7 + h) >>> 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const digest = new Uint8Array(32);
|
|
114
|
+
const hash = [h0, h1, h2, h3, h4, h5, h6, h7];
|
|
115
|
+
for (let i = 0; i < hash.length; i += 1) {
|
|
116
|
+
const value = hash[i] ?? 0;
|
|
117
|
+
const j = i * 4;
|
|
118
|
+
digest[j] = value >>> 24;
|
|
119
|
+
digest[j + 1] = value >>> 16;
|
|
120
|
+
digest[j + 2] = value >>> 8;
|
|
121
|
+
digest[j + 3] = value;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return digest;
|
|
125
|
+
};
|
package/src/_util/clean.ts
CHANGED
|
@@ -63,7 +63,12 @@ const CHAR_REGEX = new RegExp(
|
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
65
|
* Normalize Unicode artifacts to ASCII
|
|
66
|
-
* equivalents
|
|
66
|
+
* equivalents, strip the given characters, and
|
|
67
|
+
* remove surrounding whitespace.
|
|
68
|
+
*
|
|
69
|
+
* The trailing trim removes whitespace outside the
|
|
70
|
+
* separator set (newlines, tabs) so validators
|
|
71
|
+
* accept copy-pasted input.
|
|
67
72
|
*
|
|
68
73
|
* @param value - The input string
|
|
69
74
|
* @param strip - Characters to remove
|
|
@@ -82,5 +87,5 @@ export const clean = (
|
|
|
82
87
|
result = result.replaceAll(ch, "");
|
|
83
88
|
}
|
|
84
89
|
}
|
|
85
|
-
return result;
|
|
90
|
+
return result.trim();
|
|
86
91
|
};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bitcoin Base58Check address.
|
|
3
|
+
*
|
|
4
|
+
* Validates legacy mainnet P2PKH and P2SH Bitcoin
|
|
5
|
+
* addresses, including the double-SHA-256 checksum.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
GlobalValidator,
|
|
10
|
+
ValidateResult,
|
|
11
|
+
} from "../types";
|
|
12
|
+
|
|
13
|
+
import { sha256 } from "#checksums/sha256";
|
|
14
|
+
import { clean } from "#util/clean";
|
|
15
|
+
import { err } from "#util/result";
|
|
16
|
+
|
|
17
|
+
const BASE58_ALPHABET =
|
|
18
|
+
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
19
|
+
|
|
20
|
+
const MIN_LENGTH = 26;
|
|
21
|
+
const MAX_LENGTH = 35;
|
|
22
|
+
const DECODED_ADDRESS_LENGTH = 25;
|
|
23
|
+
const CHECKSUM_LENGTH = 4;
|
|
24
|
+
const MAINNET_P2PKH_VERSION = 0x00;
|
|
25
|
+
const MAINNET_P2SH_VERSION = 0x05;
|
|
26
|
+
|
|
27
|
+
const compact = (value: string): string =>
|
|
28
|
+
clean(value, " ");
|
|
29
|
+
|
|
30
|
+
const decodeBase58 = (value: string): Uint8Array | null => {
|
|
31
|
+
let decoded = 0n;
|
|
32
|
+
for (const ch of value) {
|
|
33
|
+
const digit = BASE58_ALPHABET.indexOf(ch);
|
|
34
|
+
if (digit === -1) return null;
|
|
35
|
+
decoded = decoded * 58n + BigInt(digit);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const bytes: number[] = [];
|
|
39
|
+
while (decoded > 0n) {
|
|
40
|
+
bytes.push(Number(decoded & 0xffn));
|
|
41
|
+
decoded >>= 8n;
|
|
42
|
+
}
|
|
43
|
+
bytes.reverse();
|
|
44
|
+
|
|
45
|
+
let leadingZeros = 0;
|
|
46
|
+
while (value.charAt(leadingZeros) === "1") {
|
|
47
|
+
leadingZeros += 1;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const result = new Uint8Array(
|
|
51
|
+
leadingZeros + bytes.length,
|
|
52
|
+
);
|
|
53
|
+
result.set(bytes, leadingZeros);
|
|
54
|
+
return result;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const hasValidChecksum = (decoded: Uint8Array): boolean => {
|
|
58
|
+
if (decoded.length <= CHECKSUM_LENGTH) return false;
|
|
59
|
+
|
|
60
|
+
const payload = decoded.slice(0, -CHECKSUM_LENGTH);
|
|
61
|
+
const checksum = decoded.slice(-CHECKSUM_LENGTH);
|
|
62
|
+
const digest = sha256(sha256(payload));
|
|
63
|
+
|
|
64
|
+
for (let i = 0; i < CHECKSUM_LENGTH; i += 1) {
|
|
65
|
+
if (checksum[i] !== digest[i]) return false;
|
|
66
|
+
}
|
|
67
|
+
return true;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const validate = (value: string): ValidateResult => {
|
|
71
|
+
const v = compact(value);
|
|
72
|
+
if (v.length < MIN_LENGTH || v.length > MAX_LENGTH) {
|
|
73
|
+
return err(
|
|
74
|
+
"INVALID_LENGTH",
|
|
75
|
+
"Bitcoin Base58Check address must be 26-35 characters",
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
if (!/^[13]/.test(v)) {
|
|
79
|
+
return err(
|
|
80
|
+
"INVALID_COMPONENT",
|
|
81
|
+
"Bitcoin Base58Check address must start with 1 or 3",
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const decoded = decodeBase58(v);
|
|
86
|
+
if (decoded === null) {
|
|
87
|
+
return err(
|
|
88
|
+
"INVALID_FORMAT",
|
|
89
|
+
"Bitcoin Base58Check address contains invalid characters",
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
if (decoded.length !== DECODED_ADDRESS_LENGTH) {
|
|
93
|
+
return err(
|
|
94
|
+
"INVALID_LENGTH",
|
|
95
|
+
"Bitcoin Base58Check address decoded payload must be 25 bytes",
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const version = decoded[0];
|
|
100
|
+
if (
|
|
101
|
+
version !== MAINNET_P2PKH_VERSION &&
|
|
102
|
+
version !== MAINNET_P2SH_VERSION
|
|
103
|
+
) {
|
|
104
|
+
return err(
|
|
105
|
+
"INVALID_COMPONENT",
|
|
106
|
+
"Bitcoin Base58Check address has an unsupported version",
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!hasValidChecksum(decoded)) {
|
|
111
|
+
return err(
|
|
112
|
+
"INVALID_CHECKSUM",
|
|
113
|
+
"Bitcoin Base58Check address fails checksum validation",
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return { valid: true, compact: v };
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
const format = (value: string): string => compact(value);
|
|
121
|
+
|
|
122
|
+
const btcBase58: GlobalValidator = {
|
|
123
|
+
scope: "global",
|
|
124
|
+
name: "Bitcoin Base58Check Address",
|
|
125
|
+
localName: "Bitcoin Base58Check Address",
|
|
126
|
+
abbreviation: "BTC",
|
|
127
|
+
aliases: [
|
|
128
|
+
"Bitcoin address",
|
|
129
|
+
"Bitcoin legacy address",
|
|
130
|
+
"Base58Check address",
|
|
131
|
+
] as const,
|
|
132
|
+
candidatePattern: "[13][1-9A-HJ-NP-Za-km-z]{25,34}",
|
|
133
|
+
entityType: "any",
|
|
134
|
+
examples: [
|
|
135
|
+
"1BoatSLRHtKNngkdXEeobR76b53LETtpyT",
|
|
136
|
+
"3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy",
|
|
137
|
+
] as const,
|
|
138
|
+
compact,
|
|
139
|
+
format,
|
|
140
|
+
validate,
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export default btcBase58;
|
|
144
|
+
export { compact, decodeBase58, format, validate };
|