mirror of
https://github.com/TheAlgorithms/Python.git
synced 2024-12-18 01:00:15 +00:00
Update galois_field.ipynb
This commit is contained in:
parent
f3f32ae3ca
commit
7becd05ff9
946
algorithms/Graph.ipynb
Normal file
946
algorithms/Graph.ipynb
Normal file
File diff suppressed because one or more lines are too long
215
cryptography/extended_eucledian.ipynb
Normal file
215
cryptography/extended_eucledian.ipynb
Normal file
|
@ -0,0 +1,215 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "8561e0a7",
|
||||
"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": "code",
|
||||
"execution_count": 5,
|
||||
"id": "12f36b2f",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"21"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"def eucld_gcd(a, b):\n",
|
||||
" \"\"\"\n",
|
||||
" Computes the greatest common divisor (GCD) of \n",
|
||||
" 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",
|
||||
" return b\n",
|
||||
" return eucld_gcd(b, r)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"eucld_gcd(252, 105)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "c060ee17",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[1, -48]"
|
||||
]
|
||||
},
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import numpy as np\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def ext_eucld(a, b):\n",
|
||||
" \"\"\"\n",
|
||||
" Computes the extended Euclidean algorithm to find the \n",
|
||||
" greatest common divisor (GCD)of two integers, and \n",
|
||||
" 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) \n",
|
||||
" 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 \n",
|
||||
" coefficients for the linear combination of a and b \n",
|
||||
" that equals their GCD.\n",
|
||||
" \"\"\"\n",
|
||||
" swap = False\n",
|
||||
" if a < b:\n",
|
||||
" a, b = b, a\n",
|
||||
" swap = True\n",
|
||||
"\n",
|
||||
" def eucld(a, b):\n",
|
||||
" if b in {0,1}:\n",
|
||||
" return []\n",
|
||||
" ls = []\n",
|
||||
" while b != 1:\n",
|
||||
" r = a % b\n",
|
||||
" if r == 0:\n",
|
||||
" return ls\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",
|
||||
" for i in ls:\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",
|
||||
"\n",
|
||||
"\n",
|
||||
"ext_eucld(97, 2)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "d3edd1f6",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"a=5, b=7, gcd=1, m=3, n=-2, ma+nb=1\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
<<<<<<< HEAD
|
||||
"a, b= 5, 7\n",
|
||||
=======
|
||||
"a = 5\n",
|
||||
"b = 7\n",
|
||||
>>>>>>> ffbe3bbd8623bff453d16b942b7cf035c20d808c
|
||||
"gcd = eucld_gcd(a, b)\n",
|
||||
"m, n = ext_eucld(a, b)\n",
|
||||
"print(f\"a={a}, b={b}, gcd={gcd}, m={m}, n={n}, ma+nb={m*a+n*b}\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "782bb8d3",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "e224063e",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3da0aaac-23b4-4118-ae3e-aef611f0f38c",
|
||||
"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
|
||||
}
|
732
cryptography/galois_field.ipynb
Normal file
732
cryptography/galois_field.ipynb
Normal file
|
@ -0,0 +1,732 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "054915e4",
|
||||
"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": "code",
|
||||
"execution_count": 11,
|
||||
"id": "62243eff",
|
||||
"metadata": {
|
||||
"jupyter": {
|
||||
"source_hidden": true
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[0, 0, 0, 0, 1, 1, 0, 1]"
|
||||
]
|
||||
},
|
||||
"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] # 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",
|
||||
"\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",
|
||||
" for i in range(len(ls)):\n",
|
||||
" if ls[i] == 1:\n",
|
||||
" aa.append(i)\n",
|
||||
" return aa[::-1]\n",
|
||||
"\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",
|
||||
"\n",
|
||||
" if ai == []:\n",
|
||||
" return a\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 = [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]) < maxsiz:\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",
|
||||
"\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",
|
||||
" if len(a) < maxsiz:\n",
|
||||
" a = a + [0 for _ in range(maxsiz - len(a))]\n",
|
||||
" if len(b) < maxsiz:\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",
|
||||
"\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",
|
||||
"\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 = [int(i) for i in s]\n",
|
||||
" return bit\n",
|
||||
" else:\n",
|
||||
" print(\"bit string should contain 1s and 0s\")\n",
|
||||
"\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",
|
||||
" plus = id2bit(dnt)\n",
|
||||
" 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",
|
||||
"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",
|
||||
"\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",
|
||||
" r, idx = modgf(b[::-1], dnt=a[::-1])\n",
|
||||
" r, idx = r[::-1], idx[::-1]\n",
|
||||
"\n",
|
||||
" if set(r) == set([0]):\n",
|
||||
" return ls\n",
|
||||
"\n",
|
||||
" ls.append(idx[::-1])\n",
|
||||
" a = b\n",
|
||||
" b = r\n",
|
||||
" return ls\n",
|
||||
"\n",
|
||||
" row = [\n",
|
||||
" [[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",
|
||||
"\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",
|
||||
" row.append(rowl)\n",
|
||||
"\n",
|
||||
" return row[-1]\n",
|
||||
"\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",
|
||||
"# Example call\n",
|
||||
"Gfinv([0, 0, 0, 0, 0, 1, 0, 0], irrpoly=[0, 0, 0, 1, 0, 0, 1, 1])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "0c2b9aab",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"[0, 0, 0, 0, 1, 1, 0, 1]\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"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 _ 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",
|
||||
" ls = ls[::-1]\n",
|
||||
" aa = []\n",
|
||||
" for i in range(len(ls)):\n",
|
||||
" if ls[i] == 1:\n",
|
||||
" aa.append(i)\n",
|
||||
" return aa[::-1]\n",
|
||||
"\n",
|
||||
"def bit2mul(a, b, log=False):\n",
|
||||
" ai = bit2id(a)\n",
|
||||
" bi = bit2id(b)\n",
|
||||
" a, b = a[::-1], b[::-1]\n",
|
||||
" \n",
|
||||
" if ai == []:\n",
|
||||
" return a\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 = [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]) < maxsiz:\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",
|
||||
" a, b = list(a), list(b)\n",
|
||||
" a, b = a[::-1], b[::-1]\n",
|
||||
" maxsiz = max(len(a), len(b))\n",
|
||||
" \n",
|
||||
" if len(a) < maxsiz:\n",
|
||||
" a = a + [0 for _ in range(maxsiz - len(a))]\n",
|
||||
" if len(b) < maxsiz:\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",
|
||||
" s = \"\"\n",
|
||||
" for i in bit:\n",
|
||||
" s += str(i)\n",
|
||||
" return s\n",
|
||||
"\n",
|
||||
"def str2bit(s: str):\n",
|
||||
" if set(s).issubset(set('01')):\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=None):\n",
|
||||
" if dnt is None:\n",
|
||||
" dnt = [1, 0, 0, 0, 1, 1, 0, 1, 1]\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",
|
||||
" plus = id2bit(dnt)\n",
|
||||
" 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",
|
||||
"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",
|
||||
" \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",
|
||||
" r, idx = modgf(b[::-1], dnt=a[::-1])\n",
|
||||
" r, idx = r[::-1], idx[::-1]\n",
|
||||
" \n",
|
||||
" if set(r) == set([0]):\n",
|
||||
" return ls\n",
|
||||
" \n",
|
||||
" ls.append(idx[::-1])\n",
|
||||
" a = b\n",
|
||||
" 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",
|
||||
" \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",
|
||||
" row.append(rowl)\n",
|
||||
" \n",
|
||||
" return row[-1]\n",
|
||||
"\n",
|
||||
"def Gfinv(bit, irrpoly=None):\n",
|
||||
" if irrpoly is None:\n",
|
||||
" irrpoly = [1, 0, 0, 0, 1, 1, 0, 1, 1]\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",
|
||||
"# Example call\n",
|
||||
"print(Gfinv([0, 0, 0, 0, 0, 1, 0, 0], irrpoly=[0, 0, 0, 1, 0, 0, 1, 1]))\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "edb53805",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[0, 0, 0, 0, 1, 1, 0, 1]"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"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",
|
||||
" 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\"): # Skip zero element\n",
|
||||
" inv = bit2str(Gfinv(str2bit(i), irrpoly=irrpoly)) # Find the inverse of i\n",
|
||||
<<<<<<< HEAD
|
||||
" invmap[ele2key[i]] = ele2key[inv] # Map the inverse using element-to-key mapping\n",
|
||||
" \n",
|
||||
" return gf, invmap\n",
|
||||
"# Example call\n",
|
||||
"Gfinv([0, 0, 0, 0, 0, 1, 0, 0], irrpoly=[0, 0, 0, 1, 0, 0, 1, 1])\n"
|
||||
=======
|
||||
" invmap[ele2key[i]] = ele2key[\n",
|
||||
" inv\n",
|
||||
" ] # Map the inverse using element-to-key mapping\n",
|
||||
"\n",
|
||||
" return gf, invmap"
|
||||
>>>>>>> ffbe3bbd8623bff453d16b942b7cf035c20d808c
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "d4ca99d5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"gf5, invmap = genmapping(n=5, irrpoly=id2bit([5, 2, 0]))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "44e4797e",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 7,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"set(invmap.values()) == set(invmap.keys())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "b08bd2b6",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"{1: 1,\n",
|
||||
" 2: 18,\n",
|
||||
" 3: 28,\n",
|
||||
" 4: 9,\n",
|
||||
" 5: 23,\n",
|
||||
" 6: 14,\n",
|
||||
" 7: 12,\n",
|
||||
" 8: 22,\n",
|
||||
" 9: 4,\n",
|
||||
" 10: 25,\n",
|
||||
" 11: 16,\n",
|
||||
" 12: 7,\n",
|
||||
" 13: 15,\n",
|
||||
" 14: 6,\n",
|
||||
" 15: 13,\n",
|
||||
" 16: 11,\n",
|
||||
" 17: 24,\n",
|
||||
" 18: 2,\n",
|
||||
" 19: 29,\n",
|
||||
" 20: 30,\n",
|
||||
" 21: 26,\n",
|
||||
" 22: 8,\n",
|
||||
" 23: 5,\n",
|
||||
" 24: 17,\n",
|
||||
" 25: 10,\n",
|
||||
" 26: 21,\n",
|
||||
" 27: 31,\n",
|
||||
" 28: 3,\n",
|
||||
" 29: 19,\n",
|
||||
" 30: 20,\n",
|
||||
" 31: 27}"
|
||||
]
|
||||
},
|
||||
"execution_count": 8,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"invmap"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "90374ee9",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "06a7f472",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"gf28 = [str(bin(i))[2:] for i in range(256)]\n",
|
||||
"for i in range(len(gf28)):\n",
|
||||
" if len(gf28[i]) < 8:\n",
|
||||
" gf28[i] = \"0\" * (8 - len(gf28[i])) + gf28[i]\n",
|
||||
"\n",
|
||||
"key2ele = dict(enumerate(gf28))\n",
|
||||
"ele2key = dict([i[::-1] for i in list(enumerate(gf28))])\n",
|
||||
"invmap = dict()\n",
|
||||
"for i in gf28:\n",
|
||||
" if set(i) != set(\"0\"):\n",
|
||||
" inv = bit2str(Gfinv(str2bit(i)))\n",
|
||||
" invmap[ele2key[i]] = ele2key[inv]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "5fcfedd5",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"True"
|
||||
]
|
||||
},
|
||||
"execution_count": 10,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"set(invmap.values()) == set(invmap.keys())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "4059dff6",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "06b3e5d5",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "37dd903a",
|
||||
"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
|
||||
}
|
397
cryptography/lfsr_bit_stream.ipynb
Normal file
397
cryptography/lfsr_bit_stream.ipynb
Normal file
|
@ -0,0 +1,397 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "65571230-ccb3-41a1-a361-31097b31bc5b",
|
||||
"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": "code",
|
||||
"execution_count": 5,
|
||||
"id": "d76a12a2-66f5-48b4-96c7-42cb8c8cae95",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[1, 0, 0, 0, 0, 1, 0, 1, 1, 0]"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"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",
|
||||
"\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",
|
||||
" 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",
|
||||
" if len(self.seq) != len(poly) - 1:\n",
|
||||
" raise ValueError(\"Polynomial and start value length mismatch\")\n",
|
||||
"\n",
|
||||
" def clock(self):\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",
|
||||
" else:\n",
|
||||
" majority_bit = 0\n",
|
||||
" 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(\n",
|
||||
" *[self.lfsrs[i].seq[self.clock_bits[i]] for i in range(self.lfsr_count)]\n",
|
||||
" )\n",
|
||||
" for i in range(self.lfsr_count):\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"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "182b2a83-d083-4296-a3bc-4d4f14dd8724",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import os\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"def write2txt_file(bitstream, filename):\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",
|
||||
" padding = (8 - (len(bitstream) % 8)) % 8\n",
|
||||
" bitstream += \"0\" * padding # Add extra '0's to make the length a multiple of 8\n",
|
||||
"\n",
|
||||
" for i in range(0, len(bitstream), 8):\n",
|
||||
" byte = bitstream[i : i + 8]\n",
|
||||
" byte_list.append(int(byte, 2)) # Convert 8 bits to an integer (byte)\n",
|
||||
"\n",
|
||||
" # Append the bytes to the binary file\n",
|
||||
" with open(filename, \"ab\") as f: # 'ab' mode to append to the binary file\n",
|
||||
" f.write(bytearray(byte_list))\n",
|
||||
"\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 = (\n",
|
||||
" 10000 # Number of bits to generate at a time (can adjust for performance)\n",
|
||||
" )\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 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(\n",
|
||||
" f\"File size crossed {round(next_progress_checkpoint / (1024 * 1024), 2)} MB\"\n",
|
||||
" )\n",
|
||||
" next_progress_checkpoint += (\n",
|
||||
" progress_interval # Update to next 10% checkpoint\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" print(f\"File generation complete: {file_path} (target)\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "ebf2b473-4277-4b99-9935-96802dc52488",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"File size crossed 0.1 MB\n",
|
||||
"File generation complete: mine_gen_100MB.txt (target)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"data = [\n",
|
||||
" {\"start\": [0, 1, 0, 1, 1], \"poly\": id2bit([5, 2, 0]), \"clock\": 2},\n",
|
||||
" {\"start\": [1, 0, 0, 1, 0], \"poly\": id2bit([5, 4, 3, 1, 0]), \"clock\": 3},\n",
|
||||
" {\"start\": [0, 1, 1, 0, 0], \"poly\": id2bit([5, 4, 2, 1, 0]), \"clock\": 2},\n",
|
||||
"]\n",
|
||||
"gen_bit_stream(data, target_size=1 * 1024**2, file_path=\"mine_gen_100MB.txt\")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "80acd699-63bc-4391-ac05-8166a843b1ca",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "01038d4c-ab7f-486c-b300-a95187f4cd76",
|
||||
"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
|
||||
}
|
1
cryptography/mine_gen_100MB.txt
Normal file
1
cryptography/mine_gen_100MB.txt
Normal file
File diff suppressed because one or more lines are too long
344
cryptography/playfire.ipynb
Normal file
344
cryptography/playfire.ipynb
Normal file
|
@ -0,0 +1,344 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "f06af5bc",
|
||||
"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": "code",
|
||||
"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",
|
||||
" keyy.append(i)\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",
|
||||
" mtrx = []\n",
|
||||
" idx = 0\n",
|
||||
" for i in range(6):\n",
|
||||
" t1 = xx[idx : idx + 6]\n",
|
||||
" 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",
|
||||
" 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",
|
||||
" 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 pairs:\n",
|
||||
" idxs = self.find_idx(i)\n",
|
||||
" if idxs[0][0] == idxs[1][0]:\n",
|
||||
" en_m = (\n",
|
||||
" self.key_matrix[idxs[0][0]][idxs[0][1] + 1]\n",
|
||||
" + self.key_matrix[idxs[0][0]][idxs[1][1] + 1]\n",
|
||||
" )\n",
|
||||
" elif idxs[0][1] == idxs[1][1]:\n",
|
||||
" en_m = (\n",
|
||||
" self.key_matrix[idxs[0][0] + 1][idxs[0][1]]\n",
|
||||
" + self.key_matrix[idxs[1][0] + 1][idxs[1][1]]\n",
|
||||
" )\n",
|
||||
" else:\n",
|
||||
" en_m = (\n",
|
||||
" self.key_matrix[idxs[0][0]][idxs[1][1]]\n",
|
||||
" + self.key_matrix[idxs[1][0]][idxs[0][1]]\n",
|
||||
" )\n",
|
||||
" en_msg += en_m\n",
|
||||
" 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",
|
||||
" pairs = []\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 = (\n",
|
||||
" self.key_matrix[idxs[0][0]][idxs[0][1] - 1]\n",
|
||||
" + self.key_matrix[idxs[0][0]][idxs[1][1] - 1]\n",
|
||||
" )\n",
|
||||
" elif idxs[0][1] == idxs[1][1]:\n",
|
||||
" en_m = (\n",
|
||||
" self.key_matrix[idxs[0][0] - 1][idxs[0][1]]\n",
|
||||
" + self.key_matrix[idxs[1][0] - 1][idxs[1][1]]\n",
|
||||
" )\n",
|
||||
" else:\n",
|
||||
" en_m = (\n",
|
||||
" self.key_matrix[idxs[0][0]][idxs[1][1]]\n",
|
||||
" + self.key_matrix[idxs[1][0]][idxs[0][1]]\n",
|
||||
" )\n",
|
||||
" en_msg += en_m\n",
|
||||
" return en_msg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "4b861600",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[['m', 'o', 'n', 'a', 'r', 'c'],\n",
|
||||
" ['h', 'y', '1', '2', '3', 'b'],\n",
|
||||
" ['d', 'e', 'f', 'g', 'i', 'j'],\n",
|
||||
" ['k', 'l', 'p', 'q', 's', 't'],\n",
|
||||
" ['u', 'v', 'w', 'x', 'z', '0'],\n",
|
||||
" ['4', '5', '6', '7', '8', '9']]"
|
||||
]
|
||||
},
|
||||
"execution_count": 11,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"pf = PlayFire(key=\"monarchy123\")\n",
|
||||
"pf.key_matrix"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"id": "7c4e1caa",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'ydppny3b7u'"
|
||||
]
|
||||
},
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"msg = \"hello1234\"\n",
|
||||
"enc = pf.encrypt(msg)\n",
|
||||
"enc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"id": "48c8a847",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'hello1234x'"
|
||||
]
|
||||
},
|
||||
"execution_count": 13,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"pf.decrypt(enc)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"id": "62806ee1",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'thismy1stdayofcollegeilearntabouteverythingandmetmyfriends'"
|
||||
]
|
||||
},
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"pf.decrypt(pf.encrypt(\"thismy1stdayofcollegeilearntabouteverythingandmetmyfriends\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"id": "a7a9907b",
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"'rx'"
|
||||
]
|
||||
},
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"pf.decrypt(pf.encrypt(\"r\"))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "6fe9dad9",
|
||||
"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
|
||||
}
|
Loading…
Reference in New Issue
Block a user