sha3 2.1.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/kmac.c CHANGED
@@ -1,52 +1,39 @@
1
1
  #include "kmac.h"
2
2
 
3
- #include "KeccakHash.h"
4
- #include "SP800-185.h"
5
3
  #include "sha3.h"
6
-
7
- // SHA3::KMAC.new(algorithm, output_length, key, customization)
8
- // SHA3::KMAC128.new(output_length, key, customization)
9
- // SHA3::KMAC256.new(output_length, key, customization)
10
- // kmac.update
11
- // kmac.digest | kmac.hexdigest
4
+ #include "sp800_185.h"
12
5
 
13
6
  /*** Types and structs ***/
14
-
15
- typedef enum { KMAC_128 = 0, KMAC_256 } sha3_kmac_algorithms;
16
-
17
7
  typedef struct {
18
- KMAC_Instance* state;
19
- sha3_kmac_algorithms algorithm;
20
-
21
- size_t output_length;
8
+ sp800_185_context_t base;
22
9
  } sha3_kmac_context_t;
23
10
 
24
11
  /*** Function prototypes ***/
25
-
26
- static int compare_contexts(const sha3_kmac_context_t*, const sha3_kmac_context_t*);
27
- static void sha3_kmac_free_context(void*);
28
- static size_t sha3_kmac_context_size(const void*);
12
+ static void sha3_kmac_free_context(void *);
13
+ static size_t sha3_kmac_context_size(const void *);
29
14
 
30
15
  /* Allocation and initialization */
31
16
  static VALUE rb_sha3_kmac_alloc(VALUE);
32
- static VALUE rb_sha3_kmac_init(int, VALUE*, VALUE);
17
+ static VALUE rb_sha3_kmac_init(int, VALUE *, VALUE);
33
18
  static VALUE rb_sha3_kmac_copy(VALUE, VALUE);
34
19
 
35
20
  /* Core digest operations */
36
- static VALUE rb_sha3_kmac_finish(int, VALUE*, VALUE);
21
+ static VALUE rb_sha3_kmac_finish(int, VALUE *, VALUE);
37
22
  static VALUE rb_sha3_kmac_update(VALUE, VALUE);
38
23
 
39
24
  /* Digest properties */
40
25
  static VALUE rb_sha3_kmac_name(VALUE);
41
26
 
42
27
  /* Output methods */
43
- static VALUE rb_sha3_kmac_digest(int, VALUE*, VALUE);
44
- static VALUE rb_sha3_kmac_hexdigest(int, VALUE*, VALUE);
45
- static VALUE rb_sha3_kmac_self_digest(int, VALUE*, VALUE);
46
- static VALUE rb_sha3_kmac_self_hexdigest(int, VALUE*, VALUE);
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);
47
32
 
48
- /*** Global variables ***/
33
+ static VALUE rb_sha3_kmac_squeeze(VALUE, VALUE);
34
+ static VALUE rb_sha3_kmac_hex_squeeze(VALUE, VALUE);
49
35
 
36
+ /*** Global variables ***/
50
37
  VALUE _sha3_kmac_class;
51
38
  VALUE _sha3_kmac_error_class;
52
39
 
@@ -55,21 +42,28 @@ static ID _kmac_128_id;
55
42
  static ID _kmac_256_id;
56
43
 
57
44
  /* TypedData structure for sha3_kmac_context_t */
58
- const rb_data_type_t sha3_kmac_data_type_t = {"SHA3::KMAC",
59
- {
60
- NULL,
61
- sha3_kmac_free_context,
62
- sha3_kmac_context_size,
63
- },
64
- NULL,
65
- NULL,
66
- RUBY_TYPED_FREE_IMMEDIATELY};
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
+ }
67
61
 
