Add square and multiply

This commit is contained in:
Johannes Røsvik 2020-05-24 12:33:00 +02:00
parent da33a814e6
commit 3b934c43c2
No known key found for this signature in database
GPG Key ID: 8A47E30339E13FFD
1 changed files with 106 additions and 46 deletions

View File

@ -10,7 +10,7 @@
},
{
"cell_type": "code",
"execution_count": 14,
"execution_count": 1,
"metadata": {},
"outputs": [
{
@ -19,7 +19,7 @@
"5"
]
},
"execution_count": 14,
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
@ -46,7 +46,7 @@
},
{
"cell_type": "code",
"execution_count": 17,
"execution_count": 2,
"metadata": {},
"outputs": [
{
@ -92,7 +92,7 @@
},
{
"cell_type": "code",
"execution_count": 16,
"execution_count": 3,
"metadata": {},
"outputs": [
{
@ -340,8 +340,8 @@
"A generator of $Z_p^$ is an element of order $p 1$\n",
"\n",
"To find a generator of $Z_p^$ we can choose a value g and test it as follows:\n",
"1. compute all the distinct prime factors of $p 1$ and call them $f_1, f_2, ..., f_r$\n",
"2. then $g$ is a generator as long as $g^{\\frac{p1}{f_i}} \\neq 1 \\mod(p)$ for $i = 1,2,,...,r$"
"1. Compute all the distinct prime factors of $p 1$ and call them $f_1, f_2, ..., f_r$\n",
"2. Then $g$ is a generator as long as $g^{\\frac{p1}{f_i}} \\neq 1 \\mod(p)$ for $i = 1,2,,...,r$"
]
},
{
@ -547,7 +547,26 @@
"Sources:\n",
"- https://stackoverflow.com/a/1832648/5976426\n",
"- https://en.wikipedia.org/wiki/Baby-step_giant-step\n",
"- https://gist.github.com/0xTowel/b4e7233fc86d8bb49698e4f1318a5a73"
"- https://gist.github.com/0xTowel/b4e7233fc86d8bb49698e4f1318a5a73\n",
"\n",
"### Square and multiply\n",
"\n",
"Used to simplify doing large exponentiations. Instead of solving $3^5$ as $3*3*3*3*3$, \n",
"\n",
"1. Convert the exponent to Binary.\n",
"2. For the first $1$, simply list the number\n",
"3. For each ensuing $0$, do Square operation\n",
"4. For each ensuing $1$, do Square and Multiply operations\n",
"\n",
"Example:\n",
"```\n",
"5 = 101 in Binary\n",
"1 First One lists Number 3\n",
"0 Zero calls for Square (3)²\n",
"1 One calls for Square + Multiply ((3)²)²*3\n",
"```\n",
"\n",
"https://www.practicalnetworking.net/stand-alone/square-and-multiply/\n"
]
},
{
@ -559,8 +578,74 @@
"name": "stdout",
"output_type": "stream",
"text": [
"x = 2570\n",
"y = g^x mod p ==> 34 = 7324^2570 mod 4363\n",
"7894352216^(1) * 7894352216^(2) * 7894352216^(16) * 7894352216^(64) * 7894352216^(1024) * 7894352216^(8192) * 7894352216^(131072) * 7894352216^(2097152) * 7894352216^(33554432) * 7894352216^(67108864)\n",
"squarings: 26\n",
"mults: 9\n",
"\n",
"z = 7894352216^102900819 mod(604604729)\n",
"z = 355407489\n",
"\n",
"7894352216^102900819 mod(604604729) = 355407489\n"
]
}
],
"source": [
"# Square and multiply\n",
"from math import log, floor\n",
"\n",
"def square_and_multiply(y,e,n, verbose=True):\n",
" # prep\n",
" e_bin = bin(e)[:1:-1] # e0, e1, e2, e3, ... , ek\n",
" k = len(e_bin)\n",
" z = 1\n",
" yi = y\n",
" indices = []\n",
" # -------------\n",
"\n",
" for i in range(k):\n",
" ei = int(e_bin[i])\n",
" if ei == 1:\n",
" z = z*yi % n\n",
" if ei < k:\n",
" yi = yi*yi % n\n",
" if ei:\n",
" indices.append(i)\n",
"\n",
" # post calc\n",
" mults = str(e_bin).count(\"1\") - 1\n",
" squarings = floor( log(e, 2) )\n",
" # -------------\n",
"\n",
" if verbose:\n",
" print(f\"{' * '.join([f'{y}^({2**i})' for i in indices])}\")\n",
" print(f\"squarings: {squarings}\")\n",
" print(f\"mults: {mults}\")\n",
" print()\n",
" print(f\"z = {y}^{e} mod({n})\")\n",
" print(f\"z = {z}\\n\")\n",
" return z\n",
"\n",
"# y^e mod(n)\n",
"y = 7894352216\n",
"e = 102900819\n",
"n = 604604729\n",
"\n",
"z = square_and_multiply(y,e,n, True)\n",
"\n",
"print(f\"{y}^{e} mod({n}) = {z}\")"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"x = 102900819\n",
"y = g^x mod p ==> 355407489 = 7894352216^102900819 mod 604604729\n",
"Test: True\n"
]
}
@ -591,16 +676,18 @@
" return None\n",
"\n",
"def disc_log_test(y, g, x, p):\n",
" return y == (g**x) % p\n",
" #return y == (g**x) % p\n",
" return y == square_and_multiply(g,x,p,False)\n",
"\n",
"#y = 355407489\n",
"#g = 7894352216\n",
"#p = 604604729 # Must be prime\n",
"\n",
"# y = g^x mod p\n",
"y = 34\n",
"g = 7324\n",
"p = 4363 # Must be prime\n",
"y = 355407489\n",
"g = 7894352216\n",
"p = 604604729 # Must be prime\n",
"\n",
"#y = 34\n",
"#g = 7324\n",
"#p = 4363 # Must be prime\n",
"\n",
"x = bsgs(g, y, p)\n",
"\n",
@ -608,8 +695,7 @@
"\n",
"print(f\"y = g^x mod p ==> {y} = {g}^{x} mod {p}\")\n",
"\n",
"# Don't run the test with big numbers!\n",
"if x<10000: print(f\"Test: {disc_log_test(y,g,x,p)}\")"
"print(f\"Test: {disc_log_test(y,g,x,p)}\")"
]
},
{
@ -624,34 +710,8 @@
"- `C`: Ciphertext block (length n bits) \n",
"- `K` : Key (length k bits)\n",
"- `C = E(P, K)`: Encryption function \n",
"- `P = D(C, K)`: Decryption function"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n",
"54\n"
]
}
],
"source": [
"# Discarded code\n",
"\n",
"def z(n):\n",
" return [i for i in range(n)]\n",
"print(z(10))\n",
"\n",
"n = 81\n",
"zn = z(n)\n",
"rel_primes = list(filter(lambda x: is_relative_prime(x,n), zn))\n",
"print(len(rel_primes))"
"- `P = D(C, K)`: Decryption function\n",
"- `IV`: Initialisation vector"
]
}
],