konpeito 0.1.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.
Files changed (180) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-version +1 -0
  3. data/CHANGELOG.md +75 -0
  4. data/CONTRIBUTING.md +123 -0
  5. data/LICENSE +21 -0
  6. data/README.md +257 -0
  7. data/Rakefile +11 -0
  8. data/bin/konpeito +6 -0
  9. data/konpeito.gemspec +43 -0
  10. data/lib/konpeito/ast/typed_ast.rb +620 -0
  11. data/lib/konpeito/ast/visitor.rb +78 -0
  12. data/lib/konpeito/cache/cache_manager.rb +230 -0
  13. data/lib/konpeito/cache/dependency_graph.rb +192 -0
  14. data/lib/konpeito/cache.rb +8 -0
  15. data/lib/konpeito/cli/base_command.rb +187 -0
  16. data/lib/konpeito/cli/build_command.rb +220 -0
  17. data/lib/konpeito/cli/check_command.rb +104 -0
  18. data/lib/konpeito/cli/config.rb +231 -0
  19. data/lib/konpeito/cli/deps_command.rb +128 -0
  20. data/lib/konpeito/cli/doctor_command.rb +340 -0
  21. data/lib/konpeito/cli/fmt_command.rb +199 -0
  22. data/lib/konpeito/cli/init_command.rb +312 -0
  23. data/lib/konpeito/cli/lsp_command.rb +40 -0
  24. data/lib/konpeito/cli/run_command.rb +150 -0
  25. data/lib/konpeito/cli/test_command.rb +248 -0
  26. data/lib/konpeito/cli/watch_command.rb +212 -0
  27. data/lib/konpeito/cli.rb +301 -0
  28. data/lib/konpeito/codegen/builtin_methods.rb +229 -0
  29. data/lib/konpeito/codegen/cruby_backend.rb +1090 -0
  30. data/lib/konpeito/codegen/debug_info.rb +352 -0
  31. data/lib/konpeito/codegen/inliner.rb +486 -0
  32. data/lib/konpeito/codegen/jvm_backend.rb +197 -0
  33. data/lib/konpeito/codegen/jvm_generator.rb +13412 -0
  34. data/lib/konpeito/codegen/llvm_generator.rb +13191 -0
  35. data/lib/konpeito/codegen/loop_optimizer.rb +363 -0
  36. data/lib/konpeito/codegen/monomorphizer.rb +359 -0
  37. data/lib/konpeito/codegen/profile_runtime.c +341 -0
  38. data/lib/konpeito/codegen/profiler.rb +99 -0
  39. data/lib/konpeito/compiler.rb +592 -0
  40. data/lib/konpeito/dependency_resolver.rb +296 -0
  41. data/lib/konpeito/diagnostics/collector.rb +127 -0
  42. data/lib/konpeito/diagnostics/diagnostic.rb +237 -0
  43. data/lib/konpeito/diagnostics/renderer.rb +144 -0
  44. data/lib/konpeito/formatter/formatter.rb +1214 -0
  45. data/lib/konpeito/hir/builder.rb +7167 -0
  46. data/lib/konpeito/hir/nodes.rb +2465 -0
  47. data/lib/konpeito/lsp/document_manager.rb +820 -0
  48. data/lib/konpeito/lsp/server.rb +183 -0
  49. data/lib/konpeito/lsp/transport.rb +38 -0
  50. data/lib/konpeito/parser/prism_adapter.rb +65 -0
  51. data/lib/konpeito/platform.rb +103 -0
  52. data/lib/konpeito/profile/report.rb +136 -0
  53. data/lib/konpeito/rbs_inline/preprocessor.rb +199 -0
  54. data/lib/konpeito/stdlib/compression/compression.rb +72 -0
  55. data/lib/konpeito/stdlib/compression/compression.rbs +60 -0
  56. data/lib/konpeito/stdlib/compression/compression_native.c +415 -0
  57. data/lib/konpeito/stdlib/compression/extconf.rb +19 -0
  58. data/lib/konpeito/stdlib/crypto/crypto.rb +85 -0
  59. data/lib/konpeito/stdlib/crypto/crypto.rbs +74 -0
  60. data/lib/konpeito/stdlib/crypto/crypto_native.c +312 -0
  61. data/lib/konpeito/stdlib/crypto/extconf.rb +40 -0
  62. data/lib/konpeito/stdlib/http/extconf.rb +19 -0
  63. data/lib/konpeito/stdlib/http/http.rb +125 -0
  64. data/lib/konpeito/stdlib/http/http.rbs +57 -0
  65. data/lib/konpeito/stdlib/http/http_native.c +440 -0
  66. data/lib/konpeito/stdlib/json/extconf.rb +17 -0
  67. data/lib/konpeito/stdlib/json/json.rb +44 -0
  68. data/lib/konpeito/stdlib/json/json.rbs +33 -0
  69. data/lib/konpeito/stdlib/json/json_native.c +286 -0
  70. data/lib/konpeito/stdlib/ui/extconf.rb +216 -0
  71. data/lib/konpeito/stdlib/ui/konpeito_ui_native.cpp +1625 -0
  72. data/lib/konpeito/stdlib/ui/konpeito_ui_native.h +162 -0
  73. data/lib/konpeito/stdlib/ui/ui.rb +318 -0
  74. data/lib/konpeito/stdlib/ui/ui.rbs +247 -0
  75. data/lib/konpeito/type_checker/annotation_parser.rb +67 -0
  76. data/lib/konpeito/type_checker/hm_inferrer.rb +2565 -0
  77. data/lib/konpeito/type_checker/inferrer.rb +565 -0
  78. data/lib/konpeito/type_checker/rbs_loader.rb +1621 -0
  79. data/lib/konpeito/type_checker/type_resolver.rb +276 -0
  80. data/lib/konpeito/type_checker/types.rb +1434 -0
  81. data/lib/konpeito/type_checker/unification.rb +323 -0
  82. data/lib/konpeito/ui/animation/animated_state.rb +80 -0
  83. data/lib/konpeito/ui/animation/easing.rb +59 -0
  84. data/lib/konpeito/ui/animation/value_tween.rb +66 -0
  85. data/lib/konpeito/ui/app.rb +379 -0
  86. data/lib/konpeito/ui/box.rb +38 -0
  87. data/lib/konpeito/ui/castella.rb +70 -0
  88. data/lib/konpeito/ui/castella_native.rb +76 -0
  89. data/lib/konpeito/ui/chart/area_chart.rb +305 -0
  90. data/lib/konpeito/ui/chart/bar_chart.rb +288 -0
  91. data/lib/konpeito/ui/chart/base_chart.rb +210 -0
  92. data/lib/konpeito/ui/chart/chart_helpers.rb +79 -0
  93. data/lib/konpeito/ui/chart/gauge_chart.rb +171 -0
  94. data/lib/konpeito/ui/chart/heatmap_chart.rb +222 -0
  95. data/lib/konpeito/ui/chart/line_chart.rb +289 -0
  96. data/lib/konpeito/ui/chart/pie_chart.rb +219 -0
  97. data/lib/konpeito/ui/chart/scales.rb +77 -0
  98. data/lib/konpeito/ui/chart/scatter_chart.rb +303 -0
  99. data/lib/konpeito/ui/chart/stacked_bar_chart.rb +276 -0
  100. data/lib/konpeito/ui/column.rb +271 -0
  101. data/lib/konpeito/ui/core.rb +2199 -0
  102. data/lib/konpeito/ui/dsl.rb +443 -0
  103. data/lib/konpeito/ui/frame.rb +171 -0
  104. data/lib/konpeito/ui/frame_native.rb +494 -0
  105. data/lib/konpeito/ui/markdown/ast.rb +124 -0
  106. data/lib/konpeito/ui/markdown/mermaid/layout.rb +387 -0
  107. data/lib/konpeito/ui/markdown/mermaid/models.rb +232 -0
  108. data/lib/konpeito/ui/markdown/mermaid/parser.rb +519 -0
  109. data/lib/konpeito/ui/markdown/mermaid/renderer.rb +336 -0
  110. data/lib/konpeito/ui/markdown/parser.rb +805 -0
  111. data/lib/konpeito/ui/markdown/renderer.rb +639 -0
  112. data/lib/konpeito/ui/markdown/theme.rb +165 -0
  113. data/lib/konpeito/ui/render_node.rb +260 -0
  114. data/lib/konpeito/ui/row.rb +207 -0
  115. data/lib/konpeito/ui/spacer.rb +18 -0
  116. data/lib/konpeito/ui/style.rb +799 -0
  117. data/lib/konpeito/ui/theme.rb +563 -0
  118. data/lib/konpeito/ui/themes/material.rb +35 -0
  119. data/lib/konpeito/ui/themes/tokyo_night.rb +6 -0
  120. data/lib/konpeito/ui/widgets/button.rb +103 -0
  121. data/lib/konpeito/ui/widgets/calendar.rb +1034 -0
  122. data/lib/konpeito/ui/widgets/checkbox.rb +119 -0
  123. data/lib/konpeito/ui/widgets/container.rb +91 -0
  124. data/lib/konpeito/ui/widgets/data_table.rb +667 -0
  125. data/lib/konpeito/ui/widgets/divider.rb +29 -0
  126. data/lib/konpeito/ui/widgets/image.rb +105 -0
  127. data/lib/konpeito/ui/widgets/input.rb +485 -0
  128. data/lib/konpeito/ui/widgets/markdown.rb +57 -0
  129. data/lib/konpeito/ui/widgets/modal.rb +163 -0
  130. data/lib/konpeito/ui/widgets/multiline_input.rb +968 -0
  131. data/lib/konpeito/ui/widgets/multiline_text.rb +180 -0
  132. data/lib/konpeito/ui/widgets/net_image.rb +100 -0
  133. data/lib/konpeito/ui/widgets/progress_bar.rb +70 -0
  134. data/lib/konpeito/ui/widgets/radio_buttons.rb +93 -0
  135. data/lib/konpeito/ui/widgets/slider.rb +133 -0
  136. data/lib/konpeito/ui/widgets/switch.rb +84 -0
  137. data/lib/konpeito/ui/widgets/tabs.rb +157 -0
  138. data/lib/konpeito/ui/widgets/text.rb +110 -0
  139. data/lib/konpeito/ui/widgets/tree.rb +426 -0
  140. data/lib/konpeito/version.rb +5 -0
  141. data/lib/konpeito.rb +109 -0
  142. data/test_native_array.rb +172 -0
  143. data/test_native_array_class.rb +197 -0
  144. data/test_native_class.rb +151 -0
  145. data/tools/konpeito-asm/build.sh +65 -0
  146. data/tools/konpeito-asm/lib/asm-9.7.1.jar +0 -0
  147. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KArray.class +0 -0
  148. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCompression.class +0 -0
  149. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KConditionVariable.class +0 -0
  150. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCrypto.class +0 -0
  151. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KFile.class +0 -0
  152. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHTTP.class +0 -0
  153. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHash.class +0 -0
  154. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON$Parser.class +0 -0
  155. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON.class +0 -0
  156. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KMath.class +0 -0
  157. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactor.class +0 -0
  158. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactorPort.class +0 -0
  159. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KSizedQueue.class +0 -0
  160. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KThread.class +0 -0
  161. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KTime.class +0 -0
  162. data/tools/konpeito-asm/runtime-classes/konpeito/runtime/RubyDispatch.class +0 -0
  163. data/tools/konpeito-asm/src/ClassIntrospector.java +312 -0
  164. data/tools/konpeito-asm/src/KonpeitoAssembler.java +659 -0
  165. data/tools/konpeito-asm/src/konpeito/runtime/KArray.java +390 -0
  166. data/tools/konpeito-asm/src/konpeito/runtime/KCompression.java +168 -0
  167. data/tools/konpeito-asm/src/konpeito/runtime/KConditionVariable.java +48 -0
  168. data/tools/konpeito-asm/src/konpeito/runtime/KCrypto.java +151 -0
  169. data/tools/konpeito-asm/src/konpeito/runtime/KFile.java +100 -0
  170. data/tools/konpeito-asm/src/konpeito/runtime/KHTTP.java +113 -0
  171. data/tools/konpeito-asm/src/konpeito/runtime/KHash.java +228 -0
  172. data/tools/konpeito-asm/src/konpeito/runtime/KJSON.java +405 -0
  173. data/tools/konpeito-asm/src/konpeito/runtime/KMath.java +54 -0
  174. data/tools/konpeito-asm/src/konpeito/runtime/KRactor.java +244 -0
  175. data/tools/konpeito-asm/src/konpeito/runtime/KRactorPort.java +53 -0
  176. data/tools/konpeito-asm/src/konpeito/runtime/KSizedQueue.java +49 -0
  177. data/tools/konpeito-asm/src/konpeito/runtime/KThread.java +49 -0
  178. data/tools/konpeito-asm/src/konpeito/runtime/KTime.java +53 -0
  179. data/tools/konpeito-asm/src/konpeito/runtime/RubyDispatch.java +416 -0
  180. metadata +267 -0
