mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-11-10 18:25:17 +00:00
782 lines
11 KiB
Go
782 lines
11 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.
|
|
*/
|
|
|
|
/* Finite Field arithmetic Fp^8 functions */
|
|
|
|
/* FP4 elements are of the form a+ib, where i is sqrt(-1+sqrt(-1)) */
|
|
|
|
package bls48581
|
|
|
|
import "source.quilibrium.com/quilibrium/ceremonyclient/ec/bls48581/core"
|
|
|
|
//import "fmt"
|
|
|
|
type FP8 struct {
|
|
a *FP4
|
|
b *FP4
|
|
}
|
|
|
|
func NewFP8() *FP8 {
|
|
F := new(FP8)
|
|
F.a = NewFP4()
|
|
F.b = NewFP4()
|
|
return F
|
|
}
|
|
|
|
/* Constructors */
|
|
func NewFP8int(a int) *FP8 {
|
|
F := new(FP8)
|
|
F.a = NewFP4int(a)
|
|
F.b = NewFP4()
|
|
return F
|
|
}
|
|
|
|
/* Constructors */
|
|
func NewFP8ints(a int, b int) *FP8 {
|
|
F := new(FP8)
|
|
F.a = NewFP4int(a)
|
|
F.b = NewFP4int(b)
|
|
return F
|
|
}
|
|
|
|
func NewFP8copy(x *FP8) *FP8 {
|
|
F := new(FP8)
|
|
F.a = NewFP4copy(x.a)
|
|
F.b = NewFP4copy(x.b)
|
|
return F
|
|
}
|
|
|
|
func NewFP8fp4s(c *FP4, d *FP4) *FP8 {
|
|
F := new(FP8)
|
|
F.a = NewFP4copy(c)
|
|
F.b = NewFP4copy(d)
|
|
return F
|
|
}
|
|
|
|
func NewFP8fp4(c *FP4) *FP8 {
|
|
F := new(FP8)
|
|
F.a = NewFP4copy(c)
|
|
F.b = NewFP4()
|
|
return F
|
|
}
|
|
|
|
func NewFP8fp(c *FP) *FP8 {
|
|
F := new(FP8)
|
|
F.a = NewFP4fp(c)
|
|
F.b = NewFP4()
|
|
return F
|
|
}
|
|
|
|
func NewFP8rand(rng *core.RAND) *FP8 {
|
|
F := NewFP8fp4s(NewFP4rand(rng), NewFP4rand(rng))
|
|
return F
|
|
}
|
|
|
|
/* reduce all components of this mod Modulus */
|
|
func (F *FP8) reduce() {
|
|
F.a.reduce()
|
|
F.b.reduce()
|
|
}
|
|
|
|
/* normalise all components of this mod Modulus */
|
|
func (F *FP8) norm() {
|
|
F.a.norm()
|
|
F.b.norm()
|
|
}
|
|
|
|
/* test this==0 ? */
|
|
func (F *FP8) iszilch() bool {
|
|
return F.a.iszilch() && F.b.iszilch()
|
|
}
|
|
|
|
func (F *FP8) islarger() int {
|
|
if F.iszilch() {
|
|
return 0
|
|
}
|
|
cmp := F.b.islarger()
|
|
if cmp != 0 {
|
|
return cmp
|
|
}
|
|
return F.a.islarger()
|
|
}
|
|
|
|
func (F *FP8) ToBytes(bf []byte) {
|
|
var t [4 * int(MODBYTES)]byte
|
|
MB := 4 * int(MODBYTES)
|
|
F.b.ToBytes(t[:])
|
|
for i := 0; i < MB; i++ {
|
|
bf[i] = t[i]
|
|
}
|
|
F.a.ToBytes(t[:])
|
|
for i := 0; i < MB; i++ {
|
|
bf[i+MB] = t[i]
|
|
}
|
|
}
|
|
|
|
func FP8_fromBytes(bf []byte) *FP8 {
|
|
var t [4 * int(MODBYTES)]byte
|
|
MB := 4 * int(MODBYTES)
|
|
for i := 0; i < MB; i++ {
|
|
t[i] = bf[i]
|
|
}
|
|
tb := FP4_fromBytes(t[:])
|
|
for i := 0; i < MB; i++ {
|
|
t[i] = bf[i+MB]
|
|
}
|
|
ta := FP4_fromBytes(t[:])
|
|
return NewFP8fp4s(ta, tb)
|
|
}
|
|
|
|
/* Conditional move */
|
|
func (F *FP8) cmove(g *FP8, d int) {
|
|
F.a.cmove(g.a, d)
|
|
F.b.cmove(g.b, d)
|
|
}
|
|
|
|
/* test this==1 ? */
|
|
func (F *FP8) isunity() bool {
|
|
one := NewFP4int(1)
|
|
return F.a.Equals(one) && F.b.iszilch()
|
|
}
|
|
|
|
/* test is w real? That is in a+ib test b is zero */
|
|
func (F *FP8) isreal() bool {
|
|
return F.b.iszilch()
|
|
}
|
|
|
|
/* extract real part a */
|
|
func (F *FP8) real() *FP4 {
|
|
return F.a
|
|
}
|
|
|
|
func (F *FP8) geta() *FP4 {
|
|
return F.a
|
|
}
|
|
|
|
/* extract imaginary part b */
|
|
func (F *FP8) getb() *FP4 {
|
|
return F.b
|
|
}
|
|
|
|
/* test this=x? */
|
|
func (F *FP8) Equals(x *FP8) bool {
|
|
return (F.a.Equals(x.a) && F.b.Equals(x.b))
|
|
}
|
|
|
|
/* copy this=x */
|
|
func (F *FP8) copy(x *FP8) {
|
|
F.a.copy(x.a)
|
|
F.b.copy(x.b)
|
|
}
|
|
|
|
/* set this=0 */
|
|
func (F *FP8) zero() {
|
|
F.a.zero()
|
|
F.b.zero()
|
|
}
|
|
|
|
/* set this=1 */
|
|
func (F *FP8) one() {
|
|
F.a.one()
|
|
F.b.zero()
|
|
}
|
|
|
|
/* Return sign */
|
|
func (F *FP8) sign() int {
|
|
p1 := F.a.sign()
|
|
p2 := F.b.sign()
|
|
var u int
|
|
if BIG_ENDIAN_SIGN {
|
|
if F.b.iszilch() {
|
|
u = 1
|
|
} else {
|
|
u = 0
|
|
}
|
|
p2 ^= (p1 ^ p2) & u
|
|
return p2
|
|
} else {
|
|
if F.a.iszilch() {
|
|
u = 1
|
|
} else {
|
|
u = 0
|
|
}
|
|
p1 ^= (p1 ^ p2) & u
|
|
return p1
|
|
}
|
|
}
|
|
|
|
/* set this=-this */
|
|
func (F *FP8) neg() {
|
|
F.norm()
|
|
m := NewFP4copy(F.a)
|
|
t := NewFP4()
|
|
m.add(F.b)
|
|
m.neg()
|
|
t.copy(m)
|
|
t.add(F.b)
|
|
F.b.copy(m)
|
|
F.b.add(F.a)
|
|
F.a.copy(t)
|
|
F.norm()
|
|
}
|
|
|
|
/* this=conjugate(this) */
|
|
func (F *FP8) conj() {
|
|
F.b.neg()
|
|
F.norm()
|
|
}
|
|
|
|
/* this=-conjugate(this) */
|
|
func (F *FP8) nconj() {
|
|
F.a.neg()
|
|
F.norm()
|
|
}
|
|
|
|
/* this+=x */
|
|
func (F *FP8) add(x *FP8) {
|
|
F.a.add(x.a)
|
|
F.b.add(x.b)
|
|
}
|
|
|
|
/* this-=x */
|
|
func (F *FP8) sub(x *FP8) {
|
|
m := NewFP8copy(x)
|
|
m.neg()
|
|
F.add(m)
|
|
}
|
|
|
|
/* this-=x */
|
|
func (F *FP8) rsub(x *FP8) {
|
|
F.neg()
|
|
F.add(x)
|
|
}
|
|
|
|
/* this*=s where s is FP4 */
|
|
func (F *FP8) pmul(s *FP4) {
|
|
F.a.mul(s)
|
|
F.b.mul(s)
|
|
}
|
|
|
|
/* this*=s where s is FP2 */
|
|
func (F *FP8) qmul(s *FP2) {
|
|
F.a.pmul(s)
|
|
F.b.pmul(s)
|
|
}
|
|
|
|
/* this*=s where s is FP */
|
|
func (F *FP8) tmul(s *FP) {
|
|
F.a.qmul(s)
|
|
F.b.qmul(s)
|
|
}
|
|
|
|
/* this*=c where c is int */
|
|
func (F *FP8) imul(c int) {
|
|
F.a.imul(c)
|
|
F.b.imul(c)
|
|
}
|
|
|
|
/* this*=this */
|
|
func (F *FP8) sqr() {
|
|
t1 := NewFP4copy(F.a)
|
|
t2 := NewFP4copy(F.b)
|
|
t3 := NewFP4copy(F.a)
|
|
|
|
t3.mul(F.b)
|
|
t1.add(F.b)
|
|
t2.times_i()
|
|
|
|
t2.add(F.a)
|
|
|
|
t1.norm()
|
|
t2.norm()
|
|
|
|
F.a.copy(t1)
|
|
F.a.mul(t2)
|
|
|
|
t2.copy(t3)
|
|
t2.times_i()
|
|
t2.add(t3)
|
|
t2.norm()
|
|
t2.neg()
|
|
F.a.add(t2)
|
|
|
|
F.b.copy(t3)
|
|
F.b.add(t3)
|
|
|
|
F.norm()
|
|
}
|
|
|
|
/* this*=y */
|
|
func (F *FP8) mul(y *FP8) {
|
|
t1 := NewFP4copy(F.a)
|
|
t2 := NewFP4copy(F.b)
|
|
t3 := NewFP4()
|
|
t4 := NewFP4copy(F.b)
|
|
|
|
t1.mul(y.a)
|
|
t2.mul(y.b)
|
|
t3.copy(y.b)
|
|
t3.add(y.a)
|
|
t4.add(F.a)
|
|
|
|
t3.norm()
|
|
t4.norm()
|
|
|
|
t4.mul(t3)
|
|
|
|
t3.copy(t1)
|
|
t3.neg()
|
|
t4.add(t3)
|
|
t4.norm()
|
|
|
|
t3.copy(t2)
|
|
t3.neg()
|
|
F.b.copy(t4)
|
|
F.b.add(t3)
|
|
|
|
t2.times_i()
|
|
F.a.copy(t2)
|
|
F.a.add(t1)
|
|
|
|
F.norm()
|
|
}
|
|
|
|
/* convert this to hex string */
|
|
func (F *FP8) toString() string {
|
|
return ("[" + F.a.toString() + "," + F.b.toString() + "]")
|
|
}
|
|
|
|
/* this=1/this */
|
|
func (F *FP8) inverse(h *FP) {
|
|
t1 := NewFP4copy(F.a)
|
|
t2 := NewFP4copy(F.b)
|
|
|
|
t1.sqr()
|
|
t2.sqr()
|
|
t2.times_i()
|
|
t2.norm()
|
|
t1.sub(t2)
|
|
t1.norm()
|
|
|
|
t1.inverse(h)
|
|
|
|
F.a.mul(t1)
|
|
t1.neg()
|
|
t1.norm()
|
|
F.b.mul(t1)
|
|
}
|
|
|
|
/* this*=i where i = sqrt(sqrt(-1+sqrt(-1))) */
|
|
func (F *FP8) times_i() {
|
|
s := NewFP4copy(F.b)
|
|
t := NewFP4copy(F.a)
|
|
s.times_i()
|
|
F.a.copy(s)
|
|
F.b.copy(t)
|
|
F.norm()
|
|
if TOWER == POSITOWER {
|
|
F.neg()
|
|
F.norm()
|
|
}
|
|
}
|
|
|
|
func (F *FP8) times_i2() {
|
|
F.a.times_i()
|
|
F.b.times_i()
|
|
}
|
|
|
|
/* this=this^p using Frobenius */
|
|
func (F *FP8) frob(f *FP2) {
|
|
ff := NewFP2copy(f)
|
|
ff.sqr()
|
|
ff.mul_ip()
|
|
ff.norm()
|
|
|
|
F.a.frob(ff)
|
|
F.b.frob(ff)
|
|
F.b.pmul(f)
|
|
F.b.times_i()
|
|
}
|
|
|
|
/* this=this^e
|
|
func (F *FP8) pow(e *BIG) *FP8 {
|
|
w := NewFP8copy(F)
|
|
w.norm()
|
|
z := NewBIGcopy(e)
|
|
r := NewFP8int(1)
|
|
z.norm()
|
|
for true {
|
|
bt := z.parity()
|
|
z.fshr(1)
|
|
if bt == 1 {
|
|
r.mul(w)
|
|
}
|
|
if z.iszilch() {
|
|
break
|
|
}
|
|
w.sqr()
|
|
}
|
|
r.reduce()
|
|
return r
|
|
} */
|
|
|
|
/* XTR xtr_a function */
|
|
/*
|
|
func (F *FP8) xtr_A(w *FP8, y *FP8, z *FP8) {
|
|
r := NewFP8copy(w)
|
|
t := NewFP8copy(w)
|
|
r.sub(y)
|
|
r.norm()
|
|
r.pmul(F.a)
|
|
t.add(y)
|
|
t.norm()
|
|
t.pmul(F.b)
|
|
t.times_i()
|
|
|
|
F.copy(r)
|
|
F.add(t)
|
|
F.add(z)
|
|
|
|
F.norm()
|
|
}
|
|
*/
|
|
/* XTR xtr_d function */
|
|
/*
|
|
func (F *FP8) xtr_D() {
|
|
w := NewFP8copy(F)
|
|
F.sqr()
|
|
w.conj()
|
|
w.add(w)
|
|
w.norm()
|
|
F.sub(w)
|
|
F.reduce()
|
|
}
|
|
*/
|
|
/* r=x^n using XTR method on traces of FP24s */
|
|
/*
|
|
func (F *FP8) xtr_pow(n *BIG) *FP8 {
|
|
a := NewFP8int(3)
|
|
b := NewFP8copy(F)
|
|
c := NewFP8copy(b)
|
|
c.xtr_D()
|
|
t := NewFP8()
|
|
r := NewFP8()
|
|
sf := NewFP8copy(F)
|
|
sf.norm()
|
|
|
|
par := n.parity()
|
|
v := NewBIGcopy(n)
|
|
v.norm()
|
|
v.fshr(1)
|
|
if par == 0 {
|
|
v.dec(1)
|
|
v.norm()
|
|
}
|
|
|
|
nb := v.nbits()
|
|
for i := nb - 1; i >= 0; i-- {
|
|
if v.bit(i) != 1 {
|
|
t.copy(b)
|
|
sf.conj()
|
|
c.conj()
|
|
b.xtr_A(a, sf, c)
|
|
sf.conj()
|
|
c.copy(t)
|
|
c.xtr_D()
|
|
a.xtr_D()
|
|
} else {
|
|
t.copy(a)
|
|
t.conj()
|
|
a.copy(b)
|
|
a.xtr_D()
|
|
b.xtr_A(c, sf, t)
|
|
c.xtr_D()
|
|
}
|
|
}
|
|
if par == 0 {
|
|
r.copy(c)
|
|
} else {
|
|
r.copy(b)
|
|
}
|
|
r.reduce()
|
|
return r
|
|
}
|
|
*/
|
|
/* r=ck^a.cl^n using XTR double exponentiation method on traces of FP24s. See Stam thesis. */
|
|
/*
|
|
func (F *FP8) xtr_pow2(ck *FP8, ckml *FP8, ckm2l *FP8, a *BIG, b *BIG) *FP8 {
|
|
|
|
e := NewBIGcopy(a)
|
|
d := NewBIGcopy(b)
|
|
w := NewBIGint(0)
|
|
e.norm()
|
|
d.norm()
|
|
cu := NewFP8copy(ck) // can probably be passed in w/o copying
|
|
cv := NewFP8copy(F)
|
|
cumv := NewFP8copy(ckml)
|
|
cum2v := NewFP8copy(ckm2l)
|
|
r := NewFP8()
|
|
t := NewFP8()
|
|
|
|
f2 := 0
|
|
for d.parity() == 0 && e.parity() == 0 {
|
|
d.fshr(1)
|
|
e.fshr(1)
|
|
f2++
|
|
}
|
|
|
|
for Comp(d, e) != 0 {
|
|
if Comp(d, e) > 0 {
|
|
w.copy(e)
|
|
w.imul(4)
|
|
w.norm()
|
|
if Comp(d, w) <= 0 {
|
|
w.copy(d)
|
|
d.copy(e)
|
|
e.rsub(w)
|
|
e.norm()
|
|
|
|
t.copy(cv)
|
|
t.xtr_A(cu, cumv, cum2v)
|
|
cum2v.copy(cumv)
|
|
cum2v.conj()
|
|
cumv.copy(cv)
|
|
cv.copy(cu)
|
|
cu.copy(t)
|
|
} else {
|
|
if d.parity() == 0 {
|
|
d.fshr(1)
|
|
r.copy(cum2v)
|
|
r.conj()
|
|
t.copy(cumv)
|
|
t.xtr_A(cu, cv, r)
|
|
cum2v.copy(cumv)
|
|
cum2v.xtr_D()
|
|
cumv.copy(t)
|
|
cu.xtr_D()
|
|
} else {
|
|
if e.parity() == 1 {
|
|
d.sub(e)
|
|
d.norm()
|
|
d.fshr(1)
|
|
t.copy(cv)
|
|
t.xtr_A(cu, cumv, cum2v)
|
|
cu.xtr_D()
|
|
cum2v.copy(cv)
|
|
cum2v.xtr_D()
|
|
cum2v.conj()
|
|
cv.copy(t)
|
|
} else {
|
|
w.copy(d)
|
|
d.copy(e)
|
|
d.fshr(1)
|
|
e.copy(w)
|
|
t.copy(cumv)
|
|
t.xtr_D()
|
|
cumv.copy(cum2v)
|
|
cumv.conj()
|
|
cum2v.copy(t)
|
|
cum2v.conj()
|
|
t.copy(cv)
|
|
t.xtr_D()
|
|
cv.copy(cu)
|
|
cu.copy(t)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if Comp(d, e) < 0 {
|
|
w.copy(d)
|
|
w.imul(4)
|
|
w.norm()
|
|
if Comp(e, w) <= 0 {
|
|
e.sub(d)
|
|
e.norm()
|
|
t.copy(cv)
|
|
t.xtr_A(cu, cumv, cum2v)
|
|
cum2v.copy(cumv)
|
|
cumv.copy(cu)
|
|
cu.copy(t)
|
|
} else {
|
|
if e.parity() == 0 {
|
|
w.copy(d)
|
|
d.copy(e)
|
|
d.fshr(1)
|
|
e.copy(w)
|
|
t.copy(cumv)
|
|
t.xtr_D()
|
|
cumv.copy(cum2v)
|
|
cumv.conj()
|
|
cum2v.copy(t)
|
|
cum2v.conj()
|
|
t.copy(cv)
|
|
t.xtr_D()
|
|
cv.copy(cu)
|
|
cu.copy(t)
|
|
} else {
|
|
if d.parity() == 1 {
|
|
w.copy(e)
|
|
e.copy(d)
|
|
w.sub(d)
|
|
w.norm()
|
|
d.copy(w)
|
|
d.fshr(1)
|
|
t.copy(cv)
|
|
t.xtr_A(cu, cumv, cum2v)
|
|
cumv.conj()
|
|
cum2v.copy(cu)
|
|
cum2v.xtr_D()
|
|
cum2v.conj()
|
|
cu.copy(cv)
|
|
cu.xtr_D()
|
|
cv.copy(t)
|
|
} else {
|
|
d.fshr(1)
|
|
r.copy(cum2v)
|
|
r.conj()
|
|
t.copy(cumv)
|
|
t.xtr_A(cu, cv, r)
|
|
cum2v.copy(cumv)
|
|
cum2v.xtr_D()
|
|
cumv.copy(t)
|
|
cu.xtr_D()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
r.copy(cv)
|
|
r.xtr_A(cu, cumv, cum2v)
|
|
for i := 0; i < f2; i++ {
|
|
r.xtr_D()
|
|
}
|
|
r = r.xtr_pow(d)
|
|
return r
|
|
}
|
|
*/
|
|
/* this/=2 */
|
|
func (F *FP8) div2() {
|
|
F.a.div2()
|
|
F.b.div2()
|
|
}
|
|
|
|
func (F *FP8) div_i() {
|
|
u := NewFP4copy(F.a)
|
|
v := NewFP4copy(F.b)
|
|
u.div_i()
|
|
F.a.copy(v)
|
|
F.b.copy(u)
|
|
if TOWER == POSITOWER {
|
|
F.neg()
|
|
F.norm()
|
|
}
|
|
}
|
|
|
|
/*
|
|
func (F *FP8) pow(b *BIG) {
|
|
w := NewFP8copy(F);
|
|
r := NewFP8int(1)
|
|
z := NewBIGcopy(b)
|
|
for true {
|
|
bt := z.parity()
|
|
z.shr(1)
|
|
if bt==1 {
|
|
r.mul(w)
|
|
}
|
|
if z.iszilch() {break}
|
|
w.sqr()
|
|
}
|
|
r.reduce();
|
|
F.copy(r);
|
|
}
|
|
*/
|
|
|
|
/* */
|
|
// Test for Quadratic Residue
|
|
func (F *FP8) qr(h *FP) int {
|
|
c := NewFP8copy(F)
|
|
c.conj()
|
|
c.mul(F)
|
|
return c.a.qr(h)
|
|
}
|
|
|
|
// sqrt(a+ib) = sqrt(a+sqrt(a*a-n*b*b)/2)+ib/(2*sqrt(a+sqrt(a*a-n*b*b)/2))
|
|
func (F *FP8) sqrt(h *FP) {
|
|
if F.iszilch() {
|
|
return
|
|
}
|
|
|
|
a := NewFP4copy(F.a)
|
|
b := NewFP4()
|
|
s := NewFP4copy(F.b)
|
|
t := NewFP4copy(F.a)
|
|
hint := NewFP()
|
|
|
|
s.sqr()
|
|
a.sqr()
|
|
s.times_i()
|
|
s.norm()
|
|
a.sub(s)
|
|
|
|
s.copy(a)
|
|
s.norm()
|
|
|
|
s.sqrt(h)
|
|
a.copy(t)
|
|
b.copy(t)
|
|
|
|
a.add(s)
|
|
a.norm()
|
|
a.div2()
|
|
|
|
b.copy(F.b)
|
|
b.div2()
|
|
qr := a.qr(hint)
|
|
|
|
// tweak hint - multiply old hint by Norm(1/Beta)^e where Beta is irreducible polynomial
|
|
s.copy(a)
|
|
twk := NewFPbig(NewBIGints(TWK))
|
|
twk.mul(hint)
|
|
s.div_i()
|
|
s.norm()
|
|
|
|
a.cmove(s, 1-qr)
|
|
hint.cmove(twk, 1-qr)
|
|
|
|
F.a.copy(a)
|
|
F.a.sqrt(hint)
|
|
s.copy(a)
|
|
s.inverse(hint)
|
|
s.mul(F.a)
|
|
F.b.copy(s)
|
|
F.b.mul(b)
|
|
t.copy(F.a)
|
|
|
|
F.a.cmove(F.b, 1-qr)
|
|
F.b.cmove(t, 1-qr)
|
|
|
|
sgn := F.sign()
|
|
nr := NewFP8copy(F)
|
|
nr.neg()
|
|
nr.norm()
|
|
F.cmove(nr, sgn)
|
|
}
|
|
|
|
/* */
|