diff --git a/digest-sha3.gemspec b/digest-sha3.gemspec index 0d189c5..d8916cd 100644 --- a/digest-sha3.gemspec +++ b/digest-sha3.gemspec @@ -9,6 +9,7 @@ Gem::Specification.new do |s| s.description = "The SHA-3 (Keccak) hash." s.authors = ["Hongli Lai (Phusion)", "Keccak authors"] s.extensions << "ext/digest/extconf.rb" + s.require_ruby_version = "~> 2.2" s.files = Dir[ "README.md", diff --git a/ext/digest/sha3.c b/ext/digest/sha3.c index 1a912bb..a3cbc9e 100644 --- a/ext/digest/sha3.c +++ b/ext/digest/sha3.c @@ -9,19 +9,69 @@ #define MAX_DIGEST_SIZE 64 #define DEFAULT_DIGEST_LEN 512 -static void sha3_init_func(hashState *ctx); +static int sha3_init_func(hashState *ctx); static void sha3_update_func(hashState *ctx, unsigned char *str, size_t len); +static int sha3_finish_func(hashState *ctx, unsigned char *digest); +/* + Metadata definition for the SHA3 algorithm. + Defines the Version, sizes for block and digest as well as + the entry points for the algorithms +*/ static rb_digest_metadata_t sha3 = { RUBY_DIGEST_API_VERSION, DEFAULT_DIGEST_LEN, - KeccakPermutationSize - (2 * DEFAULT_DIGEST_LEN), - sizeof(hashState), + KeccakPermutationSize - (2 * DEFAULT_DIGEST_LEN), //size of blocks + sizeof(hashState), //size of context for the object we'll be passed in below functions. (rb_digest_hash_init_func_t)sha3_init_func, (rb_digest_hash_update_func_t)sha3_update_func, - NULL, + (rb_digest_hash_finish_func_t)sha3_finish_func, }; +/* Initialization function for the algorithm, + gets called during allocation of the digest object. + we override initialize to do custom hash size, so we don't care too much here. +*/ +static int +sha3_init_func(hashState *ctx) { + // Just return a 1 ' successful' we override the init function + // so this is not necessary + // the base class alloc calls this to initialize the algorithm + return 1; +} + +/* Update function, take the current context and add str to it */ +static void +sha3_update_func(hashState *ctx, unsigned char *str, size_t len) { + Update(ctx, str, len * 8); +} + +/* Finish the hash calculation and return the finished string */ +static int +sha3_finish_func(hashState *ctx, unsigned char *digest) { + Final(ctx, digest); + return 1; +} + +/* Ruby method. Digest::SHA3#finish() + * No Arguments + * @returns [String] Encoded Digest String + */ +static VALUE +rb_sha3_finish(VALUE self) { + hashState *ctx; + VALUE digest; + + ctx = (hashState *)RTYPEDDATA_DATA(self); + digest = rb_str_new(0, ctx->capacity / 2 / 8); + sha3_finish_func(ctx, (unsigned char *)RSTRING_PTR(digest)); + + return digest; +} + +/* :nodoc: private method + * initialize the ctx with the bitlength + */ static void sha3_init(hashState *ctx, size_t bitlen) { switch (Init(ctx, bitlen)) { @@ -36,25 +86,10 @@ sha3_init(hashState *ctx, size_t bitlen) { } } -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); -} - +/* Ruby method. Digest::SHA3.new(hashlen) + * @param hashlen The length of hash, only supports 224, 256, 384 or 512 + * @returns [Digest::SHA3] new object. + */ static VALUE rb_sha3_initialize(int argc, VALUE *argv, VALUE self) { hashState *ctx; @@ -66,46 +101,35 @@ rb_sha3_initialize(int argc, VALUE *argv, VALUE self) { } else { i_hashlen = NUM2INT(hashlen); } - switch (i_hashlen) { - case 0: + if ( i_hashlen == 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; + ctx = (hashState *)RTYPEDDATA_DATA(self); + sha3_init(ctx, i_hashlen); + + return rb_call_super(0, NULL); } +/* Ruby method. Digest::SHA3#digest_length + * @returns [Numeric] Length of the digest. + */ static VALUE rb_sha3_digest_length(VALUE self) { hashState *ctx; - Data_Get_Struct(self, hashState, ctx); + ctx = (hashState *)RTYPEDDATA_DATA(self); return INT2FIX(ctx->capacity / 2 / 8); } +/* Ruby method. Digest::SHA3#block_length + * @returns [Numeric] Length of blocks in this digest. + */ static VALUE rb_sha3_block_length(VALUE self) { hashState *ctx; - Data_Get_Struct(self, hashState, ctx); + ctx = (hashState *)RTYPEDDATA_DATA(self); return INT2FIX(ctx->rate / 8); } @@ -120,11 +144,10 @@ Init_sha3() { 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_iv_set(cSHA3, "metadata", Data_Wrap_Struct(0, 0, 0, (void *)&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); + rb_define_method(cSHA3, "initialize", rb_sha3_initialize, -1); + rb_define_method(cSHA3, "digest_length", rb_sha3_digest_length, 0); + rb_define_method(cSHA3, "block_length", rb_sha3_block_length, 0); + rb_define_method(cSHA3, "finish", rb_sha3_finish, 0); } diff --git a/lib/digest/sha3/version.rb b/lib/digest/sha3/version.rb index 8a51e40..b55dcab 100644 --- a/lib/digest/sha3/version.rb +++ b/lib/digest/sha3/version.rb @@ -1,7 +1,7 @@ module Digest class SHA3 module Version - STRING = "1.0.2" + STRING = "1.1.0" end end -end \ No newline at end of file +end