Ruby 1.9.3p327(2012-11-10revision37606)
ext/openssl/ossl_bn.c
Go to the documentation of this file.
00001 /*
00002  * $Id: ossl_bn.c 31166 2011-03-24 07:29:21Z naruse $
00003  * 'OpenSSL for Ruby' project
00004  * Copyright (C) 2001-2002  Technorama team <oss-ruby@technorama.net>
00005  * All rights reserved.
00006  */
00007 /*
00008  * This program is licenced under the same licence as Ruby.
00009  * (See the file 'LICENCE'.)
00010  */
00011 /* modified by Michal Rokos <m.rokos@sh.cvut.cz> */
00012 #include "ossl.h"
00013 
00014 #define WrapBN(klass, obj, bn) do { \
00015   if (!(bn)) { \
00016     ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
00017   } \
00018   (obj) = Data_Wrap_Struct((klass), 0, BN_clear_free, (bn)); \
00019 } while (0)
00020 
00021 #define GetBN(obj, bn) do { \
00022   Data_Get_Struct((obj), BIGNUM, (bn)); \
00023   if (!(bn)) { \
00024     ossl_raise(rb_eRuntimeError, "BN wasn't initialized!"); \
00025   } \
00026 } while (0)
00027 
00028 #define SafeGetBN(obj, bn) do { \
00029   OSSL_Check_Kind((obj), cBN); \
00030   GetBN((obj), (bn)); \
00031 } while (0)
00032 
00033 /*
00034  * Classes
00035  */
00036 VALUE cBN;
00037 VALUE eBNError;
00038 
00039 /*
00040  * Public
00041  */
00042 VALUE
00043 ossl_bn_new(const BIGNUM *bn)
00044 {
00045     BIGNUM *newbn;
00046     VALUE obj;
00047 
00048     newbn = bn ? BN_dup(bn) : BN_new();
00049     if (!newbn) {
00050         ossl_raise(eBNError, NULL);
00051     }
00052     WrapBN(cBN, obj, newbn);
00053 
00054     return obj;
00055 }
00056 
00057 BIGNUM *
00058 GetBNPtr(VALUE obj)
00059 {
00060     BIGNUM *bn = NULL;
00061 
00062     if (RTEST(rb_obj_is_kind_of(obj, cBN))) {
00063         GetBN(obj, bn);
00064     } else switch (TYPE(obj)) {
00065     case T_FIXNUM:
00066     case T_BIGNUM:
00067         obj = rb_String(obj);
00068         if (!BN_dec2bn(&bn, StringValuePtr(obj))) {
00069             ossl_raise(eBNError, NULL);
00070         }
00071         WrapBN(cBN, obj, bn); /* Handle potencial mem leaks */
00072         break;
00073     case T_NIL:
00074         break;
00075     default:
00076         ossl_raise(rb_eTypeError, "Cannot convert into OpenSSL::BN");
00077     }
00078     return bn;
00079 }
00080 
00081 /*
00082  * Private
00083  */
00084 /*
00085  * BN_CTX - is used in more difficult math. ops
00086  * (Why just 1? Because Ruby itself isn't thread safe,
00087  *  we don't need to care about threads)
00088  */
00089 BN_CTX *ossl_bn_ctx;
00090 
00091 static VALUE
00092 ossl_bn_alloc(VALUE klass)
00093 {
00094     BIGNUM *bn;
00095     VALUE obj;
00096 
00097     if (!(bn = BN_new())) {
00098         ossl_raise(eBNError, NULL);
00099     }
00100     WrapBN(klass, obj, bn);
00101 
00102     return obj;
00103 }
00104 
00105 /*
00106  * call-seq:
00107  *    BN.new => aBN
00108  *    BN.new(bn) => aBN
00109  *    BN.new(string) => aBN
00110  *    BN.new(string, 0 | 2 | 10 | 16) => aBN
00111  */
00112 static VALUE
00113 ossl_bn_initialize(int argc, VALUE *argv, VALUE self)
00114 {
00115     BIGNUM *bn;
00116     VALUE str, bs;
00117     int base = 10;
00118 
00119     if (rb_scan_args(argc, argv, "11", &str, &bs) == 2) {
00120         base = NUM2INT(bs);
00121     }
00122     StringValue(str);
00123     GetBN(self, bn);
00124     if (RTEST(rb_obj_is_kind_of(str, cBN))) {
00125         BIGNUM *other;
00126 
00127         GetBN(str, other); /* Safe - we checked kind_of? above */
00128         if (!BN_copy(bn, other)) {
00129             ossl_raise(eBNError, NULL);
00130         }
00131         return self;
00132     }
00133 
00134     switch (base) {
00135     case 0:
00136         if (!BN_mpi2bn((unsigned char *)RSTRING_PTR(str), RSTRING_LENINT(str), bn)) {
00137             ossl_raise(eBNError, NULL);
00138         }
00139         break;
00140     case 2:
00141         if (!BN_bin2bn((unsigned char *)RSTRING_PTR(str), RSTRING_LENINT(str), bn)) {
00142             ossl_raise(eBNError, NULL);
00143         }
00144         break;
00145     case 10:
00146         if (!BN_dec2bn(&bn, RSTRING_PTR(str))) {
00147             ossl_raise(eBNError, NULL);
00148         }
00149         break;
00150     case 16:
00151         if (!BN_hex2bn(&bn, RSTRING_PTR(str))) {
00152             ossl_raise(eBNError, NULL);
00153         }
00154         break;
00155     default:
00156         ossl_raise(rb_eArgError, "invalid radix %d", base);
00157     }
00158     return self;
00159 }
00160 
00161 /*
00162  * call-seq:
00163  *    bn.to_s => string
00164  *    bn.to_s(base) => string
00165  *
00166  * === Parameters
00167  * * +base+ - integer
00168  * * * Valid values:
00169  * * * * 0 - MPI
00170  * * * * 2 - binary
00171  * * * * 10 - the default
00172  * * * * 16 - hex
00173  */
00174 static VALUE
00175 ossl_bn_to_s(int argc, VALUE *argv, VALUE self)
00176 {
00177     BIGNUM *bn;
00178     VALUE str, bs;
00179     int base = 10, len;
00180     char *buf;
00181 
00182     if (rb_scan_args(argc, argv, "01", &bs) == 1) {
00183         base = NUM2INT(bs);
00184     }
00185     GetBN(self, bn);
00186     switch (base) {
00187     case 0:
00188         len = BN_bn2mpi(bn, NULL);
00189         str = rb_str_new(0, len);
00190         if (BN_bn2mpi(bn, (unsigned char *)RSTRING_PTR(str)) != len)
00191             ossl_raise(eBNError, NULL);
00192         break;
00193     case 2:
00194         len = BN_num_bytes(bn);
00195         str = rb_str_new(0, len);
00196         if (BN_bn2bin(bn, (unsigned char *)RSTRING_PTR(str)) != len)
00197             ossl_raise(eBNError, NULL);
00198         break;
00199     case 10:
00200         if (!(buf = BN_bn2dec(bn))) ossl_raise(eBNError, NULL);
00201         str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
00202         break;
00203     case 16:
00204         if (!(buf = BN_bn2hex(bn))) ossl_raise(eBNError, NULL);
00205         str = ossl_buf2str(buf, rb_long2int(strlen(buf)));
00206         break;
00207     default:
00208         ossl_raise(rb_eArgError, "invalid radix %d", base);
00209     }
00210 
00211     return str;
00212 }
00213 
00214 /*
00215  * call-seq:
00216  *    bn.to_i => integer
00217  */
00218 static VALUE
00219 ossl_bn_to_i(VALUE self)
00220 {
00221     BIGNUM *bn;
00222     char *txt;
00223     VALUE num;
00224 
00225     GetBN(self, bn);
00226 
00227     if (!(txt = BN_bn2dec(bn))) {
00228         ossl_raise(eBNError, NULL);
00229     }
00230     num = rb_cstr_to_inum(txt, 10, Qtrue);
00231     OPENSSL_free(txt);
00232 
00233     return num;
00234 }
00235 
00236 static VALUE
00237 ossl_bn_to_bn(VALUE self)
00238 {
00239     return self;
00240 }
00241 
00242 static VALUE
00243 ossl_bn_coerce(VALUE self, VALUE other)
00244 {
00245     switch(TYPE(other)) {
00246     case T_STRING:
00247         self = ossl_bn_to_s(0, NULL, self);
00248         break;
00249     case T_FIXNUM:
00250     case T_BIGNUM:
00251         self = ossl_bn_to_i(self);
00252         break;
00253     default:
00254         if (!RTEST(rb_obj_is_kind_of(other, cBN))) {
00255             ossl_raise(rb_eTypeError, "Don't know how to coerce");
00256         }
00257     }
00258     return rb_assoc_new(other, self);
00259 }
00260 
00261 #define BIGNUM_BOOL1(func)                              \
00262     /*                                                  \
00263      * call-seq:                                        \
00264      *   bn.##func -> true | false                      \
00265      *                                                  \
00266      */                                                 \
00267     static VALUE                                        \
00268     ossl_bn_##func(VALUE self)                          \
00269     {                                                   \
00270         BIGNUM *bn;                                     \
00271         GetBN(self, bn);                                \
00272         if (BN_##func(bn)) {                            \
00273             return Qtrue;                               \
00274         }                                               \
00275         return Qfalse;                                  \
00276     }
00277 BIGNUM_BOOL1(is_zero)
00278 BIGNUM_BOOL1(is_one)
00279 BIGNUM_BOOL1(is_odd)
00280 
00281 #define BIGNUM_1c(func)                                 \
00282     /*                                                  \
00283      * call-seq:                                        \
00284      *   bn.##func -> aBN                               \
00285      *                                                  \
00286      */                                                 \
00287     static VALUE                                        \
00288     ossl_bn_##func(VALUE self)                          \
00289     {                                                   \
00290         BIGNUM *bn, *result;                            \
00291         VALUE obj;                                      \
00292         GetBN(self, bn);                                \
00293         if (!(result = BN_new())) {                     \
00294             ossl_raise(eBNError, NULL);                 \
00295         }                                               \
00296         if (!BN_##func(result, bn, ossl_bn_ctx)) {      \
00297             BN_free(result);                            \
00298             ossl_raise(eBNError, NULL);                 \
00299         }                                               \
00300         WrapBN(CLASS_OF(self), obj, result);            \
00301         return obj;                                     \
00302     }
00303 BIGNUM_1c(sqr)
00304 
00305 #define BIGNUM_2(func)                                  \
00306     /*                                                  \
00307      * call-seq:                                        \
00308      *   bn.##func(bn2) -> aBN                          \
00309      *                                                  \
00310      */                                                 \
00311     static VALUE                                        \
00312     ossl_bn_##func(VALUE self, VALUE other)             \
00313     {                                                   \
00314         BIGNUM *bn1, *bn2 = GetBNPtr(other), *result;   \
00315         VALUE obj;                                      \
00316         GetBN(self, bn1);                               \
00317         if (!(result = BN_new())) {                     \
00318             ossl_raise(eBNError, NULL);                 \
00319         }                                               \
00320         if (!BN_##func(result, bn1, bn2)) {             \
00321             BN_free(result);                            \
00322             ossl_raise(eBNError, NULL);                 \
00323         }                                               \
00324         WrapBN(CLASS_OF(self), obj, result);            \
00325         return obj;                                     \
00326     }
00327 BIGNUM_2(add)
00328 BIGNUM_2(sub)
00329 
00330 #define BIGNUM_2c(func)                                         \
00331     /*                                                          \
00332      * call-seq:                                                \
00333      *   bn.##func(bn2) -> aBN                                  \
00334      *                                                          \
00335      */                                                         \
00336     static VALUE                                                \
00337     ossl_bn_##func(VALUE self, VALUE other)                     \
00338     {                                                           \
00339         BIGNUM *bn1, *bn2 = GetBNPtr(other), *result;           \
00340         VALUE obj;                                              \
00341         GetBN(self, bn1);                                       \
00342         if (!(result = BN_new())) {                             \
00343             ossl_raise(eBNError, NULL);                         \
00344         }                                                       \
00345         if (!BN_##func(result, bn1, bn2, ossl_bn_ctx)) {        \
00346             BN_free(result);                                    \
00347             ossl_raise(eBNError, NULL);                         \
00348         }                                                       \
00349         WrapBN(CLASS_OF(self), obj, result);                    \
00350         return obj;                                             \
00351     }
00352 BIGNUM_2c(mul)
00353 BIGNUM_2c(mod)
00354 BIGNUM_2c(exp)
00355 BIGNUM_2c(gcd)
00356 BIGNUM_2c(mod_sqr)
00357 BIGNUM_2c(mod_inverse)
00358 
00359 /*
00360  * call-seq:
00361  *    bn1 / bn2 => [result, remainder]
00362  */
00363 static VALUE
00364 ossl_bn_div(VALUE self, VALUE other)
00365 {
00366     BIGNUM *bn1, *bn2 = GetBNPtr(other), *r1, *r2;
00367     VALUE obj1, obj2;
00368 
00369     GetBN(self, bn1);
00370 
00371     if (!(r1 = BN_new())) {
00372         ossl_raise(eBNError, NULL);
00373     }
00374     if (!(r2 = BN_new())) {
00375         BN_free(r1);
00376         ossl_raise(eBNError, NULL);
00377     }
00378     if (!BN_div(r1, r2, bn1, bn2, ossl_bn_ctx)) {
00379         BN_free(r1);
00380         BN_free(r2);
00381         ossl_raise(eBNError, NULL);
00382     }
00383     WrapBN(CLASS_OF(self), obj1, r1);
00384     WrapBN(CLASS_OF(self), obj2, r2);
00385 
00386     return rb_ary_new3(2, obj1, obj2);
00387 }
00388 
00389 #define BIGNUM_3c(func)                                         \
00390     /*                                                          \
00391      * call-seq:                                                \
00392      *   bn.##func(bn1, bn2) -> aBN                             \
00393      *                                                          \
00394      */                                                         \
00395     static VALUE                                                \
00396     ossl_bn_##func(VALUE self, VALUE other1, VALUE other2)      \
00397     {                                                           \
00398         BIGNUM *bn1, *bn2 = GetBNPtr(other1);                   \
00399         BIGNUM *bn3 = GetBNPtr(other2), *result;                \
00400         VALUE obj;                                              \
00401         GetBN(self, bn1);                                       \
00402         if (!(result = BN_new())) {                             \
00403             ossl_raise(eBNError, NULL);                         \
00404         }                                                       \
00405         if (!BN_##func(result, bn1, bn2, bn3, ossl_bn_ctx)) {   \
00406             BN_free(result);                                    \
00407             ossl_raise(eBNError, NULL);                         \
00408         }                                                       \
00409         WrapBN(CLASS_OF(self), obj, result);                    \
00410         return obj;                                             \
00411     }
00412 BIGNUM_3c(mod_add)
00413 BIGNUM_3c(mod_sub)
00414 BIGNUM_3c(mod_mul)
00415 BIGNUM_3c(mod_exp)
00416 
00417 #define BIGNUM_BIT(func)                                \
00418     /*                                                  \
00419      * call-seq:                                        \
00420      *   bn.##func(bit) -> self                         \
00421      *                                                  \
00422      */                                                 \
00423     static VALUE                                        \
00424     ossl_bn_##func(VALUE self, VALUE bit)               \
00425     {                                                   \
00426         BIGNUM *bn;                                     \
00427         GetBN(self, bn);                                \
00428         if (!BN_##func(bn, NUM2INT(bit))) {             \
00429             ossl_raise(eBNError, NULL);                 \
00430         }                                               \
00431         return self;                                    \
00432     }
00433 BIGNUM_BIT(set_bit)
00434 BIGNUM_BIT(clear_bit)
00435 BIGNUM_BIT(mask_bits)
00436 
00437 /*
00438  * call-seq:
00439  *    bn.bit_set?(bit) => true | false
00440  */
00441 static VALUE
00442 ossl_bn_is_bit_set(VALUE self, VALUE bit)
00443 {
00444     int b;
00445     BIGNUM *bn;
00446 
00447     b = NUM2INT(bit);
00448     GetBN(self, bn);
00449     if (BN_is_bit_set(bn, b)) {
00450         return Qtrue;
00451     }
00452     return Qfalse;
00453 }
00454 
00455 #define BIGNUM_SHIFT(func)                              \
00456     /*                                                  \
00457      * call-seq:                                        \
00458      *   bn.##func(bits) -> aBN                         \
00459      *                                                  \
00460      */                                                 \
00461     static VALUE                                        \
00462     ossl_bn_##func(VALUE self, VALUE bits)              \
00463     {                                                   \
00464         BIGNUM *bn, *result;                            \
00465         int b;                                          \
00466         VALUE obj;                                      \
00467         b = NUM2INT(bits);                              \
00468         GetBN(self, bn);                                \
00469         if (!(result = BN_new())) {                     \
00470                 ossl_raise(eBNError, NULL);             \
00471         }                                               \
00472         if (!BN_##func(result, bn, b)) {                \
00473                 BN_free(result);                        \
00474                 ossl_raise(eBNError, NULL);             \
00475         }                                               \
00476         WrapBN(CLASS_OF(self), obj, result);            \
00477         return obj;                                     \
00478     }
00479 BIGNUM_SHIFT(lshift)
00480 BIGNUM_SHIFT(rshift)
00481 
00482 #define BIGNUM_SELF_SHIFT(func)                         \
00483     /*                                                  \
00484      * call-seq:                                        \
00485      *   bn.##func!(bits) -> self                       \
00486      *                                                  \
00487      */                                                 \
00488     static VALUE                                        \
00489     ossl_bn_self_##func(VALUE self, VALUE bits)         \
00490     {                                                   \
00491         BIGNUM *bn;                                     \
00492         int b;                                          \
00493         b = NUM2INT(bits);                              \
00494         GetBN(self, bn);                                \
00495         if (!BN_##func(bn, bn, b))                      \
00496                 ossl_raise(eBNError, NULL);             \
00497         return self;                                    \
00498     }
00499 BIGNUM_SELF_SHIFT(lshift)
00500 BIGNUM_SELF_SHIFT(rshift)
00501 
00502 #define BIGNUM_RAND(func)                                       \
00503     /*                                                          \
00504      * call-seq:                                                \
00505      *   BN.##func(bits [, fill [, odd]]) -> aBN                \
00506      *                                                          \
00507      */                                                         \
00508     static VALUE                                                \
00509     ossl_bn_s_##func(int argc, VALUE *argv, VALUE klass)        \
00510     {                                                           \
00511         BIGNUM *result;                                         \
00512         int bottom = 0, top = 0, b;                             \
00513         VALUE bits, fill, odd, obj;                             \
00514                                                                 \
00515         switch (rb_scan_args(argc, argv, "12", &bits, &fill, &odd)) {   \
00516         case 3:                                                 \
00517             bottom = (odd == Qtrue) ? 1 : 0;                    \
00518             /* FALLTHROUGH */                                   \
00519         case 2:                                                 \
00520             top = NUM2INT(fill);                                \
00521         }                                                       \
00522         b = NUM2INT(bits);                                      \
00523         if (!(result = BN_new())) {                             \
00524             ossl_raise(eBNError, NULL);                         \
00525         }                                                       \
00526         if (!BN_##func(result, b, top, bottom)) {               \
00527             BN_free(result);                                    \
00528             ossl_raise(eBNError, NULL);                         \
00529         }                                                       \
00530         WrapBN(klass, obj, result);                             \
00531         return obj;                                             \
00532     }
00533 BIGNUM_RAND(rand)
00534 BIGNUM_RAND(pseudo_rand)
00535 
00536 #define BIGNUM_RAND_RANGE(func)                                 \
00537     /*                                                          \
00538      * call-seq:                                                \
00539      *   BN.##func(range) -> aBN                                \
00540      *                                                          \
00541      */                                                         \
00542     static VALUE                                                \
00543     ossl_bn_s_##func##_range(VALUE klass, VALUE range)          \
00544     {                                                           \
00545         BIGNUM *bn = GetBNPtr(range), *result;                  \
00546         VALUE obj;                                              \
00547         if (!(result = BN_new())) {                             \
00548             ossl_raise(eBNError, NULL);                         \
00549         }                                                       \
00550         if (!BN_##func##_range(result, bn)) {                   \
00551             BN_free(result);                                    \
00552             ossl_raise(eBNError, NULL);                         \
00553         }                                                       \
00554         WrapBN(klass, obj, result);                             \
00555         return obj;                                             \
00556     }
00557 BIGNUM_RAND_RANGE(rand)
00558 BIGNUM_RAND_RANGE(pseudo_rand)
00559 
00560 /*
00561  * call-seq:
00562  *    BN.generate_prime(bits, [, safe [, add [, rem]]]) => bn
00563  *
00564  * === Parameters
00565  * * +bits+ - integer
00566  * * +safe+ - boolean
00567  * * +add+ - BN
00568  * * +rem+ - BN
00569  */
00570 static VALUE
00571 ossl_bn_s_generate_prime(int argc, VALUE *argv, VALUE klass)
00572 {
00573     BIGNUM *add = NULL, *rem = NULL, *result;
00574     int safe = 1, num;
00575     VALUE vnum, vsafe, vadd, vrem, obj;
00576 
00577     rb_scan_args(argc, argv, "13", &vnum, &vsafe, &vadd, &vrem);
00578 
00579     num = NUM2INT(vnum);
00580 
00581     if (vsafe == Qfalse) {
00582         safe = 0;
00583     }
00584     if (!NIL_P(vadd)) {
00585         add = GetBNPtr(vadd);
00586         rem = NIL_P(vrem) ? NULL : GetBNPtr(vrem);
00587     }
00588     if (!(result = BN_new())) {
00589         ossl_raise(eBNError, NULL);
00590     }
00591     if (!BN_generate_prime(result, num, safe, add, rem, NULL, NULL)) {
00592         BN_free(result);
00593         ossl_raise(eBNError, NULL);
00594     }
00595     WrapBN(klass, obj, result);
00596 
00597     return obj;
00598 }
00599 
00600 #define BIGNUM_NUM(func)                        \
00601     /*                                                  \
00602      * call-seq:                                        \
00603      *   bn.##func -> integer                           \
00604      *                                                  \
00605      */                                                 \
00606     static VALUE                                \
00607     ossl_bn_##func(VALUE self)                  \
00608     {                                           \
00609         BIGNUM *bn;                             \
00610         GetBN(self, bn);                        \
00611         return INT2FIX(BN_##func(bn));          \
00612     }
00613 BIGNUM_NUM(num_bytes)
00614 BIGNUM_NUM(num_bits)
00615 
00616 static VALUE
00617 ossl_bn_copy(VALUE self, VALUE other)
00618 {
00619     BIGNUM *bn1, *bn2;
00620 
00621     rb_check_frozen(self);
00622 
00623     if (self == other) return self;
00624 
00625     GetBN(self, bn1);
00626     bn2 = GetBNPtr(other);
00627 
00628     if (!BN_copy(bn1, bn2)) {
00629         ossl_raise(eBNError, NULL);
00630     }
00631     return self;
00632 }
00633 
00634 #define BIGNUM_CMP(func)                                \
00635     /*                                                  \
00636      * call-seq:                                        \
00637      *   bn.##func(bn2) -> integer                      \
00638      *                                                  \
00639      */                                                 \
00640     static VALUE                                        \
00641     ossl_bn_##func(VALUE self, VALUE other)             \
00642     {                                                   \
00643         BIGNUM *bn1, *bn2 = GetBNPtr(other);            \
00644         GetBN(self, bn1);                               \
00645         return INT2FIX(BN_##func(bn1, bn2));            \
00646     }
00647 BIGNUM_CMP(cmp)
00648 BIGNUM_CMP(ucmp)
00649 
00650 static VALUE
00651 ossl_bn_eql(VALUE self, VALUE other)
00652 {
00653     if (ossl_bn_cmp(self, other) == INT2FIX(0)) {
00654         return Qtrue;
00655     }
00656     return Qfalse;
00657 }
00658 
00659 /*
00660  * call-seq:
00661  *    bn.prime? => true | false
00662  *    bn.prime?(checks) => true | false
00663  *
00664  * === Parameters
00665  * * +checks+ - integer
00666  */
00667 static VALUE
00668 ossl_bn_is_prime(int argc, VALUE *argv, VALUE self)
00669 {
00670     BIGNUM *bn;
00671     VALUE vchecks;
00672     int checks = BN_prime_checks;
00673 
00674     if (rb_scan_args(argc, argv, "01", &vchecks) == 1) {
00675         checks = NUM2INT(vchecks);
00676     }
00677     GetBN(self, bn);
00678     switch (BN_is_prime(bn, checks, NULL, ossl_bn_ctx, NULL)) {
00679     case 1:
00680         return Qtrue;
00681     case 0:
00682         return Qfalse;
00683     default:
00684         ossl_raise(eBNError, NULL);
00685     }
00686     /* not reachable */
00687     return Qnil;
00688 }
00689 
00690 /*
00691  * call-seq:
00692  *    bn.prime_fasttest? => true | false
00693  *    bn.prime_fasttest?(checks) => true | false
00694  *    bn.prime_fasttest?(checks, trial_div) => true | false
00695  *
00696  * === Parameters
00697  * * +checks+ - integer
00698  * * +trial_div+ - boolean
00699  */
00700 static VALUE
00701 ossl_bn_is_prime_fasttest(int argc, VALUE *argv, VALUE self)
00702 {
00703     BIGNUM *bn;
00704     VALUE vchecks, vtrivdiv;
00705     int checks = BN_prime_checks, do_trial_division = 1;
00706 
00707     rb_scan_args(argc, argv, "02", &vchecks, &vtrivdiv);
00708 
00709     if (!NIL_P(vchecks)) {
00710         checks = NUM2INT(vchecks);
00711     }
00712     GetBN(self, bn);
00713     /* handle true/false */
00714     if (vtrivdiv == Qfalse) {
00715         do_trial_division = 0;
00716     }
00717     switch (BN_is_prime_fasttest(bn, checks, NULL, ossl_bn_ctx, NULL, do_trial_division)) {
00718     case 1:
00719         return Qtrue;
00720     case 0:
00721         return Qfalse;
00722     default:
00723         ossl_raise(eBNError, NULL);
00724     }
00725     /* not reachable */
00726     return Qnil;
00727 }
00728 
00729 /*
00730  * INIT
00731  * (NOTE: ordering of methods is the same as in 'man bn')
00732  */
00733 void
00734 Init_ossl_bn()
00735 {
00736 #if 0
00737     mOSSL = rb_define_module("OpenSSL"); /* let rdoc know about mOSSL */
00738 #endif
00739 
00740     if (!(ossl_bn_ctx = BN_CTX_new())) {
00741         ossl_raise(rb_eRuntimeError, "Cannot init BN_CTX");
00742     }
00743 
00744     eBNError = rb_define_class_under(mOSSL, "BNError", eOSSLError);
00745 
00746     cBN = rb_define_class_under(mOSSL, "BN", rb_cObject);
00747 
00748     rb_define_alloc_func(cBN, ossl_bn_alloc);
00749     rb_define_method(cBN, "initialize", ossl_bn_initialize, -1);
00750 
00751     rb_define_copy_func(cBN, ossl_bn_copy);
00752     rb_define_method(cBN, "copy", ossl_bn_copy, 1);
00753 
00754     /* swap (=coerce?) */
00755 
00756     rb_define_method(cBN, "num_bytes", ossl_bn_num_bytes, 0);
00757     rb_define_method(cBN, "num_bits", ossl_bn_num_bits, 0);
00758     /* num_bits_word */
00759 
00760     rb_define_method(cBN, "+", ossl_bn_add, 1);
00761     rb_define_method(cBN, "-", ossl_bn_sub, 1);
00762     rb_define_method(cBN, "*", ossl_bn_mul, 1);
00763     rb_define_method(cBN, "sqr", ossl_bn_sqr, 0);
00764     rb_define_method(cBN, "/", ossl_bn_div, 1);
00765     rb_define_method(cBN, "%", ossl_bn_mod, 1);
00766     /* nnmod */
00767 
00768     rb_define_method(cBN, "mod_add", ossl_bn_mod_add, 2);
00769     rb_define_method(cBN, "mod_sub", ossl_bn_mod_sub, 2);
00770     rb_define_method(cBN, "mod_mul", ossl_bn_mod_mul, 2);
00771     rb_define_method(cBN, "mod_sqr", ossl_bn_mod_sqr, 1);
00772     rb_define_method(cBN, "**", ossl_bn_exp, 1);
00773     rb_define_method(cBN, "mod_exp", ossl_bn_mod_exp, 2);
00774     rb_define_method(cBN, "gcd", ossl_bn_gcd, 1);
00775 
00776     /* add_word
00777      * sub_word
00778      * mul_word
00779      * div_word
00780      * mod_word */
00781 
00782     rb_define_method(cBN, "cmp", ossl_bn_cmp, 1);
00783     rb_define_alias(cBN, "<=>", "cmp");
00784     rb_define_method(cBN, "ucmp", ossl_bn_ucmp, 1);
00785     rb_define_method(cBN, "eql?", ossl_bn_eql, 1);
00786     rb_define_alias(cBN, "==", "eql?");
00787     rb_define_alias(cBN, "===", "eql?");
00788     rb_define_method(cBN, "zero?", ossl_bn_is_zero, 0);
00789     rb_define_method(cBN, "one?", ossl_bn_is_one, 0);
00790     /* is_word */
00791     rb_define_method(cBN, "odd?", ossl_bn_is_odd, 0);
00792 
00793     /* zero
00794      * one
00795      * value_one - DON'T IMPL.
00796      * set_word
00797      * get_word */
00798 
00799     rb_define_singleton_method(cBN, "rand", ossl_bn_s_rand, -1);
00800     rb_define_singleton_method(cBN, "pseudo_rand", ossl_bn_s_pseudo_rand, -1);
00801     rb_define_singleton_method(cBN, "rand_range", ossl_bn_s_rand_range, 1);
00802     rb_define_singleton_method(cBN, "pseudo_rand_range", ossl_bn_s_pseudo_rand_range, 1);
00803 
00804     rb_define_singleton_method(cBN, "generate_prime", ossl_bn_s_generate_prime, -1);
00805     rb_define_method(cBN, "prime?", ossl_bn_is_prime, -1);
00806 
00807     rb_define_method(cBN, "set_bit!", ossl_bn_set_bit, 1);
00808     rb_define_method(cBN, "clear_bit!", ossl_bn_clear_bit, 1);
00809     rb_define_method(cBN, "bit_set?", ossl_bn_is_bit_set, 1);
00810     rb_define_method(cBN, "mask_bits!", ossl_bn_mask_bits, 1);
00811     rb_define_method(cBN, "<<", ossl_bn_lshift, 1);
00812     rb_define_method(cBN, ">>", ossl_bn_rshift, 1);
00813     rb_define_method(cBN, "lshift!", ossl_bn_self_lshift, 1);
00814     rb_define_method(cBN, "rshift!", ossl_bn_self_rshift, 1);
00815     /* lshift1 - DON'T IMPL. */
00816     /* rshift1 - DON'T IMPL. */
00817 
00818     /*
00819      * bn2bin
00820      * bin2bn
00821      * bn2hex
00822      * bn2dec
00823      * hex2bn
00824      * dec2bn - all these are implemented in ossl_bn_initialize, and ossl_bn_to_s
00825      * print - NOT IMPL.
00826      * print_fp - NOT IMPL.
00827      * bn2mpi
00828      * mpi2bn
00829      */
00830     rb_define_method(cBN, "to_s", ossl_bn_to_s, -1);
00831     rb_define_method(cBN, "to_i", ossl_bn_to_i, 0);
00832     rb_define_alias(cBN, "to_int", "to_i");
00833     rb_define_method(cBN, "to_bn", ossl_bn_to_bn, 0);
00834     rb_define_method(cBN, "coerce", ossl_bn_coerce, 1);
00835 
00836     /*
00837      * TODO:
00838      * But how to: from_bin, from_mpi? PACK?
00839      * to_bin
00840      * to_mpi
00841      */
00842 
00843     rb_define_method(cBN, "mod_inverse", ossl_bn_mod_inverse, 1);
00844 
00845     /* RECiProcal
00846      * MONTgomery */
00847 
00848     /*
00849      * TODO:
00850      * Where to belong these?
00851      */
00852     rb_define_method(cBN, "prime_fasttest?", ossl_bn_is_prime_fasttest, -1);
00853 }
00854 
00855