Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Negative power in modular pow()

How can we use pow with a negative exponent in a modular context?

pow(x, y, [z]) If z is present, x and y must be of integer types, and y must be non-negative.

>>> pow(11444, -357)
0.0
>>> pow(11444, -357) % 48731
0.0
>>> pow(11444, -357, 48731)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: pow() 2nd argument cannot be negative when 3rd argument specified

In my use case, I want to encrypt a message using a Schnorr scheme:

y = (g ** -w) mod p

but pow won't accept a negative number as the second argument here. As an example, from

g = 11444
p = 48731
w = 357

y should be 7355.

like image 388
kAldown Avatar asked Dec 06 '15 15:12

kAldown


2 Answers

pow won't automatically compute a modular multiplicative inverse for you. Instead, we can compute it ourselves (say via the extended Eulidean algorithm) and then rewrite pow(a,-b,c) as pow((a^-1) mod c, b, c). Stealing the MMI code from this question:

def egcd(a, b):
    if a == 0:
        return (b, 0, 1)
    else:
        g, y, x = egcd(b % a, a)
        return (g, x - (b // a) * y, y)

def modinv(a, m):
    g, x, y = egcd(a, m)
    if g != 1:
        raise Exception('modular inverse does not exist')
    else:
        return x % m

we get

>>> g = 11444
>>> p = 48731
>>> w = 357
>>> modinv(g, p)
29420
>>> pow(modinv(g, p), w, p)
7355
like image 86
DSM Avatar answered Oct 29 '22 13:10

DSM


As of python 3.8 you can do this. 3.9 adds keyword arguments. Check out there code here. There usage is

>>> pow(38, -1, mod=97)
23
>>> 23 * 38 % 97 == 1
True
like image 22
A_Arnold Avatar answered Oct 29 '22 11:10

A_Arnold