tinyhmacmd5 0.5.1 → 0.5.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,9 +2,9 @@ English | [中文](README-zh.md)
2
2
 
3
3
  # Tiny HMAC MD5
4
4
 
5
- A tiny, efficient and reliable HMAC-MD5 implementation for JavaScript.
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 **955 bytes**.
7
+ [`browser.min.js`](browser.min.js) is only **905 Bytes**.
8
8
 
9
9
  - **Input type**: `string` (UTF‑8), `Uint8Array` or `Uint8ClampedArray`
10
10
  - **Output type**: hex `string` or bytes `Uint8Array`
@@ -29,19 +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.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
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
37
38
  --------------------------------------------------
38
39
  ✅ All pure JS implementations match node:crypto result.
39
40
 
40
41
  --- Pure 513MiB Test (No prior small tests) ---
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
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
45
46
  ```
46
47
 
47
48
  CPU: i5-10600KF
@@ -60,7 +61,7 @@ As a result, the final size is not the smallest theoretically achievable.
60
61
  ### npm
61
62
 
62
63
  ```
63
- npm i tinyhmacmd5
64
+ npm i tinyhmacmd5@es2026
64
65
  ```
65
66
 
66
67
  ```js
@@ -76,7 +77,7 @@ You can also use other package managers (e.g. `pnpm` or `yarn`) in place of `npm
76
77
  See https://www.jsdelivr.com/package/npm/tinyhmacmd5
77
78
 
78
79
  ```html
79
- <script src="https://cdn.jsdelivr.net/npm/tinyhmacmd5"></script>
80
+ <script src="https://cdn.jsdelivr.net/npm/tinyhmacmd5@es2026"></script>
80
81
  ```
81
82
 
82
83
  It will define the `md5` function using `var`.
@@ -84,7 +85,7 @@ It will define the `md5` function using `var`.
84
85
  ### UNPKG
85
86
 
86
87
  ```html
87
- <script src="https://unpkg.com/tinyhmacmd5"></script>
88
+ <script src="https://unpkg.com/tinyhmacmd5@es2026"></script>
88
89
  ```
89
90
 
90
91
  It will define the `md5` function using `var`.
@@ -97,7 +98,7 @@ It will define the `md5` function using `var`.
97
98
  If you are concerned that others might not recognize what this is, you can add the following comment:
98
99
 
99
100
  ```js
100
- // tinyhmacmd5 (The Unlicense)
101
+ // https://npmjs.com/tinyhmacmd5
101
102
  ```
102
103
 
103
104
  ---
@@ -177,22 +178,22 @@ md5(data)
177
178
 
178
179
  ## Runtime Environment
179
180
 
180
- Environments that support [Exponentiation (`**`)](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Operators/Exponentiation) and [`TextEncoder`](https://developer.mozilla.org/docs/Web/API/TextEncoder) :
181
+ Environments that support [`Uint8Array.prototype.toHex()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/toHex) :
181
182
 
182
183
  - Desktop
183
- - Chrome ≥ 52 (2016-07-20)
184
- - Edge ≥ 79 (2020-01-15)
185
- - Firefox ≥ 52 (2017-03-07)
186
- - Opera ≥ 39 (2016-08-02)
187
- - Safari ≥ 10.1 (2017-03-27)
184
+ - Chrome ≥ 140 (2025-09-02)
185
+ - Edge ≥ 140 (2025-09-05)
186
+ - Firefox ≥ 133 (2024-11-26)
187
+ - Opera ≥ 124 (2025-11-13)
188
+ - Safari ≥ 18.2 (2024-12-11)
188
189
  - Mobile
189
- - Chrome Android ≥ 52 (2016-07-27)
190
- - Firefox for Android ≥ 52 (2017-03-07)
191
- - Opera Android ≥ 41 (2016-10-25)
192
- - Safari on iOS ≥ 10.3 (2017-03-27)
193
- - Samsung Browser ≥ 6 (2017-08-23)
194
- - WebView Android ≥ 51 (2016-06-08)
195
- - WebView on iOS ≥ 10.3 (2017-03-27)
190
+ - Chrome Android ≥ 140 (2025-09-02)
191
+ - Firefox for Android ≥ 133 (2024-11-26)
192
+ - Opera Android ≥ 92 (2025-10-08)
193
+ - Safari on iOS ≥ 18.2 (2024-12-11)
194
+ - Samsung Browser ×
195
+ - WebView Android ≥ 140 (2025-09-02)
196
+ - WebView on iOS ≥ 18.2 (2024-12-11)
196
197
 
197
198
  Not recommended for use in environments that support `node:crypto`, as `node:crypto` already provides HMAC-MD5.
198
199
 
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=(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),i=a?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;a?i[l]=h:i=(h>>4&&"")+h.toString(16)+i)h=u[--l>>2]>>8*l&255;return i}}
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()}}
package/main.js CHANGED
@@ -7,6 +7,12 @@ let $Uint8Array = Uint8Array
7
7
  /** MD5 constants cached in memory */
8
8
  let K = new $Int32Array(64).map((v, i) => 2 ** 32 * Math.sin(++i % Math.PI))
9
9
 
