aboutsummaryrefslogtreecommitdiffstats
path: root/ext/openssl/ossl_bn.c
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2016-08-22 19:29:20 +0900
committerKazuki Yamaguchi <k@rhe.jp>2016-08-22 19:29:20 +0900
commit106d42c93d24ba401778a235841f722fe51d65f8 (patch)
treea83835076099c40a37dc4c2ad9f5693cf57b7fbf /ext/openssl/ossl_bn.c
parentbe23fc960337e475af70419c5036cce215fd9ac9 (diff)
downloadruby-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.c101
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;