Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)
ossl_bn.c
Go to the documentation of this file.
1/*
2 * 'OpenSSL for Ruby' project
3 * Copyright (C) 2001-2002 Technorama team <oss-ruby@technorama.net>
4 * All rights reserved.
5 */
6/*
7 * This program is licensed under the same licence as Ruby.
8 * (See the file 'LICENCE'.)
9 */
10/* modified by Michal Rokos <m.rokos@sh.cvut.cz> */
11#include "ossl.h"
12
13#if HAVE_RB_EXT_RACTOR_SAFE
14#include <ruby/ractor.h>
15#endif
16
17#define NewBN(klass) \
18 TypedData_Wrap_Struct((klass), &ossl_bn_type, 0)
19#define SetBN(obj, bn) do { \
20 if (!(bn)) { \
21 ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
22 } \
23 RTYPEDDATA_DATA(obj) = (bn); \
24} while (0)
25
26#define GetBN(obj, bn) do { \
27 TypedData_Get_Struct((obj), BIGNUM, &ossl_bn_type, (bn)); \
28 if (!(bn)) { \
29 ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
30 } \
31} while (0)
32
33static void
34ossl_bn_free(void *ptr)
35{
36 BN_clear_free(ptr);
37}
38
39static const rb_data_type_t ossl_bn_type = {
40 "OpenSSL/BN",
41 {
42 0, ossl_bn_free,
43 },
45};
46
47/*
48 * Classes
49 */
51
52/* Document-class: OpenSSL::BNError
53 *
54 * Generic Error for all of OpenSSL::BN (big num)
55 */
57
58/*
59 * Public
60 */
62ossl_bn_new(const BIGNUM *bn)
63{
64 BIGNUM *newbn;
65 VALUE obj;
66
67 obj = NewBN(cBN);
68 newbn = bn ? BN_dup(bn) : BN_new();
69 if (!newbn) {
71 }
72 SetBN(obj, newbn);
73
74 return obj;
75}
76
77static BIGNUM *
78integer_to_bnptr(VALUE obj, BIGNUM *orig)
79{
80 BIGNUM *bn;
81
82 if (FIXNUM_P(obj)) {
83 long i;
84 unsigned char bin[sizeof(long)];
85 long n = FIX2LONG(obj);
86 unsigned long un = labs(n);
87
88 for (i = sizeof(long) - 1; 0 <= i; i--) {
89 bin[i] = un & 0xff;
90 un >>= 8;
91 }
92
93 bn = BN_bin2bn(bin, sizeof(bin), orig);
94 if (!bn)
95 ossl_raise(eBNError, "BN_bin2bn");
96 if (n < 0)
97 BN_set_negative(bn, 1);
98 }
99 else { /* assuming Bignum */
100 size_t len = rb_absint_size(obj, NULL);
101 unsigned char *bin;
102 VALUE buf;
103 int sign;
104
105 if (INT_MAX < len) {
106 rb_raise(eBNError, "bignum too long");
107 }
108 bin = (unsigned char*)ALLOCV_N(unsigned char, buf, len);
109 sign = rb_integer_pack(obj, bin, len, 1, 0, INTEGER_PACK_BIG_ENDIAN);
110
111 bn = BN_bin2bn(bin, (int)len, orig);
113 if (!bn)
114 ossl_raise(eBNError, "BN_bin2bn");
115 if (sign < 0)
116 BN_set_negative(bn, 1);
117 }
118
119 return bn;
120}
121
122static VALUE
123try_convert_to_bn(VALUE obj)
124{
125 BIGNUM *bn;
126 VALUE newobj = Qnil;
127
128 if (rb_obj_is_kind_of(obj, cBN))
129 return obj;
130 if (RB_INTEGER_TYPE_P(obj)) {
131 newobj = NewBN(cBN); /* Handle potential mem leaks */
132 bn = integer_to_bnptr(obj, NULL);
133 SetBN(newobj, bn);
134 }
135
136 return newobj;
137}
138
139BIGNUM *
141{
142 VALUE tmp;
143 BIGNUM *bn;
144
145 tmp = try_convert_to_bn(*ptr);
146 if (NIL_P(tmp))
147 ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN");
148 GetBN(tmp, bn);
149 *ptr = tmp;
150
151 return bn;
152}
153
154/*
155 * Private
156 */
157
158#if HAVE_RB_EXT_RACTOR_SAFE
159void
161{
162 BN_CTX *ctx = (BN_CTX *)ptr;
163 BN_CTX_free(ctx);
164}
165
166struct rb_ractor_local_storage_type ossl_bn_ctx_key_type = {
167 NULL, // mark
169};
170
171rb_ractor_local_key_t ossl_bn_ctx_key;
172
173BN_CTX *
174ossl_bn_ctx_get(void)
175{
176 // stored in ractor local storage
177
178 BN_CTX *ctx = rb_ractor_local_storage_ptr(ossl_bn_ctx_key);
179 if (!ctx) {
180 if (!(ctx = BN_CTX_new())) {
181 ossl_raise(rb_eRuntimeError, "Cannot init BN_CTX");
182 }
183 rb_ractor_local_storage_ptr_set(ossl_bn_ctx_key, ctx);
184 }
185 return ctx;
186}
187#else
188// for ruby 2.x
189static BN_CTX *gv_ossl_bn_ctx;
190
191BN_CTX *
193{
194 if (gv_ossl_bn_ctx == NULL) {
195 if (!(gv_ossl_bn_ctx = BN_CTX_new())) {
196 ossl_raise(rb_eRuntimeError, "Cannot init BN_CTX");
197 }
198 }
199 return gv_ossl_bn_ctx;
200}
201
202void
204{
205 BN_CTX_free(gv_ossl_bn_ctx);
206 gv_ossl_bn_ctx = NULL;
207}
208#endif
209
210static VALUE
211ossl_bn_alloc(VALUE klass)
212{
213 BIGNUM *bn;
214 VALUE obj = NewBN(klass);
215
216 if (!(bn = BN_new())) {
218 }
219 SetBN(obj, bn);
220
221 return obj;
222}
223
224/*
225 * call-seq:
226 * OpenSSL::BN.new(bn) => aBN
227 * OpenSSL::BN.new(integer) => aBN
228 * OpenSSL::BN.new(string) => aBN
229 * OpenSSL::BN.new(string, 0 | 2 | 10 | 16) => aBN
230 *
231 * Construct a new OpenSSL BIGNUM object.
232 */
233static VALUE
234ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
235{
236 BIGNUM *bn;
237 VALUE str, bs;
238 int base = 10;
239 char *ptr;
240
241 if (rb_scan_args(argc, argv, "11", &str, &bs) == 2) {
242 base = NUM2INT(bs);
243 }
244
245 if (NIL_P(str)) {
246 ossl_raise(rb_eArgError, "invalid argument");
247 }
248
249 if (RB_INTEGER_TYPE_P(str)) {
250 GetBN(self, bn);
251 integer_to_bnptr(str, bn);
252
253 return self;
254 }
255
257 BIGNUM *other;
258
259 GetBN(self, bn);
260 GetBN(str, other); /* Safe - we checked kind_of? above */
261 if (!BN_copy(bn, other)) {
263 }
264 return self;
265 }
266
267 GetBN(self, bn);
268 switch (base) {
269 case 0:
271 if (!BN_mpi2bn((unsigned char *)ptr, RSTRING_LENINT(str), bn)) {
273 }
274 break;
275 case 2:
277 if (!BN_bin2bn((unsigned char *)ptr, RSTRING_LENINT(str), bn)) {
279 }
280 break;
281 case 10:
282 if (!BN_dec2bn(&bn, StringValueCStr(str))) {
284 }
285 break;
286 case 16:
287 if (!BN_hex2bn(&bn, StringValueCStr(str))) {
289 }
290 break;
291 default:
292 ossl_raise(rb_eArgError, "invalid radix %d", base);
293 }
294 return self;
295}
296
297/*
298 * call-seq:
299 * bn.to_s => string
300 * bn.to_s(base) => string
301 *
302 * === Parameters
303 * * _base_ - Integer
304 * Valid values:
305 * * 0 - MPI
306 * * 2 - binary
307 * * 10 - the default
308 * * 16 - hex
309 */
310static VALUE
311ossl_bn_to_s(int argc, VALUE *argv, VALUE self)
312{
313 BIGNUM *bn;
314 VALUE str, bs;
315 int base = 10, len;
316 char *buf;
317
318 if (rb_scan_args(argc, argv, "01", &bs) == 1) {
319 base = NUM2INT(bs);
320 }
321 GetBN(self, bn);
322 switch (base) {
323 case 0:
324 len = BN_bn2mpi(bn, NULL);
325 str = rb_str_new(0, len);
326 if (BN_bn2mpi(bn, (unsigned char *)RSTRING_PTR(str)) != len)
328 break;
329 case 2:
330 len = BN_num_bytes(bn);
331 str = rb_str_new(0, len);
332 if (BN_bn2bin(bn, (unsigned char *)RSTRING_PTR(str)) != len)
334 break;
335 case 10:
336 if (!(buf = BN_bn2dec(bn))) ossl_raise(eBNError, NULL);
338 break;
339 case 16:
340 if (!(buf = BN_bn2hex(bn))) ossl_raise(eBNError, NULL);
342 break;
343 default:
344 ossl_raise(rb_eArgError, "invalid radix %d", base);
345 }
346
347 return str;
348}
349
350/*
351 * call-seq:
352 * bn.to_i => integer
353 */
354static VALUE
355ossl_bn_to_i(VALUE self)
356{
357 BIGNUM *bn;
358 char *txt;
359 VALUE num;
360
361 GetBN(self, bn);
362
363 if (!(txt = BN_bn2hex(bn))) {
365 }
366 num = rb_cstr_to_inum(txt, 16, Qtrue);
367 OPENSSL_free(txt);
368
369 return num;
370}
371
372static VALUE
373ossl_bn_to_bn(VALUE self)
374{
375 return self;
376}
377
378static VALUE
379ossl_bn_coerce(VALUE self, VALUE other)
380{
381 switch(TYPE(other)) {
382 case T_STRING:
383 self = ossl_bn_to_s(0, NULL, self);
384 break;
385 case T_FIXNUM:
386 case T_BIGNUM:
387 self = ossl_bn_to_i(self);
388 break;
389 default:
390 if (!RTEST(rb_obj_is_kind_of(other, cBN))) {
391 ossl_raise(rb_eTypeError, "Don't know how to coerce");
392 }
393 }
394 return rb_assoc_new(other, self);
395}
396
397#define BIGNUM_BOOL1(func) \
398 static VALUE \
399 ossl_bn_##func(VALUE self) \
400 { \
401 BIGNUM *bn; \
402 GetBN(self, bn); \
403 if (BN_##func(bn)) { \
404 return Qtrue; \
405 } \
406 return Qfalse; \
407 }
408
409/*
410 * Document-method: OpenSSL::BN#zero?
411 * call-seq:
412 * bn.zero? => true | false
413 */
414BIGNUM_BOOL1(is_zero)
415
416/*
417 * Document-method: OpenSSL::BN#one?
418 * call-seq:
419 * bn.one? => true | false
420 */
421BIGNUM_BOOL1(is_one)
422
423/*
424 * Document-method: OpenSSL::BN#odd?
425 * call-seq:
426 * bn.odd? => true | false
427 */
428BIGNUM_BOOL1(is_odd)
429
430/*
431 * call-seq:
432 * bn.negative? => true | false
433 */
434static VALUE
435ossl_bn_is_negative(VALUE self)
436{
437 BIGNUM *bn;
438
439 GetBN(self, bn);
440 if (BN_is_zero(bn))
441 return Qfalse;
442 return BN_is_negative(bn) ? Qtrue : Qfalse;
443}
444
445#define BIGNUM_1c(func) \
446 static VALUE \
447 ossl_bn_##func(VALUE self) \
448 { \
449 BIGNUM *bn, *result; \
450 VALUE obj; \
451 GetBN(self, bn); \
452 obj = NewBN(rb_obj_class(self)); \
453 if (!(result = BN_new())) { \
454 ossl_raise(eBNError, NULL); \
455 } \
456 if (BN_##func(result, bn, ossl_bn_ctx) <= 0) { \
457 BN_free(result); \
458 ossl_raise(eBNError, NULL); \
459 } \
460 SetBN(obj, result); \
461 return obj; \
462 }
463
464/*
465 * Document-method: OpenSSL::BN#sqr
466 * call-seq:
467 * bn.sqr => aBN
468 */
470
471#define BIGNUM_2(func) \
472 static VALUE \
473 ossl_bn_##func(VALUE self, VALUE other) \
474 { \
475 BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
476 VALUE obj; \
477 GetBN(self, bn1); \
478 obj = NewBN(rb_obj_class(self)); \
479 if (!(result = BN_new())) { \
480 ossl_raise(eBNError, NULL); \
481 } \
482 if (BN_##func(result, bn1, bn2) <= 0) { \
483 BN_free(result); \
484 ossl_raise(eBNError, NULL); \
485 } \
486 SetBN(obj, result); \
487 return obj; \
488 }
489
490/*
491 * Document-method: OpenSSL::BN#+
492 * call-seq:
493 * bn + bn2 => aBN
494 */
496
497/*
498 * Document-method: OpenSSL::BN#-
499 * call-seq:
500 * bn - bn2 => aBN
501 */
503
504#define BIGNUM_2c(func) \
505 static VALUE \
506 ossl_bn_##func(VALUE self, VALUE other) \
507 { \
508 BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
509 VALUE obj; \
510 GetBN(self, bn1); \
511 obj = NewBN(rb_obj_class(self)); \
512 if (!(result = BN_new())) { \
513 ossl_raise(eBNError, NULL); \
514 } \
515 if (BN_##func(result, bn1, bn2, ossl_bn_ctx) <= 0) { \
516 BN_free(result); \
517 ossl_raise(eBNError, NULL); \
518 } \
519 SetBN(obj, result); \
520 return obj; \
521 }
522
523/*
524 * Document-method: OpenSSL::BN#*
525 * call-seq:
526 * bn * bn2 => aBN
527 */
529
530/*
531 * Document-method: OpenSSL::BN#%
532 * call-seq:
533 * bn % bn2 => aBN
534 */
536
537/*
538 * Document-method: OpenSSL::BN#**
539 * call-seq:
540 * bn ** bn2 => aBN
541 */
542BIGNUM_2c(exp)
543
544/*
545 * Document-method: OpenSSL::BN#gcd
546 * call-seq:
547 * bn.gcd(bn2) => aBN
548 */
550
551/*
552 * Document-method: OpenSSL::BN#mod_sqr
553 * call-seq:
554 * bn.mod_sqr(bn2) => aBN
555 */
556BIGNUM_2c(mod_sqr)
557
558/*
559 * call-seq:
560 * bn.mod_inverse(bn2) => aBN
561 */
562static VALUE
563ossl_bn_mod_inverse(VALUE self, VALUE other)
564{
565 BIGNUM *bn1, *bn2 = GetBNPtr(other), *result;
566 VALUE obj;
567 GetBN(self, bn1);
568 obj = NewBN(rb_obj_class(self));
569 if (!(result = BN_mod_inverse(NULL, bn1, bn2, ossl_bn_ctx)))
570 ossl_raise(eBNError, "BN_mod_inverse");
571 SetBN(obj, result);
572 return obj;
573}
574
575/*
576 * call-seq:
577 * bn1 / bn2 => [result, remainder]
578 *
579 * Division of OpenSSL::BN instances
580 */
581static VALUE
582ossl_bn_div(VALUE self, VALUE other)
583{
584 BIGNUM *bn1, *bn2 = GetBNPtr(other), *r1, *r2;
585 VALUE klass, obj1, obj2;
586
587 GetBN(self, bn1);
588
589 klass = rb_obj_class(self);
590 obj1 = NewBN(klass);
591 obj2 = NewBN(klass);
592 if (!(r1 = BN_new())) {
594 }
595 if (!(r2 = BN_new())) {
596 BN_free(r1);
598 }
599 if (!BN_div(r1, r2, bn1, bn2, ossl_bn_ctx)) {
600 BN_free(r1);
601 BN_free(r2);
603 }
604 SetBN(obj1, r1);
605 SetBN(obj2, r2);
606
607 return rb_ary_new3(2, obj1, obj2);
608}
609
610#define BIGNUM_3c(func) \
611 static VALUE \
612 ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \
613 { \
614 BIGNUM *bn1, *bn2 = GetBNPtr(other1); \
615 BIGNUM *bn3 = GetBNPtr(other2), *result; \
616 VALUE obj; \
617 GetBN(self, bn1); \
618 obj = NewBN(rb_obj_class(self)); \
619 if (!(result = BN_new())) { \
620 ossl_raise(eBNError, NULL); \
621 } \
622 if (BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx) <= 0) { \
623 BN_free(result); \
624 ossl_raise(eBNError, NULL); \
625 } \
626 SetBN(obj, result); \
627 return obj; \
628 }
629
630/*
631 * Document-method: OpenSSL::BN#mod_add
632 * call-seq:
633 * bn.mod_add(bn1, bn2) -> aBN
634 */
635BIGNUM_3c(mod_add)
636
637/*
638 * Document-method: OpenSSL::BN#mod_sub
639 * call-seq:
640 * bn.mod_sub(bn1, bn2) -> aBN
641 */
642BIGNUM_3c(mod_sub)
643
644/*
645 * Document-method: OpenSSL::BN#mod_mul
646 * call-seq:
647 * bn.mod_mul(bn1, bn2) -> aBN
648 */
649BIGNUM_3c(mod_mul)
650
651/*
652 * Document-method: OpenSSL::BN#mod_exp
653 * call-seq:
654 * bn.mod_exp(bn1, bn2) -> aBN
655 */
656BIGNUM_3c(mod_exp)
657
658#define BIGNUM_BIT(func) \
659 static VALUE \
660 ossl_bn_##func(VALUE self, VALUE bit) \
661 { \
662 BIGNUM *bn; \
663 GetBN(self, bn); \
664 if (BN_##func(bn, NUM2INT(bit)) <= 0) { \
665 ossl_raise(eBNError, NULL); \
666 } \
667 return self; \
668 }
669
670/*
671 * Document-method: OpenSSL::BN#set_bit!
672 * call-seq:
673 * bn.set_bit!(bit) -> self
674 */
675BIGNUM_BIT(set_bit)
676
677/*
678 * Document-method: OpenSSL::BN#clear_bit!
679 * call-seq:
680 * bn.clear_bit!(bit) -> self
681 */
682BIGNUM_BIT(clear_bit)
683
684/*
685 * Document-method: OpenSSL::BN#mask_bit!
686 * call-seq:
687 * bn.mask_bit!(bit) -> self
688 */
689BIGNUM_BIT(mask_bits)
690
691/*
692 * call-seq:
693 * bn.bit_set?(bit) => true | false
694 *
695 * Tests bit _bit_ in _bn_ and returns +true+ if set, +false+ if not set.
696 */
697static VALUE
698ossl_bn_is_bit_set(VALUE self, VALUE bit)
699{
700 int b;
701 BIGNUM *bn;
702
703 b = NUM2INT(bit);
704 GetBN(self, bn);
705 if (BN_is_bit_set(bn, b)) {
706 return Qtrue;
707 }
708 return Qfalse;
709}
710
711#define BIGNUM_SHIFT(func) \
712 static VALUE \
713 ossl_bn_##func(VALUE self, VALUE bits) \
714 { \
715 BIGNUM *bn, *result; \
716 int b; \
717 VALUE obj; \
718 b = NUM2INT(bits); \
719 GetBN(self, bn); \
720 obj = NewBN(rb_obj_class(self)); \
721 if (!(result = BN_new())) { \
722 ossl_raise(eBNError, NULL); \
723 } \
724 if (BN_##func(result, bn, b) <= 0) { \
725 BN_free(result); \
726 ossl_raise(eBNError, NULL); \
727 } \
728 SetBN(obj, result); \
729 return obj; \
730 }
731
732/*
733 * Document-method: OpenSSL::BN#<<
734 * call-seq:
735 * bn << bits -> aBN
736 */
737BIGNUM_SHIFT(lshift)
738
739/*
740 * Document-method: OpenSSL::BN#>>
741 * call-seq:
742 * bn >> bits -> aBN
743 */
744BIGNUM_SHIFT(rshift)
745
746#define BIGNUM_SELF_SHIFT(func) \
747 static VALUE \
748 ossl_bn_self_##func(VALUE self, VALUE bits) \
749 { \
750 BIGNUM *bn; \
751 int b; \
752 b = NUM2INT(bits); \
753 GetBN(self, bn); \
754 if (BN_##func(bn, bn, b) <= 0) \
755 ossl_raise(eBNError, NULL); \
756 return self; \
757 }
758
759/*
760 * Document-method: OpenSSL::BN#lshift!
761 * call-seq:
762 * bn.lshift!(bits) -> self
763 */
764BIGNUM_SELF_SHIFT(lshift)
765
766/*
767 * Document-method: OpenSSL::BN#rshift!
768 * call-seq:
769 * bn.rshift!(bits) -> self
770 */
771BIGNUM_SELF_SHIFT(rshift)
772
773#define BIGNUM_RAND(func) \
774 static VALUE \
775 ossl_bn_s_##func(int argc, VALUE *argv, VALUE klass) \
776 { \
777 BIGNUM *result; \
778 int bottom = 0, top = 0, b; \
779 VALUE bits, fill, odd, obj; \
780 \
781 switch (rb_scan_args(argc, argv, "12", &bits, &fill, &odd)) { \
782 case 3: \
783 bottom = (odd == Qtrue) ? 1 : 0; \
784 /* FALLTHROUGH */ \
785 case 2: \
786 top = NUM2INT(fill); \
787 } \
788 b = NUM2INT(bits); \
789 obj = NewBN(klass); \
790 if (!(result = BN_new())) { \
791 ossl_raise(eBNError, NULL); \
792 } \
793 if (BN_##func(result, b, top, bottom) <= 0) { \
794 BN_free(result); \
795 ossl_raise(eBNError, NULL); \
796 } \
797 SetBN(obj, result); \
798 return obj; \
799 }
800
801/*
802 * Document-method: OpenSSL::BN.rand
803 * BN.rand(bits [, fill [, odd]]) -> aBN
804 */
805BIGNUM_RAND(rand)
806
807/*
808 * Document-method: OpenSSL::BN.pseudo_rand
809 * BN.pseudo_rand(bits [, fill [, odd]]) -> aBN
810 */
811BIGNUM_RAND(pseudo_rand)
812
813#define BIGNUM_RAND_RANGE(func) \
814 static VALUE \
815 ossl_bn_s_##func##_range(VALUE klass, VALUE range) \
816 { \
817 BIGNUM *bn = GetBNPtr(range), *result; \
818 VALUE obj = NewBN(klass); \
819 if (!(result = BN_new())) { \
820 ossl_raise(eBNError, NULL); \
821 } \
822 if (BN_##func##_range(result, bn) <= 0) { \
823 BN_free(result); \
824 ossl_raise(eBNError, NULL); \
825 } \
826 SetBN(obj, result); \
827 return obj; \
828 }
829
830/*
831 * Document-method: OpenSSL::BN.rand_range
832 * call-seq:
833 * BN.rand_range(range) -> aBN
834 *
835 */
837
838/*
839 * Document-method: OpenSSL::BN.pseudo_rand_range
840 * call-seq:
841 * BN.pseudo_rand_range(range) -> aBN
842 *
843 */
844BIGNUM_RAND_RANGE(pseudo_rand)
845
846/*
847 * call-seq:
848 * BN.generate_prime(bits, [, safe [, add [, rem]]]) => bn
849 *
850 * Generates a random prime number of bit length _bits_. If _safe_ is set to
851 * +true+, generates a safe prime. If _add_ is specified, generates a prime that
852 * fulfills condition <tt>p % add = rem</tt>.
853 *
854 * === Parameters
855 * * _bits_ - integer
856 * * _safe_ - boolean
857 * * _add_ - BN
858 * * _rem_ - BN
859 */
860static VALUE
861ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass)
862{
863 BIGNUM *add = NULL, *rem = NULL, *result;
864 int safe = 1, num;
865 VALUE vnum, vsafe, vadd, vrem, obj;
866
867 rb_scan_args(argc, argv, "13", &vnum, &vsafe, &vadd, &vrem);
868
869 num = NUM2INT(vnum);
870
871 if (vsafe == Qfalse) {
872 safe = 0;
873 }
874 if (!NIL_P(vadd)) {
875 add = GetBNPtr(vadd);
876 rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem);
877 }
878 obj = NewBN(klass);
879 if (!(result = BN_new())) {
881 }
882 if (!BN_generate_prime_ex(result, num, safe, add, rem, NULL)) {
883 BN_free(result);
885 }
886 SetBN(obj, result);
887
888 return obj;
889}
890
891#define BIGNUM_NUM(func) \
892 static VALUE \
893 ossl_bn_##func(VALUE self) \
894 { \
895 BIGNUM *bn; \
896 GetBN(self, bn); \
897 return INT2NUM(BN_##func(bn)); \
898 }
899
900/*
901 * Document-method: OpenSSL::BN#num_bytes
902 * call-seq:
903 * bn.num_bytes => integer
904 */
905BIGNUM_NUM(num_bytes)
906
907/*
908 * Document-method: OpenSSL::BN#num_bits
909 * call-seq:
910 * bn.num_bits => integer
911 */
912BIGNUM_NUM(num_bits)
913
914static VALUE
915ossl_bn_copy(VALUE self, VALUE other)
916{
917 BIGNUM *bn1, *bn2;
918
919 rb_check_frozen(self);
920
921 if (self == other) return self;
922
923 GetBN(self, bn1);
924 bn2 = GetBNPtr(other);
925
926 if (!BN_copy(bn1, bn2)) {
928 }
929 return self;
930}
931
932/*
933 * call-seq:
934 * +bn -> aBN
935 */
936static VALUE
937ossl_bn_uplus(VALUE self)
938{
939 return self;
940}
941
942/*
943 * call-seq:
944 * -bn -> aBN
945 */
946static VALUE
947ossl_bn_uminus(VALUE self)
948{
949 VALUE obj;
950 BIGNUM *bn1, *bn2;
951
952 GetBN(self, bn1);
953 obj = NewBN(cBN);
954 bn2 = BN_dup(bn1);
955 if (!bn2)
956 ossl_raise(eBNError, "BN_dup");
957 SetBN(obj, bn2);
958 BN_set_negative(bn2, !BN_is_negative(bn2));
959
960 return obj;
961}
962
963#define BIGNUM_CMP(func) \
964 static VALUE \
965 ossl_bn_##func(VALUE self, VALUE other) \
966 { \
967 BIGNUM *bn1, *bn2 = GetBNPtr(other); \
968 GetBN(self, bn1); \
969 return INT2NUM(BN_##func(bn1, bn2)); \
970 }
971
972/*
973 * Document-method: OpenSSL::BN#cmp
974 * call-seq:
975 * bn.cmp(bn2) => integer
976 */
977/*
978 * Document-method: OpenSSL::BN#<=>
979 * call-seq:
980 * bn <=> bn2 => integer
981 */
982BIGNUM_CMP(cmp)
983
984/*
985 * Document-method: OpenSSL::BN#ucmp
986 * call-seq:
987 * bn.ucmp(bn2) => integer
988 */
989BIGNUM_CMP(ucmp)
990
991/*
992 * call-seq:
993 * bn == obj => true or false
994 *
995 * Returns +true+ only if _obj_ has the same value as _bn_. Contrast this
996 * with OpenSSL::BN#eql?, which requires obj to be OpenSSL::BN.
997 */
998static VALUE
999ossl_bn_eq(VALUE self, VALUE other)
1000{
1001 BIGNUM *bn1, *bn2;
1002
1003 GetBN(self, bn1);
1004 other = try_convert_to_bn(other);
1005 if (NIL_P(other))
1006 return Qfalse;
1007 GetBN(other, bn2);
1008
1009 if (!BN_cmp(bn1, bn2)) {
1010 return Qtrue;
1011 }
1012 return Qfalse;
1013}
1014
1015/*
1016 * call-seq:
1017 * bn.eql?(obj) => true or false
1018 *
1019 * Returns <code>true</code> only if <i>obj</i> is a
1020 * <code>OpenSSL::BN</code> with the same value as <i>bn</i>. Contrast this
1021 * with OpenSSL::BN#==, which performs type conversions.
1022 */
1023static VALUE
1024ossl_bn_eql(VALUE self, VALUE other)
1025{
1026 BIGNUM *bn1, *bn2;
1027
1028 if (!rb_obj_is_kind_of(other, cBN))
1029 return Qfalse;
1030 GetBN(self, bn1);
1031 GetBN(other, bn2);
1032
1033 return BN_cmp(bn1, bn2) ? Qfalse : Qtrue;
1034}
1035
1036/*
1037 * call-seq:
1038 * bn.hash => Integer
1039 *
1040 * Returns a hash code for this object.
1041 *
1042 * See also Object#hash.
1043 */
1044static VALUE
1045ossl_bn_hash(VALUE self)
1046{
1047 BIGNUM *bn;
1048 VALUE tmp, hash;
1049 unsigned char *buf;
1050 int len;
1051
1052 GetBN(self, bn);
1053 len = BN_num_bytes(bn);
1054 buf = ALLOCV(tmp, len);
1055 if (BN_bn2bin(bn, buf) != len) {
1056 ALLOCV_END(tmp);
1057 ossl_raise(eBNError, "BN_bn2bin");
1058 }
1059
1060 hash = ST2FIX(rb_memhash(buf, len));
1061 ALLOCV_END(tmp);
1062
1063 return hash;
1064}
1065
1066/*
1067 * call-seq:
1068 * bn.prime? => true | false
1069 * bn.prime?(checks) => true | false
1070 *
1071 * Performs a Miller-Rabin probabilistic primality test with _checks_
1072 * iterations. If _checks_ is not specified, a number of iterations is used
1073 * that yields a false positive rate of at most 2^-80 for random input.
1074 *
1075 * === Parameters
1076 * * _checks_ - integer
1077 */
1078static VALUE
1079ossl_bn_is_prime(int argc, VALUE *argv, VALUE self)
1080{
1081 BIGNUM *bn;
1082 VALUE vchecks;
1083 int checks = BN_prime_checks;
1084
1085 if (rb_scan_args(argc, argv, "01", &vchecks) == 1) {
1086 checks = NUM2INT(vchecks);
1087 }
1088 GetBN(self, bn);
1089 switch (BN_is_prime_ex(bn, checks, ossl_bn_ctx, NULL)) {
1090 case 1:
1091 return Qtrue;
1092 case 0:
1093 return Qfalse;
1094 default:
1096 }
1097 /* not reachable */
1098 return Qnil;
1099}
1100
1101/*
1102 * call-seq:
1103 * bn.prime_fasttest? => true | false
1104 * bn.prime_fasttest?(checks) => true | false
1105 * bn.prime_fasttest?(checks, trial_div) => true | false
1106 *
1107 * Performs a Miller-Rabin primality test. This is same as #prime? except this
1108 * first attempts trial divisions with some small primes.
1109 *
1110 * === Parameters
1111 * * _checks_ - integer
1112 * * _trial_div_ - boolean
1113 */
1114static VALUE
1115ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self)
1116{
1117 BIGNUM *bn;
1118 VALUE vchecks, vtrivdiv;
1119 int checks = BN_prime_checks, do_trial_division = 1;
1120
1121 rb_scan_args(argc, argv, "02", &vchecks, &vtrivdiv);
1122
1123 if (!NIL_P(vchecks)) {
1124 checks = NUM2INT(vchecks);
1125 }
1126 GetBN(self, bn);
1127 /* handle true/false */
1128 if (vtrivdiv == Qfalse) {
1129 do_trial_division = 0;
1130 }
1131 switch (BN_is_prime_fasttest_ex(bn, checks, ossl_bn_ctx, do_trial_division, NULL)) {
1132 case 1:
1133 return Qtrue;
1134 case 0:
1135 return Qfalse;
1136 default:
1138 }
1139 /* not reachable */
1140 return Qnil;
1141}
1142
1143/*
1144 * INIT
1145 * (NOTE: ordering of methods is the same as in 'man bn')
1146 */
1147void
1149{
1150#if 0
1151 mOSSL = rb_define_module("OpenSSL");
1153#endif
1154
1155#ifdef HAVE_RB_EXT_RACTOR_SAFE
1156 ossl_bn_ctx_key = rb_ractor_local_storage_ptr_newkey(&ossl_bn_ctx_key_type);
1157#else
1159#endif
1160
1162
1164
1165 rb_define_alloc_func(cBN, ossl_bn_alloc);
1166 rb_define_method(cBN, "initialize", ossl_bn_initialize, -1);
1167
1168 rb_define_method(cBN, "initialize_copy", ossl_bn_copy, 1);
1169 rb_define_method(cBN, "copy", ossl_bn_copy, 1);
1170
1171 /* swap (=coerce?) */
1172
1173 rb_define_method(cBN, "num_bytes", ossl_bn_num_bytes, 0);
1174 rb_define_method(cBN, "num_bits", ossl_bn_num_bits, 0);
1175 /* num_bits_word */
1176
1177 rb_define_method(cBN, "+@", ossl_bn_uplus, 0);
1178 rb_define_method(cBN, "-@", ossl_bn_uminus, 0);
1179
1180 rb_define_method(cBN, "+", ossl_bn_add, 1);
1181 rb_define_method(cBN, "-", ossl_bn_sub, 1);
1182 rb_define_method(cBN, "*", ossl_bn_mul, 1);
1183 rb_define_method(cBN, "sqr", ossl_bn_sqr, 0);
1184 rb_define_method(cBN, "/", ossl_bn_div, 1);
1185 rb_define_method(cBN, "%", ossl_bn_mod, 1);
1186 /* nnmod */
1187
1188 rb_define_method(cBN, "mod_add", ossl_bn_mod_add, 2);
1189 rb_define_method(cBN, "mod_sub", ossl_bn_mod_sub, 2);
1190 rb_define_method(cBN, "mod_mul", ossl_bn_mod_mul, 2);
1191 rb_define_method(cBN, "mod_sqr", ossl_bn_mod_sqr, 1);
1192 rb_define_method(cBN, "**", ossl_bn_exp, 1);
1193 rb_define_method(cBN, "mod_exp", ossl_bn_mod_exp, 2);
1194 rb_define_method(cBN, "gcd", ossl_bn_gcd, 1);
1195
1196 /* add_word
1197 * sub_word
1198 * mul_word
1199 * div_word
1200 * mod_word */
1201
1202 rb_define_method(cBN, "cmp", ossl_bn_cmp, 1);
1203 rb_define_alias(cBN, "<=>", "cmp");
1204 rb_define_method(cBN, "ucmp", ossl_bn_ucmp, 1);
1205 rb_define_method(cBN, "eql?", ossl_bn_eql, 1);
1206 rb_define_method(cBN, "hash", ossl_bn_hash, 0);
1207 rb_define_method(cBN, "==", ossl_bn_eq, 1);
1208 rb_define_alias(cBN, "===", "==");
1209 rb_define_method(cBN, "zero?", ossl_bn_is_zero, 0);
1210 rb_define_method(cBN, "one?", ossl_bn_is_one, 0);
1211 /* is_word */
1212 rb_define_method(cBN, "odd?", ossl_bn_is_odd, 0);
1213 rb_define_method(cBN, "negative?", ossl_bn_is_negative, 0);
1214
1215 /* zero
1216 * one
1217 * value_one - DON'T IMPL.
1218 * set_word
1219 * get_word */
1220
1221 rb_define_singleton_method(cBN, "rand", ossl_bn_s_rand, -1);
1222 rb_define_singleton_method(cBN, "pseudo_rand", ossl_bn_s_pseudo_rand, -1);
1223 rb_define_singleton_method(cBN, "rand_range", ossl_bn_s_rand_range, 1);
1224 rb_define_singleton_method(cBN, "pseudo_rand_range", ossl_bn_s_pseudo_rand_range, 1);
1225
1226 rb_define_singleton_method(cBN, "generate_prime", ossl_bn_s_generate_prime, -1);
1227 rb_define_method(cBN, "prime?", ossl_bn_is_prime, -1);
1228 rb_define_method(cBN, "prime_fasttest?", ossl_bn_is_prime_fasttest, -1);
1229
1230 rb_define_method(cBN, "set_bit!", ossl_bn_set_bit, 1);
1231 rb_define_method(cBN, "clear_bit!", ossl_bn_clear_bit, 1);
1232 rb_define_method(cBN, "bit_set?", ossl_bn_is_bit_set, 1);
1233 rb_define_method(cBN, "mask_bits!", ossl_bn_mask_bits, 1);
1234 rb_define_method(cBN, "<<", ossl_bn_lshift, 1);
1235 rb_define_method(cBN, ">>", ossl_bn_rshift, 1);
1236 rb_define_method(cBN, "lshift!", ossl_bn_self_lshift, 1);
1237 rb_define_method(cBN, "rshift!", ossl_bn_self_rshift, 1);
1238 /* lshift1 - DON'T IMPL. */
1239 /* rshift1 - DON'T IMPL. */
1240
1241 /*
1242 * bn2bin
1243 * bin2bn
1244 * bn2hex
1245 * bn2dec
1246 * hex2bn
1247 * dec2bn - all these are implemented in ossl_bn_initialize, and ossl_bn_to_s
1248 * print - NOT IMPL.
1249 * print_fp - NOT IMPL.
1250 * bn2mpi
1251 * mpi2bn
1252 */
1253 rb_define_method(cBN, "to_s", ossl_bn_to_s, -1);
1254 rb_define_method(cBN, "to_i", ossl_bn_to_i, 0);
1255 rb_define_alias(cBN, "to_int", "to_i");
1256 rb_define_method(cBN, "to_bn", ossl_bn_to_bn, 0);
1257 rb_define_method(cBN, "coerce", ossl_bn_coerce, 1);
1258
1259 /*
1260 * TODO:
1261 * But how to: from_bin, from_mpi? PACK?
1262 * to_bin
1263 * to_mpi
1264 */
1265
1266 rb_define_method(cBN, "mod_inverse", ossl_bn_mod_inverse, 1);
1267
1268 /* RECiProcal
1269 * MONTgomery */
1270}
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:975
int rb_integer_pack(VALUE val, void *words, size_t numwords, size_t wordsize, size_t nails, int flags)
Definition: bignum.c:3553
size_t rb_absint_size(VALUE val, int *nlz_bits_ret)
Definition: bignum.c:3253
VALUE rb_cstr_to_inum(const char *str, int base, int badcheck)
Definition: bignum.c:4016
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:653
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition: cxxanyargs.hpp:668
#define sub(x, y)
Definition: date_strftime.c:24
#define mul(x, y)
Definition: date_strftime.c:25
#define add(x, y)
Definition: date_strftime.c:23
#define mod(x, y)
Definition: date_strftime.c:28
struct RIMemo * ptr
Definition: debug.c:88
big_t * num
Definition: enough.c:232
uint8_t len
Definition: escape.c:17
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
#define RSTRING_PTR(string)
Definition: fbuffer.h:19
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:797
VALUE rb_define_module(const char *name)
Definition: class.c:871
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
Definition: class.c:1999
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2296
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
VALUE rb_eStandardError
Definition: error.c:1054
VALUE rb_eTypeError
Definition: error.c:1057
VALUE rb_eRuntimeError
Definition: error.c:1055
VALUE rb_eArgError
Definition: error.c:1058
VALUE rb_cObject
Object class.
Definition: object.c:49
VALUE rb_obj_class(VALUE)
Definition: object.c:245
VALUE rb_obj_is_kind_of(VALUE, VALUE)
Determines if obj is a kind of c.
Definition: object.c:724
unsigned gcd(unsigned a, unsigned b)
Definition: gzappend.c:102
#define rb_ary_new3
Definition: array.h:73
#define INTEGER_PACK_BIG_ENDIAN
Definition: bignum.h:94
#define rb_check_frozen
Definition: error.h:72
st_index_t rb_memhash(const void *ptr, long len)
Definition: random.c:1629
#define rb_str_new(str, len)
Definition: string.h:213
void rb_define_alloc_func(VALUE, rb_alloc_func_t)
#define NUM2INT
Definition: int.h:44
typedef long(ZCALLBACK *tell_file_func) OF((voidpf opaque
voidpf void * buf
Definition: ioapi.h:138
#define rb_long2int
Definition: long.h:62
#define FIX2LONG
Definition: long.h:46
#define ALLOCV
Definition: memory.h:138
#define ALLOCV_N
Definition: memory.h:139
#define ALLOCV_END
Definition: memory.h:140
VALUE mOSSL
Definition: ossl.c:231
VALUE ossl_buf2str(char *buf, int len)
Definition: ossl.c:120
void ossl_raise(VALUE exc, const char *fmt,...)
Definition: ossl.c:293
VALUE eOSSLError
Definition: ossl.c:236
VALUE cBN
Definition: ossl_bn.c:50
VALUE eBNError
Definition: ossl_bn.c:56
#define BIGNUM_CMP(func)
Definition: ossl_bn.c:963
#define BIGNUM_RAND(func)
Definition: ossl_bn.c:773
void ossl_bn_ctx_free(void)
Definition: ossl_bn.c:203
#define BIGNUM_2c(func)
BIGNUM * ossl_bn_value_ptr(volatile VALUE *ptr)
Definition: ossl_bn.c:140
#define SetBN(obj, bn)
Definition: ossl_bn.c:19
#define BIGNUM_2(func)
VALUE ossl_bn_new(const BIGNUM *bn)
Definition: ossl_bn.c:62
#define NewBN(klass)
Definition: ossl_bn.c:17
BN_CTX * ossl_bn_ctx_get(void)
Definition: ossl_bn.c:192
#define GetBN(obj, bn)
Definition: ossl_bn.c:26
#define BIGNUM_BIT(func)
#define BIGNUM_SHIFT(func)
Definition: ossl_bn.c:711
#define BIGNUM_SELF_SHIFT(func)
Definition: ossl_bn.c:746
#define BIGNUM_1c(func)
Definition: ossl_bn.c:445
#define BIGNUM_3c(func)
Definition: ossl_bn.c:610
void Init_ossl_bn(void)
Definition: ossl_bn.c:1148
#define BIGNUM_BOOL1(func)
Definition: ossl_bn.c:397
#define BIGNUM_RAND_RANGE(func)
Definition: ossl_bn.c:813
#define BIGNUM_NUM(func)
Definition: ossl_bn.c:891
#define ossl_bn_ctx
Definition: ossl_bn.h:17
#define GetBNPtr(obj)
Definition: ossl_bn.h:19
void * rb_ractor_local_storage_ptr(rb_ractor_local_key_t key)
Definition: ractor.c:3195
void rb_ractor_local_storage_ptr_set(rb_ractor_local_key_t key, void *ptr)
Definition: ractor.c:3207
rb_ractor_local_key_t rb_ractor_local_storage_ptr_newkey(const struct rb_ractor_local_storage_type *type)
Definition: ractor.c:3097
#define NULL
Definition: regenc.h:69
#define StringValuePtr(v)
Definition: rstring.h:51
#define StringValueCStr(v)
Definition: rstring.h:52
@ RUBY_TYPED_FREE_IMMEDIATELY
Definition: rtypeddata.h:62
int argc
Definition: ruby.c:240
char ** argv
Definition: ruby.c:241
#define RB_INTEGER_TYPE_P(obj)
Definition: ruby_missing.h:15
#define ST2FIX(h)
Definition: ruby_missing.h:21
#define Qtrue
#define RTEST
#define Qnil
#define Qfalse
#define NIL_P
#define FIXNUM_P
#define r2
#define r1
size_t strlen(const char *)
Definition: gzjoin.c:78
unsigned long VALUE
Definition: value.h:38
#define TYPE(_)
Definition: value_type.h:105
#define T_STRING
Definition: value_type.h:77
#define T_BIGNUM
Definition: value_type.h:56
#define T_FIXNUM
Definition: value_type.h:62