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