diff --git a/cryptography/des_key_generation.ipynb b/cryptography/des_key_generation.ipynb deleted file mode 100644 index 86f1a4725..000000000 --- a/cryptography/des_key_generation.ipynb +++ /dev/null @@ -1,158 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "1057a613", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "\n" - ], - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "%%HTML\n", - "" - ] - }, - { - "cell_type": "markdown", - "id": "040e1454", - "metadata": {}, - "source": [ - "## Key generation for DES for 16 rounds" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "7bd02a30", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['1B02EFFC7072',\n", - " '79AED9DBC9E5',\n", - " '55FC8A42CF99',\n", - " '72ADD6DB351D',\n", - " '7CEC07EB53A8',\n", - " '63A53E507B2F',\n", - " 'EC84B7F618BC',\n", - " 'F78A3AC13BFB',\n", - " 'E0DBEBEDE781',\n", - " 'B1F347BA464F',\n", - " '215FD3DED386',\n", - " '7571F59467E9',\n", - " '97C5D1FABA41',\n", - " '5F43B7F2E73A',\n", - " 'BF918D3D3F0A',\n", - " 'CB3D8B0E17F5']" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import random\n", - "def r64():\n", - " r64 = ''\n", - " for i in range(8):\n", - " r = str(bin(random.randint(0,2**8)))[2:]\n", - " if(len(r)<8):\n", - " r = '0'*(8-len(r)) + r\n", - " r64 +=r\n", - " return r64\n", - "def hex2bin(hexa):\n", - " binstr = bin(int(hexa,16))[2:]\n", - " binstr = binstr.zfill(len(hexa)*4)\n", - " return binstr\n", - "\n", - "def bin2hex(binary):\n", - " binary = binary.zfill(len(binary) +( 4-len(binary)%4)%4)\n", - " hexa = hex(int(binary,2))[2:].upper()\n", - " return hexa\n", - "\n", - "\n", - "def key_gen(bit64):\n", - " bit64 = '#'+bit64\n", - " PC_1 = [57,49,41,33, 25,17,9,1,\n", - " 58,50,42,34, 26,18,10, \n", - " 2,59,51,43, 35,27,19,11,\n", - " 3,60,52,44, 36,63,55,47,\n", - " 39,31,23,15, 7,62,54,46,\n", - " 38,30,22,14, 6,61,53,45,\n", - " 37,29,21,13, 5,28,20,12,4]\n", - " \n", - " PC_2 = [14,17,11,24, 1,5,3,28,\n", - " 15,6,21,10, 23,19,12,4,\n", - " 26,8,16,7, 27,20,13,2, 41,52,31,37, 47,55,30,40,51,45,33,48, 44,49,39,56,34,53,46,42, 50,36,29,32]\n", - " bit56 = ''\n", - " for i in PC_1:\n", - " bit56 +=bit64[i]\n", - " L,R = bit56[:28],bit56[28:]\n", - " round_keys = []\n", - " ones = [1,2,9,16]\n", - " for i in range(1,17):\n", - " if(i in ones):\n", - " l = L[1:]+L[:1]\n", - " r = R[1:]+R[:1]\n", - " else:\n", - " l = L[2:]+L[:2]\n", - " r = R[2:]+R[:2]\n", - " k = '#'+l+r\n", - " sub_key = ''\n", - " for i in PC_2:\n", - " sub_key += k[i]\n", - " L,R = l,r\n", - "# print(len(k),len(sub_key))\n", - " round_keys.append(sub_key)\n", - " return round_keys\n", - "\n", - "test = \"133457799BBCDFF1\"\n", - "subkeys = key_gen(hex2bin(test))\n", - "[bin2hex(i) for i in subkeys]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "64b7d8da", - "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.12.3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/cryptography/extended_eucledian.ipynb b/cryptography/extended_eucledian.ipynb index a5de1fe8b..fe98c2962 100644 --- a/cryptography/extended_eucledian.ipynb +++ b/cryptography/extended_eucledian.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": 8, "id": "8561e0a7", "metadata": {}, "outputs": [ @@ -26,7 +26,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 7, "id": "12f36b2f", "metadata": {}, "outputs": [ @@ -36,27 +36,38 @@ "21" ] }, - "execution_count": 2, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "def eucld_gcd(a,b):\n", - " if(a < b):\n", - " a , b = b , a\n", - " if(b==0):\n", + "def eucld_gcd(a, b):\n", + " \"\"\"\n", + " Computes the greatest common divisor (GCD) of two integers using the Euclidean algorithm.\n", + "\n", + " Parameters:\n", + " a (int): The first integer.\n", + " b (int): The second integer.\n", + "\n", + " Returns:\n", + " int: The greatest common divisor of a and b.\n", + " \"\"\"\n", + " if a < b:\n", + " a, b = b, a\n", + " if b == 0:\n", " return a\n", - " r = a%b\n", - " if(r==0):\n", + " r = a % b\n", + " if r == 0:\n", " return b\n", - " return eucld_gcd(b,r)\n", + " return eucld_gcd(b, r)\n", + "\n", "eucld_gcd(252,105)" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 9, "id": "c060ee17", "metadata": {}, "outputs": [ @@ -66,45 +77,65 @@ "[1, -48]" ] }, - "execution_count": 3, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import numpy as np\n", - "def ext_eucld(a,b):\n", + "\n", + "def ext_eucld(a, b):\n", + " \"\"\"\n", + " Computes the extended Euclidean algorithm to find the greatest common divisor (GCD)\n", + " of two integers, and also the coefficients (x, y) of the equation:\n", + " a*x + b*y = GCD(a, b)\n", + "\n", + " This method returns the coefficients (x, y) such that a*x + b*y = GCD(a, b).\n", + "\n", + " Parameters:\n", + " a (int): The first integer.\n", + " b (int): The second integer.\n", + "\n", + " Returns:\n", + " list: A list of two integers [x, y] where x and y are the coefficients for the linear\n", + " combination of a and b that equals their GCD.\n", + " \"\"\"\n", " swap = False\n", - " if(a < b):\n", - " a , b = b , a\n", - " swap = True\n", - " def eucld(a,b):\n", - " if(b==0 or b==1):\n", + " if a < b:\n", + " a, b = b, a\n", + " swap = True\n", + "\n", + " def eucld(a, b):\n", + " if b == 0 or b == 1:\n", " return []\n", " ls = []\n", - " while b!=1:\n", - " r = a%b\n", - " if(r==0):\n", + " while b != 1:\n", + " r = a % b\n", + " if r == 0:\n", " return ls\n", - " idx = (a-r)//b\n", + " idx = (a - r) // b\n", " ls.append(idx)\n", " a = b\n", " b = r\n", " return ls\n", - " \n", - " row = np.array([[1,0],[0,1]])\n", - " ls = eucld(a,b)\n", + "\n", + " row = np.array([[1, 0], [0, 1]])\n", + " ls = eucld(a, b)\n", " for i in ls:\n", - " row = np.append(row, [row[-2] - i*row[-1]] ,axis=0)\n", - " if(swap):\n", + " row = np.append(row, [row[-2] - i * row[-1]], axis=0)\n", + " \n", + " if swap:\n", " return list(row[-1])[::-1]\n", + " \n", " return list(row[-1])\n", - "ext_eucld(97,2)" + "\n", + "ext_eucld(97, 2)\n" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 10, "id": "d3edd1f6", "metadata": {}, "outputs": [ diff --git a/cryptography/galois_field.ipynb b/cryptography/galois_field.ipynb index 2a9e19353..ac68caa85 100644 --- a/cryptography/galois_field.ipynb +++ b/cryptography/galois_field.ipynb @@ -26,9 +26,13 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 11, "id": "62243eff", - "metadata": {}, + "metadata": { + "jupyter": { + "source_hidden": true + } + }, "outputs": [ { "data": { @@ -36,120 +40,225 @@ "[0, 0, 0, 0, 1, 1, 0, 1]" ] }, - "execution_count": 2, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "def id2bit(ls:list):\n", - " if(len(ls)==0):\n", - " return [0,0,0,0, 0,0,0,0]\n", - " aa = [0 for i in range(max(ls)+1)]\n", + "def id2bit(ls: list):\n", + " \"\"\"\n", + " Converts a list of indices into a binary representation (bit vector).\n", + " \n", + " Given a list of indices (ls), this function returns a list of bits where \n", + " the bit positions corresponding to the indices in the list are set to 1, \n", + " and all other positions are set to 0. The resulting list is reversed.\n", + " \n", + " Args:\n", + " ls (list): A list of indices to be converted to bits.\n", + " \n", + " Returns:\n", + " list: A list of bits representing the binary values.\n", + " \"\"\"\n", + " if(len(ls) == 0):\n", + " return [0, 0, 0, 0, 0, 0, 0, 0] # Return a default 8-bit array\n", + " aa = [0 for _ in range(max(ls) + 1)]\n", " for i in ls:\n", - " aa[i]=1\n", + " aa[i] = 1\n", " return aa[::-1]\n", - "def bit2id(ls:list,log=False):\n", + "\n", + "def bit2id(ls: list, log=False):\n", + " \"\"\"\n", + " Converts a binary list (bit vector) back to a list of indices.\n", + " \n", + " Given a list of bits (ls), this function returns the indices of the bits\n", + " that are set to 1. The binary list is reversed during the conversion.\n", + " \n", + " Args:\n", + " ls (list): A list of bits representing a binary value.\n", + " log (bool, optional): Whether to log intermediate steps (default is False).\n", + " \n", + " Returns:\n", + " list: A list of indices where the bits are set to 1.\n", + " \"\"\"\n", " ls = ls[::-1]\n", - " aa =[]\n", + " aa = []\n", " \n", " for i in range(len(ls)):\n", - " if(ls[i]==1):\n", + " if(ls[i] == 1):\n", " aa.append(i)\n", " return aa[::-1]\n", "\n", - "def bit2mul(a,b,log=False):\n", + "def bit2mul(a, b, log=False):\n", + " \"\"\"\n", + " Multiplies two binary numbers represented as lists of bits.\n", " \n", + " This function multiplies two binary numbers by performing a bitwise \n", + " multiplication and addition over Galois Field (GF(2)).\n", + " \n", + " Args:\n", + " a (list): A list of bits representing the first binary number.\n", + " b (list): A list of bits representing the second binary number.\n", + " log (bool, optional): Whether to log intermediate steps (default is False).\n", + " \n", + " Returns:\n", + " list: The resulting binary number (list of bits).\n", + " \"\"\"\n", " ai = bit2id(a)\n", " bi = bit2id(b)\n", - " a,b = a[::-1],b[::-1]\n", + " a, b = a[::-1], b[::-1]\n", " \n", - " if(ai==[]):\n", + " if(ai == []):\n", " return a\n", - " elif(bi==[]):\n", + " elif(bi == []):\n", " return b\n", " \n", - " addn = [ [ ai[i]+bi[j] for j in range(len(bi)) ][::-1] for i in range(len(ai)) ][::-1]\n", + " addn = [[ai[i] + bi[j] for j in range(len(bi))][::-1] for i in range(len(ai))][::-1]\n", " addn = [id2bit(i) for i in addn]\n", " \n", " maxsiz = max([len(i) for i in addn])\n", " for i in range(len(addn)):\n", - " if(len(addn[i])=0)):\n", - " ml = max(dnt)-max(dsr)\n", + " \n", + " while (len(dnt) != 0 and len(dsr) != 0 and (max(dnt) - max(dsr) >= 0)):\n", + " ml = max(dnt) - max(dsr)\n", " qtnt.append(ml)\n", " plus = id2bit(dnt)\n", - " minus = id2bit([ml+i for i in dsr])\n", - " rem = bit2add(plus,minus)\n", + " minus = id2bit([ml + i for i in dsr])\n", + " rem = bit2add(plus, minus)\n", " dnt = bit2id(rem)\n", - " return id2bit(dnt),id2bit(qtnt)\n", + " \n", + " return id2bit(dnt), id2bit(qtnt)\n", "\n", + "def ext_eucld(a, b, log=False):\n", + " \"\"\"\n", + " Extended Euclidean algorithm for binary polynomials.\n", "\n", - "\n", - "\n", - "\n", - "\n", - "# import numpy as np\n", - "def ext_eucld(a,b,log=False):\n", - " ai,bi = bit2id(a),bit2id(b)\n", - " if((len(ai)!=0 and len(bi)!=0)):\n", - " if(max(max(ai),max(bi))==max(bi)):\n", - " a,b=b,a\n", - " elif(len(ai)==0 and len(bi)!=0):\n", - " a,b=b,a\n", - " def eucld(a,b,log=False):\n", + " This function computes the extended Euclidean algorithm for binary polynomials `a` and `b`,\n", + " returning the coefficients of the linear combination of `a` and `b` that equals the greatest common divisor (GCD).\n", + " \n", + " Args:\n", + " a (list): A list of bits representing the first binary polynomial.\n", + " b (list): A list of bits representing the second binary polynomial.\n", + " log (bool, optional): Whether to log intermediate steps (default is False).\n", " \n", - " a,b = a[::-1],b[::-1]\n", - " if(set(b)==set([0]) or (b[0]==1 and (set(b[1:])==set([0])))):\n", + " Returns:\n", + " list: The coefficients of the linear combination of `a` and `b` (as lists of bits).\n", + " \"\"\"\n", + " ai, bi = bit2id(a), bit2id(b)\n", + " if((len(ai) != 0 and len(bi) != 0)):\n", + " if(max(max(ai), max(bi)) == max(bi)):\n", + " a, b = b, a\n", + " elif(len(ai) == 0 and len(bi) != 0):\n", + " a, b = b, a\n", + " \n", + " def eucld(a, b, log=False):\n", + " a, b = a[::-1], b[::-1]\n", + " \n", + " if(set(b) == set([0]) or (b[0] == 1 and (set(b[1:]) == set([0])))):\n", " return []\n", + " \n", " ls = []\n", " \n", - " while not (b[0]==1 and (set(b[1:])==set([0]))):\n", + " while not (b[0] == 1 and (set(b[1:]) == set([0]))):\n", + " r, idx = modgf(b[::-1], dnt=a[::-1])\n", + " r, idx = r[::-1], idx[::-1]\n", " \n", - " r,idx = modgf(b[::-1],dnt=a[::-1])\n", - " r,idx = r[::-1],idx[::-1]\n", - " \n", - " if(set(r)==set([0])):\n", + " if(set(r) == set([0])):\n", " return ls\n", " \n", " ls.append(idx[::-1])\n", @@ -157,44 +266,45 @@ " b = r\n", " return ls\n", " \n", - " row = [[[0,0,0,0, 0,0,0,1],[0,0,0,0, 0,0,0,0]],\n", - " [[0,0,0,0, 0,0,0,0],[0,0,0,0, 0,0,0,1]]]\n", - " ls = eucld(a,b)\n", + " row = [[[0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 0, 0]],\n", + " [[0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1]]]\n", + " \n", + " ls = eucld(a, b)\n", " for i in ls:\n", - " r10,r11 = row[-1][0], row[-1][1]\n", - " r20,r21 = row[-2][0], row[-2][1]\n", - " r0 = bit2add(r20,bit2mul(r10,i))\n", - " r1 = bit2add(r21,bit2mul(r11,i))\n", - " rowl = [r0,r1]\n", + " r10, r11 = row[-1][0], row[-1][1]\n", + " r20, r21 = row[-2][0], row[-2][1]\n", + " r0 = bit2add(r20, bit2mul(r10, i))\n", + " r1 = bit2add(r21, bit2mul(r11, i))\n", + " rowl = [r0, r1]\n", " row.append(rowl)\n", + " \n", " return row[-1]\n", - "def Gfinv(bit,irrpoly = [1, 0, 0, 0, 1, 1, 0, 1, 1]):\n", - " if(set(bit)==set('0')):\n", + "\n", + "def Gfinv(bit, irrpoly=[1, 0, 0, 0, 1, 1, 0, 1, 1]):\n", + " \"\"\"\n", + " Computes the multiplicative inverse of a binary polynomial over GF(2).\n", + " \n", + " This function uses the extended Euclidean algorithm to compute the inverse of a binary polynomial `bit`\n", + " with respect to a predefined irreducible polynomial `irrpoly`.\n", + " \n", + " Args:\n", + " bit (list): A list of bits representing the binary polynomial to be inverted.\n", + " irrpoly (list, optional): The irreducible polynomial used for the field (default is a predefined polynomial).\n", + " \n", + " Returns:\n", + " list: The multiplicative inverse of the polynomial `bit` (list of bits).\n", + " \"\"\"\n", + " if(set(bit) == set('0')):\n", " return '--'\n", - " ans = ext_eucld(irrpoly,bit)\n", + " \n", + " ans = ext_eucld(irrpoly, bit)\n", " ans = ans[-1][-len(bit):]\n", " return ans\n", "\n", - "\n", - "Gfinv([0,0,0,0,0,1,0,0],irrpoly=[0,0,0,1, 0,0,1,1])" + "# Example call\n", + "Gfinv([0, 0, 0, 0, 0, 1, 0, 0], irrpoly=[0, 0, 0, 1, 0, 0, 1, 1])\n" ] }, - { - "cell_type": "code", - "execution_count": null, - "id": "2b8ce266", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "38ba4051", - "metadata": {}, - "outputs": [], - "source": [] - }, { "cell_type": "code", "execution_count": null, @@ -205,37 +315,59 @@ }, { "cell_type": "code", - "execution_count": null, - "id": "9410bfdf", - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 3, + "execution_count": 12, "id": "edb53805", "metadata": {}, "outputs": [], "source": [ - "def genmapping(n:int,irrpoly):\n", + "def genmapping(n:int, irrpoly):\n", + " \"\"\"\n", + " Generates the elements of GF(2^n) and their corresponding multiplicative inverses \n", + " based on the provided irreducible polynomial.\n", + "\n", + " Parameters:\n", + " n (int): The size of the Galois Field (GF(2^n)). Determines the number of elements \n", + " in the field, which is 2^n.\n", + " irrpoly (list): A list of bits representing the irreducible polynomial used \n", + " for the finite field operations (e.g., [1, 0, 0, 1] for x^3 + 1).\n", + "\n", + " Returns:\n", + " tuple: A tuple containing:\n", + " - gf (list): A list of binary strings of length `n`, representing all elements \n", + " of GF(2^n). The binary strings are padded with leading zeros.\n", + " - invmap (dict): A dictionary mapping the index of each element in `gf` to the \n", + " index of its multiplicative inverse, using the irreducible \n", + " polynomial for the field.\n", + "\n", + " Example:\n", + " gf, invmap = genmapping(3, [1, 0, 0, 1])\n", + " # gf will contain the elements ['000', '001', '010', '011', '100', '101', '110', '111']\n", + " # invmap will contain a mapping of the inverses for each non-zero element.\n", + " \"\"\"\n", " gf = [str(bin(i))[2:] for i in range(2**n)]\n", + " \n", + " # Ensure each element has length n (pad with leading zeros if necessary)\n", " for i in range(len(gf)):\n", - " if(len(gf[i]) element (key2ele) and element -> index (ele2key)\n", " key2ele = dict(enumerate(gf))\n", " ele2key = dict([i[::-1] for i in list(enumerate(gf))])\n", + " \n", + " # Generate the inverse map for all non-zero elements\n", " invmap = dict()\n", " for i in gf:\n", - " if(set(i)!=set('0')):\n", - " inv = bit2str(Gfinv(str2bit(i),irrpoly=irrpoly))\n", - " invmap[ele2key[i]] = ele2key[inv]\n", - " return gf,invmap" + " if set(i) != set('0'): # Skip zero element\n", + " inv = bit2str(Gfinv(str2bit(i), irrpoly=irrpoly)) # Find the inverse of i\n", + " invmap[ele2key[i]] = ele2key[inv] # Map the inverse using element-to-key mapping\n", + " \n", + " return gf, invmap\n" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 13, "id": "d4ca99d5", "metadata": {}, "outputs": [], @@ -245,7 +377,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 14, "id": "44e4797e", "metadata": {}, "outputs": [ @@ -255,7 +387,7 @@ "True" ] }, - "execution_count": 5, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -266,7 +398,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 15, "id": "b08bd2b6", "metadata": {}, "outputs": [ @@ -306,7 +438,7 @@ " 31: 27}" ] }, - "execution_count": 6, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" } diff --git a/cryptography/lfsr_bit_stream.ipynb b/cryptography/lfsr_bit_stream.ipynb index ebec63ed1..948155139 100644 --- a/cryptography/lfsr_bit_stream.ipynb +++ b/cryptography/lfsr_bit_stream.ipynb @@ -26,8 +26,8 @@ }, { "cell_type": "code", - "execution_count": 2, - "id": "f12511c2-01b6-45f4-b6b6-1bfe1dc93631", + "execution_count": 5, + "id": "d76a12a2-66f5-48b4-96c7-42cb8c8cae95", "metadata": {}, "outputs": [ { @@ -36,36 +36,101 @@ "[1, 0, 0, 0, 0, 1, 0, 1, 1, 0]" ] }, - "execution_count": 2, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "def id2bit(ls:list):\n", - " if(len(ls)==0):\n", - " return [0,0,0,0, 0,0,0,0] # Return a default 8-bit array\n", - " aa = [0 for i in range(max(ls)+1)]\n", + "def id2bit(ls: list):\n", + " \"\"\"\n", + " Converts a list of indices to a binary representation (bit array).\n", + " \n", + " Given a list of indices, this function creates a binary list where each index in \n", + " the input list is set to 1 in the output list, and all other positions are set to 0. \n", + " The output list is then reversed before returning.\n", + " \n", + " Args:\n", + " ls (list): A list of indices where each index will be set to 1 in the output list.\n", + " \n", + " Returns:\n", + " list: A list of binary values (0s and 1s), where each index in the input list corresponds \n", + " to a 1 in the output binary list, and all other indices are 0.\n", + " \"\"\"\n", + " if len(ls) == 0:\n", + " return [0, 0, 0, 0, 0, 0, 0, 0] # Return a default 8-bit array\n", + " aa = [0 for i in range(max(ls) + 1)]\n", " for i in ls:\n", " aa[i] = 1\n", " return aa[::-1]\n", "\n", - "def bit2id(ls:list):\n", + "\n", + "def bit2id(ls: list):\n", + " \"\"\"\n", + " Converts a binary list (bit array) to a list of indices where the value is 1.\n", + " \n", + " This function iterates over the binary list and returns a list of indices where the binary value is 1.\n", + " The list is reversed before returning.\n", + " \n", + " Args:\n", + " ls (list): A list of binary values (0s and 1s).\n", + " \n", + " Returns:\n", + " list: A list of indices where the corresponding binary value in the input list is 1.\n", + " \"\"\"\n", " ls = ls[::-1]\n", " aa = []\n", " for i in range(len(ls)):\n", - " if(ls[i] == 1):\n", + " if ls[i] == 1:\n", " aa.append(i)\n", " return aa[::-1]\n", - " \n", + "\n", + "\n", "def XOR(*args):\n", + " \"\"\"\n", + " Performs bitwise XOR on a sequence of values.\n", + " \n", + " This function takes any number of arguments and performs the XOR operation iteratively \n", + " across all the input values.\n", + " \n", + " Args:\n", + " *args: A sequence of values (typically integers) on which the XOR operation will be applied.\n", + " \n", + " Returns:\n", + " int: The result of applying the XOR operation across all input values.\n", + " \"\"\"\n", " result = 0\n", " for arg in args:\n", " result ^= arg\n", " return result\n", - " \n", + "\n", + "\n", "class LFSR:\n", - " def __init__(self,start,poly):\n", + " \"\"\"\n", + " A class representing a Linear Feedback Shift Register (LFSR).\n", + " \n", + " This class models an LFSR, which generates a sequence of bits based on an initial state \n", + " and a feedback polynomial. The LFSR can be clocked to generate subsequent bits in the sequence.\n", + " \n", + " Attributes:\n", + " seq (list): The current state (bit sequence) of the LFSR.\n", + " taps (list): The positions of the taps used for feedback calculation.\n", + " \n", + " Methods:\n", + " clock(): Shifts the bits in the LFSR and computes the new bit based on the feedback.\n", + " \"\"\"\n", + " \n", + " def __init__(self, start, poly):\n", + " \"\"\"\n", + " Initializes an LFSR with a start state and a feedback polynomial.\n", + " \n", + " Args:\n", + " start (list): The initial state of the LFSR, represented as a list of bits (0s and 1s).\n", + " poly (list): A list representing the feedback polynomial, with 1s indicating the taps.\n", + " \n", + " Raises:\n", + " ValueError: If the length of the start state does not match the polynomial length minus one.\n", + " \"\"\"\n", " self.seq = start\n", " self.taps = bit2id(poly[:-1]) # ignore the output tap (final bit)\n", "\n", @@ -73,55 +138,129 @@ " raise ValueError(\"Polynomial and start value length mismatch\")\n", "\n", " def clock(self):\n", - " # print(self.seq) \n", - " feedback = XOR(*[self.seq[bit] for bit in self.taps])\n", + " \"\"\"\n", + " Advances the LFSR by one clock cycle.\n", " \n", + " This method computes the feedback bit by XORing the bits at the tap positions, \n", + " shifts the state, and adds the feedback bit to the beginning of the sequence.\n", + " \"\"\"\n", + " feedback = XOR(*[self.seq[bit] for bit in self.taps])\n", " self.seq = [feedback] + self.seq[:-1]\n", "\n", - " \n", + "\n", "class A51:\n", - " def __init__(self,lfsrs,clock_bits):\n", + " \"\"\"\n", + " A class representing the A5/1 stream cipher.\n", + " \n", + " A51 is a stream cipher used in GSM encryption. It combines three LFSRs and uses a majority rule \n", + " to control which LFSRs are clocked. The output is the XOR of the last bits of the LFSRs.\n", + " \n", + " Attributes:\n", + " lfsrs (list): A list of LFSR instances.\n", + " clock_bits (list): The bit positions used for clocking each LFSR.\n", + " lfsr_count (int): The number of LFSRs used in the cipher.\n", + " \n", + " Methods:\n", + " majority(*bits): Computes the majority bit from a list of bits.\n", + " clock(): Advances the cipher and returns the next bit of the keystream.\n", + " \"\"\"\n", + " \n", + " def __init__(self, lfsrs, clock_bits):\n", + " \"\"\"\n", + " Initializes the A51 cipher with a list of LFSRs and their clocking bits.\n", + " \n", + " Args:\n", + " lfsrs (list): A list of LFSR instances used to generate the keystream.\n", + " clock_bits (list): A list indicating the bit positions in each LFSR to use for majority voting.\n", + " \"\"\"\n", " self.lfsrs = lfsrs\n", " self.clock_bits = clock_bits\n", " self.lfsr_count = len(clock_bits)\n", + "\n", " def majority(self, *bits):\n", - " ones = sum(i for i in bits if i==1)\n", + " \"\"\"\n", + " Computes the majority bit from a sequence of bits.\n", + " \n", + " This method determines the majority (1 or 0) from the given bits. If the number of 1s \n", + " is greater than or equal to half of the number of LFSRs, the majority bit is 1; otherwise, it is 0.\n", + " \n", + " Args:\n", + " *bits: A sequence of bits (typically 0s and 1s) for which the majority is to be determined.\n", + " \n", + " Returns:\n", + " int: The majority bit (0 or 1).\n", + " \"\"\"\n", + " ones = sum(i for i in bits if i == 1)\n", " if ones >= self.lfsr_count / 2:\n", " majority_bit = 1\n", " else:\n", " majority_bit = 0\n", " return majority_bit\n", - " \n", + "\n", " def clock(self):\n", + " \"\"\"\n", + " Advances the A51 cipher by one clock cycle and generates the next keystream bit.\n", + " \n", + " This method computes the majority bit from the specified clocking positions of the LFSRs, \n", + " clocks the LFSRs if necessary, and outputs the XOR of the last bits of each LFSR as the next \n", + " bit of the keystream.\n", + " \n", + " Returns:\n", + " int: The next bit in the keystream generated by the A51 cipher.\n", + " \"\"\"\n", " majority = self.majority(*[self.lfsrs[i].seq[self.clock_bits[i]] for i in range(self.lfsr_count)])\n", " for i in range(self.lfsr_count):\n", - " if(self.lfsrs[i].seq[self.clock_bits[i]] == majority):\n", + " if self.lfsrs[i].seq[self.clock_bits[i]] == majority:\n", " self.lfsrs[i].clock()\n", " out = XOR(*[int(i.seq[-1]) for i in self.lfsrs])\n", " return out\n", - " \n", - "lf1 = LFSR(start=[1,0,1,1],poly=id2bit([4,1]))\n", - "lf2 = LFSR(start=[0,1,1,1],poly=id2bit([4,1]))\n", - "lf3 = LFSR(start=[1,0,1,0],poly=id2bit([4,1]))\n", - "a51 = A51(lfsrs=[lf1,lf2,lf3],clock_bits=[1,2,0])\n", + "\n", + "\n", + "# Example usage\n", + "lf1 = LFSR(start=[1, 0, 1, 1], poly=id2bit([4, 1]))\n", + "lf2 = LFSR(start=[0, 1, 1, 1], poly=id2bit([4, 1]))\n", + "lf3 = LFSR(start=[1, 0, 1, 0], poly=id2bit([4, 1]))\n", + "a51 = A51(lfsrs=[lf1, lf2, lf3], clock_bits=[1, 2, 0])\n", + "\n", + "# Generate a keystream of 10 bits\n", "stream = [a51.clock() for i in range(10)]\n", - "stream" + "stream\n" ] }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 6, "id": "182b2a83-d083-4296-a3bc-4d4f14dd8724", "metadata": {}, "outputs": [], "source": [ "import os\n", + "\n", "def write2txt_file(bitstream, filename):\n", - " \"\"\"Writes a bitstream (string of '0's and '1's) to a text file.\"\"\"\n", + " \"\"\"\n", + " Writes a bitstream (string of '0's and '1's) to a text file.\n", + "\n", + " This function opens a text file in append mode and writes the provided bitstream to it.\n", + " \n", + " Args:\n", + " bitstream (str): A string of '0's and '1's representing the bitstream to be written.\n", + " filename (str): The path to the text file where the bitstream will be written.\n", + " \"\"\"\n", " with open(filename, 'a') as f: # Open in append mode to continue writing\n", " f.write(bitstream)\n", "\n", + "\n", "def write2bin_file(bitstream, filename):\n", + " \"\"\"\n", + " Writes a bitstream (string of '0's and '1's) to a binary file.\n", + "\n", + " This function converts the bitstream into bytes, pads it to ensure it's a multiple of 8 bits, \n", + " and then writes it to a binary file in append mode.\n", + " \n", + " Args:\n", + " bitstream (str): A string of '0's and '1's representing the bitstream to be written.\n", + " filename (str): The path to the binary file where the bitstream will be written.\n", + " \"\"\"\n", " byte_list = []\n", " \n", " # Pad the bitstream if it's not a multiple of 8\n", @@ -136,44 +275,57 @@ " with open(filename, 'ab') as f: # 'ab' mode to append to the binary file\n", " f.write(bytearray(byte_list))\n", "\n", - "def gen_bit_stream(data:dict,target_size,file_path):\n", - " lfsrs = [LFSR(start=i[\"start\"],poly=i[\"poly\"]) for i in data]\n", - " a51 = A51(lfsrs=lfsrs,clock_bits=[i[\"clock\"] for i in data])\n", - " \n", - " # filename = 'bitstream_output_1GB.bin'\n", - " # target_size = 1 * 1024 * 1024 * 1024 # 1 GB in bytes\n", - " current_size = 0\n", "\n", + "def gen_bit_stream(data: dict, target_size: int, file_path: str):\n", + " \"\"\"\n", + " Generates a keystream using the A51 cipher and writes it to a file.\n", + "\n", + " This function initializes the LFSRs based on the provided data, generates a keystream \n", + " using the A51 cipher, and writes the generated bits to a text file or binary file \n", + " in chunks. It keeps track of the current size of the output file and prints progress \n", + " at each 10% interval.\n", + "\n", + " Args:\n", + " data (dict): A dictionary containing information about the LFSRs, including their \n", + " start values, polynomials, and clock positions.\n", + " target_size (int): The target size of the file in bytes. The function will stop once \n", + " this size is reached.\n", + " file_path (str): The path to the output file where the generated bitstream will be written.\n", + " \"\"\"\n", + " # Initialize the LFSRs and A51 cipher\n", + " lfsrs = [LFSR(start=i[\"start\"], poly=i[\"poly\"]) for i in data]\n", + " a51 = A51(lfsrs=lfsrs, clock_bits=[i[\"clock\"] for i in data])\n", + " \n", + " current_size = 0\n", " bitstream_chunk = \"\" # Chunk of bits to write periodically\n", " chunk_size = 10000 # Number of bits to generate at a time (can adjust for performance)\n", " progress_interval = target_size // 10 # 1/10th of the target size (100 MB)\n", " next_progress_checkpoint = progress_interval\n", " \n", + " # Generate bits until the target file size is reached\n", " while current_size < target_size:\n", " # Generate bits in chunks\n", " for _ in range(chunk_size):\n", " bitstream_chunk += str(a51.clock())\n", "\n", - " # Write chunk to file\n", - " # write2bin_file(bitstream_chunk, filename)\n", + " # Write the chunk to file\n", " write2txt_file(bitstream_chunk, file_path)\n", " \n", " # Clear the chunk and update the current file size\n", " bitstream_chunk = \"\"\n", " current_size = os.path.getsize(file_path)\n", + " \n", " # Check if the file size has crossed the 1/10th checkpoint\n", " if current_size >= next_progress_checkpoint:\n", - " print(f\"File size crossed {round(next_progress_checkpoint / (1024 * 1024),2)} MB\")\n", + " print(f\"File size crossed {round(next_progress_checkpoint / (1024 * 1024), 2)} MB\")\n", " next_progress_checkpoint += progress_interval # Update to next 10% checkpoint\n", "\n", - " \n", - "\n", - " print(f\"File generation complete: {file_path} (target)\")" + " print(f\"File generation complete: {file_path} (target)\")\n" ] }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 7, "id": "ebf2b473-4277-4b99-9935-96802dc52488", "metadata": {}, "outputs": [ @@ -182,15 +334,6 @@ "output_type": "stream", "text": [ "File size crossed 0.1 MB\n", - "File size crossed 0.2 MB\n", - "File size crossed 0.3 MB\n", - "File size crossed 0.4 MB\n", - "File size crossed 0.5 MB\n", - "File size crossed 0.6 MB\n", - "File size crossed 0.7 MB\n", - "File size crossed 0.8 MB\n", - "File size crossed 0.9 MB\n", - "File size crossed 1.0 MB\n", "File generation complete: mine_gen_100MB.txt (target)\n" ] } diff --git a/cryptography/playfire.ipynb b/cryptography/playfire.ipynb index 5814f34fe..c7f9ad0b8 100644 --- a/cryptography/playfire.ipynb +++ b/cryptography/playfire.ipynb @@ -26,92 +26,163 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 10, "id": "b73906e7", "metadata": {}, "outputs": [], "source": [ "class PlayFire:\n", - " def __init__(self,key,extra='x'):\n", + " \"\"\"\n", + " PlayFire class implements the Playfair cipher for encryption and decryption of messages.\n", + "\n", + " The Playfair cipher is a digraph substitution cipher that encrypts pairs of letters. It requires a key, which \n", + " is used to create a 6x6 matrix of letters and digits, and processes the message in pairs.\n", + "\n", + " Attributes:\n", + " key (str): The key used to generate the matrix.\n", + " key_matrix (list): The 6x6 matrix used for encryption and decryption.\n", + " extra (str): The extra character used to pad the message if the length is odd (default is 'x').\n", + "\n", + " Methods:\n", + " __verify_key(key): Verifies that the key is valid (contains unique characters).\n", + " __make_matrix(): Creates a 6x6 matrix using the key and the remaining letters/digits.\n", + " find_idx(pair): Finds the positions (row and column indices) of the pair of characters in the matrix.\n", + " encrypt(msg): Encrypts the given message using the Playfair cipher.\n", + " decrypt(msg): Decrypts the given encrypted message using the Playfair cipher.\n", + " \"\"\"\n", + "\n", + " def __init__(self, key, extra='x'):\n", + " \"\"\"\n", + " Initializes the PlayFire cipher with a key and an optional extra character for padding.\n", + "\n", + " Parameters:\n", + " key (str): The key to generate the cipher matrix.\n", + " extra (str, optional): The character used for padding the message if its length is odd. Defaults to 'x'.\n", + " \"\"\"\n", " self.key = self.__verify_key(key)\n", " self.key_matrix = self.__make_matrix()\n", " self.extra = extra\n", - " def __verify_key(self,key):\n", + "\n", + " def __verify_key(self, key):\n", + " \"\"\"\n", + " Verifies that the provided key contains unique characters.\n", + "\n", + " Parameters:\n", + " key (str): The key to verify.\n", + "\n", + " Returns:\n", + " str: The valid key if it contains only unique characters, else prints an error.\n", + " \"\"\"\n", " keyy = []\n", " for i in key:\n", " if(i not in keyy):\n", " keyy.append(i)\n", - " if(len(set(key))==len(key)):\n", + " if(len(set(key)) == len(key)):\n", " return key\n", " else:\n", " print(\"key Error\")\n", + "\n", " def __make_matrix(self):\n", + " \"\"\"\n", + " Creates a 6x6 matrix from the key by filling in remaining characters of the alphabet and digits.\n", + "\n", + " Returns:\n", + " list: A 6x6 matrix for encryption and decryption.\n", + " \"\"\"\n", " alphanum = list(\"abcdefghijklmnopqrstuvwxyz0123456789\")\n", " key = list(self.key)\n", - " xx = key+[i for i in alphanum if i not in key]\n", + " xx = key + [i for i in alphanum if i not in key]\n", " mtrx = []\n", " idx = 0\n", " for i in range(6):\n", - " t1 = xx[idx:idx+6]\n", + " t1 = xx[idx:idx + 6]\n", " mtrx.append(t1)\n", - " idx = idx+6\n", + " idx = idx + 6\n", " return mtrx\n", - " def find_idx(self,pair):\n", - " idxs = [6,6]\n", - " for i in range(6):\n", - " for j in range(6):\n", - " if(i == 5):\n", - " i = -1\n", - " if(j == 5):\n", - " j = -1\n", - " if(pair[0]==self.key_matrix[i][j]):\n", - " idxs[0] = [i,j]\n", - " if(pair[1]==self.key_matrix[i][j]):\n", - " idxs[1] = [i,j]\n", - " return idxs\n", - " def encrypt(self,msg:str):\n", + "\n", + " def find_idx(self, pair):\n", + " \"\"\"\n", + " Finds the row and column indices of the characters in the matrix.\n", + "\n", + " Parameters:\n", + " pair (list): A pair of characters whose positions are to be found in the matrix.\n", + "\n", + " Returns:\n", + " list: A list containing the row and column indices of both characters in the matrix.\n", + " \"\"\"\n", + " idxs = [6, 6]\n", + " for i in range(6):\n", + " for j in range(6):\n", + " if(i == 5):\n", + " i = -1\n", + " if(j == 5):\n", + " j = -1\n", + " if(pair[0] == self.key_matrix[i][j]):\n", + " idxs[0] = [i, j]\n", + " if(pair[1] == self.key_matrix[i][j]):\n", + " idxs[1] = [i, j]\n", + " return idxs\n", + "\n", + " def encrypt(self, msg: str):\n", + " \"\"\"\n", + " Encrypts the given message using the Playfair cipher.\n", + "\n", + " Parameters:\n", + " msg (str): The plaintext message to encrypt.\n", + "\n", + " Returns:\n", + " str: The encrypted message.\n", + " \"\"\"\n", " msg = list(msg.lower())\n", - " if(len(msg)%2==1):\n", + " if(len(msg) % 2 == 1):\n", " msg.append(self.extra)\n", " pairs = []\n", - " for i in range(0,len(msg),2):\n", - " pairs.append(msg[i:i+2])\n", - " en_msg=\"\"\n", + " for i in range(0, len(msg), 2):\n", + " pairs.append(msg[i:i + 2])\n", + " en_msg = \"\"\n", " for i in pairs:\n", " idxs = self.find_idx(i)\n", - " if(idxs[0][0]==idxs[1][0]):\n", - " en_m = self.key_matrix[idxs[0][0]][idxs[0][1]+1]+self.key_matrix[idxs[0][0]][idxs[1][1]+1]\n", - " elif(idxs[0][1]==idxs[1][1]):\n", - " \n", - " en_m = self.key_matrix[idxs[0][0]+1][idxs[0][1]]+self.key_matrix[idxs[1][0]+1][idxs[1][1]]\n", + " if(idxs[0][0] == idxs[1][0]):\n", + " en_m = self.key_matrix[idxs[0][0]][idxs[0][1] + 1] + self.key_matrix[idxs[0][0]][idxs[1][1] + 1]\n", + " elif(idxs[0][1] == idxs[1][1]):\n", + " en_m = self.key_matrix[idxs[0][0] + 1][idxs[0][1]] + self.key_matrix[idxs[1][0] + 1][idxs[1][1]]\n", " else:\n", - " en_m = self.key_matrix[idxs[0][0]][idxs[1][1]]+self.key_matrix[idxs[1][0]][idxs[0][1]]\n", + " en_m = self.key_matrix[idxs[0][0]][idxs[1][1]] + self.key_matrix[idxs[1][0]][idxs[0][1]]\n", " en_msg += en_m\n", " return en_msg\n", - " \n", - " def decrypt(self,msg):\n", + "\n", + " def decrypt(self, msg):\n", + " \"\"\"\n", + " Decrypts the given encrypted message using the Playfair cipher.\n", + "\n", + " Parameters:\n", + " msg (str): The encrypted message to decrypt.\n", + "\n", + " Returns:\n", + " str: The decrypted plaintext message.\n", + " \"\"\"\n", " msg = list(msg.lower())\n", - " if(len(msg)%2==1):\n", + " if(len(msg) % 2 == 1):\n", " msg.append(self.extra)\n", " pairs = []\n", - " for i in range(0,len(msg),2):\n", - " pairs.append(msg[i:i+2])\n", - " en_msg=\"\"\n", + " for i in range(0, len(msg), 2):\n", + " pairs.append(msg[i:i + 2])\n", + " en_msg = \"\"\n", " for i in pairs:\n", " idxs = self.find_idx(i)\n", - " if(idxs[0][0]==idxs[1][0]):\n", - " en_m = self.key_matrix[idxs[0][0]][idxs[0][1]-1]+self.key_matrix[idxs[0][0]][idxs[1][1]-1]\n", - " elif(idxs[0][1]==idxs[1][1]):\n", - " en_m = self.key_matrix[idxs[0][0]-1][idxs[0][1]]+self.key_matrix[idxs[1][0]-1][idxs[1][1]]\n", + " if(idxs[0][0] == idxs[1][0]):\n", + " en_m = self.key_matrix[idxs[0][0]][idxs[0][1] - 1] + self.key_matrix[idxs[0][0]][idxs[1][1] - 1]\n", + " elif(idxs[0][1] == idxs[1][1]):\n", + " en_m = self.key_matrix[idxs[0][0] - 1][idxs[0][1]] + self.key_matrix[idxs[1][0] - 1][idxs[1][1]]\n", " else:\n", - " en_m = self.key_matrix[idxs[0][0]][idxs[1][1]]+self.key_matrix[idxs[1][0]][idxs[0][1]]\n", + " en_m = self.key_matrix[idxs[0][0]][idxs[1][1]] + self.key_matrix[idxs[1][0]][idxs[0][1]]\n", " en_msg += en_m\n", - " return en_msg" + " return en_msg\n" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 11, "id": "4b861600", "metadata": {}, "outputs": [ @@ -126,7 +197,7 @@ " ['4', '5', '6', '7', '8', '9']]" ] }, - "execution_count": 5, + "execution_count": 11, "metadata": {}, "output_type": "execute_result" } @@ -138,7 +209,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 12, "id": "7c4e1caa", "metadata": {}, "outputs": [ @@ -148,7 +219,7 @@ "'ydppny3b7u'" ] }, - "execution_count": 6, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" } @@ -161,7 +232,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 13, "id": "48c8a847", "metadata": {}, "outputs": [ @@ -171,7 +242,7 @@ "'hello1234x'" ] }, - "execution_count": 7, + "execution_count": 13, "metadata": {}, "output_type": "execute_result" } @@ -182,7 +253,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 14, "id": "62806ee1", "metadata": {}, "outputs": [ @@ -192,7 +263,7 @@ "'thismy1stdayofcollegeilearntabouteverythingandmetmyfriends'" ] }, - "execution_count": 8, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } @@ -203,7 +274,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 15, "id": "a7a9907b", "metadata": {}, "outputs": [ @@ -213,7 +284,7 @@ "'rx'" ] }, - "execution_count": 9, + "execution_count": 15, "metadata": {}, "output_type": "execute_result" }