@@ -0,0 +1,312 @@
1
+ /*
2
+ * Konpeito Crypto stdlib - OpenSSL wrapper
3
+ *
4
+ * Provides cryptographic functionality using OpenSSL.
5
+ * Supports SHA256, SHA512, HMAC, and secure random bytes.
6
+ */
7
+
8
+ #include <ruby.h>
9
+ #include <openssl/sha.h>
10
+ #include <openssl/hmac.h>
11
+ #include <openssl/rand.h>
12
+ #include <openssl/evp.h>
13
+ #include <string.h>
14
+
15
+ /*
16
+ * Convert binary data to hex string
17
+ */
18
+ static VALUE binary_to_hex(const unsigned char *data, size_t len) {
19
+ char *hex = malloc(len * 2 + 1);
20
+ if (!hex) {
21
+ rb_raise(rb_eNoMemError, "Failed to allocate hex string");
22
+ return Qnil;
23
+ }
24
+
25
+ for (size_t i = 0; i < len; i++) {
26
+ sprintf(hex + i * 2, "%02x", data[i]);
27
+ }
28
+ hex[len * 2] = '\0';
29
+
30
+ VALUE result = rb_utf8_str_new(hex, len * 2);
31
+ free(hex);
32
+ return result;
33
+ }
34
+
35
+ /*
36
+ * Compute SHA256 hash
37
+ *
38
+ * @param data [String] Data to hash
39
+ * @return [String] Hex-encoded SHA256 hash (64 characters)
40
+ */
41
+ VALUE konpeito_crypto_sha256(VALUE self, VALUE data) {
42
+ Check_Type(data, T_STRING);
43
+
44
+ const unsigned char *input = (const unsigned char *)RSTRING_PTR(data);
45
+ size_t input_len = RSTRING_LEN(data);
46
+
47
+ unsigned char hash[SHA256_DIGEST_LENGTH];
48
+ SHA256(input, input_len, hash);
49
+
50
+ return binary_to_hex(hash, SHA256_DIGEST_LENGTH);
51
+ }
52
+
53
+ /*
54
+ * Compute SHA256 hash (binary output)
55
+ *
56
+ * @param data [String] Data to hash
57
+ * @return [String] Binary SHA256 hash (32 bytes)
58
+ */
59
+ VALUE konpeito_crypto_sha256_binary(VALUE self, VALUE data) {
60
+ Check_Type(data, T_STRING);
61
+
62
+ const unsigned char *input = (const unsigned char *)RSTRING_PTR(data);
63
+ size_t input_len = RSTRING_LEN(data);
64
+
65
+ unsigned char hash[SHA256_DIGEST_LENGTH];
66
+ SHA256(input, input_len, hash);
67
+
68
+ return rb_str_new((const char *)hash, SHA256_DIGEST_LENGTH);
69
+ }
70
+
71
+ /*
72
+ * Compute SHA512 hash
73
+ *
74
+ * @param data [String] Data to hash
75
+ * @return [String] Hex-encoded SHA512 hash (128 characters)
76
+ */
77
+ VALUE konpeito_crypto_sha512(VALUE self, VALUE data) {
78
+ Check_Type(data, T_STRING);
79
+
80
+ const unsigned char *input = (const unsigned char *)RSTRING_PTR(data);
81
+ size_t input_len = RSTRING_LEN(data);
82
+
83
+ unsigned char hash[SHA512_DIGEST_LENGTH];
84
+ SHA512(input, input_len, hash);
85
+
86
+ return binary_to_hex(hash, SHA512_DIGEST_LENGTH);
87
+ }
88
+
89
+ /*
90
+ * Compute SHA512 hash (binary output)
91
+ *
92
+ * @param data [String] Data to hash
93
+ * @return [String] Binary SHA512 hash (64 bytes)
94
+ */
95
+ VALUE konpeito_crypto_sha512_binary(VALUE self, VALUE data) {
96
+ Check_Type(data, T_STRING);
97
+
98
+ const unsigned char *input = (const unsigned char *)RSTRING_PTR(data);
99
+ size_t input_len = RSTRING_LEN(data);
100
+
101
+ unsigned char hash[SHA512_DIGEST_LENGTH];
102
+ SHA512(input, input_len, hash);
103
+
104
+ return rb_str_new((const char *)hash, SHA512_DIGEST_LENGTH);
105
+ }
106
+
107
+ /*
108
+ * Compute HMAC-SHA256
109
+ *
110
+ * @param key [String] Secret key
111
+ * @param data [String] Data to authenticate
112
+ * @return [String] Hex-encoded HMAC-SHA256 (64 characters)
113
+ */
114
+ VALUE konpeito_crypto_hmac_sha256(VALUE self, VALUE key, VALUE data) {
115
+ Check_Type(key, T_STRING);
116
+ Check_Type(data, T_STRING);
117
+
118
+ const unsigned char *key_ptr = (const unsigned char *)RSTRING_PTR(key);
119
+ size_t key_len = RSTRING_LEN(key);
120
+ const unsigned char *data_ptr = (const unsigned char *)RSTRING_PTR(data);
121
+ size_t data_len = RSTRING_LEN(data);
122
+
123
+ unsigned char result[EVP_MAX_MD_SIZE];
124
+ unsigned int result_len;
125
+
126
+ HMAC(EVP_sha256(), key_ptr, (int)key_len, data_ptr, data_len, result, &result_len);
127
+
128
+ return binary_to_hex(result, result_len);
129
+ }
130
+
131
+ /*
132
+ * Compute HMAC-SHA256 (binary output)
133
+ *
134
+ * @param key [String] Secret key
135
+ * @param data [String] Data to authenticate
136
+ * @return [String] Binary HMAC-SHA256 (32 bytes)
137
+ */
138
+ VALUE konpeito_crypto_hmac_sha256_binary(VALUE self, VALUE key, VALUE data) {
139
+ Check_Type(key, T_STRING);
140
+ Check_Type(data, T_STRING);
141
+
142
+ const unsigned char *key_ptr = (const unsigned char *)RSTRING_PTR(key);
143
+ size_t key_len = RSTRING_LEN(key);
144
+ const unsigned char *data_ptr = (const unsigned char *)RSTRING_PTR(data);
145
+ size_t data_len = RSTRING_LEN(data);
146
+
147
+ unsigned char result[EVP_MAX_MD_SIZE];
148
+ unsigned int result_len;
149
+
150
+ HMAC(EVP_sha256(), key_ptr, (int)key_len, data_ptr, data_len, result, &result_len);
151
+
152
+ return rb_str_new((const char *)result, result_len);
153
+ }
154
+
155
+ /*
156
+ * Compute HMAC-SHA512
157
+ *
158
+ * @param key [String] Secret key
159
+ * @param data [String] Data to authenticate
160
+ * @return [String] Hex-encoded HMAC-SHA512 (128 characters)
161
+ */
162
+ VALUE konpeito_crypto_hmac_sha512(VALUE self, VALUE key, VALUE data) {
163
+ Check_Type(key, T_STRING);
164
+ Check_Type(data, T_STRING);
165
+
166
+ const unsigned char *key_ptr = (const unsigned char *)RSTRING_PTR(key);
167
+ size_t key_len = RSTRING_LEN(key);
168
+ const unsigned char *data_ptr = (const unsigned char *)RSTRING_PTR(data);
169
+ size_t data_len = RSTRING_LEN(data);
170
+
171
+ unsigned char result[EVP_MAX_MD_SIZE];
172
+ unsigned int result_len;
173
+
174
+ HMAC(EVP_sha512(), key_ptr, (int)key_len, data_ptr, data_len, result, &result_len);
175
+
176
+ return binary_to_hex(result, result_len);
177
+ }
178
+
179
+ /*
180
+ * Generate cryptographically secure random bytes
181
+ *
182
+ * @param count [Integer] Number of bytes to generate
183
+ * @return [String] Binary string of random bytes
184
+ * @raise [RuntimeError] if random generation fails
185
+ */
186
+ VALUE konpeito_crypto_random_bytes(VALUE self, VALUE count) {
187
+ int num_bytes = NUM2INT(count);
188
+
189
+ if (num_bytes <= 0) {
190
+ rb_raise(rb_eArgError, "count must be positive");
191
+ return Qnil;
192
+ }
193
+
194
+ if (num_bytes > 1024 * 1024) { /* 1MB limit */
195
+ rb_raise(rb_eArgError, "count too large (max 1MB)");
196
+ return Qnil;
197
+ }
198
+
199
+ unsigned char *buf = malloc(num_bytes);
200
+ if (!buf) {
201
+ rb_raise(rb_eNoMemError, "Failed to allocate random buffer");
202
+ return Qnil;
203
+ }
204
+
205
+ if (RAND_bytes(buf, num_bytes) != 1) {
206
+ free(buf);
207
+ rb_raise(rb_eRuntimeError, "Failed to generate random bytes");
208
+ return Qnil;
209
+ }
210
+
211
+ VALUE result = rb_str_new((const char *)buf, num_bytes);
212
+ free(buf);
213
+
214
+ return result;
215
+ }
216
+
217
+ /*
218
+ * Generate cryptographically secure random bytes as hex string
219
+ *
220
+ * @param count [Integer] Number of bytes to generate (output will be 2x this length)
221
+ * @return [String] Hex-encoded random bytes
222
+ * @raise [RuntimeError] if random generation fails
223
+ */
224
+ VALUE konpeito_crypto_random_hex(VALUE self, VALUE count) {
225
+ int num_bytes = NUM2INT(count);
226
+
227
+ if (num_bytes <= 0) {
228
+ rb_raise(rb_eArgError, "count must be positive");
229
+ return Qnil;
230
+ }
231
+
232
+ if (num_bytes > 1024 * 1024) { /* 1MB limit */
233
+ rb_raise(rb_eArgError, "count too large (max 1MB)");
234
+ return Qnil;
235
+ }
236
+
237
+ unsigned char *buf = malloc(num_bytes);
238
+ if (!buf) {
239
+ rb_raise(rb_eNoMemError, "Failed to allocate random buffer");
240
+ return Qnil;
241
+ }
242
+
243
+ if (RAND_bytes(buf, num_bytes) != 1) {
244
+ free(buf);
245
+ rb_raise(rb_eRuntimeError, "Failed to generate random bytes");
246
+ return Qnil;
247
+ }
248
+
249
+ VALUE result = binary_to_hex(buf, num_bytes);
250
+ free(buf);
251
+
252
+ return result;
253
+ }
254
+
255
+ /*
256
+ * Constant-time comparison of two strings
257
+ * Prevents timing attacks when comparing secrets
258
+ *
259
+ * @param a [String] First string
260
+ * @param b [String] Second string
261
+ * @return [Boolean] true if strings are equal, false otherwise
262
+ */
263
+ VALUE konpeito_crypto_secure_compare(VALUE self, VALUE a, VALUE b) {
264
+ Check_Type(a, T_STRING);
265
+ Check_Type(b, T_STRING);
266
+
267
+ size_t a_len = RSTRING_LEN(a);
268
+ size_t b_len = RSTRING_LEN(b);
269
+
270
+ /* Length must match */
271
+ if (a_len != b_len) {
272
+ return Qfalse;
273
+ }
274
+
275
+ const unsigned char *a_ptr = (const unsigned char *)RSTRING_PTR(a);
276
+ const unsigned char *b_ptr = (const unsigned char *)RSTRING_PTR(b);
277
+
278
+ /* Constant-time comparison */
279
+ unsigned char result = 0;
280
+ for (size_t i = 0; i < a_len; i++) {
281
+ result |= a_ptr[i] ^ b_ptr[i];
282
+ }
283
+
284
+ return result == 0 ? Qtrue : Qfalse;
285
+ }
286
+
287
+ /* Module initialization */
288
+ void Init_konpeito_crypto(void) {
289
+ VALUE mKonpeitoCrypto = rb_define_module("KonpeitoCrypto");
290
+
291
+ /* Hash functions (hex output) */
292
+ rb_define_module_function(mKonpeitoCrypto, "sha256", konpeito_crypto_sha256, 1);
293
+ rb_define_module_function(mKonpeitoCrypto, "sha512", konpeito_crypto_sha512, 1);
294
+
295
+ /* Hash functions (binary output) */
296
+ rb_define_module_function(mKonpeitoCrypto, "sha256_binary", konpeito_crypto_sha256_binary, 1);
297
+ rb_define_module_function(mKonpeitoCrypto, "sha512_binary", konpeito_crypto_sha512_binary, 1);
298
+
299
+ /* HMAC functions (hex output) */
300
+ rb_define_module_function(mKonpeitoCrypto, "hmac_sha256", konpeito_crypto_hmac_sha256, 2);
301
+ rb_define_module_function(mKonpeitoCrypto, "hmac_sha512", konpeito_crypto_hmac_sha512, 2);
302
+
303
+ /* HMAC functions (binary output) */
304
+ rb_define_module_function(mKonpeitoCrypto, "hmac_sha256_binary", konpeito_crypto_hmac_sha256_binary, 2);
305
+
306
+ /* Random generation */
307
+ rb_define_module_function(mKonpeitoCrypto, "random_bytes", konpeito_crypto_random_bytes, 1);
308
+ rb_define_module_function(mKonpeitoCrypto, "random_hex", konpeito_crypto_random_hex, 1);
309
+
310
+ /* Utilities */
311
+ rb_define_module_function(mKonpeitoCrypto, "secure_compare", konpeito_crypto_secure_compare, 2);
312
+ }
@@ -0,0 +1,40 @@
1
+ # extconf.rb for konpeito_crypto
2
+ require 'mkmf'
3
+
4
+ # Check for OpenSSL
5
+ # macOS: Uses LibreSSL or OpenSSL from Homebrew
6
+ # Linux: Uses system OpenSSL
7
+
8
+ # Try to find OpenSSL (Homebrew on macOS)
9
+ openssl_dir = nil
10
+ ['/opt/homebrew/opt/openssl@3', '/opt/homebrew/opt/openssl', '/usr/local/opt/openssl'].each do |dir|
11
+ if File.directory?(dir)
12
+ openssl_dir = dir
13
+ break
14
+ end
15
+ end
16
+
17
+ if openssl_dir
18
+ $INCFLAGS << " -I#{openssl_dir}/include"
19
+ $LDFLAGS << " -L#{openssl_dir}/lib"
20
+ end
21
+
22
+ # Check for required libraries and headers
23
+ unless have_library('crypto') && have_header('openssl/sha.h')
24
+ abort <<~MSG
25
+ OpenSSL (libcrypto) is required for KonpeitoCrypto.
26
+
27
+ Installation:
28
+ macOS: brew install openssl
29
+ Ubuntu: sudo apt-get install libssl-dev
30
+ Fedora: sudo dnf install openssl-devel
31
+
32
+ If OpenSSL is installed but not found, try:
33
+ macOS: export PKG_CONFIG_PATH="/opt/homebrew/opt/openssl@3/lib/pkgconfig"
34
+ MSG
35
+ end
36
+
37
+ # Optimization flags
38
+ $CFLAGS << ' -O3'
39
+
40
+ create_makefile('konpeito_crypto')
@@ -0,0 +1,19 @@
1
+ # extconf.rb for konpeito_http
2
+ require 'mkmf'
3
+
4
+ # Check for libcurl
5
+ unless have_library('curl') && have_header('curl/curl.h')
6
+ abort <<~MSG
7
+ libcurl is required for KonpeitoHTTP.
8
+
9
+ Installation:
10
+ macOS: brew install curl
11
+ Ubuntu: sudo apt-get install libcurl4-openssl-dev
12
+ Fedora: sudo dnf install libcurl-devel
13
+ MSG
14
+ end
15
+
16
+ # Optimization flags
17
+ $CFLAGS << ' -O3'
18
+
19
+ create_makefile('konpeito_http')
@@ -0,0 +1,125 @@
1
+ # KonpeitoHTTP - Fast HTTP client using libcurl
2
+ #
3
+ # This module provides HTTP client functionality using the libcurl C library.
4
+ # It is implemented as a C extension for maximum performance.
5
+ #
6
+ # Usage:
7
+ # require 'konpeito/stdlib/http'
8
+ #
9
+ # # Simple GET request
10
+ # body = KonpeitoHTTP.get("https://example.com")
11
+ #
12
+ # # Simple POST request
13
+ # body = KonpeitoHTTP.post("https://api.example.com/data", '{"key": "value"}')
14
+ #
15
+ # # GET with full response details
16
+ # response = KonpeitoHTTP.get_response("https://example.com")
17
+ # puts response[:status] # => 200
18
+ # puts response[:body] # => "<!doctype html>..."
19
+ # puts response[:headers] # => {"Content-Type" => "text/html", ...}
20
+ #
21
+ # # POST with Content-Type
22
+ # response = KonpeitoHTTP.post_response(
23
+ # "https://api.example.com/json",
24
+ # '{"name": "Alice"}',
25
+ # "application/json"
26
+ # )
27
+ #
28
+ # # Generic request with custom method and headers
29
+ # response = KonpeitoHTTP.request(
30
+ # "PUT",
31
+ # "https://api.example.com/resource/123",
32
+ # '{"updated": true}',
33
+ # {"Authorization" => "Bearer token", "Content-Type" => "application/json"}
34
+ # )
35
+
36
+ # Try to load the native extension
37
+ begin
38
+ require_relative 'konpeito_http'
39
+ rescue LoadError => e
40
+ # Fallback to net/http if native extension is not available
41
+ require 'net/http'
42
+ require 'uri'
43
+
44
+ module KonpeitoHTTP
45
+ class << self
46
+ def get(url)
47
+ uri = URI.parse(url)
48
+ Net::HTTP.get(uri)
49
+ end
50
+
51
+ def post(url, body)
52
+ uri = URI.parse(url)
53
+ http = Net::HTTP.new(uri.host, uri.port)
54
+ http.use_ssl = (uri.scheme == 'https')
55
+ request = Net::HTTP::Post.new(uri.request_uri)
56
+ request.body = body
57
+ response = http.request(request)
58
+ response.body
59
+ end
60
+
61
+ def get_response(url)
62
+ uri = URI.parse(url)
63
+ http = Net::HTTP.new(uri.host, uri.port)
64
+ http.use_ssl = (uri.scheme == 'https')
65
+ response = http.get(uri.request_uri)
66
+ headers = {}
67
+ response.each_header { |k, v| headers[k] = v }
68
+ {
69
+ status: response.code.to_i,
70
+ body: response.body,
71
+ headers: headers
72
+ }
73
+ end
74
+
75
+ def post_response(url, body, content_type = nil)
76
+ uri = URI.parse(url)
77
+ http = Net::HTTP.new(uri.host, uri.port)
78
+ http.use_ssl = (uri.scheme == 'https')
79
+ request = Net::HTTP::Post.new(uri.request_uri)
80
+ request.body = body
81
+ request['Content-Type'] = content_type if content_type
82
+ response = http.request(request)
83
+ headers = {}
84
+ response.each_header { |k, v| headers[k] = v }
85
+ {
86
+ status: response.code.to_i,
87
+ body: response.body,
88
+ headers: headers
89
+ }
90
+ end
91
+
92
+ def request(method, url, body = nil, headers = nil)
93
+ uri = URI.parse(url)
94
+ http = Net::HTTP.new(uri.host, uri.port)
95
+ http.use_ssl = (uri.scheme == 'https')
96
+
97
+ request_class = case method.upcase
98
+ when 'GET' then Net::HTTP::Get
99
+ when 'POST' then Net::HTTP::Post
100
+ when 'PUT' then Net::HTTP::Put
101
+ when 'DELETE' then Net::HTTP::Delete
102
+ when 'PATCH' then Net::HTTP::Patch
103
+ when 'HEAD' then Net::HTTP::Head
104
+ else
105
+ raise ArgumentError, "Unknown HTTP method: #{method}"
106
+ end
107
+
108
+ request = request_class.new(uri.request_uri)
109
+ request.body = body if body
110
+ headers&.each { |k, v| request[k] = v }
111
+
112
+ response = http.request(request)
113
+ response_headers = {}
114
+ response.each_header { |k, v| response_headers[k] = v }
115
+ {
116
+ status: response.code.to_i,
117
+ body: response.body,
118
+ headers: response_headers
119
+ }
120
+ end
121
+ end
122
+ end
123
+
124
+ warn "KonpeitoHTTP: Native extension not available, using net/http fallback (#{e.message})"
125
+ end
@@ -0,0 +1,57 @@
1
+ # KonpeitoHTTP - Fast HTTP client using libcurl
2
+ #
3
+ # Usage:
4
+ # # Simple GET (returns body only)
5
+ # body = KonpeitoHTTP.get("https://example.com")
6
+ #
7
+ # # Simple POST (returns body only)
8
+ # body = KonpeitoHTTP.post("https://api.example.com/data", '{"key": "value"}')
9
+ #
10
+ # # GET with full response
11
+ # response = KonpeitoHTTP.get_response("https://example.com")
12
+ # response[:status] # => 200
13
+ # response[:body] # => "<!doctype html>..."
14
+ # response[:headers] # => {"Content-Type" => "text/html", ...}
15
+ #
16
+ # # Generic request with custom headers
17
+ # response = KonpeitoHTTP.request("PUT", "https://api.example.com/resource",
18
+ # '{"data": "value"}',
19
+ # {"Authorization" => "Bearer token"})
20
+
21
+ module KonpeitoHTTP
22
+ # Perform HTTP GET request (simple, returns body only)
23
+ # @param url [String] URL to fetch
24
+ # @return [String] Response body
25
+ # @raise [RuntimeError] if request fails
26
+ def self.get: (String url) -> String
27
+
28
+ # Perform HTTP POST request (simple, returns body only)
29
+ # @param url [String] URL to post to
30
+ # @param body [String] Request body
31
+ # @return [String] Response body
32
+ # @raise [RuntimeError] if request fails
33
+ def self.post: (String url, String body) -> String
34
+
35
+ # Perform HTTP GET request with full response
36
+ # @param url [String] URL to fetch
37
+ # @return [Hash] Response with :status (Integer), :body (String), :headers (Hash)
38
+ # @raise [RuntimeError] if request fails
39
+ def self.get_response: (String url) -> Hash[Symbol, untyped]
40
+
41
+ # Perform HTTP POST request with full response
42
+ # @param url [String] URL to post to
43
+ # @param body [String] Request body
44
+ # @param content_type [String?] Content-Type header (optional)
45
+ # @return [Hash] Response with :status (Integer), :body (String), :headers (Hash)
46
+ # @raise [RuntimeError] if request fails
47
+ def self.post_response: (String url, String body, String? content_type) -> Hash[Symbol, untyped]
48
+
49
+ # Perform HTTP request with custom method and headers
50
+ # @param method [String] HTTP method (GET, POST, PUT, DELETE, PATCH, HEAD)
51
+ # @param url [String] URL
52
+ # @param body [String?] Request body (optional)
53
+ # @param headers [Hash?] Custom headers (optional)
54
+ # @return [Hash] Response with :status (Integer), :body (String), :headers (Hash)
55
+ # @raise [RuntimeError] if request fails
56
+ def self.request: (String method, String url, String? body, Hash[String, String]? headers) -> Hash[Symbol, untyped]
57
+ end