Browse code

Added README.md appinfo/info.xml appinfo/signature.json lib/Controller/AuthorApiController.php and the providers directory

DoubleBastionAdmin authored on 20/08/2022 16:33:00
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,3951 @@
1
+<?php
2
+
3
+/**
4
+ * Libsodium compatibility layer
5
+ *
6
+ * This is the only class you should be interfacing with, as a user of
7
+ * sodium_compat.
8
+ *
9
+ * If the PHP extension for libsodium is installed, it will always use that
10
+ * instead of our implementations. You get better performance and stronger
11
+ * guarantees against side-channels that way.
12
+ *
13
+ * However, if your users don't have the PHP extension installed, we offer a
14
+ * compatible interface here. It will give you the correct results as if the
15
+ * PHP extension was installed. It won't be as fast, of course.
16
+ *
17
+ * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION *
18
+ *                                                                               *
19
+ *     Until audited, this is probably not safe to use! DANGER WILL ROBINSON     *
20
+ *                                                                               *
21
+ * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION * CAUTION *
22
+ */
23
+
24
+if (class_exists('ParagonIE_Sodium_Compat', false)) {
25
+    return;
26
+}
27
+
28
+class ParagonIE_Sodium_Compat
29
+{
30
+    /**
31
+     * This parameter prevents the use of the PECL extension.
32
+     * It should only be used for unit testing.
33
+     *
34
+     * @var bool
35
+     */
36
+    public static $disableFallbackForUnitTests = false;
37
+
38
+    /**
39
+     * Use fast multiplication rather than our constant-time multiplication
40
+     * implementation. Can be enabled at runtime. Only enable this if you
41
+     * are absolutely certain that there is no timing leak on your platform.
42
+     *
43
+     * @var bool
44
+     */
45
+    public static $fastMult = false;
46
+
47
+    const LIBRARY_MAJOR_VERSION = 9;
48
+    const LIBRARY_MINOR_VERSION = 1;
49
+    const LIBRARY_VERSION_MAJOR = 9;
50
+    const LIBRARY_VERSION_MINOR = 1;
51
+    const VERSION_STRING = 'polyfill-1.0.8';
52
+
53
+    // From libsodium
54
+    const BASE64_VARIANT_ORIGINAL = 1;
55
+    const BASE64_VARIANT_ORIGINAL_NO_PADDING = 3;
56
+    const BASE64_VARIANT_URLSAFE = 5;
57
+    const BASE64_VARIANT_URLSAFE_NO_PADDING = 7;
58
+    const CRYPTO_AEAD_AES256GCM_KEYBYTES = 32;
59
+    const CRYPTO_AEAD_AES256GCM_NSECBYTES = 0;
60
+    const CRYPTO_AEAD_AES256GCM_NPUBBYTES = 12;
61
+    const CRYPTO_AEAD_AES256GCM_ABYTES = 16;
62
+    const CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES = 32;
63
+    const CRYPTO_AEAD_CHACHA20POLY1305_NSECBYTES = 0;
64
+    const CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES = 8;
65
+    const CRYPTO_AEAD_CHACHA20POLY1305_ABYTES = 16;
66
+    const CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES = 32;
67
+    const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NSECBYTES = 0;
68
+    const CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES = 12;
69
+    const CRYPTO_AEAD_CHACHA20POLY1305_IETF_ABYTES = 16;
70
+    const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES = 32;
71
+    const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NSECBYTES = 0;
72
+    const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES = 24;
73
+    const CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES = 16;
74
+    const CRYPTO_AUTH_BYTES = 32;
75
+    const CRYPTO_AUTH_KEYBYTES = 32;
76
+    const CRYPTO_BOX_SEALBYTES = 16;
77
+    const CRYPTO_BOX_SECRETKEYBYTES = 32;
78
+    const CRYPTO_BOX_PUBLICKEYBYTES = 32;
79
+    const CRYPTO_BOX_KEYPAIRBYTES = 64;
80
+    const CRYPTO_BOX_MACBYTES = 16;
81
+    const CRYPTO_BOX_NONCEBYTES = 24;
82
+    const CRYPTO_BOX_SEEDBYTES = 32;
83
+    const CRYPTO_CORE_RISTRETTO255_BYTES = 32;
84
+    const CRYPTO_CORE_RISTRETTO255_SCALARBYTES = 32;
85
+    const CRYPTO_CORE_RISTRETTO255_HASHBYTES = 64;
86
+    const CRYPTO_CORE_RISTRETTO255_NONREDUCEDSCALARBYTES = 64;
87
+    const CRYPTO_KDF_BYTES_MIN = 16;
88
+    const CRYPTO_KDF_BYTES_MAX = 64;
89
+    const CRYPTO_KDF_CONTEXTBYTES = 8;
90
+    const CRYPTO_KDF_KEYBYTES = 32;
91
+    const CRYPTO_KX_BYTES = 32;
92
+    const CRYPTO_KX_PRIMITIVE = 'x25519blake2b';
93
+    const CRYPTO_KX_SEEDBYTES = 32;
94
+    const CRYPTO_KX_KEYPAIRBYTES = 64;
95
+    const CRYPTO_KX_PUBLICKEYBYTES = 32;
96
+    const CRYPTO_KX_SECRETKEYBYTES = 32;
97
+    const CRYPTO_KX_SESSIONKEYBYTES = 32;
98
+    const CRYPTO_GENERICHASH_BYTES = 32;
99
+    const CRYPTO_GENERICHASH_BYTES_MIN = 16;
100
+    const CRYPTO_GENERICHASH_BYTES_MAX = 64;
101
+    const CRYPTO_GENERICHASH_KEYBYTES = 32;
102
+    const CRYPTO_GENERICHASH_KEYBYTES_MIN = 16;
103
+    const CRYPTO_GENERICHASH_KEYBYTES_MAX = 64;
104
+    const CRYPTO_PWHASH_SALTBYTES = 16;
105
+    const CRYPTO_PWHASH_STRPREFIX = '$argon2id$';
106
+    const CRYPTO_PWHASH_ALG_ARGON2I13 = 1;
107
+    const CRYPTO_PWHASH_ALG_ARGON2ID13 = 2;
108
+    const CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE = 33554432;
109
+    const CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE = 4;
110
+    const CRYPTO_PWHASH_MEMLIMIT_MODERATE = 134217728;
111
+    const CRYPTO_PWHASH_OPSLIMIT_MODERATE = 6;
112
+    const CRYPTO_PWHASH_MEMLIMIT_SENSITIVE = 536870912;
113
+    const CRYPTO_PWHASH_OPSLIMIT_SENSITIVE = 8;
114
+    const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_SALTBYTES = 32;
115
+    const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX = '$7$';
116
+    const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE = 534288;
117
+    const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE = 16777216;
118
+    const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE = 33554432;
119
+    const CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE = 1073741824;
120
+    const CRYPTO_SCALARMULT_BYTES = 32;
121
+    const CRYPTO_SCALARMULT_SCALARBYTES = 32;
122
+    const CRYPTO_SCALARMULT_RISTRETTO255_BYTES = 32;
123
+    const CRYPTO_SCALARMULT_RISTRETTO255_SCALARBYTES = 32;
124
+    const CRYPTO_SHORTHASH_BYTES = 8;
125
+    const CRYPTO_SHORTHASH_KEYBYTES = 16;
126
+    const CRYPTO_SECRETBOX_KEYBYTES = 32;
127
+    const CRYPTO_SECRETBOX_MACBYTES = 16;
128
+    const CRYPTO_SECRETBOX_NONCEBYTES = 24;
129
+    const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_ABYTES = 17;
130
+    const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES = 24;
131
+    const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES = 32;
132
+    const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PUSH = 0;
133
+    const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_PULL = 1;
134
+    const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_REKEY = 2;
135
+    const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_TAG_FINAL = 3;
136
+    const CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_MESSAGEBYTES_MAX = 0x3fffffff80;
137
+    const CRYPTO_SIGN_BYTES = 64;
138
+    const CRYPTO_SIGN_SEEDBYTES = 32;
139
+    const CRYPTO_SIGN_PUBLICKEYBYTES = 32;
140
+    const CRYPTO_SIGN_SECRETKEYBYTES = 64;
141
+    const CRYPTO_SIGN_KEYPAIRBYTES = 96;
142
+    const CRYPTO_STREAM_KEYBYTES = 32;
143
+    const CRYPTO_STREAM_NONCEBYTES = 24;
144
+    const CRYPTO_STREAM_XCHACHA20_KEYBYTES = 32;
145
+    const CRYPTO_STREAM_XCHACHA20_NONCEBYTES = 24;
146
+
147
+    /**
148
+     * Add two numbers (little-endian unsigned), storing the value in the first
149
+     * parameter.
150
+     *
151
+     * This mutates $val.
152
+     *
153
+     * @param string $val
154
+     * @param string $addv
155
+     * @return void
156
+     * @throws SodiumException
157
+     */
158
+    public static function add(&$val, $addv)
159
+    {
160
+        $val_len = ParagonIE_Sodium_Core_Util::strlen($val);
161
+        $addv_len = ParagonIE_Sodium_Core_Util::strlen($addv);
162
+        if ($val_len !== $addv_len) {
163
+            throw new SodiumException('values must have the same length');
164
+        }
165
+        $A = ParagonIE_Sodium_Core_Util::stringToIntArray($val);
166
+        $B = ParagonIE_Sodium_Core_Util::stringToIntArray($addv);
167
+
168
+        $c = 0;
169
+        for ($i = 0; $i < $val_len; $i++) {
170
+            $c += ($A[$i] + $B[$i]);
171
+            $A[$i] = ($c & 0xff);
172
+            $c >>= 8;
173
+        }
174
+        $val = ParagonIE_Sodium_Core_Util::intArrayToString($A);
175
+    }
176
+
177
+    /**
178
+     * @param string $encoded
179
+     * @param int $variant
180
+     * @param string $ignore
181
+     * @return string
182
+     * @throws SodiumException
183
+     */
184
+    public static function base642bin($encoded, $variant, $ignore = '')
185
+    {
186
+        /* Type checks: */
187
+        ParagonIE_Sodium_Core_Util::declareScalarType($encoded, 'string', 1);
188
+
189
+        /** @var string $encoded */
190
+        $encoded = (string) $encoded;
191
+        if (ParagonIE_Sodium_Core_Util::strlen($encoded) === 0) {
192
+            return '';
193
+        }
194
+
195
+        // Just strip before decoding
196
+        if (!empty($ignore)) {
197
+            $encoded = str_replace($ignore, '', $encoded);
198
+        }
199
+
200
+        try {
201
+            switch ($variant) {
202
+                case self::BASE64_VARIANT_ORIGINAL:
203
+                    return ParagonIE_Sodium_Core_Base64_Original::decode($encoded, true);
204
+                case self::BASE64_VARIANT_ORIGINAL_NO_PADDING:
205
+                    return ParagonIE_Sodium_Core_Base64_Original::decode($encoded, false);
206
+                case self::BASE64_VARIANT_URLSAFE:
207
+                    return ParagonIE_Sodium_Core_Base64_UrlSafe::decode($encoded, true);
208
+                case self::BASE64_VARIANT_URLSAFE_NO_PADDING:
209
+                    return ParagonIE_Sodium_Core_Base64_UrlSafe::decode($encoded, false);
210
+                default:
211
+                    throw new SodiumException('invalid base64 variant identifier');
212
+            }
213
+        } catch (Exception $ex) {
214
+            if ($ex instanceof SodiumException) {
215
+                throw $ex;
216
+            }
217
+            throw new SodiumException('invalid base64 string');
218
+        }
219
+    }
220
+
221
+    /**
222
+     * @param string $decoded
223
+     * @param int $variant
224
+     * @return string
225
+     * @throws SodiumException
226
+     */
227
+    public static function bin2base64($decoded, $variant)
228
+    {
229
+        /* Type checks: */
230
+        ParagonIE_Sodium_Core_Util::declareScalarType($decoded, 'string', 1);
231
+        /** @var string $decoded */
232
+        $decoded = (string) $decoded;
233
+        if (ParagonIE_Sodium_Core_Util::strlen($decoded) === 0) {
234
+            return '';
235
+        }
236
+
237
+        switch ($variant) {
238
+            case self::BASE64_VARIANT_ORIGINAL:
239
+                return ParagonIE_Sodium_Core_Base64_Original::encode($decoded);
240
+            case self::BASE64_VARIANT_ORIGINAL_NO_PADDING:
241
+                return ParagonIE_Sodium_Core_Base64_Original::encodeUnpadded($decoded);
242
+            case self::BASE64_VARIANT_URLSAFE:
243
+                return ParagonIE_Sodium_Core_Base64_UrlSafe::encode($decoded);
244
+            case self::BASE64_VARIANT_URLSAFE_NO_PADDING:
245
+                return ParagonIE_Sodium_Core_Base64_UrlSafe::encodeUnpadded($decoded);
246
+            default:
247
+                throw new SodiumException('invalid base64 variant identifier');
248
+        }
249
+    }
250
+
251
+    /**
252
+     * Cache-timing-safe implementation of bin2hex().
253
+     *
254
+     * @param string $string A string (probably raw binary)
255
+     * @return string        A hexadecimal-encoded string
256
+     * @throws SodiumException
257
+     * @throws TypeError
258
+     * @psalm-suppress MixedArgument
259
+     */
260
+    public static function bin2hex($string)
261
+    {
262
+        /* Type checks: */
263
+        ParagonIE_Sodium_Core_Util::declareScalarType($string, 'string', 1);
264
+
265
+        if (self::useNewSodiumAPI()) {
266
+            return (string) sodium_bin2hex($string);
267
+        }
268
+        if (self::use_fallback('bin2hex')) {
269
+            return (string) call_user_func('\\Sodium\\bin2hex', $string);
270
+        }
271
+        return ParagonIE_Sodium_Core_Util::bin2hex($string);
272
+    }
273
+
274
+    /**
275
+     * Compare two strings, in constant-time.
276
+     * Compared to memcmp(), compare() is more useful for sorting.
277
+     *
278
+     * @param string $left  The left operand; must be a string
279
+     * @param string $right The right operand; must be a string
280
+     * @return int          If < 0 if the left operand is less than the right
281
+     *                      If = 0 if both strings are equal
282
+     *                      If > 0 if the right operand is less than the left
283
+     * @throws SodiumException
284
+     * @throws TypeError
285
+     * @psalm-suppress MixedArgument
286
+     */
287
+    public static function compare($left, $right)
288
+    {
289
+        /* Type checks: */
290
+        ParagonIE_Sodium_Core_Util::declareScalarType($left, 'string', 1);
291
+        ParagonIE_Sodium_Core_Util::declareScalarType($right, 'string', 2);
292
+
293
+        if (self::useNewSodiumAPI()) {
294
+            return (int) sodium_compare($left, $right);
295
+        }
296
+        if (self::use_fallback('compare')) {
297
+            return (int) call_user_func('\\Sodium\\compare', $left, $right);
298
+        }
299
+        return ParagonIE_Sodium_Core_Util::compare($left, $right);
300
+    }
301
+
302
+    /**
303
+     * Is AES-256-GCM even available to use?
304
+     *
305
+     * @return bool
306
+     * @psalm-suppress UndefinedFunction
307
+     * @psalm-suppress MixedInferredReturnType
308
+     * @psalm-suppress MixedReturnStatement
309
+     */
310
+    public static function crypto_aead_aes256gcm_is_available()
311
+    {
312
+        if (self::useNewSodiumAPI()) {
313
+            return sodium_crypto_aead_aes256gcm_is_available();
314
+        }
315
+        if (self::use_fallback('crypto_aead_aes256gcm_is_available')) {
316
+            return call_user_func('\\Sodium\\crypto_aead_aes256gcm_is_available');
317
+        }
318
+        if (PHP_VERSION_ID < 70100) {
319
+            // OpenSSL doesn't support AEAD before 7.1.0
320
+            return false;
321
+        }
322
+        if (!is_callable('openssl_encrypt') || !is_callable('openssl_decrypt')) {
323
+            // OpenSSL isn't installed
324
+            return false;
325
+        }
326
+        return (bool) in_array('aes-256-gcm', openssl_get_cipher_methods());
327
+    }
328
+
329
+    /**
330
+     * Authenticated Encryption with Associated Data: Decryption
331
+     *
332
+     * Algorithm:
333
+     *     AES-256-GCM
334
+     *
335
+     * This mode uses a 64-bit random nonce with a 64-bit counter.
336
+     * IETF mode uses a 96-bit random nonce with a 32-bit counter.
337
+     *
338
+     * @param string $ciphertext Encrypted message (with Poly1305 MAC appended)
339
+     * @param string $assocData  Authenticated Associated Data (unencrypted)
340
+     * @param string $nonce      Number to be used only Once; must be 8 bytes
341
+     * @param string $key        Encryption key
342
+     *
343
+     * @return string|bool       The original plaintext message
344
+     * @throws SodiumException
345
+     * @throws TypeError
346
+     * @psalm-suppress MixedArgument
347
+     * @psalm-suppress MixedInferredReturnType
348
+     * @psalm-suppress MixedReturnStatement
349
+     */
350
+    public static function crypto_aead_aes256gcm_decrypt(
351
+        $ciphertext = '',
352
+        $assocData = '',
353
+        $nonce = '',
354
+        $key = ''
355
+    ) {
356
+        if (!self::crypto_aead_aes256gcm_is_available()) {
357
+            throw new SodiumException('AES-256-GCM is not available');
358
+        }
359
+        ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
360
+        ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
361
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
362
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
363
+
364
+        /* Input validation: */
365
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AES256GCM_NPUBBYTES) {
366
+            throw new SodiumException('Nonce must be CRYPTO_AEAD_AES256GCM_NPUBBYTES long');
367
+        }
368
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AES256GCM_KEYBYTES) {
369
+            throw new SodiumException('Key must be CRYPTO_AEAD_AES256GCM_KEYBYTES long');
370
+        }
371
+        if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_AES256GCM_ABYTES) {
372
+            throw new SodiumException('Message must be at least CRYPTO_AEAD_AES256GCM_ABYTES long');
373
+        }
374
+        if (!is_callable('openssl_decrypt')) {
375
+            throw new SodiumException('The OpenSSL extension is not installed, or openssl_decrypt() is not available');
376
+        }
377
+
378
+        /** @var string $ctext */
379
+        $ctext = ParagonIE_Sodium_Core_Util::substr($ciphertext, 0, -self::CRYPTO_AEAD_AES256GCM_ABYTES);
380
+        /** @var string $authTag */
381
+        $authTag = ParagonIE_Sodium_Core_Util::substr($ciphertext, -self::CRYPTO_AEAD_AES256GCM_ABYTES, 16);
382
+        return openssl_decrypt(
383
+            $ctext,
384
+            'aes-256-gcm',
385
+            $key,
386
+            OPENSSL_RAW_DATA,
387
+            $nonce,
388
+            $authTag,
389
+            $assocData
390
+        );
391
+    }
392
+
393
+    /**
394
+     * Authenticated Encryption with Associated Data: Encryption
395
+     *
396
+     * Algorithm:
397
+     *     AES-256-GCM
398
+     *
399
+     * @param string $plaintext Message to be encrypted
400
+     * @param string $assocData Authenticated Associated Data (unencrypted)
401
+     * @param string $nonce     Number to be used only Once; must be 8 bytes
402
+     * @param string $key       Encryption key
403
+     *
404
+     * @return string           Ciphertext with a 16-byte GCM message
405
+     *                          authentication code appended
406
+     * @throws SodiumException
407
+     * @throws TypeError
408
+     * @psalm-suppress MixedArgument
409
+     */
410
+    public static function crypto_aead_aes256gcm_encrypt(
411
+        $plaintext = '',
412
+        $assocData = '',
413
+        $nonce = '',
414
+        $key = ''
415
+    ) {
416
+        if (!self::crypto_aead_aes256gcm_is_available()) {
417
+            throw new SodiumException('AES-256-GCM is not available');
418
+        }
419
+        ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
420
+        ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
421
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
422
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
423
+
424
+        /* Input validation: */
425
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_AES256GCM_NPUBBYTES) {
426
+            throw new SodiumException('Nonce must be CRYPTO_AEAD_AES256GCM_NPUBBYTES long');
427
+        }
428
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_AES256GCM_KEYBYTES) {
429
+            throw new SodiumException('Key must be CRYPTO_AEAD_AES256GCM_KEYBYTES long');
430
+        }
431
+
432
+        if (!is_callable('openssl_encrypt')) {
433
+            throw new SodiumException('The OpenSSL extension is not installed, or openssl_encrypt() is not available');
434
+        }
435
+
436
+        $authTag = '';
437
+        $ciphertext = openssl_encrypt(
438
+            $plaintext,
439
+            'aes-256-gcm',
440
+            $key,
441
+            OPENSSL_RAW_DATA,
442
+            $nonce,
443
+            $authTag,
444
+            $assocData
445
+        );
446
+        return $ciphertext . $authTag;
447
+    }
448
+
449
+    /**
450
+     * Return a secure random key for use with the AES-256-GCM
451
+     * symmetric AEAD interface.
452
+     *
453
+     * @return string
454
+     * @throws Exception
455
+     * @throws Error
456
+     */
457
+    public static function crypto_aead_aes256gcm_keygen()
458
+    {
459
+        return random_bytes(self::CRYPTO_AEAD_AES256GCM_KEYBYTES);
460
+    }
461
+
462
+    /**
463
+     * Authenticated Encryption with Associated Data: Decryption
464
+     *
465
+     * Algorithm:
466
+     *     ChaCha20-Poly1305
467
+     *
468
+     * This mode uses a 64-bit random nonce with a 64-bit counter.
469
+     * IETF mode uses a 96-bit random nonce with a 32-bit counter.
470
+     *
471
+     * @param string $ciphertext Encrypted message (with Poly1305 MAC appended)
472
+     * @param string $assocData  Authenticated Associated Data (unencrypted)
473
+     * @param string $nonce      Number to be used only Once; must be 8 bytes
474
+     * @param string $key        Encryption key
475
+     *
476
+     * @return string            The original plaintext message
477
+     * @throws SodiumException
478
+     * @throws TypeError
479
+     * @psalm-suppress MixedArgument
480
+     * @psalm-suppress MixedInferredReturnType
481
+     * @psalm-suppress MixedReturnStatement
482
+     */
483
+    public static function crypto_aead_chacha20poly1305_decrypt(
484
+        $ciphertext = '',
485
+        $assocData = '',
486
+        $nonce = '',
487
+        $key = ''
488
+    ) {
489
+        /* Type checks: */
490
+        ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
491
+        ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
492
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
493
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
494
+
495
+        /* Input validation: */
496
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) {
497
+            throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long');
498
+        }
499
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) {
500
+            throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long');
501
+        }
502
+        if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) {
503
+            throw new SodiumException('Message must be at least CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long');
504
+        }
505
+
506
+        if (self::useNewSodiumAPI()) {
507
+            /**
508
+             * @psalm-suppress InvalidReturnStatement
509
+             * @psalm-suppress FalsableReturnStatement
510
+             */
511
+            return sodium_crypto_aead_chacha20poly1305_decrypt(
512
+                $ciphertext,
513
+                $assocData,
514
+                $nonce,
515
+                $key
516
+            );
517
+        }
518
+        if (self::use_fallback('crypto_aead_chacha20poly1305_decrypt')) {
519
+            return call_user_func(
520
+                '\\Sodium\\crypto_aead_chacha20poly1305_decrypt',
521
+                $ciphertext,
522
+                $assocData,
523
+                $nonce,
524
+                $key
525
+            );
526
+        }
527
+        if (PHP_INT_SIZE === 4) {
528
+            return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_decrypt(
529
+                $ciphertext,
530
+                $assocData,
531
+                $nonce,
532
+                $key
533
+            );
534
+        }
535
+        return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_decrypt(
536
+            $ciphertext,
537
+            $assocData,
538
+            $nonce,
539
+            $key
540
+        );
541
+    }
542
+
543
+    /**
544
+     * Authenticated Encryption with Associated Data
545
+     *
546
+     * Algorithm:
547
+     *     ChaCha20-Poly1305
548
+     *
549
+     * This mode uses a 64-bit random nonce with a 64-bit counter.
550
+     * IETF mode uses a 96-bit random nonce with a 32-bit counter.
551
+     *
552
+     * @param string $plaintext Message to be encrypted
553
+     * @param string $assocData Authenticated Associated Data (unencrypted)
554
+     * @param string $nonce     Number to be used only Once; must be 8 bytes
555
+     * @param string $key       Encryption key
556
+     *
557
+     * @return string           Ciphertext with a 16-byte Poly1305 message
558
+     *                          authentication code appended
559
+     * @throws SodiumException
560
+     * @throws TypeError
561
+     * @psalm-suppress MixedArgument
562
+     */
563
+    public static function crypto_aead_chacha20poly1305_encrypt(
564
+        $plaintext = '',
565
+        $assocData = '',
566
+        $nonce = '',
567
+        $key = ''
568
+    ) {
569
+        /* Type checks: */
570
+        ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
571
+        ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
572
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
573
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
574
+
575
+        /* Input validation: */
576
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES) {
577
+            throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_NPUBBYTES long');
578
+        }
579
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) {
580
+            throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long');
581
+        }
582
+
583
+        if (self::useNewSodiumAPI()) {
584
+            return (string) sodium_crypto_aead_chacha20poly1305_encrypt(
585
+                $plaintext,
586
+                $assocData,
587
+                $nonce,
588
+                $key
589
+            );
590
+        }
591
+        if (self::use_fallback('crypto_aead_chacha20poly1305_encrypt')) {
592
+            return (string) call_user_func(
593
+                '\\Sodium\\crypto_aead_chacha20poly1305_encrypt',
594
+                $plaintext,
595
+                $assocData,
596
+                $nonce,
597
+                $key
598
+            );
599
+        }
600
+        if (PHP_INT_SIZE === 4) {
601
+            return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_encrypt(
602
+                $plaintext,
603
+                $assocData,
604
+                $nonce,
605
+                $key
606
+            );
607
+        }
608
+        return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_encrypt(
609
+            $plaintext,
610
+            $assocData,
611
+            $nonce,
612
+            $key
613
+        );
614
+    }
615
+
616
+    /**
617
+     * Authenticated Encryption with Associated Data: Decryption
618
+     *
619
+     * Algorithm:
620
+     *     ChaCha20-Poly1305
621
+     *
622
+     * IETF mode uses a 96-bit random nonce with a 32-bit counter.
623
+     * Regular mode uses a 64-bit random nonce with a 64-bit counter.
624
+     *
625
+     * @param string $ciphertext Encrypted message (with Poly1305 MAC appended)
626
+     * @param string $assocData  Authenticated Associated Data (unencrypted)
627
+     * @param string $nonce      Number to be used only Once; must be 12 bytes
628
+     * @param string $key        Encryption key
629
+     *
630
+     * @return string            The original plaintext message
631
+     * @throws SodiumException
632
+     * @throws TypeError
633
+     * @psalm-suppress MixedArgument
634
+     * @psalm-suppress MixedInferredReturnType
635
+     * @psalm-suppress MixedReturnStatement
636
+     */
637
+    public static function crypto_aead_chacha20poly1305_ietf_decrypt(
638
+        $ciphertext = '',
639
+        $assocData = '',
640
+        $nonce = '',
641
+        $key = ''
642
+    ) {
643
+        /* Type checks: */
644
+        ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
645
+        ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
646
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
647
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
648
+
649
+        /* Input validation: */
650
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) {
651
+            throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long');
652
+        }
653
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) {
654
+            throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long');
655
+        }
656
+        if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_CHACHA20POLY1305_ABYTES) {
657
+            throw new SodiumException('Message must be at least CRYPTO_AEAD_CHACHA20POLY1305_ABYTES long');
658
+        }
659
+
660
+        if (self::useNewSodiumAPI()) {
661
+            /**
662
+             * @psalm-suppress InvalidReturnStatement
663
+             * @psalm-suppress FalsableReturnStatement
664
+             */
665
+            return sodium_crypto_aead_chacha20poly1305_ietf_decrypt(
666
+                $ciphertext,
667
+                $assocData,
668
+                $nonce,
669
+                $key
670
+            );
671
+        }
672
+        if (self::use_fallback('crypto_aead_chacha20poly1305_ietf_decrypt')) {
673
+            return call_user_func(
674
+                '\\Sodium\\crypto_aead_chacha20poly1305_ietf_decrypt',
675
+                $ciphertext,
676
+                $assocData,
677
+                $nonce,
678
+                $key
679
+            );
680
+        }
681
+        if (PHP_INT_SIZE === 4) {
682
+            return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_ietf_decrypt(
683
+                $ciphertext,
684
+                $assocData,
685
+                $nonce,
686
+                $key
687
+            );
688
+        }
689
+        return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_decrypt(
690
+            $ciphertext,
691
+            $assocData,
692
+            $nonce,
693
+            $key
694
+        );
695
+    }
696
+
697
+    /**
698
+     * Return a secure random key for use with the ChaCha20-Poly1305
699
+     * symmetric AEAD interface.
700
+     *
701
+     * @return string
702
+     * @throws Exception
703
+     * @throws Error
704
+     */
705
+    public static function crypto_aead_chacha20poly1305_keygen()
706
+    {
707
+        return random_bytes(self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES);
708
+    }
709
+
710
+    /**
711
+     * Authenticated Encryption with Associated Data
712
+     *
713
+     * Algorithm:
714
+     *     ChaCha20-Poly1305
715
+     *
716
+     * IETF mode uses a 96-bit random nonce with a 32-bit counter.
717
+     * Regular mode uses a 64-bit random nonce with a 64-bit counter.
718
+     *
719
+     * @param string $plaintext Message to be encrypted
720
+     * @param string $assocData Authenticated Associated Data (unencrypted)
721
+     * @param string $nonce Number to be used only Once; must be 8 bytes
722
+     * @param string $key Encryption key
723
+     *
724
+     * @return string           Ciphertext with a 16-byte Poly1305 message
725
+     *                          authentication code appended
726
+     * @throws SodiumException
727
+     * @throws TypeError
728
+     * @psalm-suppress MixedArgument
729
+     */
730
+    public static function crypto_aead_chacha20poly1305_ietf_encrypt(
731
+        $plaintext = '',
732
+        $assocData = '',
733
+        $nonce = '',
734
+        $key = ''
735
+    ) {
736
+        /* Type checks: */
737
+        ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
738
+        if (!is_null($assocData)) {
739
+            ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
740
+        }
741
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
742
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
743
+
744
+        /* Input validation: */
745
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES) {
746
+            throw new SodiumException('Nonce must be CRYPTO_AEAD_CHACHA20POLY1305_IETF_NPUBBYTES long');
747
+        }
748
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES) {
749
+            throw new SodiumException('Key must be CRYPTO_AEAD_CHACHA20POLY1305_KEYBYTES long');
750
+        }
751
+
752
+        if (self::useNewSodiumAPI()) {
753
+            return (string) sodium_crypto_aead_chacha20poly1305_ietf_encrypt(
754
+                $plaintext,
755
+                $assocData,
756
+                $nonce,
757
+                $key
758
+            );
759
+        }
760
+        if (self::use_fallback('crypto_aead_chacha20poly1305_ietf_encrypt')) {
761
+            return (string) call_user_func(
762
+                '\\Sodium\\crypto_aead_chacha20poly1305_ietf_encrypt',
763
+                $plaintext,
764
+                $assocData,
765
+                $nonce,
766
+                $key
767
+            );
768
+        }
769
+        if (PHP_INT_SIZE === 4) {
770
+            return ParagonIE_Sodium_Crypto32::aead_chacha20poly1305_ietf_encrypt(
771
+                $plaintext,
772
+                $assocData,
773
+                $nonce,
774
+                $key
775
+            );
776
+        }
777
+        return ParagonIE_Sodium_Crypto::aead_chacha20poly1305_ietf_encrypt(
778
+            $plaintext,
779
+            $assocData,
780
+            $nonce,
781
+            $key
782
+        );
783
+    }
784
+
785
+    /**
786
+     * Return a secure random key for use with the ChaCha20-Poly1305
787
+     * symmetric AEAD interface. (IETF version)
788
+     *
789
+     * @return string
790
+     * @throws Exception
791
+     * @throws Error
792
+     */
793
+    public static function crypto_aead_chacha20poly1305_ietf_keygen()
794
+    {
795
+        return random_bytes(self::CRYPTO_AEAD_CHACHA20POLY1305_IETF_KEYBYTES);
796
+    }
797
+
798
+    /**
799
+     * Authenticated Encryption with Associated Data: Decryption
800
+     *
801
+     * Algorithm:
802
+     *     XChaCha20-Poly1305
803
+     *
804
+     * This mode uses a 64-bit random nonce with a 64-bit counter.
805
+     * IETF mode uses a 96-bit random nonce with a 32-bit counter.
806
+     *
807
+     * @param string $ciphertext   Encrypted message (with Poly1305 MAC appended)
808
+     * @param string $assocData    Authenticated Associated Data (unencrypted)
809
+     * @param string $nonce        Number to be used only Once; must be 8 bytes
810
+     * @param string $key          Encryption key
811
+     * @param bool   $dontFallback Don't fallback to ext/sodium
812
+     *
813
+     * @return string|bool         The original plaintext message
814
+     * @throws SodiumException
815
+     * @throws TypeError
816
+     * @psalm-suppress MixedArgument
817
+     */
818
+    public static function crypto_aead_xchacha20poly1305_ietf_decrypt(
819
+        $ciphertext = '',
820
+        $assocData = '',
821
+        $nonce = '',
822
+        $key = '',
823
+        $dontFallback = false
824
+    ) {
825
+        /* Type checks: */
826
+        ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
827
+        if (!is_null($assocData)) {
828
+            ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
829
+        } else {
830
+            $assocData = '';
831
+        }
832
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
833
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
834
+
835
+        /* Input validation: */
836
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) {
837
+            throw new SodiumException('Nonce must be CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES long');
838
+        }
839
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) {
840
+            throw new SodiumException('Key must be CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES long');
841
+        }
842
+        if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES) {
843
+            throw new SodiumException('Message must be at least CRYPTO_AEAD_XCHACHA20POLY1305_IETF_ABYTES long');
844
+        }
845
+        if (self::useNewSodiumAPI() && !$dontFallback) {
846
+            if (is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_decrypt')) {
847
+                return sodium_crypto_aead_xchacha20poly1305_ietf_decrypt(
848
+                    $ciphertext,
849
+                    $assocData,
850
+                    $nonce,
851
+                    $key
852
+                );
853
+            }
854
+        }
855
+
856
+        if (PHP_INT_SIZE === 4) {
857
+            return ParagonIE_Sodium_Crypto32::aead_xchacha20poly1305_ietf_decrypt(
858
+                $ciphertext,
859
+                $assocData,
860
+                $nonce,
861
+                $key
862
+            );
863
+        }
864
+        return ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_decrypt(
865
+            $ciphertext,
866
+            $assocData,
867
+            $nonce,
868
+            $key
869
+        );
870
+    }
871
+
872
+    /**
873
+     * Authenticated Encryption with Associated Data
874
+     *
875
+     * Algorithm:
876
+     *     XChaCha20-Poly1305
877
+     *
878
+     * This mode uses a 64-bit random nonce with a 64-bit counter.
879
+     * IETF mode uses a 96-bit random nonce with a 32-bit counter.
880
+     *
881
+     * @param string $plaintext    Message to be encrypted
882
+     * @param string $assocData    Authenticated Associated Data (unencrypted)
883
+     * @param string $nonce        Number to be used only Once; must be 8 bytes
884
+     * @param string $key          Encryption key
885
+     * @param bool   $dontFallback Don't fallback to ext/sodium
886
+     *
887
+     * @return string           Ciphertext with a 16-byte Poly1305 message
888
+     *                          authentication code appended
889
+     * @throws SodiumException
890
+     * @throws TypeError
891
+     * @psalm-suppress MixedArgument
892
+     */
893
+    public static function crypto_aead_xchacha20poly1305_ietf_encrypt(
894
+        $plaintext = '',
895
+        $assocData = '',
896
+        $nonce = '',
897
+        $key = '',
898
+        $dontFallback = false
899
+    ) {
900
+        /* Type checks: */
901
+        ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
902
+        if (!is_null($assocData)) {
903
+            ParagonIE_Sodium_Core_Util::declareScalarType($assocData, 'string', 2);
904
+        } else {
905
+            $assocData = '';
906
+        }
907
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 3);
908
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
909
+
910
+        /* Input validation: */
911
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_NPUBBYTES) {
912
+            throw new SodiumException('Nonce must be CRYPTO_AEAD_XCHACHA20POLY1305_NPUBBYTES long');
913
+        }
914
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES) {
915
+            throw new SodiumException('Key must be CRYPTO_AEAD_XCHACHA20POLY1305_KEYBYTES long');
916
+        }
917
+        if (self::useNewSodiumAPI() && !$dontFallback) {
918
+            if (is_callable('sodium_crypto_aead_xchacha20poly1305_ietf_encrypt')) {
919
+                return sodium_crypto_aead_xchacha20poly1305_ietf_encrypt(
920
+                    $plaintext,
921
+                    $assocData,
922
+                    $nonce,
923
+                    $key
924
+                );
925
+            }
926
+        }
927
+
928
+        if (PHP_INT_SIZE === 4) {
929
+            return ParagonIE_Sodium_Crypto32::aead_xchacha20poly1305_ietf_encrypt(
930
+                $plaintext,
931
+                $assocData,
932
+                $nonce,
933
+                $key
934
+            );
935
+        }
936
+        return ParagonIE_Sodium_Crypto::aead_xchacha20poly1305_ietf_encrypt(
937
+            $plaintext,
938
+            $assocData,
939
+            $nonce,
940
+            $key
941
+        );
942
+    }
943
+
944
+    /**
945
+     * Return a secure random key for use with the XChaCha20-Poly1305
946
+     * symmetric AEAD interface.
947
+     *
948
+     * @return string
949
+     * @throws Exception
950
+     * @throws Error
951
+     */
952
+    public static function crypto_aead_xchacha20poly1305_ietf_keygen()
953
+    {
954
+        return random_bytes(self::CRYPTO_AEAD_XCHACHA20POLY1305_IETF_KEYBYTES);
955
+    }
956
+
957
+    /**
958
+     * Authenticate a message. Uses symmetric-key cryptography.
959
+     *
960
+     * Algorithm:
961
+     *     HMAC-SHA512-256. Which is HMAC-SHA-512 truncated to 256 bits.
962
+     *     Not to be confused with HMAC-SHA-512/256 which would use the
963
+     *     SHA-512/256 hash function (uses different initial parameters
964
+     *     but still truncates to 256 bits to sidestep length-extension
965
+     *     attacks).
966
+     *
967
+     * @param string $message Message to be authenticated
968
+     * @param string $key Symmetric authentication key
969
+     * @return string         Message authentication code
970
+     * @throws SodiumException
971
+     * @throws TypeError
972
+     * @psalm-suppress MixedArgument
973
+     */
974
+    public static function crypto_auth($message, $key)
975
+    {
976
+        /* Type checks: */
977
+        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
978
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2);
979
+
980
+        /* Input validation: */
981
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AUTH_KEYBYTES) {
982
+            throw new SodiumException('Argument 2 must be CRYPTO_AUTH_KEYBYTES long.');
983
+        }
984
+
985
+        if (self::useNewSodiumAPI()) {
986
+            return (string) sodium_crypto_auth($message, $key);
987
+        }
988
+        if (self::use_fallback('crypto_auth')) {
989
+            return (string) call_user_func('\\Sodium\\crypto_auth', $message, $key);
990
+        }
991
+        if (PHP_INT_SIZE === 4) {
992
+            return ParagonIE_Sodium_Crypto32::auth($message, $key);
993
+        }
994
+        return ParagonIE_Sodium_Crypto::auth($message, $key);
995
+    }
996
+
997
+    /**
998
+     * @return string
999
+     * @throws Exception
1000
+     * @throws Error
1001
+     */
1002
+    public static function crypto_auth_keygen()
1003
+    {
1004
+        return random_bytes(self::CRYPTO_AUTH_KEYBYTES);
1005
+    }
1006
+
1007
+    /**
1008
+     * Verify the MAC of a message previously authenticated with crypto_auth.
1009
+     *
1010
+     * @param string $mac Message authentication code
1011
+     * @param string $message Message whose authenticity you are attempting to
1012
+     *                        verify (with a given MAC and key)
1013
+     * @param string $key Symmetric authentication key
1014
+     * @return bool           TRUE if authenticated, FALSE otherwise
1015
+     * @throws SodiumException
1016
+     * @throws TypeError
1017
+     * @psalm-suppress MixedArgument
1018
+     */
1019
+    public static function crypto_auth_verify($mac, $message, $key)
1020
+    {
1021
+        /* Type checks: */
1022
+        ParagonIE_Sodium_Core_Util::declareScalarType($mac, 'string', 1);
1023
+        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2);
1024
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
1025
+
1026
+        /* Input validation: */
1027
+        if (ParagonIE_Sodium_Core_Util::strlen($mac) !== self::CRYPTO_AUTH_BYTES) {
1028
+            throw new SodiumException('Argument 1 must be CRYPTO_AUTH_BYTES long.');
1029
+        }
1030
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_AUTH_KEYBYTES) {
1031
+            throw new SodiumException('Argument 3 must be CRYPTO_AUTH_KEYBYTES long.');
1032
+        }
1033
+
1034
+        if (self::useNewSodiumAPI()) {
1035
+            return (bool) sodium_crypto_auth_verify($mac, $message, $key);
1036
+        }
1037
+        if (self::use_fallback('crypto_auth_verify')) {
1038
+            return (bool) call_user_func('\\Sodium\\crypto_auth_verify', $mac, $message, $key);
1039
+        }
1040
+        if (PHP_INT_SIZE === 4) {
1041
+            return ParagonIE_Sodium_Crypto32::auth_verify($mac, $message, $key);
1042
+        }
1043
+        return ParagonIE_Sodium_Crypto::auth_verify($mac, $message, $key);
1044
+    }
1045
+
1046
+    /**
1047
+     * Authenticated asymmetric-key encryption. Both the sender and recipient
1048
+     * may decrypt messages.
1049
+     *
1050
+     * Algorithm: X25519-XSalsa20-Poly1305.
1051
+     *     X25519: Elliptic-Curve Diffie Hellman over Curve25519.
1052
+     *     XSalsa20: Extended-nonce variant of salsa20.
1053
+     *     Poyl1305: Polynomial MAC for one-time message authentication.
1054
+     *
1055
+     * @param string $plaintext The message to be encrypted
1056
+     * @param string $nonce A Number to only be used Once; must be 24 bytes
1057
+     * @param string $keypair Your secret key and your recipient's public key
1058
+     * @return string           Ciphertext with 16-byte Poly1305 MAC
1059
+     * @throws SodiumException
1060
+     * @throws TypeError
1061
+     * @psalm-suppress MixedArgument
1062
+     */
1063
+    public static function crypto_box($plaintext, $nonce, $keypair)
1064
+    {
1065
+        /* Type checks: */
1066
+        ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
1067
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
1068
+        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 3);
1069
+
1070
+        /* Input validation: */
1071
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_BOX_NONCEBYTES) {
1072
+            throw new SodiumException('Argument 2 must be CRYPTO_BOX_NONCEBYTES long.');
1073
+        }
1074
+        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) {
1075
+            throw new SodiumException('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES long.');
1076
+        }
1077
+
1078
+        if (self::useNewSodiumAPI()) {
1079
+            return (string) sodium_crypto_box($plaintext, $nonce, $keypair);
1080
+        }
1081
+        if (self::use_fallback('crypto_box')) {
1082
+            return (string) call_user_func('\\Sodium\\crypto_box', $plaintext, $nonce, $keypair);
1083
+        }
1084
+        if (PHP_INT_SIZE === 4) {
1085
+            return ParagonIE_Sodium_Crypto32::box($plaintext, $nonce, $keypair);
1086
+        }
1087
+        return ParagonIE_Sodium_Crypto::box($plaintext, $nonce, $keypair);
1088
+    }
1089
+
1090
+    /**
1091
+     * Anonymous public-key encryption. Only the recipient may decrypt messages.
1092
+     *
1093
+     * Algorithm: X25519-XSalsa20-Poly1305, as with crypto_box.
1094
+     *     The sender's X25519 keypair is ephemeral.
1095
+     *     Nonce is generated from the BLAKE2b hash of both public keys.
1096
+     *
1097
+     * This provides ciphertext integrity.
1098
+     *
1099
+     * @param string $plaintext Message to be sealed
1100
+     * @param string $publicKey Your recipient's public key
1101
+     * @return string           Sealed message that only your recipient can
1102
+     *                          decrypt
1103
+     * @throws SodiumException
1104
+     * @throws TypeError
1105
+     * @psalm-suppress MixedArgument
1106
+     */
1107
+    public static function crypto_box_seal($plaintext, $publicKey)
1108
+    {
1109
+        /* Type checks: */
1110
+        ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
1111
+        ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2);
1112
+
1113
+        /* Input validation: */
1114
+        if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
1115
+            throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
1116
+        }
1117
+
1118
+        if (self::useNewSodiumAPI()) {
1119
+            return (string) sodium_crypto_box_seal($plaintext, $publicKey);
1120
+        }
1121
+        if (self::use_fallback('crypto_box_seal')) {
1122
+            return (string) call_user_func('\\Sodium\\crypto_box_seal', $plaintext, $publicKey);
1123
+        }
1124
+        if (PHP_INT_SIZE === 4) {
1125
+            return ParagonIE_Sodium_Crypto32::box_seal($plaintext, $publicKey);
1126
+        }
1127
+        return ParagonIE_Sodium_Crypto::box_seal($plaintext, $publicKey);
1128
+    }
1129
+
1130
+    /**
1131
+     * Opens a message encrypted with crypto_box_seal(). Requires
1132
+     * the recipient's keypair (sk || pk) to decrypt successfully.
1133
+     *
1134
+     * This validates ciphertext integrity.
1135
+     *
1136
+     * @param string $ciphertext Sealed message to be opened
1137
+     * @param string $keypair    Your crypto_box keypair
1138
+     * @return string            The original plaintext message
1139
+     * @throws SodiumException
1140
+     * @throws TypeError
1141
+     * @psalm-suppress MixedArgument
1142
+     * @psalm-suppress MixedInferredReturnType
1143
+     * @psalm-suppress MixedReturnStatement
1144
+     */
1145
+    public static function crypto_box_seal_open($ciphertext, $keypair)
1146
+    {
1147
+        /* Type checks: */
1148
+        ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
1149
+        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 2);
1150
+
1151
+        /* Input validation: */
1152
+        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) {
1153
+            throw new SodiumException('Argument 2 must be CRYPTO_BOX_KEYPAIRBYTES long.');
1154
+        }
1155
+
1156
+        if (self::useNewSodiumAPI()) {
1157
+            /**
1158
+             * @psalm-suppress InvalidReturnStatement
1159
+             * @psalm-suppress FalsableReturnStatement
1160
+             */
1161
+            return sodium_crypto_box_seal_open($ciphertext, $keypair);
1162
+        }
1163
+        if (self::use_fallback('crypto_box_seal_open')) {
1164
+            return call_user_func('\\Sodium\\crypto_box_seal_open', $ciphertext, $keypair);
1165
+        }
1166
+        if (PHP_INT_SIZE === 4) {
1167
+            return ParagonIE_Sodium_Crypto32::box_seal_open($ciphertext, $keypair);
1168
+        }
1169
+        return ParagonIE_Sodium_Crypto::box_seal_open($ciphertext, $keypair);
1170
+    }
1171
+
1172
+    /**
1173
+     * Generate a new random X25519 keypair.
1174
+     *
1175
+     * @return string A 64-byte string; the first 32 are your secret key, while
1176
+     *                the last 32 are your public key. crypto_box_secretkey()
1177
+     *                and crypto_box_publickey() exist to separate them so you
1178
+     *                don't accidentally get them mixed up!
1179
+     * @throws SodiumException
1180
+     * @throws TypeError
1181
+     * @psalm-suppress MixedArgument
1182
+     */
1183
+    public static function crypto_box_keypair()
1184
+    {
1185
+        if (self::useNewSodiumAPI()) {
1186
+            return (string) sodium_crypto_box_keypair();
1187
+        }
1188
+        if (self::use_fallback('crypto_box_keypair')) {
1189
+            return (string) call_user_func('\\Sodium\\crypto_box_keypair');
1190
+        }
1191
+        if (PHP_INT_SIZE === 4) {
1192
+            return ParagonIE_Sodium_Crypto32::box_keypair();
1193
+        }
1194
+        return ParagonIE_Sodium_Crypto::box_keypair();
1195
+    }
1196
+
1197
+    /**
1198
+     * Combine two keys into a keypair for use in library methods that expect
1199
+     * a keypair. This doesn't necessarily have to be the same person's keys.
1200
+     *
1201
+     * @param string $secretKey Secret key
1202
+     * @param string $publicKey Public key
1203
+     * @return string    Keypair
1204
+     * @throws SodiumException
1205
+     * @throws TypeError
1206
+     * @psalm-suppress MixedArgument
1207
+     */
1208
+    public static function crypto_box_keypair_from_secretkey_and_publickey($secretKey, $publicKey)
1209
+    {
1210
+        /* Type checks: */
1211
+        ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
1212
+        ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2);
1213
+
1214
+        /* Input validation: */
1215
+        if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
1216
+            throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
1217
+        }
1218
+        if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
1219
+            throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
1220
+        }
1221
+
1222
+        if (self::useNewSodiumAPI()) {
1223
+            return (string) sodium_crypto_box_keypair_from_secretkey_and_publickey($secretKey, $publicKey);
1224
+        }
1225
+        if (self::use_fallback('crypto_box_keypair_from_secretkey_and_publickey')) {
1226
+            return (string) call_user_func('\\Sodium\\crypto_box_keypair_from_secretkey_and_publickey', $secretKey, $publicKey);
1227
+        }
1228
+        if (PHP_INT_SIZE === 4) {
1229
+            return ParagonIE_Sodium_Crypto32::box_keypair_from_secretkey_and_publickey($secretKey, $publicKey);
1230
+        }
1231
+        return ParagonIE_Sodium_Crypto::box_keypair_from_secretkey_and_publickey($secretKey, $publicKey);
1232
+    }
1233
+
1234
+    /**
1235
+     * Decrypt a message previously encrypted with crypto_box().
1236
+     *
1237
+     * @param string $ciphertext Encrypted message
1238
+     * @param string $nonce      Number to only be used Once; must be 24 bytes
1239
+     * @param string $keypair    Your secret key and the sender's public key
1240
+     * @return string            The original plaintext message
1241
+     * @throws SodiumException
1242
+     * @throws TypeError
1243
+     * @psalm-suppress MixedArgument
1244
+     * @psalm-suppress MixedInferredReturnType
1245
+     * @psalm-suppress MixedReturnStatement
1246
+     */
1247
+    public static function crypto_box_open($ciphertext, $nonce, $keypair)
1248
+    {
1249
+        /* Type checks: */
1250
+        ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
1251
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
1252
+        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 3);
1253
+
1254
+        /* Input validation: */
1255
+        if (ParagonIE_Sodium_Core_Util::strlen($ciphertext) < self::CRYPTO_BOX_MACBYTES) {
1256
+            throw new SodiumException('Argument 1 must be at least CRYPTO_BOX_MACBYTES long.');
1257
+        }
1258
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_BOX_NONCEBYTES) {
1259
+            throw new SodiumException('Argument 2 must be CRYPTO_BOX_NONCEBYTES long.');
1260
+        }
1261
+        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) {
1262
+            throw new SodiumException('Argument 3 must be CRYPTO_BOX_KEYPAIRBYTES long.');
1263
+        }
1264
+
1265
+        if (self::useNewSodiumAPI()) {
1266
+            /**
1267
+             * @psalm-suppress InvalidReturnStatement
1268
+             * @psalm-suppress FalsableReturnStatement
1269
+             */
1270
+            return sodium_crypto_box_open($ciphertext, $nonce, $keypair);
1271
+        }
1272
+        if (self::use_fallback('crypto_box_open')) {
1273
+            return call_user_func('\\Sodium\\crypto_box_open', $ciphertext, $nonce, $keypair);
1274
+        }
1275
+        if (PHP_INT_SIZE === 4) {
1276
+            return ParagonIE_Sodium_Crypto32::box_open($ciphertext, $nonce, $keypair);
1277
+        }
1278
+        return ParagonIE_Sodium_Crypto::box_open($ciphertext, $nonce, $keypair);
1279
+    }
1280
+
1281
+    /**
1282
+     * Extract the public key from a crypto_box keypair.
1283
+     *
1284
+     * @param string $keypair Keypair containing secret and public key
1285
+     * @return string         Your crypto_box public key
1286
+     * @throws SodiumException
1287
+     * @throws TypeError
1288
+     * @psalm-suppress MixedArgument
1289
+     */
1290
+    public static function crypto_box_publickey($keypair)
1291
+    {
1292
+        /* Type checks: */
1293
+        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
1294
+
1295
+        /* Input validation: */
1296
+        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) {
1297
+            throw new SodiumException('Argument 1 must be CRYPTO_BOX_KEYPAIRBYTES long.');
1298
+        }
1299
+
1300
+        if (self::useNewSodiumAPI()) {
1301
+            return (string) sodium_crypto_box_publickey($keypair);
1302
+        }
1303
+        if (self::use_fallback('crypto_box_publickey')) {
1304
+            return (string) call_user_func('\\Sodium\\crypto_box_publickey', $keypair);
1305
+        }
1306
+        if (PHP_INT_SIZE === 4) {
1307
+            return ParagonIE_Sodium_Crypto32::box_publickey($keypair);
1308
+        }
1309
+        return ParagonIE_Sodium_Crypto::box_publickey($keypair);
1310
+    }
1311
+
1312
+    /**
1313
+     * Calculate the X25519 public key from a given X25519 secret key.
1314
+     *
1315
+     * @param string $secretKey Any X25519 secret key
1316
+     * @return string           The corresponding X25519 public key
1317
+     * @throws SodiumException
1318
+     * @throws TypeError
1319
+     * @psalm-suppress MixedArgument
1320
+     */
1321
+    public static function crypto_box_publickey_from_secretkey($secretKey)
1322
+    {
1323
+        /* Type checks: */
1324
+        ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
1325
+
1326
+        /* Input validation: */
1327
+        if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
1328
+            throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
1329
+        }
1330
+
1331
+        if (self::useNewSodiumAPI()) {
1332
+            return (string) sodium_crypto_box_publickey_from_secretkey($secretKey);
1333
+        }
1334
+        if (self::use_fallback('crypto_box_publickey_from_secretkey')) {
1335
+            return (string) call_user_func('\\Sodium\\crypto_box_publickey_from_secretkey', $secretKey);
1336
+        }
1337
+        if (PHP_INT_SIZE === 4) {
1338
+            return ParagonIE_Sodium_Crypto32::box_publickey_from_secretkey($secretKey);
1339
+        }
1340
+        return ParagonIE_Sodium_Crypto::box_publickey_from_secretkey($secretKey);
1341
+    }
1342
+
1343
+    /**
1344
+     * Extract the secret key from a crypto_box keypair.
1345
+     *
1346
+     * @param string $keypair
1347
+     * @return string         Your crypto_box secret key
1348
+     * @throws SodiumException
1349
+     * @throws TypeError
1350
+     * @psalm-suppress MixedArgument
1351
+     */
1352
+    public static function crypto_box_secretkey($keypair)
1353
+    {
1354
+        /* Type checks: */
1355
+        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
1356
+
1357
+        /* Input validation: */
1358
+        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_BOX_KEYPAIRBYTES) {
1359
+            throw new SodiumException('Argument 1 must be CRYPTO_BOX_KEYPAIRBYTES long.');
1360
+        }
1361
+
1362
+        if (self::useNewSodiumAPI()) {
1363
+            return (string) sodium_crypto_box_secretkey($keypair);
1364
+        }
1365
+        if (self::use_fallback('crypto_box_secretkey')) {
1366
+            return (string) call_user_func('\\Sodium\\crypto_box_secretkey', $keypair);
1367
+        }
1368
+        if (PHP_INT_SIZE === 4) {
1369
+            return ParagonIE_Sodium_Crypto32::box_secretkey($keypair);
1370
+        }
1371
+        return ParagonIE_Sodium_Crypto::box_secretkey($keypair);
1372
+    }
1373
+
1374
+    /**
1375
+     * Generate an X25519 keypair from a seed.
1376
+     *
1377
+     * @param string $seed
1378
+     * @return string
1379
+     * @throws SodiumException
1380
+     * @throws TypeError
1381
+     * @psalm-suppress MixedArgument
1382
+     * @psalm-suppress UndefinedFunction
1383
+     */
1384
+    public static function crypto_box_seed_keypair($seed)
1385
+    {
1386
+        /* Type checks: */
1387
+        ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1);
1388
+
1389
+        if (self::useNewSodiumAPI()) {
1390
+            return (string) sodium_crypto_box_seed_keypair($seed);
1391
+        }
1392
+        if (self::use_fallback('crypto_box_seed_keypair')) {
1393
+            return (string) call_user_func('\\Sodium\\crypto_box_seed_keypair', $seed);
1394
+        }
1395
+        if (PHP_INT_SIZE === 4) {
1396
+            return ParagonIE_Sodium_Crypto32::box_seed_keypair($seed);
1397
+        }
1398
+        return ParagonIE_Sodium_Crypto::box_seed_keypair($seed);
1399
+    }
1400
+
1401
+    /**
1402
+     * Calculates a BLAKE2b hash, with an optional key.
1403
+     *
1404
+     * @param string      $message The message to be hashed
1405
+     * @param string|null $key     If specified, must be a string between 16
1406
+     *                             and 64 bytes long
1407
+     * @param int         $length  Output length in bytes; must be between 16
1408
+     *                             and 64 (default = 32)
1409
+     * @return string              Raw binary
1410
+     * @throws SodiumException
1411
+     * @throws TypeError
1412
+     * @psalm-suppress MixedArgument
1413
+     */
1414
+    public static function crypto_generichash($message, $key = '', $length = self::CRYPTO_GENERICHASH_BYTES)
1415
+    {
1416
+        /* Type checks: */
1417
+        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
1418
+        if (is_null($key)) {
1419
+            $key = '';
1420
+        }
1421
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2);
1422
+        ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 3);
1423
+
1424
+        /* Input validation: */
1425
+        if (!empty($key)) {
1426
+            if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) {
1427
+                throw new SodiumException('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.');
1428
+            }
1429
+            if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) {
1430
+                throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.');
1431
+            }
1432
+        }
1433
+
1434
+        if (self::useNewSodiumAPI()) {
1435
+            return (string) sodium_crypto_generichash($message, $key, $length);
1436
+        }
1437
+        if (self::use_fallback('crypto_generichash')) {
1438
+            return (string) call_user_func('\\Sodium\\crypto_generichash', $message, $key, $length);
1439
+        }
1440
+        if (PHP_INT_SIZE === 4) {
1441
+            return ParagonIE_Sodium_Crypto32::generichash($message, $key, $length);
1442
+        }
1443
+        return ParagonIE_Sodium_Crypto::generichash($message, $key, $length);
1444
+    }
1445
+
1446
+    /**
1447
+     * Get the final BLAKE2b hash output for a given context.
1448
+     *
1449
+     * @param string $ctx BLAKE2 hashing context. Generated by crypto_generichash_init().
1450
+     * @param int $length Hash output size.
1451
+     * @return string     Final BLAKE2b hash.
1452
+     * @throws SodiumException
1453
+     * @throws TypeError
1454
+     * @psalm-suppress MixedArgument
1455
+     * @psalm-suppress ReferenceConstraintViolation
1456
+     * @psalm-suppress ConflictingReferenceConstraint
1457
+     */
1458
+    public static function crypto_generichash_final(&$ctx, $length = self::CRYPTO_GENERICHASH_BYTES)
1459
+    {
1460
+        /* Type checks: */
1461
+        ParagonIE_Sodium_Core_Util::declareScalarType($ctx, 'string', 1);
1462
+        ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2);
1463
+
1464
+        if (self::useNewSodiumAPI()) {
1465
+            return sodium_crypto_generichash_final($ctx, $length);
1466
+        }
1467
+        if (self::use_fallback('crypto_generichash_final')) {
1468
+            $func = '\\Sodium\\crypto_generichash_final';
1469
+            return (string) $func($ctx, $length);
1470
+        }
1471
+        if ($length < 1) {
1472
+            try {
1473
+                self::memzero($ctx);
1474
+            } catch (SodiumException $ex) {
1475
+                unset($ctx);
1476
+            }
1477
+            return '';
1478
+        }
1479
+        if (PHP_INT_SIZE === 4) {
1480
+            $result = ParagonIE_Sodium_Crypto32::generichash_final($ctx, $length);
1481
+        } else {
1482
+            $result = ParagonIE_Sodium_Crypto::generichash_final($ctx, $length);
1483
+        }
1484
+        try {
1485
+            self::memzero($ctx);
1486
+        } catch (SodiumException $ex) {
1487
+            unset($ctx);
1488
+        }
1489
+        return $result;
1490
+    }
1491
+
1492
+    /**
1493
+     * Initialize a BLAKE2b hashing context, for use in a streaming interface.
1494
+     *
1495
+     * @param string|null $key If specified must be a string between 16 and 64 bytes
1496
+     * @param int $length      The size of the desired hash output
1497
+     * @return string          A BLAKE2 hashing context, encoded as a string
1498
+     *                         (To be 100% compatible with ext/libsodium)
1499
+     * @throws SodiumException
1500
+     * @throws TypeError
1501
+     * @psalm-suppress MixedArgument
1502
+     */
1503
+    public static function crypto_generichash_init($key = '', $length = self::CRYPTO_GENERICHASH_BYTES)
1504
+    {
1505
+        /* Type checks: */
1506
+        if (is_null($key)) {
1507
+            $key = '';
1508
+        }
1509
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 1);
1510
+        ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2);
1511
+
1512
+        /* Input validation: */
1513
+        if (!empty($key)) {
1514
+            if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) {
1515
+                throw new SodiumException('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.');
1516
+            }
1517
+            if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) {
1518
+                throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.');
1519
+            }
1520
+        }
1521
+
1522
+        if (self::useNewSodiumAPI()) {
1523
+            return sodium_crypto_generichash_init($key, $length);
1524
+        }
1525
+        if (self::use_fallback('crypto_generichash_init')) {
1526
+            return (string) call_user_func('\\Sodium\\crypto_generichash_init', $key, $length);
1527
+        }
1528
+        if (PHP_INT_SIZE === 4) {
1529
+            return ParagonIE_Sodium_Crypto32::generichash_init($key, $length);
1530
+        }
1531
+        return ParagonIE_Sodium_Crypto::generichash_init($key, $length);
1532
+    }
1533
+
1534
+    /**
1535
+     * Initialize a BLAKE2b hashing context, for use in a streaming interface.
1536
+     *
1537
+     * @param string|null $key If specified must be a string between 16 and 64 bytes
1538
+     * @param int $length      The size of the desired hash output
1539
+     * @param string $salt     Salt (up to 16 bytes)
1540
+     * @param string $personal Personalization string (up to 16 bytes)
1541
+     * @return string          A BLAKE2 hashing context, encoded as a string
1542
+     *                         (To be 100% compatible with ext/libsodium)
1543
+     * @throws SodiumException
1544
+     * @throws TypeError
1545
+     * @psalm-suppress MixedArgument
1546
+     */
1547
+    public static function crypto_generichash_init_salt_personal(
1548
+        $key = '',
1549
+        $length = self::CRYPTO_GENERICHASH_BYTES,
1550
+        $salt = '',
1551
+        $personal = ''
1552
+    ) {
1553
+        /* Type checks: */
1554
+        if (is_null($key)) {
1555
+            $key = '';
1556
+        }
1557
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 1);
1558
+        ParagonIE_Sodium_Core_Util::declareScalarType($length, 'int', 2);
1559
+        ParagonIE_Sodium_Core_Util::declareScalarType($salt, 'string', 3);
1560
+        ParagonIE_Sodium_Core_Util::declareScalarType($personal, 'string', 4);
1561
+        $salt = str_pad($salt, 16, "\0", STR_PAD_RIGHT);
1562
+        $personal = str_pad($personal, 16, "\0", STR_PAD_RIGHT);
1563
+
1564
+        /* Input validation: */
1565
+        if (!empty($key)) {
1566
+            /*
1567
+            if (ParagonIE_Sodium_Core_Util::strlen($key) < self::CRYPTO_GENERICHASH_KEYBYTES_MIN) {
1568
+                throw new SodiumException('Unsupported key size. Must be at least CRYPTO_GENERICHASH_KEYBYTES_MIN bytes long.');
1569
+            }
1570
+            */
1571
+            if (ParagonIE_Sodium_Core_Util::strlen($key) > self::CRYPTO_GENERICHASH_KEYBYTES_MAX) {
1572
+                throw new SodiumException('Unsupported key size. Must be at most CRYPTO_GENERICHASH_KEYBYTES_MAX bytes long.');
1573
+            }
1574
+        }
1575
+        if (PHP_INT_SIZE === 4) {
1576
+            return ParagonIE_Sodium_Crypto32::generichash_init_salt_personal($key, $length, $salt, $personal);
1577
+        }
1578
+        return ParagonIE_Sodium_Crypto::generichash_init_salt_personal($key, $length, $salt, $personal);
1579
+    }
1580
+
1581
+    /**
1582
+     * Update a BLAKE2b hashing context with additional data.
1583
+     *
1584
+     * @param string $ctx    BLAKE2 hashing context. Generated by crypto_generichash_init().
1585
+     *                       $ctx is passed by reference and gets updated in-place.
1586
+     * @param-out string $ctx
1587
+     * @param string $message The message to append to the existing hash state.
1588
+     * @return void
1589
+     * @throws SodiumException
1590
+     * @throws TypeError
1591
+     * @psalm-suppress MixedArgument
1592
+     * @psalm-suppress ReferenceConstraintViolation
1593
+     */
1594
+    public static function crypto_generichash_update(&$ctx, $message)
1595
+    {
1596
+        /* Type checks: */
1597
+        ParagonIE_Sodium_Core_Util::declareScalarType($ctx, 'string', 1);
1598
+        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2);
1599
+
1600
+        if (self::useNewSodiumAPI()) {
1601
+            sodium_crypto_generichash_update($ctx, $message);
1602
+            return;
1603
+        }
1604
+        if (self::use_fallback('crypto_generichash_update')) {
1605
+            $func = '\\Sodium\\crypto_generichash_update';
1606
+            $func($ctx, $message);
1607
+            return;
1608
+        }
1609
+        if (PHP_INT_SIZE === 4) {
1610
+            $ctx = ParagonIE_Sodium_Crypto32::generichash_update($ctx, $message);
1611
+        } else {
1612
+            $ctx = ParagonIE_Sodium_Crypto::generichash_update($ctx, $message);
1613
+        }
1614
+    }
1615
+
1616
+    /**
1617
+     * @return string
1618
+     * @throws Exception
1619
+     * @throws Error
1620
+     */
1621
+    public static function crypto_generichash_keygen()
1622
+    {
1623
+        return random_bytes(self::CRYPTO_GENERICHASH_KEYBYTES);
1624
+    }
1625
+
1626
+    /**
1627
+     * @param int $subkey_len
1628
+     * @param int $subkey_id
1629
+     * @param string $context
1630
+     * @param string $key
1631
+     * @return string
1632
+     * @throws SodiumException
1633
+     */
1634
+    public static function crypto_kdf_derive_from_key(
1635
+        $subkey_len,
1636
+        $subkey_id,
1637
+        $context,
1638
+        $key
1639
+    ) {
1640
+        ParagonIE_Sodium_Core_Util::declareScalarType($subkey_len, 'int', 1);
1641
+        ParagonIE_Sodium_Core_Util::declareScalarType($subkey_id, 'int', 2);
1642
+        ParagonIE_Sodium_Core_Util::declareScalarType($context, 'string', 3);
1643
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 4);
1644
+        $subkey_id = (int) $subkey_id;
1645
+        $subkey_len = (int) $subkey_len;
1646
+        $context = (string) $context;
1647
+        $key = (string) $key;
1648
+
1649
+        if ($subkey_len < self::CRYPTO_KDF_BYTES_MIN) {
1650
+            throw new SodiumException('subkey cannot be smaller than SODIUM_CRYPTO_KDF_BYTES_MIN');
1651
+        }
1652
+        if ($subkey_len > self::CRYPTO_KDF_BYTES_MAX) {
1653
+            throw new SodiumException('subkey cannot be larger than SODIUM_CRYPTO_KDF_BYTES_MAX');
1654
+        }
1655
+        if ($subkey_id < 0) {
1656
+            throw new SodiumException('subkey_id cannot be negative');
1657
+        }
1658
+        if (ParagonIE_Sodium_Core_Util::strlen($context) !== self::CRYPTO_KDF_CONTEXTBYTES) {
1659
+            throw new SodiumException('context should be SODIUM_CRYPTO_KDF_CONTEXTBYTES bytes');
1660
+        }
1661
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_KDF_KEYBYTES) {
1662
+            throw new SodiumException('key should be SODIUM_CRYPTO_KDF_KEYBYTES bytes');
1663
+        }
1664
+
1665
+        $salt = ParagonIE_Sodium_Core_Util::store64_le($subkey_id);
1666
+        $state = self::crypto_generichash_init_salt_personal(
1667
+            $key,
1668
+            $subkey_len,
1669
+            $salt,
1670
+            $context
1671
+        );
1672
+        return self::crypto_generichash_final($state, $subkey_len);
1673
+    }
1674
+
1675
+    /**
1676
+     * @return string
1677
+     * @throws Exception
1678
+     * @throws Error
1679
+     */
1680
+    public static function crypto_kdf_keygen()
1681
+    {
1682
+        return random_bytes(self::CRYPTO_KDF_KEYBYTES);
1683
+    }
1684
+
1685
+    /**
1686
+     * Perform a key exchange, between a designated client and a server.
1687
+     *
1688
+     * Typically, you would designate one machine to be the client and the
1689
+     * other to be the server. The first two keys are what you'd expect for
1690
+     * scalarmult() below, but the latter two public keys don't swap places.
1691
+     *
1692
+     * | ALICE                          | BOB                                 |
1693
+     * | Client                         | Server                              |
1694
+     * |--------------------------------|-------------------------------------|
1695
+     * | shared = crypto_kx(            | shared = crypto_kx(                 |
1696
+     * |     alice_sk,                  |     bob_sk,                         | <- contextual
1697
+     * |     bob_pk,                    |     alice_pk,                       | <- contextual
1698
+     * |     alice_pk,                  |     alice_pk,                       | <----- static
1699
+     * |     bob_pk                     |     bob_pk                          | <----- static
1700
+     * | )                              | )                                   |
1701
+     *
1702
+     * They are used along with the scalarmult product to generate a 256-bit
1703
+     * BLAKE2b hash unique to the client and server keys.
1704
+     *
1705
+     * @param string $my_secret
1706
+     * @param string $their_public
1707
+     * @param string $client_public
1708
+     * @param string $server_public
1709
+     * @param bool $dontFallback
1710
+     * @return string
1711
+     * @throws SodiumException
1712
+     * @throws TypeError
1713
+     * @psalm-suppress MixedArgument
1714
+     */
1715
+    public static function crypto_kx($my_secret, $their_public, $client_public, $server_public, $dontFallback = false)
1716
+    {
1717
+        /* Type checks: */
1718
+        ParagonIE_Sodium_Core_Util::declareScalarType($my_secret, 'string', 1);
1719
+        ParagonIE_Sodium_Core_Util::declareScalarType($their_public, 'string', 2);
1720
+        ParagonIE_Sodium_Core_Util::declareScalarType($client_public, 'string', 3);
1721
+        ParagonIE_Sodium_Core_Util::declareScalarType($server_public, 'string', 4);
1722
+
1723
+        /* Input validation: */
1724
+        if (ParagonIE_Sodium_Core_Util::strlen($my_secret) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
1725
+            throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
1726
+        }
1727
+        if (ParagonIE_Sodium_Core_Util::strlen($their_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
1728
+            throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
1729
+        }
1730
+        if (ParagonIE_Sodium_Core_Util::strlen($client_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
1731
+            throw new SodiumException('Argument 3 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
1732
+        }
1733
+        if (ParagonIE_Sodium_Core_Util::strlen($server_public) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
1734
+            throw new SodiumException('Argument 4 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
1735
+        }
1736
+
1737
+        if (self::useNewSodiumAPI() && !$dontFallback) {
1738
+            if (is_callable('sodium_crypto_kx')) {
1739
+                return (string) sodium_crypto_kx(
1740
+                    $my_secret,
1741
+                    $their_public,
1742
+                    $client_public,
1743
+                    $server_public
1744
+                );
1745
+            }
1746
+        }
1747
+        if (self::use_fallback('crypto_kx')) {
1748
+            return (string) call_user_func(
1749
+                '\\Sodium\\crypto_kx',
1750
+                $my_secret,
1751
+                $their_public,
1752
+                $client_public,
1753
+                $server_public
1754
+            );
1755
+        }
1756
+        if (PHP_INT_SIZE === 4) {
1757
+            return ParagonIE_Sodium_Crypto32::keyExchange(
1758
+                $my_secret,
1759
+                $their_public,
1760
+                $client_public,
1761
+                $server_public
1762
+            );
1763
+        }
1764
+        return ParagonIE_Sodium_Crypto::keyExchange(
1765
+            $my_secret,
1766
+            $their_public,
1767
+            $client_public,
1768
+            $server_public
1769
+        );
1770
+    }
1771
+
1772
+    /**
1773
+     * @param string $seed
1774
+     * @return string
1775
+     * @throws SodiumException
1776
+     */
1777
+    public static function crypto_kx_seed_keypair($seed)
1778
+    {
1779
+        ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1);
1780
+
1781
+        $seed = (string) $seed;
1782
+
1783
+        if (ParagonIE_Sodium_Core_Util::strlen($seed) !== self::CRYPTO_KX_SEEDBYTES) {
1784
+            throw new SodiumException('seed must be SODIUM_CRYPTO_KX_SEEDBYTES bytes');
1785
+        }
1786
+
1787
+        $sk = self::crypto_generichash($seed, '', self::CRYPTO_KX_SECRETKEYBYTES);
1788
+        $pk = self::crypto_scalarmult_base($sk);
1789
+        return $sk . $pk;
1790
+    }
1791
+
1792
+    /**
1793
+     * @return string
1794
+     * @throws Exception
1795
+     */
1796
+    public static function crypto_kx_keypair()
1797
+    {
1798
+        $sk = self::randombytes_buf(self::CRYPTO_KX_SECRETKEYBYTES);
1799
+        $pk = self::crypto_scalarmult_base($sk);
1800
+        return $sk . $pk;
1801
+    }
1802
+
1803
+    /**
1804
+     * @param string $keypair
1805
+     * @param string $serverPublicKey
1806
+     * @return array{0: string, 1: string}
1807
+     * @throws SodiumException
1808
+     */
1809
+    public static function crypto_kx_client_session_keys($keypair, $serverPublicKey)
1810
+    {
1811
+        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
1812
+        ParagonIE_Sodium_Core_Util::declareScalarType($serverPublicKey, 'string', 2);
1813
+
1814
+        $keypair = (string) $keypair;
1815
+        $serverPublicKey = (string) $serverPublicKey;
1816
+
1817
+        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_KX_KEYPAIRBYTES) {
1818
+            throw new SodiumException('keypair should be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes');
1819
+        }
1820
+        if (ParagonIE_Sodium_Core_Util::strlen($serverPublicKey) !== self::CRYPTO_KX_PUBLICKEYBYTES) {
1821
+            throw new SodiumException('public keys must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes');
1822
+        }
1823
+
1824
+        $sk = self::crypto_kx_secretkey($keypair);
1825
+        $pk = self::crypto_kx_publickey($keypair);
1826
+        $h = self::crypto_generichash_init(null, self::CRYPTO_KX_SESSIONKEYBYTES * 2);
1827
+        self::crypto_generichash_update($h, self::crypto_scalarmult($sk, $serverPublicKey));
1828
+        self::crypto_generichash_update($h, $pk);
1829
+        self::crypto_generichash_update($h, $serverPublicKey);
1830
+        $sessionKeys = self::crypto_generichash_final($h, self::CRYPTO_KX_SESSIONKEYBYTES * 2);
1831
+        return array(
1832
+            ParagonIE_Sodium_Core_Util::substr(
1833
+                $sessionKeys,
1834
+                0,
1835
+                self::CRYPTO_KX_SESSIONKEYBYTES
1836
+            ),
1837
+            ParagonIE_Sodium_Core_Util::substr(
1838
+                $sessionKeys,
1839
+                self::CRYPTO_KX_SESSIONKEYBYTES,
1840
+                self::CRYPTO_KX_SESSIONKEYBYTES
1841
+            )
1842
+        );
1843
+    }
1844
+
1845
+    /**
1846
+     * @param string $keypair
1847
+     * @param string $clientPublicKey
1848
+     * @return array{0: string, 1: string}
1849
+     * @throws SodiumException
1850
+     */
1851
+    public static function crypto_kx_server_session_keys($keypair, $clientPublicKey)
1852
+    {
1853
+        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
1854
+        ParagonIE_Sodium_Core_Util::declareScalarType($clientPublicKey, 'string', 2);
1855
+
1856
+        $keypair = (string) $keypair;
1857
+        $clientPublicKey = (string) $clientPublicKey;
1858
+
1859
+        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_KX_KEYPAIRBYTES) {
1860
+            throw new SodiumException('keypair should be SODIUM_CRYPTO_KX_KEYPAIRBYTES bytes');
1861
+        }
1862
+        if (ParagonIE_Sodium_Core_Util::strlen($clientPublicKey) !== self::CRYPTO_KX_PUBLICKEYBYTES) {
1863
+            throw new SodiumException('public keys must be SODIUM_CRYPTO_KX_PUBLICKEYBYTES bytes');
1864
+        }
1865
+
1866
+        $sk = self::crypto_kx_secretkey($keypair);
1867
+        $pk = self::crypto_kx_publickey($keypair);
1868
+        $h = self::crypto_generichash_init(null, self::CRYPTO_KX_SESSIONKEYBYTES * 2);
1869
+        self::crypto_generichash_update($h, self::crypto_scalarmult($sk, $clientPublicKey));
1870
+        self::crypto_generichash_update($h, $clientPublicKey);
1871
+        self::crypto_generichash_update($h, $pk);
1872
+        $sessionKeys = self::crypto_generichash_final($h, self::CRYPTO_KX_SESSIONKEYBYTES * 2);
1873
+        return array(
1874
+            ParagonIE_Sodium_Core_Util::substr(
1875
+                $sessionKeys,
1876
+                self::CRYPTO_KX_SESSIONKEYBYTES,
1877
+                self::CRYPTO_KX_SESSIONKEYBYTES
1878
+            ),
1879
+            ParagonIE_Sodium_Core_Util::substr(
1880
+                $sessionKeys,
1881
+                0,
1882
+                self::CRYPTO_KX_SESSIONKEYBYTES
1883
+            )
1884
+        );
1885
+    }
1886
+
1887
+    /**
1888
+     * @param string $kp
1889
+     * @return string
1890
+     * @throws SodiumException
1891
+     */
1892
+    public static function crypto_kx_secretkey($kp)
1893
+    {
1894
+        return ParagonIE_Sodium_Core_Util::substr(
1895
+            $kp,
1896
+            0,
1897
+            self::CRYPTO_KX_SECRETKEYBYTES
1898
+        );
1899
+    }
1900
+
1901
+    /**
1902
+     * @param string $kp
1903
+     * @return string
1904
+     * @throws SodiumException
1905
+     */
1906
+    public static function crypto_kx_publickey($kp)
1907
+    {
1908
+        return ParagonIE_Sodium_Core_Util::substr(
1909
+            $kp,
1910
+            self::CRYPTO_KX_SECRETKEYBYTES,
1911
+            self::CRYPTO_KX_PUBLICKEYBYTES
1912
+        );
1913
+    }
1914
+
1915
+    /**
1916
+     * @param int $outlen
1917
+     * @param string $passwd
1918
+     * @param string $salt
1919
+     * @param int $opslimit
1920
+     * @param int $memlimit
1921
+     * @param int|null $alg
1922
+     * @return string
1923
+     * @throws SodiumException
1924
+     * @throws TypeError
1925
+     * @psalm-suppress MixedArgument
1926
+     */
1927
+    public static function crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit, $alg = null)
1928
+    {
1929
+        ParagonIE_Sodium_Core_Util::declareScalarType($outlen, 'int', 1);
1930
+        ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 2);
1931
+        ParagonIE_Sodium_Core_Util::declareScalarType($salt,  'string', 3);
1932
+        ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 4);
1933
+        ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 5);
1934
+
1935
+        if (self::useNewSodiumAPI()) {
1936
+            if (!is_null($alg)) {
1937
+                ParagonIE_Sodium_Core_Util::declareScalarType($alg, 'int', 6);
1938
+                return sodium_crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit, $alg);
1939
+            }
1940
+            return sodium_crypto_pwhash($outlen, $passwd, $salt, $opslimit, $memlimit);
1941
+        }
1942
+        if (self::use_fallback('crypto_pwhash')) {
1943
+            return (string) call_user_func('\\Sodium\\crypto_pwhash', $outlen, $passwd, $salt, $opslimit, $memlimit);
1944
+        }
1945
+        // This is the best we can do.
1946
+        throw new SodiumException(
1947
+            'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP'
1948
+        );
1949
+    }
1950
+
1951
+    /**
1952
+     * !Exclusive to sodium_compat!
1953
+     *
1954
+     * This returns TRUE if the native crypto_pwhash API is available by libsodium.
1955
+     * This returns FALSE if only sodium_compat is available.
1956
+     *
1957
+     * @return bool
1958
+     */
1959
+    public static function crypto_pwhash_is_available()
1960
+    {
1961
+        if (self::useNewSodiumAPI()) {
1962
+            return true;
1963
+        }
1964
+        if (self::use_fallback('crypto_pwhash')) {
1965
+            return true;
1966
+        }
1967
+        return false;
1968
+    }
1969
+
1970
+    /**
1971
+     * @param string $passwd
1972
+     * @param int $opslimit
1973
+     * @param int $memlimit
1974
+     * @return string
1975
+     * @throws SodiumException
1976
+     * @throws TypeError
1977
+     * @psalm-suppress MixedArgument
1978
+     */
1979
+    public static function crypto_pwhash_str($passwd, $opslimit, $memlimit)
1980
+    {
1981
+        ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1);
1982
+        ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2);
1983
+        ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3);
1984
+
1985
+        if (self::useNewSodiumAPI()) {
1986
+            return sodium_crypto_pwhash_str($passwd, $opslimit, $memlimit);
1987
+        }
1988
+        if (self::use_fallback('crypto_pwhash_str')) {
1989
+            return (string) call_user_func('\\Sodium\\crypto_pwhash_str', $passwd, $opslimit, $memlimit);
1990
+        }
1991
+        // This is the best we can do.
1992
+        throw new SodiumException(
1993
+            'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP'
1994
+        );
1995
+    }
1996
+
1997
+    /**
1998
+     * Do we need to rehash this password?
1999
+     *
2000
+     * @param string $hash
2001
+     * @param int $opslimit
2002
+     * @param int $memlimit
2003
+     * @return bool
2004
+     * @throws SodiumException
2005
+     */
2006
+    public static function crypto_pwhash_str_needs_rehash($hash, $opslimit, $memlimit)
2007
+    {
2008
+        ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 1);
2009
+        ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2);
2010
+        ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3);
2011
+
2012
+        // Just grab the first 4 pieces.
2013
+        $pieces = explode('$', (string) $hash);
2014
+        $prefix = implode('$', array_slice($pieces, 0, 4));
2015
+
2016
+        // Rebuild the expected header.
2017
+        /** @var int $ops */
2018
+        $ops = (int) $opslimit;
2019
+        /** @var int $mem */
2020
+        $mem = (int) $memlimit >> 10;
2021
+        $encoded = self::CRYPTO_PWHASH_STRPREFIX . 'v=19$m=' . $mem . ',t=' . $ops . ',p=1';
2022
+
2023
+        // Do they match? If so, we don't need to rehash, so return false.
2024
+        return !ParagonIE_Sodium_Core_Util::hashEquals($encoded, $prefix);
2025
+    }
2026
+
2027
+    /**
2028
+     * @param string $passwd
2029
+     * @param string $hash
2030
+     * @return bool
2031
+     * @throws SodiumException
2032
+     * @throws TypeError
2033
+     * @psalm-suppress MixedArgument
2034
+     */
2035
+    public static function crypto_pwhash_str_verify($passwd, $hash)
2036
+    {
2037
+        ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1);
2038
+        ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 2);
2039
+
2040
+        if (self::useNewSodiumAPI()) {
2041
+            return (bool) sodium_crypto_pwhash_str_verify($passwd, $hash);
2042
+        }
2043
+        if (self::use_fallback('crypto_pwhash_str_verify')) {
2044
+            return (bool) call_user_func('\\Sodium\\crypto_pwhash_str_verify', $passwd, $hash);
2045
+        }
2046
+        // This is the best we can do.
2047
+        throw new SodiumException(
2048
+            'This is not implemented, as it is not possible to implement Argon2i with acceptable performance in pure-PHP'
2049
+        );
2050
+    }
2051
+
2052
+    /**
2053
+     * @param int $outlen
2054
+     * @param string $passwd
2055
+     * @param string $salt
2056
+     * @param int $opslimit
2057
+     * @param int $memlimit
2058
+     * @return string
2059
+     * @throws SodiumException
2060
+     * @throws TypeError
2061
+     */
2062
+    public static function crypto_pwhash_scryptsalsa208sha256($outlen, $passwd, $salt, $opslimit, $memlimit)
2063
+    {
2064
+        ParagonIE_Sodium_Core_Util::declareScalarType($outlen, 'int', 1);
2065
+        ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 2);
2066
+        ParagonIE_Sodium_Core_Util::declareScalarType($salt,  'string', 3);
2067
+        ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 4);
2068
+        ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 5);
2069
+
2070
+        if (self::useNewSodiumAPI()) {
2071
+            return (string) sodium_crypto_pwhash_scryptsalsa208sha256(
2072
+                (int) $outlen,
2073
+                (string) $passwd,
2074
+                (string) $salt,
2075
+                (int) $opslimit,
2076
+                (int) $memlimit
2077
+            );
2078
+        }
2079
+        if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256')) {
2080
+            return (string) call_user_func(
2081
+                '\\Sodium\\crypto_pwhash_scryptsalsa208sha256',
2082
+                (int) $outlen,
2083
+                (string) $passwd,
2084
+                (string) $salt,
2085
+                (int) $opslimit,
2086
+                (int) $memlimit
2087
+            );
2088
+        }
2089
+        // This is the best we can do.
2090
+        throw new SodiumException(
2091
+            'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP'
2092
+        );
2093
+    }
2094
+
2095
+    /**
2096
+     * !Exclusive to sodium_compat!
2097
+     *
2098
+     * This returns TRUE if the native crypto_pwhash API is available by libsodium.
2099
+     * This returns FALSE if only sodium_compat is available.
2100
+     *
2101
+     * @return bool
2102
+     */
2103
+    public static function crypto_pwhash_scryptsalsa208sha256_is_available()
2104
+    {
2105
+        if (self::useNewSodiumAPI()) {
2106
+            return true;
2107
+        }
2108
+        if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256')) {
2109
+            return true;
2110
+        }
2111
+        return false;
2112
+    }
2113
+
2114
+    /**
2115
+     * @param string $passwd
2116
+     * @param int $opslimit
2117
+     * @param int $memlimit
2118
+     * @return string
2119
+     * @throws SodiumException
2120
+     * @throws TypeError
2121
+     */
2122
+    public static function crypto_pwhash_scryptsalsa208sha256_str($passwd, $opslimit, $memlimit)
2123
+    {
2124
+        ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1);
2125
+        ParagonIE_Sodium_Core_Util::declareScalarType($opslimit, 'int', 2);
2126
+        ParagonIE_Sodium_Core_Util::declareScalarType($memlimit, 'int', 3);
2127
+
2128
+        if (self::useNewSodiumAPI()) {
2129
+            return (string) sodium_crypto_pwhash_scryptsalsa208sha256_str(
2130
+                (string) $passwd,
2131
+                (int) $opslimit,
2132
+                (int) $memlimit
2133
+            );
2134
+        }
2135
+        if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str')) {
2136
+            return (string) call_user_func(
2137
+                '\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str',
2138
+                (string) $passwd,
2139
+                (int) $opslimit,
2140
+                (int) $memlimit
2141
+            );
2142
+        }
2143
+        // This is the best we can do.
2144
+        throw new SodiumException(
2145
+            'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP'
2146
+        );
2147
+    }
2148
+
2149
+    /**
2150
+     * @param string $passwd
2151
+     * @param string $hash
2152
+     * @return bool
2153
+     * @throws SodiumException
2154
+     * @throws TypeError
2155
+     */
2156
+    public static function crypto_pwhash_scryptsalsa208sha256_str_verify($passwd, $hash)
2157
+    {
2158
+        ParagonIE_Sodium_Core_Util::declareScalarType($passwd, 'string', 1);
2159
+        ParagonIE_Sodium_Core_Util::declareScalarType($hash, 'string', 2);
2160
+
2161
+        if (self::useNewSodiumAPI()) {
2162
+            return (bool) sodium_crypto_pwhash_scryptsalsa208sha256_str_verify(
2163
+                (string) $passwd,
2164
+                (string) $hash
2165
+            );
2166
+        }
2167
+        if (self::use_fallback('crypto_pwhash_scryptsalsa208sha256_str_verify')) {
2168
+            return (bool) call_user_func(
2169
+                '\\Sodium\\crypto_pwhash_scryptsalsa208sha256_str_verify',
2170
+                (string) $passwd,
2171
+                (string) $hash
2172
+            );
2173
+        }
2174
+        // This is the best we can do.
2175
+        throw new SodiumException(
2176
+            'This is not implemented, as it is not possible to implement Scrypt with acceptable performance in pure-PHP'
2177
+        );
2178
+    }
2179
+
2180
+    /**
2181
+     * Calculate the shared secret between your secret key and your
2182
+     * recipient's public key.
2183
+     *
2184
+     * Algorithm: X25519 (ECDH over Curve25519)
2185
+     *
2186
+     * @param string $secretKey
2187
+     * @param string $publicKey
2188
+     * @return string
2189
+     * @throws SodiumException
2190
+     * @throws TypeError
2191
+     * @psalm-suppress MixedArgument
2192
+     */
2193
+    public static function crypto_scalarmult($secretKey, $publicKey)
2194
+    {
2195
+        /* Type checks: */
2196
+        ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
2197
+        ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2);
2198
+
2199
+        /* Input validation: */
2200
+        if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
2201
+            throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
2202
+        }
2203
+        if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_BOX_PUBLICKEYBYTES) {
2204
+            throw new SodiumException('Argument 2 must be CRYPTO_BOX_PUBLICKEYBYTES long.');
2205
+        }
2206
+
2207
+        if (self::useNewSodiumAPI()) {
2208
+            return sodium_crypto_scalarmult($secretKey, $publicKey);
2209
+        }
2210
+        if (self::use_fallback('crypto_scalarmult')) {
2211
+            return (string) call_user_func('\\Sodium\\crypto_scalarmult', $secretKey, $publicKey);
2212
+        }
2213
+
2214
+        /* Output validation: Forbid all-zero keys */
2215
+        if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) {
2216
+            throw new SodiumException('Zero secret key is not allowed');
2217
+        }
2218
+        if (ParagonIE_Sodium_Core_Util::hashEquals($publicKey, str_repeat("\0", self::CRYPTO_BOX_PUBLICKEYBYTES))) {
2219
+            throw new SodiumException('Zero public key is not allowed');
2220
+        }
2221
+        if (PHP_INT_SIZE === 4) {
2222
+            return ParagonIE_Sodium_Crypto32::scalarmult($secretKey, $publicKey);
2223
+        }
2224
+        return ParagonIE_Sodium_Crypto::scalarmult($secretKey, $publicKey);
2225
+    }
2226
+
2227
+    /**
2228
+     * Calculate an X25519 public key from an X25519 secret key.
2229
+     *
2230
+     * @param string $secretKey
2231
+     * @return string
2232
+     * @throws SodiumException
2233
+     * @throws TypeError
2234
+     * @psalm-suppress TooFewArguments
2235
+     * @psalm-suppress MixedArgument
2236
+     */
2237
+    public static function crypto_scalarmult_base($secretKey)
2238
+    {
2239
+        /* Type checks: */
2240
+        ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
2241
+
2242
+        /* Input validation: */
2243
+        if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_BOX_SECRETKEYBYTES) {
2244
+            throw new SodiumException('Argument 1 must be CRYPTO_BOX_SECRETKEYBYTES long.');
2245
+        }
2246
+
2247
+        if (self::useNewSodiumAPI()) {
2248
+            return sodium_crypto_scalarmult_base($secretKey);
2249
+        }
2250
+        if (self::use_fallback('crypto_scalarmult_base')) {
2251
+            return (string) call_user_func('\\Sodium\\crypto_scalarmult_base', $secretKey);
2252
+        }
2253
+        if (ParagonIE_Sodium_Core_Util::hashEquals($secretKey, str_repeat("\0", self::CRYPTO_BOX_SECRETKEYBYTES))) {
2254
+            throw new SodiumException('Zero secret key is not allowed');
2255
+        }
2256
+        if (PHP_INT_SIZE === 4) {
2257
+            return ParagonIE_Sodium_Crypto32::scalarmult_base($secretKey);
2258
+        }
2259
+        return ParagonIE_Sodium_Crypto::scalarmult_base($secretKey);
2260
+    }
2261
+
2262
+    /**
2263
+     * Authenticated symmetric-key encryption.
2264
+     *
2265
+     * Algorithm: XSalsa20-Poly1305
2266
+     *
2267
+     * @param string $plaintext The message you're encrypting
2268
+     * @param string $nonce A Number to be used Once; must be 24 bytes
2269
+     * @param string $key Symmetric encryption key
2270
+     * @return string           Ciphertext with Poly1305 MAC
2271
+     * @throws SodiumException
2272
+     * @throws TypeError
2273
+     * @psalm-suppress MixedArgument
2274
+     */
2275
+    public static function crypto_secretbox($plaintext, $nonce, $key)
2276
+    {
2277
+        /* Type checks: */
2278
+        ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
2279
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
2280
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
2281
+
2282
+        /* Input validation: */
2283
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) {
2284
+            throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
2285
+        }
2286
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) {
2287
+            throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
2288
+        }
2289
+
2290
+        if (self::useNewSodiumAPI()) {
2291
+            return sodium_crypto_secretbox($plaintext, $nonce, $key);
2292
+        }
2293
+        if (self::use_fallback('crypto_secretbox')) {
2294
+            return (string) call_user_func('\\Sodium\\crypto_secretbox', $plaintext, $nonce, $key);
2295
+        }
2296
+        if (PHP_INT_SIZE === 4) {
2297
+            return ParagonIE_Sodium_Crypto32::secretbox($plaintext, $nonce, $key);
2298
+        }
2299
+        return ParagonIE_Sodium_Crypto::secretbox($plaintext, $nonce, $key);
2300
+    }
2301
+
2302
+    /**
2303
+     * Decrypts a message previously encrypted with crypto_secretbox().
2304
+     *
2305
+     * @param string $ciphertext Ciphertext with Poly1305 MAC
2306
+     * @param string $nonce      A Number to be used Once; must be 24 bytes
2307
+     * @param string $key        Symmetric encryption key
2308
+     * @return string            Original plaintext message
2309
+     * @throws SodiumException
2310
+     * @throws TypeError
2311
+     * @psalm-suppress MixedArgument
2312
+     * @psalm-suppress MixedInferredReturnType
2313
+     * @psalm-suppress MixedReturnStatement
2314
+     */
2315
+    public static function crypto_secretbox_open($ciphertext, $nonce, $key)
2316
+    {
2317
+        /* Type checks: */
2318
+        ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
2319
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
2320
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
2321
+
2322
+        /* Input validation: */
2323
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) {
2324
+            throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
2325
+        }
2326
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) {
2327
+            throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
2328
+        }
2329
+
2330
+        if (self::useNewSodiumAPI()) {
2331
+            /**
2332
+             * @psalm-suppress InvalidReturnStatement
2333
+             * @psalm-suppress FalsableReturnStatement
2334
+             */
2335
+            return sodium_crypto_secretbox_open($ciphertext, $nonce, $key);
2336
+        }
2337
+        if (self::use_fallback('crypto_secretbox_open')) {
2338
+            return call_user_func('\\Sodium\\crypto_secretbox_open', $ciphertext, $nonce, $key);
2339
+        }
2340
+        if (PHP_INT_SIZE === 4) {
2341
+            return ParagonIE_Sodium_Crypto32::secretbox_open($ciphertext, $nonce, $key);
2342
+        }
2343
+        return ParagonIE_Sodium_Crypto::secretbox_open($ciphertext, $nonce, $key);
2344
+    }
2345
+
2346
+    /**
2347
+     * Return a secure random key for use with crypto_secretbox
2348
+     *
2349
+     * @return string
2350
+     * @throws Exception
2351
+     * @throws Error
2352
+     */
2353
+    public static function crypto_secretbox_keygen()
2354
+    {
2355
+        return random_bytes(self::CRYPTO_SECRETBOX_KEYBYTES);
2356
+    }
2357
+
2358
+    /**
2359
+     * Authenticated symmetric-key encryption.
2360
+     *
2361
+     * Algorithm: XChaCha20-Poly1305
2362
+     *
2363
+     * @param string $plaintext The message you're encrypting
2364
+     * @param string $nonce     A Number to be used Once; must be 24 bytes
2365
+     * @param string $key       Symmetric encryption key
2366
+     * @return string           Ciphertext with Poly1305 MAC
2367
+     * @throws SodiumException
2368
+     * @throws TypeError
2369
+     * @psalm-suppress MixedArgument
2370
+     */
2371
+    public static function crypto_secretbox_xchacha20poly1305($plaintext, $nonce, $key)
2372
+    {
2373
+        /* Type checks: */
2374
+        ParagonIE_Sodium_Core_Util::declareScalarType($plaintext, 'string', 1);
2375
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
2376
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
2377
+
2378
+        /* Input validation: */
2379
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) {
2380
+            throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
2381
+        }
2382
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) {
2383
+            throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
2384
+        }
2385
+        if (PHP_INT_SIZE === 4) {
2386
+            return ParagonIE_Sodium_Crypto32::secretbox_xchacha20poly1305($plaintext, $nonce, $key);
2387
+        }
2388
+        return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305($plaintext, $nonce, $key);
2389
+    }
2390
+    /**
2391
+     * Decrypts a message previously encrypted with crypto_secretbox_xchacha20poly1305().
2392
+     *
2393
+     * @param string $ciphertext Ciphertext with Poly1305 MAC
2394
+     * @param string $nonce      A Number to be used Once; must be 24 bytes
2395
+     * @param string $key        Symmetric encryption key
2396
+     * @return string            Original plaintext message
2397
+     * @throws SodiumException
2398
+     * @throws TypeError
2399
+     * @psalm-suppress MixedArgument
2400
+     */
2401
+    public static function crypto_secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key)
2402
+    {
2403
+        /* Type checks: */
2404
+        ParagonIE_Sodium_Core_Util::declareScalarType($ciphertext, 'string', 1);
2405
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
2406
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
2407
+
2408
+        /* Input validation: */
2409
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_SECRETBOX_NONCEBYTES) {
2410
+            throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
2411
+        }
2412
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SECRETBOX_KEYBYTES) {
2413
+            throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
2414
+        }
2415
+
2416
+        if (PHP_INT_SIZE === 4) {
2417
+            return ParagonIE_Sodium_Crypto32::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key);
2418
+        }
2419
+        return ParagonIE_Sodium_Crypto::secretbox_xchacha20poly1305_open($ciphertext, $nonce, $key);
2420
+    }
2421
+
2422
+    /**
2423
+     * @param string $key
2424
+     * @return array<int, string> Returns a state and a header.
2425
+     * @throws Exception
2426
+     * @throws SodiumException
2427
+     */
2428
+    public static function crypto_secretstream_xchacha20poly1305_init_push($key)
2429
+    {
2430
+        if (PHP_INT_SIZE === 4) {
2431
+            return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_init_push($key);
2432
+        }
2433
+        return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_push($key);
2434
+    }
2435
+
2436
+    /**
2437
+     * @param string $header
2438
+     * @param string $key
2439
+     * @return string Returns a state.
2440
+     * @throws Exception
2441
+     */
2442
+    public static function crypto_secretstream_xchacha20poly1305_init_pull($header, $key)
2443
+    {
2444
+        if (ParagonIE_Sodium_Core_Util::strlen($header) < self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES) {
2445
+            throw new SodiumException(
2446
+                'header size should be SODIUM_CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_HEADERBYTES bytes'
2447
+            );
2448
+        }
2449
+        if (PHP_INT_SIZE === 4) {
2450
+            return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_init_pull($key, $header);
2451
+        }
2452
+        return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_init_pull($key, $header);
2453
+    }
2454
+
2455
+    /**
2456
+     * @param string $state
2457
+     * @param string $msg
2458
+     * @param string $aad
2459
+     * @param int $tag
2460
+     * @return string
2461
+     * @throws SodiumException
2462
+     */
2463
+    public static function crypto_secretstream_xchacha20poly1305_push(&$state, $msg, $aad = '', $tag = 0)
2464
+    {
2465
+        if (PHP_INT_SIZE === 4) {
2466
+            return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_push(
2467
+                $state,
2468
+                $msg,
2469
+                $aad,
2470
+                $tag
2471
+            );
2472
+        }
2473
+        return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_push(
2474
+            $state,
2475
+            $msg,
2476
+            $aad,
2477
+            $tag
2478
+        );
2479
+    }
2480
+
2481
+    /**
2482
+     * @param string $state
2483
+     * @param string $msg
2484
+     * @param string $aad
2485
+     * @return bool|array{0: string, 1: int}
2486
+     * @throws SodiumException
2487
+     */
2488
+    public static function crypto_secretstream_xchacha20poly1305_pull(&$state, $msg, $aad = '')
2489
+    {
2490
+        if (PHP_INT_SIZE === 4) {
2491
+            return ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_pull(
2492
+                $state,
2493
+                $msg,
2494
+                $aad
2495
+            );
2496
+        }
2497
+        return ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_pull(
2498
+            $state,
2499
+            $msg,
2500
+            $aad
2501
+        );
2502
+    }
2503
+
2504
+    /**
2505
+     * @return string
2506
+     * @throws Exception
2507
+     */
2508
+    public static function crypto_secretstream_xchacha20poly1305_keygen()
2509
+    {
2510
+        return random_bytes(self::CRYPTO_SECRETSTREAM_XCHACHA20POLY1305_KEYBYTES);
2511
+    }
2512
+
2513
+    /**
2514
+     * @param string $state
2515
+     * @return void
2516
+     * @throws SodiumException
2517
+     */
2518
+    public static function crypto_secretstream_xchacha20poly1305_rekey(&$state)
2519
+    {
2520
+        if (PHP_INT_SIZE === 4) {
2521
+            ParagonIE_Sodium_Crypto32::secretstream_xchacha20poly1305_rekey($state);
2522
+        } else {
2523
+            ParagonIE_Sodium_Crypto::secretstream_xchacha20poly1305_rekey($state);
2524
+        }
2525
+    }
2526
+
2527
+    /**
2528
+     * Calculates a SipHash-2-4 hash of a message for a given key.
2529
+     *
2530
+     * @param string $message Input message
2531
+     * @param string $key SipHash-2-4 key
2532
+     * @return string         Hash
2533
+     * @throws SodiumException
2534
+     * @throws TypeError
2535
+     * @psalm-suppress MixedArgument
2536
+     * @psalm-suppress MixedInferredReturnType
2537
+     * @psalm-suppress MixedReturnStatement
2538
+     */
2539
+    public static function crypto_shorthash($message, $key)
2540
+    {
2541
+        /* Type checks: */
2542
+        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
2543
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 2);
2544
+
2545
+        /* Input validation: */
2546
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_SHORTHASH_KEYBYTES) {
2547
+            throw new SodiumException('Argument 2 must be CRYPTO_SHORTHASH_KEYBYTES long.');
2548
+        }
2549
+
2550
+        if (self::useNewSodiumAPI()) {
2551
+            return sodium_crypto_shorthash($message, $key);
2552
+        }
2553
+        if (self::use_fallback('crypto_shorthash')) {
2554
+            return (string) call_user_func('\\Sodium\\crypto_shorthash', $message, $key);
2555
+        }
2556
+        if (PHP_INT_SIZE === 4) {
2557
+            return ParagonIE_Sodium_Core32_SipHash::sipHash24($message, $key);
2558
+        }
2559
+        return ParagonIE_Sodium_Core_SipHash::sipHash24($message, $key);
2560
+    }
2561
+
2562
+    /**
2563
+     * Return a secure random key for use with crypto_shorthash
2564
+     *
2565
+     * @return string
2566
+     * @throws Exception
2567
+     * @throws Error
2568
+     */
2569
+    public static function crypto_shorthash_keygen()
2570
+    {
2571
+        return random_bytes(self::CRYPTO_SHORTHASH_KEYBYTES);
2572
+    }
2573
+
2574
+    /**
2575
+     * Returns a signed message. You probably want crypto_sign_detached()
2576
+     * instead, which only returns the signature.
2577
+     *
2578
+     * Algorithm: Ed25519 (EdDSA over Curve25519)
2579
+     *
2580
+     * @param string $message Message to be signed.
2581
+     * @param string $secretKey Secret signing key.
2582
+     * @return string           Signed message (signature is prefixed).
2583
+     * @throws SodiumException
2584
+     * @throws TypeError
2585
+     * @psalm-suppress MixedArgument
2586
+     * @psalm-suppress MixedInferredReturnType
2587
+     * @psalm-suppress MixedReturnStatement
2588
+     */
2589
+    public static function crypto_sign($message, $secretKey)
2590
+    {
2591
+        /* Type checks: */
2592
+        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
2593
+        ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 2);
2594
+
2595
+        /* Input validation: */
2596
+        if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) {
2597
+            throw new SodiumException('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.');
2598
+        }
2599
+
2600
+        if (self::useNewSodiumAPI()) {
2601
+            return sodium_crypto_sign($message, $secretKey);
2602
+        }
2603
+        if (self::use_fallback('crypto_sign')) {
2604
+            return (string) call_user_func('\\Sodium\\crypto_sign', $message, $secretKey);
2605
+        }
2606
+        if (PHP_INT_SIZE === 4) {
2607
+            return ParagonIE_Sodium_Crypto32::sign($message, $secretKey);
2608
+        }
2609
+        return ParagonIE_Sodium_Crypto::sign($message, $secretKey);
2610
+    }
2611
+
2612
+    /**
2613
+     * Validates a signed message then returns the message.
2614
+     *
2615
+     * @param string $signedMessage A signed message
2616
+     * @param string $publicKey A public key
2617
+     * @return string               The original message (if the signature is
2618
+     *                              valid for this public key)
2619
+     * @throws SodiumException
2620
+     * @throws TypeError
2621
+     * @psalm-suppress MixedArgument
2622
+     * @psalm-suppress MixedInferredReturnType
2623
+     * @psalm-suppress MixedReturnStatement
2624
+     */
2625
+    public static function crypto_sign_open($signedMessage, $publicKey)
2626
+    {
2627
+        /* Type checks: */
2628
+        ParagonIE_Sodium_Core_Util::declareScalarType($signedMessage, 'string', 1);
2629
+        ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 2);
2630
+
2631
+        /* Input validation: */
2632
+        if (ParagonIE_Sodium_Core_Util::strlen($signedMessage) < self::CRYPTO_SIGN_BYTES) {
2633
+            throw new SodiumException('Argument 1 must be at least CRYPTO_SIGN_BYTES long.');
2634
+        }
2635
+        if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) {
2636
+            throw new SodiumException('Argument 2 must be CRYPTO_SIGN_PUBLICKEYBYTES long.');
2637
+        }
2638
+
2639
+        if (self::useNewSodiumAPI()) {
2640
+            /**
2641
+             * @psalm-suppress InvalidReturnStatement
2642
+             * @psalm-suppress FalsableReturnStatement
2643
+             */
2644
+            return sodium_crypto_sign_open($signedMessage, $publicKey);
2645
+        }
2646
+        if (self::use_fallback('crypto_sign_open')) {
2647
+            return call_user_func('\\Sodium\\crypto_sign_open', $signedMessage, $publicKey);
2648
+        }
2649
+        if (PHP_INT_SIZE === 4) {
2650
+            return ParagonIE_Sodium_Crypto32::sign_open($signedMessage, $publicKey);
2651
+        }
2652
+        return ParagonIE_Sodium_Crypto::sign_open($signedMessage, $publicKey);
2653
+    }
2654
+
2655
+    /**
2656
+     * Generate a new random Ed25519 keypair.
2657
+     *
2658
+     * @return string
2659
+     * @throws SodiumException
2660
+     * @throws TypeError
2661
+     */
2662
+    public static function crypto_sign_keypair()
2663
+    {
2664
+        if (self::useNewSodiumAPI()) {
2665
+            return sodium_crypto_sign_keypair();
2666
+        }
2667
+        if (self::use_fallback('crypto_sign_keypair')) {
2668
+            return (string) call_user_func('\\Sodium\\crypto_sign_keypair');
2669
+        }
2670
+        if (PHP_INT_SIZE === 4) {
2671
+            return ParagonIE_Sodium_Core32_Ed25519::keypair();
2672
+        }
2673
+        return ParagonIE_Sodium_Core_Ed25519::keypair();
2674
+    }
2675
+
2676
+    /**
2677
+     * @param string $sk
2678
+     * @param string $pk
2679
+     * @return string
2680
+     * @throws SodiumException
2681
+     */
2682
+    public static function crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk)
2683
+    {
2684
+        ParagonIE_Sodium_Core_Util::declareScalarType($sk, 'string', 1);
2685
+        ParagonIE_Sodium_Core_Util::declareScalarType($pk, 'string', 1);
2686
+        $sk = (string) $sk;
2687
+        $pk = (string) $pk;
2688
+
2689
+        if (ParagonIE_Sodium_Core_Util::strlen($sk) !== self::CRYPTO_SIGN_SECRETKEYBYTES) {
2690
+            throw new SodiumException('secretkey should be SODIUM_CRYPTO_SIGN_SECRETKEYBYTES bytes');
2691
+        }
2692
+        if (ParagonIE_Sodium_Core_Util::strlen($pk) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) {
2693
+            throw new SodiumException('publickey should be SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES bytes');
2694
+        }
2695
+
2696
+        if (self::useNewSodiumAPI()) {
2697
+            return sodium_crypto_sign_keypair_from_secretkey_and_publickey($sk, $pk);
2698
+        }
2699
+        return $sk . $pk;
2700
+    }
2701
+
2702
+    /**
2703
+     * Generate an Ed25519 keypair from a seed.
2704
+     *
2705
+     * @param string $seed Input seed
2706
+     * @return string      Keypair
2707
+     * @throws SodiumException
2708
+     * @throws TypeError
2709
+     * @psalm-suppress MixedArgument
2710
+     */
2711
+    public static function crypto_sign_seed_keypair($seed)
2712
+    {
2713
+        ParagonIE_Sodium_Core_Util::declareScalarType($seed, 'string', 1);
2714
+
2715
+        if (self::useNewSodiumAPI()) {
2716
+            return sodium_crypto_sign_seed_keypair($seed);
2717
+        }
2718
+        if (self::use_fallback('crypto_sign_keypair')) {
2719
+            return (string) call_user_func('\\Sodium\\crypto_sign_seed_keypair', $seed);
2720
+        }
2721
+        $publicKey = '';
2722
+        $secretKey = '';
2723
+        if (PHP_INT_SIZE === 4) {
2724
+            ParagonIE_Sodium_Core32_Ed25519::seed_keypair($publicKey, $secretKey, $seed);
2725
+        } else {
2726
+            ParagonIE_Sodium_Core_Ed25519::seed_keypair($publicKey, $secretKey, $seed);
2727
+        }
2728
+        return $secretKey . $publicKey;
2729
+    }
2730
+
2731
+    /**
2732
+     * Extract an Ed25519 public key from an Ed25519 keypair.
2733
+     *
2734
+     * @param string $keypair Keypair
2735
+     * @return string         Public key
2736
+     * @throws SodiumException
2737
+     * @throws TypeError
2738
+     * @psalm-suppress MixedArgument
2739
+     */
2740
+    public static function crypto_sign_publickey($keypair)
2741
+    {
2742
+        /* Type checks: */
2743
+        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
2744
+
2745
+        /* Input validation: */
2746
+        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_SIGN_KEYPAIRBYTES) {
2747
+            throw new SodiumException('Argument 1 must be CRYPTO_SIGN_KEYPAIRBYTES long.');
2748
+        }
2749
+
2750
+        if (self::useNewSodiumAPI()) {
2751
+            return sodium_crypto_sign_publickey($keypair);
2752
+        }
2753
+        if (self::use_fallback('crypto_sign_publickey')) {
2754
+            return (string) call_user_func('\\Sodium\\crypto_sign_publickey', $keypair);
2755
+        }
2756
+        if (PHP_INT_SIZE === 4) {
2757
+            return ParagonIE_Sodium_Core32_Ed25519::publickey($keypair);
2758
+        }
2759
+        return ParagonIE_Sodium_Core_Ed25519::publickey($keypair);
2760
+    }
2761
+
2762
+    /**
2763
+     * Calculate an Ed25519 public key from an Ed25519 secret key.
2764
+     *
2765
+     * @param string $secretKey Your Ed25519 secret key
2766
+     * @return string           The corresponding Ed25519 public key
2767
+     * @throws SodiumException
2768
+     * @throws TypeError
2769
+     * @psalm-suppress MixedArgument
2770
+     */
2771
+    public static function crypto_sign_publickey_from_secretkey($secretKey)
2772
+    {
2773
+        /* Type checks: */
2774
+        ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 1);
2775
+
2776
+        /* Input validation: */
2777
+        if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) {
2778
+            throw new SodiumException('Argument 1 must be CRYPTO_SIGN_SECRETKEYBYTES long.');
2779
+        }
2780
+
2781
+        if (self::useNewSodiumAPI()) {
2782
+            return sodium_crypto_sign_publickey_from_secretkey($secretKey);
2783
+        }
2784
+        if (self::use_fallback('crypto_sign_publickey_from_secretkey')) {
2785
+            return (string) call_user_func('\\Sodium\\crypto_sign_publickey_from_secretkey', $secretKey);
2786
+        }
2787
+        if (PHP_INT_SIZE === 4) {
2788
+            return ParagonIE_Sodium_Core32_Ed25519::publickey_from_secretkey($secretKey);
2789
+        }
2790
+        return ParagonIE_Sodium_Core_Ed25519::publickey_from_secretkey($secretKey);
2791
+    }
2792
+
2793
+    /**
2794
+     * Extract an Ed25519 secret key from an Ed25519 keypair.
2795
+     *
2796
+     * @param string $keypair Keypair
2797
+     * @return string         Secret key
2798
+     * @throws SodiumException
2799
+     * @throws TypeError
2800
+     * @psalm-suppress MixedArgument
2801
+     */
2802
+    public static function crypto_sign_secretkey($keypair)
2803
+    {
2804
+        /* Type checks: */
2805
+        ParagonIE_Sodium_Core_Util::declareScalarType($keypair, 'string', 1);
2806
+
2807
+        /* Input validation: */
2808
+        if (ParagonIE_Sodium_Core_Util::strlen($keypair) !== self::CRYPTO_SIGN_KEYPAIRBYTES) {
2809
+            throw new SodiumException('Argument 1 must be CRYPTO_SIGN_KEYPAIRBYTES long.');
2810
+        }
2811
+
2812
+        if (self::useNewSodiumAPI()) {
2813
+            return sodium_crypto_sign_secretkey($keypair);
2814
+        }
2815
+        if (self::use_fallback('crypto_sign_secretkey')) {
2816
+            return (string) call_user_func('\\Sodium\\crypto_sign_secretkey', $keypair);
2817
+        }
2818
+        if (PHP_INT_SIZE === 4) {
2819
+            return ParagonIE_Sodium_Core32_Ed25519::secretkey($keypair);
2820
+        }
2821
+        return ParagonIE_Sodium_Core_Ed25519::secretkey($keypair);
2822
+    }
2823
+
2824
+    /**
2825
+     * Calculate the Ed25519 signature of a message and return ONLY the signature.
2826
+     *
2827
+     * Algorithm: Ed25519 (EdDSA over Curve25519)
2828
+     *
2829
+     * @param string $message Message to be signed
2830
+     * @param string $secretKey Secret signing key
2831
+     * @return string           Digital signature
2832
+     * @throws SodiumException
2833
+     * @throws TypeError
2834
+     * @psalm-suppress MixedArgument
2835
+     */
2836
+    public static function crypto_sign_detached($message, $secretKey)
2837
+    {
2838
+        /* Type checks: */
2839
+        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
2840
+        ParagonIE_Sodium_Core_Util::declareScalarType($secretKey, 'string', 2);
2841
+
2842
+        /* Input validation: */
2843
+        if (ParagonIE_Sodium_Core_Util::strlen($secretKey) !== self::CRYPTO_SIGN_SECRETKEYBYTES) {
2844
+            throw new SodiumException('Argument 2 must be CRYPTO_SIGN_SECRETKEYBYTES long.');
2845
+        }
2846
+
2847
+        if (self::useNewSodiumAPI()) {
2848
+            return sodium_crypto_sign_detached($message, $secretKey);
2849
+        }
2850
+        if (self::use_fallback('crypto_sign_detached')) {
2851
+            return (string) call_user_func('\\Sodium\\crypto_sign_detached', $message, $secretKey);
2852
+        }
2853
+        if (PHP_INT_SIZE === 4) {
2854
+            return ParagonIE_Sodium_Crypto32::sign_detached($message, $secretKey);
2855
+        }
2856
+        return ParagonIE_Sodium_Crypto::sign_detached($message, $secretKey);
2857
+    }
2858
+
2859
+    /**
2860
+     * Verify the Ed25519 signature of a message.
2861
+     *
2862
+     * @param string $signature Digital sginature
2863
+     * @param string $message Message to be verified
2864
+     * @param string $publicKey Public key
2865
+     * @return bool             TRUE if this signature is good for this public key;
2866
+     *                          FALSE otherwise
2867
+     * @throws SodiumException
2868
+     * @throws TypeError
2869
+     * @psalm-suppress MixedArgument
2870
+     */
2871
+    public static function crypto_sign_verify_detached($signature, $message, $publicKey)
2872
+    {
2873
+        /* Type checks: */
2874
+        ParagonIE_Sodium_Core_Util::declareScalarType($signature, 'string', 1);
2875
+        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 2);
2876
+        ParagonIE_Sodium_Core_Util::declareScalarType($publicKey, 'string', 3);
2877
+
2878
+        /* Input validation: */
2879
+        if (ParagonIE_Sodium_Core_Util::strlen($signature) !== self::CRYPTO_SIGN_BYTES) {
2880
+            throw new SodiumException('Argument 1 must be CRYPTO_SIGN_BYTES long.');
2881
+        }
2882
+        if (ParagonIE_Sodium_Core_Util::strlen($publicKey) !== self::CRYPTO_SIGN_PUBLICKEYBYTES) {
2883
+            throw new SodiumException('Argument 3 must be CRYPTO_SIGN_PUBLICKEYBYTES long.');
2884
+        }
2885
+
2886
+        if (self::useNewSodiumAPI()) {
2887
+            return sodium_crypto_sign_verify_detached($signature, $message, $publicKey);
2888
+        }
2889
+        if (self::use_fallback('crypto_sign_verify_detached')) {
2890
+            return (bool) call_user_func(
2891
+                '\\Sodium\\crypto_sign_verify_detached',
2892
+                $signature,
2893
+                $message,
2894
+                $publicKey
2895
+            );
2896
+        }
2897
+        if (PHP_INT_SIZE === 4) {
2898
+            return ParagonIE_Sodium_Crypto32::sign_verify_detached($signature, $message, $publicKey);
2899
+        }
2900
+        return ParagonIE_Sodium_Crypto::sign_verify_detached($signature, $message, $publicKey);
2901
+    }
2902
+
2903
+    /**
2904
+     * Convert an Ed25519 public key to a Curve25519 public key
2905
+     *
2906
+     * @param string $pk
2907
+     * @return string
2908
+     * @throws SodiumException
2909
+     * @throws TypeError
2910
+     * @psalm-suppress MixedArgument
2911
+     */
2912
+    public static function crypto_sign_ed25519_pk_to_curve25519($pk)
2913
+    {
2914
+        /* Type checks: */
2915
+        ParagonIE_Sodium_Core_Util::declareScalarType($pk, 'string', 1);
2916
+
2917
+        /* Input validation: */
2918
+        if (ParagonIE_Sodium_Core_Util::strlen($pk) < self::CRYPTO_SIGN_PUBLICKEYBYTES) {
2919
+            throw new SodiumException('Argument 1 must be at least CRYPTO_SIGN_PUBLICKEYBYTES long.');
2920
+        }
2921
+        if (self::useNewSodiumAPI()) {
2922
+            if (is_callable('crypto_sign_ed25519_pk_to_curve25519')) {
2923
+                return (string) sodium_crypto_sign_ed25519_pk_to_curve25519($pk);
2924
+            }
2925
+        }
2926
+        if (self::use_fallback('crypto_sign_ed25519_pk_to_curve25519')) {
2927
+            return (string) call_user_func('\\Sodium\\crypto_sign_ed25519_pk_to_curve25519', $pk);
2928
+        }
2929
+        if (PHP_INT_SIZE === 4) {
2930
+            return ParagonIE_Sodium_Core32_Ed25519::pk_to_curve25519($pk);
2931
+        }
2932
+        return ParagonIE_Sodium_Core_Ed25519::pk_to_curve25519($pk);
2933
+    }
2934
+
2935
+    /**
2936
+     * Convert an Ed25519 secret key to a Curve25519 secret key
2937
+     *
2938
+     * @param string $sk
2939
+     * @return string
2940
+     * @throws SodiumException
2941
+     * @throws TypeError
2942
+     * @psalm-suppress MixedArgument
2943
+     */
2944
+    public static function crypto_sign_ed25519_sk_to_curve25519($sk)
2945
+    {
2946
+        /* Type checks: */
2947
+        ParagonIE_Sodium_Core_Util::declareScalarType($sk, 'string', 1);
2948
+
2949
+        /* Input validation: */
2950
+        if (ParagonIE_Sodium_Core_Util::strlen($sk) < self::CRYPTO_SIGN_SEEDBYTES) {
2951
+            throw new SodiumException('Argument 1 must be at least CRYPTO_SIGN_SEEDBYTES long.');
2952
+        }
2953
+        if (self::useNewSodiumAPI()) {
2954
+            if (is_callable('crypto_sign_ed25519_sk_to_curve25519')) {
2955
+                return sodium_crypto_sign_ed25519_sk_to_curve25519($sk);
2956
+            }
2957
+        }
2958
+        if (self::use_fallback('crypto_sign_ed25519_sk_to_curve25519')) {
2959
+            return (string) call_user_func('\\Sodium\\crypto_sign_ed25519_sk_to_curve25519', $sk);
2960
+        }
2961
+
2962
+        $h = hash('sha512', ParagonIE_Sodium_Core_Util::substr($sk, 0, 32), true);
2963
+        $h[0] = ParagonIE_Sodium_Core_Util::intToChr(
2964
+            ParagonIE_Sodium_Core_Util::chrToInt($h[0]) & 248
2965
+        );
2966
+        $h[31] = ParagonIE_Sodium_Core_Util::intToChr(
2967
+            (ParagonIE_Sodium_Core_Util::chrToInt($h[31]) & 127) | 64
2968
+        );
2969
+        return ParagonIE_Sodium_Core_Util::substr($h, 0, 32);
2970
+    }
2971
+
2972
+    /**
2973
+     * Expand a key and nonce into a keystream of pseudorandom bytes.
2974
+     *
2975
+     * @param int $len Number of bytes desired
2976
+     * @param string $nonce Number to be used Once; must be 24 bytes
2977
+     * @param string $key XSalsa20 key
2978
+     * @return string       Pseudorandom stream that can be XORed with messages
2979
+     *                      to provide encryption (but not authentication; see
2980
+     *                      Poly1305 or crypto_auth() for that, which is not
2981
+     *                      optional for security)
2982
+     * @throws SodiumException
2983
+     * @throws TypeError
2984
+     * @psalm-suppress MixedArgument
2985
+     */
2986
+    public static function crypto_stream($len, $nonce, $key)
2987
+    {
2988
+        /* Type checks: */
2989
+        ParagonIE_Sodium_Core_Util::declareScalarType($len, 'int', 1);
2990
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
2991
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
2992
+
2993
+        /* Input validation: */
2994
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_NONCEBYTES) {
2995
+            throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
2996
+        }
2997
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_KEYBYTES) {
2998
+            throw new SodiumException('Argument 3 must be CRYPTO_STREAM_KEYBYTES long.');
2999
+        }
3000
+
3001
+        if (self::useNewSodiumAPI()) {
3002
+            return sodium_crypto_stream($len, $nonce, $key);
3003
+        }
3004
+        if (self::use_fallback('crypto_stream')) {
3005
+            return (string) call_user_func('\\Sodium\\crypto_stream', $len, $nonce, $key);
3006
+        }
3007
+        if (PHP_INT_SIZE === 4) {
3008
+            return ParagonIE_Sodium_Core32_XSalsa20::xsalsa20($len, $nonce, $key);
3009
+        }
3010
+        return ParagonIE_Sodium_Core_XSalsa20::xsalsa20($len, $nonce, $key);
3011
+    }
3012
+
3013
+    /**
3014
+     * DANGER! UNAUTHENTICATED ENCRYPTION!
3015
+     *
3016
+     * Unless you are following expert advice, do not use this feature.
3017
+     *
3018
+     * Algorithm: XSalsa20
3019
+     *
3020
+     * This DOES NOT provide ciphertext integrity.
3021
+     *
3022
+     * @param string $message Plaintext message
3023
+     * @param string $nonce Number to be used Once; must be 24 bytes
3024
+     * @param string $key Encryption key
3025
+     * @return string         Encrypted text which is vulnerable to chosen-
3026
+     *                        ciphertext attacks unless you implement some
3027
+     *                        other mitigation to the ciphertext (i.e.
3028
+     *                        Encrypt then MAC)
3029
+     * @throws SodiumException
3030
+     * @throws TypeError
3031
+     * @psalm-suppress MixedArgument
3032
+     */
3033
+    public static function crypto_stream_xor($message, $nonce, $key)
3034
+    {
3035
+        /* Type checks: */
3036
+        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
3037
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
3038
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
3039
+
3040
+        /* Input validation: */
3041
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_NONCEBYTES) {
3042
+            throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_NONCEBYTES long.');
3043
+        }
3044
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_KEYBYTES) {
3045
+            throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_KEYBYTES long.');
3046
+        }
3047
+
3048
+        if (self::useNewSodiumAPI()) {
3049
+            return sodium_crypto_stream_xor($message, $nonce, $key);
3050
+        }
3051
+        if (self::use_fallback('crypto_stream_xor')) {
3052
+            return (string) call_user_func('\\Sodium\\crypto_stream_xor', $message, $nonce, $key);
3053
+        }
3054
+        if (PHP_INT_SIZE === 4) {
3055
+            return ParagonIE_Sodium_Core32_XSalsa20::xsalsa20_xor($message, $nonce, $key);
3056
+        }
3057
+        return ParagonIE_Sodium_Core_XSalsa20::xsalsa20_xor($message, $nonce, $key);
3058
+    }
3059
+
3060
+    /**
3061
+     * Return a secure random key for use with crypto_stream
3062
+     *
3063
+     * @return string
3064
+     * @throws Exception
3065
+     * @throws Error
3066
+     */
3067
+    public static function crypto_stream_keygen()
3068
+    {
3069
+        return random_bytes(self::CRYPTO_STREAM_KEYBYTES);
3070
+    }
3071
+
3072
+
3073
+    /**
3074
+     * Expand a key and nonce into a keystream of pseudorandom bytes.
3075
+     *
3076
+     * @param int $len Number of bytes desired
3077
+     * @param string $nonce Number to be used Once; must be 24 bytes
3078
+     * @param string $key XChaCha20 key
3079
+     * @param bool $dontFallback
3080
+     * @return string       Pseudorandom stream that can be XORed with messages
3081
+     *                      to provide encryption (but not authentication; see
3082
+     *                      Poly1305 or crypto_auth() for that, which is not
3083
+     *                      optional for security)
3084
+     * @throws SodiumException
3085
+     * @throws TypeError
3086
+     * @psalm-suppress MixedArgument
3087
+     */
3088
+    public static function crypto_stream_xchacha20($len, $nonce, $key, $dontFallback = false)
3089
+    {
3090
+        /* Type checks: */
3091
+        ParagonIE_Sodium_Core_Util::declareScalarType($len, 'int', 1);
3092
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
3093
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
3094
+
3095
+        /* Input validation: */
3096
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_XCHACHA20_NONCEBYTES) {
3097
+            throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_XCHACHA20_NONCEBYTES long.');
3098
+        }
3099
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_XCHACHA20_KEYBYTES) {
3100
+            throw new SodiumException('Argument 3 must be CRYPTO_STREAM_XCHACHA20_KEYBYTES long.');
3101
+        }
3102
+
3103
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3104
+            return sodium_crypto_stream_xchacha20($len, $nonce, $key);
3105
+        }
3106
+        if (PHP_INT_SIZE === 4) {
3107
+            return ParagonIE_Sodium_Core32_XChaCha20::stream($len, $nonce, $key);
3108
+        }
3109
+        return ParagonIE_Sodium_Core_XChaCha20::stream($len, $nonce, $key);
3110
+    }
3111
+
3112
+    /**
3113
+     * DANGER! UNAUTHENTICATED ENCRYPTION!
3114
+     *
3115
+     * Unless you are following expert advice, do not use this feature.
3116
+     *
3117
+     * Algorithm: XChaCha20
3118
+     *
3119
+     * This DOES NOT provide ciphertext integrity.
3120
+     *
3121
+     * @param string $message Plaintext message
3122
+     * @param string $nonce Number to be used Once; must be 24 bytes
3123
+     * @param string $key Encryption key
3124
+     * @return string         Encrypted text which is vulnerable to chosen-
3125
+     *                        ciphertext attacks unless you implement some
3126
+     *                        other mitigation to the ciphertext (i.e.
3127
+     *                        Encrypt then MAC)
3128
+     * @param bool $dontFallback
3129
+     * @throws SodiumException
3130
+     * @throws TypeError
3131
+     * @psalm-suppress MixedArgument
3132
+     */
3133
+    public static function crypto_stream_xchacha20_xor($message, $nonce, $key, $dontFallback = false)
3134
+    {
3135
+        /* Type checks: */
3136
+        ParagonIE_Sodium_Core_Util::declareScalarType($message, 'string', 1);
3137
+        ParagonIE_Sodium_Core_Util::declareScalarType($nonce, 'string', 2);
3138
+        ParagonIE_Sodium_Core_Util::declareScalarType($key, 'string', 3);
3139
+
3140
+        /* Input validation: */
3141
+        if (ParagonIE_Sodium_Core_Util::strlen($nonce) !== self::CRYPTO_STREAM_XCHACHA20_NONCEBYTES) {
3142
+            throw new SodiumException('Argument 2 must be CRYPTO_SECRETBOX_XCHACHA20_NONCEBYTES long.');
3143
+        }
3144
+        if (ParagonIE_Sodium_Core_Util::strlen($key) !== self::CRYPTO_STREAM_XCHACHA20_KEYBYTES) {
3145
+            throw new SodiumException('Argument 3 must be CRYPTO_SECRETBOX_XCHACHA20_KEYBYTES long.');
3146
+        }
3147
+
3148
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3149
+            return sodium_crypto_stream_xchacha20_xor($message, $nonce, $key);
3150
+        }
3151
+        if (PHP_INT_SIZE === 4) {
3152
+            return ParagonIE_Sodium_Core32_XChaCha20::streamXorIc($message, $nonce, $key);
3153
+        }
3154
+        return ParagonIE_Sodium_Core_XChaCha20::streamXorIc($message, $nonce, $key);
3155
+    }
3156
+
3157
+    /**
3158
+     * Return a secure random key for use with crypto_stream_xchacha20
3159
+     *
3160
+     * @return string
3161
+     * @throws Exception
3162
+     * @throws Error
3163
+     */
3164
+    public static function crypto_stream_xchacha20_keygen()
3165
+    {
3166
+        return random_bytes(self::CRYPTO_STREAM_XCHACHA20_KEYBYTES);
3167
+    }
3168
+
3169
+    /**
3170
+     * Cache-timing-safe implementation of hex2bin().
3171
+     *
3172
+     * @param string $string Hexadecimal string
3173
+     * @return string        Raw binary string
3174
+     * @throws SodiumException
3175
+     * @throws TypeError
3176
+     * @psalm-suppress TooFewArguments
3177
+     * @psalm-suppress MixedArgument
3178
+     */
3179
+    public static function hex2bin($string)
3180
+    {
3181
+        /* Type checks: */
3182
+        ParagonIE_Sodium_Core_Util::declareScalarType($string, 'string', 1);
3183
+
3184
+        if (self::useNewSodiumAPI()) {
3185
+            if (is_callable('sodium_hex2bin')) {
3186
+                return (string) sodium_hex2bin($string);
3187
+            }
3188
+        }
3189
+        if (self::use_fallback('hex2bin')) {
3190
+            return (string) call_user_func('\\Sodium\\hex2bin', $string);
3191
+        }
3192
+        return ParagonIE_Sodium_Core_Util::hex2bin($string);
3193
+    }
3194
+
3195
+    /**
3196
+     * Increase a string (little endian)
3197
+     *
3198
+     * @param string $var
3199
+     *
3200
+     * @return void
3201
+     * @throws SodiumException
3202
+     * @throws TypeError
3203
+     * @psalm-suppress MixedArgument
3204
+     */
3205
+    public static function increment(&$var)
3206
+    {
3207
+        /* Type checks: */
3208
+        ParagonIE_Sodium_Core_Util::declareScalarType($var, 'string', 1);
3209
+
3210
+        if (self::useNewSodiumAPI()) {
3211
+            sodium_increment($var);
3212
+            return;
3213
+        }
3214
+        if (self::use_fallback('increment')) {
3215
+            $func = '\\Sodium\\increment';
3216
+            $func($var);
3217
+            return;
3218
+        }
3219
+
3220
+        $len = ParagonIE_Sodium_Core_Util::strlen($var);
3221
+        $c = 1;
3222
+        $copy = '';
3223
+        for ($i = 0; $i < $len; ++$i) {
3224
+            $c += ParagonIE_Sodium_Core_Util::chrToInt(
3225
+                ParagonIE_Sodium_Core_Util::substr($var, $i, 1)
3226
+            );
3227
+            $copy .= ParagonIE_Sodium_Core_Util::intToChr($c);
3228
+            $c >>= 8;
3229
+        }
3230
+        $var = $copy;
3231
+    }
3232
+
3233
+    /**
3234
+     * @param string $str
3235
+     * @return bool
3236
+     *
3237
+     * @throws SodiumException
3238
+     */
3239
+    public static function is_zero($str)
3240
+    {
3241
+        $d = 0;
3242
+        for ($i = 0; $i < 32; ++$i) {
3243
+            $d |= ParagonIE_Sodium_Core_Util::chrToInt($str[$i]);
3244
+        }
3245
+        return ((($d - 1) >> 31) & 1) === 1;
3246
+    }
3247
+
3248
+    /**
3249
+     * The equivalent to the libsodium minor version we aim to be compatible
3250
+     * with (sans pwhash and memzero).
3251
+     *
3252
+     * @return int
3253
+     */
3254
+    public static function library_version_major()
3255
+    {
3256
+        if (self::useNewSodiumAPI() && defined('SODIUM_LIBRARY_MAJOR_VERSION')) {
3257
+            return SODIUM_LIBRARY_MAJOR_VERSION;
3258
+        }
3259
+        if (self::use_fallback('library_version_major')) {
3260
+            /** @psalm-suppress UndefinedFunction */
3261
+            return (int) call_user_func('\\Sodium\\library_version_major');
3262
+        }
3263
+        return self::LIBRARY_VERSION_MAJOR;
3264
+    }
3265
+
3266
+    /**
3267
+     * The equivalent to the libsodium minor version we aim to be compatible
3268
+     * with (sans pwhash and memzero).
3269
+     *
3270
+     * @return int
3271
+     */
3272
+    public static function library_version_minor()
3273
+    {
3274
+        if (self::useNewSodiumAPI() && defined('SODIUM_LIBRARY_MINOR_VERSION')) {
3275
+            return SODIUM_LIBRARY_MINOR_VERSION;
3276
+        }
3277
+        if (self::use_fallback('library_version_minor')) {
3278
+            /** @psalm-suppress UndefinedFunction */
3279
+            return (int) call_user_func('\\Sodium\\library_version_minor');
3280
+        }
3281
+        return self::LIBRARY_VERSION_MINOR;
3282
+    }
3283
+
3284
+    /**
3285
+     * Compare two strings.
3286
+     *
3287
+     * @param string $left
3288
+     * @param string $right
3289
+     * @return int
3290
+     * @throws SodiumException
3291
+     * @throws TypeError
3292
+     * @psalm-suppress MixedArgument
3293
+     */
3294
+    public static function memcmp($left, $right)
3295
+    {
3296
+        /* Type checks: */
3297
+        ParagonIE_Sodium_Core_Util::declareScalarType($left, 'string', 1);
3298
+        ParagonIE_Sodium_Core_Util::declareScalarType($right, 'string', 2);
3299
+
3300
+        if (self::useNewSodiumAPI()) {
3301
+            return sodium_memcmp($left, $right);
3302
+        }
3303
+        if (self::use_fallback('memcmp')) {
3304
+            return (int) call_user_func('\\Sodium\\memcmp', $left, $right);
3305
+        }
3306
+        /** @var string $left */
3307
+        /** @var string $right */
3308
+        return ParagonIE_Sodium_Core_Util::memcmp($left, $right);
3309
+    }
3310
+
3311
+    /**
3312
+     * It's actually not possible to zero memory buffers in PHP. You need the
3313
+     * native library for that.
3314
+     *
3315
+     * @param string|null $var
3316
+     * @param-out string|null $var
3317
+     *
3318
+     * @return void
3319
+     * @throws SodiumException (Unless libsodium is installed)
3320
+     * @throws TypeError
3321
+     * @psalm-suppress TooFewArguments
3322
+     */
3323
+    public static function memzero(&$var)
3324
+    {
3325
+        /* Type checks: */
3326
+        ParagonIE_Sodium_Core_Util::declareScalarType($var, 'string', 1);
3327
+
3328
+        if (self::useNewSodiumAPI()) {
3329
+            /** @psalm-suppress MixedArgument */
3330
+            sodium_memzero($var);
3331
+            return;
3332
+        }
3333
+        if (self::use_fallback('memzero')) {
3334
+            $func = '\\Sodium\\memzero';
3335
+            $func($var);
3336
+            if ($var === null) {
3337
+                return;
3338
+            }
3339
+        }
3340
+        // This is the best we can do.
3341
+        throw new SodiumException(
3342
+            'This is not implemented in sodium_compat, as it is not possible to securely wipe memory from PHP. ' .
3343
+            'To fix this error, make sure libsodium is installed and the PHP extension is enabled.'
3344
+        );
3345
+    }
3346
+
3347
+    /**
3348
+     * @param string $unpadded
3349
+     * @param int $blockSize
3350
+     * @param bool $dontFallback
3351
+     * @return string
3352
+     * @throws SodiumException
3353
+     */
3354
+    public static function pad($unpadded, $blockSize, $dontFallback = false)
3355
+    {
3356
+        /* Type checks: */
3357
+        ParagonIE_Sodium_Core_Util::declareScalarType($unpadded, 'string', 1);
3358
+        ParagonIE_Sodium_Core_Util::declareScalarType($blockSize, 'int', 2);
3359
+
3360
+        $unpadded = (string) $unpadded;
3361
+        $blockSize = (int) $blockSize;
3362
+
3363
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3364
+            return (string) sodium_pad($unpadded, $blockSize);
3365
+        }
3366
+
3367
+        if ($blockSize <= 0) {
3368
+            throw new SodiumException(
3369
+                'block size cannot be less than 1'
3370
+            );
3371
+        }
3372
+        $unpadded_len = ParagonIE_Sodium_Core_Util::strlen($unpadded);
3373
+        $xpadlen = ($blockSize - 1);
3374
+        if (($blockSize & ($blockSize - 1)) === 0) {
3375
+            $xpadlen -= $unpadded_len & ($blockSize - 1);
3376
+        } else {
3377
+            $xpadlen -= $unpadded_len % $blockSize;
3378
+        }
3379
+
3380
+        $xpadded_len = $unpadded_len + $xpadlen;
3381
+        $padded = str_repeat("\0", $xpadded_len - 1);
3382
+        if ($unpadded_len > 0) {
3383
+            $st = 1;
3384
+            $i = 0;
3385
+            $k = $unpadded_len;
3386
+            for ($j = 0; $j <= $xpadded_len; ++$j) {
3387
+                $i = (int) $i;
3388
+                $k = (int) $k;
3389
+                $st = (int) $st;
3390
+                if ($j >= $unpadded_len) {
3391
+                    $padded[$j] = "\0";
3392
+                } else {
3393
+                    $padded[$j] = $unpadded[$j];
3394
+                }
3395
+                /** @var int $k */
3396
+                $k -= $st;
3397
+                $st = (int) (~(
3398
+                            (
3399
+                                (
3400
+                                    ($k >> 48)
3401
+                                        |
3402
+                                    ($k >> 32)
3403
+                                        |
3404
+                                    ($k >> 16)
3405
+                                        |
3406
+                                    $k
3407
+                                ) - 1
3408
+                            ) >> 16
3409
+                        )
3410
+                    ) & 1;
3411
+                $i += $st;
3412
+            }
3413
+        }
3414
+
3415
+        $mask = 0;
3416
+        $tail = $xpadded_len;
3417
+        for ($i = 0; $i < $blockSize; ++$i) {
3418
+            # barrier_mask = (unsigned char)
3419
+            #     (((i ^ xpadlen) - 1U) >> ((sizeof(size_t) - 1U) * CHAR_BIT));
3420
+            $barrier_mask = (($i ^ $xpadlen) -1) >> ((PHP_INT_SIZE << 3) - 1);
3421
+            # tail[-i] = (tail[-i] & mask) | (0x80 & barrier_mask);
3422
+            $padded[$tail - $i] = ParagonIE_Sodium_Core_Util::intToChr(
3423
+                (ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i]) & $mask)
3424
+                    |
3425
+                (0x80 & $barrier_mask)
3426
+            );
3427
+            # mask |= barrier_mask;
3428
+            $mask |= $barrier_mask;
3429
+        }
3430
+        return $padded;
3431
+    }
3432
+
3433
+    /**
3434
+     * @param string $padded
3435
+     * @param int $blockSize
3436
+     * @param bool $dontFallback
3437
+     * @return string
3438
+     * @throws SodiumException
3439
+     */
3440
+    public static function unpad($padded, $blockSize, $dontFallback = false)
3441
+    {
3442
+        /* Type checks: */
3443
+        ParagonIE_Sodium_Core_Util::declareScalarType($padded, 'string', 1);
3444
+        ParagonIE_Sodium_Core_Util::declareScalarType($blockSize, 'int', 2);
3445
+
3446
+        $padded = (string) $padded;
3447
+        $blockSize = (int) $blockSize;
3448
+
3449
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3450
+            return (string) sodium_unpad($padded, $blockSize);
3451
+        }
3452
+        if ($blockSize <= 0) {
3453
+            throw new SodiumException('block size cannot be less than 1');
3454
+        }
3455
+        $padded_len = ParagonIE_Sodium_Core_Util::strlen($padded);
3456
+        if ($padded_len < $blockSize) {
3457
+            throw new SodiumException('invalid padding');
3458
+        }
3459
+
3460
+        # tail = &padded[padded_len - 1U];
3461
+        $tail = $padded_len - 1;
3462
+
3463
+        $acc = 0;
3464
+        $valid = 0;
3465
+        $pad_len = 0;
3466
+
3467
+        $found = 0;
3468
+        for ($i = 0; $i < $blockSize; ++$i) {
3469
+            # c = tail[-i];
3470
+            $c = ParagonIE_Sodium_Core_Util::chrToInt($padded[$tail - $i]);
3471
+
3472
+            # is_barrier =
3473
+            #     (( (acc - 1U) & (pad_len - 1U) & ((c ^ 0x80) - 1U) ) >> 8) & 1U;
3474
+            $is_barrier = (
3475
+                (
3476
+                    ($acc - 1) & ($pad_len - 1) & (($c ^ 80) - 1)
3477
+                ) >> 7
3478
+            ) & 1;
3479
+            $is_barrier &= ~$found;
3480
+            $found |= $is_barrier;
3481
+
3482
+            # acc |= c;
3483
+            $acc |= $c;
3484
+
3485
+            # pad_len |= i & (1U + ~is_barrier);
3486
+            $pad_len |= $i & (1 + ~$is_barrier);
3487
+
3488
+            # valid |= (unsigned char) is_barrier;
3489
+            $valid |= ($is_barrier & 0xff);
3490
+        }
3491
+        # unpadded_len = padded_len - 1U - pad_len;
3492
+        $unpadded_len = $padded_len - 1 - $pad_len;
3493
+        if ($valid !== 1) {
3494
+            throw new SodiumException('invalid padding');
3495
+        }
3496
+        return ParagonIE_Sodium_Core_Util::substr($padded, 0, $unpadded_len);
3497
+    }
3498
+
3499
+    /**
3500
+     * Will sodium_compat run fast on the current hardware and PHP configuration?
3501
+     *
3502
+     * @return bool
3503
+     */
3504
+    public static function polyfill_is_fast()
3505
+    {
3506
+        if (extension_loaded('sodium')) {
3507
+            return true;
3508
+        }
3509
+        if (extension_loaded('libsodium')) {
3510
+            return true;
3511
+        }
3512
+        return PHP_INT_SIZE === 8;
3513
+    }
3514
+
3515
+    /**
3516
+     * Generate a string of bytes from the kernel's CSPRNG.
3517
+     * Proudly uses /dev/urandom (if getrandom(2) is not available).
3518
+     *
3519
+     * @param int $numBytes
3520
+     * @return string
3521
+     * @throws Exception
3522
+     * @throws TypeError
3523
+     */
3524
+    public static function randombytes_buf($numBytes)
3525
+    {
3526
+        /* Type checks: */
3527
+        if (!is_int($numBytes)) {
3528
+            if (is_numeric($numBytes)) {
3529
+                $numBytes = (int) $numBytes;
3530
+            } else {
3531
+                throw new TypeError(
3532
+                    'Argument 1 must be an integer, ' . gettype($numBytes) . ' given.'
3533
+                );
3534
+            }
3535
+        }
3536
+        /** @var positive-int $numBytes */
3537
+        if (self::use_fallback('randombytes_buf')) {
3538
+            return (string) call_user_func('\\Sodium\\randombytes_buf', $numBytes);
3539
+        }
3540
+        if ($numBytes < 0) {
3541
+            throw new SodiumException("Number of bytes must be a positive integer");
3542
+        }
3543
+        return random_bytes($numBytes);
3544
+    }
3545
+
3546
+    /**
3547
+     * Generate an integer between 0 and $range (non-inclusive).
3548
+     *
3549
+     * @param int $range
3550
+     * @return int
3551
+     * @throws Exception
3552
+     * @throws Error
3553
+     * @throws TypeError
3554
+     */
3555
+    public static function randombytes_uniform($range)
3556
+    {
3557
+        /* Type checks: */
3558
+        if (!is_int($range)) {
3559
+            if (is_numeric($range)) {
3560
+                $range = (int) $range;
3561
+            } else {
3562
+                throw new TypeError(
3563
+                    'Argument 1 must be an integer, ' . gettype($range) . ' given.'
3564
+                );
3565
+            }
3566
+        }
3567
+        if (self::use_fallback('randombytes_uniform')) {
3568
+            return (int) call_user_func('\\Sodium\\randombytes_uniform', $range);
3569
+        }
3570
+        return random_int(0, $range - 1);
3571
+    }
3572
+
3573
+    /**
3574
+     * Generate a random 16-bit integer.
3575
+     *
3576
+     * @return int
3577
+     * @throws Exception
3578
+     * @throws Error
3579
+     * @throws TypeError
3580
+     */
3581
+    public static function randombytes_random16()
3582
+    {
3583
+        if (self::use_fallback('randombytes_random16')) {
3584
+            return (int) call_user_func('\\Sodium\\randombytes_random16');
3585
+        }
3586
+        return random_int(0, 65535);
3587
+    }
3588
+
3589
+    /**
3590
+     * @param string $p
3591
+     * @param bool $dontFallback
3592
+     * @return bool
3593
+     * @throws SodiumException
3594
+     */
3595
+    public static function ristretto255_is_valid_point($p, $dontFallback = false)
3596
+    {
3597
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3598
+            return sodium_crypto_core_ristretto255_is_valid_point($p);
3599
+        }
3600
+        try {
3601
+            $r = ParagonIE_Sodium_Core_Ristretto255::ristretto255_frombytes($p);
3602
+            return $r['res'] === 0 &&
3603
+                ParagonIE_Sodium_Core_Ristretto255::ristretto255_point_is_canonical($p) === 1;
3604
+        } catch (SodiumException $ex) {
3605
+            if ($ex->getMessage() === 'S is not canonical') {
3606
+                return false;
3607
+            }
3608
+            throw $ex;
3609
+        }
3610
+    }
3611
+
3612
+    /**
3613
+     * @param string $p
3614
+     * @param string $q
3615
+     * @param bool $dontFallback
3616
+     * @return string
3617
+     * @throws SodiumException
3618
+     */
3619
+    public static function ristretto255_add($p, $q, $dontFallback = false)
3620
+    {
3621
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3622
+            return sodium_crypto_core_ristretto255_add($p, $q);
3623
+        }
3624
+        return ParagonIE_Sodium_Core_Ristretto255::ristretto255_add($p, $q);
3625
+    }
3626
+
3627
+    /**
3628
+     * @param string $p
3629
+     * @param string $q
3630
+     * @param bool $dontFallback
3631
+     * @return string
3632
+     * @throws SodiumException
3633
+     */
3634
+    public static function ristretto255_sub($p, $q, $dontFallback = false)
3635
+    {
3636
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3637
+            return sodium_crypto_core_ristretto255_sub($p, $q);
3638
+        }
3639
+        return ParagonIE_Sodium_Core_Ristretto255::ristretto255_sub($p, $q);
3640
+    }
3641
+
3642
+    /**
3643
+     * @param string $r
3644
+     * @param bool $dontFallback
3645
+     * @return string
3646
+     *
3647
+     * @throws SodiumException
3648
+     */
3649
+    public static function ristretto255_from_hash($r, $dontFallback = false)
3650
+    {
3651
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3652
+            return sodium_crypto_core_ristretto255_from_hash($r);
3653
+        }
3654
+        return ParagonIE_Sodium_Core_Ristretto255::ristretto255_from_hash($r);
3655
+    }
3656
+
3657
+    /**
3658
+     * @param bool $dontFallback
3659
+     * @return string
3660
+     *
3661
+     * @throws SodiumException
3662
+     */
3663
+    public static function ristretto255_random($dontFallback = false)
3664
+    {
3665
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3666
+            return sodium_crypto_core_ristretto255_random();
3667
+        }
3668
+        return ParagonIE_Sodium_Core_Ristretto255::ristretto255_random();
3669
+    }
3670
+
3671
+    /**
3672
+     * @param bool $dontFallback
3673
+     * @return string
3674
+     *
3675
+     * @throws SodiumException
3676
+     */
3677
+    public static function ristretto255_scalar_random($dontFallback = false)
3678
+    {
3679
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3680
+            return sodium_crypto_core_ristretto255_scalar_random();
3681
+        }
3682
+        return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_random();
3683
+    }
3684
+
3685
+    /**
3686
+     * @param string $s
3687
+     * @param bool $dontFallback
3688
+     * @return string
3689
+     * @throws SodiumException
3690
+     */
3691
+    public static function ristretto255_scalar_invert($s, $dontFallback = false)
3692
+    {
3693
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3694
+            return sodium_crypto_core_ristretto255_scalar_invert($s);
3695
+        }
3696
+        return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_invert($s);
3697
+    }
3698
+    /**
3699
+     * @param string $s
3700
+     * @param bool $dontFallback
3701
+     * @return string
3702
+     * @throws SodiumException
3703
+     */
3704
+    public static function ristretto255_scalar_negate($s, $dontFallback = false)
3705
+    {
3706
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3707
+            return sodium_crypto_core_ristretto255_scalar_negate($s);
3708
+        }
3709
+        return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_negate($s);
3710
+    }
3711
+
3712
+    /**
3713
+     * @param string $s
3714
+     * @param bool $dontFallback
3715
+     * @return string
3716
+     * @throws SodiumException
3717
+     */
3718
+    public static function ristretto255_scalar_complement($s, $dontFallback = false)
3719
+    {
3720
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3721
+            return sodium_crypto_core_ristretto255_scalar_complement($s);
3722
+        }
3723
+        return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_complement($s);
3724
+    }
3725
+
3726
+    /**
3727
+     * @param string $x
3728
+     * @param string $y
3729
+     * @param bool $dontFallback
3730
+     * @return string
3731
+     * @throws SodiumException
3732
+     */
3733
+    public static function ristretto255_scalar_add($x, $y, $dontFallback = false)
3734
+    {
3735
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3736
+            return sodium_crypto_core_ristretto255_scalar_add($x, $y);
3737
+        }
3738
+        return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_add($x, $y);
3739
+    }
3740
+
3741
+    /**
3742
+     * @param string $x
3743
+     * @param string $y
3744
+     * @param bool $dontFallback
3745
+     * @return string
3746
+     * @throws SodiumException
3747
+     */
3748
+    public static function ristretto255_scalar_sub($x, $y, $dontFallback = false)
3749
+    {
3750
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3751
+            return sodium_crypto_core_ristretto255_scalar_sub($x, $y);
3752
+        }
3753
+        return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_sub($x, $y);
3754
+    }
3755
+
3756
+    /**
3757
+     * @param string $x
3758
+     * @param string $y
3759
+     * @param bool $dontFallback
3760
+     * @return string
3761
+     * @throws SodiumException
3762
+     */
3763
+    public static function ristretto255_scalar_mul($x, $y, $dontFallback = false)
3764
+    {
3765
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3766
+            return sodium_crypto_core_ristretto255_scalar_mul($x, $y);
3767
+        }
3768
+        return ParagonIE_Sodium_Core_Ristretto255::ristretto255_scalar_mul($x, $y);
3769
+    }
3770
+
3771
+    /**
3772
+     * @param string $n
3773
+     * @param string $p
3774
+     * @param bool $dontFallback
3775
+     * @return string
3776
+     * @throws SodiumException
3777
+     */
3778
+    public static function scalarmult_ristretto255($n, $p, $dontFallback = false)
3779
+    {
3780
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3781
+            return sodium_crypto_scalarmult_ristretto255($n, $p);
3782
+        }
3783
+        return ParagonIE_Sodium_Core_Ristretto255::scalarmult_ristretto255($n, $p);
3784
+    }
3785
+
3786
+    /**
3787
+     * @param string $n
3788
+     * @param string $p
3789
+     * @param bool $dontFallback
3790
+     * @return string
3791
+     * @throws SodiumException
3792
+     */
3793
+    public static function scalarmult_ristretto255_base($n, $dontFallback = false)
3794
+    {
3795
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3796
+            return sodium_crypto_scalarmult_ristretto255_base($n);
3797
+        }
3798
+        return ParagonIE_Sodium_Core_Ristretto255::scalarmult_ristretto255_base($n);
3799
+    }
3800
+
3801
+    /**
3802
+     * @param string $s
3803
+     * @param bool $dontFallback
3804
+     * @return string
3805
+     * @throws SodiumException
3806
+     */
3807
+    public static function ristretto255_scalar_reduce($s, $dontFallback = false)
3808
+    {
3809
+        if (self::useNewSodiumAPI() && !$dontFallback) {
3810
+            return sodium_crypto_core_ristretto255_scalar_reduce($s);
3811
+        }
3812
+        return ParagonIE_Sodium_Core_Ristretto255::sc_reduce($s);
3813
+    }
3814
+
3815
+    /**
3816
+     * Runtime testing method for 32-bit platforms.
3817
+     *
3818
+     * Usage: If runtime_speed_test() returns FALSE, then our 32-bit
3819
+     *        implementation is to slow to use safely without risking timeouts.
3820
+     *        If this happens, install sodium from PECL to get acceptable
3821
+     *        performance.
3822
+     *
3823
+     * @param int $iterations Number of multiplications to attempt
3824
+     * @param int $maxTimeout Milliseconds
3825
+     * @return bool           TRUE if we're fast enough, FALSE is not
3826
+     * @throws SodiumException
3827
+     */
3828
+    public static function runtime_speed_test($iterations, $maxTimeout)
3829
+    {
3830
+        if (self::polyfill_is_fast()) {
3831
+            return true;
3832
+        }
3833
+        /** @var float $end */
3834
+        $end = 0.0;
3835
+        /** @var float $start */
3836
+        $start = microtime(true);
3837
+        /** @var ParagonIE_Sodium_Core32_Int64 $a */
3838
+        $a = ParagonIE_Sodium_Core32_Int64::fromInt(random_int(3, 1 << 16));
3839
+        for ($i = 0; $i < $iterations; ++$i) {
3840
+            /** @var ParagonIE_Sodium_Core32_Int64 $b */
3841
+            $b = ParagonIE_Sodium_Core32_Int64::fromInt(random_int(3, 1 << 16));
3842
+            $a->mulInt64($b);
3843
+        }
3844
+        /** @var float $end */
3845
+        $end = microtime(true);
3846
+        /** @var int $diff */
3847
+        $diff = (int) ceil(($end - $start) * 1000);
3848
+        return $diff < $maxTimeout;
3849
+    }
3850
+
3851
+    /**
3852
+     * Add two numbers (little-endian unsigned), storing the value in the first
3853
+     * parameter.
3854
+     *
3855
+     * This mutates $val.
3856
+     *
3857
+     * @param string $val
3858
+     * @param string $addv
3859
+     * @return void
3860
+     * @throws SodiumException
3861
+     */
3862
+    public static function sub(&$val, $addv)
3863
+    {
3864
+        $val_len = ParagonIE_Sodium_Core_Util::strlen($val);
3865
+        $addv_len = ParagonIE_Sodium_Core_Util::strlen($addv);
3866
+        if ($val_len !== $addv_len) {
3867
+            throw new SodiumException('values must have the same length');
3868
+        }
3869
+        $A = ParagonIE_Sodium_Core_Util::stringToIntArray($val);
3870
+        $B = ParagonIE_Sodium_Core_Util::stringToIntArray($addv);
3871
+
3872
+        $c = 0;
3873
+        for ($i = 0; $i < $val_len; $i++) {
3874
+            $c = ($A[$i] - $B[$i] - $c);
3875
+            $A[$i] = ($c & 0xff);
3876
+            $c = ($c >> 8) & 1;
3877
+        }
3878
+        $val = ParagonIE_Sodium_Core_Util::intArrayToString($A);
3879
+    }
3880
+
3881
+    /**
3882
+     * This emulates libsodium's version_string() function, except ours is
3883
+     * prefixed with 'polyfill-'.
3884
+     *
3885
+     * @return string
3886
+     * @psalm-suppress MixedInferredReturnType
3887
+     * @psalm-suppress UndefinedFunction
3888
+     */
3889
+    public static function version_string()
3890
+    {
3891
+        if (self::useNewSodiumAPI()) {
3892
+            return (string) sodium_version_string();
3893
+        }
3894
+        if (self::use_fallback('version_string')) {
3895
+            return (string) call_user_func('\\Sodium\\version_string');
3896
+        }
3897
+        return (string) self::VERSION_STRING;
3898
+    }
3899
+
3900
+    /**
3901
+     * Should we use the libsodium core function instead?
3902
+     * This is always a good idea, if it's available. (Unless we're in the
3903
+     * middle of running our unit test suite.)
3904
+     *
3905
+     * If ext/libsodium is available, use it. Return TRUE.
3906
+     * Otherwise, we have to use the code provided herein. Return FALSE.
3907
+     *
3908
+     * @param string $sodium_func_name
3909
+     *
3910
+     * @return bool
3911
+     */
3912
+    protected static function use_fallback($sodium_func_name = '')
3913
+    {
3914
+        static $res = null;
3915
+        if ($res === null) {
3916
+            $res = extension_loaded('libsodium') && PHP_VERSION_ID >= 50300;
3917
+        }
3918
+        if ($res === false) {
3919
+            // No libsodium installed
3920
+            return false;
3921
+        }
3922
+        if (self::$disableFallbackForUnitTests) {
3923
+            // Don't fallback. Use the PHP implementation.
3924
+            return false;
3925
+        }
3926
+        if (!empty($sodium_func_name)) {
3927
+            return is_callable('\\Sodium\\' . $sodium_func_name);
3928
+        }
3929
+        return true;
3930
+    }
3931
+
3932
+    /**
3933
+     * Libsodium as implemented in PHP 7.2
3934
+     * and/or ext/sodium (via PECL)
3935
+     *
3936
+     * @ref https://wiki.php.net/rfc/libsodium
3937
+     * @return bool
3938
+     */
3939
+    protected static function useNewSodiumAPI()
3940
+    {
3941
+        static $res = null;
3942
+        if ($res === null) {
3943
+            $res = PHP_VERSION_ID >= 70000 && extension_loaded('sodium');
3944
+        }
3945
+        if (self::$disableFallbackForUnitTests) {
3946
+            // Don't fallback. Use the PHP implementation.
3947
+            return false;
3948
+        }
3949
+        return (bool) $res;
3950
+    }
3951
+}