sha3 2.2.0 → 2.2.2

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: 0352e31c9fba5b6e692cca78be1860cccf6a008717738ecbea414d83d195b588
4
- data.tar.gz: 24f543cfcb6b2d477182912a65b54a09cce5209dcfe6c8dbeec22c3992296cec
3
+ metadata.gz: d5da48a8f70ea2746484300e05125b21ab1fcd5837d0f194d8b12fac46a46602
4
+ data.tar.gz: 7be8cf46c2e1e4bc38dedb64b25654f70806d6c761427b062c171bf0df359caa
5
5
  SHA512:
6
- metadata.gz: a947dc104fa08b9199ed307fd43b3bee24143561aaa9665b4c6dd6a0d20ddbf69194b4eb96b845fd0974dc68d2133d024157c754f5e2835ec6161958df343caa
7
- data.tar.gz: 4dd184e53262a9ec71eaf56bf80a295e8d3b691b736333834e5ae9e416df65bbea4ca10c20cc4c22e429bb6ffc97debda126b59bd50f23d732b079c3418b2653
6
+ metadata.gz: 57e70a0c38eb04f0aab1fe81f0c3ee60a6eb2bc7ea6c6f2e57f8712f23084139bd4a494cde70ad99eca7e20fe1534adb7f91b9986a4ad31ac1127ffa4a115d07
7
+ data.tar.gz: 0b7cdd43dc7167e3e92f4ec2adfb947c00f0b8827aaaeafb9383213bdd1bc09771c0b17efec3d28667b1bb383646f006360496abf3dfd43a2a6cd54f8e1dd4c2
checksums.yaml.gz.sig CHANGED
Binary file
data/ext/sha3/cshake.c CHANGED
@@ -42,10 +42,9 @@ static ID _cshake_256_id;
42
42
  static const rb_data_type_t sha3_cshake_data_type = {
43
43
  "SHA3::CSHAKE",
44
44
  {
45
- NULL,
46
- sha3_cshake_free_context, // Use our free function directly
47
- sha3_cshake_context_size, /* We'll do our own size calculation */
48
- NULL, /* dcompact field */
45
+ NULL, sha3_cshake_free_context, // Use our free function directly
46
+ sha3_cshake_context_size, /* We'll do our own size calculation */
47
+ NULL, /* dcompact field */
49
48
  },
50
49
  NULL,
51
50
  NULL,
@@ -179,8 +178,8 @@ static VALUE rb_sha3_cshake_init(int argc, VALUE *argv, VALUE self) {
179
178
  rb_intern("customization"),
180
179
  };
181
180
 
182
- VALUE values[3];
183
- rb_get_kwargs(keywords, table, 0, 3, values);
181
+ VALUE values[2];
182
+ rb_get_kwargs(keywords, table, 0, 2, values);
184
183
 
185
184
  VALUE name_str = values[0] == Qundef ? rb_str_new2("") : values[0];
186
185
  StringValue(name_str);
@@ -196,18 +195,24 @@ static VALUE rb_sha3_cshake_init(int argc, VALUE *argv, VALUE self) {
196
195
  context->base.error_class = _sha3_cshake_error_class;
197
196
 
198
197
  // Find the appropriate function table based on the algorithm
198
+ sp800_185_algorithm_t alg_type;
199
199
  if (algorithm == ID2SYM(_cshake_128_id)) {
200
- context->base.functions = &sp800_185_functions[SP800_185_CSHAKE_128];
200
+ alg_type = SP800_185_CSHAKE_128;
201
201
  } else if (algorithm == ID2SYM(_cshake_256_id)) {
202
- context->base.functions = &sp800_185_functions[SP800_185_CSHAKE_256];
202
+ alg_type = SP800_185_CSHAKE_256;
203
203
  } else {
204
204
  rb_raise(rb_eArgError, "invalid algorithm: %s", rb_id2name(SYM2ID(algorithm)));
205
205
  }
206
206
 
207
- // Initialize the state using the function table
208
- int result = context->base.functions->cshake.init(
209
- context->base.state, context->base.output_length, (BitSequence *)RSTRING_PTR(name_str),
210
- RSTRING_LEN(name_str) * 8, (BitSequence *)RSTRING_PTR(customization), RSTRING_LEN(customization) * 8);
207
+ context->base.functions = sp800_185_get_algorithm(alg_type);
208
+ if (!context->base.functions) {
209
+ rb_raise(_sha3_cshake_error_class, "algorithm not available");
210
+ }
211
+
212
+ // Initialize using the safe accessor function
213
+ int result = sp800_185_init_cshake(context->base.functions, context->base.state, context->base.output_length,
214
+ (BitSequence *)RSTRING_PTR(name_str), RSTRING_LEN(name_str) * 8,
215
+ (BitSequence *)RSTRING_PTR(customization), RSTRING_LEN(customization) * 8);
211
216
 
212
217
  if (result != 0) {
213
218
  rb_raise(_sha3_cshake_error_class, "failed to initialize %s algorithm", context->base.functions->name);
data/ext/sha3/cshake.h CHANGED
@@ -1,7 +1,7 @@
1
1
  // Copyright (c) 2012 - 2025 Johanns Gregorian <io+sha3@jsg.io>
2
2
 
3
- #ifndef _SHA3_CSHAKE_H
4
- #define _SHA3_CSHAKE_H
3
+ #ifndef _SHA3_CSHAKE_H_
4
+ #define _SHA3_CSHAKE_H_
5
5
 
6
6
  #ifdef __cplusplus
7
7
  extern "C" {
@@ -14,4 +14,4 @@ void Init_sha3_cshake(void);
14
14
  }
15
15
  #endif
16
16
 
17
- #endif /* SHA3_CSHAKE_H */
17
+ #endif /* _SHA3_CSHAKE_H_ */
data/ext/sha3/kmac.c CHANGED
@@ -70,18 +70,15 @@ void Init_sha3_kmac(void) {
70
70
  /*
71
71
  * Document-class: SHA3::KMAC
72
72
  *
73
- * It is a subclass of the Digest::Class class, which provides a framework for
74
- * creating and manipulating hash digests.
73
+ * KMAC (Keccak Message Authentication Code) is a MAC algorithm based on the Keccak permutation.
74
+ * It is defined in NIST SP800-185 and provides both fixed-length and XOF (arbitrary-length) output modes.
75
75
  */
76
76
  _sha3_kmac_class = rb_define_class_under(_sha3_module, "KMAC", rb_cObject);
77
77
 
78
78
  /*
79
- * Document-class: SHA3::KMAC::KMACError
79
+ * Document-class: SHA3::KMAC::Error
80
80
  *
81
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
82
  */
86
83
  _sha3_kmac_error_class = rb_define_class_under(_sha3_kmac_class, "Error", rb_eStandardError);
87
84
 
@@ -190,21 +187,28 @@ static VALUE rb_sha3_kmac_init(int argc, VALUE *argv, VALUE self) {
190
187
 
191
188
  // Find the appropriate function table based on the algorithm
192
189
  ID sym_id = SYM2ID(algorithm);
190
+ sp800_185_algorithm_t alg_type;
191
+
193
192
  if (sym_id == _kmac_128_id) {
194
- context->base.functions = &sp800_185_functions[SP800_185_KMAC_128];
193
+ alg_type = SP800_185_KMAC_128;
195
194
  } else if (sym_id == _kmac_256_id) {
196
- context->base.functions = &sp800_185_functions[SP800_185_KMAC_256];
195
+ alg_type = SP800_185_KMAC_256;
197
196
  } else {
198
197
  rb_raise(rb_eArgError, "invalid algorithm: %s", rb_id2name(sym_id));
199
198
  }
200
199
 
201
- // Initialize the KMAC instance
200
+ context->base.functions = sp800_185_get_algorithm(alg_type);
201
+ if (!context->base.functions) {
202
+ rb_raise(_sha3_kmac_error_class, "algorithm not available: %s", rb_id2name(sym_id));
203
+ }
204
+
205
+ // Initialize using the safe accessor function
202
206
  size_t key_len = RSTRING_LEN(key) * 8;
203
207
  size_t customization_len = RSTRING_LEN(customization) * 8;
204
208
 
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);
209
+ int result = sp800_185_init_kmac(context->base.functions, context->base.state,
210
+ (const BitSequence *)RSTRING_PTR(key), key_len, context->base.output_length,
211
+ (const BitSequence *)RSTRING_PTR(customization), customization_len);
208
212
 
209
213
  if (result != 0) {
210
214
  rb_raise(_sha3_kmac_error_class, "failed to initialize %s", context->base.functions->name);
data/ext/sha3/kmac.h CHANGED
@@ -1,3 +1,5 @@
1
+ // Copyright (c) 2012 - 2025 Johanns Gregorian <io+sha3@jsg.io>
2
+
1
3
  #ifndef _SHA3_KMAC_H_
2
4
  #define _SHA3_KMAC_H_
3
5
 
@@ -5,10 +7,11 @@
5
7
  extern "C" {
6
8
  #endif
7
9
 
8
- extern void Init_sha3_kmac(void);
10
+ /* Function prototypes */
11
+ void Init_sha3_kmac(void);
9
12
 
10
13
  #ifdef __cplusplus
11
14
  }
12
15
  #endif
13
16
 
14
- #endif // _SHA3_KMAC_H_
17
+ #endif /* _SHA3_KMAC_H_ */
data/ext/sha3/sp800_185.c CHANGED
@@ -1,36 +1,76 @@
1
1
  #include "sp800_185.h"
2
2
 
3
- #include "sha3.h"
3
+ /* Wrapper functions for consistent interface */
4
+ static int cshake128_init_wrapper(void *state, void *params) {
5
+ cshake_init_params_t *p = (cshake_init_params_t *)params;
6
+ return cSHAKE128_Initialize(state, p->capacity, p->N, p->NLen, p->S, p->SLen);
7
+ }
8
+
9
+ static int cshake256_init_wrapper(void *state, void *params) {
10
+ cshake_init_params_t *p = (cshake_init_params_t *)params;
11
+ return cSHAKE256_Initialize(state, p->capacity, p->N, p->NLen, p->S, p->SLen);
12
+ }
13
+
14
+ static int kmac128_init_wrapper(void *state, void *params) {
15
+ kmac_init_params_t *p = (kmac_init_params_t *)params;
16
+ return KMAC128_Initialize(state, p->key, p->keyBitLen, p->outputBitLen, p->customization, p->customBitLen);
17
+ }
18
+
19
+ static int kmac256_init_wrapper(void *state, void *params) {
20
+ kmac_init_params_t *p = (kmac_init_params_t *)params;
21
+ return KMAC256_Initialize(state, p->key, p->keyBitLen, p->outputBitLen, p->customization, p->customBitLen);
22
+ }
4
23
 
5
24
  /*** Function table for SP800-185 algorithms ***/
6
25
  sp800_185_function_table_t sp800_185_functions[] = {{.algorithm = SP800_185_CSHAKE_128,
7
26
  .name = "CSHAKE128",
8
27
  .state_size = sizeof(cSHAKE_Instance),
9
- .cshake = {.init = (sp800_185_init_fn)cSHAKE128_Initialize,
10
- .update = (sp800_185_update_fn)cSHAKE128_Update,
11
- .final = (sp800_185_final_fn)cSHAKE128_Final,
12
- .squeeze = (sp800_185_squeeze_fn)cSHAKE128_Squeeze}},
28
+ .is_keyed = false,
29
+ .init = cshake128_init_wrapper,
30
+ .update = (sp800_185_update_fn)cSHAKE128_Update,
31
+ .final = (sp800_185_final_fn)cSHAKE128_Final,
32
+ .squeeze = (sp800_185_squeeze_fn)cSHAKE128_Squeeze},
13
33
  {.algorithm = SP800_185_CSHAKE_256,
14
34
  .name = "CSHAKE256",
15
35
  .state_size = sizeof(cSHAKE_Instance),
16
- .cshake = {.init = (sp800_185_init_fn)cSHAKE256_Initialize,
17
- .update = (sp800_185_update_fn)cSHAKE256_Update,
18
- .final = (sp800_185_final_fn)cSHAKE256_Final,
19
- .squeeze = (sp800_185_squeeze_fn)cSHAKE256_Squeeze}},
36
+ .is_keyed = false,
37
+ .init = cshake256_init_wrapper,
38
+ .update = (sp800_185_update_fn)cSHAKE256_Update,
39
+ .final = (sp800_185_final_fn)cSHAKE256_Final,
40
+ .squeeze = (sp800_185_squeeze_fn)cSHAKE256_Squeeze},
20
41
  {.algorithm = SP800_185_KMAC_128,
21
42
  .name = "KMAC128",
22
43
  .state_size = sizeof(KMAC_Instance),
23
- .kmac = {.init = (sp800_185_init_key_fn)KMAC128_Initialize,
24
- .update = (sp800_185_update_fn)KMAC128_Update,
25
- .final = (sp800_185_final_fn)KMAC128_Final,
26
- .squeeze = (sp800_185_squeeze_fn)KMAC128_Squeeze}},
44
+ .is_keyed = true,
45
+ .init = kmac128_init_wrapper,
46
+ .update = (sp800_185_update_fn)KMAC128_Update,
47
+ .final = (sp800_185_final_fn)KMAC128_Final,
48
+ .squeeze = (sp800_185_squeeze_fn)KMAC128_Squeeze},
27
49
  {.algorithm = SP800_185_KMAC_256,
28
50
  .name = "KMAC256",
29
51
  .state_size = sizeof(KMAC_Instance),
30
- .kmac = {.init = (sp800_185_init_key_fn)KMAC256_Initialize,
31
- .update = (sp800_185_update_fn)KMAC256_Update,
32
- .final = (sp800_185_final_fn)KMAC256_Final,
33
- .squeeze = (sp800_185_squeeze_fn)KMAC256_Squeeze}}};
52
+ .is_keyed = true,
53
+ .init = kmac256_init_wrapper,
54
+ .update = (sp800_185_update_fn)KMAC256_Update,
55
+ .final = (sp800_185_final_fn)KMAC256_Final,
56
+ .squeeze = (sp800_185_squeeze_fn)KMAC256_Squeeze}};
57
+
58
+ /* Algorithm lookup functions */
59
+ const sp800_185_function_table_t *sp800_185_get_algorithm(sp800_185_algorithm_t algorithm) {
60
+ if (algorithm >= SP800_185_CSHAKE_128 && algorithm <= SP800_185_KMAC_256) {
61
+ return &sp800_185_functions[algorithm];
62
+ }
63
+ return NULL;
64
+ }
65
+
66
+ const sp800_185_function_table_t *sp800_185_get_algorithm_by_name(const char *name) {
67
+ for (size_t i = 0; i < sizeof(sp800_185_functions) / sizeof(sp800_185_functions[0]); i++) {
68
+ if (strcmp(sp800_185_functions[i].name, name) == 0) {
69
+ return &sp800_185_functions[i];
70
+ }
71
+ }
72
+ return NULL;
73
+ }
34
74
 
