tinyhmacmd5 0.5.0 → 0.5.1-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
@@ -2,9 +2,9 @@ English | [中文](README-zh.md)
2
2
 
3
3
  # Tiny HMAC MD5
4
4
 
5
- A tiny and reliable HMAC-MD5 implementation for JavaScript:
5
+ A tiny, efficient and reliable HMAC-MD5 implementation for JavaScript.
6
6
 
7
- [`browser.min.js`](browser.min.js) is only **979 bytes**.
7
+ [`browser.min.js`](browser.min.js) is only **923 bytes**.
8
8
 
9
9
  - **Input type**: `string` (UTF‑8), `Uint8Array` or `Uint8ClampedArray`
10
10
  - **Output type**: hex `string` or bytes `Uint8Array`
@@ -25,25 +25,23 @@ If you need a smaller implementation that targets ECMAScript 2026, see the [`es2
25
25
  ## Benchmark
26
26
 
27
27
  ```
28
- pnpm benchmark
29
- ```
30
-
31
- ```
28
+ > pnpm benchmark
29
+ $ node scripts/benchmark.mjs && node scripts/test-513MiB.mjs
32
30
  Data length: 104857600 chars (100MiB)
33
31
  --------------------------------------------------
34
- tinyhmacmd5 : 550.92 ms
35
- js-md5 : 128.96 ms
36
- blueimp-md5 : 3837.83 ms
37
- crypto-js : 1562.08 ms
38
- node:crypto : 129.08 ms
32
+ tinyhmacmd5 : 388.35 ms
33
+ js-md5 : 128.71 ms
34
+ blueimp-md5 : 3823.48 ms
35
+ crypto-js : 1553.58 ms
36
+ node:crypto : 129.86 ms
39
37
  --------------------------------------------------
40
38
  ✅ All pure JS implementations match node:crypto result.
41
39
 
42
40
  --- Pure 513MiB Test (No prior small tests) ---
43
- tinyhmacmd5 HMAC-MD5 timer: 2.706s
44
- node:crypto HMAC-MD5 timer: 547.808ms
45
- tinyhmacmd5 MD5 timer: 2.693s
46
- node:crypto MD5 timer: 550.144ms
41
+ tinyhmacmd5 HMAC-MD5 timer: 1.886s
42
+ node:crypto HMAC-MD5 timer: 548.216ms
43
+ tinyhmacmd5 MD5 timer: 1.868s
44
+ node:crypto MD5 timer: 548.352ms
47
45
  ```
48
46
 
49
47
  CPU: i5-10600KF
@@ -62,7 +60,7 @@ As a result, the final size is not the smallest theoretically achievable.
62
60
  ### npm
63
61
 
64
62
  ```
65
- npm i tinyhmacmd5
63
+ npm i tinyhmacmd5@es2026
66
64
  ```
67
65
 
68
66
  ```js
@@ -78,7 +76,7 @@ You can also use other package managers (e.g. `pnpm` or `yarn`) in place of `npm
78
76
  See https://www.jsdelivr.com/package/npm/tinyhmacmd5
79
77
 
80
78
  ```html
81
- <script src="https://cdn.jsdelivr.net/npm/tinyhmacmd5"></script>
79
+ <script src="https://cdn.jsdelivr.net/npm/tinyhmacmd5@es2026"></script>
82
80
  ```
83
81
 
84
82
  It will define the `md5` function using `var`.
@@ -86,7 +84,7 @@ It will define the `md5` function using `var`.
86
84
  ### UNPKG
87
85
 
88
86
  ```html
89
- <script src="https://unpkg.com/tinyhmacmd5"></script>
87
+ <script src="https://unpkg.com/tinyhmacmd5@es2026"></script>
90
88
  ```
91
89
 
92
90
  It will define the `md5` function using `var`.
@@ -96,6 +94,12 @@ It will define the `md5` function using `var`.
96
94
  You can embed [`browser.min.js`](browser.min.js) directly into your script.
97
95
  It will define the `md5` function using `var`.
98
96
 
97
+ If you are concerned that others might not recognize what this is, you can add the following comment:
98
+
99
+ ```js
100
+ // tinyhmacmd5 (The Unlicense)
101
+ ```
102
+
99
103
  ---
100
104
 
101
105
  ## Example
@@ -173,22 +177,22 @@ md5(data)
173
177
 
174
178
  ## Runtime Environment
175
179
 
176
- Environments that support [Exponentiation (`**`)](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Exponentiation) and [`TextEncoder`](https://developer.mozilla.org/docs/Web/API/TextEncoder) :
180
+ Environments that support [`Uint8Array.prototype.toHex()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/toHex) :
177
181
 
