RSA algorithm implementation in Python 3BouncyCastle RSA ImplementationImplementation of quicksort algorithmC# AES + RSA Encryption ImplementationSecure RSA encryption with PyCryptoBaconian Cipher Python ImplementationECDH implementation in pythonECDH implementation in python (part 2)ECDH implementation in python (part 3)C++ RSA ImplementationRSA c implementation

What is the significance behind "40 days" that often appears in the Bible?

Tikz: place node leftmost of two nodes of different widths

Optimising a list searching algorithm

My friend is being a hypocrite

Can you move over difficult terrain with only 5 feet of movement?

If "dar" means "to give", what does "daros" mean?

What is the plural TO / OF something

Variable completely messes up echoed string

Print last inputted byte

How could an airship be repaired midflight?

Writing in a Christian voice

Do native speakers use "ultima" and "proxima" frequently in spoken English?

Unfrosted light bulb

Have the tides ever turned twice on any open problem?

Am I eligible for the Eurail Youth pass? I am 27.5 years old

Is this an example of a Neapolitan chord?

Calculate the frequency of characters in a string

How can an organ that provides biological immortality be unable to regenerate?

Describing a chess game in a novel

I seem to dance, I am not a dancer. Who am I?

Can other pieces capture a threatening piece and prevent a checkmate?

Fewest number of steps to reach 200 using special calculator

Brake pads destroying wheels

A Ri-diddley-iley Riddle



RSA algorithm implementation in Python 3


BouncyCastle RSA ImplementationImplementation of quicksort algorithmC# AES + RSA Encryption ImplementationSecure RSA encryption with PyCryptoBaconian Cipher Python ImplementationECDH implementation in pythonECDH implementation in python (part 2)ECDH implementation in python (part 3)C++ RSA ImplementationRSA c implementation













14












$begingroup$


First, a reminder of the RSA algorithm and what my program implements:



  • Take two distinct, large primes p and q

    • Ideally these have a similar byte-length


  • Multiply p and q and store the result in n

  • Find the totient for n using the formula $$varphi(n)=(p-1)(q-1)$$

  • Take an e coprime that is greater, than 1 and less than n

  • Find d using the formula $$dcdot eequiv1modvarphi(n)$$

At this point, the pair (e, n) is the public key and the private key (d, n) is the private key.



Conception:



  • Implement the RSA algorithm

  • Ask the user for necessary data (primes, coprime greater than 1 and less than n, string)

  • Encrypt and decrypt the given string by the user using the RSA algorithm

What do you think about my Python 3 implementation of the RSA algorithm? What's the performance of this program?



try:
input = raw_input
except NameError:
pass
try:
chr = unichr
except NameError:
pass
p=int(input('Enter prime p: '))
q=int(input('Enter prime q: '))
print("Choosen primes:np=" + str(p) + ", q=" + str(q) + "n")
n=p*q
print("n = p * q = " + str(n) + "n")
phi=(p-1)*(q-1)
print("Euler's function (totient) [phi(n)]: " + str(phi) + "n")
def gcd(a, b):
while b != 0:
c = a % b
a = b
b = c
return a
def modinv(a, m):
for x in range(1, m):
if (a * x) % m == 1:
return x
return None
def coprimes(a):
l = []
for x in range(2, a):
if gcd(a, x) == 1 and modinv(x,phi) != None:
l.append(x)
for x in l:
if x == modinv(x,phi):
l.remove(x)
return l
print("Choose an e from a below coprimes array:n")
print(str(coprimes(phi)) + "n")
e=int(input())
d=modinv(e,phi)
print("nYour public key is a pair of numbers (e=" + str(e) + ", n=" + str(n) + ").n")
print("Your private key is a pair of numbers (d=" + str(d) + ", n=" + str(n) + ").n")
def encrypt_block(m):
c = modinv(m**e, n)
if c == None: print('No modular multiplicative inverse for block ' + str(m) + '.')
return c
def decrypt_block(c):
m = modinv(c**d, n)
if m == None: print('No modular multiplicative inverse for block ' + str(c) + '.')
return m
def encrypt_string(s):
return ''.join([chr(encrypt_block(ord(x))) for x in list(s)])
def decrypt_string(s):
return ''.join([chr(decrypt_block(ord(x))) for x in list(s)])
s = input("Enter a message to encrypt: ")
print("nPlain message: " + s + "n")
enc = encrypt_string(s)
print("Encrypted message: " + enc + "n")
dec = decrypt_string(enc)
print("Decrypted message: " + dec + "n")









