{ "metadata": { "name": "recitation4" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# CS1001.py\n", "\n", "## Extended Introduction to Computer Science with Python, Tel-Aviv University, Spring 2013\n", "\n", "# Recitation 4 - 4-8.4.2013\n", "\n", "## Last update: 4.4.2013" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Reminder - `Big O` notation\n", "Let $f(x)$ and $g(x)$ be two function. Then \n", "$$\n", "f(x) = O(g(x)) \\; as \\; x \\to \\infty \n", "$$\n", "If and only if there exist $M \\ge 0 \\;$ and $x_{0}\\in \\mathbb{R}$ such that\n", "$$\n", "|f(x)| \\le M|g(x)| \\; \\forall x>x_{0}\n", "$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Time complexity hierarchy\n", "\n", "The most common time complexities we encounter are (*c > 1* is a real constant, *n >1 * is the size of the input):\n", "\n", "* Constant - $O(1)$\n", "* Logarithmic - $O(log(n))$\n", "* Root/fractional - $O(n^{1/c})$\n", "* Linear - $O(n)$\n", "* Loglinear - $O(n log(n))$\n", "* Polynomial - $O(n^{c})$\n", "* Exponential - $O(c^{n})$\n", "* Factorial - $O(n!)$\n", "\n", "See also this list on [Wikipedia](http://en.wikipedia.org/wiki/Time_complexity#Table_of_common_time_complexities).\n", "\n", "## Size of the input\n", "\n", "* For a numerical input (factorization, prime numbers) the size of the input is the number of bits of the numerical input\n", "* For a list/vector input, the size is the number of elements\n", "* For a matrix?\n", "\n", "## Examples\n", "\n", "### Constant, Linear, Loglinear, Polynomial" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from math import log\n", "\n", "domain = range(1,100)\n", "const = [10 for x in domain]\n", "lin = [x for x in domain]\n", "loglin = [x * log(x) for x in domain]\n", "poly = [x ** 2 for x in domain]\n", "\n", "# these lines are the plotting directives\n", "fig = figure(figsize=(16,6))\n", "ax = subplot(1,3,1)\n", "ax.plot(domain,const)\n", "ax.plot(domain,lin)\n", "ax.legend([\"const\",\"lin\"],loc=2);\n", "ax = subplot(1,3,2)\n", "ax.plot(domain,lin)\n", "ax.plot(domain,loglin)\n", "ax.legend([\"lin\",\"loglin\"],loc=2);\n", "ax = subplot(1,3,3)\n", "ax.plot(domain,loglin)\n", "ax.plot(domain,poly)\n", "ax.legend([\"loglin\",\"poly\"],loc=2);" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "png": "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\nc7bUICsrC/3794e3tzf69u0LQPdJwe3btwEAt27dQrVq1URGzJcjR45g+/btqFevHgYPHoygoCB4\ne3urdkz29vawt7dHu3btAACenp44duwY7OzsVDkeAIiJiUGHDh1QuXJlWFlZwcPDA+Hh4aoeE5D7\n35sXa8WNGzdQs2ZNIRkLgrXONLHWmT5Zax0gZ72TpdYBctU72WodIF+9Y63LW60zWpMqwzlbiqJg\n1KhRcHR0xIQJE56+7u7ujhUrVgAAVqxY8bTAqcGMGTMQHx+Pq1evYv369XB1dcWqVatUOyY7OzvU\nqlULFy5cAAAEBgaiWbNm6N27tyrHAwBNmjRBREQE0tPToSgKAgMD4ejoqOoxAbn/vXF3d8f69euR\nmZmJq1ev4uLFi2jfvr3IqPnCWmeaWOtMn6y1DpCz3slQ6wD56p1stQ6Qr96x1uWx1hnu1tnX2717\nt9KoUSOlQYMGyowZM4z51gZx8OBBxcLCQmnZsqXSqlUrpVWrVsqePXuU+/fvK25uboqDg4PSrVs3\n5cGDB6KjFkhISIjSu3dvRVEUVY/p+PHjStu2bZUWLVoo/fr1U5KTk1U9HkVRlNmzZyuOjo6Kk5OT\nMmzYMCUzM1NVY/Ly8lKqV6+uFC9eXLG3t1eWL1/+yvw//vij0qBBA6Vx48ZKQECAwOQFw1pn2ljr\nTJfaa52imFe9U3utUxS5650stU5R5Kt3rHWvr3UWipLLgnUiIiIiIiIiIzPacl8iIiIiIiKi12GT\nSkRERERERCaDTSoRERERERGZDDapREREREREZDLYpBIREREREZHJYJNKREREREREJuP/AeAtgiCH\nJjDWAAAAAElFTkSuQmCC\n" } ], "prompt_number": 35 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercises\n", "### Transitivity\n", "\n", "If\n", "$\n", "f(n)=O(g(n))\\;\n", "$\n", "and \n", "$ \n", "g(n) = O(h(n))\\;\n", "$\n", "then\n", "$\n", "f = O(h(n))\\;\n", "$\n", "? \n", "\n", "### Symmetry\n", "\n", "If $f=O(g)\\;$ then $g=O(f)$? Or $g \\ne O(f)$?\n", "\n", "\n", "### Series Loops\n", "\n", "Let $f_1 = O(g_1)\\;$ and $f_2=O(g_2)$.\n", "\n", "Show that $f_1 + f_2 = O(g_1 + g_2)$.\n", "\n", "This relates to two consecutive loops:\n", "\n", "\n", " for i in range(len(list1)):\n", " print i\n", " for i in range(len(list2)):\n", " print i\n", "\n", "### Parallel Loops\n", "\n", "Show that $f_1 \\cdot f_2 = O(g_1 \\cdot g_2)$.\n", "\n", "This relates to independent nested loops:\n", "\n", " for i in range(len(list1)):\n", " print i\n", " for j in range(len(list2)):\n", " print j\n", "### Maximum\n", "\n", "Show that $f_1 + f_2 + ... + f_k = O(f_{max})$. That is, in a finite constant sum of functions, the dominate function defines the growth rate.\n", "\n", "A private case is that of a polynomial.\n", "\n", "### Dependent nested loops\n", "\n", "For exmaple,\n", "\n", " for i in range(len(list1)):\n", " for j in range(i):\n", " print i, j\n", "\n", "Prove:\n", "\n", "* $\\sum_{i=1}^{n}{i} = O(n^2)$ - the arithmetic series\n", "* $\\sum_{i=1}^{n}{2^i} = O(2^n)$ - the geometric series" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Primality testing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### [Fermat's little theorem](http://en.wikipedia.org/wiki/Fermat's_little_theorem)\n", "\n", "If $p$ is a prime $a$ is a natural number such that $1\\le a < p\\;$, then $a^{p-1} = 1 \\; (mod \\; p)$.\n", "\n", "### Probabilistic test with Fermat's little theorem\n", "\n", "We can use this to create a primality test for *p*." ] }, { "cell_type": "code", "collapsed": false, "input": [ "from random import randrange\n", "def is_prime(p):\n", " \"\"\"probabilistic test for p's compositeness\"\"\"\n", " for i in range(100):\n", " a = randrange(1, p - 1) # a is a random integer in [1..p-1]\n", " if pow(a, p - 1, p) != 1: # this takes O(n^3) = O((log2 p)^3)\n", " return False\n", " return True # we get here if no compositeness witness was found" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 39 }, { "cell_type": "code", "collapsed": false, "input": [ "is_prime(11)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 4, "text": [ "True" ] } ], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "is_prime(190125101)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 5, "text": [ "True" ] } ], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Notes\n", "\n", "* `pow(a,b,c)` is equivalent to $a^b \\; mod \\; c$, only it is more efficient by use of *iterated squaring*. \n", "* The *False Positive* rate - the probablity the function returns `True` when it should return `False` - is less than $0.25^{100}$ (Miller-Rabin)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Testing the prime number theorem\n", "\n", "\n", "#### The theorem\n", "Define by $\\pi(x)$ the number of prime numbersless than or equal to $x$. Then the [prime number theorem](http://en.wikipedia.org/wiki/Prime_number_theorem) states that \n", "\n", "$$\n", "\\pi(x) \\thicksim \\frac{x}{log(x)}\n", "$$\n", "\n", "for large $x$.\n", "\n", "Now, assuming the primes are uniformaly distributed, the probability that a randomly sampled number between $1$ and $x$ is prime is $\\frac{\\pi(x)}{x} \\thicksim \\frac{1}{log(x)}$.\n", "\n", "Since the number of bits in $x$, $n$, is $O(log(x))\\;$ this translates to $O(1/n)$.\n", "\n", "Now, the probability that a number with exactly $n$ bits is prime is roughly half of the probability that a number of $n$ or less bits is prime, and this doesn't change the order of magnitude, and we can say that\n", "> A number with *n* bits is prime with a probability of $O(1/n)$.\n", "\n", "We'd like to check this, but for large *n* there are too many ($2^{n-1}$) numbers to check. So we will use *sampling*." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def prob_prime(n):\n", " \"\"\"evaluate the probability of an n-bit long integer to be prime\"\"\"\n", " count = 0\n", " sample_size = 10 ** 5\n", " for i in range(sample_size):\n", " p = randrange(2 ** (n - 1), 2 ** n - 1)\n", " count += is_prime(p)\n", " return count / sample_size" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 34 }, { "cell_type": "code", "collapsed": false, "input": [ "prob_prime(20)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 36, "text": [ "0.07423" ] } ], "prompt_number": 36 }, { "cell_type": "code", "collapsed": false, "input": [ "1 / 20" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 37, "text": [ "0.05" ] } ], "prompt_number": 37 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The relative error is therefore small:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "(0.07423 - 0.05) / 0.05" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 40, "text": [ "0.48460000000000003" ] } ], "prompt_number": 40 }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Diffie-Hellman\n", "\n", "A Khan Academy video that illustrates the Diffie-Hellman key exchange:\n", "\n", "\n", "\n", "See the paper [New directions in cryptography](http://www.cs.tau.ac.il/~bchor/diffie-hellman.pdf)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is the protocol:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def DH_exchange(p):\n", " \"\"\" generates a shared DH key \"\"\"\n", " g = randrange(1,p-1)\n", " a = randrange(1,p-1) # Alice's secret\n", " b = randrange(1,p-1) # Bob's secret\n", " x = pow(g,a,p) \n", " y = pow(g,b,p)\n", " key_A = pow(y,a,p)\n", " key_B = pow(x,b,p)\n", " return g, a, b, x, y, key_A, key_B" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 20 }, { "cell_type": "code", "collapsed": false, "input": [ "DH_exchange(190125101)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 44, "text": [ "(130721310, 61963609, 1775050, 132736567, 143446917, 74182194, 74182194)" ] } ], "prompt_number": 44 }, { "cell_type": "code", "collapsed": false, "input": [ "DH_exchange(833648000993161193752610727299)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 45, "text": [ "(225405422835827732918401478004,\n", " 153883981994400043514132897779,\n", " 556710940458985113442266962618,\n", " 620358857758647613746179753310,\n", " 479744267228387852844588852918,\n", " 610421506532174772126394293202,\n", " 610421506532174772126394293202)" ] } ], "prompt_number": 45 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's try and break it:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def crack_DH(p, g, x):\n", " \"\"\"find secret \"a\" that satisfies g**a%p == x\n", " Not feasible for large p\"\"\"\n", " for a in range(1,p-1):\n", " if a % 100000 == 0: \n", " print(\"Iteration\",a) # progress bar\n", " if pow(g,a,p) == x:\n", " return a\n", " return None" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 19 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that because `pow(a,b,c)` is not [injective](http://en.wikipedia.org/wiki/Injective_function) (in contrast to what might have been said in class...) this may return the wrong answer.\n", "\n", "To test the protocol, we first need a function that finds primes:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def find_prime(n):\n", " \"\"\" find random n-bit long prime (no leading zeros: 2**(n-1)<= N < 2**n )\"\"\"\n", " while True: #here we're optimistic, but actually we have a good reason to be:\n", " # after O(1/n) iterations we expect to find a prime and halt\n", " candidate = randrange(2**(n - 1), 2**n)\n", " if is_prime(candidate):\n", " return candidate" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 14 }, { "cell_type": "code", "collapsed": false, "input": [ "find_prime(10)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 15, "text": [ "991" ] } ], "prompt_number": 15 }, { "cell_type": "code", "collapsed": false, "input": [ "find_prime(100)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 16, "text": [ "1115065337204017303367921856997" ] } ], "prompt_number": 16 }, { "cell_type": "code", "collapsed": false, "input": [ "find_prime(256)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 17, "text": [ "59817822415413480116679649593332822338590599807236481764232916509620304609287" ] } ], "prompt_number": 17 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now run the DH protocol and try to break it.\n", "\n", "We will start with a 10-bit prime:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from math import log\n", "p = find_prime(10)\n", "print(p,log(p,2))\n", "g,a,b,x,y,key_A,key_B = DH_exchange(p)\n", "print('g',g,'a',a,'b',b,'x',x,'y',y,'key_A',key_A,'key_B',key_B)\n", "print('a',crack_DH(p,g,x))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "971 9.923327485419193\n", "g 813 a 150 b 234 x 371 y 196 key_A 939 key_B 939\n", "a 150\n" ] } ], "prompt_number": 27 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Running with a 16-bit prime:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "p = find_prime(16)\n", "print(p,log(p,2))\n", "g,a,b,x,y,key_A,key_B = DH_exchange(p)\n", "print('g',g,'a',a,'b',b,'x',x,'y',y,'key_A',key_A,'key_B',key_B)\n", "print('a',crack_DH(p,g,x))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "47809 15.54499460932774\n", "g 42852 a 42613 b 27757 x 26351 y 21063 key_A 21555 key_B 21555\n", "a 117\n" ] } ], "prompt_number": 28 }, { "cell_type": "code", "collapsed": false, "input": [ "p = find_prime(128)\n", "print(p,log(p,2))\n", "g,a,b,x,y,key_A,key_B = DH_exchange(p)\n", "print('g',g,'a',a,'b',b,'x',x,'y',y,'key_A',key_A,'key_B',key_B)\n", "print('a',crack_DH(p,g,x))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "232058770554614453837871524801758451143 127.44775783025453\n", "g 159913793420381443650379750802964420717 a 116795875092692988667366016317257384027 b 173352797834467896747096128107523563976 x 224894493378616747082831720370075484037 y 202527828205657594721613336077418916066 key_A 6312501138165008035876819356018294783 key_B 6312501138165008035876819356018294783\n", "Iteration" ] }, { "output_type": "stream", "stream": "stdout", "text": [ " 100000\n", "Iteration" ] }, { "output_type": "stream", "stream": "stdout", "text": [ " 200000\n", "Iteration" ] }, { "output_type": "stream", "stream": "stdout", "text": [ " 300000\n", "Iteration" ] }, { "output_type": "stream", "stream": "stdout", "text": [ " 400000\n", "Iteration" ] }, { "output_type": "stream", "stream": "stdout", "text": [ " 500000\n", "Iteration" ] } ], "prompt_number": "*" }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fin\n", "This notebook is part of the [Extended introduction to computer science](http://tau-cs1001-py.wikidot.com/) course at Tel-Aviv University.\n", "\n", "The notebook was written using Python 3.2 and IPython 0.13.1.\n", "\n", "The code is available at .\n", "\n", "The notebook can be viewed online at .\n", "\n", "This work is licensed under a [Creative Commons Attribution-ShareAlike 3.0 Unported License](http://creativecommons.org/licenses/by-sa/3.0/)." ] } ], "metadata": {} } ] }