0

In the gmpy2 extension module for Python there's a multiple-precision integer type called mpz. It contains a powmod(x, y, m) function and I've been missing that one in Ruby. I was recently made aware that Ruby actually has a powmod. It's hidden in the OpenSSL module.

require 'openssl'
result = a_big_int.to_bn.mod_exp(exponent, modulo)

Another function, that's also in gmpy2, I've been missing is divm(...).

divm(a, b, m) returns x such that b * x == a modulo m. Raises a ZeroDivisionError exception if no such value x exists.

Do you know if the OpenSSL module has yet another surprise up its sleeve or of any gem that sports such a function? It would be very helpful if it's a fast one.

Jonas Elfström
  • 30,834
  • 6
  • 70
  • 106

2 Answers2

1

A quick dive into the code in GMP for divm(a, b, m) shows that it essentially does this

b-1 * a % m

Where b-1 is the modular multiplicative inverse. There is some fallback logic for when the invert call fails (it is unclear to me when this could occur), but for most purposes you could do this in Ruby like so (using the same variable names as the divm method signature):

b.to_bn.mod_inverse(m).mod_mul(a, m).to_i

Paul Kehrer
  • 13,466
  • 4
  • 40
  • 57
0

I'm not sure how accessible these are in Ruby or Python.


It contains a powmod(x, y, m)...

int BN_mod_exp(BIGNUM *r, BIGNUM *a, const BIGNUM *p,
    const BIGNUM *m, BN_CTX *ctx);

divm(a, b, m)...

int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *a,
    const BIGNUM *d, BN_CTX *ctx);

You can see the full docs at OpenSSL's bn(3).

jww
  • 97,681
  • 90
  • 411
  • 885
  • Unfortunately Ruby OpenSSL does not seem to expose that function. It also seems to be pretty undocumented so I'm not sure how to map it to gmpy2.divm anyway. – Jonas Elfström Feb 25 '14 at 08:17