#include <string.h>
#include "hss.h"
#include "common_defs.h"
#include "hss_verify_inc.h"
#include "lm_verify.h"
#include "lm_common.h"
#include "lm_ots.h"
#include "lm_ots_verify.h"
#include "hash.h"
#include "endian.h"
#include "hss_internal.h"
#include "hss_sign_inc.h"
#include "hss_derive.h"
#include <oqs/oqsconfig.h>
#ifdef OQS_ALLOW_LMS_KEY_AND_SIG_GEN
bool hss_sign_init(
struct hss_sign_inc *ctx,
struct hss_working_key *w,
bool (*update_private_key)(unsigned char *private_key,
size_t len_private_key, void *context),
void *context,
unsigned char *signature, size_t signature_len,
struct hss_extra_info *info) {
struct hss_extra_info temp_info = { 0 };;
if (!info) info = &temp_info;
if (!ctx) {
info->error_code = hss_error_got_null;
return false;
}
ctx->status = hss_error_ctx_uninitialized;
if (!w) {
info->error_code = hss_error_got_null;
return false;
}
if (w->status != hss_error_none) {
info->error_code = w->status;
return false;
}
struct merkle_level *bottom = w->tree[ w->levels - 1 ];
unsigned char I[I_LEN];
memcpy( I, bottom->I, I_LEN );
merkle_index_t q = bottom->current_index;
ctx->q = q;
int h = bottom->h;
ctx->h = h;
struct seed_derive derive;
if (!hss_seed_derive_init( &derive, bottom->lm_type, bottom->lm_ots_type,
bottom->I, bottom->seed )) return false;
hss_seed_derive_set_q(&derive, q);
lm_ots_generate_randomizer( ctx->c, bottom->hash_size, &derive );
hss_seed_derive_done(&derive);
bool success = hss_generate_signature( w,
update_private_key, context,
NULL, 0,
signature, signature_len, info );
if (!success) {
ctx->status = info->error_code;
hss_zeroize( &ctx->c, sizeof ctx->c );
return false;
}
hss_init_hash_context( h, &ctx->hash_ctx );
{
unsigned char prefix[ MESG_PREFIX_MAXLEN ];
memcpy( prefix + MESG_I, I, I_LEN );
unsigned q_bin[4]; put_bigendian( q_bin, q, 4 );
memcpy( prefix + MESG_Q, q_bin, 4 );
SET_D( prefix + MESG_D, D_MESG );
int n = bottom->hash_size;
memcpy( prefix + MESG_C, ctx->c, n );
hss_update_hash_context(h, &ctx->hash_ctx, prefix, MESG_PREFIX_LEN(n) );
}
ctx->status = hss_error_none;
return true;
}
bool hss_sign_update(
struct hss_sign_inc *ctx,
const void *message_segment,
size_t len_message_segment) {
if (!ctx || ctx->status != hss_error_none) return false;
hss_update_hash_context(ctx->h, &ctx->hash_ctx,
message_segment, len_message_segment );
return true;
}
bool hss_sign_finalize(
struct hss_sign_inc *ctx,
const struct hss_working_key *working_key,
unsigned char *signature,
struct hss_extra_info *info) {
struct hss_extra_info temp_info = { 0 };
if (!info) info = &temp_info;
if (!ctx) {
info->error_code = hss_error_got_null;
return false;
}
if (ctx->status != hss_error_none) {
info->error_code = ctx->status;
return false;
}
ctx->status = hss_error_ctx_already_used;
int L = working_key->levels;
const unsigned char *I = working_key->tree[0]->I;
const unsigned char *seed = working_key->tree[0]->seed;
unsigned char I_buff[2][I_LEN];
unsigned char seed_buff[2][SEED_LEN];
signature += 4;
int i;
for (i=0; i<L-1; i++) {
merkle_index_t q = (merkle_index_t)get_bigendian( signature, 4 );
if (q > working_key->tree[i]->max_index) {
hss_zeroize( seed_buff, sizeof seed_buff );
return 0;
}
if (!hss_generate_child_seed_I_value( seed_buff[i&1], I_buff[i&1],
seed, I, q,
working_key->tree[i]->lm_type,
working_key->tree[i]->lm_ots_type )) {
hss_zeroize( seed_buff, sizeof seed_buff );
info->error_code = hss_error_internal;
return false;
}
seed = seed_buff[i&1];
I = I_buff[i&1];
signature += lm_get_signature_len( working_key->tree[i]->lm_type,
working_key->tree[i]->lm_ots_type);
signature += lm_get_public_key_len(working_key->tree[i+1]->lm_type);
}
put_bigendian( signature, ctx->q, 4 );
signature += 4;
memcpy( signature+4, ctx->c, 32 );
unsigned char hash[ MAX_HASH ];
hss_finalize_hash_context( ctx->h, &ctx->hash_ctx, hash );
param_set_t lm_type = working_key->tree[i]->lm_type;
param_set_t ots_type = working_key->tree[i]->lm_ots_type;
struct seed_derive derive;
bool success = hss_seed_derive_init( &derive, lm_type, ots_type,
I, seed );
if (success) {
hss_seed_derive_set_q( &derive, ctx->q );
success = lm_ots_generate_signature(
ots_type, I, ctx->q, &derive, hash, 0, true,
signature, lm_ots_get_signature_len( ots_type ));
hss_seed_derive_done( &derive );
}
if (!success) {
info->error_code = hss_error_internal;
}
hss_zeroize( seed_buff, sizeof seed_buff );
return success;
}
#endif