diff options
author | Kazuki Yamaguchi <k@rhe.jp> | 2016-08-22 19:29:20 +0900 |
---|---|---|
committer | Kazuki Yamaguchi <k@rhe.jp> | 2016-08-22 19:29:20 +0900 |
commit | 106d42c93d24ba401778a235841f722fe51d65f8 (patch) | |
tree | a83835076099c40a37dc4c2ad9f5693cf57b7fbf /ext/openssl/ossl_bn.c | |
parent | be23fc960337e475af70419c5036cce215fd9ac9 (diff) | |
download | ruby-openssl-106d42c93d24ba401778a235841f722fe51d65f8.tar.gz |
bn: optimize try_convert_to_bnptr() for non-BN objectstopic/argument-conversion
Use the same logic as BN#initialize. It is used through GetBNPtr(). For
example, with this change, the following code will be about 7x faster:
puts Benchmark.measure {
a = 0.to_bn
b = 2 ** 2048
i = 0; a + b while (i += 1) <= 1_000_000
}
Diffstat (limited to 'ext/openssl/ossl_bn.c')
-rw-r--r-- | ext/openssl/ossl_bn.c | 101 |
1 files changed, 55 insertions, 46 deletions
diff --git a/ext/openssl/ossl_bn.c b/ext/openssl/ossl_bn.c index c5eb362c..19a868c3 100644 --- a/ext/openssl/ossl_bn.c +++ b/ext/openssl/ossl_bn.c @@ -76,24 +76,65 @@ ossl_bn_new(const BIGNUM *bn) } static BIGNUM * +integer_to_bnptr(VALUE obj, BIGNUM *orig) +{ + BIGNUM *bn; + + if (FIXNUM_P(obj)) { + long i; + unsigned char bin[sizeof(long)]; + long n = FIX2LONG(obj); + unsigned long un = labs(n); + + for (i = sizeof(long) - 1; 0 <= i; i--) { + bin[i] = un & 0xff; + un >>= 8; + } + + bn = BN_bin2bn(bin, sizeof(bin), orig); + if (!bn) + ossl_raise(eBNError, "BN_bin2bn"); + if (n < 0) + BN_set_negative(bn, 1); + } + else { /* assuming Bignum */ + size_t len = rb_absint_size(obj, NULL); + unsigned char *bin; + VALUE buf; + int sign; + + if (INT_MAX < len) { + rb_raise(eBNError, "bignum too long"); + } + bin = (unsigned char*)ALLOCV_N(unsigned char, buf, len); + sign = rb_integer_pack(obj, bin, len, 1, 0, INTEGER_PACK_BIG_ENDIAN); + + bn = BN_bin2bn(bin, (int)len, orig); + ALLOCV_END(buf); + if (!bn) + ossl_raise(eBNError, "BN_bin2bn"); + if (sign < 0) + BN_set_negative(bn, 1); + } + + return bn; +} + +static BIGNUM * try_convert_to_bnptr(VALUE obj) { BIGNUM *bn = NULL; VALUE newobj; - if (RTEST(rb_obj_is_kind_of(obj, cBN))) { + if (rb_obj_is_kind_of(obj, cBN)) { GetBN(obj, bn); - } else switch (TYPE(obj)) { - case T_FIXNUM: - case T_BIGNUM: - obj = rb_String(obj); - newobj = NewBN(cBN); /* GC bug */ - if (!BN_dec2bn(&bn, StringValueCStr(obj))) { - ossl_raise(eBNError, NULL); - } - SetBN(newobj, bn); /* Handle potencial mem leaks */ - break; } + else if (RB_INTEGER_TYPE_P(obj)) { + newobj = NewBN(cBN); /* Handle potencial mem leaks */ + bn = integer_to_bnptr(obj, NULL); + SetBN(newobj, bn); + } + return bn; } @@ -153,45 +194,13 @@ ossl_bn_initialize(int argc, VALUE *argv, VALUE self) base = NUM2INT(bs); } - if (RB_TYPE_P(str, T_FIXNUM)) { - long i; - unsigned char bin[sizeof(long)]; - long n = FIX2LONG(str); - unsigned long un = labs(n); - - for (i = sizeof(long) - 1; 0 <= i; i--) { - bin[i] = un&0xff; - un >>= 8; - } - + if (RB_INTEGER_TYPE_P(str)) { GetBN(self, bn); - if (!BN_bin2bn(bin, sizeof(bin), bn)) { - ossl_raise(eBNError, NULL); - } - if (n < 0) BN_set_negative(bn, 1); - return self; - } - else if (RB_TYPE_P(str, T_BIGNUM)) { - size_t len = rb_absint_size(str, NULL); - unsigned char *bin; - VALUE buf; - int sign; + integer_to_bnptr(str, bn); - if (INT_MAX < len) { - rb_raise(eBNError, "bignum too long"); - } - bin = (unsigned char*)ALLOCV_N(unsigned char, buf, len); - sign = rb_integer_pack(str, bin, len, 1, 0, INTEGER_PACK_BIG_ENDIAN); - - GetBN(self, bn); - if (!BN_bin2bn(bin, (int)len, bn)) { - ALLOCV_END(buf); - ossl_raise(eBNError, NULL); - } - ALLOCV_END(buf); - if (sign < 0) BN_set_negative(bn, 1); return self; } + if (RTEST(rb_obj_is_kind_of(str, cBN))) { BIGNUM *other; |