blob: f2e83ad3d7ecfd4003a7e19d15ea7f6fd3a1644b [file] [log] [blame]
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
*/
/* MiotCL Fp^12 functions */
/* FP12 elements are of the form a+i.b+i^2.c */
package XXX
//import "fmt"
type FP48 struct {
a *FP16
b *FP16
c *FP16
stype int
}
/* Constructors */
func NewFP48() *FP48 {
F := new(FP48)
F.a = NewFP16()
F.b = NewFP16()
F.c = NewFP16()
F.stype=FP_ZERO
return F
}
func NewFP48fp16(d *FP16) *FP48 {
F := new(FP48)
F.a = NewFP16copy(d)
F.b = NewFP16()
F.c = NewFP16()
F.stype=FP_SPARSER
return F
}
func NewFP48int(d int) *FP48 {
F := new(FP48)
F.a = NewFP16int(d)
F.b = NewFP16()
F.c = NewFP16()
if d==1 {
F.stype=FP_ONE
} else {
F.stype=FP_SPARSER
}
return F
}
func NewFP48fp16s(d *FP16, e *FP16, f *FP16) *FP48 {
F := new(FP48)
F.a = NewFP16copy(d)
F.b = NewFP16copy(e)
F.c = NewFP16copy(f)
F.stype=FP_DENSE
return F
}
func NewFP48copy(x *FP48) *FP48 {
F := new(FP48)
F.a = NewFP16copy(x.a)
F.b = NewFP16copy(x.b)
F.c = NewFP16copy(x.c)
F.stype=x.stype
return F
}
/* reduce all components of this mod Modulus */
func (F *FP48) reduce() {
F.a.reduce()
F.b.reduce()
F.c.reduce()
}
/* normalise all components of this */
func (F *FP48) norm() {
F.a.norm()
F.b.norm()
F.c.norm()
}
/* test x==0 ? */
func (F *FP48) iszilch() bool {
return (F.a.iszilch() && F.b.iszilch() && F.c.iszilch())
}
/* Conditional move */
func (F *FP48) cmove(g *FP48, d int) {
F.a.cmove(g.a, d)
F.b.cmove(g.b, d)
F.c.cmove(g.c, d)
d=^(d-1)
F.stype^=(F.stype^g.stype)&d
}
/* Constant time select from pre-computed table */
func (F *FP48) selector(g []*FP48, b int32) {
m := b >> 31
babs := (b ^ m) - m
babs = (babs - 1) / 2
F.cmove(g[0], teq(babs, 0)) // conditional move
F.cmove(g[1], teq(babs, 1))
F.cmove(g[2], teq(babs, 2))
F.cmove(g[3], teq(babs, 3))
F.cmove(g[4], teq(babs, 4))
F.cmove(g[5], teq(babs, 5))
F.cmove(g[6], teq(babs, 6))
F.cmove(g[7], teq(babs, 7))
invF := NewFP48copy(F)
invF.conj()
F.cmove(invF, int(m&1))
}
/* test x==1 ? */
func (F *FP48) Isunity() bool {
one := NewFP16int(1)
return (F.a.Equals(one) && F.b.iszilch() && F.c.iszilch())
}
/* return 1 if x==y, else 0 */
func (F *FP48) Equals(x *FP48) bool {
return (F.a.Equals(x.a) && F.b.Equals(x.b) && F.c.Equals(x.c))
}
/* extract a from this */
func (F *FP48) geta() *FP16 {
return F.a
}
/* extract b */
func (F *FP48) getb() *FP16 {
return F.b
}
/* extract c */
func (F *FP48) getc() *FP16 {
return F.c
}
/* copy this=x */
func (F *FP48) Copy(x *FP48) {
F.a.copy(x.a)
F.b.copy(x.b)
F.c.copy(x.c)
F.stype=x.stype
}
/* set this=1 */
func (F *FP48) one() {
F.stype=FP_ONE
F.a.one()
F.b.zero()
F.c.zero()
}
/* set this=0 */
func (F *FP48) zero() {
F.stype=FP_ZERO
F.a.zero()
F.b.zero()
F.c.zero()
}
/* this=conj(this) */
func (F *FP48) conj() {
F.a.conj()
F.b.nconj()
F.c.conj()
}
/* Granger-Scott Unitary Squaring */
func (F *FP48) usqr() {
A := NewFP16copy(F.a)
B := NewFP16copy(F.c)
C := NewFP16copy(F.b)
D := NewFP16()
F.a.sqr()
D.copy(F.a)
D.add(F.a)
F.a.add(D)
F.a.norm()
A.nconj()
A.add(A)
F.a.add(A)
B.sqr()
B.times_i()
D.copy(B)
D.add(B)
B.add(D)
B.norm()
C.sqr()
D.copy(C)
D.add(C)
C.add(D)
C.norm()
F.b.conj()
F.b.add(F.b)
F.c.nconj()
F.c.add(F.c)
F.b.add(B)
F.c.add(C)
F.reduce()
F.stype=FP_DENSE
}
/* Chung-Hasan SQR2 method from http://cacr.uwaterloo.ca/techreports/2006/cacr2006-24.pdf */
func (F *FP48) sqr() {
if F.stype==FP_ONE {
return
}
A := NewFP16copy(F.a)
B := NewFP16copy(F.b)
C := NewFP16copy(F.c)
D := NewFP16copy(F.a)
A.sqr()
B.mul(F.c)
B.add(B)
B.norm()
C.sqr()
D.mul(F.b)
D.add(D)
F.c.add(F.a)
F.c.add(F.b)
F.c.norm()
F.c.sqr()
F.a.copy(A)
A.add(B)
A.norm()
A.add(C)
A.add(D)
A.norm()
A.neg()
B.times_i()
C.times_i()
F.a.add(B)
F.b.copy(C)
F.b.add(D)
F.c.add(A)
if F.stype==FP_SPARSER {
F.stype=FP_SPARSE
} else {
F.stype=FP_DENSE
}
F.norm()
}
/* FP48 full multiplication this=this*y */
func (F *FP48) Mul(y *FP48) {
z0 := NewFP16copy(F.a)
z1 := NewFP16()
z2 := NewFP16copy(F.b)
z3 := NewFP16()
t0 := NewFP16copy(F.a)
t1 := NewFP16copy(y.a)
z0.mul(y.a)
z2.mul(y.b)
t0.add(F.b)
t0.norm()
t1.add(y.b)
t1.norm()
z1.copy(t0)
z1.mul(t1)
t0.copy(F.b)
t0.add(F.c)
t0.norm()
t1.copy(y.b)
t1.add(y.c)
t1.norm()
z3.copy(t0)
z3.mul(t1)
t0.copy(z0)
t0.neg()
t1.copy(z2)
t1.neg()
z1.add(t0)
//z1.norm();
F.b.copy(z1)
F.b.add(t1)
z3.add(t1)
z2.add(t0)
t0.copy(F.a)
t0.add(F.c)
t0.norm()
t1.copy(y.a)
t1.add(y.c)
t1.norm()
t0.mul(t1)
z2.add(t0)
t0.copy(F.c)
t0.mul(y.c)
t1.copy(t0)
t1.neg()
F.c.copy(z2)
F.c.add(t1)
z3.add(t1)
t0.times_i()
F.b.add(t0)
z3.norm()
z3.times_i()
F.a.copy(z0)
F.a.add(z3)
F.stype=FP_DENSE
F.norm()
}
/* FP48 full multiplication w=w*y */
/* Supports sparse multiplicands */
/* Usually w is denser than y */
func (F *FP48) ssmul(y *FP48) {
if F.stype==FP_ONE {
F.Copy(y)
return
}
if y.stype==FP_ONE {
return
}
if y.stype>=FP_SPARSE {
z0:=NewFP16copy(F.a)
z1:=NewFP16()
z2:=NewFP16()
z3:=NewFP16()
z0.mul(y.a)
if SEXTIC_TWIST==M_TYPE {
if y.stype==FP_SPARSE || F.stype==FP_SPARSE {
z2.getb().copy(F.b.getb())
z2.getb().mul(y.b.getb())
z2.geta().zero()
if y.stype!=FP_SPARSE {
z2.geta().copy(F.b.getb())
z2.geta().mul(y.b.geta())
}
if F.stype!=FP_SPARSE {
z2.geta().copy(F.b.geta())
z2.geta().mul(y.b.getb())
}
z2.times_i()
} else {
z2.copy(F.b)
z2.mul(y.b)
}
} else {
z2.copy(F.b)
z2.mul(y.b)
}
t0:=NewFP16copy(F.a)
t1:=NewFP16copy(y.a)
t0.add(F.b); t0.norm();
t1.add(y.b); t1.norm()
z1.copy(t0); z1.mul(t1)
t0.copy(F.b); t0.add(F.c); t0.norm()
t1.copy(y.b); t1.add(y.c); t1.norm()
z3.copy(t0); z3.mul(t1)
t0.copy(z0); t0.neg()
t1.copy(z2); t1.neg()
z1.add(t0)
F.b.copy(z1); F.b.add(t1)
z3.add(t1)
z2.add(t0)
t0.copy(F.a); t0.add(F.c); t0.norm()
t1.copy(y.a); t1.add(y.c); t1.norm()
t0.mul(t1)
z2.add(t0)
if SEXTIC_TWIST==D_TYPE {
if y.stype==FP_SPARSE || F.stype==FP_SPARSE {
t0.geta().copy(F.c.geta())
t0.geta().mul(y.c.geta())
t0.getb().zero()
if y.stype!=FP_SPARSE {
t0.getb().copy(F.c.geta())
t0.getb().mul(y.c.getb())
}
if F.stype!=FP_SPARSE {
t0.getb().copy(F.c.getb())
t0.getb().mul(y.c.geta())
}
} else {
t0.copy(F.c)
t0.mul(y.c)
}
} else {
t0.copy(F.c)
t0.mul(y.c)
}
t1.copy(t0); t1.neg()
F.c.copy(z2); F.c.add(t1)
z3.add(t1)
t0.times_i()
F.b.add(t0)
z3.norm()
z3.times_i()
F.a.copy(z0); F.a.add(z3);
} else {
if F.stype==FP_SPARSER {
F.smul(y)
return
}
if SEXTIC_TWIST==D_TYPE { // dense by sparser - 13m
z0:=NewFP16copy(F.a)
z2:=NewFP16copy(F.b)
z3:=NewFP16copy(F.b)
t0:=NewFP16()
t1:=NewFP16copy(y.a)
z0.mul(y.a)
z2.pmul(y.b.real())
F.b.add(F.a)
t1.real().add(y.b.real())
t1.norm()
F.b.norm()
F.b.mul(t1)
z3.add(F.c)
z3.norm()
z3.pmul(y.b.real())
t0.copy(z0); t0.neg()
t1.copy(z2); t1.neg()
F.b.add(t0)
F.b.add(t1)
z3.add(t1)
z2.add(t0)
t0.copy(F.a); t0.add(F.c); t0.norm()
z3.norm()
t0.mul(y.a)
F.c.copy(z2); F.c.add(t0)
z3.times_i()
F.a.copy(z0); F.a.add(z3)
}
if SEXTIC_TWIST==M_TYPE {
z0:=NewFP16copy(F.a)
z1:=NewFP16()
z2:=NewFP16()
z3:=NewFP16()
t0:=NewFP16copy(F.a)
t1:=NewFP16()
z0.mul(y.a)
t0.add(F.b); t0.norm()
z1.copy(t0); z1.mul(y.a)
t0.copy(F.b); t0.add(F.c)
t0.norm()
z3.copy(t0)
z3.pmul(y.c.getb())
z3.times_i()
t0.copy(z0); t0.neg()
z1.add(t0)
F.b.copy(z1)
z2.copy(t0)
t0.copy(F.a); t0.add(F.c); t0.norm()
t1.copy(y.a); t1.add(y.c); t1.norm()
t0.mul(t1)
z2.add(t0)
t0.copy(F.c)
t0.pmul(y.c.getb())
t0.times_i()
t1.copy(t0); t1.neg()
F.c.copy(z2); F.c.add(t1)
z3.add(t1)
t0.times_i()
F.b.add(t0)
z3.norm()
z3.times_i()
F.a.copy(z0); F.a.add(z3)
}
}
F.stype=FP_DENSE
F.norm()
}
/* Special case of multiplication arises from special form of ATE pairing line function */
func (F *FP48) smul(y *FP48) {
if SEXTIC_TWIST==D_TYPE {
w1:=NewFP8copy(F.a.geta())
w2:=NewFP8copy(F.a.getb())
w3:=NewFP8copy(F.b.geta())
w1.mul(y.a.geta())
w2.mul(y.a.getb())
w3.mul(y.b.geta())
ta:=NewFP8copy(F.a.geta())
tb:=NewFP8copy(y.a.geta())
ta.add(F.a.getb()); ta.norm()
tb.add(y.a.getb()); tb.norm()
tc:=NewFP8copy(ta)
tc.mul(tb);
t:=NewFP8copy(w1)
t.add(w2)
t.neg()
tc.add(t)
ta.copy(F.a.geta()); ta.add(F.b.geta()); ta.norm()
tb.copy(y.a.geta()); tb.add(y.b.geta()); tb.norm()
td:=NewFP8copy(ta)
td.mul(tb)
t.copy(w1)
t.add(w3)
t.neg()
td.add(t)
ta.copy(F.a.getb()); ta.add(F.b.geta()); ta.norm()
tb.copy(y.a.getb()); tb.add(y.b.geta()); tb.norm()
te:=NewFP8copy(ta)
te.mul(tb)
t.copy(w2)
t.add(w3)
t.neg()
te.add(t)
w2.times_i()
w1.add(w2)
F.a.geta().copy(w1); F.a.getb().copy(tc)
F.b.geta().copy(td); F.b.getb().copy(te)
F.c.geta().copy(w3); F.c.getb().zero()
F.a.norm()
F.b.norm()
} else {
w1:=NewFP8copy(F.a.geta())
w2:=NewFP8copy(F.a.getb())
w3:=NewFP8copy(F.c.getb())
w1.mul(y.a.geta())
w2.mul(y.a.getb())
w3.mul(y.c.getb())
ta:=NewFP8copy(F.a.geta())
tb:=NewFP8copy(y.a.geta())
ta.add(F.a.getb()); ta.norm()
tb.add(y.a.getb()); tb.norm()
tc:=NewFP8copy(ta)
tc.mul(tb);
t:=NewFP8copy(w1)
t.add(w2)
t.neg()
tc.add(t)
ta.copy(F.a.geta()); ta.add(F.c.getb()); ta.norm()
tb.copy(y.a.geta()); tb.add(y.c.getb()); tb.norm()
td:=NewFP8copy(ta)
td.mul(tb)
t.copy(w1)
t.add(w3)
t.neg()
td.add(t)
ta.copy(F.a.getb()); ta.add(F.c.getb()); ta.norm()
tb.copy(y.a.getb()); tb.add(y.c.getb()); tb.norm()
te:=NewFP8copy(ta)
te.mul(tb)
t.copy(w2)
t.add(w3)
t.neg()
te.add(t)
w2.times_i()
w1.add(w2)
F.a.geta().copy(w1); F.a.getb().copy(tc)
w3.times_i()
w3.norm()
F.b.geta().zero(); F.b.getb().copy(w3)
te.norm()
te.times_i()
F.c.geta().copy(te)
F.c.getb().copy(td)
F.a.norm()
F.c.norm()
}
F.stype=FP_SPARSE;
}
/* this=1/this */
func (F *FP48) Inverse() {
f0 := NewFP16copy(F.a)
f1 := NewFP16copy(F.b)
f2 := NewFP16copy(F.a)
f3 := NewFP16()
//F.norm()
f0.sqr()
f1.mul(F.c)
f1.times_i()
f0.sub(f1)
f0.norm()
f1.copy(F.c)
f1.sqr()
f1.times_i()
f2.mul(F.b)
f1.sub(f2)
f1.norm()
f2.copy(F.b)
f2.sqr()
f3.copy(F.a)
f3.mul(F.c)
f2.sub(f3)
f2.norm()
f3.copy(F.b)
f3.mul(f2)
f3.times_i()
F.a.mul(f0)
f3.add(F.a)
F.c.mul(f1)
F.c.times_i()
f3.add(F.c)
f3.norm()
f3.inverse()
F.a.copy(f0)
F.a.mul(f3)
F.b.copy(f1)
F.b.mul(f3)
F.c.copy(f2)
F.c.mul(f3)
F.stype=FP_DENSE
}
/* this=this^p using Frobenius */
func (F *FP48) frob(f *FP2, n int) {
f2 := NewFP2copy(f)
f3 := NewFP2copy(f)
f2.sqr()
f3.mul(f2)
f3.mul_ip()
f3.norm()
f3.mul_ip()
f3.norm()
for i := 0; i < n; i++ {
F.a.frob(f3)
F.b.frob(f3)
F.c.frob(f3)
F.b.qmul(f)
F.b.times_i4()
F.b.times_i2()
F.c.qmul(f2)
F.c.times_i4()
F.c.times_i4()
F.c.times_i4()
}
F.stype=FP_DENSE
}
/* trace function */
func (F *FP48) trace() *FP16 {
t := NewFP16()
t.copy(F.a)
t.imul(3)
t.reduce()
return t
}
/* convert from byte array to FP48 */
func FP48_fromBytes(w []byte) *FP48 {
var t [int(MODBYTES)]byte
MB := int(MODBYTES)
for i := 0; i < MB; i++ {
t[i] = w[i]
}
a := FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+MB]
}
b := FromBytes(t[:])
c := NewFP2bigs(a, b)
for i := 0; i < MB; i++ {
t[i] = w[i+2*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+3*MB]
}
b = FromBytes(t[:])
d := NewFP2bigs(a, b)
ea := NewFP4fp2s(c, d)
for i := 0; i < MB; i++ {
t[i] = w[i+4*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+5*MB]
}
b = FromBytes(t[:])
c = NewFP2bigs(a, b)
for i := 0; i < MB; i++ {
t[i] = w[i+6*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+7*MB]
}
b = FromBytes(t[:])
d = NewFP2bigs(a, b)
eb := NewFP4fp2s(c, d)
e := NewFP8fp4s(ea, eb)
for i := 0; i < MB; i++ {
t[i] = w[i+8*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+9*MB]
}
b = FromBytes(t[:])
c = NewFP2bigs(a, b)
for i := 0; i < MB; i++ {
t[i] = w[i+10*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+11*MB]
}
b = FromBytes(t[:])
d = NewFP2bigs(a, b)
ea = NewFP4fp2s(c, d)
for i := 0; i < MB; i++ {
t[i] = w[i+12*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+13*MB]
}
b = FromBytes(t[:])
c = NewFP2bigs(a, b)
for i := 0; i < MB; i++ {
t[i] = w[i+14*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+15*MB]
}
b = FromBytes(t[:])
d = NewFP2bigs(a, b)
eb = NewFP4fp2s(c, d)
f := NewFP8fp4s(ea, eb)
g := NewFP16fp8s(e, f)
for i := 0; i < MB; i++ {
t[i] = w[i+16*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+17*MB]
}
b = FromBytes(t[:])
c = NewFP2bigs(a, b)
for i := 0; i < MB; i++ {
t[i] = w[i+18*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+19*MB]
}
b = FromBytes(t[:])
d = NewFP2bigs(a, b)
ea = NewFP4fp2s(c, d)
for i := 0; i < MB; i++ {
t[i] = w[i+20*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+21*MB]
}
b = FromBytes(t[:])
c = NewFP2bigs(a, b)
for i := 0; i < MB; i++ {
t[i] = w[i+22*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+23*MB]
}
b = FromBytes(t[:])
d = NewFP2bigs(a, b)
eb = NewFP4fp2s(c, d)
e = NewFP8fp4s(ea, eb)
for i := 0; i < MB; i++ {
t[i] = w[i+24*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+25*MB]
}
b = FromBytes(t[:])
c = NewFP2bigs(a, b)
for i := 0; i < MB; i++ {
t[i] = w[i+26*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+27*MB]
}
b = FromBytes(t[:])
d = NewFP2bigs(a, b)
ea = NewFP4fp2s(c, d)
for i := 0; i < MB; i++ {
t[i] = w[i+28*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+29*MB]
}
b = FromBytes(t[:])
c = NewFP2bigs(a, b)
for i := 0; i < MB; i++ {
t[i] = w[i+30*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+31*MB]
}
b = FromBytes(t[:])
d = NewFP2bigs(a, b)
eb = NewFP4fp2s(c, d)
f = NewFP8fp4s(ea, eb)
h := NewFP16fp8s(e, f)
for i := 0; i < MB; i++ {
t[i] = w[i+32*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+33*MB]
}
b = FromBytes(t[:])
c = NewFP2bigs(a, b)
for i := 0; i < MB; i++ {
t[i] = w[i+34*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+35*MB]
}
b = FromBytes(t[:])
d = NewFP2bigs(a, b)
ea = NewFP4fp2s(c, d)
for i := 0; i < MB; i++ {
t[i] = w[i+36*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+37*MB]
}
b = FromBytes(t[:])
c = NewFP2bigs(a, b)
for i := 0; i < MB; i++ {
t[i] = w[i+38*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+39*MB]
}
b = FromBytes(t[:])
d = NewFP2bigs(a, b)
eb = NewFP4fp2s(c, d)
e = NewFP8fp4s(ea, eb)
for i := 0; i < MB; i++ {
t[i] = w[i+40*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+41*MB]
}
b = FromBytes(t[:])
c = NewFP2bigs(a, b)
for i := 0; i < MB; i++ {
t[i] = w[i+42*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+43*MB]
}
b = FromBytes(t[:])
d = NewFP2bigs(a, b)
ea = NewFP4fp2s(c, d)
for i := 0; i < MB; i++ {
t[i] = w[i+44*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+45*MB]
}
b = FromBytes(t[:])
c = NewFP2bigs(a, b)
for i := 0; i < MB; i++ {
t[i] = w[i+46*MB]
}
a = FromBytes(t[:])
for i := 0; i < MB; i++ {
t[i] = w[i+47*MB]
}
b = FromBytes(t[:])
d = NewFP2bigs(a, b)
eb = NewFP4fp2s(c, d)
f = NewFP8fp4s(ea, eb)
i := NewFP16fp8s(e, f)
return NewFP48fp16s(g, h, i)
}
/* convert this to byte array */
func (F *FP48) ToBytes(w []byte) {
var t [int(MODBYTES)]byte
MB := int(MODBYTES)
F.a.a.a.geta().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i] = t[i]
}
F.a.a.a.geta().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+MB] = t[i]
}
F.a.a.a.getb().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+2*MB] = t[i]
}
F.a.a.a.getb().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+3*MB] = t[i]
}
F.a.a.b.geta().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+4*MB] = t[i]
}
F.a.a.b.geta().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+5*MB] = t[i]
}
F.a.a.b.getb().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+6*MB] = t[i]
}
F.a.a.b.getb().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+7*MB] = t[i]
}
F.a.b.a.geta().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+8*MB] = t[i]
}
F.a.b.a.geta().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+9*MB] = t[i]
}
F.a.b.a.getb().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+10*MB] = t[i]
}
F.a.b.a.getb().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+11*MB] = t[i]
}
F.a.b.b.geta().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+12*MB] = t[i]
}
F.a.b.b.geta().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+13*MB] = t[i]
}
F.a.b.b.getb().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+14*MB] = t[i]
}
F.a.b.b.getb().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+15*MB] = t[i]
}
F.b.a.a.geta().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+16*MB] = t[i]
}
F.b.a.a.geta().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+17*MB] = t[i]
}
F.b.a.a.getb().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+18*MB] = t[i]
}
F.b.a.a.getb().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+19*MB] = t[i]
}
F.b.a.b.geta().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+20*MB] = t[i]
}
F.b.a.b.geta().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+21*MB] = t[i]
}
F.b.a.b.getb().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+22*MB] = t[i]
}
F.b.a.b.getb().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+23*MB] = t[i]
}
F.b.b.a.geta().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+24*MB] = t[i]
}
F.b.b.a.geta().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+25*MB] = t[i]
}
F.b.b.a.getb().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+26*MB] = t[i]
}
F.b.b.a.getb().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+27*MB] = t[i]
}
F.b.b.b.geta().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+28*MB] = t[i]
}
F.b.b.b.geta().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+29*MB] = t[i]
}
F.b.b.b.getb().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+30*MB] = t[i]
}
F.b.b.b.getb().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+31*MB] = t[i]
}
F.c.a.a.geta().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+32*MB] = t[i]
}
F.c.a.a.geta().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+33*MB] = t[i]
}
F.c.a.a.getb().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+34*MB] = t[i]
}
F.c.a.a.getb().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+35*MB] = t[i]
}
F.c.a.b.geta().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+36*MB] = t[i]
}
F.c.a.b.geta().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+37*MB] = t[i]
}
F.c.a.b.getb().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+38*MB] = t[i]
}
F.c.a.b.getb().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+39*MB] = t[i]
}
F.c.b.a.geta().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+40*MB] = t[i]
}
F.c.b.a.geta().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+41*MB] = t[i]
}
F.c.b.a.getb().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+42*MB] = t[i]
}
F.c.b.a.getb().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+43*MB] = t[i]
}
F.c.b.b.geta().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+44*MB] = t[i]
}
F.c.b.b.geta().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+45*MB] = t[i]
}
F.c.b.b.getb().GetA().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+46*MB] = t[i]
}
F.c.b.b.getb().GetB().ToBytes(t[:])
for i := 0; i < MB; i++ {
w[i+47*MB] = t[i]
}
}
/* convert to hex string */
func (F *FP48) ToString() string {
return ("[" + F.a.toString() + "," + F.b.toString() + "," + F.c.toString() + "]")
}
/* this=this^e */
func (F *FP48) Pow(e *BIG) *FP48 {
sf := NewFP48copy(F)
sf.norm()
e1 := NewBIGcopy(e)
e1.norm()
e3 := NewBIGcopy(e1)
e3.pmul(3)
e3.norm()
w := NewFP48copy(sf)
nb := e3.nbits()
for i := nb - 2; i >= 1; i-- {
w.usqr()
bt := e3.bit(i) - e1.bit(i)
if bt == 1 {
w.Mul(sf)
}
if bt == -1 {
sf.conj()
w.Mul(sf)
sf.conj()
}
}
w.reduce()
return w
}
/* constant time powering by small integer of max length bts */
func (F *FP48) pinpow(e int, bts int) {
var R []*FP48
R = append(R, NewFP48int(1))
R = append(R, NewFP48copy(F))
for i := bts - 1; i >= 0; i-- {
b := (e >> uint(i)) & 1
R[1-b].Mul(R[b])
R[b].usqr()
}
F.Copy(R[0])
}
/* Fast compressed FP16 power of unitary FP48 */
func (F *FP48) Compow(e *BIG, r *BIG) *FP16 {
q := NewBIGints(Modulus)
f := NewFP2bigs(NewBIGints(Fra), NewBIGints(Frb))
m := NewBIGcopy(q)
m.Mod(r)
a := NewBIGcopy(e)
a.Mod(m)
b := NewBIGcopy(e)
b.div(m)
g1 := NewFP48copy(F)
c := g1.trace()
if b.iszilch() {
c = c.xtr_pow(e)
return c
}
g2 := NewFP48copy(F)
g2.frob(f, 1)
cp := g2.trace()
g1.conj()
g2.Mul(g1)
cpm1 := g2.trace()
g2.Mul(g1)
cpm2 := g2.trace()
c = c.xtr_pow2(cp, cpm1, cpm2, a, b)
return c
}
/* p=q0^u0.q1^u1.q2^u2.q3^u3.. */
// Bos & Costello https://eprint.iacr.org/2013/458.pdf
// Faz-Hernandez & Longa & Sanchez https://eprint.iacr.org/2013/158.pdf
// Side channel attack secure
func pow16(q []*FP48, u []*BIG) *FP48 {
var g1 []*FP48
var g2 []*FP48
var g3 []*FP48
var g4 []*FP48
var w1 [NLEN*int(BASEBITS) + 1]int8
var s1 [NLEN*int(BASEBITS) + 1]int8
var w2 [NLEN*int(BASEBITS) + 1]int8
var s2 [NLEN*int(BASEBITS) + 1]int8
var w3 [NLEN*int(BASEBITS) + 1]int8
var s3 [NLEN*int(BASEBITS) + 1]int8
var w4 [NLEN*int(BASEBITS) + 1]int8
var s4 [NLEN*int(BASEBITS) + 1]int8
var t []*BIG
r := NewFP48()
p := NewFP48()
mt := NewBIGint(0)
var bt int8
var k int
for i := 0; i < 16; i++ {
t = append(t, NewBIGcopy(u[i]))
}
g1 = append(g1, NewFP48copy(q[0])) // q[0]
g1 = append(g1, NewFP48copy(g1[0]))
g1[1].Mul(q[1]) // q[0].q[1]
g1 = append(g1, NewFP48copy(g1[0]))
g1[2].Mul(q[2]) // q[0].q[2]
g1 = append(g1, NewFP48copy(g1[1]))
g1[3].Mul(q[2]) // q[0].q[1].q[2]
g1 = append(g1, NewFP48copy(g1[0]))
g1[4].Mul(q[3]) // q[0].q[3]
g1 = append(g1, NewFP48copy(g1[1]))
g1[5].Mul(q[3]) // q[0].q[1].q[3]
g1 = append(g1, NewFP48copy(g1[2]))
g1[6].Mul(q[3]) // q[0].q[2].q[3]
g1 = append(g1, NewFP48copy(g1[3]))
g1[7].Mul(q[3]) // q[0].q[1].q[2].q[3]
Fra := NewBIGints(Fra)
Frb := NewBIGints(Frb)
X := NewFP2bigs(Fra, Frb)
// Use Frobenius
for i := 0; i < 8; i++ {
g2 = append(g2, NewFP48copy(g1[i]))
g2[i].frob(X, 4)
g3 = append(g3, NewFP48copy(g2[i]))
g3[i].frob(X, 4)
g4 = append(g4, NewFP48copy(g3[i]))
g4[i].frob(X, 4)
}
// Make them odd
pb1 := 1 - t[0].parity()
t[0].inc(pb1)
// t[0].norm();
pb2 := 1 - t[4].parity()
t[4].inc(pb2)
// t[4].norm();
pb3 := 1 - t[8].parity()
t[8].inc(pb3)
// t[8].norm();
pb4 := 1 - t[12].parity()
t[12].inc(pb4)
// t[12].norm();
// Number of bits
mt.zero()
for i := 0; i < 16; i++ {
t[i].norm()
mt.or(t[i])
}
nb := 1 + mt.nbits()
// Sign pivot
s1[nb-1] = 1
s2[nb-1] = 1
s3[nb-1] = 1
s4[nb-1] = 1
for i := 0; i < nb-1; i++ {
t[0].fshr(1)
s1[i] = 2*int8(t[0].parity()) - 1
t[4].fshr(1)
s2[i] = 2*int8(t[4].parity()) - 1
t[8].fshr(1)
s3[i] = 2*int8(t[8].parity()) - 1
t[12].fshr(1)
s4[i] = 2*int8(t[12].parity()) - 1
}
// Recoded exponents
for i := 0; i < nb; i++ {
w1[i] = 0
k = 1
for j := 1; j < 4; j++ {
bt = s1[i] * int8(t[j].parity())
t[j].fshr(1)
t[j].dec(int(bt) >> 1)
t[j].norm()
w1[i] += bt * int8(k)
k *= 2
}
w2[i] = 0
k = 1
for j := 5; j < 8; j++ {
bt = s2[i] * int8(t[j].parity())
t[j].fshr(1)
t[j].dec(int(bt) >> 1)
t[j].norm()
w2[i] += bt * int8(k)
k *= 2
}
w3[i] = 0
k = 1
for j := 9; j < 12; j++ {
bt = s3[i] * int8(t[j].parity())
t[j].fshr(1)
t[j].dec(int(bt) >> 1)
t[j].norm()
w3[i] += bt * int8(k)
k *= 2
}
w4[i] = 0
k = 1
for j := 13; j < 16; j++ {
bt = s4[i] * int8(t[j].parity())
t[j].fshr(1)
t[j].dec(int(bt) >> 1)
t[j].norm()
w4[i] += bt * int8(k)
k *= 2
}
}
// Main loop
p.selector(g1, int32(2*w1[nb-1]+1))
r.selector(g2, int32(2*w2[nb-1]+1))
p.Mul(r)
r.selector(g3, int32(2*w3[nb-1]+1))
p.Mul(r)
r.selector(g4, int32(2*w4[nb-1]+1))
p.Mul(r)
for i := nb - 2; i >= 0; i-- {
p.usqr()
r.selector(g1, int32(2*w1[i]+s1[i]))
p.Mul(r)
r.selector(g2, int32(2*w2[i]+s2[i]))
p.Mul(r)
r.selector(g3, int32(2*w3[i]+s3[i]))
p.Mul(r)
r.selector(g4, int32(2*w4[i]+s4[i]))
p.Mul(r)
}
// apply correction
r.Copy(q[0])
r.conj()
r.Mul(p)
p.cmove(r, pb1)
r.Copy(q[4])
r.conj()
r.Mul(p)
p.cmove(r, pb2)
r.Copy(q[8])
r.conj()
r.Mul(p)
p.cmove(r, pb3)
r.Copy(q[12])
r.conj()
r.Mul(p)
p.cmove(r, pb4)
p.reduce()
return p
}