main
1// Package fp25519 provides prime field arithmetic over GF(2^255-19).
2package fp25519
3
4import (
5 "errors"
6
7 "github.com/cloudflare/circl/internal/conv"
8)
9
10// Size in bytes of an element.
11const Size = 32
12
13// Elt is a prime field element.
14type Elt [Size]byte
15
16func (e Elt) String() string { return conv.BytesLe2Hex(e[:]) }
17
18// p is the prime modulus 2^255-19.
19var p = Elt{
20 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
21 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
22 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
23 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
24}
25
26// P returns the prime modulus 2^255-19.
27func P() Elt { return p }
28
29// ToBytes stores in b the little-endian byte representation of x.
30func ToBytes(b []byte, x *Elt) error {
31 if len(b) != Size {
32 return errors.New("wrong size")
33 }
34 Modp(x)
35 copy(b, x[:])
36 return nil
37}
38
39// IsZero returns true if x is equal to 0.
40func IsZero(x *Elt) bool { Modp(x); return *x == Elt{} }
41
42// SetOne assigns x=1.
43func SetOne(x *Elt) { *x = Elt{}; x[0] = 1 }
44
45// Neg calculates z = -x.
46func Neg(z, x *Elt) { Sub(z, &p, x) }
47
48// InvSqrt calculates z = sqrt(x/y) iff x/y is a quadratic-residue, which is
49// indicated by returning isQR = true. Otherwise, when x/y is a quadratic
50// non-residue, z will have an undetermined value and isQR = false.
51func InvSqrt(z, x, y *Elt) (isQR bool) {
52 sqrtMinusOne := &Elt{
53 0xb0, 0xa0, 0x0e, 0x4a, 0x27, 0x1b, 0xee, 0xc4,
54 0x78, 0xe4, 0x2f, 0xad, 0x06, 0x18, 0x43, 0x2f,
55 0xa7, 0xd7, 0xfb, 0x3d, 0x99, 0x00, 0x4d, 0x2b,
56 0x0b, 0xdf, 0xc1, 0x4f, 0x80, 0x24, 0x83, 0x2b,
57 }
58 t0, t1, t2, t3 := &Elt{}, &Elt{}, &Elt{}, &Elt{}
59
60 Mul(t0, x, y) // t0 = u*v
61 Sqr(t1, y) // t1 = v^2
62 Mul(t2, t0, t1) // t2 = u*v^3
63 Sqr(t0, t1) // t0 = v^4
64 Mul(t1, t0, t2) // t1 = u*v^7
65
66 var Tab [4]*Elt
67 Tab[0] = &Elt{}
68 Tab[1] = &Elt{}
69 Tab[2] = t3
70 Tab[3] = t1
71
72 *Tab[0] = *t1
73 Sqr(Tab[0], Tab[0])
74 Sqr(Tab[1], Tab[0])
75 Sqr(Tab[1], Tab[1])
76 Mul(Tab[1], Tab[1], Tab[3])
77 Mul(Tab[0], Tab[0], Tab[1])
78 Sqr(Tab[0], Tab[0])
79 Mul(Tab[0], Tab[0], Tab[1])
80 Sqr(Tab[1], Tab[0])
81 for i := 0; i < 4; i++ {
82 Sqr(Tab[1], Tab[1])
83 }
84 Mul(Tab[1], Tab[1], Tab[0])
85 Sqr(Tab[2], Tab[1])
86 for i := 0; i < 4; i++ {
87 Sqr(Tab[2], Tab[2])
88 }
89 Mul(Tab[2], Tab[2], Tab[0])
90 Sqr(Tab[1], Tab[2])
91 for i := 0; i < 14; i++ {
92 Sqr(Tab[1], Tab[1])
93 }
94 Mul(Tab[1], Tab[1], Tab[2])
95 Sqr(Tab[2], Tab[1])
96 for i := 0; i < 29; i++ {
97 Sqr(Tab[2], Tab[2])
98 }
99 Mul(Tab[2], Tab[2], Tab[1])
100 Sqr(Tab[1], Tab[2])
101 for i := 0; i < 59; i++ {
102 Sqr(Tab[1], Tab[1])
103 }
104 Mul(Tab[1], Tab[1], Tab[2])
105 for i := 0; i < 5; i++ {
106 Sqr(Tab[1], Tab[1])
107 }
108 Mul(Tab[1], Tab[1], Tab[0])
109 Sqr(Tab[2], Tab[1])
110 for i := 0; i < 124; i++ {
111 Sqr(Tab[2], Tab[2])
112 }
113 Mul(Tab[2], Tab[2], Tab[1])
114 Sqr(Tab[2], Tab[2])
115 Sqr(Tab[2], Tab[2])
116 Mul(Tab[2], Tab[2], Tab[3])
117
118 Mul(z, t3, t2) // z = xy^(p+3)/8 = xy^3*(xy^7)^(p-5)/8
119 // Checking whether y z^2 == x
120 Sqr(t0, z) // t0 = z^2
121 Mul(t0, t0, y) // t0 = yz^2
122 Sub(t1, t0, x) // t1 = t0-u
123 Add(t2, t0, x) // t2 = t0+u
124 if IsZero(t1) {
125 return true
126 } else if IsZero(t2) {
127 Mul(z, z, sqrtMinusOne) // z = z*sqrt(-1)
128 return true
129 } else {
130 return false
131 }
132}
133
134// Inv calculates z = 1/x mod p.
135func Inv(z, x *Elt) {
136 x0, x1, x2 := &Elt{}, &Elt{}, &Elt{}
137 Sqr(x1, x)
138 Sqr(x0, x1)
139 Sqr(x0, x0)
140 Mul(x0, x0, x)
141 Mul(z, x0, x1)
142 Sqr(x1, z)
143 Mul(x0, x0, x1)
144 Sqr(x1, x0)
145 for i := 0; i < 4; i++ {
146 Sqr(x1, x1)
147 }
148 Mul(x0, x0, x1)
149 Sqr(x1, x0)
150 for i := 0; i < 9; i++ {
151 Sqr(x1, x1)
152 }
153 Mul(x1, x1, x0)
154 Sqr(x2, x1)
155 for i := 0; i < 19; i++ {
156 Sqr(x2, x2)
157 }
158 Mul(x2, x2, x1)
159 for i := 0; i < 10; i++ {
160 Sqr(x2, x2)
161 }
162 Mul(x2, x2, x0)
163 Sqr(x0, x2)
164 for i := 0; i < 49; i++ {
165 Sqr(x0, x0)
166 }
167 Mul(x0, x0, x2)
168 Sqr(x1, x0)
169 for i := 0; i < 99; i++ {
170 Sqr(x1, x1)
171 }
172 Mul(x1, x1, x0)
173 for i := 0; i < 50; i++ {
174 Sqr(x1, x1)
175 }
176 Mul(x1, x1, x2)
177 for i := 0; i < 5; i++ {
178 Sqr(x1, x1)
179 }
180 Mul(z, z, x1)
181}
182
183// Cmov assigns y to x if n is 1.
184func Cmov(x, y *Elt, n uint) { cmov(x, y, n) }
185
186// Cswap interchanges x and y if n is 1.
187func Cswap(x, y *Elt, n uint) { cswap(x, y, n) }
188
189// Add calculates z = x+y mod p.
190func Add(z, x, y *Elt) { add(z, x, y) }
191
192// Sub calculates z = x-y mod p.
193func Sub(z, x, y *Elt) { sub(z, x, y) }
194
195// AddSub calculates (x,y) = (x+y mod p, x-y mod p).
196func AddSub(x, y *Elt) { addsub(x, y) }
197
198// Mul calculates z = x*y mod p.
199func Mul(z, x, y *Elt) { mul(z, x, y) }
200
201// Sqr calculates z = x^2 mod p.
202func Sqr(z, x *Elt) { sqr(z, x) }
203
204// Modp ensures that z is between [0,p-1].
205func Modp(z *Elt) { modp(z) }