68
62
  void Init_sha3_kmac(void) {
69
63
  _kmac_128_id = rb_intern("kmac_128");
70
64
  _kmac_256_id = rb_intern("kmac_256");
71
65
 
72
- if (NIL_P(_sha3_module)) {
66
+ if (!_sha3_module) {
73
67
  _sha3_module = rb_define_module("SHA3");
74
68
  }
75
69
 
@@ -89,7 +83,7 @@ void Init_sha3_kmac(void) {
89
83
  * It is a subclass of the StandardError class -- see the Ruby documentation
90
84
  * for more information.
91
85
  */
92
- _sha3_kmac_error_class = rb_define_class_under(_sha3_kmac_class, "KMACError", rb_eStandardError);
86
+ _sha3_kmac_error_class = rb_define_class_under(_sha3_kmac_class, "Error", rb_eStandardError);
93
87
 
94
88
  rb_define_alloc_func(_sha3_kmac_class, rb_sha3_kmac_alloc);
95
89
  rb_define_method(_sha3_kmac_class, "initialize", rb_sha3_kmac_init, -1);
@@ -100,6 +94,9 @@ void Init_sha3_kmac(void) {
100
94
  rb_define_method(_sha3_kmac_class, "digest", rb_sha3_kmac_digest, -1);
101
95
  rb_define_method(_sha3_kmac_class, "hexdigest", rb_sha3_kmac_hexdigest, -1);
102
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
+
103
100
  rb_define_private_method(_sha3_kmac_class, "finish", rb_sha3_kmac_finish, -1);
104
101
 
105
102
  rb_define_alias(_sha3_kmac_class, "<<", "update");
@@ -110,72 +107,22 @@ void Init_sha3_kmac(void) {
110
107
  return;
111
108
  }
112
109
 
113
- static int compare_contexts(const sha3_kmac_context_t* context1, const sha3_kmac_context_t* context2) {
114
- // First check the algorithm
115
- if (context1->algorithm != context2->algorithm) {
116
- return 0;
117
- }
118
-
119
- // Compare the internal state structure
120
- if (memcmp(context1->state, context2->state, sizeof(KMAC_Instance)) != 0) {
121
- return 0;
122
- }
123
-
124
- // All comparisons passed
125
- return 1;
126
- }
127
-
128
- static inline void get_sha3_kmac_context(VALUE obj, sha3_kmac_context_t** context) {
129
- TypedData_Get_Struct((obj), sha3_kmac_context_t, &sha3_kmac_data_type_t, (*context));
130
- if (!(*context)) {
131
- rb_raise(rb_eRuntimeError, "KMAC data not initialized!");
132
- }
133
- }
134
-
135
- static inline void safe_get_sha3_kmac_context(VALUE obj, sha3_kmac_context_t** context) {
136
- if (!rb_obj_is_kind_of(obj, _sha3_kmac_class)) {
137
- rb_raise(rb_eTypeError, "wrong argument (%s)! (expected %s)", rb_obj_classname(obj),
138
- rb_class2name(_sha3_kmac_class));
139
- }
140
- get_sha3_kmac_context(obj, context);
141
- }
142
-
143
- static void sha3_kmac_free_context(void* ptr) {
144
- sha3_kmac_context_t* context = (sha3_kmac_context_t*)ptr;
145
- if (context) {
146
- if (context->state) {
147
- free(context->state);
148
- }
149
- free(context);
150
- }
151
- }
152
-
153
- static size_t sha3_kmac_context_size(const void* ptr) {
154
- const sha3_kmac_context_t* context = (const sha3_kmac_context_t*)ptr;
155
- size_t size = sizeof(sha3_kmac_context_t);
110
+ static void sha3_kmac_free_context(void *ptr) { sp800_185_free_context((sp800_185_context_t *)ptr); }
156
111
 
157
- if (context && context->state) {
158
- size += sizeof(KMAC_Instance);
159
- }
160
-
161
- return size;
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));
162
114
  }
163
115
 
164
116
  static VALUE rb_sha3_kmac_alloc(VALUE klass) {
165
- sha3_kmac_context_t* context = (sha3_kmac_context_t*)malloc(sizeof(sha3_kmac_context_t));
166
- if (!context) {
167
- rb_raise(_sha3_kmac_error_class, "failed to allocate object memory");
168
- }
117
+ sha3_kmac_context_t *context =
118
+ (sha3_kmac_context_t *)sp800_185_alloc_context(sizeof(sha3_kmac_context_t), sizeof(KMAC_Instance));
169
119
 
170
- context->state = (KMAC_Instance*)calloc(1, sizeof(KMAC_Instance));
171
- if (!context->state) {
172
- sha3_kmac_free_context(context);
173
- rb_raise(_sha3_kmac_error_class, "failed to allocate state memory");
120
+ if (!context) {
121
+ rb_raise(_sha3_kmac_error_class, "failed to allocate memory");
174
122
  }
175
123
 
124
+ // Create the Ruby object with TypedData - this will automatically handle freeing
176
125
  VALUE obj = TypedData_Wrap_Struct(klass, &sha3_kmac_data_type_t, context);
177
- context->output_length = 0; // Default output length in bits
178
- context->algorithm = KMAC_128; // Default algorithm
179
126
 
180
127
  return obj;
181
128
  }
@@ -193,7 +140,7 @@ static VALUE rb_sha3_kmac_alloc(VALUE klass) {
193
140
  * - :kmac_256
194
141
  *
195
142
  * +output_length+::
196
- * The length of the output in bytes.
143
+ * The length of the output in bytes. Set to 0 for an arbitrarily-long output using "squeeze" (XOF) methods.
197
144
  *
198
145
  * +key+::
199
146
  * The key to use for the KMAC.
@@ -204,47 +151,63 @@ static VALUE rb_sha3_kmac_alloc(VALUE klass) {
204
151
  * = example
205
152
  * SHA3::KMAC.new(:kmac_128, 32, "key")
206
153
  * SHA3::KMAC.new(:kmac_256, 64, "key", "customization")
154
+ * SHA3::KMAC.new(:kmac_128, 0, "key", "customization")
155
+ *
207
156
  */
208
- static VALUE rb_sha3_kmac_init(int argc, VALUE* argv, VALUE self) {
209
- sha3_kmac_context_t* context;
157
+ static VALUE rb_sha3_kmac_init(int argc, VALUE *argv, VALUE self) {
210
158
  VALUE algorithm, output_length, key, customization;
211
159
 
212
160
  rb_scan_args(argc, argv, "31", &algorithm, &output_length, &key, &customization);
213
161
 
214
- get_sha3_kmac_context(self, &context);
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);
215
177
 
216
- ID sym = SYM2ID(algorithm);
217
- if (rb_equal(sym, _kmac_128_id)) {
218
- context->algorithm = KMAC_128;
219
- } else if (rb_equal(sym, _kmac_256_id)) {
220
- context->algorithm = KMAC_256;
178
+ if (!NIL_P(customization)) {
179
+ StringValue(customization);
221
180
  } else {
222
- rb_raise(_sha3_kmac_error_class, "invalid algorithm");
181
+ customization = rb_str_new2("");
223
182
  }
224
183
 
225
- if (!NIL_P(output_length)) {
226
- Check_Type(output_length, T_FIXNUM);
227
- context->output_length = NUM2ULONG(output_length) * 8;
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));
228
199
  }
229
200
 
230
- if (!NIL_P(key)) {
231
- Check_Type(key, T_STRING);
232
- size_t key_len = RSTRING_LEN(key) * 8;
233
- const unsigned char* key_ptr = (const unsigned char*)RSTRING_PTR(key);
234
-
235
- if (context->algorithm == KMAC_128) {
236
- if (KMAC128_Initialize(context->state, key_ptr, key_len, context->output_length,
237
- NIL_P(customization) ? NULL : (const unsigned char*)RSTRING_PTR(customization),
238
- NIL_P(customization) ? 0 : RSTRING_LEN(customization) * 8) != 0) {
239
- rb_raise(_sha3_kmac_error_class, "failed to initialize KMAC128");
240
- }
241
- } else {
242
- if (KMAC256_Initialize(context->state, key_ptr, key_len, context->output_length,
243
- NIL_P(customization) ? NULL : (const unsigned char*)RSTRING_PTR(customization),
244
- NIL_P(customization) ? 0 : RSTRING_LEN(customization) * 8) != 0) {
245
- rb_raise(_sha3_kmac_error_class, "failed to initialize KMAC256");
246
- }
247
- }
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);
248
211
  }
249
212
 
250
213
  return self;
@@ -252,9 +215,9 @@ static VALUE rb_sha3_kmac_init(int argc, VALUE* argv, VALUE self) {
252
215
 
253
216
  /*
254
217
  * :call-seq:
255
- * initialize_copy(other) -> kmac
218
+ * ::copy(other) -> kmac
256
219
  *
257
- * Initializes the KMAC with the state of another KMAC.
220
+ * Creates a copy of the KMAC instance.
258
221
  *
259
222
  * +other+::
260
223
  * The KMAC to copy the state from.
@@ -263,8 +226,7 @@ static VALUE rb_sha3_kmac_init(int argc, VALUE* argv, VALUE self) {
263
226
  * new_kmac = kmac.dup
264
227
  */
265
228
  static VALUE rb_sha3_kmac_copy(VALUE self, VALUE other) {
266
- sha3_kmac_context_t* context;
267
- sha3_kmac_context_t* other_context;
229
+ sha3_kmac_context_t *context, *other_context;
268
230
 
269
231
  rb_check_frozen(self);
270
232
  if (self == other) {
@@ -276,16 +238,15 @@ static VALUE rb_sha3_kmac_copy(VALUE self, VALUE other) {
276
238
  rb_class2name(_sha3_kmac_class));
277
239
  }
278
240
 
279
- safe_get_sha3_kmac_context(other, &other_context);
280
- get_sha3_kmac_context(self, &context);
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);
281
243
 
282
- context->algorithm = other_context->algorithm;
283
- context->output_length = other_context->output_length;
284
- memcpy(context->state, other_context->state, sizeof(KMAC_Instance));
244
+ // Copy the base context attributes
245
+ context->base.functions = other_context->base.functions;
246
+ context->base.output_length = other_context->base.output_length;
285
247
 
286
- if (!compare_contexts(context, other_context)) {
287
- rb_raise(_sha3_kmac_error_class, "failed to copy state");
288
- }
248
+ // Copy the algorithm-specific state
249
+ memcpy(context->base.state, other_context->base.state, context->base.functions->state_size);
289
250
 
290
251
  return self;
291
252
  }
@@ -304,89 +265,48 @@ static VALUE rb_sha3_kmac_copy(VALUE self, VALUE other) {
304
265
  * kmac << "more data" # alias for update
305
266
  */
306
267
  static VALUE rb_sha3_kmac_update(VALUE self, VALUE data) {
307
- sha3_kmac_context_t* context;
308
- size_t data_len;
309
-
310
- Check_Type(data, T_STRING);
311
- data_len = RSTRING_LEN(data) * 8;
312
-
313
- get_sha3_kmac_context(self, &context);
314
-
315
- if (context->algorithm == KMAC_128) {
316
- if (KMAC128_Update(context->state, (const BitSequence*)RSTRING_PTR(data), data_len) != 0) {
317
- rb_raise(_sha3_kmac_error_class, "failed to update KMAC128");
318
- }
319
- } else {
320
- if (KMAC256_Update(context->state, (const BitSequence*)RSTRING_PTR(data), data_len) != 0) {
321
- rb_raise(_sha3_kmac_error_class, "failed to update KMAC256");
322
- }
323
- }
268
+ sp800_185_context_t *context;
269
+ get_kmac_context(self, &context);
270
+ sp800_185_update(context, data);
324
271
 
325
272
  return self;
326
273
  }
327
274
 
328
275
  /*
329
276
  * :call-seq:
330
- * finish([message]) -> String
331
- *
332
- * Returns the final KMAC as a binary string.
277
+ * name -> String
333
278
  *
334
- * +message+::
335
- * _optional_ Output buffer to receive the final KMAC value.
279
+ * Returns the name of the algorithm.
336
280
  *
337
281
  * = example
338
- * kmac.finish
282
+ * kmac.name #=> "KMAC128" or "KMAC256"
339
283
  */
340
- static VALUE rb_sha3_kmac_finish(int argc, VALUE* argv, VALUE self) {
341
- sha3_kmac_context_t* context;
342
- VALUE output;
343
-
344
- rb_scan_args(argc, argv, "01", &output);
345
-
346
- get_sha3_kmac_context(self, &context);
347
-
348
- if (NIL_P(output)) {
349
- output = rb_str_new(0, context->output_length / 8);
350
- } else {
351
- StringValue(output);
352
- rb_str_resize(output, context->output_length / 8);
353
- }
354
-
355
- if (context->algorithm == KMAC_128) {
356
- if (KMAC128_Final(context->state, (BitSequence*)RSTRING_PTR(output)) != 0) {
357
- rb_raise(_sha3_kmac_error_class, "failed to finalize KMAC128");
358
- }
359
- } else {
360
- if (KMAC256_Final(context->state, (BitSequence*)RSTRING_PTR(output)) != 0) {
361
- rb_raise(_sha3_kmac_error_class, "failed to finalize KMAC256");
362
- }
363
- }
284
+ static VALUE rb_sha3_kmac_name(VALUE self) {
285
+ sp800_185_context_t *context;
286
+ get_kmac_context(self, &context);
364
287
 
365
- return output;
288
+ return rb_str_new2(sp800_185_name(context));
366
289
  }
367
290
 
368
291
  /*
369
292
  * :call-seq:
370
- * name -> String
293
+ * finish([message]) -> String
371
294
  *
372
- * Returns the name of the algorithm.
295
+ * Returns the final KMAC as a binary string.
296
+ *
297
+ * +message+::
298
+ * _optional_ Output buffer to receive the final KMAC value.
373
299
  *
374
300
  * = example
375
- * kmac.name #=> "KMAC128" or "KMAC256"
301
+ * kmac.finish
376
302
  */
377
- static VALUE rb_sha3_kmac_name(VALUE self) {
378
- sha3_kmac_context_t* context;
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);
379
306
 
380
- get_sha3_kmac_context(self, &context);
307
+ VALUE output = argc > 0 ? argv[0] : Qnil;
381
308
 
382
- switch (context->algorithm) {
383
- case KMAC_128:
384
- return rb_str_new2("KMAC128");
385
- case KMAC_256:
386
- return rb_str_new2("KMAC256");
387
- default:
388
- rb_raise(_sha3_kmac_error_class, "unknown algorithm");
389
- }
309
+ return sp800_185_finish(context, output);
390
310
  }
391
311
 
392
312
  /*
@@ -405,21 +325,13 @@ static VALUE rb_sha3_kmac_name(VALUE self) {
405
325
  * kmac.digest
406
326
  * kmac.digest('final chunk')
407
327
  */
408
- static VALUE rb_sha3_kmac_digest(int argc, VALUE* argv, VALUE self) {
409
- VALUE copy, data;
410
-
411
- rb_scan_args(argc, argv, "01", &data);
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);
412
331
 
413
- // Create a copy of the instance to avoid modifying the original
414
- copy = rb_obj_clone(self);
332
+ VALUE data = argc > 0 ? argv[0] : Qnil;
415
333
 
416
- // If data is provided, update the copy's state
417
- if (!NIL_P(data)) {
418
- rb_sha3_kmac_update(copy, data);
419
- }
420
-
421
- // Call finish on the copy
422
- return rb_sha3_kmac_finish(0, NULL, copy);
334
+ return sp800_185_digest(context, data);
423
335
  }
424
336
 
425
337
  /*
@@ -438,9 +350,55 @@ static VALUE rb_sha3_kmac_digest(int argc, VALUE* argv, VALUE self) {
438
350
  * kmac.hexdigest
439
351
  * kmac.hexdigest('final chunk')
440
352
  */
441
- static VALUE rb_sha3_kmac_hexdigest(int argc, VALUE* argv, VALUE self) {
442
- VALUE bin_str = rb_sha3_kmac_digest(argc, argv, self);
443
- return rb_funcall(bin_str, rb_intern("unpack1"), 1, rb_str_new2("H*"));
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);
444
402
  }
445
403
 
446
404
  /*
@@ -464,12 +422,18 @@ static VALUE rb_sha3_kmac_hexdigest(int argc, VALUE* argv, VALUE self) {
464
422
  * SHA3::KMAC.digest(:kmac_128, "data", 32, "key")
465
423
  * SHA3::KMAC.digest(:kmac_128, "data", 32, "key", "customization")
466
424
  */
467
- static VALUE rb_sha3_kmac_self_digest(int argc, VALUE* argv, VALUE klass) {
425
+ static VALUE rb_sha3_kmac_self_digest(int argc, VALUE *argv, VALUE klass) {
468
426
  VALUE algorithm, data, output_length, key, customization;
469
427
 
470
428
  rb_scan_args(argc, argv, "41", &algorithm, &data, &output_length, &key, &customization);
471
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
+
472
435
  VALUE kmac = rb_funcall(klass, rb_intern("new"), 4, algorithm, output_length, key, customization);
436
+
473
437
  return rb_funcall(kmac, rb_intern("digest"), 1, data);
474
438
  }
475
439
 
@@ -494,11 +458,17 @@ static VALUE rb_sha3_kmac_self_digest(int argc, VALUE* argv, VALUE klass) {
494
458
  * SHA3::KMAC.hexdigest(:kmac_128, "data", 32, "key")
495
459
  * SHA3::KMAC.hexdigest(:kmac_128, "data", 32, "key", "customization")
496
460
  */
497
- static VALUE rb_sha3_kmac_self_hexdigest(int argc, VALUE* argv, VALUE klass) {
461
+ static VALUE rb_sha3_kmac_self_hexdigest(int argc, VALUE *argv, VALUE klass) {
498
462
  VALUE algorithm, data, output_length, key, customization;
499
463
 
500
464
  rb_scan_args(argc, argv, "41", &algorithm, &data, &output_length, &key, &customization);
501
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
+
502
471
  VALUE kmac = rb_funcall(klass, rb_intern("new"), 4, algorithm, output_length, key, customization);
472
+
503
473
  return rb_funcall(kmac, rb_intern("hexdigest"), 1, data);
504
474
  }
data/ext/sha3/kmac.h CHANGED
@@ -1,5 +1,5 @@
1
- #ifndef _KMAC_H_
2
- #define _KMAC_H_
1
+ #ifndef _SHA3_KMAC_H_
2
+ #define _SHA3_KMAC_H_
3
3
 
4
4
  #ifdef __cplusplus
5
5
  extern "C" {
@@ -11,4 +11,4 @@ extern void Init_sha3_kmac(void);
11
11
  }
12
12
  #endif
13
13
 
14
- #endif // _KMAC_H_
14
+ #endif // _SHA3_KMAC_H_
data/ext/sha3/sha3.c CHANGED
@@ -1,5 +1,6 @@
1
1
  #include "sha3.h"
2
2
 
3
+ #include "cshake.h"
3
4
  #include "digest.h"
4
5
  #include "kmac.h"
5
6
 
@@ -17,14 +18,17 @@ void Init_sha3_ext(void) {
17
18
  *
18
19
  * == Classes
19
20
  * SHA3::Digest
20
- * SHA3::Digest::DigestError
21
+ * SHA3::Digest::Error
21
22
  * SHA3::KMAC
22
- * SHA3::KMAC::KMACError
23
+ * SHA3::KMAC::Error
24
+ * SHA3::CSHAKE
25
+ * SHA3::CSHAKE::Error
23
26
  *
24
27
  */
25
28
  _sha3_module = rb_define_module("SHA3");
26
29
 
27
30
  Init_sha3_digest();
31
+ Init_sha3_cshake();
28
32
  Init_sha3_kmac();
29
33
 
30
34
  return;