Added spec for Kernel#eval with binding from method defined by #eval.
[rbx.git] / stdlib / ext / openssl / ossl_bn.c
blobf508a5654322a9b6355ef4b2ab140b2a3da6bde3
1 /*
2 * $Id: ossl_bn.c 12043 2007-03-12 04:12:32Z knu $
3 * 'OpenSSL for Ruby' project
4 * Copyright (C) 2001-2002 Technorama team <oss-ruby@technorama.net>
5 * All rights reserved.
6 */
7 /*
8 * This program is licenced under the same licence as Ruby.
9 * (See the file 'LICENCE'.)
11 /* modified by Michal Rokos <m.rokos@sh.cvut.cz> */
12 #include "ossl.h"
14 #define WrapBN(klass, obj, bn) do { \
15 if (!bn) { \
16 ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
17 } \
18 obj = Data_Wrap_Struct(klass, 0, BN_clear_free, bn); \
19 } while (0)
21 #define GetBN(obj, bn) do { \
22 Data_Get_Struct(obj, BIGNUM, bn); \
23 if (!bn) { \
24 ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
25 } \
26 } while (0)
28 #define SafeGetBN(obj, bn) do { \
29 OSSL_Check_Kind(obj, cBN); \
30 GetBN(obj, bn); \
31 } while (0)
34 * Classes
36 VALUE cBN;
37 VALUE eBNError;
40 * Public
42 VALUE
43 ossl_bn_new(BIGNUM *bn)
45 BIGNUM *newbn;
46 VALUE obj;
48 newbn = bn ? BN_dup(bn) : BN_new();
49 if (!newbn) {
50 ossl_raise(eBNError, NULL);
52 WrapBN(cBN, obj, newbn);
54 return obj;
57 BIGNUM *
58 GetBNPtr(VALUE obj)
60 BIGNUM *bn = NULL;
62 if (RTEST(rb_obj_is_kind_of(obj, cBN))) {
63 GetBN(obj, bn);
64 } else switch (TYPE(obj)) {
65 case T_FIXNUM:
66 case T_BIGNUM:
67 obj = rb_String(obj);
68 if (!BN_dec2bn(&bn, StringValuePtr(obj))) {
69 ossl_raise(eBNError, NULL);
71 WrapBN(cBN, obj, bn); /* Handle potencial mem leaks */
72 break;
73 default:
74 ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN");
76 return bn;
80 * Private
83 * BN_CTX - is used in more difficult math. ops
84 * (Why just 1? Because Ruby itself isn't thread safe,
85 * we don't need to care about threads)
87 BN_CTX *ossl_bn_ctx;
89 static VALUE
90 ossl_bn_alloc(VALUE klass)
92 BIGNUM *bn;
93 VALUE obj;
95 if (!(bn = BN_new())) {
96 ossl_raise(eBNError, NULL);
98 WrapBN(klass, obj, bn);
100 return obj;
103 static VALUE
104 ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
106 BIGNUM *bn;
107 VALUE str, bs;
108 int base = 10;
110 if (rb_scan_args(argc, argv, "11", &str, &bs) == 2) {
111 base = NUM2INT(bs);
113 StringValue(str);
114 GetBN(self, bn);
115 if (RTEST(rb_obj_is_kind_of(str, cBN))) {
116 BIGNUM *other;
118 GetBN(str, other); /* Safe - we checked kind_of? above */
119 if (!BN_copy(bn, other)) {
120 ossl_raise(eBNError, NULL);
122 return self;
125 switch (base) {
126 case 0:
127 if (!BN_mpi2bn(RSTRING(str)->ptr, RSTRING(str)->len, bn)) {
128 ossl_raise(eBNError, NULL);
130 break;
131 case 2:
132 if (!BN_bin2bn(RSTRING(str)->ptr, RSTRING(str)->len, bn)) {
133 ossl_raise(eBNError, NULL);
135 break;
136 case 10:
137 if (!BN_dec2bn(&bn, RSTRING(str)->ptr)) {
138 ossl_raise(eBNError, NULL);
140 break;
141 case 16:
142 if (!BN_hex2bn(&bn, RSTRING(str)->ptr)) {
143 ossl_raise(eBNError, NULL);
145 break;
146 default:
147 ossl_raise(rb_eArgError, "illegal radix %d", base);
149 return self;
152 static VALUE
153 ossl_bn_to_s(int argc, VALUE *argv, VALUE self)
155 BIGNUM *bn;
156 VALUE str, bs;
157 int base = 10, len;
158 char *buf;
160 if (rb_scan_args(argc, argv, "01", &bs) == 1) {
161 base = NUM2INT(bs);
163 GetBN(self, bn);
164 switch (base) {
165 case 0:
166 len = BN_bn2mpi(bn, NULL);
167 str = rb_str_new(0, len);
168 if (BN_bn2mpi(bn, RSTRING(str)->ptr) != len)
169 ossl_raise(eBNError, NULL);
170 break;
171 case 2:
172 len = BN_num_bytes(bn);
173 str = rb_str_new(0, len);
174 if (BN_bn2bin(bn, RSTRING(str)->ptr) != len)
175 ossl_raise(eBNError, NULL);
176 break;
177 case 10:
178 if (!(buf = BN_bn2dec(bn))) ossl_raise(eBNError, NULL);
179 str = ossl_buf2str(buf, strlen(buf));
180 break;
181 case 16:
182 if (!(buf = BN_bn2hex(bn))) ossl_raise(eBNError, NULL);
183 str = ossl_buf2str(buf, strlen(buf));
184 break;
185 default:
186 ossl_raise(rb_eArgError, "illegal radix %d", base);
189 return str;
192 static VALUE
193 ossl_bn_to_i(VALUE self)
195 BIGNUM *bn;
196 char *txt;
197 VALUE num;
199 GetBN(self, bn);
201 if (!(txt = BN_bn2dec(bn))) {
202 ossl_raise(eBNError, NULL);
204 num = rb_cstr_to_inum(txt, 10, Qtrue);
205 OPENSSL_free(txt);
207 return num;
210 static VALUE
211 ossl_bn_to_bn(VALUE self)
213 return self;
216 static VALUE
217 ossl_bn_coerce(VALUE self, VALUE other)
219 switch(TYPE(other)) {
220 case T_STRING:
221 self = ossl_bn_to_s(0, NULL, self);
222 break;
223 case T_FIXNUM:
224 case T_BIGNUM:
225 self = ossl_bn_to_i(self);
226 break;
227 default:
228 if (!RTEST(rb_obj_is_kind_of(other, cBN))) {
229 ossl_raise(rb_eTypeError, "Don't know how to coerce");
232 return rb_assoc_new(other, self);
235 #define BIGNUM_BOOL1(func) \
236 static VALUE \
237 ossl_bn_##func(VALUE self) \
239 BIGNUM *bn; \
240 GetBN(self, bn); \
241 if (BN_##func(bn)) { \
242 return Qtrue; \
244 return Qfalse; \
246 BIGNUM_BOOL1(is_zero);
247 BIGNUM_BOOL1(is_one);
248 BIGNUM_BOOL1(is_odd);
250 #define BIGNUM_1c(func) \
251 static VALUE \
252 ossl_bn_##func(VALUE self) \
254 BIGNUM *bn, *result; \
255 VALUE obj; \
256 GetBN(self, bn); \
257 if (!(result = BN_new())) { \
258 ossl_raise(eBNError, NULL); \
260 if (!BN_##func(result, bn, ossl_bn_ctx)) { \
261 BN_free(result); \
262 ossl_raise(eBNError, NULL); \
264 WrapBN(CLASS_OF(self), obj, result); \
265 return obj; \
267 BIGNUM_1c(sqr);
269 #define BIGNUM_2(func) \
270 static VALUE \
271 ossl_bn_##func(VALUE self, VALUE other) \
273 BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
274 VALUE obj; \
275 GetBN(self, bn1); \
276 if (!(result = BN_new())) { \
277 ossl_raise(eBNError, NULL); \
279 if (!BN_##func(result, bn1, bn2)) { \
280 BN_free(result); \
281 ossl_raise(eBNError, NULL); \
283 WrapBN(CLASS_OF(self), obj, result); \
284 return obj; \
286 BIGNUM_2(add);
287 BIGNUM_2(sub);
289 #define BIGNUM_2c(func) \
290 static VALUE \
291 ossl_bn_##func(VALUE self, VALUE other) \
293 BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
294 VALUE obj; \
295 GetBN(self, bn1); \
296 if (!(result = BN_new())) { \
297 ossl_raise(eBNError, NULL); \
299 if (!BN_##func(result, bn1, bn2, ossl_bn_ctx)) { \
300 BN_free(result); \
301 ossl_raise(eBNError, NULL); \
303 WrapBN(CLASS_OF(self), obj, result); \
304 return obj; \
306 BIGNUM_2c(mul);
307 BIGNUM_2c(mod);
308 BIGNUM_2c(exp);
309 BIGNUM_2c(gcd);
310 BIGNUM_2c(mod_sqr);
311 BIGNUM_2c(mod_inverse);
313 static VALUE
314 ossl_bn_div(VALUE self, VALUE other)
316 BIGNUM *bn1, *bn2 = GetBNPtr(other), *r1, *r2;
317 VALUE obj1, obj2;
319 GetBN(self, bn1);
321 if (!(r1 = BN_new())) {
322 ossl_raise(eBNError, NULL);
324 if (!(r2 = BN_new())) {
325 BN_free(r1);
326 ossl_raise(eBNError, NULL);
328 if (!BN_div(r1, r2, bn1, bn2, ossl_bn_ctx)) {
329 BN_free(r1);
330 BN_free(r2);
331 ossl_raise(eBNError, NULL);
333 WrapBN(CLASS_OF(self), obj1, r1);
334 WrapBN(CLASS_OF(self), obj2, r2);
336 return rb_ary_new3(2, obj1, obj2);
339 #define BIGNUM_3c(func) \
340 static VALUE \
341 ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \
343 BIGNUM *bn1, *bn2 = GetBNPtr(other1); \
344 BIGNUM *bn3 = GetBNPtr(other2), *result; \
345 VALUE obj; \
346 GetBN(self, bn1); \
347 if (!(result = BN_new())) { \
348 ossl_raise(eBNError, NULL); \
350 if (!BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx)) { \
351 BN_free(result); \
352 ossl_raise(eBNError, NULL); \
354 WrapBN(CLASS_OF(self), obj, result); \
355 return obj; \
357 BIGNUM_3c(mod_add);
358 BIGNUM_3c(mod_sub);
359 BIGNUM_3c(mod_mul);
360 BIGNUM_3c(mod_exp);
362 #define BIGNUM_BIT(func) \
363 static VALUE \
364 ossl_bn_##func(VALUE self, VALUE bit) \
366 BIGNUM *bn; \
367 GetBN(self, bn); \
368 if (!BN_##func(bn, NUM2INT(bit))) { \
369 ossl_raise(eBNError, NULL); \
371 return self; \
373 BIGNUM_BIT(set_bit);
374 BIGNUM_BIT(clear_bit);
375 BIGNUM_BIT(mask_bits);
377 static VALUE
378 ossl_bn_is_bit_set(VALUE self, VALUE bit)
380 int b;
381 BIGNUM *bn;
383 b = NUM2INT(bit);
384 GetBN(self, bn);
385 if (BN_is_bit_set(bn, b)) {
386 return Qtrue;
388 return Qfalse;
391 #define BIGNUM_SHIFT(func) \
392 static VALUE \
393 ossl_bn_##func(VALUE self, VALUE bits) \
395 BIGNUM *bn, *result; \
396 int b; \
397 VALUE obj; \
398 b = NUM2INT(bits); \
399 GetBN(self, bn); \
400 if (!(result = BN_new())) { \
401 ossl_raise(eBNError, NULL); \
403 if (!BN_##func(result, bn, b)) { \
404 BN_free(result); \
405 ossl_raise(eBNError, NULL); \
407 WrapBN(CLASS_OF(self), obj, result); \
408 return obj; \
410 BIGNUM_SHIFT(lshift);
411 BIGNUM_SHIFT(rshift);
413 #define BIGNUM_RAND(func) \
414 static VALUE \
415 ossl_bn_s_##func(int argc, VALUE *argv, VALUE klass) \
417 BIGNUM *result; \
418 int bottom = 0, top = 0, b; \
419 VALUE bits, fill, odd, obj; \
421 switch (rb_scan_args(argc, argv, "12", &bits, &fill, &odd)) { \
422 case 3: \
423 bottom = (odd == Qtrue) ? 1 : 0; \
424 /* FALLTHROUGH */ \
425 case 2: \
426 top = FIX2INT(fill); \
428 b = NUM2INT(bits); \
429 if (!(result = BN_new())) { \
430 ossl_raise(eBNError, NULL); \
432 if (!BN_##func(result, b, top, bottom)) { \
433 BN_free(result); \
434 ossl_raise(eBNError, NULL); \
436 WrapBN(klass, obj, result); \
437 return obj; \
439 BIGNUM_RAND(rand);
440 BIGNUM_RAND(pseudo_rand);
442 #define BIGNUM_RAND_RANGE(func) \
443 static VALUE \
444 ossl_bn_s_##func##_range(VALUE klass, VALUE range) \
446 BIGNUM *bn = GetBNPtr(range), *result; \
447 VALUE obj; \
448 if (!(result = BN_new())) { \
449 ossl_raise(eBNError, NULL); \
451 if (!BN_##func##_range(result, bn)) { \
452 BN_free(result); \
453 ossl_raise(eBNError, NULL); \
455 WrapBN(klass, obj, result); \
456 return obj; \
458 BIGNUM_RAND_RANGE(rand);
459 BIGNUM_RAND_RANGE(pseudo_rand);
461 static VALUE
462 ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass)
464 BIGNUM *add = NULL, *rem = NULL, *result;
465 int safe = 1, num;
466 VALUE vnum, vsafe, vadd, vrem, obj;
468 rb_scan_args(argc, argv, "13", &vnum, &vsafe, &vadd, &vrem);
470 num = NUM2INT(vnum);
472 if (vsafe == Qfalse) {
473 safe = 0;
475 if (!NIL_P(vadd)) {
476 if (NIL_P(vrem)) {
477 ossl_raise(rb_eArgError,
478 "if ADD is specified, REM must be also given");
480 add = GetBNPtr(vadd);
481 rem = GetBNPtr(vrem);
483 if (!(result = BN_new())) {
484 ossl_raise(eBNError, NULL);
486 if (!BN_generate_prime(result, num, safe, add, rem, NULL, NULL)) {
487 BN_free(result);
488 ossl_raise(eBNError, NULL);
490 WrapBN(klass, obj, result);
492 return obj;
495 #define BIGNUM_NUM(func) \
496 static VALUE \
497 ossl_bn_##func(VALUE self) \
499 BIGNUM *bn; \
500 GetBN(self, bn); \
501 return INT2FIX(BN_##func(bn)); \
503 BIGNUM_NUM(num_bytes);
504 BIGNUM_NUM(num_bits);
506 static VALUE
507 ossl_bn_copy(VALUE self, VALUE other)
509 BIGNUM *bn1, *bn2;
511 rb_check_frozen(self);
513 if (self == other) return self;
515 GetBN(self, bn1);
516 bn2 = GetBNPtr(other);
518 if (!BN_copy(bn1, bn2)) {
519 ossl_raise(eBNError, NULL);
521 return self;
524 #define BIGNUM_CMP(func) \
525 static VALUE \
526 ossl_bn_##func(VALUE self, VALUE other) \
528 BIGNUM *bn1, *bn2 = GetBNPtr(other); \
529 GetBN(self, bn1); \
530 return INT2FIX(BN_##func(bn1, bn2)); \
532 BIGNUM_CMP(cmp);
533 BIGNUM_CMP(ucmp);
535 static VALUE
536 ossl_bn_eql(VALUE self, VALUE other)
538 if (ossl_bn_cmp(self, other) == INT2FIX(0)) {
539 return Qtrue;
541 return Qfalse;
544 static VALUE
545 ossl_bn_is_prime(int argc, VALUE *argv, VALUE self)
547 BIGNUM *bn;
548 VALUE vchecks;
549 int checks = BN_prime_checks;
551 if (rb_scan_args(argc, argv, "01", &vchecks) == 0) {
552 checks = NUM2INT(vchecks);
554 GetBN(self, bn);
555 switch (BN_is_prime(bn, checks, NULL, ossl_bn_ctx, NULL)) {
556 case 1:
557 return Qtrue;
558 case 0:
559 return Qfalse;
560 default:
561 ossl_raise(eBNError, NULL);
563 /* not reachable */
564 return Qnil;
567 static VALUE
568 ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self)
570 BIGNUM *bn;
571 VALUE vchecks, vtrivdiv;
572 int checks = BN_prime_checks, do_trial_division = 1;
574 rb_scan_args(argc, argv, "02", &vchecks, &vtrivdiv);
576 if (!NIL_P(vchecks)) {
577 checks = NUM2INT(vchecks);
579 GetBN(self, bn);
580 /* handle true/false */
581 if (vtrivdiv == Qfalse) {
582 do_trial_division = 0;
584 switch (BN_is_prime_fasttest(bn, checks, NULL, ossl_bn_ctx, NULL, do_trial_division)) {
585 case 1:
586 return Qtrue;
587 case 0:
588 return Qfalse;
589 default:
590 ossl_raise(eBNError, NULL);
592 /* not reachable */
593 return Qnil;
597 * INIT
598 * (NOTE: ordering of methods is the same as in 'man bn')
600 void
601 Init_ossl_bn()
603 #if 0 /* let rdoc know about mOSSL */
604 mOSSL = rb_define_module("OpenSSL");
605 #endif
607 if (!(ossl_bn_ctx = BN_CTX_new())) {
608 ossl_raise(rb_eRuntimeError, "Cannot init BN_CTX");
611 eBNError = rb_define_class_under(mOSSL, "BNError", eOSSLError);
613 cBN = rb_define_class_under(mOSSL, "BN", rb_cObject);
615 rb_define_alloc_func(cBN, ossl_bn_alloc);
616 rb_define_method(cBN, "initialize", ossl_bn_initialize, -1);
618 rb_define_copy_func(cBN, ossl_bn_copy);
619 rb_define_method(cBN, "copy", ossl_bn_copy, 1);
621 /* swap (=coerce?) */
623 rb_define_method(cBN, "num_bytes", ossl_bn_num_bytes, 0);
624 rb_define_method(cBN, "num_bits", ossl_bn_num_bits, 0);
625 /* num_bits_word */
627 rb_define_method(cBN, "+", ossl_bn_add, 1);
628 rb_define_method(cBN, "-", ossl_bn_sub, 1);
629 rb_define_method(cBN, "*", ossl_bn_mul, 1);
630 rb_define_method(cBN, "sqr", ossl_bn_sqr, 0);
631 rb_define_method(cBN, "/", ossl_bn_div, 1);
632 rb_define_method(cBN, "%", ossl_bn_mod, 1);
633 /* nnmod */
635 rb_define_method(cBN, "mod_add", ossl_bn_mod_add, 2);
636 rb_define_method(cBN, "mod_sub", ossl_bn_mod_sub, 2);
637 rb_define_method(cBN, "mod_mul", ossl_bn_mod_mul, 2);
638 rb_define_method(cBN, "mod_sqr", ossl_bn_mod_sqr, 1);
639 rb_define_method(cBN, "**", ossl_bn_exp, 1);
640 rb_define_method(cBN, "mod_exp", ossl_bn_mod_exp, 2);
641 rb_define_method(cBN, "gcd", ossl_bn_gcd, 1);
643 /* add_word
644 * sub_word
645 * mul_word
646 * div_word
647 * mod_word */
649 rb_define_method(cBN, "cmp", ossl_bn_cmp, 1);
650 rb_define_alias(cBN, "<=>", "cmp");
651 rb_define_method(cBN, "ucmp", ossl_bn_ucmp, 1);
652 rb_define_method(cBN, "eql?", ossl_bn_eql, 1);
653 rb_define_alias(cBN, "==", "eql?");
654 rb_define_alias(cBN, "===", "eql?");
655 rb_define_method(cBN, "zero?", ossl_bn_is_zero, 0);
656 rb_define_method(cBN, "one?", ossl_bn_is_one, 0);
657 /* is_word */
658 rb_define_method(cBN, "odd?", ossl_bn_is_odd, 0);
660 /* zero
661 * one
662 * value_one - DON'T IMPL.
663 * set_word
664 * get_word */
666 rb_define_singleton_method(cBN, "rand", ossl_bn_s_rand, -1);
667 rb_define_singleton_method(cBN, "pseudo_rand", ossl_bn_s_pseudo_rand, -1);
668 rb_define_singleton_method(cBN, "rand_range", ossl_bn_s_rand_range, 1);
669 rb_define_singleton_method(cBN, "pseudo_rand_range", ossl_bn_s_pseudo_rand_range, 1);
671 rb_define_singleton_method(cBN, "generate_prime", ossl_bn_s_generate_prime, -1);
672 rb_define_method(cBN, "prime?", ossl_bn_is_prime, -1);
674 rb_define_method(cBN, "set_bit!", ossl_bn_set_bit, 1);
675 rb_define_method(cBN, "clear_bit!", ossl_bn_clear_bit, 1);
676 rb_define_method(cBN, "bit_set?", ossl_bn_is_bit_set, 1);
677 rb_define_method(cBN, "mask_bits!", ossl_bn_mask_bits, 1);
678 rb_define_method(cBN, "<<", ossl_bn_lshift, 1);
679 /* lshift1 - DON'T IMPL. */
680 rb_define_method(cBN, ">>", ossl_bn_rshift, 1);
681 /* rshift1 - DON'T IMPL. */
684 * bn2bin
685 * bin2bn
686 * bn2hex
687 * bn2dec
688 * hex2bn
689 * dec2bn - all these are implemented in ossl_bn_initialize, and ossl_bn_to_s
690 * print - NOT IMPL.
691 * print_fp - NOT IMPL.
692 * bn2mpi
693 * mpi2bn
695 rb_define_method(cBN, "to_s", ossl_bn_to_s, -1);
696 rb_define_method(cBN, "to_i", ossl_bn_to_i, 0);
697 rb_define_alias(cBN, "to_int", "to_i");
698 rb_define_method(cBN, "to_bn", ossl_bn_to_bn, 0);
699 rb_define_method(cBN, "coerce", ossl_bn_coerce, 1);
702 * TODO:
703 * But how to: from_bin, from_mpi? PACK?
704 * to_bin
705 * to_mpi
708 rb_define_method(cBN, "mod_inverse", ossl_bn_mod_inverse, 1);
710 /* RECiProcal
711 * MONTgomery */
714 * TODO:
715 * Where to belong these?
717 rb_define_method(cBN, "prime_fasttest?", ossl_bn_is_prime_fasttest, -1);