/*
 * crypto - Tcl bindings for parts of the `nettle' crypto library
 * Copyright 2006-2012 Ian Jackson
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this library; if not, see <http://www.gnu.org/licenses/>.
 */


#include "chiark_tcl_crypto.h"

typedef struct {
  int ix;
  const HashAlgInfo *alg;
  Byte d[1];
} HashState;

int cht_do_hbcrypto_hash(ClientData cd, Tcl_Interp *ip, const HashAlgInfo *alg,
		   HBytes_Value message, HBytes_Value *result) {
  Byte *dest;

  dest= cht_hb_arrayspace(result,alg->hashsize);
  alg->oneshot(dest, cht_hb_data(&message), cht_hb_len(&message));
  return TCL_OK;
}

int cht_do_hbcrypto_hash_init(ClientData cd, Tcl_Interp *ip,
			      const HashAlgInfo *alg, void **state_r) {
  HashState *state= TALLOC(sizeof(*state) + alg->statesize - 1);
  state->ix= -1;
  state->alg= alg;
  alg->init(state->d);
  *state_r= state;
  return TCL_OK;
}

int cht_do_hbcrypto_hash_update(ClientData cd, Tcl_Interp *ip,
				void *state_v, HBytes_Value data) {
  HashState *state= state_v;
  state->alg->update(&state->d, cht_hb_data(&data), cht_hb_len(&data));
  return TCL_OK;
}

int cht_do_hbcrypto_hash_final(ClientData cd, Tcl_Interp *ip,
			       void *state_v, HBytes_Value *result) {
  HashState *state= state_v;
  Byte *digest;

  digest= cht_hb_arrayspace(result,state->alg->hashsize);
  state->alg->final(&state->d, digest);
  return cht_do_hbcrypto_hash_discard(cd,ip,state_v);
}

int cht_do_hbcrypto_hash_discard(ClientData cd, Tcl_Interp *ip,
				 void *state_v) {
  cht_tabledataid_disposing(ip,state_v,&cht_hash_states);
  free(state_v);
  return TCL_OK;
}

int cht_do_hbcrypto_hash_clonestate(ClientData cd, Tcl_Interp *ip,
				    void *old_v, void **new_r) {
  HashState *old= old_v;
  int len= sizeof(*old) + old->alg->statesize - 1;
  void *new_v= TALLOC(len);
  memcpy(new_v, old, len);
  ((HashState*)new_v)->ix= -1;
  *new_r= new_v;
  return TCL_OK;
}


static void destroy_idtabcb(Tcl_Interp *ip, void *state_v) {
  free(state_v);
}

const IdDataSpec cht_hash_states= {
  "hashstate", "hashstate-table", destroy_idtabcb
};
