Commit 0b0ec650 authored by Darryl Sokoloski's avatar Darryl Sokoloski

Added fast SHA1 implementation in x86 assembly for testing.

parent 1552b043
/*
* SHA-1 hash in x86 assembly
*
* Copyright (c) 2017 Project Nayuki. (MIT License)
* https://www.nayuki.io/page/fast-sha1-hash-implementation-in-x86-assembly
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
* - The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* - The Software is provided "as is", without warranty of any kind, express or
* implied, including but not limited to the warranties of merchantability,
* fitness for a particular purpose and noninfringement. In no event shall the
* authors or copyright holders be liable for any claim, damages or other
* liability, whether in an action of contract, tort or otherwise, arising from,
* out of or in connection with the Software or the use or other dealings in the
* Software.
*/
/* void sha1_compress(uint32_t state[static 5], const uint8_t block[static 64]) */
.globl sha1_compress
sha1_compress:
/*
* Storage usage:
* Bytes Location Description
* 4 eax SHA-1 state variable A
* 4 ebx SHA-1 state variable B
* 4 ecx SHA-1 state variable C
* 4 edx SHA-1 state variable D
* 4 ebp SHA-1 state variable E
* 4 esi Temporary for calculation per round
* 4 edi (First 16 rounds) base address of block array argument (read-only); (last 64 rounds) temporary for calculation per round
* 4 esp x86 stack pointer
* 64 [esp+ 0] Circular buffer of most recent 16 key schedule items, 4 bytes each
* 4 [esp+64] Caller's value of ebx
* 4 [esp+68] Caller's value of esi
* 4 [esp+72] Caller's value of edi
* 4 [esp+76] Caller's value of ebp
*/
#define ROUND0a(a, b, c, d, e, i) \
movl (i*4)(%edi), %esi; \
bswapl %esi; \
movl %esi, (i*4)(%esp); \
addl %esi, %e; \
movl %c, %esi; \
xorl %d, %esi; \
andl %b, %esi; \
xorl %d, %esi; \
ROUNDTAIL(a, b, e, i, 0x5A827999)
#define SCHEDULE(i, e) \
movl (((i- 3)&0xF)*4)(%esp), %esi; \
xorl (((i- 8)&0xF)*4)(%esp), %esi; \
xorl (((i-14)&0xF)*4)(%esp), %esi; \
xorl (((i-16)&0xF)*4)(%esp), %esi; \
roll $1, %esi; \
addl %esi, %e; \
movl %esi, ((i&0xF)*4)(%esp);
#define ROUND0b(a, b, c, d, e, i) \
SCHEDULE(i, e) \
movl %c, %esi; \
xorl %d, %esi; \
andl %b, %esi; \
xorl %d, %esi; \
ROUNDTAIL(a, b, e, i, 0x5A827999)
#define ROUND1(a, b, c, d, e, i) \
SCHEDULE(i, e) \
movl %b, %esi; \
xorl %c, %esi; \
xorl %d, %esi; \
ROUNDTAIL(a, b, e, i, 0x6ED9EBA1)
#define ROUND2(a, b, c, d, e, i) \
SCHEDULE(i, e) \
movl %c, %esi; \
movl %c, %edi; \
orl %d, %esi; \
andl %b, %esi; \
andl %d, %edi; \
orl %edi, %esi; \
ROUNDTAIL(a, b, e, i, 0x8F1BBCDC)
#define ROUND3(a, b, c, d, e, i) \
SCHEDULE(i, e) \
movl %b, %esi; \
xorl %c, %esi; \
xorl %d, %esi; \
ROUNDTAIL(a, b, e, i, 0xCA62C1D6)
#define ROUNDTAIL(a, b, e, i, k) \
roll $30, %b; \
leal k(%e,%esi), %e; \
movl %a, %esi; \
roll $5, %esi; \
addl %esi, %e;
/* Save registers */
subl $80, %esp
movl %ebx, 64(%esp)
movl %esi, 68(%esp)
movl %edi, 72(%esp)
movl %ebp, 76(%esp)
/* Load arguments */
movl 84(%esp), %esi /* state */
movl 88(%esp), %edi /* block */
movl 0(%esi), %eax /* a */
movl 4(%esi), %ebx /* b */
movl 8(%esi), %ecx /* c */
movl 12(%esi), %edx /* d */
movl 16(%esi), %ebp /* e */
/* 80 rounds of hashing */
ROUND0a(eax, ebx, ecx, edx, ebp, 0)
ROUND0a(ebp, eax, ebx, ecx, edx, 1)
ROUND0a(edx, ebp, eax, ebx, ecx, 2)
ROUND0a(ecx, edx, ebp, eax, ebx, 3)
ROUND0a(ebx, ecx, edx, ebp, eax, 4)
ROUND0a(eax, ebx, ecx, edx, ebp, 5)
ROUND0a(ebp, eax, ebx, ecx, edx, 6)
ROUND0a(edx, ebp, eax, ebx, ecx, 7)
ROUND0a(ecx, edx, ebp, eax, ebx, 8)
ROUND0a(ebx, ecx, edx, ebp, eax, 9)
ROUND0a(eax, ebx, ecx, edx, ebp, 10)
ROUND0a(ebp, eax, ebx, ecx, edx, 11)
ROUND0a(edx, ebp, eax, ebx, ecx, 12)
ROUND0a(ecx, edx, ebp, eax, ebx, 13)
ROUND0a(ebx, ecx, edx, ebp, eax, 14)
ROUND0a(eax, ebx, ecx, edx, ebp, 15)
ROUND0b(ebp, eax, ebx, ecx, edx, 16)
ROUND0b(edx, ebp, eax, ebx, ecx, 17)
ROUND0b(ecx, edx, ebp, eax, ebx, 18)
ROUND0b(ebx, ecx, edx, ebp, eax, 19)
ROUND1(eax, ebx, ecx, edx, ebp, 20)
ROUND1(ebp, eax, ebx, ecx, edx, 21)
ROUND1(edx, ebp, eax, ebx, ecx, 22)
ROUND1(ecx, edx, ebp, eax, ebx, 23)
ROUND1(ebx, ecx, edx, ebp, eax, 24)
ROUND1(eax, ebx, ecx, edx, ebp, 25)
ROUND1(ebp, eax, ebx, ecx, edx, 26)
ROUND1(edx, ebp, eax, ebx, ecx, 27)
ROUND1(ecx, edx, ebp, eax, ebx, 28)
ROUND1(ebx, ecx, edx, ebp, eax, 29)
ROUND1(eax, ebx, ecx, edx, ebp, 30)
ROUND1(ebp, eax, ebx, ecx, edx, 31)
ROUND1(edx, ebp, eax, ebx, ecx, 32)
ROUND1(ecx, edx, ebp, eax, ebx, 33)
ROUND1(ebx, ecx, edx, ebp, eax, 34)
ROUND1(eax, ebx, ecx, edx, ebp, 35)
ROUND1(ebp, eax, ebx, ecx, edx, 36)
ROUND1(edx, ebp, eax, ebx, ecx, 37)
ROUND1(ecx, edx, ebp, eax, ebx, 38)
ROUND1(ebx, ecx, edx, ebp, eax, 39)
ROUND2(eax, ebx, ecx, edx, ebp, 40)
ROUND2(ebp, eax, ebx, ecx, edx, 41)
ROUND2(edx, ebp, eax, ebx, ecx, 42)
ROUND2(ecx, edx, ebp, eax, ebx, 43)
ROUND2(ebx, ecx, edx, ebp, eax, 44)
ROUND2(eax, ebx, ecx, edx, ebp, 45)
ROUND2(ebp, eax, ebx, ecx, edx, 46)
ROUND2(edx, ebp, eax, ebx, ecx, 47)
ROUND2(ecx, edx, ebp, eax, ebx, 48)
ROUND2(ebx, ecx, edx, ebp, eax, 49)
ROUND2(eax, ebx, ecx, edx, ebp, 50)
ROUND2(ebp, eax, ebx, ecx, edx, 51)
ROUND2(edx, ebp, eax, ebx, ecx, 52)
ROUND2(ecx, edx, ebp, eax, ebx, 53)
ROUND2(ebx, ecx, edx, ebp, eax, 54)
ROUND2(eax, ebx, ecx, edx, ebp, 55)
ROUND2(ebp, eax, ebx, ecx, edx, 56)
ROUND2(edx, ebp, eax, ebx, ecx, 57)
ROUND2(ecx, edx, ebp, eax, ebx, 58)
ROUND2(ebx, ecx, edx, ebp, eax, 59)
ROUND3(eax, ebx, ecx, edx, ebp, 60)
ROUND3(ebp, eax, ebx, ecx, edx, 61)
ROUND3(edx, ebp, eax, ebx, ecx, 62)
ROUND3(ecx, edx, ebp, eax, ebx, 63)
ROUND3(ebx, ecx, edx, ebp, eax, 64)
ROUND3(eax, ebx, ecx, edx, ebp, 65)
ROUND3(ebp, eax, ebx, ecx, edx, 66)
ROUND3(edx, ebp, eax, ebx, ecx, 67)
ROUND3(ecx, edx, ebp, eax, ebx, 68)
ROUND3(ebx, ecx, edx, ebp, eax, 69)
ROUND3(eax, ebx, ecx, edx, ebp, 70)
ROUND3(ebp, eax, ebx, ecx, edx, 71)
ROUND3(edx, ebp, eax, ebx, ecx, 72)
ROUND3(ecx, edx, ebp, eax, ebx, 73)
ROUND3(ebx, ecx, edx, ebp, eax, 74)
ROUND3(eax, ebx, ecx, edx, ebp, 75)
ROUND3(ebp, eax, ebx, ecx, edx, 76)
ROUND3(edx, ebp, eax, ebx, ecx, 77)
ROUND3(ecx, edx, ebp, eax, ebx, 78)
ROUND3(ebx, ecx, edx, ebp, eax, 79)
/* Save updated state */
movl 84(%esp), %esi
addl %eax, 0(%esi)
addl %ebx, 4(%esi)
addl %ecx, 8(%esi)
addl %edx, 12(%esi)
addl %ebp, 16(%esi)
/* Restore registers */
movl 64(%esp), %ebx
movl 68(%esp), %esi
movl 72(%esp), %edi
movl 76(%esp), %ebp
addl $80, %esp
retl
/*
* SHA-1 hash in x86-64 assembly
*
* Copyright (c) 2017 Project Nayuki. (MIT License)
* https://www.nayuki.io/page/fast-sha1-hash-implementation-in-x86-assembly
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
* - The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* - The Software is provided "as is", without warranty of any kind, express or
* implied, including but not limited to the warranties of merchantability,
* fitness for a particular purpose and noninfringement. In no event shall the
* authors or copyright holders be liable for any claim, damages or other
* liability, whether in an action of contract, tort or otherwise, arising from,
* out of or in connection with the Software or the use or other dealings in the
* Software.
*/
/* void sha1_compress(uint32_t state[static 5], const uint8_t block[static 64]) */
.globl sha1_compress
sha1_compress:
/*
* Storage usage:
* Bytes Location Description
* 4 eax SHA-1 state variable A
* 4 ebx SHA-1 state variable B
* 4 ecx SHA-1 state variable C
* 4 edx SHA-1 state variable D
* 4 ebp SHA-1 state variable E
* 4 esi Temporary for calculation per round
* 4 edi (Last 64 rounds) temporary for calculation per round
* 8 rdi (First 16 rounds) base address of block array argument (read-only)
* 8 r8 Base address of state array argument (read-only)
* 8 rsp x86-64 stack pointer
* 64 [rsp+0] Circular buffer of most recent 16 key schedule items, 4 bytes each
* 16 xmm0 Caller's value of rbx (only low 64 bits are used)
* 16 xmm1 Caller's value of rbp (only low 64 bits are used)
*/
#define ROUND0a(a, b, c, d, e, i) \
movl (i*4)(%rdi), %esi; \
bswapl %esi; \
movl %esi, (i*4)(%rsp); \
addl %esi, %e; \
movl %c, %esi; \
xorl %d, %esi; \
andl %b, %esi; \
xorl %d, %esi; \
ROUNDTAIL(a, b, e, i, 0x5A827999)
#define SCHEDULE(i, e) \
movl (((i- 3)&0xF)*4)(%rsp), %esi; \
xorl (((i- 8)&0xF)*4)(%rsp), %esi; \
xorl (((i-14)&0xF)*4)(%rsp), %esi; \
xorl (((i-16)&0xF)*4)(%rsp), %esi; \
roll $1, %esi; \
addl %esi, %e; \
movl %esi, ((i&0xF)*4)(%rsp);
#define ROUND0b(a, b, c, d, e, i) \
SCHEDULE(i, e) \
movl %c, %esi; \
xorl %d, %esi; \
andl %b, %esi; \
xorl %d, %esi; \
ROUNDTAIL(a, b, e, i, 0x5A827999)
#define ROUND1(a, b, c, d, e, i) \
SCHEDULE(i, e) \
movl %b, %esi; \
xorl %c, %esi; \
xorl %d, %esi; \
ROUNDTAIL(a, b, e, i, 0x6ED9EBA1)
#define ROUND2(a, b, c, d, e, i) \
SCHEDULE(i, e) \
movl %c, %esi; \
movl %c, %edi; \
orl %d, %esi; \
andl %b, %esi; \
andl %d, %edi; \
orl %edi, %esi; \
ROUNDTAIL(a, b, e, i, -0x70E44324)
#define ROUND3(a, b, c, d, e, i) \
SCHEDULE(i, e) \
movl %b, %esi; \
xorl %c, %esi; \
xorl %d, %esi; \
ROUNDTAIL(a, b, e, i, -0x359D3E2A)
#define ROUNDTAIL(a, b, e, i, k) \
roll $30, %b; \
leal k(%e,%esi), %e; \
movl %a, %esi; \
roll $5, %esi; \
addl %esi, %e;
/* Save registers, allocate scratch space */
movq %rbx, %xmm0
movq %rbp, %xmm1
subq $64, %rsp
/* Load arguments */
movq %rdi, %r8
movl 0(%rdi), %eax /* a */
movl 4(%rdi), %ebx /* b */
movl 8(%rdi), %ecx /* c */
movl 12(%rdi), %edx /* d */
movl 16(%rdi), %ebp /* e */
movq %rsi, %rdi
/* 80 rounds of hashing */
ROUND0a(eax, ebx, ecx, edx, ebp, 0)
ROUND0a(ebp, eax, ebx, ecx, edx, 1)
ROUND0a(edx, ebp, eax, ebx, ecx, 2)
ROUND0a(ecx, edx, ebp, eax, ebx, 3)
ROUND0a(ebx, ecx, edx, ebp, eax, 4)
ROUND0a(eax, ebx, ecx, edx, ebp, 5)
ROUND0a(ebp, eax, ebx, ecx, edx, 6)
ROUND0a(edx, ebp, eax, ebx, ecx, 7)
ROUND0a(ecx, edx, ebp, eax, ebx, 8)
ROUND0a(ebx, ecx, edx, ebp, eax, 9)
ROUND0a(eax, ebx, ecx, edx, ebp, 10)
ROUND0a(ebp, eax, ebx, ecx, edx, 11)
ROUND0a(edx, ebp, eax, ebx, ecx, 12)
ROUND0a(ecx, edx, ebp, eax, ebx, 13)
ROUND0a(ebx, ecx, edx, ebp, eax, 14)
ROUND0a(eax, ebx, ecx, edx, ebp, 15)
ROUND0b(ebp, eax, ebx, ecx, edx, 16)
ROUND0b(edx, ebp, eax, ebx, ecx, 17)
ROUND0b(ecx, edx, ebp, eax, ebx, 18)
ROUND0b(ebx, ecx, edx, ebp, eax, 19)
ROUND1(eax, ebx, ecx, edx, ebp, 20)
ROUND1(ebp, eax, ebx, ecx, edx, 21)
ROUND1(edx, ebp, eax, ebx, ecx, 22)
ROUND1(ecx, edx, ebp, eax, ebx, 23)
ROUND1(ebx, ecx, edx, ebp, eax, 24)
ROUND1(eax, ebx, ecx, edx, ebp, 25)
ROUND1(ebp, eax, ebx, ecx, edx, 26)
ROUND1(edx, ebp, eax, ebx, ecx, 27)
ROUND1(ecx, edx, ebp, eax, ebx, 28)
ROUND1(ebx, ecx, edx, ebp, eax, 29)
ROUND1(eax, ebx, ecx, edx, ebp, 30)
ROUND1(ebp, eax, ebx, ecx, edx, 31)
ROUND1(edx, ebp, eax, ebx, ecx, 32)
ROUND1(ecx, edx, ebp, eax, ebx, 33)
ROUND1(ebx, ecx, edx, ebp, eax, 34)
ROUND1(eax, ebx, ecx, edx, ebp, 35)
ROUND1(ebp, eax, ebx, ecx, edx, 36)
ROUND1(edx, ebp, eax, ebx, ecx, 37)
ROUND1(ecx, edx, ebp, eax, ebx, 38)
ROUND1(ebx, ecx, edx, ebp, eax, 39)
ROUND2(eax, ebx, ecx, edx, ebp, 40)
ROUND2(ebp, eax, ebx, ecx, edx, 41)
ROUND2(edx, ebp, eax, ebx, ecx, 42)
ROUND2(ecx, edx, ebp, eax, ebx, 43)
ROUND2(ebx, ecx, edx, ebp, eax, 44)
ROUND2(eax, ebx, ecx, edx, ebp, 45)
ROUND2(ebp, eax, ebx, ecx, edx, 46)
ROUND2(edx, ebp, eax, ebx, ecx, 47)
ROUND2(ecx, edx, ebp, eax, ebx, 48)
ROUND2(ebx, ecx, edx, ebp, eax, 49)
ROUND2(eax, ebx, ecx, edx, ebp, 50)
ROUND2(ebp, eax, ebx, ecx, edx, 51)
ROUND2(edx, ebp, eax, ebx, ecx, 52)
ROUND2(ecx, edx, ebp, eax, ebx, 53)
ROUND2(ebx, ecx, edx, ebp, eax, 54)
ROUND2(eax, ebx, ecx, edx, ebp, 55)
ROUND2(ebp, eax, ebx, ecx, edx, 56)
ROUND2(edx, ebp, eax, ebx, ecx, 57)
ROUND2(ecx, edx, ebp, eax, ebx, 58)
ROUND2(ebx, ecx, edx, ebp, eax, 59)
ROUND3(eax, ebx, ecx, edx, ebp, 60)
ROUND3(ebp, eax, ebx, ecx, edx, 61)
ROUND3(edx, ebp, eax, ebx, ecx, 62)
ROUND3(ecx, edx, ebp, eax, ebx, 63)
ROUND3(ebx, ecx, edx, ebp, eax, 64)
ROUND3(eax, ebx, ecx, edx, ebp, 65)
ROUND3(ebp, eax, ebx, ecx, edx, 66)
ROUND3(edx, ebp, eax, ebx, ecx, 67)
ROUND3(ecx, edx, ebp, eax, ebx, 68)
ROUND3(ebx, ecx, edx, ebp, eax, 69)
ROUND3(eax, ebx, ecx, edx, ebp, 70)
ROUND3(ebp, eax, ebx, ecx, edx, 71)
ROUND3(edx, ebp, eax, ebx, ecx, 72)
ROUND3(ecx, edx, ebp, eax, ebx, 73)
ROUND3(ebx, ecx, edx, ebp, eax, 74)
ROUND3(eax, ebx, ecx, edx, ebp, 75)
ROUND3(ebp, eax, ebx, ecx, edx, 76)
ROUND3(edx, ebp, eax, ebx, ecx, 77)
ROUND3(ecx, edx, ebp, eax, ebx, 78)
ROUND3(ebx, ecx, edx, ebp, eax, 79)
/* Save updated state */
addl %eax, 0(%r8)
addl %ebx, 4(%r8)
addl %ecx, 8(%r8)
addl %edx, 12(%r8)
addl %ebp, 16(%r8)
/* Restore registers */
movq %xmm0, %rbx
movq %xmm1, %rbp
addq $64, %rsp
retq
/*
* SHA-1 hash in C and x86 assembly
*
* Copyright (c) 2017 Project Nayuki. (MIT License)
* https://www.nayuki.io/page/fast-sha1-hash-implementation-in-x86-assembly
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
* - The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
* - The Software is provided "as is", without warranty of any kind, express or
* implied, including but not limited to the warranties of merchantability,
* fitness for a particular purpose and noninfringement. In no event shall the
* authors or copyright holders be liable for any claim, damages or other
* liability, whether in an action of contract, tort or otherwise, arising from,
* out of or in connection with the Software or the use or other dealings in the
* Software.
*/
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* Function prototypes */
#define BLOCK_LEN 64 // In bytes
#define STATE_LEN 5 // In words
static bool self_check(void);
void sha1_hash(const uint8_t message[], size_t len, uint32_t hash[static STATE_LEN]);
// Link this program with an external C or x86 compression function
extern void sha1_compress(uint32_t state[static STATE_LEN], const uint8_t block[static BLOCK_LEN]);
/* Main program */
int main(void) {
// Self-check
if (!self_check()) {
printf("Self-check failed\n");
return EXIT_FAILURE;
}
printf("Self-check passed\n");
// Benchmark speed
uint32_t state[STATE_LEN] = {0};
uint8_t block[BLOCK_LEN] = {0};
const long ITERS = 10000000;
clock_t start_time = clock();
for (long i = 0; i < ITERS; i++)
sha1_compress(state, block);
printf("Speed: %.1f MB/s\n", (double)ITERS * (sizeof(block) / sizeof(block[0]))
/ (clock() - start_time) * CLOCKS_PER_SEC / 1000000);
return EXIT_SUCCESS;
}
/* Test vectors and checker */
static bool self_check(void) {
struct TestCase {
uint32_t answer[STATE_LEN];
const char *message;
};
static const struct TestCase cases[] = {
#define TESTCASE(a,b,c,d,e,msg) {{UINT32_C(a),UINT32_C(b),UINT32_C(c),UINT32_C(d),UINT32_C(e)}, msg}
TESTCASE(0xDA39A3EE,0x5E6B4B0D,0x3255BFEF,0x95601890,0xAFD80709, ""),
TESTCASE(0x86F7E437,0xFAA5A7FC,0xE15D1DDC,0xB9EAEAEA,0x377667B8, "a"),
TESTCASE(0xA9993E36,0x4706816A,0xBA3E2571,0x7850C26C,0x9CD0D89D, "abc"),
TESTCASE(0xC12252CE,0xDA8BE899,0x4D5FA029,0x0A47231C,0x1D16AAE3, "message digest"),
TESTCASE(0x32D10C7B,0x8CF96570,0xCA04CE37,0xF2A19D84,0x240D3A89, "abcdefghijklmnopqrstuvwxyz"),
TESTCASE(0x84983E44,0x1C3BD26E,0xBAAE4AA1,0xF95129E5,0xE54670F1, "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"),
#undef TESTCASE
};
size_t numCases = sizeof(cases) / sizeof(cases[0]);
for (size_t i = 0; i < numCases; i++) {
const struct TestCase *tc = &cases[i];
size_t len = strlen(tc->message);
uint8_t *msg = calloc(len, sizeof(uint8_t));
if (msg == NULL) {
perror("calloc");
exit(1);
}
for (size_t j = 0; j < len; j++)
msg[j] = (uint8_t)tc->message[j];
uint32_t hash[STATE_LEN];
sha1_hash(msg, len, hash);
if (memcmp(hash, tc->answer, sizeof(tc->answer)) != 0)
return false;
free(msg);
}
return true;
}
/* Full message hasher */
void sha1_hash(const uint8_t message[], size_t len, uint32_t hash[static STATE_LEN]) {
hash[0] = UINT32_C(0x67452301);
hash[1] = UINT32_C(0xEFCDAB89);
hash[2] = UINT32_C(0x98BADCFE);
hash[3] = UINT32_C(0x10325476);
hash[4] = UINT32_C(0xC3D2E1F0);
#define LENGTH_SIZE 8 // In bytes
size_t off;
for (off = 0; len - off >= BLOCK_LEN; off += BLOCK_LEN)
sha1_compress(hash, &message[off]);
uint8_t block[BLOCK_LEN] = {0};
size_t rem = len - off;
memcpy(block, &message[off], rem);
block[rem] = 0x80;
rem++;
if (BLOCK_LEN - rem < LENGTH_SIZE) {
sha1_compress(hash, block);
memset(block, 0, sizeof(block));
}
block[BLOCK_LEN - 1] = (uint8_t)((len & 0x1FU) << 3);
len >>= 5;
for (int i = 1; i < LENGTH_SIZE; i++, len >>= 8)
block[BLOCK_LEN - 1 - i] = (uint8_t)(len & 0xFFU);
sha1_compress(hash, block);
}