share|improve this question











$endgroup$











  • $begingroup$
    Instead of using "some text" + str(value_I_Want) + "more text"... you should try to use the .format function. E.G. "This is my string and is my value".format(value) It makes code more managable and readable.
    $endgroup$
    – Erich
    Aug 30 '17 at 0:07










  • $begingroup$
    Also, you should notice that your encrypt and decrypt funciton are identical, maybe you can cut out some extraneous code with an extra parameter? ;) I will also add that I generally like to keep my function definitions and code execution separated for readability. Keep all of your inputs and prints below function definitions (preferrably inside __name__ == "__main__" conditional).
    $endgroup$
    – Erich
    Aug 30 '17 at 0:10
















14












$begingroup$


First, a reminder of the RSA algorithm and what my program implements:



  • Take two distinct, large primes p and q

    • Ideally these have a similar byte-length


  • Multiply p and q and store the result in n

  • Find the totient for n using the formula $$varphi(n)=(p-1)(q-1)$$

  • Take an e coprime that is greater, than 1 and less than n

  • Find d using the formula $$dcdot eequiv1modvarphi(n)$$

At this point, the pair (e, n) is the public key and the private key (d, n) is the private key.



Conception:



  • Implement the RSA algorithm

  • Ask the user for necessary data (primes, coprime greater than 1 and less than n, string)

  • Encrypt and decrypt the given string by the user using the RSA algorithm

What do you think about my Python 3 implementation of the RSA algorithm? What's the performance of this program?



try:
input = raw_input
except NameError:
pass
try:
chr = unichr
except NameError:
pass
p=int(input('Enter prime p: '))
q=int(input('Enter prime q: '))
print("Choosen primes:np=" + str(p) + ", q=" + str(q) + "n")
n=p*q
print("n = p * q = " + str(n) + "n")
phi=(p-1)*(q-1)
print("Euler's function (totient) [phi(n)]: " + str(phi) + "n")
def gcd(a, b):
while b != 0:
c = a % b
a = b
b = c
return a
def modinv(a, m):
for x in range(1, m):
if (a * x) % m == 1:
return x
return None
def coprimes(a):
l = []
for x in range(2, a):
if gcd(a, x) == 1 and modinv(x,phi) != None:
l.append(x)
for x in l:
if x == modinv(x,phi):
l.remove(x)
return l
print("Choose an e from a below coprimes array:n")
print(str(coprimes(phi)) + "n")
e=int(input())
d=modinv(e,phi)
print("nYour public key is a pair of numbers (e=" + str(e) + ", n=" + str(n) + ").n")
print("Your private key is a pair of numbers (d=" + str(d) + ", n=" + str(n) + ").n")
def encrypt_block(m):
c = modinv(m**e, n)
if c == None: print('No modular multiplicative inverse for block ' + str(m) + '.')
return c
def decrypt_block(c):
m = modinv(c**d, n)
if m == None: print('No modular multiplicative inverse for block ' + str(c) + '.')
return m
def encrypt_string(s):
return ''.join([chr(encrypt_block(ord(x))) for x in list(s)])
def decrypt_string(s):
return ''.join([chr(decrypt_block(ord(x))) for x in list(s)])
s = input("Enter a message to encrypt: ")
print("nPlain message: " + s + "n")
enc = encrypt_string(s)
print("Encrypted message: " + enc + "n")
dec = decrypt_string(enc)
print("Decrypted message: " + dec + "n")









share|improve this question











$endgroup$











  • $begingroup$
    Instead of using "some text" + str(value_I_Want) + "more text"... you should try to use the .format function. E.G. "This is my string and is my value".format(value) It makes code more managable and readable.
    $endgroup$
    – Erich
    Aug 30 '17 at 0:07










  • $begingroup$
    Also, you should notice that your encrypt and decrypt funciton are identical, maybe you can cut out some extraneous code with an extra parameter? ;) I will also add that I generally like to keep my function definitions and code execution separated for readability. Keep all of your inputs and prints below function definitions (preferrably inside __name__ == "__main__" conditional).
    $endgroup$
    – Erich
    Aug 30 '17 at 0:10














14












14








14


3



$begingroup$


