{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "43f7fdc0", "metadata": {}, "outputs": [], "source": [ "import json\n", "\n", "with open(\"crates/prover/proof.json\", \"r\") as f:\n", " proof = json.load(f)" ] }, { "cell_type": "code", "execution_count": null, "id": "88f232b5", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 2, "id": "12ef3767", "metadata": {}, "outputs": [], "source": [ "F = FiniteField(52435875175126190479447740508185965837690552500527637822603658699938581184513)\n", "\n", "poseidon_comp_consts = [50207570499218320245539736680169582180207201335688461025883902752909290481781,\n", "24448666467656506447555018649749346340705294023832615387641453784702583464707,\n", "34092944507611308604157957266676007619644244199372265837364557849561670729974,\n", "46954129210702959446093971191783182601726081775951103310666314834569091037713,\n", "38612156878839717097806285947575477749087608521505464809942918879152074545066,\n", "19752610610343814834081989345964253902282700341539483876504601969121084774539,\n", "46567545048462867923299713424766325689670511126407629551256255807498976196546,\n", "9520793415506326549109545537894287560752519598132096386048093015534488804808,\n", "22814234098357034097599682726494820560934925862581927123816510593532324971186,\n", "3277621627834606517208177071759088097855048183641615082769528872043050020787,\n", "29230456498980145088774069819561206654397510279226264474986155631775387918911,\n", "19087113294497892618475669593723876605785307026981218038380435259594863105240,\n", "39932371919358015185769877859035474336011770016475087638554815294278664040916,\n", "17645770319151120318035258350885823104235488352935695302274836429012504407725,\n", "17990728141399065004015538797609951295983853332644474801890158217822768128628,\n", "12607949331462269429981198199999740921418125994747028428126661151190418292729,\n", "33067617079394435172767143524489677593390850035349407507374659268468278200906,\n", "10025233623562179533044093426455032352895184661359005809314430689113735312874,\n", "20398677688057466110325934731430812468657996794663167456321709689030080949228,\n", "32085671199853825909918260218834827339732598508827083525700252644622592932757,\n", "36451986593067827349794003109666944974266236856145879921902940325507228739480,\n", "51835224419566813714481533481210630888564327175625175437244377303858990291964,\n", "1944662263588038198375346521900053780907777056656211622999059135594196413076,\n", "12995068374816903282074967132431954020410301768622808407703775963080983755183,\n", "13278128079226679628648689279705910775020794457648431336050464485837924986341,\n", "39207195481789228835625472428521288347432218258431761869689775532020546099642,\n", "21081768833381902942114733002158882075348844281359283013642620389621494952015,\n", "20751788049060260683191405008569080723662271828149227137187075968560831545739,\n", "20820291785607398388900832350860967875629907105847554413318238165275470374689,\n", "6971878585215744613467847324629115462668098071102846520957717612260531709386,\n", "42421164250058173810994728364144776180689735894673627964404703973460802099146,\n", "32890116643831560295329417521056875595733120141391587236744387068135440602102,\n", "42670005614507618780436482775021159957307712089310941922452133588875084445464,\n", "21120353743307986506720883740380468652053382764895882204680310593048134053982,\n", "7853308243263055176258751393326645428041138029306706980470113526802326214700,\n", "17545076036297840030021082424260289805456380863517895917265467158332801090765,\n", "29526223376722400691172584788126610514669516909826971155598997488361793726636,\n", "48421712782536172546302502401679048379568171245541707202282458591545347755349,\n", "10740853637774754893036062076749871837371049036966225040269105665447180116170,\n", "34042041521558704677804677569712674569738576001717295340556848855085089618161,\n", "24290796201833228559129233924595614281891670608675107544294264860003803501509,\n", "26722678647461522072509896114724736555938247563993442152746954157222882824350,\n", "20252491387019425681551488261397157776479297799360691728406809731508542196845,\n", "50322025264206689090790987370440439179141270613911973034521438238687587958097,\n", "17070806525931584028449131949070191143344166668070820337429561524629464200550,\n", "25856554324149146992239414502939942208580094928192925471532421030223074525051,\n", "17714998974036855356530338446243137421735047395517260588250413348153258772076,\n", "44833315250334176776685835079382312848180252180173884969157994737319426976437,\n", "35603718839327251012037553292043899153393807438387129505923567878785822738162,\n", "20515196301761603016197694845695272699608637099106794944737311528118558777570,\n", "10100400556460905874275078234698187530913105549037797180493988678937053918124,\n", "29943022708270799252522211109308629054849337552699067311814388215768905671554,\n", "33400164627534996188947689774080657908147988421361870074239537729877153299092,\n", "45574161704098228712016716221086232277248798839906622903502141601878895917316,\n", "40623265267364613450776577487319920007897396936924051398790906883872334022964,\n", "37929176440858430683261948300797278761072096845318183419284347376614069989808,\n", "12242010394227909997626655999345208835040087302065045201635069094289920778463,\n", "38947272924417356803622776795797899233194116520680026665045628837194239730633,\n", "6838505804652359252670794375725267665530548946030641535297433541475260948424,\n", "21345718918993308853491352363460625447157796362108157527364130872100101143328,\n", "26397988737034501095129796920971941795766209722106383463197090306632188634870,\n", "47092791129593573928369881528796435131623991381197863072979392492232678100884,\n", "36850972241154890671857874025605504779963735054128436776319531005864791472123,\n", "27893799443241349360688137159923920340185830261519093384488134540544971987330,\n", "34031071010517479317003393843135868322188010660871691856659878788331169912272,\n", "3102550735908358465878301372253437950829524988677083749179431098369388780259,\n", "2963742902601529003553690631564645593518709846059084207036841793643477514707,\n", "34538583661636382515652368664945657625216404085453317149263146639486246251503,\n", "49179786922858759927440465310900376749726765337268308911471491527044937447403,\n", "31668552784983283483593666924944066737680315058069542500069213700768949573692,\n", "47303630019147536941220901582952982856517915740884282232588733470564849742080,\n", "41561182787858915334837446901194440640033856888621022207410120224293681204923,\n", "40208795410444394963490428737133513683110766973508056822474493355065333491217,\n", "24620569969402072776192280888011017497854992833864712509770555543278833718751,\n", "31418811028946653724823259636547682581071379929451162101915628592655152015310,\n", "25964807298150242099204032696543021731332498792173212422070959505270506288817,\n", "31766013031271106581980804902159064978010553325475976472264348555438361464655,\n", "15107529391758643095716794813038523751713309080738989300826699946985294497278,\n", "26149402682269665088314773514719203730233986608723938665192802061570851149320,\n", "35053126320072620250684851851709987160095640397875384355477447570643983599564]\n", "\n", "def mix(state):\n", " state[0] = state[0] + state[1] + state[2];\n", " state[1] = state[0] + state[1];\n", " state[2] = state[0] + state[2];\n", " return state\n", "\n", "def round_comp(state, idx, full):\n", " if full:\n", " state[0] += poseidon_comp_consts[idx]\n", " state[1] += poseidon_comp_consts[idx + 1]\n", " state[2] += poseidon_comp_consts[idx + 2]\n", " # Optimize multiplication\n", " state[0] = state[0] * state[0] * state[0] * state[0] * state[0]\n", " state[1] = state[1] * state[1] * state[1] * state[1] * state[1]\n", " state[2] = state[2] * state[2] * state[2] * state[2] * state[2]\n", " else:\n", " state[0] += poseidon_comp_consts[idx]\n", " state[2] = state[2] * state[2] * state[2] * state[2] * state[2]\n", " state = mix(state)\n", " return state\n", "\n", "def poseidon_permute_comp_bls(state):\n", " idx = 0;\n", " state = mix(state);\n", "\n", " # Full rounds\n", " for i in range(4):\n", " state = round_comp(state, idx, true);\n", " idx += 3;\n", "\n", " # Partial rounds\n", " for i in range(56):\n", " state = round_comp(state, idx, false);\n", " idx += 1;\n", "\n", " # Full rounds\n", " for i in range(4):\n", " state= round_comp(state, idx, true);\n", " idx += 3;\n", " return state\n", "\n", " \n", "def poseidon_hash_bls(x, y):\n", " state = [F(x), F(y), F(0)];\n", " poseidon_permute_comp_bls(state);\n", " return state[0] + F(x)\n", "\n", "\n", "def poseidon_hash_many_bls(msgs):\n", " state = [F(0), F(0), F(0)];\n", " for i in range(len(msgs)//2):\n", " state[0] += F(msgs[2*i])\n", " state[1] += F(msgs[2*i + 1])\n", " state = poseidon_permute_comp_bls(state)\n", " if len(msgs) % 2 == 1:\n", " state[0] += F(msgs[len(msgs)-1])\n", " state[len(msgs)%2] += F(1);\n", " state = poseidon_permute_comp_bls(state)\n", " return state[0]" ] }, { "cell_type": "code", "execution_count": 3, "id": "67a09953", "metadata": {}, "outputs": [], "source": [ "def draw_felt252(digest, n_sent):\n", " res = poseidon_hash_bls(digest, F(n_sent));\n", " return res\n", "\n", "def draw_base_felts(digest, n_sent):\n", " shift = 1 << 31\n", " cur = int(draw_felt252(digest, n_sent))\n", " n_sent += 1\n", " u32s = []\n", " quotient = 1\n", " while(quotient != 0):\n", " quotient = cur // shift\n", " if quotient != 0:\n", " remainder = cur % shift\n", " cur = quotient\n", " u32s.append(M31(remainder))\n", " return u32s\n", "\n", "def draw_random_bytes(digest, n_sent):\n", " shift = 1 << 8\n", " cur = int(draw_felt252(digest, n_sent))\n", " byte = []\n", " for i in range(31):\n", " quotient = cur // shift\n", " remainder = cur % shift\n", " cur = quotient\n", " byte.append(remainder)\n", " return byte\n", "\n", "def hash_node(has_children, left, right, column_values):\n", " n_column_blocks = ceil(len(column_values) / 8.0);\n", " values = []\n", " if has_children:\n", " values.append(left)\n", " values.append(right)\n", " padding_length = 8 * n_column_blocks - len(column_values)\n", " padded_values = column_values + [F(0) for i in range(padding_length)]\n", " for i in range(int(len(padded_values) / 8)):\n", " word = F(0)\n", " for j in range(8):\n", " word = word * F(2**31) + F(padded_values[i*8+j])\n", " values.append(word)\n", " return poseidon_hash_many_bls(values)" ] }, { "cell_type": "code", "execution_count": 4, "id": "1bce81d8", "metadata": {}, "outputs": [], "source": [ "M31 = FiniteField(2**31 - 1)\n", "Poly_1. = PolynomialRing(M31)\n", "poly_1 = x**2+1\n", "CM31. = M31.extension(poly_1)\n", "CM31\n", "\n", "Poly_2. = PolynomialRing(CM31)\n", "poly_2 = y**2 - 2 - i\n", "QM31. = CM31.extension(poly_2)" ] }, { "cell_type": "code", "execution_count": 5, "id": "16aa579c", "metadata": {}, "outputs": [], "source": [ "# A class to represent points on a circle using fields.\n", "class CirclePoint:\n", " def __init__(self, x, y):\n", " self.x = x\n", " self.y = y\n", "\n", " @staticmethod\n", " def zero():\n", " \"\"\"Returns the identity element of the circle.\"\"\"\n", " return CirclePoint(1, 0)\n", "\n", " def double(self):\n", " \"\"\"Returns the point after doubling.\"\"\"\n", " return self + self\n", "\n", " @staticmethod\n", " def double_x(x):\n", " \"\"\"Applies the x-coordinate doubling map.\"\"\"\n", " sx = x**2\n", " return sx + sx - 1\n", "\n", " def log_order(self):\n", " \"\"\"Returns the log order of the point (as a power of 2).\"\"\"\n", " res = 0\n", " cur = self.x\n", " while cur != 1:\n", " cur = self.double_x(cur)\n", " res += 1\n", " return res\n", "\n", " def mul(self, scalar):\n", " \"\"\"Multiplies the point by a scalar.\"\"\"\n", " res = CirclePoint.zero()\n", " cur = self\n", " while scalar > 0:\n", " if scalar & 1 == 1:\n", " res = res + cur\n", " cur = cur + cur\n", " scalar = int(scalar / 2)\n", " return res\n", "\n", " def repeated_double(self, n):\n", " \"\"\"Returns the point after repeated doubling.\"\"\"\n", " res = self\n", " for _ in range(n):\n", " res = res.double()\n", " return res\n", "\n", " def conjugate(self):\n", " \"\"\"Returns the conjugate of the point.\"\"\"\n", " return CirclePoint(self.x, -self.y)\n", "\n", " def antipode(self):\n", " \"\"\"Returns the antipode of the point.\"\"\"\n", " return CirclePoint(-self.x, -self.y)\n", "\n", " def mul_signed(self, off):\n", " \"\"\"Multiplies the point by a signed scalar.\"\"\"\n", " if off > 0:\n", " return self.mul(off)\n", " else:\n", " return self.conjugate().mul(-off)\n", "\n", " def __add__(self, other):\n", " \"\"\"Adds two circle points.\"\"\"\n", " return CirclePoint(self.x * other.x - self.y * other.y, self.x * other.y + self.y * other.x)\n", "\n", " def __repr__(self):\n", " return f\"CirclePoint(x={self.x}, y={self.y})\"" ] }, { "cell_type": "code", "execution_count": 9, "id": "d9371b02", "metadata": {}, "outputs": [], "source": [ "# First Fiat-Shamir\n", "digest = poseidon_hash_bls(0,proof[\"commitments\"][0])\n", "\n", "# Draw first random coeff\n", "random_coeff = QM31([draw_base_felts(digest,0)[:2],draw_base_felts(digest,0)[2:4]])\n", "\n", "# Second Fiat-Shamir\n", "digest = poseidon_hash_bls(digest,proof[\"commitments\"][1])\n", "\n", "# Draw OODS sample point\n", "t = QM31([draw_base_felts(digest,0)[:2],draw_base_felts(digest,0)[2:4]])\n", "t_square = t**2\n", "one_plus_tsquared_inv = (t_square + QM31(1)) ** (-1)\n", "x = (1 - t_square) * one_plus_tsquared_inv\n", "y = 2*t*one_plus_tsquared_inv\n", "oods_point = CirclePoint(x,y)\n", "\n", "# Derive sample points for now offset is always 0 so sampled points are all equals oods_point\n", "\n", "# Load sampled_values_1 and verify that they are in QM31\n", "\n", "# Then we verify the composition polynomial evaluation:\n", "point = oods_point\n", "mask_values = proof[\"sampled_values_0\"] + proof[\"sampled_values_1\"]\n", "\n", "\n", "\n", "\n", "# Evaluate random point on the vanishing polynomial of the coset\n", "evaluation = point.x\n", "for i in range(5):\n", " evaluation = CirclePoint.double_x(evaluation)\n", "evaluation_inverse = evaluation ** (-1)\n", "\n", "# Compute evaluation using the mask values\n", "accumulator = QM31(0)\n", "a = QM31([mask_values[0][:2],mask_values[0][2:4]])\n", "b = QM31([mask_values[1][:2],mask_values[1][2:4]])\n", "for i in range(len(proof[\"sampled_values_0\"])-2):\n", " c = QM31([mask_values[2+i][:2],mask_values[2+i][2:4]])\n", " accumulator = (c - (a**2 + b**2))*evaluation_inverse + accumulator * random_coeff\n", " a = b\n", " b = c\n", "\n", "expected_value = QM31([proof[\"sampled_values_1\"][0][:2],proof[\"sampled_values_1\"][0][2:4]]) + QM31([proof[\"sampled_values_1\"][1][:2],proof[\"sampled_values_1\"][1][2:4]]) * QM31([[0,1],[0,0]]) + QM31([proof[\"sampled_values_1\"][2][:2],proof[\"sampled_values_1\"][2][2:4]]) * QM31([[0,0],[1,0]]) + QM31([proof[\"sampled_values_1\"][3][:2],proof[\"sampled_values_1\"][3][2:4]]) * QM31([[0,0],[0,1]])\n", "\n", "assert(expected_value == accumulator)\n", "\n", "\n", "####FRI part\n", "# Fiat-Shamir\n", "shift = F(1 << 31)\n", "res = [digest]\n", "for i in range(len(mask_values) / 2):\n", " cur = F(0)\n", " for j in range(2):\n", " for k in range(4):\n", " cur = cur * shift + F(mask_values[2*i+j][k])\n", " res.append(cur)\n", "digest = poseidon_hash_many_bls(res)\n", "random_coeff = QM31([draw_base_felts(digest,0)[:2],draw_base_felts(digest,0)[2:4]])\n", "\n", "# Verify commitment stage\n", "circle_poly_alpha = QM31([draw_base_felts(digest,1)[:2],draw_base_felts(digest,1)[2:4]])\n", "folding_alpha = []\n", "for i in range(6):\n", " digest = poseidon_hash_bls(digest,proof[\"inner_commitment_\"+str(i)])\n", " folding_alpha.append(QM31([draw_base_felts(digest,0)[:2],draw_base_felts(digest,0)[2:4]]))\n", "last_layer_poly = QM31([proof[\"coeffs\"][:2],proof[\"coeffs\"][2:4]])\n", "\n", "#Check proof of work\n", "res = [digest]\n", "cur = F(0)\n", "for i in range(4):\n", " cur = cur * shift + F(proof[\"coeffs\"][i])\n", "res.append(cur)\n", "digest = poseidon_hash_many_bls(res)\n", "digest = poseidon_hash_bls(digest, proof[\"proof of work\"])\n", "# The first 5 bits following the first 1 must be 0 for proof of work\n", "for i in range(5):\n", " assert(bin(digest)[3+i] == '0')\n", "\n", "# Compute openings positions\n", "querries = []\n", "max_querry = (1<<8)-1\n", "random_bytes = draw_random_bytes(digest,0)\n", "# The number of required querries is 3 so we need 3*8 bytes wich is enough with the 31 bytes of random_bytes\n", "for i in range(3):\n", " querry_bits = int().from_bytes(random_bytes[i*4:i*4+4],byteorder=\"little\")\n", " querries.append(querry_bits & max_querry)\n", "positions = []\n", "# For each collumn\n", "for i in range(2):\n", " # For each querry\n", " for j in range(3):\n", " positions.append(querries[j] >> (1+i))\n", "positions_sav = positions.copy()\n", "\n", "\n", "#Verify decommitments (this part must be simplified repeting duplicated inputs)\n", "# First tree\n", "nodes = {}\n", "for i in range(6):\n", " leaf = []\n", " for j in range(100):\n", " leaf.append(M31(proof[\"queried_values_0\"][j][i]))\n", " nodes[\"level_0_node_\"+str(positions[i//2] // 2 * 2 + i % 2) ] = hash_node(false,0,0,leaf)\n", "counter = 0\n", "for level in range(7):\n", " for i in range(3):\n", " if \"level_\"+str(level)+\"_node_\"+str(positions[len(positions)-3] * 2) in nodes:\n", " lhs = nodes[\"level_\"+str(level)+\"_node_\"+str(positions[len(positions)-3] * 2)]\n", " else:\n", " lhs = F(proof[\"decommitment_0\"][counter])\n", " counter += 1\n", " if \"level_\"+str(level)+\"_node_\"+str(positions[len(positions) - 3] * 2 + 1) in nodes:\n", " rhs = nodes[\"level_\"+str(level)+\"_node_\"+str(positions[len(positions) - 3] * 2 + 1)]\n", " else:\n", " rhs = F(proof[\"decommitment_0\"][counter])\n", " counter += 1\n", " nodes[\"level_\"+str(level+1)+\"_node_\"+str(positions[len(positions)-3])] = hash_node(true,lhs,rhs,[])\n", " positions.append(positions[len(positions)-3] // 2)\n", "assert(nodes[\"level_7_node_0\"] == F(proof[\"commitments\"][0]))\n", "\n", "#Second tree\n", "positions = positions_sav\n", "for i in range(len(positions)):\n", " positions[i] = positions[i] * 2\n", "nodes = {}\n", "for i in range(6):\n", " leaf = []\n", " for j in range(4):\n", " leaf.append(M31(proof[\"queried_values_1\"][j][i]))\n", " nodes[\"level_0_node_\"+str(positions[i//2] // 2 * 2 + i % 2) ] = hash_node(false,0,0,leaf)\n", "counter = 0\n", "for level in range(8):\n", " for i in range(3):\n", " if \"level_\"+str(level)+\"_node_\"+str(positions[len(positions)-3] * 2) in nodes:\n", " lhs = nodes[\"level_\"+str(level)+\"_node_\"+str(positions[len(positions)-3] * 2)]\n", " else:\n", " lhs = F(proof[\"decommitment_1\"][counter])\n", " counter += 1\n", " if \"level_\"+str(level)+\"_node_\"+str(positions[len(positions) - 3] * 2 + 1) in nodes:\n", " rhs = nodes[\"level_\"+str(level)+\"_node_\"+str(positions[len(positions) - 3] * 2 + 1)]\n", " else:\n", " rhs = F(proof[\"decommitment_1\"][counter])\n", " counter += 1\n", " nodes[\"level_\"+str(level+1)+\"_node_\"+str(positions[len(positions)-3])] = hash_node(true,lhs,rhs,[])\n", " if level == 0:\n", " nodes[\"level_1_node_\"+str(positions[len(positions)-3] + 1)] = hash_node(true,nodes[\"level_0_node_\"+str((positions[len(positions)-3] + 1)* 2)],nodes[\"level_0_node_\"+str((positions[len(positions)-3] + 1)* 2 + 1)],[])\n", " positions.append(positions[len(positions)-3] // 2)\n", "assert(nodes[\"level_8_node_0\"] == F(proof[\"commitments\"][1]))\n", "\n", "\n", "# Check querries answer we have 104 samples each equal to x = oods_point and f(x) = sampled_value_i\n", "# For each column:\n", "for i in range(2):\n", " evaluations = []\n", " queried_values_per_column = proof[\"queried_values_\"+str(i)]" ] }, { "cell_type": "code", "execution_count": null, "id": "56e4c016", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "6b89599c", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 10, "id": "e486cb3a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[['316772341',\n", " '1526280133',\n", " '663010112',\n", " '224983897',\n", " '510598760',\n", " '1109503351'],\n", " ['754832207',\n", " '435790299',\n", " '883623752',\n", " '553207508',\n", " '154784232',\n", " '199176676'],\n", " ['689603315',\n", " '1763523007',\n", " '1720552945',\n", " '1983603154',\n", " '367841669',\n", " '319325418'],\n", " ['1290247052',\n", " '1120744584',\n", " '193500372',\n", " '294491115',\n", " '951360807',\n", " '891034447']]" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "queried_values_per_column" ] }, { "cell_type": "code", "execution_count": null, "id": "85dd52b3", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "SageMath 9.5", "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.10.12" } }, "nbformat": 4, "nbformat_minor": 5 }