ext/openssl/ossl_bn.c

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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7