First, a reminder of the RSA algorithm and what my program implements:



  • Take two distinct, large primes p and q

    • Ideally these have a similar byte-length


  • Multiply p and q and store the result in n

  • Find the totient for n using the formula $$varphi(n)=(p-1)(q-1)$$

  • Take an e coprime that is greater, than 1 and less than n

  • Find d using the formula $$dcdot eequiv1modvarphi(n)$$

At this point, the pair (e, n) is the public key and the private key (d, n) is the private key.



Conception:



  • Implement the RSA algorithm

  • Ask the user for necessary data (primes, coprime greater than 1 and less than n, string)

  • Encrypt and decrypt the given string by the user using the RSA algorithm

What do you think about my Python 3 implementation of the RSA algorithm? What's the performance of this program?



try:
input = raw_input
except NameError:
pass
try:
chr = unichr
except NameError:
pass
p=int(input('Enter prime p: '))
q=int(input('Enter prime q: '))
print("Choosen primes:np=" + str(p) + ", q=" + str(q) + "n")
n=p*q
print("n = p * q = " + str(n) + "n")
phi=(p-1)*(q-1)
print("Euler's function (totient) [phi(n)]: " + str(phi) + "n")
def gcd(a, b):
while b != 0:
c = a % b
a = b
b = c
return a
def modinv(a, m):
for x in range(1, m):
if (a * x) % m == 1:
return x
return None
def coprimes(a):
l = []
for x in range(2, a):
if gcd(a, x) == 1 and modinv(x,phi) != None:
l.append(x)
for x in l:
if x == modinv(x,phi):
l.remove(x)
return l
print("Choose an e from a below coprimes array:n")
print(str(coprimes(phi)) + "n")
e=int(input())
d=modinv(e,phi)
print("nYour public key is a pair of numbers (e=" + str(e) + ", n=" + str(n) + ").n")
print("Your private key is a pair of numbers (d=" + str(d) + ", n=" + str(n) + ").n")
def encrypt_block(m):
c = modinv(m**e, n)
if c == None: print('No modular multiplicative inverse for block ' + str(m) + '.')
return c
def decrypt_block(c):
m = modinv(c**d, n)
if m == None: print('No modular multiplicative inverse for block ' + str(c) + '.')
return m
def encrypt_string(s):
return ''.join([chr(encrypt_block(ord(x))) for x in list(s)])
def decrypt_string(s):
return ''.join([chr(decrypt_block(ord(x))) for x in list(s)])
s = input("Enter a message to encrypt: ")
print("nPlain message: " + s + "n")
enc = encrypt_string(s)
print("Encrypted message: " + enc + "n")
dec = decrypt_string(enc)
print("Decrypted message: " + dec + "n")









share|improve this question











$endgroup$




First, a reminder of the RSA algorithm and what my program implements:



  • Take two distinct, large primes p and q

    • Ideally these have a similar byte-length


  • Multiply p and q and store the result in n

  • Find the totient for n using the formula $$varphi(n)=(p-1)(q-1)$$

  • Take an e coprime that is greater, than 1 and less than n

  • Find d using the formula $$dcdot eequiv1modvarphi(n)$$

At this point, the pair (e, n) is the public key and the private key (d, n) is the private key.



Conception:



  • Implement the RSA algorithm

  • Ask the user for necessary data (primes, coprime greater than 1 and less than n, string)

  • Encrypt and decrypt the given string by the user using the RSA algorithm

What do you think about my Python 3 implementation of the RSA algorithm? What's the performance of this program?



try:
input = raw_input
except NameError:
pass
try:
chr = unichr
except NameError:
pass
p=int(input('Enter prime p: '))
q=int(input('Enter prime q: '))
print("Choosen primes:np=" + str(p) + ", q=" + str(q) + "n")
n=p*q
print("n = p * q = " + str(n) + "n")
phi=(p-1)*(q-1)
print("Euler's function (totient) [phi(n)]: " + str(phi) + "n")
def gcd(a, b):
while b != 0:
c = a % b
a = b
b = c
return a
def modinv(a, m):
for x in range(1, m):
if (a * x) % m == 1:
return x
return None
def coprimes(a):
l = []
for x in range(2, a):
if gcd(a, x) == 1 and modinv(x,phi) != None:
l.append(x)
for x in l:
if x == modinv(x,phi):
l.remove(x)
return l
print("Choose an e from a below coprimes array:n")
print(str(coprimes(phi)) + "n")
e=int(input())
d=modinv(e,phi)
print("nYour public key is a pair of numbers (e=" + str(e) + ", n=" + str(n) + ").n")
print("Your private key is a pair of numbers (d=" + str(d) + ", n=" + str(n) + ").n")
def encrypt_block(m):
c = modinv(m**e, n)
if c == None: print('No modular multiplicative inverse for block ' + str(m) + '.')
return c
def decrypt_block(c):
m = modinv(c**d, n)
if m == None: print('No modular multiplicative inverse for block ' + str(c) + '.')
return m
def encrypt_string(s):
return ''.join([chr(encrypt_block(ord(x))) for x in list(s)])
def decrypt_string(s):
return ''.join([chr(decrypt_block(ord(x))) for x in list(s)])
s = input("Enter a message to encrypt: ")
print("nPlain message: " + s + "n")
enc = encrypt_string(s)
print("Encrypted message: " + enc + "n")
dec = decrypt_string(enc)
print("Decrypted message: " + dec + "n")






