go-snark/fields/fq.go
fields/fq.goRaw
1package fields
2
3import (
4 "bytes"
5 "crypto/rand"
6 "math/big"
7)
8
9// Fq is the Z field over modulus Q
10type Fq struct {
11 Q *big.Int // Q
12}
13
14// NewFq generates a new Fq
15func NewFq(q *big.Int) Fq {
16 return Fq{
17 q,
18 }
19}
20
21// Zero returns a Zero value on the Fq
22func (fq Fq) Zero() *big.Int {
23 return big.NewInt(int64(0))
24}
25
26// One returns a One value on the Fq
27func (fq Fq) One() *big.Int {
28 return big.NewInt(int64(1))
29}
30
31// Add performs an addition on the Fq
32func (fq Fq) Add(a, b *big.Int) *big.Int {
33 r := new(big.Int).Add(a, b)
34 return new(big.Int).Mod(r, fq.Q)
35}
36
37// Double performs a doubling on the Fq
38func (fq Fq) Double(a *big.Int) *big.Int {
39 r := new(big.Int).Add(a, a)
40 return new(big.Int).Mod(r, fq.Q)
41}
42
43// Sub performs a subtraction on the Fq
44func (fq Fq) Sub(a, b *big.Int) *big.Int {
45 r := new(big.Int).Sub(a, b)
46 return new(big.Int).Mod(r, fq.Q)
47}
48
49// Neg performs a negation on the Fq
50func (fq Fq) Neg(a *big.Int) *big.Int {
51 m := new(big.Int).Neg(a)
52 return new(big.Int).Mod(m, fq.Q)
53}
54
55// Mul performs a multiplication on the Fq
56func (fq Fq) Mul(a, b *big.Int) *big.Int {
57 m := new(big.Int).Mul(a, b)
58 return new(big.Int).Mod(m, fq.Q)
59}
60
61func (fq Fq) MulScalar(base, e *big.Int) *big.Int {
62 return fq.Mul(base, e)
63}
64
65// Inverse returns the inverse on the Fq
66func (fq Fq) Inverse(a *big.Int) *big.Int {
67 return new(big.Int).ModInverse(a, fq.Q)
68 // q := bigCopy(fq.Q)
69 // t := big.NewInt(int64(0))
70 // r := fq.Q
71 // newt := big.NewInt(int64(0))
72 // newr := fq.Affine(a)
73 // for !bytes.Equal(newr.Bytes(), big.NewInt(int64(0)).Bytes()) {
74 // q := new(big.Int).Div(bigCopy(r), bigCopy(newr))
75 //
76 // t = bigCopy(newt)
77 // newt = fq.Sub(t, fq.Mul(q, newt))
78 //
79 // r = bigCopy(newr)
80 // newr = fq.Sub(r, fq.Mul(q, newr))
81 // }
82 // if t.Cmp(big.NewInt(0)) == -1 { // t< 0
83 // t = fq.Add(t, q)
84 // }
85 // return t
86}
87
88// Div performs the division over the finite field
89func (fq Fq) Div(a, b *big.Int) *big.Int {
90 d := fq.Mul(a, fq.Inverse(b))
91 return new(big.Int).Mod(d, fq.Q)
92}
93
94// Square performs a square operation on the Fq
95func (fq Fq) Square(a *big.Int) *big.Int {
96 m := new(big.Int).Mul(a, a)
97 return new(big.Int).Mod(m, fq.Q)
98}
99
100// Exp performs the exponential over Fq
101func (fq Fq) Exp(base *big.Int, e *big.Int) *big.Int {
102 res := fq.One()
103 rem := fq.Copy(e)
104 exp := base
105
106 for !bytes.Equal(rem.Bytes(), big.NewInt(int64(0)).Bytes()) {
107 if BigIsOdd(rem) {
108 res = fq.Mul(res, exp)
109 }
110 exp = fq.Square(exp)
111 rem = new(big.Int).Rsh(rem, 1)
112 }
113 return res
114}
115
116func (fq Fq) Rand() (*big.Int, error) {
117
118 // twoexp := new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(maxbits)), nil)
119 // max := new(big.Int).Sub(twoexp, big.NewInt(1))
120
121 maxbits := fq.Q.BitLen()
122 b := make([]byte, (maxbits/8)-1)
123 _, err := rand.Read(b)
124 if err != nil {
125 return nil, err
126 }
127 r := new(big.Int).SetBytes(b)
128 rq := new(big.Int).Mod(r, fq.Q)
129
130 // r over q, nil
131 return rq, nil
132}
133
134func (fq Fq) IsZero(a *big.Int) bool {
135 return bytes.Equal(a.Bytes(), fq.Zero().Bytes())
136}
137
138func (fq Fq) Copy(a *big.Int) *big.Int {
139 return new(big.Int).SetBytes(a.Bytes())
140}
141
142func (fq Fq) Affine(a *big.Int) *big.Int {
143 nq := fq.Neg(fq.Q)
144
145 aux := a
146 if aux.Cmp(big.NewInt(int64(0))) == -1 { // negative value
147 if aux.Cmp(nq) != 1 { // aux less or equal nq
148 aux = new(big.Int).Mod(aux, fq.Q)
149 }
150 if aux.Cmp(big.NewInt(int64(0))) == -1 { // negative value
151 aux = new(big.Int).Add(aux, fq.Q)
152 }
153 } else {
154 if aux.Cmp(fq.Q) != -1 { // aux greater or equal nq
155 aux = new(big.Int).Mod(aux, fq.Q)
156 }
157 }
158 return aux
159}
160
161func (fq Fq) Equal(a, b *big.Int) bool {
162 aAff := fq.Affine(a)
163 bAff := fq.Affine(b)
164 return bytes.Equal(aAff.Bytes(), bAff.Bytes())
165}
166
167func BigIsOdd(n *big.Int) bool {
168 one := big.NewInt(int64(1))
169 and := new(big.Int).And(n, one)
170 return bytes.Equal(and.Bytes(), big.NewInt(int64(1)).Bytes())
171}