mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-11-14 12:15:18 +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
|
|||
|
}
|