178
182
  - Desktop
179
- - Chrome ≥ 52 (2016-07-20)
180
- - Edge ≥ 79 (2020-01-15)
181
- - Firefox ≥ 52 (2017-03-07)
182
- - Opera ≥ 39 (2016-08-02)
183
- - Safari ≥ 10.1 (2017-03-27)
183
+ - Chrome ≥ 140 (2025-09-02)
184
+ - Edge ≥ 140 (2025-09-05)
185
+ - Firefox ≥ 133 (2024-11-26)
186
+ - Opera ≥ 124 (2025-11-13)
187
+ - Safari ≥ 18.2 (2024-12-11)
184
188
  - Mobile
185
- - Chrome Android ≥ 52 (2016-07-27)
186
- - Firefox for Android ≥ 52 (2017-03-07)
187
- - Opera Android ≥ 41 (2016-10-25)
188
- - Safari on iOS ≥ 10.3 (2017-03-27)
189
- - Samsung Browser ≥ 6 (2017-08-23)
190
- - WebView Android ≥ 51 (2016-06-08)
191
- - WebView on iOS ≥ 10.3 (2017-03-27)
189
+ - Chrome Android ≥ 140 (2025-09-02)
190
+ - Firefox for Android ≥ 133 (2024-11-26)
191
+ - Opera Android ≥ 92 (2025-10-08)
192
+ - Safari on iOS ≥ 18.2 (2024-12-11)
193
+ - Samsung Browser ×
194
+ - WebView Android ≥ 140 (2025-09-02)
195
+ - WebView on iOS ≥ 18.2 (2024-12-11)
192
196
 
193
197
  Not recommended for use in environments that support `node:crypto`, as `node:crypto` already provides HMAC-MD5.
194
198
 
@@ -208,3 +212,9 @@ cd tinyhmacmd5
208
212
  pnpm i
209
213
  pnpm test