python algorithm python-3.x mathematics cryptography






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Oct 27 '18 at 13:47







java-devel

















asked Aug 29 '17 at 19:34









java-develjava-devel

5301420




5301420











  • $begingroup$
    Instead of using "some text" + str(value_I_Want) + "more text"... you should try to use the .format function. E.G. "This is my string and is my value".format(value) It makes code more managable and readable.
    $endgroup$
    – Erich
    Aug 30 '17 at 0:07










  • $begingroup$
    Also, you should notice that your encrypt and decrypt funciton are identical, maybe you can cut out some extraneous code with an extra parameter? ;) I will also add that I generally like to keep my function definitions and code execution separated for readability. Keep all of your inputs and prints below function definitions (preferrably inside __name__ == "__main__" conditional).
    $endgroup$
    – Erich
    Aug 30 '17 at 0:10

















  • $begingroup$
    Instead of using "some text" + str(value_I_Want) + "more text"... you should try to use the .format function. E.G. "This is my string and is my value".format(value) It makes code more managable and readable.
    $endgroup$
    – Erich
    Aug 30 '17 at 0:07










  • $begingroup$
    Also, you should notice that your encrypt and decrypt funciton are identical, maybe you can cut out some extraneous code with an extra parameter? ;) I will also add that I generally like to keep my function definitions and code execution separated for readability. Keep all of your inputs and prints below function definitions (preferrably inside __name__ == "__main__" conditional).
    $endgroup$
    – Erich
    Aug 30 '17 at 0:10
















$begingroup$
Instead of using "some text" + str(value_I_Want) + "more text"... you should try to use the .format function. E.G. "This is my string and is my value".format(value) It makes code more managable and readable.
$endgroup$
– Erich
Aug 30 '17 at 0:07




$begingroup$
Instead of using "some text" + str(value_I_Want) + "more text"... you should try to use the .format function. E.G. "This is my string and is my value".format(value) It makes code more managable and readable.
$endgroup$
– Erich
Aug 30 '17 at 0:07












$begingroup$
Also, you should notice that your encrypt and decrypt funciton are identical, maybe you can cut out some extraneous code with an extra parameter? ;) I will also add that I generally like to keep my function definitions and code execution separated for readability. Keep all of your inputs and prints below function definitions (preferrably inside __name__ == "__main__" conditional).
$endgroup$
– Erich
Aug 30 '17 at 0:10





$begingroup$
Also, you should notice that your encrypt and decrypt funciton are identical, maybe you can cut out some extraneous code with an extra parameter? ;) I will also add that I generally like to keep my function definitions and code execution separated for readability. Keep all of your inputs and prints below function definitions (preferrably inside __name__ == "__main__" conditional).
$endgroup$
– Erich
Aug 30 '17 at 0:10











3 Answers
3






active

oldest

votes


















8












$begingroup$

I think your Modular Inverse implementation is slow. We can apply this Extended GCD algorithm recursive implementation which shows quite a dramatic speed improvement (at least on my machine):



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


Here is a simple benchmark for some a and m which have a modular inverse of 16013:



In [24]: a = 108 ** 151

In [25]: m = 22499

In [26]: %timeit modinv_OP(a, m)
100 loops, best of 3: 11.2 ms per loop

In [27]: %timeit modinv_new(a, m)
100000 loops, best of 3: 5.62 µs per loop


I also wonder if adding an LRU cache via functools.lru_cache() would make an impact - probably not, but please experiment with that.




