-
Notifications
You must be signed in to change notification settings - Fork 136
/
fq.go
115 lines (99 loc) · 2.51 KB
/
fq.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package fourq
import (
"crypto/subtle"
"math/big"
)
// Fq implements operations of a field of size q=p^2 as a quadratic
// extension of the base field where i^2=-1.
// An element in Fq is represented as f[0]+f[1]*i, where f[0],f[1] are in Fp.
type Fq [2]Fp
func (e *Fq) String() string { return e[1].String() + " *i+ " + e[0].String() }
func (e *Fq) toBigInt() (f0, f1 *big.Int) { return e[0].toBigInt(), e[1].toBigInt() }
func (e *Fq) setBigInt(f0, f1 *big.Int) { e[0].setBigInt(f0); e[1].setBigInt(f1) }
func (e *Fq) setZero() { var z Fp; e[0] = z; e[1] = z }
func (e *Fq) setOne() { e.setZero(); e[0][0] = 1 }
func (e *Fq) isZero() bool { return e[0].isZero() && e[1].isZero() }
func (e *Fq) toBytes(buf []byte) {
if len(buf) == 2*SizeFp {
e[0].toBytes(buf[:SizeFp])
e[1].toBytes(buf[SizeFp:])
}
}
func (e *Fq) fromBytes(buf []byte) bool {
if len(buf) == 2*SizeFp {
return e[0].fromBytes(buf[:SizeFp]) &&
e[1].fromBytes(buf[SizeFp:])
}
return false
}
func fqSgn(c *Fq) int {
s0 := fpSgn(&c[0])
s1 := fpSgn(&c[1])
return subtle.ConstantTimeSelect(s0&0x1, s0, s1)
}
func fqCopy(c, a *Fq) { *c = *a }
func fqNeg(c, a *Fq) { fpNeg(&c[0], &a[0]); fpNeg(&c[1], &a[1]) }
// fqSqrt calculates c = sqrt(u/v) such that sgn(c)=s.
func fqSqrt(c, u, v *Fq, s int) {
t0, t1, t, r := &Fp{}, &Fp{}, &Fp{}, &Fp{}
a, b, g := &Fp{}, &Fp{}, &Fp{}
// a = u0*v0 + u1*v1
fpMul(a, &u[0], &v[0])
fpMul(t0, &u[1], &v[1])
fpAdd(a, a, t0)
// b = v0^2 + v1^2
fpSqr(b, &v[0])
fpSqr(t0, &v[1])
fpAdd(b, b, t0)
// g = u1*v0 - u0*v1
fpMul(g, &u[1], &v[0])
fpMul(t0, &u[0], &v[1])
fpSub(g, g, t0)
// t = 2(a + sqrt(a^2+g^2)) = 2*(a + (a^2+g^2)^(2^125))
// if t=0; then t = 2*(a - (a^2+g^2)^(2^125))
fpSqr(t0, a)
fpSqr(t1, g)
fpAdd(t0, t0, t1)
for i := 0; i < 125; i++ {
fpSqr(t0, t0)
}
fpAdd(t, a, t0)
if t.isZero() {
fpSub(t, a, t0)
}
fpAdd(t, t, t)
// r = (t*b^3)^(2^125-1)
fpSqr(r, b)
fpMul(r, r, b)
fpMul(r, r, t)
fpTwo1251(r, r)
// x0 = (r*b*t)/2
// x1 = (r*b*g)
fpMul(&c[1], r, b)
fpMul(&c[0], &c[1], t)
fpHlf(&c[0], &c[0])
fpMul(&c[1], &c[1], g)
// if b*(2*x0)^2 == t then (x0,x1) <- (x1,x0)
fpAdd(t0, &c[0], &c[0])
fpSqr(t0, t0)
fpMul(t0, t0, b)
fpSub(t0, t0, t)
if !t0.isZero() {
*t0 = c[0]
c[0] = c[1]
c[1] = *t0
}
if fqSgn(c) != s {
fqNeg(c, c)
}
}
func fqInv(c, a *Fq) {
t1, t2 := &Fp{}, &Fp{}
fpSqr(t1, &a[0])
fpSqr(t2, &a[1])
fpAdd(t1, t1, t2)
fpInv(t1, t1)
fpMul(&c[0], &a[0], t1)
fpNeg(t1, t1)
fpMul(&c[1], &a[1], t1)
}