|
1 <?php |
|
2 |
|
3 if (class_exists('ParagonIE_Sodium_Core_X25519', false)) { |
|
4 return; |
|
5 } |
|
6 |
|
7 /** |
|
8 * Class ParagonIE_Sodium_Core_X25519 |
|
9 */ |
|
10 abstract class ParagonIE_Sodium_Core_X25519 extends ParagonIE_Sodium_Core_Curve25519 |
|
11 { |
|
12 /** |
|
13 * Alters the objects passed to this method in place. |
|
14 * |
|
15 * @internal You should not use this directly from another application |
|
16 * |
|
17 * @param ParagonIE_Sodium_Core_Curve25519_Fe $f |
|
18 * @param ParagonIE_Sodium_Core_Curve25519_Fe $g |
|
19 * @param int $b |
|
20 * @return void |
|
21 * @psalm-suppress MixedAssignment |
|
22 */ |
|
23 public static function fe_cswap( |
|
24 ParagonIE_Sodium_Core_Curve25519_Fe $f, |
|
25 ParagonIE_Sodium_Core_Curve25519_Fe $g, |
|
26 $b = 0 |
|
27 ) { |
|
28 $f0 = (int) $f[0]; |
|
29 $f1 = (int) $f[1]; |
|
30 $f2 = (int) $f[2]; |
|
31 $f3 = (int) $f[3]; |
|
32 $f4 = (int) $f[4]; |
|
33 $f5 = (int) $f[5]; |
|
34 $f6 = (int) $f[6]; |
|
35 $f7 = (int) $f[7]; |
|
36 $f8 = (int) $f[8]; |
|
37 $f9 = (int) $f[9]; |
|
38 $g0 = (int) $g[0]; |
|
39 $g1 = (int) $g[1]; |
|
40 $g2 = (int) $g[2]; |
|
41 $g3 = (int) $g[3]; |
|
42 $g4 = (int) $g[4]; |
|
43 $g5 = (int) $g[5]; |
|
44 $g6 = (int) $g[6]; |
|
45 $g7 = (int) $g[7]; |
|
46 $g8 = (int) $g[8]; |
|
47 $g9 = (int) $g[9]; |
|
48 $b = -$b; |
|
49 $x0 = ($f0 ^ $g0) & $b; |
|
50 $x1 = ($f1 ^ $g1) & $b; |
|
51 $x2 = ($f2 ^ $g2) & $b; |
|
52 $x3 = ($f3 ^ $g3) & $b; |
|
53 $x4 = ($f4 ^ $g4) & $b; |
|
54 $x5 = ($f5 ^ $g5) & $b; |
|
55 $x6 = ($f6 ^ $g6) & $b; |
|
56 $x7 = ($f7 ^ $g7) & $b; |
|
57 $x8 = ($f8 ^ $g8) & $b; |
|
58 $x9 = ($f9 ^ $g9) & $b; |
|
59 $f[0] = $f0 ^ $x0; |
|
60 $f[1] = $f1 ^ $x1; |
|
61 $f[2] = $f2 ^ $x2; |
|
62 $f[3] = $f3 ^ $x3; |
|
63 $f[4] = $f4 ^ $x4; |
|
64 $f[5] = $f5 ^ $x5; |
|
65 $f[6] = $f6 ^ $x6; |
|
66 $f[7] = $f7 ^ $x7; |
|
67 $f[8] = $f8 ^ $x8; |
|
68 $f[9] = $f9 ^ $x9; |
|
69 $g[0] = $g0 ^ $x0; |
|
70 $g[1] = $g1 ^ $x1; |
|
71 $g[2] = $g2 ^ $x2; |
|
72 $g[3] = $g3 ^ $x3; |
|
73 $g[4] = $g4 ^ $x4; |
|
74 $g[5] = $g5 ^ $x5; |
|
75 $g[6] = $g6 ^ $x6; |
|
76 $g[7] = $g7 ^ $x7; |
|
77 $g[8] = $g8 ^ $x8; |
|
78 $g[9] = $g9 ^ $x9; |
|
79 } |
|
80 |
|
81 /** |
|
82 * @internal You should not use this directly from another application |
|
83 * |
|
84 * @param ParagonIE_Sodium_Core_Curve25519_Fe $f |
|
85 * @return ParagonIE_Sodium_Core_Curve25519_Fe |
|
86 */ |
|
87 public static function fe_mul121666(ParagonIE_Sodium_Core_Curve25519_Fe $f) |
|
88 { |
|
89 $h = array( |
|
90 self::mul((int) $f[0], 121666, 17), |
|
91 self::mul((int) $f[1], 121666, 17), |
|
92 self::mul((int) $f[2], 121666, 17), |
|
93 self::mul((int) $f[3], 121666, 17), |
|
94 self::mul((int) $f[4], 121666, 17), |
|
95 self::mul((int) $f[5], 121666, 17), |
|
96 self::mul((int) $f[6], 121666, 17), |
|
97 self::mul((int) $f[7], 121666, 17), |
|
98 self::mul((int) $f[8], 121666, 17), |
|
99 self::mul((int) $f[9], 121666, 17) |
|
100 ); |
|
101 |
|
102 /** @var int $carry9 */ |
|
103 $carry9 = ($h[9] + (1 << 24)) >> 25; |
|
104 $h[0] += self::mul($carry9, 19, 5); |
|
105 $h[9] -= $carry9 << 25; |
|
106 /** @var int $carry1 */ |
|
107 $carry1 = ($h[1] + (1 << 24)) >> 25; |
|
108 $h[2] += $carry1; |
|
109 $h[1] -= $carry1 << 25; |
|
110 /** @var int $carry3 */ |
|
111 $carry3 = ($h[3] + (1 << 24)) >> 25; |
|
112 $h[4] += $carry3; |
|
113 $h[3] -= $carry3 << 25; |
|
114 /** @var int $carry5 */ |
|
115 $carry5 = ($h[5] + (1 << 24)) >> 25; |
|
116 $h[6] += $carry5; |
|
117 $h[5] -= $carry5 << 25; |
|
118 /** @var int $carry7 */ |
|
119 $carry7 = ($h[7] + (1 << 24)) >> 25; |
|
120 $h[8] += $carry7; |
|
121 $h[7] -= $carry7 << 25; |
|
122 |
|
123 /** @var int $carry0 */ |
|
124 $carry0 = ($h[0] + (1 << 25)) >> 26; |
|
125 $h[1] += $carry0; |
|
126 $h[0] -= $carry0 << 26; |
|
127 /** @var int $carry2 */ |
|
128 $carry2 = ($h[2] + (1 << 25)) >> 26; |
|
129 $h[3] += $carry2; |
|
130 $h[2] -= $carry2 << 26; |
|
131 /** @var int $carry4 */ |
|
132 $carry4 = ($h[4] + (1 << 25)) >> 26; |
|
133 $h[5] += $carry4; |
|
134 $h[4] -= $carry4 << 26; |
|
135 /** @var int $carry6 */ |
|
136 $carry6 = ($h[6] + (1 << 25)) >> 26; |
|
137 $h[7] += $carry6; |
|
138 $h[6] -= $carry6 << 26; |
|
139 /** @var int $carry8 */ |
|
140 $carry8 = ($h[8] + (1 << 25)) >> 26; |
|
141 $h[9] += $carry8; |
|
142 $h[8] -= $carry8 << 26; |
|
143 |
|
144 foreach ($h as $i => $value) { |
|
145 $h[$i] = (int) $value; |
|
146 } |
|
147 return ParagonIE_Sodium_Core_Curve25519_Fe::fromArray($h); |
|
148 } |
|
149 |
|
150 /** |
|
151 * @internal You should not use this directly from another application |
|
152 * |
|
153 * Inline comments preceded by # are from libsodium's ref10 code. |
|
154 * |
|
155 * @param string $n |
|
156 * @param string $p |
|
157 * @return string |
|
158 * @throws SodiumException |
|
159 * @throws TypeError |
|
160 */ |
|
161 public static function crypto_scalarmult_curve25519_ref10($n, $p) |
|
162 { |
|
163 # for (i = 0;i < 32;++i) e[i] = n[i]; |
|
164 $e = '' . $n; |
|
165 # e[0] &= 248; |
|
166 $e[0] = self::intToChr( |
|
167 self::chrToInt($e[0]) & 248 |
|
168 ); |
|
169 # e[31] &= 127; |
|
170 # e[31] |= 64; |
|
171 $e[31] = self::intToChr( |
|
172 (self::chrToInt($e[31]) & 127) | 64 |
|
173 ); |
|
174 # fe_frombytes(x1,p); |
|
175 $x1 = self::fe_frombytes($p); |
|
176 # fe_1(x2); |
|
177 $x2 = self::fe_1(); |
|
178 # fe_0(z2); |
|
179 $z2 = self::fe_0(); |
|
180 # fe_copy(x3,x1); |
|
181 $x3 = self::fe_copy($x1); |
|
182 # fe_1(z3); |
|
183 $z3 = self::fe_1(); |
|
184 |
|
185 # swap = 0; |
|
186 /** @var int $swap */ |
|
187 $swap = 0; |
|
188 |
|
189 # for (pos = 254;pos >= 0;--pos) { |
|
190 for ($pos = 254; $pos >= 0; --$pos) { |
|
191 # b = e[pos / 8] >> (pos & 7); |
|
192 /** @var int $b */ |
|
193 $b = self::chrToInt( |
|
194 $e[(int) floor($pos / 8)] |
|
195 ) >> ($pos & 7); |
|
196 # b &= 1; |
|
197 $b &= 1; |
|
198 # swap ^= b; |
|
199 $swap ^= $b; |
|
200 # fe_cswap(x2,x3,swap); |
|
201 self::fe_cswap($x2, $x3, $swap); |
|
202 # fe_cswap(z2,z3,swap); |
|
203 self::fe_cswap($z2, $z3, $swap); |
|
204 # swap = b; |
|
205 $swap = $b; |
|
206 # fe_sub(tmp0,x3,z3); |
|
207 $tmp0 = self::fe_sub($x3, $z3); |
|
208 # fe_sub(tmp1,x2,z2); |
|
209 $tmp1 = self::fe_sub($x2, $z2); |
|
210 |
|
211 # fe_add(x2,x2,z2); |
|
212 $x2 = self::fe_add($x2, $z2); |
|
213 |
|
214 # fe_add(z2,x3,z3); |
|
215 $z2 = self::fe_add($x3, $z3); |
|
216 |
|
217 # fe_mul(z3,tmp0,x2); |
|
218 $z3 = self::fe_mul($tmp0, $x2); |
|
219 |
|
220 # fe_mul(z2,z2,tmp1); |
|
221 $z2 = self::fe_mul($z2, $tmp1); |
|
222 |
|
223 # fe_sq(tmp0,tmp1); |
|
224 $tmp0 = self::fe_sq($tmp1); |
|
225 |
|
226 # fe_sq(tmp1,x2); |
|
227 $tmp1 = self::fe_sq($x2); |
|
228 |
|
229 # fe_add(x3,z3,z2); |
|
230 $x3 = self::fe_add($z3, $z2); |
|
231 |
|
232 # fe_sub(z2,z3,z2); |
|
233 $z2 = self::fe_sub($z3, $z2); |
|
234 |
|
235 # fe_mul(x2,tmp1,tmp0); |
|
236 $x2 = self::fe_mul($tmp1, $tmp0); |
|
237 |
|
238 # fe_sub(tmp1,tmp1,tmp0); |
|
239 $tmp1 = self::fe_sub($tmp1, $tmp0); |
|
240 |
|
241 # fe_sq(z2,z2); |
|
242 $z2 = self::fe_sq($z2); |
|
243 |
|
244 # fe_mul121666(z3,tmp1); |
|
245 $z3 = self::fe_mul121666($tmp1); |
|
246 |
|
247 # fe_sq(x3,x3); |
|
248 $x3 = self::fe_sq($x3); |
|
249 |
|
250 # fe_add(tmp0,tmp0,z3); |
|
251 $tmp0 = self::fe_add($tmp0, $z3); |
|
252 |
|
253 # fe_mul(z3,x1,z2); |
|
254 $z3 = self::fe_mul($x1, $z2); |
|
255 |
|
256 # fe_mul(z2,tmp1,tmp0); |
|
257 $z2 = self::fe_mul($tmp1, $tmp0); |
|
258 } |
|
259 |
|
260 # fe_cswap(x2,x3,swap); |
|
261 self::fe_cswap($x2, $x3, $swap); |
|
262 |
|
263 # fe_cswap(z2,z3,swap); |
|
264 self::fe_cswap($z2, $z3, $swap); |
|
265 |
|
266 # fe_invert(z2,z2); |
|
267 $z2 = self::fe_invert($z2); |
|
268 |
|
269 # fe_mul(x2,x2,z2); |
|
270 $x2 = self::fe_mul($x2, $z2); |
|
271 # fe_tobytes(q,x2); |
|
272 return self::fe_tobytes($x2); |
|
273 } |
|
274 |
|
275 /** |
|
276 * @internal You should not use this directly from another application |
|
277 * |
|
278 * @param ParagonIE_Sodium_Core_Curve25519_Fe $edwardsY |
|
279 * @param ParagonIE_Sodium_Core_Curve25519_Fe $edwardsZ |
|
280 * @return ParagonIE_Sodium_Core_Curve25519_Fe |
|
281 */ |
|
282 public static function edwards_to_montgomery( |
|
283 ParagonIE_Sodium_Core_Curve25519_Fe $edwardsY, |
|
284 ParagonIE_Sodium_Core_Curve25519_Fe $edwardsZ |
|
285 ) { |
|
286 $tempX = self::fe_add($edwardsZ, $edwardsY); |
|
287 $tempZ = self::fe_sub($edwardsZ, $edwardsY); |
|
288 $tempZ = self::fe_invert($tempZ); |
|
289 return self::fe_mul($tempX, $tempZ); |
|
290 } |
|
291 |
|
292 /** |
|
293 * @internal You should not use this directly from another application |
|
294 * |
|
295 * @param string $n |
|
296 * @return string |
|
297 * @throws SodiumException |
|
298 * @throws TypeError |
|
299 */ |
|
300 public static function crypto_scalarmult_curve25519_ref10_base($n) |
|
301 { |
|
302 # for (i = 0;i < 32;++i) e[i] = n[i]; |
|
303 $e = '' . $n; |
|
304 |
|
305 # e[0] &= 248; |
|
306 $e[0] = self::intToChr( |
|
307 self::chrToInt($e[0]) & 248 |
|
308 ); |
|
309 |
|
310 # e[31] &= 127; |
|
311 # e[31] |= 64; |
|
312 $e[31] = self::intToChr( |
|
313 (self::chrToInt($e[31]) & 127) | 64 |
|
314 ); |
|
315 |
|
316 $A = self::ge_scalarmult_base($e); |
|
317 if ( |
|
318 !($A->Y instanceof ParagonIE_Sodium_Core_Curve25519_Fe) |
|
319 || |
|
320 !($A->Z instanceof ParagonIE_Sodium_Core_Curve25519_Fe) |
|
321 ) { |
|
322 throw new TypeError('Null points encountered'); |
|
323 } |
|
324 $pk = self::edwards_to_montgomery($A->Y, $A->Z); |
|
325 return self::fe_tobytes($pk); |
|
326 } |
|
327 } |