aboutsummaryrefslogblamecommitdiffstats
path: root/libhashsum_init_keccak__.c
blob: f9c8be19fdf8f3e11d14885667bc2d92f4750b9d (plain) (tree)
1
2
3
4
5
6





                                                         



















                                                                                      









                                                                       



















                                                                                  














                                                                                                   





                                                                         

                                                                                                
                              





























                                                                                                    





                                                                         
                        

                                                                                                        
            

                                                                                                                 
                              



















                                                                       
                                                                                                                           






                                                     

                                                                                   
                                                             
                                               



















                                                                                     
                             






                                 
                                                                                                                           


                    
                        




                       
/* See LICENSE file for copyright and license details. */
#include "common.h"
#ifdef LIBHASHSUM_INCLUDE_LIBKECCAK_STATE


LIBHASHSUM_1_NONNULL_
static void
stretch(struct libhashsum_hasher *this, int skip, void *buffer)
{
	if (skip) {
		libkeccak_fast_squeeze(&this->state.keccak.s, 1);
		return;
	}

	if (buffer)
		this->hash_output = NULL;
	else if (this->hash_size > sizeof(this->state.keccak.sum.buf))
		this->hash_output = this->state.keccak.sum.dyn;
	else
		this->hash_output = this->state.keccak.sum.buf;

	libkeccak_squeeze(&this->state.keccak.s, buffer ? buffer : this->hash_output);
}


LIBHASHSUM_1_NONNULL_
static size_t
process(struct libhashsum_hasher *this, const void *data, size_t bytes)
{
	bytes -= bytes % this->input_block_size;
	libkeccak_zerocopy_update(&this->state.keccak.s, data, bytes);
	return bytes;
}


LIBHASHSUM_1_NONNULL_
static void
finalise_common(struct libhashsum_hasher *this)
{
	if (this->state.keccak.squeezes > 2U) {
		size_t squeezes = this->state.keccak.squeezes - 2U;
		while (squeezes > (size_t)LONG_MAX) {
			libkeccak_fast_squeeze(&this->state.keccak.s, LONG_MAX);
			squeezes -= (size_t)LONG_MAX;
		}
		libkeccak_fast_squeeze(&this->state.keccak.s, (long int)squeezes);
	}
	if (this->state.keccak.squeezes > 1U)
		libkeccak_squeeze(&this->state.keccak.s, this->hash_output);

	libkeccak_state_wipe_message(&this->state.keccak.s);
	this->stretch = &stretch;
}


LIBHASHSUM_1_NONNULL_
static int
finalise_const(struct libhashsum_hasher *this, const void *data, size_t bytes, unsigned extra_bits)
{
	const uint8_t *m = data;
	size_t r;

	if (extra_bits > 7U) {
		errno = EINVAL;
		return -1;
	}

	r = process(this, m, bytes);
	m = &m[r];
	bytes -= r;

	if (!this->hash_output) {
		if (this->hash_size > sizeof(this->state.keccak.sum.buf))
			this->hash_output = this->state.keccak.sum.dyn;
		else
			this->hash_output = this->state.keccak.sum.buf;
	}
	libkeccak_digest(&this->state.keccak.s, m, bytes, extra_bits, this->state.keccak.suffix,
	                 this->state.keccak.squeezes > 1U ? NULL : this->hash_output);
	finalise_common(this);
	return 0;
}


LIBHASHSUM_1_NONNULL_
static int
finalise(struct libhashsum_hasher *this, void *data, size_t bytes, unsigned extra_bits, size_t size)
{
	uint8_t *m = data;
	size_t r;
	size_t need;

	if (extra_bits > 7U) {
		errno = EINVAL;
		return -1;
	}

	r = process(this, m, bytes);
	m = &m[r];
	bytes -= r;
	size -= r;

	need = strlen(this->state.keccak.suffix) + 2U + extra_bits;
	need = (need + 7U) >> 3;
	need += bytes;
	if (need & (this->input_block_size - 1U)) {
		need &= ~(this->input_block_size - 1U);
		need += this->input_block_size;
	}

	if (!this->hash_output) {
		if (this->hash_size > sizeof(this->state.keccak.sum.buf))
			this->hash_output = this->state.keccak.sum.dyn;
		else
			this->hash_output = this->state.keccak.sum.buf;
	}
	if (size < need)
		libkeccak_digest(&this->state.keccak.s, m, bytes, extra_bits, this->state.keccak.suffix,
		                 this->state.keccak.squeezes > 1U ? NULL : this->hash_output);
	else
		libkeccak_zerocopy_digest(&this->state.keccak.s, m, bytes, extra_bits, this->state.keccak.suffix,
		                          this->state.keccak.squeezes > 1U ? NULL : this->hash_output);
	finalise_common(this);
	return 0;
}


LIBHASHSUM_1_NONNULL_
static void
destroy(struct libhashsum_hasher *this)
{
	libkeccak_state_wipe_message(&this->state.keccak.s);
	libkeccak_state_fast_destroy(&this->state.keccak.s);
	memset(&this->state.keccak.s, 0, sizeof(this->state.keccak.s));
	this->state.keccak.s.M = NULL;
	if (this->hash_size > sizeof(this->state.keccak.sum.buf)) {
		free(this->state.keccak.sum.dyn);
		this->state.keccak.sum.dyn = NULL;
	}
}


int
libhashsum_init_keccak__(struct libhashsum_hasher *this, size_t hashbits, void *spec_, size_t squeezes, const char *suffix)
{
	struct libkeccak_spec *spec = spec_;

	this->hash_size = hashbits >> 3;
	this->hash_size += (size_t)!!(hashbits & 7U);
	this->hash_output = NULL;
	this->supports_non_whole_bytes = 1;
	this->standard_partial_byte_input_encoding = LIBHASHSUM_LEAST_SIGNIFICANT;
	this->standard_partial_byte_output_encoding = LIBHASHSUM_LEAST_SIGNIFICANT;
	this->hash_excess_bits = (8U - (hashbits & 7U)) & 7U;
	this->state.keccak.squeezes = squeezes;
	this->state.keccak.suffix = suffix;

	if (this->hash_size > sizeof(this->state.keccak.sum.buf)) {
		this->state.keccak.sum.dyn = malloc(this->hash_size);
		if (!this->state.keccak.sum.dyn)
			return -1;
	}

	if (libkeccak_state_initialise(&this->state.keccak.s, spec)) {
		if (this->hash_size > sizeof(this->state.keccak.sum.buf)) {
			free(this->state.keccak.sum.dyn);
			this->state.keccak.sum.dyn = NULL;
		}
		return -1;
	}

	this->input_block_size = libkeccak_zerocopy_chunksize(&this->state.keccak.s);
	this->process = &process;
	this->finalise_const = &finalise_const;
	this->finalise = &finalise;
	this->stretch = NULL;
	this->destroy = &destroy;
	return 0;
}


#else
int
libhashsum_init_keccak__(struct libhashsum_hasher *this, size_t hashbits, void *spec, size_t squeezes, const char *suffix);
{
	(void) this;
	(void) spec;
	(void) squeezes;
	(void) suffix;
	errno = ENOSYS;
	return -1;
}
#endif