@bsv/sdk 1.9.23 → 1.9.24
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/dist/cjs/package.json +1 -1
- package/dist/cjs/src/primitives/Hash.js +70 -5
- package/dist/cjs/src/primitives/Hash.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/primitives/Hash.js +68 -6
- package/dist/esm/src/primitives/Hash.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/primitives/Hash.d.ts +47 -0
- package/dist/types/src/primitives/Hash.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +3 -3
- package/dist/umd/bundle.js.map +1 -1
- package/package.json +1 -1
- package/src/primitives/Hash.ts +72 -7
- package/src/primitives/__tests/Hash.test.ts +62 -10
package/package.json
CHANGED
package/src/primitives/Hash.ts
CHANGED
|
@@ -282,13 +282,15 @@ export function toArray (
|
|
|
282
282
|
return res
|
|
283
283
|
}
|
|
284
284
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
285
|
+
/**
|
|
286
|
+
* @deprecated
|
|
287
|
+
* This function behaves differently from the standard C `htonl()`.
|
|
288
|
+
* It always performs an unconditional 32-bit byte swap.
|
|
289
|
+
* Use `swapBytes32()` for explicit byte swapping, or `realHtonl()` for
|
|
290
|
+
* standards-compliant host-to-network conversion.
|
|
291
|
+
*/
|
|
292
|
+
export function htonl (w: number): number {
|
|
293
|
+
return swapBytes32(w)
|
|
292
294
|
}
|
|
293
295
|
|
|
294
296
|
function toHex32 (msg: number[], endian?: 'little' | 'big'): string {
|
|
@@ -1857,3 +1859,66 @@ export function pbkdf2 (
|
|
|
1857
1859
|
const out = pbkdf2Fast(p, s, iterations, keylen)
|
|
1858
1860
|
return Array.from(out)
|
|
1859
1861
|
}
|
|
1862
|
+
|
|
1863
|
+
/**
|
|
1864
|
+
* Unconditionally swaps the byte order of a 32-bit unsigned integer.
|
|
1865
|
+
*
|
|
1866
|
+
* This function performs a strict 32-bit byte swap regardless of host
|
|
1867
|
+
* endianness. It is equivalent to the behavior commonly referred to as
|
|
1868
|
+
* `bswap32` in low-level libraries.
|
|
1869
|
+
*
|
|
1870
|
+
* This function is introduced as part of TOB-20 to provide a clearly-named
|
|
1871
|
+
* alternative to `htonl()`, which was previously implemented as an
|
|
1872
|
+
* unconditional byte swap and did not match the semantics of the traditional
|
|
1873
|
+
* C `htonl()` function.
|
|
1874
|
+
*
|
|
1875
|
+
* @param w - A 32-bit unsigned integer.
|
|
1876
|
+
* @returns The value with its byte order reversed.
|
|
1877
|
+
*
|
|
1878
|
+
* @example
|
|
1879
|
+
* swapBytes32(0x11223344) // → 0x44332211
|
|
1880
|
+
*/
|
|
1881
|
+
export function swapBytes32 (w: number): number {
|
|
1882
|
+
const res =
|
|
1883
|
+
(w >>> 24) |
|
|
1884
|
+
((w >>> 8) & 0xff00) |
|
|
1885
|
+
((w << 8) & 0xff0000) |
|
|
1886
|
+
((w & 0xff) << 24)
|
|
1887
|
+
return res >>> 0
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
// Detect the host machine's endianness at runtime.
|
|
1891
|
+
//
|
|
1892
|
+
// This is used by `realHtonl()` to determine whether the value must be
|
|
1893
|
+
// byte-swapped or returned unchanged. JavaScript engines on common platforms
|
|
1894
|
+
// are almost always little-endian, but this check is included for correctness.
|
|
1895
|
+
const isLittleEndian = (() => {
|
|
1896
|
+
const b = new ArrayBuffer(4)
|
|
1897
|
+
const a = new Uint32Array(b)
|
|
1898
|
+
const c = new Uint8Array(b)
|
|
1899
|
+
a[0] = 0x01020304
|
|
1900
|
+
return c[0] === 0x04
|
|
1901
|
+
})()
|
|
1902
|
+
|
|
1903
|
+
/**
|
|
1904
|
+
* Converts a 32-bit unsigned integer from host byte order to network byte order.
|
|
1905
|
+
*
|
|
1906
|
+
* Unlike the legacy `htonl()` implementation (which always swapped bytes),
|
|
1907
|
+
* this function behaves like the traditional C `htonl()`:
|
|
1908
|
+
*
|
|
1909
|
+
* - On **little-endian** machines → performs a byte swap.
|
|
1910
|
+
* - On **big-endian** machines → returns the value unchanged.
|
|
1911
|
+
*
|
|
1912
|
+
* This function is provided to resolve TOB-20, which identified that the
|
|
1913
|
+
* previous `htonl()` implementation had a misleading name and did not match
|
|
1914
|
+
* platform-dependent semantics.
|
|
1915
|
+
*
|
|
1916
|
+
* @param w - A 32-bit unsigned integer.
|
|
1917
|
+
* @returns The value converted to network byte order.
|
|
1918
|
+
*
|
|
1919
|
+
* @example
|
|
1920
|
+
* realHtonl(0x11223344) // → 0x44332211 on little-endian systems
|
|
1921
|
+
*/
|
|
1922
|
+
export function realHtonl (w: number): number {
|
|
1923
|
+
return isLittleEndian ? swapBytes32(w) : (w >>> 0)
|
|
1924
|
+
}
|
|
@@ -105,9 +105,9 @@ describe('Hash', function () {
|
|
|
105
105
|
describe('BaseHash padding and endianness', () => {
|
|
106
106
|
it('encodes length in big-endian for SHA1', () => {
|
|
107
107
|
const sha1 = new (hash as any).SHA1()
|
|
108
|
-
;(sha1
|
|
109
|
-
const pad = (sha1
|
|
110
|
-
const padLength = (sha1
|
|
108
|
+
;(sha1).pendingTotal = 12345
|
|
109
|
+
const pad = (sha1)._pad() as number[]
|
|
110
|
+
const padLength = (sha1).padLength as number
|
|
111
111
|
const lengthBytes = pad.slice(-padLength)
|
|
112
112
|
|
|
113
113
|
const totalBits = BigInt(12345) * 8n
|
|
@@ -123,9 +123,9 @@ describe('Hash', function () {
|
|
|
123
123
|
|
|
124
124
|
it('encodes length in little-endian for RIPEMD160', () => {
|
|
125
125
|
const ripemd = new (hash as any).RIPEMD160()
|
|
126
|
-
;(ripemd
|
|
127
|
-
const pad = (ripemd
|
|
128
|
-
const padLength = (ripemd
|
|
126
|
+
;(ripemd).pendingTotal = 12345
|
|
127
|
+
const pad = (ripemd)._pad() as number[]
|
|
128
|
+
const padLength = (ripemd).padLength as number
|
|
129
129
|
const lengthBytes = pad.slice(-padLength)
|
|
130
130
|
|
|
131
131
|
const totalBits = BigInt(12345) * 8n
|
|
@@ -141,11 +141,11 @@ describe('Hash', function () {
|
|
|
141
141
|
|
|
142
142
|
it('throws when message length exceeds maximum encodable bits', () => {
|
|
143
143
|
const sha1 = new (hash as any).SHA1()
|
|
144
|
-
;(sha1
|
|
145
|
-
;(sha1
|
|
144
|
+
;(sha1).padLength = 1
|
|
145
|
+
;(sha1).pendingTotal = 40
|
|
146
146
|
|
|
147
147
|
expect(() => {
|
|
148
|
-
;(sha1
|
|
148
|
+
;(sha1)._pad()
|
|
149
149
|
}).toThrow(new Error('Message too long for this hash function'))
|
|
150
150
|
})
|
|
151
151
|
})
|
|
@@ -180,7 +180,6 @@ describe('Hash', function () {
|
|
|
180
180
|
})
|
|
181
181
|
|
|
182
182
|
describe('Hash strict length validation (TOB-21)', () => {
|
|
183
|
-
|
|
184
183
|
it('throws when pendingTotal is not a safe integer', () => {
|
|
185
184
|
const h = new SHA1()
|
|
186
185
|
|
|
@@ -201,4 +200,57 @@ describe('Hash', function () {
|
|
|
201
200
|
}).toThrow('Message too long for this hash function')
|
|
202
201
|
})
|
|
203
202
|
})
|
|
203
|
+
|
|
204
|
+
describe('TOB-20 byte-order helper functions', () => {
|
|
205
|
+
const { htonl, swapBytes32, realHtonl } = hash
|
|
206
|
+
|
|
207
|
+
it('swapBytes32 performs a strict 32-bit byte swap', () => {
|
|
208
|
+
expect(swapBytes32(0x11223344)).toBe(0x44332211)
|
|
209
|
+
expect(swapBytes32(0xaabbccdd)).toBe(0xddccbbaa)
|
|
210
|
+
expect(swapBytes32(0x00000000)).toBe(0x00000000)
|
|
211
|
+
expect(swapBytes32(0xffffffff)).toBe(0xffffffff)
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
it('swapBytes32 always returns an unsigned 32-bit integer', () => {
|
|
215
|
+
expect(swapBytes32(-1)).toBe(0xffffffff) // wraps to unsigned
|
|
216
|
+
expect(swapBytes32(0x80000000)).toBe(0x00000080) // MSB becomes LSB
|
|
217
|
+
})
|
|
218
|
+
|
|
219
|
+
it('htonl is now an alias for swapBytes32 (deprecated)', () => {
|
|
220
|
+
expect(htonl(0x11223344)).toBe(swapBytes32(0x11223344))
|
|
221
|
+
expect(htonl(0xaabbccdd)).toBe(swapBytes32(0xaabbccdd))
|
|
222
|
+
})
|
|
223
|
+
|
|
224
|
+
it('realHtonl matches swapBytes32 on little-endian systems', () => {
|
|
225
|
+
// All JS engines used for Node/Jest are little-endian
|
|
226
|
+
expect(realHtonl(0x11223344)).toBe(0x44332211)
|
|
227
|
+
expect(realHtonl(0xaabbccdd)).toBe(0xddccbbaa)
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
it('realHtonl preserves value when system is big-endian (forced simulation)', () => {
|
|
231
|
+
// We simulate the big-endian branch of realHtonl by calling
|
|
232
|
+
// the fallback path directly.
|
|
233
|
+
const forceBigEndianRealHtonl = (w: number) => (w >>> 0)
|
|
234
|
+
|
|
235
|
+
expect(forceBigEndianRealHtonl(0x11223344)).toBe(0x11223344)
|
|
236
|
+
expect(forceBigEndianRealHtonl(0xaabbccdd)).toBe(0xaabbccdd)
|
|
237
|
+
expect(forceBigEndianRealHtonl(0xffffffff)).toBe(0xffffffff >>> 0)
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
it('htonl, swapBytes32, realHtonl never throw for any 32-bit input', () => {
|
|
241
|
+
const inputs = [
|
|
242
|
+
0, 1, -1,
|
|
243
|
+
0x7fffffff,
|
|
244
|
+
0x80000000,
|
|
245
|
+
0xffffffff,
|
|
246
|
+
0x12345678
|
|
247
|
+
]
|
|
248
|
+
|
|
249
|
+
for (const n of inputs) {
|
|
250
|
+
expect(() => htonl(n)).not.toThrow()
|
|
251
|
+
expect(() => swapBytes32(n)).not.toThrow()
|
|
252
|
+
expect(() => realHtonl(n)).not.toThrow()
|
|
253
|
+
}
|
|
254
|
+
})
|
|
255
|
+
})
|
|
204
256
|
})
|