ceremonyclient/ec/bls48581/PAIR8.go
2023-04-15 00:05:26 -04:00

979 lines
15 KiB
Go

/*
* Copyright (c) 2012-2020 MIRACL UK Ltd.
*
* This file is part of MIRACL Core
* (see https://github.com/miracl/core).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* BLS Curve Pairing functions */
package bls48581
//import "fmt"
// Point doubling for pairings
func dbl(A *ECP8, AA *FP8, BB *FP8, CC *FP8) {
CC.copy(A.getx()) //X
YY := NewFP8copy(A.gety()) //Y
BB.copy(A.getz()) //Z
AA.copy(YY) //Y
AA.mul(BB) //YZ
CC.sqr() //X^2
YY.sqr() //Y^2
BB.sqr() //Z^2
AA.add(AA)
AA.neg()
AA.norm() //-2AA
AA.times_i()
sb := 3 * CURVE_B_I
BB.imul(sb)
CC.imul(3)
if SEXTIC_TWIST == D_TYPE {
YY.times_i()
CC.times_i()
}
if SEXTIC_TWIST == M_TYPE {
BB.times_i()
}
BB.sub(YY)
BB.norm()
A.dbl()
}
// Point addition for pairings
func add(A *ECP8, B *ECP8, AA *FP8, BB *FP8, CC *FP8) {
AA.copy(A.getx()) // X1
CC.copy(A.gety()) // Y1
T1 := NewFP8copy(A.getz()) // Z1
BB.copy(A.getz()) // Z1
T1.mul(B.gety()) // T1=Z1.Y2
BB.mul(B.getx()) // T2=Z1.X2
AA.sub(BB)
AA.norm() // X1=X1-Z1.X2
CC.sub(T1)
CC.norm() // Y1=Y1-Z1.Y2
T1.copy(AA) // T1=X1-Z1.X2
if SEXTIC_TWIST == M_TYPE {
AA.times_i()
AA.norm()
}
T1.mul(B.gety()) // T1=(X1-Z1.X2).Y2
BB.copy(CC) // T2=Y1-Z1.Y2
BB.mul(B.getx()) // T2=(Y1-Z1.Y2).X2
BB.sub(T1)
BB.norm() // T2=(Y1-Z1.Y2).X2 - (X1-Z1.X2).Y2
CC.neg()
CC.norm() // Y1=-(Y1-Z1.Y2).Xs
A.Add(B)
}
func line(A *ECP8, B *ECP8, Qx *FP, Qy *FP) *FP48 {
AA := NewFP8()
BB := NewFP8()
CC := NewFP8()
var a *FP16
var b *FP16
var c *FP16
if A == B {
dbl(A, AA, BB, CC)
} else {
add(A, B, AA, BB, CC)
}
CC.tmul(Qx)
AA.tmul(Qy)
a = NewFP16fp8s(AA, BB)
if SEXTIC_TWIST == D_TYPE {
b = NewFP16fp8(CC) // L(0,1) | L(0,0) | L(1,0)
c = NewFP16()
}
if SEXTIC_TWIST == M_TYPE {
b = NewFP16()
c = NewFP16fp8(CC)
c.times_i()
}
r := NewFP48fp16s(a, b, c)
r.stype = FP_SPARSER
return r
}
/* prepare ate parameter, n=6u+2 (BN) or n=u (BLS), n3=3*n */
func lbits(n3 *BIG, n *BIG) int {
n.copy(NewBIGints(CURVE_Bnx))
n3.copy(n)
n3.pmul(3)
n3.norm()
return n3.nbits()
}
/* prepare for multi-pairing */
func Initmp() []*FP48 {
var r []*FP48
for i := ATE_BITS - 1; i >= 0; i-- {
r = append(r, NewFP48int(1))
}
return r
}
/* basic Miller loop */
func Miller(r []*FP48) *FP48 {
res := NewFP48int(1)
for i := ATE_BITS - 1; i >= 1; i-- {
res.sqr()
res.ssmul(r[i])
r[i].zero()
}
if SIGN_OF_X == NEGATIVEX {
res.conj()
}
res.ssmul(r[0])
r[0].zero()
return res
}
// Store precomputed line details in an FP8
func pack(AA *FP8, BB *FP8, CC *FP8) *FP16 {
i := NewFP8copy(CC)
i.inverse(nil)
a := NewFP8copy(AA)
a.mul(i)
b := NewFP8copy(BB)
b.mul(i)
return NewFP16fp8s(a, b)
}
// Unpack G2 line function details and include G1
func unpack(T *FP16, Qx *FP, Qy *FP) *FP48 {
var a *FP16
var b *FP16
var c *FP16
a = NewFP16copy(T)
a.geta().tmul(Qy)
t := NewFP8fp(Qx)
if SEXTIC_TWIST == D_TYPE {
b = NewFP16fp8(t)
c = NewFP16()
}
if SEXTIC_TWIST == M_TYPE {
b = NewFP16()
c = NewFP16fp8(t)
c.times_i()
}
v := NewFP48fp16s(a, b, c)
v.stype = FP_SPARSEST
return v
}
func precomp(GV *ECP8) []*FP16 {
n := NewBIG()
n3 := NewBIG()
AA := NewFP8()
BB := NewFP8()
CC := NewFP8()
var bt int
P := NewECP8()
P.Copy(GV)
A := NewECP8()
A.Copy(P)
MP := NewECP8()
MP.Copy(P)
MP.neg()
nb := lbits(n3, n)
var T []*FP16
for i := nb - 2; i >= 1; i-- {
dbl(A, AA, BB, CC)
T = append(T, pack(AA, BB, CC))
bt = n3.bit(i) - n.bit(i)
if bt == 1 {
add(A, P, AA, BB, CC)
T = append(T, pack(AA, BB, CC))
}
if bt == -1 {
add(A, MP, AA, BB, CC)
T = append(T, pack(AA, BB, CC))
}
}
return T
}
func Another_pc(r []*FP48, T []*FP16, QV *ECP) {
n := NewBIG()
n3 := NewBIG()
var lv, lv2 *FP48
var bt, j int
if QV.Is_infinity() {
return
}
Q := NewECP()
Q.Copy(QV)
Q.Affine()
Qx := NewFPcopy(Q.getx())
Qy := NewFPcopy(Q.gety())
nb := lbits(n3, n)
j = 0
for i := nb - 2; i >= 1; i-- {
lv = unpack(T[j], Qx, Qy)
j += 1
bt = n3.bit(i) - n.bit(i)
if bt == 1 {
lv2 = unpack(T[j], Qx, Qy)
j += 1
lv.smul(lv2)
}
if bt == -1 {
lv2 = unpack(T[j], Qx, Qy)
j += 1
lv.smul(lv2)
}
r[i].ssmul(lv)
}
}
/* Accumulate another set of line functions for n-pairing */
func Another(r []*FP48, P1 *ECP8, Q1 *ECP) {
n := NewBIG()
n3 := NewBIG()
var lv, lv2 *FP48
if Q1.Is_infinity() {
return
}
// P is needed in affine form for line function, Q for (Qx,Qy) extraction
P := NewECP8()
P.Copy(P1)
Q := NewECP()
Q.Copy(Q1)
P.Affine()
Q.Affine()
Qx := NewFPcopy(Q.getx())
Qy := NewFPcopy(Q.gety())
A := NewECP8()
A.Copy(P)
MP := NewECP8()
MP.Copy(P)
MP.neg()
nb := lbits(n3, n)
for i := nb - 2; i >= 1; i-- {
lv = line(A, A, Qx, Qy)
bt := n3.bit(i) - n.bit(i)
if bt == 1 {
lv2 = line(A, P, Qx, Qy)
lv.smul(lv2)
}
if bt == -1 {
lv2 = line(A, MP, Qx, Qy)
lv.smul(lv2)
}
r[i].ssmul(lv)
}
}
/* Optimal R-ate pairing */
func Ate(P1 *ECP8, Q1 *ECP) *FP48 {
n := NewBIG()
n3 := NewBIG()
var lv, lv2 *FP48
if Q1.Is_infinity() {
return NewFP48int(1)
}
P := NewECP8()
P.Copy(P1)
P.Affine()
Q := NewECP()
Q.Copy(Q1)
Q.Affine()
Qx := NewFPcopy(Q.getx())
Qy := NewFPcopy(Q.gety())
A := NewECP8()
r := NewFP48int(1)
A.Copy(P)
NP := NewECP8()
NP.Copy(P)
NP.neg()
nb := lbits(n3, n)
for i := nb - 2; i >= 1; i-- {
r.sqr()
lv = line(A, A, Qx, Qy)
bt := n3.bit(i) - n.bit(i)
if bt == 1 {
lv2 = line(A, P, Qx, Qy)
lv.smul(lv2)
}
if bt == -1 {
lv2 = line(A, NP, Qx, Qy)
lv.smul(lv2)
}
r.ssmul(lv)
}
if SIGN_OF_X == NEGATIVEX {
r.conj()
}
return r
}
/* Optimal R-ate double pairing e(P,Q).e(R,S) */
func Ate2(P1 *ECP8, Q1 *ECP, R1 *ECP8, S1 *ECP) *FP48 {
n := NewBIG()
n3 := NewBIG()
var lv, lv2 *FP48
if Q1.Is_infinity() {
return Ate(R1, S1)
}
if S1.Is_infinity() {
return Ate(P1, Q1)
}
P := NewECP8()
P.Copy(P1)
P.Affine()
Q := NewECP()
Q.Copy(Q1)
Q.Affine()
R := NewECP8()
R.Copy(R1)
R.Affine()
S := NewECP()
S.Copy(S1)
S.Affine()
Qx := NewFPcopy(Q.getx())
Qy := NewFPcopy(Q.gety())
Sx := NewFPcopy(S.getx())
Sy := NewFPcopy(S.gety())
A := NewECP8()
B := NewECP8()
r := NewFP48int(1)
A.Copy(P)
B.Copy(R)
NP := NewECP8()
NP.Copy(P)
NP.neg()
NR := NewECP8()
NR.Copy(R)
NR.neg()
nb := lbits(n3, n)
for i := nb - 2; i >= 1; i-- {
r.sqr()
lv = line(A, A, Qx, Qy)
lv2 = line(B, B, Sx, Sy)
lv.smul(lv2)
r.ssmul(lv)
bt := n3.bit(i) - n.bit(i)
if bt == 1 {
lv = line(A, P, Qx, Qy)
lv2 = line(B, R, Sx, Sy)
lv.smul(lv2)
r.ssmul(lv)
}
if bt == -1 {
lv = line(A, NP, Qx, Qy)
lv2 = line(B, NR, Sx, Sy)
lv.smul(lv2)
r.ssmul(lv)
}
}
if SIGN_OF_X == NEGATIVEX {
r.conj()
}
return r
}
/* final exponentiation - keep separate for multi-pairings and to avoid thrashing stack */
func Fexp(m *FP48) *FP48 {
f := NewFP2bigs(NewBIGints(Fra), NewBIGints(Frb))
x := NewBIGints(CURVE_Bnx)
r := NewFP48copy(m)
// var t1, t2 *FP48
/* Easy part of final exp */
lv := NewFP48copy(r)
lv.Inverse()
r.conj()
r.Mul(lv)
lv.Copy(r)
r.frob(f, 8)
r.Mul(lv)
/* Hard part of final exp */
// See https://eprint.iacr.org/2020/875.pdf
y1 := NewFP48copy(r)
y1.usqr()
y1.Mul(r) // y1=r^3
y0 := NewFP48copy(r.Pow(x))
if SIGN_OF_X == NEGATIVEX {
y0.conj()
}
t0 := NewFP48copy(r)
t0.conj()
r.Copy(y0)
r.Mul(t0)
y0.Copy(r.Pow(x))
if SIGN_OF_X == NEGATIVEX {
y0.conj()
}
t0.Copy(r)
t0.conj()
r.Copy(y0)
r.Mul(t0)
// ^(x+p)
y0.Copy(r.Pow(x))
if SIGN_OF_X == NEGATIVEX {
y0.conj()
}
t0.Copy(r)
t0.frob(f, 1)
r.Copy(y0)
r.Mul(t0)
// ^(x^2+p^2)
y0.Copy(r.Pow(x))
y0.Copy(y0.Pow(x))
t0.Copy(r)
t0.frob(f, 2)
r.Copy(y0)
r.Mul(t0)
// ^(x^4+p^4)
y0.Copy(r.Pow(x))
y0.Copy(y0.Pow(x))
y0.Copy(y0.Pow(x))
y0.Copy(y0.Pow(x))
t0.Copy(r)
t0.frob(f, 4)
r.Copy(y0)
r.Mul(t0)
// ^(x^8+p^8-1)
y0.Copy(r.Pow(x))
y0.Copy(y0.Pow(x))
y0.Copy(y0.Pow(x))
y0.Copy(y0.Pow(x))
y0.Copy(y0.Pow(x))
y0.Copy(y0.Pow(x))
y0.Copy(y0.Pow(x))
y0.Copy(y0.Pow(x))
t0.Copy(r)
t0.frob(f, 8)
y0.Mul(t0)
t0.Copy(r)
t0.conj()
r.Copy(y0)
r.Mul(t0)
r.Mul(y1)
r.reduce()
/*
// Ghamman & Fouotsa Method
t7 := NewFP48copy(r)
t7.usqr()
if x.parity() == 1 {
t2 = r.Pow(x)
t1 = NewFP48copy(t2)
t1.usqr()
t2 = t2.Pow(x)
} else {
t1 = t7.Pow(x)
x.fshr(1)
t2 = t1.Pow(x)
x.fshl(1)
}
if SIGN_OF_X == NEGATIVEX {
t1.conj()
}
t3 := NewFP48copy(t1)
t3.conj()
t2.Mul(t3)
t2.Mul(r)
r.Mul(t7)
t1 = t2.Pow(x)
if SIGN_OF_X == NEGATIVEX {
t1.conj()
}
t3.Copy(t1)
t3.frob(f, 14)
r.Mul(t3)
t1 = t1.Pow(x)
if SIGN_OF_X == NEGATIVEX {
t1.conj()
}
t3.Copy(t1)
t3.frob(f, 13)
r.Mul(t3)
t1 = t1.Pow(x)
if SIGN_OF_X == NEGATIVEX {
t1.conj()
}
t3.Copy(t1)
t3.frob(f, 12)
r.Mul(t3)
t1 = t1.Pow(x)
if SIGN_OF_X == NEGATIVEX {
t1.conj()
}
t3.Copy(t1)
t3.frob(f, 11)
r.Mul(t3)
t1 = t1.Pow(x)
if SIGN_OF_X == NEGATIVEX {
t1.conj()
}
t3.Copy(t1)
t3.frob(f, 10)
r.Mul(t3)
t1 = t1.Pow(x)
if SIGN_OF_X == NEGATIVEX {
t1.conj()
}
t3.Copy(t1)
t3.frob(f, 9)
r.Mul(t3)
t1 = t1.Pow(x)
if SIGN_OF_X == NEGATIVEX {
t1.conj()
}
t3.Copy(t1)
t3.frob(f, 8)
r.Mul(t3)
t1 = t1.Pow(x)
if SIGN_OF_X == NEGATIVEX {
t1.conj()
}
t3.Copy(t2)
t3.conj()
t1.Mul(t3)
t3.Copy(t1)
t3.frob(f, 7)
r.Mul(t3)
t1 = t1.Pow(x)
if SIGN_OF_X == NEGATIVEX {
t1.conj()
}
t3.Copy(t1)
t3.frob(f, 6)
r.Mul(t3)
t1 = t1.Pow(x)
if SIGN_OF_X == NEGATIVEX {
t1.conj()
}
t3.Copy(t1)
t3.frob(f, 5)
r.Mul(t3)
t1 = t1.Pow(x)
if SIGN_OF_X == NEGATIVEX {
t1.conj()
}
t3.Copy(t1)
t3.frob(f, 4)
r.Mul(t3)
t1 = t1.Pow(x)
if SIGN_OF_X == NEGATIVEX {
t1.conj()
}
t3.Copy(t1)
t3.frob(f, 3)
r.Mul(t3)
t1 = t1.Pow(x)
if SIGN_OF_X == NEGATIVEX {
t1.conj()
}
t3.Copy(t1)
t3.frob(f, 2)
r.Mul(t3)
t1 = t1.Pow(x)
if SIGN_OF_X == NEGATIVEX {
t1.conj()
}
t3.Copy(t1)
t3.frob(f, 1)
r.Mul(t3)
t1 = t1.Pow(x)
if SIGN_OF_X == NEGATIVEX {
t1.conj()
}
r.Mul(t1)
t2.frob(f, 15)
r.Mul(t2)
r.reduce()
*/
return r
}
/* GLV method */
func glv(ee *BIG) []*BIG {
var u []*BIG
q := NewBIGints(CURVE_Order)
x := NewBIGints(CURVE_Bnx)
x2 := smul(x, x)
x = smul(x2, x2)
x2 = smul(x, x)
bd := uint(q.nbits() - x2.nbits())
u = append(u, NewBIGcopy(ee))
u[0].ctmod(x2, bd)
u = append(u, NewBIGcopy(ee))
u[1].ctdiv(x2, bd)
u[1].rsub(q)
return u
}
/* Galbraith & Scott Method */
func gs(ee *BIG) []*BIG {
var u []*BIG
q := NewBIGints(CURVE_Order)
x := NewBIGints(CURVE_Bnx)
bd := uint(q.nbits() - x.nbits())
w := NewBIGcopy(ee)
for i := 0; i < 15; i++ {
u = append(u, NewBIGcopy(w))
u[i].ctmod(x, bd)
w.ctdiv(x, bd)
}
u = append(u, NewBIGcopy(w))
if SIGN_OF_X == NEGATIVEX {
u[1].copy(Modneg(u[1], q))
u[3].copy(Modneg(u[3], q))
u[5].copy(Modneg(u[5], q))
u[7].copy(Modneg(u[7], q))
u[9].copy(Modneg(u[9], q))
u[11].copy(Modneg(u[11], q))
u[13].copy(Modneg(u[13], q))
u[15].copy(Modneg(u[15], q))
}
return u
}
/* Multiply P by e in group G1 */
func G1mul(P *ECP, e *BIG) *ECP {
var R *ECP
q := NewBIGints(CURVE_Order)
ee := NewBIGcopy(e)
ee.Mod(q)
if USE_GLV {
R = NewECP()
R.Copy(P)
Q := NewECP()
Q.Copy(P)
Q.Affine()
cru := NewFPbig(NewBIGints(CRu))
t := NewBIGint(0)
u := glv(ee)
Q.getx().mul(cru)
np := u[0].nbits()
t.copy(Modneg(u[0], q))
nn := t.nbits()
if nn < np {
u[0].copy(t)
R.Neg()
}
np = u[1].nbits()
t.copy(Modneg(u[1], q))
nn = t.nbits()
if nn < np {
u[1].copy(t)
Q.Neg()
}
u[0].norm()
u[1].norm()
R = R.Mul2(u[0], Q, u[1])
} else {
R = P.clmul(e, q)
}
return R
}
/* Multiply P by e in group G2 */
func G2mul(P *ECP8, e *BIG) *ECP8 {
var R *ECP8
q := NewBIGints(CURVE_Order)
ee := NewBIGcopy(e)
ee.Mod(q)
if USE_GS_G2 {
var Q []*ECP8
F := ECP8_frob_constants()
u := gs(ee)
t := NewBIGint(0)
Q = append(Q, NewECP8())
Q[0].Copy(P)
for i := 1; i < 16; i++ {
Q = append(Q, NewECP8())
Q[i].Copy(Q[i-1])
Q[i].frob(F, 1)
}
for i := 0; i < 16; i++ {
np := u[i].nbits()
t.copy(Modneg(u[i], q))
nn := t.nbits()
if nn < np {
u[i].copy(t)
Q[i].neg()
}
u[i].norm()
}
R = mul16(Q, u)
} else {
R = P.mul(e)
}
return R
}
/* f=f^e */
/* Note that this method requires a lot of RAM! */
func GTpow(d *FP48, e *BIG) *FP48 {
var r *FP48
q := NewBIGints(CURVE_Order)
ee := NewBIGcopy(e)
ee.Mod(q)
if USE_GS_GT {
var g []*FP48
f := NewFP2bigs(NewBIGints(Fra), NewBIGints(Frb))
t := NewBIGint(0)
u := gs(ee)
g = append(g, NewFP48copy(d))
for i := 1; i < 16; i++ {
g = append(g, NewFP48())
g[i].Copy(g[i-1])
g[i].frob(f, 1)
}
for i := 0; i < 16; i++ {
np := u[i].nbits()
t.copy(Modneg(u[i], q))
nn := t.nbits()
if nn < np {
u[i].copy(t)
g[i].conj()
}
u[i].norm()
}
r = pow16(g, u)
} else {
r = d.Pow(ee)
}
return r
}
/* test G1 group membership */
func G1member(P *ECP) bool {
if P.Is_infinity() {
return false
}
x := NewBIGints(CURVE_Bnx)
cru := NewFPbig(NewBIGints(CRu))
W := NewECP()
W.Copy(P)
W.getx().mul(cru)
T := P.mul(x)
if P.Equals(T) {
return false
} // P is of low order
T = T.mul(x)
T = T.mul(x)
T = T.mul(x)
T = T.mul(x)
T = T.mul(x)
T = T.mul(x)
T = T.mul(x)
T.Neg()
if !W.Equals(T) {
return false
}
// Not needed
// W.Add(P);
// T.getx().mul(cru)
// W.Add(T)
// if !W.Is_infinity() {return false}
/*
q := NewBIGints(CURVE_Order)
if P.Is_infinity() {return false}
W:=P.mul(q)
if !W.Is_infinity() {return false} */
return true
}
/* test G2 group membership */
func G2member(P *ECP8) bool {
if P.Is_infinity() {
return false
}
F := ECP8_frob_constants()
x := NewBIGints(CURVE_Bnx)
W := NewECP8()
W.Copy(P)
W.frob(F, 1)
T := P.mul(x)
if SIGN_OF_X == NEGATIVEX {
T.neg()
}
/*
R:=NewECP8(); R.Copy(W)
R.frob(F,1)
W.Sub(R)
R.Copy(T)
R.frob(F,1)
W.Add(R)
*/
if !W.Equals(T) {
return false
}
return true
/*
q := NewBIGints(CURVE_Order)
if P.Is_infinity() {return false}
W:=P.mul(q)
if !W.Is_infinity() {return false}
return true */
}
/* Check that m is in cyclotomic sub-group */
/* Check that m!=1, conj(m)*m==1, and m.m^{p^16}=m^{p^8} */
func GTcyclotomic(m *FP48) bool {
if m.Isunity() {
return false
}
r := NewFP48copy(m)
r.conj()
r.Mul(m)
if !r.Isunity() {
return false
}
f := NewFP2bigs(NewBIGints(Fra), NewBIGints(Frb))
r.Copy(m)
r.frob(f, 8)
w := NewFP48copy(r)
w.frob(f, 8)
w.Mul(m)
if !w.Equals(r) {
return false
}
return true
}
/* test for full GT membership */
func GTmember(m *FP48) bool {
if !GTcyclotomic(m) {
return false
}
f := NewFP2bigs(NewBIGints(Fra), NewBIGints(Frb))
x := NewBIGints(CURVE_Bnx)
r := NewFP48copy(m)
r.frob(f, 1)
t := m.Pow(x)
if SIGN_OF_X == NEGATIVEX {
t.conj()
}
if !r.Equals(t) {
return false
}
return true
/*
q := NewBIGints(CURVE_Order)
r := m.Pow(q)
if !r.Isunity() {
return false
}
return true */
}