docstring added to cryptography

This commit is contained in:
Bibekananda Hati 2024-11-20 23:13:11 +05:30
parent 27332fa728
commit d691df4e90
5 changed files with 622 additions and 403 deletions

View File

@ -1,158 +0,0 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "1057a613",
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<style>.container{width:100%}</style>\n"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%%HTML\n",
"<style>.container{width:100%}</style>"
]
},
{
"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
}

View File

@ -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",
" \"\"\"\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",
" if b == 0:\n",
" return a\n",
" r = a % b\n",
" if(r==0):\n",
" if r == 0:\n",
" return b\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,25 +77,42 @@
"[1, -48]"
]
},
"execution_count": 3,
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import numpy as np\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",
" 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",
" if b == 0 or b == 1:\n",
" return []\n",
" ls = []\n",
" while b != 1:\n",
" r = a % b\n",
" if(r==0):\n",
" if r == 0:\n",
" return ls\n",
" idx = (a - r) // b\n",
" ls.append(idx)\n",
@ -96,15 +124,18 @@
" 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",
" \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": [

View File

@ -26,9 +26,13 @@
},
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 11,
"id": "62243eff",
"metadata": {},
"metadata": {
"jupyter": {
"source_hidden": true
}
},
"outputs": [
{
"data": {
@ -36,20 +40,47 @@
"[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",
" \"\"\"\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]\n",
" aa = [0 for i in range(max(ls)+1)]\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",
" return aa[::-1]\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",
" \n",
@ -59,7 +90,20 @@
" return aa[::-1]\n",
"\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",
@ -75,46 +119,101 @@
" maxsiz = max([len(i) for i in addn])\n",
" for i in range(len(addn)):\n",
" if(len(addn[i]) < maxsiz):\n",
" addn[i] = [0 for j in range(maxsiz-len(addn[i]))]+addn[i]\n",
" addn[i] = [0 for _ in range(maxsiz - len(addn[i]))] + addn[i]\n",
" \n",
" smm = []\n",
" for i in range(maxsiz):\n",
" t = 0\n",
" for j in addn:\n",
" t += j[i]\n",
" smm.append(t % 2)\n",
" \n",
" return smm\n",
"\n",
"def bit2add(a, b):\n",
" \"\"\"\n",
" Adds two binary numbers represented as lists of bits (bitwise addition).\n",
" \n",
" This function adds two binary numbers by performing a bitwise addition over 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",
" \n",
" Returns:\n",
" list: The resulting binary number after addition (list of bits).\n",
" \"\"\"\n",
" a, b = list(a), list(b)\n",
" a, b = a[::-1], b[::-1]\n",
" maxsiz = max(len(a), len(b))\n",
" \n",
" \n",
" if(len(a) < maxsiz):\n",
" a = a+[0 for j in range(maxsiz-len(a))]\n",
" a = a + [0 for _ in range(maxsiz - len(a))]\n",
" if(len(b) < maxsiz):\n",
" b = b+[0 for j in range(maxsiz-len(b))]\n",
" b = b + [0 for _ in range(maxsiz - len(b))]\n",
" \n",
" smm = []\n",
" for i in range(maxsiz):\n",
" smm.append((a[i] + b[i]) % 2)\n",
" \n",
" return smm[::-1]\n",
"\n",
"def bit2str(bit: list):\n",
" \"\"\"\n",
" Converts a list of bits into a string.\n",
" \n",
" This function converts a list of binary bits (0s and 1s) into a string of characters.\n",
" \n",
" Args:\n",
" bit (list): A list of bits (0s and 1s).\n",
" \n",
" Returns:\n",
" str: The string representation of the binary bits.\n",
" \"\"\"\n",
" s = \"\"\n",
" for i in bit:\n",
" s += str(i)\n",
" return s\n",
"\n",
"def str2bit(s: str):\n",
" \"\"\"\n",
" Converts a string of '0's and '1's into a list of bits.\n",
" \n",
" This function converts a string containing '0's and '1's into a list of integer bits.\n",
" \n",
" Args:\n",
" s (str): A string containing '0's and '1's.\n",
" \n",
" Returns:\n",
" list: A list of bits (integers).\n",
" \n",
" Raises:\n",
" ValueError: If the string contains characters other than '0' and '1'.\n",
" \"\"\"\n",
" if(set(s).issubset(set('01'))):\n",
" bit=[]\n",
" for i in s:\n",
" bit.append(int(i))\n",
" bit = [int(i) for i in s]\n",
" return bit\n",
" else:\n",
" print(\"bit string should contain 1s and 0s\")\n",
"\n",
"def modgf(dsr: list, dnt = [1, 0, 0, 0, 1, 1, 0, 1, 1]):\n",
" \"\"\"\n",
" Performs polynomial division over Galois Field (GF(2)).\n",
"\n",
" This function divides the binary polynomial `dsr` by the binary polynomial `dnt`\n",
" and returns the quotient and remainder.\n",
" \n",
" Args:\n",
" dsr (list): The dividend as a list of bits (binary polynomial).\n",
" dnt (list, optional): The divisor as a list of bits (default is a predefined irreducible polynomial).\n",
" \n",
" Returns:\n",
" tuple: The remainder and quotient as lists of bits.\n",
" \"\"\"\n",
" dsr = bit2id(dsr)\n",
" dnt = bit2id(dnt)\n",
" qtnt = []\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",
@ -122,30 +221,40 @@
" minus = id2bit([ml + i for i in dsr])\n",
" rem = bit2add(plus, minus)\n",
" dnt = bit2id(rem)\n",
" \n",
" return id2bit(dnt), id2bit(qtnt)\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"\n",
"# import numpy as np\n",
"def ext_eucld(a, b, log=False):\n",
" \"\"\"\n",
" Extended Euclidean algorithm for binary polynomials.\n",
"\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",
" 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",
" def eucld(a,b,log=False):\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",
" \n",
" r, idx = modgf(b[::-1], dnt=a[::-1])\n",
" r, idx = r[::-1], idx[::-1]\n",
" \n",
@ -159,6 +268,7 @@
" \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",
@ -167,34 +277,34 @@
" r1 = bit2add(r21, bit2mul(r11, i))\n",
" rowl = [r0, r1]\n",
" row.append(rowl)\n",
" \n",
" return row[-1]\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",
" \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",
" \"\"\"\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])<n):\n",
" if len(gf[i]) < n:\n",
" gf[i] = '0' * (n - len(gf[i])) + gf[i]\n",
" \n",
" # Create mappings: index -> 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"
}

View File

@ -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",
" \"\"\"\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",
"\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",
"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",
"class LFSR:\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,18 +138,58 @@
" 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",
"class A51:\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",
" \"\"\"\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",
@ -93,35 +198,69 @@
" return majority_bit\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",
"\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",
"\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",
" # filename = 'bitstream_output_1GB.bin'\n",
" # target_size = 1 * 1024 * 1024 * 1024 # 1 GB in bytes\n",
" current_size = 0\n",
"\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",
" 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"
]
}

View File

@ -26,17 +26,53 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 10,
"id": "b73906e7",
"metadata": {},
"outputs": [],
"source": [
"class PlayFire:\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",
"\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",
@ -45,7 +81,14 @@
" 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",
@ -56,7 +99,17 @@
" mtrx.append(t1)\n",
" idx = idx + 6\n",
" return mtrx\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",
@ -69,7 +122,17 @@
" 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",
" msg.append(self.extra)\n",
@ -82,7 +145,6 @@
" 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",
" else:\n",
" en_m = self.key_matrix[idxs[0][0]][idxs[1][1]] + self.key_matrix[idxs[1][0]][idxs[0][1]]\n",
@ -90,6 +152,15 @@
" return en_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",
" msg.append(self.extra)\n",
@ -106,12 +177,12 @@
" else:\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"
}