Skip to content

Commit 5b98386

Browse files
committed
sha1c.js.in added
1 parent fc1e571 commit 5b98386

File tree

1 file changed

+359
-0
lines changed

1 file changed

+359
-0
lines changed

sha1c.js.in

Lines changed: 359 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,359 @@
1+
# !! THIS CODE IS NOT MEANT TO BE KEPT COMPATIBLE TO ES12 OR BELOW !!
2+
# (You can BABEL and Polyfills of course. See generated md5.js)
3+
#
4+
# This code is parsed through ./unroll.sh to output the real JS.
5+
# TBD: It runs on Big endian, too, but is a bit slower due to swap.
6+
#
7+
# vim: ft=javascript :
8+
#
9+
# I need small and fast code, which must not carry any Copyright,
10+
# and which runs in non-HTTPS-context, too.
11+
# Hence this here is free as in free beer, free speech and free baby.
12+
#
13+
# Based on the reference C code of SHA256 handed
14+
# (hence without copyright) analogous to my md5 variant
15+
# and possibly some ideas found elsewhere.
16+
17+
'use strict';
18+
// This is free as in free beer, free speech and free baby.
19+
// IMPORTANT! NEVER COVER THIS CODE WITH A COPYRIGHT
20+
// as this might break German Urheberrecht!
21+
// If you need to state a Copyright, excempt this code from it!
22+
//
23+
// How to use?
24+
// <script src="sha1.js"></script>
25+
// then
26+
// const sha1 = SHA1.sha1('string');
27+
// or
28+
// const sha1s = new SHA1();
29+
// const a = sha1s.init().update_str('str1').update_str('str2').end().$hex;
30+
// const b = sha1s.init().update8(new UInt8Array(something)) .end().$bin;
31+
// This can be repeated: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
32+
33+
const SHA1 = (_=>_())(() => {
34+
35+
function D(...a)
36+
{
37+
const p = [];
38+
for (const x of a)
39+
{
40+
if ('string' === typeof x)
41+
p.push(x);
42+
else if (typeof x !== 'object')
43+
p.push(`${Number(x>>>0).toString(16)}`.padStart(8,'0'));
44+
else if (x.BYTES_PER_ELEMENT)
45+
p.push(Array.from(x).map(_ => _.toString(16).padStart(x.BYTES_PER_ELEMENT*2, '0')).join('_'));
46+
else
47+
p.push(JSON.stringify(x));
48+
}
49+
console.log(p.join('\n'));
50+
console.log('-------');
51+
}
52+
53+
// Class layout analogous to md5c.js.in, for additional comments see there.
54+
// I need a stable independent reference code without additional dependencies.
55+
// Hence no inheritance (yet). Perhaps future will bring a modular version.
56+
class SHA1
57+
{
58+
big_endian()
59+
{
60+
const b = new ArrayBuffer(4);
61+
62+
new Uint32Array(b)[0] = 0x12345678;
63+
return new Uint8Array(b)[0] === 0x12;
64+
}
65+
constructor()
66+
{
67+
const b = new ArrayBuffer(64);
68+
this.in8 = new Uint8Array(b);
69+
this.in32 = new Uint32Array(b);
70+
71+
this.enc = new TextEncoder();
72+
73+
this.trafo = this._trafo;
74+
if (!this.big_endian())
75+
this.swap = this._swap;
76+
}
77+
_swap(a32)
78+
{
79+
for (let i = a32.length; --i>=0; )
80+
{
81+
let x = a32[i];
82+
x = ((x>> 8) & 0x00ff00ff) | ((x<< 8) & 0xff00ff00);
83+
x = ((x>>16) & 0x0000ffff) | ((x<<16) & 0xffff0000);
84+
a32[i] = x;
85+
}
86+
}
87+
88+
///////////////////////
89+
90+
!ctx a 0
91+
!ctx b 1
92+
!ctx c 2
93+
!ctx d 3
94+
!ctx e 4
95+
96+
!var 0
97+
!var 1
98+
!var 2
99+
!var 3
100+
!var 4
101+
!var 5
102+
!var 6
103+
!var 7
104+
!var 8
105+
!var 9
106+
!var 10
107+
!var 11
108+
!var 12
109+
!var 13
110+
!var 14
111+
!var 15
112+
113+
!def 16
114+
!def 17
115+
!def 18
116+
!def 19
117+
118+
!F0 0
119+
!F0 1
120+
!F0 2
121+
!F0 3
122+
!F0 4
123+
!F0 5
124+
!F0 6
125+
!F0 7
126+
!F0 8
127+
!F0 9
128+
!F0 10
129+
!F0 11
130+
!F0 12
131+
!F0 13
132+
!F0 14
133+
!F0 15
134+
135+
!F1 16
136+
!F1 17
137+
!F1 18
138+
!F1 19
139+
140+
!F2 20
141+
!F2 21
142+
!F2 22
143+
!F2 23
144+
!F2 24
145+
!F2 25
146+
!F2 26
147+
!F2 27
148+
!F2 28
149+
!F2 29
150+
!F2 30
151+
!F2 31
152+
!F2 32
153+
!F2 33
154+
!F2 34
155+
!F2 35
156+
!F2 36
157+
!F2 37
158+
!F2 38
159+
!F2 39
160+
161+
!F3 40
162+
!F3 41
163+
!F3 42
164+
!F3 43
165+
!F3 44
166+
!F3 45
167+
!F3 46
168+
!F3 47
169+
!F3 48
170+
!F3 49
171+
!F3 50
172+
!F3 51
173+
!F3 52
174+
!F3 53
175+
!F3 54
176+
!F3 55
177+
!F3 56
178+
!F3 57
179+
!F3 58
180+
!F3 59
181+
182+
!F4 60
183+
!F4 61
184+
!F4 62
185+
!F4 63
186+
!F4 64
187+
!F4 65
188+
!F4 66
189+
!F4 67
190+
!F4 68
191+
!F4 69
192+
!F4 70
193+
!F4 71
194+
!F4 72
195+
!F4 73
196+
!F4 74
197+
!F4 75
198+
!F4 76
199+
!F4 77
200+
!F4 78
201+
!F4 79
202+
203+
:F0 t = (v$1 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
204+
:F0 e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
205+
206+
:F1 t = v$[$1 - 3] ^ v$[$1 - 8] ^ v$[$1 - 14] ^ v$[$1 - 16];
207+
:F1 v$1 = (t << 1) | (t >>> 31);
208+
:F1 t = (v$1 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (~b & d)) + 0x5a827999 )|0;
209+
:F1 e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
210+
211+
:F2 t = v$[$1 - 3] ^ v$[$1 - 8] ^ v$[$1 - 14] ^ v$[$1 - 16];
212+
:F2 v$1 = (t << 1) | (t >>> 31);
213+
:F2 t = (v$1 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) + 0x6ed9eba1 )|0;
214+
:F2 e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
215+
216+
:F3 t = v$[$1 - 3] ^ v$[$1 - 8] ^ v$[$1 - 14] ^ v$[$1 - 16];
217+
:F3 v$1 = (t << 1) | (t >>> 31);
218+
:F3 t = (v$1 + ((a << 5) | (a >>> 27)) + e + ((b & c) | (b & d) | (c & d)) - 0x70e44324 )|0;
219+
:F3 e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
220+
221+
:F4 t = v$[$1 - 3] ^ v$[$1 - 8] ^ v$[$1 - 14] ^ v$[$1 - 16];
222+
:F4 v$1 = (t << 1) | (t >>> 31);
223+
:F4 t = (v$1 + ((a << 5) | (a >>> 27)) + e + (b ^ c ^ d) - 0x359d3e2a )|0;
224+
:F4 e = d; d = c; c = (b << 30) | (b >>> 2); b = a; a = t;
225+
226+
:ctx let $1 = ctx[$2];
227+
:ctx: ctx[$2] = ctx[$2] + $1 | 0;
228+
229+
:var let v$1 = buf[$1] | 0, v$[20 + $1], v$[40 + $1], v$[60 + $1];
230+
:def let v$1, v$[20 + $1], v$[40 + $1], v$[60 + $1];
231+
232+
_trafo()
233+
{
234+
const ctx = this.buf;
235+
const buf = this.in32;
236+
let n, t;
237+
238+
@ var
239+
@ def
240+
@ ctx
241+
@ F0
242+
@ F1
243+
@ F2
244+
@ F3
245+
@ F4
246+
@ ctx:
247+
248+
this.len += 64;
249+
}
250+
251+
init()
252+
{
253+
this.buf = new Uint32Array([ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 ]);
254+
255+
this.fill = 0; // fill state of this.in
256+
this.len = 0; // total bytes transformed into hash so far
257+
return this;
258+
}
259+
260+
end()
261+
{
262+
let pos = this.fill;
263+
const len = (this.len + pos)*8; // bytes
264+
const in8 = this.in8;
265+
const in32 = this.in32;
266+
267+
// there is at least 1 byte free in this.in8
268+
in8[pos] = 0x80;
269+
270+
let rest = 64-1-pos;
271+
// The last 8 byte of the block will be overwritten below
272+
for (let i=rest; --i>=0; in8[++pos]=0);
273+
if (this.swap) this.swap(this.in32);
274+
if (rest<8)
275+
{
276+
this.trafo();
277+
for (let i=14; --i>=0; in32[i]=0);
278+
}
279+
in32[14] = len / 0x100000000 | 0; // we cannot use integer math here
280+
in32[15] = len >>>0;
281+
this.trafo();
282+
283+
this.fill = void 0;
284+
this.len = void 0;
285+
// this.buf contains the result
286+
if (this.swap) this.swap(this.buf);
287+
return this;
288+
}
289+
290+
//////////////////////
291+
292+
update8(b) // Uint8Array
293+
{
294+
const _ = this.in8;
295+
296+
let out = this.fill | 0;
297+
let len = b.length | 0; // we do not support more than 2^32 bytes (AKA 4GiB) per update
298+
let pos = 0;
299+
300+
while (len)
301+
{
302+
let max = 64-out | 0;
303+
if (max > len)
304+
max = len | 0;
305+
306+
// To avoid the swap() on Big endian machines, following copy
307+
// should rather be replaced by some inlined Duff's device.
308+
// (for this we need to add up/down-counting repeats to ./unroll.sh)
309+
// (and we probably need conditional macros as well as recursive ones)
310+
_.set(b.subarray(pos, pos+max), out);
311+
312+
pos = pos + max | 0;
313+
out = out + max | 0;
314+
len = len - max | 0;
315+
if (out<64)
316+
break;
317+
if (this.swap) this.swap(this.in32);
318+
this.trafo();
319+
out = 0;
320+
}
321+
this.fill = out;
322+
return this;
323+
}
324+
update_str(s) // this is not meant for long strings!
325+
{
326+
return this.update8(this.enc.encode(s));
327+
}
328+
get $bin()
329+
{
330+
return new Uint8Array(this.buf.buffer);
331+
}
332+
get $hex()
333+
{
334+
return Array.from(this.$bin, b => b.toString(16).padStart(2, '0')).join('');
335+
}
336+
static sha1(s,bin)
337+
{
338+
const out = sha1.init().update_str(s).end();
339+
return bin ? out.$bin : out.$hex;
340+
}
341+
static test(d,t)
342+
{
343+
const r = this.sha1(t);
344+
if (r !== d)
345+
throw `sha1c.js test failed for '${t}':\n'${d}' expected\n'${r}' got`;
346+
// D('test ok', r);
347+
}
348+
349+
};
350+
351+
const sha1 = new SHA1(); // for the static sha256 above
352+
353+
SHA1.test('da39a3ee5e6b4b0d3255bfef95601890afd80709', ''); // 0 bytes
354+
SHA1.test('accfa188bccab15065e9feaf805d00217e958ec0', '0123456789abcdef0123456789abcdef0123456789abcdef0123456'); // single round
355+
SHA1.test('edc9055eaab6e86d803e41dd99272b3da1468595', '0123456789abcdef0123456789abcdef0123456789abcdef01234567'); // double round
356+
SHA1.test('ce4303f6b22257d9c9cf314ef1dee4707c6e1c13', '0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef'); // 64 byte input
357+
// console.log('selftest ok');
358+
return SHA1;
359+
});

0 commit comments

Comments
 (0)