210
214
  ```
215
+
216
+ ---
217
+
218
+ ##
219
+
220
+ INVINCIBLE EXPERIMENT!
package/browser.min.js CHANGED
@@ -1 +1 @@
1
- {let e=Int32Array,r=Uint8Array,n=new e(64).map((e,r)=>2**32*Math.abs(Math.sin(r+1))),t=1&new r(n.buffer)[3],f=(r,t,f=0,o,a=1732584193,w=271733878,l,u,h=r.length,i=e.of(a,~w,~a,w),s=new e(i))=>{for(r[h-1]=t/2**29,r[(t-t%4)/4]|=128<<(r[h-2]=t<<3);f<h;f+=16){for(t=o=0;t<16;t+=4)for(;o<4*t+16;)i[u&=3]=((w=i[u]+n[o]+(a=i[3&++u],w=i[3&++u],l=i[3&++u],w^(t>4?t>8?a|~l:a^l:t?l&(a^w):~a&(w^l)))+r[f+(o*(29521>>t)+(1296>>t)&15)])<<(l="',16%).4$+07&*/5".charCodeAt(3&o++|t))|w>>>32-l)+a;for(;u;)s[--u]=i[u]+=s[u]}return i},o=(n,f,o=("string"==typeof n?n=(new TextEncoder).encode(n):n).length,a=new e(f+18+(o-(o+8&63))/4),w=t&&new r(a.buffer,4*f).set(n))=>{for(;w<o;3&++w||f++)a[f]|=n[w]<<8*w;return[a,o]};var md5=(n,t,a)=>{var w=16,l=null!=t,[u,h]=o(n,l*w),i=a?new r(w):"";if(l){let[r,n]=o(t,0),a=new e(32);for(n>64&&(r=f(r,n)),n=w;n;)a[--n]=1785358954^(u[n]=909522486^r[n]);a.set(f(u,64+h),w),u=a,h=80}for(u=f(u,h);w;a?i[w]=h:i=(h>>4&&"")+h.toString(16)+i)h=u[--w>>2]>>8*w&255;return i}}
1
+ {let e=Int32Array,r=Uint8Array,n=new e(64).map((e,r)=>2**32*Math.sin(++r%Math.PI)),t=(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},f=(t,f,o=("string"==typeof t?t=(new TextEncoder).encode(t):t).length,a=new e(f+18+(o-(o+8&63))/4),l=1&new r(n.buffer)[3]&&new r(a.buffer,4*f).set(t))=>{for(;l<o;3&++l||f++)a[f]|=t[l]<<8*l;return[a,o]};var md5=(n,o,a)=>{var l=16,w=null!=o,[u,h]=f(n,w*l),d=new r(l);if(w){let[r,n]=f(o,0),a=new e(32);for(n>64&&(r=t(r,n)),n=l;n;)a[--n]=1785358954^(u[n]=909522486^r[n]);a.set(t(u,64+h),l),u=a,h=80}for(u=t(u,h);l;)d[--l]=u[l>>2]>>8*l;return a?d:d.toHex()}}
package/main.js CHANGED
@@ -1,12 +1,11 @@
1
+ // tinyhmacmd5 (The Unlicense)
2
+
1
3
  let $Int32Array = Int32Array
2
4
 
3
5
  let $Uint8Array = Uint8Array
4
6
 
5
7
  /** MD5 constants cached in memory */
6
- let K = new $Int32Array(64).map((v, i) => 2 ** 32 * Math.abs(Math.sin(i + 1)))
7
-
8
- /** is little-endian */
9
- let isLE = new $Uint8Array(K.buffer)[3] & 1
8
+ let K = new $Int32Array(64).map((v, i) => 2 ** 32 * Math.sin(++i % Math.PI))
10
9
 
11
10
  /**
12
11
  * Calculate the MD5 of an array of little-endian words, and a byte length.
@@ -14,10 +13,6 @@ let isLE = new $Uint8Array(K.buffer)[3] & 1
14
13
  * @param {Int32Array<ArrayBuffer>} x little-endian words
15
14
  * @param {number} l Byte length
16
15
  *
17
- * @param {number} [j]
18
- * @param {number} [t2]
19
- * @param {number} [oi]
20
- *
21
16
  * @returns {Int32Array<ArrayBuffer>} MD5 Array
22
17
  */
23
18
  let wordsMD5 = (
@@ -25,14 +20,10 @@ let wordsMD5 = (
25
20
  l,
26
21
  // var:
27
22
  i = 0,
28
- j,
29
- t0 = 1732584193,
30
- t1 = 271733878,
31
- t2,
32
- oi,
23
+ j = 1732584193,
24
+ cnt = 271733878,
25
+ output = $Int32Array.of(j, ~cnt, ~j, cnt),
33
26
  xLen = x.length,
34
- output = $Int32Array.of(t0, ~t1, ~t0, t1),
35
- oldOutput = new $Int32Array(output),
36
27
  ) => {
37
28
  // append padding
38
29
  // `l` may be >= 2**32, so cannot use `>>>` as a replacement for `floor`.
@@ -41,38 +32,40 @@ let wordsMD5 = (
41
32
  x[(l - l % 4) / 4] |= 0x80 << (x[xLen - 2] = l << 3);
42
33
 
43
34
  for (; i < xLen; i += 16) {
35
+ // Avoid array destructuring, as invoking the iterator protocol hurts performance.
36
+ let { 0: a, 1: b, 2: c, 3: d } = output
44
37
  for (l = j = 0; l < 16; l += 4) {
45
- for (; j < 4 * l + 16;) {
46
- output[oi &= 3] = (
38
+ for (
39
+ ; j < 4 * l + 16
40
+ ; b = 0 | (
47
41
  (
48
- t1 = (
49
- output[oi] +
42
+ (a += (
50
43
  K[j] +
51
- (
52
- t0 = output[++oi & 3],
53
- t1 = output[++oi & 3],
54
- t2 = output[++oi & 3],
55
- t1 ^ (
56
- l > 4
57
- ? l > 8
58
- ? t0 | ~t2 // Round 4: I
59
- : t0 ^ t2 // Round 3: H
60
- : l
61
- ? t2 & (t0 ^ t1) // Round 2: G
62
- : ~t0 & (t1 ^ t2) // Round 1: F
63
- )
64
- ) +
65
- x[i + (j * (0x7351 >> l) + (0x0510 >> l) & 15)]
66
- )
67
- ) << (
68
- t2 = "',16%).4$+07&*/5".charCodeAt(j++ & 3 | l)
69
- ) | t1 >>> 32 - t2
70
- ) + t0
44
+ (c ^ (
45
+ l > 4
46
+ ? l > 8
47
+ ? b | ~d // Round 4: I
48
+ : b ^ d // Round 3: H
49
+ : l
50
+ ? d & (b ^ c) // Round 2: G
51
+ : ~b & (c ^ d) // Round 1: F
52
+ )) +
53
+ x[i + (j++ * (0x7351 >> l) + (0x0510 >> l) & 15)]
54
+ )) << cnt | a >>> 32 - cnt // Keep `32 -` so JS engines can recognize bit rotation (ROL/ROR).
55
+ ) + (
56
+ a = d,
57
+ d = c,
58
+ c = b
59
+ )
60
+ )
61
+ ) {
62
+ cnt = "',16%).4$+07&*/5".charCodeAt(j & 3 | l)
71
63
  }
72
64
  }
73
- for (; oi;) {
74
- oldOutput[--oi] = output[oi] += oldOutput[oi]
75
- }
65
+ output[0] += a
66
+ output[1] += b
67
+ output[2] += c
68
+ output[3] += d
76
69
  }
77
70
  return output
78
71
  }
@@ -101,7 +94,7 @@ let inputToWords = (
101
94
  // so I replaced it with `Int32Array`.
102
95
  output = new $Int32Array(j + 18 + (byteLen - (byteLen + 8 & 63)) / 4),
103
96
  // (fast) little-endian
104
- i = isLE && new $Uint8Array(output.buffer, j * 4).set(input),
97
+ i = new $Uint8Array(K.buffer)[3] & 1 && new $Uint8Array(output.buffer, j * 4).set(input),
105
98
  ) => {
106
99
  // (slow) big-endian
107
100
  for (; i < byteLen; ++i & 3 || j++) {
@@ -122,12 +115,11 @@ let inputToWords = (
122
115
  * @returns {string | Uint8Array<ArrayBuffer>} The MD5 (or HMAC‑MD5) digest, either as a hex string or a Uint8Array.
123
116
  */
124
117
  let md5 = (data, key, raw) => {
118
+ // Do not use parameter defaults to declare variables in public functions.
125
119
  var i = 16
126
120
  , hasKey = key != null
127
121
  , [bdata, temp] = inputToWords(data, /**@type {*}*/(hasKey) * i)
128
-
129
- /** @type {*} */
130
- var out = raw ? new $Uint8Array(i) : ''
122
+ , out = new $Uint8Array(i)
131
123
 
132
124
  if (hasKey) {
133
125
  // HMAC
@@ -148,15 +140,11 @@ let md5 = (data, key, raw) => {
148
140
  bdata = wordsMD5(bdata, temp)
149
141
 
150
142
  // words to bytes or hex
151
- for (; i;
152
- raw
153
- ? out[i] = temp
154
- : out = (temp >> 4 && '') + temp.toString(16) + out
155
- ) {
156
- temp = bdata[--i >> 2] >> i * 8 & 0xff
143
+ for (; i;) {
144
+ out[--i] = bdata[i >> 2] >> i * 8
157
145
  }
158
146
 
159
- return out
147
+ return raw ? out : out.toHex()
160
148
  }
161
149
 
162
150
  export default md5
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tinyhmacmd5",
3
- "version": "0.5.0",
4
- "description": "A tiny and reliable HMAC-MD5 implementation for JavaScript: browser.min.js is only 979 bytes.",
3
+ "version": "0.5.1-es2026",
4
+ "description": "A tiny (923 Bytes), efficient and reliable HMAC-MD5 implementation for JavaScript.",
5
5
  "author": "bddjr",
6
6
  "license": "Unlicense",
7
7
  "type": "module",
@@ -63,7 +63,7 @@
63
63
  "typescript": "^7.0.2"
64
64
  },
65
65
  "scripts": {
66
- "build": "tsc && node scripts/build.mjs && es-check es2016 --module --checkFeatures main.js browser.min.js",
66
+ "build": "tsc && node scripts/build.mjs && es-check es2026 --module --checkFeatures main.js browser.min.js",
67
67
  "build:unchanged": "node scripts/build-unchanged.mjs",
68
68
  "test": "pnpm build && pnpm test:only",
69
69
  "test:only": "node scripts/test.mjs && node scripts/test-513MiB.mjs",