hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

sha512.ha (9401B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use bytes;
      5 use crypto::math;
      6 use endian;
      7 use hash;
      8 use io;
      9 
     10 export type variant = enum {
     11 	SHA384,
     12 	SHA512,
     13 	SHA512_224,
     14 	SHA512_256,
     15 };
     16 
     17 // The size, in bytes, of a SHA-512 checksum.
     18 export def SZ: size = 64;
     19 
     20 // The size, in bytes, of a SHA-512/224 checksum.
     21 export def SZ224: size = 28;
     22 
     23 // The size, in bytes, of a SHA-512/256 checksum.
     24 export def SZ256: size = 32;
     25 
     26 // The size, in bytes, of a SHA-384 checksum.
     27 export def SZ384: size = 48;
     28 
     29 def chunk: size = 128;
     30 def init0: u64 = 0x6a09e667f3bcc908;
     31 def init1: u64 = 0xbb67ae8584caa73b;
     32 def init2: u64 = 0x3c6ef372fe94f82b;
     33 def init3: u64 = 0xa54ff53a5f1d36f1;
     34 def init4: u64 = 0x510e527fade682d1;
     35 def init5: u64 = 0x9b05688c2b3e6c1f;
     36 def init6: u64 = 0x1f83d9abfb41bd6b;
     37 def init7: u64 = 0x5be0cd19137e2179;
     38 def init0_224: u64 = 0x8c3d37c819544da2;
     39 def init1_224: u64 = 0x73e1996689dcd4d6;
     40 def init2_224: u64 = 0x1dfab7ae32ff9c82;
     41 def init3_224: u64 = 0x679dd514582f9fcf;
     42 def init4_224: u64 = 0x0f6d2b697bd44da8;
     43 def init5_224: u64 = 0x77e36f7304c48942;
     44 def init6_224: u64 = 0x3f9d85a86a1d36c8;
     45 def init7_224: u64 = 0x1112e6ad91d692a1;
     46 def init0_256: u64 = 0x22312194fc2bf72c;
     47 def init1_256: u64 = 0x9f555fa3c84c64c2;
     48 def init2_256: u64 = 0x2393b86b6f53b151;
     49 def init3_256: u64 = 0x963877195940eabd;
     50 def init4_256: u64 = 0x96283ee2a88effe3;
     51 def init5_256: u64 = 0xbe5e1e2553863992;
     52 def init6_256: u64 = 0x2b0199fc2c85b8aa;
     53 def init7_256: u64 = 0x0eb72ddc81c52ca2;
     54 def init0_384: u64 = 0xcbbb9d5dc1059ed8;
     55 def init1_384: u64 = 0x629a292a367cd507;
     56 def init2_384: u64 = 0x9159015a3070dd17;
     57 def init3_384: u64 = 0x152fecd8f70e5939;
     58 def init4_384: u64 = 0x67332667ffc00b31;
     59 def init5_384: u64 = 0x8eb44a8768581511;
     60 def init6_384: u64 = 0xdb0c2e0d64f98fa7;
     61 def init7_384: u64 = 0x47b5481dbefa4fa4;
     62 
     63 export type digest = struct {
     64 	hash::hash,
     65 	h: [8]u64,
     66 	x: [chunk]u8,
     67 	nx: size,
     68 	ln: size,
     69 	var: variant,
     70 };
     71 
     72 // Creates a [[hash::hash]] which computes a SHA-512 hash. If this function is
     73 // used to hash sensitive information, the caller should call [[hash::close]] to
     74 // erase sensitive data from memory after use; if not, the use of
     75 // [[hash::close]] is optional.
     76 export fn sha512() digest = init(variant::SHA512, SZ);
     77 
     78 // Creates a [[hash::hash]] which computes a SHA-512/224 hash. If this function
     79 // is used to hash sensitive information, the caller should call [[hash::close]]
     80 // to erase sensitive data from memory after use; if not, the use of
     81 // [[hash::close]] is optional.
     82 export fn sha512_224() digest = init(variant::SHA512_224, SZ224);
     83 
     84 // Creates a [[hash::hash]] which computes a SHA-512/256 hash. If this function
     85 // is used to hash sensitive information, the caller should call [[hash::close]]
     86 // to erase sensitive data from memory after use; if not, the use of
     87 // [[hash::close]] is optional.
     88 export fn sha512_256() digest = init(variant::SHA512_256, SZ256);
     89 
     90 // Creates a [[hash::hash]] which computes a SHA-384 hash. If this function is
     91 // used to hash sensitive information, the caller should call [[hash::close]] to
     92 // erase sensitive data from memory after use; if not, the use of
     93 // [[hash::close]] is optional.
     94 export fn sha384() digest = init(variant::SHA384, SZ384);
     95 
     96 const sha512_vtable: io::vtable = io::vtable {
     97 	writer = &write,
     98 	closer = &close,
     99 	...
    100 };
    101 
    102 // Internal initialization function
    103 fn init(var: variant, sz: size) digest = {
    104 	let sha = digest {
    105 		stream = &sha512_vtable,
    106 		sum = &sum,
    107 		reset = &reset,
    108 		sz = sz,
    109 		bsz = chunk,
    110 		var = var,
    111 		...
    112 	};
    113 	hash::reset(&sha);
    114 	return sha;
    115 };
    116 
    117 fn write(st: *io::stream, buf: const []u8) (size | io::error) = {
    118 	let h = st: *digest;
    119 	let b: []u8 = buf;
    120 	let nn = len(buf);
    121 
    122 	h.ln += nn;
    123 
    124 	if (h.nx > 0) {
    125 		// Compute how many bytes can be copied into h.x
    126 		let r = len(h.x) - h.nx;
    127 		let n = if (nn > r) r else nn;
    128 		h.x[h.nx..h.nx + n] = b[..n];
    129 		h.nx += n;
    130 		if (h.nx == chunk) {
    131 			block(h, h.x[..]);
    132 			h.nx = 0;
    133 		};
    134 		b = b[n..];
    135 	};
    136 	if (len(b) >= chunk) {
    137 		let n = len(b) & ~(chunk - 1);
    138 		block(h, b[..n]);
    139 		b = b[n..];
    140 	};
    141 	if (len(b) > 0) {
    142 		let n = len(b);
    143 		h.x[..n] = b[..];
    144 		h.nx = n;
    145 	};
    146 	return nn;
    147 };
    148 
    149 fn sum(h: *hash::hash, buf: []u8) void = {
    150 	let d = h: *digest;
    151 	let copy = *d;
    152 	let d = &copy;
    153 	defer hash::close(d);
    154 
    155 	// Padding. Add a 1 bit and 0 bits until 112 bytes mod 128
    156 	let ln = d.ln;
    157 	let tmp: [chunk]u8 = [0x80, 0...];
    158 	if ((ln % 128) < 112) {
    159 		const n = 112 - (ln % 128);
    160 		write(d, tmp[..n])!;
    161 	} else {
    162 		const n = 128 + 112 - (ln % 128);
    163 		write(d, tmp[..n])!;
    164 	};
    165 
    166 	// Length in bits
    167 	ln <<= 3;
    168 	endian::beputu64(tmp, 0u64); // upper 64 bits are always zero
    169 	endian::beputu64(tmp[8..], ln : u64);
    170 	write(d, tmp[..16])!;
    171 
    172 	assert(d.nx == 0);
    173 
    174 	let dig: [SZ]u8 = [0...];
    175 	endian::beputu64(dig[0..], d.h[0]);
    176 	endian::beputu64(dig[8..], d.h[1]);
    177 	endian::beputu64(dig[16..], d.h[2]);
    178 	endian::beputu64(dig[24..], d.h[3]);
    179 	endian::beputu64(dig[32..], d.h[4]);
    180 	endian::beputu64(dig[40..], d.h[5]);
    181 	if (d.var != variant::SHA384) {
    182 		endian::beputu64(dig[48..], d.h[6]);
    183 		endian::beputu64(dig[56..], d.h[7]);
    184 	};
    185 
    186 	// We only copy the necessary bytes from fixed-size array into the
    187 	// returned slice. The size is already found in the inner hash struct.
    188 	buf[..d.sz] = dig[..d.sz];
    189 };
    190 
    191 fn reset(h: *hash::hash) void = {
    192 	let d = h: *digest;
    193 	switch (d.var) {
    194 	case variant::SHA384 =>
    195 		d.h[0] = init0_384;
    196 		d.h[1] = init1_384;
    197 		d.h[2] = init2_384;
    198 		d.h[3] = init3_384;
    199 		d.h[4] = init4_384;
    200 		d.h[5] = init5_384;
    201 		d.h[6] = init6_384;
    202 		d.h[7] = init7_384;
    203 	case variant::SHA512_224 =>
    204 		d.h[0] = init0_224;
    205 		d.h[1] = init1_224;
    206 		d.h[2] = init2_224;
    207 		d.h[3] = init3_224;
    208 		d.h[4] = init4_224;
    209 		d.h[5] = init5_224;
    210 		d.h[6] = init6_224;
    211 		d.h[7] = init7_224;
    212 	case variant::SHA512_256 =>
    213 		d.h[0] = init0_256;
    214 		d.h[1] = init1_256;
    215 		d.h[2] = init2_256;
    216 		d.h[3] = init3_256;
    217 		d.h[4] = init4_256;
    218 		d.h[5] = init5_256;
    219 		d.h[6] = init6_256;
    220 		d.h[7] = init7_256;
    221 	case =>
    222 		d.h[0] = init0;
    223 		d.h[1] = init1;
    224 		d.h[2] = init2;
    225 		d.h[3] = init3;
    226 		d.h[4] = init4;
    227 		d.h[5] = init5;
    228 		d.h[6] = init6;
    229 		d.h[7] = init7;
    230 	};
    231 	d.nx = 0;
    232 	d.ln = 0;
    233 };
    234 
    235 const k: [_]u64 = [
    236 	0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc,
    237 	0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118,
    238 	0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2,
    239 	0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694,
    240 	0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65,
    241 	0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5,
    242 	0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4,
    243 	0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70,
    244 	0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df,
    245 	0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b,
    246 	0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30,
    247 	0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8,
    248 	0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8,
    249 	0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3,
    250 	0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec,
    251 	0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b,
    252 	0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178,
    253 	0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b,
    254 	0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c,
    255 	0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817,
    256 ];
    257 
    258 fn block(h: *digest, p: []u8) void = {
    259 	let w: [80]u64 = [0...];
    260 
    261 	let h0 = h.h[0];
    262 	let h1 = h.h[1];
    263 	let h2 = h.h[2];
    264 	let h3 = h.h[3];
    265 	let h4 = h.h[4];
    266 	let h5 = h.h[5];
    267 	let h6 = h.h[6];
    268 	let h7 = h.h[7];
    269 
    270 	for (len(p) >= chunk; p = p[chunk..]) {
    271 		for (let i = 0z; i < 16; i += 1) {
    272 			let j = i * 8;
    273 			w[i] = p[j]: u64 << 56
    274 				| p[j+1]: u64 << 48
    275 				| p[j+2]: u64 << 40
    276 				| p[j+3]: u64 << 32
    277 				| p[j+4]: u64 << 24
    278 				| p[j+5]: u64 << 16
    279 				| p[j+6]: u64 << 8
    280 				| p[j+7]: u64;
    281 		};
    282 		for (let i = 16z; i < 80; i += 1) {
    283 			let v1 = w[i - 2];
    284 			let t1 = math::rotr64(v1, 19) ^ math::rotr64(v1, 61) ^ (v1 >> 6);
    285 			let v2 = w[i - 15];
    286 			let t2 = math::rotr64(v2, 1) ^ math::rotr64(v2, 8) ^ (v2 >> 7);
    287 
    288 			w[i] = t1 + w[i - 7] + t2 + w[i - 16];
    289 		};
    290 
    291 		let a = h0;
    292 		let b = h1;
    293 		let c = h2;
    294 		let d = h3;
    295 		let e = h4;
    296 		let f = h5;
    297 		let g = h6;
    298 		let h = h7;
    299 
    300 		for (let i = 0z; i < 80; i += 1) {
    301 			let t1 = h + (math::rotr64(e, 14)
    302 				^ math::rotr64(e, 18)
    303 				^ math::rotr64(e, 41))
    304 				+ ((e & f) ^ (~e & g))
    305 				+ k[i] + w[i];
    306 
    307 			let t2 = (math::rotr64(a, 28)
    308 				^ math::rotr64(a, 34)
    309 				^ math::rotr64(a, 39))
    310 				+ ((a & b) ^ (a & c) ^ (b & c));
    311 
    312 			h = g;
    313 			g = f;
    314 			f = e;
    315 			e = d + t1;
    316 			d = c;
    317 			c = b;
    318 			b = a;
    319 			a = t1 + t2;
    320 		};
    321 		h0 += a;
    322 		h1 += b;
    323 		h2 += c;
    324 		h3 += d;
    325 		h4 += e;
    326 		h5 += f;
    327 		h6 += g;
    328 		h7 += h;
    329 	};
    330 	h.h[0] = h0;
    331 	h.h[1] = h1;
    332 	h.h[2] = h2;
    333 	h.h[3] = h3;
    334 	h.h[4] = h4;
    335 	h.h[5] = h5;
    336 	h.h[6] = h6;
    337 	h.h[7] = h7;
    338 };
    339 
    340 fn close(stream: *io::stream) (void | io::error) = {
    341 	let s = stream: *digest;
    342 	bytes::zero((s.h[..]: *[*]u8)[..len(s.h) * size(u32)]);
    343 	bytes::zero(s.x);
    344 };