From 2f255ac5c38c8871cf1ff6861250474fa04dac33 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 24 Feb 2023 10:49:01 +0100 Subject: [PATCH] Sha1. --- lib/std/core/allocators/heap_allocator.c3 | 8 +- lib/std/core/string.c3 | 2 +- lib/std/hash/sha1.c3 | 237 ++++++++++++++++++++++ test/unit/stdlib/hash/sha1.c3 | 30 +++ 4 files changed, 272 insertions(+), 5 deletions(-) create mode 100644 lib/std/hash/sha1.c3 create mode 100644 test/unit/stdlib/hash/sha1.c3 diff --git a/lib/std/core/allocators/heap_allocator.c3 b/lib/std/core/allocators/heap_allocator.c3 index 343b78132..b3a90256a 100644 --- a/lib/std/core/allocators/heap_allocator.c3 +++ b/lib/std/core/allocators/heap_allocator.c3 @@ -74,14 +74,14 @@ fn void*! SimpleHeapAllocator._realloc(SimpleHeapAllocator* this, void* old_poin return new; } -fn void*! SimpleHeapAllocator._calloc(SimpleHeapAllocator* this, usz bytes) @private +fn void*! SimpleHeapAllocator._calloc(SimpleHeapAllocator* this, usz bytes) @local { void* data = this._alloc(bytes)?; mem::clear(data, bytes, DEFAULT_MEM_ALIGNMENT); return data; } -fn void*! SimpleHeapAllocator._alloc(SimpleHeapAllocator* this, usz bytes) @private +fn void*! SimpleHeapAllocator._alloc(SimpleHeapAllocator* this, usz bytes) @local { usz aligned_bytes = mem::aligned_offset(bytes, DEFAULT_MEM_ALIGNMENT); if (!this.free_list) @@ -130,7 +130,7 @@ fn void*! SimpleHeapAllocator._alloc(SimpleHeapAllocator* this, usz bytes) @priv return this.alloc(aligned_bytes); } -fn void! SimpleHeapAllocator.add_block(SimpleHeapAllocator* this, usz aligned_bytes) @private +fn void! SimpleHeapAllocator.add_block(SimpleHeapAllocator* this, usz aligned_bytes) @local { assert(mem::aligned_offset(aligned_bytes, DEFAULT_MEM_ALIGNMENT) == aligned_bytes); char[] result = this.alloc_fn(aligned_bytes + Header.sizeof)?; @@ -141,7 +141,7 @@ fn void! SimpleHeapAllocator.add_block(SimpleHeapAllocator* this, usz aligned_by } -fn void SimpleHeapAllocator._free(SimpleHeapAllocator* this, void* ptr) @private +fn void SimpleHeapAllocator._free(SimpleHeapAllocator* this, void* ptr) @local { // Empty ptr -> do nothing. if (!ptr) return; diff --git a/lib/std/core/string.c3 b/lib/std/core/string.c3 index 07920ac56..9f304dbae 100644 --- a/lib/std/core/string.c3 +++ b/lib/std/core/string.c3 @@ -6,7 +6,7 @@ typedef DynStr = VarString; typedef DynString = VarString; typedef DString = VarString; typedef VString = VarString; - +typedef Text = VarString; const usz MIN_CAPACITY = 16; diff --git a/lib/std/hash/sha1.c3 b/lib/std/hash/sha1.c3 new file mode 100644 index 000000000..99455f321 --- /dev/null +++ b/lib/std/hash/sha1.c3 @@ -0,0 +1,237 @@ +// Copyright (c) 2021 Christoffer Lerno. All rights reserved. +// Use of this source code is governed by the MIT license +// a copy of which can be found in the LICENSE_STDLIB file. +// +// Implementation was off Steve Reid's SHA-1 C implementation + +module std::hash::sha1; +import std::bits; + +struct Sha1 +{ + uint[5] state; + uint[2] count; + char[64] buffer; +} + +fn void Sha1.init(Sha1* this) +{ + // SHA1 initialization constants + *this = { + .state = { + 0x67452301, + 0xEFCDAB89, + 0x98BADCFE, + 0x10325476, + 0xC3D2E1F0 + } + }; +} + +/** + * @param [&inout] this + * @param [in] data + * @require data.len <= uint.max + **/ +fn void Sha1.update(Sha1* this, char[] data) +{ + uint j = this.count[0]; + uint len = data.len; + if ((this.count[0] += len << 3) < j) this.count[1]++; + this.count[1] += len >> 29; + j = (j >> 3) & 63; + uint i; + if (j + len > 63) + { + i = 64 - j; + this.buffer[j..] = data[:i]; + sha1_transform(&this.state, &this.buffer); + for (; i + 63 < len; i += 64) + { + sha1_transform(&this.state, &data[i]); + } + j = 0; + } + this.buffer[j:len - i] = data[i..]; +} + + +fn char[20] Sha1.final(Sha1* this) +{ + char[8] finalcount; + for (uint i = 0; i < 8; i++) + { + finalcount[i] = (char)((this.count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 0xFF); + } + this.update(char[] { 0o200 }); + while ((this.count[0] & 504) != 448) + { + this.update(char[] { 0 }); + } + + this.update(&finalcount); + char[20] digest; + for (uint i = 0; i < 20; i++) + { + digest[i] = (char)((this.state[i >> 2] >> ((3 - (i & 3)) * 8)) & 0xFF); + } + + // Clear mem + mem::clear(this, Sha1.sizeof); + finalcount = {}; + return digest; +} + +union Long16 @local +{ + char[64] c; + uint[16] l; +} + +macro @blk(&block, i) @local +{ + return (block.l[i & 15] = (block.l[(i + 13) & 15] ^ block.l[(i + 8) & 15] + ^ block.l[(i + 2) & 15] ^ block.l[i & 15]).rotl(1)); +} + +macro @blk0(&block, i) @local +{ +$if (env::BIG_ENDIAN): + return block.l[i]; +$else: + return block.l[i] = (block.l[i].rotl(24) & 0xFF00FF00) + | (block.l[i].rotl(8) & 0x00FF00FF); +$endif; +} + +macro @r0(&block, v, &w, x, y, &z, i) @local +{ + z += ((w & (x ^ y)) ^ y) + @blk0(block, i) + 0x5A827999 + v.rotl(5); + w = w.rotl(30); +} + +macro @r1(&block, v, &w, x, y, &z, i) @local +{ + z += ((w & (x ^ y)) ^ y) + @blk(block, i) + 0x5A827999 + v.rotl(5); + w = w.rotl(30); +} + +macro @r2(&block, v, &w, x, y, &z, i) @local +{ + z += (w ^ x ^ y) + @blk(block, i) + 0x6ED9EBA1 + v.rotl(5); + w = w.rotl(30); +} + +macro @r3(&block, v, &w, x, y, &z, i) @local +{ + z += (((w | x) &y) | (w & x)) + @blk(block, i) + 0x8F1BBCDC + v.rotl(5); + w = w.rotl(30); +} + +macro @r4(&block, v, &w, x, y, &z, i) @local +{ + z += (w ^ x ^ y) + @blk(block, i) + 0xCA62C1D6 + v.rotl(5); + w = w.rotl(30); +} + +/** + * @param [&inout] state + * @param [&in] buffer + **/ +fn void sha1_transform(uint* state, char* buffer) @local +{ + Long16 block; + block.c[..] = buffer[:64]; + uint a = state[0]; + uint b = state[1]; + uint c = state[2]; + uint d = state[3]; + uint e = state[4]; + @r0(block, a, b, c, d, e, 0); + @r0(block, e, a, b, c, d, 1); + @r0(block, d, e, a, b, c, 2); + @r0(block, c, d, e, a, b, 3); + @r0(block, b, c, d, e, a, 4); + @r0(block, a, b, c, d, e, 5); + @r0(block, e, a, b, c, d, 6); + @r0(block, d, e, a, b, c, 7); + @r0(block, c, d, e, a, b, 8); + @r0(block, b, c, d, e, a, 9); + @r0(block, a, b, c, d, e, 10); + @r0(block, e, a, b, c, d, 11); + @r0(block, d, e, a, b, c, 12); + @r0(block, c, d, e, a, b, 13); + @r0(block, b, c, d, e, a, 14); + @r0(block, a, b, c, d, e, 15); + @r1(block, e, a, b, c, d, 16); + @r1(block, d, e, a, b, c, 17); + @r1(block, c, d, e, a, b, 18); + @r1(block, b, c, d, e, a, 19); + @r2(block, a, b, c, d, e, 20); + @r2(block, e, a, b, c, d, 21); + @r2(block, d, e, a, b, c, 22); + @r2(block, c, d, e, a, b, 23); + @r2(block, b, c, d, e, a, 24); + @r2(block, a, b, c, d, e, 25); + @r2(block, e, a, b, c, d, 26); + @r2(block, d, e, a, b, c, 27); + @r2(block, c, d, e, a, b, 28); + @r2(block, b, c, d, e, a, 29); + @r2(block, a, b, c, d, e, 30); + @r2(block, e, a, b, c, d, 31); + @r2(block, d, e, a, b, c, 32); + @r2(block, c, d, e, a, b, 33); + @r2(block, b, c, d, e, a, 34); + @r2(block, a, b, c, d, e, 35); + @r2(block, e, a, b, c, d, 36); + @r2(block, d, e, a, b, c, 37); + @r2(block, c, d, e, a, b, 38); + @r2(block, b, c, d, e, a, 39); + @r3(block, a, b, c, d, e, 40); + @r3(block, e, a, b, c, d, 41); + @r3(block, d, e, a, b, c, 42); + @r3(block, c, d, e, a, b, 43); + @r3(block, b, c, d, e, a, 44); + @r3(block, a, b, c, d, e, 45); + @r3(block, e, a, b, c, d, 46); + @r3(block, d, e, a, b, c, 47); + @r3(block, c, d, e, a, b, 48); + @r3(block, b, c, d, e, a, 49); + @r3(block, a, b, c, d, e, 50); + @r3(block, e, a, b, c, d, 51); + @r3(block, d, e, a, b, c, 52); + @r3(block, c, d, e, a, b, 53); + @r3(block, b, c, d, e, a, 54); + @r3(block, a, b, c, d, e, 55); + @r3(block, e, a, b, c, d, 56); + @r3(block, d, e, a, b, c, 57); + @r3(block, c, d, e, a, b, 58); + @r3(block, b, c, d, e, a, 59); + @r4(block, a, b, c, d, e, 60); + @r4(block, e, a, b, c, d, 61); + @r4(block, d, e, a, b, c, 62); + @r4(block, c, d, e, a, b, 63); + @r4(block, b, c, d, e, a, 64); + @r4(block, a, b, c, d, e, 65); + @r4(block, e, a, b, c, d, 66); + @r4(block, d, e, a, b, c, 67); + @r4(block, c, d, e, a, b, 68); + @r4(block, b, c, d, e, a, 69); + @r4(block, a, b, c, d, e, 70); + @r4(block, e, a, b, c, d, 71); + @r4(block, d, e, a, b, c, 72); + @r4(block, c, d, e, a, b, 73); + @r4(block, b, c, d, e, a, 74); + @r4(block, a, b, c, d, e, 75); + @r4(block, e, a, b, c, d, 76); + @r4(block, d, e, a, b, c, 77); + @r4(block, c, d, e, a, b, 78); + @r4(block, b, c, d, e, a, 79); + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + a = b = c = d = e = 0; + buffer[:64] = 0; +} \ No newline at end of file diff --git a/test/unit/stdlib/hash/sha1.c3 b/test/unit/stdlib/hash/sha1.c3 new file mode 100644 index 000000000..1364f92c3 --- /dev/null +++ b/test/unit/stdlib/hash/sha1.c3 @@ -0,0 +1,30 @@ +module std::hash::sha1_test @test; +import std::hash::sha1; + +fn void test_sha1_abc() +{ + Sha1 sha; + sha.init(); + sha.update("abc"); + assert(sha.final() == x"A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D"); +} + +fn void test_sha1_longer() +{ + Sha1 sha; + sha.init(); + sha.update("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"); + assert(sha.final() == x"84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1"); +} + +fn void test_sha1_million_a() +{ + Sha1 sha; + sha.init(); + const int COUNT = 1_000_000; + for (int i = 0; i < COUNT / 10; i++) + { + sha.update("aaaaaaaaaa"); + } + assert(sha.final() == x"34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F"); +} \ No newline at end of file