sha3 2.0.0 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ext/sha3/digest.h CHANGED
@@ -1,81 +1,13 @@
1
1
  // Copyright (c) 2012 - 2025 Johanns Gregorian <io+sha3@jsg.io>
2
2
 
3
- #ifndef _DIGEST_H_
4
- #define _DIGEST_H_
5
-
6
- #include <ruby.h>
7
- #include <ruby/encoding.h>
8
- #include <string.h>
9
-
10
- #include "KeccakHash.h"
3
+ #ifndef _SHA3_DIGEST_H_
4
+ #define _SHA3_DIGEST_H_
11
5
 
12
6
  #ifdef __cplusplus
13
7
  extern "C" {
14
8
  #endif
15
9
 
16
- typedef enum { SHA3_224 = 0, SHA3_256, SHA3_384, SHA3_512, SHAKE_128, SHAKE_256 } algorithm_type;
17
-
18
- typedef HashReturn (*keccak_init_func)(Keccak_HashInstance*);
19
-
20
- typedef struct {
21
- Keccak_HashInstance* state;
22
- int hashbitlen;
23
- algorithm_type algorithm;
24
- } MDX;
25
-
26
- VALUE sha3_module;
27
- VALUE digest_class;
28
- VALUE digest_error_class;
29
-
30
- /* Static IDs for faster symbol lookup */
31
- static ID sha3_224_id;
32
- static ID sha3_256_id;
33
- static ID sha3_384_id;
34
- static ID sha3_512_id;
35
- static ID shake_128_id;
36
- static ID shake_256_id;
37
-
38
- // TypedData functions
39
- extern const rb_data_type_t mdx_type;
40
-
41
- // Static inline functions replacing macros
42
- static inline void get_mdx(VALUE obj, MDX** mdx) {
43
- TypedData_Get_Struct((obj), MDX, &mdx_type, (*mdx));
44
- if (!(*mdx)) {
45
- rb_raise(rb_eRuntimeError, "Digest data not initialized!");
46
- }
47
- }
48
-
49
- static inline void safe_get_mdx(VALUE obj, MDX** mdx) {
50
- if (!rb_obj_is_kind_of(obj, digest_class)) {
51
- rb_raise(rb_eTypeError, "wrong argument (%s)! (expected %s)", rb_obj_classname(obj),
52
- rb_class2name(digest_class));
53
- }
54
- get_mdx(obj, mdx);
55
- }
56
-
57
- /* Allocation and initialization */
58
- static VALUE rb_digest_alloc(VALUE);
59
- static VALUE rb_digest_init(int, VALUE*, VALUE);
60
-
61
- /* Core digest operations */
62
- static VALUE rb_digest_copy(VALUE, VALUE);
63
- static VALUE rb_digest_finish(int, VALUE*, VALUE);
64
- static VALUE rb_digest_reset(VALUE);
65
- static VALUE rb_digest_update(VALUE, VALUE);
66
-
67
- /* Digest properties */
68
- static VALUE rb_digest_block_length(VALUE);
69
- static VALUE rb_digest_length(VALUE);
70
- static VALUE rb_digest_name(VALUE);
71
-
72
- /* Output methods */
73
- static VALUE rb_digest_digest(int, VALUE*, VALUE);
74
- static VALUE rb_digest_hexdigest(int, VALUE*, VALUE);
75
- static VALUE rb_digest_hex_squeeze(VALUE, VALUE);
76
- static VALUE rb_digest_squeeze(VALUE, VALUE);
77
- static VALUE rb_digest_self_digest(VALUE, VALUE, VALUE);
78
- static VALUE rb_digest_self_hexdigest(VALUE, VALUE, VALUE);
10
+ extern void Init_sha3_digest(void);
79
11
 
80
12
  #ifdef __cplusplus
81
13
  }
data/ext/sha3/extconf.rb CHANGED
@@ -4,7 +4,7 @@ require 'mkmf'
4
4
  require 'rbconfig'
5
5
 
6
6
  b64 = 8.size == 8
7
- extension_name = 'sha3_digest'
7
+ extension_name = 'sha3_ext'
8
8
  ref_dir = b64 ? 'ref-64bits' : 'ref-32bits'
9
9
 
10
10
  dir_config(extension_name)
@@ -12,6 +12,9 @@ dir_config(extension_name)
12
12
  # Set compiler flags
13
13
  $CFLAGS << ' -fomit-frame-pointer -O3 -g0 -fms-extensions'
14
14
 
15
+ # Add vectorization flags for better performance on supported platforms
16
+ $CFLAGS << ' -ftree-vectorize' if RUBY_PLATFORM =~ /x86_64|amd64|arm64/
17
+
15
18
  # Add architecture-specific optimizations if enabled
16
19
  $CFLAGS << ' -march=native' if enable_config('march-tune-native', false)
17
20
 
@@ -21,9 +24,6 @@ $CFLAGS << ' -D_FORTIFY_SOURCE=2 -fstack-protector-strong'
21
24
  # Add warning flags to catch potential issues
22
25
  $CFLAGS << ' -Wall -Wextra -Wformat -Wformat-security'
23
26
 
24
- # Add vectorization flags for better performance on supported platforms
25
- $CFLAGS << ' -ftree-vectorize' if RUBY_PLATFORM =~ /x86_64|amd64|arm64/
26
-
27
27
  # Find all relevant subdirectories and filter appropriately
28
28
  vpath_dirs = Dir.glob("#{$srcdir}/lib/**/*")
29
29
  .select { |path| File.directory?(path) }
@@ -40,10 +40,16 @@ $VPATH << vpath_dirs_processed
40
40
  # Add include flags
41
41
  $INCFLAGS << vpath_dirs_processed
42
42
  .map { |dir| " -I$(srcdir)#{dir}" }
43
- .join('')
44
-
45
- # Base source files
46
- $srcs = ['digest.c']
43
+ .join
44
+
45
+ # Define source files
46
+ $srcs = %w[
47
+ cshake.c
48
+ digest.c
49
+ kmac.c
50
+ sha3.c
51
+ sp800_185.c
52
+ ]
47
53
 
48
54
  # Find and add all .c files from the filtered directories
49
55
  $srcs += vpath_dirs