10
+ /** is big-endian */
11
+ let isBE = /** @type {0 | 1} */(new $Uint8Array(K.buffer)[0] & 1)
12
+
13
+ /** @type {(a: Uint8Array | Int32Array, ...x: any[]) => any} */
14
+ let reverse = a => a.reverse()
15
+
10
16
  /**
11
17
  * Calculate the MD5 of an array of little-endian words, and a byte length.
12
18
  *
@@ -74,15 +80,13 @@ let wordsMD5 = (
74
80
  * Convert bytes to an array of little-endian words
75
81
  *
76
82
  * @param {*} input
77
- * @param {number} j pad int32 length (0 or 16)
78
- *
79
- * @param {*} [i]
83
+ * @param {number} padLen pad int32 length (0 or 16)
80
84
  *
81
85
  * @returns {[Int32Array<ArrayBuffer>, number]}
82
86
  */
83
87
  let inputToWords = (
84
88
  input,
85
- j,
89
+ padLen,
86
90
  // var:
87
91
  byteLen = (
88
92
  // Don't replace the type check below with something like `input.big`; it's unreliable.
@@ -92,16 +96,13 @@ let inputToWords = (
92
96
  ).length,
93
97
  // Using `Array` to process inputs over 512 MiB could throw a `RangeError`,
94
98
  // so I replaced it with `Int32Array`.
95
- output = new $Int32Array(j + 18 + (byteLen - (byteLen + 8 & 63)) / 4),
96
- // (fast) little-endian
97
- i = new $Uint8Array(K.buffer)[3] & 1 && new $Uint8Array(output.buffer, j * 4).set(input),
98
- ) => {
99
- // (slow) big-endian
100
- for (; i < byteLen; ++i & 3 || j++) {
101
- output[j] |= input[i] << 8 * i
102
- }
103
- return [output, byteLen]
104
- }
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]
105
+ )
105
106
 
106
107
  /**
107
108
  * Computes the MD5 hash of the input data.
@@ -116,41 +117,34 @@ let inputToWords = (
116
117
  */
117
118
  let md5 = (data, key, raw) => {
118
119
  // Do not use parameter defaults to declare variables in public functions.
119
- var i = 16
120
- , hasKey = key != null
121
- , [bdata, temp] = inputToWords(data, /**@type {*}*/(hasKey) * i)
122
-
123
- /** @type {*} */
124
- var out = raw ? new $Uint8Array(i) : ''
120
+ /** @type {boolean | Uint8Array<ArrayBuffer>} */
121
+ var temp = key != null
122
+ , [bdata, dataByteLen] = inputToWords(data, /**@type {*}*/(temp) * 16)
125
123
 
126
- if (hasKey) {
124
+ if (temp) {
127
125
  // HMAC
128
- let [bkey, j] = inputToWords(key, 0)
126
+ let [bkey, keyByteLen] = inputToWords(key, 0)
129
127
  , opad = new $Int32Array(32)
130
- if (j > 64) {
131
- bkey = wordsMD5(bkey, j)
128
+ , i = 16
129
+ if (keyByteLen > 64) {
130
+ bkey = wordsMD5(bkey, keyByteLen)
132
131
  }
133
- for (j = i; j;) {
132
+ for (; i;) {
134
133
  // (0x36363636 ^ 0x5c5c5c5c) == 0x6a6a6a6a
135
- opad[--j] = 0x6a6a6a6a ^ (bdata[j] = 0x36363636 ^ bkey[j])
134
+ opad[--i] = 0x6a6a6a6a ^ (bdata[i] = 0x36363636 ^ bkey[i])
136
135
  }
137
- opad.set(wordsMD5(bdata, 64 + temp), i)
136
+ opad.set(wordsMD5(bdata, 64 + dataByteLen), 16)
138
137
  bdata = opad
139
- temp = 80
138
+ dataByteLen = 80
140
139
  }
141
140
 
142
- bdata = wordsMD5(bdata, temp)
143
-
144
- // words to bytes or hex
145
- for (; i;
146
- raw
147
- ? out[i] = temp
148
- : out = (temp >> 4 && '') + temp.toString(16) + out
149
- ) {
150
- temp = bdata[--i >> 2] >> i * 8 & 0xff
151
- }
141
+ bdata = wordsMD5(bdata, dataByteLen)
152
142
 
153
- return out
143
+ temp = new $Uint8Array(bdata.buffer)
144
+ isBE && reverse(temp, reverse(bdata))
145
+ return raw
146
+ ? temp
147
+ : temp.toHex()
154
148
  }
155
149
 
156
150
  export default md5
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tinyhmacmd5",
3
- "version": "0.5.1",
4
- "description": "A tiny (955 Bytes), efficient and reliable HMAC-MD5 implementation for JavaScript.",
3
+ "version": "0.5.2-es2026",
4
+ "description": "A tiny (905 Bytes), fast and reliable implementation of MD5 and HMAC-MD5 for JavaScript.",
5
5
  "author": "bddjr",
6
6
  "license": "Unlicense",
7
7
  "type": "module",
@@ -58,12 +58,13 @@
58
58
  "crypto-js": "^4.2.0",
59
59
  "es-check": "^9.6.4",
60
60
  "js-md5": "^0.9.2",
61
+ "spark-md5": "^3.0.2",
61
62
  "terser": "^5.49.0",
62
63
  "tinyhmacmd5": "link:",
63
64
  "typescript": "^7.0.2"
64
65
  },
65
66
  "scripts": {
66
- "build": "tsc && node scripts/build.mjs && es-check es2016 --module --checkFeatures main.js browser.min.js",
67
+ "build": "tsc && node scripts/build.mjs && es-check es2026 --module --checkFeatures main.js browser.min.js",
67
68
  "build:unchanged": "node scripts/build-unchanged.mjs",
68
69
  "test": "pnpm build && pnpm test:only",
69
70
  "test:only": "node scripts/test.mjs && node scripts/test-513MiB.mjs",