35
75
  // Generic context allocation function
36
76
  sp800_185_context_t *sp800_185_alloc_context(size_t context_size, size_t state_size) {
@@ -94,21 +134,7 @@ VALUE sp800_185_update(sp800_185_context_t *context, VALUE data) {
94
134
  // Use the function table to call the appropriate update function
95
135
  int result;
96
136
 
97
- // KMAC, cSHAKE, and ParallelHash share the same update function signature
98
- switch (context->functions->algorithm) {
99
- case SP800_185_CSHAKE_128:
100
- case SP800_185_CSHAKE_256:
101
- result =
102
- context->functions->cshake.update(context->state, (const BitSequence *)RSTRING_PTR(data), data_len);
103
- break;
104
- case SP800_185_KMAC_128:
105
- case SP800_185_KMAC_256:
106
- result = context->functions->kmac.update(context->state, (const BitSequence *)RSTRING_PTR(data), data_len);
107
- break;
108
- default:
109
- rb_raise(context->error_class, "unknown algorithm");
110
- return Qnil;
111
- }
137
+ result = context->functions->update(context->state, (const BitSequence *)RSTRING_PTR(data), data_len);
112
138
 
113
139
  if (result != 0) {
114
140
  rb_raise(context->error_class, "failed to update %s state", context->functions->name);
@@ -129,19 +155,7 @@ VALUE sp800_185_finish(sp800_185_context_t *context, VALUE output) {
129
155
  // Use the function table to call the appropriate final function
130
156
  int result;
131
157
 
132
- switch (context->functions->algorithm) {
133
- case SP800_185_CSHAKE_128:
134
- case SP800_185_CSHAKE_256:
135
- result = context->functions->cshake.final(context->state, (BitSequence *)RSTRING_PTR(output));
136
- break;
137
- case SP800_185_KMAC_128:
138
- case SP800_185_KMAC_256:
139
- result = context->functions->kmac.final(context->state, (BitSequence *)RSTRING_PTR(output));
140
- break;
141
- default:
142
- rb_raise(context->error_class, "unknown algorithm");
143
- return Qnil;
144
- }
158
+ result = context->functions->final(context->state, (BitSequence *)RSTRING_PTR(output));
145
159
 
146
160
  if (result != 0) {
147
161
  rb_raise(context->error_class, "failed to finalize %s state", context->functions->name);
@@ -173,22 +187,7 @@ VALUE sp800_185_digest(sp800_185_context_t *context, VALUE data) {
173
187
  size_t data_len = (RSTRING_LEN(data) * 8);
174
188
 
175
189
  if (data_len > 0) {
176
- switch (context->functions->algorithm) {
177
- case SP800_185_CSHAKE_128:
178
- case SP800_185_CSHAKE_256:
179
- result =
180
- context->functions->cshake.update(state_copy, (const BitSequence *)RSTRING_PTR(data), data_len);
181
- break;
182
- case SP800_185_KMAC_128:
183
- case SP800_185_KMAC_256:
184
- result =
185
- context->functions->kmac.update(state_copy, (const BitSequence *)RSTRING_PTR(data), data_len);
186
- break;
187
- default:
188
- free(state_copy);
189
- rb_raise(context->error_class, "unknown algorithm");
190
- return Qnil;
191
- }
190
+ result = context->functions->update(state_copy, (const BitSequence *)RSTRING_PTR(data), data_len);
192
191
 
193
192
  if (result != 0) {
194
193
  free(state_copy);
@@ -200,20 +199,7 @@ VALUE sp800_185_digest(sp800_185_context_t *context, VALUE data) {
200
199
  // Prepare output and finalize
201
200
  VALUE output = rb_str_new(0, context->output_length / 8);
202
201
 
203
- switch (context->functions->algorithm) {
204
- case SP800_185_CSHAKE_128:
205
- case SP800_185_CSHAKE_256:
206
- result = context->functions->cshake.final(state_copy, (BitSequence *)RSTRING_PTR(output));
207
- break;
208
- case SP800_185_KMAC_128:
209
- case SP800_185_KMAC_256:
210
- result = context->functions->kmac.final(state_copy, (BitSequence *)RSTRING_PTR(output));
211
- break;
212
- default:
213
- free(state_copy);
214
- rb_raise(context->error_class, "unknown algorithm");
215
- return Qnil;
216
- }
202
+ result = context->functions->final(state_copy, (BitSequence *)RSTRING_PTR(output));
217
203
 
218
204
  free(state_copy);
219
205
 
@@ -256,20 +242,7 @@ VALUE sp800_185_squeeze(sp800_185_context_t *context, VALUE length) {
256
242
  VALUE dummy_output = rb_str_new(0, 0);
257
243
  int result;
258
244
 
259
- switch (context->functions->algorithm) {
260
- case SP800_185_CSHAKE_128:
261
- case SP800_185_CSHAKE_256:
262
- result = context->functions->cshake.final(state_copy, (BitSequence *)RSTRING_PTR(dummy_output));
263
- break;
264
- case SP800_185_KMAC_128:
265
- case SP800_185_KMAC_256:
266
- result = context->functions->kmac.final(state_copy, (BitSequence *)RSTRING_PTR(dummy_output));
267
- break;
268
- default:
269
- free(state_copy);
270
- rb_raise(context->error_class, "unknown algorithm");
271
- return Qnil;
272
- }
245
+ result = context->functions->final(state_copy, (BitSequence *)RSTRING_PTR(dummy_output));
273
246
 
274
247
  if (result != 0) {
275
248
  free(state_copy);
@@ -280,21 +253,7 @@ VALUE sp800_185_squeeze(sp800_185_context_t *context, VALUE length) {
280
253
  str = rb_str_new(0, output_byte_len);
281
254
 
282
255
  // Use the function table to call the appropriate squeeze function
283
- switch (context->functions->algorithm) {
284
- case SP800_185_CSHAKE_128:
285
- case SP800_185_CSHAKE_256:
286
- result =
287
- context->functions->cshake.squeeze(state_copy, (BitSequence *)RSTRING_PTR(str), output_byte_len * 8);
288
- break;
289
- case SP800_185_KMAC_128:
290
- case SP800_185_KMAC_256:
291
- result = context->functions->kmac.squeeze(state_copy, (BitSequence *)RSTRING_PTR(str), output_byte_len * 8);
292
- break;
293
- default:
294
- free(state_copy);
295
- rb_raise(context->error_class, "unknown algorithm");
296
- return Qnil;
297
- }
256
+ result = context->functions->squeeze(state_copy, (BitSequence *)RSTRING_PTR(str), output_byte_len * 8);
298
257
 
299
258
  free(state_copy);
300
259
 
data/ext/sha3/sp800_185.h CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  #include <ruby.h>
5
5
  #include <ruby/thread.h>
6
+ #include <stdbool.h>
6
7
 
7
8
  #include "KeccakHash.h"
8
9
  #include "SP800-185.h"
@@ -11,6 +12,12 @@
11
12
  extern "C" {
12
13
  #endif
13
14
 
15
+ /* Forward declarations for types from Keccak if not already defined */
16
+ #ifndef KECCAK_TYPES_DEFINED
17
+ typedef unsigned char BitSequence;
18
+ typedef size_t BitLength;
19
+ #endif
20
+
14
21
  /* SP800-185 algorithm family */
15
22
  typedef enum {
16
23
  SP800_185_CSHAKE_128 = 0,
@@ -20,37 +27,49 @@ typedef enum {
20
27
  } sp800_185_algorithm_t;
21
28
 
22
29
  /* Common function pointer typedefs for SP800-185 algorithms */
23
- typedef int (*sp800_185_init_fn)(void *state, size_t capacity, const BitSequence *N, size_t NLen, const BitSequence *S,
24
- size_t SLen);
25
-
26
- typedef int (*sp800_185_init_key_fn)(void *state, const BitSequence *key, BitLength keyBitLen, BitLength outputBitLen,
27
- const BitSequence *customization, BitLength customBitLen);
28
-
29
30
  typedef int (*sp800_185_update_fn)(void *state, const BitSequence *data, size_t dataLen);
30
31
  typedef int (*sp800_185_final_fn)(void *state, BitSequence *output);
31
32
  typedef int (*sp800_185_squeeze_fn)(void *state, BitSequence *output, size_t outputLen);
32
33
 
33
- /* Function table for SP800-185 algorithm operations */
34
+ /* Error codes for SP800-185 operations */
35
+ typedef enum {
36
+ SP800_185_SUCCESS = 0,
37
+ SP800_185_ERROR_INVALID_ALGORITHM = -1,
38
+ SP800_185_ERROR_INVALID_PARAMS = -2,
39
+ SP800_185_ERROR_INIT_FAILED = -3,
40
+ SP800_185_ERROR_INVALID_STATE = -4
41
+ } sp800_185_error_t;
42
+
43
+ /* Parameter structures for different algorithms */
44
+ typedef struct {
45
+ size_t capacity;
46
+ const BitSequence *N;
47
+ size_t NLen;
48
+ const BitSequence *S;
49
+ size_t SLen;
50
+ } cshake_init_params_t;
51
+
52
+ typedef struct {
53
+ const BitSequence *key;
54
+ BitLength keyBitLen;
55
+ BitLength outputBitLen;
56
+ const BitSequence *customization;
57
+ BitLength customBitLen;
58
+ } kmac_init_params_t;
59
+
34
60
  typedef struct {
35
61
  sp800_185_algorithm_t algorithm;
36
62
  const char *name;
37
63
  size_t state_size;
64
+ bool is_keyed; /* true for KMAC, false for CSHAKE */
38
65
 
39
- union {
40
- struct {
41
- sp800_185_init_fn init;
42
- sp800_185_update_fn update;
43
- sp800_185_final_fn final;
44
- sp800_185_squeeze_fn squeeze;
45
- } cshake;
46
-
47
- struct {
48
- sp800_185_init_key_fn init;
49
- sp800_185_update_fn update;
50
- sp800_185_final_fn final;
51
- sp800_185_squeeze_fn squeeze;
52
- } kmac;
53
- };
66
+ /* All algorithms use these same signatures */
67
+ sp800_185_update_fn update;
68
+ sp800_185_final_fn final;
69
+ sp800_185_squeeze_fn squeeze;
70
+
71
+ /* Generic initialization - let the caller handle parameter differences */
72
+ int (*init)(void *state, void *params);
54
73
  } sp800_185_function_table_t;
55
74
 
56
75
  /* Base context structure for SP800-185 algorithms */
@@ -64,6 +83,34 @@ typedef struct {
64
83
  /* Global variables */
65
84
  extern sp800_185_function_table_t sp800_185_functions[];
66
85
 
86
+ /* Algorithm lookup functions */
87
+ const sp800_185_function_table_t *sp800_185_get_algorithm(sp800_185_algorithm_t algorithm);
88
+ const sp800_185_function_table_t *sp800_185_get_algorithm_by_name(const char *name);
89
+
90
+ /* Safe accessor functions for algorithm-specific operations */
91
+ static inline int sp800_185_init_cshake(const sp800_185_function_table_t *table, void *state, size_t capacity,
92
+ const BitSequence *N, size_t NLen, const BitSequence *S, size_t SLen) {
93
+ if (!table || table->is_keyed) {
94
+ return SP800_185_ERROR_INVALID_ALGORITHM;
95
+ }
96
+ cshake_init_params_t params = {capacity, N, NLen, S, SLen};
97
+ return table->init(state, &params);
98
+ }
99
+
100
+ static inline int sp800_185_init_kmac(const sp800_185_function_table_t *table, void *state, const BitSequence *key,
101
+ BitLength keyBitLen, BitLength outputBitLen, const BitSequence *customization,
102
+ BitLength customBitLen) {
103
+ if (!table || !table->is_keyed) {
104
+ return SP800_185_ERROR_INVALID_ALGORITHM;
105
+ }
106
+ kmac_init_params_t params = {key, keyBitLen, outputBitLen, customization, customBitLen};
107
+ return table->init(state, &params);
108
+ }
109
+
110
+ /* Validation and utility functions */
111
+ bool sp800_185_validate_table(const sp800_185_function_table_t *table);
112
+ const char *sp800_185_algorithm_name(sp800_185_algorithm_t algorithm);
113
+
67
114
  extern sp800_185_context_t *sp800_185_alloc_context(size_t, size_t);
68
115
  extern size_t sp800_185_context_size(const sp800_185_context_t *, size_t);
69
116
  extern void sp800_185_free_context(sp800_185_context_t *);
@@ -77,16 +124,6 @@ VALUE sp800_185_squeeze(sp800_185_context_t *context, VALUE length);
77
124
  VALUE sp800_185_hex_squeeze(sp800_185_context_t *context, VALUE length);
78
125
  const char *sp800_185_name(sp800_185_context_t *context);
79
126
 
80
- // Macro to define common Ruby methods
81
- #define DEFINE_SP800_185_METHOD(name) static VALUE rb_sp800_185_##name(int argc, VALUE *argv, VALUE self);
82
-
83
- DEFINE_SP800_185_METHOD(update)
84
- DEFINE_SP800_185_METHOD(finish)
85
- DEFINE_SP800_185_METHOD(digest)
86
- DEFINE_SP800_185_METHOD(hexdigest)
87
- DEFINE_SP800_185_METHOD(squeeze)
88
- DEFINE_SP800_185_METHOD(hex_squeeze)
89
-
90
127
  #ifdef __cplusplus
91
128
  }
92
129
  #endif
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.0'
4
+ VERSION = '2.2.2'
5
5
  end
data/sha3.gemspec ADDED
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/constants'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'sha3'
7
+ spec.version = SHA3::VERSION
8
+
9
+ spec.authors = ['Johanns Gregorian']
10
+ spec.email = ['io+sha3@jsg.io']
11
+
12
+ spec.description = <<~EOF
13
+ A high-performance native binding to the SHA3 (FIPS 202) cryptographic hashing algorithms, based on the XKCP - eXtended Keccak Code Package.
14
+ This gem provides support for the standard SHA-3 fixed-length functions (224, 256, 384, and 512 bits),
15
+ as well as the SHAKE128/SHAKE256 extendable-output functions (XOFs), cSHAKE128/256, and KMAC as specified in NIST SP 800-185.'
16
+ EOF
17
+ spec.summary = 'SHA-3 (FIPS 202), SHAKE128/SHAKE256, cSHAKE128/cSHAKE256, and KMAC (NIST SP 800-185), powered by XKCP.'
18
+
19
+ spec.homepage = 'https://github.com/johanns/sha3'
20
+ spec.license = 'MIT'
21
+ spec.required_ruby_version = '>= 2.7.0'
22
+
23
+ spec.metadata['changelog_uri'] = "#{spec.homepage}/CHANGELOG.md"
24
+ spec.metadata['homepage_uri'] = spec.homepage
25
+ spec.metadata['documentation_uri'] = 'https://docs.jsg.io/sha3/index.html'
26
+
27
+ spec.post_install_message = <<-EOF
28
+ [NOTICE] SHA3 version 2.0 introduces breaking changes to the API.
29
+ Please review the changelog and ensure compatibility with your application.
30
+ If you need the previous behavior, lock your Gemfile to version '~> 1.0'."
31
+ EOF
32
+
33
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
34
+ `git ls-files -z`.split("\x0").reject do |f|
35
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git))})
36
+ end
37
+ end
38
+
39
+ spec.extensions = ['ext/sha3/extconf.rb']
40
+ spec.metadata['rubygems_mfa_required'] = 'true'
41
+
42
+ spec.cert_chain = ['certs/io+sha3@jsg.io.pem']
43
+ spec.signing_key = File.expand_path('~/.ssh/gem-private_key.pem') if $PROGRAM_NAME =~ /gem\z/
44
+ end
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.0
4
+ version: 2.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Johanns Gregorian
@@ -34,7 +34,7 @@ cert_chain:
34
34
  UjZtrp/rHLfHln46RvB+a1NlMRWxtJ7mQc/CMEbT+cpHlzuYa9qGakA4TmMpK10h
35
35
  uYUv/V6CD4iTEMby0dopwHt5NqE=
36
36
  -----END CERTIFICATE-----
37
- date: 2025-03-20 00:00:00.000000000 Z
37
+ date: 1980-01-02 00:00:00.000000000 Z
38
38
  dependencies: []
39
39
  description: |
40
40
  A high-performance native binding to the SHA3 (FIPS 202) cryptographic hashing algorithms, based on the XKCP - eXtended Keccak Code Package.
@@ -103,6 +103,7 @@ files:
103
103
  - ext/sha3/sp800_185.h
104
104
  - lib/constants.rb
105
105
  - lib/sha3.rb
106
+ - sha3.gemspec
106
107
  homepage: https://github.com/johanns/sha3
107
108
  licenses:
108
109
  - MIT
@@ -129,7 +130,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
130
  - !ruby/object:Gem::Version
130
131
  version: '0'
131
132
  requirements: []
132
- rubygems_version: 3.6.2
133
+ rubygems_version: 3.6.9
133
134
  specification_version: 4
134
135
  summary: SHA-3 (FIPS 202), SHAKE128/SHAKE256, cSHAKE128/cSHAKE256, and KMAC (NIST
135
136
  SP 800-185), powered by XKCP.
metadata.gz.sig CHANGED
Binary file