译自 halo2 book:https://zcash.github.io/halo2/design/implementation/fields.html
我们在 halo2 中使用的 Pasta 曲线被设计为高度 2-adic 的,这意味着每个域(field)中都存在一个较大的 2S 乘法子群(multiplicative subgroup)。也就是说,我们可以写成 p−1≡2S⋅T,其中 T 为奇数。对于 Pallas 和 Vesta,S=32;这有助于简化域的实现。
我们使用来自 Sarkar2020 的一种技术来在 halo2 中计算平方根(square roots)。该算法背后的直觉是:我们可以把任务拆分为在每个乘法子群中分别计算平方根。
假设我们想求 u 模某个 Pasta 素数 p 的平方根,其中 u 是 Zp× 中的一个非零平方数(square)。我们定义一个 2S 阶单位根(root of unity) g=zT,其中 z 是 Zp× 中的一个非平方数(non-square),并预计算以下各表:
gtab=g0(g28)0(g216)0(g224)0g1(g28)1(g216)1(g224)1............g28−1(g28)28−1(g216)28−1(g224)28−1
invtab=[(g−224)0(g−224)1...(g−224)28−1]
令 v=u(T−1)/2。我们便可定义 x=uv⋅v=uT,它是 2S 乘法子群中的一个元素。
令 x3=x,x2=x328,x1=x228,x0=x128.
使用 invtab,我们查找 t0 使得
x0=(g−224)t0⟹x0⋅gt0⋅224=1.
定义 α1=x1⋅(g216)t0.
查找 t1 使得
α1=(g−224)t1⟹x1⋅(g216)t0=(g−224)t1⟹x1⋅g(t0+28⋅t1)⋅216=1.
定义 α2=x2⋅(g28)t0+28⋅t1.
查找 t2 使得
α2=(g−224)t2⟹x2⋅(g28)t0+28⋅t1=(g−224)t2⟹x2⋅g(t0+28⋅t1+216⋅t2)⋅28=1.
定义 α3=x3⋅gt0+28⋅t1+216⋅t2.
查找 t3 使得
α3=(g−224)t3⟹x3⋅gt0+28⋅t1+216⋅t2=(g−224)t3⟹x3⋅gt0+28⋅t1+216⋅t2+224⋅t3=1.
令 t=t0+28⋅t1+216⋅t2+224⋅t3。
现在我们可以写出
x3⋅gt=1⟹⟹⟹⟹x3uv2uvuv⋅gt/2====g−tg−tv−1⋅g−tv−1⋅g−t/2.
对右端(RHS)取平方,我们观察到 (v−1g−t/2)2=v−2g−t=u. 因此,u 的平方根就是 uv⋅gt/2;其中第一部分我们在前面已经计算过,第二部分可以利用 gtab 中的查找,通过三次乘法计算得到。