Tor 0.4.9.2-alpha-dev
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
hashx.c
1/* Copyright (c) 2020 tevador <tevador@gmail.com> */
2/* See LICENSE for licensing information */
3
4#include <stdlib.h>
5#include <string.h>
6#include <assert.h>
7
8#include <hashx.h>
9#include "blake2.h"
10#include "hashx_endian.h"
11#include "program.h"
12#include "context.h"
13#include "compiler.h"
14
15#if HASHX_SIZE > 32
16#error HASHX_SIZE cannot be more than 32
17#endif
18
19#ifndef HASHX_BLOCK_MODE
20#define HASHX_INPUT_ARGS input
21#else
22#define HASHX_INPUT_ARGS input, size
23#endif
24
25static bool initialize_program(hashx_ctx* ctx, siphash_state keys[2]) {
26 if (!hashx_program_generate(&keys[0], &ctx->program)) {
27 return false;
28 }
29#ifndef HASHX_BLOCK_MODE
30 memcpy(&ctx->keys, &keys[1], 32);
31#else
32 memcpy(&ctx->params.salt, &keys[1], 32);
33#endif
34 return true;
35}
36
37hashx_result hashx_make(hashx_ctx* ctx, const void* seed, size_t size) {
38 assert(ctx != NULL);
39 assert(seed != NULL || size == 0);
40
41 uint8_t keys_bytes[2 * sizeof(siphash_state)];
42 blake2b_state hash_state;
43 hashx_blake2b_init_param(&hash_state, &hashx_blake2_params);
44 hashx_blake2b_update(&hash_state, seed, size);
45 hashx_blake2b_final(&hash_state, keys_bytes, sizeof(keys_bytes));
46
47 siphash_state keys[2];
48 keys[0].v0 = load64(keys_bytes + 0 * sizeof(uint64_t));
49 keys[0].v1 = load64(keys_bytes + 1 * sizeof(uint64_t));
50 keys[0].v2 = load64(keys_bytes + 2 * sizeof(uint64_t));
51 keys[0].v3 = load64(keys_bytes + 3 * sizeof(uint64_t));
52 keys[1].v0 = load64(keys_bytes + 4 * sizeof(uint64_t));
53 keys[1].v1 = load64(keys_bytes + 5 * sizeof(uint64_t));
54 keys[1].v2 = load64(keys_bytes + 6 * sizeof(uint64_t));
55 keys[1].v3 = load64(keys_bytes + 7 * sizeof(uint64_t));
56
57 ctx->func_type = (hashx_type)0;
58 if (!initialize_program(ctx, keys)) {
59 return HASHX_FAIL_SEED;
60 }
61
62 switch (ctx->ctx_type) {
63 case HASHX_TYPE_INTERPRETED:
64 ctx->func_type = HASHX_TYPE_INTERPRETED;
65 return HASHX_OK;
66 case HASHX_TYPE_COMPILED:
67 case HASHX_TRY_COMPILE:
68 if (ctx->compiler_mem != NULL &&
69 hashx_compile(&ctx->program, ctx->compiler_mem)) {
70 ctx->func_type = HASHX_TYPE_COMPILED;
71 return HASHX_OK;
72 }
73 if (ctx->ctx_type == HASHX_TRY_COMPILE) {
74 ctx->func_type = HASHX_TYPE_INTERPRETED;
75 return HASHX_OK;
76 } else {
77 return HASHX_FAIL_COMPILE;
78 }
79 default:
80 return HASHX_FAIL_UNDEFINED;
81 }
82}
83
84hashx_result hashx_query_type(hashx_ctx* ctx, hashx_type *type_out) {
85 assert(ctx != NULL);
86 assert(type_out != NULL);
87
88 if (ctx->func_type == (hashx_type)0) {
89 return HASHX_FAIL_UNPREPARED;
90 }
91 *type_out = ctx->func_type;
92 return HASHX_OK;
93}
94
95hashx_result hashx_exec(const hashx_ctx* ctx, HASHX_INPUT, void* output) {
96 assert(ctx != NULL);
97 assert(output != NULL);
98
99 uint64_t r[8];
100#ifndef HASHX_BLOCK_MODE
101 hashx_siphash24_ctr_state512(&ctx->keys, input, r);
102#else
103 hashx_blake2b_4r(&ctx->params, input, size, r);
104#endif
105
106 if (ctx->func_type == HASHX_TYPE_COMPILED) {
107 typedef void program_func(uint64_t r[8]);
108 assert(ctx->compiler_mem != NULL);
109 ((program_func*)ctx->compiler_mem)(r);
110 } else if (ctx->func_type == HASHX_TYPE_INTERPRETED) {
111 hashx_program_execute(&ctx->program, r);
112 } else {
113 return HASHX_FAIL_UNPREPARED;
114 }
115
116 /* Hash finalization to remove bias toward 0 caused by multiplications */
117#ifndef HASHX_BLOCK_MODE
118 r[0] += ctx->keys.v0;
119 r[1] += ctx->keys.v1;
120 r[6] += ctx->keys.v2;
121 r[7] += ctx->keys.v3;
122#else
123 const uint8_t* p = (const uint8_t*)&ctx->params;
124 r[0] ^= load64(&p[8 * 0]);
125 r[1] ^= load64(&p[8 * 1]);
126 r[2] ^= load64(&p[8 * 2]);
127 r[3] ^= load64(&p[8 * 3]);
128 r[4] ^= load64(&p[8 * 4]);
129 r[5] ^= load64(&p[8 * 5]);
130 r[6] ^= load64(&p[8 * 6]);
131 r[7] ^= load64(&p[8 * 7]);
132#endif
133 /* 1 SipRound per 4 registers is enough to pass SMHasher. */
134 SIPROUND(r[0], r[1], r[2], r[3]);
135 SIPROUND(r[4], r[5], r[6], r[7]);
136
137 /* output */
138#if HASHX_SIZE > 0
139 /* optimized output for hash sizes that are multiples of 8 */
140#if HASHX_SIZE % 8 == 0
141 uint8_t* temp_out = (uint8_t*)output;
142#if HASHX_SIZE >= 8
143 store64(temp_out + 0, r[0] ^ r[4]);
144#endif
145#if HASHX_SIZE >= 16
146 store64(temp_out + 8, r[1] ^ r[5]);
147#endif
148#if HASHX_SIZE >= 24
149 store64(temp_out + 16, r[2] ^ r[6]);
150#endif
151#if HASHX_SIZE >= 32
152 store64(temp_out + 24, r[3] ^ r[7]);
153#endif
154#else /* any output size */
155 uint8_t temp_out[32];
156#if HASHX_SIZE > 0
157 store64(temp_out + 0, r[0] ^ r[4]);
158#endif
159#if HASHX_SIZE > 8
160 store64(temp_out + 8, r[1] ^ r[5]);
161#endif
162#if HASHX_SIZE > 16
163 store64(temp_out + 16, r[2] ^ r[6]);
164#endif
165#if HASHX_SIZE > 24
166 store64(temp_out + 24, r[3] ^ r[7]);
167#endif
168 memcpy(output, temp_out, HASHX_SIZE);
169#endif
170#endif
171 return HASHX_OK;
172}