理解 Lasso (五):表格的 MLE 结构

本文介绍 Generalized Lasso,也是 [Lasso] 论文的关键部分之一。与 Lasso 相比,Generalized Lasso 不再对大表格进行拆分,而是把表格作为整体进行证明。为了处理超大尺寸表格,Generalized Lasso 需要要求表格中的每一项是可以通过其 Index 的二进制表示进行计算得到。对于尺寸为 的超大表格而言,其 Index 的二进制位数量为 ,因此表格的表项的计算复杂度一定为

这样做的一个优势是,Prover 可以不必要对表格进行承诺计算,当 Verifier 挑战表格编码的多项式时,Verifier 可以自行计算挑战点的多项式求值,因为这个运算复杂度仅为 。这样 Prover 可以节省大量的计算时间。

1. 什么是 MLE-Structured

按照 [Lasso] 论文的定义,MLE-structured 是指任何 MLE 多项式 可以在 时间的计算复杂度内完成求值运算。这里 为多项式未知数的个数。

哪些表格具有这种 MLE-structured 的性质呢?下面给出一些常用的例子:

  • Range check 表格,
  • 连续偶数或者奇数构成的表格,
  • Spread 表格。一种在数字二进制表示的相邻两位插入 0 的表格,例如,对于 。这种表格用来加速实现位运算。

2. Generalized Lasso

Generalized Lasso 可以构造针对 MLE-Structured 表格的 Indexed Lookup Argument。其核心是证明下面的等式:

这里 为查询向量,长度为 为表格向量,长度为 为表格选择矩阵,其中每一行是一个 Unit Vector。而 MLE 多项式 编码了 编码了 ,而 编码了 矩阵。

Prover 和 Verifier 需要证明每一个 等于某个表项 。他们共同拥有的 Public Inputs 为表格向量与查询向量的多项式承诺,因为我们现在只关注 Indexed Lookup Argument,因此他们还共同拥有 的多项式承诺。

协议的第一步是 Verifier 发送一个挑战向量 ,使得上面的约束转化为:

Verifier 可以通过查询 Oracle 来得到 的值,我们记为 。于是上面的等式就归约到了一个求和式:

此刻,Prover 和 Verifier 可以调用 Sumcheck 协议来完成求和式的证明。但是 Prover 需要计算 的值。

在 Sumcheck 协议的结尾,Prover 和 Verifier 可以利用多项式承诺的求值证明,证明 处的求值。尽管我们可以使用 Spark 稀疏多项式承诺来降低最后的求值证明的开销,但是 Prover 在 Sumcheck 协议过程中的计算量至少是

下一节我们介绍 Generalized Lasso 如何再次利用 矩阵的稀疏性,减少 Prover 在 Sumcheck 协议中的计算量。在此之前,我们先列出 Generalized Lasso 的协议框架:

协议框架

公共输入:

  1. 表格向量 的承诺:
  2. 查询向量 的承诺:
  3. 表格选择矩阵 的承诺:

第一轮:Verifier 发送挑战向量

第二轮:Prover 计算 的值,并且连同求值证明 一起发送给 Verifier

第三轮:Prover 和 Verifier 进行 Sparse-dense Sumcheck 协议,证明下面的等式:

经过 Sumcheck 协议,上面的约束等式被归约到:

第四轮:Prover 发送 与 求值证明 给 Verifier

第五轮:Verifier 验证下面的等式:

3. Simplified Sparse-dense Sumcheck

这一节,我们分析下 Prover 在 Sumcheck 协议中的开销,以及如何利用 的稀疏性质来减少 Prover 的计算量。

再重复下 Sumcheck 要证明的求和等式:

这里我们用 代替 ,它是一个稀疏的多项式,只有 个非零项。而 是一个 MLE-structured 的多项式,它的计算复杂度为

Sumcheck 协议总共 轮,在每一轮,Prover 主要的计算量为计算一个一元多项式并发送给 Verifier:

注意到这个一元多项式 个项的求和,但是 是一个稀疏的 MLE 多项式。如果 处的取值为零,那么 Prover 也就可以省去计算 的开销。因此,Prover 实际上只需要计算 个项的求和,而不是 个项。

进一步展开 的定义,我们可以得到:

其中 定义为 中非零项的索引集合。因此 求和式可以进一步简化为 项的求和:

每一轮,假设当前我们在第 轮,Prover 要计算 个项的求和,每一项包含两个乘法和两个 MLE 多项式的求值,分别为 。接着 Verifier 都会提供一个随机数 来求值 ,然后 Sumcheck 进入下一轮,即第 轮。

在第 轮, Prover 的策略是根据上一轮(第 轮)的 的求值来增量式的递推计算 ,即用 来代替

然后我们观察下 的定义,

注意到等式右边的三个乘积因子中的最右边一个恒等于 1。如果

那么当我们用 来代替 时,

因此,根据 还是 ,Prover 可以仅用一个乘法即可递推地计算出第 轮所需要的 。又因为总共有 需要计算,所以 Prover 要付出 的计算量。

Prover 可以维护一个长度为 的数组,里面保存 的值,每一轮过后就更新这个数组:

但是对于 这个求值运算,如果 没有内部结构,那么 Prover 需要老老实实进行求值运算。这样每一轮中 Prover 仍然需要执行 次 MLE 运算求值过程。在 轮的 Sumcheck 协议过程中,Prover 总共的计算量至少为

如果 恰好具有 MLE-Structured 性质,那么 ,那么 Prover 的计算量为

进一步,如果 具有「局部 bit 相关」的特性,即我们可以采用计算 的方法给出 的递推计算式:

这里 是两个多项式,他们的计算复杂度为 。如果 的递推计算能满足上面的等式,那么 Prover 就可以同样维护一个长度为 的数组,保存 所对应的 的值。这样 Prover 可以在每一轮中只需要总共 的计算量来计算更新所有需要用到的 的值。

这样一来, Prover 的计算量可以进一步降低为

下面举一个简单例子,来演示下整个过程。假设 ,一个稀疏的向量 ,表格向量 。稀疏向量的非零值数量为

Sumcheck 协议要证明的求和式为:

Prover 预计算 的值为 1,

在第 0 轮中,Prover 计算

可以看出,Prover 只需要计算 这四个多项式的值。而这四个多项式的计算量为 。Prover 发送 作为 的点值形式发送。

Verifier 发送挑战数 ,Prover 和 Verifier 检查

然后共同计算 作为新的求和。

Prover 更新

下面是第二轮,Prover 计算

Prover 只需要计算 这四个多项式的值。而这四个多项式的计算量为 。Prover 发送 作为 的点值形式发送。

Verifier 发送挑战数 ,Prover 和 Verifier 检查

Prover 维护 数组,更新到

到了第三轮,Prover 计算

如果 有内部结构,那么

Prover 发送 作为 的点值形式发送。

Verifier 发送挑战数 ,Prover 和 Verifier 检查

Prover 和 Verifier 最后通过 PCS 来验证下面的 Evaluation 等式:

Prover 更新 ,则得到

Prover 可以通过 来计算得到 ,计算时间复杂度为

Prover 并不需要发送 ,因为这个值可以由 Verifier 直接计算得到,计算时间复杂度为

综上,Prover 的计算量为

4. Standard Sparse-dense Sumcheck

标准的 Sparse-dense Sumcheck 可以把 轮的 Sumcheck 过程拆分成 个分段,在每个分段中,Prover 都预计算一些辅助的向量,从而避免在接下来的 Sumcheck 分段中做一些重复的计算。这个分段加预计算的步骤被称为 Condensation。通过这种方法,Prover 的计算量可以从 降到 ,其中 ,即

4.1 理解 Condensation

我们先描述一个 Sparse-dense Sumcheck 简单情况。假设查询表格 中的每一个表项 都可以用它的 index 的二进制位来计算,例如 的值可以通过下面的方式计算:

其中 的表格索引。 那么如果给定 的值,我们可以在常数时间内计算 的值。

上面这个等式想要表达的含义是:表格的每一项可以表达为该表项的索引(Index)的线性组合,并且是关于 Index 的二进制位的一次多项式。例如 RangeCheck 表格就满足这个特征。

回忆 Generalized Lasso 协议,其核心是证明下面的等式:

通过 Verifier 提供的一个随机挑战数,上面的等式可以转化为:

,那么等式转换为一个 Inner Product 的形式:

等式右边是一个 项的求和式,如果直接让 Prover 去计算每一项中的 ,那么 Prover 的计算量至少为 次 evaluation。但是我们可以利用 的内部结构来进行优化。首先 编码了一个长度为 的向量,记为 ,它相当于也编码了矩阵 的信息,只有 个非零值。因此我们只需要 就可以计算出所有的 在所有 处的取值。其次 编码了 ,它是一个 MLE-structured 的表格,其每一项都与 Index 的二进制位有关,因此每一个表项 都可以在 时间内计算得到。最后,考虑求和式 中若 ,那么我们就不需要再计算 。因此,这个求和式整体上也只需要 次 evaluation 即可。

这个 项的求和过程如果使用 Sumcheck 协议来证明,那么需要 轮。在第 轮中,由于我们都可以根据上一轮 来计算 ,因此只需要常数时间的计算量。

我们引入两个辅助的向量 ,Prover 可以在 Sumcheck 协议运行前就计算好 的值,然后 Prover 可以利用这些预计算的向量,在 Sumcheck 协议的前 轮中(记住,Sumcheck 协议总共有 轮,我们假设 )加速计算求和式。这两个向量的每个元素 定义如下:

这里我们引入了一个新的符号:,它是一个二进制串的集合

然后筛选那些二进制串的前 位与 的二进制位相等(我们采用 Big-endian 的表示方式,前面的位为高位),而后面的 位可以任意值。例如,。这个集合中每一个二进制串都是以 打头。

那么 向量的每一个元素 ,是筛选出那些高位等于 的二进制串(长度为 ,然后通过 为索引,计算 的求和。换句话说,我们通过 把前面 项求和式 划分为了 个子集,然后分别对其进行求和。由于 稀疏性, 的计算量也是

再换一个思路去理解,如果我们把 项求和式的计算过程描述成一棵深度为 的二叉树,其中树根(第 0 层)为最后的和。而其中每个叶子节点都是 ,这里 ,因此总共有 个叶子。那么向量 就是这颗二叉树中第 层的所有节点。

同样, 是叶子结点为 的求和二叉树中的第 层。 接下来,我们看看 Prover 在 Sumcheck 协议中前 轮的计算过程(总共有 轮),并且看下这两个辅助向量的作用。

在第一轮中,Prover 要构造一个一元多项式

我们把 按照定义展开,可以得到:

这里的 表示 中非零元素的索引(的二进制表示)的集合。然后把所有的求和号都展开,我们发现当 时,,因此,我们只要关注上面求和式中 对应的那些非零项(这时候 ):

上面的等式已经变成了一个 项的求和式。接下来我们根据 的结构性,展开 ,并且根据 的 Tensor 结构,即 , 我们可以得到:

我们再展开 ,可得:

这时候,我们可以代入之前计算的辅助向量 ,其中第 项为

注意到, 是按照前 位进行划分后的第 个子集的求和。我们可以把 重新写成 两个 项的求和式:

这样 Prover 只需要 的计算量就可以完成第一轮的计算,这个计算包括计算 处的求值运算。

那么第二轮开始到第 轮,每一轮 Prover 都只需要 的计算量就可以完成计算 处的求值。

但是到了 第 轮,情况会发生变化,因为这时候 Prover 要计算 个项的求和,并且 两个辅助向量已经失效。因此,对于下面新的 个轮次,Prover 需要重新计算 ,然后按照上面的方案继续。这样相当于把 轮的 Sumcheck 按照 的数量进行划分,每一个 轮次,Prover 都需要重新计算 ,然后保证 的计算始终是 个项的求和式。每次重新计算 的操作被称为 Condensation。

3.2 一般性 结构

上一小节的讨论基于一个比较强的表格结构:

对于 AND 表格与 SLT 表格等不满足上面结构要求的表格,我们需要放松表格的结构条件。首先, 可以是多个多项式之和,并且每一个多项式 的计算过程基于 index 的二进制表示,当 index 发生变化时, 的值的变化只需要常数个加法和乘法操作: