Plonky2 介绍
Plonky2由Polygon Zero Team开发,主要可以实现快速递归,只需要300ms即可生成一个递归证明。
Plonky2 数值化基于TurboPLONK, 但承诺方案采用FRI, 采用64位的Goldilocks域。
Plonky2可以将任意多的证明收缩为43KB。
域的选择
Plonky2 采用素域 , 采用64位的字,可以加速些底层运算。
扩域采用.
PLONK 算术化
基于TurboPLONK, Plonky2 广泛使用定制门。
Filtering constraints
对于 个多项式, 采用 个过虑多项式将大幅增加协议的代价,可以其它批量处理。
其中的次数为, 为了降低次数,可以将电路分成多个子集。
定义 为:
若第 j 个门电路用在 第 i 行;
则第 j 个定制电路的过滤多项式为:
它在第j 个定制电路的值为非零。
Advice wires
若是某个列不需要参与Plonk 置换证明,例如对于除法,它逆单独作为一列,这种称为advice wires
.
它不参与置换,可以减少置换多项式的次数,减少证明大小和验证者的代价。
Cumulative products
Plonk的置换多项式为度数为 的约束:
为了获取低度约束条件,可以将上述乘积为 大小为8的块,引入多项式 , 定义, 可以得到:
Boosting soundness
由于域的大小与安全性成反比,为了提升安全性,需要将置换和约束组合 证明重复 次。
公开输入
公开输入采用PublicInputGate
, 主要有以下约束:
零知识性
通过添加随机的列盲化trace
多项式和
对于FRI, 其定义域放在的陪集中,并采用基于hash的向量承诺。
Hashing
Plonky2采用 , 宽度为12个域元素,S盒为,采用 8 满轮和22个部分轮变换,实现128位的安全性。
Plonky2 采用PoseidonGate
定制电路,这可能导致宽的列,Plonky2 使用135列,这是达到证明大小和FRI验证复杂的平衡。
最终协议
定义 为重复的参数,表示多项式向量的承诺,即对于多项式的每个叶子节点,对于, 包含值。
预处理
- P 和 V 构造电路并计算 , 表示电路上的常量多项式,和 , 用以编码置换;
- P, V构建包含 和 的的Merkle树;
- P存储Merkle 树,作为
Proving key
; - V存储 作为
Verification key
;
主协议
- P 生成 witness , 并给V 发送 ;
- V 抽样获取 作为置换证明的随机数;
- P 发送 , 作为置换多项式 和 部分乘积多项式 ;
- V 抽样获取 , 作为组合约束条件的随机数;
- P 发送 , 作为商多项式 的承诺;
- V 抽象 , 用来测试多项式之间的恒等关系;
- P 发送 , 其中 包含多个多项式 ;
- P 计算 , 和 V 参与到FRI 协议中:
- V 利用 计算 , 并验证
FRI 协议
- V 抽样获取 , 主要将 转换为指定的码字;
- P 发送 , 为 DEEP组合多项式:
-
P, V执行 FRI 承诺阶段,对于每个约减参数 ,
(a) V抽样 ,
(b) P 重写 为:
P 生成承诺, 其中
-
V抽样
-
P 执行
grinding
, 并发送 PoW的 见证参数 ; -
V 断言 包含
proof of work bits
前面的0; -
V抽样获取
num_query_rounds
的随机索引 ; -
对于每个索引 :
(a) P 发送 的估值 和 每个
(b) V 验证在 的一系列一致性检查,首先是在 和 ,然后是在每个 对之间。
示例
使用plonky2写个关于x^2-4x+7
的电路证明示例为:
use anyhow::Result;
use plonky2::field::types::Field;
use plonky2::iop::witness::{PartialWitness, Witness};
use plonky2::plonk::circuit_builder::CircuitBuilder;
use plonky2::plonk::circuit_data::CircuitConfig;
use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
/// An example of using Plonky2 to prove a statement of the form
/// "I know x² - 4x + 7".
fn main() -> Result<()> {
const D: usize = 2;
type C = PoseidonGoldilocksConfig;
type F = <C as GenericConfig<D>>::F;
let config = CircuitConfig::standard_recursion_config();
let mut builder = CircuitBuilder::<F, D>::new(config);
// The arithmetic circuit.
let x = builder.add_virtual_target();
let a = builder.mul(x, x);
let b = builder.mul_const(F::from_canonical_u32(4), x);
let c = builder.mul_const(F::NEG_ONE, b);
let d = builder.add(a, c);
let e = builder.add_const(d, F::from_canonical_u32(7));
// Public inputs are the initial value (provided below) and the result (which is generated).
builder.register_public_input(x);
builder.register_public_input(e);
let mut pw = PartialWitness::new();
pw.set_target(x, F::from_canonical_u32(1));
let data = builder.build::<C>();
let proof = data.prove(pw)?;
println!(
"x² - 4 *x + 7 where x = {} is {}",
proof.public_inputs[0],
proof.public_inputs[1]
);
data.verify(proof)
}
参考
https://github.com/mir-protocol/plonky2
https://github.com/mir-protocol/plonky2/blob/main/plonky2/plonky2.pdf
https://polymerlabs.medium.com/a-tutorial-on-writing-zk-proofs-with-plonky2-part-i-be5812f6b798