CSE-107 / hw6 / hw6.py
hw6.py
Raw
import math
import json
import sys, os, itertools

from playcrypt.primitives import *
from playcrypt.tools import *
from playcrypt.new_tools import *

from playcrypt.games.game_pke_lr import GamePKELR
from playcrypt.simulator.pke_lr_sim import PKELRSim

def ADD(a,b):
    return a+b
def MULT(a,b):
    return a*b
def INT_DIV(a,N):
    return (a//N, a%N)
def MOD(a,N):
    return a%N
def EXT_GCD(a,N):
    return egcd(a,N)
def MOD_INV(a,N):
    res = modinv(a,N)
    if res == None:
        raise ValueError("Inverse does not exist.")
    return res
def MOD_EXP(a,n,N):
    return exp(a,n,N)

"""
Note: As usual, our convention is that the running time of an adversary does not
include the time taken by game procedures to compute responses to adversary's queries.
"""

"""
!!! LIST YOUR COLLABORATORS HERE !!!
"""

""" Problem 1 [20 points] Let K_rsa be a RSA generator with security parameter k >=1024.
Consider the key-generation algorithm K and encryption algorithm E defined below:
"""


def K():
    (N, p, q, e, d) = K_rsa(k)
    pk = (N, e)
    sk = (N, d)
    return (pk, sk)


def E(pk, M):
    """
    :param pk: The public key pk = (N, e) used to encrypt the message
    :param M: The plaintext to be encrypted, must be in Z_N^*
    :return: return the encryption of plaintext M
    """    
    (N, e) = pk                     # Parse pk as (N, e)
    if not in_Z_N_star(M, N):       # If M is not in Z_N^* 
        raise ValueError("Message not in appropriate domain.")     
    U = random_Z_N_star(N)          # Sample a random element U of Z_N^*
    V = MOD_EXP(U, e, N)            # V <- U^e mod N
    W = MOD(U * M, N)               # W <= (U * M) mod N
    return (V, W)

"""
(1.1) [8 points] Specify in pseudocode an O(k^3)-time decryption algorithm D such that
AE = (K, E, D) is an asymmetric encryption scheme satisfying the correct
decryption requirement, for messages that are in Z_N^* when the public key is (N, e).
"""

def D(sk, C):
    """
    This is the decryption algorithm that the problem is asking for.
    :param sk: The secret key used to decrypt the message
    :param C: The ciphertext to be decrypted
    :return: return the decryption on the ciphertext C
    """
    (N, d) = sk
    (V, W) = C

    U = MOD_EXP(V, d, N)
    M = MOD(MOD_INV(U,N)*W, N)

    return M 

    pass

"""
(1.2) [12 points] Specify in pseudocode an O(k^3)-time adversary A1 making one query to
its LR oracle and achieving Adv_{AE}^{ind-cpa}(A1) = 1. Messages in the LR query
must be in Z_N^* when the public key is (N, e).
"""

def A1(lr, pk):
    """
    You must fill in this method. This is the adversary that the problem is
    asking for.
    :param lr: This is the oracle supplied by the game.
    :param pk: This is the public key returned by the game's procedure Initialize.
    :return: return 1 to indicate your adversary believes it is the right world
    and return 0 to indicate that your adversary believes it is in the left world.
    """
    # lr(1,1) # You'll want to replace this with your own LR query
    (N, e) = pk
    M0 = 1
    M1 = 2

    C = lr(M0, M1)
    (V, W) = C 

    if(MOD_EXP(W, e, N) == V):
        return 0
    return 1


"""
==============================================================================================
The following lines are used to test your code, and should not be modified.
==============================================================================================
"""
def main():
    def pk_gen():
            (pk,sk) = K()
            return pk

    worked = True
    global k
    k = 64
    for loop in range(100):
        (pk,sk) = K()
        (N,e) = pk
        M = random_Z_N_star(N)
        C = E(pk, M)
        if M != D(sk, C):
            print ("Your decryption function is incorrect.")
            worked = False
            break
    if worked:
        print ("Your decryption function appears correct.")

    gm = GamePKELR(1, 1, E, pk_gen)
    s = PKELRSim(gm, A1)
    print ("The advantage of your adversary A1 is approx. " + str(s.compute_advantage()))

if __name__ == "__main__":
    main()