tinyhmacmd5 0.4.1 → 0.4.2-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,7 +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: [`browser.min.js`](browser.min.js) is only **1014 bytes**.
5
+ A tiny and reliable HMAC-MD5 implementation for JavaScript:
6
+
7
+ [`browser.min.js`](browser.min.js) is only **975 bytes**.
6
8
 
7
9
  - **Input type**: `string` (UTF‑8), `Uint8Array` or `Uint8ClampedArray`
8
10
  - **Output type**: hex `string` or bytes `Uint8Array`
@@ -10,14 +12,10 @@ A tiny and reliable HMAC-MD5 implementation for JavaScript: [`browser.min.js`](b
10
12
  - **TypeScript‑ready**: [`main.d.ts`](main.d.ts)
11
13
  - **0 dependencies**
12
14
 
13
- **Live demo**: https://bddjr.github.io/tinyhmacmd5/
14
-
15
15
  `tinyhmacmd5` does not simply aim for the smallest possible size.
16
16
  Its goal is to balance code size and runtime performance, so some performance-oriented implementations are intentionally retained.
17
17
  As a result, the final size is not the smallest theoretically achievable.
18
18
 
19
- If you need a smaller implementation that targets ECMAScript 2026, see the [`es2026`](https://github.com/bddjr/tinyhmacmd5/tree/es2026) branch.
20
-
21
19
  > [!WARNING]
22
20
  > MD5 is cryptographically broken and unsafe for security-sensitive applications.
23
21
  > Do not rely on it for password hashing, digital signatures, or certificate verification.
@@ -27,7 +25,7 @@ If you need a smaller implementation that targets ECMAScript 2026, see the [`es2
27
25
  ### npm
28
26
 
29
27
  ```
30
- npm i tinyhmacmd5
28
+ npm i tinyhmacmd5@es2026
31
29
  ```
32
30
 
33
31
  ```js
@@ -43,7 +41,7 @@ You can also use other package managers (e.g. `pnpm` or `yarn`) in place of `npm
43
41
  See https://www.jsdelivr.com/package/npm/tinyhmacmd5
44
42
 
45
43
  ```html
46
- <script src="https://cdn.jsdelivr.net/npm/tinyhmacmd5"></script>
44
+ <script src="https://cdn.jsdelivr.net/npm/tinyhmacmd5@es2026"></script>
47
45
  ```
48
46
 
49
47
  It will define the `md5` function using `var`.
@@ -51,7 +49,7 @@ It will define the `md5` function using `var`.
51
49
  ### UNPKG
52
50
 
53
51
  ```html
54
- <script src="https://unpkg.com/tinyhmacmd5"></script>
52
+ <script src="https://unpkg.com/tinyhmacmd5@es2026"></script>
55
53
  ```
56
54
 
57
55
  It will define the `md5` function using `var`.
@@ -142,22 +140,22 @@ md5(data)
142
140
 
143
141
  ## Runtime Environment
144
142
 
145
- Environments that support [Exponentiation (`**`)](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Exponentiation) and [`TextEncoder`](https://developer.mozilla.org/docs/Web/API/TextEncoder) :
143
+ Environments that support [`Uint8Array.prototype.toHex()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/toHex) :
146
144
 
147
145
  - Desktop
148
- - Chrome ≥ 52 (2016-07-20)
149
- - Edge ≥ 79 (2020-01-15)
150
- - Firefox ≥ 52 (2017-03-07)
151
- - Opera ≥ 39 (2016-08-02)
152
- - Safari ≥ 10.1 (2017-03-27)
146
+ - Chrome ≥ 140 (2025-09-02)
147
+ - Edge ≥ 140 (2025-09-05)
148
+ - Firefox ≥ 133 (2024-11-26)
149
+ - Opera ≥ 124 (2025-11-13)
150
+ - Safari ≥ 18.2 (2024-12-11)
153
151
  - Mobile
154
- - Chrome Android ≥ 52 (2016-07-27)
155
- - Firefox for Android ≥ 52 (2017-03-07)
156
- - Opera Android ≥ 41 (2016-10-25)
157
- - Safari on iOS ≥ 10.3 (2017-03-27)
158
- - Samsung Browser ≥ 6 (2017-08-23)
159
- - WebView Android ≥ 51 (2016-06-08)
160
- - WebView on iOS ≥ 10.3 (2017-03-27)
152
+ - Chrome Android ≥ 140 (2025-09-02)
153
+ - Firefox for Android ≥ 133 (2024-11-26)
154
+ - Opera Android ≥ 92 (2025-10-08)
155
+ - Safari on iOS ≥ 18.2 (2024-12-11)
156
+ - Samsung Browser ×
157
+ - WebView Android ≥ 140 (2025-09-02)
158
+ - WebView on iOS ≥ 18.2 (2024-12-11)
161
159
 
162
160
  Not recommended for use in environments that support `node:crypto`, as `node:crypto` already provides HMAC-MD5.
163
161
 
@@ -172,19 +170,19 @@ pnpm benchmark
172
170
  ```
173
171
  Data length: 104857600 chars (100MiB)
174
172
  --------------------------------------------------
175
- tinyhmacmd5 : 568.29 ms
176
- js-md5 : 130.97 ms
177
- blueimp-md5 : 3835.78 ms
178
- crypto-js : 1560.48 ms
179
- node:crypto : 130.22 ms
173
+ tinyhmacmd5 : 550.92 ms
174
+ js-md5 : 128.96 ms
175
+ blueimp-md5 : 3837.83 ms
176
+ crypto-js : 1562.08 ms
177
+ node:crypto : 129.08 ms
180
178
  --------------------------------------------------
181
179
  ✅ All pure JS implementations match node:crypto result.
182
180
 
183
181
  --- Pure 513MiB Test (No prior small tests) ---
184
- tinyhmacmd5 HMAC-MD5 timer: 2.789s
185
- node:crypto HMAC-MD5 timer: 552.479ms
186
- tinyhmacmd5 MD5 timer: 2.778s
187
- node:crypto MD5 timer: 550.663ms
182
+ tinyhmacmd5 HMAC-MD5 timer: 2.706s
183
+ node:crypto HMAC-MD5 timer: 547.808ms
184
+ tinyhmacmd5 MD5 timer: 2.693s
185
+ node:crypto MD5 timer: 550.144ms
188
186
  ```
189
187
 
190
188
  CPU: i5-10600KF
@@ -210,7 +208,7 @@ During the adaptation, I discovered that `blueimp-md5` did not correctly handle
210
208
 
211
209
  I also found that using `Array` to process inputs over 512 MiB could throw a `RangeError`, so I replaced it with `Int32Array`.
212
210
 
213
- I demonstrated in practice that HMAC-MD5 can be implemented in an extremely small footprint (1014 bytes) while also improving reliability.
211
+ I demonstrated in practice that HMAC-MD5 can be implemented in an extremely small footprint (975 bytes) while also improving reliability.
214
212
 
215
213
  Maybe not many people care about saving just a few KB, but `tinyhmacmd5` exists precisely to "explore the unknown".
216
214
 
package/browser.min.js CHANGED
@@ -1 +1 @@
1
- /*! npmjs.com/tinyhmacmd5 */{let e=Math,r=Int32Array,n=Uint8Array,t=new r(64).map((r,n)=>2**32*e.abs(e.sin(n+1))),f=1&new n(t.buffer)[3],o=(n,f,o=0,a,l=1732584193,w=271733878,i,u,s=n.length,c=r.of(l,~w,~l,w),d=new r(c))=>{for(n[s-1]=f/2**29,n[e.floor(f/4)]|=128<<(n[s-2]=f<<3);o<s;o+=16){for(f=0;f<16;f+=4)for(a=0;a<16;)c[u&=3]=((w=c[u]+t[4*f+a]+(l=c[3&++u],w=c[3&++u],i=c[3&++u],w^(f>4?f>8?l|~i:l^i:f?i&(l^w):~l&(w^i)))+n[o+(a*(29521>>f)+(1296>>f)&15)])<<(i="',16%).4$+07&*/5".charCodeAt(3&a++|f))|w>>>32-i)+l;for(;u;)d[--u]=c[u]+=d[u]}return c},a=(t,o,a=("string"==typeof t?t=(new TextEncoder).encode(t):t).length,l=new r(o+16*e.ceil((a+9)/64)),w=f&&new n(l.buffer,4*o).set(t))=>{for(;w<a;3&++w||o++)l[o]|=t[w]<<8*w;return[l,a]};var md5=(e,t,f)=>{var l=16,w=null!=t,[i,u]=a(e,w*l),s=f?new n(l):"";if(w){let[e,n]=a(t,0),f=new r(32);for(n>64&&(e=o(e,n)),n=l;n;)f[--n]=1785358954^(i[n]=909522486^e[n]);f.set(o(i,64+u),l),i=f,u=80}for(i=o(i,u);l;f?s[l]=u:s=(u>>4&&"")+u.toString(16)+s)u=i[--l>>2]>>8*l&255;return s}}
1
+ /*! npmjs.com/tinyhmacmd5 */{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,s=e.of(a,~w,~a,w),d=new e(s))=>{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;)s[u&=3]=((w=s[u]+n[o]+(a=s[3&++u],w=s[3&++u],l=s[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;)d[--u]=s[u]+=d[u]}return s},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),s=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;)s[--w]=u[w>>2]>>8*w;return a?s:s.toHex()}}
package/main.js CHANGED
@@ -2,14 +2,12 @@
2
2
 
