block_size = 64
word_size = block_size >> 1 # 32
key_size = 128
key = 0xe3cda8f459e1f0cf
alpha_shift = 8
beta_shift = 3
mod_mask = (2 ** word_size) - 1

def simpleSpeck(plaintext):
    right_key = key & mod_mask
    right_plain = plaintext & mod_mask
    left_plain = (plaintext >> word_size) & mod_mask

    # Run Encryption Steps For Appropriate Number of Rounds

    rs_x = ((left_plain << (word_size - alpha_shift)) + (right_plain >> alpha_shift)) & mod_mask

    add_sxy = (rs_x + right_plain) & mod_mask

    x = right_key ^ add_sxy

    return x

def hw_model(key_guess, plaintext):
    right_key = key_guess & mod_mask
    right_plain = plaintext & mod_mask
    left_plain = (plaintext >> word_size) & mod_mask

    # Run Encryption Steps For Appropriate Number of Rounds

    rs_x = ((left_plain << (word_size - alpha_shift)) + (right_plain >> alpha_shift)) & mod_mask

    add_sxy = (rs_x + right_plain) & mod_mask

    x = right_key ^ add_sxy

    return x



def encrypt_function(self, upper_word, lower_word):    
    
    x = upper_word
            y = lower_word 

    # Run Encryption Steps For Appropriate Number of Rounds
            for k in self.key_schedule:
                rs_x = ((x << (self.word_size - self.alpha_shift)) + (x >> self.alpha_shift)) & self.mod_mask
        
        add_sxy = (rs_x + y) & self.mod_mask
    
        x = k ^ add_sxy
    
        ls_y = ((y >> (self.word_size - self.beta_shift)) + (y << self.beta_shift)) & self.mod_mask
    
        y = x ^ ls_y
                
    return x,y