sha3 2.2.2 → 2.2.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d5da48a8f70ea2746484300e05125b21ab1fcd5837d0f194d8b12fac46a46602
4
- data.tar.gz: 7be8cf46c2e1e4bc38dedb64b25654f70806d6c761427b062c171bf0df359caa
3
+ metadata.gz: 9efe4158e87ea949852977b7791cf56838a9fefdbe226ebf7fdb4c5e962e927b
4
+ data.tar.gz: 6f41a24a48b714a33f846e6458aad350be5168f33202c51a95bda7a364cffc5f
5
5
  SHA512:
6
- metadata.gz: 57e70a0c38eb04f0aab1fe81f0c3ee60a6eb2bc7ea6c6f2e57f8712f23084139bd4a494cde70ad99eca7e20fe1534adb7f91b9986a4ad31ac1127ffa4a115d07
7
- data.tar.gz: 0b7cdd43dc7167e3e92f4ec2adfb947c00f0b8827aaaeafb9383213bdd1bc09771c0b17efec3d28667b1bb383646f006360496abf3dfd43a2a6cd54f8e1dd4c2
6
+ metadata.gz: 21086756d157c20bd8f74fde996cabfc8c2a8975b913cab0da03a311d41eb3d44427e344419344e7d8729b21edf0c1d550732c583df8a1f2797b700b64468464
7
+ data.tar.gz: fd6dacfcb827ecbdf8d3d60cd1b9dfacd6f50fc9c4440100890fbac7302d26f8119da33f95b67c270c73b6f75789a7b5e569e04c638a834dce9ff99a5b2050a7
checksums.yaml.gz.sig CHANGED
Binary file
data/.rubocop.yml CHANGED
@@ -6,8 +6,74 @@ AllCops:
6
6
  NewCops: enable
7
7
  TargetRubyVersion: 2.7
8
8
 
9
+ Exclude:
10
+ - ext/**/*.rb
11
+
9
12
  Layout/LineLength:
10
13
  Max: 120
11
14
 
15
+ # Metrics
16
+
17
+ Metrics/AbcSize:
18
+ Exclude:
19
+ - spec/**/*_spec.rb
20
+
21
+ Metrics/CyclomaticComplexity:
22
+ Exclude:
23
+ - spec/**/*_spec.rb
24
+
25
+ Metrics/PerceivedComplexity:
26
+ Exclude:
27
+ - spec/**/*_spec.rb
28
+
29
+ Metrics/MethodLength:
30
+ Max: 15
31
+ Exclude:
32
+ - spec/**/*_spec.rb
33
+
34
+ # Naming
35
+
36
+ Naming/ClassAndModuleCamelCase:
37
+ Enabled: false
38
+
12
39
  Naming/VariableNumber:
13
40
  EnforcedStyle: snake_case
41
+ Exclude:
42
+ - spec/**/*.rb
43
+
44
+ # Security
45
+
46
+ # Allow URI.open for test vector downloads
47
+ Security/Open:
48
+ Exclude:
49
+ - spec/sha3_digest_vectors_spec.rb
50
+
51
+ # RSpec configuration
52
+
53
+ RSpec/ExampleLength:
54
+ Max: 15
55
+ CountAsOne:
56
+ - array
57
+ - hash
58
+ - heredoc
59
+
60
+ RSpec/MultipleExpectations:
61
+ Max: 8
62
+
63
+ RSpec/SpecFilePathFormat:
64
+ Enabled: false
65
+
66
+ RSpec/LeakyConstantDeclaration:
67
+ Enabled: false
68
+
69
+ RSpec/BeforeAfterAll:
70
+ Enabled: false
71
+
72
+ RSpec/MultipleDescribes:
73
+ Enabled: false
74
+
75
+ RSpec/NamedSubject:
76
+ Enabled: false
77
+
78
+ RSpec/DescribeClass:
79
+ Enabled: false
data/ext/sha3/common.h ADDED
@@ -0,0 +1,118 @@
1
+ // Copyright (c) 2025 Johanns Gregorian <io+sha3@jsg.io>
2
+
3
+ #ifndef _SHA3_COMMON_H_
4
+ #define _SHA3_COMMON_H_
5
+
6
+ #include <ruby.h>
7
+
8
+ #include "sp800_185.h"
9
+
10
+ #ifdef __cplusplus
11
+ extern "C" {
12
+ #endif
13
+
14
+ /* Common macros for SP800-185 based implementations (CSHAKE, KMAC) */
15
+
16
+ /* Define a simple method that just calls an sp800_185 function */
17
+ #define DEFINE_SP800_185_SIMPLE_METHOD(method_name, sp_func, get_ctx_func) \
18
+ static VALUE method_name(VALUE self, VALUE data) { \
19
+ sp800_185_context_t *context; \
20
+ get_ctx_func(self, &context); \
21
+ sp_func(context, data); \
22
+ return self; \
23
+ }
24
+
25
+ /* Define a method that returns a value from sp800_185 function */
26
+ #define DEFINE_SP800_185_RETURN_METHOD(method_name, sp_func, get_ctx_func) \
27
+ static VALUE method_name(VALUE self) { \
28
+ sp800_185_context_t *context; \
29
+ get_ctx_func(self, &context); \
30
+ return sp_func(context); \
31
+ }
32
+
33
+ /* Define a method with single VALUE parameter that returns VALUE */
34
+ #define DEFINE_SP800_185_VALUE_METHOD(method_name, sp_func, get_ctx_func) \
35
+ static VALUE method_name(VALUE self, VALUE param) { \
36
+ sp800_185_context_t *context; \
37
+ get_ctx_func(self, &context); \
38
+ return sp_func(context, param); \
39
+ }
40
+
41
+ /* Define a method with variable arguments */
42
+ #define DEFINE_SP800_185_VARARGS_METHOD(method_name, sp_func, get_ctx_func) \
43
+ static VALUE method_name(int argc, VALUE *argv, VALUE self) { \
44
+ sp800_185_context_t *context; \
45
+ get_ctx_func(self, &context); \
46
+ VALUE param = argc > 0 ? argv[0] : Qnil; \
47
+ return sp_func(context, param); \
48
+ }
49
+
50
+ /* Define common memory management functions */
51
+ #define DEFINE_SP800_185_MEMORY_FUNCS(prefix, context_type) \
52
+ static void prefix##_free_context(void *ptr) { sp800_185_free_context((sp800_185_context_t *)ptr); } \
53
+ \
54
+ static size_t prefix##_context_size(const void *ptr) { \
55
+ return sp800_185_context_size((const sp800_185_context_t *)ptr, sizeof(context_type)); \
56
+ }
57
+
58
+ /* Define common allocation function */
59
+ #define DEFINE_SP800_185_ALLOC(prefix, context_type, instance_type, error_class) \
60
+ static VALUE rb_##prefix##_alloc(VALUE klass) { \
61
+ context_type *context = (context_type *)sp800_185_alloc_context(sizeof(context_type), sizeof(instance_type)); \
62
+ \
63
+ if (!context) { \
64
+ rb_raise(error_class, "failed to allocate memory"); \
65
+ } \
66
+ \
67
+ VALUE obj = TypedData_Wrap_Struct(klass, &prefix##_data_type, context); \
68
+ return obj; \
69
+ }
70
+
71
+ /* Define common copy method */
72
+ #define DEFINE_SP800_185_COPY_METHOD(method_name, context_type, data_type, class_var) \
73
+ static VALUE method_name(VALUE self, VALUE other) { \
74
+ context_type *context, *other_context; \
75
+ \
76
+ rb_check_frozen(self); \
77
+ if (self == other) { \
78
+ return self; \
79
+ } \
80
+ \
81
+ if (!rb_obj_is_kind_of(other, class_var)) { \
82
+ rb_raise(rb_eTypeError, "wrong argument (%s)! (expected %s)", rb_obj_classname(other), \
83
+ rb_class2name(class_var)); \
84
+ } \
85
+ \
86
+ TypedData_Get_Struct(other, context_type, &data_type, other_context); \
87
+ TypedData_Get_Struct(self, context_type, &data_type, context); \
88
+ \
89
+ /* Copy the base context attributes */ \
90
+ context->base.functions = other_context->base.functions; \
91
+ context->base.output_length = other_context->base.output_length; \
92
+ context->base.error_class = other_context->base.error_class; \
93
+ \
94
+ /* Copy the algorithm-specific state */ \
95
+ if (context->base.functions && other_context->base.state) { \
96
+ memcpy(context->base.state, other_context->base.state, context->base.functions->state_size); \
97
+ } \
98
+ \
99
+ return self; \
100
+ }
101
+
102
+ /* Ruby wrapper functions for SP800-185 operations */
103
+ VALUE sp800_185_rb_update(sp800_185_context_t *context, VALUE data);
104
+ VALUE sp800_185_rb_name(sp800_185_context_t *context);
105
+ VALUE sp800_185_rb_finish(sp800_185_context_t *context, VALUE output);
106
+ VALUE sp800_185_rb_digest(sp800_185_context_t *context, VALUE data);
107
+ VALUE sp800_185_rb_hexdigest(sp800_185_context_t *context, VALUE data);
108
+ VALUE sp800_185_rb_squeeze(sp800_185_context_t *context, VALUE length);
109
+ VALUE sp800_185_rb_hex_squeeze(sp800_185_context_t *context, VALUE length);
110
+
111
+ /* Helper function to register common methods */
112
+ void register_sp800_185_common_methods(VALUE klass);
113
+
114
+ #ifdef __cplusplus
115
+ }
116
+ #endif
117
+
118
+ #endif /* _SHA3_COMMON_H_ */
data/ext/sha3/cshake.c CHANGED
@@ -1,5 +1,6 @@
1
1
  #include "cshake.h"