data/ext/sha3/kmac.c ADDED
@@ -0,0 +1,474 @@
1
+ #include "kmac.h"
2
+
3
+ #include "sha3.h"
4
+ #include "sp800_185.h"
5
+
6
+ /*** Types and structs ***/
7
+ typedef struct {
8
+ sp800_185_context_t base;
9
+ } sha3_kmac_context_t;
10
+
11
+ /*** Function prototypes ***/
12
+ static void sha3_kmac_free_context(void *);
13
+ static size_t sha3_kmac_context_size(const void *);
14
+
15
+ /* Allocation and initialization */
16
+ static VALUE rb_sha3_kmac_alloc(VALUE);
17
+ static VALUE rb_sha3_kmac_init(int, VALUE *, VALUE);
18
+ static VALUE rb_sha3_kmac_copy(VALUE, VALUE);
19
+
20
+ /* Core digest operations */
21
+ static VALUE rb_sha3_kmac_finish(int, VALUE *, VALUE);
22
+ static VALUE rb_sha3_kmac_update(VALUE, VALUE);
23
+
24
+ /* Digest properties */
25
+ static VALUE rb_sha3_kmac_name(VALUE);
26
+
27
+ /* Output methods */
28
+ static VALUE rb_sha3_kmac_digest(int, VALUE *, VALUE);
29
+ static VALUE rb_sha3_kmac_hexdigest(int, VALUE *, VALUE);
30
+ static VALUE rb_sha3_kmac_self_digest(int, VALUE *, VALUE);
31
+ static VALUE rb_sha3_kmac_self_hexdigest(int, VALUE *, VALUE);
32
+
33
+ static VALUE rb_sha3_kmac_squeeze(VALUE, VALUE);
34
+ static VALUE rb_sha3_kmac_hex_squeeze(VALUE, VALUE);
35
+
36
+ /*** Global variables ***/
37
+ VALUE _sha3_kmac_class;
38
+ VALUE _sha3_kmac_error_class;
39
+
40
+ /* Define the ID variables */
41
+ static ID _kmac_128_id;
42
+ static ID _kmac_256_id;
43
+
44
+ /* TypedData structure for sha3_kmac_context_t */
45
+ const rb_data_type_t sha3_kmac_data_type_t = {
46
+ "SHA3::KMAC",
47
+ {
48
+ NULL, sha3_kmac_free_context, sha3_kmac_context_size, NULL, /* dcompact field */
49
+ },
50
+ NULL,
51
+ NULL,
52
+ RUBY_TYPED_FREE_IMMEDIATELY,
53
+ };
54
+
55
+ // Helper function to extract context from a Ruby object
56
+ void get_kmac_context(VALUE obj, sp800_185_context_t **context) {
57
+ sha3_kmac_context_t *kmac_ctx;
58
+ TypedData_Get_Struct(obj, sha3_kmac_context_t, &sha3_kmac_data_type_t, kmac_ctx);
59
+ *context = &kmac_ctx->base;
60
+ }
61
+
62
+ void Init_sha3_kmac(void) {
63
+ _kmac_128_id = rb_intern("kmac_128");
64
+ _kmac_256_id = rb_intern("kmac_256");
65
+
66
+ if (!_sha3_module) {
67
+ _sha3_module = rb_define_module("SHA3");
68
+ }
69
+
70
+ /*
71
+ * Document-class: SHA3::KMAC
72
+ *
73
+ * It is a subclass of the Digest::Class class, which provides a framework for
74
+ * creating and manipulating hash digests.
75
+ */
76
+ _sha3_kmac_class = rb_define_class_under(_sha3_module, "KMAC", rb_cObject);
77
+
78
+ /*
79
+ * Document-class: SHA3::KMAC::KMACError
80
+ *
81
+ * All KMAC methods raise this exception on error.
82
+ *
83
+ * It is a subclass of the StandardError class -- see the Ruby documentation
84
+ * for more information.
85
+ */
86
+ _sha3_kmac_error_class = rb_define_class_under(_sha3_kmac_class, "Error", rb_eStandardError);
87
+
88
+ rb_define_alloc_func(_sha3_kmac_class, rb_sha3_kmac_alloc);
89
+ rb_define_method(_sha3_kmac_class, "initialize", rb_sha3_kmac_init, -1);
90
+ rb_define_method(_sha3_kmac_class, "initialize_copy", rb_sha3_kmac_copy, 1);
91
+ rb_define_method(_sha3_kmac_class, "update", rb_sha3_kmac_update, 1);
92
+ rb_define_method(_sha3_kmac_class, "name", rb_sha3_kmac_name, 0);
93
+
94
+ rb_define_method(_sha3_kmac_class, "digest", rb_sha3_kmac_digest, -1);
95
+ rb_define_method(_sha3_kmac_class, "hexdigest", rb_sha3_kmac_hexdigest, -1);
96
+
97
+ rb_define_method(_sha3_kmac_class, "squeeze", rb_sha3_kmac_squeeze, 1);
98
+ rb_define_method(_sha3_kmac_class, "hex_squeeze", rb_sha3_kmac_hex_squeeze, 1);
99
+
100
+ rb_define_private_method(_sha3_kmac_class, "finish", rb_sha3_kmac_finish, -1);
101
+
102
+ rb_define_alias(_sha3_kmac_class, "<<", "update");
103
+
104
+ rb_define_singleton_method(_sha3_kmac_class, "digest", rb_sha3_kmac_self_digest, -1);
105
+ rb_define_singleton_method(_sha3_kmac_class, "hexdigest", rb_sha3_kmac_self_hexdigest, -1);
106
+
107
+ return;
108
+ }
109
+
110
+ static void sha3_kmac_free_context(void *ptr) { sp800_185_free_context((sp800_185_context_t *)ptr); }
111
+
112
+ static size_t sha3_kmac_context_size(const void *ptr) {
113
+ return sp800_185_context_size((const sp800_185_context_t *)ptr, sizeof(sha3_kmac_context_t));
114
+ }
115
+
116
+ static VALUE rb_sha3_kmac_alloc(VALUE klass) {
117
+ sha3_kmac_context_t *context =
118
+ (sha3_kmac_context_t *)sp800_185_alloc_context(sizeof(sha3_kmac_context_t), sizeof(KMAC_Instance));
119
+
120
+ if (!context) {
121
+ rb_raise(_sha3_kmac_error_class, "failed to allocate memory");
122
+ }
123
+
124
+ // Create the Ruby object with TypedData - this will automatically handle freeing
125
+ VALUE obj = TypedData_Wrap_Struct(klass, &sha3_kmac_data_type_t, context);
126
+
127
+ return obj;
128
+ }
129
+
130
+ /*
131
+ * :call-seq:
132
+ * ::new(algorithm, output_length, key, [customization]) -> instance
133
+ *
134
+ * Creates a new KMAC object.
135
+ *
136
+ * +algorithm+::
137
+ * The KMAC algorithm to use (as a Symbol).
138
+ * Valid algorithms are:
139
+ * - :kmac_128
140
+ * - :kmac_256
141
+ *
142
+ * +output_length+::
143
+ * The length of the output in bytes. Set to 0 for an arbitrarily-long output using "squeeze" (XOF) methods.
144
+ *
145
+ * +key+::
146
+ * The key to use for the KMAC.
147
+ *
148
+ * +customization+::
149
+ * _optional_ The customization string to use.
150
+ *
151
+ * = example
152
+ * SHA3::KMAC.new(:kmac_128, 32, "key")
153
+ * SHA3::KMAC.new(:kmac_256, 64, "key", "customization")
154
+ * SHA3::KMAC.new(:kmac_128, 0, "key", "customization")
155
+ *
156
+ */
157
+ static VALUE rb_sha3_kmac_init(int argc, VALUE *argv, VALUE self) {
158
+ VALUE algorithm, output_length, key, customization;
159
+
160
+ rb_scan_args(argc, argv, "31", &algorithm, &output_length, &key, &customization);
161
+
162
+ // Check and convert arguments
163
+ if (NIL_P(algorithm)) {
164
+ rb_raise(rb_eArgError, "missing keyword: algorithm");
165
+ }
166
+ Check_Type(algorithm, T_SYMBOL);
167
+
168
+ if (NIL_P(output_length)) {
169
+ rb_raise(rb_eArgError, "missing keyword: output_length");
170
+ }
171
+ Check_Type(output_length, T_FIXNUM);
172
+
173
+ if (NIL_P(key)) {
174
+ rb_raise(rb_eArgError, "missing keyword: key");
175
+ }
176
+ StringValue(key);
177
+
178
+ if (!NIL_P(customization)) {
179
+ StringValue(customization);
180
+ } else {
181
+ customization = rb_str_new2("");
182
+ }
183
+
184
+ sha3_kmac_context_t *context;
185
+ TypedData_Get_Struct(self, sha3_kmac_context_t, &sha3_kmac_data_type_t, context);
186
+
187
+ // Store the output length in bits
188
+ context->base.output_length = NUM2ULONG(output_length) * 8;
189
+ context->base.error_class = _sha3_kmac_error_class;
190
+
191
+ // Find the appropriate function table based on the algorithm
192
+ ID sym_id = SYM2ID(algorithm);
193
+ if (sym_id == _kmac_128_id) {
194
+ context->base.functions = &sp800_185_functions[SP800_185_KMAC_128];
195
+ } else if (sym_id == _kmac_256_id) {
196
+ context->base.functions = &sp800_185_functions[SP800_185_KMAC_256];
197
+ } else {
198
+ rb_raise(rb_eArgError, "invalid algorithm: %s", rb_id2name(sym_id));
199
+ }
200
+
201
+ // Initialize the KMAC instance
202
+ size_t key_len = RSTRING_LEN(key) * 8;
203
+ size_t customization_len = RSTRING_LEN(customization) * 8;
204
+
205
+ int result = context->base.functions->kmac.init(context->base.state, (const BitSequence *)RSTRING_PTR(key), key_len,
206
+ context->base.output_length,
207
+ (const BitSequence *)RSTRING_PTR(customization), customization_len);
208
+
209
+ if (result != 0) {
210
+ rb_raise(_sha3_kmac_error_class, "failed to initialize %s", context->base.functions->name);
211
+ }
212
+
213
+ return self;
214
+ }
215
+
216
+ /*
217
+ * :call-seq:
218
+ * ::copy(other) -> kmac
219
+ *
220
+ * Creates a copy of the KMAC instance.
221
+ *
222
+ * +other+::
223
+ * The KMAC to copy the state from.
224
+ *
225
+ * = example
226
+ * new_kmac = kmac.dup
227
+ */
228
+ static VALUE rb_sha3_kmac_copy(VALUE self, VALUE other) {
229
+ sha3_kmac_context_t *context, *other_context;
230
+
231
+ rb_check_frozen(self);
232
+ if (self == other) {
233
+ return self;
234
+ }
235
+
236
+ if (!rb_obj_is_kind_of(other, _sha3_kmac_class)) {
237
+ rb_raise(rb_eTypeError, "wrong argument (%s)! (expected %s)", rb_obj_classname(other),
238
+ rb_class2name(_sha3_kmac_class));
239
+ }
240
+
241
+ TypedData_Get_Struct(other, sha3_kmac_context_t, &sha3_kmac_data_type_t, other_context);
242
+ TypedData_Get_Struct(self, sha3_kmac_context_t, &sha3_kmac_data_type_t, context);
243
+
244
+ // Copy the base context attributes
245
+ context->base.functions = other_context->base.functions;
246
+ context->base.output_length = other_context->base.output_length;
247
+
248
+ // Copy the algorithm-specific state
249
+ memcpy(context->base.state, other_context->base.state, context->base.functions->state_size);
250
+
251
+ return self;
252
+ }
253
+
254
+ /*
255
+ * :call-seq:
256
+ * update(string) -> kmac
257
+ *
258
+ * Updates the KMAC with the given string.
259
+ *
260
+ * +string+::
261
+ * The string to update the KMAC with.
262
+ *
263
+ * = example
264
+ * kmac.update("more data")
265
+ * kmac << "more data" # alias for update
266
+ */
267
+ static VALUE rb_sha3_kmac_update(VALUE self, VALUE data) {
268
+ sp800_185_context_t *context;
269
+ get_kmac_context(self, &context);
270
+ sp800_185_update(context, data);
271
+
272
+ return self;
273
+ }
274
+
275
+ /*
276
+ * :call-seq:
277
+ * name -> String
278
+ *
279
+ * Returns the name of the algorithm.
280
+ *
281
+ * = example
282
+ * kmac.name #=> "KMAC128" or "KMAC256"
283
+ */
284
+ static VALUE rb_sha3_kmac_name(VALUE self) {
285
+ sp800_185_context_t *context;
286
+ get_kmac_context(self, &context);
287
+
288
+ return rb_str_new2(sp800_185_name(context));
289
+ }
290
+
291
+ /*
292
+ * :call-seq:
293
+ * finish([message]) -> String
294
+ *
295
+ * Returns the final KMAC as a binary string.
296
+ *
297
+ * +message+::
298
+ * _optional_ Output buffer to receive the final KMAC value.
299
+ *
300
+ * = example
301
+ * kmac.finish
302
+ */
303
+ static VALUE rb_sha3_kmac_finish(int argc, VALUE *argv, VALUE self) {
304
+ sp800_185_context_t *context;
305
+ get_kmac_context(self, &context);
306
+
307
+ VALUE output = argc > 0 ? argv[0] : Qnil;
308
+
309
+ return sp800_185_finish(context, output);
310
+ }
311
+
312
+ /*
313
+ * :call-seq:
314
+ * digest() -> string
315
+ * digest([data]) -> string
316
+ *
317
+ * Returns the binary representation of the KMAC.
318
+ * This method creates a copy of the current instance so that
319
+ * the original state is preserved for future updates.
320
+ *
321
+ * +data+::
322
+ * _optional_ Update state with additional data before returning KMAC.
323
+ *
324
+ * = example
325
+ * kmac.digest
326
+ * kmac.digest('final chunk')
327
+ */
328
+ static VALUE rb_sha3_kmac_digest(int argc, VALUE *argv, VALUE self) {
329
+ sp800_185_context_t *context;
330
+ get_kmac_context(self, &context);
331
+
332
+ VALUE data = argc > 0 ? argv[0] : Qnil;
333
+
334
+ return sp800_185_digest(context, data);
335
+ }
336
+
337
+ /*
338
+ * :call-seq:
339
+ * hexdigest() -> string
340
+ * hexdigest([data]) -> string
341
+ *
342
+ * Returns the hexadecimal representation of the KMAC.
343
+ * This method creates a copy of the current instance so that
344
+ * the original state is preserved for future updates.
345
+ *
346
+ * +data+::
347
+ * _optional_ Update state with additional data before returning KMAC.
348
+ *
349
+ * = example
350
+ * kmac.hexdigest
351
+ * kmac.hexdigest('final chunk')
352
+ */
353
+ static VALUE rb_sha3_kmac_hexdigest(int argc, VALUE *argv, VALUE self) {
354
+ sp800_185_context_t *context;
355
+ get_kmac_context(self, &context);
356
+
357
+ VALUE data = argc > 0 ? argv[0] : Qnil;
358
+
359
+ return sp800_185_hexdigest(context, data);
360
+ }
361
+
362
+ /*
363
+ * :call-seq:
364
+ * squeeze(length) -> string
365
+ *
366
+ * Returns the squeezed output as a binary string.
367
+ * This method creates a copy of the current instance so that
368
+ * the original state is preserved for future updates.
369
+ *
370
+ * = note
371
+ * The KMAC instance must be initialized with 0 output length before calling this method.
372
+ *
373
+ * = example
374
+ * kmac.squeeze(128)
375
+ */
376
+ static VALUE rb_sha3_kmac_squeeze(VALUE self, VALUE length) {
377
+ sp800_185_context_t *context;
378
+ get_kmac_context(self, &context);
379
+
380
+ return sp800_185_squeeze(context, length);
381
+ }
382
+
383
+ /*
384
+ * :call-seq:
385
+ * hex_squeeze(length) -> string
386
+ *
387
+ * Returns the squeezed output as a hexadecimal string.
388
+ * This method creates a copy of the current instance so that
389
+ * the original state is preserved for future updates.
390
+ *
391
+ * = note
392
+ * The KMAC instance must be initialized with 0 output length before calling this method.
393
+ *
394
+ * = example
395
+ * kmac.hex_squeeze(128)
396
+ */
397
+ static VALUE rb_sha3_kmac_hex_squeeze(VALUE self, VALUE length) {
398
+ sp800_185_context_t *context;
399
+ get_kmac_context(self, &context);
400
+
401
+ return sp800_185_hex_squeeze(context, length);
402
+ }
403
+
404
+ /*
405
+ * :call-seq:
406
+ * ::digest(algorithm, data, output_length, key, [customization]) -> string
407
+ *
408
+ * One-shot operation to return the binary KMAC digest without explicitly creating an instance.
409
+ *
410
+ * +algorithm+::
411
+ * The KMAC algorithm to use (as a Symbol) - :kmac_128 or :kmac_256
412
+ * +data+::
413
+ * The data to digest
414
+ * +output_length+::
415
+ * The length of the output in bytes
416
+ * +key+::
417
+ * The key to use for the KMAC
418
+ * +customization+::
419
+ * _optional_ The customization string to use
420
+ *
421
+ * = example
422
+ * SHA3::KMAC.digest(:kmac_128, "data", 32, "key")
423
+ * SHA3::KMAC.digest(:kmac_128, "data", 32, "key", "customization")
424
+ */
425
+ static VALUE rb_sha3_kmac_self_digest(int argc, VALUE *argv, VALUE klass) {
426
+ VALUE algorithm, data, output_length, key, customization;
427
+
428
+ rb_scan_args(argc, argv, "41", &algorithm, &data, &output_length, &key, &customization);
429
+
430
+ Check_Type(output_length, T_FIXNUM);
431
+ if (!NIL_P(output_length) && output_length <= INT2FIX(0)) {
432
+ rb_raise(rb_eArgError, "class method digest does not support XOF mode");
433
+ }
434
+
435
+ VALUE kmac = rb_funcall(klass, rb_intern("new"), 4, algorithm, output_length, key, customization);
436
+
437
+ return rb_funcall(kmac, rb_intern("digest"), 1, data);
438
+ }
439
+
440
+ /*
441
+ * :call-seq:
442
+ * ::hexdigest(algorithm, data, output_length, key, [customization]) -> string
443
+ *
444
+ * One-shot operation to return the hexadecimal KMAC digest without explicitly creating an instance.
445
+ *
446
+ * +algorithm+::
447
+ * The KMAC algorithm to use (as a Symbol) - :kmac_128 or :kmac_256
448
+ * +data+::
449
+ * The data to digest
450
+ * +output_length+::
451
+ * The length of the output in bytes
452
+ * +key+::
453
+ * The key to use for the KMAC
454
+ * +customization+::
455
+ * _optional_ The customization string to use
456
+ *
457
+ * = example
458
+ * SHA3::KMAC.hexdigest(:kmac_128, "data", 32, "key")
459
+ * SHA3::KMAC.hexdigest(:kmac_128, "data", 32, "key", "customization")
460
+ */
461
+ static VALUE rb_sha3_kmac_self_hexdigest(int argc, VALUE *argv, VALUE klass) {
462
+ VALUE algorithm, data, output_length, key, customization;
463
+
464
+ rb_scan_args(argc, argv, "41", &algorithm, &data, &output_length, &key, &customization);
465
+
466
+ Check_Type(output_length, T_FIXNUM);
467
+ if (!NIL_P(output_length) && output_length <= INT2FIX(0)) {
468
+ rb_raise(rb_eArgError, "class method hexdigest does not support XOF mode");
469
+ }
470
+
471
+ VALUE kmac = rb_funcall(klass, rb_intern("new"), 4, algorithm, output_length, key, customization);
472
+
473
+ return rb_funcall(kmac, rb_intern("hexdigest"), 1, data);
474
+ }
data/ext/sha3/kmac.h ADDED
@@ -0,0 +1,14 @@
1
+ #ifndef _SHA3_KMAC_H_
2
+ #define _SHA3_KMAC_H_
3
+
4
+ #ifdef __cplusplus
5
+ extern "C" {
6
+ #endif
7
+
8
+ extern void Init_sha3_kmac(void);
9
+
10
+ #ifdef __cplusplus
11
+ }
12
+ #endif
13
+
14
+ #endif // _SHA3_KMAC_H_
data/ext/sha3/sha3.c ADDED
@@ -0,0 +1,35 @@
1
+ #include "sha3.h"
2
+
3
+ #include "cshake.h"
4
+ #include "digest.h"
5
+ #include "kmac.h"
6
+
7
+ VALUE _sha3_module;
8
+
9
+ void Init_sha3_ext(void) {
10
+ /*
11
+ * Document-module: SHA3
12
+ *
13
+ * This module provides implementations of the SHA-3 family of cryptographic hash functions
14
+ * and the SHAKE extendable-output functions.
15
+ *
16
+ * It includes the SHA3::Digest and SHA3::KMAC classes, which offer methods for computing digests and keyed message
17
+ * authentication codes (KMAC).
18
+ *
19
+ * == Classes
20
+ * SHA3::Digest
21
+ * SHA3::Digest::Error
22
+ * SHA3::KMAC
23
+ * SHA3::KMAC::Error
24
+ * SHA3::CSHAKE
25
+ * SHA3::CSHAKE::Error
26
+ *
27
+ */
28
+ _sha3_module = rb_define_module("SHA3");
29
+
30
+ Init_sha3_digest();
31
+ Init_sha3_cshake();
32
+ Init_sha3_kmac();
33
+
34
+ return;
35
+ }
data/ext/sha3/sha3.h ADDED
@@ -0,0 +1,17 @@
1
+ #ifndef _SHA3_H_
2
+ #define _SHA3_H_
3
+
4
+ #include <ruby.h>
5
+ #include <ruby/encoding.h>
6
+
7
+ #ifdef __cplusplus
8
+ extern "C" {
9
+ #endif
10
+
11
+ extern VALUE _sha3_module;
12
+
13
+ #ifdef __cplusplus
14
+ }
15
+ #endif
16
+
17
+ #endif // _SHA3_H_