{ "cells": [ { "cell_type": "code", "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2021-04-18T10:42:36.285247Z", "start_time": "2021-04-18T10:42:36.267236Z" } }, "outputs": [], "source": [ "from Crypto.Util.number import inverse, GCD, isPrime, getPrime" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Prerequisites" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Number theory basics" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Theory" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- https://en.wikipedia.org/wiki/Primality_test" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Probabilistic primality tests" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- methods by which arbitrary positive integers are tested to provide **partial information** regarding their primality. \n", "\n", "How do they work?\n", "For each odd positive integern,a set $W(n)⊂\\mathbb{Z}_n$ is defined such that the following properties hold:\n", "1. given $a∈\\mathbb{Z}_n$, it can be checked in deterministic polynomial time whether $a∈W(n)$;\n", "2. if $n$ is prime, then $W(n)=∅$(the empty set)\n", "3. if $n$ is composite, then $|W(n)|≥\\dfrac n 2$.\n", "\n", "**Def**\n", "- If $n$ is composite, the elements of $W(n)$are called **witnesses** to the compositeness of $n$, and the elements of the complementary set $L(n)=\\mathbb{Z}_n−W(n)$ are called **liars**\n", "\n", "**Framework**:\n", "- Choose a random $a\\in \\mathbb{Z}_n$\n", "- Check if $a \\in W(n)$\n", "- If $a \\in W(n)$\n", " - return composite (the test is failed with respect to base $a$ => $n$ is **certain** to be composite\n", "- Else\n", " - return prime (the test is passed with respect to base $a$) => no conclusion can be drawn => $n$ is **probably prime**\n", " \n", "**Remark**:\n", "- The more tests if passes the higher the probability our probable prime has to be prime\n", "- We trade computing time for a better approximation of our probable prime" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fermat's test" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- https://en.wikipedia.org/wiki/Fermat_primality_test" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Fermat's theorem**:\n", "- Let $p$ be a prime number and $a$ be an integer not divisible by $p$. Then $a^{p-1} - 1$ is always divisible by $p$, or $a^{p-1} \\equiv 1 \\pmod{p}$\n", "\n", "**Idea**: \n", "- Use the converse :\n", " - if for some $a$ not divisible by $n$ we have $a^{n-1} \\not\\equiv 1 \\pmod{n}$, then $n$ is definitely composite\n", " \n", "**Algorithm**: \n", "- input $n>3$,the number to be tested and $k$, the number of tests / a bound\n", "- Repeat k times:\n", " - Pick a random $a \\in \\{2, n-2\\}$\n", " - if $a^{n-1} \\not\\equiv 1 \\bmod n$\n", " - return composite\n", " - else\n", " - continue\n", "- if no composite is returned then return probably prime\n", " " ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "ExecuteTime": { "end_time": "2021-04-18T10:42:38.831898Z", "start_time": "2021-04-18T10:42:38.811882Z" } }, "outputs": [], "source": [ "import random\n", "\n", "def fermat_test(n, k):\n", " for i in range(k):\n", " a = random.randint(2, n-2)\n", " #print(a)\n", " if GCD(a, n)!=1: ##Remark this should return COMPOSITE (since you found a divisor !=1) but to show the flaw we did it this way\n", " i-=1\n", " continue\n", " if pow(a, n-1, n) != 1:\n", " return 'Composite'\n", " return 'Probably prime'" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "ExecuteTime": { "end_time": "2021-04-18T10:42:39.116928Z", "start_time": "2021-04-18T10:42:38.964928Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Composite\n", "Probably prime\n" ] } ], "source": [ "print(fermat_test(2403, 12))\n", "p = getPrime(512)\n", "print(fermat_test(p, 100))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Flaw" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Carmichael numbers pass the test yet they aren't prime:\n", "- Let $n$ be a Carmichael number, then $a^{n-1} \\equiv 1 \\bmod n$ for **all** $a$ with $\\gcd(a,n) =1$\n", "- Therefore the search for composite is the same as a search for its factors\n" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "ExecuteTime": { "end_time": "2021-04-18T10:44:20.180541Z", "start_time": "2021-04-18T10:44:20.171544Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "561 is Probably prime but 561 % 3 = 0\n", "41041 is Probably prime but 41041 % 11 = 0\n" ] } ], "source": [ "print(f\"561 is {fermat_test(561, 100)} but 561 % 3 = {561 % 3}\")\n", "print(f\"41041 is {fermat_test(41041, 100)} but 41041 % 11 = {41041 % 11}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Resources" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- https://www.youtube.com/watch?v=oUMotDWVLpw\n", "- https://www.youtube.com/watch?v=jbiaz_aHHUQ" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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.9.4" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 2 }