mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-27 00:55:17 +00:00
569 lines
13 KiB
Go
569 lines
13 KiB
Go
//
|
||
// Copyright (c) 2019 harmony-one
|
||
//
|
||
// SPDX-License-Identifier: MIT
|
||
//
|
||
|
||
package iqc
|
||
|
||
import (
|
||
"math/big"
|
||
)
|
||
|
||
type ClassGroup struct {
|
||
a *big.Int
|
||
b *big.Int
|
||
c *big.Int
|
||
d *big.Int
|
||
}
|
||
|
||
func NewClassGroup(a, b, c *big.Int) *ClassGroup {
|
||
return &ClassGroup{a: a, b: b, c: c}
|
||
}
|
||
|
||
func (cg *ClassGroup) Clone() *ClassGroup {
|
||
return &ClassGroup{a: cg.a, b: cg.b, c: cg.c}
|
||
}
|
||
|
||
func NewClassGroupFromAbDiscriminant(a, b, discriminant *big.Int) *ClassGroup {
|
||
//z = b*b-discriminant
|
||
z := new(big.Int).Sub(new(big.Int).Mul(b, b), discriminant)
|
||
|
||
//z = z // 4a
|
||
c := FloorDivision(z, new(big.Int).Mul(a, big.NewInt(4)))
|
||
|
||
return NewClassGroup(a, b, c)
|
||
}
|
||
|
||
func NewClassGroupFromBytesDiscriminant(buf []byte, discriminant *big.Int) (*ClassGroup, bool) {
|
||
int_size_bits := discriminant.BitLen()
|
||
|
||
//add additional one byte for sign
|
||
int_size := (int_size_bits + 16) >> 4
|
||
|
||
//make sure the input byte buffer size matches with discriminant's
|
||
if len(buf) != int_size*2 {
|
||
return nil, false
|
||
}
|
||
|
||
a := decodeTwosComplement(buf[:int_size])
|
||
b := decodeTwosComplement(buf[int_size:])
|
||
|
||
return NewClassGroupFromAbDiscriminant(a, b, discriminant), true
|
||
}
|
||
|
||
func IdentityForDiscriminant(d *big.Int) *ClassGroup {
|
||
return NewClassGroupFromAbDiscriminant(big.NewInt(1), big.NewInt(1), d)
|
||
}
|
||
|
||
func (group *ClassGroup) Normalized() *ClassGroup {
|
||
a := new(big.Int).Set(group.a)
|
||
b := new(big.Int).Set(group.b)
|
||
c := new(big.Int).Set(group.c)
|
||
|
||
//if b > -a && b <= a:
|
||
if (b.Cmp(new(big.Int).Neg(a)) == 1) && (b.Cmp(a) < 1) {
|
||
return group
|
||
}
|
||
|
||
//r = (a - b) // (2 * a)
|
||
r := new(big.Int).Sub(a, b)
|
||
r = FloorDivision(r, new(big.Int).Mul(a, big.NewInt(2)))
|
||
|
||
//b, c = b + 2 * r * a, a * r * r + b * r + c
|
||
t := new(big.Int).Mul(big.NewInt(2), r)
|
||
t.Mul(t, a)
|
||
oldB := new(big.Int).Set(b)
|
||
b.Add(b, t)
|
||
|
||
x := new(big.Int).Mul(a, r)
|
||
x.Mul(x, r)
|
||
y := new(big.Int).Mul(oldB, r)
|
||
c.Add(c, x)
|
||
c.Add(c, y)
|
||
|
||
return NewClassGroup(a, b, c)
|
||
}
|
||
|
||
func (group *ClassGroup) Reduced() *ClassGroup {
|
||
g := group.Normalized()
|
||
a := new(big.Int).Set(g.a)
|
||
b := new(big.Int).Set(g.b)
|
||
c := new(big.Int).Set(g.c)
|
||
|
||
//while a > c or (a == c and b < 0):
|
||
for (a.Cmp(c) == 1) || ((a.Cmp(c) == 0) && (b.Sign() == -1)) {
|
||
//s = (c + b) // (c + c)
|
||
s := new(big.Int).Add(c, b)
|
||
s = FloorDivision(s, new(big.Int).Add(c, c))
|
||
|
||
//a, b, c = c, -b + 2 * s * c, c * s * s - b * s + a
|
||
oldA := new(big.Int).Set(a)
|
||
oldB := new(big.Int).Set(b)
|
||
a = new(big.Int).Set(c)
|
||
|
||
b.Neg(b)
|
||
x := new(big.Int).Mul(big.NewInt(2), s)
|
||
x.Mul(x, c)
|
||
b.Add(b, x)
|
||
|
||
c.Mul(c, s)
|
||
c.Mul(c, s)
|
||
oldB.Mul(oldB, s)
|
||
c.Sub(c, oldB)
|
||
c.Add(c, oldA)
|
||
}
|
||
|
||
return NewClassGroup(a, b, c).Normalized()
|
||
}
|
||
|
||
func (group *ClassGroup) identity() *ClassGroup {
|
||
return NewClassGroupFromAbDiscriminant(big.NewInt(1), big.NewInt(1), group.Discriminant())
|
||
}
|
||
|
||
func (group *ClassGroup) Discriminant() *big.Int {
|
||
if group.d == nil {
|
||
d := new(big.Int).Set(group.b)
|
||
d.Mul(d, d)
|
||
a := new(big.Int).Set(group.a)
|
||
a.Mul(a, group.c)
|
||
a.Mul(a, big.NewInt(4))
|
||
d.Sub(d, a)
|
||
|
||
group.d = d
|
||
}
|
||
return group.d
|
||
}
|
||
|
||
func (group *ClassGroup) Multiply(other *ClassGroup) *ClassGroup {
|
||
//a1, b1, c1 = self.reduced()
|
||
x := group.Reduced()
|
||
|
||
//a2, b2, c2 = other.reduced()
|
||
y := other.Reduced()
|
||
|
||
//g = (b2 + b1) // 2
|
||
g := new(big.Int).Add(x.b, y.b)
|
||
g = FloorDivision(g, big.NewInt(2))
|
||
|
||
//h = (b2 - b1) // 2
|
||
h := new(big.Int).Sub(y.b, x.b)
|
||
h = FloorDivision(h, big.NewInt(2))
|
||
|
||
//w = mod.gcd(a1, a2, g)
|
||
w1 := allInputValueGCD(y.a, g)
|
||
w := allInputValueGCD(x.a, w1)
|
||
|
||
//j = w
|
||
j := new(big.Int).Set(w)
|
||
//r = 0
|
||
r := big.NewInt(0)
|
||
//s = a1 // w
|
||
s := FloorDivision(x.a, w)
|
||
//t = a2 // w
|
||
t := FloorDivision(y.a, w)
|
||
//u = g // w
|
||
u := FloorDivision(g, w)
|
||
|
||
//k_temp, constant_factor = mod.solve_mod(t * u, h * u + s * c1, s * t)
|
||
b := new(big.Int).Mul(h, u)
|
||
sc := new(big.Int).Mul(s, x.c)
|
||
b.Add(b, sc)
|
||
k_temp, constant_factor, solvable := SolveMod(new(big.Int).Mul(t, u), b, new(big.Int).Mul(s, t))
|
||
if !solvable {
|
||
return nil
|
||
}
|
||
|
||
//n, constant_factor_2 = mod.solve_mod(t * constant_factor, h - t * k_temp, s)
|
||
n, _, solvable := SolveMod(new(big.Int).Mul(t, constant_factor), new(big.Int).Sub(h, new(big.Int).Mul(t, k_temp)), s)
|
||
if !solvable {
|
||
return nil
|
||
}
|
||
|
||
//k = k_temp + constant_factor * n
|
||
k := new(big.Int).Add(k_temp, new(big.Int).Mul(constant_factor, n))
|
||
|
||
//l = (t * k - h) // s
|
||
l := FloorDivision(new(big.Int).Sub(new(big.Int).Mul(t, k), h), s)
|
||
|
||
//m = (t * u * k - h * u - s * c1) // (s * t)
|
||
tuk := new(big.Int).Mul(t, u)
|
||
tuk.Mul(tuk, k)
|
||
|
||
hu := new(big.Int).Mul(h, u)
|
||
|
||
tuk.Sub(tuk, hu)
|
||
tuk.Sub(tuk, sc)
|
||
|
||
st := new(big.Int).Mul(s, t)
|
||
m := FloorDivision(tuk, st)
|
||
|
||
//a3 = s * t - r * u
|
||
ru := new(big.Int).Mul(r, u)
|
||
a3 := st.Sub(st, ru)
|
||
|
||
//b3 = (j * u + m * r) - (k * t + l * s)
|
||
ju := new(big.Int).Mul(j, u)
|
||
mr := new(big.Int).Mul(m, r)
|
||
ju = ju.Add(ju, mr)
|
||
|
||
kt := new(big.Int).Mul(k, t)
|
||
ls := new(big.Int).Mul(l, s)
|
||
kt = kt.Add(kt, ls)
|
||
|
||
b3 := ju.Sub(ju, kt)
|
||
|
||
//c3 = k * l - j * m
|
||
kl := new(big.Int).Mul(k, l)
|
||
jm := new(big.Int).Mul(j, m)
|
||
|
||
c3 := kl.Sub(kl, jm)
|
||
return NewClassGroup(a3, b3, c3).Reduced()
|
||
}
|
||
|
||
func (group *ClassGroup) Pow(n int64) *ClassGroup {
|
||
x := group.Clone()
|
||
items_prod := group.identity()
|
||
|
||
for n > 0 {
|
||
if n&1 == 1 {
|
||
items_prod = items_prod.Multiply(x)
|
||
if items_prod == nil {
|
||
return nil
|
||
}
|
||
}
|
||
x = x.Square()
|
||
if x == nil {
|
||
return nil
|
||
}
|
||
n >>= 1
|
||
}
|
||
return items_prod
|
||
}
|
||
|
||
func (group *ClassGroup) BigPow(n *big.Int) *ClassGroup {
|
||
x := group.Clone()
|
||
items_prod := group.identity()
|
||
|
||
p := new(big.Int).Set(n)
|
||
for p.Sign() > 0 {
|
||
if p.Bit(0) == 1 {
|
||
items_prod = items_prod.Multiply(x)
|
||
if items_prod == nil {
|
||
return nil
|
||
}
|
||
}
|
||
x = x.Square()
|
||
if x == nil {
|
||
return nil
|
||
}
|
||
p.Rsh(p, 1)
|
||
}
|
||
return items_prod
|
||
}
|
||
|
||
func (group *ClassGroup) Square() *ClassGroup {
|
||
u, _, solvable := SolveMod(group.b, group.c, group.a)
|
||
if !solvable {
|
||
return nil
|
||
}
|
||
|
||
//A = a
|
||
A := new(big.Int).Mul(group.a, group.a)
|
||
|
||
//B = b − 2aµ,
|
||
au := new(big.Int).Mul(group.a, u)
|
||
B := new(big.Int).Sub(group.b, new(big.Int).Mul(au, big.NewInt(2)))
|
||
|
||
//C = µ ^ 2 - (bµ−c)//a
|
||
C := new(big.Int).Mul(u, u)
|
||
m := new(big.Int).Mul(group.b, u)
|
||
m = new(big.Int).Sub(m, group.c)
|
||
m = FloorDivision(m, group.a)
|
||
C = new(big.Int).Sub(C, m)
|
||
|
||
return NewClassGroup(A, B, C).Reduced()
|
||
}
|
||
|
||
func (group *ClassGroup) SquareUsingMultiply() *ClassGroup {
|
||
//a1, b1, c1 = self.reduced()
|
||
x := group.Reduced()
|
||
|
||
//g = b1
|
||
g := x.b
|
||
//h = 0
|
||
h := big.NewInt(0)
|
||
|
||
//w = mod.gcd(a1, g)
|
||
w := allInputValueGCD(x.a, g)
|
||
|
||
//j = w
|
||
j := new(big.Int).Set(w)
|
||
//r = 0
|
||
r := big.NewInt(0)
|
||
//s = a1 // w
|
||
s := FloorDivision(x.a, w)
|
||
//t = s
|
||
t := s
|
||
//u = g // w
|
||
u := FloorDivision(g, w)
|
||
|
||
//k_temp, constant_factor = mod.solve_mod(t * u, h * u + s * c1, s * t)
|
||
b := new(big.Int).Mul(h, u)
|
||
sc := new(big.Int).Mul(s, x.c)
|
||
b.Add(b, sc)
|
||
k_temp, constant_factor, solvable := SolveMod(new(big.Int).Mul(t, u), b, new(big.Int).Mul(s, t))
|
||
if !solvable {
|
||
return nil
|
||
}
|
||
|
||
//n, constant_factor_2 = mod.solve_mod(t * constant_factor, h - t * k_temp, s)
|
||
n, _, solvable := SolveMod(new(big.Int).Mul(t, constant_factor), new(big.Int).Sub(h, new(big.Int).Mul(t, k_temp)), s)
|
||
if !solvable {
|
||
return nil
|
||
}
|
||
|
||
//k = k_temp + constant_factor * n
|
||
k := new(big.Int).Add(k_temp, new(big.Int).Mul(constant_factor, n))
|
||
|
||
//l = (t * k - h) // s
|
||
l := FloorDivision(new(big.Int).Sub(new(big.Int).Mul(t, k), h), s)
|
||
|
||
//m = (t * u * k - h * u - s * c1) // (s * t)
|
||
tuk := new(big.Int).Mul(t, u)
|
||
tuk.Mul(tuk, k)
|
||
|
||
hu := new(big.Int).Mul(h, u)
|
||
|
||
tuk.Sub(tuk, hu)
|
||
tuk.Sub(tuk, sc)
|
||
|
||
st := new(big.Int).Mul(s, t)
|
||
m := FloorDivision(tuk, st)
|
||
|
||
//a3 = s * t - r * u
|
||
ru := new(big.Int).Mul(r, u)
|
||
a3 := st.Sub(st, ru)
|
||
|
||
//b3 = (j * u + m * r) - (k * t + l * s)
|
||
ju := new(big.Int).Mul(j, u)
|
||
mr := new(big.Int).Mul(m, r)
|
||
ju = ju.Add(ju, mr)
|
||
|
||
kt := new(big.Int).Mul(k, t)
|
||
ls := new(big.Int).Mul(l, s)
|
||
kt = kt.Add(kt, ls)
|
||
|
||
b3 := ju.Sub(ju, kt)
|
||
|
||
//c3 = k * l - j * m
|
||
kl := new(big.Int).Mul(k, l)
|
||
jm := new(big.Int).Mul(j, m)
|
||
|
||
c3 := kl.Sub(kl, jm)
|
||
|
||
return NewClassGroup(a3, b3, c3).Reduced()
|
||
}
|
||
|
||
// Serialize encodes a, b based on discriminant's size
|
||
// using one more byte for sign if nessesary
|
||
func (group *ClassGroup) Serialize() []byte {
|
||
r := group.Reduced()
|
||
int_size_bits := group.Discriminant().BitLen()
|
||
int_size := (int_size_bits + 16) >> 4
|
||
|
||
buf := make([]byte, int_size*2)
|
||
copy(buf[:int_size], signBitFill(encodeTwosComplement(r.a), int_size))
|
||
copy(buf[int_size:], signBitFill(encodeTwosComplement(r.b), int_size))
|
||
|
||
return buf
|
||
}
|
||
|
||
func (group *ClassGroup) Equal(other *ClassGroup) bool {
|
||
g := group.Reduced()
|
||
o := other.Reduced()
|
||
|
||
return (g.a.Cmp(o.a) == 0 && g.b.Cmp(o.b) == 0 && g.c.Cmp(o.c) == 0)
|
||
}
|
||
|
||
func FloorDivision(x, y *big.Int) *big.Int {
|
||
var r big.Int
|
||
q, _ := new(big.Int).QuoRem(x, y, &r)
|
||
|
||
if (r.Sign() == 1 && y.Sign() == -1) || (r.Sign() == -1 && y.Sign() == 1) {
|
||
q.Sub(q, big.NewInt(1))
|
||
}
|
||
|
||
return q
|
||
}
|
||
|
||
var bigOne = big.NewInt(1)
|
||
|
||
func decodeTwosComplement(bytes []byte) *big.Int {
|
||
if bytes[0]&0x80 == 0 {
|
||
// non-negative
|
||
return new(big.Int).SetBytes(bytes)
|
||
}
|
||
setyb := make([]byte, len(bytes))
|
||
for i := range bytes {
|
||
setyb[i] = bytes[i] ^ 0xff
|
||
}
|
||
n := new(big.Int).SetBytes(setyb)
|
||
return n.Sub(n.Neg(n), bigOne)
|
||
}
|
||
|
||
func encodeTwosComplement(n *big.Int) []byte {
|
||
if n.Sign() > 0 {
|
||
bytes := n.Bytes()
|
||
if bytes[0]&0x80 == 0 {
|
||
return bytes
|
||
}
|
||
// add one more byte for positive sign
|
||
buf := make([]byte, len(bytes)+1)
|
||
copy(buf[1:], bytes)
|
||
return buf
|
||
}
|
||
if n.Sign() < 0 {
|
||
// A negative number has to be converted to two's-complement form. So we
|
||
// invert and subtract 1. If the most-significant-bit isn't set then
|
||
// we'll need to pad the beginning with 0xff in order to keep the number
|
||
// negative.
|
||
nMinus1 := new(big.Int).Neg(n)
|
||
nMinus1.Sub(nMinus1, bigOne)
|
||
bytes := nMinus1.Bytes()
|
||
if len(bytes) == 0 {
|
||
// sneaky -1 value
|
||
return []byte{0xff}
|
||
}
|
||
for i := range bytes {
|
||
bytes[i] ^= 0xff
|
||
}
|
||
if bytes[0]&0x80 != 0 {
|
||
return bytes
|
||
}
|
||
// add one more byte for negative sign
|
||
buf := make([]byte, len(bytes)+1)
|
||
buf[0] = 0xff
|
||
copy(buf[1:], bytes)
|
||
return buf
|
||
}
|
||
return []byte{}
|
||
}
|
||
|
||
func signBitFill(bytes []byte, targetLen int) []byte {
|
||
if len(bytes) >= targetLen {
|
||
return bytes
|
||
}
|
||
buf := make([]byte, targetLen)
|
||
offset := targetLen - len(bytes)
|
||
if bytes[0]&0x80 != 0 {
|
||
for i := 0; i < offset; i++ {
|
||
buf[i] = 0xff
|
||
}
|
||
}
|
||
copy(buf[offset:], bytes)
|
||
return buf
|
||
}
|
||
|
||
func EncodeBigIntBigEndian(a *big.Int) []byte {
|
||
int_size_bits := a.BitLen()
|
||
int_size := (int_size_bits + 16) >> 3
|
||
|
||
return signBitFill(encodeTwosComplement(a), int_size)
|
||
}
|
||
|
||
//Return r, s, t such that gcd(a, b) = r = a * s + b * t
|
||
func extendedGCD(a, b *big.Int) (r, s, t *big.Int) {
|
||
//r0, r1 = a, b
|
||
r0 := new(big.Int).Set(a)
|
||
r1 := new(big.Int).Set(b)
|
||
|
||
//s0, s1, t0, t1 = 1, 0, 0, 1
|
||
s0 := big.NewInt(1)
|
||
s1 := big.NewInt(0)
|
||
t0 := big.NewInt(0)
|
||
t1 := big.NewInt(1)
|
||
|
||
//if r0 > r1:
|
||
//r0, r1, s0, s1, t0, t1 = r1, r0, t0, t1, s0, s1
|
||
if r0.Cmp(r1) == 1 {
|
||
oldR0 := new(big.Int).Set(r0)
|
||
r0 = r1
|
||
r1 = oldR0
|
||
oldS0 := new(big.Int).Set(s0)
|
||
s0 = t0
|
||
oldS1 := new(big.Int).Set(s1)
|
||
s1 = t1
|
||
t0 = oldS0
|
||
t1 = oldS1
|
||
}
|
||
|
||
//while r1 > 0:
|
||
for r1.Sign() == 1 {
|
||
//q, r = divmod(r0, r1)
|
||
r := big.NewInt(1)
|
||
bb := new(big.Int).Set(b)
|
||
q, r := bb.DivMod(r0, r1, r)
|
||
|
||
//r0, r1, s0, s1, t0, t1 = r1, r, s1, s0 - q * s1, t1, t0 - q * t1
|
||
r0 = r1
|
||
r1 = r
|
||
oldS0 := new(big.Int).Set(s0)
|
||
s0 = s1
|
||
s1 = new(big.Int).Sub(oldS0, new(big.Int).Mul(q, s1))
|
||
oldT0 := new(big.Int).Set(t0)
|
||
t0 = t1
|
||
t1 = new(big.Int).Sub(oldT0, new(big.Int).Mul(q, t1))
|
||
|
||
}
|
||
return r0, s0, t0
|
||
}
|
||
|
||
//wrapper around big.Int GCD to allow all input values for GCD
|
||
//as Golang big.Int GCD requires both a, b > 0
|
||
//If a == b == 0, GCD sets r = 0.
|
||
//If a == 0 and b != 0, GCD sets r = |b|
|
||
//If a != 0 and b == 0, GCD sets r = |a|
|
||
//Otherwise r = GCD(|a|, |b|)
|
||
func allInputValueGCD(a, b *big.Int) (r *big.Int) {
|
||
if a.Sign() == 0 {
|
||
return new(big.Int).Abs(b)
|
||
}
|
||
|
||
if b.Sign() == 0 {
|
||
return new(big.Int).Abs(a)
|
||
}
|
||
|
||
return new(big.Int).GCD(nil, nil, new(big.Int).Abs(a), new(big.Int).Abs(b))
|
||
}
|
||
|
||
//Solve ax == b mod m for x.
|
||
//Return s, t where x = s + k * t for integer k yields all solutions.
|
||
func SolveMod(a, b, m *big.Int) (s, t *big.Int, solvable bool) {
|
||
//g, d, e = extended_gcd(a, m)
|
||
//TODO: golang 1.x big.int GCD requires both a > 0 and m > 0, so we can't use it :(
|
||
//d := big.NewInt(0)
|
||
//e := big.NewInt(0)
|
||
//g := new(big.Int).GCD(d, e, a, m)
|
||
g, d, _ := extendedGCD(a, m)
|
||
|
||
//q, r = divmod(b, g)
|
||
r := big.NewInt(1)
|
||
bb := new(big.Int).Set(b)
|
||
q, r := bb.DivMod(b, g, r)
|
||
|
||
//TODO: replace with utils.GetLogInstance().Error(...)
|
||
//if r != 0:
|
||
if r.Cmp(big.NewInt(0)) != 0 {
|
||
//panic(fmt.Sprintf("no solution to %s x = %s mod %s", a.String(), b.String(), m.String()))
|
||
return nil, nil, false
|
||
}
|
||
|
||
//assert b == q * g
|
||
//return (q * d) % m, m // g
|
||
q.Mul(q, d)
|
||
s = q.Mod(q, m)
|
||
t = FloorDivision(m, g)
|
||
return s, t, true
|
||
}
|