class SHA3::Digest
It is a subclass of the Digest::Class class, which provides a framework for creating and manipulating hash digest. Supported Algorithms are:
-
SHA3-224 (:sha3_224)
-
SHA3-256 (:sha3_256)
-
SHA3-384 (:sha3_384)
-
SHA3-512 (:sha3_512)
-
SHAKE128 (:shake_128)
-
SHAKE256 (:shake_256)
Public Class Methods
Source
static VALUE rb_sha3_digest_self_digest(VALUE klass, VALUE name, VALUE data) {
// Add null checks
if (NIL_P(name) || NIL_P(data)) {
rb_raise(_sha3_digest_error_class, "algorithm name and data cannot be nil");
}
// Add type validation for name
if (TYPE(name) != T_SYMBOL) {
rb_raise(_sha3_digest_error_class, "algorithm name must be a symbol");
}
// Existing code...
VALUE args[2];
// Need to add type checking for the data parameter
StringValue(data);
/* For SHAKE algorithms, we need to handle them differently */
if (TYPE(name) == T_SYMBOL) {
ID symid = SYM2ID(name);
if (symid == _shake_128_id || symid == _shake_256_id) {
/* Create a new digest instance with the specified algorithm */
VALUE digest = rb_class_new_instance(1, &name, klass);
/* Update it with the data */
rb_sha3_digest_update(digest, data);
/* For SHAKE algorithms, use a default output length based on the security strength */
int output_length = (symid == _shake_128_id) ? 16 : 32; /* 128/8 or 256/8 */
/* Return the squeezed output */
return rb_sha3_digest_squeeze(digest, INT2NUM(output_length));
}
}
/* Call the superclass method with arguments in reverse order */
args[0] = data;
args[1] = name;
return rb_call_super(2, args);
}
Returns the binary digest of the given data using the algorithm specified by name.
name-
The hash algorithm to use (as a Symbol). Valid algorithms are:
-
:sha3_224
-
:sha3_256
-
:sha3_384
-
:sha3_512
-
:shake_128
-
:shake_256
-
data-
The data to hash.
example¶ ↑
SHA3::Digest.digest(:sha3_256, "data to hash")
note¶ ↑
This method defaults to squeezing 16 bytes for SHAKE128 and 32 bytes for SHAKE256. To squeeze a different length, use squeeze instance method.
Source
static VALUE rb_sha3_digest_self_hexdigest(VALUE klass, VALUE name, VALUE data) {
VALUE args[2];
// Need to add type checking for the data parameter
StringValue(data);
/* For SHAKE algorithms, we need to handle them differently */
if (TYPE(name) == T_SYMBOL) {
ID symid = SYM2ID(name);
if (symid == _shake_128_id || symid == _shake_256_id) {
/* Create a new digest instance with the specified algorithm */
VALUE digest = rb_class_new_instance(1, &name, klass);
/* Update it with the data */
rb_sha3_digest_update(digest, data);
/* For SHAKE algorithms, use a default output length based on the security strength */
int output_length = (symid == _shake_128_id) ? 16 : 32; /* 128/8 or 256/8 */
/* Return the hexadecimal representation of the squeezed output */
return rb_sha3_digest_hex_squeeze(digest, INT2NUM(output_length));
}
}
/* Call the superclass method with arguments in reverse order */
args[0] = data;
args[1] = name;
return rb_call_super(2, args);
}
Returns the hexadecimal representation of the given data using the algorithm specified by name.
name-
The hash algorithm to use (as a Symbol). Valid algorithms are:
-
:sha3_224
-
:sha3_256
-
:sha3_384
-
:sha3_512
-
:shake_128
-
:shake_256
-
data-
The data to hash.
example¶ ↑
SHA3::Digest.hexdigest(:sha3_256, "data to hash")
note¶ ↑
This method defaults to squeezing 16 bytes for SHAKE128 and 32 bytes for SHAKE256. To squeeze a different length, use hex_squeeze instance method.
Source
static VALUE rb_sha3_digest_init(int argc, VALUE *argv, VALUE self) {
sha3_digest_context_t *context;
VALUE hlen, data;
rb_scan_args(argc, argv, "02", &hlen, &data);
get_sha3_digest_context(self, &context);
if (NIL_P(hlen)) {
context->algorithm = SHA3_256;
context->hashbitlen = 256;
} else {
context->hashbitlen = get_hashbit_length(hlen, &context->algorithm);
}
if (keccak_hash_initialize(context) != KECCAK_SUCCESS) {
rb_raise(_sha3_digest_error_class, "failed to initialize algorithm state");
}
if (!NIL_P(data)) {
return rb_sha3_digest_update(self, data);
}
return self;
}
Creates a new digest object.
algorithm-
optional The algorithm to use. Valid algorithms are:
-
:sha3_224
-
:sha3_256
-
:sha3_384
-
:sha3_512
-
:shake_128
-
:shake_256
-
message-
optional The message to hash.
example¶ ↑
SHA3::Digest.new(:sha3_256) SHA3::Digest.new(:shake_128, "initial data")
Public Instance Methods
Source
Source
static VALUE rb_sha3_digest_digest(int argc, VALUE *argv, VALUE self) {
sha3_digest_context_t *context;
get_sha3_digest_context(self, &context);
if (context->algorithm != SHAKE_128 && context->algorithm != SHAKE_256) {
return rb_call_super(argc, argv);
}
return prepare_shake_output(self, argc, argv, 0);
}
Returns the binary representation of the digest.
length-
The length of the output to squeeze when using SHAKE algorithms. This parameter is required for SHAKE algorithms.
data-
optional Update state with additional data before returning digest.
example¶ ↑
digest.digest() digest.digest('compute me') digest.digest(12) # For SHAKE algorithms digest.digest(12, 'compute me') # For SHAKE algorithms
Source
Source
static VALUE rb_sha3_digest_hex_squeeze(VALUE self, VALUE length) {
// Get the binary output using the existing squeeze function
VALUE bin_str = rb_sha3_digest_squeeze(self, length);
// Use Ruby's built-in unpack method to convert to hex
return rb_funcall(bin_str, rb_intern("unpack1"), 1, rb_str_new2("H*"));
}
Returns the hexadecimal representation of the squeezed output. Only available for SHAKE algorithms.
length-
The length in bytes of the output to squeeze.
example¶ ↑
digest.hex_squeeze(32) # Get 64 hex characters (32 bytes)
Source
static VALUE rb_sha3_digest_hexdigest(int argc, VALUE *argv, VALUE self) {
sha3_digest_context_t *context;
get_sha3_digest_context(self, &context);
if (context->algorithm != SHAKE_128 && context->algorithm != SHAKE_256) {
return rb_call_super(argc, argv);
}
return prepare_shake_output(self, argc, argv, 1);
}
Returns the hexadecimal representation of the digest.
length-
The length of the output to squeeze when using SHAKE algorithms. This parameter is required for SHAKE algorithms.
data-
optional Update state with additional data before returning digest.
example¶ ↑
digest.hexdigest() digest.hexdigest('compute me') digest.hexdigest(12) # For SHAKE algorithms digest.hexdigest(12, 'compute me') # For SHAKE algorithms
Source
static VALUE rb_sha3_digest_copy(VALUE self, VALUE other) {
sha3_digest_context_t *context;
sha3_digest_context_t *other_context;
rb_check_frozen(self);
if (self == other) {
return self;
}
if (!rb_obj_is_kind_of(other, _sha3_digest_class)) {
rb_raise(rb_eTypeError, "wrong argument (%s)! (expected %s)", rb_obj_classname(other),
rb_class2name(_sha3_digest_class));
}
safe_get_sha3_digest_context(other, &other_context);
get_sha3_digest_context(self, &context);
context->hashbitlen = other_context->hashbitlen;
context->algorithm = other_context->algorithm;
memcpy(context->state, other_context->state, sizeof(Keccak_HashInstance));
if (!compare_contexts(context, other_context)) {
rb_raise(_sha3_digest_error_class, "failed to copy state");
}
return self;
}
Initializes the digest with the state of another digest.
other-
The digest to copy the state from.
example¶ ↑
new_digest = digest.dup
Source
static VALUE rb_sha3_digest_name(VALUE self) {
sha3_digest_context_t *context;
get_sha3_digest_context(self, &context);
switch (context->algorithm) {
case SHA3_224:
return rb_str_new2("SHA3-224");
case SHA3_256:
return rb_str_new2("SHA3-256");
case SHA3_384:
return rb_str_new2("SHA3-384");
case SHA3_512:
return rb_str_new2("SHA3-512");
case SHAKE_128:
return rb_str_new2("SHAKE128");
case SHAKE_256:
return rb_str_new2("SHAKE256");
default:
rb_raise(_sha3_digest_error_class, "unknown algorithm");
}
}
Returns the name of the algorithm.
example¶ ↑
digest.name #=> "SHA3-256"
Source
static VALUE rb_sha3_digest_reset(VALUE self) {
sha3_digest_context_t *context;
get_sha3_digest_context(self, &context);
memset(context->state, 0, sizeof(Keccak_HashInstance));
if (keccak_hash_initialize(context) != KECCAK_SUCCESS) {
rb_raise(_sha3_digest_error_class, "failed to reset internal state");
}
return self;
}
Resets the digest to its initial state.
example¶ ↑
digest.reset
Source
static VALUE rb_sha3_digest_squeeze(VALUE self, VALUE length) {
sha3_digest_context_t *context;
VALUE str, copy;
int output_bytes;
Check_Type(length, T_FIXNUM);
output_bytes = NUM2INT(length);
if (output_bytes <= 0) {
rb_raise(_sha3_digest_error_class, "output length must be positive");
}
get_sha3_digest_context(self, &context);
// Only SHAKE algorithms support arbitrary-length output
if (!is_shake_algorithm(context->algorithm)) {
rb_raise(_sha3_digest_error_class, "squeeze is only supported for SHAKE algorithms");
}
// Create a copy of the digest object to avoid modifying the original
copy = rb_obj_clone(self);
// Get the sha3_digest_context_t struct from the copy
sha3_digest_context_t *context_copy;
get_sha3_digest_context(copy, &context_copy);
str = rb_str_new(0, output_bytes);
// Finalize the hash on the copy
if (Keccak_HashFinal(context_copy->state, NULL) != KECCAK_SUCCESS) {
rb_raise(_sha3_digest_error_class, "failed to finalize digest");
}
// Then squeeze out the desired number of bytes
if (Keccak_HashSqueeze(context_copy->state, (BitSequence *)RSTRING_PTR(str), output_bytes * 8) != KECCAK_SUCCESS) {
rb_raise(_sha3_digest_error_class, "failed to squeeze output");
}
return str;
}
Returns the squeezed output as a binary string. Only available for SHAKE algorithms. This method creates a copy of the current instance to preserve the original state.
length-
The length in bytes of the output to squeeze.
example¶ ↑
digest.squeeze(32) # Get 32 bytes of output
Source
static VALUE rb_sha3_digest_update(VALUE self, VALUE data) {
sha3_digest_context_t *context;
BitLength dlen;
StringValue(data);
get_sha3_digest_context(self, &context);
// Check for empty data
if (RSTRING_LEN(data) == 0) {
return self;
}
// Check for NULL data pointer
if (RSTRING_PTR(data) == NULL) {
rb_raise(_sha3_digest_error_class, "cannot update with NULL data");
}
dlen = (RSTRING_LEN(data) * 8);
if (Keccak_HashUpdate(context->state, (BitSequence *)RSTRING_PTR(data), dlen) != KECCAK_SUCCESS) {
rb_raise(_sha3_digest_error_class, "failed to update hash data");
}
return self;
}
Updates the digest with the given string.
string-
The string to update the digest with.
example¶ ↑
digest.update("more data") digest << "more data" # alias for update
Private Instance Methods
Source
static VALUE rb_sha3_digest_finish(int argc, VALUE *argv, VALUE self) {
sha3_digest_context_t *context;
VALUE str;
int digest_bytes;
rb_scan_args(argc, argv, "01", &str);
get_sha3_digest_context(self, &context);
// For both SHA3 and SHAKE algorithms, use the security strength (hashbitlen)
// as the default output length
digest_bytes = context->hashbitlen / 8;
if (NIL_P(str)) {
str = rb_str_new(0, digest_bytes);
} else {
StringValue(str);
rb_str_resize(str, digest_bytes);
}
if (Keccak_HashFinal(context->state, (BitSequence *)RSTRING_PTR(str)) != KECCAK_SUCCESS) {
rb_raise(_sha3_digest_error_class, "failed to finalize digest");
}
return str;
}
Returns the final digest as a binary string.
message-
optional Update state with additional data before finalizing.
example¶ ↑
digest.finish digest.finish("final chunk")