3
3
  // Adapted from https://github.com/blueimp/JavaScript-MD5
4
4
 
5
- let $Math = Math
6
-
7
5
  let $Int32Array = Int32Array
8
6
 
9
7
  let $Uint8Array = Uint8Array
10
8
 
11
9
  /** MD5 constants cached in memory */
12
- let K = new $Int32Array(64).map((v, i) => 2 ** 32 * $Math.abs($Math.sin(i + 1)))
10
+ let K = new $Int32Array(64).map((v, i) => 2 ** 32 * Math.abs(Math.sin(i + 1)))
13
11
 
14
12
  /** is little-endian */
15
13
  let isLE = new $Uint8Array(K.buffer)[3] & 1
@@ -44,16 +42,16 @@ let wordsMD5 = (
44
42
  // `l` may be >= 2**32, so cannot use `>>>` as a replacement for `floor`.
45
43
  // `l << 3` cannot be changed to `l * 8`, as it would trigger JIT deoptimization on large inputs.
46
44
  x[xLen - 1] = l / 2 ** 29;
47
- x[$Math.floor(l / 4)] |= 0x80 << (x[xLen - 2] = l << 3);
45
+ x[(l - l % 4) / 4] |= 0x80 << (x[xLen - 2] = l << 3);
48
46
 
49
47
  for (; i < xLen; i += 16) {
50
- for (l = 0; l < 16; l += 4) {
51
- for (j = 0; j < 16;) {
48
+ for (l = j = 0; l < 16; l += 4) {
49
+ for (; j < 4 * l + 16;) {
52
50
  output[oi &= 3] = (
53
51
  (
54
52
  t1 = (
55
53
  output[oi] +
56
- K[l * 4 + j] +
54
+ K[j] +
57
55
  (
58
56
  t0 = output[++oi & 3],
59
57
  t1 = output[++oi & 3],
@@ -98,13 +96,14 @@ let inputToWords = (
98
96
  j,
99
97
  // var:
100
98
  byteLen = (
99
+ // Don't replace the type check below with something like `input.big`; it's unreliable.
101
100
  typeof input == 'string'
102
101
  ? input = new TextEncoder().encode(input)
103
102
  : input
104
103
  ).length,
105
104
  // Using `Array` to process inputs over 512 MiB could throw a `RangeError`,
106
105
  // so I replaced it with `Int32Array`.
107
- output = new $Int32Array(j + $Math.ceil((byteLen + 9) / 64) * 16),
106
+ output = new $Int32Array(j + 18 + (byteLen - (byteLen + 8 & 63)) / 4),
108
107
  // (fast) little-endian
109
108
  i = isLE && new $Uint8Array(output.buffer, j * 4).set(input),
110
109
  ) => {
@@ -130,9 +129,7 @@ var md5 = (data, key, raw) => {
130
129
  var i = 16
131
130
  , hasKey = key != null
132
131
  , [bdata, temp] = inputToWords(data, /**@type {*}*/(hasKey) * i)
133
-
134
- /** @type {*} */
135
- var out = raw ? new $Uint8Array(i) : ''
132
+ , out = new $Uint8Array(i)
136
133
 
137
134
  if (hasKey) {
138
135
  // HMAC
@@ -153,15 +150,11 @@ var md5 = (data, key, raw) => {
153
150
  bdata = wordsMD5(bdata, temp)
154
151
 
155
152
  // words to bytes or hex
156
- for (; i;
157
- raw
158
- ? out[i] = temp
159
- : out = (temp >> 4 && '') + temp.toString(16) + out
160
- ) {
161
- temp = bdata[--i >> 2] >> i * 8 & 0xff
153
+ for (; i;) {
154
+ out[--i] = bdata[i >> 2] >> i * 8
162
155
  }
163
156
 
164
- return out
157
+ return raw ? out : out.toHex()
165
158
  }
166
159
 
167
160
  export default md5
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tinyhmacmd5",
3
- "version": "0.4.1",
4
- "description": "A tiny and reliable HMAC-MD5 implementation for JavaScript: browser.min.js is only 1014 bytes.",
3
+ "version": "0.4.2-es2026",
4
+ "description": "A tiny and reliable HMAC-MD5 implementation for JavaScript: browser.min.js is only 975 bytes.",
5
5
  "author": "bddjr",
6
6
  "license": "MIT",
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",