└── SIS.ipynb /SIS.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Collosion and quantum-resistant lattice hasher with accumulating properties" 8 | ] 9 | }, 10 | { 11 | "cell_type": "markdown", 12 | "metadata": {}, 13 | "source": [ 14 | "## Shortest integer solution problem:\n", 15 | "Given an integer `q`, a `k-times-m` matrix `M` picked uniformly at random (where `m >= k`) and a real `β`, find an integer vector `z`\n", 16 | "such that `M*z = 0 mod q` and `||z|| <= β`" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "Security parameter `k` and bound `n = poly(k)`" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 20, 29 | "metadata": {}, 30 | "outputs": [], 31 | "source": [ 32 | "k = 128\n", 33 | "n = k^8\n", 34 | "\n", 35 | "lmb = 1 # need to be > 0" 36 | ] 37 | }, 38 | { 39 | "cell_type": "markdown", 40 | "metadata": {}, 41 | "source": [ 42 | "parameter `q, mu, beta` for SIS problem" 43 | ] 44 | }, 45 | { 46 | "cell_type": "code", 47 | "execution_count": 21, 48 | "metadata": {}, 49 | "outputs": [ 50 | { 51 | "name": "stdout", 52 | "output_type": "stream", 53 | "text": [ 54 | "True\n", 55 | "q: 1244142437461793964053\n", 56 | "mu: 18176\n", 57 | "beta: 9.71468927453313e18\n", 58 | "m: 9088\n" 59 | ] 60 | } 61 | ], 62 | "source": [ 63 | "q = var('q')\n", 64 | "#assume(q>n)\n", 65 | "s = find_root(q/sqrt(log(q,2)+1) == sqrt(2)*n*k^(1/2 + lmb), 1, n^2)\n", 66 | "q = next_prime(s)\n", 67 | "RR(q/sqrt(ceil(log(q,2)))) >= RR(sqrt(2)*n*k^(1/2 + lmb))\n", 68 | "print(bool(q/sqrt(ceil(log(q,2))) >= sqrt(2)*n*k^(1/2 + lmb)))\n", 69 | "mu = ZZ(2*k*ceil(log(q,2)))\n", 70 | "beta = RR(n*sqrt(mu))\n", 71 | "m = ZZ(mu/2)\n", 72 | "G = GF(q)\n", 73 | "#print(\"Solution: \" + str(s))\n", 74 | "print(\"q: \" + str(q))\n", 75 | "print(\"mu: \" + str(mu))\n", 76 | "print(\"beta: \" + str(beta))\n", 77 | "print(\"m: \" + str(m))" 78 | ] 79 | }, 80 | { 81 | "cell_type": "markdown", 82 | "metadata": {}, 83 | "source": [ 84 | "Left and right matrices, uniform random from G" 85 | ] 86 | }, 87 | { 88 | "cell_type": "code", 89 | "execution_count": 22, 90 | "metadata": {}, 91 | "outputs": [ 92 | { 93 | "name": "stdout", 94 | "output_type": "stream", 95 | "text": [ 96 | "done\n" 97 | ] 98 | } 99 | ], 100 | "source": [ 101 | "L = matrix([[G.random_element() for i in range(0, m)] for j in range(0,k)])\n", 102 | "#outf = open(\"/tmp/matrix\", \"w\")\n", 103 | "#outf.write(str(L))\n", 104 | "#outf.close()\n", 105 | "print(\"done\")" 106 | ] 107 | }, 108 | { 109 | "cell_type": "markdown", 110 | "metadata": {}, 111 | "source": [ 112 | "Initial hash function" 113 | ] 114 | }, 115 | { 116 | "cell_type": "code", 117 | "execution_count": 23, 118 | "metadata": {}, 119 | "outputs": [], 120 | "source": [ 121 | "def hash(x):\n", 122 | " return (L*x) % q" 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": 24, 128 | "metadata": {}, 129 | "outputs": [], 130 | "source": [ 131 | "xvec = vector([G.random_element() for i in range(0, m)])\n", 132 | "Zp_result = hash(xvec)" 133 | ] 134 | }, 135 | { 136 | "cell_type": "markdown", 137 | "metadata": {}, 138 | "source": [ 139 | "Because the range and domain of the current scheme differs, we need to transform our hashes back to G to keep algebraic structures and achieve accumulating properties" 140 | ] 141 | }, 142 | { 143 | "cell_type": "code", 144 | "execution_count": 25, 145 | "metadata": {}, 146 | "outputs": [], 147 | "source": [ 148 | "def transform(x):\n", 149 | " return G(int(''.join([bin(i) for i in x]).replace(\"0b\",\"\"),2))" 150 | ] 151 | }, 152 | { 153 | "cell_type": "code", 154 | "execution_count": 28, 155 | "metadata": {}, 156 | "outputs": [ 157 | { 158 | "data": { 159 | "text/plain": [ 160 | "815150217032424563520" 161 | ] 162 | }, 163 | "execution_count": 28, 164 | "metadata": {}, 165 | "output_type": "execute_result" 166 | } 167 | ], 168 | "source": [ 169 | "transform(Zp_result)\n" 170 | ] 171 | }, 172 | { 173 | "cell_type": "markdown", 174 | "metadata": {}, 175 | "source": [ 176 | "The final hasher procudes a `ceil(log2(q))+1` size output from an input at most `m` size:" 177 | ] 178 | }, 179 | { 180 | "cell_type": "code", 181 | "execution_count": 29, 182 | "metadata": {}, 183 | "outputs": [], 184 | "source": [ 185 | "def hash(x):\n", 186 | " t = (L*x) % q\n", 187 | " return transform(t)\n", 188 | " " 189 | ] 190 | }, 191 | { 192 | "cell_type": "code", 193 | "execution_count": 30, 194 | "metadata": {}, 195 | "outputs": [ 196 | { 197 | "name": "stdout", 198 | "output_type": "stream", 199 | "text": [ 200 | "reference sha: 240dfd9fe93b9520c273\n", 201 | "our hash: 1f8187eedd60a03e93\n" 202 | ] 203 | } 204 | ], 205 | "source": [ 206 | "import hashlib\n", 207 | "sha = hashlib.sha1()\n", 208 | "xvec = random_vector(G, m)\n", 209 | "sha.update(str(xvec))\n", 210 | "print(\"reference sha: \" + sha.hexdigest()[0:20])\n", 211 | "print(\"our hash: \" + hex(ZZ(hash(xvec))))" 212 | ] 213 | }, 214 | { 215 | "cell_type": "markdown", 216 | "metadata": {}, 217 | "source": [ 218 | "We want to prove that an element belongs to our 50-long array" 219 | ] 220 | }, 221 | { 222 | "cell_type": "code", 223 | "execution_count": 59, 224 | "metadata": {}, 225 | "outputs": [], 226 | "source": [ 227 | "import hashlib\n", 228 | "test_data = [random_vector(G, m) for i in range(0, 5)]\n", 229 | "target_element = test_data[2]\n", 230 | "#print(target_element)" 231 | ] 232 | }, 233 | { 234 | "cell_type": "code", 235 | "execution_count": 60, 236 | "metadata": {}, 237 | "outputs": [], 238 | "source": [ 239 | "acc = vector(G, [0 for i in range(0, 128)])\n", 240 | "for i in test_data:\n", 241 | " acc += L*i " 242 | ] 243 | }, 244 | { 245 | "cell_type": "code", 246 | "execution_count": 61, 247 | "metadata": {}, 248 | "outputs": [], 249 | "source": [ 250 | "witness = acc + L*(target_element*-1) # we revoke our selected member from the accumulator in constant time!" 251 | ] 252 | }, 253 | { 254 | "cell_type": "code", 255 | "execution_count": 62, 256 | "metadata": {}, 257 | "outputs": [ 258 | { 259 | "data": { 260 | "text/plain": [ 261 | "True" 262 | ] 263 | }, 264 | "execution_count": 62, 265 | "metadata": {}, 266 | "output_type": "execute_result" 267 | } 268 | ], 269 | "source": [ 270 | "witness + L*(target_element) == acc # checking simply works by accumulating the member to our wittness" 271 | ] 272 | }, 273 | { 274 | "cell_type": "code", 275 | "execution_count": null, 276 | "metadata": {}, 277 | "outputs": [], 278 | "source": [] 279 | } 280 | ], 281 | "metadata": { 282 | "kernelspec": { 283 | "display_name": "SageMath 8.7", 284 | "language": "", 285 | "name": "sagemath" 286 | }, 287 | "language_info": { 288 | "codemirror_mode": { 289 | "name": "ipython", 290 | "version": 2 291 | }, 292 | "file_extension": ".py", 293 | "mimetype": "text/x-python", 294 | "name": "python", 295 | "nbconvert_exporter": "python", 296 | "pygments_lexer": "ipython2", 297 | "version": "2.7.16" 298 | } 299 | }, 300 | "nbformat": 4, 301 | "nbformat_minor": 2 302 | } 303 | --------------------------------------------------------------------------------