Source code for qrisp.algorithms.shor.crypto_tools

"""
\********************************************************************************
* Copyright (c) 2023 the Qrisp authors
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License, v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is
* available at https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
"""

import numpy as np

from qrisp.alg_primitives.arithmetic.modular_arithmetic import modinv
from qrisp.algorithms.shor import shors_alg

[docs] def rsa_decrypt(ciphertext, e, N, backend = None): """ Decrypts an integer using factorization powered by Shor's algorithm. Parameters ---------- ciphertext : int The integer to be decrypted. e : int Public key 1. N : int Public key 2. backend : :ref:`BackendClient`, optional The backend to execute the quantum algorithm. By default the Qrisp simulator will be used. Returns ------- plaintext : int The decrypted integer. We decrypt the integer 2 using $N = 33$ and $e = 7$ >>> from qrisp.shor import rsa_decrypt >>> rsa_decrypt(2, 7, 33) 8 """ if not backend is None: mes_kwargs = {"backend": backend} else: mes_kwargs = {} p = shors_alg(N, mes_kwargs = mes_kwargs) # Calculate the other factor q = N // p # Calculate the totient phi = (p - 1) * (q - 1) # Calculate the private key d = modinv(e, phi) # Decrypt the ciphertext plaintext = pow(ciphertext, d, N) return plaintext
[docs] def rsa_encrypt(p, q, e, message_int): """ Encrypts an integer using the private keys $p$, $q$ and a public key $e$. Parameters ---------- p : int Private key 1. q : int Private key 1. e : int Public key 2. message_int : int The integer to encrypt. Returns ------- ciphertext : int The encrypted integer. Examples -------- We encrypt the integer 8 using $p = 11$, $q = 3$ and $e = 7$ >>> from qrisp.shor import rsa_encrypt >>> rsa_encrypt(p = 11, q = 3, e = 7, message_int = 8) 2 """ # Calculate the modulus N = p * q # Convert the message to an integer # message_int = int.from_bytes(message.encode(), 'big') # Encrypt the message ciphertext = pow(message_int, e, N) return ciphertext
[docs] def rsa_encrypt_string(p, q, e, message): """ Encrypts an arbitrary Python string using RSA. Parameters ---------- p : int Private key 1. q : int Private key 2. e : int Public key 1. message : string The message to encrypt. Returns ------- ciphertext : string A bitstring containing the encrypted message. Examples -------- We encrypt a string containing an important message >>> from qrisp.shor import rsa_encrypt_string >>> rsa_encrypt_string(p = 5, q = 13, e = 7, message = "Qrisp is awesome!") '01010000000101001010001100100110010010000101000010001101000010100011010101110011101000100100011100000100000100110111101000011000111110111111' """ message_bitstring = " ".join(format(x, 'b').zfill(7) for x in bytearray(message, 'ascii')).replace(" ", "") chunksize = (p*q).bit_length() - 1 chunks = [message_bitstring[i*chunksize:(i+1)*chunksize][::-1].zfill(chunksize)[::-1] for i in range(int(np.ceil(len(message_bitstring)/chunksize)))] ciphertext = "" for i in range(len(chunks)): encrypted_int = rsa_encrypt(p, q, e, int(chunks[i], 2)) ciphertext += bin(encrypted_int)[2:].zfill(chunksize+1) return ciphertext
[docs] def rsa_decrypt_string(e, N, ciphertext, backend = None): """ Decrypts a bitstring into a human readable string. Parameters ---------- e : int Public key 1. N : int Public key 2. ciphertext : string A bitstring, containing the encrypted message. backend : :ref:`BackendClient`, optional The backend to execute the quantum algorithm. By default the Qrisp simulator will be used. Returns ------- plaintext : string The decrypted string. Examples -------- We decrypt the message we encrypted in the example of :meth:`rsa_encrypt_string <qrisp.shor.rsa_encrypt_string>`. >>> ciphertext = '01010000000101001010001100100110010010000101000010001101000010100011010101110011101000100100011100000100000100110111101000011000111110111111' >>> from qrisp.shor import rsa_decrypt_string >>> rsa_decrypt_string(e = 7, N = 65, ciphertext = ciphertext) 'Qrisp is awesome!' """ if not backend is None: mes_kwargs = {"backend": backend} else: mes_kwargs = {} p = shors_alg(N, mes_kwargs = mes_kwargs) # Calculate the other factor q = N // p # Calculate the totient phi = (p - 1) * (q - 1) # Calculate the private key d = modinv(e, phi) chunksize = (N).bit_length() chunks = [ciphertext[i*chunksize:(i+1)*chunksize] for i in range(int(np.ceil(len(ciphertext)/chunksize)))] plaintext_bitstring = "" for i in range(len(chunks)): cipher_int = int(chunks[i], 2) plaintext_int = pow(cipher_int, d, N) plaintext_bitstring += bin(plaintext_int)[2:].zfill(chunksize-1) return bitstring_to_string(plaintext_bitstring)
def bitstring_to_string(bitstring): chars = [] for i in range(0, len(bitstring)//7*7, 7): byte = (bitstring[i:i+7] + " ") chars.append(chr(int(byte, 2))) return ''.join(chars)