mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-27 00:55:17 +00:00
1190 lines
20 KiB
Go
1190 lines
20 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.
|
||
|
*/
|
||
|
|
||
|
/* MiotCL Fp^12 functions */
|
||
|
/* FP12 elements are of the form a+i.b+i^2.c */
|
||
|
|
||
|
package bls48581
|
||
|
|
||
|
//import "fmt"
|
||
|
|
||
|
type FP48 struct {
|
||
|
a *FP16
|
||
|
b *FP16
|
||
|
c *FP16
|
||
|
stype int
|
||
|
}
|
||
|
|
||
|
/* Constructors */
|
||
|
func NewFP48fp16(d *FP16) *FP48 {
|
||
|
F := new(FP48)
|
||
|
F.a = NewFP16copy(d)
|
||
|
F.b = NewFP16()
|
||
|
F.c = NewFP16()
|
||
|
F.stype = FP_SPARSEST
|
||
|
return F
|
||
|
}
|
||
|
|
||
|
func NewFP48() *FP48 {
|
||
|
F := new(FP48)
|
||
|
F.a = NewFP16()
|
||
|
F.b = NewFP16()
|
||
|
F.c = NewFP16()
|
||
|
F.stype = FP_ZERO
|
||
|
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_SPARSEST
|
||
|
}
|
||
|
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.a.zero()
|
||
|
F.b.zero()
|
||
|
F.c.zero()
|
||
|
F.stype = FP_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_SPARSEST {
|
||
|
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.stype == FP_SPARSEST {
|
||
|
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)
|
||
|
|
||
|
if y.stype == FP_SPARSEST {
|
||
|
z2.tmul(y.b.a.a.a.a)
|
||
|
} else {
|
||
|
z2.pmul(y.b.geta())
|
||
|
}
|
||
|
F.b.add(F.a)
|
||
|
t1.geta().add(y.b.geta())
|
||
|
|
||
|
t1.norm()
|
||
|
F.b.norm()
|
||
|
F.b.mul(t1)
|
||
|
z3.add(F.c)
|
||
|
z3.norm()
|
||
|
|
||
|
if y.stype == FP_SPARSEST {
|
||
|
z3.tmul(y.b.a.a.a.a)
|
||
|
} else {
|
||
|
z3.pmul(y.b.geta())
|
||
|
}
|
||
|
|
||
|
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)
|
||
|
|
||
|
if y.stype == FP_SPARSEST {
|
||
|
z3.tmul(y.c.b.a.a.a)
|
||
|
} else {
|
||
|
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)
|
||
|
|
||
|
if y.stype == FP_SPARSEST {
|
||
|
t0.tmul(y.c.b.a.a.a)
|
||
|
} else {
|
||
|
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())
|
||
|
var w3 *FP8
|
||
|
|
||
|
w1.mul(y.a.geta())
|
||
|
w2.mul(y.a.getb())
|
||
|
|
||
|
if y.stype == FP_SPARSEST || F.stype == FP_SPARSEST {
|
||
|
if y.stype == FP_SPARSEST && F.stype == FP_SPARSEST {
|
||
|
t := NewFPcopy(F.b.a.a.a.a)
|
||
|
t.mul(y.b.a.a.a.a)
|
||
|
w3 = NewFP8fp(t)
|
||
|
} else {
|
||
|
if y.stype != FP_SPARSEST {
|
||
|
w3 = NewFP8copy(y.b.geta())
|
||
|
w3.tmul(F.b.a.a.a.a)
|
||
|
} else {
|
||
|
w3 = NewFP8copy(F.b.geta())
|
||
|
w3.tmul(y.b.a.a.a.a)
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
w3 = NewFP8copy(F.b.geta())
|
||
|
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())
|
||
|
var w3 *FP8
|
||
|
|
||
|
w1.mul(y.a.geta())
|
||
|
w2.mul(y.a.getb())
|
||
|
|
||
|
if y.stype == FP_SPARSEST || F.stype == FP_SPARSEST {
|
||
|
if y.stype == FP_SPARSEST && F.stype == FP_SPARSEST {
|
||
|
t := NewFPcopy(F.c.b.a.a.a)
|
||
|
t.mul(y.c.b.a.a.a)
|
||
|
w3 = NewFP8fp(t)
|
||
|
} else {
|
||
|
if y.stype != FP_SPARSEST {
|
||
|
w3 = NewFP8copy(y.c.getb())
|
||
|
w3.tmul(F.c.b.a.a.a)
|
||
|
} else {
|
||
|
w3 = NewFP8copy(F.c.getb())
|
||
|
w3.tmul(y.c.b.a.a.a)
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
w3 = NewFP8copy(F.c.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 [16 * int(MODBYTES)]byte
|
||
|
MB := 16 * int(MODBYTES)
|
||
|
|
||
|
for i := 0; i < MB; i++ {
|
||
|
t[i] = w[i]
|
||
|
}
|
||
|
c := FP16_fromBytes(t[:])
|
||
|
for i := 0; i < MB; i++ {
|
||
|
t[i] = w[i+MB]
|
||
|
}
|
||
|
b := FP16_fromBytes(t[:])
|
||
|
for i := 0; i < MB; i++ {
|
||
|
t[i] = w[i+2*MB]
|
||
|
}
|
||
|
a := FP16_fromBytes(t[:])
|
||
|
return NewFP48fp16s(a, b, c)
|
||
|
}
|
||
|
|
||
|
/* convert this to byte array */
|
||
|
func (F *FP48) ToBytes(w []byte) {
|
||
|
var t [16 * int(MODBYTES)]byte
|
||
|
MB := 16 * int(MODBYTES)
|
||
|
F.c.ToBytes(t[:])
|
||
|
for i := 0; i < MB; i++ {
|
||
|
w[i] = t[i]
|
||
|
}
|
||
|
F.b.ToBytes(t[:])
|
||
|
for i := 0; i < MB; i++ {
|
||
|
w[i+MB] = t[i]
|
||
|
}
|
||
|
F.a.ToBytes(t[:])
|
||
|
for i := 0; i < MB; i++ {
|
||
|
w[i+2*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)
|
||
|
if e3.iszilch() {
|
||
|
w.one()
|
||
|
return w
|
||
|
}
|
||
|
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]
|
||
|
|
||
|
g2 = append(g2, NewFP48copy(q[4])) // q[0]
|
||
|
g2 = append(g2, NewFP48copy(g2[0]))
|
||
|
g2[1].Mul(q[5]) // q[0].q[1]
|
||
|
g2 = append(g2, NewFP48copy(g2[0]))
|
||
|
g2[2].Mul(q[6]) // q[0].q[2]
|
||
|
g2 = append(g2, NewFP48copy(g2[1]))
|
||
|
g2[3].Mul(q[6]) // q[0].q[1].q[2]
|
||
|
g2 = append(g2, NewFP48copy(g2[0]))
|
||
|
g2[4].Mul(q[7]) // q[0].q[3]
|
||
|
g2 = append(g2, NewFP48copy(g2[1]))
|
||
|
g2[5].Mul(q[7]) // q[0].q[1].q[3]
|
||
|
g2 = append(g2, NewFP48copy(g2[2]))
|
||
|
g2[6].Mul(q[7]) // q[0].q[2].q[3]
|
||
|
g2 = append(g2, NewFP48copy(g2[3]))
|
||
|
g2[7].Mul(q[7]) // q[0].q[1].q[2].q[3]
|
||
|
|
||
|
g3 = append(g3, NewFP48copy(q[8])) // q[0]
|
||
|
g3 = append(g3, NewFP48copy(g3[0]))
|
||
|
g3[1].Mul(q[9]) // q[0].q[1]
|
||
|
g3 = append(g3, NewFP48copy(g3[0]))
|
||
|
g3[2].Mul(q[10]) // q[0].q[2]
|
||
|
g3 = append(g3, NewFP48copy(g3[1]))
|
||
|
g3[3].Mul(q[10]) // q[0].q[1].q[2]
|
||
|
g3 = append(g3, NewFP48copy(g3[0]))
|
||
|
g3[4].Mul(q[11]) // q[0].q[3]
|
||
|
g3 = append(g3, NewFP48copy(g3[1]))
|
||
|
g3[5].Mul(q[11]) // q[0].q[1].q[3]
|
||
|
g3 = append(g3, NewFP48copy(g3[2]))
|
||
|
g3[6].Mul(q[11]) // q[0].q[2].q[3]
|
||
|
g3 = append(g3, NewFP48copy(g3[3]))
|
||
|
g3[7].Mul(q[11]) // q[0].q[1].q[2].q[3]
|
||
|
|
||
|
g4 = append(g4, NewFP48copy(q[12])) // q[0]
|
||
|
g4 = append(g4, NewFP48copy(g4[0]))
|
||
|
g4[1].Mul(q[13]) // q[0].q[1]
|
||
|
g4 = append(g4, NewFP48copy(g4[0]))
|
||
|
g4[2].Mul(q[14]) // q[0].q[2]
|
||
|
g4 = append(g4, NewFP48copy(g4[1]))
|
||
|
g4[3].Mul(q[14]) // q[0].q[1].q[2]
|
||
|
g4 = append(g4, NewFP48copy(g4[0]))
|
||
|
g4[4].Mul(q[15]) // q[0].q[3]
|
||
|
g4 = append(g4, NewFP48copy(g4[1]))
|
||
|
g4[5].Mul(q[15]) // q[0].q[1].q[3]
|
||
|
g4 = append(g4, NewFP48copy(g4[2]))
|
||
|
g4[6].Mul(q[15]) // q[0].q[2].q[3]
|
||
|
g4 = append(g4, NewFP48copy(g4[3]))
|
||
|
g4[7].Mul(q[15]) // q[0].q[1].q[2].q[3]
|
||
|
|
||
|
// 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
|
||
|
}
|