Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

step5 - verifier #3

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
381 changes: 381 additions & 0 deletions tutorial/Stark101-part5.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,381 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Part 5: Verifier\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Load the Previous Session\n",
"Run the next cell to load the variables we'll use in this part. Since it repeats everything done in previous parts - it will take a while to run."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Generating the trace...\n",
"13.96262812614441s\n",
"Generating the composition polynomial and the FRI layers...\n",
"20.6886248588562s\n",
"Generating queries and decommitments...\n",
"0.7515149116516113s\n",
"Overall time: 35.40322494506836s\n",
"Uncompressed proof length in characters: 46153\n"
]
}
],
"source": [
"import time\n",
"from tutorial_sessions import part1, part3 \n",
"\n",
"def decommit_on_fri_layers(idx, channel):\n",
" for layer, merkle in zip(fri_layers[:-1], fri_merkles[:-1]):\n",
" length = len(layer)\n",
" idx = idx % length\n",
" sib_idx = (idx + length // 2) % length \n",
" channel.send(str(layer[idx]))\n",
" channel.send(str(merkle.get_authentication_path(idx)))\n",
" channel.send(str(layer[sib_idx]))\n",
" channel.send(str(merkle.get_authentication_path(sib_idx)))\n",
" channel.send(str(fri_layers[-1][0]))\n",
"\n",
"def decommit_on_query(idx, channel): \n",
" assert idx + 16 < len(f_eval), f'query index: {idx} is out of range. Length of layer: {len(f_eval)}.'\n",
" channel.send(str(f_eval[idx])) # f(x).\n",
" channel.send(str(f_merkle.get_authentication_path(idx))) # auth path for f(x).\n",
" channel.send(str(f_eval[idx + 8])) # f(gx).\n",
" channel.send(str(f_merkle.get_authentication_path(idx + 8))) # auth path for f(gx).\n",
" channel.send(str(f_eval[idx + 16])) # f(g^2x).\n",
" channel.send(str(f_merkle.get_authentication_path(idx + 16))) # auth path for f(g^2x).\n",
" decommit_on_fri_layers(idx, channel) \n",
"\n",
"def decommit_fri(channel):\n",
" for query in range(3):\n",
" # Get a random index from the verifier and send the corresponding decommitment.\n",
" decommit_on_query(channel.receive_random_int(0, 8192-16-1), channel)\n",
"\n",
"start = time.time()\n",
"start_all = start\n",
"print(\"Generating the trace...\")\n",
"_, _, _, _, _, _, _, f_eval, f_merkle, _ = part1()\n",
"print(f'{time.time() - start}s')\n",
"start = time.time()\n",
"print(\"Generating the composition polynomial and the FRI layers...\")\n",
"fri_polys, fri_domains, fri_layers, fri_merkles, channel = part3()\n",
"print(f'{time.time() - start}s')\n",
"start = time.time()\n",
"print(\"Generating queries and decommitments...\")\n",
"decommit_fri(channel)\n",
"print(f'{time.time() - start}s')\n",
"start = time.time()\n",
"# print(channel.proof)\n",
"print(f'Overall time: {time.time() - start_all}s')\n",
"print(f'Uncompressed proof length in characters: {len(str(channel.proof))}')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Verify\n",
"verify the random numbers in the channel.\n",
"TODO: reduce proof size by removing the random numbers from the proof and recomputing them as in here"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Success!\n"
]
}
],
"source": [
"from channel import Channel\n",
"\n",
"verifier_channel = Channel()\n",
"for i, c in enumerate(channel.proof):\n",
" if c.startswith('send:'):\n",
" verifier_channel.send(c[len('send:'):])\n",
"# print(f'{i} send')\n",
" elif c.startswith('receive_random_field_element:'):\n",
" verifier_channel.receive_random_field_element()\n",
" assert verifier_channel.proof[-1] == c,f\"r={r} c={c}\"\n",
"# print(f'{i} receive_random_field_element')\n",
" elif c.startswith('receive_random_int:'):\n",
" verifier_channel.receive_random_int(0, 8192-16-1)\n",
" assert verifier_channel.proof[-1] == c,f\"r={r} c={c}\"\n",
"# print(f'{i} receive_random_int')\n",
" else:\n",
" raise f\"unknown channel prefix {c}\"\n",
" \n",
"print('Success!')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"utilites to read information from the channel's proof"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"channel_idx = 0\n",
"\n",
"def get_s(s='send:'):\n",
" global channel_idx\n",
" assert channel_idx < len(channel.proof)\n",
" assert channel.proof[channel_idx].startswith(s)\n",
" v = channel.proof[channel_idx][len(s):]\n",
" channel_idx += 1\n",
" return v\n",
"\n",
"def get_f():\n",
" v = get_s('receive_random_field_element:')\n",
" return FieldElement(int(v))\n",
"\n",
"def get_i():\n",
" v = get_s('receive_random_int:')\n",
" return int(v)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### channel information from part 1"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"mt_root = get_s() # of the 8K points on the trace poly"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### channel information from part 2"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"from field import FieldElement\n",
"\n",
"alpha0 = get_f()\n",
"alpha1 = get_f()\n",
"alpha2 = get_f()"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"cp_mt_root = get_s() # of the 8K points on the composite poly"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### channel information from part 3"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Below the function `cp` returns the value of the composite polynomial at `x`. Note that this is the only place in the verifier where we enter the constrains (algorithm, parameters and result) of what we want to prove\n",
"* `x` is value on the evaluation domain of the polynomials (8K points)\n",
"* `f=f0` is the value of the interpolated polynimal `p` of the trace at the point `x`\n",
"* `f1` is the value of the interpolated polynimal at `g * x` this point has an index which is +8 the index of `x`\n",
"* `f2` is the value of the interpolated polynimal at `g * g * x` this point has an index which is +16 the index of `x`"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"g = FieldElement.generator() ** (3 * 2 ** 20)\n",
"\n",
"def p0(x,f):\n",
" return (f-1)/(x-1)\n",
"\n",
"def p1(x,f):\n",
" return (f-2338775057)/(x-g**1022)\n",
"\n",
"def p2(x,f0,f1,f2):\n",
" return (f2 - f1*f1 - f0*f0)/((1 - x**1024) / ((x - g**1021) * (x - g**1022) * (x - g**1023)))\n",
"\n",
"def cp(x,f0,f1,f2):\n",
" return alpha0*p0(x,f0) + alpha1*p1(x,f0) + alpha2*p2(x,f0,f1,f2)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"alphas = []\n",
"fri_merkles_root = [cp_mt_root]\n",
"while channel.proof[channel_idx].startswith('receive_random_field_element:') and channel.proof[channel_idx+1].startswith('send:'):\n",
" alphas.append(get_f())\n",
" fri_merkles_root.append(get_s())\n",
"fri_constant = FieldElement(int(get_s()))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### channel information from part 4\n",
"Repeat query 3 times. In each query:\n",
"* read and merkle validate value of intepolated polynomal at a random point `x` (idx) and `g*x` (idx+8) and `g*g*x` (idx+16)\n",
"* compute the value of the composite polynoimal at `x`\n",
"* read and merkle validate the value of the first fri layer at `x`.\n",
"* compare the fri value at `x` to the computed value. Note that we are not doing the same for `-x`\n",
"* compute next layer value\n",
"* repeat on next layer at same index which is `x**2`"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Success!\n"
]
}
],
"source": [
"#channel_idx = 26 # reset for repeated debug runs\n",
"from merkle import verify_decommitment\n",
"\n",
"idxs = []\n",
"w = FieldElement.generator()\n",
"h = w ** ((2 ** 30 * 3) // 8192)\n",
"\n",
"def read_verify(idx,root):\n",
" v = get_s()\n",
" # TODO using eval on a string coming from an untrusted source is dangerous\n",
" assert verify_decommitment(idx,v,eval(get_s()),root)\n",
" return FieldElement(int(v))\n",
"\n",
"for query in range(3):\n",
"# print(query)\n",
" idx = get_i() # pick a random location in the domain\n",
" assert idx < 8192\n",
" \n",
" # sample the interpolated poly of the trace `f` at 3 locations that are one distance apart in the trace domain\n",
" # one step in the trace domain is 8 in the evaluation domain\n",
" f0 = read_verify(idx,mt_root) # f(x)\n",
" f1 = read_verify(idx+8,mt_root) # f(gx)\n",
" f2 = read_verify(idx+16,mt_root) # f(g^2x)\n",
" \n",
" x0 = w * (h ** idx)\n",
" next_cp0 = cp(x0,f0,f1,f2) # compute the value of the composite poly `cp` from `f`\n",
" length = 8192\n",
" # TODO we dont need to send fri_merkles_root[-1] in the channel\n",
" for i,(fri_merkle_root,alpha) in enumerate(zip(fri_merkles_root[:-1],alphas)):\n",
"# print(f'i={i}')\n",
" idx = idx % length\n",
" x0 = w * (h ** idx) # convert the index idx to a point in the evaluation domain. needed for cp_odd below\n",
" x0 = x0 ** (2**i)\n",
" cp0 = read_verify(idx,fri_merkle_root)\n",
" assert cp0 == next_cp0\n",
"\n",
" sib_idx = (idx + length // 2) % length \n",
"# x1 = w * (h ** sib_idx) # convert the index sib_idx to a point in the evaluation domain\n",
"# x1 = x1 ** (2**i)\n",
"# assert x0*x0 == x1*x1,'x0 != -x1'\n",
" cp1 = read_verify(sib_idx,fri_merkle_root)\n",
" # note we dont check cp1 because we dont have a computed value\n",
"\n",
" cp_even = (cp0 + cp1) / 2\n",
" cp_odd = (cp0 - cp1) / 2\n",
" cp_odd /= x0\n",
" next_cp0 = cp_even + alpha * cp_odd\n",
"\n",
" length = length // 2\n",
" \n",
" assert fri_constant == next_cp0\n",
" # TODO the proof implementation above gives us fri_constant again after each iteration. We dont need this\n",
" assert fri_constant == FieldElement(int(get_s()))\n",
" \n",
"assert channel_idx == len(channel.proof), 'we did not reach the end of the channel'\n",
"\n",
"print('Success!')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}