2
2
 
3
+ #include "common.h"
3
4
  #include "sha3.h"
4
5
  #include "sp800_185.h"
5
6
 
@@ -76,7 +77,7 @@ void Init_sha3_cshake(void) {
76
77
  /*
77
78
  * Document-class: SHA3::CSHAKE::Error
78
79
  *
79
- * All KMAC methods raise this exception on error.
80
+ * All CSHAKE methods raise this exception on error.
80
81
  *
81
82
  * It is a subclass of the StandardError class -- see the Ruby documentation
82
83
  * for more information.
@@ -104,25 +105,11 @@ void Init_sha3_cshake(void) {
104
105
  return;
105
106
  }
106
107
 
107
- static void sha3_cshake_free_context(void *ptr) { sp800_185_free_context((sp800_185_context_t *)ptr); }
108
+ /* Use common memory management functions */
109
+ DEFINE_SP800_185_MEMORY_FUNCS(sha3_cshake, sha3_cshake_context_t)
108
110
 
109
- static size_t sha3_cshake_context_size(const void *ptr) {
110
- return sp800_185_context_size((const sp800_185_context_t *)ptr, sizeof(sha3_cshake_context_t));
111
- }
112
-
113
- static VALUE rb_sha3_cshake_alloc(VALUE klass) {
114
- sha3_cshake_context_t *context =
115
- (sha3_cshake_context_t *)sp800_185_alloc_context(sizeof(sha3_cshake_context_t), sizeof(cSHAKE_Instance));
116
-
117
- if (!context) {
118
- rb_raise(_sha3_cshake_error_class, "failed to allocate memory");
119
- }
120
-
121
- // Create the Ruby object with TypedData - this will automatically handle freeing
122
- VALUE obj = TypedData_Wrap_Struct(klass, &sha3_cshake_data_type, context);
123
-
124
- return obj;
125
- }
111
+ /* Use common allocation function */
112
+ DEFINE_SP800_185_ALLOC(sha3_cshake, sha3_cshake_context_t, cSHAKE_Instance, _sha3_cshake_error_class)
126
113
 
127
114
  /*
128
115
  * :call-seq:
@@ -144,14 +131,14 @@ static VALUE rb_sha3_cshake_alloc(VALUE klass) {
144
131
  * _optional_ The customization string to use
145
132
  *
146
133
  * = example
147
- * # Initialize instance for fix-ed-length operation
134
+ * # Initialize instance for fixed-length operation
148
135
  * cshake = SHA3::CSHAKE.new(:cshake_128, 32, name: 'my-app')
149
136
  * cshake << 'data...'
150
137
  * cshake.hexdigest
151
138
  *
152
139
  * # Initialize instance for XOF operation (arbitrary-long output)
153
140
  * cshake = SHA3::CSHAKE.new(:cshake_256, 0, customization: 'Email Signature')
154
- * cshask.update('data...')
141
+ * cshake.update('data...')
155
142
  * cshake.squeeze(64)
156
143
  */
157
144
  static VALUE rb_sha3_cshake_init(int argc, VALUE *argv, VALUE self) {
@@ -233,31 +220,7 @@ static VALUE rb_sha3_cshake_init(int argc, VALUE *argv, VALUE self) {
233
220
  * = example
234
221
  * cshake2 = cshake.dup
235
222
  */
236
- static VALUE rb_sha3_cshake_copy(VALUE self, VALUE other) {
237
- sha3_cshake_context_t *context, *other_context;
238
-
239
- rb_check_frozen(self);
240
- if (self == other) {
241
- return self;
242
- }
243
-
244
- if (!rb_obj_is_kind_of(other, _sha3_cshake_class)) {
245
- rb_raise(rb_eTypeError, "wrong argument (%s)! (expected %s)", rb_obj_classname(other),
246
- rb_class2name(_sha3_cshake_class));
247
- }
248
-
249
- TypedData_Get_Struct(other, sha3_cshake_context_t, &sha3_cshake_data_type, other_context);
250
- TypedData_Get_Struct(self, sha3_cshake_context_t, &sha3_cshake_data_type, context);
251
-
252
- // Copy the base context attributes
253
- context->base.functions = other_context->base.functions;
254
- context->base.output_length = other_context->base.output_length;
255
-
256
- // Copy the algorithm-specific state
257
- memcpy(context->base.state, other_context->base.state, context->base.functions->state_size);
258
-
259
- return self;
260
- }
223
+ DEFINE_SP800_185_COPY_METHOD(rb_sha3_cshake_copy, sha3_cshake_context_t, sha3_cshake_data_type, _sha3_cshake_class)
261
224
 
262
225
  /*
263
226
  * :call-seq:
@@ -272,13 +235,7 @@ static VALUE rb_sha3_cshake_copy(VALUE self, VALUE other) {
272
235
  * cshake.update("more data")
273
236
  * cshake << "more data" # alias for update
274
237
  */
275
- static VALUE rb_sha3_cshake_update(VALUE self, VALUE data) {
276
- sp800_185_context_t *context;
277
- get_cshake_context(self, &context);
278
- sp800_185_update(context, data);
279
-
280
- return self;
281
- }
238
+ DEFINE_SP800_185_SIMPLE_METHOD(rb_sha3_cshake_update, sp800_185_rb_update, get_cshake_context)
282
239
 
283
240
  /*
284
241
  * :call-seq:
@@ -286,12 +243,7 @@ static VALUE rb_sha3_cshake_update(VALUE self, VALUE data) {
286
243
  *
287
244
  * Returns the name of the CSHAKE instance.
288
245
  */
289
- static VALUE rb_sha3_cshake_name(VALUE self) {
290
- sp800_185_context_t *context;
291
- get_cshake_context(self, &context);
292
-
293
- return rb_str_new2(sp800_185_name(context));
294
- }
246
+ DEFINE_SP800_185_RETURN_METHOD(rb_sha3_cshake_name, sp800_185_rb_name, get_cshake_context)
295
247
 
296
248
  /*
297
249
  * :call-seq:
@@ -305,13 +257,7 @@ static VALUE rb_sha3_cshake_name(VALUE self) {
305
257
  * = example
306
258
  * cshake.finish
307
259
  */
308
- static VALUE rb_sha3_cshake_finish(int argc, VALUE *argv, VALUE self) {
309
- sp800_185_context_t *context;
310
- get_cshake_context(self, &context);
311
-
312
- VALUE output = argc > 0 ? argv[0] : Qnil;
313
- return sp800_185_finish(context, output);
314
- }
260
+ DEFINE_SP800_185_VARARGS_METHOD(rb_sha3_cshake_finish, sp800_185_rb_finish, get_cshake_context)
315
261
 
316
262
  /*
317
263
  * :call-seq:
@@ -326,14 +272,7 @@ static VALUE rb_sha3_cshake_finish(int argc, VALUE *argv, VALUE self) {
326
272
  * cshake.digest
327
273
  * cshake.digest("final chunk")
328
274
  */
329
- static VALUE rb_sha3_cshake_digest(int argc, VALUE *argv, VALUE self) {
330
- sp800_185_context_t *context;
331
- get_cshake_context(self, &context);
332
-
333
- VALUE data = argc > 0 ? argv[0] : Qnil;
334
-
335
- return sp800_185_digest(context, data);
336
- }
275
+ DEFINE_SP800_185_VARARGS_METHOD(rb_sha3_cshake_digest, sp800_185_rb_digest, get_cshake_context)
337
276
 
338
277
  /*
339
278
  * :call-seq:
@@ -348,14 +287,7 @@ static VALUE rb_sha3_cshake_digest(int argc, VALUE *argv, VALUE self) {
348
287
  * cshake.hexdigest
349
288
  * cshake.hexdigest("final chunk")
350
289
  */
351
- static VALUE rb_sha3_cshake_hexdigest(int argc, VALUE *argv, VALUE self) {
352
- sp800_185_context_t *context;
353
- get_cshake_context(self, &context);
354
-
355
- VALUE data = argc > 0 ? argv[0] : Qnil;
356
-
357
- return sp800_185_hexdigest(context, data);
358
- }
290
+ DEFINE_SP800_185_VARARGS_METHOD(rb_sha3_cshake_hexdigest, sp800_185_rb_hexdigest, get_cshake_context)
359
291
 
360
292
  /*
361
293
  * :call-seq:
@@ -369,12 +301,7 @@ static VALUE rb_sha3_cshake_hexdigest(int argc, VALUE *argv, VALUE self) {
369
301
  * = example
370
302
  * cshake.squeeze(32)
371
303
  */
372
- static VALUE rb_sha3_cshake_squeeze(VALUE self, VALUE length) {
373
- sp800_185_context_t *context;
374
- get_cshake_context(self, &context);
375
-
376
- return sp800_185_squeeze(context, length);
377
- }
304
+ DEFINE_SP800_185_VALUE_METHOD(rb_sha3_cshake_squeeze, sp800_185_rb_squeeze, get_cshake_context)
378
305
 
379
306
  /*
380
307
  * :call-seq:
@@ -388,9 +315,4 @@ static VALUE rb_sha3_cshake_squeeze(VALUE self, VALUE length) {
388
315
  * = example
389
316
  * cshake.hex_squeeze(32)
390
317
  */
391
- static VALUE rb_sha3_cshake_hex_squeeze(VALUE self, VALUE length) {
392
- sp800_185_context_t *context;
393
- get_cshake_context(self, &context);
394
-
395
- return sp800_185_hex_squeeze(context, length);
396
- }
318
+ DEFINE_SP800_185_VALUE_METHOD(rb_sha3_cshake_hex_squeeze, sp800_185_rb_hex_squeeze, get_cshake_context)
data/ext/sha3/digest.c CHANGED
@@ -79,15 +79,16 @@ static ID _shake_128_id;
79
79
  static ID _shake_256_id;
80
80
 
81
81
  /* TypedData structure for sha3_digest_context_t */
82
- const rb_data_type_t sha3_digest_data_type_t = {"SHA3::Digest",
83
- {
84
- NULL,
85
- sha3_digest_free_context,
86
- sha3_digest_context_size,
87
- },
88
- NULL,
89
- NULL,
90
- RUBY_TYPED_FREE_IMMEDIATELY};
82
+ const rb_data_type_t sha3_digest_data_type = {"SHA3::Digest",
83
+ {
84
+ NULL,
85
+ sha3_digest_free_context,
86
+ sha3_digest_context_size,
87
+ NULL,
88
+ },
89
+ NULL,
90
+ NULL,
91
+ RUBY_TYPED_FREE_IMMEDIATELY};
91
92
 
92
93
  void Init_sha3_digest(void) {
93
94
  rb_require("digest");
@@ -154,10 +155,14 @@ void Init_sha3_digest(void) {
154
155
 
155
156
  // Static inline functions replacing macros
156
157
  static inline void get_sha3_digest_context(VALUE obj, sha3_digest_context_t **context) {
157
- TypedData_Get_Struct((obj), sha3_digest_context_t, &sha3_digest_data_type_t, (*context));
158
+ TypedData_Get_Struct((obj), sha3_digest_context_t, &sha3_digest_data_type, (*context));
158
159
  if (!(*context)) {
159
160
  rb_raise(rb_eRuntimeError, "Digest data not initialized!");
160
161
  }
162
+
163
+ if (!(*context)->state) {
164
+ rb_raise(rb_eRuntimeError, "Digest state not initialized!");
165
+ }
161
166
  }
162
167
 
163
168
  static inline void safe_get_sha3_digest_context(VALUE obj, sha3_digest_context_t **context) {
@@ -170,36 +175,36 @@ static inline void safe_get_sha3_digest_context(VALUE obj, sha3_digest_context_t
170
175
 
171
176
  static inline int is_shake_algorithm(sha3_digest_algorithms alg) { return alg == SHAKE_128 || alg == SHAKE_256; }
172
177
 
173
- int get_hashbit_length(VALUE obj, sha3_digest_algorithms *algorithm) {
174
- if (TYPE(obj) == T_SYMBOL) {
175
- ID symid = SYM2ID(obj);
176
-
177
- if (symid == _sha3_224_id) {
178
- *algorithm = SHA3_224;
179
- return 224;
180
- } else if (symid == _sha3_256_id) {
181
- *algorithm = SHA3_256;
182
- return 256;
183
- } else if (symid == _sha3_384_id) {
184
- *algorithm = SHA3_384;
185
- return 384;
186
- } else if (symid == _sha3_512_id) {
187
- *algorithm = SHA3_512;
188
- return 512;
189
- } else if (symid == _shake_128_id) {
190
- *algorithm = SHAKE_128;
191
- return 128;
192
- } else if (symid == _shake_256_id) {
193
- *algorithm = SHAKE_256;
194
- return 256;
195
- }
196
-
197
- rb_raise(rb_eArgError,
198
- "invalid hash algorithm symbol (should be: :sha3_224, "
199
- ":sha3_256, :sha3_384, :sha3_512, :shake_128, or :shake_256)");
200
- }
201
-
202
- rb_raise(_sha3_digest_error_class, "unknown type value");
178
+ static int get_hashbit_length(VALUE obj, sha3_digest_algorithms *algorithm) {
179
+ if (TYPE(obj) != T_SYMBOL) {
180
+ rb_raise(_sha3_digest_error_class, "hash algorithm must be a symbol");
181
+ }
182
+
183
+ ID symid = SYM2ID(obj);
184
+
185
+ if (symid == _sha3_224_id) {
186
+ *algorithm = SHA3_224;
187
+ return 224;
188
+ } else if (symid == _sha3_256_id) {
189
+ *algorithm = SHA3_256;
190
+ return 256;
191
+ } else if (symid == _sha3_384_id) {
192
+ *algorithm = SHA3_384;
193
+ return 384;
194
+ } else if (symid == _sha3_512_id) {
195
+ *algorithm = SHA3_512;
196
+ return 512;
197
+ } else if (symid == _shake_128_id) {
198
+ *algorithm = SHAKE_128;
199
+ return 128;
200
+ } else if (symid == _shake_256_id) {
201
+ *algorithm = SHAKE_256;
202
+ return 256;
203
+ }
204
+
205
+ rb_raise(rb_eArgError,
206
+ "invalid hash algorithm symbol (should be: :sha3_224, "
207
+ ":sha3_256, :sha3_384, :sha3_512, :shake_128, or :shake_256)");
203
208
 
204
209
  return 0; // Never reached, but silences compiler warnings
205
210
  }
@@ -208,9 +213,10 @@ static void sha3_digest_free_context(void *ptr) {
208
213
  sha3_digest_context_t *context = (sha3_digest_context_t *)ptr;
209
214
  if (context) {
210
215
  if (context->state) {
211
- free(context->state);
216
+ ruby_xfree(context->state);
217
+ context->state = NULL;
212
218
  }
213
- free(context);
219
+ ruby_xfree(context);
214
220
  }
215
221
  }
216
222
 
@@ -245,21 +251,22 @@ static HashReturn keccak_hash_initialize(sha3_digest_context_t *context) {
245
251
  }
246
252
 
247
253
  static VALUE rb_sha3_digest_alloc(VALUE klass) {
248
- sha3_digest_context_t *context = (sha3_digest_context_t *)malloc(sizeof(sha3_digest_context_t));
254
+ sha3_digest_context_t *context = RB_ALLOC(sha3_digest_context_t);
249
255
  if (!context) {
250
256
  rb_raise(_sha3_digest_error_class, "failed to allocate object memory");
251
257
  }
252
258
 
253
- context->state = (Keccak_HashInstance *)calloc(1, sizeof(Keccak_HashInstance));
259
+ context->state = RB_ALLOC(Keccak_HashInstance);
254
260
  if (!context->state) {
255
- sha3_digest_free_context(context);
261
+ ruby_xfree(context);
256
262
  rb_raise(_sha3_digest_error_class, "failed to allocate state memory");
257
263
  }
264
+ memset(context->state, 0, sizeof(*context->state));
258
265
 
259
- VALUE obj = TypedData_Wrap_Struct(klass, &sha3_digest_data_type_t, context);
260
266
  context->hashbitlen = 0;
261
- context->algorithm = SHA3_256; // Default algorithm
267
+ context->algorithm = SHA3_256;
262
268
 
269
+ VALUE obj = TypedData_Wrap_Struct(klass, &sha3_digest_data_type, context);
263
270
  return obj;
264
271
  }
265
272
 
@@ -342,7 +349,13 @@ static VALUE rb_sha3_digest_update(VALUE self, VALUE data) {
342
349
  rb_raise(_sha3_digest_error_class, "cannot update with NULL data");
343
350
  }
344
351
 
345
- dlen = (RSTRING_LEN(data) * 8);
352
+ // Prevent integer overflow and validate size
353
+ size_t data_len = RSTRING_LEN(data);
354
+ if (data_len > SIZE_MAX / 8) {
355
+ rb_raise(_sha3_digest_error_class, "data too large (exceeds maximum size)");
356
+ }
357
+
358
+ dlen = (data_len * 8);
346
359
 
347
360
  if (Keccak_HashUpdate(context->state, (BitSequence *)RSTRING_PTR(data), dlen) != KECCAK_SUCCESS) {
348
361
  rb_raise(_sha3_digest_error_class, "failed to update hash data");
@@ -374,6 +387,10 @@ static VALUE rb_sha3_digest_reset(VALUE self) {
374
387
  }
375
388
 
376
389
  static int compare_contexts(const sha3_digest_context_t *context1, const sha3_digest_context_t *context2) {
390
+ if (!context1 || !context2 || !context1->state || !context2->state) {
391
+ return 0;
392
+ }
393
+
377
394
  // First check the hashbitlen and algorithm
378
395
  if (context1->hashbitlen != context2->hashbitlen || context1->algorithm != context2->algorithm) {
379
396
  return 0;
@@ -429,7 +446,11 @@ static VALUE rb_sha3_digest_copy(VALUE self, VALUE other) {
429
446
  }
430
447
 
431
448
  safe_get_sha3_digest_context(other, &other_context);
432
- get_sha3_digest_context(self, &context);
449
+ safe_get_sha3_digest_context(self, &context);
450
+
451
+ if (!context || !other_context) {
452
+ rb_raise(_sha3_digest_error_class, "invalid context for copy");
453
+ }
433
454
 
434
455
  context->hashbitlen = other_context->hashbitlen;
435
456
  context->algorithm = other_context->algorithm;
@@ -489,17 +510,17 @@ static VALUE rb_sha3_digest_name(VALUE self) {
489
510
 
490
511
  switch (context->algorithm) {
491
512
  case SHA3_224:
492
- return rb_str_new2("SHA3-224");
513
+ return rb_str_new_cstr("SHA3-224");
493
514
  case SHA3_256:
494
- return rb_str_new2("SHA3-256");
515
+ return rb_str_new_cstr("SHA3-256");
495
516
  case SHA3_384:
496
- return rb_str_new2("SHA3-384");
517
+ return rb_str_new_cstr("SHA3-384");
497
518
  case SHA3_512:
498
- return rb_str_new2("SHA3-512");
519
+ return rb_str_new_cstr("SHA3-512");
499
520
  case SHAKE_128:
500
- return rb_str_new2("SHAKE128");
521
+ return rb_str_new_cstr("SHAKE128");
501
522
  case SHAKE_256:
502
- return rb_str_new2("SHAKE256");
523
+ return rb_str_new_cstr("SHAKE256");
503
524
  default:
504
525
  rb_raise(_sha3_digest_error_class, "unknown algorithm");
505
526
  }
@@ -560,15 +581,19 @@ static VALUE rb_sha3_digest_finish(int argc, VALUE *argv, VALUE self) {
560
581
  static VALUE rb_sha3_digest_squeeze(VALUE self, VALUE length) {
561
582
  sha3_digest_context_t *context;
562
583
  VALUE str, copy;
563
- int output_bytes;
584
+ long output_bytes;
564
585
 
565
586
  Check_Type(length, T_FIXNUM);
566
- output_bytes = NUM2INT(length);
587
+ output_bytes = NUM2LONG(length);
567
588
 
568
589
  if (output_bytes <= 0) {
569
590
  rb_raise(_sha3_digest_error_class, "output length must be positive");
570
591
  }
571
592
 
593
+ if (output_bytes > (1L << 20)) { // Limit to 1MB output
594
+ rb_raise(_sha3_digest_error_class, "output length too large (max 1MB)");
595
+ }
596
+
572
597
  get_sha3_digest_context(self, &context);
573
598
 
574
599
  // Only SHAKE algorithms support arbitrary-length output
@@ -578,6 +603,9 @@ static VALUE rb_sha3_digest_squeeze(VALUE self, VALUE length) {
578
603
 
579
604
  // Create a copy of the digest object to avoid modifying the original
580
605
  copy = rb_obj_clone(self);
606
+ if (NIL_P(copy)) {
607
+ rb_raise(_sha3_digest_error_class, "failed to clone digest object");
608
+ }
581
609
 
582
610
  // Get the sha3_digest_context_t struct from the copy
583
611
  sha3_digest_context_t *context_copy;
@@ -615,7 +643,7 @@ static VALUE rb_sha3_digest_hex_squeeze(VALUE self, VALUE length) {
615
643
  // Get the binary output using the existing squeeze function
616
644
  VALUE bin_str = rb_sha3_digest_squeeze(self, length);
617
645
  // Use Ruby's built-in unpack method to convert to hex
618
- return rb_funcall(bin_str, rb_intern("unpack1"), 1, rb_str_new2("H*"));
646
+ return rb_funcall(bin_str, rb_intern("unpack1"), 1, rb_str_new_cstr("H*"));
619
647
  }
620
648
 
621
649
  static VALUE prepare_shake_output(VALUE self, int argc, VALUE *argv, int hex_output) {
@@ -800,32 +828,26 @@ static VALUE rb_sha3_digest_self_digest(VALUE klass, VALUE name, VALUE data) {
800
828
  * To squeeze a different length, use #hex_squeeze instance method.
801
829
  */
802
830
  static VALUE rb_sha3_digest_self_hexdigest(VALUE klass, VALUE name, VALUE data) {
803
- VALUE args[2];
831
+ VALUE digest;
804
832
 
805
- // Need to add type checking for the data parameter
806
- StringValue(data);
833
+ if (NIL_P(name) || NIL_P(data)) {
834
+ rb_raise(_sha3_digest_error_class, "algorithm name and data cannot be nil");
835
+ }
807
836
 
808
- /* For SHAKE algorithms, we need to handle them differently */
809
- if (TYPE(name) == T_SYMBOL) {
810
- ID symid = SYM2ID(name);
811
- if (symid == _shake_128_id || symid == _shake_256_id) {
812
- /* Create a new digest instance with the specified algorithm */
813
- VALUE digest = rb_class_new_instance(1, &name, klass);
837
+ if (TYPE(name) != T_SYMBOL) {
838
+ rb_raise(_sha3_digest_error_class, "algorithm name must be a symbol");
839
+ }
814
840
 
815
- /* Update it with the data */
816
- rb_sha3_digest_update(digest, data);
841
+ StringValue(data);
817
842
 
818
- /* For SHAKE algorithms, use a default output length based on the security strength */
819
- int output_length = (symid == _shake_128_id) ? 16 : 32; /* 128/8 or 256/8 */
843
+ ID symid = SYM2ID(name);
844
+ digest = rb_class_new_instance(1, &name, klass);
845
+ rb_sha3_digest_update(digest, data);
820
846
 
821
- /* Return the hexadecimal representation of the squeezed output */
822
- return rb_sha3_digest_hex_squeeze(digest, INT2NUM(output_length));
823
- }
847
+ if (symid == _shake_128_id || symid == _shake_256_id) {
848
+ int output_length = (symid == _shake_128_id) ? 16 : 32;
849
+ return rb_sha3_digest_hex_squeeze(digest, INT2NUM(output_length));
824
850
  }
825
851
 
826
- /* Call the superclass method with arguments in reverse order */
827
- args[0] = data;
828
- args[1] = name;
829
-
830
- return rb_call_super(2, args);
852
+ return rb_funcall(digest, rb_intern("hexdigest"), 0);
831
853
  }
data/ext/sha3/kmac.c CHANGED
@@ -1,5 +1,6 @@
1
1
  #include "kmac.h"
2
2
 
3
+ #include "common.h"
3
4
  #include "sha3.h"
4
5
  #include "sp800_185.h"
5
6
 
@@ -42,7 +43,7 @@ static ID _kmac_128_id;
42
43
  static ID _kmac_256_id;
43
44
 
44
45
  /* TypedData structure for sha3_kmac_context_t */
45
- const rb_data_type_t sha3_kmac_data_type_t = {
46
+ const rb_data_type_t sha3_kmac_data_type = {
46
47
  "SHA3::KMAC",
47
48
  {
48
49
  NULL, sha3_kmac_free_context, sha3_kmac_context_size, NULL, /* dcompact field */
@@ -55,7 +56,7 @@ const rb_data_type_t sha3_kmac_data_type_t = {
55
56
  // Helper function to extract context from a Ruby object
56
57
  void get_kmac_context(VALUE obj, sp800_185_context_t **context) {
57
58
  sha3_kmac_context_t *kmac_ctx;
58
- TypedData_Get_Struct(obj, sha3_kmac_context_t, &sha3_kmac_data_type_t, kmac_ctx);
59
+ TypedData_Get_Struct(obj, sha3_kmac_context_t, &sha3_kmac_data_type, kmac_ctx);
59
60
  *context = &kmac_ctx->base;
60
61
  }
61
62
 
@@ -104,25 +105,11 @@ void Init_sha3_kmac(void) {
104
105
  return;
105
106
  }
106
107
 
107
- static void sha3_kmac_free_context(void *ptr) { sp800_185_free_context((sp800_185_context_t *)ptr); }
108
+ /* Use common memory management functions */
109
+ DEFINE_SP800_185_MEMORY_FUNCS(sha3_kmac, sha3_kmac_context_t)
108
110
 
109
- static size_t sha3_kmac_context_size(const void *ptr) {
110
- return sp800_185_context_size((const sp800_185_context_t *)ptr, sizeof(sha3_kmac_context_t));
111
- }
112
-
113
- static VALUE rb_sha3_kmac_alloc(VALUE klass) {
114
- sha3_kmac_context_t *context =
115
- (sha3_kmac_context_t *)sp800_185_alloc_context(sizeof(sha3_kmac_context_t), sizeof(KMAC_Instance));
116
-
117
- if (!context) {
118
- rb_raise(_sha3_kmac_error_class, "failed to allocate memory");
119
- }
120
-
121
- // Create the Ruby object with TypedData - this will automatically handle freeing
122
- VALUE obj = TypedData_Wrap_Struct(klass, &sha3_kmac_data_type_t, context);
123
-
124
- return obj;
125
- }
111
+ /* Use common allocation function */
112
+ DEFINE_SP800_185_ALLOC(sha3_kmac, sha3_kmac_context_t, KMAC_Instance, _sha3_kmac_error_class)
126
113
 
127
114
  /*
128
115
  * :call-seq:
@@ -179,7 +166,7 @@ static VALUE rb_sha3_kmac_init(int argc, VALUE *argv, VALUE self) {
179
166
  }
180
167
 
181
168
  sha3_kmac_context_t *context;
182
- TypedData_Get_Struct(self, sha3_kmac_context_t, &sha3_kmac_data_type_t, context);
169
+ TypedData_Get_Struct(self, sha3_kmac_context_t, &sha3_kmac_data_type, context);
183
170
 
184
171
  // Store the output length in bits
185
172
  context->base.output_length = NUM2ULONG(output_length) * 8;
@@ -229,31 +216,7 @@ static VALUE rb_sha3_kmac_init(int argc, VALUE *argv, VALUE self) {
229
216
  * = example
230
217
  * new_kmac = kmac.dup
231
218
  */
232
- static VALUE rb_sha3_kmac_copy(VALUE self, VALUE other) {
233
- sha3_kmac_context_t *context, *other_context;
234
-
235
- rb_check_frozen(self);
236
- if (self == other) {
237
- return self;
238
- }
239
-
240
- if (!rb_obj_is_kind_of(other, _sha3_kmac_class)) {
241
- rb_raise(rb_eTypeError, "wrong argument (%s)! (expected %s)", rb_obj_classname(other),
242
- rb_class2name(_sha3_kmac_class));
243
- }
244
-
245
- TypedData_Get_Struct(other, sha3_kmac_context_t, &sha3_kmac_data_type_t, other_context);
246
- TypedData_Get_Struct(self, sha3_kmac_context_t, &sha3_kmac_data_type_t, context);
247
-
248
- // Copy the base context attributes
249
- context->base.functions = other_context->base.functions;
250
- context->base.output_length = other_context->base.output_length;
251
-
252
- // Copy the algorithm-specific state
253
- memcpy(context->base.state, other_context->base.state, context->base.functions->state_size);
254
-
255
- return self;
256
- }
219
+ DEFINE_SP800_185_COPY_METHOD(rb_sha3_kmac_copy, sha3_kmac_context_t, sha3_kmac_data_type, _sha3_kmac_class)
257
220
 
258
221
  /*
259
222
  * :call-seq:
@@ -268,13 +231,7 @@ static VALUE rb_sha3_kmac_copy(VALUE self, VALUE other) {
268
231
  * kmac.update("more data")
269
232
  * kmac << "more data" # alias for update
270
233
  */
271
- static VALUE rb_sha3_kmac_update(VALUE self, VALUE data) {
272
- sp800_185_context_t *context;
273
- get_kmac_context(self, &context);
274
- sp800_185_update(context, data);
275
-
276
- return self;
277
- }
234
+ DEFINE_SP800_185_SIMPLE_METHOD(rb_sha3_kmac_update, sp800_185_rb_update, get_kmac_context)
278
235
 
279
236
  /*
280
237
  * :call-seq:
@@ -285,12 +242,7 @@ static VALUE rb_sha3_kmac_update(VALUE self, VALUE data) {
285
242
  * = example
286
243
  * kmac.name #=> "KMAC128" or "KMAC256"
287
244
  */
288
- static VALUE rb_sha3_kmac_name(VALUE self) {
289
- sp800_185_context_t *context;
290
- get_kmac_context(self, &context);
291
-
292
- return rb_str_new2(sp800_185_name(context));
293
- }
245
+ DEFINE_SP800_185_RETURN_METHOD(rb_sha3_kmac_name, sp800_185_rb_name, get_kmac_context)
294
246
 
295
247
  /*
296
248
  * :call-seq:
@@ -304,14 +256,7 @@ static VALUE rb_sha3_kmac_name(VALUE self) {
304
256
  * = example
305
257
  * kmac.finish
306
258
  */
307
- static VALUE rb_sha3_kmac_finish(int argc, VALUE *argv, VALUE self) {
308
- sp800_185_context_t *context;
309
- get_kmac_context(self, &context);
310
-
311
- VALUE output = argc > 0 ? argv[0] : Qnil;
312
-
313
- return sp800_185_finish(context, output);
314
- }
259
+ DEFINE_SP800_185_VARARGS_METHOD(rb_sha3_kmac_finish, sp800_185_rb_finish, get_kmac_context)
315
260
 
316
261
  /*
317
262
  * :call-seq:
@@ -329,14 +274,7 @@ static VALUE rb_sha3_kmac_finish(int argc, VALUE *argv, VALUE self) {
329
274
  * kmac.digest
330
275
  * kmac.digest('final chunk')
331
276
  */
332
- static VALUE rb_sha3_kmac_digest(int argc, VALUE *argv, VALUE self) {
333
- sp800_185_context_t *context;
334
- get_kmac_context(self, &context);
335
-
336
- VALUE data = argc > 0 ? argv[0] : Qnil;
337
-
338
- return sp800_185_digest(context, data);
339
- }
277
+ DEFINE_SP800_185_VARARGS_METHOD(rb_sha3_kmac_digest, sp800_185_rb_digest, get_kmac_context)
340
278
 
341
279
  /*
342
280
  * :call-seq:
@@ -354,14 +292,7 @@ static VALUE rb_sha3_kmac_digest(int argc, VALUE *argv, VALUE self) {
354
292
  * kmac.hexdigest
355
293
  * kmac.hexdigest('final chunk')
356
294
  */
357
- static VALUE rb_sha3_kmac_hexdigest(int argc, VALUE *argv, VALUE self) {
358
- sp800_185_context_t *context;
359
- get_kmac_context(self, &context);
360
-
361
- VALUE data = argc > 0 ? argv[0] : Qnil;
362
-
363
- return sp800_185_hexdigest(context, data);
364
- }
295
+ DEFINE_SP800_185_VARARGS_METHOD(rb_sha3_kmac_hexdigest, sp800_185_rb_hexdigest, get_kmac_context)
365
296
 
366
297
  /*
367
298
  * :call-seq:
@@ -377,12 +308,7 @@ static VALUE rb_sha3_kmac_hexdigest(int argc, VALUE *argv, VALUE self) {
377
308
  * = example
378
309
  * kmac.squeeze(128)
379
310
  */
380
- static VALUE rb_sha3_kmac_squeeze(VALUE self, VALUE length) {
381
- sp800_185_context_t *context;
382
- get_kmac_context(self, &context);
383
-
384
- return sp800_185_squeeze(context, length);
385
- }
311
+ DEFINE_SP800_185_VALUE_METHOD(rb_sha3_kmac_squeeze, sp800_185_rb_squeeze, get_kmac_context)
386
312
 
387
313
  /*
388
314
  * :call-seq:
@@ -398,12 +324,7 @@ static VALUE rb_sha3_kmac_squeeze(VALUE self, VALUE length) {
398
324
  * = example
399
325
  * kmac.hex_squeeze(128)
400
326
  */
401
- static VALUE rb_sha3_kmac_hex_squeeze(VALUE self, VALUE length) {
402
- sp800_185_context_t *context;
403
- get_kmac_context(self, &context);
404
-
405
- return sp800_185_hex_squeeze(context, length);
406
- }
327
+ DEFINE_SP800_185_VALUE_METHOD(rb_sha3_kmac_hex_squeeze, sp800_185_rb_hex_squeeze, get_kmac_context)
407
328
 
408
329
  /*
409
330
  * :call-seq:
@@ -432,7 +353,7 @@ static VALUE rb_sha3_kmac_self_digest(int argc, VALUE *argv, VALUE klass) {
432
353
  rb_scan_args(argc, argv, "41", &algorithm, &data, &output_length, &key, &customization);
433
354
 
434
355
  Check_Type(output_length, T_FIXNUM);
435
- if (!NIL_P(output_length) && output_length <= INT2FIX(0)) {
356
+ if (!NIL_P(output_length) && NUM2INT(output_length) <= 0) {
436
357
  rb_raise(rb_eArgError, "class method digest does not support XOF mode");
437
358
  }
438
359
 
@@ -468,7 +389,7 @@ static VALUE rb_sha3_kmac_self_hexdigest(int argc, VALUE *argv, VALUE klass) {
468
389
  rb_scan_args(argc, argv, "41", &algorithm, &data, &output_length, &key, &customization);
469
390
 
470
391
  Check_Type(output_length, T_FIXNUM);
471
- if (!NIL_P(output_length) && output_length <= INT2FIX(0)) {
392
+ if (!NIL_P(output_length) && NUM2INT(output_length) <= 0) {
472
393
  rb_raise(rb_eArgError, "class method hexdigest does not support XOF mode");
473
394
  }
474
395
 
data/ext/sha3/sp800_185.c CHANGED
@@ -74,12 +74,12 @@ const sp800_185_function_table_t *sp800_185_get_algorithm_by_name(const char *na
74
74
 
75
75
  // Generic context allocation function
76
76
  sp800_185_context_t *sp800_185_alloc_context(size_t context_size, size_t state_size) {
77
- sp800_185_context_t *context = (sp800_185_context_t *)malloc(context_size);
77
+ sp800_185_context_t *context = (sp800_185_context_t *)ruby_xmalloc(context_size);
78
78
  if (!context) return NULL;
79
79
 
80
- context->state = calloc(1, state_size);
80
+ context->state = ruby_xcalloc(1, state_size);
81
81
  if (!context->state) {
82
- free(context);
82
+ ruby_xfree(context);
83
83
  return NULL;
84
84
  }
85
85
 
@@ -92,9 +92,9 @@ sp800_185_context_t *sp800_185_alloc_context(size_t context_size, size_t state_s
92
92
  void sp800_185_free_context(sp800_185_context_t *context) {
93
93
  if (context) {
94
94
  if (context->state) {
95
- free(context->state);
95
+ ruby_xfree(context->state);
96
96
  }
97
- free(context);
97
+ ruby_xfree(context);
98
98
  }
99
99
  }
100
100
 
@@ -112,7 +112,7 @@ void *sp800_185_copy_state(sp800_185_context_t *context) {
112
112
  if (context->functions->state_size <= 0) {
113
113
  rb_raise(context->error_class, "invalid state size");
114
114
  }
115
- void *state_copy = malloc(context->functions->state_size);
115
+ void *state_copy = ruby_xmalloc(context->functions->state_size);
116
116
 
117
117
  if (!state_copy) {
118
118
  rb_raise(rb_eNoMemError, "failed to allocate memory for state copy");
@@ -125,6 +125,12 @@ void *sp800_185_copy_state(sp800_185_context_t *context) {
125
125
 
126
126
  VALUE sp800_185_update(sp800_185_context_t *context, VALUE data) {
127
127
  StringValue(data);
128
+
129
+ // Check for NULL data pointer
130
+ if (RSTRING_PTR(data) == NULL && RSTRING_LEN(data) > 0) {
131
+ rb_raise(context->error_class, "cannot update with NULL data");
132
+ }
133
+
128
134
  size_t data_len = (RSTRING_LEN(data) * 8);
129
135
 
130
136
  if (data_len == 0) {
@@ -172,7 +178,7 @@ VALUE sp800_185_digest(sp800_185_context_t *context, VALUE data) {
172
178
  }
173
179
 
174
180
  // Create a copy of the state for processing
175
- void *state_copy = malloc(context->functions->state_size);
181
+ void *state_copy = ruby_xmalloc(context->functions->state_size);
176
182
  if (!state_copy) {
177
183
  rb_raise(rb_eNoMemError, "failed to allocate memory for state copy");
178
184
  }
@@ -190,7 +196,7 @@ VALUE sp800_185_digest(sp800_185_context_t *context, VALUE data) {
190
196
  result = context->functions->update(state_copy, (const BitSequence *)RSTRING_PTR(data), data_len);
191
197
 
192
198
  if (result != 0) {
193
- free(state_copy);
199
+ ruby_xfree(state_copy);
194
200
  rb_raise(context->error_class, "failed to update %s state", context->functions->name);
195
201
  }
196
202
  }
@@ -201,7 +207,7 @@ VALUE sp800_185_digest(sp800_185_context_t *context, VALUE data) {
201
207
 
202
208
  result = context->functions->final(state_copy, (BitSequence *)RSTRING_PTR(output));
203
209
 
204
- free(state_copy);
210
+ ruby_xfree(state_copy);
205
211
 
206
212
  if (result != 0) {
207
213
  rb_raise(context->error_class, "failed to finalize %s state", context->functions->name);
@@ -220,18 +226,23 @@ VALUE sp800_185_squeeze(sp800_185_context_t *context, VALUE length) {
220
226
  rb_raise(context->error_class, "use digest methods for fixed-length output");
221
227
  }
222
228
 
223
- size_t output_byte_len;
229
+ long output_byte_len;
224
230
  VALUE str;
225
231
 
226
232
  Check_Type(length, T_FIXNUM);
227
- output_byte_len = NUM2ULONG(length);
233
+ output_byte_len = NUM2LONG(length);
228
234
 
229
235
  if (output_byte_len <= 0) {
230
- rb_raise(context->error_class, "output length must be specified");
236
+ rb_raise(context->error_class, "output length must be positive");
237
+ }
238
+
239
+ // Limit output to 1MB for safety
240
+ if (output_byte_len > (1L << 20)) {
241
+ rb_raise(context->error_class, "output length too large (max 1MB)");
231
242
  }
232
243
 
233
244
  // Create a copy of the state for processing
234
- void *state_copy = malloc(context->functions->state_size);
245
+ void *state_copy = ruby_xmalloc(context->functions->state_size);
235
246
  if (!state_copy) {
236
247
  rb_raise(rb_eNoMemError, "failed to allocate memory for state copy");
237
248
  }
@@ -245,7 +256,7 @@ VALUE sp800_185_squeeze(sp800_185_context_t *context, VALUE length) {
245
256
  result = context->functions->final(state_copy, (BitSequence *)RSTRING_PTR(dummy_output));
246
257
 
247
258
  if (result != 0) {
248
- free(state_copy);
259
+ ruby_xfree(state_copy);
249
260
  rb_raise(context->error_class, "failed to finalize %s state", context->functions->name);
250
261
  }
251
262
 
@@ -255,7 +266,7 @@ VALUE sp800_185_squeeze(sp800_185_context_t *context, VALUE length) {
255
266
  // Use the function table to call the appropriate squeeze function
256
267
  result = context->functions->squeeze(state_copy, (BitSequence *)RSTRING_PTR(str), output_byte_len * 8);
257
268
 
258
- free(state_copy);
269
+ ruby_xfree(state_copy);
259
270
 
260
271
  if (result != 0) {
261
272
  rb_raise(context->error_class, "failed to squeeze %s", context->functions->name);
@@ -268,3 +279,24 @@ VALUE sp800_185_hex_squeeze(sp800_185_context_t *context, VALUE length) {
268
279
  VALUE binary_result = sp800_185_squeeze(context, length);
269
280
  return rb_funcall(binary_result, rb_intern("unpack1"), 1, rb_str_new2("H*"));
270
281
  }
282
+
283
+ /* Ruby wrapper functions for common method patterns */
284
+
285
+ VALUE sp800_185_rb_update(sp800_185_context_t *context, VALUE data) {
286
+ sp800_185_update(context, data);
287
+ return Qnil; // Caller will return self
288
+ }
289
+
290
+ VALUE sp800_185_rb_name(sp800_185_context_t *context) { return rb_str_new2(sp800_185_name(context)); }
291
+
292
+ VALUE sp800_185_rb_finish(sp800_185_context_t *context, VALUE output) { return sp800_185_finish(context, output); }
293
+
294
+ VALUE sp800_185_rb_digest(sp800_185_context_t *context, VALUE data) { return sp800_185_digest(context, data); }
295
+
296
+ VALUE sp800_185_rb_hexdigest(sp800_185_context_t *context, VALUE data) { return sp800_185_hexdigest(context, data); }
297
+
298
+ VALUE sp800_185_rb_squeeze(sp800_185_context_t *context, VALUE length) { return sp800_185_squeeze(context, length); }
299
+
300
+ VALUE sp800_185_rb_hex_squeeze(sp800_185_context_t *context, VALUE length) {
301
+ return sp800_185_hex_squeeze(context, length);
302
+ }
data/lib/constants.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SHA3
4
- VERSION = '2.2.2'
4
+ VERSION = '2.2.3'
5
5
  end
data/sha3.gemspec CHANGED
@@ -9,11 +9,11 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ['Johanns Gregorian']
10
10
  spec.email = ['io+sha3@jsg.io']
11
11
 
12
- spec.description = <<~EOF
12
+ spec.description = <<~DESC
13
13
  A high-performance native binding to the SHA3 (FIPS 202) cryptographic hashing algorithms, based on the XKCP - eXtended Keccak Code Package.
14
14
  This gem provides support for the standard SHA-3 fixed-length functions (224, 256, 384, and 512 bits),
15
15
  as well as the SHAKE128/SHAKE256 extendable-output functions (XOFs), cSHAKE128/256, and KMAC as specified in NIST SP 800-185.'
16
- EOF
16
+ DESC
17
17
  spec.summary = 'SHA-3 (FIPS 202), SHAKE128/SHAKE256, cSHAKE128/cSHAKE256, and KMAC (NIST SP 800-185), powered by XKCP.'
18
18
 
19
19
  spec.homepage = 'https://github.com/johanns/sha3'
@@ -24,11 +24,11 @@ Gem::Specification.new do |spec|
24
24
  spec.metadata['homepage_uri'] = spec.homepage
25
25
  spec.metadata['documentation_uri'] = 'https://docs.jsg.io/sha3/index.html'
26
26
 
27
- spec.post_install_message = <<-EOF
27
+ spec.post_install_message = <<-NOTICE
28
28
  [NOTICE] SHA3 version 2.0 introduces breaking changes to the API.
29
29
  Please review the changelog and ensure compatibility with your application.
30
30
  If you need the previous behavior, lock your Gemfile to version '~> 1.0'."
31
- EOF
31
+ NOTICE
32
32
 
33
33
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
34
34
  `git ls-files -z`.split("\x0").reject do |f|
data.tar.gz.sig CHANGED
Binary file
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sha3
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.2.2
4
+ version: 2.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johanns Gregorian
@@ -62,6 +62,7 @@ files:
62
62
  - Rakefile
63
63
  - certs/io+sha3@jsg.io.pem
64
64
  - doc/sha3.rb
65
+ - ext/sha3/common.h
65
66
  - ext/sha3/config.h
66
67
  - ext/sha3/cshake.c
67
68
  - ext/sha3/cshake.h
@@ -130,7 +131,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
130
131
  - !ruby/object:Gem::Version
131
132
  version: '0'
132
133
  requirements: []
133
- rubygems_version: 3.6.9
134
+ rubygems_version: 3.7.1
134
135
  specification_version: 4
135
136
  summary: SHA-3 (FIPS 202), SHAKE128/SHAKE256, cSHAKE128/cSHAKE256, and KMAC (NIST
136
137
  SP 800-185), powered by XKCP.
metadata.gz.sig CHANGED
Binary file