Some other improvements:




  • you can avoid converting s to a list in order to iterate character by character:



    ''.join(str(chr(encrypt_block(ord(x)))) for x in s)


    I've also switched to a "lazy" join when joined from a generator.



  • if on Python 3.6+, you can use f-strings for your print messages






share|improve this answer











$endgroup$




















    6












    $begingroup$

    You can use math.gcd:



    from math import gcd


    One must not compare variables with None using equality operator




    Comparisons to singletons like None should always be done with is or is not, never the equality operators.




    modinv for prime mod may be implemented like this:



    def prime_mod_inv(x, mod):
    return pow(x, mod - 2, mod)


    You can use print with multiple arguments.



    No:



    print("Choosen primes:np=" + str(p) + ", q=" + str(q) + "n")


    Yes:



    print("Choosen primes:")
    print("p =", p, ", q =", q)


    No:



    print("Euler's function (totient) [phi(n)]: " + str(phi) + "n")


    Yes:



    print("Euler's function (totient) [phi(n)]:", phi)


    No:



    print(str(coprimes(phi)) + "n")


    Yes:



    print(coprimes(phi), "n")


    You can replace this



    l = []
    for x in range(2, a):
    if gcd(a, x) == 1 and modinv(x,phi) != None:
    l.append(x)
    for x in l:
    if x == modinv(x,phi):
    l.remove(x)


    With list comprehension



    l = [x for x in range(2, a) 
    if gcd(a, x) == 1
    and modinv(x, phi) is not None
    and modinv(x, phi) != x]





    share|improve this answer











    $endgroup$








    • 1




      $begingroup$
      also, please don't name lists l it looks way too much like 1 in a lot of fonts.
      $endgroup$
      – Oscar Smith
      Jul 6 '18 at 14:42










    • $begingroup$
      Actually, it is better not to use variable at all. List comprehension allows to write coprimes() function with a single return statement :)
      $endgroup$
      – belkka
      Jul 6 '18 at 15:00



















    0












    $begingroup$

    Rather than using Euler's Totient formula to compute d, its recommended to use the Carmichael Lambda Function instead. The Carmichael Lambda(CML) divides the Totient. The CML provides the smallest possible secure private key.
    Luckily, if your primes are truly primes, one can EASILY compute the CML. It's the lcm of p-1 , q-1 . Then use the same Modular inverse(definitely use the extended GCD ) algorithm for the modular inverse, a beauty of an algorithm.






    share|improve this answer









    $endgroup$












      Your Answer





      StackExchange.ifUsing("editor", function ()
      return StackExchange.using("mathjaxEditing", function ()
      StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
      StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
      );
      );
      , "mathjax-editing");

      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "196"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: false,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: null,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













      draft saved

      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f174336%2frsa-algorithm-implementation-in-python-3%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      3 Answers
      3






      active

      oldest

      votes








      3 Answers
      3






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      8












      $begingroup$

      I think your Modular Inverse implementation is slow. We can apply this Extended GCD algorithm recursive implementation which shows quite a dramatic speed improvement (at least on my machine):



      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


      Here is a simple benchmark for some a and m which have a modular inverse of 16013:



      In [24]: a = 108 ** 151

      In [25]: m = 22499

      In [26]: %timeit modinv_OP(a, m)
      100 loops, best of 3: 11.2 ms per loop

      In [27]: %timeit modinv_new(a, m)
      100000 loops, best of 3: 5.62 µs per loop


      I also wonder if adding an LRU cache via functools.lru_cache() would make an impact - probably not, but please experiment with that.




      Some other improvements:




      • you can avoid converting s to a list in order to iterate character by character:



        ''.join(str(chr(encrypt_block(ord(x)))) for x in s)


        I've also switched to a "lazy" join when joined from a generator.



      • if on Python 3.6+, you can use f-strings for your print messages






      share|improve this answer











      $endgroup$

















        8












        $begingroup$

        I think your Modular Inverse implementation is slow. We can apply this Extended GCD algorithm recursive implementation which shows quite a dramatic speed improvement (at least on my machine):



        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


        Here is a simple benchmark for some a and m which have a modular inverse of 16013:



        In [24]: a = 108 ** 151

        In [25]: m = 22499

        In [26]: %timeit modinv_OP(a, m)
        100 loops, best of 3: 11.2 ms per loop

        In [27]: %timeit modinv_new(a, m)
        100000 loops, best of 3: 5.62 µs per loop


        I also wonder if adding an LRU cache via functools.lru_cache() would make an impact - probably not, but please experiment with that.




        Some other improvements:




        • you can avoid converting s to a list in order to iterate character by character:



          ''.join(str(chr(encrypt_block(ord(x)))) for x in s)


          I've also switched to a "lazy" join when joined from a generator.



        • if on Python 3.6+, you can use f-strings for your print messages






        share|improve this answer











        $endgroup$















          8












          8








          8





          $begingroup$

          I think your Modular Inverse implementation is slow. We can apply this Extended GCD algorithm recursive implementation which shows quite a dramatic speed improvement (at least on my machine):



          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


          Here is a simple benchmark for some a and m which have a modular inverse of 16013:



          In [24]: a = 108 ** 151

          In [25]: m = 22499

          In [26]: %timeit modinv_OP(a, m)
          100 loops, best of 3: 11.2 ms per loop

          In [27]: %timeit modinv_new(a, m)
          100000 loops, best of 3: 5.62 µs per loop


          I also wonder if adding an LRU cache via functools.lru_cache() would make an impact - probably not, but please experiment with that.




          Some other improvements:




          • you can avoid converting s to a list in order to iterate character by character:



            ''.join(str(chr(encrypt_block(ord(x)))) for x in s)


            I've also switched to a "lazy" join when joined from a generator.



          • if on Python 3.6+, you can use f-strings for your print messages






          share|improve this answer











          $endgroup$



          I think your Modular Inverse implementation is slow. We can apply this Extended GCD algorithm recursive implementation which shows quite a dramatic speed improvement (at least on my machine):



          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


          Here is a simple benchmark for some a and m which have a modular inverse of 16013:



          In [24]: a = 108 ** 151

          In [25]: m = 22499

          In [26]: %timeit modinv_OP(a, m)
          100 loops, best of 3: 11.2 ms per loop

          In [27]: %timeit modinv_new(a, m)
          100000 loops, best of 3: 5.62 µs per loop


          I also wonder if adding an LRU cache via functools.lru_cache() would make an impact - probably not, but please experiment with that.




          Some other improvements:




          • you can avoid converting s to a list in order to iterate character by character:



            ''.join(str(chr(encrypt_block(ord(x)))) for x in s)


            I've also switched to a "lazy" join when joined from a generator.



          • if on Python 3.6+, you can use f-strings for your print messages







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Aug 29 '17 at 20:21

























          answered Aug 29 '17 at 19:58









          alecxealecxe

          15.3k53680




          15.3k53680























              6












              $begingroup$

              You can use math.gcd:



              from math import gcd


              One must not compare variables with None using equality operator




              Comparisons to singletons like None should always be done with is or is not, never the equality operators.




              modinv for prime mod may be implemented like this:



              def prime_mod_inv(x, mod):
              return pow(x, mod - 2, mod)


              You can use print with multiple arguments.



              No:



              print("Choosen primes:np=" + str(p) + ", q=" + str(q) + "n")


              Yes:



              print("Choosen primes:")
              print("p =", p, ", q =", q)


              No:



              print("Euler's function (totient) [phi(n)]: " + str(phi) + "n")


              Yes:



              print("Euler's function (totient) [phi(n)]:", phi)


              No:



              print(str(coprimes(phi)) + "n")


              Yes:



              print(coprimes(phi), "n")


              You can replace this



              l = []
              for x in range(2, a):
              if gcd(a, x) == 1 and modinv(x,phi) != None:
              l.append(x)
              for x in l:
              if x == modinv(x,phi):
              l.remove(x)


              With list comprehension



              l = [x for x in range(2, a) 
              if gcd(a, x) == 1
              and modinv(x, phi) is not None
              and modinv(x, phi) != x]





              share|improve this answer











              $endgroup$








              • 1




                $begingroup$
                also, please don't name lists l it looks way too much like 1 in a lot of fonts.
                $endgroup$
                – Oscar Smith
                Jul 6 '18 at 14:42










              • $begingroup$
                Actually, it is better not to use variable at all. List comprehension allows to write coprimes() function with a single return statement :)
                $endgroup$
                – belkka
                Jul 6 '18 at 15:00
















              6












              $begingroup$

              You can use math.gcd:



              from math import gcd


              One must not compare variables with None using equality operator




              Comparisons to singletons like None should always be done with is or is not, never the equality operators.




              modinv for prime mod may be implemented like this:



              def prime_mod_inv(x, mod):
              return pow(x, mod - 2, mod)


              You can use print with multiple arguments.



              No:



              print("Choosen primes:np=" + str(p) + ", q=" + str(q) + "n")


              Yes:



              print("Choosen primes:")
              print("p =", p, ", q =", q)


              No:



              print("Euler's function (totient) [phi(n)]: " + str(phi) + "n")


              Yes:



              print("Euler's function (totient) [phi(n)]:", phi)


              No:



              print(str(coprimes(phi)) + "n")


              Yes:



              print(coprimes(phi), "n")


              You can replace this



              l = []
              for x in range(2, a):
              if gcd(a, x) == 1 and modinv(x,phi) != None:
              l.append(x)
              for x in l:
              if x == modinv(x,phi):
              l.remove(x)


              With list comprehension



              l = [x for x in range(2, a) 
              if gcd(a, x) == 1
              and modinv(x, phi) is not None
              and modinv(x, phi) != x]





              share|improve this answer











              $endgroup$








              • 1




                $begingroup$
                also, please don't name lists l it looks way too much like 1 in a lot of fonts.
                $endgroup$
                – Oscar Smith
                Jul 6 '18 at 14:42










              • $begingroup$
                Actually, it is better not to use variable at all. List comprehension allows to write coprimes() function with a single return statement :)
                $endgroup$
                – belkka
                Jul 6 '18 at 15:00














              6












              6








              6





              $begingroup$

              You can use math.gcd:



              from math import gcd


              One must not compare variables with None using equality operator




              Comparisons to singletons like None should always be done with is or is not, never the equality operators.




              modinv for prime mod may be implemented like this:



              def prime_mod_inv(x, mod):
              return pow(x, mod - 2, mod)


              You can use print with multiple arguments.



              No:



              print("Choosen primes:np=" + str(p) + ", q=" + str(q) + "n")


              Yes:



              print("Choosen primes:")
              print("p =", p, ", q =", q)


              No:



              print("Euler's function (totient) [phi(n)]: " + str(phi) + "n")


              Yes:



              print("Euler's function (totient) [phi(n)]:", phi)


              No:



              print(str(coprimes(phi)) + "n")


              Yes:



              print(coprimes(phi), "n")


              You can replace this



              l = []
              for x in range(2, a):
              if gcd(a, x) == 1 and modinv(x,phi) != None:
              l.append(x)
              for x in l:
              if x == modinv(x,phi):
              l.remove(x)


              With list comprehension



              l = [x for x in range(2, a) 
              if gcd(a, x) == 1
              and modinv(x, phi) is not None
              and modinv(x, phi) != x]





              share|improve this answer











              $endgroup$



              You can use math.gcd:



              from math import gcd


              One must not compare variables with None using equality operator




              Comparisons to singletons like None should always be done with is or is not, never the equality operators.




              modinv for prime mod may be implemented like this:



              def prime_mod_inv(x, mod):
              return pow(x, mod - 2, mod)


              You can use print with multiple arguments.



              No:



              print("Choosen primes:np=" + str(p) + ", q=" + str(q) + "n")


              Yes:



              print("Choosen primes:")
              print("p =", p, ", q =", q)


              No:



              print("Euler's function (totient) [phi(n)]: " + str(phi) + "n")


              Yes:



              print("Euler's function (totient) [phi(n)]:", phi)


              No:



              print(str(coprimes(phi)) + "n")


              Yes:



              print(coprimes(phi), "n")


              You can replace this



              l = []
              for x in range(2, a):
              if gcd(a, x) == 1 and modinv(x,phi) != None:
              l.append(x)
              for x in l:
              if x == modinv(x,phi):
              l.remove(x)


              With list comprehension



              l = [x for x in range(2, a) 
              if gcd(a, x) == 1
              and modinv(x, phi) is not None
              and modinv(x, phi) != x]






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Jul 6 '18 at 14:18

























              answered Jul 6 '18 at 14:04









              belkkabelkka

              13616




              13616







              • 1




                $begingroup$
                also, please don't name lists l it looks way too much like 1 in a lot of fonts.
                $endgroup$
                – Oscar Smith
                Jul 6 '18 at 14:42










              • $begingroup$
                Actually, it is better not to use variable at all. List comprehension allows to write coprimes() function with a single return statement :)
                $endgroup$
                – belkka
                Jul 6 '18 at 15:00













              • 1




                $begingroup$
                also, please don't name lists l it looks way too much like 1 in a lot of fonts.
                $endgroup$
                – Oscar Smith
                Jul 6 '18 at 14:42










              • $begingroup$
                Actually, it is better not to use variable at all. List comprehension allows to write coprimes() function with a single return statement :)
                $endgroup$
                – belkka
                Jul 6 '18 at 15:00








              1




              1




              $begingroup$
              also, please don't name lists l it looks way too much like 1 in a lot of fonts.
              $endgroup$
              – Oscar Smith
              Jul 6 '18 at 14:42




              $begingroup$
              also, please don't name lists l it looks way too much like 1 in a lot of fonts.
              $endgroup$
              – Oscar Smith
              Jul 6 '18 at 14:42












              $begingroup$
              Actually, it is better not to use variable at all. List comprehension allows to write coprimes() function with a single return statement :)
              $endgroup$
              – belkka
              Jul 6 '18 at 15:00





              $begingroup$
              Actually, it is better not to use variable at all. List comprehension allows to write coprimes() function with a single return statement :)
              $endgroup$
              – belkka
              Jul 6 '18 at 15:00












              0












              $begingroup$

              Rather than using Euler's Totient formula to compute d, its recommended to use the Carmichael Lambda Function instead. The Carmichael Lambda(CML) divides the Totient. The CML provides the smallest possible secure private key.
              Luckily, if your primes are truly primes, one can EASILY compute the CML. It's the lcm of p-1 , q-1 . Then use the same Modular inverse(definitely use the extended GCD ) algorithm for the modular inverse, a beauty of an algorithm.






              share|improve this answer









              $endgroup$

















                0












                $begingroup$

                Rather than using Euler's Totient formula to compute d, its recommended to use the Carmichael Lambda Function instead. The Carmichael Lambda(CML) divides the Totient. The CML provides the smallest possible secure private key.
                Luckily, if your primes are truly primes, one can EASILY compute the CML. It's the lcm of p-1 , q-1 . Then use the same Modular inverse(definitely use the extended GCD ) algorithm for the modular inverse, a beauty of an algorithm.






                share|improve this answer









                $endgroup$















                  0












                  0








                  0





                  $begingroup$

                  Rather than using Euler's Totient formula to compute d, its recommended to use the Carmichael Lambda Function instead. The Carmichael Lambda(CML) divides the Totient. The CML provides the smallest possible secure private key.
                  Luckily, if your primes are truly primes, one can EASILY compute the CML. It's the lcm of p-1 , q-1 . Then use the same Modular inverse(definitely use the extended GCD ) algorithm for the modular inverse, a beauty of an algorithm.






                  share|improve this answer









                  $endgroup$



                  Rather than using Euler's Totient formula to compute d, its recommended to use the Carmichael Lambda Function instead. The Carmichael Lambda(CML) divides the Totient. The CML provides the smallest possible secure private key.
                  Luckily, if your primes are truly primes, one can EASILY compute the CML. It's the lcm of p-1 , q-1 . Then use the same Modular inverse(definitely use the extended GCD ) algorithm for the modular inverse, a beauty of an algorithm.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered 15 mins ago









                  TheHoytTheHoyt

                  444




                  444



























                      draft saved

                      draft discarded
















































                      Thanks for contributing an answer to Code Review Stack Exchange!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      Use MathJax to format equations. MathJax reference.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f174336%2frsa-algorithm-implementation-in-python-3%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      कुँवर स्रोत दिक्चालन सूची"कुँवर""राणा कुँवरके वंशावली"

                      Why is a white electrical wire connected to 2 black wires?How to wire a light fixture with 3 white wires in box?How should I wire a ceiling fan when there's only three wires in the box?Two white, two black, two ground, and red wire in ceiling box connected to switchWhy is there a white wire connected to multiple black wires in my light box?How to wire a light with two white wires and one black wireReplace light switch connected to a power outlet with dimmer - two black wires to one black and redHow to wire a light with multiple black/white/green wires from the ceiling?Ceiling box has 2 black and white wires but fan/ light only has 1 of eachWhy neutral wire connected to load wire?Switch with 2 black, 2 white, 2 ground and 1 red wire connected to ceiling light and a receptacle?

                      चैत्य भूमि चित्र दीर्घा सन्दर्भ बाहरी कडियाँ दिक्चालन सूची"Chaitya Bhoomi""Chaitya Bhoomi: Statue of Equality in India""Dadar Chaitya Bhoomi: Statue of Equality in India""Ambedkar memorial: Centre okays transfer of Indu Mill land"चैत्यभमि