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>
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> */
14 #define WrapBN(klass, obj, bn) do { \
16 ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
18 obj = Data_Wrap_Struct(klass, 0, BN_clear_free, bn); \
21 #define GetBN(obj, bn) do { \
22 Data_Get_Struct(obj, BIGNUM, bn); \
24 ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
28 #define SafeGetBN(obj, bn) do { \
29 OSSL_Check_Kind(obj, cBN); \
43 ossl_bn_new(BIGNUM
*bn
)
48 newbn
= bn
? BN_dup(bn
) : BN_new();
50 ossl_raise(eBNError
, NULL
);
52 WrapBN(cBN
, obj
, newbn
);
62 if (RTEST(rb_obj_is_kind_of(obj
, cBN
))) {
64 } else switch (TYPE(obj
)) {
68 if (!BN_dec2bn(&bn
, StringValuePtr(obj
))) {
69 ossl_raise(eBNError
, NULL
);
71 WrapBN(cBN
, obj
, bn
); /* Handle potencial mem leaks */
74 ossl_raise(rb_eTypeError
, "Cannot convert into OpenSSL::BN");
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)
90 ossl_bn_alloc(VALUE klass
)
95 if (!(bn
= BN_new())) {
96 ossl_raise(eBNError
, NULL
);
98 WrapBN(klass
, obj
, bn
);
104 ossl_bn_initialize(int argc
, VALUE
*argv
, VALUE self
)
110 if (rb_scan_args(argc
, argv
, "11", &str
, &bs
) == 2) {
115 if (RTEST(rb_obj_is_kind_of(str
, cBN
))) {
118 GetBN(str
, other
); /* Safe - we checked kind_of? above */
119 if (!BN_copy(bn
, other
)) {
120 ossl_raise(eBNError
, NULL
);
127 if (!BN_mpi2bn(RSTRING(str
)->ptr
, RSTRING(str
)->len
, bn
)) {
128 ossl_raise(eBNError
, NULL
);
132 if (!BN_bin2bn(RSTRING(str
)->ptr
, RSTRING(str
)->len
, bn
)) {
133 ossl_raise(eBNError
, NULL
);
137 if (!BN_dec2bn(&bn
, RSTRING(str
)->ptr
)) {
138 ossl_raise(eBNError
, NULL
);
142 if (!BN_hex2bn(&bn
, RSTRING(str
)->ptr
)) {
143 ossl_raise(eBNError
, NULL
);
147 ossl_raise(rb_eArgError
, "illegal radix %d", base
);
153 ossl_bn_to_s(int argc
, VALUE
*argv
, VALUE self
)
160 if (rb_scan_args(argc
, argv
, "01", &bs
) == 1) {
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
);
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
);
178 if (!(buf
= BN_bn2dec(bn
))) ossl_raise(eBNError
, NULL
);
179 str
= ossl_buf2str(buf
, strlen(buf
));
182 if (!(buf
= BN_bn2hex(bn
))) ossl_raise(eBNError
, NULL
);
183 str
= ossl_buf2str(buf
, strlen(buf
));
186 ossl_raise(rb_eArgError
, "illegal radix %d", base
);
193 ossl_bn_to_i(VALUE self
)
201 if (!(txt
= BN_bn2dec(bn
))) {
202 ossl_raise(eBNError
, NULL
);
204 num
= rb_cstr_to_inum(txt
, 10, Qtrue
);
211 ossl_bn_to_bn(VALUE self
)
217 ossl_bn_coerce(VALUE self
, VALUE other
)
219 switch(TYPE(other
)) {
221 self
= ossl_bn_to_s(0, NULL
, self
);
225 self
= ossl_bn_to_i(self
);
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) \
237 ossl_bn_##func(VALUE self) \
241 if (BN_##func(bn)) { \
246 BIGNUM_BOOL1(is_zero
);
247 BIGNUM_BOOL1(is_one
);
248 BIGNUM_BOOL1(is_odd
);
250 #define BIGNUM_1c(func) \
252 ossl_bn_##func(VALUE self) \
254 BIGNUM *bn, *result; \
257 if (!(result = BN_new())) { \
258 ossl_raise(eBNError, NULL); \
260 if (!BN_##func(result, bn, ossl_bn_ctx)) { \
262 ossl_raise(eBNError, NULL); \
264 WrapBN(CLASS_OF(self), obj, result); \
269 #define BIGNUM_2(func) \
271 ossl_bn_##func(VALUE self, VALUE other) \
273 BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
276 if (!(result = BN_new())) { \
277 ossl_raise(eBNError, NULL); \
279 if (!BN_##func(result, bn1, bn2)) { \
281 ossl_raise(eBNError, NULL); \
283 WrapBN(CLASS_OF(self), obj, result); \
289 #define BIGNUM_2c(func) \
291 ossl_bn_##func(VALUE self, VALUE other) \
293 BIGNUM *bn1, *bn2 = GetBNPtr(other), *result; \
296 if (!(result = BN_new())) { \
297 ossl_raise(eBNError, NULL); \
299 if (!BN_##func(result, bn1, bn2, ossl_bn_ctx)) { \
301 ossl_raise(eBNError, NULL); \
303 WrapBN(CLASS_OF(self), obj, result); \
311 BIGNUM_2c(mod_inverse
);
314 ossl_bn_div(VALUE self
, VALUE other
)
316 BIGNUM
*bn1
, *bn2
= GetBNPtr(other
), *r1
, *r2
;
321 if (!(r1
= BN_new())) {
322 ossl_raise(eBNError
, NULL
);
324 if (!(r2
= BN_new())) {
326 ossl_raise(eBNError
, NULL
);
328 if (!BN_div(r1
, r2
, bn1
, bn2
, ossl_bn_ctx
)) {
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) \
341 ossl_bn_##func(VALUE self, VALUE other1, VALUE other2) \
343 BIGNUM *bn1, *bn2 = GetBNPtr(other1); \
344 BIGNUM *bn3 = GetBNPtr(other2), *result; \
347 if (!(result = BN_new())) { \
348 ossl_raise(eBNError, NULL); \
350 if (!BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx)) { \
352 ossl_raise(eBNError, NULL); \
354 WrapBN(CLASS_OF(self), obj, result); \
362 #define BIGNUM_BIT(func) \
364 ossl_bn_##func(VALUE self, VALUE bit) \
368 if (!BN_##func(bn, NUM2INT(bit))) { \
369 ossl_raise(eBNError, NULL); \
374 BIGNUM_BIT(clear_bit
);
375 BIGNUM_BIT(mask_bits
);
378 ossl_bn_is_bit_set(VALUE self
, VALUE bit
)
385 if (BN_is_bit_set(bn
, b
)) {
391 #define BIGNUM_SHIFT(func) \
393 ossl_bn_##func(VALUE self, VALUE bits) \
395 BIGNUM *bn, *result; \
400 if (!(result = BN_new())) { \
401 ossl_raise(eBNError, NULL); \
403 if (!BN_##func(result, bn, b)) { \
405 ossl_raise(eBNError, NULL); \
407 WrapBN(CLASS_OF(self), obj, result); \
410 BIGNUM_SHIFT(lshift
);
411 BIGNUM_SHIFT(rshift
);
413 #define BIGNUM_RAND(func) \
415 ossl_bn_s_##func(int argc, VALUE *argv, VALUE klass) \
418 int bottom = 0, top = 0, b; \
419 VALUE bits, fill, odd, obj; \
421 switch (rb_scan_args(argc, argv, "12", &bits, &fill, &odd)) { \
423 bottom = (odd == Qtrue) ? 1 : 0; \
426 top = FIX2INT(fill); \
429 if (!(result = BN_new())) { \
430 ossl_raise(eBNError, NULL); \
432 if (!BN_##func(result, b, top, bottom)) { \
434 ossl_raise(eBNError, NULL); \
436 WrapBN(klass, obj, result); \
440 BIGNUM_RAND(pseudo_rand
);
442 #define BIGNUM_RAND_RANGE(func) \
444 ossl_bn_s_##func##_range(VALUE klass, VALUE range) \
446 BIGNUM *bn = GetBNPtr(range), *result; \
448 if (!(result = BN_new())) { \
449 ossl_raise(eBNError, NULL); \
451 if (!BN_##func##_range(result, bn)) { \
453 ossl_raise(eBNError, NULL); \
455 WrapBN(klass, obj, result); \
458 BIGNUM_RAND_RANGE(rand
);
459 BIGNUM_RAND_RANGE(pseudo_rand
);
462 ossl_bn_s_generate_prime(int argc
, VALUE
*argv
, VALUE klass
)
464 BIGNUM
*add
= NULL
, *rem
= NULL
, *result
;
466 VALUE vnum
, vsafe
, vadd
, vrem
, obj
;
468 rb_scan_args(argc
, argv
, "13", &vnum
, &vsafe
, &vadd
, &vrem
);
472 if (vsafe
== Qfalse
) {
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
)) {
488 ossl_raise(eBNError
, NULL
);
490 WrapBN(klass
, obj
, result
);
495 #define BIGNUM_NUM(func) \
497 ossl_bn_##func(VALUE self) \
501 return INT2FIX(BN_##func(bn)); \
503 BIGNUM_NUM(num_bytes
);
504 BIGNUM_NUM(num_bits
);
507 ossl_bn_copy(VALUE self
, VALUE other
)
511 rb_check_frozen(self
);
513 if (self
== other
) return self
;
516 bn2
= GetBNPtr(other
);
518 if (!BN_copy(bn1
, bn2
)) {
519 ossl_raise(eBNError
, NULL
);
524 #define BIGNUM_CMP(func) \
526 ossl_bn_##func(VALUE self, VALUE other) \
528 BIGNUM *bn1, *bn2 = GetBNPtr(other); \
530 return INT2FIX(BN_##func(bn1, bn2)); \
536 ossl_bn_eql(VALUE self
, VALUE other
)
538 if (ossl_bn_cmp(self
, other
) == INT2FIX(0)) {
545 ossl_bn_is_prime(int argc
, VALUE
*argv
, VALUE self
)
549 int checks
= BN_prime_checks
;
551 if (rb_scan_args(argc
, argv
, "01", &vchecks
) == 0) {
552 checks
= NUM2INT(vchecks
);
555 switch (BN_is_prime(bn
, checks
, NULL
, ossl_bn_ctx
, NULL
)) {
561 ossl_raise(eBNError
, NULL
);
568 ossl_bn_is_prime_fasttest(int argc
, VALUE
*argv
, VALUE self
)
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
);
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
)) {
590 ossl_raise(eBNError
, NULL
);
598 * (NOTE: ordering of methods is the same as in 'man bn')
603 #if 0 /* let rdoc know about mOSSL */
604 mOSSL
= rb_define_module("OpenSSL");
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);
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);
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);
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);
658 rb_define_method(cBN
, "odd?", ossl_bn_is_odd
, 0);
662 * value_one - DON'T IMPL.
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. */
689 * dec2bn - all these are implemented in ossl_bn_initialize, and ossl_bn_to_s
691 * print_fp - NOT IMPL.
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);
703 * But how to: from_bin, from_mpi? PACK?
708 rb_define_method(cBN
, "mod_inverse", ossl_bn_mod_inverse
, 1);
715 * Where to belong these?
717 rb_define_method(cBN
, "prime_fasttest?", ossl_bn_is_prime_fasttest
, -1);