Files
calc/hash.c
Landon Curt Noll db77e29a23 convert ASCII TABs to ASCII SPACEs
Converted all ASCII tabs to ASCII spaces using a 8 character
tab stop, for all files, except for all Makefiles (plus rpm.mk).
The `git diff -w` reports no changes.
2024-07-11 22:03:52 -07:00

1059 lines
32 KiB
C

/*
* hash - one-way hash routines
*
* Copyright (C) 1999-2007,2021-2023 Landon Curt Noll
*
* Calc is open software; you can redistribute it and/or modify it under
* the terms of the version 2.1 of the GNU Lesser General Public License
* as published by the Free Software Foundation.
*
* Calc is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
* Public License for more details.
*
* A copy of version 2.1 of the GNU Lesser General Public License is
* distributed with calc under the filename COPYING-LGPL. You should have
* received a copy with calc; if not, write to Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Under source code control: 1995/11/23 05:13:11
* File existed as early as: 1995
*
* chongo <was here> /\oo/\ http://www.isthe.com/chongo/
* Share and enjoy! :-) http://www.isthe.com/chongo/tech/comp/calc/
*/
#include <stdio.h>
#include "have_string.h"
#ifdef HAVE_STRING_H
# include <string.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include "calc.h"
#include "alloc.h"
#include "value.h"
#include "zrand.h"
#include "zrandom.h"
#include "hash.h"
#include "errtbl.h"
#include "banned.h" /* include after system header <> includes */
/*
* external hash_setup functions
*/
E_FUNC void shs_init_state(HASH*);
E_FUNC void sha1_init_state(HASH*);
E_FUNC void MD5_init_state(HASH*);
/*
* hash_long can deal with bool's, int's, FLAGS's and LEN's
*/
#define hash_bool(type, val, state) (hash_long((type), (long)(val), (state)))
#define hash_int(type, val, state) (hash_long((type), (long)(val), (state)))
#define hash_flag(type, val, state) (hash_long((type), (long)(val), (state)))
#define hash_len(type, val, state) (hash_long((type), (long)(val), (state)))
/*
* hash_setup - setup the hash state for a given hash
*/
STATIC struct hash_setup {
int type; /* hash type (see XYZ_HASH_TYPE below) */
void (*init_state)(HASH*); /* initialize a hash state */
} htbl[] = {
{ SHA1_HASH_TYPE, sha1_init_state }, /* SHA-1 / SHA-1 */
{ -1, NULL } /* must be last */
};
/*
* hash_init - initialize a hash state
*
* given:
* type - hash type (see hash.h)
* state - the state to initialize, or NULL to malloc it
*
* returns:
* initialized state
*/
HASH *
hash_init(int type, HASH *state)
{
int i;
/*
* malloc if needed
*/
if (state == NULL) {
state = (HASH *)malloc(sizeof(HASH));
if (state == NULL) {
math_error("hash_init: cannot malloc HASH");
not_reached();
}
}
/*
* clear hash value
*/
memset((void*)state, 0, sizeof(HASH));
state->bytes = true;
/*
* search for the hash_setup function
*/
for (i=0; htbl[i].init_state != NULL; ++i) {
/* if we found the state that we were looking for */
if (type == htbl[i].type) {
/* initialize state and return */
(htbl[i].init_state)(state);
/* firewall - MAX_CHUNKSIZE must be >= chunksize */
if (state->chunksize > MAX_CHUNKSIZE) {
math_error(
"internal error: MAX_CHUNKSIZE is too small");
not_reached();
}
return state;
}
}
/*
* no such hash state
*/
math_error("internal error: hash type not found in htbl[]");
return NULL;
}
/*
* hash_free - free the hash state
*/
void
hash_free(HASH *state)
{
/*
* do nothing if state is NULL
*/
if (state == NULL) {
return;
}
/*
* free main state and return
*/
free(state);
return;
}
/*
* hash_copy - copy a hash state
*
* given:
* state - the state to copy
*
* returns:
* pointer to copy of state
*/
HASH *
hash_copy(HASH *state)
{
HASH *hnew; /* copy of state */
/*
* malloc new state
*/
hnew = (HASH *)malloc(sizeof(HASH));
if (hnew == NULL) {
math_error("hash_init: cannot malloc HASH");
not_reached();
}
/*
* duplicate state
*/
memcpy((void *)hnew, (void *)state, sizeof(HASH));
return hnew;
}
/*
* hash_cmp - compare hash values
*
* given:
* a first hash state
* b second hash state
*
* returns:
* true => hash states are different
* false => hash states are the same
*/
int
hash_cmp(HASH *a, HASH *b)
{
/*
* firewall and quick check
*/
if (a == b) {
/* pointers to the same object */
return false;
}
if (a == NULL || b == NULL) {
/* one pointer is NULL, so they differ */
return true;
}
if (a->cmp == NULL || b->cmp == NULL) {
/* one cmp function is NULL, so they differ */
return true;
}
/*
* compare hash types
*/
if (a->hashtype != b->hashtype) {
/* different hash types are different */
return true;
}
/*
* perform the hash specific comparison
*/
return ((a->cmp)(a,b));
}
/*
* hash_print - print the name and value of a hash
*
* given:
* state the hash state to print name and value of
*/
void
hash_print(HASH *state)
{
/* print the hash */
(state->print)(state);
return;
}
/*
* hash_final - finalize the state of a hash and return a ZVALUE
*
* given:
* state the hash state to finalize
*
* returns:
* hash state as a ZVALUE
*/
ZVALUE
hash_final(HASH *state)
{
/* return the finalized the hash value */
return (state->final)(state);
}
/*
* hash_long - note a long value
*
* given:
* type - hash type (see hash.h)
* longval - a long value
* state - the state to hash
*
* returns:
* the new state
*
* This function will hash a long value as if it were a 64 bit value.
* The input is a long. If a long is smaller than 64 bits, we will
* hash a final 32 bits of zeros.
*
* This function is OK to hash bool's, unsigned long's, unsigned int's
* signed int's as well as FLAG's and LEN's.
*/
HASH *
hash_long(int type, long longval, HASH *state)
{
long lval[64/LONG_BITS]; /* 64 bits of longs */
/*
* initialize if state is NULL
*/
if (state == NULL) {
state = hash_init(type, NULL);
}
/*
* setup for the hash_long
*/
(state->chkpt)(state);
state->bytes = false; /* data to be read as words */
/*
* catch the zero numeric value special case
*/
if (longval == 0) {
/* note a zero numeric value and return */
(state->note)(HASH_ZERO(state->base), state);
return state;
}
/*
* prep for a long value hash
*/
(state->note)(state->base, state);
/*
* hash as if we have a 64 bit value
*/
memset((char *)lval, 0, sizeof(lval));
lval[0] = longval;
(state->update)(state, (USB8 *)lval, sizeof(lval));
/*
* all done
*/
return state;
}
/*
* hash_zvalue - hash a ZVALUE
*
* given:
* type - hash type (see hash.h)
* zval - the ZVALUE
* state - the state to hash or NULL
*
* returns:
* the new state
*/
HASH *
hash_zvalue(int type, ZVALUE zval, HASH *state)
{
#if CALC_BYTE_ORDER == BIG_ENDIAN && BASEB == 16
int full_lim; /* HALFs in whole chunks in zval */
int chunkhalf; /* size of half buffer in HALFs */
int i;
int j;
#endif
#if BASEB == 16
HALF half[MAX_CHUNKSIZE]; /* For endian reversal */
#endif
/*
* initialize if state is NULL
*/
if (state == NULL) {
state = hash_init(type, NULL);
}
/*
* setup for the ZVALUE hash
*/
(state->chkpt)(state);
state->bytes = false; /* data to be read as words */
/*
* catch the zero numeric value special case
*/
if (ziszero(zval)) {
/* note a zero numeric value and return */
(state->note)(HASH_ZERO(state->base), state);
return state;
}
/*
* prep for a ZVALUE hash
*/
(state->note)(HASH_ZVALUE(state->base), state);
/* note if we have a negative value */
if (zisneg(zval)) {
(state->note)(HASH_NEG(state->base), state);
}
#if CALC_BYTE_ORDER == BIG_ENDIAN && BASEB == 16
/*
* hash full chunks
*
* We need to convert the array of HALFs into canonical architectural
* independent form -- 32 bit arrays. Because we have 16 bit values
* in Big Endian form, we need to swap 16 bit values so that they
* appear as 32 bit Big Endian values.
*/
chunkhalf = state->chunksize/sizeof(HALF);
full_lim = (zval.len / chunkhalf) * chunkhalf;
for (i=0; i < full_lim; i += chunkhalf) {
/* HALF swap copy a chunk into a data buffer */
for (j=0; j < chunkhalf; j += 2) {
half[j] = zval.v[i+j+1];
half[j+1] = zval.v[i+j];
}
(state->update)(state, (USB8*) half, state->chunksize);
}
/*
* hash the final partial chunk (if any)
*
* We need to convert the array of HALFs into canonical architectural
* independent form -- 32 bit arrays. Because we have 16 bit values
* in Big Endian form, we need to swap 16 bit values so that they
* appear as 32 bit Big Endian values.
*/
if (zval.len > full_lim) {
for (j=0; j < zval.len-full_lim-1; j += 2) {
half[j] = zval.v[full_lim+j+1];
half[j+1] = zval.v[full_lim+j];
}
if (j < zval.len-full_lim) {
half[j] = (HALF)0;
half[j+1] = zval.v[zval.len-1];
--full_lim;
}
(state->update)(state, (USB8 *) half,
(zval.len-full_lim)*sizeof(HALF));
}
#else
/*
* hash the array of HALFs
*
* The array of HALFs is equivalent to the canonical architectural
* independent form. We either have 32 bit HALFs (in which case
* we do not case the byte order) or we have 16 bit HALFs in Little
* Endian order (which happens to be laid out in the same order as
* 32 bit values).
*/
(state->update)(state, (USB8 *)zval.v, zval.len*sizeof(HALF));
#if BASEB == 16
if (zval.len & 1) { /* padding to complete word */
half[0] = 0;
(state->update)(state, (USB8 *) half, 2);
}
#endif
#endif
/*
* all done
*/
return state;
}
/*
* hash_number - hash a NUMBER
*
* given:
* type - hash type (see hash.h)
* n - the NUMBER
* state - the state to hash or NULL
*
* returns:
* the new state
*/
HASH *
hash_number(int type, void *n, HASH *state)
{
NUMBER *number = (NUMBER *)n; /* n as a NUMBER pointer */
bool sign; /* sign of the denominator */
/*
* initialize if state is NULL
*/
if (state == NULL) {
state = hash_init(type, NULL);
}
/*
* setup for the NUMBER hash
*/
(state->chkpt)(state);
state->bytes = false;
/*
* process the numerator
*/
state = hash_zvalue(type, number->num, state);
/*
* if the NUMBER is not an integer, process the denominator
*/
if (qisfrac(number)) {
/* note the division */
(state->note)(HASH_DIV(state->base), state);
/* hash denominator as positive -- just in case */
sign = number->den.sign;
number->den.sign = 0;
/* hash the denominator */
state = hash_zvalue(type, number->den, state);
/* restore the sign */
number->den.sign = sign;
}
/*
* all done
*/
return state;
}
/*
* hash_complex - hash a COMPLEX
*
* given:
* type - hash type (see hash.h)
* c - the COMPLEX
* state - the state to hash or NULL
*
* returns:
* the new state
*/
HASH *
hash_complex(int type, void *c, HASH *state)
{
COMPLEX *complex = (COMPLEX *)c; /* c as a COMPLEX pointer */
/*
* initialize if state is NULL
*/
if (state == NULL) {
state = hash_init(type, NULL);
}
/*
* setup for the COMPLEX hash
*/
(state->chkpt)(state);
state->bytes = false;
/*
* catch the zero special case
*/
if (ciszero(complex)) {
/* note a zero numeric value and return */
(state->note)(HASH_ZERO(state->base), state);
return state;
}
/*
* process the real value if not pure imaginary
*
* We will ignore the real part if the value is of the form 0+xi.
*/
if (!qiszero(complex->real)) {
state = hash_number(type, complex->real, state);
}
/*
* if the NUMBER is not real, process the imaginary value
*
* We will ignore the imaginary part of the value is of the form x+0i.
*/
if (!cisreal(complex)) {
/* note the sqrt(-1) */
(state->note)(HASH_COMPLEX(state->base), state);
/* hash the imaginary value */
state = hash_number(type, complex->imag, state);
}
/*
* all done
*/
return state;
}
/*
* hash_str - hash a null-terminated string
*
* given:
* type - hash type (see hash.h)
* str - the string
* state - the state to hash or NULL
*
* returns:
* the new state
*/
HASH *
hash_str(int type, char *str, HASH *state)
{
size_t len; /* string length */
/*
* initialize if state is NULL
*/
if (state == NULL) {
state = hash_init(type, NULL);
}
/*
* setup for the string hash
*/
if (!state->bytes) {
(state->chkpt)(state);
state->bytes = true;
}
len = strlen(str);
/*
* hash the string
*/
(state->update)(state, (USB8*)str, len);
/*
* all done
*/
return state;
}
/*
* hash_STR - hash a STRING
*
* given:
* type - hash type (see hash.h)
* str - the STRING
* state - the state to hash or NULL
*
* returns:
* the new state
*/
HASH *
hash_STR(int type, STRING *str, HASH *state)
{
/*
* initialize if state is NULL
*/
if (state == NULL) {
state = hash_init(type, NULL);
}
/*
* setup for the string hash
*/
if (!state->bytes) {
(state->chkpt)(state);
state->bytes = true;
}
/*
* hash the string
*/
(state->update)(state, (USB8*) str->s_str, (USB32) str->s_len);
/*
* all done
*/
return state;
}
/*
* hash_usb8 - hash an array of USB8s
*
* given:
* type - hash type (see hash.h)
* byte - pointer to an array of USB8s
* len - number of USB8s to hash
* state - the state to hash or NULL
*
* returns:
* the new state
*/
HASH *
hash_usb8(int type, USB8 *byte, int len, HASH *state)
{
/*
* initialize if state is NULL
*/
if (state == NULL) {
state = hash_init(type, NULL);
}
/*
* setup for the string hash
*/
if (!state->bytes) {
(state->chkpt)(state);
state->bytes = true;
}
/*
* hash the array of octets
*/
(state->update)(state, byte, (USB32)len);
/*
* all done
*/
return state;
}
/*
* hash_value - hash a value
*
* given:
* type - hash type (see hash.h)
* v - the value
* state - the state to hash or NULL
*
* returns:
* the new state
*/
HASH *
hash_value(int type, void *v, HASH *state)
{
LISTELEM *ep; /* list element pointer */
ASSOCELEM **assochead; /* association chain head */
ASSOCELEM *aep; /* current association value */
ASSOCELEM *nextaep; /* next association value */
VALUE *value = (VALUE *)v; /* v cast to a VALUE */
VALUE *vp; /* pointer to next OBJ table value */
ZVALUE fileval; /* size, position, dev, inode of a file */
int i;
/*
* initialize if state is NULL
*/
if (state == NULL) {
state = hash_init(type, NULL);
}
/*
* process the value type
*/
switch (value->v_type) {
case V_NULL:
(state->chkpt)(state);
state->bytes = true;
break;
case V_INT:
/* setup for the this value type */
(state->chkpt)(state);
(state->type)(value->v_type, state);
/* hash as if we have a 64 bit value */
state = hash_int(type, value->v_int, state);
break;
case V_NUM:
/* hash this type */
state = hash_number(type, value->v_num, state);
break;
case V_COM:
/* setup for the this value type */
(state->chkpt)(state);
(state->type)(value->v_type, state);
/* hash this type */
state = hash_complex(type, value->v_com, state);
break;
case V_ADDR:
/* there is nothing to setup, simply hash what we point at */
state = hash_value(type, value->v_addr, state);
break;
case V_STR:
/* strings have no setup */
/* hash this type */
state = hash_STR(type, value->v_str, state);
break;
case V_MAT:
/* setup for the this value type */
(state->chkpt)(state);
(state->type)(value->v_type, state);
state->bytes = true;
/* hash all the elements of the matrix */
for (i=0; i < value->v_mat->m_size; ++i) {
/* hash the next matrix value */
state = hash_value(type,
value->v_mat->m_table+i, state);
state->bytes = false; /* as if reading words */
}
break;
case V_LIST:
/* setup for the this value type */
(state->chkpt)(state);
(state->type)(value->v_type, state);
/* hash all the elements of the list */
for (i=0, ep = value->v_list->l_first;
ep != NULL && i < value->v_list->l_count;
++i, ep = ep->e_next) {
/* hash the next list value */
state = hash_value(type, &ep->e_value, state);
state->bytes = false; /* as if reading words */
}
break;
case V_ASSOC:
/* setup for the this value type */
(state->chkpt)(state);
(state->type)(value->v_type, state);
state->bytes = true;
/* hash the association */
assochead = value->v_assoc->a_table;
for (i = 0; i < value->v_assoc->a_size; i++) {
nextaep = *assochead;
while (nextaep) {
aep = nextaep;
nextaep = aep->e_next;
/* hash the next association value */
state = hash_value(type, &aep->e_value, state);
state->bytes = false; /* as if reading words */
}
assochead++;
}
break;
case V_OBJ:
/* setup for the this value type */
(state->chkpt)(state);
(state->type)(value->v_type, state);
state->bytes = true; /* reading bytes */
/* hash the object name and then the element values */
state = hash_str(type, objtypename(
value->v_obj->o_actions->oa_index), state);
(state->chkpt)(state);
for (i=value->v_obj->o_actions->oa_count,
vp=value->v_obj->o_table;
i-- > 0;
vp++) {
/* hash the next object value */
state = hash_value(type, vp, state);
state->bytes = false; /* as if reading words */
}
break;
case V_FILE:
/* setup for the this value type */
(state->chkpt)(state);
(state->type)(value->v_type, state);
/* hash file length if possible */
if (getsize(value->v_file, &fileval) == 0) {
state = hash_zvalue(type, fileval, state);
zfree(fileval);
} else {
/* hash -1 for invalid length */
state = hash_long(type, (long)-1, state);
}
/* hash the file position if possible */
if (getloc(value->v_file, &fileval) == 0) {
state = hash_zvalue(type, fileval, state);
zfree(fileval);
} else {
/* hash -1 for invalid location */
state = hash_long(type, (long)-1, state);
}
/* hash the file device if possible */
if (get_device(value->v_file, &fileval) == 0) {
state = hash_zvalue(type, fileval, state);
zfree(fileval);
} else {
/* hash -1 for invalid device */
state = hash_long(type, (long)-1, state);
}
/* hash the file inode if possible */
if (get_inode(value->v_file, &fileval) == 0) {
state = hash_zvalue(type, fileval, state);
zfree(fileval);
} else {
/* hash -1 for invalid inode */
state = hash_long(type, (long)-1, state);
}
break;
case V_RAND:
/* setup for the this value type */
(state->chkpt)(state);
(state->type)(value->v_type, state);
/* hash the RAND state */
state = hash_int(type, value->v_rand->seeded, state);
state = hash_int(type, value->v_rand->bits, state);
(state->update)(state,
(USB8 *)value->v_rand->buffer, SLEN*FULL_BITS/8);
state = hash_int(type, value->v_rand->j, state);
state = hash_int(type, value->v_rand->k, state);
state = hash_int(type, value->v_rand->need_to_skip, state);
(state->update)(state,
(USB8 *)value->v_rand->slot, SCNT*FULL_BITS/8);
(state->update)(state,
(USB8*)value->v_rand->shuf, SHUFLEN*FULL_BITS/8);
state->bytes = false; /* as if reading words */
break;
case V_RANDOM:
/* setup for the this value type */
(state->chkpt)(state);
(state->type)(value->v_type, state);
/* hash the RANDOM state */
state = hash_int(type, value->v_random->seeded, state);
state = hash_int(type, value->v_random->bits, state);
(state->update)(state,
(USB8 *)&(value->v_random->buffer), BASEB/8);
state = hash_zvalue(type, value->v_random->r, state);
state = hash_zvalue(type, value->v_random->n, state);
state->bytes = false; /* as if reading words */
break;
case V_CONFIG:
/* setup for the this value type */
(state->chkpt)(state);
(state->type)(value->v_type, state);
/* hash the CONFIG state */
state = hash_int(type, value->v_config->outmode, state);
state = hash_int(type, value->v_config->outmode2, state);
state = hash_long(type,(long)value->v_config->outdigits, state);
state = hash_number(type, value->v_config->epsilon, state);
state = hash_long(type,
(long)value->v_config->epsilonprec, state);
state = hash_flag(type, value->v_config->traceflags, state);
state = hash_long(type, (long)value->v_config->maxprint, state);
state = hash_len(type, value->v_config->mul2, state);
state = hash_len(type, value->v_config->sq2, state);
state = hash_len(type, value->v_config->pow2, state);
state = hash_len(type, value->v_config->redc2, state);
state = hash_bool(type, value->v_config->tilde_ok, state);
state = hash_bool(type, value->v_config->tilde_space, state);
state = hash_bool(type, value->v_config->tab_ok, state);
state = hash_long(type, (long)value->v_config->quomod, state);
state = hash_long(type, (long)value->v_config->quo, state);
state = hash_long(type, (long)value->v_config->mod, state);
state = hash_long(type, (long)value->v_config->sqrt, state);
state = hash_long(type, (long)value->v_config->appr, state);
state = hash_long(type, (long)value->v_config->cfappr, state);
state = hash_long(type, (long)value->v_config->cfsim, state);
state = hash_long(type, (long)value->v_config->outround, state);
state = hash_long(type, (long)value->v_config->round, state);
state = hash_long(type, (long)value->v_config->triground, state);
state = hash_bool(type, value->v_config->leadzero, state);
state = hash_bool(type, value->v_config->fullzero, state);
state = hash_long(type,
(long)value->v_config->maxscancount, state);
state = hash_str(type, value->v_config->prompt1, state);
state->bytes = false; /* as if just read words */
state = hash_str(type, value->v_config->prompt2, state);
state->bytes = false; /* as if just read words */
state = hash_int(type, value->v_config->blkmaxprint, state);
state = hash_bool(type, value->v_config->blkverbose, state);
state = hash_int(type, value->v_config->blkbase, state);
state = hash_int(type, value->v_config->blkfmt, state);
state = hash_long(type,
(long)value->v_config->resource_debug, state);
state = hash_long(type,
(long)value->v_config->calc_debug, state);
state = hash_long(type,
(long)value->v_config->user_debug, state);
state = hash_bool(type, value->v_config->verbose_quit, state);
state = hash_int(type, value->v_config->ctrl_d, state);
state = hash_str(type, value->v_config->program, state);
state = hash_str(type, value->v_config->base_name, state);
state = hash_bool(type, value->v_config->windows, state);
state = hash_bool(type, value->v_config->cygwin, state);
state = hash_bool(type, value->v_config->compile_custom, state);
if (value->v_config->allow_custom != NULL &&
*(value->v_config->allow_custom)) {
state = hash_bool(type, true, state);
} else {
state = hash_bool(type, false, state);
}
state = hash_str(type, value->v_config->version, state);
state = hash_int(type, value->v_config->baseb, state);
state = hash_bool(type, value->v_config->redecl_warn, state);
state = hash_bool(type, value->v_config->dupvar_warn, state);
state = hash_bool(type, value->v_config->fraction_space, state);
break;
case V_HASH:
/* setup for the this value type */
(state->chkpt)(state);
(state->type)(value->v_type, state);
/* hash the HASH state */
state = hash_int(type, value->v_hash->type, state);
state = hash_bool(type, value->v_hash->bytes,state);
state = hash_int(type, value->v_hash->base, state);
state = hash_int(type, value->v_hash->chunksize, state);
state = hash_int(type, value->v_hash->unionsize, state);
(state->update)(state,
value->v_hash->h_union.data, state->unionsize);
state->bytes = false; /* as if reading words */
break;
case V_BLOCK:
/* there is no setup for a BLOCK */
/* hash the octets in the BLOCK */
if (value->v_block->datalen > 0) {
state = hash_usb8(type, value->v_block->data,
value->v_block->datalen, state);
}
break;
case V_OCTET:
/* there is no setup for an OCTET */
/* hash the OCTET */
state = hash_usb8(type, value->v_octet, 1, state);
break;
case V_NBLOCK:
/* there is no setup for a NBLOCK */
/* hash the octets in the NBLOCK */
if (value->v_nblock->blk->datalen > 0) {
state = hash_usb8(type, value->v_nblock->blk->data,
value->v_nblock->blk->datalen,
state);
}
break;
default:
math_error("hashing an unknown value");
not_reached();
}
return state;
}