stark 证明实操 python 实现 04

译者:Xiang|W3.Hitchhiker


第四部分:查询阶段

加载之前的代码

运行下面代码块以加载我们将在这部分中使用的变量。由于它会重复前面部分中所做的所有操作 - 运行需要一段时间。

from channel import Channel
from tutorial_sessions import part1, part3 

_, _, _, _, _, _, _, f_eval, f_merkle, _ = part1()
fri_polys, fri_domains, fri_layers, fri_merkles, _ = part3()

print('Success!')

查询上解承诺(decommit)

我们在这部分的目标是生成验证前三个部分的承诺所需的所有信息。 这部分我们写了两个函数:

  1. decommit_on_fri_layers - 以特定索引采样时,通过信道发送数据显示每个 FRI 层与其他层一致。

  2. decommit_on_query - 发送轨迹上解承诺所需的数据,然后调用 decommit_on_fri_layers

在 FRI 层上解承诺

实施 decommit_on_fri_layers 函数。 该函数获取索引和信道,并通过信道发送相关数据以验证 FRI 层的正确性。 更具体地说,它迭代 fri_layersfri_merkles 并且在每次迭代中它发送以下数据(按规定的顺序):

请注意,我们发送最后一层元素的身份验证路径。 在最后一层,所有元素都是相等的,无论查询如何,因为它们是常数多项式的评估。

(请记住在通过信道发送之前将非字符串变量转换为字符串。)

def decommit_on_fri_layers(idx, channel):
    for layer, merkle in zip(fri_layers[:-1], fri_merkles[:-1]):
        length = len(layer)
        idx = idx % length
        sib_idx = (idx + length // 2) % length        
        channel.send(str(layer[idx]))
        channel.send(str(merkle.get_authentication_path(idx)))
        channel.send(str(layer[sib_idx]))
        channel.send(str(merkle.get_authentication_path(sib_idx)))       
    channel.send(str(fri_layers[-1][0]))

跑测试:

# Test against a precomputed hash.
test_channel = Channel()
for query in [7527, 8168, 1190, 2668, 1262, 1889, 3828, 5798, 396, 2518]:
    decommit_on_fri_layers(query, test_channel)
assert test_channel.state == 'ad4fe9aaee0fbbad0130ae0fda896393b879c5078bf57d6c705ec41ce240861b', 'State of channel is wrong.'
print('Success!')

在轨迹多项式上解承诺

为了证明我们解承诺的 FRI 层确实是从组合多项式的评估中生成的,我们还必须发送:

验证者知道组合多项式的随机系数,可以计算其在 x 处的评估,并将其与第一个 FRI 层发送的第一个元素进行比较。

因此,函数 decommit_on_query 应该通过信道发送上述(1、2 和 3),然后调用 decommit_on_fri_layers

提示:f_eval是组合多项式的评估,f_merkle是对应的 Merkle 树。

def decommit_on_query(idx, channel): 
    assert idx + 16 < len(f_eval), f'query index: {idx} is out of range. Length of layer: {len(f_eval)}.'
    channel.send(str(f_eval[idx])) # f(x).
    channel.send(str(f_merkle.get_authentication_path(idx))) # auth path for f(x).
    channel.send(str(f_eval[idx + 8])) # f(gx).
    channel.send(str(f_merkle.get_authentication_path(idx + 8))) # auth path for f(gx).
    channel.send(str(f_eval[idx + 16])) # f(g^2x).
    channel.send(str(f_merkle.get_authentication_path(idx + 16))) # auth path for f(g^2x).
    decommit_on_fri_layers(idx, channel)   

一组查询的解承诺

为了完成证明,证明者从信道中获取一组随机查询,即 0 到 8191 之间的索引,并在每个查询上解承诺。

使用你刚刚实现的函数 decommit_on_query()Channel.receive_random_int 生成 3 个随机查询并在每个查询上解承诺。

def decommit_fri(channel):
    for query in range(3):
        # Get a random index from the verifier and send the corresponding decommitment.
        decommit_on_query(channel.receive_random_int(0, 8191-16), channel)

证明时间!

运行以下将它们联系在一起的代码块,运行所有以前的代码,以及你在这部分中编写的函数,并打印证明。

import time
from tutorial_sessions import part1, part3 

start = time.time()
start_all = start
print("Generating the trace...")
_, _, _, _, _, _, _, f_eval, f_merkle, _ = part1()
print(f'{time.time() - start}s')
start = time.time()
print("Generating the composition polynomial and the FRI layers...")
fri_polys, fri_domains, fri_layers, fri_merkles, channel = part3()
print(f'{time.time() - start}s')
start = time.time()
print("Generating queries and decommitments...")
decommit_fri(channel)
print(f'{time.time() - start}s')
start = time.time()
print(channel.proof)
print(f'Overall time: {time.time() - start_all}s')
print(f'Uncompressed proof length in characters: {len(str(channel.proof))}')
Subscribe to W3.Hitchhiker
Receive the latest updates directly to your inbox.
Mint this entry as an NFT to add it to your collection.
Verification
This entry has been permanently stored onchain and signed by its creator.