130 lines
2.9 KiB
C
130 lines
2.9 KiB
C
#include "ruby.h"
|
|
#ifdef HAVE_RUBY_DIGEST_H
|
|
#include "ruby/digest.h"
|
|
#else
|
|
#include "digest.h"
|
|
#endif
|
|
#include "KeccakNISTInterface.h"
|
|
|
|
#define MAX_DIGEST_SIZE 64
|
|
#define DEFAULT_DIGEST_LEN 512
|
|
|
|
static void sha3_init_func(hashState *ctx);
|
|
static void sha3_update_func(hashState *ctx, unsigned char *str, size_t len);
|
|
|
|
static rb_digest_metadata_t sha3 = {
|
|
RUBY_DIGEST_API_VERSION,
|
|
DEFAULT_DIGEST_LEN,
|
|
KeccakPermutationSize - (2 * DEFAULT_DIGEST_LEN),
|
|
sizeof(hashState),
|
|
(rb_digest_hash_init_func_t)sha3_init_func,
|
|
(rb_digest_hash_update_func_t)sha3_update_func,
|
|
NULL,
|
|
};
|
|
|
|
static void
|
|
sha3_init(hashState *ctx, size_t bitlen) {
|
|
switch (Init(ctx, bitlen)) {
|
|
case SUCCESS:
|
|
return;
|
|
case FAIL:
|
|
rb_raise(rb_eRuntimeError, "Unknown error");
|
|
case BAD_HASHLEN:
|
|
rb_raise(rb_eArgError, "Bad hash length (must be 0, 224, 256, 384 or 512)");
|
|
default:
|
|
rb_raise(rb_eRuntimeError, "Unknown error code");
|
|
}
|
|
}
|
|
|
|
static void
|
|
sha3_init_func(hashState *ctx) {
|
|
Init(ctx, ctx->capacity / 2);
|
|
}
|
|
|
|
static void
|
|
sha3_update_func(hashState *ctx, unsigned char *str, size_t len) {
|
|
Update(ctx, str, len * 8);
|
|
}
|
|
|
|
static VALUE
|
|
rb_sha3_alloc(VALUE klass) {
|
|
hashState *ctx;
|
|
|
|
ctx = (hashState *) xmalloc(sizeof(hashState));
|
|
sha3_init(ctx, DEFAULT_DIGEST_LEN);
|
|
return Data_Wrap_Struct(klass, 0, xfree, ctx);
|
|
}
|
|
|
|
static VALUE
|
|
rb_sha3_initialize(int argc, VALUE *argv, VALUE self) {
|
|
hashState *ctx;
|
|
VALUE hashlen;
|
|
int i_hashlen;
|
|
|
|
if (rb_scan_args(argc, argv, "01", &hashlen) == 0) {
|
|
i_hashlen = DEFAULT_DIGEST_LEN;
|
|
} else {
|
|
i_hashlen = NUM2INT(hashlen);
|
|
}
|
|
switch (i_hashlen) {
|
|
case 0:
|
|
rb_raise(rb_eArgError, "Unsupported hash length");
|
|
case DEFAULT_DIGEST_LEN:
|
|
break;
|
|
default:
|
|
Data_Get_Struct(self, hashState, ctx);
|
|
sha3_init(ctx, i_hashlen);
|
|
}
|
|
|
|
return self;
|
|
}
|
|
|
|
static VALUE
|
|
rb_sha3_finish(VALUE self) {
|
|
hashState *ctx;
|
|
VALUE digest;
|
|
|
|
Data_Get_Struct(self, hashState, ctx);
|
|
|
|
digest = rb_str_new(0, ctx->capacity / 2 / 8);
|
|
|
|
Final(ctx, (unsigned char *)RSTRING_PTR(digest));
|
|
|
|
return digest;
|
|
}
|
|
|
|
static VALUE
|
|
rb_sha3_digest_length(VALUE self) {
|
|
hashState *ctx;
|
|
|
|
Data_Get_Struct(self, hashState, ctx);
|
|
return INT2FIX(ctx->capacity / 2 / 8);
|
|
}
|
|
|
|
static VALUE
|
|
rb_sha3_block_length(VALUE self) {
|
|
hashState *ctx;
|
|
|
|
Data_Get_Struct(self, hashState, ctx);
|
|
return INT2FIX(ctx->rate / 8);
|
|
}
|
|
|
|
void __attribute__((visibility("default")))
|
|
Init_sha3() {
|
|
VALUE mDigest, cDigest_Base, cSHA3;
|
|
|
|
rb_require("digest");
|
|
|
|
mDigest = rb_path2class("Digest");
|
|
cDigest_Base = rb_path2class("Digest::Base");
|
|
|
|
cSHA3 = rb_define_class_under(mDigest, "SHA3", cDigest_Base);
|
|
|
|
rb_ivar_set(cSHA3, rb_intern("metadata"), Data_Wrap_Struct(rb_cObject, 0, 0, &sha3));
|
|
|
|
rb_define_alloc_func(cSHA3, rb_sha3_alloc);
|
|
rb_define_method(cSHA3, "initialize", rb_sha3_initialize, -1);
|
|
rb_define_private_method(cSHA3, "finish", rb_sha3_finish, 0);
|
|
rb_define_method(cSHA3, "digest_length", rb_sha3_digest_length, 0);
|
|
rb_define_method(cSHA3, "block_length", rb_sha3_block_length, 0);
|
|
}
|