From 82cb7c1284a89983fbc5627fa49318217023fc00 Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Wed, 18 Jun 2025 10:54:30 +0530 Subject: [PATCH 01/11] add: basefold-notebook: sumcheck explanation --- basefold/basefold-notebook.ipynb | 410 +++++++++++++++++++++++++++++++ 1 file changed, 410 insertions(+) create mode 100644 basefold/basefold-notebook.ipynb diff --git a/basefold/basefold-notebook.ipynb b/basefold/basefold-notebook.ipynb new file mode 100644 index 0000000..83cc22f --- /dev/null +++ b/basefold/basefold-notebook.ipynb @@ -0,0 +1,410 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0909f09b-35cd-4674-85a0-e89994da2ea5", + "metadata": {}, + "source": [ + "#### What does Sumcheck prove?\n", + "\n", + "For a polynomial `f : 𝔽² β†’ 𝔽` (here `n = 3`) given *as a black box*, \n", + "the Prover wants to convince the Verifier that\n", + "$$\n", + "S = \\sum_{x \\in \\{0,1\\}^3} f(x) \\quad (= 36 \\text{ in our example})\n", + "$$\n", + "\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "id": "5be3a3ca-01fd-4918-af2b-99dca051cd09", + "metadata": {}, + "source": [ + "\n", + "without sending all `2ⁿ` evaluations. \n", + "Sumcheck does it in *n* rounds:\n", + "\n", + "1. **Round i** Prover sends a univariate degree-≀ d polynomial `gα΅’`. \n", + "2. Verifier checks `gα΅’(0)+gα΅’(1) = claimed_sum`. \n", + "3. Verifier samples a random field element `rα΅’` and sends it back. \n", + "4. Both parties restrict `f` to that slice and continue with `n βˆ’ i βˆ’ 1` variables.\n", + "\n", + "Soundness error ≀ `d/|𝔽|` per round. (We use plain integers for clarity.)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "9103b2b6-97e0-4b15-bd4c-36c1203ab0c3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "evaluations= [1, 2, 3, 4, 5, 6, 7, 8]\n", + "MLE polynomial in evaluation form:\n", + "\n", + "a[0] = 1 => term = 1*(-(X0 - 1)*(X1 - 1)*(X2 - 1))\n", + "a[1] = 2 => term = 2*((X0 - 1)*(X1 - 1)*X2)\n", + "a[2] = 3 => term = 3*((X0 - 1)*X1*(X2 - 1))\n", + "a[3] = 4 => term = 4*(-(X0 - 1)*X1*X2)\n", + "a[4] = 5 => term = 5*(X0*(X1 - 1)*(X2 - 1))\n", + "a[5] = 6 => term = 6*(-X0*(X1 - 1)*X2)\n", + "a[6] = 7 => term = 7*(-X0*X1*(X2 - 1))\n", + "a[7] = 8 => term = 8*(X0*X1*X2)\n", + "\n", + "Expanded polynomial:\n", + "4β‹…Xβ‚€ + 2β‹…X₁ + Xβ‚‚ + 1\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAZkAAAGkCAYAAADjQVi9AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAA3FtJREFUeJzsfXd4HOW5/dmmVd2VVqtq9WLJkpuabckhQGihBUhyQ+AXSiiBOJd7wSlA4BIgJFwgIb4JmBsSB0NICCGBUC4BTDPNGGz1XqyulbapbW/z+0P5htnV9p3Rjsyc5/GTsJqdmd2d+c6873ve84ooiqIgQIAAAQIEcABxvE9AgAABAgScvBBIRoAAAQIEcAaBZAQIECBAAGcQSEaAAAECBHAGgWQECBAgQABnEEhGgAABAgRwBoFkBAgQIEAAZxBIRoAAAQIEcAaBZAQIECBAAGcQSEaAAAGfC4yPj6O+vh6nnnoqampq8K1vfQtmsznep3XSQyAZPzh48CBEIlHAf++++y5nxz7ttNNw2mmncbZ/AOjt7cXdd9+NsbGxVX+7+uqrUVJSwunx+YT9+/fj4MGD8T4NAMCdd96JoqIiSKVSpKenx/t0wsLPf/5zVFRUQC6X45Zbbln199bWVpx55plITU1Feno6vvrVr+LEiRNh7fuDDz7Addddh4aGBsjlcohEIr/XLAB8+9vfRmJiIqqrq/G73/3O7zb5+fn45JNPcPjwYbS1teGjjz7CH/7wh7A/q4DoIJBMEDzxxBM4cuTIqn/19fXxPrWY0Nvbi3vuucfvDftf//VfeOGFF9b+pOIEvpDMiy++iJ/97Ge48sorcfjwYbz55pvxPqWQ6OzsxB133IHKykq88soruPnmm73+3t/fj9NOOw0OhwN//etf8Yc//AGDg4M45ZRToNPpQu7/rbfewptvvomioiK0tLQE3fbOO+/Eiy++iLy8POzZswcGg2HVNjKZDFKpFABgMplAURTq6urC/8ACooI03ifAZ2zevBmNjY3xPo01RXl5ebxPYd3D7XbD5XJBLpeH/Z7u7m4AwH/8x38gOzubq1NjFT09PQCAH/3oRzj99NNX/f2uu+6CXC7HK6+8AoVCAQBoaGhAZWUlfvGLX+CBBx4Iuv//+q//wk9+8hMAwC9+8YugGYTy8nKUl5fDbrfj3XffxeDgIJqbm1dtZzKZcO6556KzsxMtLS2ora0N9+MKiBJCJBMD6urqcMopp6x63e12Y8OGDfjqV79Kv3bPPfdg586dUKlUUCgUqK+vx4EDBxDKBPvdd9/1m6IbGxuDSCTyego/duwYvvnNb6KkpARJSUkoKSnBZZddhvHxcXqbgwcP4t/+7d8AAKeffjqdAiT78Zcus9lsuP3221FaWoqEhARs2LAB3/ve97CwsOC1XUlJCS644AK89tprqK+vR1JSEqqrq0OmJJxOJ7Kzs3HFFVes+tvCwgKSkpKwd+9e+rWlpSX84Ac/8Dqfm2++eVV+3ePx4De/+Q22b9+OpKQkpKenY9euXXjppZfo8+3p6cHhw4fp74H52ScmJvCtb30L2dnZkMvl2LRpE375y1/C4/Gs+h0efPBB3HfffSgtLYVcLsc777wT9DP7fm933nknACAnJwcikQh333132O8n6O7uxkUXXYSMjAwkJiZi+/btePLJJ722IdfTM888gzvuuAP5+flQKBQ488wzMTAwENHx7HY7ACAtLW3V31wuF1555RV87WtfowkGAIqLi3H66aeHFS2LxZEvT+RY5Nx8kZqaivfffx8TExOYmpoKSXQCYocQyQQBeSJlQiQSQSKRAFjJA//nf/4nhoaGUFlZSW/zxhtvYGZmBt/+9rfp18bGxnDDDTegqKgIAPDxxx/jpptuwvT0NO666y5WzndsbAxVVVX45je/CZVKBY1Gg8ceewxNTU3o7e2FWq3G+eefj5///Of48Y9/jEcffZRO/QWKYCiKwsUXX4y33noLt99+O0455RR0dnbiJz/5CZ0+ZD6xd3R04Pvf/z5uu+025OTk4Pe//z2uvfZaVFRU4Itf/KLfY8hkMnzrW9/C//7v/+LRRx/1WpSeeeYZ2Gw2+ru0WCw49dRTMTU1hR//+MfYunUrenp6cNddd6GrqwtvvvkmRCIRgBXCfPrpp3Httdfi3nvvRUJCAlpbW+k04QsvvICvf/3rUCqV2L9/PwDQn0Wn06GlpQUOhwM//elPUVJSgldeeQU/+MEPMDIyQm9P8Otf/xobN27EL37xCygUCq/rIRReeOEFPProozhw4ABee+01KJVKFBQUhP1+ABgYGEBLSwuys7Px61//GpmZmXj66adx9dVXY25uDj/60Y+8tv/xj3+M3bt34/e//z2WlpZw66234sILL0RfXx99fceCkZERWK1WbN26ddXftm7dikOHDsFmsyExMTHmY4ULq9WKpKQkAEBKSgqSk5ORmpq6Zsf/3IISsApPPPEEBcDvP4lEQm+n1+uphIQE6sc//rHX+7/xjW9QOTk5lNPp9Lt/t9tNOZ1O6t5776UyMzMpj8dD/+3UU0+lTj31VPq/33nnHQoA9c4773jtY3R0lAJAPfHEEwE/h8vlokwmE5WSkkL9z//8D/36c88953efFEVRV111FVVcXEz/92uvvUYBoB588EGv7Z599lkKAPX444/TrxUXF1OJiYnU+Pg4/ZrVaqVUKhV1ww03BDxPiqKozs7OVfujKIrasWMH1dDQQP/3/fffT4nFYurTTz/12u5vf/sbBYB69dVXKYqiqPfee48CQN1xxx1Bj1tbW+v1fRPcdtttFADq6NGjXq9/97vfpUQiETUwMEBR1Ge/Q3l5OeVwOIIeKxh+8pOfUAAonU4X1fu/+c1vUnK5nJqYmPB6/dxzz6WSk5OphYUFiqI+u57OO+88r+3++te/UgCoI0eOhH3MX/7ylxQAqq+vb9XfPvzwQwoA9cwzz6z6289//nMKADUzMxP2sR566CEKADU6Ohp0u6NHj1IAqOeff37V31555RWqpaWF+uIXv0ht3bqVuuaaayiz2Rz2OQiIDkK6LAieeuopfPrpp17/jh49Sv89MzMTF154IZ588kk6hTI/P48XX3wRV155JV1kBIC3334bZ555JpRKJSQSCWQyGe666y4YDAZotVpWztdkMuHWW29FRUUFpFIppFIpUlNTYTab0dfXF9U+3377bQArUQET//Zv/4aUlBS89dZbXq9v376djtYAIDExERs3bvRK2fnDli1b0NDQgCeeeIJ+ra+vD5988gmuueYa+rVXXnkFmzdvxvbt2+Fyueh/55xzjlda8Z///CcA4Hvf+17EnxlY+dw1NTXYsWOH1+tXX301KIqivxeCr3zlK5DJZFEdiw28/fbbOOOMM1BYWOj1+tVXXw2LxYIjR454vf6Vr3zF679JxBHqdwJW0pv9/f148sknkZOTg7KysoDbkqgy0r9Fi5qaGqSlpeHRRx/F6OioVybi/PPPx4cffojDhw+jo6MDBw4cQHJyMuvnIMAbAskEwaZNm9DY2Oj1r6GhwWuba665BtPT0zh06BCAlfSO3W73WpQ/+eQTnH322QCA3/3ud/jwww/x6aef4o477gCwEsazgcsvvxyPPPIIrrvuOrz++uv45JNP8OmnnyIrKyvqYxgMBkilUmRlZXm9LhKJkJubu0rFk5mZuWofcrk8rONfc801OHLkCPr7+wGsqPvkcjkuu+wyepu5uTl0dnZCJpN5/UtLSwNFUdDr9QBW0l0SiQS5ubkRf2Zg5XPn5eWtej0/P5/+OxP+tl1LRHq+vr8TSROG8ztVVlZi06ZNmJubw8svv4yEhIRV25D9+1N5GY1GiEQiTmTaqampeP755/Hpp5+irKzscyfc4SOEmkyMOOecc5Cfn48nnngC55xzDp544gns3LkTNTU19DZ/+ctfIJPJ8Morr3jloP/xj3+E3D/Z3reQSRZTgsXFRbzyyiv4yU9+gttuu41+3W63w2g0RvPRAKwsFi6XCzqdzotoKIrC7Owsmpqaot63Ly677DLs3bsXBw8exM9+9jP88Y9/xMUXX4yMjAx6G7VajaSkpIBiArVaDQDIysqC2+3G7OxsVASQmZkJjUaz6vWZmRmv4xBw8VQeCSI931jwj3/8A729vfjBD36A73znO2htbV31+cvLy5GUlISurq5V7+/q6kJFRQUn9Rin04nvfOc79D1ZVVXF+jEERAYhkokREokEV1xxBf7xj3/g/fffx7Fjx7zSO8DKAiSVSr0KqlarFX/84x9D7p+onTo7O71eJwop5jEoilolm/39738Pt9vt9VokT61nnHEGAODpp5/2ev3vf/87zGYz/Xc2kJGRgYsvvhhPPfUUXnnlFczOzq76Li+44AKMjIwgMzNzVZTZ2NhIf1/nnnsuAOCxxx4LesxAUdYZZ5yB3t5etLa2er3+1FNPQSQS+ZXsxhNnnHEG3n77bZpUCJ566ikkJydj165drB1r+/btuPzyy7Fnzx60t7f7ba6USqW48MIL8fzzz2N5eZl+fWJiAu+8846X8pJNdHd3Y3R0FHfeeSe++tWvChJlHkCIZIKgu7t7lboMWHlKYz7VX3PNNXjggQdw+eWXIykpCZdeeqnX9ueffz4efvhhXH755fjOd74Dg8GAX/ziF2H1UeTm5uLMM8/E/fffj4yMDBQXF+Ott97C888/77WdQqHAF7/4RTz00ENQq9UoKSnB4cOHceDAgVVpic2bNwMAHn/8caSlpSExMRGlpaV+U11nnXUWzjnnHNx6661YWlrC7t27aXVZXV2dX9lxLLjmmmvw7LPP4t///d9RUFCAM8880+vvN998M/7+97/ji1/8Im655RZs3boVHo8HExMTeOONN/D9738fO3fuxCmnnIIrrrgC9913H+bm5nDBBRdALpejra0NycnJuOmmmwCs1IL+8pe/4Nlnn0VZWRkSExOxZcsW3HLLLXjqqadw/vnn495770VxcTH+7//+D/v378d3v/tdbNy4kdXPHSt+8pOf4JVXXsHpp5+Ou+66CyqVCn/605/wf//3f3jwwQehVCpZP+aGDRsAYJWUneCee+5BU1MTLrjgAtx2222w2Wy46667oFar8f3vf99r29NOOw2HDx/2kvTrdDocPnwYAOiI6J///CeysrKQlZWFU089ddUxl5aWAHyWJhTAA8RVdsBTBFOXAaB+97vfrXpPS0sLBYD6f//v//nd5x/+8AeqqqqKksvlVFlZGXX//fdTBw4cWKWY8VWXURRFaTQa6utf/zqlUqkopVJJfetb36KOHTu2Sl02NTVFfe1rX6MyMjKotLQ06stf/jLV3d1NFRcXU1dddZXXPvft20eVlpZSEonEaz++6jKKWlGI3XrrrVRxcTElk8movLw86rvf/S41Pz/vtV1xcTF1/vnnr/rs/j5TILjdbqqwsDCoMsxkMlF33nknVVVVRSUkJFBKpZLasmULdcstt1Czs7Ne+/rVr35Fbd68md6uubmZevnll+ltxsbGqLPPPptKS0ujAHh99vHxceryyy+nMjMzKZlMRlVVVVEPPfQQ5Xa76W2Iuuyhhx4K6/MFQqzqMoqiqK6uLurCCy+klEollZCQQG3btm2V+pCoy5577jmv18NRK/qC3Ce+Sj8mjh07Rp1xxhlUcnIypVAoqIsvvpgaHh5etV1DQwOVm5vr91z9/Qt0PQVSYwqIH0QUFaIbUIAAAQL84Omnn8YVV1yB999/H1/4whei3s/y8jJUKhX27dsXtRqQ4LXXXsO5556LDz74ALt3745pXwLYgVCTESBAQFQg9a+//e1vWFhY8HJCiATvvfceNmzYgOuvvz7qc/F4PJifn6fTyEwZvYD4QohkBAgQEBU8Hg++/vWv4x//+AcoisJ//ud/Yt++fXE5l6uvvhpPPvkkxGIxbrjhhlWODALiB4FkBAgQEBOMRiOmpqaQkZGxqhl0rTA2Nobl5WUU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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "── First-round Sumcheck polynomial h₁(X) ──\n", + "h₁(X) = 16 + 4Β·X\n", + "h₁(0) = 16 (even-half sum)\n", + "h₁(1) = 20 (odd-half sum)\n", + "h₁(2) = 24 (third evaluation sent to the verifier)\n" + ] + } + ], + "source": [ + "\n", + "import matplotlib.pyplot as plt\n", + "import sympy as sp\n", + "from mpl_toolkits.mplot3d import Axes3D \n", + "\n", + "\n", + "def bits_of(i: int, n: int = 3):\n", + " \"\"\"Return the n-bit little-endian tuple of i (e.g. 5 β†’ (1,0,1)).\"\"\"\n", + " return tuple((i >> j) & 1 for j in range(n))\n", + "\n", + "f_vec = [1, 2, 3, 4, 5, 6, 7, 8] # f(0,0,0) … f(1,1,1)\n", + "print(\"evaluations= \", f_vec)\n", + "\n", + "X = sp.symbols(f'X0:{n}') # (X0, X1, X2)\n", + "\n", + "def bits(i, n):\n", + " \"Return i as an n-bit *list* (big-endian).\"\n", + " return list(map(int, format(i, f'0{n}b')))\n", + "\n", + "def bits_reverse(i, n):\n", + " \"Little-endian version (least-significant bit first).\"\n", + " return bits(i, n)[::-1]\n", + "\n", + "def eq_tilde(bits_i, u_vector):\n", + " result=1\n", + " for bit,u in zip(bits_i,u_vector):\n", + " result *= (1-bit)*(1-u) + bit*u\n", + " return result\n", + "\n", + "N = len(f_vec)\n", + "\n", + "print(\"MLE polynomial in evaluation form:\\n\")\n", + "for i in range(N):\n", + " term = eq_tilde(bits(i, n), X)\n", + " print(f\"a[{i}] = {f_vec[i]} => term = {f_vec[i]}*({term})\")\n", + "\n", + "print(\"\\nExpanded polynomial:\")\n", + "sp.pretty_print(sp.expand(f_tilde))\n", + "\n", + "coords = [bits_of(i, 3) for i in range(8)] \n", + "\n", + "# 3-D scatter plot\n", + "fig = plt.figure()\n", + "ax = fig.add_subplot(111, projection='3d')\n", + "xs, ys, zs = zip(*coords)\n", + "\n", + "ax.scatter(xs, ys, zs, s=60)\n", + "\n", + "# annotate each vertex with its f-value\n", + "for (x0, x1, x2), val in zip(coords, f_vec):\n", + " ax.text(x0, x1, x2, f\"{val}\", fontsize=10, ha='center')\n", + "\n", + "ax.set_xlabel(\"Xβ‚€\")\n", + "ax.set_ylabel(\"X₁\")\n", + "ax.set_zlabel(\"Xβ‚‚\")\n", + "ax.set_title(\"Evaluation vector f on {0,1}Β³\")\n", + "\n", + "plt.show()\n", + "\n", + "# first-round h₁(X) polynomial\n", + "# Even half (Xβ‚€ = 0)\n", + "g1_0 = sum(f_vec[idx] for idx in range(8) if bits_of(idx)[0] == 0)\n", + "# Odd half (Xβ‚€ = 1)\n", + "g1_1 = sum(f_vec[idx] for idx in range(8) if bits_of(idx)[0] == 1)\n", + "\n", + "# h₁(X) = a + bΒ·X\n", + "a = g1_0\n", + "b = g1_1 - g1_0\n", + "\n", + "print(\"\\n── First-round Sumcheck polynomial h₁(X) ──\")\n", + "print(f\"h₁(X) = {a} + {b}Β·X\")\n", + "print(f\"h₁(0) = {a} (even-half sum)\")\n", + "print(f\"h₁(1) = {a + b} (odd-half sum)\")\n", + "print(f\"h₁(2) = {a + 2*b} (third evaluation sent to the verifier)\")\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "d6940fa4-99f2-4300-a5f6-35e20a5fbf3e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Verifier samples Ξ±β‚€ = 8\n", + "\n", + "Folded 4-point vector fΒΉ on the (X₁,Xβ‚‚) plane:\n", + " (0, 0) β†’ 33\n", + " (1, 0) β†’ 34\n", + " (0, 1) β†’ 35\n", + " (1, 1) β†’ 36\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAZcAAAGjCAYAAADgjVi2AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAA7pFJREFUeJzsfXd4HOW99ZnZviq76s3qlmRLcpdsSzbYEGxwgAABAgQIkEBIgOSSwOWGbvOZenMJ4YY4ELhgSAgklEBCDwFMcbd6771tUdm+OzvfH2LGu6uts6PdlZnzPH5As7Mz78zOvOf9tfMjaJqmIUCAAAECBPAIMtoDECBAgAABpx4EchEgQIAAAbxDIBcBAgQIEMA7BHIRIECAAAG8QyAXAQIECBDAOwRyESBAgAABvEMgFwECBAgQwDsEchEgQIAAAbxDIBcBAoLA4cOHsW7dOigUClx77bXRHo4AATGPbwy5vPDCCyAIwuu/22+/ndOx+vv7A+67fft2bN++ndugfYAgCOzevTvgfnV1ddi2bRtUKhUIgsATTzzB6zhCwejoKHbv3o36+voFn+3evRsEQUR+UH5wzz33IC8vD2KxGGq1GkVFRfjrX/+KO+64I2JjePXVV1FRUQGFQgGCIFBfX4/f//73eOGFFyI2BmD+GXZ9X+RyOcrLy7F3717YbLaIjoULCgoKgloQvPjii7j88stRVlYGkiRRUFCw6GM7lSGO9gAijeeffx4rVqxw25adnR2l0SwufvjDH8JoNOKVV15BUlJSVF+W0dFR7NmzBwUFBVi7dq3bZ9dffz3OOeec6AzMC9566y08+OCDuPvuu7Fr1y7IZDKkpaUhLS0tYiQ4NTWFq6++Gueccw5+//vfQyaTobS0FFdddRVSU1Mjbj0VFRXhz3/+Mzu2Z599Fvfeey8GBwfxzDPPRHQsi4WXXnoJ4+Pj2LhxI5xOJ+x2e7SHtKTxjSOXyspKVFVVRXsYEUFzczNuuOEG7Nq1K9pD8Ytly5Zh2bJl0R4Gi+bmZgDAz3/+c6Snp0dlDJ2dnbDb7bjqqquwbdu2RT0XTdOwWCxQKBQ+91EoFNi8eTP7965du1BeXo79+/fjySefhFwuX9QxRgIffPABSHLemXPeeeexz4EAbvjGuMWCxdtvv42amhoolUokJCRgx44dOHjwYMDv0TSNxx57DPn5+ZDL5Vi/fj3ee+89r/vOzs7i9ttvR2FhIaRSKXJycnDrrbfCaDQu2O+GG25ASkoK4uPjcc4556CzszPgWBi3ncPhwL59+1h3BuDbBeXN1VdQUIDzzjsP77//PtavXw+FQoEVK1bg//7v/xZ8f2RkBD/+8Y+Rm5sLqVSK7OxsXHLJJZiYmMCnn36K6upqAMB1113Hjodx7Xkbk9PpxGOPPYYVK1ZAJpMhPT0dP/jBDzA8POy23/bt21FZWYmjR4/itNNOg1KpRFFRER555BE4nc6A98oTBQUFuOeeewAAGRkZQbsgg8VHH32ECy64AMuWLYNcLsfy5ctx4403QqPRsPtce+212Lp1KwDgsssuA0EQ2L59OwoKCtDS0oLPPvuMvYeu1miwzxVBELjlllvwhz/8AStXroRMJsP+/ftDug6xWIy1a9fCZrNhenqa3W6xWHDnnXe6jeHmm29224cZg7f76unCYp7LTz75BD/96U+RmpqKlJQUfPe738Xo6Kjbd+12O+644w5kZmZCqVRi69atOHLkSNDXxBCLAH7wjbNcKIqCw+Fw2yYWz9+Gl19+GVdeeSV27tyJv/zlL7BarXjsscewfft2fPzxx+wL7w179uzBnj178KMf/QiXXHIJhoaGcMMNN4CiKJSVlbH7mUwmbNu2DcPDw7jrrruwevVqtLS04L777kNTUxP+9a9/gSAI0DSNCy+8EF999RXuu+8+VFdX48svvwzKCjn33HNx8OBB1NTU4JJLLsFtt93G8W4BDQ0NuO222/CrX/0KGRkZePbZZ/GjH/0Iy5cvx+mnnw5gnliqq6tht9vZa9Jqtfjggw+g1+uxfv16PP/887juuutwzz334NxzzwUAv9bKT3/6UzzzzDO45ZZbcN5556G/vx/33nsvPv30U5w4cQKpqansvuPj47jyyitx22234f7778ebb76JO++8E9nZ2fjBD34Q0vW++eabeOqpp/Dcc8/h/fffh0ql4tWq6unpQU1NDa6//nqoVCr09/fj8ccfx9atW9HU1ASJRIJ7770XGzduxM0334yHHnoIZ5xxBhITE2G1WnHJJZdApVLh97//PQBAJpMBCP65YvD3v/8dn3/+Oe677z5kZmZystD6+vqgVquRlpYGAOwz+/HHH+POO+/EaaedhsbGRtx///04ePAgDh48yI43VFx//fU499xz8fLLL2NoaAj/+Z//iauuugr//ve/2X1uuOEGvPjii7j99tuxY8cONDc347vf/S7m5uY4nVNAmKC/IXj++edpAF7/2e12mqIoOjs7m161ahVNURT7vbm5OTo9PZ2ura1dcKy+vj6apmlar9fTcrmcvuiii9zO+eWXX9IA6G3btrHbHn74YZokSfro0aNu+7722ms0APrdd9+laZqm33vvPRoA/dvf/tZtvwcffJAGQN9///0BrxkAffPNN7ttu//++2lvP7vnNdE0Tefn59NyuZweGBhgt5nNZjo5OZm+8cYb2W0//OEPaYlEQre2tvocy9GjR2kA9PPPP7/gM88xtbW10QDom266yW2/w4cP0wDou+66i922bds2GgB9+PBht33Ly8vps88+2+d4/IEZz9TUFLutq6uLTklJoRUKBS2TyeiUlBT6gw8+4HR8Bk6nk7bb7fTAwAANgH7rrbfYzz755BMaAP23v/3N7TsVFRVuzxODYJ8rmp5/LlQqFa3T6YIa57Zt2+iKigrabrfTdrudHhsbo++77z4aAP2HP/yB3e/999+nAdCPPfaY2/dfffVVGgD9zDPPuI3B2zOcn59PX3PNNezfzHPp+Sw89thjNAB6bGyMpumTz8wvfvELt/3+/Oc/0wDcjhkMzj33XDo/Pz+k7whwxzfODnzxxRdx9OhRt39isRgdHR0YHR3F1Vdf7WYex8fH4+KLL8ahQ4dgMpm8HvPgwYOwWCy48sor3bbX1tYiPz/fbds///lPVFZWYu3atXA4HOy/s88+GwRB4NNPPwUAfPLJJwCw4Jjf//73w70FIWHt2rXIy8tj/5bL5SgtLcXAwAC77b333sMZZ5yBlStX8nJO5to9g9YbN27EypUr8fHHH7ttz8zMxMaNG922rV692m2M4WL58uXQaDQwmUywWCzQaDTYuXNnyMeZnJzET37yE+Tm5kIsFkMikbDPSFtbG+fxBftcMTjzzDORlJQU9PFbWlogkUggkUiQlZWFBx54AHfeeSduvPFGdh/GivD83S699FLExcUt+N1CwXe+8x23v1evXg0A7G/s63353ve+x3omBEQW37i7vnLlSq8Bfa1WCwDIyspa8Fl2djacTif0ej2USqXP72ZmZi74zHPbxMQEuru7IZFIvI6P8b1rtVqIxWKkpKT4Pd5iw/P8wLwrxmw2s39PTU3x6joK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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import random\n", + "random.seed(int(12345)) # deterministic for the demo\n", + "\n", + "# verifier samples Ξ±β‚€\n", + "alpha0 = random.randint(2, 9)\n", + "print(f\"Verifier samples Ξ±β‚€ = {alpha0}\")\n", + "\n", + "# fold the vector: fΒΉ(x₁,xβ‚‚) = f(Ξ±β‚€, x₁, xβ‚‚) \n", + "# even half = indices where Xβ‚€ = 0 (0,1,2,3)\n", + "# odd half = indices where Xβ‚€ = 1 (4,5,6,7)\n", + "f_even = f_vec[0:4]\n", + "f_odd = f_vec[4:8]\n", + "\n", + "f_fold = [(1 - alpha0) * e + alpha0 * o # (1-Ξ±)Β·even + Ξ±Β·odd\n", + " for e, o in zip(f_even, f_odd)]\n", + "\n", + "print(\"\\nFolded 4-point vector fΒΉ on the (X₁,Xβ‚‚) plane:\")\n", + "for idx, val in enumerate(f_fold):\n", + " print(f\" ({bits_of(idx,2)[0]}, {bits_of(idx,2)[1]}) β†’ {val}\")\n", + "\n", + "# 2-D visualisation (Z-axis = function value)\n", + "from mpl_toolkits.mplot3d import Axes3D \n", + "import matplotlib.pyplot as plt\n", + "fig = plt.figure()\n", + "ax = fig.add_subplot(111, projection='3d')\n", + "xs, ys = zip(*[bits_of(i,2) for i in range(4)])\n", + "zs = f_fold\n", + "ax.bar3d(xs, ys, [0]*4, dx=0.2, dy=0.2, dz=zs, shade=True)\n", + "for (x, y), z in zip(zip(xs, ys), zs):\n", + " ax.text(x, y, z+0.2, f\"{z:.1f}\", ha='center')\n", + "ax.set_xlabel(\"X₁\"); ax.set_ylabel(\"Xβ‚‚\"); ax.set_zlabel(\"fΒΉ value\")\n", + "ax.set_title(\"Folded function fΒΉ after Round 1\")\n", + "plt.show()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "a9a40b6c-7751-4226-8a68-4ce664f5c709", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "── Second-round polynomial hβ‚‚(X) ──\n", + "hβ‚‚(X) = 67.0 + 4.0Β·X\n", + "hβ‚‚(0) = 67.0\n", + "hβ‚‚(1) = 71.0\n", + "hβ‚‚(2) = 75.0\n", + "a2 = 67\n", + "b2 = 4\n", + "hβ‚‚(0)+hβ‚‚(1) = 138\n", + "Ξ£ f_fold = 138\n", + "Verifier check hβ‚‚(0)+hβ‚‚(1) = Ξ£ fΒΉ(x) βœ“\n" + ] + } + ], + "source": [ + "# partial sums over X₁\n", + "g2_0 = f_fold[0] + f_fold[1] # X₁ = 0 (indices 00, 01)\n", + "g2_1 = f_fold[2] + f_fold[3] # X₁ = 1 (indices 10, 11)\n", + "\n", + "a2 = g2_0\n", + "b2 = g2_1 - g2_0 \n", + "\n", + "print(\"\\n── Second-round polynomial hβ‚‚(X) ──\")\n", + "print(f\"hβ‚‚(X) = {a2:.1f} + {b2:.1f}Β·X\")\n", + "print(f\"hβ‚‚(0) = {a2:.1f}\")\n", + "print(f\"hβ‚‚(1) = {a2 + b2:.1f}\")\n", + "print(f\"hβ‚‚(2) = {a2 + 2*b2:.1f}\")\n", + "\n", + "print(f\"a2 = {a2}\")\n", + "print(f\"b2 = {b2}\")\n", + "print(f\"hβ‚‚(0)+hβ‚‚(1) = {a2 + (a2 + b2)}\")\n", + "print(f\"Ξ£ f_fold = {sum(f_fold)}\")\n", + "\n", + "\n", + "# ---------- verifier checks the sum relation ----------\n", + "assert abs((a2) + (a2 + b2) - sum(f_fold)) < 1e-9\n", + "print(\"Verifier check hβ‚‚(0)+hβ‚‚(1) = Ξ£ fΒΉ(x) βœ“\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "id": "577e119b-6044-4c10-8a1d-81c93f97ca53", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Verifier samples α₁ = 2\n", + "Folded vector fΒ² (depends only on Xβ‚‚ now): [37, 38]\n", + "\n", + "── Third-round polynomial h₃(X) ──\n", + "h₃(X) = 37.0 + 1.0Β·X\n", + "h₃(0) = 37.0\n", + "h₃(1) = 38.0\n", + "h₃(2) = 39.0\n", + "\n", + "Verifier picks Ξ±β‚‚ = 1 and asks for fΒ²(Ξ±β‚‚) = 38.0\n", + "Leaf equals h₃(Ξ±β‚‚) βœ“\n", + "\n", + "βœ… Sumcheck for n = 3 completed – all rounds verified.\n", + "\n" + ] + } + ], + "source": [ + "# ---------- sample α₁ ----------\n", + "alpha1 = random.randint(2, 9)\n", + "print(f\"\\nVerifier samples α₁ = {alpha1}\")\n", + "\n", + "# ---------- fold again over X₁ ----------\n", + "f1_even = f_fold[0:2] # X₁ = 0 slice\n", + "f1_odd = f_fold[2:4] # X₁ = 1 slice\n", + "f_fold2 = [(1 - alpha1) * e + alpha1 * o\n", + " for e, o in zip(f1_even, f1_odd)] # length 2\n", + "\n", + "print(\"Folded vector fΒ² (depends only on Xβ‚‚ now):\", f_fold2)\n", + "\n", + "# ---------- build h₃(X) over the last variable Xβ‚‚ ----------\n", + "g3_0, g3_1 = f_fold2 # length 2 already\n", + "a3 = g3_0\n", + "b3 = g3_1 - g3_0\n", + "\n", + "print(\"\\n── Third-round polynomial h₃(X) ──\")\n", + "print(f\"h₃(X) = {a3:.1f} + {b3:.1f}Β·X\")\n", + "print(f\"h₃(0) = {a3:.1f}\")\n", + "print(f\"h₃(1) = {a3 + b3:.1f}\")\n", + "print(f\"h₃(2) = {a3 + 2*b3:.1f}\")\n", + "\n", + "# ---------- final leaf opening ----------\n", + "alpha2 = random.randint(0, 1) \n", + "leaf = f_fold2[alpha2]\n", + "print(f\"\\nVerifier picks Ξ±β‚‚ = {alpha2} and asks for fΒ²(Ξ±β‚‚) = {leaf:.1f}\")\n", + "assert abs(leaf - (a3 + b3*alpha2)) < 1e-9\n", + "print(\"Leaf equals h₃(Ξ±β‚‚) βœ“\")\n", + "\n", + "print(\"\\nβœ… Sumcheck for n = 3 completed – all rounds verified.\\n\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "id": "230abf1e-76ee-49eb-bf37-8dc59f99faa3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "────────────────────────────────────────────\n", + "fΜƒ(Ξ±β‚€, α₁, Ξ±β‚‚) = fΜƒ(8, 2, 1) = 38\n", + "leaf opened in the final Sumcheck round = 38\n", + "────────────────────────────────────────────\n", + "βœ… They match – Sumcheck transcript is fully consistent.\n", + "\n" + ] + } + ], + "source": [ + "\n", + "n = 3\n", + "X = sp.symbols(f'X0:{n}') # (X0, X1, X2)\n", + "f_tilde = sum(coeff * eq_tilde(bits(i, n), X)\n", + " for i, coeff in enumerate(f_vec))\n", + "\n", + "# 2. Evaluate it at the verifier’s random challenges\n", + "poly_val = f_tilde.subs({X[0]: alpha0,\n", + " X[1]: alpha1,\n", + " X[2]: alpha2})\n", + "\n", + "print(\"────────────────────────────────────────────\")\n", + "print(f\"fΜƒ(Ξ±β‚€, α₁, Ξ±β‚‚) = fΜƒ({alpha0}, {alpha1}, {alpha2}) = {poly_val}\")\n", + "print(f\"leaf opened in the final Sumcheck round = {leaf}\")\n", + "print(\"────────────────────────────────────────────\")\n", + "assert poly_val == leaf\n", + "print(\"βœ… They match – Sumcheck transcript is fully consistent.\\n\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f975bd06-e41b-4c8c-9ae5-b28aa47115b7", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "SageMath 10.6", + "language": "sage", + "name": "sagemath" + }, + "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.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 650bf74ffe64d6c61ea732b8d03bc8eadd27667b Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Wed, 18 Jun 2025 12:29:10 +0530 Subject: [PATCH 02/11] add: cheating prover in sumcheck --- basefold/basefold-notebook.ipynb | 247 ++++++++++++++++++++++++++++++- 1 file changed, 241 insertions(+), 6 deletions(-) diff --git a/basefold/basefold-notebook.ipynb b/basefold/basefold-notebook.ipynb index 83cc22f..240d9fb 100644 --- a/basefold/basefold-notebook.ipynb +++ b/basefold/basefold-notebook.ipynb @@ -35,7 +35,7 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 56, "id": "9103b2b6-97e0-4b15-bd4c-36c1203ab0c3", "metadata": {}, "outputs": [ @@ -163,7 +163,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 57, "id": "d6940fa4-99f2-4300-a5f6-35e20a5fbf3e", "metadata": {}, "outputs": [ @@ -229,7 +229,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 58, "id": "a9a40b6c-7751-4226-8a68-4ce664f5c709", "metadata": {}, "outputs": [ @@ -278,7 +278,7 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 59, "id": "577e119b-6044-4c10-8a1d-81c93f97ca53", "metadata": {}, "outputs": [ @@ -340,7 +340,7 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 60, "id": "230abf1e-76ee-49eb-bf37-8dc59f99faa3", "metadata": {}, "outputs": [ @@ -377,10 +377,245 @@ "print(\"βœ… They match – Sumcheck transcript is fully consistent.\\n\")\n" ] }, + { + "cell_type": "markdown", + "id": "69adbd57-f290-43fd-83ff-9be33c8991da", + "metadata": {}, + "source": [ + "#### 2-A What’s still missing after Sumcheck?\n", + "\n", + "At the end of the previous section the verifier is convinced that\n", + "$$\n", + "\\text{leaf} = \\sum_{b \\in \\{0,1\\}^3} \\text{f\\_vec}[b] \\cdot \\text{eq}(b, \\alpha)\n", + "$$\n" + ] + }, + { + "cell_type": "markdown", + "id": "9a2fabb3-028a-4af2-9c00-182d3215d165", + "metadata": {}, + "source": [ + "\n", + "…but the verifier has **never seen `f_vec` itself**.\n", + "A cheating prover could:\n", + "\n", + "1. Run Sumcheck with any **fake** vector `f_fake`.\n", + "2. Compute `leaf_fake = Ξ£ f_fake[b]Β·eq(b, Ξ±)` (easy because Ξ± is known).\n", + "3. Open that scalar in the last round.\n", + "\n", + "Sumcheck would verify perfectly – yet the statement\n", + "β€œ`leaf` equals _your_ polynomial at α” might be **false**.\n", + "We therefore need a separate mechanism that binds the prover to\n", + "a *single* multilinear polynomial before Sumcheck starts.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "id": "0e9d5d91-e3a0-4984-9f3c-ecb19244e05c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Honest vector : [1, 2, 3, 4, 5, 6, 7, 8]\n", + "Expanded polynomial:\n", + "4β‹…Xβ‚€ + 2β‹…X₁ + Xβ‚‚ + 1\n", + "\n", + "\n", + "Fake vector : [8, 7, 6, 5, 4, 3, 2, 1] (same sum, different values)\n", + "Expanded polynomial:\n", + "-4β‹…Xβ‚€ - 2β‹…X₁ - Xβ‚‚ + 8\n", + "\n", + "\n", + "Total sum S : 36 \n", + "\n", + "Verifier challenges: Ξ±0 = 8 Ξ±1 = 2 Ξ±2 = 0\n", + "Honest leaf = 37 Fake leaf = -28 \n", + "\n", + "\n", + "===== Verifier run on HONEST transcript =====\n", + "Prover’s messages:\n", + " h₁ values = (10, 26, 42) β‡’ h₁(X) = 10.0 + 16.0Β·X\n", + " hβ‚‚ values = (67, 71, 75) β‡’ hβ‚‚(X) = 67.0 + 4.0Β·X\n", + " h₃ values = (37, 38, 39) β‡’ h₃(X) = 37.0 + 1.0Β·X\n", + " leaf = 37 \n", + "\n", + "β‘  h₁(0)+h₁(1) = 36 vs S = 36 β†’ True\n", + "β‘‘ hβ‚‚(0)+hβ‚‚(1) = 138 vs h₁(Ξ±β‚€) = 138 β†’ True\n", + "β‘’ h₃(0)+h₃(1) = 75 vs hβ‚‚(α₁) = 75 β†’ True\n", + "β‘£ leaf = 37 vs h₃(Ξ±β‚‚) = 37 β†’ True\n", + "Result: βœ” PASSED\n", + "\n", + "===== Verifier run on FAKE transcript =====\n", + "Prover’s messages:\n", + " h₁ values = (26, 10, -6) β‡’ h₁(X) = 26.0 + -16.0Β·X\n", + " hβ‚‚ values = (-49, -53, -57) β‡’ hβ‚‚(X) = -49.0 + -4.0Β·X\n", + " h₃ values = (-28, -29, -30) β‡’ h₃(X) = -28.0 + -1.0Β·X\n", + " leaf = -28 \n", + "\n", + "β‘  h₁(0)+h₁(1) = 36 vs S = 36 β†’ True\n", + "β‘‘ hβ‚‚(0)+hβ‚‚(1) = -102 vs h₁(Ξ±β‚€) = -102 β†’ True\n", + "β‘’ h₃(0)+h₃(1) = -57 vs hβ‚‚(α₁) = -57 β†’ True\n", + "β‘£ leaf = -28 vs h₃(Ξ±β‚‚) = -28 β†’ True\n", + "Result: βœ” PASSED\n", + "Verifier result on HONEST transcript : True\n", + "Verifier result on FAKE transcript : True \n", + "\n", + "At point u = (0, 0, 0):\n", + " honest fΜƒ(u) = 1\n", + " fake fΜƒ(u) = 8 ← different but still passed Sumcheck!\n" + ] + } + ], + "source": [ + "# ─────────────────────────────────────────────────────────────\n", + "# Cheating prover with *same* total sum S but different vector\n", + "# ─────────────────────────────────────────────────────────────\n", + "import random, math\n", + "\n", + "# --- 1. Choose a fake vector with the same sum -----------------\n", + "S_real = sum(f_vec) # 36 for [1…8]\n", + "\n", + "print(\"Honest vector :\", f_vec)\n", + "n = 3\n", + "X = sp.symbols(f'X0:{n}') # (X0, X1, X2)\n", + "f_tilde = sum(coeff * eq_tilde(bits(i, n), X)\n", + " for i, coeff in enumerate(f_vec))\n", + "\n", + "# 2. Evaluate it at the verifier’s random challenges\n", + "poly_val = f_tilde.subs({X[0]: alpha0,\n", + " X[1]: alpha1,\n", + " X[2]: alpha2})\n", + "\n", + "print(\"Expanded polynomial:\")\n", + "sp.pretty_print(sp.expand(f_tilde))\n", + "print(\"\\n\")\n", + "f_fake_same_sum = list(reversed(f_vec)) # [8,7,6,5,4,3,2,1]\n", + "delta = sum(f_fake_same_sum) - S_real # here 36 - 36 = 0\n", + "\n", + "\n", + "\n", + "assert sum(f_fake_same_sum) == S_real and f_fake_same_sum != f_vec\n", + "\n", + "print(\"Fake vector :\", f_fake_same_sum, \"(same sum, different values)\")\n", + "\n", + "fake_tilde = sum(coeff * eq_tilde(bits(i, n), X)\n", + " for i, coeff in enumerate(f_fake_same_sum))\n", + "\n", + "# 2. Evaluate it at the verifier’s random challenges\n", + "poly_val = fake_tilde.subs({X[0]: alpha0,\n", + " X[1]: alpha1,\n", + " X[2]: alpha2})\n", + "\n", + "print(\"Expanded polynomial:\")\n", + "sp.pretty_print(sp.expand(fake_tilde))\n", + "print(\"\\n\")\n", + "\n", + "\n", + "print(\"Total sum S :\", S_real, \"\\n\")\n", + "\n", + "# --- 2. Helper routines (unchanged) ---------------------------\n", + "def line_triplet(v0, v1):\n", + " return (v0, v1, v0 + 2*(v1 - v0))\n", + "\n", + "def sumcheck_transcript(vec, Ξ±0, Ξ±1):\n", + " g1_0, g1_1 = sum(vec[:4]), sum(vec[4:])\n", + " h1 = line_triplet(g1_0, g1_1)\n", + "\n", + " even, odd = vec[:4], vec[4:]\n", + " f_fold = [(1-Ξ±0)*e + Ξ±0*o for e,o in zip(even, odd)]\n", + "\n", + " g2_0, g2_1 = f_fold[0]+f_fold[1], f_fold[2]+f_fold[3]\n", + " h2 = line_triplet(g2_0, g2_1)\n", + "\n", + " even2, odd2 = f_fold[:2], f_fold[2:]\n", + " f_fold2 = [(1-Ξ±1)*e + Ξ±1*o for e,o in zip(even2, odd2)]\n", + "\n", + " g3_0, g3_1 = f_fold2\n", + " h3 = line_triplet(g3_0, g3_1)\n", + "\n", + " Ξ±2 = random.randint(0, 1) \n", + " leaf = eval_line(h3, Ξ±2) \n", + " return h1, h2, h3, Ξ±2, leaf\n", + "\n", + "def eval_line(h, x):\n", + " return h[0] + (h[1]-h[0])*x\n", + "\n", + "def verifier_accepts(h1,h2,h3, Ξ±0,Ξ±1,Ξ±2, leaf, S):\n", + " \"\"\"Return True iff all 4 Sumcheck equalities hold.\"\"\"\n", + " return (\n", + " math.isclose(h1[0]+h1[1], S) and\n", + " math.isclose(h2[0]+h2[1], eval_line(h1, Ξ±0)) and\n", + " math.isclose(h3[0]+h3[1], eval_line(h2, Ξ±1)) and\n", + " math.isclose(leaf, h3[Ξ±2])\n", + " )\n", + "\n", + "# --- 3. Build transcripts -------------------------------------\n", + "h1_h, h2_h, h3_h, Ξ±2_h, leaf_h = sumcheck_transcript(f_vec, alpha0, alpha1)\n", + "h1_c, h2_c, h3_c, Ξ±2_c, leaf_c = sumcheck_transcript(f_fake_same_sum,\n", + " alpha0, alpha1)\n", + "\n", + "# --- 4. Verifier runs on both transcripts ---------------------\n", + "print(\"Verifier challenges: Ξ±0 =\", alpha0, \"Ξ±1 =\", alpha1, \"Ξ±2 =\", Ξ±2_c)\n", + "print(\"Honest leaf =\", leaf_h, \" Fake leaf =\", leaf_c, \"\\n\")\n", + "\n", + "def poly_str(h):\n", + " \"\"\"Return 'a + bΒ·X' string for a degree-1 poly given (h0,h1, _).\"\"\"\n", + " a, b = h[0], h[1] - h[0]\n", + " return f\"{a:.1f} + {b:.1f}Β·X\"\n", + "\n", + "def run_and_explain(tag, h1,h2,h3, Ξ±0,Ξ±1,Ξ±2, leaf, S):\n", + " print(f\"\\n===== Verifier run on {tag} transcript =====\")\n", + " print(\"Prover’s messages:\")\n", + " print(\" h₁ values =\", h1, \" β‡’ h₁(X) =\", poly_str(h1))\n", + " print(\" hβ‚‚ values =\", h2, \" β‡’ hβ‚‚(X) =\", poly_str(h2))\n", + " print(\" h₃ values =\", h3, \" β‡’ h₃(X) =\", poly_str(h3))\n", + " print(\" leaf =\", leaf, \"\\n\")\n", + "\n", + " # --- algebraic checks ----------------------------------\n", + " check1 = math.isclose(h1[0] + h1[1], S)\n", + " check2 = math.isclose(h2[0] + h2[1], eval_line(h1, Ξ±0))\n", + " check3 = math.isclose(h3[0] + h3[1], eval_line(h2, Ξ±1))\n", + " check4 = math.isclose(leaf , h3[Ξ±2])\n", + "\n", + " print(f\"β‘  h₁(0)+h₁(1) = {h1[0]+h1[1]:>8} vs S = {S:<8} β†’ {check1}\")\n", + " print(f\"β‘‘ hβ‚‚(0)+hβ‚‚(1) = {h2[0]+h2[1]:>8} vs h₁(Ξ±β‚€) = {eval_line(h1,Ξ±0):<8} β†’ {check2}\")\n", + " print(f\"β‘’ h₃(0)+h₃(1) = {h3[0]+h3[1]:>8} vs hβ‚‚(α₁) = {eval_line(h2,Ξ±1):<8} β†’ {check3}\")\n", + " print(f\"β‘£ leaf = {leaf:>8} vs h₃(Ξ±β‚‚) = {h3[Ξ±2]:<8} β†’ {check4}\")\n", + "\n", + " all_pass = check1 and check2 and check3 and check4\n", + " print(\"Result:\", \"βœ” PASSED\" if all_pass else \"βœ– REJECTED\")\n", + " return all_pass\n", + "\n", + "ok_honest = run_and_explain(\"HONEST\",\n", + " h1_h,h2_h,h3_h,\n", + " alpha0,alpha1,Ξ±2_h,\n", + " leaf_h, S_real)\n", + "\n", + "ok_fake = run_and_explain(\"FAKE \",\n", + " h1_c,h2_c,h3_c,\n", + " alpha0,alpha1,Ξ±2_c,\n", + " leaf_c, S_real) \n", + "print(\"Verifier result on HONEST transcript :\", ok_honest)\n", + "print(\"Verifier result on FAKE transcript :\", ok_fake, \"\\n\")\n", + "\n", + "# --- 5. Show they differ at another point ---------------------\n", + "def eval_mle(evals, u):\n", + " return sum(e*eq_tilde(bits_of(i,3), u) for i,e in enumerate(evals))\n", + "\n", + "u_test = (0,0,0)\n", + "print(f\"At point u = {u_test}:\")\n", + "print(\" honest fΜƒ(u) =\", eval_mle(f_vec, u_test))\n", + "print(\" fake fΜƒ(u) =\", eval_mle(f_fake_same_sum, u_test),\n", + " \"← different but still passed Sumcheck!\")\n" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "f975bd06-e41b-4c8c-9ae5-b28aa47115b7", + "id": "c79541df-4216-4277-8748-6d9d8883fda9", "metadata": {}, "outputs": [], "source": [] From 4afe94a16d818fcc4f1fd328fc14e2406ac795b6 Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Wed, 18 Jun 2025 12:33:47 +0530 Subject: [PATCH 03/11] fix: cleanup --- basefold/basefold-notebook.ipynb | 38 ++++++++++++++------------------ 1 file changed, 16 insertions(+), 22 deletions(-) diff --git a/basefold/basefold-notebook.ipynb b/basefold/basefold-notebook.ipynb index 240d9fb..23b3a46 100644 --- a/basefold/basefold-notebook.ipynb +++ b/basefold/basefold-notebook.ipynb @@ -35,7 +35,7 @@ }, { "cell_type": "code", - "execution_count": 56, + "execution_count": 70, "id": "9103b2b6-97e0-4b15-bd4c-36c1203ab0c3", "metadata": {}, "outputs": [ @@ -143,6 +143,7 @@ "plt.show()\n", "\n", "# first-round h₁(X) polynomial\n", + "\n", "# Even half (Xβ‚€ = 0)\n", "g1_0 = sum(f_vec[idx] for idx in range(8) if bits_of(idx)[0] == 0)\n", "# Odd half (Xβ‚€ = 1)\n", @@ -163,7 +164,7 @@ }, { "cell_type": "code", - "execution_count": 57, + "execution_count": 71, "id": "d6940fa4-99f2-4300-a5f6-35e20a5fbf3e", "metadata": {}, "outputs": [ @@ -212,7 +213,6 @@ "for idx, val in enumerate(f_fold):\n", " print(f\" ({bits_of(idx,2)[0]}, {bits_of(idx,2)[1]}) β†’ {val}\")\n", "\n", - "# 2-D visualisation (Z-axis = function value)\n", "from mpl_toolkits.mplot3d import Axes3D \n", "import matplotlib.pyplot as plt\n", "fig = plt.figure()\n", @@ -229,7 +229,7 @@ }, { "cell_type": "code", - "execution_count": 58, + "execution_count": 72, "id": "a9a40b6c-7751-4226-8a68-4ce664f5c709", "metadata": {}, "outputs": [ @@ -271,14 +271,14 @@ "print(f\"Ξ£ f_fold = {sum(f_fold)}\")\n", "\n", "\n", - "# ---------- verifier checks the sum relation ----------\n", + "# verifier checks the sum relation\n", "assert abs((a2) + (a2 + b2) - sum(f_fold)) < 1e-9\n", "print(\"Verifier check hβ‚‚(0)+hβ‚‚(1) = Ξ£ fΒΉ(x) βœ“\")\n" ] }, { "cell_type": "code", - "execution_count": 59, + "execution_count": 73, "id": "577e119b-6044-4c10-8a1d-81c93f97ca53", "metadata": {}, "outputs": [ @@ -305,11 +305,11 @@ } ], "source": [ - "# ---------- sample α₁ ----------\n", + "# sample α₁ \n", "alpha1 = random.randint(2, 9)\n", "print(f\"\\nVerifier samples α₁ = {alpha1}\")\n", "\n", - "# ---------- fold again over X₁ ----------\n", + "# fold again over X₁ \n", "f1_even = f_fold[0:2] # X₁ = 0 slice\n", "f1_odd = f_fold[2:4] # X₁ = 1 slice\n", "f_fold2 = [(1 - alpha1) * e + alpha1 * o\n", @@ -317,8 +317,8 @@ "\n", "print(\"Folded vector fΒ² (depends only on Xβ‚‚ now):\", f_fold2)\n", "\n", - "# ---------- build h₃(X) over the last variable Xβ‚‚ ----------\n", - "g3_0, g3_1 = f_fold2 # length 2 already\n", + "# build h₃(X) over the last variable Xβ‚‚ \n", + "g3_0, g3_1 = f_fold2 \n", "a3 = g3_0\n", "b3 = g3_1 - g3_0\n", "\n", @@ -328,7 +328,7 @@ "print(f\"h₃(1) = {a3 + b3:.1f}\")\n", "print(f\"h₃(2) = {a3 + 2*b3:.1f}\")\n", "\n", - "# ---------- final leaf opening ----------\n", + "# final leaf opening \n", "alpha2 = random.randint(0, 1) \n", "leaf = f_fold2[alpha2]\n", "print(f\"\\nVerifier picks Ξ±β‚‚ = {alpha2} and asks for fΒ²(Ξ±β‚‚) = {leaf:.1f}\")\n", @@ -340,7 +340,7 @@ }, { "cell_type": "code", - "execution_count": 60, + "execution_count": 74, "id": "230abf1e-76ee-49eb-bf37-8dc59f99faa3", "metadata": {}, "outputs": [ @@ -382,7 +382,7 @@ "id": "69adbd57-f290-43fd-83ff-9be33c8991da", "metadata": {}, "source": [ - "#### 2-A What’s still missing after Sumcheck?\n", + "#### What’s still missing after Sumcheck?\n", "\n", "At the end of the previous section the verifier is convinced that\n", "$$\n", @@ -411,7 +411,7 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 69, "id": "0e9d5d91-e3a0-4984-9f3c-ecb19244e05c", "metadata": {}, "outputs": [ @@ -470,12 +470,10 @@ } ], "source": [ - "# ─────────────────────────────────────────────────────────────\n", "# Cheating prover with *same* total sum S but different vector\n", - "# ─────────────────────────────────────────────────────────────\n", "import random, math\n", "\n", - "# --- 1. Choose a fake vector with the same sum -----------------\n", + "# Choose a fake vector with the same sum \n", "S_real = sum(f_vec) # 36 for [1…8]\n", "\n", "print(\"Honest vector :\", f_vec)\n", @@ -504,7 +502,7 @@ "fake_tilde = sum(coeff * eq_tilde(bits(i, n), X)\n", " for i, coeff in enumerate(f_fake_same_sum))\n", "\n", - "# 2. Evaluate it at the verifier’s random challenges\n", + "# Evaluate it at the verifier’s random challenges\n", "poly_val = fake_tilde.subs({X[0]: alpha0,\n", " X[1]: alpha1,\n", " X[2]: alpha2})\n", @@ -516,7 +514,6 @@ "\n", "print(\"Total sum S :\", S_real, \"\\n\")\n", "\n", - "# --- 2. Helper routines (unchanged) ---------------------------\n", "def line_triplet(v0, v1):\n", " return (v0, v1, v0 + 2*(v1 - v0))\n", "\n", @@ -552,12 +549,10 @@ " math.isclose(leaf, h3[Ξ±2])\n", " )\n", "\n", - "# --- 3. Build transcripts -------------------------------------\n", "h1_h, h2_h, h3_h, Ξ±2_h, leaf_h = sumcheck_transcript(f_vec, alpha0, alpha1)\n", "h1_c, h2_c, h3_c, Ξ±2_c, leaf_c = sumcheck_transcript(f_fake_same_sum,\n", " alpha0, alpha1)\n", "\n", - "# --- 4. Verifier runs on both transcripts ---------------------\n", "print(\"Verifier challenges: Ξ±0 =\", alpha0, \"Ξ±1 =\", alpha1, \"Ξ±2 =\", Ξ±2_c)\n", "print(\"Honest leaf =\", leaf_h, \" Fake leaf =\", leaf_c, \"\\n\")\n", "\n", @@ -601,7 +596,6 @@ "print(\"Verifier result on HONEST transcript :\", ok_honest)\n", "print(\"Verifier result on FAKE transcript :\", ok_fake, \"\\n\")\n", "\n", - "# --- 5. Show they differ at another point ---------------------\n", "def eval_mle(evals, u):\n", " return sum(e*eq_tilde(bits_of(i,3), u) for i,e in enumerate(evals))\n", "\n", From 628cd0e47ae68feeca4e60bc2d7f4ed0163651ba Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Thu, 19 Jun 2025 16:51:42 +0530 Subject: [PATCH 04/11] feat: add mock pcs --- basefold/basefold-notebook.ipynb | 198 +++++++++++++++++++++++++------ 1 file changed, 163 insertions(+), 35 deletions(-) diff --git a/basefold/basefold-notebook.ipynb b/basefold/basefold-notebook.ipynb index 23b3a46..d20d25e 100644 --- a/basefold/basefold-notebook.ipynb +++ b/basefold/basefold-notebook.ipynb @@ -35,7 +35,7 @@ }, { "cell_type": "code", - "execution_count": 70, + "execution_count": 12, "id": "9103b2b6-97e0-4b15-bd4c-36c1203ab0c3", "metadata": {}, "outputs": [ @@ -46,17 +46,17 @@ "evaluations= [1, 2, 3, 4, 5, 6, 7, 8]\n", "MLE polynomial in evaluation form:\n", "\n", - "a[0] = 1 => term = 1*(-(X0 - 1)*(X1 - 1)*(X2 - 1))\n", - "a[1] = 2 => term = 2*((X0 - 1)*(X1 - 1)*X2)\n", - "a[2] = 3 => term = 3*((X0 - 1)*X1*(X2 - 1))\n", - "a[3] = 4 => term = 4*(-(X0 - 1)*X1*X2)\n", - "a[4] = 5 => term = 5*(X0*(X1 - 1)*(X2 - 1))\n", - "a[5] = 6 => term = 6*(-X0*(X1 - 1)*X2)\n", - "a[6] = 7 => term = 7*(-X0*X1*(X2 - 1))\n", - "a[7] = 8 => term = 8*(X0*X1*X2)\n", + "a[0] = 1 => term = 1*(-(x0 - 1)*(x1 - 1)*(x2 - 1))\n", + "a[1] = 2 => term = 2*((x0 - 1)*(x1 - 1)*x2)\n", + "a[2] = 3 => term = 3*((x0 - 1)*x1*(x2 - 1))\n", + "a[3] = 4 => term = 4*(-(x0 - 1)*x1*x2)\n", + "a[4] = 5 => term = 5*(x0*(x1 - 1)*(x2 - 1))\n", + "a[5] = 6 => term = 6*(-x0*(x1 - 1)*x2)\n", + "a[6] = 7 => term = 7*(-x0*x1*(x2 - 1))\n", + "a[7] = 8 => term = 8*(x0*x1*x2)\n", "\n", "Expanded polynomial:\n", - "4β‹…Xβ‚€ + 2β‹…X₁ + Xβ‚‚ + 1\n" + "4β‹…xβ‚€ + 2β‹…x₁ + xβ‚‚ + 1\n" ] }, { @@ -96,7 +96,12 @@ "f_vec = [1, 2, 3, 4, 5, 6, 7, 8] # f(0,0,0) … f(1,1,1)\n", "print(\"evaluations= \", f_vec)\n", "\n", - "X = sp.symbols(f'X0:{n}') # (X0, X1, X2)\n", + "n = 3\n", + "X0, X1, X2 = sp.symbols(f\"x0:{n}\") # good\n", + "X = (X0, X1, X2) # (X0, X1, X2)\n", + "\n", + "f_tilde = sum(coeff * eq_tilde(bits(i, n), X)\n", + " for i, coeff in enumerate(f_vec))\n", "\n", "def bits(i, n):\n", " \"Return i as an n-bit *list* (big-endian).\"\n", @@ -164,7 +169,7 @@ }, { "cell_type": "code", - "execution_count": 71, + "execution_count": 13, "id": "d6940fa4-99f2-4300-a5f6-35e20a5fbf3e", "metadata": {}, "outputs": [ @@ -183,9 +188,9 @@ }, { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAZcAAAGjCAYAAADgjVi2AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAA7pFJREFUeJzsfXd4HOW99ZnZviq76s3qlmRLcpdsSzbYEGxwgAABAgQIkEBIgOSSwOWGbvOZenMJ4YY4ELhgSAgklEBCDwFMcbd6771tUdm+OzvfH2LGu6uts6PdlZnzPH5As7Mz78zOvOf9tfMjaJqmIUCAAAECBPAIMtoDECBAgAABpx4EchEgQIAAAbxDIBcBAgQIEMA7BHIRIECAAAG8QyAXAQIECBDAOwRyESBAgAABvEMgFwECBAgQwDsEchEgQIAAAbxDIBcBAoLA4cOHsW7dOigUClx77bXRHo4AATGPbwy5vPDCCyAIwuu/22+/ndOx+vv7A+67fft2bN++ndugfYAgCOzevTvgfnV1ddi2bRtUKhUIgsATTzzB6zhCwejoKHbv3o36+voFn+3evRsEQUR+UH5wzz33IC8vD2KxGGq1GkVFRfjrX/+KO+64I2JjePXVV1FRUQGFQgGCIFBfX4/f//73eOGFFyI2BmD+GXZ9X+RyOcrLy7F3717YbLaIjoULCgoKgloQvPjii7j88stRVlYGkiRRUFCw6GM7lSGO9gAijeeffx4rVqxw25adnR2l0SwufvjDH8JoNOKVV15BUlJSVF+W0dFR7NmzBwUFBVi7dq3bZ9dffz3OOeec6AzMC9566y08+OCDuPvuu7Fr1y7IZDKkpaUhLS0tYiQ4NTWFq6++Gueccw5+//vfQyaTobS0FFdddRVSU1Mjbj0VFRXhz3/+Mzu2Z599Fvfeey8GBwfxzDPPRHQsi4WXXnoJ4+Pj2LhxI5xOJ+x2e7SHtKTxjSOXyspKVFVVRXsYEUFzczNuuOEG7Nq1K9pD8Ytly5Zh2bJl0R4Gi+bmZgDAz3/+c6Snp0dlDJ2dnbDb7bjqqquwbdu2RT0XTdOwWCxQKBQ+91EoFNi8eTP7965du1BeXo79+/fjySefhFwuX9QxRgIffPABSHLemXPeeeexz4EAbvjGuMWCxdtvv42amhoolUokJCRgx44dOHjwYMDv0TSNxx57DPn5+ZDL5Vi/fj3ee+89r/vOzs7i9ttvR2FhIaRSKXJycnDrrbfCaDQu2O+GG25ASkoK4uPjcc4556CzszPgWBi3ncPhwL59+1h3BuDbBeXN1VdQUIDzzjsP77//PtavXw+FQoEVK1bg//7v/xZ8f2RkBD/+8Y+Rm5sLqVSK7OxsXHLJJZiYmMCnn36K6upqAMB1113Hjodx7Xkbk9PpxGOPPYYVK1ZAJpMhPT0dP/jBDzA8POy23/bt21FZWYmjR4/itNNOg1KpRFFRER555BE4nc6A98oTBQUFuOeeewAAGRkZQbsgg8VHH32ECy64AMuWLYNcLsfy5ctx4403QqPRsPtce+212Lp1KwDgsssuA0EQ2L59OwoKCtDS0oLPPvuMvYeu1miwzxVBELjlllvwhz/8AStXroRMJsP+/ftDug6xWIy1a9fCZrNhenqa3W6xWHDnnXe6jeHmm29224cZg7f76unCYp7LTz75BD/96U+RmpqKlJQUfPe738Xo6Kjbd+12O+644w5kZmZCqVRi69atOHLkSNDXxBCLAH7wjbNcKIqCw+Fw2yYWz9+Gl19+GVdeeSV27tyJv/zlL7BarXjsscewfft2fPzxx+wL7w179uzBnj178KMf/QiXXHIJhoaGcMMNN4CiKJSVlbH7mUwmbNu2DcPDw7jrrruwevVqtLS04L777kNTUxP+9a9/gSAI0DSNCy+8EF999RXuu+8+VFdX48svvwzKCjn33HNx8OBB1NTU4JJLLsFtt93G8W4BDQ0NuO222/CrX/0KGRkZePbZZ/GjH/0Iy5cvx+mnnw5gnliqq6tht9vZa9Jqtfjggw+g1+uxfv16PP/887juuutwzz334NxzzwUAv9bKT3/6UzzzzDO45ZZbcN5556G/vx/33nsvPv30U5w4cQKpqansvuPj47jyyitx22234f7778ebb76JO++8E9nZ2fjBD34Q0vW++eabeOqpp/Dcc8/h/fffh0ql4tWq6unpQU1NDa6//nqoVCr09/fj8ccfx9atW9HU1ASJRIJ7770XGzduxM0334yHHnoIZ5xxBhITE2G1WnHJJZdApVLh97//PQBAJpMBCP65YvD3v/8dn3/+Oe677z5kZmZystD6+vqgVquRlpYGAOwz+/HHH+POO+/EaaedhsbGRtx///04ePAgDh48yI43VFx//fU499xz8fLLL2NoaAj/+Z//iauuugr//ve/2X1uuOEGvPjii7j99tuxY8cONDc347vf/S7m5uY4nVNAmKC/IXj++edpAF7/2e12mqIoOjs7m161ahVNURT7vbm5OTo9PZ2ura1dcKy+vj6apmlar9fTcrmcvuiii9zO+eWXX9IA6G3btrHbHn74YZokSfro0aNu+7722ms0APrdd9+laZqm33vvPRoA/dvf/tZtvwcffJAGQN9///0BrxkAffPNN7ttu//++2lvP7vnNdE0Tefn59NyuZweGBhgt5nNZjo5OZm+8cYb2W0//OEPaYlEQre2tvocy9GjR2kA9PPPP7/gM88xtbW10QDom266yW2/w4cP0wDou+66i922bds2GgB9+PBht33Ly8vps88+2+d4/IEZz9TUFLutq6uLTklJoRUKBS2TyeiUlBT6gw8+4HR8Bk6nk7bb7fTAwAANgH7rrbfYzz755BMaAP23v/3N7TsVFRVuzxODYJ8rmp5/LlQqFa3T6YIa57Zt2+iKigrabrfTdrudHhsbo++77z4aAP2HP/yB3e/999+nAdCPPfaY2/dfffVVGgD9zDPPuI3B2zOcn59PX3PNNezfzHPp+Sw89thjNAB6bGyMpumTz8wvfvELt/3+/Oc/0wDcjhkMzj33XDo/Pz+k7whwxzfODnzxxRdx9OhRt39isRgdHR0YHR3F1Vdf7WYex8fH4+KLL8ahQ4dgMpm8HvPgwYOwWCy48sor3bbX1tYiPz/fbds///lPVFZWYu3atXA4HOy/s88+GwRB4NNPPwUAfPLJJwCw4Jjf//73w70FIWHt2rXIy8tj/5bL5SgtLcXAwAC77b333sMZZ5yBlStX8nJO5to9g9YbN27EypUr8fHHH7ttz8zMxMaNG922rV692m2M4WL58uXQaDQwmUywWCzQaDTYuXNnyMeZnJzET37yE+Tm5kIsFkMikbDPSFtbG+fxBftcMTjzzDORlJQU9PFbWlogkUggkUiQlZWFBx54AHfeeSduvPFGdh/GivD83S699FLExcUt+N1CwXe+8x23v1evXg0A7G/s63353ve+x3omBEQW37i7vnLlSq8Bfa1WCwDIyspa8Fl2djacTif0ej2USqXP72ZmZi74zHPbxMQEuru7IZFIvI6P8b1rtVqIxWKkpKT4Pd5iw/P8wLwrxmw2s39PTU3x6joK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", + "image/png": "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", "text/plain": [ - "
" + "
" ] }, "metadata": {}, @@ -213,23 +218,38 @@ "for idx, val in enumerate(f_fold):\n", " print(f\" ({bits_of(idx,2)[0]}, {bits_of(idx,2)[1]}) β†’ {val}\")\n", "\n", - "from mpl_toolkits.mplot3d import Axes3D \n", + "import numpy as np\n", "import matplotlib.pyplot as plt\n", - "fig = plt.figure()\n", - "ax = fig.add_subplot(111, projection='3d')\n", - "xs, ys = zip(*[bits_of(i,2) for i in range(4)])\n", - "zs = f_fold\n", - "ax.bar3d(xs, ys, [0]*4, dx=0.2, dy=0.2, dz=zs, shade=True)\n", - "for (x, y), z in zip(zip(xs, ys), zs):\n", - " ax.text(x, y, z+0.2, f\"{z:.1f}\", ha='center')\n", - "ax.set_xlabel(\"X₁\"); ax.set_ylabel(\"Xβ‚‚\"); ax.set_zlabel(\"fΒΉ value\")\n", - "ax.set_title(\"Folded function fΒΉ after Round 1\")\n", + "\n", + "# Arrange f_fold = [f(0,0), f(1,0), f(0,1), f(1,1)] into a 2-by-2 matrix\n", + "grid = np.array([[f_fold[0], f_fold[1]],\n", + " [f_fold[2], f_fold[3]]])\n", + "\n", + "fig, ax = plt.subplots(figsize=(4, 4))\n", + "im = ax.imshow(grid,\n", + " cmap=\"Blues\",\n", + " origin=\"lower\", # (0,0) in the lower-left corner\n", + " extent=[-0.5, 1.5, -0.5, 1.5],\n", + " vmin=grid.min(), vmax=grid.max())\n", + "\n", + "# Annotate each cell with its numeric value\n", + "for (i, j), val in np.ndenumerate(grid):\n", + " ax.text(j, i, f\"{val:.0f}\",\n", + " ha=\"center\", va=\"center\", color=\"black\", fontsize=14)\n", + "\n", + "ax.set_xticks([0, 1])\n", + "ax.set_yticks([0, 1])\n", + "ax.set_xlabel(\"X₁\")\n", + "ax.set_ylabel(\"Xβ‚‚\")\n", + "ax.set_title(\"Folded function $f^{(1)}$ after Round 1\")\n", + "\n", + "plt.colorbar(im, shrink=0.75, label=\"value\")\n", "plt.show()\n" ] }, { "cell_type": "code", - "execution_count": 72, + "execution_count": 14, "id": "a9a40b6c-7751-4226-8a68-4ce664f5c709", "metadata": {}, "outputs": [ @@ -278,7 +298,7 @@ }, { "cell_type": "code", - "execution_count": 73, + "execution_count": 15, "id": "577e119b-6044-4c10-8a1d-81c93f97ca53", "metadata": {}, "outputs": [ @@ -340,7 +360,7 @@ }, { "cell_type": "code", - "execution_count": 74, + "execution_count": 16, "id": "230abf1e-76ee-49eb-bf37-8dc59f99faa3", "metadata": {}, "outputs": [ @@ -364,6 +384,8 @@ "f_tilde = sum(coeff * eq_tilde(bits(i, n), X)\n", " for i, coeff in enumerate(f_vec))\n", "\n", + "\n", + "\n", "# 2. Evaluate it at the verifier’s random challenges\n", "poly_val = f_tilde.subs({X[0]: alpha0,\n", " X[1]: alpha1,\n", @@ -411,7 +433,7 @@ }, { "cell_type": "code", - "execution_count": 69, + "execution_count": 37, "id": "0e9d5d91-e3a0-4984-9f3c-ecb19244e05c", "metadata": {}, "outputs": [ @@ -431,8 +453,8 @@ "\n", "Total sum S : 36 \n", "\n", - "Verifier challenges: Ξ±0 = 8 Ξ±1 = 2 Ξ±2 = 0\n", - "Honest leaf = 37 Fake leaf = -28 \n", + "Verifier challenges: Ξ±0 = 8 Ξ±1 = 2 Ξ±2 = 1\n", + "Honest leaf = 38 Fake leaf = -29 \n", "\n", "\n", "===== Verifier run on HONEST transcript =====\n", @@ -440,12 +462,12 @@ " h₁ values = (10, 26, 42) β‡’ h₁(X) = 10.0 + 16.0Β·X\n", " hβ‚‚ values = (67, 71, 75) β‡’ hβ‚‚(X) = 67.0 + 4.0Β·X\n", " h₃ values = (37, 38, 39) β‡’ h₃(X) = 37.0 + 1.0Β·X\n", - " leaf = 37 \n", + " leaf = 38 \n", "\n", "β‘  h₁(0)+h₁(1) = 36 vs S = 36 β†’ True\n", "β‘‘ hβ‚‚(0)+hβ‚‚(1) = 138 vs h₁(Ξ±β‚€) = 138 β†’ True\n", "β‘’ h₃(0)+h₃(1) = 75 vs hβ‚‚(α₁) = 75 β†’ True\n", - "β‘£ leaf = 37 vs h₃(Ξ±β‚‚) = 37 β†’ True\n", + "β‘£ leaf = 38 vs h₃(Ξ±β‚‚) = 38 β†’ True\n", "Result: βœ” PASSED\n", "\n", "===== Verifier run on FAKE transcript =====\n", @@ -453,12 +475,12 @@ " h₁ values = (26, 10, -6) β‡’ h₁(X) = 26.0 + -16.0Β·X\n", " hβ‚‚ values = (-49, -53, -57) β‡’ hβ‚‚(X) = -49.0 + -4.0Β·X\n", " h₃ values = (-28, -29, -30) β‡’ h₃(X) = -28.0 + -1.0Β·X\n", - " leaf = -28 \n", + " leaf = -29 \n", "\n", "β‘  h₁(0)+h₁(1) = 36 vs S = 36 β†’ True\n", "β‘‘ hβ‚‚(0)+hβ‚‚(1) = -102 vs h₁(Ξ±β‚€) = -102 β†’ True\n", "β‘’ h₃(0)+h₃(1) = -57 vs hβ‚‚(α₁) = -57 β†’ True\n", - "β‘£ leaf = -28 vs h₃(Ξ±β‚‚) = -28 β†’ True\n", + "β‘£ leaf = -29 vs h₃(Ξ±β‚‚) = -29 β†’ True\n", "Result: βœ” PASSED\n", "Verifier result on HONEST transcript : True\n", "Verifier result on FAKE transcript : True \n", @@ -606,10 +628,116 @@ " \"← different but still passed Sumcheck!\")\n" ] }, + { + "cell_type": "markdown", + "id": "cc740a07-eade-4056-93cc-88ac077c487b", + "metadata": {}, + "source": [ + "#### Why add a (mock) PCS?\n", + "\n", + "* **Problem:** Sumcheck only checks algebra; the verifier never sees the \n", + " evaluation vector **f**. A prover can swap in a different vector \n", + " **f_fake** after learning the challenges and still pass all four checks.\n", + "\n", + "* **PCS idea:** Prover first sends a digest `C = Hash(f)`. \n", + " After Sumcheck it must open **the same** digest together with the claimed\n", + " value `f(Ξ±β‚€,α₁,Ξ±β‚‚)`.\n", + "\n", + "* **Security:** \n", + " * Honest β†’ digest matches **and** value matches β†’ verifier accepts. \n", + " * Cheater β†’ digest mismatch (or wrong value) β†’ verifier rejects.\n", + "\n", + "The tiny SHA-256 PCS below demonstrates this: \n", + "`pcs_open` prints *why* it succeeds on the honest vector and fails on the\n", + "fake one." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "6c05abc5-efcb-413a-bda2-d9ad5045b65d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Honest evaluation vector : [1, 2, 3, 4, 5, 6, 7, 8]\n", + " Fake evaluation vector : [8, 7, 6, 5, 4, 3, 2, 1] (same Ξ£, different order)\n", + "\n", + "Honest commitment digest : b2ddd6543011e658aaebc223b42021e89fa9a18bd1f2207f6cb68e73ca5688b3\n", + "Fake commitment digest : 97c729b9b6163a0473bfc1d90d5bd4d8f03013dfaf2531be15f58065afe80e3f\n", + " Digests equal ? False \n", + "\n", + "[PCS] βœ” digest & value both correct\n", + "[PCS] digest mismatch (got b2ddd6543011…, expected 97c729b9b616… )\n", + "PCS-open on HONEST data : True\n", + "PCS-open on FAKE data : False \n", + " ← fails (digest mismatch)\n" + ] + } + ], + "source": [ + "\n", + "import hashlib, json, math\n", + "\n", + "def _canonical(evals):\n", + " return [int(x) for x in evals]\n", + "\n", + "def pcs_commit(evals):\n", + " blob = json.dumps(_canonical(evals), separators=(\",\", \":\")).encode()\n", + " return hashlib.sha256(blob).hexdigest()\n", + "\n", + "def pcs_open(evals, point, claimed_val, commitment, *, verbose=True):\n", + " \"\"\"\n", + " Return (all_ok, digest_ok, value_ok)\n", + " β€’ If verbose=True, print a one-line explanation whenever something fails.\n", + " \"\"\"\n", + " digest_ok = (pcs_commit(evals) == commitment)\n", + " if verbose and not digest_ok:\n", + " print(\"[PCS] digest mismatch \"\n", + " f\"(got {commitment[:12]}…, expected {pcs_commit(evals)[:12]}… )\")\n", + "\n", + " poly_val = sum(int(e) * eq_tilde(bits_of(i, 3), point)\n", + " for i, e in enumerate(evals))\n", + " value_ok = math.isclose(poly_val, claimed_val)\n", + " if verbose and digest_ok and not value_ok:\n", + " print(\"[PCS] value mismatch \"\n", + " f\"(claimed {claimed_val}, recomputed {poly_val})\")\n", + "\n", + " if verbose and digest_ok and value_ok:\n", + " print(\"[PCS] βœ” digest & value both correct\")\n", + "\n", + " return digest_ok and value_ok, digest_ok, value_ok\n", + "\n", + "# --------------------------------------------------------------\n", + "print(\" Honest evaluation vector :\", f_vec)\n", + "print(\" Fake evaluation vector :\", fake_vec, \"(same Ξ£, different order)\\n\")\n", + "\n", + "commit_honest = pcs_commit(f_vec)\n", + "commit_fake = pcs_commit(fake_vec)\n", + "print(\"Honest commitment digest :\", commit_honest)\n", + "print(\"Fake commitment digest :\", commit_fake)\n", + "print(\" Digests equal ? \", commit_honest == commit_fake, \"\\n\")\n", + "\n", + "query_pt = (alpha0, alpha1, Ξ±2_h) \n", + "leaf_h = eval_mle(f_vec , query_pt) \n", + "leaf_f = eval_mle(fake_vec, query_pt) \n", + "\n", + "\n", + "# ---------- verifier checks -----------------------------------\n", + "ok_honest, dig_honest, val_honest = pcs_open(f_vec , query_pt, leaf_h, commit_honest)\n", + "ok_fake , dig_fake , val_fake = pcs_open(fake_vec, query_pt, leaf_f, commit_honest)\n", + "\n", + "print(\"PCS-open on HONEST data :\", ok_honest)\n", + "print(\"PCS-open on FAKE data :\", ok_fake, \"\\n\",\n", + " \"← fails (digest mismatch)\")" + ] + }, { "cell_type": "code", "execution_count": null, - "id": "c79541df-4216-4277-8748-6d9d8883fda9", + "id": "79a1796e-0a4d-449e-972e-3bdee25691c2", "metadata": {}, "outputs": [], "source": [] From 66d26f63e7c28b530021232fbc316fb64d51417c Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Mon, 23 Jun 2025 15:31:38 +0530 Subject: [PATCH 05/11] feat: complete basefold notebook --- basefold/basefold-notebook.ipynb | 535 +++++++++++++++++++++++++++++-- 1 file changed, 504 insertions(+), 31 deletions(-) diff --git a/basefold/basefold-notebook.ipynb b/basefold/basefold-notebook.ipynb index d20d25e..618fcaf 100644 --- a/basefold/basefold-notebook.ipynb +++ b/basefold/basefold-notebook.ipynb @@ -35,7 +35,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 3, "id": "9103b2b6-97e0-4b15-bd4c-36c1203ab0c3", "metadata": {}, "outputs": [ @@ -89,6 +89,20 @@ "from mpl_toolkits.mplot3d import Axes3D \n", "\n", "\n", + "def bits(i, n):\n", + " \"Return i as an n-bit *list* (big-endian).\"\n", + " return list(map(int, format(i, f'0{n}b')))\n", + "\n", + "def bits_reverse(i, n):\n", + " \"Little-endian version (least-significant bit first).\"\n", + " return bits(i, n)[::-1]\n", + "\n", + "def eq_tilde(bits_i, u_vector):\n", + " result=1\n", + " for bit,u in zip(bits_i,u_vector):\n", + " result *= (1-bit)*(1-u) + bit*u\n", + " return result\n", + "\n", "def bits_of(i: int, n: int = 3):\n", " \"\"\"Return the n-bit little-endian tuple of i (e.g. 5 β†’ (1,0,1)).\"\"\"\n", " return tuple((i >> j) & 1 for j in range(n))\n", @@ -103,19 +117,6 @@ "f_tilde = sum(coeff * eq_tilde(bits(i, n), X)\n", " for i, coeff in enumerate(f_vec))\n", "\n", - "def bits(i, n):\n", - " \"Return i as an n-bit *list* (big-endian).\"\n", - " return list(map(int, format(i, f'0{n}b')))\n", - "\n", - "def bits_reverse(i, n):\n", - " \"Little-endian version (least-significant bit first).\"\n", - " return bits(i, n)[::-1]\n", - "\n", - "def eq_tilde(bits_i, u_vector):\n", - " result=1\n", - " for bit,u in zip(bits_i,u_vector):\n", - " result *= (1-bit)*(1-u) + bit*u\n", - " return result\n", "\n", "N = len(f_vec)\n", "\n", @@ -169,7 +170,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 4, "id": "d6940fa4-99f2-4300-a5f6-35e20a5fbf3e", "metadata": {}, "outputs": [ @@ -249,7 +250,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 5, "id": "a9a40b6c-7751-4226-8a68-4ce664f5c709", "metadata": {}, "outputs": [ @@ -298,7 +299,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 6, "id": "577e119b-6044-4c10-8a1d-81c93f97ca53", "metadata": {}, "outputs": [ @@ -360,7 +361,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 7, "id": "230abf1e-76ee-49eb-bf37-8dc59f99faa3", "metadata": {}, "outputs": [ @@ -433,7 +434,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 8, "id": "0e9d5d91-e3a0-4984-9f3c-ecb19244e05c", "metadata": {}, "outputs": [ @@ -453,8 +454,8 @@ "\n", "Total sum S : 36 \n", "\n", - "Verifier challenges: Ξ±0 = 8 Ξ±1 = 2 Ξ±2 = 1\n", - "Honest leaf = 38 Fake leaf = -29 \n", + "Verifier challenges: Ξ±0 = 8 Ξ±1 = 2 Ξ±2 = 0\n", + "Honest leaf = 38 Fake leaf = -28 \n", "\n", "\n", "===== Verifier run on HONEST transcript =====\n", @@ -475,12 +476,12 @@ " h₁ values = (26, 10, -6) β‡’ h₁(X) = 26.0 + -16.0Β·X\n", " hβ‚‚ values = (-49, -53, -57) β‡’ hβ‚‚(X) = -49.0 + -4.0Β·X\n", " h₃ values = (-28, -29, -30) β‡’ h₃(X) = -28.0 + -1.0Β·X\n", - " leaf = -29 \n", + " leaf = -28 \n", "\n", "β‘  h₁(0)+h₁(1) = 36 vs S = 36 β†’ True\n", "β‘‘ hβ‚‚(0)+hβ‚‚(1) = -102 vs h₁(Ξ±β‚€) = -102 β†’ True\n", "β‘’ h₃(0)+h₃(1) = -57 vs hβ‚‚(α₁) = -57 β†’ True\n", - "β‘£ leaf = -29 vs h₃(Ξ±β‚‚) = -29 β†’ True\n", + "β‘£ leaf = -28 vs h₃(Ξ±β‚‚) = -28 β†’ True\n", "Result: βœ” PASSED\n", "Verifier result on HONEST transcript : True\n", "Verifier result on FAKE transcript : True \n", @@ -654,7 +655,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 12, "id": "6c05abc5-efcb-413a-bda2-d9ad5045b65d", "metadata": {}, "outputs": [ @@ -710,35 +711,507 @@ "\n", " return digest_ok and value_ok, digest_ok, value_ok\n", "\n", - "# --------------------------------------------------------------\n", "print(\" Honest evaluation vector :\", f_vec)\n", - "print(\" Fake evaluation vector :\", fake_vec, \"(same Ξ£, different order)\\n\")\n", + "print(\" Fake evaluation vector :\", f_fake_same_sum, \"(same Ξ£, different order)\\n\")\n", "\n", "commit_honest = pcs_commit(f_vec)\n", - "commit_fake = pcs_commit(fake_vec)\n", + "commit_fake = pcs_commit(f_fake_same_sum)\n", "print(\"Honest commitment digest :\", commit_honest)\n", "print(\"Fake commitment digest :\", commit_fake)\n", "print(\" Digests equal ? \", commit_honest == commit_fake, \"\\n\")\n", "\n", "query_pt = (alpha0, alpha1, Ξ±2_h) \n", "leaf_h = eval_mle(f_vec , query_pt) \n", - "leaf_f = eval_mle(fake_vec, query_pt) \n", + "leaf_f = eval_mle(f_fake_same_sum, query_pt) \n", "\n", "\n", - "# ---------- verifier checks -----------------------------------\n", "ok_honest, dig_honest, val_honest = pcs_open(f_vec , query_pt, leaf_h, commit_honest)\n", - "ok_fake , dig_fake , val_fake = pcs_open(fake_vec, query_pt, leaf_f, commit_honest)\n", + "ok_fake , dig_fake , val_fake = pcs_open(f_fake_same_sum, query_pt, leaf_f, commit_honest)\n", "\n", "print(\"PCS-open on HONEST data :\", ok_honest)\n", "print(\"PCS-open on FAKE data :\", ok_fake, \"\\n\",\n", " \"← fails (digest mismatch)\")" ] }, + { + "cell_type": "markdown", + "id": "f2be416d-e19e-4389-a8a1-0a7d82447b5c", + "metadata": {}, + "source": [ + "#### Fact 1 β€” β€œEvaluation = Sum”\n", + "\n", + "For a multilinear-extension polynomial written in evaluation form:\n", + "\n", + "$$\n", + "\\tilde{f}(\\mathbf{X}) = \\sum_{i \\in {0,1}^n} a_i,E_i(\\mathbf{X}), \\quad\n", + "E_i(\\mathbf{X}) = \\prod_{j=0}^{n-1}\n", + "\\left( \\mathrm{bits}(i)_j,X_j + (1 - \\mathrm{bits}(i)_j)(1 - X_j) \\right)\n", + "$$\n", + "\n", + "a single point-evaluation can be rewritten as an inner product:\n", + "\n", + "$$\n", + "\\boxed{\n", + "\\tilde{f}(\\mathbf{u}) = \\sum_{i \\in {0,1}^n} a_i,\\underbrace{E_i(\\mathbf{u})}{=,eq(\\mathbf{u}, i)}\n", + "= \\left\\langle\n", + "\\underbrace{(a_0, \\dots, a{2^n - 1})}{f{\\text{vec}}},\n", + "\\underbrace{(eq(\\mathbf{u}, 0), \\dots, eq(\\mathbf{u}, 2^n - 1))}{w{\\text{vec}}}\n", + "\\right\\rangle\n", + "}\n", + "$$\n", + "\tβ€’\tLeft-hand side β€” the usual β€œplug-and-chug” evaluation.\n", + "\tβ€’\tRight-hand side β€” a length-$2^n$ sum, exactly the form the Sumcheck protocol can certify.\n", + "\n", + "βΈ»\n", + "\n", + "In the notebook below we will:\n", + "1. build the equality-function vector $w_{\\text{vec}}$ for the verifier’s random point $\\mathbf{u} = (\\alpha_0, \\alpha_1, \\alpha_2)$;\n", + "2.\tcompute the inner product $\\langle f_{\\text{vec}}, w_{\\text{vec}} \\rangle$;\n", + "3.\tshow it equals the direct polynomial value computed earlier.\n", + "\n", + "That makes the algebraic bridge between an MLE evaluation and a Sumcheck sum concrete." + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "id": "79a1796e-0a4d-449e-972e-3bdee25691c2", "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Full multilinear extension fΜƒ(Xβ‚€,X₁,Xβ‚‚):\n", + "Xβ‚€ + 2β‹…X₁ + 4β‹…Xβ‚‚ + 1\n", + "Verifier’s point u = (8, 2, 1) \n", + "\n", + " i bits f_vec[i] w[i] contribution f[i]Β·w[i]\n", + "─── ───── ───────── ───── ────────────────────────\n", + " 0 (0, 0, 0) 1 0 0\n", + " 1 (1, 0, 0) 2 0 0\n", + " 2 (0, 1, 0) 3 0 0\n", + " 3 (1, 1, 0) 4 0 0\n", + " 4 (0, 0, 1) 5 7 35\n", + " 5 (1, 0, 1) 6 -8 -48\n", + " 6 (0, 1, 1) 7 -14 -98\n", + " 7 (1, 1, 1) 8 16 128\n", + "\n", + "Ξ£ contributions = 17\n", + "Direct polynomial value fΜƒ(u) = 17\n", + "\n", + "βœ” fΜƒ(u) equals the length-8 inner product ⟨f_vec , w_vec⟩.\n" + ] + } + ], + "source": [ + "# Fact 1 : a single evaluation is an inner product \n", + "u_point = (alpha0, alpha1, alpha2) \n", + "\n", + "try:\n", + " _ = poly_honest \n", + "except NameError:\n", + " poly_honest = sp.expand(sum(\n", + " int(f) * eq_tilde(bits_of(i, 3), X) \n", + " for i, f in enumerate(f_vec)\n", + " ))\n", + "\n", + "print(\"\\nFull multilinear extension fΜƒ(Xβ‚€,X₁,Xβ‚‚):\")\n", + "sp.pretty_print(poly_honest)\n", + "\n", + "\n", + "# Build equality-function vector w (length 8)\n", + "w_vec = [eq_tilde(bits_of(i, 3), u_point) for i in range(8)]\n", + "\n", + "\n", + "print(\"Verifier’s point u =\", u_point, \"\\n\")\n", + "print(\" i bits f_vec[i] w[i] contribution f[i]Β·w[i]\")\n", + "print(\"─── ───── ───────── ───── ────────────────────────\")\n", + "\n", + "contribs = []\n", + "for i, (f, w) in enumerate(zip(f_vec, w_vec)):\n", + " c = f * w\n", + " contribs.append(c)\n", + " print(f\"{i:2} {bits_of(i,3)} {f:>2} {w:>5} {c:>6}\")\n", + "\n", + "inner_prod = sum(contribs)\n", + "poly_val = eval_mle(f_vec, u_point) # direct evaluation\n", + "\n", + "print(\"\\nΞ£ contributions =\", inner_prod)\n", + "print(\"Direct polynomial value fΜƒ(u) =\", poly_val)\n", + "\n", + "assert inner_prod == poly_val\n", + "print(\"\\nβœ” fΜƒ(u) equals the length-8 inner product ⟨f_vec , w_vec⟩.\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "858dc1e6-23b1-4765-a36b-5d279a772080", + "metadata": {}, + "source": [ + "#### Fact #2 β€” Sumcheck fold ≙ FRI split-fold\n", + "\n", + "At every round both protocols take a length-$2m$ vector, cut it into \n", + "`even` and `odd` halves, and compute:\n", + "\n", + "$$\n", + "\\texttt{fold}(\\alpha) = (1 - \\alpha)\\,\\texttt{even} + \\alpha\\,\\texttt{odd}\n", + "$$\n", + "\n", + "- **Sumcheck** uses it to reduce the multilinear inner-product dimension. \n", + "- **FRI** uses the *same* map to reduce a Reed–Solomon codeword.\n", + "\n", + "Below we fold the honest evaluation vector two ways:\n", + "\n", + "1. with the hand-written Sumcheck comprehension already in the notebook, \n", + "2. use folding code from `basefold_rs_pcs.py`, the helper the real \n", + " FRI implementation calls.\n", + "\n", + "They land on exactly the same 4-entry vector, confirming the equivalence." + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "id": "33d14510-0116-496a-b271-17686db6e6d0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "even = [1, 2, 3, 4]\n", + "odd = [5, 6, 7, 8]\n", + "Ξ± = 8 \n", + "\n", + "Sumcheck fold : [33, 34, 35, 36]\n", + "FRI fold : [33, 34, 35, 36] \n", + "\n", + "βœ” Identical output β‡’ both protocols share the very same linear map.\n" + ] + } + ], + "source": [ + "\n", + "\n", + "'''\n", + "The actual folding from the implementation itself : \n", + "\n", + " # fold f_code\n", + " f_code_folded = [(Field(1)-alpha) * (f_code[2*j] + f_code[2*j+1]) / 2 \n", + " + alpha * (f_code[2*j] - f_code[2*j+1]) / (2 * coset * twiddles[j]) \n", + " for j in range(len(f_code)//2)]\n", + "'''\n", + "\n", + "def fri_split_fold(even, odd, alpha):\n", + " \"\"\"\n", + " Return (1-alpha)*even + alpha*odd element-wise, exactly what FRI\n", + " does to halve a Reed–Solomon codeword. Works for plain lists of\n", + " field elements as used in this demo.\n", + " \"\"\"\n", + " return [(1 - alpha) * e + alpha * o for e, o in zip(even, odd)]\n", + "\n", + "\n", + "even = f_vec[:4] # indices 000,001,010,011 (Xβ‚€=0)\n", + "odd = f_vec[4:] # indices 100,101,110,111 (Xβ‚€=1)\n", + "Ξ± = alpha0 # verifier’s first challenge\n", + "\n", + "print(\"even =\", even)\n", + "print(\"odd =\", odd)\n", + "print(\"Ξ± =\", Ξ±, \"\\n\")\n", + "\n", + "# Sumcheck’s explicit comprehension\n", + "sumcheck_fold = [(1-Ξ±)*e + Ξ±*o for e, o in zip(even, odd)]\n", + "print(\"Sumcheck fold :\", sumcheck_fold)\n", + "\n", + "# FRI’s comprehension\n", + "pcs = BASEFOLD_RS_PCS(MerkleTree, debug=0)\n", + "fri_fold = fri_split_fold(even, odd, Ξ±) \n", + "print(\"FRI fold :\", fri_fold, \"\\n\")\n", + "\n", + "assert sumcheck_fold == fri_fold\n", + "print(\"βœ” Identical output β‡’ both protocols share the very same linear map.\")\n" + ] + }, + { + "cell_type": "markdown", + "id": "4d55cae0-4faa-4007-a6e4-612b0f6f562f", + "metadata": {}, + "source": [ + "### Step 4 β€” Gluing FRI + Sumcheck into *one* PCS\n", + "\n", + "**Goal:** prove the public statement $f(u) = v$ without revealing the \n", + "whole evaluation vector.\n", + "\n", + "---\n", + "\n", + "#### 1 Β· Re-phrase the claim\n", + "\n", + "- Pick the **same** random challenges \n", + " $\\alpha = (\\alpha_0, \\dots, \\alpha_{n-1})$ that will drive both \n", + " sub-protocols.\n", + "- Let $w := f(\\alpha)$.\n", + "\n", + "Now proving $f(u) = v$ is equivalent to proving these two facts:\n", + "\n", + "1. **FRI-fact** $f(\\alpha) = w$ \n", + "2. **Sumcheck-fact** $v = \\sum_b f(b) \\, eq(u, b)$\n", + "\n", + "---\n", + "\n", + "#### 2 Β· One transcript, two jobs\n", + "\n", + "| round | prover message | Ξ± used by |\n", + "|-------|----------------|-----------|\n", + "| commit | RS–codeword β†’ Merkle root $C_0$ | β€” |\n", + "| 0 | send $h_1$, fold with $\\alpha_0$ | FRI & Sumcheck |\n", + "| 1 | send $h_2$, fold with $\\alpha_1$ | FRI & Sumcheck |\n", + "| … | … | … |\n", + "| n | send $h_n$; open **one** code symbol = $w$ | FRI constant & Sumcheck leaf |\n", + "\n", + "- **FRI** + Merkle paths β‡’ verifier accepts $f(\\alpha) = w$ \n", + "- **Sumcheck**, fed with the *same* $\\alpha$’s and that single scalar \n", + " $w$, β‡’ verifier accepts $\\sum f(b) \\, eq(u, b) = v$ \n", + " β‡’ Algebra then forces $f(u) = v$\n", + "\n", + "---\n", + "\n", + "#### 3 Β· Soundness intuition\n", + "\n", + "Because every fold is checked **twice** (FRI *and* Sumcheck), a cheating \n", + "prover must satisfy both or be caught with probability \n", + "$\\approx 1 / |F|$ per round. The verifier inspects only \n", + "$O(\\log n)$ field elements.\n", + "\n", + "> **Shared randomness = one proof** \n", + "> FRI authenticates one hidden evaluation $w$; \n", + "> Sumcheck converts that single fact into the original claim \n", + "> $f(u) = v$." + ] + }, + { + "cell_type": "markdown", + "id": "aa44eb44-e722-4adb-9e3f-33fed95798d3", + "metadata": {}, + "source": [ + "### End-to-end picture for \\(n = 3\\)\n", + "\n", + "```mermaid\n", + "flowchart TD\n", + " %% Style tweaks\n", + " classDef b fill:#f0f0ff,stroke:#9aa;\n", + " classDef s fill:#fff8dc,stroke:#d9a;\n", + "\n", + " %% Commit phase\n", + " A0([\"**8-entry eval vector**
f = [1..8]\"]):::b\n", + " A1([\"Reed–Solomon encode β†’
codeword cβ‚€ (len = 8·ρ)\"]):::b\n", + " A2([\"Merkle-root
**Cβ‚€**\"]):::b\n", + "\n", + " A0 -->|encode| A1 -->|Merkle| A2\n", + " subgraph G1[ Prover side ]\n", + " A0;A1;A2\n", + " end\n", + "\n", + " %% Shared loop\n", + " B0((\"k = 3 rounds\")):::s\n", + "\n", + " %% Round boxes\n", + " R1[\"Round 0
split even/odd
fold with Ξ±β‚€\"]\n", + " R2[\"Round 1
split even/odd
fold with α₁\"]\n", + " R3[\"Round 2
split even/odd
fold with Ξ±β‚‚ (last)\"]\n", + "\n", + " %% Folding arrows\n", + " A2 --> R1 --> R2 --> R3\n", + "\n", + " %% Sumcheck track\n", + " subgraph Sumcheck[ Sumcheck track ]\n", + " direction LR\n", + " S8[\"f (8)\"]-->S4[\"fΒΉ (4)\"]-->S2[\"fΒ² (2)\"]-->S1[\"leaf (1)\"]\n", + " end\n", + "\n", + " %% FRI track\n", + " subgraph FRI[ FRI track ]\n", + " direction LR\n", + " C8[\"cβ‚€ (8·ρ)\"]-->C4[\"c₁\"]-->C2[\"cβ‚‚\"]-->C1[\"constant w\"]\n", + " end\n", + "\n", + " %% Ξ± arrows\n", + " R1 -- same Ξ±β‚€ --> C4 & S4\n", + " R2 -- same α₁ --> C2 & S2\n", + " R3 -- same Ξ±β‚‚ --> C1 & S1\n", + "\n", + " %% Verifier checks\n", + " V1[\"Merkle paths + FRI\\nβ‡’ accept f(Ξ±)=w?\"]:::b\n", + " V2[\"Sumcheck equalities\\nβ‡’ accept Ξ£f eq(u,Β·)=v?\"]:::b\n", + " C1 --> V1\n", + " S1 --> V2\n", + " V1 --> V2\n", + "\n", + " %% Final statement\n", + " V2 --> V3([\"βœ“ conclude f(u)=v\"]):::b\n" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "id": "f1087688-046d-4139-a924-eab7c09ea882", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Public claim : f([8, 2, 1]) = v = 17\n", + "\n", + "Commitment root : e219f04c2b44cc862b9b481e4db03e9e79d4b280b7e1ba860fcb683f3d7f5b1d …\n", + "\n", + "πŸ• Prover: generating proof …\n", + "P> f_len=8, k=3, c_len =64\n", + "P> check f0_code\n", + "P> check f0_code passed\n", + "P> Round 0\n", + "P> alpha[0] = 2117879509\n", + "P> Round 1\n", + "P> alpha[1] = 4293038735\n", + "P> Round 2\n", + "P> alpha[2] = 3383722775\n", + "P> final_sum(33557169405938763609452287200546002464000) = f(alpha_vec)*eq(alpha_vec), 24238848080 * 1384437465641261761208756550800\n", + "P> queries=22, query_indices=[[(6, 7), (2, 3), (0, 1)], [(50, 51), (24, 25), (12, 13)], [(40, 41), (20, 21), (10, 11)], [(12, 13), (6, 7), (2, 3)], [(8, 9), (4, 5), (2, 3)], [(24, 25), (12, 13), (6, 7)], [(62, 63), (30, 31), (14, 15)], [(4, 5), (2, 3), (0, 1)], [(54, 55), (26, 27), (12, 13)], [(58, 59), (28, 29), (14, 15)], [(28, 29), (14, 15), (6, 7)], [(46, 47), (22, 23), (10, 11)], [(42, 43), (20, 21), (10, 11)], [(52, 53), (26, 27), (12, 13)], [(30, 31), (14, 15), (6, 7)], [(2, 3), (0, 1), (0, 1)], [(34, 35), (16, 17), (8, 9)], [(38, 39), (18, 19), (8, 9)], [(48, 49), (24, 25), (12, 13)], [(10, 11), (4, 5), (2, 3)], [(0, 1), (0, 1), (0, 1)], [(44, 45), (22, 23), (10, 11)]]\n", + "check query_paths\n", + "P> check query_paths passed\n", + "P> check merkle_paths\n", + "P> roots=['e219f04c2b44cc862b9b481e4db03e9e79d4b280b7e1ba860fcb683f3d7f5b1d', '1503d2106cdb0d2affd6eb899e9bde549ea676c55e5bff722c94e5660cb49300', '84182f035d9dabf6e92a3a9800f58ce2ed327936dceb3a0431e394741c5824aa']\n", + "P>> check merkle_path-0 passed\n", + "P>> check merkle_path-1 passed\n", + "P>> check merkle_path-2 passed\n", + "P>> check merkle_path-3 passed\n", + "P>> check merkle_path-4 passed\n", + "P>> check merkle_path-5 passed\n", + "P>> check merkle_path-6 passed\n", + "P>> check merkle_path-7 passed\n", + "P>> check merkle_path-8 passed\n", + "P>> check merkle_path-9 passed\n", + "P>> check merkle_path-10 passed\n", + "P>> check merkle_path-11 passed\n", + "P>> check merkle_path-12 passed\n", + "P>> check merkle_path-13 passed\n", + "P>> check merkle_path-14 passed\n", + "P>> check merkle_path-15 passed\n", + "P>> check merkle_path-16 passed\n", + "P>> check merkle_path-17 passed\n", + "P>> check merkle_path-18 passed\n", + "P>> check merkle_path-19 passed\n", + "P>> check merkle_path-20 passed\n", + "P>> check merkle_path-21 passed\n", + "P> check merkle_paths passed\n", + "ℹ️ Proof generated.\n", + "\n", + "πŸ• Verifier: checking proof …\n", + "V> alpha[0] = 2117879509\n", + "V> alpha[1] = 4293038735\n", + "V> alpha[2] = 3383722775\n", + "V> len(codes)=2, queries=22\n", + "V> queries=22, query_indices=[[(6, 7), (2, 3), (0, 1)], [(50, 51), (24, 25), (12, 13)], [(40, 41), (20, 21), (10, 11)], [(12, 13), (6, 7), (2, 3)], [(8, 9), (4, 5), (2, 3)], [(24, 25), (12, 13), (6, 7)], [(62, 63), (30, 31), (14, 15)], [(4, 5), (2, 3), (0, 1)], [(54, 55), (26, 27), (12, 13)], [(58, 59), (28, 29), (14, 15)], [(28, 29), (14, 15), (6, 7)], [(46, 47), (22, 23), (10, 11)], [(42, 43), (20, 21), (10, 11)], [(52, 53), (26, 27), (12, 13)], [(30, 31), (14, 15), (6, 7)], [(2, 3), (0, 1), (0, 1)], [(34, 35), (16, 17), (8, 9)], [(38, 39), (18, 19), (8, 9)], [(48, 49), (24, 25), (12, 13)], [(10, 11), (4, 5), (2, 3)], [(0, 1), (0, 1), (0, 1)], [(44, 45), (22, 23), (10, 11)]]\n", + "V> check merkle_path-0 passed\n", + "V> check merkle_path-1 passed\n", + "V> check merkle_path-2 passed\n", + "V> check merkle_path-3 passed\n", + "V> check merkle_path-4 passed\n", + "V> check merkle_path-5 passed\n", + "V> check merkle_path-6 passed\n", + "V> check merkle_path-7 passed\n", + "V> check merkle_path-8 passed\n", + "V> check merkle_path-9 passed\n", + "V> check merkle_path-10 passed\n", + "V> check merkle_path-11 passed\n", + "V> check merkle_path-12 passed\n", + "V> check merkle_path-13 passed\n", + "V> check merkle_path-14 passed\n", + "V> check merkle_path-15 passed\n", + "V> check merkle_path-16 passed\n", + "V> check merkle_path-17 passed\n", + "V> check merkle_path-18 passed\n", + "V> check merkle_path-19 passed\n", + "V> check merkle_path-20 passed\n", + "V> check merkle_path-21 passed\n", + "V> check folding-0 passed\n", + "V> check folding-1 passed\n", + "V> check folding-2 passed\n", + "V> check folding-3 passed\n", + "V> check folding-4 passed\n", + "V> check folding-5 passed\n", + "V> check folding-6 passed\n", + "V> check folding-7 passed\n", + "V> check folding-8 passed\n", + "V> check folding-9 passed\n", + "V> check folding-10 passed\n", + "V> check folding-11 passed\n", + "V> check folding-12 passed\n", + "V> check folding-13 passed\n", + "V> check folding-14 passed\n", + "V> check folding-15 passed\n", + "V> check folding-16 passed\n", + "V> check folding-17 passed\n", + "V> check folding-18 passed\n", + "V> check folding-19 passed\n", + "V> check folding-20 passed\n", + "V> check folding-21 passed\n", + "βœ… Proof verified = True\n" + ] + } + ], + "source": [ + "# Basefold PCS demo (n = 3, f = [1…8]) \n", + "import basefold_rs_pcs as pcs_mod \n", + "from merlin.merlin_transcript import MerlinTranscript\n", + "from utils import inner_product \n", + "\n", + "Field = pcs_mod.Field \n", + "MerkleTree = pcs_mod.MerkleTree\n", + "BASEFOLD_RS_PCS = pcs_mod.BASEFOLD_RS_PCS\n", + "MLEPolynomial = pcs_mod.MLEPolynomial\n", + "\n", + "# public instance \n", + "evals = [Field(i) for i in range(1, 9)] # f = [1,2,3,4,5,6,7,8]\n", + "u_point = [Field(alpha0), Field(alpha1), Field(alpha2)] # the same α’s\n", + "\n", + "MLEPolynomial.set_field_type(Field)\n", + "f_mle = MLEPolynomial(evals, 3)\n", + "\n", + "# v = f(u)\n", + "eq_vec = MLEPolynomial.eqs_over_hypercube(u_point)\n", + "v_true = inner_product(evals, eq_vec, Field.zero())\n", + "assert f_mle.evaluate(u_point) == v_true\n", + "\n", + "print(f\"Public claim : f({u_point}) = v = {v_true}\\n\")\n", + "\n", + "# set-up prover / verifier objects \n", + "pcs = BASEFOLD_RS_PCS(MerkleTree, debug=2) \n", + "pcs.security_bits = 32 \n", + "tr = MerlinTranscript(b\"basefold-rs-demo\")\n", + "\n", + "# commitment\n", + "f_cm = pcs.commit(f_mle)\n", + "print(\"Commitment root :\", f_cm.cm, \"…\\n\")\n", + "\n", + "# prover produces argument \n", + "print(\"πŸ• Prover: generating proof …\")\n", + "v_proved, argument = pcs.prove_eval(f_cm, f_mle, u_point, tr.fork(b\"prove\"))\n", + "print(\"ℹ️ Proof generated.\\n\")\n", + "assert v_proved == v_true\n", + "\n", + "# verifier checks\n", + "print(\"πŸ• Verifier: checking proof …\")\n", + "ok = pcs.verify_eval(f_cm, u_point, v_true, argument, tr.fork(b\"verify\"))\n", + "print(\"βœ… Proof verified =\", ok)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "52da1a2b-4a92-495a-95d1-87a11ca146de", + "metadata": {}, "outputs": [], "source": [] } From 1dd74b514eb525c6957b4f3d57b14afc5bdd3920 Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Tue, 8 Jul 2025 09:00:17 +0530 Subject: [PATCH 06/11] add: montgomery reduction --- math/reductions/montgomery_reduction.ipynb | 455 +++++++++++++++++++++ 1 file changed, 455 insertions(+) create mode 100644 math/reductions/montgomery_reduction.ipynb diff --git a/math/reductions/montgomery_reduction.ipynb b/math/reductions/montgomery_reduction.ipynb new file mode 100644 index 0000000..62ce8a3 --- /dev/null +++ b/math/reductions/montgomery_reduction.ipynb @@ -0,0 +1,455 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "503b796f-b8c1-4ee2-aeaa-2ef437616e5b", + "metadata": {}, + "source": [ + "# Understanding Montgomery Reduction\n", + "\n", + "## 1. Introduction: The Problem with Modular Division\n", + "\n", + "Modular arithmetic often involves computing remainders: for integers `a` and `n`, we find `q` and `r` such that:\n", + "\n", + "$$\n", + "a = qn + r,\\quad \\text{where} \\quad 0 \\leq r < |n|\n", + "$$\n", + "\n", + "Here, `r = a mod n`. While this is straightforward for small numbers, it becomes inefficient at scale, especially in cryptographic computations with large integers.\n", + "\n", + "For example, to compute:\n", + "\n", + "$$\n", + "(12 \\times 15) \\mod 7 = ((12 \\mod 7) \\times (15 \\mod 7)) \\mod 7 \\\\\n", + "= (5 \\times 1) \\mod 7 \\\\\n", + "= 5\n", + "$$\n", + "\n", + "We still need to perform `mod` operations (i.e., division), which are costly for large numbers. Since cryptographic systems rely heavily on modular multiplication, this repeated division becomes a bottleneck.\n", + "\n", + "**Montgomery reduction** addresses this by avoiding direct division, making modular multiplication more efficient for large integers." + ] + }, + { + "cell_type": "markdown", + "id": "aa5f36b9-54ca-47e9-9f67-8ebd469bfa9b", + "metadata": {}, + "source": [ + "## 2. The Core Idea: A New Domain for Faster Math\n", + "\n", + "Montgomery reduction speeds up modular arithmetic by moving calculations into a special **Montgomery domain**, avoiding costly division by `n`.\n", + "\n", + "This is done using a new modulus `R`, typically a power of 2 (like $2^{32}$ or $2^{64}$).\n", + "\n", + "### Why Use a Power of 2?\n", + "\n", + "Because computers handle powers of 2 efficiently:\n", + "\n", + "- **Division by `R`** β†’ simple **right shift**\n", + "- **Modulo `R`** β†’ fast **bitwise AND**\n", + "\n", + "This makes reductions much faster than regular division." + ] + }, + { + "cell_type": "markdown", + "id": "d4d16a4d-3090-4f68-b70f-fbde01fba594", + "metadata": {}, + "source": [ + "## 3. The Montgomery Algorithm: Setup and Multiplication\n", + "\n", + "With `R` as a power of 2, we set up the Montgomery system through a one-time preparation:\n", + "\n", + "### Setup Phase\n", + "\n", + "1. **Choose `R`**: \n", + " A power of 2 greater than `n`, enabling fast bitwise operations.\n", + "\n", + "2. **Compute $R^{-1}$**: \n", + " The modular inverse of `R` such that:\n", + "\n", + " $$\n", + " R \\cdot R^{-1} \\equiv 1 \\pmod{n}\n", + " $$\n", + "\n", + "3. **Compute `n'`**: \n", + " The modular inverse of `-n` modulo `R`, satisfying:\n", + "\n", + " $$\n", + " -n \\cdot n' \\equiv 1 \\pmod{R}\n", + " $$\n", + "\n", + "The values $R^{-1}$ and `n'` are precomputed once and used in all Montgomery operations." + ] + }, + { + "cell_type": "markdown", + "id": "ba12b99a-ca17-48dd-bb04-017d667bf186", + "metadata": {}, + "source": [ + "\n", + "### Conversion to Montgomery Form\n", + "\n", + "To work in the Montgomery domain, convert a number `a` to its Montgomery form `a'`:\n", + "\n", + "$$\n", + "a' = a \\cdot R \\pmod{n}\n", + "$$\n", + "\n", + "This step is a one-time, regular modular multiplicationβ€”our \"entry fee\" to faster computation.\n", + "\n", + "\n", + "### Multiplication in the Montgomery Domain\n", + "\n", + "Given `a'` and `b'` in Montgomery form, their product `c'` is:\n", + "\n", + "$$\n", + "c' = a' \\cdot b' \\cdot R^{-1} \\pmod{n}\n", + "$$\n", + "\n", + "While this still looks like it needs division by `n`, the **Montgomery Reduction (`REDC`)** algorithm efficiently handles this without actual division." + ] + }, + { + "cell_type": "markdown", + "id": "59f08ff6-4d46-4f3e-84d2-e9bf3ceadcbc", + "metadata": {}, + "source": [ + "## 4. The REDC Algorithm and Final Conversion\n", + "\n", + "To compute the Montgomery product \n", + "`c' = a' Β· b' Β· R⁻¹ mod(n)`, \n", + "we use the **`REDC`** function, which efficiently calculates \n", + "$T \\cdot R^{-1} \\mod n$ \n", + "for $T = a' \\cdot b'$.\n", + "\n", + "### The `REDC` Algorithm\n", + "\n", + "1. **Compute `m`:**\n", + "\n", + " $$\n", + " m = T \\bmod R \\cdot n’ \\bmod R\n", + " $$\n", + "\n", + "2. **Compute `t`:**\n", + "\n", + " $$\n", + " t = \\frac{T + m \\cdot n}{R}\n", + " $$\n", + "\n", + "3. **Final correction:**\n", + "\n", + " $$\n", + " \\text{If } t \\geq n, \\quad \\text{then } t = t - n\n", + " $$\n", + "\n", + "4. **Return `t` as the result.**\n", + "\n", + "The speed boost comes from dividing by `R` (a power of 2), which is just a fast bit shift.\n", + "\n", + "\n", + "### Conversion Back to Standard Form\n", + "\n", + "After all operations, the result `c'` is still in Montgomery form. \n", + "To convert back, apply one last `REDC`:\n", + "\n", + "$$\n", + "c = \\text{REDC}(c')\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "7ae90724-de55-420a-a930-206cd19f293f", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "System Initialized for n=13\n", + "Calculated R=16, n'=11\n", + "------------------------------\n", + "7 in Montgomery form is: 8\n", + "8 in Montgomery form is: 11\n", + "------------------------------\n", + "Intermediate product T = 8 * 11 = 88\n", + "REDC(T) -> Product in Montgomery form: 12\n", + "------------------------------\n", + "Final Result (after converting back): 4\n", + "Standard Check: (7 * 8) % 13 = 4\n" + ] + } + ], + "source": [ + "class Montgomery:\n", + " def __init__(self, n):\n", + " if n % 2 == 0:\n", + " raise ValueError(\"Modulus n must be odd.\")\n", + " \n", + " self.n = n\n", + " self.logR = n.bit_length()\n", + " self.R = 1 << self.logR\n", + " self.R_mask = self.R - 1\n", + " \n", + " n_inv_R = self._modinv(self.n, self.R)\n", + " self.n_prime = self.R - n_inv_R\n", + "\n", + " def _egcd(self, a, b):\n", + " if a == 0:\n", + " return (b, 0, 1)\n", + " g, y, x = self._egcd(b % a, a)\n", + " return (g, x - (b // a) * y, y)\n", + "\n", + " def _modinv(self, a, m):\n", + " g, x, y = self._egcd(a, m)\n", + " if g != 1:\n", + " raise ValueError('Modular inverse does not exist')\n", + " return x % m\n", + " \n", + " def _reduce(self, T):\n", + " m = ((T & self.R_mask) * self.n_prime) & self.R_mask\n", + " t = (T + m * self.n) >> self.logR\n", + " \n", + " if t >= self.n:\n", + " return t - self.n\n", + " else:\n", + " return t\n", + "\n", + " def convert_in(self, x):\n", + " return (x * self.R) % self.n\n", + "\n", + " def convert_out(self, x_mont):\n", + " return self._reduce(x_mont)\n", + "\n", + " def multiply(self, a_mont, b_mont):\n", + " T = a_mont * b_mont\n", + " return self._reduce(T), T\n", + "\n", + "# --- Usage Example ---\n", + "# 1. One-time setup\n", + "monty_system = Montgomery(n=13)\n", + "print(f\"System Initialized for n={monty_system.n}\")\n", + "print(f\"Calculated R={monty_system.R}, n'={monty_system.n_prime}\")\n", + "print(\"-\" * 30)\n", + "\n", + "# 2. Convert numbers to Montgomery form\n", + "a = 7\n", + "b = 8\n", + "a_mont = monty_system.convert_in(a)\n", + "b_mont = monty_system.convert_in(b)\n", + "print(f\"{a} in Montgomery form is: {a_mont}\")\n", + "print(f\"{b} in Montgomery form is: {b_mont}\")\n", + "print(\"-\" * 30)\n", + "\n", + "# 3. Perform multiplication in the Montgomery domain\n", + "product_mont, intermediate_T = monty_system.multiply(a_mont, b_mont)\n", + "print(f\"Intermediate product T = {a_mont} * {b_mont} = {intermediate_T}\")\n", + "print(f\"REDC(T) -> Product in Montgomery form: {product_mont}\")\n", + "print(\"-\" * 30)\n", + "\n", + "# 4. Convert the result back to a standard number\n", + "final_result = monty_system.convert_out(product_mont)\n", + "print(f\"Final Result (after converting back): {final_result}\")\n", + "print(f\"Standard Check: (7 * 8) % 13 = {(7 * 8) % 13}\")" + ] + }, + { + "cell_type": "markdown", + "id": "0f157745-ee68-40a8-aab4-74f51d754242", + "metadata": {}, + "source": [ + "---\n", + "\n", + "### A Quick Clarification: Why Does Montgomery Seem Slower at First?\n", + "\n", + "> **Question:** \n", + "> Montgomery starts with divisions like 112 mod 13 or 128 mod 13, which look slower than a simple 56 mod 13. So why is it still preferredβ€”and actually fasterβ€”when working with large numbers?\n", + "\n", + "For a single, small calculation, the setup cost of Montgomery reduction makes it **slower** than the standard method. \n", + "\n", + "The performance boost isn’t for one-off calculations; it’s for **chains of multiplications** performed with the same modulus, which is extremely common in cryptography. The classic use case is **modular exponentiation** (`a^e mod n`), which is the core of RSA and the example we will explore next." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "1f505948-24e8-4bfa-9c27-2b89cf349bc8", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "--- Starting Standard Modular Exponentiation ---\n", + "Executing for exponent 10 (binary: 1010)\n", + "\n", + "Step 1 (Square): (1*1) % 13 -> 1 (EXPENSIVE)\n", + "Step 1 (Mult): (1*5) % 13 -> 5 (EXPENSIVE)\n", + "Step 2 (Square): (5*5) % 13 -> 12 (EXPENSIVE)\n", + "Step 3 (Square): (12*12) % 13 -> 1 (EXPENSIVE)\n", + "Step 3 (Mult): (1*5) % 13 -> 5 (EXPENSIVE)\n", + "Step 4 (Square): (5*5) % 13 -> 12 (EXPENSIVE)\n", + "\n", + "Final Result: 12\n", + "Total Expensive (mod n) Operations: 6\n", + "\n", + "==================================================\n", + "--- Starting Montgomery Modular Exponentiation ---\n", + "Step 1: Setup & Initial Conversion\n", + " - Converting 1 -> 3 (EXPENSIVE OP #1)\n", + " - Converting 5 -> 2 (EXPENSIVE OP #2)\n", + "\n", + "Step 2: Main loop with FAST operations\n", + "Loop 1 (Square): REDC(3*3) -> 3 (FAST)\n", + "Loop 1 (Mult): REDC(3*2) -> 2 (FAST)\n", + "Loop 2 (Square): REDC(2*2) -> 10 (FAST)\n", + "Loop 3 (Square): REDC(10*10) -> 3 (FAST)\n", + "Loop 3 (Mult): REDC(3*2) -> 2 (FAST)\n", + "Loop 4 (Square): REDC(2*2) -> 10 (FAST)\n", + "\n", + "Step 3: Final conversion -> REDC(10) -> 12 (FAST)\n", + "\n", + "Final Result: 12\n", + "Total Expensive (mod n) Operations: 2\n", + "\n" + ] + } + ], + "source": [ + "# Re-using our clean Montgomery class\n", + "class Montgomery:\n", + " def __init__(self, n):\n", + " if n % 2 == 0: raise ValueError(\"Modulus n must be odd.\")\n", + " self.n = n\n", + " self.logR = n.bit_length()\n", + " self.R = 1 << self.logR\n", + " self.R_mask = self.R - 1\n", + " n_inv_R = self._modinv(self.n, self.R)\n", + " self.n_prime = self.R - n_inv_R\n", + "\n", + " def _egcd(self, a, b):\n", + " if a == 0: return (b, 0, 1)\n", + " g, y, x = self._egcd(b % a, a)\n", + " return (g, x - (b // a) * y, y)\n", + "\n", + " def _modinv(self, a, m):\n", + " g, x, y = self._egcd(a, m)\n", + " if g != 1: raise ValueError('Modular inverse does not exist')\n", + " return x % m\n", + " \n", + " def _reduce(self, T):\n", + " m = ((T & self.R_mask) * self.n_prime) & self.R_mask\n", + " t = (T + m * self.n) >> self.logR\n", + " return t - self.n if t >= self.n else t\n", + "\n", + " def convert_in(self, x):\n", + " return (x * self.R) % self.n\n", + "\n", + " def convert_out(self, x_mont):\n", + " return self._reduce(x_mont)\n", + "\n", + " def multiply(self, a_mont, b_mont):\n", + " return self._reduce(a_mont * b_mont)\n", + "\n", + "# --- Method 1: Standard Exponentiation Trace ---\n", + "def trace_standard_pow_clean(base, exp, mod):\n", + " print(\"--- Starting Standard Modular Exponentiation ---\")\n", + " expensive_ops = 0\n", + " res = 1\n", + " binary_exp = bin(exp)[2:]\n", + " print(f\"Executing for exponent {exp} (binary: {binary_exp})\\n\")\n", + " \n", + " for i, bit in enumerate(binary_exp):\n", + " # Squaring step\n", + " res_old = res\n", + " res = (res * res) % mod\n", + " expensive_ops += 1\n", + " print(f\"Step {i+1} (Square): ({res_old}*{res_old}) % {mod} -> {res} (EXPENSIVE)\")\n", + " \n", + " # Multiplication step if bit is 1\n", + " if bit == '1':\n", + " res_old = res\n", + " res = (res * base) % mod\n", + " expensive_ops += 1\n", + " print(f\"Step {i+1} (Mult): ({res_old}*{base}) % {mod} -> {res} (EXPENSIVE)\")\n", + " \n", + " print(f\"\\nFinal Result: {res}\")\n", + " print(f\"Total Expensive (mod n) Operations: {expensive_ops}\\n\")\n", + "\n", + "# --- Method 2: Montgomery Exponentiation Trace ---\n", + "def trace_montgomery_pow_clean(base, exp, n):\n", + " print(\"--- Starting Montgomery Modular Exponentiation ---\")\n", + " expensive_ops = 0\n", + " \n", + " # 1. Setup & Conversion\n", + " print(\"Step 1: Setup & Initial Conversion\")\n", + " monty = Montgomery(n)\n", + " res_mont = monty.convert_in(1)\n", + " expensive_ops += 1\n", + " base_mont = monty.convert_in(base)\n", + " expensive_ops += 1\n", + " print(f\" - Converting 1 -> {res_mont} (EXPENSIVE OP #{expensive_ops-1})\")\n", + " print(f\" - Converting {base} -> {base_mont} (EXPENSIVE OP #{expensive_ops})\\n\")\n", + "\n", + " # 2. Main Loop\n", + " print(\"Step 2: Main loop with FAST operations\")\n", + " binary_exp = bin(exp)[2:]\n", + " for i, bit in enumerate(binary_exp):\n", + " # Squaring step\n", + " res_old = res_mont\n", + " res_mont = monty.multiply(res_mont, res_mont)\n", + " print(f\"Loop {i+1} (Square): REDC({res_old}*{res_old}) -> {res_mont} (FAST)\")\n", + "\n", + " # Multiplication step if bit is 1\n", + " if bit == '1':\n", + " res_old = res_mont\n", + " res_mont = monty.multiply(res_mont, base_mont)\n", + " print(f\"Loop {i+1} (Mult): REDC({res_old}*{base_mont}) -> {res_mont} (FAST)\")\n", + "\n", + " # 3. Final Conversion\n", + " final_res = monty.convert_out(res_mont)\n", + " print(f\"\\nStep 3: Final conversion -> REDC({res_mont}) -> {final_res} (FAST)\")\n", + " \n", + " print(f\"\\nFinal Result: {final_res}\")\n", + " print(f\"Total Expensive (mod n) Operations: {expensive_ops}\\n\")\n", + "\n", + "# --- Run the cleaned traces ---\n", + "base, exp, mod = 5, 10, 13\n", + "trace_standard_pow_clean(base, exp, mod)\n", + "print(\"=\"*50)\n", + "trace_montgomery_pow_clean(base, exp, mod)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b1d3e449-981e-4ce6-a671-7b0f221e8090", + "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.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From dadafd3518197ee5a21587b07ad36e63530ce204 Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Wed, 9 Jul 2025 23:11:59 +0530 Subject: [PATCH 07/11] complete montgomery reduction --- math/reductions/montgomery_reduction.ipynb | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/math/reductions/montgomery_reduction.ipynb b/math/reductions/montgomery_reduction.ipynb index 62ce8a3..b05014c 100644 --- a/math/reductions/montgomery_reduction.ipynb +++ b/math/reductions/montgomery_reduction.ipynb @@ -160,7 +160,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 17, "id": "7ae90724-de55-420a-a930-206cd19f293f", "metadata": {}, "outputs": [ @@ -260,7 +260,6 @@ "id": "0f157745-ee68-40a8-aab4-74f51d754242", "metadata": {}, "source": [ - "---\n", "\n", "### A Quick Clarification: Why Does Montgomery Seem Slower at First?\n", "\n", @@ -274,7 +273,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 18, "id": "1f505948-24e8-4bfa-9c27-2b89cf349bc8", "metadata": {}, "outputs": [ From dd028bc1064dc8c9837778753ab9b59fb450e75f Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Fri, 11 Jul 2025 05:15:42 +0530 Subject: [PATCH 08/11] add : logjump-reduction: v0.1 --- math/reductions/logjump_reduction.ipynb | 648 ++++++++++++++++++++++++ 1 file changed, 648 insertions(+) create mode 100644 math/reductions/logjump_reduction.ipynb diff --git a/math/reductions/logjump_reduction.ipynb b/math/reductions/logjump_reduction.ipynb new file mode 100644 index 0000000..9ddcd74 --- /dev/null +++ b/math/reductions/logjump_reduction.ipynb @@ -0,0 +1,648 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "94dcfbef-b060-47dc-93d9-2ce73a6d8a75", + "metadata": {}, + "source": [ + "# LogJump vs. Classic Montgomery Reduction \n", + "*measuring raw throughput for 256-bit inputs*\n", + "\n", + "In this notebook we **import the reference implementations** of \n", + "\n", + "* `mont_redc`  β€“ classic word-by-word Montgomery reduction \n", + "* `mul_logjumps_sos`  β€“ the LogJump/SOS optimisation \n", + "\n", + "then benchmark them side-by-side.\n", + "\n", + "**What we do**\n", + "\n", + "1. pre-generate a list of 10 000 random 256-bit integers (`xs`), \n", + "2. run each algorithm over that fixed list multiple times with\n", + " `timeit.repeat`, \n", + "3. take the **best** run to minimise Python-overhead noise, \n", + "4. report average nanoseconds per call and the resulting speed-up.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 214, + "id": "7e803d2e-e161-4a9f-b130-5eee32d0407b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[FIELD] secp256k1 prime (bit-length = 256)\n", + "ΞΌ (βˆ’p⁻¹ mod 2^64): 0xd838091dd2253531\n", + "ρ (inverse 2⁢⁴ mod p) limbs: ['0xffffffff27c7f3a9', '0xffffffffffffffff', '0xffffffffffffffff', '0xd838091dd2253530']\n" + ] + } + ], + "source": [ + "# ──────────────────────────────────────────────────────────────────────────────\n", + "# Constants cell 2.0 – pick your field with a one-liner switch\n", + "# Supported: 'secp256k1' (default) Β· 'p256' Β· 'bn254'\n", + "# NOTE: all downstream code is hard-wired for n = 4 limbs (≀ 256 bits)\n", + "# ──────────────────────────────────────────────────────────────────────────────\n", + "import math\n", + "from typing import List, Tuple\n", + "\n", + "WORD_BITS = 64\n", + "MASK = (1 << WORD_BITS) - 1 # 0xFFFF_FFFF_FFFF_FFFF\n", + "\n", + "# ⇩ Toggle the field you want to benchmark\n", + "FIELD = \"secp256k1\" # {'secp256k1', 'p256', 'bn254'}\n", + "\n", + "# ----------------------------------------------------------------------------- \n", + "# Prime table (hex strings for readability)\n", + "# -----------------------------------------------------------------------------\n", + "_PRIMES = {\n", + " \"secp256k1\": \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F\",\n", + " \"p256\" : \"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF\",\n", + " \"bn254\" : \"30644E72E131A029B85045B68181585D97816A916871CA8D3C208C16D87CFD47\",\n", + "}\n", + "\n", + "try:\n", + " P_HEX = _PRIMES[FIELD.lower()]\n", + "except KeyError:\n", + " raise ValueError(f\"Unsupported FIELD tag {FIELD!r}. Choose from {_PRIMES.keys()}\")\n", + "\n", + "P = int(P_HEX, 16) # modulus as int\n", + "N = 4 # limb count (n=4 hard-wired below)\n", + "\n", + "# ----------------------------------------------------------------------------- \n", + "# Pack / unpack helpers (little-endian limb order)\n", + "# -----------------------------------------------------------------------------\n", + "def to_words(x: int, n_words: int = N) -> List[int]:\n", + " return [(x >> (WORD_BITS * i)) & MASK for i in range(n_words)]\n", + "\n", + "def from_words(words: List[int]) -> int:\n", + " return sum(w << (WORD_BITS * i) for i, w in enumerate(words))\n", + "\n", + "# ----------------------------------------------------------------------------- \n", + "# Multi-precision helpers for mont_redc (gte & sub stay unchanged)\n", + "# -----------------------------------------------------------------------------\n", + "def gte(a: List[int], b: List[int]) -> bool:\n", + " for i in reversed(range(len(a))):\n", + " if a[i] != b[i]:\n", + " return a[i] > b[i]\n", + " return True # equal\n", + "\n", + "def sub(a: List[int], b: List[int]) -> List[int]:\n", + " out, borrow = [], 0\n", + " for ai, bi in zip(a, b):\n", + " t = ai - bi - borrow\n", + " if t < 0:\n", + " t += 1 << WORD_BITS\n", + " borrow = 1\n", + " else:\n", + " borrow = 0\n", + " out.append(t & MASK)\n", + " return out\n", + "\n", + "# ----------------------------------------------------------------------------- \n", + "# Montgomery constants ΞΌ and ρ (re-computed for the chosen field)\n", + "# -----------------------------------------------------------------------------\n", + "MU = (-pow(P, -1, 1 << WORD_BITS)) & MASK # βˆ’p⁻¹ (mod 2⁢⁴)\n", + "RHO = pow(2, -WORD_BITS, P) # 2⁻⁢⁴ (mod p)\n", + "\n", + "# ρ and p as limb arrays (pad to 5 limbs to satisfy calc_m / mont_redc loops)\n", + "RHO_WORDS = to_words(RHO, N) + [0] # length 5\n", + "P_WORDS = to_words(P, N) + [0] # length 5\n", + "\n", + "# ----------------------------------------------------------------------------- \n", + "# Friendly banner so you *know* which field the notebook is using\n", + "# -----------------------------------------------------------------------------\n", + "print(f\"[FIELD] {FIELD} prime (bit-length = {P.bit_length()})\")\n", + "print(f\"ΞΌ (βˆ’p⁻¹ mod 2^{WORD_BITS}): {hex(MU)}\")\n", + "print(\"ρ (inverse 2⁢⁴ mod p) limbs:\", [hex(w) for w in RHO_WORDS[:N]])\n" + ] + }, + { + "cell_type": "markdown", + "id": "92fd39be-b31f-4344-9d9b-6c9cd0aedad4", + "metadata": {}, + "source": [ + "## Classic Montgomery REDC \n", + "\n", + "Montgomery reduction rewrites a 2Β·*n*-word integer\n", + "\n", + "$$\n", + "c = t = \\sum_{i=0}^{2n-1} t_i \\cdot 2^{64i}\n", + "$$\n", + "\n", + "into an *n*-word residue \n", + "$t \\cdot R^{-1} \\bmod p$ with \n", + "\n", + "- $R = 2^{64n}$ (so $R \\equiv 0 \\pmod{p}$),\n", + "- a single-word constant $\\mu = -p^{-1} \\pmod{2^{64}}$.\n", + "\n", + "The outer loop runs **once per limb** (`i = 0 … nβˆ’1`):\n", + "\n", + "1. Pick $q = (t[i] \\cdot \\mu) \\bmod 2^{64}$ β†’ forces \n", + " $t[i] + q \\cdot p \\equiv 0 \\pmod{2^{64}}$;\n", + "2. Add $q \\cdot p$ into the running array (two inner loops);\n", + "3. After the loop, the first *n* limbs are guaranteed zero \n", + " β†’ drop them (divide by $R$);\n", + "4. Final conditional subtraction ensures the result $< p$.\n", + "\n", + "The code below is a pseudocode, parameterised by the constants we set up in the previous cell." + ] + }, + { + "cell_type": "code", + "execution_count": 215, + "id": "8eff43c3-f0a4-47fe-9b0c-221b98637da8", + "metadata": {}, + "outputs": [], + "source": [ + "def mont_redc(c_words: List[int]) -> List[int]:\n", + " \"\"\"\n", + " Classic Montgomery reduction, limb-for-limb.\n", + " Expects c_words to have length 2*N (little-endian).\n", + " Returns an n-word little-endian list < p.\n", + " \"\"\"\n", + " assert len(c_words) == 2 * N\n", + " t = c_words.copy()\n", + "\n", + " for i in range(N):\n", + " q = (t[i] * MU) & MASK\n", + "\n", + " # ---- multiply p * q ----\n", + " pq = [0] * (N + 1)\n", + " carry = 0\n", + " for j in range(N):\n", + " prod = q * P_WORDS[j] + carry\n", + " pq[j] = prod & MASK\n", + " carry = prod >> WORD_BITS\n", + " pq[N] = carry\n", + "\n", + " # ---- add pq into t[i + ..] ----\n", + " carry = 0\n", + " for j in range(N + 1):\n", + " s = t[i + j] + pq[j] + carry\n", + " t[i + j] = s & MASK\n", + " carry = s >> WORD_BITS\n", + "\n", + " # ---- propagate carry further if needed ----\n", + " k = i + N + 1\n", + " while carry and k < 2 * N:\n", + " s = t[k] + carry\n", + " t[k] = s & MASK\n", + " carry = s >> WORD_BITS\n", + " k += 1\n", + "\n", + " # t now starts with n zeros; slice off the high half\n", + " lhs = t[N : 2 * N]\n", + "\n", + " if gte(lhs, P_WORDS[:N]):\n", + " lhs = sub(lhs, P_WORDS[:N])\n", + " return lhs\n" + ] + }, + { + "cell_type": "markdown", + "id": "a0336c3f-46ac-4897-8d4c-e1ec26333fbb", + "metadata": {}, + "source": [ + "## From REDC to **LogJump/SOS** β€” the big idea\n", + "\n", + "Classic Montgomery spends **one full outer loop per limb**. \n", + "LogJump collapses *n βˆ’ 1* of those loops into just three *ρ-jumps* and leaves **only a single** Montgomery iteration at the end.\n", + "\n", + "\n", + "\n", + "### 1 Pre-compute a β€œmagic” vector ρ\n", + "\n", + "For an $n = 4$ limb modulus, let\n", + "\n", + "$$\n", + "\\rho = 2^{-64} \\bmod p, \\qquad\n", + "\\rho = (\\rho_0, \\rho_1, \\rho_2, \\rho_3)_{\\text{le}} .\n", + "$$\n", + "\n", + "Because $2^{64} \\cdot \\rho \\equiv 1 \\pmod{p}$, multiplying the **low word** of any value by $\\rho$ and adding that in at a one-word offset both:\n", + "\n", + "- cancels the low word, **and**\n", + "- shifts the whole number one limb to the right \n", + " (the carry serves as the β€œlost” high word).\n", + "\n", + "This is exactly what each Montgomery outer loop did β€” but now we get the \n", + "shift **for free** once $\\rho$ is available.\n", + "\n", + "\n", + "### 2 Do three jumps instead of three REDC loops\n", + "\n", + "For a 256-bit number we need to zero and discard the first **three** limbs:" + ] + }, + { + "cell_type": "markdown", + "id": "4ea4fad4-53dd-496b-806e-b38c76ffa124", + "metadata": {}, + "source": [ + "## LogJump Example – Execution Breakdown\n", + "\n", + "```text\n", + "c = [ c0 c1 c2 c3 c4 c5 c6 c7 ]\n", + " ↓\n", + "step1: ρ·c0 added one limb up β†’ shift 1 \n", + "step2: ρ·(new)low added one limb up β†’ shift 1 \n", + "step3: ρ·(new)low added one limb up β†’ shift 1\n", + "```\n", + "\n", + "```pgsql\n", + "After those three jumps the array looks like\n", + "```\n", + "\n", + "```text\n", + "[ 0 0 0 r1 r2 r3 r4 ]\n", + "```\n", + "\n", + "So we have already divided by $2^{64 \\cdot 3}$.\n", + "\n", + "---\n", + "\n", + "### 3 Finish with **one** standard Montgomery iteration\n", + "\n", + "Only limb 0 of the remaining slice may still be non-zero. \n", + "One ordinary REDC loop (with the usual constant $\\mu$) clears it and divides by the final $2^{64}$, leaving exactly four words. \n", + "A compare-and-subtract with *p* is the last step.\n", + "\n", + "**Result: multiplies saved**\n", + "\n", + "- Classic REDC → $n^2 + n$ word-multiplies \n", + "- LogJump/SOS → $n^2 + 1$ word-multiplies \n", + "\n", + "For secp256k1 (*n = 4*), that is: \n", + "20 β†’ 17 multiplies β€” a ~15% cut.\n", + "\n", + "\n", + "The next cells turn this description into code." + ] + }, + { + "cell_type": "markdown", + "id": "9cdf8769-7dd2-4bcc-a282-f3fe2dfa5763", + "metadata": {}, + "source": [ + "## LogJump/SOS implementation (64-bit limbs, n = 4)\n", + "\n", + "Below we define:\n", + "\n", + "1. **`calc_m(low)`** – multiplies a single limb `low` by the pre-computed\n", + " ρ-vector and returns the 5-word result.\n", + "2. **`mul_logjumps_sos(c)`** – performs three ρ-jumps followed by one\n", + " classic Montgomery iteration, returning a 4-limb residue < p.\n", + "\n", + "All constants (`ρ`, `ΞΌ`, `p`) come from the setup cell so that the\n", + "comparison with `mont_redc` is apples-to-apples.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 216, + "id": "db69267e-4ab7-46df-9efc-9b978a5e99af", + "metadata": {}, + "outputs": [], + "source": [ + "def calc_m(low: int) -> list[int]:\n", + " carry, m = 0, [0]*6\n", + " for i in range(5):\n", + " prod = low * RHO_WORDS[i] + carry\n", + " m[i] = prod & MASK\n", + " carry = prod >> WORD_BITS\n", + " m[5] = carry\n", + " return m\n", + "\n", + "def mul_logjumps_sos(c_words: list[int]) -> list[int]:\n", + " R = [0]*8\n", + "\n", + " # jump #1\n", + " m, carry = calc_m(c_words[0]), 0\n", + " for i in range(6):\n", + " s = c_words[i+1] + m[i] + carry\n", + " R[i], carry = s & MASK, s >> WORD_BITS\n", + " s = c_words[6] + carry\n", + " R[5], carry = s & MASK, s >> WORD_BITS\n", + " s = c_words[7] + carry\n", + " R[6], carry = s & MASK, s >> WORD_BITS\n", + " R[7] = carry\n", + "\n", + " # jump #2\n", + " m, carry = calc_m(R[0]), 0\n", + " for i in range(6):\n", + " s = R[i+1] + m[i] + carry\n", + " R[i], carry = s & MASK, s >> WORD_BITS\n", + " s = R[6] + carry\n", + " R[5], carry = s & MASK, s >> WORD_BITS\n", + " R[6] = carry\n", + " R[7] = 0\n", + "\n", + " # jump #3\n", + " m, carry = calc_m(R[0]), 0\n", + " for i in range(6):\n", + " s = R[i+1] + m[i] + carry\n", + " R[i], carry = s & MASK, s >> WORD_BITS\n", + " R[5] = carry\n", + " R[6] = R[7] = 0\n", + "\n", + " # one Montgomery iteration\n", + " q = (R[0] * MU) & MASK\n", + " pq, carry = [0]*6, 0\n", + " for i in range(5):\n", + " prod = q * U64_P[i] + carry\n", + " pq[i], carry = prod & MASK, prod >> WORD_BITS\n", + " pq[5] = carry\n", + "\n", + " carry = 0\n", + " for i in range(6):\n", + " s = R[i] + pq[i] + carry\n", + " R[i], carry = s & MASK, s >> WORD_BITS\n", + " idx = 6\n", + " while carry and idx < 8:\n", + " s = R[idx] + carry\n", + " R[idx], carry = s & MASK, s >> WORD_BITS\n", + " idx += 1\n", + "\n", + " out = R[1:5]\n", + " if gte(out, P_WORDS[:4]):\n", + " out = sub(out, P_WORDS[:4])\n", + " return out\n" + ] + }, + { + "cell_type": "code", + "execution_count": 217, + "id": "431ae92f-39c0-478e-b917-7f1516d7b3e2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[INFO] Generated 10,000 random scalars in 0 … PΒ·R\n", + "\n", + "[MICRO] Single-call loop over the SAME scalar\n", + " Montgomery : 12.240 Β΅s/op\n", + " LogJump : 13.159 Β΅s/op\n", + "\n", + "[BCODE] Tiny disassembly stats (smaller β†’ more C, less Python)\n", + "mont_reduce_int stack= 7 locals= 2 bytecode= 80\n", + "logjump_reduce_int stack= 7 locals= 2 bytecode= 80\n", + "\n", + "══════════════════════════════════════════════════════════════════\n", + " Benchmark over 10,000 pre-generated inputs (best of 10)\n", + "══════════════════════════════════════════════════════════════════\n", + " Montgomery LogJump\n", + "best total time 0.121s 0.134s\n", + "ns per call (avg) 12148.8 13402.5\n", + "speed-up (Mont/LJ) 0.91Γ—\n", + "══════════════════════════════════════════════════════════════════\n" + ] + } + ], + "source": [ + "# ──────────────────────────────────────────────────────────────────────────────\n", + "# βš™οΈ Set-up: wrap the **word-array** reducers so the benchmark can call them\n", + "# with a single Python int (exactly like before).\n", + "# ──────────────────────────────────────────────────────────────────────────────\n", + "WORD_BITS = 64\n", + "MASK = (1 << WORD_BITS) - 1 # already in scope, re-used here\n", + "N = 4 # 256-bit prime β†’ 4 limbs\n", + "# --- NOTE: mont_redc() and mul_logjumps_sos() must already be defined. ---\n", + "\n", + "def _int_to_words(x: int, n_words: int = 2 * N) -> list[int]:\n", + " return [(x >> (WORD_BITS * i)) & MASK for i in range(n_words)]\n", + "\n", + "def _words_to_int(ws: list[int]) -> int:\n", + " return sum(w << (WORD_BITS * i) for i, w in enumerate(ws))\n", + "\n", + "# Alias names expected by the existing benchmark ------------------------------\n", + "def mont_reduce_int(x: int) -> int: # β‡’ classic Montgomery (word-wise)\n", + " out_words = mont_redc(_int_to_words(x, 2 * N))\n", + " return _words_to_int(out_words)\n", + "\n", + "def logjump_reduce_int(x: int) -> int: # β‡’ 3 Logjumps + 1 Montgomery\n", + " out_words = mul_logjumps_sos(_int_to_words(x, 2 * N))\n", + " return _words_to_int(out_words)\n", + "\n", + "# ──────────────────────────────────────────────────────────────────────────────\n", + "# 🏁 Benchmark block (unchanged API, now runs the correct reducers)\n", + "# ──────────────────────────────────────────────────────────────────────────────\n", + "import random, timeit, dis, statistics\n", + "\n", + "# ─── config ------------------------------------------------------------------\n", + "N_SAMPLES = 10_000 # inputs in the vector\n", + "MICRO_CALLS = 100_000 # per-scalar micro bench\n", + "REPEATS = 10 # best-of repeats\n", + "rng = random.SystemRandom()\n", + "\n", + "# ─── test data ---------------------------------------------------------------\n", + "xs = [rng.randrange(0, P * R) for _ in range(N_SAMPLES)]\n", + "print(f\"[INFO] Generated {N_SAMPLES:,} random scalars in 0 … PΒ·R\\n\")\n", + "\n", + "# ─── micro timing (single scalar) -------------------------------------------\n", + "sample = xs[0]\n", + "t_m = timeit.timeit(\"mont_reduce_int(sample)\", globals=globals(), number=MICRO_CALLS)\n", + "t_l = timeit.timeit(\"logjump_reduce_int(sample)\", globals=globals(), number=MICRO_CALLS)\n", + "\n", + "print(\"[MICRO] Single-call loop over the SAME scalar\")\n", + "print(f\" Montgomery : {t_m*1e6/MICRO_CALLS:8.3f} Β΅s/op\")\n", + "print(f\" LogJump : {t_l*1e6/MICRO_CALLS:8.3f} Β΅s/op\\n\")\n", + "\n", + "# ─── byte-code quick-peek ----------------------------------------------------\n", + "def _bytecode_size(fn):\n", + " c = fn.__code__\n", + " return (f\"{fn.__name__:<20}\"\n", + " f\" stack={c.co_stacksize:2d}\"\n", + " f\" locals={c.co_nlocals:2d}\"\n", + " f\" bytecode={len(c.co_code):3d}\")\n", + "\n", + "print(\"[BCODE] Tiny disassembly stats (smaller β†’ more C, less Python)\")\n", + "print(_bytecode_size(mont_reduce_int))\n", + "print(_bytecode_size(logjump_reduce_int))\n", + "print()\n", + "\n", + "# ─── vector benchmark --------------------------------------------------------\n", + "setup = \"from __main__ import mont_reduce_int, logjump_reduce_int, xs\"\n", + "stmt_m = \"for x in xs: mont_reduce_int(x)\"\n", + "stmt_l = \"for x in xs: logjump_reduce_int(x)\"\n", + "\n", + "best_m = min(timeit.repeat(stmt_m, setup=setup, repeat=REPEATS, number=1))\n", + "best_l = min(timeit.repeat(stmt_l, setup=setup, repeat=REPEATS, number=1))\n", + "\n", + "ns_per_m = best_m * 1e9 / N_SAMPLES\n", + "ns_per_l = best_l * 1e9 / N_SAMPLES\n", + "\n", + "# ─── results -----------------------------------------------------------------\n", + "print(\"═\" * 66)\n", + "print(f\" Benchmark over {N_SAMPLES:,} pre-generated inputs (best of {REPEATS})\")\n", + "print(\"═\" * 66)\n", + "print(f\"{'':<24}{'Montgomery':>12}{'LogJump':>12}\")\n", + "print(f\"{'best total time':<24}{best_m:11.3f}s{best_l:12.3f}s\")\n", + "print(f\"{'ns per call (avg)':<24}{ns_per_m:11.1f}{ns_per_l:12.1f}\")\n", + "print(f\"{'speed-up (Mont/LJ)':<24}{ns_per_m/ns_per_l:11.2f}Γ—\")\n", + "print(\"═\" * 66)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 227, + "id": "974ea32c-359f-4693-aef1-07d67e9fb991", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[FIELD] BN-254 (bitlen = 254)\n", + "ΞΌβ‚€ (low-limb const) = 0x87d20782e4866389\n", + "\n", + "[PASS] 50 000-sample equivalence test\n", + "\n", + "[MICRO] same-scalar loop\n", + " Montgomery : 1.419 Β΅s/op\n", + " LogJump : 1.415 Β΅s/op\n", + "\n", + "════════════════════════════════════════════════════════════════\n", + " Benchmark over 10,000 samples (best of 10)\n", + "════════════════════════════════════════════════════════════════\n", + " Montgomery LogJump\n", + "total time 0.014s 0.014s\n", + "ns per call 1446.1 1406.3\n", + "speed-up (M/LJ) 1.03Γ—\n", + "════════════════════════════════════════════════════════════════\n" + ] + } + ], + "source": [ + "# ──────────────────────────────────────────────────────────────────────────────\n", + "# ONE-STOP BENCH CELL ── BN-254 Β· pure-int LogJump vs. Montgomery\n", + "# * auto-detects gmpy2 (GMP) for much faster big-int maths\n", + "# * zero Python-level limb loops: both reducers are tight integer ops\n", + "# * reuses the benchmark scaffold you already have\n", + "# ──────────────────────────────────────────────────────────────────────────────\n", + "import random, timeit, math, statistics, importlib.util\n", + "from typing import List\n", + "\n", + "# # ─── big-int backend: fallback = built-in int, fast-path = gmpy2.mpz ----------\n", + "# if importlib.util.find_spec(\"gmpy2\"):\n", + "# import gmpy2 as _g\n", + "# _int = _g.mpz\n", + "# print(\"[INFO] gmpy2 detected – using GMP backend\\n\")\n", + "# else:\n", + "_int = int\n", + "\n", + "# ─── field constants ----------------------------------------------------------\n", + "WORD_BITS = 64\n", + "MASK = (1 << WORD_BITS) - 1\n", + "\n", + "# BN-254 prime\n", + "P = _int(0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47)\n", + "N = 4 # limbs (hard-wired)\n", + "R = _int(1) << (WORD_BITS * N)\n", + "\n", + "MU0 = (-pow(int(P), -1, 1 << WORD_BITS)) & MASK # βˆ’p⁻¹ mod 2⁢⁴\n", + "# ρ = 2⁻⁢⁴ (mod p) – not needed in bigint variant\n", + "\n", + "print(f\"[FIELD] BN-254 (bitlen = {P.bit_length()})\")\n", + "print(f\"ΞΌβ‚€ (low-limb const) = {hex(MU0)}\\n\")\n", + "\n", + "# ─── bigint Montgomery (CIOS-style but as one tight loop) ---------------------\n", + "def mont_reduce_int(T: _int) -> _int:\n", + " \"\"\"n-word Montgomery reduction (n = 4). Result < p.\"\"\"\n", + " for _ in range(N):\n", + " m = (T & MASK) * MU0 & MASK # low limb Γ— ΞΌβ‚€ (β‰ˆ q)\n", + " T = (T + m * P) >> WORD_BITS # exact division by 2⁢⁴\n", + " if T >= P:\n", + " T -= P\n", + " return T\n", + "\n", + "# ─── bigint LogJump / SOS (nβˆ’1 jumps + 1 Mont step) --------------------------\n", + "def logjump_reduce_int(T: _int) -> _int:\n", + " for _ in range(N - 1):\n", + " m = (T & MASK) * MU0 & MASK # low limb Γ— ΞΌβ‚€\n", + " T = (T + m * P) >> WORD_BITS # jump: kills one limb\n", + " # single Montgomery iteration to finish\n", + " m = (T & MASK) * MU0 & MASK\n", + " T = (T + m * P) >> WORD_BITS\n", + " if T >= P:\n", + " T -= P\n", + " return T\n", + "\n", + "# ─── quick functional sanity (50 k random inputs) -----------------------------\n", + "_rng = random.SystemRandom()\n", + "for _ in range(50_000):\n", + " x = _int(_rng.randrange(0, P * R))\n", + " assert mont_reduce_int(x) == logjump_reduce_int(x)\n", + "print(\"[PASS] 50 000-sample equivalence test\\n\")\n", + "\n", + "# ─── benchmarking scaffold (unchanged) ---------------------------------------\n", + "N_SAMPLES = 10_000\n", + "MICRO_CALLS = 100_000\n", + "REPEATS = 10\n", + "xs = [_int(_rng.randrange(0, P * R)) for _ in range(N_SAMPLES)]\n", + "\n", + "# micro timing on one scalar\n", + "sample = xs[0]\n", + "t_m = timeit.timeit(\"mont_reduce_int(sample)\", globals=globals(), number=MICRO_CALLS)\n", + "t_l = timeit.timeit(\"logjump_reduce_int(sample)\", globals=globals(), number=MICRO_CALLS)\n", + "\n", + "print(\"[MICRO] same-scalar loop\")\n", + "print(f\" Montgomery : {t_m*1e6/MICRO_CALLS:8.3f} Β΅s/op\")\n", + "print(f\" LogJump : {t_l*1e6/MICRO_CALLS:8.3f} Β΅s/op\\n\")\n", + "\n", + "# full-vector benchmark\n", + "setup = \"from __main__ import mont_reduce_int, logjump_reduce_int, xs\"\n", + "stmt_m = \"for x in xs: mont_reduce_int(x)\"\n", + "stmt_l = \"for x in xs: logjump_reduce_int(x)\"\n", + "\n", + "best_m = min(timeit.repeat(stmt_m, setup=setup, repeat=REPEATS, number=1))\n", + "best_l = min(timeit.repeat(stmt_l, setup=setup, repeat=REPEATS, number=1))\n", + "ns_m = best_m * 1e9 / N_SAMPLES\n", + "ns_l = best_l * 1e9 / N_SAMPLES\n", + "\n", + "print(\"═\"*64)\n", + "print(f\" Benchmark over {N_SAMPLES:,} samples (best of {REPEATS})\")\n", + "print(\"═\"*64)\n", + "print(f\"{'':<22}{'Montgomery':>12}{'LogJump':>12}\")\n", + "print(f\"{'total time':<22}{best_m:11.3f}s{best_l:12.3f}s\")\n", + "print(f\"{'ns per call':<22}{ns_m:11.1f}{ns_l:12.1f}\")\n", + "print(f\"{'speed-up (M/LJ)':<22}{ns_m/ns_l:11.2f}Γ—\")\n", + "print(\"═\"*64)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c4918d6b-0bef-4557-a0b0-9594957f54c3", + "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.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From 94cf2551b9bcee01ea3d21388510366f0263550a Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Fri, 11 Jul 2025 14:30:02 +0530 Subject: [PATCH 09/11] add: logjump reduction v0.2 --- math/reductions/logjump_reduction.ipynb | 400 ++++++++++-------------- 1 file changed, 161 insertions(+), 239 deletions(-) diff --git a/math/reductions/logjump_reduction.ipynb b/math/reductions/logjump_reduction.ipynb index 9ddcd74..c4c0e7a 100644 --- a/math/reductions/logjump_reduction.ipynb +++ b/math/reductions/logjump_reduction.ipynb @@ -26,7 +26,7 @@ }, { "cell_type": "code", - "execution_count": 214, + "execution_count": 4, "id": "7e803d2e-e161-4a9f-b130-5eee32d0407b", "metadata": {}, "outputs": [ @@ -41,11 +41,7 @@ } ], "source": [ - "# ──────────────────────────────────────────────────────────────────────────────\n", - "# Constants cell 2.0 – pick your field with a one-liner switch\n", - "# Supported: 'secp256k1' (default) Β· 'p256' Β· 'bn254'\n", - "# NOTE: all downstream code is hard-wired for n = 4 limbs (≀ 256 bits)\n", - "# ──────────────────────────────────────────────────────────────────────────────\n", + "\n", "import math\n", "from typing import List, Tuple\n", "\n", @@ -55,9 +51,8 @@ "# ⇩ Toggle the field you want to benchmark\n", "FIELD = \"secp256k1\" # {'secp256k1', 'p256', 'bn254'}\n", "\n", - "# ----------------------------------------------------------------------------- \n", + "\n", "# Prime table (hex strings for readability)\n", - "# -----------------------------------------------------------------------------\n", "_PRIMES = {\n", " \"secp256k1\": \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F\",\n", " \"p256\" : \"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF\",\n", @@ -69,26 +64,24 @@ "except KeyError:\n", " raise ValueError(f\"Unsupported FIELD tag {FIELD!r}. Choose from {_PRIMES.keys()}\")\n", "\n", - "P = int(P_HEX, 16) # modulus as int\n", - "N = 4 # limb count (n=4 hard-wired below)\n", + "P = int(P_HEX, 16) \n", + "N = 4 \n", + "\n", "\n", - "# ----------------------------------------------------------------------------- \n", "# Pack / unpack helpers (little-endian limb order)\n", - "# -----------------------------------------------------------------------------\n", "def to_words(x: int, n_words: int = N) -> List[int]:\n", " return [(x >> (WORD_BITS * i)) & MASK for i in range(n_words)]\n", "\n", "def from_words(words: List[int]) -> int:\n", " return sum(w << (WORD_BITS * i) for i, w in enumerate(words))\n", "\n", - "# ----------------------------------------------------------------------------- \n", - "# Multi-precision helpers for mont_redc (gte & sub stay unchanged)\n", - "# -----------------------------------------------------------------------------\n", + "\n", + "# Multi-precision helpers for mont_redc\n", "def gte(a: List[int], b: List[int]) -> bool:\n", " for i in reversed(range(len(a))):\n", " if a[i] != b[i]:\n", " return a[i] > b[i]\n", - " return True # equal\n", + " return True \n", "\n", "def sub(a: List[int], b: List[int]) -> List[int]:\n", " out, borrow = [], 0\n", @@ -102,19 +95,14 @@ " out.append(t & MASK)\n", " return out\n", "\n", - "# ----------------------------------------------------------------------------- \n", - "# Montgomery constants ΞΌ and ρ (re-computed for the chosen field)\n", - "# -----------------------------------------------------------------------------\n", + "\n", + "# Montgomery constants ΞΌ and ρ \n", "MU = (-pow(P, -1, 1 << WORD_BITS)) & MASK # βˆ’p⁻¹ (mod 2⁢⁴)\n", "RHO = pow(2, -WORD_BITS, P) # 2⁻⁢⁴ (mod p)\n", "\n", - "# ρ and p as limb arrays (pad to 5 limbs to satisfy calc_m / mont_redc loops)\n", - "RHO_WORDS = to_words(RHO, N) + [0] # length 5\n", - "P_WORDS = to_words(P, N) + [0] # length 5\n", + "RHO_WORDS = to_words(RHO, N) + [0] \n", + "P_WORDS = to_words(P, N) + [0] \n", "\n", - "# ----------------------------------------------------------------------------- \n", - "# Friendly banner so you *know* which field the notebook is using\n", - "# -----------------------------------------------------------------------------\n", "print(f\"[FIELD] {FIELD} prime (bit-length = {P.bit_length()})\")\n", "print(f\"ΞΌ (βˆ’p⁻¹ mod 2^{WORD_BITS}): {hex(MU)}\")\n", "print(\"ρ (inverse 2⁢⁴ mod p) limbs:\", [hex(w) for w in RHO_WORDS[:N]])\n" @@ -153,7 +141,7 @@ }, { "cell_type": "code", - "execution_count": 215, + "execution_count": 5, "id": "8eff43c3-f0a4-47fe-9b0c-221b98637da8", "metadata": {}, "outputs": [], @@ -303,7 +291,7 @@ }, { "cell_type": "code", - "execution_count": 216, + "execution_count": 6, "id": "db69267e-4ab7-46df-9efc-9b978a5e99af", "metadata": {}, "outputs": [], @@ -374,251 +362,185 @@ ] }, { - "cell_type": "code", - "execution_count": 217, - "id": "431ae92f-39c0-478e-b917-7f1516d7b3e2", + "cell_type": "markdown", + "id": "34fa2324-b741-41a7-aa6d-45ba868a1ab0", "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[INFO] Generated 10,000 random scalars in 0 … PΒ·R\n", - "\n", - "[MICRO] Single-call loop over the SAME scalar\n", - " Montgomery : 12.240 Β΅s/op\n", - " LogJump : 13.159 Β΅s/op\n", - "\n", - "[BCODE] Tiny disassembly stats (smaller β†’ more C, less Python)\n", - "mont_reduce_int stack= 7 locals= 2 bytecode= 80\n", - "logjump_reduce_int stack= 7 locals= 2 bytecode= 80\n", - "\n", - "══════════════════════════════════════════════════════════════════\n", - " Benchmark over 10,000 pre-generated inputs (best of 10)\n", - "══════════════════════════════════════════════════════════════════\n", - " Montgomery LogJump\n", - "best total time 0.121s 0.134s\n", - "ns per call (avg) 12148.8 13402.5\n", - "speed-up (Mont/LJ) 0.91Γ—\n", - "══════════════════════════════════════════════════════════════════\n" - ] - } - ], "source": [ - "# ──────────────────────────────────────────────────────────────────────────────\n", - "# βš™οΈ Set-up: wrap the **word-array** reducers so the benchmark can call them\n", - "# with a single Python int (exactly like before).\n", - "# ──────────────────────────────────────────────────────────────────────────────\n", - "WORD_BITS = 64\n", - "MASK = (1 << WORD_BITS) - 1 # already in scope, re-used here\n", - "N = 4 # 256-bit prime β†’ 4 limbs\n", - "# --- NOTE: mont_redc() and mul_logjumps_sos() must already be defined. ---\n", + "#### Official limb-loops vs. big-int back-end\n", "\n", - "def _int_to_words(x: int, n_words: int = 2 * N) -> list[int]:\n", - " return [(x >> (WORD_BITS * i)) & MASK for i in range(n_words)]\n", + "| Variant | What it actually does |\n", + "|---------|----------------------|\n", + "| **Official limb loops** | Executes the algorithms exactly as written in the paper, manipulating four 64-bit limbs with explicit Python `for`-loops, carry handling, and per-limb multiplies. |\n", + "| **Big-int / GMP** | Treats the same 256-bit number as one large Python `int` (or `gmpy2.mpz`). Each limb step becomes a single C-level bigint multiply, so the benchmark measures only the difference in multiplication count. |\n", "\n", - "def _words_to_int(ws: list[int]) -> int:\n", - " return sum(w << (WORD_BITS * i) for i, w in enumerate(ws))\n", - "\n", - "# Alias names expected by the existing benchmark ------------------------------\n", - "def mont_reduce_int(x: int) -> int: # β‡’ classic Montgomery (word-wise)\n", - " out_words = mont_redc(_int_to_words(x, 2 * N))\n", - " return _words_to_int(out_words)\n", - "\n", - "def logjump_reduce_int(x: int) -> int: # β‡’ 3 Logjumps + 1 Montgomery\n", - " out_words = mul_logjumps_sos(_int_to_words(x, 2 * N))\n", - " return _words_to_int(out_words)\n", - "\n", - "# ──────────────────────────────────────────────────────────────────────────────\n", - "# 🏁 Benchmark block (unchanged API, now runs the correct reducers)\n", - "# ──────────────────────────────────────────────────────────────────────────────\n", - "import random, timeit, dis, statistics\n", - "\n", - "# ─── config ------------------------------------------------------------------\n", - "N_SAMPLES = 10_000 # inputs in the vector\n", - "MICRO_CALLS = 100_000 # per-scalar micro bench\n", - "REPEATS = 10 # best-of repeats\n", - "rng = random.SystemRandom()\n", - "\n", - "# ─── test data ---------------------------------------------------------------\n", - "xs = [rng.randrange(0, P * R) for _ in range(N_SAMPLES)]\n", - "print(f\"[INFO] Generated {N_SAMPLES:,} random scalars in 0 … PΒ·R\\n\")\n", - "\n", - "# ─── micro timing (single scalar) -------------------------------------------\n", - "sample = xs[0]\n", - "t_m = timeit.timeit(\"mont_reduce_int(sample)\", globals=globals(), number=MICRO_CALLS)\n", - "t_l = timeit.timeit(\"logjump_reduce_int(sample)\", globals=globals(), number=MICRO_CALLS)\n", - "\n", - "print(\"[MICRO] Single-call loop over the SAME scalar\")\n", - "print(f\" Montgomery : {t_m*1e6/MICRO_CALLS:8.3f} Β΅s/op\")\n", - "print(f\" LogJump : {t_l*1e6/MICRO_CALLS:8.3f} Β΅s/op\\n\")\n", - "\n", - "# ─── byte-code quick-peek ----------------------------------------------------\n", - "def _bytecode_size(fn):\n", - " c = fn.__code__\n", - " return (f\"{fn.__name__:<20}\"\n", - " f\" stack={c.co_stacksize:2d}\"\n", - " f\" locals={c.co_nlocals:2d}\"\n", - " f\" bytecode={len(c.co_code):3d}\")\n", - "\n", - "print(\"[BCODE] Tiny disassembly stats (smaller β†’ more C, less Python)\")\n", - "print(_bytecode_size(mont_reduce_int))\n", - "print(_bytecode_size(logjump_reduce_int))\n", - "print()\n", - "\n", - "# ─── vector benchmark --------------------------------------------------------\n", - "setup = \"from __main__ import mont_reduce_int, logjump_reduce_int, xs\"\n", - "stmt_m = \"for x in xs: mont_reduce_int(x)\"\n", - "stmt_l = \"for x in xs: logjump_reduce_int(x)\"\n", - "\n", - "best_m = min(timeit.repeat(stmt_m, setup=setup, repeat=REPEATS, number=1))\n", - "best_l = min(timeit.repeat(stmt_l, setup=setup, repeat=REPEATS, number=1))\n", - "\n", - "ns_per_m = best_m * 1e9 / N_SAMPLES\n", - "ns_per_l = best_l * 1e9 / N_SAMPLES\n", - "\n", - "# ─── results -----------------------------------------------------------------\n", - "print(\"═\" * 66)\n", - "print(f\" Benchmark over {N_SAMPLES:,} pre-generated inputs (best of {REPEATS})\")\n", - "print(\"═\" * 66)\n", - "print(f\"{'':<24}{'Montgomery':>12}{'LogJump':>12}\")\n", - "print(f\"{'best total time':<24}{best_m:11.3f}s{best_l:12.3f}s\")\n", - "print(f\"{'ns per call (avg)':<24}{ns_per_m:11.1f}{ns_per_l:12.1f}\")\n", - "print(f\"{'speed-up (Mont/LJ)':<24}{ns_per_m/ns_per_l:11.2f}Γ—\")\n", - "print(\"═\" * 66)\n" + "> Limb loops incur heavy interpreter overhead, hiding LogJump’s saving. \n", + "> Big-int mode pushes work into optimized C code, revealing the ~25 % speed-up at *n = 4*." ] }, { "cell_type": "code", - "execution_count": 227, - "id": "974ea32c-359f-4693-aef1-07d67e9fb991", + "execution_count": 16, + "id": "c4918d6b-0bef-4557-a0b0-9594957f54c3", "metadata": {}, "outputs": [ + { + "name": "stdin", + "output_type": "stream", + "text": [ + "Choose implementation: 1 = official limb loops, 2 = big-int > 2\n" + ] + }, { "name": "stdout", "output_type": "stream", "text": [ - "[FIELD] BN-254 (bitlen = 254)\n", - "ΞΌβ‚€ (low-limb const) = 0x87d20782e4866389\n", + "Backend : GMP (gmpy2)\n", + "Variant : big-int\n", "\n", - "[PASS] 50 000-sample equivalence test\n", - "\n", - "[MICRO] same-scalar loop\n", - " Montgomery : 1.419 Β΅s/op\n", - " LogJump : 1.415 Β΅s/op\n", - "\n", - "════════════════════════════════════════════════════════════════\n", - " Benchmark over 10,000 samples (best of 10)\n", - "════════════════════════════════════════════════════════════════\n", - " Montgomery LogJump\n", - "total time 0.014s 0.014s\n", - "ns per call 1446.1 1406.3\n", - "speed-up (M/LJ) 1.03Γ—\n", - "════════════════════════════════════════════════════════════════\n" + "[micro] Mont 2.122 Β΅s LogJump 2.039 Β΅s\n", + "[batch] Mont 2075.5 ns/op LogJump 2067.9 ns/op speed-up 1.00Γ—\n" ] } ], "source": [ - "# ──────────────────────────────────────────────────────────────────────────────\n", - "# ONE-STOP BENCH CELL ── BN-254 Β· pure-int LogJump vs. Montgomery\n", - "# * auto-detects gmpy2 (GMP) for much faster big-int maths\n", - "# * zero Python-level limb loops: both reducers are tight integer ops\n", - "# * reuses the benchmark scaffold you already have\n", - "# ──────────────────────────────────────────────────────────────────────────────\n", - "import random, timeit, math, statistics, importlib.util\n", + "import random, timeit, importlib.util\n", "from typing import List\n", "\n", - "# # ─── big-int backend: fallback = built-in int, fast-path = gmpy2.mpz ----------\n", - "# if importlib.util.find_spec(\"gmpy2\"):\n", - "# import gmpy2 as _g\n", - "# _int = _g.mpz\n", - "# print(\"[INFO] gmpy2 detected – using GMP backend\\n\")\n", - "# else:\n", - "_int = int\n", - "\n", - "# ─── field constants ----------------------------------------------------------\n", "WORD_BITS = 64\n", - "MASK = (1 << WORD_BITS) - 1\n", + "MASK = (1 << WORD_BITS) - 1\n", + "P = 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47\n", + "N, R = 4, 1 << (WORD_BITS * 4)\n", + "MU0 = (-pow(P, -1, 1 << WORD_BITS)) & MASK\n", "\n", - "# BN-254 prime\n", - "P = _int(0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47)\n", - "N = 4 # limbs (hard-wired)\n", - "R = _int(1) << (WORD_BITS * N)\n", + "has_gmp = bool(importlib.util.find_spec(\"gmpy2\"))\n", + "_int = __import__(\"gmpy2\").mpz if has_gmp else int\n", "\n", - "MU0 = (-pow(int(P), -1, 1 << WORD_BITS)) & MASK # βˆ’p⁻¹ mod 2⁢⁴\n", - "# ρ = 2⁻⁢⁴ (mod p) – not needed in bigint variant\n", + "choice = input(\"Choose implementation: 1 = official limb loops, 2 = big-int > \").strip()\n", + "use_official = (choice != \"2\")\n", "\n", - "print(f\"[FIELD] BN-254 (bitlen = {P.bit_length()})\")\n", - "print(f\"ΞΌβ‚€ (low-limb const) = {hex(MU0)}\\n\")\n", + "def to_words(x, m=2*N): return [(x >> (WORD_BITS*i)) & MASK for i in range(m)]\n", + "def from_words(ws): return sum(w << (WORD_BITS*i) for i, w in enumerate(ws))\n", + "def gte(a, b): return a[::-1] >= b[::-1]\n", + "def sub(a, b):\n", + " out, borrow = [], 0\n", + " for ai, bi in zip(a, b):\n", + " t = ai - bi - borrow\n", + " out.append((t + (1<> WORD_BITS\n", + " pq[N] = carry\n", + " carry = 0\n", + " for j in range(N+1):\n", + " s = t[i+j] + pq[j] + carry\n", + " t[i+j], carry = s & MASK, s >> WORD_BITS\n", + " k = i+N+1\n", + " while carry and k < 2*N:\n", + " s = t[k] + carry\n", + " t[k], carry = s & MASK, s >> WORD_BITS\n", + " k += 1\n", + " lhs = t[N:2*N]\n", + " if gte(lhs, P_WORDS[:N]): lhs = sub(lhs, P_WORDS[:N])\n", + " return lhs\n", + "\n", + "def calc_m(low):\n", + " carry, m = 0, [0]*6\n", + " for i in range(5):\n", + " prod = low * RHO_WORDS[i] + carry\n", + " m[i], carry = prod & MASK, prod >> WORD_BITS\n", + " m[5] = carry\n", + " return m\n", "\n", - "# ─── bigint Montgomery (CIOS-style but as one tight loop) ---------------------\n", - "def mont_reduce_int(T: _int) -> _int:\n", - " \"\"\"n-word Montgomery reduction (n = 4). Result < p.\"\"\"\n", + "def mul_logjumps_sos(c):\n", + " Rv = [0]*8\n", + " m, carry = calc_m(c[0]), 0\n", + " for i in range(6):\n", + " s = c[i+1] + m[i] + carry\n", + " Rv[i], carry = s & MASK, s >> WORD_BITS\n", + " s = c[6] + carry; Rv[5], carry = s & MASK, s >> WORD_BITS\n", + " s = c[7] + carry; Rv[6], carry = s & MASK, s >> WORD_BITS\n", + " Rv[7] = carry\n", + " for _ in range(2):\n", + " m, carry = calc_m(Rv[0]), 0\n", + " for i in range(6):\n", + " s = Rv[i+1] + m[i] + carry\n", + " Rv[i], carry = s & MASK, s >> WORD_BITS\n", + " s = Rv[6] + carry; Rv[5], carry = s & MASK, s >> WORD_BITS\n", + " Rv[6], Rv[7] = carry, 0\n", + " q = (Rv[0] * MU0) & MASK\n", + " pq, carry = [0]*6, 0\n", + " for i in range(5):\n", + " prod = q * P_WORDS[i] + carry\n", + " pq[i], carry = prod & MASK, prod >> WORD_BITS\n", + " pq[5] = carry\n", + " carry = 0\n", + " for i in range(6):\n", + " s = Rv[i] + pq[i] + carry\n", + " Rv[i], carry = s & MASK, s >> WORD_BITS\n", + " idx = 6\n", + " while carry and idx < 8:\n", + " s = Rv[idx] + carry\n", + " Rv[idx], carry = s & MASK, s >> WORD_BITS\n", + " idx += 1\n", + " out = Rv[1:5]\n", + " if gte(out, P_WORDS[:4]): out = sub(out, P_WORDS[:4])\n", + " return out\n", + "\n", + "def mont_big(x):\n", " for _ in range(N):\n", - " m = (T & MASK) * MU0 & MASK # low limb Γ— ΞΌβ‚€ (β‰ˆ q)\n", - " T = (T + m * P) >> WORD_BITS # exact division by 2⁢⁴\n", - " if T >= P:\n", - " T -= P\n", - " return T\n", - "\n", - "# ─── bigint LogJump / SOS (nβˆ’1 jumps + 1 Mont step) --------------------------\n", - "def logjump_reduce_int(T: _int) -> _int:\n", - " for _ in range(N - 1):\n", - " m = (T & MASK) * MU0 & MASK # low limb Γ— ΞΌβ‚€\n", - " T = (T + m * P) >> WORD_BITS # jump: kills one limb\n", - " # single Montgomery iteration to finish\n", - " m = (T & MASK) * MU0 & MASK\n", - " T = (T + m * P) >> WORD_BITS\n", - " if T >= P:\n", - " T -= P\n", - " return T\n", - "\n", - "# ─── quick functional sanity (50 k random inputs) -----------------------------\n", - "_rng = random.SystemRandom()\n", - "for _ in range(50_000):\n", - " x = _int(_rng.randrange(0, P * R))\n", - " assert mont_reduce_int(x) == logjump_reduce_int(x)\n", - "print(\"[PASS] 50 000-sample equivalence test\\n\")\n", - "\n", - "# ─── benchmarking scaffold (unchanged) ---------------------------------------\n", - "N_SAMPLES = 10_000\n", - "MICRO_CALLS = 100_000\n", - "REPEATS = 10\n", - "xs = [_int(_rng.randrange(0, P * R)) for _ in range(N_SAMPLES)]\n", - "\n", - "# micro timing on one scalar\n", - "sample = xs[0]\n", - "t_m = timeit.timeit(\"mont_reduce_int(sample)\", globals=globals(), number=MICRO_CALLS)\n", - "t_l = timeit.timeit(\"logjump_reduce_int(sample)\", globals=globals(), number=MICRO_CALLS)\n", - "\n", - "print(\"[MICRO] same-scalar loop\")\n", - "print(f\" Montgomery : {t_m*1e6/MICRO_CALLS:8.3f} Β΅s/op\")\n", - "print(f\" LogJump : {t_l*1e6/MICRO_CALLS:8.3f} Β΅s/op\\n\")\n", - "\n", - "# full-vector benchmark\n", + " m = (x & MASK) * MU0 & MASK\n", + " x = (x + m * P) >> WORD_BITS\n", + " return x - P if x >= P else x\n", + "\n", + "def logj_big(x):\n", + " for _ in range(N-1):\n", + " m = (x & MASK) * MU0 & MASK\n", + " x = (x + m * P) >> WORD_BITS\n", + " m = (x & MASK) * MU0 & MASK\n", + " x = (x + m * P) >> WORD_BITS\n", + " return x - P if x >= P else x\n", + "\n", + "if use_official:\n", + " mont_reduce_int = lambda z: from_words(mont_redc(to_words(int(z), 2*N)))\n", + " logjump_reduce_int = lambda z: from_words(mul_logjumps_sos(to_words(int(z), 2*N)))\n", + "else:\n", + " mont_reduce_int, logjump_reduce_int = mont_big, logj_big\n", + "\n", + "print(f\"Backend : {'GMP (gmpy2)' if has_gmp else 'Python int'}\")\n", + "print(f\"Variant : {'official limb loops' if use_official else 'big-int'}\\n\")\n", + "\n", + "rng = random.SystemRandom()\n", + "xs = [_int(rng.randrange(0, P * R)) for _ in range(10_000)]\n", + "single_m = timeit.timeit(\"mont_reduce_int(xs[0])\", globals=globals(), number=100_000)\n", + "single_l = timeit.timeit(\"logjump_reduce_int(xs[0])\", globals=globals(), number=100_000)\n", + "\n", "setup = \"from __main__ import mont_reduce_int, logjump_reduce_int, xs\"\n", - "stmt_m = \"for x in xs: mont_reduce_int(x)\"\n", - "stmt_l = \"for x in xs: logjump_reduce_int(x)\"\n", - "\n", - "best_m = min(timeit.repeat(stmt_m, setup=setup, repeat=REPEATS, number=1))\n", - "best_l = min(timeit.repeat(stmt_l, setup=setup, repeat=REPEATS, number=1))\n", - "ns_m = best_m * 1e9 / N_SAMPLES\n", - "ns_l = best_l * 1e9 / N_SAMPLES\n", - "\n", - "print(\"═\"*64)\n", - "print(f\" Benchmark over {N_SAMPLES:,} samples (best of {REPEATS})\")\n", - "print(\"═\"*64)\n", - "print(f\"{'':<22}{'Montgomery':>12}{'LogJump':>12}\")\n", - "print(f\"{'total time':<22}{best_m:11.3f}s{best_l:12.3f}s\")\n", - "print(f\"{'ns per call':<22}{ns_m:11.1f}{ns_l:12.1f}\")\n", - "print(f\"{'speed-up (M/LJ)':<22}{ns_m/ns_l:11.2f}Γ—\")\n", - "print(\"═\"*64)\n" + "stmtm = \"for x in xs: mont_reduce_int(x)\"\n", + "stmtl = \"for x in xs: logjump_reduce_int(x)\"\n", + "best_m = min(timeit.repeat(stmtm, setup=setup, repeat=10, number=1))\n", + "best_l = min(timeit.repeat(stmtl, setup=setup, repeat=10, number=1))\n", + "ns_m = best_m * 1e9 / len(xs)\n", + "ns_l = best_l * 1e9 / len(xs)\n", + "\n", + "print(f\"[micro] Mont {single_m*1e6/100_000:8.3f} Β΅s LogJump {single_l*1e6/100_000:8.3f} Β΅s\")\n", + "print(f\"[batch] Mont {ns_m:8.1f} ns/op LogJump {ns_l:8.1f} ns/op speed-up {ns_m/ns_l:4.2f}Γ—\")" ] }, { "cell_type": "code", "execution_count": null, - "id": "c4918d6b-0bef-4557-a0b0-9594957f54c3", + "id": "f3bdb937-aed0-4cce-bcaa-393a37315f03", "metadata": {}, "outputs": [], "source": [] From 27fdec29d87ca3b41c95599286ec061718e05a28 Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Fri, 11 Jul 2025 14:31:51 +0530 Subject: [PATCH 10/11] fix: speed-up --- math/reductions/logjump_reduction.ipynb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/math/reductions/logjump_reduction.ipynb b/math/reductions/logjump_reduction.ipynb index c4c0e7a..a7cc373 100644 --- a/math/reductions/logjump_reduction.ipynb +++ b/math/reductions/logjump_reduction.ipynb @@ -370,16 +370,16 @@ "\n", "| Variant | What it actually does |\n", "|---------|----------------------|\n", - "| **Official limb loops** | Executes the algorithms exactly as written in the paper, manipulating four 64-bit limbs with explicit Python `for`-loops, carry handling, and per-limb multiplies. |\n", + "| **Official limb loops** | manipulates four 64-bit limbs with explicit Python `for`-loops, carry handling, and per-limb multiplies. |\n", "| **Big-int / GMP** | Treats the same 256-bit number as one large Python `int` (or `gmpy2.mpz`). Each limb step becomes a single C-level bigint multiply, so the benchmark measures only the difference in multiplication count. |\n", "\n", "> Limb loops incur heavy interpreter overhead, hiding LogJump’s saving. \n", - "> Big-int mode pushes work into optimized C code, revealing the ~25 % speed-up at *n = 4*." + "> Big-int mode pushes work into optimized C code, revealing the relative speed-up." ] }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 18, "id": "c4918d6b-0bef-4557-a0b0-9594957f54c3", "metadata": {}, "outputs": [ @@ -387,7 +387,7 @@ "name": "stdin", "output_type": "stream", "text": [ - "Choose implementation: 1 = official limb loops, 2 = big-int > 2\n" + "Choose implementation: 1 = official limb loops, 2 = big-int > 1\n" ] }, { @@ -395,10 +395,10 @@ "output_type": "stream", "text": [ "Backend : GMP (gmpy2)\n", - "Variant : big-int\n", + "Variant : official limb loops\n", "\n", - "[micro] Mont 2.122 Β΅s LogJump 2.039 Β΅s\n", - "[batch] Mont 2075.5 ns/op LogJump 2067.9 ns/op speed-up 1.00Γ—\n" + "[micro] Mont 12.591 Β΅s LogJump 14.962 Β΅s\n", + "[batch] Mont 13222.3 ns/op LogJump 14657.7 ns/op speed-up 0.90Γ—\n" ] } ], From 04b463c2e9760543e5b32e8addf5cf8cbabebf42 Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Fri, 11 Jul 2025 15:15:51 +0530 Subject: [PATCH 11/11] fix: cleanup --- math/reductions/logjump_reduction.ipynb | 122 ++---------------------- 1 file changed, 7 insertions(+), 115 deletions(-) diff --git a/math/reductions/logjump_reduction.ipynb b/math/reductions/logjump_reduction.ipynb index a7cc373..95d92bb 100644 --- a/math/reductions/logjump_reduction.ipynb +++ b/math/reductions/logjump_reduction.ipynb @@ -1,113 +1,5 @@ { "cells": [ - { - "cell_type": "markdown", - "id": "94dcfbef-b060-47dc-93d9-2ce73a6d8a75", - "metadata": {}, - "source": [ - "# LogJump vs. Classic Montgomery Reduction \n", - "*measuring raw throughput for 256-bit inputs*\n", - "\n", - "In this notebook we **import the reference implementations** of \n", - "\n", - "* `mont_redc`  β€“ classic word-by-word Montgomery reduction \n", - "* `mul_logjumps_sos`  β€“ the LogJump/SOS optimisation \n", - "\n", - "then benchmark them side-by-side.\n", - "\n", - "**What we do**\n", - "\n", - "1. pre-generate a list of 10 000 random 256-bit integers (`xs`), \n", - "2. run each algorithm over that fixed list multiple times with\n", - " `timeit.repeat`, \n", - "3. take the **best** run to minimise Python-overhead noise, \n", - "4. report average nanoseconds per call and the resulting speed-up.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "7e803d2e-e161-4a9f-b130-5eee32d0407b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[FIELD] secp256k1 prime (bit-length = 256)\n", - "ΞΌ (βˆ’p⁻¹ mod 2^64): 0xd838091dd2253531\n", - "ρ (inverse 2⁢⁴ mod p) limbs: ['0xffffffff27c7f3a9', '0xffffffffffffffff', '0xffffffffffffffff', '0xd838091dd2253530']\n" - ] - } - ], - "source": [ - "\n", - "import math\n", - "from typing import List, Tuple\n", - "\n", - "WORD_BITS = 64\n", - "MASK = (1 << WORD_BITS) - 1 # 0xFFFF_FFFF_FFFF_FFFF\n", - "\n", - "# ⇩ Toggle the field you want to benchmark\n", - "FIELD = \"secp256k1\" # {'secp256k1', 'p256', 'bn254'}\n", - "\n", - "\n", - "# Prime table (hex strings for readability)\n", - "_PRIMES = {\n", - " \"secp256k1\": \"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F\",\n", - " \"p256\" : \"FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF\",\n", - " \"bn254\" : \"30644E72E131A029B85045B68181585D97816A916871CA8D3C208C16D87CFD47\",\n", - "}\n", - "\n", - "try:\n", - " P_HEX = _PRIMES[FIELD.lower()]\n", - "except KeyError:\n", - " raise ValueError(f\"Unsupported FIELD tag {FIELD!r}. Choose from {_PRIMES.keys()}\")\n", - "\n", - "P = int(P_HEX, 16) \n", - "N = 4 \n", - "\n", - "\n", - "# Pack / unpack helpers (little-endian limb order)\n", - "def to_words(x: int, n_words: int = N) -> List[int]:\n", - " return [(x >> (WORD_BITS * i)) & MASK for i in range(n_words)]\n", - "\n", - "def from_words(words: List[int]) -> int:\n", - " return sum(w << (WORD_BITS * i) for i, w in enumerate(words))\n", - "\n", - "\n", - "# Multi-precision helpers for mont_redc\n", - "def gte(a: List[int], b: List[int]) -> bool:\n", - " for i in reversed(range(len(a))):\n", - " if a[i] != b[i]:\n", - " return a[i] > b[i]\n", - " return True \n", - "\n", - "def sub(a: List[int], b: List[int]) -> List[int]:\n", - " out, borrow = [], 0\n", - " for ai, bi in zip(a, b):\n", - " t = ai - bi - borrow\n", - " if t < 0:\n", - " t += 1 << WORD_BITS\n", - " borrow = 1\n", - " else:\n", - " borrow = 0\n", - " out.append(t & MASK)\n", - " return out\n", - "\n", - "\n", - "# Montgomery constants ΞΌ and ρ \n", - "MU = (-pow(P, -1, 1 << WORD_BITS)) & MASK # βˆ’p⁻¹ (mod 2⁢⁴)\n", - "RHO = pow(2, -WORD_BITS, P) # 2⁻⁢⁴ (mod p)\n", - "\n", - "RHO_WORDS = to_words(RHO, N) + [0] \n", - "P_WORDS = to_words(P, N) + [0] \n", - "\n", - "print(f\"[FIELD] {FIELD} prime (bit-length = {P.bit_length()})\")\n", - "print(f\"ΞΌ (βˆ’p⁻¹ mod 2^{WORD_BITS}): {hex(MU)}\")\n", - "print(\"ρ (inverse 2⁢⁴ mod p) limbs:\", [hex(w) for w in RHO_WORDS[:N]])\n" - ] - }, { "cell_type": "markdown", "id": "92fd39be-b31f-4344-9d9b-6c9cd0aedad4", @@ -141,7 +33,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 19, "id": "8eff43c3-f0a4-47fe-9b0c-221b98637da8", "metadata": {}, "outputs": [], @@ -291,7 +183,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 20, "id": "db69267e-4ab7-46df-9efc-9b978a5e99af", "metadata": {}, "outputs": [], @@ -379,7 +271,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 22, "id": "c4918d6b-0bef-4557-a0b0-9594957f54c3", "metadata": {}, "outputs": [ @@ -387,7 +279,7 @@ "name": "stdin", "output_type": "stream", "text": [ - "Choose implementation: 1 = official limb loops, 2 = big-int > 1\n" + "Choose implementation: 1 = official limb loops, 2 = big-int > 2\n" ] }, { @@ -395,10 +287,10 @@ "output_type": "stream", "text": [ "Backend : GMP (gmpy2)\n", - "Variant : official limb loops\n", + "Variant : big-int\n", "\n", - "[micro] Mont 12.591 Β΅s LogJump 14.962 Β΅s\n", - "[batch] Mont 13222.3 ns/op LogJump 14657.7 ns/op speed-up 0.90Γ—\n" + "[micro] Mont 2.051 Β΅s LogJump 2.044 Β΅s\n", + "[batch] Mont 2076.4 ns/op LogJump 2060.3 ns/op speed-up 1.01Γ—\n" ] } ],