// code originally taken from https://github.com/arnaucube/go-snark (https://github.com/arnaucube/go-snark/blob/master/fields/fq.go), pasted here to ensure compatibility among future changes
|
|
|
|
package field
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/rand"
|
|
"math/big"
|
|
)
|
|
|
|
// Fq is the Z field over modulus Q
|
|
type Fq struct {
|
|
Q *big.Int // Q
|
|
}
|
|
|
|
// NewFq generates a new Fq
|
|
func NewFq(q *big.Int) Fq {
|
|
return Fq{
|
|
q,
|
|
}
|
|
}
|
|
|
|
// Zero returns a Zero value on the Fq
|
|
func (fq Fq) Zero() *big.Int {
|
|
return big.NewInt(int64(0))
|
|
}
|
|
|
|
// One returns a One value on the Fq
|
|
func (fq Fq) One() *big.Int {
|
|
return big.NewInt(int64(1))
|
|
}
|
|
|
|
// Add performs an addition on the Fq
|
|
func (fq Fq) Add(a, b *big.Int) *big.Int {
|
|
r := new(big.Int).Add(a, b)
|
|
return new(big.Int).Mod(r, fq.Q)
|
|
}
|
|
|
|
// Double performs a doubling on the Fq
|
|
func (fq Fq) Double(a *big.Int) *big.Int {
|
|
r := new(big.Int).Add(a, a)
|
|
return new(big.Int).Mod(r, fq.Q)
|
|
}
|
|
|
|
// Sub performs a subtraction on the Fq
|
|
func (fq Fq) Sub(a, b *big.Int) *big.Int {
|
|
r := new(big.Int).Sub(a, b)
|
|
return new(big.Int).Mod(r, fq.Q)
|
|
}
|
|
|
|
// Neg performs a negation on the Fq
|
|
func (fq Fq) Neg(a *big.Int) *big.Int {
|
|
m := new(big.Int).Neg(a)
|
|
return new(big.Int).Mod(m, fq.Q)
|
|
}
|
|
|
|
// Mul performs a multiplication on the Fq
|
|
func (fq Fq) Mul(a, b *big.Int) *big.Int {
|
|
m := new(big.Int).Mul(a, b)
|
|
return new(big.Int).Mod(m, fq.Q)
|
|
}
|
|
|
|
func (fq Fq) MulScalar(base, e *big.Int) *big.Int {
|
|
return fq.Mul(base, e)
|
|
}
|
|
|
|
// Inverse returns the inverse on the Fq
|
|
func (fq Fq) Inverse(a *big.Int) *big.Int {
|
|
return new(big.Int).ModInverse(a, fq.Q)
|
|
}
|
|
|
|
// Div performs the division over the finite field
|
|
func (fq Fq) Div(a, b *big.Int) *big.Int {
|
|
d := fq.Mul(a, fq.Inverse(b))
|
|
return new(big.Int).Mod(d, fq.Q)
|
|
}
|
|
|
|
// Square performs a square operation on the Fq
|
|
func (fq Fq) Square(a *big.Int) *big.Int {
|
|
m := new(big.Int).Mul(a, a)
|
|
return new(big.Int).Mod(m, fq.Q)
|
|
}
|
|
|
|
// Exp performs the exponential over Fq
|
|
func (fq Fq) Exp(base *big.Int, e *big.Int) *big.Int {
|
|
res := fq.One()
|
|
rem := fq.Copy(e)
|
|
exp := base
|
|
|
|
for !bytes.Equal(rem.Bytes(), big.NewInt(int64(0)).Bytes()) {
|
|
if BigIsOdd(rem) {
|
|
res = fq.Mul(res, exp)
|
|
}
|
|
exp = fq.Square(exp)
|
|
rem = new(big.Int).Rsh(rem, 1)
|
|
}
|
|
return res
|
|
}
|
|
|
|
func (fq Fq) Rand() (*big.Int, error) {
|
|
|
|
maxbits := fq.Q.BitLen()
|
|
b := make([]byte, (maxbits/8)-1)
|
|
_, err := rand.Read(b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
r := new(big.Int).SetBytes(b)
|
|
rq := new(big.Int).Mod(r, fq.Q)
|
|
|
|
// r over q, nil
|
|
return rq, nil
|
|
}
|
|
|
|
func (fq Fq) IsZero(a *big.Int) bool {
|
|
return bytes.Equal(a.Bytes(), fq.Zero().Bytes())
|
|
}
|
|
|
|
func (fq Fq) Copy(a *big.Int) *big.Int {
|
|
return new(big.Int).SetBytes(a.Bytes())
|
|
}
|
|
|
|
func (fq Fq) Affine(a *big.Int) *big.Int {
|
|
nq := fq.Neg(fq.Q)
|
|
|
|
aux := a
|
|
if aux.Cmp(big.NewInt(int64(0))) == -1 { // negative value
|
|
if aux.Cmp(nq) != 1 { // aux less or equal nq
|
|
aux = new(big.Int).Mod(aux, fq.Q)
|
|
}
|
|
if aux.Cmp(big.NewInt(int64(0))) == -1 { // negative value
|
|
aux = new(big.Int).Add(aux, fq.Q)
|
|
}
|
|
} else {
|
|
if aux.Cmp(fq.Q) != -1 { // aux greater or equal nq
|
|
aux = new(big.Int).Mod(aux, fq.Q)
|
|
}
|
|
}
|
|
return aux
|
|
}
|
|
|
|
func (fq Fq) Equal(a, b *big.Int) bool {
|
|
aAff := fq.Affine(a)
|
|
bAff := fq.Affine(b)
|
|
return bytes.Equal(aAff.Bytes(), bAff.Bytes())
|
|
}
|
|
|
|
func BigIsOdd(n *big.Int) bool {
|
|
one := big.NewInt(int64(1))
|
|
and := new(big.Int).And(n, one)
|
|
return bytes.Equal(and.Bytes(), big.NewInt(int64(1)).Bytes())
|
|
}
|