Diff: STRATO-apps/wordpress_03/app/wp-includes/sodium_compat/src/Core/Ristretto255.php

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
1 -
1 + <?php
2 +
3 + /**
4 + * Class ParagonIE_Sodium_Core_Ristretto255
5 + */
6 + class ParagonIE_Sodium_Core_Ristretto255 extends ParagonIE_Sodium_Core_Ed25519
7 + {
8 + const crypto_core_ristretto255_HASHBYTES = 64;
9 + const HASH_SC_L = 48;
10 + const CORE_H2C_SHA256 = 1;
11 + const CORE_H2C_SHA512 = 2;
12 +
13 + /**
14 + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
15 + * @param int $b
16 + * @return ParagonIE_Sodium_Core_Curve25519_Fe
17 + */
18 + public static function fe_cneg(ParagonIE_Sodium_Core_Curve25519_Fe $f, $b)
19 + {
20 + $negf = self::fe_neg($f);
21 + return self::fe_cmov($f, $negf, $b);
22 + }
23 +
24 + /**
25 + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
26 + * @return ParagonIE_Sodium_Core_Curve25519_Fe
27 + * @throws SodiumException
28 + */
29 + public static function fe_abs(ParagonIE_Sodium_Core_Curve25519_Fe $f)
30 + {
31 + return self::fe_cneg($f, self::fe_isnegative($f));
32 + }
33 +
34 + /**
35 + * Returns 0 if this field element results in all NUL bytes.
36 + *
37 + * @internal You should not use this directly from another application
38 + *
39 + * @param ParagonIE_Sodium_Core_Curve25519_Fe $f
40 + * @return int
41 + * @throws SodiumException
42 + */
43 + public static function fe_iszero(ParagonIE_Sodium_Core_Curve25519_Fe $f)
44 + {
45 + static $zero;
46 + if ($zero === null) {
47 + $zero = str_repeat("\x00", 32);
48 + }
49 + /** @var string $zero */
50 + $str = self::fe_tobytes($f);
51 +
52 + $d = 0;
53 + for ($i = 0; $i < 32; ++$i) {
54 + $d |= self::chrToInt($str[$i]);
55 + }
56 + return (($d - 1) >> 31) & 1;
57 + }
58 +
59 +
60 + /**
61 + * @param ParagonIE_Sodium_Core_Curve25519_Fe $u
62 + * @param ParagonIE_Sodium_Core_Curve25519_Fe $v
63 + * @return array{x: ParagonIE_Sodium_Core_Curve25519_Fe, nonsquare: int}
64 + *
65 + * @throws SodiumException
66 + */
67 + public static function ristretto255_sqrt_ratio_m1(
68 + ParagonIE_Sodium_Core_Curve25519_Fe $u,
69 + ParagonIE_Sodium_Core_Curve25519_Fe $v
70 + ) {
71 + $sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1);
72 +
73 + $v3 = self::fe_mul(
74 + self::fe_sq($v),
75 + $v
76 + ); /* v3 = v^3 */
77 + $x = self::fe_mul(
78 + self::fe_mul(
79 + self::fe_sq($v3),
80 + $u
81 + ),
82 + $v
83 + ); /* x = uv^7 */
84 +
85 + $x = self::fe_mul(
86 + self::fe_mul(
87 + self::fe_pow22523($x), /* x = (uv^7)^((q-5)/8) */
88 + $v3
89 + ),
90 + $u
91 + ); /* x = uv^3(uv^7)^((q-5)/8) */
92 +
93 + $vxx = self::fe_mul(
94 + self::fe_sq($x),
95 + $v
96 + ); /* vx^2 */
97 +
98 + $m_root_check = self::fe_sub($vxx, $u); /* vx^2-u */
99 + $p_root_check = self::fe_add($vxx, $u); /* vx^2+u */
100 + $f_root_check = self::fe_mul($u, $sqrtm1); /* u*sqrt(-1) */
101 + $f_root_check = self::fe_add($vxx, $f_root_check); /* vx^2+u*sqrt(-1) */
102 +
103 + $has_m_root = self::fe_iszero($m_root_check);
104 + $has_p_root = self::fe_iszero($p_root_check);
105 + $has_f_root = self::fe_iszero($f_root_check);
106 +
107 + $x_sqrtm1 = self::fe_mul($x, $sqrtm1); /* x*sqrt(-1) */
108 +
109 + $x = self::fe_abs(
110 + self::fe_cmov($x, $x_sqrtm1, $has_p_root | $has_f_root)
111 + );
112 + return array(
113 + 'x' => $x,
114 + 'nonsquare' => $has_m_root | $has_p_root
115 + );
116 + }
117 +
118 + /**
119 + * @param string $s
120 + * @return int
121 + * @throws SodiumException
122 + */
123 + public static function ristretto255_point_is_canonical($s)
124 + {
125 + $c = (self::chrToInt($s[31]) & 0x7f) ^ 0x7f;
126 + for ($i = 30; $i > 0; --$i) {
127 + $c |= self::chrToInt($s[$i]) ^ 0xff;
128 + }
129 + $c = ($c - 1) >> 8;
130 + $d = (0xed - 1 - self::chrToInt($s[0])) >> 8;
131 + $e = self::chrToInt($s[31]) >> 7;
132 +
133 + return 1 - ((($c & $d) | $e | self::chrToInt($s[0])) & 1);
134 + }
135 +
136 + /**
137 + * @param string $s
138 + * @param bool $skipCanonicalCheck
139 + * @return array{h: ParagonIE_Sodium_Core_Curve25519_Ge_P3, res: int}
140 + * @throws SodiumException
141 + */
142 + public static function ristretto255_frombytes($s, $skipCanonicalCheck = false)
143 + {
144 + if (!$skipCanonicalCheck) {
145 + if (!self::ristretto255_point_is_canonical($s)) {
146 + throw new SodiumException('S is not canonical');
147 + }
148 + }
149 +
150 + $s_ = self::fe_frombytes($s);
151 + $ss = self::fe_sq($s_); /* ss = s^2 */
152 +
153 + $u1 = self::fe_sub(self::fe_1(), $ss); /* u1 = 1-ss */
154 + $u1u1 = self::fe_sq($u1); /* u1u1 = u1^2 */
155 +
156 + $u2 = self::fe_add(self::fe_1(), $ss); /* u2 = 1+ss */
157 + $u2u2 = self::fe_sq($u2); /* u2u2 = u2^2 */
158 +
159 + $v = self::fe_mul(
160 + ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d),
161 + $u1u1
162 + ); /* v = d*u1^2 */
163 + $v = self::fe_neg($v); /* v = -d*u1^2 */
164 + $v = self::fe_sub($v, $u2u2); /* v = -(d*u1^2)-u2^2 */
165 + $v_u2u2 = self::fe_mul($v, $u2u2); /* v_u2u2 = v*u2^2 */
166 +
167 + // fe25519_1(one);
168 + // notsquare = ristretto255_sqrt_ratio_m1(inv_sqrt, one, v_u2u2);
169 + $one = self::fe_1();
170 + $result = self::ristretto255_sqrt_ratio_m1($one, $v_u2u2);
171 + $inv_sqrt = $result['x'];
172 + $notsquare = $result['nonsquare'];
173 +
174 + $h = new ParagonIE_Sodium_Core_Curve25519_Ge_P3();
175 +
176 + $h->X = self::fe_mul($inv_sqrt, $u2);
177 + $h->Y = self::fe_mul(self::fe_mul($inv_sqrt, $h->X), $v);
178 +
179 + $h->X = self::fe_mul($h->X, $s_);
180 + $h->X = self::fe_abs(
181 + self::fe_add($h->X, $h->X)
182 + );
183 + $h->Y = self::fe_mul($u1, $h->Y);
184 + $h->Z = self::fe_1();
185 + $h->T = self::fe_mul($h->X, $h->Y);
186 +
187 + $res = - ((1 - $notsquare) | self::fe_isnegative($h->T) | self::fe_iszero($h->Y));
188 + return array('h' => $h, 'res' => $res);
189 + }
190 +
191 + /**
192 + * @param ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h
193 + * @return string
194 + * @throws SodiumException
195 + */
196 + public static function ristretto255_p3_tobytes(ParagonIE_Sodium_Core_Curve25519_Ge_P3 $h)
197 + {
198 + $sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1);
199 + $invsqrtamd = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$invsqrtamd);
200 +
201 + $u1 = self::fe_add($h->Z, $h->Y); /* u1 = Z+Y */
202 + $zmy = self::fe_sub($h->Z, $h->Y); /* zmy = Z-Y */
203 + $u1 = self::fe_mul($u1, $zmy); /* u1 = (Z+Y)*(Z-Y) */
204 + $u2 = self::fe_mul($h->X, $h->Y); /* u2 = X*Y */
205 +
206 + $u1_u2u2 = self::fe_mul(self::fe_sq($u2), $u1); /* u1_u2u2 = u1*u2^2 */
207 + $one = self::fe_1();
208 +
209 + // fe25519_1(one);
210 + // (void) ristretto255_sqrt_ratio_m1(inv_sqrt, one, u1_u2u2);
211 + $result = self::ristretto255_sqrt_ratio_m1($one, $u1_u2u2);
212 + $inv_sqrt = $result['x'];
213 +
214 + $den1 = self::fe_mul($inv_sqrt, $u1); /* den1 = inv_sqrt*u1 */
215 + $den2 = self::fe_mul($inv_sqrt, $u2); /* den2 = inv_sqrt*u2 */
216 + $z_inv = self::fe_mul($h->T, self::fe_mul($den1, $den2)); /* z_inv = den1*den2*T */
217 +
218 + $ix = self::fe_mul($h->X, $sqrtm1); /* ix = X*sqrt(-1) */
219 + $iy = self::fe_mul($h->Y, $sqrtm1); /* iy = Y*sqrt(-1) */
220 + $eden = self::fe_mul($den1, $invsqrtamd);
221 +
222 + $t_z_inv = self::fe_mul($h->T, $z_inv); /* t_z_inv = T*z_inv */
223 + $rotate = self::fe_isnegative($t_z_inv);
224 +
225 + $x_ = self::fe_copy($h->X);
226 + $y_ = self::fe_copy($h->Y);
227 + $den_inv = self::fe_copy($den2);
228 +
229 + $x_ = self::fe_cmov($x_, $iy, $rotate);
230 + $y_ = self::fe_cmov($y_, $ix, $rotate);
231 + $den_inv = self::fe_cmov($den_inv, $eden, $rotate);
232 +
233 + $x_z_inv = self::fe_mul($x_, $z_inv);
234 + $y_ = self::fe_cneg($y_, self::fe_isnegative($x_z_inv));
235 +
236 +
237 + // fe25519_sub(s_, h->Z, y_);
238 + // fe25519_mul(s_, den_inv, s_);
239 + // fe25519_abs(s_, s_);
240 + // fe25519_tobytes(s, s_);
241 + return self::fe_tobytes(
242 + self::fe_abs(
243 + self::fe_mul(
244 + $den_inv,
245 + self::fe_sub($h->Z, $y_)
246 + )
247 + )
248 + );
249 + }
250 +
251 + /**
252 + * @param ParagonIE_Sodium_Core_Curve25519_Fe $t
253 + * @return ParagonIE_Sodium_Core_Curve25519_Ge_P3
254 + *
255 + * @throws SodiumException
256 + */
257 + public static function ristretto255_elligator(ParagonIE_Sodium_Core_Curve25519_Fe $t)
258 + {
259 + $sqrtm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtm1);
260 + $onemsqd = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$onemsqd);
261 + $d = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$d);
262 + $sqdmone = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqdmone);
263 + $sqrtadm1 = ParagonIE_Sodium_Core_Curve25519_Fe::fromArray(self::$sqrtadm1);
264 +
265 + $one = self::fe_1();
266 + $r = self::fe_mul($sqrtm1, self::fe_sq($t)); /* r = sqrt(-1)*t^2 */
267 + $u = self::fe_mul(self::fe_add($r, $one), $onemsqd); /* u = (r+1)*(1-d^2) */
268 + $c = self::fe_neg(self::fe_1()); /* c = -1 */
269 + $rpd = self::fe_add($r, $d); /* rpd = r+d */
270 +
271 + $v = self::fe_mul(
272 + self::fe_sub(
273 + $c,
274 + self::fe_mul($r, $d)
275 + ),
276 + $rpd
277 + ); /* v = (c-r*d)*(r+d) */
278 +
279 + $result = self::ristretto255_sqrt_ratio_m1($u, $v);
280 + $s = $result['x'];
281 + $wasnt_square = 1 - $result['nonsquare'];
282 +
283 + $s_prime = self::fe_neg(
284 + self::fe_abs(
285 + self::fe_mul($s, $t)
286 + )
287 + ); /* s_prime = -|s*t| */
288 + $s = self::fe_cmov($s, $s_prime, $wasnt_square);
289 + $c = self::fe_cmov($c, $r, $wasnt_square);
290 +
291 + // fe25519_sub(n, r, one); /* n = r-1 */
292 + // fe25519_mul(n, n, c); /* n = c*(r-1) */
293 + // fe25519_mul(n, n, ed25519_sqdmone); /* n = c*(r-1)*(d-1)^2 */
294 + // fe25519_sub(n, n, v); /* n = c*(r-1)*(d-1)^2-v */
295 + $n = self::fe_sub(
296 + self::fe_mul(
297 + self::fe_mul(
298 + self::fe_sub($r, $one),
299 + $c
300 + ),
301 + $sqdmone
302 + ),
303 + $v
304 + ); /* n = c*(r-1)*(d-1)^2-v */
305 +
306 + $w0 = self::fe_mul(
307 + self::fe_add($s, $s),
308 + $v
309 + ); /* w0 = 2s*v */
310 +
311 + $w1 = self::fe_mul($n, $sqrtadm1); /* w1 = n*sqrt(ad-1) */
312 + $ss = self::fe_sq($s); /* ss = s^2 */
313 + $w2 = self::fe_sub($one, $ss); /* w2 = 1-s^2 */
314 + $w3 = self::fe_add($one, $ss); /* w3 = 1+s^2 */
315 +
316 + return new ParagonIE_Sodium_Core_Curve25519_Ge_P3(
317 + self::fe_mul($w0, $w3),
318 + self::fe_mul($w2, $w1),
319 + self::fe_mul($w1, $w3),
320 + self::fe_mul($w0, $w2)
321 + );
322 + }
323 +
324 + /**
325 + * @param string $h
326 + * @return string
327 + * @throws SodiumException
328 + */
329 + public static function ristretto255_from_hash($h)
330 + {
331 + if (self::strlen($h) !== 64) {
332 + throw new SodiumException('Hash must be 64 bytes');
333 + }
334 + //fe25519_frombytes(r0, h);
335 + //fe25519_frombytes(r1, h + 32);
336 + $r0 = self::fe_frombytes(self::substr($h, 0, 32));
337 + $r1 = self::fe_frombytes(self::substr($h, 32, 32));
338 +
339 + //ristretto255_elligator(&p0, r0);
340 + //ristretto255_elligator(&p1, r1);
341 + $p0 = self::ristretto255_elligator($r0);
342 + $p1 = self::ristretto255_elligator($r1);
343 +
344 + //ge25519_p3_to_cached(&p1_cached, &p1);
345 + //ge25519_add_cached(&p_p1p1, &p0, &p1_cached);
346 + $p_p1p1 = self::ge_add(
347 + $p0,
348 + self::ge_p3_to_cached($p1)
349 + );
350 +
351 + //ge25519_p1p1_to_p3(&p, &p_p1p1);
352 + //ristretto255_p3_tobytes(s, &p);
353 + return self::ristretto255_p3_tobytes(
354 + self::ge_p1p1_to_p3($p_p1p1)
355 + );
356 + }
357 +
358 + /**
359 + * @param string $p
360 + * @return int
361 + * @throws SodiumException
362 + */
363 + public static function is_valid_point($p)
364 + {
365 + $result = self::ristretto255_frombytes($p);
366 + if ($result['res'] !== 0) {
367 + return 0;
368 + }
369 + return 1;
370 + }
371 +
372 + /**
373 + * @param string $p
374 + * @param string $q
375 + * @return string
376 + * @throws SodiumException
377 + */
378 + public static function ristretto255_add($p, $q)
379 + {
380 + $p_res = self::ristretto255_frombytes($p);
381 + $q_res = self::ristretto255_frombytes($q);
382 + if ($p_res['res'] !== 0 || $q_res['res'] !== 0) {
383 + throw new SodiumException('Could not add points');
384 + }
385 + $p_p3 = $p_res['h'];
386 + $q_p3 = $q_res['h'];
387 + $q_cached = self::ge_p3_to_cached($q_p3);
388 + $r_p1p1 = self::ge_add($p_p3, $q_cached);
389 + $r_p3 = self::ge_p1p1_to_p3($r_p1p1);
390 + return self::ristretto255_p3_tobytes($r_p3);
391 + }
392 +
393 + /**
394 + * @param string $p
395 + * @param string $q
396 + * @return string
397 + * @throws SodiumException
398 + */
399 + public static function ristretto255_sub($p, $q)
400 + {
401 + $p_res = self::ristretto255_frombytes($p);
402 + $q_res = self::ristretto255_frombytes($q);
403 + if ($p_res['res'] !== 0 || $q_res['res'] !== 0) {
404 + throw new SodiumException('Could not add points');
405 + }
406 + $p_p3 = $p_res['h'];
407 + $q_p3 = $q_res['h'];
408 + $q_cached = self::ge_p3_to_cached($q_p3);
409 + $r_p1p1 = self::ge_sub($p_p3, $q_cached);
410 + $r_p3 = self::ge_p1p1_to_p3($r_p1p1);
411 + return self::ristretto255_p3_tobytes($r_p3);
412 + }
413 +
414 +
415 + /**
416 + * @param int $hLen
417 + * @param ?string $ctx
418 + * @param string $msg
419 + * @return string
420 + * @throws SodiumException
421 + * @psalm-suppress PossiblyInvalidArgument hash API
422 + */
423 + protected static function h2c_string_to_hash_sha256($hLen, $ctx, $msg)
424 + {
425 + $h = array_fill(0, $hLen, 0);
426 + $ctx_len = !is_null($ctx) ? self::strlen($ctx) : 0;
427 + if ($hLen > 0xff) {
428 + throw new SodiumException('Hash must be less than 256 bytes');
429 + }
430 +
431 + if ($ctx_len > 0xff) {
432 + $st = hash_init('sha256');
433 + self::hash_update($st, "H2C-OVERSIZE-DST-");
434 + self::hash_update($st, $ctx);
435 + $ctx = hash_final($st, true);
436 + $ctx_len = 32;
437 + }
438 + $t = array(0, $hLen, 0);
439 + $ux = str_repeat("\0", 64);
440 + $st = hash_init('sha256');
441 + self::hash_update($st, $ux);
442 + self::hash_update($st, $msg);
443 + self::hash_update($st, self::intArrayToString($t));
444 + self::hash_update($st, $ctx);
445 + self::hash_update($st, self::intToChr($ctx_len));
446 + $u0 = hash_final($st, true);
447 +
448 + for ($i = 0; $i < $hLen; $i += 64) {
449 + $ux = self::xorStrings($ux, $u0);
450 + ++$t[2];
451 + $st = hash_init('sha256');
452 + self::hash_update($st, $ux);
453 + self::hash_update($st, self::intToChr($t[2]));
454 + self::hash_update($st, $ctx);
455 + self::hash_update($st, self::intToChr($ctx_len));
456 + $ux = hash_final($st, true);
457 + $amount = min($hLen - $i, 64);
458 + for ($j = 0; $j < $amount; ++$j) {
459 + $h[$i + $j] = self::chrToInt($ux[$i]);
460 + }
461 + }
462 + return self::intArrayToString(array_slice($h, 0, $hLen));
463 + }
464 +
465 + /**
466 + * @param int $hLen
467 + * @param ?string $ctx
468 + * @param string $msg
469 + * @return string
470 + * @throws SodiumException
471 + * @psalm-suppress PossiblyInvalidArgument hash API
472 + */
473 + protected static function h2c_string_to_hash_sha512($hLen, $ctx, $msg)
474 + {
475 + $h = array_fill(0, $hLen, 0);
476 + $ctx_len = !is_null($ctx) ? self::strlen($ctx) : 0;
477 + if ($hLen > 0xff) {
478 + throw new SodiumException('Hash must be less than 256 bytes');
479 + }
480 +
481 + if ($ctx_len > 0xff) {
482 + $st = hash_init('sha256');
483 + self::hash_update($st, "H2C-OVERSIZE-DST-");
484 + self::hash_update($st, $ctx);
485 + $ctx = hash_final($st, true);
486 + $ctx_len = 32;
487 + }
488 + $t = array(0, $hLen, 0);
489 + $ux = str_repeat("\0", 128);
490 + $st = hash_init('sha512');
491 + self::hash_update($st, $ux);
492 + self::hash_update($st, $msg);
493 + self::hash_update($st, self::intArrayToString($t));
494 + self::hash_update($st, $ctx);
495 + self::hash_update($st, self::intToChr($ctx_len));
496 + $u0 = hash_final($st, true);
497 +
498 + for ($i = 0; $i < $hLen; $i += 128) {
499 + $ux = self::xorStrings($ux, $u0);
500 + ++$t[2];
501 + $st = hash_init('sha512');
502 + self::hash_update($st, $ux);
503 + self::hash_update($st, self::intToChr($t[2]));
504 + self::hash_update($st, $ctx);
505 + self::hash_update($st, self::intToChr($ctx_len));
506 + $ux = hash_final($st, true);
507 + $amount = min($hLen - $i, 128);
508 + for ($j = 0; $j < $amount; ++$j) {
509 + $h[$i + $j] = self::chrToInt($ux[$i]);
510 + }
511 + }
512 + return self::intArrayToString(array_slice($h, 0, $hLen));
513 + }
514 +
515 + /**
516 + * @param int $hLen
517 + * @param ?string $ctx
518 + * @param string $msg
519 + * @param int $hash_alg
520 + * @return string
521 + * @throws SodiumException
522 + */
523 + public static function h2c_string_to_hash($hLen, $ctx, $msg, $hash_alg)
524 + {
525 + switch ($hash_alg) {
526 + case self::CORE_H2C_SHA256:
527 + return self::h2c_string_to_hash_sha256($hLen, $ctx, $msg);
528 + case self::CORE_H2C_SHA512:
529 + return self::h2c_string_to_hash_sha512($hLen, $ctx, $msg);
530 + default:
531 + throw new SodiumException('Invalid H2C hash algorithm');
532 + }
533 + }
534 +
535 + /**
536 + * @param ?string $ctx
537 + * @param string $msg
538 + * @param int $hash_alg
539 + * @return string
540 + * @throws SodiumException
541 + */
542 + protected static function _string_to_element($ctx, $msg, $hash_alg)
543 + {
544 + return self::ristretto255_from_hash(
545 + self::h2c_string_to_hash(self::crypto_core_ristretto255_HASHBYTES, $ctx, $msg, $hash_alg)
546 + );
547 + }
548 +
549 + /**
550 + * @return string
551 + * @throws SodiumException
552 + * @throws Exception
553 + */
554 + public static function ristretto255_random()
555 + {
556 + return self::ristretto255_from_hash(
557 + ParagonIE_Sodium_Compat::randombytes_buf(self::crypto_core_ristretto255_HASHBYTES)
558 + );
559 + }
560 +
561 + /**
562 + * @return string
563 + * @throws SodiumException
564 + */
565 + public static function ristretto255_scalar_random()
566 + {
567 + return self::scalar_random();
568 + }
569 +
570 + /**
571 + * @param string $s
572 + * @return string
573 + * @throws SodiumException
574 + */
575 + public static function ristretto255_scalar_complement($s)
576 + {
577 + return self::scalar_complement($s);
578 + }
579 +
580 +
581 + /**
582 + * @param string $s
583 + * @return string
584 + */
585 + public static function ristretto255_scalar_invert($s)
586 + {
587 + return self::sc25519_invert($s);
588 + }
589 +
590 + /**
591 + * @param string $s
592 + * @return string
593 + * @throws SodiumException
594 + */
595 + public static function ristretto255_scalar_negate($s)
596 + {
597 + return self::scalar_negate($s);
598 + }
599 +
600 + /**
601 + * @param string $x
602 + * @param string $y
603 + * @return string
604 + */
605 + public static function ristretto255_scalar_add($x, $y)
606 + {
607 + return self::scalar_add($x, $y);
608 + }
609 +
610 + /**
611 + * @param string $x
612 + * @param string $y
613 + * @return string
614 + */
615 + public static function ristretto255_scalar_sub($x, $y)
616 + {
617 + return self::scalar_sub($x, $y);
618 + }
619 +
620 + /**
621 + * @param string $x
622 + * @param string $y
623 + * @return string
624 + */
625 + public static function ristretto255_scalar_mul($x, $y)
626 + {
627 + return self::sc25519_mul($x, $y);
628 + }
629 +
630 + /**
631 + * @param string $ctx
632 + * @param string $msg
633 + * @param int $hash_alg
634 + * @return string
635 + * @throws SodiumException
636 + */
637 + public static function ristretto255_scalar_from_string($ctx, $msg, $hash_alg)
638 + {
639 + $h = array_fill(0, 64, 0);
640 + $h_be = self::stringToIntArray(
641 + self::h2c_string_to_hash(
642 + self::HASH_SC_L, $ctx, $msg, $hash_alg
643 + )
644 + );
645 +
646 + for ($i = 0; $i < self::HASH_SC_L; ++$i) {
647 + $h[$i] = $h_be[self::HASH_SC_L - 1 - $i];
648 + }
649 + return self::ristretto255_scalar_reduce(self::intArrayToString($h));
650 + }
651 +
652 + /**
653 + * @param string $s
654 + * @return string
655 + */
656 + public static function ristretto255_scalar_reduce($s)
657 + {
658 + return self::sc_reduce($s);
659 + }
660 +
661 + /**
662 + * @param string $n
663 + * @param string $p
664 + * @return string
665 + * @throws SodiumException
666 + */
667 + public static function scalarmult_ristretto255($n, $p)
668 + {
669 + if (self::strlen($n) !== 32) {
670 + throw new SodiumException('Scalar must be 32 bytes, ' . self::strlen($p) . ' given.');
671 + }
672 + if (self::strlen($p) !== 32) {
673 + throw new SodiumException('Point must be 32 bytes, ' . self::strlen($p) . ' given.');
674 + }
675 + $result = self::ristretto255_frombytes($p);
676 + if ($result['res'] !== 0) {
677 + throw new SodiumException('Could not multiply points');
678 + }
679 + $P = $result['h'];
680 +
681 + $t = self::stringToIntArray($n);
682 + $t[31] &= 0x7f;
683 + $Q = self::ge_scalarmult(self::intArrayToString($t), $P);
684 + $q = self::ristretto255_p3_tobytes($Q);
685 + if (ParagonIE_Sodium_Compat::is_zero($q)) {
686 + throw new SodiumException('An unknown error has occurred');
687 + }
688 + return $q;
689 + }
690 +
691 + /**
692 + * @param string $n
693 + * @return string
694 + * @throws SodiumException
695 + */
696 + public static function scalarmult_ristretto255_base($n)
697 + {
698 + $t = self::stringToIntArray($n);
699 + $t[31] &= 0x7f;
700 + $Q = self::ge_scalarmult_base(self::intArrayToString($t));
701 + $q = self::ristretto255_p3_tobytes($Q);
702 + if (ParagonIE_Sodium_Compat::is_zero($q)) {
703 + throw new SodiumException('An unknown error has occurred');
704 + }
705 + return $q;
706 + }
707 + }
708 +