{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "5eff0353",
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as pyplot\n",
    "import numpy as np\n",
    "from scipy.stats import pearsonr\n",
    "import random\n",
    "from operator import xor\n",
    "import time\n",
    "\n",
    "# Fast implementation of the Hamming weight for 64 bit values\n",
    "# See book: A Hacker's delight\n",
    "def popcount(x):\n",
    "    x -= (x >> 1) & 0x5555555555555555\n",
    "    x = (x & 0x3333333333333333) + ((x >> 2) & 0x3333333333333333)\n",
    "    x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f\n",
    "    return ((x * 0x0101010101010101) & 0xffffffffffffffff ) >> 56"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "41b66e0d",
   "metadata": {},
   "outputs": [],
   "source": [
    "key = 0xe3cda8f459e1f0cf\n",
    "plaintext = 0x624aa9b7b28eee6d"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "bc4530c1",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0xe34d84ecf40020e6\n"
     ]
    }
   ],
   "source": [
    "\n",
    "class Speck(object):\n",
    "    valid_setups = {32: {64: 22},\n",
    "                    48: {72: 22, 96: 23},\n",
    "                    64: {96: 26, 128: 27},\n",
    "                    96: {96: 28, 144: 29},\n",
    "                    128: {128: 32, 192: 33, 256: 34}}\n",
    "    \n",
    "    \n",
    "    def __init__(self, key, key_size=64, block_size=32):\n",
    "        \n",
    "        try:\n",
    "            self.possible_setups = self.valid_setups[block_size]\n",
    "            self.block_size = block_size\n",
    "            self.word_size = self.block_size >> 1\n",
    "            \n",
    "        except KeyError:\n",
    "            print(\"Invalid block size!\")\n",
    "            print(\"Please use one of the following block size: \", [x for x in self.valid_setups.keys()])\n",
    "            raise\n",
    "             \n",
    "        try:\n",
    "            self.rounds = self.possible_setups[key_size]\n",
    "            self.key_size = key_size\n",
    "        except KeyError:\n",
    "            print(\"Invalid key size for selected block size!\")\n",
    "            print(\"Please use one of the following key sizes: \", [x for x in self.possible_setups.keys()])\n",
    "            raise\n",
    "        \n",
    "        # Bit Maske für Shifts und Addition\n",
    "        self.mod_mask = (2 ** self.word_size) - 1\n",
    "        \n",
    "        # Bis Maske für modulare Subtraktion\n",
    "        self.mod_mask_sub = (2 ** self.word_size)\n",
    "              \n",
    "        # Setup Circular Shift Parameters - they depend on block size (if block size == 32 --> 2 & 7, else 3 & 8)\n",
    "        if self.block_size == 32:\n",
    "            self.beta_shift = 2\n",
    "            self.alpha_shift = 7\n",
    "        else:\n",
    "            self.beta_shift = 3\n",
    "            self.alpha_shift = 8\n",
    "\n",
    "        # Parse the given key and truncate it to the key length\n",
    "        try:\n",
    "            self.key = key & ((2 ** self.key_size) - 1)\n",
    "        except (ValueError, TypeError):\n",
    "            print('Invalid Key Value!')\n",
    "            print('Please Provide Key as int')\n",
    "            raise\n",
    "\n",
    "        # Pre-compile key schedule\n",
    " \n",
    "        self.key_schedule = [self.key & self.mod_mask]\n",
    "        l_schedule = [(self.key >> (x * self.word_size)) & self.mod_mask for x in\n",
    "                      range(1, self.key_size // self.word_size)]\n",
    "        \n",
    "        for x in range(self.rounds - 1):\n",
    "            new_l_k = self.encrypt_round(l_schedule[x], self.key_schedule[x], x)\n",
    "            l_schedule.append(new_l_k[0])\n",
    "            self.key_schedule.append(new_l_k[1])\n",
    "        \n",
    "    def encrypt_round(self, x, y, k):\n",
    "        \"\"\"Complete One Round of Feistel Operation\"\"\"\n",
    "        \n",
    "        rs_x = ((x << (self.word_size - self.alpha_shift)) + (x >> self.alpha_shift)) & self.mod_mask\n",
    "\n",
    "        add_sxy = (rs_x + y) & self.mod_mask\n",
    "\n",
    "        new_x = k ^ add_sxy\n",
    "        \n",
    "        \n",
    "        ls_y = ((y >> (self.word_size - self.beta_shift)) + (y << self.beta_shift)) & self.mod_mask\n",
    "\n",
    "        new_y = new_x ^ ls_y\n",
    "\n",
    "        return new_x, new_y\n",
    "    \n",
    "    def encrypt(self, plaintext):\n",
    "        try:\n",
    "            b = (plaintext >> self.word_size) & self.mod_mask\n",
    "            a = plaintext & self.mod_mask\n",
    "        except TypeError:\n",
    "            print('Invalid plaintext!')\n",
    "            print('Please provide plaintext as int')\n",
    "            raise\n",
    "\n",
    "        b, a = self.encrypt_function(b, a)\n",
    "            \n",
    "        ciphertext = (b << self.word_size) + a\n",
    "\n",
    "        return ciphertext\n",
    "    \n",
    "    def encrypt_function(self, upper_word, lower_word):    \n",
    "        \n",
    "        x = upper_word\n",
    "        y = lower_word \n",
    "\n",
    "        # Run Encryption Steps For Appropriate Number of Rounds\n",
    "        for k in self.key_schedule:\n",
    "            \n",
    "            rs_x = ((x << (self.word_size - self.alpha_shift)) + (x >> self.alpha_shift)) & self.mod_mask\n",
    "\n",
    "            add_sxy = (rs_x + y) & self.mod_mask\n",
    "\n",
    "            x = k ^ add_sxy\n",
    "\n",
    "            ls_y = ((y >> (self.word_size - self.beta_shift)) + (y << self.beta_shift)) & self.mod_mask\n",
    "\n",
    "            y = x ^ ls_y\n",
    "            \n",
    "        return x,y   \n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    cipher = Speck(0x55, 128, 64)\n",
    "    g = cipher.encrypt(plaintext)\n",
    "    print(hex(g))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "6dd8b3dc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "16414961984268792015\n"
     ]
    }
   ],
   "source": [
    "print(key)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "a6802abf",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Help on module random:\n",
      "\n",
      "NAME\n",
      "    random - Random variable generators.\n",
      "\n",
      "MODULE REFERENCE\n",
      "    https://docs.python.org/3.7/library/random\n",
      "    \n",
      "    The following documentation is automatically generated from the Python\n",
      "    source files.  It may be incomplete, incorrect or include features that\n",
      "    are considered implementation detail and may vary between Python\n",
      "    implementations.  When in doubt, consult the module reference at the\n",
      "    location listed above.\n",
      "\n",
      "DESCRIPTION\n",
      "        integers\n",
      "        --------\n",
      "               uniform within range\n",
      "    \n",
      "        sequences\n",
      "        ---------\n",
      "               pick random element\n",
      "               pick random sample\n",
      "               pick weighted random sample\n",
      "               generate random permutation\n",
      "    \n",
      "        distributions on the real line:\n",
      "        ------------------------------\n",
      "               uniform\n",
      "               triangular\n",
      "               normal (Gaussian)\n",
      "               lognormal\n",
      "               negative exponential\n",
      "               gamma\n",
      "               beta\n",
      "               pareto\n",
      "               Weibull\n",
      "    \n",
      "        distributions on the circle (angles 0 to 2pi)\n",
      "        ---------------------------------------------\n",
      "               circular uniform\n",
      "               von Mises\n",
      "    \n",
      "    General notes on the underlying Mersenne Twister core generator:\n",
      "    \n",
      "    * The period is 2**19937-1.\n",
      "    * It is one of the most extensively tested generators in existence.\n",
      "    * The random() method is implemented in C, executes in a single Python step,\n",
      "      and is, therefore, threadsafe.\n",
      "\n",
      "CLASSES\n",
      "    _random.Random(builtins.object)\n",
      "        Random\n",
      "            SystemRandom\n",
      "    \n",
      "    class Random(_random.Random)\n",
      "     |  Random(x=None)\n",
      "     |  \n",
      "     |  Random number generator base class used by bound module functions.\n",
      "     |  \n",
      "     |  Used to instantiate instances of Random to get generators that don't\n",
      "     |  share state.\n",
      "     |  \n",
      "     |  Class Random can also be subclassed if you want to use a different basic\n",
      "     |  generator of your own devising: in that case, override the following\n",
      "     |  methods:  random(), seed(), getstate(), and setstate().\n",
      "     |  Optionally, implement a getrandbits() method so that randrange()\n",
      "     |  can cover arbitrarily large ranges.\n",
      "     |  \n",
      "     |  Method resolution order:\n",
      "     |      Random\n",
      "     |      _random.Random\n",
      "     |      builtins.object\n",
      "     |  \n",
      "     |  Methods defined here:\n",
      "     |  \n",
      "     |  __getstate__(self)\n",
      "     |      # Issue 17489: Since __reduce__ was defined to fix #759889 this is no\n",
      "     |      # longer called; we leave it here because it has been here since random was\n",
      "     |      # rewritten back in 2001 and why risk breaking something.\n",
      "     |  \n",
      "     |  __init__(self, x=None)\n",
      "     |      Initialize an instance.\n",
      "     |      \n",
      "     |      Optional argument x controls seeding, as for Random.seed().\n",
      "     |  \n",
      "     |  __reduce__(self)\n",
      "     |      Helper for pickle.\n",
      "     |  \n",
      "     |  __setstate__(self, state)\n",
      "     |  \n",
      "     |  betavariate(self, alpha, beta)\n",
      "     |      Beta distribution.\n",
      "     |      \n",
      "     |      Conditions on the parameters are alpha > 0 and beta > 0.\n",
      "     |      Returned values range between 0 and 1.\n",
      "     |  \n",
      "     |  choice(self, seq)\n",
      "     |      Choose a random element from a non-empty sequence.\n",
      "     |  \n",
      "     |  choices(self, population, weights=None, *, cum_weights=None, k=1)\n",
      "     |      Return a k sized list of population elements chosen with replacement.\n",
      "     |      \n",
      "     |      If the relative weights or cumulative weights are not specified,\n",
      "     |      the selections are made with equal probability.\n",
      "     |  \n",
      "     |  expovariate(self, lambd)\n",
      "     |      Exponential distribution.\n",
      "     |      \n",
      "     |      lambd is 1.0 divided by the desired mean.  It should be\n",
      "     |      nonzero.  (The parameter would be called \"lambda\", but that is\n",
      "     |      a reserved word in Python.)  Returned values range from 0 to\n",
      "     |      positive infinity if lambd is positive, and from negative\n",
      "     |      infinity to 0 if lambd is negative.\n",
      "     |  \n",
      "     |  gammavariate(self, alpha, beta)\n",
      "     |      Gamma distribution.  Not the gamma function!\n",
      "     |      \n",
      "     |      Conditions on the parameters are alpha > 0 and beta > 0.\n",
      "     |      \n",
      "     |      The probability distribution function is:\n",
      "     |      \n",
      "     |                  x ** (alpha - 1) * math.exp(-x / beta)\n",
      "     |        pdf(x) =  --------------------------------------\n",
      "     |                    math.gamma(alpha) * beta ** alpha\n",
      "     |  \n",
      "     |  gauss(self, mu, sigma)\n",
      "     |      Gaussian distribution.\n",
      "     |      \n",
      "     |      mu is the mean, and sigma is the standard deviation.  This is\n",
      "     |      slightly faster than the normalvariate() function.\n",
      "     |      \n",
      "     |      Not thread-safe without a lock around calls.\n",
      "     |  \n",
      "     |  getstate(self)\n",
      "     |      Return internal state; can be passed to setstate() later.\n",
      "     |  \n",
      "     |  lognormvariate(self, mu, sigma)\n",
      "     |      Log normal distribution.\n",
      "     |      \n",
      "     |      If you take the natural logarithm of this distribution, you'll get a\n",
      "     |      normal distribution with mean mu and standard deviation sigma.\n",
      "     |      mu can have any value, and sigma must be greater than zero.\n",
      "     |  \n",
      "     |  normalvariate(self, mu, sigma)\n",
      "     |      Normal distribution.\n",
      "     |      \n",
      "     |      mu is the mean, and sigma is the standard deviation.\n",
      "     |  \n",
      "     |  paretovariate(self, alpha)\n",
      "     |      Pareto distribution.  alpha is the shape parameter.\n",
      "     |  \n",
      "     |  randint(self, a, b)\n",
      "     |      Return random integer in range [a, b], including both end points.\n",
      "     |  \n",
      "     |  randrange(self, start, stop=None, step=1, _int=<class 'int'>)\n",
      "     |      Choose a random item from range(start, stop[, step]).\n",
      "     |      \n",
      "     |      This fixes the problem with randint() which includes the\n",
      "     |      endpoint; in Python this is usually not what you want.\n",
      "     |  \n",
      "     |  sample(self, population, k)\n",
      "     |      Chooses k unique random elements from a population sequence or set.\n",
      "     |      \n",
      "     |      Returns a new list containing elements from the population while\n",
      "     |      leaving the original population unchanged.  The resulting list is\n",
      "     |      in selection order so that all sub-slices will also be valid random\n",
      "     |      samples.  This allows raffle winners (the sample) to be partitioned\n",
      "     |      into grand prize and second place winners (the subslices).\n",
      "     |      \n",
      "     |      Members of the population need not be hashable or unique.  If the\n",
      "     |      population contains repeats, then each occurrence is a possible\n",
      "     |      selection in the sample.\n",
      "     |      \n",
      "     |      To choose a sample in a range of integers, use range as an argument.\n",
      "     |      This is especially fast and space efficient for sampling from a\n",
      "     |      large population:   sample(range(10000000), 60)\n",
      "     |  \n",
      "     |  seed(self, a=None, version=2)\n",
      "     |      Initialize internal state from hashable object.\n",
      "     |      \n",
      "     |      None or no argument seeds from current time or from an operating\n",
      "     |      system specific randomness source if available.\n",
      "     |      \n",
      "     |      If *a* is an int, all bits are used.\n",
      "     |      \n",
      "     |      For version 2 (the default), all of the bits are used if *a* is a str,\n",
      "     |      bytes, or bytearray.  For version 1 (provided for reproducing random\n",
      "     |      sequences from older versions of Python), the algorithm for str and\n",
      "     |      bytes generates a narrower range of seeds.\n",
      "     |  \n",
      "     |  setstate(self, state)\n",
      "     |      Restore internal state from object returned by getstate().\n",
      "     |  \n",
      "     |  shuffle(self, x, random=None)\n",
      "     |      Shuffle list x in place, and return None.\n",
      "     |      \n",
      "     |      Optional argument random is a 0-argument function returning a\n",
      "     |      random float in [0.0, 1.0); if it is the default None, the\n",
      "     |      standard random.random will be used.\n",
      "     |  \n",
      "     |  triangular(self, low=0.0, high=1.0, mode=None)\n",
      "     |      Triangular distribution.\n",
      "     |      \n",
      "     |      Continuous distribution bounded by given lower and upper limits,\n",
      "     |      and having a given mode value in-between.\n",
      "     |      \n",
      "     |      http://en.wikipedia.org/wiki/Triangular_distribution\n",
      "     |  \n",
      "     |  uniform(self, a, b)\n",
      "     |      Get a random number in the range [a, b) or [a, b] depending on rounding.\n",
      "     |  \n",
      "     |  vonmisesvariate(self, mu, kappa)\n",
      "     |      Circular data distribution.\n",
      "     |      \n",
      "     |      mu is the mean angle, expressed in radians between 0 and 2*pi, and\n",
      "     |      kappa is the concentration parameter, which must be greater than or\n",
      "     |      equal to zero.  If kappa is equal to zero, this distribution reduces\n",
      "     |      to a uniform random angle over the range 0 to 2*pi.\n",
      "     |  \n",
      "     |  weibullvariate(self, alpha, beta)\n",
      "     |      Weibull distribution.\n",
      "     |      \n",
      "     |      alpha is the scale parameter and beta is the shape parameter.\n",
      "     |  \n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data descriptors defined here:\n",
      "     |  \n",
      "     |  __dict__\n",
      "     |      dictionary for instance variables (if defined)\n",
      "     |  \n",
      "     |  __weakref__\n",
      "     |      list of weak references to the object (if defined)\n",
      "     |  \n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data and other attributes defined here:\n",
      "     |  \n",
      "     |  VERSION = 3\n",
      "     |  \n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Methods inherited from _random.Random:\n",
      "     |  \n",
      "     |  __getattribute__(self, name, /)\n",
      "     |      Return getattr(self, name).\n",
      "     |  \n",
      "     |  getrandbits(...)\n",
      "     |      getrandbits(k) -> x.  Generates an int with k random bits.\n",
      "     |  \n",
      "     |  random(...)\n",
      "     |      random() -> x in the interval [0, 1).\n",
      "     |  \n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Static methods inherited from _random.Random:\n",
      "     |  \n",
      "     |  __new__(*args, **kwargs) from builtins.type\n",
      "     |      Create and return a new object.  See help(type) for accurate signature.\n",
      "    \n",
      "    class SystemRandom(Random)\n",
      "     |  SystemRandom(x=None)\n",
      "     |  \n",
      "     |  Alternate random number generator using sources provided\n",
      "     |  by the operating system (such as /dev/urandom on Unix or\n",
      "     |  CryptGenRandom on Windows).\n",
      "     |  \n",
      "     |   Not available on all systems (see os.urandom() for details).\n",
      "     |  \n",
      "     |  Method resolution order:\n",
      "     |      SystemRandom\n",
      "     |      Random\n",
      "     |      _random.Random\n",
      "     |      builtins.object\n",
      "     |  \n",
      "     |  Methods defined here:\n",
      "     |  \n",
      "     |  getrandbits(self, k)\n",
      "     |      getrandbits(k) -> x.  Generates an int with k random bits.\n",
      "     |  \n",
      "     |  getstate = _notimplemented(self, *args, **kwds)\n",
      "     |  \n",
      "     |  random(self)\n",
      "     |      Get the next random number in the range [0.0, 1.0).\n",
      "     |  \n",
      "     |  seed(self, *args, **kwds)\n",
      "     |      Stub method.  Not used for a system random number generator.\n",
      "     |  \n",
      "     |  setstate = _notimplemented(self, *args, **kwds)\n",
      "     |  \n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Methods inherited from Random:\n",
      "     |  \n",
      "     |  __getstate__(self)\n",
      "     |      # Issue 17489: Since __reduce__ was defined to fix #759889 this is no\n",
      "     |      # longer called; we leave it here because it has been here since random was\n",
      "     |      # rewritten back in 2001 and why risk breaking something.\n",
      "     |  \n",
      "     |  __init__(self, x=None)\n",
      "     |      Initialize an instance.\n",
      "     |      \n",
      "     |      Optional argument x controls seeding, as for Random.seed().\n",
      "     |  \n",
      "     |  __reduce__(self)\n",
      "     |      Helper for pickle.\n",
      "     |  \n",
      "     |  __setstate__(self, state)\n",
      "     |  \n",
      "     |  betavariate(self, alpha, beta)\n",
      "     |      Beta distribution.\n",
      "     |      \n",
      "     |      Conditions on the parameters are alpha > 0 and beta > 0.\n",
      "     |      Returned values range between 0 and 1.\n",
      "     |  \n",
      "     |  choice(self, seq)\n",
      "     |      Choose a random element from a non-empty sequence.\n",
      "     |  \n",
      "     |  choices(self, population, weights=None, *, cum_weights=None, k=1)\n",
      "     |      Return a k sized list of population elements chosen with replacement.\n",
      "     |      \n",
      "     |      If the relative weights or cumulative weights are not specified,\n",
      "     |      the selections are made with equal probability.\n",
      "     |  \n",
      "     |  expovariate(self, lambd)\n",
      "     |      Exponential distribution.\n",
      "     |      \n",
      "     |      lambd is 1.0 divided by the desired mean.  It should be\n",
      "     |      nonzero.  (The parameter would be called \"lambda\", but that is\n",
      "     |      a reserved word in Python.)  Returned values range from 0 to\n",
      "     |      positive infinity if lambd is positive, and from negative\n",
      "     |      infinity to 0 if lambd is negative.\n",
      "     |  \n",
      "     |  gammavariate(self, alpha, beta)\n",
      "     |      Gamma distribution.  Not the gamma function!\n",
      "     |      \n",
      "     |      Conditions on the parameters are alpha > 0 and beta > 0.\n",
      "     |      \n",
      "     |      The probability distribution function is:\n",
      "     |      \n",
      "     |                  x ** (alpha - 1) * math.exp(-x / beta)\n",
      "     |        pdf(x) =  --------------------------------------\n",
      "     |                    math.gamma(alpha) * beta ** alpha\n",
      "     |  \n",
      "     |  gauss(self, mu, sigma)\n",
      "     |      Gaussian distribution.\n",
      "     |      \n",
      "     |      mu is the mean, and sigma is the standard deviation.  This is\n",
      "     |      slightly faster than the normalvariate() function.\n",
      "     |      \n",
      "     |      Not thread-safe without a lock around calls.\n",
      "     |  \n",
      "     |  lognormvariate(self, mu, sigma)\n",
      "     |      Log normal distribution.\n",
      "     |      \n",
      "     |      If you take the natural logarithm of this distribution, you'll get a\n",
      "     |      normal distribution with mean mu and standard deviation sigma.\n",
      "     |      mu can have any value, and sigma must be greater than zero.\n",
      "     |  \n",
      "     |  normalvariate(self, mu, sigma)\n",
      "     |      Normal distribution.\n",
      "     |      \n",
      "     |      mu is the mean, and sigma is the standard deviation.\n",
      "     |  \n",
      "     |  paretovariate(self, alpha)\n",
      "     |      Pareto distribution.  alpha is the shape parameter.\n",
      "     |  \n",
      "     |  randint(self, a, b)\n",
      "     |      Return random integer in range [a, b], including both end points.\n",
      "     |  \n",
      "     |  randrange(self, start, stop=None, step=1, _int=<class 'int'>)\n",
      "     |      Choose a random item from range(start, stop[, step]).\n",
      "     |      \n",
      "     |      This fixes the problem with randint() which includes the\n",
      "     |      endpoint; in Python this is usually not what you want.\n",
      "     |  \n",
      "     |  sample(self, population, k)\n",
      "     |      Chooses k unique random elements from a population sequence or set.\n",
      "     |      \n",
      "     |      Returns a new list containing elements from the population while\n",
      "     |      leaving the original population unchanged.  The resulting list is\n",
      "     |      in selection order so that all sub-slices will also be valid random\n",
      "     |      samples.  This allows raffle winners (the sample) to be partitioned\n",
      "     |      into grand prize and second place winners (the subslices).\n",
      "     |      \n",
      "     |      Members of the population need not be hashable or unique.  If the\n",
      "     |      population contains repeats, then each occurrence is a possible\n",
      "     |      selection in the sample.\n",
      "     |      \n",
      "     |      To choose a sample in a range of integers, use range as an argument.\n",
      "     |      This is especially fast and space efficient for sampling from a\n",
      "     |      large population:   sample(range(10000000), 60)\n",
      "     |  \n",
      "     |  shuffle(self, x, random=None)\n",
      "     |      Shuffle list x in place, and return None.\n",
      "     |      \n",
      "     |      Optional argument random is a 0-argument function returning a\n",
      "     |      random float in [0.0, 1.0); if it is the default None, the\n",
      "     |      standard random.random will be used.\n",
      "     |  \n",
      "     |  triangular(self, low=0.0, high=1.0, mode=None)\n",
      "     |      Triangular distribution.\n",
      "     |      \n",
      "     |      Continuous distribution bounded by given lower and upper limits,\n",
      "     |      and having a given mode value in-between.\n",
      "     |      \n",
      "     |      http://en.wikipedia.org/wiki/Triangular_distribution\n",
      "     |  \n",
      "     |  uniform(self, a, b)\n",
      "     |      Get a random number in the range [a, b) or [a, b] depending on rounding.\n",
      "     |  \n",
      "     |  vonmisesvariate(self, mu, kappa)\n",
      "     |      Circular data distribution.\n",
      "     |      \n",
      "     |      mu is the mean angle, expressed in radians between 0 and 2*pi, and\n",
      "     |      kappa is the concentration parameter, which must be greater than or\n",
      "     |      equal to zero.  If kappa is equal to zero, this distribution reduces\n",
      "     |      to a uniform random angle over the range 0 to 2*pi.\n",
      "     |  \n",
      "     |  weibullvariate(self, alpha, beta)\n",
      "     |      Weibull distribution.\n",
      "     |      \n",
      "     |      alpha is the scale parameter and beta is the shape parameter.\n",
      "     |  \n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data descriptors inherited from Random:\n",
      "     |  \n",
      "     |  __dict__\n",
      "     |      dictionary for instance variables (if defined)\n",
      "     |  \n",
      "     |  __weakref__\n",
      "     |      list of weak references to the object (if defined)\n",
      "     |  \n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Data and other attributes inherited from Random:\n",
      "     |  \n",
      "     |  VERSION = 3\n",
      "     |  \n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Methods inherited from _random.Random:\n",
      "     |  \n",
      "     |  __getattribute__(self, name, /)\n",
      "     |      Return getattr(self, name).\n",
      "     |  \n",
      "     |  ----------------------------------------------------------------------\n",
      "     |  Static methods inherited from _random.Random:\n",
      "     |  \n",
      "     |  __new__(*args, **kwargs) from builtins.type\n",
      "     |      Create and return a new object.  See help(type) for accurate signature.\n",
      "\n",
      "FUNCTIONS\n",
      "    betavariate(alpha, beta) method of Random instance\n",
      "        Beta distribution.\n",
      "        \n",
      "        Conditions on the parameters are alpha > 0 and beta > 0.\n",
      "        Returned values range between 0 and 1.\n",
      "    \n",
      "    choice(seq) method of Random instance\n",
      "        Choose a random element from a non-empty sequence.\n",
      "    \n",
      "    choices(population, weights=None, *, cum_weights=None, k=1) method of Random instance\n",
      "        Return a k sized list of population elements chosen with replacement.\n",
      "        \n",
      "        If the relative weights or cumulative weights are not specified,\n",
      "        the selections are made with equal probability.\n",
      "    \n",
      "    expovariate(lambd) method of Random instance\n",
      "        Exponential distribution.\n",
      "        \n",
      "        lambd is 1.0 divided by the desired mean.  It should be\n",
      "        nonzero.  (The parameter would be called \"lambda\", but that is\n",
      "        a reserved word in Python.)  Returned values range from 0 to\n",
      "        positive infinity if lambd is positive, and from negative\n",
      "        infinity to 0 if lambd is negative.\n",
      "    \n",
      "    gammavariate(alpha, beta) method of Random instance\n",
      "        Gamma distribution.  Not the gamma function!\n",
      "        \n",
      "        Conditions on the parameters are alpha > 0 and beta > 0.\n",
      "        \n",
      "        The probability distribution function is:\n",
      "        \n",
      "                    x ** (alpha - 1) * math.exp(-x / beta)\n",
      "          pdf(x) =  --------------------------------------\n",
      "                      math.gamma(alpha) * beta ** alpha\n",
      "    \n",
      "    gauss(mu, sigma) method of Random instance\n",
      "        Gaussian distribution.\n",
      "        \n",
      "        mu is the mean, and sigma is the standard deviation.  This is\n",
      "        slightly faster than the normalvariate() function.\n",
      "        \n",
      "        Not thread-safe without a lock around calls.\n",
      "    \n",
      "    getrandbits(...) method of Random instance\n",
      "        getrandbits(k) -> x.  Generates an int with k random bits.\n",
      "    \n",
      "    getstate() method of Random instance\n",
      "        Return internal state; can be passed to setstate() later.\n",
      "    \n",
      "    lognormvariate(mu, sigma) method of Random instance\n",
      "        Log normal distribution.\n",
      "        \n",
      "        If you take the natural logarithm of this distribution, you'll get a\n",
      "        normal distribution with mean mu and standard deviation sigma.\n",
      "        mu can have any value, and sigma must be greater than zero.\n",
      "    \n",
      "    normalvariate(mu, sigma) method of Random instance\n",
      "        Normal distribution.\n",
      "        \n",
      "        mu is the mean, and sigma is the standard deviation.\n",
      "    \n",
      "    paretovariate(alpha) method of Random instance\n",
      "        Pareto distribution.  alpha is the shape parameter.\n",
      "    \n",
      "    randint(a, b) method of Random instance\n",
      "        Return random integer in range [a, b], including both end points.\n",
      "    \n",
      "    random(...) method of Random instance\n",
      "        random() -> x in the interval [0, 1).\n",
      "    \n",
      "    randrange(start, stop=None, step=1, _int=<class 'int'>) method of Random instance\n",
      "        Choose a random item from range(start, stop[, step]).\n",
      "        \n",
      "        This fixes the problem with randint() which includes the\n",
      "        endpoint; in Python this is usually not what you want.\n",
      "    \n",
      "    sample(population, k) method of Random instance\n",
      "        Chooses k unique random elements from a population sequence or set.\n",
      "        \n",
      "        Returns a new list containing elements from the population while\n",
      "        leaving the original population unchanged.  The resulting list is\n",
      "        in selection order so that all sub-slices will also be valid random\n",
      "        samples.  This allows raffle winners (the sample) to be partitioned\n",
      "        into grand prize and second place winners (the subslices).\n",
      "        \n",
      "        Members of the population need not be hashable or unique.  If the\n",
      "        population contains repeats, then each occurrence is a possible\n",
      "        selection in the sample.\n",
      "        \n",
      "        To choose a sample in a range of integers, use range as an argument.\n",
      "        This is especially fast and space efficient for sampling from a\n",
      "        large population:   sample(range(10000000), 60)\n",
      "    \n",
      "    seed(a=None, version=2) method of Random instance\n",
      "        Initialize internal state from hashable object.\n",
      "        \n",
      "        None or no argument seeds from current time or from an operating\n",
      "        system specific randomness source if available.\n",
      "        \n",
      "        If *a* is an int, all bits are used.\n",
      "        \n",
      "        For version 2 (the default), all of the bits are used if *a* is a str,\n",
      "        bytes, or bytearray.  For version 1 (provided for reproducing random\n",
      "        sequences from older versions of Python), the algorithm for str and\n",
      "        bytes generates a narrower range of seeds.\n",
      "    \n",
      "    setstate(state) method of Random instance\n",
      "        Restore internal state from object returned by getstate().\n",
      "    \n",
      "    shuffle(x, random=None) method of Random instance\n",
      "        Shuffle list x in place, and return None.\n",
      "        \n",
      "        Optional argument random is a 0-argument function returning a\n",
      "        random float in [0.0, 1.0); if it is the default None, the\n",
      "        standard random.random will be used.\n",
      "    \n",
      "    triangular(low=0.0, high=1.0, mode=None) method of Random instance\n",
      "        Triangular distribution.\n",
      "        \n",
      "        Continuous distribution bounded by given lower and upper limits,\n",
      "        and having a given mode value in-between.\n",
      "        \n",
      "        http://en.wikipedia.org/wiki/Triangular_distribution\n",
      "    \n",
      "    uniform(a, b) method of Random instance\n",
      "        Get a random number in the range [a, b) or [a, b] depending on rounding.\n",
      "    \n",
      "    vonmisesvariate(mu, kappa) method of Random instance\n",
      "        Circular data distribution.\n",
      "        \n",
      "        mu is the mean angle, expressed in radians between 0 and 2*pi, and\n",
      "        kappa is the concentration parameter, which must be greater than or\n",
      "        equal to zero.  If kappa is equal to zero, this distribution reduces\n",
      "        to a uniform random angle over the range 0 to 2*pi.\n",
      "    \n",
      "    weibullvariate(alpha, beta) method of Random instance\n",
      "        Weibull distribution.\n",
      "        \n",
      "        alpha is the scale parameter and beta is the shape parameter.\n",
      "\n",
      "DATA\n",
      "    __all__ = ['Random', 'seed', 'random', 'uniform', 'randint', 'choice',...\n",
      "\n",
      "FILE\n",
      "    d:\\progra~1\\chipwh~1\\cw\\home\\portable\\wpy64-3771\\python-3.7.7.amd64\\lib\\random.py\n",
      "\n",
      "\n"
     ]
    }
   ],
   "source": [
    "import random \n",
    "help(random)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "6a19fe2d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0x624aa9b7b28eee6d\n"
     ]
    }
   ],
   "source": [
    "print(hex(random.getrandbits(64)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "id": "f1eb832b",
   "metadata": {},
   "outputs": [],
   "source": [
    "def simplified_speck (plaintext):\n",
    "    k = 0x1110\n",
    "    x = plaintext\n",
    "    y = 0x110\n",
    "    alpha_shift = 8\n",
    "    beta_shift = 3\n",
    "    word_size = 64 >> 1\n",
    "    mod_mask = (2 ** word_size) - 1\n",
    "    \n",
    "    rs_x = ((x << (word_size - alpha_shift)) + (x >> alpha_shift)) & mod_mask\n",
    "    \n",
    "    add_sxy = (rs_x + y) & mod_mask\n",
    "\n",
    "    new_x = k ^ x\n",
    "\n",
    "    #ls_y = ((y >> (word_size - beta_shift)) + (y << beta_shift)) & mod_mask\n",
    "\n",
    "    #new_y = new_x ^ ls_y\n",
    "\n",
    "    return add_sxy\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e1d6bd34",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "5f5c6552",
   "metadata": {},
   "outputs": [],
   "source": [
    "block_size = 64\n",
    "word_size = block_size >> 1\n",
    "key_size = 128\n",
    "key = 0x00000000000055\n",
    "alpha_shift = 8\n",
    "beta_shift = 3\n",
    "mod_mask = (2 ** word_size) - 1\n",
    "\n",
    "def simpleSpeck(plaintext):    \n",
    "    right_key = key & mod_mask \n",
    "    right_plain = plaintext & mod_mask\n",
    "    left_plain = (plaintext >> word_size) & mod_mask\n",
    "\n",
    "    rs_x = ((left_plain << (word_size - alpha_shift)) + (right_plain >> alpha_shift)) & mod_mask\n",
    "\n",
    "    add_sxy = (rs_x + right_plain) & mod_mask\n",
    "\n",
    "    x = right_key ^ add_sxy\n",
    "    \n",
    "    return x\n",
    "\n",
    "def hw_model(key_guess, plaintext):    \n",
    "    right_key = key_guess & mod_mask \n",
    "    right_plain = plaintext & mod_mask\n",
    "    left_plain = (plaintext >> word_size) & mod_mask\n",
    "    \n",
    "    rs_x = ((left_plain << (word_size - alpha_shift)) + (right_plain >> alpha_shift)) & mod_mask\n",
    "    \n",
    "    add_sxy = (rs_x + right_plain) & mod_mask\n",
    "\n",
    "    x = key_guess ^ add_sxy\n",
    "    \n",
    "    return x\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "9a8cb228",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "2595877967"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "simpleSpeck(plaintext)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "bf388a52",
   "metadata": {},
   "outputs": [],
   "source": [
    "plaintext = 0x5248718298"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "05c9b121",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Correct 8-bit key is: 0xff\n"
     ]
    }
   ],
   "source": [
    "num_traces = 1000\n",
    "\n",
    "traces = np.empty(num_traces)\n",
    "hw_traces = np.empty((256, num_traces))\n",
    "\n",
    "for i in range(0,num_traces):\n",
    "    traces[i] = popcount(simpleSpeck(i%256)) \n",
    "    for key in range(0, 256):\n",
    "        hw_traces[key][i] = hw_model(key, i%256)\n",
    "        \n",
    "corr = np.empty(256)\n",
    "        \n",
    "#compute pearson correlation for each key\n",
    "for key in range(0, 256):\n",
    "    corr[key],p = pearsonr(hw_traces[key], traces)\n",
    "\n",
    "pyplot.plot(corr)\n",
    "pyplot.show()\n",
    "\n",
    "print(\"Correct 8-bit key is: \" + hex(np.argmax(corr)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9ccaad64",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}