📄 md6_mode.c
字号:
/* State initialization. (md6_init, which defaults most parameters.)
**
*/
int md6_init( md6_state *st,
int d
)
/* Same as md6_full_init, but with default key, L, and r */
{ return md6_full_init(st,
d,
NULL,
0,
md6_default_L,
md6_default_r(d,0)
);
}
/* Data structure notes.
*/
/*
Here are some notes on the data structures used (inside state).
* The variable B[] is a stack of length-b (b-64) word records,
each corresponding to a node in the tree. B[ell] corresponds
to a node at level ell. Specifically, it represents the record which,
when compressed, will yield the value at that level. (It only
contains the data payload, not the auxiliary information.)
Note that B[i] is used to store the *inputs* to the computation at
level i, not the output for the node at that level.
Thus, for example, the message input is stored in B[1], not B[0].
* Level 0 is not used. The message bytes are placed into B[1].
* top is the largest ell for which B[ell] has received data,
or is equal to 1 in case no data has been received yet at all.
* top is never greater than L+1. If B[L+1] is
compressed, the result is put back into B[L+1] (this is SEQ).
* bits[ell] says how many bits have been placed into
B[ell]. An invariant maintained is that of the bits in B[ell],
only the first bits[ell] may be nonzero; the following bits must be zero.
* The B nodes may have somewhat different formats, depending on the level:
-- Level 1 node contains a variable-length bit-string, and so
0 <= bits[1] <= b*w is all we can say.
-- Levels 2...top always receive data in c-word chunks (from
children), so for them bits[ell] is between 0 and b*w,
inclusive, but is also a multiple of cw. We can think of these
nodes as have (b/c) (i.e. 4) "slots" for chunks.
-- Level L+1 is special, in that the first c words of B are dedicated
to the "chaining variable" (or IV, for the first node on the level).
* When the hashing is over, B[top] will contain the
final hash value, in the first or second (if top = L+1) slot.
*/
/* Compress one block -- compress data at a node (md6_compress_block).
*/
int md6_compress_block( md6_word *C,
md6_state *st,
int ell,
int z
)
/* compress block at level ell, and put c-word result into C.
** Input:
** st current md6 computation state
** ell 0 <= ell < max_stack_height-1
** z z = 1 if this is very last compression; else 0
** Output:
** C c-word array to put result in
** Modifies:
** st->bits[ell] (zeroed)
** st->i_for_level[ell] (incremented)
** st->B[ell] (zeroed)
** st->compression_calls (incremented)
** Returns one of the following:
** MD6_SUCCESS
** MD6_NULLSTATE
** MD6_STATENOTINIT
** MD6_STACKUNDERFLOW
** MD6_STACKOVERFLOW
*/
{ int p, err;
/* check that input values are sensible */
if ( st == NULL) return MD6_NULLSTATE;
if ( st->initialized == 0 ) return MD6_STATENOTINIT;
if ( ell < 0 ) return MD6_STACKUNDERFLOW;
if ( ell >= md6_max_stack_height-1 ) return MD6_STACKOVERFLOW;
st->compression_calls++;
if (ell==1) /* leaf; hashing data; reverse bytes if nec. */
{ if (ell<(st->L + 1)) /* PAR (tree) node */
md6_reverse_little_endian(&(st->B[ell][0]),b);
else /* SEQ (sequential) node; don't reverse chaining vars */
md6_reverse_little_endian(&(st->B[ell][c]),b-c);
}
p = b*w - st->bits[ell]; /* number of pad bits */
err =
md6_standard_compress(
C, /* C */
Q, /* Q */
st->K, /* K */
ell, st->i_for_level[ell], /* -> U */
st->r, st->L, z, p, st->keylen, st->d, /* -> V */
st->B[ell] /* B */
);
if (err) return err;
st->bits[ell] = 0; /* clear bits used count this level */
st->i_for_level[ell]++;
memset(&(st->B[ell][0]),0,b*sizeof(md6_word)); /* clear B[ell] */
return MD6_SUCCESS;
}
/* Process (compress) a node and its compressible ancestors.
*/
int md6_process( md6_state *st,
int ell,
int final )
/*
** Do processing of level ell (and higher, if necessary) blocks.
**
** Input:
** st md6 state that has been accumulating message bits
** and/or intermediate results
** ell level number of block to process
** final true if this routine called from md6_final
** (no more input will come)
** false if more input will be coming
** (This is not same notion as "final bit" (i.e. z)
** indicating the last compression operation.)
** Output (by side effect on state):
** Sets st->hashval to final chaining value on final compression.
** Returns one of the following:
** MD6_SUCCESS
** MD6_NULLSTATE
** MD6_STATENOTINIT
*/
{ int err, z, next_level;
md6_word C[c];
/* check that input values are sensible */
if ( st == NULL) return MD6_NULLSTATE;
if ( st->initialized == 0 ) return MD6_STATENOTINIT;
if (!final) /* not final -- more input will be coming */
{ /* if not final and block on this level not full, nothing to do */
if ( st->bits[ell] < b*w )
return MD6_SUCCESS;
/* else fall through to compress this full block,
** since more input will be coming
*/
}
else /* final -- no more input will be coming */
{ if ( ell == st->top )
{ if (ell == (st->L + 1)) /* SEQ node */
{ if ( st->bits[ell]==c*w && st->i_for_level[ell]>0 )
return MD6_SUCCESS;
/* else (bits>cw or i==0, so fall thru to compress */
}
else /* st->top == ell <= st->L so we are at top tree node */
{ if ( ell>1 && st->bits[ell]==c*w)
return MD6_SUCCESS;
/* else (ell==1 or bits>cw, so fall thru to compress */
}
}
/* else (here ell < st->top so fall through to compress */
}
/* compress block at this level; result goes into C */
/* first set z to 1 iff this is the very last compression */
z = 0; if (final && (ell == st->top)) z = 1;
if ((err = md6_compress_block(C,st,ell,z)))
return err;
if (z==1) /* save final chaining value in st->hashval */
{ memcpy( st->hashval, C, md6_c*(w/8) );
return MD6_SUCCESS;
}
/* where should result go? To "next level" */
next_level = min(ell+1,st->L+1);
/* Start sequential mode with IV=0 at that level if necessary
** (All that is needed is to set bits[next_level] to c*w,
** since the bits themselves are already zeroed, either
** initially, or at the end of md6_compress_block.)
*/
if (next_level == st->L + 1
&& st->i_for_level[next_level]==0
&& st->bits[next_level]==0 )
st->bits[next_level] = c*w;
/* now copy C onto next level */
memcpy((char *)st->B[next_level] + st->bits[next_level]/8,
C,
c*(w/8));
st->bits[next_level] += c*w;
if (next_level > st->top) st->top = next_level;
return md6_process(st,next_level,final);
}
/* Update -- incorporate data string into hash computation.
*/
int md6_update( md6_state *st,
unsigned char *data,
uint64_t databitlen )
/* Process input byte string data, updating state to reflect result
** Input:
** st already initialized state to be updated
** data byte string of length databitlen bits
** to be processed (aka "M")
** databitlen number of bits in string data (aka "m")
** Modifies:
** st updated to reflect input of data
*/
{ unsigned int j, portion_size;
int err;
/* check that input values are sensible */
if ( st == NULL ) return MD6_NULLSTATE;
if ( st->initialized == 0 ) return MD6_STATENOTINIT;
if ( data == NULL ) return MD6_NULLDATA;
j = 0; /* j = number of bits processed so far with this update */
while (j<databitlen)
{ /* handle input string in portions (portion_size in bits)
** portion_size may be zero (level 1 data block might be full,
** having size b*w bits) */
portion_size = min(databitlen-j,
(unsigned int)(b*w-(st->bits[1])));
if ((portion_size % 8 == 0) &&
(st->bits[1] % 8 == 0) &&
(j % 8 == 0))
{ /* use mempy to handle easy, but most common, case */
memcpy((char *)st->B[1] + st->bits[1]/8,
&(data[j/8]),
portion_size/8);
}
else /* handle messy case where shifting is needed */
{ append_bits((unsigned char *)st->B[1], /* dest */
st->bits[1], /* dest current bit size */
&(data[j/8]), /* src */
portion_size); /* src size in bits */
}
j += portion_size;
st->bits[1] += portion_size;
st->bits_processed += portion_size;
/* compress level-1 block if it is now full
but we're not done yet */
if (st->bits[1] == b*w && j<databitlen)
{ if ((err=md6_process(st,
1, /* ell */
0 /* final */
)))
return err;
}
} /* end of loop body handling input portion */
return MD6_SUCCESS;
}
/* Convert hash value to hexadecimal, and store it in state.
*/
int md6_compute_hex_hashval( md6_state *st )
/*
** Convert hashval in st->hashval into hexadecimal, and
** save result in st->hexhashval
** This will be a zero-terminated string of length ceil(d/4).
** Assumes that hashval has already been "trimmed" to correct
** length.
**
** Returns one of the following:
** MD6_SUCCESS
** MD6_NULLSTATE (if input state pointer was NULL)
*/
{ int i;
static unsigned char hex_digits[] = "0123456789abcdef";
/* check that input is sensible */
if ( st == NULL ) return MD6_NULLSTATE;
for (i=0;i<((st->d+7)/8);i++)
{ st->hexhashval[2*i]
= hex_digits[ ((st->hashval[i])>>4) & 0xf ];
st->hexhashval[2*i+1]
= hex_digits[ (st->hashval[i]) & 0xf ];
}
/* insert zero string termination byte at position ceil(d/4) */
st->hexhashval[(st->d+3)/4] = 0;
return MD6_SUCCESS;
}
/* Extract last d bits of chaining variable as hash value.
*/
void trim_hashval(md6_state *st)
{ /* trim hashval to desired length d bits by taking only last d bits */
/* note that high-order bit of a byte is considered its *first* bit */
int full_or_partial_bytes = (st->d+7)/8;
int bits = st->d % 8; /* bits in partial byte */
int i;
/* move relevant bytes to the front */
for ( i=0; i<full_or_partial_bytes; i++ )
st->hashval[i] = st->hashval[c*(w/8)-full_or_partial_bytes+i];
/* zero out following bytes */
for ( i=full_or_partial_bytes; i<c*(w/8); i++ )
st->hashval[i] = 0;
/* shift result left by (8-bits) bit positions, per byte, if needed */
if (bits>0)
{ for ( i=0; i<full_or_partial_bytes; i++ )
{ st->hashval[i] = (st->hashval[i] << (8-bits));
if ( (i+1) < c*(w/8) )
st->hashval[i] |= (st->hashval[i+1] >> bits);
}
}
}
/* Final -- no more data; finish up and produce hash value.
*/
int md6_final( md6_state *st , unsigned char *hashval)
/* Do final processing to produce md6 hash value
** Input:
** st md6 state that has been accumulating message bits
** and/or intermediate results
** Output (by side effect on state):
** hashval If this is non-NULL, final hash value copied here.
** (NULL means don't copy.) In any case, the hash
** value remains in st->hashval.
** st->hashval this is a 64-byte array; the first st->d
** bits of which will be the desired hash value
** (with high-order bits of a byte used first), and
** remaining bits set to zero (same as hashval)
** st->hexhashval this is a 129-byte array which contains the
** zero-terminated hexadecimal version of the hash
** Returns one of the following:
** MD6_SUCCESS
** MD6_NULLSTATE
** MD6_STATENOTINIT
*/
{ int ell, err;
/* check that input values are sensible */
if ( st == NULL) return MD6_NULLSTATE;
if ( st->initialized == 0 ) return MD6_STATENOTINIT;
/* md6_final was previously called */
if ( st->finalized == 1 ) return MD6_SUCCESS;
/* force any processing that needs doing */
if (st->top == 1) ell = 1;
else for (ell=1; ell<=st->top; ell++)
if (st->bits[ell]>0) break;
/* process starting at level ell, up to root */
err = md6_process(st,ell,1);
if (err) return err;
/* md6_process has saved final chaining value in st->hashval */
md6_reverse_little_endian( (md6_word*)st->hashval, c );
if (hashval != NULL) memcpy( hashval, st->hashval, (st->d+7)/8 );
trim_hashval( st );
md6_compute_hex_hashval( st );
st->finalized = 1;
return MD6_SUCCESS;
}
/* Routines for hashing message given "all at once".
*/
int md6_full_hash( int d, /* hash bit length */
unsigned char *data,/* complete data to hash */
uint64_t databitlen, /* its length in bits */
unsigned char *key, /* OK to give NULL */
int keylen, /* (in bytes) OK to give 0 */
int L, /* mode; OK to give md6_default_L */
int r, /* number of rounds */
unsigned char *hashval /* output */
)
{ md6_state st;
int err;
err = md6_full_init(&st,d,key,keylen,L,r);
if (err) return err;
err = md6_update(&st,data,databitlen);
if (err) return err;
md6_final(&st,hashval);
if (err) return err;
return MD6_SUCCESS;
}
int md6_hash( int d, /* hash bit length */
unsigned char *data, /* complete data to hash */
uint64_t databitlen, /* its length in bits */
unsigned char *hashval /* output */
)
{ int err;
err = md6_full_hash(d,data,databitlen,
NULL,0,md6_default_L,md6_default_r(d,0),hashval);
if (err) return err;
return MD6_SUCCESS;
}
/*
** end of md6_mode.c
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -