Polygon zkEVM中Goldilock域元素circom约束
Posted mutourend
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Polygon zkEVM中Goldilock域元素circom约束相关的知识,希望对你有一定的参考价值。
1. 引言
前序博客有:
Goldilocks域 p = 2 64 − 2 32 + 1 p= 2^64 - 2^32 + 1 p=264−232+1。
Polygon zkEVM中Goldilock域元素circom约束,代码见:
2. Goldilocks域元素转换为二进制
将Goldilocks域元素转换为64位二进制表示:
//本质为`getPermutations`,获取nQueries个查询位置index
//Fibonacci例子中,查询位置index ys[0]~ys[7]的取值范围为0~(2^11-1)【即以11个bit来表示】
//以transcript中获取的challenge为输入,获得相应的二进制表示
component tcN2b_0 = Num2Bits_strict();
tcN2b_0.in <== tcHahs_8.out[0];
//以transcript中获取的challenge为输入,获得相应的二进制表示
component tcN2b_1 = Num2Bits_strict();
tcN2b_1.in <== tcHahs_8.out[1];
其中:【CompConstant(-1)
用于约束输入为有效Goldilocks域元素:
[
0
,
p
−
1
]
[0,p-1]
[0,p−1]。】
template Num2Bits_strict()
signal input in; //输入为Goldilocks域元素
signal output out[64]; //输出为64位二进制值
component aliasCheck = AliasCheck();
component n2b = Num2Bits(64); //将Goldilocks域元素转换为64位二进制值
in ==> n2b.in;
for (var i=0; i<64; i++)
n2b.out[i] ==> out[i];
n2b.out[i] ==> aliasCheck.in[i]; //将每个二进制bit给AliasCheck
template AliasCheck()
signal input in[64]; //输入为64位二进制值
//约束64位二进制值 <= -1
//即 约束Goldilocks域元素转换后的64位二进制值 仍为 0~(p-1)
component compConstant = CompConstant(-1);
for (var i=0; i<64; i++) in[i] ==> compConstant.in[i]; //将每个二进制bit给CompConstant
compConstant.out === 0;//约束CompConstant输出恒为0
template Num2Bits(n) //将Goldilocks域元素转换为64位二进制值
signal input in;
signal output out[n];
var lc1=0;
var e2=1;
for (var i = 0; i<n; i++)
out[i] <-- (in >> i) & 1;
out[i] * (out[i] -1 ) === 0;
lc1 += out[i] * e2;
e2 = e2+e2;
lc1 === in;
/*
cm cl sm sl res
0 0 0 0 0
0 1 1
1 0 1
1 1 1 sm + sl - sm*sl
0 1 0 0 -1
0 1 0
1 0 1
1 1 1 -1 + sl + 2*sm - sm*sl
1 0 0 0 -1
0 1 -1
1 0 0
1 1 1 sm*sl -1 +sm
1 1 0 0 -1
0 1 -1
1 0 -1
1 1 0 sm*sl -1
*/
// Returns 1 if in (in binary) > ct
template CompConstant(ct) //ct值为-1
signal input in[64]; //输入为64位二进制值
signal output out;
signal parts[32]; //中间值
signal sout; //中间值
//变量
var clsb;
var cmsb;
var sl;
var sm;
signal sum[32]; //中间值
var e = 1;
var i;
for (i=0;i<32; i++)
clsb = (ct >> (i*2)) & 1;
cmsb = (ct >> (i*2+1)) & 1;
sl = in[i*2];
sm = in[i*2+1];
if ((cmsb==0)&&(clsb==0))
parts[i] <== sm*e + sl*e -sm*sl*e;
else if ((cmsb==0)&&(clsb==1))
parts[i] <== -e + e*sl + e*2*sm - e*sm*sl;
else if ((cmsb==1)&&(clsb==0))
parts[i] <== e*sm*sl -e +e*sm;
else
parts[i] <== e*sm*sl -e;
if (i==0)
sum[i] <== (1<<32)-1 + parts[i];
else
sum[i] <== sum[i-1] + parts[i];
e = e*2;
component num2bits = Num2Bits(33);
num2bits.in <== sum[31];
out <== num2bits.out[32];
3. Goldilocks extension 3 域元素运算
3.1 Goldilocks extension 3 域元素乘法运算
Goldilocks域元素乘法运算为:
mul(a, b)
if (typeof(a) == "bigint")
if (typeof(b) == "bigint") //2个基域元素相乘
return (a*b) % this.p;
else //基域元素 * extension 3域元素
return [(a*b[0]) % this.p, (a*b[1]) % this.p, (a*b[2]) % this.p];
else if (typeof(b) == "bigint") //extension 3域元素 * extension 3域元素
return [(a[0]*b) % this.p, (a[1]*b) % this.p, (a[2]*b) % this.p];
else //2个extension 3域元素相乘
const A = (a[0] + a[1]) * (b[0] + b[1]);
const B = (a[0] + a[2]) * (b[0] + b[2]);
const C = (a[1] + a[2]) * (b[1] + b[2]);
const D = a[0]*b[0];
const E = a[1]*b[1];
const F = a[2]*b[2];
const G = D - E;
return [ (C + G - F)%this.p, (A + C - E -E - D )%this.p,(B-G)%this.p ];
2个Goldilocks extension 3 域元素相乘的circom约束为:【事实上是只计算,未约束】
template custom CMul() // 计算out = ina * inb
signal input ina[3];
signal input inb[3];
signal output out[3];
var A = (ina[0] + ina[1]) * (inb[0] + inb[1]);
var B = (ina[0] + ina[2]) * (inb[0] + inb[2]);
var C = (ina[1] + ina[2]) * (inb[1] + inb[2]);
var D = ina[0]*inb[0];
var E = ina[1]*inb[1];
var F = ina[2]*inb[2];
var G = D-E;
out[0] <-- C+G-F; //只赋值,未约束
out[1] <-- A+C-E-E-D; //只赋值,未约束
out[2] <-- B-G; //只赋值,未约束
3.2 Goldilocks extension 3 域元素倒数运算
Goldilocks域元素倒数运算为:
/*
Formula deducted here: https://www.polymathlove.com/polymonials/midpoint-of-a-line/symbolic-equation-solving.html#c=solve_algstepsequationsolvesystem&v247=d%252Ce%252Cf&v248=3&v249=f*a%2Bb*e%2Bd*c%2B%2520c*f%2520%253D%25200&v250=d*b%2Be*a%2Bc*f%2Bb*f%2Be*c%253D0&v251=a*d%2Bb*f%2Be*c%253D1
*/
inv(a)
if (typeof(a) == "bigint") //Goldilocks基域求倒数
return this._inv1(a);
else //Goldilocks extension 3 域求倒数
const aa = a[0] * a[0];
const ac = a[0] * a[2];
const ba = a[1] * a[0];
const bb = a[1] * a[1];
const bc = a[1] * a[2];
const cc = a[2] * a[2];
const aaa = aa * a[0];
const aac = aa * a[2];
const abc = ba * a[2];
const abb = ba * a[1];
const acc = ac * a[2];
const bbb = bb * a[1];
const bcc = bc * a[2];
const ccc = cc * a[2];
let t = (-aaa -aac-aac +abc+abc+abc + abb - acc - bbb + bcc - ccc)%this.p;
if (t<0n) t = t + this.p;
const tinv = this._inv1(t);
let i1 = ((-aa -ac-ac +bc + bb - cc)*tinv) % this.p;
let i2 = ((ba -cc)*tinv) % this.p;
let i3 = ((-bb +ac + cc)*tinv) % this.p;
if (i1<0) i1 = this.p+i1;
if (i2<0) i2 = this.p+i2;
if (i3<0) i3 = this.p+i3;
return [i1, i2, i3];
_inv1(a)
if (!a) throw new Error("Division by zero");
let t = this.zero;
let r = this.p;
let newt = this.one;
let newr = a % this.p;
while (newr)
let q = r/newr;
[t, newt] = [newt, t-q*newt];
[r, newr] = [newr, r-q*newr];
if (t<this.zero) t += this.p;
return t;
相应的约束为:
template CInv() //计算out=1/in
signal input in[3];
signal output out[3];
var aa = in[0] * in[0];
var ac = in[0] * in[2];
var ba = in[1] * in[0];
var bb = in[1] * in[1];
var bc = in[1] * in[2];
var cc = in[2] * in[2];
var aaa = aa * in[0];
var aac = aa * in[2];
var abc = ba * in[2];
var abb = ba * in[1];
var acc = ac * in[2];
var bbb = bb * in[1];
var bcc = bc * in[2];
var ccc = cc * in[2];
var t = -aaa -aac-aac +abc+abc+abc + abb - acc - bbb + bcc - ccc;
var tinv = 1/t;
out[0] <-- (-aa -ac-ac +bc + bb - cc)*tinv; //只赋值,未约束
out[1] <-- (ba -cc)*tinv; //只赋值,未约束
out[2] <-- (-bb +ac + cc)*tinv; //只赋值,未约束
component check = CMul(); //约束in*out=1
check.ina[0] <== in[0];
check.ina[1] <== in[1];
check.ina[2] <== in[2];
check.inb[0] <== out[0];
check.inb[1] <== out[1];
check.inb[2] <== out[2];
check.out[0] === 1;
check.out[1] === 0;
check.out[2] === 0;
参考资料
[1] Circom 2 文档——Basic Operators
附录:Polygon Hermez 2.0 zkEVM系列博客
- ZK-Rollups工作原理
- Polygon zkEVM——Hermez 2.0简介
- Polygon zkEVM网络节点
- Polygon zkEVM 基本概念
- Polygon zkEVM Prover
- Polygon zkEVM工具——PIL和CIRCOM
- Polygon zkEVM节点代码解析
- Polygon zkEVM的pil-stark Fibonacci状态机初体验
- Polygon zkEVM的pil-stark Fibonacci状态机代码解析
- Polygon zkEVM PIL编译器——pilcom 代码解析
- Polygon zkEVM Arithmetic状态机
- Polygon zkEVM中的常量多项式
- Polygon zkEVM Binary状态机
- Polygon zkEVM Memory状态机
- Polygon zkEVM Memory Align状态机
- Polygon zkEVM zkASM编译器——zkasmcom
- Polygon zkEVM哈希状态机——Keccak-256和Poseidon
- Polygon zkEVM zkASM语法
- Polygon zkEVM可验证计算简单状态机示例
- Polygon zkEVM zkASM 与 以太坊虚拟机opcode 对应集合
- Polygon zkEVM zkROM代码解析(1)
- Polygon zkEVM zkASM中的函数集合
- Polygon zkEVM zkROM代码解析(2)
- Polygon zkEVM zkROM代码解析(3)
- Polygon zkEVM中的Merkle tree
以上是关于Polygon zkEVM中Goldilock域元素circom约束的主要内容,如果未能解决你的问题,请参考以下文章