tinyhmacmd5 0.5.2-es2026 → 0.5.3-es2026

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 CHANGED
@@ -4,9 +4,9 @@ English | [中文](README-zh.md)
4
4
 
5
5
  A tiny, fast and reliable implementation of MD5 and HMAC-MD5 for JavaScript.
6
6
 
7
- [`browser.min.js`](browser.min.js) is only **905 Bytes**.
7
+ [`browser.min.js`](browser.min.js) is only **888 Bytes**.
8
8
 
9
- - **Input type**: `string` (UTF‑8), `Uint8Array` or `Uint8ClampedArray`
9
+ - **Input type**: `string` (UTF‑8), `Uint8Array`, `Uint8ClampedArray`, `Int8Array` or `number[]`
10
10
  - **Output type**: hex `string` or bytes `Uint8Array`
11
11
  - **Supports inputs ≥ 512 MiB**: The input length theoretically supports 0 to 2⁵³-137
12
12
  - **TypeScript‑ready**: [`main.d.ts`](main.d.ts)
@@ -29,20 +29,20 @@ If you need a smaller implementation that targets ECMAScript 2026, see the [`es2
29
29
  $ node scripts/benchmark.mjs && node scripts/test-513MiB.mjs
30
30
  Data length: 104857600 chars (100MiB)
31
31
  --------------------------------------------------
32
- tinyhmacmd5 : 388.45 ms
33
- spark-md5 : 520.13 ms
34
- js-md5 : 480.29 ms
35
- crypto-js : 1661.32 ms
36
- blueimp-md5 : 3749.15 ms
37
- node:crypto : 129.97 ms
32
+ tinyhmacmd5 : 374.04 ms
33
+ spark-md5 : 513.18 ms
34
+ js-md5 : 481.65 ms
35
+ crypto-js : 1667.43 ms
36
+ blueimp-md5 : 3753.25 ms
37
+ node:crypto : 130.88 ms
38
38
  --------------------------------------------------
39
39
  ✅ All pure JS implementations match node:crypto result.
40
40
 
41
41
  --- Pure 513MiB Test (No prior small tests) ---
42
- tinyhmacmd5 HMAC-MD5 timer: 1.867s
43
- node:crypto HMAC-MD5 timer: 548.332ms
44
- tinyhmacmd5 MD5 timer: 1.869s
45
- node:crypto MD5 timer: 551.244ms
42
+ tinyhmacmd5 HMAC-MD5 timer: 1.794s
43
+ node:crypto HMAC-MD5 timer: 550.872ms
44
+ tinyhmacmd5 MD5 timer: 1.786s
45
+ node:crypto MD5 timer: 548.873ms
46
46
  ```
47
47
 
48
48
  CPU: i5-10600KF
@@ -80,21 +80,20 @@ See https://www.jsdelivr.com/package/npm/tinyhmacmd5
80
80
  <script src="https://cdn.jsdelivr.net/npm/tinyhmacmd5@es2026"></script>
81
81
  ```
82
82
 
83
- It will define the `md5` function using `var`.
84
-
85
83
  ### UNPKG
86
84
 
87
85
  ```html
88
86
  <script src="https://unpkg.com/tinyhmacmd5@es2026"></script>
89
87
  ```
90
88
 
91
- It will define the `md5` function using `var`.
89
+ ### cdnjs
90
+
91
+ See https://cdnjs.com/libraries/tinyhmacmd5
92
92
 
93
93
  ### Inline
94
94
 
95
95
  You can embed [`browser.min.js`](browser.min.js) directly into your script.
96
- It will define the `md5` function using `var`.
97
-
96
+ It will define the `md5` function using `var`.
98
97
  If you are concerned that others might not recognize what this is, you can add the following comment:
99
98
 
100
99
  ```js
@@ -145,7 +144,7 @@ md5(Uint8Array.of(1, 2, 3))
145
144
  md5(Uint8Array.of(1, 2, 3), null, true)
146
145
  ```
147
146
 
148
- `ArrayBuffer` must be wrapped in a `Uint8Array` before use as input; otherwise, it will return an incorrect MD5 hash.
147
+ `ArrayBuffer` must be wrapped in a `Uint8Array` before use as input; otherwise, it will return an incorrect MD5 hash `"0123456789abcdeffedcba9876543210"`.
149
148
 
150
149
  ```js
151
150
  let data = new ArrayBuffer(8)
@@ -154,24 +153,24 @@ let data = new ArrayBuffer(8)
154
153
  md5(new Uint8Array(data))
155
154
  ```
156
155
 
157
- You can also input a `Uint8ClampedArray`, which has the same effect as using a `Uint8Array`.
156
+ You can also input `Uint8ClampedArray` or `Int8Array`.
158
157
 
159
158
  ```js
160
159
  // MD5: bytes to hex
161
160
  // returns "5289df737df57326fcdd22597afb1fac"
162
161
  md5(Uint8ClampedArray.of(1, 2, 3))
162
+
163
+ // MD5: bytes to hex
164
+ // returns "915273adf4c4b9b384bc5550b54d6319"
165
+ md5(Int8Array.of(1, -2, 3, -4))
163
166
  ```
164
167
 
165
- **[⚠️Unsafe]**
166
- You can also input a `number[]`, but every element must be an integer in the range `0 ≤ x ≤ 255`; otherwise, it will return an incorrect MD5 hash.
168
+ You can also input a `number[]`, and each item will be converted to a byte.
167
169
 
168
170
  ```js
169
- let data = [0, 1, 127, 255]
170
-
171
171
  // MD5: bytes to hex
172
- // returns "b23d6235d525eed4c4b8d741d4c2a5a1"
173
- //@ts-ignore
174
- md5(data)
172
+ // returns "47e3385934cd3e9abefb2f87c3bd4288"
173
+ md5([0, 1, 127, 255, -9])
175
174
  ```
176
175
 
177
176
  ---
package/browser.min.js CHANGED
@@ -1 +1 @@
1
- {let e=Int32Array,r=Uint8Array,n=new e(64).map((e,r)=>2**32*Math.sin(++r%Math.PI)),t=1&new r(n.buffer)[0],f=e=>e.reverse(),o=(r,t,f=0,o=1732584193,a=271733878,l=e.of(o,~a,~o,a),w=r.length)=>{for(r[w-1]=t/2**29,r[(t-t%4)/4]|=128<<(r[w-2]=t<<3);f<w;f+=16){let{0:e,1:w,2:u,3:h}=l;for(t=o=0;t<16;t+=4)for(;o<4*t+16;w=0|((e+=n[o]+(u^(t>4?t>8?w|~h:w^h:t?h&(w^u):~w&(u^h)))+r[f+(o++*(29521>>t)+(1296>>t)&15)])<<a|e>>>32-a)+(e=h,h=u,u=w))a="',16%).4$+07&*/5".charCodeAt(3&o|t);l[0]+=e,l[1]+=w,l[2]+=u,l[3]+=h}return l},a=(n,o,a=("string"==typeof n?n=(new TextEncoder).encode(n):n).length,l=new e(o+18+(a-(a+8&63))/4),w=new r(l.buffer))=>(w.set(n,4*o),t&&f(w,f(l)),[l,a]);var md5=(n,l,w)=>{var u=null!=l,[h,s]=a(n,16*u);if(u){let[r,n]=a(l,0),t=new e(32),f=16;for(n>64&&(r=o(r,n));f;)t[--f]=1785358954^(h[f]=909522486^r[f]);t.set(o(h,64+s),16),h=t,s=80}return h=o(h,s),u=new r(h.buffer),t&&f(u,f(h)),w?u:u.toHex()}}
1
+ {let e=Int32Array,r=Uint8Array,t=new e(64).map((e,r)=>2**32*Math.sin(++r%Math.PI)),n=1&new r(t.buffer)[0],f=e=>n?e.reverse():e,o=(r,n,f=0,o=1732584193,a=271733878,l=e.of(o,~a,~o,a),w=r.length)=>{for(r[w-1]=n/2**29,r[(n-n%4)/4]|=128<<(r[w-2]=n<<3);f<w;f+=16){let{0:e,1:w,2:u,3:h}=l;for(n=o=0;n<16;n+=4)for(let l=29521>>n,s=1296>>n;o<4*n+16;w=0|((e+=t[o]+(u^(n>4?n>8?w|~h:w^h:n?h&(w^u):~w&(u^h)))+r[f+(o++*l+s&15)])>>>a|e<<32-a)+(e=h,h=u,u=w))a="94/*;72,<50):61+".charCodeAt(3&o|n);l[0]+=e,l[1]+=w,l[2]+=u,l[3]+=h}return l},a=(t,n,o=("string"==typeof t?t=(new TextEncoder).encode(t):t).length,a=new r(n+o+72-(o+8&63)))=>[f(new e(a.buffer),a.set(t,n),f(a)),o];var md5=(t,n,l)=>{var w=null!=n,[u,h]=a(t,64*w);if(w){let[r,t]=a(n,0),f=new e(32);for(t>64&&(r=o(r,t)),t=16;t;)f[--t]=1785358954^(u[t]=909522486^r[t]);f.set(o(u,64+h),16),u=f,h=80}return w=f(new r(f(o(u,h)).buffer)),l?w:w.toHex()}}
package/main.d.ts CHANGED
@@ -11,18 +11,18 @@
11
11
  */
12
12
  declare var md5: {
13
13
  (
14
- data: string | Uint8Array | Uint8ClampedArray,
15
- key?: string | Uint8Array | Uint8ClampedArray | null,
14
+ data: string | Uint8Array | Uint8ClampedArray | Int8Array | number[],
15
+ key?: string | Uint8Array | Uint8ClampedArray | Int8Array | number[] | null,
16
16
  raw?: false
17
17
  ): string;
18
18
  (
19
- data: string | Uint8Array | Uint8ClampedArray,
20
- key: string | Uint8Array | Uint8ClampedArray | null | undefined,
19
+ data: string | Uint8Array | Uint8ClampedArray | Int8Array | number[],
20
+ key: string | Uint8Array | Uint8ClampedArray | Int8Array | number[] | null | undefined,
21
21
  raw: true
22
22
  ): Uint8Array<ArrayBuffer>;
23
23
  (
24
- data: string | Uint8Array | Uint8ClampedArray,
25
- key: string | Uint8Array | Uint8ClampedArray | null | undefined,
24
+ data: string | Uint8Array | Uint8ClampedArray | Int8Array | number[],
25
+ key: string | Uint8Array | Uint8ClampedArray | Int8Array | number[] | null | undefined,
26
26
  raw: boolean
27
27
  ): string | Uint8Array<ArrayBuffer>;
28
28
  };
package/main.js CHANGED
@@ -10,18 +10,17 @@ let K = new $Int32Array(64).map((v, i) => 2 ** 32 * Math.sin(++i % Math.PI))
10
10
  /** is big-endian */
11
11
  let isBE = /** @type {0 | 1} */(new $Uint8Array(K.buffer)[0] & 1)
12
12
 
13
- /** @type {(a: Uint8Array | Int32Array, ...x: any[]) => any} */
14
- let reverse = a => a.reverse()
13
+ /** @type {<T extends { reverse(): T }>(a: T, ..._: any[]) => T} */
14
+ let reverseOnBE = a => isBE ? a.reverse() : a
15
15
 
16
16
  /**
17
- * Calculate the MD5 of an array of little-endian words, and a byte length.
17
+ * Calculate the MD5 of an Int32Array of little-endian words, and a byte length.
18
18
  *
19
- * @param {Int32Array<ArrayBuffer>} x little-endian words
20
- * @param {number} l Byte length
21
- *
22
- * @returns {Int32Array<ArrayBuffer>} MD5 Array
19
+ * @type {(x: Int32Array<ArrayBuffer>, l: number) => Int32Array<ArrayBuffer>}
20
+ * @param x words
21
+ * @param l Byte length
23
22
  */
24
- let wordsMD5 = (
23
+ let wordsMD5 = ((
25
24
  x,
26
25
  l,
27
26
  // var:
@@ -42,6 +41,7 @@ let wordsMD5 = (
42
41
  let { 0: a, 1: b, 2: c, 3: d } = output
43
42
  for (l = j = 0; l < 16; l += 4) {
44
43
  for (
44
+ let mul = 0x7351 >> l, add = 0x0510 >> l
45
45
  ; j < 4 * l + 16
46
46
  ; b = 0 | (
47
47
  (
@@ -56,8 +56,8 @@ let wordsMD5 = (
56
56
  ? d & (b ^ c) // Round 2: G
57
57
  : ~b & (c ^ d) // Round 1: F
58
58
  )) +
59
- x[i + (j++ * (0x7351 >> l) + (0x0510 >> l) & 15)]
60
- )) << cnt | a >>> 32 - cnt // Keep `32 -` so JS engines can recognize bit rotation (ROL/ROR).
59
+ x[i + (j++ * mul + add & 15)]
60
+ )) >>> cnt | a << 32 - cnt // Keep `32 -` so JS engines can recognize bit rotation (ROR).
61
61
  ) + (
62
62
  a = d,
63
63
  d = c,
@@ -65,7 +65,7 @@ let wordsMD5 = (
65
65
  )
66
66
  )
67
67
  ) {
68
- cnt = "',16%).4$+07&*/5".charCodeAt(j & 3 | l)
68
+ cnt = "94/*;72,<50):61+".charCodeAt(j & 3 | l)
69
69
  }
70
70
  }
71
71
  output[0] += a
@@ -74,17 +74,17 @@ let wordsMD5 = (
74
74
  output[3] += d
75
75
  }
76
76
  return output
77
- }
77
+ })
78
+
79
+ /** @typedef {string | Uint8Array | Uint8ClampedArray | Int8Array | number[]} Input */
78
80
 
79
81
  /**
80
- * Convert bytes to an array of little-endian words
82
+ * Convert bytes to an Int32Array of little-endian words
81
83
  *
82
- * @param {*} input
83
- * @param {number} padLen pad int32 length (0 or 16)
84
- *
85
- * @returns {[Int32Array<ArrayBuffer>, number]}
84
+ * @type {(input: Input, padLen: number) => [Int32Array<ArrayBuffer>, number]}
85
+ * @param padLen pad byte-length (0 or 64)
86
86
  */
87
- let inputToWords = (
87
+ let inputToWords = ((
88
88
  input,
89
89
  padLen,
90
90
  // var:
@@ -94,14 +94,16 @@ let inputToWords = (
94
94
  ? input = new TextEncoder().encode(input)
95
95
  : input
96
96
  ).length,
97
- // Using `Array` to process inputs over 512 MiB could throw a `RangeError`,
98
- // so I replaced it with `Int32Array`.
99
- output = new $Int32Array(padLen + 18 + (byteLen - (byteLen + 8 & 63)) / 4),
100
- outputBytes = new $Uint8Array(output.buffer),
101
- ) => (
102
- outputBytes.set(input, padLen * 4),
103
- isBE && reverse(outputBytes, reverse(output)),
104
- [output, byteLen]
97
+ outputBytes = new $Uint8Array(padLen + byteLen + 72 - (byteLen + 8 & 63)),
98
+ ) =>
99
+ [
100
+ reverseOnBE(
101
+ new $Int32Array(outputBytes.buffer),
102
+ outputBytes.set(/** @type {Exclude<Input, string>} */(input), padLen),
103
+ reverseOnBE(outputBytes)
104
+ ),
105
+ byteLen
106
+ ]
105
107
  )
106
108
 
107
109
  /**
@@ -110,8 +112,8 @@ let inputToWords = (
110
112
  * By default, returns the hash as a lowercase hexadecimal string.
111
113
  * If `raw` is true, returns a Uint8Array.
112
114
  *
113
- * @param {string | Uint8Array | Uint8ClampedArray} data The input data to hash. Strings are UTF‑8 encoded.
114
- * @param {string | Uint8Array | Uint8ClampedArray | null} [key] Optional HMAC key. When given, HMAC‑MD5 is calculated instead of plain MD5.
115
+ * @param {Input} data The input data to hash. Strings are UTF‑8 encoded.
116
+ * @param {Input | null} [key] Optional HMAC key. When given, HMAC‑MD5 is calculated instead of plain MD5.
115
117
  * @param {boolean} [raw] If true, the hash is returned as raw bytes (Uint8Array); otherwise, as a hex string.
116
118
  * @returns {string | Uint8Array<ArrayBuffer>} The MD5 (or HMAC‑MD5) digest, either as a hex string or a Uint8Array.
117
119
  */
@@ -119,17 +121,16 @@ let md5 = (data, key, raw) => {
119
121
  // Do not use parameter defaults to declare variables in public functions.
120
122
  /** @type {boolean | Uint8Array<ArrayBuffer>} */
121
123
  var temp = key != null
122
- , [bdata, dataByteLen] = inputToWords(data, /**@type {*}*/(temp) * 16)
124
+ , [bdata, dataByteLen] = inputToWords(data, /** @type {*} */(temp) * 64)
123
125
 
124
126
  if (temp) {
125
127
  // HMAC
126
- let [bkey, keyByteLen] = inputToWords(key, 0)
128
+ let [bkey, i] = inputToWords(key, 0)
127
129
  , opad = new $Int32Array(32)
128
- , i = 16
129
- if (keyByteLen > 64) {
130
- bkey = wordsMD5(bkey, keyByteLen)
130
+ if (i > 64) {
131
+ bkey = wordsMD5(bkey, i)
131
132
  }
132
- for (; i;) {
133
+ for (i = 16; i;) {
133
134
  // (0x36363636 ^ 0x5c5c5c5c) == 0x6a6a6a6a
134
135
  opad[--i] = 0x6a6a6a6a ^ (bdata[i] = 0x36363636 ^ bkey[i])
135
136
  }
@@ -138,10 +139,13 @@ let md5 = (data, key, raw) => {
138
139
  dataByteLen = 80
139
140
  }
140
141
 
141
- bdata = wordsMD5(bdata, dataByteLen)
142
-
143
- temp = new $Uint8Array(bdata.buffer)
144
- isBE && reverse(temp, reverse(bdata))
142
+ temp = reverseOnBE(
143
+ new $Uint8Array(
144
+ reverseOnBE(
145
+ wordsMD5(bdata, dataByteLen)
146
+ ).buffer
147
+ )
148
+ )
145
149
  return raw
146
150
  ? temp
147
151
  : temp.toHex()
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tinyhmacmd5",
3
- "version": "0.5.2-es2026",
4
- "description": "A tiny (905 Bytes), fast and reliable implementation of MD5 and HMAC-MD5 for JavaScript.",
3
+ "version": "0.5.3-es2026",
4
+ "description": "A tiny (888 Bytes), fast and reliable implementation of MD5 and HMAC-MD5 for JavaScript.",
5
5
  "author": "bddjr",
6
6
  "license": "Unlicense",
7
7
  "type": "module",
@@ -56,10 +56,10 @@
56
56
  "devDependencies": {
57
57
  "blueimp-md5": "^2.19.0",
58
58
  "crypto-js": "^4.2.0",
59
- "es-check": "^9.6.4",
59
+ "es-check": "^9.7.1",
60
60
  "js-md5": "^0.9.2",
61
61
  "spark-md5": "^3.0.2",
62
- "terser": "^5.49.0",
62
+ "terser": "^5.51.2",
63
63
  "tinyhmacmd5": "link:",
64
64
  "typescript": "^7.0.2"
65
65
  },